summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticResultFormats
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
committerYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
commitfc7369835258467bf97eb64f184b93691f9a9fd5 (patch)
treedaabd60089d2dd76d9f5fb416b005fbe159c799d /www/wiki/extensions/SemanticResultFormats
first commit
Diffstat (limited to 'www/wiki/extensions/SemanticResultFormats')
-rw-r--r--www/wiki/extensions/SemanticResultFormats/.gitignore15
-rw-r--r--www/wiki/extensions/SemanticResultFormats/.jshintignore7
-rw-r--r--www/wiki/extensions/SemanticResultFormats/.jshintrc35
-rw-r--r--www/wiki/extensions/SemanticResultFormats/.scrutinizer.yml14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/.travis.yml32
-rw-r--r--www/wiki/extensions/SemanticResultFormats/COPYING103
-rw-r--r--www/wiki/extensions/SemanticResultFormats/DefaultSettings.php157
-rw-r--r--www/wiki/extensions/SemanticResultFormats/README.md56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/RELEASE-NOTES.md562
-rw-r--r--www/wiki/extensions/SemanticResultFormats/Resources.php1042
-rw-r--r--www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.hooks.php231
-rw-r--r--www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.i18n.magic.php133
-rw-r--r--www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.parser.php168
-rw-r--r--www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.php189
-rw-r--r--www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.utils.php74
-rw-r--r--www/wiki/extensions/SemanticResultFormats/build/travis/install-mediawiki.sh25
-rw-r--r--www/wiki/extensions/SemanticResultFormats/build/travis/install-semantic-result-formats.sh84
-rw-r--r--www/wiki/extensions/SemanticResultFormats/build/travis/run-tests.sh20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/composer.json87
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/COMPATIBILITY.md111
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/CONTRIBUTING.md15
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/INSTALL.md88
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/ISSUE_TEMPLATE.md30
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/PULL_REQUEST_TEMPLATE.md13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/README.md16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/jsduck.categories.json66
-rw-r--r--www/wiki/extensions/SemanticResultFormats/docs/jsduck.json16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/extension.json33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.css3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.js124
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.php628
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/LICENSE.txt29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-epilog.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-prolog.js1
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/content/history.html7
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-down.pngbin0 -> 988 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-left.pngbin0 -> 785 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-right.pngbin0 -> 939 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-up.pngbin0 -> 741 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-left.pngbin0 -> 656 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-right.pngbin0 -> 823 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom.pngbin0 -> 324 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-left.pngbin0 -> 208 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-right.pngbin0 -> 239 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-left.pngbin0 -> 406 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-right.pngbin0 -> 612 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top.pngbin0 -> 228 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/close-button.pngbin0 -> 583 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/copy.pngbin0 -> 120 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-left.pngbin0 -> 1068 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-right.pngbin0 -> 1574 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-left.pngbin0 -> 248 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-right.pngbin0 -> 379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-left.pngbin0 -> 755 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-right.pngbin0 -> 1088 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/loader.js34
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/ajax.js45
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/data-structure.js447
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/date-time.js452
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/debug.js94
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/dom.js344
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/graphics.js653
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/history.js220
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/html.js274
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/jquery-1.3.2.min.js23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/json.js129
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/platform.js114
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/signal.js43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/string.js43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/units.js73
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/window-manager.js414
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/xmlhttp.js137
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-api.js215
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle-debug.js2911
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle.js2911
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/LICENSE.txt29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-epilog.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-prolog.js1
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-api.js276
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.css742
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.js8362
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.css785
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.js8475
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-left.gifbin0 -> 73 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-right.gifbin0 -> 71 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check-no-border.pngbin0 -> 216 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check.pngbin0 -> 747 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/blank-16x16.pngbin0 -> 105 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/collapse.pngbin0 -> 116 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/day-with-items-bkgrd.gifbin0 -> 57 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/down-arrow.pngbin0 -> 135 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/expand.pngbin0 -> 120 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check-no-border.pngbin0 -> 216 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check.pngbin0 -> 725 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/left-arrow.pngbin0 -> 130 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/liveclipboard-icon.pngbin0 -> 645 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/map-marker-shadow.pngbin0 -> 1212 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-left.pngbin0 -> 1068 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-right.pngbin0 -> 1574 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-left.pngbin0 -> 248 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-right.pngbin0 -> 379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-left.pngbin0 -> 755 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-right.pngbin0 -> 1088 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-left.gifbin0 -> 111 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-right.gifbin0 -> 110 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check-no-border.pngbin0 -> 105 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check.pngbin0 -> 241 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option-check.pngbin0 -> 466 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option.pngbin0 -> 380 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/progress-running.gifbin0 -> 1002 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/right-arrow.pngbin0 -> 129 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle.pngbin0 -> 386 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle2.pngbin0 -> 437 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/up-arrow.pngbin0 -> 135 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector-active.gifbin0 -> 133 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector.gifbin0 -> 134 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/exhibit-de-bundle.js180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/locale.js38
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/data/database-l10n.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/exhibit-en-bundle.js190
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/locale.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/data/database-l10n.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/ordered-view-frame-l10n.js46
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/exhibit-es-bundle.js171
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/locale.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/data/database-l10n.js54
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/exhibit-fr-bundle.js180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/locale.js38
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/data/database-l10n.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/exhibit-nl-bundle.js180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/locale.js38
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/data/database-l10n.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/ordered-view-frame-l10n.js34
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/exhibit-no-bundle.js180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/locale.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/data/database-l10n.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/widgets/collection-summary-widget-l10n.js27
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/exhibit-sv-bundle.js171
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/locale.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/data/database-l10n.js54
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/exhibit-zh-bundle.js181
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/locale.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/data/database-l10n.js74
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/exhibit-l10n.js50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/formatter-l10n.js56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/lens-l10n.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/ui-context-l10n.js13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/ordered-view-frame-l10n.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tabular-view-l10n.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/thumbnail-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tile-view-l10n.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/view-panel-l10n.js21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/widgets/collection-summary-widget-l10n.js22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/coders-l10n.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/facets-l10n.js17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/views-l10n.js18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/manifest.json55
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/authentication.js64
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/create.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/collection.js395
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/controls.js115
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/database.js1306
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/bibtex-exporter.js78
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/exhibit-json-exporter.js93
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/facet-selection-exporter.js27
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/rdf-xml-exporter.js99
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/semantic-wikitext-exporter.js61
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/tsv-exporter.js53
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression-parser.js345
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression.js523
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/functions.js349
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/authenticated-importer.js53
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/babel-based-importer.js75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-json-importer.js42
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-xml-importer.js323
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/html-table-importer.js175
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/json-importer.js262
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/jsonp-importer.js257
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/rdfa-importer.js138
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/tsv-csv-importer.js198
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/exhibit.js395
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/persistence.js83
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-coder.js161
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-gradient-coder.js185
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/default-color-coder.js83
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/icon-coder.js148
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/ordered-color-coder.js250
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-coder.js139
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-gradient-coder.js192
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coordinator.js64
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/alpha-range-facet.js382
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/cloud-facet.js541
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/hierarchical-facet.js718
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/image-facet.js486
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/list-facet.js489
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/numeric-range-facet.js361
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider-facet.js291
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider.js363
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/text-search-facet.js294
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/format-parser.js500
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/formatter.js565
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/lens.js1000
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui-context.js295
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui.js623
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/html-view.js39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/ordered-view-frame.js979
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tabular-view.js640
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/thumbnail-view.js327
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tile-view.js214
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/view-panel.js365
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/collection-summary-widget.js129
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-gradient-widget.js171
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-widget.js136
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/logo.js53
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/option-widget.js78
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/resizable-div-widget.js61
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/toolbox-widget.js267
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/coders.js10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/facets.js543
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/set.js98
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/settings.js439
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/util.js118
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/views.js124
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/browse-panel.css20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/exhibit.css170
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/lens.css32
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/facets.css327
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/views.css104
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tabular-view.css28
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/thumbnail-view.css14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tile-view.css12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/view-panel.css25
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/collection-summary-widget.css11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/legend-widget.css14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/option-widget.css7
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/resizable-div-widget.css10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/toolbox-widget.css13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/LICENSE.txt29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.css243
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.js3039
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.css243
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.js3039
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-epilog.js16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-prolog.js1
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/geochrono-api.js92
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/ether-painters.js204
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/geochrono.js518
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/l10n/en/labellers.js10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/labellers.js52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/units.js86
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/planning-api.js92
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/ether-painters.js176
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/l10n/en/labellers.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/labellers.js33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/planning.js47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/units.js66
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/blue-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-arrow.pngbin0 -> 957 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-left.pngbin0 -> 653 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-right.pngbin0 -> 803 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom.pngbin0 -> 309 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left-arrow.pngbin0 -> 763 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left.pngbin0 -> 191 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right-arrow.pngbin0 -> 915 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right.pngbin0 -> 226 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-arrow.pngbin0 -> 715 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-left.pngbin0 -> 403 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-right.pngbin0 -> 607 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top.pngbin0 -> 220 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/close-button.pngbin0 -> 583 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright-vertical.pngbin0 -> 679 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright.pngbin0 -> 684 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-blue-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-green-circle.pngbin0 -> 479 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-red-circle.pngbin0 -> 488 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-blue-circle.pngbin0 -> 488 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-green-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-red-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/gray-circle.pngbin0 -> 469 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/green-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-left.pngbin0 -> 1068 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-right.pngbin0 -> 1574 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-left.pngbin0 -> 248 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-right.pngbin0 -> 379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-left.pngbin0 -> 755 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-right.pngbin0 -> 1088 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/progress-running.gifbin0 -> 1002 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/red-circle.pngbin0 -> 491 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/top-bubble.pngbin0 -> 2617 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/band.js960
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/compact-painter.js1074
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/decorators.js184
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/detailed-painter.js691
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ether-painters.js582
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ethers.js305
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/event-utils.js64
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ext/japanese-eras.js395
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/labellers.js30
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/labellers.js27
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/timeline.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/labellers.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/labellers.js11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/labellers.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/labellers.js10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/labellers.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/labellers.js26
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/labellers.js27
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/labellers.js91
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/original-painter.js700
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/overview-painter.js258
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/sources.js583
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/themes.js180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/timeline.js648
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/ethers.css120
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/events.css45
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/timeline.css79
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-api.js303
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.css243
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.js2950
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.css243
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.js2950
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Gantt/GanttPrinter.php284
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Gantt/resources/ext.gantt.js81
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/Gantt.php203
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttSection.php66
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttTask.php99
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/Extras/excanvas.js1415
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit-yc.js23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit.js17162
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/README11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.js208
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.php385
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/base.css85
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbar.gifbin0 -> 120 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_black.gifbin0 -> 1626 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_green.gifbin0 -> 1308 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_orange.gifbin0 -> 1308 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_red.gifbin0 -> 1308 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_yellow.gifbin0 -> 1308 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/JitGraph/jquery.progressbar.js132
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Array.php469
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Hash.php88
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/boilerplate/SRF_Boilerplate.php296
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.css11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.namespace.js109
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.simple.js70
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/EventCalendar.php156
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/SRFC_HistoricalDate.php98
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/SRF_Calendar.php694
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.calendar.css100
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.css360
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.js1124
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.hooks.eventcalendar.js48
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarbutton.js113
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarlegend.js196
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarpane.js109
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarparameters.js351
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/left-arrow.pngbin0 -> 302 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/right-arrow.pngbin0 -> 298 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/SRF_D3Chart.php171
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/LICENSE ColorBrewer38
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.css31
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.js122
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.css18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.js127
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.css31
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.js60
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/datatables/DataTables.php98
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.css292
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.js768
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/dygraphs/SRF_Dygraphs.php330
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.css43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.js416
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.pngbin0 -> 176 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.psdbin0 -> 32768 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/README.md179
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/gulpfile.js154
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/package-lock.json5174
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/package.json41
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.calendar-view.less10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.distance-filter.less50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.leaflet.css711
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.less166
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.map-view.less3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.number-filter.less96
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.select.css484
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.slider.css244
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.value-filter.less79
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers-2x.pngbin0 -> 1259 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers.pngbin0 -> 696 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon-2x.pngbin0 -> 2464 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon.pngbin0 -> 1466 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-shadow.pngbin0 -> 618 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js1456
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js.map1
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.leaflet.js17397
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.select.js5725
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.slider.js2450
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Controller.ts204
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/DistanceFilter.ts142
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/Filter.ts180
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/NumberFilter.ts288
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/ValueFilter.ts237
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filtered.ts108
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/CalendarView.ts122
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/ListView.ts10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/MapView.ts255
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/TableView.ts9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/View.ts86
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/ViewSelector.ts35
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/bootstrap.ts11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/types.ts2
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filtered.php494
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/DistanceFilter.php135
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/Filter.php178
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/NumberFilter.php95
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/ValueFilter.php43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Hooks.php26
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/ResultItem.php113
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/CalendarView.php271
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/ListView.php272
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/MapView.php317
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/TableView.php287
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/View.php115
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ControllerTest.ts177
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/Filter/ValueFilterTest.ts88
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/MapViewTest.ts23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/ViewTest.ts75
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ViewSelectorTest.ts113
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MWQunit.ts5
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MockedFilter.ts3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTest.ts3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTestHandler.ts55
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/bootstrap.ts19
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/filtered/tsconfig.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/Gallery.php512
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.formats.gallery.js80
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.css296
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.js98
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.css68
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.js158
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.css44
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.js118
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.css103
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.js116
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/gallery-redirect.pngbin0 -> 176 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-horizontal.pngbin0 -> 421 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-vertical.pngbin0 -> 369 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/overlay-zoom.pngbin0 -> 193 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-horizontal.pngbin0 -> 430 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-vertical.pngbin0 -> 341 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/googlecharts/README18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GoogleBar.php96
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GooglePie.php97
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/README23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/SRF_Process.php1390
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/detail_icon.pngbin0 -> 1110 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon.pngbin0 -> 971 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon_grey.pngbin0 -> 549 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p000.pngbin0 -> 369 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p025.pngbin0 -> 630 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p050.pngbin0 -> 664 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p075.pngbin0 -> 787 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p100.pngbin0 -> 436 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/subprocess.pngbin0 -> 420 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/incoming/SRF_Incoming.php200
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlot.php195
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotChart.php250
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotSeries.php427
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/LICENSE ColorBrewer38
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqlpot.chart.css52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bar.js255
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bubble.js98
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.js162
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.pie.js69
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.themes.js76
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/math/SRF_Math.php125
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/media/MediaPlayer.php358
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.css39
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.js250
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.template.jplayer.js242
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/media/resources/images/audio.auto.cover.pngbin0 -> 7686 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShow.php182
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShowApi.php184
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.css43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.js489
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/sparkline/SRF_Sparkline.php115
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/sparkline/resources/ext.srf.sparkline.js71
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/spreadsheet/SpreadsheetPrinter.php461
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tagcloud/TagCloud.php465
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.css52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.js294
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/time/SRF_Time.php94
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/README18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/SRF_Timeline.php427
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/LICENSE33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/geochrono-api.js92
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/ether-painters.js204
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/geochrono.js532
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/l10n/en/labellers.js10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/labellers.js52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/units.js86
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/blue-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-arrow.pngbin0 -> 957 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-left.pngbin0 -> 653 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-right.pngbin0 -> 803 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom.pngbin0 -> 309 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left-arrow.pngbin0 -> 763 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left.pngbin0 -> 191 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right-arrow.pngbin0 -> 915 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right.pngbin0 -> 226 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-arrow.pngbin0 -> 715 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-left.pngbin0 -> 403 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-right.pngbin0 -> 607 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top.pngbin0 -> 220 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/close-button.pngbin0 -> 583 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright-vertical.pngbin0 -> 679 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright.pngbin0 -> 684 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-blue-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-green-circle.pngbin0 -> 493 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-red-circle.pngbin0 -> 503 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-blue-circle.pngbin0 -> 503 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-green-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-red-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/gray-circle.pngbin0 -> 483 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/green-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-left.pngbin0 -> 1068 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-right.pngbin0 -> 1574 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-left.pngbin0 -> 248 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-right.pngbin0 -> 379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-left.pngbin0 -> 755 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-right.pngbin0 -> 1088 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/progress-running.gifbin0 -> 1002 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/red-circle.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/top-bubble.pngbin0 -> 2617 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/decorators.js179
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ether-painters.js563
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ethers.js250
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ext/japanese-eras.js395
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/labellers.js8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/labellers.js10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/labellers.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/labellers.js26
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/labellers.js27
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/timeline.js9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/labellers.js92
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/layouts.js128
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/painters.js334
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/sources.js426
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/themes.js127
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/timeline.js892
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/units.js70
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/data-structure.js247
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/date-time.js321
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/debug.js14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/dom.js76
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/graphics.js303
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/platform.js90
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/xmlhttp.js133
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/ethers.css63
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/events.css45
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/timeline.css65
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/timeline-api.js226
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/ext.srf.timeline.js281
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeseries/SRF_Timeseries.php275
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.flot.core.css63
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.timeseries.flot.js342
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNode.php67
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNodeVisitor.php193
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/tree/TreeResultPrinter.php384
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/valuerank/SRF_ValueRank.php265
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_ListWidget.php132
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_PageWidget.php105
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.css115
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.js76
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.css79
-rw-r--r--www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.js99
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/af.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/am.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ar.json348
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/arc.json20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/arz.json43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ast.json323
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/az.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/be-tarask.json73
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/bg.json24
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/bho.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/bn.json25
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/br.json138
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/bs.json29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ca.json133
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ce.json41
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/co.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/cs.json330
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/da.json99
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/de-formal.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/de.json355
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/diq.json43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/dsb.json129
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/el.json269
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/en.json355
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/eo.json21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/es.json339
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/et.json49
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/eu.json144
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/fa.json154
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/fi.json177
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/fr.json366
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/frp.json73
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/fy.json20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ga.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/gd.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/gl.json329
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/grc.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/gsw.json48
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/gv.json10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/he.json292
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/hi.json14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/hsb.json200
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ht.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/hu.json121
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ia.json131
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/id.json93
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ig.json14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/it.json149
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ja.json230
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/jv.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ka.json29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/km.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ko.json251
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/krc.json16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ksh.json49
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ku-latn.json17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ky.json10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/lb.json136
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/lki.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/lt.json175
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/lv.json34
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/mk.json303
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ml.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/mr.json14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ms.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/my.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/myv.json10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/nah.json13
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/nb.json304
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/nl.json276
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/nn.json25
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/oc.json135
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/om.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/os.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pdc.json10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pfl.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pl.json217
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pms.json232
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ps.json29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pt-br.json356
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/pt.json352
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/qqq.json372
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/qu.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/rmf.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ro.json41
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/roa-tara.json97
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ru.json329
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/rue.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sco.json67
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/si.json165
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sk.json25
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sr-ec.json26
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sr-el.json23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sv.json263
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/sw.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ta.json88
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/te.json22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tg-cyrl.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tg-latn.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tl.json176
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tr.json33
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tt-cyrl.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tyv.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/tzm.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/uk.json338
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/ur.json18
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/uz.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/vec.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/vep.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/vi.json31
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/vo.json12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/wa.json9
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/yi.json11
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/zh-hans.json340
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/zh-hant.json338
-rw-r--r--www/wiki/extensions/SemanticResultFormats/i18n/zh-hk.json8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/phpunit.xml.dist32
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/LICENSE3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/docs/jsduck.external.js37
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.query.js274
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.results.js267
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.css109
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.js130
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.css22
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.js242
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.html.js64
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.js364
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js398
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.v3.js7806
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psdbin0 -> 27490 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.pngbin0 -> 1361 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.pngbin0 -> 1379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.pngbin0 -> 1375 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/favicon.icobin0 -> 894 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.pngbin0 -> 1363 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.pngbin0 -> 1380 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.pngbin0 -> 1379 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.pngbin0 -> 1118 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.pngbin0 -> 1050 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_both.pngbin0 -> 1136 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.pngbin0 -> 1127 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.pngbin0 -> 1045 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css217
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js116
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css221
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js91
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js12099
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css244
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js2
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/ext.jquery.migration.browser.js40
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/blank.gifbin0 -> 43 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/closelabel.gifbin0 -> 979 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_close.pngbin0 -> 1517 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.pngbin0 -> 10195 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.pngbin0 -> 1446 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.pngbin0 -> 1454 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.pngbin0 -> 107 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.pngbin0 -> 106 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.pngbin0 -> 347 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.pngbin0 -> 324 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.pngbin0 -> 111 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.pngbin0 -> 352 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.pngbin0 -> 340 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.pngbin0 -> 103 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.pngbin0 -> 503 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.pngbin0 -> 96 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.pngbin0 -> 70 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.pngbin0 -> 506 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.pngbin0 -> 203 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.pngbin0 -> 176 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox.pngbin0 -> 15287 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css359
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js46
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.js2605
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js750
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js344
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt278
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt322
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css1293
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js15012
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css176
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js324
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/moment.js4506
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.js496
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js2
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js338
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.min.js2
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.js3506
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.swfbin0 -> 13714 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.css551
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.min.css1
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.jpgbin0 -> 23189 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.seeking.gifbin0 -> 3284 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.video.play.pngbin0 -> 17692 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css640
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpgbin0 -> 23189 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gifbin0 -> 3284 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.pngbin0 -> 17692 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.playlist.html42
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.single.html37
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.stream.html24
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.playlist.html52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.single.html43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css749
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.pngbin0 -> 324 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.pngbin0 -> 275 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.pngbin0 -> 34557 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gifbin0 -> 3284 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.pngbin0 -> 19197 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js169
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js516
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css144
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/excanvas.js1438
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright29
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE21
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js313
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js797
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js235
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js759
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js203
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js243
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js865
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js449
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js673
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js116
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js1108
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js737
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js805
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js225
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js305
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js943
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js465
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js475
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js529
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js611
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js437
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js1030
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js45
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js373
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js904
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js379
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js728
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js429
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js514
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js223
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css259
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js11381
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.blockUI.js619
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js526
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.easing.js205
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jStorage.js1143
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jcarousel.js1057
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listmenu.js281
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listnav.js232
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.pajinate.js313
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js391
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.sparkline.js3054
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js1406
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css23
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css3
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js172
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js727
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js157
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js107
-rw-r--r--www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js128
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/BibTex/BibTexFileExportPrinter.php190
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/BibTex/Item.php185
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/BibTex/README.md91
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php419
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/ListTreeBuilder.php162
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineItem.php62
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineResultPrinter.php139
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineTree.php90
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/README.md53
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/Outline/TemplateBuilder.php156
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/ResourceFormatter.php107
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/iCalendar/IcalTimezoneFormatter.php183
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/iCalendar/iCalendarFileExportPrinter.php368
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/vCard/Address.php87
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/vCard/Email.php50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/vCard/Tel.php51
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/vCard/vCard.php250
-rw-r--r--www/wiki/extensions/SemanticResultFormats/src/vCard/vCardFileExportPrinter.php433
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/bootstrap.php20
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/I18nJsonFileIntegrityTest.php52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-0.bib2
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-1.bib10
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-2.bib8
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-3.bib16
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-01.1.txt14
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-02.0.txt28
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.0.txt37
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.1.txt46
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/image-upload-480.pngbin0 -> 97253 bytes
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.0.txt12
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.1.txt17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.2.txt17
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/JsonTestCaseScriptRunnerTest.php63
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/README.md82
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/bibtex-01.json159
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/datatables-01.json47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/earliest-01.json61
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/eventcalendar-01.json47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-01.json330
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-02.json56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gallery-01.json60
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gantt-01.json167
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-01.json68
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-02.json78
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-03.json131
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/latest-01.json61
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/listwidget-01.json95
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/math-01.json113
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-01.json101
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-02.json105
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-01.json70
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-02.json78
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/timeline-01.json50
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-01.json222
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-02.json91
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-03.json43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-04.json44
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-05.json76
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-06.json127
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-07.json139
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/vcard-01.json136
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/bootstrap.json53
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/ResourcesTest.php81
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/ResultPrinterReflector.php55
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/BibTexFileExportPrinterTest.php149
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/ItemTest.php111
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ArrayTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DataTablesTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DygraphsTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/EventCalendarTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GalleryTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GanttTest.php30
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GraphTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/IncomingTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ListWidgetTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MathTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MediaPlayerTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/PageWidgetTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SparklineTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SpreadsheetTest.php51
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TagCloudTest.php52
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TimeseriesTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TreeTest.php173
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotChartTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotSeriesTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/vCardTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/ListTreeBuilderTest.php41
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineItemTest.php36
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineResultPrinterTest.php96
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineTreeTest.php49
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/TemplateBuilderTest.php43
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/ResourceFormatterTest.php34
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/iCalendar/IcalTimezoneFormatterTest.php89
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/AddressTest.php56
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/EmailTest.php36
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/TelTest.php36
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardFileExportPrinterTest.php133
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardTest.php47
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.test.js79
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.util.test.js119
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.datatables.test.js119
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.eventcalendar.tests.js160
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.filtered.test.js1404
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.gallery.test.js73
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.media.test.js131
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.tagcloud.test.js178
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.eventcalendar.tests.js137
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.optionslist.test.js154
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.panel.test.js57
-rw-r--r--www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.parameters.test.js69
1070 files changed, 280945 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticResultFormats/.gitignore b/www/wiki/extensions/SemanticResultFormats/.gitignore
new file mode 100644
index 00000000..14c434f4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/.gitignore
@@ -0,0 +1,15 @@
+*~
+*.kate-swp
+.*.swp
+
+!.*
+.idea/
+
+composer.lock
+composer.phar
+
+npm-debug.log
+
+vendor/
+extensions/
+node_modules/
diff --git a/www/wiki/extensions/SemanticResultFormats/.jshintignore b/www/wiki/extensions/SemanticResultFormats/.jshintignore
new file mode 100644
index 00000000..8ee3b29a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/.jshintignore
@@ -0,0 +1,7 @@
+# jQuery third-party libs
+resources/jquery/
+
+# other third-party libs
+formats/Exhibit
+formats/JitGraph
+formats/timeline/resources/SimileTimeline \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/.jshintrc b/www/wiki/extensions/SemanticResultFormats/.jshintrc
new file mode 100644
index 00000000..b4fecbac
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/.jshintrc
@@ -0,0 +1,35 @@
+{
+ "predef": [
+ "mediaWiki",
+ "smw",
+ "srf",
+ "semanticMediaWiki",
+ "semanticFormats",
+ "jQuery",
+ "QUnit"
+ ],
+
+ "bitwise": false, // prohibits the use of bitwise operators such as ^ (XOR), | (OR)
+ "camelcase": false, // allows you to force all variable names to use either camelCase style
+ "curly": true, // requires you to always put curly braces around blocks in loops and conditionals
+ "eqeqeq": true, // prohibits the use of == and != in favor of === and !==
+ "forin": false, // requires all for in loops to filter object's items
+ "immed": true, // prohibits the use of immediate function invocations without wrapping them
+ "latedef": true, // prohibits the use of a variable before it was defined
+ "newcap": false, // requires you to capitalize names of constructor functions
+ "noarg": true, // prohibits the use of arguments.caller and arguments.callee
+ "noempty": true, // warns when you have an empty block in your code
+ "nonew": false, // prohibits the use of constructor functions for side-effects
+ "quotmark": "single", // enforces the consistency of quotation marks used throughout your code
+ "regexp": false, // prohibits the use of unsafe . in regular expressions
+ "undef": false, // prohibits the use of explicitly undeclared variables
+ "unused": true, // warns when you define and never use your variables
+ "strict": true, // requires all functions to run in EcmaScript 5's strict mode
+ "trailing": true, // makes it an error to leave a trailing whitespace in your code
+
+ "laxbreak": true, // suppresses most of the warnings about possibly unsafe line breakings
+ "smarttabs": true, // suppresses warnings about mixed tabs
+ "multistr": true, // suppresses warnings about multi-line strings
+
+ "browser": true // defines globals exposed by modern browsers
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/.scrutinizer.yml b/www/wiki/extensions/SemanticResultFormats/.scrutinizer.yml
new file mode 100644
index 00000000..1af8ee2b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/.scrutinizer.yml
@@ -0,0 +1,14 @@
+inherit: true
+
+tools:
+ external_code_coverage:
+ timeout: 900
+ php_code_coverage: false
+ php_code_sniffer: true
+ php_cpd: true
+ php_cs_fixer: true
+ php_loc: true
+ php_mess_detector: true
+ php_pdepend: true
+ php_analyzer: true
+ sensiolabs_security_checker: true \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/.travis.yml b/www/wiki/extensions/SemanticResultFormats/.travis.yml
new file mode 100644
index 00000000..6dfe5634
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/.travis.yml
@@ -0,0 +1,32 @@
+language: php
+
+services:
+ - mysql
+
+matrix:
+ fast_finish: true
+ include:
+ - env: DB=sqlite; MW=master; SMW=~3.0@dev; TYPE=coverage
+ php: 7.3
+ - env: DB=sqlite; MW=REL1_31; SMW=~3.0; MERMAID=dev-master
+ php: 7.0
+ - env: DB=mysql; MW=REL1_31; SMW=~3.0@dev
+ php: 7.0
+ - env: DB=postgres; MW=REL1_32; SMW=~3.0@dev
+ php: 7.2
+ - env: DB=mysql; MW=REL1_33; SMW=~3.0@dev
+ php: 7.2
+ allow_failures:
+ # postgres broken due to https://phabricator.wikimedia.org/T188840
+ - env: DB=postgres; MW=REL1_32; SMW=~3.0@dev
+
+install:
+ - bash ./build/travis/install-mediawiki.sh
+ - bash ./build/travis/install-semantic-result-formats.sh
+
+script:
+ - bash ./build/travis/run-tests.sh
+
+cache:
+ directories:
+ - $HOME/.composer/cache
diff --git a/www/wiki/extensions/SemanticResultFormats/COPYING b/www/wiki/extensions/SemanticResultFormats/COPYING
new file mode 100644
index 00000000..9bc2ff5d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/COPYING
@@ -0,0 +1,103 @@
+'''Semantic Result Formats (SRF)''' is a free, open-source extension to Semantic MediaWiki that adds a large number of further result formats to inline queries, including formats for calendars, timelines, charts, graphs and mathematical functions.
+
+Copyright (C) 2008
+
+
+The license text below "====" applies to all files within this distribution, other than those that are in a directory which contains files named "LICENSE" or "COPYING", or a subdirectory thereof. For those files, the license text contained in said file overrides any license information contained in directories of smaller depth. Alternative licenses are typically used for software that is provided by external parties, and merely packaged with this extension for convenience.
+----
+----
+
+== GNU GENERAL PUBLIC LICENSE ==
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.,<br />
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Everyone is permitted to copy and distribute verbatim copies<br />
+of this license document, but changing it is not allowed.
+
+=== Preamble ===
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software - to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+=== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ===
+
+'''0.''' This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+'''1.''' You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+'''2.''' You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+: '''a)''' You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+: '''b)''' You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+: '''c)''' If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+'''3.''' You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+: '''a)''' Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+: '''b)''' Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+: '''c)''' Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+'''4.''' You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+'''5.''' You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+'''6.''' Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+'''7.''' If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+'''8.''' If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+'''9.''' The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+'''10.''' If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+'''<big>NO WARRANTY</big>'''
+
+'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+'''<big>END OF TERMS AND CONDITIONS</big>'''
diff --git a/www/wiki/extensions/SemanticResultFormats/DefaultSettings.php b/www/wiki/extensions/SemanticResultFormats/DefaultSettings.php
new file mode 100644
index 00000000..b7482584
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/DefaultSettings.php
@@ -0,0 +1,157 @@
+<?php
+
+/**
+ * Settings file for the Semantic Result Formats extension.
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/Semantic_Result_Formats
+ *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Daniel Werner < danweetz@web.de >
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ die( "This file is part of the Semantic Result Formats extension. It is not a valid entry point.\n" );
+}
+
+// The formats you want to be able to use.
+// See the INSTALL file or
+// http://www.semantic-mediawiki.org/wiki/Semantic_Result_Formats#Installation
+$GLOBALS['srfgFormats'] = [
+ 'icalendar',
+ 'vcard',
+ 'bibtex',
+ 'calendar',
+ 'eventcalendar',
+ 'eventline',
+ 'timeline',
+ 'outline',
+ 'gallery',
+ 'jqplotchart',
+ 'jqplotseries',
+ 'sum',
+ 'average',
+ 'min',
+ 'max',
+ 'median',
+ 'product',
+ 'tagcloud',
+ 'valuerank',
+ 'array',
+ 'tree',
+ 'ultree',
+ 'oltree',
+ 'd3chart',
+ 'latest',
+ 'earliest',
+ 'filtered',
+ 'slideshow',
+ 'timeseries',
+ 'sparkline',
+ 'listwidget',
+ 'pagewidget',
+ 'dygraphs',
+ 'media',
+ 'datatables',
+ 'spreadsheet',
+ 'gantt',
+ 'graph'
+ // Boilerplate
+ // Enable access to the format identifier
+ // 'boilerplate',
+
+ // Disabled by default
+
+ // This format can influence performance during execution due to potential
+ // large number of incoming properties assigned to each selected entity
+ // @see Help:Incoming_format
+ // 'incoming',
+
+ // Still in alpha:
+ // 'jitgraph', // Several issues need to be fixed before this can be enabled, most notably it does not work properly with the RL.
+
+ // Disabled by default since they contact external sites:
+ // 'googlebar',
+ // 'googlepie',
+
+ // Unstable/broken:
+ // 'exhibit',
+];
+
+// Load hash format only if HashTables extension is initialised, otherwise 'Array' format is enough
+// FIXME: According to the INSTALL file only formats should be enabled, that "do not require further software to be installed (besides SMW)"
+if( array_key_exists( 'ExtHashTables', $GLOBALS['wgAutoloadClasses'] ) && defined( 'ExtHashTables::VERSION' )
+ && version_compare( ExtHashTables::VERSION, '0.999', '>=' )
+ || isset( $GLOBALS['wgHashTables'] ) // Version < 1.0 alpha
+) {
+ $GLOBALS['srfgFormats'][] = 'hash';
+}
+
+// Used for Array and Hash formats.
+// Allows value as string or object instances of Title or Article classes or an array
+// where index 0 is the page title and 1 is the namespace-index (by default NS_MAIN)
+// also allows defining optional template-arguments by index 'args' as array where a
+// key represents an argument name and a keys associated value an argument value.
+$GLOBALS['srfgArraySep'] = ', ';
+$GLOBALS['srfgArrayPropSep'] = '<PROP>';
+$GLOBALS['srfgArrayManySep'] = '<MANY>';
+$GLOBALS['srfgArrayRecordSep'] = '<RCRD>';
+$GLOBALS['srfgArrayHeaderSep'] = ' ';
+
+/**
+ * Used if Array|Hash result format is not used inline and the standard config values
+ * defined in LocalSettings.php can not be used because they are page references which
+ * can only be evaluated in inline queries
+ *
+ * @var Array
+ */
+$GLOBALS['srfgArraySepTextualFallbacks'] = [
+ 'sep' => $GLOBALS['srfgArraySep'],
+ 'propsep' => $GLOBALS['srfgArrayPropSep'],
+ 'manysep' => $GLOBALS['srfgArrayManySep'],
+ 'recordsep' => $GLOBALS['srfgArrayRecordSep'],
+ 'headersep' => $GLOBALS['srfgArrayHeaderSep']
+];
+
+// $srfgColorScheme
+// Color schems are used among v1.8 jqPlot, and other printers if change
+// those settings please ensure that the content of themes.js has to be
+// altered as well
+$GLOBALS['srfgColorScheme'] = [
+ 'cc124',
+ 'cc128',
+ 'cc129',
+ 'cc173',
+ 'cc210',
+ 'cc252',
+ 'cc267',
+ 'cc294' ,
+ 'cc303',
+ 'cc327',
+ 'ylgn',
+ 'ylgnbu',
+ 'gnbu',
+ 'bugn',
+ 'pubugn',
+ 'pubu',
+ 'bupu',
+ 'rdpu',
+ 'purd',
+ 'orrd',
+ 'ylorrd',
+ 'ylorbr',
+ 'purples',
+ 'blues',
+ 'greens',
+ 'oranges',
+ 'reds',
+ 'greys',
+ 'puor',
+ 'brbg',
+ 'prgn',
+ 'piyg',
+ 'rdbu',
+ 'rdgy',
+ 'rdylbu',
+ 'spectral',
+ 'rdylgn'
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/README.md b/www/wiki/extensions/SemanticResultFormats/README.md
new file mode 100644
index 00000000..4806f992
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/README.md
@@ -0,0 +1,56 @@
+# Semantic Result Formats
+
+[![Build Status](https://secure.travis-ci.org/SemanticMediaWiki/SemanticResultFormats.svg?branch=master)](http://travis-ci.org/SemanticMediaWiki/SemanticResultFormats)
+[![Code Coverage](https://scrutinizer-ci.com/g/SemanticMediaWiki/SemanticResultFormats/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/SemanticMediaWiki/SemanticResultFormats/?branch=master)
+[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/SemanticMediaWiki/SemanticResultFormats/badges/quality-score.png?s=a2f091e91cb9c8aa297e028f2f30d99153446796)](https://scrutinizer-ci.com/g/SemanticMediaWiki/SemanticResultFormats/)
+[![Latest Stable Version](https://poser.pugx.org/mediawiki/semantic-result-formats/version.png)](https://packagist.org/packages/mediawiki/semantic-result-formats)
+[![Packagist download count](https://poser.pugx.org/mediawiki/semantic-result-formats/d/total.png)](https://packagist.org/packages/mediawiki/semantic-result-formats)
+
+Semantic Result Formats (a.k.a. SRF) is an extension to MediaWiki that bundles a number of result
+formats for [Semantic MediaWiki's][smw] inline queries. The individual formats can be added to the
+installation independently. For more information, visit the [SRF homepage][srf] or consult the
+[release notes](RELEASE-NOTES.md).
+
+## Requirements
+
+- PHP 7.0 or later
+- MediaWiki 1.31 or later
+- Semantic MediaWiki 3.0 or later
+
+## Installation
+
+The recommended way to install this extension is by using [Composer][composer]. See the detailed
+[installation guide](docs/INSTALL.md) which also contains information about compatibility and
+configuration.
+
+## Contribution and support
+
+Development is coordinated by James Hong Kong and Jeroen De Dauw.
+
+If you have remarks, questions, or suggestions, please ask them on semediawiki-users@lists.sourceforge.net.
+You can subscribe to this list [here](https://lists.sourceforge.net/lists/listinfo/semediawiki-user).
+
+If you want to contribute work to the project please subscribe to the
+developers mailing list and have a look at the [contribution guildline](/CONTRIBUTING.md).
+A list of people who have made contributions in the past can be found [here][contributors].
+
+* [File an issue](https://github.com/SemanticMediaWiki/SemanticResultFormats/issues)
+* [Submit a pull request](https://github.com/SemanticMediaWiki/SemanticResultFormats/pulls)
+* Ask a question on [the mailing list](https://www.semantic-mediawiki.org/wiki/Mailing_list)
+
+## Tests
+
+This extension provides unit and integration tests and are normally run by a [continues integration platform][travis]
+but can also be executed locally using the shortcut command `composer phpunit` from the extension base directory.
+
+## License
+
+Generally published under [GNU General Public License 2.0 or later][licence] together with
+third-party plugins and their license.
+
+[smw]: https://github.com/SemanticMediaWiki/SemanticMediaWiki
+[travis]: https://travis-ci.org/SemanticMediaWiki/SemanticResultFormats
+[srf]: https://www.semantic-mediawiki.org/wiki/Extension:Semantic_Result_Formats
+[composer]: https://getcomposer.org/
+[contributors]: https://github.com/SemanticMediaWiki/SemanticResultFormats/graphs/contributors
+[licence]: https://www.gnu.org/copyleft/gpl.html
diff --git a/www/wiki/extensions/SemanticResultFormats/RELEASE-NOTES.md b/www/wiki/extensions/SemanticResultFormats/RELEASE-NOTES.md
new file mode 100644
index 00000000..2c63772c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/RELEASE-NOTES.md
@@ -0,0 +1,562 @@
+These are the release notes for the [Semantic Result Formats](https://www.semantic-mediawiki.org/wiki/Extension:Semantic_Result_Formats) (a.k.a SRF) MediaWiki extension.
+
+## SRF 3.1.0
+
+Released on August 18, 2019.
+
+* Minimum requirement for
+ * PHP changed to version 7.0 and later
+ * MediaWiki changed to version 1.31 and later
+* Added compatibility with Semantic MediaWiki 3.1.x
+* Improved compatibility with PHP 7.2+
+* Added `spreadsheet` format (by Stephan Gambke)
+* Deprecated `excel` format (by Stephan Gambke)
+* Added `gantt` result format (by Sebastian Schmid)
+* Added `filename` parameter to the `vcard` format (by James Hong Kong)
+* Added `template` parameter to the `outline` format (by James Hong Kong)
+* Added css `class` parameter to the `tree` format (by Stephan Gambke)
+* Improved `timeseries` format (by Christian Zagrodnick)
+ * Fixed `uncaught exception: Invalid dimensions for plot`
+ * Only correct plot height when there are tabs
+* Other bug fixes and code improvements
+* Made the extension installable without the `php-gd` PHP extension
+* Updated translations (by translatewiki.net community)
+
+## SRF 3.0.1
+
+Released on March 27, 2019.
+
+* [#391](https://github.com/SemanticMediaWiki/SemanticResultFormats/issues/391) Updates build tools, thus fixing a security issue for the "filtered" format (by Stephan Gambke)
+* [#444](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/444) Removed a feature switch, now always using `TraditionalImageGallery`; fixes a potential "method not found" warning both for the "gallery" format (by Stephan Gambke)
+* [#462](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/462) Removed usage of `$this->mFormat` which was no longer taken into account thus fixing the "listwidget" format (by Stephan Gambke)
+* [#471](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/471) Updated to secure versions of dependencies for the "filtered" format (by Stephan Gambke)
+* Updated translations (by translatewiki.net community)
+
+## SRF 3.0.0
+
+Released on October 12, 2018.
+
+* Minimum requirement for
+ * PHP changed to version 5.6 and later
+ * MediaWiki changed to version 1.27 and later
+ * Semantic MediaWiki changed to version 3.0 and later
+* #438 Added support for extension registration via "extension.json" (by James Hong Kong)
+ → Now you have to use `wfLoadExtension( 'SemanticResultFormats' );` in the "LocalSettings.php" file to invoke the extension
+* Improved filtered format: More options, better test coverage, re-enabled by default (by Stephan Gambke)
+* Refactored vcard format: Mostly code improvements (by James Hong Kong)
+* [#248](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/248) Fixed localization of numbers in the math result formats (by James Hong Kong)
+* [#311](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/365) Improved display of user preference options on special page "Preferences" (by James Hong Kong)
+* [#365](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/365) Added support for the latest versions of the GraphViz extension (by Sam Wilson)
+* [#375](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/375) Fixed exposing of file dimensions in captions for the "gallery" format (by James Hong Kong)
+* [#384](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/384) Updated "fullcalendar" library as well as added the "list views" feature for the "eventcalendar" format (by Nischay Nahata and James Hong Kong)
+* [#435](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/435) Fixed time zone transitions (by James Hong Kong)
+* [#436](https://github.com/SemanticMediaWiki/SemanticResultFormats/pull/436) Removed the `template arguments` parameter of the "gallery" format (by Stephan Gambke)
+* Added support for installation together with the latest versions of the Maps extension (by Jeroen De Dauw)
+* Provided general code improvements as well as additional integrations tests for several result formats
+* Updated translations (by translatewiki.net community)
+
+## SRF 2.5.6
+
+Released on September 7, 2018.
+
+* 399: Fixes columnsearchinput field being always disabled for the "datatables" format (by Matthew A.Thompson)
+* 410 Added support for installation together with the latest versions of the Maps extension (by Jeroen De Dauw)
+
+## SRF 2.5.5
+
+Released on April 4, 2018.
+
+* #354: Fixed value filter labels for the "filtered" format (by Stephan Gambke)
+* #355: Fixed missing namespace in the "tagcloud" format (by Cindy Cicalese)
+* #361: Set stacking context for srf-gallery-slideshow in the "gallery" format (by Stephan Gambke)
+* #374: Fixed "select2" list elements rendering outside of containing element for the "filtered" format (by Matthew A.Thompson)
+* #379: Fixed result printers still using the Google Chart API ("googlechart", "googlepie") via http (by Karsten Hoffmeyer)
+* #383: Updated some "leaflet" and "select2" modules and fixed "package-lock.json" for the "fitered" format (by Stephan Gambke)
+
+## SRF 2.5.4
+
+Released on November 13, 2017.
+
+* #337: Fixed style issues when collapsing filters for the "filtered" format (by Stephan Gambke)
+* #343: Fixed style and layout fixes and optimise performance of the "filtered" format (by Stephan Gambke)
+* #346: Brings more performance improvements and adds missing system messages for the value filter of the "filtered" format (by Stephan Gambke)
+* #349: Removed `default` parameter from "earliest" and "latest" formats (by James Hong Kong)
+* #351: Added `map view marker icon property` and `map view marker icons` parameters to allow map icons depending on a printout value to the "filtered" format (by Stephan Gambke)
+* Made map assets load over HTTPS for the "exhibit" format (by Máté Szabó)
+
+## SRF 2.5.3
+
+Released on October 25, 2017.
+
+* #293: Fixes resource loading for the "timeline" format (by James Hong Kong)
+* #295: Fixes issues with subobject for the "timeline" format (by James Hong Kong)
+* #299: Brings improvements to the "filtered" format as authored with the following pull requests: (by Stephan Gambke)
+ - #224: Makes radio buttons belong to the same button group
+ - #278: Adds a multi-select dropdown or similar for value filters
+ - #286: Brings a reworked number filter
+ - #291: Fixes `list view template` to actually show the template instead of defaulting to a table
+* #300: Brings improvements and fixes to the "filtered" format: (by Stephan Gambke)
+ - Brings back checkboxes for value filter with only few values
+ - Brings new query parameter ` |+value filter max checkboxes`
+ - Allows for easier installation of "data-values/geo"
+* #302: Fixes error messages shown in the instance language instead of the user language for the "filtered" format (by Stephan Gambke)
+* #305: Fixes "SRF\Filtered\Filtered::setParser() must be an instance of Parser..." for the "filtered" format (by Stephan Gambke)
+* Fixes issues with HTML-encoded values sent by JavaScript for the "filtered" format (by Stephan Gambke)
+* #324: Brings improvements to the "filtered" format as authored with the following pull requests: (by Stephan Gambke)
+ - #318: Wrap input elements of the Value filter (checkboxes and radioboxes) in label elements. This way they will also be triggered when only the label text is clicked.
+ - #322: Show a spinner while filtering. This will block users from triggering further filter events while filtering is still ongoing.
+ - #323: Adds printout parameter`|+show if undefined`. Setting it makes filters show a result item even if the printout does not contain a value.
+* #328: Brings useability fixes to the "filtered" foramat like the fix for the styling of Value filter for long labels as well as the fix for the slider grid when showing less than 4 step values (by Stephan Gambke)
+* #331: Switches the "filtered" format to use Less instead of CSS (by Stephan Gambke)
+* #334: Adds an On/Off switch for filters to the "filtered" format (by Stephan Gambke)
+
+## SRF 2.5.2
+
+Released on August 17, 2017.
+
+* #266: Fixed bug #224: The and/or selectors can not be selected at the same time anymore in "filtered" format (by Stephan Gambke)
+* #269: Fixed bug #263: Fix the `link` and `userparam` parameters on the "tree" format and provide tests for it (by Stephan Gambke)
+* #276: Use type `parser-html` for JsonScript tests of the "tree" format (by Stephan Gambke)
+* #284: Fixed rendering of the "calendar" format in Internet Explorer (by kwji)
+* #285: Add `+hide` for all views of the "filtered" format (by Stephan Gambke)
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.5.1
+
+Released on July 11, 2017.
+
+* #236: Fixed bug #234: Make the "oltree" format to actually use `<ol>`
+* #237: Fixed bug #235: Fix the `template` parameter to the "tree", "oltree" and "ultree" formats
+* Fixed bug #253: Remove obsolete `"div"` element `align="justify"` from the "tagcloud" and "gallery" formats
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.5.0
+
+Released on June 13, 2017.
+
+* Dropped compatibility with PHP 5.3 and 5.4
+* Dropped compatibility with MediaWiki 1.19 to 1.22
+* Updated installation instructions in [INSTALL.md](INSTALL.md)
+* Changed bootstrapping of SRF to make it work with SMW 3.0+ (by James Hong Kong)
+* Re-organized file layout unit testing and added JSONScript integration testing facility from SMW (by Stephan Gambke)
+* Improved math format to recognize output format "-" (by Sebastian Schmid (gesinn.it))
+* Improved eventcalendar format: Added parameter 'clicktarget' to allow users to define a target URL that get's called when clicking on a calendar date. (by Felix Aba)
+* Reworked tree format (by Stephan Gambke)
+* Reworked filtered format which is no longer available by default (by Stephan Gambke)
+* Fixed bug #199 in HTML utils JS script (by gesinn.it)
+* Fixed bug #207: Added missing system messages for the process format and improved existing system messages for the graph format (by Karsten Hoffmeyer)
+* Fixed bug #215: Added missing argument 4 for `GraphViz::graphvizParserHook()` (by Karsten Hoffmeyer)
+* Fixed jplayer file path used by media format (by Stephan Gambke)
+* Fixed gallery format to ensure compatibility with MW 1.23+ (by James Hong Kong)
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.4.3
+
+Released on May 7, 2017
+
+* #199: Fixed uncaught TypeError on 'in' operator to search for 'length' for "eventcalendar" format (by gesinn.it)
+
+## SRF 2.4.2
+
+Released on February 25, 2017
+
+* Fixed slidshow format from using a dependancy removed with MediaWiki 1.26+ (by Stephan Gambke)
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.4.1
+
+Released on December 20, 2016.
+
+* Fixed excel format to throw an error if the required phpExcel library is missing (by Stephan Gambke)
+* Provided minor internal code changes to the excel format (by Stephan Gambke)
+* Fixed datatables format not reading property 'aTypes' of undefined TypeError (by James Hong Kong)
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.4.0
+
+Released on October 10, 2016.
+
+### Enhancements
+
+* Added link support to the media format (by James Hong Kong)
+* Added displaytitle label support to filtered format (by Simon Heimler)
+* Improved list and page widget CSS (by James Hong Kong)
+* Updated jplayer to version 2.9.2 (by James Hong Kong)
+* Improved compatibility with the latest versions of MediaWiki (by Florian Schmidt)
+* Improved internationalization (by Karsten Hoffmeyer)
+* Made installation via Composer more robust (by Cindy Cicalese)
+* Removed the Ploticus format previously disabled due to security concerns (by Jeroen De Dauw)
+* Provided translation updates (by translatewiki.net community)
+
+### Bugfixes
+
+* Fixed RuntimeError when selecting excel format in Special:Ask (by Stephan Gambke)
+* Fixed bug causing occasional exceptions in the calendar format (by Mark A. Hershberger)
+* Fixed bug in timeseries format that caused the value 0 to be excluded (by James Hong Kong)
+* Fixed bug in the calendar parser functions (by James Montalvo)
+* Fixed bug in the datatables format when having empty printouts (by Fr Jeremy Krieg)
+* Fixed bug in filtered format that broke the format on browsers supporting the
+ [Array.prototype.values()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/values) method
+
+## SRF 2.3.0
+
+Released on September 24, 2015.
+
+* Added table view to filtered format
+* Fixed eventcalendar format to return a truncated version of strings in tooltips
+* Internal code cleanup concerning the calendar format
+* Internal code cleanup concerning the tagcould format
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.2.0
+
+Released on July 30, 2015.
+
+* Fixed filtered format so that filters work for ol/ul type lists
+* Fixed gallery format by adding a required dependency for the carousel option to the widget parameter
+* Enhanced calendar format by adding the startmonth and startyear parameters
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 2.1.2
+
+Released on February 26, 2015.
+
+* Fixed bug in the slideshow format API
+
+## SRF 2.1.1
+
+Released on February 4, 2015.
+
+* Fixed various jQuery 1.9+ issues that appeared in connection with MW 1.24+ including `jquery.jqplot`, `jquery.fancybox`, and`jquery.jgrid`
+* Added replacement pattern for `%3A` in `gallery` overlay format (65abda9)
+* Fixed the usage of plain-text title attribute in `gallery` overlay format (f18f3ea8)
+* Added support for apostrophes in title text `gallery` overlay format (8dec4106)
+* #79 Fixed `event calender` class parameter usage
+* #73 Fixed `icalendar` escaping issues (as per RFC)
+
+## SRF 2.0.0
+
+Released on August 6, 2014.
+
+* #26 Fixed not showing up of graphvis legend when it should
+* #35 Fixed error in the gallary format for a null object
+* #37 Fixed error in the timeline format for named arguments
+* #43 Fixed graphname parameter in the graphviz format
+* [14daff1](https://github.com/SemanticMediaWiki/SemanticResultFormats/commit/14daff10350190634b96f644961beb15d0b29e09)
+commit added support for date/time values to the [excel format](https://www.semantic-mediawiki.org/wiki/Help:Excel_format)
+* #46 Added support for `format=graph` using Composer `mediawiki/graph-viz` package
+* #47 Added parameters 'filename' (the download file name for the generated file) and 'templatefile' (a template file
+ from the NS_FILE namespace used for formatting the generated file) to [excel format](https://www.semantic-mediawiki.org/wiki/Help:Excel_format)
+* #51 Fixed null title issue in Gallery.php for MW 1.23+
+* #52 Fixed `format=process` exception that was caused by missing message parameters
+* #53 Updated jQuery blockUI plugin to v.2.66.0-2013.10.09
+* Provided translation updates (by translatewiki.net community)
+
+## SRF 1.9.1
+
+Released on April 25, 2014.
+
+* #13 Fixed PHP warning when running PHP >=5.1 in strict mode
+* #16 Improved handling of empty values in the filtered format
+* #19 Fixed duplicate headers bug in the excel format
+* #22 The excel format is now enabled by default when PHPExcel is loaded
+* #23 The PHPUnit bootstrap now works on Windows
+* #24 Added support for the new MediaWiki i18n JSON system
+* #25 Fixed resource path issue occurring on some installations
+* #27 Fixed error in the tagcloud format occurring when referencing a non-existing page
+* #31 Added template parameter to the timeline format
+
+## SRF 1.9.0.1
+
+Released on January 17, 2014.
+
+* #7 Fix tagcloud rendering on special pages and when using templates
+
+## SRF 1.9.0
+
+Released on January 10, 2014.
+
+### Compatibility changes
+
+* Changed minimum MediaWiki version from 1.17 to 1.19.
+* Changed minimum PHP version from 5.2.x. to 5.3.x.
+* Changed Semantic MediaWiki compatibility from 1.8.x to 1.9.x.
+* Full compatibility with MediaWiki 1.19, 1.20, 1.21, 1.22 and forward-compatibility with 1.23.
+* Deleted SRF_Settings.php entry point, the main entry point is SemanticResultFormats.php
+* [Installation](INSTALL.md) is now done via the [Composer](http://getcomposer.org/) dependency manager.
+
+### New formats
+
+* [media](https://www.semantic-mediawiki.org/wiki/Help:Media_format) (Added by James Hong Kong)
+* [excel](https://www.semantic-mediawiki.org/wiki/Help:Excel_format) (Requires PHPExcel, disabled by default) (Added by Kim Eik)
+
+### New features
+
+* [EventCalendar](https://www.semantic-mediawiki.org/wiki/Help:Eventcalendar_format) SMWAPI/Ajax integration
+* [tree format](https://www.semantic-mediawiki.org/wiki/Help:Tree_format): new parameters 'root' and 'start level'
+
+### Other improvements and changes
+
+* jquery.tagcanvas increase from 1.18 to 1.20
+* jquery.responsiveslides increase from v1.32 to v1.53
+* jquery.sparkline increase from 2.0 to 2.1
+* d3 increase from d3.vs to d3.v3
+* Introduce PHP SRF\ namespaces
+
+### Bug fixes
+
+* tree format: root elements not included
+
+## SRF 1.8.0
+
+Released on December 2, 2012.
+
+### Compatibility changes
+
+* Changed minimum MediaWiki version from 1.16 to 1.17.
+* Changed minimum Semantic MediaWiki version from 1.7 to 1.8.
+* Full compatibility with MediaWiki 1.19 and forward-compatibility with 1.20.
+* Changed minimum Validator version from 0.4 to 1.0.
+* jqplotbar and jqplotpie format are replaced by jqplotchart format
+* SRF_Settings.php has been deprecated (will be removed in 1.9) as entry point, use SemanticResultFormats.php instead
+
+### New formats
+
+* slideshow (written by Stephan Gambke)
+* listwidget (bug 37721, I54660c15) (James Hong Kong)
+* sparkline format (I911862ce) (James Hong Kong)
+* timeseries printer (Ibad00690) (James Hong Kong)
+* d3chart format (I4baa7df8) (James Hong Kong)
+* jqplotseries format (I3c8847aa) (James Hong Kong)
+* jqplotchart format (I3c8847aa) (James Hong Kong)
+* incoming format (Ie5be9196) (James Hong Kong)
+* syndication feed (atom, rss) (bug 38636, Ia3cdc243) (James Hong Kong)
+* dygraphs chart format (Ibac4b753) (James Hong Kong)
+* event calendar (Iaff44b71) (James Hong Kong)
+* earliest format (written by Jeroen De Dauw, Nischay Nahata)
+* latest format (written by Jeroen De Dauw, Nischay Nahata)
+
+### New features
+
+* (Ice7ba7ea) Enable tableview plugin support for timeseries, jqplotseries, and dygraphs format
+* (bug 38094) Tag cloud format added 'sphere widget' (James Hong Kong)
+* (I6920ae49) Tag cloud format added 'wordcloud widget' (James Hong Kong)
+* (bug 37695) Tag cloud format added template support (James Hong Kong)
+* (bug 38184) Gallery format added 'slideshow widget' (James Hong Kong)
+* (bug 38357) Gallery format added 'overlay' parameter enabling gallery slideshow/carousel image overlay (James Hong Kong)
+* (I7c49a644) Gallery format added redirects to enable images to be redirect to another target (James Hong Kong)
+* (bug 38296, Ic9f5e186) Gallery format fixed Special:Ask gallery display error (James Hong Kong)
+* (I338b6b19, I7a0e663b) Gallery format added support for pointing to the subject property in the gallery property parameters using "-"
+* (I762cde6a) Value rank format added template support (James Hong Kong)
+
+### Other improvements
+
+* Added test file support (see SemanticResultFormats/tests/...)
+* All formats have been moved (see SemanticResultFormats/formats/...)
+* Added new folder (SemanticResultFormats/resources/...) where all external plug-ins will be successively been moved
+* Introduce a new array-based syntax to define parameters (see Validator/IParameterDefinition class)
+
+### Bug fixes
+
+* (bug 38258, I10be92c9) Fix authors/editors in bibtex
+
+## SRF 1.7.1
+
+Released on March 8, 2012.
+
+* Fixed issue with the graphlenegd parameter in the graph format (bug 33745).
+* Added 'default' parameter to math formats (bug 34983).
+* Added 'galleryformat' parameter with carousel option (bug 34411) (James Hong Kong)
+
+New formats in this version are:
+
+* tree, ultree, oltree (written by Stephan Gambke)
+* JitGraph (still in alpha, disabled by default) (written by Alex Shapovalov) (bug 32877)
+* filtered (still in alpha, disabled by default) (written by Stephan Gambke)
+
+## SRF 1.7.0
+
+Released on January 1, 2012.
+
+* Compatibility with SMW 1.7 and later.
+* Dropped support for MediaWiki 1.15.x and SMW < 1.7.
+* Added warning message to jqplotpie and jqplotbar shown when there are no results instead of a non-working chart.
+* Added value distribution support to jqplotpie and jqplotbar.
+* Added min parameter to jqplotbar to set the minimun value for the Y-axis.
+* Added pointlabel parameter to jqplotbar and chartlegend, legendlocation,
+ datalabels and datalabeltype parameters to jqplotpie based on a patches by James Hong Kong.
+* Made array and hash formats compatible with 'Array' extension 2.0 and 'HashTables' 1.0.
+* Added summary parameter to the icalendar format.
+
+New formats in this version are:
+
+* valuerank (written by Daniel Schuba)
+* D3Line, D3Bar and D3Treemap (written by James Hong Kong) (requires MW 1.17 or later)
+
+## SRF 1.6.2
+
+Released on September 18, 2011.
+
+* Fixed error in math printer when there are no numerical results.
+* Fixed vCard compatibility with SMW 1.6 and later.
+* Fixed array compatibility with SMW 1.6 and later.
+* Added median and product formats to the list of default enabled formats.
+
+## SRF 1.6.1
+
+Released on August 20, 2011.
+
+* Fixed rendering bug in the tagcloud format occuring for inline queries.
+* Fixed jqPlotBar and jqPlotPie rendering on Special:Ask and other special pages.
+* Cleaned up the jqPlotBar format somewhat.
+* Dropped compatibility with SMW < 1.6 for the tagcloud format.
+
+## SRF 1.6
+
+Released on July 30, 2011.
+
+Changes in this version:
+
+* Added compatibility with SMW 1.6.
+* Rewrote math formats for efficiency, correct recursion and handling of multiple numerical properties.
+* Cleaned up the graph format.
+* Fixed division by zero issue (oh shii~) in the tagcloud format.
+* Added parameter descriptions to the graph and ploticus formats.
+* Added support for SMW 1.6 style parameter handling to the tagcloud format.
+* Somewhat cleaned up the BibTeX format.
+* Fixed double HTML escaping issue in the tagcloud format.
+* Added fileextensions parameter to the Gallery format and added missing parameter description messages.
+
+New formats in this version are:
+
+* product (written by Jeroen De Dauw)
+* median (written by Jeroen De Dauw)
+
+## SRF 1.5.3
+
+Released on February 9, 2011.
+
+Changes in this version:
+
+* Support for images specified by properties in the gallery format.
+* Fixes to the calendar and jqplot formats.
+* Improvements to the timeline and eventline formats.
+
+New formats in this version are:
+
+* tagcloud (written by Jeroen De Dauw)
+
+## SRF 1.5.2
+
+Released on January 11, 2011.
+
+Changes in this version:
+
+* Handling for ResourceLoader in MediaWiki 1.17+ added for
+ 'timeline', 'eventline', 'jqplotbar' and 'jqplotpie' formats.
+* Visualization improvements for 'process' format.
+
+## SRF 1.5.1
+
+Released on August 26, 2010.
+
+New formats in this version are:
+
+* jqplotbar (written by Sanyam Goyal and Yaron Koren)
+* jqplotpie (written by Sanyam Goyal and Yaron Koren)
+
+Other changes:
+
+* Added support for 'semantic' extension type, added by SMW 1.5.2 and above.
+
+## SRF 1.5.0
+
+Released on June 22, 2010.
+
+New formats in this version are:
+
+* gallery (written by Rowan Rodrik van der Molen)
+
+Changes in this version:
+
+* the functions getName() and getParameters() were added to most formats, for use in Special:Ask
+* a 'lang' parameter was added to the 'calendar' format
+* improvements in 'exhibit' result format
+** new facet styles (slider and search)
+
+## SRF 1.4.5
+
+Released on June 3, 2009.
+
+New formats in this version are:
+
+* outline (written by Yaron Koren)
+
+Other changes:
+
+* the 'ploticus' format was disabled, due to a security hole
+* the 'calendar' format no longer requires disabling of caching
+* imagemap links were fixed for the 'graph' format
+* handling was added for the Admin Links extension
+
+## SRF 1.4.4
+
+Released on April 16, 2009.
+
+* improvements in 'exhibit' result format:
+** required scripts, styles, images largely included (no remote server access needed)
+** fixes for Timeline
+** Usage of Google Maps now requires to set a Google Maps key (as obtained from Google)
+ in LocalSettings.php:
+ $wgGoogleMapsKey = 'yourkey';
+ If this is not set, the "maps" view will be disabled.
+** many formatting improvements
+** improved compatibility with Internet Explorer (esp. IE8)
+** only Timeline and Map will access a remote server now
+
+* other changes:
+** a getName() method was added to many of the formats
+** SRF_ParserFunctions.php file added, holding parser functions for use by
+'calendar' format.
+
+## SRF 1.4.3
+
+Released on March 2, 2009.
+
+New formats in this version are:
+* bibtex (written by Steren Giannini)
+
+Also, handling of templates was added to the 'calendar' format by David
+Loomer.
+
+## SRF 1.4.2
+
+Released on February 10, 2009.
+
+The initialization of formats was changed to use the global $srfgFormats
+variable, instead of the srfInit() function.
+
+New formats in this version are:
+* ploticus (written by Joel Natividad)
+* exhibit (written by Fabian Howahl and using code from MIT CSAIL)
+* average (written by Yaron Koren)
+* min (written by Yaron Koren)
+* max (written by Yaron Koren)
+* sum (written by Nathan Yergler)
+* moved existing formats 'vcard' and 'icalendar' from SMW
+
+## SRF 1.4.0
+
+Released on November 26, 2008.
+
+This is the initial release of Semantic Result Formats. The version number
+was chosen in order to be aligned to the Semantic MediaWiki core distribution.
+SRF 1.4.0 is compatible to SMW 1.4.0 and thus equally versioned.
+
+The initial sets of Semantic Result Formats are:
+* calendar (written by Yaron Koren)
+* eventline (written by Markus Krötzsch and based on code by MIT's Simile group)
+* googlebar (written by Denny Vrandecic)
+* googlepie (written by Denny Vrandecic)
+* graph (written by Frank Dengler)
+* timeline (written by Markus Krötzsch and based on code by MIT's Simile group)
diff --git a/www/wiki/extensions/SemanticResultFormats/Resources.php b/www/wiki/extensions/SemanticResultFormats/Resources.php
new file mode 100644
index 00000000..26871a9e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/Resources.php
@@ -0,0 +1,1042 @@
+<?php
+
+/**
+ * The resource module definitions for the Semantic Result Formats extension.
+ *
+ * @since 1.7
+ *
+ * @licence GNU GPL v2 or later
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author mwjames
+ */
+
+$moduleTemplate = [
+ 'localBasePath' => __DIR__ ,
+ 'remoteExtPath' => 'SemanticResultFormats'
+];
+
+$formatModule = [
+ 'localBasePath' => __DIR__ . '/formats',
+ 'remoteExtPath' => 'SemanticResultFormats/formats'
+];
+
+$calendarMessages = [ 'messages' => [
+ 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august',
+ 'september', 'october', 'november', 'december',
+ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec',
+ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday',
+ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat',
+ 'srf-ui-eventcalendar-label-today', 'srf-ui-eventcalendar-label-month',
+ 'srf-ui-eventcalendar-label-week', 'srf-ui-eventcalendar-label-day',
+ 'srf-ui-eventcalendar-label-listmonth', 'srf-ui-eventcalendar-label-listweek',
+ 'srf-ui-eventcalendar-label-listday',
+ 'srf-ui-eventcalendar-label-allday', 'srf-ui-eventcalendar-format-time',
+ 'srf-ui-eventcalendar-format-time-agenda', 'srf-ui-eventcalendar-format-axis',
+ 'srf-ui-eventcalendar-format-title-month', 'srf-ui-eventcalendar-format-title-week',
+ 'srf-ui-eventcalendar-format-title-day', 'srf-ui-eventcalendar-format-column-month',
+ 'srf-ui-eventcalendar-format-column-week', 'srf-ui-eventcalendar-format-column-day',
+ 'srf-ui-tooltip-title-legend', 'srf-ui-tooltip-title-filter',
+ 'srf-ui-common-label-refresh', 'srf-ui-eventcalendar-label-update-success',
+ 'srf-ui-eventcalendar-label-update-error', 'srf-ui-common-label-parameters',
+ 'srf-ui-common-label-paneview', 'srf-ui-common-label-daterange',
+ 'srf-ui-eventcalendar-click-popup',
+ ]
+];
+
+return [
+ //SRF common and non printer specific resources
+ 'ext.jquery.easing' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.easing.js'
+ ],
+
+ // Fancybox
+ 'ext.jquery.fancybox' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js',
+ 'styles' => 'resources/jquery/fancybox/jquery.fancybox-1.3.4.css',
+ 'dependencies' => [
+ 'ext.jquery.easing',
+ 'ext.jquery.migration.browser'
+ ]
+ ],
+
+ // Multiselect
+ 'ext.jquery.multiselect' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/multiselect/jquery.multiselect.js',
+ 'styles' => 'resources/jquery/multiselect/jquery.multiselect.css',
+ 'dependencies' => [
+ 'jquery.ui.core',
+ 'jquery.ui.widget'
+ ]
+ ],
+
+ // Multiselect filter
+ 'ext.jquery.multiselect.filter' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/multiselect/jquery.multiselect.filter.js',
+ 'styles' => 'resources/jquery/multiselect/jquery.multiselect.filter.css',
+ 'dependencies' => 'ext.jquery.multiselect'
+ ],
+
+ // blockUI plugin
+ 'ext.jquery.blockUI' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.blockUI.js'
+ ],
+
+ // jqgrid
+ 'ext.jquery.jqgrid' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/jqgrid/jquery.jqGrid.js',
+ 'resources/jquery/jqgrid/grid.locale-en.js'
+ ],
+ 'styles' => 'resources/jquery/jqgrid/ui.jqgrid.css',
+ 'dependencies' => [
+ 'jquery.ui.core',
+ 'ext.jquery.migration.browser'
+ ]
+ ],
+
+ // Flot
+ 'ext.jquery.flot' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/flot/jquery.flot.js',
+ 'resources/jquery/flot/jquery.flot.selection.js'
+ ]
+ ],
+
+ // Provide migration tool to avoid jqplot to fail with
+ // $.browser is undefined jquery.jqplot.js:398 caused
+ // by jQuery 1.9+
+ // @see https://github.com/SemanticMediaWiki/SemanticMediaWiki/issues/356
+ 'ext.jquery.migration.browser' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/ext.jquery.migration.browser.js'
+ ]
+ ],
+
+ // SRF specific printer independent utility resources
+ 'ext.srf' => $moduleTemplate + [
+ 'scripts' => 'resources/ext.srf.js',
+ 'styles' => [
+ 'resources/ext.srf.css',
+
+ // Someone broke the CSS loading (Suspect bug 46401) in 1.22
+ // until this is fixed force styles to be loaded at the very start
+ // to avoid display clutter
+ 'formats/calendar/resources/ext.srf.formats.eventcalendar.css',
+ ],
+ 'dependencies' => 'ext.smw.api',
+ 'position' => 'top',
+ 'group' => 'ext.srf'
+ ],
+
+ 'ext.srf.styles' => $moduleTemplate + [
+ 'styles' => [
+ 'resources/ext.srf.css',
+ ],
+ 'position' => 'top',
+ 'group' => 'ext.srf'
+ ],
+
+ // SMW/SRF query/result api module
+ 'ext.srf.api' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/ext.srf.api.results.js',
+ 'resources/ext.srf.api.query.js',
+ ],
+ 'position' => 'top',
+ 'dependencies' => 'ext.srf',
+ 'group' => 'ext.srf'
+ ],
+
+ // Collects utility methods that are shared among different printers
+ 'ext.srf.util' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/ext.srf.util.js',
+ 'resources/ext.srf.util.html.js',
+ ],
+ 'dependencies' => [
+ 'ext.srf',
+ 'ext.jquery.jStorage',
+ 'ext.jquery.blockUI',
+ 'jquery.client',
+ 'mediawiki.Title',
+ ],
+ 'group' => 'ext.srf'
+ ],
+
+ // SRF widgets
+ 'ext.srf.widgets' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/widgets/ext.srf.widgets.panel.js',
+ 'resources/widgets/ext.srf.widgets.parameters.js',
+ 'resources/widgets/ext.srf.widgets.optionslist.js'
+ ],
+ 'dependencies' => [
+ 'ext.srf',
+ 'jquery.ui.core',
+ 'jquery.ui.widget',
+ 'jquery.ui.button',
+ 'jquery.ui.slider',
+ 'ext.jquery.multiselect'
+ ],
+ 'messages' => [
+ 'srf-ui-widgets-label-parameter-limit',
+ ],
+ 'group' => 'ext.srf'
+ ],
+
+ 'ext.srf.util.grid' => $moduleTemplate + [
+ 'scripts' => 'resources/ext.srf.util.grid.js',
+ 'styles' => 'resources/ext.srf.util.grid.css',
+ 'dependencies' => [
+ 'jquery.ui.tabs',
+ 'ext.srf.util',
+ 'ext.jquery.jqgrid',
+ ],
+ 'messages' => [
+ 'ask',
+ 'srf-ui-gridview-label-series',
+ 'srf-ui-gridview-label-item',
+ 'srf-ui-gridview-label-value',
+ 'srf-ui-gridview-label-chart-tab',
+ 'srf-ui-gridview-label-data-tab',
+ 'srf-ui-gridview-label-info-tab'
+ ],
+ 'position' => 'top',
+ 'group' => 'ext.srf'
+ ],
+
+ // Sparkline
+ 'ext.jquery.sparkline' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.sparkline.js',
+ 'dependencies' => [
+ 'ext.jquery.migration.browser'
+ ]
+ ],
+
+ 'ext.srf.sparkline' => $formatModule + [
+ 'scripts' => 'sparkline/resources/ext.srf.sparkline.js',
+ 'dependencies' => [
+ 'ext.srf.util',
+ 'ext.jquery.sparkline'
+ ],
+ 'group' => 'ext.srf',
+ 'position' => 'top',
+ ],
+
+ // Dygraphs
+ 'ext.dygraphs.combined' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/dygraphs/dygraph-combined.js'
+ ],
+ 'ext.srf.dygraphs' => $formatModule + [
+ 'scripts' => [
+ 'dygraphs/resources/ext.srf.dygraphs.js',
+ '../resources/jquery/dygraphs/dygraph-combined.js'
+ ],
+ 'styles' => 'dygraphs/resources/ext.srf.dygraphs.css',
+ 'dependencies' => [
+ 'jquery.client',
+ 'ext.jquery.async',
+ 'ext.srf.util',
+ 'ext.smw.tooltip',
+ 'ext.dygraphs.combined',
+ ],
+ 'messages' => [
+ 'srf-ui-common-label-datasource',
+ 'srf-ui-common-label-request-object',
+ 'srf-ui-common-label-ajax-error',
+ 'srf-ui-common-label-help-section',
+ 'srf-ui-tooltip-title-scope'
+ ],
+ 'position' => 'top',
+ ],
+
+ // Listnav
+ 'ext.jquery.listnav' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.listnav.js'
+ ],
+
+ // Listmenu
+ 'ext.jquery.listmenu' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.listmenu.js'
+ ],
+
+ // pajinate
+ 'ext.jquery.pajinate' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.pajinate.js'
+ ],
+
+ // Listwidget
+ 'ext.srf.listwidget' => $formatModule + [
+ 'scripts' => 'widget/resources/ext.srf.listwidget.js',
+ 'styles' => 'widget/resources/ext.srf.listwidget.css',
+ 'dependencies' => 'ext.srf.util',
+ 'messages' => [
+ 'srf-module-nomatch'
+ ]
+ ],
+ 'ext.srf.listwidget.alphabet' => $formatModule + [
+ 'dependencies' => [
+ 'ext.srf.listwidget',
+ 'ext.jquery.listnav'
+ ],
+ 'position' => 'top'
+ ],
+ 'ext.srf.listwidget.menu' => $formatModule + [
+ 'dependencies' => [
+ 'ext.srf.listwidget',
+ 'ext.jquery.listmenu'
+ ],
+ 'position' => 'top'
+ ],
+ 'ext.srf.listwidget.pagination' => $formatModule + [
+ 'dependencies' => [
+ 'ext.srf.listwidget',
+ 'ext.jquery.pajinate'
+ ],
+ 'position' => 'top'
+ ],
+
+ // Dynamiccarousel
+ 'ext.jquery.dynamiccarousel' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.dynamiccarousel.js',
+ 'dependencies' => [
+ 'ext.jquery.migration.browser'
+ ]
+ ],
+
+ // Pagewidget
+ 'ext.srf.pagewidget.carousel' => $formatModule + [
+ 'scripts' => 'widget/resources/ext.srf.pagewidget.carousel.js',
+ 'styles' => 'widget/resources/ext.srf.pagewidget.carousel.css',
+ 'dependencies' => [
+ 'ext.jquery.dynamiccarousel',
+ 'ext.srf.util'
+ ],
+ 'messages' => [
+ 'srf-ui-navigation-prev',
+ 'srf-ui-navigation-next',
+ 'srf-ui-common-label-source',
+ ],
+ 'position' => 'top',
+ ],
+
+ // jqPlot
+ // jQuery plugin specific declarations
+ 'ext.jquery.jqplot.core' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jquery.jqplot.js',
+ 'styles' => 'resources/jquery/jqplot/jquery.jqplot.css',
+ 'dependencies' => [
+ 'ext.jquery.migration.browser'
+ ]
+ ],
+
+ // excanvas is required only for pre- IE 9 versions
+ 'ext.jquery.jqplot.excanvas' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/excanvas.js'
+ ],
+
+ // JSON data formatting according the the City Index API spec
+ 'ext.jquery.jqplot.json' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/jqplot/jqplot.json2.js',
+ 'resources/jquery/jqplot/jqplot.ciParser.js'
+ ]
+ ],
+
+ // Plugin class representing the cursor
+ 'ext.jquery.jqplot.cursor' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.cursor.js'
+ ],
+
+ // Plugin class to render a logarithmic axis
+ 'ext.jquery.jqplot.logaxisrenderer' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.logAxisRenderer.js'
+ ],
+
+ // Plugin class to render a mekko style chart
+ 'ext.jquery.jqplot.mekko' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/jqplot/jqplot.mekkoRenderer.js',
+ 'resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js'
+ ]
+ ],
+
+ // Plugin class to render a bar/line style chart
+ 'ext.jquery.jqplot.bar' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js',
+ 'resources/jquery/jqplot/jqplot.canvasTextRenderer.js',
+ 'resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js',
+ 'resources/jquery/jqplot/jqplot.categoryAxisRenderer.js',
+ 'resources/jquery/jqplot/jqplot.barRenderer.js'
+ ],
+ 'dependencies' => 'ext.jquery.jqplot.core',
+ ],
+
+ // Plugin class to render a pie style chart
+ 'ext.jquery.jqplot.pie' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.pieRenderer.js',
+ 'dependencies' => 'ext.jquery.jqplot.core'
+ ],
+
+ // Plugin class to render a bubble style chart
+ 'ext.jquery.jqplot.bubble' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.bubbleRenderer.js',
+ 'dependencies' => 'ext.jquery.jqplot.core'
+ ],
+
+ // Plugin class to render a donut style chart
+ 'ext.jquery.jqplot.donut' => $moduleTemplate + [
+ 'scripts' =>'resources/jquery/jqplot/jqplot.donutRenderer.js',
+ 'dependencies' => 'ext.jquery.jqplot.pie'
+ ],
+
+ 'ext.jquery.jqplot.pointlabels' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.pointLabels.js',
+ 'dependencies' => 'ext.jquery.jqplot.core'
+ ],
+
+ 'ext.jquery.jqplot.highlighter' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.highlighter.js',
+ 'dependencies' => 'ext.jquery.jqplot.core'
+ ],
+
+ 'ext.jquery.jqplot.enhancedlegend' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js',
+ 'dependencies' => 'ext.jquery.jqplot.core'
+ ],
+
+ // Plugin class to render a trendline
+ 'ext.jquery.jqplot.trendline' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jqplot/jqplot.trendline.js'
+ ],
+
+ // General jqplot/SRF specific declarations
+ // Plugin class supporting themes
+ 'ext.srf.jqplot.themes' => $formatModule + [
+ 'scripts' => 'jqplot/resources/ext.srf.jqplot.themes.js',
+ 'dependencies' => 'jquery.client'
+ ],
+
+ //
+ 'ext.srf.jqplot.cursor' => $moduleTemplate + [
+ 'dependencies' => [
+ 'ext.srf.jqplot.bar',
+ 'ext.jquery.jqplot.cursor',
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.enhancedlegend' => $moduleTemplate + [
+ 'dependencies' => [
+ 'ext.srf.jqplot.bar',
+ 'ext.jquery.jqplot.enhancedlegend',
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.pointlabels' => $moduleTemplate + [
+ 'dependencies' => [
+ 'ext.srf.jqplot.bar',
+ 'ext.jquery.jqplot.pointlabels',
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.highlighter' => $moduleTemplate + [
+ 'dependencies' => [
+ 'ext.srf.jqplot.bar',
+ 'ext.jquery.jqplot.highlighter',
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.trendline' => $moduleTemplate + [
+ 'dependencies' => [
+ 'ext.srf.jqplot.bar',
+ 'ext.jquery.jqplot.trendline',
+ ],
+ 'position' => 'top',
+ ],
+
+ // Chart specific declarations
+ 'ext.srf.jqplot.chart' => $formatModule + [
+ 'scripts' => [
+ 'jqplot/resources/ext.srf.jqplot.chart.bar.js',
+ 'jqplot/resources/ext.srf.jqplot.chart.pie.js',
+ 'jqplot/resources/ext.srf.jqplot.chart.js',
+ ],
+ 'styles' => 'jqplot/resources/ext.srf.jqlpot.chart.css',
+ 'dependencies' => [
+ 'ext.jquery.jqplot.core',
+ 'ext.jquery.async',
+ 'ext.srf.util',
+ 'ext.srf.jqplot.themes'
+ ]
+ ],
+
+ //
+ 'ext.srf.jqplot.bar' => $formatModule + [
+ 'scripts' => 'jqplot/resources/ext.srf.jqplot.chart.bar.js',
+ 'dependencies' => [
+ 'ext.jquery.jqplot.bar',
+ 'ext.srf.jqplot.chart'
+ ],
+ 'messages' => [
+ 'srf-error-jqplot-stackseries-data-length'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.pie' => $formatModule + [
+ 'scripts' => 'jqplot/resources/ext.srf.jqplot.chart.pie.js',
+ 'dependencies' => [
+ 'ext.jquery.jqplot.pie',
+ 'ext.srf.jqplot.chart'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.bubble' => $formatModule + [
+ 'scripts' => 'jqplot/resources/ext.srf.jqplot.chart.bubble.js',
+ 'dependencies' => [
+ 'ext.jquery.jqplot.bubble',
+ 'ext.srf.jqplot.chart'
+ ],
+ 'messages' => [
+ 'srf-error-jqplot-bubble-data-length'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.jqplot.donut' => $formatModule + [
+ 'scripts' => 'jqplot/resources/ext.srf.jqplot.chart.pie.js',
+ 'dependencies' => [
+ 'ext.jquery.jqplot.donut',
+ 'ext.srf.jqplot.chart'
+ ],
+ 'position' => 'top',
+ ],
+
+ // Timeline
+ // Copied from timeline-api.js
+ 'ext.smile.timeline.core' => $formatModule + [
+ 'scripts' => [
+ 'timeline/resources/SimileTimeline/scripts/timeline.js',
+ 'timeline/resources/SimileTimeline/scripts/util/platform.js',
+ 'timeline/resources/SimileTimeline/scripts/util/debug.js',
+ 'timeline/resources/SimileTimeline/scripts/util/xmlhttp.js',
+ 'timeline/resources/SimileTimeline/scripts/util/dom.js',
+ 'timeline/resources/SimileTimeline/scripts/util/graphics.js',
+ 'timeline/resources/SimileTimeline/scripts/util/date-time.js',
+ 'timeline/resources/SimileTimeline/scripts/util/data-structure.js',
+ 'timeline/resources/SimileTimeline/scripts/units.js',
+ 'timeline/resources/SimileTimeline/scripts/themes.js',
+ 'timeline/resources/SimileTimeline/scripts/ethers.js',
+ 'timeline/resources/SimileTimeline/scripts/ether-painters.js',
+ 'timeline/resources/SimileTimeline/scripts/labellers.js',
+ 'timeline/resources/SimileTimeline/scripts/sources.js',
+ 'timeline/resources/SimileTimeline/scripts/layouts.js',
+ 'timeline/resources/SimileTimeline/scripts/painters.js',
+ 'timeline/resources/SimileTimeline/scripts/decorators.js',
+ 'timeline/resources/SimileTimeline/scripts/labellers.js',
+
+ // Keep this with in the same load sequence
+ 'timeline/resources/SimileTimeline/scripts/l10n/en/labellers.js',
+ 'timeline/resources/SimileTimeline/scripts/l10n/en/timeline.js'
+ ],
+ 'styles' => [
+ 'timeline/resources/SimileTimeline/styles/timeline.css',
+ 'timeline/resources/SimileTimeline/styles/ethers.css',
+ 'timeline/resources/SimileTimeline/styles/events.css',
+ ],
+ 'targets' => [ 'mobile', 'desktop' ]
+ ],
+
+ 'ext.smile.timeline' => $formatModule + [
+ 'scripts' => [
+ 'timeline/resources/SimileTimeline/timeline-api.js',
+ ],
+ 'targets' => [ 'mobile', 'desktop' ]
+ ],
+
+ 'ext.srf.timeline' => $formatModule + [
+ 'scripts' => 'timeline/resources/ext.srf.timeline.js',
+ 'dependencies' => [
+ 'ext.smile.timeline',
+ ],
+ 'position' => 'top',
+ 'targets' => [ 'mobile', 'desktop' ]
+ ],
+
+ // D3
+ 'ext.d3.core' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/d3/d3.v3.js'
+ ],
+
+ //
+ 'ext.srf.d3.common' => $formatModule + [
+ 'scripts' => 'd3/resources/ext.srf.d3.common.js',
+ 'styles' => 'd3/resources/ext.srf.d3.common.css',
+ 'dependencies' => 'ext.srf.util'
+ ],
+
+ // Wordcloud
+ 'ext.d3.wordcloud' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/d3/d3.layout.cloud.js',
+ 'dependencies' => [
+ 'ext.d3.core',
+ 'ext.srf.d3.common'
+ ]
+ ],
+
+ //
+ 'ext.srf.d3.chart.treemap' => $formatModule + [
+ 'scripts' => 'd3/resources/ext.srf.d3.chart.treemap.js',
+ 'styles' => 'd3/resources/ext.srf.d3.chart.treemap.css',
+ 'dependencies' => [ 'ext.d3.core', 'ext.srf.d3.common' ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.d3.chart.bubble' => $formatModule + [
+ 'scripts' => 'd3/resources/ext.srf.d3.chart.bubble.js',
+ 'styles' => 'd3/resources/ext.srf.d3.chart.bubble.css',
+ 'dependencies' => [ 'ext.d3.core', 'ext.srf.d3.common' ],
+ 'position' => 'top',
+ ],
+
+
+ // JitGraph
+ 'ext.srf.jquery.progressbar' => $formatModule + [
+ 'scripts' => [
+ 'JitGraph/jquery.progressbar.js',
+ ],
+ ],
+ 'ext.srf.jit' => $formatModule + [
+ 'scripts' => [
+ 'JitGraph/Jit/jit.js',
+ ],
+ ],
+ 'ext.srf.jitgraph' => $formatModule + [
+ 'scripts' => [
+ 'JitGraph/SRF_JitGraph.js',
+ ],
+ 'styles' => [
+ 'JitGraph/base.css',
+ ],
+ 'dependencies' => [
+ 'ext.srf.jquery.progressbar',
+ 'ext.srf.jit',
+ ],
+ 'position' => 'top',
+ ],
+
+ // Gallery
+
+ // jcarousel
+ 'ext.jquery.jcarousel' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.jcarousel.js',
+ 'dependencies' => 'ext.jquery.migration.browser'
+ ],
+
+ // responsiveslides
+ 'ext.jquery.responsiveslides' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.responsiveslides.js',
+ ],
+
+ // Gallery base class
+ 'ext.srf.formats.gallery' => $formatModule + [
+ 'scripts' => 'gallery/resources/ext.srf.formats.gallery.js',
+ 'dependencies' => 'ext.srf.util'
+ ],
+
+ //
+ 'ext.srf.gallery.carousel' => $formatModule + [
+ 'styles' => 'gallery/resources/ext.srf.gallery.carousel.css',
+ 'scripts' => 'gallery/resources/ext.srf.gallery.carousel.js',
+ 'dependencies' => [
+ 'ext.srf.formats.gallery',
+ 'ext.jquery.jcarousel'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.gallery.slideshow' => $formatModule + [
+ 'scripts' => 'gallery/resources/ext.srf.gallery.slideshow.js',
+ 'styles' => 'gallery/resources/ext.srf.gallery.slideshow.css',
+ 'dependencies' => [
+ 'ext.srf.formats.gallery',
+ 'ext.jquery.responsiveslides'
+ ],
+ 'messages' => [
+ 'srf-gallery-navigation-previous',
+ 'srf-gallery-navigation-next'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.gallery.overlay' => $formatModule + [
+ 'scripts' => 'gallery/resources/ext.srf.gallery.overlay.js',
+ 'styles' => 'gallery/resources/ext.srf.gallery.overlay.css',
+ 'dependencies' => [
+ 'ext.srf.formats.gallery',
+ 'ext.jquery.fancybox'
+ ],
+ 'messages' => [
+ 'srf-gallery-overlay-count',
+ 'srf-gallery-image-url-error'
+ ],
+ 'position' => 'top',
+ ],
+
+ //
+ 'ext.srf.gallery.redirect' => $formatModule + [
+ 'scripts' => 'gallery/resources/ext.srf.gallery.redirect.js',
+ 'styles' => 'gallery/resources/ext.srf.gallery.redirect.css',
+ 'dependencies' => 'ext.srf.formats.gallery',
+ 'messages' => [
+ 'srf-gallery-image-url-error'
+ ],
+ 'position' => 'top',
+ ],
+
+ // fullCalendar
+ 'ext.jquery.fullcalendar' => $moduleTemplate + [
+ 'scripts' => [
+ 'resources/jquery/fullcalendar/moment.js',
+ 'resources/jquery/fullcalendar/fullcalendar.js'
+ ],
+ 'styles' => 'resources/jquery/fullcalendar/fullcalendar.css',
+ // If you have MW 1.20+ the definitions below will work but not for earlier
+ // MW installations
+ // 'styles' => array(
+ // 'resources/jquery/fullcalendar/fullcalendar.css' => array( 'media' => 'screen' ),
+ // 'resources/jquery/fullcalendar/fullcalendar.print.css' => array( 'media' => 'print' ),
+ // )
+ ],
+
+ //
+ 'ext.jquery.gcal' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/fullcalendar/gcal.js',
+ ],
+
+ // Eventcalendar widgets
+ 'ext.srf.widgets.eventcalendar' => $formatModule + [
+ 'scripts' => [
+ 'calendar/resources/ext.srf.widgets.calendarpane.js',
+ 'calendar/resources/ext.srf.widgets.calendarbutton.js',
+ 'calendar/resources/ext.srf.widgets.calendarparameters.js',
+ 'calendar/resources/ext.srf.widgets.calendarlegend.js',
+ ],
+ 'dependencies' => [
+ 'jquery.ui.core',
+ 'jquery.ui.widget',
+ 'jquery.ui.datepicker',
+ 'jquery.ui.slider',
+ 'ext.smw.tooltip',
+ 'ext.srf.util',
+ 'ext.srf.api',
+ ]
+ ],
+
+ // Eventcalendar hooks
+ 'ext.srf.hooks.eventcalendar' => $formatModule + [
+ 'scripts' => 'calendar/resources/ext.srf.hooks.eventcalendar.js',
+ 'dependencies' => 'ext.srf'
+ ],
+
+ // Eventcalendar module
+ 'ext.srf.eventcalendar' => $formatModule + $calendarMessages + [
+ 'scripts' => 'calendar/resources/ext.srf.formats.eventcalendar.js',
+ 'styles' => 'calendar/resources/ext.srf.formats.eventcalendar.css',
+ 'dependencies' => [
+ 'ext.srf.widgets.eventcalendar',
+ 'ext.srf.hooks.eventcalendar',
+ 'ext.jquery.fullcalendar',
+ ],
+ ],
+
+ // Filtered
+ 'ext.srf.filtered' => $formatModule + [
+ 'scripts' => [
+ 'filtered/resources/js/ext.srf.filtered.js',
+ ],
+ 'styles' => [
+ 'filtered/resources/css/ext.srf.filtered.less',
+ ],
+ 'messages' => [
+ 'srf-filtered-value-filter-placeholder',
+ 'srf-filtered-value-filter-and',
+ 'srf-filtered-value-filter-or',
+ ],
+ 'dependencies' => [
+ 'ext.srf',
+ ],
+ 'position' => 'top',
+ ],
+
+ 'ext.srf.filtered.calendar-view.messages' => $formatModule + $calendarMessages,
+
+ 'ext.srf.filtered.calendar-view' => $formatModule + array(
+ 'styles' => array(
+ 'filtered/resources/css/ext.srf.filtered.calendar-view.less',
+ ),
+ 'dependencies' => array(
+ 'ext.srf.filtered.calendar-view.messages',
+ 'ext.jquery.fullcalendar'
+ ),
+ ),
+
+ 'ext.srf.filtered.map-view.leaflet' => $formatModule + [
+ 'scripts' => [
+ 'filtered/resources/js/ext.srf.filtered.leaflet.js',
+ ],
+ 'styles' => [
+ 'filtered/resources/css/ext.srf.filtered.leaflet.css',
+ ],
+ ],
+
+ 'ext.srf.filtered.map-view' => $formatModule + [
+ 'styles' => [
+ 'filtered/resources/css/ext.srf.filtered.map-view.less',
+ ],
+ ],
+
+ 'ext.srf.filtered.value-filter' => $formatModule + [
+ 'styles' => [ 'filtered/resources/css/ext.srf.filtered.value-filter.less' ],
+ ],
+
+ 'ext.srf.filtered.value-filter.select' => $formatModule + [
+ 'scripts' => [ 'filtered/resources/js/ext.srf.filtered.select.js' ],
+ 'styles' => [ 'filtered/resources/css/ext.srf.filtered.select.css' ],
+ ],
+
+ 'ext.srf.filtered.slider' => $formatModule + [
+ 'scripts' => [ 'filtered/resources/js/ext.srf.filtered.slider.js' ],
+ 'styles' => [ 'filtered/resources/css/ext.srf.filtered.slider.css' ],
+ ],
+
+ 'ext.srf.filtered.distance-filter' => $formatModule + [
+ 'styles' => [ 'filtered/resources/css/ext.srf.filtered.distance-filter.less' ],
+ 'dependencies' => [ 'ext.srf.filtered.slider' ],
+ ],
+
+ 'ext.srf.filtered.number-filter' => $formatModule + [
+ 'styles' => [ 'filtered/resources/css/ext.srf.filtered.number-filter.less' ],
+ 'dependencies' => [ 'ext.srf.filtered.slider' ],
+ ],
+
+ // Slideshow
+ 'ext.srf.slideshow' => $formatModule + [
+ 'scripts' => 'slideshow/resources/ext.srf.slideshow.js',
+ 'styles' => 'slideshow/resources/ext.srf.slideshow.css',
+ 'dependencies' =>'mediawiki.util'
+ ],
+
+ // Tagcanvas module
+
+ 'ext.jquery.tagcanvas' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jquery.tagcanvas.js'
+ ],
+
+ // SRF Tag cloud module
+ 'ext.srf.formats.tagcloud' => $formatModule + [
+ 'scripts' => 'tagcloud/resources/ext.srf.formats.tagcloud.js',
+ 'styles' => 'tagcloud/resources/ext.srf.formats.tagcloud.css',
+ 'dependencies' => 'ext.srf.util'
+ ],
+
+ // Timeseries
+ 'ext.srf.flot.core' => $formatModule + [
+ 'styles' => 'timeseries/resources/ext.srf.flot.core.css',
+ ],
+
+ 'ext.srf.timeseries.flot' => $formatModule + [
+ 'scripts' => 'timeseries/resources/ext.srf.timeseries.flot.js',
+ 'dependencies' => [
+ 'ext.jquery.async',
+ 'ext.jquery.flot',
+ 'ext.srf.util',
+ 'ext.srf.flot.core'
+ ],
+ 'position' => 'top'
+ ],
+
+ // Register the jplayer js
+ 'ext.jquery.jplayer' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jplayer/jquery.jplayer.js',
+ ],
+
+ // Register the jplayer skin
+ 'ext.jquery.jplayer.skin.blue.monday' => $moduleTemplate + [
+ 'styles' => 'resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css',
+ ],
+
+ // Register the jplayer skin
+ 'ext.jquery.jplayer.skin.morning.light' => $moduleTemplate + [
+ 'styles' => 'resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css',
+ ],
+
+ // Register the jplayer playlist js
+ 'ext.jquery.jplayer.playlist' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jplayer/add-on/jplayer.playlist.min.js',
+ 'dependencies' => 'ext.jquery.jplayer',
+ ],
+
+ // Register the jplayer inspector js
+ 'ext.jquery.jplayer.inspector' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js',
+ 'dependencies' => 'ext.jquery.jplayer',
+ ],
+
+ // SRF jplayer template specifications
+ 'ext.srf.template.jplayer' => $formatModule + [
+ 'scripts' => 'media/resources/ext.srf.template.jplayer.js',
+ 'messages' => [
+ 'srf-ui-mediaplayer-label-previous',
+ 'srf-ui-mediaplayer-label-play',
+ 'srf-ui-mediaplayer-label-pause',
+ 'srf-ui-mediaplayer-label-next',
+ 'srf-ui-mediaplayer-label-stop',
+ 'srf-ui-mediaplayer-label-mute',
+ 'srf-ui-mediaplayer-label-unmute',
+ 'srf-ui-mediaplayer-label-volume-max',
+ 'srf-ui-mediaplayer-label-shuffle',
+ 'srf-ui-mediaplayer-label-shuffle-off',
+ 'srf-ui-mediaplayer-label-repeat',
+ 'srf-ui-mediaplayer-label-repeat-off',
+ 'srf-ui-mediaplayer-label-full-screen',
+ 'srf-ui-mediaplayer-label-restore-screen',
+ ],
+ 'dependencies' => 'ext.srf'
+ ],
+
+ // SRF implementation
+ 'ext.srf.formats.media' => $formatModule + [
+ 'scripts' => 'media/resources/ext.srf.formats.media.js',
+ 'styles' => 'media/resources/ext.srf.formats.media.css',
+ 'dependencies' => [
+ 'ext.srf',
+ 'ext.srf.template.jplayer',
+ 'ext.jquery.jplayer.playlist'
+ ],
+ 'group' => 'ext.srf'
+ ],
+
+ // jQuery DataTables
+ 'jquery.dataTables' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/datatables/jquery.dataTables.js',
+ 'position' => 'top'
+ ],
+
+ // DataTables extras
+ 'jquery.dataTables.extras' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/datatables/jquery.dataTables.extras.js',
+ ],
+
+ // DataTables implementation
+ 'ext.srf.datatables' => $formatModule + [
+ 'scripts' => 'datatables/resources/ext.srf.formats.datatables.js',
+ 'styles' => 'datatables/resources/ext.srf.formats.datatables.css',
+ 'dependencies' => [
+ 'jquery.dataTables',
+ 'jquery.dataTables.extras',
+ 'jquery.ui.core',
+ 'jquery.ui.widget',
+ 'jquery.ui.button',
+ 'ext.smw.dataItem',
+ 'ext.smw.api',
+ 'ext.srf.api',
+ 'ext.srf.util',
+ 'ext.srf.widgets'
+ ],
+ 'messages' => [
+ 'srf-ui-datatables-label-conditions',
+ 'srf-ui-datatables-label-parameters',
+ 'srf-ui-datatables-label-filters',
+ 'srf-ui-datatables-label-information',
+ 'srf-ui-datatables-panel-disclaimer',
+ 'srf-ui-datatables-label-update-success',
+ 'srf-ui-datatables-label-update-error',
+ 'srf-ui-datatables-label-sEmptyTable',
+ 'srf-ui-datatables-label-sInfo',
+ 'srf-ui-datatables-label-sInfoEmpty',
+ 'srf-ui-datatables-label-sInfoFiltered',
+ 'srf-ui-datatables-label-sInfoPostFix',
+ 'srf-ui-datatables-label-sInfoThousands',
+ 'srf-ui-datatables-label-sLengthMenu',
+ 'srf-ui-datatables-label-sLoadingRecords',
+ 'srf-ui-datatables-label-sProcessing',
+ 'srf-ui-datatables-label-sSearch',
+ 'srf-ui-datatables-label-sZeroRecords',
+ 'srf-ui-datatables-label-oPaginate-sFirst',
+ 'srf-ui-datatables-label-oPaginate-sLast',
+ 'srf-ui-datatables-label-oPaginate-sNext',
+ 'srf-ui-datatables-label-oPaginate-sPrevious',
+ 'srf-ui-datatables-label-oAria-sSortAscending',
+ 'srf-ui-datatables-label-oAria-sSortDescending',
+ 'srf-ui-datatables-label-multiselect-column-header',
+ 'srf-ui-datatables-label-multiselect-column-noneselectedtext',
+ 'srf-ui-datatables-label-multiselect-column-selectedtext',
+ 'srf-ui-datatables-label-placeholder-column-search',
+ 'srf-ui-datatables-label-content-cache',
+ 'srf-ui-datatables-label-content-server'
+ ]
+ ],
+
+ // DataTables bootstrap
+ 'ext.srf.datatables.bootstrap' => $moduleTemplate + [
+ 'scripts' => 'resources/jquery/datatables/jquery.dataTables.bootstrap.js',
+ 'styles' => 'resources/jquery/datatables/jquery.dataTables.bootstrap.css',
+ 'dependencies' => 'ext.srf.datatables'
+ ],
+
+ // DataTables basic
+ 'ext.srf.datatables.basic' => $moduleTemplate + [
+ 'styles' => [
+ 'resources/jquery/datatables/jquery.dataTables.css',
+ 'resources/jquery/datatables/jquery.dataTables.images.css'
+ ],
+ 'dependencies' => 'ext.srf.datatables'
+ ],
+
+ // Mermaid Format
+ 'ext.srf.gantt' => $formatModule + [
+ 'scripts' => 'Gantt/resources/ext.gantt.js',
+ 'dependencies' => 'ext.mermaid'
+ ]
+
+ // Boilerplate example registration
+ /*
+ // Simple implementation
+ 'ext.srf.boilerplate.simple' => $formatModule + array(
+ 'scripts' => 'boilerplate/resources/ext.srf.boilerplate.simple.js',
+ 'styles' => 'boilerplate/resources/ext.srf.boilerplate.css',
+ 'messages' => array(
+ 'srf-boilerplate-message'
+ ),
+ );
+
+ // Using the semanticFormats namespace class implementation
+ 'ext.srf.boilerplate.namespace' => $formatModule + array(
+ 'scripts' => 'boilerplate/resources/ext.srf.boilerplate.namespace.js',
+ 'styles' => 'boilerplate/resources/ext.srf.boilerplate.css',
+ 'dependencies' => array (
+ 'ext.srf.util'
+ ),
+ 'messages' => array(
+ 'srf-boilerplate-message'
+ ),
+ );
+ */
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.hooks.php b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.hooks.php
new file mode 100644
index 00000000..fba34807
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.hooks.php
@@ -0,0 +1,231 @@
+<?php
+
+/**
+ * Static class for hooks handled by the Semantic Result Formats.
+ *
+ * @since 1.7
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author mwjames
+ */
+final class SRFHooks {
+
+ /**
+ * Hook to add PHPUnit test cases.
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/UnitTestsList
+ *
+ * @since 1.8
+ *
+ * @param array $files
+ *
+ * @return boolean
+ */
+ public static function registerUnitTests( array &$files ) {
+ // Keep this in alphabetical order please!
+ $testFiles = [
+
+ 'Resources',
+
+ // Formats
+ 'formats/Array',
+ 'formats/Dygraphs',
+ 'formats/EventCalendar',
+ 'formats/Gallery',
+ 'formats/Graph',
+ 'formats/Incoming',
+ 'formats/jqPlotChart',
+ 'formats/jqPlotSeries',
+ 'formats/ListWidget',
+ 'formats/Math',
+ 'formats/PageWidget',
+ 'formats/Sparkline',
+ 'formats/TagCloud',
+ 'formats/Timeseries',
+ 'formats/Tree',
+ 'formats/vCard',
+ 'formats/MediaPlayer',
+ 'formats/DataTables',
+
+ // Boilerplate
+ // Register your testclass
+ // 'formats/Boilerplate',
+ ];
+
+ foreach ( $testFiles as $file ) {
+ $files[] = dirname( __FILE__ ) . '/tests/phpunit/' . $file . 'Test.php';
+ }
+
+ return true;
+ }
+
+ /**
+ * Add new JavaScript/QUnit testing modules
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderTestModules
+ *
+ * @since: 1.9
+ *
+ * @param array $testModules array of JavaScript testing modules
+ * @param ResourceLoader $resourceLoader object
+ *
+ * @return boolean
+ */
+ public static function registerQUnitTests( array &$testModules, ResourceLoader &$resourceLoader ) {
+ $testModules['qunit']['ext.srf.tests'] = [
+ 'scripts' => [
+ // Base
+ 'tests/qunit/ext.srf.test.js',
+ 'tests/qunit/ext.srf.util.test.js',
+
+ // Formats
+ 'tests/qunit/formats/ext.srf.formats.eventcalendar.tests.js',
+ 'tests/qunit/formats/ext.srf.formats.datatables.test.js',
+ 'tests/qunit/formats/ext.srf.formats.filtered.test.js',
+ 'tests/qunit/formats/ext.srf.formats.gallery.test.js',
+ 'tests/qunit/formats/ext.srf.formats.media.test.js',
+ 'tests/qunit/formats/ext.srf.formats.tagcloud.test.js',
+
+ // Widgets
+ 'tests/qunit/widgets/ext.srf.widgets.eventcalendar.tests.js',
+ 'tests/qunit/widgets/ext.srf.widgets.optionslist.test.js',
+ 'tests/qunit/widgets/ext.srf.widgets.panel.test.js',
+ 'tests/qunit/widgets/ext.srf.widgets.parameters.test.js'
+
+ ],
+ 'dependencies' => [
+ 'ext.srf',
+ 'ext.srf.util',
+ 'ext.srf.eventcalendar',
+ 'ext.srf.datatables',
+ 'ext.srf.widgets',
+ 'ext.srf.gallery.overlay',
+ 'ext.srf.gallery.carousel',
+ 'ext.srf.gallery.slideshow',
+ 'ext.srf.gallery.redirect',
+ 'ext.srf.formats.media',
+ 'ext.srf.formats.tagcloud',
+ 'ext.srf.filtered.value-filter.select',
+ ],
+ 'position' => 'top',
+ 'localBasePath' => __DIR__,
+ 'remoteExtPath' => 'SemanticResultFormats',
+ ];
+
+ return true;
+ }
+
+ /**
+ * Adds a link to Admin Links page.
+ *
+ * @since 1.7
+ *
+ * @param ALTree $admin_links_tree
+ *
+ * @return boolean
+ */
+ public static function addToAdminLinks( ALTree &$admin_links_tree ) {
+ $displaying_data_section = $admin_links_tree->getSection( wfMessage( 'smw_adminlinks_displayingdata' )->text() );
+
+ // Escape is SMW hasn't added links.
+ if ( is_null( $displaying_data_section ) ) {
+ return true;
+ }
+
+ $smw_docu_row = $displaying_data_section->getRow( 'smw' );
+ $srf_docu_label = wfMessage( 'adminlinks_documentation', wfMessage( 'srf-name' )->text() )->text();
+ $smw_docu_row->addItem( AlItem::newFromExternalLink( 'https://www.mediawiki.org/wiki/Extension:Semantic_Result_Formats', $srf_docu_label ) );
+
+ return true;
+ }
+
+ /**
+ * Hook: ResourceLoaderGetConfigVars called right before
+ * ResourceLoaderStartUpModule::getConfig returns
+ *
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderGetConfigVars
+ *
+ * @param &$vars Array of variables to be added into the output of the startup module.
+ *
+ * @return true
+ */
+ public static function onResourceLoaderGetConfigVars( &$vars ) {
+
+ $vars['srf-config'] = [
+ 'version' => SRF_VERSION,
+ 'settings' => [
+ 'wgThumbLimits' => $GLOBALS['wgThumbLimits'],
+ 'srfgScriptPath' => $GLOBALS['srfgScriptPath'],
+ ]
+ ];
+
+ return true;
+ }
+
+ /**
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay
+ *
+ * @param OutputPage $outputPage
+ * @param Skin $skin
+ *
+ * @return true
+ */
+ public static function onBeforePageDisplay ( &$outputPage, &$skin ) {
+
+ $outputPage->addModuleStyles( 'ext.srf.styles' );
+
+ return true;
+ }
+
+ /**
+ * Hook: GetPreferences adds user preference
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/GetPreferences
+ *
+ * @param User $user
+ * @param array $preferences
+ *
+ * @return true
+ */
+ public static function onGetPreferences( $user, &$preferences ) {
+
+ // Intro text, do not escape the message here as it contains
+ // href links
+ $preferences['srf-prefs-intro'] = [
+ 'type' => 'info',
+ 'label' => '&#160;',
+ 'default' => wfMessage( 'srf-prefs-intro-text' )->parseAsBlock(),
+ 'section' => 'smw/srf',
+ 'raw' => 1,
+ ];
+
+ // Enable auto update during a page refresh
+ $preferences['srf-prefs-eventcalendar-options-update-default'] = [
+ 'type' => 'toggle',
+ 'label-message' => 'srf-prefs-eventcalendar-options-update-default',
+ 'section' => 'smw/srf-eventcalendar-options',
+ ];
+
+ // Enable paneView by default
+ $preferences['srf-prefs-eventcalendar-options-paneview-default'] = [
+ 'type' => 'toggle',
+ 'label-message' => 'srf-prefs-eventcalendar-options-paneview-default',
+ 'section' => 'smw/srf-eventcalendar-options',
+ ];
+
+
+ // Enable auto update during a page refresh
+ $preferences['srf-prefs-datatables-options-update-default'] = [
+ 'type' => 'toggle',
+ 'label-message' => 'srf-prefs-datatables-options-update-default',
+ 'section' => 'smw/srf-datatables-options',
+ ];
+
+ // Enable local caching
+ $preferences['srf-prefs-datatables-options-cache-default'] = [
+ 'type' => 'toggle',
+ 'label-message' => 'srf-prefs-datatables-options-cache-default',
+ 'section' => 'smw/srf-datatables-options',
+ ];
+
+ return true;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.i18n.magic.php b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.i18n.magic.php
new file mode 100644
index 00000000..d80a7ef5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.i18n.magic.php
@@ -0,0 +1,133 @@
+<?php
+
+$magicWords = [];
+
+/** English (English) */
+
+$magicWords = [];
+
+/** English (English) */
+$magicWords['en'] = [
+ 'calendarstartdate' => [ 0, 'calendarstartdate' ],
+ 'calendarenddate' => [ 0, 'calendarenddate' ],
+];
+
+/** Arabic (العربية) */
+$magicWords['ar'] = [
+ 'calendarstartdate' => [ 0, 'تاريخ_بداية_التقويم' ],
+ 'calendarenddate' => [ 0, 'تاريخ_نهاية_التقويم' ],
+];
+
+/** Egyptian Arabic (مصرى) */
+$magicWords['arz'] = [
+ 'calendarstartdate' => [ 0, 'تاريخ_بداية_التقويم' ],
+ 'calendarenddate' => [ 0, 'تاريخ_نهاية_التقويم' ],
+];
+
+/** German (Deutsch) */
+$magicWords['de'] = [
+ 'calendarstartdate' => [ 0, 'kalenderanfangsdatum' ],
+ 'calendarenddate' => [ 0, 'kalenderenddatum' ],
+];
+
+/** Zazaki (Zazaki) */
+$magicWords['diq'] = [
+ 'calendarstartdate' => [ 0, 'standardemêteqwimi' ],
+ 'calendarenddate' => [ 0, 'demeuteqwima' ],
+];
+
+/** Spanish (español) */
+$magicWords['es'] = [
+ 'calendarstartdate' => [ 0, 'fechadeiniciodecalendario', 'fechainiciocalendario' ],
+ 'calendarenddate' => [ 0, 'fechadefindecalendario', 'fechafincalendario' ],
+];
+
+/** French (français) */
+$magicWords['fr'] = [
+ 'calendarstartdate' => [ 0, 'datedébutcalendrier' ],
+ 'calendarenddate' => [ 0, 'datefincalendrier' ],
+];
+
+/** Japanese (日本語) */
+$magicWords['ja'] = [
+ 'calendarstartdate' => [ 0, '暦開始日' ],
+ 'calendarenddate' => [ 0, '暦終了日' ],
+];
+
+/** Georgian (ქáƒáƒ áƒ—ული) */
+$magicWords['ka'] = [
+ 'calendarstartdate' => [ 0, 'კáƒáƒšáƒ”ნდრის_დáƒáƒ¬áƒ§áƒ”ბის_თáƒáƒ áƒ˜áƒ¦áƒ˜' ],
+ 'calendarenddate' => [ 0, 'კáƒáƒšáƒ”ნდრის_დáƒáƒ¡áƒ áƒ£áƒšáƒ”ბის_თáƒáƒ áƒ˜áƒ¦áƒ˜' ],
+];
+
+/** Korean (한국어) */
+$magicWords['ko'] = [
+ 'calendarstartdate' => [ 0, '달력시작날짜' ],
+ 'calendarenddate' => [ 0, '달력ë날짜' ],
+];
+
+/** Macedonian (македонÑки) */
+$magicWords['mk'] = [
+ 'calendarstartdate' => [ 0, 'почетенкалендарÑкидатум' ],
+ 'calendarenddate' => [ 0, 'краенкалендарÑкидатум' ],
+];
+
+/** Malayalam (മലയാളം) */
+$magicWords['ml'] = [
+ 'calendarstartdate' => [ 0, 'കലണàµà´Ÿà´±à´¿à´²àµ†à´¯à´¾à´¦àµà´¯à´¤àµ€à´¯à´¤à´¿' ],
+ 'calendarenddate' => [ 0, 'കലണàµà´Ÿà´±à´¿à´²àµ†à´¯à´µà´¸à´¾à´¨à´¤àµ€à´¯à´¤à´¿' ],
+];
+
+/** Marathi (मराठी) */
+$magicWords['mr'] = [
+ 'calendarstartdate' => [ 0, 'दिनदरà¥à¤¶à¤¿à¤•à¤¾à¤°à¤‚भदिन', 'calendarstartdate' ],
+ 'calendarenddate' => [ 0, 'दिनदरà¥à¤¶à¤¿à¤•à¤¾à¤¸à¤¾à¤‚गतादिन', 'calendarenddate' ],
+];
+
+/** Norwegian Bokmål (norsk bokmål) */
+$magicWords['nb'] = [
+ 'calendarstartdate' => [ 0, 'kalenderstartdato' ],
+ 'calendarenddate' => [ 0, 'kalendersluttdato' ],
+];
+
+/** Low Saxon (Netherlands) (Nedersaksies) */
+$magicWords['nds-nl'] = [
+ 'calendarstartdate' => [ 0, 'startdaotumkalender', 'startdatumkalender' ],
+ 'calendarenddate' => [ 0, 'einddaotumkalender', 'einddatumkalender' ],
+];
+
+/** Dutch (Nederlands) */
+$magicWords['nl'] = [
+ 'calendarstartdate' => [ 0, 'startdatumkalender' ],
+ 'calendarenddate' => [ 0, 'einddatumkalender' ],
+];
+
+/** Quechua (Runa Simi) */
+$magicWords['qu'] = [
+ 'calendarstartdate' => [ 0, 'watapiqallarinapunchaw', 'watapiqallariypunchaw' ],
+ 'calendarenddate' => [ 0, 'watapipuchukanapunchaw', 'watapipuchukaypunchaw' ],
+];
+
+/** Serbian (Cyrillic script) (ÑрпÑки (ћирилица)‎) */
+$magicWords['sr-ec'] = [
+ 'calendarstartdate' => [ 0, 'почетнидатум', 'почетни_датум' ],
+ 'calendarenddate' => [ 0, 'завршнидатум', 'завршни_датум' ],
+];
+
+/** Serbian (Latin script) (srpski (latinica)‎) */
+$magicWords['sr-el'] = [
+ 'calendarstartdate' => [ 0, 'poÄetnidatum', 'poÄetni_datum' ],
+ 'calendarenddate' => [ 0, 'završnidatum', 'završni_datum' ],
+];
+
+/** Simplified Chinese (中文(简体)‎) */
+$magicWords['zh-hans'] = [
+ 'calendarstartdate' => [ 0, '日历起始日期' ],
+ 'calendarenddate' => [ 0, '日历届满日期' ],
+];
+
+/** Traditional Chinese (中文(ç¹é«”)‎) */
+$magicWords['zh-hant'] = [
+ 'calendarstartdate' => [ 0, '記錄起始日期' ],
+ 'calendarenddate' => [ 0, '記錄屆滿日期' ],
+]; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.parser.php b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.parser.php
new file mode 100644
index 00000000..3adfdf4b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.parser.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Parser functions for the Semantic Result Formats extension.
+ *
+ * Two parser functions are defined, both for use by the Calendar format:
+ *
+ * #calendarstartdate returns the start date for the set of dates being
+ * displayed on the screen, according to the query string.
+ *
+ * #calendarenddate returns the *day after* the end date for the set of dates
+ * being displayed on the screen, according to the query string.
+ *
+ * @author David Loomer
+ */
+class SRFParserFunctions {
+
+ static function registerFunctions( &$parser ) {
+ $parser->setFunctionHook( 'calendarstartdate', [ 'SRFParserFunctions', 'runCalendarStartDate' ] );
+ $parser->setFunctionHook( 'calendarenddate', [ 'SRFParserFunctions', 'runCalendarEndDate' ] );
+ return true;
+ }
+
+ static function runCalendarStartDate( &$parser, $calendar_type = 'month', $calendar_start_day = null, $calendar_days = 7, $default_year = null, $default_month = null, $default_day = null ) {
+ if ( $calendar_type == '' ) $calendar_type = 'month';
+ list( $lower_date, $upper_date, $query_date ) =
+ SRFParserFunctions::getBoundaryDates( $calendar_type, $calendar_start_day, $calendar_days, $default_year, $default_month, $default_day );
+ return date( "Y", $lower_date ) . '-' . date( "m", $lower_date ) . '-' . date( "d", $lower_date );
+ }
+
+ static function runCalendarEndDate( &$parser, $calendar_type = 'month', $calendar_start_day = null, $calendar_days = 7, $default_year = null, $default_month = null, $default_day = null ) {
+ if ( $calendar_type == '' ) $calendar_type = 'month';
+ list( $lower_date, $upper_date, $query_date ) =
+ SRFParserFunctions::getBoundaryDates( $calendar_type, $calendar_start_day, $calendar_days, $default_year, $default_month, $default_day );
+ return date( "Y", $upper_date ) . '-' . date( "m", $upper_date ) . '-' . date( "d", $upper_date );
+ }
+
+ /**
+ * Obtain both a lower- and upper- bound date to be used for querying.
+ *
+ * @param $calendar_type string Values: 'month' (the default) for monthly
+ * calendar such as SRF Calendar; others not yet defined.
+ * @param $calendar_start_day int Optionally force the lower bound date to be a certain
+ * day of the week (0 for Sunday, 6 for Saturday). If using a $calendar_type
+ * of 'month' this parameter is ignored, as the start day of week for a monthly
+ * calendar is currently always set as Sunday. Ohterwise defaults to either the day
+ * supplied in the query string, or the current day.
+ * @param $calendar_days int The number of days to display. Ignored if using a
+ * $calendar_type of 'month'; otherwise defaults to 7.
+ * @param $default_year int (Optional) Default year if none is specified in
+ * the query string. If parameter is not supplied, will fall back to current year.
+ * @param $default_month int (Optional) Default month if none is specified in
+ * the query string. If parameter is not supplied, will fall back to current month.
+ * @param $default_day int (Optional) Default day of month if none is specified in
+ * the query string. If parameter is not supplied, will fall back to current day of month.
+ * @return array First element contains the lower bound date, second
+ * element contains the upper bound, third element contains a date indicating
+ * the year/month/day to be queried.
+ *
+ */
+ static function getBoundaryDates( $calendar_type = 'month', $calendar_start_day = null, $calendar_days = 7, $default_year = null, $default_month = null, $default_day = null ) {
+ if ( $calendar_type == 'month' ) $calendar_start_day = 0;
+
+ if ( $default_year == null ) $default_year = date( "Y", time() );
+ if ( $default_month == null ) $default_month = date( "n", time() );
+ if ( $default_day == null ) $default_day = date( "j", time() );
+
+ global $wgRequest;
+
+ // Set the lower bound based on query string parameters if provided;
+ // otherwise fall back to defaults.
+ if ( $wgRequest->getCheck( 'year' ) && $wgRequest->getCheck( 'month' ) ) {
+
+ $query_year = $wgRequest->getVal( 'year' );
+ if ( is_numeric( $query_year ) && ( intval( $query_year ) == $query_year ) ) {
+ $lower_year = $query_year;
+ }
+ else {
+ $lower_year = $default_year;
+ }
+
+ $query_month = $wgRequest->getVal( 'month' );
+ if ( is_numeric( $query_month ) && ( intval( $query_month ) == $query_month ) && $query_month >= 1 && $query_month <= 12 ) {
+ $lower_month = $query_month;
+ }
+ else {
+ $lower_month = $default_month;
+ }
+
+ $query_day = $wgRequest->getVal( 'day' );
+ if ( $wgRequest->getCheck( 'day' )
+ && is_numeric( $query_day )
+ && ( intval( $query_day ) == $query_day )
+ && $query_day >= 1
+ && $query_day <= 31 ) {
+
+ $lower_day = $query_day;
+ } elseif ( $calendar_type != 'month'
+ && (int)$lower_year == (int)$default_year
+ && (int)$lower_month == (int)$default_month ) {
+
+ $lower_day = $default_day;
+ }
+ else {
+ $lower_day = '1';
+ }
+
+ } else {
+ $lower_year = $default_year;
+ $lower_month = $default_month;
+
+ if ( $calendar_type == 'month' ) {
+ $lower_day = 1;
+ }
+ else {
+ $lower_day = $default_day;
+ }
+ }
+
+ $lower_date = mktime( 0, 0, 0, $lower_month, $lower_day, $lower_year );
+
+ // Date to be queried
+ $return_date = $lower_date;
+
+ // Set the upper bound based on calendar type or number of days.
+ if ( $calendar_type == 'month' ) {
+ $upper_year = date( "Y", $lower_date );
+ $upper_month = date( "n", $lower_date ) + 1;
+ if ( $upper_month == 13 ) {
+ $upper_month = 1;
+ $upper_year = $upper_year + 1;
+ }
+ // One second before start of next month.
+ $upper_date = mktime( 0, 0, 0, $upper_month, 1, $upper_year ) - 1;
+ } else {
+ // One second before start of first day outside our range.
+ $upper_date = $lower_date + $calendar_days * 86400 - 1;
+ }
+
+ // If necessary, adjust bounds to comply with required days of week for each.
+ if ( $calendar_type == 'month' || $calendar_start_day >= 0 ) {
+ $lower_offset = date( "w", $lower_date ) - $calendar_start_day;
+
+ if ( $lower_offset < 0 ) {
+ $lower_offset += 7;
+ }
+
+ if ( $calendar_type == 'month' ) {
+ $upper_offset = $calendar_start_day + 6 - date( "w", $upper_date );
+
+ if ( $upper_offset > 6 ) {
+ $upper_offset -= 7;
+ }
+ } else {
+ $upper_offset = 0 - $lower_offset;
+ }
+
+ $lower_date = $lower_date - 86400 * $lower_offset;
+ $upper_date = $upper_date + 86400 * $upper_offset;
+ }
+
+ // Add a day since users will need to use < operator for upper date.
+ $upper_date += 86400;
+
+ return [ $lower_date, $upper_date, $return_date ];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.php b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.php
new file mode 100644
index 00000000..36a66555
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.php
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * @see https://github.com/SemanticMediaWiki/SemanticResultFormats/
+ *
+ * @defgroup SRF Semantic Result Formats
+ */
+
+SemanticResultFormats::load();
+
+/**
+ * @codeCoverageIgnore
+ */
+class SemanticResultFormats {
+
+ /**
+ * @since 2.5
+ *
+ * @note It is expected that this function is loaded before LocalSettings.php
+ * to ensure that settings and global functions are available by the time
+ * the extension is activated.
+ */
+ public static function load() {
+
+ if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) {
+ include_once __DIR__ . '/vendor/autoload.php';
+ }
+
+ // Load DefaultSettings
+ require_once __DIR__ . '/DefaultSettings.php';
+ }
+
+ /**
+ * @since 2.5
+ */
+ public static function initExtension( $credits = [] ) {
+
+ // See https://phabricator.wikimedia.org/T151136
+ define( 'SRF_VERSION', isset( $credits['version'] ) ? $credits['version'] : 'UNKNOWN' );
+
+ // Register message files
+ $GLOBALS['wgMessagesDirs']['SemanticResultFormats'] = __DIR__ . '/i18n';
+ $GLOBALS['wgExtensionMessagesFiles']['SemanticResultFormats'] = __DIR__ . '/SemanticResultFormats.i18n.php';
+ $GLOBALS['wgExtensionMessagesFiles']['SemanticResultFormatsMagic'] = __DIR__ . '/SemanticResultFormats.i18n.magic.php';
+
+ $GLOBALS['srfgIP'] = __DIR__;
+ $GLOBALS['wgResourceModules'] = array_merge( $GLOBALS['wgResourceModules'], include( __DIR__ . "/Resources.php" ) );
+
+ self::registerHooks();
+ }
+
+ /**
+ * @since 2.5
+ */
+ public static function registerHooks() {
+ $formatDir = __DIR__ . '/formats/';
+
+ unset( $formatDir );
+
+ $GLOBALS['wgHooks']['ParserFirstCallInit'][] = 'SRFParserFunctions::registerFunctions';
+ $GLOBALS['wgHooks']['UnitTestsList'][] = 'SRFHooks::registerUnitTests';
+
+ $GLOBALS['wgHooks']['ResourceLoaderTestModules'][] = 'SRFHooks::registerQUnitTests';
+ $GLOBALS['wgHooks']['ResourceLoaderGetConfigVars'][] = 'SRFHooks::onResourceLoaderGetConfigVars';
+
+ // Format hooks
+ $GLOBALS['wgHooks']['OutputPageParserOutput'][] = 'SRF\Filtered\Hooks::onOutputPageParserOutput';
+ $GLOBALS['wgHooks']['MakeGlobalVariablesScript'][] = 'SRF\Filtered\Hooks::onMakeGlobalVariablesScript';
+
+ // register API modules
+ $GLOBALS['wgAPIModules']['ext.srf.slideshow.show'] = 'SRFSlideShowApi';
+
+ // User preference
+ $GLOBALS['wgHooks']['SMW::GetPreferences'][] = 'SRFHooks::onGetPreferences';
+
+ // Allows last minute changes to the output page, e.g. adding of CSS or JavaScript by extensions
+ $GLOBALS['wgHooks']['BeforePageDisplay'][] = 'SRFHooks::onBeforePageDisplay';
+ }
+
+ /**
+ * @since 2.5
+ */
+ public static function onExtensionFunction() {
+
+ if ( !defined( 'SMW_VERSION' ) ) {
+
+ if ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ) {
+ die( "\nThe 'Semantic Result Formats' extension requires 'Semantic MediaWiki' to be installed and enabled.\n" );
+ } else {
+ die(
+ '<b>Error:</b> The <a href="https://github.com/SemanticMediaWiki/SemanticResultFormats/">Semantic Result Formats</a> ' .
+ 'extension requires <a href="https://www.semantic-mediawiki.org/wiki/Semantic_MediaWiki">Semantic MediaWiki</a> to be ' .
+ 'installed and enabled.<br />'
+ );
+ }
+ }
+
+ // Admin Links hook needs to be called in a delayed way so that it
+ // will always be called after SMW's Admin Links addition; as of
+ // SMW 1.9, SMW delays calling all its hook functions.
+ $GLOBALS['wgHooks']['AdminLinks'][] = 'SRFHooks::addToAdminLinks';
+
+ $GLOBALS['srfgScriptPath'] = ( $GLOBALS['wgExtensionAssetsPath'] === false ? $GLOBALS['wgScriptPath'] . '/extensions' : $GLOBALS['wgExtensionAssetsPath'] ) . '/SemanticResultFormats';
+
+ $formatClasses = [
+ // Assign the Boilerplate class to a format identifier
+ // 'boilerplate' => 'SRFBoilerplate',
+ 'timeline' => 'SRFTimeline',
+ 'eventline' => 'SRFTimeline',
+ 'vcard' => 'SRF\vCard\vCardFileExportPrinter',
+ 'icalendar' => 'SRF\iCalendar\iCalendarFileExportPrinter',
+ 'bibtex' => 'SRF\BibTex\BibTexFileExportPrinter',
+ 'calendar' => 'SRFCalendar',
+ 'eventcalendar' => 'SRF\EventCalendar',
+ 'outline' => 'SRF\Outline\OutlineResultPrinter',
+ 'sum' => 'SRFMath',
+ 'product' => 'SRFMath',
+ 'average' => 'SRFMath',
+ 'min' => 'SRFMath',
+ 'max' => 'SRFMath',
+ 'median' => 'SRFMath',
+ 'exhibit' => 'SRFExhibit',
+ 'googlebar' => 'SRFGoogleBar',
+ 'googlepie' => 'SRFGooglePie',
+ 'jitgraph' => 'SRFJitGraph',
+ 'jqplotchart' => 'SRFjqPlotChart',
+ 'jqplotseries' => 'SRFjqPlotSeries',
+ 'graph' => 'SRF\Graph\GraphPrinter',
+ 'process' => 'SRFProcess',
+ 'gallery' => 'SRF\Gallery',
+ 'tagcloud' => 'SRF\TagCloud',
+ 'valuerank' => 'SRFValueRank',
+ 'array' => 'SRFArray',
+ 'hash' => 'SRFHash',
+ 'd3chart' => 'SRFD3Chart',
+ 'tree' => 'SRF\Formats\Tree\TreeResultPrinter',
+ 'ultree' => 'SRF\Formats\Tree\TreeResultPrinter',
+ 'oltree' => 'SRF\Formats\Tree\TreeResultPrinter',
+ 'filtered' => 'SRF\Filtered\Filtered',
+ 'latest' => 'SRFTime',
+ 'earliest' => 'SRFTime',
+ 'slideshow' => 'SRFSlideShow',
+ 'timeseries' => 'SRFTimeseries',
+ 'sparkline' => 'SRFSparkline',
+ 'listwidget' => 'SRFListWidget',
+ 'pagewidget' => 'SRFPageWidget',
+ 'dygraphs' => 'SRFDygraphs',
+ 'incoming' => 'SRFIncoming',
+ 'media' => 'SRF\MediaPlayer',
+ 'datatables' => 'SRF\DataTables',
+ 'gantt' => 'SRF\Gantt\GanttPrinter'
+ ];
+
+ $formatAliases = [
+ 'tagcloud' => [ 'tag cloud' ],
+ 'datatables' => [ 'datatable' ],
+ 'valuerank' => [ 'value rank' ],
+ 'd3chart' => [ 'd3 chart' ],
+ 'timeseries' => [ 'time series' ],
+ 'jqplotchart' => [ 'jqplot chart', 'jqplotpie', 'jqplotbar' ],
+ 'jqplotseries' => [ 'jqplot series' ],
+ ];
+
+ if ( class_exists( '\PhpOffice\PhpSpreadsheet\Spreadsheet' ) ) {
+ $formatClasses['spreadsheet'] = 'SRF\SpreadsheetPrinter';
+ $formatAliases['spreadsheet'] = [ 'excel' ];
+ }
+
+ foreach ( $GLOBALS['srfgFormats'] as $format ) {
+ if ( array_key_exists( $format, $formatClasses ) ) {
+ $GLOBALS['smwgResultFormats'][$format] = $formatClasses[$format];
+
+ if ( isset( $GLOBALS['smwgResultAliases'] ) && array_key_exists( $format, $formatAliases ) ) {
+ $GLOBALS['smwgResultAliases'][$format] = $formatAliases[$format];
+ }
+ }
+ }
+ }
+
+ /**
+ * @since 2.5
+ *
+ * @return string|null
+ */
+ public static function getVersion() {
+ return SRF_VERSION;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.utils.php b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.utils.php
new file mode 100644
index 00000000..0093c000
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/SemanticResultFormats.utils.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Common libray of independent functions that are shared among different printers
+ * @licence GNU GPL v2 or later
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ */
+final class SRFUtils {
+
+ /**
+ * Helper function that generates a html element, representing a
+ * processing/loading image as long as jquery is inactive
+ *
+ * @param boolean $isHtml
+ *
+ * @since 1.8
+ */
+ public static function htmlProcessingElement( $isHtml = true ) {
+ SMWOutputs::requireResource( 'ext.srf' );
+
+ return Html::rawElement(
+ 'div',
+ [ 'class' => 'srf-spinner mw-small-spinner' ],
+ Html::element(
+ 'span',
+ [ 'class' => 'srf-processing-text' ],
+ wfMessage( 'srf-module-loading' )->inContentLanguage()->text()
+ )
+ );
+ }
+
+ /**
+ * Add JavaScript variables to the output
+ *
+ * @since 1.8
+ */
+ public static function addGlobalJSVariables(){
+ $options = [
+ 'srfgScriptPath' => $GLOBALS['srfgScriptPath'],
+ 'srfVersion' => SRF_VERSION
+ ];
+
+ $requireHeadItem = [ 'srf.options' => $options ];
+ SMWOutputs::requireHeadItem( 'srf.options', Skin::makeVariablesScript( $requireHeadItem, false ) );
+ }
+
+ /**
+ * @brief Returns semantic search link for the current query
+ *
+ * Generate a link to access the current ask query
+ *
+ * @since 1.8
+ *
+ * @param string $link
+ *
+ * @return $link
+ */
+ public static function htmlQueryResultLink( $link ) {
+ // Get linker instance
+ $linker = class_exists( 'DummyLinker' ) ? new DummyLinker : new Linker;
+
+ // Set caption
+ $link->setCaption( '[+]' );
+
+ // Set parameters
+ $link->setParameter( '' , 'class' );
+ $link->setParameter( '' , 'searchlabel' );
+ return $link->getText( SMW_OUTPUT_HTML, $linker );
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/build/travis/install-mediawiki.sh b/www/wiki/extensions/SemanticResultFormats/build/travis/install-mediawiki.sh
new file mode 100644
index 00000000..ac2037ec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/build/travis/install-mediawiki.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+set -ex
+
+cd ..
+
+wget https://github.com/wikimedia/mediawiki/archive/$MW.tar.gz
+tar -zxf $MW.tar.gz
+mv mediawiki-$MW mw
+
+cd mw
+
+## MW 1.25 requires Psr\Logger
+if [ -f composer.json ]
+then
+ composer install
+fi
+
+if [ "$DB" == "postgres" ]
+then
+ psql -c 'create database its_a_mw;' -U postgres
+ php maintenance/install.php --dbtype $DB --dbuser postgres --dbname its_a_mw --pass nyan TravisWiki admin --scriptpath /TravisWiki
+else
+ mysql -e 'create database its_a_mw;'
+ php maintenance/install.php --dbtype $DB --dbuser root --dbname its_a_mw --dbpath $(pwd) --pass nyan TravisWiki admin --scriptpath /TravisWiki
+fi
diff --git a/www/wiki/extensions/SemanticResultFormats/build/travis/install-semantic-result-formats.sh b/www/wiki/extensions/SemanticResultFormats/build/travis/install-semantic-result-formats.sh
new file mode 100644
index 00000000..fb79ef4b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/build/travis/install-semantic-result-formats.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+set -ex
+
+BASE_PATH=$(pwd)
+MW_INSTALL_PATH=$BASE_PATH/../mw
+
+function installPHPUnitWithComposer {
+ if [ "$PHPUNIT" != "" ]
+ then
+ composer require 'phpunit/phpunit='$PHPUNIT --update-with-dependencies
+ fi
+}
+
+function installSMWWithComposer {
+ if [ "$SMW" != "" ]
+ then
+ composer require 'mediawiki/semantic-media-wiki='$SMW --update-with-dependencies
+ fi
+}
+
+# Run Composer installation from the MW root directory
+function installToMediaWikiRoot {
+ echo -e "Running MW root composer install build on $TRAVIS_BRANCH \n"
+
+ cd $MW_INSTALL_PATH
+
+ installPHPUnitWithComposer
+ installSMWWithComposer
+
+ if [ "$MERMAID" != "" ]
+ then
+ composer require 'mediawiki/mermaid='$MERMAID --update-with-dependencies
+ fi
+
+ composer require mediawiki/semantic-result-formats "dev-master"
+
+ cd extensions
+ cd SemanticResultFormats
+
+ # Pull request number, "false" if it's not a pull request
+ # After the install via composer an additional git fetch is carried out to
+ # update the repository to make sure that the latest code changes are
+ # deployed for testing
+ if [ "$TRAVIS_PULL_REQUEST" != "false" ]
+ then
+ git fetch origin +refs/pull/"$TRAVIS_PULL_REQUEST"/merge:
+ git checkout -qf FETCH_HEAD
+ else
+ git fetch origin "$TRAVIS_BRANCH"
+ git checkout -qf FETCH_HEAD
+ fi
+
+ cd ../..
+
+ # Rebuild the class map for added classes during git fetch
+ composer dump-autoload
+}
+
+function updateConfiguration {
+
+ cd $MW_INSTALL_PATH
+
+ # SMW#1732
+ echo 'wfLoadExtension( "SemanticMediaWiki" );' >> LocalSettings.php
+
+ if [ "$MERMAID" != "" ]
+ then
+ echo 'wfLoadExtension( "Mermaid" );' >> LocalSettings.php
+ fi
+
+ echo 'wfLoadExtension( "SemanticResultFormats" );' >> LocalSettings.php
+
+ echo 'error_reporting(E_ALL| E_STRICT);' >> LocalSettings.php
+ echo 'ini_set("display_errors", 1);' >> LocalSettings.php
+ echo '$wgShowExceptionDetails = true;' >> LocalSettings.php
+ echo '$wgDevelopmentWarnings = true;' >> LocalSettings.php
+ echo "putenv( 'MW_INSTALL_PATH=$(pwd)' );" >> LocalSettings.php
+ echo '$GLOBALS["srfgFormats"][] = "filtered";' >> LocalSettings.php
+
+ php maintenance/update.php --skip-external-dependencies --quick
+}
+
+installToMediaWikiRoot
+updateConfiguration
diff --git a/www/wiki/extensions/SemanticResultFormats/build/travis/run-tests.sh b/www/wiki/extensions/SemanticResultFormats/build/travis/run-tests.sh
new file mode 100644
index 00000000..6093e162
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/build/travis/run-tests.sh
@@ -0,0 +1,20 @@
+#! /bin/bash
+set -ex
+
+BASE_PATH=$(pwd)
+MW_INSTALL_PATH=$BASE_PATH/../mw
+
+function uploadCoverageReport {
+ wget https://scrutinizer-ci.com/ocular.phar
+ php ocular.phar code-coverage:upload --format=php-clover coverage.clover
+}
+
+cd $MW_INSTALL_PATH/extensions/SemanticResultFormats
+
+if [ "$TYPE" == "coverage" ]
+then
+ composer phpunit -- --coverage-clover coverage.clover
+ uploadCoverageReport
+else
+ composer phpunit
+fi \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/composer.json b/www/wiki/extensions/SemanticResultFormats/composer.json
new file mode 100644
index 00000000..abb877c5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/composer.json
@@ -0,0 +1,87 @@
+{
+ "name": "mediawiki/semantic-result-formats",
+ "type": "mediawiki-extension",
+ "description": "Provides additional result formats for queries using Semantic MediaWiki",
+ "keywords": [
+ "SRF",
+ "Semantic Result Formats",
+ "Result Formats",
+ "SMW",
+ "Semantic MediaWiki",
+ "Wiki",
+ "MediaWiki"
+ ],
+ "homepage": "https://www.semantic-mediawiki.org/wiki/Extension:Semantic_Result_Formats",
+ "license": "GPL-2.0-or-later",
+ "authors": [
+ {
+ "name": "Jeroen De Dauw",
+ "email": "jeroendedauw@gmail.com",
+ "homepage": "https://www.entropywins.wtf/",
+ "role": "Developer"
+ },
+ {
+ "name": "James Hong Kong",
+ "homepage": "https://www.semantic-mediawiki.org/wiki/User:MWJames",
+ "role": "Developer"
+ },
+ {
+ "name": "Stephan Gambke",
+ "homepage": "https://www.mediawiki.org/wiki/User:F.trott",
+ "role": "Developer"
+ },
+ {
+ "name": "Yaron Koren",
+ "homepage": "https://www.yaronkoren.com/",
+ "role": "Developer"
+ }
+ ],
+ "support": {
+ "email": "semediawiki-user@lists.sourceforge.net",
+ "issues": "https://github.com/SemanticMediaWiki/SemanticResultFormats/issues",
+ "forum": "https://www.semantic-mediawiki.org/wiki/semantic-mediawiki.org_talk:Community_portal",
+ "wiki": "https://www.semantic-mediawiki.org/wiki/",
+ "source": "https://github.com/SemanticMediaWiki/SemanticResultFormats"
+ },
+ "require": {
+ "php": ">=7.0",
+ "composer/installers": "1.*,>=1.0.1",
+ "mediawiki/semantic-media-wiki": "~3.0",
+ "nicmart/tree": "^0.2.7",
+ "data-values/geo": "~4.0|~3.0|~2.0",
+ "symfony/css-selector": "^3.3",
+ "mediawiki/mermaid": "~2.1"
+ },
+ "suggest": {
+ "phpoffice/phpspreadsheet": "Required for 'format=spreadsheet'",
+ "phpoffice/phpexcel": "Required for 'format=excel'",
+ "mediawiki/graph-viz": "Required for 'format=graph' and 'format=process'"
+ },
+ "autoload": {
+ "psr-4": {
+ "SRF\\": "src/"
+ },
+ "files" : [
+ "SemanticResultFormats.php"
+ ],
+ "classmap": [
+ "formats/",
+ "SemanticResultFormats.hooks.php",
+ "SemanticResultFormats.parser.php",
+ "SemanticResultFormats.utils.php"
+ ]
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.x-dev"
+ }
+ },
+ "config": {
+ "process-timeout": 0
+ },
+ "scripts":{
+ "test": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist",
+ "phpunit": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist",
+ "integration": "composer phpunit -- --testsuite=semantic-result-formats-integration"
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/COMPATIBILITY.md b/www/wiki/extensions/SemanticResultFormats/docs/COMPATIBILITY.md
new file mode 100644
index 00000000..e340b7b2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/COMPATIBILITY.md
@@ -0,0 +1,111 @@
+This document holds the **compatibility information** for the Semantic Result Formats (SRF) extension.
+
+- For a full list of changes in each release, see the [release notes](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/RELEASE-NOTES.md).
+- For instructions on how to install the latest version, see the [installation instructions](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/docs/INSTALL.md).
+
+### Platform compatibility
+
+The PHP and MediaWiki version ranges listed are those in which SRF is known to work. It might also
+work with more recent versions of PHP and MediaWiki, though this is not guaranteed. Increases of
+minimum requirements are indicated in bold.
+
+<table>
+ <tr>
+ <th>SRF</th>
+ <th>PHP</th>
+ <th>MediaWiki</th>
+ <th>Semantic MediaWiki</th>
+ <th>Release status</th>
+ </tr>
+ <tr>
+ <th>3.2.x</th>
+ <td><strong>7.1.0</strong> - 7.4.x</td>
+ <td>1.31 - 1.33+</td>
+ <td>3.0.x - 3.1.x+</td>
+ <td>Future release</td>
+ <tr>
+ <tr>
+ <th>3.1.x</th>
+ <td><strong>7.0.0</strong> - 7.3.x</td>
+ <td><strong>1.31</strong> - 1.33</td>
+ <td>3.0.x - 3.1.x</td>
+ <td><strong>Stable release</strong></td>
+ <tr>
+ <tr>
+ <th>3.0.x</th>
+ <td><strong>5.6.0</strong> - 7.1.x</td>
+ <td><strong>1.27</strong> - 1.33</td>
+ <td><strong>3.0.x</strong></td>
+ <td>Obsolete release, no support</td>
+ <tr>
+ <tr>
+ <th>2.5.x</th>
+ <td><strong>5.5.0</strong> - 7.0.x</td>
+ <td><strong>1.23</strong> - 1.29</td>
+ <td>2.1.x - 2.5.x</td>
+ <td>Obsolete release, no support</td>
+ <tr>
+ <th>2.4.x</th>
+ <td>5.3.2 - 7.0.x</td>
+ <td>1.19 - 1.28</td>
+ <td>2.1.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>2.3.x</th>
+ <td>5.3.2 - 5.6.x</td>
+ <td>1.19 - 1.25</td>
+ <td>2.1.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>2.2.x</th>
+ <td>5.3.2 - 5.6.x</td>
+ <td>1.19 - 1.25</td>
+ <td>2.1.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>2.1.x</th>
+ <td>5.3.2 - 5.6.x</td>
+ <td>1.19 - 1.24</td>
+ <td>2.1.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>2.0.x</th>
+ <td>5.3.2 - 5.5.x</td>
+ <td>1.19 - 1.23</td>
+ <td>2.0.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>1.9.x</th>
+ <td><strong>5.3.2</strong> - 5.5.x</td>
+ <td><strong>1.19</strong> - 1.23</td>
+ <td>1.9.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>1.8.x</th>
+ <td>5.2.0 - 5.5.x</td>
+ <td><strong>1.17</strong> - 1.22</td>
+ <td>1.8.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+ <tr>
+ <th>1.7.x</th>
+ <td>5.2.0 - 5.4.x</td>
+ <td>1.16 - 1.19</td>
+ <td>1.7.x</td>
+ <td>Obsolete release, no support</td>
+ </tr>
+</table>
+
+**Note:**
+* It is strongly recommended to also always upgrade the underlying MediaWiki software to supported versions.
+See the [version lifecycle](https://www.mediawiki.org/wiki/Version_lifecycle) for current information on
+supported versions.
+* It is strongly recommended to also always upgrade the underlying Semantic MediaWiki software to supported
+versions. See the page on [compatibility](https://www.semantic-mediawiki.org/wiki/Help:Compatibility) for
+current information on supported versions.
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/CONTRIBUTING.md b/www/wiki/extensions/SemanticResultFormats/docs/CONTRIBUTING.md
new file mode 100644
index 00000000..fa62eb09
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/CONTRIBUTING.md
@@ -0,0 +1,15 @@
+If you would like to make a contribution to [Semantic Result Formats][srf] (a.k.a. SRF), please ensure that pull requests are based on the current master.
+
+In order to swiftly coordinate a contribution, the following should be provided:
+- Code should be easily read and if necessary be put into separate components (or classes)
+- Newly added features should not alter an existing test but instead provide additional test coverage to verify the expected behaviour
+
+For a description on how to write and run PHPUnit test, please consult the [manual][mw-testing].
+
+### Reporting an issue
+
+If you report an issue, please ensure to use the current master (this helps to verify that the problem still persists and isn't solved already) and describe your environment (SMW, MW version etc.) together with a [stack trace][stack-trace] and a clear description on how to reproduce it.
+
+[srf]: https://github.com/SemanticMediaWiki/SemanticExtraSpecialProperties
+[mw-testing]: https://www.mediawiki.org/wiki/Manual:PHP_unit_testing
+[stack-trace]: https://semantic-mediawiki.org/wiki/Stack_trace
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/INSTALL.md b/www/wiki/extensions/SemanticResultFormats/docs/INSTALL.md
new file mode 100644
index 00000000..39087a47
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/INSTALL.md
@@ -0,0 +1,88 @@
+This document holds the **installation and configuration instructions** for the [Semantic Result Formats](README.md) (SRF) extension.
+
+- For information on the release series, see the [version overview](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/VERSIONS.md).
+- For a full list of changes in each release, see the [release notes](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/RELEASE-NOTES.md).
+- For instructions on how to install the latest version, see the [installation instructions](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/docs/INSTALL.md).
+
+# Installation
+
+The recommended way to install Semantic Result Formats is using [Composer](http://getcomposer.org) with
+[MediaWiki's built-in support for Composer](https://www.mediawiki.org/wiki/Composer).
+
+Note that the required extension Semantic MediaWiki must be installed first according to the installation
+instructions provided.
+
+### Step 1
+
+Change to the base directory of your MediaWiki installation. If you do not have a "composer.local.json" file yet,
+create one and add the following content to it:
+
+```
+{
+ "require": {
+ "mediawiki/semantic-result-formats": "~3.1"
+ }
+}
+```
+
+If you already have a "composer.local.json" file add the following line to the end of the "require"
+section in your file:
+
+ "mediawiki/semantic-result-formats": "~3.1"
+
+Remember to add a comma to the end of the preceding line in this section.
+
+### Step 2
+
+Run the following command in your shell:
+
+ php composer.phar update --no-dev
+
+Note if you have Git installed on your system add the `--prefer-source` flag to the above command. Also
+note that it may be necessary to run this command twice. If unsure do it twice right away.
+
+### Step 3
+
+Add the following line to the end of your "LocalSettings.php" file:
+
+ wfLoadExtension( 'SemanticResultFormats' );
+
+## Configuration
+
+A default set of formats is enabled. These are the formats that satisfy the following criteria:
+
+* they do not require further software to be installed (besides Semantic MediaWiki),
+* they do not transmit any data to external websites, not even by making client browsers request
+ any static external resources (such as an externally hosted image file),
+* they are considered reasonably stable and secure.
+
+Currently, these default formats are:
+
+'icalendar', 'vcard', 'bibtex', 'calendar', 'eventcalendar', 'eventline', 'timeline', 'outline',
+'gallery', 'jqplotchart', 'jqplotseries', 'sum', 'average', 'min', 'max', 'median', 'product',
+'tagcloud', 'valuerank', 'array', 'tree', 'ultree', 'oltree', 'd3chart', 'latest', 'earliest',
+'filtered', 'slideshow', 'timeseries', 'sparkline', 'listwidget', 'pagewidget', 'dygraphs', 'media',
+'datatables'
+
+To add more formats to this list, you can add lines like:
+
+ $srfgFormats[] = 'googlebar';
+
+... or you can override the set of formats entirely, with a call like:
+
+ $srfgFormats = [ 'calendar', 'timeline' ];
+
+There are some formats that you may not want to include because they may not follow certain policies
+within your wiki; the formats 'googlebar' and 'googlepie', for instance, send data to external web
+services for rendering, which may be considered a data leak.
+
+Notes on specific formats:
+* array: requires the MediaWiki Arrays extension to work.
+* excel: requires the phpexcel library from phpoffice to work.
+* googlebar: sends data to Google for rendering. It also requires
+ access to the Google servers in order to render.
+* googlepie: sends data to Google for rendering. It also requires
+ access to the Google servers in order to render.
+* graph: requires the MediaWiki GraphViz extension to work.
+* hash: requires the MediaWiki HashTables extensions to work.
+* process: requires the MediaWiki GraphViz extension to work.
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/ISSUE_TEMPLATE.md b/www/wiki/extensions/SemanticResultFormats/docs/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..880c078b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/ISSUE_TEMPLATE.md
@@ -0,0 +1,30 @@
+### Setup
+
+- MW version:
+- DB (MySQL etc.):
+- PHP version:
+- SMW version:
+- SRF version:
+- Browsers and versions (if applicable):
+
+### Issue
+
+...context and general description...
+
+**Steps to reproduce**
+
+(recommendation is to use the [sandbox](https://sandbox.semantic-mediawiki.org))
+
+1. ...
+2. ...
+3. ...
+
+**Expected result:** ...
+
+**Observed result:** ...
+
+**Stacktrace**
+
+```
+...
+```
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/PULL_REQUEST_TEMPLATE.md b/www/wiki/extensions/SemanticResultFormats/docs/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..1384a39d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,13 @@
+This PR is made in reference to: #
+
+This PR addresses or contains:
+- ...
+- ...
+- ...
+
+This PR includes:
+- [ ] Update of RELEASE-NOTES.md
+- [ ] Tests (unit/integration)
+- [ ] CI build passed
+
+Fixes #
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/README.md b/www/wiki/extensions/SemanticResultFormats/docs/README.md
new file mode 100644
index 00000000..898bcf8e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/README.md
@@ -0,0 +1,16 @@
+## General documentation
+
+* [Installation and configuration](INSTALL.md)
+* [Release notes (changes in each version)](../RELEASE-NOTES.md)
+* [Platform compatibility per version](COMPATIBILITY.md)
+* [Homepage](https://www.semantic-mediawiki.org/wiki/Extension:Semantic_Result_Formats)
+
+## Technical documentation
+
+* [Filtered format](https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/formats/filtered/README.md)
+
+## Repository documentation
+
+* [Contributing](CONTRIBUTING.md)
+* [Issue template](ISSUE_TEMPLATE.md)
+* [Pull request template](PULL_REQUEST_TEMPLATE.md)
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/jsduck.categories.json b/www/wiki/extensions/SemanticResultFormats/docs/jsduck.categories.json
new file mode 100644
index 00000000..c6522be8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/jsduck.categories.json
@@ -0,0 +1,66 @@
+[
+ {
+ "name": "General",
+ "groups": [
+ {
+ "name": "Instance",
+ "classes": ["srf"]
+ }
+ ]
+ },
+ {
+ "name": "Formats",
+ "groups": [
+ {
+ "name": "Meta",
+ "classes": ["srf.format"]
+ },
+ {
+ "name": "Formats",
+ "classes": ["srf.formats.*"]
+ }
+ ]
+ },
+ {
+ "name": "Widgets",
+ "groups": [
+ {
+ "name": "Meta",
+ "classes": ["srf.widget*"]
+ }
+ ]
+ },
+ {
+ "name": "Utilities",
+ "groups": [
+ {
+ "name": "Support",
+ "classes": ["srf.util*"]
+ }
+ ]
+ },
+ {
+ "name": "Test",
+ "groups": [
+ {
+ "name": "QUnit",
+ "classes": ["QUnit", "QUnit.assert"]
+ }
+ ]
+ },
+ {
+ "name": "Upstream",
+ "groups": [
+ {
+ "name": "jQuery",
+ "classes": ["jQuery", "jQuery.Event", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR", "QUnit"]
+ },
+ {
+ "name": "JavaScript",
+ "classes": [
+ "Array", "Boolean", "Date", "Function", "Number", "Object", "RegExp", "String"
+ ]
+ }
+ ]
+ }
+] \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/docs/jsduck.json b/www/wiki/extensions/SemanticResultFormats/docs/jsduck.json
new file mode 100644
index 00000000..e257880c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/docs/jsduck.json
@@ -0,0 +1,16 @@
+{
+ "--title": "Semantic Result Formats Code Documentation",
+ "--categories": "../docs/jsduck.categories.json",
+ "--warnings": ["-no_doc"],
+ "--builtin-classes": true,
+ "--external": "HTMLDocument,Window",
+ "--":[
+ "../resources/docs",
+ "../resources/srf",
+ "../formats/tagcloud",
+ "../formats/gallery",
+ "../formats/datatables",
+ "../formats/media",
+ "../formats/calendar"
+ ]
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/extension.json b/www/wiki/extensions/SemanticResultFormats/extension.json
new file mode 100644
index 00000000..4af484ef
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/extension.json
@@ -0,0 +1,33 @@
+{
+ "name": "SemanticResultFormats",
+ "version": "3.1.0",
+ "author": [
+ "James Hong Kong",
+ "Stephan Gambke",
+ "[https://www.entropywins.wtf/mediawiki Jeroen De Dauw]",
+ "Yaron Koren",
+ "..."
+ ],
+ "url": "https://www.semantic-mediawiki.org/wiki/Semantic_Result_Formats",
+ "descriptionmsg": "srf-desc",
+ "namemsg": "srf-name",
+ "license-name": "GPL-2.0-or-later",
+ "type": "semantic",
+ "requires": {
+ "MediaWiki": ">= 1.31",
+ "extensions": {
+ "SemanticMediaWiki": ">= 3.0"
+ }
+ },
+ "MessagesDirs": {
+ "SemanticResultFormats": [
+ "i18n"
+ ]
+ },
+ "callback": "SemanticResultFormats::initExtension",
+ "ExtensionFunctions": [
+ "SemanticResultFormats::onExtensionFunction"
+ ],
+ "load_composer_autoloader":true,
+ "manifest_version": 2
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.css
new file mode 100644
index 00000000..eb6e1b27
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.css
@@ -0,0 +1,3 @@
+.head {border:1px solid gray; background-color:#E0E0E0; padding:4px}
+div.inlines { display:inline; }
+ol.exhibit-tileView-body { list-style-type: none } \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.js
new file mode 100644
index 00000000..f56f456b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.js
@@ -0,0 +1,124 @@
+function createExhibit() {//overload Exhibit's autoCreate-functionality
+
+ /*
+ * This javascript bases on the Wibbit startup procedure and was modified for the use in Semantic MediaWiki
+ * Data: We're using the HTML table importer to get the data for the exhibit.
+ */
+
+ window.database = Exhibit.Database.create();
+ window.exhibit = Exhibit.create(window.database);
+
+ if(!remote){
+
+ for (var id in ex_sources) {
+ var source = ex_sources[id];
+ var dataTable = document.getElementById(source.id);
+ //if (source.hideTable == 1) { dataTable.setAttribute("style", "display:none"); };
+ dataTable.setAttribute("ex:type", source.type);
+ dataTable.setAttribute("ex:label", source.label);
+ dataTable.setAttribute("ex:pluralLabel", source.pluralLabel);
+ var th, ths = dataTable.getElementsByTagName("th");
+ var columns = source.columns;
+ if (columns[0] !== "") {
+ for(var c = 0; c < ths.length; c++) {
+ var split = columns[c].indexOf(':');
+ if (split > 0) {
+ var name = columns[c].substring(0, split);
+ var valueType = columns[c].substring((split + 1), columns[c].length);
+ ths[c].setAttribute('ex:valueType', valueType);
+ } else { var name = columns[c]; }
+ ths[c].setAttribute('ex:name', name);
+ }
+ } else {
+ ths[0].setAttribute('ex:name', 'label');
+ for (var c = 1; c < ths.length; c++) {
+ //Safari uses innerText instead of textContent, so:
+ var thetext = ths[c].textContent || ths[c].innerText;
+ var label = thetext.toLowerCase();
+ label = label.replace(/\s/g,'');
+ ths[c].setAttribute('ex:name', label);
+ }
+ }
+ Exhibit.HtmlTableImporter.loadTable(dataTable, window.database);
+ }}
+
+ window.database.loadDataLinks(); //load JSON files in addition
+
+ var exhibitDiv = document.getElementById('exhibitLocation');
+ exhibitDiv.innerHTML = "<div id='top-facets'></div><table width='100%' style='clear: both'><tr id='exhibit-content' valign='top'><td id='left-facets' width='0%'></td><td id='view-content'><div id='view'></div></td><td id='right-facets' width='0%'></td></tr></table><div id='bottom-facets'></div>";//<div ex:role='exhibit-collection' ex:itemTypes='Item'/>";
+
+ /*
+ * Configuration: We're creating HTML strings that specify the configurations,
+ * formatted in the same form as specifications in the HTML of a regular exhibit.
+ */
+ if (ex_facets) {//facets
+ for (var index in ex_facets) {
+ var facet = ex_facets[index];
+ var position = facet.position;
+ var innerHTML = "<div " + facet.innerHTML + " style='padding: 2px; float: left; width: 15em' ></div>";
+ if (position == "top") {
+ var facetDiv = document.getElementById('top-facets')
+ facetDiv.innerHTML = facetDiv.innerHTML + innerHTML;
+ }
+ if (position == "bottom") {
+ var facetDiv = document.getElementById('bottom-facets');
+ facetDiv.innerHTML = facetDiv.innerHTML + innerHTML;
+ }
+ if (position == "left") {
+ var facetTd = document.getElementById('left-facets');
+ facetTd.innerHTML = facetTd.innerHTML + innerHTML;
+ facetTd.setAttribute('width', '24%');
+ }
+ if (position == "right") {
+ var facetTd = document.getElementById('right-facets');
+ facetTd.innerHTML = facetTd.innerHTML + innerHTML;
+ facetTd.setAttribute('width', '24%');
+ }
+ }
+ }
+
+ if (ex_views && (ex_views[0] !== "")) {//views
+ var viewHTML = '<div '+formats+' id="exhibit-view-panel" ex:role="viewPanel"><div ex:role="lens">'+ex_lens+'</div>';
+ for (var i = 0; i < ex_views.length; i++) {
+ viewHTML = viewHTML + '<div ' + ex_views[i] + ' ></div>';
+ }
+ viewHTML = viewHTML + '</div>';
+ document.getElementById("view").innerHTML = viewHTML;
+ } else {
+ document.getElementById("view").innerHTML = '<div ex:role="view"></div>';
+ }
+
+ for(var i = 0; i < ex_lenscounter; i++){ //lenses
+ var test = document.getElementById("lenscontent"+i);
+ if(test.innerHTML.indexOf('|')>=0){
+ var commands = test.innerHTML.split('|');
+ test.setAttribute('ex:formats','date { template:\'' + commands[1] +'\' }');
+ test.innerHTML = commands[0];
+ }
+ test.setAttribute('ex:content','.' + test.innerHTML.replace(' ','_').toLowerCase());
+ test.setAttribute('class',"inlines");
+ test.innerHTML = '';
+ }
+ for(var i = 0; i < ex_linkcounter; i++){ //lenses
+ var test = document.getElementById("linkcontent"+i);
+ var newlink = document.createElement('a');
+ newlink.setAttribute('ex:href-subcontent',wgServer + wgScript + '?title={{urlenc(.' + test.innerHTML + ')}}');
+ newlink.setAttribute('ex:content','.' + test.innerHTML);
+ test.innerHTML = '';
+ test.appendChild(newlink);
+ }
+ for(var i = 0; i < ex_imagecounter; i++){ //lenses
+ var test = document.getElementById("imagecontent"+i);
+ var newimage = document.createElement('img');
+ newimage.setAttribute('ex:src-content','.' + test.innerHTML);
+ newimage.setAttribute('height','100');
+ test.innerHTML = '';
+ test.appendChild(newimage);
+ }
+
+ window.exhibit.configureFromDOM();
+}
+
+addOnloadHook(createExhibit);
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.php b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.php
new file mode 100644
index 00000000..a666733a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/SRF_Exhibit.php
@@ -0,0 +1,628 @@
+<?php
+/**
+ * Use Exhibit to print query results.
+ *
+ * @author Fabian Howahl
+ * @file
+ * @ingroup SMWQuery
+ */
+
+/**
+ * Result printer using Exhibit to display query results
+ *
+ * @ingroup SMWQuery
+ */
+class SRFExhibit extends SMWResultPrinter {
+
+ // /mapping between SMW's and Exhibit's the data types
+ protected $m_types = [ "_wpg" => "text", "_num" => "number", "_dat" => "date", "_geo" => "text", "_uri" => "url" ];
+
+ protected static $exhibitRunningNumber = 0; // not sufficient since there might be multiple pages rendered within one PHP run; but good enough now
+
+ // /overwrite function to allow execution of result printer even if no results are available (in case remote query yields no results in local wiki)
+ public function getResult( $results, $params, $outputmode ) {
+ $this->readParameters( $params, $outputmode );
+ $result = $this->getResultText( $results, $outputmode );
+ return $result;
+ }
+
+ // /function aligns the format of SMW's property names to Exhibit's format
+ protected function encodePropertyName( $property ) {
+ return strtolower( str_replace( " ", "_", trim( $property ) ) );
+ }
+
+ // /Tries to determine the namespace in the event it got lost
+ protected function determineNamespace( $res ) {
+ $row = $res->getNext();
+ if ( $row != null ) {
+ $tmp = clone $row[0];
+ $object = $tmp->getNextDataValue();
+
+ if ( $object instanceof SMWWikiPageValue ) {
+ $value = $object->getPrefixedText();
+ if ( strpos( $value, ':' ) ) {
+ $value = explode( ':', $value, 2 );
+ return $value[0] . ':';
+ }
+ }
+ }
+
+ return "";
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+
+ global $smwgIQRunningNumber, $wgScriptPath, $wgGoogleMapsKey, $srfgScriptPath;
+
+ if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
+ SMWOutputs::requireHeadItem( 'exhibit-compat', Html::linkedScript( "$wgScriptPath/common/wikibits.js" ) );
+ }
+
+ // //////////////////////////////
+ // ///////REMOTE STUFF///////////
+ // //////////////////////////////
+
+ $remote = false;
+
+ // in case the remote parameter is set, a link to the JSON export of the remote wiki is included in the header as data source for Exhibit
+ // this section creates the link
+ if ( array_key_exists( 'remote', $this->params ) && srfgExhibitRemote == true ) {
+
+ $remote = true;
+
+ // fetch interwiki link
+ $dbr = &wfGetDB( DB_SLAVE );
+ $cl = $dbr->tableName( 'interwiki' );
+ $dbres = $dbr->select( $cl, 'iw_url', "iw_prefix='" . $this->params['remote'] . "'", __METHOD__, [] );
+ $row = $dbr->fetchRow( $dbres );
+ $extlinkpattern = $row[iw_url];
+ $dbr->freeResult( $dbres );
+
+ $newheader = '<link rel="exhibit/data" type="application/jsonp" href="';
+ $link = $res->getQueryLink( 'JSON Link' );
+ $link->setParameter( 'json', 'format' );
+
+ if ( array_key_exists(
+ 'callback',
+ $this->params
+ ) ) { // check if a special name for the callback function is set, if not stick with 'callback'
+ $callbackfunc = $this->params['callback'];
+ } else {
+ $callbackfunc = 'callback';
+ }
+
+ if ( array_key_exists( 'limit', $this->params ) ) {
+ $link->setParameter( $this->params['limit'], 'limit' );
+ }
+
+ $link->setParameter( $callbackfunc, 'callback' );
+ $link = $link->getText( 2, $this->mLinker );
+
+ list( $link, $trash ) = explode( '|', $link );
+ $link = str_replace( '[[:', '', $link );
+
+ $newheader .= str_replace( '$1', $link, $extlinkpattern );
+ $newheader .= '" ex:jsonp-callback="' . $callbackfunc . '"';
+ $newheader .= '/>';
+
+ SMWOutputs::requireHeadItem( 'REMOTE', $newheader );
+ }
+
+ // the following variables indicate the use of special views
+ // the variable's values define the way Exhibit is called
+ $timeline = false;
+ $map = false;
+
+ /*The javascript file adopted from Wibbit uses a bunch of javascript variables in the header to store information about the Exhibit markup.
+ The following code sequence creates these variables*/
+
+ // prepare sources (the sources holds information about the table which contains the information)
+ $colstack = [];
+ foreach ( $res->getPrintRequests() as $pr ) {
+ $colstack[] = $this->encodePropertyName( $pr->getLabel() ) . ':' . ( array_key_exists(
+ $pr->getTypeID(),
+ $this->m_types
+ ) ? $this->m_types[$pr->getTypeID()] : 'text' );
+ }
+ array_shift( $colstack );
+ array_unshift( $colstack, 'label' );
+
+ if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
+ $sourcesrc = "var ex_sources = { source" . ( $smwgIQRunningNumber - 1 ) . ": { id: 'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
+ ',',
+ $colstack
+ ) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' } };";
+ } else {
+ $sourcesrc = "sources.source" . $smwgIQRunningNumber . " = { id: 'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
+ ',',
+ $colstack
+ ) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' };";
+ }
+ $sourcesrc = "<script type=\"text/javascript\">" . $sourcesrc . "</script>";
+
+ // prepare facets
+ $facetcounter = 0;
+ if ( array_key_exists( 'facets', $this->params ) ) {
+ $facets = explode( ',', $this->params['facets'] );
+ $facetstack = [];
+ $params = [ 'height' ];
+ $facparams = [];
+ foreach ( $params as $param ) {
+ if ( array_key_exists( $param, $this->params ) ) {
+ $facparams[] = 'ex:' . $param . '="' . $this->encodePropertyName( $this->params[$param] ) . '" ';
+ }
+ }
+ foreach ( $facets as $facet ) {
+ $facet = trim( $facet );
+ if ( strtolower( $facet ) == "search" ) { // special facet (text search)
+ $facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:facetClass="TextSearch" ex:facetLabel="' . $facet . '"\'}';
+ } else { // usual facet
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( $this->encodePropertyName( $pr->getLabel() ) == $this->encodePropertyName( $facet ) ) {
+ switch ( $pr->getTypeID() ) {
+ case '_num':
+ $facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:expression=".' . $this->encodePropertyName(
+ $facet
+ ) . '" ex:facetLabel="' . $facet . '" ex:facetClass="Slider"\'}';
+ break;
+ default:
+ $facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ' . implode(
+ " ",
+ $facparams
+ ) . ' ex:expression=".' . $this->encodePropertyName(
+ $facet
+ ) . '" ex:facetLabel="' . $facet . '"\'}';
+ }
+ }
+
+ }
+ }
+ }
+ $facetstring = implode( ',', $facetstack );
+ } else {
+ $facetstring = '';
+ }
+ $facetsrc = "var ex_facets = {" . $facetstring . " };";
+
+ // prepare views
+ $stylesrc = '';
+ if ( array_key_exists( 'views', $this->params ) ) {
+ $views = explode( ',', $this->params['views'] );
+ } else {
+ $views[] = 'tiles';
+ }
+
+ foreach ( $views as $view ) {
+ switch ( trim( $view ) ) {
+ case 'tabular':// table view (the columns are automatically defined by the selected properties)
+ $thstack = [];
+ foreach ( $res->getPrintRequests() as $pr ) {
+ $thstack[] = "." . $this->encodePropertyName( $pr->getLabel() );
+ }
+ array_shift( $thstack );
+ array_unshift( $thstack, '.label' );
+ $stylesrc = 'var myStyler = function(table, database) {table.className=\'smwtable\';};'; // assign SMWtable CSS to Exhibit tabular view
+ $viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Tabular\' ex:showSummary=\'false\' ex:sortAscending=\'true\' ex:tableStyler=\'myStyler\' ex:label=\'Table\' ex:columns=\'' . implode(
+ ',',
+ $thstack
+ ) . '\' ex:sortAscending=\'false\'';
+ break;
+ case 'timeline':// timeline view
+ $timeline = true;
+ $exparams = [
+ 'start',
+ 'end',
+ 'proxy',
+ 'colorkey' ]; // parameters expecting an Exhibit graph expression
+ $usparams = [
+ 'timelineheight',
+ 'topbandheight',
+ 'bottombandheight',
+ 'bottombandunit',
+ 'topbandunit' ]; // parametes expecting a textual or numeric value
+ $tlparams = [];
+ foreach ( $exparams as $param ) {
+ if ( array_key_exists( $param, $this->params ) ) {
+ $tlparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
+ $this->params[$param]
+ ) . '\' ';
+ }
+ }
+ foreach ( $usparams as $param ) {
+ if ( array_key_exists( $param, $this->params ) ) {
+ $tlparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
+ $this->params[$param]
+ ) . '\' ';
+ }
+ }
+ if ( !array_key_exists(
+ 'start',
+ $this->params
+ ) ) {// find out if a start and/or end date is specified
+ $dates = [];
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( $pr->getTypeID() == '_dat' ) {
+ $dates[] = $pr;
+ if ( sizeof( $dates ) > 2 ) {
+ break;
+ }
+ }
+ }
+ if ( sizeof( $dates ) == 1 ) {
+ $tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
+ } elseif ( sizeof( $dates ) == 2 ) {
+ $tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
+ $tlparams[] = 'ex:end=\'.' . $this->encodePropertyName( $dates[1]->getLabel() ) . '\' ';
+ }
+ }
+ $viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Timeline\' ex:label=\'Timeline\' ex:showSummary=\'false\' ' . implode(
+ " ",
+ $tlparams
+ );
+ break;
+ case 'map':// map view
+ if ( isset( $wgGoogleMapsKey ) ) {
+ $map = true;
+ $exparams = [ 'latlng', 'colorkey' ];
+ $usparams = [
+ 'type',
+ 'center',
+ 'zoom',
+ 'size',
+ 'scalecontrol',
+ 'overviewcontrol',
+ 'mapheight' ];
+ $mapparams = [];
+ foreach ( $exparams as $param ) {
+ if ( array_key_exists( $param, $this->params ) ) {
+ $mapparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
+ $this->params[$param]
+ ) . '\' ';
+ }
+ }
+ foreach ( $usparams as $param ) {
+ if ( array_key_exists( $param, $this->params ) ) {
+ $mapparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
+ $this->params[$param]
+ ) . '\' ';
+ }
+ }
+ if ( !array_key_exists( 'start', $this->params ) && !array_key_exists(
+ 'end',
+ $this->params
+ ) ) { // find out if a geographic coordinate is available
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( $pr->getTypeID() == '_geo' ) {
+ $mapparams[] = 'ex:latlng=\'.' . $this->encodePropertyName(
+ $pr->getLabel()
+ ) . '\' ';
+ break;
+ }
+ }
+ }
+ $viewstack[] .= 'ex:role=\'view\' ex:viewClass=\'Map\' ex:showSummary=\'false\' ex:label=\'Map\' ' . implode(
+ " ",
+ $mapparams
+ );
+ }
+ break;
+ default:
+ case 'tiles':// tile view
+ $sortstring = '';
+ if ( array_key_exists( 'sort', $this->params ) ) {
+ $sortfields = explode( ",", $this->params['sort'] );
+ foreach ( $sortfields as $field ) {
+ $sortkeys[] = "." . $this->encodePropertyName( trim( $field ) );
+ }
+ $sortstring = 'ex:orders=\'' . implode( ",", $sortkeys ) . '\' ';
+ if ( array_key_exists( 'order', $this->params ) ) {
+ $sortstring .= ' ex:directions=\'' . $this->encodePropertyName(
+ $this->params['order']
+ ) . '\'';
+ }
+ if ( array_key_exists( 'grouped', $this->params ) ) {
+ $sortstring .= ' ex:grouped=\'' . $this->encodePropertyName(
+ $this->params['grouped']
+ ) . '\'';
+ }
+ }
+ $viewstack[] = 'ex:role=\'view\' ex:showSummary=\'false\' ' . $sortstring;
+ break;
+ }
+ }
+
+ $viewsrc = 'var ex_views = "' . implode( "/", $viewstack ) . '".split(\'/\');;';
+
+ // prepare automatic lenses
+
+ global $wgParser;
+ $lenscounter = 0;
+ $linkcounter = 0;
+ $imagecounter = 0;
+
+ if ( array_key_exists(
+ 'lens',
+ $this->params
+ ) ) {// a customized lens is specified via the lens parameter within the query
+ $lenstitle = Title::newFromText( "Template:" . $this->params['lens'] );
+ $lensarticle = new Article( $lenstitle );
+ $lenswikitext = $lensarticle->getContent();
+
+ if ( preg_match_all(
+ "/[\[][\[][Ii][m][a][g][e][:][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
+ $lenswikitext,
+ $matches
+ ) ) {
+ foreach ( $matches as $match ) {
+ foreach ( $match as $value ) {
+ $strippedvalue = trim( substr( $value, 8 ), "[[{}]]" );
+ $lenswikitext = str_replace(
+ $value,
+ '<div class="inlines" id="imagecontent' . $imagecounter . '">' . $this->encodePropertyName(
+ strtolower( str_replace( "\n", "", $strippedvalue ) )
+ ) . '</div>',
+ $lenswikitext
+ );
+ $imagecounter++;
+ }
+ }
+ }
+
+ if ( preg_match_all(
+ "/[\[][\[][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
+ $lenswikitext,
+ $matches
+ ) ) {
+ foreach ( $matches as $match ) {
+ foreach ( $match as $value ) {
+ $strippedvalue = trim( $value, "[[{}]]" );
+ $lenswikitext = str_replace(
+ $value,
+ '<div class="inlines" id="linkcontent' . $linkcounter . '">' . $this->encodePropertyName(
+ strtolower( str_replace( "\n", "", $strippedvalue ) )
+ ) . '</div>',
+ $lenswikitext
+ );
+ $linkcounter++;
+ }
+ }
+ }
+
+ if ( preg_match_all( "/[{][{][{][1-9A-z\:\|\/\=\-[:space:]]*[}][}][}]/u", $lenswikitext, $matches ) ) {
+ foreach ( $matches as $match ) {
+ foreach ( $match as $value ) {
+ $strippedvalue = trim( $value, "{}" );
+ $lenswikitext = str_replace(
+ $value,
+ '<div class="inlines" id="lenscontent' . $lenscounter . '">' . $this->encodePropertyName(
+ strtolower( str_replace( "\n", "", $strippedvalue ) )
+ ) . '</div>',
+ $lenswikitext
+ );
+ $lenscounter++;
+ }
+ }
+ }
+
+ $lenshtml = $wgParser->internalParse(
+ $lenswikitext
+ );// $wgParser->parse($lenswikitext, $lenstitle, new ParserOptions(), true, true)->getText();
+
+ $lenssrc = "var ex_lens = '" . str_replace(
+ "\n",
+ "",
+ $lenshtml
+ ) . "';ex_lenscounter =" . $lenscounter . ";ex_linkcounter=" . $linkcounter . ";ex_imagecounter=" . $imagecounter . ";";
+ } else {// generic lens (creates links to further content (property-pages, pages about values)
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( $remote ) {
+ $wikiurl = str_replace( "$1", "", $extlinkpattern );
+ } else {
+ $wikiurl = $wgScriptPath . "/index.php?title=";
+ }
+ if ( $pr->getTypeID() == '_wpg' ) {
+ $prefix = '';
+ if ( $pr->getLabel() == 'Category' ) {
+ $prefix = "Category:";
+ }
+ $lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
+ $pr->getLabel()
+ ) . '"><td width="20%">' . $pr->getText(
+ 0,
+ $this->mLinker
+ ) . '</td><td width="80%" ex:content=".' . $this->encodePropertyName(
+ $pr->getLabel()
+ ) . '"><a ex:href-subcontent="' . $wikiurl . $prefix . '{{urlencval(value)}}"><div ex:content="value" class="name"></div></a></td></tr>';
+ } else {
+ $lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
+ $pr->getLabel()
+ ) . '"><td width="20%">' . $pr->getText(
+ 0,
+ $this->mLinker
+ ) . '</td><td width="80%"><div ex:content=".' . $this->encodePropertyName(
+ $pr->getLabel()
+ ) . '" class="name"></div></td></tr>';
+ }
+ }
+ array_shift( $lensstack );
+ $lenssrc = 'var ex_lens = \'<table width=100% cellpadding=3><tr><th class="head" align=left bgcolor="#DDDDDD"><a ex:href-subcontent="' . $wikiurl . $this->determineNamespace(
+ clone $res
+ ) . '{{urlenc(.label)}}" class="linkhead"><div ex:content=".label" class="name"></div></a></th></tr></table><table width="100%" cellpadding=3>' . implode(
+ "",
+ $lensstack
+ ) . '</table>\'; ex_lenscounter = 0; ex_linkcounter=0; ex_imagecounter=0;';
+ }
+
+ if ( $remote ) {
+ $varremote = 'true';
+ } else {
+ $varremote = 'false';
+ }
+
+ // Handling special formats like date
+ $formatssrc = 'var formats =\'\'';
+ if ( array_key_exists( 'date', $this->params ) ) {
+ $formatssrc = 'var formats = \'ex:formats="date { mode:' . $this->params['date'] . '; show:date }"\';';
+ }
+
+ // create a URL pointing to the corresponding JSON feed
+ $label = '';
+ $JSONlink = $res->getQueryLink( $label );
+ if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) { // used as a file name
+ $link->setParameter( $this->getSearchLabel( SMW_OUTPUT_WIKI ), 'searchlabel' );
+ }
+ if ( array_key_exists( 'limit', $this->params ) ) {
+ $JSONlink->setParameter( htmlspecialchars( $this->params['limit'] ), 'limit' );
+ }
+ $JSONlink->setParameter( 'json', 'format' );
+ $stringtoedit = explode( "|", $JSONlink->getText( $outputmode, $this->mLinker ) );
+ $stringtoedit = substr( $stringtoedit[0], 3 );
+ $JSONlinksrc = "var JSONlink = '" . $stringtoedit . "';";
+
+ // create script header with variables containing the Exhibit markup
+ $headervars = "<script type='text/javascript'>\n\t\t\t" . $facetsrc . "\n\t\t\t" . $viewsrc . "\n\t\t\t" . $lenssrc . "\n\t\t\t" . $stylesrc . "\n\t\t\t" . $formatssrc . "\n\t\t\t" . $JSONlinksrc . "\n\t\t\t var remote=" . $varremote . ";</script>";
+
+ // To run Exhibit some links to the scripts of the API need to be included in the header
+
+ $ExhibitScriptSrc1 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/exhibit/exhibit-api.js?autoCreate=false&safe=true&bundle=false';
+ if ( $timeline ) {
+ $ExhibitScriptSrc1 .= '&views=timeline';
+ }
+ if ( $map ) {
+ $ExhibitScriptSrc1 .= '&gmapkey=' . $wgGoogleMapsKey;
+ }
+ $ExhibitScriptSrc1 .= '"></script>';
+ $ExhibitScriptSrc2 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.js"></script>';
+ $CSSSrc = '<link rel="stylesheet" type="text/css" href="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.css"></link>';
+
+ SMWOutputs::requireHeadItem( 'CSS', $CSSSrc ); // include CSS
+ SMWOutputs::requireHeadItem( 'EXHIBIT1', $ExhibitScriptSrc1 ); // include Exhibit API
+ SMWOutputs::requireHeadItem(
+ 'EXHIBIT2',
+ $ExhibitScriptSrc2
+ ); // includes javascript overwriting the Exhibit start-up functions
+ SMWOutputs::requireHeadItem( 'SOURCES' . $smwgIQRunningNumber, $sourcesrc );// include sources variable
+ SMWOutputs::requireHeadItem( 'VIEWSFACETS', $headervars );// include views and facets variable
+
+ if ( !$remote ) {
+
+ // print input table
+ // print header
+ $result = "<table style=\"display:none\" class=\"smwtable\" id=\"querytable" . $smwgIQRunningNumber . "\">\n";
+ if ( $this->mShowHeaders ) { // building headers
+ $result .= "\t<tr>\n";
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( $pr->getText( $outputmode, $this->getLinker( 0 ) ) == '' ) {
+ $headerlabel = "Name";
+ } else {
+ $headerlabel = $pr->getText( $outputmode, $this->getLinker( 0 ) );
+ }
+ $result .= "\t\t<th>" . $headerlabel . "</th>\n";
+ }
+ $result .= "\t</tr>\n";
+ }
+
+ // print all result rows
+ while ( $row = $res->getNext() ) {
+ $result .= "\t<tr>\n";
+ foreach ( $row as $field ) {
+ $result .= "\t\t<td>";
+ $textstack = [];
+ while ( ( $object = $field->getNextDataValue() ) !== false ) {
+ switch ( $object->getTypeID() ) {
+ case '_wpg':
+ $textstack[] = $object->getLongText( $outputmode, $this->getLinker( 0 ) );
+ break;
+ case '_geo':
+ $c = $object->getDBKeys();
+ $textstack[] = $c[0] . "," . $c[1];
+ break;
+ case '_num':
+ if ( method_exists( $object, 'getValueKey' ) ) {
+ $textstack[] = $object->getValueKey( $outputmode, $this->getLinker( 0 ) );
+ } else {
+ $textstack[] = $object->getNumericValue( $outputmode, $this->getLinker( 0 ) );
+ }
+ break;
+ case '_dat':
+ $textstack[] = $object->getYear() . "-" . str_pad(
+ $object->getMonth(),
+ 2,
+ '0',
+ STR_PAD_LEFT
+ ) . "-" . str_pad(
+ $object->getDay(),
+ 2,
+ '0',
+ STR_PAD_LEFT
+ ) . " " . $object->getTimeString();
+ break;
+ case '_ema':
+ $textstack[] = $object->getShortWikiText( $this->getLinker( 0 ) );
+ break;
+ case '_tel':
+ case '_anu':
+ case '_uri':
+ $textstack[] = $object->getWikiValue();
+ break;
+ case '__sin':
+ $tmp = $object->getShortText( $outputmode, null );
+ if ( strpos( $tmp, ":" ) ) {
+ $tmp = explode( ":", $tmp, 2 );
+ $tmp = $tmp[1];
+ }
+ $textstack[] = $tmp;
+ break;
+ case '_txt':
+ case '_cod':
+ case '_str':
+ $textstack[] = $object->getWikiValue();
+ break;
+ default:
+ $textstack[] = $object->getLongHTMLText( $this->getLinker( 0 ) );
+ }
+ }
+
+ if ( $textstack != null ) {
+ $result .= implode( ';', $textstack ) . "</td>\n";
+ } else {
+ $result .= "</td>\n";
+ }
+ }
+ $result .= "\t</tr>\n";
+ }
+ $result .= "</table>\n";
+ }
+
+ if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
+ $result .= "<div id=\"exhibitLocation\"></div>";
+ } // print placeholder (just print it one time)
+ $this->isHTML = ( $outputmode == SMW_OUTPUT_HTML ); // yes, our code can be viewed as HTML if requested, no more parsing needed
+ SRFExhibit::$exhibitRunningNumber++;
+ return $result;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params[] = [
+ 'name' => 'views',
+ 'message' => 'srf_paramdesc_views',
+ 'islist' => true,
+ 'values' => [ 'tiles', 'tabular', 'timeline', 'maps' ] ];
+ $params[] = [ 'name' => 'facets', 'message' => 'srf_paramdesc_facets' ];
+ $params[] = [ 'name' => 'lens', 'message' => 'srf_paramdesc_lens' ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/LICENSE.txt b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/LICENSE.txt
new file mode 100644
index 00000000..2f3e0503
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/LICENSE.txt
@@ -0,0 +1,29 @@
+/*
+ * (c) Copyright The SIMILE Project 2006. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-epilog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-epilog.js
new file mode 100644
index 00000000..d1a70927
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-epilog.js
@@ -0,0 +1,16 @@
+(function() {
+ var f = null;
+ if ("SimileWidgets_onLoad" in window) {
+ if (typeof SimileWidgets_onLoad == "string") {
+ f = eval(SimileWidgets_onLoad);
+ SimileWidgets_onLoad = null;
+ } else if (typeof SimileWidgets_onLoad == "function") {
+ f = SimileWidgets_onLoad;
+ SimileWidgets_onLoad = null;
+ }
+ }
+
+ if (f != null) {
+ f();
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-prolog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-prolog.js
new file mode 100644
index 00000000..5c5cd684
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/compile-prolog.js
@@ -0,0 +1 @@
+window.SimileAjax_isCompiled = true; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/content/history.html b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/content/history.html
new file mode 100644
index 00000000..a30fbd81
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/content/history.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+ <title>Dummy Page for Keeping Track of History</title>
+</head>
+<body>
+</body>
+</html> \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-down.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-down.png
new file mode 100644
index 00000000..9fefa020
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-down.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-left.png
new file mode 100644
index 00000000..6a430faf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-right.png
new file mode 100644
index 00000000..e9625403
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-up.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-up.png
new file mode 100644
index 00000000..5afbf048
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-arrow-point-up.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-left.png
new file mode 100644
index 00000000..a8c51488
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-right.png
new file mode 100644
index 00000000..0096633e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom.png
new file mode 100644
index 00000000..6875a448
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-bottom.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-left.png
new file mode 100644
index 00000000..27ddcca6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-right.png
new file mode 100644
index 00000000..7d937f5b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-left.png
new file mode 100644
index 00000000..08739c4d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-right.png
new file mode 100644
index 00000000..bd49cf74
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top.png
new file mode 100644
index 00000000..ba2d9f98
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/bubble-top.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/close-button.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/close-button.png
new file mode 100644
index 00000000..2c6f9e1a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/close-button.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/copy.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/copy.png
new file mode 100644
index 00000000..fbc3e583
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/copy.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-left.png
new file mode 100644
index 00000000..4f8c64a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-right.png
new file mode 100644
index 00000000..a8834bb6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-left.png
new file mode 100644
index 00000000..b6416aab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-right.png
new file mode 100644
index 00000000..729524bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-left.png
new file mode 100644
index 00000000..b0501341
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-right.png
new file mode 100644
index 00000000..01a82ab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/images/message-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/loader.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/loader.js
new file mode 100644
index 00000000..86ba5ac3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/loader.js
@@ -0,0 +1,34 @@
+(function() {
+ if ("SimileWidgets_styles" in window) {
+ var head = document.getElementsByTagName("head")[0];
+ var styles = SimileWidgets_styles;
+ for (var i = 0; i < styles.length; i++) {
+ var link = document.createElement("link");
+ link.href = styles[i];
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ head.appendChild(link);
+ }
+ }
+ if ("SimileWidgets_scripts" in window) {
+ var onLoad = window.SimileWidgets_onLoad;
+
+ var scripts = SimileWidgets_scripts;
+ var i = 0;
+ var next = function() {
+ if (i < scripts.length) {
+ var url = scripts[i++];
+
+ window.SimileWidgets_onLoad = arguments.callee;
+
+ var script = document.createElement("script");
+ script.src = url;
+ script.type = "text/javascript";
+ document.body.appendChild(script);
+ } else {
+ onLoad();
+ }
+ };
+ next();
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/ajax.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/ajax.js
new file mode 100644
index 00000000..71726092
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/ajax.js
@@ -0,0 +1,45 @@
+/*==================================================
+ * General, miscellaneous SimileAjax stuff
+ *==================================================
+ */
+
+SimileAjax.ListenerQueue = function(wildcardHandlerName) {
+ this._listeners = [];
+ this._wildcardHandlerName = wildcardHandlerName;
+};
+
+SimileAjax.ListenerQueue.prototype.add = function(listener) {
+ this._listeners.push(listener);
+};
+
+SimileAjax.ListenerQueue.prototype.remove = function(listener) {
+ var listeners = this._listeners;
+ for (var i = 0; i < listeners.length; i++) {
+ if (listeners[i] == listener) {
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+SimileAjax.ListenerQueue.prototype.fire = function(handlerName, args) {
+ var listeners = [].concat(this._listeners);
+ for (var i = 0; i < listeners.length; i++) {
+ var listener = listeners[i];
+ if (handlerName in listener) {
+ try {
+ listener[handlerName].apply(listener, args);
+ } catch (e) {
+ SimileAjax.Debug.exception("Error firing event of name " + handlerName, e);
+ }
+ } else if (this._wildcardHandlerName != null &&
+ this._wildcardHandlerName in listener) {
+ try {
+ listener[this._wildcardHandlerName].apply(listener, [ handlerName ]);
+ } catch (e) {
+ SimileAjax.Debug.exception("Error firing event of name " + handlerName + " to wildcard handler", e);
+ }
+ }
+ }
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/data-structure.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/data-structure.js
new file mode 100644
index 00000000..e789cb41
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/data-structure.js
@@ -0,0 +1,447 @@
+/**
+ * A basic set (in the mathematical sense) data structure
+ *
+ * @constructor
+ * @param {Array or SimileAjax.Set} [a] an initial collection
+ */
+SimileAjax.Set = function(a) {
+ this._hash = {};
+ this._count = 0;
+
+ if (a instanceof Array) {
+ for (var i = 0; i < a.length; i++) {
+ this.add(a[i]);
+ }
+ } else if (a instanceof SimileAjax.Set) {
+ this.addSet(a);
+ }
+}
+
+/**
+ * Adds the given object to this set, assuming there it does not already exist
+ *
+ * @param {Object} o the object to add
+ * @return {Boolean} true if the object was added, false if not
+ */
+SimileAjax.Set.prototype.add = function(o) {
+ if (!(o in this._hash)) {
+ this._hash[o] = true;
+ this._count++;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Adds each element in the given set to this set
+ *
+ * @param {SimileAjax.Set} set the set of elements to add
+ */
+SimileAjax.Set.prototype.addSet = function(set) {
+ for (var o in set._hash) {
+ this.add(o);
+ }
+}
+
+/**
+ * Removes the given element from this set
+ *
+ * @param {Object} o the object to remove
+ * @return {Boolean} true if the object was successfully removed,
+ * false otherwise
+ */
+SimileAjax.Set.prototype.remove = function(o) {
+ if (o in this._hash) {
+ delete this._hash[o];
+ this._count--;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Removes the elements in this set that correspond to the elements in the
+ * given set
+ *
+ * @param {SimileAjax.Set} set the set of elements to remove
+ */
+SimileAjax.Set.prototype.removeSet = function(set) {
+ for (var o in set._hash) {
+ this.remove(o);
+ }
+}
+
+/**
+ * Removes all elements in this set that are not present in the given set, i.e.
+ * modifies this set to the intersection of the two sets
+ *
+ * @param {SimileAjax.Set} set the set to intersect
+ */
+SimileAjax.Set.prototype.retainSet = function(set) {
+ for (var o in this._hash) {
+ if (!set.contains(o)) {
+ delete this._hash[o];
+ this._count--;
+ }
+ }
+}
+
+/**
+ * Returns whether or not the given element exists in this set
+ *
+ * @param {SimileAjax.Set} o the object to test for
+ * @return {Boolean} true if the object is present, false otherwise
+ */
+SimileAjax.Set.prototype.contains = function(o) {
+ return (o in this._hash);
+}
+
+/**
+ * Returns the number of elements in this set
+ *
+ * @return {Number} the number of elements in this set
+ */
+SimileAjax.Set.prototype.size = function() {
+ return this._count;
+}
+
+/**
+ * Returns the elements of this set as an array
+ *
+ * @return {Array} a new array containing the elements of this set
+ */
+SimileAjax.Set.prototype.toArray = function() {
+ var a = [];
+ for (var o in this._hash) {
+ a.push(o);
+ }
+ return a;
+}
+
+/**
+ * Iterates through the elements of this set, order unspecified, executing the
+ * given function on each element until the function returns true
+ *
+ * @param {Function} f a function of form f(element)
+ */
+SimileAjax.Set.prototype.visit = function(f) {
+ for (var o in this._hash) {
+ if (f(o) == true) {
+ break;
+ }
+ }
+}
+
+/**
+ * A sorted array data structure
+ *
+ * @constructor
+ */
+SimileAjax.SortedArray = function(compare, initialArray) {
+ this._a = (initialArray instanceof Array) ? initialArray : [];
+ this._compare = compare;
+};
+
+SimileAjax.SortedArray.prototype.add = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ if (index < this._a.length) {
+ this._a.splice(index, 0, elmt);
+ } else {
+ this._a.push(elmt);
+ }
+};
+
+SimileAjax.SortedArray.prototype.remove = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ while (index < this._a.length && this._compare(this._a[index], elmt) == 0) {
+ if (this._a[index] == elmt) {
+ this._a.splice(index, 1);
+ return true;
+ } else {
+ index++;
+ }
+ }
+ return false;
+};
+
+SimileAjax.SortedArray.prototype.removeAll = function() {
+ this._a = [];
+};
+
+SimileAjax.SortedArray.prototype.elementAt = function(index) {
+ return this._a[index];
+};
+
+SimileAjax.SortedArray.prototype.length = function() {
+ return this._a.length;
+};
+
+SimileAjax.SortedArray.prototype.find = function(compare) {
+ var a = 0;
+ var b = this._a.length;
+
+ while (a < b) {
+ var mid = Math.floor((a + b) / 2);
+ var c = compare(this._a[mid]);
+ if (mid == a) {
+ return c < 0 ? a+1 : a;
+ } else if (c < 0) {
+ a = mid;
+ } else {
+ b = mid;
+ }
+ }
+ return a;
+};
+
+SimileAjax.SortedArray.prototype.getFirst = function() {
+ return (this._a.length > 0) ? this._a[0] : null;
+};
+
+SimileAjax.SortedArray.prototype.getLast = function() {
+ return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
+};
+
+/*==================================================
+ * Event Index
+ *==================================================
+ */
+
+SimileAjax.EventIndex = function(unit) {
+ var eventIndex = this;
+
+ this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
+ this._events = new SimileAjax.SortedArray(
+ function(event1, event2) {
+ return eventIndex._unit.compare(event1.getStart(), event2.getStart());
+ }
+ );
+ this._idToEvent = {};
+ this._indexed = true;
+};
+
+SimileAjax.EventIndex.prototype.getUnit = function() {
+ return this._unit;
+};
+
+SimileAjax.EventIndex.prototype.getEvent = function(id) {
+ return this._idToEvent[id];
+};
+
+SimileAjax.EventIndex.prototype.add = function(evt) {
+ this._events.add(evt);
+ this._idToEvent[evt.getID()] = evt;
+ this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.removeAll = function() {
+ this._events.removeAll();
+ this._idToEvent = {};
+ this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.getCount = function() {
+ return this._events.length();
+};
+
+SimileAjax.EventIndex.prototype.getIterator = function(startDate, endDate) {
+ if (!this._indexed) {
+ this._index();
+ }
+ return new SimileAjax.EventIndex._Iterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getReverseIterator = function(startDate, endDate) {
+ if (!this._indexed) {
+ this._index();
+ }
+ return new SimileAjax.EventIndex._ReverseIterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getAllIterator = function() {
+ return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+
+SimileAjax.EventIndex.prototype.getEarliestDate = function() {
+ var evt = this._events.getFirst();
+ return (evt == null) ? null : evt.getStart();
+};
+
+SimileAjax.EventIndex.prototype.getLatestDate = function() {
+ var evt = this._events.getLast();
+ if (evt == null) {
+ return null;
+ }
+
+ if (!this._indexed) {
+ this._index();
+ }
+
+ var index = evt._earliestOverlapIndex;
+ var date = this._events.elementAt(index).getEnd();
+ for (var i = index + 1; i < this._events.length(); i++) {
+ date = this._unit.later(date, this._events.elementAt(i).getEnd());
+ }
+
+ return date;
+};
+
+SimileAjax.EventIndex.prototype._index = function() {
+ /*
+ * For each event, we want to find the earliest preceding
+ * event that overlaps with it, if any.
+ */
+
+ var l = this._events.length();
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ evt._earliestOverlapIndex = i;
+ }
+
+ var toIndex = 1;
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ var end = evt.getEnd();
+
+ toIndex = Math.max(toIndex, i + 1);
+ while (toIndex < l) {
+ var evt2 = this._events.elementAt(toIndex);
+ var start2 = evt2.getStart();
+
+ if (this._unit.compare(start2, end) < 0) {
+ evt2._earliestOverlapIndex = i;
+ toIndex++;
+ } else {
+ break;
+ }
+ }
+ }
+ this._indexed = true;
+};
+
+SimileAjax.EventIndex._Iterator = function(events, startDate, endDate, unit) {
+ this._events = events;
+ this._startDate = startDate;
+ this._endDate = endDate;
+ this._unit = unit;
+
+ this._currentIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), startDate);
+ });
+ if (this._currentIndex - 1 >= 0) {
+ this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex;
+ }
+ this._currentIndex--;
+
+ this._maxIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), endDate);
+ });
+
+ this._hasNext = false;
+ this._next = null;
+ this._findNext();
+};
+
+SimileAjax.EventIndex._Iterator.prototype = {
+ hasNext: function() { return this._hasNext; },
+ next: function() {
+ if (this._hasNext) {
+ var next = this._next;
+ this._findNext();
+
+ return next;
+ } else {
+ return null;
+ }
+ },
+ _findNext: function() {
+ var unit = this._unit;
+ while ((++this._currentIndex) < this._maxIndex) {
+ var evt = this._events.elementAt(this._currentIndex);
+ if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+ unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+ this._next = evt;
+ this._hasNext = true;
+ return;
+ }
+ }
+ this._next = null;
+ this._hasNext = false;
+ }
+};
+
+SimileAjax.EventIndex._ReverseIterator = function(events, startDate, endDate, unit) {
+ this._events = events;
+ this._startDate = startDate;
+ this._endDate = endDate;
+ this._unit = unit;
+
+ this._minIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), startDate);
+ });
+ if (this._minIndex - 1 >= 0) {
+ this._minIndex = this._events.elementAt(this._minIndex - 1)._earliestOverlapIndex;
+ }
+
+ this._maxIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), endDate);
+ });
+
+ this._currentIndex = this._maxIndex;
+ this._hasNext = false;
+ this._next = null;
+ this._findNext();
+};
+
+SimileAjax.EventIndex._ReverseIterator.prototype = {
+ hasNext: function() { return this._hasNext; },
+ next: function() {
+ if (this._hasNext) {
+ var next = this._next;
+ this._findNext();
+
+ return next;
+ } else {
+ return null;
+ }
+ },
+ _findNext: function() {
+ var unit = this._unit;
+ while ((--this._currentIndex) >= this._minIndex) {
+ var evt = this._events.elementAt(this._currentIndex);
+ if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+ unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+ this._next = evt;
+ this._hasNext = true;
+ return;
+ }
+ }
+ this._next = null;
+ this._hasNext = false;
+ }
+};
+
+SimileAjax.EventIndex._AllIterator = function(events) {
+ this._events = events;
+ this._index = 0;
+};
+
+SimileAjax.EventIndex._AllIterator.prototype = {
+ hasNext: function() {
+ return this._index < this._events.length();
+ },
+ next: function() {
+ return this._index < this._events.length() ?
+ this._events.elementAt(this._index++) : null;
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/date-time.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/date-time.js
new file mode 100644
index 00000000..97140396
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/date-time.js
@@ -0,0 +1,452 @@
+/**
+ * @fileOverview A collection of date/time utility functions
+ * @name SimileAjax.DateTime
+ */
+
+SimileAjax.DateTime = new Object();
+
+SimileAjax.DateTime.MILLISECOND = 0;
+SimileAjax.DateTime.SECOND = 1;
+SimileAjax.DateTime.MINUTE = 2;
+SimileAjax.DateTime.HOUR = 3;
+SimileAjax.DateTime.DAY = 4;
+SimileAjax.DateTime.WEEK = 5;
+SimileAjax.DateTime.MONTH = 6;
+SimileAjax.DateTime.YEAR = 7;
+SimileAjax.DateTime.DECADE = 8;
+SimileAjax.DateTime.CENTURY = 9;
+SimileAjax.DateTime.MILLENNIUM = 10;
+
+SimileAjax.DateTime.EPOCH = -1;
+SimileAjax.DateTime.ERA = -2;
+
+/**
+ * An array of unit lengths, expressed in milliseconds, of various lengths of
+ * time. The array indices are predefined and stored as properties of the
+ * SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.
+ * @type Array
+ */
+SimileAjax.DateTime.gregorianUnitLengths = [];
+ (function() {
+ var d = SimileAjax.DateTime;
+ var a = d.gregorianUnitLengths;
+
+ a[d.MILLISECOND] = 1;
+ a[d.SECOND] = 1000;
+ a[d.MINUTE] = a[d.SECOND] * 60;
+ a[d.HOUR] = a[d.MINUTE] * 60;
+ a[d.DAY] = a[d.HOUR] * 24;
+ a[d.WEEK] = a[d.DAY] * 7;
+ a[d.MONTH] = a[d.DAY] * 31;
+ a[d.YEAR] = a[d.DAY] * 365;
+ a[d.DECADE] = a[d.YEAR] * 10;
+ a[d.CENTURY] = a[d.YEAR] * 100;
+ a[d.MILLENNIUM] = a[d.YEAR] * 1000;
+ })();
+
+SimileAjax.DateTime._dateRegexp = new RegExp(
+ "^(-?)([0-9]{4})(" + [
+ "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth
+ "(-?([0-9]{3}))", // -dayOfYear
+ "(-?W([0-9]{2})(-?([1-7]))?)" // -Wweek-dayOfWeek
+ ].join("|") + ")?$"
+);
+SimileAjax.DateTime._timezoneRegexp = new RegExp(
+ "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"
+);
+SimileAjax.DateTime._timeRegexp = new RegExp(
+ "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"
+);
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and sets the
+ * the date using information parsed from the string. Note that this method
+ * does not parse any time information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Date = function(dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var d = string.match(SimileAjax.DateTime._dateRegexp);
+ if(!d) {
+ throw new Error("Invalid date string: " + string);
+ }
+
+ var sign = (d[1] == "-") ? -1 : 1; // BC or AD
+ var year = sign * d[2];
+ var month = d[5];
+ var date = d[7];
+ var dayofyear = d[9];
+ var week = d[11];
+ var dayofweek = (d[13]) ? d[13] : 1;
+
+ dateObject.setUTCFullYear(year);
+ if (dayofyear) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(Number(dayofyear));
+ } else if (week) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(1);
+ var gd = dateObject.getUTCDay();
+ var day = (gd) ? gd : 7;
+ var offset = Number(dayofweek) + (7 * Number(week));
+
+ if (day <= 4) {
+ dateObject.setUTCDate(offset + 1 - day);
+ } else {
+ dateObject.setUTCDate(offset + 8 - day);
+ }
+ } else {
+ if (month) {
+ dateObject.setUTCDate(1);
+ dateObject.setUTCMonth(month - 1);
+ }
+ if (date) {
+ dateObject.setUTCDate(date);
+ }
+ }
+
+ return dateObject;
+};
+
+/**
+ * Takes a date object and a string containing an ISO 8601 time and sets the
+ * the time using information parsed from the string. Note that this method
+ * does not parse any date information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Time = function (dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var d = string.match(SimileAjax.DateTime._timeRegexp);
+ if(!d) {
+ SimileAjax.Debug.warn("Invalid time string: " + string);
+ return false;
+ }
+ var hours = d[1];
+ var mins = Number((d[3]) ? d[3] : 0);
+ var secs = (d[5]) ? d[5] : 0;
+ var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+ dateObject.setUTCHours(hours);
+ dateObject.setUTCMinutes(mins);
+ dateObject.setUTCSeconds(secs);
+ dateObject.setUTCMilliseconds(ms);
+
+ return dateObject;
+};
+
+/**
+ * The timezone offset in minutes in the user's browser.
+ * @type Number
+ */
+SimileAjax.DateTime.timezoneOffset = new Date().getTimezoneOffset();
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and time and
+ * sets the date object using information parsed from the string.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601 = function (dateObject, string){
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var offset = null;
+ var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
+
+ SimileAjax.DateTime.setIso8601Date(dateObject, comps[0]);
+ if (comps.length == 2) {
+ // first strip timezone info from the end
+ var d = comps[1].match(SimileAjax.DateTime._timezoneRegexp);
+ if (d) {
+ if (d[0] == 'Z') {
+ offset = 0;
+ } else {
+ offset = (Number(d[3]) * 60) + Number(d[5]);
+ offset *= ((d[2] == '-') ? 1 : -1);
+ }
+ comps[1] = comps[1].substr(0, comps[1].length - d[0].length);
+ }
+
+ SimileAjax.DateTime.setIso8601Time(dateObject, comps[1]);
+ }
+ if (offset == null) {
+ offset = dateObject.getTimezoneOffset(); // local time zone if no tz info
+ }
+ dateObject.setTime(dateObject.getTime() + offset * 60000);
+
+ return dateObject;
+};
+
+/**
+ * Takes a string containing an ISO 8601 date and returns a newly instantiated
+ * date object with the parsed date and time information from the string.
+ *
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} a new date object created from the string
+ */
+SimileAjax.DateTime.parseIso8601DateTime = function (string) {
+ try {
+ return SimileAjax.DateTime.setIso8601(new Date(0), string);
+ } catch (e) {
+ return null;
+ }
+};
+
+/**
+ * Takes a string containing a Gregorian date and time and returns a newly
+ * instantiated date object with the parsed date and time information from the
+ * string. If the param is actually an instance of Date instead of a string,
+ * simply returns the given date instead.
+ *
+ * @param {Object} o an object, to either return or parse as a string
+ * @return {Date} the date object
+ */
+SimileAjax.DateTime.parseGregorianDateTime = function(o) {
+ if (o == null) {
+ return null;
+ } else if (o instanceof Date) {
+ return o;
+ }
+
+ var s = o.toString();
+ if (s.length > 0 && s.length < 8) {
+ var space = s.indexOf(" ");
+ if (space > 0) {
+ var year = parseInt(s.substr(0, space));
+ var suffix = s.substr(space + 1);
+ if (suffix.toLowerCase() == "bc") {
+ year = 1 - year;
+ }
+ } else {
+ var year = parseInt(s);
+ }
+
+ var d = new Date(0);
+ d.setUTCFullYear(year);
+
+ return d;
+ }
+
+ try {
+ return new Date(Date.parse(s));
+ } catch (e) {
+ return null;
+ }
+};
+
+/**
+ * Rounds date objects down to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ * week, 0 corresponds to Sunday, 1 to Monday, etc.
+ */
+SimileAjax.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var timeShift = timeZone *
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+ var date2 = new Date(date.getTime() + timeShift);
+ var clearInDay = function(d) {
+ d.setUTCMilliseconds(0);
+ d.setUTCSeconds(0);
+ d.setUTCMinutes(0);
+ d.setUTCHours(0);
+ };
+ var clearInYear = function(d) {
+ clearInDay(d);
+ d.setUTCDate(1);
+ d.setUTCMonth(0);
+ };
+
+ switch(intervalUnit) {
+ case SimileAjax.DateTime.MILLISECOND:
+ var x = date2.getUTCMilliseconds();
+ date2.setUTCMilliseconds(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.SECOND:
+ date2.setUTCMilliseconds(0);
+
+ var x = date2.getUTCSeconds();
+ date2.setUTCSeconds(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.MINUTE:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+
+ var x = date2.getUTCMinutes();
+ date2.setTime(date2.getTime() -
+ (x % multiple) * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+ break;
+ case SimileAjax.DateTime.HOUR:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+ date2.setUTCMinutes(0);
+
+ var x = date2.getUTCHours();
+ date2.setUTCHours(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.DAY:
+ clearInDay(date2);
+ break;
+ case SimileAjax.DateTime.WEEK:
+ clearInDay(date2);
+ var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
+ date2.setTime(date2.getTime() -
+ d * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+ break;
+ case SimileAjax.DateTime.MONTH:
+ clearInDay(date2);
+ date2.setUTCDate(1);
+
+ var x = date2.getUTCMonth();
+ date2.setUTCMonth(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.YEAR:
+ clearInYear(date2);
+
+ var x = date2.getUTCFullYear();
+ date2.setUTCFullYear(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.DECADE:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
+ break;
+ case SimileAjax.DateTime.CENTURY:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
+ break;
+ case SimileAjax.DateTime.MILLENNIUM:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
+ break;
+ }
+
+ date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Rounds date objects up to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ * week, 0 corresponds to Sunday, 1 to Monday, etc.
+ * @see SimileAjax.DateTime.roundDownToInterval
+ */
+SimileAjax.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var originalTime = date.getTime();
+ SimileAjax.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
+ if (date.getTime() < originalTime) {
+ date.setTime(date.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
+ }
+};
+
+/**
+ * Increments a date object by a specified interval, taking into
+ * consideration the timezone.
+ *
+ * @param {Date} date the date object to increment
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone the timezone offset in hours
+ */
+SimileAjax.DateTime.incrementByInterval = function(date, intervalUnit, timeZone) {
+ timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone;
+
+ var timeShift = timeZone *
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+ var date2 = new Date(date.getTime() + timeShift);
+
+ switch(intervalUnit) {
+ case SimileAjax.DateTime.MILLISECOND:
+ date2.setTime(date2.getTime() + 1)
+ break;
+ case SimileAjax.DateTime.SECOND:
+ date2.setTime(date2.getTime() + 1000);
+ break;
+ case SimileAjax.DateTime.MINUTE:
+ date2.setTime(date2.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+ break;
+ case SimileAjax.DateTime.HOUR:
+ date2.setTime(date2.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+ break;
+ case SimileAjax.DateTime.DAY:
+ date2.setUTCDate(date2.getUTCDate() + 1);
+ break;
+ case SimileAjax.DateTime.WEEK:
+ date2.setUTCDate(date2.getUTCDate() + 7);
+ break;
+ case SimileAjax.DateTime.MONTH:
+ date2.setUTCMonth(date2.getUTCMonth() + 1);
+ break;
+ case SimileAjax.DateTime.YEAR:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 1);
+ break;
+ case SimileAjax.DateTime.DECADE:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 10);
+ break;
+ case SimileAjax.DateTime.CENTURY:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 100);
+ break;
+ case SimileAjax.DateTime.MILLENNIUM:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 1000);
+ break;
+ }
+
+ date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Returns a new date object with the given time offset removed.
+ *
+ * @param {Date} date the starting date
+ * @param {Number} timeZone a timezone specified in an hour offset to remove
+ * @return {Date} a new date object with the offset removed
+ */
+SimileAjax.DateTime.removeTimeZoneOffset = function(date, timeZone) {
+ return new Date(date.getTime() +
+ timeZone * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+
+/**
+ * Returns the timezone of the user's browser.
+ *
+ * @return {Number} the timezone in the user's locale in hours
+ */
+SimileAjax.DateTime.getTimezone = function() {
+ var d = new Date().getTimezoneOffset();
+ return d / -60;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/debug.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/debug.js
new file mode 100644
index 00000000..3fca6a54
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/debug.js
@@ -0,0 +1,94 @@
+/*==================================================
+ * Debug Utility Functions
+ *==================================================
+ */
+
+SimileAjax.Debug = {
+ silent: false
+};
+
+SimileAjax.Debug.log = function(msg) {
+ var f;
+ if ("console" in window && "log" in window.console) { // FireBug installed
+ f = function(msg2) {
+ console.log(msg2);
+ }
+ } else {
+ f = function(msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert(msg2);
+ }
+ }
+ }
+ SimileAjax.Debug.log = f;
+ f(msg);
+};
+
+SimileAjax.Debug.warn = function(msg) {
+ var f;
+ if ("console" in window && "warn" in window.console) { // FireBug installed
+ f = function(msg2) {
+ console.warn(msg2);
+ }
+ } else {
+ f = function(msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert(msg2);
+ }
+ }
+ }
+ SimileAjax.Debug.warn = f;
+ f(msg);
+};
+
+SimileAjax.Debug.exception = function(e, msg) {
+ var f, params = SimileAjax.parseURLParameters();
+ if (params.errors == "throw" || SimileAjax.params.errors == "throw") {
+ f = function(e2, msg2) {
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ } else if ("console" in window && "error" in window.console) { // FireBug installed
+ f = function(e2, msg2) {
+ if (msg2 != null) {
+ console.error(msg2 + " %o", e2);
+ } else {
+ console.error(e2);
+ }
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ } else {
+ f = function(e2, msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert("Caught exception: " + msg2 + "\n\nDetails: " + ("description" in e2 ? e2.description : e2));
+ }
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ }
+ SimileAjax.Debug.exception = f;
+ f(e, msg);
+};
+
+SimileAjax.Debug.objectToString = function(o) {
+ return SimileAjax.Debug._objectToString(o, "");
+};
+
+SimileAjax.Debug._objectToString = function(o, indent) {
+ var indent2 = indent + " ";
+ if (typeof o == "object") {
+ var s = "{";
+ for (n in o) {
+ s += indent2 + n + ": " + SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+ }
+ s += indent + "}";
+ return s;
+ } else if (typeof o == "array") {
+ var s = "[";
+ for (var n = 0; n < o.length; n++) {
+ s += SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+ }
+ s += indent + "]";
+ return s;
+ } else {
+ return o;
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/dom.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/dom.js
new file mode 100644
index 00000000..373997b9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/dom.js
@@ -0,0 +1,344 @@
+/*==================================================
+ * DOM Utility Functions
+ *==================================================
+ */
+
+SimileAjax.DOM = new Object();
+
+SimileAjax.DOM.registerEventWithObject = function(elmt, eventName, obj, handlerName) {
+ SimileAjax.DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) {
+ return obj[handlerName].call(obj, elmt2, evt, target);
+ });
+};
+
+SimileAjax.DOM.registerEvent = function(elmt, eventName, handler) {
+ var handler2 = function(evt) {
+ evt = (evt) ? evt : ((event) ? event : null);
+ if (evt) {
+ var target = (evt.target) ?
+ evt.target : ((evt.srcElement) ? evt.srcElement : null);
+ if (target) {
+ target = (target.nodeType == 1 || target.nodeType == 9) ?
+ target : target.parentNode;
+ }
+
+ return handler(elmt, evt, target);
+ }
+ return true;
+ }
+
+ if (SimileAjax.Platform.browser.isIE) {
+ elmt.attachEvent("on" + eventName, handler2);
+ } else {
+ elmt.addEventListener(eventName, handler2, false);
+ }
+};
+
+SimileAjax.DOM.getPageCoordinates = function(elmt) {
+ var left = 0;
+ var top = 0;
+
+ if (elmt.nodeType != 1) {
+ elmt = elmt.parentNode;
+ }
+
+ var elmt2 = elmt;
+ while (elmt2 != null) {
+ left += elmt2.offsetLeft;
+ top += elmt2.offsetTop;
+ elmt2 = elmt2.offsetParent;
+ }
+
+ var body = document.body;
+ while (elmt != null && elmt != body) {
+ if ("scrollLeft" in elmt) {
+ left -= elmt.scrollLeft;
+ top -= elmt.scrollTop;
+ }
+ elmt = elmt.parentNode;
+ }
+
+ return { left: left, top: top };
+};
+
+SimileAjax.DOM.getSize = function(elmt) {
+ var w = this.getStyle(elmt,"width");
+ var h = this.getStyle(elmt,"height");
+ if (w.indexOf("px") > -1) w = w.replace("px","");
+ if (h.indexOf("px") > -1) h = h.replace("px","");
+ return {
+ w: w,
+ h: h
+ }
+}
+
+SimileAjax.DOM.getStyle = function(elmt, styleProp) {
+ if (elmt.currentStyle) { // IE
+ var style = elmt.currentStyle[styleProp];
+ } else if (window.getComputedStyle) { // standard DOM
+ var style = document.defaultView.getComputedStyle(elmt, null).getPropertyValue(styleProp);
+ } else {
+ var style = "";
+ }
+ return style;
+}
+
+SimileAjax.DOM.getEventRelativeCoordinates = function(evt, elmt) {
+ if (SimileAjax.Platform.browser.isIE) {
+ if (evt.type == "mousewheel") {
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+ return {
+ x: evt.clientX - coords.left,
+ y: evt.clientY - coords.top
+ };
+ } else {
+ return {
+ x: evt.offsetX,
+ y: evt.offsetY
+ };
+ }
+ } else {
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+
+ if ((evt.type == "DOMMouseScroll") &&
+ SimileAjax.Platform.browser.isFirefox &&
+ (SimileAjax.Platform.browser.majorVersion == 2)) {
+ // Due to: https://bugzilla.mozilla.org/show_bug.cgi?id=352179
+
+ return {
+ x: evt.screenX - coords.left,
+ y: evt.screenY - coords.top
+ };
+ } else {
+ return {
+ x: evt.pageX - coords.left,
+ y: evt.pageY - coords.top
+ };
+ }
+ }
+};
+
+SimileAjax.DOM.getEventPageCoordinates = function(evt) {
+ if (SimileAjax.Platform.browser.isIE) {
+ return {
+ x: evt.clientX + document.body.scrollLeft,
+ y: evt.clientY + document.body.scrollTop
+ };
+ } else {
+ return {
+ x: evt.pageX,
+ y: evt.pageY
+ };
+ }
+};
+
+SimileAjax.DOM.hittest = function(x, y, except) {
+ return SimileAjax.DOM._hittest(document.body, x, y, except);
+};
+
+SimileAjax.DOM._hittest = function(elmt, x, y, except) {
+ var childNodes = elmt.childNodes;
+ outer: for (var i = 0; i < childNodes.length; i++) {
+ var childNode = childNodes[i];
+ for (var j = 0; j < except.length; j++) {
+ if (childNode == except[j]) {
+ continue outer;
+ }
+ }
+
+ if (childNode.offsetWidth == 0 && childNode.offsetHeight == 0) {
+ /*
+ * Sometimes SPAN elements have zero width and height but
+ * they have children like DIVs that cover non-zero areas.
+ */
+ var hitNode = SimileAjax.DOM._hittest(childNode, x, y, except);
+ if (hitNode != childNode) {
+ return hitNode;
+ }
+ } else {
+ var top = 0;
+ var left = 0;
+
+ var node = childNode;
+ while (node) {
+ top += node.offsetTop;
+ left += node.offsetLeft;
+ node = node.offsetParent;
+ }
+
+ if (left <= x && top <= y && (x - left) < childNode.offsetWidth && (y - top) < childNode.offsetHeight) {
+ return SimileAjax.DOM._hittest(childNode, x, y, except);
+ } else if (childNode.nodeType == 1 && childNode.tagName == "TR") {
+ /*
+ * Table row might have cells that span several rows.
+ */
+ var childNode2 = SimileAjax.DOM._hittest(childNode, x, y, except);
+ if (childNode2 != childNode) {
+ return childNode2;
+ }
+ }
+ }
+ }
+ return elmt;
+};
+
+SimileAjax.DOM.cancelEvent = function(evt) {
+ evt.returnValue = false;
+ evt.cancelBubble = true;
+ if ("preventDefault" in evt) {
+ evt.preventDefault();
+ }
+};
+
+SimileAjax.DOM.appendClassName = function(elmt, className) {
+ var classes = elmt.className.split(" ");
+ for (var i = 0; i < classes.length; i++) {
+ if (classes[i] == className) {
+ return;
+ }
+ }
+ classes.push(className);
+ elmt.className = classes.join(" ");
+};
+
+SimileAjax.DOM.createInputElement = function(type) {
+ var div = document.createElement("div");
+ div.innerHTML = "<input type='" + type + "' />";
+
+ return div.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromTemplate = function(template) {
+ var result = {};
+ result.elmt = SimileAjax.DOM._createDOMFromTemplate(template, result, null);
+
+ return result;
+};
+
+SimileAjax.DOM._createDOMFromTemplate = function(templateNode, result, parentElmt) {
+ if (templateNode == null) {
+ /*
+ var node = doc.createTextNode("--null--");
+ if (parentElmt != null) {
+ parentElmt.appendChild(node);
+ }
+ return node;
+ */
+ return null;
+ } else if (typeof templateNode != "object") {
+ var node = document.createTextNode(templateNode);
+ if (parentElmt != null) {
+ parentElmt.appendChild(node);
+ }
+ return node;
+ } else {
+ var elmt = null;
+ if ("tag" in templateNode) {
+ var tag = templateNode.tag;
+ if (parentElmt != null) {
+ if (tag == "tr") {
+ elmt = parentElmt.insertRow(parentElmt.rows.length);
+ } else if (tag == "td") {
+ elmt = parentElmt.insertCell(parentElmt.cells.length);
+ }
+ }
+ if (elmt == null) {
+ elmt = tag == "input" ?
+ SimileAjax.DOM.createInputElement(templateNode.type) :
+ document.createElement(tag);
+
+ if (parentElmt != null) {
+ parentElmt.appendChild(elmt);
+ }
+ }
+ } else {
+ elmt = templateNode.elmt;
+ if (parentElmt != null) {
+ parentElmt.appendChild(elmt);
+ }
+ }
+
+ for (var attribute in templateNode) {
+ var value = templateNode[attribute];
+
+ if (attribute == "field") {
+ result[value] = elmt;
+
+ } else if (attribute == "className") {
+ elmt.className = value;
+ } else if (attribute == "id") {
+ elmt.id = value;
+ } else if (attribute == "title") {
+ elmt.title = value;
+ } else if (attribute == "type" && elmt.tagName == "input") {
+ // do nothing
+ } else if (attribute == "style") {
+ for (n in value) {
+ var v = value[n];
+ if (n == "float") {
+ n = SimileAjax.Platform.browser.isIE ? "styleFloat" : "cssFloat";
+ }
+ elmt.style[n] = v;
+ }
+ } else if (attribute == "children") {
+ for (var i = 0; i < value.length; i++) {
+ SimileAjax.DOM._createDOMFromTemplate(value[i], result, elmt);
+ }
+ } else if (attribute != "tag" && attribute != "elmt") {
+ elmt.setAttribute(attribute, value);
+ }
+ }
+ return elmt;
+ }
+}
+
+SimileAjax.DOM._cachedParent = null;
+SimileAjax.DOM.createElementFromString = function(s) {
+ if (SimileAjax.DOM._cachedParent == null) {
+ SimileAjax.DOM._cachedParent = document.createElement("div");
+ }
+ SimileAjax.DOM._cachedParent.innerHTML = s;
+ return SimileAjax.DOM._cachedParent.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromString = function(root, s, fieldElmts) {
+ var elmt = typeof root == "string" ? document.createElement(root) : root;
+ elmt.innerHTML = s;
+
+ var dom = { elmt: elmt };
+ SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts != null ? fieldElmts : {} );
+
+ return dom;
+};
+
+SimileAjax.DOM._processDOMConstructedFromString = function(dom, elmt, fieldElmts) {
+ var id = elmt.id;
+ if (id != null && id.length > 0) {
+ elmt.removeAttribute("id");
+ if (id in fieldElmts) {
+ var parentElmt = elmt.parentNode;
+ parentElmt.insertBefore(fieldElmts[id], elmt);
+ parentElmt.removeChild(elmt);
+
+ dom[id] = fieldElmts[id];
+ return;
+ } else {
+ dom[id] = elmt;
+ }
+ }
+
+ if (elmt.hasChildNodes()) {
+ SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts);
+ }
+};
+
+SimileAjax.DOM._processDOMChildrenConstructedFromString = function(dom, elmt, fieldElmts) {
+ var node = elmt.firstChild;
+ while (node != null) {
+ var node2 = node.nextSibling;
+ if (node.nodeType == 1) {
+ SimileAjax.DOM._processDOMConstructedFromString(dom, node, fieldElmts);
+ }
+ node = node2;
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/graphics.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/graphics.js
new file mode 100644
index 00000000..770e17c1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/graphics.js
@@ -0,0 +1,653 @@
+/**
+ * @fileOverview Graphics utility functions and constants
+ * @name SimileAjax.Graphics
+ */
+
+SimileAjax.Graphics = new Object();
+
+/**
+ * A boolean value indicating whether PNG translucency is supported on the
+ * user's browser or not.
+ *
+ * @type Boolean
+ */
+SimileAjax.Graphics.pngIsTranslucent = (!SimileAjax.Platform.browser.isIE) || (SimileAjax.Platform.browser.majorVersion > 6);
+if (!SimileAjax.Graphics.pngIsTranslucent) {
+ SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
+}
+
+/*==================================================
+ * Opacity, translucency
+ *==================================================
+ */
+SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
+ var elmt = document.createElement("img");
+ elmt.setAttribute("src", url);
+ if (verticalAlign != null) {
+ elmt.style.verticalAlign = verticalAlign;
+ }
+ return elmt;
+};
+SimileAjax.Graphics._createTranslucentImage2 = function(url, verticalAlign) {
+ var elmt = document.createElement("img");
+ elmt.style.width = "1px"; // just so that IE will calculate the size property
+ elmt.style.height = "1px";
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
+ elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
+ return elmt;
+};
+
+/**
+ * Creates a DOM element for an <code>img</code> tag using the URL given. This
+ * is a convenience method that automatically includes the necessary CSS to
+ * allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {Element} a DOM element containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImage = SimileAjax.Graphics.pngIsTranslucent ?
+ SimileAjax.Graphics._createTranslucentImage1 :
+ SimileAjax.Graphics._createTranslucentImage2;
+
+SimileAjax.Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) {
+ return "<img src=\"" + url + "\"" +
+ (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") +
+ " />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) {
+ var style =
+ "width: 1px; height: 1px; " +
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" +
+ (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : "");
+
+ return "<img src='" + url + "' style=\"" + style + "\" />";
+};
+
+/**
+ * Creates an HTML string for an <code>img</code> tag using the URL given.
+ * This is a convenience method that automatically includes the necessary CSS
+ * to allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {String} a string containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImageHTML = SimileAjax.Graphics.pngIsTranslucent ?
+ SimileAjax.Graphics._createTranslucentImageHTML1 :
+ SimileAjax.Graphics._createTranslucentImageHTML2;
+
+/**
+ * Sets the opacity on the given DOM element.
+ *
+ * @param {Element} elmt the DOM element to set the opacity on
+ * @param {Number} opacity an integer from 0 to 100 specifying the opacity
+ */
+SimileAjax.Graphics.setOpacity = function(elmt, opacity) {
+ if (SimileAjax.Platform.browser.isIE) {
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
+ } else {
+ var o = (opacity / 100).toString();
+ elmt.style.opacity = o;
+ elmt.style.MozOpacity = o;
+ }
+};
+
+/*==================================================
+ * Bubble
+ *==================================================
+ */
+
+SimileAjax.Graphics.bubbleConfig = {
+ containerCSSClass: "simileAjax-bubble-container",
+ innerContainerCSSClass: "simileAjax-bubble-innerContainer",
+ contentContainerCSSClass: "simileAjax-bubble-contentContainer",
+
+ borderGraphicSize: 50,
+ borderGraphicCSSClassPrefix: "simileAjax-bubble-border-",
+
+ arrowGraphicTargetOffset: 33, // from tip of arrow to the side of the graphic that touches the content of the bubble
+ arrowGraphicLength: 100, // dimension of arrow graphic along the direction that the arrow points
+ arrowGraphicWidth: 49, // dimension of arrow graphic perpendicular to the direction that the arrow points
+ arrowGraphicCSSClassPrefix: "simileAjax-bubble-arrow-",
+
+ closeGraphicCSSClass: "simileAjax-bubble-close",
+
+ extraPadding: 20
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given content in a div,
+ * page coordinates and a suggested width. The bubble will point to the
+ * location on the page as described by pageX and pageY. All measurements
+ * should be given in pixels.
+ *
+ * @param {Element} the content div
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth a suggested width of the content
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ * that describes the orientation of the arrow on the bubble
+ * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall.
+ * Default of 0 or null means no maximum
+ */
+SimileAjax.Graphics.createBubbleForContentAndPoint = function(
+ div, pageX, pageY, contentWidth, orientation, maxHeight) {
+ if (typeof contentWidth != "number") {
+ contentWidth = 300;
+ }
+ if (typeof maxHeight != "number") {
+ maxHeight = 0;
+ }
+
+ div.style.position = "absolute";
+ div.style.left = "-5000px";
+ div.style.top = "0px";
+ div.style.width = contentWidth + "px";
+ document.body.appendChild(div);
+
+ window.setTimeout(function() {
+ var width = div.scrollWidth + 10;
+ var height = div.scrollHeight + 10;
+ var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
+ if (maxHeight > 0 && height > maxHeight) {
+ height = maxHeight;
+ scrollDivW = width - 25;
+ }
+
+ var bubble = SimileAjax.Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation);
+
+ document.body.removeChild(div);
+ div.style.position = "static";
+ div.style.left = "";
+ div.style.top = "";
+
+ // create a scroll div if needed
+ if (scrollDivW > 0) {
+ var scrollDiv = document.createElement("div");
+ div.style.width = "";
+ scrollDiv.style.width = scrollDivW + "px";
+ scrollDiv.appendChild(div);
+ bubble.content.appendChild(scrollDiv);
+ } else {
+ div.style.width = width + "px";
+ bubble.content.appendChild(div);
+ }
+ }, 200);
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given page coordinates and
+ * content dimensions. The bubble will point to the location on the page
+ * as described by pageX and pageY. All measurements should be given in
+ * pixels.
+ *
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth the width of the content box in the bubble
+ * @param {Number} contentHeight the height of the content box in the bubble
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ * that describes the orientation of the arrow on the bubble
+ * @return {Element} a DOM element for the newly created bubble
+ */
+SimileAjax.Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) {
+ contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs
+ contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings
+
+ var bubbleConfig = SimileAjax.Graphics.bubbleConfig;
+ var pngTransparencyClassSuffix =
+ SimileAjax.Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent";
+
+ var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
+ var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
+
+ var generatePngSensitiveClass = function(className) {
+ return className + " " + className + "-" + pngTransparencyClassSuffix;
+ };
+
+ /*
+ * Render container divs
+ */
+ var div = document.createElement("div");
+ div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass);
+ div.style.width = contentWidth + "px";
+ div.style.height = contentHeight + "px";
+
+ var divInnerContainer = document.createElement("div");
+ divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
+ div.appendChild(divInnerContainer);
+
+ /*
+ * Create layer for bubble
+ */
+ var close = function() {
+ if (!bubble._closed) {
+ document.body.removeChild(bubble._div);
+ bubble._doc = null;
+ bubble._div = null;
+ bubble._content = null;
+ bubble._closed = true;
+ }
+ }
+ var bubble = { _closed: false };
+ var layer = SimileAjax.WindowManager.pushLayer(close, true, div);
+ bubble._div = div;
+ bubble.close = function() { SimileAjax.WindowManager.popLayer(layer); }
+
+ /*
+ * Render border graphics
+ */
+ var createBorder = function(classNameSuffix) {
+ var divBorderGraphic = document.createElement("div");
+ divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix);
+ divInnerContainer.appendChild(divBorderGraphic);
+ };
+ createBorder("top-left");
+ createBorder("top-right");
+ createBorder("bottom-left");
+ createBorder("bottom-right");
+ createBorder("left");
+ createBorder("right");
+ createBorder("top");
+ createBorder("bottom");
+
+ /*
+ * Render content
+ */
+ var divContentContainer = document.createElement("div");
+ divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
+ divInnerContainer.appendChild(divContentContainer);
+ bubble.content = divContentContainer;
+
+ /*
+ * Render close button
+ */
+ var divClose = document.createElement("div");
+ divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
+ divInnerContainer.appendChild(divClose);
+ SimileAjax.WindowManager.registerEventWithObject(divClose, "click", bubble, "close");
+
+ (function() {
+ var dims = SimileAjax.Graphics.getWindowDimensions();
+ var docWidth = dims.w;
+ var docHeight = dims.h;
+
+ var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
+
+ var createArrow = function(classNameSuffix) {
+ var divArrowGraphic = document.createElement("div");
+ divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix);
+ divInnerContainer.appendChild(divArrowGraphic);
+ return divArrowGraphic;
+ };
+
+ if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
+ pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
+
+ /*
+ * Bubble can be positioned above or below the target point.
+ */
+
+ var left = pageX - Math.round(contentWidth / 2);
+ left = pageX < (docWidth / 2) ?
+ Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+ Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
+
+ if ((orientation && orientation == "top") ||
+ (!orientation &&
+ (pageY
+ - bubbleConfig.arrowGraphicTargetOffset
+ - contentHeight
+ - bubbleConfig.borderGraphicSize
+ - bubbleConfig.extraPadding > 0))) {
+
+ /*
+ * Position bubble above the target point.
+ */
+
+ var divArrow = createArrow("down");
+ divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+ div.style.left = left + "px";
+ div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px";
+
+ return;
+ } else if ((orientation && orientation == "bottom") ||
+ (!orientation &&
+ (pageY
+ + bubbleConfig.arrowGraphicTargetOffset
+ + contentHeight
+ + bubbleConfig.borderGraphicSize
+ + bubbleConfig.extraPadding < docHeight))) {
+
+ /*
+ * Position bubble below the target point.
+ */
+
+ var divArrow = createArrow("up");
+ divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+ div.style.left = left + "px";
+ div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px";
+
+ return;
+ }
+ }
+
+ var top = pageY - Math.round(contentHeight / 2);
+ top = pageY < (docHeight / 2) ?
+ Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+ Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
+
+ if ((orientation && orientation == "left") ||
+ (!orientation &&
+ (pageX
+ - bubbleConfig.arrowGraphicTargetOffset
+ - contentWidth
+ - bubbleConfig.borderGraphicSize
+ - bubbleConfig.extraPadding > 0))) {
+
+ /*
+ * Position bubble left of the target point.
+ */
+
+ var divArrow = createArrow("right");
+ divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+ div.style.top = top + "px";
+ div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px";
+ } else {
+
+ /*
+ * Position bubble right of the target point, as the last resort.
+ */
+
+ var divArrow = createArrow("left");
+ divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+ div.style.top = top + "px";
+ div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px";
+ }
+ })();
+
+ document.body.appendChild(div);
+
+ return bubble;
+};
+
+SimileAjax.Graphics.getWindowDimensions = function() {
+ if (typeof window.innerHeight == 'number') {
+ return { w:window.innerWidth, h:window.innerHeight }; // Non-IE
+ } else if (document.documentElement && document.documentElement.clientHeight) {
+ return { // IE6+, in "standards compliant mode"
+ w:document.documentElement.clientWidth,
+ h:document.documentElement.clientHeight
+ };
+ } else if (document.body && document.body.clientHeight) {
+ return { // IE 4 compatible
+ w:document.body.clientWidth,
+ h:document.body.clientHeight
+ };
+ }
+};
+
+
+/**
+ * Creates a floating, rounded message bubble in the center of the window for
+ * displaying modal information, e.g. "Loading..."
+ *
+ * @param {Document} doc the root document for the page to render on
+ * @param {Object} an object with two properties, contentDiv and containerDiv,
+ * consisting of the newly created DOM elements
+ */
+SimileAjax.Graphics.createMessageBubble = function(doc) {
+ var containerDiv = doc.createElement("div");
+ if (SimileAjax.Graphics.pngIsTranslucent) {
+ var topDiv = doc.createElement("div");
+ topDiv.style.height = "33px";
+ topDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-left.png) top left no-repeat";
+ topDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(topDiv);
+
+ var topRightDiv = doc.createElement("div");
+ topRightDiv.style.height = "33px";
+ topRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-right.png) top right no-repeat";
+ topDiv.appendChild(topRightDiv);
+
+ var middleDiv = doc.createElement("div");
+ middleDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-left.png) top left repeat-y";
+ middleDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(middleDiv);
+
+ var middleRightDiv = doc.createElement("div");
+ middleRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-right.png) top right repeat-y";
+ middleRightDiv.style.paddingRight = "44px";
+ middleDiv.appendChild(middleRightDiv);
+
+ var contentDiv = doc.createElement("div");
+ middleRightDiv.appendChild(contentDiv);
+
+ var bottomDiv = doc.createElement("div");
+ bottomDiv.style.height = "55px";
+ bottomDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
+ bottomDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(bottomDiv);
+
+ var bottomRightDiv = doc.createElement("div");
+ bottomRightDiv.style.height = "55px";
+ bottomRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
+ bottomDiv.appendChild(bottomRightDiv);
+ } else {
+ containerDiv.style.border = "2px solid #7777AA";
+ containerDiv.style.padding = "20px";
+ containerDiv.style.background = "white";
+ SimileAjax.Graphics.setOpacity(containerDiv, 90);
+
+ var contentDiv = doc.createElement("div");
+ containerDiv.appendChild(contentDiv);
+ }
+
+ return {
+ containerDiv: containerDiv,
+ contentDiv: contentDiv
+ };
+};
+
+/*==================================================
+ * Animation
+ *==================================================
+ */
+
+/**
+ * Creates an animation for a function, and an interval of values. The word
+ * "animation" here is used in the sense of repeatedly calling a function with
+ * a current value from within an interval, and a delta value.
+ *
+ * @param {Function} f a function to be called every 50 milliseconds throughout
+ * the animation duration, of the form f(current, delta), where current is
+ * the current value within the range and delta is the current change.
+ * @param {Number} from a starting value
+ * @param {Number} to an ending value
+ * @param {Number} duration the duration of the animation in milliseconds
+ * @param {Function} [cont] an optional function that is called at the end of
+ * the animation, i.e. a continuation.
+ * @return {SimileAjax.Graphics._Animation} a new animation object
+ */
+SimileAjax.Graphics.createAnimation = function(f, from, to, duration, cont) {
+ return new SimileAjax.Graphics._Animation(f, from, to, duration, cont);
+};
+
+SimileAjax.Graphics._Animation = function(f, from, to, duration, cont) {
+ this.f = f;
+ this.cont = (typeof cont == "function") ? cont : function() {};
+
+ this.from = from;
+ this.to = to;
+ this.current = from;
+
+ this.duration = duration;
+ this.start = new Date().getTime();
+ this.timePassed = 0;
+};
+
+/**
+ * Runs this animation.
+ */
+SimileAjax.Graphics._Animation.prototype.run = function() {
+ var a = this;
+ window.setTimeout(function() { a.step(); }, 50);
+};
+
+/**
+ * Increments this animation by one step, and then continues the animation with
+ * <code>run()</code>.
+ */
+SimileAjax.Graphics._Animation.prototype.step = function() {
+ this.timePassed += 50;
+
+ var timePassedFraction = this.timePassed / this.duration;
+ var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
+ var current = parameterFraction * (this.to - this.from) + this.from;
+
+ try {
+ this.f(current, current - this.current);
+ } catch (e) {
+ }
+ this.current = current;
+
+ if (this.timePassed < this.duration) {
+ this.run();
+ } else {
+ this.f(this.to, 0);
+ this["cont"]();
+ }
+};
+
+/*==================================================
+ * CopyPasteButton
+ *
+ * Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
+ *==================================================
+ */
+
+/**
+ * Creates a button and textarea for displaying structured data and copying it
+ * to the clipboard. The data is dynamically generated by the given
+ * createDataFunction parameter.
+ *
+ * @param {String} image an image URL to use as the background for the
+ * generated box
+ * @param {Number} width the width in pixels of the generated box
+ * @param {Number} height the height in pixels of the generated box
+ * @param {Function} createDataFunction a function that is called with no
+ * arguments to generate the structured data
+ * @return a new DOM element
+ */
+SimileAjax.Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) {
+ var div = document.createElement("div");
+ div.style.position = "relative";
+ div.style.display = "inline";
+ div.style.width = width + "px";
+ div.style.height = height + "px";
+ div.style.overflow = "hidden";
+ div.style.margin = "2px";
+
+ if (SimileAjax.Graphics.pngIsTranslucent) {
+ div.style.background = "url(" + image + ") no-repeat";
+ } else {
+ div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')";
+ }
+
+ var style;
+ if (SimileAjax.Platform.browser.isIE) {
+ style = "filter:alpha(opacity=0)";
+ } else {
+ style = "opacity: 0";
+ }
+ div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />";
+
+ var textarea = div.firstChild;
+ textarea.style.width = width + "px";
+ textarea.style.height = height + "px";
+ textarea.onmousedown = function(evt) {
+ evt = (evt) ? evt : ((event) ? event : null);
+ if (evt.button == 2) {
+ textarea.value = createDataFunction();
+ textarea.select();
+ }
+ };
+
+ return div;
+};
+
+/*==================================================
+ * getWidthHeight
+ *==================================================
+ */
+SimileAjax.Graphics.getWidthHeight = function(el) {
+ // RETURNS hash {width: w, height: h} in pixels
+
+ var w, h;
+ // offsetWidth rounds on FF, so doesn't work for us.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617
+ if (el.getBoundingClientRect == null) {
+ // use offsetWidth
+ w = el.offsetWidth;
+ h = el.offsetHeight;
+ } else {
+ // use getBoundingClientRect
+ var rect = el.getBoundingClientRect();
+ w = Math.ceil(rect.right - rect.left);
+ h = Math.ceil(rect.bottom - rect.top);
+ }
+ return {
+ width: w,
+ height: h
+ };
+};
+
+
+/*==================================================
+ * FontRenderingContext
+ *==================================================
+ */
+SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
+ return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
+};
+
+SimileAjax.Graphics._FontRenderingContext = function(elmt, width) {
+ this._elmt = elmt;
+ this._elmt.style.visibility = "hidden";
+ if (typeof width == "string") {
+ this._elmt.style.width = width;
+ } else if (typeof width == "number") {
+ this._elmt.style.width = width + "px";
+ }
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose = function() {
+ this._elmt = null;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.update = function() {
+ this._elmt.innerHTML = "A";
+ this._lineHeight = this._elmt.offsetHeight;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize = function(text, className) {
+ // className arg is optional
+ var el = this._elmt;
+ el.innerHTML = text;
+ el.className = className === undefined ? '' : className;
+ var wh = SimileAjax.Graphics.getWidthHeight(el);
+ el.className = ''; // reset for the next guy
+
+ return wh;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight = function() {
+ return this._lineHeight;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/history.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/history.js
new file mode 100644
index 00000000..75bfed7d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/history.js
@@ -0,0 +1,220 @@
+/*======================================================================
+ * History
+ *
+ * This is a singleton that keeps track of undoable user actions and
+ * performs undos and redos in response to the browser's Back and
+ * Forward buttons.
+ *
+ * Call addAction(action) to register an undoable user action. action
+ * must have 4 fields:
+ *
+ * perform: an argument-less function that carries out the action
+ * undo: an argument-less function that undos the action
+ * label: a short, user-friendly string describing the action
+ * uiLayer: the UI layer on which the action takes place
+ *
+ * By default, the history keeps track of upto 10 actions. You can
+ * configure this behavior by setting
+ * SimileAjax.History.maxHistoryLength
+ * to a different number.
+ *
+ * An iframe is inserted into the document's body element to track
+ * onload events.
+ *======================================================================
+ */
+
+SimileAjax.History = {
+ maxHistoryLength: 10,
+ historyFile: "__history__.html",
+ enabled: true,
+
+ _initialized: false,
+ _listeners: new SimileAjax.ListenerQueue(),
+
+ _actions: [],
+ _baseIndex: 0,
+ _currentIndex: 0,
+
+ _plainDocumentTitle: document.title
+};
+
+SimileAjax.History.formatHistoryEntryTitle = function(actionLabel) {
+ return SimileAjax.History._plainDocumentTitle + " {" + actionLabel + "}";
+};
+
+SimileAjax.History.initialize = function() {
+ if (SimileAjax.History._initialized) {
+ return;
+ }
+
+ if (SimileAjax.History.enabled) {
+ var iframe = document.createElement("iframe");
+ iframe.id = "simile-ajax-history";
+ iframe.style.position = "absolute";
+ iframe.style.width = "10px";
+ iframe.style.height = "10px";
+ iframe.style.top = "0px";
+ iframe.style.left = "0px";
+ iframe.style.visibility = "hidden";
+ iframe.src = SimileAjax.History.historyFile + "?0";
+
+ document.body.appendChild(iframe);
+ SimileAjax.DOM.registerEvent(iframe, "load", SimileAjax.History._handleIFrameOnLoad);
+
+ SimileAjax.History._iframe = iframe;
+ }
+ SimileAjax.History._initialized = true;
+};
+
+SimileAjax.History.addListener = function(listener) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.add(listener);
+};
+
+SimileAjax.History.removeListener = function(listener) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.remove(listener);
+};
+
+SimileAjax.History.addAction = function(action) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.fire("onBeforePerform", [ action ]);
+ window.setTimeout(function() {
+ try {
+ action.perform();
+ SimileAjax.History._listeners.fire("onAfterPerform", [ action ]);
+
+ if (SimileAjax.History.enabled) {
+ SimileAjax.History._actions = SimileAjax.History._actions.slice(
+ 0, SimileAjax.History._currentIndex - SimileAjax.History._baseIndex);
+
+ SimileAjax.History._actions.push(action);
+ SimileAjax.History._currentIndex++;
+
+ var diff = SimileAjax.History._actions.length - SimileAjax.History.maxHistoryLength;
+ if (diff > 0) {
+ SimileAjax.History._actions = SimileAjax.History._actions.slice(diff);
+ SimileAjax.History._baseIndex += diff;
+ }
+
+ try {
+ SimileAjax.History._iframe.contentWindow.location.search =
+ "?" + SimileAjax.History._currentIndex;
+ } catch (e) {
+ /*
+ * We can't modify location.search most probably because it's a file:// url.
+ * We'll just going to modify the document's title.
+ */
+ var title = SimileAjax.History.formatHistoryEntryTitle(action.label);
+ document.title = title;
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error adding action {" + action.label + "} to history");
+ }
+ }, 0);
+};
+
+SimileAjax.History.addLengthyAction = function(perform, undo, label) {
+ SimileAjax.History.addAction({
+ perform: perform,
+ undo: undo,
+ label: label,
+ uiLayer: SimileAjax.WindowManager.getBaseLayer(),
+ lengthy: true
+ });
+};
+
+SimileAjax.History._handleIFrameOnLoad = function() {
+ /*
+ * This function is invoked when the user herself
+ * navigates backward or forward. We need to adjust
+ * the application's state accordingly.
+ */
+
+ try {
+ var q = SimileAjax.History._iframe.contentWindow.location.search;
+ var c = (q.length == 0) ? 0 : Math.max(0, parseInt(q.substr(1)));
+
+ var finishUp = function() {
+ var diff = c - SimileAjax.History._currentIndex;
+ SimileAjax.History._currentIndex += diff;
+ SimileAjax.History._baseIndex += diff;
+
+ SimileAjax.History._iframe.contentWindow.location.search = "?" + c;
+ };
+
+ if (c < SimileAjax.History._currentIndex) { // need to undo
+ SimileAjax.History._listeners.fire("onBeforeUndoSeveral", []);
+ window.setTimeout(function() {
+ while (SimileAjax.History._currentIndex > c &&
+ SimileAjax.History._currentIndex > SimileAjax.History._baseIndex) {
+
+ SimileAjax.History._currentIndex--;
+
+ var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+ try {
+ action.undo();
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "History: Failed to undo action {" + action.label + "}");
+ }
+ }
+
+ SimileAjax.History._listeners.fire("onAfterUndoSeveral", []);
+ finishUp();
+ }, 0);
+ } else if (c > SimileAjax.History._currentIndex) { // need to redo
+ SimileAjax.History._listeners.fire("onBeforeRedoSeveral", []);
+ window.setTimeout(function() {
+ while (SimileAjax.History._currentIndex < c &&
+ SimileAjax.History._currentIndex - SimileAjax.History._baseIndex < SimileAjax.History._actions.length) {
+
+ var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+ try {
+ action.perform();
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "History: Failed to redo action {" + action.label + "}");
+ }
+
+ SimileAjax.History._currentIndex++;
+ }
+
+ SimileAjax.History._listeners.fire("onAfterRedoSeveral", []);
+ finishUp();
+ }, 0);
+ } else {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+ var title = (index >= 0 && index < SimileAjax.History._actions.length) ?
+ SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[index].label) :
+ SimileAjax.History._plainDocumentTitle;
+
+ SimileAjax.History._iframe.contentWindow.document.title = title;
+ document.title = title;
+ }
+ } catch (e) {
+ // silent
+ }
+};
+
+SimileAjax.History.getNextUndoAction = function() {
+ try {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+ return SimileAjax.History._actions[index];
+ } catch (e) {
+ return null;
+ }
+};
+
+SimileAjax.History.getNextRedoAction = function() {
+ try {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex;
+ return SimileAjax.History._actions[index];
+ } catch (e) {
+ return null;
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/html.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/html.js
new file mode 100644
index 00000000..cedeb4ab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/html.js
@@ -0,0 +1,274 @@
+/*==================================================
+ * HTML Utility Functions
+ *==================================================
+ */
+
+SimileAjax.HTML = new Object();
+
+SimileAjax.HTML._e2uHash = {};
+(function() {
+ var e2uHash = SimileAjax.HTML._e2uHash;
+ e2uHash['nbsp']= '\u00A0[space]';
+ e2uHash['iexcl']= '\u00A1';
+ e2uHash['cent']= '\u00A2';
+ e2uHash['pound']= '\u00A3';
+ e2uHash['curren']= '\u00A4';
+ e2uHash['yen']= '\u00A5';
+ e2uHash['brvbar']= '\u00A6';
+ e2uHash['sect']= '\u00A7';
+ e2uHash['uml']= '\u00A8';
+ e2uHash['copy']= '\u00A9';
+ e2uHash['ordf']= '\u00AA';
+ e2uHash['laquo']= '\u00AB';
+ e2uHash['not']= '\u00AC';
+ e2uHash['shy']= '\u00AD';
+ e2uHash['reg']= '\u00AE';
+ e2uHash['macr']= '\u00AF';
+ e2uHash['deg']= '\u00B0';
+ e2uHash['plusmn']= '\u00B1';
+ e2uHash['sup2']= '\u00B2';
+ e2uHash['sup3']= '\u00B3';
+ e2uHash['acute']= '\u00B4';
+ e2uHash['micro']= '\u00B5';
+ e2uHash['para']= '\u00B6';
+ e2uHash['middot']= '\u00B7';
+ e2uHash['cedil']= '\u00B8';
+ e2uHash['sup1']= '\u00B9';
+ e2uHash['ordm']= '\u00BA';
+ e2uHash['raquo']= '\u00BB';
+ e2uHash['frac14']= '\u00BC';
+ e2uHash['frac12']= '\u00BD';
+ e2uHash['frac34']= '\u00BE';
+ e2uHash['iquest']= '\u00BF';
+ e2uHash['Agrave']= '\u00C0';
+ e2uHash['Aacute']= '\u00C1';
+ e2uHash['Acirc']= '\u00C2';
+ e2uHash['Atilde']= '\u00C3';
+ e2uHash['Auml']= '\u00C4';
+ e2uHash['Aring']= '\u00C5';
+ e2uHash['AElig']= '\u00C6';
+ e2uHash['Ccedil']= '\u00C7';
+ e2uHash['Egrave']= '\u00C8';
+ e2uHash['Eacute']= '\u00C9';
+ e2uHash['Ecirc']= '\u00CA';
+ e2uHash['Euml']= '\u00CB';
+ e2uHash['Igrave']= '\u00CC';
+ e2uHash['Iacute']= '\u00CD';
+ e2uHash['Icirc']= '\u00CE';
+ e2uHash['Iuml']= '\u00CF';
+ e2uHash['ETH']= '\u00D0';
+ e2uHash['Ntilde']= '\u00D1';
+ e2uHash['Ograve']= '\u00D2';
+ e2uHash['Oacute']= '\u00D3';
+ e2uHash['Ocirc']= '\u00D4';
+ e2uHash['Otilde']= '\u00D5';
+ e2uHash['Ouml']= '\u00D6';
+ e2uHash['times']= '\u00D7';
+ e2uHash['Oslash']= '\u00D8';
+ e2uHash['Ugrave']= '\u00D9';
+ e2uHash['Uacute']= '\u00DA';
+ e2uHash['Ucirc']= '\u00DB';
+ e2uHash['Uuml']= '\u00DC';
+ e2uHash['Yacute']= '\u00DD';
+ e2uHash['THORN']= '\u00DE';
+ e2uHash['szlig']= '\u00DF';
+ e2uHash['agrave']= '\u00E0';
+ e2uHash['aacute']= '\u00E1';
+ e2uHash['acirc']= '\u00E2';
+ e2uHash['atilde']= '\u00E3';
+ e2uHash['auml']= '\u00E4';
+ e2uHash['aring']= '\u00E5';
+ e2uHash['aelig']= '\u00E6';
+ e2uHash['ccedil']= '\u00E7';
+ e2uHash['egrave']= '\u00E8';
+ e2uHash['eacute']= '\u00E9';
+ e2uHash['ecirc']= '\u00EA';
+ e2uHash['euml']= '\u00EB';
+ e2uHash['igrave']= '\u00EC';
+ e2uHash['iacute']= '\u00ED';
+ e2uHash['icirc']= '\u00EE';
+ e2uHash['iuml']= '\u00EF';
+ e2uHash['eth']= '\u00F0';
+ e2uHash['ntilde']= '\u00F1';
+ e2uHash['ograve']= '\u00F2';
+ e2uHash['oacute']= '\u00F3';
+ e2uHash['ocirc']= '\u00F4';
+ e2uHash['otilde']= '\u00F5';
+ e2uHash['ouml']= '\u00F6';
+ e2uHash['divide']= '\u00F7';
+ e2uHash['oslash']= '\u00F8';
+ e2uHash['ugrave']= '\u00F9';
+ e2uHash['uacute']= '\u00FA';
+ e2uHash['ucirc']= '\u00FB';
+ e2uHash['uuml']= '\u00FC';
+ e2uHash['yacute']= '\u00FD';
+ e2uHash['thorn']= '\u00FE';
+ e2uHash['yuml']= '\u00FF';
+ e2uHash['quot']= '\u0022';
+ e2uHash['amp']= '\u0026';
+ e2uHash['lt']= '\u003C';
+ e2uHash['gt']= '\u003E';
+ e2uHash['OElig']= '';
+ e2uHash['oelig']= '\u0153';
+ e2uHash['Scaron']= '\u0160';
+ e2uHash['scaron']= '\u0161';
+ e2uHash['Yuml']= '\u0178';
+ e2uHash['circ']= '\u02C6';
+ e2uHash['tilde']= '\u02DC';
+ e2uHash['ensp']= '\u2002';
+ e2uHash['emsp']= '\u2003';
+ e2uHash['thinsp']= '\u2009';
+ e2uHash['zwnj']= '\u200C';
+ e2uHash['zwj']= '\u200D';
+ e2uHash['lrm']= '\u200E';
+ e2uHash['rlm']= '\u200F';
+ e2uHash['ndash']= '\u2013';
+ e2uHash['mdash']= '\u2014';
+ e2uHash['lsquo']= '\u2018';
+ e2uHash['rsquo']= '\u2019';
+ e2uHash['sbquo']= '\u201A';
+ e2uHash['ldquo']= '\u201C';
+ e2uHash['rdquo']= '\u201D';
+ e2uHash['bdquo']= '\u201E';
+ e2uHash['dagger']= '\u2020';
+ e2uHash['Dagger']= '\u2021';
+ e2uHash['permil']= '\u2030';
+ e2uHash['lsaquo']= '\u2039';
+ e2uHash['rsaquo']= '\u203A';
+ e2uHash['euro']= '\u20AC';
+ e2uHash['fnof']= '\u0192';
+ e2uHash['Alpha']= '\u0391';
+ e2uHash['Beta']= '\u0392';
+ e2uHash['Gamma']= '\u0393';
+ e2uHash['Delta']= '\u0394';
+ e2uHash['Epsilon']= '\u0395';
+ e2uHash['Zeta']= '\u0396';
+ e2uHash['Eta']= '\u0397';
+ e2uHash['Theta']= '\u0398';
+ e2uHash['Iota']= '\u0399';
+ e2uHash['Kappa']= '\u039A';
+ e2uHash['Lambda']= '\u039B';
+ e2uHash['Mu']= '\u039C';
+ e2uHash['Nu']= '\u039D';
+ e2uHash['Xi']= '\u039E';
+ e2uHash['Omicron']= '\u039F';
+ e2uHash['Pi']= '\u03A0';
+ e2uHash['Rho']= '\u03A1';
+ e2uHash['Sigma']= '\u03A3';
+ e2uHash['Tau']= '\u03A4';
+ e2uHash['Upsilon']= '\u03A5';
+ e2uHash['Phi']= '\u03A6';
+ e2uHash['Chi']= '\u03A7';
+ e2uHash['Psi']= '\u03A8';
+ e2uHash['Omega']= '\u03A9';
+ e2uHash['alpha']= '\u03B1';
+ e2uHash['beta']= '\u03B2';
+ e2uHash['gamma']= '\u03B3';
+ e2uHash['delta']= '\u03B4';
+ e2uHash['epsilon']= '\u03B5';
+ e2uHash['zeta']= '\u03B6';
+ e2uHash['eta']= '\u03B7';
+ e2uHash['theta']= '\u03B8';
+ e2uHash['iota']= '\u03B9';
+ e2uHash['kappa']= '\u03BA';
+ e2uHash['lambda']= '\u03BB';
+ e2uHash['mu']= '\u03BC';
+ e2uHash['nu']= '\u03BD';
+ e2uHash['xi']= '\u03BE';
+ e2uHash['omicron']= '\u03BF';
+ e2uHash['pi']= '\u03C0';
+ e2uHash['rho']= '\u03C1';
+ e2uHash['sigmaf']= '\u03C2';
+ e2uHash['sigma']= '\u03C3';
+ e2uHash['tau']= '\u03C4';
+ e2uHash['upsilon']= '\u03C5';
+ e2uHash['phi']= '\u03C6';
+ e2uHash['chi']= '\u03C7';
+ e2uHash['psi']= '\u03C8';
+ e2uHash['omega']= '\u03C9';
+ e2uHash['thetasym']= '\u03D1';
+ e2uHash['upsih']= '\u03D2';
+ e2uHash['piv']= '\u03D6';
+ e2uHash['bull']= '\u2022';
+ e2uHash['hellip']= '\u2026';
+ e2uHash['prime']= '\u2032';
+ e2uHash['Prime']= '\u2033';
+ e2uHash['oline']= '\u203E';
+ e2uHash['frasl']= '\u2044';
+ e2uHash['weierp']= '\u2118';
+ e2uHash['image']= '\u2111';
+ e2uHash['real']= '\u211C';
+ e2uHash['trade']= '\u2122';
+ e2uHash['alefsym']= '\u2135';
+ e2uHash['larr']= '\u2190';
+ e2uHash['uarr']= '\u2191';
+ e2uHash['rarr']= '\u2192';
+ e2uHash['darr']= '\u2193';
+ e2uHash['harr']= '\u2194';
+ e2uHash['crarr']= '\u21B5';
+ e2uHash['lArr']= '\u21D0';
+ e2uHash['uArr']= '\u21D1';
+ e2uHash['rArr']= '\u21D2';
+ e2uHash['dArr']= '\u21D3';
+ e2uHash['hArr']= '\u21D4';
+ e2uHash['forall']= '\u2200';
+ e2uHash['part']= '\u2202';
+ e2uHash['exist']= '\u2203';
+ e2uHash['empty']= '\u2205';
+ e2uHash['nabla']= '\u2207';
+ e2uHash['isin']= '\u2208';
+ e2uHash['notin']= '\u2209';
+ e2uHash['ni']= '\u220B';
+ e2uHash['prod']= '\u220F';
+ e2uHash['sum']= '\u2211';
+ e2uHash['minus']= '\u2212';
+ e2uHash['lowast']= '\u2217';
+ e2uHash['radic']= '\u221A';
+ e2uHash['prop']= '\u221D';
+ e2uHash['infin']= '\u221E';
+ e2uHash['ang']= '\u2220';
+ e2uHash['and']= '\u2227';
+ e2uHash['or']= '\u2228';
+ e2uHash['cap']= '\u2229';
+ e2uHash['cup']= '\u222A';
+ e2uHash['int']= '\u222B';
+ e2uHash['there4']= '\u2234';
+ e2uHash['sim']= '\u223C';
+ e2uHash['cong']= '\u2245';
+ e2uHash['asymp']= '\u2248';
+ e2uHash['ne']= '\u2260';
+ e2uHash['equiv']= '\u2261';
+ e2uHash['le']= '\u2264';
+ e2uHash['ge']= '\u2265';
+ e2uHash['sub']= '\u2282';
+ e2uHash['sup']= '\u2283';
+ e2uHash['nsub']= '\u2284';
+ e2uHash['sube']= '\u2286';
+ e2uHash['supe']= '\u2287';
+ e2uHash['oplus']= '\u2295';
+ e2uHash['otimes']= '\u2297';
+ e2uHash['perp']= '\u22A5';
+ e2uHash['sdot']= '\u22C5';
+ e2uHash['lceil']= '\u2308';
+ e2uHash['rceil']= '\u2309';
+ e2uHash['lfloor']= '\u230A';
+ e2uHash['rfloor']= '\u230B';
+ e2uHash['lang']= '\u2329';
+ e2uHash['rang']= '\u232A';
+ e2uHash['loz']= '\u25CA';
+ e2uHash['spades']= '\u2660';
+ e2uHash['clubs']= '\u2663';
+ e2uHash['hearts']= '\u2665';
+ e2uHash['diams']= '\u2666';
+})();
+
+SimileAjax.HTML.deEntify = function(s) {
+ var e2uHash = SimileAjax.HTML._e2uHash;
+
+ var re = /&(\w+?);/;
+ while (re.test(s)) {
+ var m = s.match(re);
+ s = s.replace(re, e2uHash[m[1]]);
+ }
+ return s;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/jquery-1.3.2.min.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/jquery-1.3.2.min.js
new file mode 100644
index 00000000..e4c1728e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/jquery-1.3.2.min.js
@@ -0,0 +1,23 @@
+if (!("jQuery" in window) && !("$" in window)) {
+
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/json.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/json.js
new file mode 100644
index 00000000..8d6d39ad
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/json.js
@@ -0,0 +1,129 @@
+/*
+ * Copied directly from http://www.json.org/json.js.
+ */
+
+/*
+ json.js
+ 2006-04-28
+
+ This file adds these methods to JavaScript:
+
+ object.toJSONString()
+
+ This method produces a JSON text from an object. The
+ object must not contain any cyclical references.
+
+ array.toJSONString()
+
+ This method produces a JSON text from an array. The
+ array must not contain any cyclical references.
+
+ string.parseJSON()
+
+ This method parses a JSON text to produce an object or
+ array. It will return false if there is an error.
+*/
+
+SimileAjax.JSON = new Object();
+
+(function () {
+ var m = {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ };
+ var s = {
+ array: function (x) {
+ var a = ['['], b, f, i, l = x.length, v;
+ for (i = 0; i < l; i += 1) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a[a.length] = v;
+ b = true;
+ }
+ }
+ }
+ a[a.length] = ']';
+ return a.join('');
+ },
+ 'boolean': function (x) {
+ return String(x);
+ },
+ 'null': function (x) {
+ return "null";
+ },
+ number: function (x) {
+ return isFinite(x) ? String(x) : 'null';
+ },
+ object: function (x) {
+ if (x) {
+ if (x instanceof Array) {
+ return s.array(x);
+ }
+ var a = ['{'], b, f, i, v;
+ for (i in x) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a.push(s.string(i), ':', v);
+ b = true;
+ }
+ }
+ }
+ a[a.length] = '}';
+ return a.join('');
+ }
+ return 'null';
+ },
+ string: function (x) {
+ if (/["\\\x00-\x1f]/.test(x)) {
+ x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+ var c = m[b];
+ if (c) {
+ return c;
+ }
+ c = b.charCodeAt();
+ return '\\u00' +
+ Math.floor(c / 16).toString(16) +
+ (c % 16).toString(16);
+ });
+ }
+ return '"' + x + '"';
+ }
+ };
+
+ SimileAjax.JSON.toJSONString = function(o) {
+ if (o instanceof Object) {
+ return s.object(o);
+ } else if (o instanceof Array) {
+ return s.array(o);
+ } else {
+ return o.toString();
+ }
+ };
+
+ SimileAjax.JSON.parseJSON = function () {
+ try {
+ return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
+ this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
+ eval('(' + this + ')');
+ } catch (e) {
+ return false;
+ }
+ };
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/platform.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/platform.js
new file mode 100644
index 00000000..ace89d42
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/platform.js
@@ -0,0 +1,114 @@
+/*==================================================
+ * Platform Utility Functions and Constants
+ *==================================================
+ */
+
+/* This must be called after our jQuery has been loaded
+ but before control returns to user-code.
+*/
+
+
+/*==================================================
+ * REMEMBER to update the Version!
+ *==================================================
+ */
+SimileAjax.version = '2.2.1';
+
+SimileAjax.jQuery = jQuery.noConflict(true);
+if (typeof window["$"] == "undefined") {
+ window.$ = SimileAjax.jQuery;
+}
+
+SimileAjax.Platform.os = {
+ isMac: false,
+ isWin: false,
+ isWin32: false,
+ isUnix: false
+};
+SimileAjax.Platform.browser = {
+ isIE: false,
+ isNetscape: false,
+ isMozilla: false,
+ isFirefox: false,
+ isOpera: false,
+ isSafari: false,
+
+ majorVersion: 0,
+ minorVersion: 0
+};
+
+(function() {
+ var an = navigator.appName.toLowerCase();
+ var ua = navigator.userAgent.toLowerCase();
+
+ /*
+ * Operating system
+ */
+ SimileAjax.Platform.os.isMac = (ua.indexOf('mac') != -1);
+ SimileAjax.Platform.os.isWin = (ua.indexOf('win') != -1);
+ SimileAjax.Platform.os.isWin32 = SimileAjax.Platform.isWin && (
+ ua.indexOf('95') != -1 ||
+ ua.indexOf('98') != -1 ||
+ ua.indexOf('nt') != -1 ||
+ ua.indexOf('win32') != -1 ||
+ ua.indexOf('32bit') != -1
+ );
+ SimileAjax.Platform.os.isUnix = (ua.indexOf('x11') != -1);
+
+ /*
+ * Browser
+ */
+ SimileAjax.Platform.browser.isIE = (an.indexOf("microsoft") != -1);
+ SimileAjax.Platform.browser.isNetscape = (an.indexOf("netscape") != -1);
+ SimileAjax.Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1);
+ SimileAjax.Platform.browser.isFirefox = (ua.indexOf("firefox") != -1);
+ SimileAjax.Platform.browser.isOpera = (an.indexOf("opera") != -1);
+ SimileAjax.Platform.browser.isSafari = (an.indexOf("safari") != -1);
+
+ var parseVersionString = function(s) {
+ var a = s.split(".");
+ SimileAjax.Platform.browser.majorVersion = parseInt(a[0]);
+ SimileAjax.Platform.browser.minorVersion = parseInt(a[1]);
+ };
+ var indexOf = function(s, sub, start) {
+ var i = s.indexOf(sub, start);
+ return i >= 0 ? i : s.length;
+ };
+
+ if (SimileAjax.Platform.browser.isMozilla) {
+ var offset = ua.indexOf("mozilla/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isIE) {
+ var offset = ua.indexOf("msie ");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isNetscape) {
+ var offset = ua.indexOf("rv:");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isFirefox) {
+ var offset = ua.indexOf("firefox/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+
+ if (!("localeCompare" in String.prototype)) {
+ String.prototype.localeCompare = function (s) {
+ if (this < s) return -1;
+ else if (this > s) return 1;
+ else return 0;
+ };
+ }
+})();
+
+SimileAjax.Platform.getDefaultLocale = function() {
+ return SimileAjax.Platform.clientLocale;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/signal.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/signal.js
new file mode 100644
index 00000000..9c424d4c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/signal.js
@@ -0,0 +1,43 @@
+/*==================================================
+ * This file is used to detect that all outstanding
+ * javascript files have been loaded. You can put
+ * a function reference into SimileAjax_onLoad
+ * to have it executed once all javascript files
+ * have loaded.
+ *==================================================
+ */
+(function() {
+ var substring = SimileAjax.urlPrefix + "scripts/signal.js";
+ var heads = document.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var node = heads[h].firstChild;
+ while (node != null) {
+ if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
+ var url = node.src;
+ var i = url.indexOf(substring);
+ if (i >= 0) {
+ heads[h].removeChild(node); // remove it so we won't hit it again
+
+ var count = parseInt(url.substr(url.indexOf(substring) + substring.length + 1));
+ SimileAjax.loadingScriptsCount -= count;
+ if (SimileAjax.loadingScriptsCount == 0) {
+ var f = null;
+ if (typeof SimileAjax_onLoad == "string") {
+ f = eval(SimileAjax_onLoad);
+ SimileAjax_onLoad = null;
+ } else if (typeof SimileAjax_onLoad == "function") {
+ f = SimileAjax_onLoad;
+ SimileAjax_onLoad = null;
+ }
+
+ if (f != null) {
+ f();
+ }
+ }
+ return;
+ }
+ }
+ node = node.nextSibling;
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/string.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/string.js
new file mode 100644
index 00000000..11b31e04
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/string.js
@@ -0,0 +1,43 @@
+/*==================================================
+ * String Utility Functions and Constants
+ *==================================================
+ */
+
+String.prototype.trim = function() {
+ return this.replace(/^\s+|\s+$/g, '');
+};
+
+String.prototype.startsWith = function(prefix) {
+ return this.length >= prefix.length && this.substr(0, prefix.length) == prefix;
+};
+
+String.prototype.endsWith = function(suffix) {
+ return this.length >= suffix.length && this.substr(this.length - suffix.length) == suffix;
+};
+
+String.substitute = function(s, objects) {
+ var result = "";
+ var start = 0;
+ while (start < s.length - 1) {
+ var percent = s.indexOf("%", start);
+ if (percent < 0 || percent == s.length - 1) {
+ break;
+ } else if (percent > start && s.charAt(percent - 1) == "\\") {
+ result += s.substring(start, percent - 1) + "%";
+ start = percent + 1;
+ } else {
+ var n = parseInt(s.charAt(percent + 1));
+ if (isNaN(n) || n >= objects.length) {
+ result += s.substring(start, percent + 2);
+ } else {
+ result += s.substring(start, percent) + objects[n].toString();
+ }
+ start = percent + 2;
+ }
+ }
+
+ if (start < s.length) {
+ result += s.substring(start);
+ }
+ return result;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/units.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/units.js
new file mode 100644
index 00000000..cc68e0dd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/units.js
@@ -0,0 +1,73 @@
+/*==================================================
+ * Default Unit
+ *==================================================
+ */
+
+SimileAjax.NativeDateUnit = new Object();
+
+SimileAjax.NativeDateUnit.makeDefaultValue = function() {
+ return new Date();
+};
+
+SimileAjax.NativeDateUnit.cloneValue = function(v) {
+ return new Date(v.getTime());
+};
+
+SimileAjax.NativeDateUnit.getParser = function(format) {
+ if (typeof format == "string") {
+ format = format.toLowerCase();
+ }
+
+ var parser = (format == "iso8601" || format == "iso 8601") ?
+ SimileAjax.DateTime.parseIso8601DateTime :
+ SimileAjax.DateTime.parseGregorianDateTime;
+
+ return function(d) {
+ if (typeof d != 'undefined' && typeof d.toUTCString == "function") {
+ return d;
+ } else {
+ return parser(d);
+ }
+ };
+};
+
+SimileAjax.NativeDateUnit.parseFromObject = function(o) {
+ return SimileAjax.DateTime.parseGregorianDateTime(o);
+};
+
+SimileAjax.NativeDateUnit.toNumber = function(v) {
+ return v.getTime();
+};
+
+SimileAjax.NativeDateUnit.fromNumber = function(n) {
+ return new Date(n);
+};
+
+SimileAjax.NativeDateUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1.getTime();
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2.getTime();
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n1 - n2;
+};
+
+SimileAjax.NativeDateUnit.earlier = function(v1, v2) {
+ return SimileAjax.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.later = function(v1, v2) {
+ return SimileAjax.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.change = function(v, n) {
+ return new Date(v.getTime() + n);
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/window-manager.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/window-manager.js
new file mode 100644
index 00000000..4d826483
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/window-manager.js
@@ -0,0 +1,414 @@
+/**
+ * @fileOverview UI layers and window-wide dragging
+ * @name SimileAjax.WindowManager
+ */
+
+/**
+ * This is a singleton that keeps track of UI layers (modal and
+ * modeless) and enables/disables UI elements based on which layers
+ * they belong to. It also provides window-wide dragging
+ * implementation.
+ */
+SimileAjax.WindowManager = {
+ _initialized: false,
+ _listeners: [],
+
+ _draggedElement: null,
+ _draggedElementCallback: null,
+ _dropTargetHighlightElement: null,
+ _lastCoords: null,
+ _ghostCoords: null,
+ _draggingMode: "",
+ _dragging: false,
+
+ _layers: []
+};
+
+SimileAjax.WindowManager.initialize = function() {
+ if (SimileAjax.WindowManager._initialized) {
+ return;
+ }
+
+ SimileAjax.DOM.registerEvent(document.body, "mousedown", SimileAjax.WindowManager._onBodyMouseDown);
+ SimileAjax.DOM.registerEvent(document.body, "mousemove", SimileAjax.WindowManager._onBodyMouseMove);
+ SimileAjax.DOM.registerEvent(document.body, "mouseup", SimileAjax.WindowManager._onBodyMouseUp);
+ SimileAjax.DOM.registerEvent(document, "keydown", SimileAjax.WindowManager._onBodyKeyDown);
+ SimileAjax.DOM.registerEvent(document, "keyup", SimileAjax.WindowManager._onBodyKeyUp);
+
+ SimileAjax.WindowManager._layers.push({index: 0});
+
+ SimileAjax.WindowManager._historyListener = {
+ onBeforeUndoSeveral: function() {},
+ onAfterUndoSeveral: function() {},
+ onBeforeUndo: function() {},
+ onAfterUndo: function() {},
+
+ onBeforeRedoSeveral: function() {},
+ onAfterRedoSeveral: function() {},
+ onBeforeRedo: function() {},
+ onAfterRedo: function() {}
+ };
+ SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+
+ SimileAjax.WindowManager._initialized = true;
+};
+
+SimileAjax.WindowManager.getBaseLayer = function() {
+ SimileAjax.WindowManager.initialize();
+ return SimileAjax.WindowManager._layers[0];
+};
+
+SimileAjax.WindowManager.getHighestLayer = function() {
+ SimileAjax.WindowManager.initialize();
+ return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length - 1];
+};
+
+SimileAjax.WindowManager.registerEventWithObject = function(elmt, eventName, obj, handlerName, layer) {
+ SimileAjax.WindowManager.registerEvent(
+ elmt,
+ eventName,
+ function(elmt2, evt, target) {
+ return obj[handlerName].call(obj, elmt2, evt, target);
+ },
+ layer
+ );
+};
+
+SimileAjax.WindowManager.registerEvent = function(elmt, eventName, handler, layer) {
+ if (layer == null) {
+ layer = SimileAjax.WindowManager.getHighestLayer();
+ }
+
+ var handler2 = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._canProcessEventAtLayer(layer)) {
+ SimileAjax.WindowManager._popToLayer(layer.index);
+ try {
+ handler(elmt, evt, target);
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+
+ SimileAjax.DOM.registerEvent(elmt, eventName, handler2);
+};
+
+SimileAjax.WindowManager.pushLayer = function(f, ephemeral, elmt) {
+ var layer = { onPop: f, index: SimileAjax.WindowManager._layers.length, ephemeral: (ephemeral), elmt: elmt };
+ SimileAjax.WindowManager._layers.push(layer);
+
+ return layer;
+};
+
+SimileAjax.WindowManager.popLayer = function(layer) {
+ for (var i = 1; i < SimileAjax.WindowManager._layers.length; i++) {
+ if (SimileAjax.WindowManager._layers[i] == layer) {
+ SimileAjax.WindowManager._popToLayer(i - 1);
+ break;
+ }
+ }
+};
+
+SimileAjax.WindowManager.popAllLayers = function() {
+ SimileAjax.WindowManager._popToLayer(0);
+};
+
+SimileAjax.WindowManager.registerForDragging = function(elmt, callback, layer) {
+ SimileAjax.WindowManager.registerEvent(
+ elmt,
+ "mousedown",
+ function(elmt, evt, target) {
+ SimileAjax.WindowManager._handleMouseDown(elmt, evt, callback);
+ },
+ layer
+ );
+};
+
+SimileAjax.WindowManager._popToLayer = function(level) {
+ while (level+1 < SimileAjax.WindowManager._layers.length) {
+ try {
+ var layer = SimileAjax.WindowManager._layers.pop();
+ if (layer.onPop != null) {
+ layer.onPop();
+ }
+ } catch (e) {
+ }
+ }
+};
+
+SimileAjax.WindowManager._canProcessEventAtLayer = function(layer) {
+ if (layer.index == (SimileAjax.WindowManager._layers.length - 1)) {
+ return true;
+ }
+ for (var i = layer.index + 1; i < SimileAjax.WindowManager._layers.length; i++) {
+ if (!SimileAjax.WindowManager._layers[i].ephemeral) {
+ return false;
+ }
+ }
+ return true;
+};
+
+SimileAjax.WindowManager.cancelPopups = function(evt) {
+ var evtCoords = (evt) ? SimileAjax.DOM.getEventPageCoordinates(evt) : { x: -1, y: -1 };
+
+ var i = SimileAjax.WindowManager._layers.length - 1;
+ while (i > 0 && SimileAjax.WindowManager._layers[i].ephemeral) {
+ var layer = SimileAjax.WindowManager._layers[i];
+ if (layer.elmt != null) { // if event falls within main element of layer then don't cancel
+ var elmt = layer.elmt;
+ var elmtCoords = SimileAjax.DOM.getPageCoordinates(elmt);
+ if (evtCoords.x >= elmtCoords.left && evtCoords.x < (elmtCoords.left + elmt.offsetWidth) &&
+ evtCoords.y >= elmtCoords.top && evtCoords.y < (elmtCoords.top + elmt.offsetHeight)) {
+ break;
+ }
+ }
+ i--;
+ }
+ SimileAjax.WindowManager._popToLayer(i);
+};
+
+SimileAjax.WindowManager._onBodyMouseDown = function(elmt, evt, target) {
+ if (!("eventPhase" in evt) || evt.eventPhase == evt.BUBBLING_PHASE) {
+ SimileAjax.WindowManager.cancelPopups(evt);
+ }
+};
+
+SimileAjax.WindowManager._handleMouseDown = function(elmt, evt, callback) {
+ SimileAjax.WindowManager._draggedElement = elmt;
+ SimileAjax.WindowManager._draggedElementCallback = callback;
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+};
+
+SimileAjax.WindowManager._onBodyKeyDown = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._dragging) {
+ if (evt.keyCode == 27) { // esc
+ SimileAjax.WindowManager._cancelDragging();
+ } else if ((evt.keyCode == 17 || evt.keyCode == 16) && SimileAjax.WindowManager._draggingMode != "copy") {
+ SimileAjax.WindowManager._draggingMode = "copy";
+
+ var img = SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix + "images/copy.png");
+ img.style.position = "absolute";
+ img.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+ img.style.top = (SimileAjax.WindowManager._ghostCoords.top) + "px";
+ document.body.appendChild(img);
+
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = img;
+ }
+ }
+};
+
+SimileAjax.WindowManager._onBodyKeyUp = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._dragging) {
+ if (evt.keyCode == 17 || evt.keyCode == 16) {
+ SimileAjax.WindowManager._draggingMode = "";
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+ }
+ }
+ }
+};
+
+SimileAjax.WindowManager._onBodyMouseMove = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._draggedElement != null) {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+
+ var lastCoords = SimileAjax.WindowManager._lastCoords;
+ var diffX = evt.clientX - lastCoords.x;
+ var diffY = evt.clientY - lastCoords.y;
+
+ if (!SimileAjax.WindowManager._dragging) {
+ if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
+ try {
+ if ("onDragStart" in callback) {
+ callback.onDragStart();
+ }
+
+ if ("ghost" in callback && callback.ghost) {
+ var draggedElmt = SimileAjax.WindowManager._draggedElement;
+
+ SimileAjax.WindowManager._ghostCoords = SimileAjax.DOM.getPageCoordinates(draggedElmt);
+ SimileAjax.WindowManager._ghostCoords.left += diffX;
+ SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+ var ghostElmt = draggedElmt.cloneNode(true);
+ ghostElmt.style.position = "absolute";
+ ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+ ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ ghostElmt.style.zIndex = 1000;
+ SimileAjax.Graphics.setOpacity(ghostElmt, 50);
+
+ document.body.appendChild(ghostElmt);
+ callback._ghostElmt = ghostElmt;
+ }
+
+ SimileAjax.WindowManager._dragging = true;
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ document.body.focus();
+ } catch (e) {
+ SimileAjax.Debug.exception("WindowManager: Error handling mouse down", e);
+ SimileAjax.WindowManager._cancelDragging();
+ }
+ }
+ } else {
+ try {
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ if ("onDragBy" in callback) {
+ callback.onDragBy(diffX, diffY);
+ }
+
+ if ("_ghostElmt" in callback) {
+ var ghostElmt = callback._ghostElmt;
+
+ SimileAjax.WindowManager._ghostCoords.left += diffX;
+ SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+ ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+ ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ var indicatorElmt = SimileAjax.WindowManager._draggingModeIndicatorElmt;
+
+ indicatorElmt.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+ indicatorElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ }
+
+ if ("droppable" in callback && callback.droppable) {
+ var coords = SimileAjax.DOM.getEventPageCoordinates(evt);
+ var target = SimileAjax.DOM.hittest(
+ coords.x, coords.y,
+ [ SimileAjax.WindowManager._ghostElmt,
+ SimileAjax.WindowManager._dropTargetHighlightElement
+ ]
+ );
+ target = SimileAjax.WindowManager._findDropTarget(target);
+
+ if (target != SimileAjax.WindowManager._potentialDropTarget) {
+ if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+ document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ SimileAjax.WindowManager._potentialDropTarget = null;
+ }
+
+ var droppable = false;
+ if (target != null) {
+ if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+ (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+ droppable = true;
+ }
+ }
+
+ if (droppable) {
+ var border = 4;
+ var targetCoords = SimileAjax.DOM.getPageCoordinates(target);
+ var highlight = document.createElement("div");
+ highlight.style.border = border + "px solid yellow";
+ highlight.style.backgroundColor = "yellow";
+ highlight.style.position = "absolute";
+ highlight.style.left = targetCoords.left + "px";
+ highlight.style.top = targetCoords.top + "px";
+ highlight.style.width = (target.offsetWidth - border * 2) + "px";
+ highlight.style.height = (target.offsetHeight - border * 2) + "px";
+ SimileAjax.Graphics.setOpacity(highlight, 30);
+ document.body.appendChild(highlight);
+
+ SimileAjax.WindowManager._potentialDropTarget = target;
+ SimileAjax.WindowManager._dropTargetHighlightElement = highlight;
+ }
+ }
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception("WindowManager: Error handling mouse move", e);
+ SimileAjax.WindowManager._cancelDragging();
+ }
+ }
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+};
+
+SimileAjax.WindowManager._onBodyMouseUp = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._draggedElement != null) {
+ try {
+ if (SimileAjax.WindowManager._dragging) {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+ if ("onDragEnd" in callback) {
+ callback.onDragEnd();
+ }
+ if ("droppable" in callback && callback.droppable) {
+ var dropped = false;
+
+ var target = SimileAjax.WindowManager._potentialDropTarget;
+ if (target != null) {
+ if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+ (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+ if ("onDropOn" in callback) {
+ callback.onDropOn(target);
+ }
+ target.ondrop(SimileAjax.WindowManager._draggedElement, SimileAjax.WindowManager._draggingMode);
+
+ dropped = true;
+ }
+ }
+
+ if (!dropped) {
+ // TODO: do holywood explosion here
+ }
+ }
+ }
+ } finally {
+ SimileAjax.WindowManager._cancelDragging();
+ }
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+};
+
+SimileAjax.WindowManager._cancelDragging = function() {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+ if ("_ghostElmt" in callback) {
+ var ghostElmt = callback._ghostElmt;
+ document.body.removeChild(ghostElmt);
+
+ delete callback._ghostElmt;
+ }
+ if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+ document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ }
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+ }
+
+ SimileAjax.WindowManager._draggedElement = null;
+ SimileAjax.WindowManager._draggedElementCallback = null;
+ SimileAjax.WindowManager._potentialDropTarget = null;
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ SimileAjax.WindowManager._lastCoords = null;
+ SimileAjax.WindowManager._ghostCoords = null;
+ SimileAjax.WindowManager._draggingMode = "";
+ SimileAjax.WindowManager._dragging = false;
+};
+
+SimileAjax.WindowManager._findDropTarget = function(elmt) {
+ while (elmt != null) {
+ if ("ondrop" in elmt && (typeof elmt.ondrop) == "function") {
+ break;
+ }
+ elmt = elmt.parentNode;
+ }
+ return elmt;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/xmlhttp.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/xmlhttp.js
new file mode 100644
index 00000000..b6d2c0aa
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/scripts/xmlhttp.js
@@ -0,0 +1,137 @@
+/**
+ * @fileOverview XmlHttp utility functions
+ * @name SimileAjax.XmlHttp
+ */
+
+SimileAjax.XmlHttp = new Object();
+
+/**
+ * Callback for XMLHttp onRequestStateChange.
+ */
+SimileAjax.XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) {
+ switch (xmlhttp.readyState) {
+ // 1: Request not yet made
+ // 2: Contact established with server but nothing downloaded yet
+ // 3: Called multiple while downloading in progress
+
+ // Download complete
+ case 4:
+ try {
+ if (xmlhttp.status == 0 // file:// urls, works on Firefox
+ || xmlhttp.status == 200 // http:// urls
+ ) {
+ if (fDone) {
+ fDone(xmlhttp);
+ }
+ } else {
+ if (fError) {
+ fError(
+ xmlhttp.statusText,
+ xmlhttp.status,
+ xmlhttp
+ );
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange", e);
+ }
+ break;
+ }
+};
+
+/**
+ * Creates an XMLHttpRequest object. On the first run, this
+ * function creates a platform-specific function for
+ * instantiating an XMLHttpRequest object and then replaces
+ * itself with that function.
+ */
+SimileAjax.XmlHttp._createRequest = function() {
+ if (SimileAjax.Platform.browser.isIE) {
+ var programIDs = [
+ "Msxml2.XMLHTTP",
+ "Microsoft.XMLHTTP",
+ "Msxml2.XMLHTTP.4.0"
+ ];
+ for (var i = 0; i < programIDs.length; i++) {
+ try {
+ var programID = programIDs[i];
+ var f = function() {
+ return new ActiveXObject(programID);
+ };
+ var o = f();
+
+ // We are replacing the SimileAjax._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ SimileAjax.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ // silent
+ }
+ }
+ // fall through to try new XMLHttpRequest();
+ }
+
+ try {
+ var f = function() {
+ return new XMLHttpRequest();
+ };
+ var o = f();
+
+ // We are replacing the SimileAjax._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ SimileAjax.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ throw new Error("Failed to create an XMLHttpRequest object");
+ }
+};
+
+/**
+ * Performs an asynchronous HTTP GET.
+ *
+ * @param {Function} fError a function of the form
+ function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.get = function(url, fError, fDone) {
+ var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+ xmlhttp.open("GET", url, true);
+ xmlhttp.onreadystatechange = function() {
+ SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(null);
+};
+
+/**
+ * Performs an asynchronous HTTP POST.
+ *
+ * @param {Function} fError a function of the form
+ function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.post = function(url, body, fError, fDone) {
+ var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+ xmlhttp.open("POST", url, true);
+ xmlhttp.onreadystatechange = function() {
+ SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(body);
+};
+
+SimileAjax.XmlHttp._forceXML = function(xmlhttp) {
+ try {
+ xmlhttp.overrideMimeType("text/xml");
+ } catch (e) {
+ xmlhttp.setrequestheader("Content-Type", "text/xml");
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-api.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-api.js
new file mode 100644
index 00000000..8a0ec49d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-api.js
@@ -0,0 +1,215 @@
+/*==================================================
+ * Simile Ajax API
+ *==================================================
+ */
+
+if (typeof SimileAjax == "undefined") {
+ var isCompiled = ("SimileAjax_isCompiled" in window) && window.SimileAjax_isCompiled;
+
+ var SimileAjax = {
+ loaded: false,
+ loadingScriptsCount: 0,
+ error: null,
+ params: { bundle:"true" }
+ };
+
+ SimileAjax.Platform = new Object();
+ /*
+ HACK: We need these 2 things here because we cannot simply append
+ a <script> element containing code that accesses SimileAjax.Platform
+ to initialize it because IE executes that <script> code first
+ before it loads ajax.js and platform.js.
+ */
+
+ var getHead = function(doc) {
+ return doc.getElementsByTagName("head")[0];
+ };
+
+ SimileAjax.findScript = function(doc, substring) {
+ var heads = doc.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var node = heads[h].firstChild;
+ while (node != null) {
+ if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
+ var url = node.src;
+ var i = url.indexOf(substring);
+ if (i >= 0) {
+ return url;
+ }
+ }
+ node = node.nextSibling;
+ }
+ }
+ return null;
+ };
+ SimileAjax.includeJavascriptFile = function(doc, url, onerror, charset) {
+ onerror = onerror || "";
+ if (doc.body == null) {
+ try {
+ var q = "'" + onerror.replace( /'/g, '&apos' ) + "'"; // "
+ doc.write("<script src='" + url + "' onerror="+ q +
+ (charset ? " charset='"+ charset +"'" : "") +
+ " type='text/javascript'>"+ onerror + "</script>");
+ return;
+ } catch (e) {
+ // fall through
+ }
+ }
+
+ var script = doc.createElement("script");
+ if (onerror) {
+ try { script.innerHTML = onerror; } catch(e) {}
+ script.setAttribute("onerror", onerror);
+ }
+ if (charset) {
+ script.setAttribute("charset", charset);
+ }
+ script.type = "text/javascript";
+ script.language = "JavaScript";
+ script.src = url;
+ return getHead(doc).appendChild(script);
+ };
+ SimileAjax.includeJavascriptFiles = function(doc, urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ SimileAjax.includeJavascriptFile(doc, urlPrefix + filenames[i]);
+ }
+ SimileAjax.loadingScriptsCount += filenames.length;
+ SimileAjax.includeJavascriptFile(doc, SimileAjax.urlPrefix + "scripts/signal.js?" + filenames.length);
+ };
+ SimileAjax.includeCssFile = function(doc, url) {
+ if (doc.body == null) {
+ try {
+ doc.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>");
+ return;
+ } catch (e) {
+ // fall through
+ }
+ }
+
+ var link = doc.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("type", "text/css");
+ link.setAttribute("href", url);
+ getHead(doc).appendChild(link);
+ };
+ SimileAjax.includeCssFiles = function(doc, urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ SimileAjax.includeCssFile(doc, urlPrefix + filenames[i]);
+ }
+ };
+
+ /**
+ * Append into urls each string in suffixes after prefixing it with urlPrefix.
+ * @param {Array} urls
+ * @param {String} urlPrefix
+ * @param {Array} suffixes
+ */
+ SimileAjax.prefixURLs = function(urls, urlPrefix, suffixes) {
+ for (var i = 0; i < suffixes.length; i++) {
+ urls.push(urlPrefix + suffixes[i]);
+ }
+ };
+
+ /**
+ * Parse out the query parameters from a URL
+ * @param {String} url the url to parse, or location.href if undefined
+ * @param {Object} to optional object to extend with the parameters
+ * @param {Object} types optional object mapping keys to value types
+ * (String, Number, Boolean or Array, String by default)
+ * @return a key/value Object whose keys are the query parameter names
+ * @type Object
+ */
+ SimileAjax.parseURLParameters = function(url, to, types) {
+ to = to || {};
+ types = types || {};
+
+ if (typeof url == "undefined") {
+ url = location.href;
+ }
+ var q = url.indexOf("?");
+ if (q < 0) {
+ return to;
+ }
+ url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
+
+ var params = url.split("&"), param, parsed = {};
+ var decode = window.decodeURIComponent || unescape;
+ for (var i = 0; param = params[i]; i++) {
+ var eq = param.indexOf("=");
+ var name = decode(param.slice(0,eq));
+ var old = parsed[name];
+ if (typeof old == "undefined") {
+ old = [];
+ } else if (!(old instanceof Array)) {
+ old = [old];
+ }
+ parsed[name] = old.concat(decode(param.slice(eq+1)));
+ }
+ for (var i in parsed) {
+ if (!parsed.hasOwnProperty(i)) continue;
+ var type = types[i] || String;
+ var data = parsed[i];
+ if (!(data instanceof Array)) {
+ data = [data];
+ }
+ if (type === Boolean && data[0] == "false") {
+ to[i] = false; // because Boolean("false") === true
+ } else {
+ to[i] = type.apply(this, data);
+ }
+ }
+ return to;
+ };
+
+ if (!isCompiled) {
+ (function() {
+ var javascriptFiles = [
+ "platform.js",
+ "debug.js",
+ "xmlhttp.js",
+ "json.js",
+ "dom.js",
+ "graphics.js",
+ "date-time.js",
+ "string.js",
+ "html.js",
+ "data-structure.js",
+ "units.js",
+
+ "ajax.js",
+ "history.js",
+ "window-manager.js"
+ ];
+ var cssFiles = [
+ "graphics.css"
+ ];
+ if (!("jQuery" in window) && !("$" in window)) {
+ javascriptFiles.unshift("jquery-1.3.2.min.js");
+ }
+
+ if (typeof SimileAjax_urlPrefix == "string") {
+ SimileAjax.urlPrefix = SimileAjax_urlPrefix;
+ } else {
+ var url = SimileAjax.findScript(document, "simile-ajax-api.js");
+ if (url == null) {
+ SimileAjax.error = new Error("Failed to derive URL prefix for Simile Ajax API code files");
+ return;
+ }
+
+ SimileAjax.urlPrefix = url.substr(0, url.indexOf("simile-ajax-api.js"));
+ SimileAjax.parseURLParameters(url, SimileAjax.params, { bundle: Boolean });
+ }
+
+ if (!isCompiled) {
+ if (SimileAjax.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix, [ "simile-ajax-bundle.js" ]);
+ } else {
+ SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix + "scripts/", javascriptFiles);
+ }
+ SimileAjax.includeCssFiles(document, SimileAjax.urlPrefix + "styles/", cssFiles);
+ }
+
+ SimileAjax.loaded = true;
+ })();
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle-debug.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle-debug.js
new file mode 100644
index 00000000..2cc5e9b5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle-debug.js
@@ -0,0 +1,2911 @@
+
+
+/* jquery-1.3.2.min.js */
+if(!("jQuery" in window)&&!("$" in window)){(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F);
+},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;
+o.fn=o.prototype={init:function(E,H){E=E||document;
+if(E.nodeType){this[0]=E;
+this.length=1;
+this.context=E;
+return this;
+}if(typeof E==="string"){var G=D.exec(E);
+if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H);
+}else{var I=document.getElementById(G[3]);
+if(I&&I.id!=G[3]){return o().find(E);
+}var F=o(I||[]);
+F.context=document;
+F.selector=E;
+return F;
+}}else{return o(H).find(E);
+}}else{if(o.isFunction(E)){return o(document).ready(E);
+}}if(E.selector&&E.context){this.selector=E.selector;
+this.context=E.context;
+}return this.setArray(o.isArray(E)?E:o.makeArray(E));
+},selector:"",jquery:"1.3.2",size:function(){return this.length;
+},get:function(E){return E===g?Array.prototype.slice.call(this):this[E];
+},pushStack:function(F,H,E){var G=o(F);
+G.prevObject=this;
+G.context=this.context;
+if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E;
+}else{if(H){G.selector=this.selector+"."+H+"("+E+")";
+}}return G;
+},setArray:function(E){this.length=0;
+Array.prototype.push.apply(this,E);
+return this;
+},each:function(F,E){return o.each(this,F,E);
+},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this);
+},attr:function(F,H,G){var E=F;
+if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F);
+}else{E={};
+E[F]=H;
+}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F));
+}});
+},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g;
+}return this.attr(E,F,"curCSS");
+},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F));
+}var E="";
+o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this]);
+}});
+});
+return E;
+},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();
+if(this[0].parentNode){F.insertBefore(this[0]);
+}F.map(function(){var G=this;
+while(G.firstChild){G=G.firstChild;
+}return G;
+}).append(this);
+}return this;
+},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E);
+});
+},wrap:function(E){return this.each(function(){o(this).wrapAll(E);
+});
+},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E);
+}});
+},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild);
+}});
+},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this);
+});
+},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling);
+});
+},end:function(){return this.prevObject||o([]);
+},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);
+F.length=0;
+o.find(E,this[0],F);
+return F;
+}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G);
+})),"find",E);
+}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;
+if(!I){var J=this.ownerDocument.createElement("div");
+J.appendChild(this.cloneNode(true));
+I=J.innerHTML;
+}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0];
+}else{return this.cloneNode(true);
+}});
+if(G===true){var H=this.find("*").andSelf(),F=0;
+E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return ;
+}var I=o.data(H[F],"events");
+for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data);
+}}F++;
+});
+}return E;
+},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F);
+})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1;
+})),"filter",E);
+},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;
+return this.map(function(){var H=this;
+while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);
+return H;
+}H=H.parentNode;
+F++;
+}});
+},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E);
+}else{E=o.multiFilter(E,this);
+}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;
+return this.filter(function(){return F?o.inArray(this,E)<0:this!=E;
+});
+},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))));
+},is:function(E){return !!E&&o.multiFilter(E,this).length>0;
+},hasClass:function(E){return !!E&&this.is("."+E);
+},val:function(K){if(K===g){var E=this[0];
+if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text;
+}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";
+if(I<0){return null;
+}for(var F=H?I:0,J=H?I+1:M.length;
+F<J;
+F++){var G=M[F];
+if(G.selected){K=o(G).val();
+if(H){return K;
+}L.push(K);
+}}return L;
+}return(E.value||"").replace(/\r/g,"");
+}return g;
+}if(typeof K==="number"){K+="";
+}return this.each(function(){if(this.nodeType!=1){return ;
+}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0);
+}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);
+o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0);
+});
+if(!N.length){this.selectedIndex=-1;
+}}else{this.value=K;
+}}});
+},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E);
+},replaceWith:function(E){return this.after(E).remove();
+},eq:function(E){return this.slice(E,+E+1);
+},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","));
+},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G);
+}));
+},andSelf:function(){return this.add(this.prevObject);
+},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;
+if(H){for(var G=0,E=this.length;
+G<E;
+G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I);
+}}if(F){o.each(F,z);
+}}return this;
+function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N;
+}}};
+o.fn.init.prototype=o.fn;
+function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"});
+}else{o.globalEval(F.text||F.textContent||F.innerHTML||"");
+}if(F.parentNode){F.parentNode.removeChild(F);
+}}function e(){return +new Date;
+}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;
+if(typeof J==="boolean"){E=J;
+J=arguments[1]||{};
+H=2;
+}if(typeof J!=="object"&&!o.isFunction(J)){J={};
+}if(I==H){J=this;
+--H;
+}for(;
+H<I;
+H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];
+if(J===L){continue;
+}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L);
+}else{if(L!==g){J[F]=L;
+}}}}}return J;
+};
+var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;
+o.extend({noConflict:function(E){l.$=p;
+if(E){l.jQuery=y;
+}return o;
+},isFunction:function(E){return s.call(E)==="[object Function]";
+},isArray:function(E){return s.call(E)==="[object Array]";
+},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument);
+},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");
+E.type="text/javascript";
+if(o.support.scriptEval){E.appendChild(document.createTextNode(G));
+}else{E.text=G;
+}F.insertBefore(E,F.firstChild);
+F.removeChild(E);
+}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase();
+},each:function(G,K,F){var E,H=0,I=G.length;
+if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break;
+}}}else{for(;
+H<I;
+){if(K.apply(G[H++],F)===false){break;
+}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break;
+}}}else{for(var J=G[0];
+H<I&&K.call(J,H,J)!==false;
+J=G[++H]){}}}return G;
+},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F);
+}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I;
+},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H;
+}});
+},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G);
+}).join(" "):"";
+}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1;
+}},swap:function(H,G,I){var E={};
+for(var F in G){E[F]=H.style[F];
+H.style[F]=G[F];
+}I.call(H);
+for(var F in G){H.style[F]=E[F];
+}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];
+function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;
+if(E==="border"){return ;
+}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0;
+}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0;
+}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0;
+}});
+}if(H.offsetWidth!==0){I();
+}else{o.swap(H,G,I);
+}return Math.max(0,Math.round(L));
+}return o.curCSS(H,F,J);
+},curCSS:function(I,F,G){var L,E=I.style;
+if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");
+return L==""?"1":L;
+}if(F.match(/float/i)){F=w;
+}if(!G&&E&&E[F]){L=E[F];
+}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float";
+}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();
+var M=q.getComputedStyle(I,null);
+if(M){L=M.getPropertyValue(F);
+}if(F=="opacity"&&L==""){L="1";
+}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase();
+});
+L=I.currentStyle[F]||I.currentStyle[J];
+if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;
+I.runtimeStyle.left=I.currentStyle.left;
+E.left=L||0;
+L=E.pixelLeft+"px";
+E.left=H;
+I.runtimeStyle.left=K;
+}}}}return L;
+},clean:function(F,K,I){K=K||document;
+if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document;
+}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);
+if(H){return[K.createElement(H[1])];
+}}var G=[],E=[],L=K.createElement("div");
+o.each(F,function(P,S){if(typeof S==="number"){S+="";
+}if(!S){return ;
+}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">";
+});
+var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();
+var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];
+L.innerHTML=Q[1]+S+Q[2];
+while(Q[0]--){L=L.lastChild;
+}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];
+for(var M=N.length-1;
+M>=0;
+--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M]);
+}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild);
+}S=o.makeArray(L.childNodes);
+}if(S.nodeType){G.push(S);
+}else{G=o.merge(G,S);
+}});
+if(I){for(var J=0;
+G[J];
+J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J]);
+}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))));
+}I.appendChild(G[J]);
+}}return E;
+}return G;
+},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g;
+}var H=!o.isXMLDoc(J),L=K!==g;
+G=H&&o.props[G]||G;
+if(J.tagName){var F=/href|src|style/.test(G);
+if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex;
+}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed";
+}J[G]=K;
+}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue;
+}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");
+return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g;
+}return J[G];
+}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K);
+}if(L){J.setAttribute(G,""+K);
+}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);
+return E===null?g:E;
+}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;
+J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")");
+}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":"";
+}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase();
+});
+if(L){J[G]=K;
+}return J[G];
+},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"");
+},makeArray:function(G){var E=[];
+if(G!=null){var F=G.length;
+if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G;
+}else{while(F){E[--F]=G[F];
+}}}return E;
+},inArray:function(G,H){for(var E=0,F=H.length;
+E<F;
+E++){if(H[E]===G){return E;
+}}return -1;
+},merge:function(H,E){var F=0,G,I=H.length;
+if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G;
+}}}else{while((G=E[F++])!=null){H[I++]=G;
+}}return H;
+},unique:function(K){var F=[],E={};
+try{for(var G=0,H=K.length;
+G<H;
+G++){var J=o.data(K[G]);
+if(!E[J]){E[J]=true;
+F.push(K[G]);
+}}}catch(I){F=K;
+}return F;
+},grep:function(F,J,E){var G=[];
+for(var H=0,I=F.length;
+H<I;
+H++){if(!E!=!J(F[H],H)){G.push(F[H]);
+}}return G;
+},map:function(E,J){var F=[];
+for(var G=0,H=E.length;
+G<H;
+G++){var I=J(E[G],G);
+if(I!=null){F[F.length]=I;
+}}return F.concat.apply([],F);
+}});
+var C=navigator.userAgent.toLowerCase();
+o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};
+o.each({parent:function(E){return E.parentNode;
+},parents:function(E){return o.dir(E,"parentNode");
+},next:function(E){return o.nth(E,2,"nextSibling");
+},prev:function(E){return o.nth(E,2,"previousSibling");
+},nextAll:function(E){return o.dir(E,"nextSibling");
+},prevAll:function(E){return o.dir(E,"previousSibling");
+},siblings:function(E){return o.sibling(E.parentNode.firstChild,E);
+},children:function(E){return o.sibling(E.firstChild);
+},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes);
+}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);
+if(G&&typeof G=="string"){H=o.multiFilter(G,H);
+}return this.pushStack(o.unique(H),E,G);
+};
+});
+o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);
+for(var K=0,H=L.length;
+K<H;
+K++){var I=(K>0?this.clone(true):this).get();
+o.fn[F].apply(o(L[K]),I);
+J=J.concat(I);
+}return this.pushStack(J,E,G);
+};
+});
+o.each({removeAttr:function(E){o.attr(this,E,"");
+if(this.nodeType==1){this.removeAttribute(E);
+}},addClass:function(E){o.className.add(this,E);
+},removeClass:function(E){o.className.remove(this,E);
+},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F);
+}o.className[E?"add":"remove"](this,F);
+},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);
+o.removeData(this);
+});
+if(this.parentNode){this.parentNode.removeChild(this);
+}}},empty:function(){o(this).children().remove();
+while(this.firstChild){this.removeChild(this.firstChild);
+}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments);
+};
+});
+function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0;
+}var h="jQuery"+e(),v=0,A={};
+o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;
+var H=F[h];
+if(!H){H=F[h]=++v;
+}if(E&&!o.cache[H]){o.cache[H]={};
+}if(G!==g){o.cache[H][E]=G;
+}return E?o.cache[H][E]:H;
+},removeData:function(F,E){F=F==l?A:F;
+var H=F[h];
+if(E){if(o.cache[H]){delete o.cache[H][E];
+E="";
+for(E in o.cache[H]){break;
+}if(!E){o.removeData(F);
+}}}else{try{delete F[h];
+}catch(G){if(F.removeAttribute){F.removeAttribute(h);
+}}delete o.cache[H];
+}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";
+var G=o.data(F,E);
+if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H));
+}else{if(H){G.push(H);
+}}}return G;
+},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();
+if(!G||G==="fx"){F=E[0];
+}if(F!==g){F.call(H);
+}}});
+o.fn.extend({data:function(E,G){var H=E.split(".");
+H[1]=H[1]?"."+H[1]:"";
+if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);
+if(F===g&&this.length){F=o.data(this[0],E);
+}return F===g&&H[1]?this.data(H[0]):F;
+}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G);
+});
+}},removeData:function(E){return this.each(function(){o.removeData(this,E);
+});
+},queue:function(E,F){if(typeof E!=="string"){F=E;
+E="fx";
+}if(F===g){return o.queue(this[0],E);
+}return this.each(function(){var G=o.queue(this,E,F);
+if(E=="fx"&&G.length==1){G[0].call(this);
+}});
+},dequeue:function(E){return this.each(function(){o.dequeue(this,E);
+});
+}});
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;
+var F=function(Y,U,ab,ac){ab=ab||[];
+U=U||document;
+if(U.nodeType!==1&&U.nodeType!==9){return[];
+}if(!Y||typeof Y!=="string"){return ab;
+}var Z=[],W,af,ai,T,ad,V,X=true;
+R.lastIndex=0;
+while((W=R.exec(Y))!==null){Z.push(W[1]);
+if(W[2]){V=RegExp.rightContext;
+break;
+}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U);
+}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);
+while(Z.length){Y=Z.shift();
+if(I.relative[Y]){Y+=Z.shift();
+}af=J(Y,af);
+}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));
+af=F.filter(ae.expr,ae.set);
+if(Z.length>0){ai=E(af);
+}else{X=false;
+}while(Z.length){var ah=Z.pop(),ag=ah;
+if(!I.relative[ah]){ah="";
+}else{ag=Z.pop();
+}if(ag==null){ag=U;
+}I.relative[ah](ai,ag,Q(U));
+}}if(!ai){ai=af;
+}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y);
+}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai);
+}else{if(U.nodeType===1){for(var aa=0;
+ai[aa]!=null;
+aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa]);
+}}}else{for(var aa=0;
+ai[aa]!=null;
+aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa]);
+}}}}}else{E(ai,ab);
+}if(V){F(V,U,ab,ac);
+if(G){hasDuplicate=false;
+ab.sort(G);
+if(hasDuplicate){for(var aa=1;
+aa<ab.length;
+aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1);
+}}}}}return ab;
+};
+F.matches=function(T,U){return F(T,null,null,U);
+};
+F.find=function(aa,T,ab){var Z,X;
+if(!aa){return[];
+}for(var W=0,V=I.order.length;
+W<V;
+W++){var Y=I.order[W],X;
+if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;
+if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");
+Z=I.find[Y](X,T,ab);
+if(Z!=null){aa=aa.replace(I.match[Y],"");
+break;
+}}}}if(!Z){Z=T.getElementsByTagName("*");
+}return{set:Z,expr:aa};
+};
+F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);
+while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;
+T=false;
+if(aa==ai){ai=[];
+}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);
+if(!Y){T=ah=true;
+}else{if(Y===true){continue;
+}}}if(Y){for(var X=0;
+(af=aa[X])!=null;
+X++){if(af){ah=U(af,Y,X,aa);
+var ae=W^!!ah;
+if(ag&&ah!=null){if(ae){T=true;
+}else{aa[X]=false;
+}}else{if(ae){ai.push(af);
+T=true;
+}}}}}if(ah!==g){if(!ag){aa=ai;
+}ad=ad.replace(I.match[ab],"");
+if(!T){return[];
+}break;
+}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad;
+}else{break;
+}}V=ad;
+}return aa;
+};
+var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href");
+}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;
+if(ab&&!Z){T=T.toUpperCase();
+}for(var W=0,V=aa.length,U;
+W<V;
+W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T;
+}}if(Y){F.filter(T,aa,true);
+}},">":function(Z,U,aa){var X=typeof U==="string";
+if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();
+for(var V=0,T=Z.length;
+V<T;
+V++){var Y=Z[V];
+if(Y){var W=Y.parentNode;
+Z[V]=W.nodeName===U?W:false;
+}}}else{for(var V=0,T=Z.length;
+V<T;
+V++){var Y=Z[V];
+if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U;
+}}if(X){F.filter(U,Z,true);
+}}},"":function(W,U,Y){var V=L++,T=S;
+if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();
+T=P;
+}T("parentNode",U,V,W,X,Y);
+},"~":function(W,U,Y){var V=L++,T=S;
+if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();
+T=P;
+}T("previousSibling",U,V,W,X,Y);
+}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);
+return T?[T]:[];
+}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);
+for(var W=0,T=X.length;
+W<T;
+W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W]);
+}}return U.length===0?null:U;
+}},TAG:function(T,U){return U.getElementsByTagName(T[1]);
+}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";
+if(aa){return W;
+}for(var X=0,Y;
+(Y=U[X])!=null;
+X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y);
+}}else{if(V){U[X]=false;
+}}}}return false;
+},ID:function(T){return T[1].replace(/\\/g,"");
+},TAG:function(U,T){for(var V=0;
+T[V]===false;
+V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase();
+},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);
+T[2]=(U[1]+(U[2]||1))-0;
+T[3]=U[3]-0;
+}T[0]=L++;
+return T;
+},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");
+if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W];
+}if(X[2]==="~="){X[4]=" "+X[4]+" ";
+}return X;
+},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U);
+}else{var W=F.filter(X[3],U,V,true^Y);
+if(!V){T.push.apply(T,W);
+}return false;
+}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true;
+}}return X;
+},POS:function(T){T.unshift(true);
+return T;
+}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden";
+},disabled:function(T){return T.disabled===true;
+},checked:function(T){return T.checked===true;
+},selected:function(T){T.parentNode.selectedIndex;
+return T.selected===true;
+},parent:function(T){return !!T.firstChild;
+},empty:function(T){return !T.firstChild;
+},has:function(V,U,T){return !!F(T[3],V).length;
+},header:function(T){return/h\d/i.test(T.nodeName);
+},text:function(T){return"text"===T.type;
+},radio:function(T){return"radio"===T.type;
+},checkbox:function(T){return"checkbox"===T.type;
+},file:function(T){return"file"===T.type;
+},password:function(T){return"password"===T.type;
+},submit:function(T){return"submit"===T.type;
+},image:function(T){return"image"===T.type;
+},reset:function(T){return"reset"===T.type;
+},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON";
+},input:function(T){return/input|select|textarea|button/i.test(T.nodeName);
+}},setFilters:{first:function(U,T){return T===0;
+},last:function(V,U,T,W){return U===W.length-1;
+},even:function(U,T){return T%2===0;
+},odd:function(U,T){return T%2===1;
+},lt:function(V,U,T){return U<T[3]-0;
+},gt:function(V,U,T){return U>T[3]-0;
+},nth:function(V,U,T){return T[3]-0==U;
+},eq:function(V,U,T){return T[3]-0==U;
+}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];
+if(X){return X(Z,W,V,aa);
+}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0;
+}else{if(U==="not"){var Y=V[3];
+for(var W=0,T=Y.length;
+W<T;
+W++){if(Y[W]===Z){return false;
+}}return true;
+}}}},CHILD:function(T,W){var Z=W[1],U=T;
+switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false;
+}}if(Z=="first"){return true;
+}U=T;
+case"last":while(U=U.nextSibling){if(U.nodeType===1){return false;
+}}return true;
+case"nth":var V=W[2],ac=W[3];
+if(V==1&&ac==0){return true;
+}var Y=W[0],ab=T.parentNode;
+if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;
+for(U=ab.firstChild;
+U;
+U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X;
+}}ab.sizcache=Y;
+}var aa=T.nodeIndex-ac;
+if(V==0){return aa==0;
+}else{return(aa%V==0&&aa/V>=0);
+}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T;
+},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T;
+},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1;
+},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];
+return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false;
+},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];
+if(W){return W(X,V,U,Y);
+}}}};
+var M=I.match.POS;
+for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source);
+}var E=function(U,T){U=Array.prototype.slice.call(U);
+if(T){T.push.apply(T,U);
+return T;
+}return U;
+};
+try{Array.prototype.slice.call(document.documentElement.childNodes);
+}catch(N){E=function(X,W){var U=W||[];
+if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X);
+}else{if(typeof X.length==="number"){for(var V=0,T=X.length;
+V<T;
+V++){U.push(X[V]);
+}}else{for(var V=0;
+X[V];
+V++){U.push(X[V]);
+}}}return U;
+};
+}var G;
+if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;
+if(V===0){hasDuplicate=true;
+}return V;
+};
+}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;
+if(V===0){hasDuplicate=true;
+}return V;
+};
+}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();
+V.selectNode(W);
+V.collapse(true);
+T.selectNode(U);
+T.collapse(true);
+var X=V.compareBoundaryPoints(Range.START_TO_END,T);
+if(X===0){hasDuplicate=true;
+}return X;
+};
+}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();
+U.innerHTML="<input name='"+V+"'/>";
+var T=document.documentElement;
+T.insertBefore(U,T.firstChild);
+if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);
+return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[];
+}};
+I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");
+return Y.nodeType===1&&X&&X.nodeValue===W;
+};
+}T.removeChild(U);
+})();
+(function(){var T=document.createElement("div");
+T.appendChild(document.createComment(""));
+if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);
+if(U[1]==="*"){var W=[];
+for(var V=0;
+X[V];
+V++){if(X[V].nodeType===1){W.push(X[V]);
+}}X=W;
+}return X;
+};
+}T.innerHTML="<a href='#'></a>";
+if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2);
+};
+}})();
+if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");
+U.innerHTML="<p class='TEST'></p>";
+if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return ;
+}F=function(Y,X,V,W){X=X||document;
+if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V);
+}catch(Z){}}return T(Y,X,V,W);
+};
+F.find=T.find;
+F.filter=T.filter;
+F.selectors=T.selectors;
+F.matches=T.matches;
+})();
+}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");
+T.innerHTML="<div class='test e'></div><div class='test'></div>";
+if(T.getElementsByClassName("e").length===0){return ;
+}T.lastChild.className="e";
+if(T.getElementsByClassName("e").length===1){return ;
+}I.order.splice(1,0,"CLASS");
+I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1]);
+}};
+})();
+}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;
+for(var W=0,V=ad.length;
+W<V;
+W++){var T=ad[W];
+if(T){if(ab&&T.nodeType===1){T.sizcache=Y;
+T.sizset=W;
+}T=T[U];
+var X=false;
+while(T){if(T.sizcache===Y){X=ad[T.sizset];
+break;
+}if(T.nodeType===1&&!ac){T.sizcache=Y;
+T.sizset=W;
+}if(T.nodeName===Z){X=T;
+break;
+}T=T[U];
+}ad[W]=X;
+}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;
+for(var W=0,V=ad.length;
+W<V;
+W++){var T=ad[W];
+if(T){if(ab&&T.nodeType===1){T.sizcache=Y;
+T.sizset=W;
+}T=T[U];
+var X=false;
+while(T){if(T.sizcache===Y){X=ad[T.sizset];
+break;
+}if(T.nodeType===1){if(!ac){T.sizcache=Y;
+T.sizset=W;
+}if(typeof Z!=="string"){if(T===Z){X=true;
+break;
+}}else{if(F.filter(Z,[T]).length>0){X=T;
+break;
+}}}T=T[U];
+}ad[W]=X;
+}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16;
+}:function(U,T){return U!==T&&(U.contains?U.contains(T):true);
+};
+var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument);
+};
+var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;
+while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];
+T=T.replace(I.match.PSEUDO,"");
+}T=I.relative[T]?T+"*":T;
+for(var Z=0,U=V.length;
+Z<U;
+Z++){F(T,V[Z],W);
+}return F.filter(X,W);
+};
+o.find=F;
+o.filter=F.filter;
+o.expr=F.selectors;
+o.expr[":"]=o.expr.filters;
+F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0;
+};
+F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0;
+};
+F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem;
+}).length;
+};
+o.multiFilter=function(V,T,U){if(U){V=":not("+V+")";
+}return F.matches(V,T);
+};
+o.dir=function(V,U){var T=[],W=V[U];
+while(W&&W!=document){if(W.nodeType==1){T.push(W);
+}W=W[U];
+}return T;
+};
+o.nth=function(X,T,V,W){T=T||1;
+var U=0;
+for(;
+X;
+X=X[V]){if(X.nodeType==1&&++U==T){break;
+}}return X;
+};
+o.sibling=function(V,U){var T=[];
+for(;
+V;
+V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V);
+}}return T;
+};
+return ;
+l.Sizzle=F;
+})();
+o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return ;
+}if(I.setInterval&&I!=l){I=l;
+}if(!H.guid){H.guid=this.guid++;
+}if(K!==g){var G=H;
+H=this.proxy(G);
+H.data=K;
+}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g;
+});
+J.elem=I;
+o.each(F.split(/\s+/),function(M,N){var O=N.split(".");
+N=O.shift();
+H.type=O.slice().sort().join(".");
+var L=E[N];
+if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O);
+}if(!L){L=E[N]={};
+if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false);
+}else{if(I.attachEvent){I.attachEvent("on"+N,J);
+}}}}L[H.guid]=H;
+o.event.global[N]=true;
+});
+I=null;
+},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return ;
+}var G=o.data(K,"events"),F,E;
+if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""));
+}}else{if(H.type){J=H.handler;
+H=H.type;
+}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");
+O=Q.shift();
+var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");
+if(G[O]){if(J){delete G[O][J.guid];
+}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P];
+}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q);
+}for(F in G[O]){break;
+}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false);
+}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"));
+}}}F=null;
+delete G[O];
+}}});
+}for(F in G){break;
+}if(!F){var L=o.data(K,"handle");
+if(L){L.elem=null;
+}o.removeData(K,"events");
+o.removeData(K,"handle");
+}}},trigger:function(I,K,H,E){var G=I.type||I;
+if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);
+if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);
+I.exclusive=true;
+}if(!H){I.stopPropagation();
+if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem);
+}});
+}}if(!H||H.nodeType==3||H.nodeType==8){return g;
+}I.result=g;
+I.target=H;
+K=o.makeArray(K);
+K.unshift(I);
+}I.currentTarget=H;
+var J=o.data(H,"handle");
+if(J){J.apply(H,K);
+}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false;
+}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;
+try{H[G]();
+}catch(L){}}this.triggered=false;
+if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;
+if(F){o.event.trigger(I,K,F,true);
+}}},handle:function(K){var J,E;
+K=arguments[0]=o.event.fix(K||l.event);
+K.currentTarget=this;
+var L=K.type.split(".");
+K.type=L.shift();
+J=!L.length&&!K.exclusive;
+var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");
+E=(o.data(this,"events")||{})[K.type];
+for(var G in E){var H=E[G];
+if(J||I.test(H.type)){K.handler=H;
+K.data=H.data;
+var F=H.apply(this,arguments);
+if(F!==g){K.result=F;
+if(F===false){K.preventDefault();
+K.stopPropagation();
+}}if(K.isImmediatePropagationStopped()){break;
+}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H;
+}var F=H;
+H=o.Event(F);
+for(var G=this.props.length,J;
+G;
+){J=this.props[--G];
+H[J]=F[J];
+}if(!H.target){H.target=H.srcElement||document;
+}if(H.target.nodeType==3){H.target=H.target.parentNode;
+}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement;
+}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;
+H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);
+H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0);
+}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode;
+}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey;
+}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)));
+}return H;
+},proxy:function(F,E){E=E||function(){return F.apply(this,arguments);
+};
+E.guid=F.guid=F.guid||E.guid||this.guid++;
+return E;
+},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c);
+},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");
+o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++;
+}});
+if(E<1){o.event.remove(this,G[0],c);
+}}}}}};
+o.Event=function(E){if(!this.preventDefault){return new o.Event(E);
+}if(E&&E.type){this.originalEvent=E;
+this.type=E.type;
+}else{this.type=E;
+}this.timeStamp=e();
+this[h]=true;
+};
+function k(){return false;
+}function u(){return true;
+}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;
+var E=this.originalEvent;
+if(!E){return ;
+}if(E.preventDefault){E.preventDefault();
+}E.returnValue=false;
+},stopPropagation:function(){this.isPropagationStopped=u;
+var E=this.originalEvent;
+if(!E){return ;
+}if(E.stopPropagation){E.stopPropagation();
+}E.cancelBubble=true;
+},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;
+this.stopPropagation();
+},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};
+var a=function(F){var E=F.relatedTarget;
+while(E&&E!=this){try{E=E.parentNode;
+}catch(G){E=this;
+}}if(E!=this){F.type=F.data;
+o.event.handle.apply(this,arguments);
+}};
+o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E);
+},teardown:function(){o.event.remove(this,F,a);
+}};
+});
+o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G);
+});
+},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);
+return(F||H).apply(this,arguments);
+});
+return this.each(function(){o.event.add(this,G,E,F&&H);
+});
+},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E);
+});
+},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this);
+});
+},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);
+F.preventDefault();
+F.stopPropagation();
+o.event.trigger(F,G,this[0]);
+return F.result;
+}},toggle:function(G){var E=arguments,F=1;
+while(F<E.length){o.event.proxy(G,E[F++]);
+}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;
+H.preventDefault();
+return E[this.lastToggle++].apply(this,arguments)||false;
+}));
+},hover:function(E,F){return this.mouseenter(E).mouseleave(F);
+},ready:function(E){B();
+if(o.isReady){E.call(document,o);
+}else{o.readyList.push(E);
+}return this;
+},live:function(G,F){var E=o.event.proxy(F);
+E.guid+=this.selector+G;
+o(document).bind(i(G,this.selector),this.selector,E);
+return this;
+},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);
+return this;
+}});
+function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];
+o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];
+if(K){F.push({elem:K,fn:J});
+}}});
+F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest");
+});
+o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false);
+}});
+return G;
+}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".");
+}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;
+if(o.readyList){o.each(o.readyList,function(){this.call(document,o);
+});
+o.readyList=null;
+}o(document).triggerHandler("ready");
+}}});
+var x=false;
+function B(){if(x){return ;
+}x=true;
+if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);
+o.ready();
+},false);
+}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);
+o.ready();
+}});
+if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return ;
+}try{document.documentElement.doScroll("left");
+}catch(E){setTimeout(arguments.callee,0);
+return ;
+}o.ready();
+})();
+}}}o.event.add(l,"load",o.ready);
+}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E);
+};
+});
+o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem);
+}}});
+(function(){o.support={};
+var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();
+K.style.display="none";
+K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
+var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];
+if(!H||!H.length||!E){return ;
+}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};
+G.type="text/javascript";
+try{G.appendChild(document.createTextNode("window."+J+"=1;"));
+}catch(I){}F.insertBefore(G,F.firstChild);
+if(l[J]){o.support.scriptEval=true;
+delete l[J];
+}F.removeChild(G);
+if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;
+K.detachEvent("onclick",arguments.callee);
+});
+K.cloneNode(true).fireEvent("onclick");
+}o(function(){var L=document.createElement("div");
+L.style.width=L.style.paddingLeft="1px";
+document.body.appendChild(L);
+o.boxModel=o.support.boxModel=L.offsetWidth===2;
+document.body.removeChild(L).style.display="none";
+});
+})();
+var w=o.support.cssFloat?"cssFloat":"styleFloat";
+o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};
+o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G);
+}var I=G.indexOf(" ");
+if(I>=0){var E=G.slice(I,G.length);
+G=G.slice(0,I);
+}var H="GET";
+if(J){if(o.isFunction(J)){K=J;
+J=null;
+}else{if(typeof J==="object"){J=o.param(J);
+H="POST";
+}}}var F=this;
+o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText);
+}if(K){F.each(K,[M.responseText,L,M]);
+}}});
+return this;
+},serialize:function(){return o.param(this.serializeArray());
+},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this;
+}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type));
+}).map(function(E,F){var G=o(this).val();
+return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I};
+}):{name:F.name,value:G};
+}).get();
+}});
+o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G);
+};
+});
+var r=e();
+o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;
+G=null;
+}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F});
+},getScript:function(E,F){return o.get(E,null,F,"script");
+},getJSON:function(E,F,G){return o.get(E,F,G,"json");
+},post:function(E,G,H,F){if(o.isFunction(G)){H=G;
+G={};
+}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F});
+},ajaxSetup:function(E){o.extend(o.ajaxSettings,E);
+},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();
+},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));
+var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();
+if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data);
+}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?";
+}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?";
+}}M.dataType="json";
+}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;
+if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1");
+}M.url=M.url.replace(F,"="+W+"$1");
+M.dataType="script";
+l[W]=function(X){V=X;
+I();
+L();
+l[W]=g;
+try{delete l[W];
+}catch(Y){}if(H){H.removeChild(T);
+}};
+}if(M.dataType=="script"&&M.cache==null){M.cache=false;
+}if(M.cache===false&&G=="GET"){var E=e();
+var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");
+M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"");
+}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;
+M.data=null;
+}if(M.global&&!o.active++){o.event.trigger("ajaxStart");
+}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);
+if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];
+var T=document.createElement("script");
+T.src=M.url;
+if(M.scriptCharset){T.charset=M.scriptCharset;
+}if(!W){var O=false;
+T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;
+I();
+L();
+T.onload=T.onreadystatechange=null;
+H.removeChild(T);
+}};
+}H.appendChild(T);
+return g;
+}var K=false;
+var J=M.xhr();
+if(M.username){J.open(G,M.url,M.async,M.username,M.password);
+}else{J.open(G,M.url,M.async);
+}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType);
+}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT");
+}J.setRequestHeader("X-Requested-With","XMLHttpRequest");
+J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default);
+}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop");
+}J.abort();
+return false;
+}if(M.global){o.event.trigger("ajaxSend",[J,M]);
+}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);
+P=null;
+if(M.global&&!--o.active){o.event.trigger("ajaxStop");
+}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;
+if(P){clearInterval(P);
+P=null;
+}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";
+if(R=="success"){try{V=o.httpData(J,M.dataType,M);
+}catch(Z){R="parsererror";
+}}if(R=="success"){var Y;
+try{Y=J.getResponseHeader("Last-Modified");
+}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y;
+}if(!W){I();
+}}else{o.handleError(M,J,R);
+}L();
+if(X){J.abort();
+}if(M.async){J=null;
+}}}};
+if(M.async){var P=setInterval(N,13);
+if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout");
+}},M.timeout);
+}}try{J.send(M.data);
+}catch(S){o.handleError(M,J,null,S);
+}if(!M.async){N();
+}function I(){if(M.success){M.success(V,R);
+}if(M.global){o.event.trigger("ajaxSuccess",[J,M]);
+}}function L(){if(M.complete){M.complete(J,R);
+}if(M.global){o.event.trigger("ajaxComplete",[J,M]);
+}if(M.global&&!--o.active){o.event.trigger("ajaxStop");
+}}return J;
+},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G);
+}if(F.global){o.event.trigger("ajaxError",[H,F,G]);
+}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223;
+}catch(E){}return false;
+},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");
+return G.status==304||H==o.lastModified[E];
+}catch(F){}return false;
+},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;
+if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror";
+}if(G&&G.dataFilter){I=G.dataFilter(I,H);
+}if(typeof I==="string"){if(H=="script"){o.globalEval(I);
+}if(H=="json"){I=l["eval"]("("+I+")");
+}}return I;
+},param:function(E){var G=[];
+function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J);
+}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value);
+});
+}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this);
+});
+}else{H(F,o.isFunction(E[F])?E[F]():E[F]);
+}}}return G.join("&").replace(/%20/g,"+");
+}});
+var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];
+function t(F,E){var G={};
+o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F;
+});
+return G;
+}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L);
+}else{for(var H=0,F=this.length;
+H<F;
+H++){var E=o.data(this[H],"olddisplay");
+this[H].style.display=E||"";
+if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;
+if(m[G]){K=m[G];
+}else{var I=o("<"+G+" />").appendTo("body");
+K=I.css("display");
+if(K==="none"){K="block";
+}I.remove();
+m[G]=K;
+}o.data(this[H],"olddisplay",K);
+}}for(var H=0,F=this.length;
+H<F;
+H++){this[H].style.display=o.data(this[H],"olddisplay")||"";
+}return this;
+}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I);
+}else{for(var G=0,F=this.length;
+G<F;
+G++){var E=o.data(this[G],"olddisplay");
+if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"));
+}}for(var G=0,F=this.length;
+G<F;
+G++){this[G].style.display="none";
+}return this;
+}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";
+return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");
+o(this)[H?"show":"hide"]();
+}):this.animate(t("toggle",3),G,F);
+},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F);
+},animate:function(I,F,H,G){var E=o.speed(F,H,G);
+return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;
+for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this);
+}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");
+K.overflow=this.style.overflow;
+}}if(K.overflow!=null){this.style.overflow="hidden";
+}K.curAnim=o.extend({},I);
+o.each(I,function(O,S){var R=new o.fx(J,K,O);
+if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I);
+}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;
+if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";
+if(P!="px"){J.style[O]=(N||1)+P;
+T=((N||1)/R.cur(true))*T;
+J.style[O]=T+P;
+}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T;
+}R.custom(T,N,P);
+}else{R.custom(T,S,"");
+}}});
+return true;
+});
+},stop:function(F,E){var G=o.timers;
+if(F){this.queue([]);
+}this.each(function(){for(var H=G.length-1;
+H>=0;
+H--){if(G[H].elem==this){if(E){G[H](true);
+}G.splice(H,1);
+}}});
+if(!E){this.dequeue();
+}return this;
+}});
+o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H);
+};
+});
+o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};
+E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;
+E.old=E.complete;
+E.complete=function(){if(E.queue!==false){o(this).dequeue();
+}if(o.isFunction(E.old)){E.old.call(this);
+}};
+return E;
+},easing:{linear:function(G,H,E,F){return E+F*G;
+},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E;
+}},timers:[],fx:function(F,E,G){this.options=E;
+this.elem=F;
+this.prop=G;
+if(!E.orig){E.orig={};
+}}});
+o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this);
+}(o.fx.step[this.prop]||o.fx.step._default)(this);
+if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block";
+}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop];
+}var E=parseFloat(o.css(this.elem,this.prop,F));
+return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0;
+},custom:function(I,H,G){this.startTime=e();
+this.start=I;
+this.end=H;
+this.unit=G||this.unit||"px";
+this.now=this.start;
+this.pos=this.state=0;
+var E=this;
+function F(J){return E.step(J);
+}F.elem=this.elem;
+if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;
+for(var J=0;
+J<K.length;
+J++){if(!K[J]()){K.splice(J--,1);
+}}if(!K.length){clearInterval(n);
+n=g;
+}},13);
+}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);
+this.options.show=true;
+this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());
+o(this.elem).show();
+},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);
+this.options.hide=true;
+this.custom(this.cur(),0);
+},step:function(H){var G=e();
+if(H||G>=this.options.duration+this.startTime){this.now=this.end;
+this.pos=this.state=1;
+this.update();
+this.options.curAnim[this.prop]=true;
+var E=true;
+for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false;
+}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;
+this.elem.style.display=this.options.display;
+if(o.css(this.elem,"display")=="none"){this.elem.style.display="block";
+}}if(this.options.hide){o(this.elem).hide();
+}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I]);
+}}this.options.complete.call(this.elem);
+}return false;
+}else{var J=G-this.startTime;
+this.state=J/this.options.duration;
+this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);
+this.now=this.start+((this.end-this.start)*this.pos);
+this.update();
+}return true;
+}};
+o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now);
+},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit;
+}else{E.elem[E.prop]=E.now;
+}}}});
+if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0};
+}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0]);
+}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;
+return{top:I,left:H};
+};
+}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0};
+}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0]);
+}o.offset.initialized||o.offset.initialize();
+var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;
+while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);
+N-=J.scrollTop,I-=J.scrollLeft;
+if(J===G){N+=J.offsetTop,I+=J.offsetLeft;
+if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0;
+}F=G,G=J.offsetParent;
+}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0;
+}E=M;
+}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft;
+}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft);
+}return{top:N,left:I};
+};
+}o.offset={initialize:function(){if(this.initialized){return ;
+}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
+M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};
+for(E in M){F.style[E]=M[E];
+}F.innerHTML=K;
+L.insertBefore(F,L.firstChild);
+H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;
+this.doesNotAddBorder=(G.offsetTop!==5);
+this.doesAddBorderForTableAndCells=(I.offsetTop===5);
+H.style.overflow="hidden",H.style.position="relative";
+this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);
+L.style.marginTop="1px";
+this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);
+L.style.marginTop=J;
+L.removeChild(F);
+this.initialized=true;
+},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();
+var G=E.offsetTop,F=E.offsetLeft;
+if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0;
+}return{top:G,left:F};
+}};
+o.fn.extend({position:function(){var I=0,H=0,F;
+if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();
+J.top-=j(this,"marginTop");
+J.left-=j(this,"marginLeft");
+E.top+=j(G,"borderTopWidth");
+E.left+=j(G,"borderLeftWidth");
+F={top:J.top-E.top,left:J.left-E.left};
+}return F;
+},offsetParent:function(){var E=this[0].offsetParent||document.body;
+while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent;
+}return o(E);
+}});
+o.each(["Left","Top"],function(F,E){var G="scroll"+E;
+o.fn[G]=function(H){if(!this[0]){return null;
+}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H;
+}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G];
+};
+});
+o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();
+o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null;
+};
+o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null;
+};
+var J=G.toLowerCase();
+o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px");
+};
+});
+})();
+}
+
+/* platform.js */
+SimileAjax.version="2.2.1";
+SimileAjax.jQuery=jQuery.noConflict(true);
+if(typeof window["$"]=="undefined"){window.$=SimileAjax.jQuery;
+}SimileAjax.Platform.os={isMac:false,isWin:false,isWin32:false,isUnix:false};
+SimileAjax.Platform.browser={isIE:false,isNetscape:false,isMozilla:false,isFirefox:false,isOpera:false,isSafari:false,majorVersion:0,minorVersion:0};
+(function(){var an=navigator.appName.toLowerCase();
+var ua=navigator.userAgent.toLowerCase();
+SimileAjax.Platform.os.isMac=(ua.indexOf("mac")!=-1);
+SimileAjax.Platform.os.isWin=(ua.indexOf("win")!=-1);
+SimileAjax.Platform.os.isWin32=SimileAjax.Platform.isWin&&(ua.indexOf("95")!=-1||ua.indexOf("98")!=-1||ua.indexOf("nt")!=-1||ua.indexOf("win32")!=-1||ua.indexOf("32bit")!=-1);
+SimileAjax.Platform.os.isUnix=(ua.indexOf("x11")!=-1);
+SimileAjax.Platform.browser.isIE=(an.indexOf("microsoft")!=-1);
+SimileAjax.Platform.browser.isNetscape=(an.indexOf("netscape")!=-1);
+SimileAjax.Platform.browser.isMozilla=(ua.indexOf("mozilla")!=-1);
+SimileAjax.Platform.browser.isFirefox=(ua.indexOf("firefox")!=-1);
+SimileAjax.Platform.browser.isOpera=(an.indexOf("opera")!=-1);
+SimileAjax.Platform.browser.isSafari=(an.indexOf("safari")!=-1);
+var parseVersionString=function(s){var a=s.split(".");
+SimileAjax.Platform.browser.majorVersion=parseInt(a[0]);
+SimileAjax.Platform.browser.minorVersion=parseInt(a[1]);
+};
+var indexOf=function(s,sub,start){var i=s.indexOf(sub,start);
+return i>=0?i:s.length;
+};
+if(SimileAjax.Platform.browser.isMozilla){var offset=ua.indexOf("mozilla/");
+if(offset>=0){parseVersionString(ua.substring(offset+8,indexOf(ua," ",offset)));
+}}if(SimileAjax.Platform.browser.isIE){var offset=ua.indexOf("msie ");
+if(offset>=0){parseVersionString(ua.substring(offset+5,indexOf(ua,";",offset)));
+}}if(SimileAjax.Platform.browser.isNetscape){var offset=ua.indexOf("rv:");
+if(offset>=0){parseVersionString(ua.substring(offset+3,indexOf(ua,")",offset)));
+}}if(SimileAjax.Platform.browser.isFirefox){var offset=ua.indexOf("firefox/");
+if(offset>=0){parseVersionString(ua.substring(offset+8,indexOf(ua," ",offset)));
+}}if(!("localeCompare" in String.prototype)){String.prototype.localeCompare=function(s){if(this<s){return -1;
+}else{if(this>s){return 1;
+}else{return 0;
+}}};
+}})();
+SimileAjax.Platform.getDefaultLocale=function(){return SimileAjax.Platform.clientLocale;
+};
+
+
+/* ajax.js */
+SimileAjax.ListenerQueue=function(wildcardHandlerName){this._listeners=[];
+this._wildcardHandlerName=wildcardHandlerName;
+};
+SimileAjax.ListenerQueue.prototype.add=function(listener){this._listeners.push(listener);
+};
+SimileAjax.ListenerQueue.prototype.remove=function(listener){var listeners=this._listeners;
+for(var i=0;
+i<listeners.length;
+i++){if(listeners[i]==listener){listeners.splice(i,1);
+break;
+}}};
+SimileAjax.ListenerQueue.prototype.fire=function(handlerName,args){var listeners=[].concat(this._listeners);
+for(var i=0;
+i<listeners.length;
+i++){var listener=listeners[i];
+if(handlerName in listener){try{listener[handlerName].apply(listener,args);
+}catch(e){SimileAjax.Debug.exception("Error firing event of name "+handlerName,e);
+}}else{if(this._wildcardHandlerName!=null&&this._wildcardHandlerName in listener){try{listener[this._wildcardHandlerName].apply(listener,[handlerName]);
+}catch(e){SimileAjax.Debug.exception("Error firing event of name "+handlerName+" to wildcard handler",e);
+}}}}};
+
+
+/* data-structure.js */
+SimileAjax.Set=function(a){this._hash={};
+this._count=0;
+if(a instanceof Array){for(var i=0;
+i<a.length;
+i++){this.add(a[i]);
+}}else{if(a instanceof SimileAjax.Set){this.addSet(a);
+}}};
+SimileAjax.Set.prototype.add=function(o){if(!(o in this._hash)){this._hash[o]=true;
+this._count++;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.addSet=function(set){for(var o in set._hash){this.add(o);
+}};
+SimileAjax.Set.prototype.remove=function(o){if(o in this._hash){delete this._hash[o];
+this._count--;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.removeSet=function(set){for(var o in set._hash){this.remove(o);
+}};
+SimileAjax.Set.prototype.retainSet=function(set){for(var o in this._hash){if(!set.contains(o)){delete this._hash[o];
+this._count--;
+}}};
+SimileAjax.Set.prototype.contains=function(o){return(o in this._hash);
+};
+SimileAjax.Set.prototype.size=function(){return this._count;
+};
+SimileAjax.Set.prototype.toArray=function(){var a=[];
+for(var o in this._hash){a.push(o);
+}return a;
+};
+SimileAjax.Set.prototype.visit=function(f){for(var o in this._hash){if(f(o)==true){break;
+}}};
+SimileAjax.SortedArray=function(compare,initialArray){this._a=(initialArray instanceof Array)?initialArray:[];
+this._compare=compare;
+};
+SimileAjax.SortedArray.prototype.add=function(elmt){var sa=this;
+var index=this.find(function(elmt2){return sa._compare(elmt2,elmt);
+});
+if(index<this._a.length){this._a.splice(index,0,elmt);
+}else{this._a.push(elmt);
+}};
+SimileAjax.SortedArray.prototype.remove=function(elmt){var sa=this;
+var index=this.find(function(elmt2){return sa._compare(elmt2,elmt);
+});
+while(index<this._a.length&&this._compare(this._a[index],elmt)==0){if(this._a[index]==elmt){this._a.splice(index,1);
+return true;
+}else{index++;
+}}return false;
+};
+SimileAjax.SortedArray.prototype.removeAll=function(){this._a=[];
+};
+SimileAjax.SortedArray.prototype.elementAt=function(index){return this._a[index];
+};
+SimileAjax.SortedArray.prototype.length=function(){return this._a.length;
+};
+SimileAjax.SortedArray.prototype.find=function(compare){var a=0;
+var b=this._a.length;
+while(a<b){var mid=Math.floor((a+b)/2);
+var c=compare(this._a[mid]);
+if(mid==a){return c<0?a+1:a;
+}else{if(c<0){a=mid;
+}else{b=mid;
+}}}return a;
+};
+SimileAjax.SortedArray.prototype.getFirst=function(){return(this._a.length>0)?this._a[0]:null;
+};
+SimileAjax.SortedArray.prototype.getLast=function(){return(this._a.length>0)?this._a[this._a.length-1]:null;
+};
+SimileAjax.EventIndex=function(unit){var eventIndex=this;
+this._unit=(unit!=null)?unit:SimileAjax.NativeDateUnit;
+this._events=new SimileAjax.SortedArray(function(event1,event2){return eventIndex._unit.compare(event1.getStart(),event2.getStart());
+});
+this._idToEvent={};
+this._indexed=true;
+};
+SimileAjax.EventIndex.prototype.getUnit=function(){return this._unit;
+};
+SimileAjax.EventIndex.prototype.getEvent=function(id){return this._idToEvent[id];
+};
+SimileAjax.EventIndex.prototype.add=function(evt){this._events.add(evt);
+this._idToEvent[evt.getID()]=evt;
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.removeAll=function(){this._events.removeAll();
+this._idToEvent={};
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.getCount=function(){return this._events.length();
+};
+SimileAjax.EventIndex.prototype.getIterator=function(startDate,endDate){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._Iterator(this._events,startDate,endDate,this._unit);
+};
+SimileAjax.EventIndex.prototype.getReverseIterator=function(startDate,endDate){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._ReverseIterator(this._events,startDate,endDate,this._unit);
+};
+SimileAjax.EventIndex.prototype.getAllIterator=function(){return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+SimileAjax.EventIndex.prototype.getEarliestDate=function(){var evt=this._events.getFirst();
+return(evt==null)?null:evt.getStart();
+};
+SimileAjax.EventIndex.prototype.getLatestDate=function(){var evt=this._events.getLast();
+if(evt==null){return null;
+}if(!this._indexed){this._index();
+}var index=evt._earliestOverlapIndex;
+var date=this._events.elementAt(index).getEnd();
+for(var i=index+1;
+i<this._events.length();
+i++){date=this._unit.later(date,this._events.elementAt(i).getEnd());
+}return date;
+};
+SimileAjax.EventIndex.prototype._index=function(){var l=this._events.length();
+for(var i=0;
+i<l;
+i++){var evt=this._events.elementAt(i);
+evt._earliestOverlapIndex=i;
+}var toIndex=1;
+for(var i=0;
+i<l;
+i++){var evt=this._events.elementAt(i);
+var end=evt.getEnd();
+toIndex=Math.max(toIndex,i+1);
+while(toIndex<l){var evt2=this._events.elementAt(toIndex);
+var start2=evt2.getStart();
+if(this._unit.compare(start2,end)<0){evt2._earliestOverlapIndex=i;
+toIndex++;
+}else{break;
+}}}this._indexed=true;
+};
+SimileAjax.EventIndex._Iterator=function(events,startDate,endDate,unit){this._events=events;
+this._startDate=startDate;
+this._endDate=endDate;
+this._unit=unit;
+this._currentIndex=events.find(function(evt){return unit.compare(evt.getStart(),startDate);
+});
+if(this._currentIndex-1>=0){this._currentIndex=this._events.elementAt(this._currentIndex-1)._earliestOverlapIndex;
+}this._currentIndex--;
+this._maxIndex=events.find(function(evt){return unit.compare(evt.getStart(),endDate);
+});
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._Iterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var next=this._next;
+this._findNext();
+return next;
+}else{return null;
+}},_findNext:function(){var unit=this._unit;
+while((++this._currentIndex)<this._maxIndex){var evt=this._events.elementAt(this._currentIndex);
+if(unit.compare(evt.getStart(),this._endDate)<0&&unit.compare(evt.getEnd(),this._startDate)>0){this._next=evt;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._ReverseIterator=function(events,startDate,endDate,unit){this._events=events;
+this._startDate=startDate;
+this._endDate=endDate;
+this._unit=unit;
+this._minIndex=events.find(function(evt){return unit.compare(evt.getStart(),startDate);
+});
+if(this._minIndex-1>=0){this._minIndex=this._events.elementAt(this._minIndex-1)._earliestOverlapIndex;
+}this._maxIndex=events.find(function(evt){return unit.compare(evt.getStart(),endDate);
+});
+this._currentIndex=this._maxIndex;
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._ReverseIterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var next=this._next;
+this._findNext();
+return next;
+}else{return null;
+}},_findNext:function(){var unit=this._unit;
+while((--this._currentIndex)>=this._minIndex){var evt=this._events.elementAt(this._currentIndex);
+if(unit.compare(evt.getStart(),this._endDate)<0&&unit.compare(evt.getEnd(),this._startDate)>0){this._next=evt;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._AllIterator=function(events){this._events=events;
+this._index=0;
+};
+SimileAjax.EventIndex._AllIterator.prototype={hasNext:function(){return this._index<this._events.length();
+},next:function(){return this._index<this._events.length()?this._events.elementAt(this._index++):null;
+}};
+
+
+/* date-time.js */
+SimileAjax.DateTime=new Object();
+SimileAjax.DateTime.MILLISECOND=0;
+SimileAjax.DateTime.SECOND=1;
+SimileAjax.DateTime.MINUTE=2;
+SimileAjax.DateTime.HOUR=3;
+SimileAjax.DateTime.DAY=4;
+SimileAjax.DateTime.WEEK=5;
+SimileAjax.DateTime.MONTH=6;
+SimileAjax.DateTime.YEAR=7;
+SimileAjax.DateTime.DECADE=8;
+SimileAjax.DateTime.CENTURY=9;
+SimileAjax.DateTime.MILLENNIUM=10;
+SimileAjax.DateTime.EPOCH=-1;
+SimileAjax.DateTime.ERA=-2;
+SimileAjax.DateTime.gregorianUnitLengths=[];
+(function(){var d=SimileAjax.DateTime;
+var a=d.gregorianUnitLengths;
+a[d.MILLISECOND]=1;
+a[d.SECOND]=1000;
+a[d.MINUTE]=a[d.SECOND]*60;
+a[d.HOUR]=a[d.MINUTE]*60;
+a[d.DAY]=a[d.HOUR]*24;
+a[d.WEEK]=a[d.DAY]*7;
+a[d.MONTH]=a[d.DAY]*31;
+a[d.YEAR]=a[d.DAY]*365;
+a[d.DECADE]=a[d.YEAR]*10;
+a[d.CENTURY]=a[d.YEAR]*100;
+a[d.MILLENNIUM]=a[d.YEAR]*1000;
+})();
+SimileAjax.DateTime._dateRegexp=new RegExp("^(-?)([0-9]{4})("+["(-?([0-9]{2})(-?([0-9]{2}))?)","(-?([0-9]{3}))","(-?W([0-9]{2})(-?([1-7]))?)"].join("|")+")?$");
+SimileAjax.DateTime._timezoneRegexp=new RegExp("Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$");
+SimileAjax.DateTime._timeRegexp=new RegExp("^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$");
+SimileAjax.DateTime.setIso8601Date=function(dateObject,string){var d=string.match(SimileAjax.DateTime._dateRegexp);
+if(!d){throw new Error("Invalid date string: "+string);
+}var sign=(d[1]=="-")?-1:1;
+var year=sign*d[2];
+var month=d[5];
+var date=d[7];
+var dayofyear=d[9];
+var week=d[11];
+var dayofweek=(d[13])?d[13]:1;
+dateObject.setUTCFullYear(year);
+if(dayofyear){dateObject.setUTCMonth(0);
+dateObject.setUTCDate(Number(dayofyear));
+}else{if(week){dateObject.setUTCMonth(0);
+dateObject.setUTCDate(1);
+var gd=dateObject.getUTCDay();
+var day=(gd)?gd:7;
+var offset=Number(dayofweek)+(7*Number(week));
+if(day<=4){dateObject.setUTCDate(offset+1-day);
+}else{dateObject.setUTCDate(offset+8-day);
+}}else{if(month){dateObject.setUTCDate(1);
+dateObject.setUTCMonth(month-1);
+}if(date){dateObject.setUTCDate(date);
+}}}return dateObject;
+};
+SimileAjax.DateTime.setIso8601Time=function(dateObject,string){var d=string.match(SimileAjax.DateTime._timeRegexp);
+if(!d){SimileAjax.Debug.warn("Invalid time string: "+string);
+return false;
+}var hours=d[1];
+var mins=Number((d[3])?d[3]:0);
+var secs=(d[5])?d[5]:0;
+var ms=d[7]?(Number("0."+d[7])*1000):0;
+dateObject.setUTCHours(hours);
+dateObject.setUTCMinutes(mins);
+dateObject.setUTCSeconds(secs);
+dateObject.setUTCMilliseconds(ms);
+return dateObject;
+};
+SimileAjax.DateTime.timezoneOffset=new Date().getTimezoneOffset();
+SimileAjax.DateTime.setIso8601=function(dateObject,string){var offset=null;
+var comps=(string.indexOf("T")==-1)?string.split(" "):string.split("T");
+SimileAjax.DateTime.setIso8601Date(dateObject,comps[0]);
+if(comps.length==2){var d=comps[1].match(SimileAjax.DateTime._timezoneRegexp);
+if(d){if(d[0]=="Z"){offset=0;
+}else{offset=(Number(d[3])*60)+Number(d[5]);
+offset*=((d[2]=="-")?1:-1);
+}comps[1]=comps[1].substr(0,comps[1].length-d[0].length);
+}SimileAjax.DateTime.setIso8601Time(dateObject,comps[1]);
+}if(offset==null){offset=dateObject.getTimezoneOffset();
+}dateObject.setTime(dateObject.getTime()+offset*60000);
+return dateObject;
+};
+SimileAjax.DateTime.parseIso8601DateTime=function(string){try{return SimileAjax.DateTime.setIso8601(new Date(0),string);
+}catch(e){return null;
+}};
+SimileAjax.DateTime.parseGregorianDateTime=function(o){if(o==null){return null;
+}else{if(o instanceof Date){return o;
+}}var s=o.toString();
+if(s.length>0&&s.length<8){var space=s.indexOf(" ");
+if(space>0){var year=parseInt(s.substr(0,space));
+var suffix=s.substr(space+1);
+if(suffix.toLowerCase()=="bc"){year=1-year;
+}}else{var year=parseInt(s);
+}var d=new Date(0);
+d.setUTCFullYear(year);
+return d;
+}try{return new Date(Date.parse(s));
+}catch(e){return null;
+}};
+SimileAjax.DateTime.roundDownToInterval=function(date,intervalUnit,timeZone,multiple,firstDayOfWeek){var timeShift=timeZone*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var date2=new Date(date.getTime()+timeShift);
+var clearInDay=function(d){d.setUTCMilliseconds(0);
+d.setUTCSeconds(0);
+d.setUTCMinutes(0);
+d.setUTCHours(0);
+};
+var clearInYear=function(d){clearInDay(d);
+d.setUTCDate(1);
+d.setUTCMonth(0);
+};
+switch(intervalUnit){case SimileAjax.DateTime.MILLISECOND:var x=date2.getUTCMilliseconds();
+date2.setUTCMilliseconds(x-(x%multiple));
+break;
+case SimileAjax.DateTime.SECOND:date2.setUTCMilliseconds(0);
+var x=date2.getUTCSeconds();
+date2.setUTCSeconds(x-(x%multiple));
+break;
+case SimileAjax.DateTime.MINUTE:date2.setUTCMilliseconds(0);
+date2.setUTCSeconds(0);
+var x=date2.getUTCMinutes();
+date2.setTime(date2.getTime()-(x%multiple)*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:date2.setUTCMilliseconds(0);
+date2.setUTCSeconds(0);
+date2.setUTCMinutes(0);
+var x=date2.getUTCHours();
+date2.setUTCHours(x-(x%multiple));
+break;
+case SimileAjax.DateTime.DAY:clearInDay(date2);
+break;
+case SimileAjax.DateTime.WEEK:clearInDay(date2);
+var d=(date2.getUTCDay()+7-firstDayOfWeek)%7;
+date2.setTime(date2.getTime()-d*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+break;
+case SimileAjax.DateTime.MONTH:clearInDay(date2);
+date2.setUTCDate(1);
+var x=date2.getUTCMonth();
+date2.setUTCMonth(x-(x%multiple));
+break;
+case SimileAjax.DateTime.YEAR:clearInYear(date2);
+var x=date2.getUTCFullYear();
+date2.setUTCFullYear(x-(x%multiple));
+break;
+case SimileAjax.DateTime.DECADE:clearInYear(date2);
+date2.setUTCFullYear(Math.floor(date2.getUTCFullYear()/10)*10);
+break;
+case SimileAjax.DateTime.CENTURY:clearInYear(date2);
+date2.setUTCFullYear(Math.floor(date2.getUTCFullYear()/100)*100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:clearInYear(date2);
+date2.setUTCFullYear(Math.floor(date2.getUTCFullYear()/1000)*1000);
+break;
+}date.setTime(date2.getTime()-timeShift);
+};
+SimileAjax.DateTime.roundUpToInterval=function(date,intervalUnit,timeZone,multiple,firstDayOfWeek){var originalTime=date.getTime();
+SimileAjax.DateTime.roundDownToInterval(date,intervalUnit,timeZone,multiple,firstDayOfWeek);
+if(date.getTime()<originalTime){date.setTime(date.getTime()+SimileAjax.DateTime.gregorianUnitLengths[intervalUnit]*multiple);
+}};
+SimileAjax.DateTime.incrementByInterval=function(date,intervalUnit,timeZone){timeZone=(typeof timeZone=="undefined")?0:timeZone;
+var timeShift=timeZone*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var date2=new Date(date.getTime()+timeShift);
+switch(intervalUnit){case SimileAjax.DateTime.MILLISECOND:date2.setTime(date2.getTime()+1);
+break;
+case SimileAjax.DateTime.SECOND:date2.setTime(date2.getTime()+1000);
+break;
+case SimileAjax.DateTime.MINUTE:date2.setTime(date2.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:date2.setTime(date2.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+break;
+case SimileAjax.DateTime.DAY:date2.setUTCDate(date2.getUTCDate()+1);
+break;
+case SimileAjax.DateTime.WEEK:date2.setUTCDate(date2.getUTCDate()+7);
+break;
+case SimileAjax.DateTime.MONTH:date2.setUTCMonth(date2.getUTCMonth()+1);
+break;
+case SimileAjax.DateTime.YEAR:date2.setUTCFullYear(date2.getUTCFullYear()+1);
+break;
+case SimileAjax.DateTime.DECADE:date2.setUTCFullYear(date2.getUTCFullYear()+10);
+break;
+case SimileAjax.DateTime.CENTURY:date2.setUTCFullYear(date2.getUTCFullYear()+100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:date2.setUTCFullYear(date2.getUTCFullYear()+1000);
+break;
+}date.setTime(date2.getTime()-timeShift);
+};
+SimileAjax.DateTime.removeTimeZoneOffset=function(date,timeZone){return new Date(date.getTime()+timeZone*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+SimileAjax.DateTime.getTimezone=function(){var d=new Date().getTimezoneOffset();
+return d/-60;
+};
+
+
+/* debug.js */
+SimileAjax.Debug={silent:false};
+SimileAjax.Debug.log=function(msg){var f;
+if("console" in window&&"log" in window.console){f=function(msg2){console.log(msg2);
+};
+}else{f=function(msg2){if(!SimileAjax.Debug.silent){alert(msg2);
+}};
+}SimileAjax.Debug.log=f;
+f(msg);
+};
+SimileAjax.Debug.warn=function(msg){var f;
+if("console" in window&&"warn" in window.console){f=function(msg2){console.warn(msg2);
+};
+}else{f=function(msg2){if(!SimileAjax.Debug.silent){alert(msg2);
+}};
+}SimileAjax.Debug.warn=f;
+f(msg);
+};
+SimileAjax.Debug.exception=function(e,msg){var f,params=SimileAjax.parseURLParameters();
+if(params.errors=="throw"||SimileAjax.params.errors=="throw"){f=function(e2,msg2){throw (e2);
+};
+}else{if("console" in window&&"error" in window.console){f=function(e2,msg2){if(msg2!=null){console.error(msg2+" %o",e2);
+}else{console.error(e2);
+}throw (e2);
+};
+}else{f=function(e2,msg2){if(!SimileAjax.Debug.silent){alert("Caught exception: "+msg2+"\n\nDetails: "+("description" in e2?e2.description:e2));
+}throw (e2);
+};
+}}SimileAjax.Debug.exception=f;
+f(e,msg);
+};
+SimileAjax.Debug.objectToString=function(o){return SimileAjax.Debug._objectToString(o,"");
+};
+SimileAjax.Debug._objectToString=function(o,indent){var indent2=indent+" ";
+if(typeof o=="object"){var s="{";
+for(n in o){s+=indent2+n+": "+SimileAjax.Debug._objectToString(o[n],indent2)+"\n";
+}s+=indent+"}";
+return s;
+}else{if(typeof o=="array"){var s="[";
+for(var n=0;
+n<o.length;
+n++){s+=SimileAjax.Debug._objectToString(o[n],indent2)+"\n";
+}s+=indent+"]";
+return s;
+}else{return o;
+}}};
+
+
+/* dom.js */
+SimileAjax.DOM=new Object();
+SimileAjax.DOM.registerEventWithObject=function(elmt,eventName,obj,handlerName){SimileAjax.DOM.registerEvent(elmt,eventName,function(elmt2,evt,target){return obj[handlerName].call(obj,elmt2,evt,target);
+});
+};
+SimileAjax.DOM.registerEvent=function(elmt,eventName,handler){var handler2=function(evt){evt=(evt)?evt:((event)?event:null);
+if(evt){var target=(evt.target)?evt.target:((evt.srcElement)?evt.srcElement:null);
+if(target){target=(target.nodeType==1||target.nodeType==9)?target:target.parentNode;
+}return handler(elmt,evt,target);
+}return true;
+};
+if(SimileAjax.Platform.browser.isIE){elmt.attachEvent("on"+eventName,handler2);
+}else{elmt.addEventListener(eventName,handler2,false);
+}};
+SimileAjax.DOM.getPageCoordinates=function(elmt){var left=0;
+var top=0;
+if(elmt.nodeType!=1){elmt=elmt.parentNode;
+}var elmt2=elmt;
+while(elmt2!=null){left+=elmt2.offsetLeft;
+top+=elmt2.offsetTop;
+elmt2=elmt2.offsetParent;
+}var body=document.body;
+while(elmt!=null&&elmt!=body){if("scrollLeft" in elmt){left-=elmt.scrollLeft;
+top-=elmt.scrollTop;
+}elmt=elmt.parentNode;
+}return{left:left,top:top};
+};
+SimileAjax.DOM.getSize=function(elmt){var w=this.getStyle(elmt,"width");
+var h=this.getStyle(elmt,"height");
+if(w.indexOf("px")>-1){w=w.replace("px","");
+}if(h.indexOf("px")>-1){h=h.replace("px","");
+}return{w:w,h:h};
+};
+SimileAjax.DOM.getStyle=function(elmt,styleProp){if(elmt.currentStyle){var style=elmt.currentStyle[styleProp];
+}else{if(window.getComputedStyle){var style=document.defaultView.getComputedStyle(elmt,null).getPropertyValue(styleProp);
+}else{var style="";
+}}return style;
+};
+SimileAjax.DOM.getEventRelativeCoordinates=function(evt,elmt){if(SimileAjax.Platform.browser.isIE){if(evt.type=="mousewheel"){var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+return{x:evt.clientX-coords.left,y:evt.clientY-coords.top};
+}else{return{x:evt.offsetX,y:evt.offsetY};
+}}else{var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+if((evt.type=="DOMMouseScroll")&&SimileAjax.Platform.browser.isFirefox&&(SimileAjax.Platform.browser.majorVersion==2)){return{x:evt.screenX-coords.left,y:evt.screenY-coords.top};
+}else{return{x:evt.pageX-coords.left,y:evt.pageY-coords.top};
+}}};
+SimileAjax.DOM.getEventPageCoordinates=function(evt){if(SimileAjax.Platform.browser.isIE){return{x:evt.clientX+document.body.scrollLeft,y:evt.clientY+document.body.scrollTop};
+}else{return{x:evt.pageX,y:evt.pageY};
+}};
+SimileAjax.DOM.hittest=function(x,y,except){return SimileAjax.DOM._hittest(document.body,x,y,except);
+};
+SimileAjax.DOM._hittest=function(elmt,x,y,except){var childNodes=elmt.childNodes;
+outer:for(var i=0;
+i<childNodes.length;
+i++){var childNode=childNodes[i];
+for(var j=0;
+j<except.length;
+j++){if(childNode==except[j]){continue outer;
+}}if(childNode.offsetWidth==0&&childNode.offsetHeight==0){var hitNode=SimileAjax.DOM._hittest(childNode,x,y,except);
+if(hitNode!=childNode){return hitNode;
+}}else{var top=0;
+var left=0;
+var node=childNode;
+while(node){top+=node.offsetTop;
+left+=node.offsetLeft;
+node=node.offsetParent;
+}if(left<=x&&top<=y&&(x-left)<childNode.offsetWidth&&(y-top)<childNode.offsetHeight){return SimileAjax.DOM._hittest(childNode,x,y,except);
+}else{if(childNode.nodeType==1&&childNode.tagName=="TR"){var childNode2=SimileAjax.DOM._hittest(childNode,x,y,except);
+if(childNode2!=childNode){return childNode2;
+}}}}}return elmt;
+};
+SimileAjax.DOM.cancelEvent=function(evt){evt.returnValue=false;
+evt.cancelBubble=true;
+if("preventDefault" in evt){evt.preventDefault();
+}};
+SimileAjax.DOM.appendClassName=function(elmt,className){var classes=elmt.className.split(" ");
+for(var i=0;
+i<classes.length;
+i++){if(classes[i]==className){return ;
+}}classes.push(className);
+elmt.className=classes.join(" ");
+};
+SimileAjax.DOM.createInputElement=function(type){var div=document.createElement("div");
+div.innerHTML="<input type='"+type+"' />";
+return div.firstChild;
+};
+SimileAjax.DOM.createDOMFromTemplate=function(template){var result={};
+result.elmt=SimileAjax.DOM._createDOMFromTemplate(template,result,null);
+return result;
+};
+SimileAjax.DOM._createDOMFromTemplate=function(templateNode,result,parentElmt){if(templateNode==null){return null;
+}else{if(typeof templateNode!="object"){var node=document.createTextNode(templateNode);
+if(parentElmt!=null){parentElmt.appendChild(node);
+}return node;
+}else{var elmt=null;
+if("tag" in templateNode){var tag=templateNode.tag;
+if(parentElmt!=null){if(tag=="tr"){elmt=parentElmt.insertRow(parentElmt.rows.length);
+}else{if(tag=="td"){elmt=parentElmt.insertCell(parentElmt.cells.length);
+}}}if(elmt==null){elmt=tag=="input"?SimileAjax.DOM.createInputElement(templateNode.type):document.createElement(tag);
+if(parentElmt!=null){parentElmt.appendChild(elmt);
+}}}else{elmt=templateNode.elmt;
+if(parentElmt!=null){parentElmt.appendChild(elmt);
+}}for(var attribute in templateNode){var value=templateNode[attribute];
+if(attribute=="field"){result[value]=elmt;
+}else{if(attribute=="className"){elmt.className=value;
+}else{if(attribute=="id"){elmt.id=value;
+}else{if(attribute=="title"){elmt.title=value;
+}else{if(attribute=="type"&&elmt.tagName=="input"){}else{if(attribute=="style"){for(n in value){var v=value[n];
+if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
+}elmt.style[n]=v;
+}}else{if(attribute=="children"){for(var i=0;
+i<value.length;
+i++){SimileAjax.DOM._createDOMFromTemplate(value[i],result,elmt);
+}}else{if(attribute!="tag"&&attribute!="elmt"){elmt.setAttribute(attribute,value);
+}}}}}}}}}return elmt;
+}}};
+SimileAjax.DOM._cachedParent=null;
+SimileAjax.DOM.createElementFromString=function(s){if(SimileAjax.DOM._cachedParent==null){SimileAjax.DOM._cachedParent=document.createElement("div");
+}SimileAjax.DOM._cachedParent.innerHTML=s;
+return SimileAjax.DOM._cachedParent.firstChild;
+};
+SimileAjax.DOM.createDOMFromString=function(root,s,fieldElmts){var elmt=typeof root=="string"?document.createElement(root):root;
+elmt.innerHTML=s;
+var dom={elmt:elmt};
+SimileAjax.DOM._processDOMChildrenConstructedFromString(dom,elmt,fieldElmts!=null?fieldElmts:{});
+return dom;
+};
+SimileAjax.DOM._processDOMConstructedFromString=function(dom,elmt,fieldElmts){var id=elmt.id;
+if(id!=null&&id.length>0){elmt.removeAttribute("id");
+if(id in fieldElmts){var parentElmt=elmt.parentNode;
+parentElmt.insertBefore(fieldElmts[id],elmt);
+parentElmt.removeChild(elmt);
+dom[id]=fieldElmts[id];
+return ;
+}else{dom[id]=elmt;
+}}if(elmt.hasChildNodes()){SimileAjax.DOM._processDOMChildrenConstructedFromString(dom,elmt,fieldElmts);
+}};
+SimileAjax.DOM._processDOMChildrenConstructedFromString=function(dom,elmt,fieldElmts){var node=elmt.firstChild;
+while(node!=null){var node2=node.nextSibling;
+if(node.nodeType==1){SimileAjax.DOM._processDOMConstructedFromString(dom,node,fieldElmts);
+}node=node2;
+}};
+
+
+/* graphics.js */
+SimileAjax.Graphics=new Object();
+SimileAjax.Graphics.pngIsTranslucent=(!SimileAjax.Platform.browser.isIE)||(SimileAjax.Platform.browser.majorVersion>6);
+if(!SimileAjax.Graphics.pngIsTranslucent){SimileAjax.includeCssFile(document,SimileAjax.urlPrefix+"styles/graphics-ie6.css");
+}SimileAjax.Graphics._createTranslucentImage1=function(url,verticalAlign){var elmt=document.createElement("img");
+elmt.setAttribute("src",url);
+if(verticalAlign!=null){elmt.style.verticalAlign=verticalAlign;
+}return elmt;
+};
+SimileAjax.Graphics._createTranslucentImage2=function(url,verticalAlign){var elmt=document.createElement("img");
+elmt.style.width="1px";
+elmt.style.height="1px";
+elmt.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='image')";
+elmt.style.verticalAlign=(verticalAlign!=null)?verticalAlign:"middle";
+return elmt;
+};
+SimileAjax.Graphics.createTranslucentImage=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImage1:SimileAjax.Graphics._createTranslucentImage2;
+SimileAjax.Graphics._createTranslucentImageHTML1=function(url,verticalAlign){return'<img src="'+url+'"'+(verticalAlign!=null?' style="vertical-align: '+verticalAlign+';"':"")+" />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2=function(url,verticalAlign){var style="width: 1px; height: 1px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='image');"+(verticalAlign!=null?" vertical-align: "+verticalAlign+";":"");
+return"<img src='"+url+"' style=\""+style+'" />';
+};
+SimileAjax.Graphics.createTranslucentImageHTML=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImageHTML1:SimileAjax.Graphics._createTranslucentImageHTML2;
+SimileAjax.Graphics.setOpacity=function(elmt,opacity){if(SimileAjax.Platform.browser.isIE){elmt.style.filter="progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity="+opacity+")";
+}else{var o=(opacity/100).toString();
+elmt.style.opacity=o;
+elmt.style.MozOpacity=o;
+}};
+SimileAjax.Graphics.bubbleConfig={containerCSSClass:"simileAjax-bubble-container",innerContainerCSSClass:"simileAjax-bubble-innerContainer",contentContainerCSSClass:"simileAjax-bubble-contentContainer",borderGraphicSize:50,borderGraphicCSSClassPrefix:"simileAjax-bubble-border-",arrowGraphicTargetOffset:33,arrowGraphicLength:100,arrowGraphicWidth:49,arrowGraphicCSSClassPrefix:"simileAjax-bubble-arrow-",closeGraphicCSSClass:"simileAjax-bubble-close",extraPadding:20};
+SimileAjax.Graphics.createBubbleForContentAndPoint=function(div,pageX,pageY,contentWidth,orientation,maxHeight){if(typeof contentWidth!="number"){contentWidth=300;
+}if(typeof maxHeight!="number"){maxHeight=0;
+}div.style.position="absolute";
+div.style.left="-5000px";
+div.style.top="0px";
+div.style.width=contentWidth+"px";
+document.body.appendChild(div);
+window.setTimeout(function(){var width=div.scrollWidth+10;
+var height=div.scrollHeight+10;
+var scrollDivW=0;
+if(maxHeight>0&&height>maxHeight){height=maxHeight;
+scrollDivW=width-25;
+}var bubble=SimileAjax.Graphics.createBubbleForPoint(pageX,pageY,width,height,orientation);
+document.body.removeChild(div);
+div.style.position="static";
+div.style.left="";
+div.style.top="";
+if(scrollDivW>0){var scrollDiv=document.createElement("div");
+div.style.width="";
+scrollDiv.style.width=scrollDivW+"px";
+scrollDiv.appendChild(div);
+bubble.content.appendChild(scrollDiv);
+}else{div.style.width=width+"px";
+bubble.content.appendChild(div);
+}},200);
+};
+SimileAjax.Graphics.createBubbleForPoint=function(pageX,pageY,contentWidth,contentHeight,orientation){contentWidth=parseInt(contentWidth,10);
+contentHeight=parseInt(contentHeight,10);
+var bubbleConfig=SimileAjax.Graphics.bubbleConfig;
+var pngTransparencyClassSuffix=SimileAjax.Graphics.pngIsTranslucent?"pngTranslucent":"pngNotTranslucent";
+var bubbleWidth=contentWidth+2*bubbleConfig.borderGraphicSize;
+var bubbleHeight=contentHeight+2*bubbleConfig.borderGraphicSize;
+var generatePngSensitiveClass=function(className){return className+" "+className+"-"+pngTransparencyClassSuffix;
+};
+var div=document.createElement("div");
+div.className=generatePngSensitiveClass(bubbleConfig.containerCSSClass);
+div.style.width=contentWidth+"px";
+div.style.height=contentHeight+"px";
+var divInnerContainer=document.createElement("div");
+divInnerContainer.className=generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
+div.appendChild(divInnerContainer);
+var close=function(){if(!bubble._closed){document.body.removeChild(bubble._div);
+bubble._doc=null;
+bubble._div=null;
+bubble._content=null;
+bubble._closed=true;
+}};
+var bubble={_closed:false};
+var layer=SimileAjax.WindowManager.pushLayer(close,true,div);
+bubble._div=div;
+bubble.close=function(){SimileAjax.WindowManager.popLayer(layer);
+};
+var createBorder=function(classNameSuffix){var divBorderGraphic=document.createElement("div");
+divBorderGraphic.className=generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix+classNameSuffix);
+divInnerContainer.appendChild(divBorderGraphic);
+};
+createBorder("top-left");
+createBorder("top-right");
+createBorder("bottom-left");
+createBorder("bottom-right");
+createBorder("left");
+createBorder("right");
+createBorder("top");
+createBorder("bottom");
+var divContentContainer=document.createElement("div");
+divContentContainer.className=generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
+divInnerContainer.appendChild(divContentContainer);
+bubble.content=divContentContainer;
+var divClose=document.createElement("div");
+divClose.className=generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
+divInnerContainer.appendChild(divClose);
+SimileAjax.WindowManager.registerEventWithObject(divClose,"click",bubble,"close");
+(function(){var dims=SimileAjax.Graphics.getWindowDimensions();
+var docWidth=dims.w;
+var docHeight=dims.h;
+var halfArrowGraphicWidth=Math.ceil(bubbleConfig.arrowGraphicWidth/2);
+var createArrow=function(classNameSuffix){var divArrowGraphic=document.createElement("div");
+divArrowGraphic.className=generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix+"point-"+classNameSuffix);
+divInnerContainer.appendChild(divArrowGraphic);
+return divArrowGraphic;
+};
+if(pageX-halfArrowGraphicWidth-bubbleConfig.borderGraphicSize-bubbleConfig.extraPadding>0&&pageX+halfArrowGraphicWidth+bubbleConfig.borderGraphicSize+bubbleConfig.extraPadding<docWidth){var left=pageX-Math.round(contentWidth/2);
+left=pageX<(docWidth/2)?Math.max(left,bubbleConfig.extraPadding+bubbleConfig.borderGraphicSize):Math.min(left,docWidth-bubbleConfig.extraPadding-bubbleConfig.borderGraphicSize-contentWidth);
+if((orientation&&orientation=="top")||(!orientation&&(pageY-bubbleConfig.arrowGraphicTargetOffset-contentHeight-bubbleConfig.borderGraphicSize-bubbleConfig.extraPadding>0))){var divArrow=createArrow("down");
+divArrow.style.left=(pageX-halfArrowGraphicWidth-left)+"px";
+div.style.left=left+"px";
+div.style.top=(pageY-bubbleConfig.arrowGraphicTargetOffset-contentHeight)+"px";
+return ;
+}else{if((orientation&&orientation=="bottom")||(!orientation&&(pageY+bubbleConfig.arrowGraphicTargetOffset+contentHeight+bubbleConfig.borderGraphicSize+bubbleConfig.extraPadding<docHeight))){var divArrow=createArrow("up");
+divArrow.style.left=(pageX-halfArrowGraphicWidth-left)+"px";
+div.style.left=left+"px";
+div.style.top=(pageY+bubbleConfig.arrowGraphicTargetOffset)+"px";
+return ;
+}}}var top=pageY-Math.round(contentHeight/2);
+top=pageY<(docHeight/2)?Math.max(top,bubbleConfig.extraPadding+bubbleConfig.borderGraphicSize):Math.min(top,docHeight-bubbleConfig.extraPadding-bubbleConfig.borderGraphicSize-contentHeight);
+if((orientation&&orientation=="left")||(!orientation&&(pageX-bubbleConfig.arrowGraphicTargetOffset-contentWidth-bubbleConfig.borderGraphicSize-bubbleConfig.extraPadding>0))){var divArrow=createArrow("right");
+divArrow.style.top=(pageY-halfArrowGraphicWidth-top)+"px";
+div.style.top=top+"px";
+div.style.left=(pageX-bubbleConfig.arrowGraphicTargetOffset-contentWidth)+"px";
+}else{var divArrow=createArrow("left");
+divArrow.style.top=(pageY-halfArrowGraphicWidth-top)+"px";
+div.style.top=top+"px";
+div.style.left=(pageX+bubbleConfig.arrowGraphicTargetOffset)+"px";
+}})();
+document.body.appendChild(div);
+return bubble;
+};
+SimileAjax.Graphics.getWindowDimensions=function(){if(typeof window.innerHeight=="number"){return{w:window.innerWidth,h:window.innerHeight};
+}else{if(document.documentElement&&document.documentElement.clientHeight){return{w:document.documentElement.clientWidth,h:document.documentElement.clientHeight};
+}else{if(document.body&&document.body.clientHeight){return{w:document.body.clientWidth,h:document.body.clientHeight};
+}}}};
+SimileAjax.Graphics.createMessageBubble=function(doc){var containerDiv=doc.createElement("div");
+if(SimileAjax.Graphics.pngIsTranslucent){var topDiv=doc.createElement("div");
+topDiv.style.height="33px";
+topDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-top-left.png) top left no-repeat";
+topDiv.style.paddingLeft="44px";
+containerDiv.appendChild(topDiv);
+var topRightDiv=doc.createElement("div");
+topRightDiv.style.height="33px";
+topRightDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-top-right.png) top right no-repeat";
+topDiv.appendChild(topRightDiv);
+var middleDiv=doc.createElement("div");
+middleDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-left.png) top left repeat-y";
+middleDiv.style.paddingLeft="44px";
+containerDiv.appendChild(middleDiv);
+var middleRightDiv=doc.createElement("div");
+middleRightDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-right.png) top right repeat-y";
+middleRightDiv.style.paddingRight="44px";
+middleDiv.appendChild(middleRightDiv);
+var contentDiv=doc.createElement("div");
+middleRightDiv.appendChild(contentDiv);
+var bottomDiv=doc.createElement("div");
+bottomDiv.style.height="55px";
+bottomDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-left.png) bottom left no-repeat";
+bottomDiv.style.paddingLeft="44px";
+containerDiv.appendChild(bottomDiv);
+var bottomRightDiv=doc.createElement("div");
+bottomRightDiv.style.height="55px";
+bottomRightDiv.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-right.png) bottom right no-repeat";
+bottomDiv.appendChild(bottomRightDiv);
+}else{containerDiv.style.border="2px solid #7777AA";
+containerDiv.style.padding="20px";
+containerDiv.style.background="white";
+SimileAjax.Graphics.setOpacity(containerDiv,90);
+var contentDiv=doc.createElement("div");
+containerDiv.appendChild(contentDiv);
+}return{containerDiv:containerDiv,contentDiv:contentDiv};
+};
+SimileAjax.Graphics.createAnimation=function(f,from,to,duration,cont){return new SimileAjax.Graphics._Animation(f,from,to,duration,cont);
+};
+SimileAjax.Graphics._Animation=function(f,from,to,duration,cont){this.f=f;
+this.cont=(typeof cont=="function")?cont:function(){};
+this.from=from;
+this.to=to;
+this.current=from;
+this.duration=duration;
+this.start=new Date().getTime();
+this.timePassed=0;
+};
+SimileAjax.Graphics._Animation.prototype.run=function(){var a=this;
+window.setTimeout(function(){a.step();
+},50);
+};
+SimileAjax.Graphics._Animation.prototype.step=function(){this.timePassed+=50;
+var timePassedFraction=this.timePassed/this.duration;
+var parameterFraction=-Math.cos(timePassedFraction*Math.PI)/2+0.5;
+var current=parameterFraction*(this.to-this.from)+this.from;
+try{this.f(current,current-this.current);
+}catch(e){}this.current=current;
+if(this.timePassed<this.duration){this.run();
+}else{this.f(this.to,0);
+this["cont"]();
+}};
+SimileAjax.Graphics.createStructuredDataCopyButton=function(image,width,height,createDataFunction){var div=document.createElement("div");
+div.style.position="relative";
+div.style.display="inline";
+div.style.width=width+"px";
+div.style.height=height+"px";
+div.style.overflow="hidden";
+div.style.margin="2px";
+if(SimileAjax.Graphics.pngIsTranslucent){div.style.background="url("+image+") no-repeat";
+}else{div.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+image+"', sizingMethod='image')";
+}var style;
+if(SimileAjax.Platform.browser.isIE){style="filter:alpha(opacity=0)";
+}else{style="opacity: 0";
+}div.innerHTML="<textarea rows='1' autocomplete='off' value='none' style='"+style+"' />";
+var textarea=div.firstChild;
+textarea.style.width=width+"px";
+textarea.style.height=height+"px";
+textarea.onmousedown=function(evt){evt=(evt)?evt:((event)?event:null);
+if(evt.button==2){textarea.value=createDataFunction();
+textarea.select();
+}};
+return div;
+};
+SimileAjax.Graphics.getWidthHeight=function(el){var w,h;
+if(el.getBoundingClientRect==null){w=el.offsetWidth;
+h=el.offsetHeight;
+}else{var rect=el.getBoundingClientRect();
+w=Math.ceil(rect.right-rect.left);
+h=Math.ceil(rect.bottom-rect.top);
+}return{width:w,height:h};
+};
+SimileAjax.Graphics.getFontRenderingContext=function(elmt,width){return new SimileAjax.Graphics._FontRenderingContext(elmt,width);
+};
+SimileAjax.Graphics._FontRenderingContext=function(elmt,width){this._elmt=elmt;
+this._elmt.style.visibility="hidden";
+if(typeof width=="string"){this._elmt.style.width=width;
+}else{if(typeof width=="number"){this._elmt.style.width=width+"px";
+}}};
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose=function(){this._elmt=null;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.update=function(){this._elmt.innerHTML="A";
+this._lineHeight=this._elmt.offsetHeight;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize=function(text,className){var el=this._elmt;
+el.innerHTML=text;
+el.className=className===undefined?"":className;
+var wh=SimileAjax.Graphics.getWidthHeight(el);
+el.className="";
+return wh;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight=function(){return this._lineHeight;
+};
+
+
+/* history.js */
+SimileAjax.History={maxHistoryLength:10,historyFile:"__history__.html",enabled:true,_initialized:false,_listeners:new SimileAjax.ListenerQueue(),_actions:[],_baseIndex:0,_currentIndex:0,_plainDocumentTitle:document.title};
+SimileAjax.History.formatHistoryEntryTitle=function(actionLabel){return SimileAjax.History._plainDocumentTitle+" {"+actionLabel+"}";
+};
+SimileAjax.History.initialize=function(){if(SimileAjax.History._initialized){return ;
+}if(SimileAjax.History.enabled){var iframe=document.createElement("iframe");
+iframe.id="simile-ajax-history";
+iframe.style.position="absolute";
+iframe.style.width="10px";
+iframe.style.height="10px";
+iframe.style.top="0px";
+iframe.style.left="0px";
+iframe.style.visibility="hidden";
+iframe.src=SimileAjax.History.historyFile+"?0";
+document.body.appendChild(iframe);
+SimileAjax.DOM.registerEvent(iframe,"load",SimileAjax.History._handleIFrameOnLoad);
+SimileAjax.History._iframe=iframe;
+}SimileAjax.History._initialized=true;
+};
+SimileAjax.History.addListener=function(listener){SimileAjax.History.initialize();
+SimileAjax.History._listeners.add(listener);
+};
+SimileAjax.History.removeListener=function(listener){SimileAjax.History.initialize();
+SimileAjax.History._listeners.remove(listener);
+};
+SimileAjax.History.addAction=function(action){SimileAjax.History.initialize();
+SimileAjax.History._listeners.fire("onBeforePerform",[action]);
+window.setTimeout(function(){try{action.perform();
+SimileAjax.History._listeners.fire("onAfterPerform",[action]);
+if(SimileAjax.History.enabled){SimileAjax.History._actions=SimileAjax.History._actions.slice(0,SimileAjax.History._currentIndex-SimileAjax.History._baseIndex);
+SimileAjax.History._actions.push(action);
+SimileAjax.History._currentIndex++;
+var diff=SimileAjax.History._actions.length-SimileAjax.History.maxHistoryLength;
+if(diff>0){SimileAjax.History._actions=SimileAjax.History._actions.slice(diff);
+SimileAjax.History._baseIndex+=diff;
+}try{SimileAjax.History._iframe.contentWindow.location.search="?"+SimileAjax.History._currentIndex;
+}catch(e){var title=SimileAjax.History.formatHistoryEntryTitle(action.label);
+document.title=title;
+}}}catch(e){SimileAjax.Debug.exception(e,"Error adding action {"+action.label+"} to history");
+}},0);
+};
+SimileAjax.History.addLengthyAction=function(perform,undo,label){SimileAjax.History.addAction({perform:perform,undo:undo,label:label,uiLayer:SimileAjax.WindowManager.getBaseLayer(),lengthy:true});
+};
+SimileAjax.History._handleIFrameOnLoad=function(){try{var q=SimileAjax.History._iframe.contentWindow.location.search;
+var c=(q.length==0)?0:Math.max(0,parseInt(q.substr(1)));
+var finishUp=function(){var diff=c-SimileAjax.History._currentIndex;
+SimileAjax.History._currentIndex+=diff;
+SimileAjax.History._baseIndex+=diff;
+SimileAjax.History._iframe.contentWindow.location.search="?"+c;
+};
+if(c<SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeUndoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex>c&&SimileAjax.History._currentIndex>SimileAjax.History._baseIndex){SimileAjax.History._currentIndex--;
+var action=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{action.undo();
+}catch(e){SimileAjax.Debug.exception(e,"History: Failed to undo action {"+action.label+"}");
+}}SimileAjax.History._listeners.fire("onAfterUndoSeveral",[]);
+finishUp();
+},0);
+}else{if(c>SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeRedoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex<c&&SimileAjax.History._currentIndex-SimileAjax.History._baseIndex<SimileAjax.History._actions.length){var action=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{action.perform();
+}catch(e){SimileAjax.Debug.exception(e,"History: Failed to redo action {"+action.label+"}");
+}SimileAjax.History._currentIndex++;
+}SimileAjax.History._listeners.fire("onAfterRedoSeveral",[]);
+finishUp();
+},0);
+}else{var index=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+var title=(index>=0&&index<SimileAjax.History._actions.length)?SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[index].label):SimileAjax.History._plainDocumentTitle;
+SimileAjax.History._iframe.contentWindow.document.title=title;
+document.title=title;
+}}}catch(e){}};
+SimileAjax.History.getNextUndoAction=function(){try{var index=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+return SimileAjax.History._actions[index];
+}catch(e){return null;
+}};
+SimileAjax.History.getNextRedoAction=function(){try{var index=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex;
+return SimileAjax.History._actions[index];
+}catch(e){return null;
+}};
+
+
+/* html.js */
+SimileAjax.HTML=new Object();
+SimileAjax.HTML._e2uHash={};
+(function(){var e2uHash=SimileAjax.HTML._e2uHash;
+e2uHash["nbsp"]="\u00A0[space]";
+e2uHash["iexcl"]="\u00A1";
+e2uHash["cent"]="\u00A2";
+e2uHash["pound"]="\u00A3";
+e2uHash["curren"]="\u00A4";
+e2uHash["yen"]="\u00A5";
+e2uHash["brvbar"]="\u00A6";
+e2uHash["sect"]="\u00A7";
+e2uHash["uml"]="\u00A8";
+e2uHash["copy"]="\u00A9";
+e2uHash["ordf"]="\u00AA";
+e2uHash["laquo"]="\u00AB";
+e2uHash["not"]="\u00AC";
+e2uHash["shy"]="\u00AD";
+e2uHash["reg"]="\u00AE";
+e2uHash["macr"]="\u00AF";
+e2uHash["deg"]="\u00B0";
+e2uHash["plusmn"]="\u00B1";
+e2uHash["sup2"]="\u00B2";
+e2uHash["sup3"]="\u00B3";
+e2uHash["acute"]="\u00B4";
+e2uHash["micro"]="\u00B5";
+e2uHash["para"]="\u00B6";
+e2uHash["middot"]="\u00B7";
+e2uHash["cedil"]="\u00B8";
+e2uHash["sup1"]="\u00B9";
+e2uHash["ordm"]="\u00BA";
+e2uHash["raquo"]="\u00BB";
+e2uHash["frac14"]="\u00BC";
+e2uHash["frac12"]="\u00BD";
+e2uHash["frac34"]="\u00BE";
+e2uHash["iquest"]="\u00BF";
+e2uHash["Agrave"]="\u00C0";
+e2uHash["Aacute"]="\u00C1";
+e2uHash["Acirc"]="\u00C2";
+e2uHash["Atilde"]="\u00C3";
+e2uHash["Auml"]="\u00C4";
+e2uHash["Aring"]="\u00C5";
+e2uHash["AElig"]="\u00C6";
+e2uHash["Ccedil"]="\u00C7";
+e2uHash["Egrave"]="\u00C8";
+e2uHash["Eacute"]="\u00C9";
+e2uHash["Ecirc"]="\u00CA";
+e2uHash["Euml"]="\u00CB";
+e2uHash["Igrave"]="\u00CC";
+e2uHash["Iacute"]="\u00CD";
+e2uHash["Icirc"]="\u00CE";
+e2uHash["Iuml"]="\u00CF";
+e2uHash["ETH"]="\u00D0";
+e2uHash["Ntilde"]="\u00D1";
+e2uHash["Ograve"]="\u00D2";
+e2uHash["Oacute"]="\u00D3";
+e2uHash["Ocirc"]="\u00D4";
+e2uHash["Otilde"]="\u00D5";
+e2uHash["Ouml"]="\u00D6";
+e2uHash["times"]="\u00D7";
+e2uHash["Oslash"]="\u00D8";
+e2uHash["Ugrave"]="\u00D9";
+e2uHash["Uacute"]="\u00DA";
+e2uHash["Ucirc"]="\u00DB";
+e2uHash["Uuml"]="\u00DC";
+e2uHash["Yacute"]="\u00DD";
+e2uHash["THORN"]="\u00DE";
+e2uHash["szlig"]="\u00DF";
+e2uHash["agrave"]="\u00E0";
+e2uHash["aacute"]="\u00E1";
+e2uHash["acirc"]="\u00E2";
+e2uHash["atilde"]="\u00E3";
+e2uHash["auml"]="\u00E4";
+e2uHash["aring"]="\u00E5";
+e2uHash["aelig"]="\u00E6";
+e2uHash["ccedil"]="\u00E7";
+e2uHash["egrave"]="\u00E8";
+e2uHash["eacute"]="\u00E9";
+e2uHash["ecirc"]="\u00EA";
+e2uHash["euml"]="\u00EB";
+e2uHash["igrave"]="\u00EC";
+e2uHash["iacute"]="\u00ED";
+e2uHash["icirc"]="\u00EE";
+e2uHash["iuml"]="\u00EF";
+e2uHash["eth"]="\u00F0";
+e2uHash["ntilde"]="\u00F1";
+e2uHash["ograve"]="\u00F2";
+e2uHash["oacute"]="\u00F3";
+e2uHash["ocirc"]="\u00F4";
+e2uHash["otilde"]="\u00F5";
+e2uHash["ouml"]="\u00F6";
+e2uHash["divide"]="\u00F7";
+e2uHash["oslash"]="\u00F8";
+e2uHash["ugrave"]="\u00F9";
+e2uHash["uacute"]="\u00FA";
+e2uHash["ucirc"]="\u00FB";
+e2uHash["uuml"]="\u00FC";
+e2uHash["yacute"]="\u00FD";
+e2uHash["thorn"]="\u00FE";
+e2uHash["yuml"]="\u00FF";
+e2uHash["quot"]="\u0022";
+e2uHash["amp"]="\u0026";
+e2uHash["lt"]="\u003C";
+e2uHash["gt"]="\u003E";
+e2uHash["OElig"]="";
+e2uHash["oelig"]="\u0153";
+e2uHash["Scaron"]="\u0160";
+e2uHash["scaron"]="\u0161";
+e2uHash["Yuml"]="\u0178";
+e2uHash["circ"]="\u02C6";
+e2uHash["tilde"]="\u02DC";
+e2uHash["ensp"]="\u2002";
+e2uHash["emsp"]="\u2003";
+e2uHash["thinsp"]="\u2009";
+e2uHash["zwnj"]="\u200C";
+e2uHash["zwj"]="\u200D";
+e2uHash["lrm"]="\u200E";
+e2uHash["rlm"]="\u200F";
+e2uHash["ndash"]="\u2013";
+e2uHash["mdash"]="\u2014";
+e2uHash["lsquo"]="\u2018";
+e2uHash["rsquo"]="\u2019";
+e2uHash["sbquo"]="\u201A";
+e2uHash["ldquo"]="\u201C";
+e2uHash["rdquo"]="\u201D";
+e2uHash["bdquo"]="\u201E";
+e2uHash["dagger"]="\u2020";
+e2uHash["Dagger"]="\u2021";
+e2uHash["permil"]="\u2030";
+e2uHash["lsaquo"]="\u2039";
+e2uHash["rsaquo"]="\u203A";
+e2uHash["euro"]="\u20AC";
+e2uHash["fnof"]="\u0192";
+e2uHash["Alpha"]="\u0391";
+e2uHash["Beta"]="\u0392";
+e2uHash["Gamma"]="\u0393";
+e2uHash["Delta"]="\u0394";
+e2uHash["Epsilon"]="\u0395";
+e2uHash["Zeta"]="\u0396";
+e2uHash["Eta"]="\u0397";
+e2uHash["Theta"]="\u0398";
+e2uHash["Iota"]="\u0399";
+e2uHash["Kappa"]="\u039A";
+e2uHash["Lambda"]="\u039B";
+e2uHash["Mu"]="\u039C";
+e2uHash["Nu"]="\u039D";
+e2uHash["Xi"]="\u039E";
+e2uHash["Omicron"]="\u039F";
+e2uHash["Pi"]="\u03A0";
+e2uHash["Rho"]="\u03A1";
+e2uHash["Sigma"]="\u03A3";
+e2uHash["Tau"]="\u03A4";
+e2uHash["Upsilon"]="\u03A5";
+e2uHash["Phi"]="\u03A6";
+e2uHash["Chi"]="\u03A7";
+e2uHash["Psi"]="\u03A8";
+e2uHash["Omega"]="\u03A9";
+e2uHash["alpha"]="\u03B1";
+e2uHash["beta"]="\u03B2";
+e2uHash["gamma"]="\u03B3";
+e2uHash["delta"]="\u03B4";
+e2uHash["epsilon"]="\u03B5";
+e2uHash["zeta"]="\u03B6";
+e2uHash["eta"]="\u03B7";
+e2uHash["theta"]="\u03B8";
+e2uHash["iota"]="\u03B9";
+e2uHash["kappa"]="\u03BA";
+e2uHash["lambda"]="\u03BB";
+e2uHash["mu"]="\u03BC";
+e2uHash["nu"]="\u03BD";
+e2uHash["xi"]="\u03BE";
+e2uHash["omicron"]="\u03BF";
+e2uHash["pi"]="\u03C0";
+e2uHash["rho"]="\u03C1";
+e2uHash["sigmaf"]="\u03C2";
+e2uHash["sigma"]="\u03C3";
+e2uHash["tau"]="\u03C4";
+e2uHash["upsilon"]="\u03C5";
+e2uHash["phi"]="\u03C6";
+e2uHash["chi"]="\u03C7";
+e2uHash["psi"]="\u03C8";
+e2uHash["omega"]="\u03C9";
+e2uHash["thetasym"]="\u03D1";
+e2uHash["upsih"]="\u03D2";
+e2uHash["piv"]="\u03D6";
+e2uHash["bull"]="\u2022";
+e2uHash["hellip"]="\u2026";
+e2uHash["prime"]="\u2032";
+e2uHash["Prime"]="\u2033";
+e2uHash["oline"]="\u203E";
+e2uHash["frasl"]="\u2044";
+e2uHash["weierp"]="\u2118";
+e2uHash["image"]="\u2111";
+e2uHash["real"]="\u211C";
+e2uHash["trade"]="\u2122";
+e2uHash["alefsym"]="\u2135";
+e2uHash["larr"]="\u2190";
+e2uHash["uarr"]="\u2191";
+e2uHash["rarr"]="\u2192";
+e2uHash["darr"]="\u2193";
+e2uHash["harr"]="\u2194";
+e2uHash["crarr"]="\u21B5";
+e2uHash["lArr"]="\u21D0";
+e2uHash["uArr"]="\u21D1";
+e2uHash["rArr"]="\u21D2";
+e2uHash["dArr"]="\u21D3";
+e2uHash["hArr"]="\u21D4";
+e2uHash["forall"]="\u2200";
+e2uHash["part"]="\u2202";
+e2uHash["exist"]="\u2203";
+e2uHash["empty"]="\u2205";
+e2uHash["nabla"]="\u2207";
+e2uHash["isin"]="\u2208";
+e2uHash["notin"]="\u2209";
+e2uHash["ni"]="\u220B";
+e2uHash["prod"]="\u220F";
+e2uHash["sum"]="\u2211";
+e2uHash["minus"]="\u2212";
+e2uHash["lowast"]="\u2217";
+e2uHash["radic"]="\u221A";
+e2uHash["prop"]="\u221D";
+e2uHash["infin"]="\u221E";
+e2uHash["ang"]="\u2220";
+e2uHash["and"]="\u2227";
+e2uHash["or"]="\u2228";
+e2uHash["cap"]="\u2229";
+e2uHash["cup"]="\u222A";
+e2uHash["int"]="\u222B";
+e2uHash["there4"]="\u2234";
+e2uHash["sim"]="\u223C";
+e2uHash["cong"]="\u2245";
+e2uHash["asymp"]="\u2248";
+e2uHash["ne"]="\u2260";
+e2uHash["equiv"]="\u2261";
+e2uHash["le"]="\u2264";
+e2uHash["ge"]="\u2265";
+e2uHash["sub"]="\u2282";
+e2uHash["sup"]="\u2283";
+e2uHash["nsub"]="\u2284";
+e2uHash["sube"]="\u2286";
+e2uHash["supe"]="\u2287";
+e2uHash["oplus"]="\u2295";
+e2uHash["otimes"]="\u2297";
+e2uHash["perp"]="\u22A5";
+e2uHash["sdot"]="\u22C5";
+e2uHash["lceil"]="\u2308";
+e2uHash["rceil"]="\u2309";
+e2uHash["lfloor"]="\u230A";
+e2uHash["rfloor"]="\u230B";
+e2uHash["lang"]="\u2329";
+e2uHash["rang"]="\u232A";
+e2uHash["loz"]="\u25CA";
+e2uHash["spades"]="\u2660";
+e2uHash["clubs"]="\u2663";
+e2uHash["hearts"]="\u2665";
+e2uHash["diams"]="\u2666";
+})();
+SimileAjax.HTML.deEntify=function(s){var e2uHash=SimileAjax.HTML._e2uHash;
+var re=/&(\w+?);/;
+while(re.test(s)){var m=s.match(re);
+s=s.replace(re,e2uHash[m[1]]);
+}return s;
+};
+
+
+/* json.js */
+SimileAjax.JSON=new Object();
+(function(){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};
+var s={array:function(x){var a=["["],b,f,i,l=x.length,v;
+for(i=0;
+i<l;
+i+=1){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a[a.length]=v;
+b=true;
+}}}a[a.length]="]";
+return a.join("");
+},"boolean":function(x){return String(x);
+},"null":function(x){return"null";
+},number:function(x){return isFinite(x)?String(x):"null";
+},object:function(x){if(x){if(x instanceof Array){return s.array(x);
+}var a=["{"],b,f,i,v;
+for(i in x){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a.push(s.string(i),":",v);
+b=true;
+}}}a[a.length]="}";
+return a.join("");
+}return"null";
+},string:function(x){if(/["\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];
+if(c){return c;
+}c=b.charCodeAt();
+return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);
+});
+}return'"'+x+'"';
+}};
+SimileAjax.JSON.toJSONString=function(o){if(o instanceof Object){return s.object(o);
+}else{if(o instanceof Array){return s.array(o);
+}else{return o.toString();
+}}};
+SimileAjax.JSON.parseJSON=function(){try{return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g,"")))&&eval("("+this+")");
+}catch(e){return false;
+}};
+})();
+
+
+/* string.js */
+String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
+};
+String.prototype.startsWith=function(prefix){return this.length>=prefix.length&&this.substr(0,prefix.length)==prefix;
+};
+String.prototype.endsWith=function(suffix){return this.length>=suffix.length&&this.substr(this.length-suffix.length)==suffix;
+};
+String.substitute=function(s,objects){var result="";
+var start=0;
+while(start<s.length-1){var percent=s.indexOf("%",start);
+if(percent<0||percent==s.length-1){break;
+}else{if(percent>start&&s.charAt(percent-1)=="\\"){result+=s.substring(start,percent-1)+"%";
+start=percent+1;
+}else{var n=parseInt(s.charAt(percent+1));
+if(isNaN(n)||n>=objects.length){result+=s.substring(start,percent+2);
+}else{result+=s.substring(start,percent)+objects[n].toString();
+}start=percent+2;
+}}}if(start<s.length){result+=s.substring(start);
+}return result;
+};
+
+
+/* units.js */
+SimileAjax.NativeDateUnit=new Object();
+SimileAjax.NativeDateUnit.makeDefaultValue=function(){return new Date();
+};
+SimileAjax.NativeDateUnit.cloneValue=function(v){return new Date(v.getTime());
+};
+SimileAjax.NativeDateUnit.getParser=function(format){if(typeof format=="string"){format=format.toLowerCase();
+}var parser=(format=="iso8601"||format=="iso 8601")?SimileAjax.DateTime.parseIso8601DateTime:SimileAjax.DateTime.parseGregorianDateTime;
+return function(d){if(typeof d!="undefined"&&typeof d.toUTCString=="function"){return d;
+}else{return parser(d);
+}};
+};
+SimileAjax.NativeDateUnit.parseFromObject=function(o){return SimileAjax.DateTime.parseGregorianDateTime(o);
+};
+SimileAjax.NativeDateUnit.toNumber=function(v){return v.getTime();
+};
+SimileAjax.NativeDateUnit.fromNumber=function(n){return new Date(n);
+};
+SimileAjax.NativeDateUnit.compare=function(v1,v2){var n1,n2;
+if(typeof v1=="object"){n1=v1.getTime();
+}else{n1=Number(v1);
+}if(typeof v2=="object"){n2=v2.getTime();
+}else{n2=Number(v2);
+}return n1-n2;
+};
+SimileAjax.NativeDateUnit.earlier=function(v1,v2){return SimileAjax.NativeDateUnit.compare(v1,v2)<0?v1:v2;
+};
+SimileAjax.NativeDateUnit.later=function(v1,v2){return SimileAjax.NativeDateUnit.compare(v1,v2)>0?v1:v2;
+};
+SimileAjax.NativeDateUnit.change=function(v,n){return new Date(v.getTime()+n);
+};
+
+
+/* window-manager.js */
+SimileAjax.WindowManager={_initialized:false,_listeners:[],_draggedElement:null,_draggedElementCallback:null,_dropTargetHighlightElement:null,_lastCoords:null,_ghostCoords:null,_draggingMode:"",_dragging:false,_layers:[]};
+SimileAjax.WindowManager.initialize=function(){if(SimileAjax.WindowManager._initialized){return ;
+}SimileAjax.DOM.registerEvent(document.body,"mousedown",SimileAjax.WindowManager._onBodyMouseDown);
+SimileAjax.DOM.registerEvent(document.body,"mousemove",SimileAjax.WindowManager._onBodyMouseMove);
+SimileAjax.DOM.registerEvent(document.body,"mouseup",SimileAjax.WindowManager._onBodyMouseUp);
+SimileAjax.DOM.registerEvent(document,"keydown",SimileAjax.WindowManager._onBodyKeyDown);
+SimileAjax.DOM.registerEvent(document,"keyup",SimileAjax.WindowManager._onBodyKeyUp);
+SimileAjax.WindowManager._layers.push({index:0});
+SimileAjax.WindowManager._historyListener={onBeforeUndoSeveral:function(){},onAfterUndoSeveral:function(){},onBeforeUndo:function(){},onAfterUndo:function(){},onBeforeRedoSeveral:function(){},onAfterRedoSeveral:function(){},onBeforeRedo:function(){},onAfterRedo:function(){}};
+SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+SimileAjax.WindowManager._initialized=true;
+};
+SimileAjax.WindowManager.getBaseLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[0];
+};
+SimileAjax.WindowManager.getHighestLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length-1];
+};
+SimileAjax.WindowManager.registerEventWithObject=function(elmt,eventName,obj,handlerName,layer){SimileAjax.WindowManager.registerEvent(elmt,eventName,function(elmt2,evt,target){return obj[handlerName].call(obj,elmt2,evt,target);
+},layer);
+};
+SimileAjax.WindowManager.registerEvent=function(elmt,eventName,handler,layer){if(layer==null){layer=SimileAjax.WindowManager.getHighestLayer();
+}var handler2=function(elmt,evt,target){if(SimileAjax.WindowManager._canProcessEventAtLayer(layer)){SimileAjax.WindowManager._popToLayer(layer.index);
+try{handler(elmt,evt,target);
+}catch(e){SimileAjax.Debug.exception(e);
+}}SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.DOM.registerEvent(elmt,eventName,handler2);
+};
+SimileAjax.WindowManager.pushLayer=function(f,ephemeral,elmt){var layer={onPop:f,index:SimileAjax.WindowManager._layers.length,ephemeral:(ephemeral),elmt:elmt};
+SimileAjax.WindowManager._layers.push(layer);
+return layer;
+};
+SimileAjax.WindowManager.popLayer=function(layer){for(var i=1;
+i<SimileAjax.WindowManager._layers.length;
+i++){if(SimileAjax.WindowManager._layers[i]==layer){SimileAjax.WindowManager._popToLayer(i-1);
+break;
+}}};
+SimileAjax.WindowManager.popAllLayers=function(){SimileAjax.WindowManager._popToLayer(0);
+};
+SimileAjax.WindowManager.registerForDragging=function(elmt,callback,layer){SimileAjax.WindowManager.registerEvent(elmt,"mousedown",function(elmt,evt,target){SimileAjax.WindowManager._handleMouseDown(elmt,evt,callback);
+},layer);
+};
+SimileAjax.WindowManager._popToLayer=function(level){while(level+1<SimileAjax.WindowManager._layers.length){try{var layer=SimileAjax.WindowManager._layers.pop();
+if(layer.onPop!=null){layer.onPop();
+}}catch(e){}}};
+SimileAjax.WindowManager._canProcessEventAtLayer=function(layer){if(layer.index==(SimileAjax.WindowManager._layers.length-1)){return true;
+}for(var i=layer.index+1;
+i<SimileAjax.WindowManager._layers.length;
+i++){if(!SimileAjax.WindowManager._layers[i].ephemeral){return false;
+}}return true;
+};
+SimileAjax.WindowManager.cancelPopups=function(evt){var evtCoords=(evt)?SimileAjax.DOM.getEventPageCoordinates(evt):{x:-1,y:-1};
+var i=SimileAjax.WindowManager._layers.length-1;
+while(i>0&&SimileAjax.WindowManager._layers[i].ephemeral){var layer=SimileAjax.WindowManager._layers[i];
+if(layer.elmt!=null){var elmt=layer.elmt;
+var elmtCoords=SimileAjax.DOM.getPageCoordinates(elmt);
+if(evtCoords.x>=elmtCoords.left&&evtCoords.x<(elmtCoords.left+elmt.offsetWidth)&&evtCoords.y>=elmtCoords.top&&evtCoords.y<(elmtCoords.top+elmt.offsetHeight)){break;
+}}i--;
+}SimileAjax.WindowManager._popToLayer(i);
+};
+SimileAjax.WindowManager._onBodyMouseDown=function(elmt,evt,target){if(!("eventPhase" in evt)||evt.eventPhase==evt.BUBBLING_PHASE){SimileAjax.WindowManager.cancelPopups(evt);
+}};
+SimileAjax.WindowManager._handleMouseDown=function(elmt,evt,callback){SimileAjax.WindowManager._draggedElement=elmt;
+SimileAjax.WindowManager._draggedElementCallback=callback;
+SimileAjax.WindowManager._lastCoords={x:evt.clientX,y:evt.clientY};
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.WindowManager._onBodyKeyDown=function(elmt,evt,target){if(SimileAjax.WindowManager._dragging){if(evt.keyCode==27){SimileAjax.WindowManager._cancelDragging();
+}else{if((evt.keyCode==17||evt.keyCode==16)&&SimileAjax.WindowManager._draggingMode!="copy"){SimileAjax.WindowManager._draggingMode="copy";
+var img=SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix+"images/copy.png");
+img.style.position="absolute";
+img.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+img.style.top=(SimileAjax.WindowManager._ghostCoords.top)+"px";
+document.body.appendChild(img);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=img;
+}}}};
+SimileAjax.WindowManager._onBodyKeyUp=function(elmt,evt,target){if(SimileAjax.WindowManager._dragging){if(evt.keyCode==17||evt.keyCode==16){SimileAjax.WindowManager._draggingMode="";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}}}};
+SimileAjax.WindowManager._onBodyMouseMove=function(elmt,evt,target){if(SimileAjax.WindowManager._draggedElement!=null){var callback=SimileAjax.WindowManager._draggedElementCallback;
+var lastCoords=SimileAjax.WindowManager._lastCoords;
+var diffX=evt.clientX-lastCoords.x;
+var diffY=evt.clientY-lastCoords.y;
+if(!SimileAjax.WindowManager._dragging){if(Math.abs(diffX)>5||Math.abs(diffY)>5){try{if("onDragStart" in callback){callback.onDragStart();
+}if("ghost" in callback&&callback.ghost){var draggedElmt=SimileAjax.WindowManager._draggedElement;
+SimileAjax.WindowManager._ghostCoords=SimileAjax.DOM.getPageCoordinates(draggedElmt);
+SimileAjax.WindowManager._ghostCoords.left+=diffX;
+SimileAjax.WindowManager._ghostCoords.top+=diffY;
+var ghostElmt=draggedElmt.cloneNode(true);
+ghostElmt.style.position="absolute";
+ghostElmt.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+ghostElmt.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+ghostElmt.style.zIndex=1000;
+SimileAjax.Graphics.setOpacity(ghostElmt,50);
+document.body.appendChild(ghostElmt);
+callback._ghostElmt=ghostElmt;
+}SimileAjax.WindowManager._dragging=true;
+SimileAjax.WindowManager._lastCoords={x:evt.clientX,y:evt.clientY};
+document.body.focus();
+}catch(e){SimileAjax.Debug.exception("WindowManager: Error handling mouse down",e);
+SimileAjax.WindowManager._cancelDragging();
+}}}else{try{SimileAjax.WindowManager._lastCoords={x:evt.clientX,y:evt.clientY};
+if("onDragBy" in callback){callback.onDragBy(diffX,diffY);
+}if("_ghostElmt" in callback){var ghostElmt=callback._ghostElmt;
+SimileAjax.WindowManager._ghostCoords.left+=diffX;
+SimileAjax.WindowManager._ghostCoords.top+=diffY;
+ghostElmt.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+ghostElmt.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){var indicatorElmt=SimileAjax.WindowManager._draggingModeIndicatorElmt;
+indicatorElmt.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+indicatorElmt.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+}if("droppable" in callback&&callback.droppable){var coords=SimileAjax.DOM.getEventPageCoordinates(evt);
+var target=SimileAjax.DOM.hittest(coords.x,coords.y,[SimileAjax.WindowManager._ghostElmt,SimileAjax.WindowManager._dropTargetHighlightElement]);
+target=SimileAjax.WindowManager._findDropTarget(target);
+if(target!=SimileAjax.WindowManager._potentialDropTarget){if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+}var droppable=false;
+if(target!=null){if((!("canDropOn" in callback)||callback.canDropOn(target))&&(!("canDrop" in target)||target.canDrop(SimileAjax.WindowManager._draggedElement))){droppable=true;
+}}if(droppable){var border=4;
+var targetCoords=SimileAjax.DOM.getPageCoordinates(target);
+var highlight=document.createElement("div");
+highlight.style.border=border+"px solid yellow";
+highlight.style.backgroundColor="yellow";
+highlight.style.position="absolute";
+highlight.style.left=targetCoords.left+"px";
+highlight.style.top=targetCoords.top+"px";
+highlight.style.width=(target.offsetWidth-border*2)+"px";
+highlight.style.height=(target.offsetHeight-border*2)+"px";
+SimileAjax.Graphics.setOpacity(highlight,30);
+document.body.appendChild(highlight);
+SimileAjax.WindowManager._potentialDropTarget=target;
+SimileAjax.WindowManager._dropTargetHighlightElement=highlight;
+}}}}}catch(e){SimileAjax.Debug.exception("WindowManager: Error handling mouse move",e);
+SimileAjax.WindowManager._cancelDragging();
+}}SimileAjax.DOM.cancelEvent(evt);
+return false;
+}};
+SimileAjax.WindowManager._onBodyMouseUp=function(elmt,evt,target){if(SimileAjax.WindowManager._draggedElement!=null){try{if(SimileAjax.WindowManager._dragging){var callback=SimileAjax.WindowManager._draggedElementCallback;
+if("onDragEnd" in callback){callback.onDragEnd();
+}if("droppable" in callback&&callback.droppable){var dropped=false;
+var target=SimileAjax.WindowManager._potentialDropTarget;
+if(target!=null){if((!("canDropOn" in callback)||callback.canDropOn(target))&&(!("canDrop" in target)||target.canDrop(SimileAjax.WindowManager._draggedElement))){if("onDropOn" in callback){callback.onDropOn(target);
+}target.ondrop(SimileAjax.WindowManager._draggedElement,SimileAjax.WindowManager._draggingMode);
+dropped=true;
+}}if(!dropped){}}}}finally{SimileAjax.WindowManager._cancelDragging();
+}SimileAjax.DOM.cancelEvent(evt);
+return false;
+}};
+SimileAjax.WindowManager._cancelDragging=function(){var callback=SimileAjax.WindowManager._draggedElementCallback;
+if("_ghostElmt" in callback){var ghostElmt=callback._ghostElmt;
+document.body.removeChild(ghostElmt);
+delete callback._ghostElmt;
+}if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+}if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}SimileAjax.WindowManager._draggedElement=null;
+SimileAjax.WindowManager._draggedElementCallback=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._lastCoords=null;
+SimileAjax.WindowManager._ghostCoords=null;
+SimileAjax.WindowManager._draggingMode="";
+SimileAjax.WindowManager._dragging=false;
+};
+SimileAjax.WindowManager._findDropTarget=function(elmt){while(elmt!=null){if("ondrop" in elmt&&(typeof elmt.ondrop)=="function"){break;
+}elmt=elmt.parentNode;
+}return elmt;
+};
+
+
+/* xmlhttp.js */
+SimileAjax.XmlHttp=new Object();
+SimileAjax.XmlHttp._onReadyStateChange=function(xmlhttp,fError,fDone){switch(xmlhttp.readyState){case 4:try{if(xmlhttp.status==0||xmlhttp.status==200){if(fDone){fDone(xmlhttp);
+}}else{if(fError){fError(xmlhttp.statusText,xmlhttp.status,xmlhttp);
+}}}catch(e){SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange",e);
+}break;
+}};
+SimileAjax.XmlHttp._createRequest=function(){if(SimileAjax.Platform.browser.isIE){var programIDs=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
+for(var i=0;
+i<programIDs.length;
+i++){try{var programID=programIDs[i];
+var f=function(){return new ActiveXObject(programID);
+};
+var o=f();
+SimileAjax.XmlHttp._createRequest=f;
+return o;
+}catch(e){}}}try{var f=function(){return new XMLHttpRequest();
+};
+var o=f();
+SimileAjax.XmlHttp._createRequest=f;
+return o;
+}catch(e){throw new Error("Failed to create an XMLHttpRequest object");
+}};
+SimileAjax.XmlHttp.get=function(url,fError,fDone){var xmlhttp=SimileAjax.XmlHttp._createRequest();
+xmlhttp.open("GET",url,true);
+xmlhttp.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(xmlhttp,fError,fDone);
+};
+xmlhttp.send(null);
+};
+SimileAjax.XmlHttp.post=function(url,body,fError,fDone){var xmlhttp=SimileAjax.XmlHttp._createRequest();
+xmlhttp.open("POST",url,true);
+xmlhttp.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(xmlhttp,fError,fDone);
+};
+xmlhttp.send(body);
+};
+SimileAjax.XmlHttp._forceXML=function(xmlhttp){try{xmlhttp.overrideMimeType("text/xml");
+}catch(e){xmlhttp.setrequestheader("Content-Type","text/xml");
+}};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle.js
new file mode 100644
index 00000000..bc51c664
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-bundle.js
@@ -0,0 +1,2911 @@
+
+
+/* jquery-1.3.2.min.js */
+if(!("jQuery" in window)&&!("$" in window)){(function(){var W=this,AB,F=W.jQuery,S=W.$,T=W.jQuery=W.$=function(B,A){return new T.fn.init(B,A);
+},M=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,AC=/^.[^:#\[\.,]*$/;
+T.fn=T.prototype={init:function(a,B){a=a||document;
+if(a.nodeType){this[0]=a;
+this.length=1;
+this.context=a;
+return this;
+}if(typeof a==="string"){var C=M.exec(a);
+if(C&&(C[1]||!B)){if(C[1]){a=T.clean([C[1]],B);
+}else{var A=document.getElementById(C[3]);
+if(A&&A.id!=C[3]){return T().find(a);
+}var D=T(A||[]);
+D.context=document;
+D.selector=a;
+return D;
+}}else{return T(B).find(a);
+}}else{if(T.isFunction(a)){return T(document).ready(a);
+}}if(a.selector&&a.context){this.selector=a.selector;
+this.context=a.context;
+}return this.setArray(T.isArray(a)?a:T.makeArray(a));
+},selector:"",jquery:"1.3.2",size:function(){return this.length;
+},get:function(A){return A===AB?Array.prototype.slice.call(this):this[A];
+},pushStack:function(C,A,D){var B=T(C);
+B.prevObject=this;
+B.context=this.context;
+if(A==="find"){B.selector=this.selector+(this.selector?" ":"")+D;
+}else{if(A){B.selector=this.selector+"."+A+"("+D+")";
+}}return B;
+},setArray:function(A){this.length=0;
+Array.prototype.push.apply(this,A);
+return this;
+},each:function(A,B){return T.each(this,A,B);
+},index:function(A){return T.inArray(A&&A.jquery?A[0]:A,this);
+},attr:function(C,A,B){var D=C;
+if(typeof C==="string"){if(A===AB){return this[0]&&T[B||"attr"](this[0],C);
+}else{D={};
+D[C]=A;
+}}return this.each(function(a){for(C in D){T.attr(B?this.style:this,C,T.prop(this,D[C],B,a,C));
+}});
+},css:function(B,A){if((B=="width"||B=="height")&&parseFloat(A)<0){A=AB;
+}return this.attr(B,A,"curCSS");
+},text:function(A){if(typeof A!=="object"&&A!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(A));
+}var B="";
+T.each(A||this,function(){T.each(this.childNodes,function(){if(this.nodeType!=8){B+=this.nodeType!=1?this.nodeValue:T.fn.text([this]);
+}});
+});
+return B;
+},wrapAll:function(B){if(this[0]){var A=T(B,this[0].ownerDocument).clone();
+if(this[0].parentNode){A.insertBefore(this[0]);
+}A.map(function(){var C=this;
+while(C.firstChild){C=C.firstChild;
+}return C;
+}).append(this);
+}return this;
+},wrapInner:function(A){return this.each(function(){T(this).contents().wrapAll(A);
+});
+},wrap:function(A){return this.each(function(){T(this).wrapAll(A);
+});
+},append:function(){return this.domManip(arguments,true,function(A){if(this.nodeType==1){this.appendChild(A);
+}});
+},prepend:function(){return this.domManip(arguments,true,function(A){if(this.nodeType==1){this.insertBefore(A,this.firstChild);
+}});
+},before:function(){return this.domManip(arguments,false,function(A){this.parentNode.insertBefore(A,this);
+});
+},after:function(){return this.domManip(arguments,false,function(A){this.parentNode.insertBefore(A,this.nextSibling);
+});
+},end:function(){return this.prevObject||T([]);
+},push:[].push,sort:[].sort,splice:[].splice,find:function(B){if(this.length===1){var A=this.pushStack([],"find",B);
+A.length=0;
+T.find(B,this[0],A);
+return A;
+}else{return this.pushStack(T.unique(T.map(this,function(C){return T.find(B,C);
+})),"find",B);
+}},clone:function(B){var D=this.map(function(){if(!T.support.noCloneEvent&&!T.isXMLDoc(this)){var b=this.outerHTML;
+if(!b){var a=this.ownerDocument.createElement("div");
+a.appendChild(this.cloneNode(true));
+b=a.innerHTML;
+}return T.clean([b.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0];
+}else{return this.cloneNode(true);
+}});
+if(B===true){var A=this.find("*").andSelf(),C=0;
+D.find("*").andSelf().each(function(){if(this.nodeName!==A[C].nodeName){return ;
+}var c=T.data(A[C],"events");
+for(var a in c){for(var b in c[a]){T.event.add(this,a,c[a][b],c[a][b].data);
+}}C++;
+});
+}return D;
+},filter:function(A){return this.pushStack(T.isFunction(A)&&T.grep(this,function(B,C){return A.call(B,C);
+})||T.multiFilter(A,T.grep(this,function(B){return B.nodeType===1;
+})),"filter",A);
+},closest:function(C){var A=T.expr.match.POS.test(C)?T(C):null,B=0;
+return this.map(function(){var D=this;
+while(D&&D.ownerDocument){if(A?A.index(D)>-1:T(D).is(C)){T.data(D,"closest",B);
+return D;
+}D=D.parentNode;
+B++;
+}});
+},not:function(B){if(typeof B==="string"){if(AC.test(B)){return this.pushStack(T.multiFilter(B,this,true),"not",B);
+}else{B=T.multiFilter(B,this);
+}}var A=B.length&&B[B.length-1]!==AB&&!B.nodeType;
+return this.filter(function(){return A?T.inArray(this,B)<0:this!=B;
+});
+},add:function(A){return this.pushStack(T.unique(T.merge(this.get(),typeof A==="string"?T(A):T.makeArray(A))));
+},is:function(A){return !!A&&T.multiFilter(A,this).length>0;
+},hasClass:function(A){return !!A&&this.is("."+A);
+},val:function(C){if(C===AB){var e=this[0];
+if(e){if(T.nodeName(e,"option")){return(e.attributes.value||{}).specified?e.value:e.text;
+}if(T.nodeName(e,"select")){var a=e.selectedIndex,B=[],A=e.options,b=e.type=="select-one";
+if(a<0){return null;
+}for(var d=b?a:0,D=b?a+1:A.length;
+d<D;
+d++){var c=A[d];
+if(c.selected){C=T(c).val();
+if(b){return C;
+}B.push(C);
+}}return B;
+}return(e.value||"").replace(/\r/g,"");
+}return AB;
+}if(typeof C==="number"){C+="";
+}return this.each(function(){if(this.nodeType!=1){return ;
+}if(T.isArray(C)&&/radio|checkbox/.test(this.type)){this.checked=(T.inArray(this.value,C)>=0||T.inArray(this.name,C)>=0);
+}else{if(T.nodeName(this,"select")){var f=T.makeArray(C);
+T("option",this).each(function(){this.selected=(T.inArray(this.value,f)>=0||T.inArray(this.text,f)>=0);
+});
+if(!f.length){this.selectedIndex=-1;
+}}else{this.value=C;
+}}});
+},html:function(A){return A===AB?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(A);
+},replaceWith:function(A){return this.after(A).remove();
+},eq:function(A){return this.slice(A,+A+1);
+},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","));
+},map:function(A){return this.pushStack(T.map(this,function(B,C){return A.call(B,C,B);
+}));
+},andSelf:function(){return this.add(this.prevObject);
+},domManip:function(D,A,B){if(this[0]){var a=(this[0].ownerDocument||this[0]).createDocumentFragment(),d=T.clean(D,(this[0].ownerDocument||this[0]),a),b=a.firstChild;
+if(b){for(var c=0,e=this.length;
+c<e;
+c++){B.call(C(this[c],b),this.length>1||c>0?a.cloneNode(true):a);
+}}if(d){T.each(d,E);
+}}return this;
+function C(g,f){return A&&T.nodeName(g,"table")&&T.nodeName(f,"tr")?(g.getElementsByTagName("tbody")[0]||g.appendChild(g.ownerDocument.createElement("tbody"))):g;
+}}};
+T.fn.init.prototype=T.fn;
+function E(B,A){if(A.src){T.ajax({url:A.src,async:false,dataType:"script"});
+}else{T.globalEval(A.text||A.textContent||A.innerHTML||"");
+}if(A.parentNode){A.parentNode.removeChild(A);
+}}function AD(){return +new Date;
+}T.extend=T.fn.extend=function(){var C=arguments[0]||{},a=1,D=arguments.length,d=false,b;
+if(typeof C==="boolean"){d=C;
+C=arguments[1]||{};
+a=2;
+}if(typeof C!=="object"&&!T.isFunction(C)){C={};
+}if(D==a){C=this;
+--a;
+}for(;
+a<D;
+a++){if((b=arguments[a])!=null){for(var c in b){var B=C[c],A=b[c];
+if(C===A){continue;
+}if(d&&A&&typeof A==="object"&&!A.nodeType){C[c]=T.extend(d,B||(A.length!=null?[]:{}),A);
+}else{if(A!==AB){C[c]=A;
+}}}}}return C;
+};
+var AG=/z-?index|font-?weight|opacity|zoom|line-?height/i,Q=document.defaultView||{},L=Object.prototype.toString;
+T.extend({noConflict:function(A){W.$=S;
+if(A){W.jQuery=F;
+}return T;
+},isFunction:function(A){return L.call(A)==="[object Function]";
+},isArray:function(A){return L.call(A)==="[object Array]";
+},isXMLDoc:function(A){return A.nodeType===9&&A.documentElement.nodeName!=="HTML"||!!A.ownerDocument&&T.isXMLDoc(A.ownerDocument);
+},globalEval:function(A){if(A&&/\S/.test(A)){var B=document.getElementsByTagName("head")[0]||document.documentElement,C=document.createElement("script");
+C.type="text/javascript";
+if(T.support.scriptEval){C.appendChild(document.createTextNode(A));
+}else{C.text=A;
+}B.insertBefore(C,B.firstChild);
+B.removeChild(C);
+}},nodeName:function(A,B){return A.nodeName&&A.nodeName.toUpperCase()==B.toUpperCase();
+},each:function(a,A,b){var c,D=0,C=a.length;
+if(b){if(C===AB){for(c in a){if(A.apply(a[c],b)===false){break;
+}}}else{for(;
+D<C;
+){if(A.apply(a[D++],b)===false){break;
+}}}}else{if(C===AB){for(c in a){if(A.call(a[c],c,a[c])===false){break;
+}}}else{for(var B=a[0];
+D<C&&A.call(B,D,B)!==false;
+B=a[++D]){}}}return a;
+},prop:function(B,A,C,D,a){if(T.isFunction(A)){A=A.call(B,D);
+}return typeof A==="number"&&C=="curCSS"&&!AG.test(a)?A+"px":A;
+},className:{add:function(B,A){T.each((A||"").split(/\s+/),function(D,C){if(B.nodeType==1&&!T.className.has(B.className,C)){B.className+=(B.className?" ":"")+C;
+}});
+},remove:function(B,A){if(B.nodeType==1){B.className=A!==AB?T.grep(B.className.split(/\s+/),function(C){return !T.className.has(A,C);
+}).join(" "):"";
+}},has:function(A,B){return A&&T.inArray(B,(A.className||A).toString().split(/\s+/))>-1;
+}},swap:function(B,C,A){var a={};
+for(var D in C){a[D]=B.style[D];
+B.style[D]=C[D];
+}A.call(B);
+for(var D in C){B.style[D]=a[D];
+}},css:function(a,c,C,d){if(c=="width"||c=="height"){var A,b={position:"absolute",visibility:"hidden",display:"block"},B=c=="width"?["Left","Right"]:["Top","Bottom"];
+function D(){A=c=="width"?a.offsetWidth:a.offsetHeight;
+if(d==="border"){return ;
+}T.each(B,function(){if(!d){A-=parseFloat(T.curCSS(a,"padding"+this,true))||0;
+}if(d==="margin"){A+=parseFloat(T.curCSS(a,"margin"+this,true))||0;
+}else{A-=parseFloat(T.curCSS(a,"border"+this+"Width",true))||0;
+}});
+}if(a.offsetWidth!==0){D();
+}else{T.swap(a,b,D);
+}return Math.max(0,Math.round(A));
+}return T.curCSS(a,c,C);
+},curCSS:function(a,d,c){var B,e=a.style;
+if(d=="opacity"&&!T.support.opacity){B=T.attr(e,"opacity");
+return B==""?"1":B;
+}if(d.match(/float/i)){d=H;
+}if(!c&&e&&e[d]){B=e[d];
+}else{if(Q.getComputedStyle){if(d.match(/float/i)){d="float";
+}d=d.replace(/([A-Z])/g,"-$1").toLowerCase();
+var A=Q.getComputedStyle(a,null);
+if(A){B=A.getPropertyValue(d);
+}if(d=="opacity"&&B==""){B="1";
+}}else{if(a.currentStyle){var D=d.replace(/\-(\w)/g,function(g,f){return f.toUpperCase();
+});
+B=a.currentStyle[d]||a.currentStyle[D];
+if(!/^\d+(px)?$/i.test(B)&&/^\d/.test(B)){var b=e.left,C=a.runtimeStyle.left;
+a.runtimeStyle.left=a.currentStyle.left;
+e.left=B||0;
+B=e.pixelLeft+"px";
+e.left=b;
+a.runtimeStyle.left=C;
+}}}}return B;
+},clean:function(c,B,D){B=B||document;
+if(typeof B.createElement==="undefined"){B=B.ownerDocument||B[0]&&B[0].ownerDocument||document;
+}if(!D&&c.length===1&&typeof c[0]==="string"){var a=/^<(\w+)\s*\/?>$/.exec(c[0]);
+if(a){return[B.createElement(a[1])];
+}}var b=[],d=[],A=B.createElement("div");
+T.each(c,function(h,e){if(typeof e==="number"){e+="";
+}if(!e){return ;
+}if(typeof e==="string"){e=e.replace(/(<(\w+)[^>]*?)\/>/g,function(m,l,n){return n.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?m:l+"></"+n+">";
+});
+var i=e.replace(/^\s+/,"").substring(0,10).toLowerCase();
+var g=!i.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!i.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||i.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!i.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!i.indexOf("<td")||!i.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!i.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!T.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];
+A.innerHTML=g[1]+e+g[2];
+while(g[0]--){A=A.lastChild;
+}if(!T.support.tbody){var f=/<tbody/i.test(e),j=!i.indexOf("<table")&&!f?A.firstChild&&A.firstChild.childNodes:g[1]=="<table>"&&!f?A.childNodes:[];
+for(var k=j.length-1;
+k>=0;
+--k){if(T.nodeName(j[k],"tbody")&&!j[k].childNodes.length){j[k].parentNode.removeChild(j[k]);
+}}}if(!T.support.leadingWhitespace&&/^\s/.test(e)){A.insertBefore(B.createTextNode(e.match(/^\s*/)[0]),A.firstChild);
+}e=T.makeArray(A.childNodes);
+}if(e.nodeType){b.push(e);
+}else{b=T.merge(b,e);
+}});
+if(D){for(var C=0;
+b[C];
+C++){if(T.nodeName(b[C],"script")&&(!b[C].type||b[C].type.toLowerCase()==="text/javascript")){d.push(b[C].parentNode?b[C].parentNode.removeChild(b[C]):b[C]);
+}else{if(b[C].nodeType===1){b.splice.apply(b,[C+1,0].concat(T.makeArray(b[C].getElementsByTagName("script"))));
+}D.appendChild(b[C]);
+}}return d;
+}return b;
+},attr:function(C,b,B){if(!C||C.nodeType==3||C.nodeType==8){return AB;
+}var a=!T.isXMLDoc(C),A=B!==AB;
+b=a&&T.props[b]||b;
+if(C.tagName){var c=/href|src|style/.test(b);
+if(b=="selected"&&C.parentNode){C.parentNode.selectedIndex;
+}if(b in C&&a&&!c){if(A){if(b=="type"&&T.nodeName(C,"input")&&C.parentNode){throw"type property can't be changed";
+}C[b]=B;
+}if(T.nodeName(C,"form")&&C.getAttributeNode(b)){return C.getAttributeNode(b).nodeValue;
+}if(b=="tabIndex"){var D=C.getAttributeNode("tabIndex");
+return D&&D.specified?D.value:C.nodeName.match(/(button|input|object|select|textarea)/i)?0:C.nodeName.match(/^(a|area)$/i)&&C.href?0:AB;
+}return C[b];
+}if(!T.support.style&&a&&b=="style"){return T.attr(C.style,"cssText",B);
+}if(A){C.setAttribute(b,""+B);
+}var d=!T.support.hrefNormalized&&a&&c?C.getAttribute(b,2):C.getAttribute(b);
+return d===null?AB:d;
+}if(!T.support.opacity&&b=="opacity"){if(A){C.zoom=1;
+C.filter=(C.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(B)+""=="NaN"?"":"alpha(opacity="+B*100+")");
+}return C.filter&&C.filter.indexOf("opacity=")>=0?(parseFloat(C.filter.match(/opacity=([^)]*)/)[1])/100)+"":"";
+}b=b.replace(/-([a-z])/ig,function(f,e){return e.toUpperCase();
+});
+if(A){C[b]=B;
+}return C[b];
+},trim:function(A){return(A||"").replace(/^\s+|\s+$/g,"");
+},makeArray:function(A){var C=[];
+if(A!=null){var B=A.length;
+if(B==null||typeof A==="string"||T.isFunction(A)||A.setInterval){C[0]=A;
+}else{while(B){C[--B]=A[B];
+}}}return C;
+},inArray:function(B,A){for(var D=0,C=A.length;
+D<C;
+D++){if(A[D]===B){return D;
+}}return -1;
+},merge:function(B,a){var D=0,C,A=B.length;
+if(!T.support.getAll){while((C=a[D++])!=null){if(C.nodeType!=8){B[A++]=C;
+}}}else{while((C=a[D++])!=null){B[A++]=C;
+}}return B;
+},unique:function(A){var b=[],c={};
+try{for(var a=0,D=A.length;
+a<D;
+a++){var B=T.data(A[a]);
+if(!c[B]){c[B]=true;
+b.push(A[a]);
+}}}catch(C){b=A;
+}return b;
+},grep:function(a,A,b){var D=[];
+for(var C=0,B=a.length;
+C<B;
+C++){if(!b!=!A(a[C],C)){D.push(a[C]);
+}}return D;
+},map:function(b,A){var a=[];
+for(var D=0,C=b.length;
+D<C;
+D++){var B=A(b[D],D);
+if(B!=null){a[a.length]=B;
+}}return a.concat.apply([],a);
+}});
+var O=navigator.userAgent.toLowerCase();
+T.browser={version:(O.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(O),opera:/opera/.test(O),msie:/msie/.test(O)&&!/opera/.test(O),mozilla:/mozilla/.test(O)&&!/(compatible|webkit)/.test(O)};
+T.each({parent:function(A){return A.parentNode;
+},parents:function(A){return T.dir(A,"parentNode");
+},next:function(A){return T.nth(A,2,"nextSibling");
+},prev:function(A){return T.nth(A,2,"previousSibling");
+},nextAll:function(A){return T.dir(A,"nextSibling");
+},prevAll:function(A){return T.dir(A,"previousSibling");
+},siblings:function(A){return T.sibling(A.parentNode.firstChild,A);
+},children:function(A){return T.sibling(A.firstChild);
+},contents:function(A){return T.nodeName(A,"iframe")?A.contentDocument||A.contentWindow.document:T.makeArray(A.childNodes);
+}},function(B,A){T.fn[B]=function(D){var C=T.map(this,A);
+if(D&&typeof D=="string"){C=T.multiFilter(D,C);
+}return this.pushStack(T.unique(C),B,D);
+};
+});
+T.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(B,A){T.fn[B]=function(d){var a=[],C=T(d);
+for(var D=0,c=C.length;
+D<c;
+D++){var b=(D>0?this.clone(true):this).get();
+T.fn[A].apply(T(C[D]),b);
+a=a.concat(b);
+}return this.pushStack(a,B,d);
+};
+});
+T.each({removeAttr:function(A){T.attr(this,A,"");
+if(this.nodeType==1){this.removeAttribute(A);
+}},addClass:function(A){T.className.add(this,A);
+},removeClass:function(A){T.className.remove(this,A);
+},toggleClass:function(A,B){if(typeof B!=="boolean"){B=!T.className.has(this,A);
+}T.className[B?"add":"remove"](this,A);
+},remove:function(A){if(!A||T.filter(A,[this]).length){T("*",this).add([this]).each(function(){T.event.remove(this);
+T.removeData(this);
+});
+if(this.parentNode){this.parentNode.removeChild(this);
+}}},empty:function(){T(this).children().remove();
+while(this.firstChild){this.removeChild(this.firstChild);
+}}},function(B,A){T.fn[B]=function(){return this.each(A,arguments);
+};
+});
+function Y(B,A){return B[0]&&parseInt(T.curCSS(B[0],A,true),10)||0;
+}var AA="jQuery"+AD(),I=0,R={};
+T.extend({cache:{},data:function(C,D,B){C=C==W?R:C;
+var A=C[AA];
+if(!A){A=C[AA]=++I;
+}if(D&&!T.cache[A]){T.cache[A]={};
+}if(B!==AB){T.cache[A][D]=B;
+}return D?T.cache[A][D]:A;
+},removeData:function(C,D){C=C==W?R:C;
+var A=C[AA];
+if(D){if(T.cache[A]){delete T.cache[A][D];
+D="";
+for(D in T.cache[A]){break;
+}if(!D){T.removeData(C);
+}}}else{try{delete C[AA];
+}catch(B){if(C.removeAttribute){C.removeAttribute(AA);
+}}delete T.cache[A];
+}},queue:function(C,D,A){if(C){D=(D||"fx")+"queue";
+var B=T.data(C,D);
+if(!B||T.isArray(A)){B=T.data(C,D,T.makeArray(A));
+}else{if(A){B.push(A);
+}}}return B;
+},dequeue:function(A,B){var D=T.queue(A,B),C=D.shift();
+if(!B||B==="fx"){C=D[0];
+}if(C!==AB){C.call(A);
+}}});
+T.fn.extend({data:function(D,B){var A=D.split(".");
+A[1]=A[1]?"."+A[1]:"";
+if(B===AB){var C=this.triggerHandler("getData"+A[1]+"!",[A[0]]);
+if(C===AB&&this.length){C=T.data(this[0],D);
+}return C===AB&&A[1]?this.data(A[0]):C;
+}else{return this.trigger("setData"+A[1]+"!",[A[0],B]).each(function(){T.data(this,D,B);
+});
+}},removeData:function(A){return this.each(function(){T.removeData(this,A);
+});
+},queue:function(B,A){if(typeof B!=="string"){A=B;
+B="fx";
+}if(A===AB){return T.queue(this[0],B);
+}return this.each(function(){var C=T.queue(this,B,A);
+if(B=="fx"&&C.length==1){C[0].call(this);
+}});
+},dequeue:function(A){return this.each(function(){T.dequeue(this,A);
+});
+}});
+(function(){var B=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,d=0,h=Object.prototype.toString;
+var j=function(n,r,AI,z){AI=AI||[];
+r=r||document;
+if(r.nodeType!==1&&r.nodeType!==9){return[];
+}if(!n||typeof n!=="string"){return AI;
+}var m=[],p,w,t,s,y,q,o=true;
+B.lastIndex=0;
+while((p=B.exec(n))!==null){m.push(p[1]);
+if(p[2]){q=RegExp.rightContext;
+break;
+}}if(m.length>1&&c.exec(n)){if(m.length===2&&g.relative[m[0]]){w=f(m[0]+m[1],r);
+}else{w=g.relative[m[0]]?[r]:j(m.shift(),r);
+while(m.length){n=m.shift();
+if(g.relative[n]){n+=m.shift();
+}w=f(n,w);
+}}}else{var x=z?{expr:m.pop(),set:k(z)}:j.find(m.pop(),m.length===1&&r.parentNode?r.parentNode:r,C(r));
+w=j.filter(x.expr,x.set);
+if(m.length>0){t=k(w);
+}else{o=false;
+}while(m.length){var u=m.pop(),v=u;
+if(!g.relative[u]){u="";
+}else{v=m.pop();
+}if(v==null){v=r;
+}g.relative[u](t,v,C(r));
+}}if(!t){t=w;
+}if(!t){throw"Syntax error, unrecognized expression: "+(u||n);
+}if(h.call(t)==="[object Array]"){if(!o){AI.push.apply(AI,t);
+}else{if(r.nodeType===1){for(var l=0;
+t[l]!=null;
+l++){if(t[l]&&(t[l]===true||t[l].nodeType===1&&e(r,t[l]))){AI.push(w[l]);
+}}}else{for(var l=0;
+t[l]!=null;
+l++){if(t[l]&&t[l].nodeType===1){AI.push(w[l]);
+}}}}}else{k(t,AI);
+}if(q){j(q,r,AI,z);
+if(i){hasDuplicate=false;
+AI.sort(i);
+if(hasDuplicate){for(var l=1;
+l<AI.length;
+l++){if(AI[l]===AI[l-1]){AI.splice(l--,1);
+}}}}}return AI;
+};
+j.matches=function(m,l){return j(m,null,null,l);
+};
+j.find=function(l,s,t){var m,o;
+if(!l){return[];
+}for(var p=0,q=g.order.length;
+p<q;
+p++){var n=g.order[p],o;
+if((o=g.match[n].exec(l))){var r=RegExp.leftContext;
+if(r.substr(r.length-1)!=="\\"){o[1]=(o[1]||"").replace(/\\/g,"");
+m=g.find[n](o,s,t);
+if(m!=null){l=l.replace(g.match[n],"");
+break;
+}}}}if(!m){m=s.getElementsByTagName("*");
+}return{set:m,expr:l};
+};
+j.filter=function(y,z,v,p){var q=y,t=[],l=z,n,s,m=z&&z[0]&&C(z[0]);
+while(y&&z.length){for(var AI in g.filter){if((n=g.match[AI].exec(y))!=null){var r=g.filter[AI],u,w;
+s=false;
+if(l==t){t=[];
+}if(g.preFilter[AI]){n=g.preFilter[AI](n,l,v,t,p,m);
+if(!n){s=u=true;
+}else{if(n===true){continue;
+}}}if(n){for(var o=0;
+(w=l[o])!=null;
+o++){if(w){u=r(w,n,o,l);
+var x=p^!!u;
+if(v&&u!=null){if(x){s=true;
+}else{l[o]=false;
+}}else{if(x){t.push(w);
+s=true;
+}}}}}if(u!==AB){if(!v){l=t;
+}y=y.replace(g.match[AI],"");
+if(!s){return[];
+}break;
+}}}if(y==q){if(s==null){throw"Syntax error, unrecognized expression: "+y;
+}else{break;
+}}q=y;
+}return l;
+};
+var g=j.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(l){return l.getAttribute("href");
+}},relative:{"+":function(l,s,m){var o=typeof s==="string",t=o&&!/\W/.test(s),n=o&&!t;
+if(t&&!m){s=s.toUpperCase();
+}for(var p=0,q=l.length,r;
+p<q;
+p++){if((r=l[p])){while((r=r.previousSibling)&&r.nodeType!==1){}l[p]=n||r&&r.nodeName===s?r||false:r===s;
+}}if(n){j.filter(s,l,true);
+}},">":function(q,n,p){var s=typeof n==="string";
+if(s&&!/\W/.test(n)){n=p?n:n.toUpperCase();
+for(var m=0,o=q.length;
+m<o;
+m++){var r=q[m];
+if(r){var l=r.parentNode;
+q[m]=l.nodeName===n?l:false;
+}}}else{for(var m=0,o=q.length;
+m<o;
+m++){var r=q[m];
+if(r){q[m]=s?r.parentNode:r.parentNode===n;
+}}if(s){j.filter(n,q,true);
+}}},"":function(l,n,p){var m=d++,o=A;
+if(!n.match(/\W/)){var q=n=p?n:n.toUpperCase();
+o=D;
+}o("parentNode",n,m,l,q,p);
+},"~":function(l,n,p){var m=d++,o=A;
+if(typeof n==="string"&&!n.match(/\W/)){var q=n=p?n:n.toUpperCase();
+o=D;
+}o("previousSibling",n,m,l,q,p);
+}},find:{ID:function(n,m,l){if(typeof m.getElementById!=="undefined"&&!l){var o=m.getElementById(n[1]);
+return o?[o]:[];
+}},NAME:function(m,q,p){if(typeof q.getElementsByName!=="undefined"){var n=[],r=q.getElementsByName(m[1]);
+for(var l=0,o=r.length;
+l<o;
+l++){if(r[l].getAttribute("name")===m[1]){n.push(r[l]);
+}}return n.length===0?null:n;
+}},TAG:function(m,l){return l.getElementsByTagName(m[1]);
+}},preFilter:{CLASS:function(l,n,m,o,q,p){l=" "+l[1].replace(/\\/g,"")+" ";
+if(p){return l;
+}for(var s=0,r;
+(r=n[s])!=null;
+s++){if(r){if(q^(r.className&&(" "+r.className+" ").indexOf(l)>=0)){if(!m){o.push(r);
+}}else{if(m){n[s]=false;
+}}}}return false;
+},ID:function(l){return l[1].replace(/\\/g,"");
+},TAG:function(m,n){for(var l=0;
+n[l]===false;
+l++){}return n[l]&&C(n[l])?m[1]:m[1].toUpperCase();
+},CHILD:function(m){if(m[1]=="nth"){var l=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[2]=="even"&&"2n"||m[2]=="odd"&&"2n+1"||!/\D/.test(m[2])&&"0n+"+m[2]||m[2]);
+m[2]=(l[1]+(l[2]||1))-0;
+m[3]=l[3]-0;
+}m[0]=d++;
+return m;
+},ATTR:function(r,n,m,o,q,p){var l=r[1].replace(/\\/g,"");
+if(!p&&g.attrMap[l]){r[1]=g.attrMap[l];
+}if(r[2]==="~="){r[4]=" "+r[4]+" ";
+}return r;
+},PSEUDO:function(q,n,m,o,p){if(q[1]==="not"){if(q[3].match(B).length>1||/^\w/.test(q[3])){q[3]=j(q[3],null,null,n);
+}else{var l=j.filter(q[3],n,m,true^p);
+if(!m){o.push.apply(o,l);
+}return false;
+}}else{if(g.match.POS.test(q[0])||g.match.CHILD.test(q[0])){return true;
+}}return q;
+},POS:function(l){l.unshift(true);
+return l;
+}},filters:{enabled:function(l){return l.disabled===false&&l.type!=="hidden";
+},disabled:function(l){return l.disabled===true;
+},checked:function(l){return l.checked===true;
+},selected:function(l){l.parentNode.selectedIndex;
+return l.selected===true;
+},parent:function(l){return !!l.firstChild;
+},empty:function(l){return !l.firstChild;
+},has:function(l,m,n){return !!j(n[3],l).length;
+},header:function(l){return/h\d/i.test(l.nodeName);
+},text:function(l){return"text"===l.type;
+},radio:function(l){return"radio"===l.type;
+},checkbox:function(l){return"checkbox"===l.type;
+},file:function(l){return"file"===l.type;
+},password:function(l){return"password"===l.type;
+},submit:function(l){return"submit"===l.type;
+},image:function(l){return"image"===l.type;
+},reset:function(l){return"reset"===l.type;
+},button:function(l){return"button"===l.type||l.nodeName.toUpperCase()==="BUTTON";
+},input:function(l){return/input|select|textarea|button/i.test(l.nodeName);
+}},setFilters:{first:function(l,m){return m===0;
+},last:function(m,n,o,l){return n===l.length-1;
+},even:function(l,m){return m%2===0;
+},odd:function(l,m){return m%2===1;
+},lt:function(l,m,n){return m<n[3]-0;
+},gt:function(l,m,n){return m>n[3]-0;
+},nth:function(l,m,n){return n[3]-0==m;
+},eq:function(l,m,n){return n[3]-0==m;
+}},filter:{PSEUDO:function(q,m,l,p){var n=m[1],s=g.filters[n];
+if(s){return s(q,l,m,p);
+}else{if(n==="contains"){return(q.textContent||q.innerText||"").indexOf(m[3])>=0;
+}else{if(n==="not"){var r=m[3];
+for(var l=0,o=r.length;
+l<o;
+l++){if(r[l]===q){return false;
+}}return true;
+}}}},CHILD:function(s,p){var m=p[1],r=s;
+switch(m){case"only":case"first":while(r=r.previousSibling){if(r.nodeType===1){return false;
+}}if(m=="first"){return true;
+}r=s;
+case"last":while(r=r.nextSibling){if(r.nodeType===1){return false;
+}}return true;
+case"nth":var q=p[2],t=p[3];
+if(q==1&&t==0){return true;
+}var n=p[0],u=s.parentNode;
+if(u&&(u.sizcache!==n||!s.nodeIndex)){var o=0;
+for(r=u.firstChild;
+r;
+r=r.nextSibling){if(r.nodeType===1){r.nodeIndex=++o;
+}}u.sizcache=n;
+}var l=s.nodeIndex-t;
+if(q==0){return l==0;
+}else{return(l%q==0&&l/q>=0);
+}}},ID:function(l,m){return l.nodeType===1&&l.getAttribute("id")===m;
+},TAG:function(l,m){return(m==="*"&&l.nodeType===1)||l.nodeName===m;
+},CLASS:function(l,m){return(" "+(l.className||l.getAttribute("class"))+" ").indexOf(m)>-1;
+},ATTR:function(q,l){var m=l[1],o=g.attrHandle[m]?g.attrHandle[m](q):q[m]!=null?q[m]:q.getAttribute(m),p=o+"",r=l[2],n=l[4];
+return o==null?r==="!=":r==="="?p===n:r==="*="?p.indexOf(n)>=0:r==="~="?(" "+p+" ").indexOf(n)>=0:!n?p&&o!==false:r==="!="?p!=n:r==="^="?p.indexOf(n)===0:r==="$="?p.substr(p.length-n.length)===n:r==="|="?p===n||p.substr(0,n.length+1)===n+"-":false;
+},POS:function(q,n,m,p){var o=n[2],l=g.setFilters[o];
+if(l){return l(q,m,n,p);
+}}}};
+var c=g.match.POS;
+for(var a in g.match){g.match[a]=RegExp(g.match[a].source+/(?![^\[]*\])(?![^\(]*\))/.source);
+}var k=function(l,m){l=Array.prototype.slice.call(l);
+if(m){m.push.apply(m,l);
+return m;
+}return l;
+};
+try{Array.prototype.slice.call(document.documentElement.childNodes);
+}catch(b){k=function(p,l){var n=l||[];
+if(h.call(p)==="[object Array]"){Array.prototype.push.apply(n,p);
+}else{if(typeof p.length==="number"){for(var m=0,o=p.length;
+m<o;
+m++){n.push(p[m]);
+}}else{for(var m=0;
+p[m];
+m++){n.push(p[m]);
+}}}return n;
+};
+}var i;
+if(document.documentElement.compareDocumentPosition){i=function(m,n){var l=m.compareDocumentPosition(n)&4?-1:m===n?0:1;
+if(l===0){hasDuplicate=true;
+}return l;
+};
+}else{if("sourceIndex" in document.documentElement){i=function(m,n){var l=m.sourceIndex-n.sourceIndex;
+if(l===0){hasDuplicate=true;
+}return l;
+};
+}else{if(document.createRange){i=function(l,n){var m=l.ownerDocument.createRange(),o=n.ownerDocument.createRange();
+m.selectNode(l);
+m.collapse(true);
+o.selectNode(n);
+o.collapse(true);
+var p=m.compareBoundaryPoints(Range.START_TO_END,o);
+if(p===0){hasDuplicate=true;
+}return p;
+};
+}}}(function(){var m=document.createElement("form"),l="script"+(new Date).getTime();
+m.innerHTML="<input name='"+l+"'/>";
+var n=document.documentElement;
+n.insertBefore(m,n.firstChild);
+if(!!document.getElementById(l)){g.find.ID=function(r,q,p){if(typeof q.getElementById!=="undefined"&&!p){var o=q.getElementById(r[1]);
+return o?o.id===r[1]||typeof o.getAttributeNode!=="undefined"&&o.getAttributeNode("id").nodeValue===r[1]?[o]:AB:[];
+}};
+g.filter.ID=function(p,o){var q=typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id");
+return p.nodeType===1&&q&&q.nodeValue===o;
+};
+}n.removeChild(m);
+})();
+(function(){var l=document.createElement("div");
+l.appendChild(document.createComment(""));
+if(l.getElementsByTagName("*").length>0){g.find.TAG=function(o,p){var q=p.getElementsByTagName(o[1]);
+if(o[1]==="*"){var m=[];
+for(var n=0;
+q[n];
+n++){if(q[n].nodeType===1){m.push(q[n]);
+}}q=m;
+}return q;
+};
+}l.innerHTML="<a href='#'></a>";
+if(l.firstChild&&typeof l.firstChild.getAttribute!=="undefined"&&l.firstChild.getAttribute("href")!=="#"){g.attrHandle.href=function(m){return m.getAttribute("href",2);
+};
+}})();
+if(document.querySelectorAll){(function(){var m=j,l=document.createElement("div");
+l.innerHTML="<p class='TEST'></p>";
+if(l.querySelectorAll&&l.querySelectorAll(".TEST").length===0){return ;
+}j=function(q,r,o,n){r=r||document;
+if(!n&&r.nodeType===9&&!C(r)){try{return k(r.querySelectorAll(q),o);
+}catch(p){}}return m(q,r,o,n);
+};
+j.find=m.find;
+j.filter=m.filter;
+j.selectors=m.selectors;
+j.matches=m.matches;
+})();
+}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var l=document.createElement("div");
+l.innerHTML="<div class='test e'></div><div class='test'></div>";
+if(l.getElementsByClassName("e").length===0){return ;
+}l.lastChild.className="e";
+if(l.getElementsByClassName("e").length===1){return ;
+}g.order.splice(1,0,"CLASS");
+g.find.CLASS=function(o,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m){return n.getElementsByClassName(o[1]);
+}};
+})();
+}function D(r,m,n,t,l,u){var v=r=="previousSibling"&&!u;
+for(var p=0,q=t.length;
+p<q;
+p++){var s=t[p];
+if(s){if(v&&s.nodeType===1){s.sizcache=n;
+s.sizset=p;
+}s=s[r];
+var o=false;
+while(s){if(s.sizcache===n){o=t[s.sizset];
+break;
+}if(s.nodeType===1&&!u){s.sizcache=n;
+s.sizset=p;
+}if(s.nodeName===m){o=s;
+break;
+}s=s[r];
+}t[p]=o;
+}}}function A(r,m,n,t,l,u){var v=r=="previousSibling"&&!u;
+for(var p=0,q=t.length;
+p<q;
+p++){var s=t[p];
+if(s){if(v&&s.nodeType===1){s.sizcache=n;
+s.sizset=p;
+}s=s[r];
+var o=false;
+while(s){if(s.sizcache===n){o=t[s.sizset];
+break;
+}if(s.nodeType===1){if(!u){s.sizcache=n;
+s.sizset=p;
+}if(typeof m!=="string"){if(s===m){o=true;
+break;
+}}else{if(j.filter(m,[s]).length>0){o=s;
+break;
+}}}s=s[r];
+}t[p]=o;
+}}}var e=document.compareDocumentPosition?function(l,m){return l.compareDocumentPosition(m)&16;
+}:function(l,m){return l!==m&&(l.contains?l.contains(m):true);
+};
+var C=function(l){return l.nodeType===9&&l.documentElement.nodeName!=="HTML"||!!l.ownerDocument&&C(l.ownerDocument);
+};
+var f=function(o,q){var l=[],s="",r,m=q.nodeType?[q]:q;
+while((r=g.match.PSEUDO.exec(o))){s+=r[0];
+o=o.replace(g.match.PSEUDO,"");
+}o=g.relative[o]?o+"*":o;
+for(var p=0,n=m.length;
+p<n;
+p++){j(o,m[p],l);
+}return j.filter(s,l);
+};
+T.find=j;
+T.filter=j.filter;
+T.expr=j.selectors;
+T.expr[":"]=T.expr.filters;
+j.selectors.filters.hidden=function(l){return l.offsetWidth===0||l.offsetHeight===0;
+};
+j.selectors.filters.visible=function(l){return l.offsetWidth>0||l.offsetHeight>0;
+};
+j.selectors.filters.animated=function(l){return T.grep(T.timers,function(m){return l===m.elem;
+}).length;
+};
+T.multiFilter=function(l,n,m){if(m){l=":not("+l+")";
+}return j.matches(l,n);
+};
+T.dir=function(m,n){var o=[],l=m[n];
+while(l&&l!=document){if(l.nodeType==1){o.push(l);
+}l=l[n];
+}return o;
+};
+T.nth=function(p,o,m,l){o=o||1;
+var n=0;
+for(;
+p;
+p=p[m]){if(p.nodeType==1&&++n==o){break;
+}}return p;
+};
+T.sibling=function(l,m){var n=[];
+for(;
+l;
+l=l.nextSibling){if(l.nodeType==1&&l!=m){n.push(l);
+}}return n;
+};
+return ;
+W.Sizzle=j;
+})();
+T.event={add:function(C,b,D,A){if(C.nodeType==3||C.nodeType==8){return ;
+}if(C.setInterval&&C!=W){C=W;
+}if(!D.guid){D.guid=this.guid++;
+}if(A!==AB){var a=D;
+D=this.proxy(a);
+D.data=A;
+}var c=T.data(C,"events")||T.data(C,"events",{}),B=T.data(C,"handle")||T.data(C,"handle",function(){return typeof T!=="undefined"&&!T.event.triggered?T.event.handle.apply(arguments.callee.elem,arguments):AB;
+});
+B.elem=C;
+T.each(b.split(/\s+/),function(g,f){var e=f.split(".");
+f=e.shift();
+D.type=e.slice().sort().join(".");
+var d=c[f];
+if(T.event.specialAll[f]){T.event.specialAll[f].setup.call(C,A,e);
+}if(!d){d=c[f]={};
+if(!T.event.special[f]||T.event.special[f].setup.call(C,A,e)===false){if(C.addEventListener){C.addEventListener(f,B,false);
+}else{if(C.attachEvent){C.attachEvent("on"+f,B);
+}}}}d[D.guid]=D;
+T.event.global[f]=true;
+});
+C=null;
+},guid:1,global:{},remove:function(B,a,C){if(B.nodeType==3||B.nodeType==8){return ;
+}var b=T.data(B,"events"),c,d;
+if(b){if(a===AB||(typeof a==="string"&&a.charAt(0)==".")){for(var D in b){this.remove(B,D+(a||""));
+}}else{if(a.type){C=a.handler;
+a=a.type;
+}T.each(a.split(/\s+/),function(i,g){var e=g.split(".");
+g=e.shift();
+var h=RegExp("(^|\\.)"+e.slice().sort().join(".*\\.")+"(\\.|$)");
+if(b[g]){if(C){delete b[g][C.guid];
+}else{for(var f in b[g]){if(h.test(b[g][f].type)){delete b[g][f];
+}}}if(T.event.specialAll[g]){T.event.specialAll[g].teardown.call(B,e);
+}for(c in b[g]){break;
+}if(!c){if(!T.event.special[g]||T.event.special[g].teardown.call(B,e)===false){if(B.removeEventListener){B.removeEventListener(g,T.data(B,"handle"),false);
+}else{if(B.detachEvent){B.detachEvent("on"+g,T.data(B,"handle"));
+}}}c=null;
+delete b[g];
+}}});
+}for(c in b){break;
+}if(!c){var A=T.data(B,"handle");
+if(A){A.elem=null;
+}T.removeData(B,"events");
+T.removeData(B,"handle");
+}}},trigger:function(D,B,a,d){var b=D.type||D;
+if(!d){D=typeof D==="object"?D[AA]?D:T.extend(T.Event(b),D):T.Event(b);
+if(b.indexOf("!")>=0){D.type=b=b.slice(0,-1);
+D.exclusive=true;
+}if(!a){D.stopPropagation();
+if(this.global[b]){T.each(T.cache,function(){if(this.events&&this.events[b]){T.event.trigger(D,B,this.handle.elem);
+}});
+}}if(!a||a.nodeType==3||a.nodeType==8){return AB;
+}D.result=AB;
+D.target=a;
+B=T.makeArray(B);
+B.unshift(D);
+}D.currentTarget=a;
+var C=T.data(a,"handle");
+if(C){C.apply(a,B);
+}if((!a[b]||(T.nodeName(a,"a")&&b=="click"))&&a["on"+b]&&a["on"+b].apply(a,B)===false){D.result=false;
+}if(!d&&a[b]&&!D.isDefaultPrevented()&&!(T.nodeName(a,"a")&&b=="click")){this.triggered=true;
+try{a[b]();
+}catch(A){}}this.triggered=false;
+if(!D.isPropagationStopped()){var c=a.parentNode||a.ownerDocument;
+if(c){T.event.trigger(D,B,c,true);
+}}},handle:function(B){var C,d;
+B=arguments[0]=T.event.fix(B||W.event);
+B.currentTarget=this;
+var A=B.type.split(".");
+B.type=A.shift();
+C=!A.length&&!B.exclusive;
+var D=RegExp("(^|\\.)"+A.slice().sort().join(".*\\.")+"(\\.|$)");
+d=(T.data(this,"events")||{})[B.type];
+for(var b in d){var a=d[b];
+if(C||D.test(a.type)){B.handler=a;
+B.data=a.data;
+var c=a.apply(this,arguments);
+if(c!==AB){B.result=c;
+if(c===false){B.preventDefault();
+B.stopPropagation();
+}}if(B.isImmediatePropagationStopped()){break;
+}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(C){if(C[AA]){return C;
+}var a=C;
+C=T.Event(a);
+for(var D=this.props.length,A;
+D;
+){A=this.props[--D];
+C[A]=a[A];
+}if(!C.target){C.target=C.srcElement||document;
+}if(C.target.nodeType==3){C.target=C.target.parentNode;
+}if(!C.relatedTarget&&C.fromElement){C.relatedTarget=C.fromElement==C.target?C.toElement:C.fromElement;
+}if(C.pageX==null&&C.clientX!=null){var B=document.documentElement,b=document.body;
+C.pageX=C.clientX+(B&&B.scrollLeft||b&&b.scrollLeft||0)-(B.clientLeft||0);
+C.pageY=C.clientY+(B&&B.scrollTop||b&&b.scrollTop||0)-(B.clientTop||0);
+}if(!C.which&&((C.charCode||C.charCode===0)?C.charCode:C.keyCode)){C.which=C.charCode||C.keyCode;
+}if(!C.metaKey&&C.ctrlKey){C.metaKey=C.ctrlKey;
+}if(!C.which&&C.button){C.which=(C.button&1?1:(C.button&2?3:(C.button&4?2:0)));
+}return C;
+},proxy:function(A,B){B=B||function(){return A.apply(this,arguments);
+};
+B.guid=A.guid=A.guid||B.guid||this.guid++;
+return B;
+},special:{ready:{setup:P,teardown:function(){}}},specialAll:{live:{setup:function(B,A){T.event.add(this,A[0],AF);
+},teardown:function(A){if(A.length){var C=0,B=RegExp("(^|\\.)"+A[0]+"(\\.|$)");
+T.each((T.data(this,"events").live||{}),function(){if(B.test(this.type)){C++;
+}});
+if(C<1){T.event.remove(this,A[0],AF);
+}}}}}};
+T.Event=function(A){if(!this.preventDefault){return new T.Event(A);
+}if(A&&A.type){this.originalEvent=A;
+this.type=A.type;
+}else{this.type=A;
+}this.timeStamp=AD();
+this[AA]=true;
+};
+function X(){return false;
+}function J(){return true;
+}T.Event.prototype={preventDefault:function(){this.isDefaultPrevented=J;
+var A=this.originalEvent;
+if(!A){return ;
+}if(A.preventDefault){A.preventDefault();
+}A.returnValue=false;
+},stopPropagation:function(){this.isPropagationStopped=J;
+var A=this.originalEvent;
+if(!A){return ;
+}if(A.stopPropagation){A.stopPropagation();
+}A.cancelBubble=true;
+},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=J;
+this.stopPropagation();
+},isDefaultPrevented:X,isPropagationStopped:X,isImmediatePropagationStopped:X};
+var AH=function(B){var C=B.relatedTarget;
+while(C&&C!=this){try{C=C.parentNode;
+}catch(A){C=this;
+}}if(C!=this){B.type=B.data;
+T.event.handle.apply(this,arguments);
+}};
+T.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(A,B){T.event.special[B]={setup:function(){T.event.add(this,A,AH,B);
+},teardown:function(){T.event.remove(this,A,AH);
+}};
+});
+T.fn.extend({bind:function(B,A,C){return B=="unload"?this.one(B,A,C):this.each(function(){T.event.add(this,B,C||A,C&&A);
+});
+},one:function(B,A,C){var D=T.event.proxy(C||A,function(a){T(this).unbind(a,D);
+return(C||A).apply(this,arguments);
+});
+return this.each(function(){T.event.add(this,B,D,C&&A);
+});
+},unbind:function(A,B){return this.each(function(){T.event.remove(this,A,B);
+});
+},trigger:function(B,A){return this.each(function(){T.event.trigger(B,A,this);
+});
+},triggerHandler:function(C,A){if(this[0]){var B=T.Event(C);
+B.preventDefault();
+B.stopPropagation();
+T.event.trigger(B,A,this[0]);
+return B.result;
+}},toggle:function(A){var C=arguments,B=1;
+while(B<C.length){T.event.proxy(A,C[B++]);
+}return this.click(T.event.proxy(A,function(D){this.lastToggle=(this.lastToggle||0)%B;
+D.preventDefault();
+return C[this.lastToggle++].apply(this,arguments)||false;
+}));
+},hover:function(B,A){return this.mouseenter(B).mouseleave(A);
+},ready:function(A){P();
+if(T.isReady){A.call(document,T);
+}else{T.readyList.push(A);
+}return this;
+},live:function(A,B){var C=T.event.proxy(B);
+C.guid+=this.selector+A;
+T(document).bind(Z(A,this.selector),this.selector,C);
+return this;
+},die:function(A,B){T(document).unbind(Z(A,this.selector),B?{guid:B.guid+this.selector+A}:null);
+return this;
+}});
+function AF(A){var D=RegExp("(^|\\.)"+A.type+"(\\.|$)"),B=true,C=[];
+T.each(T.data(this,"events").live||[],function(c,b){if(D.test(b.type)){var a=T(A.target).closest(b.data)[0];
+if(a){C.push({elem:a,fn:b});
+}}});
+C.sort(function(a,b){return T.data(a.elem,"closest")-T.data(b.elem,"closest");
+});
+T.each(C,function(){if(this.fn.call(this.elem,A,this.fn.data)===false){return(B=false);
+}});
+return B;
+}function Z(A,B){return["live",A,B.replace(/\./g,"`").replace(/ /g,"|")].join(".");
+}T.extend({isReady:false,readyList:[],ready:function(){if(!T.isReady){T.isReady=true;
+if(T.readyList){T.each(T.readyList,function(){this.call(document,T);
+});
+T.readyList=null;
+}T(document).triggerHandler("ready");
+}}});
+var G=false;
+function P(){if(G){return ;
+}G=true;
+if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);
+T.ready();
+},false);
+}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);
+T.ready();
+}});
+if(document.documentElement.doScroll&&W==W.top){(function(){if(T.isReady){return ;
+}try{document.documentElement.doScroll("left");
+}catch(A){setTimeout(arguments.callee,0);
+return ;
+}T.ready();
+})();
+}}}T.event.add(W,"load",T.ready);
+}T.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(A,B){T.fn[B]=function(C){return C?this.bind(B,C):this.trigger(B);
+};
+});
+T(W).bind("unload",function(){for(var A in T.cache){if(A!=1&&T.cache[A].handle){T.event.remove(T.cache[A].handle.elem);
+}}});
+(function(){T.support={};
+var b=document.documentElement,a=document.createElement("script"),A=document.createElement("div"),B="script"+(new Date).getTime();
+A.style.display="none";
+A.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
+var D=A.getElementsByTagName("*"),c=A.getElementsByTagName("a")[0];
+if(!D||!D.length||!c){return ;
+}T.support={leadingWhitespace:A.firstChild.nodeType==3,tbody:!A.getElementsByTagName("tbody").length,objectAll:!!A.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!A.getElementsByTagName("link").length,style:/red/.test(c.getAttribute("style")),hrefNormalized:c.getAttribute("href")==="/a",opacity:c.style.opacity==="0.5",cssFloat:!!c.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};
+a.type="text/javascript";
+try{a.appendChild(document.createTextNode("window."+B+"=1;"));
+}catch(C){}b.insertBefore(a,b.firstChild);
+if(W[B]){T.support.scriptEval=true;
+delete W[B];
+}b.removeChild(a);
+if(A.attachEvent&&A.fireEvent){A.attachEvent("onclick",function(){T.support.noCloneEvent=false;
+A.detachEvent("onclick",arguments.callee);
+});
+A.cloneNode(true).fireEvent("onclick");
+}T(function(){var d=document.createElement("div");
+d.style.width=d.style.paddingLeft="1px";
+document.body.appendChild(d);
+T.boxModel=T.support.boxModel=d.offsetWidth===2;
+document.body.removeChild(d).style.display="none";
+});
+})();
+var H=T.support.cssFloat?"cssFloat":"styleFloat";
+T.props={"for":"htmlFor","class":"className","float":H,cssFloat:H,styleFloat:H,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};
+T.fn.extend({_load:T.fn.load,load:function(a,B,A){if(typeof a!=="string"){return this._load(a);
+}var C=a.indexOf(" ");
+if(C>=0){var c=a.slice(C,a.length);
+a=a.slice(0,C);
+}var D="GET";
+if(B){if(T.isFunction(B)){A=B;
+B=null;
+}else{if(typeof B==="object"){B=T.param(B);
+D="POST";
+}}}var b=this;
+T.ajax({url:a,type:D,dataType:"html",data:B,complete:function(e,d){if(d=="success"||d=="notmodified"){b.html(c?T("<div/>").append(e.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(c):e.responseText);
+}if(A){b.each(A,[e.responseText,d,e]);
+}}});
+return this;
+},serialize:function(){return T.param(this.serializeArray());
+},serializeArray:function(){return this.map(function(){return this.elements?T.makeArray(this.elements):this;
+}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type));
+}).map(function(C,B){var A=T(this).val();
+return A==null?null:T.isArray(A)?T.map(A,function(D,a){return{name:B.name,value:D};
+}):{name:B.name,value:A};
+}).get();
+}});
+T.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(B,A){T.fn[A]=function(C){return this.bind(A,C);
+};
+});
+var N=AD();
+T.extend({get:function(D,B,A,C){if(T.isFunction(B)){A=B;
+B=null;
+}return T.ajax({type:"GET",url:D,data:B,success:A,dataType:C});
+},getScript:function(B,A){return T.get(B,null,A,"script");
+},getJSON:function(C,B,A){return T.get(C,B,A,"json");
+},post:function(D,B,A,C){if(T.isFunction(B)){A=B;
+B={};
+}return T.ajax({type:"POST",url:D,data:B,success:A,dataType:C});
+},ajaxSetup:function(A){T.extend(T.ajaxSettings,A);
+},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return W.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();
+},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(g){g=T.extend(true,g,T.extend(true,{},T.ajaxSettings,g));
+var A,n=/=\?(&|$)/g,b,B,m=g.type.toUpperCase();
+if(g.data&&g.processData&&typeof g.data!=="string"){g.data=T.param(g.data);
+}if(g.dataType=="jsonp"){if(m=="GET"){if(!g.url.match(n)){g.url+=(g.url.match(/\?/)?"&":"?")+(g.jsonp||"callback")+"=?";
+}}else{if(!g.data||!g.data.match(n)){g.data=(g.data?g.data+"&":"")+(g.jsonp||"callback")+"=?";
+}}g.dataType="json";
+}if(g.dataType=="json"&&(g.data&&g.data.match(n)||g.url.match(n))){A="jsonp"+N++;
+if(g.data){g.data=(g.data+"").replace(n,"="+A+"$1");
+}g.url=g.url.replace(n,"="+A+"$1");
+g.dataType="script";
+W[A]=function(q){B=q;
+k();
+h();
+W[A]=AB;
+try{delete W[A];
+}catch(p){}if(l){l.removeChild(D);
+}};
+}if(g.dataType=="script"&&g.cache==null){g.cache=false;
+}if(g.cache===false&&m=="GET"){var o=AD();
+var C=g.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+o+"$2");
+g.url=C+((C==g.url)?(g.url.match(/\?/)?"&":"?")+"_="+o:"");
+}if(g.data&&m=="GET"){g.url+=(g.url.match(/\?/)?"&":"?")+g.data;
+g.data=null;
+}if(g.global&&!T.active++){T.event.trigger("ajaxStart");
+}var c=/^(\w+:)?\/\/([^\/?#]+)/.exec(g.url);
+if(g.dataType=="script"&&m=="GET"&&c&&(c[1]&&c[1]!=location.protocol||c[2]!=location.host)){var l=document.getElementsByTagName("head")[0];
+var D=document.createElement("script");
+D.src=g.url;
+if(g.scriptCharset){D.charset=g.scriptCharset;
+}if(!A){var e=false;
+D.onload=D.onreadystatechange=function(){if(!e&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){e=true;
+k();
+h();
+D.onload=D.onreadystatechange=null;
+l.removeChild(D);
+}};
+}l.appendChild(D);
+return AB;
+}var i=false;
+var j=g.xhr();
+if(g.username){j.open(m,g.url,g.async,g.username,g.password);
+}else{j.open(m,g.url,g.async);
+}try{if(g.data){j.setRequestHeader("Content-Type",g.contentType);
+}if(g.ifModified){j.setRequestHeader("If-Modified-Since",T.lastModified[g.url]||"Thu, 01 Jan 1970 00:00:00 GMT");
+}j.setRequestHeader("X-Requested-With","XMLHttpRequest");
+j.setRequestHeader("Accept",g.dataType&&g.accepts[g.dataType]?g.accepts[g.dataType]+", */*":g.accepts._default);
+}catch(a){}if(g.beforeSend&&g.beforeSend(j,g)===false){if(g.global&&!--T.active){T.event.trigger("ajaxStop");
+}j.abort();
+return false;
+}if(g.global){T.event.trigger("ajaxSend",[j,g]);
+}var f=function(r){if(j.readyState==0){if(d){clearInterval(d);
+d=null;
+if(g.global&&!--T.active){T.event.trigger("ajaxStop");
+}}}else{if(!i&&j&&(j.readyState==4||r=="timeout")){i=true;
+if(d){clearInterval(d);
+d=null;
+}b=r=="timeout"?"timeout":!T.httpSuccess(j)?"error":g.ifModified&&T.httpNotModified(j,g.url)?"notmodified":"success";
+if(b=="success"){try{B=T.httpData(j,g.dataType,g);
+}catch(p){b="parsererror";
+}}if(b=="success"){var q;
+try{q=j.getResponseHeader("Last-Modified");
+}catch(p){}if(g.ifModified&&q){T.lastModified[g.url]=q;
+}if(!A){k();
+}}else{T.handleError(g,j,b);
+}h();
+if(r){j.abort();
+}if(g.async){j=null;
+}}}};
+if(g.async){var d=setInterval(f,13);
+if(g.timeout>0){setTimeout(function(){if(j&&!i){f("timeout");
+}},g.timeout);
+}}try{j.send(g.data);
+}catch(a){T.handleError(g,j,null,a);
+}if(!g.async){f();
+}function k(){if(g.success){g.success(B,b);
+}if(g.global){T.event.trigger("ajaxSuccess",[j,g]);
+}}function h(){if(g.complete){g.complete(j,b);
+}if(g.global){T.event.trigger("ajaxComplete",[j,g]);
+}if(g.global&&!--T.active){T.event.trigger("ajaxStop");
+}}return j;
+},handleError:function(C,A,D,B){if(C.error){C.error(A,D,B);
+}if(C.global){T.event.trigger("ajaxError",[A,C,B]);
+}},active:0,httpSuccess:function(A){try{return !A.status&&location.protocol=="file:"||(A.status>=200&&A.status<300)||A.status==304||A.status==1223;
+}catch(B){}return false;
+},httpNotModified:function(B,D){try{var A=B.getResponseHeader("Last-Modified");
+return B.status==304||A==T.lastModified[D];
+}catch(C){}return false;
+},httpData:function(A,C,D){var a=A.getResponseHeader("content-type"),b=C=="xml"||!C&&a&&a.indexOf("xml")>=0,B=b?A.responseXML:A.responseText;
+if(b&&B.documentElement.tagName=="parsererror"){throw"parsererror";
+}if(D&&D.dataFilter){B=D.dataFilter(B,C);
+}if(typeof B==="string"){if(C=="script"){T.globalEval(B);
+}if(C=="json"){B=W["eval"]("("+B+")");
+}}return B;
+},param:function(D){var B=[];
+function A(b,a){B[B.length]=encodeURIComponent(b)+"="+encodeURIComponent(a);
+}if(T.isArray(D)||D.jquery){T.each(D,function(){A(this.name,this.value);
+});
+}else{for(var C in D){if(T.isArray(D[C])){T.each(D[C],function(){A(C,this);
+});
+}else{A(C,T.isFunction(D[C])?D[C]():D[C]);
+}}}return B.join("&").replace(/%20/g,"+");
+}});
+var V={},U,AE=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];
+function K(B,C){var A={};
+T.each(AE.concat.apply([],AE.slice(0,C)),function(){A[this]=B;
+});
+return A;
+}T.fn.extend({show:function(C,A){if(C){return this.animate(K("show",3),C,A);
+}else{for(var a=0,c=this.length;
+a<c;
+a++){var d=T.data(this[a],"olddisplay");
+this[a].style.display=d||"";
+if(T.css(this[a],"display")==="none"){var b=this[a].tagName,B;
+if(V[b]){B=V[b];
+}else{var D=T("<"+b+" />").appendTo("body");
+B=D.css("display");
+if(B==="none"){B="block";
+}D.remove();
+V[b]=B;
+}T.data(this[a],"olddisplay",B);
+}}for(var a=0,c=this.length;
+a<c;
+a++){this[a].style.display=T.data(this[a],"olddisplay")||"";
+}return this;
+}},hide:function(B,A){if(B){return this.animate(K("hide",3),B,A);
+}else{for(var C=0,D=this.length;
+C<D;
+C++){var a=T.data(this[C],"olddisplay");
+if(!a&&a!=="none"){T.data(this[C],"olddisplay",T.css(this[C],"display"));
+}}for(var C=0,D=this.length;
+C<D;
+C++){this[C].style.display="none";
+}return this;
+}},_toggle:T.fn.toggle,toggle:function(A,B){var C=typeof A==="boolean";
+return T.isFunction(A)&&T.isFunction(B)?this._toggle.apply(this,arguments):A==null||C?this.each(function(){var D=C?A:T(this).is(":hidden");
+T(this)[D?"show":"hide"]();
+}):this.animate(K("toggle",3),A,B);
+},fadeTo:function(C,A,B){return this.animate({opacity:A},C,B);
+},animate:function(A,D,B,C){var a=T.speed(D,B,C);
+return this[a.queue===false?"each":"queue"](function(){var c=T.extend({},a),e,b=this.nodeType==1&&T(this).is(":hidden"),d=this;
+for(e in A){if(A[e]=="hide"&&b||A[e]=="show"&&!b){return c.complete.call(this);
+}if((e=="height"||e=="width")&&this.style){c.display=T.css(this,"display");
+c.overflow=this.style.overflow;
+}}if(c.overflow!=null){this.style.overflow="hidden";
+}c.curAnim=T.extend({},A);
+T.each(A,function(k,g){var h=new T.fx(d,c,k);
+if(/toggle|show|hide/.test(g)){h[g=="toggle"?b?"show":"hide":g](A);
+}else{var i=g.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),f=h.cur(true)||0;
+if(i){var l=parseFloat(i[2]),j=i[3]||"px";
+if(j!="px"){d.style[k]=(l||1)+j;
+f=((l||1)/h.cur(true))*f;
+d.style[k]=f+j;
+}if(i[1]){l=((i[1]=="-="?-1:1)*l)+f;
+}h.custom(f,l,j);
+}else{h.custom(f,g,"");
+}}});
+return true;
+});
+},stop:function(B,C){var A=T.timers;
+if(B){this.queue([]);
+}this.each(function(){for(var D=A.length-1;
+D>=0;
+D--){if(A[D].elem==this){if(C){A[D](true);
+}A.splice(D,1);
+}}});
+if(!C){this.dequeue();
+}return this;
+}});
+T.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(B,A){T.fn[B]=function(D,C){return this.animate(A,D,C);
+};
+});
+T.extend({speed:function(B,A,C){var D=typeof B==="object"?B:{complete:C||!C&&A||T.isFunction(B)&&B,duration:B,easing:C&&A||A&&!T.isFunction(A)&&A};
+D.duration=T.fx.off?0:typeof D.duration==="number"?D.duration:T.fx.speeds[D.duration]||T.fx.speeds._default;
+D.old=D.complete;
+D.complete=function(){if(D.queue!==false){T(this).dequeue();
+}if(T.isFunction(D.old)){D.old.call(this);
+}};
+return D;
+},easing:{linear:function(B,A,D,C){return D+C*B;
+},swing:function(B,A,D,C){return((-Math.cos(B*Math.PI)/2)+0.5)*C+D;
+}},timers:[],fx:function(B,C,A){this.options=C;
+this.elem=B;
+this.prop=A;
+if(!C.orig){C.orig={};
+}}});
+T.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this);
+}(T.fx.step[this.prop]||T.fx.step._default)(this);
+if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block";
+}},cur:function(A){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop];
+}var B=parseFloat(T.css(this.elem,this.prop,A));
+return B&&B>-10000?B:parseFloat(T.curCSS(this.elem,this.prop))||0;
+},custom:function(A,B,C){this.startTime=AD();
+this.start=A;
+this.end=B;
+this.unit=C||this.unit||"px";
+this.now=this.start;
+this.pos=this.state=0;
+var a=this;
+function D(b){return a.step(b);
+}D.elem=this.elem;
+if(D()&&T.timers.push(D)&&!U){U=setInterval(function(){var b=T.timers;
+for(var c=0;
+c<b.length;
+c++){if(!b[c]()){b.splice(c--,1);
+}}if(!b.length){clearInterval(U);
+U=AB;
+}},13);
+}},show:function(){this.options.orig[this.prop]=T.attr(this.elem.style,this.prop);
+this.options.show=true;
+this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());
+T(this.elem).show();
+},hide:function(){this.options.orig[this.prop]=T.attr(this.elem.style,this.prop);
+this.options.hide=true;
+this.custom(this.cur(),0);
+},step:function(C){var D=AD();
+if(C||D>=this.options.duration+this.startTime){this.now=this.end;
+this.pos=this.state=1;
+this.update();
+this.options.curAnim[this.prop]=true;
+var b=true;
+for(var a in this.options.curAnim){if(this.options.curAnim[a]!==true){b=false;
+}}if(b){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;
+this.elem.style.display=this.options.display;
+if(T.css(this.elem,"display")=="none"){this.elem.style.display="block";
+}}if(this.options.hide){T(this.elem).hide();
+}if(this.options.hide||this.options.show){for(var B in this.options.curAnim){T.attr(this.elem.style,B,this.options.orig[B]);
+}}this.options.complete.call(this.elem);
+}return false;
+}else{var A=D-this.startTime;
+this.state=A/this.options.duration;
+this.pos=T.easing[this.options.easing||(T.easing.swing?"swing":"linear")](this.state,A,0,1,this.options.duration);
+this.now=this.start+((this.end-this.start)*this.pos);
+this.update();
+}return true;
+}};
+T.extend(T.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(A){T.attr(A.elem.style,"opacity",A.now);
+},_default:function(A){if(A.elem.style&&A.elem.style[A.prop]!=null){A.elem.style[A.prop]=A.now+A.unit;
+}else{A.elem[A.prop]=A.now;
+}}}});
+if(document.documentElement.getBoundingClientRect){T.fn.offset=function(){if(!this[0]){return{top:0,left:0};
+}if(this[0]===this[0].ownerDocument.body){return T.offset.bodyOffset(this[0]);
+}var b=this[0].getBoundingClientRect(),C=this[0].ownerDocument,c=C.body,d=C.documentElement,A=d.clientTop||c.clientTop||0,B=d.clientLeft||c.clientLeft||0,D=b.top+(self.pageYOffset||T.boxModel&&d.scrollTop||c.scrollTop)-A,a=b.left+(self.pageXOffset||T.boxModel&&d.scrollLeft||c.scrollLeft)-B;
+return{top:D,left:a};
+};
+}else{T.fn.offset=function(){if(!this[0]){return{top:0,left:0};
+}if(this[0]===this[0].ownerDocument.body){return T.offset.bodyOffset(this[0]);
+}T.offset.initialized||T.offset.initialize();
+var b=this[0],e=b.offsetParent,f=b,A=b.ownerDocument,C,d=A.documentElement,a=A.body,D=A.defaultView,g=D.getComputedStyle(b,null),B=b.offsetTop,c=b.offsetLeft;
+while((b=b.parentNode)&&b!==a&&b!==d){C=D.getComputedStyle(b,null);
+B-=b.scrollTop,c-=b.scrollLeft;
+if(b===e){B+=b.offsetTop,c+=b.offsetLeft;
+if(T.offset.doesNotAddBorder&&!(T.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.tagName))){B+=parseInt(C.borderTopWidth,10)||0,c+=parseInt(C.borderLeftWidth,10)||0;
+}f=e,e=b.offsetParent;
+}if(T.offset.subtractsBorderForOverflowNotVisible&&C.overflow!=="visible"){B+=parseInt(C.borderTopWidth,10)||0,c+=parseInt(C.borderLeftWidth,10)||0;
+}g=C;
+}if(g.position==="relative"||g.position==="static"){B+=a.offsetTop,c+=a.offsetLeft;
+}if(g.position==="fixed"){B+=Math.max(d.scrollTop,a.scrollTop),c+=Math.max(d.scrollLeft,a.scrollLeft);
+}return{top:B,left:c};
+};
+}T.offset={initialize:function(){if(this.initialized){return ;
+}var C=document.body,e=document.createElement("div"),c,d,A,b,B,f,a=C.style.marginTop,D='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
+B={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};
+for(f in B){e.style[f]=B[f];
+}e.innerHTML=D;
+C.insertBefore(e,C.firstChild);
+c=e.firstChild,d=c.firstChild,b=c.nextSibling.firstChild.firstChild;
+this.doesNotAddBorder=(d.offsetTop!==5);
+this.doesAddBorderForTableAndCells=(b.offsetTop===5);
+c.style.overflow="hidden",c.style.position="relative";
+this.subtractsBorderForOverflowNotVisible=(d.offsetTop===-5);
+C.style.marginTop="1px";
+this.doesNotIncludeMarginInBodyOffset=(C.offsetTop===0);
+C.style.marginTop=a;
+C.removeChild(e);
+this.initialized=true;
+},bodyOffset:function(C){T.offset.initialized||T.offset.initialize();
+var A=C.offsetTop,B=C.offsetLeft;
+if(T.offset.doesNotIncludeMarginInBodyOffset){A+=parseInt(T.curCSS(C,"marginTop",true),10)||0,B+=parseInt(T.curCSS(C,"marginLeft",true),10)||0;
+}return{top:A,left:B};
+}};
+T.fn.extend({position:function(){var B=0,C=0,a;
+if(this[0]){var D=this.offsetParent(),A=this.offset(),b=/^body|html$/i.test(D[0].tagName)?{top:0,left:0}:D.offset();
+A.top-=Y(this,"marginTop");
+A.left-=Y(this,"marginLeft");
+b.top+=Y(D,"borderTopWidth");
+b.left+=Y(D,"borderLeftWidth");
+a={top:A.top-b.top,left:A.left-b.left};
+}return a;
+},offsetParent:function(){var A=this[0].offsetParent||document.body;
+while(A&&(!/^body|html$/i.test(A.tagName)&&T.css(A,"position")=="static")){A=A.offsetParent;
+}return T(A);
+}});
+T.each(["Left","Top"],function(B,C){var A="scroll"+C;
+T.fn[A]=function(D){if(!this[0]){return null;
+}return D!==AB?this.each(function(){this==W||this==document?W.scrollTo(!B?D:T(W).scrollLeft(),B?D:T(W).scrollTop()):this[A]=D;
+}):this[0]==W||this[0]==document?self[B?"pageYOffset":"pageXOffset"]||T.boxModel&&document.documentElement[A]||document.body[A]:this[0][A];
+};
+});
+T.each(["Height","Width"],function(B,D){var b=B?"Left":"Top",C=B?"Right":"Bottom",a=D.toLowerCase();
+T.fn["inner"+D]=function(){return this[0]?T.css(this[0],a,false,"padding"):null;
+};
+T.fn["outer"+D]=function(c){return this[0]?T.css(this[0],a,false,c?"margin":"border"):null;
+};
+var A=D.toLowerCase();
+T.fn[A]=function(c){return this[0]==W?document.compatMode=="CSS1Compat"&&document.documentElement["client"+D]||document.body["client"+D]:this[0]==document?Math.max(document.documentElement["client"+D],document.body["scroll"+D],document.documentElement["scroll"+D],document.body["offset"+D],document.documentElement["offset"+D]):c===AB?(this.length?T.css(this[0],A):null):this.css(A,typeof c==="string"?c:c+"px");
+};
+});
+})();
+}
+
+/* platform.js */
+SimileAjax.version="2.2.1";
+SimileAjax.jQuery=jQuery.noConflict(true);
+if(typeof window["$"]=="undefined"){window.$=SimileAjax.jQuery;
+}SimileAjax.Platform.os={isMac:false,isWin:false,isWin32:false,isUnix:false};
+SimileAjax.Platform.browser={isIE:false,isNetscape:false,isMozilla:false,isFirefox:false,isOpera:false,isSafari:false,majorVersion:0,minorVersion:0};
+(function(){var C=navigator.appName.toLowerCase();
+var A=navigator.userAgent.toLowerCase();
+SimileAjax.Platform.os.isMac=(A.indexOf("mac")!=-1);
+SimileAjax.Platform.os.isWin=(A.indexOf("win")!=-1);
+SimileAjax.Platform.os.isWin32=SimileAjax.Platform.isWin&&(A.indexOf("95")!=-1||A.indexOf("98")!=-1||A.indexOf("nt")!=-1||A.indexOf("win32")!=-1||A.indexOf("32bit")!=-1);
+SimileAjax.Platform.os.isUnix=(A.indexOf("x11")!=-1);
+SimileAjax.Platform.browser.isIE=(C.indexOf("microsoft")!=-1);
+SimileAjax.Platform.browser.isNetscape=(C.indexOf("netscape")!=-1);
+SimileAjax.Platform.browser.isMozilla=(A.indexOf("mozilla")!=-1);
+SimileAjax.Platform.browser.isFirefox=(A.indexOf("firefox")!=-1);
+SimileAjax.Platform.browser.isOpera=(C.indexOf("opera")!=-1);
+SimileAjax.Platform.browser.isSafari=(C.indexOf("safari")!=-1);
+var E=function(G){var F=G.split(".");
+SimileAjax.Platform.browser.majorVersion=parseInt(F[0]);
+SimileAjax.Platform.browser.minorVersion=parseInt(F[1]);
+};
+var B=function(H,G,I){var F=H.indexOf(G,I);
+return F>=0?F:H.length;
+};
+if(SimileAjax.Platform.browser.isMozilla){var D=A.indexOf("mozilla/");
+if(D>=0){E(A.substring(D+8,B(A," ",D)));
+}}if(SimileAjax.Platform.browser.isIE){var D=A.indexOf("msie ");
+if(D>=0){E(A.substring(D+5,B(A,";",D)));
+}}if(SimileAjax.Platform.browser.isNetscape){var D=A.indexOf("rv:");
+if(D>=0){E(A.substring(D+3,B(A,")",D)));
+}}if(SimileAjax.Platform.browser.isFirefox){var D=A.indexOf("firefox/");
+if(D>=0){E(A.substring(D+8,B(A," ",D)));
+}}if(!("localeCompare" in String.prototype)){String.prototype.localeCompare=function(F){if(this<F){return -1;
+}else{if(this>F){return 1;
+}else{return 0;
+}}};
+}})();
+SimileAjax.Platform.getDefaultLocale=function(){return SimileAjax.Platform.clientLocale;
+};
+
+
+/* ajax.js */
+SimileAjax.ListenerQueue=function(A){this._listeners=[];
+this._wildcardHandlerName=A;
+};
+SimileAjax.ListenerQueue.prototype.add=function(A){this._listeners.push(A);
+};
+SimileAjax.ListenerQueue.prototype.remove=function(C){var B=this._listeners;
+for(var A=0;
+A<B.length;
+A++){if(B[A]==C){B.splice(A,1);
+break;
+}}};
+SimileAjax.ListenerQueue.prototype.fire=function(B,A){var D=[].concat(this._listeners);
+for(var C=0;
+C<D.length;
+C++){var E=D[C];
+if(B in E){try{E[B].apply(E,A);
+}catch(F){SimileAjax.Debug.exception("Error firing event of name "+B,F);
+}}else{if(this._wildcardHandlerName!=null&&this._wildcardHandlerName in E){try{E[this._wildcardHandlerName].apply(E,[B]);
+}catch(F){SimileAjax.Debug.exception("Error firing event of name "+B+" to wildcard handler",F);
+}}}}};
+
+
+/* data-structure.js */
+SimileAjax.Set=function(A){this._hash={};
+this._count=0;
+if(A instanceof Array){for(var B=0;
+B<A.length;
+B++){this.add(A[B]);
+}}else{if(A instanceof SimileAjax.Set){this.addSet(A);
+}}};
+SimileAjax.Set.prototype.add=function(A){if(!(A in this._hash)){this._hash[A]=true;
+this._count++;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.addSet=function(B){for(var A in B._hash){this.add(A);
+}};
+SimileAjax.Set.prototype.remove=function(A){if(A in this._hash){delete this._hash[A];
+this._count--;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.removeSet=function(B){for(var A in B._hash){this.remove(A);
+}};
+SimileAjax.Set.prototype.retainSet=function(B){for(var A in this._hash){if(!B.contains(A)){delete this._hash[A];
+this._count--;
+}}};
+SimileAjax.Set.prototype.contains=function(A){return(A in this._hash);
+};
+SimileAjax.Set.prototype.size=function(){return this._count;
+};
+SimileAjax.Set.prototype.toArray=function(){var A=[];
+for(var B in this._hash){A.push(B);
+}return A;
+};
+SimileAjax.Set.prototype.visit=function(A){for(var B in this._hash){if(A(B)==true){break;
+}}};
+SimileAjax.SortedArray=function(B,A){this._a=(A instanceof Array)?A:[];
+this._compare=B;
+};
+SimileAjax.SortedArray.prototype.add=function(C){var A=this;
+var B=this.find(function(D){return A._compare(D,C);
+});
+if(B<this._a.length){this._a.splice(B,0,C);
+}else{this._a.push(C);
+}};
+SimileAjax.SortedArray.prototype.remove=function(C){var A=this;
+var B=this.find(function(D){return A._compare(D,C);
+});
+while(B<this._a.length&&this._compare(this._a[B],C)==0){if(this._a[B]==C){this._a.splice(B,1);
+return true;
+}else{B++;
+}}return false;
+};
+SimileAjax.SortedArray.prototype.removeAll=function(){this._a=[];
+};
+SimileAjax.SortedArray.prototype.elementAt=function(A){return this._a[A];
+};
+SimileAjax.SortedArray.prototype.length=function(){return this._a.length;
+};
+SimileAjax.SortedArray.prototype.find=function(D){var B=0;
+var A=this._a.length;
+while(B<A){var C=Math.floor((B+A)/2);
+var E=D(this._a[C]);
+if(C==B){return E<0?B+1:B;
+}else{if(E<0){B=C;
+}else{A=C;
+}}}return B;
+};
+SimileAjax.SortedArray.prototype.getFirst=function(){return(this._a.length>0)?this._a[0]:null;
+};
+SimileAjax.SortedArray.prototype.getLast=function(){return(this._a.length>0)?this._a[this._a.length-1]:null;
+};
+SimileAjax.EventIndex=function(B){var A=this;
+this._unit=(B!=null)?B:SimileAjax.NativeDateUnit;
+this._events=new SimileAjax.SortedArray(function(D,C){return A._unit.compare(D.getStart(),C.getStart());
+});
+this._idToEvent={};
+this._indexed=true;
+};
+SimileAjax.EventIndex.prototype.getUnit=function(){return this._unit;
+};
+SimileAjax.EventIndex.prototype.getEvent=function(A){return this._idToEvent[A];
+};
+SimileAjax.EventIndex.prototype.add=function(A){this._events.add(A);
+this._idToEvent[A.getID()]=A;
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.removeAll=function(){this._events.removeAll();
+this._idToEvent={};
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.getCount=function(){return this._events.length();
+};
+SimileAjax.EventIndex.prototype.getIterator=function(A,B){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._Iterator(this._events,A,B,this._unit);
+};
+SimileAjax.EventIndex.prototype.getReverseIterator=function(A,B){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._ReverseIterator(this._events,A,B,this._unit);
+};
+SimileAjax.EventIndex.prototype.getAllIterator=function(){return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+SimileAjax.EventIndex.prototype.getEarliestDate=function(){var A=this._events.getFirst();
+return(A==null)?null:A.getStart();
+};
+SimileAjax.EventIndex.prototype.getLatestDate=function(){var A=this._events.getLast();
+if(A==null){return null;
+}if(!this._indexed){this._index();
+}var C=A._earliestOverlapIndex;
+var B=this._events.elementAt(C).getEnd();
+for(var D=C+1;
+D<this._events.length();
+D++){B=this._unit.later(B,this._events.elementAt(D).getEnd());
+}return B;
+};
+SimileAjax.EventIndex.prototype._index=function(){var D=this._events.length();
+for(var E=0;
+E<D;
+E++){var C=this._events.elementAt(E);
+C._earliestOverlapIndex=E;
+}var G=1;
+for(var E=0;
+E<D;
+E++){var C=this._events.elementAt(E);
+var B=C.getEnd();
+G=Math.max(G,E+1);
+while(G<D){var A=this._events.elementAt(G);
+var F=A.getStart();
+if(this._unit.compare(F,B)<0){A._earliestOverlapIndex=E;
+G++;
+}else{break;
+}}}this._indexed=true;
+};
+SimileAjax.EventIndex._Iterator=function(B,A,D,C){this._events=B;
+this._startDate=A;
+this._endDate=D;
+this._unit=C;
+this._currentIndex=B.find(function(E){return C.compare(E.getStart(),A);
+});
+if(this._currentIndex-1>=0){this._currentIndex=this._events.elementAt(this._currentIndex-1)._earliestOverlapIndex;
+}this._currentIndex--;
+this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
+});
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._Iterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var A=this._next;
+this._findNext();
+return A;
+}else{return null;
+}},_findNext:function(){var B=this._unit;
+while((++this._currentIndex)<this._maxIndex){var A=this._events.elementAt(this._currentIndex);
+if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._ReverseIterator=function(B,A,D,C){this._events=B;
+this._startDate=A;
+this._endDate=D;
+this._unit=C;
+this._minIndex=B.find(function(E){return C.compare(E.getStart(),A);
+});
+if(this._minIndex-1>=0){this._minIndex=this._events.elementAt(this._minIndex-1)._earliestOverlapIndex;
+}this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
+});
+this._currentIndex=this._maxIndex;
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._ReverseIterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var A=this._next;
+this._findNext();
+return A;
+}else{return null;
+}},_findNext:function(){var B=this._unit;
+while((--this._currentIndex)>=this._minIndex){var A=this._events.elementAt(this._currentIndex);
+if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._AllIterator=function(A){this._events=A;
+this._index=0;
+};
+SimileAjax.EventIndex._AllIterator.prototype={hasNext:function(){return this._index<this._events.length();
+},next:function(){return this._index<this._events.length()?this._events.elementAt(this._index++):null;
+}};
+
+
+/* date-time.js */
+SimileAjax.DateTime=new Object();
+SimileAjax.DateTime.MILLISECOND=0;
+SimileAjax.DateTime.SECOND=1;
+SimileAjax.DateTime.MINUTE=2;
+SimileAjax.DateTime.HOUR=3;
+SimileAjax.DateTime.DAY=4;
+SimileAjax.DateTime.WEEK=5;
+SimileAjax.DateTime.MONTH=6;
+SimileAjax.DateTime.YEAR=7;
+SimileAjax.DateTime.DECADE=8;
+SimileAjax.DateTime.CENTURY=9;
+SimileAjax.DateTime.MILLENNIUM=10;
+SimileAjax.DateTime.EPOCH=-1;
+SimileAjax.DateTime.ERA=-2;
+SimileAjax.DateTime.gregorianUnitLengths=[];
+(function(){var B=SimileAjax.DateTime;
+var A=B.gregorianUnitLengths;
+A[B.MILLISECOND]=1;
+A[B.SECOND]=1000;
+A[B.MINUTE]=A[B.SECOND]*60;
+A[B.HOUR]=A[B.MINUTE]*60;
+A[B.DAY]=A[B.HOUR]*24;
+A[B.WEEK]=A[B.DAY]*7;
+A[B.MONTH]=A[B.DAY]*31;
+A[B.YEAR]=A[B.DAY]*365;
+A[B.DECADE]=A[B.YEAR]*10;
+A[B.CENTURY]=A[B.YEAR]*100;
+A[B.MILLENNIUM]=A[B.YEAR]*1000;
+})();
+SimileAjax.DateTime._dateRegexp=new RegExp("^(-?)([0-9]{4})("+["(-?([0-9]{2})(-?([0-9]{2}))?)","(-?([0-9]{3}))","(-?W([0-9]{2})(-?([1-7]))?)"].join("|")+")?$");
+SimileAjax.DateTime._timezoneRegexp=new RegExp("Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$");
+SimileAjax.DateTime._timeRegexp=new RegExp("^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$");
+SimileAjax.DateTime.setIso8601Date=function(H,F){var I=F.match(SimileAjax.DateTime._dateRegexp);
+if(!I){throw new Error("Invalid date string: "+F);
+}var B=(I[1]=="-")?-1:1;
+var J=B*I[2];
+var G=I[5];
+var C=I[7];
+var E=I[9];
+var A=I[11];
+var M=(I[13])?I[13]:1;
+H.setUTCFullYear(J);
+if(E){H.setUTCMonth(0);
+H.setUTCDate(Number(E));
+}else{if(A){H.setUTCMonth(0);
+H.setUTCDate(1);
+var L=H.getUTCDay();
+var K=(L)?L:7;
+var D=Number(M)+(7*Number(A));
+if(K<=4){H.setUTCDate(D+1-K);
+}else{H.setUTCDate(D+8-K);
+}}else{if(G){H.setUTCDate(1);
+H.setUTCMonth(G-1);
+}if(C){H.setUTCDate(C);
+}}}return H;
+};
+SimileAjax.DateTime.setIso8601Time=function(F,C){var G=C.match(SimileAjax.DateTime._timeRegexp);
+if(!G){SimileAjax.Debug.warn("Invalid time string: "+C);
+return false;
+}var A=G[1];
+var E=Number((G[3])?G[3]:0);
+var D=(G[5])?G[5]:0;
+var B=G[7]?(Number("0."+G[7])*1000):0;
+F.setUTCHours(A);
+F.setUTCMinutes(E);
+F.setUTCSeconds(D);
+F.setUTCMilliseconds(B);
+return F;
+};
+SimileAjax.DateTime.timezoneOffset=new Date().getTimezoneOffset();
+SimileAjax.DateTime.setIso8601=function(B,A){var D=null;
+var E=(A.indexOf("T")==-1)?A.split(" "):A.split("T");
+SimileAjax.DateTime.setIso8601Date(B,E[0]);
+if(E.length==2){var C=E[1].match(SimileAjax.DateTime._timezoneRegexp);
+if(C){if(C[0]=="Z"){D=0;
+}else{D=(Number(C[3])*60)+Number(C[5]);
+D*=((C[2]=="-")?1:-1);
+}E[1]=E[1].substr(0,E[1].length-C[0].length);
+}SimileAjax.DateTime.setIso8601Time(B,E[1]);
+}if(D==null){D=B.getTimezoneOffset();
+}B.setTime(B.getTime()+D*60000);
+return B;
+};
+SimileAjax.DateTime.parseIso8601DateTime=function(A){try{return SimileAjax.DateTime.setIso8601(new Date(0),A);
+}catch(B){return null;
+}};
+SimileAjax.DateTime.parseGregorianDateTime=function(G){if(G==null){return null;
+}else{if(G instanceof Date){return G;
+}}var B=G.toString();
+if(B.length>0&&B.length<8){var C=B.indexOf(" ");
+if(C>0){var A=parseInt(B.substr(0,C));
+var E=B.substr(C+1);
+if(E.toLowerCase()=="bc"){A=1-A;
+}}else{var A=parseInt(B);
+}var F=new Date(0);
+F.setUTCFullYear(A);
+return F;
+}try{return new Date(Date.parse(B));
+}catch(D){return null;
+}};
+SimileAjax.DateTime.roundDownToInterval=function(B,G,J,K,A){var D=J*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var I=new Date(B.getTime()+D);
+var E=function(L){L.setUTCMilliseconds(0);
+L.setUTCSeconds(0);
+L.setUTCMinutes(0);
+L.setUTCHours(0);
+};
+var C=function(L){E(L);
+L.setUTCDate(1);
+L.setUTCMonth(0);
+};
+switch(G){case SimileAjax.DateTime.MILLISECOND:var H=I.getUTCMilliseconds();
+I.setUTCMilliseconds(H-(H%K));
+break;
+case SimileAjax.DateTime.SECOND:I.setUTCMilliseconds(0);
+var H=I.getUTCSeconds();
+I.setUTCSeconds(H-(H%K));
+break;
+case SimileAjax.DateTime.MINUTE:I.setUTCMilliseconds(0);
+I.setUTCSeconds(0);
+var H=I.getUTCMinutes();
+I.setTime(I.getTime()-(H%K)*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:I.setUTCMilliseconds(0);
+I.setUTCSeconds(0);
+I.setUTCMinutes(0);
+var H=I.getUTCHours();
+I.setUTCHours(H-(H%K));
+break;
+case SimileAjax.DateTime.DAY:E(I);
+break;
+case SimileAjax.DateTime.WEEK:E(I);
+var F=(I.getUTCDay()+7-A)%7;
+I.setTime(I.getTime()-F*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+break;
+case SimileAjax.DateTime.MONTH:E(I);
+I.setUTCDate(1);
+var H=I.getUTCMonth();
+I.setUTCMonth(H-(H%K));
+break;
+case SimileAjax.DateTime.YEAR:C(I);
+var H=I.getUTCFullYear();
+I.setUTCFullYear(H-(H%K));
+break;
+case SimileAjax.DateTime.DECADE:C(I);
+I.setUTCFullYear(Math.floor(I.getUTCFullYear()/10)*10);
+break;
+case SimileAjax.DateTime.CENTURY:C(I);
+I.setUTCFullYear(Math.floor(I.getUTCFullYear()/100)*100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:C(I);
+I.setUTCFullYear(Math.floor(I.getUTCFullYear()/1000)*1000);
+break;
+}B.setTime(I.getTime()-D);
+};
+SimileAjax.DateTime.roundUpToInterval=function(D,F,C,A,B){var E=D.getTime();
+SimileAjax.DateTime.roundDownToInterval(D,F,C,A,B);
+if(D.getTime()<E){D.setTime(D.getTime()+SimileAjax.DateTime.gregorianUnitLengths[F]*A);
+}};
+SimileAjax.DateTime.incrementByInterval=function(B,E,A){A=(typeof A=="undefined")?0:A;
+var D=A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var C=new Date(B.getTime()+D);
+switch(E){case SimileAjax.DateTime.MILLISECOND:C.setTime(C.getTime()+1);
+break;
+case SimileAjax.DateTime.SECOND:C.setTime(C.getTime()+1000);
+break;
+case SimileAjax.DateTime.MINUTE:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+break;
+case SimileAjax.DateTime.DAY:C.setUTCDate(C.getUTCDate()+1);
+break;
+case SimileAjax.DateTime.WEEK:C.setUTCDate(C.getUTCDate()+7);
+break;
+case SimileAjax.DateTime.MONTH:C.setUTCMonth(C.getUTCMonth()+1);
+break;
+case SimileAjax.DateTime.YEAR:C.setUTCFullYear(C.getUTCFullYear()+1);
+break;
+case SimileAjax.DateTime.DECADE:C.setUTCFullYear(C.getUTCFullYear()+10);
+break;
+case SimileAjax.DateTime.CENTURY:C.setUTCFullYear(C.getUTCFullYear()+100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:C.setUTCFullYear(C.getUTCFullYear()+1000);
+break;
+}B.setTime(C.getTime()-D);
+};
+SimileAjax.DateTime.removeTimeZoneOffset=function(B,A){return new Date(B.getTime()+A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+SimileAjax.DateTime.getTimezone=function(){var A=new Date().getTimezoneOffset();
+return A/-60;
+};
+
+
+/* debug.js */
+SimileAjax.Debug={silent:false};
+SimileAjax.Debug.log=function(B){var A;
+if("console" in window&&"log" in window.console){A=function(C){console.log(C);
+};
+}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
+}};
+}SimileAjax.Debug.log=A;
+A(B);
+};
+SimileAjax.Debug.warn=function(B){var A;
+if("console" in window&&"warn" in window.console){A=function(C){console.warn(C);
+};
+}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
+}};
+}SimileAjax.Debug.warn=A;
+A(B);
+};
+SimileAjax.Debug.exception=function(B,D){var A,C=SimileAjax.parseURLParameters();
+if(C.errors=="throw"||SimileAjax.params.errors=="throw"){A=function(F,E){throw (F);
+};
+}else{if("console" in window&&"error" in window.console){A=function(F,E){if(E!=null){console.error(E+" %o",F);
+}else{console.error(F);
+}throw (F);
+};
+}else{A=function(F,E){if(!SimileAjax.Debug.silent){alert("Caught exception: "+E+"\n\nDetails: "+("description" in F?F.description:F));
+}throw (F);
+};
+}}SimileAjax.Debug.exception=A;
+A(B,D);
+};
+SimileAjax.Debug.objectToString=function(A){return SimileAjax.Debug._objectToString(A,"");
+};
+SimileAjax.Debug._objectToString=function(D,A){var C=A+" ";
+if(typeof D=="object"){var B="{";
+for(E in D){B+=C+E+": "+SimileAjax.Debug._objectToString(D[E],C)+"\n";
+}B+=A+"}";
+return B;
+}else{if(typeof D=="array"){var B="[";
+for(var E=0;
+E<D.length;
+E++){B+=SimileAjax.Debug._objectToString(D[E],C)+"\n";
+}B+=A+"]";
+return B;
+}else{return D;
+}}};
+
+
+/* dom.js */
+SimileAjax.DOM=new Object();
+SimileAjax.DOM.registerEventWithObject=function(C,A,D,B){SimileAjax.DOM.registerEvent(C,A,function(F,E,G){return D[B].call(D,F,E,G);
+});
+};
+SimileAjax.DOM.registerEvent=function(C,B,D){var A=function(E){E=(E)?E:((event)?event:null);
+if(E){var F=(E.target)?E.target:((E.srcElement)?E.srcElement:null);
+if(F){F=(F.nodeType==1||F.nodeType==9)?F:F.parentNode;
+}return D(C,E,F);
+}return true;
+};
+if(SimileAjax.Platform.browser.isIE){C.attachEvent("on"+B,A);
+}else{C.addEventListener(B,A,false);
+}};
+SimileAjax.DOM.getPageCoordinates=function(B){var E=0;
+var D=0;
+if(B.nodeType!=1){B=B.parentNode;
+}var C=B;
+while(C!=null){E+=C.offsetLeft;
+D+=C.offsetTop;
+C=C.offsetParent;
+}var A=document.body;
+while(B!=null&&B!=A){if("scrollLeft" in B){E-=B.scrollLeft;
+D-=B.scrollTop;
+}B=B.parentNode;
+}return{left:E,top:D};
+};
+SimileAjax.DOM.getSize=function(B){var A=this.getStyle(B,"width");
+var C=this.getStyle(B,"height");
+if(A.indexOf("px")>-1){A=A.replace("px","");
+}if(C.indexOf("px")>-1){C=C.replace("px","");
+}return{w:A,h:C};
+};
+SimileAjax.DOM.getStyle=function(B,A){if(B.currentStyle){var C=B.currentStyle[A];
+}else{if(window.getComputedStyle){var C=document.defaultView.getComputedStyle(B,null).getPropertyValue(A);
+}else{var C="";
+}}return C;
+};
+SimileAjax.DOM.getEventRelativeCoordinates=function(A,B){if(SimileAjax.Platform.browser.isIE){if(A.type=="mousewheel"){var C=SimileAjax.DOM.getPageCoordinates(B);
+return{x:A.clientX-C.left,y:A.clientY-C.top};
+}else{return{x:A.offsetX,y:A.offsetY};
+}}else{var C=SimileAjax.DOM.getPageCoordinates(B);
+if((A.type=="DOMMouseScroll")&&SimileAjax.Platform.browser.isFirefox&&(SimileAjax.Platform.browser.majorVersion==2)){return{x:A.screenX-C.left,y:A.screenY-C.top};
+}else{return{x:A.pageX-C.left,y:A.pageY-C.top};
+}}};
+SimileAjax.DOM.getEventPageCoordinates=function(A){if(SimileAjax.Platform.browser.isIE){return{x:A.clientX+document.body.scrollLeft,y:A.clientY+document.body.scrollTop};
+}else{return{x:A.pageX,y:A.pageY};
+}};
+SimileAjax.DOM.hittest=function(A,C,B){return SimileAjax.DOM._hittest(document.body,A,C,B);
+};
+SimileAjax.DOM._hittest=function(C,L,K,H){var M=C.childNodes;
+outer:for(var G=0;
+G<M.length;
+G++){var A=M[G];
+for(var F=0;
+F<H.length;
+F++){if(A==H[F]){continue outer;
+}}if(A.offsetWidth==0&&A.offsetHeight==0){var B=SimileAjax.DOM._hittest(A,L,K,H);
+if(B!=A){return B;
+}}else{var J=0;
+var E=0;
+var D=A;
+while(D){J+=D.offsetTop;
+E+=D.offsetLeft;
+D=D.offsetParent;
+}if(E<=L&&J<=K&&(L-E)<A.offsetWidth&&(K-J)<A.offsetHeight){return SimileAjax.DOM._hittest(A,L,K,H);
+}else{if(A.nodeType==1&&A.tagName=="TR"){var I=SimileAjax.DOM._hittest(A,L,K,H);
+if(I!=A){return I;
+}}}}}return C;
+};
+SimileAjax.DOM.cancelEvent=function(A){A.returnValue=false;
+A.cancelBubble=true;
+if("preventDefault" in A){A.preventDefault();
+}};
+SimileAjax.DOM.appendClassName=function(C,D){var B=C.className.split(" ");
+for(var A=0;
+A<B.length;
+A++){if(B[A]==D){return ;
+}}B.push(D);
+C.className=B.join(" ");
+};
+SimileAjax.DOM.createInputElement=function(A){var B=document.createElement("div");
+B.innerHTML="<input type='"+A+"' />";
+return B.firstChild;
+};
+SimileAjax.DOM.createDOMFromTemplate=function(B){var A={};
+A.elmt=SimileAjax.DOM._createDOMFromTemplate(B,A,null);
+return A;
+};
+SimileAjax.DOM._createDOMFromTemplate=function(A,I,E){if(A==null){return null;
+}else{if(typeof A!="object"){var D=document.createTextNode(A);
+if(E!=null){E.appendChild(D);
+}return D;
+}else{var C=null;
+if("tag" in A){var J=A.tag;
+if(E!=null){if(J=="tr"){C=E.insertRow(E.rows.length);
+}else{if(J=="td"){C=E.insertCell(E.cells.length);
+}}}if(C==null){C=J=="input"?SimileAjax.DOM.createInputElement(A.type):document.createElement(J);
+if(E!=null){E.appendChild(C);
+}}}else{C=A.elmt;
+if(E!=null){E.appendChild(C);
+}}for(var B in A){var G=A[B];
+if(B=="field"){I[G]=C;
+}else{if(B=="className"){C.className=G;
+}else{if(B=="id"){C.id=G;
+}else{if(B=="title"){C.title=G;
+}else{if(B=="type"&&C.tagName=="input"){}else{if(B=="style"){for(n in G){var H=G[n];
+if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
+}C.style[n]=H;
+}}else{if(B=="children"){for(var F=0;
+F<G.length;
+F++){SimileAjax.DOM._createDOMFromTemplate(G[F],I,C);
+}}else{if(B!="tag"&&B!="elmt"){C.setAttribute(B,G);
+}}}}}}}}}return C;
+}}};
+SimileAjax.DOM._cachedParent=null;
+SimileAjax.DOM.createElementFromString=function(A){if(SimileAjax.DOM._cachedParent==null){SimileAjax.DOM._cachedParent=document.createElement("div");
+}SimileAjax.DOM._cachedParent.innerHTML=A;
+return SimileAjax.DOM._cachedParent.firstChild;
+};
+SimileAjax.DOM.createDOMFromString=function(A,C,D){var B=typeof A=="string"?document.createElement(A):A;
+B.innerHTML=C;
+var E={elmt:B};
+SimileAjax.DOM._processDOMChildrenConstructedFromString(E,B,D!=null?D:{});
+return E;
+};
+SimileAjax.DOM._processDOMConstructedFromString=function(D,A,B){var E=A.id;
+if(E!=null&&E.length>0){A.removeAttribute("id");
+if(E in B){var C=A.parentNode;
+C.insertBefore(B[E],A);
+C.removeChild(A);
+D[E]=B[E];
+return ;
+}else{D[E]=A;
+}}if(A.hasChildNodes()){SimileAjax.DOM._processDOMChildrenConstructedFromString(D,A,B);
+}};
+SimileAjax.DOM._processDOMChildrenConstructedFromString=function(E,B,D){var C=B.firstChild;
+while(C!=null){var A=C.nextSibling;
+if(C.nodeType==1){SimileAjax.DOM._processDOMConstructedFromString(E,C,D);
+}C=A;
+}};
+
+
+/* graphics.js */
+SimileAjax.Graphics=new Object();
+SimileAjax.Graphics.pngIsTranslucent=(!SimileAjax.Platform.browser.isIE)||(SimileAjax.Platform.browser.majorVersion>6);
+if(!SimileAjax.Graphics.pngIsTranslucent){SimileAjax.includeCssFile(document,SimileAjax.urlPrefix+"styles/graphics-ie6.css");
+}SimileAjax.Graphics._createTranslucentImage1=function(A,C){var B=document.createElement("img");
+B.setAttribute("src",A);
+if(C!=null){B.style.verticalAlign=C;
+}return B;
+};
+SimileAjax.Graphics._createTranslucentImage2=function(A,C){var B=document.createElement("img");
+B.style.width="1px";
+B.style.height="1px";
+B.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image')";
+B.style.verticalAlign=(C!=null)?C:"middle";
+return B;
+};
+SimileAjax.Graphics.createTranslucentImage=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImage1:SimileAjax.Graphics._createTranslucentImage2;
+SimileAjax.Graphics._createTranslucentImageHTML1=function(A,B){return'<img src="'+A+'"'+(B!=null?' style="vertical-align: '+B+';"':"")+" />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2=function(A,C){var B="width: 1px; height: 1px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image');"+(C!=null?" vertical-align: "+C+";":"");
+return"<img src='"+A+"' style=\""+B+'" />';
+};
+SimileAjax.Graphics.createTranslucentImageHTML=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImageHTML1:SimileAjax.Graphics._createTranslucentImageHTML2;
+SimileAjax.Graphics.setOpacity=function(B,A){if(SimileAjax.Platform.browser.isIE){B.style.filter="progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity="+A+")";
+}else{var C=(A/100).toString();
+B.style.opacity=C;
+B.style.MozOpacity=C;
+}};
+SimileAjax.Graphics.bubbleConfig={containerCSSClass:"simileAjax-bubble-container",innerContainerCSSClass:"simileAjax-bubble-innerContainer",contentContainerCSSClass:"simileAjax-bubble-contentContainer",borderGraphicSize:50,borderGraphicCSSClassPrefix:"simileAjax-bubble-border-",arrowGraphicTargetOffset:33,arrowGraphicLength:100,arrowGraphicWidth:49,arrowGraphicCSSClassPrefix:"simileAjax-bubble-arrow-",closeGraphicCSSClass:"simileAjax-bubble-close",extraPadding:20};
+SimileAjax.Graphics.createBubbleForContentAndPoint=function(F,D,C,A,B,E){if(typeof A!="number"){A=300;
+}if(typeof E!="number"){E=0;
+}F.style.position="absolute";
+F.style.left="-5000px";
+F.style.top="0px";
+F.style.width=A+"px";
+document.body.appendChild(F);
+window.setTimeout(function(){var J=F.scrollWidth+10;
+var G=F.scrollHeight+10;
+var I=0;
+if(E>0&&G>E){G=E;
+I=J-25;
+}var H=SimileAjax.Graphics.createBubbleForPoint(D,C,J,G,B);
+document.body.removeChild(F);
+F.style.position="static";
+F.style.left="";
+F.style.top="";
+if(I>0){var K=document.createElement("div");
+F.style.width="";
+K.style.width=I+"px";
+K.appendChild(F);
+H.content.appendChild(K);
+}else{F.style.width=J+"px";
+H.content.appendChild(F);
+}},200);
+};
+SimileAjax.Graphics.createBubbleForPoint=function(B,A,K,M,D){K=parseInt(K,10);
+M=parseInt(M,10);
+var E=SimileAjax.Graphics.bubbleConfig;
+var N=SimileAjax.Graphics.pngIsTranslucent?"pngTranslucent":"pngNotTranslucent";
+var L=K+2*E.borderGraphicSize;
+var P=M+2*E.borderGraphicSize;
+var O=function(S){return S+" "+S+"-"+N;
+};
+var H=document.createElement("div");
+H.className=O(E.containerCSSClass);
+H.style.width=K+"px";
+H.style.height=M+"px";
+var F=document.createElement("div");
+F.className=O(E.innerContainerCSSClass);
+H.appendChild(F);
+var I=function(){if(!J._closed){document.body.removeChild(J._div);
+J._doc=null;
+J._div=null;
+J._content=null;
+J._closed=true;
+}};
+var J={_closed:false};
+var R=SimileAjax.WindowManager.pushLayer(I,true,H);
+J._div=H;
+J.close=function(){SimileAjax.WindowManager.popLayer(R);
+};
+var G=function(T){var S=document.createElement("div");
+S.className=O(E.borderGraphicCSSClassPrefix+T);
+F.appendChild(S);
+};
+G("top-left");
+G("top-right");
+G("bottom-left");
+G("bottom-right");
+G("left");
+G("right");
+G("top");
+G("bottom");
+var C=document.createElement("div");
+C.className=O(E.contentContainerCSSClass);
+F.appendChild(C);
+J.content=C;
+var Q=document.createElement("div");
+Q.className=O(E.closeGraphicCSSClass);
+F.appendChild(Q);
+SimileAjax.WindowManager.registerEventWithObject(Q,"click",J,"close");
+(function(){var Z=SimileAjax.Graphics.getWindowDimensions();
+var U=Z.w;
+var S=Z.h;
+var V=Math.ceil(E.arrowGraphicWidth/2);
+var Y=function(a){var b=document.createElement("div");
+b.className=O(E.arrowGraphicCSSClassPrefix+"point-"+a);
+F.appendChild(b);
+return b;
+};
+if(B-V-E.borderGraphicSize-E.extraPadding>0&&B+V+E.borderGraphicSize+E.extraPadding<U){var X=B-Math.round(K/2);
+X=B<(U/2)?Math.max(X,E.extraPadding+E.borderGraphicSize):Math.min(X,U-E.extraPadding-E.borderGraphicSize-K);
+if((D&&D=="top")||(!D&&(A-E.arrowGraphicTargetOffset-M-E.borderGraphicSize-E.extraPadding>0))){var T=Y("down");
+T.style.left=(B-V-X)+"px";
+H.style.left=X+"px";
+H.style.top=(A-E.arrowGraphicTargetOffset-M)+"px";
+return ;
+}else{if((D&&D=="bottom")||(!D&&(A+E.arrowGraphicTargetOffset+M+E.borderGraphicSize+E.extraPadding<S))){var T=Y("up");
+T.style.left=(B-V-X)+"px";
+H.style.left=X+"px";
+H.style.top=(A+E.arrowGraphicTargetOffset)+"px";
+return ;
+}}}var W=A-Math.round(M/2);
+W=A<(S/2)?Math.max(W,E.extraPadding+E.borderGraphicSize):Math.min(W,S-E.extraPadding-E.borderGraphicSize-M);
+if((D&&D=="left")||(!D&&(B-E.arrowGraphicTargetOffset-K-E.borderGraphicSize-E.extraPadding>0))){var T=Y("right");
+T.style.top=(A-V-W)+"px";
+H.style.top=W+"px";
+H.style.left=(B-E.arrowGraphicTargetOffset-K)+"px";
+}else{var T=Y("left");
+T.style.top=(A-V-W)+"px";
+H.style.top=W+"px";
+H.style.left=(B+E.arrowGraphicTargetOffset)+"px";
+}})();
+document.body.appendChild(H);
+return J;
+};
+SimileAjax.Graphics.getWindowDimensions=function(){if(typeof window.innerHeight=="number"){return{w:window.innerWidth,h:window.innerHeight};
+}else{if(document.documentElement&&document.documentElement.clientHeight){return{w:document.documentElement.clientWidth,h:document.documentElement.clientHeight};
+}else{if(document.body&&document.body.clientHeight){return{w:document.body.clientWidth,h:document.body.clientHeight};
+}}}};
+SimileAjax.Graphics.createMessageBubble=function(H){var G=H.createElement("div");
+if(SimileAjax.Graphics.pngIsTranslucent){var I=H.createElement("div");
+I.style.height="33px";
+I.style.background="url("+SimileAjax.urlPrefix+"images/message-top-left.png) top left no-repeat";
+I.style.paddingLeft="44px";
+G.appendChild(I);
+var C=H.createElement("div");
+C.style.height="33px";
+C.style.background="url("+SimileAjax.urlPrefix+"images/message-top-right.png) top right no-repeat";
+I.appendChild(C);
+var F=H.createElement("div");
+F.style.background="url("+SimileAjax.urlPrefix+"images/message-left.png) top left repeat-y";
+F.style.paddingLeft="44px";
+G.appendChild(F);
+var A=H.createElement("div");
+A.style.background="url("+SimileAjax.urlPrefix+"images/message-right.png) top right repeat-y";
+A.style.paddingRight="44px";
+F.appendChild(A);
+var D=H.createElement("div");
+A.appendChild(D);
+var B=H.createElement("div");
+B.style.height="55px";
+B.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-left.png) bottom left no-repeat";
+B.style.paddingLeft="44px";
+G.appendChild(B);
+var E=H.createElement("div");
+E.style.height="55px";
+E.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-right.png) bottom right no-repeat";
+B.appendChild(E);
+}else{G.style.border="2px solid #7777AA";
+G.style.padding="20px";
+G.style.background="white";
+SimileAjax.Graphics.setOpacity(G,90);
+var D=H.createElement("div");
+G.appendChild(D);
+}return{containerDiv:G,contentDiv:D};
+};
+SimileAjax.Graphics.createAnimation=function(B,E,D,C,A){return new SimileAjax.Graphics._Animation(B,E,D,C,A);
+};
+SimileAjax.Graphics._Animation=function(B,E,D,C,A){this.f=B;
+this.cont=(typeof A=="function")?A:function(){};
+this.from=E;
+this.to=D;
+this.current=E;
+this.duration=C;
+this.start=new Date().getTime();
+this.timePassed=0;
+};
+SimileAjax.Graphics._Animation.prototype.run=function(){var A=this;
+window.setTimeout(function(){A.step();
+},50);
+};
+SimileAjax.Graphics._Animation.prototype.step=function(){this.timePassed+=50;
+var B=this.timePassed/this.duration;
+var A=-Math.cos(B*Math.PI)/2+0.5;
+var D=A*(this.to-this.from)+this.from;
+try{this.f(D,D-this.current);
+}catch(C){}this.current=D;
+if(this.timePassed<this.duration){this.run();
+}else{this.f(this.to,0);
+this["cont"]();
+}};
+SimileAjax.Graphics.createStructuredDataCopyButton=function(F,D,A,E){var G=document.createElement("div");
+G.style.position="relative";
+G.style.display="inline";
+G.style.width=D+"px";
+G.style.height=A+"px";
+G.style.overflow="hidden";
+G.style.margin="2px";
+if(SimileAjax.Graphics.pngIsTranslucent){G.style.background="url("+F+") no-repeat";
+}else{G.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+F+"', sizingMethod='image')";
+}var C;
+if(SimileAjax.Platform.browser.isIE){C="filter:alpha(opacity=0)";
+}else{C="opacity: 0";
+}G.innerHTML="<textarea rows='1' autocomplete='off' value='none' style='"+C+"' />";
+var B=G.firstChild;
+B.style.width=D+"px";
+B.style.height=A+"px";
+B.onmousedown=function(H){H=(H)?H:((event)?event:null);
+if(H.button==2){B.value=E();
+B.select();
+}};
+return G;
+};
+SimileAjax.Graphics.getWidthHeight=function(C){var A,B;
+if(C.getBoundingClientRect==null){A=C.offsetWidth;
+B=C.offsetHeight;
+}else{var D=C.getBoundingClientRect();
+A=Math.ceil(D.right-D.left);
+B=Math.ceil(D.bottom-D.top);
+}return{width:A,height:B};
+};
+SimileAjax.Graphics.getFontRenderingContext=function(A,B){return new SimileAjax.Graphics._FontRenderingContext(A,B);
+};
+SimileAjax.Graphics._FontRenderingContext=function(A,B){this._elmt=A;
+this._elmt.style.visibility="hidden";
+if(typeof B=="string"){this._elmt.style.width=B;
+}else{if(typeof B=="number"){this._elmt.style.width=B+"px";
+}}};
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose=function(){this._elmt=null;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.update=function(){this._elmt.innerHTML="A";
+this._lineHeight=this._elmt.offsetHeight;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize=function(D,C){var B=this._elmt;
+B.innerHTML=D;
+B.className=C===undefined?"":C;
+var A=SimileAjax.Graphics.getWidthHeight(B);
+B.className="";
+return A;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight=function(){return this._lineHeight;
+};
+
+
+/* history.js */
+SimileAjax.History={maxHistoryLength:10,historyFile:"__history__.html",enabled:true,_initialized:false,_listeners:new SimileAjax.ListenerQueue(),_actions:[],_baseIndex:0,_currentIndex:0,_plainDocumentTitle:document.title};
+SimileAjax.History.formatHistoryEntryTitle=function(A){return SimileAjax.History._plainDocumentTitle+" {"+A+"}";
+};
+SimileAjax.History.initialize=function(){if(SimileAjax.History._initialized){return ;
+}if(SimileAjax.History.enabled){var A=document.createElement("iframe");
+A.id="simile-ajax-history";
+A.style.position="absolute";
+A.style.width="10px";
+A.style.height="10px";
+A.style.top="0px";
+A.style.left="0px";
+A.style.visibility="hidden";
+A.src=SimileAjax.History.historyFile+"?0";
+document.body.appendChild(A);
+SimileAjax.DOM.registerEvent(A,"load",SimileAjax.History._handleIFrameOnLoad);
+SimileAjax.History._iframe=A;
+}SimileAjax.History._initialized=true;
+};
+SimileAjax.History.addListener=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.add(A);
+};
+SimileAjax.History.removeListener=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.remove(A);
+};
+SimileAjax.History.addAction=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.fire("onBeforePerform",[A]);
+window.setTimeout(function(){try{A.perform();
+SimileAjax.History._listeners.fire("onAfterPerform",[A]);
+if(SimileAjax.History.enabled){SimileAjax.History._actions=SimileAjax.History._actions.slice(0,SimileAjax.History._currentIndex-SimileAjax.History._baseIndex);
+SimileAjax.History._actions.push(A);
+SimileAjax.History._currentIndex++;
+var C=SimileAjax.History._actions.length-SimileAjax.History.maxHistoryLength;
+if(C>0){SimileAjax.History._actions=SimileAjax.History._actions.slice(C);
+SimileAjax.History._baseIndex+=C;
+}try{SimileAjax.History._iframe.contentWindow.location.search="?"+SimileAjax.History._currentIndex;
+}catch(B){var D=SimileAjax.History.formatHistoryEntryTitle(A.label);
+document.title=D;
+}}}catch(B){SimileAjax.Debug.exception(B,"Error adding action {"+A.label+"} to history");
+}},0);
+};
+SimileAjax.History.addLengthyAction=function(C,A,B){SimileAjax.History.addAction({perform:C,undo:A,label:B,uiLayer:SimileAjax.WindowManager.getBaseLayer(),lengthy:true});
+};
+SimileAjax.History._handleIFrameOnLoad=function(){try{var B=SimileAjax.History._iframe.contentWindow.location.search;
+var F=(B.length==0)?0:Math.max(0,parseInt(B.substr(1)));
+var E=function(){var G=F-SimileAjax.History._currentIndex;
+SimileAjax.History._currentIndex+=G;
+SimileAjax.History._baseIndex+=G;
+SimileAjax.History._iframe.contentWindow.location.search="?"+F;
+};
+if(F<SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeUndoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex>F&&SimileAjax.History._currentIndex>SimileAjax.History._baseIndex){SimileAjax.History._currentIndex--;
+var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{G.undo();
+}catch(H){SimileAjax.Debug.exception(H,"History: Failed to undo action {"+G.label+"}");
+}}SimileAjax.History._listeners.fire("onAfterUndoSeveral",[]);
+E();
+},0);
+}else{if(F>SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeRedoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex<F&&SimileAjax.History._currentIndex-SimileAjax.History._baseIndex<SimileAjax.History._actions.length){var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{G.perform();
+}catch(H){SimileAjax.Debug.exception(H,"History: Failed to redo action {"+G.label+"}");
+}SimileAjax.History._currentIndex++;
+}SimileAjax.History._listeners.fire("onAfterRedoSeveral",[]);
+E();
+},0);
+}else{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+var D=(A>=0&&A<SimileAjax.History._actions.length)?SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[A].label):SimileAjax.History._plainDocumentTitle;
+SimileAjax.History._iframe.contentWindow.document.title=D;
+document.title=D;
+}}}catch(C){}};
+SimileAjax.History.getNextUndoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+return SimileAjax.History._actions[A];
+}catch(B){return null;
+}};
+SimileAjax.History.getNextRedoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex;
+return SimileAjax.History._actions[A];
+}catch(B){return null;
+}};
+
+
+/* html.js */
+SimileAjax.HTML=new Object();
+SimileAjax.HTML._e2uHash={};
+(function(){var A=SimileAjax.HTML._e2uHash;
+A["nbsp"]="\u00A0[space]";
+A["iexcl"]="\u00A1";
+A["cent"]="\u00A2";
+A["pound"]="\u00A3";
+A["curren"]="\u00A4";
+A["yen"]="\u00A5";
+A["brvbar"]="\u00A6";
+A["sect"]="\u00A7";
+A["uml"]="\u00A8";
+A["copy"]="\u00A9";
+A["ordf"]="\u00AA";
+A["laquo"]="\u00AB";
+A["not"]="\u00AC";
+A["shy"]="\u00AD";
+A["reg"]="\u00AE";
+A["macr"]="\u00AF";
+A["deg"]="\u00B0";
+A["plusmn"]="\u00B1";
+A["sup2"]="\u00B2";
+A["sup3"]="\u00B3";
+A["acute"]="\u00B4";
+A["micro"]="\u00B5";
+A["para"]="\u00B6";
+A["middot"]="\u00B7";
+A["cedil"]="\u00B8";
+A["sup1"]="\u00B9";
+A["ordm"]="\u00BA";
+A["raquo"]="\u00BB";
+A["frac14"]="\u00BC";
+A["frac12"]="\u00BD";
+A["frac34"]="\u00BE";
+A["iquest"]="\u00BF";
+A["Agrave"]="\u00C0";
+A["Aacute"]="\u00C1";
+A["Acirc"]="\u00C2";
+A["Atilde"]="\u00C3";
+A["Auml"]="\u00C4";
+A["Aring"]="\u00C5";
+A["AElig"]="\u00C6";
+A["Ccedil"]="\u00C7";
+A["Egrave"]="\u00C8";
+A["Eacute"]="\u00C9";
+A["Ecirc"]="\u00CA";
+A["Euml"]="\u00CB";
+A["Igrave"]="\u00CC";
+A["Iacute"]="\u00CD";
+A["Icirc"]="\u00CE";
+A["Iuml"]="\u00CF";
+A["ETH"]="\u00D0";
+A["Ntilde"]="\u00D1";
+A["Ograve"]="\u00D2";
+A["Oacute"]="\u00D3";
+A["Ocirc"]="\u00D4";
+A["Otilde"]="\u00D5";
+A["Ouml"]="\u00D6";
+A["times"]="\u00D7";
+A["Oslash"]="\u00D8";
+A["Ugrave"]="\u00D9";
+A["Uacute"]="\u00DA";
+A["Ucirc"]="\u00DB";
+A["Uuml"]="\u00DC";
+A["Yacute"]="\u00DD";
+A["THORN"]="\u00DE";
+A["szlig"]="\u00DF";
+A["agrave"]="\u00E0";
+A["aacute"]="\u00E1";
+A["acirc"]="\u00E2";
+A["atilde"]="\u00E3";
+A["auml"]="\u00E4";
+A["aring"]="\u00E5";
+A["aelig"]="\u00E6";
+A["ccedil"]="\u00E7";
+A["egrave"]="\u00E8";
+A["eacute"]="\u00E9";
+A["ecirc"]="\u00EA";
+A["euml"]="\u00EB";
+A["igrave"]="\u00EC";
+A["iacute"]="\u00ED";
+A["icirc"]="\u00EE";
+A["iuml"]="\u00EF";
+A["eth"]="\u00F0";
+A["ntilde"]="\u00F1";
+A["ograve"]="\u00F2";
+A["oacute"]="\u00F3";
+A["ocirc"]="\u00F4";
+A["otilde"]="\u00F5";
+A["ouml"]="\u00F6";
+A["divide"]="\u00F7";
+A["oslash"]="\u00F8";
+A["ugrave"]="\u00F9";
+A["uacute"]="\u00FA";
+A["ucirc"]="\u00FB";
+A["uuml"]="\u00FC";
+A["yacute"]="\u00FD";
+A["thorn"]="\u00FE";
+A["yuml"]="\u00FF";
+A["quot"]="\u0022";
+A["amp"]="\u0026";
+A["lt"]="\u003C";
+A["gt"]="\u003E";
+A["OElig"]="";
+A["oelig"]="\u0153";
+A["Scaron"]="\u0160";
+A["scaron"]="\u0161";
+A["Yuml"]="\u0178";
+A["circ"]="\u02C6";
+A["tilde"]="\u02DC";
+A["ensp"]="\u2002";
+A["emsp"]="\u2003";
+A["thinsp"]="\u2009";
+A["zwnj"]="\u200C";
+A["zwj"]="\u200D";
+A["lrm"]="\u200E";
+A["rlm"]="\u200F";
+A["ndash"]="\u2013";
+A["mdash"]="\u2014";
+A["lsquo"]="\u2018";
+A["rsquo"]="\u2019";
+A["sbquo"]="\u201A";
+A["ldquo"]="\u201C";
+A["rdquo"]="\u201D";
+A["bdquo"]="\u201E";
+A["dagger"]="\u2020";
+A["Dagger"]="\u2021";
+A["permil"]="\u2030";
+A["lsaquo"]="\u2039";
+A["rsaquo"]="\u203A";
+A["euro"]="\u20AC";
+A["fnof"]="\u0192";
+A["Alpha"]="\u0391";
+A["Beta"]="\u0392";
+A["Gamma"]="\u0393";
+A["Delta"]="\u0394";
+A["Epsilon"]="\u0395";
+A["Zeta"]="\u0396";
+A["Eta"]="\u0397";
+A["Theta"]="\u0398";
+A["Iota"]="\u0399";
+A["Kappa"]="\u039A";
+A["Lambda"]="\u039B";
+A["Mu"]="\u039C";
+A["Nu"]="\u039D";
+A["Xi"]="\u039E";
+A["Omicron"]="\u039F";
+A["Pi"]="\u03A0";
+A["Rho"]="\u03A1";
+A["Sigma"]="\u03A3";
+A["Tau"]="\u03A4";
+A["Upsilon"]="\u03A5";
+A["Phi"]="\u03A6";
+A["Chi"]="\u03A7";
+A["Psi"]="\u03A8";
+A["Omega"]="\u03A9";
+A["alpha"]="\u03B1";
+A["beta"]="\u03B2";
+A["gamma"]="\u03B3";
+A["delta"]="\u03B4";
+A["epsilon"]="\u03B5";
+A["zeta"]="\u03B6";
+A["eta"]="\u03B7";
+A["theta"]="\u03B8";
+A["iota"]="\u03B9";
+A["kappa"]="\u03BA";
+A["lambda"]="\u03BB";
+A["mu"]="\u03BC";
+A["nu"]="\u03BD";
+A["xi"]="\u03BE";
+A["omicron"]="\u03BF";
+A["pi"]="\u03C0";
+A["rho"]="\u03C1";
+A["sigmaf"]="\u03C2";
+A["sigma"]="\u03C3";
+A["tau"]="\u03C4";
+A["upsilon"]="\u03C5";
+A["phi"]="\u03C6";
+A["chi"]="\u03C7";
+A["psi"]="\u03C8";
+A["omega"]="\u03C9";
+A["thetasym"]="\u03D1";
+A["upsih"]="\u03D2";
+A["piv"]="\u03D6";
+A["bull"]="\u2022";
+A["hellip"]="\u2026";
+A["prime"]="\u2032";
+A["Prime"]="\u2033";
+A["oline"]="\u203E";
+A["frasl"]="\u2044";
+A["weierp"]="\u2118";
+A["image"]="\u2111";
+A["real"]="\u211C";
+A["trade"]="\u2122";
+A["alefsym"]="\u2135";
+A["larr"]="\u2190";
+A["uarr"]="\u2191";
+A["rarr"]="\u2192";
+A["darr"]="\u2193";
+A["harr"]="\u2194";
+A["crarr"]="\u21B5";
+A["lArr"]="\u21D0";
+A["uArr"]="\u21D1";
+A["rArr"]="\u21D2";
+A["dArr"]="\u21D3";
+A["hArr"]="\u21D4";
+A["forall"]="\u2200";
+A["part"]="\u2202";
+A["exist"]="\u2203";
+A["empty"]="\u2205";
+A["nabla"]="\u2207";
+A["isin"]="\u2208";
+A["notin"]="\u2209";
+A["ni"]="\u220B";
+A["prod"]="\u220F";
+A["sum"]="\u2211";
+A["minus"]="\u2212";
+A["lowast"]="\u2217";
+A["radic"]="\u221A";
+A["prop"]="\u221D";
+A["infin"]="\u221E";
+A["ang"]="\u2220";
+A["and"]="\u2227";
+A["or"]="\u2228";
+A["cap"]="\u2229";
+A["cup"]="\u222A";
+A["int"]="\u222B";
+A["there4"]="\u2234";
+A["sim"]="\u223C";
+A["cong"]="\u2245";
+A["asymp"]="\u2248";
+A["ne"]="\u2260";
+A["equiv"]="\u2261";
+A["le"]="\u2264";
+A["ge"]="\u2265";
+A["sub"]="\u2282";
+A["sup"]="\u2283";
+A["nsub"]="\u2284";
+A["sube"]="\u2286";
+A["supe"]="\u2287";
+A["oplus"]="\u2295";
+A["otimes"]="\u2297";
+A["perp"]="\u22A5";
+A["sdot"]="\u22C5";
+A["lceil"]="\u2308";
+A["rceil"]="\u2309";
+A["lfloor"]="\u230A";
+A["rfloor"]="\u230B";
+A["lang"]="\u2329";
+A["rang"]="\u232A";
+A["loz"]="\u25CA";
+A["spades"]="\u2660";
+A["clubs"]="\u2663";
+A["hearts"]="\u2665";
+A["diams"]="\u2666";
+})();
+SimileAjax.HTML.deEntify=function(C){var D=SimileAjax.HTML._e2uHash;
+var B=/&(\w+?);/;
+while(B.test(C)){var A=C.match(B);
+C=C.replace(B,D[A[1]]);
+}return C;
+};
+
+
+/* json.js */
+SimileAjax.JSON=new Object();
+(function(){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};
+var s={array:function(x){var a=["["],b,f,i,l=x.length,v;
+for(i=0;
+i<l;
+i+=1){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a[a.length]=v;
+b=true;
+}}}a[a.length]="]";
+return a.join("");
+},"boolean":function(x){return String(x);
+},"null":function(x){return"null";
+},number:function(x){return isFinite(x)?String(x):"null";
+},object:function(x){if(x){if(x instanceof Array){return s.array(x);
+}var a=["{"],b,f,i,v;
+for(i in x){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a.push(s.string(i),":",v);
+b=true;
+}}}a[a.length]="}";
+return a.join("");
+}return"null";
+},string:function(x){if(/["\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];
+if(c){return c;
+}c=b.charCodeAt();
+return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);
+});
+}return'"'+x+'"';
+}};
+SimileAjax.JSON.toJSONString=function(o){if(o instanceof Object){return s.object(o);
+}else{if(o instanceof Array){return s.array(o);
+}else{return o.toString();
+}}};
+SimileAjax.JSON.parseJSON=function(){try{return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g,"")))&&eval("("+this+")");
+}catch(e){return false;
+}};
+})();
+
+
+/* string.js */
+String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
+};
+String.prototype.startsWith=function(A){return this.length>=A.length&&this.substr(0,A.length)==A;
+};
+String.prototype.endsWith=function(A){return this.length>=A.length&&this.substr(this.length-A.length)==A;
+};
+String.substitute=function(B,D){var A="";
+var F=0;
+while(F<B.length-1){var C=B.indexOf("%",F);
+if(C<0||C==B.length-1){break;
+}else{if(C>F&&B.charAt(C-1)=="\\"){A+=B.substring(F,C-1)+"%";
+F=C+1;
+}else{var E=parseInt(B.charAt(C+1));
+if(isNaN(E)||E>=D.length){A+=B.substring(F,C+2);
+}else{A+=B.substring(F,C)+D[E].toString();
+}F=C+2;
+}}}if(F<B.length){A+=B.substring(F);
+}return A;
+};
+
+
+/* units.js */
+SimileAjax.NativeDateUnit=new Object();
+SimileAjax.NativeDateUnit.makeDefaultValue=function(){return new Date();
+};
+SimileAjax.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
+};
+SimileAjax.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
+}var B=(A=="iso8601"||A=="iso 8601")?SimileAjax.DateTime.parseIso8601DateTime:SimileAjax.DateTime.parseGregorianDateTime;
+return function(C){if(typeof C!="undefined"&&typeof C.toUTCString=="function"){return C;
+}else{return B(C);
+}};
+};
+SimileAjax.NativeDateUnit.parseFromObject=function(A){return SimileAjax.DateTime.parseGregorianDateTime(A);
+};
+SimileAjax.NativeDateUnit.toNumber=function(A){return A.getTime();
+};
+SimileAjax.NativeDateUnit.fromNumber=function(A){return new Date(A);
+};
+SimileAjax.NativeDateUnit.compare=function(D,C){var B,A;
+if(typeof D=="object"){B=D.getTime();
+}else{B=Number(D);
+}if(typeof C=="object"){A=C.getTime();
+}else{A=Number(C);
+}return B-A;
+};
+SimileAjax.NativeDateUnit.earlier=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)<0?B:A;
+};
+SimileAjax.NativeDateUnit.later=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)>0?B:A;
+};
+SimileAjax.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
+};
+
+
+/* window-manager.js */
+SimileAjax.WindowManager={_initialized:false,_listeners:[],_draggedElement:null,_draggedElementCallback:null,_dropTargetHighlightElement:null,_lastCoords:null,_ghostCoords:null,_draggingMode:"",_dragging:false,_layers:[]};
+SimileAjax.WindowManager.initialize=function(){if(SimileAjax.WindowManager._initialized){return ;
+}SimileAjax.DOM.registerEvent(document.body,"mousedown",SimileAjax.WindowManager._onBodyMouseDown);
+SimileAjax.DOM.registerEvent(document.body,"mousemove",SimileAjax.WindowManager._onBodyMouseMove);
+SimileAjax.DOM.registerEvent(document.body,"mouseup",SimileAjax.WindowManager._onBodyMouseUp);
+SimileAjax.DOM.registerEvent(document,"keydown",SimileAjax.WindowManager._onBodyKeyDown);
+SimileAjax.DOM.registerEvent(document,"keyup",SimileAjax.WindowManager._onBodyKeyUp);
+SimileAjax.WindowManager._layers.push({index:0});
+SimileAjax.WindowManager._historyListener={onBeforeUndoSeveral:function(){},onAfterUndoSeveral:function(){},onBeforeUndo:function(){},onAfterUndo:function(){},onBeforeRedoSeveral:function(){},onAfterRedoSeveral:function(){},onBeforeRedo:function(){},onAfterRedo:function(){}};
+SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+SimileAjax.WindowManager._initialized=true;
+};
+SimileAjax.WindowManager.getBaseLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[0];
+};
+SimileAjax.WindowManager.getHighestLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length-1];
+};
+SimileAjax.WindowManager.registerEventWithObject=function(D,A,E,B,C){SimileAjax.WindowManager.registerEvent(D,A,function(G,F,H){return E[B].call(E,G,F,H);
+},C);
+};
+SimileAjax.WindowManager.registerEvent=function(D,B,E,C){if(C==null){C=SimileAjax.WindowManager.getHighestLayer();
+}var A=function(G,F,I){if(SimileAjax.WindowManager._canProcessEventAtLayer(C)){SimileAjax.WindowManager._popToLayer(C.index);
+try{E(G,F,I);
+}catch(H){SimileAjax.Debug.exception(H);
+}}SimileAjax.DOM.cancelEvent(F);
+return false;
+};
+SimileAjax.DOM.registerEvent(D,B,A);
+};
+SimileAjax.WindowManager.pushLayer=function(C,D,B){var A={onPop:C,index:SimileAjax.WindowManager._layers.length,ephemeral:(D),elmt:B};
+SimileAjax.WindowManager._layers.push(A);
+return A;
+};
+SimileAjax.WindowManager.popLayer=function(B){for(var A=1;
+A<SimileAjax.WindowManager._layers.length;
+A++){if(SimileAjax.WindowManager._layers[A]==B){SimileAjax.WindowManager._popToLayer(A-1);
+break;
+}}};
+SimileAjax.WindowManager.popAllLayers=function(){SimileAjax.WindowManager._popToLayer(0);
+};
+SimileAjax.WindowManager.registerForDragging=function(B,C,A){SimileAjax.WindowManager.registerEvent(B,"mousedown",function(E,D,F){SimileAjax.WindowManager._handleMouseDown(E,D,C);
+},A);
+};
+SimileAjax.WindowManager._popToLayer=function(C){while(C+1<SimileAjax.WindowManager._layers.length){try{var A=SimileAjax.WindowManager._layers.pop();
+if(A.onPop!=null){A.onPop();
+}}catch(B){}}};
+SimileAjax.WindowManager._canProcessEventAtLayer=function(B){if(B.index==(SimileAjax.WindowManager._layers.length-1)){return true;
+}for(var A=B.index+1;
+A<SimileAjax.WindowManager._layers.length;
+A++){if(!SimileAjax.WindowManager._layers[A].ephemeral){return false;
+}}return true;
+};
+SimileAjax.WindowManager.cancelPopups=function(A){var F=(A)?SimileAjax.DOM.getEventPageCoordinates(A):{x:-1,y:-1};
+var E=SimileAjax.WindowManager._layers.length-1;
+while(E>0&&SimileAjax.WindowManager._layers[E].ephemeral){var D=SimileAjax.WindowManager._layers[E];
+if(D.elmt!=null){var C=D.elmt;
+var B=SimileAjax.DOM.getPageCoordinates(C);
+if(F.x>=B.left&&F.x<(B.left+C.offsetWidth)&&F.y>=B.top&&F.y<(B.top+C.offsetHeight)){break;
+}}E--;
+}SimileAjax.WindowManager._popToLayer(E);
+};
+SimileAjax.WindowManager._onBodyMouseDown=function(B,A,C){if(!("eventPhase" in A)||A.eventPhase==A.BUBBLING_PHASE){SimileAjax.WindowManager.cancelPopups(A);
+}};
+SimileAjax.WindowManager._handleMouseDown=function(B,A,C){SimileAjax.WindowManager._draggedElement=B;
+SimileAjax.WindowManager._draggedElementCallback=C;
+SimileAjax.WindowManager._lastCoords={x:A.clientX,y:A.clientY};
+SimileAjax.DOM.cancelEvent(A);
+return false;
+};
+SimileAjax.WindowManager._onBodyKeyDown=function(C,A,D){if(SimileAjax.WindowManager._dragging){if(A.keyCode==27){SimileAjax.WindowManager._cancelDragging();
+}else{if((A.keyCode==17||A.keyCode==16)&&SimileAjax.WindowManager._draggingMode!="copy"){SimileAjax.WindowManager._draggingMode="copy";
+var B=SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix+"images/copy.png");
+B.style.position="absolute";
+B.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+B.style.top=(SimileAjax.WindowManager._ghostCoords.top)+"px";
+document.body.appendChild(B);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=B;
+}}}};
+SimileAjax.WindowManager._onBodyKeyUp=function(B,A,C){if(SimileAjax.WindowManager._dragging){if(A.keyCode==17||A.keyCode==16){SimileAjax.WindowManager._draggingMode="";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}}}};
+SimileAjax.WindowManager._onBodyMouseMove=function(A,N,H){if(SimileAjax.WindowManager._draggedElement!=null){var P=SimileAjax.WindowManager._draggedElementCallback;
+var E=SimileAjax.WindowManager._lastCoords;
+var M=N.clientX-E.x;
+var J=N.clientY-E.y;
+if(!SimileAjax.WindowManager._dragging){if(Math.abs(M)>5||Math.abs(J)>5){try{if("onDragStart" in P){P.onDragStart();
+}if("ghost" in P&&P.ghost){var K=SimileAjax.WindowManager._draggedElement;
+SimileAjax.WindowManager._ghostCoords=SimileAjax.DOM.getPageCoordinates(K);
+SimileAjax.WindowManager._ghostCoords.left+=M;
+SimileAjax.WindowManager._ghostCoords.top+=J;
+var O=K.cloneNode(true);
+O.style.position="absolute";
+O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+O.style.zIndex=1000;
+SimileAjax.Graphics.setOpacity(O,50);
+document.body.appendChild(O);
+P._ghostElmt=O;
+}SimileAjax.WindowManager._dragging=true;
+SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
+document.body.focus();
+}catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse down",G);
+SimileAjax.WindowManager._cancelDragging();
+}}}else{try{SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
+if("onDragBy" in P){P.onDragBy(M,J);
+}if("_ghostElmt" in P){var O=P._ghostElmt;
+SimileAjax.WindowManager._ghostCoords.left+=M;
+SimileAjax.WindowManager._ghostCoords.top+=J;
+O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){var I=SimileAjax.WindowManager._draggingModeIndicatorElmt;
+I.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+I.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+}if("droppable" in P&&P.droppable){var L=SimileAjax.DOM.getEventPageCoordinates(N);
+var H=SimileAjax.DOM.hittest(L.x,L.y,[SimileAjax.WindowManager._ghostElmt,SimileAjax.WindowManager._dropTargetHighlightElement]);
+H=SimileAjax.WindowManager._findDropTarget(H);
+if(H!=SimileAjax.WindowManager._potentialDropTarget){if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+}var F=false;
+if(H!=null){if((!("canDropOn" in P)||P.canDropOn(H))&&(!("canDrop" in H)||H.canDrop(SimileAjax.WindowManager._draggedElement))){F=true;
+}}if(F){var C=4;
+var D=SimileAjax.DOM.getPageCoordinates(H);
+var B=document.createElement("div");
+B.style.border=C+"px solid yellow";
+B.style.backgroundColor="yellow";
+B.style.position="absolute";
+B.style.left=D.left+"px";
+B.style.top=D.top+"px";
+B.style.width=(H.offsetWidth-C*2)+"px";
+B.style.height=(H.offsetHeight-C*2)+"px";
+SimileAjax.Graphics.setOpacity(B,30);
+document.body.appendChild(B);
+SimileAjax.WindowManager._potentialDropTarget=H;
+SimileAjax.WindowManager._dropTargetHighlightElement=B;
+}}}}}catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse move",G);
+SimileAjax.WindowManager._cancelDragging();
+}}SimileAjax.DOM.cancelEvent(N);
+return false;
+}};
+SimileAjax.WindowManager._onBodyMouseUp=function(B,A,C){if(SimileAjax.WindowManager._draggedElement!=null){try{if(SimileAjax.WindowManager._dragging){var E=SimileAjax.WindowManager._draggedElementCallback;
+if("onDragEnd" in E){E.onDragEnd();
+}if("droppable" in E&&E.droppable){var D=false;
+var C=SimileAjax.WindowManager._potentialDropTarget;
+if(C!=null){if((!("canDropOn" in E)||E.canDropOn(C))&&(!("canDrop" in C)||C.canDrop(SimileAjax.WindowManager._draggedElement))){if("onDropOn" in E){E.onDropOn(C);
+}C.ondrop(SimileAjax.WindowManager._draggedElement,SimileAjax.WindowManager._draggingMode);
+D=true;
+}}if(!D){}}}}finally{SimileAjax.WindowManager._cancelDragging();
+}SimileAjax.DOM.cancelEvent(A);
+return false;
+}};
+SimileAjax.WindowManager._cancelDragging=function(){var B=SimileAjax.WindowManager._draggedElementCallback;
+if("_ghostElmt" in B){var A=B._ghostElmt;
+document.body.removeChild(A);
+delete B._ghostElmt;
+}if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+}if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}SimileAjax.WindowManager._draggedElement=null;
+SimileAjax.WindowManager._draggedElementCallback=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._lastCoords=null;
+SimileAjax.WindowManager._ghostCoords=null;
+SimileAjax.WindowManager._draggingMode="";
+SimileAjax.WindowManager._dragging=false;
+};
+SimileAjax.WindowManager._findDropTarget=function(A){while(A!=null){if("ondrop" in A&&(typeof A.ondrop)=="function"){break;
+}A=A.parentNode;
+}return A;
+};
+
+
+/* xmlhttp.js */
+SimileAjax.XmlHttp=new Object();
+SimileAjax.XmlHttp._onReadyStateChange=function(A,D,B){switch(A.readyState){case 4:try{if(A.status==0||A.status==200){if(B){B(A);
+}}else{if(D){D(A.statusText,A.status,A);
+}}}catch(C){SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange",C);
+}break;
+}};
+SimileAjax.XmlHttp._createRequest=function(){if(SimileAjax.Platform.browser.isIE){var A=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
+for(var B=0;
+B<A.length;
+B++){try{var C=A[B];
+var D=function(){return new ActiveXObject(C);
+};
+var F=D();
+SimileAjax.XmlHttp._createRequest=D;
+return F;
+}catch(E){}}}try{var D=function(){return new XMLHttpRequest();
+};
+var F=D();
+SimileAjax.XmlHttp._createRequest=D;
+return F;
+}catch(E){throw new Error("Failed to create an XMLHttpRequest object");
+}};
+SimileAjax.XmlHttp.get=function(A,D,C){var B=SimileAjax.XmlHttp._createRequest();
+B.open("GET",A,true);
+B.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(B,D,C);
+};
+B.send(null);
+};
+SimileAjax.XmlHttp.post=function(B,A,E,D){var C=SimileAjax.XmlHttp._createRequest();
+C.open("POST",B,true);
+C.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(C,E,D);
+};
+C.send(A);
+};
+SimileAjax.XmlHttp._forceXML=function(A){try{A.overrideMimeType("text/xml");
+}catch(B){A.setrequestheader("Content-Type","text/xml");
+}};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/LICENSE.txt b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/LICENSE.txt
new file mode 100644
index 00000000..2f3e0503
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/LICENSE.txt
@@ -0,0 +1,29 @@
+/*
+ * (c) Copyright The SIMILE Project 2006. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-epilog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-epilog.js
new file mode 100644
index 00000000..d1a70927
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-epilog.js
@@ -0,0 +1,16 @@
+(function() {
+ var f = null;
+ if ("SimileWidgets_onLoad" in window) {
+ if (typeof SimileWidgets_onLoad == "string") {
+ f = eval(SimileWidgets_onLoad);
+ SimileWidgets_onLoad = null;
+ } else if (typeof SimileWidgets_onLoad == "function") {
+ f = SimileWidgets_onLoad;
+ SimileWidgets_onLoad = null;
+ }
+ }
+
+ if (f != null) {
+ f();
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-prolog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-prolog.js
new file mode 100644
index 00000000..0e17f88b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/compile-prolog.js
@@ -0,0 +1 @@
+window.Exhibit_isCompiled = true; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-api.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-api.js
new file mode 100644
index 00000000..84f02f7c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-api.js
@@ -0,0 +1,276 @@
+/*==================================================
+ * Simile Exhibit API
+ *
+ * Include Exhibit in your HTML file as follows:
+ * <script src="http://static.simile.mit.edu/exhibit/api-2.0/exhibit-api.js" type="text/javascript"></script>
+ *
+ *==================================================
+ */
+
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+
+ var useLocalResources = true;
+ var noAuthentication = false;
+
+ if (document.location.search.length > 0) {
+ var params = document.location.search.substr(1).split("&");
+ for (var i = 0; i < params.length; i++) {
+ if (params[i] == "exhibit-use-local-resources") {
+ useLocalResources = true;
+ }
+ if (params[i] == 'exhibit-no-authentication') {
+ noAuthentication = true;
+ }
+
+ }
+ }
+
+ var loadMe = function() {
+ if (typeof window.Exhibit != "undefined") {
+ return;
+ }
+
+ window.Exhibit = {
+ version: "2.2.0",
+ loaded: false,
+ params: { bundle: !useLocalResources, authenticated: !noAuthentication, autoCreate: true, safe: false },
+ namespace: "http://simile.mit.edu/2006/11/exhibit#",
+ importers: {},
+ locales: [ "en" ]
+ };
+
+ var javascriptFiles = [
+ "exhibit.js",
+ "persistence.js",
+ "authentication.js",
+ "util/set.js",
+ "util/util.js",
+ "util/settings.js",
+ "util/views.js",
+ "util/facets.js",
+ "util/coders.js",
+
+ "data/database.js",
+ "data/expression.js",
+ "data/expression-parser.js",
+ "data/functions.js",
+ "data/controls.js",
+ "data/collection.js",
+
+ "data/importers/authenticated-importer.js",
+ "data/importers/exhibit-json-importer.js",
+ "data/importers/html-table-importer.js",
+ "data/importers/jsonp-importer.js",
+ "data/importers/babel-based-importer.js",
+ "data/importers/rdfa-importer.js",
+ "data/importers/exhibit-xml-importer.js",
+ "data/importers/tsv-csv-importer.js",
+ "data/importers/json-importer.js",
+
+ "data/exporters/rdf-xml-exporter.js",
+ "data/exporters/semantic-wikitext-exporter.js",
+ "data/exporters/exhibit-json-exporter.js",
+ "data/exporters/tsv-exporter.js",
+ "data/exporters/bibtex-exporter.js",
+ "data/exporters/facet-selection-exporter.js",
+
+ "ui/ui.js",
+ "ui/ui-context.js",
+ "ui/lens.js",
+ "ui/format-parser.js",
+ "ui/formatter.js",
+ "ui/coordinator.js",
+
+ "ui/facets/list-facet.js",
+ "ui/facets/numeric-range-facet.js",
+ "ui/facets/text-search-facet.js",
+ "ui/facets/cloud-facet.js",
+ "ui/facets/hierarchical-facet.js",
+ "ui/facets/image-facet.js",
+ "ui/facets/slider-facet.js",
+ "ui/facets/slider.js",
+ "ui/facets/alpha-range-facet.js",
+
+ "ui/coders/color-coder.js",
+ "ui/coders/default-color-coder.js",
+ "ui/coders/color-gradient-coder.js",
+ "ui/coders/size-coder.js",
+ "ui/coders/size-gradient-coder.js",
+ "ui/coders/icon-coder.js",
+
+ "ui/widgets/logo.js",
+ "ui/widgets/collection-summary-widget.js",
+ "ui/widgets/resizable-div-widget.js",
+ "ui/widgets/legend-widget.js",
+ "ui/widgets/legend-gradient-widget.js",
+ "ui/widgets/option-widget.js",
+ "ui/widgets/toolbox-widget.js",
+
+ "ui/views/view-panel.js",
+ "ui/views/ordered-view-frame.js",
+ "ui/views/tile-view.js",
+ "ui/views/thumbnail-view.js",
+ "ui/views/tabular-view.js",
+ "ui/views/html-view.js"
+ ];
+ var cssFiles = [
+ "exhibit.css",
+ "browse-panel.css",
+ "lens.css",
+
+ "util/facets.css",
+ "util/views.css",
+
+ "widgets/collection-summary-widget.css",
+ "widgets/resizable-div-widget.css",
+ "widgets/legend-widget.css",
+ "widgets/option-widget.css",
+ "widgets/toolbox-widget.css",
+
+ "views/view-panel.css",
+ "views/tile-view.css",
+ "views/thumbnail-view.css",
+ "views/tabular-view.css"
+ ];
+
+ var includeMap = false;
+ var includeTimeline = false;
+
+ var defaultClientLocales = ("language" in navigator ? navigator.language : navigator.browserLanguage).split(";");
+ for (var l = 0; l < defaultClientLocales.length; l++) {
+ var locale = defaultClientLocales[l];
+ if (locale != "en") {
+ var segments = locale.split("-");
+ if (segments.length > 1 && segments[0] != "en") {
+ Exhibit.locales.push(segments[0]);
+ }
+ Exhibit.locales.push(locale);
+ }
+ }
+
+ var paramTypes = { bundle:Boolean, js:Array, css:Array, autoCreate:Boolean, safe:Boolean };
+ if (typeof Exhibit_urlPrefix == "string") {
+ Exhibit.urlPrefix = Exhibit_urlPrefix;
+ if ("Exhibit_parameters" in window) {
+ SimileAjax.parseURLParameters(Exhibit_parameters,
+ Exhibit.params,
+ paramTypes);
+ }
+ } else {
+ var url = SimileAjax.findScript(document, "/exhibit-api.js");
+ if (url == null) {
+ Exhibit.error = new Error("Failed to derive URL prefix for Simile Exhibit API code files");
+ return;
+ }
+ Exhibit.urlPrefix = url.substr(0, url.indexOf("exhibit-api.js"));
+
+ SimileAjax.parseURLParameters(url, Exhibit.params, paramTypes);
+ }
+
+ if (useLocalResources) {
+ Exhibit.urlPrefix = wgServer + wgScriptPath + "/extensions/SemanticResultFormats/formats/Exhibit/exhibit/";
+ }
+
+ if (Exhibit.params.locale) { // ISO-639 language codes,
+ // optional ISO-3166 country codes (2 characters)
+ if (Exhibit.params.locale != "en") {
+ var segments = Exhibit.params.locale.split("-");
+ if (segments.length > 1 && segments[0] != "en") {
+ Exhibit.locales.push(segments[0]);
+ }
+ Exhibit.locales.push(Exhibit.params.locale);
+ }
+ }
+ if (Exhibit.params.gmapkey) {
+ includeMap = true;
+ }
+ if (Exhibit.params.views) {
+ var views = Exhibit.params.views.split(",");
+ for (var j = 0; j < views.length; j++) {
+ var view = views[j];
+ if (view == "timeline") {
+ includeTimeline = true;
+ } else if (view == "map") {
+ includeMap = true;
+ }
+ }
+ }
+
+ var scriptURLs = Exhibit.params.js || [];
+ var cssURLs = Exhibit.params.css || [];
+
+ /*
+ * Core scripts and styles
+ */
+ if (Exhibit.params.bundle) {
+ scriptURLs.push(Exhibit.urlPrefix + "exhibit-bundle.js");
+ cssURLs.push(Exhibit.urlPrefix + "exhibit-bundle.css");
+ } else {
+ SimileAjax.prefixURLs(scriptURLs, Exhibit.urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.prefixURLs(cssURLs, Exhibit.urlPrefix + "styles/", cssFiles);
+ }
+
+ /*
+ * Localization
+ */
+ for (var i = 0; i < Exhibit.locales.length; i++) {
+ scriptURLs.push(Exhibit.urlPrefix + "locales/" + Exhibit.locales[i] + "/locale.js");
+ }
+
+ if (Exhibit.params.callback) {
+ window.SimileAjax_onLoad = function() {
+ eval(Exhibit.params.callback + "()");
+ }
+ } else if (Exhibit.params.autoCreate) {
+ scriptURLs.push(Exhibit.urlPrefix + "scripts/create.js");
+ }
+
+ /*
+ * Extensions (for backward compatibility)
+ */
+ if (includeTimeline) {
+ scriptURLs.push(Exhibit.urlPrefix + "extensions/time/time-extension.js");
+ }
+ if (includeMap) {
+ scriptURLs.push(Exhibit.urlPrefix + "extensions/map/map-extension.js");
+ }
+
+ if (!isCompiled) {
+ SimileAjax.includeJavascriptFiles(document, "", scriptURLs);
+ SimileAjax.includeCssFiles(document, "", cssURLs);
+ }
+
+ Exhibit.loaded = true;
+ };
+
+ /*
+ * Load SimileAjax if it's not already loaded
+ */
+ if (typeof SimileAjax == "undefined" && !isCompiled) {
+ window.SimileAjax_onLoad = loadMe;
+
+ var url = /*useLocalResources*/ true ?
+ wgServer + wgScriptPath + "/extensions/SemanticResultFormats/formats/Exhibit/ajax/simile-ajax-api.js?bundle=false" :
+ "http://api.simile-widgets.org/ajax/2.2.1/simile-ajax-api.js";
+
+ var createScriptElement = function() {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.language = "JavaScript";
+ script.src = url;
+ document.getElementsByTagName("head")[0].appendChild(script);
+ }
+ if (document.body == null) {
+ try {
+ document.write("<script src='" + url + "' type='text/javascript'></script>");
+ } catch (e) {
+ createScriptElement();
+ }
+ } else {
+ createScriptElement();
+ }
+ } else {
+ loadMe();
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.css
new file mode 100644
index 00000000..c02398d5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.css
@@ -0,0 +1,742 @@
+/*==================================================
+ * Browse Panel styles
+ *==================================================
+ */
+div.exhibit-browsePanel {
+}
+
+div.exhibit-browsePanel-notConfigureMessage {
+ border: 1px solid #604800;
+ padding: 1em;
+ background: #FFFFE0;
+ text-align: center;
+}
+
+div.exhibit-browsePanel-logoContainer {
+ text-align: center;
+ margin: 1em;
+ clear: both;
+}
+
+/*==================================================
+ * Exhibit styles
+ *
+ * Note that almost all CSS code is in themes.
+ *==================================================
+ */
+.exhibit-ui-protection div {
+ margin: 0;
+ padding: 0;
+}
+.exhibit-ui-protection table {
+ font-size: 100%;
+}
+.exhibit-ui-protection tr {
+ vertical-align: top;
+}
+a img {
+ border: none;
+}
+
+a.exhibit-action,
+a.exhibit-action:link,
+a.exhibit-action:active,
+a.exhibit-action:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+}
+a.exhibit-action:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-action-disabled,
+a.exhibit-action-disabled:link,
+a.exhibit-action-disabled:active,
+a.exhibit-action-disabled:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+ opacity: 0.5;
+}
+a.exhibit-action-disabled:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-item,
+a.exhibit-item:link,
+a.exhibit-item:active,
+a.exhibit-item:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted red;
+ cursor: pointer;
+}
+a.exhibit-item:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+span.exhibit-value {
+}
+
+/*
+ * Menu Popup
+ */
+div.exhibit-menu-popup {
+ position: absolute;
+ width: 15em;
+ z-index: 1000;
+ background: #FFFFE0;
+ border: 1px solid #aaa;
+}
+
+a.exhibit-menu-item {
+ text-decoration: none;
+}
+
+a.exhibit-menu-item > div {
+ padding: 2px 2px 2px 20px;
+ text-indent: -18px;
+}
+
+a:hover.exhibit-menu-item > div {
+ background: #DFDFC8;
+}
+
+a.exhibit-menu-item div img {
+ vertical-align: middle;
+ margin-right: 2px;
+}
+
+div.exhibit-menu-section {
+ padding: 2px;
+ font-weight: bold;
+}
+
+/*
+ * Copy Button and Dialog Box
+ */
+button.exhibit-copyButton, button.exhibit-button {
+ border: 1px dashed;
+ cursor: pointer;
+ margin: 2px;
+}
+button:hover.exhibit-copyButton, button.exhibit-button:hover {
+ background: white;
+ border: 1px dashed blue;
+ color: blue;
+ cursor: pointer;
+}
+
+div.exhibit-copyDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-copyDialog textarea {
+ width: 100%;
+ font-size: 90%;
+ color: #888;
+}
+
+div.exhibit-copyDialog button {
+ float: right;
+}
+
+/*
+ * Focus Dialog Box
+ */
+div.exhibit-focusDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-focusDialog-lensContainer {
+}
+
+div.exhibit-focusDialog-controls {
+ margin: 1em;
+ text-align: center;
+}
+
+/*
+ * Busy indicator
+ */
+.exhibit-busyIndicator {
+ position: absolute;
+ left: 35%;
+ width: 30%;
+ z-index: 1000;
+}
+.exhibit-busyIndicator-content {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.exhibit-busyIndicator-content img {
+ vertical-align: middle;
+}
+div.exhibit-lens {
+ border: 1px solid #aaa;
+ margin-bottom: 1em;
+}
+
+div.exhibit-lens-title {
+ font-weight: bold;
+ background: #eee;
+ padding: 2px;
+}
+
+.exhibit-lens-copyButton {
+ float: right;
+}
+
+div.exhibit-lens-body {
+ padding: 0.3em;
+}
+
+table.exhibit-lens-properties {
+}
+
+tr.exhibit-lens-property {
+}
+
+td.exhibit-lens-property-name {
+ color: #888;
+}
+
+td.exhibit-lens-property-values {
+}
+
+/*==================================================
+ * Facet box
+ *==================================================
+ */
+div.exhibit-facet {
+ position: relative;
+}
+
+div.exhibit-facet-header {
+ padding: 2px;
+}
+div.exhibit-facet-header-filterControl {
+ float: right;
+ width: 2em;
+ display: none;
+ cursor: pointer;
+}
+div.exhibit-facet-header-filterControl img {
+ vertical-align: text-bottom;
+}
+
+img.exhibit-facet-header-collapse {
+ border: 1px;
+ cursor: pointer;
+ padding-right: 3px;
+}
+
+span.exhibit-facet-header-title {
+ font-weight: bold;
+}
+span.exhibit-facet-header-detail {
+ color: #888;
+ padding-left: 0.5em;
+}
+
+div.exhibit-facet-body-frame {
+ clear: both;
+}
+
+div.exhibit-facet-body {
+ border: 1px solid #ddd;
+ height: 10em;
+ overflow: auto;
+}
+
+/*==================================================
+ * Facet value
+ *==================================================
+ */
+
+div.exhibit-facet-value {
+ cursor: pointer;
+ padding: 2px 0px;
+ clear: both;
+}
+div.exhibit-facet-value-selected {
+ font-weight: bold;
+}
+
+div.exhibit-facet-value-count {
+ float: left;
+ width: 2em;
+ text-align: right;
+ color: #aaa;
+}
+
+div.exhibit-facet-value-inner {
+ padding-left: 2.5em;
+}
+
+a.exhibit-facet-value-link {
+ text-decoration: none;
+}
+a.exhibit-facet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-facet-value-checkbox {
+ float: right;
+}
+
+span.exhibit-facet-value-missingThisField {
+ color: #888;
+}
+
+/*==================================================
+ * Flowing facet box
+ *==================================================
+ */
+div.exhibit-flowingFacet {
+ clear: both;
+}
+
+div.exhibit-flowingFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-flowingFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-flowingFacet-body {
+}
+
+/*==================================================
+ * Flowing facet value
+ *==================================================
+ */
+
+div.exhibit-flowingFacet-value {
+ cursor: pointer;
+ clear: both;
+ position: relative;
+ margin-left: 20px;
+}
+
+a.exhibit-flowingFacet-value-link {
+ text-decoration: none;
+}
+a.exhibit-flowingFacet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-flowingFacet-value-selected {
+ font-weight: bold;
+}
+
+span.exhibit-flowingFacet-value-count {
+ color: #aaa;
+}
+
+div.exhibit-flowingFacet-value-checkbox {
+ position: absolute;
+ left: -20px;
+ padding: 0;
+ margin: 0;
+}
+
+/*==================================================
+ * Text search facet
+ *==================================================
+ */
+div.exhibit-text-facet {
+}
+
+div.exhibit-text-facet input {
+ width: 100%;
+}
+
+/*==================================================
+ * Cloud facet
+ *==================================================
+ */
+div.exhibit-cloudFacet {
+ clear: both;
+}
+
+div.exhibit-cloudFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-cloudFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-cloudFacet-body {
+ padding: 0.5em;
+ border: 1px solid #aaa;
+}
+
+span.exhibit-cloudFacet-value {
+ cursor: pointer;
+}
+
+span.exhibit-cloudFacet-value-selected {
+ text-decoration: underline;
+ background: yellow;
+}
+
+/*==================================================
+ * Hierarchical facet
+ *==================================================
+ */
+
+a.exhibit-facet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-facet-value-children-toggle:hover {
+ background: #eee;
+}
+
+a.exhibit-flowingFacet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-flowingFacet-value-children-toggle:hover {
+ background: #eee;
+}
+
+div.exhibit-flowingFacet-childrenContainer {
+}
+
+div.exhibit-facet-childrenContainer {
+ padding-left: 16px;
+}
+
+/*==================================================
+ * Slider facet
+ *==================================================
+ */
+
+div.exhibit-slider {
+ font-size: 0; /* IE sucks */
+ padding-left: 10px;
+}
+
+div.exhibit-slider-bar {
+ background: #000;
+ margin: 5px 0 15px 0;
+ position: relative;
+}
+
+div.exhibit-slider-bar2 {
+ background: #eee;
+ line-height: 0;
+ margin: 15px 10px 10px 5px;
+ height: 150px;
+ width: 20px;
+ position: relative;
+}
+
+div.exhibit-slider-handle {
+ cursor: pointer;
+ float: left;
+ height: 19px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 12px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram {
+ background: #eee;
+}
+
+div.exhibit-slider-handle2 {
+ cursor: pointer;
+ float: left;
+ height: 12px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 19px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram div {
+ background: #999;
+}
+
+div.exhibit-slider-display {
+ font-size: 16px;
+}
+
+.exhibit-slider-display input {
+ background: #eee;
+ font-size: 10px;
+ width: 40px;
+}
+
+/*==================================================
+ * Image facet
+ *==================================================
+ */
+.inline-block {
+ display: -moz-inline-box;
+ display: inline-block;
+}
+
+.exhibit-imageFacet-value, .exhibit-imageFacet-value div, .exhibit-imageFacet-value img {
+ margin: 0px;
+ padding: 0px;
+}
+
+.exhibit-imageFacet-value div.wrapper {
+ margin: 3px;
+ padding: 6px;
+ padding-bottom: 10px;
+ text-align: right;
+ vertical-align: bottom;
+ cursor: pointer;
+ position: relative;
+}
+
+.exhibit-imageFacet-value .countDiv div.text {
+ position: absolute;
+ bottom: .1em;
+ left: .3em;
+}
+.exhibit-imageFacet-value .countDiv {
+ position: absolute;
+ border: 1px solid black;
+ bottom: 0px;
+ right: 5px;
+ width: 2em;
+ height: 2em;
+ font-size: 6pt;
+}
+
+div.countBackground { /* this class makes a window partially transparent */
+ background-color: #FF9000;
+ clear: both;
+ width: 100%;
+ height: 100%;
+ opacity: .5; /* Standard style for transparency */
+ -moz-opacity: .5; /* Transparency for older Mozillas */
+ filter: alpha(opacity=50); /* Transparency for IE */
+}
+
+
+.exhibit-imageFacet-value-selected img {
+ background: #fcc;
+}
+
+ .exhibit-imageFacet-value-selected {
+ background: #fcc;
+}
+/*==================================================
+ * Common styles for views
+ *==================================================
+ */
+div.exhibit-views-unplottableMessage {
+ padding: 1em;
+ text-align: center;
+}
+.exhibit-views-unplottableCount {
+ font-weight: bold;
+}
+.exhibit-views-totalCount {
+}
+
+div.exhibit-views-bubbleWithItems {
+}
+
+div.exhibit-collectionView {
+}
+
+div.exhibit-collectionView-header {
+}
+span.exhibit-collectionView-header-count {
+ font-size: 200%;
+}
+span.exhibit-collectionView-header-types {
+ padding-left: 0.5em;
+}
+span.exhibit-collectionView-header-details {
+ padding-left: 0.5em;
+ color: #888;
+}
+div.exhibit-collectionView-header-sortControls {
+ text-align: center;
+ margin: 1em 0;
+}
+.exhibit-collectionView-header-groupControls {
+ cursor: pointer;
+}
+.exhibit-collectionView-header-duplicateControls {
+ cursor: pointer;
+}
+
+div.exhibit-collectionView-body {
+}
+
+div.exhibit-collectionView-group {
+}
+
+span.exhibit-collectionView-group-count {
+}
+
+div.exhibit-collectionView-group-content {
+ margin-left: 1em;
+}
+
+div.exhibit-collectionView-group h1 {
+ font-size: 150%;
+ margin: 1em 0;
+}
+
+div.exhibit-collectionView-group h2 {
+ font-size: 120%;
+ margin: 0.5em 0;
+}
+
+.exhibit-collectionView-group h3 {
+}
+
+div.exhibit-collectionView-footer {
+ clear: both;
+ text-align: center;
+ margin: 2em 0;
+}
+
+table.exhibit-tabularView-body {
+ width: 100%;
+}
+
+.exhibit-tabularView-columnHeader {
+ cursor: pointer;
+ white-space: pre;
+}
+
+.exhibit-tabularView-columnHeader-sorted {
+ cursor: pointer;
+ white-space: pre;
+}div.exhibit-thumbnailView-group {
+ clear: both;
+}
+
+div.exhibit-thumbnailView-body {
+}
+
+div.exhibit-thumbnailView-itemContainer {
+ float: left;
+}
+
+div.exhibit-thumbnailView-itemContainer-IE {
+ float: left;
+ width: 0;
+ overflow: visible;
+}table.exhibit-tileView-body {
+ width: 100%;
+}
+
+.exhibit-tileView-body > tbody > tr > td:first-child {
+ width: 3em;
+ text-align: right;
+ color: #aaa
+}
+
+td.exhibit-tileView-itemIndex {
+}/*==================================================
+ * View Panel styles
+ *==================================================
+ */
+div.exhibit-viewPanel {
+}
+
+div.exhibit-viewPanel-viewSelection {
+ text-align: center;
+}
+
+span.exhibit-viewPanel-viewSelection-view {
+ text-transform: uppercase;
+ cursor: pointer;
+}
+
+span.exhibit-viewPanel-viewSelection-selectedView {
+ text-transform: uppercase;
+ font-weight: bold;
+ border-bottom: 3px solid red;
+}
+
+div.exhibit-viewPanel-viewContainer {
+}
+
+/*==================================================
+ * Collection Summary Widget styles
+ *==================================================
+ */
+div.exhibit-collectionSummaryWidget {
+}
+span.exhibit-collectionSummaryWidget-count {
+ font-size: 200%;
+}
+span.exhibit-collectionSummaryWidget-results {
+}
+div.exhibit-legendWidget {
+ margin: 1em 0;
+ text-align: center;
+ line-height: 2em;
+}
+div.exhibit-legendWidget-entry {
+}
+span.exhibit-legendWidget-entry-title {
+ font-weight: bold;
+}
+span.exhibit-legendWidget-entry-swatch {
+ border: 1px solid #888;
+ padding: 0px 3px;
+}
+.exhibit-optionWidget {
+ cursor: pointer;
+}
+
+.exhibit-optionWidget img {
+ vertical-align: middle;
+}
+/*==================================================
+ * Resizable Div Widget styles
+ *==================================================
+ */
+div.exhibit-resizableDivWidget-resizer {
+ text-align: center;
+ cursor: s-resize;
+ height: 15px;
+ clear: both;
+}
+div.exhibit-toolboxWidget-popup {
+ position: absolute;
+ border: 1px solid #ccc;
+ background: white;
+ padding: 3px;
+ text-align: right;
+ z-index: 1000;
+}
+
+img.exhibit-toolboxWidget-button {
+ cursor: pointer;
+ margin: 0px 1px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.js
new file mode 100644
index 00000000..83b7da19
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle-debug.js
@@ -0,0 +1,8362 @@
+
+
+/* authentication.js */
+Exhibit.Authentication={};
+Exhibit.Authentication.Enabled=false;
+Exhibit.Authentication.GoogleToken=null;
+Exhibit.Authentication.GoogleSessionToken=null;
+Exhibit.Authentication.authenticate=function(){if(!window.Exhibit.params.authenticated){return ;
+}var links=document.getElementsByTagName("head")[0].childNodes;
+for(var i=0;
+i<links.length;
+i++){var link=links[i];
+if(link.rel=="exhibit/output"&&link.getAttribute("ex:authenticated")){Exhibit.Authentication.handleGoogleAuthentication();
+return ;
+}}};
+Exhibit.Authentication.parseLocationParams=function(){var params=document.location.search.substr(1).split("&");
+var ret={};
+for(var i=0;
+i<params.length;
+i++){var p=params[i];
+if(p.indexOf("=")!=-1){var components=p.split("=");
+if(components.length!=2){SimileAjax.Debug.warn("Error parsing location parameter "+p);
+}else{ret[components[0]]=components[1];
+}}else{ret[p]=true;
+}}return ret;
+};
+Exhibit.Authentication.GoogleAuthenticationURL="https://www.google.com/accounts/AuthSubRequest";
+Exhibit.Authentication.handleGoogleAuthentication=function(){var params=Exhibit.Authentication.parseLocationParams();
+if(params.token){Exhibit.Authentication.GoogleToken=params.token;
+Exhibit.Authentication.Enabled=true;
+}else{var authURL=Exhibit.Authentication.GoogleAuthenticationURL;
+authURL+="?session=1";
+authURL+="&scope=http://spreadsheets.google.com/feeds/";
+authURL+="&next="+document.location.href;
+document.location.href=authURL;
+}};
+
+
+/* collection.js */
+Exhibit.Collection=function(id,database){this._id=id;
+this._database=database;
+this._listeners=new SimileAjax.ListenerQueue();
+this._facets=[];
+this._updating=false;
+this._items=null;
+this._restrictedItems=null;
+};
+Exhibit.Collection.createAllItemsCollection=function(id,database){var collection=new Exhibit.Collection(id,database);
+collection._update=Exhibit.Collection._allItemsCollection_update;
+Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.createSubmissionsCollection=function(id,database){var collection=new Exhibit.Collection(id,database);
+collection._update=Exhibit.Collection._submissionCollection_update;
+Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.create=function(id,configuration,database){var collection=new Exhibit.Collection(id,database);
+if("itemTypes" in configuration){collection._itemTypes=configuration.itemTypes;
+collection._update=Exhibit.Collection._typeBasedCollection_update;
+}else{collection._update=Exhibit.Collection._allItemsCollection_update;
+}Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.createFromDOM=function(id,elmt,database){var collection=new Exhibit.Collection(id,database);
+var itemTypes=Exhibit.getAttribute(elmt,"itemTypes",",");
+if(itemTypes!=null&&itemTypes.length>0){collection._itemTypes=itemTypes;
+collection._update=Exhibit.Collection._typeBasedCollection_update;
+}else{collection._update=Exhibit.Collection._allItemsCollection_update;
+}Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.create2=function(id,configuration,uiContext){var database=uiContext.getDatabase();
+if("expression" in configuration){var collection=new Exhibit.Collection(id,database);
+collection._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+collection._baseCollection=("baseCollectionID" in configuration)?uiContext.getExhibit().getCollection(configuration.baseCollectionID):uiContext.getCollection();
+collection._restrictBaseCollection=("restrictBaseCollection" in configuration)?configuration.restrictBaseCollection:false;
+if(collection._restrictBaseCollection){Exhibit.Collection._initializeRestrictingBasedCollection(collection);
+}else{Exhibit.Collection._initializeBasedCollection(collection);
+}return collection;
+}else{return Exhibit.Collection.create(id,configuration,database);
+}};
+Exhibit.Collection.createFromDOM2=function(id,elmt,uiContext){var database=uiContext.getDatabase();
+var collection;
+if(Exhibit.getAttribute(elmt,"submissionsCollection")){return Exhibit.Collection.createSubmissionsCollection(id,database);
+}var expressionString=Exhibit.getAttribute(elmt,"expression");
+if(expressionString!=null&&expressionString.length>0){collection=new Exhibit.Collection(id,database);
+collection._expression=Exhibit.ExpressionParser.parse(expressionString);
+var baseCollectionID=Exhibit.getAttribute(elmt,"baseCollectionID");
+collection._baseCollection=(baseCollectionID!=null&&baseCollectionID.length>0)?uiContext.getExhibit().getCollection(baseCollectionID):uiContext.getCollection();
+collection._restrictBaseCollection=Exhibit.getAttribute(elmt,"restrictBaseCollection")=="true";
+if(collection._restrictBaseCollection){Exhibit.Collection._initializeRestrictingBasedCollection(collection,database);
+}else{Exhibit.Collection._initializeBasedCollection(collection);
+}}else{collection=Exhibit.Collection.createFromDOM(id,elmt,database);
+}return collection;
+};
+Exhibit.Collection._initializeBasicCollection=function(collection,database){var update=function(){collection._update();
+};
+collection._listener={onAfterLoadingItems:update,onAfterRemovingAllStatements:update};
+database.addListener(collection._listener);
+collection._update();
+};
+Exhibit.Collection._initializeBasedCollection=function(collection){collection._update=Exhibit.Collection._basedCollection_update;
+collection._listener={onItemsChanged:function(){collection._update();
+}};
+collection._baseCollection.addListener(collection._listener);
+collection._update();
+};
+Exhibit.Collection._initializeRestrictingBasedCollection=function(collection,database){collection._cache=new Exhibit.FacetUtilities.Cache(database,collection._baseCollection,collection._expression);
+collection._isUpdatingBaseCollection=false;
+collection.onFacetUpdated=Exhibit.Collection._restrictingBasedCollection_onFacetUpdated;
+collection.restrict=Exhibit.Collection._restrictingBasedCollection_restrict;
+collection.update=Exhibit.Collection._restrictingBasedCollection_update;
+collection.hasRestrictions=Exhibit.Collection._restrictingBasedCollection_hasRestrictions;
+collection._baseCollection.addFacet(collection);
+};
+Exhibit.Collection._allItemsCollection_update=function(){this.setItems(this._database.getAllItems());
+this._onRootItemsChanged();
+};
+Exhibit.Collection._submissionCollection_update=function(){this.setItems(this._database.getAllSubmissions());
+this._onRootItemsChanged();
+};
+Exhibit.Collection._typeBasedCollection_update=function(){var newItems=new Exhibit.Set();
+for(var i=0;
+i<this._itemTypes.length;
+i++){this._database.getSubjects(this._itemTypes[i],"type",newItems);
+}this.setItems(newItems);
+this._onRootItemsChanged();
+};
+Exhibit.Collection._basedCollection_update=function(){this.setItems(this._expression.evaluate({"value":this._baseCollection.getRestrictedItems()},{"value":"item"},"value",this._database).values);
+this._onRootItemsChanged();
+};
+Exhibit.Collection._restrictingBasedCollection_onFacetUpdated=function(facetChanged){if(!this._updating){Exhibit.Collection.prototype.onFacetUpdated.call(this,facetChanged);
+this._isUpdatingBaseCollection=true;
+this._baseCollection.onFacetUpdated(this);
+this._isUpdatingBaseCollection=false;
+}};
+Exhibit.Collection._restrictingBasedCollection_restrict=function(items){if(this._restrictedItems.size()==this._items.size()){return items;
+}return this._cache.getItemsFromValues(this._restrictedItems,items);
+};
+Exhibit.Collection._restrictingBasedCollection_update=function(items){if(!this._isUpdatingBaseCollection){this.setItems(this._cache.getValuesFromItems(items));
+this._onRootItemsChanged();
+}};
+Exhibit.Collection._restrictingBasedCollection_hasRestrictions=function(){return(this._items!=null)&&(this._restrictedItems!=null)&&(this._restrictedItems.size()!=this._items.size());
+};
+Exhibit.Collection.prototype.getID=function(){return this._id;
+};
+Exhibit.Collection.prototype.dispose=function(){if("_baseCollection" in this){this._baseCollection.removeListener(this._listener);
+this._baseCollection=null;
+this._expression=null;
+}else{this._database.removeListener(this._listener);
+}this._database=null;
+this._listener=null;
+this._listeners=null;
+this._items=null;
+this._restrictedItems=null;
+};
+Exhibit.Collection.prototype.addListener=function(listener){this._listeners.add(listener);
+};
+Exhibit.Collection.prototype.removeListener=function(listener){this._listeners.remove(listener);
+};
+Exhibit.Collection.prototype.addFacet=function(facet){this._facets.push(facet);
+if(facet.hasRestrictions()){this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+}else{facet.update(this.getRestrictedItems());
+}};
+Exhibit.Collection.prototype.removeFacet=function(facet){for(var i=0;
+i<this._facets.length;
+i++){if(facet==this._facets[i]){this._facets.splice(i,1);
+if(facet.hasRestrictions()){this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+}break;
+}}};
+Exhibit.Collection.prototype.clearAllRestrictions=function(){var restrictions=[];
+this._updating=true;
+for(var i=0;
+i<this._facets.length;
+i++){restrictions.push(this._facets[i].clearAllRestrictions());
+}this._updating=false;
+this.onFacetUpdated(null);
+return restrictions;
+};
+Exhibit.Collection.prototype.applyRestrictions=function(restrictions){this._updating=true;
+for(var i=0;
+i<this._facets.length;
+i++){this._facets[i].applyRestrictions(restrictions[i]);
+}this._updating=false;
+this.onFacetUpdated(null);
+};
+Exhibit.Collection.prototype.getAllItems=function(){return new Exhibit.Set(this._items);
+};
+Exhibit.Collection.prototype.countAllItems=function(){return this._items.size();
+};
+Exhibit.Collection.prototype.getRestrictedItems=function(){return new Exhibit.Set(this._restrictedItems);
+};
+Exhibit.Collection.prototype.countRestrictedItems=function(){return this._restrictedItems.size();
+};
+Exhibit.Collection.prototype.onFacetUpdated=function(facetChanged){if(!this._updating){this._computeRestrictedItems();
+this._updateFacets(facetChanged);
+this._listeners.fire("onItemsChanged",[]);
+}};
+Exhibit.Collection.prototype._onRootItemsChanged=function(){this._listeners.fire("onRootItemsChanged",[]);
+this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+};
+Exhibit.Collection.prototype._updateFacets=function(facetChanged){var restrictedFacetCount=0;
+for(var i=0;
+i<this._facets.length;
+i++){if(this._facets[i].hasRestrictions()){restrictedFacetCount++;
+}}for(var i=0;
+i<this._facets.length;
+i++){var facet=this._facets[i];
+if(facet.hasRestrictions()){if(restrictedFacetCount<=1){facet.update(this.getAllItems());
+}else{var items=this.getAllItems();
+for(var j=0;
+j<this._facets.length;
+j++){if(i!=j){items=this._facets[j].restrict(items);
+}}facet.update(items);
+}}else{facet.update(this.getRestrictedItems());
+}}};
+Exhibit.Collection.prototype._computeRestrictedItems=function(){this._restrictedItems=this._items;
+for(var i=0;
+i<this._facets.length;
+i++){var facet=this._facets[i];
+if(facet.hasRestrictions()){this._restrictedItems=facet.restrict(this._restrictedItems);
+}}};
+Exhibit.Collection.prototype.setItems=function(items){this._items=items;
+};
+
+
+/* controls.js */
+Exhibit.Controls={};
+Exhibit.Controls["if"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var conditionCollection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var condition=false;
+conditionCollection.forEachValue(function(v){if(v){condition=true;
+return true;
+}});
+if(condition){return args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+}else{return args[2].evaluate(roots,rootValueTypes,defaultRootName,database);
+}}};
+Exhibit.Controls["foreach"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var collection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var oldValue=roots["value"];
+var oldValueType=rootValueTypes["value"];
+rootValueTypes["value"]=collection.valueType;
+var results=[];
+var valueType="text";
+collection.forEachValue(function(element){roots["value"]=element;
+var collection2=args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+valueType=collection2.valueType;
+collection2.forEachValue(function(result){results.push(result);
+});
+});
+roots["value"]=oldValue;
+rootValueTypes["value"]=oldValueType;
+return new Exhibit.Expression._Collection(results,valueType);
+}};
+Exhibit.Controls["default"]={f:function(args,roots,rootValueTypes,defaultRootName,database){for(var i=0;
+i<args.length;
+i++){var collection=args[i].evaluate(roots,rootValueTypes,defaultRootName,database);
+if(collection.size>0){return collection;
+}}return new Exhibit.Expression._Collection([],"text");
+}};
+Exhibit.Controls["filter"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var collection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var oldValue=roots["value"];
+var oldValueType=rootValueTypes["value"];
+var results=new Exhibit.Set();
+rootValueTypes["value"]=collection.valueType;
+collection.forEachValue(function(element){roots["value"]=element;
+var collection2=args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+if(collection2.size>0&&collection2.contains("true")){results.add(element);
+}});
+roots["value"]=oldValue;
+rootValueTypes["value"]=oldValueType;
+return new Exhibit.Expression._Collection(results,collection.valueType);
+}};
+
+
+/* database.js */
+Exhibit.Database=new Object();
+Exhibit.Database.create=function(){Exhibit.Database.handleAuthentication();
+return new Exhibit.Database._Impl();
+};
+Exhibit.Database.handleAuthentication=function(){if(window.Exhibit.params.authenticated){var links=document.getElementsByTagName("head")[0].childNodes;
+for(var i=0;
+i<links.length;
+i++){var link=links[i];
+if(link.rel=="exhibit/output"&&link.getAttribute("ex:authenticated")){}}}};
+Exhibit.Database.makeISO8601DateString=function(date){date=date||new Date();
+var pad=function(i){return i>9?i.toString():"0"+i;
+};
+var s=date.getFullYear()+"-"+pad(date.getMonth()+1)+"-"+pad(date.getDate());
+return s;
+};
+Exhibit.Database.TimestampPropertyName="addedOn";
+Exhibit.Database._Impl=function(){this._types={};
+this._properties={};
+this._propertyArray={};
+this._submissionRegistry={};
+this._originalValues={};
+this._newItems={};
+this._listeners=new SimileAjax.ListenerQueue();
+this._spo={};
+this._ops={};
+this._items=new Exhibit.Set();
+var l10n=Exhibit.Database.l10n;
+var itemType=new Exhibit.Database._Type("Item");
+itemType._custom=Exhibit.Database.l10n.itemType;
+this._types["Item"]=itemType;
+var labelProperty=new Exhibit.Database._Property("label",this);
+labelProperty._uri="http://www.w3.org/2000/01/rdf-schema#label";
+labelProperty._valueType="text";
+labelProperty._label=l10n.labelProperty.label;
+labelProperty._pluralLabel=l10n.labelProperty.pluralLabel;
+labelProperty._reverseLabel=l10n.labelProperty.reverseLabel;
+labelProperty._reversePluralLabel=l10n.labelProperty.reversePluralLabel;
+labelProperty._groupingLabel=l10n.labelProperty.groupingLabel;
+labelProperty._reverseGroupingLabel=l10n.labelProperty.reverseGroupingLabel;
+this._properties["label"]=labelProperty;
+var typeProperty=new Exhibit.Database._Property("type");
+typeProperty._uri="http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+typeProperty._valueType="text";
+typeProperty._label="type";
+typeProperty._pluralLabel=l10n.typeProperty.label;
+typeProperty._reverseLabel=l10n.typeProperty.reverseLabel;
+typeProperty._reversePluralLabel=l10n.typeProperty.reversePluralLabel;
+typeProperty._groupingLabel=l10n.typeProperty.groupingLabel;
+typeProperty._reverseGroupingLabel=l10n.typeProperty.reverseGroupingLabel;
+this._properties["type"]=typeProperty;
+var uriProperty=new Exhibit.Database._Property("uri");
+uriProperty._uri="http://simile.mit.edu/2006/11/exhibit#uri";
+uriProperty._valueType="url";
+uriProperty._label="URI";
+uriProperty._pluralLabel="URIs";
+uriProperty._reverseLabel="URI of";
+uriProperty._reversePluralLabel="URIs of";
+uriProperty._groupingLabel="URIs";
+uriProperty._reverseGroupingLabel="things named by these URIs";
+this._properties["uri"]=uriProperty;
+var changeProperty=new Exhibit.Database._Property("change",this);
+changeProperty._uri="http://simile.mit.edu/2006/11/exhibit#change";
+changeProperty._valueType="text";
+changeProperty._label="change type";
+changeProperty._pluralLabel="change types";
+changeProperty._reverseLabel="change type of";
+changeProperty._reversePluralLabel="change types of";
+changeProperty._groupingLabel="change types";
+changeProperty._reverseGroupingLabel="changes of this type";
+this._properties["change"]=changeProperty;
+var changedItemProperty=new Exhibit.Database._Property("changedItem",this);
+changedItemProperty._uri="http://simile.mit.edu/2006/11/exhibit#changedItem";
+changedItemProperty._valueType="text";
+changedItemProperty._label="changed item";
+changedItemProperty._pluralLabel="changed item";
+changedItemProperty._groupingLabel="changed items";
+this._properties["changedItem"]=changedItemProperty;
+var modifiedProperty=new Exhibit.Database._Property(Exhibit.Database.ModifiedPropertyName,this);
+modifiedProperty._uri="http://simile.mit.edu/2006/11/exhibit#modified";
+modifiedProperty._valueType="text";
+modifiedProperty._label="modified";
+modifiedProperty._pluralLabel="modified";
+modifiedProperty._groupingLabel="was modified";
+this._properties["modified"]=modifiedProperty;
+};
+Exhibit.Database._Impl.prototype.createDatabase=function(){return Exhibit.Database.create();
+};
+Exhibit.Database._Impl.prototype.addListener=function(listener){this._listeners.add(listener);
+};
+Exhibit.Database._Impl.prototype.removeListener=function(listener){this._listeners.remove(listener);
+};
+Exhibit.Database._Impl.prototype.loadDataLinks=function(fDone){var links=SimileAjax.jQuery("head > link[rel=exhibit/data]").get();
+this._loadLinks(links,this,fDone);
+};
+Exhibit.Database._Impl.prototype.loadLinks=function(links,fDone){this._loadLinks(links,this,fDone);
+};
+Exhibit.Database._Impl.prototype.loadSubmissionLinks=function(fDone){var db=this;
+var dbProxy={loadData:function(o,baseURI){if("types" in o){db.loadTypes(o.types,baseURI);
+}if("properties" in o){db.loadProperties(o.properties,baseURI);
+}if("items" in o){db._listeners.fire("onBeforeLoadingItems",[]);
+o.items.forEach(function(item){var oldID=item.id||item.label;
+var newID=oldID+Math.floor(Math.random()*1000000);
+db._submissionRegistry[newID]=true;
+item.id=newID;
+item.changedItem=oldID;
+if(db.containsItem(oldID)){item.change="modification";
+if(!item.type){item.type=db.getObject(oldID,"type");
+}}else{item.change="addition";
+}});
+db.loadItems(o.items,baseURI);
+db._listeners.fire("onAfterLoadingItems",[]);
+}}};
+var links=SimileAjax.jQuery("head > link[rel=exhibit/submissions]").get();
+this._loadLinks(links,dbProxy,fDone);
+};
+Exhibit.Database._Impl.prototype._loadLinks=function(links,database,fDone){links=[].concat(links);
+var fNext=function(){while(links.length>0){var link=links.shift();
+var type=link.type;
+if(type==null||type.length==0){type="application/json";
+}var importer=Exhibit.importers[type];
+if(importer){importer.load(link,database,fNext);
+return ;
+}else{SimileAjax.Debug.log("No importer for data of type "+type);
+}}if(fDone!=null){fDone();
+}};
+fNext();
+};
+Exhibit.Database._Impl.prototype.loadData=function(o,baseURI){if(typeof baseURI=="undefined"){baseURI=location.href;
+}if("types" in o){this.loadTypes(o.types,baseURI);
+}if("properties" in o){this.loadProperties(o.properties,baseURI);
+}if("items" in o){this.loadItems(o.items,baseURI);
+}};
+Exhibit.Database._Impl.prototype.loadTypes=function(typeEntries,baseURI){this._listeners.fire("onBeforeLoadingTypes",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}for(var typeID in typeEntries){if(typeof typeID!="string"){continue;
+}var typeEntry=typeEntries[typeID];
+if(typeof typeEntry!="object"){continue;
+}var type;
+if(typeID in this._types){type=this._types[typeID];
+}else{type=new Exhibit.Database._Type(typeID);
+this._types[typeID]=type;
+}for(var p in typeEntry){type._custom[p]=typeEntry[p];
+}if(!("uri" in type._custom)){type._custom["uri"]=baseURI+"type#"+encodeURIComponent(typeID);
+}if(!("label" in type._custom)){type._custom["label"]=typeID;
+}}this._listeners.fire("onAfterLoadingTypes",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadTypes failed");
+}};
+Exhibit.Database._Impl.prototype.loadProperties=function(propertyEntries,baseURI){this._listeners.fire("onBeforeLoadingProperties",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}for(var propertyID in propertyEntries){if(typeof propertyID!="string"){continue;
+}var propertyEntry=propertyEntries[propertyID];
+if(typeof propertyEntry!="object"){continue;
+}var property;
+if(propertyID in this._properties){property=this._properties[propertyID];
+}else{property=new Exhibit.Database._Property(propertyID,this);
+this._properties[propertyID]=property;
+}property._uri=("uri" in propertyEntry)?propertyEntry.uri:(baseURI+"property#"+encodeURIComponent(propertyID));
+property._valueType=("valueType" in propertyEntry)?propertyEntry.valueType:"text";
+property._label=("label" in propertyEntry)?propertyEntry.label:propertyID;
+property._pluralLabel=("pluralLabel" in propertyEntry)?propertyEntry.pluralLabel:property._label;
+property._reverseLabel=("reverseLabel" in propertyEntry)?propertyEntry.reverseLabel:("!"+property._label);
+property._reversePluralLabel=("reversePluralLabel" in propertyEntry)?propertyEntry.reversePluralLabel:("!"+property._pluralLabel);
+property._groupingLabel=("groupingLabel" in propertyEntry)?propertyEntry.groupingLabel:property._label;
+property._reverseGroupingLabel=("reverseGroupingLabel" in propertyEntry)?propertyEntry.reverseGroupingLabel:property._reverseLabel;
+if("origin" in propertyEntry){property._origin=propertyEntry.origin;
+}}this._propertyArray=null;
+this._listeners.fire("onAfterLoadingProperties",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadProperties failed");
+}};
+Exhibit.Database._Impl.prototype.loadItems=function(itemEntries,baseURI){this._listeners.fire("onBeforeLoadingItems",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}var spo=this._spo;
+var ops=this._ops;
+var indexPut=Exhibit.Database._indexPut;
+var indexTriple=function(s,p,o){indexPut(spo,s,p,o);
+indexPut(ops,o,p,s);
+};
+for(var i=0;
+i<itemEntries.length;
+i++){var entry=itemEntries[i];
+if(typeof entry=="object"){this._loadItem(entry,indexTriple,baseURI);
+}}this._propertyArray=null;
+this._listeners.fire("onAfterLoadingItems",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadItems failed");
+}};
+Exhibit.Database._Impl.prototype.getType=function(typeID){return this._types[typeID];
+};
+Exhibit.Database._Impl.prototype.getProperty=function(propertyID){return propertyID in this._properties?this._properties[propertyID]:null;
+};
+Exhibit.Database._Impl.prototype.getAllProperties=function(){if(this._propertyArray==null){this._propertyArray=[];
+for(var propertyID in this._properties){this._propertyArray.push(propertyID);
+}}return[].concat(this._propertyArray);
+};
+Exhibit.Database._Impl.prototype.isSubmission=function(id){return id in this._submissionRegistry;
+};
+Exhibit.Database._Impl.prototype.getAllItems=function(){var ret=new Exhibit.Set();
+var self=this;
+this._items.visit(function(item){if(!self.isSubmission(item)){ret.add(item);
+}});
+return ret;
+};
+Exhibit.Database._Impl.prototype.getAllSubmissions=function(){var ret=new Exhibit.Set();
+var itemList=this._items.toArray();
+for(var i in itemList){var item=itemList[i];
+if(this.isSubmission(item)){ret.add(item);
+}}return ret;
+};
+Exhibit.Database._Impl.prototype.getAllItemsCount=function(){return this._items.size();
+};
+Exhibit.Database._Impl.prototype.containsItem=function(itemID){return this._items.contains(itemID);
+};
+Exhibit.Database._Impl.prototype.getNamespaces=function(idToQualifiedName,prefixToBase){var bases={};
+for(var propertyID in this._properties){var property=this._properties[propertyID];
+var uri=property.getURI();
+var hash=uri.indexOf("#");
+if(hash>0){var base=uri.substr(0,hash+1);
+bases[base]=true;
+idToQualifiedName[propertyID]={base:base,localName:uri.substr(hash+1)};
+continue;
+}var slash=uri.lastIndexOf("/");
+if(slash>0){var base=uri.substr(0,slash+1);
+bases[base]=true;
+idToQualifiedName[propertyID]={base:base,localName:uri.substr(slash+1)};
+continue;
+}}var baseToPrefix={};
+var letters="abcdefghijklmnopqrstuvwxyz";
+var i=0;
+for(var base in bases){var prefix=letters.substr(i++,1);
+prefixToBase[prefix]=base;
+baseToPrefix[base]=prefix;
+}for(var propertyID in idToQualifiedName){var qname=idToQualifiedName[propertyID];
+qname.prefix=baseToPrefix[qname.base];
+}};
+Exhibit.Database._Impl.prototype._loadItem=function(itemEntry,indexFunction,baseURI){if(!("label" in itemEntry)&&!("id" in itemEntry)){SimileAjax.Debug.warn("Item entry has no label and no id: "+SimileAjax.JSON.toJSONString(itemEntry));
+return ;
+}var id;
+if(!("label" in itemEntry)){id=itemEntry.id;
+if(!this._items.contains(id)){SimileAjax.Debug.warn("Cannot add new item containing no label: "+SimileAjax.JSON.toJSONString(itemEntry));
+}}else{var label=itemEntry.label;
+var id=("id" in itemEntry)?itemEntry.id:label;
+var uri=("uri" in itemEntry)?itemEntry.uri:(baseURI+"item#"+encodeURIComponent(id));
+var type=("type" in itemEntry)?itemEntry.type:"Item";
+var isArray=function(obj){if(obj.constructor.toString().indexOf("Array")==-1){return false;
+}else{return true;
+}};
+if(isArray(label)){label=label[0];
+}if(isArray(id)){id=id[0];
+}if(isArray(uri)){uri=uri[0];
+}if(isArray(type)){type=type[0];
+}this._items.add(id);
+indexFunction(id,"uri",uri);
+indexFunction(id,"label",label);
+indexFunction(id,"type",type);
+this._ensureTypeExists(type,baseURI);
+}itemEntry.modified=itemEntry.modified||"no";
+for(var p in itemEntry){if(typeof p!="string"){continue;
+}if(p!="uri"&&p!="label"&&p!="id"&&p!="type"){this._ensurePropertyExists(p,baseURI)._onNewData();
+var v=itemEntry[p];
+if(v instanceof Array){for(var j=0;
+j<v.length;
+j++){indexFunction(id,p,v[j]);
+}}else{if(v!=undefined&&v!=null){indexFunction(id,p,v);
+}}}}};
+Exhibit.Database._Impl.prototype._ensureTypeExists=function(typeID,baseURI){if(!(typeID in this._types)){var type=new Exhibit.Database._Type(typeID);
+type._custom["uri"]=baseURI+"type#"+encodeURIComponent(typeID);
+type._custom["label"]=typeID;
+this._types[typeID]=type;
+}};
+Exhibit.Database._Impl.prototype._ensurePropertyExists=function(propertyID,baseURI){if(!(propertyID in this._properties)){var property=new Exhibit.Database._Property(propertyID,this);
+property._uri=baseURI+"property#"+encodeURIComponent(propertyID);
+property._valueType="text";
+property._label=propertyID;
+property._pluralLabel=property._label;
+property._reverseLabel="reverse of "+property._label;
+property._reversePluralLabel="reverse of "+property._pluralLabel;
+property._groupingLabel=property._label;
+property._reverseGroupingLabel=property._reverseLabel;
+this._properties[propertyID]=property;
+this._propertyArray=null;
+return property;
+}else{return this._properties[propertyID];
+}};
+Exhibit.Database._indexPut=function(index,x,y,z){var hash=index[x];
+if(!hash){hash={};
+index[x]=hash;
+}var array=hash[y];
+if(!array){array=new Array();
+hash[y]=array;
+}else{for(var i=0;
+i<array.length;
+i++){if(z==array[i]){return ;
+}}}array.push(z);
+};
+Exhibit.Database._indexPutList=function(index,x,y,list){var hash=index[x];
+if(!hash){hash={};
+index[x]=hash;
+}var array=hash[y];
+if(!array){hash[y]=list;
+}else{hash[y]=hash[y].concat(list);
+}};
+Exhibit.Database._indexRemove=function(index,x,y,z){function isEmpty(obj){for(p in obj){return false;
+}return true;
+}var hash=index[x];
+if(!hash){return false;
+}var array=hash[y];
+if(!array){return false;
+}for(var i=0;
+i<array.length;
+i++){if(z==array[i]){array.splice(i,1);
+if(array.length==0){delete hash[y];
+if(isEmpty(hash)){delete index[x];
+}}return true;
+}}};
+Exhibit.Database._indexRemoveList=function(index,x,y){var hash=index[x];
+if(!hash){return null;
+}var array=hash[y];
+if(!array){return null;
+}delete hash[y];
+return array;
+};
+Exhibit.Database._Impl.prototype._indexFillSet=function(index,x,y,set,filter){var hash=index[x];
+if(hash){var array=hash[y];
+if(array){if(filter){for(var i=0;
+i<array.length;
+i++){var z=array[i];
+if(filter.contains(z)){set.add(z);
+}}}else{for(var i=0;
+i<array.length;
+i++){set.add(array[i]);
+}}}}};
+Exhibit.Database._Impl.prototype._indexCountDistinct=function(index,x,y,filter){var count=0;
+var hash=index[x];
+if(hash){var array=hash[y];
+if(array){if(filter){for(var i=0;
+i<array.length;
+i++){if(filter.contains(array[i])){count++;
+}}}else{count=array.length;
+}}}return count;
+};
+Exhibit.Database._Impl.prototype._get=function(index,x,y,set,filter){if(!set){set=new Exhibit.Set();
+}this._indexFillSet(index,x,y,set,filter);
+return set;
+};
+Exhibit.Database._Impl.prototype._getUnion=function(index,xSet,y,set,filter){if(!set){set=new Exhibit.Set();
+}var database=this;
+xSet.visit(function(x){database._indexFillSet(index,x,y,set,filter);
+});
+return set;
+};
+Exhibit.Database._Impl.prototype._countDistinctUnion=function(index,xSet,y,filter){var count=0;
+var database=this;
+xSet.visit(function(x){count+=database._indexCountDistinct(index,x,y,filter);
+});
+return count;
+};
+Exhibit.Database._Impl.prototype._countDistinct=function(index,x,y,filter){return this._indexCountDistinct(index,x,y,filter);
+};
+Exhibit.Database._Impl.prototype._getProperties=function(index,x){var hash=index[x];
+var properties=[];
+if(hash){for(var p in hash){properties.push(p);
+}}return properties;
+};
+Exhibit.Database._Impl.prototype.getObjects=function(s,p,set,filter){return this._get(this._spo,s,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctObjects=function(s,p,filter){return this._countDistinct(this._spo,s,p,filter);
+};
+Exhibit.Database._Impl.prototype.getObjectsUnion=function(subjects,p,set,filter){return this._getUnion(this._spo,subjects,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctObjectsUnion=function(subjects,p,filter){return this._countDistinctUnion(this._spo,subjects,p,filter);
+};
+Exhibit.Database._Impl.prototype.getSubjects=function(o,p,set,filter){return this._get(this._ops,o,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctSubjects=function(o,p,filter){return this._countDistinct(this._ops,o,p,filter);
+};
+Exhibit.Database._Impl.prototype.getSubjectsUnion=function(objects,p,set,filter){return this._getUnion(this._ops,objects,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctSubjectsUnion=function(objects,p,filter){return this._countDistinctUnion(this._ops,objects,p,filter);
+};
+Exhibit.Database._Impl.prototype.getObject=function(s,p){var hash=this._spo[s];
+if(hash){var array=hash[p];
+if(array){return array[0];
+}}return null;
+};
+Exhibit.Database._Impl.prototype.getSubject=function(o,p){var hash=this._ops[o];
+if(hash){var array=hash[p];
+if(array){return array[0];
+}}return null;
+};
+Exhibit.Database._Impl.prototype.getForwardProperties=function(s){return this._getProperties(this._spo,s);
+};
+Exhibit.Database._Impl.prototype.getBackwardProperties=function(o){return this._getProperties(this._ops,o);
+};
+Exhibit.Database._Impl.prototype.getSubjectsInRange=function(p,min,max,inclusive,set,filter){var property=this.getProperty(p);
+if(property!=null){var rangeIndex=property.getRangeIndex();
+if(rangeIndex!=null){return rangeIndex.getSubjectsInRange(min,max,inclusive,set,filter);
+}}return(!set)?new Exhibit.Set():set;
+};
+Exhibit.Database._Impl.prototype.getTypeIDs=function(set){return this.getObjectsUnion(set,"type",null,null);
+};
+Exhibit.Database._Impl.prototype.addStatement=function(s,p,o){var indexPut=Exhibit.Database._indexPut;
+indexPut(this._spo,s,p,o);
+indexPut(this._ops,o,p,s);
+};
+Exhibit.Database._Impl.prototype.removeStatement=function(s,p,o){var indexRemove=Exhibit.Database._indexRemove;
+var removedObject=indexRemove(this._spo,s,p,o);
+var removedSubject=indexRemove(this._ops,o,p,s);
+return removedObject||removedSubject;
+};
+Exhibit.Database._Impl.prototype.removeObjects=function(s,p){var indexRemove=Exhibit.Database._indexRemove;
+var indexRemoveList=Exhibit.Database._indexRemoveList;
+var objects=indexRemoveList(this._spo,s,p);
+if(objects==null){return false;
+}else{for(var i=0;
+i<objects.length;
+i++){indexRemove(this._ops,objects[i],p,s);
+}return true;
+}};
+Exhibit.Database._Impl.prototype.removeSubjects=function(o,p){var indexRemove=Exhibit.Database._indexRemove;
+var indexRemoveList=Exhibit.Database._indexRemoveList;
+var subjects=indexRemoveList(this._ops,o,p);
+if(subjects==null){return false;
+}else{for(var i=0;
+i<subjects.length;
+i++){indexRemove(this._spo,subjects[i],p,o);
+}return true;
+}};
+Exhibit.Database._Impl.prototype.removeAllStatements=function(){this._listeners.fire("onBeforeRemovingAllStatements",[]);
+try{this._spo={};
+this._ops={};
+this._items=new Exhibit.Set();
+for(var propertyID in this._properties){this._properties[propertyID]._onNewData();
+}this._propertyArray=null;
+this._listeners.fire("onAfterRemovingAllStatements",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.removeAllStatements failed");
+}};
+Exhibit.Database._Type=function(id){this._id=id;
+this._custom={};
+};
+Exhibit.Database._Type.prototype={getID:function(){return this._id;
+},getURI:function(){return this._custom["uri"];
+},getLabel:function(){return this._custom["label"];
+},getOrigin:function(){return this._custom["origin"];
+},getProperty:function(p){return this._custom[p];
+}};
+Exhibit.Database._Property=function(id,database){this._id=id;
+this._database=database;
+this._rangeIndex=null;
+};
+Exhibit.Database._Property.prototype={getID:function(){return this._id;
+},getURI:function(){return this._uri;
+},getValueType:function(){return this._valueType;
+},getLabel:function(){return this._label;
+},getPluralLabel:function(){return this._pluralLabel;
+},getReverseLabel:function(){return this._reverseLabel;
+},getReversePluralLabel:function(){return this._reversePluralLabel;
+},getGroupingLabel:function(){return this._groupingLabel;
+},getGroupingPluralLabel:function(){return this._groupingPluralLabel;
+},getOrigin:function(){return this._origin;
+}};
+Exhibit.Database._Property.prototype._onNewData=function(){this._rangeIndex=null;
+};
+Exhibit.Database._Property.prototype.getRangeIndex=function(){if(this._rangeIndex==null){this._buildRangeIndex();
+}return this._rangeIndex;
+};
+Exhibit.Database._Property.prototype._buildRangeIndex=function(){var getter;
+var database=this._database;
+var p=this._id;
+switch(this.getValueType()){case"currency":case"number":getter=function(item,f){database.getObjects(item,p,null,null).visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+break;
+case"date":getter=function(item,f){database.getObjects(item,p,null,null).visit(function(value){if(value!=null&&!(value instanceof Date)){value=SimileAjax.DateTime.parseIso8601DateTime(value);
+}if(value instanceof Date){f(value.getTime());
+}});
+};
+break;
+default:getter=function(item,f){};
+}this._rangeIndex=new Exhibit.Database._RangeIndex(this._database.getAllItems(),getter);
+};
+Exhibit.Database._RangeIndex=function(items,getter){pairs=[];
+items.visit(function(item){getter(item,function(value){pairs.push({item:item,value:value});
+});
+});
+pairs.sort(function(p1,p2){var c=p1.value-p2.value;
+return(isNaN(c)===false)?c:p1.value.localeCompare(p2.value);
+});
+this._pairs=pairs;
+};
+Exhibit.Database._RangeIndex.prototype.getCount=function(){return this._pairs.length;
+};
+Exhibit.Database._RangeIndex.prototype.getMin=function(){return this._pairs.length>0?this._pairs[0].value:Number.POSITIVE_INFINITY;
+};
+Exhibit.Database._RangeIndex.prototype.getMax=function(){return this._pairs.length>0?this._pairs[this._pairs.length-1].value:Number.NEGATIVE_INFINITY;
+};
+Exhibit.Database._RangeIndex.prototype.getRange=function(visitor,min,max,inclusive){var startIndex=this._indexOf(min);
+var pairs=this._pairs;
+var l=pairs.length;
+inclusive=(inclusive);
+while(startIndex<l){var pair=pairs[startIndex++];
+var value=pair.value;
+if(value<max||(value==max&&inclusive)){visitor(pair.item);
+}else{break;
+}}};
+Exhibit.Database._RangeIndex.prototype.getSubjectsInRange=function(min,max,inclusive,set,filter){if(!set){set=new Exhibit.Set();
+}var f=(filter!=null)?function(item){if(filter.contains(item)){set.add(item);
+}}:function(item){set.add(item);
+};
+this.getRange(f,min,max,inclusive);
+return set;
+};
+Exhibit.Database._RangeIndex.prototype.countRange=function(min,max,inclusive){var startIndex=this._indexOf(min);
+var endIndex=this._indexOf(max);
+if(inclusive){var pairs=this._pairs;
+var l=pairs.length;
+while(endIndex<l){if(pairs[endIndex].value==max){endIndex++;
+}else{break;
+}}}return endIndex-startIndex;
+};
+Exhibit.Database._RangeIndex.prototype._indexOf=function(v){var pairs=this._pairs;
+if(pairs.length==0||pairs[0].value>=v){return 0;
+}var from=0;
+var to=pairs.length;
+while(from+1<to){var middle=(from+to)>>1;
+var v2=pairs[middle].value;
+if(v2>=v){to=middle;
+}else{from=middle;
+}}return to;
+};
+Exhibit.Database._Impl.prototype.isNewItem=function(id){return id in this._newItems;
+};
+Exhibit.Database._Impl.prototype.getItem=function(id){var item={id:id};
+var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+var val=this.getObject(id,prop);
+if(val){item[prop]=val;
+}}return item;
+};
+Exhibit.Database._Impl.prototype.addItem=function(item){if(!item.id){item.id=item.label;
+}if(!item.modified){item.modified="yes";
+}this._ensurePropertyExists(Exhibit.Database.TimestampPropertyName);
+item[Exhibit.Database.TimestampPropertyName]=Exhibit.Database.makeISO8601DateString();
+this.loadItems([item],"");
+this._newItems[item.id]=true;
+this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database._Impl.prototype.editItem=function(id,prop,value){if(prop.toLowerCase()=="id"){Exhibit.UI.showHelp("We apologize, but changing the IDs of items in the Exhibit isn't supported at the moment.");
+return ;
+}var prevValue=this.getObject(id,prop);
+this._originalValues[id]=this._originalValues[id]||{};
+this._originalValues[id][prop]=this._originalValues[id][prop]||prevValue;
+var origVal=this._originalValues[id][prop];
+if(origVal==value){this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+delete this._originalValues[id][prop];
+}else{if(this.getObject(id,"modified")!="yes"){this.removeObjects(id,"modified");
+this.addStatement(id,"modified","yes");
+}}this.removeObjects(id,prop);
+this.addStatement(id,prop,value);
+var propertyObject=this._ensurePropertyExists(prop);
+propertyObject._onNewData();
+this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database._Impl.prototype.removeItem=function(id){if(!this.containsItem(id)){throw"Removing non-existent item "+id;
+}this._items.remove(id);
+delete this._spo[id];
+if(this._newItems[id]){delete this._newItems[id];
+}if(this._originalValues[id]){delete this._originalValues[id];
+}var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+this.removeObjects(id,prop);
+}this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database.defaultIgnoredProperties=["uri","modified"];
+Exhibit.Database._Impl.prototype.fixAllChanges=function(){this._originalValues={};
+this._newItems={};
+var items=this._items.toArray();
+for(var i in items){var id=items[i];
+this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+}};
+Exhibit.Database._Impl.prototype.fixChangesForItem=function(id){delete this._originalValues[id];
+delete this._newItems[id];
+this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+};
+Exhibit.Database._Impl.prototype.collectChangesForItem=function(id,ignoredProperties){ignoredProperties=ignoredProperties||Exhibit.Database.defaultIgnoredProperties;
+var type=this.getObject(id,"type");
+var label=this.getObject(id,"label")||id;
+var item={id:id,label:label,type:type,vals:{}};
+if(id in this._newItems){item.changeType="added";
+var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+if(ignoredProperties.indexOf(prop)!=-1){continue;
+}var val=this.getObject(id,prop);
+if(val){item.vals[prop]={newVal:val};
+}}}else{if(id in this._originalValues&&!this.isSubmission(id)){item.changeType="modified";
+var vals=this._originalValues[id];
+var hasModification=false;
+for(var prop in vals){if(ignoredProperties.indexOf(prop)!=-1){continue;
+}hasModification=true;
+var oldVal=this._originalValues[id][prop];
+var newVal=this.getObject(id,prop);
+if(!newVal){SimileAjax.Debug.warn("empty value for "+id+", "+prop);
+}else{item.vals[prop]={oldVal:oldVal,newVal:newVal};
+}}if(!hasModification){return null;
+}}else{return null;
+}}if(!item[Exhibit.Database.TimestampPropertyName]){item[Exhibit.Database.TimestampPropertyName]=Exhibit.Database.makeISO8601DateString();
+}return item;
+};
+Exhibit.Database._Impl.prototype.collectAllChanges=function(ignoredProperties){var ret=[];
+var items=this._items.toArray();
+for(var i in items){var id=items[i];
+var item=this.collectChangesForItem(id,ignoredProperties);
+if(item){ret.push(item);
+}}return ret;
+};
+Exhibit.Database._Impl.prototype.mergeSubmissionIntoItem=function(submissionID){var db=this;
+if(!this.isSubmission(submissionID)){throw submissionID+" is not a submission!";
+}var change=this.getObject(submissionID,"change");
+if(change=="modification"){var itemID=this.getObject(submissionID,"changedItem");
+var vals=this._spo[submissionID];
+SimileAjax.jQuery.each(vals,function(attr,val){if(Exhibit.Database.defaultIgnoredSubmissionProperties.indexOf(attr)!=-1){return ;
+}if(val.length==1){db.editItem(itemID,attr,val[0]);
+}else{SimileAjax.Debug.warn("Exhibit.Database._Impl.prototype.commitChangeToItem cannot handle multiple values for attribute "+attr+": "+val);
+}});
+delete this._submissionRegistry[submissionID];
+}else{if(change=="addition"){delete this._submissionRegistry[submissionID];
+this._newItems[submissionID]=true;
+}else{throw"unknown change type "+change;
+}}this._listeners.fire("onAfterLoadingItems",[]);
+};
+
+
+/* bibtex-exporter.js */
+Exhibit.BibtexExporter={getLabel:function(){return"Bibtex";
+},_excludeProperties:{"pub-type":true,"type":true,"uri":true,"key":true}};
+Exhibit.BibtexExporter.exportOne=function(itemID,database){return Exhibit.BibtexExporter._wrap(Exhibit.BibtexExporter._exportOne(itemID,database));
+};
+Exhibit.BibtexExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.BibtexExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.BibtexExporter._wrap(s);
+};
+Exhibit.BibtexExporter._exportOne=function(itemID,database){var s="";
+var type=database.getObject(itemID,"pub-type");
+var key=database.getObject(itemID,"key");
+key=(key!=null?key:itemID);
+key=key.replace(/[\s,]/g,"-");
+s+="@"+type+"{"+key+",\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(values.size()>0&&!(propertyID in Exhibit.BibtexExporter._excludeProperties)){s+="\t"+(propertyID=="label"?"title":propertyID)+' = "';
+var strings;
+if(valueType=="item"){strings=[];
+values.visit(function(value){strings.push(database.getObject(value,"label"));
+});
+}else{if(valueType=="url"){strings=[];
+values.visit(function(value){strings.push(Exhibit.Persistence.resolveURL(value));
+});
+}else{strings=values.toArray();
+}}s+=strings.join(" and ")+'",\n';
+}}s+='\torigin = "'+Exhibit.Persistence.getItemLink(itemID)+'"\n';
+s+="}\n";
+return s;
+};
+Exhibit.BibtexExporter._wrap=function(s){return s;
+};
+
+
+/* exhibit-json-exporter.js */
+Exhibit.ExhibitJsonExporter={getLabel:function(){return Exhibit.l10n.exhibitJsonExporterLabel;
+}};
+Exhibit.ExhibitJsonExporter.exportOne=function(itemID,database){return Exhibit.ExhibitJsonExporter._wrap(Exhibit.ExhibitJsonExporter._exportOne(itemID,database)+"\n");
+};
+Exhibit.ExhibitJsonExporter.exportMany=function(set,database){var s="";
+var size=set.size();
+var count=0;
+set.visit(function(itemID){s+=Exhibit.ExhibitJsonExporter._exportOne(itemID,database)+((count++<size-1)?",\n":"\n");
+});
+return Exhibit.ExhibitJsonExporter._wrap(s);
+};
+Exhibit.ExhibitJsonExporter._exportOne=function(itemID,database){function quote(s){if(/[\\\x00-\x1F\x22]/.test(s)){return'"'+s.replace(/([\\\x00-\x1f\x22])/g,function(a,b){var c={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"}[b];
+if(c){return c;
+}c=b.charCodeAt();
+return"\\x"+Math.floor(c/16).toString(16)+(c%16).toString(16);
+})+'"';
+}return'"'+s+'"';
+}var s="";
+var uri=database.getObject(itemID,"uri");
+s+=' {"id":'+quote(itemID)+",\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(values.size()>0){var array;
+if(valueType=="url"){array=[];
+values.visit(function(value){array.push(Exhibit.Persistence.resolveURL(value));
+});
+}else{array=values.toArray();
+}s+=" "+quote(propertyID)+":";
+if(array.length==1){s+=quote(array[0]);
+}else{s+="[";
+for(var j=0;
+j<array.length;
+j++){s+=(j>0?",":"")+quote(array[j]);
+}s+="]";
+}s+=",\n";
+}}s+=' "origin":'+quote(Exhibit.Persistence.getItemLink(itemID))+"\n";
+s+=" }";
+return s;
+};
+Exhibit.ExhibitJsonExporter._wrap=function(s){return'{\n "items":[\n'+s+" ]\n}";
+};
+
+
+/* facet-selection-exporter.js */
+Exhibit.FacetSelectionExporter={getLabel:function(){return"Facet Selections";
+},exportOne:function(itemID,database){return Exhibit.FacetSelectionExporter._exportUrl();
+},exportMany:function(set,database){return Exhibit.FacetSelectionExporter._exportUrl();
+}};
+Exhibit.FacetSelectionExporter._exportUrl=function(){var currentSettings=window.exhibit.exportSettings();
+var url=window.location.href.split("?")[0]+"?";
+var sep="";
+for(id in currentSettings){url+=sep+id+"="+escape(currentSettings[id]);
+if(sep===""){sep="&";
+}}return url;
+};
+
+
+/* rdf-xml-exporter.js */
+Exhibit.RdfXmlExporter={getLabel:function(){return Exhibit.l10n.rdfXmlExporterLabel;
+}};
+Exhibit.RdfXmlExporter.exportOne=function(itemID,database){var propertyIDToQualifiedName={};
+var prefixToBase={};
+database.getNamespaces(propertyIDToQualifiedName,prefixToBase);
+return Exhibit.RdfXmlExporter._wrapRdf(Exhibit.RdfXmlExporter._exportOne(itemID,database,propertyIDToQualifiedName,prefixToBase),prefixToBase);
+};
+Exhibit.RdfXmlExporter.exportMany=function(set,database){var s="";
+var propertyIDToQualifiedName={};
+var prefixToBase={};
+database.getNamespaces(propertyIDToQualifiedName,prefixToBase);
+set.visit(function(itemID){s+=Exhibit.RdfXmlExporter._exportOne(itemID,database,propertyIDToQualifiedName,prefixToBase)+"\n";
+});
+return Exhibit.RdfXmlExporter._wrapRdf(s,prefixToBase);
+};
+Exhibit.RdfXmlExporter._exportOne=function(itemID,database,propertyIDToQualifiedName,prefixToBase){var s="";
+var uri=database.getObject(itemID,"uri");
+s+="<rdf:Description rdf:about='"+uri+"'>\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+var propertyString;
+if(propertyID in propertyIDToQualifiedName){var qname=propertyIDToQualifiedName[propertyID];
+propertyString=qname.prefix+":"+qname.localName;
+}else{propertyString=property.getURI();
+}if(valueType=="item"){values.visit(function(value){s+="\t<"+propertyString+" rdf:resource='"+value+"' />\n";
+});
+}else{if(propertyID!="uri"){if(valueType=="url"){values.visit(function(value){s+="\t<"+propertyString+">"+Exhibit.Persistence.resolveURL(value)+"</"+propertyString+">\n";
+});
+}else{values.visit(function(value){s+="\t<"+propertyString+">"+value+"</"+propertyString+">\n";
+});
+}}}}s+="\t<exhibit:origin>"+Exhibit.Persistence.getItemLink(itemID)+"</exhibit:origin>\n";
+s+="</rdf:Description>";
+return s;
+};
+Exhibit.RdfXmlExporter._wrapRdf=function(s,prefixToBase){var s2="<?xml version = '1.0'?>\n<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n\txmlns:exhibit='http://simile.mit.edu/2006/11/exhibit#'";
+for(prefix in prefixToBase){s2+="\n\txmlns:"+prefix+"='"+prefixToBase[prefix]+"'";
+}s2+=">\n"+s+"\n</rdf:RDF>";
+return s2;
+};
+
+
+/* semantic-wikitext-exporter.js */
+Exhibit.SemanticWikitextExporter={getLabel:function(){return Exhibit.l10n.smwExporterLabel;
+}};
+Exhibit.SemanticWikitextExporter.exportOne=function(itemID,database){return Exhibit.SemanticWikitextExporter._wrap(Exhibit.SemanticWikitextExporter._exportOne(itemID,database));
+};
+Exhibit.SemanticWikitextExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.SemanticWikitextExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.SemanticWikitextExporter._wrap(s);
+};
+Exhibit.SemanticWikitextExporter._exportOne=function(itemID,database){var s="";
+var uri=database.getObject(itemID,"uri");
+s+=uri+"\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(valueType=="item"){values.visit(function(value){s+="[["+propertyID+"::"+value+"]]\n";
+});
+}else{if(valueType=="url"){values.visit(function(value){s+="[["+propertyID+":="+Exhibit.Persistence.resolveURL(value)+"]]\n";
+});
+}else{values.visit(function(value){s+="[["+propertyID+":="+value+"]]\n";
+});
+}}}s+="[[origin:="+Exhibit.Persistence.getItemLink(itemID)+"]]\n";
+s+="\n";
+return s;
+};
+Exhibit.SemanticWikitextExporter._wrap=function(s){return s;
+};
+
+
+/* tsv-exporter.js */
+Exhibit.TSVExporter={getLabel:function(){return Exhibit.l10n.tsvExporterLabel;
+}};
+Exhibit.TSVExporter.exportOne=function(itemID,database){return Exhibit.TSVExporter._wrap(Exhibit.TSVExporter._exportOne(itemID,database),database);
+};
+Exhibit.TSVExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.TSVExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.TSVExporter._wrap(s,database);
+};
+Exhibit.TSVExporter._exportOne=function(itemID,database){var s="";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+s+=values.toArray().join("; ")+"\t";
+}return s;
+};
+Exhibit.TSVExporter._wrap=function(s,database){var header="";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var valueType=property.getValueType();
+header+=propertyID+":"+valueType+"\t";
+}return header+"\n"+s;
+};
+
+
+/* expression-parser.js */
+Exhibit.ExpressionParser=new Object();
+Exhibit.ExpressionParser.parse=function(s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.ExpressionScanner(s,startIndex);
+try{return Exhibit.ExpressionParser._internalParse(scanner,false);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.ExpressionParser.parseSeveral=function(s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.ExpressionScanner(s,startIndex);
+try{return Exhibit.ExpressionParser._internalParse(scanner,true);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.ExpressionParser._internalParse=function(scanner,several){var Scanner=Exhibit.ExpressionScanner;
+var token=scanner.token();
+var next=function(){scanner.next();
+token=scanner.token();
+};
+var makePosition=function(){return token!=null?token.start:scanner.index();
+};
+var parsePath=function(){var path=new Exhibit.Expression.Path();
+while(token!=null&&token.type==Scanner.PATH_OPERATOR){var hopOperator=token.value;
+next();
+if(token!=null&&token.type==Scanner.IDENTIFIER){path.appendSegment(token.value,hopOperator);
+next();
+}else{throw new Error("Missing property ID at position "+makePosition());
+}}return path;
+};
+var parseFactor=function(){if(token==null){throw new Error("Missing factor at end of expression");
+}var result=null;
+switch(token.type){case Scanner.NUMBER:result=new Exhibit.Expression._Constant(token.value,"number");
+next();
+break;
+case Scanner.STRING:result=new Exhibit.Expression._Constant(token.value,"text");
+next();
+break;
+case Scanner.PATH_OPERATOR:result=parsePath();
+break;
+case Scanner.IDENTIFIER:var identifier=token.value;
+next();
+if(identifier in Exhibit.Controls){if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="("){next();
+var args=(token!=null&&token.type==Scanner.DELIMITER&&token.value==")")?[]:parseExpressionList();
+result=new Exhibit.Expression._ControlCall(identifier,args);
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+}else{throw new Error("Missing ) to end "+identifier+" at position "+makePosition());
+}}else{throw new Error("Missing ( to start "+identifier+" at position "+makePosition());
+}}else{if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="("){next();
+var args=(token!=null&&token.type==Scanner.DELIMITER&&token.value==")")?[]:parseExpressionList();
+result=new Exhibit.Expression._FunctionCall(identifier,args);
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+}else{throw new Error("Missing ) after function call "+identifier+" at position "+makePosition());
+}}else{result=parsePath();
+result.setRootName(identifier);
+}}break;
+case Scanner.DELIMITER:if(token.value=="("){next();
+result=parseExpression();
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+break;
+}else{throw new Error("Missing ) at position "+makePosition());
+}}default:throw new Error("Unexpected text "+token.value+" at position "+makePosition());
+}return result;
+};
+var parseTerm=function(){var term=parseFactor();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="*"||token.value=="/")){var operator=token.value;
+next();
+term=new Exhibit.Expression._Operator(operator,[term,parseFactor()]);
+}return term;
+};
+var parseSubExpression=function(){var subExpression=parseTerm();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="+"||token.value=="-")){var operator=token.value;
+next();
+subExpression=new Exhibit.Expression._Operator(operator,[subExpression,parseTerm()]);
+}return subExpression;
+};
+var parseExpression=function(){var expression=parseSubExpression();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="="||token.value=="<>"||token.value=="<"||token.value=="<="||token.value==">"||token.value==">=")){var operator=token.value;
+next();
+expression=new Exhibit.Expression._Operator(operator,[expression,parseSubExpression()]);
+}return expression;
+};
+var parseExpressionList=function(){var expressions=[parseExpression()];
+while(token!=null&&token.type==Scanner.DELIMITER&&token.value==","){next();
+expressions.push(parseExpression());
+}return expressions;
+};
+if(several){var roots=parseExpressionList();
+var expressions=[];
+for(var r=0;
+r<roots.length;
+r++){expressions.push(new Exhibit.Expression._Impl(roots[r]));
+}return expressions;
+}else{return new Exhibit.Expression._Impl(parseExpression());
+}};
+Exhibit.ExpressionScanner=function(text,startIndex){this._text=text+" ";
+this._maxIndex=text.length;
+this._index=startIndex;
+this.next();
+};
+Exhibit.ExpressionScanner.DELIMITER=0;
+Exhibit.ExpressionScanner.NUMBER=1;
+Exhibit.ExpressionScanner.STRING=2;
+Exhibit.ExpressionScanner.IDENTIFIER=3;
+Exhibit.ExpressionScanner.OPERATOR=4;
+Exhibit.ExpressionScanner.PATH_OPERATOR=5;
+Exhibit.ExpressionScanner.prototype.token=function(){return this._token;
+};
+Exhibit.ExpressionScanner.prototype.index=function(){return this._index;
+};
+Exhibit.ExpressionScanner.prototype.next=function(){this._token=null;
+while(this._index<this._maxIndex&&" \t\r\n".indexOf(this._text.charAt(this._index))>=0){this._index++;
+}if(this._index<this._maxIndex){var c1=this._text.charAt(this._index);
+var c2=this._text.charAt(this._index+1);
+if(".!".indexOf(c1)>=0){if(c2=="@"){this._token={type:Exhibit.ExpressionScanner.PATH_OPERATOR,value:c1+c2,start:this._index,end:this._index+2};
+this._index+=2;
+}else{this._token={type:Exhibit.ExpressionScanner.PATH_OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}}else{if("<>".indexOf(c1)>=0){if((c2=="=")||("<>".indexOf(c2)>=0&&c1!=c2)){this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1+c2,start:this._index,end:this._index+2};
+this._index+=2;
+}else{this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}}else{if("+-*/=".indexOf(c1)>=0){this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("(),".indexOf(c1)>=0){this._token={type:Exhibit.ExpressionScanner.DELIMITER,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("\"'".indexOf(c1)>=0){var i=this._index+1;
+while(i<this._maxIndex){if(this._text.charAt(i)==c1&&this._text.charAt(i-1)!="\\"){break;
+}i++;
+}if(i<this._maxIndex){this._token={type:Exhibit.ExpressionScanner.STRING,value:this._text.substring(this._index+1,i).replace(/\\'/g,"'").replace(/\\"/g,'"'),start:this._index,end:i+1};
+this._index=i+1;
+}else{throw new Error("Unterminated string starting at "+this._index);
+}}else{if(this._isDigit(c1)){var i=this._index;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}if(i<this._maxIndex&&this._text.charAt(i)=="."){i++;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}}this._token={type:Exhibit.ExpressionScanner.NUMBER,value:parseFloat(this._text.substring(this._index,i)),start:this._index,end:i};
+this._index=i;
+}else{var i=this._index;
+while(i<this._maxIndex){var c=this._text.charAt(i);
+if("(),.!@ \t".indexOf(c)<0){i++;
+}else{break;
+}}this._token={type:Exhibit.ExpressionScanner.IDENTIFIER,value:this._text.substring(this._index,i),start:this._index,end:i};
+this._index=i;
+}}}}}}}};
+Exhibit.ExpressionScanner.prototype._isDigit=function(c){return"0123456789".indexOf(c)>=0;
+};
+
+
+/* expression.js */
+Exhibit.Expression=new Object();
+Exhibit.Expression._Impl=function(rootNode){this._rootNode=rootNode;
+};
+Exhibit.Expression._Impl.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var collection=this._rootNode.evaluate(roots,rootValueTypes,defaultRootName,database);
+return{values:collection.getSet(),valueType:collection.valueType,size:collection.size};
+};
+Exhibit.Expression._Impl.prototype.evaluateOnItem=function(itemID,database){return this.evaluate({"value":itemID},{"value":"item"},"value",database);
+};
+Exhibit.Expression._Impl.prototype.evaluateSingle=function(roots,rootValueTypes,defaultRootName,database){var collection=this._rootNode.evaluate(roots,rootValueTypes,defaultRootName,database);
+var result={value:null,valueType:collection.valueType};
+collection.forEachValue(function(v){result.value=v;
+return true;
+});
+return result;
+};
+Exhibit.Expression._Impl.prototype.evaluateSingleOnItem=function(itemID,database){return this.evaluateSingle({"value":itemID},{"value":"item"},"value",database);
+};
+Exhibit.Expression._Impl.prototype.testExists=function(roots,rootValueTypes,defaultRootName,database){return this.isPath()?this._rootNode.testExists(roots,rootValueTypes,defaultRootName,database):this.evaluate(roots,rootValueTypes,defaultRootName,database).values.size()>0;
+};
+Exhibit.Expression._Impl.prototype.isPath=function(){return this._rootNode instanceof Exhibit.Expression.Path;
+};
+Exhibit.Expression._Impl.prototype.getPath=function(){return this.isPath()?this._rootNode:null;
+};
+Exhibit.Expression._Collection=function(values,valueType){this._values=values;
+this.valueType=valueType;
+if(values instanceof Array){this.forEachValue=Exhibit.Expression._Collection._forEachValueInArray;
+this.getSet=Exhibit.Expression._Collection._getSetFromArray;
+this.contains=Exhibit.Expression._Collection._containsInArray;
+this.size=values.length;
+}else{this.forEachValue=Exhibit.Expression._Collection._forEachValueInSet;
+this.getSet=Exhibit.Expression._Collection._getSetFromSet;
+this.contains=Exhibit.Expression._Collection._containsInSet;
+this.size=values.size();
+}};
+Exhibit.Expression._Collection._forEachValueInSet=function(f){this._values.visit(f);
+};
+Exhibit.Expression._Collection._forEachValueInArray=function(f){var a=this._values;
+for(var i=0;
+i<a.length;
+i++){if(f(a[i])){break;
+}}};
+Exhibit.Expression._Collection._getSetFromSet=function(){return this._values;
+};
+Exhibit.Expression._Collection._getSetFromArray=function(){return new Exhibit.Set(this._values);
+};
+Exhibit.Expression._Collection._containsInSet=function(v){this._values.contains(v);
+};
+Exhibit.Expression._Collection._containsInArray=function(v){var a=this._values;
+for(var i=0;
+i<a.length;
+i++){if(a[i]==v){return true;
+}}return false;
+};
+Exhibit.Expression.Path=function(){this._rootName=null;
+this._segments=[];
+};
+Exhibit.Expression.Path.create=function(property,forward){var path=new Exhibit.Expression.Path();
+path._segments.push({property:property,forward:forward,isArray:false});
+return path;
+};
+Exhibit.Expression.Path.prototype.setRootName=function(rootName){this._rootName=rootName;
+};
+Exhibit.Expression.Path.prototype.appendSegment=function(property,hopOperator){this._segments.push({property:property,forward:hopOperator.charAt(0)==".",isArray:hopOperator.length>1});
+};
+Exhibit.Expression.Path.prototype.getSegment=function(index){if(index<this._segments.length){var segment=this._segments[index];
+return{property:segment.property,forward:segment.forward,isArray:segment.isArray};
+}else{return null;
+}};
+Exhibit.Expression.Path.prototype.getLastSegment=function(){return this.getSegment(this._segments.length-1);
+};
+Exhibit.Expression.Path.prototype.getSegmentCount=function(){return this._segments.length;
+};
+Exhibit.Expression.Path.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var rootName=this._rootName!=null?this._rootName:defaultRootName;
+var valueType=rootName in rootValueTypes?rootValueTypes[rootName]:"text";
+var collection=null;
+if(rootName in roots){var root=roots[rootName];
+if(root instanceof Exhibit.Set||root instanceof Array){collection=new Exhibit.Expression._Collection(root,valueType);
+}else{collection=new Exhibit.Expression._Collection([root],valueType);
+}return this._walkForward(collection,database);
+}else{throw new Error("No such variable called "+rootName);
+}};
+Exhibit.Expression.Path.prototype.evaluateBackward=function(value,valueType,filter,database){var collection=new Exhibit.Expression._Collection([value],valueType);
+return this._walkBackward(collection,filter,database);
+};
+Exhibit.Expression.Path.prototype.walkForward=function(values,valueType,database){return this._walkForward(new Exhibit.Expression._Collection(values,valueType),database);
+};
+Exhibit.Expression.Path.prototype.walkBackward=function(values,valueType,filter,database){return this._walkBackward(new Exhibit.Expression._Collection(values,valueType),filter,database);
+};
+Exhibit.Expression.Path.prototype._walkForward=function(collection,database){for(var i=0;
+i<this._segments.length;
+i++){var segment=this._segments[i];
+if(segment.isArray){var a=[];
+var valueType;
+if(segment.forward){collection.forEachValue(function(v){database.getObjects(v,segment.property).visit(function(v2){a.push(v2);
+});
+});
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}else{collection.forEachValue(function(v){database.getSubjects(v,segment.property).visit(function(v2){a.push(v2);
+});
+});
+valueType="item";
+}collection=new Exhibit.Expression._Collection(a,valueType);
+}else{if(segment.forward){var values=database.getObjectsUnion(collection.getSet(),segment.property);
+var property=database.getProperty(segment.property);
+var valueType=property!=null?property.getValueType():"text";
+collection=new Exhibit.Expression._Collection(values,valueType);
+}else{var values=database.getSubjectsUnion(collection.getSet(),segment.property);
+collection=new Exhibit.Expression._Collection(values,"item");
+}}}return collection;
+};
+Exhibit.Expression.Path.prototype._walkBackward=function(collection,filter,database){for(var i=this._segments.length-1;
+i>=0;
+i--){var segment=this._segments[i];
+if(segment.isArray){var a=[];
+var valueType;
+if(segment.forward){collection.forEachValue(function(v){database.getSubjects(v,segment.property).visit(function(v2){if(i>0||filter==null||filter.contains(v2)){a.push(v2);
+}});
+});
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}else{collection.forEachValue(function(v){database.getObjects(v,segment.property).visit(function(v2){if(i>0||filter==null||filter.contains(v2)){a.push(v2);
+}});
+});
+valueType="item";
+}collection=new Exhibit.Expression._Collection(a,valueType);
+}else{if(segment.forward){var values=database.getSubjectsUnion(collection.getSet(),segment.property,null,i==0?filter:null);
+collection=new Exhibit.Expression._Collection(values,"item");
+}else{var values=database.getObjectsUnion(collection.getSet(),segment.property,null,i==0?filter:null);
+var property=database.getProperty(segment.property);
+var valueType=property!=null?property.getValueType():"text";
+collection=new Exhibit.Expression._Collection(values,valueType);
+}}}return collection;
+};
+Exhibit.Expression.Path.prototype.rangeBackward=function(from,to,inclusive,filter,database){var set=new Exhibit.Set();
+var valueType="item";
+if(this._segments.length>0){var segment=this._segments[this._segments.length-1];
+if(segment.forward){database.getSubjectsInRange(segment.property,from,to,inclusive,set,this._segments.length==1?filter:null);
+}else{throw new Error("Last path of segment must be forward");
+}for(var i=this._segments.length-2;
+i>=0;
+i--){segment=this._segments[i];
+if(segment.forward){set=database.getSubjectsUnion(set,segment.property,null,i==0?filter:null);
+valueType="item";
+}else{set=database.getObjectsUnion(set,segment.property,null,i==0?filter:null);
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}}}return{valueType:valueType,values:set,count:set.size()};
+};
+Exhibit.Expression.Path.prototype.testExists=function(roots,rootValueTypes,defaultRootName,database){return this.evaluate(roots,rootValueTypes,defaultRootName,database).size>0;
+};
+Exhibit.Expression._Constant=function(value,valueType){this._value=value;
+this._valueType=valueType;
+};
+Exhibit.Expression._Constant.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){return new Exhibit.Expression._Collection([this._value],this._valueType);
+};
+Exhibit.Expression._Operator=function(operator,args){this._operator=operator;
+this._args=args;
+};
+Exhibit.Expression._Operator.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var values=[];
+var args=[];
+for(var i=0;
+i<this._args.length;
+i++){args.push(this._args[i].evaluate(roots,rootValueTypes,defaultRootName,database));
+}var operator=Exhibit.Expression._operators[this._operator];
+var f=operator.f;
+if(operator.argumentType=="number"){args[0].forEachValue(function(v1){if(!(typeof v1=="number")){v1=parseFloat(v1);
+}args[1].forEachValue(function(v2){if(!(typeof v2=="number")){v2=parseFloat(v2);
+}values.push(f(v1,v2));
+});
+});
+}else{args[0].forEachValue(function(v1){args[1].forEachValue(function(v2){values.push(f(v1,v2));
+});
+});
+}return new Exhibit.Expression._Collection(values,operator.valueType);
+};
+Exhibit.Expression._operators={"+":{argumentType:"number",valueType:"number",f:function(a,b){return a+b;
+}},"-":{argumentType:"number",valueType:"number",f:function(a,b){return a-b;
+}},"*":{argumentType:"number",valueType:"number",f:function(a,b){return a*b;
+}},"/":{argumentType:"number",valueType:"number",f:function(a,b){return a/b;
+}},"=":{valueType:"boolean",f:function(a,b){return a==b;
+}},"<>":{valueType:"boolean",f:function(a,b){return a!=b;
+}},"><":{valueType:"boolean",f:function(a,b){return a!=b;
+}},"<":{argumentType:"number",valueType:"boolean",f:function(a,b){return a<b;
+}},">":{argumentType:"number",valueType:"boolean",f:function(a,b){return a>b;
+}},"<=":{argumentType:"number",valueType:"boolean",f:function(a,b){return a<=b;
+}},">=":{argumentType:"number",valueType:"boolean",f:function(a,b){return a>=b;
+}}};
+Exhibit.Expression._FunctionCall=function(name,args){this._name=name;
+this._args=args;
+};
+Exhibit.Expression._FunctionCall.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var args=[];
+for(var i=0;
+i<this._args.length;
+i++){args.push(this._args[i].evaluate(roots,rootValueTypes,defaultRootName,database));
+}if(this._name in Exhibit.Functions){return Exhibit.Functions[this._name].f(args);
+}else{throw new Error("No such function named "+this._name);
+}};
+Exhibit.Expression._ControlCall=function(name,args){this._name=name;
+this._args=args;
+};
+Exhibit.Expression._ControlCall.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){return Exhibit.Controls[this._name].f(this._args,roots,rootValueTypes,defaultRootName,database);
+};
+
+
+/* functions.js */
+Exhibit.Functions={};
+Exhibit.FunctionUtilities={};
+Exhibit.FunctionUtilities.registerSimpleMappingFunction=function(name,f,valueType){Exhibit.Functions[name]={f:function(args){var set=new Exhibit.Set();
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){var v2=f(v);
+if(v2!=undefined){set.add(v2);
+}});
+}return new Exhibit.Expression._Collection(set,valueType);
+}};
+};
+Exhibit.Functions["union"]={f:function(args){var set=new Exhibit.Set();
+var valueType=null;
+if(args.length>0){var valueType=args[0].valueType;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+if(arg.size>0){if(valueType==null){valueType=arg.valueType;
+}set.addSet(arg.getSet());
+}}}return new Exhibit.Expression._Collection(set,valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["contains"]={f:function(args){var result=args[0].size>0;
+var set=args[0].getSet();
+args[1].forEachValue(function(v){if(!set.contains(v)){result=false;
+return true;
+}});
+return new Exhibit.Expression._Collection([result],"boolean");
+}};
+Exhibit.Functions["exists"]={f:function(args){return new Exhibit.Expression._Collection([args[0].size>0],"boolean");
+}};
+Exhibit.Functions["count"]={f:function(args){return new Exhibit.Expression._Collection([args[0].size],"number");
+}};
+Exhibit.Functions["not"]={f:function(args){return new Exhibit.Expression._Collection([!args[0].contains(true)],"boolean");
+}};
+Exhibit.Functions["and"]={f:function(args){var r=true;
+for(var i=0;
+r&&i<args.length;
+i++){r=r&&args[i].contains(true);
+}return new Exhibit.Expression._Collection([r],"boolean");
+}};
+Exhibit.Functions["or"]={f:function(args){var r=false;
+for(var i=0;
+!r&&i<args.length;
+i++){r=r||args[i].contains(true);
+}return new Exhibit.Expression._Collection([r],"boolean");
+}};
+Exhibit.Functions["add"]={f:function(args){var total=0;
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){if(typeof v=="number"){total+=v;
+}else{var n=parseFloat(v);
+if(!isNaN(n)){total+=n;
+}}}});
+}return new Exhibit.Expression._Collection([total],"number");
+}};
+Exhibit.Functions["concat"]={f:function(args){var result=[];
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){result.push(v);
+}});
+}return new Exhibit.Expression._Collection([result.join("")],"text");
+}};
+Exhibit.Functions["multiply"]={f:function(args){var product=1;
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){if(typeof v=="number"){product*=v;
+}else{var n=parseFloat(v);
+if(!isNaN(n)){product*=n;
+}}}});
+}return new Exhibit.Expression._Collection([product],"number");
+}};
+Exhibit.Functions["date-range"]={_parseDate:function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(v instanceof Date){return v.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+}catch(e){return Number.NEGATIVE_INFINITY;
+}}}},_factors:{second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,week:7*24*60*60*1000,month:30*24*60*60*1000,quarter:3*30*24*60*60*1000,year:365*24*60*60*1000,decade:10*365*24*60*60*1000,century:100*365*24*60*60*1000},_computeRange:function(from,to,interval){var range=to-from;
+if(isFinite(range)){if(interval in this._factors){range=Math.round(range/this._factors[interval]);
+}return range;
+}return null;
+},f:function(args){var self=this;
+var from=Number.POSITIVE_INFINITY;
+args[0].forEachValue(function(v){from=Math.min(from,self._parseDate(v));
+});
+var to=Number.NEGATIVE_INFINITY;
+args[1].forEachValue(function(v){to=Math.max(to,self._parseDate(v));
+});
+var interval="day";
+args[2].forEachValue(function(v){interval=v;
+});
+var range=this._computeRange(from,to,interval);
+return new Exhibit.Expression._Collection(range!=null?[range]:[],"number");
+}};
+Exhibit.Functions["distance"]={_units:{km:1000,mile:1609.344},_computeDistance:function(from,to,unit,roundTo){var range=from.distanceFrom(to);
+if(!roundTo){roundTo=1;
+}if(isFinite(range)){if(this._units.hasOwnProperty(unit)){range=range/this._units[unit];
+}return Exhibit.Util.round(range,roundTo);
+}return null;
+},f:function(args){var self=this;
+var data={};
+var name=["origo","lat","lng","unit","round"];
+for(var i=0,n;
+n=name[i];
+i++){args[i].forEachValue(function(v){data[n]=v;
+});
+}var latlng=data.origo.split(",");
+var from=new GLatLng(latlng[0],latlng[1]);
+var to=new GLatLng(data.lat,data.lng);
+var range=this._computeDistance(from,to,data.unit,data.round);
+return new Exhibit.Expression._Collection(range!=null?[range]:[],"number");
+}};
+Exhibit.Functions["min"]={f:function(args){var returnMe=function(val){return val;
+};
+var min=Number.POSITIVE_INFINITY;
+var valueType=null;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+var currentValueType=arg.valueType?arg.valueType:"text";
+var parser=Exhibit.SettingsUtilities._typeToParser(currentValueType);
+arg.forEachValue(function(v){parsedV=parser(v,returnMe);
+if(parsedV<min||min==Number.POSITIVE_INFINITY){min=parsedV;
+valueType=(valueType==null)?currentValueType:(valueType==currentValueType?valueType:"text");
+}});
+}return new Exhibit.Expression._Collection([min],valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["max"]={f:function(args){var returnMe=function(val){return val;
+};
+var max=Number.NEGATIVE_INFINITY;
+var valueType=null;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+var currentValueType=arg.valueType?arg.valueType:"text";
+var parser=Exhibit.SettingsUtilities._typeToParser(currentValueType);
+arg.forEachValue(function(v){parsedV=parser(v,returnMe);
+if(parsedV>max||max==Number.NEGATIVE_INFINITY){max=parsedV;
+valueType=(valueType==null)?currentValueType:(valueType==currentValueType?valueType:"text");
+}});
+}return new Exhibit.Expression._Collection([max],valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["remove"]={f:function(args){var set=args[0].getSet();
+var valueType=args[0].valueType;
+for(var i=1;
+i<args.length;
+i++){var arg=args[i];
+if(arg.size>0){set.removeSet(arg.getSet());
+}}return new Exhibit.Expression._Collection(set,valueType);
+}};
+Exhibit.Functions["now"]={f:function(args){return new Exhibit.Expression._Collection([new Date()],"date");
+}};
+
+
+/* authenticated-importer.js */
+Exhibit.AuthenticatedImporter={_callbacks:{}};
+Exhibit.importers["application/authenticated"]=Exhibit.AuthenticatedImporter;
+Exhibit.AuthenticatedImporter.constructURL=function(){return"https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fspreadsheets.google.com%2Ffeeds%2F&session=1&secure=0&next="+window.location;
+};
+Exhibit.AuthenticatedImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{o=eval("("+xmlhttp.responseText+")");
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* babel-based-importer.js */
+Exhibit.BabelBasedImporter={mimetypeToReader:{"application/rdf+xml":"rdf-xml","application/n3":"n3","application/msexcel":"xls","application/x-msexcel":"xls","application/x-ms-excel":"xls","application/vnd.ms-excel":"xls","application/x-excel":"xls","application/xls":"xls","application/x-xls":"xls","application/x-bibtex":"bibtex"},babelTranslatorURL:"http://service.simile-widgets.org/babel/translator",_initialize:function(){var links=[];
+var heads=document.documentElement.getElementsByTagName("head");
+for(var h=0;
+h<heads.length;
+h++){var linkElmts=heads[h].getElementsByTagName("link");
+for(var l=0;
+l<linkElmts.length;
+l++){var link=linkElmts[l];
+if(link.rel.match(/\bexhibit\/babel-translator\b/)){Exhibit.BabelBasedImporter.babelTranslatorURL=link.href;
+}}}Exhibit.BabelBasedImporter._initialize=function(){};
+}};
+Exhibit.importers["application/rdf+xml"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/n3"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/msexcel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-msexcel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/vnd.ms-excel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-excel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/xls"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-xls"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-bibtex"]=Exhibit.BabelBasedImporter;
+Exhibit.BabelBasedImporter.load=function(link,database,cont){Exhibit.BabelBasedImporter._initialize();
+var url=(typeof link=="string")?Exhibit.Persistence.resolveURL(link):Exhibit.Persistence.resolveURL(link.href);
+var reader="rdf-xml";
+var writer="exhibit-jsonp";
+if(typeof link!="string"){var mimetype=link.type;
+if(mimetype in Exhibit.BabelBasedImporter.mimetypeToReader){reader=Exhibit.BabelBasedImporter.mimetypeToReader[mimetype];
+}}if(reader=="bibtex"){writer="bibtex-exhibit-jsonp";
+}var babelURL=Exhibit.BabelBasedImporter.babelTranslatorURL+"?"+["reader="+reader,"writer="+writer,"url="+encodeURIComponent(url)].join("&");
+return Exhibit.JSONPImporter.load(babelURL,database,cont);
+};
+
+
+/* exhibit-json-importer.js */
+Exhibit.ExhibitJSONImporter={};
+Exhibit.importers["application/json"]=Exhibit.ExhibitJSONImporter;
+Exhibit.ExhibitJSONImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{o=eval("("+xmlhttp.responseText+")");
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* exhibit-xml-importer.js */
+Exhibit.ExhibitXMLImporter={};
+Exhibit.importers["application/xml"]=Exhibit.ExhibitXMLImporter;
+Exhibit.ExhibitXMLImporter.getXMLDocument=function(docURL){var xmlDoc=null;
+$.ajax({url:docURL,type:"GET",dataType:"xml",async:false,success:function(data){xmlDoc=data;
+}});
+if(xmlDoc){return xmlDoc;
+}else{alert("ERROR FINDING XML DOC");
+return ;
+}};
+Exhibit.ExhibitXMLImporter.appendUserPropertyToArray=function(node,configuration,objectToAppend){var referenceIndex=configuration.propertyTags.indexOf(node.nodeName);
+var array=objectToAppend[configuration.propertyNames[referenceIndex]];
+if(typeof objectToAppend[configuration.propertyNames[referenceIndex]]=="string"){array=[array];
+array.push(node.textContent);
+}else{array.push(node.textContent);
+}return array;
+};
+Exhibit.ExhibitXMLImporter.appendPropertyToArray=function(node,configuration,objectToAppend){var array=objectToAppend[node.nodeName];
+if(typeof array=="string"){array=[array];
+array.push(node.textContent);
+}else{array.push(node.textContent);
+}return array;
+};
+Exhibit.ExhibitXMLImporter.getItems=function(xmlDoc,object,index,configuration){var self=this;
+$(configuration.itemTag[index],xmlDoc).each(function(){var propertyList=[];
+var queue=[];
+$(this).children().each(function(){queue.push(this);
+});
+objectToAppend={};
+while(queue.length){var node=queue.pop();
+var nodeType=self.determineType(node,configuration);
+if(nodeType=="property"){if(propertyList.indexOf(node.nodeName)>=0){if(configuration.propertyTags.indexOf(node.nodeName)>=0){objectToAppend[configuration.propertyNames[index]]=self.appendUserPropertyToArray(node,configuration,objectToAppend);
+}else{objectToAppend[node.nodeName]=self.appendPropertyToArray(node,configuration,objectToAppend);
+}}else{if(configuration.propertyTags.indexOf(node.nodeName)>=0){var referenceIndex=configuration.propertyTags.indexOf(node.nodeName);
+objectToAppend[configuration.propertyNames[referenceIndex]]=node.textContent;
+}else{objectToAppend[node.nodeName]=node.textContent;
+}}propertyList.push(node.nodeName);
+}else{if(nodeType=="Item"){var referenceIndex=configuration.itemTag.indexOf(node.nodeName);
+var tempObject=self.configureItem(node,{},configuration,referenceIndex);
+objectToAppend[tempObject.type]=tempObject.label;
+}else{if(nodeType=="fakeItem"){$(node).children().each(function(){queue.push(this);
+});
+}else{alert("error: nodetype not understood");
+}}}}objectToAppend=self.configureItem(this,objectToAppend,configuration,index);
+object.items.push(objectToAppend);
+});
+return object;
+};
+Exhibit.ExhibitXMLImporter.getParentItem=function(itemNode,configuration){if(itemNode.parentNode==null){return null;
+}else{if(configuration.itemTag.indexOf(itemNode.parentNode.nodeName)>=0){var referenceIndex=configuration.itemTag.indexOf(itemNode.parentNode.nodeName);
+return this.configureItem(itemNode.parentNode,{},configuration,referenceIndex);
+}else{this.getParentItem(itemNode.parentNode,configuration);
+}}};
+Exhibit.ExhibitXMLImporter.configureItem=function(myItem,object,configuration,index){if(!(object.label)&&configuration.propertyLabel[index]!=null){object["label"]=$(configuration.propertyLabel[index],myItem)[0].textContent;
+}else{object["label"]=$(myItem).children()[0].textContent;
+}if(!(object.type)&&configuration.itemType[index]!=null){object["type"]=configuration.itemType[index];
+}else{object["type"]=myItem.nodeName;
+}var parentItem=this.getParentItem(myItem,configuration);
+if(parentItem){if(configuration.parentRelation[index]){object[configuration.parentRelation[index]]=parentItem.label;
+}else{object["isChildOf"]=parentItem.label;
+}}return object;
+};
+Exhibit.ExhibitXMLImporter.configure=function(){var configuration={"itemTag":[],"propertyLabel":[],"itemType":[],"parentRelation":[],"propertyTags":[],"propertyNames":[]};
+$("link").each(function(){if(this.hasAttribute("ex:itemTag")){configuration.itemTag=Exhibit.getAttribute(this,"ex:itemTag",",");
+}if(this.hasAttribute("ex:setPropertyAsLabel")){configuration.propertyLabel=Exhibit.getAttribute(this,"ex:setPropertyAsLabel",",");
+}if(this.hasAttribute("ex:itemType")){configuration.itemType=Exhibit.getAttribute(this,"ex:itemType",",");
+}if(this.hasAttribute("ex:parentRelation")){configuration.parentRelation=Exhibit.getAttribute(this,"ex:parentRelation",",");
+}if(this.hasAttribute("ex:propertyNames")){configuration.propertyNames=Exhibit.getAttribute(this,"ex:propertyNames",",");
+}if(this.hasAttribute("ex:propertyTags")){configuration.propertyTags=Exhibit.getAttribute(this,"ex:propertyTags",",");
+}});
+return configuration;
+};
+Exhibit.ExhibitXMLImporter.determineType=function(node,configuration){if(configuration.itemTag.indexOf(node.nodeName)>=0){return"Item";
+}else{if($(node).children().length==0){return"property";
+}else{return"fakeItem";
+}}};
+Exhibit.ExhibitXMLImporter.load=function(link,database,cont){var self=this;
+var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{xmlDoc=Exhibit.ExhibitXMLImporter.getXMLDocument(url);
+var configuration=self.configure();
+o={"items":[]};
+for(index in configuration.itemTag){o=Exhibit.ExhibitXMLImporter.getItems(xmlDoc,o,index,configuration);
+}}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* html-table-importer.js */
+Exhibit.HtmlTableImporter={};
+Exhibit.importers["text/html"]=Exhibit.HtmlTableImporter;
+Exhibit.HtmlTableImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+if(url.substr(0,1)=="#"){try{var id=/#(.*)/.exec(f)[1];
+var table=document.getElementById(id);
+table.style.display="none";
+Exhibit.HtmlTableImporter.loadTable(table,database);
+}catch(e){SimileAjax.Debug.exception(e);
+}finally{if(cont){cont();
+}}}else{if(typeof link!="string"){var xpath=link.getAttribute("ex:xpath");
+var columns=(link.getAttribute("ex:columns")).split(",");
+var babelURL="http://simile.mit.edu/babel/html-extractor?"+["xpath="+xpath,"url="+encodeURIComponent(url)].join("&");
+var fConvert=function(string){var div=document.createElement("div");
+div.innerHTML=string;
+var table=div.firstChild;
+var th,ths=table.getElementsByTagName("th");
+for(col=0;
+th=ths[col];
+col++){var label=columns[col];
+th.setAttribute("ex:name",label);
+}Exhibit.HtmlTableImporter.loadTable(table,database);
+return{};
+};
+return Exhibit.JSONPImporter.load(babelURL,database,cont,fConvert);
+}else{if(cont){cont();
+}}}};
+Exhibit.HtmlTableImporter.loadTable=function(table,database){var textOf=function(n){return n.textContent||n.innerText||"";
+};
+var readAttributes=function(node,attributes){var result={},found=false,attr,value,i;
+for(i=0;
+attr=attributes[i];
+i++){value=Exhibit.getAttribute(node,attr);
+if(value){result[attr]=value;
+found=true;
+}}return found&&result;
+};
+var typelist=["uri","label","pluralLabel"];
+var proplist=["uri","valueType","label","reverseLabel","pluralLabel","reversePluralLabel","groupingLabel","reverseGroupingLabel"];
+var columnProps=["valueParser","arity"];
+var parsed={};
+var type=Exhibit.getAttribute(table,"type");
+var types=type&&readAttributes(table,typelist);
+if(types){parsed.types={};
+parsed.types[type]=types;
+}var fields=[],props={},columnData=[],row,col;
+var tr,trs=table.getElementsByTagName("tr");
+var th,ths=trs[0].getElementsByTagName("th");
+for(col=0;
+th=ths[col];
+col++){var field=textOf(th).trim();
+var hastextwithlink=false;
+var attr=readAttributes(th,proplist);
+var name=Exhibit.getAttribute(th,"name");
+if(name){attr=attr||{};
+attr.label=attr.label||field;
+field=name;
+}if(attr){props[field]=attr;
+if(props[field].valueType=="textwithlink"){props[field].valueType="text";
+props[(field+"-link")]={valueType:"url"};
+hastextwithlink=true;
+}parsed.properties=props;
+}fields.push(field);
+attr=readAttributes(th,columnProps)||{};
+if(attr.valueParser&&attr.valueParser in window){attr.valueParser=window[attr.valueParser];
+}else{if(attr.arity=="single"){attr.valueParser=function(text,node,rowNo,colNo){return text.trim();
+};
+}else{attr.valueParser=function(text,node,rowNo,colNo){if(text.indexOf(";")==-1){return text.trim();
+}var data=text.split(";");
+for(var i=0;
+i<data.length;
+i++){data[i]=data[i].trim();
+}return data;
+};
+if(hastextwithlink){var fallback=attr.valueParser;
+attr.valueParser=function(text,node,rowNo,colNo){var links=node.getElementsByTagName("a");
+if(!links.length){return fallback(text,node,rowNo,colNo);
+}var data={};
+data[fields[colNo]]=text.trim();
+data[(fields[colNo]+"-link")]=links[0].href;
+return data;
+};
+}}}columnData[col]=attr;
+}var img,imgs=table.getElementsByTagName("img");
+while(img=imgs[0]){img.parentNode.replaceChild(document.createTextNode(img.src),img);
+}var items=[],td,raw;
+for(row=1;
+tr=trs[row];
+row++){var item={};
+var tds=tr.getElementsByTagName("td");
+for(col=0;
+td=tds[col];
+col++){var raw=textOf(td);
+data=columnData[col].valueParser(raw,td,row,col);
+if(data==null||raw===""){continue;
+}if(typeof data=="object"&&!(data instanceof Array)){for(var property in data){item[property]=data[property];
+}}else{item[fields[col]]=data;
+}}if(type){item.type=type;
+}items.push(item);
+parsed.items=items;
+}database.loadData(parsed,Exhibit.Persistence.resolveURL(location.href));
+};
+
+
+/* json-importer.js */
+Exhibit.jsonImporter={};
+Exhibit.importers["application/general-json"]=Exhibit.jsonImporter;
+Exhibit.jsonImporter.getjsonDocument=function(docURL){var jsonDoc=null;
+$.ajax({url:docURL,type:"GET",dataType:"json",async:false,success:function(data){jsonDoc=data;
+}});
+if(jsonDoc){return jsonDoc;
+}else{alert("ERROR FINDING JSON DOC");
+return null;
+}};
+Exhibit.jsonImporter.findFirstItems=function(json,configuration){if(json instanceof Array){return json.length>0?Exhibit.jsonImporter.findFirstItems(json[0],configuration):null;
+}else{var visited=[];
+var listOfItems=[];
+for(child in json){visited.push(json[child]);
+if(configuration.itemTag.indexOf(child)>=0){for(var i=0;
+i<json[child].length;
+i++){var subChild=json[child][i];
+subChild.index=configuration.itemTag.indexOf(child);
+listOfItems.push(subChild);
+}}}if(listOfItems.length){return listOfItems;
+}else{return Exhibit.jsonImporter.findFirstItems(visited,configuration);
+}}};
+Exhibit.jsonImporter.getItems=function(json,exhibitJSON,configuration){var itemQueue;
+var root=json;
+if(root instanceof Array){itemQueue=root;
+}else{itemQueue=[root];
+}while(itemQueue.length>0){var myObject=itemQueue.shift();
+var index=myObject.index;
+var objectToAppend={};
+var propertyQueue=[];
+for(propertyKey in myObject){propertyQueue.push(propertyKey);
+}while(propertyQueue.length>0){var key=propertyQueue.shift();
+var keyID=key.split(".").pop();
+if(configuration.itemTag.indexOf(keyID)==-1){var propertyValue=eval("myObject."+key);
+if(keyID=="index"){}else{if(propertyValue instanceof Array){objectToAppend[keyID]=propertyValue;
+}else{if(propertyValue instanceof Object){for(newProperty in propertyValue){propertyQueue.push(key+"."+newProperty);
+}}else{if(keyID==configuration.propertyTags[index]){var referenceIndex=configuration.propertyTags.indexOf(keyID);
+var newKey=configuration.propertyNames[referenceIndex];
+objectToAppend[newKey]=propertyValue;
+}else{if(keyID==configuration.propertyLabel[index]){objectToAppend.label=propertyValue;
+}else{objectToAppend[keyID]=propertyValue;
+}}}}}if(configuration.itemType[index]){objectToAppend.type=configuration.itemType[index];
+}else{objectToAppend.type="Item";
+}}else{newObject=eval("myObject."+key);
+if(newObject instanceof Array){for(var i=0;
+i<newObject.length;
+i++){var object=newObject[i];
+object.index=configuration.itemTag.indexOf(keyID);
+if(configuration.parentRelation[object.index]){object[configuration.parentRelation[object.index]]=objectToAppend.label;
+}else{object["is a child of"]=objectToAppend.label;
+}itemQueue.push(object);
+}}else{newObject.index=configuration.itemTag.indexOf(keyID);
+if(configuration.parentRelation[newObject.index]){newObject[configuration.parentRelation[newObject.index]]=objectToAppend.label;
+}else{newObject["isChildOf"]=objectToAppend.label;
+}itemQueue.push(newObject);
+}}}exhibitJSON.items.push(objectToAppend);
+}return exhibitJSON;
+};
+Exhibit.jsonImporter.configure=function(){var configuration={"itemTag":[],"propertyLabel":[],"itemType":[],"parentRelation":[],"propertyTags":[],"propertyNames":[]};
+$("link").each(function(){if(this.hasAttribute("ex:itemTag")){configuration.itemTag=Exhibit.getAttribute(this,"ex:itemTag",",");
+}if(this.hasAttribute("ex:setPropertyAsLabel")){configuration.propertyLabel=Exhibit.getAttribute(this,"ex:setPropertyAsLabel",",");
+}if(this.hasAttribute("ex:itemType")){configuration.itemType=Exhibit.getAttribute(this,"ex:itemType",",");
+}if(this.hasAttribute("ex:parentRelation")){configuration.parentRelation=Exhibit.getAttribute(this,"ex:parentRelation",",");
+}if(this.hasAttribute("ex:propertyNames")){configuration.propertyNames=Exhibit.getAttribute(this,"ex:propertyNames",",");
+}if(this.hasAttribute("ex:propertyTags")){configuration.propertyTags=Exhibit.getAttribute(this,"ex:propertyTags",",");
+}});
+return configuration;
+};
+Exhibit.jsonImporter.load=function(link,database,cont){var self=this;
+var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{jsonDoc=Exhibit.jsonImporter.getjsonDocument(url);
+var configuration=self.configure();
+o={"items":[]};
+var root=self.findFirstItems(jsonDoc,configuration);
+o=Exhibit.jsonImporter.getItems(root,o,configuration);
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* jsonp-importer.js */
+Exhibit.JSONPImporter={_callbacks:{}};
+Exhibit.importers["application/jsonp"]=Exhibit.JSONPImporter;
+Exhibit.JSONPImporter.load=function(link,database,cont,fConvert,staticJSONPCallback,charset){var url=link;
+if(typeof link!="string"){url=Exhibit.Persistence.resolveURL(link.href);
+fConvert=Exhibit.getAttribute(link,"converter");
+staticJSONPCallback=Exhibit.getAttribute(link,"jsonp-callback");
+charset=Exhibit.getAttribute(link,"charset");
+}if(typeof fConvert=="string"){var name=fConvert;
+name=name.charAt(0).toLowerCase()+name.substring(1)+"Converter";
+if(name in Exhibit.JSONPImporter){fConvert=Exhibit.JSONPImporter[name];
+}else{try{fConvert=eval(fConvert);
+}catch(e){fConvert=null;
+}}}if(fConvert!=null&&"preprocessURL" in fConvert){url=fConvert.preprocessURL(url);
+}var next=Exhibit.JSONPImporter._callbacks.next||1;
+Exhibit.JSONPImporter._callbacks.next=next+1;
+var callbackName="cb"+next.toString(36);
+var callbackURL=url;
+if(callbackURL.indexOf("?")==-1){callbackURL+="?";
+}var lastChar=callbackURL.charAt(callbackURL.length-1);
+if(lastChar!="="){if(lastChar!="&"&&lastChar!="?"){callbackURL+="&";
+}callbackURL+="callback=";
+}var callbackFull="Exhibit.JSONPImporter._callbacks."+callbackName;
+callbackURL+=callbackFull;
+var cleanup=function(failedURL){try{Exhibit.UI.hideBusyIndicator();
+delete Exhibit.JSONPImporter._callbacks[callbackName+"_fail"];
+delete Exhibit.JSONPImporter._callbacks[callbackName];
+if(script&&script.parentNode){script.parentNode.removeChild(script);
+}}finally{if(failedURL){prompt("Failed to load javascript file:",failedURL);
+cont&&cont(undefined);
+}}};
+Exhibit.JSONPImporter._callbacks[callbackName+"_fail"]=cleanup;
+Exhibit.JSONPImporter._callbacks[callbackName]=function(json){try{cleanup(null);
+database.loadData(fConvert?fConvert(json,url,link):json,Exhibit.Persistence.getBaseURL(url));
+}finally{if(cont){cont(json);
+}}};
+if(staticJSONPCallback){callbackURL=url;
+eval(staticJSONPCallback+"="+callbackFull);
+}var fail=callbackFull+"_fail('"+callbackURL+"');";
+var script=SimileAjax.includeJavascriptFile(document,callbackURL,fail,charset);
+Exhibit.UI.showBusyIndicator();
+return Exhibit.JSONPImporter._callbacks[callbackName];
+};
+Exhibit.JSONPImporter.transformJSON=function(json,index,mapping,converters){var objects=json,items=[];
+if(index){index=index.split(".");
+while(index.length){objects=objects[index.shift()];
+}}for(var i=0,object;
+object=objects[i];
+i++){var item={};
+for(var name in mapping){var index=mapping[name];
+if(!mapping.hasOwnProperty(name)||!object.hasOwnProperty(index)){continue;
+}var property=object[index];
+if(converters&&converters.hasOwnProperty(name)){property=converters[name](property,object,i,objects,json);
+}if(typeof property!="undefined"){item[name]=property;
+}}items.push(item);
+}return items;
+};
+Exhibit.JSONPImporter.deliciousConverter=function(json,url){var items=Exhibit.JSONPImporter.transformJSON(json,null,{label:"u",note:"n",description:"d",tags:"t"});
+return{items:items,properties:{url:{valueType:"url"}}};
+};
+Exhibit.JSONPImporter.googleSpreadsheetsConverter=function(json,url,link){var separator=";";
+if((link)&&(typeof link!="string")){var s=Exhibit.getAttribute(link,"separator");
+if(s!=null&&s.length>0){separator=s;
+}}var items=[];
+var properties={};
+var types={};
+var valueTypes={"text":true,"number":true,"item":true,"url":true,"boolean":true,"date":true};
+var entries=json.feed.entry||[];
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+var id=entry.id.$t;
+var c=id.lastIndexOf("C");
+var r=id.lastIndexOf("R");
+entries[i]={row:parseInt(id.substring(r+1,c))-1,col:parseInt(id.substring(c+1))-1,val:entry.content.$t};
+}var cellIndex=0;
+var getNextRow=function(){if(cellIndex<entries.length){var firstEntry=entries[cellIndex++];
+var row=[firstEntry];
+while(cellIndex<entries.length){var nextEntry=entries[cellIndex];
+if(nextEntry.row==firstEntry.row){row.push(nextEntry);
+cellIndex++;
+}else{break;
+}}return row;
+}return null;
+};
+var propertyRow=getNextRow();
+if(propertyRow!=null){var propertiesByColumn=[];
+for(var i=0;
+i<propertyRow.length;
+i++){var cell=propertyRow[i];
+var fieldSpec=cell.val.trim().replace(/^\{/g,"").replace(/\}$/g,"").split(":");
+var fieldName=fieldSpec[0].trim();
+var fieldDetails=fieldSpec.length>1?fieldSpec[1].split(","):[];
+var property={single:false};
+for(var d=0;
+d<fieldDetails.length;
+d++){var detail=fieldDetails[d].trim();
+if(detail in valueTypes){property.valueType=detail;
+}else{if(detail=="single"){property.single=true;
+}}}propertiesByColumn[cell.col]=fieldName;
+properties[fieldName]=property;
+}var row=null;
+while((row=getNextRow())!=null){var item={};
+for(var i=0;
+i<row.length;
+i++){var cell=row[i];
+var fieldName=propertiesByColumn[cell.col];
+if(typeof fieldName=="string"){var googleDocsDateRegex=/^\d{1,2}\/\d{1,2}\/\d{4}$/;
+if(googleDocsDateRegex.exec(cell.val)){cell.val=Exhibit.Database.makeISO8601DateString(new Date(cell.val));
+}item[fieldName]=cell.val;
+var property=properties[fieldName];
+if(!property.single){var fieldValues=cell.val.split(separator);
+for(var v=0;
+v<fieldValues.length;
+v++){fieldValues[v]=fieldValues[v].trim();
+}item[fieldName]=fieldValues;
+}else{item[fieldName]=cell.val.trim();
+}}}items.push(item);
+}}return{types:types,properties:properties,items:items};
+};
+Exhibit.JSONPImporter.googleSpreadsheetsConverter.preprocessURL=function(url){return url.replace(/\/list\//g,"/cells/");
+};
+
+
+/* rdfa-importer.js */
+var RDFA=new Object();
+RDFA.url="http://www.w3.org/2006/07/SWD/RDFa/impl/js/20070301/rdfa.js";
+Exhibit.RDFaImporter={};
+Exhibit.importers["application/RDFa"]=Exhibit.RDFaImporter;
+Exhibit.RDFaImporter.load=function(link,database,cont){try{if((link.getAttribute("href")||"").length==0){Exhibit.RDFaImporter.loadRDFa(null,document,database);
+}else{iframe=document.createElement("iframe");
+iframe.style.display="none";
+iframe.setAttribute("onLoad","Exhibit.RDFaImporter.loadRDFa(this, this.contentDocument, database)");
+iframe.src=link.href;
+document.body.appendChild(iframe);
+}}catch(e){SimileAjax.Debug.exception(e);
+}finally{if(cont){cont();
+}}};
+Exhibit.RDFaImporter.loadRDFa=function(iframe,rdfa,database){var textOf=function(n){return n.textContent||n.innerText||"";
+};
+var readAttributes=function(node,attributes){var result={},found=false,attr,value,i;
+for(i=0;
+attr=attributes[i];
+i++){value=Exhibit.getAttribute(node,attr);
+if(value){result[attr]=value;
+found=true;
+}}return found&&result;
+};
+RDFA.CALLBACK_DONE_PARSING=function(){if(iframe!=null){document.body.removeChild(iframe);
+}this.cloneObject=function(what){for(var i in what){this[i]=what[i];
+}};
+var triples=this.triples;
+var parsed={"classes":{},"properties":{},"items":[]};
+for(var i in triples){var item={};
+item["id"],item["uri"],item["label"]=i;
+var tri=triples[i];
+for(var j in tri){for(var k=0;
+k<tri[j].length;
+k++){if(tri[j][k].predicate.ns){var p_label=tri[j][k].predicate.ns.prefix+":"+tri[j][k].predicate.suffix;
+if(j=="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"){try{var type_uri=tri[j][k]["object"];
+var matches=type_uri.match(/(.+?)(#|\/)([a-zA-Z_]+)?$/);
+var type_label=matches[3]+"("+matches[1]+")";
+parsed["classes"][type_label]={"label":type_label,"uri":type_uri};
+item["type"]=type_label;
+}catch(e){}}else{parsed["properties"][p_label]={"uri":j,"label":tri[j][k]["predicate"]["suffix"]};
+try{if(!item[p_label]){item[p_label]=[];
+}item[p_label].push(tri[j][k]["object"]);
+}catch(e){SimileAjax.Debug.log("problem adding property value: "+e);
+}if(j=="http://purl.org/dc/elements/1.1/title"||j=="http://www.w3.org/2000/01/rdf-schema#"||j=="http://xmlns.com/foaf/0.1/name"){item.label=item[p_label];
+}}}else{item[j]=tri[j][k]["object"];
+}}}parsed["items"].push(new this.cloneObject(item));
+}database.loadData(parsed,Exhibit.Persistence.getBaseURL(document.location.href));
+};
+RDFA.CALLBACK_DONE_LOADING=function(){RDFA.parse(rdfa);
+};
+SimileAjax.includeJavascriptFile(document,RDFA.url);
+};
+
+
+/* tsv-csv-importer.js */
+Exhibit.TsvCsvImporter={};
+Exhibit.importers["text/comma-separated-values"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/csv"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tab-separated-values"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tsv"]=Exhibit.TsvCsvImporter;
+Exhibit.TsvCsvImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var type=link.type.substring(link.type.indexOf("/")+1);
+var hasColumnTitles=Exhibit.getAttribute(link,"hasColumnTitles")!=null?Exhibit.getAttribute(link,"hasColumnTitles"):true;
+var expressionString=Exhibit.getAttribute(link,"properties");
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{var text=xmlhttp.responseText;
+o=eval(Exhibit.TsvCsvImporter.parseTsvCsv(text,type,expressionString,hasColumnTitles));
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading tsv/csv data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Exhibit.TsvCsvImporter.parseTsvCsv=function(text,format,expressionString,hasColumnTitles){var separator=Exhibit.TsvCsvImporter.formatType(format);
+var lines=text.split("\n");
+var rest;
+var hasPropertyListAttribute=expressionString!=null;
+var exString;
+var propertyRow;
+if(hasPropertyListAttribute){exString=Exhibit.TsvCsvImporter.replaceAll(expressionString,",",separator);
+}if(hasPropertyListAttribute){propertyRow=exString.split(separator);
+if(hasColumnTitles=="false"){rest=lines;
+}else{rest=lines.slice(1);
+}}else{if(hasColumnTitles=="false"){alert("No header row was given for the property names. Either specify them in the ex:properties attribute or add a header row to the file.");
+return ;
+}else{propertyRow=lines[0].split(separator);
+rest=lines.slice(1);
+}}while(rest[rest.length-1]==""){rest=rest.slice(0,rest.length-1);
+}var properties=Exhibit.TsvCsvImporter.getProperties(propertyRow);
+var items=Exhibit.TsvCsvImporter.getItems(separator,rest,propertyRow);
+var json={"properties":properties,"items":items};
+return json;
+};
+Exhibit.TsvCsvImporter.formatType=function(format){var separator="";
+if(format=="tab-separated-values"||format=="tsv"){separator=separator.concat("\t");
+}else{if(format=="comma-separated-values"||format=="csv"){separator=separator.concat(",");
+}else{alert("invalid format, must be tsv or csv");
+}}return separator;
+};
+Exhibit.TsvCsvImporter.getProperties=function(propertyRow){var properties={};
+var valueTypes={"text":true,"number":true,"item":true,"url":true,"boolean":true,"date":true};
+for(i=0;
+i<propertyRow.length;
+i++){var prop=propertyRow[i];
+var type="";
+if(prop.match(":")){var t=prop.substring(prop.lastIndexOf(":")+1);
+prop=prop.substring(0,prop.lastIndexOf(":"));
+if(t in valueTypes){type=t;
+}else{type="text";
+}}else{type="text";
+}properties[prop]={"valueType":type};
+}return properties;
+};
+Exhibit.TsvCsvImporter.getItems=function(separator,rest,propertyRow){var items=[];
+var listSeparator=";";
+for(i=0;
+i<rest.length;
+i++){var row=rest[i].split(separator);
+if(separator==","){var quotes=false;
+for(var j=0;
+j<row.length;
+j++){if(row[j].indexOf('"')==0&&row[j][row[j].length-1]!='"'){quotes=true;
+var x=j;
+while(quotes){joined=[row[x]+","+row[x+1]];
+row=row.slice(0,x).concat(joined,row.slice(x+2));
+if(row[x][row[x].length-1]=='"'){quotes=false;
+}}}}}if(row.length<propertyRow.length){while(row.length!=propertyRow.length){row.push("");
+}}var item={};
+for(var j=0;
+j<propertyRow.length;
+j++){var values=row[j];
+values=Exhibit.TsvCsvImporter.replaceAll(values,'""','"');
+if(values[0]=='"'){values=values.slice(1);
+}if(values[values.length-1]=='"'){values=values.slice(0,values.length-1);
+}var fieldValues=values.split(listSeparator);
+if(fieldValues.length>1){for(var k=0;
+k<fieldValues.length;
+k++){while(fieldValues[k][0]==" "){fieldValues[k]=fieldValues[k].slice(1);
+}}}var property=propertyRow[j];
+var fieldname=property.match(":")?property.substring(0,property.lastIndexOf(":")):property;
+item[fieldname]=fieldValues;
+}items.push(item);
+}return items;
+};
+Exhibit.TsvCsvImporter.replaceAll=function(string,toBeReplaced,replaceWith){var regex="/"+toBeReplaced+"/g";
+return string.replace(eval(regex),replaceWith);
+};
+
+
+/* exhibit.js */
+Exhibit.create=function(database){return new Exhibit._Impl(database);
+};
+Exhibit.getAttribute=function(elmt,name,splitOn){try{var value=elmt.getAttribute(name);
+if(value==null||value.length==0){value=elmt.getAttribute("ex:"+name);
+if(value==null||value.length==0){return null;
+}}if(splitOn==null){return value;
+}var values=value.split(splitOn);
+for(var i=0;
+value=values[i];
+i++){values[i]=value.trim();
+}return values;
+}catch(e){return null;
+}};
+Exhibit.getRoleAttribute=function(elmt){var role=Exhibit.getAttribute(elmt,"role")||"";
+role=role.replace(/^exhibit-/,"");
+return role;
+};
+Exhibit.getConfigurationFromDOM=function(elmt){var c=Exhibit.getAttribute(elmt,"configuration");
+if(c!=null&&c.length>0){try{var o=eval(c);
+if(typeof o=="object"){return o;
+}}catch(e){}}return{};
+};
+Exhibit.extractOptionsFromElement=function(elmt){var opts={};
+var attrs=elmt.attributes;
+for(var i in attrs){if(attrs.hasOwnProperty(i)){var name=attrs[i].nodeName;
+var value=attrs[i].nodeValue;
+if(name.indexOf("ex:")==0){name=name.substring(3);
+}opts[name]=value;
+}}return opts;
+};
+Exhibit.getExporters=function(){Exhibit._initializeExporters();
+return[].concat(Exhibit._exporters);
+};
+Exhibit.addExporter=function(exporter){Exhibit._initializeExporters();
+Exhibit._exporters.push(exporter);
+};
+Exhibit._initializeExporters=function(){if(!("_exporters" in Exhibit)){Exhibit._exporters=[Exhibit.RdfXmlExporter,Exhibit.SemanticWikitextExporter,Exhibit.TSVExporter,Exhibit.ExhibitJsonExporter,Exhibit.FacetSelectionExporter];
+}};
+Exhibit._Impl=function(database){this._database=database!=null?database:("database" in window?window.database:Exhibit.Database.create());
+this._uiContext=Exhibit.UIContext.createRootContext({},this);
+this._collectionMap={};
+this._componentMap={};
+this._historyListener={onBeforePerform:function(action){if(action.lengthy){Exhibit.UI.showBusyIndicator();
+}},onAfterPerform:function(action){if(action.lengthy){Exhibit.UI.hideBusyIndicator();
+}},onBeforeUndoSeveral:function(){Exhibit.UI.showBusyIndicator();
+},onAfterUndoSeveral:function(){Exhibit.UI.hideBusyIndicator();
+},onBeforeRedoSeveral:function(){Exhibit.UI.showBusyIndicator();
+},onAfterRedoSeveral:function(){Exhibit.UI.hideBusyIndicator();
+}};
+SimileAjax.History.addListener(this._historyListener);
+};
+Exhibit._Impl.prototype.dispose=function(){SimileAjax.History.removeListener(this._historyListener);
+for(var id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e,"Failed to dispose component");
+}}for(var id in this._collectionMap){try{this._collectionMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e,"Failed to dispose collection");
+}}this._uiContext.dispose();
+this._componentMap=null;
+this._collectionMap=null;
+this._uiContext=null;
+this._database=null;
+};
+Exhibit._Impl.prototype.getDatabase=function(){return this._database;
+};
+Exhibit._Impl.prototype.getUIContext=function(){return this._uiContext;
+};
+Exhibit._Impl.prototype.getCollection=function(id){var collection=this._collectionMap[id];
+if(collection==null&&id=="default"){collection=Exhibit.Collection.createAllItemsCollection(id,this._database);
+this.setDefaultCollection(collection);
+}return collection;
+};
+Exhibit._Impl.prototype.getDefaultCollection=function(){return this.getCollection("default");
+};
+Exhibit._Impl.prototype.setCollection=function(id,c){if(id in this._collectionMap){try{this._collectionMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}}this._collectionMap[id]=c;
+};
+Exhibit._Impl.prototype.setDefaultCollection=function(c){this.setCollection("default",c);
+};
+Exhibit._Impl.prototype.getComponent=function(id){return this._componentMap[id];
+};
+Exhibit._Impl.prototype.setComponent=function(id,c){if(id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}}this._componentMap[id]=c;
+};
+Exhibit._Impl.prototype.disposeComponent=function(id){if(id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}delete this._componentMap[id];
+}};
+Exhibit._Impl.prototype.configure=function(configuration){if("collections" in configuration){for(var i=0;
+i<configuration.collections.length;
+i++){var config=configuration.collections[i];
+var id=config.id;
+if(id==null||id.length==0){id="default";
+}this.setCollection(id,Exhibit.Collection.create2(id,config,this._uiContext));
+}}if("components" in configuration){for(var i=0;
+i<configuration.components.length;
+i++){var config=configuration.components[i];
+var component=Exhibit.UI.create(config,config.elmt,this._uiContext);
+if(component!=null){var id=elmt.id;
+if(id==null||id.length==0){id="component"+Math.floor(Math.random()*1000000);
+}this.setComponent(id,component);
+}}}};
+Exhibit._Impl.prototype.configureFromDOM=function(root){var collectionElmts=[];
+var coderElmts=[];
+var coordinatorElmts=[];
+var lensElmts=[];
+var facetElmts=[];
+var otherElmts=[];
+var f=function(elmt){var role=Exhibit.getRoleAttribute(elmt);
+if(role.length>0){switch(role){case"collection":collectionElmts.push(elmt);
+break;
+case"coder":coderElmts.push(elmt);
+break;
+case"coordinator":coordinatorElmts.push(elmt);
+break;
+case"lens":case"submission-lens":case"edit-lens":lensElmts.push(elmt);
+break;
+case"facet":facetElmts.push(elmt);
+break;
+default:otherElmts.push(elmt);
+}}else{var node=elmt.firstChild;
+while(node!=null){if(node.nodeType==1){f(node);
+}node=node.nextSibling;
+}}};
+f(root||document.body);
+var uiContext=this._uiContext;
+for(var i=0;
+i<collectionElmts.length;
+i++){var elmt=collectionElmts[i];
+var id=elmt.id;
+if(id==null||id.length==0){id="default";
+}this.setCollection(id,Exhibit.Collection.createFromDOM2(id,elmt,uiContext));
+}var self=this;
+var processElmts=function(elmts){for(var i=0;
+i<elmts.length;
+i++){var elmt=elmts[i];
+try{var component=Exhibit.UI.createFromDOM(elmt,uiContext);
+if(component!=null){var id=elmt.id;
+if(id==null||id.length==0){id="component"+Math.floor(Math.random()*1000000);
+}self.setComponent(id,component);
+}}catch(e){SimileAjax.Debug.exception(e);
+}}};
+processElmts(coordinatorElmts);
+processElmts(coderElmts);
+processElmts(lensElmts);
+processElmts(facetElmts);
+processElmts(otherElmts);
+this.importSettings();
+var exporters=Exhibit.getAttribute(document.body,"exporters");
+if(exporters!=null){exporters=exporters.split(";");
+for(var i=0;
+i<exporters.length;
+i++){var expr=exporters[i];
+var exporter=null;
+try{exporter=eval(expr);
+}catch(e){}if(exporter==null){try{exporter=eval(expr+"Exporter");
+}catch(e){}}if(exporter==null){try{exporter=eval("Exhibit."+expr+"Exporter");
+}catch(e){}}if(typeof exporter=="object"){Exhibit.addExporter(exporter);
+}}}var hash=document.location.hash;
+if(hash.length>1){var itemID=decodeURIComponent(hash.substr(1));
+if(this._database.containsItem(itemID)){this._showFocusDialogOnItem(itemID);
+}}};
+Exhibit._Impl.prototype._showFocusDialogOnItem=function(itemID){var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-focusDialog-viewContainer' id='lensContainer'></div><div class='exhibit-focusDialog-controls'><button id='closeButton'>"+Exhibit.l10n.focusDialogBoxCloseButtonLabel+"</button></div>");
+dom.elmt.className="exhibit-focusDialog exhibit-ui-protection";
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var itemLens=this._uiContext.getLensRegistry().createLens(itemID,dom.lensContainer,this._uiContext);
+dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+},dom.layer);
+};
+Exhibit._Impl.prototype.exportSettings=function(){var facetSelections={},facetSettings="";
+for(var id in this._componentMap){if(typeof this._componentMap[id].exportFacetSelection!=="undefined"){facetSettings=this._componentMap[id].exportFacetSelection()||false;
+if(facetSettings){facetSelections[id]=facetSettings;
+}}}return facetSelections;
+};
+Exhibit._Impl.prototype.importSettings=function(){if(window.location.search.length>0){searchComponents=window.location.search.substr(1,window.location.search.length-1).split("&");
+for(var x=0;
+x<searchComponents.length;
+x++){var component=searchComponents[x].split("=");
+var componentId=component[0];
+var componentSelection=unescape(component[1]);
+if(this._componentMap[componentId]&&(typeof this._componentMap[componentId].importFacetSelection!=="undefined")){this._componentMap[componentId].importFacetSelection(componentSelection);
+}}}};
+
+
+/* persistence.js */
+Exhibit.Persistence={};
+Exhibit.Persistence.getBaseURL=function(url){try{if(url.indexOf("://")<0){var url2=Exhibit.Persistence.getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}var i=url.lastIndexOf("/");
+if(i<0){return"";
+}else{return url.substr(0,i+1);
+}}catch(e){return url;
+}};
+Exhibit.Persistence.resolveURL=function(url){if(url.indexOf("://")<0){var url2=Exhibit.Persistence.getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}return url;
+};
+Exhibit.Persistence.getURLWithoutQueryAndHash=function(){var url;
+if("_urlWithoutQueryAndHash" in Exhibit){url=Exhibit.Persistence._urlWithoutQueryAndHash;
+}else{url=document.location.href;
+var hash=url.indexOf("#");
+var question=url.indexOf("?");
+if(question>=0){url=url.substr(0,question);
+}else{if(hash>=0){url=url.substr(0,hash);
+}}Exhibit.Persistence._urlWithoutQueryAndHash=url;
+}return url;
+};
+Exhibit.Persistence.getURLWithoutQuery=function(){var url;
+if("_urlWithoutQuery" in Exhibit.Persistence){url=Exhibit.Persistence._urlWithoutQuery;
+}else{url=document.location.href;
+var question=url.indexOf("?");
+if(question>=0){url=url.substr(0,question);
+}Exhibit.Persistence._urlWithoutQuery=url;
+}return url;
+};
+Exhibit.Persistence.getItemLink=function(itemID){return Exhibit.Persistence.getURLWithoutQueryAndHash()+"#"+encodeURIComponent(itemID);
+};
+
+
+/* color-coder.js */
+Exhibit.ColorCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:Exhibit.Coders.l10n.mixedCaseLabel,color:Exhibit.Coders.mixedCaseColor};
+this._missingCase={label:Exhibit.Coders.l10n.missingCaseLabel,color:Exhibit.Coders.missingCaseColor};
+this._othersCase={label:Exhibit.Coders.l10n.othersCaseLabel,color:Exhibit.Coders.othersCaseColor};
+};
+Exhibit.ColorCoder._settingSpecs={};
+Exhibit.ColorCoder.create=function(configuration,uiContext){var coder=new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ColorCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"color"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"ColorCoder: Error processing configuration of coder");
+}Exhibit.ColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ColorCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].color);
+}}};
+Exhibit.ColorCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.ColorCoder._colorTable={"red":"#ff0000","green":"#00ff00","blue":"#0000ff","white":"#ffffff","black":"#000000","gray":"#888888"};
+Exhibit.ColorCoder.prototype._addEntry=function(kase,key,color){if(color in Exhibit.ColorCoder._colorTable){color=Exhibit.ColorCoder._colorTable[color];
+}var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.color=color;
+}else{this._map[key]={color:color};
+}};
+Exhibit.ColorCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].color;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.color;
+}else{if(flags){flags.others=true;
+}return this._othersCase.color;
+}}};
+Exhibit.ColorCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){if(flags){flags.mixed=true;
+}color=self._mixedCase.color;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.color;
+}};
+Exhibit.ColorCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.ColorCoder.prototype.getOthersColor=function(){return this._othersCase.color;
+};
+Exhibit.ColorCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.ColorCoder.prototype.getMissingColor=function(){return this._missingCase.color;
+};
+Exhibit.ColorCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.ColorCoder.prototype.getMixedColor=function(){return this._mixedCase.color;
+};
+
+
+/* color-gradient-coder.js */
+Exhibit.ColorGradientCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._gradientPoints=[];
+this._mixedCase={label:Exhibit.Coders.l10n.mixedCaseLabel,color:Exhibit.Coders.mixedCaseColor};
+this._missingCase={label:Exhibit.Coders.l10n.missingCaseLabel,color:Exhibit.Coders.missingCaseColor};
+this._othersCase={label:Exhibit.Coders.l10n.othersCaseLabel,color:Exhibit.Coders.othersCaseColor};
+};
+Exhibit.ColorGradientCoder._settingSpecs={};
+Exhibit.ColorGradientCoder.create=function(configuration,uiContext){var coder=new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ColorGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorGradientCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ColorGradientCoder._settingSpecs,coder._settings);
+try{var gradientPoints=Exhibit.getAttribute(configElmt,"gradientPoints",";");
+for(var i=0;
+i<gradientPoints.length;
+i++){var point=gradientPoints[i];
+var value=parseFloat(point);
+var colorIndex=point.indexOf("#")+1;
+var red=parseInt(point.slice(colorIndex,colorIndex+2),16);
+var green=parseInt(point.slice(colorIndex+2,colorIndex+4),16);
+var blue=parseInt(point.slice(colorIndex+4),16);
+coder._gradientPoints.push({value:value,red:red,green:green,blue:blue});
+}var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"color"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"ColorGradientCoder: Error processing configuration of coder");
+}Exhibit.ColorGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorGradientCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ColorGradientCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].color);
+}}};
+Exhibit.ColorGradientCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.ColorGradientCoder.prototype._addEntry=function(kase,key,color){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.color=color;
+}};
+Exhibit.ColorGradientCoder.prototype.translate=function(key,flags){var gradientPoints=this._gradientPoints;
+var getColor=function(key){if(key.constructor!=Number){key=parseFloat(key);
+}for(j=0;
+j<gradientPoints.length;
+j++){if(key==gradientPoints[j].value){return rgbToHex(gradientPoints[j].red,gradientPoints[j].green,gradientPoints[j].blue);
+}else{if(gradientPoints[j+1]!=null){if(key<gradientPoints[j+1].value){var fraction=(key-gradientPoints[j].value)/(gradientPoints[j+1].value-gradientPoints[j].value);
+var newRed=Math.floor(gradientPoints[j].red+fraction*(gradientPoints[j+1].red-gradientPoints[j].red));
+var newGreen=Math.floor(gradientPoints[j].green+fraction*(gradientPoints[j+1].green-gradientPoints[j].green));
+var newBlue=Math.floor(gradientPoints[j].blue+fraction*(gradientPoints[j+1].blue-gradientPoints[j].blue));
+return rgbToHex(newRed,newGreen,newBlue);
+}}}}};
+var rgbToHex=function(r,g,b){var decToHex=function(n){if(n==0){return"00";
+}else{return n.toString(16);
+}};
+return"#"+decToHex(r)+decToHex(g)+decToHex(b);
+};
+if(key>=gradientPoints[0].value&key<=gradientPoints[gradientPoints.length-1].value){if(flags){flags.keys.add(key);
+}return getColor(key);
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.color;
+}else{if(flags){flags.others=true;
+}return this._othersCase.color;
+}}};
+Exhibit.ColorGradientCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){if(flags){flags.mixed=true;
+}color=self._mixedCase.color;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.color;
+}};
+Exhibit.ColorGradientCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getOthersColor=function(){return this._othersCase.color;
+};
+Exhibit.ColorGradientCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMissingColor=function(){return this._missingCase.color;
+};
+Exhibit.ColorGradientCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMixedColor=function(){return this._mixedCase.color;
+};
+
+
+/* default-color-coder.js */
+Exhibit.DefaultColorCoder=function(uiContext){};
+Exhibit.DefaultColorCoder.colors=["#FF9000","#5D7CBA","#A97838","#8B9BBA","#FFC77F","#003EBA","#29447B","#543C1C"];
+Exhibit.DefaultColorCoder._map={};
+Exhibit.DefaultColorCoder._nextColor=0;
+Exhibit.DefaultColorCoder.prototype.translate=function(key,flags){if(key==null){if(flags){flags.missing=true;
+}return Exhibit.Coders.missingCaseColor;
+}else{if(flags){flags.keys.add(key);
+}if(key in Exhibit.DefaultColorCoder._map){return Exhibit.DefaultColorCoder._map[key];
+}else{var color=Exhibit.DefaultColorCoder.colors[Exhibit.DefaultColorCoder._nextColor];
+Exhibit.DefaultColorCoder._nextColor=(Exhibit.DefaultColorCoder._nextColor+1)%Exhibit.DefaultColorCoder.colors.length;
+Exhibit.DefaultColorCoder._map[key]=color;
+return color;
+}}};
+Exhibit.DefaultColorCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){color=Exhibit.Coders.mixedCaseColor;
+flags.mixed=true;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{flags.missing=true;
+return Exhibit.Coders.missingCaseColor;
+}};
+Exhibit.DefaultColorCoder.prototype.getOthersLabel=function(){return Exhibit.Coders.l10n.othersCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getOthersColor=function(){return Exhibit.Coders.othersCaseColor;
+};
+Exhibit.DefaultColorCoder.prototype.getMissingLabel=function(){return Exhibit.Coders.l10n.missingCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMissingColor=function(){return Exhibit.Coders.missingCaseColor;
+};
+Exhibit.DefaultColorCoder.prototype.getMixedLabel=function(){return Exhibit.Coders.l10n.mixedCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMixedColor=function(){return Exhibit.Coders.mixedCaseColor;
+};
+
+
+/* icon-coder.js */
+Exhibit.IconCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:"mixed",icon:null};
+this._missingCase={label:"missing",icon:null};
+this._othersCase={label:"others",icon:null};
+};
+Exhibit.IconCoder._settingSpecs={};
+Exhibit.IconCoder.create=function(configuration,uiContext){var coder=new Exhibit.IconCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.IconCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.IconCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.IconCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.IconCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"icon"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"IconCoder: Error processing configuration of coder");
+}Exhibit.IconCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.IconCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.IconCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].icon);
+}}};
+Exhibit.IconCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.IconCoder._iconTable={};
+Exhibit.IconCoder.prototype._addEntry=function(kase,key,icon){if(icon in Exhibit.IconCoder._iconTable){icon=Exhibit.IconCoder._iconTable[icon];
+}var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.icon=icon;
+}else{this._map[key]={icon:icon};
+}};
+Exhibit.IconCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].icon;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.icon;
+}else{if(flags){flags.others=true;
+}return this._othersCase.icon;
+}}};
+Exhibit.IconCoder.prototype.translateSet=function(keys,flags){var icon=null;
+var self=this;
+keys.visit(function(key){var icon2=self.translate(key,flags);
+if(icon==null){icon=icon2;
+}else{if(icon!=icon2){if(flags){flags.mixed=true;
+}icon=self._mixedCase.icon;
+return true;
+}}return false;
+});
+if(icon!=null){return icon;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.icon;
+}};
+Exhibit.IconCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.IconCoder.prototype.getOthersIcon=function(){return this._othersCase.icon;
+};
+Exhibit.IconCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.IconCoder.prototype.getMissingIcon=function(){return this._missingCase.icon;
+};
+Exhibit.IconCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.IconCoder.prototype.getMixedIcon=function(){return this._mixedCase.icon;
+};
+
+
+/* size-coder.js */
+Exhibit.SizeCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:"mixed",size:10};
+this._missingCase={label:"missing",size:10};
+this._othersCase={label:"others",size:10};
+};
+Exhibit.SizeCoder._settingSpecs={};
+Exhibit.SizeCoder.create=function(configuration,uiContext){var coder=new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SizeCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SizeCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"size"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"SizeCoder: Error processing configuration of coder");
+}Exhibit.SizeCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SizeCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].size);
+}}};
+Exhibit.SizeCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.SizeCoder.prototype._addEntry=function(kase,key,size){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.size=size;
+}else{this._map[key]={size:size};
+}};
+Exhibit.SizeCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].size;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.size;
+}else{if(flags){flags.others=true;
+}return this._othersCase.size;
+}}};
+Exhibit.SizeCoder.prototype.translateSet=function(keys,flags){var size=null;
+var self=this;
+keys.visit(function(key){var size2=self.translate(key,flags);
+if(size==null){size=size2;
+}else{if(size!=size2){if(flags){flags.mixed=true;
+}size=self._mixedCase.size;
+return true;
+}}return false;
+});
+if(size!=null){return size;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.size;
+}};
+Exhibit.SizeCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.SizeCoder.prototype.getOthersSize=function(){return this._othersCase.size;
+};
+Exhibit.SizeCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.SizeCoder.prototype.getMissingSize=function(){return this._missingCase.size;
+};
+Exhibit.SizeCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.SizeCoder.prototype.getMixedSize=function(){return this._mixedCase.size;
+};
+
+
+/* size-gradient-coder.js */
+Exhibit.SizeGradientCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._log={func:function(size){return Math.ceil(Math.log(size));
+},invFunc:function(size){return Math.ceil(Math.exp(size));
+}};
+this._linear={func:function(size){return Math.ceil(size);
+},invFunc:function(size){return Math.ceil(size);
+}};
+this._quad={func:function(size){return Math.ceil(Math.pow((size/100),2));
+},invFunc:function(size){return Math.sqrt(size)*100;
+}};
+this._exp={func:function(size){return Math.ceil(Math.exp(size));
+},invFunc:function(size){return Math.ceil(Math.log(size));
+}};
+this._markerScale=this._quad;
+this._valueScale=this._linear;
+this._gradientPoints=[];
+this._mixedCase={label:"mixed",size:20};
+this._missingCase={label:"missing",size:20};
+this._othersCase={label:"others",size:20};
+};
+Exhibit.SizeGradientCoder._settingSpecs={};
+Exhibit.SizeGradientCoder.create=function(configuration,uiContext){var coder=new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SizeGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeGradientCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SizeGradientCoder._settingSpecs,coder._settings);
+try{var markerScale=coder._settings.markerScale;
+if(markerScale=="log"){coder._markerScale=coder._log;
+}if(markerScale=="linear"){coder._markerScale=coder._linear;
+}if(markerScale=="exp"){coder._markerScale=coder._exp;
+}var gradientPoints=Exhibit.getAttribute(configElmt,"gradientPoints",";");
+for(var i=0;
+i<gradientPoints.length;
+i++){var point=gradientPoints[i].split(",");
+var value=parseFloat(point[0]);
+var size=coder._markerScale.invFunc(parseFloat(point[1]));
+coder._gradientPoints.push({value:value,size:size});
+}var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"size"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"SizeGradientCoder: Error processing configuration of coder");
+}Exhibit.SizeGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeGradientCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SizeGradientCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].size);
+}}};
+Exhibit.SizeGradientCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.SizeGradientCoder.prototype._addEntry=function(kase,key,size){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.size=size;
+}};
+Exhibit.SizeGradientCoder.prototype.translate=function(key,flags){var self=this;
+var gradientPoints=this._gradientPoints;
+var getSize=function(key){if(key.constructor!=Number){key=parseFloat(key);
+}for(j=0;
+j<gradientPoints.length;
+j++){if(key==gradientPoints[j].value){return self._markerScale.func(gradientPoints[j].size);
+}else{if(gradientPoints[j+1]!=null){if(key<gradientPoints[j+1].value){var fraction=(key-gradientPoints[j].value)/(gradientPoints[j+1].value-gradientPoints[j].value);
+var newSize=Math.floor(gradientPoints[j].size+fraction*(gradientPoints[j+1].size-gradientPoints[j].size));
+return self._markerScale.func(newSize);
+}}}}};
+if(key>=gradientPoints[0].value&key<=gradientPoints[gradientPoints.length-1].value){if(flags){flags.keys.add(key);
+}return getSize(key);
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.size;
+}else{if(flags){flags.others=true;
+}return this._othersCase.size;
+}}};
+Exhibit.SizeGradientCoder.prototype.translateSet=function(keys,flags){var size=null;
+var self=this;
+keys.visit(function(key){var size2=self.translate(key,flags);
+if(size==null){size=size2;
+}else{if(size!=size2){if(flags){flags.mixed=true;
+}size=self._mixedCase.size;
+return true;
+}}return false;
+});
+if(size!=null){return size;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.size;
+}};
+Exhibit.SizeGradientCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getOthersSize=function(){return this._othersCase.size;
+};
+Exhibit.SizeGradientCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMissingSize=function(){return this._missingCase.size;
+};
+Exhibit.SizeGradientCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMixedSize=function(){return this._mixedCase.size;
+};
+
+
+/* coordinator.js */
+Exhibit.Coordinator=function(uiContext){this._uiContext=uiContext;
+this._listeners=[];
+};
+Exhibit.Coordinator.create=function(configuration,uiContext){var coordinator=new Exhibit.Coordinator(uiContext);
+return coordinator;
+};
+Exhibit.Coordinator.createFromDOM=function(div,uiContext){var coordinator=new Exhibit.Coordinator(Exhibit.UIContext.createFromDOM(div,uiContext,false));
+return coordinator;
+};
+Exhibit.Coordinator.prototype.dispose=function(){this._uiContext.dispose();
+this._uiContext=null;
+};
+Exhibit.Coordinator.prototype.addListener=function(callback){var listener=new Exhibit.Coordinator._Listener(this,callback);
+this._listeners.push(listener);
+return listener;
+};
+Exhibit.Coordinator.prototype._removeListener=function(listener){for(var i=0;
+i<this._listeners.length;
+i++){if(this._listeners[i]==listener){this._listeners.splice(i,1);
+return ;
+}}};
+Exhibit.Coordinator.prototype._fire=function(listener,o){for(var i=0;
+i<this._listeners.length;
+i++){var listener2=this._listeners[i];
+if(listener2!=listener){listener2._callback(o);
+}}};
+Exhibit.Coordinator._Listener=function(coordinator,callback){this._coordinator=coordinator;
+this._callback=callback;
+};
+Exhibit.Coordinator._Listener.prototype.dispose=function(){this._coordinator._removeListener(this);
+};
+Exhibit.Coordinator._Listener.prototype.fire=function(o){this._coordinator._fire(this,o);
+};
+
+
+/* alpha-range-facet.js */
+Exhibit.AlphaRangeFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._dom=null;
+this._ranges=[];
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_rangeIndex" in self){delete self._rangeIndex;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.AlphaRangeFacet._settingSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"interval":{type:"int",defaultValue:7},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.AlphaRangeFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.AlphaRangeFacet(containerElmt,uiContext);
+Exhibit.AlphaRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.AlphaRangeFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.AlphaRangeFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.AlphaRangeFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}}catch(e){SimileAjax.Debug.exception(e,"AlphaRangeFacet: Error processing configuration of alpha range facet");
+}Exhibit.AlphaRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.AlphaRangeFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.AlphaRangeFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.AlphaRangeFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._ranges=[];
+};
+Exhibit.AlphaRangeFacet.prototype.hasRestrictions=function(){return this._ranges.length>0;
+};
+Exhibit.AlphaRangeFacet.prototype.clearAllRestrictions=function(){var restrictions=[];
+if(this._ranges.length>0){restrictions=restrictions.concat(this._ranges);
+this._ranges=[];
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.AlphaRangeFacet.prototype.applyRestrictions=function(restrictions){this._ranges=restrictions;
+this._notifyCollection();
+};
+Exhibit.AlphaRangeFacet.prototype.setRange=function(from,to,selected){if(selected){for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){return ;
+}}this._ranges.push({from:from,to:to});
+}else{for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){this._ranges.splice(i,1);
+break;
+}}}this._notifyCollection();
+};
+Exhibit.AlphaRangeFacet.prototype.restrict=function(items){if(this._ranges.length==0){return items;
+}else{this._buildRangeIndex();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+this._rangeIndex.getSubjectsInRange(range.from,String.fromCharCode(range.to.charCodeAt(0)+1),true,set,items);
+}return set;
+}};
+Exhibit.AlphaRangeFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._reconstruct(items);
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.AlphaRangeFacet.prototype._reconstruct=function(items){var self=this;
+var ranges=[];
+var rangeIndex;
+var computeItems;
+this._buildRangeIndex();
+rangeIndex=this._rangeIndex;
+countItems=function(range){return rangeIndex.getSubjectsInRange(range.from,String.fromCharCode(range.to.charCodeAt(0)+1),true,null,items).size();
+};
+var alphaList=[];
+var alphaInList=function(a){for(x in alphaList){if(alphaList[x]==a){return true;
+}}return false;
+};
+for(var y=0;
+y<rangeIndex.getCount();
+y+=1){var alphaChar=rangeIndex._pairs[y].value.substr(0,1).toUpperCase();
+if(!alphaInList(alphaChar)){alphaList.push(alphaChar);
+}}for(var x=0;
+x<alphaList.length;
+x+=this._settings.interval){var range={from:alphaList[x],to:alphaList[(x+this._settings.interval>=alphaList.length?alphaList.length-1:x+this._settings.interval-1)],selected:false};
+range.count=countItems(range);
+for(var i=0;
+i<this._ranges.length;
+i++){var range2=this._ranges[i];
+if(range2.from==range.from&&range2.to==range.to){range.selected=true;
+facetHasSelection=true;
+break;
+}}ranges.push(range);
+}var facetHasSelection=this._ranges.length>0;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var makeFacetValue=function(from,to,count,selected){var onSelect=function(elmt,evt,target){self._toggleRange(from,to,selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._toggleRange(from,to,selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(from.substr(0,1)+" - "+to.substr(0,1),count,null,selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+containerDiv.appendChild(elmt);
+};
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i];
+if(range.selected||range.count>0){makeFacetValue(range.from,range.to,range.count,range.selected);
+}}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._ranges.length);
+};
+Exhibit.AlphaRangeFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.AlphaRangeFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.AlphaRangeFacet.prototype._toggleRange=function(from,to,wasSelected,singleSelection){var self=this;
+var label=from+" to "+to;
+var wasOnlyThingSelected=(this._ranges.length==1&&wasSelected);
+if(singleSelection&&!wasOnlyThingSelected){var newRestrictions=[{from:from,to:to}];
+var oldRestrictions=[].concat(this._ranges);
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]));
+}else{SimileAjax.History.addLengthyAction(function(){self.setRange(from,to,!wasSelected);
+},function(){self.setRange(from,to,wasSelected);
+},String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+}};
+Exhibit.AlphaRangeFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.AlphaRangeFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var segment=expression.getPath().getLastSegment();
+var property=database.getProperty(segment.property);
+var getter=function(item,f){database.getObjects(item,property.getID(),null,null).visit(function(value){f(value.toUpperCase());
+});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+Exhibit.AlphaRangeFacet.prototype.exportFacetSelection=function(){var exportedSettings=[];
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+exportedSettings.push(range.from+"|"+range.to);
+}return exportedSettings.join(",");
+};
+Exhibit.AlphaRangeFacet.prototype.importFacetSelection=function(settings){if(settings.length>0){var ranges=settings.split(",");
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i].split("|");
+this._ranges.push({from:range[0],to:range[1]});
+}}if(ranges&&ranges.length>0){this.update();
+this._notifyCollection();
+}};
+
+
+/* cloud-facet.js */
+Exhibit.CloudFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._settings={};
+this._dom=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}if("_valueToItem" in self){delete self._valueToItem;
+}if("_missingItems" in self){delete self._missingItems;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.CloudFacet._settingSpecs={"facetLabel":{type:"text"},"minimumCount":{type:"int",defaultValue:1},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"}};
+Exhibit.CloudFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.CloudFacet(containerElmt,uiContext);
+Exhibit.CloudFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.CloudFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.CloudFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.CloudFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"CloudFacet: Error processing configuration of cloud facet");
+}Exhibit.CloudFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.CloudFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.CloudFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}};
+Exhibit.CloudFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+this._itemToValue=null;
+this._valueToItem=null;
+this._missingItems=null;
+};
+Exhibit.CloudFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.CloudFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.CloudFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.CloudFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.CloudFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.CloudFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set;
+if(this._expression.isPath()){set=this._expression.getPath().walkBackward(this._valueSet,"item",items,this._uiContext.getDatabase()).getSet();
+}else{this._buildMaps();
+set=new Exhibit.Set();
+var valueToItem=this._valueToItem;
+this._valueSet.visit(function(value){if(value in valueToItem){var itemA=valueToItem[value];
+for(var i=0;
+i<itemA.length;
+i++){var item=itemA[i];
+if(items.contains(item)){set.add(item);
+}}}});
+}if(this._selectMissing){this._buildMaps();
+var missingItems=this._missingItems;
+items.visit(function(item){if(item in missingItems){set.add(item);
+}});
+}return set;
+};
+Exhibit.CloudFacet.prototype.update=function(items){this._constructBody(this._computeFacet(items));
+};
+Exhibit.CloudFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var entries=[];
+var valueType="text";
+var self=this;
+if(this._expression.isPath()){var path=this._expression.getPath();
+var facetValueResult=path.walkForward(items,"item",database);
+valueType=facetValueResult.valueType;
+if(facetValueResult.size>0){facetValueResult.forEachValue(function(facetValue){var itemSubcollection=path.evaluateBackward(facetValue,valueType,items,database);
+if(itemSubcollection.size>=self._settings.minimumCount||self._valueSet.contains(facetValue)){entries.push({value:facetValue,count:itemSubcollection.size});
+}});
+}}else{this._buildMaps();
+valueType=this._valueType;
+for(var value in this._valueToItem){var itemA=this._valueToItem[value];
+var count=0;
+for(var i=0;
+i<itemA.length;
+i++){if(items.contains(itemA[i])){count++;
+}}if(count>=this._settings.minimumCount||this._valueSet.contains(value)){entries.push({value:value,count:count});
+}}}if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.selected=selection.contains(entry.value);
+}var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}entries.sort(sortDirectionFunction);
+}if(this._settings.showMissing||this._selectMissing){this._buildMaps();
+var count=0;
+for(var item in this._missingItems){if(items.contains(item)){count++;
+}}if(count>0||this._selectMissing){var span=document.createElement("span");
+span.innerHTML=("missingLabel" in this._settings)?this._settings.missingLabel:Exhibit.FacetUtilities.l10n.missingThisField;
+span.className="exhibit-facet-value-missingThisField";
+entries.unshift({value:null,count:count,selected:this._selectMissing,selectionLabel:span,actionLabel:Exhibit.FacetUtilities.l10n.missingThisField});
+}}return entries;
+};
+Exhibit.CloudFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.CloudFacet.prototype._initializeUI=function(){this._div.innerHTML="";
+this._div.className="exhibit-cloudFacet";
+var dom=SimileAjax.DOM.createDOMFromString(this._div,(("facetLabel" in this._settings)?("<div class='exhibit-cloudFacet-header'><span class='exhibit-cloudFacet-header-title'>"+this._settings.facetLabel+"</span></div>"):"")+"<div class='exhibit-cloudFacet-body' id='valuesContainer'></div>");
+this._dom=dom;
+};
+Exhibit.CloudFacet.prototype._constructBody=function(entries){var self=this;
+var div=this._dom.valuesContainer;
+div.style.display="none";
+div.innerHTML="";
+if(entries.length>0){var min=Number.POSITIVE_INFINITY;
+var max=Number.NEGATIVE_INFINITY;
+for(var j=0;
+j<entries.length;
+j++){var entry=entries[j];
+min=Math.min(min,entry.count);
+max=Math.max(max,entry.count);
+}var range=max-min;
+var constructValue=function(entry){var onSelect=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=document.createElement("span");
+elmt.appendChild(document.createTextNode("\u00A0"));
+if(typeof entry.selectionLabel=="string"){elmt.appendChild(document.createTextNode(entry.selectionLabel));
+}else{elmt.appendChild(entry.selectionLabel);
+}elmt.appendChild(document.createTextNode("\u00A0"));
+elmt.className=entry.selected?"exhibit-cloudFacet-value exhibit-cloudFacet-value-selected":"exhibit-cloudFacet-value";
+if(entry.count>min){elmt.style.fontSize=Math.ceil(100+100*Math.log(1+1.5*(entry.count-min)/range))+"%";
+}SimileAjax.WindowManager.registerEvent(elmt,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+div.appendChild(elmt);
+div.appendChild(document.createTextNode(" "));
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}}div.style.display="block";
+};
+Exhibit.CloudFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+var facetLabel=("facetLabel" in this._settings)?this._settings.facetLabel:"";
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,facetLabel]));
+};
+Exhibit.CloudFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.CloudFacet.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var valueToItem={};
+var missingItems={};
+var valueType="text";
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var expression=this._expression;
+var database=this._uiContext.getDatabase();
+this._uiContext.getCollection().getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){insert(item,value,itemToValue);
+insert(value,item,valueToItem);
+});
+}else{missingItems[item]=true;
+}});
+this._itemToValue=itemToValue;
+this._valueToItem=valueToItem;
+this._missingItems=missingItems;
+this._valueType=valueType;
+}};
+
+
+/* hierarchical-facet.js */
+Exhibit.HierarchicalFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._uniformGroupingExpression=null;
+this._selections=[];
+this._expanded={};
+this._settings={};
+this._dom=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_cache" in self){delete self._cache;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.HierarchicalFacet._settingSpecs={"facetLabel":{type:"text"},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"othersLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.HierarchicalFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.HierarchicalFacet(containerElmt,uiContext);
+Exhibit.HierarchicalFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.HierarchicalFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.HierarchicalFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.HierarchicalFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var uniformGroupingString=Exhibit.getAttribute(configElmt,"uniformGrouping");
+if(uniformGroupingString!=null&&uniformGroupingString.length>0){facet._uniformGroupingExpression=Exhibit.ExpressionParser.parse(uniformGroupingString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._selections=facet._internalAddSelection({value:s,selectOthers:false});
+}}}catch(e){SimileAjax.Debug.exception(e,"HierarchicalFacet: Error processing configuration of hierarchical facet");
+}Exhibit.HierarchicalFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.HierarchicalFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.HierarchicalFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("uniformGrouping" in configuration){facet._uniformGroupingExpression=Exhibit.ExpressionParser.parse(configuration.uniformGrouping);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._selections.push({value:selection[i],selectOthers:false});
+}}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.HierarchicalFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._uniformGroupingExpression=null;
+this._selections=null;
+this._settings=null;
+this._cache=null;
+};
+Exhibit.HierarchicalFacet.prototype.hasRestrictions=function(){return this._selections.length>0;
+};
+Exhibit.HierarchicalFacet.prototype.clearAllRestrictions=function(){var selections=this._selections;
+this._selections=[];
+if(selections.length>0){this._notifyCollection();
+}return selections;
+};
+Exhibit.HierarchicalFacet.prototype.applyRestrictions=function(restrictions){this._selections=[].concat(restrictions);
+this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.setSelection=function(value,selected){var selection={value:value,selectOthers:false};
+if(selected){this._selections=this._internalAddSelection(selection);
+}else{this._selections=this._internalRemoveSelection(selection);
+}this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.setselectOthers=function(value,selected){var selection={value:value,selectOthers:true};
+if(selected){this._selections=this._internalAddSelection(selection);
+}else{this._selections=this._internalRemoveSelection(selection);
+}this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.restrict=function(items){if(this._selections.length==0){return items;
+}this._buildCache();
+var set=new Exhibit.Set();
+var includeNode=function(node){if("children" in node){includeChildNodes(node.children);
+Exhibit.Set.createIntersection(node.others,items,set);
+}else{Exhibit.Set.createIntersection(node.items,items,set);
+}};
+var includeChildNodes=function(childNodes){for(var i=0;
+i<childNodes.length;
+i++){includeNode(childNodes[i]);
+}};
+for(var i=0;
+i<this._selections.length;
+i++){var selection=this._selections[i];
+var node=this._getTreeNode(selection.value);
+if(node){if(selection.selectOthers){Exhibit.Set.createIntersection(node.others,items,set);
+}else{includeNode(node);
+}}}return set;
+};
+Exhibit.HierarchicalFacet.prototype._internalAddSelection=function(selection){var parentToClear={};
+var childrenToClear={};
+var cache=this._cache;
+var markClearAncestors=function(value){if(value in cache.valueToParent){var parents=cache.valueToParent[value];
+for(var i=0;
+i<parents.length;
+i++){var parent=parents[i];
+parentToClear[parent]=true;
+markClearAncestors(parent);
+}}};
+var markClearDescendants=function(value){if(value in cache.valueToChildren){var children=cache.valueToChildren[value];
+for(var i=0;
+i<children.length;
+i++){var child=children[i];
+childrenToClear[child]=true;
+markClearDescendants(child);
+}}};
+if(selection.value!=null){markClearAncestors(selection.value);
+if(selection.selectOthers){parentToClear[selection.value]=true;
+}else{childrenToClear[selection.value]=true;
+markClearDescendants(selection.value);
+}}var oldSelections=this._selections;
+var newSelections=[selection];
+for(var i=0;
+i<oldSelections.length;
+i++){var s=oldSelections[i];
+if((!(s.value in parentToClear)||s.selectOthers)&&(!(s.value in childrenToClear))){newSelections.push(s);
+}}return newSelections;
+};
+Exhibit.HierarchicalFacet.prototype._internalRemoveSelection=function(selection){var oldSelections=this._selections;
+var newSelections=[];
+for(var i=0;
+i<oldSelections.length;
+i++){var s=oldSelections[i];
+if(s.value!=selection.value||s.selectOthers!=selection.selectOthers){newSelections.push(s);
+}}return newSelections;
+};
+Exhibit.HierarchicalFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+var tree=this._computeFacet(items);
+if(tree){this._constructBody(tree);
+}this._dom.valuesContainer.style.display="block";
+};
+Exhibit.HierarchicalFacet.prototype._computeFacet=function(items){this._buildCache();
+var database=this._uiContext.getDatabase();
+var sorter=this._getValueSorter();
+var othersLabel="othersLabel" in this._settings?this._settings.othersLabel:"(others)";
+var selectionMap={};
+for(var i=0;
+i<this._selections.length;
+i++){var s=this._selections[i];
+selectionMap[s.value]=s.selectOthers;
+}var processNode=function(node,resultNodes,superset){var selected=(node.value in selectionMap&&!selectionMap[node.value]);
+if("children" in node){var resultNode={value:node.value,label:node.label,children:[],selected:selected,areOthers:false};
+var superset2=new Exhibit.Set();
+for(var i=0;
+i<node.children.length;
+i++){var childNode=node.children[i];
+processNode(childNode,resultNode.children,superset2);
+}resultNode.children.sort(sorter);
+if(node.others.size()>0){var othersSelected=(node.value in selectionMap&&selectionMap[node.value]);
+var subset=Exhibit.Set.createIntersection(items,node.others);
+if(subset.size()>0||othersSelected){resultNode.children.push({value:node.value,label:othersLabel,count:subset.size(),selected:othersSelected,areOthers:true});
+superset2.addSet(subset);
+}}resultNode.count=superset2.size();
+if(selected||resultNode.count>0||resultNode.children.length>0){resultNodes.push(resultNode);
+if(superset!=null&&superset2.size()>0){superset.addSet(superset2);
+}}}else{var subset=Exhibit.Set.createIntersection(items,node.items);
+if(subset.size()>0||selected){resultNodes.push({value:node.value,label:node.label,count:subset.size(),selected:selected,areOthers:false});
+if(superset!=null&&subset.size()>0){superset.addSet(subset);
+}}}};
+var nodes=[];
+processNode(this._cache.tree,nodes,null);
+return nodes[0];
+};
+Exhibit.HierarchicalFacet.prototype._getValueSorter=function(){var sortValueFunction=function(a,b){return a.label.localeCompare(b.label);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.label in orderMap){if(b.label in orderMap){return orderMap[a.label]-orderMap[b.label];
+}else{return -1;
+}}else{if(b.label in orderMap){return 1;
+}else{return a.label.localeCompare(b.label);
+}}};
+}else{if(this._cache.valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+Exhibit.HierarchicalFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.HierarchicalFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.HierarchicalFacet.prototype._constructBody=function(tree){var self=this;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructHierarchicalFacetItem":"constructFlowingHierarchicalFacetItem"];
+var facetHasSelection=this._selections.length>0;
+var processNode=function(node,div){var hasChildren=("children" in node);
+var onSelect=function(elmt,evt,target){self._filter(node.value,node.areOthers,node.label,node.selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._filter(node.value,node.areOthers,node.label,node.selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onToggleChildren=function(elmt,evt,target){var show;
+if(node.value in self._expanded){delete self._expanded[node.value];
+show=false;
+}else{self._expanded[node.value]=true;
+show=true;
+}dom.showChildren(show);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var dom=constructFacetItemFunction(node.label,node.count,(self._colorCoder!=null)?self._colorCoder.translate(node.value):null,node.selected,hasChildren,(node.value in self._expanded),facetHasSelection,onSelect,onSelectOnly,onToggleChildren,self._uiContext);
+div.appendChild(dom.elmt);
+if(hasChildren){processChildNodes(node.children,dom.childrenContainer);
+}};
+var processChildNodes=function(childNodes,div){for(var i=0;
+i<childNodes.length;
+i++){processNode(childNodes[i],div);
+}};
+processChildNodes(tree.children,containerDiv);
+containerDiv.style.display="block";
+this._dom.setSelectionCount(this._selections.length);
+};
+Exhibit.HierarchicalFacet.prototype._filter=function(value,areOthers,label,wasSelected,selectOnly){var self=this;
+var wasSelectedAlone=wasSelected&&this._selections.length==1;
+var selection={value:value,selectOthers:areOthers};
+var oldRestrictions=this._selections;
+var newRestrictions;
+if(wasSelected){if(selectOnly){if(wasSelectedAlone){newRestrictions=[];
+}else{newRestrictions=[selection];
+}}else{newRestrictions=this._internalRemoveSelection(selection);
+}}else{if(selectOnly){newRestrictions=[selection];
+}else{newRestrictions=this._internalAddSelection(selection);
+}}SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasSelectedAlone)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.HierarchicalFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.HierarchicalFacet.prototype._buildCache=function(){if(!("_cache" in this)){var valueToItem={};
+var valueType="text";
+var valueToChildren={};
+var valueToParent={};
+var valueToPath={};
+var values=new Exhibit.Set();
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var database=this._uiContext.getDatabase();
+var tree={value:null,label:"(root)",others:new Exhibit.Set(),children:[]};
+var expression=this._expression;
+this._uiContext.getCollection().getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){values.add(value);
+insert(value,item,valueToItem);
+});
+}else{tree.others.add(item);
+}});
+var groupingExpression=this._uniformGroupingExpression;
+var rootValues=new Exhibit.Set();
+var getParentChildRelationships=function(valueSet){var newValueSet=new Exhibit.Set();
+valueSet.visit(function(value){var results=groupingExpression.evaluateOnItem(value,database);
+if(results.values.size()>0){results.values.visit(function(parentValue){insert(value,parentValue,valueToParent);
+insert(parentValue,value,valueToChildren);
+if(!valueSet.contains(parentValue)){newValueSet.add(parentValue);
+}return true;
+});
+}else{rootValues.add(value);
+}});
+if(newValueSet.size()>0){getParentChildRelationships(newValueSet);
+}};
+getParentChildRelationships(values);
+var processValue=function(value,nodes,valueSet,path){var label=database.getObject(value,"label");
+var node={value:value,label:label!=null?label:value};
+nodes.push(node);
+valueToPath[value]=path;
+if(value in valueToChildren){node.children=[];
+var valueSet2=new Exhibit.Set();
+var childrenValue=valueToChildren[value];
+for(var i=0;
+i<childrenValue.length;
+i++){processValue(childrenValue[i],node.children,valueSet2,path.concat(i));
+}node.others=new Exhibit.Set();
+if(value in valueToItem){var items=valueToItem[value];
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+if(!valueSet2.contains(item)){node.others.add(item);
+valueSet.add(item);
+}}}valueSet.addSet(valueSet2);
+}else{node.items=new Exhibit.Set();
+if(value in valueToItem){var items=valueToItem[value];
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+node.items.add(item);
+valueSet.add(item);
+}}}};
+var index=0;
+rootValues.visit(function(value){processValue(value,tree.children,new Exhibit.Set(),[index++]);
+});
+this._cache={tree:tree,valueToChildren:valueToChildren,valueToParent:valueToParent,valueToPath:valueToPath,valueType:valueType};
+}};
+Exhibit.HierarchicalFacet.prototype._getTreeNode=function(value){if(value==null){return this._cache.tree;
+}var path=this._cache.valueToPath[value];
+var trace=function(node,path,index){var node2=node.children[path[index]];
+if(++index<path.length){return trace(node2,path,index);
+}else{return node2;
+}};
+return(path)?trace(this._cache.tree,path,0):null;
+};
+
+
+/* image-facet.js */
+Exhibit.ImageFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._settings={};
+this._dom=null;
+};
+Exhibit.ImageFacet._settingSpecs={"facetLabel":{type:"text"},"thumbNail":{type:"uri"},"overlayCounts":{type:"boolean",defaultValue:true},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.ImageFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.ImageFacet(containerElmt,uiContext);
+Exhibit.ImageFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ImageFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.ImageFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ImageFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var imageString=Exhibit.getAttribute(configElmt,"image");
+if(imageString!=null&&imageString.length>0){facet._imageExpression=Exhibit.ExpressionParser.parse(imageString);
+}var tooltipString=Exhibit.getAttribute(configElmt,"tooltip");
+if(tooltipString!=null&&tooltipString.length>0){facet._tooltipExpression=Exhibit.ExpressionParser.parse(tooltipString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"ImageFacet: Error processing configuration of list facet");
+}Exhibit.ImageFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ImageFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ImageFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("image" in configuration){facet._imageExpression=Exhibit.ExpressionParser.parse(configuration.image);
+}if("tooltip" in configuration){facet._tooltipExpression=Exhibit.ExpressionParser.parse(configuration.tooltip);
+}if(!(facet._imageExpression)){facet._imageExpression=Exhibit.ExpressionParser.parse("value");
+}if(!(facet._tooltipExpression)){facet._tooltipExpression=Exhibit.ExpressionParser.parse("value");
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+};
+Exhibit.ImageFacet.prototype.dispose=function(){this._cache.dispose();
+this._cache=null;
+this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+};
+Exhibit.ImageFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.ImageFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.ImageFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.ImageFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.ImageFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.ImageFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set=this._cache.getItemsFromValues(this._valueSet,items);
+if(this._selectMissing){this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.ImageFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._constructBody(this._computeFacet(items));
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.ImageFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var r=this._cache.getValueCountsFromItems(items);
+var entries=r.entries;
+var valueType=r.valueType;
+if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.image=this._imageExpression.evaluateSingleOnItem(entry.value,database).value;
+entry.tooltip=this._tooltipExpression.evaluateSingleOnItem(entry.value,database).value;
+entry.selected=selection.contains(entry.value);
+}entries.sort(this._createSortFunction(valueType));
+}return entries;
+};
+Exhibit.ImageFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.ImageFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.ImageFacet.prototype._constructBody=function(entries){var self=this;
+var shouldOverlayCounts=this._settings.overlayCounts;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var facetHasSelection=this._valueSet.size()>0||this._selectMissing;
+var constructValue=function(entry){var onSelectOnly=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=document.createElement("span");
+var wrapper=document.createElement("div");
+wrapper.className="wrapper";
+var image=document.createElement("img");
+image.src=entry.image;
+wrapper.appendChild(image);
+if(shouldOverlayCounts==true){var countDiv=document.createElement("div");
+countDiv.className="countDiv";
+var countBackground=document.createElement("div");
+countBackground.className="countBackground";
+countDiv.appendChild(countBackground);
+var innerCount=document.createElement("div");
+innerCount.className="text";
+innerCount.innerHTML=entry.count;
+countDiv.appendChild(innerCount);
+wrapper.appendChild(countDiv);
+}elmt.appendChild(wrapper);
+elmt.className=entry.selected?"inline-block exhibit-imageFacet-value exhibit-imageFacet-value-selected":"inline-block exhibit-imageFacet-value";
+elmt.title=entry.count+" "+entry.tooltip;
+SimileAjax.WindowManager.registerEvent(elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+containerDiv.appendChild(elmt);
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._valueSet.size()+(this._selectMissing?1:0));
+};
+Exhibit.ImageFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.ImageFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.ImageFacet.prototype._createSortFunction=function(valueType){var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+
+
+/* list-facet.js */
+Exhibit.ListFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._delayedUpdateItems=null;
+this._settings={};
+this._dom=null;
+};
+Exhibit.ListFacet._settingSpecs={"facetLabel":{type:"text"},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false},"formatter":{type:"text",defaultValue:null}};
+Exhibit.ListFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.ListFacet(containerElmt,uiContext);
+Exhibit.ListFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ListFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.ListFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ListFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"ListFacet: Error processing configuration of list facet");
+}Exhibit.ListFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ListFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ListFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}if("formatter" in facet._settings){var formatter=facet._settings.formatter;
+if(formatter!=null&&formatter.length>0){try{facet._formatter=eval(formatter);
+}catch(e){SimileAjax.Debug.log(e);
+}}}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+};
+Exhibit.ListFacet.prototype.dispose=function(){this._cache.dispose();
+this._cache=null;
+this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+};
+Exhibit.ListFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.ListFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.ListFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.ListFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.ListFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.ListFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set=this._cache.getItemsFromValues(this._valueSet,items);
+if(this._selectMissing){this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.ListFacet.prototype.onUncollapse=function(){if(this._delayedUpdateItems!=null){this.update(this._delayedUpdateItems);
+this._delayedUpdateItems=null;
+}};
+Exhibit.ListFacet.prototype.update=function(items){if(Exhibit.FacetUtilities.isCollapsed(this)){this._delayedUpdateItems=items;
+return ;
+}this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._constructBody(this._computeFacet(items));
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.ListFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var r=this._cache.getValueCountsFromItems(items);
+var entries=r.entries;
+var valueType=r.valueType;
+if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.selected=selection.contains(entry.value);
+}entries.sort(this._createSortFunction(valueType));
+}if(this._settings.showMissing||this._selectMissing){var count=this._cache.countItemsMissingValue(items);
+if(count>0||this._selectMissing){var span=document.createElement("span");
+span.innerHTML=("missingLabel" in this._settings)?this._settings.missingLabel:Exhibit.FacetUtilities.l10n.missingThisField;
+span.className="exhibit-facet-value-missingThisField";
+entries.unshift({value:null,count:count,selected:this._selectMissing,selectionLabel:span,actionLabel:Exhibit.FacetUtilities.l10n.missingThisField});
+}}return entries;
+};
+Exhibit.ListFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.ListFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.ListFacet.prototype._constructBody=function(entries){var self=this;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var facetHasSelection=this._valueSet.size()>0||this._selectMissing;
+var constructValue=function(entry){var onSelect=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(entry.selectionLabel,entry.count,(self._colorCoder!=null)?self._colorCoder.translate(entry.value):null,entry.selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+if(self._formatter){self._formatter(elmt);
+}containerDiv.appendChild(elmt);
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._valueSet.size()+(this._selectMissing?1:0));
+};
+Exhibit.ListFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.ListFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.ListFacet.prototype._createSortFunction=function(valueType){var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+Exhibit.ListFacet.prototype.exportFacetSelection=function(){var s=[];
+this._valueSet.visit(function(v){s.push(v);
+});
+if(s.length>0){return s.join(",");
+}};
+Exhibit.ListFacet.prototype.importFacetSelection=function(settings){var self=this;
+self.applyRestrictions({selection:settings.split(","),selectMissing:self._selectMissing});
+};
+
+
+/* numeric-range-facet.js */
+Exhibit.NumericRangeFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._dom=null;
+this._ranges=[];
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_rangeIndex" in self){delete self._rangeIndex;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.NumericRangeFacet._settingSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"interval":{type:"float",defaultValue:10},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.NumericRangeFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.NumericRangeFacet(containerElmt,uiContext);
+Exhibit.NumericRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.NumericRangeFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.NumericRangeFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.NumericRangeFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}}catch(e){SimileAjax.Debug.exception(e,"NumericRangeFacet: Error processing configuration of numeric range facet");
+}Exhibit.NumericRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.NumericRangeFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.NumericRangeFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.NumericRangeFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._ranges=null;
+};
+Exhibit.NumericRangeFacet.prototype.hasRestrictions=function(){return this._ranges.length>0;
+};
+Exhibit.NumericRangeFacet.prototype.clearAllRestrictions=function(){var restrictions=[];
+if(this._ranges.length>0){restrictions=restrictions.concat(this._ranges);
+this._ranges=[];
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.NumericRangeFacet.prototype.applyRestrictions=function(restrictions){this._ranges=restrictions;
+this._notifyCollection();
+};
+Exhibit.NumericRangeFacet.prototype.setRange=function(from,to,selected){if(selected){for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){return ;
+}}this._ranges.push({from:from,to:to});
+}else{for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){this._ranges.splice(i,1);
+break;
+}}}this._notifyCollection();
+};
+Exhibit.NumericRangeFacet.prototype.restrict=function(items){if(this._ranges.length==0){return items;
+}else{if(this._expression.isPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+set.addSet(path.rangeBackward(range.from,range.to,false,items,database).values);
+}return set;
+}else{this._buildRangeIndex();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+this._rangeIndex.getSubjectsInRange(range.from,range.to,false,set,items);
+}return set;
+}}};
+Exhibit.NumericRangeFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._reconstruct(items);
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.NumericRangeFacet.prototype._reconstruct=function(items){var self=this;
+var ranges=[];
+var rangeIndex;
+var computeItems;
+if(this._expression.isPath()){var database=this._uiContext.getDatabase();
+var path=this._expression.getPath();
+var propertyID=path.getLastSegment().property;
+var property=database.getProperty(propertyID);
+if(property==null){return null;
+}rangeIndex=property.getRangeIndex();
+countItems=function(range){return path.rangeBackward(range.from,range.to,false,items,database).values.size();
+};
+}else{this._buildRangeIndex();
+rangeIndex=this._rangeIndex;
+countItems=function(range){return rangeIndex.getSubjectsInRange(range.from,range.to,false,null,items).size();
+};
+}var min=rangeIndex.getMin();
+var max=rangeIndex.getMax();
+min=Math.floor(min/this._settings.interval)*this._settings.interval;
+max=Math.ceil((max+this._settings.interval)/this._settings.interval)*this._settings.interval;
+for(var x=min;
+x<max;
+x+=this._settings.interval){var range={from:x,to:x+this._settings.interval,selected:false};
+range.count=countItems(range);
+for(var i=0;
+i<this._ranges.length;
+i++){var range2=this._ranges[i];
+if(range2.from==range.from&&range2.to==range.to){range.selected=true;
+facetHasSelection=true;
+break;
+}}ranges.push(range);
+}var facetHasSelection=this._ranges.length>0;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var makeFacetValue=function(from,to,count,selected){var onSelect=function(elmt,evt,target){self._toggleRange(from,to,selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._toggleRange(from,to,selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(from+" - "+to,count,null,selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+containerDiv.appendChild(elmt);
+};
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i];
+if(range.selected||range.count>0){makeFacetValue(range.from,range.to,range.count,range.selected);
+}}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._ranges.length);
+};
+Exhibit.NumericRangeFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.NumericRangeFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.NumericRangeFacet.prototype._toggleRange=function(from,to,wasSelected,singleSelection){var self=this;
+var label=from+" to "+to;
+var wasOnlyThingSelected=(this._ranges.length==1&&wasSelected);
+if(singleSelection&&!wasOnlyThingSelected){var newRestrictions=[{from:from,to:to}];
+var oldRestrictions=[].concat(this._ranges);
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]));
+}else{SimileAjax.History.addLengthyAction(function(){self.setRange(from,to,!wasSelected);
+},function(){self.setRange(from,to,wasSelected);
+},String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+}};
+Exhibit.NumericRangeFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.NumericRangeFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var getter=function(item,f){expression.evaluateOnItem(item,database).values.visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+
+
+/* slider-facet.js */
+Exhibit.SliderFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._selection={min:null,max:null};
+this._range={min:null,max:null};
+this._maxRange={min:null,max:null};
+};
+Exhibit.SliderFacet._settingsSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"precision":{type:"float",defaultValue:1},"histogram":{type:"boolean",defaultValue:true},"height":{type:"int",defaultValue:false},"width":{type:"int",defaultValue:false},"horizontal":{type:"boolean",defaultValue:true},"inputText":{type:"boolean",defaultValue:true},"showMissing":{type:"boolean",defaultValue:true}};
+Exhibit.SliderFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.SliderFacet(containerElmt,uiContext);
+Exhibit.SliderFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.SliderFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.SliderFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SliderFacet._settingsSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var showMissing=Exhibit.getAttribute(configElmt,"showMissing");
+console.log(showMissing);
+if(showMissing!=null&&showMissing.length>0){facet._showMissing=(showMissing=="true");
+}else{facet._showMissing=true;
+}}catch(e){SimileAjax.Debug.exception(e,"SliderFacet: Error processing configuration of slider facet");
+}Exhibit.SliderFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.SliderFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SliderFacet._settingsSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+facet._selection={min:selection[0],max:selection[1]};
+}if("showMissing" in configuration){facet._showMissing=configuration.showMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+facet._maxRange=facet._getMaxRange();
+};
+Exhibit.SliderFacet.prototype._initializeUI=function(){this._dom=SimileAjax.DOM.createDOMFromString(this._div,"<div class='exhibit-facet-header'><span class='exhibit-facet-header-title'>"+this._settings.facetLabel+"</span></div><div class='exhibit-slider' id='slider'></div>");
+this._slider=new Exhibit.SliderFacet.slider(this._dom.slider,this,this._settings.precision,this._settings.horizontal);
+};
+Exhibit.SliderFacet.prototype.hasRestrictions=function(){return(this._range.min&&this._range.min!=this._maxRange.min)||(this._range.max&&this._range.max!=this._maxRange.max);
+};
+Exhibit.SliderFacet.prototype.update=function(items){if(this._settings.histogram){var data=[];
+var n=75;
+var range=(this._maxRange.max-this._maxRange.min)/n;
+var missingCount=0;
+var database=this._uiContext.getDatabase();
+if(this._selectMissing){missingCount=this._cache.getItemsMissingValue(items).size();
+}if(this._expression.isPath()){var path=this._expression.getPath();
+for(var i=0;
+i<n;
+i++){data[i]=path.rangeBackward(this._maxRange.min+i*range,this._maxRange.min+(i+1)*range,false,items,database).values.size()+missingCount;
+}}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+for(var i=0;
+i<n;
+i++){data[i]=rangeIndex.getSubjectsInRange(this._maxRange.min+i*range,this._maxRange.min+(i+1)*range,false,null,items).size()+missingCount;
+}}this._slider.updateHistogram(data);
+}};
+Exhibit.SliderFacet.prototype.restrict=function(items){if(!this.hasRestrictions()){return items;
+}set=new Exhibit.Set();
+if(this._expression.isPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+set=path.rangeBackward(this._range.min,this._range.max,false,items,database).values;
+}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+set=rangeIndex.getSubjectsInRange(this._range.min,this._range.max,false,null,items);
+}if(this._showMissing){console.log("showMissing:true");
+this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.SliderFacet.prototype._getMaxRange=function(){if(this._expression.getPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+var propertyID=path.getLastSegment().property;
+var property=database.getProperty(propertyID);
+var rangeIndex=property.getRangeIndex();
+}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+}return{min:rangeIndex.getMin(),max:rangeIndex.getMax()};
+};
+Exhibit.SliderFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var getter=function(item,f){expression.evaluateOnItem(item,database).values.visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+Exhibit.SliderFacet.prototype.changeRange=function(range){this._range=range;
+this._notifyCollection();
+};
+Exhibit.SliderFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.SliderFacet.prototype.clearAllRestrictions=function(){this._slider.resetSliders();
+this._range=this._maxRange;
+};
+Exhibit.SliderFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._selection=null;
+this._range=null;
+this._maxRange=null;
+};
+
+
+/* slider.js */
+Exhibit.SliderFacet.slider=function(div,facet,precision){this._div=div;
+this._facet=facet;
+this._prec=precision||0.1;
+this._maxRange={min:parseFloat(Exhibit.Util.round(facet._maxRange.min-precision/2,this._prec)),max:parseFloat(Exhibit.Util.round(facet._maxRange.max+precision/2,this._prec))};
+this._horizontal=this._facet._settings.horizontal;
+this._scaleFactor=null;
+this._slider1={};
+this._slider2={};
+this._dom=SimileAjax.DOM.createDOMFromString(div,'<div class="exhibit-slider-bar" id="bar"><div id="slider1"></div><div id="slider2"></div>'+(this._facet._settings.histogram?'<div class="exhibit-slider-histogram" id="histogram"></div>':"")+'</div><div class="exhibit-slider-display">'+(this._facet._settings.inputText?'<input type="text" id="minDisplay"></input> - <input type="text" id="maxDisplay"></input> ':'<span id="minDisplay"></span> - <span id="maxDisplay"></span>')+"</div>");
+var horizontal=this._horizontal;
+var histogram=this._dom.histogram;
+if(horizontal&&histogram){this._dom.bar.style.height="14px";
+this._dom.bar.style.width="150px";
+}else{if(horizontal&&!histogram){this._dom.bar.style.height="1px";
+this._dom.bar.style.width="150px";
+}else{if(!horizontal&&histogram){this._dom.bar.style.height="150px";
+this._dom.bar.style.width="14px";
+}else{this._dom.bar.style.height="150px";
+this._dom.bar.style.width="1px";
+}}}if(this._facet._settings.height){this._dom.bar.style.height=this._facet._settings.height+"px";
+}if(this._facet._settings.width){this._dom.bar.style.width=this._facet._settings.width+"px";
+}if(histogram){this._dom.histogram.style.height=this._dom.bar.offsetHeight;
+this._dom.histogram.style.width=this._dom.bar.offsetWidth;
+}if(horizontal){this._scaleFactor=(this._maxRange.max-this._maxRange.min)/this._dom.bar.offsetWidth;
+}else{this._scaleFactor=(this._maxRange.max-this._maxRange.min)/this._dom.bar.offsetHeight;
+}this._slider1=new Exhibit.SliderFacet.slider.slider(this._dom.slider1,this);
+this._slider2=new Exhibit.SliderFacet.slider.slider(this._dom.slider2,this);
+this._setSlider(this._slider1,this._maxRange.min);
+this._setSlider(this._slider2,this._maxRange.max);
+this._registerDragging();
+if(this._facet._settings.inputText){this._registerInputs();
+}};
+Exhibit.SliderFacet.slider.prototype.resetSliders=function(){this._setSlider(this._slider1,this._maxRange.min);
+this._setSlider(this._slider2,this._maxRange.max);
+};
+Exhibit.SliderFacet.slider.prototype._setSlider=function(slider,value){if(value>this._maxRange.max){value=this._maxRange.max;
+}else{if(value<this._maxRange.min){value=this._maxRange.min;
+}}value=parseFloat(Exhibit.Util.round(value,this._prec));
+slider.value=value;
+if(this._horizontal){slider.div.style.left=((value-this._maxRange.min)/this._scaleFactor-slider.offset)+"px";
+}else{slider.div.style.top=((value-this._maxRange.min)/this._scaleFactor-slider.offset)+"px";
+}this._setDisplays(slider);
+};
+Exhibit.SliderFacet.slider.prototype._setMin=function(value){var slider=this._slider1.value<this._slider2.value?this._slider1:this._slider2;
+var other=(slider==this._slider1)?this._slider2:this._slider1;
+value=parseFloat(value);
+if(isNaN(value)){return ;
+}if(value>other.value){value=other.value;
+}this._setSlider(slider,value);
+};
+Exhibit.SliderFacet.slider.prototype._setMax=function(value){var slider=this._slider1.value>this._slider2.value?this._slider1:this._slider2;
+var other=(slider==this._slider1)?this._slider2:this._slider1;
+value=parseFloat(value);
+if(isNaN(value)){return ;
+}if(value<other.value){value=other.value;
+}this._setSlider(slider,value);
+};
+Exhibit.SliderFacet.slider.prototype._setDisplays=function(slider){var other=(slider==this._slider1)?this._slider2:this._slider1;
+var min=Math.min(slider.value,other.value);
+var max=Math.max(slider.value,other.value);
+if(this._facet._settings.inputText){this._dom.minDisplay.value=min;
+this._dom.maxDisplay.value=max;
+}else{this._dom.minDisplay.innerHTML=min;
+this._dom.maxDisplay.innerHTML=max;
+}};
+Exhibit.SliderFacet.slider.slider=function(div,self){var barEl=self._dom.bar;
+this.div=div;
+if(self._horizontal){this.div.className="exhibit-slider-handle";
+this.div.style.backgroundImage='url("'+Exhibit.urlPrefix+'images/slider-handle.png")';
+this.offset=this.div.offsetWidth/2;
+this.min=-this.offset;
+this.max=barEl.offsetWidth-this.offset;
+}else{this.div.className="exhibit-slider-handle2";
+this.div.style.backgroundImage='url("'+Exhibit.urlPrefix+'images/slider-handle2.png")';
+this.offset=this.div.offsetHeight/2;
+this.min=-this.offset;
+this.max=barEl.offsetHeight-this.offset;
+}if(self._facet._settings.histogram){this.div.style.top=(barEl.offsetHeight-4)+"px";
+}};
+Exhibit.SliderFacet.slider.prototype._registerDragging=function(){var self=this;
+var startDrag=function(slider){return function(e){e=e||window.event;
+var onMove=self._horizontal?onDragH(e,slider):onDragV(e,slider);
+if(document.attachEvent){document.attachEvent("onmousemove",onMove);
+document.attachEvent("onmouseup",endDrag(slider,onMove));
+}else{document.addEventListener("mousemove",onMove,false);
+document.addEventListener("mouseup",endDrag(slider,onMove),false);
+}SimileAjax.DOM.cancelEvent(e);
+return false;
+};
+};
+var onDragH=function(e,slider){var origX=e.screenX;
+var origLeft=parseInt(slider.div.style.left);
+var min=slider.min;
+var max=slider.max;
+return function(e){e=e||window.event;
+var dx=e.screenX-origX;
+var newLeft=origLeft+dx;
+if(newLeft<min){newLeft=min;
+}if(newLeft>max){newLeft=max;
+}slider.div.style.left=newLeft+"px";
+setTimeout(function(){var position=parseInt(slider.div.style.left)+slider.offset;
+slider.value=parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min,self._prec));
+self._setDisplays(slider);
+},0);
+};
+};
+var onDragV=function(e,slider){var origY=e.screenY;
+var origTop=parseInt(slider.div.style.top);
+var min=slider.min;
+var max=slider.max;
+return function(e){e=e||window.event;
+var dy=e.screenY-origY;
+var newTop=origTop+dy;
+if(newTop<min){newTop=min;
+}if(newTop>max){newTop=max;
+}slider.div.style.top=newTop+"px";
+setTimeout(function(){var position=parseInt(slider.div.style.top)+slider.offset;
+slider.value=parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min,self._prec));
+self._setDisplays(slider);
+},0);
+};
+};
+var endDrag=function(slider,moveListener){return function(e){if(document.detachEvent){document.detachEvent("onmousemove",moveListener);
+document.detachEvent("onmouseup",arguments.callee);
+}else{document.removeEventListener("mousemove",moveListener,false);
+document.removeEventListener("mouseup",arguments.callee,false);
+}self._notifyFacet();
+};
+};
+var attachListeners=function(slider){if(document.attachEvent){slider.div.attachEvent("onmousedown",startDrag(slider));
+}else{slider.div.addEventListener("mousedown",startDrag(slider),false);
+}};
+attachListeners(this._slider1);
+attachListeners(this._slider2);
+};
+Exhibit.SliderFacet.slider.prototype._notifyFacet=function(){var val1=this._slider1.value;
+var val2=this._slider2.value;
+this._facet.changeRange({min:Math.min(val1,val2),max:Math.max(val1,val2)});
+};
+Exhibit.SliderFacet.slider.prototype.updateHistogram=function(data){var n=data.length;
+var histogram=this._dom.histogram;
+var maxVal=Math.max.apply(Math,data);
+if(!maxVal){return ;
+}if(this._horizontal){var width=histogram.offsetWidth/n;
+var maxHeight=histogram.offsetHeight;
+var ratio=maxHeight/maxVal;
+histogram.innerHTML="";
+for(var i=0;
+i<n;
+i++){var height=Math.round(data[i]*ratio);
+var bar=document.createElement("div");
+histogram.appendChild(bar);
+bar.style.width=width+"px";
+bar.style.height=height+"px";
+bar.style.display=height?"":"none";
+bar.style.position="absolute";
+bar.style.top=(maxHeight-height)+"px";
+bar.style.left=i*width+"px";
+}}else{var width=histogram.offsetHeight/n;
+var maxHeight=histogram.offsetWidth;
+var ratio=maxHeight/maxVal;
+histogram.innerHTML="";
+for(var i=0;
+i<n;
+i++){var height=Math.round(data[i]*ratio);
+var bar=document.createElement("div");
+bar.style.height=width;
+bar.style.width=height;
+bar.style.position="absolute";
+bar.style.left=0;
+bar.style.top=i*width;
+histogram.appendChild(bar);
+}}};
+Exhibit.SliderFacet.slider.prototype._registerInputs=function(){var self=this;
+if(document.attachEvent){this._dom.minDisplay.attachEvent("onchange",function(e){self._setMin(this.value);
+self._notifyFacet();
+});
+this._dom.maxDisplay.attachEvent("onchange",function(e){self._setMax(this.value);
+self._notifyFacet();
+});
+}else{this._dom.minDisplay.addEventListener("change",function(e){self._setMin(this.value);
+self._notifyFacet();
+},false);
+this._dom.maxDisplay.addEventListener("change",function(e){self._setMax(this.value);
+self._notifyFacet();
+},false);
+}};
+
+
+/* text-search-facet.js */
+Exhibit.TextSearchFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expressions=[];
+this._text=null;
+this._settings={};
+this._dom=null;
+this._timerID=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.TextSearchFacet._settingSpecs={"facetLabel":{type:"text"},"queryParamName":{type:"text"},"requiresEnter":{type:"boolean",defaultValue:false}};
+Exhibit.TextSearchFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.TextSearchFacet(containerElmt,uiContext);
+Exhibit.TextSearchFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.TextSearchFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.TextSearchFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TextSearchFacet._settingSpecs,facet._settings);
+try{var s=Exhibit.getAttribute(configElmt,"expressions");
+if(s!=null&&s.length>0){facet._expressions=Exhibit.ExpressionParser.parseSeveral(s);
+}var query=Exhibit.getAttribute(configElmt,"query");
+if(query!=null&&query.length>0){facet._text=query;
+}}catch(e){SimileAjax.Debug.exception(e,"TextSearchFacet: Error processing configuration of list facet");
+}Exhibit.TextSearchFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.TextSearchFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TextSearchFacet._settingSpecs,facet._settings);
+if("expressions" in configuration){for(var i=0;
+i<configuration.expressions.length;
+i++){facet._expressions.push(Exhibit.ExpressionParser.parse(configuration.expressions[i]));
+}}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("query" in configuration){facet._text=configuration.query;
+}if("queryParamName" in facet._settings){var params=SimileAjax.parseURLParameters();
+if(facet._settings["queryParamName"] in params){facet._text=params[facet._settings["queryParamName"]];
+}}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="";
+}};
+Exhibit.TextSearchFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expressions=null;
+this._itemToValue=null;
+this._settings=null;
+};
+Exhibit.TextSearchFacet.prototype.hasRestrictions=function(){return this._text!=null;
+};
+Exhibit.TextSearchFacet.prototype.clearAllRestrictions=function(){var restrictions=this._text;
+if(this._text!=null){this._text=null;
+this._notifyCollection();
+}this._dom.input.value="";
+return restrictions;
+};
+Exhibit.TextSearchFacet.prototype.applyRestrictions=function(restrictions){this.setText(restrictions);
+};
+Exhibit.TextSearchFacet.prototype.setText=function(text){if(text!=null){text=text.trim();
+this._dom.input.value=text;
+text=text.length>0?text:null;
+}else{this._dom.input.value="";
+}if(text!=this._text){this._text=text;
+this._notifyCollection();
+}};
+Exhibit.TextSearchFacet.prototype.restrict=function(items){if(this._text==null){return items;
+}else{this._buildMaps();
+var set=new Exhibit.Set();
+var itemToValue=this._itemToValue;
+var text=this._text.toLowerCase();
+items.visit(function(item){if(item in itemToValue){var values=itemToValue[item];
+for(var v=0;
+v<values.length;
+v++){if(values[v].indexOf(text)>=0){set.add(item);
+break;
+}}}});
+return set;
+}};
+Exhibit.TextSearchFacet.prototype.update=function(items){};
+Exhibit.TextSearchFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.TextSearchFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.TextSearchFacet.constructFacetFrame(this._div,this._settings.facetLabel);
+if(this._text!=null){this._dom.input.value=this._text;
+}SimileAjax.WindowManager.registerEvent(this._dom.input,"keyup",function(elmt,evt,target){self._onTextInputKeyUp(evt);
+});
+};
+Exhibit.TextSearchFacet.constructFacetFrame=function(div,facetLabel){if(facetLabel!==""&&facetLabel!==null){return SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-facet-header'><span class='exhibit-facet-header-title'>"+facetLabel+"</span></div><div class='exhibit-text-facet'><input type='text' id='input'></div>");
+}else{return SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-text-facet'><input type='text' id='input'></div>");
+}};
+Exhibit.TextSearchFacet.prototype._onTextInputKeyUp=function(evt){if(this._timerID!=null){window.clearTimeout(this._timerID);
+}var self=this;
+if(this._settings.requiresEnter==false){this._timerID=window.setTimeout(function(){self._onTimeout();
+},500);
+}else{var newText=this._dom.input.value.trim();
+if(newText.length==0||evt.keyCode==13){this._timerID=window.setTimeout(function(){self._onTimeout();
+},0);
+}}};
+Exhibit.TextSearchFacet.prototype._onTimeout=function(){this._timerID=null;
+var newText=this._dom.input.value.trim();
+if(newText.length==0){newText=null;
+}if(newText!=this._text){var self=this;
+var oldText=this._text;
+SimileAjax.History.addLengthyAction(function(){self.setText(newText);
+},function(){self.setText(oldText);
+},newText!=null?String.substitute(Exhibit.FacetUtilities.l10n["facetTextSearchActionTitle"],[newText]):Exhibit.FacetUtilities.l10n["facetClearTextSearchActionTitle"]);
+}};
+Exhibit.TextSearchFacet.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var allItems=this._uiContext.getCollection().getAllItems();
+var database=this._uiContext.getDatabase();
+if(this._expressions.length>0){var expressions=this._expressions;
+allItems.visit(function(item){var values=[];
+for(var x=0;
+x<expressions.length;
+x++){var expression=expressions[x];
+expression.evaluateOnItem(item,database).values.visit(function(v){values.push(v.toLowerCase());
+});
+}itemToValue[item]=values;
+});
+}else{var propertyIDs=database.getAllProperties();
+allItems.visit(function(item){var values=[];
+for(var p=0;
+p<propertyIDs.length;
+p++){database.getObjects(item,propertyIDs[p]).visit(function(v){values.push(v.toLowerCase());
+});
+}itemToValue[item]=values;
+});
+}this._itemToValue=itemToValue;
+}};
+Exhibit.TextSearchFacet.prototype.exportFacetSelection=function(){return this._text;
+};
+Exhibit.TextSearchFacet.prototype.importFacetSelection=function(settings){this.setText(settings);
+};
+
+
+/* format-parser.js */
+Exhibit.FormatParser=new Object();
+Exhibit.FormatParser.parse=function(uiContext,s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.FormatScanner(s,startIndex);
+try{return Exhibit.FormatParser._internalParse(uiContext,scanner,results,false);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.FormatParser.parseSeveral=function(uiContext,s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.FormatScanner(s,startIndex);
+try{return Exhibit.FormatParser._internalParse(uiContext,scanner,results,true);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.FormatParser._valueTypes={"list":true,"number":true,"date":true,"item":true,"text":true,"url":true,"image":true,"currency":true};
+Exhibit.FormatParser._internalParse=function(uiContext,scanner,results,several){var Scanner=Exhibit.FormatScanner;
+var token=scanner.token();
+var next=function(){scanner.next();
+token=scanner.token();
+};
+var makePosition=function(){return token!=null?token.start:scanner.index();
+};
+var enterSetting=function(valueType,settingName,value){uiContext.putSetting("format/"+valueType+"/"+settingName,value);
+};
+var checkKeywords=function(valueType,settingName,keywords){if(token!=null&&token.type!=Scanner.IDENTIFIER&&token.value in keywords){enterSetting(valueType,settingName,keywords[token.value]);
+next();
+return false;
+}return true;
+};
+var parseNumber=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER){throw new Error("Missing number at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseInteger=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER){throw new Error("Missing integer at position "+makePosition());
+}enterSetting(valueType,settingName,Math.round(token.value));
+next();
+}};
+var parseNonnegativeInteger=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER||token.value<0){throw new Error("Missing non-negative integer at position "+makePosition());
+}enterSetting(valueType,settingName,Math.round(token.value));
+next();
+}};
+var parseString=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.STRING){throw new Error("Missing string at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseURL=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.URL){throw new Error("Missing url at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseExpression=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.EXPRESSION){throw new Error("Missing expression at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseExpressionOrString=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||(token.type!=Scanner.EXPRESSION&&token.type!=Scanner.STRING)){throw new Error("Missing expression or string at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseChoices=function(valueType,settingName,choices){if(token==null||token.type!=Scanner.IDENTIFIER){throw new Error("Missing option at position "+makePosition());
+}for(var i=0;
+i<choices.length;
+i++){if(token.value==choices[i]){enterSetting(valueType,settingName,token.value);
+next();
+return ;
+}}throw new Error("Unsupported option "+token.value+" for setting "+settingName+" on value type "+valueType+" found at position "+makePosition());
+};
+var parseFlags=function(valueType,settingName,flags,counterFlags){outer:while(token!=null&&token.type==Scanner.IDENTIFIER){for(var i=0;
+i<flags.length;
+i++){if(token.value==flags[i]){enterSetting(valueType,settingName+"/"+token.value,true);
+next();
+continue outer;
+}}if(token.value in counterFlags){enterSetting(valueType,settingName+"/"+counterFlags[token.value],false);
+next();
+continue outer;
+}throw new Error("Unsupported flag "+token.value+" for setting "+settingName+" on value type "+valueType+" found at position "+makePosition());
+}};
+var parseSetting=function(valueType,settingName){switch(valueType){case"number":switch(settingName){case"decimal-digits":parseNonnegativeInteger(valueType,settingName,{"default":-1});
+return ;
+}break;
+case"date":switch(settingName){case"time-zone":parseNumber(valueType,settingName,{"default":null});
+return ;
+case"show":parseChoices(valueType,settingName,["date","time","date-time"]);
+return ;
+case"mode":parseChoices(valueType,settingName,["short","medium","long","full"]);
+enterSetting(valueType,"template",null);
+return ;
+case"template":parseString(valueType,settingName,{});
+enterSetting(valueType,"mode",null);
+return ;
+}break;
+case"boolean":switch(settingName){}break;
+case"text":switch(settingName){case"max-length":parseInteger(valueType,settingName,{"none":0});
+return ;
+}break;
+case"image":switch(settingName){case"tooltip":parseExpressionOrString(valueType,settingName,{"none":null});
+return ;
+case"max-width":case"max-height":parseInteger(valueType,settingName,{"none":-1});
+return ;
+}break;
+case"url":switch(settingName){case"target":parseString(valueType,settingName,{"none":null});
+return ;
+case"external-icon":parseURL(valueType,settingName,{"none":null});
+return ;
+}break;
+case"item":switch(settingName){case"title":parseExpression(valueType,settingName,{"default":null});
+return ;
+}break;
+case"currency":switch(settingName){case"negative-format":parseFlags(valueType,settingName,["red","parentheses","signed"],{"unsigned":"signed","no-parenthesis":"parentheses","black":"red"});
+return ;
+case"symbol":parseString(valueType,settingName,{"default":"$","none":null});
+return ;
+case"symbol-placement":parseChoices(valueType,settingName,["first","last","after-sign"]);
+return ;
+case"decimal-digits":parseNonnegativeInteger(valueType,settingName,{"default":-1});
+return ;
+}break;
+case"list":switch(settingName){case"separator":case"last-separator":case"pair-separator":case"empty-text":parseString(valueType,settingName,{});
+return ;
+}break;
+}throw new Error("Unsupported setting called "+settingName+" for value type "+valueType+" found at position "+makePosition());
+};
+var parseSettingList=function(valueType){while(token!=null&&token.type==Scanner.IDENTIFIER){var settingName=token.value;
+next();
+if(token==null||token.type!=Scanner.DELIMITER||token.value!=":"){throw new Error("Missing : at position "+makePosition());
+}next();
+parseSetting(valueType,settingName);
+if(token==null||token.type!=Scanner.DELIMITER||token.value!=";"){break;
+}else{next();
+}}};
+var parseRule=function(){if(token==null||token.type!=Scanner.IDENTIFIER){throw new Error("Missing value type at position "+makePosition());
+}var valueType=token.value;
+if(!(valueType in Exhibit.FormatParser._valueTypes)){throw new Error("Unsupported value type "+valueType+" at position "+makePosition());
+}next();
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="{"){next();
+parseSettingList(valueType);
+if(token==null||token.type!=Scanner.DELIMITER||token.value!="}"){throw new Error("Missing } at position "+makePosition());
+}next();
+}return valueType;
+};
+var parseRuleList=function(){var valueType="text";
+while(token!=null&&token.type==Scanner.IDENTIFIER){valueType=parseRule();
+}return valueType;
+};
+if(several){return parseRuleList();
+}else{return parseRule();
+}};
+Exhibit.FormatScanner=function(text,startIndex){this._text=text+" ";
+this._maxIndex=text.length;
+this._index=startIndex;
+this.next();
+};
+Exhibit.FormatScanner.DELIMITER=0;
+Exhibit.FormatScanner.NUMBER=1;
+Exhibit.FormatScanner.STRING=2;
+Exhibit.FormatScanner.IDENTIFIER=3;
+Exhibit.FormatScanner.URL=4;
+Exhibit.FormatScanner.EXPRESSION=5;
+Exhibit.FormatScanner.COLOR=6;
+Exhibit.FormatScanner.prototype.token=function(){return this._token;
+};
+Exhibit.FormatScanner.prototype.index=function(){return this._index;
+};
+Exhibit.FormatScanner.prototype.next=function(){this._token=null;
+var self=this;
+var skipSpaces=function(x){while(x<self._maxIndex&&" \t\r\n".indexOf(self._text.charAt(x))>=0){x++;
+}return x;
+};
+this._index=skipSpaces(this._index);
+if(this._index<this._maxIndex){var c1=this._text.charAt(this._index);
+var c2=this._text.charAt(this._index+1);
+if("{}(),:;".indexOf(c1)>=0){this._token={type:Exhibit.FormatScanner.DELIMITER,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("\"'".indexOf(c1)>=0){var i=this._index+1;
+while(i<this._maxIndex){if(this._text.charAt(i)==c1&&this._text.charAt(i-1)!="\\"){break;
+}i++;
+}if(i<this._maxIndex){this._token={type:Exhibit.FormatScanner.STRING,value:this._text.substring(this._index+1,i).replace(/\\'/g,"'").replace(/\\"/g,'"'),start:this._index,end:i+1};
+this._index=i+1;
+}else{throw new Error("Unterminated string starting at "+this._index);
+}}else{if(c1=="#"){var i=this._index+1;
+while(i<this._maxIndex&&this._isHexDigit(this._text.charAt(i))){i++;
+}this._token={type:Exhibit.FormatScanner.COLOR,value:this._text.substring(this._index,i),start:this._index,end:i};
+this._index=i;
+}else{if(this._isDigit(c1)){var i=this._index;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}if(i<this._maxIndex&&this._text.charAt(i)=="."){i++;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}}this._token={type:Exhibit.FormatScanner.NUMBER,value:parseFloat(this._text.substring(this._index,i)),start:this._index,end:i};
+this._index=i;
+}else{var i=this._index;
+while(i<this._maxIndex){var j=this._text.substr(i).search(/\W/);
+if(j>0){i+=j;
+}else{if("-".indexOf(this._text.charAt(i))>=0){i++;
+}else{break;
+}}}var identifier=this._text.substring(this._index,i);
+while(true){if(identifier=="url"){var openParen=skipSpaces(i);
+if(this._text.charAt(openParen)=="("){var closeParen=this._text.indexOf(")",openParen);
+if(closeParen>0){this._token={type:Exhibit.FormatScanner.URL,value:this._text.substring(openParen+1,closeParen),start:this._index,end:closeParen+1};
+this._index=closeParen+1;
+break;
+}else{throw new Error("Missing ) to close url at "+this._index);
+}}}else{if(identifier=="expression"){var openParen=skipSpaces(i);
+if(this._text.charAt(openParen)=="("){var o={};
+var expression=Exhibit.ExpressionParser.parse(this._text,openParen+1,o);
+var closeParen=skipSpaces(o.index);
+if(this._text.charAt(closeParen)==")"){this._token={type:Exhibit.FormatScanner.EXPRESSION,value:expression,start:this._index,end:closeParen+1};
+this._index=closeParen+1;
+break;
+}else{throw new Error("Missing ) to close expression at "+o.index);
+}}}}this._token={type:Exhibit.FormatScanner.IDENTIFIER,value:identifier,start:this._index,end:i};
+this._index=i;
+break;
+}}}}}}};
+Exhibit.FormatScanner.prototype._isDigit=function(c){return"0123456789".indexOf(c)>=0;
+};
+Exhibit.FormatScanner.prototype._isHexDigit=function(c){return"0123456789abcdefABCDEF".indexOf(c)>=0;
+};
+
+
+/* formatter.js */
+Exhibit.Formatter=new Object();
+Exhibit.Formatter.createListDelimiter=function(parentElmt,count,uiContext){var separator=uiContext.getSetting("format/list/separator");
+var lastSeparator=uiContext.getSetting("format/list/last-separator");
+var pairSeparator=uiContext.getSetting("format/list/pair-separator");
+if(typeof separator!="string"){separator=Exhibit.Formatter.l10n.listSeparator;
+}if(typeof lastSeparator!="string"){lastSeparator=Exhibit.Formatter.l10n.listLastSeparator;
+}if(typeof pairSeparator!="string"){pairSeparator=Exhibit.Formatter.l10n.listPairSeparator;
+}var f=function(){if(f.index>0&&f.index<count){if(count>2){parentElmt.appendChild(document.createTextNode((f.index==count-1)?lastSeparator:separator));
+}else{parentElmt.appendChild(document.createTextNode(pairSeparator));
+}}f.index++;
+};
+f.index=0;
+return f;
+};
+Exhibit.Formatter._lessThanRegex=/</g;
+Exhibit.Formatter._greaterThanRegex=/>/g;
+Exhibit.Formatter.encodeAngleBrackets=function(s){return s.replace(Exhibit.Formatter._lessThanRegex,"&lt;").replace(Exhibit.Formatter._greaterThanRegex,"&gt;");
+};
+Exhibit.Formatter._ListFormatter=function(uiContext){this._uiContext=uiContext;
+this._separator=uiContext.getSetting("format/list/separator");
+this._lastSeparator=uiContext.getSetting("format/list/last-separator");
+this._pairSeparator=uiContext.getSetting("format/list/pair-separator");
+this._emptyText=uiContext.getSetting("format/list/empty-text");
+if(typeof this._separator!="string"){this._separator=Exhibit.Formatter.l10n.listSeparator;
+}if(typeof this._lastSeparator!="string"){this._lastSeparator=Exhibit.Formatter.l10n.listLastSeparator;
+}if(typeof this._pairSeparator!="string"){this._pairSeparator=Exhibit.Formatter.l10n.listPairSeparator;
+}};
+Exhibit.Formatter._ListFormatter.prototype.formatList=function(values,count,valueType,appender){var uiContext=this._uiContext;
+var self=this;
+if(count==0){if(this._emptyText!=null&&this._emptyText.length>0){appender(document.createTextNode(this._emptyText));
+}}else{if(count==1){values.visit(function(v){uiContext.format(v,valueType,appender);
+});
+}else{var index=0;
+if(count==2){values.visit(function(v){uiContext.format(v,valueType,appender);
+index++;
+if(index==1){appender(document.createTextNode(self._pairSeparator));
+}});
+}else{values.visit(function(v){uiContext.format(v,valueType,appender);
+index++;
+if(index<count){appender(document.createTextNode((index==count-1)?self._lastSeparator:self._separator));
+}});
+}}}};
+Exhibit.Formatter._TextFormatter=function(uiContext){this._maxLength=uiContext.getSetting("format/text/max-length");
+if(typeof this._maxLength=="number"){this._maxLength=Math.max(3,Math.round(this._maxLength));
+}else{this._maxLength=0;
+}};
+Exhibit.Formatter._TextFormatter.prototype.format=function(value,appender){var span=document.createElement("span");
+span.innerHTML=this.formatText(value);
+appender(span);
+};
+Exhibit.Formatter._TextFormatter.prototype.formatText=function(value){if(Exhibit.params.safe){value=Exhibit.Formatter.encodeAngleBrackets(value);
+}if(this._maxLength==0||value.length<=this._maxLength){return value;
+}else{return value.substr(0,this._maxLength)+Exhibit.Formatter.l10n.textEllipsis;
+}};
+Exhibit.Formatter._BooleanFormatter=function(uiContext){};
+Exhibit.Formatter._BooleanFormatter.prototype.format=function(value,appender){var span=document.createElement("span");
+span.innerHTML=this.formatText(value);
+appender(span);
+};
+Exhibit.Formatter._BooleanFormatter.prototype.formatText=function(value){return(typeof value=="boolean"?value:(typeof value=="string"?(value=="true"):false))?Exhibit.Formatter.l10n.booleanTrue:Exhibit.Formatter.l10n.booleanFalse;
+};
+Exhibit.Formatter._NumberFormatter=function(uiContext){this._decimalDigits=uiContext.getSetting("format/number/decimal-digits");
+if(typeof this._decimalDigits=="number"){this._decimalDigits=Math.max(-1,Math.round(this._decimalDigits));
+}else{this._decimalDigits=-1;
+}};
+Exhibit.Formatter._NumberFormatter.prototype.format=function(value,appender){appender(document.createTextNode(this.formatText(value)));
+};
+Exhibit.Formatter._NumberFormatter.prototype.formatText=function(value){if(this._decimalDigits==-1){return value.toString();
+}else{return new Number(value).toFixed(this._decimalDigits);
+}};
+Exhibit.Formatter._ImageFormatter=function(uiContext){this._uiContext=uiContext;
+this._maxWidth=uiContext.getSetting("format/image/max-width");
+if(typeof this._maxWidth=="number"){this._maxWidth=Math.max(-1,Math.round(this._maxWidth));
+}else{this._maxWidth=-1;
+}this._maxHeight=uiContext.getSetting("format/image/max-height");
+if(typeof this._maxHeight=="number"){this._maxHeight=Math.max(-1,Math.round(this._maxHeight));
+}else{this._maxHeight=-1;
+}this._tooltip=uiContext.getSetting("format/image/tooltip");
+};
+Exhibit.Formatter._ImageFormatter.prototype.format=function(value,appender){if(Exhibit.params.safe){value=value.trim().startsWith("javascript:")?"":value;
+}var img=document.createElement("img");
+img.src=value;
+if(this._tooltip!=null){if(typeof this._tooltip=="string"){img.title=this._tootlip;
+}else{img.title=this._tooltip.evaluateSingleOnItem(this._uiContext.getSetting("itemID"),this._uiContext.getDatabase()).value;
+}}appender(img);
+};
+Exhibit.Formatter._ImageFormatter.prototype.formatText=function(value){return value;
+};
+Exhibit.Formatter._URLFormatter=function(uiContext){this._target=uiContext.getSetting("format/url/target");
+this._externalIcon=uiContext.getSetting("format/url/external-icon");
+};
+Exhibit.Formatter._URLFormatter.prototype.format=function(value,appender){var a=document.createElement("a");
+a.href=value;
+a.innerHTML=value;
+if(this._target!=null){a.target=this._target;
+}if(this._externalIcon!=null){}appender(a);
+};
+Exhibit.Formatter._URLFormatter.prototype.formatText=function(value){if(Exhibit.params.safe){value=value.trim().startsWith("javascript:")?"":value;
+}return value;
+};
+Exhibit.Formatter._CurrencyFormatter=function(uiContext){this._decimalDigits=uiContext.getSetting("format/currency/decimal-digits");
+if(typeof this._decimalDigits=="number"){this._decimalDigits=Math.max(-1,Math.round(this._decimalDigits));
+}else{this._decimalDigits=2;
+}this._symbol=uiContext.getSetting("format/currency/symbol");
+if(this._symbol==null){this._symbol=Exhibit.Formatter.l10n.currencySymbol;
+}this._symbolPlacement=uiContext.getSetting("format/currency/symbol-placement");
+if(this._symbolPlacement==null){this._symbol=Exhibit.Formatter.l10n.currencySymbolPlacement;
+}this._negativeFormat={signed:uiContext.getBooleanSetting("format/currency/negative-format/signed",Exhibit.Formatter.l10n.currencyShowSign),red:uiContext.getBooleanSetting("format/currency/negative-format/red",Exhibit.Formatter.l10n.currencyShowRed),parentheses:uiContext.getBooleanSetting("format/currency/negative-format/parentheses",Exhibit.Formatter.l10n.currencyShowParentheses)};
+};
+Exhibit.Formatter._CurrencyFormatter.prototype.format=function(value,appender){var text=this.formatText(value);
+if(value<0&&this._negativeFormat.red){var span=document.createElement("span");
+span.innerHTML=text;
+span.style.color="red";
+appender(span);
+}else{appender(document.createTextNode(text));
+}};
+Exhibit.Formatter._CurrencyFormatter.prototype.formatText=function(value){var negative=value<0;
+var text;
+if(this._decimalDigits==-1){text=Math.abs(value);
+}else{text=new Number(Math.abs(value)).toFixed(this._decimalDigits);
+}var sign=(negative&&this._negativeFormat.signed)?"-":"";
+if(negative&&this._negativeFormat.parentheses){text="("+text+")";
+}switch(this._negativeFormat){case"first":text=this._symbol+sign+text;
+break;
+case"after-sign":text=sign+this._symbol+text;
+break;
+case"last":text=sign+text+this._symbol;
+break;
+}return text;
+};
+Exhibit.Formatter._ItemFormatter=function(uiContext){this._uiContext=uiContext;
+this._title=uiContext.getSetting("format/item/title");
+};
+Exhibit.Formatter._ItemFormatter.prototype.format=function(value,appender){var self=this;
+var title=this.formatText(value);
+var a=SimileAjax.DOM.createElementFromString('<a href="'+Exhibit.Persistence.getItemLink(value)+"\" class='exhibit-item'>"+title+"</a>");
+var handler=function(elmt,evt,target){Exhibit.UI.showItemInPopup(value,elmt,self._uiContext);
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler,this._uiContext.getSetting("layer"));
+appender(a);
+};
+Exhibit.Formatter._ItemFormatter.prototype.formatText=function(value){var database=this._uiContext.getDatabase();
+var title=null;
+if(this._title==null){title=database.getObject(value,"label");
+}else{title=this._title.evaluateSingleOnItem(value,database).value;
+}if(title==null){title=value;
+}return title;
+};
+Exhibit.Formatter._DateFormatter=function(uiContext){this._timeZone=uiContext.getSetting("format/date/time-zone");
+if(!(typeof this._timeZone=="number")){this._timeZone=-(new Date().getTimezoneOffset())/60;
+}this._timeZoneOffset=this._timeZone*3600000;
+var mode=uiContext.getSetting("format/date/mode");
+var show=uiContext.getSetting("format/date/show");
+var template=null;
+switch(mode){case"short":template=show=="date"?Exhibit.Formatter.l10n.dateShortFormat:(show=="time"?Exhibit.Formatter.l10n.timeShortFormat:Exhibit.Formatter.l10n.dateTimeShortFormat);
+break;
+case"medium":template=show=="date"?Exhibit.Formatter.l10n.dateMediumFormat:(show=="time"?Exhibit.Formatter.l10n.timeMediumFormat:Exhibit.Formatter.l10n.dateTimeMediumFormat);
+break;
+case"long":template=show=="date"?Exhibit.Formatter.l10n.dateLongFormat:(show=="time"?Exhibit.Formatter.l10n.timeLongFormat:Exhibit.Formatter.l10n.dateTimeLongFormat);
+break;
+case"full":template=show=="date"?Exhibit.Formatter.l10n.dateFullFormat:(show=="time"?Exhibit.Formatter.l10n.timeFullFormat:Exhibit.Formatter.l10n.dateTimeFullFormat);
+break;
+default:template=uiContext.getSetting("format/date/template");
+}if(typeof template!="string"){template=Exhibit.Formatter.l10n.dateTimeDefaultFormat;
+}var segments=[];
+var placeholders=template.match(/\b\w+\b/g);
+var startIndex=0;
+for(var p=0;
+p<placeholders.length;
+p++){var placeholder=placeholders[p];
+var index=template.indexOf(placeholder,startIndex);
+if(index>startIndex){segments.push(template.substring(startIndex,index));
+}var retriever=Exhibit.Formatter._DateFormatter._retrievers[placeholder];
+if(typeof retriever=="function"){segments.push(retriever);
+}else{segments.push(placeholder);
+}startIndex=index+placeholder.length;
+}if(startIndex<template.length){segments.push(template.substr(startIndex));
+}this._segments=segments;
+};
+Exhibit.Formatter._DateFormatter.prototype.format=function(value,appender){appender(document.createTextNode(this.formatText(value)));
+};
+Exhibit.Formatter._DateFormatter.prototype.formatText=function(value){var date=(value instanceof Date)?value:SimileAjax.DateTime.parseIso8601DateTime(value);
+if(date==null){return value;
+}date.setTime(date.getTime()+this._timeZoneOffset);
+var text="";
+var segments=this._segments;
+for(var i=0;
+i<segments.length;
+i++){var segment=segments[i];
+if(typeof segment=="string"){text+=segment;
+}else{text+=segment(date);
+}}return text;
+};
+Exhibit.Formatter._DateFormatter._pad=function(n){return n<10?("0"+n):n.toString();
+};
+Exhibit.Formatter._DateFormatter._pad3=function(n){return n<10?("00"+n):(n<100?("0"+n):n.toString());
+};
+Exhibit.Formatter._DateFormatter._retrievers={"d":function(date){return date.getUTCDate().toString();
+},"dd":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCDate());
+},"EEE":function(date){return Exhibit.Formatter.l10n.shortDaysOfWeek[date.getUTCDay()];
+},"EEEE":function(date){return Exhibit.Formatter.l10n.daysOfWeek[date.getUTCDay()];
+},"MM":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCMonth()+1);
+},"MMM":function(date){return Exhibit.Formatter.l10n.shortMonths[date.getUTCMonth()];
+},"MMMM":function(date){return Exhibit.Formatter.l10n.months[date.getUTCMonth()];
+},"yy":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCFullYear()%100);
+},"yyyy":function(date){var y=date.getUTCFullYear();
+return y>0?y.toString():(1-y);
+},"G":function(date){var y=date.getUTCYear();
+return y>0?Exhibit.Formatter.l10n.commonEra:Exhibit.Formatter.l10n.beforeCommonEra;
+},"HH":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCHours());
+},"hh":function(date){var h=date.getUTCHours();
+return Exhibit.Formatter._DateFormatter._pad(h==0?12:(h>12?h-12:h));
+},"h":function(date){var h=date.getUTCHours();
+return(h==0?12:(h>12?h-12:h)).toString();
+},"a":function(date){return date.getUTCHours()<12?Exhibit.Formatter.l10n.beforeNoon:Exhibit.Formatter.l10n.afterNoon;
+},"A":function(date){return date.getUTCHours()<12?Exhibit.Formatter.l10n.BeforeNoon:Exhibit.Formatter.l10n.AfterNoon;
+},"mm":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCMinutes());
+},"ss":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCSeconds());
+},"S":function(date){return Exhibit.Formatter._DateFormatter._pad3(date.getUTCMilliseconds());
+}};
+Exhibit.Formatter._constructors={"number":Exhibit.Formatter._NumberFormatter,"date":Exhibit.Formatter._DateFormatter,"text":Exhibit.Formatter._TextFormatter,"boolean":Exhibit.Formatter._BooleanFormatter,"image":Exhibit.Formatter._ImageFormatter,"url":Exhibit.Formatter._URLFormatter,"item":Exhibit.Formatter._ItemFormatter,"currency":Exhibit.Formatter._CurrencyFormatter};
+
+
+/* lens.js */
+Exhibit.LensRegistry=function(parentRegistry){this._parentRegistry=parentRegistry;
+this._defaultLens=null;
+this._typeToLens={};
+this._editLensTemplates={};
+this._submissionLensTemplates={};
+this._lensSelectors=[];
+};
+Exhibit.LensRegistry.prototype.registerDefaultLens=function(elmtOrURL){this._defaultLens=(typeof elmtOrURL=="string")?elmtOrURL:elmtOrURL.cloneNode(true);
+};
+Exhibit.LensRegistry.prototype.registerLensForType=function(elmtOrURL,type){if(typeof elmtOrURL=="string"){this._typeToLens[type]=elmtOrURL;
+}var role=Exhibit.getRoleAttribute(elmtOrURL);
+if(role=="lens"){this._typeToLens[type]=elmtOrURL.cloneNode(true);
+}else{if(role=="edit-lens"){this._editLensTemplates[type]=elmtOrURL.cloneNode(true);
+}else{if(role=="submission-lens"){this._submissionLensTemplates[type]=elmtOrURL.cloneNode(true);
+}else{SimileAjax.Debug.warn("Unknown lens type "+elmtOrURL);
+}}}};
+Exhibit.LensRegistry.prototype.addLensSelector=function(lensSelector){this._lensSelectors.unshift(lensSelector);
+};
+Exhibit.LensRegistry.prototype.getLens=function(itemID,uiContext){return uiContext.isBeingEdited(itemID)?this.getEditLens(itemID,uiContext):this.getNormalLens(itemID,uiContext);
+};
+Exhibit.LensRegistry.prototype.getNormalLens=function(itemID,uiContext){var db=uiContext.getDatabase();
+for(var i=0;
+i<this._lensSelectors.length;
+i++){var lens=this._lensSelectors[i](itemID,db);
+if(lens!=null){return lens;
+}}var type=db.getObject(itemID,"type");
+if(type in this._typeToLens){return this._typeToLens[type];
+}if(this._defaultLens!=null){return this._defaultLens;
+}if(this._parentRegistry){return this._parentRegistry.getLens(itemID,uiContext);
+}return null;
+};
+Exhibit.LensRegistry.prototype.getEditLens=function(itemID,uiContext){var type=uiContext.getDatabase().getObject(itemID,"type");
+if(type in this._editLensTemplates){return this._editLensTemplates[type];
+}else{return this._parentRegistry&&this._parentRegistry.getEditLens(itemID,uiContext);
+}};
+Exhibit.LensRegistry.prototype.createLens=function(itemID,div,uiContext,opts){var lens=new Exhibit.Lens();
+if(uiContext.getDatabase().isNewItem(itemID)){SimileAjax.jQuery(div).addClass("newItem");
+}opts=opts||{};
+var lensTemplate=opts.lensTemplate||this.getLens(itemID,uiContext);
+if(lensTemplate==null){lens._constructDefaultUI(itemID,div,uiContext);
+}else{if(typeof lensTemplate=="string"){lens._constructFromLensTemplateURL(itemID,div,uiContext,lensTemplate,opts);
+}else{lens._constructFromLensTemplateDOM(itemID,div,uiContext,lensTemplate,opts);
+}}return lens;
+};
+Exhibit.LensRegistry.prototype.createEditLens=function(itemID,div,uiContext,opts){opts=opts||{};
+opts.lensTemplate=this.getEditLens(itemID,uiContext);
+return this.createLens(itemID,div,uiContext,opts);
+};
+Exhibit.LensRegistry.prototype.createNormalLens=function(itemID,div,uiContext,opts){opts=opts||{};
+opts.lensTemplate=this.getNormalLens(itemID,uiContext);
+return this.createLens(itemID,div,uiContext,opts);
+};
+Exhibit.Lens=function(){};
+Exhibit.Lens._commonProperties=null;
+Exhibit.Lens.prototype._constructDefaultUI=function(itemID,div,uiContext){var database=uiContext.getDatabase();
+if(Exhibit.Lens._commonProperties==null){Exhibit.Lens._commonProperties=database.getAllProperties();
+}var properties=Exhibit.Lens._commonProperties;
+var label=database.getObject(itemID,"label");
+label=label!=null?label:itemID;
+if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var template={elmt:div,className:"exhibit-lens",children:[{tag:"div",className:"exhibit-lens-title",title:label,children:[label+" (",{tag:"a",href:Exhibit.Persistence.getItemLink(itemID),target:"_blank",children:[Exhibit.l10n.itemLinkLabel]},")"]},{tag:"div",className:"exhibit-lens-body",children:[{tag:"table",className:"exhibit-lens-properties",field:"propertiesTable"}]}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+div.setAttribute("ex:itemID",itemID);
+var pairs=Exhibit.ViewPanel.getPropertyValuesPairs(itemID,properties,database);
+for(var j=0;
+j<pairs.length;
+j++){var pair=pairs[j];
+var tr=dom.propertiesTable.insertRow(j);
+tr.className="exhibit-lens-property";
+var tdName=tr.insertCell(0);
+tdName.className="exhibit-lens-property-name";
+tdName.innerHTML=pair.propertyLabel+": ";
+var tdValues=tr.insertCell(1);
+tdValues.className="exhibit-lens-property-values";
+if(pair.valueType=="item"){for(var m=0;
+m<pair.values.length;
+m++){if(m>0){tdValues.appendChild(document.createTextNode(", "));
+}tdValues.appendChild(Exhibit.UI.makeItemSpan(pair.values[m],null,uiContext));
+}}else{for(var m=0;
+m<pair.values.length;
+m++){if(m>0){tdValues.appendChild(document.createTextNode(", "));
+}tdValues.appendChild(Exhibit.UI.makeValueSpan(pair.values[m],pair.valueType));
+}}}};
+Exhibit.Lens.prototype._constructDefaultEditingUI=function(itemID,div,uiContext){};
+Exhibit.Lens._compiledTemplates={};
+Exhibit.Lens._handlers=["onblur","onfocus","onkeydown","onkeypress","onkeyup","onmousedown","onmouseenter","onmouseleave","onmousemove","onmouseout","onmouseover","onmouseup","onclick","onresize","onscroll"];
+Exhibit.Lens.prototype._constructFromLensTemplateURL=function(itemID,div,uiContext,lensTemplateURL){var job={lens:this,itemID:itemID,div:div,uiContext:uiContext,opts:opts};
+var compiledTemplate=Exhibit.Lens._compiledTemplates[lensTemplateURL];
+if(compiledTemplate==null){Exhibit.Lens._startCompilingTemplate(lensTemplateURL,job);
+}else{if(!compiledTemplate.compiled){compiledTemplate.jobs.push(job);
+}else{job.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job);
+}}};
+Exhibit.Lens.prototype._constructFromLensTemplateDOM=function(itemID,div,uiContext,lensTemplateNode,opts){var job={lens:this,itemID:itemID,div:div,uiContext:uiContext,opts:opts};
+var id=lensTemplateNode.id;
+if(id==null||id.length==0){id="exhibitLensTemplate"+Math.floor(Math.random()*10000);
+lensTemplateNode.id=id;
+}var compiledTemplate=Exhibit.Lens._compiledTemplates[id];
+if(compiledTemplate==null){compiledTemplate={url:id,template:Exhibit.Lens.compileTemplate(lensTemplateNode,false,uiContext),compiled:true,jobs:[]};
+Exhibit.Lens._compiledTemplates[id]=compiledTemplate;
+}job.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job);
+};
+Exhibit.Lens._startCompilingTemplate=function(lensTemplateURL,job){var compiledTemplate={url:lensTemplateURL,template:null,compiled:false,jobs:[job]};
+Exhibit.Lens._compiledTemplates[lensTemplateURL]=compiledTemplate;
+var fError=function(statusText,status,xmlhttp){SimileAjax.Debug.log("Failed to load view template from "+lensTemplateURL+"\n"+statusText);
+};
+var fDone=function(xmlhttp){try{compiledTemplate.template=Exhibit.Lens.compileTemplate(xmlhttp.responseXML.documentElement,true,job.uiContext);
+compiledTemplate.compiled=true;
+for(var i=0;
+i<compiledTemplate.jobs.length;
+i++){try{var job2=compiledTemplate.jobs[i];
+job2.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job2);
+}catch(e){SimileAjax.Debug.exception(e,"Lens: Error constructing lens template in job queue");
+}}compiledTemplate.jobs=null;
+}catch(e){SimileAjax.Debug.exception(e,"Lens: Error compiling lens template and processing template job queue");
+}};
+SimileAjax.XmlHttp.get(lensTemplateURL,fError,fDone);
+return compiledTemplate;
+};
+Exhibit.Lens.compileTemplate=function(rootNode,isXML,uiContext){return Exhibit.Lens._processTemplateNode(rootNode,isXML,uiContext);
+};
+Exhibit.Lens._processTemplateNode=function(node,isXML,uiContext){if(node.nodeType==1){return Exhibit.Lens._processTemplateElement(node,isXML,uiContext);
+}else{return node.nodeValue;
+}};
+Exhibit.Lens._processTemplateElement=function(elmt,isXML,uiContext){var templateNode={tag:elmt.tagName.toLowerCase(),uiContext:uiContext,control:null,condition:null,content:null,contentAttributes:null,subcontentAttributes:null,attributes:[],styles:[],handlers:[],children:null};
+var settings={parseChildTextNodes:true};
+var attributes=elmt.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+var name=attribute.nodeName;
+var value=attribute.nodeValue;
+Exhibit.Lens._processTemplateAttribute(uiContext,templateNode,settings,name,value);
+}if(!isXML&&SimileAjax.Platform.browser.isIE){var handlers=Exhibit.Lens._handlers;
+for(var h=0;
+h<handlers.length;
+h++){var handler=handlers[h];
+var code=elmt[handler];
+if(code!=null){templateNode.handlers.push({name:handler,code:code});
+}}}var childNode=elmt.firstChild;
+if(childNode!=null){templateNode.children=[];
+while(childNode!=null){if((settings.parseChildTextNodes&&childNode.nodeType==3)||childNode.nodeType==1){templateNode.children.push(Exhibit.Lens._processTemplateNode(childNode,isXML,templateNode.uiContext));
+}childNode=childNode.nextSibling;
+}}return templateNode;
+};
+Exhibit.Lens._processTemplateAttribute=function(uiContext,templateNode,settings,name,value){if(value==null||typeof value!="string"||value.length==0||name=="contentEditable"){return ;
+}if(name.length>3&&name.substr(0,3)=="ex:"){name=name.substr(3);
+if(name=="formats"){templateNode.uiContext=Exhibit.UIContext._createWithParent(uiContext);
+Exhibit.FormatParser.parseSeveral(templateNode.uiContext,value,0,{});
+}else{if(name=="onshow"){templateNode.attributes.push({name:name,value:value});
+}else{if(name=="control"){templateNode.control=value;
+}else{if(name=="content"){templateNode.content=Exhibit.ExpressionParser.parse(value);
+templateNode.attributes.push({name:"ex:content",value:value});
+}else{if(name=="editor"){templateNode.attributes.push({name:"ex:editor",value:value});
+}else{if(name=="edit"){templateNode.edit=value;
+}else{if(name=="options"){templateNode.options=value;
+}else{if(name=="editvalues"){templateNode.editValues=value;
+}else{if(name=="tag"){templateNode.tag=value;
+}else{if(name=="if-exists"){templateNode.condition={test:"if-exists",expression:Exhibit.ExpressionParser.parse(value)};
+}else{if(name=="if"){templateNode.condition={test:"if",expression:Exhibit.ExpressionParser.parse(value)};
+settings.parseChildTextNodes=false;
+}else{if(name=="select"){templateNode.condition={test:"select",expression:Exhibit.ExpressionParser.parse(value)};
+}else{if(name=="case"){templateNode.condition={test:"case",value:value};
+settings.parseChildTextNodes=false;
+}else{var isStyle=false;
+var x=name.indexOf("-style-content");
+if(x>0){isStyle=true;
+}else{x=name.indexOf("-content");
+}if(x>0){if(templateNode.contentAttributes==null){templateNode.contentAttributes=[];
+}templateNode.contentAttributes.push({name:name.substr(0,x),expression:Exhibit.ExpressionParser.parse(value),isStyle:isStyle});
+}else{x=name.indexOf("-style-subcontent");
+if(x>0){isStyle=true;
+}else{x=name.indexOf("-subcontent");
+}if(x>0){if(templateNode.subcontentAttributes==null){templateNode.subcontentAttributes=[];
+}templateNode.subcontentAttributes.push({name:name.substr(0,x),fragments:Exhibit.Lens._parseSubcontentAttribute(value),isStyle:isStyle});
+}}}}}}}}}}}}}}}}else{if(name=="style"){Exhibit.Lens._processStyle(templateNode,value);
+}else{if(name!="id"){if(name=="class"){if(SimileAjax.Platform.browser.isIE){name="className";
+}}else{if(name=="cellspacing"){name="cellSpacing";
+}else{if(name=="cellpadding"){name="cellPadding";
+}else{if(name=="bgcolor"){name="bgColor";
+}}}}templateNode.attributes.push({name:name,value:value});
+}}}};
+Exhibit.Lens._processStyle=function(templateNode,styleValue){var styles=styleValue.split(";");
+for(var s=0;
+s<styles.length;
+s++){var pair=styles[s].split(":");
+if(pair.length>1){var n=pair[0].trim();
+var v=pair[1].trim();
+if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
+}else{if(n=="-moz-opacity"){n="MozOpacity";
+}else{if(n.indexOf("-")>0){var segments=n.split("-");
+n=segments[0];
+for(var x=1;
+x<segments.length;
+x++){n+=segments[x].substr(0,1).toUpperCase()+segments[x].substr(1);
+}}}}templateNode.styles.push({name:n,value:v});
+}}};
+Exhibit.Lens._parseSubcontentAttribute=function(value){var fragments=[];
+var current=0;
+var open;
+while(current<value.length&&(open=value.indexOf("{{",current))>=0){var close=value.indexOf("}}",open);
+if(close<0){break;
+}fragments.push(value.substring(current,open));
+fragments.push(Exhibit.ExpressionParser.parse(value.substring(open+2,close)));
+current=close+2;
+}if(current<value.length){fragments.push(value.substr(current));
+}return fragments;
+};
+Exhibit.Lens.constructFromLensTemplate=function(itemID,templateNode,parentElmt,uiContext,opts){return Exhibit.Lens._performConstructFromLensTemplateJob({itemID:itemID,template:{template:templateNode},div:parentElmt,uiContext:uiContext,opts:opts});
+};
+Exhibit.Lens._performConstructFromLensTemplateJob=function(job){Exhibit.Lens._constructFromLensTemplateNode({"value":job.itemID},{"value":"item"},job.template.template,job.div,job.opts);
+var node=job.div.tagName.toLowerCase()=="table"?job.div.rows[job.div.rows.length-1]:job.div.lastChild;
+var tagName=node.tagName.toLowerCase();
+switch(tagName){case"span":node.style.display="inline";
+break;
+case"tr":node.style.display="table-row";
+break;
+case"td":node.style.display="table-cell";
+break;
+default:node.style.display="block";
+}node.setAttribute("ex:itemID",job.itemID);
+if(!Exhibit.params.safe){var onshow=Exhibit.getAttribute(node,"onshow");
+if(onshow!=null&&onshow.length>0){try{(new Function(onshow)).call(node);
+}catch(e){SimileAjax.Debug.log(e);
+}}}return node;
+};
+Exhibit.Lens._constructFromLensTemplateNode=function(roots,rootValueTypes,templateNode,parentElmt,opts){if(typeof templateNode=="string"){parentElmt.appendChild(document.createTextNode(templateNode));
+return ;
+}var uiContext=templateNode.uiContext;
+var database=uiContext.getDatabase();
+var children=templateNode.children;
+function processChildren(){if(children!=null){for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[i],elmt,opts);
+}}}if(templateNode.condition!=null){if(templateNode.condition.test=="if-exists"){if(!templateNode.condition.expression.testExists(roots,rootValueTypes,"value",database)){return ;
+}}else{if(templateNode.condition.test=="if"){if(templateNode.condition.expression.evaluate(roots,rootValueTypes,"value",database).values.contains(true)){if(children!=null&&children.length>0){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[0],parentElmt,opts);
+}}else{if(children!=null&&children.length>1){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[1],parentElmt,opts);
+}}return ;
+}else{if(templateNode.condition.test=="select"){var values=templateNode.condition.expression.evaluate(roots,rootValueTypes,"value",database).values;
+if(children!=null){var lastChildTemplateNode=null;
+for(var c=0;
+c<children.length;
+c++){var childTemplateNode=children[c];
+if(childTemplateNode.condition!=null&&childTemplateNode.condition.test=="case"){if(values.contains(childTemplateNode.condition.value)){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,childTemplateNode,parentElmt,opts);
+return ;
+}}else{if(typeof childTemplateNode!="string"){lastChildTemplateNode=childTemplateNode;
+}}}}if(lastChildTemplateNode!=null){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,lastChildTemplateNode,parentElmt,opts);
+}return ;
+}}}}var elmt=Exhibit.Lens._constructElmtWithAttributes(templateNode,parentElmt,database);
+if(templateNode.contentAttributes!=null){var contentAttributes=templateNode.contentAttributes;
+for(var i=0;
+i<contentAttributes.length;
+i++){var attribute=contentAttributes[i];
+var values=[];
+attribute.expression.evaluate(roots,rootValueTypes,"value",database).values.visit(function(v){values.push(v);
+});
+var value=values.join(";");
+if(attribute.isStyle){elmt.style[attribute.name]=value;
+}else{if("class"==attribute.name){elmt.className=value;
+}else{if(Exhibit.Lens._attributeValueIsSafe(attribute.name,value)){elmt.setAttribute(attribute.name,value);
+}}}}}if(templateNode.subcontentAttributes!=null){var subcontentAttributes=templateNode.subcontentAttributes;
+for(var i=0;
+i<subcontentAttributes.length;
+i++){var attribute=subcontentAttributes[i];
+var fragments=attribute.fragments;
+var results="";
+for(var r=0;
+r<fragments.length;
+r++){var fragment=fragments[r];
+if(typeof fragment=="string"){results+=fragment;
+}else{results+=fragment.evaluateSingle(roots,rootValueTypes,"value",database).value;
+}}if(attribute.isStyle){elmt.style[attribute.name]=results;
+}else{if("class"==attribute.name){elmt.className=results;
+}else{if(Exhibit.Lens._attributeValueIsSafe(attribute.name,results)){elmt.setAttribute(attribute.name,results);
+}}}}}if(!Exhibit.params.safe){var handlers=templateNode.handlers;
+for(var h=0;
+h<handlers.length;
+h++){var handler=handlers[h];
+elmt[handler.name]=handler.code;
+}}var itemID=roots["value"];
+if(templateNode.control!=null){switch(templateNode.control){case"item-link":var a=document.createElement("a");
+a.innerHTML=Exhibit.l10n.itemLinkLabel;
+a.href=Exhibit.Persistence.getItemLink(itemID);
+a.target="_blank";
+elmt.appendChild(a);
+break;
+case"remove-item":if(!opts.disableEditWidgets&&database.isNewItem(itemID)){if(templateNode.tag=="a"){elmt.href="javascript:";
+}SimileAjax.jQuery(elmt).click(function(){database.removeItem(itemID);
+});
+processChildren();
+}else{parentElmt.removeChild(elmt);
+}break;
+case"start-editing":if(templateNode.tag=="a"){elmt.href="javascript:";
+}if(opts.disableEditWidgets){parentElmt.removeChild(elmt);
+}else{if(opts.inPopup){SimileAjax.jQuery(elmt).click(function(){Exhibit.UI.showItemInPopup(itemID,null,uiContext,{lensType:"edit",coords:opts.coords});
+});
+processChildren();
+}else{SimileAjax.jQuery(elmt).click(function(){uiContext.setEditMode(itemID,true);
+uiContext.getCollection()._listeners.fire("onItemsChanged",[]);
+});
+processChildren();
+}}break;
+case"stop-editing":if(templateNode.tag=="a"){elmt.href="javascript:";
+}if(opts.disableEditWidgets){parentElmt.removeChild(elmt);
+}else{if(opts.inPopup){SimileAjax.jQuery(elmt).click(function(){Exhibit.UI.showItemInPopup(itemID,null,uiContext,{lensType:"normal",coords:opts.coords});
+});
+processChildren();
+}else{SimileAjax.jQuery(elmt).click(function(){uiContext.setEditMode(itemID,false);
+uiContext.getCollection()._listeners.fire("onItemsChanged",[]);
+});
+processChildren();
+}}break;
+case"accept-changes":if(database.isSubmission(itemID)){if(templateNode.tag=="a"){elmt.href="javascript:";
+}SimileAjax.jQuery(elmt).click(function(){database.mergeSubmissionIntoItem(itemID);
+});
+processChildren();
+}else{SimileAjax.Debug.warn("accept-changes element in non-submission item");
+parentElmt.removeChild(elmt);
+}break;
+}}else{if(templateNode.content!=null){var results=templateNode.content.evaluate(roots,rootValueTypes,"value",database);
+if(children!=null){var rootValueTypes2={"value":results.valueType,"index":"number"};
+var index=1;
+var processOneValue=function(childValue){var roots2={"value":childValue,"index":index++};
+for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots2,rootValueTypes2,children[i],elmt,opts);
+}};
+if(results.values instanceof Array){for(var i=0;
+i<results.values.length;
+i++){processOneValue(results.values[i]);
+}}else{results.values.visit(processOneValue);
+}}else{Exhibit.Lens._constructDefaultValueList(results.values,results.valueType,elmt,templateNode.uiContext);
+}}else{if(templateNode.edit!=null){processChildren();
+Exhibit.Lens._constructEditableContent(templateNode,elmt,itemID,uiContext);
+}else{if(children!=null){for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[i],elmt,opts);
+}}}}}};
+Exhibit.Lens._constructElmtWithAttributes=function(templateNode,parentElmt,database){var elmt;
+if(templateNode.tag=="input"&&SimileAjax.Platform.browser.isIE){var a=["<input"];
+var attributes=templateNode.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+if(Exhibit.Lens._attributeValueIsSafe(attribute.name,attribute.value)){a.push(attribute.name+'="'+attribute.value+'"');
+}}a.push("></input>");
+elmt=SimileAjax.DOM.createElementFromString(a.join(" "));
+parentElmt.appendChild(elmt);
+}else{switch(templateNode.tag){case"tr":elmt=parentElmt.insertRow(parentElmt.rows.length);
+break;
+case"td":elmt=parentElmt.insertCell(parentElmt.cells.length);
+break;
+default:elmt=document.createElement(templateNode.tag);
+parentElmt.appendChild(elmt);
+}var attributes=templateNode.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+if(Exhibit.Lens._attributeValueIsSafe(attribute.name,attribute.value)){try{elmt.setAttribute(attribute.name,attribute.value);
+}catch(e){}}}}var styles=templateNode.styles;
+for(var i=0;
+i<styles.length;
+i++){var style=styles[i];
+elmt.style[style.name]=style.value;
+}return elmt;
+};
+Exhibit.Lens._constructEditableContent=function(templateNode,elmt,itemID,uiContext){var db=uiContext.getDatabase();
+var attr=templateNode.edit.replace(".","");
+var itemValue=db.getObject(itemID,attr);
+var changeHandler=function(){if(this.value&&this.value!=itemValue){db.editItem(itemID,attr,this.value);
+}};
+if(templateNode.tag=="select"){Exhibit.Lens._constructEditableSelect(templateNode,elmt,itemID,uiContext,itemValue);
+SimileAjax.jQuery(elmt).blur(changeHandler);
+}else{elmt.value=itemValue;
+SimileAjax.jQuery(elmt).change(changeHandler);
+}};
+Exhibit.Lens.doesSelectContain=function(select,text){for(var i in select.options){var opt=select.options[i];
+if(opt.text==text||opt.value==text){return true;
+}}return false;
+};
+Exhibit.Lens._constructEditableSelect=function(templateNode,elmt,itemID,uiContext,itemValue){if(templateNode.options){var expr=Exhibit.ExpressionParser.parse(templateNode.options);
+var allItems=uiContext.getDatabase().getAllItems();
+var results=expr.evaluate({"value":allItems},{value:"item"},"value",uiContext.getDatabase());
+var sortedResults=results.values.toArray().sort();
+for(var i in sortedResults){var optText=sortedResults[i];
+if(!Exhibit.Lens.doesSelectContain(elmt,optText)){var newOption=new Option(sortedResults[i],sortedResults[i]);
+elmt.add(newOption,null);
+}}}if(!itemValue){if(!Exhibit.Lens.doesSelectContain(elmt,"")){var newOption=new Option("","",true);
+elmt.add(newOption,elmt.options[0]);
+}}else{for(var i in elmt.options){if(elmt.options.hasOwnProperty(i)&&elmt.options[i].value==itemValue){elmt.selectedIndex=i;
+}}}};
+Exhibit.Lens._constructDefaultValueList=function(values,valueType,parentElmt,uiContext){uiContext.formatList(values,values.size(),valueType,function(elmt){parentElmt.appendChild(elmt);
+});
+};
+Exhibit.Lens._attributeValueIsSafe=function(name,value){if(Exhibit.params.safe){if((name=="href"&&value.startsWith("javascript:"))||(name.startsWith("on"))){return false;
+}}return true;
+};
+
+
+/* ui-context.js */
+Exhibit.UIContext=function(){this._parent=null;
+this._exhibit=null;
+this._collection=null;
+this._lensRegistry=new Exhibit.LensRegistry();
+this._settings={};
+this._formatters={};
+this._listFormatter=null;
+this._editModeRegistry={};
+this._popupFunc=null;
+};
+Exhibit.UIContext.createRootContext=function(configuration,exhibit){var context=new Exhibit.UIContext();
+context._exhibit=exhibit;
+var settings=Exhibit.UIContext.l10n.initialSettings;
+for(var n in settings){context._settings[n]=settings[n];
+}var formats=Exhibit.getAttribute(document.body,"formats");
+if(formats!=null&&formats.length>0){Exhibit.FormatParser.parseSeveral(context,formats,0,{});
+}Exhibit.SettingsUtilities.collectSettingsFromDOM(document.body,Exhibit.UIContext._settingSpecs,context._settings);
+Exhibit.UIContext._configure(context,configuration);
+return context;
+};
+Exhibit.UIContext.create=function(configuration,parentUIContext,ignoreLenses){var context=Exhibit.UIContext._createWithParent(parentUIContext);
+Exhibit.UIContext._configure(context,configuration,ignoreLenses);
+return context;
+};
+Exhibit.UIContext.createFromDOM=function(configElmt,parentUIContext,ignoreLenses){var context=Exhibit.UIContext._createWithParent(parentUIContext);
+if(!(ignoreLenses)){Exhibit.UIContext.registerLensesFromDOM(configElmt,context.getLensRegistry());
+}var id=Exhibit.getAttribute(configElmt,"collectionID");
+if(id!=null&&id.length>0){context._collection=context._exhibit.getCollection(id);
+}var formats=Exhibit.getAttribute(configElmt,"formats");
+if(formats!=null&&formats.length>0){Exhibit.FormatParser.parseSeveral(context,formats,0,{});
+}Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.UIContext._settingSpecs,context._settings);
+Exhibit.UIContext._configure(context,Exhibit.getConfigurationFromDOM(configElmt),ignoreLenses);
+return context;
+};
+Exhibit.UIContext.prototype.dispose=function(){};
+Exhibit.UIContext.prototype.getParentUIContext=function(){return this._parent;
+};
+Exhibit.UIContext.prototype.getExhibit=function(){return this._exhibit;
+};
+Exhibit.UIContext.prototype.getDatabase=function(){return this.getExhibit().getDatabase();
+};
+Exhibit.UIContext.prototype.getCollection=function(){if(this._collection==null){if(this._parent!=null){this._collection=this._parent.getCollection();
+}else{this._collection=this._exhibit.getDefaultCollection();
+}}return this._collection;
+};
+Exhibit.UIContext.prototype.getLensRegistry=function(){return this._lensRegistry;
+};
+Exhibit.UIContext.prototype.getSetting=function(name){return name in this._settings?this._settings[name]:(this._parent!=null?this._parent.getSetting(name):undefined);
+};
+Exhibit.UIContext.prototype.getBooleanSetting=function(name,defaultValue){var v=this.getSetting(name);
+return v==undefined||v==null?defaultValue:v;
+};
+Exhibit.UIContext.prototype.putSetting=function(name,value){this._settings[name]=value;
+};
+Exhibit.UIContext.prototype.format=function(value,valueType,appender){var f;
+if(valueType in this._formatters){f=this._formatters[valueType];
+}else{f=this._formatters[valueType]=new Exhibit.Formatter._constructors[valueType](this);
+}f.format(value,appender);
+};
+Exhibit.UIContext.prototype.formatList=function(iterator,count,valueType,appender){if(this._listFormatter==null){this._listFormatter=new Exhibit.Formatter._ListFormatter(this);
+}this._listFormatter.formatList(iterator,count,valueType,appender);
+};
+Exhibit.UIContext.prototype.setEditMode=function(itemID,val){if(val){this._editModeRegistry[itemID]=true;
+}else{this._editModeRegistry[itemID]=false;
+}};
+Exhibit.UIContext.prototype.isBeingEdited=function(itemID){return !!this._editModeRegistry[itemID];
+};
+Exhibit.UIContext._createWithParent=function(parent){var context=new Exhibit.UIContext();
+context._parent=parent;
+context._exhibit=parent._exhibit;
+context._lensRegistry=new Exhibit.LensRegistry(parent.getLensRegistry());
+context._editModeRegistry=parent._editModeRegistry;
+return context;
+};
+Exhibit.UIContext._settingSpecs={"bubbleWidth":{type:"int"},"bubbleHeight":{type:"int"}};
+Exhibit.UIContext._configure=function(context,configuration,ignoreLenses){Exhibit.UIContext.registerLenses(configuration,context.getLensRegistry());
+if("collectionID" in configuration){context._collection=context._exhibit.getCollection(configuration["collectionID"]);
+}if("formats" in configuration){Exhibit.FormatParser.parseSeveral(context,configuration.formats,0,{});
+}if(!(ignoreLenses)){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.UIContext._settingSpecs,context._settings);
+}};
+Exhibit.UIContext.registerLens=function(configuration,lensRegistry){var template=configuration.templateFile;
+if(template!=null){if("itemTypes" in configuration){for(var i=0;
+i<configuration.itemTypes.length;
+i++){lensRegistry.registerLensForType(template,configuration.itemTypes[i]);
+}}else{lensRegistry.registerDefaultLens(template);
+}}};
+Exhibit.UIContext.registerLensFromDOM=function(elmt,lensRegistry){elmt.style.display="none";
+var itemTypes=Exhibit.getAttribute(elmt,"itemTypes",",");
+var template=null;
+var url=Exhibit.getAttribute(elmt,"templateFile");
+if(url!=null&&url.length>0){template=url;
+}else{var id=Exhibit.getAttribute(elmt,"template");
+var elmt2=id&&document.getElementById(id);
+if(elmt2!=null){template=elmt2;
+}else{template=elmt;
+}}if(template!=null){if(itemTypes==null||itemTypes.length==0||(itemTypes.length==1&&itemTypes[0]=="")){lensRegistry.registerDefaultLens(template);
+}else{for(var i=0;
+i<itemTypes.length;
+i++){lensRegistry.registerLensForType(template,itemTypes[i]);
+}}}};
+Exhibit.UIContext.registerLenses=function(configuration,lensRegistry){if("lenses" in configuration){for(var i=0;
+i<configuration.lenses.length;
+i++){Exhibit.UIContext.registerLens(configuration.lenses[i],lensRegistry);
+}}if("lensSelector" in configuration){var lensSelector=configuration.lensSelector;
+if(typeof lensSelector=="function"){lensRegistry.addLensSelector(lensSelector);
+}else{SimileAjax.Debug.log("lensSelector is not a function");
+}}};
+Exhibit.UIContext.registerLensesFromDOM=function(parentNode,lensRegistry){var node=parentNode.firstChild;
+while(node!=null){if(node.nodeType==1){var role=Exhibit.getRoleAttribute(node);
+if(role=="lens"||role=="edit-lens"){Exhibit.UIContext.registerLensFromDOM(node,lensRegistry);
+}}node=node.nextSibling;
+}var lensSelectorString=Exhibit.getAttribute(parentNode,"lensSelector");
+if(lensSelectorString!=null&&lensSelectorString.length>0){try{var lensSelector=eval(lensSelectorString);
+if(typeof lensSelector=="function"){lensRegistry.addLensSelector(lensSelector);
+}else{SimileAjax.Debug.log("lensSelector expression "+lensSelectorString+" is not a function");
+}}catch(e){SimileAjax.Debug.exception(e,"Bad lensSelector expression: "+lensSelectorString);
+}}};
+Exhibit.UIContext.createLensRegistry=function(configuration,parentLensRegistry){var lensRegistry=new Exhibit.LensRegistry(parentLensRegistry);
+Exhibit.UIContext.registerLenses(configuration,lensRegistry);
+return lensRegistry;
+};
+Exhibit.UIContext.createLensRegistryFromDOM=function(parentNode,configuration,parentLensRegistry){var lensRegistry=new Exhibit.LensRegistry(parentLensRegistry);
+Exhibit.UIContext.registerLensesFromDOM(parentNode,lensRegistry);
+Exhibit.UIContext.registerLenses(configuration,lensRegistry);
+return lensRegistry;
+};
+
+
+/* ui.js */
+Exhibit.UI=new Object();
+Exhibit.UI.componentMap={};
+Exhibit.UI.registerComponent=function(name,comp){var msg="Cannot register component "+name+" -- ";
+if(name in Exhibit.UI.componentMap){SimileAjax.Debug.warn(msg+"another component has taken that name");
+}else{if(!comp){SimileAjax.Debug.warn(msg+"no component object provided");
+}else{if(!comp.create){SimileAjax.Debug.warn(msg+"component has no create function");
+}else{if(!comp.createFromDOM){SimileAjax.Debug.warn(msg+"component has no createFromDOM function");
+}else{Exhibit.UI.componentMap[name]=comp;
+}}}}};
+Exhibit.UI.create=function(configuration,elmt,uiContext){if("role" in configuration){var role=configuration.role;
+if(role!=null&&role.startsWith("exhibit-")){role=role.substr("exhibit-".length);
+}if(role in Exhibit.UI.componentMap){var createFunc=Exhibit.UI.componentMap[role].create;
+return createFunc(configuration,elmt,uiContext);
+}switch(role){case"lens":case"edit-lens":Exhibit.UIContext.registerLens(configuration,uiContext.getLensRegistry());
+return null;
+case"view":return Exhibit.UI.createView(configuration,elmt,uiContext);
+case"facet":return Exhibit.UI.createFacet(configuration,elmt,uiContext);
+case"coordinator":return Exhibit.UI.createCoordinator(configuration,uiContext);
+case"coder":return Exhibit.UI.createCoder(configuration,uiContext);
+case"viewPanel":return Exhibit.ViewPanel.create(configuration,elmt,uiContext);
+case"logo":return Exhibit.Logo.create(configuration,elmt,uiContext);
+case"hiddenContent":elmt.style.display="none";
+return null;
+}}return null;
+};
+Exhibit.UI.createFromDOM=function(elmt,uiContext){var role=Exhibit.getRoleAttribute(elmt);
+if(role in Exhibit.UI.componentMap){var createFromDOMFunc=Exhibit.UI.componentMap[role].createFromDOM;
+return createFromDOMFunc(elmt,uiContext);
+}switch(role){case"lens":case"edit-lens":Exhibit.UIContext.registerLensFromDOM(elmt,uiContext.getLensRegistry());
+return null;
+case"view":return Exhibit.UI.createViewFromDOM(elmt,null,uiContext);
+case"facet":return Exhibit.UI.createFacetFromDOM(elmt,null,uiContext);
+case"coordinator":return Exhibit.UI.createCoordinatorFromDOM(elmt,uiContext);
+case"coder":return Exhibit.UI.createCoderFromDOM(elmt,uiContext);
+case"viewPanel":return Exhibit.ViewPanel.createFromDOM(elmt,uiContext);
+case"logo":return Exhibit.Logo.createFromDOM(elmt,uiContext);
+case"hiddenContent":elmt.style.display="none";
+return null;
+}return null;
+};
+Exhibit.UI.generateCreationMethods=function(constructor){constructor.create=function(configuration,elmt,uiContext){var newContext=Exhibit.UIContext.create(configuration,uiContext);
+var settings={};
+Exhibit.SettingsUtilities.collectSettings(configuration,constructor._settingSpecs||{},settings);
+return new constructor(elmt,newContext,settings);
+};
+constructor.createFromDOM=function(elmt,uiContext){var newContext=Exhibit.UIContext.createFromDOM(elmt,uiContext);
+var settings={};
+Exhibit.SettingsUtilities.collectSettingsFromDOM(elmt,constructor._settingSpecs||{},settings);
+return new constructor(elmt,newContext,settings);
+};
+};
+Exhibit.UI.createView=function(configuration,elmt,uiContext){var viewClass="viewClass" in configuration?configuration.viewClass:Exhibit.TileView;
+if(typeof viewClass=="string"){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClass);
+}return viewClass.create(configuration,elmt,uiContext);
+};
+Exhibit.UI.createViewFromDOM=function(elmt,container,uiContext){var viewClass=Exhibit.UI.viewClassNameToViewClass(Exhibit.getAttribute(elmt,"viewClass"));
+return viewClass.createFromDOM(elmt,container,uiContext);
+};
+Exhibit.UI.viewClassNameToViewClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"View");
+}catch(e){SimileAjax.Debug.warn("Unknown viewClass "+name);
+}}return Exhibit.TileView;
+};
+Exhibit.UI.createFacet=function(configuration,elmt,uiContext){var facetClass="facetClass" in configuration?configuration.facetClass:Exhibit.ListFacet;
+if(typeof facetClass=="string"){facetClass=Exhibit.UI.facetClassNameToFacetClass(facetClass);
+}return facetClass.create(configuration,elmt,uiContext);
+};
+Exhibit.UI.createFacetFromDOM=function(elmt,container,uiContext){var facetClass=Exhibit.UI.facetClassNameToFacetClass(Exhibit.getAttribute(elmt,"facetClass"));
+return facetClass.createFromDOM(elmt,container,uiContext);
+};
+Exhibit.UI.facetClassNameToFacetClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"Facet");
+}catch(e){SimileAjax.Debug.warn("Unknown facetClass "+name);
+}}return Exhibit.ListFacet;
+};
+Exhibit.UI.createCoder=function(configuration,uiContext){var coderClass="coderClass" in configuration?configuration.coderClass:Exhibit.ColorCoder;
+if(typeof coderClass=="string"){coderClass=Exhibit.UI.coderClassNameToCoderClass(coderClass);
+}return coderClass.create(configuration,uiContext);
+};
+Exhibit.UI.createCoderFromDOM=function(elmt,uiContext){var coderClass=Exhibit.UI.coderClassNameToCoderClass(Exhibit.getAttribute(elmt,"coderClass"));
+return coderClass.createFromDOM(elmt,uiContext);
+};
+Exhibit.UI.coderClassNameToCoderClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"Coder");
+}catch(e){SimileAjax.Debug.warn("Unknown coderClass "+name);
+}}return Exhibit.ColorCoder;
+};
+Exhibit.UI.createCoordinator=function(configuration,uiContext){return Exhibit.Coordinator.create(configuration,uiContext);
+};
+Exhibit.UI.createCoordinatorFromDOM=function(elmt,uiContext){return Exhibit.Coordinator.createFromDOM(elmt,uiContext);
+};
+Exhibit.UI._stringToObject=function(name,suffix){if(!name.startsWith("Exhibit.")){if(!name.endsWith(suffix)){try{return eval("Exhibit."+name+suffix);
+}catch(e){}}try{return eval("Exhibit."+name);
+}catch(e){}}if(!name.endsWith(suffix)){try{return eval(name+suffix);
+}catch(e){}}try{return eval(name);
+}catch(e){}throw new Error("Unknown class "+name);
+};
+Exhibit.UI.docRoot="http://simile.mit.edu/wiki/";
+Exhibit.UI.validator="http://simile.mit.edu/babel/validator";
+Exhibit.UI.showHelp=function(message,url,target){target=(target)?target:"_blank";
+if(url!=null){if(window.confirm(message+"\n\n"+Exhibit.l10n.showDocumentationMessage)){window.open(url,target);
+}}else{window.alert(message);
+}};
+Exhibit.UI.showJavascriptExpressionValidation=function(message,expression){var target="_blank";
+if(window.confirm(message+"\n\n"+Exhibit.l10n.showJavascriptValidationMessage)){window.open(Exhibit.UI.validator+"?expresson="+encodeURIComponent(expression),target);
+}};
+Exhibit.UI.showJsonFileValidation=function(message,url){var target="_blank";
+if(url.indexOf("file:")==0){if(window.confirm(message+"\n\n"+Exhibit.l10n.showJsonValidationFormMessage)){window.open(Exhibit.UI.validator,target);
+}}else{if(window.confirm(message+"\n\n"+Exhibit.l10n.showJsonValidationMessage)){window.open(Exhibit.UI.validator+"?url="+url,target);
+}}};
+Exhibit.UI._busyIndicator=null;
+Exhibit.UI._busyIndicatorCount=0;
+Exhibit.UI.showBusyIndicator=function(){Exhibit.UI._busyIndicatorCount++;
+if(Exhibit.UI._busyIndicatorCount>1){return ;
+}if(Exhibit.UI._busyIndicator==null){Exhibit.UI._busyIndicator=Exhibit.UI.createBusyIndicator();
+}var scrollTop=("scrollTop" in document.body)?document.body.scrollTop:document.body.parentNode.scrollTop;
+var height=("innerHeight" in window)?window.innerHeight:("clientHeight" in document.body?document.body.clientHeight:document.body.parentNode.clientHeight);
+var top=Math.floor(scrollTop+height/3);
+Exhibit.UI._busyIndicator.style.top=top+"px";
+document.body.appendChild(Exhibit.UI._busyIndicator);
+};
+Exhibit.UI.hideBusyIndicator=function(){Exhibit.UI._busyIndicatorCount--;
+if(Exhibit.UI._busyIndicatorCount>0){return ;
+}try{document.body.removeChild(Exhibit.UI._busyIndicator);
+}catch(e){}};
+Exhibit.UI.protectUI=function(elmt){SimileAjax.DOM.appendClassName(elmt,"exhibit-ui-protection");
+};
+Exhibit.UI.makeActionLink=function(text,handler,layer){var a=document.createElement("a");
+a.href="javascript:";
+a.className="exhibit-action";
+a.innerHTML=text;
+var handler2=function(elmt,evt,target){if("true"!=elmt.getAttribute("disabled")){handler(elmt,evt,target);
+}};
+SimileAjax.WindowManager.registerEvent(a,"click",handler2,layer);
+return a;
+};
+Exhibit.UI.enableActionLink=function(a,enabled){a.setAttribute("disabled",enabled?"false":"true");
+a.className=enabled?"exhibit-action":"exhibit-action-disabled";
+};
+Exhibit.UI.makeItemSpan=function(itemID,label,uiContext,layer){if(label==null){label=database.getObject(itemID,"label");
+if(label==null){label=itemID;
+}}var a=SimileAjax.DOM.createElementFromString('<a href="'+Exhibit.Persistence.getItemLink(itemID)+"\" class='exhibit-item'>"+label+"</a>");
+var handler=function(elmt,evt,target){Exhibit.UI.showItemInPopup(itemID,elmt,uiContext);
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler,layer);
+return a;
+};
+Exhibit.UI.makeValueSpan=function(label,valueType,layer){var span=document.createElement("span");
+span.className="exhibit-value";
+if(valueType=="url"){var url=label;
+if(Exhibit.params.safe&&url.trim().startsWith("javascript:")){span.appendChild(document.createTextNode(url));
+}else{span.innerHTML='<a href="'+url+"\" target='_blank'>"+(label.length>50?label.substr(0,20)+" ... "+label.substr(label.length-20):label)+"</a>";
+}}else{if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}span.innerHTML=label;
+}return span;
+};
+Exhibit.UI.calculatePopupPosition=function(elmt){var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+return{x:coords.left+Math.round(elmt.offsetWidth/2),y:coords.top+Math.round(elmt.offsetHeight/2)};
+};
+Exhibit.UI.showItemInPopup=function(itemID,elmt,uiContext,opts){SimileAjax.WindowManager.popAllLayers();
+opts=opts||{};
+opts.coords=opts.coords||Exhibit.UI.calculatePopupPosition(elmt);
+var itemLensDiv=document.createElement("div");
+var lensOpts={inPopup:true,coords:opts.coords};
+if(opts.lensType=="normal"){lensOpts.lensTemplate=uiContext.getLensRegistry().getNormalLens(itemID,uiContext);
+}else{if(opts.lensType=="edit"){lensOpts.lensTemplate=uiContext.getLensRegistry().getEditLens(itemID,uiContext);
+}else{if(opts.lensType){SimileAjax.Debug.warn("Unknown Exhibit.UI.showItemInPopup opts.lensType: "+opts.lensType);
+}}}uiContext.getLensRegistry().createLens(itemID,itemLensDiv,uiContext,lensOpts);
+SimileAjax.Graphics.createBubbleForContentAndPoint(itemLensDiv,opts.coords.x,opts.coords.y,uiContext.getSetting("bubbleWidth"));
+};
+Exhibit.UI.createButton=function(name,handler,className){var button=document.createElement("button");
+button.className=(className||"exhibit-button")+" screen";
+button.innerHTML=name;
+if(handler){SimileAjax.WindowManager.registerEvent(button,"click",handler);
+}return button;
+};
+Exhibit.UI.createPopupMenuDom=function(element){var div=document.createElement("div");
+div.className="exhibit-menu-popup exhibit-ui-protection";
+var dom={elmt:div,close:function(){document.body.removeChild(this.elmt);
+},open:function(){var self=this;
+this.layer=SimileAjax.WindowManager.pushLayer(function(){self.close();
+},true,div);
+var docWidth=document.body.offsetWidth;
+var docHeight=document.body.offsetHeight;
+var coords=SimileAjax.DOM.getPageCoordinates(element);
+div.style.top=(coords.top+element.scrollHeight)+"px";
+div.style.right=(docWidth-(coords.left+element.scrollWidth))+"px";
+document.body.appendChild(this.elmt);
+},appendMenuItem:function(label,icon,onClick){var self=this;
+var a=document.createElement("a");
+a.className="exhibit-menu-item";
+a.href="javascript:";
+SimileAjax.WindowManager.registerEvent(a,"click",function(elmt,evt,target){onClick(elmt,evt,target);
+SimileAjax.WindowManager.popLayer(self.layer);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+});
+var div=document.createElement("div");
+a.appendChild(div);
+div.appendChild(SimileAjax.Graphics.createTranslucentImage(icon!=null?icon:(Exhibit.urlPrefix+"images/blank-16x16.png")));
+div.appendChild(document.createTextNode(label));
+this.elmt.appendChild(a);
+},appendSeparator:function(){var hr=document.createElement("hr");
+this.elmt.appendChild(hr);
+}};
+return dom;
+};
+Exhibit.UI.createBusyIndicator=function(){var urlPrefix=Exhibit.urlPrefix+"images/";
+var containerDiv=document.createElement("div");
+if(SimileAjax.Graphics.pngIsTranslucent){var topDiv=document.createElement("div");
+topDiv.style.height="33px";
+topDiv.style.background="url("+urlPrefix+"message-bubble/message-top-left.png) top left no-repeat";
+topDiv.style.paddingLeft="44px";
+containerDiv.appendChild(topDiv);
+var topRightDiv=document.createElement("div");
+topRightDiv.style.height="33px";
+topRightDiv.style.background="url("+urlPrefix+"message-bubble/message-top-right.png) top right no-repeat";
+topDiv.appendChild(topRightDiv);
+var middleDiv=document.createElement("div");
+middleDiv.style.background="url("+urlPrefix+"message-bubble/message-left.png) top left repeat-y";
+middleDiv.style.paddingLeft="44px";
+containerDiv.appendChild(middleDiv);
+var middleRightDiv=document.createElement("div");
+middleRightDiv.style.background="url("+urlPrefix+"message-bubble/message-right.png) top right repeat-y";
+middleRightDiv.style.paddingRight="44px";
+middleDiv.appendChild(middleRightDiv);
+var contentDiv=document.createElement("div");
+middleRightDiv.appendChild(contentDiv);
+var bottomDiv=document.createElement("div");
+bottomDiv.style.height="55px";
+bottomDiv.style.background="url("+urlPrefix+"message-bubble/message-bottom-left.png) bottom left no-repeat";
+bottomDiv.style.paddingLeft="44px";
+containerDiv.appendChild(bottomDiv);
+var bottomRightDiv=document.createElement("div");
+bottomRightDiv.style.height="55px";
+bottomRightDiv.style.background="url("+urlPrefix+"message-bubble/message-bottom-right.png) bottom right no-repeat";
+bottomDiv.appendChild(bottomRightDiv);
+}else{containerDiv.style.border="2px solid #7777AA";
+containerDiv.style.padding="20px";
+containerDiv.style.background="white";
+SimileAjax.Graphics.setOpacity(containerDiv,90);
+var contentDiv=document.createElement("div");
+containerDiv.appendChild(contentDiv);
+}containerDiv.className="exhibit-busyIndicator";
+contentDiv.className="exhibit-busyIndicator-content";
+var img=document.createElement("img");
+img.src=urlPrefix+"progress-running.gif";
+contentDiv.appendChild(img);
+contentDiv.appendChild(document.createTextNode(" "+Exhibit.l10n.busyIndicatorMessage));
+return containerDiv;
+};
+Exhibit.UI.createFocusDialogBox=function(itemID,exhibit,configuration){var template={tag:"div",className:"exhibit-focusDialog exhibit-ui-protection",children:[{tag:"div",className:"exhibit-focusDialog-viewContainer",field:"viewContainer"},{tag:"div",className:"exhibit-focusDialog-controls",children:[{tag:"button",field:"closeButton",children:[Exhibit.l10n.focusDialogBoxCloseButtonLabel]}]}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.open=function(){dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var lens=new Exhibit.Lens(itemID,dom.viewContainer,exhibit,configuration);
+dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+},dom.layer);
+};
+return dom;
+};
+Exhibit.UI.createTranslucentImage=function(relativeUrl,verticalAlign){return SimileAjax.Graphics.createTranslucentImage(Exhibit.urlPrefix+relativeUrl,verticalAlign);
+};
+Exhibit.UI.createTranslucentImageHTML=function(relativeUrl,verticalAlign){return SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+relativeUrl,verticalAlign);
+};
+Exhibit.UI.findAttribute=function(attr,value,parent){var parent=SimileAjax.jQuery(parent||document.body);
+var f=function(){var v=this.getAttribute(attr);
+if(value===undefined){return !!v;
+}else{if(value instanceof Array){return value.indexOf(v)!=-1;
+}else{return value.toString()==v;
+}}};
+return parent.find("*").add(parent).filter(f);
+};
+
+
+/* html-view.js */
+Exhibit.HTMLView=function(containerElmt,uiContext,html){this.html=html;
+this.view=this.moveChildNodes(html,containerElmt);
+};
+Exhibit.HTMLView.create=Exhibit.HTMLView.createFromDOM=function(configElmt,containerElmt,uiContext){return new Exhibit.HTMLView(containerElmt!=null?containerElmt:configElmt,null,configElmt);
+};
+Exhibit.HTMLView.prototype.dispose=function(){this.html=this.moveChildNodes(this.view,this.html);
+this.view=this.html=null;
+};
+Exhibit.HTMLView.prototype.moveChildNodes=function(src,dst){if(src===dst){return dst;
+}var tmp=document.createDocumentFragment();
+while(src.firstChild){tmp.appendChild(src.firstChild);
+}dst.appendChild(tmp);
+return dst;
+};
+
+
+/* ordered-view-frame.js */
+Exhibit.OrderedViewFrame=function(uiContext){this._uiContext=uiContext;
+this._orders=null;
+this._possibleOrders=null;
+this._settings={};
+};
+Exhibit.OrderedViewFrame._settingSpecs={"showAll":{type:"boolean",defaultValue:false},"grouped":{type:"boolean",defaultValue:true},"showDuplicates":{type:"boolean",defaultValue:false},"abbreviatedCount":{type:"int",defaultValue:10},"showHeader":{type:"boolean",defaultValue:true},"showSummary":{type:"boolean",defaultValue:true},"showControls":{type:"boolean",defaultValue:true},"showFooter":{type:"boolean",defaultValue:true},"paginate":{type:"boolean",defaultValue:false},"pageSize":{type:"int",defaultValue:20},"pageWindow":{type:"int",defaultValue:2},"page":{type:"int",defaultValue:0},"alwaysShowPagingControls":{type:"boolean",defaultValue:false},"pagingControlLocations":{type:"enum",defaultValue:"topbottom",choices:["top","bottom","topbottom"]}};
+Exhibit.OrderedViewFrame.prototype.configure=function(configuration){if("orders" in configuration){this._orders=[];
+this._configureOrders(configuration.orders);
+}if("possibleOrders" in configuration){this._possibleOrders=[];
+this._configurePossibleOrders(configuration.possibleOrders);
+}Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.OrderedViewFrame._settingSpecs,this._settings);
+this._internalValidate();
+};
+Exhibit.OrderedViewFrame.prototype.configureFromDOM=function(domConfiguration){var orders=Exhibit.getAttribute(domConfiguration,"orders",",");
+if(orders!=null&&orders.length>0){this._orders=[];
+this._configureOrders(orders);
+}var directions=Exhibit.getAttribute(domConfiguration,"directions",",");
+if(directions!=null&&directions.length>0&&this._orders!=null){for(var i=0;
+i<directions.length&&i<this._orders.length;
+i++){this._orders[i].ascending=(directions[i].toLowerCase()!="descending");
+}}var possibleOrders=Exhibit.getAttribute(domConfiguration,"possibleOrders",",");
+if(possibleOrders!=null&&possibleOrders.length>0){this._possibleOrders=[];
+this._configurePossibleOrders(possibleOrders);
+}var possibleDirections=Exhibit.getAttribute(domConfiguration,"possibleDirections",",");
+if(possibleDirections!=null&&possibleDirections.length>0&&this._possibleOrders!=null){for(var i=0;
+i<possibleDirections.length&&i<this._possibleOrders.length;
+i++){this._possibleOrders[i].ascending=(possibleDirections[i].toLowerCase()!="descending");
+}}Exhibit.SettingsUtilities.collectSettingsFromDOM(domConfiguration,Exhibit.OrderedViewFrame._settingSpecs,this._settings);
+this._internalValidate();
+};
+Exhibit.OrderedViewFrame.prototype.dispose=function(){if(this._headerDom){this._headerDom.dispose();
+this._headerDom=null;
+}if(this._footerDom){this._footerDom.dispose();
+this._footerDom=null;
+}this._divHeader=null;
+this._divFooter=null;
+this._uiContext=null;
+};
+Exhibit.OrderedViewFrame.prototype._internalValidate=function(){if(this._orders!=null&&this._orders.length==0){this._orders=null;
+}if(this._possibleOrders!=null&&this._possibleOrders.length==0){this._possibleOrders=null;
+}if(this._settings.paginate){this._settings.grouped=false;
+}};
+Exhibit.OrderedViewFrame.prototype._configureOrders=function(orders){for(var i=0;
+i<orders.length;
+i++){var order=orders[i];
+var expr;
+var ascending=true;
+if(typeof order=="string"){expr=order;
+}else{if(typeof order=="object"){expr=order.expression,ascending=("ascending" in order)?(order.ascending):true;
+}else{SimileAjax.Debug.warn("Bad order object "+order);
+continue;
+}}try{var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(path.getSegmentCount()==1){var segment=path.getSegment(0);
+this._orders.push({property:segment.property,forward:segment.forward,ascending:ascending});
+}}}catch(e){SimileAjax.Debug.warn("Bad order expression "+expr);
+}}};
+Exhibit.OrderedViewFrame.prototype._configurePossibleOrders=function(possibleOrders){for(var i=0;
+i<possibleOrders.length;
+i++){var order=possibleOrders[i];
+var expr;
+var ascending=true;
+if(typeof order=="string"){expr=order;
+}else{if(typeof order=="object"){expr=order.expression,ascending=("ascending" in order)?(order.ascending):true;
+}else{SimileAjax.Debug.warn("Bad possible order object "+order);
+continue;
+}}try{var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(path.getSegmentCount()==1){var segment=path.getSegment(0);
+this._possibleOrders.push({property:segment.property,forward:segment.forward,ascending:ascending});
+}}}catch(e){SimileAjax.Debug.warn("Bad possible order expression "+expr);
+}}};
+Exhibit.OrderedViewFrame.prototype.initializeUI=function(){var self=this;
+if(this._settings.showHeader){this._headerDom=Exhibit.OrderedViewFrame.createHeaderDom(this._uiContext,this._divHeader,this._settings.showSummary,this._settings.showControls,function(elmt,evt,target){self._openSortPopup(elmt,-1);
+},function(elmt,evt,target){self._toggleGroup();
+},function(pageIndex){self._gotoPage(pageIndex);
+});
+}if(this._settings.showFooter){this._footerDom=Exhibit.OrderedViewFrame.createFooterDom(this._uiContext,this._divFooter,function(elmt,evt,target){self._setShowAll(true);
+},function(elmt,evt,target){self._setShowAll(false);
+},function(pageIndex){self._gotoPage(pageIndex);
+});
+}};
+Exhibit.OrderedViewFrame.prototype.reconstruct=function(){var self=this;
+var collection=this._uiContext.getCollection();
+var database=this._uiContext.getDatabase();
+var originalSize=collection.countAllItems();
+var currentSize=collection.countRestrictedItems();
+var hasSomeGrouping=false;
+if(currentSize>0){var currentSet=collection.getRestrictedItems();
+hasSomeGrouping=this._internalReconstruct(currentSet);
+var orderElmts=[];
+var buildOrderElmt=function(order,index){var property=database.getProperty(order.property);
+var label=property!=null?(order.forward?property.getPluralLabel():property.getReversePluralLabel()):(order.forward?order.property:"reverse of "+order.property);
+orderElmts.push(Exhibit.UI.makeActionLink(label,function(elmt,evt,target){self._openSortPopup(elmt,index);
+}));
+};
+var orders=this._getOrders();
+for(var i=0;
+i<orders.length;
+i++){buildOrderElmt(orders[i],i);
+}if(this._settings.showHeader&&this._settings.showControls){this._headerDom.setOrders(orderElmts);
+this._headerDom.enableThenByAction(orderElmts.length<this._getPossibleOrders().length);
+}}if(this._settings.showHeader&&this._settings.showControls){this._headerDom.groupOptionWidget.setChecked(this._settings.grouped);
+}if(this._settings.showFooter){this._footerDom.setCounts(currentSize,this._settings.abbreviatedCount,this._settings.showAll,!(hasSomeGrouping&&this._grouped)&&!this._settings.paginate);
+}};
+Exhibit.OrderedViewFrame.prototype._internalReconstruct=function(allItems){var self=this;
+var settings=this._settings;
+var database=this._uiContext.getDatabase();
+var orders=this._getOrders();
+var itemIndex=0;
+var hasSomeGrouping=false;
+var createItem=function(itemID){if((itemIndex>=fromIndex&&itemIndex<toIndex)||(hasSomeGrouping&&settings.grouped)){self.onNewItem(itemID,itemIndex);
+}itemIndex++;
+};
+var createGroup=function(label,valueType,index){if((itemIndex>=fromIndex&&itemIndex<toIndex)||(hasSomeGrouping&&settings.grouped)){self.onNewGroup(label,valueType,index);
+}};
+var processLevel=function(items,index){var order=orders[index];
+var values=order.forward?database.getObjectsUnion(items,order.property):database.getSubjectsUnion(items,order.property);
+var valueType="text";
+if(order.forward){var property=database.getProperty(order.property);
+valueType=property!=null?property.getValueType():"text";
+}else{valueType="item";
+}var keys=(valueType=="item"||valueType=="text")?processNonNumericLevel(items,index,values,valueType):processNumericLevel(items,index,values,valueType);
+var grouped=false;
+for(var k=0;
+k<keys.length;
+k++){if(keys[k].items.size()>1){grouped=true;
+}}if(grouped){hasSomeGrouping=true;
+}for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+if(key.items.size()>0){if(grouped&&settings.grouped){createGroup(key.display,valueType,index);
+}items.removeSet(key.items);
+if(key.items.size()>1&&index<orders.length-1){processLevel(key.items,index+1);
+}else{key.items.visit(createItem);
+}}}if(items.size()>0){if(grouped&&settings.grouped){createGroup(Exhibit.l10n.missingSortKey,valueType,index);
+}if(items.size()>1&&index<orders.length-1){processLevel(items,index+1);
+}else{items.visit(createItem);
+}}};
+var processNonNumericLevel=function(items,index,values,valueType){var keys=[];
+var compareKeys;
+var retrieveItems;
+var order=orders[index];
+if(valueType=="item"){values.visit(function(itemID){var label=database.getObject(itemID,"label");
+label=label!=null?label:itemID;
+keys.push({itemID:itemID,display:label});
+});
+compareKeys=function(key1,key2){var c=key1.display.localeCompare(key2.display);
+return c!=0?c:key1.itemID.localeCompare(key2.itemID);
+};
+retrieveItems=order.forward?function(key){return database.getSubjects(key.itemID,order.property,null,items);
+}:function(key){return database.getObjects(key.itemID,order.property,null,items);
+};
+}else{values.visit(function(value){keys.push({display:value});
+});
+compareKeys=function(key1,key2){return key1.display.localeCompare(key2.display);
+};
+retrieveItems=order.forward?function(key){return database.getSubjects(key.display,order.property,null,items);
+}:function(key){return database.getObjects(key.display,order.property,null,items);
+};
+}keys.sort(function(key1,key2){return(order.ascending?1:-1)*compareKeys(key1,key2);
+});
+for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+key.items=retrieveItems(key);
+if(!settings.showDuplicates){items.removeSet(key.items);
+}}return keys;
+};
+var processNumericLevel=function(items,index,values,valueType){var keys=[];
+var keyMap={};
+var order=orders[index];
+var valueParser;
+if(valueType=="number"){valueParser=function(value){if(typeof value=="number"){return value;
+}else{try{return parseFloat(value);
+}catch(e){return null;
+}}};
+}else{valueParser=function(value){if(value instanceof Date){return value.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(value.toString()).getTime();
+}catch(e){return null;
+}}};
+}values.visit(function(value){var sortkey=valueParser(value);
+if(sortkey!=null){var key=keyMap[sortkey];
+if(!key){key={sortkey:sortkey,display:value,values:[],items:new Exhibit.Set()};
+keyMap[sortkey]=key;
+keys.push(key);
+}key.values.push(value);
+}});
+keys.sort(function(key1,key2){return(order.ascending?1:-1)*(key1.sortkey-key2.sortkey);
+});
+for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+var values=key.values;
+for(var v=0;
+v<values.length;
+v++){if(order.forward){database.getSubjects(values[v],order.property,key.items,items);
+}else{database.getObjects(values[v],order.property,key.items,items);
+}}if(!settings.showDuplicates){items.removeSet(key.items);
+}}return keys;
+};
+var totalCount=allItems.size();
+var pageCount=Math.ceil(totalCount/settings.pageSize);
+var fromIndex=0;
+var toIndex=settings.showAll?totalCount:Math.min(totalCount,settings.abbreviatedCount);
+if(!settings.grouped&&settings.paginate&&(pageCount>1||(pageCount>0&&settings.alwaysShowPagingControls))){fromIndex=settings.page*settings.pageSize;
+toIndex=Math.min(fromIndex+settings.pageSize,totalCount);
+if(settings.showHeader&&(settings.pagingControlLocations=="top"||settings.pagingControlLocations=="topbottom")){this._headerDom.renderPageLinks(settings.page,pageCount,settings.pageWindow);
+}if(settings.showFooter&&(settings.pagingControlLocations=="bottom"||settings.pagingControlLocations=="topbottom")){this._footerDom.renderPageLinks(settings.page,pageCount,settings.pageWindow);
+}}else{if(settings.showHeader){this._headerDom.hidePageLinks();
+}if(settings.showFooter){this._footerDom.hidePageLinks();
+}}processLevel(allItems,0);
+return hasSomeGrouping;
+};
+Exhibit.OrderedViewFrame.prototype._getOrders=function(){return this._orders||[this._getPossibleOrders()[0]];
+};
+Exhibit.OrderedViewFrame.prototype._getPossibleOrders=function(){var possibleOrders=null;
+if(this._possibleOrders==null){possibleOrders=this._uiContext.getDatabase().getAllProperties();
+for(var i=0,p;
+p=possibleOrders[i];
+i++){possibleOrders[i]={ascending:true,forward:true,property:p};
+}}else{possibleOrders=[].concat(this._possibleOrders);
+}if(possibleOrders.length==0){possibleOrders.push({property:"label",forward:true,ascending:true});
+}return possibleOrders;
+};
+Exhibit.OrderedViewFrame.prototype._openSortPopup=function(elmt,index){var self=this;
+var database=this._uiContext.getDatabase();
+var popupDom=Exhibit.UI.createPopupMenuDom(elmt);
+var configuredOrders=this._getOrders();
+if(index>=0){var order=configuredOrders[index];
+var property=database.getProperty(order.property);
+var propertyLabel=order.forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=order.forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+popupDom.appendMenuItem(sortLabels.ascending,Exhibit.urlPrefix+(order.ascending?"images/option-check.png":"images/option.png"),order.ascending?function(){}:function(){self._reSort(index,order.property,order.forward,true,false);
+});
+popupDom.appendMenuItem(sortLabels.descending,Exhibit.urlPrefix+(order.ascending?"images/option.png":"images/option-check.png"),order.ascending?function(){self._reSort(index,order.property,order.forward,false,false);
+}:function(){});
+if(configuredOrders.length>1){popupDom.appendSeparator();
+popupDom.appendMenuItem(Exhibit.OrderedViewFrame.l10n.removeOrderLabel,null,function(){self._removeOrder(index);
+});
+}}var orders=[];
+var possibleOrders=this._getPossibleOrders();
+for(i=0;
+i<possibleOrders.length;
+i++){var possibleOrder=possibleOrders[i];
+var skip=false;
+for(var j=(index<0)?configuredOrders.length-1:index;
+j>=0;
+j--){var existingOrder=configuredOrders[j];
+if(existingOrder.property==possibleOrder.property&&existingOrder.forward==possibleOrder.forward){skip=true;
+break;
+}}if(!skip){var property=database.getProperty(possibleOrder.property);
+orders.push({property:possibleOrder.property,forward:possibleOrder.forward,ascending:possibleOrder.ascending,label:possibleOrder.forward?property.getPluralLabel():property.getReversePluralLabel()});
+}}if(orders.length>0){if(index>=0){popupDom.appendSeparator();
+}orders.sort(function(order1,order2){return order1.label.localeCompare(order2.label);
+});
+var appendOrder=function(order){popupDom.appendMenuItem(order.label,null,function(){self._reSort(index,order.property,order.forward,order.ascending,true);
+});
+};
+for(var i=0;
+i<orders.length;
+i++){appendOrder(orders[i]);
+}}popupDom.open();
+};
+Exhibit.OrderedViewFrame.prototype._reSort=function(index,propertyID,forward,ascending,slice){var oldOrders=this._getOrders();
+index=(index<0)?oldOrders.length:index;
+var newOrders=oldOrders.slice(0,index);
+newOrders.push({property:propertyID,forward:forward,ascending:ascending});
+if(!slice){newOrders=newOrders.concat(oldOrders.slice(index+1));
+}var property=this._uiContext.getDatabase().getProperty(propertyID);
+var propertyLabel=forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._orders=newOrders;
+self.parentReconstruct();
+},function(){self._orders=oldOrders;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.formatSortActionTitle(propertyLabel,ascending?sortLabels.ascending:sortLabels.descending));
+};
+Exhibit.OrderedViewFrame.prototype._removeOrder=function(index){var oldOrders=this._getOrders();
+var newOrders=oldOrders.slice(0,index).concat(oldOrders.slice(index+1));
+var order=oldOrders[index];
+var property=this._uiContext.getDatabase().getProperty(order.property);
+var propertyLabel=order.forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=order.forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._orders=newOrders;
+self.parentReconstruct();
+},function(){self._orders=oldOrders;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle(propertyLabel,order.ascending?sortLabels.ascending:sortLabels.descending));
+};
+Exhibit.OrderedViewFrame.prototype._setShowAll=function(showAll){var self=this;
+var settings=this._settings;
+SimileAjax.History.addLengthyAction(function(){settings.showAll=showAll;
+self.parentReconstruct();
+},function(){settings.showAll=!showAll;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[showAll?"showAllActionTitle":"dontShowAllActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._toggleGroup=function(){var settings=this._settings;
+var oldGrouped=settings.grouped;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.grouped=!oldGrouped;
+self.parentReconstruct();
+},function(){settings.grouped=oldGrouped;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[oldGrouped?"ungroupAsSortedActionTitle":"groupAsSortedActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._toggleShowDuplicates=function(){var settings=this._settings;
+var oldShowDuplicates=settings.showDuplicates;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.showDuplicates=!oldShowDuplicates;
+self.parentReconstruct();
+},function(){settings.showDuplicates=oldShowDuplicates;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[oldShowDuplicates?"hideDuplicatesActionTitle":"showDuplicatesActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._gotoPage=function(pageIndex){var settings=this._settings;
+var oldPageIndex=settings.page;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.page=pageIndex;
+self.parentReconstruct();
+},function(){settings.page=oldPageIndex;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(pageIndex));
+};
+Exhibit.OrderedViewFrame.headerTemplate="<div id='collectionSummaryDiv' style='display: none;'></div><div class='exhibit-collectionView-header-sortControls' style='display: none;' id='controlsDiv'>%0<span class='exhibit-collectionView-header-groupControl'> \u2022 <a id='groupOption' class='exhibit-action'></a></span></div>";
+Exhibit.OrderedViewFrame.createHeaderDom=function(uiContext,headerDiv,showSummary,showControls,onThenSortBy,onGroupToggle,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+var template=String.substitute(Exhibit.OrderedViewFrame.headerTemplate+"<"+l10n.pagingControlContainerElement+" class='exhibit-collectionView-pagingControls' style='display: none;' id='topPagingDiv'></"+l10n.pagingControlContainerElement+">",[l10n.sortingControlsTemplate]);
+var dom=SimileAjax.DOM.createDOMFromString(headerDiv,template,{});
+headerDiv.className="exhibit-collectionView-header";
+if(showSummary){dom.collectionSummaryDiv.style.display="block";
+dom.collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},dom.collectionSummaryDiv,uiContext);
+}if(showControls){dom.controlsDiv.style.display="block";
+dom.groupOptionWidget=Exhibit.OptionWidget.create({label:l10n.groupedAsSortedOptionLabel,onToggle:onGroupToggle},dom.groupOption,uiContext);
+SimileAjax.WindowManager.registerEvent(dom.thenSortByAction,"click",onThenSortBy);
+dom.enableThenByAction=function(enabled){Exhibit.UI.enableActionLink(dom.thenSortByAction,enabled);
+};
+dom.setOrders=function(orderElmts){dom.ordersSpan.innerHTML="";
+var addDelimiter=Exhibit.Formatter.createListDelimiter(dom.ordersSpan,orderElmts.length,uiContext);
+for(var i=0;
+i<orderElmts.length;
+i++){addDelimiter();
+dom.ordersSpan.appendChild(orderElmts[i]);
+}addDelimiter();
+};
+}dom.renderPageLinks=function(page,totalPage,pageWindow){Exhibit.OrderedViewFrame.renderPageLinks(dom.topPagingDiv,page,totalPage,pageWindow,gotoPage);
+dom.topPagingDiv.style.display="block";
+};
+dom.hidePageLinks=function(){dom.topPagingDiv.style.display="none";
+};
+dom.dispose=function(){if("collectionSummaryWidget" in dom){dom.collectionSummaryWidget.dispose();
+dom.collectionSummaryWidget=null;
+}dom.groupOptionWidget.dispose();
+dom.groupOptionWidget=null;
+};
+return dom;
+};
+Exhibit.OrderedViewFrame.footerTemplate="<div id='showAllSpan'></div>";
+Exhibit.OrderedViewFrame.createFooterDom=function(uiContext,footerDiv,onShowAll,onDontShowAll,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+var dom=SimileAjax.DOM.createDOMFromString(footerDiv,Exhibit.OrderedViewFrame.footerTemplate+"<"+l10n.pagingControlContainerElement+" class='exhibit-collectionView-pagingControls' style='display: none;' id='bottomPagingDiv'></"+l10n.pagingControlContainerElement+">",{});
+footerDiv.className="exhibit-collectionView-footer";
+dom.setCounts=function(count,limitCount,showAll,canToggle){dom.showAllSpan.innerHTML="";
+if(canToggle&&count>limitCount){dom.showAllSpan.style.display="block";
+if(showAll){dom.showAllSpan.appendChild(Exhibit.UI.makeActionLink(l10n.formatDontShowAll(limitCount),onDontShowAll));
+}else{dom.showAllSpan.appendChild(Exhibit.UI.makeActionLink(l10n.formatShowAll(count),onShowAll));
+}}};
+dom.renderPageLinks=function(page,totalPage,pageWindow){Exhibit.OrderedViewFrame.renderPageLinks(dom.bottomPagingDiv,page,totalPage,pageWindow,gotoPage);
+dom.bottomPagingDiv.style.display="block";
+dom.showAllSpan.style.display="none";
+};
+dom.hidePageLinks=function(){dom.bottomPagingDiv.style.display="none";
+};
+dom.dispose=function(){};
+return dom;
+};
+Exhibit.OrderedViewFrame.renderPageLinks=function(parentElmt,page,pageCount,pageWindow,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+parentElmt.className="exhibit-collectionView-pagingControls";
+parentElmt.innerHTML="";
+var self=this;
+var renderPageLink=function(label,index){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.className="exhibit-collectionView-pagingControls-page";
+parentElmt.appendChild(elmt);
+var a=document.createElement("a");
+a.innerHTML=label;
+a.href="javascript:{}";
+a.title=l10n.makePagingLinkTooltip(index);
+elmt.appendChild(a);
+var handler=function(elmt,evt,target){gotoPage(index);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler);
+};
+var renderPageNumber=function(index){if(index==page){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.className="exhibit-collectionView-pagingControls-currentPage";
+elmt.innerHTML=(index+1);
+parentElmt.appendChild(elmt);
+}else{renderPageLink(index+1,index);
+}};
+var renderHTML=function(html){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.innerHTML=html;
+parentElmt.appendChild(elmt);
+};
+if(page>0){renderPageLink(l10n.previousPage,page-1);
+if(l10n.pageSeparator.length>0){renderHTML(" ");
+}}var pageWindowStart=0;
+var pageWindowEnd=pageCount-1;
+if(page-pageWindow>1){renderPageNumber(0);
+renderHTML(l10n.pageWindowEllipses);
+pageWindowStart=page-pageWindow;
+}if(page+pageWindow<pageCount-2){pageWindowEnd=page+pageWindow;
+}for(var i=pageWindowStart;
+i<=pageWindowEnd;
+i++){if(i>pageWindowStart&&l10n.pageSeparator.length>0){renderHTML(l10n.pageSeparator);
+}renderPageNumber(i);
+}if(pageWindowEnd<pageCount-1){renderHTML(l10n.pageWindowEllipses);
+renderPageNumber(pageCount-1);
+}if(page<pageCount-1){if(l10n.pageSeparator.length>0){renderHTML(" ");
+}renderPageLink(l10n.nextPage,page+1);
+}};
+
+
+/* tabular-view.js */
+Exhibit.TabularView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={rowStyler:null,tableStyler:null};
+this._columns=[];
+this._rowTemplate=null;
+var view=this;
+this._listener={onItemsChanged:function(){view._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.TabularView._settingSpecs={"sortAscending":{type:"boolean",defaultValue:true},"sortColumn":{type:"int",defaultValue:0},"showSummary":{type:"boolean",defaultValue:true},"showToolbox":{type:"boolean",defaultValue:true},"border":{type:"int",defaultValue:1},"cellPadding":{type:"int",defaultValue:5},"cellSpacing":{type:"int",defaultValue:3},"paginate":{type:"boolean",defaultValue:false},"pageSize":{type:"int",defaultValue:20},"pageWindow":{type:"int",defaultValue:2},"page":{type:"int",defaultValue:0},"alwaysShowPagingControls":{type:"boolean",defaultValue:false},"pagingControlLocations":{type:"enum",defaultValue:"topbottom",choices:["top","bottom","topbottom"]}};
+Exhibit.TabularView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.TabularView(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.TabularView._configure(view,configuration);
+view._internalValidate();
+view._initializeUI();
+return view;
+};
+Exhibit.TabularView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var view=new Exhibit.TabularView(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TabularView._settingSpecs,view._settings);
+try{var expressions=[];
+var labels=Exhibit.getAttribute(configElmt,"columnLabels",",")||[];
+var s=Exhibit.getAttribute(configElmt,"columns");
+if(s!=null&&s.length>0){expressions=Exhibit.ExpressionParser.parseSeveral(s);
+}for(var i=0;
+i<expressions.length;
+i++){var expression=expressions[i];
+view._columns.push({expression:expression,uiContext:Exhibit.UIContext.create({},view._uiContext,true),styler:null,label:i<labels.length?labels[i]:null,format:"list"});
+}var formats=Exhibit.getAttribute(configElmt,"columnFormats");
+if(formats!=null&&formats.length>0){var index=0;
+var startPosition=0;
+while(index<view._columns.length&&startPosition<formats.length){var column=view._columns[index];
+var o={};
+column.format=Exhibit.FormatParser.parseSeveral(column.uiContext,formats,startPosition,o);
+startPosition=o.index;
+while(startPosition<formats.length&&" \t\r\n".indexOf(formats.charAt(startPosition))>=0){startPosition++;
+}if(startPosition<formats.length&&formats.charAt(startPosition)==","){startPosition++;
+}index++;
+}}var tables=configElmt.getElementsByTagName("table");
+if(tables.length>0&&tables[0].rows.length>0){view._rowTemplate=Exhibit.Lens.compileTemplate(tables[0].rows[0],false,uiContext);
+}}catch(e){SimileAjax.Debug.exception(e,"TabularView: Error processing configuration of tabular view");
+}var s=Exhibit.getAttribute(configElmt,"rowStyler");
+if(s!=null&&s.length>0){var f=eval(s);
+if(typeof f=="function"){view._settings.rowStyler=f;
+}}s=Exhibit.getAttribute(configElmt,"tableStyler");
+if(s!=null&&s.length>0){f=eval(s);
+if(typeof f=="function"){view._settings.tableStyler=f;
+}}Exhibit.TabularView._configure(view,configuration);
+view._internalValidate();
+view._initializeUI();
+return view;
+};
+Exhibit.TabularView._configure=function(view,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TabularView._settingSpecs,view._settings);
+if("columns" in configuration){var columns=configuration.columns;
+for(var i=0;
+i<columns.length;
+i++){var column=columns[i];
+var expr;
+var styler=null;
+var label=null;
+var format=null;
+if(typeof column=="string"){expr=column;
+}else{expr=column.expression;
+styler=column.styler;
+label=column.label;
+format=column.format;
+}var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(format!=null&&format.length>0){format=Exhibit.FormatParser.parse(view._uiContext,format,0);
+}else{format="list";
+}view._columns.push({expression:expression,styler:styler,label:label,format:format,uiContext:view._uiContext});
+}}}if("rowStyler" in configuration){view._settings.rowStyler=configuration.rowStyler;
+}if("tableStyler" in configuration){view._settings.tableStyler=configuration.tableStyler;
+}};
+Exhibit.TabularView.prototype._internalValidate=function(){if(this._columns.length==0){var database=this._uiContext.getDatabase();
+var propertyIDs=database.getAllProperties();
+for(var i=0;
+i<propertyIDs.length;
+i++){var propertyID=propertyIDs[i];
+if(propertyID!="uri"){this._columns.push({expression:Exhibit.ExpressionParser.parse("."+propertyID),styler:null,label:database.getProperty(propertyID).getLabel(),format:"list"});
+}}}this._settings.sortColumn=Math.max(0,Math.min(this._settings.sortColumn,this._columns.length-1));
+};
+Exhibit.TabularView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._collectionSummaryWidget.dispose();
+this._collectionSummaryWidget=null;
+this._uiContext.dispose();
+this._uiContext=null;
+this._div.innerHTML="";
+this._dom=null;
+this._div=null;
+};
+Exhibit.TabularView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+this._dom=Exhibit.TabularView.createDom(this._div);
+this._collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},this._dom.collectionSummaryDiv,this._uiContext);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}if(!this._settings.showSummary){this._dom.collectionSummaryDiv.style.display="none";
+}this._reconstruct();
+};
+Exhibit.TabularView.prototype._reconstruct=function(){var self=this;
+var collection=this._uiContext.getCollection();
+var database=this._uiContext.getDatabase();
+var bodyDiv=this._dom.bodyDiv;
+bodyDiv.innerHTML="";
+var items=[];
+var originalSize=collection.countAllItems();
+if(originalSize>0){var currentSet=collection.getRestrictedItems();
+currentSet.visit(function(itemID){items.push({id:itemID,sortKey:""});
+});
+}if(items.length>0){var sortColumn=this._columns[this._settings.sortColumn];
+items.sort(this._createSortFunction(items,sortColumn.expression,this._settings.sortAscending));
+var table=document.createElement("table");
+table.className="exhibit-tabularView-body";
+if(this._settings.tableStyler!=null){this._settings.tableStyler(table,database);
+}else{table.cellSpacing=this._settings.cellSpacing;
+table.cellPadding=this._settings.cellPadding;
+table.border=this._settings.border;
+}var tr=table.insertRow(0);
+var createColumnHeader=function(i){var column=self._columns[i];
+if(column.label==null){column.label=self._getColumnLabel(column.expression);
+}var td=document.createElement("th");
+Exhibit.TabularView.createColumnHeader(exhibit,td,column.label,i==self._settings.sortColumn,self._settings.sortAscending,function(elmt,evt,target){self._doSort(i);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+});
+tr.appendChild(td);
+};
+for(var i=0;
+i<this._columns.length;
+i++){createColumnHeader(i);
+}var renderItem;
+if(this._rowTemplate!=null){renderItem=function(i){var item=items[i];
+var tr=Exhibit.Lens.constructFromLensTemplate(item.id,self._rowTemplate,table,self._uiContext);
+if(self._settings.rowStyler!=null){self._settings.rowStyler(item.id,database,tr,i);
+}};
+}else{renderItem=function(i){var item=items[i];
+var tr=table.insertRow(table.rows.length);
+for(var c=0;
+c<self._columns.length;
+c++){var column=self._columns[c];
+var td=tr.insertCell(c);
+var results=column.expression.evaluate({"value":item.id},{"value":"item"},"value",database);
+var valueType=column.format=="list"?results.valueType:column.format;
+column.uiContext.formatList(results.values,results.size,valueType,function(elmt){td.appendChild(elmt);
+});
+if(column.styler!=null){column.styler(item.id,database,td);
+}}if(self._settings.rowStyler!=null){self._settings.rowStyler(item.id,database,tr,i);
+}};
+}var start,end;
+var generatePagingControls=false;
+if(this._settings.paginate){start=this._settings.page*this._settings.pageSize;
+end=Math.min(start+this._settings.pageSize,items.length);
+generatePagingControls=(items.length>this._settings.pageSize)||(items.length>0&&this._settings.alwaysShowPagingControls);
+}else{start=0;
+end=items.length;
+}for(var i=start;
+i<end;
+i++){renderItem(i);
+}bodyDiv.appendChild(table);
+if(generatePagingControls){if(this._settings.pagingControlLocations=="top"||this._settings.pagingControlLocations=="topbottom"){this._renderPagingDiv(this._dom.topPagingDiv,items.length,this._settings.page);
+this._dom.topPagingDiv.style.display="block";
+}if(this._settings.pagingControlLocations=="bottom"||this._settings.pagingControlLocations=="topbottom"){this._renderPagingDiv(this._dom.bottomPagingDiv,items.length,this._settings.page);
+this._dom.bottomPagingDiv.style.display="block";
+}}else{this._dom.topPagingDiv.style.display="none";
+this._dom.bottomPagingDiv.style.display="none";
+}}};
+Exhibit.TabularView.prototype._renderPagingDiv=function(parentElmt,itemCount,page){var pageCount=Math.ceil(itemCount/this._settings.pageSize);
+var self=this;
+Exhibit.OrderedViewFrame.renderPageLinks(parentElmt,page,pageCount,this._settings.pageWindow,function(p){self._gotoPage(p);
+});
+};
+Exhibit.TabularView.prototype._getColumnLabel=function(expression){var database=this._uiContext.getDatabase();
+var path=expression.getPath();
+var segment=path.getSegment(path.getSegmentCount()-1);
+var propertyID=segment.property;
+var property=database.getProperty(propertyID);
+if(property!=null){return segment.forward?property.getLabel():property.getReverseLabel();
+}else{return propertyID;
+}};
+Exhibit.TabularView.prototype._createSortFunction=function(items,expression,ascending){var database=this._uiContext.getDatabase();
+var multiply=ascending?1:-1;
+var numericFunction=function(item1,item2){return multiply*(item1.sortKey-item2.sortKey);
+};
+var textFunction=function(item1,item2){return multiply*item1.sortKey.localeCompare(item2.sortKey);
+};
+var valueTypes=[];
+var valueTypeMap={};
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+var r=expression.evaluate({"value":item.id},{"value":"item"},"value",database);
+r.values.visit(function(value){item.sortKey=value;
+});
+if(!(r.valueType in valueTypeMap)){valueTypeMap[r.valueType]=true;
+valueTypes.push(r.valueType);
+}}var coercedValueType="text";
+if(valueTypes.length==1){coercedValueType=valueTypes[0];
+}else{coercedValueType="text";
+}var coersion;
+var sortingFunction;
+if(coercedValueType=="number"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(typeof v=="number"){return v;
+}else{var n=parseFloat(v);
+if(isNaN(n)){return Number.NEGATIVE_INFINITY;
+}else{return n;
+}}}};
+}else{if(coercedValueType=="date"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(v instanceof Date){return v.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+}catch(e){return Number.NEGATIVE_INFINITY;
+}}}};
+}else{if(coercedValueType=="boolean"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(typeof v=="boolean"){return v?1:0;
+}else{return v.toString().toLowerCase()=="true";
+}}};
+}else{if(coercedValueType=="item"){sortingFunction=textFunction;
+coersion=function(v){if(v==null){return Exhibit.l10n.missingSortKey;
+}else{var label=database.getObject(v,"label");
+return(label==null)?v:label;
+}};
+}else{sortingFunction=textFunction;
+coersion=function(v){if(v==null){return Exhibit.l10n.missingSortKey;
+}else{return v.toString();
+}};
+}}}}for(var i=0;
+i<items.length;
+i++){var item=items[i];
+item.sortKey=coersion(item.sortKey);
+}return sortingFunction;
+};
+Exhibit.TabularView.prototype._doSort=function(columnIndex){var oldSortColumn=this._settings.sortColumn;
+var oldSortAscending=this._settings.sortAscending;
+var newSortColumn=columnIndex;
+var newSortAscending=oldSortColumn==newSortColumn?!oldSortAscending:true;
+var oldPage=this._settings.page;
+var newPage=0;
+var settings=this._settings;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.sortColumn=newSortColumn;
+settings.sortAscending=newSortAscending;
+settings.page=newPage;
+self._reconstruct();
+},function(){settings.sortColumn=oldSortColumn;
+settings.sortAscending=oldSortAscending;
+settings.page=oldPage;
+self._reconstruct();
+},Exhibit.TabularView.l10n.makeSortActionTitle(this._columns[columnIndex].label,newSortAscending));
+};
+Exhibit.TabularView.prototype._gotoPage=function(page){var oldPage=this._settings.page;
+var newPage=page;
+var settings=this._settings;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.page=newPage;
+self._reconstruct();
+},function(){settings.page=oldPage;
+self._reconstruct();
+},Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(page));
+};
+Exhibit.TabularView._constructDefaultValueList=function(values,valueType,parentElmt,uiContext){uiContext.formatList(values,values.size(),valueType,function(elmt){parentElmt.appendChild(elmt);
+});
+};
+Exhibit.TabularView.createDom=function(div){var l10n=Exhibit.TabularView.l10n;
+var l10n2=Exhibit.OrderedViewFrame.l10n;
+var headerTemplate={elmt:div,className:"exhibit-collectionView-header",children:[{tag:"div",field:"collectionSummaryDiv"},{tag:l10n2.pagingControlContainerElement,className:"exhibit-tabularView-pagingControls",field:"topPagingDiv"},{tag:"div",field:"bodyDiv"},{tag:l10n2.pagingControlContainerElement,className:"exhibit-tabularView-pagingControls",field:"bottomPagingDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(headerTemplate);
+};
+Exhibit.TabularView.createColumnHeader=function(exhibit,th,label,sort,sortAscending,sortFunction){var l10n=Exhibit.TabularView.l10n;
+var template={elmt:th,className:sort?"exhibit-tabularView-columnHeader-sorted":"exhibit-tabularView-columnHeader",title:sort?l10n.columnHeaderReSortTooltip:l10n.columnHeaderSortTooltip,children:[label]};
+if(sort){template.children.push({elmt:Exhibit.UI.createTranslucentImage(sortAscending?"images/up-arrow.png":"images/down-arrow.png")});
+}SimileAjax.WindowManager.registerEvent(th,"click",sortFunction,null);
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+return dom;
+};
+
+
+/* thumbnail-view.js */
+Exhibit.ThumbnailView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+var view=this;
+this._listener={onItemsChanged:function(){view._orderedViewFrame._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+this._orderedViewFrame=new Exhibit.OrderedViewFrame(uiContext);
+this._orderedViewFrame.parentReconstruct=function(){view._reconstruct();
+};
+};
+Exhibit.ThumbnailView._settingSpecs={"showToolbox":{type:"boolean",defaultValue:true},"columnCount":{type:"int",defaultValue:-1}};
+Exhibit.ThumbnailView._itemContainerClass=SimileAjax.Platform.browser.isIE?"exhibit-thumbnailView-itemContainer-IE":"exhibit-thumbnailView-itemContainer";
+Exhibit.ThumbnailView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.ThumbnailView(containerElmt,Exhibit.UIContext.create(configuration,uiContext,true));
+view._lensRegistry=Exhibit.UIContext.createLensRegistry(configuration,uiContext.getLensRegistry());
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ThumbnailView._settingSpecs,view._settings);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.ThumbnailView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var view=new Exhibit.ThumbnailView(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext,true));
+view._lensRegistry=Exhibit.UIContext.createLensRegistryFromDOM(configElmt,configuration,uiContext.getLensRegistry());
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ThumbnailView._settingSpecs,view._settings);
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ThumbnailView._settingSpecs,view._settings);
+view._orderedViewFrame.configureFromDOM(configElmt);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.ThumbnailView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._orderedViewFrame.dispose();
+this._orderedViewFrame=null;
+this._lensRegistry=null;
+this._dom=null;
+this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.ThumbnailView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+var template={elmt:this._div,children:[{tag:"div",field:"headerDiv"},{tag:"div",className:"exhibit-collectionView-body",field:"bodyDiv"},{tag:"div",field:"footerDiv"}]};
+this._dom=SimileAjax.DOM.createDOMFromTemplate(template);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}this._orderedViewFrame._divHeader=this._dom.headerDiv;
+this._orderedViewFrame._divFooter=this._dom.footerDiv;
+this._orderedViewFrame._generatedContentElmtRetriever=function(){return self._dom.bodyDiv;
+};
+this._orderedViewFrame.initializeUI();
+this._reconstruct();
+};
+Exhibit.ThumbnailView.prototype._reconstruct=function(){if(this._settings.columnCount<2){this._reconstructWithFloats();
+}else{this._reconstructWithTable();
+}};
+Exhibit.ThumbnailView.prototype._reconstructWithFloats=function(){var view=this;
+var state={div:this._dom.bodyDiv,itemContainer:null,groupDoms:[],groupCounts:[]};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.itemContainer=null;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.ThumbnailView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.itemContainer==null){state.itemContainer=Exhibit.ThumbnailView.constructItemContainer();
+state.div.appendChild(state.itemContainer);
+}for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensDiv=document.createElement("div");
+itemLensDiv.className=Exhibit.ThumbnailView._itemContainerClass;
+var itemLens=view._lensRegistry.createLens(itemID,itemLensDiv,view._uiContext);
+state.itemContainer.appendChild(itemLensDiv);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.ThumbnailView.prototype._reconstructWithTable=function(){var view=this;
+var state={div:this._dom.bodyDiv,groupDoms:[],groupCounts:[],table:null,columnIndex:0};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.itemContainer=null;
+state.table=null;
+state.columnIndex=0;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.ThumbnailView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.columnIndex>=view._settings.columnCount){state.columnIndex=0;
+}if(state.table==null){state.table=Exhibit.ThumbnailView.constructTableItemContainer();
+state.div.appendChild(state.table);
+}if(state.columnIndex==0){state.table.insertRow(state.table.rows.length);
+}var td=state.table.rows[state.table.rows.length-1].insertCell(state.columnIndex++);
+for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensDiv=document.createElement("div");
+itemLensDiv.className=Exhibit.ThumbnailView._itemContainerClass;
+var itemLens=view._lensRegistry.createLens(itemID,itemLensDiv,view._uiContext);
+td.appendChild(itemLensDiv);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.ThumbnailView.constructGroup=function(groupLevel,label){var l10n=Exhibit.ThumbnailView.l10n;
+var template={tag:"div",className:"exhibit-thumbnailView-group",children:[{tag:"h"+(groupLevel+1),children:[label,{tag:"span",className:"exhibit-collectionView-group-count",children:[" (",{tag:"span",field:"countSpan"},")"]}],field:"header"},{tag:"div",className:"exhibit-collectionView-group-content",field:"contentDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+Exhibit.ThumbnailView.constructItemContainer=function(){var div=document.createElement("div");
+div.className="exhibit-thumbnailView-body";
+return div;
+};
+Exhibit.ThumbnailView.constructTableItemContainer=function(){var table=document.createElement("table");
+table.className="exhibit-thumbnailView-body";
+return table;
+};
+
+
+/* tile-view.js */
+Exhibit.TileView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+var view=this;
+this._listener={onItemsChanged:function(){view._orderedViewFrame._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+this._orderedViewFrame=new Exhibit.OrderedViewFrame(uiContext);
+this._orderedViewFrame.parentReconstruct=function(){view._reconstruct();
+};
+};
+Exhibit.TileView._settingSpecs={"showToolbox":{type:"boolean",defaultValue:true}};
+Exhibit.TileView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.TileView(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TileView._settingSpecs,view._settings);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.TileView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var view=new Exhibit.TileView(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TileView._settingSpecs,view._settings);
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TileView._settingSpecs,view._settings);
+view._orderedViewFrame.configureFromDOM(configElmt);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.TileView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+this._div.innerHTML="";
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._orderedViewFrame.dispose();
+this._orderedViewFrame=null;
+this._dom=null;
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.TileView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+var template={elmt:this._div,children:[{tag:"div",field:"headerDiv"},{tag:"div",className:"exhibit-collectionView-body",field:"bodyDiv"},{tag:"div",field:"footerDiv"}]};
+this._dom=SimileAjax.DOM.createDOMFromTemplate(template);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}this._orderedViewFrame._divHeader=this._dom.headerDiv;
+this._orderedViewFrame._divFooter=this._dom.footerDiv;
+this._orderedViewFrame._generatedContentElmtRetriever=function(){return self._dom.bodyDiv;
+};
+this._orderedViewFrame.initializeUI();
+this._reconstruct();
+};
+Exhibit.TileView.prototype._reconstruct=function(){var view=this;
+var state={div:this._dom.bodyDiv,contents:null,groupDoms:[],groupCounts:[]};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.contents=null;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.TileView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.contents==null){state.contents=Exhibit.TileView.constructList();
+state.div.appendChild(state.contents);
+}for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensItem=document.createElement("li");
+var itemLens=view._uiContext.getLensRegistry().createLens(itemID,itemLensItem,view._uiContext);
+state.contents.appendChild(itemLensItem);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.TileView.constructGroup=function(groupLevel,label){var template={tag:"div",className:"exhibit-collectionView-group",children:[{tag:"h"+(groupLevel+1),children:[label,{tag:"span",className:"exhibit-collectionView-group-count",children:[" (",{tag:"span",field:"countSpan"},")"]}],field:"header"},{tag:"div",className:"exhibit-collectionView-group-content",field:"contentDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+Exhibit.TileView.constructList=function(){var div=document.createElement("ol");
+div.className="exhibit-tileView-body";
+return div;
+};
+
+
+/* view-panel.js */
+Exhibit.ViewPanel=function(div,uiContext){this._uiContext=uiContext;
+this._div=div;
+this._uiContextCache={};
+this._viewConstructors=[];
+this._viewConfigs=[];
+this._viewLabels=[];
+this._viewTooltips=[];
+this._viewDomConfigs=[];
+this._viewIDs=[];
+this._viewIndex=0;
+this._view=null;
+};
+Exhibit.ViewPanel.create=function(configuration,div,uiContext){var viewPanel=new Exhibit.ViewPanel(div,uiContext);
+if("views" in configuration){for(var i=0;
+i<configuration.views.length;
+i++){var viewConfig=configuration.views[i];
+var viewClass=("viewClass" in view)?view.viewClass:Exhibit.TileView;
+if(typeof viewClass=="string"){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClass);
+}var label=null;
+if("viewLabel" in viewConfig){label=viewConfig.viewLabel;
+}else{if("label" in viewConfig){label=viewConfig.label;
+}else{if("l10n" in viewClass&&"viewLabel" in viewClass.l10n){label=viewClass.l10n.viewLabel;
+}else{label=""+viewClass;
+}}}var tooltip=null;
+if("tooltip" in viewConfig){tooltip=viewConfig.tooltip;
+}else{if("l10n" in viewClass&&"viewTooltip" in viewClass.l10n){tooltip=viewClass.l10n.viewTooltip;
+}else{tooltip=label;
+}}var id=viewPanel._generateViewID();
+if("id" in viewConfig){id=viewConfig.id;
+}viewPanel._viewConstructors.push(viewClass);
+viewPanel._viewConfigs.push(viewConfig);
+viewPanel._viewLabels.push(label);
+viewPanel._viewTooltips.push(tooltip);
+viewPanel._viewDomConfigs.push(null);
+viewPanel._viewIDs.push(id);
+}}if("initialView" in configuration){viewPanel._viewIndex=configuration.initialView;
+}viewPanel._internalValidate();
+viewPanel._initializeUI();
+return viewPanel;
+};
+Exhibit.ViewPanel.createFromDOM=function(div,uiContext){var viewPanel=new Exhibit.ViewPanel(div,Exhibit.UIContext.createFromDOM(div,uiContext,false));
+var node=div.firstChild;
+while(node!=null){if(node.nodeType==1){node.style.display="none";
+var role=Exhibit.getRoleAttribute(node);
+if(role=="view"){var viewClass=Exhibit.TileView;
+var viewClassString=Exhibit.getAttribute(node,"viewClass");
+if(viewClassString!=null&&viewClassString.length>0){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClassString);
+if(viewClass==null){SimileAjax.Debug.warn("Unknown viewClass "+viewClassString);
+}}var viewLabel=Exhibit.getAttribute(node,"viewLabel");
+var label=(viewLabel!=null&&viewLabel.length>0)?viewLabel:Exhibit.getAttribute(node,"label");
+var tooltip=Exhibit.getAttribute(node,"title");
+var id=node.id;
+if(label==null){if("viewLabel" in viewClass.l10n){label=viewClass.l10n.viewLabel;
+}else{label=""+viewClass;
+}}if(tooltip==null){if("l10n" in viewClass&&"viewTooltip" in viewClass.l10n){tooltip=viewClass.l10n.viewTooltip;
+}else{tooltip=label;
+}}if(id==null||id.length==0){id=viewPanel._generateViewID();
+}viewPanel._viewConstructors.push(viewClass);
+viewPanel._viewConfigs.push(null);
+viewPanel._viewLabels.push(label);
+viewPanel._viewTooltips.push(tooltip);
+viewPanel._viewDomConfigs.push(node);
+viewPanel._viewIDs.push(id);
+}}node=node.nextSibling;
+}var initialView=Exhibit.getAttribute(div,"initialView");
+if(initialView!=null&&initialView.length>0){try{var n=parseInt(initialView);
+if(!isNaN(n)){viewPanel._viewIndex=n;
+}}catch(e){}}viewPanel._internalValidate();
+viewPanel._initializeUI();
+return viewPanel;
+};
+Exhibit.ViewPanel.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._view!=null){this._view.dispose();
+this._view=null;
+}this._div.innerHTML="";
+this._uiContext.dispose();
+this._uiContext=null;
+this._div=null;
+};
+Exhibit.ViewPanel.prototype._generateViewID=function(){return"view"+Math.floor(Math.random()*1000000).toString();
+};
+Exhibit.ViewPanel.prototype._internalValidate=function(){if(this._viewConstructors.length==0){this._viewConstructors.push(Exhibit.TileView);
+this._viewConfigs.push({});
+this._viewLabels.push(Exhibit.TileView.l10n.viewLabel);
+this._viewTooltips.push(Exhibit.TileView.l10n.viewTooltip);
+this._viewDomConfigs.push(null);
+this._viewIDs.push(this._generateViewID());
+}this._viewIndex=Math.max(0,Math.min(this._viewIndex,this._viewConstructors.length-1));
+};
+Exhibit.ViewPanel.prototype._initializeUI=function(){var div=document.createElement("div");
+if(this._div.firstChild!=null){this._div.insertBefore(div,this._div.firstChild);
+}else{this._div.appendChild(div);
+}var self=this;
+this._dom=Exhibit.ViewPanel.constructDom(this._div.firstChild,this._viewLabels,this._viewTooltips,function(index){self._selectView(index);
+});
+this._createView();
+};
+Exhibit.ViewPanel.prototype._createView=function(){var viewContainer=this._dom.getViewContainer();
+viewContainer.innerHTML="";
+var viewDiv=document.createElement("div");
+viewContainer.appendChild(viewDiv);
+var index=this._viewIndex;
+var context=this._uiContextCache[index]||this._uiContext;
+try{if(this._viewDomConfigs[index]!=null){this._view=this._viewConstructors[index].createFromDOM(this._viewDomConfigs[index],viewContainer,context);
+}else{this._view=this._viewConstructors[index].create(this._viewConfigs[index],viewContainer,context);
+}}catch(e){SimileAjax.Debug.log("Failed to create view "+this._viewLabels[index]);
+SimileAjax.Debug.exception(e);
+}this._uiContextCache[index]=this._view._uiContext;
+this._uiContext.getExhibit().setComponent(this._viewIDs[index],this._view);
+this._dom.setViewIndex(index);
+};
+Exhibit.ViewPanel.prototype._switchView=function(newIndex){if(this._view){this._uiContext.getExhibit().disposeComponent(this._viewIDs[this._viewIndex]);
+this._view=null;
+}this._viewIndex=newIndex;
+this._createView();
+};
+Exhibit.ViewPanel.prototype._selectView=function(newIndex){var oldIndex=this._viewIndex;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._switchView(newIndex);
+},function(){self._switchView(oldIndex);
+},Exhibit.ViewPanel.l10n.createSelectViewActionTitle(self._viewLabels[newIndex]));
+};
+Exhibit.ViewPanel.getPropertyValuesPairs=function(itemID,propertyEntries,database){var pairs=[];
+var enterPair=function(propertyID,forward){var property=database.getProperty(propertyID);
+var values=forward?database.getObjects(itemID,propertyID):database.getSubjects(itemID,propertyID);
+var count=values.size();
+if(count>0){var itemValues=property.getValueType()=="item";
+var pair={propertyLabel:forward?(count>1?property.getPluralLabel():property.getLabel()):(count>1?property.getReversePluralLabel():property.getReverseLabel()),valueType:property.getValueType(),values:[]};
+if(itemValues){values.visit(function(value){var label=database.getObject(value,"label");
+pair.values.push(label!=null?label:value);
+});
+}else{values.visit(function(value){pair.values.push(value);
+});
+}pairs.push(pair);
+}};
+for(var i=0;
+i<propertyEntries.length;
+i++){var entry=propertyEntries[i];
+if(typeof entry=="string"){enterPair(entry,true);
+}else{enterPair(entry.property,entry.forward);
+}}return pairs;
+};
+Exhibit.ViewPanel.constructDom=function(div,viewLabels,viewTooltips,onSelectView){var l10n=Exhibit.ViewPanel.l10n;
+var template={elmt:div,className:"exhibit-viewPanel exhibit-ui-protection",children:[{tag:"div",className:"exhibit-viewPanel-viewSelection",field:"viewSelectionDiv"},{tag:"div",className:"exhibit-viewPanel-viewContainer",field:"viewContainerDiv"}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.getViewContainer=function(){return dom.viewContainerDiv;
+};
+dom.setViewIndex=function(index){if(viewLabels.length>1){dom.viewSelectionDiv.innerHTML="";
+var appendView=function(i){var selected=(i==index);
+if(i>0){dom.viewSelectionDiv.appendChild(document.createTextNode(" \u2022 "));
+}var span=document.createElement("span");
+span.className=selected?"exhibit-viewPanel-viewSelection-selectedView":"exhibit-viewPanel-viewSelection-view";
+span.title=viewTooltips[i];
+span.innerHTML=viewLabels[i];
+if(!selected){var handler=function(elmt,evt,target){onSelectView(i);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.WindowManager.registerEvent(span,"click",handler);
+}dom.viewSelectionDiv.appendChild(span);
+};
+for(var i=0;
+i<viewLabels.length;
+i++){appendView(i);
+}}};
+return dom;
+};
+
+
+/* collection-summary-widget.js */
+Exhibit.CollectionSummaryWidget=function(containerElmt,uiContext){this._exhibit=uiContext.getExhibit();
+this._collection=uiContext.getCollection();
+this._uiContext=uiContext;
+this._div=containerElmt;
+var widget=this;
+this._listener={onItemsChanged:function(){widget._reconstruct();
+}};
+this._collection.addListener(this._listener);
+};
+Exhibit.CollectionSummaryWidget.create=function(configuration,containerElmt,uiContext){var widget=new Exhibit.CollectionSummaryWidget(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+widget._initializeUI();
+return widget;
+};
+Exhibit.CollectionSummaryWidget.createFromDOM=function(configElmt,containerElmt,uiContext){var widget=new Exhibit.CollectionSummaryWidget(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+widget._initializeUI();
+return widget;
+};
+Exhibit.CollectionSummaryWidget.prototype.dispose=function(){this._collection.removeListener(this._listener);
+this._div.innerHTML="";
+this._noResultsDom=null;
+this._allResultsDom=null;
+this._filteredResultsDom=null;
+this._div=null;
+this._collection=null;
+this._exhibit=null;
+};
+Exhibit.CollectionSummaryWidget.prototype._initializeUI=function(){var self=this;
+var l10n=Exhibit.CollectionSummaryWidget.l10n;
+var onClearFilters=function(elmt,evt,target){self._resetCollection();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+this._allResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.allResultsTemplate,["exhibit-collectionSummaryWidget-results"]));
+this._filteredResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.filteredResultsTemplate,["exhibit-collectionSummaryWidget-results"]),{resetActionLink:Exhibit.UI.makeActionLink(l10n.resetFiltersLabel,onClearFilters)});
+this._noResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.noResultsTemplate,["exhibit-collectionSummaryWidget-results","exhibit-collectionSummaryWidget-count"]),{resetActionLink:Exhibit.UI.makeActionLink(l10n.resetFiltersLabel,onClearFilters)});
+this._div.innerHTML="";
+this._reconstruct();
+};
+Exhibit.CollectionSummaryWidget.prototype._reconstruct=function(){var originalSize=this._collection.countAllItems();
+var currentSize=this._collection.countRestrictedItems();
+var database=this._uiContext.getDatabase();
+var dom=this._dom;
+while(this._div.childNodes.length>0){this._div.removeChild(this._div.firstChild);
+}if(originalSize>0){if(currentSize==0){this._div.appendChild(this._noResultsDom.elmt);
+}else{var typeIDs=database.getTypeIDs(this._collection.getRestrictedItems()).toArray();
+var typeID=typeIDs.length==1?typeIDs[0]:"Item";
+var description=Exhibit.Database.l10n.labelItemsOfType(currentSize,typeID,database,"exhibit-collectionSummaryWidget-count");
+if(currentSize==originalSize){this._div.appendChild(this._allResultsDom.elmt);
+this._allResultsDom.resultDescription.innerHTML="";
+this._allResultsDom.resultDescription.appendChild(description);
+}else{this._div.appendChild(this._filteredResultsDom.elmt);
+this._filteredResultsDom.resultDescription.innerHTML="";
+this._filteredResultsDom.resultDescription.appendChild(description);
+this._filteredResultsDom.originalCountSpan.innerHTML=originalSize;
+}}}};
+Exhibit.CollectionSummaryWidget.prototype._resetCollection=function(){var state={};
+var collection=this._collection;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=collection.clearAllRestrictions();
+},function(){collection.applyRestrictions(state.restrictions);
+},Exhibit.CollectionSummaryWidget.l10n.resetActionTitle);
+};
+
+
+/* legend-gradient-widget.js */
+Exhibit.LegendGradientWidget=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._initializeUI();
+};
+Exhibit.LegendGradientWidget.create=function(containerElmt,uiContext){return new Exhibit.LegendGradientWidget(containerElmt,uiContext);
+};
+Exhibit.LegendGradientWidget.prototype.addGradient=function(configuration){var gradientPoints=[];
+var gradientPoints=configuration;
+var sortObj=function(a,b){return a.value-b.value;
+};
+gradientPoints.sort(sortObj);
+var theTable=document.createElement("table");
+var tableBody=document.createElement("tbody");
+var theRow1=document.createElement("tr");
+var theRow2=document.createElement("tr");
+var theRow3=document.createElement("tr");
+theRow1.style.height="2em";
+theRow2.style.height="2em";
+theRow3.style.height="2em";
+theTable.style.width="80%";
+theTable.cellSpacing="0";
+theTable.style.emptyCells="show";
+theTable.style.marginLeft="auto";
+theTable.style.marginRight="auto";
+tableBody.appendChild(theRow1);
+tableBody.appendChild(theRow2);
+tableBody.appendChild(theRow3);
+theTable.appendChild(tableBody);
+this._theRow1=theRow1;
+this._theRow2=theRow2;
+this._theRow3=theRow3;
+var globLowPoint=gradientPoints[0].value;
+var globHighPoint=gradientPoints[gradientPoints.length-1].value;
+var stepSize=(globHighPoint-globLowPoint)/50;
+var counter=0;
+for(var i=0;
+i<gradientPoints.length-1;
+i++){var lowPoint=gradientPoints[i].value;
+var highPoint=gradientPoints[i+1].value;
+var colorRect=document.createElement("td");
+colorRect.style.backgroundColor="rgb("+gradientPoints[i].red+","+gradientPoints[i].green+","+gradientPoints[i].blue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode(gradientPoints[i].value);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+theRow1.appendChild(document.createElement("td"));
+theRow2.appendChild(colorRect);
+theRow3.appendChild(numberRect);
+colorRect.onmouseover=function(){this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.style.border="none";
+};
+counter++;
+for(var j=lowPoint+stepSize;
+j<highPoint;
+j+=stepSize){var fraction=(j-lowPoint)/(highPoint-lowPoint);
+var newRed=Math.floor(gradientPoints[i].red+fraction*(gradientPoints[i+1].red-gradientPoints[i].red));
+var newGreen=Math.floor(gradientPoints[i].green+fraction*(gradientPoints[i+1].green-gradientPoints[i].green));
+var newBlue=Math.floor(gradientPoints[i].blue+fraction*(gradientPoints[i+1].blue-gradientPoints[i].blue));
+var colorRect=document.createElement("td");
+colorRect.count=counter;
+colorRect.style.backgroundColor="rgb("+newRed+","+newGreen+","+newBlue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode((Math.floor(j*100))/100);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+textDiv.style.width="2px";
+textDiv.style.overflow="hidden";
+textDiv.style.visibility="hidden";
+theRow1.appendChild(numberRect);
+theRow2.appendChild(colorRect);
+theRow3.appendChild(document.createElement("td"));
+counter++;
+colorRect.onmouseover=function(){this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="visible";
+this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="visible";
+this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="hidden";
+this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="hidden";
+this.style.border="none";
+};
+}}var high=gradientPoints.length-1;
+var colorRect=document.createElement("td");
+colorRect.style.backgroundColor="rgb("+gradientPoints[high].red+","+gradientPoints[high].green+","+gradientPoints[high].blue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode(globHighPoint);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+theRow1.appendChild(document.createElement("td"));
+theRow2.appendChild(colorRect);
+theRow3.appendChild(numberRect);
+counter++;
+colorRect.onmouseover=function(){this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.style.border="none";
+};
+this._div.appendChild(theTable);
+};
+Exhibit.LegendGradientWidget.prototype.addEntry=function(color,label){var cell=document.createElement("td");
+cell.style.width="1.5em";
+cell.style.height="2em";
+this._theRow1.appendChild(cell);
+this._theRow1.appendChild(document.createElement("td"));
+this._theRow2.appendChild(document.createElement("td"));
+this._theRow3.appendChild(document.createElement("td"));
+var colorCell=document.createElement("td");
+colorCell.style.backgroundColor=color;
+this._theRow2.appendChild(colorCell);
+var labelCell=document.createElement("td");
+var labelDiv=document.createElement("div");
+labelDiv.appendChild(document.createTextNode(label));
+labelCell.appendChild(labelDiv);
+this._theRow3.appendChild(labelCell);
+};
+Exhibit.LegendGradientWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.LegendGradientWidget.prototype._initializeUI=function(){this._div.className="exhibit-legendGradientWidget";
+this._div.innerHTML="";
+};
+Exhibit.LegendGradientWidget.prototype.clear=function(){this._div.innerHTML="";
+};
+
+
+/* legend-widget.js */
+Exhibit.LegendWidget=function(configuration,containerElmt,uiContext){this._configuration=configuration;
+this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorMarkerGenerator="colorMarkerGenerator" in configuration?configuration.colorMarkerGenerator:Exhibit.LegendWidget._defaultColorMarkerGenerator;
+this._sizeMarkerGenerator="sizeMarkerGenerator" in configuration?configuration.sizeMarkerGenerator:Exhibit.LegendWidget._defaultSizeMarkerGenerator;
+this._iconMarkerGenerator="iconMarkerGenerator" in configuration?configuration.iconMarkerGenerator:Exhibit.LegendWidget._defaultIconMarkerGenerator;
+this._labelStyler="labelStyler" in configuration?configuration.labelStyler:Exhibit.LegendWidget._defaultColorLabelStyler;
+this._initializeUI();
+};
+Exhibit.LegendWidget.create=function(configuration,containerElmt,uiContext){return new Exhibit.LegendWidget(configuration,containerElmt,uiContext);
+};
+Exhibit.LegendWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.LegendWidget.prototype._initializeUI=function(){this._div.className="exhibit-legendWidget";
+this._div.innerHTML="<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+Exhibit.LegendWidget.prototype.clear=function(){this._div.innerHTML="<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+Exhibit.LegendWidget.prototype.addLegendLabel=function(label,type){var dom=SimileAjax.DOM.createDOMFromString("div","<div id='legend-label'><span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 </div>",{});
+dom.elmt.className="exhibit-legendWidget-label";
+var id="exhibit-"+type+"-legend";
+document.getElementById(id).appendChild(dom.elmt);
+};
+Exhibit.LegendWidget.prototype.addEntry=function(value,label,type){type=type||"color";
+label=(label!=null)?label.toString():key.toString();
+if(type=="color"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._colorMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-color-legend");
+}if(type=="size"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._sizeMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-size-legend");
+}if(type=="icon"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._iconMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-icon-legend");
+}dom.elmt.className="exhibit-legendWidget-entry";
+this._labelStyler(dom.label,value);
+legendDiv.appendChild(dom.elmt);
+};
+Exhibit.LegendWidget._localeSort=function(a,b){return a.localeCompare(b);
+};
+Exhibit.LegendWidget._defaultColorMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="exhibit-legendWidget-entry-swatch";
+span.style.background=value;
+span.innerHTML="\u00a0\u00a0";
+return span;
+};
+Exhibit.LegendWidget._defaultSizeMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="exhibit-legendWidget-entry-swatch";
+span.style.height=value;
+span.style.width=value;
+span.style.background="#C0C0C0";
+span.innerHTML="\u00a0\u00a0";
+return span;
+};
+Exhibit.LegendWidget._defaultIconMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="<img src="+value+"/>";
+return span;
+};
+Exhibit.LegendWidget._defaultColorLabelStyler=function(elmt,value){};
+
+
+/* logo.js */
+Exhibit.Logo=function(elmt,exhibit){this._exhibit=exhibit;
+this._elmt=elmt;
+this._color="Silver";
+};
+Exhibit.Logo.create=function(configuration,elmt,exhibit){var logo=new Exhibit.Logo(elmt,exhibit);
+if("color" in configuration){logo._color=configuration.color;
+}logo._initializeUI();
+return logo;
+};
+Exhibit.Logo.createFromDOM=function(elmt,exhibit){var logo=new Exhibit.Logo(elmt,exhibit);
+var color=Exhibit.getAttribute(elmt,"color");
+if(color!=null&&color.length>0){logo._color=color;
+}logo._initializeUI();
+return logo;
+};
+Exhibit.Logo.prototype.dispose=function(){this._elmt=null;
+this._exhibit=null;
+};
+Exhibit.Logo.prototype._initializeUI=function(){var logoURL="http://static.simile.mit.edu/graphics/logos/exhibit/exhibit-small-"+this._color+".png";
+var img=SimileAjax.Graphics.createTranslucentImage(logoURL);
+var id="exhibit-logo-image";
+if(!document.getElementById(id)){img.id=id;
+}var a=document.createElement("a");
+a.href="http://simile.mit.edu/exhibit/";
+a.title="http://simile.mit.edu/exhibit/";
+a.target="_blank";
+a.appendChild(img);
+this._elmt.appendChild(a);
+};
+
+
+/* option-widget.js */
+Exhibit.OptionWidget=function(configuration,containerElmt,uiContext){this._label=configuration.label;
+this._checked="checked" in configuration?configuration.checked:false;
+this._onToggle=configuration.onToggle;
+this._containerElmt=containerElmt;
+this._uiContext=uiContext;
+this._initializeUI();
+};
+Exhibit.OptionWidget.create=function(configuration,containerElmt,uiContext){return new Exhibit.OptionWidget(configuration,containerElmt,uiContext);
+};
+Exhibit.OptionWidget.prototype.dispose=function(){this._containerElmt.innerHTML="";
+this._dom=null;
+this._containerElmt=null;
+this._uiContext=null;
+};
+Exhibit.OptionWidget.uncheckedImageURL=Exhibit.urlPrefix+"images/option.png";
+Exhibit.OptionWidget.checkedImageURL=Exhibit.urlPrefix+"images/option-check.png";
+Exhibit.OptionWidget.uncheckedTemplate="<span id='uncheckedSpan' style='display: none;'><img id='uncheckedImage' /> %0</span>";
+Exhibit.OptionWidget.checkedTemplate="<span id='checkedSpan' style='display: none;'><img id='checkedImage' /> %0</span>";
+Exhibit.OptionWidget.prototype._initializeUI=function(){this._containerElmt.className="exhibit-optionWidget";
+this._dom=SimileAjax.DOM.createDOMFromString(this._containerElmt,String.substitute(Exhibit.OptionWidget.uncheckedTemplate+Exhibit.OptionWidget.checkedTemplate,[this._label]),{uncheckedImage:SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.uncheckedImageURL),checkedImage:SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.checkedImageURL)});
+if(this._checked){this._dom.checkedSpan.style.display="inline";
+}else{this._dom.uncheckedSpan.style.display="inline";
+}SimileAjax.WindowManager.registerEvent(this._containerElmt,"click",this._onToggle);
+};
+Exhibit.OptionWidget.prototype.getChecked=function(){return this._checked;
+};
+Exhibit.OptionWidget.prototype.setChecked=function(checked){if(checked!=this._checked){this._checked=checked;
+if(checked){this._dom.checkedSpan.style.display="inline";
+this._dom.uncheckedSpan.style.display="none";
+}else{this._dom.checkedSpan.style.display="none";
+this._dom.uncheckedSpan.style.display="inline";
+}}};
+Exhibit.OptionWidget.prototype.toggle=function(){this.setChecked(!this._checked);
+};
+
+
+/* resizable-div-widget.js */
+Exhibit.ResizableDivWidget=function(configuration,elmt,uiContext){this._div=elmt;
+this._configuration=configuration;
+if(!("minHeight" in configuration)){configuration["minHeight"]=10;
+}this._initializeUI();
+};
+Exhibit.ResizableDivWidget.create=function(configuration,elmt,uiContext){return new Exhibit.ResizableDivWidget(configuration,elmt,uiContext);
+};
+Exhibit.ResizableDivWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._contentDiv=null;
+this._resizerDiv=null;
+this._div=null;
+};
+Exhibit.ResizableDivWidget.prototype.getContentDiv=function(){return this._contentDiv;
+};
+Exhibit.ResizableDivWidget.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="<div></div><div class='exhibit-resizableDivWidget-resizer'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+"</div>";
+this._contentDiv=this._div.childNodes[0];
+this._resizerDiv=this._div.childNodes[1];
+SimileAjax.WindowManager.registerForDragging(this._resizerDiv,{onDragStart:function(){this._height=self._contentDiv.offsetHeight;
+},onDragBy:function(diffX,diffY){this._height+=diffY;
+self._contentDiv.style.height=Math.max(self._configuration.minHeight,this._height)+"px";
+},onDragEnd:function(){if("onResize" in self._configuration){self._configuration["onResize"]();
+}}});
+};
+
+
+/* toolbox-widget.js */
+Exhibit.ToolboxWidget=function(containerElmt,uiContext){this._containerElmt=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+this._customExporters=[];
+this._hovering=false;
+this._initializeUI();
+};
+Exhibit.ToolboxWidget._settingSpecs={"itemID":{type:"text"}};
+Exhibit.ToolboxWidget.create=function(configuration,containerElmt,uiContext){var widget=new Exhibit.ToolboxWidget(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ToolboxWidget._configure(widget,configuration);
+widget._initializeUI();
+return widget;
+};
+Exhibit.ToolboxWidget.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var widget=new Exhibit.ToolboxWidget(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ToolboxWidget._settingSpecs,widget._settings);
+Exhibit.ToolboxWidget._configure(widget,configuration);
+widget._initializeUI();
+return widget;
+};
+Exhibit.ToolboxWidget._configure=function(widget,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ToolboxWidget._settingSpecs,widget._settings);
+};
+Exhibit.ToolboxWidget.prototype.dispose=function(){this._containerElmt.onmouseover=null;
+this._containerElmt.onmouseout=null;
+this._dismiss();
+this._settings=null;
+this._containerElmt=null;
+this._uiContext=null;
+};
+Exhibit.ToolboxWidget.prototype.addExporter=function(exporter){this._customExporters.push(exporter);
+};
+Exhibit.ToolboxWidget.prototype._initializeUI=function(){var self=this;
+this._containerElmt.onmouseover=function(evt){self._onContainerMouseOver(evt);
+};
+this._containerElmt.onmouseout=function(evt){self._onContainerMouseOut(evt);
+};
+};
+Exhibit.ToolboxWidget.prototype._onContainerMouseOver=function(evt){if(!this._hovering){var self=this;
+var coords=SimileAjax.DOM.getPageCoordinates(this._containerElmt);
+var docWidth=document.body.offsetWidth;
+var docHeight=document.body.offsetHeight;
+var popup=document.createElement("div");
+popup.className="exhibit-toolboxWidget-popup screen";
+popup.style.top=coords.top+"px";
+popup.style.right=(docWidth-coords.left-this._containerElmt.offsetWidth)+"px";
+this._fillPopup(popup);
+document.body.appendChild(popup);
+popup.onmouseover=function(evt){self._onPopupMouseOver(evt);
+};
+popup.onmouseout=function(evt){self._onPopupMouseOut(evt);
+};
+this._popup=popup;
+this._hovering=true;
+}else{this._clearTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._onContainerMouseOut=function(evt){if(Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt),this._containerElmt)){this._setTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._onPopupMouseOver=function(evt){this._clearTimeout();
+};
+Exhibit.ToolboxWidget.prototype._onPopupMouseOut=function(evt){if(Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt),this._containerElmt)){this._setTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._setTimeout=function(){var self=this;
+this._timer=window.setTimeout(function(){self._onTimeout();
+},200);
+};
+Exhibit.ToolboxWidget.prototype._clearTimeout=function(){if(this._timer){window.clearTimeout(this._timer);
+this._timer=null;
+}};
+Exhibit.ToolboxWidget.prototype._onTimeout=function(){this._dismiss();
+this._hovering=false;
+this._timer=null;
+};
+Exhibit.ToolboxWidget.prototype._fillPopup=function(elmt){var self=this;
+var exportImg=Exhibit.UI.createTranslucentImage("images/liveclipboard-icon.png");
+exportImg.className="exhibit-toolboxWidget-button";
+SimileAjax.WindowManager.registerEvent(exportImg,"click",function(elmt,evt,target){self._showExportMenu(exportImg);
+});
+elmt.appendChild(exportImg);
+};
+Exhibit.ToolboxWidget.prototype._dismiss=function(){if(this._popup){document.body.removeChild(this._popup);
+this._popup=null;
+}};
+Exhibit.ToolboxWidget._mouseOutsideElmt=function(evt,elmt){var eventCoords=SimileAjax.DOM.getEventPageCoordinates(evt);
+var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+return((eventCoords.x<coords.left||eventCoords.x>coords.left+elmt.offsetWidth)||(eventCoords.y<coords.top||eventCoords.y>coords.top+elmt.offsetHeight));
+};
+Exhibit.ToolboxWidget._getEvent=function(evt){return(evt)?evt:((event)?event:null);
+};
+Exhibit.ToolboxWidget.prototype._showExportMenu=function(elmt){var self=this;
+var popupDom=Exhibit.UI.createPopupMenuDom(elmt);
+var makeMenuItem=function(exporter){popupDom.appendMenuItem(exporter.getLabel(),null,function(){var database=self._uiContext.getDatabase();
+var text=("itemID" in self._settings)?exporter.exportOne(self._settings.itemID,database):exporter.exportMany(self._uiContext.getCollection().getRestrictedItems(),database);
+Exhibit.ToolboxWidget.createExportDialogBox(text).open();
+});
+};
+var exporters=Exhibit.getExporters();
+for(var i=0;
+i<exporters.length;
+i++){makeMenuItem(exporters[i]);
+}for(var i=0;
+i<this._customExporters.length;
+i++){makeMenuItem(this._customExporters[i]);
+}if("getGeneratedHTML" in this){makeMenuItem({getLabel:function(){return Exhibit.l10n.htmlExporterLabel;
+},exportOne:this.getGeneratedHTML,exportMany:this.getGeneratedHTML});
+}popupDom.open();
+};
+Exhibit.ToolboxWidget.createExportDialogBox=function(string){var template={tag:"div",className:"exhibit-copyDialog exhibit-ui-protection",children:[{tag:"button",field:"closeButton",children:[Exhibit.l10n.exportDialogBoxCloseButtonLabel]},{tag:"p",children:[Exhibit.l10n.exportDialogBoxPrompt]},{tag:"div",field:"textAreaContainer"}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.textAreaContainer.innerHTML="<textarea wrap='off' rows='15'>"+string+"</textarea>";
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.open=function(){dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var textarea=dom.textAreaContainer.firstChild;
+textarea.select();
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+},dom.layer);
+SimileAjax.WindowManager.registerEvent(textarea,"keyup",function(elmt,evt,target){if(evt.keyCode==27){SimileAjax.WindowManager.popLayer(dom.layer);
+}},dom.layer);
+};
+return dom;
+};
+
+
+/* coders.js */
+Exhibit.Coders=new Object();
+Exhibit.Coders.mixedCaseColor="#fff";
+Exhibit.Coders.othersCaseColor="#aaa";
+Exhibit.Coders.missingCaseColor="#888";
+
+
+/* facets.js */
+Exhibit.FacetUtilities=new Object();
+Exhibit.FacetUtilities.constructFacetFrame=function(forFacet,div,facetLabel,onClearAllSelections,uiContext,collapsible,collapsed){div.className="exhibit-facet";
+var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-facet-header'><div class='exhibit-facet-header-filterControl' id='clearSelectionsDiv' title='"+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip+"'><span id='filterCountSpan'></span><img id='checkImage' /></div>"+((collapsible)?"<img src='"+Exhibit.urlPrefix+"images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />":"")+"<span class='exhibit-facet-header-title'>"+facetLabel+"</span></div><div class='exhibit-facet-body-frame' id='frameDiv'></div>",{checkImage:Exhibit.UI.createTranslucentImage("images/black-check.png")});
+var resizableDivWidget=Exhibit.ResizableDivWidget.create({},dom.frameDiv,uiContext);
+dom.valuesContainer=resizableDivWidget.getContentDiv();
+dom.valuesContainer.className="exhibit-facet-body";
+dom.setSelectionCount=function(count){this.filterCountSpan.innerHTML=count;
+this.clearSelectionsDiv.style.display=count>0?"block":"none";
+};
+SimileAjax.WindowManager.registerEvent(dom.clearSelectionsDiv,"click",onClearAllSelections);
+if(collapsible){SimileAjax.WindowManager.registerEvent(dom.collapseImg,"click",function(){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+});
+if(collapsed){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+}}return dom;
+};
+Exhibit.FacetUtilities.toggleCollapse=function(dom,facet){var el=dom.frameDiv;
+if(el.style.display!="none"){el.style.display="none";
+dom.collapseImg.src=Exhibit.urlPrefix+"images/expand.png";
+}else{el.style.display="block";
+dom.collapseImg.src=Exhibit.urlPrefix+"images/collapse.png";
+if(typeof facet.onUncollapse=="function"){facet.onUncollapse();
+}}};
+Exhibit.FacetUtilities.isCollapsed=function(facet){var el=facet._dom.frameDiv;
+return el.style.display=="none";
+};
+Exhibit.FacetUtilities.constructFacetItem=function(label,count,color,selected,facetHasSelection,onSelect,onSelectOnly,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-facet-value-count'>"+count+"</div><div class='exhibit-facet-value-inner' id='inner'>"+("<div class='exhibit-facet-value-checkbox'>&#160;"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a></div>");
+dom.elmt.className=selected?"exhibit-facet-value exhibit-facet-value-selected":"exhibit-facet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.link.innerHTML=label;
+if(color!=null){dom.link.style.color=color;
+}}else{dom.link.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.inner.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}return dom.elmt;
+};
+Exhibit.FacetUtilities.constructFlowingFacetFrame=function(forFacet,div,facetLabel,onClearAllSelections,uiContext,collapsible,collapsed){div.className="exhibit-flowingFacet";
+var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-flowingFacet-header'>"+((collapsible)?"<img src='"+Exhibit.urlPrefix+"images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />":"")+"<span class='exhibit-flowingFacet-header-title'>"+facetLabel+"</span></div><div id='frameDiv'><div class='exhibit-flowingFacet-body' id='valuesContainer'></div></div>");
+dom.setSelectionCount=function(count){};
+if(collapsible){SimileAjax.WindowManager.registerEvent(dom.collapseImg,"click",function(){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+});
+if(collapsed){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+}}return dom;
+};
+Exhibit.FacetUtilities.constructFlowingFacetItem=function(label,count,color,selected,facetHasSelection,onSelect,onSelectOnly,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div",("<div class='exhibit-flowingFacet-value-checkbox'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a> <span class='exhibit-flowingFacet-value-count'>("+count+")</span>");
+dom.elmt.className=selected?"exhibit-flowingFacet-value exhibit-flowingFacet-value-selected":"exhibit-flowingFacet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.inner.innerHTML=label;
+if(color!=null){dom.inner.style.color=color;
+}}else{dom.inner.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}return dom.elmt;
+};
+Exhibit.FacetUtilities.constructHierarchicalFacetItem=function(label,count,color,selected,hasChildren,expanded,facetHasSelection,onSelect,onSelectOnly,onToggleChildren,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-facet-value-count'>"+count+"</div><div class='exhibit-facet-value-inner' id='inner'>"+("<div class='exhibit-facet-value-checkbox'>&#160;"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a>"+(hasChildren?("<a class='exhibit-facet-value-children-toggle' href='javascript:{}' id='toggle'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/right-arrow.png")+"</a>"):"")+"</div>"+(hasChildren?"<div class='exhibit-facet-childrenContainer' id='childrenContainer'></div>":""));
+dom.elmt.className=selected?"exhibit-facet-value exhibit-facet-value-selected":"exhibit-facet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.link.appendChild(document.createTextNode(label));
+if(color!=null){dom.link.style.color=color;
+}}else{dom.link.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.inner.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}if(hasChildren){dom.showChildren=function(show){dom.childrenContainer.style.display=show?"block":"none";
+dom.toggle.childNodes[0].style.display=show?"inline":"none";
+dom.toggle.childNodes[1].style.display=show?"none":"inline";
+};
+SimileAjax.WindowManager.registerEvent(dom.toggle,"click",onToggleChildren,SimileAjax.WindowManager.getBaseLayer());
+dom.showChildren(expanded);
+}return dom;
+};
+Exhibit.FacetUtilities.constructFlowingHierarchicalFacetItem=function(label,count,color,selected,hasChildren,expanded,facetHasSelection,onSelect,onSelectOnly,onToggleChildren,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div",("<div class='exhibit-flowingFacet-value-checkbox'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a> <span class='exhibit-flowingFacet-value-count'>("+count+")</span>"+(hasChildren?("<a class='exhibit-flowingFacet-value-children-toggle' href='javascript:{}' id='toggle'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/right-arrow.png")+"</a>"):"")+(hasChildren?"<div class='exhibit-flowingFacet-childrenContainer' id='childrenContainer'></div>":""));
+dom.elmt.className=selected?"exhibit-flowingFacet-value exhibit-flowingFacet-value-selected":"exhibit-flowingFacet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.inner.appendChild(document.createTextNode(label));
+if(color!=null){dom.inner.style.color=color;
+}}else{dom.inner.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}if(hasChildren){dom.showChildren=function(show){dom.childrenContainer.style.display=show?"block":"none";
+dom.toggle.childNodes[0].style.display=show?"inline":"none";
+dom.toggle.childNodes[1].style.display=show?"none":"inline";
+};
+SimileAjax.WindowManager.registerEvent(dom.toggle,"click",onToggleChildren,SimileAjax.WindowManager.getBaseLayer());
+dom.showChildren(expanded);
+}return dom;
+};
+Exhibit.FacetUtilities.Cache=function(database,collection,expression){var self=this;
+this._database=database;
+this._collection=collection;
+this._expression=expression;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}if("_valueToItem" in self){delete self._valueToItem;
+}if("_missingItems" in self){delete self._missingItems;
+}}};
+collection.addListener(this._listener);
+};
+Exhibit.FacetUtilities.Cache.prototype.dispose=function(){this._collection.removeListener(this._listener);
+this._collection=null;
+this._listener=null;
+this._itemToValue=null;
+this._valueToItem=null;
+this._missingItems=null;
+};
+Exhibit.FacetUtilities.Cache.prototype.getItemsFromValues=function(values,filter){var set;
+if(this._expression.isPath()){set=this._expression.getPath().walkBackward(values,"item",filter,this._database).getSet();
+}else{this._buildMaps();
+set=new Exhibit.Set();
+var valueToItem=this._valueToItem;
+values.visit(function(value){if(value in valueToItem){var itemA=valueToItem[value];
+for(var i=0;
+i<itemA.length;
+i++){var item=itemA[i];
+if(filter.contains(item)){set.add(item);
+}}}});
+}return set;
+};
+Exhibit.FacetUtilities.Cache.prototype.getItemsMissingValue=function(filter,results){this._buildMaps();
+results=results||new Exhibit.Set();
+var missingItems=this._missingItems;
+filter.visit(function(item){if(item in missingItems){results.add(item);
+}});
+return results;
+};
+Exhibit.FacetUtilities.Cache.prototype.getValueCountsFromItems=function(items){var entries=[];
+var database=this._database;
+var valueType="text";
+if(this._expression.isPath()){var path=this._expression.getPath();
+var facetValueResult=path.walkForward(items,"item",database);
+valueType=facetValueResult.valueType;
+if(facetValueResult.size>0){facetValueResult.forEachValue(function(facetValue){var itemSubcollection=path.evaluateBackward(facetValue,valueType,items,database);
+entries.push({value:facetValue,count:itemSubcollection.size});
+});
+}}else{this._buildMaps();
+valueType=this._valueType;
+for(var value in this._valueToItem){var itemA=this._valueToItem[value];
+var count=0;
+for(var i=0;
+i<itemA.length;
+i++){if(items.contains(itemA[i])){count++;
+}}if(count>0){entries.push({value:value,count:count});
+}}}return{entries:entries,valueType:valueType};
+};
+Exhibit.FacetUtilities.Cache.prototype.getValuesFromItems=function(items){if(this._expression.isPath()){return this._expression.getPath().walkForward(items,"item",database).getSet();
+}else{this._buildMaps();
+var set=new Exhibit.Set();
+var itemToValue=this._itemToValue;
+items.visit(function(item){if(item in itemToValue){var a=itemToValue[item];
+for(var i=0;
+i<a.length;
+i++){set.add(a[i]);
+}}});
+return set;
+}};
+Exhibit.FacetUtilities.Cache.prototype.countItemsMissingValue=function(items){this._buildMaps();
+var count=0;
+for(var item in this._missingItems){if(items.contains(item)){count++;
+}}return count;
+};
+Exhibit.FacetUtilities.Cache.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var valueToItem={};
+var missingItems={};
+var valueType="text";
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var expression=this._expression;
+var database=this._database;
+this._collection.getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){insert(item,value,itemToValue);
+insert(value,item,valueToItem);
+});
+}else{missingItems[item]=true;
+}});
+this._itemToValue=itemToValue;
+this._valueToItem=valueToItem;
+this._missingItems=missingItems;
+this._valueType=valueType;
+}};
+
+
+/* set.js */
+Exhibit.Set=function(a){this._hash={};
+this._count=0;
+if(a instanceof Array){for(var i=0;
+i<a.length;
+i++){this.add(a[i]);
+}}else{if(a instanceof Exhibit.Set){this.addSet(a);
+}}};
+Exhibit.Set.prototype.add=function(o){if(!(o in this._hash)){this._hash[o]=true;
+this._count++;
+return true;
+}return false;
+};
+Exhibit.Set.prototype.addSet=function(set){for(var o in set._hash){this.add(o);
+}};
+Exhibit.Set.prototype.remove=function(o){if(o in this._hash){delete this._hash[o];
+this._count--;
+return true;
+}return false;
+};
+Exhibit.Set.prototype.removeSet=function(set){for(var o in set._hash){this.remove(o);
+}};
+Exhibit.Set.prototype.retainSet=function(set){for(var o in this._hash){if(!set.contains(o)){delete this._hash[o];
+this._count--;
+}}};
+Exhibit.Set.prototype.contains=function(o){return(o in this._hash);
+};
+Exhibit.Set.prototype.size=function(){return this._count;
+};
+Exhibit.Set.prototype.toArray=function(){var a=[];
+for(var o in this._hash){a.push(o);
+}return a;
+};
+Exhibit.Set.prototype.visit=function(f){for(var o in this._hash){if(f(o)==true){break;
+}}};
+Exhibit.Set.createIntersection=function(set1,set2,result){var set=(result)?result:new Exhibit.Set();
+var setA,setB;
+if(set1.size()<set2.size()){setA=set1;
+setB=set2;
+}else{setA=set2;
+setB=set1;
+}setA.visit(function(v){if(setB.contains(v)){set.add(v);
+}});
+return set;
+};
+
+
+/* settings.js */
+Exhibit.SettingsUtilities=new Object();
+Exhibit.SettingsUtilities.collectSettings=function(config,specs,settings){Exhibit.SettingsUtilities._internalCollectSettings(function(field){return config[field];
+},specs,settings);
+};
+Exhibit.SettingsUtilities.collectSettingsFromDOM=function(configElmt,specs,settings){Exhibit.SettingsUtilities._internalCollectSettings(function(field){return Exhibit.getAttribute(configElmt,field);
+},specs,settings);
+};
+Exhibit.SettingsUtilities._internalCollectSettings=function(f,specs,settings){for(var field in specs){var spec=specs[field];
+var name=field;
+if("name" in spec){name=spec.name;
+}if(!(name in settings)&&"defaultValue" in spec){settings[name]=spec.defaultValue;
+}var value=f(field);
+if(value==null){continue;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){continue;
+}}var type="text";
+if("type" in spec){type=spec.type;
+}var dimensions=1;
+if("dimensions" in spec){dimensions=spec.dimensions;
+}try{if(dimensions>1){var separator=",";
+if("separator" in spec){separator=spec.separator;
+}var a=value.split(separator);
+if(a.length!=dimensions){throw new Error("Expected a tuple of "+dimensions+" dimensions separated with "+separator+" but got "+value);
+}else{for(var i=0;
+i<a.length;
+i++){a[i]=Exhibit.SettingsUtilities._parseSetting(a[i].trim(),type,spec);
+}settings[name]=a;
+}}else{settings[name]=Exhibit.SettingsUtilities._parseSetting(value,type,spec);
+}}catch(e){SimileAjax.Debug.exception(e);
+}}};
+Exhibit.SettingsUtilities._parseSetting=function(s,type,spec){var sType=typeof s;
+if(type=="text"){return s;
+}else{if(type=="float"){if(sType=="number"){return s;
+}else{if(sType=="string"){var f=parseFloat(s);
+if(!isNaN(f)){return f;
+}}}throw new Error("Expected a floating point number but got "+s);
+}else{if(type=="int"){if(sType=="number"){return Math.round(s);
+}else{if(sType=="string"){var n=parseInt(s);
+if(!isNaN(n)){return n;
+}}}throw new Error("Expected an integer but got "+s);
+}else{if(type=="boolean"){if(sType=="boolean"){return s;
+}else{if(sType=="string"){s=s.toLowerCase();
+if(s=="true"){return true;
+}else{if(s=="false"){return false;
+}}}}throw new Error("Expected either 'true' or 'false' but got "+s);
+}else{if(type=="function"){if(sType=="function"){return s;
+}else{if(sType=="string"){try{var f=eval(s);
+if(typeof f=="function"){return f;
+}}catch(e){}}}throw new Error("Expected a function or the name of a function but got "+s);
+}else{if(type=="enum"){var choices=spec.choices;
+for(var i=0;
+i<choices.length;
+i++){if(choices[i]==s){return s;
+}}throw new Error("Expected one of "+choices.join(", ")+" but got "+s);
+}else{throw new Error("Unknown setting type "+type);
+}}}}}}};
+Exhibit.SettingsUtilities.createAccessors=function(config,specs,accessors){Exhibit.SettingsUtilities._internalCreateAccessors(function(field){return config[field];
+},specs,accessors);
+};
+Exhibit.SettingsUtilities.createAccessorsFromDOM=function(configElmt,specs,accessors){Exhibit.SettingsUtilities._internalCreateAccessors(function(field){return Exhibit.getAttribute(configElmt,field);
+},specs,accessors);
+};
+Exhibit.SettingsUtilities._internalCreateAccessors=function(f,specs,accessors){for(var field in specs){var spec=specs[field];
+var accessorName=spec.accessorName;
+var accessor=null;
+var isTuple=false;
+var createOneAccessor=function(spec2){isTuple=false;
+if("bindings" in spec2){return Exhibit.SettingsUtilities._createBindingsAccessor(f,spec2.bindings);
+}else{if("bindingNames" in spec2){isTuple=true;
+return Exhibit.SettingsUtilities._createTupleAccessor(f,spec2);
+}else{return Exhibit.SettingsUtilities._createElementalAccessor(f,spec2);
+}}};
+if("alternatives" in spec){var alternatives=spec.alternatives;
+for(var i=0;
+i<alternatives.length;
+i++){accessor=createOneAccessor(alternatives[i]);
+if(accessor!=null){break;
+}}}else{accessor=createOneAccessor(spec);
+}if(accessor!=null){accessors[accessorName]=accessor;
+}else{if(!(accessorName in accessors)){accessors[accessorName]=function(value,database,visitor){};
+}}}};
+Exhibit.SettingsUtilities._createBindingsAccessor=function(f,bindingSpecs){var bindings=[];
+for(var i=0;
+i<bindingSpecs.length;
+i++){var bindingSpec=bindingSpecs[i];
+var accessor=null;
+var isTuple=false;
+if("bindingNames" in bindingSpec){isTuple=true;
+accessor=Exhibit.SettingsUtilities._createTupleAccessor(f,bindingSpec);
+}else{accessor=Exhibit.SettingsUtilities._createElementalAccessor(f,bindingSpec);
+}if(accessor==null){if(!("optional" in bindingSpec)||!bindingSpec.optional){return null;
+}}else{bindings.push({bindingName:bindingSpec.bindingName,accessor:accessor,isTuple:isTuple});
+}}return function(value,database,visitor){Exhibit.SettingsUtilities._evaluateBindings(value,database,visitor,bindings);
+};
+};
+Exhibit.SettingsUtilities._createTupleAccessor=function(f,spec){var value=f(spec.attributeName);
+if(value==null){return null;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){return null;
+}}try{var expression=Exhibit.ExpressionParser.parse(value);
+var parsers=[];
+var bindingTypes=spec.types;
+for(var i=0;
+i<bindingTypes.length;
+i++){parsers.push(Exhibit.SettingsUtilities._typeToParser(bindingTypes[i]));
+}var bindingNames=spec.bindingNames;
+var separator=",";
+if("separator" in spec){separator=spec.separator;
+}return function(itemID,database,visitor,tuple){expression.evaluateOnItem(itemID,database).values.visit(function(v){var a=v.split(separator);
+if(a.length==parsers.length){var tuple2={};
+if(tuple){for(var n in tuple){tuple2[n]=tuple[n];
+}}for(var i=0;
+i<bindingNames.length;
+i++){tuple2[bindingNames[i]]=null;
+parsers[i](a[i],function(v){tuple2[bindingNames[i]]=v;
+});
+}visitor(tuple2);
+}});
+};
+}catch(e){SimileAjax.Debug.exception(e);
+return null;
+}};
+Exhibit.SettingsUtilities._createElementalAccessor=function(f,spec){var value=f(spec.attributeName);
+if(value==null){return null;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){return null;
+}}var bindingType="text";
+if("type" in spec){bindingType=spec.type;
+}try{var expression=Exhibit.ExpressionParser.parse(value);
+var parser=Exhibit.SettingsUtilities._typeToParser(bindingType);
+return function(itemID,database,visitor){expression.evaluateOnItem(itemID,database).values.visit(function(v){return parser(v,visitor);
+});
+};
+}catch(e){SimileAjax.Debug.exception(e);
+return null;
+}};
+Exhibit.SettingsUtilities._typeToParser=function(type){switch(type){case"text":return Exhibit.SettingsUtilities._textParser;
+case"url":return Exhibit.SettingsUtilities._urlParser;
+case"float":return Exhibit.SettingsUtilities._floatParser;
+case"int":return Exhibit.SettingsUtilities._intParser;
+case"date":return Exhibit.SettingsUtilities._dateParser;
+case"boolean":return Exhibit.SettingsUtilities._booleanParser;
+default:throw new Error("Unknown setting type "+type);
+}};
+Exhibit.SettingsUtilities._textParser=function(v,f){return f(v);
+};
+Exhibit.SettingsUtilities._floatParser=function(v,f){var n=parseFloat(v);
+if(!isNaN(n)){return f(n);
+}return false;
+};
+Exhibit.SettingsUtilities._intParser=function(v,f){var n=parseInt(v);
+if(!isNaN(n)){return f(n);
+}return false;
+};
+Exhibit.SettingsUtilities._dateParser=function(v,f){if(v instanceof Date){return f(v);
+}else{if(typeof v=="number"){var d=new Date(0);
+d.setUTCFullYear(v);
+return f(d);
+}else{var d=SimileAjax.DateTime.parseIso8601DateTime(v.toString());
+if(d!=null){return f(d);
+}}}return false;
+};
+Exhibit.SettingsUtilities._booleanParser=function(v,f){v=v.toString().toLowerCase();
+if(v=="true"){return f(true);
+}else{if(v=="false"){return f(false);
+}}return false;
+};
+Exhibit.SettingsUtilities._urlParser=function(v,f){return f(Exhibit.Persistence.resolveURL(v.toString()));
+};
+Exhibit.SettingsUtilities._evaluateBindings=function(value,database,visitor,bindings){var maxIndex=bindings.length-1;
+var f=function(tuple,index){var binding=bindings[index];
+var visited=false;
+var recurse=index==maxIndex?function(){visitor(tuple);
+}:function(){f(tuple,index+1);
+};
+if(binding.isTuple){binding.accessor(value,database,function(tuple2){visited=true;
+tuple=tuple2;
+recurse();
+},tuple);
+}else{var bindingName=binding.bindingName;
+binding.accessor(value,database,function(v){visited=true;
+tuple[bindingName]=v;
+recurse();
+});
+}if(!visited){recurse();
+}};
+f({},0);
+};
+
+
+/* util.js */
+Exhibit.Util={};
+Exhibit.Util.round=function(n,precision){precision=precision||1;
+var lg=Math.floor(Math.log(precision)/Math.log(10));
+n=(Math.round(n/precision)*precision).toString();
+var d=n.split(".");
+if(lg>=0){return d[0];
+}lg=-lg;
+d[1]=(d[1]||"").substring(0,lg);
+while(d[1].length<lg){d[1]+="0";
+}return d.join(".");
+};
+if(!Array.prototype.indexOf){Array.prototype.indexOf=function(elt){var len=this.length;
+var from=Number(arguments[1])||0;
+from=(from<0)?Math.ceil(from):Math.floor(from);
+if(from<0){from+=len;
+}for(;
+from<len;
+from++){if(from in this&&this[from]===elt){return from;
+}}return -1;
+};
+}if(!Array.prototype.filter){Array.prototype.filter=function(fun){var len=this.length;
+if(typeof fun!="function"){throw new TypeError();
+}var res=new Array();
+var thisp=arguments[1];
+for(var i=0;
+i<len;
+i++){if(i in this){var val=this[i];
+if(fun.call(thisp,val,i,this)){res.push(val);
+}}}return res;
+};
+}if(!Array.prototype.map){Array.prototype.map=function(f,thisp){if(typeof f!="function"){throw new TypeError();
+}if(typeof thisp=="undefined"){thisp=this;
+}var res=[],length=this.length;
+for(var i=0;
+i<length;
+i++){if(this.hasOwnProperty(i)){res[i]=f.call(thisp,this[i],i,this);
+}}return res;
+};
+}if(!Array.prototype.forEach){Array.prototype.forEach=function(fun){var len=this.length;
+if(typeof fun!="function"){throw new TypeError();
+}var thisp=arguments[1];
+for(var i=0;
+i<len;
+i++){if(i in this){fun.call(thisp,this[i],i,this);
+}}};
+}
+
+/* views.js */
+Exhibit.ViewUtilities=new Object();
+Exhibit.ViewUtilities.openBubbleForItems=function(anchorElmt,arrayOfItemIDs,uiContext){var coords=SimileAjax.DOM.getPageCoordinates(anchorElmt);
+var bubble=SimileAjax.Graphics.createBubbleForPoint(coords.left+Math.round(anchorElmt.offsetWidth/2),coords.top+Math.round(anchorElmt.offsetHeight/2),uiContext.getSetting("bubbleWidth"),uiContext.getSetting("bubbleHeight"));
+Exhibit.ViewUtilities.fillBubbleWithItems(bubble.content,arrayOfItemIDs,uiContext);
+};
+Exhibit.ViewUtilities.fillBubbleWithItems=function(bubbleElmt,arrayOfItemIDs,uiContext){if(bubbleElmt==null){bubbleElmt=document.createElement("div");
+}if(arrayOfItemIDs.length>1){bubbleElmt.className=[bubbleElmt.className,"exhibit-views-bubbleWithItems"].join(" ");
+var ul=document.createElement("ul");
+for(var i=0;
+i<arrayOfItemIDs.length;
+i++){uiContext.format(arrayOfItemIDs[i],"item",function(elmt){var li=document.createElement("li");
+li.appendChild(elmt);
+ul.appendChild(li);
+});
+}bubbleElmt.appendChild(ul);
+}else{var itemLensDiv=document.createElement("div");
+var itemLens=uiContext.getLensRegistry().createLens(arrayOfItemIDs[0],itemLensDiv,uiContext);
+bubbleElmt.appendChild(itemLensDiv);
+}return bubbleElmt;
+};
+Exhibit.ViewUtilities.constructPlottingViewDom=function(div,uiContext,showSummary,resizableDivWidgetSettings,legendWidgetSettings){var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-views-header'>"+(showSummary?"<div id='collectionSummaryDiv'></div>":"")+"<div id='unplottableMessageDiv' class='exhibit-views-unplottableMessage'></div></div><div id='resizableDiv'></div><div id='legendDiv'></div>",{});
+if(showSummary){dom.collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},dom.collectionSummaryDiv,uiContext);
+}dom.resizableDivWidget=Exhibit.ResizableDivWidget.create(resizableDivWidgetSettings,dom.resizableDiv,uiContext);
+dom.plotContainer=dom.resizableDivWidget.getContentDiv();
+if(legendWidgetSettings.colorGradient==true){dom.legendGradientWidget=Exhibit.LegendGradientWidget.create(dom.legendDiv,uiContext);
+}else{dom.legendWidget=Exhibit.LegendWidget.create(legendWidgetSettings,dom.legendDiv,uiContext);
+}dom.setUnplottableMessage=function(totalCount,unplottableItems){Exhibit.ViewUtilities._setUnplottableMessage(dom,totalCount,unplottableItems,uiContext);
+};
+dom.dispose=function(){if(showSummary){dom.collectionSummaryWidget.dispose();
+}dom.resizableDivWidget.dispose();
+dom.legendWidget.dispose();
+};
+return dom;
+};
+Exhibit.ViewUtilities._setUnplottableMessage=function(dom,totalCount,unplottableItems,uiContext){var div=dom.unplottableMessageDiv;
+if(unplottableItems.length==0){div.style.display="none";
+}else{div.innerHTML="";
+var dom=SimileAjax.DOM.createDOMFromString(div,Exhibit.ViewUtilities.l10n.unplottableMessageFormatter(totalCount,unplottableItems,uiContext),{});
+SimileAjax.WindowManager.registerEvent(dom.unplottableCountLink,"click",function(elmt,evt,target){Exhibit.ViewUtilities.openBubbleForItems(elmt,unplottableItems,uiContext);
+});
+div.style.display="block";
+}};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.css
new file mode 100644
index 00000000..17cc3208
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.css
@@ -0,0 +1,785 @@
+/*==================================================
+ * Browse Panel styles
+ *==================================================
+ */
+div.exhibit-browsePanel {
+}
+
+div.exhibit-browsePanel-notConfigureMessage {
+ border: 1px solid #604800;
+ padding: 1em;
+ background: #FFFFE0;
+ text-align: center;
+}
+
+div.exhibit-browsePanel-logoContainer {
+ text-align: center;
+ margin: 1em;
+ clear: both;
+}
+
+/*==================================================
+ * Exhibit styles
+ *
+ * Note that almost all CSS code is in themes.
+ *==================================================
+ */
+.exhibit-ui-protection div {
+ margin: 0;
+ padding: 0;
+}
+.exhibit-ui-protection table {
+ font-size: 100%;
+}
+.exhibit-ui-protection tr {
+ vertical-align: top;
+}
+a img {
+ border: none;
+}
+
+a.exhibit-action,
+a.exhibit-action:link,
+a.exhibit-action:active,
+a.exhibit-action:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+}
+a.exhibit-action:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-action-disabled,
+a.exhibit-action-disabled:link,
+a.exhibit-action-disabled:active,
+a.exhibit-action-disabled:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+ opacity: 0.5;
+}
+a.exhibit-action-disabled:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-item,
+a.exhibit-item:link,
+a.exhibit-item:active,
+a.exhibit-item:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted red;
+ cursor: pointer;
+}
+a.exhibit-item:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+span.exhibit-value {
+}
+
+/*
+ * Menu Popup
+ */
+div.exhibit-menu-popup {
+ position: absolute;
+ width: 15em;
+ z-index: 1000;
+ background: #FFFFE0;
+ border: 1px solid #aaa;
+}
+
+a.exhibit-menu-item {
+ text-decoration: none;
+}
+
+a.exhibit-menu-item > div {
+ padding: 2px 2px 2px 20px;
+ text-indent: -18px;
+}
+
+a:hover.exhibit-menu-item > div {
+ background: #DFDFC8;
+}
+
+a.exhibit-menu-item div img {
+ vertical-align: middle;
+ margin-right: 2px;
+}
+
+div.exhibit-menu-section {
+ padding: 2px;
+ font-weight: bold;
+}
+
+/*
+ * Copy Button and Dialog Box
+ */
+button.exhibit-copyButton, button.exhibit-button {
+ border: 1px dashed;
+ cursor: pointer;
+ margin: 2px;
+}
+button:hover.exhibit-copyButton, button.exhibit-button:hover {
+ background: white;
+ border: 1px dashed blue;
+ color: blue;
+ cursor: pointer;
+}
+
+div.exhibit-copyDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-copyDialog textarea {
+ width: 100%;
+ font-size: 90%;
+ color: #888;
+}
+
+div.exhibit-copyDialog button {
+ float: right;
+}
+
+/*
+ * Focus Dialog Box
+ */
+div.exhibit-focusDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-focusDialog-lensContainer {
+}
+
+div.exhibit-focusDialog-controls {
+ margin: 1em;
+ text-align: center;
+}
+
+/*
+ * Busy indicator
+ */
+.exhibit-busyIndicator {
+ position: absolute;
+ left: 35%;
+ width: 30%;
+ z-index: 1000;
+}
+.exhibit-busyIndicator-content {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.exhibit-busyIndicator-content img {
+ vertical-align: middle;
+}
+div.exhibit-lens {
+ border: 1px solid #aaa;
+ margin-bottom: 1em;
+}
+
+div.exhibit-lens-title {
+ font-weight: bold;
+ background: #eee;
+ padding: 2px;
+}
+
+.exhibit-lens-copyButton {
+ float: right;
+}
+
+div.exhibit-lens-body {
+ padding: 0.3em;
+}
+
+table.exhibit-lens-properties {
+}
+
+tr.exhibit-lens-property {
+}
+
+td.exhibit-lens-property-name {
+ color: #888;
+}
+
+td.exhibit-lens-property-values {
+}
+
+/*==================================================
+ * Facet box
+ *==================================================
+ */
+div.exhibit-facet {
+ position: relative;
+}
+
+div.exhibit-facet-header {
+ padding: 2px;
+}
+div.exhibit-facet-header-filterControl {
+ float: right;
+ width: 2em;
+ display: none;
+ cursor: pointer;
+}
+div.exhibit-facet-header-filterControl img {
+ vertical-align: text-bottom;
+}
+
+img.exhibit-facet-header-collapse {
+ border: 1px;
+ cursor: pointer;
+ padding-right: 3px;
+}
+
+span.exhibit-facet-header-title {
+ font-weight: bold;
+}
+span.exhibit-facet-header-detail {
+ color: #888;
+ padding-left: 0.5em;
+}
+
+div.exhibit-facet-body-frame {
+ clear: both;
+}
+
+div.exhibit-facet-body {
+ border: 1px solid #ddd;
+ height: 10em;
+ overflow: auto;
+}
+
+/*==================================================
+ * Facet value
+ *==================================================
+ */
+
+div.exhibit-facet-value {
+ cursor: pointer;
+ padding: 2px 0px;
+ clear: both;
+}
+div.exhibit-facet-value-selected {
+ font-weight: bold;
+}
+
+div.exhibit-facet-value-count {
+ float: left;
+ width: 2em;
+ text-align: right;
+ color: #aaa;
+}
+
+div.exhibit-facet-value-inner {
+ padding-left: 2.5em;
+}
+
+a.exhibit-facet-value-link {
+ text-decoration: none;
+}
+a.exhibit-facet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-facet-value-checkbox {
+ float: right;
+}
+
+span.exhibit-facet-value-missingThisField {
+ color: #888;
+}
+
+/*==================================================
+ * Flowing facet box
+ *==================================================
+ */
+div.exhibit-flowingFacet {
+ clear: both;
+}
+
+div.exhibit-flowingFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-flowingFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-flowingFacet-body {
+}
+
+/*==================================================
+ * Flowing facet value
+ *==================================================
+ */
+
+div.exhibit-flowingFacet-value {
+ cursor: pointer;
+ clear: both;
+ position: relative;
+ margin-left: 20px;
+}
+
+a.exhibit-flowingFacet-value-link {
+ text-decoration: none;
+}
+a.exhibit-flowingFacet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-flowingFacet-value-selected {
+ font-weight: bold;
+}
+
+span.exhibit-flowingFacet-value-count {
+ color: #aaa;
+}
+
+div.exhibit-flowingFacet-value-checkbox {
+ position: absolute;
+ left: -20px;
+ padding: 0;
+ margin: 0;
+}
+
+/*==================================================
+ * Text search facet
+ *==================================================
+ */
+div.exhibit-text-facet {
+}
+
+div.exhibit-text-facet input {
+ width: 100%;
+}
+
+/*==================================================
+ * Cloud facet
+ *==================================================
+ */
+div.exhibit-cloudFacet {
+ clear: both;
+}
+
+div.exhibit-cloudFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-cloudFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-cloudFacet-body {
+ padding: 0.5em;
+ border: 1px solid #aaa;
+}
+
+span.exhibit-cloudFacet-value {
+ cursor: pointer;
+}
+
+span.exhibit-cloudFacet-value-selected {
+ text-decoration: underline;
+ background: yellow;
+}
+
+/*==================================================
+ * Hierarchical facet
+ *==================================================
+ */
+
+a.exhibit-facet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-facet-value-children-toggle:hover {
+ background: #eee;
+}
+
+a.exhibit-flowingFacet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-flowingFacet-value-children-toggle:hover {
+ background: #eee;
+}
+
+div.exhibit-flowingFacet-childrenContainer {
+}
+
+div.exhibit-facet-childrenContainer {
+ padding-left: 16px;
+}
+
+/*==================================================
+ * Slider facet
+ *==================================================
+ */
+
+div.exhibit-slider {
+ font-size: 0; /* IE sucks */
+ padding-left: 10px;
+}
+
+div.exhibit-slider-bar {
+ background: #000;
+ margin: 5px 0 15px 0;
+ position: relative;
+}
+
+div.exhibit-slider-bar2 {
+ background: #eee;
+ line-height: 0;
+ margin: 15px 10px 10px 5px;
+ height: 150px;
+ width: 20px;
+ position: relative;
+}
+
+div.exhibit-slider-handle {
+ cursor: pointer;
+ float: left;
+ height: 19px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 12px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram {
+ background: #eee;
+}
+
+div.exhibit-slider-handle2 {
+ cursor: pointer;
+ float: left;
+ height: 12px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 19px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram div {
+ background: #999;
+}
+
+div.exhibit-slider-display {
+ font-size: 16px;
+}
+
+.exhibit-slider-display input {
+ background: #eee;
+ font-size: 10px;
+ width: 40px;
+}
+
+/*==================================================
+ * Image facet
+ *==================================================
+ */
+.inline-block {
+ display: -moz-inline-box;
+ display: inline-block;
+}
+
+.exhibit-imageFacet-value, .exhibit-imageFacet-value div, .exhibit-imageFacet-value img {
+ margin: 0px;
+ padding: 0px;
+}
+
+.exhibit-imageFacet-value div.wrapper {
+ margin: 3px;
+ padding: 6px;
+ padding-bottom: 10px;
+ text-align: right;
+ vertical-align: bottom;
+ cursor: pointer;
+ position: relative;
+}
+
+.exhibit-imageFacet-value .countDiv div.text {
+ position: absolute;
+ bottom: .1em;
+ left: .3em;
+}
+.exhibit-imageFacet-value .countDiv {
+ position: absolute;
+ border: 1px solid black;
+ bottom: 0px;
+ right: 5px;
+ width: 2em;
+ height: 2em;
+ font-size: 6pt;
+}
+
+div.countBackground { /* this class makes a window partially transparent */
+ background-color: #FF9000;
+ clear: both;
+ width: 100%;
+ height: 100%;
+ opacity: .5; /* Standard style for transparency */
+ -moz-opacity: .5; /* Transparency for older Mozillas */
+ filter: alpha(opacity=50); /* Transparency for IE */
+}
+
+
+.exhibit-imageFacet-value-selected img {
+ background: #fcc;
+}
+
+ .exhibit-imageFacet-value-selected {
+ background: #fcc;
+}
+/*==================================================
+ * Common styles for views
+ *==================================================
+ */
+div.exhibit-views-unplottableMessage {
+ padding: 1em;
+ text-align: center;
+}
+.exhibit-views-unplottableCount {
+ font-weight: bold;
+}
+.exhibit-views-totalCount {
+}
+
+div.exhibit-views-bubbleWithItems {
+}
+
+div.exhibit-collectionView {
+}
+
+div.exhibit-collectionView-header {
+}
+span.exhibit-collectionView-header-count {
+ font-size: 200%;
+}
+span.exhibit-collectionView-header-types {
+ padding-left: 0.5em;
+}
+span.exhibit-collectionView-header-details {
+ padding-left: 0.5em;
+ color: #888;
+}
+div.exhibit-collectionView-header-sortControls {
+ text-align: center;
+ margin: 1em 0;
+}
+.exhibit-collectionView-header-groupControls {
+ cursor: pointer;
+}
+.exhibit-collectionView-header-duplicateControls {
+ cursor: pointer;
+}
+
+div.exhibit-collectionView-body {
+}
+
+div.exhibit-collectionView-group {
+}
+
+span.exhibit-collectionView-group-count {
+}
+
+div.exhibit-collectionView-group-content {
+ margin-left: 1em;
+}
+
+div.exhibit-collectionView-group h1 {
+ font-size: 150%;
+ margin: 1em 0;
+}
+
+div.exhibit-collectionView-group h2 {
+ font-size: 120%;
+ margin: 0.5em 0;
+}
+
+.exhibit-collectionView-group h3 {
+}
+
+div.exhibit-collectionView-footer {
+ clear: both;
+ text-align: center;
+ margin: 2em 0;
+}
+
+div.exhibit-collectionView-pagingControls {
+ margin: 1em 0;
+ text-align: center;
+}
+
+.exhibit-collectionView-pagingControls-currentPage {
+ padding: 0px 0.5em;
+ font-weight: bold;
+}
+
+.exhibit-collectionView-pagingControls-page {
+ padding: 0px 0.5em;
+}
+
+ul.exhibit-collectionView-pagingControls {
+ clear: both;
+ margin: 2em 0;
+ text-align: center;
+}
+ul.exhibit-collectionView-pagingControls li {
+ list-style-type: none;
+ display: inline;
+}
+ul.exhibit-collectionView-pagingControls li a {
+ border: 1px solid #90C2E1;
+ background: #DFEDF7;
+ padding: 2px 5px;
+ text-decoration: none;
+}
+table.exhibit-tabularView-body {
+ width: 100%;
+}
+
+.exhibit-tabularView-columnHeader {
+ cursor: pointer;
+ white-space: pre;
+}
+
+.exhibit-tabularView-columnHeader-sorted {
+ cursor: pointer;
+ white-space: pre;
+}
+
+div.exhibit-tabularView-pagingControls {
+ margin: 1em 0;
+ text-align: center;
+}
+
+.exhibit-tabularView-pagingControls-currentPage {
+ padding: 0px 0.5em;
+ font-weight: bold;
+}
+
+.exhibit-tabularView-pagingControls-page {
+ padding: 0px 0.5em;
+}
+
+div.exhibit-thumbnailView-group {
+ clear: both;
+}
+
+div.exhibit-thumbnailView-body {
+}
+
+div.exhibit-thumbnailView-itemContainer {
+ float: left;
+}
+
+div.exhibit-thumbnailView-itemContainer-IE {
+ float: left;
+}table.exhibit-tileView-body {
+ width: 100%;
+}
+
+.exhibit-tileView-body > tbody > tr > td:first-child {
+ width: 3em;
+ text-align: right;
+ color: #aaa
+}
+
+td.exhibit-tileView-itemIndex {
+}/*==================================================
+ * View Panel styles
+ *==================================================
+ */
+div.exhibit-viewPanel {
+}
+
+div.exhibit-viewPanel-viewSelection {
+ text-align: center;
+}
+
+span.exhibit-viewPanel-viewSelection-view {
+ text-transform: uppercase;
+ cursor: pointer;
+}
+
+span.exhibit-viewPanel-viewSelection-selectedView {
+ text-transform: uppercase;
+ font-weight: bold;
+ border-bottom: 3px solid red;
+}
+
+div.exhibit-viewPanel-viewContainer {
+}
+
+/*==================================================
+ * Collection Summary Widget styles
+ *==================================================
+ */
+div.exhibit-collectionSummaryWidget {
+}
+span.exhibit-collectionSummaryWidget-count {
+ font-size: 200%;
+}
+span.exhibit-collectionSummaryWidget-results {
+}
+div.exhibit-legendWidget {
+ margin: 1em 0;
+ text-align: center;
+ line-height: 2em;
+}
+div.exhibit-legendWidget-entry {
+}
+span.exhibit-legendWidget-entry-title {
+ font-weight: bold;
+}
+span.exhibit-legendWidget-entry-swatch {
+ border: 1px solid #888;
+ padding: 0px 3px;
+}
+.exhibit-optionWidget {
+ cursor: pointer;
+}
+
+.exhibit-optionWidget img {
+ vertical-align: middle;
+}
+/*==================================================
+ * Resizable Div Widget styles
+ *==================================================
+ */
+div.exhibit-resizableDivWidget-resizer {
+ text-align: center;
+ cursor: s-resize;
+ height: 15px;
+ clear: both;
+}
+div.exhibit-toolboxWidget-popup {
+ position: absolute;
+ border: 1px solid #ccc;
+ background: white;
+ padding: 3px;
+ text-align: right;
+ z-index: 1000;
+}
+
+img.exhibit-toolboxWidget-button {
+ cursor: pointer;
+ margin: 0px 1px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.js
new file mode 100644
index 00000000..fdbe16c5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/exhibit-bundle.js
@@ -0,0 +1,8475 @@
+
+
+/* authentication.js */
+Exhibit.Authentication={};
+Exhibit.Authentication.Enabled=false;
+Exhibit.Authentication.GoogleToken=null;
+Exhibit.Authentication.GoogleSessionToken=null;
+Exhibit.Authentication.authenticate=function(){if(!window.Exhibit.params.authenticated){return ;
+}var links=document.getElementsByTagName("head")[0].childNodes;
+for(var i=0;
+i<links.length;
+i++){var link=links[i];
+if(link.rel=="exhibit/output"&&link.getAttribute("ex:authenticated")){Exhibit.Authentication.handleGoogleAuthentication();
+return ;
+}}};
+Exhibit.Authentication.parseLocationParams=function(){var params=document.location.search.substr(1).split("&");
+var ret={};
+for(var i=0;
+i<params.length;
+i++){var p=params[i];
+if(p.indexOf("=")!=-1){var components=p.split("=");
+if(components.length!=2){SimileAjax.Debug.warn("Error parsing location parameter "+p);
+}else{ret[components[0]]=components[1];
+}}else{ret[p]=true;
+}}return ret;
+};
+Exhibit.Authentication.GoogleAuthenticationURL="https://www.google.com/accounts/AuthSubRequest";
+Exhibit.Authentication.handleGoogleAuthentication=function(){var params=Exhibit.Authentication.parseLocationParams();
+if(params.token){Exhibit.Authentication.GoogleToken=params.token;
+Exhibit.Authentication.Enabled=true;
+}else{var authURL=Exhibit.Authentication.GoogleAuthenticationURL;
+authURL+="?session=1";
+authURL+="&scope=http://spreadsheets.google.com/feeds/";
+authURL+="&next="+document.location.href;
+document.location.href=authURL;
+}};
+
+
+/* collection.js */
+Exhibit.Collection=function(id,database){this._id=id;
+this._database=database;
+this._listeners=new SimileAjax.ListenerQueue();
+this._facets=[];
+this._updating=false;
+this._items=null;
+this._restrictedItems=null;
+};
+Exhibit.Collection.createAllItemsCollection=function(id,database){var collection=new Exhibit.Collection(id,database);
+collection._update=Exhibit.Collection._allItemsCollection_update;
+Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.createSubmissionsCollection=function(id,database){var collection=new Exhibit.Collection(id,database);
+collection._update=Exhibit.Collection._submissionCollection_update;
+Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.create=function(id,configuration,database){var collection=new Exhibit.Collection(id,database);
+if("itemTypes" in configuration){collection._itemTypes=configuration.itemTypes;
+collection._update=Exhibit.Collection._typeBasedCollection_update;
+}else{collection._update=Exhibit.Collection._allItemsCollection_update;
+}Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.createFromDOM=function(id,elmt,database){var collection=new Exhibit.Collection(id,database);
+var itemTypes=Exhibit.getAttribute(elmt,"itemTypes",",");
+if(itemTypes!=null&&itemTypes.length>0){collection._itemTypes=itemTypes;
+collection._update=Exhibit.Collection._typeBasedCollection_update;
+}else{collection._update=Exhibit.Collection._allItemsCollection_update;
+}Exhibit.Collection._initializeBasicCollection(collection,database);
+return collection;
+};
+Exhibit.Collection.create2=function(id,configuration,uiContext){var database=uiContext.getDatabase();
+if("expression" in configuration){var collection=new Exhibit.Collection(id,database);
+collection._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+collection._baseCollection=("baseCollectionID" in configuration)?uiContext.getExhibit().getCollection(configuration.baseCollectionID):uiContext.getCollection();
+collection._restrictBaseCollection=("restrictBaseCollection" in configuration)?configuration.restrictBaseCollection:false;
+if(collection._restrictBaseCollection){Exhibit.Collection._initializeRestrictingBasedCollection(collection);
+}else{Exhibit.Collection._initializeBasedCollection(collection);
+}return collection;
+}else{return Exhibit.Collection.create(id,configuration,database);
+}};
+Exhibit.Collection.createFromDOM2=function(id,elmt,uiContext){var database=uiContext.getDatabase();
+var collection;
+if(Exhibit.getAttribute(elmt,"submissionsCollection")){return Exhibit.Collection.createSubmissionsCollection(id,database);
+}var expressionString=Exhibit.getAttribute(elmt,"expression");
+if(expressionString!=null&&expressionString.length>0){collection=new Exhibit.Collection(id,database);
+collection._expression=Exhibit.ExpressionParser.parse(expressionString);
+var baseCollectionID=Exhibit.getAttribute(elmt,"baseCollectionID");
+collection._baseCollection=(baseCollectionID!=null&&baseCollectionID.length>0)?uiContext.getExhibit().getCollection(baseCollectionID):uiContext.getCollection();
+collection._restrictBaseCollection=Exhibit.getAttribute(elmt,"restrictBaseCollection")=="true";
+if(collection._restrictBaseCollection){Exhibit.Collection._initializeRestrictingBasedCollection(collection,database);
+}else{Exhibit.Collection._initializeBasedCollection(collection);
+}}else{collection=Exhibit.Collection.createFromDOM(id,elmt,database);
+}return collection;
+};
+Exhibit.Collection._initializeBasicCollection=function(collection,database){var update=function(){collection._update();
+};
+collection._listener={onAfterLoadingItems:update,onAfterRemovingAllStatements:update};
+database.addListener(collection._listener);
+collection._update();
+};
+Exhibit.Collection._initializeBasedCollection=function(collection){collection._update=Exhibit.Collection._basedCollection_update;
+collection._listener={onItemsChanged:function(){collection._update();
+}};
+collection._baseCollection.addListener(collection._listener);
+collection._update();
+};
+Exhibit.Collection._initializeRestrictingBasedCollection=function(collection,database){collection._cache=new Exhibit.FacetUtilities.Cache(database,collection._baseCollection,collection._expression);
+collection._isUpdatingBaseCollection=false;
+collection.onFacetUpdated=Exhibit.Collection._restrictingBasedCollection_onFacetUpdated;
+collection.restrict=Exhibit.Collection._restrictingBasedCollection_restrict;
+collection.update=Exhibit.Collection._restrictingBasedCollection_update;
+collection.hasRestrictions=Exhibit.Collection._restrictingBasedCollection_hasRestrictions;
+collection._baseCollection.addFacet(collection);
+};
+Exhibit.Collection._allItemsCollection_update=function(){this.setItems(this._database.getAllItems());
+this._onRootItemsChanged();
+};
+Exhibit.Collection._submissionCollection_update=function(){this.setItems(this._database.getAllSubmissions());
+this._onRootItemsChanged();
+};
+Exhibit.Collection._typeBasedCollection_update=function(){var newItems=new Exhibit.Set();
+for(var i=0;
+i<this._itemTypes.length;
+i++){this._database.getSubjects(this._itemTypes[i],"type",newItems);
+}this.setItems(newItems);
+this._onRootItemsChanged();
+};
+Exhibit.Collection._basedCollection_update=function(){this.setItems(this._expression.evaluate({"value":this._baseCollection.getRestrictedItems()},{"value":"item"},"value",this._database).values);
+this._onRootItemsChanged();
+};
+Exhibit.Collection._restrictingBasedCollection_onFacetUpdated=function(facetChanged){if(!this._updating){Exhibit.Collection.prototype.onFacetUpdated.call(this,facetChanged);
+this._isUpdatingBaseCollection=true;
+this._baseCollection.onFacetUpdated(this);
+this._isUpdatingBaseCollection=false;
+}};
+Exhibit.Collection._restrictingBasedCollection_restrict=function(items){if(this._restrictedItems.size()==this._items.size()){return items;
+}return this._cache.getItemsFromValues(this._restrictedItems,items);
+};
+Exhibit.Collection._restrictingBasedCollection_update=function(items){if(!this._isUpdatingBaseCollection){this.setItems(this._cache.getValuesFromItems(items));
+this._onRootItemsChanged();
+}};
+Exhibit.Collection._restrictingBasedCollection_hasRestrictions=function(){return(this._items!=null)&&(this._restrictedItems!=null)&&(this._restrictedItems.size()!=this._items.size());
+};
+Exhibit.Collection.prototype.getID=function(){return this._id;
+};
+Exhibit.Collection.prototype.dispose=function(){if("_baseCollection" in this){this._baseCollection.removeListener(this._listener);
+this._baseCollection=null;
+this._expression=null;
+}else{this._database.removeListener(this._listener);
+}this._database=null;
+this._listener=null;
+this._listeners=null;
+this._items=null;
+this._restrictedItems=null;
+};
+Exhibit.Collection.prototype.addListener=function(listener){this._listeners.add(listener);
+};
+Exhibit.Collection.prototype.removeListener=function(listener){this._listeners.remove(listener);
+};
+Exhibit.Collection.prototype.addFacet=function(facet){this._facets.push(facet);
+if(facet.hasRestrictions()){this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+}else{facet.update(this.getRestrictedItems());
+}};
+Exhibit.Collection.prototype.removeFacet=function(facet){for(var i=0;
+i<this._facets.length;
+i++){if(facet==this._facets[i]){this._facets.splice(i,1);
+if(facet.hasRestrictions()){this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+}break;
+}}};
+Exhibit.Collection.prototype.clearAllRestrictions=function(){var restrictions=[];
+this._updating=true;
+for(var i=0;
+i<this._facets.length;
+i++){restrictions.push(this._facets[i].clearAllRestrictions());
+}this._updating=false;
+this.onFacetUpdated(null);
+return restrictions;
+};
+Exhibit.Collection.prototype.applyRestrictions=function(restrictions){this._updating=true;
+for(var i=0;
+i<this._facets.length;
+i++){this._facets[i].applyRestrictions(restrictions[i]);
+}this._updating=false;
+this.onFacetUpdated(null);
+};
+Exhibit.Collection.prototype.getAllItems=function(){return new Exhibit.Set(this._items);
+};
+Exhibit.Collection.prototype.countAllItems=function(){return this._items.size();
+};
+Exhibit.Collection.prototype.getRestrictedItems=function(){return new Exhibit.Set(this._restrictedItems);
+};
+Exhibit.Collection.prototype.countRestrictedItems=function(){return this._restrictedItems.size();
+};
+Exhibit.Collection.prototype.onFacetUpdated=function(facetChanged){if(!this._updating){this._computeRestrictedItems();
+this._updateFacets(facetChanged);
+this._listeners.fire("onItemsChanged",[]);
+}};
+Exhibit.Collection.prototype._onRootItemsChanged=function(){this._listeners.fire("onRootItemsChanged",[]);
+this._computeRestrictedItems();
+this._updateFacets(null);
+this._listeners.fire("onItemsChanged",[]);
+};
+Exhibit.Collection.prototype._updateFacets=function(facetChanged){var restrictedFacetCount=0;
+for(var i=0;
+i<this._facets.length;
+i++){if(this._facets[i].hasRestrictions()){restrictedFacetCount++;
+}}for(var i=0;
+i<this._facets.length;
+i++){var facet=this._facets[i];
+if(facet.hasRestrictions()){if(restrictedFacetCount<=1){facet.update(this.getAllItems());
+}else{var items=this.getAllItems();
+for(var j=0;
+j<this._facets.length;
+j++){if(i!=j){items=this._facets[j].restrict(items);
+}}facet.update(items);
+}}else{facet.update(this.getRestrictedItems());
+}}};
+Exhibit.Collection.prototype._computeRestrictedItems=function(){this._restrictedItems=this._items;
+for(var i=0;
+i<this._facets.length;
+i++){var facet=this._facets[i];
+if(facet.hasRestrictions()){this._restrictedItems=facet.restrict(this._restrictedItems);
+}}};
+Exhibit.Collection.prototype.setItems=function(items){this._items=items;
+};
+
+
+/* controls.js */
+Exhibit.Controls={};
+Exhibit.Controls["if"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var conditionCollection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var condition=false;
+conditionCollection.forEachValue(function(v){if(v){condition=true;
+return true;
+}});
+if(condition){return args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+}else{return args[2].evaluate(roots,rootValueTypes,defaultRootName,database);
+}}};
+Exhibit.Controls["foreach"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var collection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var oldValue=roots["value"];
+var oldValueType=rootValueTypes["value"];
+rootValueTypes["value"]=collection.valueType;
+var results=[];
+var valueType="text";
+collection.forEachValue(function(element){roots["value"]=element;
+var collection2=args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+valueType=collection2.valueType;
+collection2.forEachValue(function(result){results.push(result);
+});
+});
+roots["value"]=oldValue;
+rootValueTypes["value"]=oldValueType;
+return new Exhibit.Expression._Collection(results,valueType);
+}};
+Exhibit.Controls["default"]={f:function(args,roots,rootValueTypes,defaultRootName,database){for(var i=0;
+i<args.length;
+i++){var collection=args[i].evaluate(roots,rootValueTypes,defaultRootName,database);
+if(collection.size>0){return collection;
+}}return new Exhibit.Expression._Collection([],"text");
+}};
+Exhibit.Controls["filter"]={f:function(args,roots,rootValueTypes,defaultRootName,database){var collection=args[0].evaluate(roots,rootValueTypes,defaultRootName,database);
+var oldValue=roots["value"];
+var oldValueType=rootValueTypes["value"];
+var results=new Exhibit.Set();
+rootValueTypes["value"]=collection.valueType;
+collection.forEachValue(function(element){roots["value"]=element;
+var collection2=args[1].evaluate(roots,rootValueTypes,defaultRootName,database);
+if(collection2.size>0&&collection2.contains("true")){results.add(element);
+}});
+roots["value"]=oldValue;
+rootValueTypes["value"]=oldValueType;
+return new Exhibit.Expression._Collection(results,collection.valueType);
+}};
+
+
+/* database.js */
+Exhibit.Database=new Object();
+Exhibit.Database.create=function(){Exhibit.Database.handleAuthentication();
+return new Exhibit.Database._Impl();
+};
+Exhibit.Database.handleAuthentication=function(){if(window.Exhibit.params.authenticated){var links=document.getElementsByTagName("head")[0].childNodes;
+for(var i=0;
+i<links.length;
+i++){var link=links[i];
+if(link.rel=="exhibit/output"&&link.getAttribute("ex:authenticated")){}}}};
+Exhibit.Database.makeISO8601DateString=function(date){date=date||new Date();
+var pad=function(i){return i>9?i.toString():"0"+i;
+};
+var s=date.getFullYear()+"-"+pad(date.getMonth()+1)+"-"+pad(date.getDate());
+return s;
+};
+Exhibit.Database.TimestampPropertyName="addedOn";
+Exhibit.Database._Impl=function(){this._types={};
+this._properties={};
+this._propertyArray={};
+this._submissionRegistry={};
+this._originalValues={};
+this._newItems={};
+this._listeners=new SimileAjax.ListenerQueue();
+this._spo={};
+this._ops={};
+this._items=new Exhibit.Set();
+var l10n=Exhibit.Database.l10n;
+var itemType=new Exhibit.Database._Type("Item");
+itemType._custom=Exhibit.Database.l10n.itemType;
+this._types["Item"]=itemType;
+var labelProperty=new Exhibit.Database._Property("label",this);
+labelProperty._uri="http://www.w3.org/2000/01/rdf-schema#label";
+labelProperty._valueType="text";
+labelProperty._label=l10n.labelProperty.label;
+labelProperty._pluralLabel=l10n.labelProperty.pluralLabel;
+labelProperty._reverseLabel=l10n.labelProperty.reverseLabel;
+labelProperty._reversePluralLabel=l10n.labelProperty.reversePluralLabel;
+labelProperty._groupingLabel=l10n.labelProperty.groupingLabel;
+labelProperty._reverseGroupingLabel=l10n.labelProperty.reverseGroupingLabel;
+this._properties["label"]=labelProperty;
+var typeProperty=new Exhibit.Database._Property("type");
+typeProperty._uri="http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+typeProperty._valueType="text";
+typeProperty._label="type";
+typeProperty._pluralLabel=l10n.typeProperty.label;
+typeProperty._reverseLabel=l10n.typeProperty.reverseLabel;
+typeProperty._reversePluralLabel=l10n.typeProperty.reversePluralLabel;
+typeProperty._groupingLabel=l10n.typeProperty.groupingLabel;
+typeProperty._reverseGroupingLabel=l10n.typeProperty.reverseGroupingLabel;
+this._properties["type"]=typeProperty;
+var uriProperty=new Exhibit.Database._Property("uri");
+uriProperty._uri="http://simile.mit.edu/2006/11/exhibit#uri";
+uriProperty._valueType="url";
+uriProperty._label="URI";
+uriProperty._pluralLabel="URIs";
+uriProperty._reverseLabel="URI of";
+uriProperty._reversePluralLabel="URIs of";
+uriProperty._groupingLabel="URIs";
+uriProperty._reverseGroupingLabel="things named by these URIs";
+this._properties["uri"]=uriProperty;
+var changeProperty=new Exhibit.Database._Property("change",this);
+changeProperty._uri="http://simile.mit.edu/2006/11/exhibit#change";
+changeProperty._valueType="text";
+changeProperty._label="change type";
+changeProperty._pluralLabel="change types";
+changeProperty._reverseLabel="change type of";
+changeProperty._reversePluralLabel="change types of";
+changeProperty._groupingLabel="change types";
+changeProperty._reverseGroupingLabel="changes of this type";
+this._properties["change"]=changeProperty;
+var changedItemProperty=new Exhibit.Database._Property("changedItem",this);
+changedItemProperty._uri="http://simile.mit.edu/2006/11/exhibit#changedItem";
+changedItemProperty._valueType="text";
+changedItemProperty._label="changed item";
+changedItemProperty._pluralLabel="changed item";
+changedItemProperty._groupingLabel="changed items";
+this._properties["changedItem"]=changedItemProperty;
+var modifiedProperty=new Exhibit.Database._Property(Exhibit.Database.ModifiedPropertyName,this);
+modifiedProperty._uri="http://simile.mit.edu/2006/11/exhibit#modified";
+modifiedProperty._valueType="text";
+modifiedProperty._label="modified";
+modifiedProperty._pluralLabel="modified";
+modifiedProperty._groupingLabel="was modified";
+this._properties["modified"]=modifiedProperty;
+};
+Exhibit.Database._Impl.prototype.createDatabase=function(){return Exhibit.Database.create();
+};
+Exhibit.Database._Impl.prototype.addListener=function(listener){this._listeners.add(listener);
+};
+Exhibit.Database._Impl.prototype.removeListener=function(listener){this._listeners.remove(listener);
+};
+Exhibit.Database._Impl.prototype.loadDataLinks=function(fDone){var links=SimileAjax.jQuery("head > link[rel=exhibit/data]").get();
+this._loadLinks(links,this,fDone);
+};
+Exhibit.Database._Impl.prototype.loadLinks=function(links,fDone){this._loadLinks(links,this,fDone);
+};
+Exhibit.Database._Impl.prototype.loadSubmissionLinks=function(fDone){var db=this;
+var dbProxy={loadData:function(o,baseURI){if("types" in o){db.loadTypes(o.types,baseURI);
+}if("properties" in o){db.loadProperties(o.properties,baseURI);
+}if("items" in o){db._listeners.fire("onBeforeLoadingItems",[]);
+o.items.forEach(function(item){var oldID=item.id||item.label;
+var newID=oldID+Math.floor(Math.random()*1000000);
+db._submissionRegistry[newID]=true;
+item.id=newID;
+item.changedItem=oldID;
+if(db.containsItem(oldID)){item.change="modification";
+if(!item.type){item.type=db.getObject(oldID,"type");
+}}else{item.change="addition";
+}});
+db.loadItems(o.items,baseURI);
+db._listeners.fire("onAfterLoadingItems",[]);
+}}};
+var links=SimileAjax.jQuery("head > link[rel=exhibit/submissions]").get();
+this._loadLinks(links,dbProxy,fDone);
+};
+Exhibit.Database._Impl.prototype._loadLinks=function(links,database,fDone){links=[].concat(links);
+var fNext=function(){while(links.length>0){var link=links.shift();
+var type=link.type;
+if(type==null||type.length==0){type="application/json";
+}var importer=Exhibit.importers[type];
+if(importer){importer.load(link,database,fNext);
+return ;
+}else{SimileAjax.Debug.log("No importer for data of type "+type);
+}}if(fDone!=null){fDone();
+}};
+fNext();
+};
+Exhibit.Database._Impl.prototype.loadData=function(o,baseURI){if(typeof baseURI=="undefined"){baseURI=location.href;
+}if("types" in o){this.loadTypes(o.types,baseURI);
+}if("properties" in o){this.loadProperties(o.properties,baseURI);
+}if("items" in o){this.loadItems(o.items,baseURI);
+}};
+Exhibit.Database._Impl.prototype.loadTypes=function(typeEntries,baseURI){this._listeners.fire("onBeforeLoadingTypes",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}for(var typeID in typeEntries){if(typeof typeID!="string"){continue;
+}var typeEntry=typeEntries[typeID];
+if(typeof typeEntry!="object"){continue;
+}var type;
+if(typeID in this._types){type=this._types[typeID];
+}else{type=new Exhibit.Database._Type(typeID);
+this._types[typeID]=type;
+}for(var p in typeEntry){type._custom[p]=typeEntry[p];
+}if(!("uri" in type._custom)){type._custom["uri"]=baseURI+"type#"+encodeURIComponent(typeID);
+}if(!("label" in type._custom)){type._custom["label"]=typeID;
+}}this._listeners.fire("onAfterLoadingTypes",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadTypes failed");
+}};
+Exhibit.Database._Impl.prototype.loadProperties=function(propertyEntries,baseURI){this._listeners.fire("onBeforeLoadingProperties",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}for(var propertyID in propertyEntries){if(typeof propertyID!="string"){continue;
+}var propertyEntry=propertyEntries[propertyID];
+if(typeof propertyEntry!="object"){continue;
+}var property;
+if(propertyID in this._properties){property=this._properties[propertyID];
+}else{property=new Exhibit.Database._Property(propertyID,this);
+this._properties[propertyID]=property;
+}property._uri=("uri" in propertyEntry)?propertyEntry.uri:(baseURI+"property#"+encodeURIComponent(propertyID));
+property._valueType=("valueType" in propertyEntry)?propertyEntry.valueType:"text";
+property._label=("label" in propertyEntry)?propertyEntry.label:propertyID;
+property._pluralLabel=("pluralLabel" in propertyEntry)?propertyEntry.pluralLabel:property._label;
+property._reverseLabel=("reverseLabel" in propertyEntry)?propertyEntry.reverseLabel:("!"+property._label);
+property._reversePluralLabel=("reversePluralLabel" in propertyEntry)?propertyEntry.reversePluralLabel:("!"+property._pluralLabel);
+property._groupingLabel=("groupingLabel" in propertyEntry)?propertyEntry.groupingLabel:property._label;
+property._reverseGroupingLabel=("reverseGroupingLabel" in propertyEntry)?propertyEntry.reverseGroupingLabel:property._reverseLabel;
+if("origin" in propertyEntry){property._origin=propertyEntry.origin;
+}}this._propertyArray=null;
+this._listeners.fire("onAfterLoadingProperties",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadProperties failed");
+}};
+Exhibit.Database._Impl.prototype.loadItems=function(itemEntries,baseURI){this._listeners.fire("onBeforeLoadingItems",[]);
+try{var lastChar=baseURI.substr(baseURI.length-1);
+if(lastChar=="#"){baseURI=baseURI.substr(0,baseURI.length-1)+"/";
+}else{if(lastChar!="/"&&lastChar!=":"){baseURI+="/";
+}}var spo=this._spo;
+var ops=this._ops;
+var indexPut=Exhibit.Database._indexPut;
+var indexTriple=function(s,p,o){indexPut(spo,s,p,o);
+indexPut(ops,o,p,s);
+};
+for(var i=0;
+i<itemEntries.length;
+i++){var entry=itemEntries[i];
+if(typeof entry=="object"){this._loadItem(entry,indexTriple,baseURI);
+}}this._propertyArray=null;
+this._listeners.fire("onAfterLoadingItems",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.loadItems failed");
+}};
+Exhibit.Database._Impl.prototype.getType=function(typeID){return this._types[typeID];
+};
+Exhibit.Database._Impl.prototype.getProperty=function(propertyID){return propertyID in this._properties?this._properties[propertyID]:null;
+};
+Exhibit.Database._Impl.prototype.getAllProperties=function(){if(this._propertyArray==null){this._propertyArray=[];
+for(var propertyID in this._properties){this._propertyArray.push(propertyID);
+}}return[].concat(this._propertyArray);
+};
+Exhibit.Database._Impl.prototype.isSubmission=function(id){return id in this._submissionRegistry;
+};
+Exhibit.Database._Impl.prototype.getAllItems=function(){var ret=new Exhibit.Set();
+var self=this;
+this._items.visit(function(item){if(!self.isSubmission(item)){ret.add(item);
+}});
+return ret;
+};
+Exhibit.Database._Impl.prototype.getAllSubmissions=function(){var ret=new Exhibit.Set();
+var itemList=this._items.toArray();
+for(var i in itemList){var item=itemList[i];
+if(this.isSubmission(item)){ret.add(item);
+}}return ret;
+};
+Exhibit.Database._Impl.prototype.getAllItemsCount=function(){return this._items.size();
+};
+Exhibit.Database._Impl.prototype.containsItem=function(itemID){return this._items.contains(itemID);
+};
+Exhibit.Database._Impl.prototype.getNamespaces=function(idToQualifiedName,prefixToBase){var bases={};
+for(var propertyID in this._properties){var property=this._properties[propertyID];
+var uri=property.getURI();
+var hash=uri.indexOf("#");
+if(hash>0){var base=uri.substr(0,hash+1);
+bases[base]=true;
+idToQualifiedName[propertyID]={base:base,localName:uri.substr(hash+1)};
+continue;
+}var slash=uri.lastIndexOf("/");
+if(slash>0){var base=uri.substr(0,slash+1);
+bases[base]=true;
+idToQualifiedName[propertyID]={base:base,localName:uri.substr(slash+1)};
+continue;
+}}var baseToPrefix={};
+var letters="abcdefghijklmnopqrstuvwxyz";
+var i=0;
+for(var base in bases){var prefix=letters.substr(i++,1);
+prefixToBase[prefix]=base;
+baseToPrefix[base]=prefix;
+}for(var propertyID in idToQualifiedName){var qname=idToQualifiedName[propertyID];
+qname.prefix=baseToPrefix[qname.base];
+}};
+Exhibit.Database._Impl.prototype._loadItem=function(itemEntry,indexFunction,baseURI){if(!("label" in itemEntry)&&!("id" in itemEntry)){SimileAjax.Debug.warn("Item entry has no label and no id: "+SimileAjax.JSON.toJSONString(itemEntry));
+return ;
+}var id;
+if(!("label" in itemEntry)){id=itemEntry.id;
+if(!this._items.contains(id)){SimileAjax.Debug.warn("Cannot add new item containing no label: "+SimileAjax.JSON.toJSONString(itemEntry));
+}}else{var label=itemEntry.label;
+var id=("id" in itemEntry)?itemEntry.id:label;
+var uri=("uri" in itemEntry)?itemEntry.uri:(baseURI+"item#"+encodeURIComponent(id));
+var type=("type" in itemEntry)?itemEntry.type:"Item";
+var isArray=function(obj){if(obj.constructor.toString().indexOf("Array")==-1){return false;
+}else{return true;
+}};
+if(isArray(label)){label=label[0];
+}if(isArray(id)){id=id[0];
+}if(isArray(uri)){uri=uri[0];
+}if(isArray(type)){type=type[0];
+}this._items.add(id);
+indexFunction(id,"uri",uri);
+indexFunction(id,"label",label);
+indexFunction(id,"type",type);
+this._ensureTypeExists(type,baseURI);
+}itemEntry.modified=itemEntry.modified||"no";
+for(var p in itemEntry){if(typeof p!="string"){continue;
+}if(p!="uri"&&p!="label"&&p!="id"&&p!="type"){this._ensurePropertyExists(p,baseURI)._onNewData();
+var v=itemEntry[p];
+if(v instanceof Array){for(var j=0;
+j<v.length;
+j++){indexFunction(id,p,v[j]);
+}}else{if(v!=undefined&&v!=null){indexFunction(id,p,v);
+}}}}};
+Exhibit.Database._Impl.prototype._ensureTypeExists=function(typeID,baseURI){if(!(typeID in this._types)){var type=new Exhibit.Database._Type(typeID);
+type._custom["uri"]=baseURI+"type#"+encodeURIComponent(typeID);
+type._custom["label"]=typeID;
+this._types[typeID]=type;
+}};
+Exhibit.Database._Impl.prototype._ensurePropertyExists=function(propertyID,baseURI){if(!(propertyID in this._properties)){var property=new Exhibit.Database._Property(propertyID,this);
+property._uri=baseURI+"property#"+encodeURIComponent(propertyID);
+property._valueType="text";
+property._label=propertyID;
+property._pluralLabel=property._label;
+property._reverseLabel="reverse of "+property._label;
+property._reversePluralLabel="reverse of "+property._pluralLabel;
+property._groupingLabel=property._label;
+property._reverseGroupingLabel=property._reverseLabel;
+this._properties[propertyID]=property;
+this._propertyArray=null;
+return property;
+}else{return this._properties[propertyID];
+}};
+Exhibit.Database._indexPut=function(index,x,y,z){var hash=index[x];
+if(!hash){hash={};
+index[x]=hash;
+}var array=hash[y];
+if(!array){array=new Array();
+hash[y]=array;
+}else{for(var i=0;
+i<array.length;
+i++){if(z==array[i]){return ;
+}}}array.push(z);
+};
+Exhibit.Database._indexPutList=function(index,x,y,list){var hash=index[x];
+if(!hash){hash={};
+index[x]=hash;
+}var array=hash[y];
+if(!array){hash[y]=list;
+}else{hash[y]=hash[y].concat(list);
+}};
+Exhibit.Database._indexRemove=function(index,x,y,z){function isEmpty(obj){for(p in obj){return false;
+}return true;
+}var hash=index[x];
+if(!hash){return false;
+}var array=hash[y];
+if(!array){return false;
+}for(var i=0;
+i<array.length;
+i++){if(z==array[i]){array.splice(i,1);
+if(array.length==0){delete hash[y];
+if(isEmpty(hash)){delete index[x];
+}}return true;
+}}};
+Exhibit.Database._indexRemoveList=function(index,x,y){var hash=index[x];
+if(!hash){return null;
+}var array=hash[y];
+if(!array){return null;
+}delete hash[y];
+return array;
+};
+Exhibit.Database._Impl.prototype._indexFillSet=function(index,x,y,set,filter){var hash=index[x];
+if(hash){var array=hash[y];
+if(array){if(filter){for(var i=0;
+i<array.length;
+i++){var z=array[i];
+if(filter.contains(z)){set.add(z);
+}}}else{for(var i=0;
+i<array.length;
+i++){set.add(array[i]);
+}}}}};
+Exhibit.Database._Impl.prototype._indexCountDistinct=function(index,x,y,filter){var count=0;
+var hash=index[x];
+if(hash){var array=hash[y];
+if(array){if(filter){for(var i=0;
+i<array.length;
+i++){if(filter.contains(array[i])){count++;
+}}}else{count=array.length;
+}}}return count;
+};
+Exhibit.Database._Impl.prototype._get=function(index,x,y,set,filter){if(!set){set=new Exhibit.Set();
+}this._indexFillSet(index,x,y,set,filter);
+return set;
+};
+Exhibit.Database._Impl.prototype._getUnion=function(index,xSet,y,set,filter){if(!set){set=new Exhibit.Set();
+}var database=this;
+xSet.visit(function(x){database._indexFillSet(index,x,y,set,filter);
+});
+return set;
+};
+Exhibit.Database._Impl.prototype._countDistinctUnion=function(index,xSet,y,filter){var count=0;
+var database=this;
+xSet.visit(function(x){count+=database._indexCountDistinct(index,x,y,filter);
+});
+return count;
+};
+Exhibit.Database._Impl.prototype._countDistinct=function(index,x,y,filter){return this._indexCountDistinct(index,x,y,filter);
+};
+Exhibit.Database._Impl.prototype._getProperties=function(index,x){var hash=index[x];
+var properties=[];
+if(hash){for(var p in hash){properties.push(p);
+}}return properties;
+};
+Exhibit.Database._Impl.prototype.getObjects=function(s,p,set,filter){return this._get(this._spo,s,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctObjects=function(s,p,filter){return this._countDistinct(this._spo,s,p,filter);
+};
+Exhibit.Database._Impl.prototype.getObjectsUnion=function(subjects,p,set,filter){return this._getUnion(this._spo,subjects,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctObjectsUnion=function(subjects,p,filter){return this._countDistinctUnion(this._spo,subjects,p,filter);
+};
+Exhibit.Database._Impl.prototype.getSubjects=function(o,p,set,filter){return this._get(this._ops,o,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctSubjects=function(o,p,filter){return this._countDistinct(this._ops,o,p,filter);
+};
+Exhibit.Database._Impl.prototype.getSubjectsUnion=function(objects,p,set,filter){return this._getUnion(this._ops,objects,p,set,filter);
+};
+Exhibit.Database._Impl.prototype.countDistinctSubjectsUnion=function(objects,p,filter){return this._countDistinctUnion(this._ops,objects,p,filter);
+};
+Exhibit.Database._Impl.prototype.getObject=function(s,p){var hash=this._spo[s];
+if(hash){var array=hash[p];
+if(array){return array[0];
+}}return null;
+};
+Exhibit.Database._Impl.prototype.getSubject=function(o,p){var hash=this._ops[o];
+if(hash){var array=hash[p];
+if(array){return array[0];
+}}return null;
+};
+Exhibit.Database._Impl.prototype.getForwardProperties=function(s){return this._getProperties(this._spo,s);
+};
+Exhibit.Database._Impl.prototype.getBackwardProperties=function(o){return this._getProperties(this._ops,o);
+};
+Exhibit.Database._Impl.prototype.getSubjectsInRange=function(p,min,max,inclusive,set,filter){var property=this.getProperty(p);
+if(property!=null){var rangeIndex=property.getRangeIndex();
+if(rangeIndex!=null){return rangeIndex.getSubjectsInRange(min,max,inclusive,set,filter);
+}}return(!set)?new Exhibit.Set():set;
+};
+Exhibit.Database._Impl.prototype.getTypeIDs=function(set){return this.getObjectsUnion(set,"type",null,null);
+};
+Exhibit.Database._Impl.prototype.addStatement=function(s,p,o){var indexPut=Exhibit.Database._indexPut;
+indexPut(this._spo,s,p,o);
+indexPut(this._ops,o,p,s);
+};
+Exhibit.Database._Impl.prototype.removeStatement=function(s,p,o){var indexRemove=Exhibit.Database._indexRemove;
+var removedObject=indexRemove(this._spo,s,p,o);
+var removedSubject=indexRemove(this._ops,o,p,s);
+return removedObject||removedSubject;
+};
+Exhibit.Database._Impl.prototype.removeObjects=function(s,p){var indexRemove=Exhibit.Database._indexRemove;
+var indexRemoveList=Exhibit.Database._indexRemoveList;
+var objects=indexRemoveList(this._spo,s,p);
+if(objects==null){return false;
+}else{for(var i=0;
+i<objects.length;
+i++){indexRemove(this._ops,objects[i],p,s);
+}return true;
+}};
+Exhibit.Database._Impl.prototype.removeSubjects=function(o,p){var indexRemove=Exhibit.Database._indexRemove;
+var indexRemoveList=Exhibit.Database._indexRemoveList;
+var subjects=indexRemoveList(this._ops,o,p);
+if(subjects==null){return false;
+}else{for(var i=0;
+i<subjects.length;
+i++){indexRemove(this._spo,subjects[i],p,o);
+}return true;
+}};
+Exhibit.Database._Impl.prototype.removeAllStatements=function(){this._listeners.fire("onBeforeRemovingAllStatements",[]);
+try{this._spo={};
+this._ops={};
+this._items=new Exhibit.Set();
+for(var propertyID in this._properties){this._properties[propertyID]._onNewData();
+}this._propertyArray=null;
+this._listeners.fire("onAfterRemovingAllStatements",[]);
+}catch(e){SimileAjax.Debug.exception(e,"Database.removeAllStatements failed");
+}};
+Exhibit.Database._Type=function(id){this._id=id;
+this._custom={};
+};
+Exhibit.Database._Type.prototype={getID:function(){return this._id;
+},getURI:function(){return this._custom["uri"];
+},getLabel:function(){return this._custom["label"];
+},getOrigin:function(){return this._custom["origin"];
+},getProperty:function(p){return this._custom[p];
+}};
+Exhibit.Database._Property=function(id,database){this._id=id;
+this._database=database;
+this._rangeIndex=null;
+};
+Exhibit.Database._Property.prototype={getID:function(){return this._id;
+},getURI:function(){return this._uri;
+},getValueType:function(){return this._valueType;
+},getLabel:function(){return this._label;
+},getPluralLabel:function(){return this._pluralLabel;
+},getReverseLabel:function(){return this._reverseLabel;
+},getReversePluralLabel:function(){return this._reversePluralLabel;
+},getGroupingLabel:function(){return this._groupingLabel;
+},getGroupingPluralLabel:function(){return this._groupingPluralLabel;
+},getOrigin:function(){return this._origin;
+}};
+Exhibit.Database._Property.prototype._onNewData=function(){this._rangeIndex=null;
+};
+Exhibit.Database._Property.prototype.getRangeIndex=function(){if(this._rangeIndex==null){this._buildRangeIndex();
+}return this._rangeIndex;
+};
+Exhibit.Database._Property.prototype._buildRangeIndex=function(){var getter;
+var database=this._database;
+var p=this._id;
+switch(this.getValueType()){case"currency":case"number":getter=function(item,f){database.getObjects(item,p,null,null).visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+break;
+case"date":getter=function(item,f){database.getObjects(item,p,null,null).visit(function(value){if(value!=null&&!(value instanceof Date)){value=SimileAjax.DateTime.parseIso8601DateTime(value);
+}if(value instanceof Date){f(value.getTime());
+}});
+};
+break;
+default:getter=function(item,f){};
+}this._rangeIndex=new Exhibit.Database._RangeIndex(this._database.getAllItems(),getter);
+};
+Exhibit.Database._RangeIndex=function(items,getter){pairs=[];
+items.visit(function(item){getter(item,function(value){pairs.push({item:item,value:value});
+});
+});
+pairs.sort(function(p1,p2){var c=p1.value-p2.value;
+return(isNaN(c)===false)?c:p1.value.localeCompare(p2.value);
+});
+this._pairs=pairs;
+};
+Exhibit.Database._RangeIndex.prototype.getCount=function(){return this._pairs.length;
+};
+Exhibit.Database._RangeIndex.prototype.getMin=function(){return this._pairs.length>0?this._pairs[0].value:Number.POSITIVE_INFINITY;
+};
+Exhibit.Database._RangeIndex.prototype.getMax=function(){return this._pairs.length>0?this._pairs[this._pairs.length-1].value:Number.NEGATIVE_INFINITY;
+};
+Exhibit.Database._RangeIndex.prototype.getRange=function(visitor,min,max,inclusive){var startIndex=this._indexOf(min);
+var pairs=this._pairs;
+var l=pairs.length;
+inclusive=(inclusive);
+while(startIndex<l){var pair=pairs[startIndex++];
+var value=pair.value;
+if(value<max||(value==max&&inclusive)){visitor(pair.item);
+}else{break;
+}}};
+Exhibit.Database._RangeIndex.prototype.getSubjectsInRange=function(min,max,inclusive,set,filter){if(!set){set=new Exhibit.Set();
+}var f=(filter!=null)?function(item){if(filter.contains(item)){set.add(item);
+}}:function(item){set.add(item);
+};
+this.getRange(f,min,max,inclusive);
+return set;
+};
+Exhibit.Database._RangeIndex.prototype.countRange=function(min,max,inclusive){var startIndex=this._indexOf(min);
+var endIndex=this._indexOf(max);
+if(inclusive){var pairs=this._pairs;
+var l=pairs.length;
+while(endIndex<l){if(pairs[endIndex].value==max){endIndex++;
+}else{break;
+}}}return endIndex-startIndex;
+};
+Exhibit.Database._RangeIndex.prototype._indexOf=function(v){var pairs=this._pairs;
+if(pairs.length==0||pairs[0].value>=v){return 0;
+}var from=0;
+var to=pairs.length;
+while(from+1<to){var middle=(from+to)>>1;
+var v2=pairs[middle].value;
+if(v2>=v){to=middle;
+}else{from=middle;
+}}return to;
+};
+Exhibit.Database._Impl.prototype.isNewItem=function(id){return id in this._newItems;
+};
+Exhibit.Database._Impl.prototype.getItem=function(id){var item={id:id};
+var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+var val=this.getObject(id,prop);
+if(val){item[prop]=val;
+}}return item;
+};
+Exhibit.Database._Impl.prototype.addItem=function(item){if(!item.id){item.id=item.label;
+}if(!item.modified){item.modified="yes";
+}this._ensurePropertyExists(Exhibit.Database.TimestampPropertyName);
+item[Exhibit.Database.TimestampPropertyName]=Exhibit.Database.makeISO8601DateString();
+this.loadItems([item],"");
+this._newItems[item.id]=true;
+this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database._Impl.prototype.editItem=function(id,prop,value){if(prop.toLowerCase()=="id"){Exhibit.UI.showHelp("We apologize, but changing the IDs of items in the Exhibit isn't supported at the moment.");
+return ;
+}var prevValue=this.getObject(id,prop);
+this._originalValues[id]=this._originalValues[id]||{};
+this._originalValues[id][prop]=this._originalValues[id][prop]||prevValue;
+var origVal=this._originalValues[id][prop];
+if(origVal==value){this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+delete this._originalValues[id][prop];
+}else{if(this.getObject(id,"modified")!="yes"){this.removeObjects(id,"modified");
+this.addStatement(id,"modified","yes");
+}}this.removeObjects(id,prop);
+this.addStatement(id,prop,value);
+var propertyObject=this._ensurePropertyExists(prop);
+propertyObject._onNewData();
+this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database._Impl.prototype.removeItem=function(id){if(!this.containsItem(id)){throw"Removing non-existent item "+id;
+}this._items.remove(id);
+delete this._spo[id];
+if(this._newItems[id]){delete this._newItems[id];
+}if(this._originalValues[id]){delete this._originalValues[id];
+}var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+this.removeObjects(id,prop);
+}this._listeners.fire("onAfterLoadingItems",[]);
+};
+Exhibit.Database.defaultIgnoredProperties=["uri","modified"];
+Exhibit.Database._Impl.prototype.fixAllChanges=function(){this._originalValues={};
+this._newItems={};
+var items=this._items.toArray();
+for(var i in items){var id=items[i];
+this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+}};
+Exhibit.Database._Impl.prototype.fixChangesForItem=function(id){delete this._originalValues[id];
+delete this._newItems[id];
+this.removeObjects(id,"modified");
+this.addStatement(id,"modified","no");
+};
+Exhibit.Database._Impl.prototype.collectChangesForItem=function(id,ignoredProperties){ignoredProperties=ignoredProperties||Exhibit.Database.defaultIgnoredProperties;
+var type=this.getObject(id,"type");
+var label=this.getObject(id,"label")||id;
+var item={id:id,label:label,type:type,vals:{}};
+if(id in this._newItems){item.changeType="added";
+var properties=this.getAllProperties();
+for(var i in properties){var prop=properties[i];
+if(ignoredProperties.indexOf(prop)!=-1){continue;
+}var val=this.getObject(id,prop);
+if(val){item.vals[prop]={newVal:val};
+}}}else{if(id in this._originalValues&&!this.isSubmission(id)){item.changeType="modified";
+var vals=this._originalValues[id];
+var hasModification=false;
+for(var prop in vals){if(ignoredProperties.indexOf(prop)!=-1){continue;
+}hasModification=true;
+var oldVal=this._originalValues[id][prop];
+var newVal=this.getObject(id,prop);
+if(!newVal){SimileAjax.Debug.warn("empty value for "+id+", "+prop);
+}else{item.vals[prop]={oldVal:oldVal,newVal:newVal};
+}}if(!hasModification){return null;
+}}else{return null;
+}}if(!item[Exhibit.Database.TimestampPropertyName]){item[Exhibit.Database.TimestampPropertyName]=Exhibit.Database.makeISO8601DateString();
+}return item;
+};
+Exhibit.Database._Impl.prototype.collectAllChanges=function(ignoredProperties){var ret=[];
+var items=this._items.toArray();
+for(var i in items){var id=items[i];
+var item=this.collectChangesForItem(id,ignoredProperties);
+if(item){ret.push(item);
+}}return ret;
+};
+Exhibit.Database._Impl.prototype.mergeSubmissionIntoItem=function(submissionID){var db=this;
+if(!this.isSubmission(submissionID)){throw submissionID+" is not a submission!";
+}var change=this.getObject(submissionID,"change");
+if(change=="modification"){var itemID=this.getObject(submissionID,"changedItem");
+var vals=this._spo[submissionID];
+SimileAjax.jQuery.each(vals,function(attr,val){if(Exhibit.Database.defaultIgnoredSubmissionProperties.indexOf(attr)!=-1){return ;
+}if(val.length==1){db.editItem(itemID,attr,val[0]);
+}else{SimileAjax.Debug.warn("Exhibit.Database._Impl.prototype.commitChangeToItem cannot handle multiple values for attribute "+attr+": "+val);
+}});
+delete this._submissionRegistry[submissionID];
+}else{if(change=="addition"){delete this._submissionRegistry[submissionID];
+this._newItems[submissionID]=true;
+}else{throw"unknown change type "+change;
+}}this._listeners.fire("onAfterLoadingItems",[]);
+};
+
+
+/* bibtex-exporter.js */
+Exhibit.BibtexExporter={getLabel:function(){return"Bibtex";
+},_excludeProperties:{"pub-type":true,"type":true,"uri":true,"key":true}};
+Exhibit.BibtexExporter.exportOne=function(itemID,database){return Exhibit.BibtexExporter._wrap(Exhibit.BibtexExporter._exportOne(itemID,database));
+};
+Exhibit.BibtexExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.BibtexExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.BibtexExporter._wrap(s);
+};
+Exhibit.BibtexExporter._exportOne=function(itemID,database){var s="";
+var type=database.getObject(itemID,"pub-type");
+var key=database.getObject(itemID,"key");
+key=(key!=null?key:itemID);
+key=key.replace(/[\s,]/g,"-");
+s+="@"+type+"{"+key+",\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(values.size()>0&&!(propertyID in Exhibit.BibtexExporter._excludeProperties)){s+="\t"+(propertyID=="label"?"title":propertyID)+' = "';
+var strings;
+if(valueType=="item"){strings=[];
+values.visit(function(value){strings.push(database.getObject(value,"label"));
+});
+}else{if(valueType=="url"){strings=[];
+values.visit(function(value){strings.push(Exhibit.Persistence.resolveURL(value));
+});
+}else{strings=values.toArray();
+}}s+=strings.join(" and ")+'",\n';
+}}s+='\torigin = "'+Exhibit.Persistence.getItemLink(itemID)+'"\n';
+s+="}\n";
+return s;
+};
+Exhibit.BibtexExporter._wrap=function(s){return s;
+};
+
+
+/* exhibit-json-exporter.js */
+Exhibit.ExhibitJsonExporter={getLabel:function(){return Exhibit.l10n.exhibitJsonExporterLabel;
+}};
+Exhibit.ExhibitJsonExporter.exportOne=function(itemID,database){return Exhibit.ExhibitJsonExporter._wrap(Exhibit.ExhibitJsonExporter._exportOne(itemID,database)+"\n");
+};
+Exhibit.ExhibitJsonExporter.exportMany=function(set,database){var s="";
+var size=set.size();
+var count=0;
+set.visit(function(itemID){s+=Exhibit.ExhibitJsonExporter._exportOne(itemID,database)+((count++<size-1)?",\n":"\n");
+});
+return Exhibit.ExhibitJsonExporter._wrap(s);
+};
+Exhibit.ExhibitJsonExporter._exportOne=function(itemID,database){function quote(s){if(/[\\\x00-\x1F\x22]/.test(s)){return'"'+s.replace(/([\\\x00-\x1f\x22])/g,function(a,b){var c={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"}[b];
+if(c){return c;
+}c=b.charCodeAt();
+return"\\x"+Math.floor(c/16).toString(16)+(c%16).toString(16);
+})+'"';
+}return'"'+s+'"';
+}var s="";
+var uri=database.getObject(itemID,"uri");
+s+=' {"id":'+quote(itemID)+",\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(values.size()>0){var array;
+if(valueType=="url"){array=[];
+values.visit(function(value){array.push(Exhibit.Persistence.resolveURL(value));
+});
+}else{array=values.toArray();
+}s+=" "+quote(propertyID)+":";
+if(array.length==1){s+=quote(array[0]);
+}else{s+="[";
+for(var j=0;
+j<array.length;
+j++){s+=(j>0?",":"")+quote(array[j]);
+}s+="]";
+}s+=",\n";
+}}s+=' "origin":'+quote(Exhibit.Persistence.getItemLink(itemID))+"\n";
+s+=" }";
+return s;
+};
+Exhibit.ExhibitJsonExporter._wrap=function(s){return'{\n "items":[\n'+s+" ]\n}";
+};
+
+
+/* facet-selection-exporter.js */
+Exhibit.FacetSelectionExporter={getLabel:function(){return"Facet Selections";
+},exportOne:function(itemID,database){return Exhibit.FacetSelectionExporter._exportUrl();
+},exportMany:function(set,database){return Exhibit.FacetSelectionExporter._exportUrl();
+}};
+Exhibit.FacetSelectionExporter._exportUrl=function(){var currentSettings=window.exhibit.exportSettings();
+var url=window.location.href.split("?")[0]+"?";
+var sep="";
+for(id in currentSettings){url+=sep+id+"="+escape(currentSettings[id]);
+if(sep===""){sep="&";
+}}return url;
+};
+
+
+/* rdf-xml-exporter.js */
+Exhibit.RdfXmlExporter={getLabel:function(){return Exhibit.l10n.rdfXmlExporterLabel;
+}};
+Exhibit.RdfXmlExporter.exportOne=function(itemID,database){var propertyIDToQualifiedName={};
+var prefixToBase={};
+database.getNamespaces(propertyIDToQualifiedName,prefixToBase);
+return Exhibit.RdfXmlExporter._wrapRdf(Exhibit.RdfXmlExporter._exportOne(itemID,database,propertyIDToQualifiedName,prefixToBase),prefixToBase);
+};
+Exhibit.RdfXmlExporter.exportMany=function(set,database){var s="";
+var propertyIDToQualifiedName={};
+var prefixToBase={};
+database.getNamespaces(propertyIDToQualifiedName,prefixToBase);
+set.visit(function(itemID){s+=Exhibit.RdfXmlExporter._exportOne(itemID,database,propertyIDToQualifiedName,prefixToBase)+"\n";
+});
+return Exhibit.RdfXmlExporter._wrapRdf(s,prefixToBase);
+};
+Exhibit.RdfXmlExporter._exportOne=function(itemID,database,propertyIDToQualifiedName,prefixToBase){var s="";
+var uri=database.getObject(itemID,"uri");
+s+="<rdf:Description rdf:about='"+uri+"'>\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+var propertyString;
+if(propertyID in propertyIDToQualifiedName){var qname=propertyIDToQualifiedName[propertyID];
+propertyString=qname.prefix+":"+qname.localName;
+}else{propertyString=property.getURI();
+}if(valueType=="item"){values.visit(function(value){s+="\t<"+propertyString+" rdf:resource='"+value+"' />\n";
+});
+}else{if(propertyID!="uri"){if(valueType=="url"){values.visit(function(value){s+="\t<"+propertyString+">"+Exhibit.Persistence.resolveURL(value)+"</"+propertyString+">\n";
+});
+}else{values.visit(function(value){s+="\t<"+propertyString+">"+value+"</"+propertyString+">\n";
+});
+}}}}s+="\t<exhibit:origin>"+Exhibit.Persistence.getItemLink(itemID)+"</exhibit:origin>\n";
+s+="</rdf:Description>";
+return s;
+};
+Exhibit.RdfXmlExporter._wrapRdf=function(s,prefixToBase){var s2="<?xml version = '1.0'?>\n<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n\txmlns:exhibit='http://simile.mit.edu/2006/11/exhibit#'";
+for(prefix in prefixToBase){s2+="\n\txmlns:"+prefix+"='"+prefixToBase[prefix]+"'";
+}s2+=">\n"+s+"\n</rdf:RDF>";
+return s2;
+};
+
+
+/* semantic-wikitext-exporter.js */
+Exhibit.SemanticWikitextExporter={getLabel:function(){return Exhibit.l10n.smwExporterLabel;
+}};
+Exhibit.SemanticWikitextExporter.exportOne=function(itemID,database){return Exhibit.SemanticWikitextExporter._wrap(Exhibit.SemanticWikitextExporter._exportOne(itemID,database));
+};
+Exhibit.SemanticWikitextExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.SemanticWikitextExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.SemanticWikitextExporter._wrap(s);
+};
+Exhibit.SemanticWikitextExporter._exportOne=function(itemID,database){var s="";
+var uri=database.getObject(itemID,"uri");
+s+=uri+"\n";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+if(valueType=="item"){values.visit(function(value){s+="[["+propertyID+"::"+value+"]]\n";
+});
+}else{if(valueType=="url"){values.visit(function(value){s+="[["+propertyID+":="+Exhibit.Persistence.resolveURL(value)+"]]\n";
+});
+}else{values.visit(function(value){s+="[["+propertyID+":="+value+"]]\n";
+});
+}}}s+="[[origin:="+Exhibit.Persistence.getItemLink(itemID)+"]]\n";
+s+="\n";
+return s;
+};
+Exhibit.SemanticWikitextExporter._wrap=function(s){return s;
+};
+
+
+/* tsv-exporter.js */
+Exhibit.TSVExporter={getLabel:function(){return Exhibit.l10n.tsvExporterLabel;
+}};
+Exhibit.TSVExporter.exportOne=function(itemID,database){return Exhibit.TSVExporter._wrap(Exhibit.TSVExporter._exportOne(itemID,database),database);
+};
+Exhibit.TSVExporter.exportMany=function(set,database){var s="";
+set.visit(function(itemID){s+=Exhibit.TSVExporter._exportOne(itemID,database)+"\n";
+});
+return Exhibit.TSVExporter._wrap(s,database);
+};
+Exhibit.TSVExporter._exportOne=function(itemID,database){var s="";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var values=database.getObjects(itemID,propertyID);
+var valueType=property.getValueType();
+s+=values.toArray().join("; ")+"\t";
+}return s;
+};
+Exhibit.TSVExporter._wrap=function(s,database){var header="";
+var allProperties=database.getAllProperties();
+for(var i=0;
+i<allProperties.length;
+i++){var propertyID=allProperties[i];
+var property=database.getProperty(propertyID);
+var valueType=property.getValueType();
+header+=propertyID+":"+valueType+"\t";
+}return header+"\n"+s;
+};
+
+
+/* expression-parser.js */
+Exhibit.ExpressionParser=new Object();
+Exhibit.ExpressionParser.parse=function(s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.ExpressionScanner(s,startIndex);
+try{return Exhibit.ExpressionParser._internalParse(scanner,false);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.ExpressionParser.parseSeveral=function(s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.ExpressionScanner(s,startIndex);
+try{return Exhibit.ExpressionParser._internalParse(scanner,true);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.ExpressionParser._internalParse=function(scanner,several){var Scanner=Exhibit.ExpressionScanner;
+var token=scanner.token();
+var next=function(){scanner.next();
+token=scanner.token();
+};
+var makePosition=function(){return token!=null?token.start:scanner.index();
+};
+var parsePath=function(){var path=new Exhibit.Expression.Path();
+while(token!=null&&token.type==Scanner.PATH_OPERATOR){var hopOperator=token.value;
+next();
+if(token!=null&&token.type==Scanner.IDENTIFIER){path.appendSegment(token.value,hopOperator);
+next();
+}else{throw new Error("Missing property ID at position "+makePosition());
+}}return path;
+};
+var parseFactor=function(){if(token==null){throw new Error("Missing factor at end of expression");
+}var result=null;
+switch(token.type){case Scanner.NUMBER:result=new Exhibit.Expression._Constant(token.value,"number");
+next();
+break;
+case Scanner.STRING:result=new Exhibit.Expression._Constant(token.value,"text");
+next();
+break;
+case Scanner.PATH_OPERATOR:result=parsePath();
+break;
+case Scanner.IDENTIFIER:var identifier=token.value;
+next();
+if(identifier in Exhibit.Controls){if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="("){next();
+var args=(token!=null&&token.type==Scanner.DELIMITER&&token.value==")")?[]:parseExpressionList();
+result=new Exhibit.Expression._ControlCall(identifier,args);
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+}else{throw new Error("Missing ) to end "+identifier+" at position "+makePosition());
+}}else{throw new Error("Missing ( to start "+identifier+" at position "+makePosition());
+}}else{if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="("){next();
+var args=(token!=null&&token.type==Scanner.DELIMITER&&token.value==")")?[]:parseExpressionList();
+result=new Exhibit.Expression._FunctionCall(identifier,args);
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+}else{throw new Error("Missing ) after function call "+identifier+" at position "+makePosition());
+}}else{result=parsePath();
+result.setRootName(identifier);
+}}break;
+case Scanner.DELIMITER:if(token.value=="("){next();
+result=parseExpression();
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value==")"){next();
+break;
+}else{throw new Error("Missing ) at position "+makePosition());
+}}default:throw new Error("Unexpected text "+token.value+" at position "+makePosition());
+}return result;
+};
+var parseTerm=function(){var term=parseFactor();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="*"||token.value=="/")){var operator=token.value;
+next();
+term=new Exhibit.Expression._Operator(operator,[term,parseFactor()]);
+}return term;
+};
+var parseSubExpression=function(){var subExpression=parseTerm();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="+"||token.value=="-")){var operator=token.value;
+next();
+subExpression=new Exhibit.Expression._Operator(operator,[subExpression,parseTerm()]);
+}return subExpression;
+};
+var parseExpression=function(){var expression=parseSubExpression();
+while(token!=null&&token.type==Scanner.OPERATOR&&(token.value=="="||token.value=="<>"||token.value=="<"||token.value=="<="||token.value==">"||token.value==">=")){var operator=token.value;
+next();
+expression=new Exhibit.Expression._Operator(operator,[expression,parseSubExpression()]);
+}return expression;
+};
+var parseExpressionList=function(){var expressions=[parseExpression()];
+while(token!=null&&token.type==Scanner.DELIMITER&&token.value==","){next();
+expressions.push(parseExpression());
+}return expressions;
+};
+if(several){var roots=parseExpressionList();
+var expressions=[];
+for(var r=0;
+r<roots.length;
+r++){expressions.push(new Exhibit.Expression._Impl(roots[r]));
+}return expressions;
+}else{return new Exhibit.Expression._Impl(parseExpression());
+}};
+Exhibit.ExpressionScanner=function(text,startIndex){this._text=text+" ";
+this._maxIndex=text.length;
+this._index=startIndex;
+this.next();
+};
+Exhibit.ExpressionScanner.DELIMITER=0;
+Exhibit.ExpressionScanner.NUMBER=1;
+Exhibit.ExpressionScanner.STRING=2;
+Exhibit.ExpressionScanner.IDENTIFIER=3;
+Exhibit.ExpressionScanner.OPERATOR=4;
+Exhibit.ExpressionScanner.PATH_OPERATOR=5;
+Exhibit.ExpressionScanner.prototype.token=function(){return this._token;
+};
+Exhibit.ExpressionScanner.prototype.index=function(){return this._index;
+};
+Exhibit.ExpressionScanner.prototype.next=function(){this._token=null;
+while(this._index<this._maxIndex&&" \t\r\n".indexOf(this._text.charAt(this._index))>=0){this._index++;
+}if(this._index<this._maxIndex){var c1=this._text.charAt(this._index);
+var c2=this._text.charAt(this._index+1);
+if(".!".indexOf(c1)>=0){if(c2=="@"){this._token={type:Exhibit.ExpressionScanner.PATH_OPERATOR,value:c1+c2,start:this._index,end:this._index+2};
+this._index+=2;
+}else{this._token={type:Exhibit.ExpressionScanner.PATH_OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}}else{if("<>".indexOf(c1)>=0){if((c2=="=")||("<>".indexOf(c2)>=0&&c1!=c2)){this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1+c2,start:this._index,end:this._index+2};
+this._index+=2;
+}else{this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}}else{if("+-*/=".indexOf(c1)>=0){this._token={type:Exhibit.ExpressionScanner.OPERATOR,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("(),".indexOf(c1)>=0){this._token={type:Exhibit.ExpressionScanner.DELIMITER,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("\"'".indexOf(c1)>=0){var i=this._index+1;
+while(i<this._maxIndex){if(this._text.charAt(i)==c1&&this._text.charAt(i-1)!="\\"){break;
+}i++;
+}if(i<this._maxIndex){this._token={type:Exhibit.ExpressionScanner.STRING,value:this._text.substring(this._index+1,i).replace(/\\'/g,"'").replace(/\\"/g,'"'),start:this._index,end:i+1};
+this._index=i+1;
+}else{throw new Error("Unterminated string starting at "+this._index);
+}}else{if(this._isDigit(c1)){var i=this._index;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}if(i<this._maxIndex&&this._text.charAt(i)=="."){i++;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}}this._token={type:Exhibit.ExpressionScanner.NUMBER,value:parseFloat(this._text.substring(this._index,i)),start:this._index,end:i};
+this._index=i;
+}else{var i=this._index;
+while(i<this._maxIndex){var c=this._text.charAt(i);
+if("(),.!@ \t".indexOf(c)<0){i++;
+}else{break;
+}}this._token={type:Exhibit.ExpressionScanner.IDENTIFIER,value:this._text.substring(this._index,i),start:this._index,end:i};
+this._index=i;
+}}}}}}}};
+Exhibit.ExpressionScanner.prototype._isDigit=function(c){return"0123456789".indexOf(c)>=0;
+};
+
+
+/* expression.js */
+Exhibit.Expression=new Object();
+Exhibit.Expression._Impl=function(rootNode){this._rootNode=rootNode;
+};
+Exhibit.Expression._Impl.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var collection=this._rootNode.evaluate(roots,rootValueTypes,defaultRootName,database);
+return{values:collection.getSet(),valueType:collection.valueType,size:collection.size};
+};
+Exhibit.Expression._Impl.prototype.evaluateOnItem=function(itemID,database){return this.evaluate({"value":itemID},{"value":"item"},"value",database);
+};
+Exhibit.Expression._Impl.prototype.evaluateSingle=function(roots,rootValueTypes,defaultRootName,database){var collection=this._rootNode.evaluate(roots,rootValueTypes,defaultRootName,database);
+var result={value:null,valueType:collection.valueType};
+collection.forEachValue(function(v){result.value=v;
+return true;
+});
+return result;
+};
+Exhibit.Expression._Impl.prototype.evaluateSingleOnItem=function(itemID,database){return this.evaluateSingle({"value":itemID},{"value":"item"},"value",database);
+};
+Exhibit.Expression._Impl.prototype.testExists=function(roots,rootValueTypes,defaultRootName,database){return this.isPath()?this._rootNode.testExists(roots,rootValueTypes,defaultRootName,database):this.evaluate(roots,rootValueTypes,defaultRootName,database).values.size()>0;
+};
+Exhibit.Expression._Impl.prototype.isPath=function(){return this._rootNode instanceof Exhibit.Expression.Path;
+};
+Exhibit.Expression._Impl.prototype.getPath=function(){return this.isPath()?this._rootNode:null;
+};
+Exhibit.Expression._Collection=function(values,valueType){this._values=values;
+this.valueType=valueType;
+if(values instanceof Array){this.forEachValue=Exhibit.Expression._Collection._forEachValueInArray;
+this.getSet=Exhibit.Expression._Collection._getSetFromArray;
+this.contains=Exhibit.Expression._Collection._containsInArray;
+this.size=values.length;
+}else{this.forEachValue=Exhibit.Expression._Collection._forEachValueInSet;
+this.getSet=Exhibit.Expression._Collection._getSetFromSet;
+this.contains=Exhibit.Expression._Collection._containsInSet;
+this.size=values.size();
+}};
+Exhibit.Expression._Collection._forEachValueInSet=function(f){this._values.visit(f);
+};
+Exhibit.Expression._Collection._forEachValueInArray=function(f){var a=this._values;
+for(var i=0;
+i<a.length;
+i++){if(f(a[i])){break;
+}}};
+Exhibit.Expression._Collection._getSetFromSet=function(){return this._values;
+};
+Exhibit.Expression._Collection._getSetFromArray=function(){return new Exhibit.Set(this._values);
+};
+Exhibit.Expression._Collection._containsInSet=function(v){this._values.contains(v);
+};
+Exhibit.Expression._Collection._containsInArray=function(v){var a=this._values;
+for(var i=0;
+i<a.length;
+i++){if(a[i]==v){return true;
+}}return false;
+};
+Exhibit.Expression.Path=function(){this._rootName=null;
+this._segments=[];
+};
+Exhibit.Expression.Path.create=function(property,forward){var path=new Exhibit.Expression.Path();
+path._segments.push({property:property,forward:forward,isArray:false});
+return path;
+};
+Exhibit.Expression.Path.prototype.setRootName=function(rootName){this._rootName=rootName;
+};
+Exhibit.Expression.Path.prototype.appendSegment=function(property,hopOperator){this._segments.push({property:property,forward:hopOperator.charAt(0)==".",isArray:hopOperator.length>1});
+};
+Exhibit.Expression.Path.prototype.getSegment=function(index){if(index<this._segments.length){var segment=this._segments[index];
+return{property:segment.property,forward:segment.forward,isArray:segment.isArray};
+}else{return null;
+}};
+Exhibit.Expression.Path.prototype.getLastSegment=function(){return this.getSegment(this._segments.length-1);
+};
+Exhibit.Expression.Path.prototype.getSegmentCount=function(){return this._segments.length;
+};
+Exhibit.Expression.Path.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var rootName=this._rootName!=null?this._rootName:defaultRootName;
+var valueType=rootName in rootValueTypes?rootValueTypes[rootName]:"text";
+var collection=null;
+if(rootName in roots){var root=roots[rootName];
+if(root instanceof Exhibit.Set||root instanceof Array){collection=new Exhibit.Expression._Collection(root,valueType);
+}else{collection=new Exhibit.Expression._Collection([root],valueType);
+}return this._walkForward(collection,database);
+}else{throw new Error("No such variable called "+rootName);
+}};
+Exhibit.Expression.Path.prototype.evaluateBackward=function(value,valueType,filter,database){var collection=new Exhibit.Expression._Collection([value],valueType);
+return this._walkBackward(collection,filter,database);
+};
+Exhibit.Expression.Path.prototype.walkForward=function(values,valueType,database){return this._walkForward(new Exhibit.Expression._Collection(values,valueType),database);
+};
+Exhibit.Expression.Path.prototype.walkBackward=function(values,valueType,filter,database){return this._walkBackward(new Exhibit.Expression._Collection(values,valueType),filter,database);
+};
+Exhibit.Expression.Path.prototype._walkForward=function(collection,database){for(var i=0;
+i<this._segments.length;
+i++){var segment=this._segments[i];
+if(segment.isArray){var a=[];
+var valueType;
+if(segment.forward){collection.forEachValue(function(v){database.getObjects(v,segment.property).visit(function(v2){a.push(v2);
+});
+});
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}else{collection.forEachValue(function(v){database.getSubjects(v,segment.property).visit(function(v2){a.push(v2);
+});
+});
+valueType="item";
+}collection=new Exhibit.Expression._Collection(a,valueType);
+}else{if(segment.forward){var values=database.getObjectsUnion(collection.getSet(),segment.property);
+var property=database.getProperty(segment.property);
+var valueType=property!=null?property.getValueType():"text";
+collection=new Exhibit.Expression._Collection(values,valueType);
+}else{var values=database.getSubjectsUnion(collection.getSet(),segment.property);
+collection=new Exhibit.Expression._Collection(values,"item");
+}}}return collection;
+};
+Exhibit.Expression.Path.prototype._walkBackward=function(collection,filter,database){for(var i=this._segments.length-1;
+i>=0;
+i--){var segment=this._segments[i];
+if(segment.isArray){var a=[];
+var valueType;
+if(segment.forward){collection.forEachValue(function(v){database.getSubjects(v,segment.property).visit(function(v2){if(i>0||filter==null||filter.contains(v2)){a.push(v2);
+}});
+});
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}else{collection.forEachValue(function(v){database.getObjects(v,segment.property).visit(function(v2){if(i>0||filter==null||filter.contains(v2)){a.push(v2);
+}});
+});
+valueType="item";
+}collection=new Exhibit.Expression._Collection(a,valueType);
+}else{if(segment.forward){var values=database.getSubjectsUnion(collection.getSet(),segment.property,null,i==0?filter:null);
+collection=new Exhibit.Expression._Collection(values,"item");
+}else{var values=database.getObjectsUnion(collection.getSet(),segment.property,null,i==0?filter:null);
+var property=database.getProperty(segment.property);
+var valueType=property!=null?property.getValueType():"text";
+collection=new Exhibit.Expression._Collection(values,valueType);
+}}}return collection;
+};
+Exhibit.Expression.Path.prototype.rangeBackward=function(from,to,inclusive,filter,database){var set=new Exhibit.Set();
+var valueType="item";
+if(this._segments.length>0){var segment=this._segments[this._segments.length-1];
+if(segment.forward){database.getSubjectsInRange(segment.property,from,to,inclusive,set,this._segments.length==1?filter:null);
+}else{throw new Error("Last path of segment must be forward");
+}for(var i=this._segments.length-2;
+i>=0;
+i--){segment=this._segments[i];
+if(segment.forward){set=database.getSubjectsUnion(set,segment.property,null,i==0?filter:null);
+valueType="item";
+}else{set=database.getObjectsUnion(set,segment.property,null,i==0?filter:null);
+var property=database.getProperty(segment.property);
+valueType=property!=null?property.getValueType():"text";
+}}}return{valueType:valueType,values:set,count:set.size()};
+};
+Exhibit.Expression.Path.prototype.testExists=function(roots,rootValueTypes,defaultRootName,database){return this.evaluate(roots,rootValueTypes,defaultRootName,database).size>0;
+};
+Exhibit.Expression._Constant=function(value,valueType){this._value=value;
+this._valueType=valueType;
+};
+Exhibit.Expression._Constant.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){return new Exhibit.Expression._Collection([this._value],this._valueType);
+};
+Exhibit.Expression._Operator=function(operator,args){this._operator=operator;
+this._args=args;
+};
+Exhibit.Expression._Operator.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var values=[];
+var args=[];
+for(var i=0;
+i<this._args.length;
+i++){args.push(this._args[i].evaluate(roots,rootValueTypes,defaultRootName,database));
+}var operator=Exhibit.Expression._operators[this._operator];
+var f=operator.f;
+if(operator.argumentType=="number"){args[0].forEachValue(function(v1){if(!(typeof v1=="number")){v1=parseFloat(v1);
+}args[1].forEachValue(function(v2){if(!(typeof v2=="number")){v2=parseFloat(v2);
+}values.push(f(v1,v2));
+});
+});
+}else{args[0].forEachValue(function(v1){args[1].forEachValue(function(v2){values.push(f(v1,v2));
+});
+});
+}return new Exhibit.Expression._Collection(values,operator.valueType);
+};
+Exhibit.Expression._operators={"+":{argumentType:"number",valueType:"number",f:function(a,b){return a+b;
+}},"-":{argumentType:"number",valueType:"number",f:function(a,b){return a-b;
+}},"*":{argumentType:"number",valueType:"number",f:function(a,b){return a*b;
+}},"/":{argumentType:"number",valueType:"number",f:function(a,b){return a/b;
+}},"=":{valueType:"boolean",f:function(a,b){return a==b;
+}},"<>":{valueType:"boolean",f:function(a,b){return a!=b;
+}},"><":{valueType:"boolean",f:function(a,b){return a!=b;
+}},"<":{argumentType:"number",valueType:"boolean",f:function(a,b){return a<b;
+}},">":{argumentType:"number",valueType:"boolean",f:function(a,b){return a>b;
+}},"<=":{argumentType:"number",valueType:"boolean",f:function(a,b){return a<=b;
+}},">=":{argumentType:"number",valueType:"boolean",f:function(a,b){return a>=b;
+}}};
+Exhibit.Expression._FunctionCall=function(name,args){this._name=name;
+this._args=args;
+};
+Exhibit.Expression._FunctionCall.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){var args=[];
+for(var i=0;
+i<this._args.length;
+i++){args.push(this._args[i].evaluate(roots,rootValueTypes,defaultRootName,database));
+}if(this._name in Exhibit.Functions){return Exhibit.Functions[this._name].f(args);
+}else{throw new Error("No such function named "+this._name);
+}};
+Exhibit.Expression._ControlCall=function(name,args){this._name=name;
+this._args=args;
+};
+Exhibit.Expression._ControlCall.prototype.evaluate=function(roots,rootValueTypes,defaultRootName,database){return Exhibit.Controls[this._name].f(this._args,roots,rootValueTypes,defaultRootName,database);
+};
+
+
+/* functions.js */
+Exhibit.Functions={};
+Exhibit.FunctionUtilities={};
+Exhibit.FunctionUtilities.registerSimpleMappingFunction=function(name,f,valueType){Exhibit.Functions[name]={f:function(args){var set=new Exhibit.Set();
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){var v2=f(v);
+if(v2!=undefined){set.add(v2);
+}});
+}return new Exhibit.Expression._Collection(set,valueType);
+}};
+};
+Exhibit.Functions["union"]={f:function(args){var set=new Exhibit.Set();
+var valueType=null;
+if(args.length>0){var valueType=args[0].valueType;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+if(arg.size>0){if(valueType==null){valueType=arg.valueType;
+}set.addSet(arg.getSet());
+}}}return new Exhibit.Expression._Collection(set,valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["contains"]={f:function(args){var result=args[0].size>0;
+var set=args[0].getSet();
+args[1].forEachValue(function(v){if(!set.contains(v)){result=false;
+return true;
+}});
+return new Exhibit.Expression._Collection([result],"boolean");
+}};
+Exhibit.Functions["exists"]={f:function(args){return new Exhibit.Expression._Collection([args[0].size>0],"boolean");
+}};
+Exhibit.Functions["count"]={f:function(args){return new Exhibit.Expression._Collection([args[0].size],"number");
+}};
+Exhibit.Functions["not"]={f:function(args){return new Exhibit.Expression._Collection([!args[0].contains(true)],"boolean");
+}};
+Exhibit.Functions["and"]={f:function(args){var r=true;
+for(var i=0;
+r&&i<args.length;
+i++){r=r&&args[i].contains(true);
+}return new Exhibit.Expression._Collection([r],"boolean");
+}};
+Exhibit.Functions["or"]={f:function(args){var r=false;
+for(var i=0;
+!r&&i<args.length;
+i++){r=r||args[i].contains(true);
+}return new Exhibit.Expression._Collection([r],"boolean");
+}};
+Exhibit.Functions["add"]={f:function(args){var total=0;
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){if(typeof v=="number"){total+=v;
+}else{var n=parseFloat(v);
+if(!isNaN(n)){total+=n;
+}}}});
+}return new Exhibit.Expression._Collection([total],"number");
+}};
+Exhibit.Functions["concat"]={f:function(args){var result=[];
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){result.push(v);
+}});
+}return new Exhibit.Expression._Collection([result.join("")],"text");
+}};
+Exhibit.Functions["multiply"]={f:function(args){var product=1;
+for(var i=0;
+i<args.length;
+i++){args[i].forEachValue(function(v){if(v!=null){if(typeof v=="number"){product*=v;
+}else{var n=parseFloat(v);
+if(!isNaN(n)){product*=n;
+}}}});
+}return new Exhibit.Expression._Collection([product],"number");
+}};
+Exhibit.Functions["date-range"]={_parseDate:function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(v instanceof Date){return v.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+}catch(e){return Number.NEGATIVE_INFINITY;
+}}}},_factors:{second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,week:7*24*60*60*1000,month:30*24*60*60*1000,quarter:3*30*24*60*60*1000,year:365*24*60*60*1000,decade:10*365*24*60*60*1000,century:100*365*24*60*60*1000},_computeRange:function(from,to,interval){var range=to-from;
+if(isFinite(range)){if(interval in this._factors){range=Math.round(range/this._factors[interval]);
+}return range;
+}return null;
+},f:function(args){var self=this;
+var from=Number.POSITIVE_INFINITY;
+args[0].forEachValue(function(v){from=Math.min(from,self._parseDate(v));
+});
+var to=Number.NEGATIVE_INFINITY;
+args[1].forEachValue(function(v){to=Math.max(to,self._parseDate(v));
+});
+var interval="day";
+args[2].forEachValue(function(v){interval=v;
+});
+var range=this._computeRange(from,to,interval);
+return new Exhibit.Expression._Collection(range!=null?[range]:[],"number");
+}};
+Exhibit.Functions["distance"]={_units:{km:1000,mile:1609.344},_computeDistance:function(from,to,unit,roundTo){var range=from.distanceFrom(to);
+if(!roundTo){roundTo=1;
+}if(isFinite(range)){if(this._units.hasOwnProperty(unit)){range=range/this._units[unit];
+}return Exhibit.Util.round(range,roundTo);
+}return null;
+},f:function(args){var self=this;
+var data={};
+var name=["origo","lat","lng","unit","round"];
+for(var i=0,n;
+n=name[i];
+i++){args[i].forEachValue(function(v){data[n]=v;
+});
+}var latlng=data.origo.split(",");
+var from=new GLatLng(latlng[0],latlng[1]);
+var to=new GLatLng(data.lat,data.lng);
+var range=this._computeDistance(from,to,data.unit,data.round);
+return new Exhibit.Expression._Collection(range!=null?[range]:[],"number");
+}};
+Exhibit.Functions["min"]={f:function(args){var returnMe=function(val){return val;
+};
+var min=Number.POSITIVE_INFINITY;
+var valueType=null;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+var currentValueType=arg.valueType?arg.valueType:"text";
+var parser=Exhibit.SettingsUtilities._typeToParser(currentValueType);
+arg.forEachValue(function(v){parsedV=parser(v,returnMe);
+if(parsedV<min||min==Number.POSITIVE_INFINITY){min=parsedV;
+valueType=(valueType==null)?currentValueType:(valueType==currentValueType?valueType:"text");
+}});
+}return new Exhibit.Expression._Collection([min],valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["max"]={f:function(args){var returnMe=function(val){return val;
+};
+var max=Number.NEGATIVE_INFINITY;
+var valueType=null;
+for(var i=0;
+i<args.length;
+i++){var arg=args[i];
+var currentValueType=arg.valueType?arg.valueType:"text";
+var parser=Exhibit.SettingsUtilities._typeToParser(currentValueType);
+arg.forEachValue(function(v){parsedV=parser(v,returnMe);
+if(parsedV>max||max==Number.NEGATIVE_INFINITY){max=parsedV;
+valueType=(valueType==null)?currentValueType:(valueType==currentValueType?valueType:"text");
+}});
+}return new Exhibit.Expression._Collection([max],valueType!=null?valueType:"text");
+}};
+Exhibit.Functions["remove"]={f:function(args){var set=args[0].getSet();
+var valueType=args[0].valueType;
+for(var i=1;
+i<args.length;
+i++){var arg=args[i];
+if(arg.size>0){set.removeSet(arg.getSet());
+}}return new Exhibit.Expression._Collection(set,valueType);
+}};
+Exhibit.Functions["now"]={f:function(args){return new Exhibit.Expression._Collection([new Date()],"date");
+}};
+
+
+/* authenticated-importer.js */
+Exhibit.AuthenticatedImporter={_callbacks:{}};
+Exhibit.importers["application/authenticated"]=Exhibit.AuthenticatedImporter;
+Exhibit.AuthenticatedImporter.constructURL=function(){return"https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fspreadsheets.google.com%2Ffeeds%2F&session=1&secure=0&next="+window.location;
+};
+Exhibit.AuthenticatedImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{o=eval("("+xmlhttp.responseText+")");
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* babel-based-importer.js */
+Exhibit.BabelBasedImporter={mimetypeToReader:{"application/rdf+xml":"rdf-xml","application/n3":"n3","application/msexcel":"xls","application/x-msexcel":"xls","application/x-ms-excel":"xls","application/vnd.ms-excel":"xls","application/x-excel":"xls","application/xls":"xls","application/x-xls":"xls","application/x-bibtex":"bibtex"},babelTranslatorURL:"http://service.simile-widgets.org/babel/translator",_initialize:function(){var links=[];
+var heads=document.documentElement.getElementsByTagName("head");
+for(var h=0;
+h<heads.length;
+h++){var linkElmts=heads[h].getElementsByTagName("link");
+for(var l=0;
+l<linkElmts.length;
+l++){var link=linkElmts[l];
+if(link.rel.match(/\bexhibit\/babel-translator\b/)){Exhibit.BabelBasedImporter.babelTranslatorURL=link.href;
+}}}Exhibit.BabelBasedImporter._initialize=function(){};
+}};
+Exhibit.importers["application/rdf+xml"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/n3"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/msexcel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-msexcel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/vnd.ms-excel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-excel"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/xls"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-xls"]=Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-bibtex"]=Exhibit.BabelBasedImporter;
+Exhibit.BabelBasedImporter.load=function(link,database,cont){Exhibit.BabelBasedImporter._initialize();
+var url=(typeof link=="string")?Exhibit.Persistence.resolveURL(link):Exhibit.Persistence.resolveURL(link.href);
+var reader="rdf-xml";
+var writer="exhibit-jsonp";
+if(typeof link!="string"){var mimetype=link.type;
+if(mimetype in Exhibit.BabelBasedImporter.mimetypeToReader){reader=Exhibit.BabelBasedImporter.mimetypeToReader[mimetype];
+}}if(reader=="bibtex"){writer="bibtex-exhibit-jsonp";
+}var babelURL=Exhibit.BabelBasedImporter.babelTranslatorURL+"?"+["reader="+reader,"writer="+writer,"url="+encodeURIComponent(url)].join("&");
+return Exhibit.JSONPImporter.load(babelURL,database,cont);
+};
+
+
+/* exhibit-json-importer.js */
+Exhibit.ExhibitJSONImporter={};
+Exhibit.importers["application/json"]=Exhibit.ExhibitJSONImporter;
+Exhibit.ExhibitJSONImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{o=eval("("+xmlhttp.responseText+")");
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* exhibit-xml-importer.js */
+Exhibit.ExhibitXMLImporter={};
+Exhibit.importers["application/xml"]=Exhibit.ExhibitXMLImporter;
+Exhibit.ExhibitXMLImporter.getXMLDocument=function(docURL){var xmlDoc=null;
+$.ajax({url:docURL,type:"GET",dataType:"xml",async:false,success:function(data){xmlDoc=data;
+}});
+if(xmlDoc){return xmlDoc;
+}else{alert("ERROR FINDING XML DOC");
+return ;
+}};
+Exhibit.ExhibitXMLImporter.appendUserPropertyToArray=function(node,configuration,objectToAppend){var referenceIndex=configuration.propertyTags.indexOf(node.nodeName);
+var array=objectToAppend[configuration.propertyNames[referenceIndex]];
+if(typeof objectToAppend[configuration.propertyNames[referenceIndex]]=="string"){array=[array];
+array.push(node.textContent);
+}else{array.push(node.textContent);
+}return array;
+};
+Exhibit.ExhibitXMLImporter.appendPropertyToArray=function(node,configuration,objectToAppend){var array=objectToAppend[node.nodeName];
+if(typeof array=="string"){array=[array];
+array.push(node.textContent);
+}else{array.push(node.textContent);
+}return array;
+};
+Exhibit.ExhibitXMLImporter.getItems=function(xmlDoc,object,index,configuration){var self=this;
+$(configuration.itemTag[index],xmlDoc).each(function(){var propertyList=[];
+var queue=[];
+$(this).children().each(function(){queue.push(this);
+});
+objectToAppend={};
+while(queue.length){var node=queue.pop();
+var nodeType=self.determineType(node,configuration);
+if(nodeType=="property"){if(propertyList.indexOf(node.nodeName)>=0){if(configuration.propertyTags.indexOf(node.nodeName)>=0){objectToAppend[configuration.propertyNames[index]]=self.appendUserPropertyToArray(node,configuration,objectToAppend);
+}else{objectToAppend[node.nodeName]=self.appendPropertyToArray(node,configuration,objectToAppend);
+}}else{if(configuration.propertyTags.indexOf(node.nodeName)>=0){var referenceIndex=configuration.propertyTags.indexOf(node.nodeName);
+objectToAppend[configuration.propertyNames[referenceIndex]]=node.textContent;
+}else{objectToAppend[node.nodeName]=node.textContent;
+}}propertyList.push(node.nodeName);
+}else{if(nodeType=="Item"){var referenceIndex=configuration.itemTag.indexOf(node.nodeName);
+var tempObject=self.configureItem(node,{},configuration,referenceIndex);
+objectToAppend[tempObject.type]=tempObject.label;
+}else{if(nodeType=="fakeItem"){$(node).children().each(function(){queue.push(this);
+});
+}else{alert("error: nodetype not understood");
+}}}}objectToAppend=self.configureItem(this,objectToAppend,configuration,index);
+object.items.push(objectToAppend);
+});
+return object;
+};
+Exhibit.ExhibitXMLImporter.getParentItem=function(itemNode,configuration){if(itemNode.parentNode==null){return null;
+}else{if(configuration.itemTag.indexOf(itemNode.parentNode.nodeName)>=0){var referenceIndex=configuration.itemTag.indexOf(itemNode.parentNode.nodeName);
+return this.configureItem(itemNode.parentNode,{},configuration,referenceIndex);
+}else{this.getParentItem(itemNode.parentNode,configuration);
+}}};
+Exhibit.ExhibitXMLImporter.configureItem=function(myItem,object,configuration,index){if(!(object.label)&&configuration.propertyLabel[index]!=null){object["label"]=$(configuration.propertyLabel[index],myItem)[0].textContent;
+}else{object["label"]=$(myItem).children()[0].textContent;
+}if(!(object.type)&&configuration.itemType[index]!=null){object["type"]=configuration.itemType[index];
+}else{object["type"]=myItem.nodeName;
+}var parentItem=this.getParentItem(myItem,configuration);
+if(parentItem){if(configuration.parentRelation[index]){object[configuration.parentRelation[index]]=parentItem.label;
+}else{object["isChildOf"]=parentItem.label;
+}}return object;
+};
+Exhibit.ExhibitXMLImporter.configure=function(){var configuration={"itemTag":[],"propertyLabel":[],"itemType":[],"parentRelation":[],"propertyTags":[],"propertyNames":[]};
+$("link").each(function(){if(this.hasAttribute("ex:itemTag")){configuration.itemTag=Exhibit.getAttribute(this,"ex:itemTag",",");
+}if(this.hasAttribute("ex:setPropertyAsLabel")){configuration.propertyLabel=Exhibit.getAttribute(this,"ex:setPropertyAsLabel",",");
+}if(this.hasAttribute("ex:itemType")){configuration.itemType=Exhibit.getAttribute(this,"ex:itemType",",");
+}if(this.hasAttribute("ex:parentRelation")){configuration.parentRelation=Exhibit.getAttribute(this,"ex:parentRelation",",");
+}if(this.hasAttribute("ex:propertyNames")){configuration.propertyNames=Exhibit.getAttribute(this,"ex:propertyNames",",");
+}if(this.hasAttribute("ex:propertyTags")){configuration.propertyTags=Exhibit.getAttribute(this,"ex:propertyTags",",");
+}});
+return configuration;
+};
+Exhibit.ExhibitXMLImporter.determineType=function(node,configuration){if(configuration.itemTag.indexOf(node.nodeName)>=0){return"Item";
+}else{if($(node).children().length==0){return"property";
+}else{return"fakeItem";
+}}};
+Exhibit.ExhibitXMLImporter.load=function(link,database,cont){var self=this;
+var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{xmlDoc=Exhibit.ExhibitXMLImporter.getXMLDocument(url);
+var configuration=self.configure();
+o={"items":[]};
+for(index in configuration.itemTag){o=Exhibit.ExhibitXMLImporter.getItems(xmlDoc,o,index,configuration);
+}}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* html-table-importer.js */
+Exhibit.HtmlTableImporter={};
+Exhibit.importers["text/html"]=Exhibit.HtmlTableImporter;
+Exhibit.HtmlTableImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+if(url.substr(0,1)=="#"){try{var id=/#(.*)/.exec(f)[1];
+var table=document.getElementById(id);
+table.style.display="none";
+Exhibit.HtmlTableImporter.loadTable(table,database);
+}catch(e){SimileAjax.Debug.exception(e);
+}finally{if(cont){cont();
+}}}else{if(typeof link!="string"){var xpath=link.getAttribute("ex:xpath");
+var columns=(link.getAttribute("ex:columns")).split(",");
+var babelURL="http://simile.mit.edu/babel/html-extractor?"+["xpath="+xpath,"url="+encodeURIComponent(url)].join("&");
+var fConvert=function(string){var div=document.createElement("div");
+div.innerHTML=string;
+var table=div.firstChild;
+var th,ths=table.getElementsByTagName("th");
+for(col=0;
+th=ths[col];
+col++){var label=columns[col];
+th.setAttribute("ex:name",label);
+}Exhibit.HtmlTableImporter.loadTable(table,database);
+return{};
+};
+return Exhibit.JSONPImporter.load(babelURL,database,cont,fConvert);
+}else{if(cont){cont();
+}}}};
+Exhibit.HtmlTableImporter.loadTable=function(table,database){var textOf=function(n){return n.textContent||n.innerText||"";
+};
+var readAttributes=function(node,attributes){var result={},found=false,attr,value,i;
+for(i=0;
+attr=attributes[i];
+i++){value=Exhibit.getAttribute(node,attr);
+if(value){result[attr]=value;
+found=true;
+}}return found&&result;
+};
+var typelist=["uri","label","pluralLabel"];
+var proplist=["uri","valueType","label","reverseLabel","pluralLabel","reversePluralLabel","groupingLabel","reverseGroupingLabel"];
+var columnProps=["valueParser","arity"];
+var parsed={};
+var type=Exhibit.getAttribute(table,"type");
+var types=type&&readAttributes(table,typelist);
+if(types){parsed.types={};
+parsed.types[type]=types;
+}var fields=[],props={},columnData=[],row,col;
+var tr,trs=table.getElementsByTagName("tr");
+var th,ths=trs[0].getElementsByTagName("th");
+for(col=0;
+th=ths[col];
+col++){var field=textOf(th).trim();
+var hastextwithlink=false;
+var attr=readAttributes(th,proplist);
+var name=Exhibit.getAttribute(th,"name");
+if(name){attr=attr||{};
+attr.label=attr.label||field;
+field=name;
+}if(attr){props[field]=attr;
+if(props[field].valueType=="textwithlink"){props[field].valueType="text";
+props[(field+"-link")]={valueType:"url"};
+hastextwithlink=true;
+}parsed.properties=props;
+}fields.push(field);
+attr=readAttributes(th,columnProps)||{};
+if(attr.valueParser&&attr.valueParser in window){attr.valueParser=window[attr.valueParser];
+}else{if(attr.arity=="single"){attr.valueParser=function(text,node,rowNo,colNo){return text.trim();
+};
+}else{attr.valueParser=function(text,node,rowNo,colNo){if(text.indexOf(";")==-1){return text.trim();
+}var data=text.split(";");
+for(var i=0;
+i<data.length;
+i++){data[i]=data[i].trim();
+}return data;
+};
+if(hastextwithlink){var fallback=attr.valueParser;
+attr.valueParser=function(text,node,rowNo,colNo){var links=node.getElementsByTagName("a");
+if(!links.length){return fallback(text,node,rowNo,colNo);
+}var data={};
+data[fields[colNo]]=text.trim();
+data[(fields[colNo]+"-link")]=links[0].href;
+return data;
+};
+}}}columnData[col]=attr;
+}var img,imgs=table.getElementsByTagName("img");
+while(img=imgs[0]){img.parentNode.replaceChild(document.createTextNode(img.src),img);
+}var items=[],td,raw;
+for(row=1;
+tr=trs[row];
+row++){var item={};
+var tds=tr.getElementsByTagName("td");
+for(col=0;
+td=tds[col];
+col++){var raw=textOf(td);
+data=columnData[col].valueParser(raw,td,row,col);
+if(data==null||raw===""){continue;
+}if(typeof data=="object"&&!(data instanceof Array)){for(var property in data){item[property]=data[property];
+}}else{item[fields[col]]=data;
+}}if(type){item.type=type;
+}items.push(item);
+parsed.items=items;
+}database.loadData(parsed,Exhibit.Persistence.resolveURL(location.href));
+};
+
+
+/* json-importer.js */
+Exhibit.jsonImporter={};
+Exhibit.importers["application/general-json"]=Exhibit.jsonImporter;
+Exhibit.jsonImporter.getjsonDocument=function(docURL){var jsonDoc=null;
+$.ajax({url:docURL,type:"GET",dataType:"json",async:false,success:function(data){jsonDoc=data;
+}});
+if(jsonDoc){return jsonDoc;
+}else{alert("ERROR FINDING JSON DOC");
+return null;
+}};
+Exhibit.jsonImporter.findFirstItems=function(json,configuration){if(json instanceof Array){return json.length>0?Exhibit.jsonImporter.findFirstItems(json[0],configuration):null;
+}else{var visited=[];
+var listOfItems=[];
+for(child in json){visited.push(json[child]);
+if(configuration.itemTag.indexOf(child)>=0){for(var i=0;
+i<json[child].length;
+i++){var subChild=json[child][i];
+subChild.index=configuration.itemTag.indexOf(child);
+listOfItems.push(subChild);
+}}}if(listOfItems.length){return listOfItems;
+}else{return Exhibit.jsonImporter.findFirstItems(visited,configuration);
+}}};
+Exhibit.jsonImporter.getItems=function(json,exhibitJSON,configuration){var itemQueue;
+var root=json;
+if(root instanceof Array){itemQueue=root;
+}else{itemQueue=[root];
+}while(itemQueue.length>0){var myObject=itemQueue.shift();
+var index=myObject.index;
+var objectToAppend={};
+var propertyQueue=[];
+for(propertyKey in myObject){propertyQueue.push(propertyKey);
+}while(propertyQueue.length>0){var key=propertyQueue.shift();
+var keyID=key.split(".").pop();
+if(configuration.itemTag.indexOf(keyID)==-1){var propertyValue=eval("myObject."+key);
+if(keyID=="index"){}else{if(propertyValue instanceof Array){objectToAppend[keyID]=propertyValue;
+}else{if(propertyValue instanceof Object){for(newProperty in propertyValue){propertyQueue.push(key+"."+newProperty);
+}}else{if(keyID==configuration.propertyTags[index]){var referenceIndex=configuration.propertyTags.indexOf(keyID);
+var newKey=configuration.propertyNames[referenceIndex];
+objectToAppend[newKey]=propertyValue;
+}else{if(keyID==configuration.propertyLabel[index]){objectToAppend.label=propertyValue;
+}else{objectToAppend[keyID]=propertyValue;
+}}}}}if(configuration.itemType[index]){objectToAppend.type=configuration.itemType[index];
+}else{objectToAppend.type="Item";
+}}else{newObject=eval("myObject."+key);
+if(newObject instanceof Array){for(var i=0;
+i<newObject.length;
+i++){var object=newObject[i];
+object.index=configuration.itemTag.indexOf(keyID);
+if(configuration.parentRelation[object.index]){object[configuration.parentRelation[object.index]]=objectToAppend.label;
+}else{object["is a child of"]=objectToAppend.label;
+}itemQueue.push(object);
+}}else{newObject.index=configuration.itemTag.indexOf(keyID);
+if(configuration.parentRelation[newObject.index]){newObject[configuration.parentRelation[newObject.index]]=objectToAppend.label;
+}else{newObject["isChildOf"]=objectToAppend.label;
+}itemQueue.push(newObject);
+}}}exhibitJSON.items.push(objectToAppend);
+}return exhibitJSON;
+};
+Exhibit.jsonImporter.configure=function(){var configuration={"itemTag":[],"propertyLabel":[],"itemType":[],"parentRelation":[],"propertyTags":[],"propertyNames":[]};
+$("link").each(function(){if(this.hasAttribute("ex:itemTag")){configuration.itemTag=Exhibit.getAttribute(this,"ex:itemTag",",");
+}if(this.hasAttribute("ex:setPropertyAsLabel")){configuration.propertyLabel=Exhibit.getAttribute(this,"ex:setPropertyAsLabel",",");
+}if(this.hasAttribute("ex:itemType")){configuration.itemType=Exhibit.getAttribute(this,"ex:itemType",",");
+}if(this.hasAttribute("ex:parentRelation")){configuration.parentRelation=Exhibit.getAttribute(this,"ex:parentRelation",",");
+}if(this.hasAttribute("ex:propertyNames")){configuration.propertyNames=Exhibit.getAttribute(this,"ex:propertyNames",",");
+}if(this.hasAttribute("ex:propertyTags")){configuration.propertyTags=Exhibit.getAttribute(this,"ex:propertyTags",",");
+}});
+return configuration;
+};
+Exhibit.jsonImporter.load=function(link,database,cont){var self=this;
+var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{jsonDoc=Exhibit.jsonImporter.getjsonDocument(url);
+var configuration=self.configure();
+o={"items":[]};
+var root=self.findFirstItems(jsonDoc,configuration);
+o=Exhibit.jsonImporter.getItems(root,o,configuration);
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading Exhibit JSON data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+
+
+/* jsonp-importer.js */
+Exhibit.JSONPImporter={_callbacks:{}};
+Exhibit.importers["application/jsonp"]=Exhibit.JSONPImporter;
+Exhibit.JSONPImporter.load=function(link,database,cont,fConvert,staticJSONPCallback,charset){var url=link;
+if(typeof link!="string"){url=Exhibit.Persistence.resolveURL(link.href);
+fConvert=Exhibit.getAttribute(link,"converter");
+staticJSONPCallback=Exhibit.getAttribute(link,"jsonp-callback");
+charset=Exhibit.getAttribute(link,"charset");
+}if(typeof fConvert=="string"){var name=fConvert;
+name=name.charAt(0).toLowerCase()+name.substring(1)+"Converter";
+if(name in Exhibit.JSONPImporter){fConvert=Exhibit.JSONPImporter[name];
+}else{try{fConvert=eval(fConvert);
+}catch(e){fConvert=null;
+}}}if(fConvert!=null&&"preprocessURL" in fConvert){url=fConvert.preprocessURL(url);
+}var next=Exhibit.JSONPImporter._callbacks.next||1;
+Exhibit.JSONPImporter._callbacks.next=next+1;
+var callbackName="cb"+next.toString(36);
+var callbackURL=url;
+if(callbackURL.indexOf("?")==-1){callbackURL+="?";
+}var lastChar=callbackURL.charAt(callbackURL.length-1);
+if(lastChar!="="){if(lastChar!="&"&&lastChar!="?"){callbackURL+="&";
+}callbackURL+="callback=";
+}var callbackFull="Exhibit.JSONPImporter._callbacks."+callbackName;
+callbackURL+=callbackFull;
+var cleanup=function(failedURL){try{Exhibit.UI.hideBusyIndicator();
+delete Exhibit.JSONPImporter._callbacks[callbackName+"_fail"];
+delete Exhibit.JSONPImporter._callbacks[callbackName];
+if(script&&script.parentNode){script.parentNode.removeChild(script);
+}}finally{if(failedURL){prompt("Failed to load javascript file:",failedURL);
+cont&&cont(undefined);
+}}};
+Exhibit.JSONPImporter._callbacks[callbackName+"_fail"]=cleanup;
+Exhibit.JSONPImporter._callbacks[callbackName]=function(json){try{cleanup(null);
+database.loadData(fConvert?fConvert(json,url,link):json,Exhibit.Persistence.getBaseURL(url));
+}finally{if(cont){cont(json);
+}}};
+if(staticJSONPCallback){callbackURL=url;
+eval(staticJSONPCallback+"="+callbackFull);
+}var fail=callbackFull+"_fail('"+callbackURL+"');";
+var script=SimileAjax.includeJavascriptFile(document,callbackURL,fail,charset);
+Exhibit.UI.showBusyIndicator();
+return Exhibit.JSONPImporter._callbacks[callbackName];
+};
+Exhibit.JSONPImporter.transformJSON=function(json,index,mapping,converters){var objects=json,items=[];
+if(index){index=index.split(".");
+while(index.length){objects=objects[index.shift()];
+}}for(var i=0,object;
+object=objects[i];
+i++){var item={};
+for(var name in mapping){var index=mapping[name];
+if(!mapping.hasOwnProperty(name)||!object.hasOwnProperty(index)){continue;
+}var property=object[index];
+if(converters&&converters.hasOwnProperty(name)){property=converters[name](property,object,i,objects,json);
+}if(typeof property!="undefined"){item[name]=property;
+}}items.push(item);
+}return items;
+};
+Exhibit.JSONPImporter.deliciousConverter=function(json,url){var items=Exhibit.JSONPImporter.transformJSON(json,null,{label:"u",note:"n",description:"d",tags:"t"});
+return{items:items,properties:{url:{valueType:"url"}}};
+};
+Exhibit.JSONPImporter.googleSpreadsheetsConverter=function(json,url,link){var separator=";";
+if((link)&&(typeof link!="string")){var s=Exhibit.getAttribute(link,"separator");
+if(s!=null&&s.length>0){separator=s;
+}}var items=[];
+var properties={};
+var types={};
+var valueTypes={"text":true,"number":true,"item":true,"url":true,"boolean":true,"date":true};
+var entries=json.feed.entry||[];
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+var id=entry.id.$t;
+var c=id.lastIndexOf("C");
+var r=id.lastIndexOf("R");
+entries[i]={row:parseInt(id.substring(r+1,c))-1,col:parseInt(id.substring(c+1))-1,val:entry.content.$t};
+}var cellIndex=0;
+var getNextRow=function(){if(cellIndex<entries.length){var firstEntry=entries[cellIndex++];
+var row=[firstEntry];
+while(cellIndex<entries.length){var nextEntry=entries[cellIndex];
+if(nextEntry.row==firstEntry.row){row.push(nextEntry);
+cellIndex++;
+}else{break;
+}}return row;
+}return null;
+};
+var propertyRow=getNextRow();
+if(propertyRow!=null){var propertiesByColumn=[];
+for(var i=0;
+i<propertyRow.length;
+i++){var cell=propertyRow[i];
+var fieldSpec=cell.val.trim().replace(/^\{/g,"").replace(/\}$/g,"").split(":");
+var fieldName=fieldSpec[0].trim();
+var fieldDetails=fieldSpec.length>1?fieldSpec[1].split(","):[];
+var property={single:false};
+for(var d=0;
+d<fieldDetails.length;
+d++){var detail=fieldDetails[d].trim();
+if(detail in valueTypes){property.valueType=detail;
+}else{if(detail=="single"){property.single=true;
+}}}propertiesByColumn[cell.col]=fieldName;
+properties[fieldName]=property;
+}var row=null;
+while((row=getNextRow())!=null){var item={};
+for(var i=0;
+i<row.length;
+i++){var cell=row[i];
+var fieldName=propertiesByColumn[cell.col];
+if(typeof fieldName=="string"){var googleDocsDateRegex=/^\d{1,2}\/\d{1,2}\/\d{4}$/;
+if(googleDocsDateRegex.exec(cell.val)){cell.val=Exhibit.Database.makeISO8601DateString(new Date(cell.val));
+}item[fieldName]=cell.val;
+var property=properties[fieldName];
+if(!property.single){var fieldValues=cell.val.split(separator);
+for(var v=0;
+v<fieldValues.length;
+v++){fieldValues[v]=fieldValues[v].trim();
+}item[fieldName]=fieldValues;
+}else{item[fieldName]=cell.val.trim();
+}}}items.push(item);
+}}return{types:types,properties:properties,items:items};
+};
+Exhibit.JSONPImporter.googleSpreadsheetsConverter.preprocessURL=function(url){return url.replace(/\/list\//g,"/cells/");
+};
+
+
+/* rdfa-importer.js */
+var RDFA=new Object();
+RDFA.url="http://www.w3.org/2006/07/SWD/RDFa/impl/js/20070301/rdfa.js";
+Exhibit.RDFaImporter={};
+Exhibit.importers["application/RDFa"]=Exhibit.RDFaImporter;
+Exhibit.RDFaImporter.load=function(link,database,cont){try{if((link.getAttribute("href")||"").length==0){Exhibit.RDFaImporter.loadRDFa(null,document,database);
+}else{iframe=document.createElement("iframe");
+iframe.style.display="none";
+iframe.setAttribute("onLoad","Exhibit.RDFaImporter.loadRDFa(this, this.contentDocument, database)");
+iframe.src=link.href;
+document.body.appendChild(iframe);
+}}catch(e){SimileAjax.Debug.exception(e);
+}finally{if(cont){cont();
+}}};
+Exhibit.RDFaImporter.loadRDFa=function(iframe,rdfa,database){var textOf=function(n){return n.textContent||n.innerText||"";
+};
+var readAttributes=function(node,attributes){var result={},found=false,attr,value,i;
+for(i=0;
+attr=attributes[i];
+i++){value=Exhibit.getAttribute(node,attr);
+if(value){result[attr]=value;
+found=true;
+}}return found&&result;
+};
+RDFA.CALLBACK_DONE_PARSING=function(){if(iframe!=null){document.body.removeChild(iframe);
+}this.cloneObject=function(what){for(var i in what){this[i]=what[i];
+}};
+var triples=this.triples;
+var parsed={"classes":{},"properties":{},"items":[]};
+for(var i in triples){var item={};
+item["id"],item["uri"],item["label"]=i;
+var tri=triples[i];
+for(var j in tri){for(var k=0;
+k<tri[j].length;
+k++){if(tri[j][k].predicate.ns){var p_label=tri[j][k].predicate.ns.prefix+":"+tri[j][k].predicate.suffix;
+if(j=="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"){try{var type_uri=tri[j][k]["object"];
+var matches=type_uri.match(/(.+?)(#|\/)([a-zA-Z_]+)?$/);
+var type_label=matches[3]+"("+matches[1]+")";
+parsed["classes"][type_label]={"label":type_label,"uri":type_uri};
+item["type"]=type_label;
+}catch(e){}}else{parsed["properties"][p_label]={"uri":j,"label":tri[j][k]["predicate"]["suffix"]};
+try{if(!item[p_label]){item[p_label]=[];
+}item[p_label].push(tri[j][k]["object"]);
+}catch(e){SimileAjax.Debug.log("problem adding property value: "+e);
+}if(j=="http://purl.org/dc/elements/1.1/title"||j=="http://www.w3.org/2000/01/rdf-schema#"||j=="http://xmlns.com/foaf/0.1/name"){item.label=item[p_label];
+}}}else{item[j]=tri[j][k]["object"];
+}}}parsed["items"].push(new this.cloneObject(item));
+}database.loadData(parsed,Exhibit.Persistence.getBaseURL(document.location.href));
+};
+RDFA.CALLBACK_DONE_LOADING=function(){RDFA.parse(rdfa);
+};
+SimileAjax.includeJavascriptFile(document,RDFA.url);
+};
+
+
+/* tsv-csv-importer.js */
+Exhibit.TsvCsvImporter={};
+Exhibit.importers["text/comma-separated-values"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/csv"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tab-separated-values"]=Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tsv"]=Exhibit.TsvCsvImporter;
+Exhibit.TsvCsvImporter.load=function(link,database,cont){var url=typeof link=="string"?link:link.href;
+url=Exhibit.Persistence.resolveURL(url);
+var type=link.type.substring(link.type.indexOf("/")+1);
+var hasColumnTitles=Exhibit.getAttribute(link,"hasColumnTitles")!=null?Exhibit.getAttribute(link,"hasColumnTitles"):true;
+var expressionString=Exhibit.getAttribute(link,"properties");
+var fError=function(statusText,status,xmlhttp){Exhibit.UI.hideBusyIndicator();
+Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+if(cont){cont();
+}};
+var fDone=function(xmlhttp){Exhibit.UI.hideBusyIndicator();
+try{var o=null;
+try{var text=xmlhttp.responseText;
+o=eval(Exhibit.TsvCsvImporter.parseTsvCsv(text,type,expressionString,hasColumnTitles));
+}catch(e){Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url,e),url);
+}if(o!=null){database.loadData(o,Exhibit.Persistence.getBaseURL(url));
+}}catch(e){SimileAjax.Debug.exception(e,"Error loading tsv/csv data from "+url);
+}finally{if(cont){cont();
+}}};
+Exhibit.UI.showBusyIndicator();
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Exhibit.TsvCsvImporter.parseTsvCsv=function(text,format,expressionString,hasColumnTitles){var separator=Exhibit.TsvCsvImporter.formatType(format);
+var lines=text.split("\n");
+var rest;
+var hasPropertyListAttribute=expressionString!=null;
+var exString;
+var propertyRow;
+if(hasPropertyListAttribute){exString=Exhibit.TsvCsvImporter.replaceAll(expressionString,",",separator);
+}if(hasPropertyListAttribute){propertyRow=exString.split(separator);
+if(hasColumnTitles=="false"){rest=lines;
+}else{rest=lines.slice(1);
+}}else{if(hasColumnTitles=="false"){alert("No header row was given for the property names. Either specify them in the ex:properties attribute or add a header row to the file.");
+return ;
+}else{propertyRow=lines[0].split(separator);
+rest=lines.slice(1);
+}}while(rest[rest.length-1]==""){rest=rest.slice(0,rest.length-1);
+}var properties=Exhibit.TsvCsvImporter.getProperties(propertyRow);
+var items=Exhibit.TsvCsvImporter.getItems(separator,rest,propertyRow);
+var json={"properties":properties,"items":items};
+return json;
+};
+Exhibit.TsvCsvImporter.formatType=function(format){var separator="";
+if(format=="tab-separated-values"||format=="tsv"){separator=separator.concat("\t");
+}else{if(format=="comma-separated-values"||format=="csv"){separator=separator.concat(",");
+}else{alert("invalid format, must be tsv or csv");
+}}return separator;
+};
+Exhibit.TsvCsvImporter.getProperties=function(propertyRow){var properties={};
+var valueTypes={"text":true,"number":true,"item":true,"url":true,"boolean":true,"date":true};
+for(i=0;
+i<propertyRow.length;
+i++){var prop=propertyRow[i];
+var type="";
+if(prop.match(":")){var t=prop.substring(prop.lastIndexOf(":")+1);
+prop=prop.substring(0,prop.lastIndexOf(":"));
+if(t in valueTypes){type=t;
+}else{type="text";
+}}else{type="text";
+}properties[prop]={"valueType":type};
+}return properties;
+};
+Exhibit.TsvCsvImporter.getItems=function(separator,rest,propertyRow){var items=[];
+var listSeparator=";";
+for(i=0;
+i<rest.length;
+i++){var row=rest[i].split(separator);
+if(separator==","){var quotes=false;
+for(var j=0;
+j<row.length;
+j++){if(row[j].indexOf('"')==0&&row[j][row[j].length-1]!='"'){quotes=true;
+var x=j;
+while(quotes){joined=[row[x]+","+row[x+1]];
+row=row.slice(0,x).concat(joined,row.slice(x+2));
+if(row[x][row[x].length-1]=='"'){quotes=false;
+}}}}}if(row.length<propertyRow.length){while(row.length!=propertyRow.length){row.push("");
+}}var item={};
+for(var j=0;
+j<propertyRow.length;
+j++){var values=row[j];
+values=Exhibit.TsvCsvImporter.replaceAll(values,'""','"');
+if(values[0]=='"'){values=values.slice(1);
+}if(values[values.length-1]=='"'){values=values.slice(0,values.length-1);
+}var fieldValues=values.split(listSeparator);
+if(fieldValues.length>1){for(var k=0;
+k<fieldValues.length;
+k++){while(fieldValues[k][0]==" "){fieldValues[k]=fieldValues[k].slice(1);
+}}}var property=propertyRow[j];
+var fieldname=property.match(":")?property.substring(0,property.lastIndexOf(":")):property;
+item[fieldname]=fieldValues;
+}items.push(item);
+}return items;
+};
+Exhibit.TsvCsvImporter.replaceAll=function(string,toBeReplaced,replaceWith){var regex="/"+toBeReplaced+"/g";
+return string.replace(eval(regex),replaceWith);
+};
+
+
+/* exhibit.js */
+Exhibit.create=function(database){return new Exhibit._Impl(database);
+};
+Exhibit.getAttribute=function(elmt,name,splitOn){try{var value=elmt.getAttribute(name);
+if(value==null||value.length==0){value=elmt.getAttribute("ex:"+name);
+if(value==null||value.length==0){return null;
+}}if(splitOn==null){return value;
+}var values=value.split(splitOn);
+for(var i=0;
+value=values[i];
+i++){values[i]=value.trim();
+}return values;
+}catch(e){return null;
+}};
+Exhibit.getRoleAttribute=function(elmt){var role=Exhibit.getAttribute(elmt,"role")||"";
+role=role.replace(/^exhibit-/,"");
+return role;
+};
+Exhibit.getConfigurationFromDOM=function(elmt){var c=Exhibit.getAttribute(elmt,"configuration");
+if(c!=null&&c.length>0){try{var o=eval(c);
+if(typeof o=="object"){return o;
+}}catch(e){}}return{};
+};
+Exhibit.extractOptionsFromElement=function(elmt){var opts={};
+var attrs=elmt.attributes;
+for(var i in attrs){if(attrs.hasOwnProperty(i)){var name=attrs[i].nodeName;
+var value=attrs[i].nodeValue;
+if(name.indexOf("ex:")==0){name=name.substring(3);
+}opts[name]=value;
+}}return opts;
+};
+Exhibit.getExporters=function(){Exhibit._initializeExporters();
+return[].concat(Exhibit._exporters);
+};
+Exhibit.addExporter=function(exporter){Exhibit._initializeExporters();
+Exhibit._exporters.push(exporter);
+};
+Exhibit._initializeExporters=function(){if(!("_exporters" in Exhibit)){Exhibit._exporters=[Exhibit.RdfXmlExporter,Exhibit.SemanticWikitextExporter,Exhibit.TSVExporter,Exhibit.ExhibitJsonExporter,Exhibit.FacetSelectionExporter];
+}};
+Exhibit._Impl=function(database){this._database=database!=null?database:("database" in window?window.database:Exhibit.Database.create());
+this._uiContext=Exhibit.UIContext.createRootContext({},this);
+this._collectionMap={};
+this._componentMap={};
+this._historyListener={onBeforePerform:function(action){if(action.lengthy){Exhibit.UI.showBusyIndicator();
+}},onAfterPerform:function(action){if(action.lengthy){Exhibit.UI.hideBusyIndicator();
+}},onBeforeUndoSeveral:function(){Exhibit.UI.showBusyIndicator();
+},onAfterUndoSeveral:function(){Exhibit.UI.hideBusyIndicator();
+},onBeforeRedoSeveral:function(){Exhibit.UI.showBusyIndicator();
+},onAfterRedoSeveral:function(){Exhibit.UI.hideBusyIndicator();
+}};
+SimileAjax.History.addListener(this._historyListener);
+};
+Exhibit._Impl.prototype.dispose=function(){SimileAjax.History.removeListener(this._historyListener);
+for(var id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e,"Failed to dispose component");
+}}for(var id in this._collectionMap){try{this._collectionMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e,"Failed to dispose collection");
+}}this._uiContext.dispose();
+this._componentMap=null;
+this._collectionMap=null;
+this._uiContext=null;
+this._database=null;
+};
+Exhibit._Impl.prototype.getDatabase=function(){return this._database;
+};
+Exhibit._Impl.prototype.getUIContext=function(){return this._uiContext;
+};
+Exhibit._Impl.prototype.getCollection=function(id){var collection=this._collectionMap[id];
+if(collection==null&&id=="default"){collection=Exhibit.Collection.createAllItemsCollection(id,this._database);
+this.setDefaultCollection(collection);
+}return collection;
+};
+Exhibit._Impl.prototype.getDefaultCollection=function(){return this.getCollection("default");
+};
+Exhibit._Impl.prototype.setCollection=function(id,c){if(id in this._collectionMap){try{this._collectionMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}}this._collectionMap[id]=c;
+};
+Exhibit._Impl.prototype.setDefaultCollection=function(c){this.setCollection("default",c);
+};
+Exhibit._Impl.prototype.getComponent=function(id){return this._componentMap[id];
+};
+Exhibit._Impl.prototype.setComponent=function(id,c){if(id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}}this._componentMap[id]=c;
+};
+Exhibit._Impl.prototype.disposeComponent=function(id){if(id in this._componentMap){try{this._componentMap[id].dispose();
+}catch(e){SimileAjax.Debug.exception(e);
+}delete this._componentMap[id];
+}};
+Exhibit._Impl.prototype.configure=function(configuration){if("collections" in configuration){for(var i=0;
+i<configuration.collections.length;
+i++){var config=configuration.collections[i];
+var id=config.id;
+if(id==null||id.length==0){id="default";
+}this.setCollection(id,Exhibit.Collection.create2(id,config,this._uiContext));
+}}if("components" in configuration){for(var i=0;
+i<configuration.components.length;
+i++){var config=configuration.components[i];
+var component=Exhibit.UI.create(config,config.elmt,this._uiContext);
+if(component!=null){var id=elmt.id;
+if(id==null||id.length==0){id="component"+Math.floor(Math.random()*1000000);
+}this.setComponent(id,component);
+}}}};
+Exhibit._Impl.prototype.configureFromDOM=function(root){var collectionElmts=[];
+var coderElmts=[];
+var coordinatorElmts=[];
+var lensElmts=[];
+var facetElmts=[];
+var otherElmts=[];
+var f=function(elmt){var role=Exhibit.getRoleAttribute(elmt);
+if(role.length>0){switch(role){case"collection":collectionElmts.push(elmt);
+break;
+case"coder":coderElmts.push(elmt);
+break;
+case"coordinator":coordinatorElmts.push(elmt);
+break;
+case"lens":case"submission-lens":case"edit-lens":lensElmts.push(elmt);
+break;
+case"facet":facetElmts.push(elmt);
+break;
+default:otherElmts.push(elmt);
+}}else{var node=elmt.firstChild;
+while(node!=null){if(node.nodeType==1){f(node);
+}node=node.nextSibling;
+}}};
+f(root||document.body);
+var uiContext=this._uiContext;
+for(var i=0;
+i<collectionElmts.length;
+i++){var elmt=collectionElmts[i];
+var id=elmt.id;
+if(id==null||id.length==0){id="default";
+}this.setCollection(id,Exhibit.Collection.createFromDOM2(id,elmt,uiContext));
+}var self=this;
+var processElmts=function(elmts){for(var i=0;
+i<elmts.length;
+i++){var elmt=elmts[i];
+try{var component=Exhibit.UI.createFromDOM(elmt,uiContext);
+if(component!=null){var id=elmt.id;
+if(id==null||id.length==0){id="component"+Math.floor(Math.random()*1000000);
+}self.setComponent(id,component);
+}}catch(e){SimileAjax.Debug.exception(e);
+}}};
+processElmts(coordinatorElmts);
+processElmts(coderElmts);
+processElmts(lensElmts);
+processElmts(facetElmts);
+processElmts(otherElmts);
+this.importSettings();
+var exporters=Exhibit.getAttribute(document.body,"exporters");
+if(exporters!=null){exporters=exporters.split(";");
+for(var i=0;
+i<exporters.length;
+i++){var expr=exporters[i];
+var exporter=null;
+try{exporter=eval(expr);
+}catch(e){}if(exporter==null){try{exporter=eval(expr+"Exporter");
+}catch(e){}}if(exporter==null){try{exporter=eval("Exhibit."+expr+"Exporter");
+}catch(e){}}if(typeof exporter=="object"){Exhibit.addExporter(exporter);
+}}}var hash=document.location.hash;
+if(hash.length>1){var itemID=decodeURIComponent(hash.substr(1));
+if(this._database.containsItem(itemID)){this._showFocusDialogOnItem(itemID);
+}}};
+Exhibit._Impl.prototype._showFocusDialogOnItem=function(itemID){var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-focusDialog-viewContainer' id='lensContainer'></div><div class='exhibit-focusDialog-controls'><button id='closeButton'>"+Exhibit.l10n.focusDialogBoxCloseButtonLabel+"</button></div>");
+dom.elmt.className="exhibit-focusDialog exhibit-ui-protection";
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var itemLens=this._uiContext.getLensRegistry().createLens(itemID,dom.lensContainer,this._uiContext);
+dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+},dom.layer);
+};
+Exhibit._Impl.prototype.exportSettings=function(){var facetSelections={},facetSettings="";
+for(var id in this._componentMap){if(typeof this._componentMap[id].exportFacetSelection!=="undefined"){facetSettings=this._componentMap[id].exportFacetSelection()||false;
+if(facetSettings){facetSelections[id]=facetSettings;
+}}}return facetSelections;
+};
+Exhibit._Impl.prototype.importSettings=function(){if(window.location.search.length>0){searchComponents=window.location.search.substr(1,window.location.search.length-1).split("&");
+for(var x=0;
+x<searchComponents.length;
+x++){var component=searchComponents[x].split("=");
+var componentId=component[0];
+var componentSelection=unescape(component[1]);
+if(this._componentMap[componentId]&&(typeof this._componentMap[componentId].importFacetSelection!=="undefined")){this._componentMap[componentId].importFacetSelection(componentSelection);
+}}}};
+
+
+/* persistence.js */
+Exhibit.Persistence={};
+Exhibit.Persistence.getBaseURL=function(url){try{if(url.indexOf("://")<0){var url2=Exhibit.Persistence.getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}var i=url.lastIndexOf("/");
+if(i<0){return"";
+}else{return url.substr(0,i+1);
+}}catch(e){return url;
+}};
+Exhibit.Persistence.resolveURL=function(url){if(url.indexOf("://")<0){var url2=Exhibit.Persistence.getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}return url;
+};
+Exhibit.Persistence.getURLWithoutQueryAndHash=function(){var url;
+if("_urlWithoutQueryAndHash" in Exhibit){url=Exhibit.Persistence._urlWithoutQueryAndHash;
+}else{url=document.location.href;
+var hash=url.indexOf("#");
+var question=url.indexOf("?");
+if(question>=0){url=url.substr(0,question);
+}else{if(hash>=0){url=url.substr(0,hash);
+}}Exhibit.Persistence._urlWithoutQueryAndHash=url;
+}return url;
+};
+Exhibit.Persistence.getURLWithoutQuery=function(){var url;
+if("_urlWithoutQuery" in Exhibit.Persistence){url=Exhibit.Persistence._urlWithoutQuery;
+}else{url=document.location.href;
+var question=url.indexOf("?");
+if(question>=0){url=url.substr(0,question);
+}Exhibit.Persistence._urlWithoutQuery=url;
+}return url;
+};
+Exhibit.Persistence.getItemLink=function(itemID){return Exhibit.Persistence.getURLWithoutQueryAndHash()+"#"+encodeURIComponent(itemID);
+};
+
+
+/* color-coder.js */
+Exhibit.ColorCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:Exhibit.Coders.l10n.mixedCaseLabel,color:Exhibit.Coders.mixedCaseColor};
+this._missingCase={label:Exhibit.Coders.l10n.missingCaseLabel,color:Exhibit.Coders.missingCaseColor};
+this._othersCase={label:Exhibit.Coders.l10n.othersCaseLabel,color:Exhibit.Coders.othersCaseColor};
+};
+Exhibit.ColorCoder._settingSpecs={};
+Exhibit.ColorCoder.create=function(configuration,uiContext){var coder=new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ColorCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"color"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"ColorCoder: Error processing configuration of coder");
+}Exhibit.ColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ColorCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].color);
+}}};
+Exhibit.ColorCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.ColorCoder._colorTable={"red":"#ff0000","green":"#00ff00","blue":"#0000ff","white":"#ffffff","black":"#000000","gray":"#888888"};
+Exhibit.ColorCoder.prototype._addEntry=function(kase,key,color){if(color in Exhibit.ColorCoder._colorTable){color=Exhibit.ColorCoder._colorTable[color];
+}var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.color=color;
+}else{this._map[key]={color:color};
+}};
+Exhibit.ColorCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].color;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.color;
+}else{if(flags){flags.others=true;
+}return this._othersCase.color;
+}}};
+Exhibit.ColorCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){if(flags){flags.mixed=true;
+}color=self._mixedCase.color;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.color;
+}};
+Exhibit.ColorCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.ColorCoder.prototype.getOthersColor=function(){return this._othersCase.color;
+};
+Exhibit.ColorCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.ColorCoder.prototype.getMissingColor=function(){return this._missingCase.color;
+};
+Exhibit.ColorCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.ColorCoder.prototype.getMixedColor=function(){return this._mixedCase.color;
+};
+
+
+/* color-gradient-coder.js */
+Exhibit.ColorGradientCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._gradientPoints=[];
+this._mixedCase={label:Exhibit.Coders.l10n.mixedCaseLabel,color:Exhibit.Coders.mixedCaseColor};
+this._missingCase={label:Exhibit.Coders.l10n.missingCaseLabel,color:Exhibit.Coders.missingCaseColor};
+this._othersCase={label:Exhibit.Coders.l10n.othersCaseLabel,color:Exhibit.Coders.othersCaseColor};
+};
+Exhibit.ColorGradientCoder._settingSpecs={};
+Exhibit.ColorGradientCoder.create=function(configuration,uiContext){var coder=new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ColorGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorGradientCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ColorGradientCoder._settingSpecs,coder._settings);
+try{var gradientPoints=Exhibit.getAttribute(configElmt,"gradientPoints",";");
+for(var i=0;
+i<gradientPoints.length;
+i++){var point=gradientPoints[i];
+var value=parseFloat(point);
+var colorIndex=point.indexOf("#")+1;
+var red=parseInt(point.slice(colorIndex,colorIndex+2),16);
+var green=parseInt(point.slice(colorIndex+2,colorIndex+4),16);
+var blue=parseInt(point.slice(colorIndex+4),16);
+coder._gradientPoints.push({value:value,red:red,green:green,blue:blue});
+}var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"color"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"ColorGradientCoder: Error processing configuration of coder");
+}Exhibit.ColorGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.ColorGradientCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ColorGradientCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].color);
+}}};
+Exhibit.ColorGradientCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.ColorGradientCoder.prototype._addEntry=function(kase,key,color){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.color=color;
+}};
+Exhibit.ColorGradientCoder.prototype.translate=function(key,flags){var gradientPoints=this._gradientPoints;
+var getColor=function(key){if(key.constructor!=Number){key=parseFloat(key);
+}for(j=0;
+j<gradientPoints.length;
+j++){if(key==gradientPoints[j].value){return rgbToHex(gradientPoints[j].red,gradientPoints[j].green,gradientPoints[j].blue);
+}else{if(gradientPoints[j+1]!=null){if(key<gradientPoints[j+1].value){var fraction=(key-gradientPoints[j].value)/(gradientPoints[j+1].value-gradientPoints[j].value);
+var newRed=Math.floor(gradientPoints[j].red+fraction*(gradientPoints[j+1].red-gradientPoints[j].red));
+var newGreen=Math.floor(gradientPoints[j].green+fraction*(gradientPoints[j+1].green-gradientPoints[j].green));
+var newBlue=Math.floor(gradientPoints[j].blue+fraction*(gradientPoints[j+1].blue-gradientPoints[j].blue));
+return rgbToHex(newRed,newGreen,newBlue);
+}}}}};
+var rgbToHex=function(r,g,b){var decToHex=function(n){if(n==0){return"00";
+}else{return n.toString(16);
+}};
+return"#"+decToHex(r)+decToHex(g)+decToHex(b);
+};
+if(key>=gradientPoints[0].value&key<=gradientPoints[gradientPoints.length-1].value){if(flags){flags.keys.add(key);
+}return getColor(key);
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.color;
+}else{if(flags){flags.others=true;
+}return this._othersCase.color;
+}}};
+Exhibit.ColorGradientCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){if(flags){flags.mixed=true;
+}color=self._mixedCase.color;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.color;
+}};
+Exhibit.ColorGradientCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getOthersColor=function(){return this._othersCase.color;
+};
+Exhibit.ColorGradientCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMissingColor=function(){return this._missingCase.color;
+};
+Exhibit.ColorGradientCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMixedColor=function(){return this._mixedCase.color;
+};
+
+
+/* default-color-coder.js */
+Exhibit.DefaultColorCoder=function(uiContext){};
+Exhibit.DefaultColorCoder.colors=["#FF9000","#5D7CBA","#A97838","#8B9BBA","#FFC77F","#003EBA","#29447B","#543C1C"];
+Exhibit.DefaultColorCoder._map={};
+Exhibit.DefaultColorCoder._nextColor=0;
+Exhibit.DefaultColorCoder.prototype.translate=function(key,flags){if(key==null){if(flags){flags.missing=true;
+}return Exhibit.Coders.missingCaseColor;
+}else{if(flags){flags.keys.add(key);
+}if(key in Exhibit.DefaultColorCoder._map){return Exhibit.DefaultColorCoder._map[key];
+}else{var color=Exhibit.DefaultColorCoder.colors[Exhibit.DefaultColorCoder._nextColor];
+Exhibit.DefaultColorCoder._nextColor=(Exhibit.DefaultColorCoder._nextColor+1)%Exhibit.DefaultColorCoder.colors.length;
+Exhibit.DefaultColorCoder._map[key]=color;
+return color;
+}}};
+Exhibit.DefaultColorCoder.prototype.translateSet=function(keys,flags){var color=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+}else{if(color!=color2){color=Exhibit.Coders.mixedCaseColor;
+flags.mixed=true;
+return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{flags.missing=true;
+return Exhibit.Coders.missingCaseColor;
+}};
+Exhibit.DefaultColorCoder.prototype.getOthersLabel=function(){return Exhibit.Coders.l10n.othersCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getOthersColor=function(){return Exhibit.Coders.othersCaseColor;
+};
+Exhibit.DefaultColorCoder.prototype.getMissingLabel=function(){return Exhibit.Coders.l10n.missingCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMissingColor=function(){return Exhibit.Coders.missingCaseColor;
+};
+Exhibit.DefaultColorCoder.prototype.getMixedLabel=function(){return Exhibit.Coders.l10n.mixedCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMixedColor=function(){return Exhibit.Coders.mixedCaseColor;
+};
+
+
+/* icon-coder.js */
+Exhibit.IconCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:"mixed",icon:null};
+this._missingCase={label:"missing",icon:null};
+this._othersCase={label:"others",icon:null};
+};
+Exhibit.IconCoder._settingSpecs={};
+Exhibit.IconCoder.create=function(configuration,uiContext){var coder=new Exhibit.IconCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.IconCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.IconCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.IconCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.IconCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"icon"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"IconCoder: Error processing configuration of coder");
+}Exhibit.IconCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.IconCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.IconCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].icon);
+}}};
+Exhibit.IconCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.IconCoder._iconTable={};
+Exhibit.IconCoder.prototype._addEntry=function(kase,key,icon){if(icon in Exhibit.IconCoder._iconTable){icon=Exhibit.IconCoder._iconTable[icon];
+}var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.icon=icon;
+}else{this._map[key]={icon:icon};
+}};
+Exhibit.IconCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].icon;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.icon;
+}else{if(flags){flags.others=true;
+}return this._othersCase.icon;
+}}};
+Exhibit.IconCoder.prototype.translateSet=function(keys,flags){var icon=null;
+var self=this;
+keys.visit(function(key){var icon2=self.translate(key,flags);
+if(icon==null){icon=icon2;
+}else{if(icon!=icon2){if(flags){flags.mixed=true;
+}icon=self._mixedCase.icon;
+return true;
+}}return false;
+});
+if(icon!=null){return icon;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.icon;
+}};
+Exhibit.IconCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.IconCoder.prototype.getOthersIcon=function(){return this._othersCase.icon;
+};
+Exhibit.IconCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.IconCoder.prototype.getMissingIcon=function(){return this._missingCase.icon;
+};
+Exhibit.IconCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.IconCoder.prototype.getMixedIcon=function(){return this._mixedCase.icon;
+};
+
+
+/* ordered-color-coder.js */
+Exhibit.OrderedColorCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._order=new Exhibit.OrderedColorCoder._OrderedHash();
+this._usePriority="highest";
+this._mixedCase={label:null,color:null,isDefault:true};
+this._missingCase={label:Exhibit.Coders.l10n.missingCaseLabel,color:Exhibit.Coders.missingCaseColor,isDefault:true};
+this._othersCase={label:Exhibit.Coders.l10n.othersCaseLabel,color:Exhibit.Coders.othersCaseColor,isDefault:true};
+};
+Exhibit.OrderedColorCoder._OrderedHash=function(){this.size=0;
+this.hash={};
+};
+Exhibit.OrderedColorCoder._OrderedHash.prototype.add=function(key){this.hash[key]=this.size++;
+};
+Exhibit.OrderedColorCoder._OrderedHash.prototype.size=function(){return this.size;
+};
+Exhibit.OrderedColorCoder._OrderedHash.prototype.get=function(key){return this.hash[key];
+};
+Exhibit.OrderedColorCoder._settingSpecs={};
+Exhibit.OrderedColorCoder.create=function(configuration,uiContext){var coder=new Exhibit.OrderedColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.OrderedColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.OrderedColorCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.OrderedColorCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.OrderedColorCoder._settingSpecs,coder._settings);
+try{this._usePriority=coder._settings.usePriority;
+var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"color"));
+}node=node.nextSibling;
+}if(coder.getOthersIsDefault()){coder._addEntry("other",coder.getOthersLabel(),coder.getOthersColor());
+}if(coder.getMissingIsDefault()){coder._addEntry("missing",coder.getMissingLabel(),coder.getMissingColor());
+}}catch(e){SimileAjax.Debug.exception(e,"OrderedColorCoder: Error processing configuration of coder");
+}Exhibit.OrderedColorCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.OrderedColorCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.OrderedColorCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].color);
+}if(this.getOthersIsDefault()){coder._addEntry("other",this.getOthersLabel(),this.getOthersColor());
+}if(this.getMissingIsDefault()){coder._addEntry("missing",this.getMissingLabel(),this.getMissingColor());
+}}};
+Exhibit.OrderedColorCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.OrderedColorCoder._colorTable={"red":"#ff0000","green":"#00ff00","blue":"#0000ff","white":"#ffffff","black":"#000000","gray":"#888888"};
+Exhibit.OrderedColorCoder.prototype._addEntry=function(kase,key,color){if(color in Exhibit.OrderedColorCoder._colorTable){color=Exhibit.OrderedColorCoder._colorTable[color];
+}var entry=null;
+var mixed=false;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+case"mixed":mixed=true;
+break;
+}if(entry!=null){entry.label=key;
+entry.color=color;
+entry.isDefault=false;
+this._order.add(key);
+}else{if(!mixed){this._map[key]={color:color};
+this._order.add(key);
+}}};
+Exhibit.OrderedColorCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].color;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.color;
+}else{if(flags){flags.others=true;
+}return this._othersCase.color;
+}}};
+Exhibit.OrderedColorCoder.prototype.translateSet=function(keys,flags){var color=null;
+var lastKey=null;
+var self=this;
+keys.visit(function(key){var color2=self.translate(key,flags);
+if(color==null){color=color2;
+lastKey=key;
+}else{if(color!=color2){if(key==null){key=self.getMissingLabel();
+}else{if(!(key in self._map)){key=self.getOthersLabel();
+}}var keyOrder=self._order.get(key);
+var lastKeyOrder=self._order.get(lastKey);
+if(self._usePriority=="highest"){if(keyOrder<lastKeyOrder){color=color2;
+lastKey=key;
+}}else{if(self._usePriority=="lowest"){if(keyOrder>lastKeyOrder){color=color2;
+lastKey=key;
+}}else{return false;
+}}return true;
+}}return false;
+});
+if(color!=null){return color;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.color;
+}};
+Exhibit.OrderedColorCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getOthersColor=function(){return this._othersCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getOthersIsDefault=function(){return this._othersCase.isDefault;
+};
+Exhibit.OrderedColorCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getMissingColor=function(){return this._missingCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getMissingIsDefault=function(){return this._missingCase.isDefault;
+};
+Exhibit.OrderedColorCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getMixedColor=function(){return this._mixedCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getMixedIsDefault=function(){return this._mixedCase.isDefault;
+};
+
+
+/* size-coder.js */
+Exhibit.SizeCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._map={};
+this._mixedCase={label:"mixed",size:10};
+this._missingCase={label:"missing",size:10};
+this._othersCase={label:"others",size:10};
+};
+Exhibit.SizeCoder._settingSpecs={};
+Exhibit.SizeCoder.create=function(configuration,uiContext){var coder=new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SizeCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SizeCoder._settingSpecs,coder._settings);
+try{var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"size"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"SizeCoder: Error processing configuration of coder");
+}Exhibit.SizeCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SizeCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].size);
+}}};
+Exhibit.SizeCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.SizeCoder.prototype._addEntry=function(kase,key,size){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.size=size;
+}else{this._map[key]={size:size};
+}};
+Exhibit.SizeCoder.prototype.translate=function(key,flags){if(key in this._map){if(flags){flags.keys.add(key);
+}return this._map[key].size;
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.size;
+}else{if(flags){flags.others=true;
+}return this._othersCase.size;
+}}};
+Exhibit.SizeCoder.prototype.translateSet=function(keys,flags){var size=null;
+var self=this;
+keys.visit(function(key){var size2=self.translate(key,flags);
+if(size==null){size=size2;
+}else{if(size!=size2){if(flags){flags.mixed=true;
+}size=self._mixedCase.size;
+return true;
+}}return false;
+});
+if(size!=null){return size;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.size;
+}};
+Exhibit.SizeCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.SizeCoder.prototype.getOthersSize=function(){return this._othersCase.size;
+};
+Exhibit.SizeCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.SizeCoder.prototype.getMissingSize=function(){return this._missingCase.size;
+};
+Exhibit.SizeCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.SizeCoder.prototype.getMixedSize=function(){return this._mixedCase.size;
+};
+
+
+/* size-gradient-coder.js */
+Exhibit.SizeGradientCoder=function(uiContext){this._uiContext=uiContext;
+this._settings={};
+this._log={func:function(size){return Math.ceil(Math.log(size));
+},invFunc:function(size){return Math.ceil(Math.exp(size));
+}};
+this._linear={func:function(size){return Math.ceil(size);
+},invFunc:function(size){return Math.ceil(size);
+}};
+this._quad={func:function(size){return Math.ceil(Math.pow((size/100),2));
+},invFunc:function(size){return Math.sqrt(size)*100;
+}};
+this._exp={func:function(size){return Math.ceil(Math.exp(size));
+},invFunc:function(size){return Math.ceil(Math.log(size));
+}};
+this._markerScale=this._quad;
+this._valueScale=this._linear;
+this._gradientPoints=[];
+this._mixedCase={label:"mixed",size:20};
+this._missingCase={label:"missing",size:20};
+this._othersCase={label:"others",size:20};
+};
+Exhibit.SizeGradientCoder._settingSpecs={};
+Exhibit.SizeGradientCoder.create=function(configuration,uiContext){var coder=new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SizeGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeGradientCoder.createFromDOM=function(configElmt,uiContext){configElmt.style.display="none";
+var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var coder=new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SizeGradientCoder._settingSpecs,coder._settings);
+try{var markerScale=coder._settings.markerScale;
+if(markerScale=="log"){coder._markerScale=coder._log;
+}if(markerScale=="linear"){coder._markerScale=coder._linear;
+}if(markerScale=="exp"){coder._markerScale=coder._exp;
+}var gradientPoints=Exhibit.getAttribute(configElmt,"gradientPoints",";");
+for(var i=0;
+i<gradientPoints.length;
+i++){var point=gradientPoints[i].split(",");
+var value=parseFloat(point[0]);
+var size=coder._markerScale.invFunc(parseFloat(point[1]));
+coder._gradientPoints.push({value:value,size:size});
+}var node=configElmt.firstChild;
+while(node!=null){if(node.nodeType==1){coder._addEntry(Exhibit.getAttribute(node,"case"),node.firstChild.nodeValue.trim(),Exhibit.getAttribute(node,"size"));
+}node=node.nextSibling;
+}}catch(e){SimileAjax.Debug.exception(e,"SizeGradientCoder: Error processing configuration of coder");
+}Exhibit.SizeGradientCoder._configure(coder,configuration);
+return coder;
+};
+Exhibit.SizeGradientCoder._configure=function(coder,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SizeGradientCoder._settingSpecs,coder._settings);
+if("entries" in configuration){var entries=configuration.entries;
+for(var i=0;
+i<entries.length;
+i++){coder._addEntry(entries[i].kase,entries[i].key,entries[i].size);
+}}};
+Exhibit.SizeGradientCoder.prototype.dispose=function(){this._uiContext=null;
+this._settings=null;
+};
+Exhibit.SizeGradientCoder.prototype._addEntry=function(kase,key,size){var entry=null;
+switch(kase){case"others":entry=this._othersCase;
+break;
+case"mixed":entry=this._mixedCase;
+break;
+case"missing":entry=this._missingCase;
+break;
+}if(entry!=null){entry.label=key;
+entry.size=size;
+}};
+Exhibit.SizeGradientCoder.prototype.translate=function(key,flags){var self=this;
+var gradientPoints=this._gradientPoints;
+var getSize=function(key){if(key.constructor!=Number){key=parseFloat(key);
+}for(j=0;
+j<gradientPoints.length;
+j++){if(key==gradientPoints[j].value){return self._markerScale.func(gradientPoints[j].size);
+}else{if(gradientPoints[j+1]!=null){if(key<gradientPoints[j+1].value){var fraction=(key-gradientPoints[j].value)/(gradientPoints[j+1].value-gradientPoints[j].value);
+var newSize=Math.floor(gradientPoints[j].size+fraction*(gradientPoints[j+1].size-gradientPoints[j].size));
+return self._markerScale.func(newSize);
+}}}}};
+if(key>=gradientPoints[0].value&key<=gradientPoints[gradientPoints.length-1].value){if(flags){flags.keys.add(key);
+}return getSize(key);
+}else{if(key==null){if(flags){flags.missing=true;
+}return this._missingCase.size;
+}else{if(flags){flags.others=true;
+}return this._othersCase.size;
+}}};
+Exhibit.SizeGradientCoder.prototype.translateSet=function(keys,flags){var size=null;
+var self=this;
+keys.visit(function(key){var size2=self.translate(key,flags);
+if(size==null){size=size2;
+}else{if(size!=size2){if(flags){flags.mixed=true;
+}size=self._mixedCase.size;
+return true;
+}}return false;
+});
+if(size!=null){return size;
+}else{if(flags){flags.missing=true;
+}return this._missingCase.size;
+}};
+Exhibit.SizeGradientCoder.prototype.getOthersLabel=function(){return this._othersCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getOthersSize=function(){return this._othersCase.size;
+};
+Exhibit.SizeGradientCoder.prototype.getMissingLabel=function(){return this._missingCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMissingSize=function(){return this._missingCase.size;
+};
+Exhibit.SizeGradientCoder.prototype.getMixedLabel=function(){return this._mixedCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMixedSize=function(){return this._mixedCase.size;
+};
+
+
+/* coordinator.js */
+Exhibit.Coordinator=function(uiContext){this._uiContext=uiContext;
+this._listeners=[];
+};
+Exhibit.Coordinator.create=function(configuration,uiContext){var coordinator=new Exhibit.Coordinator(uiContext);
+return coordinator;
+};
+Exhibit.Coordinator.createFromDOM=function(div,uiContext){var coordinator=new Exhibit.Coordinator(Exhibit.UIContext.createFromDOM(div,uiContext,false));
+return coordinator;
+};
+Exhibit.Coordinator.prototype.dispose=function(){this._uiContext.dispose();
+this._uiContext=null;
+};
+Exhibit.Coordinator.prototype.addListener=function(callback){var listener=new Exhibit.Coordinator._Listener(this,callback);
+this._listeners.push(listener);
+return listener;
+};
+Exhibit.Coordinator.prototype._removeListener=function(listener){for(var i=0;
+i<this._listeners.length;
+i++){if(this._listeners[i]==listener){this._listeners.splice(i,1);
+return ;
+}}};
+Exhibit.Coordinator.prototype._fire=function(listener,o){for(var i=0;
+i<this._listeners.length;
+i++){var listener2=this._listeners[i];
+if(listener2!=listener){listener2._callback(o);
+}}};
+Exhibit.Coordinator._Listener=function(coordinator,callback){this._coordinator=coordinator;
+this._callback=callback;
+};
+Exhibit.Coordinator._Listener.prototype.dispose=function(){this._coordinator._removeListener(this);
+};
+Exhibit.Coordinator._Listener.prototype.fire=function(o){this._coordinator._fire(this,o);
+};
+
+
+/* alpha-range-facet.js */
+Exhibit.AlphaRangeFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._dom=null;
+this._ranges=[];
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_rangeIndex" in self){delete self._rangeIndex;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.AlphaRangeFacet._settingSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"interval":{type:"int",defaultValue:7},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.AlphaRangeFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.AlphaRangeFacet(containerElmt,uiContext);
+Exhibit.AlphaRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.AlphaRangeFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.AlphaRangeFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.AlphaRangeFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}}catch(e){SimileAjax.Debug.exception(e,"AlphaRangeFacet: Error processing configuration of alpha range facet");
+}Exhibit.AlphaRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.AlphaRangeFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.AlphaRangeFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.AlphaRangeFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._ranges=[];
+};
+Exhibit.AlphaRangeFacet.prototype.hasRestrictions=function(){return this._ranges.length>0;
+};
+Exhibit.AlphaRangeFacet.prototype.clearAllRestrictions=function(){var restrictions=[];
+if(this._ranges.length>0){restrictions=restrictions.concat(this._ranges);
+this._ranges=[];
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.AlphaRangeFacet.prototype.applyRestrictions=function(restrictions){this._ranges=restrictions;
+this._notifyCollection();
+};
+Exhibit.AlphaRangeFacet.prototype.setRange=function(from,to,selected){if(selected){for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){return ;
+}}this._ranges.push({from:from,to:to});
+}else{for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){this._ranges.splice(i,1);
+break;
+}}}this._notifyCollection();
+};
+Exhibit.AlphaRangeFacet.prototype.restrict=function(items){if(this._ranges.length==0){return items;
+}else{this._buildRangeIndex();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+this._rangeIndex.getSubjectsInRange(range.from,String.fromCharCode(range.to.charCodeAt(0)+1),true,set,items);
+}return set;
+}};
+Exhibit.AlphaRangeFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._reconstruct(items);
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.AlphaRangeFacet.prototype._reconstruct=function(items){var self=this;
+var ranges=[];
+var rangeIndex;
+var computeItems;
+this._buildRangeIndex();
+rangeIndex=this._rangeIndex;
+countItems=function(range){return rangeIndex.getSubjectsInRange(range.from,String.fromCharCode(range.to.charCodeAt(0)+1),true,null,items).size();
+};
+var alphaList=[];
+var alphaInList=function(a){for(x in alphaList){if(alphaList[x]==a){return true;
+}}return false;
+};
+for(var y=0;
+y<rangeIndex.getCount();
+y+=1){var alphaChar=rangeIndex._pairs[y].value.substr(0,1).toUpperCase();
+if(!alphaInList(alphaChar)){alphaList.push(alphaChar);
+}}for(var x=0;
+x<alphaList.length;
+x+=this._settings.interval){var range={from:alphaList[x],to:alphaList[(x+this._settings.interval>=alphaList.length?alphaList.length-1:x+this._settings.interval-1)],selected:false};
+range.count=countItems(range);
+for(var i=0;
+i<this._ranges.length;
+i++){var range2=this._ranges[i];
+if(range2.from==range.from&&range2.to==range.to){range.selected=true;
+facetHasSelection=true;
+break;
+}}ranges.push(range);
+}var facetHasSelection=this._ranges.length>0;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var makeFacetValue=function(from,to,count,selected){var onSelect=function(elmt,evt,target){self._toggleRange(from,to,selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._toggleRange(from,to,selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(from.substr(0,1)+" - "+to.substr(0,1),count,null,selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+containerDiv.appendChild(elmt);
+};
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i];
+if(range.selected||range.count>0){makeFacetValue(range.from,range.to,range.count,range.selected);
+}}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._ranges.length);
+};
+Exhibit.AlphaRangeFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.AlphaRangeFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.AlphaRangeFacet.prototype._toggleRange=function(from,to,wasSelected,singleSelection){var self=this;
+var label=from+" to "+to;
+var wasOnlyThingSelected=(this._ranges.length==1&&wasSelected);
+if(singleSelection&&!wasOnlyThingSelected){var newRestrictions=[{from:from,to:to}];
+var oldRestrictions=[].concat(this._ranges);
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]));
+}else{SimileAjax.History.addLengthyAction(function(){self.setRange(from,to,!wasSelected);
+},function(){self.setRange(from,to,wasSelected);
+},String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+}};
+Exhibit.AlphaRangeFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.AlphaRangeFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var segment=expression.getPath().getLastSegment();
+var property=database.getProperty(segment.property);
+var getter=function(item,f){database.getObjects(item,property.getID(),null,null).visit(function(value){f(value.toUpperCase());
+});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+Exhibit.AlphaRangeFacet.prototype.exportFacetSelection=function(){var exportedSettings=[];
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+exportedSettings.push(range.from+"|"+range.to);
+}return exportedSettings.join(",");
+};
+Exhibit.AlphaRangeFacet.prototype.importFacetSelection=function(settings){if(settings.length>0){var ranges=settings.split(",");
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i].split("|");
+this._ranges.push({from:range[0],to:range[1]});
+}}if(ranges&&ranges.length>0){this.update();
+this._notifyCollection();
+}};
+
+
+/* cloud-facet.js */
+Exhibit.CloudFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._settings={};
+this._dom=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}if("_valueToItem" in self){delete self._valueToItem;
+}if("_missingItems" in self){delete self._missingItems;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.CloudFacet._settingSpecs={"facetLabel":{type:"text"},"minimumCount":{type:"int",defaultValue:1},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"}};
+Exhibit.CloudFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.CloudFacet(containerElmt,uiContext);
+Exhibit.CloudFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.CloudFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.CloudFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.CloudFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"CloudFacet: Error processing configuration of cloud facet");
+}Exhibit.CloudFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.CloudFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.CloudFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}};
+Exhibit.CloudFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+this._itemToValue=null;
+this._valueToItem=null;
+this._missingItems=null;
+};
+Exhibit.CloudFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.CloudFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.CloudFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.CloudFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.CloudFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.CloudFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set;
+if(this._expression.isPath()){set=this._expression.getPath().walkBackward(this._valueSet,"item",items,this._uiContext.getDatabase()).getSet();
+}else{this._buildMaps();
+set=new Exhibit.Set();
+var valueToItem=this._valueToItem;
+this._valueSet.visit(function(value){if(value in valueToItem){var itemA=valueToItem[value];
+for(var i=0;
+i<itemA.length;
+i++){var item=itemA[i];
+if(items.contains(item)){set.add(item);
+}}}});
+}if(this._selectMissing){this._buildMaps();
+var missingItems=this._missingItems;
+items.visit(function(item){if(item in missingItems){set.add(item);
+}});
+}return set;
+};
+Exhibit.CloudFacet.prototype.update=function(items){this._constructBody(this._computeFacet(items));
+};
+Exhibit.CloudFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var entries=[];
+var valueType="text";
+var self=this;
+if(this._expression.isPath()){var path=this._expression.getPath();
+var facetValueResult=path.walkForward(items,"item",database);
+valueType=facetValueResult.valueType;
+if(facetValueResult.size>0){facetValueResult.forEachValue(function(facetValue){var itemSubcollection=path.evaluateBackward(facetValue,valueType,items,database);
+if(itemSubcollection.size>=self._settings.minimumCount||self._valueSet.contains(facetValue)){entries.push({value:facetValue,count:itemSubcollection.size});
+}});
+}}else{this._buildMaps();
+valueType=this._valueType;
+for(var value in this._valueToItem){var itemA=this._valueToItem[value];
+var count=0;
+for(var i=0;
+i<itemA.length;
+i++){if(items.contains(itemA[i])){count++;
+}}if(count>=this._settings.minimumCount||this._valueSet.contains(value)){entries.push({value:value,count:count});
+}}}if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.selected=selection.contains(entry.value);
+}var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}entries.sort(sortDirectionFunction);
+}if(this._settings.showMissing||this._selectMissing){this._buildMaps();
+var count=0;
+for(var item in this._missingItems){if(items.contains(item)){count++;
+}}if(count>0||this._selectMissing){var span=document.createElement("span");
+span.innerHTML=("missingLabel" in this._settings)?this._settings.missingLabel:Exhibit.FacetUtilities.l10n.missingThisField;
+span.className="exhibit-facet-value-missingThisField";
+entries.unshift({value:null,count:count,selected:this._selectMissing,selectionLabel:span,actionLabel:Exhibit.FacetUtilities.l10n.missingThisField});
+}}return entries;
+};
+Exhibit.CloudFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.CloudFacet.prototype._initializeUI=function(){this._div.innerHTML="";
+this._div.className="exhibit-cloudFacet";
+var dom=SimileAjax.DOM.createDOMFromString(this._div,(("facetLabel" in this._settings)?("<div class='exhibit-cloudFacet-header'><span class='exhibit-cloudFacet-header-title'>"+this._settings.facetLabel+"</span></div>"):"")+"<div class='exhibit-cloudFacet-body' id='valuesContainer'></div>");
+this._dom=dom;
+};
+Exhibit.CloudFacet.prototype._constructBody=function(entries){var self=this;
+var div=this._dom.valuesContainer;
+div.style.display="none";
+div.innerHTML="";
+if(entries.length>0){var min=Number.POSITIVE_INFINITY;
+var max=Number.NEGATIVE_INFINITY;
+for(var j=0;
+j<entries.length;
+j++){var entry=entries[j];
+min=Math.min(min,entry.count);
+max=Math.max(max,entry.count);
+}var range=max-min;
+var constructValue=function(entry){var onSelect=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=document.createElement("span");
+elmt.appendChild(document.createTextNode("\u00A0"));
+if(typeof entry.selectionLabel=="string"){elmt.appendChild(document.createTextNode(entry.selectionLabel));
+}else{elmt.appendChild(entry.selectionLabel);
+}elmt.appendChild(document.createTextNode("\u00A0"));
+elmt.className=entry.selected?"exhibit-cloudFacet-value exhibit-cloudFacet-value-selected":"exhibit-cloudFacet-value";
+if(entry.count>min){elmt.style.fontSize=Math.ceil(100+100*Math.log(1+1.5*(entry.count-min)/range))+"%";
+}SimileAjax.WindowManager.registerEvent(elmt,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+div.appendChild(elmt);
+div.appendChild(document.createTextNode(" "));
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}}div.style.display="block";
+};
+Exhibit.CloudFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+var facetLabel=("facetLabel" in this._settings)?this._settings.facetLabel:"";
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,facetLabel]));
+};
+Exhibit.CloudFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.CloudFacet.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var valueToItem={};
+var missingItems={};
+var valueType="text";
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var expression=this._expression;
+var database=this._uiContext.getDatabase();
+this._uiContext.getCollection().getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){insert(item,value,itemToValue);
+insert(value,item,valueToItem);
+});
+}else{missingItems[item]=true;
+}});
+this._itemToValue=itemToValue;
+this._valueToItem=valueToItem;
+this._missingItems=missingItems;
+this._valueType=valueType;
+}};
+
+
+/* hierarchical-facet.js */
+Exhibit.HierarchicalFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._uniformGroupingExpression=null;
+this._selections=[];
+this._expanded={};
+this._settings={};
+this._dom=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_cache" in self){delete self._cache;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.HierarchicalFacet._settingSpecs={"facetLabel":{type:"text"},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"othersLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.HierarchicalFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.HierarchicalFacet(containerElmt,uiContext);
+Exhibit.HierarchicalFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.HierarchicalFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.HierarchicalFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.HierarchicalFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var uniformGroupingString=Exhibit.getAttribute(configElmt,"uniformGrouping");
+if(uniformGroupingString!=null&&uniformGroupingString.length>0){facet._uniformGroupingExpression=Exhibit.ExpressionParser.parse(uniformGroupingString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._selections=facet._internalAddSelection({value:s,selectOthers:false});
+}}}catch(e){SimileAjax.Debug.exception(e,"HierarchicalFacet: Error processing configuration of hierarchical facet");
+}Exhibit.HierarchicalFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.HierarchicalFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.HierarchicalFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("uniformGrouping" in configuration){facet._uniformGroupingExpression=Exhibit.ExpressionParser.parse(configuration.uniformGrouping);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._selections.push({value:selection[i],selectOthers:false});
+}}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.HierarchicalFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._uniformGroupingExpression=null;
+this._selections=null;
+this._settings=null;
+this._cache=null;
+};
+Exhibit.HierarchicalFacet.prototype.hasRestrictions=function(){return this._selections.length>0;
+};
+Exhibit.HierarchicalFacet.prototype.clearAllRestrictions=function(){var selections=this._selections;
+this._selections=[];
+if(selections.length>0){this._notifyCollection();
+}return selections;
+};
+Exhibit.HierarchicalFacet.prototype.applyRestrictions=function(restrictions){this._selections=[].concat(restrictions);
+this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.setSelection=function(value,selected){var selection={value:value,selectOthers:false};
+if(selected){this._selections=this._internalAddSelection(selection);
+}else{this._selections=this._internalRemoveSelection(selection);
+}this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.setselectOthers=function(value,selected){var selection={value:value,selectOthers:true};
+if(selected){this._selections=this._internalAddSelection(selection);
+}else{this._selections=this._internalRemoveSelection(selection);
+}this._notifyCollection();
+};
+Exhibit.HierarchicalFacet.prototype.restrict=function(items){if(this._selections.length==0){return items;
+}this._buildCache();
+var set=new Exhibit.Set();
+var includeNode=function(node){if("children" in node){includeChildNodes(node.children);
+Exhibit.Set.createIntersection(node.others,items,set);
+}else{Exhibit.Set.createIntersection(node.items,items,set);
+}};
+var includeChildNodes=function(childNodes){for(var i=0;
+i<childNodes.length;
+i++){includeNode(childNodes[i]);
+}};
+for(var i=0;
+i<this._selections.length;
+i++){var selection=this._selections[i];
+var node=this._getTreeNode(selection.value);
+if(node){if(selection.selectOthers){Exhibit.Set.createIntersection(node.others,items,set);
+}else{includeNode(node);
+}}}return set;
+};
+Exhibit.HierarchicalFacet.prototype._internalAddSelection=function(selection){var parentToClear={};
+var childrenToClear={};
+var cache=this._cache;
+var markClearAncestors=function(value){if(value in cache.valueToParent){var parents=cache.valueToParent[value];
+for(var i=0;
+i<parents.length;
+i++){var parent=parents[i];
+parentToClear[parent]=true;
+markClearAncestors(parent);
+}}};
+var markClearDescendants=function(value){if(value in cache.valueToChildren){var children=cache.valueToChildren[value];
+for(var i=0;
+i<children.length;
+i++){var child=children[i];
+childrenToClear[child]=true;
+markClearDescendants(child);
+}}};
+if(selection.value!=null){markClearAncestors(selection.value);
+if(selection.selectOthers){parentToClear[selection.value]=true;
+}else{childrenToClear[selection.value]=true;
+markClearDescendants(selection.value);
+}}var oldSelections=this._selections;
+var newSelections=[selection];
+for(var i=0;
+i<oldSelections.length;
+i++){var s=oldSelections[i];
+if((!(s.value in parentToClear)||s.selectOthers)&&(!(s.value in childrenToClear))){newSelections.push(s);
+}}return newSelections;
+};
+Exhibit.HierarchicalFacet.prototype._internalRemoveSelection=function(selection){var oldSelections=this._selections;
+var newSelections=[];
+for(var i=0;
+i<oldSelections.length;
+i++){var s=oldSelections[i];
+if(s.value!=selection.value||s.selectOthers!=selection.selectOthers){newSelections.push(s);
+}}return newSelections;
+};
+Exhibit.HierarchicalFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+var tree=this._computeFacet(items);
+if(tree){this._constructBody(tree);
+}this._dom.valuesContainer.style.display="block";
+};
+Exhibit.HierarchicalFacet.prototype._computeFacet=function(items){this._buildCache();
+var database=this._uiContext.getDatabase();
+var sorter=this._getValueSorter();
+var othersLabel="othersLabel" in this._settings?this._settings.othersLabel:"(others)";
+var selectionMap={};
+for(var i=0;
+i<this._selections.length;
+i++){var s=this._selections[i];
+selectionMap[s.value]=s.selectOthers;
+}var processNode=function(node,resultNodes,superset){var selected=(node.value in selectionMap&&!selectionMap[node.value]);
+if("children" in node){var resultNode={value:node.value,label:node.label,children:[],selected:selected,areOthers:false};
+var superset2=new Exhibit.Set();
+for(var i=0;
+i<node.children.length;
+i++){var childNode=node.children[i];
+processNode(childNode,resultNode.children,superset2);
+}resultNode.children.sort(sorter);
+if(node.others.size()>0){var othersSelected=(node.value in selectionMap&&selectionMap[node.value]);
+var subset=Exhibit.Set.createIntersection(items,node.others);
+if(subset.size()>0||othersSelected){resultNode.children.push({value:node.value,label:othersLabel,count:subset.size(),selected:othersSelected,areOthers:true});
+superset2.addSet(subset);
+}}resultNode.count=superset2.size();
+if(selected||resultNode.count>0||resultNode.children.length>0){resultNodes.push(resultNode);
+if(superset!=null&&superset2.size()>0){superset.addSet(superset2);
+}}}else{var subset=Exhibit.Set.createIntersection(items,node.items);
+if(subset.size()>0||selected){resultNodes.push({value:node.value,label:node.label,count:subset.size(),selected:selected,areOthers:false});
+if(superset!=null&&subset.size()>0){superset.addSet(subset);
+}}}};
+var nodes=[];
+processNode(this._cache.tree,nodes,null);
+return nodes[0];
+};
+Exhibit.HierarchicalFacet.prototype._getValueSorter=function(){var sortValueFunction=function(a,b){return a.label.localeCompare(b.label);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.label in orderMap){if(b.label in orderMap){return orderMap[a.label]-orderMap[b.label];
+}else{return -1;
+}}else{if(b.label in orderMap){return 1;
+}else{return a.label.localeCompare(b.label);
+}}};
+}else{if(this._cache.valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+Exhibit.HierarchicalFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.HierarchicalFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.HierarchicalFacet.prototype._constructBody=function(tree){var self=this;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructHierarchicalFacetItem":"constructFlowingHierarchicalFacetItem"];
+var facetHasSelection=this._selections.length>0;
+var processNode=function(node,div){var hasChildren=("children" in node);
+var onSelect=function(elmt,evt,target){self._filter(node.value,node.areOthers,node.label,node.selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._filter(node.value,node.areOthers,node.label,node.selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onToggleChildren=function(elmt,evt,target){var show;
+if(node.value in self._expanded){delete self._expanded[node.value];
+show=false;
+}else{self._expanded[node.value]=true;
+show=true;
+}dom.showChildren(show);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var dom=constructFacetItemFunction(node.label,node.count,(self._colorCoder!=null)?self._colorCoder.translate(node.value):null,node.selected,hasChildren,(node.value in self._expanded),facetHasSelection,onSelect,onSelectOnly,onToggleChildren,self._uiContext);
+div.appendChild(dom.elmt);
+if(hasChildren){processChildNodes(node.children,dom.childrenContainer);
+}};
+var processChildNodes=function(childNodes,div){for(var i=0;
+i<childNodes.length;
+i++){processNode(childNodes[i],div);
+}};
+processChildNodes(tree.children,containerDiv);
+containerDiv.style.display="block";
+this._dom.setSelectionCount(this._selections.length);
+};
+Exhibit.HierarchicalFacet.prototype._filter=function(value,areOthers,label,wasSelected,selectOnly){var self=this;
+var wasSelectedAlone=wasSelected&&this._selections.length==1;
+var selection={value:value,selectOthers:areOthers};
+var oldRestrictions=this._selections;
+var newRestrictions;
+if(wasSelected){if(selectOnly){if(wasSelectedAlone){newRestrictions=[];
+}else{newRestrictions=[selection];
+}}else{newRestrictions=this._internalRemoveSelection(selection);
+}}else{if(selectOnly){newRestrictions=[selection];
+}else{newRestrictions=this._internalAddSelection(selection);
+}}SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasSelectedAlone)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.HierarchicalFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.HierarchicalFacet.prototype._buildCache=function(){if(!("_cache" in this)){var valueToItem={};
+var valueType="text";
+var valueToChildren={};
+var valueToParent={};
+var valueToPath={};
+var values=new Exhibit.Set();
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var database=this._uiContext.getDatabase();
+var tree={value:null,label:"(root)",others:new Exhibit.Set(),children:[]};
+var expression=this._expression;
+this._uiContext.getCollection().getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){values.add(value);
+insert(value,item,valueToItem);
+});
+}else{tree.others.add(item);
+}});
+var groupingExpression=this._uniformGroupingExpression;
+var rootValues=new Exhibit.Set();
+var getParentChildRelationships=function(valueSet){var newValueSet=new Exhibit.Set();
+valueSet.visit(function(value){var results=groupingExpression.evaluateOnItem(value,database);
+if(results.values.size()>0){results.values.visit(function(parentValue){insert(value,parentValue,valueToParent);
+insert(parentValue,value,valueToChildren);
+if(!valueSet.contains(parentValue)){newValueSet.add(parentValue);
+}return true;
+});
+}else{rootValues.add(value);
+}});
+if(newValueSet.size()>0){getParentChildRelationships(newValueSet);
+}};
+getParentChildRelationships(values);
+var processValue=function(value,nodes,valueSet,path){var label=database.getObject(value,"label");
+var node={value:value,label:label!=null?label:value};
+nodes.push(node);
+valueToPath[value]=path;
+if(value in valueToChildren){node.children=[];
+var valueSet2=new Exhibit.Set();
+var childrenValue=valueToChildren[value];
+for(var i=0;
+i<childrenValue.length;
+i++){processValue(childrenValue[i],node.children,valueSet2,path.concat(i));
+}node.others=new Exhibit.Set();
+if(value in valueToItem){var items=valueToItem[value];
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+if(!valueSet2.contains(item)){node.others.add(item);
+valueSet.add(item);
+}}}valueSet.addSet(valueSet2);
+}else{node.items=new Exhibit.Set();
+if(value in valueToItem){var items=valueToItem[value];
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+node.items.add(item);
+valueSet.add(item);
+}}}};
+var index=0;
+rootValues.visit(function(value){processValue(value,tree.children,new Exhibit.Set(),[index++]);
+});
+this._cache={tree:tree,valueToChildren:valueToChildren,valueToParent:valueToParent,valueToPath:valueToPath,valueType:valueType};
+}};
+Exhibit.HierarchicalFacet.prototype._getTreeNode=function(value){if(value==null){return this._cache.tree;
+}var path=this._cache.valueToPath[value];
+var trace=function(node,path,index){var node2=node.children[path[index]];
+if(++index<path.length){return trace(node2,path,index);
+}else{return node2;
+}};
+return(path)?trace(this._cache.tree,path,0):null;
+};
+
+
+/* image-facet.js */
+Exhibit.ImageFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._settings={};
+this._dom=null;
+};
+Exhibit.ImageFacet._settingSpecs={"facetLabel":{type:"text"},"thumbNail":{type:"uri"},"overlayCounts":{type:"boolean",defaultValue:true},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.ImageFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.ImageFacet(containerElmt,uiContext);
+Exhibit.ImageFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ImageFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.ImageFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ImageFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var imageString=Exhibit.getAttribute(configElmt,"image");
+if(imageString!=null&&imageString.length>0){facet._imageExpression=Exhibit.ExpressionParser.parse(imageString);
+}var tooltipString=Exhibit.getAttribute(configElmt,"tooltip");
+if(tooltipString!=null&&tooltipString.length>0){facet._tooltipExpression=Exhibit.ExpressionParser.parse(tooltipString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"ImageFacet: Error processing configuration of list facet");
+}Exhibit.ImageFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ImageFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ImageFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("image" in configuration){facet._imageExpression=Exhibit.ExpressionParser.parse(configuration.image);
+}if("tooltip" in configuration){facet._tooltipExpression=Exhibit.ExpressionParser.parse(configuration.tooltip);
+}if(!(facet._imageExpression)){facet._imageExpression=Exhibit.ExpressionParser.parse("value");
+}if(!(facet._tooltipExpression)){facet._tooltipExpression=Exhibit.ExpressionParser.parse("value");
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+};
+Exhibit.ImageFacet.prototype.dispose=function(){this._cache.dispose();
+this._cache=null;
+this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+};
+Exhibit.ImageFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.ImageFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.ImageFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.ImageFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.ImageFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.ImageFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set=this._cache.getItemsFromValues(this._valueSet,items);
+if(this._selectMissing){this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.ImageFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._constructBody(this._computeFacet(items));
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.ImageFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var r=this._cache.getValueCountsFromItems(items);
+var entries=r.entries;
+var valueType=r.valueType;
+if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.image=this._imageExpression.evaluateSingleOnItem(entry.value,database).value;
+entry.tooltip=this._tooltipExpression.evaluateSingleOnItem(entry.value,database).value;
+entry.selected=selection.contains(entry.value);
+}entries.sort(this._createSortFunction(valueType));
+}return entries;
+};
+Exhibit.ImageFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.ImageFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.ImageFacet.prototype._constructBody=function(entries){var self=this;
+var shouldOverlayCounts=this._settings.overlayCounts;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var facetHasSelection=this._valueSet.size()>0||this._selectMissing;
+var constructValue=function(entry){var onSelectOnly=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=document.createElement("span");
+var wrapper=document.createElement("div");
+wrapper.className="wrapper";
+var image=document.createElement("img");
+image.src=entry.image;
+wrapper.appendChild(image);
+if(shouldOverlayCounts==true){var countDiv=document.createElement("div");
+countDiv.className="countDiv";
+var countBackground=document.createElement("div");
+countBackground.className="countBackground";
+countDiv.appendChild(countBackground);
+var innerCount=document.createElement("div");
+innerCount.className="text";
+innerCount.innerHTML=entry.count;
+countDiv.appendChild(innerCount);
+wrapper.appendChild(countDiv);
+}elmt.appendChild(wrapper);
+elmt.className=entry.selected?"inline-block exhibit-imageFacet-value exhibit-imageFacet-value-selected":"inline-block exhibit-imageFacet-value";
+elmt.title=entry.count+" "+entry.tooltip;
+SimileAjax.WindowManager.registerEvent(elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+containerDiv.appendChild(elmt);
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._valueSet.size()+(this._selectMissing?1:0));
+};
+Exhibit.ImageFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.ImageFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.ImageFacet.prototype._createSortFunction=function(valueType){var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+
+
+/* list-facet.js */
+Exhibit.ListFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorCoder=null;
+this._expression=null;
+this._valueSet=new Exhibit.Set();
+this._selectMissing=false;
+this._delayedUpdateItems=null;
+this._settings={};
+this._dom=null;
+};
+Exhibit.ListFacet._settingSpecs={"facetLabel":{type:"text"},"fixedOrder":{type:"text"},"sortMode":{type:"text",defaultValue:"value"},"sortDirection":{type:"text",defaultValue:"forward"},"showMissing":{type:"boolean",defaultValue:true},"missingLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"colorCoder":{type:"text",defaultValue:null},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false},"formatter":{type:"text",defaultValue:null}};
+Exhibit.ListFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.ListFacet(containerElmt,uiContext);
+Exhibit.ListFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ListFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.ListFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ListFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var selection=Exhibit.getAttribute(configElmt,"selection",";");
+if(selection!=null&&selection.length>0){for(var i=0,s;
+s=selection[i];
+i++){facet._valueSet.add(s);
+}}var selectMissing=Exhibit.getAttribute(configElmt,"selectMissing");
+if(selectMissing!=null&&selectMissing.length>0){facet._selectMissing=(selectMissing=="true");
+}}catch(e){SimileAjax.Debug.exception(e,"ListFacet: Error processing configuration of list facet");
+}Exhibit.ListFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.ListFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ListFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("selectMissing" in configuration){facet._selectMissing=configuration.selectMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if("fixedOrder" in facet._settings){var values=facet._settings.fixedOrder.split(";");
+var orderMap={};
+for(var i=0;
+i<values.length;
+i++){orderMap[values[i].trim()]=i;
+}facet._orderMap=orderMap;
+}if("colorCoder" in facet._settings){facet._colorCoder=facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}if("formatter" in facet._settings){var formatter=facet._settings.formatter;
+if(formatter!=null&&formatter.length>0){try{facet._formatter=eval(formatter);
+}catch(e){SimileAjax.Debug.log(e);
+}}}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+};
+Exhibit.ListFacet.prototype.dispose=function(){this._cache.dispose();
+this._cache=null;
+this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._valueSet=null;
+this._settings=null;
+};
+Exhibit.ListFacet.prototype.hasRestrictions=function(){return this._valueSet.size()>0||this._selectMissing;
+};
+Exhibit.ListFacet.prototype.clearAllRestrictions=function(){var restrictions={selection:[],selectMissing:false};
+if(this.hasRestrictions()){this._valueSet.visit(function(v){restrictions.selection.push(v);
+});
+this._valueSet=new Exhibit.Set();
+restrictions.selectMissing=this._selectMissing;
+this._selectMissing=false;
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.ListFacet.prototype.applyRestrictions=function(restrictions){this._valueSet=new Exhibit.Set();
+for(var i=0;
+i<restrictions.selection.length;
+i++){this._valueSet.add(restrictions.selection[i]);
+}this._selectMissing=restrictions.selectMissing;
+this._notifyCollection();
+};
+Exhibit.ListFacet.prototype.setSelection=function(value,selected){if(selected){this._valueSet.add(value);
+}else{this._valueSet.remove(value);
+}this._notifyCollection();
+};
+Exhibit.ListFacet.prototype.setSelectMissing=function(selected){if(selected!=this._selectMissing){this._selectMissing=selected;
+this._notifyCollection();
+}};
+Exhibit.ListFacet.prototype.restrict=function(items){if(this._valueSet.size()==0&&!this._selectMissing){return items;
+}var set=this._cache.getItemsFromValues(this._valueSet,items);
+if(this._selectMissing){this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.ListFacet.prototype.onUncollapse=function(){if(this._delayedUpdateItems!=null){this.update(this._delayedUpdateItems);
+this._delayedUpdateItems=null;
+}};
+Exhibit.ListFacet.prototype.update=function(items){if(Exhibit.FacetUtilities.isCollapsed(this)){this._delayedUpdateItems=items;
+return ;
+}this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._constructBody(this._computeFacet(items));
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.ListFacet.prototype._computeFacet=function(items){var database=this._uiContext.getDatabase();
+var r=this._cache.getValueCountsFromItems(items);
+var entries=r.entries;
+var valueType=r.valueType;
+if(entries.length>0){var selection=this._valueSet;
+var labeler=valueType=="item"?function(v){var l=database.getObject(v,"label");
+return l!=null?l:v;
+}:function(v){return v;
+};
+for(var i=0;
+i<entries.length;
+i++){var entry=entries[i];
+entry.actionLabel=entry.selectionLabel=labeler(entry.value);
+entry.selected=selection.contains(entry.value);
+}entries.sort(this._createSortFunction(valueType));
+}if(this._settings.showMissing||this._selectMissing){var count=this._cache.countItemsMissingValue(items);
+if(count>0||this._selectMissing){var span=document.createElement("span");
+span.innerHTML=("missingLabel" in this._settings)?this._settings.missingLabel:Exhibit.FacetUtilities.l10n.missingThisField;
+span.className="exhibit-facet-value-missingThisField";
+entries.unshift({value:null,count:count,selected:this._selectMissing,selectionLabel:span,actionLabel:Exhibit.FacetUtilities.l10n.missingThisField});
+}}return entries;
+};
+Exhibit.ListFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.ListFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings&&this._settings.scroll){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.ListFacet.prototype._constructBody=function(entries){var self=this;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var facetHasSelection=this._valueSet.size()>0||this._selectMissing;
+var constructValue=function(entry){var onSelect=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._filter(entry.value,entry.actionLabel,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(entry.selectionLabel,entry.count,(self._colorCoder!=null)?self._colorCoder.translate(entry.value):null,entry.selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+if(self._formatter){self._formatter(elmt);
+}containerDiv.appendChild(elmt);
+};
+for(var j=0;
+j<entries.length;
+j++){constructValue(entries[j]);
+}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._valueSet.size()+(this._selectMissing?1:0));
+};
+Exhibit.ListFacet.prototype._filter=function(value,label,selectOnly){var self=this;
+var selected,select,deselect;
+var oldValues=new Exhibit.Set(this._valueSet);
+var oldSelectMissing=this._selectMissing;
+var newValues;
+var newSelectMissing;
+var actionLabel;
+var wasSelected;
+var wasOnlyThingSelected;
+if(value==null){wasSelected=oldSelectMissing;
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==0);
+if(selectOnly){if(oldValues.size()==0){newSelectMissing=!oldSelectMissing;
+}else{newSelectMissing=true;
+}newValues=new Exhibit.Set();
+}else{newSelectMissing=!oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+}}else{wasSelected=oldValues.contains(value);
+wasOnlyThingSelected=wasSelected&&(oldValues.size()==1)&&!oldSelectMissing;
+if(selectOnly){newSelectMissing=false;
+newValues=new Exhibit.Set();
+if(!oldValues.contains(value)){newValues.add(value);
+}else{if(oldValues.size()>1||oldSelectMissing){newValues.add(value);
+}}}else{newSelectMissing=oldSelectMissing;
+newValues=new Exhibit.Set(oldValues);
+if(newValues.contains(value)){newValues.remove(value);
+}else{newValues.add(value);
+}}}var newRestrictions={selection:newValues.toArray(),selectMissing:newSelectMissing};
+var oldRestrictions={selection:oldValues.toArray(),selectMissing:oldSelectMissing};
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},(selectOnly&&!wasOnlyThingSelected)?String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]):String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+};
+Exhibit.ListFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.ListFacet.prototype._createSortFunction=function(valueType){var sortValueFunction=function(a,b){return a.selectionLabel.localeCompare(b.selectionLabel);
+};
+if("_orderMap" in this){var orderMap=this._orderMap;
+sortValueFunction=function(a,b){if(a.selectionLabel in orderMap){if(b.selectionLabel in orderMap){return orderMap[a.selectionLabel]-orderMap[b.selectionLabel];
+}else{return -1;
+}}else{if(b.selectionLabel in orderMap){return 1;
+}else{return a.selectionLabel.localeCompare(b.selectionLabel);
+}}};
+}else{if(valueType=="number"){sortValueFunction=function(a,b){a=parseFloat(a.value);
+b=parseFloat(b.value);
+return a<b?-1:a>b?1:0;
+};
+}}var sortFunction=sortValueFunction;
+if(this._settings.sortMode=="count"){sortFunction=function(a,b){var c=b.count-a.count;
+return c!=0?c:sortValueFunction(a,b);
+};
+}var sortDirectionFunction=sortFunction;
+if(this._settings.sortDirection=="reverse"){sortDirectionFunction=function(a,b){return sortFunction(b,a);
+};
+}return sortDirectionFunction;
+};
+Exhibit.ListFacet.prototype.exportFacetSelection=function(){var s=[];
+this._valueSet.visit(function(v){s.push(v);
+});
+if(s.length>0){return s.join(",");
+}};
+Exhibit.ListFacet.prototype.importFacetSelection=function(settings){var self=this;
+self.applyRestrictions({selection:settings.split(","),selectMissing:self._selectMissing});
+};
+
+
+/* numeric-range-facet.js */
+Exhibit.NumericRangeFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._dom=null;
+this._ranges=[];
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_rangeIndex" in self){delete self._rangeIndex;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.NumericRangeFacet._settingSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"interval":{type:"float",defaultValue:10},"collapsible":{type:"boolean",defaultValue:false},"collapsed":{type:"boolean",defaultValue:false}};
+Exhibit.NumericRangeFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.NumericRangeFacet(containerElmt,uiContext);
+Exhibit.NumericRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.NumericRangeFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.NumericRangeFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.NumericRangeFacet._settingSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}}catch(e){SimileAjax.Debug.exception(e,"NumericRangeFacet: Error processing configuration of numeric range facet");
+}Exhibit.NumericRangeFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.NumericRangeFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.NumericRangeFacet._settingSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}if(facet._settings.collapsed){facet._settings.collapsible=true;
+}};
+Exhibit.NumericRangeFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._ranges=null;
+};
+Exhibit.NumericRangeFacet.prototype.hasRestrictions=function(){return this._ranges.length>0;
+};
+Exhibit.NumericRangeFacet.prototype.clearAllRestrictions=function(){var restrictions=[];
+if(this._ranges.length>0){restrictions=restrictions.concat(this._ranges);
+this._ranges=[];
+this._notifyCollection();
+}return restrictions;
+};
+Exhibit.NumericRangeFacet.prototype.applyRestrictions=function(restrictions){this._ranges=restrictions;
+this._notifyCollection();
+};
+Exhibit.NumericRangeFacet.prototype.setRange=function(from,to,selected){if(selected){for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){return ;
+}}this._ranges.push({from:from,to:to});
+}else{for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+if(range.from==from&&range.to==to){this._ranges.splice(i,1);
+break;
+}}}this._notifyCollection();
+};
+Exhibit.NumericRangeFacet.prototype.restrict=function(items){if(this._ranges.length==0){return items;
+}else{if(this._expression.isPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+set.addSet(path.rangeBackward(range.from,range.to,false,items,database).values);
+}return set;
+}else{this._buildRangeIndex();
+var set=new Exhibit.Set();
+for(var i=0;
+i<this._ranges.length;
+i++){var range=this._ranges[i];
+this._rangeIndex.getSubjectsInRange(range.from,range.to,false,set,items);
+}return set;
+}}};
+Exhibit.NumericRangeFacet.prototype.update=function(items){this._dom.valuesContainer.style.display="none";
+this._dom.valuesContainer.innerHTML="";
+this._reconstruct(items);
+this._dom.valuesContainer.style.display="block";
+};
+Exhibit.NumericRangeFacet.prototype._reconstruct=function(items){var self=this;
+var ranges=[];
+var rangeIndex;
+var computeItems;
+if(this._expression.isPath()){var database=this._uiContext.getDatabase();
+var path=this._expression.getPath();
+var propertyID=path.getLastSegment().property;
+var property=database.getProperty(propertyID);
+if(property==null){return null;
+}rangeIndex=property.getRangeIndex();
+countItems=function(range){return path.rangeBackward(range.from,range.to,false,items,database).values.size();
+};
+}else{this._buildRangeIndex();
+rangeIndex=this._rangeIndex;
+countItems=function(range){return rangeIndex.getSubjectsInRange(range.from,range.to,false,null,items).size();
+};
+}var min=rangeIndex.getMin();
+var max=rangeIndex.getMax();
+min=Math.floor(min/this._settings.interval)*this._settings.interval;
+max=Math.ceil((max+this._settings.interval)/this._settings.interval)*this._settings.interval;
+for(var x=min;
+x<max;
+x+=this._settings.interval){var range={from:x,to:x+this._settings.interval,selected:false};
+range.count=countItems(range);
+for(var i=0;
+i<this._ranges.length;
+i++){var range2=this._ranges[i];
+if(range2.from==range.from&&range2.to==range.to){range.selected=true;
+facetHasSelection=true;
+break;
+}}ranges.push(range);
+}var facetHasSelection=this._ranges.length>0;
+var containerDiv=this._dom.valuesContainer;
+containerDiv.style.display="none";
+var constructFacetItemFunction=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetItem":"constructFlowingFacetItem"];
+var makeFacetValue=function(from,to,count,selected){var onSelect=function(elmt,evt,target){self._toggleRange(from,to,selected,false);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var onSelectOnly=function(elmt,evt,target){self._toggleRange(from,to,selected,!(evt.ctrlKey||evt.metaKey));
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+var elmt=constructFacetItemFunction(from+" - "+to,count,null,selected,facetHasSelection,onSelect,onSelectOnly,self._uiContext);
+containerDiv.appendChild(elmt);
+};
+for(var i=0;
+i<ranges.length;
+i++){var range=ranges[i];
+if(range.selected||range.count>0){makeFacetValue(range.from,range.to,range.count,range.selected);
+}}containerDiv.style.display="block";
+this._dom.setSelectionCount(this._ranges.length);
+};
+Exhibit.NumericRangeFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.NumericRangeFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.FacetUtilities[this._settings.scroll?"constructFacetFrame":"constructFlowingFacetFrame"](this,this._div,this._settings.facetLabel,function(elmt,evt,target){self._clearSelections();
+},this._uiContext,this._settings.collapsible,this._settings.collapsed);
+if("height" in this._settings){this._dom.valuesContainer.style.height=this._settings.height;
+}};
+Exhibit.NumericRangeFacet.prototype._toggleRange=function(from,to,wasSelected,singleSelection){var self=this;
+var label=from+" to "+to;
+var wasOnlyThingSelected=(this._ranges.length==1&&wasSelected);
+if(singleSelection&&!wasOnlyThingSelected){var newRestrictions=[{from:from,to:to}];
+var oldRestrictions=[].concat(this._ranges);
+SimileAjax.History.addLengthyAction(function(){self.applyRestrictions(newRestrictions);
+},function(){self.applyRestrictions(oldRestrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],[label,this._settings.facetLabel]));
+}else{SimileAjax.History.addLengthyAction(function(){self.setRange(from,to,!wasSelected);
+},function(){self.setRange(from,to,wasSelected);
+},String.substitute(Exhibit.FacetUtilities.l10n[wasSelected?"facetUnselectActionTitle":"facetSelectActionTitle"],[label,this._settings.facetLabel]));
+}};
+Exhibit.NumericRangeFacet.prototype._clearSelections=function(){var state={};
+var self=this;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=self.clearAllRestrictions();
+},function(){self.applyRestrictions(state.restrictions);
+},String.substitute(Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],[this._settings.facetLabel]));
+};
+Exhibit.NumericRangeFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var getter=function(item,f){expression.evaluateOnItem(item,database).values.visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+
+
+/* slider-facet.js */
+Exhibit.SliderFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expression=null;
+this._settings={};
+this._selection={min:null,max:null};
+this._range={min:null,max:null};
+this._maxRange={min:null,max:null};
+};
+Exhibit.SliderFacet._settingsSpecs={"facetLabel":{type:"text"},"scroll":{type:"boolean",defaultValue:true},"height":{type:"text"},"precision":{type:"float",defaultValue:1},"histogram":{type:"boolean",defaultValue:true},"height":{type:"int",defaultValue:false},"width":{type:"int",defaultValue:false},"horizontal":{type:"boolean",defaultValue:true},"inputText":{type:"boolean",defaultValue:true},"showMissing":{type:"boolean",defaultValue:true}};
+Exhibit.SliderFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.SliderFacet(containerElmt,uiContext);
+Exhibit.SliderFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.SliderFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.SliderFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.SliderFacet._settingsSpecs,facet._settings);
+try{var expressionString=Exhibit.getAttribute(configElmt,"expression");
+if(expressionString!=null&&expressionString.length>0){facet._expression=Exhibit.ExpressionParser.parse(expressionString);
+}var showMissing=Exhibit.getAttribute(configElmt,"showMissing");
+if(showMissing!=null&&showMissing.length>0){facet._showMissing=(showMissing=="true");
+}else{facet._showMissing=true;
+}}catch(e){SimileAjax.Debug.exception(e,"SliderFacet: Error processing configuration of slider facet");
+}Exhibit.SliderFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.SliderFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.SliderFacet._settingsSpecs,facet._settings);
+if("expression" in configuration){facet._expression=Exhibit.ExpressionParser.parse(configuration.expression);
+}if("selection" in configuration){var selection=configuration.selection;
+facet._selection={min:selection[0],max:selection[1]};
+}if("showMissing" in configuration){facet._showMissing=configuration.showMissing;
+}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="missing ex:facetLabel";
+if(facet._expression!=null&&facet._expression.isPath()){var segment=facet._expression.getPath().getLastSegment();
+var property=facet._uiContext.getDatabase().getProperty(segment.property);
+if(property!=null){facet._settings.facetLabel=segment.forward?property.getLabel():property.getReverseLabel();
+}}}facet._cache=new Exhibit.FacetUtilities.Cache(facet._uiContext.getDatabase(),facet._uiContext.getCollection(),facet._expression);
+facet._maxRange=facet._getMaxRange();
+};
+Exhibit.SliderFacet.prototype._initializeUI=function(){this._dom=SimileAjax.DOM.createDOMFromString(this._div,"<div class='exhibit-facet-header'><span class='exhibit-facet-header-title'>"+this._settings.facetLabel+"</span></div><div class='exhibit-slider' id='slider'></div>");
+this._slider=new Exhibit.SliderFacet.slider(this._dom.slider,this,this._settings.precision,this._settings.horizontal);
+};
+Exhibit.SliderFacet.prototype.hasRestrictions=function(){return(this._range.min&&this._range.min!=this._maxRange.min)||(this._range.max&&this._range.max!=this._maxRange.max);
+};
+Exhibit.SliderFacet.prototype.update=function(items){if(this._settings.histogram){var data=[];
+var n=75;
+var range=(this._maxRange.max-this._maxRange.min)/n;
+var missingCount=0;
+var database=this._uiContext.getDatabase();
+if(this._selectMissing){missingCount=this._cache.getItemsMissingValue(items).size();
+}if(this._expression.isPath()){var path=this._expression.getPath();
+for(var i=0;
+i<n;
+i++){data[i]=path.rangeBackward(this._maxRange.min+i*range,this._maxRange.min+(i+1)*range,false,items,database).values.size()+missingCount;
+}}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+for(var i=0;
+i<n;
+i++){data[i]=rangeIndex.getSubjectsInRange(this._maxRange.min+i*range,this._maxRange.min+(i+1)*range,false,null,items).size()+missingCount;
+}}this._slider.updateHistogram(data);
+}};
+Exhibit.SliderFacet.prototype.restrict=function(items){if(!this.hasRestrictions()){return items;
+}set=new Exhibit.Set();
+if(this._expression.isPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+set=path.rangeBackward(this._range.min,this._range.max,false,items,database).values;
+}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+set=rangeIndex.getSubjectsInRange(this._range.min,this._range.max,false,null,items);
+}if(this._showMissing){this._cache.getItemsMissingValue(items,set);
+}return set;
+};
+Exhibit.SliderFacet.prototype._getMaxRange=function(){if(this._expression.getPath()){var path=this._expression.getPath();
+var database=this._uiContext.getDatabase();
+var propertyID=path.getLastSegment().property;
+var property=database.getProperty(propertyID);
+var rangeIndex=property.getRangeIndex();
+}else{this._buildRangeIndex();
+var rangeIndex=this._rangeIndex;
+}return{min:rangeIndex.getMin(),max:rangeIndex.getMax()};
+};
+Exhibit.SliderFacet.prototype._buildRangeIndex=function(){if(!("_rangeIndex" in this)){var expression=this._expression;
+var database=this._uiContext.getDatabase();
+var getter=function(item,f){expression.evaluateOnItem(item,database).values.visit(function(value){if(typeof value!="number"){value=parseFloat(value);
+}if(!isNaN(value)){f(value);
+}});
+};
+this._rangeIndex=new Exhibit.Database._RangeIndex(this._uiContext.getCollection().getAllItems(),getter);
+}};
+Exhibit.SliderFacet.prototype.changeRange=function(range){this._range=range;
+this._notifyCollection();
+};
+Exhibit.SliderFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.SliderFacet.prototype.clearAllRestrictions=function(){this._slider.resetSliders();
+this._range=this._maxRange;
+};
+Exhibit.SliderFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext=null;
+this._colorCoder=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expression=null;
+this._settings=null;
+this._selection=null;
+this._range=null;
+this._maxRange=null;
+};
+
+
+/* slider.js */
+Exhibit.SliderFacet.slider=function(div,facet,precision){this._div=div;
+this._facet=facet;
+this._prec=precision||0.1;
+this._maxRange={min:parseFloat(Exhibit.Util.round(facet._maxRange.min-precision/2,this._prec)),max:parseFloat(Exhibit.Util.round(facet._maxRange.max+precision/2,this._prec))};
+this._horizontal=this._facet._settings.horizontal;
+this._scaleFactor=null;
+this._slider1={};
+this._slider2={};
+this._dom=SimileAjax.DOM.createDOMFromString(div,'<div class="exhibit-slider-bar" id="bar"><div id="slider1"></div><div id="slider2"></div>'+(this._facet._settings.histogram?'<div class="exhibit-slider-histogram" id="histogram"></div>':"")+'</div><div class="exhibit-slider-display">'+(this._facet._settings.inputText?'<input type="text" id="minDisplay"></input> - <input type="text" id="maxDisplay"></input> ':'<span id="minDisplay"></span> - <span id="maxDisplay"></span>')+"</div>");
+var horizontal=this._horizontal;
+var histogram=this._dom.histogram;
+if(horizontal&&histogram){this._dom.bar.style.height="14px";
+this._dom.bar.style.width="150px";
+}else{if(horizontal&&!histogram){this._dom.bar.style.height="1px";
+this._dom.bar.style.width="150px";
+}else{if(!horizontal&&histogram){this._dom.bar.style.height="150px";
+this._dom.bar.style.width="14px";
+}else{this._dom.bar.style.height="150px";
+this._dom.bar.style.width="1px";
+}}}if(this._facet._settings.height){this._dom.bar.style.height=this._facet._settings.height+"px";
+}if(this._facet._settings.width){this._dom.bar.style.width=this._facet._settings.width+"px";
+}if(histogram){this._dom.histogram.style.height=this._dom.bar.offsetHeight;
+this._dom.histogram.style.width=this._dom.bar.offsetWidth;
+}if(horizontal){this._scaleFactor=(this._maxRange.max-this._maxRange.min)/this._dom.bar.offsetWidth;
+}else{this._scaleFactor=(this._maxRange.max-this._maxRange.min)/this._dom.bar.offsetHeight;
+}this._slider1=new Exhibit.SliderFacet.slider.slider(this._dom.slider1,this);
+this._slider2=new Exhibit.SliderFacet.slider.slider(this._dom.slider2,this);
+this._setSlider(this._slider1,this._maxRange.min);
+this._setSlider(this._slider2,this._maxRange.max);
+this._registerDragging();
+if(this._facet._settings.inputText){this._registerInputs();
+}};
+Exhibit.SliderFacet.slider.prototype.resetSliders=function(){this._setSlider(this._slider1,this._maxRange.min);
+this._setSlider(this._slider2,this._maxRange.max);
+};
+Exhibit.SliderFacet.slider.prototype._setSlider=function(slider,value){if(value>this._maxRange.max){value=this._maxRange.max;
+}else{if(value<this._maxRange.min){value=this._maxRange.min;
+}}value=parseFloat(Exhibit.Util.round(value,this._prec));
+slider.value=value;
+if(this._horizontal){slider.div.style.left=((value-this._maxRange.min)/this._scaleFactor-slider.offset)+"px";
+}else{slider.div.style.top=((value-this._maxRange.min)/this._scaleFactor-slider.offset)+"px";
+}this._setDisplays(slider);
+};
+Exhibit.SliderFacet.slider.prototype._setMin=function(value){var slider=this._slider1.value<this._slider2.value?this._slider1:this._slider2;
+var other=(slider==this._slider1)?this._slider2:this._slider1;
+value=parseFloat(value);
+if(isNaN(value)){return ;
+}if(value>other.value){value=other.value;
+}this._setSlider(slider,value);
+};
+Exhibit.SliderFacet.slider.prototype._setMax=function(value){var slider=this._slider1.value>this._slider2.value?this._slider1:this._slider2;
+var other=(slider==this._slider1)?this._slider2:this._slider1;
+value=parseFloat(value);
+if(isNaN(value)){return ;
+}if(value<other.value){value=other.value;
+}this._setSlider(slider,value);
+};
+Exhibit.SliderFacet.slider.prototype._setDisplays=function(slider){var other=(slider==this._slider1)?this._slider2:this._slider1;
+var min=Math.min(slider.value,other.value);
+var max=Math.max(slider.value,other.value);
+if(this._facet._settings.inputText){this._dom.minDisplay.value=min;
+this._dom.maxDisplay.value=max;
+}else{this._dom.minDisplay.innerHTML=min;
+this._dom.maxDisplay.innerHTML=max;
+}};
+Exhibit.SliderFacet.slider.slider=function(div,self){var barEl=self._dom.bar;
+this.div=div;
+if(self._horizontal){this.div.className="exhibit-slider-handle";
+this.div.style.backgroundImage='url("'+Exhibit.urlPrefix+'images/slider-handle.png")';
+this.offset=this.div.offsetWidth/2;
+this.min=-this.offset;
+this.max=barEl.offsetWidth-this.offset;
+}else{this.div.className="exhibit-slider-handle2";
+this.div.style.backgroundImage='url("'+Exhibit.urlPrefix+'images/slider-handle2.png")';
+this.offset=this.div.offsetHeight/2;
+this.min=-this.offset;
+this.max=barEl.offsetHeight-this.offset;
+}if(self._facet._settings.histogram){this.div.style.top=(barEl.offsetHeight-4)+"px";
+}};
+Exhibit.SliderFacet.slider.prototype._registerDragging=function(){var self=this;
+var startDrag=function(slider){return function(e){e=e||window.event;
+var onMove=self._horizontal?onDragH(e,slider):onDragV(e,slider);
+if(document.attachEvent){document.attachEvent("onmousemove",onMove);
+document.attachEvent("onmouseup",endDrag(slider,onMove));
+}else{document.addEventListener("mousemove",onMove,false);
+document.addEventListener("mouseup",endDrag(slider,onMove),false);
+}SimileAjax.DOM.cancelEvent(e);
+return false;
+};
+};
+var onDragH=function(e,slider){var origX=e.screenX;
+var origLeft=parseInt(slider.div.style.left);
+var min=slider.min;
+var max=slider.max;
+return function(e){e=e||window.event;
+var dx=e.screenX-origX;
+var newLeft=origLeft+dx;
+if(newLeft<min){newLeft=min;
+}if(newLeft>max){newLeft=max;
+}slider.div.style.left=newLeft+"px";
+setTimeout(function(){var position=parseInt(slider.div.style.left)+slider.offset;
+slider.value=parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min,self._prec));
+self._setDisplays(slider);
+},0);
+};
+};
+var onDragV=function(e,slider){var origY=e.screenY;
+var origTop=parseInt(slider.div.style.top);
+var min=slider.min;
+var max=slider.max;
+return function(e){e=e||window.event;
+var dy=e.screenY-origY;
+var newTop=origTop+dy;
+if(newTop<min){newTop=min;
+}if(newTop>max){newTop=max;
+}slider.div.style.top=newTop+"px";
+setTimeout(function(){var position=parseInt(slider.div.style.top)+slider.offset;
+slider.value=parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min,self._prec));
+self._setDisplays(slider);
+},0);
+};
+};
+var endDrag=function(slider,moveListener){return function(e){if(document.detachEvent){document.detachEvent("onmousemove",moveListener);
+document.detachEvent("onmouseup",arguments.callee);
+}else{document.removeEventListener("mousemove",moveListener,false);
+document.removeEventListener("mouseup",arguments.callee,false);
+}self._notifyFacet();
+};
+};
+var attachListeners=function(slider){if(document.attachEvent){slider.div.attachEvent("onmousedown",startDrag(slider));
+}else{slider.div.addEventListener("mousedown",startDrag(slider),false);
+}};
+attachListeners(this._slider1);
+attachListeners(this._slider2);
+};
+Exhibit.SliderFacet.slider.prototype._notifyFacet=function(){var val1=this._slider1.value;
+var val2=this._slider2.value;
+this._facet.changeRange({min:Math.min(val1,val2),max:Math.max(val1,val2)});
+};
+Exhibit.SliderFacet.slider.prototype.updateHistogram=function(data){var n=data.length;
+var histogram=this._dom.histogram;
+var maxVal=Math.max.apply(Math,data);
+if(!maxVal){return ;
+}if(this._horizontal){var width=histogram.offsetWidth/n;
+var maxHeight=histogram.offsetHeight;
+var ratio=maxHeight/maxVal;
+histogram.innerHTML="";
+for(var i=0;
+i<n;
+i++){var height=Math.round(data[i]*ratio);
+var bar=document.createElement("div");
+histogram.appendChild(bar);
+bar.style.width=width+"px";
+bar.style.height=height+"px";
+bar.style.display=height?"":"none";
+bar.style.position="absolute";
+bar.style.top=(maxHeight-height)+"px";
+bar.style.left=i*width+"px";
+}}else{var width=histogram.offsetHeight/n;
+var maxHeight=histogram.offsetWidth;
+var ratio=maxHeight/maxVal;
+histogram.innerHTML="";
+for(var i=0;
+i<n;
+i++){var height=Math.round(data[i]*ratio);
+var bar=document.createElement("div");
+bar.style.height=width;
+bar.style.width=height;
+bar.style.position="absolute";
+bar.style.left=0;
+bar.style.top=i*width;
+histogram.appendChild(bar);
+}}};
+Exhibit.SliderFacet.slider.prototype._registerInputs=function(){var self=this;
+if(document.attachEvent){this._dom.minDisplay.attachEvent("onchange",function(e){self._setMin(this.value);
+self._notifyFacet();
+});
+this._dom.maxDisplay.attachEvent("onchange",function(e){self._setMax(this.value);
+self._notifyFacet();
+});
+}else{this._dom.minDisplay.addEventListener("change",function(e){self._setMin(this.value);
+self._notifyFacet();
+},false);
+this._dom.maxDisplay.addEventListener("change",function(e){self._setMax(this.value);
+self._notifyFacet();
+},false);
+}};
+
+
+/* text-search-facet.js */
+Exhibit.TextSearchFacet=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._expressions=[];
+this._text=null;
+this._settings={};
+this._dom=null;
+this._timerID=null;
+var self=this;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.TextSearchFacet._settingSpecs={"facetLabel":{type:"text"},"queryParamName":{type:"text"},"requiresEnter":{type:"boolean",defaultValue:false}};
+Exhibit.TextSearchFacet.create=function(configuration,containerElmt,uiContext){var uiContext=Exhibit.UIContext.create(configuration,uiContext);
+var facet=new Exhibit.TextSearchFacet(containerElmt,uiContext);
+Exhibit.TextSearchFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.TextSearchFacet.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var facet=new Exhibit.TextSearchFacet(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TextSearchFacet._settingSpecs,facet._settings);
+try{var s=Exhibit.getAttribute(configElmt,"expressions");
+if(s!=null&&s.length>0){facet._expressions=Exhibit.ExpressionParser.parseSeveral(s);
+}var query=Exhibit.getAttribute(configElmt,"query");
+if(query!=null&&query.length>0){facet._text=query;
+}}catch(e){SimileAjax.Debug.exception(e,"TextSearchFacet: Error processing configuration of list facet");
+}Exhibit.TextSearchFacet._configure(facet,configuration);
+facet._initializeUI();
+uiContext.getCollection().addFacet(facet);
+return facet;
+};
+Exhibit.TextSearchFacet._configure=function(facet,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TextSearchFacet._settingSpecs,facet._settings);
+if("expressions" in configuration){for(var i=0;
+i<configuration.expressions.length;
+i++){facet._expressions.push(Exhibit.ExpressionParser.parse(configuration.expressions[i]));
+}}if("selection" in configuration){var selection=configuration.selection;
+for(var i=0;
+i<selection.length;
+i++){facet._valueSet.add(selection[i]);
+}}if("query" in configuration){facet._text=configuration.query;
+}if("queryParamName" in facet._settings){var params=SimileAjax.parseURLParameters();
+if(facet._settings["queryParamName"] in params){facet._text=params[facet._settings["queryParamName"]];
+}}if(!("facetLabel" in facet._settings)){facet._settings.facetLabel="";
+}};
+Exhibit.TextSearchFacet.prototype.dispose=function(){this._uiContext.getCollection().removeFacet(this);
+this._uiContext.getCollection().removeListener(this._listener);
+this._uiContext=null;
+this._div.innerHTML="";
+this._div=null;
+this._dom=null;
+this._expressions=null;
+this._itemToValue=null;
+this._settings=null;
+};
+Exhibit.TextSearchFacet.prototype.hasRestrictions=function(){return this._text!=null;
+};
+Exhibit.TextSearchFacet.prototype.clearAllRestrictions=function(){var restrictions=this._text;
+if(this._text!=null){this._text=null;
+this._notifyCollection();
+}this._dom.input.value="";
+return restrictions;
+};
+Exhibit.TextSearchFacet.prototype.applyRestrictions=function(restrictions){this.setText(restrictions);
+};
+Exhibit.TextSearchFacet.prototype.setText=function(text){if(text!=null){text=text.trim();
+this._dom.input.value=text;
+text=text.length>0?text:null;
+}else{this._dom.input.value="";
+}if(text!=this._text){this._text=text;
+this._notifyCollection();
+}};
+Exhibit.TextSearchFacet.prototype.restrict=function(items){if(this._text==null){return items;
+}else{this._buildMaps();
+var set=new Exhibit.Set();
+var itemToValue=this._itemToValue;
+var text=this._text.toLowerCase();
+items.visit(function(item){if(item in itemToValue){var values=itemToValue[item];
+for(var v=0;
+v<values.length;
+v++){if(values[v].indexOf(text)>=0){set.add(item);
+break;
+}}}});
+return set;
+}};
+Exhibit.TextSearchFacet.prototype.update=function(items){};
+Exhibit.TextSearchFacet.prototype._notifyCollection=function(){this._uiContext.getCollection().onFacetUpdated(this);
+};
+Exhibit.TextSearchFacet.prototype._initializeUI=function(){var self=this;
+this._dom=Exhibit.TextSearchFacet.constructFacetFrame(this._div,this._settings.facetLabel);
+if(this._text!=null){this._dom.input.value=this._text;
+}SimileAjax.WindowManager.registerEvent(this._dom.input,"keyup",function(elmt,evt,target){self._onTextInputKeyUp(evt);
+});
+};
+Exhibit.TextSearchFacet.constructFacetFrame=function(div,facetLabel){if(facetLabel!==""&&facetLabel!==null){return SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-facet-header'><span class='exhibit-facet-header-title'>"+facetLabel+"</span></div><div class='exhibit-text-facet'><input type='text' id='input'></div>");
+}else{return SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-text-facet'><input type='text' id='input'></div>");
+}};
+Exhibit.TextSearchFacet.prototype._onTextInputKeyUp=function(evt){if(this._timerID!=null){window.clearTimeout(this._timerID);
+}var self=this;
+if(this._settings.requiresEnter==false){this._timerID=window.setTimeout(function(){self._onTimeout();
+},500);
+}else{var newText=this._dom.input.value.trim();
+if(newText.length==0||evt.keyCode==13){this._timerID=window.setTimeout(function(){self._onTimeout();
+},0);
+}}};
+Exhibit.TextSearchFacet.prototype._onTimeout=function(){this._timerID=null;
+var newText=this._dom.input.value.trim();
+if(newText.length==0){newText=null;
+}if(newText!=this._text){var self=this;
+var oldText=this._text;
+SimileAjax.History.addLengthyAction(function(){self.setText(newText);
+},function(){self.setText(oldText);
+},newText!=null?String.substitute(Exhibit.FacetUtilities.l10n["facetTextSearchActionTitle"],[newText]):Exhibit.FacetUtilities.l10n["facetClearTextSearchActionTitle"]);
+}};
+Exhibit.TextSearchFacet.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var allItems=this._uiContext.getCollection().getAllItems();
+var database=this._uiContext.getDatabase();
+if(this._expressions.length>0){var expressions=this._expressions;
+allItems.visit(function(item){var values=[];
+for(var x=0;
+x<expressions.length;
+x++){var expression=expressions[x];
+expression.evaluateOnItem(item,database).values.visit(function(v){values.push(v.toLowerCase());
+});
+}itemToValue[item]=values;
+});
+}else{var propertyIDs=database.getAllProperties();
+allItems.visit(function(item){var values=[];
+for(var p=0;
+p<propertyIDs.length;
+p++){database.getObjects(item,propertyIDs[p]).visit(function(v){values.push(v.toLowerCase());
+});
+}itemToValue[item]=values;
+});
+}this._itemToValue=itemToValue;
+}};
+Exhibit.TextSearchFacet.prototype.exportFacetSelection=function(){return this._text;
+};
+Exhibit.TextSearchFacet.prototype.importFacetSelection=function(settings){this.setText(settings);
+};
+
+
+/* format-parser.js */
+Exhibit.FormatParser=new Object();
+Exhibit.FormatParser.parse=function(uiContext,s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.FormatScanner(s,startIndex);
+try{return Exhibit.FormatParser._internalParse(uiContext,scanner,results,false);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.FormatParser.parseSeveral=function(uiContext,s,startIndex,results){startIndex=startIndex||0;
+results=results||{};
+var scanner=new Exhibit.FormatScanner(s,startIndex);
+try{return Exhibit.FormatParser._internalParse(uiContext,scanner,results,true);
+}finally{results.index=scanner.token()!=null?scanner.token().start:scanner.index();
+}};
+Exhibit.FormatParser._valueTypes={"list":true,"number":true,"date":true,"item":true,"text":true,"url":true,"image":true,"currency":true};
+Exhibit.FormatParser._internalParse=function(uiContext,scanner,results,several){var Scanner=Exhibit.FormatScanner;
+var token=scanner.token();
+var next=function(){scanner.next();
+token=scanner.token();
+};
+var makePosition=function(){return token!=null?token.start:scanner.index();
+};
+var enterSetting=function(valueType,settingName,value){uiContext.putSetting("format/"+valueType+"/"+settingName,value);
+};
+var checkKeywords=function(valueType,settingName,keywords){if(token!=null&&token.type!=Scanner.IDENTIFIER&&token.value in keywords){enterSetting(valueType,settingName,keywords[token.value]);
+next();
+return false;
+}return true;
+};
+var parseNumber=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER){throw new Error("Missing number at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseInteger=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER){throw new Error("Missing integer at position "+makePosition());
+}enterSetting(valueType,settingName,Math.round(token.value));
+next();
+}};
+var parseNonnegativeInteger=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.NUMBER||token.value<0){throw new Error("Missing non-negative integer at position "+makePosition());
+}enterSetting(valueType,settingName,Math.round(token.value));
+next();
+}};
+var parseString=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.STRING){throw new Error("Missing string at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseURL=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.URL){throw new Error("Missing url at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseExpression=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||token.type!=Scanner.EXPRESSION){throw new Error("Missing expression at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseExpressionOrString=function(valueType,settingName,keywords){if(checkKeywords(valueType,settingName,keywords)){if(token==null||(token.type!=Scanner.EXPRESSION&&token.type!=Scanner.STRING)){throw new Error("Missing expression or string at position "+makePosition());
+}enterSetting(valueType,settingName,token.value);
+next();
+}};
+var parseChoices=function(valueType,settingName,choices){if(token==null||token.type!=Scanner.IDENTIFIER){throw new Error("Missing option at position "+makePosition());
+}for(var i=0;
+i<choices.length;
+i++){if(token.value==choices[i]){enterSetting(valueType,settingName,token.value);
+next();
+return ;
+}}throw new Error("Unsupported option "+token.value+" for setting "+settingName+" on value type "+valueType+" found at position "+makePosition());
+};
+var parseFlags=function(valueType,settingName,flags,counterFlags){outer:while(token!=null&&token.type==Scanner.IDENTIFIER){for(var i=0;
+i<flags.length;
+i++){if(token.value==flags[i]){enterSetting(valueType,settingName+"/"+token.value,true);
+next();
+continue outer;
+}}if(token.value in counterFlags){enterSetting(valueType,settingName+"/"+counterFlags[token.value],false);
+next();
+continue outer;
+}throw new Error("Unsupported flag "+token.value+" for setting "+settingName+" on value type "+valueType+" found at position "+makePosition());
+}};
+var parseSetting=function(valueType,settingName){switch(valueType){case"number":switch(settingName){case"decimal-digits":parseNonnegativeInteger(valueType,settingName,{"default":-1});
+return ;
+}break;
+case"date":switch(settingName){case"time-zone":parseNumber(valueType,settingName,{"default":null});
+return ;
+case"show":parseChoices(valueType,settingName,["date","time","date-time"]);
+return ;
+case"mode":parseChoices(valueType,settingName,["short","medium","long","full"]);
+enterSetting(valueType,"template",null);
+return ;
+case"template":parseString(valueType,settingName,{});
+enterSetting(valueType,"mode",null);
+return ;
+}break;
+case"boolean":switch(settingName){}break;
+case"text":switch(settingName){case"max-length":parseInteger(valueType,settingName,{"none":0});
+return ;
+}break;
+case"image":switch(settingName){case"tooltip":parseExpressionOrString(valueType,settingName,{"none":null});
+return ;
+case"max-width":case"max-height":parseInteger(valueType,settingName,{"none":-1});
+return ;
+}break;
+case"url":switch(settingName){case"target":parseString(valueType,settingName,{"none":null});
+return ;
+case"external-icon":parseURL(valueType,settingName,{"none":null});
+return ;
+}break;
+case"item":switch(settingName){case"title":parseExpression(valueType,settingName,{"default":null});
+return ;
+}break;
+case"currency":switch(settingName){case"negative-format":parseFlags(valueType,settingName,["red","parentheses","signed"],{"unsigned":"signed","no-parenthesis":"parentheses","black":"red"});
+return ;
+case"symbol":parseString(valueType,settingName,{"default":"$","none":null});
+return ;
+case"symbol-placement":parseChoices(valueType,settingName,["first","last","after-sign"]);
+return ;
+case"decimal-digits":parseNonnegativeInteger(valueType,settingName,{"default":-1});
+return ;
+}break;
+case"list":switch(settingName){case"separator":case"last-separator":case"pair-separator":case"empty-text":parseString(valueType,settingName,{});
+return ;
+}break;
+}throw new Error("Unsupported setting called "+settingName+" for value type "+valueType+" found at position "+makePosition());
+};
+var parseSettingList=function(valueType){while(token!=null&&token.type==Scanner.IDENTIFIER){var settingName=token.value;
+next();
+if(token==null||token.type!=Scanner.DELIMITER||token.value!=":"){throw new Error("Missing : at position "+makePosition());
+}next();
+parseSetting(valueType,settingName);
+if(token==null||token.type!=Scanner.DELIMITER||token.value!=";"){break;
+}else{next();
+}}};
+var parseRule=function(){if(token==null||token.type!=Scanner.IDENTIFIER){throw new Error("Missing value type at position "+makePosition());
+}var valueType=token.value;
+if(!(valueType in Exhibit.FormatParser._valueTypes)){throw new Error("Unsupported value type "+valueType+" at position "+makePosition());
+}next();
+if(token!=null&&token.type==Scanner.DELIMITER&&token.value=="{"){next();
+parseSettingList(valueType);
+if(token==null||token.type!=Scanner.DELIMITER||token.value!="}"){throw new Error("Missing } at position "+makePosition());
+}next();
+}return valueType;
+};
+var parseRuleList=function(){var valueType="text";
+while(token!=null&&token.type==Scanner.IDENTIFIER){valueType=parseRule();
+}return valueType;
+};
+if(several){return parseRuleList();
+}else{return parseRule();
+}};
+Exhibit.FormatScanner=function(text,startIndex){this._text=text+" ";
+this._maxIndex=text.length;
+this._index=startIndex;
+this.next();
+};
+Exhibit.FormatScanner.DELIMITER=0;
+Exhibit.FormatScanner.NUMBER=1;
+Exhibit.FormatScanner.STRING=2;
+Exhibit.FormatScanner.IDENTIFIER=3;
+Exhibit.FormatScanner.URL=4;
+Exhibit.FormatScanner.EXPRESSION=5;
+Exhibit.FormatScanner.COLOR=6;
+Exhibit.FormatScanner.prototype.token=function(){return this._token;
+};
+Exhibit.FormatScanner.prototype.index=function(){return this._index;
+};
+Exhibit.FormatScanner.prototype.next=function(){this._token=null;
+var self=this;
+var skipSpaces=function(x){while(x<self._maxIndex&&" \t\r\n".indexOf(self._text.charAt(x))>=0){x++;
+}return x;
+};
+this._index=skipSpaces(this._index);
+if(this._index<this._maxIndex){var c1=this._text.charAt(this._index);
+var c2=this._text.charAt(this._index+1);
+if("{}(),:;".indexOf(c1)>=0){this._token={type:Exhibit.FormatScanner.DELIMITER,value:c1,start:this._index,end:this._index+1};
+this._index++;
+}else{if("\"'".indexOf(c1)>=0){var i=this._index+1;
+while(i<this._maxIndex){if(this._text.charAt(i)==c1&&this._text.charAt(i-1)!="\\"){break;
+}i++;
+}if(i<this._maxIndex){this._token={type:Exhibit.FormatScanner.STRING,value:this._text.substring(this._index+1,i).replace(/\\'/g,"'").replace(/\\"/g,'"'),start:this._index,end:i+1};
+this._index=i+1;
+}else{throw new Error("Unterminated string starting at "+this._index);
+}}else{if(c1=="#"){var i=this._index+1;
+while(i<this._maxIndex&&this._isHexDigit(this._text.charAt(i))){i++;
+}this._token={type:Exhibit.FormatScanner.COLOR,value:this._text.substring(this._index,i),start:this._index,end:i};
+this._index=i;
+}else{if(this._isDigit(c1)){var i=this._index;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}if(i<this._maxIndex&&this._text.charAt(i)=="."){i++;
+while(i<this._maxIndex&&this._isDigit(this._text.charAt(i))){i++;
+}}this._token={type:Exhibit.FormatScanner.NUMBER,value:parseFloat(this._text.substring(this._index,i)),start:this._index,end:i};
+this._index=i;
+}else{var i=this._index;
+while(i<this._maxIndex){var j=this._text.substr(i).search(/\W/);
+if(j>0){i+=j;
+}else{if("-".indexOf(this._text.charAt(i))>=0){i++;
+}else{break;
+}}}var identifier=this._text.substring(this._index,i);
+while(true){if(identifier=="url"){var openParen=skipSpaces(i);
+if(this._text.charAt(openParen)=="("){var closeParen=this._text.indexOf(")",openParen);
+if(closeParen>0){this._token={type:Exhibit.FormatScanner.URL,value:this._text.substring(openParen+1,closeParen),start:this._index,end:closeParen+1};
+this._index=closeParen+1;
+break;
+}else{throw new Error("Missing ) to close url at "+this._index);
+}}}else{if(identifier=="expression"){var openParen=skipSpaces(i);
+if(this._text.charAt(openParen)=="("){var o={};
+var expression=Exhibit.ExpressionParser.parse(this._text,openParen+1,o);
+var closeParen=skipSpaces(o.index);
+if(this._text.charAt(closeParen)==")"){this._token={type:Exhibit.FormatScanner.EXPRESSION,value:expression,start:this._index,end:closeParen+1};
+this._index=closeParen+1;
+break;
+}else{throw new Error("Missing ) to close expression at "+o.index);
+}}}}this._token={type:Exhibit.FormatScanner.IDENTIFIER,value:identifier,start:this._index,end:i};
+this._index=i;
+break;
+}}}}}}};
+Exhibit.FormatScanner.prototype._isDigit=function(c){return"0123456789".indexOf(c)>=0;
+};
+Exhibit.FormatScanner.prototype._isHexDigit=function(c){return"0123456789abcdefABCDEF".indexOf(c)>=0;
+};
+
+
+/* formatter.js */
+Exhibit.Formatter=new Object();
+Exhibit.Formatter.createListDelimiter=function(parentElmt,count,uiContext){var separator=uiContext.getSetting("format/list/separator");
+var lastSeparator=uiContext.getSetting("format/list/last-separator");
+var pairSeparator=uiContext.getSetting("format/list/pair-separator");
+if(typeof separator!="string"){separator=Exhibit.Formatter.l10n.listSeparator;
+}if(typeof lastSeparator!="string"){lastSeparator=Exhibit.Formatter.l10n.listLastSeparator;
+}if(typeof pairSeparator!="string"){pairSeparator=Exhibit.Formatter.l10n.listPairSeparator;
+}var f=function(){if(f.index>0&&f.index<count){if(count>2){parentElmt.appendChild(document.createTextNode((f.index==count-1)?lastSeparator:separator));
+}else{parentElmt.appendChild(document.createTextNode(pairSeparator));
+}}f.index++;
+};
+f.index=0;
+return f;
+};
+Exhibit.Formatter._lessThanRegex=/</g;
+Exhibit.Formatter._greaterThanRegex=/>/g;
+Exhibit.Formatter.encodeAngleBrackets=function(s){return s.replace(Exhibit.Formatter._lessThanRegex,"&lt;").replace(Exhibit.Formatter._greaterThanRegex,"&gt;");
+};
+Exhibit.Formatter._ListFormatter=function(uiContext){this._uiContext=uiContext;
+this._separator=uiContext.getSetting("format/list/separator");
+this._lastSeparator=uiContext.getSetting("format/list/last-separator");
+this._pairSeparator=uiContext.getSetting("format/list/pair-separator");
+this._emptyText=uiContext.getSetting("format/list/empty-text");
+if(typeof this._separator!="string"){this._separator=Exhibit.Formatter.l10n.listSeparator;
+}if(typeof this._lastSeparator!="string"){this._lastSeparator=Exhibit.Formatter.l10n.listLastSeparator;
+}if(typeof this._pairSeparator!="string"){this._pairSeparator=Exhibit.Formatter.l10n.listPairSeparator;
+}};
+Exhibit.Formatter._ListFormatter.prototype.formatList=function(values,count,valueType,appender){var uiContext=this._uiContext;
+var self=this;
+if(count==0){if(this._emptyText!=null&&this._emptyText.length>0){appender(document.createTextNode(this._emptyText));
+}}else{if(count==1){values.visit(function(v){uiContext.format(v,valueType,appender);
+});
+}else{var index=0;
+if(count==2){values.visit(function(v){uiContext.format(v,valueType,appender);
+index++;
+if(index==1){appender(document.createTextNode(self._pairSeparator));
+}});
+}else{values.visit(function(v){uiContext.format(v,valueType,appender);
+index++;
+if(index<count){appender(document.createTextNode((index==count-1)?self._lastSeparator:self._separator));
+}});
+}}}};
+Exhibit.Formatter._TextFormatter=function(uiContext){this._maxLength=uiContext.getSetting("format/text/max-length");
+if(typeof this._maxLength=="number"){this._maxLength=Math.max(3,Math.round(this._maxLength));
+}else{this._maxLength=0;
+}};
+Exhibit.Formatter._TextFormatter.prototype.format=function(value,appender){var span=document.createElement("span");
+span.innerHTML=this.formatText(value);
+appender(span);
+};
+Exhibit.Formatter._TextFormatter.prototype.formatText=function(value){if(Exhibit.params.safe){value=Exhibit.Formatter.encodeAngleBrackets(value);
+}if(this._maxLength==0||value.length<=this._maxLength){return value;
+}else{return value.substr(0,this._maxLength)+Exhibit.Formatter.l10n.textEllipsis;
+}};
+Exhibit.Formatter._BooleanFormatter=function(uiContext){};
+Exhibit.Formatter._BooleanFormatter.prototype.format=function(value,appender){var span=document.createElement("span");
+span.innerHTML=this.formatText(value);
+appender(span);
+};
+Exhibit.Formatter._BooleanFormatter.prototype.formatText=function(value){return(typeof value=="boolean"?value:(typeof value=="string"?(value=="true"):false))?Exhibit.Formatter.l10n.booleanTrue:Exhibit.Formatter.l10n.booleanFalse;
+};
+Exhibit.Formatter._NumberFormatter=function(uiContext){this._decimalDigits=uiContext.getSetting("format/number/decimal-digits");
+if(typeof this._decimalDigits=="number"){this._decimalDigits=Math.max(-1,Math.round(this._decimalDigits));
+}else{this._decimalDigits=-1;
+}};
+Exhibit.Formatter._NumberFormatter.prototype.format=function(value,appender){appender(document.createTextNode(this.formatText(value)));
+};
+Exhibit.Formatter._NumberFormatter.prototype.formatText=function(value){if(this._decimalDigits==-1){return value.toString();
+}else{return new Number(value).toFixed(this._decimalDigits);
+}};
+Exhibit.Formatter._ImageFormatter=function(uiContext){this._uiContext=uiContext;
+this._maxWidth=uiContext.getSetting("format/image/max-width");
+if(typeof this._maxWidth=="number"){this._maxWidth=Math.max(-1,Math.round(this._maxWidth));
+}else{this._maxWidth=-1;
+}this._maxHeight=uiContext.getSetting("format/image/max-height");
+if(typeof this._maxHeight=="number"){this._maxHeight=Math.max(-1,Math.round(this._maxHeight));
+}else{this._maxHeight=-1;
+}this._tooltip=uiContext.getSetting("format/image/tooltip");
+};
+Exhibit.Formatter._ImageFormatter.prototype.format=function(value,appender){if(Exhibit.params.safe){value=value.trim().startsWith("javascript:")?"":value;
+}var img=document.createElement("img");
+img.src=value;
+if(this._tooltip!=null){if(typeof this._tooltip=="string"){img.title=this._tootlip;
+}else{img.title=this._tooltip.evaluateSingleOnItem(this._uiContext.getSetting("itemID"),this._uiContext.getDatabase()).value;
+}}appender(img);
+};
+Exhibit.Formatter._ImageFormatter.prototype.formatText=function(value){return value;
+};
+Exhibit.Formatter._URLFormatter=function(uiContext){this._target=uiContext.getSetting("format/url/target");
+this._externalIcon=uiContext.getSetting("format/url/external-icon");
+};
+Exhibit.Formatter._URLFormatter.prototype.format=function(value,appender){var a=document.createElement("a");
+a.href=value;
+a.innerHTML=value;
+if(this._target!=null){a.target=this._target;
+}if(this._externalIcon!=null){}appender(a);
+};
+Exhibit.Formatter._URLFormatter.prototype.formatText=function(value){if(Exhibit.params.safe){value=value.trim().startsWith("javascript:")?"":value;
+}return value;
+};
+Exhibit.Formatter._CurrencyFormatter=function(uiContext){this._decimalDigits=uiContext.getSetting("format/currency/decimal-digits");
+if(typeof this._decimalDigits=="number"){this._decimalDigits=Math.max(-1,Math.round(this._decimalDigits));
+}else{this._decimalDigits=2;
+}this._symbol=uiContext.getSetting("format/currency/symbol");
+if(this._symbol==null){this._symbol=Exhibit.Formatter.l10n.currencySymbol;
+}this._symbolPlacement=uiContext.getSetting("format/currency/symbol-placement");
+if(this._symbolPlacement==null){this._symbol=Exhibit.Formatter.l10n.currencySymbolPlacement;
+}this._negativeFormat={signed:uiContext.getBooleanSetting("format/currency/negative-format/signed",Exhibit.Formatter.l10n.currencyShowSign),red:uiContext.getBooleanSetting("format/currency/negative-format/red",Exhibit.Formatter.l10n.currencyShowRed),parentheses:uiContext.getBooleanSetting("format/currency/negative-format/parentheses",Exhibit.Formatter.l10n.currencyShowParentheses)};
+};
+Exhibit.Formatter._CurrencyFormatter.prototype.format=function(value,appender){var text=this.formatText(value);
+if(value<0&&this._negativeFormat.red){var span=document.createElement("span");
+span.innerHTML=text;
+span.style.color="red";
+appender(span);
+}else{appender(document.createTextNode(text));
+}};
+Exhibit.Formatter._CurrencyFormatter.prototype.formatText=function(value){var negative=value<0;
+var text;
+if(this._decimalDigits==-1){text=Math.abs(value);
+}else{text=new Number(Math.abs(value)).toFixed(this._decimalDigits);
+}var sign=(negative&&this._negativeFormat.signed)?"-":"";
+if(negative&&this._negativeFormat.parentheses){text="("+text+")";
+}switch(this._negativeFormat){case"first":text=this._symbol+sign+text;
+break;
+case"after-sign":text=sign+this._symbol+text;
+break;
+case"last":text=sign+text+this._symbol;
+break;
+}return text;
+};
+Exhibit.Formatter._ItemFormatter=function(uiContext){this._uiContext=uiContext;
+this._title=uiContext.getSetting("format/item/title");
+};
+Exhibit.Formatter._ItemFormatter.prototype.format=function(value,appender){var self=this;
+var title=this.formatText(value);
+var a=SimileAjax.DOM.createElementFromString('<a href="'+Exhibit.Persistence.getItemLink(value)+"\" class='exhibit-item'>"+title+"</a>");
+var handler=function(elmt,evt,target){Exhibit.UI.showItemInPopup(value,elmt,self._uiContext);
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler,this._uiContext.getSetting("layer"));
+appender(a);
+};
+Exhibit.Formatter._ItemFormatter.prototype.formatText=function(value){var database=this._uiContext.getDatabase();
+var title=null;
+if(this._title==null){title=database.getObject(value,"label");
+}else{title=this._title.evaluateSingleOnItem(value,database).value;
+}if(title==null){title=value;
+}return title;
+};
+Exhibit.Formatter._DateFormatter=function(uiContext){this._timeZone=uiContext.getSetting("format/date/time-zone");
+if(!(typeof this._timeZone=="number")){this._timeZone=-(new Date().getTimezoneOffset())/60;
+}this._timeZoneOffset=this._timeZone*3600000;
+var mode=uiContext.getSetting("format/date/mode");
+var show=uiContext.getSetting("format/date/show");
+var template=null;
+switch(mode){case"short":template=show=="date"?Exhibit.Formatter.l10n.dateShortFormat:(show=="time"?Exhibit.Formatter.l10n.timeShortFormat:Exhibit.Formatter.l10n.dateTimeShortFormat);
+break;
+case"medium":template=show=="date"?Exhibit.Formatter.l10n.dateMediumFormat:(show=="time"?Exhibit.Formatter.l10n.timeMediumFormat:Exhibit.Formatter.l10n.dateTimeMediumFormat);
+break;
+case"long":template=show=="date"?Exhibit.Formatter.l10n.dateLongFormat:(show=="time"?Exhibit.Formatter.l10n.timeLongFormat:Exhibit.Formatter.l10n.dateTimeLongFormat);
+break;
+case"full":template=show=="date"?Exhibit.Formatter.l10n.dateFullFormat:(show=="time"?Exhibit.Formatter.l10n.timeFullFormat:Exhibit.Formatter.l10n.dateTimeFullFormat);
+break;
+default:template=uiContext.getSetting("format/date/template");
+}if(typeof template!="string"){template=Exhibit.Formatter.l10n.dateTimeDefaultFormat;
+}var segments=[];
+var placeholders=template.match(/\b\w+\b/g);
+var startIndex=0;
+for(var p=0;
+p<placeholders.length;
+p++){var placeholder=placeholders[p];
+var index=template.indexOf(placeholder,startIndex);
+if(index>startIndex){segments.push(template.substring(startIndex,index));
+}var retriever=Exhibit.Formatter._DateFormatter._retrievers[placeholder];
+if(typeof retriever=="function"){segments.push(retriever);
+}else{segments.push(placeholder);
+}startIndex=index+placeholder.length;
+}if(startIndex<template.length){segments.push(template.substr(startIndex));
+}this._segments=segments;
+};
+Exhibit.Formatter._DateFormatter.prototype.format=function(value,appender){appender(document.createTextNode(this.formatText(value)));
+};
+Exhibit.Formatter._DateFormatter.prototype.formatText=function(value){var date=(value instanceof Date)?value:SimileAjax.DateTime.parseIso8601DateTime(value);
+if(date==null){return value;
+}date.setTime(date.getTime()+this._timeZoneOffset);
+var text="";
+var segments=this._segments;
+for(var i=0;
+i<segments.length;
+i++){var segment=segments[i];
+if(typeof segment=="string"){text+=segment;
+}else{text+=segment(date);
+}}return text;
+};
+Exhibit.Formatter._DateFormatter._pad=function(n){return n<10?("0"+n):n.toString();
+};
+Exhibit.Formatter._DateFormatter._pad3=function(n){return n<10?("00"+n):(n<100?("0"+n):n.toString());
+};
+Exhibit.Formatter._DateFormatter._retrievers={"d":function(date){return date.getUTCDate().toString();
+},"dd":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCDate());
+},"EEE":function(date){return Exhibit.Formatter.l10n.shortDaysOfWeek[date.getUTCDay()];
+},"EEEE":function(date){return Exhibit.Formatter.l10n.daysOfWeek[date.getUTCDay()];
+},"MM":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCMonth()+1);
+},"MMM":function(date){return Exhibit.Formatter.l10n.shortMonths[date.getUTCMonth()];
+},"MMMM":function(date){return Exhibit.Formatter.l10n.months[date.getUTCMonth()];
+},"yy":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCFullYear()%100);
+},"yyyy":function(date){var y=date.getUTCFullYear();
+return y>0?y.toString():(1-y);
+},"G":function(date){var y=date.getUTCYear();
+return y>0?Exhibit.Formatter.l10n.commonEra:Exhibit.Formatter.l10n.beforeCommonEra;
+},"HH":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCHours());
+},"hh":function(date){var h=date.getUTCHours();
+return Exhibit.Formatter._DateFormatter._pad(h==0?12:(h>12?h-12:h));
+},"h":function(date){var h=date.getUTCHours();
+return(h==0?12:(h>12?h-12:h)).toString();
+},"a":function(date){return date.getUTCHours()<12?Exhibit.Formatter.l10n.beforeNoon:Exhibit.Formatter.l10n.afterNoon;
+},"A":function(date){return date.getUTCHours()<12?Exhibit.Formatter.l10n.BeforeNoon:Exhibit.Formatter.l10n.AfterNoon;
+},"mm":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCMinutes());
+},"ss":function(date){return Exhibit.Formatter._DateFormatter._pad(date.getUTCSeconds());
+},"S":function(date){return Exhibit.Formatter._DateFormatter._pad3(date.getUTCMilliseconds());
+}};
+Exhibit.Formatter._constructors={"number":Exhibit.Formatter._NumberFormatter,"date":Exhibit.Formatter._DateFormatter,"text":Exhibit.Formatter._TextFormatter,"boolean":Exhibit.Formatter._BooleanFormatter,"image":Exhibit.Formatter._ImageFormatter,"url":Exhibit.Formatter._URLFormatter,"item":Exhibit.Formatter._ItemFormatter,"currency":Exhibit.Formatter._CurrencyFormatter};
+
+
+/* lens.js */
+Exhibit.LensRegistry=function(parentRegistry){this._parentRegistry=parentRegistry;
+this._defaultLens=null;
+this._typeToLens={};
+this._editLensTemplates={};
+this._submissionLensTemplates={};
+this._lensSelectors=[];
+};
+Exhibit.LensRegistry.prototype.registerDefaultLens=function(elmtOrURL){this._defaultLens=(typeof elmtOrURL=="string")?elmtOrURL:elmtOrURL.cloneNode(true);
+};
+Exhibit.LensRegistry.prototype.registerLensForType=function(elmtOrURL,type){if(typeof elmtOrURL=="string"){this._typeToLens[type]=elmtOrURL;
+}var role=Exhibit.getRoleAttribute(elmtOrURL);
+if(role=="lens"){this._typeToLens[type]=elmtOrURL.cloneNode(true);
+}else{if(role=="edit-lens"){this._editLensTemplates[type]=elmtOrURL.cloneNode(true);
+}else{if(role=="submission-lens"){this._submissionLensTemplates[type]=elmtOrURL.cloneNode(true);
+}else{SimileAjax.Debug.warn("Unknown lens type "+elmtOrURL);
+}}}};
+Exhibit.LensRegistry.prototype.addLensSelector=function(lensSelector){this._lensSelectors.unshift(lensSelector);
+};
+Exhibit.LensRegistry.prototype.getLens=function(itemID,uiContext){return uiContext.isBeingEdited(itemID)?this.getEditLens(itemID,uiContext):this.getNormalLens(itemID,uiContext);
+};
+Exhibit.LensRegistry.prototype.getNormalLens=function(itemID,uiContext){var db=uiContext.getDatabase();
+for(var i=0;
+i<this._lensSelectors.length;
+i++){var lens=this._lensSelectors[i](itemID,db);
+if(lens!=null){return lens;
+}}var type=db.getObject(itemID,"type");
+if(type in this._typeToLens){return this._typeToLens[type];
+}if(this._defaultLens!=null){return this._defaultLens;
+}if(this._parentRegistry){return this._parentRegistry.getLens(itemID,uiContext);
+}return null;
+};
+Exhibit.LensRegistry.prototype.getEditLens=function(itemID,uiContext){var type=uiContext.getDatabase().getObject(itemID,"type");
+if(type in this._editLensTemplates){return this._editLensTemplates[type];
+}else{return this._parentRegistry&&this._parentRegistry.getEditLens(itemID,uiContext);
+}};
+Exhibit.LensRegistry.prototype.createLens=function(itemID,div,uiContext,opts){var lens=new Exhibit.Lens();
+if(uiContext.getDatabase().isNewItem(itemID)){SimileAjax.jQuery(div).addClass("newItem");
+}opts=opts||{};
+var lensTemplate=opts.lensTemplate||this.getLens(itemID,uiContext);
+if(lensTemplate==null){lens._constructDefaultUI(itemID,div,uiContext);
+}else{if(typeof lensTemplate=="string"){lens._constructFromLensTemplateURL(itemID,div,uiContext,lensTemplate,opts);
+}else{lens._constructFromLensTemplateDOM(itemID,div,uiContext,lensTemplate,opts);
+}}return lens;
+};
+Exhibit.LensRegistry.prototype.createEditLens=function(itemID,div,uiContext,opts){opts=opts||{};
+opts.lensTemplate=this.getEditLens(itemID,uiContext);
+return this.createLens(itemID,div,uiContext,opts);
+};
+Exhibit.LensRegistry.prototype.createNormalLens=function(itemID,div,uiContext,opts){opts=opts||{};
+opts.lensTemplate=this.getNormalLens(itemID,uiContext);
+return this.createLens(itemID,div,uiContext,opts);
+};
+Exhibit.Lens=function(){};
+Exhibit.Lens._commonProperties=null;
+Exhibit.Lens.prototype._constructDefaultUI=function(itemID,div,uiContext){var database=uiContext.getDatabase();
+if(Exhibit.Lens._commonProperties==null){Exhibit.Lens._commonProperties=database.getAllProperties();
+}var properties=Exhibit.Lens._commonProperties;
+var label=database.getObject(itemID,"label");
+label=label!=null?label:itemID;
+if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var template={elmt:div,className:"exhibit-lens",children:[{tag:"div",className:"exhibit-lens-title",title:label,children:[label+" (",{tag:"a",href:Exhibit.Persistence.getItemLink(itemID),target:"_blank",children:[Exhibit.l10n.itemLinkLabel]},")"]},{tag:"div",className:"exhibit-lens-body",children:[{tag:"table",className:"exhibit-lens-properties",field:"propertiesTable"}]}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+div.setAttribute("ex:itemID",itemID);
+var pairs=Exhibit.ViewPanel.getPropertyValuesPairs(itemID,properties,database);
+for(var j=0;
+j<pairs.length;
+j++){var pair=pairs[j];
+var tr=dom.propertiesTable.insertRow(j);
+tr.className="exhibit-lens-property";
+var tdName=tr.insertCell(0);
+tdName.className="exhibit-lens-property-name";
+tdName.innerHTML=pair.propertyLabel+": ";
+var tdValues=tr.insertCell(1);
+tdValues.className="exhibit-lens-property-values";
+if(pair.valueType=="item"){for(var m=0;
+m<pair.values.length;
+m++){if(m>0){tdValues.appendChild(document.createTextNode(", "));
+}tdValues.appendChild(Exhibit.UI.makeItemSpan(pair.values[m],null,uiContext));
+}}else{for(var m=0;
+m<pair.values.length;
+m++){if(m>0){tdValues.appendChild(document.createTextNode(", "));
+}tdValues.appendChild(Exhibit.UI.makeValueSpan(pair.values[m],pair.valueType));
+}}}};
+Exhibit.Lens.prototype._constructDefaultEditingUI=function(itemID,div,uiContext){};
+Exhibit.Lens._compiledTemplates={};
+Exhibit.Lens._handlers=["onblur","onfocus","onkeydown","onkeypress","onkeyup","onmousedown","onmouseenter","onmouseleave","onmousemove","onmouseout","onmouseover","onmouseup","onclick","onresize","onscroll"];
+Exhibit.Lens.prototype._constructFromLensTemplateURL=function(itemID,div,uiContext,lensTemplateURL){var job={lens:this,itemID:itemID,div:div,uiContext:uiContext,opts:opts};
+var compiledTemplate=Exhibit.Lens._compiledTemplates[lensTemplateURL];
+if(compiledTemplate==null){Exhibit.Lens._startCompilingTemplate(lensTemplateURL,job);
+}else{if(!compiledTemplate.compiled){compiledTemplate.jobs.push(job);
+}else{job.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job);
+}}};
+Exhibit.Lens.prototype._constructFromLensTemplateDOM=function(itemID,div,uiContext,lensTemplateNode,opts){var job={lens:this,itemID:itemID,div:div,uiContext:uiContext,opts:opts};
+var id=lensTemplateNode.id;
+if(id==null||id.length==0){id="exhibitLensTemplate"+Math.floor(Math.random()*10000);
+lensTemplateNode.id=id;
+}var compiledTemplate=Exhibit.Lens._compiledTemplates[id];
+if(compiledTemplate==null){compiledTemplate={url:id,template:Exhibit.Lens.compileTemplate(lensTemplateNode,false,uiContext),compiled:true,jobs:[]};
+Exhibit.Lens._compiledTemplates[id]=compiledTemplate;
+}job.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job);
+};
+Exhibit.Lens._startCompilingTemplate=function(lensTemplateURL,job){var compiledTemplate={url:lensTemplateURL,template:null,compiled:false,jobs:[job]};
+Exhibit.Lens._compiledTemplates[lensTemplateURL]=compiledTemplate;
+var fError=function(statusText,status,xmlhttp){SimileAjax.Debug.log("Failed to load view template from "+lensTemplateURL+"\n"+statusText);
+};
+var fDone=function(xmlhttp){try{compiledTemplate.template=Exhibit.Lens.compileTemplate(xmlhttp.responseXML.documentElement,true,job.uiContext);
+compiledTemplate.compiled=true;
+for(var i=0;
+i<compiledTemplate.jobs.length;
+i++){try{var job2=compiledTemplate.jobs[i];
+job2.template=compiledTemplate;
+Exhibit.Lens._performConstructFromLensTemplateJob(job2);
+}catch(e){SimileAjax.Debug.exception(e,"Lens: Error constructing lens template in job queue");
+}}compiledTemplate.jobs=null;
+}catch(e){SimileAjax.Debug.exception(e,"Lens: Error compiling lens template and processing template job queue");
+}};
+SimileAjax.XmlHttp.get(lensTemplateURL,fError,fDone);
+return compiledTemplate;
+};
+Exhibit.Lens.compileTemplate=function(rootNode,isXML,uiContext){return Exhibit.Lens._processTemplateNode(rootNode,isXML,uiContext);
+};
+Exhibit.Lens._processTemplateNode=function(node,isXML,uiContext){if(node.nodeType==1){return Exhibit.Lens._processTemplateElement(node,isXML,uiContext);
+}else{return node.nodeValue;
+}};
+Exhibit.Lens._processTemplateElement=function(elmt,isXML,uiContext){var templateNode={tag:elmt.tagName.toLowerCase(),uiContext:uiContext,control:null,condition:null,content:null,contentAttributes:null,subcontentAttributes:null,attributes:[],styles:[],handlers:[],children:null};
+var settings={parseChildTextNodes:true};
+var attributes=elmt.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+var name=attribute.nodeName;
+var value=attribute.nodeValue;
+Exhibit.Lens._processTemplateAttribute(uiContext,templateNode,settings,name,value);
+}if(!isXML&&SimileAjax.Platform.browser.isIE){var handlers=Exhibit.Lens._handlers;
+for(var h=0;
+h<handlers.length;
+h++){var handler=handlers[h];
+var code=elmt[handler];
+if(code!=null){templateNode.handlers.push({name:handler,code:code});
+}}}var childNode=elmt.firstChild;
+if(childNode!=null){templateNode.children=[];
+while(childNode!=null){if((settings.parseChildTextNodes&&childNode.nodeType==3)||childNode.nodeType==1){templateNode.children.push(Exhibit.Lens._processTemplateNode(childNode,isXML,templateNode.uiContext));
+}childNode=childNode.nextSibling;
+}}return templateNode;
+};
+Exhibit.Lens._processTemplateAttribute=function(uiContext,templateNode,settings,name,value){if(value==null||typeof value!="string"||value.length==0||name=="contentEditable"){return ;
+}if(name.length>3&&name.substr(0,3)=="ex:"){name=name.substr(3);
+if(name=="formats"){templateNode.uiContext=Exhibit.UIContext._createWithParent(uiContext);
+Exhibit.FormatParser.parseSeveral(templateNode.uiContext,value,0,{});
+}else{if(name=="onshow"){templateNode.attributes.push({name:name,value:value});
+}else{if(name=="control"){templateNode.control=value;
+}else{if(name=="content"){templateNode.content=Exhibit.ExpressionParser.parse(value);
+templateNode.attributes.push({name:"ex:content",value:value});
+}else{if(name=="editor"){templateNode.attributes.push({name:"ex:editor",value:value});
+}else{if(name=="edit"){templateNode.edit=value;
+}else{if(name=="options"){templateNode.options=value;
+}else{if(name=="editvalues"){templateNode.editValues=value;
+}else{if(name=="tag"){templateNode.tag=value;
+}else{if(name=="if-exists"){templateNode.condition={test:"if-exists",expression:Exhibit.ExpressionParser.parse(value)};
+}else{if(name=="if"){templateNode.condition={test:"if",expression:Exhibit.ExpressionParser.parse(value)};
+settings.parseChildTextNodes=false;
+}else{if(name=="select"){templateNode.condition={test:"select",expression:Exhibit.ExpressionParser.parse(value)};
+}else{if(name=="case"){templateNode.condition={test:"case",value:value};
+settings.parseChildTextNodes=false;
+}else{var isStyle=false;
+var x=name.indexOf("-style-content");
+if(x>0){isStyle=true;
+}else{x=name.indexOf("-content");
+}if(x>0){if(templateNode.contentAttributes==null){templateNode.contentAttributes=[];
+}templateNode.contentAttributes.push({name:name.substr(0,x),expression:Exhibit.ExpressionParser.parse(value),isStyle:isStyle});
+}else{x=name.indexOf("-style-subcontent");
+if(x>0){isStyle=true;
+}else{x=name.indexOf("-subcontent");
+}if(x>0){if(templateNode.subcontentAttributes==null){templateNode.subcontentAttributes=[];
+}templateNode.subcontentAttributes.push({name:name.substr(0,x),fragments:Exhibit.Lens._parseSubcontentAttribute(value),isStyle:isStyle});
+}}}}}}}}}}}}}}}}else{if(name=="style"){Exhibit.Lens._processStyle(templateNode,value);
+}else{if(name!="id"){if(name=="class"){if(SimileAjax.Platform.browser.isIE){name="className";
+}}else{if(name=="cellspacing"){name="cellSpacing";
+}else{if(name=="cellpadding"){name="cellPadding";
+}else{if(name=="bgcolor"){name="bgColor";
+}}}}templateNode.attributes.push({name:name,value:value});
+}}}};
+Exhibit.Lens._processStyle=function(templateNode,styleValue){var styles=styleValue.split(";");
+for(var s=0;
+s<styles.length;
+s++){var pair=styles[s].split(":");
+if(pair.length>1){var n=pair[0].trim();
+var v=pair[1].trim();
+if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
+}else{if(n=="-moz-opacity"){n="MozOpacity";
+}else{if(n.indexOf("-")>0){var segments=n.split("-");
+n=segments[0];
+for(var x=1;
+x<segments.length;
+x++){n+=segments[x].substr(0,1).toUpperCase()+segments[x].substr(1);
+}}}}templateNode.styles.push({name:n,value:v});
+}}};
+Exhibit.Lens._parseSubcontentAttribute=function(value){var fragments=[];
+var current=0;
+var open;
+while(current<value.length&&(open=value.indexOf("{{",current))>=0){var close=value.indexOf("}}",open);
+if(close<0){break;
+}fragments.push(value.substring(current,open));
+fragments.push(Exhibit.ExpressionParser.parse(value.substring(open+2,close)));
+current=close+2;
+}if(current<value.length){fragments.push(value.substr(current));
+}return fragments;
+};
+Exhibit.Lens.constructFromLensTemplate=function(itemID,templateNode,parentElmt,uiContext,opts){return Exhibit.Lens._performConstructFromLensTemplateJob({itemID:itemID,template:{template:templateNode},div:parentElmt,uiContext:uiContext,opts:opts});
+};
+Exhibit.Lens._performConstructFromLensTemplateJob=function(job){Exhibit.Lens._constructFromLensTemplateNode({"value":job.itemID},{"value":"item"},job.template.template,job.div,job.opts);
+var node=job.div.tagName.toLowerCase()=="table"?job.div.rows[job.div.rows.length-1]:job.div.lastChild;
+var tagName=node.tagName.toLowerCase();
+switch(tagName){case"span":node.style.display="inline";
+break;
+case"tr":node.style.display="table-row";
+break;
+case"td":node.style.display="table-cell";
+break;
+default:node.style.display="block";
+}node.setAttribute("ex:itemID",job.itemID);
+if(!Exhibit.params.safe){var onshow=Exhibit.getAttribute(node,"onshow");
+if(onshow!=null&&onshow.length>0){try{(new Function(onshow)).call(node);
+}catch(e){SimileAjax.Debug.log(e);
+}}}return node;
+};
+Exhibit.Lens._constructFromLensTemplateNode=function(roots,rootValueTypes,templateNode,parentElmt,opts){if(typeof templateNode=="string"){parentElmt.appendChild(document.createTextNode(templateNode));
+return ;
+}var uiContext=templateNode.uiContext;
+var database=uiContext.getDatabase();
+var children=templateNode.children;
+function processChildren(){if(children!=null){for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[i],elmt,opts);
+}}}if(templateNode.condition!=null){if(templateNode.condition.test=="if-exists"){if(!templateNode.condition.expression.testExists(roots,rootValueTypes,"value",database)){return ;
+}}else{if(templateNode.condition.test=="if"){if(templateNode.condition.expression.evaluate(roots,rootValueTypes,"value",database).values.contains(true)){if(children!=null&&children.length>0){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[0],parentElmt,opts);
+}}else{if(children!=null&&children.length>1){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[1],parentElmt,opts);
+}}return ;
+}else{if(templateNode.condition.test=="select"){var values=templateNode.condition.expression.evaluate(roots,rootValueTypes,"value",database).values;
+if(children!=null){var lastChildTemplateNode=null;
+for(var c=0;
+c<children.length;
+c++){var childTemplateNode=children[c];
+if(childTemplateNode.condition!=null&&childTemplateNode.condition.test=="case"){if(values.contains(childTemplateNode.condition.value)){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,childTemplateNode,parentElmt,opts);
+return ;
+}}else{if(typeof childTemplateNode!="string"){lastChildTemplateNode=childTemplateNode;
+}}}}if(lastChildTemplateNode!=null){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,lastChildTemplateNode,parentElmt,opts);
+}return ;
+}}}}var elmt=Exhibit.Lens._constructElmtWithAttributes(templateNode,parentElmt,database);
+if(templateNode.contentAttributes!=null){var contentAttributes=templateNode.contentAttributes;
+for(var i=0;
+i<contentAttributes.length;
+i++){var attribute=contentAttributes[i];
+var values=[];
+attribute.expression.evaluate(roots,rootValueTypes,"value",database).values.visit(function(v){values.push(v);
+});
+var value=values.join(";");
+if(attribute.isStyle){elmt.style[attribute.name]=value;
+}else{if("class"==attribute.name){elmt.className=value;
+}else{if(Exhibit.Lens._attributeValueIsSafe(attribute.name,value)){elmt.setAttribute(attribute.name,value);
+}}}}}if(templateNode.subcontentAttributes!=null){var subcontentAttributes=templateNode.subcontentAttributes;
+for(var i=0;
+i<subcontentAttributes.length;
+i++){var attribute=subcontentAttributes[i];
+var fragments=attribute.fragments;
+var results="";
+for(var r=0;
+r<fragments.length;
+r++){var fragment=fragments[r];
+if(typeof fragment=="string"){results+=fragment;
+}else{results+=fragment.evaluateSingle(roots,rootValueTypes,"value",database).value;
+}}if(attribute.isStyle){elmt.style[attribute.name]=results;
+}else{if("class"==attribute.name){elmt.className=results;
+}else{if(Exhibit.Lens._attributeValueIsSafe(attribute.name,results)){elmt.setAttribute(attribute.name,results);
+}}}}}if(!Exhibit.params.safe){var handlers=templateNode.handlers;
+for(var h=0;
+h<handlers.length;
+h++){var handler=handlers[h];
+elmt[handler.name]=handler.code;
+}}var itemID=roots["value"];
+if(templateNode.control!=null){switch(templateNode.control){case"item-link":var a=document.createElement("a");
+a.innerHTML=Exhibit.l10n.itemLinkLabel;
+a.href=Exhibit.Persistence.getItemLink(itemID);
+a.target="_blank";
+elmt.appendChild(a);
+break;
+case"remove-item":if(!opts.disableEditWidgets&&database.isNewItem(itemID)){if(templateNode.tag=="a"){elmt.href="javascript:";
+}SimileAjax.jQuery(elmt).click(function(){database.removeItem(itemID);
+});
+processChildren();
+}else{parentElmt.removeChild(elmt);
+}break;
+case"start-editing":if(templateNode.tag=="a"){elmt.href="javascript:";
+}if(opts.disableEditWidgets){parentElmt.removeChild(elmt);
+}else{if(opts.inPopup){SimileAjax.jQuery(elmt).click(function(){Exhibit.UI.showItemInPopup(itemID,null,uiContext,{lensType:"edit",coords:opts.coords});
+});
+processChildren();
+}else{SimileAjax.jQuery(elmt).click(function(){uiContext.setEditMode(itemID,true);
+uiContext.getCollection()._listeners.fire("onItemsChanged",[]);
+});
+processChildren();
+}}break;
+case"stop-editing":if(templateNode.tag=="a"){elmt.href="javascript:";
+}if(opts.disableEditWidgets){parentElmt.removeChild(elmt);
+}else{if(opts.inPopup){SimileAjax.jQuery(elmt).click(function(){Exhibit.UI.showItemInPopup(itemID,null,uiContext,{lensType:"normal",coords:opts.coords});
+});
+processChildren();
+}else{SimileAjax.jQuery(elmt).click(function(){uiContext.setEditMode(itemID,false);
+uiContext.getCollection()._listeners.fire("onItemsChanged",[]);
+});
+processChildren();
+}}break;
+case"accept-changes":if(database.isSubmission(itemID)){if(templateNode.tag=="a"){elmt.href="javascript:";
+}SimileAjax.jQuery(elmt).click(function(){database.mergeSubmissionIntoItem(itemID);
+});
+processChildren();
+}else{SimileAjax.Debug.warn("accept-changes element in non-submission item");
+parentElmt.removeChild(elmt);
+}break;
+}}else{if(templateNode.content!=null){var results=templateNode.content.evaluate(roots,rootValueTypes,"value",database);
+if(children!=null){var rootValueTypes2={"value":results.valueType,"index":"number"};
+var index=1;
+var processOneValue=function(childValue){var roots2={"value":childValue,"index":index++};
+for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots2,rootValueTypes2,children[i],elmt,opts);
+}};
+if(results.values instanceof Array){for(var i=0;
+i<results.values.length;
+i++){processOneValue(results.values[i]);
+}}else{results.values.visit(processOneValue);
+}}else{Exhibit.Lens._constructDefaultValueList(results.values,results.valueType,elmt,templateNode.uiContext);
+}}else{if(templateNode.edit!=null){processChildren();
+Exhibit.Lens._constructEditableContent(templateNode,elmt,itemID,uiContext);
+}else{if(children!=null){for(var i=0;
+i<children.length;
+i++){Exhibit.Lens._constructFromLensTemplateNode(roots,rootValueTypes,children[i],elmt,opts);
+}}}}}};
+Exhibit.Lens._constructElmtWithAttributes=function(templateNode,parentElmt,database){var elmt;
+if(templateNode.tag=="input"&&SimileAjax.Platform.browser.isIE){var a=["<input"];
+var attributes=templateNode.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+if(Exhibit.Lens._attributeValueIsSafe(attribute.name,attribute.value)){a.push(attribute.name+'="'+attribute.value+'"');
+}}a.push("></input>");
+elmt=SimileAjax.DOM.createElementFromString(a.join(" "));
+parentElmt.appendChild(elmt);
+}else{switch(templateNode.tag){case"tr":elmt=parentElmt.insertRow(parentElmt.rows.length);
+break;
+case"td":elmt=parentElmt.insertCell(parentElmt.cells.length);
+break;
+default:elmt=document.createElement(templateNode.tag);
+parentElmt.appendChild(elmt);
+}var attributes=templateNode.attributes;
+for(var i=0;
+i<attributes.length;
+i++){var attribute=attributes[i];
+if(Exhibit.Lens._attributeValueIsSafe(attribute.name,attribute.value)){try{elmt.setAttribute(attribute.name,attribute.value);
+}catch(e){}}}}var styles=templateNode.styles;
+for(var i=0;
+i<styles.length;
+i++){var style=styles[i];
+elmt.style[style.name]=style.value;
+}return elmt;
+};
+Exhibit.Lens._constructEditableContent=function(templateNode,elmt,itemID,uiContext){var db=uiContext.getDatabase();
+var attr=templateNode.edit.replace(".","");
+var itemValue=db.getObject(itemID,attr);
+var changeHandler=function(){if(this.value&&this.value!=itemValue){db.editItem(itemID,attr,this.value);
+}};
+if(templateNode.tag=="select"){Exhibit.Lens._constructEditableSelect(templateNode,elmt,itemID,uiContext,itemValue);
+SimileAjax.jQuery(elmt).blur(changeHandler);
+}else{elmt.value=itemValue;
+SimileAjax.jQuery(elmt).change(changeHandler);
+}};
+Exhibit.Lens.doesSelectContain=function(select,text){for(var i in select.options){var opt=select.options[i];
+if(opt.text==text||opt.value==text){return true;
+}}return false;
+};
+Exhibit.Lens._constructEditableSelect=function(templateNode,elmt,itemID,uiContext,itemValue){if(templateNode.options){var expr=Exhibit.ExpressionParser.parse(templateNode.options);
+var allItems=uiContext.getDatabase().getAllItems();
+var results=expr.evaluate({"value":allItems},{value:"item"},"value",uiContext.getDatabase());
+var sortedResults=results.values.toArray().sort();
+for(var i in sortedResults){var optText=sortedResults[i];
+if(!Exhibit.Lens.doesSelectContain(elmt,optText)){var newOption=new Option(sortedResults[i],sortedResults[i]);
+elmt.add(newOption,null);
+}}}if(!itemValue){if(!Exhibit.Lens.doesSelectContain(elmt,"")){var newOption=new Option("","",true);
+elmt.add(newOption,elmt.options[0]);
+}}else{for(var i in elmt.options){if(elmt.options.hasOwnProperty(i)&&elmt.options[i].value==itemValue){elmt.selectedIndex=i;
+}}}};
+Exhibit.Lens._constructDefaultValueList=function(values,valueType,parentElmt,uiContext){uiContext.formatList(values,values.size(),valueType,function(elmt){parentElmt.appendChild(elmt);
+});
+};
+Exhibit.Lens._attributeValueIsSafe=function(name,value){if(Exhibit.params.safe){if((name=="href"&&value.startsWith("javascript:"))||(name.startsWith("on"))){return false;
+}}return true;
+};
+
+
+/* ui-context.js */
+Exhibit.UIContext=function(){this._parent=null;
+this._exhibit=null;
+this._collection=null;
+this._lensRegistry=new Exhibit.LensRegistry();
+this._settings={};
+this._formatters={};
+this._listFormatter=null;
+this._editModeRegistry={};
+this._popupFunc=null;
+};
+Exhibit.UIContext.createRootContext=function(configuration,exhibit){var context=new Exhibit.UIContext();
+context._exhibit=exhibit;
+var settings=Exhibit.UIContext.l10n.initialSettings;
+for(var n in settings){context._settings[n]=settings[n];
+}var formats=Exhibit.getAttribute(document.body,"formats");
+if(formats!=null&&formats.length>0){Exhibit.FormatParser.parseSeveral(context,formats,0,{});
+}Exhibit.SettingsUtilities.collectSettingsFromDOM(document.body,Exhibit.UIContext._settingSpecs,context._settings);
+Exhibit.UIContext._configure(context,configuration);
+return context;
+};
+Exhibit.UIContext.create=function(configuration,parentUIContext,ignoreLenses){var context=Exhibit.UIContext._createWithParent(parentUIContext);
+Exhibit.UIContext._configure(context,configuration,ignoreLenses);
+return context;
+};
+Exhibit.UIContext.createFromDOM=function(configElmt,parentUIContext,ignoreLenses){var context=Exhibit.UIContext._createWithParent(parentUIContext);
+if(!(ignoreLenses)){Exhibit.UIContext.registerLensesFromDOM(configElmt,context.getLensRegistry());
+}var id=Exhibit.getAttribute(configElmt,"collectionID");
+if(id!=null&&id.length>0){context._collection=context._exhibit.getCollection(id);
+}var formats=Exhibit.getAttribute(configElmt,"formats");
+if(formats!=null&&formats.length>0){Exhibit.FormatParser.parseSeveral(context,formats,0,{});
+}Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.UIContext._settingSpecs,context._settings);
+Exhibit.UIContext._configure(context,Exhibit.getConfigurationFromDOM(configElmt),ignoreLenses);
+return context;
+};
+Exhibit.UIContext.prototype.dispose=function(){};
+Exhibit.UIContext.prototype.getParentUIContext=function(){return this._parent;
+};
+Exhibit.UIContext.prototype.getExhibit=function(){return this._exhibit;
+};
+Exhibit.UIContext.prototype.getDatabase=function(){return this.getExhibit().getDatabase();
+};
+Exhibit.UIContext.prototype.getCollection=function(){if(this._collection==null){if(this._parent!=null){this._collection=this._parent.getCollection();
+}else{this._collection=this._exhibit.getDefaultCollection();
+}}return this._collection;
+};
+Exhibit.UIContext.prototype.getLensRegistry=function(){return this._lensRegistry;
+};
+Exhibit.UIContext.prototype.getSetting=function(name){return name in this._settings?this._settings[name]:(this._parent!=null?this._parent.getSetting(name):undefined);
+};
+Exhibit.UIContext.prototype.getBooleanSetting=function(name,defaultValue){var v=this.getSetting(name);
+return v==undefined||v==null?defaultValue:v;
+};
+Exhibit.UIContext.prototype.putSetting=function(name,value){this._settings[name]=value;
+};
+Exhibit.UIContext.prototype.format=function(value,valueType,appender){var f;
+if(valueType in this._formatters){f=this._formatters[valueType];
+}else{f=this._formatters[valueType]=new Exhibit.Formatter._constructors[valueType](this);
+}f.format(value,appender);
+};
+Exhibit.UIContext.prototype.formatList=function(iterator,count,valueType,appender){if(this._listFormatter==null){this._listFormatter=new Exhibit.Formatter._ListFormatter(this);
+}this._listFormatter.formatList(iterator,count,valueType,appender);
+};
+Exhibit.UIContext.prototype.setEditMode=function(itemID,val){if(val){this._editModeRegistry[itemID]=true;
+}else{this._editModeRegistry[itemID]=false;
+}};
+Exhibit.UIContext.prototype.isBeingEdited=function(itemID){return !!this._editModeRegistry[itemID];
+};
+Exhibit.UIContext._createWithParent=function(parent){var context=new Exhibit.UIContext();
+context._parent=parent;
+context._exhibit=parent._exhibit;
+context._lensRegistry=new Exhibit.LensRegistry(parent.getLensRegistry());
+context._editModeRegistry=parent._editModeRegistry;
+return context;
+};
+Exhibit.UIContext._settingSpecs={"bubbleWidth":{type:"int"},"bubbleHeight":{type:"int"}};
+Exhibit.UIContext._configure=function(context,configuration,ignoreLenses){Exhibit.UIContext.registerLenses(configuration,context.getLensRegistry());
+if("collectionID" in configuration){context._collection=context._exhibit.getCollection(configuration["collectionID"]);
+}if("formats" in configuration){Exhibit.FormatParser.parseSeveral(context,configuration.formats,0,{});
+}if(!(ignoreLenses)){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.UIContext._settingSpecs,context._settings);
+}};
+Exhibit.UIContext.registerLens=function(configuration,lensRegistry){var template=configuration.templateFile;
+if(template!=null){if("itemTypes" in configuration){for(var i=0;
+i<configuration.itemTypes.length;
+i++){lensRegistry.registerLensForType(template,configuration.itemTypes[i]);
+}}else{lensRegistry.registerDefaultLens(template);
+}}};
+Exhibit.UIContext.registerLensFromDOM=function(elmt,lensRegistry){elmt.style.display="none";
+var itemTypes=Exhibit.getAttribute(elmt,"itemTypes",",");
+var template=null;
+var url=Exhibit.getAttribute(elmt,"templateFile");
+if(url!=null&&url.length>0){template=url;
+}else{var id=Exhibit.getAttribute(elmt,"template");
+var elmt2=id&&document.getElementById(id);
+if(elmt2!=null){template=elmt2;
+}else{template=elmt;
+}}if(template!=null){if(itemTypes==null||itemTypes.length==0||(itemTypes.length==1&&itemTypes[0]=="")){lensRegistry.registerDefaultLens(template);
+}else{for(var i=0;
+i<itemTypes.length;
+i++){lensRegistry.registerLensForType(template,itemTypes[i]);
+}}}};
+Exhibit.UIContext.registerLenses=function(configuration,lensRegistry){if("lenses" in configuration){for(var i=0;
+i<configuration.lenses.length;
+i++){Exhibit.UIContext.registerLens(configuration.lenses[i],lensRegistry);
+}}if("lensSelector" in configuration){var lensSelector=configuration.lensSelector;
+if(typeof lensSelector=="function"){lensRegistry.addLensSelector(lensSelector);
+}else{SimileAjax.Debug.log("lensSelector is not a function");
+}}};
+Exhibit.UIContext.registerLensesFromDOM=function(parentNode,lensRegistry){var node=parentNode.firstChild;
+while(node!=null){if(node.nodeType==1){var role=Exhibit.getRoleAttribute(node);
+if(role=="lens"||role=="edit-lens"){Exhibit.UIContext.registerLensFromDOM(node,lensRegistry);
+}}node=node.nextSibling;
+}var lensSelectorString=Exhibit.getAttribute(parentNode,"lensSelector");
+if(lensSelectorString!=null&&lensSelectorString.length>0){try{var lensSelector=eval(lensSelectorString);
+if(typeof lensSelector=="function"){lensRegistry.addLensSelector(lensSelector);
+}else{SimileAjax.Debug.log("lensSelector expression "+lensSelectorString+" is not a function");
+}}catch(e){SimileAjax.Debug.exception(e,"Bad lensSelector expression: "+lensSelectorString);
+}}};
+Exhibit.UIContext.createLensRegistry=function(configuration,parentLensRegistry){var lensRegistry=new Exhibit.LensRegistry(parentLensRegistry);
+Exhibit.UIContext.registerLenses(configuration,lensRegistry);
+return lensRegistry;
+};
+Exhibit.UIContext.createLensRegistryFromDOM=function(parentNode,configuration,parentLensRegistry){var lensRegistry=new Exhibit.LensRegistry(parentLensRegistry);
+Exhibit.UIContext.registerLensesFromDOM(parentNode,lensRegistry);
+Exhibit.UIContext.registerLenses(configuration,lensRegistry);
+return lensRegistry;
+};
+
+
+/* ui.js */
+Exhibit.UI=new Object();
+Exhibit.UI.componentMap={};
+Exhibit.UI.registerComponent=function(name,comp){var msg="Cannot register component "+name+" -- ";
+if(name in Exhibit.UI.componentMap){SimileAjax.Debug.warn(msg+"another component has taken that name");
+}else{if(!comp){SimileAjax.Debug.warn(msg+"no component object provided");
+}else{if(!comp.create){SimileAjax.Debug.warn(msg+"component has no create function");
+}else{if(!comp.createFromDOM){SimileAjax.Debug.warn(msg+"component has no createFromDOM function");
+}else{Exhibit.UI.componentMap[name]=comp;
+}}}}};
+Exhibit.UI.create=function(configuration,elmt,uiContext){if("role" in configuration){var role=configuration.role;
+if(role!=null&&role.startsWith("exhibit-")){role=role.substr("exhibit-".length);
+}if(role in Exhibit.UI.componentMap){var createFunc=Exhibit.UI.componentMap[role].create;
+return createFunc(configuration,elmt,uiContext);
+}switch(role){case"lens":case"edit-lens":Exhibit.UIContext.registerLens(configuration,uiContext.getLensRegistry());
+return null;
+case"view":return Exhibit.UI.createView(configuration,elmt,uiContext);
+case"facet":return Exhibit.UI.createFacet(configuration,elmt,uiContext);
+case"coordinator":return Exhibit.UI.createCoordinator(configuration,uiContext);
+case"coder":return Exhibit.UI.createCoder(configuration,uiContext);
+case"viewPanel":return Exhibit.ViewPanel.create(configuration,elmt,uiContext);
+case"logo":return Exhibit.Logo.create(configuration,elmt,uiContext);
+case"hiddenContent":elmt.style.display="none";
+return null;
+}}return null;
+};
+Exhibit.UI.createFromDOM=function(elmt,uiContext){var role=Exhibit.getRoleAttribute(elmt);
+if(role in Exhibit.UI.componentMap){var createFromDOMFunc=Exhibit.UI.componentMap[role].createFromDOM;
+return createFromDOMFunc(elmt,uiContext);
+}switch(role){case"lens":case"edit-lens":Exhibit.UIContext.registerLensFromDOM(elmt,uiContext.getLensRegistry());
+return null;
+case"view":return Exhibit.UI.createViewFromDOM(elmt,null,uiContext);
+case"facet":return Exhibit.UI.createFacetFromDOM(elmt,null,uiContext);
+case"coordinator":return Exhibit.UI.createCoordinatorFromDOM(elmt,uiContext);
+case"coder":return Exhibit.UI.createCoderFromDOM(elmt,uiContext);
+case"viewPanel":return Exhibit.ViewPanel.createFromDOM(elmt,uiContext);
+case"logo":return Exhibit.Logo.createFromDOM(elmt,uiContext);
+case"hiddenContent":elmt.style.display="none";
+return null;
+}return null;
+};
+Exhibit.UI.generateCreationMethods=function(constructor){constructor.create=function(configuration,elmt,uiContext){var newContext=Exhibit.UIContext.create(configuration,uiContext);
+var settings={};
+Exhibit.SettingsUtilities.collectSettings(configuration,constructor._settingSpecs||{},settings);
+return new constructor(elmt,newContext,settings);
+};
+constructor.createFromDOM=function(elmt,uiContext){var newContext=Exhibit.UIContext.createFromDOM(elmt,uiContext);
+var settings={};
+Exhibit.SettingsUtilities.collectSettingsFromDOM(elmt,constructor._settingSpecs||{},settings);
+return new constructor(elmt,newContext,settings);
+};
+};
+Exhibit.UI.createView=function(configuration,elmt,uiContext){var viewClass="viewClass" in configuration?configuration.viewClass:Exhibit.TileView;
+if(typeof viewClass=="string"){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClass);
+}return viewClass.create(configuration,elmt,uiContext);
+};
+Exhibit.UI.createViewFromDOM=function(elmt,container,uiContext){var viewClass=Exhibit.UI.viewClassNameToViewClass(Exhibit.getAttribute(elmt,"viewClass"));
+return viewClass.createFromDOM(elmt,container,uiContext);
+};
+Exhibit.UI.viewClassNameToViewClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"View");
+}catch(e){SimileAjax.Debug.warn("Unknown viewClass "+name);
+}}return Exhibit.TileView;
+};
+Exhibit.UI.createFacet=function(configuration,elmt,uiContext){var facetClass="facetClass" in configuration?configuration.facetClass:Exhibit.ListFacet;
+if(typeof facetClass=="string"){facetClass=Exhibit.UI.facetClassNameToFacetClass(facetClass);
+}return facetClass.create(configuration,elmt,uiContext);
+};
+Exhibit.UI.createFacetFromDOM=function(elmt,container,uiContext){var facetClass=Exhibit.UI.facetClassNameToFacetClass(Exhibit.getAttribute(elmt,"facetClass"));
+return facetClass.createFromDOM(elmt,container,uiContext);
+};
+Exhibit.UI.facetClassNameToFacetClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"Facet");
+}catch(e){SimileAjax.Debug.warn("Unknown facetClass "+name);
+}}return Exhibit.ListFacet;
+};
+Exhibit.UI.createCoder=function(configuration,uiContext){var coderClass="coderClass" in configuration?configuration.coderClass:Exhibit.ColorCoder;
+if(typeof coderClass=="string"){coderClass=Exhibit.UI.coderClassNameToCoderClass(coderClass);
+}return coderClass.create(configuration,uiContext);
+};
+Exhibit.UI.createCoderFromDOM=function(elmt,uiContext){var coderClass=Exhibit.UI.coderClassNameToCoderClass(Exhibit.getAttribute(elmt,"coderClass"));
+return coderClass.createFromDOM(elmt,uiContext);
+};
+Exhibit.UI.coderClassNameToCoderClass=function(name){if(name!=null&&name.length>0){try{return Exhibit.UI._stringToObject(name,"Coder");
+}catch(e){SimileAjax.Debug.warn("Unknown coderClass "+name);
+}}return Exhibit.ColorCoder;
+};
+Exhibit.UI.createCoordinator=function(configuration,uiContext){return Exhibit.Coordinator.create(configuration,uiContext);
+};
+Exhibit.UI.createCoordinatorFromDOM=function(elmt,uiContext){return Exhibit.Coordinator.createFromDOM(elmt,uiContext);
+};
+Exhibit.UI._stringToObject=function(name,suffix){if(!name.startsWith("Exhibit.")){if(!name.endsWith(suffix)){try{return eval("Exhibit."+name+suffix);
+}catch(e){}}try{return eval("Exhibit."+name);
+}catch(e){}}if(!name.endsWith(suffix)){try{return eval(name+suffix);
+}catch(e){}}try{return eval(name);
+}catch(e){}throw new Error("Unknown class "+name);
+};
+Exhibit.UI.docRoot="http://simile.mit.edu/wiki/";
+Exhibit.UI.validator="http://simile.mit.edu/babel/validator";
+Exhibit.UI.showHelp=function(message,url,target){target=(target)?target:"_blank";
+if(url!=null){if(window.confirm(message+"\n\n"+Exhibit.l10n.showDocumentationMessage)){window.open(url,target);
+}}else{window.alert(message);
+}};
+Exhibit.UI.showJavascriptExpressionValidation=function(message,expression){var target="_blank";
+if(window.confirm(message+"\n\n"+Exhibit.l10n.showJavascriptValidationMessage)){window.open(Exhibit.UI.validator+"?expresson="+encodeURIComponent(expression),target);
+}};
+Exhibit.UI.showJsonFileValidation=function(message,url){var target="_blank";
+if(url.indexOf("file:")==0){if(window.confirm(message+"\n\n"+Exhibit.l10n.showJsonValidationFormMessage)){window.open(Exhibit.UI.validator,target);
+}}else{if(window.confirm(message+"\n\n"+Exhibit.l10n.showJsonValidationMessage)){window.open(Exhibit.UI.validator+"?url="+url,target);
+}}};
+Exhibit.UI._busyIndicator=null;
+Exhibit.UI._busyIndicatorCount=0;
+Exhibit.UI.showBusyIndicator=function(){Exhibit.UI._busyIndicatorCount++;
+if(Exhibit.UI._busyIndicatorCount>1){return ;
+}if(Exhibit.UI._busyIndicator==null){Exhibit.UI._busyIndicator=Exhibit.UI.createBusyIndicator();
+}var scrollTop=("scrollTop" in document.body)?document.body.scrollTop:document.body.parentNode.scrollTop;
+var height=("innerHeight" in window)?window.innerHeight:("clientHeight" in document.body?document.body.clientHeight:document.body.parentNode.clientHeight);
+var top=Math.floor(scrollTop+height/3);
+Exhibit.UI._busyIndicator.style.top=top+"px";
+document.body.appendChild(Exhibit.UI._busyIndicator);
+};
+Exhibit.UI.hideBusyIndicator=function(){Exhibit.UI._busyIndicatorCount--;
+if(Exhibit.UI._busyIndicatorCount>0){return ;
+}try{document.body.removeChild(Exhibit.UI._busyIndicator);
+}catch(e){}};
+Exhibit.UI.protectUI=function(elmt){SimileAjax.DOM.appendClassName(elmt,"exhibit-ui-protection");
+};
+Exhibit.UI.makeActionLink=function(text,handler,layer){var a=document.createElement("a");
+a.href="javascript:";
+a.className="exhibit-action";
+a.innerHTML=text;
+var handler2=function(elmt,evt,target){if("true"!=elmt.getAttribute("disabled")){handler(elmt,evt,target);
+}};
+SimileAjax.WindowManager.registerEvent(a,"click",handler2,layer);
+return a;
+};
+Exhibit.UI.enableActionLink=function(a,enabled){a.setAttribute("disabled",enabled?"false":"true");
+a.className=enabled?"exhibit-action":"exhibit-action-disabled";
+};
+Exhibit.UI.makeItemSpan=function(itemID,label,uiContext,layer){if(label==null){label=database.getObject(itemID,"label");
+if(label==null){label=itemID;
+}}var a=SimileAjax.DOM.createElementFromString('<a href="'+Exhibit.Persistence.getItemLink(itemID)+"\" class='exhibit-item'>"+label+"</a>");
+var handler=function(elmt,evt,target){Exhibit.UI.showItemInPopup(itemID,elmt,uiContext);
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler,layer);
+return a;
+};
+Exhibit.UI.makeValueSpan=function(label,valueType,layer){var span=document.createElement("span");
+span.className="exhibit-value";
+if(valueType=="url"){var url=label;
+if(Exhibit.params.safe&&url.trim().startsWith("javascript:")){span.appendChild(document.createTextNode(url));
+}else{span.innerHTML='<a href="'+url+"\" target='_blank'>"+(label.length>50?label.substr(0,20)+" ... "+label.substr(label.length-20):label)+"</a>";
+}}else{if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}span.innerHTML=label;
+}return span;
+};
+Exhibit.UI.calculatePopupPosition=function(elmt){var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+return{x:coords.left+Math.round(elmt.offsetWidth/2),y:coords.top+Math.round(elmt.offsetHeight/2)};
+};
+Exhibit.UI.showItemInPopup=function(itemID,elmt,uiContext,opts){SimileAjax.WindowManager.popAllLayers();
+opts=opts||{};
+opts.coords=opts.coords||Exhibit.UI.calculatePopupPosition(elmt);
+var itemLensDiv=document.createElement("div");
+var lensOpts={inPopup:true,coords:opts.coords};
+if(opts.lensType=="normal"){lensOpts.lensTemplate=uiContext.getLensRegistry().getNormalLens(itemID,uiContext);
+}else{if(opts.lensType=="edit"){lensOpts.lensTemplate=uiContext.getLensRegistry().getEditLens(itemID,uiContext);
+}else{if(opts.lensType){SimileAjax.Debug.warn("Unknown Exhibit.UI.showItemInPopup opts.lensType: "+opts.lensType);
+}}}uiContext.getLensRegistry().createLens(itemID,itemLensDiv,uiContext,lensOpts);
+SimileAjax.Graphics.createBubbleForContentAndPoint(itemLensDiv,opts.coords.x,opts.coords.y,uiContext.getSetting("bubbleWidth"));
+};
+Exhibit.UI.createButton=function(name,handler,className){var button=document.createElement("button");
+button.className=(className||"exhibit-button")+" screen";
+button.innerHTML=name;
+if(handler){SimileAjax.WindowManager.registerEvent(button,"click",handler);
+}return button;
+};
+Exhibit.UI.createPopupMenuDom=function(element){var div=document.createElement("div");
+div.className="exhibit-menu-popup exhibit-ui-protection";
+var dom={elmt:div,close:function(){document.body.removeChild(this.elmt);
+},open:function(){var self=this;
+this.layer=SimileAjax.WindowManager.pushLayer(function(){self.close();
+},true,div);
+var docWidth=document.body.offsetWidth;
+var docHeight=document.body.offsetHeight;
+var coords=SimileAjax.DOM.getPageCoordinates(element);
+div.style.top=(coords.top+element.scrollHeight)+"px";
+div.style.right=(docWidth-(coords.left+element.scrollWidth))+"px";
+document.body.appendChild(this.elmt);
+},appendMenuItem:function(label,icon,onClick){var self=this;
+var a=document.createElement("a");
+a.className="exhibit-menu-item";
+a.href="javascript:";
+SimileAjax.WindowManager.registerEvent(a,"click",function(elmt,evt,target){onClick(elmt,evt,target);
+SimileAjax.WindowManager.popLayer(self.layer);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+});
+var div=document.createElement("div");
+a.appendChild(div);
+div.appendChild(SimileAjax.Graphics.createTranslucentImage(icon!=null?icon:(Exhibit.urlPrefix+"images/blank-16x16.png")));
+div.appendChild(document.createTextNode(label));
+this.elmt.appendChild(a);
+},appendSeparator:function(){var hr=document.createElement("hr");
+this.elmt.appendChild(hr);
+}};
+return dom;
+};
+Exhibit.UI.createBusyIndicator=function(){var urlPrefix=Exhibit.urlPrefix+"images/";
+var containerDiv=document.createElement("div");
+if(SimileAjax.Graphics.pngIsTranslucent){var topDiv=document.createElement("div");
+topDiv.style.height="33px";
+topDiv.style.background="url("+urlPrefix+"message-bubble/message-top-left.png) top left no-repeat";
+topDiv.style.paddingLeft="44px";
+containerDiv.appendChild(topDiv);
+var topRightDiv=document.createElement("div");
+topRightDiv.style.height="33px";
+topRightDiv.style.background="url("+urlPrefix+"message-bubble/message-top-right.png) top right no-repeat";
+topDiv.appendChild(topRightDiv);
+var middleDiv=document.createElement("div");
+middleDiv.style.background="url("+urlPrefix+"message-bubble/message-left.png) top left repeat-y";
+middleDiv.style.paddingLeft="44px";
+containerDiv.appendChild(middleDiv);
+var middleRightDiv=document.createElement("div");
+middleRightDiv.style.background="url("+urlPrefix+"message-bubble/message-right.png) top right repeat-y";
+middleRightDiv.style.paddingRight="44px";
+middleDiv.appendChild(middleRightDiv);
+var contentDiv=document.createElement("div");
+middleRightDiv.appendChild(contentDiv);
+var bottomDiv=document.createElement("div");
+bottomDiv.style.height="55px";
+bottomDiv.style.background="url("+urlPrefix+"message-bubble/message-bottom-left.png) bottom left no-repeat";
+bottomDiv.style.paddingLeft="44px";
+containerDiv.appendChild(bottomDiv);
+var bottomRightDiv=document.createElement("div");
+bottomRightDiv.style.height="55px";
+bottomRightDiv.style.background="url("+urlPrefix+"message-bubble/message-bottom-right.png) bottom right no-repeat";
+bottomDiv.appendChild(bottomRightDiv);
+}else{containerDiv.style.border="2px solid #7777AA";
+containerDiv.style.padding="20px";
+containerDiv.style.background="white";
+SimileAjax.Graphics.setOpacity(containerDiv,90);
+var contentDiv=document.createElement("div");
+containerDiv.appendChild(contentDiv);
+}containerDiv.className="exhibit-busyIndicator";
+contentDiv.className="exhibit-busyIndicator-content";
+var img=document.createElement("img");
+img.src=urlPrefix+"progress-running.gif";
+contentDiv.appendChild(img);
+contentDiv.appendChild(document.createTextNode(" "+Exhibit.l10n.busyIndicatorMessage));
+return containerDiv;
+};
+Exhibit.UI.createFocusDialogBox=function(itemID,exhibit,configuration){var template={tag:"div",className:"exhibit-focusDialog exhibit-ui-protection",children:[{tag:"div",className:"exhibit-focusDialog-viewContainer",field:"viewContainer"},{tag:"div",className:"exhibit-focusDialog-controls",children:[{tag:"button",field:"closeButton",children:[Exhibit.l10n.focusDialogBoxCloseButtonLabel]}]}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.open=function(){dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var lens=new Exhibit.Lens(itemID,dom.viewContainer,exhibit,configuration);
+dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+},dom.layer);
+};
+return dom;
+};
+Exhibit.UI.createTranslucentImage=function(relativeUrl,verticalAlign){return SimileAjax.Graphics.createTranslucentImage(Exhibit.urlPrefix+relativeUrl,verticalAlign);
+};
+Exhibit.UI.createTranslucentImageHTML=function(relativeUrl,verticalAlign){return SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+relativeUrl,verticalAlign);
+};
+Exhibit.UI.findAttribute=function(attr,value,parent){var parent=SimileAjax.jQuery(parent||document.body);
+var f=function(){var v=this.getAttribute(attr);
+if(value===undefined){return !!v;
+}else{if(value instanceof Array){return value.indexOf(v)!=-1;
+}else{return value.toString()==v;
+}}};
+return parent.find("*").add(parent).filter(f);
+};
+
+
+/* html-view.js */
+Exhibit.HTMLView=function(containerElmt,uiContext,html){this.html=html;
+this.view=this.moveChildNodes(html,containerElmt);
+};
+Exhibit.HTMLView.create=Exhibit.HTMLView.createFromDOM=function(configElmt,containerElmt,uiContext){return new Exhibit.HTMLView(containerElmt!=null?containerElmt:configElmt,null,configElmt);
+};
+Exhibit.HTMLView.prototype.dispose=function(){this.html=this.moveChildNodes(this.view,this.html);
+this.view=this.html=null;
+};
+Exhibit.HTMLView.prototype.moveChildNodes=function(src,dst){if(src===dst){return dst;
+}var tmp=document.createDocumentFragment();
+while(src.firstChild){tmp.appendChild(src.firstChild);
+}dst.appendChild(tmp);
+return dst;
+};
+
+
+/* ordered-view-frame.js */
+Exhibit.OrderedViewFrame=function(uiContext){this._uiContext=uiContext;
+this._orders=null;
+this._possibleOrders=null;
+this._settings={};
+};
+Exhibit.OrderedViewFrame._settingSpecs={"showAll":{type:"boolean",defaultValue:false},"grouped":{type:"boolean",defaultValue:true},"showDuplicates":{type:"boolean",defaultValue:false},"abbreviatedCount":{type:"int",defaultValue:10},"showHeader":{type:"boolean",defaultValue:true},"showSummary":{type:"boolean",defaultValue:true},"showControls":{type:"boolean",defaultValue:true},"showFooter":{type:"boolean",defaultValue:true},"paginate":{type:"boolean",defaultValue:false},"pageSize":{type:"int",defaultValue:20},"pageWindow":{type:"int",defaultValue:2},"page":{type:"int",defaultValue:0},"alwaysShowPagingControls":{type:"boolean",defaultValue:false},"pagingControlLocations":{type:"enum",defaultValue:"topbottom",choices:["top","bottom","topbottom"]}};
+Exhibit.OrderedViewFrame.prototype.configure=function(configuration){if("orders" in configuration){this._orders=[];
+this._configureOrders(configuration.orders);
+}if("possibleOrders" in configuration){this._possibleOrders=[];
+this._configurePossibleOrders(configuration.possibleOrders);
+}Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.OrderedViewFrame._settingSpecs,this._settings);
+this._internalValidate();
+};
+Exhibit.OrderedViewFrame.prototype.configureFromDOM=function(domConfiguration){var orders=Exhibit.getAttribute(domConfiguration,"orders",",");
+if(orders!=null&&orders.length>0){this._orders=[];
+this._configureOrders(orders);
+}var directions=Exhibit.getAttribute(domConfiguration,"directions",",");
+if(directions!=null&&directions.length>0&&this._orders!=null){for(var i=0;
+i<directions.length&&i<this._orders.length;
+i++){this._orders[i].ascending=(directions[i].toLowerCase()!="descending");
+}}var possibleOrders=Exhibit.getAttribute(domConfiguration,"possibleOrders",",");
+if(possibleOrders!=null&&possibleOrders.length>0){this._possibleOrders=[];
+this._configurePossibleOrders(possibleOrders);
+}var possibleDirections=Exhibit.getAttribute(domConfiguration,"possibleDirections",",");
+if(possibleDirections!=null&&possibleDirections.length>0&&this._possibleOrders!=null){for(var i=0;
+i<possibleDirections.length&&i<this._possibleOrders.length;
+i++){this._possibleOrders[i].ascending=(possibleDirections[i].toLowerCase()!="descending");
+}}Exhibit.SettingsUtilities.collectSettingsFromDOM(domConfiguration,Exhibit.OrderedViewFrame._settingSpecs,this._settings);
+this._internalValidate();
+};
+Exhibit.OrderedViewFrame.prototype.dispose=function(){if(this._headerDom){this._headerDom.dispose();
+this._headerDom=null;
+}if(this._footerDom){this._footerDom.dispose();
+this._footerDom=null;
+}this._divHeader=null;
+this._divFooter=null;
+this._uiContext=null;
+};
+Exhibit.OrderedViewFrame.prototype._internalValidate=function(){if(this._orders!=null&&this._orders.length==0){this._orders=null;
+}if(this._possibleOrders!=null&&this._possibleOrders.length==0){this._possibleOrders=null;
+}if(this._settings.paginate){this._settings.grouped=false;
+}};
+Exhibit.OrderedViewFrame.prototype._configureOrders=function(orders){for(var i=0;
+i<orders.length;
+i++){var order=orders[i];
+var expr;
+var ascending=true;
+if(typeof order=="string"){expr=order;
+}else{if(typeof order=="object"){expr=order.expression,ascending=("ascending" in order)?(order.ascending):true;
+}else{SimileAjax.Debug.warn("Bad order object "+order);
+continue;
+}}try{var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(path.getSegmentCount()==1){var segment=path.getSegment(0);
+this._orders.push({property:segment.property,forward:segment.forward,ascending:ascending});
+}}}catch(e){SimileAjax.Debug.warn("Bad order expression "+expr);
+}}};
+Exhibit.OrderedViewFrame.prototype._configurePossibleOrders=function(possibleOrders){for(var i=0;
+i<possibleOrders.length;
+i++){var order=possibleOrders[i];
+var expr;
+var ascending=true;
+if(typeof order=="string"){expr=order;
+}else{if(typeof order=="object"){expr=order.expression,ascending=("ascending" in order)?(order.ascending):true;
+}else{SimileAjax.Debug.warn("Bad possible order object "+order);
+continue;
+}}try{var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(path.getSegmentCount()==1){var segment=path.getSegment(0);
+this._possibleOrders.push({property:segment.property,forward:segment.forward,ascending:ascending});
+}}}catch(e){SimileAjax.Debug.warn("Bad possible order expression "+expr);
+}}};
+Exhibit.OrderedViewFrame.prototype.initializeUI=function(){var self=this;
+if(this._settings.showHeader){this._headerDom=Exhibit.OrderedViewFrame.createHeaderDom(this._uiContext,this._divHeader,this._settings.showSummary,this._settings.showControls,function(elmt,evt,target){self._openSortPopup(elmt,-1);
+},function(elmt,evt,target){self._toggleGroup();
+},function(pageIndex){self._gotoPage(pageIndex);
+});
+}if(this._settings.showFooter){this._footerDom=Exhibit.OrderedViewFrame.createFooterDom(this._uiContext,this._divFooter,function(elmt,evt,target){self._setShowAll(true);
+},function(elmt,evt,target){self._setShowAll(false);
+},function(pageIndex){self._gotoPage(pageIndex);
+});
+}};
+Exhibit.OrderedViewFrame.prototype.reconstruct=function(){var self=this;
+var collection=this._uiContext.getCollection();
+var database=this._uiContext.getDatabase();
+var originalSize=collection.countAllItems();
+var currentSize=collection.countRestrictedItems();
+var hasSomeGrouping=false;
+if(currentSize>0){var currentSet=collection.getRestrictedItems();
+hasSomeGrouping=this._internalReconstruct(currentSet);
+var orderElmts=[];
+var buildOrderElmt=function(order,index){var property=database.getProperty(order.property);
+var label=property!=null?(order.forward?property.getPluralLabel():property.getReversePluralLabel()):(order.forward?order.property:"reverse of "+order.property);
+orderElmts.push(Exhibit.UI.makeActionLink(label,function(elmt,evt,target){self._openSortPopup(elmt,index);
+}));
+};
+var orders=this._getOrders();
+for(var i=0;
+i<orders.length;
+i++){buildOrderElmt(orders[i],i);
+}if(this._settings.showHeader&&this._settings.showControls){this._headerDom.setOrders(orderElmts);
+this._headerDom.enableThenByAction(orderElmts.length<this._getPossibleOrders().length);
+}}if(this._settings.showHeader&&this._settings.showControls){this._headerDom.groupOptionWidget.setChecked(this._settings.grouped);
+}if(this._settings.showFooter){this._footerDom.setCounts(currentSize,this._settings.abbreviatedCount,this._settings.showAll,!(hasSomeGrouping&&this._grouped)&&!this._settings.paginate);
+}};
+Exhibit.OrderedViewFrame.prototype._internalReconstruct=function(allItems){var self=this;
+var settings=this._settings;
+var database=this._uiContext.getDatabase();
+var orders=this._getOrders();
+var itemIndex=0;
+var hasSomeGrouping=false;
+var createItem=function(itemID){if((itemIndex>=fromIndex&&itemIndex<toIndex)||(hasSomeGrouping&&settings.grouped)){self.onNewItem(itemID,itemIndex);
+}itemIndex++;
+};
+var createGroup=function(label,valueType,index){if((itemIndex>=fromIndex&&itemIndex<toIndex)||(hasSomeGrouping&&settings.grouped)){self.onNewGroup(label,valueType,index);
+}};
+var processLevel=function(items,index){var order=orders[index];
+var values=order.forward?database.getObjectsUnion(items,order.property):database.getSubjectsUnion(items,order.property);
+var valueType="text";
+if(order.forward){var property=database.getProperty(order.property);
+valueType=property!=null?property.getValueType():"text";
+}else{valueType="item";
+}var keys=(valueType=="item"||valueType=="text")?processNonNumericLevel(items,index,values,valueType):processNumericLevel(items,index,values,valueType);
+var grouped=false;
+for(var k=0;
+k<keys.length;
+k++){if(keys[k].items.size()>1){grouped=true;
+}}if(grouped){hasSomeGrouping=true;
+}for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+if(key.items.size()>0){if(grouped&&settings.grouped){createGroup(key.display,valueType,index);
+}items.removeSet(key.items);
+if(key.items.size()>1&&index<orders.length-1){processLevel(key.items,index+1);
+}else{key.items.visit(createItem);
+}}}if(items.size()>0){if(grouped&&settings.grouped){createGroup(Exhibit.l10n.missingSortKey,valueType,index);
+}if(items.size()>1&&index<orders.length-1){processLevel(items,index+1);
+}else{items.visit(createItem);
+}}};
+var processNonNumericLevel=function(items,index,values,valueType){var keys=[];
+var compareKeys;
+var retrieveItems;
+var order=orders[index];
+if(valueType=="item"){values.visit(function(itemID){var label=database.getObject(itemID,"label");
+label=label!=null?label:itemID;
+keys.push({itemID:itemID,display:label});
+});
+compareKeys=function(key1,key2){var c=key1.display.localeCompare(key2.display);
+return c!=0?c:key1.itemID.localeCompare(key2.itemID);
+};
+retrieveItems=order.forward?function(key){return database.getSubjects(key.itemID,order.property,null,items);
+}:function(key){return database.getObjects(key.itemID,order.property,null,items);
+};
+}else{values.visit(function(value){keys.push({display:value});
+});
+compareKeys=function(key1,key2){return key1.display.localeCompare(key2.display);
+};
+retrieveItems=order.forward?function(key){return database.getSubjects(key.display,order.property,null,items);
+}:function(key){return database.getObjects(key.display,order.property,null,items);
+};
+}keys.sort(function(key1,key2){return(order.ascending?1:-1)*compareKeys(key1,key2);
+});
+for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+key.items=retrieveItems(key);
+if(!settings.showDuplicates){items.removeSet(key.items);
+}}return keys;
+};
+var processNumericLevel=function(items,index,values,valueType){var keys=[];
+var keyMap={};
+var order=orders[index];
+var valueParser;
+if(valueType=="number"){valueParser=function(value){if(typeof value=="number"){return value;
+}else{try{return parseFloat(value);
+}catch(e){return null;
+}}};
+}else{valueParser=function(value){if(value instanceof Date){return value.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(value.toString()).getTime();
+}catch(e){return null;
+}}};
+}values.visit(function(value){var sortkey=valueParser(value);
+if(sortkey!=null){var key=keyMap[sortkey];
+if(!key){key={sortkey:sortkey,display:value,values:[],items:new Exhibit.Set()};
+keyMap[sortkey]=key;
+keys.push(key);
+}key.values.push(value);
+}});
+keys.sort(function(key1,key2){return(order.ascending?1:-1)*(key1.sortkey-key2.sortkey);
+});
+for(var k=0;
+k<keys.length;
+k++){var key=keys[k];
+var values=key.values;
+for(var v=0;
+v<values.length;
+v++){if(order.forward){database.getSubjects(values[v],order.property,key.items,items);
+}else{database.getObjects(values[v],order.property,key.items,items);
+}}if(!settings.showDuplicates){items.removeSet(key.items);
+}}return keys;
+};
+var totalCount=allItems.size();
+var pageCount=Math.ceil(totalCount/settings.pageSize);
+var fromIndex=0;
+var toIndex=settings.showAll?totalCount:Math.min(totalCount,settings.abbreviatedCount);
+if(!settings.grouped&&settings.paginate&&(pageCount>1||(pageCount>0&&settings.alwaysShowPagingControls))){fromIndex=settings.page*settings.pageSize;
+toIndex=Math.min(fromIndex+settings.pageSize,totalCount);
+if(settings.showHeader&&(settings.pagingControlLocations=="top"||settings.pagingControlLocations=="topbottom")){this._headerDom.renderPageLinks(settings.page,pageCount,settings.pageWindow);
+}if(settings.showFooter&&(settings.pagingControlLocations=="bottom"||settings.pagingControlLocations=="topbottom")){this._footerDom.renderPageLinks(settings.page,pageCount,settings.pageWindow);
+}}else{if(settings.showHeader){this._headerDom.hidePageLinks();
+}if(settings.showFooter){this._footerDom.hidePageLinks();
+}}processLevel(allItems,0);
+return hasSomeGrouping;
+};
+Exhibit.OrderedViewFrame.prototype._getOrders=function(){return this._orders||[this._getPossibleOrders()[0]];
+};
+Exhibit.OrderedViewFrame.prototype._getPossibleOrders=function(){var possibleOrders=null;
+if(this._possibleOrders==null){possibleOrders=this._uiContext.getDatabase().getAllProperties();
+for(var i=0,p;
+p=possibleOrders[i];
+i++){possibleOrders[i]={ascending:true,forward:true,property:p};
+}}else{possibleOrders=[].concat(this._possibleOrders);
+}if(possibleOrders.length==0){possibleOrders.push({property:"label",forward:true,ascending:true});
+}return possibleOrders;
+};
+Exhibit.OrderedViewFrame.prototype._openSortPopup=function(elmt,index){var self=this;
+var database=this._uiContext.getDatabase();
+var popupDom=Exhibit.UI.createPopupMenuDom(elmt);
+var configuredOrders=this._getOrders();
+if(index>=0){var order=configuredOrders[index];
+var property=database.getProperty(order.property);
+var propertyLabel=order.forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=order.forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+popupDom.appendMenuItem(sortLabels.ascending,Exhibit.urlPrefix+(order.ascending?"images/option-check.png":"images/option.png"),order.ascending?function(){}:function(){self._reSort(index,order.property,order.forward,true,false);
+});
+popupDom.appendMenuItem(sortLabels.descending,Exhibit.urlPrefix+(order.ascending?"images/option.png":"images/option-check.png"),order.ascending?function(){self._reSort(index,order.property,order.forward,false,false);
+}:function(){});
+if(configuredOrders.length>1){popupDom.appendSeparator();
+popupDom.appendMenuItem(Exhibit.OrderedViewFrame.l10n.removeOrderLabel,null,function(){self._removeOrder(index);
+});
+}}var orders=[];
+var possibleOrders=this._getPossibleOrders();
+for(i=0;
+i<possibleOrders.length;
+i++){var possibleOrder=possibleOrders[i];
+var skip=false;
+for(var j=(index<0)?configuredOrders.length-1:index;
+j>=0;
+j--){var existingOrder=configuredOrders[j];
+if(existingOrder.property==possibleOrder.property&&existingOrder.forward==possibleOrder.forward){skip=true;
+break;
+}}if(!skip){var property=database.getProperty(possibleOrder.property);
+orders.push({property:possibleOrder.property,forward:possibleOrder.forward,ascending:possibleOrder.ascending,label:possibleOrder.forward?property.getPluralLabel():property.getReversePluralLabel()});
+}}if(orders.length>0){if(index>=0){popupDom.appendSeparator();
+}orders.sort(function(order1,order2){return order1.label.localeCompare(order2.label);
+});
+var appendOrder=function(order){popupDom.appendMenuItem(order.label,null,function(){self._reSort(index,order.property,order.forward,order.ascending,true);
+});
+};
+for(var i=0;
+i<orders.length;
+i++){appendOrder(orders[i]);
+}}popupDom.open();
+};
+Exhibit.OrderedViewFrame.prototype._reSort=function(index,propertyID,forward,ascending,slice){var oldOrders=this._getOrders();
+index=(index<0)?oldOrders.length:index;
+var newOrders=oldOrders.slice(0,index);
+newOrders.push({property:propertyID,forward:forward,ascending:ascending});
+if(!slice){newOrders=newOrders.concat(oldOrders.slice(index+1));
+}var property=this._uiContext.getDatabase().getProperty(propertyID);
+var propertyLabel=forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._orders=newOrders;
+self.parentReconstruct();
+},function(){self._orders=oldOrders;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.formatSortActionTitle(propertyLabel,ascending?sortLabels.ascending:sortLabels.descending));
+};
+Exhibit.OrderedViewFrame.prototype._removeOrder=function(index){var oldOrders=this._getOrders();
+var newOrders=oldOrders.slice(0,index).concat(oldOrders.slice(index+1));
+var order=oldOrders[index];
+var property=this._uiContext.getDatabase().getProperty(order.property);
+var propertyLabel=order.forward?property.getPluralLabel():property.getReversePluralLabel();
+var valueType=order.forward?property.getValueType():"item";
+var sortLabels=Exhibit.Database.l10n.sortLabels[valueType];
+sortLabels=(sortLabels!=null)?sortLabels:Exhibit.Database.l10n.sortLabels["text"];
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._orders=newOrders;
+self.parentReconstruct();
+},function(){self._orders=oldOrders;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle(propertyLabel,order.ascending?sortLabels.ascending:sortLabels.descending));
+};
+Exhibit.OrderedViewFrame.prototype._setShowAll=function(showAll){var self=this;
+var settings=this._settings;
+SimileAjax.History.addLengthyAction(function(){settings.showAll=showAll;
+self.parentReconstruct();
+},function(){settings.showAll=!showAll;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[showAll?"showAllActionTitle":"dontShowAllActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._toggleGroup=function(){var settings=this._settings;
+var oldGrouped=settings.grouped;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.grouped=!oldGrouped;
+self.parentReconstruct();
+},function(){settings.grouped=oldGrouped;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[oldGrouped?"ungroupAsSortedActionTitle":"groupAsSortedActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._toggleShowDuplicates=function(){var settings=this._settings;
+var oldShowDuplicates=settings.showDuplicates;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.showDuplicates=!oldShowDuplicates;
+self.parentReconstruct();
+},function(){settings.showDuplicates=oldShowDuplicates;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n[oldShowDuplicates?"hideDuplicatesActionTitle":"showDuplicatesActionTitle"]);
+};
+Exhibit.OrderedViewFrame.prototype._gotoPage=function(pageIndex){var settings=this._settings;
+var oldPageIndex=settings.page;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.page=pageIndex;
+self.parentReconstruct();
+},function(){settings.page=oldPageIndex;
+self.parentReconstruct();
+},Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(pageIndex));
+};
+Exhibit.OrderedViewFrame.headerTemplate="<div id='collectionSummaryDiv' style='display: none;'></div><div class='exhibit-collectionView-header-sortControls' style='display: none;' id='controlsDiv'>%0<span class='exhibit-collectionView-header-groupControl'> \u2022 <a id='groupOption' class='exhibit-action'></a></span></div>";
+Exhibit.OrderedViewFrame.createHeaderDom=function(uiContext,headerDiv,showSummary,showControls,onThenSortBy,onGroupToggle,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+var template=String.substitute(Exhibit.OrderedViewFrame.headerTemplate+"<"+l10n.pagingControlContainerElement+" class='exhibit-collectionView-pagingControls' style='display: none;' id='topPagingDiv'></"+l10n.pagingControlContainerElement+">",[l10n.sortingControlsTemplate]);
+var dom=SimileAjax.DOM.createDOMFromString(headerDiv,template,{});
+headerDiv.className="exhibit-collectionView-header";
+if(showSummary){dom.collectionSummaryDiv.style.display="block";
+dom.collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},dom.collectionSummaryDiv,uiContext);
+}if(showControls){dom.controlsDiv.style.display="block";
+dom.groupOptionWidget=Exhibit.OptionWidget.create({label:l10n.groupedAsSortedOptionLabel,onToggle:onGroupToggle},dom.groupOption,uiContext);
+SimileAjax.WindowManager.registerEvent(dom.thenSortByAction,"click",onThenSortBy);
+dom.enableThenByAction=function(enabled){Exhibit.UI.enableActionLink(dom.thenSortByAction,enabled);
+};
+dom.setOrders=function(orderElmts){dom.ordersSpan.innerHTML="";
+var addDelimiter=Exhibit.Formatter.createListDelimiter(dom.ordersSpan,orderElmts.length,uiContext);
+for(var i=0;
+i<orderElmts.length;
+i++){addDelimiter();
+dom.ordersSpan.appendChild(orderElmts[i]);
+}addDelimiter();
+};
+}dom.renderPageLinks=function(page,totalPage,pageWindow){Exhibit.OrderedViewFrame.renderPageLinks(dom.topPagingDiv,page,totalPage,pageWindow,gotoPage);
+dom.topPagingDiv.style.display="block";
+};
+dom.hidePageLinks=function(){dom.topPagingDiv.style.display="none";
+};
+dom.dispose=function(){if("collectionSummaryWidget" in dom){dom.collectionSummaryWidget.dispose();
+dom.collectionSummaryWidget=null;
+}dom.groupOptionWidget.dispose();
+dom.groupOptionWidget=null;
+};
+return dom;
+};
+Exhibit.OrderedViewFrame.footerTemplate="<div id='showAllSpan'></div>";
+Exhibit.OrderedViewFrame.createFooterDom=function(uiContext,footerDiv,onShowAll,onDontShowAll,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+var dom=SimileAjax.DOM.createDOMFromString(footerDiv,Exhibit.OrderedViewFrame.footerTemplate+"<"+l10n.pagingControlContainerElement+" class='exhibit-collectionView-pagingControls' style='display: none;' id='bottomPagingDiv'></"+l10n.pagingControlContainerElement+">",{});
+footerDiv.className="exhibit-collectionView-footer";
+dom.setCounts=function(count,limitCount,showAll,canToggle){dom.showAllSpan.innerHTML="";
+if(canToggle&&count>limitCount){dom.showAllSpan.style.display="block";
+if(showAll){dom.showAllSpan.appendChild(Exhibit.UI.makeActionLink(l10n.formatDontShowAll(limitCount),onDontShowAll));
+}else{dom.showAllSpan.appendChild(Exhibit.UI.makeActionLink(l10n.formatShowAll(count),onShowAll));
+}}};
+dom.renderPageLinks=function(page,totalPage,pageWindow){Exhibit.OrderedViewFrame.renderPageLinks(dom.bottomPagingDiv,page,totalPage,pageWindow,gotoPage);
+dom.bottomPagingDiv.style.display="block";
+dom.showAllSpan.style.display="none";
+};
+dom.hidePageLinks=function(){dom.bottomPagingDiv.style.display="none";
+};
+dom.dispose=function(){};
+return dom;
+};
+Exhibit.OrderedViewFrame.renderPageLinks=function(parentElmt,page,pageCount,pageWindow,gotoPage){var l10n=Exhibit.OrderedViewFrame.l10n;
+parentElmt.className="exhibit-collectionView-pagingControls";
+parentElmt.innerHTML="";
+var self=this;
+var renderPageLink=function(label,index){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.className="exhibit-collectionView-pagingControls-page";
+parentElmt.appendChild(elmt);
+var a=document.createElement("a");
+a.innerHTML=label;
+a.href="javascript:{}";
+a.title=l10n.makePagingLinkTooltip(index);
+elmt.appendChild(a);
+var handler=function(elmt,evt,target){gotoPage(index);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.WindowManager.registerEvent(a,"click",handler);
+};
+var renderPageNumber=function(index){if(index==page){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.className="exhibit-collectionView-pagingControls-currentPage";
+elmt.innerHTML=(index+1);
+parentElmt.appendChild(elmt);
+}else{renderPageLink(index+1,index);
+}};
+var renderHTML=function(html){var elmt=document.createElement(l10n.pagingControlElement);
+elmt.innerHTML=html;
+parentElmt.appendChild(elmt);
+};
+if(page>0){renderPageLink(l10n.previousPage,page-1);
+if(l10n.pageSeparator.length>0){renderHTML(" ");
+}}var pageWindowStart=0;
+var pageWindowEnd=pageCount-1;
+if(page-pageWindow>1){renderPageNumber(0);
+renderHTML(l10n.pageWindowEllipses);
+pageWindowStart=page-pageWindow;
+}if(page+pageWindow<pageCount-2){pageWindowEnd=page+pageWindow;
+}for(var i=pageWindowStart;
+i<=pageWindowEnd;
+i++){if(i>pageWindowStart&&l10n.pageSeparator.length>0){renderHTML(l10n.pageSeparator);
+}renderPageNumber(i);
+}if(pageWindowEnd<pageCount-1){renderHTML(l10n.pageWindowEllipses);
+renderPageNumber(pageCount-1);
+}if(page<pageCount-1){if(l10n.pageSeparator.length>0){renderHTML(" ");
+}renderPageLink(l10n.nextPage,page+1);
+}};
+
+
+/* tabular-view.js */
+Exhibit.TabularView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={rowStyler:null,tableStyler:null};
+this._columns=[];
+this._rowTemplate=null;
+var view=this;
+this._listener={onItemsChanged:function(){view._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+};
+Exhibit.TabularView._settingSpecs={"sortAscending":{type:"boolean",defaultValue:true},"sortColumn":{type:"int",defaultValue:0},"showSummary":{type:"boolean",defaultValue:true},"showToolbox":{type:"boolean",defaultValue:true},"border":{type:"int",defaultValue:1},"cellPadding":{type:"int",defaultValue:5},"cellSpacing":{type:"int",defaultValue:3},"paginate":{type:"boolean",defaultValue:false},"pageSize":{type:"int",defaultValue:20},"pageWindow":{type:"int",defaultValue:2},"page":{type:"int",defaultValue:0},"alwaysShowPagingControls":{type:"boolean",defaultValue:false},"pagingControlLocations":{type:"enum",defaultValue:"topbottom",choices:["top","bottom","topbottom"]}};
+Exhibit.TabularView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.TabularView(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.TabularView._configure(view,configuration);
+view._internalValidate();
+view._initializeUI();
+return view;
+};
+Exhibit.TabularView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+uiContext=Exhibit.UIContext.createFromDOM(configElmt,uiContext);
+var view=new Exhibit.TabularView(containerElmt!=null?containerElmt:configElmt,uiContext);
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TabularView._settingSpecs,view._settings);
+try{var expressions=[];
+var labels=Exhibit.getAttribute(configElmt,"columnLabels",",")||[];
+var s=Exhibit.getAttribute(configElmt,"columns");
+if(s!=null&&s.length>0){expressions=Exhibit.ExpressionParser.parseSeveral(s);
+}for(var i=0;
+i<expressions.length;
+i++){var expression=expressions[i];
+view._columns.push({expression:expression,uiContext:Exhibit.UIContext.create({},view._uiContext,true),styler:null,label:i<labels.length?labels[i]:null,format:"list"});
+}var formats=Exhibit.getAttribute(configElmt,"columnFormats");
+if(formats!=null&&formats.length>0){var index=0;
+var startPosition=0;
+while(index<view._columns.length&&startPosition<formats.length){var column=view._columns[index];
+var o={};
+column.format=Exhibit.FormatParser.parseSeveral(column.uiContext,formats,startPosition,o);
+startPosition=o.index;
+while(startPosition<formats.length&&" \t\r\n".indexOf(formats.charAt(startPosition))>=0){startPosition++;
+}if(startPosition<formats.length&&formats.charAt(startPosition)==","){startPosition++;
+}index++;
+}}var tables=configElmt.getElementsByTagName("table");
+if(tables.length>0&&tables[0].rows.length>0){view._rowTemplate=Exhibit.Lens.compileTemplate(tables[0].rows[0],false,uiContext);
+}}catch(e){SimileAjax.Debug.exception(e,"TabularView: Error processing configuration of tabular view");
+}var s=Exhibit.getAttribute(configElmt,"rowStyler");
+if(s!=null&&s.length>0){var f=eval(s);
+if(typeof f=="function"){view._settings.rowStyler=f;
+}}s=Exhibit.getAttribute(configElmt,"tableStyler");
+if(s!=null&&s.length>0){f=eval(s);
+if(typeof f=="function"){view._settings.tableStyler=f;
+}}Exhibit.TabularView._configure(view,configuration);
+view._internalValidate();
+view._initializeUI();
+return view;
+};
+Exhibit.TabularView._configure=function(view,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TabularView._settingSpecs,view._settings);
+if("columns" in configuration){var columns=configuration.columns;
+for(var i=0;
+i<columns.length;
+i++){var column=columns[i];
+var expr;
+var styler=null;
+var label=null;
+var format=null;
+if(typeof column=="string"){expr=column;
+}else{expr=column.expression;
+styler=column.styler;
+label=column.label;
+format=column.format;
+}var expression=Exhibit.ExpressionParser.parse(expr);
+if(expression.isPath()){var path=expression.getPath();
+if(format!=null&&format.length>0){format=Exhibit.FormatParser.parse(view._uiContext,format,0);
+}else{format="list";
+}view._columns.push({expression:expression,styler:styler,label:label,format:format,uiContext:view._uiContext});
+}}}if("rowStyler" in configuration){view._settings.rowStyler=configuration.rowStyler;
+}if("tableStyler" in configuration){view._settings.tableStyler=configuration.tableStyler;
+}};
+Exhibit.TabularView.prototype._internalValidate=function(){if(this._columns.length==0){var database=this._uiContext.getDatabase();
+var propertyIDs=database.getAllProperties();
+for(var i=0;
+i<propertyIDs.length;
+i++){var propertyID=propertyIDs[i];
+if(propertyID!="uri"){this._columns.push({expression:Exhibit.ExpressionParser.parse("."+propertyID),styler:null,label:database.getProperty(propertyID).getLabel(),format:"list"});
+}}}this._settings.sortColumn=Math.max(0,Math.min(this._settings.sortColumn,this._columns.length-1));
+};
+Exhibit.TabularView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._collectionSummaryWidget.dispose();
+this._collectionSummaryWidget=null;
+this._uiContext.dispose();
+this._uiContext=null;
+this._div.innerHTML="";
+this._dom=null;
+this._div=null;
+};
+Exhibit.TabularView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+this._dom=Exhibit.TabularView.createDom(this._div);
+this._collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},this._dom.collectionSummaryDiv,this._uiContext);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}if(!this._settings.showSummary){this._dom.collectionSummaryDiv.style.display="none";
+}this._reconstruct();
+};
+Exhibit.TabularView.prototype._reconstruct=function(){var self=this;
+var collection=this._uiContext.getCollection();
+var database=this._uiContext.getDatabase();
+var bodyDiv=this._dom.bodyDiv;
+bodyDiv.innerHTML="";
+var items=[];
+var originalSize=collection.countAllItems();
+if(originalSize>0){var currentSet=collection.getRestrictedItems();
+currentSet.visit(function(itemID){items.push({id:itemID,sortKey:""});
+});
+}if(items.length>0){var sortColumn=this._columns[this._settings.sortColumn];
+items.sort(this._createSortFunction(items,sortColumn.expression,this._settings.sortAscending));
+var table=document.createElement("table");
+table.className="exhibit-tabularView-body";
+if(this._settings.tableStyler!=null){this._settings.tableStyler(table,database);
+}else{table.cellSpacing=this._settings.cellSpacing;
+table.cellPadding=this._settings.cellPadding;
+table.border=this._settings.border;
+}var tr=table.insertRow(0);
+var createColumnHeader=function(i){var column=self._columns[i];
+if(column.label==null){column.label=self._getColumnLabel(column.expression);
+}var td=document.createElement("th");
+Exhibit.TabularView.createColumnHeader(exhibit,td,column.label,i==self._settings.sortColumn,self._settings.sortAscending,function(elmt,evt,target){self._doSort(i);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+});
+tr.appendChild(td);
+};
+for(var i=0;
+i<this._columns.length;
+i++){createColumnHeader(i);
+}var renderItem;
+if(this._rowTemplate!=null){renderItem=function(i){var item=items[i];
+var tr=Exhibit.Lens.constructFromLensTemplate(item.id,self._rowTemplate,table,self._uiContext);
+if(self._settings.rowStyler!=null){self._settings.rowStyler(item.id,database,tr,i);
+}};
+}else{renderItem=function(i){var item=items[i];
+var tr=table.insertRow(table.rows.length);
+for(var c=0;
+c<self._columns.length;
+c++){var column=self._columns[c];
+var td=tr.insertCell(c);
+var results=column.expression.evaluate({"value":item.id},{"value":"item"},"value",database);
+var valueType=column.format=="list"?results.valueType:column.format;
+column.uiContext.formatList(results.values,results.size,valueType,function(elmt){td.appendChild(elmt);
+});
+if(column.styler!=null){column.styler(item.id,database,td);
+}}if(self._settings.rowStyler!=null){self._settings.rowStyler(item.id,database,tr,i);
+}};
+}var start,end;
+var generatePagingControls=false;
+if(this._settings.paginate){start=this._settings.page*this._settings.pageSize;
+end=Math.min(start+this._settings.pageSize,items.length);
+generatePagingControls=(items.length>this._settings.pageSize)||(items.length>0&&this._settings.alwaysShowPagingControls);
+}else{start=0;
+end=items.length;
+}for(var i=start;
+i<end;
+i++){renderItem(i);
+}bodyDiv.appendChild(table);
+if(generatePagingControls){if(this._settings.pagingControlLocations=="top"||this._settings.pagingControlLocations=="topbottom"){this._renderPagingDiv(this._dom.topPagingDiv,items.length,this._settings.page);
+this._dom.topPagingDiv.style.display="block";
+}if(this._settings.pagingControlLocations=="bottom"||this._settings.pagingControlLocations=="topbottom"){this._renderPagingDiv(this._dom.bottomPagingDiv,items.length,this._settings.page);
+this._dom.bottomPagingDiv.style.display="block";
+}}else{this._dom.topPagingDiv.style.display="none";
+this._dom.bottomPagingDiv.style.display="none";
+}}};
+Exhibit.TabularView.prototype._renderPagingDiv=function(parentElmt,itemCount,page){var pageCount=Math.ceil(itemCount/this._settings.pageSize);
+var self=this;
+Exhibit.OrderedViewFrame.renderPageLinks(parentElmt,page,pageCount,this._settings.pageWindow,function(p){self._gotoPage(p);
+});
+};
+Exhibit.TabularView.prototype._getColumnLabel=function(expression){var database=this._uiContext.getDatabase();
+var path=expression.getPath();
+var segment=path.getSegment(path.getSegmentCount()-1);
+var propertyID=segment.property;
+var property=database.getProperty(propertyID);
+if(property!=null){return segment.forward?property.getLabel():property.getReverseLabel();
+}else{return propertyID;
+}};
+Exhibit.TabularView.prototype._createSortFunction=function(items,expression,ascending){var database=this._uiContext.getDatabase();
+var multiply=ascending?1:-1;
+var numericFunction=function(item1,item2){return multiply*(item1.sortKey-item2.sortKey);
+};
+var textFunction=function(item1,item2){return multiply*item1.sortKey.localeCompare(item2.sortKey);
+};
+var valueTypes=[];
+var valueTypeMap={};
+for(var i=0;
+i<items.length;
+i++){var item=items[i];
+var r=expression.evaluate({"value":item.id},{"value":"item"},"value",database);
+r.values.visit(function(value){item.sortKey=value;
+});
+if(!(r.valueType in valueTypeMap)){valueTypeMap[r.valueType]=true;
+valueTypes.push(r.valueType);
+}}var coercedValueType="text";
+if(valueTypes.length==1){coercedValueType=valueTypes[0];
+}else{coercedValueType="text";
+}var coersion;
+var sortingFunction;
+if(coercedValueType=="number"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(typeof v=="number"){return v;
+}else{var n=parseFloat(v);
+if(isNaN(n)){return Number.NEGATIVE_INFINITY;
+}else{return n;
+}}}};
+}else{if(coercedValueType=="date"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(v instanceof Date){return v.getTime();
+}else{try{return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+}catch(e){return Number.NEGATIVE_INFINITY;
+}}}};
+}else{if(coercedValueType=="boolean"){sortingFunction=numericFunction;
+coersion=function(v){if(v==null){return Number.NEGATIVE_INFINITY;
+}else{if(typeof v=="boolean"){return v?1:0;
+}else{return v.toString().toLowerCase()=="true";
+}}};
+}else{if(coercedValueType=="item"){sortingFunction=textFunction;
+coersion=function(v){if(v==null){return Exhibit.l10n.missingSortKey;
+}else{var label=database.getObject(v,"label");
+return(label==null)?v:label;
+}};
+}else{sortingFunction=textFunction;
+coersion=function(v){if(v==null){return Exhibit.l10n.missingSortKey;
+}else{return v.toString();
+}};
+}}}}for(var i=0;
+i<items.length;
+i++){var item=items[i];
+item.sortKey=coersion(item.sortKey);
+}return sortingFunction;
+};
+Exhibit.TabularView.prototype._doSort=function(columnIndex){var oldSortColumn=this._settings.sortColumn;
+var oldSortAscending=this._settings.sortAscending;
+var newSortColumn=columnIndex;
+var newSortAscending=oldSortColumn==newSortColumn?!oldSortAscending:true;
+var oldPage=this._settings.page;
+var newPage=0;
+var settings=this._settings;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.sortColumn=newSortColumn;
+settings.sortAscending=newSortAscending;
+settings.page=newPage;
+self._reconstruct();
+},function(){settings.sortColumn=oldSortColumn;
+settings.sortAscending=oldSortAscending;
+settings.page=oldPage;
+self._reconstruct();
+},Exhibit.TabularView.l10n.makeSortActionTitle(this._columns[columnIndex].label,newSortAscending));
+};
+Exhibit.TabularView.prototype._gotoPage=function(page){var oldPage=this._settings.page;
+var newPage=page;
+var settings=this._settings;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){settings.page=newPage;
+self._reconstruct();
+},function(){settings.page=oldPage;
+self._reconstruct();
+},Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(page));
+};
+Exhibit.TabularView._constructDefaultValueList=function(values,valueType,parentElmt,uiContext){uiContext.formatList(values,values.size(),valueType,function(elmt){parentElmt.appendChild(elmt);
+});
+};
+Exhibit.TabularView.createDom=function(div){var l10n=Exhibit.TabularView.l10n;
+var l10n2=Exhibit.OrderedViewFrame.l10n;
+var headerTemplate={elmt:div,className:"exhibit-collectionView-header",children:[{tag:"div",field:"collectionSummaryDiv"},{tag:l10n2.pagingControlContainerElement,className:"exhibit-tabularView-pagingControls",field:"topPagingDiv"},{tag:"div",field:"bodyDiv"},{tag:l10n2.pagingControlContainerElement,className:"exhibit-tabularView-pagingControls",field:"bottomPagingDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(headerTemplate);
+};
+Exhibit.TabularView.createColumnHeader=function(exhibit,th,label,sort,sortAscending,sortFunction){var l10n=Exhibit.TabularView.l10n;
+var template={elmt:th,className:sort?"exhibit-tabularView-columnHeader-sorted":"exhibit-tabularView-columnHeader",title:sort?l10n.columnHeaderReSortTooltip:l10n.columnHeaderSortTooltip,children:[label]};
+if(sort){template.children.push({elmt:Exhibit.UI.createTranslucentImage(sortAscending?"images/up-arrow.png":"images/down-arrow.png")});
+}SimileAjax.WindowManager.registerEvent(th,"click",sortFunction,null);
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+return dom;
+};
+
+
+/* thumbnail-view.js */
+Exhibit.ThumbnailView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+var view=this;
+this._listener={onItemsChanged:function(){view._orderedViewFrame._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+this._orderedViewFrame=new Exhibit.OrderedViewFrame(uiContext);
+this._orderedViewFrame.parentReconstruct=function(){view._reconstruct();
+};
+};
+Exhibit.ThumbnailView._settingSpecs={"showToolbox":{type:"boolean",defaultValue:true},"columnCount":{type:"int",defaultValue:-1}};
+Exhibit.ThumbnailView._itemContainerClass=SimileAjax.Platform.browser.isIE?"exhibit-thumbnailView-itemContainer-IE":"exhibit-thumbnailView-itemContainer";
+Exhibit.ThumbnailView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.ThumbnailView(containerElmt,Exhibit.UIContext.create(configuration,uiContext,true));
+view._lensRegistry=Exhibit.UIContext.createLensRegistry(configuration,uiContext.getLensRegistry());
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ThumbnailView._settingSpecs,view._settings);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.ThumbnailView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var view=new Exhibit.ThumbnailView(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext,true));
+view._lensRegistry=Exhibit.UIContext.createLensRegistryFromDOM(configElmt,configuration,uiContext.getLensRegistry());
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ThumbnailView._settingSpecs,view._settings);
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ThumbnailView._settingSpecs,view._settings);
+view._orderedViewFrame.configureFromDOM(configElmt);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.ThumbnailView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._orderedViewFrame.dispose();
+this._orderedViewFrame=null;
+this._lensRegistry=null;
+this._dom=null;
+this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.ThumbnailView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+var template={elmt:this._div,children:[{tag:"div",field:"headerDiv"},{tag:"div",className:"exhibit-collectionView-body",field:"bodyDiv"},{tag:"div",field:"footerDiv"}]};
+this._dom=SimileAjax.DOM.createDOMFromTemplate(template);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}this._orderedViewFrame._divHeader=this._dom.headerDiv;
+this._orderedViewFrame._divFooter=this._dom.footerDiv;
+this._orderedViewFrame._generatedContentElmtRetriever=function(){return self._dom.bodyDiv;
+};
+this._orderedViewFrame.initializeUI();
+this._reconstruct();
+};
+Exhibit.ThumbnailView.prototype._reconstruct=function(){if(this._settings.columnCount<2){this._reconstructWithFloats();
+}else{this._reconstructWithTable();
+}};
+Exhibit.ThumbnailView.prototype._reconstructWithFloats=function(){var view=this;
+var state={div:this._dom.bodyDiv,itemContainer:null,groupDoms:[],groupCounts:[]};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.itemContainer=null;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.ThumbnailView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.itemContainer==null){state.itemContainer=Exhibit.ThumbnailView.constructItemContainer();
+state.div.appendChild(state.itemContainer);
+}for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensDiv=document.createElement("div");
+itemLensDiv.className=Exhibit.ThumbnailView._itemContainerClass;
+var itemLens=view._lensRegistry.createLens(itemID,itemLensDiv,view._uiContext);
+state.itemContainer.appendChild(itemLensDiv);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.ThumbnailView.prototype._reconstructWithTable=function(){var view=this;
+var state={div:this._dom.bodyDiv,groupDoms:[],groupCounts:[],table:null,columnIndex:0};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.itemContainer=null;
+state.table=null;
+state.columnIndex=0;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.ThumbnailView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.columnIndex>=view._settings.columnCount){state.columnIndex=0;
+}if(state.table==null){state.table=Exhibit.ThumbnailView.constructTableItemContainer();
+state.div.appendChild(state.table);
+}if(state.columnIndex==0){state.table.insertRow(state.table.rows.length);
+}var td=state.table.rows[state.table.rows.length-1].insertCell(state.columnIndex++);
+for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensDiv=document.createElement("div");
+itemLensDiv.className=Exhibit.ThumbnailView._itemContainerClass;
+var itemLens=view._lensRegistry.createLens(itemID,itemLensDiv,view._uiContext);
+td.appendChild(itemLensDiv);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.ThumbnailView.constructGroup=function(groupLevel,label){var l10n=Exhibit.ThumbnailView.l10n;
+var template={tag:"div",className:"exhibit-thumbnailView-group",children:[{tag:"h"+(groupLevel+1),children:[label,{tag:"span",className:"exhibit-collectionView-group-count",children:[" (",{tag:"span",field:"countSpan"},")"]}],field:"header"},{tag:"div",className:"exhibit-collectionView-group-content",field:"contentDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+Exhibit.ThumbnailView.constructItemContainer=function(){var div=document.createElement("div");
+div.className="exhibit-thumbnailView-body";
+return div;
+};
+Exhibit.ThumbnailView.constructTableItemContainer=function(){var table=document.createElement("table");
+table.className="exhibit-thumbnailView-body";
+return table;
+};
+
+
+/* tile-view.js */
+Exhibit.TileView=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+var view=this;
+this._listener={onItemsChanged:function(){view._orderedViewFrame._settings.page=0;
+view._reconstruct();
+}};
+uiContext.getCollection().addListener(this._listener);
+this._orderedViewFrame=new Exhibit.OrderedViewFrame(uiContext);
+this._orderedViewFrame.parentReconstruct=function(){view._reconstruct();
+};
+};
+Exhibit.TileView._settingSpecs={"showToolbox":{type:"boolean",defaultValue:true}};
+Exhibit.TileView.create=function(configuration,containerElmt,uiContext){var view=new Exhibit.TileView(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TileView._settingSpecs,view._settings);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.TileView.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var view=new Exhibit.TileView(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.TileView._settingSpecs,view._settings);
+Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.TileView._settingSpecs,view._settings);
+view._orderedViewFrame.configureFromDOM(configElmt);
+view._orderedViewFrame.configure(configuration);
+view._initializeUI();
+return view;
+};
+Exhibit.TileView.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+this._div.innerHTML="";
+if(this._toolboxWidget){this._toolboxWidget.dispose();
+this._toolboxWidget=null;
+}this._orderedViewFrame.dispose();
+this._orderedViewFrame=null;
+this._dom=null;
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.TileView.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="";
+var template={elmt:this._div,children:[{tag:"div",field:"headerDiv"},{tag:"div",className:"exhibit-collectionView-body",field:"bodyDiv"},{tag:"div",field:"footerDiv"}]};
+this._dom=SimileAjax.DOM.createDOMFromTemplate(template);
+if(this._settings.showToolbox){this._toolboxWidget=Exhibit.ToolboxWidget.createFromDOM(this._div,this._div,this._uiContext);
+this._toolboxWidget.getGeneratedHTML=function(){return self._dom.bodyDiv.innerHTML;
+};
+}this._orderedViewFrame._divHeader=this._dom.headerDiv;
+this._orderedViewFrame._divFooter=this._dom.footerDiv;
+this._orderedViewFrame._generatedContentElmtRetriever=function(){return self._dom.bodyDiv;
+};
+this._orderedViewFrame.initializeUI();
+this._reconstruct();
+};
+Exhibit.TileView.prototype._reconstruct=function(){var view=this;
+var state={div:this._dom.bodyDiv,contents:null,groupDoms:[],groupCounts:[]};
+var closeGroups=function(groupLevel){for(var i=groupLevel;
+i<state.groupDoms.length;
+i++){state.groupDoms[i].countSpan.innerHTML=state.groupCounts[i];
+}state.groupDoms=state.groupDoms.slice(0,groupLevel);
+state.groupCounts=state.groupCounts.slice(0,groupLevel);
+if(groupLevel>0){state.div=state.groupDoms[groupLevel-1].contentDiv;
+}else{state.div=view._dom.bodyDiv;
+}state.contents=null;
+};
+this._orderedViewFrame.onNewGroup=function(groupSortKey,keyType,groupLevel){closeGroups(groupLevel);
+var groupDom=Exhibit.TileView.constructGroup(groupLevel,groupSortKey);
+state.div.appendChild(groupDom.elmt);
+state.div=groupDom.contentDiv;
+state.groupDoms.push(groupDom);
+state.groupCounts.push(0);
+};
+this._orderedViewFrame.onNewItem=function(itemID,index){if(state.contents==null){state.contents=Exhibit.TileView.constructList();
+state.div.appendChild(state.contents);
+}for(var i=0;
+i<state.groupCounts.length;
+i++){state.groupCounts[i]++;
+}var itemLensItem=document.createElement("li");
+var itemLens=view._uiContext.getLensRegistry().createLens(itemID,itemLensItem,view._uiContext);
+state.contents.appendChild(itemLensItem);
+};
+this._div.style.display="none";
+this._dom.bodyDiv.innerHTML="";
+this._orderedViewFrame.reconstruct();
+closeGroups(0);
+this._div.style.display="block";
+};
+Exhibit.TileView.constructGroup=function(groupLevel,label){var template={tag:"div",className:"exhibit-collectionView-group",children:[{tag:"h"+(groupLevel+1),children:[label,{tag:"span",className:"exhibit-collectionView-group-count",children:[" (",{tag:"span",field:"countSpan"},")"]}],field:"header"},{tag:"div",className:"exhibit-collectionView-group-content",field:"contentDiv"}]};
+return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+Exhibit.TileView.constructList=function(){var div=document.createElement("ol");
+div.className="exhibit-tileView-body";
+return div;
+};
+
+
+/* view-panel.js */
+Exhibit.ViewPanel=function(div,uiContext){this._uiContext=uiContext;
+this._div=div;
+this._uiContextCache={};
+this._viewConstructors=[];
+this._viewConfigs=[];
+this._viewLabels=[];
+this._viewTooltips=[];
+this._viewDomConfigs=[];
+this._viewIDs=[];
+this._viewIndex=0;
+this._view=null;
+};
+Exhibit.ViewPanel.create=function(configuration,div,uiContext){var viewPanel=new Exhibit.ViewPanel(div,uiContext);
+if("views" in configuration){for(var i=0;
+i<configuration.views.length;
+i++){var viewConfig=configuration.views[i];
+var viewClass=("viewClass" in view)?view.viewClass:Exhibit.TileView;
+if(typeof viewClass=="string"){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClass);
+}var label=null;
+if("viewLabel" in viewConfig){label=viewConfig.viewLabel;
+}else{if("label" in viewConfig){label=viewConfig.label;
+}else{if("l10n" in viewClass&&"viewLabel" in viewClass.l10n){label=viewClass.l10n.viewLabel;
+}else{label=""+viewClass;
+}}}var tooltip=null;
+if("tooltip" in viewConfig){tooltip=viewConfig.tooltip;
+}else{if("l10n" in viewClass&&"viewTooltip" in viewClass.l10n){tooltip=viewClass.l10n.viewTooltip;
+}else{tooltip=label;
+}}var id=viewPanel._generateViewID();
+if("id" in viewConfig){id=viewConfig.id;
+}viewPanel._viewConstructors.push(viewClass);
+viewPanel._viewConfigs.push(viewConfig);
+viewPanel._viewLabels.push(label);
+viewPanel._viewTooltips.push(tooltip);
+viewPanel._viewDomConfigs.push(null);
+viewPanel._viewIDs.push(id);
+}}if("initialView" in configuration){viewPanel._viewIndex=configuration.initialView;
+}viewPanel._internalValidate();
+viewPanel._initializeUI();
+return viewPanel;
+};
+Exhibit.ViewPanel.createFromDOM=function(div,uiContext){var viewPanel=new Exhibit.ViewPanel(div,Exhibit.UIContext.createFromDOM(div,uiContext,false));
+var node=div.firstChild;
+while(node!=null){if(node.nodeType==1){node.style.display="none";
+var role=Exhibit.getRoleAttribute(node);
+if(role=="view"){var viewClass=Exhibit.TileView;
+var viewClassString=Exhibit.getAttribute(node,"viewClass");
+if(viewClassString!=null&&viewClassString.length>0){viewClass=Exhibit.UI.viewClassNameToViewClass(viewClassString);
+if(viewClass==null){SimileAjax.Debug.warn("Unknown viewClass "+viewClassString);
+}}var viewLabel=Exhibit.getAttribute(node,"viewLabel");
+var label=(viewLabel!=null&&viewLabel.length>0)?viewLabel:Exhibit.getAttribute(node,"label");
+var tooltip=Exhibit.getAttribute(node,"title");
+var id=node.id;
+if(label==null){if("viewLabel" in viewClass.l10n){label=viewClass.l10n.viewLabel;
+}else{label=""+viewClass;
+}}if(tooltip==null){if("l10n" in viewClass&&"viewTooltip" in viewClass.l10n){tooltip=viewClass.l10n.viewTooltip;
+}else{tooltip=label;
+}}if(id==null||id.length==0){id=viewPanel._generateViewID();
+}viewPanel._viewConstructors.push(viewClass);
+viewPanel._viewConfigs.push(null);
+viewPanel._viewLabels.push(label);
+viewPanel._viewTooltips.push(tooltip);
+viewPanel._viewDomConfigs.push(node);
+viewPanel._viewIDs.push(id);
+}}node=node.nextSibling;
+}var initialView=Exhibit.getAttribute(div,"initialView");
+if(initialView!=null&&initialView.length>0){try{var n=parseInt(initialView);
+if(!isNaN(n)){viewPanel._viewIndex=n;
+}}catch(e){}}viewPanel._internalValidate();
+viewPanel._initializeUI();
+return viewPanel;
+};
+Exhibit.ViewPanel.prototype.dispose=function(){this._uiContext.getCollection().removeListener(this._listener);
+if(this._view!=null){this._view.dispose();
+this._view=null;
+}this._div.innerHTML="";
+this._uiContext.dispose();
+this._uiContext=null;
+this._div=null;
+};
+Exhibit.ViewPanel.prototype._generateViewID=function(){return"view"+Math.floor(Math.random()*1000000).toString();
+};
+Exhibit.ViewPanel.prototype._internalValidate=function(){if(this._viewConstructors.length==0){this._viewConstructors.push(Exhibit.TileView);
+this._viewConfigs.push({});
+this._viewLabels.push(Exhibit.TileView.l10n.viewLabel);
+this._viewTooltips.push(Exhibit.TileView.l10n.viewTooltip);
+this._viewDomConfigs.push(null);
+this._viewIDs.push(this._generateViewID());
+}this._viewIndex=Math.max(0,Math.min(this._viewIndex,this._viewConstructors.length-1));
+};
+Exhibit.ViewPanel.prototype._initializeUI=function(){var div=document.createElement("div");
+if(this._div.firstChild!=null){this._div.insertBefore(div,this._div.firstChild);
+}else{this._div.appendChild(div);
+}var self=this;
+this._dom=Exhibit.ViewPanel.constructDom(this._div.firstChild,this._viewLabels,this._viewTooltips,function(index){self._selectView(index);
+});
+this._createView();
+};
+Exhibit.ViewPanel.prototype._createView=function(){var viewContainer=this._dom.getViewContainer();
+viewContainer.innerHTML="";
+var viewDiv=document.createElement("div");
+viewContainer.appendChild(viewDiv);
+var index=this._viewIndex;
+var context=this._uiContextCache[index]||this._uiContext;
+try{if(this._viewDomConfigs[index]!=null){this._view=this._viewConstructors[index].createFromDOM(this._viewDomConfigs[index],viewContainer,context);
+}else{this._view=this._viewConstructors[index].create(this._viewConfigs[index],viewContainer,context);
+}}catch(e){SimileAjax.Debug.log("Failed to create view "+this._viewLabels[index]);
+SimileAjax.Debug.exception(e);
+}this._uiContextCache[index]=this._view._uiContext;
+this._uiContext.getExhibit().setComponent(this._viewIDs[index],this._view);
+this._dom.setViewIndex(index);
+};
+Exhibit.ViewPanel.prototype._switchView=function(newIndex){if(this._view){this._uiContext.getExhibit().disposeComponent(this._viewIDs[this._viewIndex]);
+this._view=null;
+}this._viewIndex=newIndex;
+this._createView();
+};
+Exhibit.ViewPanel.prototype._selectView=function(newIndex){var oldIndex=this._viewIndex;
+var self=this;
+SimileAjax.History.addLengthyAction(function(){self._switchView(newIndex);
+},function(){self._switchView(oldIndex);
+},Exhibit.ViewPanel.l10n.createSelectViewActionTitle(self._viewLabels[newIndex]));
+};
+Exhibit.ViewPanel.getPropertyValuesPairs=function(itemID,propertyEntries,database){var pairs=[];
+var enterPair=function(propertyID,forward){var property=database.getProperty(propertyID);
+var values=forward?database.getObjects(itemID,propertyID):database.getSubjects(itemID,propertyID);
+var count=values.size();
+if(count>0){var itemValues=property.getValueType()=="item";
+var pair={propertyLabel:forward?(count>1?property.getPluralLabel():property.getLabel()):(count>1?property.getReversePluralLabel():property.getReverseLabel()),valueType:property.getValueType(),values:[]};
+if(itemValues){values.visit(function(value){var label=database.getObject(value,"label");
+pair.values.push(label!=null?label:value);
+});
+}else{values.visit(function(value){pair.values.push(value);
+});
+}pairs.push(pair);
+}};
+for(var i=0;
+i<propertyEntries.length;
+i++){var entry=propertyEntries[i];
+if(typeof entry=="string"){enterPair(entry,true);
+}else{enterPair(entry.property,entry.forward);
+}}return pairs;
+};
+Exhibit.ViewPanel.constructDom=function(div,viewLabels,viewTooltips,onSelectView){var l10n=Exhibit.ViewPanel.l10n;
+var template={elmt:div,className:"exhibit-viewPanel exhibit-ui-protection",children:[{tag:"div",className:"exhibit-viewPanel-viewSelection",field:"viewSelectionDiv"},{tag:"div",className:"exhibit-viewPanel-viewContainer",field:"viewContainerDiv"}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.getViewContainer=function(){return dom.viewContainerDiv;
+};
+dom.setViewIndex=function(index){if(viewLabels.length>1){dom.viewSelectionDiv.innerHTML="";
+var appendView=function(i){var selected=(i==index);
+if(i>0){dom.viewSelectionDiv.appendChild(document.createTextNode(" \u2022 "));
+}var span=document.createElement("span");
+span.className=selected?"exhibit-viewPanel-viewSelection-selectedView":"exhibit-viewPanel-viewSelection-view";
+span.title=viewTooltips[i];
+span.innerHTML=viewLabels[i];
+if(!selected){var handler=function(elmt,evt,target){onSelectView(i);
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+SimileAjax.WindowManager.registerEvent(span,"click",handler);
+}dom.viewSelectionDiv.appendChild(span);
+};
+for(var i=0;
+i<viewLabels.length;
+i++){appendView(i);
+}}};
+return dom;
+};
+
+
+/* collection-summary-widget.js */
+Exhibit.CollectionSummaryWidget=function(containerElmt,uiContext){this._exhibit=uiContext.getExhibit();
+this._collection=uiContext.getCollection();
+this._uiContext=uiContext;
+this._div=containerElmt;
+var widget=this;
+this._listener={onItemsChanged:function(){widget._reconstruct();
+}};
+this._collection.addListener(this._listener);
+};
+Exhibit.CollectionSummaryWidget.create=function(configuration,containerElmt,uiContext){var widget=new Exhibit.CollectionSummaryWidget(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+widget._initializeUI();
+return widget;
+};
+Exhibit.CollectionSummaryWidget.createFromDOM=function(configElmt,containerElmt,uiContext){var widget=new Exhibit.CollectionSummaryWidget(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+widget._initializeUI();
+return widget;
+};
+Exhibit.CollectionSummaryWidget.prototype.dispose=function(){this._collection.removeListener(this._listener);
+this._div.innerHTML="";
+this._noResultsDom=null;
+this._allResultsDom=null;
+this._filteredResultsDom=null;
+this._div=null;
+this._collection=null;
+this._exhibit=null;
+};
+Exhibit.CollectionSummaryWidget.prototype._initializeUI=function(){var self=this;
+var l10n=Exhibit.CollectionSummaryWidget.l10n;
+var onClearFilters=function(elmt,evt,target){self._resetCollection();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+this._allResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.allResultsTemplate,["exhibit-collectionSummaryWidget-results"]));
+this._filteredResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.filteredResultsTemplate,["exhibit-collectionSummaryWidget-results"]),{resetActionLink:Exhibit.UI.makeActionLink(l10n.resetFiltersLabel,onClearFilters)});
+this._noResultsDom=SimileAjax.DOM.createDOMFromString("span",String.substitute(l10n.noResultsTemplate,["exhibit-collectionSummaryWidget-results","exhibit-collectionSummaryWidget-count"]),{resetActionLink:Exhibit.UI.makeActionLink(l10n.resetFiltersLabel,onClearFilters)});
+this._div.innerHTML="";
+this._reconstruct();
+};
+Exhibit.CollectionSummaryWidget.prototype._reconstruct=function(){var originalSize=this._collection.countAllItems();
+var currentSize=this._collection.countRestrictedItems();
+var database=this._uiContext.getDatabase();
+var dom=this._dom;
+while(this._div.childNodes.length>0){this._div.removeChild(this._div.firstChild);
+}if(originalSize>0){if(currentSize==0){this._div.appendChild(this._noResultsDom.elmt);
+}else{var typeIDs=database.getTypeIDs(this._collection.getRestrictedItems()).toArray();
+var typeID=typeIDs.length==1?typeIDs[0]:"Item";
+var description=Exhibit.Database.l10n.labelItemsOfType(currentSize,typeID,database,"exhibit-collectionSummaryWidget-count");
+if(currentSize==originalSize){this._div.appendChild(this._allResultsDom.elmt);
+this._allResultsDom.resultDescription.innerHTML="";
+this._allResultsDom.resultDescription.appendChild(description);
+}else{this._div.appendChild(this._filteredResultsDom.elmt);
+this._filteredResultsDom.resultDescription.innerHTML="";
+this._filteredResultsDom.resultDescription.appendChild(description);
+this._filteredResultsDom.originalCountSpan.innerHTML=originalSize;
+}}}};
+Exhibit.CollectionSummaryWidget.prototype._resetCollection=function(){var state={};
+var collection=this._collection;
+SimileAjax.History.addLengthyAction(function(){state.restrictions=collection.clearAllRestrictions();
+},function(){collection.applyRestrictions(state.restrictions);
+},Exhibit.CollectionSummaryWidget.l10n.resetActionTitle);
+};
+
+
+/* legend-gradient-widget.js */
+Exhibit.LegendGradientWidget=function(containerElmt,uiContext){this._div=containerElmt;
+this._uiContext=uiContext;
+this._initializeUI();
+};
+Exhibit.LegendGradientWidget.create=function(containerElmt,uiContext){return new Exhibit.LegendGradientWidget(containerElmt,uiContext);
+};
+Exhibit.LegendGradientWidget.prototype.addGradient=function(configuration){var gradientPoints=[];
+var gradientPoints=configuration;
+var sortObj=function(a,b){return a.value-b.value;
+};
+gradientPoints.sort(sortObj);
+var theTable=document.createElement("table");
+var tableBody=document.createElement("tbody");
+var theRow1=document.createElement("tr");
+var theRow2=document.createElement("tr");
+var theRow3=document.createElement("tr");
+theRow1.style.height="2em";
+theRow2.style.height="2em";
+theRow3.style.height="2em";
+theTable.style.width="80%";
+theTable.cellSpacing="0";
+theTable.style.emptyCells="show";
+theTable.style.marginLeft="auto";
+theTable.style.marginRight="auto";
+tableBody.appendChild(theRow1);
+tableBody.appendChild(theRow2);
+tableBody.appendChild(theRow3);
+theTable.appendChild(tableBody);
+this._theRow1=theRow1;
+this._theRow2=theRow2;
+this._theRow3=theRow3;
+var globLowPoint=gradientPoints[0].value;
+var globHighPoint=gradientPoints[gradientPoints.length-1].value;
+var stepSize=(globHighPoint-globLowPoint)/50;
+var counter=0;
+for(var i=0;
+i<gradientPoints.length-1;
+i++){var lowPoint=gradientPoints[i].value;
+var highPoint=gradientPoints[i+1].value;
+var colorRect=document.createElement("td");
+colorRect.style.backgroundColor="rgb("+gradientPoints[i].red+","+gradientPoints[i].green+","+gradientPoints[i].blue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode(gradientPoints[i].value);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+theRow1.appendChild(document.createElement("td"));
+theRow2.appendChild(colorRect);
+theRow3.appendChild(numberRect);
+colorRect.onmouseover=function(){this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.style.border="none";
+};
+counter++;
+for(var j=lowPoint+stepSize;
+j<highPoint;
+j+=stepSize){var fraction=(j-lowPoint)/(highPoint-lowPoint);
+var newRed=Math.floor(gradientPoints[i].red+fraction*(gradientPoints[i+1].red-gradientPoints[i].red));
+var newGreen=Math.floor(gradientPoints[i].green+fraction*(gradientPoints[i+1].green-gradientPoints[i].green));
+var newBlue=Math.floor(gradientPoints[i].blue+fraction*(gradientPoints[i+1].blue-gradientPoints[i].blue));
+var colorRect=document.createElement("td");
+colorRect.count=counter;
+colorRect.style.backgroundColor="rgb("+newRed+","+newGreen+","+newBlue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode((Math.floor(j*100))/100);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+textDiv.style.width="2px";
+textDiv.style.overflow="hidden";
+textDiv.style.visibility="hidden";
+theRow1.appendChild(numberRect);
+theRow2.appendChild(colorRect);
+theRow3.appendChild(document.createElement("td"));
+counter++;
+colorRect.onmouseover=function(){this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="visible";
+this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="visible";
+this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="hidden";
+this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="hidden";
+this.style.border="none";
+};
+}}var high=gradientPoints.length-1;
+var colorRect=document.createElement("td");
+colorRect.style.backgroundColor="rgb("+gradientPoints[high].red+","+gradientPoints[high].green+","+gradientPoints[high].blue+")";
+var numberRect=document.createElement("td");
+var textDiv=document.createElement("div");
+var theText=document.createTextNode(globHighPoint);
+textDiv.appendChild(theText);
+numberRect.appendChild(textDiv);
+theRow1.appendChild(document.createElement("td"));
+theRow2.appendChild(colorRect);
+theRow3.appendChild(numberRect);
+counter++;
+colorRect.onmouseover=function(){this.style.border="solid 1.2px";
+};
+colorRect.onmouseout=function(){this.style.border="none";
+};
+this._div.appendChild(theTable);
+};
+Exhibit.LegendGradientWidget.prototype.addEntry=function(color,label){var cell=document.createElement("td");
+cell.style.width="1.5em";
+cell.style.height="2em";
+this._theRow1.appendChild(cell);
+this._theRow1.appendChild(document.createElement("td"));
+this._theRow2.appendChild(document.createElement("td"));
+this._theRow3.appendChild(document.createElement("td"));
+var colorCell=document.createElement("td");
+colorCell.style.backgroundColor=color;
+this._theRow2.appendChild(colorCell);
+var labelCell=document.createElement("td");
+var labelDiv=document.createElement("div");
+labelDiv.appendChild(document.createTextNode(label));
+labelCell.appendChild(labelDiv);
+this._theRow3.appendChild(labelCell);
+};
+Exhibit.LegendGradientWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.LegendGradientWidget.prototype._initializeUI=function(){this._div.className="exhibit-legendGradientWidget";
+this._div.innerHTML="";
+};
+Exhibit.LegendGradientWidget.prototype.clear=function(){this._div.innerHTML="";
+};
+
+
+/* legend-widget.js */
+Exhibit.LegendWidget=function(configuration,containerElmt,uiContext){this._configuration=configuration;
+this._div=containerElmt;
+this._uiContext=uiContext;
+this._colorMarkerGenerator="colorMarkerGenerator" in configuration?configuration.colorMarkerGenerator:Exhibit.LegendWidget._defaultColorMarkerGenerator;
+this._sizeMarkerGenerator="sizeMarkerGenerator" in configuration?configuration.sizeMarkerGenerator:Exhibit.LegendWidget._defaultSizeMarkerGenerator;
+this._iconMarkerGenerator="iconMarkerGenerator" in configuration?configuration.iconMarkerGenerator:Exhibit.LegendWidget._defaultIconMarkerGenerator;
+this._labelStyler="labelStyler" in configuration?configuration.labelStyler:Exhibit.LegendWidget._defaultColorLabelStyler;
+this._initializeUI();
+};
+Exhibit.LegendWidget.create=function(configuration,containerElmt,uiContext){return new Exhibit.LegendWidget(configuration,containerElmt,uiContext);
+};
+Exhibit.LegendWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._div=null;
+this._uiContext=null;
+};
+Exhibit.LegendWidget.prototype._initializeUI=function(){this._div.className="exhibit-legendWidget";
+this._div.innerHTML="<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+Exhibit.LegendWidget.prototype.clear=function(){this._div.innerHTML="<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+Exhibit.LegendWidget.prototype.addLegendLabel=function(label,type){var dom=SimileAjax.DOM.createDOMFromString("div","<div id='legend-label'><span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 </div>",{});
+dom.elmt.className="exhibit-legendWidget-label";
+var id="exhibit-"+type+"-legend";
+document.getElementById(id).appendChild(dom.elmt);
+};
+Exhibit.LegendWidget.prototype.addEntry=function(value,label,type){type=type||"color";
+label=(label!=null)?label.toString():key.toString();
+if(type=="color"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._colorMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-color-legend");
+}if(type=="size"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._sizeMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-size-legend");
+}if(type=="icon"){var dom=SimileAjax.DOM.createDOMFromString("span","<span id='marker'></span>\u00a0<span id='label' class='exhibit-legendWidget-entry-title'>"+label.replace(/\s+/g,"\u00a0")+"</span>\u00a0\u00a0 ",{marker:this._iconMarkerGenerator(value)});
+var legendDiv=document.getElementById("exhibit-icon-legend");
+}dom.elmt.className="exhibit-legendWidget-entry";
+this._labelStyler(dom.label,value);
+legendDiv.appendChild(dom.elmt);
+};
+Exhibit.LegendWidget._localeSort=function(a,b){return a.localeCompare(b);
+};
+Exhibit.LegendWidget._defaultColorMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="exhibit-legendWidget-entry-swatch";
+span.style.background=value;
+span.innerHTML="\u00a0\u00a0";
+return span;
+};
+Exhibit.LegendWidget._defaultSizeMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="exhibit-legendWidget-entry-swatch";
+span.style.height=value;
+span.style.width=value;
+span.style.background="#C0C0C0";
+span.innerHTML="\u00a0\u00a0";
+return span;
+};
+Exhibit.LegendWidget._defaultIconMarkerGenerator=function(value){var span=document.createElement("span");
+span.className="<img src="+value+"/>";
+return span;
+};
+Exhibit.LegendWidget._defaultColorLabelStyler=function(elmt,value){};
+
+
+/* logo.js */
+Exhibit.Logo=function(elmt,exhibit){this._exhibit=exhibit;
+this._elmt=elmt;
+this._color="Silver";
+};
+Exhibit.Logo.create=function(configuration,elmt,exhibit){var logo=new Exhibit.Logo(elmt,exhibit);
+if("color" in configuration){logo._color=configuration.color;
+}logo._initializeUI();
+return logo;
+};
+Exhibit.Logo.createFromDOM=function(elmt,exhibit){var logo=new Exhibit.Logo(elmt,exhibit);
+var color=Exhibit.getAttribute(elmt,"color");
+if(color!=null&&color.length>0){logo._color=color;
+}logo._initializeUI();
+return logo;
+};
+Exhibit.Logo.prototype.dispose=function(){this._elmt=null;
+this._exhibit=null;
+};
+Exhibit.Logo.prototype._initializeUI=function(){var logoURL="http://static.simile.mit.edu/graphics/logos/exhibit/exhibit-small-"+this._color+".png";
+var img=SimileAjax.Graphics.createTranslucentImage(logoURL);
+var id="exhibit-logo-image";
+if(!document.getElementById(id)){img.id=id;
+}var a=document.createElement("a");
+a.href="http://simile.mit.edu/exhibit/";
+a.title="http://simile.mit.edu/exhibit/";
+a.target="_blank";
+a.appendChild(img);
+this._elmt.appendChild(a);
+};
+
+
+/* option-widget.js */
+Exhibit.OptionWidget=function(configuration,containerElmt,uiContext){this._label=configuration.label;
+this._checked="checked" in configuration?configuration.checked:false;
+this._onToggle=configuration.onToggle;
+this._containerElmt=containerElmt;
+this._uiContext=uiContext;
+this._initializeUI();
+};
+Exhibit.OptionWidget.create=function(configuration,containerElmt,uiContext){return new Exhibit.OptionWidget(configuration,containerElmt,uiContext);
+};
+Exhibit.OptionWidget.prototype.dispose=function(){this._containerElmt.innerHTML="";
+this._dom=null;
+this._containerElmt=null;
+this._uiContext=null;
+};
+Exhibit.OptionWidget.uncheckedImageURL=Exhibit.urlPrefix+"images/option.png";
+Exhibit.OptionWidget.checkedImageURL=Exhibit.urlPrefix+"images/option-check.png";
+Exhibit.OptionWidget.uncheckedTemplate="<span id='uncheckedSpan' style='display: none;'><img id='uncheckedImage' /> %0</span>";
+Exhibit.OptionWidget.checkedTemplate="<span id='checkedSpan' style='display: none;'><img id='checkedImage' /> %0</span>";
+Exhibit.OptionWidget.prototype._initializeUI=function(){this._containerElmt.className="exhibit-optionWidget";
+this._dom=SimileAjax.DOM.createDOMFromString(this._containerElmt,String.substitute(Exhibit.OptionWidget.uncheckedTemplate+Exhibit.OptionWidget.checkedTemplate,[this._label]),{uncheckedImage:SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.uncheckedImageURL),checkedImage:SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.checkedImageURL)});
+if(this._checked){this._dom.checkedSpan.style.display="inline";
+}else{this._dom.uncheckedSpan.style.display="inline";
+}SimileAjax.WindowManager.registerEvent(this._containerElmt,"click",this._onToggle);
+};
+Exhibit.OptionWidget.prototype.getChecked=function(){return this._checked;
+};
+Exhibit.OptionWidget.prototype.setChecked=function(checked){if(checked!=this._checked){this._checked=checked;
+if(checked){this._dom.checkedSpan.style.display="inline";
+this._dom.uncheckedSpan.style.display="none";
+}else{this._dom.checkedSpan.style.display="none";
+this._dom.uncheckedSpan.style.display="inline";
+}}};
+Exhibit.OptionWidget.prototype.toggle=function(){this.setChecked(!this._checked);
+};
+
+
+/* resizable-div-widget.js */
+Exhibit.ResizableDivWidget=function(configuration,elmt,uiContext){this._div=elmt;
+this._configuration=configuration;
+if(!("minHeight" in configuration)){configuration["minHeight"]=10;
+}this._initializeUI();
+};
+Exhibit.ResizableDivWidget.create=function(configuration,elmt,uiContext){return new Exhibit.ResizableDivWidget(configuration,elmt,uiContext);
+};
+Exhibit.ResizableDivWidget.prototype.dispose=function(){this._div.innerHTML="";
+this._contentDiv=null;
+this._resizerDiv=null;
+this._div=null;
+};
+Exhibit.ResizableDivWidget.prototype.getContentDiv=function(){return this._contentDiv;
+};
+Exhibit.ResizableDivWidget.prototype._initializeUI=function(){var self=this;
+this._div.innerHTML="<div></div><div class='exhibit-resizableDivWidget-resizer'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+"</div>";
+this._contentDiv=this._div.childNodes[0];
+this._resizerDiv=this._div.childNodes[1];
+SimileAjax.WindowManager.registerForDragging(this._resizerDiv,{onDragStart:function(){this._height=self._contentDiv.offsetHeight;
+},onDragBy:function(diffX,diffY){this._height+=diffY;
+self._contentDiv.style.height=Math.max(self._configuration.minHeight,this._height)+"px";
+},onDragEnd:function(){if("onResize" in self._configuration){self._configuration["onResize"]();
+}}});
+};
+
+
+/* toolbox-widget.js */
+Exhibit.ToolboxWidget=function(containerElmt,uiContext){this._containerElmt=containerElmt;
+this._uiContext=uiContext;
+this._settings={};
+this._customExporters=[];
+this._hovering=false;
+this._initializeUI();
+};
+Exhibit.ToolboxWidget._settingSpecs={"itemID":{type:"text"}};
+Exhibit.ToolboxWidget.create=function(configuration,containerElmt,uiContext){var widget=new Exhibit.ToolboxWidget(containerElmt,Exhibit.UIContext.create(configuration,uiContext));
+Exhibit.ToolboxWidget._configure(widget,configuration);
+widget._initializeUI();
+return widget;
+};
+Exhibit.ToolboxWidget.createFromDOM=function(configElmt,containerElmt,uiContext){var configuration=Exhibit.getConfigurationFromDOM(configElmt);
+var widget=new Exhibit.ToolboxWidget(containerElmt!=null?containerElmt:configElmt,Exhibit.UIContext.createFromDOM(configElmt,uiContext));
+Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt,Exhibit.ToolboxWidget._settingSpecs,widget._settings);
+Exhibit.ToolboxWidget._configure(widget,configuration);
+widget._initializeUI();
+return widget;
+};
+Exhibit.ToolboxWidget._configure=function(widget,configuration){Exhibit.SettingsUtilities.collectSettings(configuration,Exhibit.ToolboxWidget._settingSpecs,widget._settings);
+};
+Exhibit.ToolboxWidget.prototype.dispose=function(){this._containerElmt.onmouseover=null;
+this._containerElmt.onmouseout=null;
+this._dismiss();
+this._settings=null;
+this._containerElmt=null;
+this._uiContext=null;
+};
+Exhibit.ToolboxWidget.prototype.addExporter=function(exporter){this._customExporters.push(exporter);
+};
+Exhibit.ToolboxWidget.prototype._initializeUI=function(){var self=this;
+this._containerElmt.onmouseover=function(evt){self._onContainerMouseOver(evt);
+};
+this._containerElmt.onmouseout=function(evt){self._onContainerMouseOut(evt);
+};
+};
+Exhibit.ToolboxWidget.prototype._onContainerMouseOver=function(evt){if(!this._hovering){var self=this;
+var coords=SimileAjax.DOM.getPageCoordinates(this._containerElmt);
+var docWidth=document.body.offsetWidth;
+var docHeight=document.body.offsetHeight;
+var popup=document.createElement("div");
+popup.className="exhibit-toolboxWidget-popup screen";
+popup.style.top=coords.top+"px";
+popup.style.right=(docWidth-coords.left-this._containerElmt.offsetWidth)+"px";
+this._fillPopup(popup);
+document.body.appendChild(popup);
+popup.onmouseover=function(evt){self._onPopupMouseOver(evt);
+};
+popup.onmouseout=function(evt){self._onPopupMouseOut(evt);
+};
+this._popup=popup;
+this._hovering=true;
+}else{this._clearTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._onContainerMouseOut=function(evt){if(Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt),this._containerElmt)){this._setTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._onPopupMouseOver=function(evt){this._clearTimeout();
+};
+Exhibit.ToolboxWidget.prototype._onPopupMouseOut=function(evt){if(Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt),this._containerElmt)){this._setTimeout();
+}};
+Exhibit.ToolboxWidget.prototype._setTimeout=function(){var self=this;
+this._timer=window.setTimeout(function(){self._onTimeout();
+},200);
+};
+Exhibit.ToolboxWidget.prototype._clearTimeout=function(){if(this._timer){window.clearTimeout(this._timer);
+this._timer=null;
+}};
+Exhibit.ToolboxWidget.prototype._onTimeout=function(){this._dismiss();
+this._hovering=false;
+this._timer=null;
+};
+Exhibit.ToolboxWidget.prototype._fillPopup=function(elmt){var self=this;
+var exportImg=Exhibit.UI.createTranslucentImage("images/liveclipboard-icon.png");
+exportImg.className="exhibit-toolboxWidget-button";
+SimileAjax.WindowManager.registerEvent(exportImg,"click",function(elmt,evt,target){self._showExportMenu(exportImg);
+});
+elmt.appendChild(exportImg);
+};
+Exhibit.ToolboxWidget.prototype._dismiss=function(){if(this._popup){document.body.removeChild(this._popup);
+this._popup=null;
+}};
+Exhibit.ToolboxWidget._mouseOutsideElmt=function(evt,elmt){var eventCoords=SimileAjax.DOM.getEventPageCoordinates(evt);
+var coords=SimileAjax.DOM.getPageCoordinates(elmt);
+return((eventCoords.x<coords.left||eventCoords.x>coords.left+elmt.offsetWidth)||(eventCoords.y<coords.top||eventCoords.y>coords.top+elmt.offsetHeight));
+};
+Exhibit.ToolboxWidget._getEvent=function(evt){return(evt)?evt:((event)?event:null);
+};
+Exhibit.ToolboxWidget.prototype._showExportMenu=function(elmt){var self=this;
+var popupDom=Exhibit.UI.createPopupMenuDom(elmt);
+var makeMenuItem=function(exporter){popupDom.appendMenuItem(exporter.getLabel(),null,function(){var database=self._uiContext.getDatabase();
+var text=("itemID" in self._settings)?exporter.exportOne(self._settings.itemID,database):exporter.exportMany(self._uiContext.getCollection().getRestrictedItems(),database);
+Exhibit.ToolboxWidget.createExportDialogBox(text).open();
+});
+};
+var exporters=Exhibit.getExporters();
+for(var i=0;
+i<exporters.length;
+i++){makeMenuItem(exporters[i]);
+}for(var i=0;
+i<this._customExporters.length;
+i++){makeMenuItem(this._customExporters[i]);
+}if("getGeneratedHTML" in this){makeMenuItem({getLabel:function(){return Exhibit.l10n.htmlExporterLabel;
+},exportOne:this.getGeneratedHTML,exportMany:this.getGeneratedHTML});
+}popupDom.open();
+};
+Exhibit.ToolboxWidget.createExportDialogBox=function(string){var template={tag:"div",className:"exhibit-copyDialog exhibit-ui-protection",children:[{tag:"button",field:"closeButton",children:[Exhibit.l10n.exportDialogBoxCloseButtonLabel]},{tag:"p",children:[Exhibit.l10n.exportDialogBoxPrompt]},{tag:"div",field:"textAreaContainer"}]};
+var dom=SimileAjax.DOM.createDOMFromTemplate(template);
+dom.textAreaContainer.innerHTML="<textarea wrap='off' rows='15'>"+string+"</textarea>";
+dom.close=function(){document.body.removeChild(dom.elmt);
+};
+dom.open=function(){dom.elmt.style.top=(document.body.scrollTop+100)+"px";
+document.body.appendChild(dom.elmt);
+dom.layer=SimileAjax.WindowManager.pushLayer(function(){dom.close();
+},false);
+var textarea=dom.textAreaContainer.firstChild;
+textarea.select();
+SimileAjax.WindowManager.registerEvent(dom.closeButton,"click",function(elmt,evt,target){SimileAjax.WindowManager.popLayer(dom.layer);
+},dom.layer);
+SimileAjax.WindowManager.registerEvent(textarea,"keyup",function(elmt,evt,target){if(evt.keyCode==27){SimileAjax.WindowManager.popLayer(dom.layer);
+}},dom.layer);
+};
+return dom;
+};
+
+
+/* coders.js */
+Exhibit.Coders=new Object();
+Exhibit.Coders.mixedCaseColor="#fff";
+Exhibit.Coders.othersCaseColor="#aaa";
+Exhibit.Coders.missingCaseColor="#888";
+
+
+/* facets.js */
+Exhibit.FacetUtilities=new Object();
+Exhibit.FacetUtilities.constructFacetFrame=function(forFacet,div,facetLabel,onClearAllSelections,uiContext,collapsible,collapsed){div.className="exhibit-facet";
+var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-facet-header'><div class='exhibit-facet-header-filterControl' id='clearSelectionsDiv' title='"+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip+"'><span id='filterCountSpan'></span><img id='checkImage' /></div>"+((collapsible)?"<img src='"+Exhibit.urlPrefix+"images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />":"")+"<span class='exhibit-facet-header-title'>"+facetLabel+"</span></div><div class='exhibit-facet-body-frame' id='frameDiv'></div>",{checkImage:Exhibit.UI.createTranslucentImage("images/black-check.png")});
+var resizableDivWidget=Exhibit.ResizableDivWidget.create({},dom.frameDiv,uiContext);
+dom.valuesContainer=resizableDivWidget.getContentDiv();
+dom.valuesContainer.className="exhibit-facet-body";
+dom.setSelectionCount=function(count){this.filterCountSpan.innerHTML=count;
+this.clearSelectionsDiv.style.display=count>0?"block":"none";
+};
+SimileAjax.WindowManager.registerEvent(dom.clearSelectionsDiv,"click",onClearAllSelections);
+if(collapsible){SimileAjax.WindowManager.registerEvent(dom.collapseImg,"click",function(){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+});
+if(collapsed){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+}}return dom;
+};
+Exhibit.FacetUtilities.toggleCollapse=function(dom,facet){var el=dom.frameDiv;
+if(el.style.display!="none"){el.style.display="none";
+dom.collapseImg.src=Exhibit.urlPrefix+"images/expand.png";
+}else{el.style.display="block";
+dom.collapseImg.src=Exhibit.urlPrefix+"images/collapse.png";
+if(typeof facet.onUncollapse=="function"){facet.onUncollapse();
+}}};
+Exhibit.FacetUtilities.isCollapsed=function(facet){var el=facet._dom.frameDiv;
+return el.style.display=="none";
+};
+Exhibit.FacetUtilities.constructFacetItem=function(label,count,color,selected,facetHasSelection,onSelect,onSelectOnly,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-facet-value-count'>"+count+"</div><div class='exhibit-facet-value-inner' id='inner'>"+("<div class='exhibit-facet-value-checkbox'>&#160;"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a></div>");
+dom.elmt.className=selected?"exhibit-facet-value exhibit-facet-value-selected":"exhibit-facet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.link.innerHTML=label;
+if(color!=null){dom.link.style.color=color;
+}}else{dom.link.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.inner.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}return dom.elmt;
+};
+Exhibit.FacetUtilities.constructFlowingFacetFrame=function(forFacet,div,facetLabel,onClearAllSelections,uiContext,collapsible,collapsed){div.className="exhibit-flowingFacet";
+var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-flowingFacet-header'>"+((collapsible)?"<img src='"+Exhibit.urlPrefix+"images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />":"")+"<span class='exhibit-flowingFacet-header-title'>"+facetLabel+"</span></div><div id='frameDiv'><div class='exhibit-flowingFacet-body' id='valuesContainer'></div></div>");
+dom.setSelectionCount=function(count){};
+if(collapsible){SimileAjax.WindowManager.registerEvent(dom.collapseImg,"click",function(){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+});
+if(collapsed){Exhibit.FacetUtilities.toggleCollapse(dom,forFacet);
+}}return dom;
+};
+Exhibit.FacetUtilities.constructFlowingFacetItem=function(label,count,color,selected,facetHasSelection,onSelect,onSelectOnly,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div",("<div class='exhibit-flowingFacet-value-checkbox'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a> <span class='exhibit-flowingFacet-value-count'>("+count+")</span>");
+dom.elmt.className=selected?"exhibit-flowingFacet-value exhibit-flowingFacet-value-selected":"exhibit-flowingFacet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.inner.innerHTML=label;
+if(color!=null){dom.inner.style.color=color;
+}}else{dom.inner.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}return dom.elmt;
+};
+Exhibit.FacetUtilities.constructHierarchicalFacetItem=function(label,count,color,selected,hasChildren,expanded,facetHasSelection,onSelect,onSelectOnly,onToggleChildren,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div","<div class='exhibit-facet-value-count'>"+count+"</div><div class='exhibit-facet-value-inner' id='inner'>"+("<div class='exhibit-facet-value-checkbox'>&#160;"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a>"+(hasChildren?("<a class='exhibit-facet-value-children-toggle' href='javascript:{}' id='toggle'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/right-arrow.png")+"</a>"):"")+"</div>"+(hasChildren?"<div class='exhibit-facet-childrenContainer' id='childrenContainer'></div>":""));
+dom.elmt.className=selected?"exhibit-facet-value exhibit-facet-value-selected":"exhibit-facet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.link.appendChild(document.createTextNode(label));
+if(color!=null){dom.link.style.color=color;
+}}else{dom.link.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.inner.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}if(hasChildren){dom.showChildren=function(show){dom.childrenContainer.style.display=show?"block":"none";
+dom.toggle.childNodes[0].style.display=show?"inline":"none";
+dom.toggle.childNodes[1].style.display=show?"none":"inline";
+};
+SimileAjax.WindowManager.registerEvent(dom.toggle,"click",onToggleChildren,SimileAjax.WindowManager.getBaseLayer());
+dom.showChildren(expanded);
+}return dom;
+};
+Exhibit.FacetUtilities.constructFlowingHierarchicalFacetItem=function(label,count,color,selected,hasChildren,expanded,facetHasSelection,onSelect,onSelectOnly,onToggleChildren,uiContext){if(Exhibit.params.safe){label=Exhibit.Formatter.encodeAngleBrackets(label);
+}var dom=SimileAjax.DOM.createDOMFromString("div",("<div class='exhibit-flowingFacet-value-checkbox'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+(facetHasSelection?(selected?"images/black-check.png":"images/no-check.png"):"images/no-check-no-border.png"))+"</div>")+"<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a> <span class='exhibit-flowingFacet-value-count'>("+count+")</span>"+(hasChildren?("<a class='exhibit-flowingFacet-value-children-toggle' href='javascript:{}' id='toggle'>"+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/down-arrow.png")+SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix+"images/right-arrow.png")+"</a>"):"")+(hasChildren?"<div class='exhibit-flowingFacet-childrenContainer' id='childrenContainer'></div>":""));
+dom.elmt.className=selected?"exhibit-flowingFacet-value exhibit-flowingFacet-value-selected":"exhibit-flowingFacet-value";
+if(typeof label=="string"){dom.elmt.title=label;
+dom.inner.appendChild(document.createTextNode(label));
+if(color!=null){dom.inner.style.color=color;
+}}else{dom.inner.appendChild(label);
+if(color!=null){label.style.color=color;
+}}SimileAjax.WindowManager.registerEvent(dom.elmt,"click",onSelectOnly,SimileAjax.WindowManager.getBaseLayer());
+if(facetHasSelection){SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild,"click",onSelect,SimileAjax.WindowManager.getBaseLayer());
+}if(hasChildren){dom.showChildren=function(show){dom.childrenContainer.style.display=show?"block":"none";
+dom.toggle.childNodes[0].style.display=show?"inline":"none";
+dom.toggle.childNodes[1].style.display=show?"none":"inline";
+};
+SimileAjax.WindowManager.registerEvent(dom.toggle,"click",onToggleChildren,SimileAjax.WindowManager.getBaseLayer());
+dom.showChildren(expanded);
+}return dom;
+};
+Exhibit.FacetUtilities.Cache=function(database,collection,expression){var self=this;
+this._database=database;
+this._collection=collection;
+this._expression=expression;
+this._listener={onRootItemsChanged:function(){if("_itemToValue" in self){delete self._itemToValue;
+}if("_valueToItem" in self){delete self._valueToItem;
+}if("_missingItems" in self){delete self._missingItems;
+}}};
+collection.addListener(this._listener);
+};
+Exhibit.FacetUtilities.Cache.prototype.dispose=function(){this._collection.removeListener(this._listener);
+this._collection=null;
+this._listener=null;
+this._itemToValue=null;
+this._valueToItem=null;
+this._missingItems=null;
+};
+Exhibit.FacetUtilities.Cache.prototype.getItemsFromValues=function(values,filter){var set;
+if(this._expression.isPath()){set=this._expression.getPath().walkBackward(values,"item",filter,this._database).getSet();
+}else{this._buildMaps();
+set=new Exhibit.Set();
+var valueToItem=this._valueToItem;
+values.visit(function(value){if(value in valueToItem){var itemA=valueToItem[value];
+for(var i=0;
+i<itemA.length;
+i++){var item=itemA[i];
+if(filter.contains(item)){set.add(item);
+}}}});
+}return set;
+};
+Exhibit.FacetUtilities.Cache.prototype.getItemsMissingValue=function(filter,results){this._buildMaps();
+results=results||new Exhibit.Set();
+var missingItems=this._missingItems;
+filter.visit(function(item){if(item in missingItems){results.add(item);
+}});
+return results;
+};
+Exhibit.FacetUtilities.Cache.prototype.getValueCountsFromItems=function(items){var entries=[];
+var database=this._database;
+var valueType="text";
+if(this._expression.isPath()){var path=this._expression.getPath();
+var facetValueResult=path.walkForward(items,"item",database);
+valueType=facetValueResult.valueType;
+if(facetValueResult.size>0){facetValueResult.forEachValue(function(facetValue){var itemSubcollection=path.evaluateBackward(facetValue,valueType,items,database);
+entries.push({value:facetValue,count:itemSubcollection.size});
+});
+}}else{this._buildMaps();
+valueType=this._valueType;
+for(var value in this._valueToItem){var itemA=this._valueToItem[value];
+var count=0;
+for(var i=0;
+i<itemA.length;
+i++){if(items.contains(itemA[i])){count++;
+}}if(count>0){entries.push({value:value,count:count});
+}}}return{entries:entries,valueType:valueType};
+};
+Exhibit.FacetUtilities.Cache.prototype.getValuesFromItems=function(items){if(this._expression.isPath()){return this._expression.getPath().walkForward(items,"item",database).getSet();
+}else{this._buildMaps();
+var set=new Exhibit.Set();
+var itemToValue=this._itemToValue;
+items.visit(function(item){if(item in itemToValue){var a=itemToValue[item];
+for(var i=0;
+i<a.length;
+i++){set.add(a[i]);
+}}});
+return set;
+}};
+Exhibit.FacetUtilities.Cache.prototype.countItemsMissingValue=function(items){this._buildMaps();
+var count=0;
+for(var item in this._missingItems){if(items.contains(item)){count++;
+}}return count;
+};
+Exhibit.FacetUtilities.Cache.prototype._buildMaps=function(){if(!("_itemToValue" in this)){var itemToValue={};
+var valueToItem={};
+var missingItems={};
+var valueType="text";
+var insert=function(x,y,map){if(x in map){map[x].push(y);
+}else{map[x]=[y];
+}};
+var expression=this._expression;
+var database=this._database;
+this._collection.getAllItems().visit(function(item){var results=expression.evaluateOnItem(item,database);
+if(results.values.size()>0){valueType=results.valueType;
+results.values.visit(function(value){insert(item,value,itemToValue);
+insert(value,item,valueToItem);
+});
+}else{missingItems[item]=true;
+}});
+this._itemToValue=itemToValue;
+this._valueToItem=valueToItem;
+this._missingItems=missingItems;
+this._valueType=valueType;
+}};
+
+
+/* set.js */
+Exhibit.Set=function(a){this._hash={};
+this._count=0;
+if(a instanceof Array){for(var i=0;
+i<a.length;
+i++){this.add(a[i]);
+}}else{if(a instanceof Exhibit.Set){this.addSet(a);
+}}};
+Exhibit.Set.prototype.add=function(o){if(!(o in this._hash)){this._hash[o]=true;
+this._count++;
+return true;
+}return false;
+};
+Exhibit.Set.prototype.addSet=function(set){for(var o in set._hash){this.add(o);
+}};
+Exhibit.Set.prototype.remove=function(o){if(o in this._hash){delete this._hash[o];
+this._count--;
+return true;
+}return false;
+};
+Exhibit.Set.prototype.removeSet=function(set){for(var o in set._hash){this.remove(o);
+}};
+Exhibit.Set.prototype.retainSet=function(set){for(var o in this._hash){if(!set.contains(o)){delete this._hash[o];
+this._count--;
+}}};
+Exhibit.Set.prototype.contains=function(o){return(o in this._hash);
+};
+Exhibit.Set.prototype.size=function(){return this._count;
+};
+Exhibit.Set.prototype.toArray=function(){var a=[];
+for(var o in this._hash){a.push(o);
+}return a;
+};
+Exhibit.Set.prototype.visit=function(f){for(var o in this._hash){if(f(o)==true){break;
+}}};
+Exhibit.Set.createIntersection=function(set1,set2,result){var set=(result)?result:new Exhibit.Set();
+var setA,setB;
+if(set1.size()<set2.size()){setA=set1;
+setB=set2;
+}else{setA=set2;
+setB=set1;
+}setA.visit(function(v){if(setB.contains(v)){set.add(v);
+}});
+return set;
+};
+
+
+/* settings.js */
+Exhibit.SettingsUtilities=new Object();
+Exhibit.SettingsUtilities.collectSettings=function(config,specs,settings){Exhibit.SettingsUtilities._internalCollectSettings(function(field){return config[field];
+},specs,settings);
+};
+Exhibit.SettingsUtilities.collectSettingsFromDOM=function(configElmt,specs,settings){Exhibit.SettingsUtilities._internalCollectSettings(function(field){return Exhibit.getAttribute(configElmt,field);
+},specs,settings);
+};
+Exhibit.SettingsUtilities._internalCollectSettings=function(f,specs,settings){for(var field in specs){var spec=specs[field];
+var name=field;
+if("name" in spec){name=spec.name;
+}if(!(name in settings)&&"defaultValue" in spec){settings[name]=spec.defaultValue;
+}var value=f(field);
+if(value==null){continue;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){continue;
+}}var type="text";
+if("type" in spec){type=spec.type;
+}var dimensions=1;
+if("dimensions" in spec){dimensions=spec.dimensions;
+}try{if(dimensions>1){var separator=",";
+if("separator" in spec){separator=spec.separator;
+}var a=value.split(separator);
+if(a.length!=dimensions){throw new Error("Expected a tuple of "+dimensions+" dimensions separated with "+separator+" but got "+value);
+}else{for(var i=0;
+i<a.length;
+i++){a[i]=Exhibit.SettingsUtilities._parseSetting(a[i].trim(),type,spec);
+}settings[name]=a;
+}}else{settings[name]=Exhibit.SettingsUtilities._parseSetting(value,type,spec);
+}}catch(e){SimileAjax.Debug.exception(e);
+}}};
+Exhibit.SettingsUtilities._parseSetting=function(s,type,spec){var sType=typeof s;
+if(type=="text"){return s;
+}else{if(type=="float"){if(sType=="number"){return s;
+}else{if(sType=="string"){var f=parseFloat(s);
+if(!isNaN(f)){return f;
+}}}throw new Error("Expected a floating point number but got "+s);
+}else{if(type=="int"){if(sType=="number"){return Math.round(s);
+}else{if(sType=="string"){var n=parseInt(s);
+if(!isNaN(n)){return n;
+}}}throw new Error("Expected an integer but got "+s);
+}else{if(type=="boolean"){if(sType=="boolean"){return s;
+}else{if(sType=="string"){s=s.toLowerCase();
+if(s=="true"){return true;
+}else{if(s=="false"){return false;
+}}}}throw new Error("Expected either 'true' or 'false' but got "+s);
+}else{if(type=="function"){if(sType=="function"){return s;
+}else{if(sType=="string"){try{var f=eval(s);
+if(typeof f=="function"){return f;
+}}catch(e){}}}throw new Error("Expected a function or the name of a function but got "+s);
+}else{if(type=="enum"){var choices=spec.choices;
+for(var i=0;
+i<choices.length;
+i++){if(choices[i]==s){return s;
+}}throw new Error("Expected one of "+choices.join(", ")+" but got "+s);
+}else{throw new Error("Unknown setting type "+type);
+}}}}}}};
+Exhibit.SettingsUtilities.createAccessors=function(config,specs,accessors){Exhibit.SettingsUtilities._internalCreateAccessors(function(field){return config[field];
+},specs,accessors);
+};
+Exhibit.SettingsUtilities.createAccessorsFromDOM=function(configElmt,specs,accessors){Exhibit.SettingsUtilities._internalCreateAccessors(function(field){return Exhibit.getAttribute(configElmt,field);
+},specs,accessors);
+};
+Exhibit.SettingsUtilities._internalCreateAccessors=function(f,specs,accessors){for(var field in specs){var spec=specs[field];
+var accessorName=spec.accessorName;
+var accessor=null;
+var isTuple=false;
+var createOneAccessor=function(spec2){isTuple=false;
+if("bindings" in spec2){return Exhibit.SettingsUtilities._createBindingsAccessor(f,spec2.bindings);
+}else{if("bindingNames" in spec2){isTuple=true;
+return Exhibit.SettingsUtilities._createTupleAccessor(f,spec2);
+}else{return Exhibit.SettingsUtilities._createElementalAccessor(f,spec2);
+}}};
+if("alternatives" in spec){var alternatives=spec.alternatives;
+for(var i=0;
+i<alternatives.length;
+i++){accessor=createOneAccessor(alternatives[i]);
+if(accessor!=null){break;
+}}}else{accessor=createOneAccessor(spec);
+}if(accessor!=null){accessors[accessorName]=accessor;
+}else{if(!(accessorName in accessors)){accessors[accessorName]=function(value,database,visitor){};
+}}}};
+Exhibit.SettingsUtilities._createBindingsAccessor=function(f,bindingSpecs){var bindings=[];
+for(var i=0;
+i<bindingSpecs.length;
+i++){var bindingSpec=bindingSpecs[i];
+var accessor=null;
+var isTuple=false;
+if("bindingNames" in bindingSpec){isTuple=true;
+accessor=Exhibit.SettingsUtilities._createTupleAccessor(f,bindingSpec);
+}else{accessor=Exhibit.SettingsUtilities._createElementalAccessor(f,bindingSpec);
+}if(accessor==null){if(!("optional" in bindingSpec)||!bindingSpec.optional){return null;
+}}else{bindings.push({bindingName:bindingSpec.bindingName,accessor:accessor,isTuple:isTuple});
+}}return function(value,database,visitor){Exhibit.SettingsUtilities._evaluateBindings(value,database,visitor,bindings);
+};
+};
+Exhibit.SettingsUtilities._createTupleAccessor=function(f,spec){var value=f(spec.attributeName);
+if(value==null){return null;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){return null;
+}}try{var expression=Exhibit.ExpressionParser.parse(value);
+var parsers=[];
+var bindingTypes=spec.types;
+for(var i=0;
+i<bindingTypes.length;
+i++){parsers.push(Exhibit.SettingsUtilities._typeToParser(bindingTypes[i]));
+}var bindingNames=spec.bindingNames;
+var separator=",";
+if("separator" in spec){separator=spec.separator;
+}return function(itemID,database,visitor,tuple){expression.evaluateOnItem(itemID,database).values.visit(function(v){var a=v.split(separator);
+if(a.length==parsers.length){var tuple2={};
+if(tuple){for(var n in tuple){tuple2[n]=tuple[n];
+}}for(var i=0;
+i<bindingNames.length;
+i++){tuple2[bindingNames[i]]=null;
+parsers[i](a[i],function(v){tuple2[bindingNames[i]]=v;
+});
+}visitor(tuple2);
+}});
+};
+}catch(e){SimileAjax.Debug.exception(e);
+return null;
+}};
+Exhibit.SettingsUtilities._createElementalAccessor=function(f,spec){var value=f(spec.attributeName);
+if(value==null){return null;
+}if(typeof value=="string"){value=value.trim();
+if(value.length==0){return null;
+}}var bindingType="text";
+if("type" in spec){bindingType=spec.type;
+}try{var expression=Exhibit.ExpressionParser.parse(value);
+var parser=Exhibit.SettingsUtilities._typeToParser(bindingType);
+return function(itemID,database,visitor){expression.evaluateOnItem(itemID,database).values.visit(function(v){return parser(v,visitor);
+});
+};
+}catch(e){SimileAjax.Debug.exception(e);
+return null;
+}};
+Exhibit.SettingsUtilities._typeToParser=function(type){switch(type){case"text":return Exhibit.SettingsUtilities._textParser;
+case"url":return Exhibit.SettingsUtilities._urlParser;
+case"float":return Exhibit.SettingsUtilities._floatParser;
+case"int":return Exhibit.SettingsUtilities._intParser;
+case"date":return Exhibit.SettingsUtilities._dateParser;
+case"boolean":return Exhibit.SettingsUtilities._booleanParser;
+default:throw new Error("Unknown setting type "+type);
+}};
+Exhibit.SettingsUtilities._textParser=function(v,f){return f(v);
+};
+Exhibit.SettingsUtilities._floatParser=function(v,f){var n=parseFloat(v);
+if(!isNaN(n)){return f(n);
+}return false;
+};
+Exhibit.SettingsUtilities._intParser=function(v,f){var n=parseInt(v);
+if(!isNaN(n)){return f(n);
+}return false;
+};
+Exhibit.SettingsUtilities._dateParser=function(v,f){if(v instanceof Date){return f(v);
+}else{if(typeof v=="number"){var d=new Date(0);
+d.setUTCFullYear(v);
+return f(d);
+}else{var d=SimileAjax.DateTime.parseIso8601DateTime(v.toString());
+if(d!=null){return f(d);
+}}}return false;
+};
+Exhibit.SettingsUtilities._booleanParser=function(v,f){v=v.toString().toLowerCase();
+if(v=="true"){return f(true);
+}else{if(v=="false"){return f(false);
+}}return false;
+};
+Exhibit.SettingsUtilities._urlParser=function(v,f){return f(Exhibit.Persistence.resolveURL(v.toString()));
+};
+Exhibit.SettingsUtilities._evaluateBindings=function(value,database,visitor,bindings){var maxIndex=bindings.length-1;
+var f=function(tuple,index){var binding=bindings[index];
+var visited=false;
+var recurse=index==maxIndex?function(){visitor(tuple);
+}:function(){f(tuple,index+1);
+};
+if(binding.isTuple){binding.accessor(value,database,function(tuple2){visited=true;
+tuple=tuple2;
+recurse();
+},tuple);
+}else{var bindingName=binding.bindingName;
+binding.accessor(value,database,function(v){visited=true;
+tuple[bindingName]=v;
+recurse();
+});
+}if(!visited){recurse();
+}};
+f({},0);
+};
+
+
+/* util.js */
+Exhibit.Util={};
+Exhibit.Util.round=function(n,precision){precision=precision||1;
+var lg=Math.floor(Math.log(precision)/Math.log(10));
+n=(Math.round(n/precision)*precision).toString();
+var d=n.split(".");
+if(lg>=0){return d[0];
+}lg=-lg;
+d[1]=(d[1]||"").substring(0,lg);
+while(d[1].length<lg){d[1]+="0";
+}return d.join(".");
+};
+if(!Array.prototype.indexOf){Array.prototype.indexOf=function(elt){var len=this.length;
+var from=Number(arguments[1])||0;
+from=(from<0)?Math.ceil(from):Math.floor(from);
+if(from<0){from+=len;
+}for(;
+from<len;
+from++){if(from in this&&this[from]===elt){return from;
+}}return -1;
+};
+}if(!Array.prototype.filter){Array.prototype.filter=function(fun){var len=this.length;
+if(typeof fun!="function"){throw new TypeError();
+}var res=new Array();
+var thisp=arguments[1];
+for(var i=0;
+i<len;
+i++){if(i in this){var val=this[i];
+if(fun.call(thisp,val,i,this)){res.push(val);
+}}}return res;
+};
+}if(!Array.prototype.map){Array.prototype.map=function(f,thisp){if(typeof f!="function"){throw new TypeError();
+}if(typeof thisp=="undefined"){thisp=this;
+}var res=[],length=this.length;
+for(var i=0;
+i<length;
+i++){if(this.hasOwnProperty(i)){res[i]=f.call(thisp,this[i],i,this);
+}}return res;
+};
+}if(!Array.prototype.forEach){Array.prototype.forEach=function(fun){var len=this.length;
+if(typeof fun!="function"){throw new TypeError();
+}var thisp=arguments[1];
+for(var i=0;
+i<len;
+i++){if(i in this){fun.call(thisp,this[i],i,this);
+}}};
+}
+
+/* views.js */
+Exhibit.ViewUtilities=new Object();
+Exhibit.ViewUtilities.openBubbleForItems=function(anchorElmt,arrayOfItemIDs,uiContext){var coords=SimileAjax.DOM.getPageCoordinates(anchorElmt);
+var bubble=SimileAjax.Graphics.createBubbleForPoint(coords.left+Math.round(anchorElmt.offsetWidth/2),coords.top+Math.round(anchorElmt.offsetHeight/2),uiContext.getSetting("bubbleWidth"),uiContext.getSetting("bubbleHeight"));
+Exhibit.ViewUtilities.fillBubbleWithItems(bubble.content,arrayOfItemIDs,uiContext);
+};
+Exhibit.ViewUtilities.fillBubbleWithItems=function(bubbleElmt,arrayOfItemIDs,uiContext){if(bubbleElmt==null){bubbleElmt=document.createElement("div");
+}if(arrayOfItemIDs.length>1){bubbleElmt.className=[bubbleElmt.className,"exhibit-views-bubbleWithItems"].join(" ");
+var ul=document.createElement("ul");
+for(var i=0;
+i<arrayOfItemIDs.length;
+i++){uiContext.format(arrayOfItemIDs[i],"item",function(elmt){var li=document.createElement("li");
+li.appendChild(elmt);
+ul.appendChild(li);
+});
+}bubbleElmt.appendChild(ul);
+}else{var itemLensDiv=document.createElement("div");
+var itemLens=uiContext.getLensRegistry().createLens(arrayOfItemIDs[0],itemLensDiv,uiContext);
+bubbleElmt.appendChild(itemLensDiv);
+}return bubbleElmt;
+};
+Exhibit.ViewUtilities.constructPlottingViewDom=function(div,uiContext,showSummary,resizableDivWidgetSettings,legendWidgetSettings){var dom=SimileAjax.DOM.createDOMFromString(div,"<div class='exhibit-views-header'>"+(showSummary?"<div id='collectionSummaryDiv'></div>":"")+"<div id='unplottableMessageDiv' class='exhibit-views-unplottableMessage'></div></div><div id='resizableDiv'></div><div id='legendDiv'></div>",{});
+if(showSummary){dom.collectionSummaryWidget=Exhibit.CollectionSummaryWidget.create({},dom.collectionSummaryDiv,uiContext);
+}dom.resizableDivWidget=Exhibit.ResizableDivWidget.create(resizableDivWidgetSettings,dom.resizableDiv,uiContext);
+dom.plotContainer=dom.resizableDivWidget.getContentDiv();
+if(legendWidgetSettings.colorGradient==true){dom.legendGradientWidget=Exhibit.LegendGradientWidget.create(dom.legendDiv,uiContext);
+}else{dom.legendWidget=Exhibit.LegendWidget.create(legendWidgetSettings,dom.legendDiv,uiContext);
+}dom.setUnplottableMessage=function(totalCount,unplottableItems){Exhibit.ViewUtilities._setUnplottableMessage(dom,totalCount,unplottableItems,uiContext);
+};
+dom.dispose=function(){if(showSummary){dom.collectionSummaryWidget.dispose();
+}dom.resizableDivWidget.dispose();
+dom.legendWidget.dispose();
+};
+return dom;
+};
+Exhibit.ViewUtilities._setUnplottableMessage=function(dom,totalCount,unplottableItems,uiContext){var div=dom.unplottableMessageDiv;
+if(unplottableItems.length==0){div.style.display="none";
+}else{div.innerHTML="";
+var dom=SimileAjax.DOM.createDOMFromString(div,Exhibit.ViewUtilities.l10n.unplottableMessageFormatter(totalCount,unplottableItems,uiContext),{});
+SimileAjax.WindowManager.registerEvent(dom.unplottableCountLink,"click",function(elmt,evt,target){Exhibit.ViewUtilities.openBubbleForItems(elmt,unplottableItems,uiContext);
+});
+div.style.display="block";
+}};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-left.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-left.gif
new file mode 100644
index 00000000..271a31c8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-left.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-right.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-right.gif
new file mode 100644
index 00000000..1418bd03
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/arrow-right.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check-no-border.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check-no-border.png
new file mode 100644
index 00000000..71c696c5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check-no-border.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check.png
new file mode 100644
index 00000000..ae3f8cf6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/black-check.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/blank-16x16.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/blank-16x16.png
new file mode 100644
index 00000000..a580e590
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/blank-16x16.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/collapse.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/collapse.png
new file mode 100644
index 00000000..ace11b63
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/collapse.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/day-with-items-bkgrd.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/day-with-items-bkgrd.gif
new file mode 100644
index 00000000..38480916
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/day-with-items-bkgrd.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/down-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/down-arrow.png
new file mode 100644
index 00000000..0121f605
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/down-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/expand.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/expand.png
new file mode 100644
index 00000000..fbc3e583
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/expand.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check-no-border.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check-no-border.png
new file mode 100644
index 00000000..510ab285
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check-no-border.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check.png
new file mode 100644
index 00000000..fa8e8b5d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/gray-check.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/left-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/left-arrow.png
new file mode 100644
index 00000000..0c031fee
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/left-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/liveclipboard-icon.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/liveclipboard-icon.png
new file mode 100644
index 00000000..b8f5ed35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/liveclipboard-icon.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/map-marker-shadow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/map-marker-shadow.png
new file mode 100644
index 00000000..52debb7a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/map-marker-shadow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-left.png
new file mode 100644
index 00000000..4f8c64a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-right.png
new file mode 100644
index 00000000..a8834bb6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-left.png
new file mode 100644
index 00000000..b6416aab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-right.png
new file mode 100644
index 00000000..729524bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-left.png
new file mode 100644
index 00000000..b0501341
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-right.png
new file mode 100644
index 00000000..01a82ab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/message-bubble/message-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-left.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-left.gif
new file mode 100644
index 00000000..b1259142
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-left.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-right.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-right.gif
new file mode 100644
index 00000000..7870f8ba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/month-header-right.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check-no-border.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check-no-border.png
new file mode 100644
index 00000000..a580e590
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check-no-border.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check.png
new file mode 100644
index 00000000..621c523e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/no-check.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option-check.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option-check.png
new file mode 100644
index 00000000..0603e3e1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option-check.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option.png
new file mode 100644
index 00000000..9433dcf6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/option.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/progress-running.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/progress-running.gif
new file mode 100644
index 00000000..f7429ebc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/progress-running.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/right-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/right-arrow.png
new file mode 100644
index 00000000..1bf0e28c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/right-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle.png
new file mode 100644
index 00000000..94146f71
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle2.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle2.png
new file mode 100644
index 00000000..81248478
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/slider-handle2.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/up-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/up-arrow.png
new file mode 100644
index 00000000..73b1af51
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/up-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector-active.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector-active.gif
new file mode 100644
index 00000000..2a62a69b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector-active.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector.gif
new file mode 100644
index 00000000..5c57c9c9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/images/week-selector.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/exhibit-de-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/exhibit-de-bundle.js
new file mode 100644
index 00000000..dce7ed68
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/exhibit-de-bundle.js
@@ -0,0 +1,180 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Element",pluralLabel:"Elemente",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"Bezeichnung",pluralLabel:"Bezeichnungen",reverseLabel:"Bezeichnung von",reversePluralLabel:"Bezeichnungen von"};
+Exhibit.Database.l10n.typeProperty={label:"Typ",pluralLabel:"Typen",reverseLabel:"Typ von",reversePluralLabel:"Typen von"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI von",reversePluralLabel:"URIs von"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"kleinstes zuerst",descending:"größtes zuerst"},"date":{ascending:"frühestes zuerst",descending:"spätestes zuerst"},"boolean":{ascending:"falsch zuerst",descending:"wahr zuerst"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(F,C,G,B){var A=F==1?Exhibit.Database.l10n.itemType.label:Exhibit.Database.l10n.itemType.pluralLabel;
+var E=G.getType(C);
+if(E){A=E.getLabel();
+if(F!=1){var H=E.getProperty("pluralLabel");
+if(H){A=H;
+}}}var D=document.createElement("span");
+D.innerHTML="<span class='"+B+"'>"+F+"</span> "+A;
+return D;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="fehlend";
+Exhibit.l10n.missingSortKey="(fehlend)";
+Exhibit.l10n.notApplicableSortKey="(k.A.)";
+Exhibit.l10n.itemLinkLabel="Verweis";
+Exhibit.l10n.busyIndicatorMessage="Bitte warten...";
+Exhibit.l10n.showDocumentationMessage="Der relevante Teil der Dokumentation wird nach nach dieser Nachricht angezeigt.";
+Exhibit.l10n.showJavascriptValidationMessage="Dieser Fehler wird detailliert nach dieser Nachricht erklärt.";
+Exhibit.l10n.showJsonValidationMessage="Dieser Fehler wird detailliert nach dieser Nachricht erklärt.";
+Exhibit.l10n.showJsonValidationFormMessage="Nach dieser Nachricht werden Sie zu einem Webservice weitergeleitet, mit dessen Hilfe Sie ihren Code überprüfen können.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"Die JSON Datei\n "+A+"\nenthält Fehler =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"Die Datei\n "+A+"\nkann nicht gefunden werden. Bitte überprüfen Sie den Dateinamen.";
+};
+Exhibit.l10n.exportButtonLabel="Exportieren";
+Exhibit.l10n.exportAllButtonLabel="Alles Exportieren";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="Schließen";
+Exhibit.l10n.exportDialogBoxPrompt="Kopieren Sie diesen Code wie normalen Text in die Zwischenablage. Drücken Sie ESC um dieses Dialogfenster zu schliessen.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Schließen";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tabulator-getrennte Werte";
+Exhibit.l10n.htmlExporterLabel="Erzeugtes HTML dieser Ansicht";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=" und ";
+Exhibit.Formatter.l10n.listPairSeparator=" und ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="wahr";
+Exhibit.Formatter.l10n.booleanFalse="falsch";
+Exhibit.Formatter.l10n.currencySymbol="€";
+Exhibit.Formatter.l10n.currencySymbolPlacement="first";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd.MM.yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd.MM.yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, d. MMM yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, d. MMM, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, d. MMMM, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, d. MMMM, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, d. MMMM, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, d. MMMM, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["So","Mo","Di","Mi","Do","Fr","Sa"];
+Exhibit.Formatter.l10n.daysOfWeek=["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"];
+Exhibit.Formatter.l10n.months=["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"];
+Exhibit.Formatter.l10n.commonEra="u.Z.";
+Exhibit.Formatter.l10n.beforeCommonEra="v.u.Z";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Diese Sortierung aufheben";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="sortiert nach: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Sortiere die Elemente ferner nach'>sowie nach...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sortiert nach "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Hebe Sortierung nach "+B+" auf ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="Gruppierung wie Sortierung";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="Gruppierung nach Sortierung";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="hebe Gruppierung nach Sortierung auf";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="zeige alle Ergebnisse";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="zeige die ersten paar Ergebnisse";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Zeige nur die ersten "+A+" Ergebnisse";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Zeige alle "+A+" Ergebnisse";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tabelle";
+Exhibit.TabularView.l10n.viewTooltip="Zeige Elemente in einer Tabelle";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Nach dieser Spalte sortieren";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="In umgekehrter Reihenfolge sortieren";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"aufsteigend sortiert nach ":"absteigend sortiert nach ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Vorschaubilder";
+Exhibit.ThumbnailView.l10n.viewTooltip="Zeige Elemente als Vorschaubilder";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Kachelansicht";
+Exhibit.TileView.l10n.viewTooltip="Zeige Elemente in einer Kachelansicht (als Liste)";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"Wähle Sicht "+A;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="Der Beschreibung einer der Sichten fehlt das viewClass Attribut.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"Der angegebene Wert '"+A+"' des viewClass Attributs\neiner der Sichten ist keine Javascript Funktion.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"Der angegebene Wert '"+A+"' des viewClass Attributs\neiner der Sichten ist kein gültiger Javascript Ausdruck.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Alle Filter zurücksetzen";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Alle Filter zurücksetzen und ursprüngliche Elemente anzeigen";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Alle Filter zurücksetzen";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> Ergebnisse</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> gefiltert von ursprünglich <span id='originalCountSpan'>0</span> (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="gemischt";
+Exhibit.Coders.l10n.missingCaseLabel="fehlend";
+Exhibit.Coders.l10n.othersCaseLabel="andere";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Auswahl aufheben";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Auswahl %0 in Facette %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Auswahl %0 in Facette %1 aufheben";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Wähle nur %0 in Facette %1 aus";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Lösche Auswahl in Facette %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Textsuche %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Textsuche zurücksetzen";
+Exhibit.FacetUtilities.l10n.missingThisField="(Feld fehlt)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> von <class class='exhibit-views-totalCount'>%1</span> können nicht angezeigt werden.",[D==1?(D+" Ergebnis"):(D+" Ergebnisse"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/locale.js
new file mode 100644
index 00000000..48d51e49
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/locale.js
@@ -0,0 +1,38 @@
+/*==================================================
+ * German localization
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/de/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-de-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-de-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/data/database-l10n.js
new file mode 100644
index 00000000..f3ceddf3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/data/database-l10n.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.Database German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Element",
+ pluralLabel: "Elemente",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "Bezeichnung",
+ pluralLabel: "Bezeichnungen",
+ reverseLabel: "Bezeichnung von",
+ reversePluralLabel: "Bezeichnungen von"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "Typ",
+ pluralLabel: "Typen",
+ reverseLabel: "Typ von",
+ reversePluralLabel: "Typen von"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI von",
+ reversePluralLabel: "URIs von"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "kleinstes zuerst",
+ descending: "größtes zuerst"
+ },
+ "date": {
+ ascending: "frühestes zuerst",
+ descending: "spätestes zuerst"
+ },
+ "boolean": {
+ ascending: "falsch zuerst",
+ descending: "wahr zuerst"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = count == 1 ? Exhibit.Database.l10n.itemType.label :
+ Exhibit.Database.l10n.itemType.pluralLabel
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+ if (count != 1) {
+ var pluralLabel = type.getProperty("pluralLabel");
+ if (pluralLabel) {
+ label = pluralLabel;
+ }
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span> " + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..857e2638
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "fehlend";
+Exhibit.l10n.missingSortKey = "(fehlend)";
+Exhibit.l10n.notApplicableSortKey = "(k.A.)";
+Exhibit.l10n.itemLinkLabel = "Verweis";
+
+Exhibit.l10n.busyIndicatorMessage = "Bitte warten...";
+Exhibit.l10n.showDocumentationMessage = "Der relevante Teil der Dokumentation wird nach nach dieser Nachricht angezeigt.";
+Exhibit.l10n.showJavascriptValidationMessage = "Dieser Fehler wird detailliert nach dieser Nachricht erklärt.";
+
+Exhibit.l10n.showJsonValidationMessage = "Dieser Fehler wird detailliert nach dieser Nachricht erklärt.";
+Exhibit.l10n.showJsonValidationFormMessage = "Nach dieser Nachricht werden Sie zu einem Webservice weitergeleitet, mit dessen Hilfe Sie ihren Code überprüfen können.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "Die JSON Datei\n " + url + "\nenthält Fehler =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "Die Datei\n " + url + "\nkann nicht gefunden werden. Bitte überprüfen Sie den Dateinamen.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Exportieren";
+Exhibit.l10n.exportAllButtonLabel = "Alles Exportieren";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "Schließen";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Kopieren Sie diesen Code wie normalen Text in die Zwischenablage. Drücken Sie ESC um dieses Dialogfenster zu schliessen.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Schließen";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tabulator-getrennte Werte";
+Exhibit.l10n.htmlExporterLabel = "Erzeugtes HTML dieser Ansicht";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..f22e64d7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = " und ";
+Exhibit.Formatter.l10n.listPairSeparator = " und ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "wahr";
+Exhibit.Formatter.l10n.booleanFalse = "falsch";
+
+Exhibit.Formatter.l10n.currencySymbol = "€";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "first"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd.MM.yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd.MM.yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, d. MMM yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, d. MMM, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, d. MMMM, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, d. MMMM, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, d. MMMM, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, d. MMMM, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez" ];
+Exhibit.Formatter.l10n.months = [ "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" ];
+
+Exhibit.Formatter.l10n.commonEra = "u.Z.";
+Exhibit.Formatter.l10n.beforeCommonEra = "v.u.Z";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..34e9fa85
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..7249cebd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..7e24ffd9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Diese Sortierung aufheben";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "sortiert nach: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Sortiere die Elemente ferner nach'>sowie nach...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sortiert nach " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Hebe Sortierung nach " + propertyLabel + " auf (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "Gruppierung wie Sortierung";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "Gruppierung nach Sortierung";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "hebe Gruppierung nach Sortierung auf";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "zeige alle Ergebnisse";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "zeige die ersten paar Ergebnisse";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Zeige nur die ersten " + limitCount + " Ergebnisse";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Zeige alle " + count + " Ergebnisse";
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..940b34d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView German localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tabelle";
+Exhibit.TabularView.l10n.viewTooltip = "Zeige Elemente in einer Tabelle";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Nach dieser Spalte sortieren";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "In umgekehrter Reihenfolge sortieren";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "aufsteigend sortiert nach " : "absteigend sortiert nach ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..ef09ad89
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Vorschaubilder";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Zeige Elemente als Vorschaubilder";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..32b16084
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Kachelansicht";
+Exhibit.TileView.l10n.viewTooltip = "Zeige Elemente in einer Kachelansicht (als Liste)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..02cef697
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "Wähle Sicht " + viewLabel;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "Der Beschreibung einer der Sichten fehlt das viewClass Attribut.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "Der angegebene Wert '" + expr + "' des viewClass Attributs\n" +
+ "einer der Sichten ist keine Javascript Funktion.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "Der angegebene Wert '" + expr + "' des viewClass Attributs\n" +
+ "einer der Sichten ist kein gültiger Javascript Ausdruck.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..b45a794a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Alle Filter zurücksetzen";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Alle Filter zurücksetzen und ursprüngliche Elemente anzeigen";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Alle Filter zurücksetzen";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'><span class='%1'>0</span> Ergebnisse</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "gefiltert von ursprünglich <span id='originalCountSpan'>0</span> (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..fc909708
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "gemischt";
+Exhibit.Coders.l10n.missingCaseLabel = "fehlend";
+Exhibit.Coders.l10n.othersCaseLabel = "andere";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..6618787c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Auswahl aufheben";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Auswahl %0 in Facette %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Auswahl %0 in Facette %1 aufheben";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Wähle nur %0 in Facette %1 aus";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Lösche Auswahl in Facette %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Textsuche %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Textsuche zurücksetzen";
+Exhibit.FacetUtilities.l10n.missingThisField = "(Feld fehlt)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/views-l10n.js
new file mode 100644
index 00000000..dd883204
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/de/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities German localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "von <class class='exhibit-views-totalCount'>%1</span> können nicht angezeigt werden.",
+ [ count == 1 ? (count + " Ergebnis") : (count + " Ergebnisse"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/exhibit-en-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/exhibit-en-bundle.js
new file mode 100644
index 00000000..eef3fc56
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/exhibit-en-bundle.js
@@ -0,0 +1,190 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Item",pluralLabel:"Items",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"label",pluralLabel:"labels",reverseLabel:"label of",reversePluralLabel:"labels of"};
+Exhibit.Database.l10n.typeProperty={label:"type",pluralLabel:"types",reverseLabel:"type of",reversePluralLabel:"types of"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI of",reversePluralLabel:"URIs of"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"smallest first",descending:"largest first"},"date":{ascending:"earliest first",descending:"latest first"},"boolean":{ascending:"false first",descending:"true first"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(F,C,G,B){var A=F==1?Exhibit.Database.l10n.itemType.label:Exhibit.Database.l10n.itemType.pluralLabel;
+var E=G.getType(C);
+if(E){A=E.getLabel();
+if(F!=1){var H=E.getProperty("pluralLabel");
+if(H){A=H;
+}}}var D=document.createElement("span");
+D.innerHTML="<span class='"+B+"'>"+F+"</span> "+A;
+return D;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="missing";
+Exhibit.l10n.missingSortKey="(missing)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="link";
+Exhibit.l10n.busyIndicatorMessage="Working...";
+Exhibit.l10n.showDocumentationMessage="We will show the relevant documentation after this message.";
+Exhibit.l10n.showJavascriptValidationMessage="We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationMessage="We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationFormMessage="We will browse to a web service where you can upload and check your code after this message.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"The JSON data file\n "+A+"\ncontains errors =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"We cannot locate the data file\n "+A+"\nCheck that the file name is correct.";
+};
+Exhibit.l10n.exportButtonLabel="Export";
+Exhibit.l10n.exportAllButtonLabel="Export All";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="Close";
+Exhibit.l10n.exportDialogBoxPrompt="Copy this code to your clipboard as you would copy any text. Press ESC to close this dialog box.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Close";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel="Generated HTML of this view";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", and ";
+Exhibit.Formatter.l10n.listPairSeparator=" and ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="true";
+Exhibit.Formatter.l10n.booleanFalse="false";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="first";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Sun","Mon","Tue","Wed","Thr","Fri","Sat"];
+Exhibit.Formatter.l10n.daysOfWeek=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Exhibit.Formatter.l10n.months=["January","February","March","April","May","June","July","August","September","October","November","December"];
+Exhibit.Formatter.l10n.commonEra="CE";
+Exhibit.Formatter.l10n.beforeCommonEra="BCE";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Remove this order";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="sorted by: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Further sort the items'>then by...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sorted by "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Removed order by "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="grouped as sorted";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="group as sorted";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="ungroup as sorted";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Show only the first "+A+" results";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Show all "+A+" results";
+};
+Exhibit.OrderedViewFrame.l10n.pagingControlContainerElement="div";
+Exhibit.OrderedViewFrame.l10n.pagingControlElement="span";
+Exhibit.OrderedViewFrame.l10n.pageWindowEllipses=" ... ";
+Exhibit.OrderedViewFrame.l10n.pageSeparator=" &bull; ";
+Exhibit.OrderedViewFrame.l10n.previousPage="&laquo;&nbsp;Previous";
+Exhibit.OrderedViewFrame.l10n.nextPage="Next&nbsp;&raquo;";
+Exhibit.OrderedViewFrame.l10n.makePagingActionTitle=function(A){return("Page "+(A+1));
+};
+Exhibit.OrderedViewFrame.l10n.makePagingLinkTooltip=function(A){return("Go to page "+(A+1));
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Table";
+Exhibit.TabularView.l10n.viewTooltip="View items in a table";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Click to sort by this column";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Click to sort in the reverse order";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"sorted ascending by ":"sorted descending by ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip="View items as thumbnails";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Tiles";
+Exhibit.TileView.l10n.viewTooltip="View items as tiles in a list";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"select "+A+" view";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views is not a valid Javascript expression.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Clear all filters and see the original items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Reset all filters";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> results</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missing";
+Exhibit.Coders.l10n.othersCaseLabel="others";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Clear these selections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField="(missing this field)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",[D==1?(D+" result"):(D+" results"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/locale.js
new file mode 100644
index 00000000..6c2fbc00
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/locale.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * English localization
+ * (also base and default localization)
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/en/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-en-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-en-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/data/database-l10n.js
new file mode 100644
index 00000000..c0a4b913
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/data/database-l10n.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.Database English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Item",
+ pluralLabel: "Items",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "label",
+ pluralLabel: "labels",
+ reverseLabel: "label of",
+ reversePluralLabel: "labels of"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "type",
+ pluralLabel: "types",
+ reverseLabel: "type of",
+ reversePluralLabel: "types of"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI of",
+ reversePluralLabel: "URIs of"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "smallest first",
+ descending: "largest first"
+ },
+ "date": {
+ ascending: "earliest first",
+ descending: "latest first"
+ },
+ "boolean": {
+ ascending: "false first",
+ descending: "true first"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = count == 1 ? Exhibit.Database.l10n.itemType.label :
+ Exhibit.Database.l10n.itemType.pluralLabel
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+ if (count != 1) {
+ var pluralLabel = type.getProperty("pluralLabel");
+ if (pluralLabel) {
+ label = pluralLabel;
+ }
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span> " + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..6f876b35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "missing";
+Exhibit.l10n.missingSortKey = "(missing)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "link";
+
+Exhibit.l10n.busyIndicatorMessage = "Working...";
+Exhibit.l10n.showDocumentationMessage = "We will show the relevant documentation after this message.";
+Exhibit.l10n.showJavascriptValidationMessage = "We will explain the error in details after this message.";
+
+Exhibit.l10n.showJsonValidationMessage = "We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationFormMessage = "We will browse to a web service where you can upload and check your code after this message.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "The JSON data file\n " + url + "\ncontains errors =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "We cannot locate the data file\n " + url + "\nCheck that the file name is correct.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Export";
+Exhibit.l10n.exportAllButtonLabel = "Export All";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "Close";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Copy this code to your clipboard as you would copy any text. Press ESC to close this dialog box.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Close";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel = "Generated HTML of this view";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..0cc5208f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", and ";
+Exhibit.Formatter.l10n.listPairSeparator = " and ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "true";
+Exhibit.Formatter.l10n.booleanFalse = "false";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "first"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+Exhibit.Formatter.l10n.months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
+
+Exhibit.Formatter.l10n.commonEra = "CE";
+Exhibit.Formatter.l10n.beforeCommonEra = "BCE";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..03be7df7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..4ae89f8c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..12e188b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,46 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Remove this order";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "sorted by: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Further sort the items'>then by...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sorted by " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Removed order by " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "grouped as sorted";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "group as sorted";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "ungroup as sorted";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Show only the first " + limitCount + " results";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Show all " + count + " results";
+};
+
+Exhibit.OrderedViewFrame.l10n.pagingControlContainerElement = "div";
+Exhibit.OrderedViewFrame.l10n.pagingControlElement = "span";
+Exhibit.OrderedViewFrame.l10n.pageWindowEllipses = " ... ";
+Exhibit.OrderedViewFrame.l10n.pageSeparator = " &bull; ";
+Exhibit.OrderedViewFrame.l10n.previousPage = "&laquo;&nbsp;Previous";
+Exhibit.OrderedViewFrame.l10n.nextPage = "Next&nbsp;&raquo;";
+Exhibit.OrderedViewFrame.l10n.makePagingActionTitle = function(pageIndex) {
+ return ("Page " + (pageIndex + 1));
+};
+Exhibit.OrderedViewFrame.l10n.makePagingLinkTooltip = function(pageIndex) {
+ return ("Go to page " + (pageIndex + 1));
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..b52f1769
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView English localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Table";
+Exhibit.TabularView.l10n.viewTooltip = "View items in a table";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Click to sort by this column";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Click to sort in the reverse order";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "sorted ascending by " : "sorted descending by ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..2433fea1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip = "View items as thumbnails";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..143ce958
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Tiles";
+Exhibit.TileView.l10n.viewTooltip = "View items as tiles in a list";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..ca09f0bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "select " + viewLabel + " view";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views is not a valid Javascript expression.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..64ed5c3d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Clear all filters and see the original items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Reset all filters";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'><span class='%1'>0</span> results</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..7f68ce9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missing";
+Exhibit.Coders.l10n.othersCaseLabel = "others";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..e7878db4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Clear these selections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField = "(missing this field)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/views-l10n.js
new file mode 100644
index 00000000..c96020b7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/en/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",
+ [ count == 1 ? (count + " result") : (count + " results"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/exhibit-es-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/exhibit-es-bundle.js
new file mode 100644
index 00000000..6ec3290e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/exhibit-es-bundle.js
@@ -0,0 +1,171 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Elemento",pluralLabel:"Elementos"};
+Exhibit.Database.l10n.labelProperty={label:"etiqueta",pluralLabel:"etiquetas",reverseLabel:"etiqueta de",reversePluralLabel:"etiquetas de"};
+Exhibit.Database.l10n.typeProperty={label:"tipo",pluralLabel:"tipos",reverseLabel:"tipo de",reversePluralLabel:"tipos de"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI de",reversePluralLabel:"URIs de"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"menor primero",descending:"mayor primero"},"date":{ascending:"la más antigua primero",descending:"la más reciente primero"},"boolean":{ascending:"falso primero",descending:"verdadero primero"},"item":{ascending:"a - z",descending:"z - a"}};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="falta";
+Exhibit.l10n.missingSortKey="(falta)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="link";
+Exhibit.l10n.busyIndicatorMessage="Procesando...";
+Exhibit.l10n.showDocumentationMessage="Te enseñaremos la documentación asociada después de este mensaje.";
+Exhibit.l10n.showJavascriptValidationMessage="Te explicaremos los detalles del error después de este mensaje.";
+Exhibit.l10n.showJsonValidationMessage="Te explicaremos los detalles del error después de este mensaje.";
+Exhibit.l10n.showJsonValidationFormMessage="Te redirigiremos a un servicio web donde podrás subir y verificar tu código después de este mensaje.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"El fichero de datos JSON\n "+A+"\ncontiene errores =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"No podemos localizar el fichero de datos\n "+A+"\nComprueba que el nombre del archivo es correcto.";
+};
+Exhibit.l10n.copyButtonLabel="Copiar";
+Exhibit.l10n.copyAllButtonLabel="Copiar todo";
+Exhibit.l10n.copyDialogBoxCloseButtonLabel="Cerrar";
+Exhibit.l10n.copyDialogBoxPrompt="Copia este código en tu clipboard como si fuera texto. Pulsa ESC para cerrar este cuadro de diálogo.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Cerrar";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel="Generated HTML of this view";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", and ";
+Exhibit.Formatter.l10n.listPairSeparator=" and ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="true";
+Exhibit.Formatter.l10n.booleanFalse="false";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="first";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Sun","Mon","Tue","Wed","Thr","Fri","Sat"];
+Exhibit.Formatter.l10n.daysOfWeek=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Exhibit.Formatter.l10n.months=["January","February","March","April","May","June","July","August","September","October","November","December"];
+Exhibit.Formatter.l10n.commonEra="CE";
+Exhibit.Formatter.l10n.beforeCommonEra="BCE";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Eliminar este orden";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="ordenados por: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Seguir ordenando elementos'>luego por...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Ordenados por "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Eliminar ordenación por "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="agrupar según orden";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="agrupar según orden";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="sin agrupar";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Mostrar solamente "+A+" resultados";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Mostrar "+A+" resultados";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tabla";
+Exhibit.TabularView.l10n.viewTooltip="Ver elementos como una tabla";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Click para ordenar por esta columna";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Click para ordenar inversamente";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"ordenado acendentemente por ":"ordenado descendentemente por ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip="Ver elementos como iconos";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Tiles";
+Exhibit.TileView.l10n.viewTooltip="Ver elementos en una lista detallada";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"selecciona "+A+" vista";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="En la especificación de una de las vistas falta el campo viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"El valor del atributo viewClass '"+A+"' espeficicado\nen una de las vistas no se corresponde con una función Javascript.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"El valor del atributo viewClass '"+A+"' especificado\nen una de las vistas no es una expresión Javascript válida.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Elimina algunos filtros para obtener resultados.";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Reset all filters";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'>0</span> <span class='%1' id='typesSpan'>resultados</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missing";
+Exhibit.Coders.l10n.othersCaseLabel="others";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Eliminar estas selecciones";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField="(missing this field)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",[D==1?(D+" result"):(D+" results"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/locale.js
new file mode 100644
index 00000000..87f5b1d7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/locale.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * Spanish localization
+ *
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/es/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-es-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-es-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/data/database-l10n.js
new file mode 100644
index 00000000..aaebc679
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/data/database-l10n.js
@@ -0,0 +1,54 @@
+/*==================================================
+ * Exhibit.Database Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Elemento",
+ pluralLabel: "Elementos"
+
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "etiqueta",
+ pluralLabel: "etiquetas",
+ reverseLabel: "etiqueta de",
+ reversePluralLabel: "etiquetas de"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "tipo",
+ pluralLabel: "tipos",
+ reverseLabel: "tipo de",
+ reversePluralLabel: "tipos de"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI de",
+ reversePluralLabel: "URIs de"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "menor primero",
+ descending: "mayor primero"
+ },
+ "date": {
+ ascending: "la más antigua primero",
+ descending: "la más reciente primero"
+ },
+ "boolean": {
+ ascending: "falso primero",
+ descending: "verdadero primero"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..f8a38f0d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "falta";
+Exhibit.l10n.missingSortKey = "(falta)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "link";
+
+Exhibit.l10n.busyIndicatorMessage = "Procesando...";
+Exhibit.l10n.showDocumentationMessage = "Te enseñaremos la documentación asociada después de este mensaje.";
+Exhibit.l10n.showJavascriptValidationMessage = "Te explicaremos los detalles del error después de este mensaje.";
+
+Exhibit.l10n.showJsonValidationMessage = "Te explicaremos los detalles del error después de este mensaje.";
+Exhibit.l10n.showJsonValidationFormMessage = "Te redirigiremos a un servicio web donde podrás subir y verificar tu código después de este mensaje.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "El fichero de datos JSON\n " + url + "\ncontiene errores =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "No podemos localizar el fichero de datos\n " + url + "\nComprueba que el nombre del archivo es correcto.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.copyButtonLabel = "Copiar";
+Exhibit.l10n.copyAllButtonLabel = "Copiar todo";
+Exhibit.l10n.copyDialogBoxCloseButtonLabel = "Cerrar";
+Exhibit.l10n.copyDialogBoxPrompt =
+ "Copia este código en tu clipboard como si fuera texto. Pulsa ESC para cerrar este cuadro de diálogo.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Cerrar";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel = "Generated HTML of this view";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..908eb399
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", and ";
+Exhibit.Formatter.l10n.listPairSeparator = " and ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "true";
+Exhibit.Formatter.l10n.booleanFalse = "false";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "first"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+Exhibit.Formatter.l10n.months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
+
+Exhibit.Formatter.l10n.commonEra = "CE";
+Exhibit.Formatter.l10n.beforeCommonEra = "BCE";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..f5e25ca0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..ede2ed53
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..39401071
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Eliminar este orden";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "ordenados por: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Seguir ordenando elementos'>luego por...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Ordenados por " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Eliminar ordenación por " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "agrupar según orden";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "agrupar según orden";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "sin agrupar";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Mostrar solamente " + limitCount + " resultados";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Mostrar " + count + " resultados";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..b844b74f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView Spanish localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tabla";
+Exhibit.TabularView.l10n.viewTooltip = "Ver elementos como una tabla";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Click para ordenar por esta columna";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Click para ordenar inversamente";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "ordenado acendentemente por " : "ordenado descendentemente por ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..0b1e855c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Ver elementos como iconos";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..f97af539
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Tiles";
+Exhibit.TileView.l10n.viewTooltip = "Ver elementos en una lista detallada";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..bad06ef8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "selecciona " + viewLabel + " vista";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "En la especificación de una de las vistas falta el campo viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "El valor del atributo viewClass '" + expr + "' espeficicado\n" +
+ "en una de las vistas no se corresponde con una función Javascript.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "El valor del atributo viewClass '" + expr + "' especificado\n" +
+ "en una de las vistas no es una expresión Javascript válida.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..c29594fd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Elimina algunos filtros para obtener resultados.";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Reset all filters";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'>0</span> <span class='%1' id='typesSpan'>resultados</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..7f68ce9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missing";
+Exhibit.Coders.l10n.othersCaseLabel = "others";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..ce1c7ea9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Eliminar estas selecciones";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField = "(missing this field)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/views-l10n.js
new file mode 100644
index 00000000..1b3658bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/es/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities Spanish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",
+ [ count == 1 ? (count + " result") : (count + " results"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/exhibit-fr-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/exhibit-fr-bundle.js
new file mode 100644
index 00000000..60430a7a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/exhibit-fr-bundle.js
@@ -0,0 +1,180 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Item",pluralLabel:"Items",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"libellé",pluralLabel:"libellés",reverseLabel:"libellé de",reversePluralLabel:"libellés de"};
+Exhibit.Database.l10n.typeProperty={label:"type",pluralLabel:"types",reverseLabel:"type de",reversePluralLabel:"types de"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI de",reversePluralLabel:"URIs de"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"du plus petit au plus grand",descending:"du plus grand au plus petit"},"date":{ascending:"du plus ancien au plus récent",descending:"du plus récent au plus ancien"},"boolean":{ascending:"faux en premier",descending:"vrai en premier"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(F,C,G,B){var A=F==1?Exhibit.Database.l10n.itemType.label:Exhibit.Database.l10n.itemType.pluralLabel;
+var E=G.getType(C);
+if(E){A=E.getLabel();
+if(F!=1){var H=E.getProperty("pluralLabel");
+if(H){A=H;
+}}}var D=document.createElement("span");
+D.innerHTML="<span class='"+B+"'>"+F+"</span> "+A;
+return D;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="manquant";
+Exhibit.l10n.missingSortKey="(manquant)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="lien";
+Exhibit.l10n.busyIndicatorMessage="Traitement en cours...";
+Exhibit.l10n.showDocumentationMessage="Vous verrez la documentation appropriée après ce message.";
+Exhibit.l10n.showJavascriptValidationMessage="Vous aurez l'explication détaillée de l'erreur après ce message.";
+Exhibit.l10n.showJsonValidationMessage="Vous aurez l'explication détaillée de l'erreur après ce message.";
+Exhibit.l10n.showJsonValidationFormMessage="Après ce message, vous accéderez à un service web sur lequel vous pourrez transmettre et vérifier votre code.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"Le fichier de données JSON\n "+A+"\ncontient des erreurs :\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"Impossible de trouver le fichier de données\n "+A+"\nVérifiez que le nom du fichier est correct.";
+};
+Exhibit.l10n.exportButtonLabel="Exporter";
+Exhibit.l10n.exportAllButtonLabel="Tout exporter";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="Fermer";
+Exhibit.l10n.exportDialogBoxPrompt="Copiez ce code dans votre presse-papier comme vous le feriez pour un texte. Appuyez sur ESC pour fermer cette fenêtre.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Fermer";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Valeurs séparées par tabulation";
+Exhibit.l10n.htmlExporterLabel="Exportation HTML";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", et ";
+Exhibit.Formatter.l10n.listPairSeparator=" et ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="vrai";
+Exhibit.Formatter.l10n.booleanFalse="faux";
+Exhibit.Formatter.l10n.currencySymbol="€";
+Exhibit.Formatter.l10n.currencySymbolPlacement="last";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE d MMM yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE d MMM yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEE d MMM yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE d MMM yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"];
+Exhibit.Formatter.l10n.daysOfWeek=["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Fév","Mar","Avr","Mai","Jun","Jul","Aou","Sep","Oct","Nov","Déc"];
+Exhibit.Formatter.l10n.months=["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"];
+Exhibit.Formatter.l10n.commonEra="ap J-C";
+Exhibit.Formatter.l10n.beforeCommonEra="av J-C";
+Exhibit.Formatter.l10n.beforeNoon="mat";
+Exhibit.Formatter.l10n.afterNoon="a-m";
+Exhibit.Formatter.l10n.BeforeNoon="MAT";
+Exhibit.Formatter.l10n.AfterNoon="A-M";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Retirer ce critère";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="Trier par : <span id='ordersSpan'></span>, <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Ajouter un item'>puis par...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Trier par "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Critère de tri retiré : "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="Grouper selon le tri";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="Grouper selon le tri";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="Dégrouper selon le tri";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="Voir tous les résultats";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="Voir les premiers résultats";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Montrer seulement les "+A+" premiers résultats";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Montrer l'ensemble des "+A+" résultats";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tableau";
+Exhibit.TabularView.l10n.viewTooltip="Voir les items dans un tableau";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Cliquer pour trier sur cette colonne";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Cliquer pour trier dans l'ordre inverse";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"triés par ordre croissant selon ":"triés par ordre décroissant selon ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Vignettes";
+Exhibit.ThumbnailView.l10n.viewTooltip="Voir les items commes des vignettes";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Blocs";
+Exhibit.TileView.l10n.viewTooltip="Voir les items sous forme de blocs dans une liste";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"Sélectionner la vue "+A;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="La spécification pour une des vues ne contient pas le champ viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"La valeur '"+A+"' de l'attribut viewClass que vous avez spécifiée\npour une des vues ne correspond pas à une fonction Javascript.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"La valeur '"+A+"' de l'attribut viewClass que vous avez spécifiée\npour une des vues n'est pas une expression Javascript valide.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Réinitialiser tous les filtres";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Retirer tous les filtres et voir les items d'origine";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Retirer tous les filtres";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> résultats</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> filtrés sur un total de <span id='originalCountSpan'>0</span> items (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missing";
+Exhibit.Coders.l10n.othersCaseLabel="others";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Effacer ces sélections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Sélectionner %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Déselectionner %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Sélectionner seulement %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Effacer les sélections dans la facette %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Recherche du texte %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Effacer la recherche de texte";
+Exhibit.FacetUtilities.l10n.missingThisField="(missing this field)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> sur <class class='exhibit-views-totalCount'>%1</span> ne peuvent pas être tracés.",[D==1?(D+" résultat"):(D+" résultats"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/locale.js
new file mode 100644
index 00000000..01a64fe0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/locale.js
@@ -0,0 +1,38 @@
+/*==================================================
+ * French localization
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/fr/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-fr-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-fr-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/data/database-l10n.js
new file mode 100644
index 00000000..5a8cbf79
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/data/database-l10n.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.Database French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Item",
+ pluralLabel: "Items",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "libellé",
+ pluralLabel: "libellés",
+ reverseLabel: "libellé de",
+ reversePluralLabel: "libellés de"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "type",
+ pluralLabel: "types",
+ reverseLabel: "type de",
+ reversePluralLabel: "types de"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI de",
+ reversePluralLabel: "URIs de"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "du plus petit au plus grand",
+ descending: "du plus grand au plus petit"
+ },
+ "date": {
+ ascending: "du plus ancien au plus récent",
+ descending: "du plus récent au plus ancien"
+ },
+ "boolean": {
+ ascending: "faux en premier",
+ descending: "vrai en premier"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = count == 1 ? Exhibit.Database.l10n.itemType.label :
+ Exhibit.Database.l10n.itemType.pluralLabel
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+ if (count != 1) {
+ var pluralLabel = type.getProperty("pluralLabel");
+ if (pluralLabel) {
+ label = pluralLabel;
+ }
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span> " + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..8badecc2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "manquant";
+Exhibit.l10n.missingSortKey = "(manquant)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "lien";
+
+Exhibit.l10n.busyIndicatorMessage = "Traitement en cours...";
+Exhibit.l10n.showDocumentationMessage = "Vous verrez la documentation appropriée après ce message.";
+Exhibit.l10n.showJavascriptValidationMessage = "Vous aurez l'explication détaillée de l'erreur après ce message.";
+
+Exhibit.l10n.showJsonValidationMessage = "Vous aurez l'explication détaillée de l'erreur après ce message.";
+Exhibit.l10n.showJsonValidationFormMessage = "Après ce message, vous accéderez à un service web sur lequel vous pourrez transmettre et vérifier votre code.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "Le fichier de données JSON\n " + url + "\ncontient des erreurs :\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "Impossible de trouver le fichier de données\n " + url + "\nVérifiez que le nom du fichier est correct.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Exporter";
+Exhibit.l10n.exportAllButtonLabel = "Tout exporter";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "Fermer";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Copiez ce code dans votre presse-papier comme vous le feriez pour un texte. Appuyez sur ESC pour fermer cette fenêtre.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Fermer";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Valeurs séparées par tabulation";
+Exhibit.l10n.htmlExporterLabel = "Exportation HTML";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..1c5bbdaf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", et ";
+Exhibit.Formatter.l10n.listPairSeparator = " et ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "vrai";
+Exhibit.Formatter.l10n.booleanFalse = "faux";
+
+Exhibit.Formatter.l10n.currencySymbol = "€";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "last"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE d MMM yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE d MMM yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEE d MMM yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEE d MMM yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE d MMM yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Fév", "Mar", "Avr", "Mai", "Jun", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc" ];
+Exhibit.Formatter.l10n.months = [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" ];
+
+Exhibit.Formatter.l10n.commonEra = "ap J-C";
+Exhibit.Formatter.l10n.beforeCommonEra = "av J-C";
+
+Exhibit.Formatter.l10n.beforeNoon = "mat";
+Exhibit.Formatter.l10n.afterNoon = "a-m";
+
+Exhibit.Formatter.l10n.BeforeNoon = "MAT";
+Exhibit.Formatter.l10n.AfterNoon = "A-M";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..5f30dcde
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..c7392424
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..4c2cd0eb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Retirer ce critère";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "Trier par : <span id='ordersSpan'></span>, <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Ajouter un item'>puis par...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Trier par " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Critère de tri retiré : " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "Grouper selon le tri";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "Grouper selon le tri";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "Dégrouper selon le tri";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "Voir tous les résultats";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "Voir les premiers résultats";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Montrer seulement les " + limitCount + " premiers résultats";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Montrer l'ensemble des " + count + " résultats";
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..30a6ba35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView French localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tableau";
+Exhibit.TabularView.l10n.viewTooltip = "Voir les items dans un tableau";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Cliquer pour trier sur cette colonne";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Cliquer pour trier dans l'ordre inverse";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "triés par ordre croissant selon " : "triés par ordre décroissant selon ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..6cfaccbb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Vignettes";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Voir les items commes des vignettes";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..dedb5e8e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Blocs";
+Exhibit.TileView.l10n.viewTooltip = "Voir les items sous forme de blocs dans une liste";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..fa8ba4ce
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "Sélectionner la vue " + viewLabel;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "La spécification pour une des vues ne contient pas le champ viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "La valeur '" + expr + "' de l'attribut viewClass que vous avez spécifiée\n" +
+ "pour une des vues ne correspond pas à une fonction Javascript.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "La valeur '" + expr + "' de l'attribut viewClass que vous avez spécifiée\n" +
+ "pour une des vues n'est pas une expression Javascript valide.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..567e9fd7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Réinitialiser tous les filtres";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Retirer tous les filtres et voir les items d'origine";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Retirer tous les filtres";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'><span class='%1'>0</span> résultats</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "filtrés sur un total de <span id='originalCountSpan'>0</span> items (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..7f68ce9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missing";
+Exhibit.Coders.l10n.othersCaseLabel = "others";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..cc8109cc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Effacer ces sélections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Sélectionner %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Déselectionner %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Sélectionner seulement %0 dans la facette %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Effacer les sélections dans la facette %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Recherche du texte %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Effacer la recherche de texte";
+Exhibit.FacetUtilities.l10n.missingThisField = "(missing this field)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/views-l10n.js
new file mode 100644
index 00000000..e4166254
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/fr/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities French localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "sur <class class='exhibit-views-totalCount'>%1</span> ne peuvent pas être tracés.",
+ [ count == 1 ? (count + " résultat") : (count + " résultats"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/exhibit-nl-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/exhibit-nl-bundle.js
new file mode 100644
index 00000000..5192959b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/exhibit-nl-bundle.js
@@ -0,0 +1,180 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Element",pluralLabel:"Elemente",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"Bezeichnung",pluralLabel:"Bezeichnungen",reverseLabel:"Bezeichnung von",reversePluralLabel:"Bezeichnungen von"};
+Exhibit.Database.l10n.typeProperty={label:"Type",pluralLabel:"Typen",reverseLabel:"Type van",reversePluralLabel:"Typen van"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI van",reversePluralLabel:"URIs van"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"kleinste eerst",descending:"grootste eerst"},"date":{ascending:"eerste eerst",descending:"laatste eerst"},"boolean":{ascending:"foutief eerst",descending:"correct eerst"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(F,C,G,B){var A=F==1?Exhibit.Database.l10n.itemType.label:Exhibit.Database.l10n.itemType.pluralLabel;
+var E=G.getType(C);
+if(E){A=E.getLabel();
+if(F!=1){var H=E.getProperty("pluralLabel");
+if(H){A=H;
+}}}var D=document.createElement("span");
+D.innerHTML="<span class='"+B+"'>"+F+"</span> "+A;
+return D;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="missend";
+Exhibit.l10n.missingSortKey="(missend)";
+Exhibit.l10n.notApplicableSortKey="(niet beschikbaar)";
+Exhibit.l10n.itemLinkLabel="link";
+Exhibit.l10n.busyIndicatorMessage="Even wachten aub...";
+Exhibit.l10n.showDocumentationMessage="We zullen de relevante informatie tonen na dit bericht.";
+Exhibit.l10n.showJavascriptValidationMessage="We zullen de fout gedetailleerd uitleggen na dit bericht.";
+Exhibit.l10n.showJsonValidationMessage="We zullen de fout gedetailleerd uitleggen na dit bericht.";
+Exhibit.l10n.showJsonValidationFormMessage="We zullen naar een website surfen waar u uw code kunt uploaden en checken..";
+Exhibit.l10n.badJsonMessage=function(A,B){return"De JSON-data\n "+A+"\nbevat fouten =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"De data\n "+A+"\nkan niet gevonden worden. Is de bestandsnaam wel correct?";
+};
+Exhibit.l10n.exportButtonLabel="Exporteren";
+Exhibit.l10n.exportAllButtonLabel="Alles exporteren";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="sluiten";
+Exhibit.l10n.exportDialogBoxPrompt="Kopieer deze code naar het clipboard, zoals u ook zou doen met tekst. Druk op ESC om dit dialoogvenster te sluiten.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Sluiten";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantische wikitekst";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tab gescheiden waardes";
+Exhibit.l10n.htmlExporterLabel="Generateer hier HTML van";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", en ";
+Exhibit.Formatter.l10n.listPairSeparator=" en ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="correct";
+Exhibit.Formatter.l10n.booleanFalse="foutief";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="eerste";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["zo","ma","di","wo","do","vr","za"];
+Exhibit.Formatter.l10n.daysOfWeek=["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"];
+Exhibit.Formatter.l10n.shortMonths=["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"];
+Exhibit.Formatter.l10n.months=["Januari","februari","maart","april","mei","june","july","augustus","september","oktober","november","december"];
+Exhibit.Formatter.l10n.commonEra="A.D.";
+Exhibit.Formatter.l10n.beforeCommonEra="B.C.";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Verwijder deze sortering";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="Sortering: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Sorteer deze items'>daarna door...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sortering is "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Verwijder sortering "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="Groepering zoals gesorteerd";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="Groepeer zoals gesorteerd";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="Hef groupering zoals gesorteerd op";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="Toon alle resultaten";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="Toon alleen de eerste paar resultaten";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Toon alleen de eerste "+A+" resultaten";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Toon alle "+A+" resultaten";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tabel";
+Exhibit.TabularView.l10n.viewTooltip="Toon items in een tabel";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Klik om deze kolom te sorteren";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Klik om deze kolom te sorteren in omgekeerde volgorder";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"Sorteer oplopend ":"sorteer aflopend ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Miniaturen";
+Exhibit.ThumbnailView.l10n.viewTooltip="Toon items als miniaturen";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Tegels";
+Exhibit.TileView.l10n.viewTooltip="Toon items als tegels in een lijst";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"selecteer "+A+" toon";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="De beschrijving voor een van de zichten mist het viewClass-veld.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"De waarde van het viewClass attribuut '"+A+"' die u heeft aangegeven\nvoor een van de zichten lijkt geen javascriptfunctie te zijn.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"De waarde van het viewClass attribuut '"+A+"' die u heeft aangegeven\nvoor een van de zichten lijkt geen javascriptexpressie te zijn.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Reset alle filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Maak alle filters leeg en toon de oorspronkelijke items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Reset alle filters";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> resultaten</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> <span id='originalCountSpan'>0</span> gefilterd van oorspronkelijk (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missend";
+Exhibit.Coders.l10n.othersCaseLabel="anders";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Maak deze selecties leeg";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Selecteer %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Hef selectie %0 in facet %1 op";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Selecteer alleen %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Maak selecties in facet %0 leeg";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Tekst doorzoeken %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Maak veld tekst doorzoeken leeg";
+Exhibit.FacetUtilities.l10n.missingThisField="(mist dit veld)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> van <class class='exhibit-views-totalCount'>%1</span> kan niet worden afgebeeld.",[D==1?(D+" result"):(D+" results"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/locale.js
new file mode 100644
index 00000000..0958ad04
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/locale.js
@@ -0,0 +1,38 @@
+/*==================================================
+ * Dutch localization
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/nl/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-nl-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-nl-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/data/database-l10n.js
new file mode 100644
index 00000000..b847c715
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/data/database-l10n.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.Database Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Element",
+ pluralLabel: "Elemente",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "Bezeichnung",
+ pluralLabel: "Bezeichnungen",
+ reverseLabel: "Bezeichnung von",
+ reversePluralLabel: "Bezeichnungen von"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "Type",
+ pluralLabel: "Typen",
+ reverseLabel: "Type van",
+ reversePluralLabel: "Typen van"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI van",
+ reversePluralLabel: "URIs van"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "kleinste eerst",
+ descending: "grootste eerst"
+ },
+ "date": {
+ ascending: "eerste eerst",
+ descending: "laatste eerst"
+ },
+ "boolean": {
+ ascending: "foutief eerst",
+ descending: "correct eerst"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = count == 1 ? Exhibit.Database.l10n.itemType.label :
+ Exhibit.Database.l10n.itemType.pluralLabel
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+ if (count != 1) {
+ var pluralLabel = type.getProperty("pluralLabel");
+ if (pluralLabel) {
+ label = pluralLabel;
+ }
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span> " + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..63fc97f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "missend";
+Exhibit.l10n.missingSortKey = "(missend)";
+Exhibit.l10n.notApplicableSortKey = "(niet beschikbaar)";
+Exhibit.l10n.itemLinkLabel = "link";
+
+Exhibit.l10n.busyIndicatorMessage = "Even wachten aub...";
+Exhibit.l10n.showDocumentationMessage = "We zullen de relevante informatie tonen na dit bericht.";
+Exhibit.l10n.showJavascriptValidationMessage = "We zullen de fout gedetailleerd uitleggen na dit bericht.";
+
+Exhibit.l10n.showJsonValidationMessage = "We zullen de fout gedetailleerd uitleggen na dit bericht.";
+Exhibit.l10n.showJsonValidationFormMessage = "We zullen naar een website surfen waar u uw code kunt uploaden en checken..";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "De JSON-data\n " + url + "\nbevat fouten =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "De data\n " + url + "\nkan niet gevonden worden. Is de bestandsnaam wel correct?";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Exporteren";
+Exhibit.l10n.exportAllButtonLabel = "Alles exporteren";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "sluiten";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Kopieer deze code naar het clipboard, zoals u ook zou doen met tekst. Druk op ESC om dit dialoogvenster te sluiten.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Sluiten";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantische wikitekst";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tab gescheiden waardes";
+Exhibit.l10n.htmlExporterLabel = "Generateer hier HTML van";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..116a8498
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", en ";
+Exhibit.Formatter.l10n.listPairSeparator = " en ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "correct";
+Exhibit.Formatter.l10n.booleanFalse = "foutief";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "eerste"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek=["zo","ma","di","wo","do","vr","za"];
+Exhibit.Formatter.l10n.daysOfWeek=["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"];
+
+Exhibit.Formatter.l10n.shortMonths=["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"];
+Exhibit.Formatter.l10n.months=["Januari","februari","maart","april","mei","june","july","augustus","september","oktober","november","december"];
+
+Exhibit.Formatter.l10n.commonEra="A.D.";
+Exhibit.Formatter.l10n.beforeCommonEra="B.C.";
+
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..98a4532c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..7a24e14e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..87baafbf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,34 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Verwijder deze sortering";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="Sortering: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Sorteer deze items'>daarna door...</a>";
+
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sortering is " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Verwijder sortering " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="Groepering zoals gesorteerd";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="Groepeer zoals gesorteerd";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="Hef groupering zoals gesorteerd op";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="Toon alle resultaten";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="Toon alleen de eerste paar resultaten";
+
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Toon alleen de eerste " + limitCount + " resultaten";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Toon alle " + count + " resultaten";
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..9d3f5abf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView Dutch localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tabel";
+Exhibit.TabularView.l10n.viewTooltip = "Toon items in een tabel";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Klik om deze kolom te sorteren";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Klik om deze kolom te sorteren in omgekeerde volgorder";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "Sorteer oplopend " : "sorteer aflopend ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..7049d079
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Miniaturen";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Toon items als miniaturen";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..9f4c2fc9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Tegels";
+Exhibit.TileView.l10n.viewTooltip = "Toon items als tegels in een lijst";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..a620d23d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "selecteer " + viewLabel + " toon";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "De beschrijving voor een van de zichten mist het viewClass-veld.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "De waarde van het viewClass attribuut '" + expr + "' die u heeft aangegeven\nvoor een van de zichten lijkt geen javascriptfunctie te zijn.";
+
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "De waarde van het viewClass attribuut '" + expr + "' die u heeft aangegeven\n" +
+ "voor een van de zichten lijkt geen javascriptexpressie te zijn.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..d32a6b83
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Reset alle filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Maak alle filters leeg en toon de oorspronkelijke items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Reset alle filters";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'><span class='%1'>0</span> resultaten</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "<span id='originalCountSpan'>0</span> gefilterd van oorspronkelijk (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..d419d2ab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missend";
+Exhibit.Coders.l10n.othersCaseLabel = "anders";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..dada2d8f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities Dutch localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Maak deze selecties leeg";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Selecteer %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Hef selectie %0 in facet %1 op";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Selecteer alleen %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Maak selecties in facet %0 leeg";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Tekst doorzoeken %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Maak veld tekst doorzoeken leeg";
+Exhibit.FacetUtilities.l10n.missingThisField = "(mist dit veld)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/views-l10n.js
new file mode 100644
index 00000000..16194de5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/nl/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "van <class class='exhibit-views-totalCount'>%1</span> kan niet worden afgebeeld.",
+ [ count == 1 ? (count + " result") : (count + " results"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/exhibit-no-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/exhibit-no-bundle.js
new file mode 100644
index 00000000..4cdfe26e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/exhibit-no-bundle.js
@@ -0,0 +1,180 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Objekter",pluralLabel:"Objekter",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"label",pluralLabel:"labels",reverseLabel:"label of",reversePluralLabel:"labels of"};
+Exhibit.Database.l10n.typeProperty={label:"type",pluralLabel:"types",reverseLabel:"type of",reversePluralLabel:"types of"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI of",reversePluralLabel:"URIs of"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - å",descending:"å - a"},"number":{ascending:"minste først",descending:"største først"},"date":{ascending:"tidligste først",descending:"yngste først"},"boolean":{ascending:"false first",descending:"true first"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(F,C,G,B){var A=F==1?Exhibit.Database.l10n.itemType.label:Exhibit.Database.l10n.itemType.pluralLabel;
+var E=G.getType(C);
+if(E){A=E.getLabel();
+if(F!=1){var H=E.getProperty("pluralLabel");
+if(H){A=H;
+}}}var D=document.createElement("span");
+D.innerHTML="<span class='"+B+"'>"+F+"</span> "+A;
+return D;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="mangler";
+Exhibit.l10n.missingSortKey="(mangler)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="lenke";
+Exhibit.l10n.busyIndicatorMessage="Søker...";
+Exhibit.l10n.showDocumentationMessage="Vi vil vise relevant dokumentasjon etter denne meldinga...";
+Exhibit.l10n.showJavascriptValidationMessage="Vi vil forklare denne feilen etter denne denne meldinga.";
+Exhibit.l10n.showJsonValidationMessage="Vi vil forklare feilen etter denne meldinga.";
+Exhibit.l10n.showJsonValidationFormMessage="Vi vil lete etter en webservice der du kan laste opp koden etter denne meldinga.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"JSON data fila\n "+A+"\nhar feil =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"Vi kan ikke finne fila i\n "+A+"\nse om filnavnet er riktig.";
+};
+Exhibit.l10n.exportButtonLabel="Eksporter";
+Exhibit.l10n.exportAllButtonLabel="Eksporter alle";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="Lukk";
+Exhibit.l10n.exportDialogBoxPrompt="Kopier denne koden til utklippstavla. Trykk ESC for å fjerne denne dialogboksen.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Lukk";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantisk wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tab-separert tekst";
+Exhibit.l10n.htmlExporterLabel="HTML generet fra denne visninga";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", og ";
+Exhibit.Formatter.l10n.listPairSeparator=" og ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="sann";
+Exhibit.Formatter.l10n.booleanFalse="usann";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="første";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Søn","Man","Tir","Ons","Tor","Fre","Lør"];
+Exhibit.Formatter.l10n.daysOfWeek=["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Des"];
+Exhibit.Formatter.l10n.months=["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"];
+Exhibit.Formatter.l10n.commonEra="CE";
+Exhibit.Formatter.l10n.beforeCommonEra="Fvt.";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="fjern sorteringsrekkefølgen";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="sortert etter: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='sorter videre etter'>så etter...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sortert etter "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Fjernet rekkefølgen "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="gruppert etter sorteringsrekkefølge";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="grupper som sortert";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="avgrupper som sortert";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="vis alle treff";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="vis de første resultatene";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Vis bare de første "+A+" ";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Vis alle "+A+" ";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tabell";
+Exhibit.TabularView.l10n.viewTooltip="Vis objektene i en tabell";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Klikk for å sortere denne kolonna";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Klikk for å sortere i omvendt rekkefølge";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"sortert i stigende rekkefølge ":"sortert i synkende rekkefølge etter ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="miniatyrbilder";
+Exhibit.ThumbnailView.l10n.viewTooltip="Vis alle som miniatyrbilder";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Liste";
+Exhibit.TileView.l10n.viewTooltip="Vis alle objektene som liste";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"velg "+A+" visning";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views is not a valid Javascript expression.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Slå av alle filter";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Fjern alle filter og se opprinnelig utvalg";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Slå av alle søkefilter";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> treff</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> filtrert fra <span id='originalCountSpan'>0</span> opprinnelig (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="blandet";
+Exhibit.Coders.l10n.missingCaseLabel="mangler";
+Exhibit.Coders.l10n.othersCaseLabel="andre";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Fjern disse utvalgene";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Velg %0 i fasett %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Fjern valg %0 i fasett %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Velg bare %0 i fasetten %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Fjern valg i fasetten %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Tekstsøk %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Fjern søketekst";
+Exhibit.FacetUtilities.l10n.missingThisField="(mangler dette feltet)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> av <class class='exhibit-views-totalCount'>%1</span> kunne ikke vises på kartet.",[D==1?(D+" treff"):(D+" treff"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/locale.js
new file mode 100644
index 00000000..f0cd1d61
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/locale.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * Norwegian (bokmål) localization
+ *
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/no/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-no-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-no-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/data/database-l10n.js
new file mode 100644
index 00000000..df79912f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/data/database-l10n.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.Database English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Objekt",
+ pluralLabel: "Objekter",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "navn",
+ pluralLabel: "navn",
+ reverseLabel: "navn på",
+ reversePluralLabel: "navn på"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "type",
+ pluralLabel: "typer",
+ reverseLabel: "type av",
+ reversePluralLabel: "typer av"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIer",
+ reverseLabel: "URI av",
+ reversePluralLabel: "URIer av"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - å",
+ descending: "å - a"
+ },
+ "number": {
+ ascending: "minste først",
+ descending: "største først"
+ },
+ "date": {
+ ascending: "eldste først",
+ descending: "yngste først"
+ },
+ "boolean": {
+ ascending: "usann først",
+ descending: "sanne først"
+ },
+ "item": {
+ ascending: "a - å",
+ descending: "å - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = count == 1 ? Exhibit.Database.l10n.itemType.label :
+ Exhibit.Database.l10n.itemType.pluralLabel
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+ if (count != 1) {
+ var pluralLabel = type.getProperty("pluralLabel");
+ if (pluralLabel) {
+ label = pluralLabel;
+ }
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span> " + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..84543602
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "mangler";
+Exhibit.l10n.missingSortKey = "(mangler)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "lenke";
+
+Exhibit.l10n.busyIndicatorMessage = "Søker...";
+Exhibit.l10n.showDocumentationMessage = "Vi vil vise dokumentasjon etter denne meldinga.";
+Exhibit.l10n.showJavascriptValidationMessage = "Vi vil forklare feilen etter denne meldinga.";
+
+Exhibit.l10n.showJsonValidationMessage = "Vi vil forklare feilen etter denne meldinga.";
+Exhibit.l10n.showJsonValidationFormMessage = "Vi vil lete opp en webservice der du kan laste opp og teste koden etter denne meldinga.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "JSON-datafila\n " + url + "\ninneholder feil =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "Vi kan ikke finne fila \n " + url + "\n sjekk om filnavnet stemmer.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Eksporter";
+Exhibit.l10n.exportAllButtonLabel = "Eksporter alle";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "Lukk";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Kopier koden til utklippstavlen. Trykk ESC for å fjerne denne dialogboksen.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Lukk";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantisk wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tab-separerte verdier";
+Exhibit.l10n.htmlExporterLabel = "HTML generert fra denne visninga";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..7638ef8e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", og ";
+Exhibit.Formatter.l10n.listPairSeparator = " og ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "sann";
+Exhibit.Formatter.l10n.booleanFalse = "usann";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "først"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Søn","Man","Tir","Ons","Tor","Fre","Lør"];
+Exhibit.Formatter.l10n.daysOfWeek=["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"];
+
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Des"];
+Exhibit.Formatter.l10n.months=["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"];
+
+Exhibit.Formatter.l10n.commonEra = "CE";
+Exhibit.Formatter.l10n.beforeCommonEra = "fvt.";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..03be7df7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..4ae89f8c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..9f2f708e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Fjern denne sorteringsrekkefølgen";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "sortert etter: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Further sort the items'>then by...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sorter etter " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Fjernet sorteringsrekkefølge " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "gruppert som sortert";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "grupper etter sortering";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "avgrupper slik de er sortert";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "vis alle";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "vis bare de første";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Vis bare de første " + limitCount + " ";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Vis alle " + count + " ";
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..8f971b7d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView Norwegian localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tabell";
+Exhibit.TabularView.l10n.viewTooltip = "Vis i en tabell";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Klikk her for å sortere etter denne kolonna";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Klikk her for å sortere i omvendt rekkefølge";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "sortert i stigende rekkefølge etter " : "sortert i synkende rekkefølge etter ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..3cbd17e7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Miniatyrbilder";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Vis som miniatyrbilder";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..b1c1f9ff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Liste";
+Exhibit.TileView.l10n.viewTooltip = "Vis som liste ";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..e1bf42b6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "velg " + viewLabel + " visning";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views is not a valid Javascript expression.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..53ba5111
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,27 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Slå av alle filter";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Fjern alle filter og se opprinnelig utvalg";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Slå av alle søkefilter";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate=
+"<span class='%0'><span class='%1'>0</span> treff</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate=
+"<span class='%0' id='resultDescription'></span> filtrert fra <span id='originalCountSpan'>0</span> opprinnelig (<span id='resetActionLink'></span>)";
+
+
+
+
+
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..a48af21b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "blandet";
+Exhibit.Coders.l10n.missingCaseLabel = "mangler";
+Exhibit.Coders.l10n.othersCaseLabel = "andre";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..cfd8114d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Fjern disse utvalgene";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Velg %0 i fasett %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Avvelg %0 i fasett %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Velg bare %0 i fasetten %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Fjern valg i fasetten %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Tekstsøk %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Fjern søketekst";
+Exhibit.FacetUtilities.l10n.missingThisField="(mangler dette feltet)"; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/views-l10n.js
new file mode 100644
index 00000000..df270162
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/no/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities Norwegian localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "av <class class='exhibit-views-totalCount'>%1</span> kunne ikke vises på kart.",
+ [ count == 1 ? (count + " treff") : (count + " treff"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/exhibit-sv-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/exhibit-sv-bundle.js
new file mode 100644
index 00000000..431195b2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/exhibit-sv-bundle.js
@@ -0,0 +1,171 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Sak",pluralLabel:"Saker"};
+Exhibit.Database.l10n.labelProperty={label:"etikett",pluralLabel:"etiketter",reverseLabel:"etikett till",reversePluralLabel:"etiketter till"};
+Exhibit.Database.l10n.typeProperty={label:"typ",pluralLabel:"typer",reverseLabel:"typ av",reversePluralLabel:"typer av"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIer",reverseLabel:"URI för",reversePluralLabel:"URIer för"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"lägst först",descending:"högst först"},"date":{ascending:"tidigast först",descending:"nyligast först"},"boolean":{ascending:"falskt först",descending:"sant först"},"item":{ascending:"a - z",descending:"z - a"}};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="saknas";
+Exhibit.l10n.missingSortKey="(saknas)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="länk";
+Exhibit.l10n.busyIndicatorMessage="Arbetar...";
+Exhibit.l10n.showDocumentationMessage="Relevant dokumentation kommer visas efter det här meddelandet.";
+Exhibit.l10n.showJavascriptValidationMessage="Felet förklaras mer ingående efter det här meddelandet.";
+Exhibit.l10n.showJsonValidationMessage="Felet förklaras mer ingående efter det här meddelandet.";
+Exhibit.l10n.showJsonValidationFormMessage="Vi skickar dig till en webtjänst du kan ladda upp din kod till för felsökning efter det här meddelandet.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"JSON-filen\n "+A+"\ninnehåller fel =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"Kunde inte hitta filen\n "+A+"\nKontrollera att filnamnet är korrekt.";
+};
+Exhibit.l10n.copyButtonLabel="Kopiera";
+Exhibit.l10n.copyAllButtonLabel="Kopiera allt";
+Exhibit.l10n.copyDialogBoxCloseButtonLabel="Stäng";
+Exhibit.l10n.copyDialogBoxPrompt="Kopiera det här till klippbordet precis som du skulle göra för annan text. Tryck ESC för att stänga den här dialogen.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Stäng";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantisk wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tabseparerade värden";
+Exhibit.l10n.htmlExporterLabel="HTML för den här vyn";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", och ";
+Exhibit.Formatter.l10n.listPairSeparator=" och ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="true";
+Exhibit.Formatter.l10n.booleanFalse="false";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="first";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Sun","Mon","Tue","Wed","Thr","Fri","Sat"];
+Exhibit.Formatter.l10n.daysOfWeek=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Exhibit.Formatter.l10n.months=["January","February","March","April","May","June","July","August","September","October","November","December"];
+Exhibit.Formatter.l10n.commonEra="CE";
+Exhibit.Formatter.l10n.beforeCommonEra="BCE";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Ta bort det här sorteringskriteriet";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="sorterat efter: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='sortera ytterligare'>then by...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sorterat efter "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Ta bort sorteringskriteriet "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="gruppera som de sorterats";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="grupperade som de sorterats";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="ogrupperade";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Visa bara de första "+A+" resultaten";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Visa samtliga "+A+" resultat";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Tabell";
+Exhibit.TabularView.l10n.viewTooltip="Visa i tabell";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Klicka för att sortera efter den här kolumnen";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Klicka för att välja omvänd ordning";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return"sortera efter "+(B?"stigande ":"fallande ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Tumnaglar";
+Exhibit.ThumbnailView.l10n.viewTooltip="Visa som tumnaglar";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Lista";
+Exhibit.TileView.l10n.viewTooltip="Visa som lista";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"välj vyn "+A;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="Specifikationen för en av vyerna saknas i fältet viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"Värdet '"+A+"' du angivit för attributet viewClass\nför en av dessa vyer var inte namnet på en javascriptfunktion.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"Värdet '"+A+"' du angivit för attributet viewClass\nför en av dessa vyer är inte ett giltigt javascriptuttryck.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="visa alla";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Välj bort några filter för fler resultat.";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="visa alla";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'>0</span> <span class='%1' id='typesSpan'>resultat</span>. (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> av <span id='originalCountSpan'>0</span> totalt. (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missing";
+Exhibit.Coders.l10n.othersCaseLabel="others";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Ã¥ngra dessa val";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField="(missing this field)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",[D==1?(D+" result"):(D+" results"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/locale.js
new file mode 100644
index 00000000..dd55eab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/locale.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * Swedish localization
+ *
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/sv/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-sv-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-sv-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/data/database-l10n.js
new file mode 100644
index 00000000..94d5f524
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/data/database-l10n.js
@@ -0,0 +1,54 @@
+/*==================================================
+ * Exhibit.Database Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Sak",
+ pluralLabel: "Saker"
+
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "etikett",
+ pluralLabel: "etiketter",
+ reverseLabel: "etikett till",
+ reversePluralLabel: "etiketter till"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "typ",
+ pluralLabel: "typer",
+ reverseLabel: "typ av",
+ reversePluralLabel: "typer av"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIer",
+ reverseLabel: "URI för",
+ reversePluralLabel: "URIer för"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "lägst först",
+ descending: "högst först"
+ },
+ "date": {
+ ascending: "tidigast först",
+ descending: "nyligast först"
+ },
+ "boolean": {
+ ascending: "falskt först",
+ descending: "sant först"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..767785fd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "saknas";
+Exhibit.l10n.missingSortKey = "(saknas)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "länk";
+
+Exhibit.l10n.busyIndicatorMessage = "Arbetar...";
+Exhibit.l10n.showDocumentationMessage = "Relevant dokumentation kommer visas efter det här meddelandet.";
+Exhibit.l10n.showJavascriptValidationMessage = "Felet förklaras mer ingående efter det här meddelandet.";
+
+Exhibit.l10n.showJsonValidationMessage = "Felet förklaras mer ingående efter det här meddelandet.";
+Exhibit.l10n.showJsonValidationFormMessage = "Vi skickar dig till en webtjänst du kan ladda upp din kod till för felsökning efter det här meddelandet.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "JSON-filen\n " + url + "\ninnehåller fel =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "Kunde inte hitta filen\n " + url + "\nKontrollera att filnamnet är korrekt.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.copyButtonLabel = "Kopiera";
+Exhibit.l10n.copyAllButtonLabel = "Kopiera allt";
+Exhibit.l10n.copyDialogBoxCloseButtonLabel = "Stäng";
+Exhibit.l10n.copyDialogBoxPrompt =
+ "Kopiera det här till klippbordet precis som du skulle göra för annan text. Tryck ESC för att stänga den här dialogen.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Stäng";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantisk wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tabseparerade värden";
+Exhibit.l10n.htmlExporterLabel = "HTML för den här vyn";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..63557df2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", och ";
+Exhibit.Formatter.l10n.listPairSeparator = " och ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "true";
+Exhibit.Formatter.l10n.booleanFalse = "false";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "first"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+Exhibit.Formatter.l10n.months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
+
+Exhibit.Formatter.l10n.commonEra = "CE";
+Exhibit.Formatter.l10n.beforeCommonEra = "BCE";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..cd2b977b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {}
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..72b40674
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..b24feed7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Ta bort det här sorteringskriteriet";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "sorterat efter: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='sortera ytterligare'>then by...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sorterat efter " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Ta bort sorteringskriteriet " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "gruppera som de sorterats";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "grupperade som de sorterats";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "ogrupperade";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Visa bara de första " + limitCount + " resultaten";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Visa samtliga " + count + " resultat";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..a1b4dc05
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView Swedish localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Tabell";
+Exhibit.TabularView.l10n.viewTooltip = "Visa i tabell";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Klicka för att sortera efter den här kolumnen";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Klicka för att välja omvänd ordning";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return "sortera efter " + (ascending ? "stigande " : "fallande ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..a968660e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Tumnaglar";
+Exhibit.ThumbnailView.l10n.viewTooltip = "Visa som tumnaglar";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..e29d7953
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Lista";
+Exhibit.TileView.l10n.viewTooltip = "Visa som lista";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..1751142c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "välj vyn " + viewLabel;
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "Specifikationen för en av vyerna saknas i fältet viewClass.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "Värdet '" + expr + "' du angivit för attributet viewClass\n" +
+ "för en av dessa vyer var inte namnet på en javascriptfunktion.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "Värdet '" + expr + "' du angivit för attributet viewClass\n" +
+ "för en av dessa vyer är inte ett giltigt javascriptuttryck.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..c28dc632
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "visa alla";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Välj bort några filter för fler resultat.";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "visa alla";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'>0</span> <span class='%1' id='typesSpan'>resultat</span>. (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "av <span id='originalCountSpan'>0</span> totalt. (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..7f68ce9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missing";
+Exhibit.Coders.l10n.othersCaseLabel = "others";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..3724d291
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "ångra dessa val";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField = "(missing this field)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/views-l10n.js
new file mode 100644
index 00000000..f64f5729
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/sv/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities Swedish localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",
+ [ count == 1 ? (count + " result") : (count + " results"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/exhibit-zh-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/exhibit-zh-bundle.js
new file mode 100644
index 00000000..6d6c9c26
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/exhibit-zh-bundle.js
@@ -0,0 +1,181 @@
+
+
+/* database-l10n.js */
+if(!("l10n" in Exhibit.Database)){Exhibit.Database.l10n={};
+}Exhibit.Database.l10n.itemType={label:"Item",pluralLabel:"Items",uri:"http://simile.mit.edu/2006/11/exhibit#Item"};
+Exhibit.Database.l10n.labelProperty={label:"label",pluralLabel:"labels",reverseLabel:"label of",reversePluralLabel:"labels of"};
+Exhibit.Database.l10n.typeProperty={label:"type",pluralLabel:"types",reverseLabel:"type of",reversePluralLabel:"types of"};
+Exhibit.Database.l10n.uriProperty={label:"URI",pluralLabel:"URIs",reverseLabel:"URI of",reversePluralLabel:"URIs of"};
+Exhibit.Database.l10n.sortLabels={"text":{ascending:"a - z",descending:"z - a"},"number":{ascending:"smallest first",descending:"largest first"},"date":{ascending:"earliest first",descending:"latest first"},"boolean":{ascending:"false first",descending:"true first"},"item":{ascending:"a - z",descending:"z - a"}};
+Exhibit.Database.l10n.labelItemsOfType=function(D,B,I,A){var G=Exhibit.Database.l10n.itemType.label;
+var C="个";
+var F=I.getType(B);
+if(F){G=F.getLabel();
+var E=F.getProperty("measureWord");
+if(E){C=E;
+}}var H=document.createElement("span");
+H.innerHTML="<span class='"+A+"'>"+D+"</span>"+C+G;
+return H;
+};
+
+
+/* exhibit-l10n.js */
+if(!("l10n" in Exhibit)){Exhibit.l10n={};
+}Exhibit.l10n.missingLabel="missing";
+Exhibit.l10n.missingSortKey="(missing)";
+Exhibit.l10n.notApplicableSortKey="(n/a)";
+Exhibit.l10n.itemLinkLabel="link";
+Exhibit.l10n.busyIndicatorMessage="Working...";
+Exhibit.l10n.showDocumentationMessage="We will show the relevant documentation after this message.";
+Exhibit.l10n.showJavascriptValidationMessage="We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationMessage="We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationFormMessage="We will browse to a web service where you can upload and check your code after this message.";
+Exhibit.l10n.badJsonMessage=function(A,B){return"The JSON data file\n "+A+"\ncontains errors =\n\n"+B;
+};
+Exhibit.l10n.failedToLoadDataFileMessage=function(A){return"We cannot locate the data file\n "+A+"\nCheck that the file name is correct.";
+};
+Exhibit.l10n.exportButtonLabel="Export";
+Exhibit.l10n.exportAllButtonLabel="Export All";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel="Close";
+Exhibit.l10n.exportDialogBoxPrompt="Copy this code to your clipboard as you would copy any text. Press ESC to close this dialog box.";
+Exhibit.l10n.focusDialogBoxCloseButtonLabel="Close";
+Exhibit.l10n.rdfXmlExporterLabel="RDF/XML";
+Exhibit.l10n.smwExporterLabel="Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel="Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel="Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel="Generated HTML of this view";
+
+
+/* formatter-l10n.js */
+if(!("l10n" in Exhibit.Formatter)){Exhibit.Formatter.l10n={};
+}Exhibit.Formatter.l10n.listSeparator=", ";
+Exhibit.Formatter.l10n.listLastSeparator=", and ";
+Exhibit.Formatter.l10n.listPairSeparator=" and ";
+Exhibit.Formatter.l10n.textEllipsis="...";
+Exhibit.Formatter.l10n.booleanTrue="true";
+Exhibit.Formatter.l10n.booleanFalse="false";
+Exhibit.Formatter.l10n.currencySymbol="$";
+Exhibit.Formatter.l10n.currencySymbolPlacement="first";
+Exhibit.Formatter.l10n.currencyShowSign=true;
+Exhibit.Formatter.l10n.currencyShowRed=false;
+Exhibit.Formatter.l10n.currencyShowParentheses=false;
+Exhibit.Formatter.l10n.dateTimeDefaultFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateShortFormat="dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat="dd/MM/yy hh:mm a";
+Exhibit.Formatter.l10n.dateMediumFormat="EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat="hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat="EEE, MMM d, yyyy, hh:mm a";
+Exhibit.Formatter.l10n.dateLongFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat="HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat="EEEE, MMMM d, yyyy, HH:mm:ss z";
+Exhibit.Formatter.l10n.dateFullFormat="EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat="HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat="EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+Exhibit.Formatter.l10n.shortDaysOfWeek=["Sun","Mon","Tue","Wed","Thr","Fri","Sat"];
+Exhibit.Formatter.l10n.daysOfWeek=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+Exhibit.Formatter.l10n.shortMonths=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Exhibit.Formatter.l10n.months=["January","February","March","April","May","June","July","August","September","October","November","December"];
+Exhibit.Formatter.l10n.commonEra="CE";
+Exhibit.Formatter.l10n.beforeCommonEra="BCE";
+Exhibit.Formatter.l10n.beforeNoon="am";
+Exhibit.Formatter.l10n.afterNoon="pm";
+Exhibit.Formatter.l10n.BeforeNoon="AM";
+Exhibit.Formatter.l10n.AfterNoon="PM";
+
+
+/* lens-l10n.js */
+if(!("l10n" in Exhibit.Lens)){Exhibit.Lens.l10n={};
+}
+
+/* ui-context-l10n.js */
+if(!("l10n" in Exhibit.UIContext)){Exhibit.UIContext.l10n={};
+}Exhibit.UIContext.l10n.initialSettings={"bubbleWidth":400,"bubbleHeight":300};
+
+
+/* ordered-view-frame-l10n.js */
+if(!("l10n" in Exhibit.OrderedViewFrame)){Exhibit.OrderedViewFrame.l10n={};
+}Exhibit.OrderedViewFrame.l10n.removeOrderLabel="Remove this order";
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate="sorted by: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Further sort the items'>then by...</a>";
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle=function(B,A){return"Sorted by "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle=function(B,A){return"Removed order by "+B+" ("+A+")";
+};
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel="grouped as sorted";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle="group as sorted";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle="ungroup as sorted";
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle="show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle="show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll=function(A){return"Show only the first "+A+" results";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll=function(A){return"Show all "+A+" results";
+};
+
+
+/* tabular-view-l10n.js */
+if(!("l10n" in Exhibit.TabularView)){Exhibit.TabularView.l10n={};
+}Exhibit.TabularView.l10n.viewLabel="Table";
+Exhibit.TabularView.l10n.viewTooltip="View items in a table";
+Exhibit.TabularView.l10n.columnHeaderSortTooltip="Click to sort by this column";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip="Click to sort in the reverse order";
+Exhibit.TabularView.l10n.makeSortActionTitle=function(A,B){return(B?"sorted ascending by ":"sorted descending by ")+A;
+};
+
+
+/* thumbnail-view-l10n.js */
+if(!("l10n" in Exhibit.ThumbnailView)){Exhibit.ThumbnailView.l10n={};
+}Exhibit.ThumbnailView.l10n.viewLabel="Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip="View items as thumbnails";
+
+
+/* tile-view-l10n.js */
+if(!("l10n" in Exhibit.TileView)){Exhibit.TileView.l10n={};
+}Exhibit.TileView.l10n.viewLabel="Tiles";
+Exhibit.TileView.l10n.viewTooltip="View items as tiles in a list";
+
+
+/* view-panel-l10n.js */
+if(!("l10n" in Exhibit.ViewPanel)){Exhibit.ViewPanel.l10n={};
+}Exhibit.ViewPanel.l10n.createSelectViewActionTitle=function(A){return"select "+A+" view";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage="The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage=function(A){return"The viewClass attribute value '"+A+"' you have specified\nfor one of the views is not a valid Javascript expression.";
+};
+
+
+/* collection-summary-widget-l10n.js */
+if(!("l10n" in Exhibit.CollectionSummaryWidget)){Exhibit.CollectionSummaryWidget.l10n={};
+}Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel="Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip="Clear all filters and see the original items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle="Reset all filters";
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate="<span class='%0' id='resultDescription'></span>";
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate="<span class='%0'><span class='%1'>0</span> results</span> (<span id='resetActionLink'></span>)";
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate="<span class='%0' id='resultDescription'></span> filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
+
+
+/* coders-l10n.js */
+if(!("l10n" in Exhibit.Coders)){Exhibit.Coders.l10n={};
+}Exhibit.Coders.l10n.mixedCaseLabel="mixed";
+Exhibit.Coders.l10n.missingCaseLabel="missing";
+Exhibit.Coders.l10n.othersCaseLabel="others";
+
+
+/* facets-l10n.js */
+if(!("l10n" in Exhibit.FacetUtilities)){Exhibit.FacetUtilities.l10n={};
+}Exhibit.FacetUtilities.l10n.clearSelectionsTooltip="Clear these selections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle="Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle="Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle="Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle="Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle="Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle="Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField="(missing this field)";
+
+
+/* views-l10n.js */
+if(!("l10n" in Exhibit.ViewUtilities)){Exhibit.ViewUtilities.l10n={};
+}Exhibit.ViewUtilities.l10n.unplottableMessageFormatter=function(B,A,C){var D=A.length;
+return String.substitute("<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",[D==1?(D+" result"):(D+" results"),B]);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/locale.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/locale.js
new file mode 100644
index 00000000..011a174a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/locale.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * Chinese localization
+ *
+ *==================================================
+ */
+(function() {
+ var isCompiled = ("Exhibit_isCompiled" in window) && window.Exhibit_isCompiled;
+ if (!isCompiled) {
+ var javascriptFiles = [
+ "exhibit-l10n.js",
+ "data/database-l10n.js",
+ "ui/ui-context-l10n.js",
+ "ui/lens-l10n.js",
+ "ui/formatter-l10n.js",
+ "ui/widgets/collection-summary-widget-l10n.js",
+ "ui/views/view-panel-l10n.js",
+ "ui/views/ordered-view-frame-l10n.js",
+ "ui/views/tile-view-l10n.js",
+ "ui/views/thumbnail-view-l10n.js",
+ "ui/views/tabular-view-l10n.js",
+ "util/coders-l10n.js",
+ "util/facets-l10n.js",
+ "util/views-l10n.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var urlPrefix = Exhibit.urlPrefix + "locales/zh/";
+ if (Exhibit.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, [ "exhibit-zh-bundle.js" ]);
+ if (cssFiles.length > 0) {
+ SimileAjax.includeCssFiles(document, urlPrefix, [ "exhibit-zh-bundle.css" ]);
+ }
+ } else {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix + "scripts/", javascriptFiles);
+ SimileAjax.includeCssFiles(document, urlPrefix + "styles/", cssFiles);
+ }
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/data/database-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/data/database-l10n.js
new file mode 100644
index 00000000..123c7582
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/data/database-l10n.js
@@ -0,0 +1,74 @@
+/*==================================================
+ * Exhibit.Database Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Database)) {
+ Exhibit.Database.l10n = {};
+}
+
+Exhibit.Database.l10n.itemType = {
+ label: "Item",
+ pluralLabel: "Items",
+ uri: "http://simile.mit.edu/2006/11/exhibit#Item"
+};
+Exhibit.Database.l10n.labelProperty = {
+ label: "label",
+ pluralLabel: "labels",
+ reverseLabel: "label of",
+ reversePluralLabel: "labels of"
+};
+Exhibit.Database.l10n.typeProperty = {
+ label: "type",
+ pluralLabel: "types",
+ reverseLabel: "type of",
+ reversePluralLabel: "types of"
+};
+Exhibit.Database.l10n.uriProperty = {
+ label: "URI",
+ pluralLabel: "URIs",
+ reverseLabel: "URI of",
+ reversePluralLabel: "URIs of"
+};
+Exhibit.Database.l10n.sortLabels = {
+ "text": {
+ ascending: "a - z",
+ descending: "z - a"
+ },
+ "number": {
+ ascending: "smallest first",
+ descending: "largest first"
+ },
+ "date": {
+ ascending: "earliest first",
+ descending: "latest first"
+ },
+ "boolean": {
+ ascending: "false first",
+ descending: "true first"
+ },
+ "item": {
+ ascending: "a - z",
+ descending: "z - a"
+ }
+};
+
+Exhibit.Database.l10n.labelItemsOfType = function(count, typeID, database, countStyleClass) {
+ var label = Exhibit.Database.l10n.itemType.label;
+ var measureWord = "个";
+
+ var type = database.getType(typeID);
+ if (type) {
+ label = type.getLabel();
+
+ var measureWord2 = type.getProperty("measureWord");
+ if (measureWord2) {
+ measureWord = measureWord2;
+ }
+ }
+
+ var span = document.createElement("span");
+ span.innerHTML = "<span class='" + countStyleClass + "'>" + count + "</span>" + measureWord + label;
+
+ return span;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/exhibit-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/exhibit-l10n.js
new file mode 100644
index 00000000..1f410e6b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/exhibit-l10n.js
@@ -0,0 +1,50 @@
+/*==================================================
+ * Exhibit Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit)) {
+ Exhibit.l10n = {};
+}
+
+Exhibit.l10n.missingLabel = "missing";
+Exhibit.l10n.missingSortKey = "(missing)";
+Exhibit.l10n.notApplicableSortKey = "(n/a)";
+Exhibit.l10n.itemLinkLabel = "link";
+
+Exhibit.l10n.busyIndicatorMessage = "Working...";
+Exhibit.l10n.showDocumentationMessage = "We will show the relevant documentation after this message.";
+Exhibit.l10n.showJavascriptValidationMessage = "We will explain the error in details after this message.";
+
+Exhibit.l10n.showJsonValidationMessage = "We will explain the error in details after this message.";
+Exhibit.l10n.showJsonValidationFormMessage = "We will browse to a web service where you can upload and check your code after this message.";
+
+Exhibit.l10n.badJsonMessage = function(url, e) {
+ return "The JSON data file\n " + url + "\ncontains errors =\n\n" + e;
+};
+Exhibit.l10n.failedToLoadDataFileMessage = function(url) {
+ return "We cannot locate the data file\n " + url + "\nCheck that the file name is correct.";
+};
+
+/*
+ * Copy button and dialog box
+ */
+Exhibit.l10n.exportButtonLabel = "Export";
+Exhibit.l10n.exportAllButtonLabel = "Export All";
+Exhibit.l10n.exportDialogBoxCloseButtonLabel = "Close";
+Exhibit.l10n.exportDialogBoxPrompt =
+ "Copy this code to your clipboard as you would copy any text. Press ESC to close this dialog box.";
+
+/*
+ * Focusdialog box
+ */
+Exhibit.l10n.focusDialogBoxCloseButtonLabel = "Close";
+
+/*
+ * Common exporters' labels
+ */
+Exhibit.l10n.rdfXmlExporterLabel = "RDF/XML";
+Exhibit.l10n.smwExporterLabel = "Semantic wikitext";
+Exhibit.l10n.exhibitJsonExporterLabel = "Exhibit JSON";
+Exhibit.l10n.tsvExporterLabel = "Tab Separated Values";
+Exhibit.l10n.htmlExporterLabel = "Generated HTML of this view";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/formatter-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/formatter-l10n.js
new file mode 100644
index 00000000..d7f30314
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/formatter-l10n.js
@@ -0,0 +1,56 @@
+/*==================================================
+ * Exhibit.Formatter Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Formatter)) {
+ Exhibit.Formatter.l10n = {};
+}
+
+Exhibit.Formatter.l10n.listSeparator = ", ";
+Exhibit.Formatter.l10n.listLastSeparator = ", and ";
+Exhibit.Formatter.l10n.listPairSeparator = " and ";
+
+Exhibit.Formatter.l10n.textEllipsis = "...";
+
+Exhibit.Formatter.l10n.booleanTrue = "true";
+Exhibit.Formatter.l10n.booleanFalse = "false";
+
+Exhibit.Formatter.l10n.currencySymbol = "$";
+Exhibit.Formatter.l10n.currencySymbolPlacement = "first"; // "last", "after-sign"
+Exhibit.Formatter.l10n.currencyShowSign = true;
+Exhibit.Formatter.l10n.currencyShowRed = false;
+Exhibit.Formatter.l10n.currencyShowParentheses = false;
+
+Exhibit.Formatter.l10n.dateTimeDefaultFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateShortFormat = "dd/MM/yy";
+Exhibit.Formatter.l10n.timeShortFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeShortFormat = "dd/MM/yy hh:mm a";
+
+Exhibit.Formatter.l10n.dateMediumFormat = "EEE, MMM d, yyyy";
+Exhibit.Formatter.l10n.timeMediumFormat = "hh:mm a";
+Exhibit.Formatter.l10n.dateTimeMediumFormat = "EEE, MMM d, yyyy, hh:mm a";
+
+Exhibit.Formatter.l10n.dateLongFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeLongFormat = "HH:mm:ss z";
+Exhibit.Formatter.l10n.dateTimeLongFormat = "EEEE, MMMM d, yyyy, HH:mm:ss z";
+
+Exhibit.Formatter.l10n.dateFullFormat = "EEEE, MMMM d, yyyy";
+Exhibit.Formatter.l10n.timeFullFormat = "HH:mm:ss.S z";
+Exhibit.Formatter.l10n.dateTimeFullFormat = "EEEE, MMMM d, yyyy G, HH:mm:ss.S z";
+
+Exhibit.Formatter.l10n.shortDaysOfWeek = [ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" ];
+Exhibit.Formatter.l10n.daysOfWeek = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+
+Exhibit.Formatter.l10n.shortMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+Exhibit.Formatter.l10n.months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
+
+Exhibit.Formatter.l10n.commonEra = "CE";
+Exhibit.Formatter.l10n.beforeCommonEra = "BCE";
+
+Exhibit.Formatter.l10n.beforeNoon = "am";
+Exhibit.Formatter.l10n.afterNoon = "pm";
+
+Exhibit.Formatter.l10n.BeforeNoon = "AM";
+Exhibit.Formatter.l10n.AfterNoon = "PM";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/lens-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/lens-l10n.js
new file mode 100644
index 00000000..a5fa7b1f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/lens-l10n.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Exhibit.Lens Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Lens)) {
+ Exhibit.Lens.l10n = {};
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/ui-context-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/ui-context-l10n.js
new file mode 100644
index 00000000..488cbca2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/ui-context-l10n.js
@@ -0,0 +1,13 @@
+/*==================================================
+ * Exhibit.UIContext Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.UIContext)) {
+ Exhibit.UIContext.l10n = {};
+}
+
+Exhibit.UIContext.l10n.initialSettings = {
+ "bubbleWidth": 400, // pixels
+ "bubbleHeight": 300 // pixels
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/ordered-view-frame-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/ordered-view-frame-l10n.js
new file mode 100644
index 00000000..1f55751b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/ordered-view-frame-l10n.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.OrderedViewFrame)) {
+ Exhibit.OrderedViewFrame.l10n = {};
+}
+
+Exhibit.OrderedViewFrame.l10n.removeOrderLabel = "Remove this order";
+
+Exhibit.OrderedViewFrame.l10n.sortingControlsTemplate =
+ "sorted by: <span id='ordersSpan'></span>; <a id='thenSortByAction' href='javascript:void' class='exhibit-action' title='Further sort the items'>then by...</a>";
+
+Exhibit.OrderedViewFrame.l10n.formatSortActionTitle = function(propertyLabel, sortLabel) {
+ return "Sorted by " + propertyLabel + " (" + sortLabel + ")";
+};
+Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle = function(propertyLabel, sortLabel) {
+ return "Removed order by " + propertyLabel + " (" + sortLabel + ")";
+};
+
+Exhibit.OrderedViewFrame.l10n.groupedAsSortedOptionLabel = "grouped as sorted";
+Exhibit.OrderedViewFrame.l10n.groupAsSortedActionTitle = "group as sorted";
+Exhibit.OrderedViewFrame.l10n.ungroupAsSortedActionTitle = "ungroup as sorted";
+
+Exhibit.OrderedViewFrame.l10n.showAllActionTitle = "show all results";
+Exhibit.OrderedViewFrame.l10n.dontShowAllActionTitle = "show first few results";
+Exhibit.OrderedViewFrame.l10n.formatDontShowAll = function(limitCount) {
+ return "Show only the first " + limitCount + " results";
+};
+Exhibit.OrderedViewFrame.l10n.formatShowAll = function(count) {
+ return "Show all " + count + " results";
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tabular-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tabular-view-l10n.js
new file mode 100644
index 00000000..6da5de9e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tabular-view-l10n.js
@@ -0,0 +1,16 @@
+/*==================================================
+ * Exhibit.TabularView Chinese localization
+ *==================================================
+ */
+if (!("l10n" in Exhibit.TabularView)) {
+ Exhibit.TabularView.l10n = {};
+}
+
+Exhibit.TabularView.l10n.viewLabel = "Table";
+Exhibit.TabularView.l10n.viewTooltip = "View items in a table";
+
+Exhibit.TabularView.l10n.columnHeaderSortTooltip = "Click to sort by this column";
+Exhibit.TabularView.l10n.columnHeaderReSortTooltip = "Click to sort in the reverse order";
+Exhibit.TabularView.l10n.makeSortActionTitle = function(label, ascending) {
+ return (ascending ? "sorted ascending by " : "sorted descending by ") + label;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/thumbnail-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/thumbnail-view-l10n.js
new file mode 100644
index 00000000..f0d1aa52
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/thumbnail-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.ThumbnailView Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ThumbnailView)) {
+ Exhibit.ThumbnailView.l10n = {};
+}
+
+Exhibit.ThumbnailView.l10n.viewLabel = "Thumbnails";
+Exhibit.ThumbnailView.l10n.viewTooltip = "View items as thumbnails";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tile-view-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tile-view-l10n.js
new file mode 100644
index 00000000..bbeee7a8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/tile-view-l10n.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Exhibit.TileView Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.TileView)) {
+ Exhibit.TileView.l10n = {};
+}
+
+Exhibit.TileView.l10n.viewLabel = "Tiles";
+Exhibit.TileView.l10n.viewTooltip = "View items as tiles in a list";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/view-panel-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/view-panel-l10n.js
new file mode 100644
index 00000000..48c9fc86
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/views/view-panel-l10n.js
@@ -0,0 +1,21 @@
+/*==================================================
+ * Exhibit.ViewPanel Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewPanel)) {
+ Exhibit.ViewPanel.l10n = {};
+}
+
+Exhibit.ViewPanel.l10n.createSelectViewActionTitle = function(viewLabel) {
+ return "select " + viewLabel + " view";
+};
+Exhibit.ViewPanel.l10n.missingViewClassMessage = "The specification for one of the views is missing the viewClass field.";
+Exhibit.ViewPanel.l10n.viewClassNotFunctionMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views does not evaluate to a Javascript function.";
+};
+Exhibit.ViewPanel.l10n.badViewClassMessage = function(expr) {
+ return "The viewClass attribute value '" + expr + "' you have specified\n" +
+ "for one of the views is not a valid Javascript expression.";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/widgets/collection-summary-widget-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/widgets/collection-summary-widget-l10n.js
new file mode 100644
index 00000000..0734881f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/ui/widgets/collection-summary-widget-l10n.js
@@ -0,0 +1,22 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.CollectionSummaryWidget)) {
+ Exhibit.CollectionSummaryWidget.l10n = {};
+}
+
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersLabel = "Reset All Filters";
+Exhibit.CollectionSummaryWidget.l10n.resetFiltersTooltip = "Clear all filters and see the original items";
+Exhibit.CollectionSummaryWidget.l10n.resetActionTitle = "Reset all filters";
+
+Exhibit.CollectionSummaryWidget.l10n.allResultsTemplate =
+ "<span class='%0' id='resultDescription'></span>";
+
+Exhibit.CollectionSummaryWidget.l10n.noResultsTemplate =
+ "<span class='%0'><span class='%1'>0</span> results</span> (<span id='resetActionLink'></span>)";
+
+Exhibit.CollectionSummaryWidget.l10n.filteredResultsTemplate =
+ "<span class='%0' id='resultDescription'></span> " +
+ "filtered from <span id='originalCountSpan'>0</span> originally (<span id='resetActionLink'></span>)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/coders-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/coders-l10n.js
new file mode 100644
index 00000000..7f68ce9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/coders-l10n.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Exhibit.Coders English localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.Coders)) {
+ Exhibit.Coders.l10n = {};
+}
+
+Exhibit.Coders.l10n.mixedCaseLabel = "mixed";
+Exhibit.Coders.l10n.missingCaseLabel = "missing";
+Exhibit.Coders.l10n.othersCaseLabel = "others";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/facets-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/facets-l10n.js
new file mode 100644
index 00000000..f6f2ca15
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/facets-l10n.js
@@ -0,0 +1,17 @@
+/*==================================================
+ * Exhibit.FacetUtilities Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.FacetUtilities)) {
+ Exhibit.FacetUtilities.l10n = {};
+}
+
+Exhibit.FacetUtilities.l10n.clearSelectionsTooltip = "Clear these selections";
+Exhibit.FacetUtilities.l10n.facetSelectActionTitle = "Select %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetUnselectActionTitle = "Unselect %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetSelectOnlyActionTitle = "Select only %0 in facet %1";
+Exhibit.FacetUtilities.l10n.facetClearSelectionsActionTitle = "Clear selections in facet %0";
+Exhibit.FacetUtilities.l10n.facetTextSearchActionTitle = "Text search %0";
+Exhibit.FacetUtilities.l10n.facetClearTextSearchActionTitle = "Clear text search";
+Exhibit.FacetUtilities.l10n.missingThisField = "(missing this field)";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/views-l10n.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/views-l10n.js
new file mode 100644
index 00000000..5fa36214
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/locales/zh/scripts/util/views-l10n.js
@@ -0,0 +1,18 @@
+/*==================================================
+ * Exhibit.ViewUtilities Chinese localization
+ *==================================================
+ */
+
+if (!("l10n" in Exhibit.ViewUtilities)) {
+ Exhibit.ViewUtilities.l10n = {};
+}
+
+Exhibit.ViewUtilities.l10n.unplottableMessageFormatter = function(totalCount, unplottableItems, uiContext) {
+ var count = unplottableItems.length;
+
+ return String.substitute(
+ "<a class='exhibit-action exhibit-views-unplottableCount' href='javascript:void' id='unplottableCountLink'>%0</a> "+
+ "out of <class class='exhibit-views-totalCount'>%1</span> cannot be plotted.",
+ [ count == 1 ? (count + " result") : (count + " results"), totalCount ]
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/manifest.json b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/manifest.json
new file mode 100644
index 00000000..c29a00e8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/manifest.json
@@ -0,0 +1,55 @@
+{
+ "betaManifestVersion":1,
+ "version":"revision 7096",
+ "entries":[
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/exhibit-api.js?bundle=false" },
+ { "url":"http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js" },
+ { "url":"http://static.simile.mit.edu/ajax/api-2.0/bundle.js" },
+ { "url":"http://static.simile.mit.edu/ajax/api-2.0/scripts/signal.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/exhibit.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/persistence.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/util/set.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/util/util.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/util/settings.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/util/views.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/util/facets.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/database.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/expression.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/expression-parser.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/functions.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/collection.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/importers/exhibit-json-importer.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/importers/html-table-importer.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/importers/jsonp-importer.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/exporters/rdf-xml-exporter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/exporters/semantic-wikitext-exporter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/exporters/exhibit-json-exporter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/exporters/tsv-exporter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/data/exporters/bibtex-exporter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/ui.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/ui-context.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/lens.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/format-parser.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/formatter.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/facets/list-facet.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/scripts/ui/facets/numeric-range-facet.js" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/exhibit.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/browse-panel.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/lens.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/util/facets.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/util/views.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/widgets/collection-summary-widget.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/widgets/resizable-div-widget.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/widgets/legend-widget.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/widgets/option-widget.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/widgets/toolbox-widget.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/view-panel.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/tile-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/map-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/timeline-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/thumbnail-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/tabular-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/scatter-plot-view.css" },
+ { "url":"http://static.simile.mit.edu/exhibit/api-2.0/styles/views/pivot-table-view.css" }
+ ]
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/authentication.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/authentication.js
new file mode 100644
index 00000000..cf22d775
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/authentication.js
@@ -0,0 +1,64 @@
+Exhibit.Authentication = {};
+
+// global flag for whether exhibit is authenticated
+Exhibit.Authentication.Enabled = false;
+
+// token given by Google AuthSubRequest service, passed to CGI scripts
+// to authenticate exhibit user.
+Exhibit.Authentication.GoogleToken = null;
+
+// token returned from CGI script, after auth token is upgraded
+// to a session token. once a session token is obtained, it should
+// be used for all subsequent requests.
+Exhibit.Authentication.GoogleSessionToken = null;
+
+Exhibit.Authentication.authenticate = function() {
+ if (!window.Exhibit.params.authenticated) {
+ return;
+ }
+
+ var links = document.getElementsByTagName('head')[0].childNodes;
+ for (var i = 0; i < links.length; i++) {
+ var link = links[i];
+ if (link.rel == 'exhibit/output' && link.getAttribute('ex:authenticated')) {
+ Exhibit.Authentication.handleGoogleAuthentication();
+ return;
+ }
+ }
+
+}
+
+Exhibit.Authentication.parseLocationParams = function() {
+ var params = document.location.search.substr(1).split("&");
+ var ret = {};
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i];
+ if (p.indexOf('=') != -1) {
+ var components = p.split('=');
+ if (components.length != 2) {
+ SimileAjax.Debug.warn("Error parsing location parameter " + p);
+ } else {
+ ret[components[0]] = components[1];
+ }
+ } else {
+ ret[p] = true;
+ }
+ }
+ return ret;
+}
+
+Exhibit.Authentication.GoogleAuthenticationURL = "https://www.google.com/accounts/AuthSubRequest";
+
+Exhibit.Authentication.handleGoogleAuthentication = function() {
+ var params = Exhibit.Authentication.parseLocationParams();
+ if (params.token) {
+ Exhibit.Authentication.GoogleToken = params.token;
+ Exhibit.Authentication.Enabled = true;
+ } else {
+ var authURL = Exhibit.Authentication.GoogleAuthenticationURL;
+ authURL += '?session=1'; // server CGI script requires session authentication to perform multiple actions
+ authURL += '&scope=http://spreadsheets.google.com/feeds/';
+ authURL += '&next=' + document.location.href;
+ document.location.href = authURL;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/create.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/create.js
new file mode 100644
index 00000000..fce5136f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/create.js
@@ -0,0 +1,39 @@
+/*======================================================================
+ * Exhibit auto-create
+ * Code to automatically create the database, load the data links in
+ * <head>, and then to create an exhibit if there's no ex:ondataload
+ * handler on the body element.
+ *
+ * You can avoid running this code by adding the URL parameter
+ * autoCreate=false when you include exhibit-api.js.
+ *======================================================================
+ */
+SimileAjax.jQuery(document).ready(function() {
+ var fDone = function() {
+ window.exhibit = Exhibit.create();
+ window.exhibit.configureFromDOM();
+ };
+
+ try {
+ var s = Exhibit.getAttribute(document.body, "ondataload");
+ if (s != null && typeof s == "string" && s.length > 0) {
+ fDone = function() {
+ var f = eval(s);
+ if (typeof f == "function") {
+ f.call();
+ }
+ }
+ }
+ } catch (e) {
+ // silent
+ }
+
+ var fLoadSubmissions = function() {
+ window.database.loadSubmissionLinks(fDone);
+ };
+
+ Exhibit.Authentication.authenticate();
+ window.database = Exhibit.Database.create();
+ window.database.loadDataLinks(fLoadSubmissions);
+});
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/collection.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/collection.js
new file mode 100644
index 00000000..850490ab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/collection.js
@@ -0,0 +1,395 @@
+/*======================================================================
+ * Collection
+ *======================================================================
+ */
+Exhibit.Collection = function(id, database) {
+ this._id = id;
+ this._database = database;
+
+ this._listeners = new SimileAjax.ListenerQueue();
+ this._facets = [];
+ this._updating = false;
+
+ this._items = null;
+ this._restrictedItems = null;
+};
+
+Exhibit.Collection.createAllItemsCollection = function(id, database) {
+ var collection = new Exhibit.Collection(id, database);
+ collection._update = Exhibit.Collection._allItemsCollection_update;
+
+ Exhibit.Collection._initializeBasicCollection(collection, database);
+
+ return collection;
+};
+
+Exhibit.Collection.createSubmissionsCollection = function(id, database) {
+ var collection = new Exhibit.Collection(id, database);
+ collection._update = Exhibit.Collection._submissionCollection_update;
+
+ Exhibit.Collection._initializeBasicCollection(collection, database);
+
+ return collection;
+}
+
+Exhibit.Collection.create = function(id, configuration, database) {
+ var collection = new Exhibit.Collection(id, database);
+
+ if ("itemTypes" in configuration) {
+ collection._itemTypes = configuration.itemTypes;
+ collection._update = Exhibit.Collection._typeBasedCollection_update;
+ } else {
+ collection._update = Exhibit.Collection._allItemsCollection_update;
+ }
+
+ Exhibit.Collection._initializeBasicCollection(collection, database);
+
+ return collection;
+};
+
+Exhibit.Collection.createFromDOM = function(id, elmt, database) {
+ var collection = new Exhibit.Collection(id, database);
+
+ var itemTypes = Exhibit.getAttribute(elmt, "itemTypes", ",");
+ if (itemTypes != null && itemTypes.length > 0) {
+ collection._itemTypes = itemTypes;
+ collection._update = Exhibit.Collection._typeBasedCollection_update;
+ } else {
+ collection._update = Exhibit.Collection._allItemsCollection_update;
+ }
+
+ Exhibit.Collection._initializeBasicCollection(collection, database);
+
+ return collection;
+};
+
+Exhibit.Collection.create2 = function(id, configuration, uiContext) {
+ var database = uiContext.getDatabase();
+
+ if ("expression" in configuration) {
+ var collection = new Exhibit.Collection(id, database);
+
+ collection._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ collection._baseCollection = ("baseCollectionID" in configuration) ?
+ uiContext.getExhibit().getCollection(configuration.baseCollectionID) :
+ uiContext.getCollection();
+
+ collection._restrictBaseCollection = ("restrictBaseCollection" in configuration) ?
+ configuration.restrictBaseCollection : false;
+
+ if (collection._restrictBaseCollection) {
+ Exhibit.Collection._initializeRestrictingBasedCollection(collection);
+ } else {
+ Exhibit.Collection._initializeBasedCollection(collection);
+ }
+
+ return collection;
+ } else {
+ return Exhibit.Collection.create(id, configuration, database);
+ }
+};
+
+Exhibit.Collection.createFromDOM2 = function(id, elmt, uiContext) {
+ var database = uiContext.getDatabase();
+ var collection;
+
+ if (Exhibit.getAttribute(elmt, 'submissionsCollection')) {
+ return Exhibit.Collection.createSubmissionsCollection(id, database);
+ }
+
+ var expressionString = Exhibit.getAttribute(elmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ collection = new Exhibit.Collection(id, database);
+
+ collection._expression = Exhibit.ExpressionParser.parse(expressionString);
+
+ var baseCollectionID = Exhibit.getAttribute(elmt, "baseCollectionID");
+ collection._baseCollection = (baseCollectionID != null && baseCollectionID.length > 0) ?
+ uiContext.getExhibit().getCollection(baseCollectionID) :
+ uiContext.getCollection();
+
+ collection._restrictBaseCollection = Exhibit.getAttribute(elmt, "restrictBaseCollection") == "true";
+ if (collection._restrictBaseCollection) {
+ Exhibit.Collection._initializeRestrictingBasedCollection(collection, database);
+ } else {
+ Exhibit.Collection._initializeBasedCollection(collection);
+ }
+ } else {
+ collection = Exhibit.Collection.createFromDOM(id, elmt, database);
+ }
+ return collection;
+};
+
+Exhibit.Collection._initializeBasicCollection = function(collection, database) {
+ var update = function() { collection._update(); };
+ collection._listener = {
+ onAfterLoadingItems: update,
+ onAfterRemovingAllStatements: update
+ };
+ database.addListener(collection._listener);
+
+ collection._update();
+};
+
+Exhibit.Collection._initializeBasedCollection = function(collection) {
+ collection._update = Exhibit.Collection._basedCollection_update;
+
+ collection._listener = { onItemsChanged: function() { collection._update(); } };
+ collection._baseCollection.addListener(collection._listener);
+
+ collection._update();
+};
+
+Exhibit.Collection._initializeRestrictingBasedCollection = function(collection, database) {
+ collection._cache = new Exhibit.FacetUtilities.Cache(
+ database,
+ collection._baseCollection,
+ collection._expression
+ );
+ collection._isUpdatingBaseCollection = false;
+
+ collection.onFacetUpdated = Exhibit.Collection._restrictingBasedCollection_onFacetUpdated;
+ collection.restrict = Exhibit.Collection._restrictingBasedCollection_restrict;
+ collection.update = Exhibit.Collection._restrictingBasedCollection_update;
+ collection.hasRestrictions = Exhibit.Collection._restrictingBasedCollection_hasRestrictions;
+
+ collection._baseCollection.addFacet(collection);
+};
+
+/*======================================================================
+ * Implementation
+ *======================================================================
+ */
+Exhibit.Collection._allItemsCollection_update = function() {
+ this.setItems(this._database.getAllItems());
+ this._onRootItemsChanged();
+};
+
+Exhibit.Collection._submissionCollection_update = function() {
+ this.setItems(this._database.getAllSubmissions());
+ this._onRootItemsChanged();
+};
+
+
+Exhibit.Collection._typeBasedCollection_update = function() {
+ var newItems = new Exhibit.Set();
+ for (var i = 0; i < this._itemTypes.length; i++) {
+ this._database.getSubjects(this._itemTypes[i], "type", newItems);
+ }
+
+ this.setItems(newItems);
+ this._onRootItemsChanged();
+};
+
+Exhibit.Collection._basedCollection_update = function() {
+ this.setItems(this._expression.evaluate(
+ { "value" : this._baseCollection.getRestrictedItems() },
+ { "value" : "item" },
+ "value",
+ this._database
+ ).values);
+
+ this._onRootItemsChanged();
+};
+
+Exhibit.Collection._restrictingBasedCollection_onFacetUpdated = function(facetChanged) {
+ if (!this._updating) {
+ /*
+ * This is called when one of our own facets is changed.
+ */
+ Exhibit.Collection.prototype.onFacetUpdated.call(this, facetChanged);
+
+ /*
+ * We need to restrict the base collection.
+ */
+ this._isUpdatingBaseCollection = true;
+ this._baseCollection.onFacetUpdated(this);
+ this._isUpdatingBaseCollection = false;
+ }
+};
+
+Exhibit.Collection._restrictingBasedCollection_restrict = function(items) {
+ /*
+ * Restrict the base collection using our own restricted items
+ * (as filtered by our own facets).
+ */
+ if (this._restrictedItems.size() == this._items.size()) {
+ return items;
+ }
+
+ return this._cache.getItemsFromValues(this._restrictedItems, items);
+};
+
+Exhibit.Collection._restrictingBasedCollection_update = function(items) {
+ if (!this._isUpdatingBaseCollection) {
+ /*
+ * This is called when the base collection is changed by
+ * one of its other facets. This causes our root items to
+ * change.
+ */
+ this.setItems(this._cache.getValuesFromItems(items));
+ this._onRootItemsChanged();
+ }
+};
+
+Exhibit.Collection._restrictingBasedCollection_hasRestrictions = function() {
+ return (this._items != null) && (this._restrictedItems != null) &&
+ (this._restrictedItems.size() != this._items.size());
+};
+
+/*======================================================================
+ * Common Implementation
+ *======================================================================
+ */
+Exhibit.Collection.prototype.getID = function() {
+ return this._id;
+};
+
+Exhibit.Collection.prototype.dispose = function() {
+ if ("_baseCollection" in this) {
+ this._baseCollection.removeListener(this._listener);
+ this._baseCollection = null;
+ this._expression = null;
+ } else {
+ this._database.removeListener(this._listener);
+ }
+ this._database = null;
+ this._listener = null;
+
+ this._listeners = null;
+ this._items = null;
+ this._restrictedItems = null;
+};
+
+Exhibit.Collection.prototype.addListener = function(listener) {
+ this._listeners.add(listener);
+};
+
+Exhibit.Collection.prototype.removeListener = function(listener) {
+ this._listeners.remove(listener);
+};
+
+Exhibit.Collection.prototype.addFacet = function(facet) {
+ this._facets.push(facet);
+
+ if (facet.hasRestrictions()) {
+ this._computeRestrictedItems();
+ this._updateFacets(null);
+ this._listeners.fire("onItemsChanged", []);
+ } else {
+ facet.update(this.getRestrictedItems());
+ }
+};
+
+Exhibit.Collection.prototype.removeFacet = function(facet) {
+ for (var i = 0; i < this._facets.length; i++) {
+ if (facet == this._facets[i]) {
+ this._facets.splice(i, 1);
+ if (facet.hasRestrictions()) {
+ this._computeRestrictedItems();
+ this._updateFacets(null);
+ this._listeners.fire("onItemsChanged", []);
+ }
+ break;
+ }
+ }
+};
+
+Exhibit.Collection.prototype.clearAllRestrictions = function() {
+ var restrictions = [];
+
+ this._updating = true;
+ for (var i = 0; i < this._facets.length; i++) {
+ restrictions.push(this._facets[i].clearAllRestrictions());
+ }
+ this._updating = false;
+
+ this.onFacetUpdated(null);
+
+ return restrictions;
+};
+
+Exhibit.Collection.prototype.applyRestrictions = function(restrictions) {
+ this._updating = true;
+ for (var i = 0; i < this._facets.length; i++) {
+ this._facets[i].applyRestrictions(restrictions[i]);
+ }
+ this._updating = false;
+
+ this.onFacetUpdated(null);
+};
+
+Exhibit.Collection.prototype.getAllItems = function() {
+ return new Exhibit.Set(this._items);
+};
+
+Exhibit.Collection.prototype.countAllItems = function() {
+ return this._items.size();
+};
+
+Exhibit.Collection.prototype.getRestrictedItems = function() {
+ return new Exhibit.Set(this._restrictedItems);
+};
+
+Exhibit.Collection.prototype.countRestrictedItems = function() {
+ return this._restrictedItems.size();
+};
+
+Exhibit.Collection.prototype.onFacetUpdated = function(facetChanged) {
+ if (!this._updating) {
+ this._computeRestrictedItems();
+ this._updateFacets(facetChanged);
+ this._listeners.fire("onItemsChanged", []);
+ }
+}
+
+Exhibit.Collection.prototype._onRootItemsChanged = function() {
+ this._listeners.fire("onRootItemsChanged", []);
+
+ this._computeRestrictedItems();
+ this._updateFacets(null);
+
+ this._listeners.fire("onItemsChanged", []);
+};
+
+Exhibit.Collection.prototype._updateFacets = function(facetChanged) {
+ var restrictedFacetCount = 0;
+ for (var i = 0; i < this._facets.length; i++) {
+ if (this._facets[i].hasRestrictions()) {
+ restrictedFacetCount++;
+ }
+ }
+
+ for (var i = 0; i < this._facets.length; i++) {
+ var facet = this._facets[i];
+ if (facet.hasRestrictions()) {
+ if (restrictedFacetCount <= 1) {
+ facet.update(this.getAllItems());
+ } else {
+ var items = this.getAllItems();
+ for (var j = 0; j < this._facets.length; j++) {
+ if (i != j) {
+ items = this._facets[j].restrict(items);
+ }
+ }
+ facet.update(items);
+ }
+ } else {
+ facet.update(this.getRestrictedItems());
+ }
+ }
+};
+
+Exhibit.Collection.prototype._computeRestrictedItems = function() {
+ this._restrictedItems = this._items;
+ for (var i = 0; i < this._facets.length; i++) {
+ var facet = this._facets[i];
+ if (facet.hasRestrictions()) {
+ this._restrictedItems = facet.restrict(this._restrictedItems);
+ }
+ }
+};
+
+Exhibit.Collection.prototype.setItems = function(items) {
+ this._items = items;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/controls.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/controls.js
new file mode 100644
index 00000000..fb807ab6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/controls.js
@@ -0,0 +1,115 @@
+/*==================================================
+ * Exhibit.Controls
+ *==================================================
+ */
+Exhibit.Controls = {};
+
+Exhibit.Controls["if"] = {
+ f: function(
+ args,
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+ ) {
+ var conditionCollection = args[0].evaluate(roots, rootValueTypes, defaultRootName, database);
+ var condition = false;
+ conditionCollection.forEachValue(function(v) {
+ if (v) {
+ condition = true;
+ return true;
+ }
+ });
+
+ if (condition) {
+ return args[1].evaluate(roots, rootValueTypes, defaultRootName, database);
+ } else {
+ return args[2].evaluate(roots, rootValueTypes, defaultRootName, database);
+ }
+ }
+};
+
+Exhibit.Controls["foreach"] = {
+ f: function(
+ args,
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+ ) {
+ var collection = args[0].evaluate(roots, rootValueTypes, defaultRootName, database);
+
+ var oldValue = roots["value"];
+ var oldValueType = rootValueTypes["value"];
+ rootValueTypes["value"] = collection.valueType;
+
+ var results = [];
+ var valueType = "text";
+
+ collection.forEachValue(function(element) {
+ roots["value"] = element;
+
+ var collection2 = args[1].evaluate(roots, rootValueTypes, defaultRootName, database);
+ valueType = collection2.valueType;
+
+ collection2.forEachValue(function(result) {
+ results.push(result);
+ });
+ });
+
+ roots["value"] = oldValue;
+ rootValueTypes["value"] = oldValueType;
+
+ return new Exhibit.Expression._Collection(results, valueType);
+ }
+};
+
+Exhibit.Controls["default"] = {
+ f: function(
+ args,
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+ ) {
+ for (var i = 0; i < args.length; i++) {
+ var collection = args[i].evaluate(roots, rootValueTypes, defaultRootName, database);
+ if (collection.size > 0) {
+ return collection;
+ }
+ }
+ return new Exhibit.Expression._Collection([], "text");
+ }
+};
+
+Exhibit.Controls["filter"] = {
+ f: function(
+ args,
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+ ) {
+ var collection = args[0].evaluate(roots, rootValueTypes, defaultRootName, database);
+
+ var oldValue = roots["value"];
+ var oldValueType = rootValueTypes["value"];
+
+ var results = new Exhibit.Set();
+ rootValueTypes["value"] = collection.valueType;
+
+ collection.forEachValue(function(element) {
+ roots["value"] = element;
+
+ var collection2 = args[1].evaluate(roots, rootValueTypes, defaultRootName, database);
+ if (collection2.size > 0 && collection2.contains("true")) {
+ results.add(element);
+ }
+ });
+
+ roots["value"] = oldValue;
+ rootValueTypes["value"] = oldValueType;
+
+ return new Exhibit.Expression._Collection(results, collection.valueType);
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/database.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/database.js
new file mode 100644
index 00000000..0808c9a4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/database.js
@@ -0,0 +1,1306 @@
+/*======================================================================
+ * Exhibit.Database
+ * http://simile.mit.edu/wiki/Exhibit/API/Database
+ *======================================================================
+ */
+
+Exhibit.Database = new Object();
+
+Exhibit.Database.create = function() {
+ Exhibit.Database.handleAuthentication();
+ return new Exhibit.Database._Impl();
+};
+
+Exhibit.Database.handleAuthentication = function() {
+ if (window.Exhibit.params.authenticated) {
+ var links = document.getElementsByTagName('head')[0].childNodes;
+ for (var i = 0; i < links.length; i++) {
+ var link = links[i];
+ if (link.rel == 'exhibit/output' && link.getAttribute('ex:authenticated')) {
+
+ }
+ }
+ }
+};
+
+Exhibit.Database.makeISO8601DateString = function(date) {
+ date = date || new Date();
+ var pad = function(i) { return i > 9 ? i.toString() : '0'+i };
+ var s = date.getFullYear() + '-' + pad(date.getMonth() +1) + '-' + pad(date.getDate());
+ return s;
+}
+
+Exhibit.Database.TimestampPropertyName = "addedOn";
+
+/*==================================================
+ * Exhibit.Database._Impl
+ *==================================================
+ */
+Exhibit.Database._Impl = function() {
+ this._types = {};
+ this._properties = {};
+ this._propertyArray = {};
+
+ this._submissionRegistry = {}; // stores unmodified copies of submissions
+
+ this._originalValues = {};
+ this._newItems = {};
+
+ this._listeners = new SimileAjax.ListenerQueue();
+
+ this._spo = {};
+ this._ops = {};
+ this._items = new Exhibit.Set();
+
+ /*
+ * Predefined types and properties
+ */
+
+ var l10n = Exhibit.Database.l10n;
+
+ var itemType = new Exhibit.Database._Type("Item");
+ itemType._custom = Exhibit.Database.l10n.itemType;
+ this._types["Item"] = itemType;
+
+ var labelProperty = new Exhibit.Database._Property("label", this);
+ labelProperty._uri = "http://www.w3.org/2000/01/rdf-schema#label";
+ labelProperty._valueType = "text";
+ labelProperty._label = l10n.labelProperty.label;
+ labelProperty._pluralLabel = l10n.labelProperty.pluralLabel;
+ labelProperty._reverseLabel = l10n.labelProperty.reverseLabel;
+ labelProperty._reversePluralLabel = l10n.labelProperty.reversePluralLabel;
+ labelProperty._groupingLabel = l10n.labelProperty.groupingLabel;
+ labelProperty._reverseGroupingLabel = l10n.labelProperty.reverseGroupingLabel;
+ this._properties["label"] = labelProperty;
+
+ var typeProperty = new Exhibit.Database._Property("type");
+ typeProperty._uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+ typeProperty._valueType = "text";
+ typeProperty._label = "type";
+ typeProperty._pluralLabel = l10n.typeProperty.label;
+ typeProperty._reverseLabel = l10n.typeProperty.reverseLabel;
+ typeProperty._reversePluralLabel = l10n.typeProperty.reversePluralLabel;
+ typeProperty._groupingLabel = l10n.typeProperty.groupingLabel;
+ typeProperty._reverseGroupingLabel = l10n.typeProperty.reverseGroupingLabel;
+ this._properties["type"] = typeProperty;
+
+ var uriProperty = new Exhibit.Database._Property("uri");
+ uriProperty._uri = "http://simile.mit.edu/2006/11/exhibit#uri";
+ uriProperty._valueType = "url";
+ uriProperty._label = "URI";
+ uriProperty._pluralLabel = "URIs";
+ uriProperty._reverseLabel = "URI of";
+ uriProperty._reversePluralLabel = "URIs of";
+ uriProperty._groupingLabel = "URIs";
+ uriProperty._reverseGroupingLabel = "things named by these URIs";
+ this._properties["uri"] = uriProperty;
+
+ var changeProperty = new Exhibit.Database._Property("change", this);
+ changeProperty._uri = "http://simile.mit.edu/2006/11/exhibit#change";
+ changeProperty._valueType = "text";
+ changeProperty._label = "change type";
+ changeProperty._pluralLabel = "change types";
+ changeProperty._reverseLabel = "change type of";
+ changeProperty._reversePluralLabel = "change types of";
+ changeProperty._groupingLabel = "change types";
+ changeProperty._reverseGroupingLabel = "changes of this type";
+ this._properties["change"] = changeProperty;
+
+ var changedItemProperty = new Exhibit.Database._Property("changedItem", this);
+ changedItemProperty._uri = "http://simile.mit.edu/2006/11/exhibit#changedItem";
+ changedItemProperty._valueType = "text";
+ changedItemProperty._label = "changed item";
+ changedItemProperty._pluralLabel = "changed item";
+ changedItemProperty._groupingLabel = "changed items";
+ this._properties["changedItem"] = changedItemProperty;
+
+ var modifiedProperty = new Exhibit.Database._Property(Exhibit.Database.ModifiedPropertyName, this);
+ modifiedProperty._uri = "http://simile.mit.edu/2006/11/exhibit#modified";
+ modifiedProperty._valueType = "text";
+ modifiedProperty._label = "modified";
+ modifiedProperty._pluralLabel = "modified";
+ modifiedProperty._groupingLabel = "was modified";
+ this._properties["modified"] = modifiedProperty;
+};
+
+Exhibit.Database._Impl.prototype.createDatabase = function() {
+ return Exhibit.Database.create();
+};
+
+Exhibit.Database._Impl.prototype.addListener = function(listener) {
+ this._listeners.add(listener);
+};
+
+Exhibit.Database._Impl.prototype.removeListener = function(listener) {
+ this._listeners.remove(listener);
+};
+
+Exhibit.Database._Impl.prototype.loadDataLinks = function(fDone) {
+ var links = SimileAjax.jQuery('head > link[rel=exhibit/data]').get();
+ this._loadLinks(links, this, fDone);
+};
+
+Exhibit.Database._Impl.prototype.loadLinks = function(links, fDone) {
+ this._loadLinks(links, this, fDone);
+};
+
+Exhibit.Database._Impl.prototype.loadSubmissionLinks = function(fDone) {
+ var db = this;
+ var dbProxy = {
+ loadData: function(o, baseURI) {
+ if ("types" in o) {
+ db.loadTypes(o.types, baseURI);
+ }
+ if ("properties" in o) {
+ db.loadProperties(o.properties, baseURI);
+ }
+ if ("items" in o) {
+ db._listeners.fire("onBeforeLoadingItems", []);
+ o.items.forEach(function(item) {
+ var oldID = item.id || item.label;
+ var newID = oldID + Math.floor(Math.random() * 1000000);
+ db._submissionRegistry[newID] = true;
+
+ item.id = newID;
+ item.changedItem = oldID;
+
+ if (db.containsItem(oldID)) {
+ item.change = 'modification';
+
+ if (!item.type) {
+ item.type = db.getObject(oldID, 'type');
+ }
+ } else {
+ item.change = 'addition';
+ }
+ });
+ db.loadItems(o.items, baseURI);
+ db._listeners.fire("onAfterLoadingItems", []);
+ }
+ }
+
+ };
+
+ var links = SimileAjax.jQuery('head > link[rel=exhibit/submissions]').get()
+ this._loadLinks(links, dbProxy, fDone);
+};
+
+Exhibit.Database._Impl.prototype._loadLinks = function(links, database, fDone) {
+ links = [].concat(links);
+ var fNext = function() {
+ while (links.length > 0) {
+ var link = links.shift();
+ var type = link.type;
+ if (type == null || type.length == 0) {
+ type = "application/json";
+ }
+
+ var importer = Exhibit.importers[type];
+ if (importer) {
+ importer.load(link, database, fNext);
+ return;
+ } else {
+ SimileAjax.Debug.log("No importer for data of type " + type);
+ }
+ }
+
+ if (fDone != null) {
+ fDone();
+ }
+ };
+ fNext();
+};
+
+Exhibit.Database._Impl.prototype.loadData = function(o, baseURI) {
+ if (typeof baseURI == "undefined") {
+ baseURI = location.href;
+ }
+ if ("types" in o) {
+ this.loadTypes(o.types, baseURI);
+ }
+ if ("properties" in o) {
+ this.loadProperties(o.properties, baseURI);
+ }
+ if ("items" in o) {
+ this.loadItems(o.items, baseURI);
+ }
+};
+
+Exhibit.Database._Impl.prototype.loadTypes = function(typeEntries, baseURI) {
+ this._listeners.fire("onBeforeLoadingTypes", []);
+ try {
+ var lastChar = baseURI.substr(baseURI.length - 1)
+ if (lastChar == "#") {
+ baseURI = baseURI.substr(0, baseURI.length - 1) + "/";
+ } else if (lastChar != "/" && lastChar != ":") {
+ baseURI += "/";
+ }
+
+ for (var typeID in typeEntries) {
+ if (typeof typeID != "string") {
+ continue;
+ }
+
+ var typeEntry = typeEntries[typeID];
+ if (typeof typeEntry != "object") {
+ continue;
+ }
+
+ var type;
+ if (typeID in this._types) {
+ type = this._types[typeID];
+ } else {
+ type = new Exhibit.Database._Type(typeID);
+ this._types[typeID] = type;
+ }
+ for (var p in typeEntry) {
+ type._custom[p] = typeEntry[p];
+ }
+
+ if (!("uri" in type._custom)) {
+ type._custom["uri"] = baseURI + "type#" + encodeURIComponent(typeID);
+ }
+ if (!("label" in type._custom)) {
+ type._custom["label"] = typeID;
+ }
+ }
+
+ this._listeners.fire("onAfterLoadingTypes", []);
+ } catch(e) {
+ SimileAjax.Debug.exception(e, "Database.loadTypes failed");
+ }
+};
+
+Exhibit.Database._Impl.prototype.loadProperties = function(propertyEntries, baseURI) {
+ this._listeners.fire("onBeforeLoadingProperties", []);
+ try {
+ var lastChar = baseURI.substr(baseURI.length - 1)
+ if (lastChar == "#") {
+ baseURI = baseURI.substr(0, baseURI.length - 1) + "/";
+ } else if (lastChar != "/" && lastChar != ":") {
+ baseURI += "/";
+ }
+
+ for (var propertyID in propertyEntries) {
+ if (typeof propertyID != "string") {
+ continue;
+ }
+
+ var propertyEntry = propertyEntries[propertyID];
+ if (typeof propertyEntry != "object") {
+ continue;
+ }
+
+ var property;
+ if (propertyID in this._properties) {
+ property = this._properties[propertyID];
+ } else {
+ property = new Exhibit.Database._Property(propertyID, this);
+ this._properties[propertyID] = property;
+ }
+ property._uri = ("uri" in propertyEntry) ? propertyEntry.uri : (baseURI + "property#" + encodeURIComponent(propertyID));
+ property._valueType = ("valueType" in propertyEntry) ? propertyEntry.valueType : "text";
+ // text, html, number, date, boolean, item, url
+
+ property._label = ("label" in propertyEntry) ? propertyEntry.label : propertyID;
+ property._pluralLabel = ("pluralLabel" in propertyEntry) ? propertyEntry.pluralLabel : property._label;
+
+ property._reverseLabel = ("reverseLabel" in propertyEntry) ? propertyEntry.reverseLabel : ("!" + property._label);
+ property._reversePluralLabel = ("reversePluralLabel" in propertyEntry) ? propertyEntry.reversePluralLabel : ("!" + property._pluralLabel);
+
+ property._groupingLabel = ("groupingLabel" in propertyEntry) ? propertyEntry.groupingLabel : property._label;
+ property._reverseGroupingLabel = ("reverseGroupingLabel" in propertyEntry) ? propertyEntry.reverseGroupingLabel : property._reverseLabel;
+
+ if ("origin" in propertyEntry) {
+ property._origin = propertyEntry.origin;
+ }
+ }
+ this._propertyArray = null;
+
+ this._listeners.fire("onAfterLoadingProperties", []);
+ } catch(e) {
+ SimileAjax.Debug.exception(e, "Database.loadProperties failed");
+ }
+};
+
+Exhibit.Database._Impl.prototype.loadItems = function(itemEntries, baseURI) {
+ this._listeners.fire("onBeforeLoadingItems", []);
+ try {
+ var lastChar = baseURI.substr(baseURI.length - 1);
+ if (lastChar == "#") {
+ baseURI = baseURI.substr(0, baseURI.length - 1) + "/";
+ } else if (lastChar != "/" && lastChar != ":") {
+ baseURI += "/";
+ }
+
+ var spo = this._spo;
+ var ops = this._ops;
+ var indexPut = Exhibit.Database._indexPut;
+ var indexTriple = function(s, p, o) {
+ indexPut(spo, s, p, o);
+ indexPut(ops, o, p, s);
+ };
+
+ for (var i = 0; i < itemEntries.length; i++) {
+ var entry = itemEntries[i];
+ if (typeof entry == "object") {
+ this._loadItem(entry, indexTriple, baseURI);
+ }
+ }
+
+ this._propertyArray = null;
+
+ this._listeners.fire("onAfterLoadingItems", []);
+ } catch(e) {
+ SimileAjax.Debug.exception(e, "Database.loadItems failed");
+ }
+};
+
+Exhibit.Database._Impl.prototype.getType = function(typeID) {
+ return this._types[typeID];
+};
+
+Exhibit.Database._Impl.prototype.getProperty = function(propertyID) {
+ return propertyID in this._properties ? this._properties[propertyID] : null;
+};
+
+/**
+ * Get an array of all property names known to this database.
+ */
+Exhibit.Database._Impl.prototype.getAllProperties = function() {
+ if (this._propertyArray == null) {
+ this._propertyArray = [];
+ for (var propertyID in this._properties) {
+ this._propertyArray.push(propertyID);
+ }
+ }
+
+ return [].concat(this._propertyArray);
+};
+
+Exhibit.Database._Impl.prototype.isSubmission = function(id) {
+ return id in this._submissionRegistry;
+}
+
+Exhibit.Database._Impl.prototype.getAllItems = function() {
+ var ret = new Exhibit.Set();
+ var self = this;
+
+ this._items.visit(function(item) {
+ if (!self.isSubmission(item)) {
+ ret.add(item);
+ }
+ });
+
+ return ret;
+};
+
+Exhibit.Database._Impl.prototype.getAllSubmissions = function() {
+ var ret = new Exhibit.Set();
+ var itemList = this._items.toArray();
+
+ for (var i in itemList) {
+ var item = itemList[i];
+ if (this.isSubmission(item)) {
+ ret.add(item);
+ }
+ }
+
+ return ret;
+}
+
+Exhibit.Database._Impl.prototype.getAllItemsCount = function() {
+ return this._items.size();
+};
+
+Exhibit.Database._Impl.prototype.containsItem = function(itemID) {
+ return this._items.contains(itemID);
+};
+
+Exhibit.Database._Impl.prototype.getNamespaces = function(idToQualifiedName, prefixToBase) {
+ var bases = {};
+ for (var propertyID in this._properties) {
+ var property = this._properties[propertyID];
+ var uri = property.getURI();
+
+ var hash = uri.indexOf("#");
+ if (hash > 0) {
+ var base = uri.substr(0, hash + 1);
+ bases[base] = true;
+
+ idToQualifiedName[propertyID] = {
+ base: base,
+ localName: uri.substr(hash + 1)
+ };
+ continue;
+ }
+
+ var slash = uri.lastIndexOf("/");
+ if (slash > 0) {
+ var base = uri.substr(0, slash + 1);
+ bases[base] = true;
+
+ idToQualifiedName[propertyID] = {
+ base: base,
+ localName: uri.substr(slash + 1)
+ };
+ continue;
+ }
+ }
+
+ var baseToPrefix = {};
+ var letters = "abcdefghijklmnopqrstuvwxyz";
+ var i = 0;
+
+ for (var base in bases) {
+ var prefix = letters.substr(i++,1);
+ prefixToBase[prefix] = base;
+ baseToPrefix[base] = prefix;
+ }
+
+ for (var propertyID in idToQualifiedName) {
+ var qname = idToQualifiedName[propertyID];
+ qname.prefix = baseToPrefix[qname.base];
+ }
+};
+
+Exhibit.Database._Impl.prototype._loadItem = function(itemEntry, indexFunction, baseURI) {
+ if (!("label" in itemEntry) && !("id" in itemEntry)) {
+ SimileAjax.Debug.warn("Item entry has no label and no id: " +
+ SimileAjax.JSON.toJSONString( itemEntry ));
+ return;
+ }
+
+ var id;
+ if (!("label" in itemEntry)) {
+ id = itemEntry.id;
+ if (!this._items.contains(id)) {
+ SimileAjax.Debug.warn("Cannot add new item containing no label: " +
+ SimileAjax.JSON.toJSONString( itemEntry ));
+ }
+ } else {
+ var label = itemEntry.label;
+ var id = ("id" in itemEntry) ? itemEntry.id : label;
+ var uri = ("uri" in itemEntry) ? itemEntry.uri : (baseURI + "item#" + encodeURIComponent(id));
+ var type = ("type" in itemEntry) ? itemEntry.type : "Item";
+
+
+ var isArray = function(obj) {
+ if (obj.constructor.toString().indexOf("Array") == -1)
+ return false;
+ else
+ return true;
+ }
+ if(isArray(label))
+ label = label[0];
+ if(isArray(id))
+ id = id[0];
+ if(isArray(uri))
+ uri = uri[0];
+ if(isArray(type))
+ type = type[0];
+
+ this._items.add(id);
+
+ indexFunction(id, "uri", uri);
+ indexFunction(id, "label", label);
+ indexFunction(id, "type", type);
+
+ this._ensureTypeExists(type, baseURI);
+ }
+
+ // items default to not being modified
+ itemEntry.modified = itemEntry.modified || "no";
+
+ for (var p in itemEntry) {
+ if (typeof p != "string") {
+ continue;
+ }
+
+ if (p != "uri" && p != "label" && p != "id" && p != "type") {
+ this._ensurePropertyExists(p, baseURI)._onNewData();
+
+ var v = itemEntry[p];
+ if (v instanceof Array) {
+ for (var j = 0; j < v.length; j++) {
+ indexFunction(id, p, v[j]);
+ }
+ } else if (v != undefined && v != null) {
+ indexFunction(id, p, v);
+ }
+ }
+ }
+};
+
+Exhibit.Database._Impl.prototype._ensureTypeExists = function(typeID, baseURI) {
+ if (!(typeID in this._types)) {
+ var type = new Exhibit.Database._Type(typeID);
+
+ type._custom["uri"] = baseURI + "type#" + encodeURIComponent(typeID);
+ type._custom["label"] = typeID;
+
+ this._types[typeID] = type;
+ }
+};
+
+Exhibit.Database._Impl.prototype._ensurePropertyExists = function(propertyID, baseURI) {
+ if (!(propertyID in this._properties)) {
+ var property = new Exhibit.Database._Property(propertyID, this);
+
+ property._uri = baseURI + "property#" + encodeURIComponent(propertyID);
+ property._valueType = "text";
+
+ property._label = propertyID;
+ property._pluralLabel = property._label;
+
+ property._reverseLabel = "reverse of " + property._label;
+ property._reversePluralLabel = "reverse of " + property._pluralLabel;
+
+ property._groupingLabel = property._label;
+ property._reverseGroupingLabel = property._reverseLabel;
+
+ this._properties[propertyID] = property;
+
+ this._propertyArray = null;
+ return property;
+ } else {
+ return this._properties[propertyID];
+ }
+};
+
+Exhibit.Database._indexPut = function(index, x, y, z) {
+ var hash = index[x];
+ if (!hash) {
+ hash = {};
+ index[x] = hash;
+ }
+
+ var array = hash[y];
+ if (!array) {
+ array = new Array();
+ hash[y] = array;
+ } else {
+ for (var i = 0; i < array.length; i++) {
+ if (z == array[i]) {
+ return;
+ }
+ }
+ }
+ array.push(z);
+};
+
+Exhibit.Database._indexPutList = function(index, x, y, list) {
+ var hash = index[x];
+ if (!hash) {
+ hash = {};
+ index[x] = hash;
+ }
+
+ var array = hash[y];
+ if (!array) {
+ hash[y] = list;
+ } else {
+ hash[y] = hash[y].concat(list);
+ }
+};
+
+Exhibit.Database._indexRemove = function(index, x, y, z) {
+ function isEmpty(obj) {
+ for (p in obj) { return false; }
+ return true;
+ }
+
+ var hash = index[x];
+ if (!hash) {
+ return false;
+ }
+
+ var array = hash[y];
+ if (!array) {
+ return false;
+ }
+
+ for (var i = 0; i < array.length; i++) {
+ if (z == array[i]) {
+ array.splice(i, 1);
+
+ // prevent accumulation of empty arrays/hashes in indices
+ if (array.length == 0) {
+ delete hash[y];
+
+ if (isEmpty(hash)) {
+ delete index[x];
+ }
+ }
+ return true;
+ }
+ }
+};
+
+Exhibit.Database._indexRemoveList = function(index, x, y) {
+ var hash = index[x];
+ if (!hash) {
+ return null;
+ }
+
+ var array = hash[y];
+ if (!array) {
+ return null;
+ }
+
+ delete hash[y];
+ return array;
+};
+
+Exhibit.Database._Impl.prototype._indexFillSet = function(index, x, y, set, filter) {
+ var hash = index[x];
+ if (hash) {
+ var array = hash[y];
+ if (array) {
+ if (filter) {
+ for (var i = 0; i < array.length; i++) {
+ var z = array[i];
+ if (filter.contains(z)) {
+ set.add(z);
+ }
+ }
+ } else {
+ for (var i = 0; i < array.length; i++) {
+ set.add(array[i]);
+ }
+ }
+ }
+ }
+};
+
+Exhibit.Database._Impl.prototype._indexCountDistinct = function(index, x, y, filter) {
+ var count = 0;
+ var hash = index[x];
+ if (hash) {
+ var array = hash[y];
+ if (array) {
+ if (filter) {
+ for (var i = 0; i < array.length; i++) {
+ if (filter.contains(array[i])) {
+ count++;
+ }
+ }
+ } else {
+ count = array.length;
+ }
+ }
+ }
+ return count;
+};
+
+Exhibit.Database._Impl.prototype._get = function(index, x, y, set, filter) {
+ if (!set) {
+ set = new Exhibit.Set();
+ }
+ this._indexFillSet(index, x, y, set, filter);
+ return set;
+};
+
+Exhibit.Database._Impl.prototype._getUnion = function(index, xSet, y, set, filter) {
+ if (!set) {
+ set = new Exhibit.Set();
+ }
+
+ var database = this;
+ xSet.visit(function(x) {
+ database._indexFillSet(index, x, y, set, filter);
+ });
+ return set;
+};
+
+Exhibit.Database._Impl.prototype._countDistinctUnion = function(index, xSet, y, filter) {
+ var count = 0;
+ var database = this;
+ xSet.visit(function(x) {
+ count += database._indexCountDistinct(index, x, y, filter);
+ });
+ return count;
+};
+
+Exhibit.Database._Impl.prototype._countDistinct = function(index, x, y, filter) {
+ return this._indexCountDistinct(index, x, y, filter);
+};
+
+Exhibit.Database._Impl.prototype._getProperties = function(index, x) {
+ var hash = index[x];
+ var properties = []
+ if (hash) {
+ for (var p in hash) {
+ properties.push(p);
+ }
+ }
+ return properties;
+};
+
+Exhibit.Database._Impl.prototype.getObjects = function(s, p, set, filter) {
+ return this._get(this._spo, s, p, set, filter);
+};
+
+Exhibit.Database._Impl.prototype.countDistinctObjects = function(s, p, filter) {
+ return this._countDistinct(this._spo, s, p, filter);
+};
+
+Exhibit.Database._Impl.prototype.getObjectsUnion = function(subjects, p, set, filter) {
+ return this._getUnion(this._spo, subjects, p, set, filter);
+};
+
+Exhibit.Database._Impl.prototype.countDistinctObjectsUnion = function(subjects, p, filter) {
+ return this._countDistinctUnion(this._spo, subjects, p, filter);
+};
+
+Exhibit.Database._Impl.prototype.getSubjects = function(o, p, set, filter) {
+ return this._get(this._ops, o, p, set, filter);
+};
+
+Exhibit.Database._Impl.prototype.countDistinctSubjects = function(o, p, filter) {
+ return this._countDistinct(this._ops, o, p, filter);
+};
+
+Exhibit.Database._Impl.prototype.getSubjectsUnion = function(objects, p, set, filter) {
+ return this._getUnion(this._ops, objects, p, set, filter);
+};
+
+Exhibit.Database._Impl.prototype.countDistinctSubjectsUnion = function(objects, p, filter) {
+ return this._countDistinctUnion(this._ops, objects, p, filter);
+};
+
+Exhibit.Database._Impl.prototype.getObject = function(s, p) {
+ var hash = this._spo[s];
+ if (hash) {
+ var array = hash[p];
+ if (array) {
+ return array[0];
+ }
+ }
+ return null;
+};
+
+Exhibit.Database._Impl.prototype.getSubject = function(o, p) {
+ var hash = this._ops[o];
+ if (hash) {
+ var array = hash[p];
+ if (array) {
+ return array[0];
+ }
+ }
+ return null;
+};
+
+Exhibit.Database._Impl.prototype.getForwardProperties = function(s) {
+ return this._getProperties(this._spo, s);
+};
+
+Exhibit.Database._Impl.prototype.getBackwardProperties = function(o) {
+ return this._getProperties(this._ops, o);
+};
+
+Exhibit.Database._Impl.prototype.getSubjectsInRange = function(p, min, max, inclusive, set, filter) {
+ var property = this.getProperty(p);
+ if (property != null) {
+ var rangeIndex = property.getRangeIndex();
+ if (rangeIndex != null) {
+ return rangeIndex.getSubjectsInRange(min, max, inclusive, set, filter);
+ }
+ }
+ return (!set) ? new Exhibit.Set() : set;
+};
+
+Exhibit.Database._Impl.prototype.getTypeIDs = function(set) {
+ return this.getObjectsUnion(set, "type", null, null);
+};
+
+Exhibit.Database._Impl.prototype.addStatement = function(s, p, o) {
+ var indexPut = Exhibit.Database._indexPut;
+ indexPut(this._spo, s, p, o);
+ indexPut(this._ops, o, p, s);
+};
+
+Exhibit.Database._Impl.prototype.removeStatement = function(s, p, o) {
+ var indexRemove = Exhibit.Database._indexRemove;
+ var removedObject = indexRemove(this._spo, s, p, o);
+ var removedSubject = indexRemove(this._ops, o, p, s);
+ return removedObject || removedSubject;
+};
+
+Exhibit.Database._Impl.prototype.removeObjects = function(s, p) {
+ var indexRemove = Exhibit.Database._indexRemove;
+ var indexRemoveList = Exhibit.Database._indexRemoveList;
+ var objects = indexRemoveList(this._spo, s, p);
+ if (objects == null) {
+ return false;
+ } else {
+ for (var i = 0; i < objects.length; i++) {
+ indexRemove(this._ops, objects[i], p, s);
+ }
+ return true;
+ }
+};
+
+Exhibit.Database._Impl.prototype.removeSubjects = function(o, p) {
+ var indexRemove = Exhibit.Database._indexRemove;
+ var indexRemoveList = Exhibit.Database._indexRemoveList;
+ var subjects = indexRemoveList(this._ops, o, p);
+ if (subjects == null) {
+ return false;
+ } else {
+ for (var i = 0; i < subjects.length; i++) {
+ indexRemove(this._spo, subjects[i], p, o);
+ }
+ return true;
+ }
+};
+
+Exhibit.Database._Impl.prototype.removeAllStatements = function() {
+ this._listeners.fire("onBeforeRemovingAllStatements", []);
+ try {
+ this._spo = {};
+ this._ops = {};
+ this._items = new Exhibit.Set();
+
+ for (var propertyID in this._properties) {
+ this._properties[propertyID]._onNewData();
+ }
+ this._propertyArray = null;
+
+ this._listeners.fire("onAfterRemovingAllStatements", []);
+ } catch(e) {
+ SimileAjax.Debug.exception(e, "Database.removeAllStatements failed");
+ }
+};
+
+/*==================================================
+ * Exhibit.Database._Type
+ *==================================================
+ */
+Exhibit.Database._Type = function(id) {
+ this._id = id;
+ this._custom = {};
+};
+
+Exhibit.Database._Type.prototype = {
+ getID: function() { return this._id; },
+ getURI: function() { return this._custom["uri"]; },
+ getLabel: function() { return this._custom["label"]; },
+ getOrigin: function() { return this._custom["origin"]; },
+ getProperty: function(p) { return this._custom[p]; }
+};
+
+/*==================================================
+ * Exhibit.Database._Property
+ *==================================================
+ */
+Exhibit.Database._Property = function(id, database) {
+ this._id = id;
+ this._database = database;
+ this._rangeIndex = null;
+};
+
+Exhibit.Database._Property.prototype = {
+ getID: function() { return this._id; },
+ getURI: function() { return this._uri; },
+ getValueType: function() { return this._valueType; },
+
+ getLabel: function() { return this._label; },
+ getPluralLabel: function() { return this._pluralLabel; },
+ getReverseLabel: function() { return this._reverseLabel; },
+ getReversePluralLabel: function() { return this._reversePluralLabel; },
+ getGroupingLabel: function() { return this._groupingLabel; },
+ getGroupingPluralLabel: function() { return this._groupingPluralLabel; },
+ getOrigin: function() { return this._origin; }
+};
+
+Exhibit.Database._Property.prototype._onNewData = function() {
+ this._rangeIndex = null;
+};
+
+Exhibit.Database._Property.prototype.getRangeIndex = function() {
+ if (this._rangeIndex == null) {
+ this._buildRangeIndex();
+ }
+ return this._rangeIndex;
+};
+
+Exhibit.Database._Property.prototype._buildRangeIndex = function() {
+ var getter;
+ var database = this._database;
+ var p = this._id;
+
+ switch (this.getValueType()) {
+ case "currency":
+ case "number":
+ getter = function(item, f) {
+ database.getObjects(item, p, null, null).visit(function(value) {
+ if (typeof value != "number") {
+ value = parseFloat(value);
+ }
+ if (!isNaN(value)) {
+ f(value);
+ }
+ });
+ };
+ break;
+ case "date":
+ getter = function(item, f) {
+ database.getObjects(item, p, null, null).visit(function(value) {
+ if (value != null && !(value instanceof Date)) {
+ value = SimileAjax.DateTime.parseIso8601DateTime(value);
+ }
+ if (value instanceof Date) {
+ f(value.getTime());
+ }
+ });
+ };
+ break;
+ default:
+ getter = function(item, f) {};
+ }
+
+ this._rangeIndex = new Exhibit.Database._RangeIndex(
+ this._database.getAllItems(),
+ getter
+ );
+};
+
+/*==================================================
+ * Exhibit.Database._RangeIndex
+ *==================================================
+ */
+Exhibit.Database._RangeIndex = function(items, getter) {
+ pairs = [];
+ items.visit(function(item) {
+ getter(item, function(value) {
+ pairs.push({ item: item, value: value });
+ });
+ });
+
+ pairs.sort(function(p1, p2) {
+ var c = p1.value - p2.value;
+ return (isNaN(c) === false) ? c : p1.value.localeCompare(p2.value);
+ });
+
+ this._pairs = pairs;
+};
+
+Exhibit.Database._RangeIndex.prototype.getCount = function() {
+ return this._pairs.length;
+};
+
+Exhibit.Database._RangeIndex.prototype.getMin = function() {
+ return this._pairs.length > 0 ?
+ this._pairs[0].value :
+ Number.POSITIVE_INFINITY;
+};
+
+Exhibit.Database._RangeIndex.prototype.getMax = function() {
+ return this._pairs.length > 0 ?
+ this._pairs[this._pairs.length - 1].value :
+ Number.NEGATIVE_INFINITY;
+};
+
+Exhibit.Database._RangeIndex.prototype.getRange = function(visitor, min, max, inclusive) {
+ var startIndex = this._indexOf(min);
+ var pairs = this._pairs;
+ var l = pairs.length;
+
+ inclusive = (inclusive);
+ while (startIndex < l) {
+ var pair = pairs[startIndex++];
+ var value = pair.value;
+ if (value < max || (value == max && inclusive)) {
+ visitor(pair.item);
+ } else {
+ break;
+ }
+ }
+};
+
+Exhibit.Database._RangeIndex.prototype.getSubjectsInRange = function(min, max, inclusive, set, filter) {
+ if (!set) {
+ set = new Exhibit.Set();
+ }
+
+ var f = (filter != null) ?
+ function(item) {
+ if (filter.contains(item)) {
+ set.add(item);
+ }
+ } :
+ function(item) {
+ set.add(item);
+ };
+
+ this.getRange(f, min, max, inclusive);
+
+ return set;
+};
+
+Exhibit.Database._RangeIndex.prototype.countRange = function(min, max, inclusive) {
+ var startIndex = this._indexOf(min);
+ var endIndex = this._indexOf(max);
+
+ if (inclusive) {
+ var pairs = this._pairs;
+ var l = pairs.length;
+ while (endIndex < l) {
+ if (pairs[endIndex].value == max) {
+ endIndex++;
+ } else {
+ break;
+ }
+ }
+ }
+ return endIndex - startIndex;
+};
+
+Exhibit.Database._RangeIndex.prototype._indexOf = function(v) {
+ var pairs = this._pairs;
+ if (pairs.length == 0 || pairs[0].value >= v) {
+ return 0;
+ }
+
+ var from = 0;
+ var to = pairs.length;
+ while (from + 1 < to) {
+ var middle = (from + to) >> 1;
+ var v2 = pairs[middle].value;
+ if (v2 >= v) {
+ to = middle;
+ } else {
+ from = middle;
+ }
+ }
+
+ return to;
+};
+
+
+//=============================================================================
+// Editable Database Support
+//=============================================================================
+
+Exhibit.Database._Impl.prototype.isNewItem = function(id) {
+ return id in this._newItems;
+}
+
+Exhibit.Database._Impl.prototype.getItem = function(id) {
+ var item = { id: id };
+ var properties = this.getAllProperties();
+ for (var i in properties) {
+ var prop = properties[i];
+ var val = this.getObject(id, prop);
+ if ( val ) {
+ item[prop] = val
+ }
+ }
+ return item;
+}
+
+Exhibit.Database._Impl.prototype.addItem = function(item) {
+ if ( !item.id ) {
+ item.id = item.label
+ }
+ if (!item.modified) {
+ item.modified = "yes";
+ }
+
+ this._ensurePropertyExists(Exhibit.Database.TimestampPropertyName);
+ item[Exhibit.Database.TimestampPropertyName] = Exhibit.Database.makeISO8601DateString();
+
+ this.loadItems([item], '');
+
+ this._newItems[item.id] = true;
+
+ this._listeners.fire('onAfterLoadingItems', []);
+}
+
+// TODO: cleanup item editing logic
+Exhibit.Database._Impl.prototype.editItem = function(id, prop, value) {
+ if (prop.toLowerCase() == 'id') {
+ Exhibit.UI.showHelp("We apologize, but changing the IDs of items in the Exhibit isn't supported at the moment.");
+ return;
+ }
+
+ var prevValue = this.getObject(id, prop);
+
+ this._originalValues[id] = this._originalValues[id] || {};
+ this._originalValues[id][prop] = this._originalValues[id][prop] || prevValue;
+
+ var origVal = this._originalValues[id][prop];
+
+ if (origVal == value) {
+ this.removeObjects(id, "modified");
+ this.addStatement(id, "modified", 'no');
+ delete this._originalValues[id][prop];
+ } else if (this.getObject(id, "modified") != "yes") {
+ this.removeObjects(id, "modified");
+ this.addStatement(id, "modified", "yes");
+ }
+
+ this.removeObjects(id, prop);
+ this.addStatement(id, prop, value);
+
+ var propertyObject = this._ensurePropertyExists(prop);
+ propertyObject._onNewData();
+
+ this._listeners.fire('onAfterLoadingItems', []);
+}
+
+Exhibit.Database._Impl.prototype.removeItem = function(id) {
+ if (!this.containsItem(id)) {
+ throw "Removing non-existent item " + id;
+ }
+
+ this._items.remove(id);
+ delete this._spo[id];
+
+ if (this._newItems[id]) {
+ delete this._newItems[id];
+ }
+
+ if (this._originalValues[id]) {
+ delete this._originalValues[id];
+ }
+
+ var properties = this.getAllProperties();
+ for (var i in properties) {
+ var prop = properties[i];
+ this.removeObjects(id, prop);
+ }
+
+ this._listeners.fire('onAfterLoadingItems', []);
+};
+
+Exhibit.Database.defaultIgnoredProperties = ['uri', 'modified'];
+
+// this makes all changes become "permanent"
+// i.e. after change set is committed to server
+Exhibit.Database._Impl.prototype.fixAllChanges = function() {
+ this._originalValues = {};
+ this._newItems = {};
+
+ var items = this._items.toArray();
+ for (var i in items) {
+ var id = items[i];
+ this.removeObjects(id, "modified");
+ this.addStatement(id, "modified", "no");
+ }
+};
+
+Exhibit.Database._Impl.prototype.fixChangesForItem = function(id) {
+ delete this._originalValues[id];
+ delete this._newItems[id];
+
+ this.removeObjects(id, "modified");
+ this.addStatement(id, "modified", "no");
+};
+
+Exhibit.Database._Impl.prototype.collectChangesForItem = function(id, ignoredProperties) {
+ ignoredProperties = ignoredProperties || Exhibit.Database.defaultIgnoredProperties;
+
+ var type = this.getObject(id, 'type');
+ var label = this.getObject(id, 'label') || id;
+ var item = { id: id, label: label, type: type, vals: {} };
+
+ if (id in this._newItems) {
+ item.changeType = 'added';
+
+ var properties = this.getAllProperties();
+
+ for (var i in properties) {
+ var prop = properties[i];
+ if (ignoredProperties.indexOf(prop) != -1) { continue; }
+
+ var val = this.getObject(id, prop);
+ if (val) {
+ item.vals[prop] = { newVal: val }
+ }
+ }
+ } else if (id in this._originalValues && !this.isSubmission(id)) {
+ item.changeType = 'modified';
+ var vals = this._originalValues[id];
+ var hasModification = false;
+
+ for (var prop in vals) {
+ if (ignoredProperties.indexOf(prop) != -1) { continue; }
+
+ hasModification = true;
+ var oldVal = this._originalValues[id][prop];
+ var newVal = this.getObject(id, prop);
+
+ if (!newVal) {
+ SimileAjax.Debug.warn('empty value for ' + id + ', ' + prop)
+ } else {
+ item.vals[prop] = { oldVal: oldVal, newVal: newVal };
+ }
+ }
+
+ if (!hasModification) return null;
+ } else {
+ return null;
+ }
+
+ if (!item[Exhibit.Database.TimestampPropertyName]) {
+ item[Exhibit.Database.TimestampPropertyName] = Exhibit.Database.makeISO8601DateString();
+ }
+
+ return item;
+}
+
+Exhibit.Database._Impl.prototype.collectAllChanges = function(ignoredProperties) {
+ var ret = [];
+ var items = this._items.toArray();
+
+ for (var i in items) {
+ var id = items[i];
+ var item = this.collectChangesForItem(id, ignoredProperties);
+ if (item) {
+ ret.push(item);
+ }
+ }
+
+ return ret;
+}
+
+//=============================================================================
+// Submissions Support
+//=============================================================================
+
+Exhibit.Database._Impl.prototype.mergeSubmissionIntoItem = function(submissionID) {
+ var db = this;
+
+ if (!this.isSubmission(submissionID)){
+ throw submissionID + " is not a submission!";
+ }
+
+ var change = this.getObject(submissionID, 'change');
+ if (change == 'modification') {
+ var itemID = this.getObject(submissionID, 'changedItem');
+ var vals = this._spo[submissionID];
+
+ SimileAjax.jQuery.each(vals, function(attr, val) {
+ if (Exhibit.Database.defaultIgnoredSubmissionProperties.indexOf(attr) != -1) {
+ return;
+ }
+
+ if (val.length == 1) {
+ db.editItem(itemID, attr, val[0]);
+ } else {
+ SimileAjax.Debug.warn("Exhibit.Database._Impl.prototype.commitChangeToItem cannot handle " +
+ "multiple values for attribute " + attr + ": " + val);
+ }
+ });
+ delete this._submissionRegistry[submissionID];
+
+ } else if (change == 'addition') {
+ delete this._submissionRegistry[submissionID];
+ this._newItems[submissionID] = true;
+ } else {
+ throw "unknown change type " + change;
+ }
+ this._listeners.fire('onAfterLoadingItems', []);
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/bibtex-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/bibtex-exporter.js
new file mode 100644
index 00000000..4c66ae66
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/bibtex-exporter.js
@@ -0,0 +1,78 @@
+/*==================================================
+ * Exhibit.BibtexExporter
+ *==================================================
+ */
+
+Exhibit.BibtexExporter = {
+ getLabel: function() {
+ return "Bibtex";
+ },
+ _excludeProperties: {
+ "pub-type" : true,
+ "type" : true,
+ "uri" : true,
+ "key" : true
+ }
+};
+
+Exhibit.BibtexExporter.exportOne = function(itemID, database) {
+ return Exhibit.BibtexExporter._wrap(
+ Exhibit.BibtexExporter._exportOne(itemID, database));
+};
+
+Exhibit.BibtexExporter.exportMany = function(set, database) {
+ var s = "";
+ set.visit(function(itemID) {
+ s += Exhibit.BibtexExporter._exportOne(itemID, database) + "\n";
+ });
+ return Exhibit.BibtexExporter._wrap(s);
+};
+
+Exhibit.BibtexExporter._exportOne = function(itemID, database) {
+ var s = "";
+ var type = database.getObject(itemID, "pub-type");
+
+ var key = database.getObject(itemID, "key");
+ key = (key != null ? key : itemID);
+ key = key.replace(/[\s,]/g, "-");
+ s += "@" + type + "{" + key + ",\n";
+
+ var allProperties = database.getAllProperties();
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var values = database.getObjects(itemID, propertyID);
+ var valueType = property.getValueType();
+
+ if (values.size() > 0 && !(propertyID in Exhibit.BibtexExporter._excludeProperties)) {
+ s += "\t" + (propertyID == "label" ? "title" : propertyID) + " = \"";
+
+ var strings;
+ if (valueType == "item") {
+ strings = [];
+ values.visit(function(value) {
+ strings.push(database.getObject(value, "label"));
+ });
+ } else {
+ if (valueType == "url") {
+ strings = [];
+ values.visit(function(value) {
+ strings.push(Exhibit.Persistence.resolveURL(value));
+ });
+ } else {
+ strings = values.toArray();
+ }
+ }
+
+ s += strings.join(" and ") + "\",\n";
+ }
+ }
+ s += "\torigin = \"" + Exhibit.Persistence.getItemLink(itemID) + "\"\n";
+ s += "}\n";
+
+ return s;
+};
+
+Exhibit.BibtexExporter._wrap = function(s) {
+ return s;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/exhibit-json-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/exhibit-json-exporter.js
new file mode 100644
index 00000000..271b1dda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/exhibit-json-exporter.js
@@ -0,0 +1,93 @@
+/*==================================================
+ * Exhibit.ExhibitJsonExporter
+ *==================================================
+ */
+
+Exhibit.ExhibitJsonExporter = {
+ getLabel: function() {
+ return Exhibit.l10n.exhibitJsonExporterLabel;
+ }
+};
+
+Exhibit.ExhibitJsonExporter.exportOne = function(itemID, database) {
+ return Exhibit.ExhibitJsonExporter._wrap(
+ Exhibit.ExhibitJsonExporter._exportOne(itemID, database) + "\n");
+};
+
+Exhibit.ExhibitJsonExporter.exportMany = function(set, database) {
+ var s = "";
+ var size = set.size();
+ var count = 0;
+ set.visit(function(itemID) {
+ s += Exhibit.ExhibitJsonExporter._exportOne(itemID, database) + ((count++ < size - 1) ? ",\n" : "\n");
+ });
+ return Exhibit.ExhibitJsonExporter._wrap(s);
+};
+
+Exhibit.ExhibitJsonExporter._exportOne = function(itemID, database) {
+ function quote(s) {
+ if (/[\\\x00-\x1F\x22]/.test(s)) {
+ return '"' + s.replace(/([\\\x00-\x1f\x22])/g, function(a, b) {
+ var c = { '\b':'\\b', '\t':'\\t', '\n':'\\n', '\f':'\\f',
+ '\r':'\\r', '"':'\\"', '\\':'\\\\' }[b];
+ if (c) {
+ return c;
+ }
+ c = b.charCodeAt();
+ return '\\x' +
+ Math.floor(c / 16).toString(16) +
+ (c % 16).toString(16);
+ }) + '"';
+ }
+ return '"' + s + '"';
+ }
+ var s = "";
+ var uri = database.getObject(itemID, "uri");
+
+ s += " {\"id\":" + quote(itemID) + ",\n";
+
+ var allProperties = database.getAllProperties();
+
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var values = database.getObjects(itemID, propertyID);
+ var valueType = property.getValueType();
+
+ if (values.size() > 0) {
+ var array;
+ if (valueType == "url") {
+ array = [];
+ values.visit(function(value) {
+ array.push(Exhibit.Persistence.resolveURL(value));
+ });
+ } else {
+ array = values.toArray();
+ }
+
+ s += " " + quote(propertyID) + ":";
+ if (array.length == 1) {
+ s += quote(array[0]);
+ } else {
+ s += "[";
+ for (var j = 0; j < array.length; j++) {
+ s += (j > 0 ? "," : "") + quote(array[j]);
+ }
+ s += "]";
+ }
+ s += ",\n";
+ }
+ }
+ s += " \"origin\":"+ quote(Exhibit.Persistence.getItemLink(itemID)) +"\n";
+ s += " }";
+
+ return s;
+};
+
+Exhibit.ExhibitJsonExporter._wrap = function(s) {
+ return "{\n" +
+ " \"items\":[\n" +
+ s +
+ " ]\n" +
+ "}";
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/facet-selection-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/facet-selection-exporter.js
new file mode 100644
index 00000000..17aadd3a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/facet-selection-exporter.js
@@ -0,0 +1,27 @@
+/*==================================================
+ * Exhibit.FacetSelectionExporter
+ *==================================================
+ */
+
+Exhibit.FacetSelectionExporter = {
+ getLabel: function() {
+ return "Facet Selections";
+ },
+ exportOne: function(itemID, database) {
+ return Exhibit.FacetSelectionExporter._exportUrl();
+ },
+ exportMany: function(set, database) {
+ return Exhibit.FacetSelectionExporter._exportUrl();
+ }
+};
+
+Exhibit.FacetSelectionExporter._exportUrl = function() {
+ var currentSettings = window.exhibit.exportSettings();
+ var url = window.location.href.split('?')[0] + '?';
+ var sep = '';
+ for(id in currentSettings) {
+ url += sep + id + '=' + escape(currentSettings[id]);
+ if (sep === '') sep = '&';
+ }
+ return url;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/rdf-xml-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/rdf-xml-exporter.js
new file mode 100644
index 00000000..2e22a479
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/rdf-xml-exporter.js
@@ -0,0 +1,99 @@
+/*==================================================
+ * Exhibit.RdfXmlExporter
+ *==================================================
+ */
+
+Exhibit.RdfXmlExporter = {
+ getLabel: function() {
+ return Exhibit.l10n.rdfXmlExporterLabel;
+ }
+};
+
+Exhibit.RdfXmlExporter.exportOne = function(itemID, database) {
+ var propertyIDToQualifiedName = {};
+ var prefixToBase = {};
+ database.getNamespaces(propertyIDToQualifiedName, prefixToBase);
+
+ return Exhibit.RdfXmlExporter._wrapRdf(
+ Exhibit.RdfXmlExporter._exportOne(
+ itemID,
+ database,
+ propertyIDToQualifiedName,
+ prefixToBase
+ ),
+ prefixToBase
+ );
+};
+
+Exhibit.RdfXmlExporter.exportMany = function(set, database) {
+ var s = "";
+
+ var propertyIDToQualifiedName = {};
+ var prefixToBase = {};
+ database.getNamespaces(propertyIDToQualifiedName, prefixToBase);
+
+ set.visit(function(itemID) {
+ s += Exhibit.RdfXmlExporter._exportOne(
+ itemID,
+ database,
+ propertyIDToQualifiedName,
+ prefixToBase
+ ) + "\n";
+ });
+ return Exhibit.RdfXmlExporter._wrapRdf(s, prefixToBase);
+};
+
+Exhibit.RdfXmlExporter._exportOne = function(itemID, database, propertyIDToQualifiedName, prefixToBase) {
+ var s = "";
+ var uri = database.getObject(itemID, "uri");
+ s += "<rdf:Description rdf:about='" + uri + "'>\n"
+
+ var allProperties = database.getAllProperties();
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var values = database.getObjects(itemID, propertyID);
+ var valueType = property.getValueType();
+
+ var propertyString;
+ if (propertyID in propertyIDToQualifiedName) {
+ var qname = propertyIDToQualifiedName[propertyID];
+ propertyString = qname.prefix + ":" + qname.localName;
+ } else {
+ propertyString = property.getURI();
+ }
+
+ if (valueType == "item") {
+ values.visit(function(value) {
+ s += "\t<" + propertyString + " rdf:resource='" + value + "' />\n";
+ });
+ } else if (propertyID != "uri") {
+ if (valueType == "url") {
+ values.visit(function(value) {
+ s += "\t<" + propertyString + ">" + Exhibit.Persistence.resolveURL(value) + "</" + propertyString + ">\n";
+ });
+ } else {
+ values.visit(function(value) {
+ s += "\t<" + propertyString + ">" + value + "</" + propertyString + ">\n";
+ });
+ }
+ }
+ }
+ s += "\t<exhibit:origin>" + Exhibit.Persistence.getItemLink(itemID) + "</exhibit:origin>\n";
+
+ s += "</rdf:Description>";
+ return s;
+};
+
+Exhibit.RdfXmlExporter._wrapRdf = function(s, prefixToBase) {
+ var s2 = "<?xml version = '1.0'?>\n" +
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n" +
+ "\txmlns:exhibit='http://simile.mit.edu/2006/11/exhibit#'";
+
+ for (prefix in prefixToBase) {
+ s2 += "\n\txmlns:" + prefix + "='" + prefixToBase[prefix] + "'";
+ }
+
+ s2 += ">\n" + s + "\n</rdf:RDF>";
+ return s2;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/semantic-wikitext-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/semantic-wikitext-exporter.js
new file mode 100644
index 00000000..0f58e98d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/semantic-wikitext-exporter.js
@@ -0,0 +1,61 @@
+/*==================================================
+ * Exhibit.SemanticWikitextExporter
+ *==================================================
+ */
+
+Exhibit.SemanticWikitextExporter = {
+ getLabel: function() {
+ return Exhibit.l10n.smwExporterLabel;
+ }
+};
+
+Exhibit.SemanticWikitextExporter.exportOne = function(itemID, database) {
+ return Exhibit.SemanticWikitextExporter._wrap(
+ Exhibit.SemanticWikitextExporter._exportOne(itemID, database));
+};
+
+Exhibit.SemanticWikitextExporter.exportMany = function(set, database) {
+ var s = "";
+ set.visit(function(itemID) {
+ s += Exhibit.SemanticWikitextExporter._exportOne(itemID, database) + "\n";
+ });
+ return Exhibit.SemanticWikitextExporter._wrap(s);
+};
+
+Exhibit.SemanticWikitextExporter._exportOne = function(itemID, database) {
+ var s = "";
+ var uri = database.getObject(itemID, "uri");
+ s += uri + "\n"
+
+ var allProperties = database.getAllProperties();
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var values = database.getObjects(itemID, propertyID);
+ var valueType = property.getValueType();
+
+ if (valueType == "item") {
+ values.visit(function(value) {
+ s += "[[" + propertyID + "::" + value + "]]\n";
+ });
+ } else {
+ if (valueType == "url") {
+ values.visit(function(value) {
+ s += "[[" + propertyID + ":=" + Exhibit.Persistence.resolveURL(value) + "]]\n";
+ });
+ } else {
+ values.visit(function(value) {
+ s += "[[" + propertyID + ":=" + value + "]]\n";
+ });
+ }
+ }
+ }
+ s += "[[origin:=" + Exhibit.Persistence.getItemLink(itemID) + "]]\n";
+
+ s += "\n";
+ return s;
+};
+
+Exhibit.SemanticWikitextExporter._wrap = function(s) {
+ return s;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/tsv-exporter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/tsv-exporter.js
new file mode 100644
index 00000000..e49b3d87
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/exporters/tsv-exporter.js
@@ -0,0 +1,53 @@
+/*==================================================
+ * Exhibit.TSVExporter
+ *==================================================
+ */
+
+Exhibit.TSVExporter = {
+ getLabel: function() {
+ return Exhibit.l10n.tsvExporterLabel;
+ }
+};
+
+Exhibit.TSVExporter.exportOne = function(itemID, database) {
+ return Exhibit.TSVExporter._wrap(
+ Exhibit.TSVExporter._exportOne(itemID, database), database);
+};
+
+Exhibit.TSVExporter.exportMany = function(set, database) {
+ var s = "";
+ set.visit(function(itemID) {
+ s += Exhibit.TSVExporter._exportOne(itemID, database) + "\n";
+ });
+ return Exhibit.TSVExporter._wrap(s, database);
+};
+
+Exhibit.TSVExporter._exportOne = function(itemID, database) {
+ var s = "";
+
+ var allProperties = database.getAllProperties();
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var values = database.getObjects(itemID, propertyID);
+ var valueType = property.getValueType();
+
+ s += values.toArray().join("; ") + "\t";
+ }
+
+ return s;
+};
+
+Exhibit.TSVExporter._wrap = function(s, database) {
+ var header = "";
+
+ var allProperties = database.getAllProperties();
+ for (var i = 0; i < allProperties.length; i++) {
+ var propertyID = allProperties[i];
+ var property = database.getProperty(propertyID);
+ var valueType = property.getValueType();
+ header += propertyID + ":" + valueType + "\t";
+ }
+
+ return header + "\n" + s;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression-parser.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression-parser.js
new file mode 100644
index 00000000..3f89b945
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression-parser.js
@@ -0,0 +1,345 @@
+/*==================================================
+ * Exhibit.ExpressionParser
+ * http://simile.mit.edu/wiki/Exhibit/API/ExpressionParser
+ *==================================================
+ */
+Exhibit.ExpressionParser = new Object();
+
+Exhibit.ExpressionParser.parse = function(s, startIndex, results) {
+ startIndex = startIndex || 0;
+ results = results || {};
+
+ var scanner = new Exhibit.ExpressionScanner(s, startIndex);
+ try {
+ return Exhibit.ExpressionParser._internalParse(scanner, false);
+ } finally {
+ results.index = scanner.token() != null ? scanner.token().start : scanner.index();
+ }
+};
+
+Exhibit.ExpressionParser.parseSeveral = function(s, startIndex, results) {
+ startIndex = startIndex || 0;
+ results = results || {};
+
+ var scanner = new Exhibit.ExpressionScanner(s, startIndex);
+ try {
+ return Exhibit.ExpressionParser._internalParse(scanner, true);
+ } finally {
+ results.index = scanner.token() != null ? scanner.token().start : scanner.index();
+ }
+};
+
+Exhibit.ExpressionParser._internalParse = function(scanner, several) {
+ var Scanner = Exhibit.ExpressionScanner;
+ var token = scanner.token();
+ var next = function() { scanner.next(); token = scanner.token(); };
+ var makePosition = function() { return token != null ? token.start : scanner.index(); };
+
+ var parsePath = function() {
+ var path = new Exhibit.Expression.Path();
+ while (token != null && token.type == Scanner.PATH_OPERATOR) {
+ var hopOperator = token.value;
+ next();
+
+ if (token != null && token.type == Scanner.IDENTIFIER) {
+ path.appendSegment(token.value, hopOperator);
+ next();
+
+ } else {
+ throw new Error("Missing property ID at position " + makePosition());
+ }
+ }
+ return path;
+ };
+ var parseFactor = function() {
+ if (token == null) {
+ throw new Error("Missing factor at end of expression");
+ }
+
+ var result = null;
+
+ switch (token.type) {
+ case Scanner.NUMBER:
+ result = new Exhibit.Expression._Constant(token.value, "number");
+ next();
+ break;
+ case Scanner.STRING:
+ result = new Exhibit.Expression._Constant(token.value, "text");
+ next();
+ break;
+ case Scanner.PATH_OPERATOR:
+ result = parsePath();
+ break;
+ case Scanner.IDENTIFIER:
+ var identifier = token.value;
+ next();
+
+ if (identifier in Exhibit.Controls) {
+ if (token != null && token.type == Scanner.DELIMITER && token.value == "(") {
+ next();
+
+ var args = (token != null && token.type == Scanner.DELIMITER && token.value == ")") ?
+ [] :
+ parseExpressionList();
+
+ result = new Exhibit.Expression._ControlCall(identifier, args);
+
+ if (token != null && token.type == Scanner.DELIMITER && token.value == ")") {
+ next();
+ } else {
+ throw new Error("Missing ) to end " + identifier + " at position " + makePosition());
+ }
+ } else {
+ throw new Error("Missing ( to start " + identifier + " at position " + makePosition());
+ }
+ } else {
+ if (token != null && token.type == Scanner.DELIMITER && token.value == "(") {
+ next();
+
+ var args = (token != null && token.type == Scanner.DELIMITER && token.value == ")") ?
+ [] :
+ parseExpressionList();
+
+ result = new Exhibit.Expression._FunctionCall(identifier, args);
+
+ if (token != null && token.type == Scanner.DELIMITER && token.value == ")") {
+ next();
+ } else {
+ throw new Error("Missing ) after function call " + identifier + " at position " + makePosition());
+ }
+ } else {
+ result = parsePath();
+ result.setRootName(identifier);
+ }
+ }
+ break;
+ case Scanner.DELIMITER:
+ if (token.value == "(") {
+ next();
+
+ result = parseExpression();
+ if (token != null && token.type == Scanner.DELIMITER && token.value == ")") {
+ next();
+ break;
+ } else {
+ throw new Error("Missing ) at position " + makePosition());
+ }
+ } // else, fall through
+ default:
+ throw new Error("Unexpected text " + token.value + " at position " + makePosition());
+ }
+
+ return result;
+ };
+ var parseTerm = function() {
+ var term = parseFactor();
+ while (token != null && token.type == Scanner.OPERATOR &&
+ (token.value == "*" || token.value == "/")) {
+ var operator = token.value;
+ next();
+
+ term = new Exhibit.Expression._Operator(operator, [ term, parseFactor() ]);
+ }
+ return term;
+ };
+ var parseSubExpression = function() {
+ var subExpression = parseTerm();
+ while (token != null && token.type == Scanner.OPERATOR &&
+ (token.value == "+" || token.value == "-")) {
+
+ var operator = token.value;
+ next();
+
+ subExpression = new Exhibit.Expression._Operator(operator, [ subExpression, parseTerm() ]);
+ }
+ return subExpression;
+ };
+ var parseExpression = function() {
+ var expression = parseSubExpression();
+ while (token != null && token.type == Scanner.OPERATOR &&
+ (token.value == "=" || token.value == "<>" ||
+ token.value == "<" || token.value == "<=" ||
+ token.value == ">" || token.value == ">=")) {
+
+ var operator = token.value;
+ next();
+
+ expression = new Exhibit.Expression._Operator(operator, [ expression, parseSubExpression() ]);
+ }
+ return expression;
+ };
+ var parseExpressionList = function() {
+ var expressions = [ parseExpression() ];
+ while (token != null && token.type == Scanner.DELIMITER && token.value == ",") {
+ next();
+ expressions.push(parseExpression());
+ }
+ return expressions;
+ }
+
+ if (several) {
+ var roots = parseExpressionList();
+ var expressions = [];
+ for (var r = 0; r < roots.length; r++) {
+ expressions.push(new Exhibit.Expression._Impl(roots[r]));
+ }
+ return expressions;
+ } else {
+ return new Exhibit.Expression._Impl(parseExpression());
+ }
+};
+
+/*==================================================
+ * Exhibit.ExpressionScanner
+ *==================================================
+ */
+Exhibit.ExpressionScanner = function(text, startIndex) {
+ this._text = text + " "; // make it easier to parse
+ this._maxIndex = text.length;
+ this._index = startIndex;
+ this.next();
+};
+
+Exhibit.ExpressionScanner.DELIMITER = 0;
+Exhibit.ExpressionScanner.NUMBER = 1;
+Exhibit.ExpressionScanner.STRING = 2;
+Exhibit.ExpressionScanner.IDENTIFIER = 3;
+Exhibit.ExpressionScanner.OPERATOR = 4;
+Exhibit.ExpressionScanner.PATH_OPERATOR = 5;
+
+Exhibit.ExpressionScanner.prototype.token = function() {
+ return this._token;
+};
+
+Exhibit.ExpressionScanner.prototype.index = function() {
+ return this._index;
+};
+
+Exhibit.ExpressionScanner.prototype.next = function() {
+ this._token = null;
+
+ while (this._index < this._maxIndex &&
+ " \t\r\n".indexOf(this._text.charAt(this._index)) >= 0) {
+ this._index++;
+ }
+
+ if (this._index < this._maxIndex) {
+ var c1 = this._text.charAt(this._index);
+ var c2 = this._text.charAt(this._index + 1);
+
+ if (".!".indexOf(c1) >= 0) {
+ if (c2 == "@") {
+ this._token = {
+ type: Exhibit.ExpressionScanner.PATH_OPERATOR,
+ value: c1 + c2,
+ start: this._index,
+ end: this._index + 2
+ };
+ this._index += 2;
+ } else {
+ this._token = {
+ type: Exhibit.ExpressionScanner.PATH_OPERATOR,
+ value: c1,
+ start: this._index,
+ end: this._index + 1
+ };
+ this._index++;
+ }
+ } else if ("<>".indexOf(c1) >= 0) {
+ if ((c2 == "=") || ("<>".indexOf(c2) >= 0 && c1 != c2)) {
+ this._token = {
+ type: Exhibit.ExpressionScanner.OPERATOR,
+ value: c1 + c2,
+ start: this._index,
+ end: this._index + 2
+ };
+ this._index += 2;
+ } else {
+ this._token = {
+ type: Exhibit.ExpressionScanner.OPERATOR,
+ value: c1,
+ start: this._index,
+ end: this._index + 1
+ };
+ this._index++;
+ }
+ } else if ("+-*/=".indexOf(c1) >= 0) {
+ this._token = {
+ type: Exhibit.ExpressionScanner.OPERATOR,
+ value: c1,
+ start: this._index,
+ end: this._index + 1
+ };
+ this._index++;
+ } else if ("(),".indexOf(c1) >= 0) {
+ this._token = {
+ type: Exhibit.ExpressionScanner.DELIMITER,
+ value: c1,
+ start: this._index,
+ end: this._index + 1
+ };
+ this._index++;
+ } else if ("\"'".indexOf(c1) >= 0) { // quoted strings
+ var i = this._index + 1;
+ while (i < this._maxIndex) {
+ if (this._text.charAt(i) == c1 && this._text.charAt(i - 1) != "\\") {
+ break;
+ }
+ i++;
+ }
+
+ if (i < this._maxIndex) {
+ this._token = {
+ type: Exhibit.ExpressionScanner.STRING,
+ value: this._text.substring(this._index + 1, i).replace(/\\'/g, "'").replace(/\\"/g, '"'),
+ start: this._index,
+ end: i + 1
+ };
+ this._index = i + 1;
+ } else {
+ throw new Error("Unterminated string starting at " + this._index);
+ }
+ } else if (this._isDigit(c1)) { // number
+ var i = this._index;
+ while (i < this._maxIndex && this._isDigit(this._text.charAt(i))) {
+ i++;
+ }
+
+ if (i < this._maxIndex && this._text.charAt(i) == ".") {
+ i++;
+ while (i < this._maxIndex && this._isDigit(this._text.charAt(i))) {
+ i++;
+ }
+ }
+
+ this._token = {
+ type: Exhibit.ExpressionScanner.NUMBER,
+ value: parseFloat(this._text.substring(this._index, i)),
+ start: this._index,
+ end: i
+ };
+ this._index = i;
+ } else { // identifier
+ var i = this._index;
+ while (i < this._maxIndex) {
+ var c = this._text.charAt(i);
+ if ("(),.!@ \t".indexOf(c) < 0) {
+ i++;
+ } else {
+ break;
+ }
+ }
+ this._token = {
+ type: Exhibit.ExpressionScanner.IDENTIFIER,
+ value: this._text.substring(this._index, i),
+ start: this._index,
+ end: i
+ };
+ this._index = i;
+ }
+ }
+};
+
+Exhibit.ExpressionScanner.prototype._isDigit = function(c) {
+ return "0123456789".indexOf(c) >= 0;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression.js
new file mode 100644
index 00000000..484590b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/expression.js
@@ -0,0 +1,523 @@
+/*==================================================
+ * Exhibit.Expression
+ * http://simile.mit.edu/wiki/Exhibit/API/Expression
+ *==================================================
+ */
+Exhibit.Expression = new Object();
+
+Exhibit.Expression._Impl = function(rootNode) {
+ this._rootNode = rootNode;
+};
+
+Exhibit.Expression._Impl.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ var collection = this._rootNode.evaluate(roots, rootValueTypes, defaultRootName, database);
+ return {
+ values: collection.getSet(),
+ valueType: collection.valueType,
+ size: collection.size
+ };
+};
+
+Exhibit.Expression._Impl.prototype.evaluateOnItem = function(itemID, database) {
+ return this.evaluate(
+ { "value" : itemID },
+ { "value" : "item" },
+ "value",
+ database
+ );
+};
+
+Exhibit.Expression._Impl.prototype.evaluateSingle = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ var collection = this._rootNode.evaluate(roots, rootValueTypes, defaultRootName, database);
+ var result = { value: null, valueType: collection.valueType };
+ collection.forEachValue(function(v) { result.value = v; return true; });
+
+ return result;
+};
+
+Exhibit.Expression._Impl.prototype.evaluateSingleOnItem = function(itemID, database) {
+ return this.evaluateSingle(
+ { "value" : itemID },
+ { "value" : "item" },
+ "value",
+ database
+ );
+};
+
+Exhibit.Expression._Impl.prototype.testExists = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ return this.isPath() ?
+ this._rootNode.testExists(roots, rootValueTypes, defaultRootName, database) :
+ this.evaluate(roots, rootValueTypes, defaultRootName, database).values.size() > 0;
+};
+
+Exhibit.Expression._Impl.prototype.isPath = function() {
+ return this._rootNode instanceof Exhibit.Expression.Path;
+};
+
+Exhibit.Expression._Impl.prototype.getPath = function() {
+ return this.isPath() ? this._rootNode : null;
+};
+
+/*==================================================
+ * Exhibit.Expression._Collection
+ *==================================================
+ */
+Exhibit.Expression._Collection = function(values, valueType) {
+ this._values = values;
+ this.valueType = valueType;
+
+ if (values instanceof Array) {
+ this.forEachValue = Exhibit.Expression._Collection._forEachValueInArray;
+ this.getSet = Exhibit.Expression._Collection._getSetFromArray;
+ this.contains = Exhibit.Expression._Collection._containsInArray;
+ this.size = values.length;
+ } else {
+ this.forEachValue = Exhibit.Expression._Collection._forEachValueInSet;
+ this.getSet = Exhibit.Expression._Collection._getSetFromSet;
+ this.contains = Exhibit.Expression._Collection._containsInSet;
+ this.size = values.size();
+ }
+};
+
+Exhibit.Expression._Collection._forEachValueInSet = function(f) {
+ this._values.visit(f);
+};
+
+Exhibit.Expression._Collection._forEachValueInArray = function(f) {
+ var a = this._values;
+ for (var i = 0; i < a.length; i++) {
+ if (f(a[i])) {
+ break;
+ }
+ }
+};
+
+Exhibit.Expression._Collection._getSetFromSet = function() {
+ return this._values;
+};
+
+Exhibit.Expression._Collection._getSetFromArray = function() {
+ return new Exhibit.Set(this._values);
+};
+
+Exhibit.Expression._Collection._containsInSet = function(v) {
+ this._values.contains(v);
+};
+
+Exhibit.Expression._Collection._containsInArray = function(v) {
+ var a = this._values;
+ for (var i = 0; i < a.length; i++) {
+ if (a[i] == v) {
+ return true;
+ }
+ }
+ return false;
+};
+
+/*==================================================
+ * Exhibit.Expression.Path
+ *==================================================
+ */
+Exhibit.Expression.Path = function() {
+ this._rootName = null;
+ this._segments = [];
+};
+
+Exhibit.Expression.Path.create = function(property, forward) {
+ var path = new Exhibit.Expression.Path();
+ path._segments.push({ property: property, forward: forward, isArray: false });
+ return path;
+};
+
+Exhibit.Expression.Path.prototype.setRootName = function(rootName) {
+ this._rootName = rootName;
+};
+
+Exhibit.Expression.Path.prototype.appendSegment = function(property, hopOperator) {
+ this._segments.push({
+ property: property,
+ forward: hopOperator.charAt(0) == ".",
+ isArray: hopOperator.length > 1
+ });
+};
+
+Exhibit.Expression.Path.prototype.getSegment = function(index) {
+ if (index < this._segments.length) {
+ var segment = this._segments[index];
+ return {
+ property: segment.property,
+ forward: segment.forward,
+ isArray: segment.isArray
+ };
+ } else {
+ return null;
+ }
+};
+
+Exhibit.Expression.Path.prototype.getLastSegment = function() {
+ return this.getSegment(this._segments.length - 1);
+};
+
+Exhibit.Expression.Path.prototype.getSegmentCount = function() {
+ return this._segments.length;
+};
+
+Exhibit.Expression.Path.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ var rootName = this._rootName != null ? this._rootName : defaultRootName;
+ var valueType = rootName in rootValueTypes ? rootValueTypes[rootName] : "text";
+
+ var collection = null;
+ if (rootName in roots) {
+ var root = roots[rootName];
+ if (root instanceof Exhibit.Set || root instanceof Array) {
+ collection = new Exhibit.Expression._Collection(root, valueType);
+ } else {
+ collection = new Exhibit.Expression._Collection([ root ], valueType);
+ }
+
+ return this._walkForward(collection, database);
+ } else {
+ throw new Error("No such variable called " + rootName);
+ }
+};
+
+Exhibit.Expression.Path.prototype.evaluateBackward = function(
+ value,
+ valueType,
+ filter,
+ database
+) {
+ var collection = new Exhibit.Expression._Collection([ value ], valueType);
+
+ return this._walkBackward(collection, filter, database);
+}
+
+Exhibit.Expression.Path.prototype.walkForward = function(
+ values,
+ valueType,
+ database
+) {
+ return this._walkForward(new Exhibit.Expression._Collection(values, valueType), database);
+};
+
+Exhibit.Expression.Path.prototype.walkBackward = function(
+ values,
+ valueType,
+ filter,
+ database
+) {
+ return this._walkBackward(new Exhibit.Expression._Collection(values, valueType), filter, database);
+};
+
+Exhibit.Expression.Path.prototype._walkForward = function(collection, database) {
+ for (var i = 0; i < this._segments.length; i++) {
+ var segment = this._segments[i];
+ if (segment.isArray) {
+ var a = [];
+ var valueType;
+ if (segment.forward) {
+ collection.forEachValue(function(v) {
+ database.getObjects(v, segment.property).visit(function(v2) { a.push(v2); });
+ });
+
+ var property = database.getProperty(segment.property);
+ valueType = property != null ? property.getValueType() : "text";
+ } else {
+ collection.forEachValue(function(v) {
+ database.getSubjects(v, segment.property).visit(function(v2) { a.push(v2); });
+ });
+ valueType = "item";
+ }
+ collection = new Exhibit.Expression._Collection(a, valueType);
+ } else {
+ if (segment.forward) {
+ var values = database.getObjectsUnion(collection.getSet(), segment.property);
+ var property = database.getProperty(segment.property);
+ var valueType = property != null ? property.getValueType() : "text";
+ collection = new Exhibit.Expression._Collection(values, valueType);
+ } else {
+ var values = database.getSubjectsUnion(collection.getSet(), segment.property);
+ collection = new Exhibit.Expression._Collection(values, "item");
+ }
+ }
+ }
+
+ return collection;
+};
+
+Exhibit.Expression.Path.prototype._walkBackward = function(collection, filter, database) {
+ for (var i = this._segments.length - 1; i >= 0; i--) {
+ var segment = this._segments[i];
+ if (segment.isArray) {
+ var a = [];
+ var valueType;
+ if (segment.forward) {
+ collection.forEachValue(function(v) {
+ database.getSubjects(v, segment.property).visit(function(v2) {
+ if (i > 0 || filter == null || filter.contains(v2)) {
+ a.push(v2);
+ }
+ });
+ });
+
+ var property = database.getProperty(segment.property);
+ valueType = property != null ? property.getValueType() : "text";
+ } else {
+ collection.forEachValue(function(v) {
+ database.getObjects(v, segment.property).visit(function(v2) {
+ if (i > 0 || filter == null || filter.contains(v2)) {
+ a.push(v2);
+ }
+ });
+ });
+ valueType = "item";
+ }
+ collection = new Exhibit.Expression._Collection(a, valueType);
+ } else {
+ if (segment.forward) {
+ var values = database.getSubjectsUnion(collection.getSet(), segment.property, null, i == 0 ? filter : null);
+ collection = new Exhibit.Expression._Collection(values, "item");
+ } else {
+ var values = database.getObjectsUnion(collection.getSet(), segment.property, null, i == 0 ? filter : null);
+ var property = database.getProperty(segment.property);
+ var valueType = property != null ? property.getValueType() : "text";
+ collection = new Exhibit.Expression._Collection(values, valueType);
+ }
+ }
+ }
+
+ return collection;
+};
+
+Exhibit.Expression.Path.prototype.rangeBackward = function(
+ from,
+ to,
+ inclusive,
+ filter,
+ database
+) {
+ var set = new Exhibit.Set();
+ var valueType = "item";
+ if (this._segments.length > 0) {
+ var segment = this._segments[this._segments.length - 1];
+ if (segment.forward) {
+ database.getSubjectsInRange(segment.property, from, to, inclusive, set, this._segments.length == 1 ? filter : null);
+ } else {
+ throw new Error("Last path of segment must be forward");
+ }
+
+ for (var i = this._segments.length - 2; i >= 0; i--) {
+ segment = this._segments[i];
+ if (segment.forward) {
+ set = database.getSubjectsUnion(set, segment.property, null, i == 0 ? filter : null);
+ valueType = "item";
+ } else {
+ set = database.getObjectsUnion(set, segment.property, null, i == 0 ? filter : null);
+
+ var property = database.getProperty(segment.property);
+ valueType = property != null ? property.getValueType() : "text";
+ }
+ }
+ }
+ return {
+ valueType: valueType,
+ values: set,
+ count: set.size()
+ };
+};
+
+Exhibit.Expression.Path.prototype.testExists = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ return this.evaluate(roots, rootValueTypes, defaultRootName, database).size > 0;
+};
+
+/*==================================================
+ * Exhibit.Expression._Constant
+ *==================================================
+ */
+Exhibit.Expression._Constant = function(value, valueType) {
+ this._value = value;
+ this._valueType = valueType;
+};
+
+Exhibit.Expression._Constant.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ return new Exhibit.Expression._Collection([ this._value ], this._valueType);
+};
+
+/*==================================================
+ * Exhibit.Expression._Operator
+ *==================================================
+ */
+Exhibit.Expression._Operator = function(operator, args) {
+ this._operator = operator;
+ this._args = args;
+};
+
+Exhibit.Expression._Operator.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ var values = [];
+
+ var args = [];
+ for (var i = 0; i < this._args.length; i++) {
+ args.push(this._args[i].evaluate(roots, rootValueTypes, defaultRootName, database));
+ }
+
+ var operator = Exhibit.Expression._operators[this._operator];
+ var f = operator.f;
+ if (operator.argumentType == "number") {
+ args[0].forEachValue(function(v1) {
+ if (!(typeof v1 == "number")) {
+ v1 = parseFloat(v1);
+ }
+
+ args[1].forEachValue(function(v2) {
+ if (!(typeof v2 == "number")) {
+ v2 = parseFloat(v2);
+ }
+
+ values.push(f(v1, v2));
+ });
+ });
+ } else {
+ args[0].forEachValue(function(v1) {
+ args[1].forEachValue(function(v2) {
+ values.push(f(v1, v2));
+ });
+ });
+ }
+
+ return new Exhibit.Expression._Collection(values, operator.valueType);
+};
+
+Exhibit.Expression._operators = {
+ "+" : {
+ argumentType: "number",
+ valueType: "number",
+ f: function(a, b) { return a + b; }
+ },
+ "-" : {
+ argumentType: "number",
+ valueType: "number",
+ f: function(a, b) { return a - b; }
+ },
+ "*" : {
+ argumentType: "number",
+ valueType: "number",
+ f: function(a, b) { return a * b; }
+ },
+ "/" : {
+ argumentType: "number",
+ valueType: "number",
+ f: function(a, b) { return a / b; }
+ },
+ "=" : {
+ valueType: "boolean",
+ f: function(a, b) { return a == b; }
+ },
+ "<>" : {
+ valueType: "boolean",
+ f: function(a, b) { return a != b; }
+ },
+ "><" : {
+ valueType: "boolean",
+ f: function(a, b) { return a != b; }
+ },
+ "<" : {
+ argumentType: "number",
+ valueType: "boolean",
+ f: function(a, b) { return a < b; }
+ },
+ ">" : {
+ argumentType: "number",
+ valueType: "boolean",
+ f: function(a, b) { return a > b; }
+ },
+ "<=" : {
+ argumentType: "number",
+ valueType: "boolean",
+ f: function(a, b) { return a <= b; }
+ },
+ ">=" : {
+ argumentType: "number",
+ valueType: "boolean",
+ f: function(a, b) { return a >= b; }
+ }
+}
+
+/*==================================================
+ * Exhibit.Expression._FunctionCall
+ *==================================================
+ */
+Exhibit.Expression._FunctionCall = function(name, args) {
+ this._name = name;
+ this._args = args;
+};
+
+Exhibit.Expression._FunctionCall.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ var args = [];
+ for (var i = 0; i < this._args.length; i++) {
+ args.push(this._args[i].evaluate(roots, rootValueTypes, defaultRootName, database));
+ }
+
+ if (this._name in Exhibit.Functions) {
+ return Exhibit.Functions[this._name].f(args);
+ } else {
+ throw new Error("No such function named " + this._name);
+ }
+};
+
+/*==================================================
+ * Exhibit.Expression._ControlCall
+ *==================================================
+ */
+Exhibit.Expression._ControlCall = function(name, args) {
+ this._name = name;
+ this._args = args;
+};
+
+Exhibit.Expression._ControlCall.prototype.evaluate = function(
+ roots,
+ rootValueTypes,
+ defaultRootName,
+ database
+) {
+ return Exhibit.Controls[this._name].f(this._args, roots, rootValueTypes, defaultRootName, database);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/functions.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/functions.js
new file mode 100644
index 00000000..d07118fc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/functions.js
@@ -0,0 +1,349 @@
+/*==================================================
+ * Exhibit.Functions
+ * http://simile.mit.edu/wiki/Exhibit/API/Functions
+ *==================================================
+ */
+Exhibit.Functions = {};
+
+Exhibit.FunctionUtilities = {};
+Exhibit.FunctionUtilities.registerSimpleMappingFunction = function(name, f, valueType) {
+ Exhibit.Functions[name] = {
+ f: function(args) {
+ var set = new Exhibit.Set();
+ for (var i = 0; i < args.length; i++) {
+ args[i].forEachValue(function(v) {
+ var v2 = f(v);
+ if (v2 != undefined) {
+ set.add(v2);
+ }
+ });
+ }
+ return new Exhibit.Expression._Collection(set, valueType);
+ }
+ };
+};
+
+Exhibit.Functions["union"] = {
+ f: function(args) {
+ var set = new Exhibit.Set();
+ var valueType = null;
+
+ if (args.length > 0) {
+ var valueType = args[0].valueType;
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+ if (arg.size > 0) {
+ if (valueType == null) {
+ valueType = arg.valueType;
+ }
+ set.addSet(arg.getSet());
+ }
+ }
+ }
+ return new Exhibit.Expression._Collection(set, valueType != null ? valueType : "text");
+ }
+};
+
+Exhibit.Functions["contains"] = {
+ f: function(args) {
+ var result = args[0].size > 0;
+ var set = args[0].getSet();
+
+ args[1].forEachValue(function(v) {
+ if (!set.contains(v)) {
+ result = false;
+ return true;
+ }
+ });
+
+ return new Exhibit.Expression._Collection([ result ], "boolean");
+ }
+};
+
+Exhibit.Functions["exists"] = {
+ f: function(args) {
+ return new Exhibit.Expression._Collection([ args[0].size > 0 ], "boolean");
+ }
+};
+
+Exhibit.Functions["count"] = {
+ f: function(args) {
+ return new Exhibit.Expression._Collection([ args[0].size ], "number");
+ }
+};
+
+Exhibit.Functions["not"] = {
+ f: function(args) {
+ return new Exhibit.Expression._Collection([ !args[0].contains(true) ], "boolean");
+ }
+};
+
+Exhibit.Functions["and"] = {
+ f: function(args) {
+ var r = true;
+ for (var i = 0; r && i < args.length; i++) {
+ r = r && args[i].contains(true);
+ }
+ return new Exhibit.Expression._Collection([ r ], "boolean");
+ }
+};
+
+Exhibit.Functions["or"] = {
+ f: function(args) {
+ var r = false;
+ for (var i = 0; !r && i < args.length; i++) {
+ r = r || args[i].contains(true);
+ }
+ return new Exhibit.Expression._Collection([ r ], "boolean");
+ }
+};
+
+Exhibit.Functions["add"] = {
+ f: function(args) {
+ var total = 0;
+ for (var i = 0; i < args.length; i++) {
+ args[i].forEachValue(function(v) {
+ if (v != null) {
+ if (typeof v == "number") {
+ total += v;
+ } else {
+ var n = parseFloat(v);
+ if (!isNaN(n)) {
+ total += n;
+ }
+ }
+ }
+ });
+ }
+
+ return new Exhibit.Expression._Collection([ total ], "number");
+ }
+};
+
+// Note: arguments expanding to multiple items get concatenated in random order
+Exhibit.Functions["concat"] = {
+ f: function(args) {
+ var result = [];
+ for (var i = 0; i < args.length; i++) {
+ args[i].forEachValue(function(v) {
+ if (v != null) {
+ result.push(v);
+ }
+ });
+ }
+
+ return new Exhibit.Expression._Collection([ result.join('') ], "text");
+ }
+};
+
+Exhibit.Functions["multiply"] = {
+ f: function(args) {
+ var product = 1;
+ for (var i = 0; i < args.length; i++) {
+ args[i].forEachValue(function(v) {
+ if (v != null) {
+ if (typeof v == "number") {
+ product *= v;
+ } else {
+ var n = parseFloat(v);
+ if (!isNaN(n)) {
+ product *= n;
+ }
+ }
+ }
+ });
+ }
+
+ return new Exhibit.Expression._Collection([ product ], "number");
+ }
+};
+
+Exhibit.Functions["date-range"] = {
+ _parseDate: function (v) {
+ if (v == null) {
+ return Number.NEGATIVE_INFINITY;
+ } else if (v instanceof Date) {
+ return v.getTime();
+ } else {
+ try {
+ return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+ } catch (e) {
+ return Number.NEGATIVE_INFINITY;
+ }
+ }
+ },
+ _factors: {
+ second: 1000,
+ minute: 60 * 1000,
+ hour: 60 * 60 * 1000,
+ day: 24 * 60 * 60 * 1000,
+ week: 7 * 24 * 60 * 60 * 1000,
+ month: 30 * 24 * 60 * 60 * 1000,
+ quarter: 3 * 30 * 24 * 60 * 60 * 1000,
+ year: 365 * 24 * 60 * 60 * 1000,
+ decade: 10 * 365 * 24 * 60 * 60 * 1000,
+ century: 100 * 365 * 24 * 60 * 60 * 1000
+ },
+ _computeRange: function(from, to, interval) {
+ var range = to - from;
+ if (isFinite(range)) {
+ if (interval in this._factors) {
+ range = Math.round(range / this._factors[interval]);
+ }
+ return range;
+ }
+ return null;
+ },
+ f: function(args) {
+ var self = this;
+
+ var from = Number.POSITIVE_INFINITY;
+ args[0].forEachValue(function(v) {
+ from = Math.min(from, self._parseDate(v));
+ });
+
+ var to = Number.NEGATIVE_INFINITY;
+ args[1].forEachValue(function(v) {
+ to = Math.max(to, self._parseDate(v));
+ });
+
+ var interval = "day";
+ args[2].forEachValue(function(v) {
+ interval = v;
+ });
+
+ var range = this._computeRange(from, to, interval);
+ return new Exhibit.Expression._Collection(range != null ? [ range ] : [], "number");
+ }
+};
+
+Exhibit.Functions["distance"] = {
+ _units: {
+ km: 1e3,
+ mile: 1609.344
+ },
+ _computeDistance: function(from, to, unit, roundTo) {
+ var range = from.distanceFrom(to);
+ if (!roundTo) roundTo = 1;
+ if (isFinite(range)) {
+ if (this._units.hasOwnProperty(unit)) {
+ range = range / this._units[unit];
+ }
+ return Exhibit.Util.round(range, roundTo);
+ }
+ return null;
+ },
+ f: function(args) {
+ var self = this;
+ var data = {};
+ var name = ["origo", "lat", "lng", "unit", "round"];
+ for (var i = 0, n; n = name[i]; i++) {
+ args[i].forEachValue(function(v) { data[n] = v; });
+ }
+
+ var latlng = data.origo.split(",");
+ var from = new GLatLng( latlng[0], latlng[1] );
+ var to = new GLatLng( data.lat, data.lng );
+
+ var range = this._computeDistance(from, to, data.unit, data.round);
+ return new Exhibit.Expression._Collection(range != null ? [ range ] : [], "number");
+ }
+};
+
+Exhibit.Functions["min"] = {
+ f: function(args) {
+ var returnMe = function (val) { return val; };
+ var min = Number.POSITIVE_INFINITY;
+ var valueType = null;
+
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+ var currentValueType = arg.valueType ? arg.valueType : 'text';
+ var parser = Exhibit.SettingsUtilities._typeToParser(currentValueType);
+
+ arg.forEachValue(function(v) {
+ parsedV = parser(v, returnMe);
+ if (parsedV < min || min == Number.POSITIVE_INFINITY) {
+ min = parsedV;
+ valueType = (valueType == null) ? currentValueType :
+ (valueType == currentValueType ? valueType : "text") ;
+ }
+ });
+ }
+
+ return new Exhibit.Expression._Collection([ min ], valueType != null ? valueType : "text");
+ }
+};
+
+Exhibit.Functions["max"] = {
+ f: function(args) {
+ var returnMe = function (val) { return val; };
+ var max = Number.NEGATIVE_INFINITY;
+ var valueType = null;
+
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+ var currentValueType = arg.valueType ? arg.valueType : 'text';
+ var parser = Exhibit.SettingsUtilities._typeToParser(currentValueType);
+
+ arg.forEachValue(function(v) {
+ parsedV = parser(v, returnMe);
+ if (parsedV > max || max == Number.NEGATIVE_INFINITY) {
+ max = parsedV;
+ valueType = (valueType == null) ? currentValueType :
+ (valueType == currentValueType ? valueType : "text") ;
+ }
+ });
+ }
+ return new Exhibit.Expression._Collection([ max ], valueType != null ? valueType : "text");
+ }
+};
+
+Exhibit.Functions["remove"] = {
+ f: function(args) {
+ var set = args[0].getSet();
+ var valueType = args[0].valueType;
+ for (var i = 1; i < args.length; i++) {
+ var arg = args[i];
+ if (arg.size > 0) {
+ set.removeSet(arg.getSet());
+ }
+ }
+ return new Exhibit.Expression._Collection(set, valueType);
+ }
+};
+
+Exhibit.Functions["now"] = {
+ f: function(args) {
+ return new Exhibit.Expression._Collection([ new Date() ], "date");
+ }
+};
+
+Exhibit.Functions["urlenc"] = {
+ f: function(arguments) {
+ if(typeof arguments[0]._values.toArray == "function"){
+ try{
+ var firstentry = arguments[0]._values.toArray();
+ }
+ catch(err){document.write(err.description)}
+ var url = escape(firstentry[0]).replace(/\+/g,'%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40');
+ return new Exhibit.Expression._Collection([ url ], "url");
+ } else {
+ return new Exhibit.Expression._Collection([ "error" ], "url");
+ }
+ }
+};
+
+Exhibit.Functions["urlencval"] = {
+ f: function(arguments) {
+ if(arguments[0]._values[0] != null){
+ var url = escape(arguments[0]._values[0]).replace(/\+/g,'%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40');
+ return new Exhibit.Expression._Collection([ url ], "url");
+ } else {
+ return new Exhibit.Expression._Collection([ "error" ], "url");
+ }
+ }
+};
+
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/authenticated-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/authenticated-importer.js
new file mode 100644
index 00000000..6980eb0f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/authenticated-importer.js
@@ -0,0 +1,53 @@
+Exhibit.AuthenticatedImporter = {
+ _callbacks: {}
+};
+
+Exhibit.importers["application/authenticated"] = Exhibit.AuthenticatedImporter;
+
+Exhibit.AuthenticatedImporter.constructURL = function () {
+ return "https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fspreadsheets.google.com%2Ffeeds%2F&session=1&secure=0&next="
+ + window.location;
+};
+
+Exhibit.AuthenticatedImporter.load = function(link, database, cont) {
+
+ // var params = SimileAjax.parseURLParameters();
+ //
+ // if (!params.token) {
+ // window.location = Exhibit.AuthenticatedImporter.constructURL();
+ // }
+ //
+
+
+ var url = typeof link == "string" ? link : link.href;
+ url = Exhibit.Persistence.resolveURL(url);
+
+ var fError = function(statusText, status, xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+ if (cont) cont();
+ };
+
+ var fDone = function(xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ try {
+ var o = null;
+ try {
+ o = eval("(" + xmlhttp.responseText + ")");
+ } catch (e) {
+ Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url, e), url);
+ }
+
+ if (o != null) {
+ database.loadData(o, Exhibit.Persistence.getBaseURL(url));
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error loading Exhibit JSON data from " + url);
+ } finally {
+ if (cont) cont();
+ }
+ };
+
+ Exhibit.UI.showBusyIndicator();
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/babel-based-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/babel-based-importer.js
new file mode 100644
index 00000000..3d1300ba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/babel-based-importer.js
@@ -0,0 +1,75 @@
+/*==================================================
+ * Exhibit.BabelBasedImporter
+ *==================================================
+ */
+
+Exhibit.BabelBasedImporter = {
+ mimetypeToReader: {
+ "application/rdf+xml" : "rdf-xml",
+ "application/n3" : "n3",
+
+ "application/msexcel" : "xls",
+ "application/x-msexcel" : "xls",
+ "application/x-ms-excel" : "xls",
+ "application/vnd.ms-excel" : "xls",
+ "application/x-excel" : "xls",
+ "application/xls" : "xls",
+ "application/x-xls" : "xls",
+
+ "application/x-bibtex" : "bibtex"
+ },
+ babelTranslatorURL: "http://service.simile-widgets.org/babel/translator",
+
+ _initialize: function() {
+ var links = [];
+ var heads = document.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var linkElmts = heads[h].getElementsByTagName("link");
+ for (var l = 0; l < linkElmts.length; l++) {
+ var link = linkElmts[l];
+ if (link.rel.match(/\bexhibit\/babel-translator\b/)) {
+ Exhibit.BabelBasedImporter.babelTranslatorURL = link.href;
+ }
+ }
+ }
+ Exhibit.BabelBasedImporter._initialize = function() {}
+ }
+};
+
+Exhibit.importers["application/rdf+xml"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/n3"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/msexcel"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-msexcel"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/vnd.ms-excel"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-excel"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/xls"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-xls"] = Exhibit.BabelBasedImporter;
+Exhibit.importers["application/x-bibtex"] = Exhibit.BabelBasedImporter;
+
+Exhibit.BabelBasedImporter.load = function(link, database, cont) {
+ Exhibit.BabelBasedImporter._initialize();
+
+ var url = (typeof link == "string") ?
+ Exhibit.Persistence.resolveURL(link) :
+ Exhibit.Persistence.resolveURL(link.href);
+
+ var reader = "rdf-xml";
+ var writer = "exhibit-jsonp";
+ if (typeof link != "string") {
+ var mimetype = link.type;
+ if (mimetype in Exhibit.BabelBasedImporter.mimetypeToReader) {
+ reader = Exhibit.BabelBasedImporter.mimetypeToReader[mimetype];
+ }
+ }
+ if (reader == "bibtex") {
+ writer = "bibtex-exhibit-jsonp";
+ }
+
+ var babelURL = Exhibit.BabelBasedImporter.babelTranslatorURL + "?" + [
+ "reader=" + reader,
+ "writer=" + writer,
+ "url=" + encodeURIComponent(url)
+ ].join("&");
+
+ return Exhibit.JSONPImporter.load(babelURL, database, cont);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-json-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-json-importer.js
new file mode 100644
index 00000000..274fb40c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-json-importer.js
@@ -0,0 +1,42 @@
+/*==================================================
+ * Exhibit.ExhibitJSONImporter
+ *==================================================
+ */
+
+Exhibit.ExhibitJSONImporter = {
+};
+Exhibit.importers["application/json"] = Exhibit.ExhibitJSONImporter;
+
+Exhibit.ExhibitJSONImporter.load = function(link, database, cont) {
+ var url = typeof link == "string" ? link : link.href;
+ url = Exhibit.Persistence.resolveURL(url);
+
+ var fError = function(statusText, status, xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+ if (cont) cont();
+ };
+
+ var fDone = function(xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ try {
+ var o = null;
+ try {
+ o = eval("(" + xmlhttp.responseText + ")");
+ } catch (e) {
+ Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url, e), url);
+ }
+
+ if (o != null) {
+ database.loadData(o, Exhibit.Persistence.getBaseURL(url));
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error loading Exhibit JSON data from " + url);
+ } finally {
+ if (cont) cont();
+ }
+ };
+
+ Exhibit.UI.showBusyIndicator();
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-xml-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-xml-importer.js
new file mode 100644
index 00000000..0e0de358
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/exhibit-xml-importer.js
@@ -0,0 +1,323 @@
+/*==================================================
+ * Exhibit.ExhibitXMLImporter
+ *==================================================
+ */
+
+
+
+Exhibit.ExhibitXMLImporter = { };
+
+Exhibit.importers["application/xml"] = Exhibit.ExhibitXMLImporter;
+
+Exhibit.ExhibitXMLImporter.getXMLDocument = function (docURL) {
+
+ var xmlDoc = null;
+ $.ajax({
+ url: docURL,
+ type: 'GET',
+ dataType: 'xml',
+ async: false, //Need this due to failure of getting XMLDoc from server
+ success: function(data) { xmlDoc = data;}
+ });
+ if (xmlDoc)
+ {
+ return xmlDoc;
+ }
+ else
+ {
+ alert('ERROR FINDING XML DOC');
+ return;
+ }
+}
+
+
+//APPENDS PROPERTIES (NAME SPECIFIED BY USER) TO ARRAY
+Exhibit.ExhibitXMLImporter.appendUserPropertyToArray = function(node,configuration,objectToAppend)
+{
+
+ var referenceIndex = configuration.propertyTags.indexOf(node.nodeName);
+ var array = objectToAppend[configuration.propertyNames[referenceIndex]];
+ // check if property list has been initialized
+ if (typeof objectToAppend[configuration.propertyNames[referenceIndex]] == 'string')
+ {
+ array = [array];
+ array.push(node.textContent);
+ }
+ else
+ {
+ array.push(node.textContent);
+ }
+ return array;
+}
+
+// APPENDS PROPERTIES (NAME NOT SPECIFIED BY USER) TO ARRAY
+Exhibit.ExhibitXMLImporter.appendPropertyToArray = function(node,configuration,objectToAppend)
+{
+ var array = objectToAppend[node.nodeName];
+
+
+ if (typeof array == 'string')
+ {
+ array = [array];
+ array.push(node.textContent);
+ }
+ else
+ {
+ array.push(node.textContent);
+
+ }
+ return array;
+}
+
+//GETS ALL ITEMS OF CONFIGURATION.ITEMTAG[INDEX]
+Exhibit.ExhibitXMLImporter.getItems = function(xmlDoc, object,index,configuration)
+{
+ var self = this;
+ $(configuration.itemTag[index],xmlDoc).each( function()
+ {
+ var propertyList = [];
+ var queue = [];
+ $(this).children().each(function() {
+ queue.push(this);
+ }
+ );
+ objectToAppend = {};
+ while (queue.length)
+ {
+ var node = queue.pop();
+ var nodeType = self.determineType(node,configuration);
+
+ if (nodeType == 'property')
+ {
+ // IF MULTIPLE PROPERTIES OF SAME NODENAME, APPEND TO ARRAY
+ if (propertyList.indexOf(node.nodeName)>=0)
+ {
+ // check if user specified property name
+ if (configuration.propertyTags.indexOf(node.nodeName)>=0)
+ {
+ objectToAppend[configuration.propertyNames[index]]= self.appendUserPropertyToArray(node,configuration,objectToAppend);
+
+ }
+ else // Use tag name as property name
+ {
+ objectToAppend[node.nodeName]= self.appendPropertyToArray(node,configuration,objectToAppend);
+ }
+
+ }
+ else //IF SINGLE VALUE APPEND TO STRING VALUE
+ {
+ // APPLY USER SPECIFIED PROPERTY NAMES
+ if (configuration.propertyTags.indexOf(node.nodeName)>=0)
+ {
+ var referenceIndex = configuration.propertyTags.indexOf(node.nodeName);
+ objectToAppend[configuration.propertyNames[referenceIndex]] = node.textContent;
+ }
+ //ELSE, USE TAG NODENAME
+ else
+ {
+ objectToAppend[node.nodeName] = node.textContent;
+ }
+ }
+ propertyList.push(node.nodeName);
+ }
+ else if (nodeType == 'Item')
+ {
+ var referenceIndex = configuration.itemTag.indexOf(node.nodeName);
+ var tempObject = self.configureItem(node,{},configuration,referenceIndex);
+
+ objectToAppend[tempObject.type] = tempObject.label;
+ }
+ else if (nodeType == 'fakeItem')
+ {
+ $(node).children().each(function()
+ {
+ queue.push(this);
+ }
+ );
+ }
+ else
+ {
+ alert('error: nodetype not understood');
+ }
+ }
+ objectToAppend = self.configureItem(this, objectToAppend,configuration,index);
+ object.items.push(objectToAppend);
+ }
+ )
+
+
+ return object;
+}
+
+//FINDS THE CLOSEST PARENT NODE THAT'S IN CONFIGURATION.ITEMTAG
+Exhibit.ExhibitXMLImporter.getParentItem = function(itemNode,configuration)
+{
+ if (itemNode.parentNode==null)
+ {
+ return null;
+ }
+ else if (configuration.itemTag.indexOf(itemNode.parentNode.nodeName)>=0)
+ {
+ var referenceIndex = configuration.itemTag.indexOf(itemNode.parentNode.nodeName);
+ return this.configureItem(itemNode.parentNode,{},configuration,referenceIndex);
+ }
+ else
+ {
+ this.getParentItem(itemNode.parentNode,configuration);
+ }
+}
+
+// SETS LABEL, TYPE, AND PARENT RELATION
+Exhibit.ExhibitXMLImporter.configureItem = function(myItem, object,configuration,index)
+{
+ if (!(object.label) && configuration.propertyLabel[index]!=null)
+ {
+ object['label'] = $(configuration.propertyLabel[index],myItem)[0].textContent;
+ }
+ else //DEFAULT TO FIRST PROPERTY
+ {
+ object['label'] = $(myItem).children()[0].textContent;
+ }
+
+ if (!(object.type) && configuration.itemType[index]!=null)
+ {
+ object['type'] = configuration.itemType[index];
+ }
+ else //DEFAULT TO NODENAME
+ {
+ object['type'] = myItem.nodeName;
+ }
+
+ var parentItem = this.getParentItem(myItem,configuration);
+ if (parentItem)
+ {
+ if (configuration.parentRelation[index])
+ {
+ object[configuration.parentRelation[index]] = parentItem.label;
+ }
+ else //DEFAULT TO "IS A CHILD OF"
+ {
+ object['isChildOf'] = parentItem.label;
+ }
+ }
+ return object;
+}
+
+
+Exhibit.ExhibitXMLImporter.configure = function()
+{
+ var configuration =
+ {
+ 'itemTag': [],
+ 'propertyLabel': [],
+ 'itemType': [],
+ 'parentRelation': [],
+ 'propertyTags': [],
+ 'propertyNames': []
+
+
+ }
+
+ // get itemTag, propertyLabel, itemType, and parentRelation
+ $('link').each( function()
+ {
+ if (this.hasAttribute('ex:itemTag'))
+ {
+ configuration.itemTag = Exhibit.getAttribute(this,'ex:itemTag',',');
+ }
+ if (this.hasAttribute('ex:setPropertyAsLabel'))
+ {
+ configuration.propertyLabel = Exhibit.getAttribute(this,'ex:setPropertyAsLabel',',');
+ }
+ if (this.hasAttribute('ex:itemType'))
+ {
+ configuration.itemType = Exhibit.getAttribute(this,'ex:itemType',',');
+ }
+ if (this.hasAttribute('ex:parentRelation'))
+ {
+ configuration.parentRelation = Exhibit.getAttribute(this,'ex:parentRelation',',');
+ }
+ if (this.hasAttribute('ex:propertyNames'))
+ {
+ configuration.propertyNames = Exhibit.getAttribute(this,'ex:propertyNames',',');
+ }
+ if (this.hasAttribute('ex:propertyTags'))
+ {
+ configuration.propertyTags = Exhibit.getAttribute(this,'ex:propertyTags',',');
+ }
+
+ }
+ )
+
+ return configuration;
+}
+
+Exhibit.ExhibitXMLImporter.determineType = function(node,configuration)
+{
+
+ if (configuration.itemTag.indexOf(node.nodeName)>=0)
+ {
+ return "Item";
+ }
+
+ else if ($(node).children().length == 0)
+ {
+ return 'property';
+ }
+
+ else
+ {
+ return 'fakeItem';
+ }
+}
+
+
+
+
+Exhibit.ExhibitXMLImporter.load = function (link,database,cont)
+{
+ var self = this;
+ var url = typeof link == "string" ? link : link.href;
+ url = Exhibit.Persistence.resolveURL(url);
+ var fError = function(statusText, status, xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+ if (cont) cont();
+ };
+
+ var fDone = function() {
+ Exhibit.UI.hideBusyIndicator();
+ try {
+ var o = null;
+ try {
+ xmlDoc = Exhibit.ExhibitXMLImporter.getXMLDocument(url);
+ var configuration = self.configure();
+ o = {
+ 'items': []
+ };
+ for (index in configuration.itemTag)
+ {
+ o = Exhibit.ExhibitXMLImporter.getItems(xmlDoc,o,index,configuration);
+ }
+
+ } catch (e) {
+ Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url, e), url);
+ }
+
+ if (o != null) {
+ database.loadData(o, Exhibit.Persistence.getBaseURL(url));
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error loading Exhibit JSON data from " + url);
+ }
+
+ finally {
+ if (cont) cont();
+ }
+ };
+
+ Exhibit.UI.showBusyIndicator();
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+}
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/html-table-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/html-table-importer.js
new file mode 100644
index 00000000..33f849d4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/html-table-importer.js
@@ -0,0 +1,175 @@
+/*==================================================
+ * Exhibit.HtmlTableImporter
+ *==================================================
+ */
+
+Exhibit.HtmlTableImporter = {
+};
+Exhibit.importers["text/html"] = Exhibit.HtmlTableImporter;
+
+Exhibit.HtmlTableImporter.load = function(link, database, cont) {
+ var url = typeof link == "string" ? link : link.href;
+ if (url.substr(0,1) == "#") {
+ try {
+ var id = /#(.*)/.exec(f)[1];
+ var table = document.getElementById(id);
+ table.style.display = "none"; // as we are replacing it with the exhibit UI
+
+ Exhibit.HtmlTableImporter.loadTable(table, database);
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ } finally {
+ if (cont) {
+ cont();
+ }
+ }
+ } else if (typeof link != "string") {
+ var xpath = link.getAttribute('ex:xpath');
+ var columns = (link.getAttribute('ex:columns')).split(',');
+ var babelURL = "http://simile.mit.edu/babel/html-extractor?" + [
+ "xpath=" + xpath,
+ "url=" + encodeURIComponent(url)
+ ].join("&");
+ var fConvert = function(string) {
+ var div = document.createElement("div");
+ div.innerHTML = string;
+ var table = div.firstChild;
+
+ var th, ths = table.getElementsByTagName("th");
+ for( col = 0; th = ths[col]; col++ ) {
+ var label = columns[col];
+ th.setAttribute('ex:name', label);
+ }
+
+ Exhibit.HtmlTableImporter.loadTable(table, database);
+ return {};
+ }
+ return Exhibit.JSONPImporter.load(babelURL, database, cont, fConvert);
+ } else {
+ if (cont) {
+ cont();
+ }
+ }
+}
+
+Exhibit.HtmlTableImporter.loadTable = function(table, database) {
+
+ var textOf = function( n ) { return n.textContent || n.innerText || ""; };
+ var readAttributes = function( node, attributes ) {
+ var result = {}, found = false, attr, value, i;
+ for( i = 0; attr = attributes[i]; i++ ) {
+ value = Exhibit.getAttribute( node, attr );
+ if( value ) {
+ result[attr] = value;
+ found = true;
+ }
+ }
+ return found && result;
+ }
+
+ // FIXME: it's probably a better idea to ask database.js for these lists:
+ var typelist = [ "uri", "label", "pluralLabel" ];
+ var proplist = [ "uri", "valueType", // [text|number|date|boolean|item|url|textwithlink]
+ "label", "reverseLabel",
+ "pluralLabel", "reversePluralLabel",
+ "groupingLabel", "reverseGroupingLabel" ];
+ var columnProps = [ "valueParser", "arity" ];
+
+ var parsed = {}; // accumulator of all data we scrape up (for loadData)
+ var type = Exhibit.getAttribute( table, 'type' );
+ var types = type && readAttributes( table, typelist );
+ if( types ) {
+ parsed.types = {};
+ parsed.types[type] = types;
+ }
+
+ var fields = [], props = {}, columnData = [], row, col;
+ var tr, trs = table.getElementsByTagName("tr");
+ var th, ths = trs[0].getElementsByTagName("th");
+ for( col = 0; th = ths[col]; col++ ) {
+ var field = textOf( th ).trim();
+ var hastextwithlink = false;
+ var attr = readAttributes( th, proplist );
+ var name = Exhibit.getAttribute( th, 'name' );
+ if( name ) {
+ attr = attr || {};
+ attr.label = attr.label || field;
+ field = name;
+ }
+ if( attr ) {
+ props[field] = attr;
+ if (props[field].valueType == "textwithlink") {
+ props[field].valueType = "text";
+ props[(field + "-link")] = {valueType : "url"};
+ hastextwithlink = true;
+ }
+ parsed.properties = props;
+ }
+ fields.push( field );
+ attr = readAttributes( th, columnProps ) || {};
+ if( attr.valueParser && attr.valueParser in window ) {
+ attr.valueParser = window[attr.valueParser];
+ } else { // provide a default valueParser:
+ if( attr.arity == "single" ) {
+ attr.valueParser = function( text, node, rowNo, colNo ) {
+ return text.trim();
+ };
+ } else {
+ attr.valueParser = function( text, node, rowNo, colNo ) {
+ if( text.indexOf(';') == -1 )
+ return text.trim();
+
+ var data = text.split(';');
+ for( var i = 0; i<data.length; i++ )
+ data[i] = data[i].trim();
+
+ return data;
+ };
+ if (hastextwithlink) {
+ var fallback = attr.valueParser;
+ attr.valueParser = function( text, node, rowNo, colNo ) {
+ var links = node.getElementsByTagName("a");
+ if( !links.length ) { return fallback( text, node, rowNo, colNo ); }
+ var data={};
+ data[fields[colNo]] = text.trim();
+ data[(fields[colNo] + "-link") ] = links[0].href;
+ return data;
+ }
+ }
+ }
+ }
+ columnData[col] = attr;
+ }
+
+ var img, imgs = table.getElementsByTagName("img");
+ while( img = imgs[0] ) // replace any images with their respective URLs
+ img.parentNode.replaceChild( document.createTextNode( img.src ), img );
+
+ var items = [], td, raw;
+ for( row = 1; tr = trs[row]; row++ ) {
+ var item = {};
+ var tds = tr.getElementsByTagName("td");
+ for( col = 0; td = tds[col]; col++ ) {
+ var raw = textOf( td );
+ data = columnData[col].valueParser( raw, td, row, col );
+ if( data == null || raw === "" ) {
+ continue;
+ }
+ if( typeof data == 'object' && !(data instanceof Array) ) {
+ for( var property in data ) {
+ item[property] = data[property];
+ }
+ } else {
+ item[fields[col]] = data;
+ }
+ }
+
+ if( type )
+ item.type = type;
+
+ items.push( item );
+ parsed.items = items;
+ }
+
+ database.loadData( parsed, Exhibit.Persistence.resolveURL(location.href) );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/json-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/json-importer.js
new file mode 100644
index 00000000..2c42cdda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/json-importer.js
@@ -0,0 +1,262 @@
+Exhibit.jsonImporter = { };
+
+Exhibit.importers["application/general-json"] = Exhibit.jsonImporter;
+
+Exhibit.jsonImporter.getjsonDocument = function (docURL)
+{
+
+ var jsonDoc = null;
+ $.ajax({
+ url: docURL,
+ type: 'GET',
+ dataType: 'json',
+ async: false, //Need this due to failure of getting jsonDoc from server
+ success: function(data) { jsonDoc = data;}
+ });
+ if (jsonDoc)
+ {
+ return jsonDoc;
+ }
+ else
+ {
+ alert('ERROR FINDING JSON DOC');
+ return null;
+ }
+};
+
+Exhibit.jsonImporter.findFirstItems = function(json,configuration)
+{
+ if (json instanceof Array)
+ {
+ return json.length > 0 ? Exhibit.jsonImporter.findFirstItems(json[0],configuration) : null;
+ }
+ else
+ {
+ var visited = [];
+ var listOfItems = [];
+ for (child in json)
+ {
+ visited.push(json[child]);
+ if (configuration.itemTag.indexOf(child)>=0)
+ {
+ for (var i = 0; i < json[child].length; i++)
+ {
+ var subChild = json[child][i];
+ subChild.index = configuration.itemTag.indexOf(child);
+ listOfItems.push(subChild);
+ }
+ }
+ }
+ if (listOfItems.length)
+ {
+ return listOfItems;
+ }
+ else {
+ return Exhibit.jsonImporter.findFirstItems(visited,configuration);
+ }
+ }
+};
+
+
+Exhibit.jsonImporter.getItems = function(json,exhibitJSON,configuration)
+{
+ var itemQueue;
+ var root = json;
+ if (root instanceof Array)
+ itemQueue = root;
+ else
+ itemQueue = [root];
+
+ while (itemQueue.length>0)
+ {
+
+ var myObject = itemQueue.shift();
+ var index = myObject.index;
+ var objectToAppend = {};
+
+ var propertyQueue = [];
+ for (propertyKey in myObject)
+ {
+ propertyQueue.push(propertyKey)
+ }
+ while (propertyQueue.length>0)
+ {
+ var key = propertyQueue.shift();
+
+ var keyID = key.split('.').pop();
+
+ // TEST IF Property
+ if (configuration.itemTag.indexOf(keyID)==-1)
+ {
+ var propertyValue = eval('myObject.' + key);
+ if (keyID=='index') { }
+ // remain silent
+ else if (propertyValue instanceof Array)
+ {
+ objectToAppend[keyID] = propertyValue;
+ }
+ // Fake Item
+ else if (propertyValue instanceof Object)
+ {
+ for (newProperty in propertyValue)
+ {
+ propertyQueue.push(key + '.' + newProperty);
+ }
+ }
+ // Rename property Tag
+ else if (keyID == configuration.propertyTags[index])
+ {
+ var referenceIndex = configuration.propertyTags.indexOf(keyID);
+ var newKey = configuration.propertyNames[referenceIndex];
+ objectToAppend[newKey] = propertyValue;
+ }
+ // Label property
+ else if (keyID == configuration.propertyLabel[index])
+ {
+ objectToAppend.label = propertyValue;
+ }
+ // arbitrary property
+ else
+ {
+ objectToAppend[keyID] = propertyValue;
+ }
+ if (configuration.itemType[index])
+ {
+ objectToAppend.type = configuration.itemType[index];
+ }
+ else
+ {
+ objectToAppend.type='Item';
+ }
+
+ }
+ // MUST BE Item
+ else
+ {
+ newObject = eval('myObject.' + key);
+ if (newObject instanceof Array)
+ {
+ for (var i = 0; i < newObject.length; i++)
+ {
+ var object = newObject[i];
+ object.index = configuration.itemTag.indexOf(keyID);
+ // PARENT RELATION
+ if (configuration.parentRelation[object.index])
+ object[configuration.parentRelation[object.index]] = objectToAppend.label;
+ else
+ object['is a child of'] = objectToAppend.label;
+ itemQueue.push(object);
+ }
+ }
+ else
+ {
+ newObject.index = configuration.itemTag.indexOf(keyID);
+ if (configuration.parentRelation[newObject.index])
+ newObject[configuration.parentRelation[newObject.index]] = objectToAppend.label;
+ else
+ newObject['isChildOf'] = objectToAppend.label;
+ itemQueue.push(newObject);
+ }
+
+
+ }
+ }
+ exhibitJSON.items.push(objectToAppend);
+ }
+ return exhibitJSON;
+
+};
+
+Exhibit.jsonImporter.configure = function()
+{
+ var configuration =
+ {
+ 'itemTag': [],
+ 'propertyLabel': [],
+ 'itemType': [],
+ 'parentRelation': [],
+ 'propertyTags': [],
+ 'propertyNames': []
+
+
+ };
+
+ // get itemTag, propertyLabel, itemType, and parentRelation
+ $('link').each( function()
+ {
+ if (this.hasAttribute('ex:itemTag'))
+ {
+ configuration.itemTag = Exhibit.getAttribute(this,'ex:itemTag',',');
+ }
+ if (this.hasAttribute('ex:setPropertyAsLabel'))
+ {
+ configuration.propertyLabel = Exhibit.getAttribute(this,'ex:setPropertyAsLabel',',');
+ }
+ if (this.hasAttribute('ex:itemType'))
+ {
+ configuration.itemType = Exhibit.getAttribute(this,'ex:itemType',',');
+ }
+ if (this.hasAttribute('ex:parentRelation'))
+ {
+ configuration.parentRelation = Exhibit.getAttribute(this,'ex:parentRelation',',');
+ }
+ if (this.hasAttribute('ex:propertyNames'))
+ {
+ configuration.propertyNames = Exhibit.getAttribute(this,'ex:propertyNames',',');
+ }
+ if (this.hasAttribute('ex:propertyTags'))
+ {
+ configuration.propertyTags = Exhibit.getAttribute(this,'ex:propertyTags',',');
+ }
+
+ }
+ );
+
+ return configuration;
+};
+
+
+Exhibit.jsonImporter.load = function (link,database,cont)
+{
+ var self = this;
+ var url = typeof link == "string" ? link : link.href;
+ url = Exhibit.Persistence.resolveURL(url);
+ var fError = function(statusText, status, xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+ if (cont) cont();
+ };
+
+ var fDone = function() {
+ Exhibit.UI.hideBusyIndicator();
+ try {
+ var o = null;
+ try {
+ jsonDoc = Exhibit.jsonImporter.getjsonDocument(url);
+ var configuration = self.configure();
+ o = {
+ 'items': []
+ };
+ var root = self.findFirstItems(jsonDoc,configuration);
+ o = Exhibit.jsonImporter.getItems(root,o,configuration);
+
+
+ } catch (e) {
+ Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url, e), url);
+ }
+
+ if (o != null) {
+ database.loadData(o, Exhibit.Persistence.getBaseURL(url));
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error loading Exhibit JSON data from " + url);
+ }
+
+ finally {
+ if (cont) cont();
+ }
+ };
+
+ Exhibit.UI.showBusyIndicator();
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/jsonp-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/jsonp-importer.js
new file mode 100644
index 00000000..4531da83
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/jsonp-importer.js
@@ -0,0 +1,257 @@
+/*==================================================
+ * Exhibit.JSONPImporter
+ *==================================================
+ */
+
+Exhibit.JSONPImporter = {
+ _callbacks: {}
+};
+Exhibit.importers["application/jsonp"] = Exhibit.JSONPImporter;
+
+// cont gets called with the original feed (so you can pick up details from the
+// feed from user code that were of interest to you but not the exhibit itself,
+// for instance). load returns the callback that the JSONP payload should call,
+// so that even partial static JSONP implementations (with a fixed callback
+// name) can assign that variable with the return value, and things will
+// work out, as much as they can (i e concurrent requests can get mixed up).
+Exhibit.JSONPImporter.load = function(
+ link, database, cont, fConvert, staticJSONPCallback, charset
+) {
+ var url = link;
+ if (typeof link != "string") {
+ url = Exhibit.Persistence.resolveURL(link.href);
+ fConvert = Exhibit.getAttribute(link, "converter");
+ staticJSONPCallback = Exhibit.getAttribute(link, "jsonp-callback");
+ charset = Exhibit.getAttribute(link, "charset");
+ }
+ if (typeof fConvert == "string") {
+ var name = fConvert;
+ name = name.charAt(0).toLowerCase() + name.substring(1) + "Converter";
+ if (name in Exhibit.JSONPImporter) {
+ fConvert = Exhibit.JSONPImporter[name];
+ } else {
+ try {
+ fConvert = eval(fConvert);
+ } catch (e) {
+ fConvert = null;
+ // silent
+ }
+ }
+ }
+ if (fConvert != null && "preprocessURL" in fConvert) {
+ url = fConvert.preprocessURL(url);
+ }
+
+ var next = Exhibit.JSONPImporter._callbacks.next || 1;
+ Exhibit.JSONPImporter._callbacks.next = next + 1;
+
+ var callbackName = "cb" + next.toString(36);
+ var callbackURL = url;
+ if (callbackURL.indexOf("?") == -1)
+ callbackURL += "?";
+
+ var lastChar = callbackURL.charAt(callbackURL.length - 1);
+ if (lastChar != "=") {
+ if (lastChar != "&" && lastChar != "?")
+ callbackURL += "&";
+ callbackURL += "callback=";
+ }
+
+ var callbackFull = "Exhibit.JSONPImporter._callbacks." + callbackName;
+ callbackURL += callbackFull;
+ var cleanup = function( failedURL ) {
+ try {
+ Exhibit.UI.hideBusyIndicator();
+
+ delete Exhibit.JSONPImporter._callbacks[callbackName+"_fail"];
+ delete Exhibit.JSONPImporter._callbacks[callbackName];
+ if (script && script.parentNode) {
+ script.parentNode.removeChild(script);
+ }
+ } finally {
+ if (failedURL) {
+ prompt("Failed to load javascript file:", failedURL);
+ cont && cont(undefined); // got no json! signal with undefined
+ }
+ }
+ };
+
+ Exhibit.JSONPImporter._callbacks[callbackName+"_fail"] = cleanup;
+ Exhibit.JSONPImporter._callbacks[callbackName] = function(json) {
+ try {
+ cleanup(null);
+ database.loadData(fConvert ? fConvert(json, url, link) : json,
+ Exhibit.Persistence.getBaseURL(url));
+ } finally {
+ if (cont) cont(json);
+ }
+ };
+ if (staticJSONPCallback) { // fallback for partial JSONP support feeds
+ callbackURL = url; // url callback parameter not supported; do not pass
+ eval(staticJSONPCallback + "=" + callbackFull);
+ }
+
+ var fail = callbackFull + "_fail('"+ callbackURL +"');";
+ var script = SimileAjax.includeJavascriptFile(document,
+ callbackURL,
+ fail,
+ charset);
+ Exhibit.UI.showBusyIndicator();
+ return Exhibit.JSONPImporter._callbacks[callbackName];
+};
+
+// Does 90% of the feed conversion for 90% of all (well designed) JSONP feeds.
+// Pass the raw json object, an optional index to drill into to get at the
+// array of items ("feed.entry", in the case of Google Spreadsheets -- pass
+// null, if the array is already the top container, as in a Del.icio.us feed),
+// an object mapping the wanted item property name to the properties to pick
+// them up from, and an optional similar mapping with conversion callbacks to
+// perform on the data value before storing it in the item property. These
+// callback functions are invoked with the value, the object it was picked up
+// from, its index in the items array, the items array and the feed as a whole
+// (for the cases where you need to look up properties from the surroundings).
+// Returning the undefined value your converter means the property is not set.
+Exhibit.JSONPImporter.transformJSON = function(json, index, mapping, converters) {
+ var objects = json, items = [];
+ if (index) {
+ index = index.split(".");
+ while (index.length) {
+ objects = objects[index.shift()];
+ }
+ }
+ for (var i = 0, object; object = objects[i]; i++) {
+ var item = {};
+ for (var name in mapping) {
+ var index = mapping[name];
+ if (!mapping.hasOwnProperty(name) || // gracefully handle poisoned
+ !object.hasOwnProperty(index)) continue; // Object.prototype
+ var property = object[index];
+ if (converters && converters.hasOwnProperty(name)) {
+ property = converters[name](property, object, i, objects, json);
+ }
+ if (typeof property != "undefined") {
+ item[name] = property;
+ }
+ }
+ items.push(item);
+ }
+ return items;
+};
+
+Exhibit.JSONPImporter.deliciousConverter = function(json, url) {
+ var items = Exhibit.JSONPImporter.transformJSON(json, null,
+ { label:"u", note:"n", description:"d", tags:"t" });
+ return { items:items, properties:{ url:{ valueType:"url" } } };
+};
+
+Exhibit.JSONPImporter.googleSpreadsheetsConverter = function(json, url, link) {
+ var separator = ";";
+ if ((link) && (typeof link != "string")) {
+ var s = Exhibit.getAttribute(link, "separator");
+ if (s != null && s.length > 0) {
+ separator = s;
+ }
+ }
+
+ var items = [];
+ var properties = {};
+ var types = {};
+ var valueTypes = { "text" : true, "number" : true, "item" : true, "url" : true, "boolean" : true, "date" : true };
+
+ var entries = json.feed.entry || []; // if no entries in feed
+ for (var i = 0; i < entries.length; i++) {
+ var entry = entries[i];
+ var id = entry.id.$t;
+ var c = id.lastIndexOf("C");
+ var r = id.lastIndexOf("R");
+
+ entries[i] = {
+ row: parseInt(id.substring(r + 1, c)) - 1,
+ col: parseInt(id.substring(c + 1)) - 1,
+ val: entry.content.$t
+ };
+ }
+ var cellIndex = 0;
+ var getNextRow = function() {
+ if (cellIndex < entries.length) {
+ var firstEntry = entries[cellIndex++];
+ var row = [ firstEntry ];
+ while (cellIndex < entries.length) {
+ var nextEntry = entries[cellIndex];
+ if (nextEntry.row == firstEntry.row) {
+ row.push(nextEntry);
+ cellIndex++;
+ } else {
+ break;
+ }
+ }
+ return row;
+ }
+ return null;
+ };
+
+ var propertyRow = getNextRow();
+ if (propertyRow != null) {
+ var propertiesByColumn = [];
+ for (var i = 0; i < propertyRow.length; i++) {
+ var cell = propertyRow[i];
+
+ var fieldSpec = cell.val.trim().replace(/^\{/g, "").replace(/\}$/g, "").split(":");
+ var fieldName = fieldSpec[0].trim();
+ var fieldDetails = fieldSpec.length > 1 ? fieldSpec[1].split(",") : [];
+
+ var property = { single: false };
+
+ for (var d = 0; d < fieldDetails.length; d++) {
+ var detail = fieldDetails[d].trim();
+ if (detail in valueTypes) {
+ property.valueType = detail;
+ } else if (detail == "single") {
+ property.single = true;
+ }
+ }
+
+ propertiesByColumn[cell.col] = fieldName;
+ properties[fieldName] = property;
+ }
+
+ var row = null;
+ while ((row = getNextRow()) != null) {
+ var item = {};
+
+ for (var i = 0; i < row.length; i++) {
+ var cell = row[i];
+ var fieldName = propertiesByColumn[cell.col];
+ if (typeof fieldName == "string") {
+
+ // ensure round-trip iso8601 date strings through google docs
+ var googleDocsDateRegex = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
+ if (googleDocsDateRegex.exec(cell.val)) {
+ cell.val = Exhibit.Database.makeISO8601DateString(new Date(cell.val));
+ }
+
+ item[fieldName] = cell.val;
+
+ var property = properties[fieldName];
+ if (!property.single) {
+ var fieldValues = cell.val.split(separator);
+ for (var v = 0; v < fieldValues.length; v++) {
+ fieldValues[v] = fieldValues[v].trim();
+ }
+ item[fieldName] = fieldValues;
+ } else {
+ item[fieldName] = cell.val.trim();
+ }
+ }
+ }
+
+ items.push(item);
+ }
+ }
+
+ return { types:types, properties:properties, items:items };
+};
+
+Exhibit.JSONPImporter.googleSpreadsheetsConverter.preprocessURL = function(url) {
+ return url.replace(/\/list\//g, "/cells/");
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/rdfa-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/rdfa-importer.js
new file mode 100644
index 00000000..0394a9b4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/rdfa-importer.js
@@ -0,0 +1,138 @@
+/*==================================================
+ * Exhibit.RDFaImporter
+ * author: Keith Alexander (with the assistance of Johan Sundstr�m and Ben Adida)
+ *==================================================
+ */
+
+var RDFA = new Object();
+RDFA.url = 'http://www.w3.org/2006/07/SWD/RDFa/impl/js/20070301/rdfa.js';
+
+Exhibit.RDFaImporter = {
+};
+
+Exhibit.importers["application/RDFa"] = Exhibit.RDFaImporter;
+
+Exhibit.RDFaImporter.load = function(link, database, cont) {
+ try {
+ if ((link.getAttribute('href') || "").length == 0) {
+ // use current document
+ // not sure what to do about hiding the existing content - how to know what is exhibit markup, and what isn't?
+ Exhibit.RDFaImporter.loadRDFa(null, document, database);
+ } else {
+ iframe = document.createElement("iframe");
+ iframe.style.display = 'none';
+ iframe.setAttribute('onLoad', 'Exhibit.RDFaImporter.loadRDFa(this, this.contentDocument, database)');
+ iframe.src = link.href
+ document.body.appendChild(iframe);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ } finally {
+ if (cont) {
+ cont();
+ }
+ }
+};
+
+Exhibit.RDFaImporter.loadRDFa = function(iframe, rdfa, database) {
+ // helper functions
+ var textOf = function(n) { return n.textContent || n.innerText || ""; };
+ var readAttributes = function (node, attributes) {
+ var result = {}, found = false, attr, value, i;
+ for (i = 0; attr = attributes[i]; i++) {
+ value = Exhibit.getAttribute(node, attr);
+ if (value) {
+ result[attr] = value;
+ found = true;
+ }
+ }
+ return found && result;
+ };
+
+ // callback when the RDF/A parsing is done.
+ RDFA.CALLBACK_DONE_PARSING = function() {
+ if (iframe != null) {
+ document.body.removeChild(iframe);
+ }
+
+ this.cloneObject = function (what) {
+ for (var i in what) {
+ this[i] = what[i];
+ }
+ };
+
+ var triples = this.triples;
+ var parsed = { "classes": {}, "properties": {},"items": [] };
+ for (var i in triples) {
+ var item = {};
+
+ item['id'], item['uri'], item['label'] = i; // shouldn't have to do this, not sure if it's been fixed in the exporter or not yet
+
+ var tri = triples[i];
+ for (var j in tri) {
+ for (var k = 0; k < tri[j].length; k++) {
+ if (tri[j][k].predicate.ns) {
+ var p_label = tri[j][k].predicate.ns.prefix+':'+tri[j][k].predicate.suffix;
+
+ //item[p_label] = tri[j][k]['object'];
+
+ if (j == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') {
+ try {
+ var type_uri = tri[j][k]['object'];
+ var matches = type_uri.match(/(.+?)(#|\/)([a-zA-Z_]+)?$/);
+ var type_label = matches[3]+'('+matches[1]+')';
+ parsed['classes'][type_label] = {"label":type_label,"uri": type_uri}
+ item['type'] = type_label;
+ } catch(e) {
+ //ERRORS GO HERE
+ }
+ } else {
+ parsed['properties'][p_label] = { "uri": j, "label": tri[j][k]['predicate']['suffix'] };
+ try {
+ if (!item[p_label]) {
+ item[p_label] = [];
+ }
+ item[p_label].push(tri[j][k]['object']);
+ } catch(e) {
+ SimileAjax.Debug.log("problem adding property value: " + e);
+ }
+
+ if (j == 'http://purl.org/dc/elements/1.1/title' ||
+ j == 'http://www.w3.org/2000/01/rdf-schema#' ||
+ j == 'http://xmlns.com/foaf/0.1/name') {
+ item.label = item[p_label];
+ }
+ }
+ }
+ else {
+ item[j] = tri[j][k]['object'];
+ }
+ }
+ }
+
+ parsed['items'].push(new this.cloneObject(item));
+ }
+ database.loadData(parsed, Exhibit.Persistence.getBaseURL(document.location.href));
+ }
+
+ // callback when the RDF/A loading is done.
+ RDFA.CALLBACK_DONE_LOADING = function() {
+ RDFA.parse(rdfa);
+ };
+
+ /**
+ * Dynamically include the
+ *
+ * RDFa Javascript parser
+ *
+ * Ben Adida - ben@mit.edu
+ * 2006-03-21
+ * 2006-05-22 moved to W3C
+ *
+ * licensed under GPL v2
+ *
+ * Dynamic include nullifies license incompatibility.
+ */
+
+ SimileAjax.includeJavascriptFile(document, RDFA.url);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/tsv-csv-importer.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/tsv-csv-importer.js
new file mode 100644
index 00000000..e0435746
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/data/importers/tsv-csv-importer.js
@@ -0,0 +1,198 @@
+Exhibit.TsvCsvImporter = {
+};
+
+//the importer will be called with any of the following MIME types
+Exhibit.importers["text/comma-separated-values"] = Exhibit.TsvCsvImporter;
+Exhibit.importers["text/csv"] = Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tab-separated-values"] = Exhibit.TsvCsvImporter;
+Exhibit.importers["text/tsv"] = Exhibit.TsvCsvImporter;
+
+
+Exhibit.TsvCsvImporter.load = function(link, database, cont) {
+ var url = typeof link == "string" ? link : link.href;
+ url = Exhibit.Persistence.resolveURL(url);
+ var type = link.type.substring(link.type.indexOf("/")+1); //type of data (either tsv or csv)
+ var hasColumnTitles = Exhibit.getAttribute(link, "hasColumnTitles")!=null? Exhibit.getAttribute(link, "hasColumnTitles") : true; // false if ex:hasColumnTitles is set to false, otherwise the default value is true
+ var expressionString = Exhibit.getAttribute(link, "properties"); //null if no ex:properties attribute is given in the html documents
+
+ var fError = function(statusText, status, xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ Exhibit.UI.showHelp(Exhibit.l10n.failedToLoadDataFileMessage(url));
+ if (cont) cont();
+ };
+
+ var fDone = function(xmlhttp) {
+ Exhibit.UI.hideBusyIndicator();
+ try {
+ var o = null;
+ try {
+ var text = xmlhttp.responseText; //the text retrieved from the link
+ o = eval(Exhibit.TsvCsvImporter.parseTsvCsv(text, type, expressionString, hasColumnTitles)); //text is converted to Exhibit JSON
+ } catch (e) {
+ Exhibit.UI.showJsonFileValidation(Exhibit.l10n.badJsonMessage(url, e), url);
+ }
+
+ if (o != null) {
+ database.loadData(o, Exhibit.Persistence.getBaseURL(url));
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error loading tsv/csv data from " + url);
+ } finally {
+ if (cont) cont();
+ }
+ };
+
+ Exhibit.UI.showBusyIndicator();
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+
+}
+
+Exhibit.TsvCsvImporter.parseTsvCsv = function(text, format, expressionString, hasColumnTitles) {
+ var separator = Exhibit.TsvCsvImporter.formatType(format); // type of separator ("," or "/t")
+
+ var lines = text.split("\n");
+ var rest; //array containing the data excluding the column titles
+
+ var hasPropertyListAttribute = expressionString!=null; //boolean that is false unless the ex:properties attribute is specified
+ var exString;
+ var propertyRow;
+
+ if (hasPropertyListAttribute){ //if the data is in tsv format, the comma-separated list of the ex:properties attribute must become a tab-separated string
+ exString = Exhibit.TsvCsvImporter.replaceAll(expressionString, ",", separator)
+ }
+
+ if (hasPropertyListAttribute){ //if the ex:properties attribute is specified, the string becomes the column header row
+ propertyRow = exString.split(separator);
+ if(hasColumnTitles=="false"){
+ rest = lines;
+ }else{ //if there is a header row in the data file, the first row must be removed and the list of property names given in ex:properties will override it
+ rest = lines.slice(1);
+ }
+ }else{
+ if (hasColumnTitles=="false"){ //if there is no header row in the file and no ex:properties attribute is specified, the user is notified that the column names are required
+ alert("No header row was given for the property names. Either specify them in the ex:properties attribute or add a header row to the file.");
+ return;
+ }
+ else{
+ propertyRow = lines[0].split(separator);
+ rest = lines.slice(1);
+ }
+ }
+
+ while (rest[rest.length-1]==""){ //removes empty rows at the end
+ rest = rest.slice(0,rest.length-1);
+ }
+ var properties = Exhibit.TsvCsvImporter.getProperties(propertyRow);
+ var items = Exhibit.TsvCsvImporter.getItems(separator, rest, propertyRow);
+
+ var json = {"properties":properties, "items":items}; //data converted to Exhibit JSON
+ return json;
+ }
+
+
+Exhibit.TsvCsvImporter.formatType = function(format) { //function that returns the right separator according to the MIME type specified in the html document
+ var separator = "";
+ if (format == "tab-separated-values" || format == "tsv"){
+ separator = separator.concat("\t");
+ }
+ else if (format == "comma-separated-values" || format == "csv"){
+ separator = separator.concat(",");
+ }else{
+ alert("invalid format, must be tsv or csv");
+ }
+ return separator;
+ }
+
+Exhibit.TsvCsvImporter.getProperties = function(propertyRow) { //function that parses the array of properties and returns the properties in Exhibit JSON format
+ var properties = {};
+ var valueTypes = { "text" : true, "number" : true, "item" : true, "url" : true, "boolean" : true, "date" : true }; //possible value types for the properties
+
+ for (i = 0; i<propertyRow.length; i++){
+ var prop = propertyRow[i];
+ var type = "";
+
+ if (prop.match(":")){
+ var t = prop.substring(prop.lastIndexOf(":") + 1);
+ prop = prop.substring(0, prop.lastIndexOf(":"));
+ if (t in valueTypes){
+ type = t;
+ }else{
+ type = "text"; //if the value type that is specified is not contained in valueTypes, it is set to text
+ }
+ }else{
+ type = "text"; //the default value type is text
+ }
+ properties[prop] = {"valueType":type}; //each property and its corresponding valueType are added to properties object
+ }
+ return properties
+ }
+
+
+Exhibit.TsvCsvImporter.getItems = function(separator, rest, propertyRow){
+ var items = [];
+ var listSeparator = ";";
+
+ for (i = 0; i<rest.length; i++){
+ var row = rest[i].split(separator);
+
+ if (separator==","){ //in csv data, commas within the data are escaped using double-quote characters, for example "Boston, MA" should not be split at the comma
+ var quotes = false; //boolean that is set to true when the first double-quote is encountered
+ for (var j = 0; j < row.length; j++){ //this for loop fixes each row if the elements were separated incorrectly due to presences of commas in the text
+ if (row[j].indexOf('"')==0 && row[j][row[j].length-1]!='"'){
+ quotes = true;
+ var x = j
+ while (quotes){
+ joined = [row[x] + "," + row[x+1]];
+ row = row.slice(0,x).concat(joined, row.slice(x+2));
+ if (row[x][row[x].length-1]=='"'){
+ quotes=false; //boolean is set to false when the ending double-quote character is found
+ }
+ }
+ }
+
+ }
+ }
+
+
+ if (row.length < propertyRow.length){
+ while (row.length!=propertyRow.length){
+ row.push(""); //adds empty strings to the row if some of the ending property fields are missing
+ }
+ }
+ var item = {}; // variable that stores each item's property values
+
+ for (var j = 0; j < propertyRow.length; j++){
+ var values = row[j];
+
+ values = Exhibit.TsvCsvImporter.replaceAll(values, '""', '"');
+ if(values[0]=='"'){
+ values = values.slice(1);
+ }
+ if(values[values.length-1]=='"'){
+ values = values.slice(0,values.length-1);
+ }
+
+ var fieldValues = values.split(listSeparator); // array of field values for each property
+ if (fieldValues.length > 1){
+ for (var k = 0; k < fieldValues.length; k++){
+ while (fieldValues[k][0]==" "){ //removes leading white spaces from each field value
+ fieldValues[k] = fieldValues[k].slice(1);
+ }
+ }
+ }
+ var property = propertyRow[j]; //retrieves the corresponding property name
+ var fieldname = property.match(":") ? property.substring(0, property.lastIndexOf(":")): property;
+ item[fieldname]= fieldValues; //stores the field values associated with the corresponding property in the item object
+ }
+ items.push(item); //current item is added to the end of the items array
+ }
+ return items;
+}
+
+
+Exhibit.TsvCsvImporter.replaceAll = function(string, toBeReplaced, replaceWith) { //function that replaces all the occurrences of "toBeReplaced" in the string with "replacedWith"
+ var regex = "/"+toBeReplaced+"/g";
+ return string.replace(eval(regex),replaceWith);
+}
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/exhibit.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/exhibit.js
new file mode 100644
index 00000000..ef97aeae
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/exhibit.js
@@ -0,0 +1,395 @@
+/*======================================================================
+ * Exhibit
+ * http://simile.mit.edu/wiki/Exhibit/API/Exhibit
+ *======================================================================
+ */
+
+Exhibit.create = function(database) {
+ return new Exhibit._Impl(database);
+};
+
+Exhibit.getAttribute = function(elmt, name, splitOn) {
+ try {
+ var value = elmt.getAttribute(name);
+ if (value == null || value.length == 0) {
+ value = elmt.getAttribute("ex:" + name);
+ if (value == null || value.length == 0) {
+ return null;
+ }
+ }
+ if (splitOn == null) {
+ return value;
+ }
+ var values = value.split(splitOn);
+ for (var i = 0; value = values[i]; i++) {
+ values[i] = value.trim();
+ }
+ return values;
+ } catch(e) {
+ return null;
+ }
+};
+
+Exhibit.getRoleAttribute = function(elmt) {
+ var role = Exhibit.getAttribute(elmt, "role") || "";
+ role = role.replace(/^exhibit-/, "");
+ return role;
+};
+
+Exhibit.getConfigurationFromDOM = function(elmt) {
+ var c = Exhibit.getAttribute(elmt, "configuration");
+ if (c != null && c.length > 0) {
+ try{
+ var o = eval(c);
+ if (typeof o == "object") {
+ return o;
+ }
+ } catch (e) {}
+ }
+ return {};
+};
+
+Exhibit.extractOptionsFromElement = function(elmt) {
+ var opts = {};
+ var attrs = elmt.attributes;
+ for (var i in attrs) {
+ if (attrs.hasOwnProperty(i)) {
+ var name = attrs[i].nodeName;
+ var value = attrs[i].nodeValue;
+ if (name.indexOf('ex:') == 0) {
+ name = name.substring(3);
+ }
+ opts[name] = value;
+ }
+ }
+ return opts;
+}
+
+Exhibit.getExporters = function() {
+ Exhibit._initializeExporters();
+ return [].concat(Exhibit._exporters);
+};
+
+Exhibit.addExporter = function(exporter) {
+ Exhibit._initializeExporters();
+ Exhibit._exporters.push(exporter);
+};
+
+Exhibit._initializeExporters = function() {
+ if (!("_exporters" in Exhibit)) {
+ Exhibit._exporters = [
+ Exhibit.RdfXmlExporter,
+ Exhibit.SemanticWikitextExporter,
+ Exhibit.TSVExporter,
+ Exhibit.ExhibitJsonExporter,
+ Exhibit.FacetSelectionExporter
+ ];
+ }
+};
+
+/*==================================================
+ * Exhibit._Impl
+ *==================================================
+ */
+Exhibit._Impl = function(database) {
+ this._database = database != null ?
+ database :
+ ("database" in window ?
+ window.database :
+ Exhibit.Database.create());
+
+ this._uiContext = Exhibit.UIContext.createRootContext({}, this);
+ this._collectionMap = {};
+ this._componentMap= {};
+
+ this._historyListener = {
+ onBeforePerform: function(action) { if(action.lengthy) { Exhibit.UI.showBusyIndicator();} },
+ onAfterPerform: function(action) { if(action.lengthy) { Exhibit.UI.hideBusyIndicator();} },
+ onBeforeUndoSeveral: function() { Exhibit.UI.showBusyIndicator();},
+ onAfterUndoSeveral: function() { Exhibit.UI.hideBusyIndicator();},
+ onBeforeRedoSeveral: function() { Exhibit.UI.showBusyIndicator();},
+ onAfterRedoSeveral: function() { Exhibit.UI.hideBusyIndicator();}
+ };
+ SimileAjax.History.addListener(this._historyListener);
+};
+
+Exhibit._Impl.prototype.dispose = function() {
+ SimileAjax.History.removeListener(this._historyListener);
+
+ for (var id in this._componentMap) {
+ try{
+ this._componentMap[id].dispose();
+ }catch(e) {
+ SimileAjax.Debug.exception(e, "Failed to dispose component");
+ }
+ }
+ for (var id in this._collectionMap) {
+ try{
+ this._collectionMap[id].dispose();
+ } catch(e) {
+ SimileAjax.Debug.exception(e, "Failed to dispose collection");
+ }
+ }
+
+ this._uiContext.dispose();
+
+ this._componentMap = null;
+ this._collectionMap = null;
+ this._uiContext = null;
+ this._database = null;
+};
+
+Exhibit._Impl.prototype.getDatabase = function() {
+ return this._database;
+};
+
+Exhibit._Impl.prototype.getUIContext = function() {
+ return this._uiContext;
+};
+
+Exhibit._Impl.prototype.getCollection = function(id) {
+ var collection = this._collectionMap[id];
+ if (collection == null && id == "default") {
+ collection = Exhibit.Collection.createAllItemsCollection(id, this._database);
+ this.setDefaultCollection(collection);
+ }
+ return collection;
+};
+
+Exhibit._Impl.prototype.getDefaultCollection = function() {
+ return this.getCollection("default");
+};
+
+Exhibit._Impl.prototype.setCollection = function(id, c) {
+ if (id in this._collectionMap) {
+ try{
+ this._collectionMap[id].dispose();
+ } catch(e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+ this._collectionMap[id] = c;
+};
+
+Exhibit._Impl.prototype.setDefaultCollection = function(c) {
+ this.setCollection("default", c);
+};
+
+Exhibit._Impl.prototype.getComponent = function(id) {
+ return this._componentMap[id];
+};
+
+Exhibit._Impl.prototype.setComponent = function(id, c) {
+ if (id in this._componentMap) {
+ try{
+ this._componentMap[id].dispose();
+ } catch(e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+
+ this._componentMap[id] = c;
+};
+
+Exhibit._Impl.prototype.disposeComponent = function(id) {
+ if (id in this._componentMap) {
+ try{
+ this._componentMap[id].dispose();
+ } catch(e) {
+ SimileAjax.Debug.exception(e);
+ }
+ delete this._componentMap[id];
+ }
+};
+
+Exhibit._Impl.prototype.configure = function(configuration) {
+ if ("collections" in configuration) {
+ for (var i = 0; i < configuration.collections.length; i++) {
+ var config = configuration.collections[i];
+ var id = config.id;
+ if (id == null || id.length == 0) {
+ id = "default";
+ }
+ this.setCollection(id, Exhibit.Collection.create2(id, config, this._uiContext));
+ }
+ }
+ if ("components" in configuration) {
+ for (var i = 0; i < configuration.components.length; i++) {
+ var config = configuration.components[i];
+ var component = Exhibit.UI.create(config, config.elmt, this._uiContext);
+ if (component != null) {
+ var id = elmt.id;
+ if (id == null || id.length == 0) {
+ id = "component" + Math.floor(Math.random() * 1000000);
+ }
+ this.setComponent(id, component);
+ }
+ }
+ }
+};
+
+/**
+ * Set up this Exhibit's view from its DOM configuration.
+ * @param {Node} root optional root node, below which configuration gets read
+ * (defaults to document.body, when none provided)
+ */
+Exhibit._Impl.prototype.configureFromDOM = function(root) {
+ var collectionElmts = [];
+ var coderElmts = [];
+ var coordinatorElmts = [];
+ var lensElmts = [];
+ var facetElmts = [];
+ var otherElmts = [];
+ var f = function(elmt) {
+ var role = Exhibit.getRoleAttribute(elmt);
+ if (role.length > 0) {
+ switch (role) {
+ case "collection": collectionElmts.push(elmt); break;
+ case "coder": coderElmts.push(elmt); break;
+ case "coordinator": coordinatorElmts.push(elmt); break;
+ case "lens":
+ case "submission-lens":
+ case "edit-lens": lensElmts.push(elmt); break;
+ case "facet": facetElmts.push(elmt); break;
+ default:
+ otherElmts.push(elmt);
+ }
+ } else {
+ var node = elmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ f(node);
+ }
+ node=node.nextSibling;
+ }
+ }
+ };
+ f(root || document.body);
+
+ var uiContext = this._uiContext;
+ for (var i = 0; i < collectionElmts.length; i++) {
+ var elmt = collectionElmts[i];
+ var id = elmt.id;
+ if (id == null || id.length == 0) {
+ id = "default";
+ }
+ this.setCollection(id, Exhibit.Collection.createFromDOM2(id, elmt, uiContext));
+ }
+
+ var self = this;
+ var processElmts = function(elmts) {
+ for (var i = 0; i < elmts.length; i++) {
+ var elmt = elmts[i];
+ try {
+ var component = Exhibit.UI.createFromDOM(elmt, uiContext);
+ if (component != null) {
+ var id = elmt.id;
+ if (id == null || id.length == 0) {
+ id = "component" + Math.floor(Math.random() * 1000000);
+ }
+ self.setComponent(id, component);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+ };
+ processElmts(coordinatorElmts);
+ processElmts(coderElmts);
+ processElmts(lensElmts);
+ processElmts(facetElmts);
+ processElmts(otherElmts);
+
+ this.importSettings();
+
+ var exporters = Exhibit.getAttribute(document.body, "exporters");
+ if (exporters != null) {
+ exporters = exporters.split(";");
+ for (var i = 0; i < exporters.length; i++) {
+ var expr = exporters[i];
+ var exporter = null;
+
+ try {
+ exporter = eval(expr);
+ } catch (e) {}
+
+ if (exporter == null) {
+ try { exporter = eval(expr + "Exporter"); } catch (e) {}
+ }
+
+ if (exporter == null) {
+ try { exporter = eval("Exhibit." + expr + "Exporter"); } catch (e) {}
+ }
+
+ if (typeof exporter == "object") {
+ Exhibit.addExporter(exporter);
+ }
+ }
+ }
+
+ var hash = document.location.hash;
+ if (hash.length > 1) {
+ var itemID = decodeURIComponent(hash.substr(1));
+ if (this._database.containsItem(itemID)) {
+ this._showFocusDialogOnItem(itemID);
+ }
+ }
+};
+
+Exhibit._Impl.prototype._showFocusDialogOnItem = function(itemID) {
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ "<div class='exhibit-focusDialog-viewContainer' id='lensContainer'>" +
+ "</div>" +
+ "<div class='exhibit-focusDialog-controls'>" +
+ "<button id='closeButton'>" +
+ Exhibit.l10n.focusDialogBoxCloseButtonLabel +
+ "</button>" +
+ "</div>"
+ );
+ dom.elmt.className = "exhibit-focusDialog exhibit-ui-protection";
+ dom.close = function() {
+ document.body.removeChild(dom.elmt);
+ };
+ dom.layer = SimileAjax.WindowManager.pushLayer(function() { dom.close(); }, false);
+
+ var itemLens = this._uiContext.getLensRegistry().createLens(itemID, dom.lensContainer, this._uiContext);
+
+ dom.elmt.style.top = (document.body.scrollTop + 100) + "px";
+ document.body.appendChild(dom.elmt);
+
+ SimileAjax.WindowManager.registerEvent(
+ dom.closeButton,
+ "click",
+ function(elmt, evt, target) { SimileAjax.WindowManager.popLayer(dom.layer); },
+ dom.layer
+ );
+};
+
+Exhibit._Impl.prototype.exportSettings = function() {
+ var facetSelections = {},
+ facetSettings = '';
+ for (var id in this._componentMap) {
+ if (typeof this._componentMap[id].exportFacetSelection !== 'undefined') {
+ facetSettings = this._componentMap[id].exportFacetSelection() || false;
+ if (facetSettings) {
+ facetSelections[id] = facetSettings;
+ }
+ }
+ }
+ return facetSelections;
+};
+
+Exhibit._Impl.prototype.importSettings = function() {
+ if (window.location.search.length > 0) {
+ searchComponents = window.location.search.substr(1, window.location.search.length-1).split('&');
+ for(var x = 0; x < searchComponents.length; x++) {
+ var component = searchComponents[x].split('=');
+ var componentId = component[0];
+ var componentSelection = unescape(component[1]);
+ if (this._componentMap[componentId] && (typeof this._componentMap[componentId].importFacetSelection !== 'undefined')) {
+ this._componentMap[componentId].importFacetSelection(componentSelection);
+ }
+ }
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/persistence.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/persistence.js
new file mode 100644
index 00000000..c0a37116
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/persistence.js
@@ -0,0 +1,83 @@
+/*======================================================================
+ * Persistence Utility Functions
+ *======================================================================
+ */
+Exhibit.Persistence = {};
+
+Exhibit.Persistence.getBaseURL = function(url) {
+ // HACK: for some unknown reason Safari keeps throwing
+ // TypeError: no default value
+ // when this function is called from the RDFa importer. So I put a try catch here.
+ try {
+ if (url.indexOf("://") < 0) {
+ var url2 = Exhibit.Persistence.getBaseURL(document.location.href);
+ if (url.substr(0,1) == "/") {
+ url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
+ } else {
+ url = url2 + url;
+ }
+ }
+
+ var i = url.lastIndexOf("/");
+ if (i < 0) {
+ return "";
+ } else {
+ return url.substr(0, i+1);
+ }
+ } catch (e) {
+ return url;
+ }
+};
+
+Exhibit.Persistence.resolveURL = function(url) {
+ if (url.indexOf("://") < 0) {
+ var url2 = Exhibit.Persistence.getBaseURL(document.location.href);
+ if (url.substr(0,1) == "/") {
+ url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
+ } else {
+ url = url2 + url;
+ }
+ }
+ return url;
+};
+
+Exhibit.Persistence.getURLWithoutQueryAndHash = function() {
+ var url;
+ if ("_urlWithoutQueryAndHash" in Exhibit) {
+ url = Exhibit.Persistence._urlWithoutQueryAndHash;
+ } else {
+ url = document.location.href;
+
+ var hash = url.indexOf("#");
+ var question = url.indexOf("?");
+ if (question >= 0) {
+ url = url.substr(0, question);
+ } else if (hash >= 0) {
+ url = url.substr(0, hash);
+ }
+
+ Exhibit.Persistence._urlWithoutQueryAndHash = url;
+ }
+ return url;
+};
+
+Exhibit.Persistence.getURLWithoutQuery = function() {
+ var url;
+ if ("_urlWithoutQuery" in Exhibit.Persistence) {
+ url = Exhibit.Persistence._urlWithoutQuery;
+ } else {
+ url = document.location.href;
+
+ var question = url.indexOf("?");
+ if (question >= 0) {
+ url = url.substr(0, question);
+ }
+
+ Exhibit.Persistence._urlWithoutQuery = url;
+ }
+ return url;
+};
+
+Exhibit.Persistence.getItemLink = function(itemID) {
+ return Exhibit.Persistence.getURLWithoutQueryAndHash() + "#" + encodeURIComponent(itemID);
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-coder.js
new file mode 100644
index 00000000..23871798
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-coder.js
@@ -0,0 +1,161 @@
+/*==================================================
+ * Exhibit.ColorCoder
+ *==================================================
+ */
+
+Exhibit.ColorCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._map = {};
+ this._mixedCase = {
+ label: Exhibit.Coders.l10n.mixedCaseLabel,
+ color: Exhibit.Coders.mixedCaseColor
+ };
+ this._missingCase = {
+ label: Exhibit.Coders.l10n.missingCaseLabel,
+ color: Exhibit.Coders.missingCaseColor
+ };
+ this._othersCase = {
+ label: Exhibit.Coders.l10n.othersCaseLabel,
+ color: Exhibit.Coders.othersCaseColor
+ };
+};
+
+Exhibit.ColorCoder._settingSpecs = {
+};
+
+Exhibit.ColorCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.ColorCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.ColorCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.ColorCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.ColorCoder._settingSpecs, coder._settings);
+
+ try {
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "color"));
+ }
+ node = node.nextSibling;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "ColorCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.ColorCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.ColorCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.ColorCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].color);
+ }
+ }
+}
+
+Exhibit.ColorCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.ColorCoder._colorTable = {
+ "red" : "#ff0000",
+ "green" : "#00ff00",
+ "blue" : "#0000ff",
+ "white" : "#ffffff",
+ "black" : "#000000",
+ "gray" : "#888888"
+};
+
+Exhibit.ColorCoder.prototype._addEntry = function(kase, key, color) {
+ if (color in Exhibit.ColorCoder._colorTable) {
+ color = Exhibit.ColorCoder._colorTable[color];
+ }
+
+ var entry = null;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "mixed": entry = this._mixedCase; break;
+ case "missing": entry = this._missingCase; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.color = color;
+ } else {
+ this._map[key] = { color: color };
+ }
+};
+
+Exhibit.ColorCoder.prototype.translate = function(key, flags) {
+ if (key in this._map) {
+ if (flags) flags.keys.add(key);
+ return this._map[key].color;
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.color;
+ }
+};
+
+Exhibit.ColorCoder.prototype.translateSet = function(keys, flags) {
+ var color = null;
+ var self = this;
+ keys.visit(function(key) {
+ var color2 = self.translate(key, flags);
+ if (color == null) {
+ color = color2;
+ } else if (color != color2) {
+ if (flags) flags.mixed = true;
+ color = self._mixedCase.color;
+ return true;
+ }
+ return false;
+ });
+
+ if (color != null) {
+ return color;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ }
+};
+
+Exhibit.ColorCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.ColorCoder.prototype.getOthersColor = function() {
+ return this._othersCase.color;
+};
+
+Exhibit.ColorCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.ColorCoder.prototype.getMissingColor = function() {
+ return this._missingCase.color;
+};
+
+Exhibit.ColorCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.ColorCoder.prototype.getMixedColor = function() {
+ return this._mixedCase.color;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-gradient-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-gradient-coder.js
new file mode 100644
index 00000000..616c5ef2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/color-gradient-coder.js
@@ -0,0 +1,185 @@
+/*==================================================
+ * Exhibit.ColorGradientCoder
+ *==================================================
+ */
+
+Exhibit.ColorGradientCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._gradientPoints = [];
+ this._mixedCase = {
+ label: Exhibit.Coders.l10n.mixedCaseLabel,
+ color: Exhibit.Coders.mixedCaseColor
+ };
+ this._missingCase = {
+ label: Exhibit.Coders.l10n.missingCaseLabel,
+ color: Exhibit.Coders.missingCaseColor
+ };
+ this._othersCase = {
+ label: Exhibit.Coders.l10n.othersCaseLabel,
+ color: Exhibit.Coders.othersCaseColor
+ };
+};
+
+Exhibit.ColorGradientCoder._settingSpecs = {
+};
+
+Exhibit.ColorGradientCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.ColorGradientCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.ColorGradientCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.ColorGradientCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.ColorGradientCoder._settingSpecs, coder._settings);
+
+ try {
+ var gradientPoints = Exhibit.getAttribute(configElmt, "gradientPoints", ";")
+ for (var i = 0; i < gradientPoints.length; i++) {
+ var point = gradientPoints[i];
+ var value = parseFloat(point);
+ var colorIndex = point.indexOf("#") + 1;
+ var red = parseInt(point.slice(colorIndex, colorIndex + 2), 16);
+ var green = parseInt(point.slice(colorIndex + 2, colorIndex + 4), 16);
+ var blue = parseInt(point.slice(colorIndex + 4), 16);
+ coder._gradientPoints.push({ value: value, red: red, green: green, blue: blue });
+ }
+
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "color"));
+ }
+ node = node.nextSibling;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "ColorGradientCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.ColorGradientCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.ColorGradientCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.ColorGradientCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].color);
+ }
+ }
+}
+
+Exhibit.ColorGradientCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.ColorGradientCoder.prototype._addEntry = function(kase, key, color) {
+ var entry = null;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "mixed": entry = this._mixedCase; break;
+ case "missing": entry = this._missingCase; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.color = color;
+ }
+};
+
+Exhibit.ColorGradientCoder.prototype.translate = function(key, flags) {
+ var gradientPoints = this._gradientPoints;
+ var getColor = function(key) {
+ if (key.constructor != Number) {
+ key = parseFloat(key);
+ }
+ for (j = 0; j < gradientPoints.length; j++) {
+ if (key == gradientPoints[j].value) {
+ return rgbToHex(gradientPoints[j].red, gradientPoints[j].green, gradientPoints[j].blue);
+ } else if (gradientPoints[j+1] != null) {
+ if (key < gradientPoints[j+1].value) {
+ var fraction = (key - gradientPoints[j].value)/(gradientPoints[j+1].value - gradientPoints[j].value);
+ var newRed = Math.floor(gradientPoints[j].red + fraction*(gradientPoints[j+1].red - gradientPoints[j].red));
+ var newGreen = Math.floor(gradientPoints[j].green + fraction*(gradientPoints[j+1].green - gradientPoints[j].green));
+ var newBlue = Math.floor(gradientPoints[j].blue + fraction*(gradientPoints[j+1].blue - gradientPoints[j].blue));
+ return rgbToHex(newRed, newGreen, newBlue)
+ }
+ }
+ }
+ }
+
+ var rgbToHex = function(r, g, b) {
+ var decToHex = function(n) {
+ if (n == 0) {return "00"}
+ else {return n.toString(16)}
+ }
+ return "#" + decToHex(r) + decToHex(g) + decToHex(b);
+ }
+
+ if (key >= gradientPoints[0].value & key <= gradientPoints[gradientPoints.length-1].value) {
+ if (flags) flags.keys.add(key);
+ return getColor(key);
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.color;
+ }
+};
+
+Exhibit.ColorGradientCoder.prototype.translateSet = function(keys, flags) {
+ var color = null;
+ var self = this;
+ keys.visit(function(key) {
+ var color2 = self.translate(key, flags);
+ if (color == null) {
+ color = color2;
+ } else if (color != color2) {
+ if (flags) flags.mixed = true;
+ color = self._mixedCase.color;
+ return true;
+ }
+ return false;
+ });
+
+ if (color != null) {
+ return color;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ }
+};
+
+Exhibit.ColorGradientCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getOthersColor = function() {
+ return this._othersCase.color;
+};
+
+Exhibit.ColorGradientCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMissingColor = function() {
+ return this._missingCase.color;
+};
+
+Exhibit.ColorGradientCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.ColorGradientCoder.prototype.getMixedColor = function() {
+ return this._mixedCase.color;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/default-color-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/default-color-coder.js
new file mode 100644
index 00000000..d013a361
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/default-color-coder.js
@@ -0,0 +1,83 @@
+/*==================================================
+ * Exhibit.DefaultColorCoder
+ *==================================================
+ */
+
+Exhibit.DefaultColorCoder = function(uiContext) {
+};
+
+Exhibit.DefaultColorCoder.colors = [
+ "#FF9000",
+ "#5D7CBA",
+ "#A97838",
+ "#8B9BBA",
+ "#FFC77F",
+ "#003EBA",
+ "#29447B",
+ "#543C1C"
+];
+Exhibit.DefaultColorCoder._map = {};
+Exhibit.DefaultColorCoder._nextColor = 0;
+
+Exhibit.DefaultColorCoder.prototype.translate = function(key, flags) {
+ if (key == null) {
+ if (flags) flags.missing = true;
+ return Exhibit.Coders.missingCaseColor;
+ } else {
+ if (flags) flags.keys.add(key);
+ if (key in Exhibit.DefaultColorCoder._map) {
+ return Exhibit.DefaultColorCoder._map[key];
+ } else {
+ var color = Exhibit.DefaultColorCoder.colors[Exhibit.DefaultColorCoder._nextColor];
+ Exhibit.DefaultColorCoder._nextColor =
+ (Exhibit.DefaultColorCoder._nextColor + 1) % Exhibit.DefaultColorCoder.colors.length;
+
+ Exhibit.DefaultColorCoder._map[key] = color;
+ return color;
+ }
+ }
+};
+
+Exhibit.DefaultColorCoder.prototype.translateSet = function(keys, flags) {
+ var color = null;
+ var self = this;
+ keys.visit(function(key) {
+ var color2 = self.translate(key, flags);
+ if (color == null) {
+ color = color2;
+ } else if (color != color2) {
+ color = Exhibit.Coders.mixedCaseColor;
+ flags.mixed = true;
+ return true; // exit visitation
+ }
+ return false;
+ });
+
+ if (color != null) {
+ return color;
+ } else {
+ flags.missing = true;
+ return Exhibit.Coders.missingCaseColor;
+ }
+};
+
+Exhibit.DefaultColorCoder.prototype.getOthersLabel = function() {
+ return Exhibit.Coders.l10n.othersCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getOthersColor = function() {
+ return Exhibit.Coders.othersCaseColor;
+};
+
+Exhibit.DefaultColorCoder.prototype.getMissingLabel = function() {
+ return Exhibit.Coders.l10n.missingCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMissingColor = function() {
+ return Exhibit.Coders.missingCaseColor;
+};
+
+Exhibit.DefaultColorCoder.prototype.getMixedLabel = function() {
+ return Exhibit.Coders.l10n.mixedCaseLabel;
+};
+Exhibit.DefaultColorCoder.prototype.getMixedColor = function() {
+ return Exhibit.Coders.mixedCaseColor;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/icon-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/icon-coder.js
new file mode 100644
index 00000000..68a400c6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/icon-coder.js
@@ -0,0 +1,148 @@
+/*==================================================
+ * Exhibit.IconCoder
+ *==================================================
+ */
+
+Exhibit.IconCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._map = {};
+ this._mixedCase = { label: "mixed", icon: null };
+ this._missingCase = { label: "missing", icon: null };
+ this._othersCase = { label: "others", icon: null };
+};
+
+Exhibit.IconCoder._settingSpecs = {
+};
+
+Exhibit.IconCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.IconCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.IconCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.IconCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.IconCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.IconCoder._settingSpecs, coder._settings);
+
+ try {
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "icon"));
+ }
+ node = node.nextSibling;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "IconCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.IconCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.IconCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.IconCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].icon);
+ }
+ }
+}
+
+Exhibit.IconCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.IconCoder._iconTable = {
+ // add built-in icons?
+};
+
+Exhibit.IconCoder.prototype._addEntry = function(kase, key, icon) {
+ // used if there are built-in icons
+ if (icon in Exhibit.IconCoder._iconTable) {
+ icon = Exhibit.IconCoder._iconTable[icon];
+ }
+
+ var entry = null;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "mixed": entry = this._mixedCase; break;
+ case "missing": entry = this._missingCase; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.icon = icon;
+ } else {
+ this._map[key] = { icon: icon };
+ }
+};
+
+Exhibit.IconCoder.prototype.translate = function(key, flags) {
+ if (key in this._map) {
+ if (flags) flags.keys.add(key);
+ return this._map[key].icon;
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.icon;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.icon;
+ }
+};
+
+Exhibit.IconCoder.prototype.translateSet = function(keys, flags) {
+ var icon = null;
+ var self = this;
+ keys.visit(function(key) {
+ var icon2 = self.translate(key, flags);
+ if (icon == null) {
+ icon = icon2;
+ } else if (icon != icon2) {
+ if (flags) flags.mixed = true;
+ icon = self._mixedCase.icon;
+ return true;
+ }
+ return false;
+ });
+
+ if (icon != null) {
+ return icon;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.icon;
+ }
+};
+
+Exhibit.IconCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.IconCoder.prototype.getOthersIcon = function() {
+ return this._othersCase.icon;
+};
+
+Exhibit.IconCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.IconCoder.prototype.getMissingIcon = function() {
+ return this._missingCase.icon;
+};
+
+Exhibit.IconCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.IconCoder.prototype.getMixedIcon = function() {
+ return this._mixedCase.icon;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/ordered-color-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/ordered-color-coder.js
new file mode 100644
index 00000000..04665451
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/ordered-color-coder.js
@@ -0,0 +1,250 @@
+/*==================================================
+ * Exhibit.OrderedColorCoder
+ * Reads the color coder entries as if they were
+ * in order. Eliminates the mixed case and uses
+ * either the highest or lowest 'color' in any set.
+ * Note the 'other' and 'missing' cases will be
+ * included in the ordering. If they are not
+ * included in the coder definition, they will be
+ * added as the lowest priority, other, then
+ * missing.
+ *==================================================
+ */
+
+Exhibit.OrderedColorCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._map = {};
+ this._order = new Exhibit.OrderedColorCoder._OrderedHash();
+ this._usePriority = "highest";
+ this._mixedCase = {
+ label: null,
+ color: null,
+ isDefault: true
+ };
+ this._missingCase = {
+ label: Exhibit.Coders.l10n.missingCaseLabel,
+ color: Exhibit.Coders.missingCaseColor,
+ isDefault: true
+ };
+ this._othersCase = {
+ label: Exhibit.Coders.l10n.othersCaseLabel,
+ color: Exhibit.Coders.othersCaseColor,
+ isDefault: true
+ };
+};
+
+Exhibit.OrderedColorCoder._OrderedHash = function() {
+ this.size = 0;
+ this.hash = {};
+}
+Exhibit.OrderedColorCoder._OrderedHash.prototype.add = function(key) {
+ this.hash[key] = this.size++;
+}
+Exhibit.OrderedColorCoder._OrderedHash.prototype.size = function() {
+ return this.size;
+}
+Exhibit.OrderedColorCoder._OrderedHash.prototype.get = function(key) {
+ return this.hash[key];
+}
+
+Exhibit.OrderedColorCoder._settingSpecs = {
+};
+
+Exhibit.OrderedColorCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.OrderedColorCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.OrderedColorCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.OrderedColorCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.OrderedColorCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.OrderedColorCoder._settingSpecs, coder._settings);
+
+ try {
+ this._usePriority = coder._settings.usePriority;
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "color"));
+ }
+ node = node.nextSibling;
+ }
+ if (coder.getOthersIsDefault()) {
+ coder._addEntry(
+ "other",
+ coder.getOthersLabel(),
+ coder.getOthersColor());
+ }
+ if (coder.getMissingIsDefault()) {
+ coder._addEntry(
+ "missing",
+ coder.getMissingLabel(),
+ coder.getMissingColor());
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "OrderedColorCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.OrderedColorCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.OrderedColorCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.OrderedColorCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].color);
+ }
+ if (this.getOthersIsDefault()) {
+ coder._addEntry(
+ "other",
+ this.getOthersLabel(),
+ this.getOthersColor());
+ }
+ if (this.getMissingIsDefault()) {
+ coder._addEntry(
+ "missing",
+ this.getMissingLabel(),
+ this.getMissingColor());
+ }
+ }
+}
+
+Exhibit.OrderedColorCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.OrderedColorCoder._colorTable = {
+ "red" : "#ff0000",
+ "green" : "#00ff00",
+ "blue" : "#0000ff",
+ "white" : "#ffffff",
+ "black" : "#000000",
+ "gray" : "#888888"
+};
+
+Exhibit.OrderedColorCoder.prototype._addEntry = function(kase, key, color) {
+ if (color in Exhibit.OrderedColorCoder._colorTable) {
+ color = Exhibit.OrderedColorCoder._colorTable[color];
+ }
+
+ var entry = null;
+ var mixed = false;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "missing": entry = this._missingCase; break;
+ case "mixed": mixed = true; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.color = color;
+ entry.isDefault = false;
+ this._order.add(key);
+ } else {
+ // the 'mixed' case will be entirely ignored
+ if (!mixed) {
+ this._map[key] = { color: color };
+ this._order.add(key);
+ }
+ }
+};
+
+Exhibit.OrderedColorCoder.prototype.translate = function(key, flags) {
+ if (key in this._map) {
+ if (flags) flags.keys.add(key);
+ return this._map[key].color;
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.color;
+ }
+};
+
+Exhibit.OrderedColorCoder.prototype.translateSet = function(keys, flags) {
+ var color = null;
+ var lastKey = null;
+ var self = this;
+ keys.visit(function(key) {
+ var color2 = self.translate(key, flags);
+ if (color == null) {
+ color = color2;
+ lastKey = key;
+ } else if (color != color2) {
+ if (key == null) {
+ key = self.getMissingLabel();
+ } else if (!(key in self._map)) {
+ key = self.getOthersLabel();
+ }
+ var keyOrder = self._order.get(key);
+ var lastKeyOrder = self._order.get(lastKey);
+ if (self._usePriority == "highest") {
+ if (keyOrder < lastKeyOrder) {
+ color = color2;
+ lastKey = key;
+ }
+ } else if (self._usePriority == "lowest") {
+ if (keyOrder > lastKeyOrder) {
+ color = color2;
+ lastKey = key;
+ }
+ } else {
+ // an incorrect setting value will cause problems
+ return false;
+ }
+ return true;
+ }
+ return false;
+ });
+
+ if (color != null) {
+ return color;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.color;
+ }
+};
+
+Exhibit.OrderedColorCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getOthersColor = function() {
+ return this._othersCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getOthersIsDefault = function() {
+ return this._othersCase.isDefault;
+};
+
+Exhibit.OrderedColorCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getMissingColor = function() {
+ return this._missingCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getMissingIsDefault = function() {
+ return this._missingCase.isDefault;
+};
+
+Exhibit.OrderedColorCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.OrderedColorCoder.prototype.getMixedColor = function() {
+ return this._mixedCase.color;
+};
+Exhibit.OrderedColorCoder.prototype.getMixedIsDefault = function() {
+ return this._mixedCase.isDefault;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-coder.js
new file mode 100644
index 00000000..4a77d3a9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-coder.js
@@ -0,0 +1,139 @@
+/*==================================================
+ * Exhibit.SizeCoder
+ *==================================================
+ */
+
+Exhibit.SizeCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._map = {};
+ this._mixedCase = { label: "mixed", size: 10 };
+ this._missingCase = { label: "missing", size: 10 };
+ this._othersCase = { label: "others", size: 10 };
+};
+
+Exhibit.SizeCoder._settingSpecs = {
+};
+
+Exhibit.SizeCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SizeCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.SizeCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.SizeCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.SizeCoder._settingSpecs, coder._settings);
+
+ try {
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "size"));
+ }
+ node = node.nextSibling;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "SizeCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.SizeCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.SizeCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.SizeCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].size);
+ }
+ }
+}
+
+Exhibit.SizeCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.SizeCoder.prototype._addEntry = function(kase, key, size) {
+ var entry = null;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "mixed": entry = this._mixedCase; break;
+ case "missing": entry = this._missingCase; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.size = size;
+ } else {
+ this._map[key] = { size: size };
+ }
+};
+
+Exhibit.SizeCoder.prototype.translate = function(key, flags) {
+ if (key in this._map) {
+ if (flags) flags.keys.add(key);
+ return this._map[key].size;
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.size;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.size;
+ }
+};
+
+Exhibit.SizeCoder.prototype.translateSet = function(keys, flags) {
+ var size = null;
+ var self = this;
+ keys.visit(function(key) {
+ var size2 = self.translate(key, flags);
+ if (size == null) {
+ size = size2;
+ } else if (size != size2) {
+ if (flags) flags.mixed = true;
+ size = self._mixedCase.size;
+ return true;
+ }
+ return false;
+ });
+
+ if (size != null) {
+ return size;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.size;
+ }
+};
+
+Exhibit.SizeCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.SizeCoder.prototype.getOthersSize = function() {
+ return this._othersCase.size;
+};
+
+Exhibit.SizeCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.SizeCoder.prototype.getMissingSize = function() {
+ return this._missingCase.size;
+};
+
+Exhibit.SizeCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.SizeCoder.prototype.getMixedSize = function() {
+ return this._mixedCase.size;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-gradient-coder.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-gradient-coder.js
new file mode 100644
index 00000000..df654737
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coders/size-gradient-coder.js
@@ -0,0 +1,192 @@
+/*==================================================
+ * Exhibit.SizeGradientCoder
+ *==================================================
+ */
+
+Exhibit.SizeGradientCoder = function(uiContext) {
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ this._log = {
+ func: function ( size ) {
+ return Math.ceil( Math.log( size ) );
+ },
+ invFunc: function ( size ) {
+ return Math.ceil( Math.exp( size ) );
+ }
+ };
+ this._linear = {
+ func: function(size) { return Math.ceil(size); },
+ invFunc: function(size) { return Math.ceil(size); }
+ }
+ this._quad = {
+ func: function(size) { return Math.ceil(Math.pow((size / 100), 2)); },
+ invFunc: function(size) { return Math.sqrt(size) * 100; }
+ }
+ this._exp = {
+ func: function(size) { return Math.ceil(Math.exp(size)); },
+ invFunc: function(size) { return Math.ceil(Math.log(size)); }
+ }
+ this._markerScale = this._quad; // default marker scale type
+ this._valueScale = this._linear; // value scaling functionality needs to be added
+
+ this._gradientPoints = [];
+ this._mixedCase = { label: "mixed", size: 20 };
+ this._missingCase = { label: "missing", size: 20 };
+ this._othersCase = { label: "others", size: 20 };
+};
+
+Exhibit.SizeGradientCoder._settingSpecs = {
+};
+
+Exhibit.SizeGradientCoder.create = function(configuration, uiContext) {
+ var coder = new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SizeGradientCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.SizeGradientCoder.createFromDOM = function(configElmt, uiContext) {
+ configElmt.style.display = "none";
+
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var coder = new Exhibit.SizeGradientCoder(Exhibit.UIContext.create(configuration, uiContext));
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.SizeGradientCoder._settingSpecs, coder._settings);
+
+ try {
+ var markerScale = coder._settings.markerScale;
+ if (markerScale == "log") { coder._markerScale = coder._log; }
+ if (markerScale == "linear") { coder._markerScale = coder._linear; }
+ if (markerScale == "exp") { coder._markerScale = coder._exp; }
+
+ var gradientPoints = Exhibit.getAttribute(configElmt, "gradientPoints", ";")
+ for (var i = 0; i < gradientPoints.length; i++) {
+ var point = gradientPoints[i].split(',');
+ var value = parseFloat(point[0]); // add value scaling
+ var size = coder._markerScale.invFunc(parseFloat(point[1]));
+ coder._gradientPoints.push({ value: value, size: size});
+ }
+
+ var node = configElmt.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ coder._addEntry(
+ Exhibit.getAttribute(node, "case"),
+ node.firstChild.nodeValue.trim(),
+ Exhibit.getAttribute(node, "size"));
+ }
+ node = node.nextSibling;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "SizeGradientCoder: Error processing configuration of coder");
+ }
+
+ Exhibit.SizeGradientCoder._configure(coder, configuration);
+ return coder;
+};
+
+Exhibit.SizeGradientCoder._configure = function(coder, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.SizeGradientCoder._settingSpecs, coder._settings);
+
+ if ("entries" in configuration) {
+ var entries = configuration.entries;
+ for (var i = 0; i < entries.length; i++) {
+ coder._addEntry(entries[i].kase, entries[i].key, entries[i].size);
+ }
+ }
+}
+
+Exhibit.SizeGradientCoder.prototype.dispose = function() {
+ this._uiContext = null;
+ this._settings = null;
+};
+
+Exhibit.SizeGradientCoder.prototype._addEntry = function(kase, key, size) {
+ var entry = null;
+ switch (kase) {
+ case "others": entry = this._othersCase; break;
+ case "mixed": entry = this._mixedCase; break;
+ case "missing": entry = this._missingCase; break;
+ }
+ if (entry != null) {
+ entry.label = key;
+ entry.size = size;
+ }
+};
+
+Exhibit.SizeGradientCoder.prototype.translate = function(key, flags) {
+ var self = this;
+ var gradientPoints = this._gradientPoints;
+ var getSize = function(key) {
+ if (key.constructor != Number) {
+ key = parseFloat(key);
+ }
+ for (j = 0; j < gradientPoints.length; j++) {
+ if (key == gradientPoints[j].value) {
+ return self._markerScale.func(gradientPoints[j].size);
+ } else if (gradientPoints[j+1] != null) {
+ if (key < gradientPoints[j+1].value) {
+ var fraction = (key - gradientPoints[j].value)/(gradientPoints[j+1].value - gradientPoints[j].value);
+ var newSize = Math.floor(gradientPoints[j].size + fraction*(gradientPoints[j+1].size - gradientPoints[j].size));
+ return self._markerScale.func(newSize);
+ }
+ }
+ }
+ }
+
+ if (key >= gradientPoints[0].value & key <= gradientPoints[gradientPoints.length-1].value) {
+ if (flags) flags.keys.add(key);
+ return getSize(key);
+ } else if (key == null) {
+ if (flags) flags.missing = true;
+ return this._missingCase.size;
+ } else {
+ if (flags) flags.others = true;
+ return this._othersCase.size;
+ }
+};
+
+Exhibit.SizeGradientCoder.prototype.translateSet = function(keys, flags) {
+ var size = null;
+ var self = this;
+ keys.visit(function(key) {
+ var size2 = self.translate(key, flags);
+ if (size == null) {
+ size = size2;
+ } else if (size != size2) {
+ if (flags) flags.mixed = true;
+ size = self._mixedCase.size;
+ return true;
+ }
+ return false;
+ });
+
+ if (size != null) {
+ return size;
+ } else {
+ if (flags) flags.missing = true;
+ return this._missingCase.size;
+ }
+};
+
+Exhibit.SizeGradientCoder.prototype.getOthersLabel = function() {
+ return this._othersCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getOthersSize = function() {
+ return this._othersCase.size;
+};
+
+Exhibit.SizeGradientCoder.prototype.getMissingLabel = function() {
+ return this._missingCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMissingSize = function() {
+ return this._missingCase.size;
+};
+
+Exhibit.SizeGradientCoder.prototype.getMixedLabel = function() {
+ return this._mixedCase.label;
+};
+Exhibit.SizeGradientCoder.prototype.getMixedSize = function() {
+ return this._mixedCase.size;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coordinator.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coordinator.js
new file mode 100644
index 00000000..1cd8011a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/coordinator.js
@@ -0,0 +1,64 @@
+/*======================================================================
+ * Exhibit.Coordinator
+ *======================================================================
+ */
+Exhibit.Coordinator = function ( uiContext ) {
+ this._uiContext = uiContext;
+ this._listeners = [];
+};
+
+Exhibit.Coordinator.create = function(configuration, uiContext) {
+ var coordinator = new Exhibit.Coordinator(uiContext);
+
+ return coordinator;
+};
+
+Exhibit.Coordinator.createFromDOM = function(div, uiContext) {
+ var coordinator = new Exhibit.Coordinator(Exhibit.UIContext.createFromDOM(div, uiContext, false));
+
+ return coordinator;
+};
+
+Exhibit.Coordinator.prototype.dispose = function() {
+ this._uiContext.dispose();
+ this._uiContext = null;
+};
+
+Exhibit.Coordinator.prototype.addListener = function(callback) {
+ var listener = new Exhibit.Coordinator._Listener(this, callback);
+ this._listeners.push(listener);
+
+ return listener;
+};
+
+Exhibit.Coordinator.prototype._removeListener = function(listener) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ if (this._listeners[i] == listener) {
+ this._listeners.splice(i, 1);
+ return;
+ }
+ }
+};
+
+Exhibit.Coordinator.prototype._fire = function(listener, o) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ var listener2 = this._listeners[i];
+ if (listener2 != listener) {
+ listener2._callback(o);
+ }
+ }
+};
+
+Exhibit.Coordinator._Listener = function(coordinator, callback) {
+ this._coordinator = coordinator;
+ this._callback = callback;
+};
+
+Exhibit.Coordinator._Listener.prototype.dispose = function() {
+ this._coordinator._removeListener(this);
+};
+
+Exhibit.Coordinator._Listener.prototype.fire = function(o) {
+ this._coordinator._fire(this, o);
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/alpha-range-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/alpha-range-facet.js
new file mode 100644
index 00000000..26163146
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/alpha-range-facet.js
@@ -0,0 +1,382 @@
+/*==================================================
+ * Exhibit.AlphaRangeFacet
+ *==================================================
+ */
+
+Exhibit.AlphaRangeFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._expression = null;
+ this._settings = {};
+
+ this._dom = null;
+ this._ranges = [];
+
+ var self = this;
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_rangeIndex" in self) {
+ delete self._rangeIndex;
+ }
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.AlphaRangeFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "interval": { type: "int", defaultValue: 7 },
+ "collapsible": { type: "boolean", defaultValue: false },
+ "collapsed": { type: "boolean", defaultValue: false }
+};
+
+Exhibit.AlphaRangeFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.AlphaRangeFacet(
+ containerElmt,
+ uiContext
+ );
+
+ Exhibit.AlphaRangeFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.AlphaRangeFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.AlphaRangeFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.AlphaRangeFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "AlphaRangeFacet: Error processing configuration of alpha range facet");
+ }
+ Exhibit.AlphaRangeFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.AlphaRangeFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.AlphaRangeFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+
+ if (facet._settings.collapsed) {
+ facet._settings.collapsible = true;
+ }
+}
+
+Exhibit.AlphaRangeFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+
+ this._uiContext.getCollection().removeListener(this._listener);
+ this._uiContext = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._settings = null;
+ this._ranges = [];
+};
+
+Exhibit.AlphaRangeFacet.prototype.hasRestrictions = function() {
+ return this._ranges.length > 0;
+};
+
+Exhibit.AlphaRangeFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = [];
+ if (this._ranges.length > 0) {
+ restrictions = restrictions.concat(this._ranges);
+ this._ranges = [];
+ this._notifyCollection();
+ }
+ return restrictions;
+};
+
+Exhibit.AlphaRangeFacet.prototype.applyRestrictions = function(restrictions) {
+ this._ranges = restrictions;
+ this._notifyCollection();
+};
+
+Exhibit.AlphaRangeFacet.prototype.setRange = function(from, to, selected) {
+ if (selected) {
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ if (range.from == from && range.to == to) {
+ return;
+ }
+ }
+ this._ranges.push({ from: from, to: to });
+ } else {
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ if (range.from == from && range.to == to) {
+ this._ranges.splice(i, 1);
+ break;
+ }
+ }
+ }
+ this._notifyCollection();
+}
+
+Exhibit.AlphaRangeFacet.prototype.restrict = function(items) {
+ if (this._ranges.length == 0) {
+ return items;
+ }
+ else {
+ this._buildRangeIndex();
+
+ var set = new Exhibit.Set();
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ this._rangeIndex.getSubjectsInRange(range.from, String.fromCharCode(range.to.charCodeAt(0)+1), true, set, items);
+ }
+ return set;
+ }
+};
+
+Exhibit.AlphaRangeFacet.prototype.update = function(items) {
+ this._dom.valuesContainer.style.display = "none";
+ this._dom.valuesContainer.innerHTML = "";
+
+ this._reconstruct(items);
+ this._dom.valuesContainer.style.display = "block";
+};
+
+Exhibit.AlphaRangeFacet.prototype._reconstruct = function(items) {
+
+ var self = this;
+ var ranges = [];
+
+ var rangeIndex;
+ var computeItems;
+
+ this._buildRangeIndex();
+
+ rangeIndex = this._rangeIndex;
+
+ countItems = function(range) {
+ return rangeIndex.getSubjectsInRange(range.from, String.fromCharCode(range.to.charCodeAt(0)+1), true, null, items).size();
+ }
+
+ // Create list of alpha characters
+ var alphaList = [];
+
+ var alphaInList = function(a) {
+ for (x in alphaList) {
+ if (alphaList[x] == a) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ for (var y = 0; y < rangeIndex.getCount(); y+=1) {
+ var alphaChar = rangeIndex._pairs[y].value.substr(0,1).toUpperCase();
+ if (!alphaInList(alphaChar)) {
+ alphaList.push(alphaChar);
+ }
+ }
+
+ for (var x = 0; x < alphaList.length; x += this._settings.interval) {
+ var range = {
+ from: alphaList[x],
+ to: alphaList[(x + this._settings.interval >= alphaList.length ? alphaList.length-1 : x + this._settings.interval - 1)],
+ selected: false
+ };
+ range.count = countItems(range);
+
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range2 = this._ranges[i];
+ if (range2.from == range.from && range2.to == range.to) {
+ range.selected = true;
+ facetHasSelection = true;
+ break;
+ }
+ }
+
+ ranges.push(range);
+ }
+
+ var facetHasSelection = this._ranges.length > 0;
+ var containerDiv = this._dom.valuesContainer;
+ containerDiv.style.display = "none";
+ var constructFacetItemFunction = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetItem" : "constructFlowingFacetItem"];
+ var makeFacetValue = function(from, to, count, selected) {
+ var onSelect = function(elmt, evt, target) {
+ self._toggleRange(from, to, selected, false);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var onSelectOnly = function(elmt, evt, target) {
+ self._toggleRange(from, to, selected, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var elmt = constructFacetItemFunction(
+ from.substr(0,1) + " - " + to.substr(0,1),
+ count,
+ null,
+ selected,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ self._uiContext
+ );
+ containerDiv.appendChild(elmt);
+ };
+
+ for (var i = 0; i < ranges.length; i++) {
+ var range = ranges[i];
+ if (range.selected || range.count > 0) {
+ makeFacetValue(range.from, range.to, range.count, range.selected);
+ }
+ }
+ containerDiv.style.display = "block";
+
+ this._dom.setSelectionCount(this._ranges.length);
+}
+
+Exhibit.AlphaRangeFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.AlphaRangeFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetFrame" : "constructFlowingFacetFrame"](
+ this,
+ this._div,
+ this._settings.facetLabel,
+ function(elmt, evt, target) { self._clearSelections(); },
+ this._uiContext,
+ this._settings.collapsible,
+ this._settings.collapsed
+ );
+
+ if ("height" in this._settings) {
+ this._dom.valuesContainer.style.height = this._settings.height;
+ }
+};
+
+Exhibit.AlphaRangeFacet.prototype._toggleRange = function(from, to, wasSelected, singleSelection) {
+ var self = this;
+ var label = from + " to " + to;
+ var wasOnlyThingSelected = (this._ranges.length == 1 && wasSelected);
+ if (singleSelection && !wasOnlyThingSelected) {
+ var newRestrictions = [ { from: from, to: to } ];
+ var oldRestrictions = [].concat(this._ranges);
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+ } else {
+ SimileAjax.History.addLengthyAction(
+ function() { self.setRange(from, to, !wasSelected); },
+ function() { self.setRange(from, to, wasSelected); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+ }
+};
+
+Exhibit.AlphaRangeFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+
+Exhibit.AlphaRangeFacet.prototype._buildRangeIndex = function() {
+ if (!("_rangeIndex" in this)) {
+ var expression = this._expression;
+ var database = this._uiContext.getDatabase();
+
+ var segment = expression.getPath().getLastSegment();
+ var property = database.getProperty(segment.property);
+
+ var getter = function(item, f) {
+ database.getObjects(item, property.getID(), null, null).visit(function(value) {
+ f(value.toUpperCase());
+ });
+ // expression.evaluateOnItem(item, database).values.visit(function(value) {
+ // f(value.toUpperCase());
+ // });
+ };
+
+ this._rangeIndex = new Exhibit.Database._RangeIndex(
+ this._uiContext.getCollection().getAllItems(),
+ getter
+ );
+
+ // this._rangeIndex._pairs.sort(function(p1, p2) {
+ // return p1.value.localeCompare(p2.value);
+ // });
+ }
+};
+
+Exhibit.AlphaRangeFacet.prototype.exportFacetSelection = function() {
+ var exportedSettings = [];
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ exportedSettings.push(range.from + '|' + range.to);
+ }
+ return exportedSettings.join(',');
+};
+
+Exhibit.AlphaRangeFacet.prototype.importFacetSelection = function(settings) {
+ if (settings.length > 0) {
+ var ranges = settings.split(',');
+ for (var i = 0; i < ranges.length; i++) {
+ var range = ranges[i].split('|');
+ this._ranges.push({from: range[0], to: range[1]});
+ }
+ }
+ if (ranges && ranges.length > 0) {
+ this.update();
+ this._notifyCollection();
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/cloud-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/cloud-facet.js
new file mode 100644
index 00000000..69a6b0f4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/cloud-facet.js
@@ -0,0 +1,541 @@
+/*==================================================
+ * Exhibit.CloudFacet
+ *==================================================
+ */
+
+Exhibit.CloudFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._colorCoder = null;
+
+ this._expression = null;
+ this._valueSet = new Exhibit.Set();
+ this._selectMissing = false;
+
+ this._settings = {};
+ this._dom = null;
+
+ var self = this;
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_itemToValue" in self) {
+ delete self._itemToValue;
+ }
+ if ("_valueToItem" in self) {
+ delete self._valueToItem;
+ }
+ if ("_missingItems" in self) {
+ delete self._missingItems;
+ }
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.CloudFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "minimumCount": { type: "int", defaultValue: 1 },
+ "showMissing": { type: "boolean", defaultValue: true },
+ "missingLabel": { type: "text" }
+};
+
+Exhibit.CloudFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.CloudFacet(containerElmt, uiContext);
+
+ Exhibit.CloudFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.CloudFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.CloudFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.CloudFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+
+ var selection = Exhibit.getAttribute(configElmt, "selection", ";");
+ if (selection != null && selection.length > 0) {
+ for (var i = 0, s; s = selection[i]; i++) {
+ facet._valueSet.add(s);
+ }
+ }
+
+ var selectMissing = Exhibit.getAttribute(configElmt, "selectMissing");
+ if (selectMissing != null && selectMissing.length > 0) {
+ facet._selectMissing = (selectMissing == "true");
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "CloudFacet: Error processing configuration of cloud facet");
+ }
+ Exhibit.CloudFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.CloudFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.CloudFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ for (var i = 0; i < selection.length; i++) {
+ facet._valueSet.add(selection[i]);
+ }
+ }
+ if ("selectMissing" in configuration) {
+ facet._selectMissing = configuration.selectMissing;
+ }
+}
+
+Exhibit.CloudFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+
+ this._uiContext.getCollection().removeListener(this._listener);
+ this._uiContext = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._valueSet = null;
+ this._settings = null;
+
+ this._itemToValue = null;
+ this._valueToItem = null;
+ this._missingItems = null;
+};
+
+Exhibit.CloudFacet.prototype.hasRestrictions = function() {
+ return this._valueSet.size() > 0 || this._selectMissing;
+};
+
+Exhibit.CloudFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = { selection: [], selectMissing: false };
+ if (this.hasRestrictions()) {
+ this._valueSet.visit(function(v) {
+ restrictions.selection.push(v);
+ });
+ this._valueSet = new Exhibit.Set();
+
+ restrictions.selectMissing = this._selectMissing;
+ this._selectMissing = false;
+
+ this._notifyCollection();
+ }
+ return restrictions;
+};
+
+Exhibit.CloudFacet.prototype.applyRestrictions = function(restrictions) {
+ this._valueSet = new Exhibit.Set();
+ for (var i = 0; i < restrictions.selection.length; i++) {
+ this._valueSet.add(restrictions.selection[i]);
+ }
+ this._selectMissing = restrictions.selectMissing;
+
+ this._notifyCollection();
+};
+
+Exhibit.CloudFacet.prototype.setSelection = function(value, selected) {
+ if (selected) {
+ this._valueSet.add(value);
+ } else {
+ this._valueSet.remove(value);
+ }
+ this._notifyCollection();
+}
+
+Exhibit.CloudFacet.prototype.setSelectMissing = function(selected) {
+ if (selected != this._selectMissing) {
+ this._selectMissing = selected;
+ this._notifyCollection();
+ }
+}
+
+Exhibit.CloudFacet.prototype.restrict = function(items) {
+ if (this._valueSet.size() == 0 && !this._selectMissing) {
+ return items;
+ }
+
+ var set;
+ if (this._expression.isPath()) {
+ set = this._expression.getPath().walkBackward(
+ this._valueSet,
+ "item", items,
+ this._uiContext.getDatabase()
+ ).getSet();
+ } else {
+ this._buildMaps();
+
+ set = new Exhibit.Set();
+
+ var valueToItem = this._valueToItem;
+ this._valueSet.visit(function(value) {
+ if (value in valueToItem) {
+ var itemA = valueToItem[value];
+ for (var i = 0; i < itemA.length; i++) {
+ var item = itemA[i];
+ if (items.contains(item)) {
+ set.add(item);
+ }
+ }
+ }
+ });
+ }
+
+ if (this._selectMissing) {
+ this._buildMaps();
+
+ var missingItems = this._missingItems;
+ items.visit(function(item) {
+ if (item in missingItems) {
+ set.add(item);
+ }
+ });
+ }
+
+ return set;
+};
+
+Exhibit.CloudFacet.prototype.update = function(items) {
+ this._constructBody(this._computeFacet(items));
+};
+
+Exhibit.CloudFacet.prototype._computeFacet = function(items) {
+ var database = this._uiContext.getDatabase();
+ var entries = [];
+ var valueType = "text";
+ var self = this;
+
+ if (this._expression.isPath()) {
+ var path = this._expression.getPath();
+ var facetValueResult = path.walkForward(items, "item", database);
+ valueType = facetValueResult.valueType;
+
+ if (facetValueResult.size > 0) {
+ facetValueResult.forEachValue(function(facetValue) {
+ var itemSubcollection = path.evaluateBackward(facetValue, valueType, items, database);
+ if (itemSubcollection.size >= self._settings.minimumCount || self._valueSet.contains(facetValue)) {
+ entries.push({ value: facetValue, count: itemSubcollection.size });
+ }
+ });
+ }
+ } else {
+ this._buildMaps();
+
+ valueType = this._valueType;
+ for (var value in this._valueToItem) {
+ var itemA = this._valueToItem[value];
+ var count = 0;
+ for (var i = 0; i < itemA.length; i++) {
+ if (items.contains(itemA[i])) {
+ count++;
+ }
+ }
+
+ if (count >= this._settings.minimumCount || this._valueSet.contains(value)) {
+ entries.push({ value: value, count: count });
+ }
+ }
+ }
+
+ if (entries.length > 0) {
+ var selection = this._valueSet;
+ var labeler = valueType == "item" ?
+ function(v) { var l = database.getObject(v, "label"); return l != null ? l : v; } :
+ function(v) { return v; }
+
+ for (var i = 0; i < entries.length; i++) {
+ var entry = entries[i];
+ entry.actionLabel = entry.selectionLabel = labeler(entry.value);
+ entry.selected = selection.contains(entry.value);
+ }
+
+ var sortValueFunction = function(a, b) { return a.selectionLabel.localeCompare(b.selectionLabel); };
+ if ("_orderMap" in this) {
+ var orderMap = this._orderMap;
+
+ sortValueFunction = function(a, b) {
+ if (a.selectionLabel in orderMap) {
+ if (b.selectionLabel in orderMap) {
+ return orderMap[a.selectionLabel] - orderMap[b.selectionLabel];
+ } else {
+ return -1;
+ }
+ } else if (b.selectionLabel in orderMap) {
+ return 1;
+ } else {
+ return a.selectionLabel.localeCompare(b.selectionLabel);
+ }
+ }
+ } else if (valueType == "number") {
+ sortValueFunction = function(a, b) {
+ a = parseFloat(a.value);
+ b = parseFloat(b.value);
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ }
+
+ var sortFunction = sortValueFunction;
+ if (this._settings.sortMode == "count") {
+ sortFunction = function(a, b) {
+ var c = b.count - a.count;
+ return c != 0 ? c : sortValueFunction(a, b);
+ }
+ }
+
+ var sortDirectionFunction = sortFunction;
+ if (this._settings.sortDirection == "reverse"){
+ sortDirectionFunction = function(a, b) {
+ return sortFunction(b, a);
+ }
+ }
+
+ entries.sort(sortDirectionFunction);
+ }
+
+ if (this._settings.showMissing || this._selectMissing) {
+ this._buildMaps();
+
+ var count = 0;
+ for (var item in this._missingItems) {
+ if (items.contains(item)) {
+ count++;
+ }
+ }
+
+ if (count > 0 || this._selectMissing) {
+ var span = document.createElement("span");
+ span.innerHTML = ("missingLabel" in this._settings) ?
+ this._settings.missingLabel : Exhibit.FacetUtilities.l10n.missingThisField;
+ span.className = "exhibit-facet-value-missingThisField";
+
+ entries.unshift({
+ value: null,
+ count: count,
+ selected: this._selectMissing,
+ selectionLabel: span,
+ actionLabel: Exhibit.FacetUtilities.l10n.missingThisField
+ });
+ }
+ }
+
+ return entries;
+}
+
+Exhibit.CloudFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.CloudFacet.prototype._initializeUI = function() {
+ this._div.innerHTML = "";
+ this._div.className = "exhibit-cloudFacet";
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ this._div,
+ (("facetLabel" in this._settings) ?
+ ( "<div class='exhibit-cloudFacet-header'>" +
+ "<span class='exhibit-cloudFacet-header-title'>" + this._settings.facetLabel + "</span>" +
+ "</div>"
+ ) :
+ ""
+ ) +
+ "<div class='exhibit-cloudFacet-body' id='valuesContainer'></div>"
+ );
+
+ this._dom = dom;
+};
+
+Exhibit.CloudFacet.prototype._constructBody = function(entries) {
+ var self = this;
+ var div = this._dom.valuesContainer;
+
+ div.style.display = "none";
+ div.innerHTML = "";
+
+ if (entries.length > 0) {
+ var min = Number.POSITIVE_INFINITY;
+ var max = Number.NEGATIVE_INFINITY;
+ for (var j = 0; j < entries.length; j++) {
+ var entry = entries[j];
+ min = Math.min(min, entry.count);
+ max = Math.max(max, entry.count);
+ }
+ var range = max - min;
+
+ var constructValue = function(entry) {
+ var onSelect = function(elmt, evt, target) {
+ self._filter(entry.value, entry.actionLabel, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+
+ var elmt = document.createElement("span");
+
+ elmt.appendChild(document.createTextNode("\u00A0"));
+ if (typeof entry.selectionLabel == "string") {
+ elmt.appendChild(document.createTextNode(entry.selectionLabel));
+ } else {
+ elmt.appendChild(entry.selectionLabel);
+ }
+ elmt.appendChild(document.createTextNode("\u00A0"));
+
+ elmt.className = entry.selected ?
+ "exhibit-cloudFacet-value exhibit-cloudFacet-value-selected" :
+ "exhibit-cloudFacet-value";
+
+ if (entry.count > min) {
+ elmt.style.fontSize = Math.ceil(100 + 100 * Math.log(1 + 1.5 * (entry.count - min) / range)) + "%";
+ }
+
+ SimileAjax.WindowManager.registerEvent(elmt, "click", onSelect, SimileAjax.WindowManager.getBaseLayer());
+
+ div.appendChild(elmt);
+ div.appendChild(document.createTextNode(" "));
+ };
+
+ for (var j = 0; j < entries.length; j++) {
+ constructValue(entries[j]);
+ }
+ }
+ div.style.display = "block";
+};
+
+Exhibit.CloudFacet.prototype._filter = function(value, label, selectOnly) {
+ var self = this;
+ var selected, select, deselect;
+
+ var oldValues = new Exhibit.Set(this._valueSet);
+ var oldSelectMissing = this._selectMissing;
+
+ var newValues;
+ var newSelectMissing;
+ var actionLabel;
+
+ var wasSelected;
+ var wasOnlyThingSelected;
+
+ if (value == null) { // the (missing this field) case
+ wasSelected = oldSelectMissing;
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 0);
+
+ if (selectOnly) {
+ if (oldValues.size() == 0) {
+ newSelectMissing = !oldSelectMissing;
+ } else {
+ newSelectMissing = true;
+ }
+ newValues = new Exhibit.Set();
+ } else {
+ newSelectMissing = !oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ }
+ } else {
+ wasSelected = oldValues.contains(value);
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 1) && !oldSelectMissing;
+
+ if (selectOnly) {
+ newSelectMissing = false;
+ newValues = new Exhibit.Set();
+
+ if (!oldValues.contains(value)) {
+ newValues.add(value);
+ } else if (oldValues.size() > 1 || oldSelectMissing) {
+ newValues.add(value);
+ }
+ } else {
+ newSelectMissing = oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ if (newValues.contains(value)) {
+ newValues.remove(value);
+ } else {
+ newValues.add(value);
+ }
+ }
+ }
+
+ var newRestrictions = { selection: newValues.toArray(), selectMissing: newSelectMissing };
+ var oldRestrictions = { selection: oldValues.toArray(), selectMissing: oldSelectMissing };
+
+ var facetLabel = ("facetLabel" in this._settings) ? this._settings.facetLabel : "";
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ (selectOnly && !wasOnlyThingSelected) ?
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, facetLabel ]) :
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, facetLabel ])
+ );
+};
+
+Exhibit.CloudFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+Exhibit.CloudFacet.prototype._buildMaps = function() {
+ if (!("_itemToValue" in this)) {
+ var itemToValue = {};
+ var valueToItem = {};
+ var missingItems = {};
+ var valueType = "text";
+
+ var insert = function(x, y, map) {
+ if (x in map) {
+ map[x].push(y);
+ } else {
+ map[x] = [ y ];
+ }
+ };
+
+ var expression = this._expression;
+ var database = this._uiContext.getDatabase();
+
+ this._uiContext.getCollection().getAllItems().visit(function(item) {
+ var results = expression.evaluateOnItem(item, database);
+ if (results.values.size() > 0) {
+ valueType = results.valueType;
+ results.values.visit(function(value) {
+ insert(item, value, itemToValue);
+ insert(value, item, valueToItem);
+ });
+ } else {
+ missingItems[item] = true;
+ }
+ });
+
+ this._itemToValue = itemToValue;
+ this._valueToItem = valueToItem;
+ this._missingItems = missingItems;
+ this._valueType = valueType;
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/hierarchical-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/hierarchical-facet.js
new file mode 100644
index 00000000..99c50130
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/hierarchical-facet.js
@@ -0,0 +1,718 @@
+/*==================================================
+ * Exhibit.HierarchicalFacet
+ *==================================================
+ */
+
+Exhibit.HierarchicalFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._colorCoder = null;
+
+ this._expression = null;
+ this._uniformGroupingExpression = null;
+ this._selections = [];
+ this._expanded = {};
+
+ this._settings = {};
+ this._dom = null;
+
+ var self = this;
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_cache" in self) {
+ delete self._cache;
+ }
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.HierarchicalFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "fixedOrder": { type: "text" },
+ "sortMode": { type: "text", defaultValue: "value" },
+ "sortDirection": { type: "text", defaultValue: "forward" },
+ "othersLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "colorCoder": { type: "text", defaultValue: null },
+ "collapsible": { type: "boolean", defaultValue: false },
+ "collapsed": { type: "boolean", defaultValue: false }
+};
+
+Exhibit.HierarchicalFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.HierarchicalFacet(containerElmt, uiContext);
+
+ Exhibit.HierarchicalFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.HierarchicalFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.HierarchicalFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.HierarchicalFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+
+ var uniformGroupingString = Exhibit.getAttribute(configElmt, "uniformGrouping");
+ if (uniformGroupingString != null && uniformGroupingString.length > 0) {
+ facet._uniformGroupingExpression = Exhibit.ExpressionParser.parse(uniformGroupingString);
+ }
+
+ var selection = Exhibit.getAttribute(configElmt, "selection", ";");
+ if (selection != null && selection.length > 0) {
+ for (var i = 0, s; s = selection[i]; i++) {
+ facet._selections =
+ facet._internalAddSelection({ value: s, selectOthers: false });
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "HierarchicalFacet: Error processing configuration of hierarchical facet");
+ }
+ Exhibit.HierarchicalFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.HierarchicalFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.HierarchicalFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+ if ("uniformGrouping" in configuration) {
+ facet._uniformGroupingExpression = Exhibit.ExpressionParser.parse(configuration.uniformGrouping);
+ }
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ for (var i = 0; i < selection.length; i++) {
+ facet._selections.push({ value: selection[i], selectOthers: false });
+ }
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+ if ("fixedOrder" in facet._settings) {
+ var values = facet._settings.fixedOrder.split(";");
+ var orderMap = {};
+ for (var i = 0; i < values.length; i++) {
+ orderMap[values[i].trim()] = i;
+ }
+
+ facet._orderMap = orderMap;
+ }
+
+ if ("colorCoder" in facet._settings) {
+ facet._colorCoder = facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+ }
+
+ if (facet._settings.collapsed) {
+ facet._settings.collapsible = true;
+ }
+}
+
+Exhibit.HierarchicalFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+
+ this._uiContext.getCollection().removeListener(this._listener);
+ this._uiContext = null;
+ this._colorCoder = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._uniformGroupingExpression = null;
+ this._selections = null;
+ this._settings = null;
+
+ this._cache = null;
+};
+
+Exhibit.HierarchicalFacet.prototype.hasRestrictions = function() {
+ return this._selections.length > 0;
+};
+
+Exhibit.HierarchicalFacet.prototype.clearAllRestrictions = function() {
+ var selections = this._selections;
+ this._selections = [];
+
+ if (selections.length > 0) {
+ this._notifyCollection();
+ }
+ return selections;
+};
+
+Exhibit.HierarchicalFacet.prototype.applyRestrictions = function(restrictions) {
+ this._selections = [].concat(restrictions);
+ this._notifyCollection();
+};
+
+Exhibit.HierarchicalFacet.prototype.setSelection = function(value, selected) {
+ var selection = { value: value, selectOthers: false };
+ if (selected) {
+ this._selections = this._internalAddSelection(selection);
+ } else {
+ this._selections = this._internalRemoveSelection(selection);
+ }
+ this._notifyCollection();
+}
+
+Exhibit.HierarchicalFacet.prototype.setselectOthers = function(value, selected) {
+ var selection = { value: value, selectOthers: true };
+ if (selected) {
+ this._selections = this._internalAddSelection(selection);
+ } else {
+ this._selections = this._internalRemoveSelection(selection);
+ }
+ this._notifyCollection();
+}
+
+Exhibit.HierarchicalFacet.prototype.restrict = function(items) {
+ if (this._selections.length == 0) {
+ return items;
+ }
+
+ this._buildCache();
+
+ var set = new Exhibit.Set();
+ var includeNode = function(node) {
+ if ("children" in node) {
+ includeChildNodes(node.children);
+ Exhibit.Set.createIntersection(node.others, items, set);
+ } else {
+ Exhibit.Set.createIntersection(node.items, items, set);
+ }
+ }
+ var includeChildNodes = function(childNodes) {
+ for (var i = 0; i < childNodes.length; i++) {
+ includeNode(childNodes[i]);
+ }
+ };
+
+ for (var i = 0; i < this._selections.length; i++) {
+ var selection = this._selections[i];
+ var node = this._getTreeNode(selection.value);
+ if (node) {
+ if (selection.selectOthers) {
+ Exhibit.Set.createIntersection(node.others, items, set);
+ } else {
+ includeNode(node);
+ }
+ }
+ }
+
+ return set;
+};
+
+Exhibit.HierarchicalFacet.prototype._internalAddSelection = function(selection) {
+ var parentToClear = {};
+ var childrenToClear = {};
+
+ var cache = this._cache;
+ var markClearAncestors = function(value) {
+ if (value in cache.valueToParent) {
+ var parents = cache.valueToParent[value];
+ for (var i = 0; i < parents.length; i++) {
+ var parent = parents[i];
+ parentToClear[parent] = true;
+ markClearAncestors(parent);
+ }
+ }
+ };
+ var markClearDescendants = function(value) {
+ if (value in cache.valueToChildren) {
+ var children = cache.valueToChildren[value];
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ childrenToClear[child] = true;
+ markClearDescendants(child);
+ }
+ }
+ };
+
+ /*
+ ignore "(others)" at the root (its value is null)
+ because it has no parent nor children.
+ */
+ if (selection.value != null) {
+ markClearAncestors(selection.value);
+ if (selection.selectOthers) {
+ parentToClear[selection.value] = true;
+ } else {
+ childrenToClear[selection.value] = true;
+ markClearDescendants(selection.value);
+ }
+ }
+
+ var oldSelections = this._selections;
+ var newSelections = [ selection ];
+ for (var i = 0; i < oldSelections.length; i++) {
+ var s = oldSelections[i];
+ if ((!(s.value in parentToClear) || s.selectOthers) &&
+ (!(s.value in childrenToClear))) {
+
+ newSelections.push(s);
+ }
+ }
+
+ return newSelections;
+};
+
+Exhibit.HierarchicalFacet.prototype._internalRemoveSelection = function(selection) {
+ var oldSelections = this._selections;
+ var newSelections = [];
+ for (var i = 0; i < oldSelections.length; i++) {
+ var s = oldSelections[i];
+ if (s.value != selection.value || s.selectOthers != selection.selectOthers) {
+ newSelections.push(s);
+ }
+ }
+
+ return newSelections;
+};
+
+Exhibit.HierarchicalFacet.prototype.update = function(items) {
+ this._dom.valuesContainer.style.display = "none";
+ this._dom.valuesContainer.innerHTML = "";
+
+ var tree = this._computeFacet(items);
+ if (tree) {
+ this._constructBody(tree);
+ }
+ this._dom.valuesContainer.style.display = "block";
+};
+
+Exhibit.HierarchicalFacet.prototype._computeFacet = function(items) {
+ this._buildCache();
+
+ var database = this._uiContext.getDatabase();
+ var sorter = this._getValueSorter();
+ var othersLabel = "othersLabel" in this._settings ? this._settings.othersLabel : "(others)";
+
+ var selectionMap = {};
+ for (var i = 0; i < this._selections.length; i++) {
+ var s = this._selections[i];
+ selectionMap[s.value] = s.selectOthers;
+ }
+
+ var processNode = function(node, resultNodes, superset) {
+ var selected = (node.value in selectionMap && !selectionMap[node.value]);
+ if ("children" in node) {
+ var resultNode = {
+ value: node.value,
+ label: node.label,
+ children: [],
+ selected: selected,
+ areOthers: false
+ };
+
+ var superset2 = new Exhibit.Set();
+
+ for (var i = 0; i < node.children.length; i++) {
+ var childNode = node.children[i];
+ processNode(childNode, resultNode.children, superset2);
+ }
+ resultNode.children.sort(sorter);
+
+ if (node.others.size() > 0) {
+ var othersSelected = (node.value in selectionMap && selectionMap[node.value]);
+ var subset = Exhibit.Set.createIntersection(items, node.others);
+ if (subset.size() > 0 || othersSelected) {
+ resultNode.children.push({
+ value: node.value,
+ label: othersLabel,
+ count: subset.size(),
+ selected: othersSelected,
+ areOthers: true
+ });
+ superset2.addSet(subset);
+ }
+ }
+
+ resultNode.count = superset2.size();
+ if (selected || resultNode.count > 0 || resultNode.children.length > 0) {
+ resultNodes.push(resultNode);
+
+ if (superset != null && superset2.size() > 0) {
+ superset.addSet(superset2);
+ }
+ }
+ } else {
+ var subset = Exhibit.Set.createIntersection(items, node.items);
+ if (subset.size() > 0 || selected) {
+ resultNodes.push({
+ value: node.value,
+ label: node.label,
+ count: subset.size(),
+ selected: selected,
+ areOthers: false
+ });
+
+ if (superset != null && subset.size() > 0) {
+ superset.addSet(subset);
+ }
+ }
+ }
+ };
+
+ var nodes = [];
+ processNode(this._cache.tree, nodes, null);
+
+ return nodes[0];
+};
+
+Exhibit.HierarchicalFacet.prototype._getValueSorter = function() {
+ var sortValueFunction = function(a, b) { return a.label.localeCompare(b.label); };
+
+ if ("_orderMap" in this) {
+ var orderMap = this._orderMap;
+
+ sortValueFunction = function(a, b) {
+ if (a.label in orderMap) {
+ if (b.label in orderMap) {
+ return orderMap[a.label] - orderMap[b.label];
+ } else {
+ return -1;
+ }
+ } else if (b.label in orderMap) {
+ return 1;
+ } else {
+ return a.label.localeCompare(b.label);
+ }
+ }
+ } else if (this._cache.valueType == "number") {
+ sortValueFunction = function(a, b) {
+ a = parseFloat(a.value);
+ b = parseFloat(b.value);
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ }
+
+ var sortFunction = sortValueFunction;
+ if (this._settings.sortMode == "count") {
+ sortFunction = function(a, b) {
+ var c = b.count - a.count;
+ return c != 0 ? c : sortValueFunction(a, b);
+ }
+ }
+
+ var sortDirectionFunction = sortFunction;
+ if (this._settings.sortDirection == "reverse"){
+ sortDirectionFunction = function(a, b) {
+ return sortFunction(b, a);
+ }
+ }
+
+ return sortDirectionFunction;
+};
+
+Exhibit.HierarchicalFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.HierarchicalFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetFrame" : "constructFlowingFacetFrame"](
+ this,
+ this._div,
+ this._settings.facetLabel,
+ function(elmt, evt, target) { self._clearSelections(); },
+ this._uiContext,
+ this._settings.collapsible,
+ this._settings.collapsed
+ );
+
+ if ("height" in this._settings && this._settings.scroll) {
+ this._dom.valuesContainer.style.height = this._settings.height;
+ }
+};
+
+Exhibit.HierarchicalFacet.prototype._constructBody = function(tree) {
+ var self = this;
+ var containerDiv = this._dom.valuesContainer;
+
+ containerDiv.style.display = "none";
+
+ var constructFacetItemFunction = Exhibit.FacetUtilities[this._settings.scroll ? "constructHierarchicalFacetItem" : "constructFlowingHierarchicalFacetItem"];
+ var facetHasSelection = this._selections.length > 0;
+
+ var processNode = function(node, div) {
+ var hasChildren = ("children" in node);
+ var onSelect = function(elmt, evt, target) {
+ self._filter(node.value, node.areOthers, node.label, node.selected, false);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var onSelectOnly = function(elmt, evt, target) {
+ self._filter(node.value, node.areOthers, node.label, node.selected, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var onToggleChildren = function(elmt, evt, target) {
+ var show;
+ if (node.value in self._expanded) {
+ delete self._expanded[node.value];
+ show = false;
+ } else {
+ self._expanded[node.value] = true;
+ show = true;
+ }
+ dom.showChildren(show);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var dom = constructFacetItemFunction(
+ node.label,
+ node.count,
+ (self._colorCoder != null) ? self._colorCoder.translate(node.value) : null,
+ node.selected,
+ hasChildren,
+ (node.value in self._expanded),
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ onToggleChildren,
+ self._uiContext
+ );
+ div.appendChild(dom.elmt);
+
+ if (hasChildren) {
+ processChildNodes(node.children, dom.childrenContainer);
+ }
+ };
+ var processChildNodes = function(childNodes, div) {
+ for (var i = 0; i < childNodes.length; i++) {
+ processNode(childNodes[i], div);
+ }
+ };
+
+ processChildNodes(tree.children, containerDiv);
+
+ containerDiv.style.display = "block";
+
+ this._dom.setSelectionCount(this._selections.length);
+};
+
+Exhibit.HierarchicalFacet.prototype._filter = function(value, areOthers, label, wasSelected, selectOnly) {
+ var self = this;
+ var wasSelectedAlone = wasSelected && this._selections.length == 1;
+
+ var selection = {
+ value: value,
+ selectOthers: areOthers
+ };
+
+ var oldRestrictions = this._selections;
+ var newRestrictions;
+ if (wasSelected) {
+ if (selectOnly) {
+ if (wasSelectedAlone) {
+ // deselect
+ newRestrictions = [];
+ } else {
+ // clear all other selections
+ newRestrictions = [ selection ];
+ }
+ } else {
+ // toggle
+ newRestrictions = this._internalRemoveSelection(selection);
+ }
+ } else {
+ if (selectOnly) {
+ newRestrictions = [ selection ];
+ } else {
+ newRestrictions = this._internalAddSelection(selection);
+ }
+ }
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ (selectOnly && !wasSelectedAlone) ?
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, this._settings.facetLabel ]) :
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+};
+
+Exhibit.HierarchicalFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+Exhibit.HierarchicalFacet.prototype._buildCache = function() {
+ if (!("_cache" in this)) {
+ var valueToItem = {};
+ var valueType = "text";
+
+ var valueToChildren = {};
+ var valueToParent = {};
+ var valueToPath = {};
+ var values = new Exhibit.Set();
+
+ var insert = function(x, y, map) {
+ if (x in map) {
+ map[x].push(y);
+ } else {
+ map[x] = [ y ];
+ }
+ };
+
+ var database = this._uiContext.getDatabase();
+ var tree = {
+ value: null,
+ label: "(root)",
+ others: new Exhibit.Set(),
+ children: []
+ };
+
+ var expression = this._expression;
+ this._uiContext.getCollection().getAllItems().visit(function(item) {
+ var results = expression.evaluateOnItem(item, database);
+ if (results.values.size() > 0) {
+ valueType = results.valueType;
+ results.values.visit(function(value) {
+ values.add(value);
+ insert(value, item, valueToItem);
+ });
+ } else {
+ tree.others.add(item);
+ }
+ });
+
+ var groupingExpression = this._uniformGroupingExpression;
+ var rootValues = new Exhibit.Set();
+ var getParentChildRelationships = function(valueSet) {
+ var newValueSet = new Exhibit.Set();
+ valueSet.visit(function(value) {
+ var results = groupingExpression.evaluateOnItem(value, database);
+ if (results.values.size() > 0) {
+ results.values.visit(function(parentValue) {
+ insert(value, parentValue, valueToParent);
+ insert(parentValue, value, valueToChildren);
+ if (!valueSet.contains(parentValue)) {
+ newValueSet.add(parentValue);
+ }
+ return true;
+ });
+ } else {
+ rootValues.add(value);
+ }
+ });
+
+ if (newValueSet.size() > 0) {
+ getParentChildRelationships(newValueSet);
+ }
+ };
+ getParentChildRelationships(values);
+
+ var processValue = function(value, nodes, valueSet, path) {
+ var label = database.getObject(value, "label");
+ var node = {
+ value: value,
+ label: label != null ? label : value
+ };
+ nodes.push(node);
+ valueToPath[value] = path;
+
+ if (value in valueToChildren) {
+ node.children = [];
+
+ var valueSet2 = new Exhibit.Set();
+ var childrenValue = valueToChildren[value];
+ for (var i = 0; i < childrenValue.length; i++) {
+ processValue(childrenValue[i], node.children, valueSet2, path.concat(i));
+ }
+ node.others = new Exhibit.Set();
+ if (value in valueToItem) {
+ var items = valueToItem[value];
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ if (!valueSet2.contains(item)) {
+ node.others.add(item);
+ valueSet.add(item);
+ }
+ }
+ }
+
+ valueSet.addSet(valueSet2);
+ } else {
+ node.items = new Exhibit.Set();
+ if (value in valueToItem) {
+ var items = valueToItem[value];
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ node.items.add(item);
+ valueSet.add(item);
+ }
+ }
+ }
+ }
+
+ var index = 0;
+ rootValues.visit(function (value) { processValue(value, tree.children, new Exhibit.Set(), [index++]); });
+
+ this._cache = {
+ tree: tree,
+ valueToChildren: valueToChildren,
+ valueToParent: valueToParent,
+ valueToPath: valueToPath,
+ valueType: valueType
+ };
+ }
+};
+
+Exhibit.HierarchicalFacet.prototype._getTreeNode = function(value) {
+ if (value == null) {
+ return this._cache.tree;
+ }
+
+ var path = this._cache.valueToPath[value];
+ var trace = function(node, path, index) {
+ var node2 = node.children[path[index]];
+ if (++index < path.length) {
+ return trace(node2, path, index);
+ } else {
+ return node2;
+ }
+ };
+ return (path) ? trace(this._cache.tree, path, 0) : null;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/image-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/image-facet.js
new file mode 100644
index 00000000..e2011aa1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/image-facet.js
@@ -0,0 +1,486 @@
+/*==================================================
+ * Exhibit.ImageFacet
+ *==================================================
+ */
+
+Exhibit.ImageFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._colorCoder = null;
+
+ this._expression = null;
+ this._valueSet = new Exhibit.Set();
+ this._selectMissing = false;
+
+ this._settings = {};
+ this._dom = null;
+};
+
+Exhibit.ImageFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "thumbNail": { type: "uri" },
+ "overlayCounts": { type: "boolean", defaultValue: true },
+ "fixedOrder": { type: "text" },
+ "sortMode": { type: "text", defaultValue: "value" },
+ "sortDirection": { type: "text", defaultValue: "forward" },
+ "showMissing": { type: "boolean", defaultValue: true },
+ "missingLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "colorCoder": { type: "text", defaultValue: null },
+ "collapsible": { type: "boolean", defaultValue: false },
+ "collapsed": { type: "boolean", defaultValue: false }
+};
+
+Exhibit.ImageFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.ImageFacet(containerElmt, uiContext);
+
+ Exhibit.ImageFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.ImageFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.ImageFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.ImageFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+
+ var imageString = Exhibit.getAttribute(configElmt, "image");
+ if (imageString != null && imageString.length > 0) {
+ facet._imageExpression = Exhibit.ExpressionParser.parse(imageString);
+ }
+
+ var tooltipString = Exhibit.getAttribute(configElmt, "tooltip");
+ if (tooltipString != null && tooltipString.length > 0) {
+ facet._tooltipExpression = Exhibit.ExpressionParser.parse(tooltipString);
+ }
+
+ var selection = Exhibit.getAttribute(configElmt, "selection", ";");
+ if (selection != null && selection.length > 0) {
+ for (var i = 0, s; s = selection[i]; i++) {
+ facet._valueSet.add(s);
+ }
+ }
+
+ var selectMissing = Exhibit.getAttribute(configElmt, "selectMissing");
+ if (selectMissing != null && selectMissing.length > 0) {
+ facet._selectMissing = (selectMissing == "true");
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "ImageFacet: Error processing configuration of list facet");
+ }
+ Exhibit.ImageFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.ImageFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.ImageFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+ if ("image" in configuration) {
+ facet._imageExpression = Exhibit.ExpressionParser.parse(configuration.image);
+ }
+ if ("tooltip" in configuration) {
+ facet._tooltipExpression = Exhibit.ExpressionParser.parse(configuration.tooltip);
+ }
+
+ if (!(facet._imageExpression)) {
+ facet._imageExpression = Exhibit.ExpressionParser.parse("value");
+ }
+ if (!(facet._tooltipExpression)) {
+ facet._tooltipExpression = Exhibit.ExpressionParser.parse("value");
+ }
+
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ for (var i = 0; i < selection.length; i++) {
+ facet._valueSet.add(selection[i]);
+ }
+ }
+ if ("selectMissing" in configuration) {
+ facet._selectMissing = configuration.selectMissing;
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+ if ("fixedOrder" in facet._settings) {
+ var values = facet._settings.fixedOrder.split(";");
+ var orderMap = {};
+ for (var i = 0; i < values.length; i++) {
+ orderMap[values[i].trim()] = i;
+ }
+
+ facet._orderMap = orderMap;
+ }
+
+ if ("colorCoder" in facet._settings) {
+ facet._colorCoder = facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+ }
+
+ if (facet._settings.collapsed) {
+ facet._settings.collapsible = true;
+ }
+
+ facet._cache = new Exhibit.FacetUtilities.Cache(
+ facet._uiContext.getDatabase(),
+ facet._uiContext.getCollection(),
+ facet._expression
+ );
+}
+
+Exhibit.ImageFacet.prototype.dispose = function() {
+ this._cache.dispose();
+ this._cache = null;
+
+ this._uiContext.getCollection().removeFacet(this);
+ this._uiContext = null;
+ this._colorCoder = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._valueSet = null;
+ this._settings = null;
+};
+
+Exhibit.ImageFacet.prototype.hasRestrictions = function() {
+ return this._valueSet.size() > 0 || this._selectMissing;
+};
+
+Exhibit.ImageFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = { selection: [], selectMissing: false };
+ if (this.hasRestrictions()) {
+ this._valueSet.visit(function(v) {
+ restrictions.selection.push(v);
+ });
+ this._valueSet = new Exhibit.Set();
+
+ restrictions.selectMissing = this._selectMissing;
+ this._selectMissing = false;
+
+ this._notifyCollection();
+ }
+ return restrictions;
+};
+
+Exhibit.ImageFacet.prototype.applyRestrictions = function(restrictions) {
+ this._valueSet = new Exhibit.Set();
+ for (var i = 0; i < restrictions.selection.length; i++) {
+ this._valueSet.add(restrictions.selection[i]);
+ }
+ this._selectMissing = restrictions.selectMissing;
+
+ this._notifyCollection();
+};
+
+Exhibit.ImageFacet.prototype.setSelection = function(value, selected) {
+ if (selected) {
+ this._valueSet.add(value);
+ } else {
+ this._valueSet.remove(value);
+ }
+ this._notifyCollection();
+}
+
+Exhibit.ImageFacet.prototype.setSelectMissing = function(selected) {
+ if (selected != this._selectMissing) {
+ this._selectMissing = selected;
+ this._notifyCollection();
+ }
+}
+
+Exhibit.ImageFacet.prototype.restrict = function(items) {
+ if (this._valueSet.size() == 0 && !this._selectMissing) {
+ return items;
+ }
+
+ var set = this._cache.getItemsFromValues(this._valueSet, items);
+ if (this._selectMissing) {
+ this._cache.getItemsMissingValue(items, set);
+ }
+
+ return set;
+};
+
+Exhibit.ImageFacet.prototype.update = function(items) {
+ this._dom.valuesContainer.style.display = "none";
+ this._dom.valuesContainer.innerHTML = "";
+ this._constructBody(this._computeFacet(items));
+ this._dom.valuesContainer.style.display = "block";
+};
+
+Exhibit.ImageFacet.prototype._computeFacet = function(items) {
+ var database = this._uiContext.getDatabase();
+ var r = this._cache.getValueCountsFromItems(items);
+ var entries = r.entries;
+ var valueType = r.valueType;
+
+ if (entries.length > 0) {
+ var selection = this._valueSet;
+ var labeler = valueType == "item" ?
+ function(v) { var l = database.getObject(v, "label"); return l != null ? l : v; } :
+ function(v) { return v; }
+
+ for (var i = 0; i < entries.length; i++) {
+ var entry = entries[i];
+ entry.actionLabel = entry.selectionLabel = labeler(entry.value);
+ entry.image = this._imageExpression.evaluateSingleOnItem(entry.value, database).value;
+ entry.tooltip = this._tooltipExpression.evaluateSingleOnItem(entry.value, database).value;
+ entry.selected = selection.contains(entry.value);
+ }
+
+ entries.sort(this._createSortFunction(valueType));
+ }
+ /* should display something to account for items that don't have this field
+
+ if (this._settings.showMissing || this._selectMissing) {
+ var count = this._cache.countItemsMissingValue(items);
+ if (count > 0 || this._selectMissing) {
+ var span = document.createElement("span");
+ span.innerHTML = ("missingLabel" in this._settings) ?
+ this._settings.missingLabel : Exhibit.FacetUtilities.l10n.missingThisField;
+ span.className = "exhibit-facet-value-missingThisField";
+
+ entries.unshift({
+ value: null,
+ count: count,
+ selected: this._selectMissing,
+ selectionLabel: span,
+ actionLabel: Exhibit.FacetUtilities.l10n.missingThisField
+ });
+ }
+ }
+ */
+ return entries;
+}
+
+Exhibit.ImageFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.ImageFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetFrame" : "constructFlowingFacetFrame"](
+ this,
+ this._div,
+ this._settings.facetLabel,
+ function(elmt, evt, target) { self._clearSelections(); },
+ this._uiContext,
+ this._settings.collapsible,
+ this._settings.collapsed
+ );
+
+ if ("height" in this._settings && this._settings.scroll) {
+ this._dom.valuesContainer.style.height = this._settings.height;
+ }
+};
+
+Exhibit.ImageFacet.prototype._constructBody = function(entries) {
+ var self = this;
+ var shouldOverlayCounts = this._settings.overlayCounts;
+ var containerDiv = this._dom.valuesContainer;
+
+ containerDiv.style.display = "none";
+ var facetHasSelection = this._valueSet.size() > 0 || this._selectMissing;
+ var constructValue = function(entry) {
+ var onSelectOnly = function(elmt, evt, target) {
+ self._filter(entry.value, entry.actionLabel, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var elmt = document.createElement("span");
+ var wrapper = document.createElement("div");
+ wrapper.className = "wrapper";
+ var image = document.createElement("img");
+ image.src = entry.image;
+ wrapper.appendChild(image);
+
+ if(shouldOverlayCounts == true) {
+ var countDiv = document.createElement("div");
+ countDiv.className = "countDiv";
+ var countBackground = document.createElement("div");
+ countBackground.className = "countBackground";
+ //countImage.src = "http://simile.mit.edu/painter/painter?renderer=map-marker&shape=square&alpha=0.7&width=20&height=20&background=FF9000&label=&pin=false&.png"
+ //countImage.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="http://simile.mit.edu/painter/painter?renderer=map-marker&shape=circle&alpha=0.7&width=31&height=31&background=FF9000&label=&pin=false&.png");'
+ countDiv.appendChild(countBackground);
+ var innerCount = document.createElement("div");
+ innerCount.className = "text";
+ innerCount.innerHTML = entry.count;
+ countDiv.appendChild(innerCount);
+ wrapper.appendChild(countDiv);
+ }
+
+ elmt.appendChild(wrapper);
+
+ elmt.className = entry.selected ? "inline-block exhibit-imageFacet-value exhibit-imageFacet-value-selected" : "inline-block exhibit-imageFacet-value";
+
+ elmt.title = entry.count + " " + entry.tooltip;
+
+ SimileAjax.WindowManager.registerEvent(elmt, "click", onSelectOnly, SimileAjax.WindowManager.getBaseLayer());
+
+ containerDiv.appendChild(elmt);
+ };
+
+ for (var j = 0; j < entries.length; j++) {
+ constructValue(entries[j]);
+ }
+ containerDiv.style.display = "block";
+
+ this._dom.setSelectionCount(this._valueSet.size() + (this._selectMissing ? 1 : 0));
+};
+
+Exhibit.ImageFacet.prototype._filter = function(value, label, selectOnly) {
+ var self = this;
+ var selected, select, deselect;
+
+ var oldValues = new Exhibit.Set(this._valueSet);
+ var oldSelectMissing = this._selectMissing;
+
+ var newValues;
+ var newSelectMissing;
+ var actionLabel;
+
+ var wasSelected;
+ var wasOnlyThingSelected;
+
+ if (value == null) { // the (missing this field) case
+ wasSelected = oldSelectMissing;
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 0);
+
+ if (selectOnly) {
+ if (oldValues.size() == 0) {
+ newSelectMissing = !oldSelectMissing;
+ } else {
+ newSelectMissing = true;
+ }
+ newValues = new Exhibit.Set();
+ } else {
+ newSelectMissing = !oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ }
+ } else {
+ wasSelected = oldValues.contains(value);
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 1) && !oldSelectMissing;
+
+ if (selectOnly) {
+ newSelectMissing = false;
+ newValues = new Exhibit.Set();
+
+ if (!oldValues.contains(value)) {
+ newValues.add(value);
+ } else if (oldValues.size() > 1 || oldSelectMissing) {
+ newValues.add(value);
+ }
+ } else {
+ newSelectMissing = oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ if (newValues.contains(value)) {
+ newValues.remove(value);
+ } else {
+ newValues.add(value);
+ }
+ }
+ }
+
+ var newRestrictions = { selection: newValues.toArray(), selectMissing: newSelectMissing };
+ var oldRestrictions = { selection: oldValues.toArray(), selectMissing: oldSelectMissing };
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ (selectOnly && !wasOnlyThingSelected) ?
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, this._settings.facetLabel ]) :
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+};
+
+Exhibit.ImageFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+Exhibit.ImageFacet.prototype._createSortFunction = function(valueType) {
+ var sortValueFunction = function(a, b) { return a.selectionLabel.localeCompare(b.selectionLabel); };
+ if ("_orderMap" in this) {
+ var orderMap = this._orderMap;
+
+ sortValueFunction = function(a, b) {
+ if (a.selectionLabel in orderMap) {
+ if (b.selectionLabel in orderMap) {
+ return orderMap[a.selectionLabel] - orderMap[b.selectionLabel];
+ } else {
+ return -1;
+ }
+ } else if (b.selectionLabel in orderMap) {
+ return 1;
+ } else {
+ return a.selectionLabel.localeCompare(b.selectionLabel);
+ }
+ }
+ } else if (valueType == "number") {
+ sortValueFunction = function(a, b) {
+ a = parseFloat(a.value);
+ b = parseFloat(b.value);
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ }
+
+ var sortFunction = sortValueFunction;
+ if (this._settings.sortMode == "count") {
+ sortFunction = function(a, b) {
+ var c = b.count - a.count;
+ return c != 0 ? c : sortValueFunction(a, b);
+ }
+ }
+
+ var sortDirectionFunction = sortFunction;
+ if (this._settings.sortDirection == "reverse"){
+ sortDirectionFunction = function(a, b) {
+ return sortFunction(b, a);
+ }
+ }
+
+ return sortDirectionFunction;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/list-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/list-facet.js
new file mode 100644
index 00000000..fda2c55d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/list-facet.js
@@ -0,0 +1,489 @@
+/*==================================================
+ * Exhibit.ListFacet
+ *==================================================
+ */
+
+Exhibit.ListFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._colorCoder = null;
+
+ this._expression = null;
+ this._valueSet = new Exhibit.Set();
+ this._selectMissing = false;
+
+ this._delayedUpdateItems = null;
+
+ this._settings = {};
+ this._dom = null;
+};
+
+Exhibit.ListFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "fixedOrder": { type: "text" },
+ "sortMode": { type: "text", defaultValue: "value" },
+ "sortDirection": { type: "text", defaultValue: "forward" },
+ "showMissing": { type: "boolean", defaultValue: true },
+ "missingLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "colorCoder": { type: "text", defaultValue: null },
+ "collapsible": { type: "boolean", defaultValue: false },
+ "collapsed": { type: "boolean", defaultValue: false },
+ "formatter": { type: "text", defaultValue: null}
+};
+
+Exhibit.ListFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.ListFacet(containerElmt, uiContext);
+
+ Exhibit.ListFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.ListFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.ListFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.ListFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+
+ var selection = Exhibit.getAttribute(configElmt, "selection", ";");
+ if (selection != null && selection.length > 0) {
+ for (var i = 0, s; s = selection[i]; i++) {
+ facet._valueSet.add(s);
+ }
+ }
+
+ var selectMissing = Exhibit.getAttribute(configElmt, "selectMissing");
+ if (selectMissing != null && selectMissing.length > 0) {
+ facet._selectMissing = (selectMissing == "true");
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "ListFacet: Error processing configuration of list facet");
+ }
+ Exhibit.ListFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.ListFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.ListFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ for (var i = 0; i < selection.length; i++) {
+ facet._valueSet.add(selection[i]);
+ }
+ }
+ if ("selectMissing" in configuration) {
+ facet._selectMissing = configuration.selectMissing;
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+ if ("fixedOrder" in facet._settings) {
+ var values = facet._settings.fixedOrder.split(";");
+ var orderMap = {};
+ for (var i = 0; i < values.length; i++) {
+ orderMap[values[i].trim()] = i;
+ }
+
+ facet._orderMap = orderMap;
+ }
+
+ if ("colorCoder" in facet._settings) {
+ facet._colorCoder = facet._uiContext.getExhibit().getComponent(facet._settings.colorCoder);
+ }
+
+ if (facet._settings.collapsed) {
+ facet._settings.collapsible = true;
+ }
+
+ if ("formatter" in facet._settings) {
+ var formatter = facet._settings.formatter;
+ if (formatter != null && formatter.length > 0) {
+ try {
+ facet._formatter = eval(formatter);
+ } catch (e) {
+ SimileAjax.Debug.log(e);
+ }
+ }
+ }
+
+ facet._cache = new Exhibit.FacetUtilities.Cache(
+ facet._uiContext.getDatabase(),
+ facet._uiContext.getCollection(),
+ facet._expression
+ );
+}
+
+Exhibit.ListFacet.prototype.dispose = function() {
+ this._cache.dispose();
+ this._cache = null;
+
+ this._uiContext.getCollection().removeFacet(this);
+ this._uiContext = null;
+ this._colorCoder = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._valueSet = null;
+ this._settings = null;
+};
+
+Exhibit.ListFacet.prototype.hasRestrictions = function() {
+ return this._valueSet.size() > 0 || this._selectMissing;
+};
+
+Exhibit.ListFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = { selection: [], selectMissing: false };
+ if (this.hasRestrictions()) {
+ this._valueSet.visit(function(v) {
+ restrictions.selection.push(v);
+ });
+ this._valueSet = new Exhibit.Set();
+
+ restrictions.selectMissing = this._selectMissing;
+ this._selectMissing = false;
+
+ this._notifyCollection();
+ }
+ return restrictions;
+};
+
+Exhibit.ListFacet.prototype.applyRestrictions = function(restrictions) {
+ this._valueSet = new Exhibit.Set();
+ for (var i = 0; i < restrictions.selection.length; i++) {
+ this._valueSet.add(restrictions.selection[i]);
+ }
+ this._selectMissing = restrictions.selectMissing;
+
+ this._notifyCollection();
+};
+
+Exhibit.ListFacet.prototype.setSelection = function(value, selected) {
+ if (selected) {
+ this._valueSet.add(value);
+ } else {
+ this._valueSet.remove(value);
+ }
+ this._notifyCollection();
+}
+
+Exhibit.ListFacet.prototype.setSelectMissing = function(selected) {
+ if (selected != this._selectMissing) {
+ this._selectMissing = selected;
+ this._notifyCollection();
+ }
+}
+
+Exhibit.ListFacet.prototype.restrict = function(items) {
+ if (this._valueSet.size() == 0 && !this._selectMissing) {
+ return items;
+ }
+
+ var set = this._cache.getItemsFromValues(this._valueSet, items);
+ if (this._selectMissing) {
+ this._cache.getItemsMissingValue(items, set);
+ }
+
+ return set;
+};
+
+Exhibit.ListFacet.prototype.onUncollapse = function() {
+ if (this._delayedUpdateItems != null) {
+ this.update(this._delayedUpdateItems);
+ this._delayedUpdateItems = null;
+ }
+}
+
+Exhibit.ListFacet.prototype.update = function(items) {
+ if (Exhibit.FacetUtilities.isCollapsed(this)) {
+ this._delayedUpdateItems = items;
+ return;
+ }
+ this._dom.valuesContainer.style.display = "none";
+ this._dom.valuesContainer.innerHTML = "";
+ this._constructBody(this._computeFacet(items));
+ this._dom.valuesContainer.style.display = "block";
+};
+
+
+
+Exhibit.ListFacet.prototype._computeFacet = function(items) {
+ var database = this._uiContext.getDatabase();
+ var r = this._cache.getValueCountsFromItems(items);
+ var entries = r.entries;
+ var valueType = r.valueType;
+
+ if (entries.length > 0) {
+ var selection = this._valueSet;
+ var labeler = valueType == "item" ?
+ function(v) { var l = database.getObject(v, "label"); return l != null ? l : v; } :
+ function(v) { return v; }
+
+ for (var i = 0; i < entries.length; i++) {
+ var entry = entries[i];
+ entry.actionLabel = entry.selectionLabel = labeler(entry.value);
+ entry.selected = selection.contains(entry.value);
+ }
+
+ entries.sort(this._createSortFunction(valueType));
+ }
+
+ if (this._settings.showMissing || this._selectMissing) {
+ var count = this._cache.countItemsMissingValue(items);
+ if (count > 0 || this._selectMissing) {
+ var span = document.createElement("span");
+ span.innerHTML = ("missingLabel" in this._settings) ?
+ this._settings.missingLabel : Exhibit.FacetUtilities.l10n.missingThisField;
+ span.className = "exhibit-facet-value-missingThisField";
+
+ entries.unshift({
+ value: null,
+ count: count,
+ selected: this._selectMissing,
+ selectionLabel: span,
+ actionLabel: Exhibit.FacetUtilities.l10n.missingThisField
+ });
+ }
+ }
+
+ return entries;
+}
+
+Exhibit.ListFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.ListFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetFrame" : "constructFlowingFacetFrame"](
+ this,
+ this._div,
+ this._settings.facetLabel,
+ function(elmt, evt, target) { self._clearSelections(); },
+ this._uiContext,
+ this._settings.collapsible,
+ this._settings.collapsed
+ );
+
+ if ("height" in this._settings && this._settings.scroll) {
+ this._dom.valuesContainer.style.height = this._settings.height;
+ }
+};
+
+Exhibit.ListFacet.prototype._constructBody = function(entries) {
+ var self = this;
+ var containerDiv = this._dom.valuesContainer;
+
+ containerDiv.style.display = "none";
+
+ var constructFacetItemFunction = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetItem" : "constructFlowingFacetItem"];
+ var facetHasSelection = this._valueSet.size() > 0 || this._selectMissing;
+ var constructValue = function(entry) {
+ var onSelect = function(elmt, evt, target) {
+ self._filter(entry.value, entry.actionLabel, false);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var onSelectOnly = function(elmt, evt, target) {
+ self._filter(entry.value, entry.actionLabel, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var elmt = constructFacetItemFunction(
+ entry.selectionLabel,
+ entry.count,
+ (self._colorCoder != null) ? self._colorCoder.translate(entry.value) : null,
+ entry.selected,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ self._uiContext
+ );
+
+ if (self._formatter) self._formatter(elmt);
+
+ containerDiv.appendChild(elmt);
+ };
+
+ for (var j = 0; j < entries.length; j++) {
+ constructValue(entries[j]);
+ }
+ containerDiv.style.display = "block";
+
+ this._dom.setSelectionCount(this._valueSet.size() + (this._selectMissing ? 1 : 0));
+};
+
+Exhibit.ListFacet.prototype._filter = function(value, label, selectOnly) {
+ var self = this;
+ var selected, select, deselect;
+
+ var oldValues = new Exhibit.Set(this._valueSet);
+ var oldSelectMissing = this._selectMissing;
+
+ var newValues;
+ var newSelectMissing;
+ var actionLabel;
+
+ var wasSelected;
+ var wasOnlyThingSelected;
+
+ if (value == null) { // the (missing this field) case
+ wasSelected = oldSelectMissing;
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 0);
+
+ if (selectOnly) {
+ if (oldValues.size() == 0) {
+ newSelectMissing = !oldSelectMissing;
+ } else {
+ newSelectMissing = true;
+ }
+ newValues = new Exhibit.Set();
+ } else {
+ newSelectMissing = !oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ }
+ } else {
+ wasSelected = oldValues.contains(value);
+ wasOnlyThingSelected = wasSelected && (oldValues.size() == 1) && !oldSelectMissing;
+
+ if (selectOnly) {
+ newSelectMissing = false;
+ newValues = new Exhibit.Set();
+
+ if (!oldValues.contains(value)) {
+ newValues.add(value);
+ } else if (oldValues.size() > 1 || oldSelectMissing) {
+ newValues.add(value);
+ }
+ } else {
+ newSelectMissing = oldSelectMissing;
+ newValues = new Exhibit.Set(oldValues);
+ if (newValues.contains(value)) {
+ newValues.remove(value);
+ } else {
+ newValues.add(value);
+ }
+ }
+ }
+
+ var newRestrictions = { selection: newValues.toArray(), selectMissing: newSelectMissing };
+ var oldRestrictions = { selection: oldValues.toArray(), selectMissing: oldSelectMissing };
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ (selectOnly && !wasOnlyThingSelected) ?
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, this._settings.facetLabel ]) :
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+};
+
+Exhibit.ListFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+Exhibit.ListFacet.prototype._createSortFunction = function(valueType) {
+ var sortValueFunction = function(a, b) { return a.selectionLabel.localeCompare(b.selectionLabel); };
+ if ("_orderMap" in this) {
+ var orderMap = this._orderMap;
+
+ sortValueFunction = function(a, b) {
+ if (a.selectionLabel in orderMap) {
+ if (b.selectionLabel in orderMap) {
+ return orderMap[a.selectionLabel] - orderMap[b.selectionLabel];
+ } else {
+ return -1;
+ }
+ } else if (b.selectionLabel in orderMap) {
+ return 1;
+ } else {
+ return a.selectionLabel.localeCompare(b.selectionLabel);
+ }
+ }
+ } else if (valueType == "number") {
+ sortValueFunction = function(a, b) {
+ a = parseFloat(a.value);
+ b = parseFloat(b.value);
+ return a < b ? -1 : a > b ? 1 : 0;
+ }
+ }
+
+ var sortFunction = sortValueFunction;
+ if (this._settings.sortMode == "count") {
+ sortFunction = function(a, b) {
+ var c = b.count - a.count;
+ return c != 0 ? c : sortValueFunction(a, b);
+ }
+ }
+
+ var sortDirectionFunction = sortFunction;
+ if (this._settings.sortDirection == "reverse"){
+ sortDirectionFunction = function(a, b) {
+ return sortFunction(b, a);
+ }
+ }
+
+ return sortDirectionFunction;
+}
+
+Exhibit.ListFacet.prototype.exportFacetSelection = function() {
+ var s = [];
+ this._valueSet.visit(function(v) {
+ s.push(v);
+ });
+ if (s.length > 0) {
+ return s.join(',');
+ }
+};
+
+Exhibit.ListFacet.prototype.importFacetSelection = function(settings) {
+ var self = this;
+
+ self.applyRestrictions({ selection: settings.split(','), selectMissing: self._selectMissing });
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/numeric-range-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/numeric-range-facet.js
new file mode 100644
index 00000000..64d7b623
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/numeric-range-facet.js
@@ -0,0 +1,361 @@
+/*==================================================
+ * Exhibit.NumericRangeFacet
+ *==================================================
+ */
+
+Exhibit.NumericRangeFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._expression = null;
+ this._settings = {};
+
+ this._dom = null;
+ this._ranges = [];
+
+ var self = this;
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_rangeIndex" in self) {
+ delete self._rangeIndex;
+ }
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.NumericRangeFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "interval": { type: "float", defaultValue: 10 },
+ "collapsible": { type: "boolean", defaultValue: false },
+ "collapsed": { type: "boolean", defaultValue: false }
+};
+
+Exhibit.NumericRangeFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.NumericRangeFacet(
+ containerElmt,
+ uiContext
+ );
+
+ Exhibit.NumericRangeFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.NumericRangeFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.NumericRangeFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.NumericRangeFacet._settingSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "NumericRangeFacet: Error processing configuration of numeric range facet");
+ }
+ Exhibit.NumericRangeFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.NumericRangeFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.NumericRangeFacet._settingSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+
+ if (facet._settings.collapsed) {
+ facet._settings.collapsible = true;
+ }
+}
+
+Exhibit.NumericRangeFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+
+ this._uiContext.getCollection().removeListener(this._listener);
+ this._uiContext = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._settings = null;
+ this._ranges = null;
+};
+
+Exhibit.NumericRangeFacet.prototype.hasRestrictions = function() {
+ return this._ranges.length > 0;
+};
+
+Exhibit.NumericRangeFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = [];
+ if (this._ranges.length > 0) {
+ restrictions = restrictions.concat(this._ranges);
+ this._ranges = [];
+ this._notifyCollection();
+ }
+ return restrictions;
+};
+
+Exhibit.NumericRangeFacet.prototype.applyRestrictions = function(restrictions) {
+ this._ranges = restrictions;
+ this._notifyCollection();
+};
+
+Exhibit.NumericRangeFacet.prototype.setRange = function(from, to, selected) {
+ if (selected) {
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ if (range.from == from && range.to == to) {
+ return;
+ }
+ }
+ this._ranges.push({ from: from, to: to });
+ } else {
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ if (range.from == from && range.to == to) {
+ this._ranges.splice(i, 1);
+ break;
+ }
+ }
+ }
+ this._notifyCollection();
+}
+
+Exhibit.NumericRangeFacet.prototype.restrict = function(items) {
+ if (this._ranges.length == 0) {
+ return items;
+ } else if (this._expression.isPath()) {
+ var path = this._expression.getPath();
+ var database = this._uiContext.getDatabase();
+
+ var set = new Exhibit.Set();
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ set.addSet(path.rangeBackward(range.from, range.to, false, items, database).values);
+ }
+ return set;
+ } else {
+ this._buildRangeIndex();
+
+ var set = new Exhibit.Set();
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range = this._ranges[i];
+ this._rangeIndex.getSubjectsInRange(range.from, range.to, false, set, items);
+ }
+ return set;
+ }
+};
+
+Exhibit.NumericRangeFacet.prototype.update = function(items) {
+ this._dom.valuesContainer.style.display = "none";
+ this._dom.valuesContainer.innerHTML = "";
+
+ this._reconstruct(items);
+ this._dom.valuesContainer.style.display = "block";
+};
+
+Exhibit.NumericRangeFacet.prototype._reconstruct = function(items) {
+ var self = this;
+ var ranges = [];
+
+ var rangeIndex;
+ var computeItems;
+ if (this._expression.isPath()) {
+ var database = this._uiContext.getDatabase();
+ var path = this._expression.getPath();
+
+ var propertyID = path.getLastSegment().property;
+ var property = database.getProperty(propertyID);
+ if (property == null) {
+ return null;
+ }
+
+ rangeIndex = property.getRangeIndex();
+ countItems = function(range) {
+ return path.rangeBackward(range.from, range.to, false, items, database).values.size();
+ }
+ } else {
+ this._buildRangeIndex();
+
+ rangeIndex = this._rangeIndex;
+ countItems = function(range) {
+ return rangeIndex.getSubjectsInRange(range.from, range.to, false, null, items).size();
+ }
+ }
+
+ var min = rangeIndex.getMin();
+ var max = rangeIndex.getMax();
+ min = Math.floor(min / this._settings.interval) * this._settings.interval;
+ max = Math.ceil((max + this._settings.interval) / this._settings.interval) * this._settings.interval;
+
+ for (var x = min; x < max; x += this._settings.interval) {
+ var range = {
+ from: x,
+ to: x + this._settings.interval,
+ selected: false
+ };
+ range.count = countItems(range);
+
+ for (var i = 0; i < this._ranges.length; i++) {
+ var range2 = this._ranges[i];
+ if (range2.from == range.from && range2.to == range.to) {
+ range.selected = true;
+ facetHasSelection = true;
+ break;
+ }
+ }
+
+ ranges.push(range);
+ }
+
+ var facetHasSelection = this._ranges.length > 0;
+ var containerDiv = this._dom.valuesContainer;
+ containerDiv.style.display = "none";
+ var constructFacetItemFunction = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetItem" : "constructFlowingFacetItem"];
+ var makeFacetValue = function(from, to, count, selected) {
+ var onSelect = function(elmt, evt, target) {
+ self._toggleRange(from, to, selected, false);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var onSelectOnly = function(elmt, evt, target) {
+ self._toggleRange(from, to, selected, !(evt.ctrlKey || evt.metaKey));
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ };
+ var elmt = constructFacetItemFunction(
+ from + " - " + to,
+ count,
+ null,
+ selected,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ self._uiContext
+ );
+ containerDiv.appendChild(elmt);
+ };
+
+ for (var i = 0; i < ranges.length; i++) {
+ var range = ranges[i];
+ if (range.selected || range.count > 0) {
+ makeFacetValue(range.from, range.to, range.count, range.selected);
+ }
+ }
+ containerDiv.style.display = "block";
+
+ this._dom.setSelectionCount(this._ranges.length);
+}
+
+Exhibit.NumericRangeFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.NumericRangeFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.FacetUtilities[this._settings.scroll ? "constructFacetFrame" : "constructFlowingFacetFrame"](
+ this,
+ this._div,
+ this._settings.facetLabel,
+ function(elmt, evt, target) { self._clearSelections(); },
+ this._uiContext,
+ this._settings.collapsible,
+ this._settings.collapsed
+ );
+
+ if ("height" in this._settings) {
+ this._dom.valuesContainer.style.height = this._settings.height;
+ }
+};
+
+Exhibit.NumericRangeFacet.prototype._toggleRange = function(from, to, wasSelected, singleSelection) {
+ var self = this;
+ var label = from + " to " + to;
+ var wasOnlyThingSelected = (this._ranges.length == 1 && wasSelected);
+ if (singleSelection && !wasOnlyThingSelected) {
+ var newRestrictions = [ { from: from, to: to } ];
+ var oldRestrictions = [].concat(this._ranges);
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.applyRestrictions(newRestrictions); },
+ function() { self.applyRestrictions(oldRestrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetSelectOnlyActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+ } else {
+ SimileAjax.History.addLengthyAction(
+ function() { self.setRange(from, to, !wasSelected); },
+ function() { self.setRange(from, to, wasSelected); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n[wasSelected ? "facetUnselectActionTitle" : "facetSelectActionTitle"],
+ [ label, this._settings.facetLabel ])
+ );
+ }
+};
+
+Exhibit.NumericRangeFacet.prototype._clearSelections = function() {
+ var state = {};
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = self.clearAllRestrictions(); },
+ function() { self.applyRestrictions(state.restrictions); },
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetClearSelectionsActionTitle"],
+ [ this._settings.facetLabel ])
+ );
+};
+
+
+Exhibit.NumericRangeFacet.prototype._buildRangeIndex = function() {
+ if (!("_rangeIndex" in this)) {
+ var expression = this._expression;
+ var database = this._uiContext.getDatabase();
+ var getter = function(item, f) {
+ expression.evaluateOnItem(item, database).values.visit(function(value) {
+ if (typeof value != "number") {
+ value = parseFloat(value);
+ }
+ if (!isNaN(value)) {
+ f(value);
+ }
+ });
+ };
+
+ this._rangeIndex = new Exhibit.Database._RangeIndex(
+ this._uiContext.getCollection().getAllItems(),
+ getter
+ );
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider-facet.js
new file mode 100644
index 00000000..33c9ac50
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider-facet.js
@@ -0,0 +1,291 @@
+/*==================================================
+ * Exhibit.SliderFacet
+ *==================================================
+ */
+
+
+Exhibit.SliderFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._expression = null;
+ this._settings = {};
+
+ this._selection = {min: null, max: null};
+ this._range = {min: null, max: null}; //currently selected range
+ this._maxRange = {min: null, max: null}; //total range of slider
+};
+
+
+
+Exhibit.SliderFacet._settingsSpecs = {
+ "facetLabel": { type: "text" },
+ "scroll": { type: "boolean", defaultValue: true },
+ "height": { type: "text" },
+ "precision": { type: "float", defaultValue: 1 },
+ "histogram": { type: "boolean", defaultValue: true },
+ "height": { type: "int", defaultValue: false },
+ "width": { type: "int", defaultValue: false },
+ "horizontal": { type: "boolean", defaultValue: true },
+ "inputText": { type: "boolean", defaultValue: true },
+ "showMissing": { type: "boolean", defaultValue: true}
+ };
+
+
+
+Exhibit.SliderFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.SliderFacet(containerElmt, uiContext);
+
+ Exhibit.SliderFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+//this is what Exhibit.UI.createFromDOM(elmt, uiContext) redirects to for the slider facet
+Exhibit.SliderFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.SliderFacet(
+ containerElmt != null? containerElmt : configElmt,
+ uiContext
+ );
+
+ //fills facet with configuration information
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.SliderFacet._settingsSpecs, facet._settings);
+
+ try {
+ var expressionString = Exhibit.getAttribute(configElmt, "expression");
+ if (expressionString != null && expressionString.length > 0) {
+ facet._expression = Exhibit.ExpressionParser.parse(expressionString);
+ }
+
+ var showMissing = Exhibit.getAttribute(configElmt, "showMissing");
+
+ if (showMissing != null && showMissing.length > 0) {
+ facet._showMissing = (showMissing == "true");
+ }
+ else{facet._showMissing=true;}
+
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "SliderFacet: Error processing configuration of slider facet");
+ }
+
+ Exhibit.SliderFacet._configure(facet, configuration);
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+//what appears to be redundant configuration
+Exhibit.SliderFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.SliderFacet._settingsSpecs, facet._settings);
+
+ if ("expression" in configuration) {
+ facet._expression = Exhibit.ExpressionParser.parse(configuration.expression);
+
+ }
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ facet._selection = {min: selection[0], max: selection[1]};
+ }
+
+ if ("showMissing" in configuration){
+ facet._showMissing=configuration.showMissing;
+
+ }
+
+
+
+
+
+ //needs to be altered...get a label for something complex
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "missing ex:facetLabel";
+ if (facet._expression != null && facet._expression.isPath()) {
+ var segment = facet._expression.getPath().getLastSegment();
+ var property = facet._uiContext.getDatabase().getProperty(segment.property);
+ if (property != null) {
+ facet._settings.facetLabel = segment.forward ? property.getLabel() : property.getReverseLabel();
+ }
+ }
+ }
+
+ facet._cache = new Exhibit.FacetUtilities.Cache(
+ facet._uiContext.getDatabase(),
+ facet._uiContext.getCollection(),
+ facet._expression
+ );
+
+ facet._maxRange = facet._getMaxRange();
+};
+//initializes UI, obviously
+Exhibit.SliderFacet.prototype._initializeUI = function() {
+ this._dom = SimileAjax.DOM.createDOMFromString(
+ this._div,
+ "<div class='exhibit-facet-header'>" +
+ "<span class='exhibit-facet-header-title'>" + this._settings.facetLabel + "</span>" +
+ "</div>" +
+ "<div class='exhibit-slider' id='slider'></div>"
+ );
+
+ this._slider = new Exhibit.SliderFacet.slider(this._dom.slider, this, this._settings.precision, this._settings.horizontal);
+};
+
+//checks for user use of slider, null if slider not yet used
+Exhibit.SliderFacet.prototype.hasRestrictions = function() {
+ return (this._range.min && this._range.min != this._maxRange.min) || (this._range.max && this._range.max != this._maxRange.max);
+};
+
+//[items] used by other function
+Exhibit.SliderFacet.prototype.update = function(items) {
+ if (this._settings.histogram) {
+ var data = [];
+ var n = 75; //number of bars on histogram
+ var range = (this._maxRange.max - this._maxRange.min)/n //range represented by each bar
+ var missingCount=0;
+ var database = this._uiContext.getDatabase();
+
+ if(this._selectMissing){
+ missingCount=this._cache.getItemsMissingValue(items).size();
+
+
+ }
+ if(this._expression.isPath()){
+ var path = this._expression.getPath();
+
+ for(var i=0; i<n; i++) {
+ data[i] = path.rangeBackward(this._maxRange.min+i*range, this._maxRange.min+(i+1)*range, false, items,database).values.size()+missingCount;
+ }
+ }
+
+
+ else{
+ this._buildRangeIndex();
+ var rangeIndex=this._rangeIndex;
+
+ for(var i=0; i<n; i++){
+
+ data[i] = rangeIndex.getSubjectsInRange(this._maxRange.min+i*range, this._maxRange.min+(i+1)*range, false, null, items).size()+missingCount;
+ }
+
+ }
+
+
+ this._slider.updateHistogram(data);
+ }
+
+};
+//[items] used by other function
+Exhibit.SliderFacet.prototype.restrict = function(items) {
+ if (!this.hasRestrictions()) {
+ return items;
+ }
+
+
+ set=new Exhibit.Set();
+
+
+
+
+ if(this._expression.isPath()){
+ var path = this._expression.getPath();
+ var database = this._uiContext.getDatabase();
+ set=path.rangeBackward(this._range.min, this._range.max, false, items, database).values;
+
+ }
+
+ else{
+ this._buildRangeIndex();
+ var rangeIndex=this._rangeIndex;
+ set=rangeIndex.getSubjectsInRange(this._range.min, this._range.max, false, null, items);
+
+
+ }
+
+ if(this._showMissing){
+
+ this._cache.getItemsMissingValue(items, set);
+ }
+
+ return set;
+
+};
+//gets maximum range? need to construct a range index for this...
+Exhibit.SliderFacet.prototype._getMaxRange = function() {
+ if(this._expression.getPath()){
+ var path = this._expression.getPath();
+ var database = this._uiContext.getDatabase();
+ var propertyID = path.getLastSegment().property;
+ var property = database.getProperty(propertyID);
+ var rangeIndex = property.getRangeIndex();
+ }
+ else{
+
+ this._buildRangeIndex();
+ var rangeIndex=this._rangeIndex;
+
+
+ }
+
+ return {min: rangeIndex.getMin(), max: rangeIndex.getMax()};
+};
+
+Exhibit.SliderFacet.prototype._buildRangeIndex = function() {
+ if (!("_rangeIndex" in this)) {
+ var expression = this._expression;
+ var database = this._uiContext.getDatabase();
+ var getter = function(item, f) {
+ expression.evaluateOnItem(item, database).values.visit(function(value) {
+ if (typeof value != "number") {
+ value = parseFloat(value);
+ }
+ if (!isNaN(value)) {
+ f(value);
+ }
+ });
+ };
+
+ this._rangeIndex = new Exhibit.Database._RangeIndex(
+ this._uiContext.getCollection().getAllItems(),
+ getter
+ );
+ }
+};
+
+
+//clear
+Exhibit.SliderFacet.prototype.changeRange = function(range) {
+ this._range = range;
+ this._notifyCollection();
+};
+//clear
+Exhibit.SliderFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+//clear
+Exhibit.SliderFacet.prototype.clearAllRestrictions = function() {
+ this._slider.resetSliders();
+ this._range = this._maxRange;
+};
+//clear
+Exhibit.SliderFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+ this._uiContext = null;
+ this._colorCoder = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expression = null;
+ this._settings = null;
+
+ this._selection = null;
+ this._range = null; //currently selected range
+ this._maxRange = null; //total range of slider
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider.js
new file mode 100644
index 00000000..e3558539
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/slider.js
@@ -0,0 +1,363 @@
+
+Exhibit.SliderFacet.slider = function(div, facet, precision) {
+ this._div = div;
+ this._facet = facet;
+ this._prec = precision || .1;
+ this._maxRange = {min: parseFloat(Exhibit.Util.round(facet._maxRange.min-precision/2, this._prec)), // round down
+ max: parseFloat(Exhibit.Util.round(facet._maxRange.max+precision/2, this._prec))}; // round up
+ this._horizontal = this._facet._settings.horizontal;
+
+ this._scaleFactor = null; // scale factor used for determining value from slider position
+ this._slider1 = {};
+ this._slider2 = {};
+
+ this._dom = SimileAjax.DOM.createDOMFromString(
+ div,
+ '<div class="exhibit-slider-bar" id="bar">' +
+ '<div id="slider1"></div>' +
+ '<div id="slider2"></div>' +
+ (this._facet._settings.histogram? '<div class="exhibit-slider-histogram" id="histogram"></div>':'') +
+ '</div>' +
+ '<div class="exhibit-slider-display">' +
+ (this._facet._settings.inputText? '<input type="text" id="minDisplay"></input> - <input type="text" id="maxDisplay"></input> '
+ : '<span id="minDisplay"></span> - <span id="maxDisplay"></span>') +
+ '</div>'
+ );
+
+ // sizing
+ var horizontal = this._horizontal;
+ var histogram = this._dom.histogram;
+
+ if (horizontal && histogram) { // horizontal and histogram
+ this._dom.bar.style.height = '14px';
+ this._dom.bar.style.width = '150px'
+ }
+ else if (horizontal && !histogram) { // horizontal and no histogram
+ this._dom.bar.style.height = '1px';
+ this._dom.bar.style.width = '150px'
+ }
+ else if (!horizontal && histogram) { // vertical and histogram
+ this._dom.bar.style.height = '150px';
+ this._dom.bar.style.width = '14px'
+ }
+ else { // vertical and no histogram
+ this._dom.bar.style.height = '150px';
+ this._dom.bar.style.width = '1px'
+ }
+
+ if (this._facet._settings.height) {
+ this._dom.bar.style.height = this._facet._settings.height+'px';
+ }
+ if (this._facet._settings.width) {
+ this._dom.bar.style.width = this._facet._settings.width+'px';
+ }
+
+ if(histogram) {
+ this._dom.histogram.style.height = this._dom.bar.offsetHeight;
+ this._dom.histogram.style.width = this._dom.bar.offsetWidth;
+ }
+
+ if (horizontal) {
+ this._scaleFactor = (this._maxRange.max - this._maxRange.min)/this._dom.bar.offsetWidth;
+ } else {
+ this._scaleFactor = (this._maxRange.max - this._maxRange.min)/this._dom.bar.offsetHeight;
+ }
+
+ // init sliders
+ this._slider1 = new Exhibit.SliderFacet.slider.slider(this._dom.slider1, this);
+ this._slider2 = new Exhibit.SliderFacet.slider.slider(this._dom.slider2, this);
+ this._setSlider(this._slider1, this._maxRange.min);
+ this._setSlider(this._slider2, this._maxRange.max);
+
+ this._registerDragging();
+
+
+ if (this._facet._settings.inputText) {
+ this._registerInputs();
+ }
+
+};
+
+// If you call this, it's up to you to notifyFacet if necessary
+Exhibit.SliderFacet.slider.prototype.resetSliders = function(){
+ this._setSlider(this._slider1, this._maxRange.min);
+ this._setSlider(this._slider2, this._maxRange.max);
+};
+
+// If you call this, it's up to you to notifyFacet if necessary
+Exhibit.SliderFacet.slider.prototype._setSlider = function(slider, value) {
+ if (value > this._maxRange.max) {
+ value = this._maxRange.max
+ }
+ else if (value < this._maxRange.min) {
+ value = this._maxRange.min
+ }
+
+ value = parseFloat(Exhibit.Util.round(value, this._prec));
+
+ slider.value = value;
+
+ if (this._horizontal) {
+ slider.div.style.left = ((value-this._maxRange.min)/this._scaleFactor-slider.offset) + 'px';
+ } else {
+ slider.div.style.top = ((value-this._maxRange.min)/this._scaleFactor-slider.offset) + 'px';
+ }
+
+ this._setDisplays(slider);
+};
+
+// If you call this, it's up to you to notifyFacet if necessary
+Exhibit.SliderFacet.slider.prototype._setMin = function(value) {
+ var slider = this._slider1.value < this._slider2.value? this._slider1 : this._slider2;
+ var other = (slider == this._slider1)? this._slider2 : this._slider1;
+
+ value = parseFloat(value);
+ if (isNaN(value)) {
+ return;
+ }
+
+ if (value > other.value) {
+ value = other.value;
+ }
+
+ this._setSlider(slider, value);
+};
+
+// If you call this, it's up to you to notifyFacet if necessary
+Exhibit.SliderFacet.slider.prototype._setMax = function(value) {
+ var slider = this._slider1.value > this._slider2.value? this._slider1 : this._slider2;
+ var other = (slider == this._slider1)? this._slider2 : this._slider1;
+
+ value = parseFloat(value);
+ if (isNaN(value)) {
+ return;
+ }
+
+ if (value < other.value) {
+ value = other.value;
+ }
+
+ this._setSlider(slider, value);
+};
+
+// Updates displays based on slider's value (i.e., slider's value should have changed recently)
+Exhibit.SliderFacet.slider.prototype._setDisplays = function(slider) {
+ var other = (slider == this._slider1)? this._slider2 : this._slider1;
+
+ var min = Math.min(slider.value, other.value);
+ var max = Math.max(slider.value, other.value);
+
+ if (this._facet._settings.inputText) {
+ this._dom.minDisplay.value = min;
+ this._dom.maxDisplay.value = max;
+ } else {
+ this._dom.minDisplay.innerHTML = min;
+ this._dom.maxDisplay.innerHTML = max;
+ }
+};
+
+Exhibit.SliderFacet.slider.slider = function(div, self) { // individual slider handle that can be dragged
+ var barEl = self._dom.bar;
+
+ this.div = div; // containing div of handle
+
+ if (self._horizontal) {
+ this.div.className = "exhibit-slider-handle";
+ this.div.style.backgroundImage = 'url("'+Exhibit.urlPrefix+'images/slider-handle.png")';
+ this.offset = this.div.offsetWidth/2;
+ this.min = -this.offset; // slider's middle can reach left edge of bar
+ this.max = barEl.offsetWidth - this.offset; //slider's middle can reach right edge of bar
+ } else {
+ this.div.className = "exhibit-slider-handle2";
+ this.div.style.backgroundImage = 'url("'+Exhibit.urlPrefix+'images/slider-handle2.png")';
+ this.offset = this.div.offsetHeight/2;
+ this.min = -this.offset; // slider's middle can reach left edge of bar
+ this.max = barEl.offsetHeight - this.offset; //slider's middle can reach right edge of bar
+ }
+
+ if (self._facet._settings.histogram) {
+ this.div.style.top = (barEl.offsetHeight-4)+'px';
+ }
+};
+
+
+Exhibit.SliderFacet.slider.prototype._registerDragging = function() {
+ var self = this;
+
+ var startDrag = function(slider) {
+ return function(e) {
+ e = e || window.event;
+
+ var onMove = self._horizontal? onDragH(e, slider) : onDragV(e, slider);
+
+ if (document.attachEvent) {
+ document.attachEvent('onmousemove', onMove);
+ document.attachEvent('onmouseup', endDrag(slider, onMove));
+ } else {
+ document.addEventListener('mousemove', onMove, false);
+ document.addEventListener('mouseup', endDrag(slider, onMove), false);
+ }
+
+ SimileAjax.DOM.cancelEvent(e);
+ return false;
+ };
+ };
+
+ var onDragH = function(e, slider) {
+ var origX = e.screenX;
+ var origLeft = parseInt(slider.div.style.left);
+ var min = slider.min;
+ var max = slider.max;
+
+ return function(e) {
+ e = e || window.event
+
+ var dx = e.screenX - origX;
+ var newLeft = origLeft + dx;
+ if (newLeft < min) {
+ newLeft = min;
+ }
+ if (newLeft > max) {
+ newLeft = max;
+ }
+ slider.div.style.left = newLeft + 'px';
+
+ //setTimeout keeps setDisplay from slowing down the dragging
+ //I'm not entirely sure why, but I think it might have something to do with it putting the call in a new environment
+ setTimeout(function(){ var position = parseInt(slider.div.style.left) + slider.offset;
+ slider.value = parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min, self._prec));
+ self._setDisplays(slider); }, 0);
+ };
+ };
+
+ var onDragV = function(e, slider) {
+ var origY = e.screenY;
+ var origTop = parseInt(slider.div.style.top);
+ var min = slider.min;
+ var max = slider.max;
+
+ return function(e) {
+ e = e || window.event
+
+ var dy = e.screenY - origY;
+ var newTop = origTop + dy;
+ if (newTop < min) {
+ newTop = min;
+ }
+ if (newTop > max) {
+ newTop = max;
+ }
+ slider.div.style.top = newTop + 'px';
+
+ //setTimeout keeps setDisplay from slowing down the dragging
+ //I'm not entirely sure why, but I think it might have something to do with it putting the call in a new environment
+ setTimeout(function(){ var position = parseInt(slider.div.style.top) + slider.offset;
+ slider.value = parseFloat(Exhibit.Util.round(position*self._scaleFactor+self._maxRange.min, self._prec));
+ self._setDisplays(slider); }, 0);
+ };
+ };
+
+ var endDrag = function(slider, moveListener) {
+ return function(e) {
+
+ if(document.detachEvent) {
+ document.detachEvent('onmousemove', moveListener);
+ document.detachEvent('onmouseup', arguments.callee);
+ } else {
+ document.removeEventListener('mousemove', moveListener, false);
+ document.removeEventListener('mouseup', arguments.callee, false); //remove this function
+ }
+
+ self._notifyFacet();
+ };
+ };
+
+ var attachListeners = function(slider) {
+ if (document.attachEvent) {
+ slider.div.attachEvent('onmousedown', startDrag(slider));
+ } else {
+ slider.div.addEventListener('mousedown', startDrag(slider), false);
+ }
+ };
+
+ attachListeners(this._slider1);
+ attachListeners(this._slider2);
+
+};
+
+
+Exhibit.SliderFacet.slider.prototype._notifyFacet = function() {
+ var val1 = this._slider1.value;
+ var val2 = this._slider2.value;
+ this._facet.changeRange( {min: Math.min(val1, val2), max: Math.max(val1, val2)} );
+};
+
+
+Exhibit.SliderFacet.slider.prototype.updateHistogram = function(data) {
+ // data ([numbers]): the values to graphed (essentially specifies the relative height of each bar)
+ // data.length = # of bars
+
+ var n = data.length;
+ var histogram = this._dom.histogram; //data = [0,1,2]; n = 4;
+
+ var maxVal = Math.max.apply(Math, data); //find the max of an array
+ if (!maxVal) {
+ return; //nothing to draw
+ }
+
+ if (this._horizontal) {
+ var width = histogram.offsetWidth/n; // width of each bar
+ var maxHeight = histogram.offsetHeight;
+ var ratio = maxHeight/maxVal;
+
+ histogram.innerHTML = ''; //clear histogram
+
+ for (var i=0; i<n; i++){ // create new bars
+ var height = Math.round(data[i]*ratio);
+
+ var bar = document.createElement('div');
+ histogram.appendChild(bar);
+ bar.style.width = width+'px';
+ bar.style.height = height+'px';
+ bar.style.display = height? '' : 'none'; //IE, even with font-size:0,
+ //will still render divs with height:0
+ //as several pixels tall
+ bar.style.position = 'absolute';
+ bar.style.top = (maxHeight-height)+'px';
+ bar.style.left = i*width+'px';
+
+ }
+ } else { // vertical (height and width are essentially flipped)
+ var width = histogram.offsetHeight/n; // width of each bar
+ var maxHeight = histogram.offsetWidth;
+ var ratio = maxHeight/maxVal;
+
+ histogram.innerHTML = ''; //clear histogram
+
+ for (var i=0; i<n; i++){ // create new bars
+ var height = Math.round(data[i]*ratio);
+
+ var bar = document.createElement('div');
+ bar.style.height = width;
+ bar.style.width = height;
+ bar.style.position = 'absolute';
+ bar.style.left = 0;
+ bar.style.top = i*width;
+
+ histogram.appendChild(bar);
+ }
+ }
+
+};
+
+Exhibit.SliderFacet.slider.prototype._registerInputs = function() {
+ var self = this;
+
+ if (document.attachEvent) {
+ this._dom.minDisplay.attachEvent('onchange', function(e) {self._setMin(this.value); self._notifyFacet()});
+ this._dom.maxDisplay.attachEvent('onchange', function(e) {self._setMax(this.value); self._notifyFacet()});
+ } else {
+ this._dom.minDisplay.addEventListener('change', function(e) {self._setMin(this.value); self._notifyFacet()}, false);
+ this._dom.maxDisplay.addEventListener('change', function(e) {self._setMax(this.value); self._notifyFacet()}, false);
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/text-search-facet.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/text-search-facet.js
new file mode 100644
index 00000000..a4a6a62a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/facets/text-search-facet.js
@@ -0,0 +1,294 @@
+/*==================================================
+ * Exhibit.TextSearchFacet
+ *==================================================
+ */
+
+Exhibit.TextSearchFacet = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._expressions = [];
+ this._text = null;
+
+ this._settings = {};
+ this._dom = null;
+ this._timerID = null;
+
+ var self = this;
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_itemToValue" in self) {
+ delete self._itemToValue;
+ }
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.TextSearchFacet._settingSpecs = {
+ "facetLabel": { type: "text" },
+ "queryParamName": { type: "text" },
+ "requiresEnter": {type: "boolean", defaultValue: false}
+ };
+
+Exhibit.TextSearchFacet.create = function(configuration, containerElmt, uiContext) {
+ var uiContext = Exhibit.UIContext.create(configuration, uiContext);
+ var facet = new Exhibit.TextSearchFacet(containerElmt, uiContext);
+
+ Exhibit.TextSearchFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.TextSearchFacet.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+ var facet = new Exhibit.TextSearchFacet(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.TextSearchFacet._settingSpecs, facet._settings);
+
+ try {
+ var s = Exhibit.getAttribute(configElmt, "expressions");
+ if (s != null && s.length > 0) {
+ facet._expressions = Exhibit.ExpressionParser.parseSeveral(s);
+ }
+
+ var query = Exhibit.getAttribute(configElmt, "query");
+ if (query != null && query.length > 0) {
+ facet._text = query;
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "TextSearchFacet: Error processing configuration of list facet");
+ }
+ Exhibit.TextSearchFacet._configure(facet, configuration);
+
+ facet._initializeUI();
+ uiContext.getCollection().addFacet(facet);
+
+ return facet;
+};
+
+Exhibit.TextSearchFacet._configure = function(facet, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.TextSearchFacet._settingSpecs, facet._settings);
+
+ if ("expressions" in configuration) {
+ for (var i = 0; i < configuration.expressions.length; i++) {
+ facet._expressions.push(Exhibit.ExpressionParser.parse(configuration.expressions[i]));
+ }
+ }
+ if ("selection" in configuration) {
+ var selection = configuration.selection;
+ for (var i = 0; i < selection.length; i++) {
+ facet._valueSet.add(selection[i]);
+ }
+ }
+ if ("query" in configuration) {
+ facet._text = configuration.query;
+ }
+ if ("queryParamName" in facet._settings) {
+ var params = SimileAjax.parseURLParameters();
+ if (facet._settings["queryParamName"] in params) {
+ facet._text = params[facet._settings["queryParamName"]];
+ }
+ }
+
+ if (!("facetLabel" in facet._settings)) {
+ facet._settings.facetLabel = "";
+ }
+}
+
+Exhibit.TextSearchFacet.prototype.dispose = function() {
+ this._uiContext.getCollection().removeFacet(this);
+
+ this._uiContext.getCollection().removeListener(this._listener);
+ this._uiContext = null;
+
+ this._div.innerHTML = "";
+ this._div = null;
+ this._dom = null;
+
+ this._expressions = null;
+ this._itemToValue = null;
+ this._settings = null;
+};
+
+Exhibit.TextSearchFacet.prototype.hasRestrictions = function() {
+ return this._text != null;
+};
+
+Exhibit.TextSearchFacet.prototype.clearAllRestrictions = function() {
+ var restrictions = this._text;
+ if (this._text != null) {
+ this._text = null;
+ this._notifyCollection();
+ }
+ this._dom.input.value = "";
+
+ return restrictions;
+};
+
+Exhibit.TextSearchFacet.prototype.applyRestrictions = function(restrictions) {
+ this.setText(restrictions);
+};
+
+Exhibit.TextSearchFacet.prototype.setText = function(text) {
+ if (text != null) {
+ text = text.trim();
+ this._dom.input.value = text;
+
+ text = text.length > 0 ? text : null;
+ } else {
+ this._dom.input.value = "";
+ }
+
+ if (text != this._text) {
+ this._text = text;
+ this._notifyCollection();
+ }
+}
+
+Exhibit.TextSearchFacet.prototype.restrict = function(items) {
+ if (this._text == null) {
+ return items;
+ } else {
+ this._buildMaps();
+
+ var set = new Exhibit.Set();
+ var itemToValue = this._itemToValue;
+ var text = this._text.toLowerCase();
+
+ items.visit(function(item) {
+ if (item in itemToValue) {
+ var values = itemToValue[item];
+ for (var v = 0; v < values.length; v++) {
+ if (values[v].indexOf(text) >= 0) {
+ set.add(item);
+ break;
+ }
+ }
+ }
+ });
+ return set;
+ }
+};
+
+Exhibit.TextSearchFacet.prototype.update = function(items) {
+ // nothing to do
+};
+
+Exhibit.TextSearchFacet.prototype._notifyCollection = function() {
+ this._uiContext.getCollection().onFacetUpdated(this);
+};
+
+Exhibit.TextSearchFacet.prototype._initializeUI = function() {
+ var self = this;
+ this._dom = Exhibit.TextSearchFacet.constructFacetFrame(this._div, this._settings.facetLabel);
+
+ if (this._text != null) {
+ this._dom.input.value = this._text;
+ }
+
+ SimileAjax.WindowManager.registerEvent(this._dom.input, "keyup",
+ function(elmt, evt, target) { self._onTextInputKeyUp(evt); });
+};
+
+Exhibit.TextSearchFacet.constructFacetFrame = function(div, facetLabel) {
+ if (facetLabel !== "" && facetLabel !== null) {
+ return SimileAjax.DOM.createDOMFromString(
+ div,
+ "<div class='exhibit-facet-header'>" +
+ "<span class='exhibit-facet-header-title'>" + facetLabel + "</span>" +
+ "</div>" +
+ "<div class='exhibit-text-facet'><input type='text' id='input'></div>"
+ );
+ } else {
+ return SimileAjax.DOM.createDOMFromString(
+ div,
+ "<div class='exhibit-text-facet'><input type='text' id='input'></div>"
+ );
+ }
+};
+
+Exhibit.TextSearchFacet.prototype._onTextInputKeyUp = function(evt) {
+ if (this._timerID != null) {
+ window.clearTimeout(this._timerID);
+ }
+ var self = this;
+ if (this._settings.requiresEnter == false) {
+ this._timerID = window.setTimeout(function() { self._onTimeout(); }, 500);
+ } else {
+ var newText = this._dom.input.value.trim();
+ if (newText.length == 0 || evt.keyCode == 13) { // arbitrary
+ this._timerID = window.setTimeout(function() { self._onTimeout(); }, 0);
+ }
+ }
+};
+
+Exhibit.TextSearchFacet.prototype._onTimeout = function() {
+ this._timerID = null;
+
+ var newText = this._dom.input.value.trim();
+ if (newText.length == 0) {
+ newText = null;
+ }
+
+ if (newText != this._text) {
+ var self = this;
+ var oldText = this._text;
+
+ SimileAjax.History.addLengthyAction(
+ function() { self.setText(newText); },
+ function() { self.setText(oldText); },
+ newText != null ?
+ String.substitute(
+ Exhibit.FacetUtilities.l10n["facetTextSearchActionTitle"],
+ [ newText ]) :
+ Exhibit.FacetUtilities.l10n["facetClearTextSearchActionTitle"]
+ );
+ }
+}
+
+Exhibit.TextSearchFacet.prototype._buildMaps = function() {
+ if (!("_itemToValue" in this)) {
+ var itemToValue = {};
+ var allItems = this._uiContext.getCollection().getAllItems();
+ var database = this._uiContext.getDatabase();
+
+ if (this._expressions.length > 0) {
+ var expressions = this._expressions;
+ allItems.visit(function(item) {
+ var values = [];
+ for (var x = 0; x < expressions.length; x++) {
+ var expression = expressions[x];
+ expression.evaluateOnItem(item, database).values.visit(function(v) { values.push(v.toLowerCase()); });
+ }
+ itemToValue[item] = values;
+ });
+ } else {
+ var propertyIDs = database.getAllProperties();
+ allItems.visit(function(item) {
+ var values = [];
+ for (var p = 0; p < propertyIDs.length; p++) {
+ database.getObjects(item, propertyIDs[p]).visit(function(v) { values.push(v.toLowerCase()); });
+ }
+ itemToValue[item] = values;
+ });
+ }
+
+ this._itemToValue = itemToValue;
+ }
+};
+
+Exhibit.TextSearchFacet.prototype.exportFacetSelection = function() {
+ return this._text;
+};
+
+Exhibit.TextSearchFacet.prototype.importFacetSelection = function(settings) {
+ this.setText(settings);
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/format-parser.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/format-parser.js
new file mode 100644
index 00000000..14bc9c00
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/format-parser.js
@@ -0,0 +1,500 @@
+/*==================================================
+ * Exhibit.FormatParser
+ * http://simile.mit.edu/wiki/Exhibit/API/FormatParser
+ *==================================================
+ */
+Exhibit.FormatParser = new Object();
+
+Exhibit.FormatParser.parse = function(uiContext, s, startIndex, results) {
+ startIndex = startIndex || 0;
+ results = results || {};
+
+ var scanner = new Exhibit.FormatScanner(s, startIndex);
+ try {
+ return Exhibit.FormatParser._internalParse(uiContext, scanner, results, false);
+ } finally {
+ results.index = scanner.token() != null ? scanner.token().start : scanner.index();
+ }
+};
+
+Exhibit.FormatParser.parseSeveral = function(uiContext, s, startIndex, results) {
+ startIndex = startIndex || 0;
+ results = results || {};
+
+ var scanner = new Exhibit.FormatScanner(s, startIndex);
+ try {
+ return Exhibit.FormatParser._internalParse(uiContext, scanner, results, true);
+ } finally {
+ results.index = scanner.token() != null ? scanner.token().start : scanner.index();
+ }
+};
+
+Exhibit.FormatParser._valueTypes = {
+ "list" : true,
+ "number" : true,
+ "date" : true,
+ "item" : true,
+ "text" : true,
+ "url" : true,
+ "image" : true,
+ "currency" : true
+};
+
+Exhibit.FormatParser._internalParse = function(uiContext, scanner, results, several) {
+ var Scanner = Exhibit.FormatScanner;
+ var token = scanner.token();
+ var next = function() { scanner.next(); token = scanner.token(); };
+ var makePosition = function() { return token != null ? token.start : scanner.index(); };
+ var enterSetting = function(valueType, settingName, value) {
+ uiContext.putSetting("format/" + valueType + "/" + settingName, value);
+ };
+ var checkKeywords = function(valueType, settingName, keywords) {
+ if (token != null && token.type != Scanner.IDENTIFIER && token.value in keywords) {
+ enterSetting(valueType, settingName, keywords[token.value]);
+ next();
+ return false;
+ }
+ return true;
+ };
+
+ var parseNumber = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.NUMBER) {
+ throw new Error("Missing number at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, token.value);
+ next();
+ }
+ };
+ var parseInteger = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.NUMBER) {
+ throw new Error("Missing integer at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, Math.round(token.value));
+ next();
+ }
+ };
+ var parseNonnegativeInteger = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.NUMBER || token.value < 0) {
+ throw new Error("Missing non-negative integer at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, Math.round(token.value));
+ next();
+ }
+ };
+ var parseString = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.STRING) {
+ throw new Error("Missing string at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, token.value);
+ next();
+ }
+ };
+ var parseURL = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.URL) {
+ throw new Error("Missing url at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, token.value);
+ next();
+ }
+ };
+ var parseExpression = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || token.type != Scanner.EXPRESSION) {
+ throw new Error("Missing expression at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, token.value);
+ next();
+ }
+ };
+ var parseExpressionOrString = function(valueType, settingName, keywords) {
+ if (checkKeywords(valueType, settingName, keywords)) {
+ if (token == null || (token.type != Scanner.EXPRESSION && token.type != Scanner.STRING)) {
+ throw new Error("Missing expression or string at position " + makePosition());
+ }
+ enterSetting(valueType, settingName, token.value);
+ next();
+ }
+ };
+ var parseChoices = function(valueType, settingName, choices) {
+ if (token == null || token.type != Scanner.IDENTIFIER) {
+ throw new Error("Missing option at position " + makePosition());
+ }
+ for (var i = 0; i < choices.length; i++) {
+ if (token.value == choices[i]) {
+ enterSetting(valueType, settingName, token.value);
+ next();
+ return;
+ }
+ }
+ throw new Error(
+ "Unsupported option " + token.value +
+ " for setting " + settingName +
+ " on value type " + valueType +
+ " found at position " + makePosition());
+ };
+ var parseFlags = function(valueType, settingName, flags, counterFlags) {
+ outer: while (token != null && token.type == Scanner.IDENTIFIER) {
+ for (var i = 0; i < flags.length; i++) {
+ if (token.value == flags[i]) {
+ enterSetting(valueType, settingName + "/" + token.value, true);
+ next();
+ continue outer;
+ }
+ }
+ if (token.value in counterFlags) {
+ enterSetting(valueType, settingName + "/" + counterFlags[token.value], false);
+ next();
+ continue outer;
+ }
+ throw new Error(
+ "Unsupported flag " + token.value +
+ " for setting " + settingName +
+ " on value type " + valueType +
+ " found at position " + makePosition());
+ }
+ };
+
+ var parseSetting = function(valueType, settingName) {
+ switch (valueType) {
+ case "number":
+ switch (settingName) {
+ case "decimal-digits":
+ parseNonnegativeInteger(valueType, settingName, { "default": -1 });
+ return;
+ }
+ break;
+ case "date":
+ switch (settingName) {
+ case "time-zone":
+ parseNumber(valueType, settingName, { "default" : null });
+ return;
+ case "show":
+ parseChoices(valueType, settingName, [ "date", "time", "date-time" ]);
+ return;
+ case "mode":
+ parseChoices(valueType, settingName, [ "short", "medium", "long", "full" ]);
+ enterSetting(valueType, "template", null); // mode and template are exclusive
+ return;
+ case "template":
+ parseString(valueType, settingName, {});
+ enterSetting(valueType, "mode", null); // mode and template are exclusive
+ return;
+ }
+ break;
+ case "boolean":
+ switch (settingName) {
+ }
+ break;
+ case "text":
+ switch (settingName) {
+ case "max-length":
+ parseInteger(valueType, settingName, { "none" : 0 });
+ return;
+ }
+ break;
+ case "image":
+ switch (settingName) {
+ case "tooltip":
+ parseExpressionOrString(valueType, settingName, { "none" : null });
+ return;
+ case "max-width":
+ case "max-height":
+ parseInteger(valueType, settingName, { "none" : -1 });
+ return;
+ }
+ break;
+ case "url":
+ switch (settingName) {
+ case "target":
+ parseString(valueType, settingName, { "none" : null });
+ return;
+ case "external-icon":
+ parseURL(valueType, settingName, { "none" : null });
+ return;
+ }
+ break;
+ case "item":
+ switch (settingName) {
+ case "title":
+ parseExpression(valueType, settingName, { "default" : null });
+ return;
+ }
+ break;
+ case "currency":
+ switch (settingName) {
+ case "negative-format":
+ parseFlags(valueType, settingName,
+ [ "red", "parentheses", "signed" ],
+ { "unsigned" : "signed", "no-parenthesis" : "parentheses", "black" : "red" }
+ );
+ return;
+ case "symbol":
+ parseString(valueType, settingName, { "default" : "$", "none" : null });
+ return;
+ case "symbol-placement":
+ parseChoices(valueType, settingName, [ "first", "last", "after-sign" ]);
+ return;
+ case "decimal-digits":
+ parseNonnegativeInteger(valueType, settingName, { "default" : -1 });
+ return;
+ }
+ break;
+ case "list":
+ switch (settingName) {
+ case "separator":
+ case "last-separator":
+ case "pair-separator":
+ case "empty-text":
+ parseString(valueType, settingName, {});
+ return;
+ }
+ break;
+ }
+ throw new Error("Unsupported setting called " + settingName +
+ " for value type " + valueType + " found at position " + makePosition());
+ };
+ var parseSettingList = function(valueType) {
+
+ while (token != null && token.type == Scanner.IDENTIFIER) {
+ var settingName = token.value;
+
+ next();
+
+
+ if (token == null || token.type != Scanner.DELIMITER || token.value != ":") {
+ throw new Error("Missing : at position " + makePosition());
+ }
+ next();
+
+ parseSetting(valueType, settingName);
+
+
+ if (token == null || token.type != Scanner.DELIMITER || token.value != ";") {
+ break;
+ } else {
+ next();
+ }
+ }
+
+ }
+ var parseRule = function() {
+ if (token == null || token.type != Scanner.IDENTIFIER) {
+ throw new Error("Missing value type at position " + makePosition());
+ }
+
+ var valueType = token.value;
+ if (!(valueType in Exhibit.FormatParser._valueTypes)) {
+ throw new Error("Unsupported value type " + valueType + " at position " + makePosition());
+ }
+ next();
+
+ if (token != null && token.type == Scanner.DELIMITER && token.value == "{") {
+ next();
+ parseSettingList(valueType);
+
+ if (token == null || token.type != Scanner.DELIMITER || token.value != "}") {
+ throw new Error("Missing } at position " + makePosition());
+ }
+ next();
+ }
+ return valueType;
+ };
+ var parseRuleList = function() {
+ var valueType = "text";
+ while (token != null && token.type == Scanner.IDENTIFIER) {
+ valueType = parseRule();
+ }
+ return valueType;
+ }
+
+ if (several) {
+ return parseRuleList();
+ } else {
+ return parseRule();
+ }
+};
+
+/*==================================================
+ * Exhibit.FormatScanner
+ *==================================================
+ */
+Exhibit.FormatScanner = function(text, startIndex) {
+ this._text = text + " "; // make it easier to parse
+ this._maxIndex = text.length;
+ this._index = startIndex;
+ this.next();
+};
+
+Exhibit.FormatScanner.DELIMITER = 0;
+Exhibit.FormatScanner.NUMBER = 1;
+Exhibit.FormatScanner.STRING = 2;
+Exhibit.FormatScanner.IDENTIFIER = 3;
+Exhibit.FormatScanner.URL = 4;
+Exhibit.FormatScanner.EXPRESSION = 5;
+Exhibit.FormatScanner.COLOR = 6;
+
+Exhibit.FormatScanner.prototype.token = function() {
+ return this._token;
+};
+
+Exhibit.FormatScanner.prototype.index = function() {
+ return this._index;
+};
+
+Exhibit.FormatScanner.prototype.next = function() {
+ this._token = null;
+
+ var self = this;
+ var skipSpaces = function(x) {
+ while (x < self._maxIndex &&
+ " \t\r\n".indexOf(self._text.charAt(x)) >= 0) {
+
+ x++;
+ }
+ return x;
+ };
+ this._index = skipSpaces(this._index);
+
+ if (this._index < this._maxIndex) {
+ var c1 = this._text.charAt(this._index);
+ var c2 = this._text.charAt(this._index + 1);
+
+ if ("{}(),:;".indexOf(c1) >= 0) {
+ this._token = {
+ type: Exhibit.FormatScanner.DELIMITER,
+ value: c1,
+ start: this._index,
+ end: this._index + 1
+ };
+ this._index++;
+ } else if ("\"'".indexOf(c1) >= 0) { // quoted strings
+ var i = this._index + 1;
+ while (i < this._maxIndex) {
+ if (this._text.charAt(i) == c1 && this._text.charAt(i - 1) != "\\") {
+ break;
+ }
+ i++;
+ }
+
+ if (i < this._maxIndex) {
+ this._token = {
+ type: Exhibit.FormatScanner.STRING,
+ value: this._text.substring(this._index + 1, i).replace(/\\'/g, "'").replace(/\\"/g, '"'),
+ start: this._index,
+ end: i + 1
+ };
+ this._index = i + 1;
+ } else {
+ throw new Error("Unterminated string starting at " + this._index);
+ }
+ } else if (c1 == "#") { // color
+ var i = this._index + 1;
+ while (i < this._maxIndex && this._isHexDigit(this._text.charAt(i))) {
+ i++;
+ }
+
+ this._token = {
+ type: Exhibit.FormatScanner.COLOR,
+ value: this._text.substring(this._index, i),
+ start: this._index,
+ end: i
+ };
+ this._index = i;
+ } else if (this._isDigit(c1)) { // number
+ var i = this._index;
+ while (i < this._maxIndex && this._isDigit(this._text.charAt(i))) {
+ i++;
+ }
+
+ if (i < this._maxIndex && this._text.charAt(i) == ".") {
+ i++;
+ while (i < this._maxIndex && this._isDigit(this._text.charAt(i))) {
+ i++;
+ }
+ }
+
+ this._token = {
+ type: Exhibit.FormatScanner.NUMBER,
+ value: parseFloat(this._text.substring(this._index, i)),
+ start: this._index,
+ end: i
+ };
+ this._index = i;
+ } else { // identifier
+ var i = this._index;
+ while (i < this._maxIndex) {
+ var j = this._text.substr(i).search(/\W/);
+ if (j > 0) {
+ i += j;
+ } else if ("-".indexOf(this._text.charAt(i)) >= 0) {
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ var identifier = this._text.substring(this._index, i);
+ while (true) {
+ if (identifier == "url") {
+ var openParen = skipSpaces(i);
+ if (this._text.charAt(openParen) == "(") {
+ var closeParen = this._text.indexOf(")", openParen);
+ if (closeParen > 0) {
+ this._token = {
+ type: Exhibit.FormatScanner.URL,
+ value: this._text.substring(openParen + 1, closeParen),
+ start: this._index,
+ end: closeParen + 1
+ };
+ this._index = closeParen + 1;
+ break;
+ } else {
+ throw new Error("Missing ) to close url at " + this._index);
+ }
+ }
+ } else if (identifier == "expression") {
+ var openParen = skipSpaces(i);
+ if (this._text.charAt(openParen) == "(") {
+ var o = {};
+ var expression = Exhibit.ExpressionParser.parse(this._text, openParen + 1, o);
+
+ var closeParen = skipSpaces(o.index);
+ if (this._text.charAt(closeParen) == ")") {
+ this._token = {
+ type: Exhibit.FormatScanner.EXPRESSION,
+ value: expression,
+ start: this._index,
+ end: closeParen + 1
+ };
+ this._index = closeParen + 1;
+ break;
+ } else {
+ throw new Error("Missing ) to close expression at " + o.index);
+ }
+ }
+ }
+
+ this._token = {
+ type: Exhibit.FormatScanner.IDENTIFIER,
+ value: identifier,
+ start: this._index,
+ end: i
+ };
+ this._index = i;
+ break;
+ }
+ }
+ }
+};
+
+Exhibit.FormatScanner.prototype._isDigit = function(c) {
+ return "0123456789".indexOf(c) >= 0;
+};
+Exhibit.FormatScanner.prototype._isHexDigit = function(c) {
+ return "0123456789abcdefABCDEF".indexOf(c) >= 0;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/formatter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/formatter.js
new file mode 100644
index 00000000..9ae0c154
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/formatter.js
@@ -0,0 +1,565 @@
+/*==================================================
+ * Exhibit.Formatter
+ * http://simile.mit.edu/wiki/Exhibit/API/Formatter
+ *==================================================
+ */
+Exhibit.Formatter = new Object();
+
+Exhibit.Formatter.createListDelimiter = function(parentElmt, count, uiContext) {
+ var separator = uiContext.getSetting("format/list/separator");
+ var lastSeparator = uiContext.getSetting("format/list/last-separator");
+ var pairSeparator = uiContext.getSetting("format/list/pair-separator");
+
+ if (typeof separator != "string") {
+ separator = Exhibit.Formatter.l10n.listSeparator;
+ }
+ if (typeof lastSeparator != "string") {
+ lastSeparator = Exhibit.Formatter.l10n.listLastSeparator;
+ }
+ if (typeof pairSeparator != "string") {
+ pairSeparator = Exhibit.Formatter.l10n.listPairSeparator;
+ }
+
+ var f = function() {
+ if (f.index > 0 && f.index < count) {
+ if (count > 2) {
+ parentElmt.appendChild(document.createTextNode(
+ (f.index == count - 1) ? lastSeparator : separator));
+ } else {
+ parentElmt.appendChild(document.createTextNode(pairSeparator));
+ }
+ }
+ f.index++;
+ };
+ f.index = 0;
+
+ return f;
+};
+
+Exhibit.Formatter._lessThanRegex = /</g;
+Exhibit.Formatter._greaterThanRegex = />/g;
+
+Exhibit.Formatter.encodeAngleBrackets = function(s) {
+ return s.replace(Exhibit.Formatter._lessThanRegex, "&lt;").
+ replace(Exhibit.Formatter._greaterThanRegex, "&gt;");
+};
+
+/*==================================================
+ * Exhibit.Formatter._ListFormatter
+ *==================================================
+ */
+Exhibit.Formatter._ListFormatter = function(uiContext) {
+ this._uiContext = uiContext;
+ this._separator = uiContext.getSetting("format/list/separator");
+ this._lastSeparator = uiContext.getSetting("format/list/last-separator");
+ this._pairSeparator = uiContext.getSetting("format/list/pair-separator");
+ this._emptyText = uiContext.getSetting("format/list/empty-text");
+
+ if (typeof this._separator != "string") {
+ this._separator = Exhibit.Formatter.l10n.listSeparator;
+ }
+ if (typeof this._lastSeparator != "string") {
+ this._lastSeparator = Exhibit.Formatter.l10n.listLastSeparator;
+ }
+ if (typeof this._pairSeparator != "string") {
+ this._pairSeparator = Exhibit.Formatter.l10n.listPairSeparator;
+ }
+};
+
+Exhibit.Formatter._ListFormatter.prototype.formatList = function(values, count, valueType, appender) {
+ var uiContext = this._uiContext;
+ var self = this;
+ if (count == 0) {
+ if (this._emptyText != null && this._emptyText.length > 0) {
+ appender(document.createTextNode(this._emptyText));
+ }
+ } else if (count == 1) {
+ values.visit(function(v) {
+ uiContext.format(v, valueType, appender);
+ });
+ } else {
+ var index = 0;
+ if (count == 2) {
+ values.visit(function(v) {
+ uiContext.format(v, valueType, appender);
+ index++;
+
+ if (index == 1) {
+ appender(document.createTextNode(self._pairSeparator));
+ }
+ });
+ } else {
+ values.visit(function(v) {
+ uiContext.format(v, valueType, appender);
+ index++;
+
+ if (index < count) {
+ appender(document.createTextNode(
+ (index == count - 1) ? self._lastSeparator : self._separator));
+ }
+ });
+ }
+ }
+};
+
+/*==================================================
+ * Exhibit.Formatter._TextFormatter
+ *==================================================
+ */
+Exhibit.Formatter._TextFormatter = function(uiContext) {
+ this._maxLength = uiContext.getSetting("format/text/max-length");
+
+ if (typeof this._maxLength == "number") {
+ this._maxLength = Math.max(3, Math.round(this._maxLength));
+ } else {
+ this._maxLength = 0; // zero means no limit
+ }
+};
+
+Exhibit.Formatter._TextFormatter.prototype.format = function(value, appender) {
+ var span = document.createElement("span");
+
+ span.innerHTML = this.formatText(value);
+ appender(span);
+};
+
+Exhibit.Formatter._TextFormatter.prototype.formatText = function(value) {
+ if (Exhibit.params.safe) {
+ value = Exhibit.Formatter.encodeAngleBrackets(value);
+ }
+
+ if (this._maxLength == 0 || value.length <= this._maxLength) {
+ return value;
+ } else {
+ return value.substr(0, this._maxLength) + Exhibit.Formatter.l10n.textEllipsis;
+ }
+};
+
+/*==================================================
+ * Exhibit.Formatter._BooleanFormatter
+ *==================================================
+ */
+Exhibit.Formatter._BooleanFormatter = function(uiContext) {
+};
+
+Exhibit.Formatter._BooleanFormatter.prototype.format = function(value, appender) {
+ var span = document.createElement("span");
+ span.innerHTML = this.formatText(value);
+ appender(span);
+};
+
+Exhibit.Formatter._BooleanFormatter.prototype.formatText = function(value) {
+ return (typeof value == "boolean" ? value : (typeof value == "string" ? (value == "true") : false)) ?
+ Exhibit.Formatter.l10n.booleanTrue : Exhibit.Formatter.l10n.booleanFalse;
+};
+
+/*==================================================
+ * Exhibit.Formatter._NumberFormatter
+ *==================================================
+ */
+Exhibit.Formatter._NumberFormatter = function(uiContext) {
+ this._decimalDigits = uiContext.getSetting("format/number/decimal-digits");
+
+ if (typeof this._decimalDigits == "number") {
+ this._decimalDigits = Math.max(-1, Math.round(this._decimalDigits));
+ } else {
+ this._decimalDigits = -1; // -1 means no limit
+ }
+};
+
+Exhibit.Formatter._NumberFormatter.prototype.format = function(value, appender) {
+ appender(document.createTextNode(this.formatText(value)));
+};
+
+Exhibit.Formatter._NumberFormatter.prototype.formatText = function(value) {
+ if (this._decimalDigits == -1) {
+ return value.toString();
+ } else {
+ return new Number(value).toFixed(this._decimalDigits);
+ }
+};
+
+/*==================================================
+ * Exhibit.Formatter._ImageFormatter
+ *==================================================
+ */
+Exhibit.Formatter._ImageFormatter = function(uiContext) {
+ this._uiContext = uiContext;
+
+ this._maxWidth = uiContext.getSetting("format/image/max-width");
+ if (typeof this._maxWidth == "number") {
+ this._maxWidth = Math.max(-1, Math.round(this._maxWidth));
+ } else {
+ this._maxWidth = -1; // -1 means no limit
+ }
+
+ this._maxHeight = uiContext.getSetting("format/image/max-height");
+ if (typeof this._maxHeight == "number") {
+ this._maxHeight = Math.max(-1, Math.round(this._maxHeight));
+ } else {
+ this._maxHeight = -1; // -1 means no limit
+ }
+
+ this._tooltip = uiContext.getSetting("format/image/tooltip");
+};
+
+Exhibit.Formatter._ImageFormatter.prototype.format = function(value, appender) {
+ if (Exhibit.params.safe) {
+ value = value.trim().startsWith("javascript:") ? "" : value;
+ }
+
+ var img = document.createElement("img");
+ img.src = value;
+
+ if (this._tooltip != null) {
+ if (typeof this._tooltip == "string") {
+ img.title = this._tootlip;
+ } else {
+ img.title = this._tooltip.evaluateSingleOnItem(
+ this._uiContext.getSetting("itemID"), this._uiContext.getDatabase()).value;
+ }
+ }
+ appender(img);
+};
+
+Exhibit.Formatter._ImageFormatter.prototype.formatText = function(value) {
+ return value;
+};
+
+/*==================================================
+ * Exhibit.Formatter._URLFormatter
+ *==================================================
+ */
+Exhibit.Formatter._URLFormatter = function(uiContext) {
+ this._target = uiContext.getSetting("format/url/target");
+ this._externalIcon = uiContext.getSetting("format/url/external-icon");
+};
+
+Exhibit.Formatter._URLFormatter.prototype.format = function(value, appender) {
+ var a = document.createElement("a");
+ a.href = value;
+ a.innerHTML = value;
+
+ if (this._target != null) {
+ a.target = this._target;
+ }
+ if (this._externalIcon != null) {
+ //
+ }
+ appender(a);
+};
+
+Exhibit.Formatter._URLFormatter.prototype.formatText = function(value) {
+ if (Exhibit.params.safe) {
+ value = value.trim().startsWith("javascript:") ? "" : value;
+ }
+ return value;
+};
+
+/*==================================================
+ * Exhibit.Formatter._CurrencyFormatter
+ *==================================================
+ */
+Exhibit.Formatter._CurrencyFormatter = function(uiContext) {
+ this._decimalDigits = uiContext.getSetting("format/currency/decimal-digits");
+ if (typeof this._decimalDigits == "number") {
+ this._decimalDigits = Math.max(-1, Math.round(this._decimalDigits)); // -1 means no limit
+ } else {
+ this._decimalDigits = 2;
+ }
+
+ this._symbol = uiContext.getSetting("format/currency/symbol");
+ if (this._symbol == null) {
+ this._symbol = Exhibit.Formatter.l10n.currencySymbol;
+ }
+
+ this._symbolPlacement = uiContext.getSetting("format/currency/symbol-placement");
+ if (this._symbolPlacement == null) {
+ this._symbol = Exhibit.Formatter.l10n.currencySymbolPlacement;
+ }
+
+ this._negativeFormat = {
+ signed : uiContext.getBooleanSetting("format/currency/negative-format/signed", Exhibit.Formatter.l10n.currencyShowSign),
+ red : uiContext.getBooleanSetting("format/currency/negative-format/red", Exhibit.Formatter.l10n.currencyShowRed),
+ parentheses : uiContext.getBooleanSetting("format/currency/negative-format/parentheses", Exhibit.Formatter.l10n.currencyShowParentheses)
+ };
+};
+
+Exhibit.Formatter._CurrencyFormatter.prototype.format = function(value, appender) {
+ var text = this.formatText(value);
+ if (value < 0 && this._negativeFormat.red) {
+ var span = document.createElement("span");
+ span.innerHTML = text;
+ span.style.color = "red";
+ appender(span);
+ } else {
+ appender(document.createTextNode(text));
+ }
+};
+
+Exhibit.Formatter._CurrencyFormatter.prototype.formatText = function(value) {
+ var negative = value < 0;
+ var text;
+ if (this._decimalDigits == -1) {
+ text = Math.abs(value);
+ } else {
+ text = new Number(Math.abs(value)).toFixed(this._decimalDigits);
+ }
+
+ var sign = (negative && this._negativeFormat.signed) ? "-" : "";
+ if (negative && this._negativeFormat.parentheses) {
+ text = "(" + text + ")";
+ }
+
+ switch (this._negativeFormat) {
+ case "first": text = this._symbol + sign + text; break;
+ case "after-sign": text = sign + this._symbol + text; break;
+ case "last": text = sign + text + this._symbol; break;
+ }
+ return text;
+};
+
+/*==================================================
+ * Exhibit.Formatter._ItemFormatter
+ *==================================================
+ */
+Exhibit.Formatter._ItemFormatter = function(uiContext) {
+ this._uiContext = uiContext;
+ this._title = uiContext.getSetting("format/item/title");
+};
+
+Exhibit.Formatter._ItemFormatter.prototype.format = function(value, appender) {
+ var self = this;
+ var title = this.formatText(value);
+
+ var a = SimileAjax.DOM.createElementFromString(
+ "<a href=\"" + Exhibit.Persistence.getItemLink(value) + "\" class='exhibit-item'>" + title + "</a>");
+
+ var handler = function(elmt, evt, target) {
+ Exhibit.UI.showItemInPopup(value, elmt, self._uiContext);
+ }
+ SimileAjax.WindowManager.registerEvent(a, "click", handler, this._uiContext.getSetting("layer"));
+
+ appender(a);
+};
+
+Exhibit.Formatter._ItemFormatter.prototype.formatText = function(value) {
+ var database = this._uiContext.getDatabase();
+ var title = null;
+
+ if (this._title == null) {
+ title = database.getObject(value, "label");
+ } else {
+ title = this._title.evaluateSingleOnItem(value, database).value;
+ }
+
+ if (title == null) {
+ title = value;
+ }
+
+ return title;
+};
+
+/*==================================================
+ * Exhibit.Formatter._DateFormatter
+ *==================================================
+ */
+Exhibit.Formatter._DateFormatter = function(uiContext) {
+ this._timeZone = uiContext.getSetting("format/date/time-zone");
+ if (!(typeof this._timeZone == "number")) {
+ this._timeZone = -(new Date().getTimezoneOffset()) / 60;
+ }
+ this._timeZoneOffset = this._timeZone * 3600000;
+
+ var mode = uiContext.getSetting("format/date/mode");
+ var show = uiContext.getSetting("format/date/show");
+ var template = null;
+
+ switch (mode) {
+ case "short":
+ template =
+ show == "date" ? Exhibit.Formatter.l10n.dateShortFormat :
+ (show == "time" ? Exhibit.Formatter.l10n.timeShortFormat :
+ Exhibit.Formatter.l10n.dateTimeShortFormat);
+ break;
+ case "medium":
+ template =
+ show == "date" ? Exhibit.Formatter.l10n.dateMediumFormat :
+ (show == "time" ? Exhibit.Formatter.l10n.timeMediumFormat :
+ Exhibit.Formatter.l10n.dateTimeMediumFormat);
+ break;
+ case "long":
+ template =
+ show == "date" ? Exhibit.Formatter.l10n.dateLongFormat :
+ (show == "time" ? Exhibit.Formatter.l10n.timeLongFormat :
+ Exhibit.Formatter.l10n.dateTimeLongFormat);
+ break;
+ case "full":
+ template =
+ show == "date" ? Exhibit.Formatter.l10n.dateFullFormat :
+ (show == "time" ? Exhibit.Formatter.l10n.timeFullFormat :
+ Exhibit.Formatter.l10n.dateTimeFullFormat);
+ break;
+ default:
+ template = uiContext.getSetting("format/date/template");
+ }
+
+ if (typeof template != "string") {
+ template = Exhibit.Formatter.l10n.dateTimeDefaultFormat;
+ }
+
+ var segments = [];
+
+ var placeholders = template.match(/\b\w+\b/g);
+ var startIndex = 0;
+ for (var p = 0; p < placeholders.length; p++) {
+ var placeholder = placeholders[p];
+ var index = template.indexOf(placeholder, startIndex);
+ if (index > startIndex) {
+ segments.push(template.substring(startIndex, index));
+ }
+
+ var retriever = Exhibit.Formatter._DateFormatter._retrievers[placeholder];
+ if (typeof retriever == "function") {
+ segments.push(retriever);
+ } else {
+ segments.push(placeholder);
+ }
+
+ startIndex = index + placeholder.length;
+ }
+
+ if (startIndex < template.length) {
+ segments.push(template.substr(startIndex));
+ }
+
+ this._segments = segments;
+};
+
+Exhibit.Formatter._DateFormatter.prototype.format = function(value, appender) {
+ appender(document.createTextNode(this.formatText(value)));
+};
+
+Exhibit.Formatter._DateFormatter.prototype.formatText = function(value) {
+ var date = (value instanceof Date) ? value : SimileAjax.DateTime.parseIso8601DateTime(value);
+ if (date == null) {
+ return value;
+ }
+
+ date.setTime(date.getTime() + this._timeZoneOffset);
+
+ var text = "";
+ var segments = this._segments;
+ for (var i = 0; i < segments.length; i++) {
+ var segment = segments[i];
+ if (typeof segment == "string") {
+ text += segment;
+ } else {
+ text += segment(date);
+ }
+ }
+ return text;
+};
+
+Exhibit.Formatter._DateFormatter._pad = function(n) {
+ return n < 10 ? ("0" + n) : n.toString();
+};
+Exhibit.Formatter._DateFormatter._pad3 = function(n) {
+ return n < 10 ? ("00" + n) : (n < 100 ? ("0" + n) : n.toString());
+};
+
+Exhibit.Formatter._DateFormatter._retrievers = {
+ // day of month
+ "d": function(date) {
+ return date.getUTCDate().toString();
+ },
+ "dd": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCDate());
+ },
+
+ // day of week
+ "EEE": function(date) {
+ return Exhibit.Formatter.l10n.shortDaysOfWeek[date.getUTCDay()];
+ },
+ "EEEE": function(date) {
+ return Exhibit.Formatter.l10n.daysOfWeek[date.getUTCDay()];
+ },
+
+ // month
+ "MM": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCMonth() + 1);
+ },
+ "MMM": function(date) {
+ return Exhibit.Formatter.l10n.shortMonths[date.getUTCMonth()];
+ },
+ "MMMM": function(date) {
+ return Exhibit.Formatter.l10n.months[date.getUTCMonth()];
+ },
+
+ // year
+ "yy": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCFullYear() % 100);
+ },
+ "yyyy": function(date) {
+ var y = date.getUTCFullYear();
+ return y > 0 ? y.toString() : (1 - y);
+ },
+
+ // era
+ "G": function(date) {
+ var y = date.getUTCYear();
+ return y > 0 ? Exhibit.Formatter.l10n.commonEra : Exhibit.Formatter.l10n.beforeCommonEra;
+ },
+
+ // hours of day
+ "HH": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCHours());
+ },
+ "hh": function(date) {
+ var h = date.getUTCHours();
+ return Exhibit.Formatter._DateFormatter._pad(h == 0 ? 12 : (h > 12 ? h - 12 : h));
+ },
+ "h": function(date) {
+ var h = date.getUTCHours();
+ return (h == 0 ? 12 : (h > 12 ? h - 12 : h)).toString();
+ },
+
+ // am/pm
+ "a": function(date) {
+ return date.getUTCHours() < 12 ? Exhibit.Formatter.l10n.beforeNoon : Exhibit.Formatter.l10n.afterNoon;
+ },
+ "A": function(date) {
+ return date.getUTCHours() < 12 ? Exhibit.Formatter.l10n.BeforeNoon : Exhibit.Formatter.l10n.AfterNoon;
+ },
+
+ // minutes of hour
+ "mm": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCMinutes());
+ },
+
+ // seconds of minute
+ "ss": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad(date.getUTCSeconds());
+ },
+
+ // milliseconds of minute
+ "S": function(date) {
+ return Exhibit.Formatter._DateFormatter._pad3(date.getUTCMilliseconds());
+ }
+
+};
+
+/*==================================================
+ * Exhibit.Formatter constructor map
+ *==================================================
+ */
+Exhibit.Formatter._constructors = {
+ "number" : Exhibit.Formatter._NumberFormatter,
+ "date" : Exhibit.Formatter._DateFormatter,
+ "text" : Exhibit.Formatter._TextFormatter,
+ "boolean" : Exhibit.Formatter._BooleanFormatter,
+ "image" : Exhibit.Formatter._ImageFormatter,
+ "url" : Exhibit.Formatter._URLFormatter,
+ "item" : Exhibit.Formatter._ItemFormatter,
+ "currency" : Exhibit.Formatter._CurrencyFormatter
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/lens.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/lens.js
new file mode 100644
index 00000000..bb3102ff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/lens.js
@@ -0,0 +1,1000 @@
+/*==================================================
+ * Exhibit.LensRegistry
+ *==================================================
+ */
+
+Exhibit.LensRegistry = function(parentRegistry) {
+ this._parentRegistry = parentRegistry;
+ this._defaultLens = null;
+ this._typeToLens = {};
+ this._editLensTemplates = {};
+ this._submissionLensTemplates = {};
+ this._lensSelectors = [];
+};
+
+Exhibit.LensRegistry.prototype.registerDefaultLens = function(elmtOrURL) {
+ this._defaultLens = (typeof elmtOrURL == "string") ? elmtOrURL : elmtOrURL.cloneNode(true);
+};
+
+Exhibit.LensRegistry.prototype.registerLensForType = function(elmtOrURL, type) {
+ if (typeof elmtOrURL == 'string') {
+ this._typeToLens[type] = elmtOrURL;
+ }
+
+ var role = Exhibit.getRoleAttribute(elmtOrURL);
+ if (role == 'lens') {
+ this._typeToLens[type] = elmtOrURL.cloneNode(true);
+ } else if (role == 'edit-lens') {
+ this._editLensTemplates[type] = elmtOrURL.cloneNode(true);
+ } else if (role == 'submission-lens') {
+ this._submissionLensTemplates[type] = elmtOrURL.cloneNode(true);
+ } else {
+ SimileAjax.Debug.warn('Unknown lens type ' + elmtOrURL);
+ }
+};
+
+Exhibit.LensRegistry.prototype.addLensSelector = function(lensSelector) {
+ this._lensSelectors.unshift(lensSelector);
+};
+
+Exhibit.LensRegistry.prototype.getLens = function(itemID, uiContext) {
+ return uiContext.isBeingEdited(itemID)
+ ? this.getEditLens(itemID, uiContext)
+ : this.getNormalLens(itemID, uiContext);
+};
+
+Exhibit.LensRegistry.prototype.getNormalLens = function(itemID, uiContext) {
+ var db = uiContext.getDatabase();
+
+ for (var i = 0; i < this._lensSelectors.length; i++) {
+ var lens = this._lensSelectors[i](itemID, db);
+ if (lens != null) {
+ return lens;
+ }
+ }
+
+ var type = db.getObject(itemID, "type");
+ if (type in this._typeToLens) {
+ return this._typeToLens[type];
+ }
+ if (this._defaultLens != null) {
+ return this._defaultLens;
+ }
+ if (this._parentRegistry) {
+ return this._parentRegistry.getLens(itemID, uiContext);
+ }
+ return null;
+}
+
+Exhibit.LensRegistry.prototype.getEditLens = function(itemID, uiContext) {
+ var type = uiContext.getDatabase().getObject(itemID, "type");
+
+ if (type in this._editLensTemplates) {
+ return this._editLensTemplates[type];
+ } else {
+ return this._parentRegistry && this._parentRegistry.getEditLens(itemID, uiContext);
+ }
+}
+
+Exhibit.LensRegistry.prototype.createLens = function(itemID, div, uiContext, opts) {
+ var lens = new Exhibit.Lens();
+
+ if (uiContext.getDatabase().isNewItem(itemID)) {
+ SimileAjax.jQuery(div).addClass('newItem');
+ }
+
+ opts = opts || {};
+ var lensTemplate = opts.lensTemplate || this.getLens(itemID, uiContext);
+
+ if (lensTemplate == null) {
+ lens._constructDefaultUI(itemID, div, uiContext);
+ } else if (typeof lensTemplate == "string") {
+ lens._constructFromLensTemplateURL(itemID, div, uiContext, lensTemplate, opts);
+ } else {
+ lens._constructFromLensTemplateDOM(itemID, div, uiContext, lensTemplate, opts);
+ }
+ return lens;
+};
+
+Exhibit.LensRegistry.prototype.createEditLens = function(itemID, div, uiContext, opts) {
+ opts = opts || {};
+ opts.lensTemplate = this.getEditLens(itemID, uiContext);
+ return this.createLens(itemID, div, uiContext, opts);
+}
+
+Exhibit.LensRegistry.prototype.createNormalLens = function(itemID, div, uiContext, opts) {
+ opts = opts || {};
+ opts.lensTemplate = this.getNormalLens(itemID, uiContext);
+ return this.createLens(itemID, div, uiContext, opts);
+}
+
+
+/*==================================================
+ * Exhibit.Lens
+ * http://simile.mit.edu/wiki/Exhibit/API/Lens
+ *==================================================
+ */
+Exhibit.Lens = function() {
+};
+
+Exhibit.Lens._commonProperties = null;
+Exhibit.Lens.prototype._constructDefaultUI = function(itemID, div, uiContext) {
+ var database = uiContext.getDatabase();
+
+ if (Exhibit.Lens._commonProperties == null) {
+ Exhibit.Lens._commonProperties = database.getAllProperties();
+ }
+ var properties = Exhibit.Lens._commonProperties;
+
+ var label = database.getObject(itemID, "label");
+ label = label != null ? label : itemID;
+
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+
+ var template = {
+ elmt: div,
+ className: "exhibit-lens",
+ children: [
+ { tag: "div",
+ className: "exhibit-lens-title",
+ title: label,
+ children: [
+ label + " (",
+ { tag: "a",
+ href: Exhibit.Persistence.getItemLink(itemID),
+ target: "_blank",
+ children: [ Exhibit.l10n.itemLinkLabel ]
+ },
+ ")"
+ ]
+ },
+ { tag: "div",
+ className: "exhibit-lens-body",
+ children: [
+ { tag: "table",
+ className: "exhibit-lens-properties",
+ field: "propertiesTable"
+ }
+ ]
+ }
+ ]
+ };
+ var dom = SimileAjax.DOM.createDOMFromTemplate(template);
+
+ div.setAttribute("ex:itemID", itemID);
+ //Exhibit.ToolboxWidget.createFromDOM(div, div, uiContext);
+
+ var pairs = Exhibit.ViewPanel.getPropertyValuesPairs(
+ itemID, properties, database);
+
+ for (var j = 0; j < pairs.length; j++) {
+ var pair = pairs[j];
+
+ var tr = dom.propertiesTable.insertRow(j);
+ tr.className = "exhibit-lens-property";
+
+ var tdName = tr.insertCell(0);
+ tdName.className = "exhibit-lens-property-name";
+ tdName.innerHTML = pair.propertyLabel + ": ";
+
+ var tdValues = tr.insertCell(1);
+ tdValues.className = "exhibit-lens-property-values";
+
+ if (pair.valueType == "item") {
+ for (var m = 0; m < pair.values.length; m++) {
+ if (m > 0) {
+ tdValues.appendChild(document.createTextNode(", "));
+ }
+ tdValues.appendChild(Exhibit.UI.makeItemSpan(pair.values[m], null, uiContext));
+ }
+ } else {
+ for (var m = 0; m < pair.values.length; m++) {
+ if (m > 0) {
+ tdValues.appendChild(document.createTextNode(", "));
+ }
+ tdValues.appendChild(Exhibit.UI.makeValueSpan(pair.values[m], pair.valueType));
+ }
+ }
+ }
+};
+
+Exhibit.Lens.prototype._constructDefaultEditingUI = function(itemID, div, uiContext) {
+ // TODO
+}
+
+Exhibit.Lens._compiledTemplates = {};
+Exhibit.Lens._handlers = [
+ "onblur", "onfocus",
+ "onkeydown", "onkeypress", "onkeyup",
+ "onmousedown", "onmouseenter", "onmouseleave", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onclick",
+ "onresize", "onscroll"
+];
+
+Exhibit.Lens.prototype._constructFromLensTemplateURL =
+ function(itemID, div, uiContext, lensTemplateURL) {
+
+ var job = {
+ lens: this,
+ itemID: itemID,
+ div: div,
+ uiContext: uiContext,
+ opts: opts
+ };
+
+ var compiledTemplate = Exhibit.Lens._compiledTemplates[lensTemplateURL];
+ if (compiledTemplate == null) {
+ Exhibit.Lens._startCompilingTemplate(lensTemplateURL, job);
+ } else if (!compiledTemplate.compiled) {
+ compiledTemplate.jobs.push(job);
+ } else {
+ job.template = compiledTemplate;
+ Exhibit.Lens._performConstructFromLensTemplateJob(job);
+ }
+};
+
+Exhibit.Lens.prototype._constructFromLensTemplateDOM =
+ function(itemID, div, uiContext, lensTemplateNode, opts) {
+
+ var job = {
+ lens: this,
+ itemID: itemID,
+ div: div,
+ uiContext: uiContext,
+ opts: opts
+ };
+
+ var id = lensTemplateNode.id;
+ if (id == null || id.length == 0) {
+ id = "exhibitLensTemplate" + Math.floor(Math.random() * 10000);
+ lensTemplateNode.id = id;
+ }
+
+ var compiledTemplate = Exhibit.Lens._compiledTemplates[id];
+ if (compiledTemplate == null) {
+ compiledTemplate = {
+ url: id,
+ template: Exhibit.Lens.compileTemplate(lensTemplateNode, false, uiContext),
+ compiled: true,
+ jobs: []
+ };
+ Exhibit.Lens._compiledTemplates[id] = compiledTemplate;
+ }
+ job.template = compiledTemplate;
+ Exhibit.Lens._performConstructFromLensTemplateJob(job);
+};
+
+Exhibit.Lens._startCompilingTemplate = function(lensTemplateURL, job) {
+ var compiledTemplate = {
+ url: lensTemplateURL,
+ template: null,
+ compiled: false,
+ jobs: [ job ]
+ };
+ Exhibit.Lens._compiledTemplates[lensTemplateURL] = compiledTemplate;
+
+ var fError = function(statusText, status, xmlhttp) {
+ SimileAjax.Debug.log("Failed to load view template from " + lensTemplateURL + "\n" + statusText);
+ };
+ var fDone = function(xmlhttp) {
+ try {
+ compiledTemplate.template = Exhibit.Lens.compileTemplate(
+ xmlhttp.responseXML.documentElement, true, job.uiContext);
+
+ compiledTemplate.compiled = true;
+
+ for (var i = 0; i < compiledTemplate.jobs.length; i++) {
+ try {
+ var job2 = compiledTemplate.jobs[i];
+ job2.template = compiledTemplate;
+ Exhibit.Lens._performConstructFromLensTemplateJob(job2);
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Lens: Error constructing lens template in job queue");
+ }
+ }
+ compiledTemplate.jobs = null;
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Lens: Error compiling lens template and processing template job queue");
+ }
+ };
+
+ SimileAjax.XmlHttp.get(lensTemplateURL, fError, fDone);
+
+ return compiledTemplate;
+};
+
+Exhibit.Lens.compileTemplate = function(rootNode, isXML, uiContext) {
+ return Exhibit.Lens._processTemplateNode(rootNode, isXML, uiContext);
+};
+
+Exhibit.Lens._processTemplateNode = function(node, isXML, uiContext) {
+ if (node.nodeType == 1) {
+ return Exhibit.Lens._processTemplateElement(node, isXML, uiContext);
+ } else {
+ return node.nodeValue;
+ }
+};
+
+Exhibit.Lens._processTemplateElement = function(elmt, isXML, uiContext) {
+ var templateNode = {
+ tag: elmt.tagName.toLowerCase(),
+ uiContext: uiContext,
+ control: null,
+ condition: null,
+ content: null,
+ contentAttributes: null,
+ subcontentAttributes: null,
+ attributes: [],
+ styles: [],
+ handlers: [],
+ children: null
+ };
+
+ var settings = {
+ parseChildTextNodes: true
+ };
+
+ var attributes = elmt.attributes;
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ var name = attribute.nodeName;
+ var value = attribute.nodeValue;
+ Exhibit.Lens._processTemplateAttribute(uiContext, templateNode, settings, name, value);
+ }
+
+ if (!isXML && SimileAjax.Platform.browser.isIE) {
+ /*
+ * IE swallows style and event handler attributes of HTML elements.
+ * So our loop above will not catch them.
+ */
+
+ /* Need to handle this for IE
+ var style = elmt.getAttribute("style");
+ if (style != null && style.length > 0) {
+ Exhibit.Lens._processStyle(templateNode, value);
+ }
+ */
+
+ var handlers = Exhibit.Lens._handlers;
+ for (var h = 0; h < handlers.length; h++) {
+ var handler = handlers[h];
+ var code = elmt[handler];
+ if (code != null) {
+ templateNode.handlers.push({ name: handler, code: code });
+ }
+ }
+ }
+
+ var childNode = elmt.firstChild;
+ if (childNode != null) {
+ templateNode.children = [];
+ while (childNode != null) {
+ if ((settings.parseChildTextNodes && childNode.nodeType == 3) || childNode.nodeType == 1) {
+ templateNode.children.push(Exhibit.Lens._processTemplateNode(childNode, isXML, templateNode.uiContext));
+ }
+ childNode = childNode.nextSibling;
+ }
+ }
+ return templateNode;
+};
+
+Exhibit.Lens._processTemplateAttribute = function(uiContext, templateNode, settings, name, value) {
+ if (value == null || typeof value != "string" || value.length == 0 || name == "contentEditable") {
+ return;
+ }
+ if (name.length > 3 && name.substr(0,3) == "ex:") {
+ name = name.substr(3);
+ if (name == "formats") {
+ templateNode.uiContext = Exhibit.UIContext._createWithParent(uiContext);
+
+ Exhibit.FormatParser.parseSeveral(templateNode.uiContext, value, 0, {});
+ } else if (name == "onshow") {
+ templateNode.attributes.push({
+ name: name,
+ value: value
+ });
+ } else if (name == "control") {
+ templateNode.control = value;
+ } else if (name == "content") {
+ templateNode.content = Exhibit.ExpressionParser.parse(value);
+ templateNode.attributes.push({
+ name: "ex:content",
+ value: value
+ });
+ } else if (name == "editor") {
+ templateNode.attributes.push({
+ name: "ex:editor",
+ value: value
+ });
+ } else if (name == "edit") {
+ templateNode.edit = value;
+ } else if (name == 'options') {
+ templateNode.options = value;
+ } else if (name == "editvalues") {
+ templateNode.editValues = value;
+ } else if (name == "tag") {
+ /*
+ This is a hack for 2 cases:
+ 1. See http://simile.mit.edu/mail/ReadMsg?listName=General&msgId=22328
+ 2. IE7 throws a "Not enough storage is available to complete this operation"
+ exception if we try to access elmt.attributes on <embed> elements
+ */
+ templateNode.tag = value;
+ } else if (name == "if-exists") {
+ templateNode.condition = {
+ test: "if-exists",
+ expression: Exhibit.ExpressionParser.parse(value)
+ };
+ } else if (name == "if") {
+ templateNode.condition = {
+ test: "if",
+ expression: Exhibit.ExpressionParser.parse(value)
+ };
+ settings.parseChildTextNodes = false;
+ } else if (name == "select") {
+ templateNode.condition = {
+ test: "select",
+ expression: Exhibit.ExpressionParser.parse(value)
+ };
+ } else if (name == "case") {
+ templateNode.condition = {
+ test: "case",
+ value: value
+ };
+ settings.parseChildTextNodes = false;
+ } else {
+ var isStyle = false;
+ var x = name.indexOf("-style-content");
+ if (x > 0) {
+ isStyle = true;
+ } else {
+ x = name.indexOf("-content");
+ }
+
+ if (x > 0) {
+ if (templateNode.contentAttributes == null) {
+ templateNode.contentAttributes = [];
+ }
+ templateNode.contentAttributes.push({
+ name: name.substr(0, x),
+ expression: Exhibit.ExpressionParser.parse(value),
+ isStyle: isStyle
+ });
+ } else {
+ x = name.indexOf("-style-subcontent");
+ if (x > 0) {
+ isStyle = true;
+ } else {
+ x = name.indexOf("-subcontent");
+ }
+
+ if (x > 0) {
+ if (templateNode.subcontentAttributes == null) {
+ templateNode.subcontentAttributes = [];
+ }
+ templateNode.subcontentAttributes.push({
+ name: name.substr(0, x),
+ fragments: Exhibit.Lens._parseSubcontentAttribute(value),
+ isStyle: isStyle
+ });
+ }
+ }
+ }
+ } else {
+ if (name == "style") {
+ Exhibit.Lens._processStyle(templateNode, value);
+ } else if (name != "id") {
+ if (name == "class") {
+ if (SimileAjax.Platform.browser.isIE) {
+ name = "className";
+ }
+ } else if (name == "cellspacing") {
+ name = "cellSpacing";
+ } else if (name == "cellpadding") {
+ name = "cellPadding";
+ } else if (name == "bgcolor") {
+ name = "bgColor";
+ }
+
+ templateNode.attributes.push({
+ name: name,
+ value: value
+ });
+ }
+ }
+};
+
+Exhibit.Lens._processStyle = function(templateNode, styleValue) {
+ var styles = styleValue.split(";");
+ for (var s = 0; s < styles.length; s++) {
+ var pair = styles[s].split(":");
+ if (pair.length > 1) {
+ var n = pair[0].trim();
+ var v = pair[1].trim();
+ if (n == "float") {
+ n = SimileAjax.Platform.browser.isIE ? "styleFloat" : "cssFloat";
+ } else if (n == "-moz-opacity") {
+ n = "MozOpacity";
+ } else {
+ if (n.indexOf("-") > 0) {
+ var segments = n.split("-");
+ n = segments[0];
+ for (var x = 1; x < segments.length; x++) {
+ n += segments[x].substr(0, 1).toUpperCase() + segments[x].substr(1);
+ }
+ }
+ }
+ templateNode.styles.push({ name: n, value: v });
+ }
+ }
+};
+
+Exhibit.Lens._parseSubcontentAttribute = function(value) {
+ var fragments = [];
+ var current = 0;
+ var open;
+ while (current < value.length && (open = value.indexOf("{{", current)) >= 0) {
+ var close = value.indexOf("}}", open);
+ if (close < 0) {
+ break;
+ }
+
+ fragments.push(value.substring(current, open));
+ fragments.push(Exhibit.ExpressionParser.parse(value.substring(open + 2, close)));
+
+ current = close + 2;
+ }
+ if (current < value.length) {
+ fragments.push(value.substr(current));
+ }
+
+ return fragments;
+};
+
+Exhibit.Lens.constructFromLensTemplate = function(itemID, templateNode, parentElmt, uiContext, opts) {
+ return Exhibit.Lens._performConstructFromLensTemplateJob({
+ itemID: itemID,
+ template: { template: templateNode },
+ div: parentElmt,
+ uiContext: uiContext,
+ opts: opts
+ });
+};
+
+Exhibit.Lens._performConstructFromLensTemplateJob = function(job) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ { "value" : job.itemID
+ },
+ { "value" : "item"
+ },
+ job.template.template,
+ job.div,
+ job.opts
+ );
+
+ var node = job.div.tagName.toLowerCase() == "table" ? job.div.rows[job.div.rows.length - 1] : job.div.lastChild;
+ var tagName = node.tagName.toLowerCase();
+ switch (tagName) {
+ case "span":
+ node.style.display = "inline";
+ break;
+ case "tr":
+ node.style.display = "table-row";
+ break;
+ case "td":
+ node.style.display = "table-cell";
+ break;
+ default:
+ node.style.display = "block";
+ }
+
+ node.setAttribute("ex:itemID", job.itemID);
+
+ if (!Exhibit.params.safe) {
+ var onshow = Exhibit.getAttribute(node, "onshow");
+ if (onshow != null && onshow.length > 0) {
+ try {
+ (new Function(onshow)).call(node);
+ } catch (e) {
+ SimileAjax.Debug.log(e);
+ }
+ }
+ }
+
+ //Exhibit.ToolboxWidget.createFromDOM(job.div, job.div, job.uiContext);
+ return node;
+};
+
+Exhibit.Lens._constructFromLensTemplateNode = function(
+ roots, rootValueTypes, templateNode, parentElmt, opts
+) {
+ if (typeof templateNode == "string") {
+ parentElmt.appendChild(document.createTextNode(templateNode));
+ return;
+ }
+ var uiContext = templateNode.uiContext;
+ var database = uiContext.getDatabase();
+ var children = templateNode.children;
+
+ function processChildren() {
+ if (children != null) {
+ for (var i = 0; i < children.length; i++) {
+ Exhibit.Lens._constructFromLensTemplateNode(roots, rootValueTypes, children[i], elmt, opts);
+ }
+ }
+ }
+
+ if (templateNode.condition != null) {
+ if (templateNode.condition.test == "if-exists") {
+ if (!templateNode.condition.expression.testExists(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ )) {
+ return;
+ }
+ } else if (templateNode.condition.test == "if") {
+ if (templateNode.condition.expression.evaluate(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ ).values.contains(true)) {
+
+ if (children != null && children.length > 0) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ roots, rootValueTypes, children[0], parentElmt, opts);
+ }
+ } else {
+ if (children != null && children.length > 1) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ roots, rootValueTypes, children[1], parentElmt, opts);
+ }
+ }
+ return;
+ } else if (templateNode.condition.test == "select") {
+ var values = templateNode.condition.expression.evaluate(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ ).values;
+
+ if (children != null) {
+ var lastChildTemplateNode = null;
+ for (var c = 0; c < children.length; c++) {
+ var childTemplateNode = children[c];
+ if (childTemplateNode.condition != null &&
+ childTemplateNode.condition.test == "case") {
+
+ if (values.contains(childTemplateNode.condition.value)) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ roots, rootValueTypes, childTemplateNode, parentElmt, opts);
+
+ return;
+ }
+ } else if (typeof childTemplateNode != "string") {
+ lastChildTemplateNode = childTemplateNode;
+ }
+ }
+ }
+
+ if (lastChildTemplateNode != null) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ roots, rootValueTypes, lastChildTemplateNode, parentElmt, opts);
+ }
+ return;
+ }
+ }
+
+ var elmt = Exhibit.Lens._constructElmtWithAttributes(templateNode, parentElmt, database);
+ if (templateNode.contentAttributes != null) {
+ var contentAttributes = templateNode.contentAttributes;
+ for (var i = 0; i < contentAttributes.length; i++) {
+ var attribute = contentAttributes[i];
+ var values = [];
+
+ attribute.expression.evaluate(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ ).values.visit(function(v) { values.push(v); });
+
+ var value = values.join(";");
+ if (attribute.isStyle) {
+ elmt.style[attribute.name] = value;
+ } else if ("class" == attribute.name) {
+ elmt.className = value;
+ } else if (Exhibit.Lens._attributeValueIsSafe(attribute.name, value)) {
+ elmt.setAttribute(attribute.name, value);
+ }
+ }
+ }
+ if (templateNode.subcontentAttributes != null) {
+ var subcontentAttributes = templateNode.subcontentAttributes;
+ for (var i = 0; i < subcontentAttributes.length; i++) {
+ var attribute = subcontentAttributes[i];
+ var fragments = attribute.fragments;
+ var results = "";
+ for (var r = 0; r < fragments.length; r++) {
+ var fragment = fragments[r];
+ if (typeof fragment == "string") {
+ results += fragment;
+ } else {
+ results += fragment.evaluateSingle(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ ).value;
+ }
+ }
+
+ if (attribute.isStyle) {
+ elmt.style[attribute.name] = results;
+ } else if ("class" == attribute.name) {
+ elmt.className = results;
+ } else if (Exhibit.Lens._attributeValueIsSafe(attribute.name, results)) {
+ elmt.setAttribute(attribute.name, results);
+ }
+ }
+ }
+
+ if (!Exhibit.params.safe) {
+ var handlers = templateNode.handlers;
+ for (var h = 0; h < handlers.length; h++) {
+ var handler = handlers[h];
+ elmt[handler.name] = handler.code;
+ }
+ }
+ var itemID = roots["value"];
+ if (templateNode.control != null) {
+ switch (templateNode.control) {
+
+ case "item-link":
+ var a = document.createElement("a");
+ a.innerHTML = Exhibit.l10n.itemLinkLabel;
+ a.href = Exhibit.Persistence.getItemLink(itemID);
+ a.target = "_blank";
+ elmt.appendChild(a);
+ break;
+
+ case "remove-item":
+ // only new items can be deleted from an exhibit
+ if (!opts.disableEditWidgets && database.isNewItem(itemID)) {
+ if (templateNode.tag == 'a') { elmt.href = 'javascript:'; }
+ SimileAjax.jQuery(elmt).click(function() { database.removeItem(itemID) });
+ processChildren();
+ } else {
+ parentElmt.removeChild(elmt);
+ }
+ break;
+
+ case "start-editing":
+ if (templateNode.tag == 'a') { elmt.href = 'javascript:'; }
+
+ if (opts.disableEditWidgets) {
+ parentElmt.removeChild(elmt);
+ } else if (opts.inPopup) {
+ SimileAjax.jQuery(elmt).click(function() {
+ Exhibit.UI.showItemInPopup(itemID, null, uiContext, {
+ lensType: 'edit',
+ coords: opts.coords
+ });
+ });
+ processChildren();
+ } else {
+ SimileAjax.jQuery(elmt).click(function() {
+ uiContext.setEditMode(itemID, true);
+ uiContext.getCollection()._listeners.fire("onItemsChanged", []);
+ });
+ processChildren();
+ }
+ break;
+
+ case "stop-editing":
+ if (templateNode.tag == 'a') { elmt.href = 'javascript:'; }
+
+ if (opts.disableEditWidgets) {
+ parentElmt.removeChild(elmt);
+ } else if (opts.inPopup) {
+ SimileAjax.jQuery(elmt).click(function() {
+ Exhibit.UI.showItemInPopup(itemID, null, uiContext, {
+ lensType: 'normal',
+ coords: opts.coords
+ });
+ });
+ processChildren();
+ } else {
+ SimileAjax.jQuery(elmt).click(function() {
+ uiContext.setEditMode(itemID, false);
+ uiContext.getCollection()._listeners.fire("onItemsChanged", []);
+ });
+ processChildren();
+ }
+ break;
+
+ case "accept-changes":
+ if (database.isSubmission(itemID)) {
+ if (templateNode.tag == 'a')
+ elmt.href = 'javascript:';
+ SimileAjax.jQuery(elmt).click(function() {
+ database.mergeSubmissionIntoItem(itemID);
+ });
+ processChildren();
+ } else {
+ SimileAjax.Debug.warn('accept-changes element in non-submission item');
+ parentElmt.removeChild(elmt);
+ }
+ break;
+ }
+ } else if (templateNode.content != null) {
+ var results = templateNode.content.evaluate(
+ roots,
+ rootValueTypes,
+ "value",
+ database
+ );
+ if (children != null) {
+ var rootValueTypes2 = { "value" : results.valueType, "index" : "number" };
+ var index = 1;
+
+ var processOneValue = function(childValue) {
+ var roots2 = { "value" : childValue, "index" : index++ };
+ for (var i = 0; i < children.length; i++) {
+ Exhibit.Lens._constructFromLensTemplateNode(
+ roots2, rootValueTypes2, children[i], elmt, opts);
+ }
+ };
+ if (results.values instanceof Array) {
+ for (var i = 0; i < results.values.length; i++) {
+ processOneValue(results.values[i]);
+ }
+ } else {
+ results.values.visit(processOneValue);
+ }
+ } else {
+ Exhibit.Lens._constructDefaultValueList(results.values, results.valueType, elmt, templateNode.uiContext);
+ }
+ } else if (templateNode.edit != null) {
+ // TODO: handle editType
+
+ // process children first, to get access to OPTION children of SELECT elements
+ processChildren();
+ Exhibit.Lens._constructEditableContent(templateNode, elmt, itemID, uiContext);
+ } else if (children != null) {
+ for (var i = 0; i < children.length; i++) {
+ Exhibit.Lens._constructFromLensTemplateNode(roots, rootValueTypes, children[i], elmt, opts);
+ }
+ }
+};
+
+Exhibit.Lens._constructElmtWithAttributes = function(templateNode, parentElmt, database) {
+ var elmt;
+ if (templateNode.tag == "input" && SimileAjax.Platform.browser.isIE) {
+ var a = [ "<input" ];
+ var attributes = templateNode.attributes;
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ if (Exhibit.Lens._attributeValueIsSafe(attribute.name, attribute.value)) {
+ a.push(attribute.name + "=\"" + attribute.value + "\"");
+ }
+ }
+ a.push("></input>");
+
+ elmt = SimileAjax.DOM.createElementFromString(a.join(" "));
+ parentElmt.appendChild(elmt);
+ } else {
+ switch (templateNode.tag) {
+ case "tr":
+ elmt = parentElmt.insertRow(parentElmt.rows.length);
+ break;
+ case "td":
+ elmt = parentElmt.insertCell(parentElmt.cells.length);
+ break;
+ default:
+ elmt = document.createElement(templateNode.tag);
+ parentElmt.appendChild(elmt);
+ }
+
+ var attributes = templateNode.attributes;
+ for (var i = 0; i < attributes.length; i++) {
+ var attribute = attributes[i];
+ if (Exhibit.Lens._attributeValueIsSafe(attribute.name, attribute.value)) {
+ try {
+ elmt.setAttribute(attribute.name, attribute.value);
+ } catch (e) {
+ // ignore; this happens on IE for attribute "type" on element "input"
+ }
+ }
+ }
+ }
+
+ var styles = templateNode.styles;
+ for (var i = 0; i < styles.length; i++) {
+ var style = styles[i];
+ elmt.style[style.name] = style.value;
+ }
+ return elmt;
+};
+
+
+Exhibit.Lens._constructEditableContent = function(templateNode, elmt, itemID, uiContext) {
+ var db = uiContext.getDatabase();
+ var attr = templateNode.edit.replace('.', '');
+
+ var itemValue = db.getObject(itemID, attr);
+ var changeHandler = function() {
+ if (this.value && this.value != itemValue)
+ db.editItem(itemID, attr, this.value);
+ }
+
+ if (templateNode.tag == 'select') {
+ Exhibit.Lens._constructEditableSelect(templateNode, elmt, itemID, uiContext, itemValue);
+ SimileAjax.jQuery(elmt).blur(changeHandler);
+ } else {
+ elmt.value = itemValue;
+ SimileAjax.jQuery(elmt).change(changeHandler);
+ }
+}
+
+Exhibit.Lens.doesSelectContain = function(select, text) {
+ for (var i in select.options) {
+ var opt = select.options[i];
+ if (opt.text == text || opt.value == text) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// helper function to handle special-case rules for editable select tags
+Exhibit.Lens._constructEditableSelect = function(templateNode, elmt, itemID, uiContext, itemValue) {
+ if (templateNode.options) {
+ var expr = Exhibit.ExpressionParser.parse(templateNode.options);
+ var allItems = uiContext.getDatabase().getAllItems();
+ var results = expr.evaluate({'value': allItems}, {value: 'item'}, 'value', uiContext.getDatabase());
+ var sortedResults = results.values.toArray().sort();
+
+ for (var i in sortedResults) {
+ var optText = sortedResults[i];
+ if (!Exhibit.Lens.doesSelectContain(elmt, optText)) {
+ var newOption = new Option(sortedResults[i], sortedResults[i]);
+ elmt.add(newOption, null);
+ }
+ }
+ }
+
+ if (!itemValue) {
+ if (!Exhibit.Lens.doesSelectContain(elmt, '')) {
+ var newOption = new Option("", "", true);
+ elmt.add(newOption, elmt.options[0]);
+ }
+ } else {
+ for (var i in elmt.options) {
+ if (elmt.options.hasOwnProperty(i) && elmt.options[i].value == itemValue) {
+ elmt.selectedIndex = i;
+ }
+ }
+ }
+}
+
+
+Exhibit.Lens._constructDefaultValueList = function(values, valueType, parentElmt, uiContext) {
+ uiContext.formatList(values, values.size(), valueType, function(elmt) {
+ parentElmt.appendChild(elmt);
+ });
+};
+
+Exhibit.Lens._attributeValueIsSafe = function(name, value) {
+ if (Exhibit.params.safe) {
+ if ((name == "href" && value.startsWith("javascript:")) ||
+ (name.startsWith("on"))) {
+ return false;
+ }
+ }
+ return true;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui-context.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui-context.js
new file mode 100644
index 00000000..f3908d66
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui-context.js
@@ -0,0 +1,295 @@
+/*======================================================================
+ * UIContext
+ *======================================================================
+ */
+Exhibit.UIContext = function() {
+ this._parent = null;
+
+ this._exhibit = null;
+ this._collection = null;
+ this._lensRegistry = new Exhibit.LensRegistry();
+ this._settings = {};
+
+ this._formatters = {};
+ this._listFormatter = null;
+
+ this._editModeRegistry = {};
+
+ this._popupFunc = null;
+};
+
+Exhibit.UIContext.createRootContext = function(configuration, exhibit) {
+ var context = new Exhibit.UIContext();
+ context._exhibit = exhibit;
+
+ var settings = Exhibit.UIContext.l10n.initialSettings;
+ for (var n in settings) {
+ context._settings[n] = settings[n];
+ }
+
+ var formats = Exhibit.getAttribute(document.body, "formats");
+ if (formats != null && formats.length > 0) {
+ Exhibit.FormatParser.parseSeveral(context, formats, 0, {});
+ }
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ document.body, Exhibit.UIContext._settingSpecs, context._settings);
+
+ Exhibit.UIContext._configure(context, configuration);
+
+ return context;
+};
+
+Exhibit.UIContext.create = function(configuration, parentUIContext, ignoreLenses) {
+ var context = Exhibit.UIContext._createWithParent(parentUIContext);
+ Exhibit.UIContext._configure(context, configuration, ignoreLenses);
+
+ return context;
+};
+
+Exhibit.UIContext.createFromDOM = function(configElmt, parentUIContext, ignoreLenses) {
+ var context = Exhibit.UIContext._createWithParent(parentUIContext);
+
+ if (!(ignoreLenses)) {
+ Exhibit.UIContext.registerLensesFromDOM(configElmt, context.getLensRegistry());
+ }
+
+ var id = Exhibit.getAttribute(configElmt, "collectionID");
+ if (id != null && id.length > 0) {
+ context._collection = context._exhibit.getCollection(id);
+ }
+
+ var formats = Exhibit.getAttribute(configElmt, "formats");
+ if (formats != null && formats.length > 0) {
+ Exhibit.FormatParser.parseSeveral(context, formats, 0, {});
+ }
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ configElmt, Exhibit.UIContext._settingSpecs, context._settings);
+
+ Exhibit.UIContext._configure(context, Exhibit.getConfigurationFromDOM(configElmt), ignoreLenses);
+
+ return context;
+};
+
+/*----------------------------------------------------------------------
+ * Public interface
+ *----------------------------------------------------------------------
+ */
+Exhibit.UIContext.prototype.dispose = function() {
+};
+
+Exhibit.UIContext.prototype.getParentUIContext = function() {
+ return this._parent;
+};
+
+Exhibit.UIContext.prototype.getExhibit = function() {
+ return this._exhibit;
+};
+
+Exhibit.UIContext.prototype.getDatabase = function() {
+ return this.getExhibit().getDatabase();
+};
+
+Exhibit.UIContext.prototype.getCollection = function() {
+ if (this._collection == null) {
+ if (this._parent != null) {
+ this._collection = this._parent.getCollection();
+ } else {
+ this._collection = this._exhibit.getDefaultCollection();
+ }
+ }
+ return this._collection;
+};
+
+Exhibit.UIContext.prototype.getLensRegistry = function() {
+ return this._lensRegistry;
+};
+
+Exhibit.UIContext.prototype.getSetting = function(name) {
+ return name in this._settings ?
+ this._settings[name] :
+ (this._parent != null ? this._parent.getSetting(name) : undefined);
+};
+
+Exhibit.UIContext.prototype.getBooleanSetting = function(name, defaultValue) {
+ var v = this.getSetting(name);
+ return v == undefined || v == null ? defaultValue : v;
+};
+
+Exhibit.UIContext.prototype.putSetting = function(name, value) {
+ this._settings[name] = value;
+};
+
+Exhibit.UIContext.prototype.format = function(value, valueType, appender) {
+ var f;
+ if (valueType in this._formatters) {
+ f = this._formatters[valueType];
+ } else {
+ f = this._formatters[valueType] =
+ new Exhibit.Formatter._constructors[valueType](this);
+ }
+ f.format(value, appender);
+};
+
+Exhibit.UIContext.prototype.formatList = function(iterator, count, valueType, appender) {
+ if (this._listFormatter == null) {
+ this._listFormatter = new Exhibit.Formatter._ListFormatter(this);
+ }
+ this._listFormatter.formatList(iterator, count, valueType, appender);
+};
+
+Exhibit.UIContext.prototype.setEditMode = function(itemID, val) {
+ if (val) {
+ this._editModeRegistry[itemID] = true;
+ } else {
+ this._editModeRegistry[itemID] = false;
+ }
+}
+
+Exhibit.UIContext.prototype.isBeingEdited = function(itemID) {
+ return !!this._editModeRegistry[itemID];
+}
+
+
+/*----------------------------------------------------------------------
+ * Internal implementation
+ *----------------------------------------------------------------------
+ */
+Exhibit.UIContext._createWithParent = function(parent) {
+ var context = new Exhibit.UIContext();
+
+ context._parent = parent;
+ context._exhibit = parent._exhibit;
+ context._lensRegistry = new Exhibit.LensRegistry(parent.getLensRegistry());
+ context._editModeRegistry = parent._editModeRegistry;
+
+ return context;
+};
+
+Exhibit.UIContext._settingSpecs = {
+ "bubbleWidth": { type: "int" },
+ "bubbleHeight": { type: "int" }
+};
+
+Exhibit.UIContext._configure = function(context, configuration, ignoreLenses) {
+ Exhibit.UIContext.registerLenses(configuration, context.getLensRegistry());
+
+ if ("collectionID" in configuration) {
+ context._collection = context._exhibit.getCollection(configuration["collectionID"]);
+ }
+
+ if ("formats" in configuration) {
+ Exhibit.FormatParser.parseSeveral(context, configuration.formats, 0, {});
+ }
+
+ if (!(ignoreLenses)) {
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.UIContext._settingSpecs, context._settings);
+ }
+};
+
+/*----------------------------------------------------------------------
+ * Lens utility functions for internal use
+ *----------------------------------------------------------------------
+ */
+Exhibit.UIContext.registerLens = function(configuration, lensRegistry) {
+ var template = configuration.templateFile;
+ if (template != null) {
+ if ("itemTypes" in configuration) {
+ for (var i = 0; i < configuration.itemTypes.length; i++) {
+ lensRegistry.registerLensForType(template, configuration.itemTypes[i]);
+ }
+ } else {
+ lensRegistry.registerDefaultLens(template);
+ }
+ }
+};
+
+Exhibit.UIContext.registerLensFromDOM = function(elmt, lensRegistry) {
+ elmt.style.display = "none";
+
+ var itemTypes = Exhibit.getAttribute(elmt, "itemTypes", ",");
+ var template = null;
+
+ var url = Exhibit.getAttribute(elmt, "templateFile");
+ if (url != null && url.length > 0) {
+ template = url;
+ } else {
+ var id = Exhibit.getAttribute(elmt, "template");
+ var elmt2 = id && document.getElementById(id);
+ if (elmt2 != null) {
+ template = elmt2;
+ } else {
+ template = elmt;
+ }
+ }
+
+ if (template != null) {
+ if (itemTypes == null || itemTypes.length == 0 || (itemTypes.length == 1 && itemTypes[0] == "")) {
+ lensRegistry.registerDefaultLens(template);
+ } else {
+ for (var i = 0; i < itemTypes.length; i++) {
+ lensRegistry.registerLensForType(template, itemTypes[i]);
+ }
+ }
+ }
+};
+
+Exhibit.UIContext.registerLenses = function(configuration, lensRegistry) {
+ if ("lenses" in configuration) {
+ for (var i = 0; i < configuration.lenses.length; i++) {
+ Exhibit.UIContext.registerLens(configuration.lenses[i], lensRegistry);
+ }
+ }
+ if ("lensSelector" in configuration) {
+ var lensSelector = configuration.lensSelector;
+ if (typeof lensSelector == "function") {
+ lensRegistry.addLensSelector(lensSelector);
+ } else {
+ SimileAjax.Debug.log("lensSelector is not a function");
+ }
+ }
+};
+
+Exhibit.UIContext.registerLensesFromDOM = function(parentNode, lensRegistry) {
+ var node = parentNode.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ var role = Exhibit.getRoleAttribute(node);
+ if (role == "lens" || role == "edit-lens") {
+ Exhibit.UIContext.registerLensFromDOM(node, lensRegistry);
+ }
+ }
+ node = node.nextSibling;
+ }
+
+ var lensSelectorString = Exhibit.getAttribute(parentNode, "lensSelector");
+ if (lensSelectorString != null && lensSelectorString.length > 0) {
+ try {
+ var lensSelector = eval(lensSelectorString);
+ if (typeof lensSelector == "function") {
+ lensRegistry.addLensSelector(lensSelector);
+ } else {
+ SimileAjax.Debug.log("lensSelector expression " + lensSelectorString + " is not a function");
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Bad lensSelector expression: " + lensSelectorString);
+ }
+ }
+};
+
+Exhibit.UIContext.createLensRegistry = function(configuration, parentLensRegistry) {
+ var lensRegistry = new Exhibit.LensRegistry(parentLensRegistry);
+ Exhibit.UIContext.registerLenses(configuration, lensRegistry);
+
+ return lensRegistry;
+};
+
+Exhibit.UIContext.createLensRegistryFromDOM = function(parentNode, configuration, parentLensRegistry) {
+ var lensRegistry = new Exhibit.LensRegistry(parentLensRegistry);
+ Exhibit.UIContext.registerLensesFromDOM(parentNode, lensRegistry);
+ Exhibit.UIContext.registerLenses(configuration, lensRegistry);
+
+ return lensRegistry;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui.js
new file mode 100644
index 00000000..7ec70438
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/ui.js
@@ -0,0 +1,623 @@
+/*======================================================================
+ * Exhibit UI Utilities
+ *======================================================================
+ */
+Exhibit.UI = new Object();
+
+/*----------------------------------------------------------------------
+ * Component instantiation functions
+ *----------------------------------------------------------------------
+ */
+
+Exhibit.UI.componentMap = {};
+
+Exhibit.UI.registerComponent = function(name, comp) {
+ var msg = "Cannot register component " + name + " -- ";
+ if (name in Exhibit.UI.componentMap) {
+ SimileAjax.Debug.warn(msg + 'another component has taken that name');
+ } else if (!comp) {
+ SimileAjax.Debug.warn(msg + 'no component object provided')
+ } else if (!comp.create) {
+ SimileAjax.Debug.warn(msg + "component has no create function");
+ } else if (!comp.createFromDOM) {
+ SimileAjax.Debug.warn(msg + "component has no createFromDOM function");
+ } else {
+ Exhibit.UI.componentMap[name] = comp;
+ }
+};
+
+Exhibit.UI.create = function(configuration, elmt, uiContext) {
+ if ("role" in configuration) {
+ var role = configuration.role;
+ if (role != null && role.startsWith("exhibit-")) {
+ role = role.substr("exhibit-".length);
+ }
+
+ if (role in Exhibit.UI.componentMap) {
+ var createFunc = Exhibit.UI.componentMap[role].create;
+ return createFunc(configuration, elmt, uiContext);
+ }
+
+ switch (role) {
+ case "lens":
+ case "edit-lens":
+ Exhibit.UIContext.registerLens(configuration, uiContext.getLensRegistry());
+ return null;
+ case "view":
+ return Exhibit.UI.createView(configuration, elmt, uiContext);
+ case "facet":
+ return Exhibit.UI.createFacet(configuration, elmt, uiContext);
+ case "coordinator":
+ return Exhibit.UI.createCoordinator(configuration, uiContext);
+ case "coder":
+ return Exhibit.UI.createCoder(configuration, uiContext);
+ case "viewPanel":
+ return Exhibit.ViewPanel.create(configuration, elmt, uiContext);
+ case "logo":
+ return Exhibit.Logo.create(configuration, elmt, uiContext);
+ case "hiddenContent":
+ elmt.style.display = "none";
+ return null;
+ }
+ }
+ return null;
+};
+
+Exhibit.UI.createFromDOM = function(elmt, uiContext) {
+ var role = Exhibit.getRoleAttribute(elmt);
+
+ if (role in Exhibit.UI.componentMap) {
+ var createFromDOMFunc = Exhibit.UI.componentMap[role].createFromDOM;
+ return createFromDOMFunc(elmt, uiContext);
+ }
+
+ switch (role) {
+ case "lens":
+ case "edit-lens":
+ Exhibit.UIContext.registerLensFromDOM(elmt, uiContext.getLensRegistry());
+ return null;
+ case "view":
+ return Exhibit.UI.createViewFromDOM(elmt, null, uiContext);
+ case "facet":
+ return Exhibit.UI.createFacetFromDOM(elmt, null, uiContext);
+ case "coordinator":
+ return Exhibit.UI.createCoordinatorFromDOM(elmt, uiContext);
+ case "coder":
+ return Exhibit.UI.createCoderFromDOM(elmt, uiContext);
+ case "viewPanel":
+ return Exhibit.ViewPanel.createFromDOM(elmt, uiContext);
+ case "logo":
+ return Exhibit.Logo.createFromDOM(elmt, uiContext);
+ case "hiddenContent":
+ elmt.style.display = "none";
+ return null;
+ }
+ return null;
+};
+
+
+Exhibit.UI.generateCreationMethods = function(constructor) {
+ constructor.create = function(configuration, elmt, uiContext) {
+ var newContext = Exhibit.UIContext.create(configuration, uiContext);
+ var settings = {};
+
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration,
+ constructor._settingSpecs || {},
+ settings);
+
+ return new constructor(elmt, newContext, settings);
+ };
+ constructor.createFromDOM = function(elmt, uiContext) {
+ var newContext = Exhibit.UIContext.createFromDOM(elmt, uiContext);
+ var settings = {};
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ elmt,
+ constructor._settingSpecs || {},
+ settings);
+
+ return new constructor(elmt, newContext, settings);
+ };
+};
+
+Exhibit.UI.createView = function(configuration, elmt, uiContext) {
+ var viewClass = "viewClass" in configuration ? configuration.viewClass : Exhibit.TileView;
+ if (typeof viewClass == "string") {
+ viewClass = Exhibit.UI.viewClassNameToViewClass(viewClass);
+ }
+ return viewClass.create(configuration, elmt, uiContext);
+};
+
+Exhibit.UI.createViewFromDOM = function(elmt, container, uiContext) {
+ var viewClass = Exhibit.UI.viewClassNameToViewClass(Exhibit.getAttribute(elmt, "viewClass"));
+ return viewClass.createFromDOM(elmt, container, uiContext);
+};
+
+Exhibit.UI.viewClassNameToViewClass = function(name) {
+ if (name != null && name.length > 0) {
+ try {
+ return Exhibit.UI._stringToObject(name, "View");
+ } catch (e) {
+ SimileAjax.Debug.warn("Unknown viewClass " + name);
+ }
+ }
+ return Exhibit.TileView;
+};
+
+Exhibit.UI.createFacet = function(configuration, elmt, uiContext) {
+ var facetClass = "facetClass" in configuration ? configuration.facetClass : Exhibit.ListFacet;
+ if (typeof facetClass == "string") {
+ facetClass = Exhibit.UI.facetClassNameToFacetClass(facetClass);
+ }
+ return facetClass.create(configuration, elmt, uiContext);
+};
+
+Exhibit.UI.createFacetFromDOM = function(elmt, container, uiContext) {
+ var facetClass = Exhibit.UI.facetClassNameToFacetClass(Exhibit.getAttribute(elmt, "facetClass"));
+ return facetClass.createFromDOM(elmt, container, uiContext);
+};
+
+Exhibit.UI.facetClassNameToFacetClass = function(name) {
+ if (name != null && name.length > 0) {
+ try {
+ return Exhibit.UI._stringToObject(name, "Facet");
+ } catch (e) {
+ SimileAjax.Debug.warn("Unknown facetClass " + name);
+ }
+ }
+ return Exhibit.ListFacet;
+};
+
+
+Exhibit.UI.createCoder = function(configuration, uiContext) {
+ var coderClass = "coderClass" in configuration ? configuration.coderClass : Exhibit.ColorCoder;
+ if (typeof coderClass == "string") {
+ coderClass = Exhibit.UI.coderClassNameToCoderClass(coderClass);
+ }
+ return coderClass.create(configuration, uiContext);
+};
+
+Exhibit.UI.createCoderFromDOM = function(elmt, uiContext) {
+ var coderClass = Exhibit.UI.coderClassNameToCoderClass(Exhibit.getAttribute(elmt, "coderClass"));
+ return coderClass.createFromDOM(elmt, uiContext);
+};
+
+Exhibit.UI.coderClassNameToCoderClass = function(name) {
+ if (name != null && name.length > 0) {
+ try {
+ return Exhibit.UI._stringToObject(name, "Coder");
+ } catch (e) {
+ SimileAjax.Debug.warn("Unknown coderClass " + name);
+ }
+ }
+ return Exhibit.ColorCoder;
+};
+
+
+Exhibit.UI.createCoordinator = function(configuration, uiContext) {
+ return Exhibit.Coordinator.create(configuration, uiContext);
+};
+
+Exhibit.UI.createCoordinatorFromDOM = function(elmt, uiContext) {
+ return Exhibit.Coordinator.createFromDOM(elmt, uiContext);
+};
+
+Exhibit.UI._stringToObject = function(name, suffix) {
+ if (!name.startsWith("Exhibit.")) {
+ if (!name.endsWith(suffix)) {
+ try {
+ return eval("Exhibit." + name + suffix);
+ } catch (e) {
+ // ignore
+ }
+ }
+
+ try {
+ return eval("Exhibit." + name);
+ } catch (e) {
+ // ignore
+ }
+ }
+
+ if (!name.endsWith(suffix)) {
+ try {
+ return eval(name + suffix);
+ } catch (e) {
+ // ignore
+ }
+ }
+
+ try {
+ return eval(name);
+ } catch (e) {
+ // ignore
+ }
+
+ throw new Error("Unknown class " + name);
+};
+
+/*----------------------------------------------------------------------
+ * Help and Debugging
+ *----------------------------------------------------------------------
+ */
+Exhibit.UI.docRoot = "http://simile.mit.edu/wiki/";
+Exhibit.UI.validator = "http://simile.mit.edu/babel/validator";
+
+Exhibit.UI.showHelp = function(message, url, target) {
+ target = (target) ? target : "_blank";
+ if (url != null) {
+ if (window.confirm(message + "\n\n" + Exhibit.l10n.showDocumentationMessage)) {
+ window.open(url, target);
+ }
+ } else {
+ window.alert(message);
+ }
+};
+
+Exhibit.UI.showJavascriptExpressionValidation = function(message, expression) {
+ var target = "_blank";
+ if (window.confirm(message + "\n\n" + Exhibit.l10n.showJavascriptValidationMessage)) {
+ window.open(Exhibit.UI.validator + "?expresson=" + encodeURIComponent(expression), target);
+ }
+};
+
+Exhibit.UI.showJsonFileValidation = function(message, url) {
+ var target = "_blank";
+ if (url.indexOf("file:") == 0) {
+ if (window.confirm(message + "\n\n" + Exhibit.l10n.showJsonValidationFormMessage)) {
+ window.open(Exhibit.UI.validator, target);
+ }
+ } else {
+ if (window.confirm(message + "\n\n" + Exhibit.l10n.showJsonValidationMessage)) {
+ window.open(Exhibit.UI.validator + "?url=" + url, target);
+ }
+ }
+};
+
+/*----------------------------------------------------------------------
+ * Status Indication and Feedback
+ *----------------------------------------------------------------------
+ */
+Exhibit.UI._busyIndicator = null;
+Exhibit.UI._busyIndicatorCount = 0;
+
+Exhibit.UI.showBusyIndicator = function() {
+ Exhibit.UI._busyIndicatorCount++;
+ if (Exhibit.UI._busyIndicatorCount > 1) {
+ return;
+ }
+
+ if (Exhibit.UI._busyIndicator == null) {
+ Exhibit.UI._busyIndicator = Exhibit.UI.createBusyIndicator();
+ }
+
+ var scrollTop = ("scrollTop" in document.body) ?
+ document.body.scrollTop :
+ document.body.parentNode.scrollTop;
+ var height = ("innerHeight" in window) ?
+ window.innerHeight :
+ ("clientHeight" in document.body ?
+ document.body.clientHeight :
+ document.body.parentNode.clientHeight);
+
+ var top = Math.floor(scrollTop + height / 3);
+
+ Exhibit.UI._busyIndicator.style.top = top + "px";
+ document.body.appendChild(Exhibit.UI._busyIndicator);
+};
+
+Exhibit.UI.hideBusyIndicator = function() {
+ Exhibit.UI._busyIndicatorCount--;
+ if (Exhibit.UI._busyIndicatorCount > 0) {
+ return;
+ }
+
+ try {
+ document.body.removeChild(Exhibit.UI._busyIndicator);
+ } catch(e) {
+ // silent
+ }
+};
+
+/*----------------------------------------------------------------------
+ * Common UI Generation
+ *----------------------------------------------------------------------
+ */
+Exhibit.UI.protectUI = function(elmt) {
+ SimileAjax.DOM.appendClassName(elmt, "exhibit-ui-protection");
+};
+
+Exhibit.UI.makeActionLink = function(text, handler, layer) {
+ var a = document.createElement("a");
+ a.href = "javascript:";
+ a.className = "exhibit-action";
+ a.innerHTML = text;
+
+ var handler2 = function(elmt, evt, target) {
+ if ("true" != elmt.getAttribute("disabled")) {
+ handler(elmt, evt, target);
+ }
+ }
+ SimileAjax.WindowManager.registerEvent(a, "click", handler2, layer);
+
+ return a;
+};
+
+Exhibit.UI.enableActionLink = function(a, enabled) {
+ a.setAttribute("disabled", enabled ? "false" : "true");
+ a.className = enabled ? "exhibit-action" : "exhibit-action-disabled";
+};
+
+Exhibit.UI.makeItemSpan = function(itemID, label, uiContext, layer) {
+ if (label == null) {
+ label = database.getObject(itemID, "label");
+ if (label == null) {
+ label = itemID;
+ }
+ }
+
+ var a = SimileAjax.DOM.createElementFromString(
+ "<a href=\"" + Exhibit.Persistence.getItemLink(itemID) + "\" class='exhibit-item'>" + label + "</a>");
+
+ var handler = function(elmt, evt, target) {
+ Exhibit.UI.showItemInPopup(itemID, elmt, uiContext);
+ }
+ SimileAjax.WindowManager.registerEvent(a, "click", handler, layer);
+
+ return a;
+};
+
+Exhibit.UI.makeValueSpan = function(label, valueType, layer) {
+ var span = document.createElement("span");
+ span.className = "exhibit-value";
+ if (valueType == "url") {
+ var url = label;
+ if (Exhibit.params.safe && url.trim().startsWith("javascript:")) {
+ span.appendChild(document.createTextNode(url));
+ } else {
+ span.innerHTML =
+ "<a href=\"" + url + "\" target='_blank'>" +
+ (label.length > 50 ?
+ label.substr(0, 20) + " ... " + label.substr(label.length - 20) :
+ label) +
+ "</a>";
+ }
+ } else {
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+ span.innerHTML = label;
+ }
+ return span;
+};
+
+Exhibit.UI.calculatePopupPosition = function(elmt) {
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+ return {
+ x: coords.left + Math.round(elmt.offsetWidth / 2),
+ y: coords.top + Math.round(elmt.offsetHeight / 2)
+ };
+}
+
+Exhibit.UI.showItemInPopup = function(itemID, elmt, uiContext, opts) {
+ SimileAjax.WindowManager.popAllLayers();
+
+ opts = opts || {};
+ opts.coords = opts.coords || Exhibit.UI.calculatePopupPosition(elmt);
+
+ var itemLensDiv = document.createElement("div");
+
+ var lensOpts = {
+ inPopup: true,
+ coords: opts.coords
+ };
+
+ if (opts.lensType == 'normal') {
+ lensOpts.lensTemplate = uiContext.getLensRegistry().getNormalLens(itemID, uiContext);
+ } else if (opts.lensType == 'edit') {
+ lensOpts.lensTemplate = uiContext.getLensRegistry().getEditLens(itemID, uiContext);
+ } else if (opts.lensType) {
+ SimileAjax.Debug.warn('Unknown Exhibit.UI.showItemInPopup opts.lensType: ' + opts.lensType);
+ }
+
+ uiContext.getLensRegistry().createLens(itemID, itemLensDiv, uiContext, lensOpts);
+
+ SimileAjax.Graphics.createBubbleForContentAndPoint(
+ itemLensDiv,
+ opts.coords.x,
+ opts.coords.y,
+ uiContext.getSetting("bubbleWidth")
+ );
+};
+
+Exhibit.UI.createButton = function(name, handler, className) {
+ var button = document.createElement("button");
+ button.className = (className || "exhibit-button") + " screen";
+ button.innerHTML = name;
+ if (handler) {
+ SimileAjax.WindowManager.registerEvent(button, "click", handler);
+ }
+ return button;
+};
+
+Exhibit.UI.createPopupMenuDom = function(element) {
+ var div = document.createElement("div");
+ div.className = "exhibit-menu-popup exhibit-ui-protection";
+
+ var dom = {
+ elmt: div,
+ close: function() {
+ document.body.removeChild(this.elmt);
+ },
+ open: function() {
+ var self = this;
+ this.layer = SimileAjax.WindowManager.pushLayer(function() { self.close(); }, true, div);
+
+ var docWidth = document.body.offsetWidth;
+ var docHeight = document.body.offsetHeight;
+
+ var coords = SimileAjax.DOM.getPageCoordinates(element);
+ div.style.top = (coords.top + element.scrollHeight) + "px";
+ div.style.right = (docWidth - (coords.left + element.scrollWidth)) + "px";
+
+ document.body.appendChild(this.elmt);
+ },
+ appendMenuItem: function(label, icon, onClick) {
+ var self = this;
+ var a = document.createElement("a");
+ a.className = "exhibit-menu-item";
+ a.href = "javascript:";
+ SimileAjax.WindowManager.registerEvent(a, "click", function(elmt, evt, target) {
+ onClick(elmt, evt, target);
+ SimileAjax.WindowManager.popLayer(self.layer);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ });
+
+ var div = document.createElement("div");
+ a.appendChild(div);
+
+ div.appendChild(SimileAjax.Graphics.createTranslucentImage(
+ icon != null ? icon : (Exhibit.urlPrefix + "images/blank-16x16.png")));
+
+ div.appendChild(document.createTextNode(label));
+
+ this.elmt.appendChild(a);
+ },
+ appendSeparator: function() {
+ var hr = document.createElement("hr");
+ this.elmt.appendChild(hr);
+ }
+ };
+ return dom;
+};
+
+Exhibit.UI.createBusyIndicator = function() {
+ var urlPrefix = Exhibit.urlPrefix + "images/";
+ var containerDiv = document.createElement("div");
+ if (SimileAjax.Graphics.pngIsTranslucent) {
+
+ var topDiv = document.createElement("div");
+ topDiv.style.height = "33px";
+ topDiv.style.background = "url(" + urlPrefix + "message-bubble/message-top-left.png) top left no-repeat";
+ topDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(topDiv);
+
+ var topRightDiv = document.createElement("div");
+ topRightDiv.style.height = "33px";
+ topRightDiv.style.background = "url(" + urlPrefix + "message-bubble/message-top-right.png) top right no-repeat";
+ topDiv.appendChild(topRightDiv);
+
+ var middleDiv = document.createElement("div");
+ middleDiv.style.background = "url(" + urlPrefix + "message-bubble/message-left.png) top left repeat-y";
+ middleDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(middleDiv);
+
+ var middleRightDiv = document.createElement("div");
+ middleRightDiv.style.background = "url(" + urlPrefix + "message-bubble/message-right.png) top right repeat-y";
+ middleRightDiv.style.paddingRight = "44px";
+ middleDiv.appendChild(middleRightDiv);
+
+ var contentDiv = document.createElement("div");
+ middleRightDiv.appendChild(contentDiv);
+
+ var bottomDiv = document.createElement("div");
+ bottomDiv.style.height = "55px";
+ bottomDiv.style.background = "url(" + urlPrefix + "message-bubble/message-bottom-left.png) bottom left no-repeat";
+ bottomDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(bottomDiv);
+
+ var bottomRightDiv = document.createElement("div");
+ bottomRightDiv.style.height = "55px";
+ bottomRightDiv.style.background = "url(" + urlPrefix + "message-bubble/message-bottom-right.png) bottom right no-repeat";
+ bottomDiv.appendChild(bottomRightDiv);
+ } else {
+ containerDiv.style.border = "2px solid #7777AA";
+ containerDiv.style.padding = "20px";
+ containerDiv.style.background = "white";
+ SimileAjax.Graphics.setOpacity(containerDiv, 90);
+
+ var contentDiv = document.createElement("div");
+ containerDiv.appendChild(contentDiv);
+ }
+
+ containerDiv.className = "exhibit-busyIndicator";
+ contentDiv.className = "exhibit-busyIndicator-content";
+
+ var img = document.createElement("img");
+ img.src = urlPrefix + "progress-running.gif";
+ contentDiv.appendChild(img);
+ contentDiv.appendChild(document.createTextNode(" " + Exhibit.l10n.busyIndicatorMessage));
+
+ return containerDiv;
+};
+
+Exhibit.UI.createFocusDialogBox = function(itemID, exhibit, configuration) {
+ var template = {
+ tag: "div",
+ className: "exhibit-focusDialog exhibit-ui-protection",
+ children: [
+ { tag: "div",
+ className: "exhibit-focusDialog-viewContainer",
+ field: "viewContainer"
+ },
+ { tag: "div",
+ className: "exhibit-focusDialog-controls",
+ children: [
+ { tag: "button",
+ field: "closeButton",
+ children: [ Exhibit.l10n.focusDialogBoxCloseButtonLabel ]
+ }
+ ]
+ }
+ ]
+ };
+ var dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ dom.close = function() {
+ document.body.removeChild(dom.elmt);
+ };
+ dom.open = function() {
+ dom.layer = SimileAjax.WindowManager.pushLayer(function() { dom.close(); }, false);
+ var lens = new Exhibit.Lens(itemID, dom.viewContainer, exhibit, configuration);
+
+ dom.elmt.style.top = (document.body.scrollTop + 100) + "px";
+ document.body.appendChild(dom.elmt);
+
+ SimileAjax.WindowManager.registerEvent(
+ dom.closeButton,
+ "click",
+ function(elmt, evt, target) {
+ SimileAjax.WindowManager.popLayer(dom.layer);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ },
+ dom.layer
+ );
+ };
+
+ return dom;
+};
+
+Exhibit.UI.createTranslucentImage = function(relativeUrl, verticalAlign) {
+ return SimileAjax.Graphics.createTranslucentImage(Exhibit.urlPrefix + relativeUrl, verticalAlign);
+};
+Exhibit.UI.createTranslucentImageHTML = function(relativeUrl, verticalAlign) {
+ return SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix + relativeUrl, verticalAlign);
+};
+
+// jQuery can't search for attributes with colons in them
+Exhibit.UI.findAttribute = function(attr, value, parent) {
+ var parent = SimileAjax.jQuery(parent || document.body);
+ var f = function( ) {
+ var v = this.getAttribute(attr);
+ if (value === undefined) {
+ return !!v;
+ } else if (value instanceof Array) {
+ return value.indexOf(v) != -1;
+ } else {
+ return value.toString() == v;
+ }
+ }
+ return parent.find('*').add(parent).filter(f);
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/html-view.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/html-view.js
new file mode 100644
index 00000000..b8dcf0a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/html-view.js
@@ -0,0 +1,39 @@
+/*==================================================
+ * Exhibit.HTMLView
+ *==================================================
+ */
+
+Exhibit.HTMLView = function(containerElmt, uiContext, html) {
+ this.html = html;
+ this.view = this.moveChildNodes(html, containerElmt);
+ //this._uiContext = uiContext;
+};
+
+Exhibit.HTMLView.create = Exhibit.HTMLView.createFromDOM = function(
+ configElmt,
+ containerElmt,
+ uiContext
+) {
+ return new Exhibit.HTMLView(
+ containerElmt != null ? containerElmt : configElmt,
+ null,//Exhibit.UIContext.createFromDOM(configElmt, uiContext),
+ configElmt
+ );
+};
+
+Exhibit.HTMLView.prototype.dispose = function() {
+ //this._uiContext.dispose();
+ //this._uiContext = null;
+
+ this.html = this.moveChildNodes(this.view, this.html);
+ this.view = this.html = null;
+};
+
+Exhibit.HTMLView.prototype.moveChildNodes = function(src, dst) {
+ if( src === dst ) return dst;
+ var tmp = document.createDocumentFragment();
+ while(src.firstChild)
+ tmp.appendChild(src.firstChild);
+ dst.appendChild(tmp);
+ return dst;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/ordered-view-frame.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/ordered-view-frame.js
new file mode 100644
index 00000000..e0674ac7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/ordered-view-frame.js
@@ -0,0 +1,979 @@
+/*==================================================
+ * Exhibit.OrderedViewFrame
+ *==================================================
+ */
+
+Exhibit.OrderedViewFrame = function(uiContext) {
+ this._uiContext = uiContext;
+
+ this._orders = null;
+ this._possibleOrders = null;
+ this._settings = {};
+};
+
+Exhibit.OrderedViewFrame._settingSpecs = {
+ "showAll": { type: "boolean", defaultValue: false },
+ "grouped": { type: "boolean", defaultValue: true },
+ "showDuplicates": { type: "boolean", defaultValue: false },
+ "abbreviatedCount": { type: "int", defaultValue: 10 },
+ "showHeader": { type: "boolean", defaultValue: true },
+ "showSummary": { type: "boolean", defaultValue: true },
+ "showControls": { type: "boolean", defaultValue: true },
+ "showFooter": { type: "boolean", defaultValue: true },
+ "paginate": { type: "boolean", defaultValue: false },
+ "pageSize": { type: "int", defaultValue: 20 },
+ "pageWindow": { type: "int", defaultValue: 2 },
+ "page": { type: "int", defaultValue: 0 },
+ "alwaysShowPagingControls": { type: "boolean", defaultValue: false },
+ "pagingControlLocations": { type: "enum", defaultValue: "topbottom", choices: [ "top", "bottom", "topbottom" ] }
+};
+
+Exhibit.OrderedViewFrame.prototype.configure = function(configuration) {
+ if ("orders" in configuration) {
+ this._orders = [];
+ this._configureOrders(configuration.orders);
+ }
+ if ("possibleOrders" in configuration) {
+ this._possibleOrders = [];
+ this._configurePossibleOrders(configuration.possibleOrders);
+ }
+
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.OrderedViewFrame._settingSpecs, this._settings);
+
+ this._internalValidate();
+};
+
+Exhibit.OrderedViewFrame.prototype.configureFromDOM = function(domConfiguration) {
+ var orders = Exhibit.getAttribute(domConfiguration, "orders", ",");
+ if (orders != null && orders.length > 0) {
+ this._orders = [];
+ this._configureOrders(orders);
+ }
+
+ var directions = Exhibit.getAttribute(domConfiguration, "directions", ",");
+ if (directions != null && directions.length > 0 && this._orders != null) {
+ for (var i = 0; i < directions.length && i < this._orders.length; i++) {
+ this._orders[i].ascending = (directions[i].toLowerCase() != "descending");
+ }
+ }
+
+ var possibleOrders = Exhibit.getAttribute(domConfiguration, "possibleOrders", ",");
+ if (possibleOrders != null && possibleOrders.length > 0) {
+ this._possibleOrders = [];
+ this._configurePossibleOrders(possibleOrders);
+ }
+
+ var possibleDirections = Exhibit.getAttribute(domConfiguration, "possibleDirections", ",");
+ if (possibleDirections != null && possibleDirections.length > 0 && this._possibleOrders != null) {
+ for (var i = 0; i < possibleDirections.length && i < this._possibleOrders.length; i++) {
+ this._possibleOrders[i].ascending = (possibleDirections[i].toLowerCase() != "descending");
+ }
+ }
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ domConfiguration, Exhibit.OrderedViewFrame._settingSpecs, this._settings);
+
+ this._internalValidate();
+}
+
+Exhibit.OrderedViewFrame.prototype.dispose = function() {
+ if (this._headerDom) {
+ this._headerDom.dispose();
+ this._headerDom = null;
+ }
+ if (this._footerDom) {
+ this._footerDom.dispose();
+ this._footerDom = null;
+ }
+
+ this._divHeader = null;
+ this._divFooter = null;
+ this._uiContext = null;
+};
+
+Exhibit.OrderedViewFrame.prototype._internalValidate = function() {
+ if (this._orders != null && this._orders.length == 0) {
+ this._orders = null;
+ }
+ if (this._possibleOrders != null && this._possibleOrders.length == 0) {
+ this._possibleOrders = null;
+ }
+ if (this._settings.paginate) {
+ this._settings.grouped = false;
+ }
+};
+
+Exhibit.OrderedViewFrame.prototype._configureOrders = function(orders) {
+ for (var i = 0; i < orders.length; i++) {
+ var order = orders[i];
+ var expr;
+ var ascending = true;
+
+ if (typeof order == "string") {
+ expr = order;
+ } else if (typeof order == "object") {
+ expr = order.expression,
+ ascending = ("ascending" in order) ? (order.ascending) : true;
+ } else {
+ SimileAjax.Debug.warn("Bad order object " + order);
+ continue;
+ }
+
+ try {
+ var expression = Exhibit.ExpressionParser.parse(expr);
+ if (expression.isPath()) {
+ var path = expression.getPath();
+ if (path.getSegmentCount() == 1) {
+ var segment = path.getSegment(0);
+ this._orders.push({
+ property: segment.property,
+ forward: segment.forward,
+ ascending: ascending
+ });
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.warn("Bad order expression " + expr);
+ }
+ }
+};
+
+Exhibit.OrderedViewFrame.prototype._configurePossibleOrders = function(possibleOrders) {
+ for (var i = 0; i < possibleOrders.length; i++) {
+ var order = possibleOrders[i];
+ var expr;
+ var ascending = true;
+
+ if (typeof order == "string") {
+ expr = order;
+ } else if (typeof order == "object") {
+ expr = order.expression,
+ ascending = ("ascending" in order) ? (order.ascending) : true;
+ } else {
+ SimileAjax.Debug.warn("Bad possible order object " + order);
+ continue;
+ }
+
+ try {
+ var expression = Exhibit.ExpressionParser.parse(expr);
+ if (expression.isPath()) {
+ var path = expression.getPath();
+ if (path.getSegmentCount() == 1) {
+ var segment = path.getSegment(0);
+ this._possibleOrders.push({
+ property: segment.property,
+ forward: segment.forward,
+ ascending: ascending
+ });
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.warn("Bad possible order expression " + expr);
+ }
+ }
+};
+
+Exhibit.OrderedViewFrame.prototype.initializeUI = function() {
+ var self = this;
+ if (this._settings.showHeader) {
+ this._headerDom = Exhibit.OrderedViewFrame.createHeaderDom(
+ this._uiContext,
+ this._divHeader,
+ this._settings.showSummary,
+ this._settings.showControls,
+ function(elmt, evt, target) { self._openSortPopup(elmt, -1); },
+ function(elmt, evt, target) { self._toggleGroup(); },
+ function(pageIndex) { self._gotoPage(pageIndex); }
+ );
+ }
+ if (this._settings.showFooter) {
+ this._footerDom = Exhibit.OrderedViewFrame.createFooterDom(
+ this._uiContext,
+ this._divFooter,
+ function(elmt, evt, target) { self._setShowAll(true); },
+ function(elmt, evt, target) { self._setShowAll(false); },
+ function(pageIndex) { self._gotoPage(pageIndex); }
+ );
+ }
+};
+
+Exhibit.OrderedViewFrame.prototype.reconstruct = function() {
+ var self = this;
+ var collection = this._uiContext.getCollection();
+ var database = this._uiContext.getDatabase();
+
+ var originalSize = collection.countAllItems();
+ var currentSize = collection.countRestrictedItems();
+
+ var hasSomeGrouping = false;
+ if (currentSize > 0) {
+ var currentSet = collection.getRestrictedItems();
+
+ hasSomeGrouping = this._internalReconstruct(currentSet);
+
+ /*
+ * Build sort controls
+ */
+ var orderElmts = [];
+ var buildOrderElmt = function(order, index) {
+ var property = database.getProperty(order.property);
+ var label = property != null ?
+ (order.forward ? property.getPluralLabel() : property.getReversePluralLabel()) :
+ (order.forward ? order.property : "reverse of " + order.property);
+
+ orderElmts.push(Exhibit.UI.makeActionLink(
+ label,
+ function(elmt, evt, target) {
+ self._openSortPopup(elmt, index);
+ }
+ ));
+ };
+ var orders = this._getOrders();
+ for (var i = 0; i < orders.length; i++) {
+ buildOrderElmt(orders[i], i);
+ }
+
+ if (this._settings.showHeader && this._settings.showControls) {
+ this._headerDom.setOrders(orderElmts);
+ this._headerDom.enableThenByAction(orderElmts.length < this._getPossibleOrders().length);
+ }
+ }
+
+ if (this._settings.showHeader && this._settings.showControls) {
+ this._headerDom.groupOptionWidget.setChecked(this._settings.grouped);
+ }
+ if (this._settings.showFooter) {
+ this._footerDom.setCounts(
+ currentSize,
+ this._settings.abbreviatedCount,
+ this._settings.showAll,
+ !(hasSomeGrouping && this._grouped) && !this._settings.paginate
+ );
+ }
+};
+
+Exhibit.OrderedViewFrame.prototype._internalReconstruct = function(allItems) {
+ var self = this;
+ var settings = this._settings;
+ var database = this._uiContext.getDatabase();
+ var orders = this._getOrders();
+ var itemIndex = 0;
+
+ var hasSomeGrouping = false;
+ var createItem = function(itemID) {
+ if ((itemIndex >= fromIndex && itemIndex < toIndex) || (hasSomeGrouping && settings.grouped)) {
+ self.onNewItem(itemID, itemIndex);
+ }
+ itemIndex++;
+ };
+ var createGroup = function(label, valueType, index) {
+ if ((itemIndex >= fromIndex && itemIndex < toIndex) || (hasSomeGrouping && settings.grouped)) {
+ self.onNewGroup(label, valueType, index);
+ }
+ };
+
+ var processLevel = function(items, index) {
+ var order = orders[index];
+ var values = order.forward ?
+ database.getObjectsUnion(items, order.property) :
+ database.getSubjectsUnion(items, order.property);
+
+ var valueType = "text";
+ if (order.forward) {
+ var property = database.getProperty(order.property);
+ valueType = property != null ? property.getValueType() : "text";
+ } else {
+ valueType = "item";
+ }
+
+ var keys = (valueType == "item" || valueType == "text") ?
+ processNonNumericLevel(items, index, values, valueType) :
+ processNumericLevel(items, index, values, valueType);
+
+ var grouped = false;
+ for (var k = 0; k < keys.length; k++) {
+ if (keys[k].items.size() > 1) {
+ grouped = true;
+ }
+ }
+ //grouped = grouped && keys.length > 1;
+ if (grouped) {
+ hasSomeGrouping = true;
+ }
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+ if (key.items.size() > 0) {
+ if (grouped && settings.grouped) {
+ createGroup(key.display, valueType, index);
+ }
+
+ items.removeSet(key.items);
+ if (key.items.size() > 1 && index < orders.length - 1) {
+ processLevel(key.items, index+1);
+ } else {
+ key.items.visit(createItem);
+ }
+ }
+ }
+
+ if (items.size() > 0) {
+ if (grouped && settings.grouped) {
+ createGroup(Exhibit.l10n.missingSortKey, valueType, index);
+ }
+
+ if (items.size() > 1 && index < orders.length - 1) {
+ processLevel(items, index+1);
+ } else {
+ items.visit(createItem);
+ }
+ }
+ };
+
+ var processNonNumericLevel = function(items, index, values, valueType) {
+ var keys = [];
+ var compareKeys;
+ var retrieveItems;
+ var order = orders[index];
+
+ if (valueType == "item") {
+ values.visit(function(itemID) {
+ var label = database.getObject(itemID, "label");
+ label = label != null ? label : itemID;
+ keys.push({ itemID: itemID, display: label });
+ });
+
+ compareKeys = function(key1, key2) {
+ var c = key1.display.localeCompare(key2.display);
+ return c != 0 ? c : key1.itemID.localeCompare(key2.itemID);
+ };
+
+ retrieveItems = order.forward ? function(key) {
+ return database.getSubjects(key.itemID, order.property, null, items);
+ } : function(key) {
+ return database.getObjects(key.itemID, order.property, null, items);
+ };
+ } else { //text
+ values.visit(function(value) {
+ keys.push({ display: value });
+ });
+
+ compareKeys = function(key1, key2) {
+ return key1.display.localeCompare(key2.display);
+ };
+ retrieveItems = order.forward ? function(key) {
+ return database.getSubjects(key.display, order.property, null, items);
+ } : function(key) {
+ return database.getObjects(key.display, order.property, null, items);
+ };
+ }
+
+ keys.sort(function(key1, key2) {
+ return (order.ascending ? 1 : -1) * compareKeys(key1, key2);
+ });
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+ key.items = retrieveItems(key);
+ if (!settings.showDuplicates) {
+ items.removeSet(key.items);
+ }
+ }
+
+ return keys;
+ };
+
+ var processNumericLevel = function(items, index, values, valueType) {
+ var keys = [];
+ var keyMap = {};
+ var order = orders[index];
+
+ var valueParser;
+ if (valueType == "number") {
+ valueParser = function(value) {
+ if (typeof value == "number") {
+ return value;
+ } else {
+ try {
+ return parseFloat(value);
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ } else { //date
+ valueParser = function(value) {
+ if (value instanceof Date) {
+ return value.getTime();
+ } else {
+ try {
+ return SimileAjax.DateTime.parseIso8601DateTime(value.toString()).getTime();
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ }
+
+ values.visit(function(value) {
+ var sortkey = valueParser(value);
+ if (sortkey != null) {
+ var key = keyMap[sortkey];
+ if (!key) {
+ key = { sortkey: sortkey, display: value, values: [], items: new Exhibit.Set() };
+ keyMap[sortkey] = key;
+ keys.push(key);
+ }
+ key.values.push(value);
+ }
+ });
+
+ keys.sort(function(key1, key2) {
+ return (order.ascending ? 1 : -1) * (key1.sortkey - key2.sortkey);
+ });
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+ var values = key.values;
+ for (var v = 0; v < values.length; v++) {
+ if (order.forward) {
+ database.getSubjects(values[v], order.property, key.items, items);
+ } else {
+ database.getObjects(values[v], order.property, key.items, items);
+ }
+ }
+
+ if (!settings.showDuplicates) {
+ items.removeSet(key.items);
+ }
+ }
+
+ return keys;
+ };
+
+ var totalCount = allItems.size();
+ var pageCount = Math.ceil(totalCount / settings.pageSize);
+ var fromIndex = 0;
+ var toIndex = settings.showAll ? totalCount : Math.min(totalCount, settings.abbreviatedCount);
+
+ if (!settings.grouped && settings.paginate && (pageCount > 1 || (pageCount > 0 && settings.alwaysShowPagingControls))) {
+ fromIndex = settings.page * settings.pageSize;
+ toIndex = Math.min(fromIndex + settings.pageSize, totalCount);
+
+ if (settings.showHeader && (settings.pagingControlLocations == "top" || settings.pagingControlLocations == "topbottom")) {
+ this._headerDom.renderPageLinks(
+ settings.page,
+ pageCount,
+ settings.pageWindow
+ );
+ }
+ if (settings.showFooter && (settings.pagingControlLocations == "bottom" || settings.pagingControlLocations == "topbottom")) {
+ this._footerDom.renderPageLinks(
+ settings.page,
+ pageCount,
+ settings.pageWindow
+ );
+ }
+ } else {
+ if (settings.showHeader) {
+ this._headerDom.hidePageLinks();
+ }
+ if (settings.showFooter) {
+ this._footerDom.hidePageLinks();
+ }
+ }
+ processLevel(allItems, 0);
+
+ return hasSomeGrouping;
+};
+
+Exhibit.OrderedViewFrame.prototype._getOrders = function() {
+ return this._orders || [ this._getPossibleOrders()[0] ];
+};
+
+Exhibit.OrderedViewFrame.prototype._getPossibleOrders = function() {
+ var possibleOrders = null;
+ if (this._possibleOrders == null) {
+ possibleOrders = this._uiContext.getDatabase().getAllProperties();
+ for (var i = 0, p; p = possibleOrders[i]; i++ ) {
+ possibleOrders[i] = { ascending:true, forward:true, property:p };
+ }
+ } else {
+ possibleOrders = [].concat(this._possibleOrders);
+ }
+
+ if (possibleOrders.length == 0) {
+ possibleOrders.push({
+ property: "label",
+ forward: true,
+ ascending: true
+ });
+ }
+ return possibleOrders;
+};
+
+Exhibit.OrderedViewFrame.prototype._openSortPopup = function(elmt, index) {
+ var self = this;
+ var database = this._uiContext.getDatabase();
+
+ var popupDom = Exhibit.UI.createPopupMenuDom(elmt);
+
+ /*
+ * Ascending/descending/remove options for the current order
+ */
+ var configuredOrders = this._getOrders();
+ if (index >= 0) {
+ var order = configuredOrders[index];
+ var property = database.getProperty(order.property);
+ var propertyLabel = order.forward ? property.getPluralLabel() : property.getReversePluralLabel();
+ var valueType = order.forward ? property.getValueType() : "item";
+ var sortLabels = Exhibit.Database.l10n.sortLabels[valueType];
+ sortLabels = (sortLabels != null) ? sortLabels :
+ Exhibit.Database.l10n.sortLabels["text"];
+
+ popupDom.appendMenuItem(
+ sortLabels.ascending,
+ Exhibit.urlPrefix +
+ (order.ascending ? "images/option-check.png" : "images/option.png"),
+ order.ascending ?
+ function() {} :
+ function() {
+ self._reSort(
+ index,
+ order.property,
+ order.forward,
+ true,
+ false
+ );
+ }
+ );
+ popupDom.appendMenuItem(
+ sortLabels.descending,
+ Exhibit.urlPrefix +
+ (order.ascending ? "images/option.png" : "images/option-check.png"),
+ order.ascending ?
+ function() {
+ self._reSort(
+ index,
+ order.property,
+ order.forward,
+ false,
+ false
+ );
+ } :
+ function() {}
+ );
+ if (configuredOrders.length > 1) {
+ popupDom.appendSeparator();
+ popupDom.appendMenuItem(
+ Exhibit.OrderedViewFrame.l10n.removeOrderLabel,
+ null,
+ function() {self._removeOrder(index);}
+ );
+ }
+ }
+
+ /*
+ * The remaining possible orders
+ */
+ var orders = [];
+ var possibleOrders = this._getPossibleOrders();
+ for (i = 0; i < possibleOrders.length; i++) {
+ var possibleOrder = possibleOrders[i];
+ var skip = false;
+ for (var j = (index < 0) ? configuredOrders.length - 1 : index; j >= 0; j--) {
+ var existingOrder = configuredOrders[j];
+ if (existingOrder.property == possibleOrder.property &&
+ existingOrder.forward == possibleOrder.forward) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (!skip) {
+ var property = database.getProperty(possibleOrder.property);
+ orders.push({
+ property: possibleOrder.property,
+ forward: possibleOrder.forward,
+ ascending: possibleOrder.ascending,
+ label: possibleOrder.forward ?
+ property.getPluralLabel() :
+ property.getReversePluralLabel()
+ });
+ }
+ }
+
+ if (orders.length > 0) {
+ if (index >= 0) {
+ popupDom.appendSeparator();
+ }
+
+ orders.sort(function(order1, order2) {
+ return order1.label.localeCompare(order2.label);
+ });
+
+ var appendOrder = function(order) {
+ popupDom.appendMenuItem(
+ order.label,
+ null,
+ function() {
+ self._reSort(
+ index,
+ order.property,
+ order.forward,
+ order.ascending,
+ true
+ );
+ }
+ );
+ }
+
+ for (var i = 0; i < orders.length; i++) {
+ appendOrder(orders[i]);
+ }
+ }
+ popupDom.open();
+};
+
+Exhibit.OrderedViewFrame.prototype._reSort = function(index, propertyID, forward, ascending, slice) {
+ var oldOrders = this._getOrders();
+ index = (index < 0) ? oldOrders.length : index;
+
+ var newOrders = oldOrders.slice(0, index);
+ newOrders.push({ property: propertyID, forward: forward, ascending: ascending });
+ if (!slice) {
+ newOrders = newOrders.concat(oldOrders.slice(index+1));
+ }
+
+ var property = this._uiContext.getDatabase().getProperty(propertyID);
+ var propertyLabel = forward ? property.getPluralLabel() : property.getReversePluralLabel();
+ var valueType = forward ? property.getValueType() : "item";
+ var sortLabels = Exhibit.Database.l10n.sortLabels[valueType];
+ sortLabels = (sortLabels != null) ? sortLabels :
+ Exhibit.Database.l10n.sortLabels["text"];
+
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ self._orders = newOrders;
+ self.parentReconstruct();
+ },
+ function() {
+ self._orders = oldOrders;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n.formatSortActionTitle(
+ propertyLabel, ascending ? sortLabels.ascending : sortLabels.descending)
+ );
+};
+
+Exhibit.OrderedViewFrame.prototype._removeOrder = function(index) {
+ var oldOrders = this._getOrders();
+ var newOrders = oldOrders.slice(0, index).concat(oldOrders.slice(index + 1));
+
+ var order = oldOrders[index];
+ var property = this._uiContext.getDatabase().getProperty(order.property);
+ var propertyLabel = order.forward ? property.getPluralLabel() : property.getReversePluralLabel();
+ var valueType = order.forward ? property.getValueType() : "item";
+ var sortLabels = Exhibit.Database.l10n.sortLabels[valueType];
+ sortLabels = (sortLabels != null) ? sortLabels :
+ Exhibit.Database.l10n.sortLabels["text"];
+
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ self._orders = newOrders;
+ self.parentReconstruct();
+ },
+ function() {
+ self._orders = oldOrders;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n.formatRemoveOrderActionTitle(
+ propertyLabel, order.ascending ? sortLabels.ascending : sortLabels.descending)
+ );
+};
+
+Exhibit.OrderedViewFrame.prototype._setShowAll = function(showAll) {
+ var self = this;
+ var settings = this._settings;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.showAll = showAll;
+ self.parentReconstruct();
+ },
+ function() {
+ settings.showAll = !showAll;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n[
+ showAll ? "showAllActionTitle" : "dontShowAllActionTitle"]
+ );
+};
+
+Exhibit.OrderedViewFrame.prototype._toggleGroup = function() {
+ var settings = this._settings;
+ var oldGrouped = settings.grouped;
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.grouped = !oldGrouped;
+ self.parentReconstruct();
+ },
+ function() {
+ settings.grouped = oldGrouped;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n[
+ oldGrouped ? "ungroupAsSortedActionTitle" : "groupAsSortedActionTitle"]
+ );
+};
+
+Exhibit.OrderedViewFrame.prototype._toggleShowDuplicates = function() {
+ var settings = this._settings;
+ var oldShowDuplicates = settings.showDuplicates;
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.showDuplicates = !oldShowDuplicates;
+ self.parentReconstruct();
+ },
+ function() {
+ settings.showDuplicates = oldShowDuplicates;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n[
+ oldShowDuplicates ? "hideDuplicatesActionTitle" : "showDuplicatesActionTitle"]
+ );
+};
+
+Exhibit.OrderedViewFrame.prototype._gotoPage = function(pageIndex) {
+ var settings = this._settings;
+ var oldPageIndex = settings.page;
+
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.page = pageIndex;
+ self.parentReconstruct();
+ },
+ function() {
+ settings.page = oldPageIndex;
+ self.parentReconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(pageIndex)
+ );
+};
+
+Exhibit.OrderedViewFrame.headerTemplate =
+ "<div id='collectionSummaryDiv' style='display: none;'></div>" +
+ "<div class='exhibit-collectionView-header-sortControls' style='display: none;' id='controlsDiv'>" +
+ "%0" + // sorting controls template
+ "<span class='exhibit-collectionView-header-groupControl'> \u2022 " +
+ "<a id='groupOption' class='exhibit-action'></a>" +
+ "</span>" +
+ "</div>";
+
+Exhibit.OrderedViewFrame.createHeaderDom = function(
+ uiContext,
+ headerDiv,
+ showSummary,
+ showControls,
+ onThenSortBy,
+ onGroupToggle,
+ gotoPage
+) {
+ var l10n = Exhibit.OrderedViewFrame.l10n;
+ var template = String.substitute(
+ Exhibit.OrderedViewFrame.headerTemplate +
+ "<" + l10n.pagingControlContainerElement + " class='exhibit-collectionView-pagingControls' style='display: none;' id='topPagingDiv'></" + l10n.pagingControlContainerElement + ">",
+ [ l10n.sortingControlsTemplate ]);
+
+ var dom = SimileAjax.DOM.createDOMFromString(headerDiv, template, {});
+ headerDiv.className = "exhibit-collectionView-header";
+
+ if (showSummary) {
+ dom.collectionSummaryDiv.style.display = "block";
+ dom.collectionSummaryWidget = Exhibit.CollectionSummaryWidget.create(
+ {},
+ dom.collectionSummaryDiv,
+ uiContext
+ );
+ }
+ if (showControls) {
+ dom.controlsDiv.style.display = "block";
+ dom.groupOptionWidget = Exhibit.OptionWidget.create(
+ { label: l10n.groupedAsSortedOptionLabel,
+ onToggle: onGroupToggle
+ },
+ dom.groupOption,
+ uiContext
+ );
+
+ SimileAjax.WindowManager.registerEvent(dom.thenSortByAction, "click", onThenSortBy);
+ dom.enableThenByAction = function(enabled) {
+ Exhibit.UI.enableActionLink(dom.thenSortByAction, enabled);
+ };
+ dom.setOrders = function(orderElmts) {
+ dom.ordersSpan.innerHTML = "";
+
+ var addDelimiter = Exhibit.Formatter.createListDelimiter(dom.ordersSpan, orderElmts.length, uiContext);
+ for (var i = 0; i < orderElmts.length; i++) {
+ addDelimiter();
+ dom.ordersSpan.appendChild(orderElmts[i]);
+ }
+ addDelimiter();
+ };
+ }
+ dom.renderPageLinks = function(page, totalPage, pageWindow) {
+ Exhibit.OrderedViewFrame.renderPageLinks(dom.topPagingDiv, page, totalPage, pageWindow, gotoPage);
+ dom.topPagingDiv.style.display = "block";
+ };
+ dom.hidePageLinks = function() {
+ dom.topPagingDiv.style.display = "none";
+ };
+
+ dom.dispose = function() {
+ if ("collectionSummaryWidget" in dom) {
+ dom.collectionSummaryWidget.dispose();
+ dom.collectionSummaryWidget = null;
+ }
+
+ dom.groupOptionWidget.dispose();
+ dom.groupOptionWidget = null;
+ }
+
+ return dom;
+};
+
+Exhibit.OrderedViewFrame.footerTemplate =
+ "<div id='showAllSpan'></div>";
+
+Exhibit.OrderedViewFrame.createFooterDom = function(
+ uiContext,
+ footerDiv,
+ onShowAll,
+ onDontShowAll,
+ gotoPage
+) {
+ var l10n = Exhibit.OrderedViewFrame.l10n;
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ footerDiv,
+ Exhibit.OrderedViewFrame.footerTemplate +
+ "<" + l10n.pagingControlContainerElement + " class='exhibit-collectionView-pagingControls' style='display: none;' id='bottomPagingDiv'></" + l10n.pagingControlContainerElement + ">",
+ {}
+ );
+ footerDiv.className = "exhibit-collectionView-footer";
+
+ dom.setCounts = function(count, limitCount, showAll, canToggle) {
+ dom.showAllSpan.innerHTML = "";
+ if (canToggle && count > limitCount) {
+ dom.showAllSpan.style.display = "block";
+ if (showAll) {
+ dom.showAllSpan.appendChild(
+ Exhibit.UI.makeActionLink(
+ l10n.formatDontShowAll(limitCount), onDontShowAll));
+ } else {
+ dom.showAllSpan.appendChild(
+ Exhibit.UI.makeActionLink(
+ l10n.formatShowAll(count), onShowAll));
+ }
+ }
+ };
+ dom.renderPageLinks = function(page, totalPage, pageWindow) {
+ Exhibit.OrderedViewFrame.renderPageLinks(dom.bottomPagingDiv, page, totalPage, pageWindow, gotoPage);
+ dom.bottomPagingDiv.style.display = "block";
+ dom.showAllSpan.style.display = "none";
+ };
+ dom.hidePageLinks = function() {
+ dom.bottomPagingDiv.style.display = "none";
+ };
+ dom.dispose = function() {};
+
+ return dom;
+};
+
+Exhibit.OrderedViewFrame.renderPageLinks = function(parentElmt, page, pageCount, pageWindow, gotoPage) {
+ var l10n = Exhibit.OrderedViewFrame.l10n;
+
+ parentElmt.className = "exhibit-collectionView-pagingControls";
+ parentElmt.innerHTML = "";
+
+ var self = this;
+ var renderPageLink = function(label, index) {
+ var elmt = document.createElement(l10n.pagingControlElement);
+ elmt.className = "exhibit-collectionView-pagingControls-page";
+ parentElmt.appendChild(elmt);
+
+ var a = document.createElement("a");
+ a.innerHTML = label;
+ a.href = "javascript:{}";
+ a.title = l10n.makePagingLinkTooltip(index);
+ elmt.appendChild(a);
+
+ var handler = function(elmt, evt, target) {
+ gotoPage(index);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ SimileAjax.WindowManager.registerEvent(a, "click", handler);
+ };
+ var renderPageNumber = function(index) {
+ if (index == page) {
+ var elmt = document.createElement(l10n.pagingControlElement);
+ elmt.className = "exhibit-collectionView-pagingControls-currentPage";
+ elmt.innerHTML = (index + 1);
+
+ parentElmt.appendChild(elmt);
+ } else {
+ renderPageLink(index + 1, index);
+ }
+ };
+ var renderHTML = function(html) {
+ var elmt = document.createElement(l10n.pagingControlElement);
+ elmt.innerHTML = html;
+
+ parentElmt.appendChild(elmt);
+ };
+
+ if (page > 0) {
+ renderPageLink(l10n.previousPage, page - 1);
+ if (l10n.pageSeparator.length > 0) {
+ renderHTML(" ");
+ }
+ }
+
+ var pageWindowStart = 0;
+ var pageWindowEnd = pageCount - 1;
+
+ if (page - pageWindow > 1) {
+ renderPageNumber(0);
+ renderHTML(l10n.pageWindowEllipses);
+
+ pageWindowStart = page - pageWindow;
+ }
+ if (page + pageWindow < pageCount - 2) {
+ pageWindowEnd = page + pageWindow;
+ }
+
+ for (var i = pageWindowStart; i <= pageWindowEnd; i++) {
+ if (i > pageWindowStart && l10n.pageSeparator.length > 0) {
+ renderHTML(l10n.pageSeparator);
+ }
+ renderPageNumber(i);
+ }
+
+ if (pageWindowEnd < pageCount - 1) {
+ renderHTML(l10n.pageWindowEllipses);
+ renderPageNumber(pageCount - 1);
+ }
+
+ if (page < pageCount - 1) {
+ if (l10n.pageSeparator.length > 0) {
+ renderHTML(" ");
+ }
+ renderPageLink(l10n.nextPage, page + 1);
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tabular-view.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tabular-view.js
new file mode 100644
index 00000000..5aa1e3ed
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tabular-view.js
@@ -0,0 +1,640 @@
+/*==================================================
+ * Exhibit.TabularView
+ *==================================================
+ */
+
+Exhibit.TabularView = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._settings = { rowStyler: null, tableStyler: null };
+ this._columns = [];
+ this._rowTemplate = null;
+
+ var view = this;
+ this._listener = {
+ onItemsChanged: function() {
+ view._settings.page = 0;
+ view._reconstruct();
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+};
+
+Exhibit.TabularView._settingSpecs = {
+ "sortAscending": { type: "boolean", defaultValue: true },
+ "sortColumn": { type: "int", defaultValue: 0 },
+ "showSummary": { type: "boolean", defaultValue: true },
+ "showToolbox": { type: "boolean", defaultValue: true },
+ "border": { type: "int", defaultValue: 1 },
+ "cellPadding": { type: "int", defaultValue: 5 },
+ "cellSpacing": { type: "int", defaultValue: 3 },
+ "paginate": { type: "boolean", defaultValue: false },
+ "pageSize": { type: "int", defaultValue: 20 },
+ "pageWindow": { type: "int", defaultValue: 2 },
+ "page": { type: "int", defaultValue: 0 },
+ "alwaysShowPagingControls": { type: "boolean", defaultValue: false },
+ "pagingControlLocations": { type: "enum", defaultValue: "topbottom", choices: [ "top", "bottom", "topbottom" ] }
+};
+
+Exhibit.TabularView.create = function(configuration, containerElmt, uiContext) {
+ var view = new Exhibit.TabularView(
+ containerElmt,
+ Exhibit.UIContext.create(configuration, uiContext)
+ );
+ Exhibit.TabularView._configure(view, configuration);
+
+ view._internalValidate();
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.TabularView.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+
+ uiContext = Exhibit.UIContext.createFromDOM(configElmt, uiContext);
+
+ var view = new Exhibit.TabularView(
+ containerElmt != null ? containerElmt : configElmt,
+ uiContext
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.TabularView._settingSpecs, view._settings);
+
+ try {
+ var expressions = [];
+ var labels = Exhibit.getAttribute(configElmt, "columnLabels", ",") || [];
+
+ var s = Exhibit.getAttribute(configElmt, "columns");
+ if (s != null && s.length > 0) {
+ expressions = Exhibit.ExpressionParser.parseSeveral(s);
+ }
+
+ for (var i = 0; i < expressions.length; i++) {
+ var expression = expressions[i];
+ view._columns.push({
+ expression: expression,
+ uiContext: Exhibit.UIContext.create({}, view._uiContext, true),
+ styler: null,
+ label: i < labels.length ? labels[i] : null,
+ format: "list"
+ });
+ }
+
+ var formats = Exhibit.getAttribute(configElmt, "columnFormats");
+ if (formats != null && formats.length > 0) {
+ var index = 0;
+ var startPosition = 0;
+ while (index < view._columns.length && startPosition < formats.length) {
+ var column = view._columns[index];
+ var o = {};
+
+ column.format = Exhibit.FormatParser.parseSeveral(column.uiContext, formats, startPosition, o);
+
+ startPosition = o.index;
+ while (startPosition < formats.length && " \t\r\n".indexOf(formats.charAt(startPosition)) >= 0) {
+ startPosition++;
+ }
+ if (startPosition < formats.length && formats.charAt(startPosition) == ",") {
+ startPosition++;
+ }
+
+ index++;
+ }
+ }
+
+ var tables = configElmt.getElementsByTagName("table");
+ if (tables.length > 0 && tables[0].rows.length > 0) {
+ view._rowTemplate = Exhibit.Lens.compileTemplate(tables[0].rows[0], false, uiContext);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "TabularView: Error processing configuration of tabular view");
+ }
+
+ var s = Exhibit.getAttribute(configElmt, "rowStyler");
+ if (s != null && s.length > 0) {
+ var f = eval(s);
+ if (typeof f == "function") {
+ view._settings.rowStyler = f;
+ }
+ }
+ s = Exhibit.getAttribute(configElmt, "tableStyler");
+ if (s != null && s.length > 0) {
+ f = eval(s);
+ if (typeof f == "function") {
+ view._settings.tableStyler = f;
+ }
+ }
+
+ Exhibit.TabularView._configure(view, configuration);
+ view._internalValidate();
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.TabularView._configure = function(view, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.TabularView._settingSpecs, view._settings);
+
+ if ("columns" in configuration) {
+ var columns = configuration.columns;
+ for (var i = 0; i < columns.length; i++) {
+ var column = columns[i];
+ var expr;
+ var styler = null;
+ var label = null;
+ var format = null;
+
+ if (typeof column == "string") {
+ expr = column;
+ } else {
+ expr = column.expression;
+ styler = column.styler;
+ label = column.label;
+ format = column.format;
+ }
+
+ var expression = Exhibit.ExpressionParser.parse(expr);
+ if (expression.isPath()) {
+ var path = expression.getPath();
+ if (format != null && format.length > 0) {
+ format = Exhibit.FormatParser.parse(view._uiContext, format, 0);
+ } else {
+ format = "list";
+ }
+
+ view._columns.push({
+ expression: expression,
+ styler: styler,
+ label: label,
+ format: format,
+ uiContext: view._uiContext
+ });
+ }
+ }
+ }
+
+ if ("rowStyler" in configuration) {
+ view._settings.rowStyler = configuration.rowStyler;
+ }
+ if ("tableStyler" in configuration) {
+ view._settings.tableStyler = configuration.tableStyler;
+ }
+};
+
+Exhibit.TabularView.prototype._internalValidate = function() {
+ if (this._columns.length == 0) {
+ var database = this._uiContext.getDatabase();
+ var propertyIDs = database.getAllProperties();
+ for (var i = 0; i < propertyIDs.length; i++) {
+ var propertyID = propertyIDs[i];
+ if (propertyID != "uri") {
+ this._columns.push(
+ { expression: Exhibit.ExpressionParser.parse("." + propertyID),
+ styler: null,
+ label: database.getProperty(propertyID).getLabel(),
+ format: "list"
+ }
+ );
+ }
+ }
+ }
+ this._settings.sortColumn =
+ Math.max(0, Math.min(this._settings.sortColumn, this._columns.length - 1));
+};
+
+Exhibit.TabularView.prototype.dispose = function() {
+ this._uiContext.getCollection().removeListener(this._listener);
+
+ if (this._toolboxWidget) {
+ this._toolboxWidget.dispose();
+ this._toolboxWidget = null;
+ }
+
+ this._collectionSummaryWidget.dispose();
+ this._collectionSummaryWidget = null;
+
+ this._uiContext.dispose();
+ this._uiContext = null;
+
+ this._div.innerHTML = "";
+
+ this._dom = null;
+ this._div = null;
+};
+
+Exhibit.TabularView.prototype._initializeUI = function() {
+ var self = this;
+
+ this._div.innerHTML = "";
+ this._dom = Exhibit.TabularView.createDom(this._div);
+ this._collectionSummaryWidget = Exhibit.CollectionSummaryWidget.create(
+ {},
+ this._dom.collectionSummaryDiv,
+ this._uiContext
+ );
+ if (this._settings.showToolbox) {
+ this._toolboxWidget = Exhibit.ToolboxWidget.createFromDOM(this._div, this._div, this._uiContext);
+ this._toolboxWidget.getGeneratedHTML = function() {
+ return self._dom.bodyDiv.innerHTML;
+ };
+ }
+
+ if (!this._settings.showSummary) {
+ this._dom.collectionSummaryDiv.style.display = "none";
+ }
+
+ this._reconstruct();
+};
+
+Exhibit.TabularView.prototype._reconstruct = function() {
+ var self = this;
+ var collection = this._uiContext.getCollection();
+ var database = this._uiContext.getDatabase();
+
+ var bodyDiv = this._dom.bodyDiv;
+ bodyDiv.innerHTML = "";
+
+ /*
+ * Get the current collection and check if it's empty
+ */
+ var items = [];
+ var originalSize = collection.countAllItems();
+ if (originalSize > 0) {
+ var currentSet = collection.getRestrictedItems();
+ currentSet.visit(function(itemID) { items.push({ id: itemID, sortKey: "" }); });
+ }
+
+ if (items.length > 0) {
+ /*
+ * Sort the items
+ */
+ var sortColumn = this._columns[this._settings.sortColumn];
+ items.sort(this._createSortFunction(items, sortColumn.expression, this._settings.sortAscending));
+
+ /*
+ * Style the table
+ */
+ var table = document.createElement("table");
+ table.className = "exhibit-tabularView-body";
+ if (this._settings.tableStyler != null) {
+ this._settings.tableStyler(table, database);
+ } else {
+ table.cellSpacing = this._settings.cellSpacing;
+ table.cellPadding = this._settings.cellPadding;
+ table.border = this._settings.border;
+ }
+
+ /*
+ * Create the column headers
+ */
+ var tr = table.insertRow(0);
+ var createColumnHeader = function(i) {
+ var column = self._columns[i];
+ if (column.label == null) {
+ column.label = self._getColumnLabel(column.expression);
+ }
+
+ var td = document.createElement("th");
+ Exhibit.TabularView.createColumnHeader(
+ exhibit, td, column.label, i == self._settings.sortColumn, self._settings.sortAscending,
+ function(elmt, evt, target) {
+ self._doSort(i);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ );
+
+ tr.appendChild(td);
+ };
+ for (var i = 0; i < this._columns.length; i++) {
+ createColumnHeader(i);
+ }
+
+ /*
+ * Create item rows
+ */
+ var renderItem;
+ if (this._rowTemplate != null) {
+ renderItem = function(i) {
+ var item = items[i];
+ var tr = Exhibit.Lens.constructFromLensTemplate(item.id, self._rowTemplate, table, self._uiContext);
+
+ if (self._settings.rowStyler != null) {
+ self._settings.rowStyler(item.id, database, tr, i);
+ }
+ }
+ } else {
+ renderItem = function(i) {
+ var item = items[i];
+ var tr = table.insertRow(table.rows.length);
+
+ for (var c = 0; c < self._columns.length; c++) {
+ var column = self._columns[c];
+ var td = tr.insertCell(c);
+
+ var results = column.expression.evaluate(
+ { "value" : item.id },
+ { "value" : "item" },
+ "value",
+ database
+ );
+
+ var valueType = column.format == "list" ? results.valueType : column.format;
+ column.uiContext.formatList(
+ results.values,
+ results.size,
+ valueType,
+ function(elmt) { td.appendChild(elmt); }
+ );
+
+ if (column.styler != null) {
+ column.styler(item.id, database, td);
+ }
+ }
+
+ if (self._settings.rowStyler != null) {
+ self._settings.rowStyler(item.id, database, tr, i);
+ }
+ }
+ }
+
+ var start, end;
+ var generatePagingControls = false;
+ if (this._settings.paginate) {
+ start = this._settings.page * this._settings.pageSize;
+ end = Math.min(start + this._settings.pageSize, items.length);
+
+ generatePagingControls = (items.length > this._settings.pageSize) || (items.length > 0 && this._settings.alwaysShowPagingControls);
+ } else {
+ start = 0;
+ end = items.length;
+ }
+ for (var i = start; i < end; i++) {
+ renderItem(i);
+ }
+
+ bodyDiv.appendChild(table);
+
+ if (generatePagingControls) {
+ if (this._settings.pagingControlLocations == "top" || this._settings.pagingControlLocations == "topbottom") {
+ this._renderPagingDiv(this._dom.topPagingDiv, items.length, this._settings.page);
+ this._dom.topPagingDiv.style.display = "block";
+ }
+
+ if (this._settings.pagingControlLocations == "bottom" || this._settings.pagingControlLocations == "topbottom") {
+ this._renderPagingDiv(this._dom.bottomPagingDiv, items.length, this._settings.page);
+ this._dom.bottomPagingDiv.style.display = "block";
+ }
+ } else {
+ this._dom.topPagingDiv.style.display = "none";
+ this._dom.bottomPagingDiv.style.display = "none";
+ }
+ }
+};
+
+Exhibit.TabularView.prototype._renderPagingDiv = function(parentElmt, itemCount, page) {
+ var pageCount = Math.ceil(itemCount / this._settings.pageSize);
+ var self = this;
+
+ Exhibit.OrderedViewFrame.renderPageLinks(
+ parentElmt,
+ page,
+ pageCount,
+ this._settings.pageWindow,
+ function(p) {
+ self._gotoPage(p);
+ }
+ );
+};
+
+Exhibit.TabularView.prototype._getColumnLabel = function(expression) {
+ var database = this._uiContext.getDatabase();
+ var path = expression.getPath();
+ var segment = path.getSegment(path.getSegmentCount() - 1);
+ var propertyID = segment.property;
+ var property = database.getProperty(propertyID);
+ if (property != null) {
+ return segment.forward ? property.getLabel() : property.getReverseLabel();
+ } else {
+ return propertyID;
+ }
+};
+
+Exhibit.TabularView.prototype._createSortFunction = function(items, expression, ascending) {
+ var database = this._uiContext.getDatabase();
+ var multiply = ascending ? 1 : -1;
+
+ var numericFunction = function(item1, item2) {
+ return multiply * (item1.sortKey - item2.sortKey);
+ };
+ var textFunction = function(item1, item2) {
+ return multiply * item1.sortKey.localeCompare(item2.sortKey);
+ };
+
+ var valueTypes = [];
+ var valueTypeMap = {};
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ var r = expression.evaluate(
+ { "value" : item.id },
+ { "value" : "item" },
+ "value",
+ database
+ );
+ r.values.visit(function(value) {
+ item.sortKey = value;
+ });
+
+ if (!(r.valueType in valueTypeMap)) {
+ valueTypeMap[r.valueType] = true;
+ valueTypes.push(r.valueType);
+ }
+ }
+
+ var coercedValueType = "text"
+ if (valueTypes.length == 1) {
+ coercedValueType = valueTypes[0];
+ } else {
+ coercedValueType = "text";
+ }
+
+ var coersion;
+ var sortingFunction;
+ if (coercedValueType == "number") {
+ sortingFunction = numericFunction;
+ coersion = function(v) {
+ if (v == null) {
+ return Number.NEGATIVE_INFINITY;
+ } else if (typeof v == "number") {
+ return v;
+ } else {
+ var n = parseFloat(v);
+ if (isNaN(n)) {
+ return Number.NEGATIVE_INFINITY;
+ } else {
+ return n;
+ }
+ }
+ }
+ } else if (coercedValueType == "date") {
+ sortingFunction = numericFunction;
+ coersion = function(v) {
+ if (v == null) {
+ return Number.NEGATIVE_INFINITY;
+ } else if (v instanceof Date) {
+ return v.getTime();
+ } else {
+ try {
+ return SimileAjax.DateTime.parseIso8601DateTime(v).getTime();
+ } catch (e) {
+ return Number.NEGATIVE_INFINITY;
+ }
+ }
+ }
+ } else if (coercedValueType == "boolean") {
+ sortingFunction = numericFunction;
+ coersion = function(v) {
+ if (v == null) {
+ return Number.NEGATIVE_INFINITY;
+ } else if (typeof v == "boolean") {
+ return v ? 1 : 0;
+ } else {
+ return v.toString().toLowerCase() == "true";
+ }
+ }
+ } else if (coercedValueType == "item") {
+ sortingFunction = textFunction;
+ coersion = function(v) {
+ if (v == null) {
+ return Exhibit.l10n.missingSortKey;
+ } else {
+ var label = database.getObject(v, "label");
+ return (label == null) ? v : label;
+ }
+ }
+ } else {
+ sortingFunction = textFunction;
+ coersion = function(v) {
+ if (v == null) {
+ return Exhibit.l10n.missingSortKey;
+ } else {
+ return v.toString();
+ }
+ }
+ }
+
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ item.sortKey = coersion(item.sortKey);
+ }
+
+ return sortingFunction;
+};
+
+Exhibit.TabularView.prototype._doSort = function(columnIndex) {
+ var oldSortColumn = this._settings.sortColumn;
+ var oldSortAscending = this._settings.sortAscending;
+ var newSortColumn = columnIndex;
+ var newSortAscending = oldSortColumn == newSortColumn ? !oldSortAscending : true;
+ var oldPage = this._settings.page;
+ var newPage = 0;
+ var settings = this._settings;
+
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.sortColumn = newSortColumn;
+ settings.sortAscending = newSortAscending;
+ settings.page = newPage;
+ self._reconstruct();
+ },
+ function() {
+ settings.sortColumn = oldSortColumn;
+ settings.sortAscending = oldSortAscending;
+ settings.page = oldPage;
+ self._reconstruct();
+ },
+ Exhibit.TabularView.l10n.makeSortActionTitle(this._columns[columnIndex].label, newSortAscending)
+ );
+};
+
+Exhibit.TabularView.prototype._gotoPage = function(page) {
+ var oldPage = this._settings.page;
+ var newPage = page;
+ var settings = this._settings;
+
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ settings.page = newPage;
+ self._reconstruct();
+ },
+ function() {
+ settings.page = oldPage;
+ self._reconstruct();
+ },
+ Exhibit.OrderedViewFrame.l10n.makePagingActionTitle(page)
+ );
+};
+
+Exhibit.TabularView._constructDefaultValueList = function(values, valueType, parentElmt, uiContext) {
+ uiContext.formatList(values, values.size(), valueType, function(elmt) {
+ parentElmt.appendChild(elmt);
+ });
+};
+
+Exhibit.TabularView.createDom = function(div) {
+ var l10n = Exhibit.TabularView.l10n;
+ var l10n2 = Exhibit.OrderedViewFrame.l10n;
+
+ var headerTemplate = {
+ elmt: div,
+ className: "exhibit-collectionView-header",
+ children: [
+ { tag: "div",
+ field: "collectionSummaryDiv"
+ },
+ { tag: l10n2.pagingControlContainerElement,
+ className: "exhibit-tabularView-pagingControls",
+ field: "topPagingDiv"
+ },
+ { tag: "div",
+ field: "bodyDiv"
+ },
+ { tag: l10n2.pagingControlContainerElement,
+ className: "exhibit-tabularView-pagingControls",
+ field: "bottomPagingDiv"
+ }
+ ]
+ };
+ return SimileAjax.DOM.createDOMFromTemplate(headerTemplate);
+};
+
+Exhibit.TabularView.createColumnHeader = function(
+ exhibit,
+ th,
+ label,
+ sort,
+ sortAscending,
+ sortFunction
+) {
+ var l10n = Exhibit.TabularView.l10n;
+ var template = {
+ elmt: th,
+ className: sort ?
+ "exhibit-tabularView-columnHeader-sorted" :
+ "exhibit-tabularView-columnHeader",
+ title: sort ? l10n.columnHeaderReSortTooltip : l10n.columnHeaderSortTooltip,
+ children: [ label ]
+ };
+ if (sort) {
+ template.children.push({
+ elmt: Exhibit.UI.createTranslucentImage(
+ sortAscending ? "images/up-arrow.png" : "images/down-arrow.png")
+ });
+ }
+ SimileAjax.WindowManager.registerEvent(th, "click", sortFunction, null);
+
+ var dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ return dom;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/thumbnail-view.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/thumbnail-view.js
new file mode 100644
index 00000000..a7115658
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/thumbnail-view.js
@@ -0,0 +1,327 @@
+/*==================================================
+ * Exhibit.ThumbnailView
+ *==================================================
+ */
+
+Exhibit.ThumbnailView = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ var view = this;
+ this._listener = {
+ onItemsChanged: function() {
+ view._orderedViewFrame._settings.page = 0;
+ view._reconstruct();
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+
+ this._orderedViewFrame = new Exhibit.OrderedViewFrame(uiContext);
+ this._orderedViewFrame.parentReconstruct = function() {
+ view._reconstruct();
+ };
+};
+
+Exhibit.ThumbnailView._settingSpecs = {
+ "showToolbox": { type: "boolean", defaultValue: true },
+ "columnCount": { type: "int", defaultValue: -1 }
+};
+
+Exhibit.ThumbnailView._itemContainerClass = SimileAjax.Platform.browser.isIE ?
+ "exhibit-thumbnailView-itemContainer-IE" :
+ "exhibit-thumbnailView-itemContainer";
+
+Exhibit.ThumbnailView.create = function(configuration, containerElmt, uiContext) {
+ var view = new Exhibit.ThumbnailView(
+ containerElmt,
+ Exhibit.UIContext.create(configuration, uiContext, true)
+ );
+
+ view._lensRegistry = Exhibit.UIContext.createLensRegistry(configuration, uiContext.getLensRegistry());
+
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.ThumbnailView._settingSpecs, view._settings);
+
+ view._orderedViewFrame.configure(configuration);
+
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.ThumbnailView.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var view = new Exhibit.ThumbnailView(
+ containerElmt != null ? containerElmt : configElmt,
+ Exhibit.UIContext.createFromDOM(configElmt, uiContext, true)
+ );
+
+ view._lensRegistry = Exhibit.UIContext.createLensRegistryFromDOM(configElmt, configuration, uiContext.getLensRegistry());
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ configElmt, Exhibit.ThumbnailView._settingSpecs, view._settings);
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.ThumbnailView._settingSpecs, view._settings);
+
+ view._orderedViewFrame.configureFromDOM(configElmt);
+ view._orderedViewFrame.configure(configuration);
+
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.ThumbnailView.prototype.dispose = function() {
+ this._uiContext.getCollection().removeListener(this._listener);
+
+ if (this._toolboxWidget) {
+ this._toolboxWidget.dispose();
+ this._toolboxWidget = null;
+ }
+
+ this._orderedViewFrame.dispose();
+ this._orderedViewFrame = null;
+
+ this._lensRegistry = null;
+ this._dom = null;
+
+ this._div.innerHTML = "";
+
+ this._div = null;
+ this._uiContext = null;
+};
+
+Exhibit.ThumbnailView.prototype._initializeUI = function() {
+ var self = this;
+
+ this._div.innerHTML = "";
+ var template = {
+ elmt: this._div,
+ children: [
+ { tag: "div",
+ field: "headerDiv"
+ },
+ { tag: "div",
+ className: "exhibit-collectionView-body",
+ field: "bodyDiv"
+ },
+ { tag: "div",
+ field: "footerDiv"
+ }
+ ]
+ };
+ this._dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ if (this._settings.showToolbox) {
+ this._toolboxWidget = Exhibit.ToolboxWidget.createFromDOM(this._div, this._div, this._uiContext);
+ this._toolboxWidget.getGeneratedHTML = function() {
+ return self._dom.bodyDiv.innerHTML;
+ };
+ }
+
+ this._orderedViewFrame._divHeader = this._dom.headerDiv;
+ this._orderedViewFrame._divFooter = this._dom.footerDiv;
+ this._orderedViewFrame._generatedContentElmtRetriever = function() {
+ return self._dom.bodyDiv;
+ };
+ this._orderedViewFrame.initializeUI();
+
+ this._reconstruct();
+};
+
+Exhibit.ThumbnailView.prototype._reconstruct = function() {
+ if (this._settings.columnCount < 2) {
+ this._reconstructWithFloats();
+ } else {
+ this._reconstructWithTable();
+ }
+};
+
+Exhibit.ThumbnailView.prototype._reconstructWithFloats = function() {
+ var view = this;
+ var state = {
+ div: this._dom.bodyDiv,
+ itemContainer: null,
+ groupDoms: [],
+ groupCounts: []
+ };
+
+ var closeGroups = function(groupLevel) {
+ for (var i = groupLevel; i < state.groupDoms.length; i++) {
+ state.groupDoms[i].countSpan.innerHTML = state.groupCounts[i];
+ }
+ state.groupDoms = state.groupDoms.slice(0, groupLevel);
+ state.groupCounts = state.groupCounts.slice(0, groupLevel);
+
+ if (groupLevel > 0) {
+ state.div = state.groupDoms[groupLevel - 1].contentDiv;
+ } else {
+ state.div = view._dom.bodyDiv;
+ }
+ state.itemContainer = null;
+ }
+
+ this._orderedViewFrame.onNewGroup = function(groupSortKey, keyType, groupLevel) {
+ closeGroups(groupLevel);
+
+ var groupDom = Exhibit.ThumbnailView.constructGroup(
+ groupLevel,
+ groupSortKey
+ );
+
+ state.div.appendChild(groupDom.elmt);
+ state.div = groupDom.contentDiv;
+
+ state.groupDoms.push(groupDom);
+ state.groupCounts.push(0);
+ };
+
+ this._orderedViewFrame.onNewItem = function(itemID, index) {
+ //if (index > 10) return;
+
+ if (state.itemContainer == null) {
+ state.itemContainer = Exhibit.ThumbnailView.constructItemContainer();
+ state.div.appendChild(state.itemContainer);
+ }
+
+ for (var i = 0; i < state.groupCounts.length; i++) {
+ state.groupCounts[i]++;
+ }
+
+ var itemLensDiv = document.createElement("div");
+ itemLensDiv.className = Exhibit.ThumbnailView._itemContainerClass;
+
+ var itemLens = view._lensRegistry.createLens(itemID, itemLensDiv, view._uiContext);
+ state.itemContainer.appendChild(itemLensDiv);
+ };
+
+ this._div.style.display = "none";
+
+ this._dom.bodyDiv.innerHTML = "";
+ this._orderedViewFrame.reconstruct();
+ closeGroups(0);
+
+ this._div.style.display = "block";
+};
+
+Exhibit.ThumbnailView.prototype._reconstructWithTable = function() {
+ var view = this;
+ var state = {
+ div: this._dom.bodyDiv,
+ groupDoms: [],
+ groupCounts: [],
+ table: null,
+ columnIndex: 0
+ };
+
+ var closeGroups = function(groupLevel) {
+ for (var i = groupLevel; i < state.groupDoms.length; i++) {
+ state.groupDoms[i].countSpan.innerHTML = state.groupCounts[i];
+ }
+ state.groupDoms = state.groupDoms.slice(0, groupLevel);
+ state.groupCounts = state.groupCounts.slice(0, groupLevel);
+
+ if (groupLevel > 0) {
+ state.div = state.groupDoms[groupLevel - 1].contentDiv;
+ } else {
+ state.div = view._dom.bodyDiv;
+ }
+ state.itemContainer = null;
+ state.table = null;
+ state.columnIndex = 0;
+ }
+
+ this._orderedViewFrame.onNewGroup = function(groupSortKey, keyType, groupLevel) {
+ closeGroups(groupLevel);
+
+ var groupDom = Exhibit.ThumbnailView.constructGroup(
+ groupLevel,
+ groupSortKey
+ );
+
+ state.div.appendChild(groupDom.elmt);
+ state.div = groupDom.contentDiv;
+
+ state.groupDoms.push(groupDom);
+ state.groupCounts.push(0);
+ };
+
+ this._orderedViewFrame.onNewItem = function(itemID, index) {
+ //if (index > 10) return;
+
+ if (state.columnIndex >= view._settings.columnCount) {
+ state.columnIndex = 0;
+ }
+
+ if (state.table == null) {
+ state.table = Exhibit.ThumbnailView.constructTableItemContainer();
+ state.div.appendChild(state.table);
+ }
+ if (state.columnIndex == 0) {
+ state.table.insertRow(state.table.rows.length);
+ }
+ var td = state.table.rows[state.table.rows.length - 1].insertCell(state.columnIndex++);
+
+ for (var i = 0; i < state.groupCounts.length; i++) {
+ state.groupCounts[i]++;
+ }
+
+ var itemLensDiv = document.createElement("div");
+ itemLensDiv.className = Exhibit.ThumbnailView._itemContainerClass;
+
+ var itemLens = view._lensRegistry.createLens(itemID, itemLensDiv, view._uiContext);
+ td.appendChild(itemLensDiv);
+ };
+
+ this._div.style.display = "none";
+
+ this._dom.bodyDiv.innerHTML = "";
+ this._orderedViewFrame.reconstruct();
+ closeGroups(0);
+
+ this._div.style.display = "block";
+};
+
+Exhibit.ThumbnailView.constructGroup = function(
+ groupLevel,
+ label
+) {
+ var l10n = Exhibit.ThumbnailView.l10n;
+ var template = {
+ tag: "div",
+ className: "exhibit-thumbnailView-group",
+ children: [
+ { tag: "h" + (groupLevel + 1),
+ children: [
+ label,
+ { tag: "span",
+ className: "exhibit-collectionView-group-count",
+ children: [
+ " (",
+ { tag: "span",
+ field: "countSpan"
+ },
+ ")"
+ ]
+ }
+ ],
+ field: "header"
+ },
+ { tag: "div",
+ className: "exhibit-collectionView-group-content",
+ field: "contentDiv"
+ }
+ ]
+ };
+ return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+
+Exhibit.ThumbnailView.constructItemContainer = function() {
+ var div = document.createElement("div");
+ div.className = "exhibit-thumbnailView-body";
+ return div;
+};
+
+Exhibit.ThumbnailView.constructTableItemContainer = function() {
+ var table = document.createElement("table");
+ table.className = "exhibit-thumbnailView-body";
+ return table;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tile-view.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tile-view.js
new file mode 100644
index 00000000..1908b471
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/tile-view.js
@@ -0,0 +1,214 @@
+/*==================================================
+ * Exhibit.TileView
+ *==================================================
+ */
+
+Exhibit.TileView = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+ this._settings = {};
+
+ var view = this;
+
+ this._listener = {
+ onItemsChanged: function() {
+ view._orderedViewFrame._settings.page = 0;
+ view._reconstruct();
+ }
+ };
+ uiContext.getCollection().addListener(this._listener);
+
+ this._orderedViewFrame = new Exhibit.OrderedViewFrame(uiContext);
+ this._orderedViewFrame.parentReconstruct = function() {
+ view._reconstruct();
+ };
+};
+
+Exhibit.TileView._settingSpecs = {
+ "showToolbox": { type: "boolean", defaultValue: true }
+};
+
+Exhibit.TileView.create = function(configuration, containerElmt, uiContext) {
+ var view = new Exhibit.TileView(
+ containerElmt,
+ Exhibit.UIContext.create(configuration, uiContext)
+ );
+
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.TileView._settingSpecs, view._settings);
+
+ view._orderedViewFrame.configure(configuration);
+
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.TileView.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var view = new Exhibit.TileView(
+ containerElmt != null ? containerElmt : configElmt,
+ Exhibit.UIContext.createFromDOM(configElmt, uiContext)
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(
+ configElmt, Exhibit.TileView._settingSpecs, view._settings);
+ Exhibit.SettingsUtilities.collectSettings(
+ configuration, Exhibit.TileView._settingSpecs, view._settings);
+
+ view._orderedViewFrame.configureFromDOM(configElmt);
+ view._orderedViewFrame.configure(configuration);
+
+ view._initializeUI();
+ return view;
+};
+
+Exhibit.TileView.prototype.dispose = function() {
+ this._uiContext.getCollection().removeListener(this._listener);
+
+ this._div.innerHTML = "";
+
+ if (this._toolboxWidget) {
+ this._toolboxWidget.dispose();
+ this._toolboxWidget = null;
+ }
+
+ this._orderedViewFrame.dispose();
+ this._orderedViewFrame = null;
+ this._dom = null;
+
+ this._div = null;
+ this._uiContext = null;
+};
+
+Exhibit.TileView.prototype._initializeUI = function() {
+ var self = this;
+
+ this._div.innerHTML = "";
+ var template = {
+ elmt: this._div,
+ children: [
+ { tag: "div",
+ field: "headerDiv"
+ },
+ { tag: "div",
+ className: "exhibit-collectionView-body",
+ field: "bodyDiv"
+ },
+ { tag: "div",
+ field: "footerDiv"
+ }
+ ]
+ };
+ this._dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ if (this._settings.showToolbox) {
+ this._toolboxWidget = Exhibit.ToolboxWidget.createFromDOM(this._div, this._div, this._uiContext);
+ this._toolboxWidget.getGeneratedHTML = function() {
+ return self._dom.bodyDiv.innerHTML;
+ };
+ }
+
+ this._orderedViewFrame._divHeader = this._dom.headerDiv;
+ this._orderedViewFrame._divFooter = this._dom.footerDiv;
+ this._orderedViewFrame._generatedContentElmtRetriever = function() {
+ return self._dom.bodyDiv;
+ };
+ this._orderedViewFrame.initializeUI();
+
+ this._reconstruct();
+};
+
+Exhibit.TileView.prototype._reconstruct = function() {
+ var view = this;
+ var state = {
+ div: this._dom.bodyDiv,
+ contents: null,
+ groupDoms: [],
+ groupCounts: []
+ };
+
+ var closeGroups = function(groupLevel) {
+ for (var i = groupLevel; i < state.groupDoms.length; i++) {
+ state.groupDoms[i].countSpan.innerHTML = state.groupCounts[i];
+ }
+ state.groupDoms = state.groupDoms.slice(0, groupLevel);
+ state.groupCounts = state.groupCounts.slice(0, groupLevel);
+
+ if (groupLevel > 0) {
+ state.div = state.groupDoms[groupLevel - 1].contentDiv;
+ } else {
+ state.div = view._dom.bodyDiv;
+ }
+ state.contents = null;
+ }
+
+ this._orderedViewFrame.onNewGroup = function(groupSortKey, keyType, groupLevel) {
+ closeGroups(groupLevel);
+
+ var groupDom = Exhibit.TileView.constructGroup(groupLevel, groupSortKey);
+
+ state.div.appendChild(groupDom.elmt);
+ state.div = groupDom.contentDiv;
+
+ state.groupDoms.push(groupDom);
+ state.groupCounts.push(0);
+ };
+
+ this._orderedViewFrame.onNewItem = function(itemID, index) {
+ if (state.contents == null) {
+ state.contents = Exhibit.TileView.constructList();
+ state.div.appendChild(state.contents);
+ }
+
+ for (var i = 0; i < state.groupCounts.length; i++) {
+ state.groupCounts[i]++;
+ }
+
+ var itemLensItem = document.createElement("li");
+ var itemLens = view._uiContext.getLensRegistry().createLens(itemID, itemLensItem, view._uiContext);
+ state.contents.appendChild( itemLensItem );
+ };
+
+ this._div.style.display = "none";
+
+ this._dom.bodyDiv.innerHTML = "";
+ this._orderedViewFrame.reconstruct();
+ closeGroups(0);
+
+ this._div.style.display = "block";
+};
+
+Exhibit.TileView.constructGroup = function(groupLevel, label) {
+ var template = {
+ tag: "div",
+ className: "exhibit-collectionView-group",
+ children: [
+ { tag: "h" + (groupLevel + 1),
+ children: [
+ label,
+ { tag: "span",
+ className: "exhibit-collectionView-group-count",
+ children: [
+ " (",
+ { tag: "span",
+ field: "countSpan"
+ },
+ ")"
+ ]
+ }
+ ],
+ field: "header"
+ },
+ { tag: "div",
+ className: "exhibit-collectionView-group-content",
+ field: "contentDiv"
+ }
+ ]
+ };
+ return SimileAjax.DOM.createDOMFromTemplate(template);
+};
+
+Exhibit.TileView.constructList = function() {
+ var div = document.createElement("ol");
+ div.className = "exhibit-tileView-body";
+ return div;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/view-panel.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/view-panel.js
new file mode 100644
index 00000000..87bad214
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/views/view-panel.js
@@ -0,0 +1,365 @@
+/*======================================================================
+ * Exhibit.ViewPanel
+ * http://simile.mit.edu/wiki/Exhibit/API/ViewPanel
+ *======================================================================
+ */
+Exhibit.ViewPanel = function(div, uiContext) {
+ this._uiContext = uiContext;
+ this._div = div;
+ this._uiContextCache = {};
+
+ this._viewConstructors = [];
+ this._viewConfigs = [];
+ this._viewLabels = [];
+ this._viewTooltips = [];
+ this._viewDomConfigs = [];
+ this._viewIDs = [];
+
+ this._viewIndex = 0;
+ this._view = null;
+}
+
+Exhibit.ViewPanel.create = function(configuration, div, uiContext) {
+ var viewPanel = new Exhibit.ViewPanel(div, uiContext);
+
+ if ("views" in configuration) {
+ for (var i = 0; i < configuration.views.length; i++) {
+ var viewConfig = configuration.views[i];
+
+ var viewClass = ("viewClass" in view) ? view.viewClass : Exhibit.TileView;
+ if (typeof viewClass == "string") {
+ viewClass = Exhibit.UI.viewClassNameToViewClass(viewClass);
+ }
+
+ var label = null;
+ if ("viewLabel" in viewConfig) {
+ label = viewConfig.viewLabel;
+ } else if ("label" in viewConfig) {
+ label = viewConfig.label;
+ } else if ("l10n" in viewClass && "viewLabel" in viewClass.l10n) {
+ label = viewClass.l10n.viewLabel;
+ } else {
+ label = "" + viewClass;
+ }
+
+ var tooltip = null;
+ if ("tooltip" in viewConfig) {
+ tooltip = viewConfig.tooltip;
+ } else if ("l10n" in viewClass && "viewTooltip" in viewClass.l10n) {
+ tooltip = viewClass.l10n.viewTooltip;
+ } else {
+ tooltip = label;
+ }
+
+ var id = viewPanel._generateViewID();
+ if ("id" in viewConfig) {
+ id = viewConfig.id;
+ }
+
+ viewPanel._viewConstructors.push(viewClass);
+ viewPanel._viewConfigs.push(viewConfig);
+ viewPanel._viewLabels.push(label);
+ viewPanel._viewTooltips.push(tooltip);
+ viewPanel._viewDomConfigs.push(null);
+ viewPanel._viewIDs.push(id);
+ }
+ }
+
+ if ("initialView" in configuration) {
+ viewPanel._viewIndex = configuration.initialView;
+ }
+
+ viewPanel._internalValidate();
+ viewPanel._initializeUI();
+
+ return viewPanel;
+};
+
+Exhibit.ViewPanel.createFromDOM = function(div, uiContext) {
+ var viewPanel = new Exhibit.ViewPanel(div, Exhibit.UIContext.createFromDOM(div, uiContext, false));
+
+ var node = div.firstChild;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ node.style.display = "none";
+
+ var role = Exhibit.getRoleAttribute(node);
+ if (role == "view") {
+ var viewClass = Exhibit.TileView;
+
+ var viewClassString = Exhibit.getAttribute(node, "viewClass");
+ if (viewClassString != null && viewClassString.length > 0) {
+ viewClass = Exhibit.UI.viewClassNameToViewClass(viewClassString);
+ if (viewClass == null) {
+ SimileAjax.Debug.warn("Unknown viewClass " + viewClassString);
+ }
+ }
+
+ var viewLabel = Exhibit.getAttribute(node, "viewLabel");
+ var label = (viewLabel != null && viewLabel.length > 0) ? viewLabel : Exhibit.getAttribute(node, "label");
+ var tooltip = Exhibit.getAttribute(node, "title");
+ var id = node.id;
+
+ if (label == null) {
+ if ("viewLabel" in viewClass.l10n) {
+ label = viewClass.l10n.viewLabel;
+ } else {
+ label = "" + viewClass;
+ }
+ }
+ if (tooltip == null) {
+ if ("l10n" in viewClass && "viewTooltip" in viewClass.l10n) {
+ tooltip = viewClass.l10n.viewTooltip;
+ } else {
+ tooltip = label;
+ }
+ }
+ if (id == null || id.length == 0) {
+ id = viewPanel._generateViewID();
+ }
+
+ viewPanel._viewConstructors.push(viewClass);
+ viewPanel._viewConfigs.push(null);
+ viewPanel._viewLabels.push(label);
+ viewPanel._viewTooltips.push(tooltip);
+ viewPanel._viewDomConfigs.push(node);
+ viewPanel._viewIDs.push(id);
+ }
+ }
+ node = node.nextSibling;
+ }
+
+ var initialView = Exhibit.getAttribute(div, "initialView");
+ if (initialView != null && initialView.length > 0) {
+ try {
+ var n = parseInt(initialView);
+ if (!isNaN(n)) {
+ viewPanel._viewIndex = n;
+ }
+ } catch (e) {
+ }
+ }
+
+ viewPanel._internalValidate();
+ viewPanel._initializeUI();
+
+ return viewPanel;
+};
+
+Exhibit.ViewPanel.prototype.dispose = function() {
+ this._uiContext.getCollection().removeListener(this._listener);
+
+ if (this._view != null) {
+ this._view.dispose();
+ this._view = null;
+ }
+
+ this._div.innerHTML = "";
+
+ this._uiContext.dispose();
+ this._uiContext = null;
+ this._div = null;
+};
+
+Exhibit.ViewPanel.prototype._generateViewID = function() {
+ return "view" + Math.floor(Math.random() * 1000000).toString();
+};
+
+Exhibit.ViewPanel.prototype._internalValidate = function() {
+ if (this._viewConstructors.length == 0) {
+ this._viewConstructors.push(Exhibit.TileView);
+ this._viewConfigs.push({});
+ this._viewLabels.push(Exhibit.TileView.l10n.viewLabel);
+ this._viewTooltips.push(Exhibit.TileView.l10n.viewTooltip);
+ this._viewDomConfigs.push(null);
+ this._viewIDs.push(this._generateViewID());
+ }
+
+ this._viewIndex =
+ Math.max(0, Math.min(this._viewIndex, this._viewConstructors.length - 1));
+};
+
+Exhibit.ViewPanel.prototype._initializeUI = function() {
+ var div = document.createElement("div");
+ if (this._div.firstChild != null) {
+ this._div.insertBefore(div, this._div.firstChild);
+ } else {
+ this._div.appendChild(div);
+ }
+
+ var self = this;
+ this._dom = Exhibit.ViewPanel.constructDom(
+ this._div.firstChild,
+ this._viewLabels,
+ this._viewTooltips,
+ function(index) {
+ self._selectView(index);
+ }
+ );
+
+ this._createView();
+};
+
+Exhibit.ViewPanel.prototype._createView = function() {
+ var viewContainer = this._dom.getViewContainer();
+ viewContainer.innerHTML = "";
+
+ var viewDiv = document.createElement("div");
+ viewContainer.appendChild(viewDiv);
+
+ var index = this._viewIndex;
+ var context = this._uiContextCache[index] || this._uiContext;
+ try {
+ if (this._viewDomConfigs[index] != null) {
+ this._view = this._viewConstructors[index].createFromDOM(
+ this._viewDomConfigs[index],
+ viewContainer,
+ context
+ );
+ } else {
+ this._view = this._viewConstructors[index].create(
+ this._viewConfigs[index],
+ viewContainer,
+ context
+ );
+ }
+ } catch (e) {
+ SimileAjax.Debug.log("Failed to create view " + this._viewLabels[index]);
+ SimileAjax.Debug.exception(e);
+ }
+
+ this._uiContextCache[index] = this._view._uiContext;
+
+ this._uiContext.getExhibit().setComponent(this._viewIDs[index], this._view);
+ this._dom.setViewIndex(index);
+};
+
+Exhibit.ViewPanel.prototype._switchView = function(newIndex) {
+ if (this._view) {
+ this._uiContext.getExhibit().disposeComponent(this._viewIDs[this._viewIndex]);
+ this._view = null;
+ }
+ this._viewIndex = newIndex;
+ this._createView();
+};
+
+Exhibit.ViewPanel.prototype._selectView = function(newIndex) {
+ var oldIndex = this._viewIndex;
+ var self = this;
+ SimileAjax.History.addLengthyAction(
+ function() {
+ self._switchView(newIndex);
+ },
+ function() {
+ self._switchView(oldIndex);
+ },
+ Exhibit.ViewPanel.l10n.createSelectViewActionTitle(self._viewLabels[newIndex])
+ );
+};
+
+Exhibit.ViewPanel.getPropertyValuesPairs = function(itemID, propertyEntries, database) {
+ var pairs = [];
+ var enterPair = function(propertyID, forward) {
+ var property = database.getProperty(propertyID);
+ var values = forward ?
+ database.getObjects(itemID, propertyID) :
+ database.getSubjects(itemID, propertyID);
+ var count = values.size();
+
+ if (count > 0) {
+ var itemValues = property.getValueType() == "item";
+ var pair = {
+ propertyLabel:
+ forward ?
+ (count > 1 ? property.getPluralLabel() : property.getLabel()) :
+ (count > 1 ? property.getReversePluralLabel() : property.getReverseLabel()),
+ valueType: property.getValueType(),
+ values: []
+ };
+
+ if (itemValues) {
+ values.visit(function(value) {
+ var label = database.getObject(value, "label");
+ pair.values.push(label != null ? label : value);
+ });
+ } else {
+ values.visit(function(value) {
+ pair.values.push(value);
+ });
+ }
+ pairs.push(pair);
+ }
+ };
+
+ for (var i = 0; i < propertyEntries.length; i++) {
+ var entry = propertyEntries[i];
+ if (typeof entry == "string") {
+ enterPair(entry, true);
+ } else {
+ enterPair(entry.property, entry.forward);
+ }
+ }
+ return pairs;
+};
+
+Exhibit.ViewPanel.constructDom = function(
+ div,
+ viewLabels,
+ viewTooltips,
+ onSelectView
+) {
+ var l10n = Exhibit.ViewPanel.l10n;
+ var template = {
+ elmt: div,
+ className: "exhibit-viewPanel exhibit-ui-protection",
+ children: [
+ { tag: "div",
+ className: "exhibit-viewPanel-viewSelection",
+ field: "viewSelectionDiv"
+ },
+ { tag: "div",
+ className: "exhibit-viewPanel-viewContainer",
+ field: "viewContainerDiv"
+ }
+ ]
+ };
+ var dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ dom.getViewContainer = function() {
+ return dom.viewContainerDiv;
+ };
+ dom.setViewIndex = function(index) {
+ if (viewLabels.length > 1) {
+ dom.viewSelectionDiv.innerHTML = "";
+
+ var appendView = function(i) {
+ var selected = (i == index);
+ if (i > 0) {
+ dom.viewSelectionDiv.appendChild(document.createTextNode(" \u2022 "));
+ }
+
+ var span = document.createElement("span");
+ span.className = selected ?
+ "exhibit-viewPanel-viewSelection-selectedView" :
+ "exhibit-viewPanel-viewSelection-view";
+ span.title = viewTooltips[i];
+ span.innerHTML = viewLabels[i];
+
+ if (!selected) {
+ var handler = function(elmt, evt, target) {
+ onSelectView(i);
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ SimileAjax.WindowManager.registerEvent(span, "click", handler);
+ }
+ dom.viewSelectionDiv.appendChild(span);
+ };
+
+ for (var i = 0; i < viewLabels.length; i++) {
+ appendView(i);
+ }
+ }
+ };
+
+ return dom;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/collection-summary-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/collection-summary-widget.js
new file mode 100644
index 00000000..d5ab63a5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/collection-summary-widget.js
@@ -0,0 +1,129 @@
+/*==================================================
+ * Exhibit.CollectionSummaryWidget
+ *==================================================
+ */
+Exhibit.CollectionSummaryWidget = function(containerElmt, uiContext) {
+ this._exhibit = uiContext.getExhibit();
+ this._collection = uiContext.getCollection();
+ this._uiContext = uiContext;
+ this._div = containerElmt;
+
+ var widget = this;
+ this._listener = { onItemsChanged: function() { widget._reconstruct(); } };
+ this._collection.addListener(this._listener);
+};
+
+Exhibit.CollectionSummaryWidget.create = function(configuration, containerElmt, uiContext) {
+ var widget = new Exhibit.CollectionSummaryWidget(
+ containerElmt,
+ Exhibit.UIContext.create(configuration, uiContext)
+ );
+ widget._initializeUI();
+ return widget;
+};
+
+Exhibit.CollectionSummaryWidget.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var widget = new Exhibit.CollectionSummaryWidget(
+ containerElmt != null ? containerElmt : configElmt,
+ Exhibit.UIContext.createFromDOM(configElmt, uiContext)
+ );
+ widget._initializeUI();
+ return widget;
+};
+
+Exhibit.CollectionSummaryWidget.prototype.dispose = function() {
+ this._collection.removeListener(this._listener);
+ this._div.innerHTML = "";
+
+ this._noResultsDom = null;
+ this._allResultsDom = null;
+ this._filteredResultsDom = null;
+ this._div = null;
+ this._collection = null;
+ this._exhibit = null;
+};
+
+Exhibit.CollectionSummaryWidget.prototype._initializeUI = function() {
+ var self = this;
+
+ var l10n = Exhibit.CollectionSummaryWidget.l10n;
+ var onClearFilters = function(elmt, evt, target) {
+ self._resetCollection();
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+
+ this._allResultsDom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ String.substitute(
+ l10n.allResultsTemplate,
+ [ "exhibit-collectionSummaryWidget-results" ]
+ )
+ );
+ this._filteredResultsDom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ String.substitute(
+ l10n.filteredResultsTemplate,
+ [ "exhibit-collectionSummaryWidget-results" ]
+ ),
+ { resetActionLink: Exhibit.UI.makeActionLink(l10n.resetFiltersLabel, onClearFilters)
+ }
+ );
+ this._noResultsDom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ String.substitute(
+ l10n.noResultsTemplate,
+ [ "exhibit-collectionSummaryWidget-results", "exhibit-collectionSummaryWidget-count" ]
+ ),
+ { resetActionLink: Exhibit.UI.makeActionLink(l10n.resetFiltersLabel, onClearFilters)
+ }
+ );
+
+ this._div.innerHTML = "";
+ this._reconstruct();
+};
+
+Exhibit.CollectionSummaryWidget.prototype._reconstruct = function() {
+ var originalSize = this._collection.countAllItems();
+ var currentSize = this._collection.countRestrictedItems();
+ var database = this._uiContext.getDatabase();
+ var dom = this._dom;
+
+ while (this._div.childNodes.length > 0) {
+ this._div.removeChild(this._div.firstChild);
+ }
+
+ if (originalSize > 0) {
+ if (currentSize == 0) {
+ this._div.appendChild(this._noResultsDom.elmt);
+ } else {
+ var typeIDs = database.getTypeIDs(this._collection.getRestrictedItems()).toArray();
+ var typeID = typeIDs.length == 1 ? typeIDs[0] : "Item";
+
+ var description =
+ Exhibit.Database.l10n.labelItemsOfType(currentSize, typeID, database, "exhibit-collectionSummaryWidget-count");
+
+ if (currentSize == originalSize) {
+ this._div.appendChild(this._allResultsDom.elmt);
+ this._allResultsDom.resultDescription.innerHTML = "";
+ this._allResultsDom.resultDescription.appendChild(description);
+ } else {
+ this._div.appendChild(this._filteredResultsDom.elmt);
+ this._filteredResultsDom.resultDescription.innerHTML = "";
+ this._filteredResultsDom.resultDescription.appendChild(description);
+ this._filteredResultsDom.originalCountSpan.innerHTML = originalSize;
+ }
+ }
+ }
+};
+
+Exhibit.CollectionSummaryWidget.prototype._resetCollection = function() {
+ var state = {};
+ var collection = this._collection;
+
+ SimileAjax.History.addLengthyAction(
+ function() { state.restrictions = collection.clearAllRestrictions(); },
+ function() { collection.applyRestrictions(state.restrictions); },
+ Exhibit.CollectionSummaryWidget.l10n.resetActionTitle
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-gradient-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-gradient-widget.js
new file mode 100644
index 00000000..9a9d1451
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-gradient-widget.js
@@ -0,0 +1,171 @@
+/*==================================================
+ * Exhibit.LegendGradientWidget
+ *==================================================
+ */
+Exhibit.LegendGradientWidget = function(containerElmt, uiContext) {
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._initializeUI();
+};
+
+Exhibit.LegendGradientWidget.create = function (containerElmt, uiContext) {
+ return new Exhibit.LegendGradientWidget(containerElmt, uiContext);
+};
+
+Exhibit.LegendGradientWidget.prototype.addGradient = function(configuration) {
+ var gradientPoints = [];
+ var gradientPoints = configuration;
+ var sortObj = function(a, b) {
+ return a.value - b.value;
+ };
+ gradientPoints.sort(sortObj);
+
+ var theTable = document.createElement("table");
+ var tableBody = document.createElement("tbody");
+ var theRow1 = document.createElement("tr");
+ var theRow2 = document.createElement("tr");
+ var theRow3 = document.createElement("tr");
+
+ theRow1.style.height="2em";
+ theRow2.style.height="2em";
+ theRow3.style.height="2em";
+ theTable.style.width="80%";
+ theTable.cellSpacing="0";
+ theTable.style.emptyCells="show";
+ theTable.style.marginLeft="auto";
+ theTable.style.marginRight="auto";
+ tableBody.appendChild(theRow1);
+ tableBody.appendChild(theRow2);
+ tableBody.appendChild(theRow3);
+ theTable.appendChild(tableBody);
+
+ this._theRow1 = theRow1;
+ this._theRow2 = theRow2;
+ this._theRow3 = theRow3;
+
+ var globLowPoint = gradientPoints[0].value;
+ var globHighPoint = gradientPoints[gradientPoints.length - 1].value;
+ var stepSize = (globHighPoint - globLowPoint) / 50;
+ var counter = 0;
+
+ for(var i = 0; i < gradientPoints.length-1; i++) {
+ var lowPoint = gradientPoints[i].value;
+ var highPoint = gradientPoints[i+1].value;
+
+ var colorRect = document.createElement("td");
+ colorRect.style.backgroundColor = "rgb(" + gradientPoints[i].red + "," + gradientPoints[i].green + "," + gradientPoints[i].blue + ")";
+ var numberRect = document.createElement("td");
+ var textDiv = document.createElement("div");
+ var theText = document.createTextNode(gradientPoints[i].value);
+ textDiv.appendChild(theText);
+ numberRect.appendChild(textDiv);
+ theRow1.appendChild(document.createElement("td"));
+ theRow2.appendChild(colorRect);
+ theRow3.appendChild(numberRect);
+
+ colorRect.onmouseover = function() {
+ this.style.border="solid 1.2px";
+ };
+ colorRect.onmouseout = function() {
+ this.style.border="none";
+ };
+
+ counter++;
+
+ for(var j = lowPoint + stepSize; j < highPoint; j += stepSize) {
+ var fraction = (j - lowPoint)/(highPoint - lowPoint);
+ var newRed = Math.floor(gradientPoints[i].red + fraction*(gradientPoints[i+1].red - gradientPoints[i].red));
+ var newGreen = Math.floor(gradientPoints[i].green + fraction*(gradientPoints[i+1].green - gradientPoints[i].green));
+ var newBlue = Math.floor(gradientPoints[i].blue + fraction*(gradientPoints[i+1].blue - gradientPoints[i].blue));
+
+ var colorRect = document.createElement("td");
+ colorRect.count = counter;
+ colorRect.style.backgroundColor = "rgb(" + newRed + "," + newGreen + "," + newBlue + ")";
+ var numberRect = document.createElement("td");
+ var textDiv = document.createElement("div");
+ var theText = document.createTextNode((Math.floor(j*100))/100);
+ textDiv.appendChild(theText);
+ numberRect.appendChild(textDiv);
+ textDiv.style.width="2px";
+ textDiv.style.overflow="hidden";
+ textDiv.style.visibility="hidden";
+ theRow1.appendChild(numberRect);
+ theRow2.appendChild(colorRect);
+ theRow3.appendChild(document.createElement("td"));
+ counter++;
+
+ colorRect.onmouseover = function() {
+ this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="visible";
+ this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="visible";
+ this.style.border="solid 1.2px";
+ }
+ colorRect.onmouseout = function() {
+ this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.visibility="hidden";
+ this.parentNode.parentNode.childNodes[0].childNodes[this.count].childNodes[0].style.overflow="hidden";
+ this.style.border="none";
+ }
+ }
+ }
+
+ var high = gradientPoints.length - 1
+ var colorRect = document.createElement("td");
+ colorRect.style.backgroundColor = "rgb(" + gradientPoints[high].red + "," + gradientPoints[high].green + "," + gradientPoints[high].blue + ")";
+ var numberRect = document.createElement("td");
+ var textDiv = document.createElement("div");
+ var theText = document.createTextNode(globHighPoint);
+ textDiv.appendChild(theText);
+ numberRect.appendChild(textDiv);
+ theRow1.appendChild(document.createElement("td"));
+ theRow2.appendChild(colorRect);
+ theRow3.appendChild(numberRect);
+ counter++;
+
+ colorRect.onmouseover = function() {
+ this.style.border="solid 1.2px";
+ };
+ colorRect.onmouseout = function() {
+ this.style.border="none";
+ };
+
+ this._div.appendChild(theTable);
+};
+
+Exhibit.LegendGradientWidget.prototype.addEntry = function(color, label) {
+ var cell = document.createElement("td");
+
+ cell.style.width="1.5em";
+ cell.style.height="2em";
+ this._theRow1.appendChild(cell);
+ this._theRow1.appendChild(document.createElement("td"));
+ this._theRow2.appendChild(document.createElement("td"));
+ this._theRow3.appendChild(document.createElement("td"));
+
+ var colorCell = document.createElement("td");
+
+ colorCell.style.backgroundColor = color;
+ this._theRow2.appendChild(colorCell);
+
+ var labelCell = document.createElement("td");
+ var labelDiv = document.createElement("div");
+
+ labelDiv.appendChild(document.createTextNode(label));
+ labelCell.appendChild(labelDiv);
+ this._theRow3.appendChild(labelCell);
+}
+
+Exhibit.LegendGradientWidget.prototype.dispose = function() {
+ this._div.innerHTML = "";
+
+ this._div = null;
+ this._uiContext = null;
+};
+
+Exhibit.LegendGradientWidget.prototype._initializeUI = function() {
+ this._div.className = "exhibit-legendGradientWidget";
+ this._div.innerHTML = "";
+};
+
+Exhibit.LegendGradientWidget.prototype.clear = function() {
+ this._div.innerHTML = "";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-widget.js
new file mode 100644
index 00000000..00b8de6d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/legend-widget.js
@@ -0,0 +1,136 @@
+/*==================================================
+ * Exhibit.LegendWidget
+ *==================================================
+ */
+Exhibit.LegendWidget = function(configuration, containerElmt, uiContext) {
+ this._configuration = configuration;
+ this._div = containerElmt;
+ this._uiContext = uiContext;
+
+ this._colorMarkerGenerator = "colorMarkerGenerator" in configuration ?
+ configuration.colorMarkerGenerator :
+ Exhibit.LegendWidget._defaultColorMarkerGenerator;
+ this._sizeMarkerGenerator = "sizeMarkerGenerator" in configuration ?
+ configuration.sizeMarkerGenerator :
+ Exhibit.LegendWidget._defaultSizeMarkerGenerator;
+ this._iconMarkerGenerator = "iconMarkerGenerator" in configuration ?
+ configuration.iconMarkerGenerator :
+ Exhibit.LegendWidget._defaultIconMarkerGenerator;
+
+ this._labelStyler = "labelStyler" in configuration ?
+ configuration.labelStyler :
+ Exhibit.LegendWidget._defaultColorLabelStyler;
+
+ this._initializeUI();
+};
+
+Exhibit.LegendWidget.create = function(configuration, containerElmt, uiContext) {
+ return new Exhibit.LegendWidget(configuration, containerElmt, uiContext);
+};
+
+Exhibit.LegendWidget.prototype.dispose = function() {
+ this._div.innerHTML = "";
+
+ this._div = null;
+ this._uiContext = null;
+};
+
+Exhibit.LegendWidget.prototype._initializeUI = function() {
+ this._div.className = "exhibit-legendWidget";
+ this._div.innerHTML = "<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+
+Exhibit.LegendWidget.prototype.clear = function() {
+ this._div.innerHTML = "<div id='exhibit-color-legend'></div><div id='exhibit-size-legend'></div><div id='exhibit-icon-legend'></div>";
+};
+
+Exhibit.LegendWidget.prototype.addLegendLabel = function(label, type) {
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ "<div id='legend-label'>" +
+ "<span id='label' class='exhibit-legendWidget-entry-title'>" +
+ label.replace(/\s+/g, "\u00a0") +
+ "</span>" +
+ "\u00a0\u00a0 </div>",
+ { }
+ );
+ dom.elmt.className = "exhibit-legendWidget-label";
+ var id = 'exhibit-' + type + '-legend';
+ document.getElementById(id).appendChild(dom.elmt);
+}
+
+Exhibit.LegendWidget.prototype.addEntry = function(value, label, type) {
+ type = type || 'color';
+ label = (label != null) ? label.toString() : key.toString();
+ if (type == 'color') {
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ "<span id='marker'></span>\u00a0" +
+ "<span id='label' class='exhibit-legendWidget-entry-title'>" +
+ label.replace(/\s+/g, "\u00a0") +
+ "</span>" +
+ "\u00a0\u00a0 ",
+ { marker: this._colorMarkerGenerator(value) }
+ );
+ var legendDiv = document.getElementById('exhibit-color-legend');
+ }
+ if (type == 'size') {
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ "<span id='marker'></span>\u00a0" +
+ "<span id='label' class='exhibit-legendWidget-entry-title'>" +
+ label.replace(/\s+/g, "\u00a0") +
+ "</span>" +
+ "\u00a0\u00a0 ",
+ { marker: this._sizeMarkerGenerator(value) }
+ );
+ var legendDiv = document.getElementById('exhibit-size-legend');
+ }
+ if (type == 'icon') {
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "span",
+ "<span id='marker'></span>\u00a0" +
+ "<span id='label' class='exhibit-legendWidget-entry-title'>" +
+ label.replace(/\s+/g, "\u00a0") +
+ "</span>" +
+ "\u00a0\u00a0 ",
+ { marker: this._iconMarkerGenerator(value) }
+ );
+ var legendDiv = document.getElementById('exhibit-icon-legend');
+ }
+ dom.elmt.className = "exhibit-legendWidget-entry";
+ this._labelStyler(dom.label, value);
+ legendDiv.appendChild(dom.elmt);
+};
+
+Exhibit.LegendWidget._localeSort = function(a,b) {
+ return a.localeCompare(b);
+}
+
+Exhibit.LegendWidget._defaultColorMarkerGenerator = function(value) {
+ var span = document.createElement("span");
+ span.className = "exhibit-legendWidget-entry-swatch";
+ span.style.background = value;
+ span.innerHTML = "\u00a0\u00a0";
+ return span;
+};
+
+Exhibit.LegendWidget._defaultSizeMarkerGenerator = function(value) {
+ var span = document.createElement("span");
+ span.className = "exhibit-legendWidget-entry-swatch";
+ span.style.height = value;
+ span.style.width = value;
+ span.style.background = "#C0C0C0";
+ span.innerHTML = "\u00a0\u00a0";
+ return span;
+}
+
+Exhibit.LegendWidget._defaultIconMarkerGenerator = function(value) {
+ var span = document.createElement("span");
+ span.className = "<img src="+value+"/>";
+ return span;
+}
+
+Exhibit.LegendWidget._defaultColorLabelStyler = function(elmt, value) {
+ //elmt.style.color = "#" + value;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/logo.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/logo.js
new file mode 100644
index 00000000..f199030e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/logo.js
@@ -0,0 +1,53 @@
+/*======================================================================
+ * Exhibit.Logo
+ *======================================================================
+ */
+Exhibit.Logo = function ( elmt, exhibit ) {
+ this._exhibit = exhibit;
+ this._elmt = elmt;
+ this._color = "Silver";
+};
+
+Exhibit.Logo.create = function(configuration, elmt, exhibit) {
+ var logo = new Exhibit.Logo(elmt, exhibit);
+
+ if ("color" in configuration) {
+ logo._color = configuration.color;
+ }
+
+ logo._initializeUI();
+ return logo;
+};
+
+Exhibit.Logo.createFromDOM = function(elmt, exhibit) {
+ var logo = new Exhibit.Logo(elmt, exhibit);
+
+ var color = Exhibit.getAttribute(elmt, "color");
+ if (color != null && color.length > 0) {
+ logo._color = color;
+ }
+
+ logo._initializeUI();
+ return logo;
+};
+
+Exhibit.Logo.prototype.dispose = function() {
+ this._elmt = null;
+ this._exhibit = null;
+};
+
+Exhibit.Logo.prototype._initializeUI = function() {
+ var logoURL = "http://static.simile.mit.edu/graphics/logos/exhibit/exhibit-small-" + this._color + ".png";
+ var img = SimileAjax.Graphics.createTranslucentImage(logoURL);
+ var id = "exhibit-logo-image";
+ if (!document.getElementById(id)) {
+ img.id = id;
+ }
+ var a = document.createElement("a");
+ a.href = "http://simile.mit.edu/exhibit/";
+ a.title = "http://simile.mit.edu/exhibit/";
+ a.target = "_blank";
+ a.appendChild(img);
+
+ this._elmt.appendChild(a);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/option-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/option-widget.js
new file mode 100644
index 00000000..0eb48a1f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/option-widget.js
@@ -0,0 +1,78 @@
+/*==================================================
+ * Exhibit.OptionWidget
+ *==================================================
+ */
+Exhibit.OptionWidget = function(configuration, containerElmt, uiContext) {
+ this._label = configuration.label;
+ this._checked = "checked" in configuration ? configuration.checked : false;
+ this._onToggle = configuration.onToggle;
+
+ this._containerElmt = containerElmt;
+ this._uiContext = uiContext;
+ this._initializeUI();
+};
+
+Exhibit.OptionWidget.create = function(configuration, containerElmt, uiContext) {
+ return new Exhibit.OptionWidget(configuration, containerElmt, uiContext);
+};
+
+Exhibit.OptionWidget.prototype.dispose = function() {
+ this._containerElmt.innerHTML = "";
+
+ this._dom = null;
+ this._containerElmt = null;
+ this._uiContext = null;
+};
+
+Exhibit.OptionWidget.uncheckedImageURL = Exhibit.urlPrefix + "images/option.png";
+
+Exhibit.OptionWidget.checkedImageURL = Exhibit.urlPrefix + "images/option-check.png";
+
+Exhibit.OptionWidget.uncheckedTemplate =
+ "<span id='uncheckedSpan' style='display: none;'><img id='uncheckedImage' /> %0</span>";
+
+Exhibit.OptionWidget.checkedTemplate =
+ "<span id='checkedSpan' style='display: none;'><img id='checkedImage' /> %0</span>";
+
+Exhibit.OptionWidget.prototype._initializeUI = function() {
+ this._containerElmt.className = "exhibit-optionWidget";
+ this._dom = SimileAjax.DOM.createDOMFromString(
+ this._containerElmt,
+ String.substitute(
+ Exhibit.OptionWidget.uncheckedTemplate + Exhibit.OptionWidget.checkedTemplate,
+ [ this._label ]
+ ),
+ { uncheckedImage: SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.uncheckedImageURL),
+ checkedImage: SimileAjax.Graphics.createTranslucentImage(Exhibit.OptionWidget.checkedImageURL)
+ }
+ );
+
+ if (this._checked) {
+ this._dom.checkedSpan.style.display = "inline";
+ } else {
+ this._dom.uncheckedSpan.style.display = "inline";
+ }
+
+ SimileAjax.WindowManager.registerEvent(this._containerElmt, "click", this._onToggle);
+};
+
+Exhibit.OptionWidget.prototype.getChecked = function() {
+ return this._checked;
+};
+
+Exhibit.OptionWidget.prototype.setChecked = function(checked) {
+ if (checked != this._checked) {
+ this._checked = checked;
+ if (checked) {
+ this._dom.checkedSpan.style.display = "inline";
+ this._dom.uncheckedSpan.style.display = "none";
+ } else {
+ this._dom.checkedSpan.style.display = "none";
+ this._dom.uncheckedSpan.style.display = "inline";
+ }
+ }
+};
+
+Exhibit.OptionWidget.prototype.toggle = function() {
+ this.setChecked(!this._checked);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/resizable-div-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/resizable-div-widget.js
new file mode 100644
index 00000000..0bdc364a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/resizable-div-widget.js
@@ -0,0 +1,61 @@
+/*==================================================
+ * Exhibit.ResizableDivWidget
+ *==================================================
+ */
+Exhibit.ResizableDivWidget = function(configuration, elmt, uiContext) {
+ this._div = elmt;
+ this._configuration = configuration;
+ if (!("minHeight" in configuration)) {
+ configuration["minHeight"] = 10; // pixels
+ }
+
+ this._initializeUI();
+};
+
+Exhibit.ResizableDivWidget.create = function(configuration, elmt, uiContext) {
+ return new Exhibit.ResizableDivWidget(configuration, elmt, uiContext);
+};
+
+Exhibit.ResizableDivWidget.prototype.dispose = function() {
+ this._div.innerHTML = "";
+ this._contentDiv = null;
+ this._resizerDiv = null;
+ this._div = null;
+};
+
+Exhibit.ResizableDivWidget.prototype.getContentDiv = function() {
+ return this._contentDiv;
+};
+
+Exhibit.ResizableDivWidget.prototype._initializeUI = function() {
+ var self = this;
+
+ this._div.innerHTML =
+ "<div></div>" +
+ "<div class='exhibit-resizableDivWidget-resizer'>" +
+ SimileAjax.Graphics.createTranslucentImageHTML(Exhibit.urlPrefix + "images/down-arrow.png") +
+ "</div>";
+
+ this._contentDiv = this._div.childNodes[0];
+ this._resizerDiv = this._div.childNodes[1];
+
+ SimileAjax.WindowManager.registerForDragging(
+ this._resizerDiv,
+ { onDragStart: function() {
+ this._height = self._contentDiv.offsetHeight;
+ },
+ onDragBy: function(diffX, diffY) {
+ this._height += diffY;
+ self._contentDiv.style.height = Math.max(
+ self._configuration.minHeight,
+ this._height
+ ) + "px";
+ },
+ onDragEnd: function() {
+ if ("onResize" in self._configuration) {
+ self._configuration["onResize"]();
+ }
+ }
+ }
+ );
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/toolbox-widget.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/toolbox-widget.js
new file mode 100644
index 00000000..bb1a40c9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/ui/widgets/toolbox-widget.js
@@ -0,0 +1,267 @@
+/*==================================================
+ * Exhibit.ToolboxWidget
+ *==================================================
+ */
+Exhibit.ToolboxWidget = function(containerElmt, uiContext) {
+ this._containerElmt = containerElmt;
+ this._uiContext = uiContext;
+ this._settings = {};
+ this._customExporters = [];
+
+ this._hovering = false;
+ this._initializeUI();
+};
+
+Exhibit.ToolboxWidget._settingSpecs = {
+ "itemID": { type: "text" }
+};
+
+Exhibit.ToolboxWidget.create = function(configuration, containerElmt, uiContext) {
+ var widget = new Exhibit.ToolboxWidget(
+ containerElmt,
+ Exhibit.UIContext.create(configuration, uiContext)
+ );
+ Exhibit.ToolboxWidget._configure(widget, configuration);
+
+ widget._initializeUI();
+ return widget;
+};
+
+Exhibit.ToolboxWidget.createFromDOM = function(configElmt, containerElmt, uiContext) {
+ var configuration = Exhibit.getConfigurationFromDOM(configElmt);
+ var widget = new Exhibit.ToolboxWidget(
+ containerElmt != null ? containerElmt : configElmt,
+ Exhibit.UIContext.createFromDOM(configElmt, uiContext)
+ );
+
+ Exhibit.SettingsUtilities.collectSettingsFromDOM(configElmt, Exhibit.ToolboxWidget._settingSpecs, widget._settings);
+ Exhibit.ToolboxWidget._configure(widget, configuration);
+
+ widget._initializeUI();
+ return widget;
+};
+
+Exhibit.ToolboxWidget._configure = function(widget, configuration) {
+ Exhibit.SettingsUtilities.collectSettings(configuration, Exhibit.ToolboxWidget._settingSpecs, widget._settings);
+};
+
+Exhibit.ToolboxWidget.prototype.dispose = function() {
+ this._containerElmt.onmouseover = null;
+ this._containerElmt.onmouseout = null;
+
+ this._dismiss();
+ this._settings = null;
+ this._containerElmt = null;
+ this._uiContext = null;
+};
+
+Exhibit.ToolboxWidget.prototype.addExporter = function(exporter) {
+ this._customExporters.push(exporter);
+};
+
+Exhibit.ToolboxWidget.prototype._initializeUI = function() {
+ var self = this;
+ this._containerElmt.onmouseover = function(evt) { self._onContainerMouseOver(evt); };
+ this._containerElmt.onmouseout = function(evt) { self._onContainerMouseOut(evt); };
+};
+
+Exhibit.ToolboxWidget.prototype._onContainerMouseOver = function(evt) {
+ if (!this._hovering) {
+ var self = this;
+ var coords = SimileAjax.DOM.getPageCoordinates(this._containerElmt);
+ var docWidth = document.body.offsetWidth;
+ var docHeight = document.body.offsetHeight;
+
+ var popup = document.createElement("div");
+ popup.className = "exhibit-toolboxWidget-popup screen";
+ popup.style.top = coords.top + "px";
+ popup.style.right = (docWidth - coords.left - this._containerElmt.offsetWidth) + "px";
+
+ this._fillPopup(popup);
+
+ document.body.appendChild(popup);
+ popup.onmouseover = function(evt) { self._onPopupMouseOver(evt); };
+ popup.onmouseout = function(evt) { self._onPopupMouseOut(evt); };
+
+ this._popup = popup;
+ this._hovering = true;
+ } else {
+ this._clearTimeout();
+ }
+};
+
+Exhibit.ToolboxWidget.prototype._onContainerMouseOut = function(evt) {
+ if (Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt), this._containerElmt)) {
+ this._setTimeout();
+ }
+};
+
+Exhibit.ToolboxWidget.prototype._onPopupMouseOver = function(evt) {
+ this._clearTimeout();
+};
+
+Exhibit.ToolboxWidget.prototype._onPopupMouseOut = function(evt) {
+ if (Exhibit.ToolboxWidget._mouseOutsideElmt(Exhibit.ToolboxWidget._getEvent(evt), this._containerElmt)) {
+ this._setTimeout();
+ }
+};
+
+Exhibit.ToolboxWidget.prototype._setTimeout = function() {
+ var self = this;
+ this._timer = window.setTimeout(function() { self._onTimeout(); }, 200)
+};
+
+Exhibit.ToolboxWidget.prototype._clearTimeout = function() {
+ if (this._timer) {
+ window.clearTimeout(this._timer);
+ this._timer = null;
+ }
+};
+
+Exhibit.ToolboxWidget.prototype._onTimeout = function() {
+ this._dismiss();
+ this._hovering = false;
+ this._timer = null;
+};
+
+Exhibit.ToolboxWidget.prototype._fillPopup = function(elmt) {
+ var self = this;
+
+ var exportImg = Exhibit.UI.createTranslucentImage("images/liveclipboard-icon.png");
+ exportImg.className = "exhibit-toolboxWidget-button";
+ SimileAjax.WindowManager.registerEvent(
+ exportImg,
+ "click",
+ function(elmt, evt, target) {
+ self._showExportMenu(exportImg);
+ }
+ );
+
+ elmt.appendChild(exportImg);
+};
+
+Exhibit.ToolboxWidget.prototype._dismiss = function() {
+ if (this._popup) {
+ document.body.removeChild(this._popup);
+ this._popup = null;
+ }
+};
+
+Exhibit.ToolboxWidget._mouseOutsideElmt = function(evt, elmt) {
+ var eventCoords = SimileAjax.DOM.getEventPageCoordinates(evt);
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+ return ((eventCoords.x < coords.left || eventCoords.x > coords.left + elmt.offsetWidth) ||
+ (eventCoords.y < coords.top || eventCoords.y > coords.top + elmt.offsetHeight));
+};
+
+Exhibit.ToolboxWidget._getEvent = function(evt) {
+ return (evt) ? evt : ((event) ? event : null);
+};
+
+Exhibit.ToolboxWidget.prototype._showExportMenu = function(elmt) {
+ var self = this;
+ var popupDom = Exhibit.UI.createPopupMenuDom(elmt);
+
+ var makeMenuItem = function(exporter) {
+ popupDom.appendMenuItem(
+ exporter.getLabel(),
+ null,
+ function() {
+ var database = self._uiContext.getDatabase();
+ var text = ("itemID" in self._settings) ?
+ exporter.exportOne(self._settings.itemID, database) :
+ exporter.exportMany(
+ self._uiContext.getCollection().getRestrictedItems(),
+ database
+ );
+ Exhibit.ToolboxWidget.createExportDialogBox(text).open();
+ }
+ );
+ }
+
+ var exporters = Exhibit.getExporters();
+ for (var i = 0; i < exporters.length; i++) {
+ makeMenuItem(exporters[i]);
+ }
+ for (var i = 0; i < this._customExporters.length; i++) {
+ makeMenuItem(this._customExporters[i]);
+ }
+
+ if ("getGeneratedHTML" in this) {
+ makeMenuItem({
+ getLabel: function() { return Exhibit.l10n.htmlExporterLabel; },
+ exportOne: this.getGeneratedHTML,
+ exportMany: this.getGeneratedHTML
+ });
+ }
+
+ /*if (generatedContentElmtRetriever != null) {
+ popupDom.appendMenuItem(
+ Exhibit.l10n.htmlExporterLabel,
+ null,
+ function() {
+ Exhibit.UI.createCopyDialogBox(
+ generatedContentElmtRetriever().innerHTML
+ //.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\&/g, "&amp;")
+ ).open();
+ }
+ );
+ }*/
+
+ popupDom.open();
+};
+
+Exhibit.ToolboxWidget.createExportDialogBox = function(string) {
+ var template = {
+ tag: "div",
+ className: "exhibit-copyDialog exhibit-ui-protection",
+ children: [
+ { tag: "button",
+ field: "closeButton",
+ children: [ Exhibit.l10n.exportDialogBoxCloseButtonLabel ]
+ },
+ { tag: "p",
+ children: [ Exhibit.l10n.exportDialogBoxPrompt ]
+ },
+ { tag: "div",
+ field: "textAreaContainer"
+ }
+ ]
+ };
+ var dom = SimileAjax.DOM.createDOMFromTemplate(template);
+ dom.textAreaContainer.innerHTML =
+ "<textarea wrap='off' rows='15'>" + string + "</textarea>";
+
+ dom.close = function() {
+ document.body.removeChild(dom.elmt);
+ };
+ dom.open = function() {
+ dom.elmt.style.top = (document.body.scrollTop + 100) + "px";
+
+ document.body.appendChild(dom.elmt);
+ dom.layer = SimileAjax.WindowManager.pushLayer(function() { dom.close(); }, false);
+
+ var textarea = dom.textAreaContainer.firstChild;
+ textarea.select();
+
+ SimileAjax.WindowManager.registerEvent(
+ dom.closeButton,
+ "click",
+ function(elmt, evt, target) { SimileAjax.WindowManager.popLayer(dom.layer); },
+ dom.layer
+ );
+ SimileAjax.WindowManager.registerEvent(
+ textarea,
+ "keyup",
+ function(elmt, evt, target) {
+ if (evt.keyCode == 27) { // ESC
+ SimileAjax.WindowManager.popLayer(dom.layer);
+ }
+ },
+ dom.layer
+ );
+ };
+
+ return dom;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/coders.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/coders.js
new file mode 100644
index 00000000..d62256a8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/coders.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Exhibit.Coders
+ *==================================================
+ */
+
+Exhibit.Coders = new Object();
+
+Exhibit.Coders.mixedCaseColor= "#fff";
+Exhibit.Coders.othersCaseColor = "#aaa";
+Exhibit.Coders.missingCaseColor = "#888";
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/facets.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/facets.js
new file mode 100644
index 00000000..61c26d74
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/facets.js
@@ -0,0 +1,543 @@
+/*==================================================
+ * Exhibit.FacetUtilities
+ *
+ * Utilities for facets' code.
+ *==================================================
+ */
+Exhibit.FacetUtilities = new Object();
+
+Exhibit.FacetUtilities.constructFacetFrame = function(forFacet, div, facetLabel, onClearAllSelections, uiContext, collapsible, collapsed) {
+ div.className = "exhibit-facet";
+ var dom = SimileAjax.DOM.createDOMFromString(
+ div,
+ "<div class='exhibit-facet-header'>" +
+ "<div class='exhibit-facet-header-filterControl' id='clearSelectionsDiv' title='" + Exhibit.FacetUtilities.l10n.clearSelectionsTooltip + "'>" +
+ "<span id='filterCountSpan'></span>" +
+ "<img id='checkImage' />" +
+ "</div>" +
+ ((collapsible) ?
+ "<img src='"+Exhibit.urlPrefix+"images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />" :
+ "") +
+ "<span class='exhibit-facet-header-title'>" + facetLabel + "</span>" +
+ "</div>" +
+ "<div class='exhibit-facet-body-frame' id='frameDiv'></div>",
+ { checkImage: Exhibit.UI.createTranslucentImage("images/black-check.png") }
+ );
+ var resizableDivWidget = Exhibit.ResizableDivWidget.create({}, dom.frameDiv, uiContext);
+
+ dom.valuesContainer = resizableDivWidget.getContentDiv();
+ dom.valuesContainer.className = "exhibit-facet-body";
+
+ dom.setSelectionCount = function(count) {
+ this.filterCountSpan.innerHTML = count;
+ this.clearSelectionsDiv.style.display = count > 0 ? "block" : "none";
+ };
+ SimileAjax.WindowManager.registerEvent(dom.clearSelectionsDiv, "click", onClearAllSelections);
+
+ if (collapsible) {
+ SimileAjax.WindowManager.registerEvent(dom.collapseImg, "click", function() {
+ Exhibit.FacetUtilities.toggleCollapse(dom, forFacet);
+ });
+
+ if (collapsed) {
+ Exhibit.FacetUtilities.toggleCollapse(dom, forFacet);
+ }
+ }
+
+ return dom;
+};
+
+Exhibit.FacetUtilities.toggleCollapse = function(dom, facet) {
+ var el = dom.frameDiv;
+ if (el.style.display != "none") {
+ el.style.display = "none";
+ dom.collapseImg.src = Exhibit.urlPrefix + "images/expand.png";
+ } else {
+ el.style.display = "block";
+ dom.collapseImg.src = Exhibit.urlPrefix + "images/collapse.png";
+ // Try to call onUncollapse but don't sweat it if it isn't there.
+ if (typeof facet.onUncollapse == 'function') {
+ facet.onUncollapse();
+ }
+ }
+};
+
+Exhibit.FacetUtilities.isCollapsed = function(facet) {
+ var el = facet._dom.frameDiv;
+ return el.style.display == "none";
+};
+
+Exhibit.FacetUtilities.constructFacetItem = function(
+ label,
+ count,
+ color,
+ selected,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ uiContext
+) {
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ "<div class='exhibit-facet-value-count'>" + count + "</div>" +
+ "<div class='exhibit-facet-value-inner' id='inner'>" +
+ ( "<div class='exhibit-facet-value-checkbox'>&#160;" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix +
+ ( facetHasSelection ?
+ (selected ? "images/black-check.png" : "images/no-check.png") :
+ "images/no-check-no-border.png"
+ )) +
+ "</div>"
+ ) +
+ "<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a>" +
+ "</div>"
+ );
+ dom.elmt.className = selected ? "exhibit-facet-value exhibit-facet-value-selected" : "exhibit-facet-value";
+ if (typeof label == "string") {
+ dom.elmt.title = label;
+ dom.link.innerHTML = label;
+ if (color != null) {
+ dom.link.style.color = color;
+ }
+ } else {
+ dom.link.appendChild(label);
+ if (color != null) {
+ label.style.color = color;
+ }
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.elmt, "click", onSelectOnly, SimileAjax.WindowManager.getBaseLayer());
+ if (facetHasSelection) {
+ SimileAjax.WindowManager.registerEvent(dom.inner.firstChild, "click", onSelect, SimileAjax.WindowManager.getBaseLayer());
+ }
+ return dom.elmt;
+};
+
+Exhibit.FacetUtilities.constructFlowingFacetFrame = function(forFacet, div, facetLabel, onClearAllSelections, uiContext, collapsible, collapsed) {
+ div.className = "exhibit-flowingFacet";
+ var dom = SimileAjax.DOM.createDOMFromString(
+ div,
+ "<div class='exhibit-flowingFacet-header'>" +
+ ((collapsible) ?
+ "<img src='" + Exhibit.urlPrefix + "images/collapse.png' class='exhibit-facet-header-collapse' id='collapseImg' />" :
+ "") +
+ "<span class='exhibit-flowingFacet-header-title'>" + facetLabel + "</span>" +
+ "</div>" +
+ "<div id='frameDiv'><div class='exhibit-flowingFacet-body' id='valuesContainer'></div></div>"
+ );
+
+ dom.setSelectionCount = function(count) {
+ // nothing
+ };
+
+ if (collapsible) {
+ SimileAjax.WindowManager.registerEvent(dom.collapseImg, "click", function() {
+ Exhibit.FacetUtilities.toggleCollapse(dom, forFacet);
+ });
+
+ if (collapsed) {
+ Exhibit.FacetUtilities.toggleCollapse(dom, forFacet);
+ }
+ }
+
+ return dom;
+};
+
+Exhibit.FacetUtilities.constructFlowingFacetItem = function(
+ label,
+ count,
+ color,
+ selected,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ uiContext
+) {
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ ( "<div class='exhibit-flowingFacet-value-checkbox'>" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix +
+ ( facetHasSelection ?
+ (selected ? "images/black-check.png" : "images/no-check.png") :
+ "images/no-check-no-border.png"
+ )) +
+ "</div>"
+ ) +
+ "<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a>" +
+ " " +
+ "<span class='exhibit-flowingFacet-value-count'>(" + count + ")</span>"
+ );
+
+ dom.elmt.className = selected ? "exhibit-flowingFacet-value exhibit-flowingFacet-value-selected" : "exhibit-flowingFacet-value";
+ if (typeof label == "string") {
+ dom.elmt.title = label;
+ dom.inner.innerHTML = label;
+ if (color != null) {
+ dom.inner.style.color = color;
+ }
+ } else {
+ dom.inner.appendChild(label);
+ if (color != null) {
+ label.style.color = color;
+ }
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.elmt, "click", onSelectOnly, SimileAjax.WindowManager.getBaseLayer());
+ if (facetHasSelection) {
+ SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild, "click", onSelect, SimileAjax.WindowManager.getBaseLayer());
+ }
+ return dom.elmt;
+};
+
+Exhibit.FacetUtilities.constructHierarchicalFacetItem = function(
+ label,
+ count,
+ color,
+ selected,
+ hasChildren,
+ expanded,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ onToggleChildren,
+ uiContext
+) {
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ "<div class='exhibit-facet-value-count'>" + count + "</div>" +
+ "<div class='exhibit-facet-value-inner' id='inner'>" +
+ ( "<div class='exhibit-facet-value-checkbox'>&#160;" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix +
+ ( facetHasSelection ?
+ (selected ? "images/black-check.png" : "images/no-check.png") :
+ "images/no-check-no-border.png"
+ )) +
+ "</div>"
+ ) +
+ "<a class='exhibit-facet-value-link' href='javascript:{}' id='link'></a>" +
+ ( hasChildren ?
+ ( "<a class='exhibit-facet-value-children-toggle' href='javascript:{}' id='toggle'>" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix + "images/down-arrow.png") +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix + "images/right-arrow.png") +
+ "</a>"
+ ) :
+ ""
+ ) +
+ "</div>" +
+ (hasChildren ? "<div class='exhibit-facet-childrenContainer' id='childrenContainer'></div>" : "")
+ );
+ dom.elmt.className = selected ? "exhibit-facet-value exhibit-facet-value-selected" : "exhibit-facet-value";
+ if (typeof label == "string") {
+ dom.elmt.title = label;
+ dom.link.appendChild(document.createTextNode(label));
+ if (color != null) {
+ dom.link.style.color = color;
+ }
+ } else {
+ dom.link.appendChild(label);
+ if (color != null) {
+ label.style.color = color;
+ }
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.elmt, "click", onSelectOnly, SimileAjax.WindowManager.getBaseLayer());
+ if (facetHasSelection) {
+ SimileAjax.WindowManager.registerEvent(dom.inner.firstChild, "click", onSelect, SimileAjax.WindowManager.getBaseLayer());
+ }
+ if (hasChildren) {
+ dom.showChildren = function(show) {
+ dom.childrenContainer.style.display = show ? "block" : "none";
+ dom.toggle.childNodes[0].style.display = show ? "inline" : "none";
+ dom.toggle.childNodes[1].style.display = show ? "none" : "inline";
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.toggle, "click", onToggleChildren, SimileAjax.WindowManager.getBaseLayer());
+ dom.showChildren(expanded);
+ }
+
+ return dom;
+};
+
+Exhibit.FacetUtilities.constructFlowingHierarchicalFacetItem = function(
+ label,
+ count,
+ color,
+ selected,
+ hasChildren,
+ expanded,
+ facetHasSelection,
+ onSelect,
+ onSelectOnly,
+ onToggleChildren,
+ uiContext
+) {
+ if (Exhibit.params.safe) {
+ label = Exhibit.Formatter.encodeAngleBrackets(label);
+ }
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ "div",
+ ( "<div class='exhibit-flowingFacet-value-checkbox'>" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix +
+ ( facetHasSelection ?
+ (selected ? "images/black-check.png" : "images/no-check.png") :
+ "images/no-check-no-border.png"
+ )) +
+ "</div>"
+ ) +
+ "<a class='exhibit-flowingFacet-value-link' href='javascript:{}' id='inner'></a>" +
+ " " +
+ "<span class='exhibit-flowingFacet-value-count'>(" + count + ")</span>" +
+ ( hasChildren ?
+ ( "<a class='exhibit-flowingFacet-value-children-toggle' href='javascript:{}' id='toggle'>" +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix + "images/down-arrow.png") +
+ SimileAjax.Graphics.createTranslucentImageHTML(
+ Exhibit.urlPrefix + "images/right-arrow.png") +
+ "</a>"
+ ) :
+ ""
+ ) +
+ (hasChildren ? "<div class='exhibit-flowingFacet-childrenContainer' id='childrenContainer'></div>" : "")
+ );
+
+ dom.elmt.className = selected ? "exhibit-flowingFacet-value exhibit-flowingFacet-value-selected" : "exhibit-flowingFacet-value";
+ if (typeof label == "string") {
+ dom.elmt.title = label;
+ dom.inner.appendChild(document.createTextNode(label));
+ if (color != null) {
+ dom.inner.style.color = color;
+ }
+ } else {
+ dom.inner.appendChild(label);
+ if (color != null) {
+ label.style.color = color;
+ }
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.elmt, "click", onSelectOnly, SimileAjax.WindowManager.getBaseLayer());
+ if (facetHasSelection) {
+ SimileAjax.WindowManager.registerEvent(dom.elmt.firstChild, "click", onSelect, SimileAjax.WindowManager.getBaseLayer());
+ }
+ if (hasChildren) {
+ dom.showChildren = function(show) {
+ dom.childrenContainer.style.display = show ? "block" : "none";
+ dom.toggle.childNodes[0].style.display = show ? "inline" : "none";
+ dom.toggle.childNodes[1].style.display = show ? "none" : "inline";
+ }
+
+ SimileAjax.WindowManager.registerEvent(dom.toggle, "click", onToggleChildren, SimileAjax.WindowManager.getBaseLayer());
+ dom.showChildren(expanded);
+ }
+
+ return dom;
+};
+
+
+/*======================================================================
+ * Cache for item/value mapping
+ *======================================================================
+ */
+
+Exhibit.FacetUtilities.Cache = function(database, collection, expression) {
+ var self = this;
+
+ this._database = database;
+ this._collection = collection;
+ this._expression = expression;
+
+ this._listener = {
+ onRootItemsChanged: function() {
+ if ("_itemToValue" in self) {
+ delete self._itemToValue;
+ }
+ if ("_valueToItem" in self) {
+ delete self._valueToItem;
+ }
+ if ("_missingItems" in self) {
+ delete self._missingItems;
+ }
+ }
+ };
+ collection.addListener(this._listener);
+}
+
+Exhibit.FacetUtilities.Cache.prototype.dispose = function() {
+ this._collection.removeListener(this._listener);
+ this._collection = null;
+ this._listener = null;
+
+ this._itemToValue = null;
+ this._valueToItem = null;
+ this._missingItems = null;
+}
+
+Exhibit.FacetUtilities.Cache.prototype.getItemsFromValues = function(values, filter) {
+ var set;
+ if (this._expression.isPath()) {
+ set = this._expression.getPath().walkBackward(
+ values,
+ "item",
+ filter,
+ this._database
+ ).getSet();
+ } else {
+ this._buildMaps();
+
+ set = new Exhibit.Set();
+
+ var valueToItem = this._valueToItem;
+ values.visit(function(value) {
+ if (value in valueToItem) {
+ var itemA = valueToItem[value];
+ for (var i = 0; i < itemA.length; i++) {
+ var item = itemA[i];
+ if (filter.contains(item)) {
+ set.add(item);
+ }
+ }
+ }
+ });
+ }
+ return set;
+}
+
+Exhibit.FacetUtilities.Cache.prototype.getItemsMissingValue = function(filter, results) {
+ this._buildMaps();
+
+ results = results || new Exhibit.Set();
+
+ var missingItems = this._missingItems;
+ filter.visit(function(item) {
+ if (item in missingItems) {
+ results.add(item);
+ }
+ });
+ return results;
+}
+
+Exhibit.FacetUtilities.Cache.prototype.getValueCountsFromItems = function(items) {
+ var entries = [];
+ var database = this._database;
+ var valueType = "text";
+
+ if (this._expression.isPath()) {
+ var path = this._expression.getPath();
+ var facetValueResult = path.walkForward(items, "item", database);
+ valueType = facetValueResult.valueType;
+
+ if (facetValueResult.size > 0) {
+ facetValueResult.forEachValue(function(facetValue) {
+ var itemSubcollection = path.evaluateBackward(facetValue, valueType, items, database);
+ entries.push({ value: facetValue, count: itemSubcollection.size });
+ });
+ }
+ } else {
+ this._buildMaps();
+
+ valueType = this._valueType;
+ for (var value in this._valueToItem) {
+ var itemA = this._valueToItem[value];
+ var count = 0;
+ for (var i = 0; i < itemA.length; i++) {
+ if (items.contains(itemA[i])) {
+ count++;
+ }
+ }
+
+ if (count > 0) {
+ entries.push({ value: value, count: count });
+ }
+ }
+ }
+ return { entries: entries, valueType: valueType };
+}
+
+Exhibit.FacetUtilities.Cache.prototype.getValuesFromItems = function(items) {
+ if (this._expression.isPath()) {
+ return this._expression.getPath().walkForward(items, "item", database).getSet();
+ } else {
+ this._buildMaps();
+
+ var set = new Exhibit.Set();
+ var itemToValue = this._itemToValue;
+ items.visit(function(item) {
+ if (item in itemToValue) {
+ var a = itemToValue[item];
+ for (var i = 0; i < a.length; i++) {
+ set.add(a[i]);
+ }
+ }
+ });
+
+ return set;
+ }
+}
+
+Exhibit.FacetUtilities.Cache.prototype.countItemsMissingValue = function(items) {
+ this._buildMaps();
+
+ var count = 0;
+ for (var item in this._missingItems) {
+ if (items.contains(item)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+Exhibit.FacetUtilities.Cache.prototype._buildMaps = function() {
+ if (!("_itemToValue" in this)) {
+ var itemToValue = {};
+ var valueToItem = {};
+ var missingItems = {};
+ var valueType = "text";
+
+ var insert = function(x, y, map) {
+ if (x in map) {
+ map[x].push(y);
+ } else {
+ map[x] = [ y ];
+ }
+ };
+
+ var expression = this._expression;
+ var database = this._database;
+
+ this._collection.getAllItems().visit(function(item) {
+ var results = expression.evaluateOnItem(item, database);
+ if (results.values.size() > 0) {
+ valueType = results.valueType;
+ results.values.visit(function(value) {
+ insert(item, value, itemToValue);
+ insert(value, item, valueToItem);
+ });
+ } else {
+ missingItems[item] = true;
+ }
+ });
+
+ this._itemToValue = itemToValue;
+ this._valueToItem = valueToItem;
+ this._missingItems = missingItems;
+ this._valueType = valueType;
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/set.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/set.js
new file mode 100644
index 00000000..9277e7df
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/set.js
@@ -0,0 +1,98 @@
+/*==================================================
+ * Exhibit.Set
+ *==================================================
+ */
+
+Exhibit.Set = function ( a ) {
+ this._hash = {};
+ this._count = 0;
+
+ if ( a instanceof Array ) {
+ for ( var i = 0; i < a.length; i++ ) {
+ this.add( a[i] );
+ }
+ } else if ( a instanceof Exhibit.Set ) {
+ this.addSet( a );
+ }
+};
+
+Exhibit.Set.prototype.add = function(o) {
+ if (!(o in this._hash)) {
+ this._hash[o] = true;
+ this._count++;
+ return true;
+ }
+ return false;
+}
+
+Exhibit.Set.prototype.addSet = function(set) {
+ for (var o in set._hash) {
+ this.add(o);
+ }
+}
+
+Exhibit.Set.prototype.remove = function(o) {
+ if (o in this._hash) {
+ delete this._hash[o];
+ this._count--;
+ return true;
+ }
+ return false;
+}
+
+Exhibit.Set.prototype.removeSet = function(set) {
+ for (var o in set._hash) {
+ this.remove(o);
+ }
+}
+
+Exhibit.Set.prototype.retainSet = function(set) {
+ for (var o in this._hash) {
+ if (!set.contains(o)) {
+ delete this._hash[o];
+ this._count--;
+ }
+ }
+}
+
+Exhibit.Set.prototype.contains = function(o) {
+ return (o in this._hash);
+}
+
+Exhibit.Set.prototype.size = function() {
+ return this._count;
+}
+
+Exhibit.Set.prototype.toArray = function() {
+ var a = [];
+ for (var o in this._hash) {
+ a.push(o);
+ }
+ return a;
+}
+
+Exhibit.Set.prototype.visit = function(f) {
+ for (var o in this._hash) {
+ if (f(o) == true) {
+ break;
+ }
+ }
+}
+
+Exhibit.Set.createIntersection = function(set1, set2, result) {
+ var set = (result) ? result : new Exhibit.Set();
+ var setA, setB;
+ if (set1.size() < set2.size()) {
+ setA = set1;
+ setB = set2;
+ } else {
+ setA = set2;
+ setB = set1;
+ }
+ setA.visit(function (v) {
+ if (setB.contains(v)) {
+ set.add(v);
+ }
+ });
+ return set;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/settings.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/settings.js
new file mode 100644
index 00000000..e0d7ed65
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/settings.js
@@ -0,0 +1,439 @@
+/*==================================================
+ * Exhibit.SettingsUtilities
+ *
+ * Utilities for various parts of Exhibit to
+ * collect their settings.
+ *==================================================
+ */
+Exhibit.SettingsUtilities = new Object();
+
+/*--------------------------------------------------
+ * Static settings
+ *--------------------------------------------------
+ */
+Exhibit.SettingsUtilities.collectSettings = function(config, specs, settings) {
+ Exhibit.SettingsUtilities._internalCollectSettings(
+ function(field) { return config[field]; },
+ specs,
+ settings
+ );
+};
+
+Exhibit.SettingsUtilities.collectSettingsFromDOM = function(configElmt, specs, settings) {
+ Exhibit.SettingsUtilities._internalCollectSettings(
+ function(field) { return Exhibit.getAttribute(configElmt, field); },
+ specs,
+ settings
+ );
+};
+
+Exhibit.SettingsUtilities._internalCollectSettings = function(f, specs, settings) {
+ for (var field in specs) {
+ var spec = specs[field];
+ var name = field;
+ if ("name" in spec) {
+ name = spec.name;
+ }
+ if (!(name in settings) && "defaultValue" in spec) {
+ settings[name] = spec.defaultValue;
+ }
+
+ var value = f(field);
+ if (value == null) {
+ continue;
+ }
+
+ if (typeof value == "string") {
+ value = value.trim();
+ if (value.length == 0) {
+ continue;
+ }
+ }
+
+ var type = "text";
+ if ("type" in spec) {
+ type = spec.type;
+ }
+
+ var dimensions = 1;
+ if ("dimensions" in spec) {
+ dimensions = spec.dimensions;
+ }
+
+ try {
+ if (dimensions > 1) {
+ var separator = ",";
+ if ("separator" in spec) {
+ separator = spec.separator;
+ }
+
+ var a = value.split(separator);
+ if (a.length != dimensions) {
+ throw new Error("Expected a tuple of " + dimensions + " dimensions separated with " + separator + " but got " + value);
+ } else {
+ for (var i = 0; i < a.length; i++) {
+ a[i] = Exhibit.SettingsUtilities._parseSetting(a[i].trim(), type, spec);
+ }
+
+ settings[name] = a;
+ }
+ } else {
+ settings[name] = Exhibit.SettingsUtilities._parseSetting(value, type, spec);
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+};
+
+Exhibit.SettingsUtilities._parseSetting = function(s, type, spec) {
+ var sType = typeof s;
+ if (type == "text") {
+ return s;
+ } else if (type == "float") {
+ if (sType == "number") {
+ return s;
+ } else if (sType == "string") {
+ var f = parseFloat(s);
+ if (!isNaN(f)) {
+ return f;
+ }
+ }
+ throw new Error("Expected a floating point number but got " + s);
+ } else if (type == "int") {
+ if (sType == "number") {
+ return Math.round(s);
+ } else if (sType == "string") {
+ var n = parseInt(s);
+ if (!isNaN(n)) {
+ return n;
+ }
+ }
+ throw new Error("Expected an integer but got " + s);
+ } else if (type == "boolean") {
+ if (sType == "boolean") {
+ return s;
+ } else if (sType == "string") {
+ s = s.toLowerCase();
+ if (s == "true") {
+ return true;
+ } else if (s == "false") {
+ return false;
+ }
+ }
+ throw new Error("Expected either 'true' or 'false' but got " + s);
+ } else if (type == "function") {
+ if (sType == "function") {
+ return s;
+ } else if (sType == "string") {
+ try {
+ var f = eval(s);
+ if (typeof f == "function") {
+ return f;
+ }
+ } catch (e) {
+ // silent
+ }
+ }
+ throw new Error("Expected a function or the name of a function but got " + s);
+ } else if (type == "enum") {
+ var choices = spec.choices;
+ for (var i = 0; i < choices.length; i++) {
+ if (choices[i] == s) {
+ return s;
+ }
+ }
+ throw new Error("Expected one of " + choices.join(", ") + " but got " + s);
+ } else {
+ throw new Error("Unknown setting type " + type);
+ }
+};
+
+/*--------------------------------------------------
+ * Accessors
+ *--------------------------------------------------
+ */
+Exhibit.SettingsUtilities.createAccessors = function(config, specs, accessors) {
+ Exhibit.SettingsUtilities._internalCreateAccessors(
+ function(field) { return config[field]; },
+ specs,
+ accessors
+ );
+};
+
+Exhibit.SettingsUtilities.createAccessorsFromDOM = function(configElmt, specs, accessors) {
+ Exhibit.SettingsUtilities._internalCreateAccessors(
+ function(field) { return Exhibit.getAttribute(configElmt, field); },
+ specs,
+ accessors
+ );
+};
+
+Exhibit.SettingsUtilities._internalCreateAccessors = function(f, specs, accessors) {
+ for (var field in specs) {
+ var spec = specs[field];
+ var accessorName = spec.accessorName;
+ var accessor = null;
+ var isTuple = false;
+
+ var createOneAccessor = function(spec2) {
+ isTuple = false;
+ if ("bindings" in spec2) {
+ return Exhibit.SettingsUtilities._createBindingsAccessor(f, spec2.bindings);
+ } else if ("bindingNames" in spec2) {
+ isTuple = true;
+ return Exhibit.SettingsUtilities._createTupleAccessor(f, spec2);
+ } else {
+ return Exhibit.SettingsUtilities._createElementalAccessor(f, spec2);
+ }
+ };
+
+ if ("alternatives" in spec) {
+ var alternatives = spec.alternatives;
+ for (var i = 0; i < alternatives.length; i++) {
+ accessor = createOneAccessor(alternatives[i]);
+ if (accessor != null) {
+ break;
+ }
+ }
+ } else {
+ accessor = createOneAccessor(spec);
+ }
+
+ if (accessor != null) {
+ accessors[accessorName] = accessor;
+ } else if (!(accessorName in accessors)) {
+ accessors[accessorName] = function(value, database, visitor) {};
+ }
+ }
+};
+
+Exhibit.SettingsUtilities._createBindingsAccessor = function(f, bindingSpecs) {
+ var bindings = [];
+ for (var i = 0; i < bindingSpecs.length; i++) {
+ var bindingSpec = bindingSpecs[i];
+ var accessor = null;
+ var isTuple = false;
+
+ if ("bindingNames" in bindingSpec) {
+ isTuple = true;
+ accessor = Exhibit.SettingsUtilities._createTupleAccessor(f, bindingSpec);
+ } else {
+ accessor = Exhibit.SettingsUtilities._createElementalAccessor(f, bindingSpec);
+ }
+
+ if (accessor == null) {
+ if (!("optional" in bindingSpec) || !bindingSpec.optional) {
+ return null;
+ }
+ } else {
+ bindings.push({
+ bindingName: bindingSpec.bindingName,
+ accessor: accessor,
+ isTuple: isTuple
+ });
+ }
+ }
+
+ return function(value, database, visitor) {
+ Exhibit.SettingsUtilities._evaluateBindings(value, database, visitor, bindings);
+ };
+};
+
+Exhibit.SettingsUtilities._createTupleAccessor = function(f, spec) {
+ var value = f(spec.attributeName);
+
+ if (value == null) {
+ return null;
+ }
+
+ if (typeof value == "string") {
+ value = value.trim();
+ if (value.length == 0) {
+ return null;
+ }
+ }
+
+ try {
+ var expression = Exhibit.ExpressionParser.parse(value);
+
+ var parsers = [];
+ var bindingTypes = spec.types;
+ for (var i = 0; i < bindingTypes.length; i++) {
+ parsers.push(Exhibit.SettingsUtilities._typeToParser(bindingTypes[i]));
+ }
+
+ var bindingNames = spec.bindingNames;
+ var separator = ",";
+
+ if ("separator" in spec) {
+
+ separator = spec.separator;
+
+ }
+
+ return function(itemID, database, visitor, tuple) {
+ expression.evaluateOnItem(itemID, database).values.visit(
+ function(v) {
+ var a = v.split(separator);
+ if (a.length == parsers.length) {
+ var tuple2 = {};
+ if (tuple) {
+ for (var n in tuple) {
+ tuple2[n] = tuple[n];
+ }
+ }
+
+ for (var i = 0; i < bindingNames.length; i++) {
+ tuple2[bindingNames[i]] = null;
+ parsers[i](a[i], function(v) { tuple2[bindingNames[i]] = v; });
+ }
+ visitor(tuple2);
+ }
+ }
+ );
+ };
+
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ return null;
+ }
+};
+
+Exhibit.SettingsUtilities._createElementalAccessor = function(f, spec) {
+ var value = f(spec.attributeName);
+
+ if (value == null) {
+ return null;
+ }
+
+ if (typeof value == "string") {
+ value = value.trim();
+ if (value.length == 0) {
+ return null;
+ }
+ }
+
+ var bindingType = "text";
+
+ if ("type" in spec) {
+
+ bindingType = spec.type;
+
+ }
+
+
+ try {
+ var expression = Exhibit.ExpressionParser.parse(value);
+
+ var parser = Exhibit.SettingsUtilities._typeToParser(bindingType);
+
+ return function(itemID, database, visitor) {
+ expression.evaluateOnItem(itemID, database).values.visit(
+ function(v) { return parser(v, visitor); }
+ );
+ };
+
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ return null;
+ }
+}
+
+Exhibit.SettingsUtilities._typeToParser = function(type) {
+ switch (type) {
+ case "text": return Exhibit.SettingsUtilities._textParser;
+ case "url": return Exhibit.SettingsUtilities._urlParser;
+ case "float": return Exhibit.SettingsUtilities._floatParser;
+ case "int": return Exhibit.SettingsUtilities._intParser;
+ case "date": return Exhibit.SettingsUtilities._dateParser;
+ case "boolean": return Exhibit.SettingsUtilities._booleanParser;
+ default:
+ throw new Error("Unknown setting type " + type);
+
+ }
+}
+
+Exhibit.SettingsUtilities._textParser = function(v, f) {
+ return f(v);
+};
+
+Exhibit.SettingsUtilities._floatParser = function(v, f) {
+ var n = parseFloat(v);
+ if (!isNaN(n)) {
+ return f(n);
+ }
+ return false;
+};
+
+Exhibit.SettingsUtilities._intParser = function(v, f) {
+ var n = parseInt(v);
+ if (!isNaN(n)) {
+ return f(n);
+ }
+ return false;
+};
+
+Exhibit.SettingsUtilities._dateParser = function(v, f) {
+ if (v instanceof Date) {
+ return f(v);
+ } else if (typeof v == "number") {
+ var d = new Date(0);
+ d.setUTCFullYear(v);
+ return f(d);
+ } else {
+ var d = SimileAjax.DateTime.parseIso8601DateTime(v.toString());
+ if (d != null) {
+ return f(d);
+ }
+ }
+ return false;
+};
+
+Exhibit.SettingsUtilities._booleanParser = function(v, f) {
+ v = v.toString().toLowerCase();
+ if (v == "true") {
+ return f(true);
+ } else if (v == "false") {
+ return f(false);
+ }
+ return false;
+};
+
+Exhibit.SettingsUtilities._urlParser = function(v, f) {
+ return f(Exhibit.Persistence.resolveURL(v.toString()));
+};
+
+Exhibit.SettingsUtilities._evaluateBindings = function(value, database, visitor, bindings) {
+ var maxIndex = bindings.length - 1;
+ var f = function(tuple, index) {
+ var binding = bindings[index];
+ var visited = false;
+
+ var recurse = index == maxIndex ? function() { visitor(tuple); } : function() { f(tuple, index + 1); };
+ if (binding.isTuple) {
+ /*
+ The tuple accessor will copy existing fields out of "tuple" into a new
+ object and then injects new fields into it before calling the visitor.
+ This is so that the same tuple object is not reused for different
+ tuple values, which would cause old tuples to be overwritten by new ones.
+ */
+ binding.accessor(
+ value,
+ database,
+ function(tuple2) { visited = true; tuple = tuple2; recurse(); },
+ tuple
+ );
+ } else {
+ var bindingName = binding.bindingName;
+ binding.accessor(
+ value,
+ database,
+ function(v) { visited = true; tuple[bindingName] = v; recurse(); }
+ );
+ }
+
+ if (!visited) { recurse(); }
+ };
+ f({}, 0);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/util.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/util.js
new file mode 100644
index 00000000..92721897
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/util.js
@@ -0,0 +1,118 @@
+/*==================================================
+ * Exhibit Utility Functions
+ *==================================================
+ */
+Exhibit.Util = {};
+
+/**
+ * Round a number n to the nearest multiple of precision (any positive value),
+ * such as 5000, 0.1 (one decimal), 1e-12 (twelve decimals), or 1024 (if you'd
+ * want "to the nearest kilobyte" -- so round(66000, 1024) == "65536"). You are
+ * also guaranteed to get the precision you ask for, so round(0, 0.1) == "0.0".
+ */
+Exhibit.Util.round = function(n, precision) {
+ precision = precision || 1;
+ var lg = Math.floor( Math.log(precision) / Math.log(10) );
+ n = (Math.round(n / precision) * precision).toString();
+ var d = n.split(".");
+ if (lg >= 0) {
+ return d[0];
+ }
+
+ lg = -lg;
+ d[1] = (d[1]||"").substring(0, lg);
+ while (d[1].length < lg) {
+ d[1] += "0";
+ }
+ return d.join(".");
+}
+
+
+//=============================================================================
+// Javascript 1.6 Array extensions
+// from Mozilla's compatibility implementations
+//=============================================================================
+
+
+if (!Array.prototype.indexOf)
+{
+ Array.prototype.indexOf = function(elt /*, from*/)
+ {
+ var len = this.length;
+
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0)
+ ? Math.ceil(from)
+ : Math.floor(from);
+ if (from < 0)
+ from += len;
+
+ for (; from < len; from++)
+ {
+ if (from in this &&
+ this[from] === elt)
+ return from;
+ }
+ return -1;
+ };
+}
+
+
+if (!Array.prototype.filter)
+{
+ Array.prototype.filter = function(fun /*, thisp*/)
+ {
+ var len = this.length;
+ if (typeof fun != "function")
+ throw new TypeError();
+
+ var res = new Array();
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++)
+ {
+ if (i in this)
+ {
+ var val = this[i]; // in case fun mutates this
+ if (fun.call(thisp, val, i, this))
+ res.push(val);
+ }
+ }
+
+ return res;
+ };
+}
+
+
+if (!Array.prototype.map) {
+ Array.prototype.map = function(f, thisp) {
+ if (typeof f != "function")
+ throw new TypeError();
+ if (typeof thisp == "undefined") {
+ thisp = this;
+ }
+ var res = [], length = this.length;
+ for (var i = 0; i < length; i++) {
+ if (this.hasOwnProperty(i))
+ res[i] = f.call(thisp, this[i], i, this);
+ }
+ return res;
+ };
+}
+
+
+if (!Array.prototype.forEach)
+{
+ Array.prototype.forEach = function(fun /*, thisp*/)
+ {
+ var len = this.length;
+ if (typeof fun != "function")
+ throw new TypeError();
+
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++)
+ {
+ if (i in this)
+ fun.call(thisp, this[i], i, this);
+ }
+ };
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/views.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/views.js
new file mode 100644
index 00000000..d65ad919
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/scripts/util/views.js
@@ -0,0 +1,124 @@
+/*==================================================
+ * Exhibit.ViewUtilities
+ *
+ * Utilities for views' code.
+ *==================================================
+ */
+Exhibit.ViewUtilities = new Object();
+
+Exhibit.ViewUtilities.openBubbleForItems = function(anchorElmt, arrayOfItemIDs, uiContext) {
+ var coords = SimileAjax.DOM.getPageCoordinates(anchorElmt);
+ var bubble = SimileAjax.Graphics.createBubbleForPoint(
+ coords.left + Math.round(anchorElmt.offsetWidth / 2),
+ coords.top + Math.round(anchorElmt.offsetHeight / 2),
+ uiContext.getSetting("bubbleWidth"), // px
+ uiContext.getSetting("bubbleHeight") // px
+ );
+ Exhibit.ViewUtilities.fillBubbleWithItems(bubble.content, arrayOfItemIDs, uiContext);
+};
+
+Exhibit.ViewUtilities.fillBubbleWithItems = function(bubbleElmt, arrayOfItemIDs, uiContext) {
+ if (bubbleElmt == null) {
+ bubbleElmt = document.createElement("div");
+ }
+
+ if (arrayOfItemIDs.length > 1) {
+ bubbleElmt.className = [ bubbleElmt.className, "exhibit-views-bubbleWithItems" ].join(" ");
+
+ var ul = document.createElement("ul");
+ for (var i = 0; i < arrayOfItemIDs.length; i++) {
+ uiContext.format(arrayOfItemIDs[i], "item", function(elmt) {
+ var li = document.createElement("li");
+ li.appendChild(elmt);
+ ul.appendChild(li);
+ });
+ }
+ bubbleElmt.appendChild(ul);
+ } else {
+ var itemLensDiv = document.createElement("div");
+ var itemLens = uiContext.getLensRegistry().createLens(arrayOfItemIDs[0], itemLensDiv, uiContext);
+ bubbleElmt.appendChild(itemLensDiv);
+ }
+
+ return bubbleElmt;
+};
+
+Exhibit.ViewUtilities.constructPlottingViewDom = function(
+ div,
+ uiContext,
+ showSummary,
+ resizableDivWidgetSettings,
+ legendWidgetSettings
+)
+{
+ var dom = SimileAjax.DOM.createDOMFromString(
+ div,
+ "<div class='exhibit-views-header'>" +
+ (showSummary ? "<div id='collectionSummaryDiv'></div>" : "") +
+ "<div id='unplottableMessageDiv' class='exhibit-views-unplottableMessage'></div>" +
+ "</div>" +
+ "<div id='resizableDiv'></div>" +
+ "<div id='legendDiv'></div>",
+ {}
+ );
+
+ if (showSummary) {
+ dom.collectionSummaryWidget = Exhibit.CollectionSummaryWidget.create(
+ {},
+ dom.collectionSummaryDiv,
+ uiContext
+ );
+ }
+
+ dom.resizableDivWidget = Exhibit.ResizableDivWidget.create(
+ resizableDivWidgetSettings,
+ dom.resizableDiv,
+ uiContext
+ );
+ dom.plotContainer = dom.resizableDivWidget.getContentDiv();
+
+ if (legendWidgetSettings.colorGradient == true) {
+ dom.legendGradientWidget = Exhibit.LegendGradientWidget.create(
+ dom.legendDiv,
+ uiContext
+ );
+ } else {
+ dom.legendWidget = Exhibit.LegendWidget.create(
+ legendWidgetSettings,
+ dom.legendDiv,
+ uiContext
+ );
+ }
+
+ dom.setUnplottableMessage = function(totalCount, unplottableItems) {
+ Exhibit.ViewUtilities._setUnplottableMessage(dom, totalCount, unplottableItems, uiContext);
+ };
+ dom.dispose = function() {
+ if (showSummary) {
+ dom.collectionSummaryWidget.dispose();
+ }
+ dom.resizableDivWidget.dispose();
+ dom.legendWidget.dispose();
+ };
+
+ return dom;
+};
+
+Exhibit.ViewUtilities._setUnplottableMessage = function(dom, totalCount, unplottableItems, uiContext) {
+ var div = dom.unplottableMessageDiv;
+ if (unplottableItems.length == 0) {
+ div.style.display = "none";
+ } else {
+ div.innerHTML = "";
+
+ var dom = SimileAjax.DOM.createDOMFromString(
+ div,
+ Exhibit.ViewUtilities.l10n.unplottableMessageFormatter(totalCount, unplottableItems, uiContext),
+ {}
+ );
+ SimileAjax.WindowManager.registerEvent(dom.unplottableCountLink, "click", function(elmt, evt, target) {
+ Exhibit.ViewUtilities.openBubbleForItems(elmt, unplottableItems, uiContext);
+ });
+ div.style.display = "block";
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/browse-panel.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/browse-panel.css
new file mode 100644
index 00000000..eea7f8c3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/browse-panel.css
@@ -0,0 +1,20 @@
+/*==================================================
+ * Browse Panel styles
+ *==================================================
+ */
+div.exhibit-browsePanel {
+}
+
+div.exhibit-browsePanel-notConfigureMessage {
+ border: 1px solid #604800;
+ padding: 1em;
+ background: #FFFFE0;
+ text-align: center;
+}
+
+div.exhibit-browsePanel-logoContainer {
+ text-align: center;
+ margin: 1em;
+ clear: both;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/exhibit.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/exhibit.css
new file mode 100644
index 00000000..ff65eb7d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/exhibit.css
@@ -0,0 +1,170 @@
+/*==================================================
+ * Exhibit styles
+ *
+ * Note that almost all CSS code is in themes.
+ *==================================================
+ */
+.exhibit-ui-protection div {
+ margin: 0;
+ padding: 0;
+}
+.exhibit-ui-protection table {
+ font-size: 100%;
+}
+.exhibit-ui-protection tr {
+ vertical-align: top;
+}
+a img {
+ border: none;
+}
+
+a.exhibit-action,
+a.exhibit-action:link,
+a.exhibit-action:active,
+a.exhibit-action:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+}
+a.exhibit-action:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-action-disabled,
+a.exhibit-action-disabled:link,
+a.exhibit-action-disabled:active,
+a.exhibit-action-disabled:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted;
+ cursor: pointer;
+ opacity: 0.5;
+}
+a.exhibit-action-disabled:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+a.exhibit-item,
+a.exhibit-item:link,
+a.exhibit-item:active,
+a.exhibit-item:visited {
+ text-decoration: none;
+ border-bottom: 1px dotted red;
+ cursor: pointer;
+}
+a.exhibit-item:hover {
+ border-bottom: 1px solid;
+ cursor: pointer;
+}
+
+span.exhibit-value {
+}
+
+/*
+ * Menu Popup
+ */
+div.exhibit-menu-popup {
+ position: absolute;
+ width: 15em;
+ z-index: 1000;
+ background: #FFFFE0;
+ border: 1px solid #aaa;
+}
+
+a.exhibit-menu-item {
+ text-decoration: none;
+}
+
+a.exhibit-menu-item > div {
+ padding: 2px 2px 2px 20px;
+ text-indent: -18px;
+}
+
+a:hover.exhibit-menu-item > div {
+ background: #DFDFC8;
+}
+
+a.exhibit-menu-item div img {
+ vertical-align: middle;
+ margin-right: 2px;
+}
+
+div.exhibit-menu-section {
+ padding: 2px;
+ font-weight: bold;
+}
+
+/*
+ * Copy Button and Dialog Box
+ */
+button.exhibit-copyButton, button.exhibit-button {
+ border: 1px dashed;
+ cursor: pointer;
+ margin: 2px;
+}
+button:hover.exhibit-copyButton, button.exhibit-button:hover {
+ background: white;
+ border: 1px dashed blue;
+ color: blue;
+ cursor: pointer;
+}
+
+div.exhibit-copyDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-copyDialog textarea {
+ width: 100%;
+ font-size: 90%;
+ color: #888;
+}
+
+div.exhibit-copyDialog button {
+ float: right;
+}
+
+/*
+ * Focus Dialog Box
+ */
+div.exhibit-focusDialog {
+ position: absolute;
+ z-index: 1000;
+ background: #B2E8FF;
+ border: 1px solid #aaa;
+ padding: 2em;
+ left: 25%;
+ right: 25%;
+}
+
+div.exhibit-focusDialog-lensContainer {
+}
+
+div.exhibit-focusDialog-controls {
+ margin: 1em;
+ text-align: center;
+}
+
+/*
+ * Busy indicator
+ */
+.exhibit-busyIndicator {
+ position: absolute;
+ left: 35%;
+ width: 30%;
+ z-index: 1000;
+}
+.exhibit-busyIndicator-content {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.exhibit-busyIndicator-content img {
+ vertical-align: middle;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/lens.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/lens.css
new file mode 100644
index 00000000..9ae0c4b7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/lens.css
@@ -0,0 +1,32 @@
+div.exhibit-lens {
+ border: 1px solid #aaa;
+ margin-bottom: 1em;
+}
+
+div.exhibit-lens-title {
+ font-weight: bold;
+ background: #eee;
+ padding: 2px;
+}
+
+.exhibit-lens-copyButton {
+ float: right;
+}
+
+div.exhibit-lens-body {
+ padding: 0.3em;
+}
+
+table.exhibit-lens-properties {
+}
+
+tr.exhibit-lens-property {
+}
+
+td.exhibit-lens-property-name {
+ color: #888;
+}
+
+td.exhibit-lens-property-values {
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/facets.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/facets.css
new file mode 100644
index 00000000..1f67c84c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/facets.css
@@ -0,0 +1,327 @@
+/*==================================================
+ * Facet box
+ *==================================================
+ */
+div.exhibit-facet {
+ position: relative;
+}
+
+div.exhibit-facet-header {
+ padding: 2px;
+}
+div.exhibit-facet-header-filterControl {
+ float: right;
+ width: 2em;
+ display: none;
+ cursor: pointer;
+}
+div.exhibit-facet-header-filterControl img {
+ vertical-align: text-bottom;
+}
+
+img.exhibit-facet-header-collapse {
+ border: 1px;
+ cursor: pointer;
+ padding-right: 3px;
+}
+
+span.exhibit-facet-header-title {
+ font-weight: bold;
+}
+span.exhibit-facet-header-detail {
+ color: #888;
+ padding-left: 0.5em;
+}
+
+div.exhibit-facet-body-frame {
+ clear: both;
+}
+
+div.exhibit-facet-body {
+ border: 1px solid #ddd;
+ height: 10em;
+ overflow: auto;
+}
+
+/*==================================================
+ * Facet value
+ *==================================================
+ */
+
+div.exhibit-facet-value {
+ cursor: pointer;
+ padding: 2px 0px;
+ clear: both;
+}
+div.exhibit-facet-value-selected {
+ font-weight: bold;
+}
+
+div.exhibit-facet-value-count {
+ float: left;
+ width: 2em;
+ text-align: right;
+ color: #aaa;
+}
+
+div.exhibit-facet-value-inner {
+ padding-left: 2.5em;
+}
+
+a.exhibit-facet-value-link {
+ text-decoration: none;
+}
+a.exhibit-facet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-facet-value-checkbox {
+ float: right;
+}
+
+span.exhibit-facet-value-missingThisField {
+ color: #888;
+}
+
+/*==================================================
+ * Flowing facet box
+ *==================================================
+ */
+div.exhibit-flowingFacet {
+ clear: both;
+}
+
+div.exhibit-flowingFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-flowingFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-flowingFacet-body {
+}
+
+/*==================================================
+ * Flowing facet value
+ *==================================================
+ */
+
+div.exhibit-flowingFacet-value {
+ cursor: pointer;
+ clear: both;
+ position: relative;
+ margin-left: 20px;
+}
+
+a.exhibit-flowingFacet-value-link {
+ text-decoration: none;
+}
+a.exhibit-flowingFacet-value-link:hover {
+ text-decoration: underline;
+}
+
+div.exhibit-flowingFacet-value-selected {
+ font-weight: bold;
+}
+
+span.exhibit-flowingFacet-value-count {
+ color: #aaa;
+}
+
+div.exhibit-flowingFacet-value-checkbox {
+ position: absolute;
+ left: -20px;
+ padding: 0;
+ margin: 0;
+}
+
+/*==================================================
+ * Text search facet
+ *==================================================
+ */
+div.exhibit-text-facet {
+}
+
+div.exhibit-text-facet input {
+ width: 100%;
+}
+
+/*==================================================
+ * Cloud facet
+ *==================================================
+ */
+div.exhibit-cloudFacet {
+ clear: both;
+}
+
+div.exhibit-cloudFacet-header {
+ padding: 2px 0px;
+}
+
+span.exhibit-cloudFacet-header-title {
+ font-weight: bold;
+}
+
+div.exhibit-cloudFacet-body {
+ padding: 0.5em;
+ border: 1px solid #aaa;
+}
+
+span.exhibit-cloudFacet-value {
+ cursor: pointer;
+}
+
+span.exhibit-cloudFacet-value-selected {
+ text-decoration: underline;
+ background: yellow;
+}
+
+/*==================================================
+ * Hierarchical facet
+ *==================================================
+ */
+
+a.exhibit-facet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-facet-value-children-toggle:hover {
+ background: #eee;
+}
+
+a.exhibit-flowingFacet-value-children-toggle {
+ padding: 0px 5px;
+}
+a.exhibit-flowingFacet-value-children-toggle:hover {
+ background: #eee;
+}
+
+div.exhibit-flowingFacet-childrenContainer {
+}
+
+div.exhibit-facet-childrenContainer {
+ padding-left: 16px;
+}
+
+/*==================================================
+ * Slider facet
+ *==================================================
+ */
+
+div.exhibit-slider {
+ font-size: 0; /* IE sucks */
+ padding-left: 10px;
+}
+
+div.exhibit-slider-bar {
+ background: #000;
+ margin: 5px 0 15px 0;
+ position: relative;
+}
+
+div.exhibit-slider-bar2 {
+ background: #eee;
+ line-height: 0;
+ margin: 15px 10px 10px 5px;
+ height: 150px;
+ width: 20px;
+ position: relative;
+}
+
+div.exhibit-slider-handle {
+ cursor: pointer;
+ float: left;
+ height: 19px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 12px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram {
+ background: #eee;
+}
+
+div.exhibit-slider-handle2 {
+ cursor: pointer;
+ float: left;
+ height: 12px;
+ left: 0px;
+ position: absolute;
+ top: 0px;
+ width: 19px;
+ z-index: 1;
+}
+
+div.exhibit-slider-histogram div {
+ background: #999;
+}
+
+div.exhibit-slider-display {
+ font-size: 16px;
+}
+
+.exhibit-slider-display input {
+ background: #eee;
+ font-size: 10px;
+ width: 40px;
+}
+
+/*==================================================
+ * Image facet
+ *==================================================
+ */
+.inline-block {
+ display: -moz-inline-box;
+ display: inline-block;
+}
+
+.exhibit-imageFacet-value, .exhibit-imageFacet-value div, .exhibit-imageFacet-value img {
+ margin: 0px;
+ padding: 0px;
+}
+
+.exhibit-imageFacet-value div.wrapper {
+ margin: 3px;
+ padding: 6px;
+ padding-bottom: 10px;
+ text-align: right;
+ vertical-align: bottom;
+ cursor: pointer;
+ position: relative;
+}
+
+.exhibit-imageFacet-value .countDiv div.text {
+ position: absolute;
+ bottom: .1em;
+ left: .3em;
+}
+.exhibit-imageFacet-value .countDiv {
+ position: absolute;
+ border: 1px solid black;
+ bottom: 0px;
+ right: 5px;
+ width: 2em;
+ height: 2em;
+ font-size: 6pt;
+}
+
+div.countBackground { /* this class makes a window partially transparent */
+ background-color: #FF9000;
+ clear: both;
+ width: 100%;
+ height: 100%;
+ opacity: .5; /* Standard style for transparency */
+ -moz-opacity: .5; /* Transparency for older Mozillas */
+ filter: alpha(opacity=50); /* Transparency for IE */
+}
+
+
+.exhibit-imageFacet-value-selected img {
+ background: #fcc;
+}
+
+ .exhibit-imageFacet-value-selected {
+ background: #fcc;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/views.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/views.css
new file mode 100644
index 00000000..d576f84f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/util/views.css
@@ -0,0 +1,104 @@
+/*==================================================
+ * Common styles for views
+ *==================================================
+ */
+div.exhibit-views-unplottableMessage {
+ padding: 1em;
+ text-align: center;
+}
+.exhibit-views-unplottableCount {
+ font-weight: bold;
+}
+.exhibit-views-totalCount {
+}
+
+div.exhibit-views-bubbleWithItems {
+}
+
+div.exhibit-collectionView {
+}
+
+div.exhibit-collectionView-header {
+}
+span.exhibit-collectionView-header-count {
+ font-size: 200%;
+}
+span.exhibit-collectionView-header-types {
+ padding-left: 0.5em;
+}
+span.exhibit-collectionView-header-details {
+ padding-left: 0.5em;
+ color: #888;
+}
+div.exhibit-collectionView-header-sortControls {
+ text-align: center;
+ margin: 1em 0;
+}
+.exhibit-collectionView-header-groupControls {
+ cursor: pointer;
+}
+.exhibit-collectionView-header-duplicateControls {
+ cursor: pointer;
+}
+
+div.exhibit-collectionView-body {
+}
+
+div.exhibit-collectionView-group {
+}
+
+span.exhibit-collectionView-group-count {
+}
+
+div.exhibit-collectionView-group-content {
+ margin-left: 1em;
+}
+
+div.exhibit-collectionView-group h1 {
+ font-size: 150%;
+ margin: 1em 0;
+}
+
+div.exhibit-collectionView-group h2 {
+ font-size: 120%;
+ margin: 0.5em 0;
+}
+
+.exhibit-collectionView-group h3 {
+}
+
+div.exhibit-collectionView-footer {
+ clear: both;
+ text-align: center;
+ margin: 2em 0;
+}
+
+div.exhibit-collectionView-pagingControls {
+ margin: 1em 0;
+ text-align: center;
+}
+
+.exhibit-collectionView-pagingControls-currentPage {
+ padding: 0px 0.5em;
+ font-weight: bold;
+}
+
+.exhibit-collectionView-pagingControls-page {
+ padding: 0px 0.5em;
+}
+
+ul.exhibit-collectionView-pagingControls {
+ clear: both;
+ margin: 2em 0;
+ text-align: center;
+}
+ul.exhibit-collectionView-pagingControls li {
+ list-style-type: none;
+ display: inline;
+}
+ul.exhibit-collectionView-pagingControls li a {
+ border: 1px solid #90C2E1;
+ background: #DFEDF7;
+ padding: 2px 5px;
+ text-decoration: none;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tabular-view.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tabular-view.css
new file mode 100644
index 00000000..6706d242
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tabular-view.css
@@ -0,0 +1,28 @@
+table.exhibit-tabularView-body {
+ width: 100%;
+}
+
+.exhibit-tabularView-columnHeader {
+ cursor: pointer;
+ white-space: pre;
+}
+
+.exhibit-tabularView-columnHeader-sorted {
+ cursor: pointer;
+ white-space: pre;
+}
+
+div.exhibit-tabularView-pagingControls {
+ margin: 1em 0;
+ text-align: center;
+}
+
+.exhibit-tabularView-pagingControls-currentPage {
+ padding: 0px 0.5em;
+ font-weight: bold;
+}
+
+.exhibit-tabularView-pagingControls-page {
+ padding: 0px 0.5em;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/thumbnail-view.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/thumbnail-view.css
new file mode 100644
index 00000000..b6ccb12f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/thumbnail-view.css
@@ -0,0 +1,14 @@
+div.exhibit-thumbnailView-group {
+ clear: both;
+}
+
+div.exhibit-thumbnailView-body {
+}
+
+div.exhibit-thumbnailView-itemContainer {
+ float: left;
+}
+
+div.exhibit-thumbnailView-itemContainer-IE {
+ float: left;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tile-view.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tile-view.css
new file mode 100644
index 00000000..d02d08fc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/tile-view.css
@@ -0,0 +1,12 @@
+table.exhibit-tileView-body {
+ width: 100%;
+}
+
+.exhibit-tileView-body > tbody > tr > td:first-child {
+ width: 3em;
+ text-align: right;
+ color: #aaa
+}
+
+td.exhibit-tileView-itemIndex {
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/view-panel.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/view-panel.css
new file mode 100644
index 00000000..ff5fc3fa
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/views/view-panel.css
@@ -0,0 +1,25 @@
+/*==================================================
+ * View Panel styles
+ *==================================================
+ */
+div.exhibit-viewPanel {
+}
+
+div.exhibit-viewPanel-viewSelection {
+ text-align: center;
+}
+
+span.exhibit-viewPanel-viewSelection-view {
+ text-transform: uppercase;
+ cursor: pointer;
+}
+
+span.exhibit-viewPanel-viewSelection-selectedView {
+ text-transform: uppercase;
+ font-weight: bold;
+ border-bottom: 3px solid red;
+}
+
+div.exhibit-viewPanel-viewContainer {
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/collection-summary-widget.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/collection-summary-widget.css
new file mode 100644
index 00000000..a51eec6d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/collection-summary-widget.css
@@ -0,0 +1,11 @@
+/*==================================================
+ * Collection Summary Widget styles
+ *==================================================
+ */
+div.exhibit-collectionSummaryWidget {
+}
+span.exhibit-collectionSummaryWidget-count {
+ font-size: 200%;
+}
+span.exhibit-collectionSummaryWidget-results {
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/legend-widget.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/legend-widget.css
new file mode 100644
index 00000000..05a5744d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/legend-widget.css
@@ -0,0 +1,14 @@
+div.exhibit-legendWidget {
+ margin: 1em 0;
+ text-align: center;
+ line-height: 2em;
+}
+div.exhibit-legendWidget-entry {
+}
+span.exhibit-legendWidget-entry-title {
+ font-weight: bold;
+}
+span.exhibit-legendWidget-entry-swatch {
+ border: 1px solid #888;
+ padding: 0px 3px;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/option-widget.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/option-widget.css
new file mode 100644
index 00000000..be0093ac
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/option-widget.css
@@ -0,0 +1,7 @@
+.exhibit-optionWidget {
+ cursor: pointer;
+}
+
+.exhibit-optionWidget img {
+ vertical-align: middle;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/resizable-div-widget.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/resizable-div-widget.css
new file mode 100644
index 00000000..02904ca3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/resizable-div-widget.css
@@ -0,0 +1,10 @@
+/*==================================================
+ * Resizable Div Widget styles
+ *==================================================
+ */
+div.exhibit-resizableDivWidget-resizer {
+ text-align: center;
+ cursor: s-resize;
+ height: 15px;
+ clear: both;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/toolbox-widget.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/toolbox-widget.css
new file mode 100644
index 00000000..3e616381
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/exhibit/styles/widgets/toolbox-widget.css
@@ -0,0 +1,13 @@
+div.exhibit-toolboxWidget-popup {
+ position: absolute;
+ border: 1px solid #ccc;
+ background: white;
+ padding: 3px;
+ text-align: right;
+ z-index: 1000;
+}
+
+img.exhibit-toolboxWidget-button {
+ cursor: pointer;
+ margin: 0px 1px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/LICENSE.txt b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/LICENSE.txt
new file mode 100644
index 00000000..2f3e0503
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/LICENSE.txt
@@ -0,0 +1,29 @@
+/*
+ * (c) Copyright The SIMILE Project 2006. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.css
new file mode 100644
index 00000000..b5cd3d32
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.css
@@ -0,0 +1,243 @@
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+ position:absolute;
+ background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+ position:absolute;
+ overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+ set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+ top:0;
+ height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+ width:100%;
+ left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+ position:absolute; overflow:hidden; font-size:200%;
+ font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+ position: absolute;
+ border: solid #aaa;
+ color: #aaa;
+ width: 5em;
+ height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+ position:absolute;
+ cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ background-color:#58A0DC;
+ overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+}.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input {
+ width: 0;
+}
+
+.timeline-band-scrollbar {
+ display: none;
+ position: absolute;
+ background: #f8f8f8;
+ z-index: 100;
+ overflow: hidden;
+}
+
+.timeline-band-scrollbar-thumb {
+ margin: 2px;
+ background: #666;
+ position: relative;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.js
new file mode 100644
index 00000000..6b9d93b8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation-debug.js
@@ -0,0 +1,3039 @@
+
+
+/* compile-prolog.js */
+window.Timeline_isCompiled=true;
+
+
+/* timeline-api.js */
+(function(){var simile_ajax_ver="2.2.1";
+var isCompiled=("Timeline_isCompiled" in window)&&window.Timeline_isCompiled;
+var useLocalResources=false;
+if(document.location.search.length>0){var params=document.location.search.substr(1).split("&");
+for(var i=0;
+i<params.length;
+i++){if(params[i]=="timeline-use-local-resources"){useLocalResources=true;
+}}}var loadMe=function(){if("Timeline" in window){return ;
+}window.Timeline=new Object();
+window.Timeline.DateTime=window.SimileAjax.DateTime;
+var bundle=false;
+var javascriptFiles=["timeline.js","band.js","themes.js","ethers.js","ether-painters.js","event-utils.js","labellers.js","sources.js","original-painter.js","detailed-painter.js","overview-painter.js","compact-painter.js","decorators.js","units.js"];
+var cssFiles=["timeline.css","ethers.css","events.css"];
+var localizedJavascriptFiles=["timeline.js","labellers.js"];
+var localizedCssFiles=[];
+var supportedLocales=["cs","de","en","es","fr","it","nl","ru","se","tr","vi","zh"];
+try{var desiredLocales=["en"],defaultServerLocale="en",forceLocale=null;
+var parseURLParameters=function(parameters){var params=parameters.split("&");
+for(var p=0;
+p<params.length;
+p++){var pair=params[p].split("=");
+if(pair[0]=="locales"){desiredLocales=desiredLocales.concat(pair[1].split(","));
+}else{if(pair[0]=="defaultLocale"){defaultServerLocale=pair[1];
+}else{if(pair[0]=="forceLocale"){forceLocale=pair[1];
+desiredLocales=desiredLocales.concat(pair[1].split(","));
+}else{if(pair[0]=="bundle"){bundle=pair[1]!="false";
+}}}}}};
+(function(){if(typeof Timeline_urlPrefix=="string"){Timeline.urlPrefix=Timeline_urlPrefix;
+if(typeof Timeline_parameters=="string"){parseURLParameters(Timeline_parameters);
+}}else{var heads=document.documentElement.getElementsByTagName("head");
+for(var h=0;
+h<heads.length;
+h++){var scripts=heads[h].getElementsByTagName("script");
+for(var s=0;
+s<scripts.length;
+s++){var url=scripts[s].src;
+var i=url.indexOf("timeline-api.js");
+if(i>=0){Timeline.urlPrefix=url.substr(0,i);
+var q=url.indexOf("?");
+if(q>0){parseURLParameters(url.substr(q+1));
+}return ;
+}}}throw new Error("Failed to derive URL prefix for Timeline API code files");
+}})();
+var includeJavascriptFiles=function(urlPrefix,filenames){SimileAjax.includeJavascriptFiles(document,urlPrefix,filenames);
+};
+var includeCssFiles=function(urlPrefix,filenames){SimileAjax.includeCssFiles(document,urlPrefix,filenames);
+};
+if(!isCompiled){if(bundle){includeJavascriptFiles(Timeline.urlPrefix,["timeline-bundle.js"]);
+includeCssFiles(Timeline.urlPrefix,["timeline-bundle.css"]);
+}else{includeJavascriptFiles(Timeline.urlPrefix+"scripts/",javascriptFiles);
+includeCssFiles(Timeline.urlPrefix+"styles/",cssFiles);
+}}var loadLocale=[];
+loadLocale[defaultServerLocale]=true;
+var tryExactLocale=function(locale){for(var l=0;
+l<supportedLocales.length;
+l++){if(locale==supportedLocales[l]){loadLocale[locale]=true;
+return true;
+}}return false;
+};
+var tryLocale=function(locale){if(tryExactLocale(locale)){return locale;
+}var dash=locale.indexOf("-");
+if(dash>0&&tryExactLocale(locale.substr(0,dash))){return locale.substr(0,dash);
+}return null;
+};
+for(var l=0;
+l<desiredLocales.length;
+l++){tryLocale(desiredLocales[l]);
+}var defaultClientLocale=defaultServerLocale;
+var defaultClientLocales=("language" in navigator?navigator.language:navigator.browserLanguage).split(";");
+for(var l=0;
+l<defaultClientLocales.length;
+l++){var locale=tryLocale(defaultClientLocales[l]);
+if(locale!=null){defaultClientLocale=locale;
+break;
+}}if(!isCompiled){for(var l=0;
+l<supportedLocales.length;
+l++){var locale=supportedLocales[l];
+if(loadLocale[locale]){includeJavascriptFiles(Timeline.urlPrefix+"scripts/l10n/"+locale+"/",localizedJavascriptFiles);
+includeCssFiles(Timeline.urlPrefix+"styles/l10n/"+locale+"/",localizedCssFiles);
+}}}if(forceLocale==null){Timeline.serverLocale=defaultServerLocale;
+Timeline.clientLocale=defaultClientLocale;
+}else{Timeline.serverLocale=forceLocale;
+Timeline.clientLocale=forceLocale;
+}}catch(e){alert(e);
+}};
+if(typeof SimileAjax=="undefined"&&!isCompiled){window.SimileAjax_onLoad=loadMe;
+var url=useLocalResources?"http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false":"http://api.simile-widgets.org/ajax/"+simile_ajax_ver+"/simile-ajax-api.js";
+if(typeof Timeline_ajax_url=="string"){url=Timeline_ajax_url;
+}var createScriptElement=function(){var script=document.createElement("script");
+script.type="text/javascript";
+script.language="JavaScript";
+script.src=url;
+document.getElementsByTagName("head")[0].appendChild(script);
+};
+if(document.body==null){try{document.write("<script src='"+url+"' type='text/javascript'><\/script>");
+}catch(e){createScriptElement();
+}}else{createScriptElement();
+}}else{loadMe();
+}})();
+
+
+/* timeline-bundle-debug.js */
+Timeline._Band=function(timeline,bandInfo,index){if(timeline.autoWidth&&typeof bandInfo.width=="string"){bandInfo.width=bandInfo.width.indexOf("%")>-1?0:parseInt(bandInfo.width);
+}this._timeline=timeline;
+this._bandInfo=bandInfo;
+this._index=index;
+this._locale=("locale" in bandInfo)?bandInfo.locale:Timeline.getDefaultLocale();
+this._timeZone=("timeZone" in bandInfo)?bandInfo.timeZone:0;
+this._labeller=("labeller" in bandInfo)?bandInfo.labeller:(("createLabeller" in timeline.getUnit())?timeline.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
+this._theme=bandInfo.theme;
+this._zoomIndex=("zoomIndex" in bandInfo)?bandInfo.zoomIndex:0;
+this._zoomSteps=("zoomSteps" in bandInfo)?bandInfo.zoomSteps:null;
+this._dragging=false;
+this._changing=false;
+this._originalScrollSpeed=5;
+this._scrollSpeed=this._originalScrollSpeed;
+this._onScrollListeners=[];
+this._orthogonalDragging=false;
+this._viewOrthogonalOffset=0;
+this._onOrthogonalScrollListeners=[];
+var b=this;
+this._syncWithBand=null;
+this._syncWithBandHandler=function(band){b._onHighlightBandScroll();
+};
+this._syncWithBandOrthogonalScrollHandler=function(band){b._onHighlightBandOrthogonalScroll();
+};
+this._selectorListener=function(band){b._onHighlightBandScroll();
+};
+var inputDiv=this._timeline.getDocument().createElement("div");
+inputDiv.className="timeline-band-input";
+this._timeline.addDiv(inputDiv);
+this._keyboardInput=document.createElement("input");
+this._keyboardInput.type="text";
+inputDiv.appendChild(this._keyboardInput);
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
+this._div=this._timeline.getDocument().createElement("div");
+this._div.id="timeline-band-"+index;
+this._div.className="timeline-band timeline-band-"+index;
+this._timeline.addDiv(this._div);
+SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
+SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
+SimileAjax.DOM.registerEventWithObject(document.body,"mousemove",this,"_onMouseMove");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseup",this,"_onMouseUp");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseout",this,"_onMouseOut");
+var mouseWheel=this._theme!=null?this._theme.mouseWheel:"scroll";
+if(mouseWheel==="zoom"||mouseWheel==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
+}else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
+}}this._innerDiv=this._timeline.getDocument().createElement("div");
+this._innerDiv.className="timeline-band-inner";
+this._div.appendChild(this._innerDiv);
+this._ether=bandInfo.ether;
+bandInfo.ether.initialize(this,timeline);
+this._etherPainter=bandInfo.etherPainter;
+bandInfo.etherPainter.initialize(this,timeline);
+this._eventSource=bandInfo.eventSource;
+if(this._eventSource){this._eventListener={onAddMany:function(){b._onAddMany();
+},onClear:function(){b._onClear();
+}};
+this._eventSource.addListener(this._eventListener);
+}this._eventPainter=bandInfo.eventPainter;
+this._eventTracksNeeded=0;
+this._eventTrackIncrement=0;
+bandInfo.eventPainter.initialize(this,timeline);
+this._decorators=("decorators" in bandInfo)?bandInfo.decorators:[];
+for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].initialize(this,timeline);
+}this._supportsOrthogonalScrolling=("supportsOrthogonalScrolling" in this._eventPainter)&&this._eventPainter.supportsOrthogonalScrolling();
+if(this._supportsOrthogonalScrolling){this._scrollBar=this._timeline.getDocument().createElement("div");
+this._scrollBar.id="timeline-band-scrollbar-"+index;
+this._scrollBar.className="timeline-band-scrollbar";
+this._timeline.addDiv(this._scrollBar);
+this._scrollBar.innerHTML='<div class="timeline-band-scrollbar-thumb"> </div>';
+var scrollbarThumb=this._scrollBar.firstChild;
+if(SimileAjax.Platform.browser.isIE){scrollbarThumb.style.cursor="move";
+}else{scrollbarThumb.style.cursor="-moz-grab";
+}SimileAjax.DOM.registerEventWithObject(scrollbarThumb,"mousedown",this,"_onScrollBarMouseDown");
+}};
+Timeline._Band.SCROLL_MULTIPLES=5;
+Timeline._Band.prototype.dispose=function(){this.closeBubble();
+if(this._eventSource){this._eventSource.removeListener(this._eventListener);
+this._eventListener=null;
+this._eventSource=null;
+}this._timeline=null;
+this._bandInfo=null;
+this._labeller=null;
+this._ether=null;
+this._etherPainter=null;
+this._eventPainter=null;
+this._decorators=null;
+this._onScrollListeners=null;
+this._syncWithBandHandler=null;
+this._syncWithBandOrthogonalScrollHandler=null;
+this._selectorListener=null;
+this._div=null;
+this._innerDiv=null;
+this._keyboardInput=null;
+this._scrollBar=null;
+};
+Timeline._Band.prototype.addOnScrollListener=function(listener){this._onScrollListeners.push(listener);
+};
+Timeline._Band.prototype.removeOnScrollListener=function(listener){for(var i=0;
+i<this._onScrollListeners.length;
+i++){if(this._onScrollListeners[i]==listener){this._onScrollListeners.splice(i,1);
+break;
+}}};
+Timeline._Band.prototype.addOnOrthogonalScrollListener=function(listener){this._onOrthogonalScrollListeners.push(listener);
+};
+Timeline._Band.prototype.removeOnOrthogonalScrollListener=function(listener){for(var i=0;
+i<this._onOrthogonalScrollListeners.length;
+i++){if(this._onOrthogonalScrollListeners[i]==listener){this._onOrthogonalScrollListeners.splice(i,1);
+break;
+}}};
+Timeline._Band.prototype.setSyncWithBand=function(band,highlight){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.removeOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+}this._syncWithBand=band;
+this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.addOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+this._highlight=highlight;
+this._positionHighlight();
+};
+Timeline._Band.prototype.getLocale=function(){return this._locale;
+};
+Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
+};
+Timeline._Band.prototype.getLabeller=function(){return this._labeller;
+};
+Timeline._Band.prototype.getIndex=function(){return this._index;
+};
+Timeline._Band.prototype.getEther=function(){return this._ether;
+};
+Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
+};
+Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
+};
+Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
+};
+Timeline._Band.prototype.getTimeline=function(){return this._timeline;
+};
+Timeline._Band.prototype.updateEventTrackInfo=function(tracks,increment){this._eventTrackIncrement=increment;
+if(tracks>this._eventTracksNeeded){this._eventTracksNeeded=tracks;
+}};
+Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
+}var overviewBand=this._eventPainter.getType()=="overview";
+var margin=overviewBand?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
+var desiredWidth=Math.ceil((this._eventTracksNeeded+margin)*this._eventTrackIncrement);
+desiredWidth+=overviewBand?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
+var bandInfo=this._bandInfo;
+if(desiredWidth!=bandInfo.width){bandInfo.width=desiredWidth;
+}};
+Timeline._Band.prototype.layout=function(){this.paint();
+};
+Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
+this._paintDecorators();
+this._paintEvents();
+};
+Timeline._Band.prototype.softLayout=function(){this.softPaint();
+};
+Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
+this._softPaintDecorators();
+this._softPaintEvents();
+};
+Timeline._Band.prototype.setBandShiftAndWidth=function(shift,width){var inputDiv=this._keyboardInput.parentNode;
+var middle=shift+Math.floor(width/2);
+if(this._timeline.isHorizontal()){this._div.style.top=shift+"px";
+this._div.style.height=width+"px";
+inputDiv.style.top=middle+"px";
+inputDiv.style.left="-1em";
+}else{this._div.style.left=shift+"px";
+this._div.style.width=width+"px";
+inputDiv.style.left=middle+"px";
+inputDiv.style.top="-1em";
+}};
+Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
+}else{return this._div.offsetWidth;
+}};
+Timeline._Band.prototype.setViewLength=function(length){this._viewLength=length;
+this._recenterDiv();
+this._onChanging();
+};
+Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
+};
+Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
+};
+Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
+};
+Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
+};
+Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
+};
+Timeline._Band.prototype.getMinVisibleDateAfterDelta=function(delta){return this._ether.pixelOffsetToDate(delta);
+};
+Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
+};
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta=function(delta){return this._ether.pixelOffsetToDate(this._viewLength+delta);
+};
+Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
+};
+Timeline._Band.prototype.setMinVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.setMaxVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.setCenterVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.dateToPixelOffset=function(date){return this._ether.dateToPixelOffset(date)-this._viewOffset;
+};
+Timeline._Band.prototype.pixelOffsetToDate=function(pixels){return this._ether.pixelOffsetToDate(pixels+this._viewOffset);
+};
+Timeline._Band.prototype.getViewOrthogonalOffset=function(){return this._viewOrthogonalOffset;
+};
+Timeline._Band.prototype.setViewOrthogonalOffset=function(offset){this._viewOrthogonalOffset=Math.max(0,offset);
+};
+Timeline._Band.prototype.createLayerDiv=function(zIndex,className){var div=this._timeline.getDocument().createElement("div");
+div.className="timeline-band-layer"+(typeof className=="string"?(" "+className):"");
+div.style.zIndex=zIndex;
+this._innerDiv.appendChild(div);
+var innerDiv=this._timeline.getDocument().createElement("div");
+innerDiv.className="timeline-band-layer-inner";
+if(SimileAjax.Platform.browser.isIE){innerDiv.style.cursor="move";
+}else{innerDiv.style.cursor="-moz-grab";
+}div.appendChild(innerDiv);
+return innerDiv;
+};
+Timeline._Band.prototype.removeLayerDiv=function(div){this._innerDiv.removeChild(div.parentNode);
+};
+Timeline._Band.prototype.scrollToCenter=function(date,f){var pixelOffset=this._ether.dateToPixelOffset(date);
+if(pixelOffset<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset+this._viewLength));
+}else{if(pixelOffset>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset-this._viewLength));
+}}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(date)),f);
+};
+Timeline._Band.prototype.showBubbleForEvent=function(eventID){var evt=this.getEventSource().getEvent(eventID);
+if(evt){var self=this;
+this.scrollToCenter(evt.getStart(),function(){self._eventPainter.showBubble(evt);
+});
+}};
+Timeline._Band.prototype.zoom=function(zoomIn,x,y,target){if(!this._zoomSteps){return ;
+}x+=this._viewOffset;
+var zoomDate=this._ether.pixelOffsetToDate(x);
+var netIntervalChange=this._ether.zoom(zoomIn);
+this._etherPainter.zoom(netIntervalChange);
+this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
+this._moveEther(x);
+};
+Timeline._Band.prototype._onMouseDown=function(elmt,evt,target){if(!this._dragging){this.closeBubble();
+this._dragging=true;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onMouseMove=function(elmt,evt,target){if(this._dragging||this._orthogonalDragging){var diffX=evt.clientX-this._dragX;
+var diffY=evt.clientY-this._dragY;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+}if(this._dragging){if(this._timeline.isHorizontal()){this._moveEther(diffX,diffY);
+}else{this._moveEther(diffY,diffX);
+}}else{if(this._orthogonalDragging){var viewWidth=this.getViewWidth();
+var scrollbarThumb=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._moveEther(0,-diffY*viewWidth/scrollbarThumb.offsetHeight);
+}else{this._moveEther(0,-diffX*viewWidth/scrollbarThumb.offsetWidth);
+}}else{return ;
+}}this._positionHighlight();
+this._showScrollbar();
+return this._cancelEvent(evt);
+};
+Timeline._Band.prototype._onMouseUp=function(elmt,evt,target){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._keyboardInput.focus();
+this._bounceBack();
+return this._cancelEvent(evt);
+};
+Timeline._Band.prototype._onMouseOut=function(elmt,evt,target){if(target==document.body){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._bounceBack();
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onScrollBarMouseDown=function(elmt,evt,target){if(!this._orthogonalDragging){this.closeBubble();
+this._orthogonalDragging=true;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onMouseScroll=function(innerFrame,evt,target){var now=new Date();
+now=now.getTime();
+if(!this._lastScrollTime||((now-this._lastScrollTime)>50)){this._lastScrollTime=now;
+var delta=0;
+if(evt.wheelDelta){delta=evt.wheelDelta/120;
+}else{if(evt.detail){delta=-evt.detail/3;
+}}var mouseWheel=this._theme.mouseWheel;
+if(this._zoomSteps||mouseWheel==="zoom"){var loc=SimileAjax.DOM.getEventRelativeCoordinates(evt,innerFrame);
+if(delta!=0){var zoomIn;
+if(delta>0){zoomIn=true;
+}if(delta<0){zoomIn=false;
+}this._timeline.zoom(zoomIn,loc.x,loc.y,innerFrame);
+}}else{if(mouseWheel==="scroll"){var move_amt=50*(delta<0?-1:1);
+this._moveEther(move_amt);
+}}}if(evt.stopPropagation){evt.stopPropagation();
+}evt.cancelBubble=true;
+if(evt.preventDefault){evt.preventDefault();
+}evt.returnValue=false;
+};
+Timeline._Band.prototype._onDblClick=function(innerFrame,evt,target){var coords=SimileAjax.DOM.getEventRelativeCoordinates(evt,innerFrame);
+var distance=coords.x-(this._viewLength/2-this._viewOffset);
+this._autoScroll(-distance);
+};
+Timeline._Band.prototype._onKeyDown=function(keyboardInput,evt,target){if(!this._dragging){switch(evt.keyCode){case 27:break;
+case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+}return true;
+};
+Timeline._Band.prototype._onKeyUp=function(keyboardInput,evt,target){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
+switch(evt.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
+break;
+case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+break;
+case 33:this._autoScroll(this._timeline.getPixelLength());
+break;
+case 34:this._autoScroll(-this._timeline.getPixelLength());
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+}return true;
+};
+Timeline._Band.prototype._autoScroll=function(distance,f){var b=this;
+var a=SimileAjax.Graphics.createAnimation(function(abs,diff){b._moveEther(diff);
+},0,distance,1000,f);
+a.run();
+};
+Timeline._Band.prototype._moveEther=function(shift,orthogonalShift){if(orthogonalShift===undefined){orthogonalShift=0;
+}this.closeBubble();
+if(!this._timeline.shiftOK(this._index,shift)){return ;
+}this._viewOffset+=shift;
+this._ether.shiftPixels(-shift);
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+}if(this._supportsOrthogonalScrolling){if(this._eventPainter.getOrthogonalExtent()<=this.getViewWidth()){this._viewOrthogonalOffset=0;
+}else{this._viewOrthogonalOffset=this._viewOrthogonalOffset+orthogonalShift;
+}}if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
+}else{this.softLayout();
+}this._onChanging();
+};
+Timeline._Band.prototype._onChanging=function(){this._changing=true;
+this._fireOnScroll();
+this._setSyncWithBandDate();
+this._changing=false;
+};
+Timeline._Band.prototype.busy=function(){return(this._changing);
+};
+Timeline._Band.prototype._fireOnScroll=function(){for(var i=0;
+i<this._onScrollListeners.length;
+i++){this._onScrollListeners[i](this);
+}};
+Timeline._Band.prototype._fireOnOrthogonalScroll=function(){for(var i=0;
+i<this._onOrthogonalScrollListeners.length;
+i++){this._onOrthogonalScrollListeners[i](this);
+}};
+Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var centerDate=this._ether.pixelOffsetToDate(this.getViewLength()/2);
+this._syncWithBand.setCenterVisibleDate(centerDate);
+}};
+Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var centerDate=this._syncWithBand.getCenterVisibleDate();
+var centerPixelOffset=this._ether.dateToPixelOffset(centerDate);
+this._moveEther(Math.round(this._viewLength/2-centerPixelOffset));
+this._positionHighlight();
+}};
+Timeline._Band.prototype._onHighlightBandOrthogonalScroll=function(){if(this._syncWithBand){this._positionHighlight();
+}};
+Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
+};
+Timeline._Band.prototype._onClear=function(){this._paintEvents();
+};
+Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var startDate=this._syncWithBand.getMinVisibleDate();
+var endDate=this._syncWithBand.getMaxVisibleDate();
+if(this._highlight){var offset=0;
+var extent=1;
+var syncEventPainter=this._syncWithBand.getEventPainter();
+if("supportsOrthogonalScrolling" in syncEventPainter&&syncEventPainter.supportsOrthogonalScrolling()){var orthogonalExtent=syncEventPainter.getOrthogonalExtent();
+var visibleWidth=this._syncWithBand.getViewWidth();
+var totalWidth=Math.max(visibleWidth,orthogonalExtent);
+extent=visibleWidth/totalWidth;
+offset=-this._syncWithBand.getViewOrthogonalOffset()/totalWidth;
+}this._etherPainter.setHighlight(startDate,endDate,offset,extent);
+}}};
+Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}this.layout();
+};
+Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
+this._showScrollbar();
+this._fireOnOrthogonalScroll();
+};
+Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
+};
+Timeline._Band.prototype._paintDecorators=function(){for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].paint();
+}};
+Timeline._Band.prototype._softPaintDecorators=function(){for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].softPaint();
+}};
+Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
+};
+Timeline._Band.prototype._bounceBack=function(f){if(!this._supportsOrthogonalScrolling){return ;
+}var target=0;
+if(this._viewOrthogonalOffset<0){var orthogonalExtent=this._eventPainter.getOrthogonalExtent();
+if(this._viewOrthogonalOffset+orthogonalExtent>=this.getViewWidth()){target=this._viewOrthogonalOffset;
+}else{target=Math.min(0,this.getViewWidth()-orthogonalExtent);
+}}if(target!=this._viewOrthogonalOffset){var self=this;
+SimileAjax.Graphics.createAnimation(function(abs,diff){self._viewOrthogonalOffset=abs;
+self._eventPainter.softPaint();
+self._showScrollbar();
+self._fireOnOrthogonalScroll();
+},this._viewOrthogonalOffset,target,300,function(){self._hideScrollbar();
+}).run();
+}else{this._hideScrollbar();
+}};
+Timeline._Band.prototype._showScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}var orthogonalExtent=this._eventPainter.getOrthogonalExtent();
+var visibleWidth=this.getViewWidth();
+var totalWidth=Math.max(visibleWidth,orthogonalExtent);
+var ratio=(visibleWidth/totalWidth);
+var thumbWidth=Math.round(visibleWidth*ratio)+"px";
+var thumbOffset=Math.round(-this._viewOrthogonalOffset*ratio)+"px";
+var thumbThickness=12;
+var thumb=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._scrollBar.style.top=this._div.style.top;
+this._scrollBar.style.height=this._div.style.height;
+this._scrollBar.style.right="0px";
+this._scrollBar.style.width=thumbThickness+"px";
+thumb.style.top=thumbOffset;
+thumb.style.height=thumbWidth;
+}else{this._scrollBar.style.left=this._div.style.left;
+this._scrollBar.style.width=this._div.style.width;
+this._scrollBar.style.bottom="0px";
+this._scrollBar.style.height=thumbThickness+"px";
+thumb.style.left=thumbOffset;
+thumb.style.width=thumbWidth;
+}if(ratio>=1&&this._viewOrthogonalOffset==0){this._scrollBar.style.display="none";
+}else{this._scrollBar.style.display="block";
+}};
+Timeline._Band.prototype._hideScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}};
+Timeline._Band.prototype._cancelEvent=function(evt){SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+Timeline.CompactEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.CompactEventPainter.prototype.getType=function(){return"compact";
+};
+Timeline.CompactEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.CompactEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.CompactEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.CompactEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.CompactEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var metrics=this._computeMetrics();
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventIterator(minDate,maxDate);
+var stackConcurrentPreciseInstantEvents="stackConcurrentPreciseInstantEvents" in this._params&&typeof this._params.stackConcurrentPreciseInstantEvents=="object";
+var collapseConcurrentPreciseInstantEvents="collapseConcurrentPreciseInstantEvents" in this._params&&this._params.collapseConcurrentPreciseInstantEvents;
+if(collapseConcurrentPreciseInstantEvents||stackConcurrentPreciseInstantEvents){var bufferedEvents=[];
+var previousInstantEvent=null;
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){if(!evt.isInstant()||evt.isImprecise()){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}else{if(previousInstantEvent!=null&&previousInstantEvent.getStart().getTime()==evt.getStart().getTime()){bufferedEvents[bufferedEvents.length-1].push(evt);
+}else{bufferedEvents.push([evt]);
+previousInstantEvent=evt;
+}}}}for(var i=0;
+i<bufferedEvents.length;
+i++){var compositeEvents=bufferedEvents[i];
+if(compositeEvents.length==1){this.paintEvent(compositeEvents[0],metrics,this._params.theme,highlightMatcher(evt));
+}else{var match=-1;
+for(var j=0;
+match<0&&j<compositeEvents.length;
+j++){match=highlightMatcher(compositeEvents[j]);
+}if(stackConcurrentPreciseInstantEvents){this.paintStackedPreciseInstantEvents(compositeEvents,metrics,this._params.theme,match);
+}else{this.paintCompositePreciseInstantEvents(compositeEvents,metrics,this._params.theme,match);
+}}}}else{while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._setOrthogonalOffset(metrics);
+};
+Timeline.CompactEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.CompactEventPainter.prototype.getOrthogonalExtent=function(){var metrics=this._computeMetrics();
+return 2*metrics.trackOffset+this._tracks.length*metrics.trackHeight;
+};
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset=function(metrics){var orthogonalOffset=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=orthogonalOffset+"px";
+};
+Timeline.CompactEventPainter.prototype._computeMetrics=function(){var theme=this._params.theme;
+var eventTheme=theme.event;
+var metrics={trackOffset:"trackOffset" in this._params?this._params.trackOffset:10,trackHeight:"trackHeight" in this._params?this._params.trackHeight:10,tapeHeight:theme.event.tape.height,tapeBottomMargin:"tapeBottomMargin" in this._params?this._params.tapeBottomMargin:2,labelBottomMargin:"labelBottomMargin" in this._params?this._params.labelBottomMargin:5,labelRightMargin:"labelRightMargin" in this._params?this._params.labelRightMargin:5,defaultIcon:eventTheme.instant.icon,defaultIconWidth:eventTheme.instant.iconWidth,defaultIconHeight:eventTheme.instant.iconHeight,customIconWidth:"iconWidth" in this._params?this._params.iconWidth:eventTheme.instant.iconWidth,customIconHeight:"iconHeight" in this._params?this._params.iconHeight:eventTheme.instant.iconHeight,iconLabelGap:"iconLabelGap" in this._params?this._params.iconLabelGap:2,iconBottomMargin:"iconBottomMargin" in this._params?this._params.iconBottomMargin:2};
+if("compositeIcon" in this._params){metrics.compositeIcon=this._params.compositeIcon;
+metrics.compositeIconWidth=this._params.compositeIconWidth||metrics.customIconWidth;
+metrics.compositeIconHeight=this._params.compositeIconHeight||metrics.customIconHeight;
+}else{metrics.compositeIcon=metrics.defaultIcon;
+metrics.compositeIconWidth=metrics.defaultIconWidth;
+metrics.compositeIconHeight=metrics.defaultIconHeight;
+}metrics.defaultStackIcon=("stackConcurrentPreciseInstantEvents" in this._params&&"icon" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.icon:metrics.defaultIcon;
+metrics.defaultStackIconWidth=("stackConcurrentPreciseInstantEvents" in this._params&&"iconWidth" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconWidth:metrics.defaultIconWidth;
+metrics.defaultStackIconHeight=("stackConcurrentPreciseInstantEvents" in this._params&&"iconHeight" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconHeight:metrics.defaultIconHeight;
+return metrics;
+};
+Timeline.CompactEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.CompactEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData.url=metrics.defaultIcon;
+iconData.width=metrics.defaultIconWidth;
+iconData.height=metrics.defaultIconHeight;
+iconData.className="timeline-event-icon-default";
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,null,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+};
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents=function(events,metrics,theme,highlightIndex){var evt=events[0];
+var tooltips=[];
+for(var i=0;
+i<events.length;
+i++){tooltips.push(events[i].getProperty("tooltip")||events[i].getText());
+}var commonData={tooltip:tooltips.join("; ")};
+var iconData={url:metrics.compositeIcon,width:metrics.compositeIconWidth,height:metrics.compositeIconHeight,className:"timeline-event-icon-composite"};
+var labelData={text:String.substitute(this._params.compositeEventLabelTemplate,[events.length])};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,null,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt,domEvt,events);
+};
+SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+for(var i=0;
+i<events.length;
+i++){this._eventIdToElmt[events[i].getID()]=result.iconElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents=function(events,metrics,theme,highlightIndex){var limit="limit" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.limit:10;
+var moreMessageTemplate="moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate:"%0 More Events";
+var showMoreMessage=limit<=events.length-2;
+var band=this._band;
+var getPixelOffset=function(date){return Math.round(band.dateToPixelOffset(date));
+};
+var getIconData=function(evt){var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData.url=metrics.defaultStackIcon;
+iconData.width=metrics.defaultStackIconWidth;
+iconData.height=metrics.defaultStackIconHeight;
+iconData.className="timeline-event-icon-stack timeline-event-icon-default";
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+iconData.className="timeline-event-icon-stack";
+}return iconData;
+};
+var firstIconData=getIconData(events[0]);
+var horizontalIncrement=5;
+var leftIconEdge=0;
+var totalLabelWidth=0;
+var totalLabelHeight=0;
+var totalIconHeight=0;
+var records=[];
+for(var i=0;
+i<events.length&&(!showMoreMessage||i<limit);
+i++){var evt=events[i];
+var text=evt.getText();
+var iconData=getIconData(evt);
+var labelSize=this._frc.computeSize(text);
+var record={text:text,iconData:iconData,labelSize:labelSize,iconLeft:firstIconData.width+i*horizontalIncrement-iconData.width};
+record.labelLeft=firstIconData.width+i*horizontalIncrement+metrics.iconLabelGap;
+record.top=totalLabelHeight;
+records.push(record);
+leftIconEdge=Math.min(leftIconEdge,record.iconLeft);
+totalLabelHeight+=labelSize.height;
+totalLabelWidth=Math.max(totalLabelWidth,record.labelLeft+labelSize.width);
+totalIconHeight=Math.max(totalIconHeight,record.top+iconData.height);
+}if(showMoreMessage){var moreMessage=String.substitute(moreMessageTemplate,[events.length-limit]);
+var moreMessageLabelSize=this._frc.computeSize(moreMessage);
+var moreMessageLabelLeft=firstIconData.width+(limit-1)*horizontalIncrement+metrics.iconLabelGap;
+var moreMessageLabelTop=totalLabelHeight;
+totalLabelHeight+=moreMessageLabelSize.height;
+totalLabelWidth=Math.max(totalLabelWidth,moreMessageLabelLeft+moreMessageLabelSize.width);
+}totalLabelWidth+=metrics.labelRightMargin;
+totalLabelHeight+=metrics.labelBottomMargin;
+totalIconHeight+=metrics.iconBottomMargin;
+var anchorPixel=getPixelOffset(events[0].getStart());
+var newTracks=[];
+var trackCount=Math.ceil(Math.max(totalIconHeight,totalLabelHeight)/metrics.trackHeight);
+var rightIconEdge=firstIconData.width+(events.length-1)*horizontalIncrement;
+for(var i=0;
+i<trackCount;
+i++){newTracks.push({start:leftIconEdge,end:rightIconEdge});
+}var labelTrackCount=Math.ceil(totalLabelHeight/metrics.trackHeight);
+for(var i=0;
+i<labelTrackCount;
+i++){var track=newTracks[i];
+track.end=Math.max(track.end,totalLabelWidth);
+}var firstTrack=this._fitTracks(anchorPixel,newTracks);
+var verticalPixelOffset=firstTrack*metrics.trackHeight+metrics.trackOffset;
+var iconStackDiv=this._timeline.getDocument().createElement("div");
+iconStackDiv.className="timeline-event-icon-stack";
+iconStackDiv.style.position="absolute";
+iconStackDiv.style.overflow="visible";
+iconStackDiv.style.left=anchorPixel+"px";
+iconStackDiv.style.top=verticalPixelOffset+"px";
+iconStackDiv.style.width=rightIconEdge+"px";
+iconStackDiv.style.height=totalIconHeight+"px";
+iconStackDiv.innerHTML="<div style='position: relative'></div>";
+this._eventLayer.appendChild(iconStackDiv);
+var self=this;
+var onMouseOver=function(domEvt){try{var n=parseInt(this.getAttribute("index"));
+var childNodes=iconStackDiv.firstChild.childNodes;
+for(var i=0;
+i<childNodes.length;
+i++){var child=childNodes[i];
+if(i==n){child.style.zIndex=childNodes.length;
+}else{child.style.zIndex=childNodes.length-i;
+}}}catch(e){}};
+var paintEvent=function(index){var record=records[index];
+var evt=events[index];
+var tooltip=evt.getProperty("tooltip")||evt.getText();
+var labelElmtData=self._paintEventLabel({tooltip:tooltip},{text:record.text},anchorPixel+record.labelLeft,verticalPixelOffset+record.top,record.labelSize.width,record.labelSize.height,theme);
+labelElmtData.elmt.setAttribute("index",index);
+labelElmtData.elmt.onmouseover=onMouseOver;
+var img=SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
+var iconDiv=self._timeline.getDocument().createElement("div");
+iconDiv.className="timeline-event-icon"+("className" in record.iconData?(" "+record.iconData.className):"");
+iconDiv.style.left=record.iconLeft+"px";
+iconDiv.style.top=record.top+"px";
+iconDiv.style.zIndex=(records.length-index);
+iconDiv.appendChild(img);
+iconDiv.setAttribute("index",index);
+iconDiv.onmouseover=onMouseOver;
+iconStackDiv.firstChild.appendChild(iconDiv);
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconDiv,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+self._eventIdToElmt[evt.getID()]=iconDiv;
+};
+for(var i=0;
+i<records.length;
+i++){paintEvent(i);
+}if(showMoreMessage){var moreEvents=events.slice(limit);
+var moreMessageLabelElmtData=this._paintEventLabel({tooltip:moreMessage},{text:moreMessage},anchorPixel+moreMessageLabelLeft,verticalPixelOffset+moreMessageLabelTop,moreMessageLabelSize.width,moreMessageLabelSize.height,theme);
+var moreMessageClickHandler=function(elmt,domEvt,target){return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt,domEvt,moreEvents);
+};
+SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt,"mousedown",moreMessageClickHandler);
+for(var i=0;
+i<moreEvents.length;
+i++){this._eventIdToElmt[moreEvents[i].getID()]=moreMessageLabelElmtData.elmt;
+}}};
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),latestStart:evt.getLatestStart(),earliestEnd:evt.getEarliestEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:true};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:false};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getLatestStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),latestStart:evt.getLatestStart(),earliestEnd:evt.getEarliestEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:false};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getLatestStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel=function(anchorDate,commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex){var band=this._band;
+var getPixelOffset=function(date){return Math.round(band.dateToPixelOffset(date));
+};
+var anchorPixel=getPixelOffset(anchorDate);
+var newTracks=[];
+var tapeHeightOccupied=0;
+var tapeTrackCount=0;
+var tapeLastTrackExtraSpace=0;
+if(tapeData!=null){tapeHeightOccupied=metrics.tapeHeight+metrics.tapeBottomMargin;
+tapeTrackCount=Math.ceil(metrics.tapeHeight/metrics.trackHeight);
+var tapeEndPixelOffset=getPixelOffset(tapeData.end)-anchorPixel;
+var tapeStartPixelOffset=getPixelOffset(tapeData.start)-anchorPixel;
+for(var t=0;
+t<tapeTrackCount;
+t++){newTracks.push({start:tapeStartPixelOffset,end:tapeEndPixelOffset});
+}tapeLastTrackExtraSpace=metrics.trackHeight-(tapeHeightOccupied%metrics.tapeHeight);
+}var iconStartPixelOffset=0;
+var iconHorizontalSpaceOccupied=0;
+if(iconData!=null){if("iconAlign" in iconData&&iconData.iconAlign=="center"){iconStartPixelOffset=-Math.floor(iconData.width/2);
+}iconHorizontalSpaceOccupied=iconStartPixelOffset+iconData.width+metrics.iconLabelGap;
+if(tapeTrackCount>0){newTracks[tapeTrackCount-1].end=Math.max(newTracks[tapeTrackCount-1].end,iconHorizontalSpaceOccupied);
+}var iconHeight=iconData.height+metrics.iconBottomMargin+tapeLastTrackExtraSpace;
+while(iconHeight>0){newTracks.push({start:iconStartPixelOffset,end:iconHorizontalSpaceOccupied});
+iconHeight-=metrics.trackHeight;
+}}var text=labelData.text;
+var labelSize=this._frc.computeSize(text);
+var labelHeight=labelSize.height+metrics.labelBottomMargin+tapeLastTrackExtraSpace;
+var labelEndPixelOffset=iconHorizontalSpaceOccupied+labelSize.width+metrics.labelRightMargin;
+if(tapeTrackCount>0){newTracks[tapeTrackCount-1].end=Math.max(newTracks[tapeTrackCount-1].end,labelEndPixelOffset);
+}for(var i=0;
+labelHeight>0;
+i++){if(tapeTrackCount+i<newTracks.length){var track=newTracks[tapeTrackCount+i];
+track.end=labelEndPixelOffset;
+}else{newTracks.push({start:0,end:labelEndPixelOffset});
+}labelHeight-=metrics.trackHeight;
+}var firstTrack=this._fitTracks(anchorPixel,newTracks);
+var verticalPixelOffset=firstTrack*metrics.trackHeight+metrics.trackOffset;
+var result={};
+result.labelElmtData=this._paintEventLabel(commonData,labelData,anchorPixel+iconHorizontalSpaceOccupied,verticalPixelOffset+tapeHeightOccupied,labelSize.width,labelSize.height,theme);
+if(tapeData!=null){if("latestStart" in tapeData||"earliestEnd" in tapeData){result.impreciseTapeElmtData=this._paintEventTape(commonData,tapeData,metrics.tapeHeight,verticalPixelOffset,getPixelOffset(tapeData.start),getPixelOffset(tapeData.end),theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme);
+}if(!tapeData.isInstant&&"start" in tapeData&&"end" in tapeData){result.tapeElmtData=this._paintEventTape(commonData,tapeData,metrics.tapeHeight,verticalPixelOffset,anchorPixel,getPixelOffset("earliestEnd" in tapeData?tapeData.earliestEnd:tapeData.end),tapeData.color,100,metrics,theme);
+}}if(iconData!=null){result.iconElmtData=this._paintEventIcon(commonData,iconData,verticalPixelOffset+tapeHeightOccupied,anchorPixel+iconStartPixelOffset,metrics,theme);
+}return result;
+};
+Timeline.CompactEventPainter.prototype._fitTracks=function(anchorPixel,newTracks){var firstTrack;
+for(firstTrack=0;
+firstTrack<this._tracks.length;
+firstTrack++){var fit=true;
+for(var j=0;
+j<newTracks.length&&(firstTrack+j)<this._tracks.length;
+j++){var existingTrack=this._tracks[firstTrack+j];
+var newTrack=newTracks[j];
+if(anchorPixel+newTrack.start<existingTrack){fit=false;
+break;
+}}if(fit){break;
+}}for(var i=0;
+i<newTracks.length;
+i++){this._tracks[firstTrack+i]=anchorPixel+newTracks[i].end;
+}return firstTrack;
+};
+Timeline.CompactEventPainter.prototype._paintEventIcon=function(commonData,iconData,top,left,metrics,theme){var img=SimileAjax.Graphics.createTranslucentImage(iconData.url);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.className="timeline-event-icon"+("className" in iconData?(" "+iconData.className):"");
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){iconDiv.title=commonData.tooltip;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.CompactEventPainter.prototype._paintEventLabel=function(commonData,labelData,left,top,width,height,theme){var doc=this._timeline.getDocument();
+var labelDiv=doc.createElement("div");
+labelDiv.className="timeline-event-label";
+labelDiv.style.left=left+"px";
+labelDiv.style.width=(width+1)+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=labelData.text;
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){labelDiv.title=commonData.tooltip;
+}if("color" in labelData&&typeof labelData.color=="string"){labelDiv.style.color=labelData.color;
+}if("className" in labelData&&typeof labelData.className=="string"){labelDiv.className+=" "+labelData.className;
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.CompactEventPainter.prototype._paintEventTape=function(commonData,tapeData,height,top,startPixel,endPixel,color,opacity,metrics,theme){var width=endPixel-startPixel;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className="timeline-event-tape";
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.width=width+"px";
+tapeDiv.style.height=height+"px";
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){tapeDiv.title=commonData.tooltip;
+}if(color!=null&&typeof tapeData.color=="string"){tapeDiv.style.backgroundColor=color;
+}if("backgroundImage" in tapeData&&typeof tapeData.backgroundImage=="string"){tapeDiv.style.backgroundImage="url("+backgroundImage+")";
+tapeDiv.style.backgroundRepeat=("backgroundRepeat" in tapeData&&typeof tapeData.backgroundRepeat=="string")?tapeData.backgroundRepeat:"repeat";
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+if("className" in tapeData&&typeof tapeData.className=="string"){tapeDiv.className+=" "+tapeData.className;
+}this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:width,height:height,elmt:tapeDiv};
+};
+Timeline.CompactEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+this._highlightLayer.appendChild(div);
+}};
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent=function(icon,domEvt,events){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),events);
+var ids=[];
+for(var i=0;
+i<events.length;
+i++){ids.push(events[i].getID());
+}this._fireOnSelect(ids);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),[evt]);
+this._fireOnSelect([evt.getID()]);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,[evt]);
+this._fireOnSelect([evt.getID()]);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,[evt]);
+}};
+Timeline.CompactEventPainter.prototype._showBubble=function(x,y,evts){var div=document.createElement("div");
+evts=("fillInfoBubble" in evts)?[evts]:evts;
+for(var i=0;
+i<evts.length;
+i++){var div2=document.createElement("div");
+div.appendChild(div2);
+evts[i].fillInfoBubble(div2,this._params.theme,this._band.getLabeller());
+}SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,this._params.theme.event.bubble.width);
+};
+Timeline.CompactEventPainter.prototype._fireOnSelect=function(eventIDs){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventIDs);
+}};
+Timeline.SpanHighlightDecorator=function(params){this._unit=params.unit!=null?params.unit:SimileAjax.NativeDateUnit;
+this._startDate=(typeof params.startDate=="string")?this._unit.parseFromObject(params.startDate):params.startDate;
+this._endDate=(typeof params.endDate=="string")?this._unit.parseFromObject(params.endDate):params.endDate;
+this._startLabel=params.startLabel!=null?params.startLabel:"";
+this._endLabel=params.endLabel!=null?params.endLabel:"";
+this._color=params.color;
+this._cssClass=params.cssClass!=null?params.cssClass:null;
+this._opacity=params.opacity!=null?params.opacity:100;
+this._zIndex=(params.inFront!=null&&params.inFront)?113:10;
+};
+Timeline.SpanHighlightDecorator.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._layerDiv=null;
+};
+Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(this._zIndex);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+if(this._unit.compare(this._startDate,maxDate)<0&&this._unit.compare(this._endDate,minDate)>0){minDate=this._unit.later(minDate,this._startDate);
+maxDate=this._unit.earlier(maxDate,this._endDate);
+var minPixel=this._band.dateToPixelOffset(minDate);
+var maxPixel=this._band.dateToPixelOffset(maxDate);
+var doc=this._timeline.getDocument();
+var createTable=function(){var table=doc.createElement("table");
+table.insertRow(0).insertCell(0);
+return table;
+};
+var div=doc.createElement("div");
+div.className="timeline-highlight-decorator";
+if(this._cssClass){div.className+=" "+this._cssClass;
+}if(this._color!=null){div.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(div,this._opacity);
+}this._layerDiv.appendChild(div);
+var tableStartLabel=createTable();
+tableStartLabel.className="timeline-highlight-label timeline-highlight-label-start";
+var tdStart=tableStartLabel.rows[0].cells[0];
+tdStart.innerHTML=this._startLabel;
+if(this._cssClass){tdStart.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(tableStartLabel);
+var tableEndLabel=createTable();
+tableEndLabel.className="timeline-highlight-label timeline-highlight-label-end";
+var tdEnd=tableEndLabel.rows[0].cells[0];
+tdEnd.innerHTML=this._endLabel;
+if(this._cssClass){tdEnd.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(tableEndLabel);
+if(this._timeline.isHorizontal()){div.style.left=minPixel+"px";
+div.style.width=(maxPixel-minPixel)+"px";
+tableStartLabel.style.right=(this._band.getTotalViewLength()-minPixel)+"px";
+tableStartLabel.style.width=(this._startLabel.length)+"em";
+tableEndLabel.style.left=maxPixel+"px";
+tableEndLabel.style.width=(this._endLabel.length)+"em";
+}else{div.style.top=minPixel+"px";
+div.style.height=(maxPixel-minPixel)+"px";
+tableStartLabel.style.bottom=minPixel+"px";
+tableStartLabel.style.height="1.5px";
+tableEndLabel.style.top=maxPixel+"px";
+tableEndLabel.style.height="1.5px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
+Timeline.PointHighlightDecorator=function(params){this._unit=params.unit!=null?params.unit:SimileAjax.NativeDateUnit;
+this._date=(typeof params.date=="string")?this._unit.parseFromObject(params.date):params.date;
+this._width=params.width!=null?params.width:10;
+this._color=params.color;
+this._cssClass=params.cssClass!=null?params.cssClass:"";
+this._opacity=params.opacity!=null?params.opacity:100;
+};
+Timeline.PointHighlightDecorator.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._layerDiv=null;
+};
+Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(10);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+if(this._unit.compare(this._date,maxDate)<0&&this._unit.compare(this._date,minDate)>0){var pixel=this._band.dateToPixelOffset(this._date);
+var minPixel=pixel-Math.round(this._width/2);
+var doc=this._timeline.getDocument();
+var div=doc.createElement("div");
+div.className="timeline-highlight-point-decorator";
+div.className+=" "+this._cssClass;
+if(this._color!=null){div.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(div,this._opacity);
+}this._layerDiv.appendChild(div);
+if(this._timeline.isHorizontal()){div.style.left=minPixel+"px";
+div.style.width=this._width+"px";
+}else{div.style.top=minPixel+"px";
+div.style.height=this._width+"px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.DetailedEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
+};
+Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var eventTheme=this._params.theme.event;
+var trackHeight=Math.max(eventTheme.track.height,this._frc.getLineHeight());
+var metrics={trackOffset:Math.round(this._band.getViewWidth()/2-trackHeight/2),trackHeight:trackHeight,trackGap:eventTheme.track.gap,trackIncrement:trackHeight+eventTheme.track.gap,icon:eventTheme.instant.icon,iconWidth:eventTheme.instant.iconWidth,iconHeight:eventTheme.instant.iconHeight,labelWidth:eventTheme.label.width};
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,metrics.trackIncrement);
+};
+Timeline.DetailedEventPainter.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._lowerTracks=[];
+this._upperTracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.DetailedEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelSize=this._frc.computeSize(text);
+var iconTrack=this._findFreeTrackForSolid(iconRightEdge,startPixel);
+var iconElmtData=this._paintEventIcon(evt,iconTrack,iconLeftEdge,metrics,theme);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelTrack=iconTrack;
+var iconTrackData=this._getTrackData(iconTrack);
+if(Math.min(iconTrackData.solid,iconTrackData.text)>=labelLeft+labelSize.width){iconTrackData.solid=iconLeftEdge;
+iconTrackData.text=labelLeft;
+}else{iconTrackData.solid=iconLeftEdge;
+labelLeft=startPixel+theme.event.label.offsetFromLine;
+labelTrack=this._findFreeTrackForText(iconTrack,labelLeft+labelSize.width,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=iconLeftEdge;
+this._paintEventLine(evt,startPixel,iconTrack,labelTrack,metrics,theme);
+}var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,iconElmtData,theme);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelSize=this._frc.computeSize(text);
+var iconTrack=this._findFreeTrackForSolid(endPixel,startPixel);
+var tapeElmtData=this._paintEventTape(evt,iconTrack,startPixel,endPixel,theme.event.instant.impreciseColor,theme.event.instant.impreciseOpacity,metrics,theme);
+var iconElmtData=this._paintEventIcon(evt,iconTrack,iconLeftEdge,metrics,theme);
+var iconTrackData=this._getTrackData(iconTrack);
+iconTrackData.solid=iconLeftEdge;
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var labelTrack;
+if(labelRight<endPixel){labelTrack=iconTrack;
+}else{labelLeft=startPixel+theme.event.label.offsetFromLine;
+labelRight=labelLeft+labelSize.width;
+labelTrack=this._findFreeTrackForText(iconTrack,labelRight,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=iconLeftEdge;
+this._paintEventLine(evt,startPixel,iconTrack,labelTrack,metrics,theme);
+}var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,iconElmtData,theme);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var labelSize=this._frc.computeSize(text);
+var tapeTrack=this._findFreeTrackForSolid(endPixel);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var tapeElmtData=this._paintEventTape(evt,tapeTrack,startPixel,endPixel,color,100,metrics,theme);
+var tapeTrackData=this._getTrackData(tapeTrack);
+tapeTrackData.solid=startPixel;
+var labelLeft=startPixel+theme.event.label.offsetFromLine;
+var labelTrack=this._findFreeTrackForText(tapeTrack,labelLeft+labelSize.width,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=startPixel-2;
+this._paintEventLine(evt,startPixel,tapeTrack,labelTrack,metrics,theme);
+var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var latestStartDate=evt.getLatestStart();
+var endDate=evt.getEnd();
+var earliestEndDate=evt.getEarliestEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var labelSize=this._frc.computeSize(text);
+var tapeTrack=this._findFreeTrackForSolid(endPixel);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var impreciseTapeElmtData=this._paintEventTape(evt,tapeTrack,startPixel,endPixel,theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme);
+var tapeElmtData=this._paintEventTape(evt,tapeTrack,latestStartPixel,earliestEndPixel,color,100,metrics,theme);
+var tapeTrackData=this._getTrackData(tapeTrack);
+tapeTrackData.solid=startPixel;
+var labelLeft=latestStartPixel+theme.event.label.offsetFromLine;
+var labelTrack=this._findFreeTrackForText(tapeTrack,labelLeft+labelSize.width,function(t){t.line=latestStartPixel-2;
+});
+this._getTrackData(labelTrack).text=latestStartPixel-2;
+this._paintEventLine(evt,latestStartPixel,tapeTrack,labelTrack,metrics,theme);
+var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(solidEdge,softEdge){for(var i=0;
+true;
+i++){if(i<this._lowerTracks.length){var t=this._lowerTracks[i];
+if(Math.min(t.solid,t.text)>solidEdge&&(!(softEdge)||t.line>softEdge)){return i;
+}}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return i;
+}if(i<this._upperTracks.length){var t=this._upperTracks[i];
+if(Math.min(t.solid,t.text)>solidEdge&&(!(softEdge)||t.line>softEdge)){return -1-i;
+}}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return -1-i;
+}}};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(fromTrack,edge,occupiedTrackVisitor){var extendUp;
+var index;
+var firstIndex;
+var result;
+if(fromTrack<0){extendUp=true;
+firstIndex=-fromTrack;
+index=this._findFreeUpperTrackForText(firstIndex,edge);
+result=-1-index;
+}else{if(fromTrack>0){extendUp=false;
+firstIndex=fromTrack+1;
+index=this._findFreeLowerTrackForText(firstIndex,edge);
+result=index;
+}else{var upIndex=this._findFreeUpperTrackForText(0,edge);
+var downIndex=this._findFreeLowerTrackForText(1,edge);
+if(downIndex-1<=upIndex){extendUp=false;
+firstIndex=1;
+index=downIndex;
+result=index;
+}else{extendUp=true;
+firstIndex=0;
+index=upIndex;
+result=-1-index;
+}}}if(extendUp){if(index==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var i=firstIndex;
+i<index;
+i++){occupiedTrackVisitor(this._upperTracks[i]);
+}}else{if(index==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var i=firstIndex;
+i<index;
+i++){occupiedTrackVisitor(this._lowerTracks[i]);
+}}return result;
+};
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(index,edge){for(;
+index<this._lowerTracks.length;
+index++){var t=this._lowerTracks[index];
+if(Math.min(t.solid,t.text)>=edge){break;
+}}return index;
+};
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(index,edge){for(;
+index<this._upperTracks.length;
+index++){var t=this._upperTracks[index];
+if(Math.min(t.solid,t.text)>=edge){break;
+}}return index;
+};
+Timeline.DetailedEventPainter.prototype._getTrackData=function(index){return(index<0)?this._upperTracks[-index-1]:this._lowerTracks[index];
+};
+Timeline.DetailedEventPainter.prototype._paintEventLine=function(evt,left,startTrack,endTrack,metrics,theme){var top=Math.round(metrics.trackOffset+startTrack*metrics.trackIncrement+metrics.trackHeight/2);
+var height=Math.round(Math.abs(endTrack-startTrack)*metrics.trackIncrement);
+var lineStyle="1px solid "+theme.event.label.lineColor;
+var lineDiv=this._timeline.getDocument().createElement("div");
+lineDiv.style.position="absolute";
+lineDiv.style.left=left+"px";
+lineDiv.style.width=theme.event.label.offsetFromLine+"px";
+lineDiv.style.height=height+"px";
+if(startTrack>endTrack){lineDiv.style.top=(top-height)+"px";
+lineDiv.style.borderTop=lineStyle;
+}else{lineDiv.style.top=top+"px";
+lineDiv.style.borderBottom=lineStyle;
+}lineDiv.style.borderLeft=lineStyle;
+this._lineLayer.appendChild(lineDiv);
+};
+Timeline.DetailedEventPainter.prototype._paintEventIcon=function(evt,iconTrack,left,metrics,theme){var icon=evt.getIcon();
+icon=icon!=null?icon:metrics.icon;
+var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+var top=Math.round(middle-metrics.iconHeight/2);
+var img=SimileAjax.Graphics.createTranslucentImage(icon);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.style.position="absolute";
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+iconDiv.style.cursor="pointer";
+if(evt._title!=null){iconDiv.title=evt._title;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.DetailedEventPainter.prototype._paintEventLabel=function(evt,text,left,top,width,height,theme){var doc=this._timeline.getDocument();
+var labelBackgroundDiv=doc.createElement("div");
+labelBackgroundDiv.style.position="absolute";
+labelBackgroundDiv.style.left=left+"px";
+labelBackgroundDiv.style.width=width+"px";
+labelBackgroundDiv.style.top=top+"px";
+labelBackgroundDiv.style.height=height+"px";
+labelBackgroundDiv.style.backgroundColor=theme.event.label.backgroundColor;
+SimileAjax.Graphics.setOpacity(labelBackgroundDiv,theme.event.label.backgroundOpacity);
+this._eventLayer.appendChild(labelBackgroundDiv);
+var labelDiv=doc.createElement("div");
+labelDiv.style.position="absolute";
+labelDiv.style.left=left+"px";
+labelDiv.style.width=width+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=text;
+labelDiv.style.cursor="pointer";
+if(evt._title!=null){labelDiv.title=evt._title;
+}var color=evt.getTextColor();
+if(color==null){color=evt.getColor();
+}if(color!=null){labelDiv.style.color=color;
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.DetailedEventPainter.prototype._paintEventTape=function(evt,iconTrack,startPixel,endPixel,color,opacity,metrics,theme){var tapeWidth=endPixel-startPixel;
+var tapeHeight=theme.event.tape.height;
+var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+var top=Math.round(middle-tapeHeight/2);
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.style.position="absolute";
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.width=tapeWidth+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.height=tapeHeight+"px";
+tapeDiv.style.backgroundColor=color;
+tapeDiv.style.overflow="hidden";
+tapeDiv.style.cursor="pointer";
+if(evt._title!=null){tapeDiv.title=evt._title;
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:tapeWidth,height:tapeHeight,elmt:tapeDiv};
+};
+Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}};
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.DetailedEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,evt);
+}};
+Timeline.DetailedEventPainter.prototype._showBubble=function(x,y,evt){var div=document.createElement("div");
+var themeBubble=this._params.theme.event.bubble;
+evt.fillInfoBubble(div,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,themeBubble.width,null,themeBubble.maxHeight);
+};
+Timeline.DetailedEventPainter.prototype._fireOnSelect=function(eventID){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventID);
+}};
+Timeline.GregorianEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._unit=params.unit;
+this._multiple=("multiple" in params)?params.multiple:1;
+};
+Timeline.GregorianEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.GregorianEtherPainter.prototype.setHighlight=function(startDate,endDate,orthogonalOffset,orthogonalExtent){this._highlight.position(startDate,endDate,orthogonalOffset,orthogonalExtent);
+};
+Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var timeZone=this._band.getTimeZone();
+var labeller=this._band.getLabeller();
+SimileAjax.DateTime.roundDownToInterval(minDate,this._unit,timeZone,this._multiple,this._theme.firstDayOfWeek);
+var p=this;
+var incrementDate=function(date){for(var i=0;
+i<p._multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,p._unit);
+}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,this._unit,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.GregorianEtherPainter.prototype.zoom=function(netIntervalChange){if(netIntervalChange!=0){this._unit+=netIntervalChange;
+}};
+Timeline.HotZoneGregorianEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:params.unit,multiple:1}];
+for(var i=0;
+i<params.zones.length;
+i++){var zone=params.zones[i];
+var zoneStart=SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
+var zoneEnd=SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
+for(var j=0;
+j<this._zones.length&&zoneEnd>zoneStart;
+j++){var zone2=this._zones[j];
+if(zoneStart<zone2.endTime){if(zoneStart>zone2.startTime){this._zones.splice(j,0,{startTime:zone2.startTime,endTime:zoneStart,unit:zone2.unit,multiple:zone2.multiple});
+j++;
+zone2.startTime=zoneStart;
+}if(zoneEnd<zone2.endTime){this._zones.splice(j,0,{startTime:zoneStart,endTime:zoneEnd,unit:zone.unit,multiple:(zone.multiple)?zone.multiple:1});
+j++;
+zone2.startTime=zoneEnd;
+zoneStart=zoneEnd;
+}else{zone2.multiple=zone.multiple;
+zone2.unit=zone.unit;
+zoneStart=zone2.endTime;
+}}}}};
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var timeZone=this._band.getTimeZone();
+var labeller=this._band.getLabeller();
+var p=this;
+var incrementDate=function(date,zone){for(var i=0;
+i<zone.multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,zone.unit);
+}};
+var zStart=0;
+while(zStart<this._zones.length){if(minDate.getTime()<this._zones[zStart].endTime){break;
+}zStart++;
+}var zEnd=this._zones.length-1;
+while(zEnd>=0){if(maxDate.getTime()>this._zones[zEnd].startTime){break;
+}zEnd--;
+}for(var z=zStart;
+z<=zEnd;
+z++){var zone=this._zones[z];
+var minDate2=new Date(Math.max(minDate.getTime(),zone.startTime));
+var maxDate2=new Date(Math.min(maxDate.getTime(),zone.endTime));
+SimileAjax.DateTime.roundDownToInterval(minDate2,zone.unit,timeZone,zone.multiple,this._theme.firstDayOfWeek);
+SimileAjax.DateTime.roundUpToInterval(maxDate2,zone.unit,timeZone,zone.multiple,this._theme.firstDayOfWeek);
+while(minDate2.getTime()<maxDate2.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate2,labeller,zone.unit,this._markerLayer,this._lineLayer);
+incrementDate(minDate2,zone);
+}}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(netIntervalChange){if(netIntervalChange!=0){for(var i=0;
+i<this._zones.length;
+++i){if(this._zones[i]){this._zones[i].unit+=netIntervalChange;
+}}}};
+Timeline.YearCountEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+this._multiple=("multiple" in params)?params.multiple:1;
+};
+Timeline.YearCountEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.YearCountEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=new Date(this._startDate.getTime());
+var maxDate=this._band.getMaxDate();
+var yearDiff=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
+minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-yearDiff%this._multiple);
+var p=this;
+var incrementDate=function(date){for(var i=0;
+i<p._multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,SimileAjax.DateTime.YEAR);
+}};
+var labeller={labelInterval:function(date,intervalUnit){var diff=date.getUTCFullYear()-p._startDate.getUTCFullYear();
+return{text:diff,emphasized:diff==0};
+}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
+Timeline.QuarterlyEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=new Date(0);
+var maxDate=this._band.getMaxDate();
+minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
+minDate.setUTCMonth(this._startDate.getUTCMonth());
+var p=this;
+var incrementDate=function(date){date.setUTCMonth(date.getUTCMonth()+3);
+};
+var labeller={labelInterval:function(date,intervalUnit){var quarters=(4+(date.getUTCMonth()-p._startDate.getUTCMonth())/3)%4;
+if(quarters!=0){return{text:"Q"+(quarters+1),emphasized:false};
+}else{return{text:"Y"+(date.getUTCFullYear()-p._startDate.getUTCFullYear()+1),emphasized:true};
+}}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
+Timeline.EtherIntervalMarkerLayout=function(timeline,band,theme,align,showLine){var horizontal=timeline.isHorizontal();
+if(horizontal){if(align=="Top"){this.positionDiv=function(div,offset){div.style.left=offset+"px";
+div.style.top="0px";
+};
+}else{this.positionDiv=function(div,offset){div.style.left=offset+"px";
+div.style.bottom="0px";
+};
+}}else{if(align=="Left"){this.positionDiv=function(div,offset){div.style.top=offset+"px";
+div.style.left="0px";
+};
+}else{this.positionDiv=function(div,offset){div.style.top=offset+"px";
+div.style.right="0px";
+};
+}}var markerTheme=theme.ether.interval.marker;
+var lineTheme=theme.ether.interval.line;
+var weekendTheme=theme.ether.interval.weekend;
+var stylePrefix=(horizontal?"h":"v")+align;
+var labelStyler=markerTheme[stylePrefix+"Styler"];
+var emphasizedLabelStyler=markerTheme[stylePrefix+"EmphasizedStyler"];
+var day=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+this.createIntervalMarker=function(date,labeller,unit,markerDiv,lineDiv){var offset=Math.round(band.dateToPixelOffset(date));
+if(showLine&&unit!=SimileAjax.DateTime.WEEK){var divLine=timeline.getDocument().createElement("div");
+divLine.className="timeline-ether-lines";
+if(lineTheme.opacity<100){SimileAjax.Graphics.setOpacity(divLine,lineTheme.opacity);
+}if(horizontal){divLine.style.left=offset+"px";
+}else{divLine.style.top=offset+"px";
+}lineDiv.appendChild(divLine);
+}if(unit==SimileAjax.DateTime.WEEK){var firstDayOfWeek=theme.firstDayOfWeek;
+var saturday=new Date(date.getTime()+(6-firstDayOfWeek-7)*day);
+var monday=new Date(saturday.getTime()+2*day);
+var saturdayPixel=Math.round(band.dateToPixelOffset(saturday));
+var mondayPixel=Math.round(band.dateToPixelOffset(monday));
+var length=Math.max(1,mondayPixel-saturdayPixel);
+var divWeekend=timeline.getDocument().createElement("div");
+divWeekend.className="timeline-ether-weekends";
+if(weekendTheme.opacity<100){SimileAjax.Graphics.setOpacity(divWeekend,weekendTheme.opacity);
+}if(horizontal){divWeekend.style.left=saturdayPixel+"px";
+divWeekend.style.width=length+"px";
+}else{divWeekend.style.top=saturdayPixel+"px";
+divWeekend.style.height=length+"px";
+}lineDiv.appendChild(divWeekend);
+}var label=labeller.labelInterval(date,unit);
+var div=timeline.getDocument().createElement("div");
+div.innerHTML=label.text;
+div.className="timeline-date-label";
+if(label.emphasized){div.className+=" timeline-date-label-em";
+}this.positionDiv(div,offset);
+markerDiv.appendChild(div);
+return div;
+};
+};
+Timeline.EtherHighlight=function(timeline,band,theme,backgroundLayer){var horizontal=timeline.isHorizontal();
+this._highlightDiv=null;
+this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=timeline.getDocument().createElement("div");
+this._highlightDiv.setAttribute("name","ether-highlight");
+this._highlightDiv.className="timeline-ether-highlight";
+var opacity=theme.ether.highlightOpacity;
+if(opacity<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,opacity);
+}backgroundLayer.appendChild(this._highlightDiv);
+}};
+this.position=function(startDate,endDate,orthogonalOffset,orthogonalExtent){orthogonalOffset=orthogonalOffset||0;
+orthogonalExtent=orthogonalExtent||1;
+this._createHighlightDiv();
+var startPixel=Math.round(band.dateToPixelOffset(startDate));
+var endPixel=Math.round(band.dateToPixelOffset(endDate));
+var length=Math.max(endPixel-startPixel,3);
+var totalWidth=band.getViewWidth()-4;
+if(horizontal){this._highlightDiv.style.left=startPixel+"px";
+this._highlightDiv.style.width=length+"px";
+this._highlightDiv.style.top=Math.round(orthogonalOffset*totalWidth)+"px";
+this._highlightDiv.style.height=Math.round(orthogonalExtent*totalWidth)+"px";
+}else{this._highlightDiv.style.top=startPixel+"px";
+this._highlightDiv.style.height=length+"px";
+this._highlightDiv.style.left=Math.round(orthogonalOffset*totalWidth)+"px";
+this._highlightDiv.style.width=Math.round(orthogonalExtent*totalWidth)+"px";
+}};
+};
+Timeline.LinearEther=function(params){this._params=params;
+this._interval=params.interval;
+this._pixelsPerInterval=params.pixelsPerInterval;
+};
+Timeline.LinearEther.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._unit=timeline.getUnit();
+if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.LinearEther.prototype.setDate=function(date){this._start=this._unit.cloneValue(date);
+};
+Timeline.LinearEther.prototype.shiftPixels=function(pixels){var numeric=this._interval*pixels/this._pixelsPerInterval;
+this._start=this._unit.change(this._start,numeric);
+};
+Timeline.LinearEther.prototype.dateToPixelOffset=function(date){var numeric=this._unit.compare(date,this._start);
+return this._pixelsPerInterval*numeric/this._interval;
+};
+Timeline.LinearEther.prototype.pixelOffsetToDate=function(pixels){var numeric=pixels*this._interval/this._pixelsPerInterval;
+return this._unit.change(this._start,numeric);
+};
+Timeline.LinearEther.prototype.zoom=function(zoomIn){var netIntervalChange=0;
+var currentZoomIndex=this._band._zoomIndex;
+var newZoomIndex=currentZoomIndex;
+if(zoomIn&&(currentZoomIndex>0)){newZoomIndex=currentZoomIndex-1;
+}if(!zoomIn&&(currentZoomIndex<(this._band._zoomSteps.length-1))){newZoomIndex=currentZoomIndex+1;
+}this._band._zoomIndex=newZoomIndex;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+this._pixelsPerInterval=this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+netIntervalChange=this._band._zoomSteps[newZoomIndex].unit-this._band._zoomSteps[currentZoomIndex].unit;
+return netIntervalChange;
+};
+Timeline.HotZoneEther=function(params){this._params=params;
+this._interval=params.interval;
+this._pixelsPerInterval=params.pixelsPerInterval;
+this._theme=params.theme;
+};
+Timeline.HotZoneEther.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._unit=timeline.getUnit();
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
+var params=this._params;
+for(var i=0;
+i<params.zones.length;
+i++){var zone=params.zones[i];
+var zoneStart=this._unit.parseFromObject(zone.start);
+var zoneEnd=this._unit.parseFromObject(zone.end);
+for(var j=0;
+j<this._zones.length&&this._unit.compare(zoneEnd,zoneStart)>0;
+j++){var zone2=this._zones[j];
+if(this._unit.compare(zoneStart,zone2.endTime)<0){if(this._unit.compare(zoneStart,zone2.startTime)>0){this._zones.splice(j,0,{startTime:zone2.startTime,endTime:zoneStart,magnify:zone2.magnify});
+j++;
+zone2.startTime=zoneStart;
+}if(this._unit.compare(zoneEnd,zone2.endTime)<0){this._zones.splice(j,0,{startTime:zoneStart,endTime:zoneEnd,magnify:zone.magnify*zone2.magnify});
+j++;
+zone2.startTime=zoneEnd;
+zoneStart=zoneEnd;
+}else{zone2.magnify*=zone.magnify;
+zoneStart=zone2.endTime;
+}}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.HotZoneEther.prototype.setDate=function(date){this._start=this._unit.cloneValue(date);
+};
+Timeline.HotZoneEther.prototype.shiftPixels=function(pixels){this._start=this.pixelOffsetToDate(pixels);
+};
+Timeline.HotZoneEther.prototype.dateToPixelOffset=function(date){return this._dateDiffToPixelOffset(this._start,date);
+};
+Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(pixels){return this._pixelOffsetToDate(pixels,this._start);
+};
+Timeline.HotZoneEther.prototype.zoom=function(zoomIn){var netIntervalChange=0;
+var currentZoomIndex=this._band._zoomIndex;
+var newZoomIndex=currentZoomIndex;
+if(zoomIn&&(currentZoomIndex>0)){newZoomIndex=currentZoomIndex-1;
+}if(!zoomIn&&(currentZoomIndex<(this._band._zoomSteps.length-1))){newZoomIndex=currentZoomIndex+1;
+}this._band._zoomIndex=newZoomIndex;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+this._pixelsPerInterval=this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+netIntervalChange=this._band._zoomSteps[newZoomIndex].unit-this._band._zoomSteps[currentZoomIndex].unit;
+return netIntervalChange;
+};
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(fromDate,toDate){var scale=this._getScale();
+var fromTime=fromDate;
+var toTime=toDate;
+var pixels=0;
+if(this._unit.compare(fromTime,toTime)<0){var z=0;
+while(z<this._zones.length){if(this._unit.compare(fromTime,this._zones[z].endTime)<0){break;
+}z++;
+}while(this._unit.compare(fromTime,toTime)<0){var zone=this._zones[z];
+var toTime2=this._unit.earlier(toTime,zone.endTime);
+pixels+=(this._unit.compare(toTime2,fromTime)/(scale/zone.magnify));
+fromTime=toTime2;
+z++;
+}}else{var z=this._zones.length-1;
+while(z>=0){if(this._unit.compare(fromTime,this._zones[z].startTime)>0){break;
+}z--;
+}while(this._unit.compare(fromTime,toTime)>0){var zone=this._zones[z];
+var toTime2=this._unit.later(toTime,zone.startTime);
+pixels+=(this._unit.compare(toTime2,fromTime)/(scale/zone.magnify));
+fromTime=toTime2;
+z--;
+}}return pixels;
+};
+Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(pixels,fromDate){var scale=this._getScale();
+var time=fromDate;
+if(pixels>0){var z=0;
+while(z<this._zones.length){if(this._unit.compare(time,this._zones[z].endTime)<0){break;
+}z++;
+}while(pixels>0){var zone=this._zones[z];
+var scale2=scale/zone.magnify;
+if(zone.endTime==Number.POSITIVE_INFINITY){time=this._unit.change(time,pixels*scale2);
+pixels=0;
+}else{var pixels2=this._unit.compare(zone.endTime,time)/scale2;
+if(pixels2>pixels){time=this._unit.change(time,pixels*scale2);
+pixels=0;
+}else{time=zone.endTime;
+pixels-=pixels2;
+}}z++;
+}}else{var z=this._zones.length-1;
+while(z>=0){if(this._unit.compare(time,this._zones[z].startTime)>0){break;
+}z--;
+}pixels=-pixels;
+while(pixels>0){var zone=this._zones[z];
+var scale2=scale/zone.magnify;
+if(zone.startTime==Number.NEGATIVE_INFINITY){time=this._unit.change(time,-pixels*scale2);
+pixels=0;
+}else{var pixels2=this._unit.compare(time,zone.startTime)/scale2;
+if(pixels2>pixels){time=this._unit.change(time,-pixels*scale2);
+pixels=0;
+}else{time=zone.startTime;
+pixels-=pixels2;
+}}z--;
+}}return time;
+};
+Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
+};
+Timeline.EventUtils={};
+Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
+}this._lastEventID+=1;
+return"e"+this._lastEventID;
+};
+Timeline.EventUtils.decodeEventElID=function(elementID){var parts=elementID.split("-");
+if(parts[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
+return{band:null,evt:null};
+}var timeline=Timeline.getTimelineFromID(parts[2]);
+var band=timeline.getBand(parts[3]);
+var evt=band.getEventSource.getEvent(parts[4]);
+return{band:band,evt:evt};
+};
+Timeline.EventUtils.encodeEventElID=function(timeline,band,elType,evt){return elType+"-tl-"+timeline.timelineID+"-"+band.getIndex()+"-"+evt.getID();
+};
+Timeline.GregorianDateLabeller=function(locale,timeZone){this._locale=locale;
+this._timeZone=timeZone;
+};
+Timeline.GregorianDateLabeller.monthNames=[];
+Timeline.GregorianDateLabeller.dayNames=[];
+Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
+Timeline.GregorianDateLabeller.getMonthName=function(month,locale){return Timeline.GregorianDateLabeller.monthNames[locale][month];
+};
+Timeline.GregorianDateLabeller.prototype.labelInterval=function(date,intervalUnit){var f=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+if(f==null){f=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+}return f.call(this,date,intervalUnit);
+};
+Timeline.GregorianDateLabeller.prototype.labelPrecise=function(date){return SimileAjax.DateTime.removeTimeZoneOffset(date,this._timeZone).toUTCString();
+};
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(date,intervalUnit){var text;
+var emphasized=false;
+date=SimileAjax.DateTime.removeTimeZoneOffset(date,this._timeZone);
+switch(intervalUnit){case SimileAjax.DateTime.MILLISECOND:text=date.getUTCMilliseconds();
+break;
+case SimileAjax.DateTime.SECOND:text=date.getUTCSeconds();
+break;
+case SimileAjax.DateTime.MINUTE:var m=date.getUTCMinutes();
+if(m==0){text=date.getUTCHours()+":00";
+emphasized=true;
+}else{text=m;
+}break;
+case SimileAjax.DateTime.HOUR:text=date.getUTCHours()+"hr";
+break;
+case SimileAjax.DateTime.DAY:text=Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(),this._locale)+" "+date.getUTCDate();
+break;
+case SimileAjax.DateTime.WEEK:text=Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(),this._locale)+" "+date.getUTCDate();
+break;
+case SimileAjax.DateTime.MONTH:var m=date.getUTCMonth();
+if(m!=0){text=Timeline.GregorianDateLabeller.getMonthName(m,this._locale);
+break;
+}case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var y=date.getUTCFullYear();
+if(y>0){text=date.getUTCFullYear();
+}else{text=(1-y)+"BC";
+}emphasized=(intervalUnit==SimileAjax.DateTime.MONTH)||(intervalUnit==SimileAjax.DateTime.DECADE&&y%100==0)||(intervalUnit==SimileAjax.DateTime.CENTURY&&y%1000==0);
+break;
+default:text=date.toUTCString();
+}return{text:text,emphasized:emphasized};
+};
+Timeline.OriginalEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._eventPaintListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.OriginalEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
+};
+Timeline.OriginalEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(listener){this._eventPaintListeners.push(listener);
+};
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(listener){for(var i=0;
+i<this._eventPaintListeners.length;
+i++){if(this._eventPaintListeners[i]==listener){this._eventPaintListeners.splice(i,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._fireEventPaintListeners("paintStarting",null,null);
+this._prepareForPainting();
+var metrics=this._computeMetrics();
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,metrics.trackIncrement);
+this._fireEventPaintListeners("paintEnded",null,null);
+this._setOrthogonalOffset(metrics);
+};
+Timeline.OriginalEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.OriginalEventPainter.prototype.getOrthogonalExtent=function(){var metrics=this._computeMetrics();
+return 2*metrics.trackOffset+this._tracks.length*metrics.trackIncrement;
+};
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset=function(metrics){var orthogonalOffset=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=orthogonalOffset+"px";
+};
+Timeline.OriginalEventPainter.prototype._computeMetrics=function(){var eventTheme=this._params.theme.event;
+var trackHeight=Math.max(eventTheme.track.height,eventTheme.tape.height+this._frc.getLineHeight());
+var metrics={trackOffset:eventTheme.track.offset,trackHeight:trackHeight,trackGap:eventTheme.track.gap,trackIncrement:trackHeight+eventTheme.track.gap,icon:eventTheme.instant.icon,iconWidth:eventTheme.instant.iconWidth,iconHeight:eventTheme.instant.iconHeight,labelWidth:eventTheme.label.width,maxLabelChar:eventTheme.label.maxLabelChar,impreciseIconMargin:eventTheme.instant.impreciseIconMargin};
+return metrics;
+};
+Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OriginalEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=labelRight;
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var iconElmtData=this._paintEventIcon(evt,track,iconLeftEdge,metrics,theme,0);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[iconElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,iconElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+this._tracks[track]=iconLeftEdge;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var tapeHeight=theme.event.tape.height;
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+tapeHeight);
+var iconElmtData=this._paintEventIcon(evt,track,iconLeftEdge,metrics,theme,tapeHeight);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var color=evt.getColor();
+color=color!=null?color:theme.event.instant.impreciseColor;
+var tapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,color,theme.event.instant.impreciseOpacity,metrics,theme,0);
+var els=[iconElmtData.elmt,labelElmtData.elmt,tapeElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,iconElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+this._tracks[track]=iconLeftEdge;
+};
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=startPixel;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+theme.event.tape.height);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var tapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,color,100,metrics,theme,0);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[tapeElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,tapeElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+this._tracks[track]=startPixel;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var latestStartDate=evt.getLatestStart();
+var endDate=evt.getEnd();
+var earliestEndDate=evt.getEarliestEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=latestStartPixel;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+theme.event.tape.height);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var impreciseTapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme,0);
+var tapeElmtData=this._paintEventTape(evt,track,latestStartPixel,earliestEndPixel,color,100,metrics,theme,1);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[impreciseTapeElmtData.elmt,tapeElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,tapeElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+this._tracks[track]=startPixel;
+};
+Timeline.OriginalEventPainter.prototype._encodeEventElID=function(elType,evt){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,elType,evt);
+};
+Timeline.OriginalEventPainter.prototype._findFreeTrack=function(event,rightEdge){var trackAttribute=event.getTrackNum();
+if(trackAttribute!=null){return trackAttribute;
+}for(var i=0;
+i<this._tracks.length;
+i++){var t=this._tracks[i];
+if(t>rightEdge){break;
+}}return i;
+};
+Timeline.OriginalEventPainter.prototype._paintEventIcon=function(evt,iconTrack,left,metrics,theme,tapeHeight){var icon=evt.getIcon();
+icon=icon!=null?icon:metrics.icon;
+var top;
+if(tapeHeight>0){top=metrics.trackOffset+iconTrack*metrics.trackIncrement+tapeHeight+metrics.impreciseIconMargin;
+}else{var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+top=Math.round(middle-metrics.iconHeight/2);
+}var img=SimileAjax.Graphics.createTranslucentImage(icon);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.className=this._getElClassName("timeline-event-icon",evt,"icon");
+iconDiv.id=this._encodeEventElID("icon",evt);
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+if(evt._title!=null){iconDiv.title=evt._title;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.OriginalEventPainter.prototype._paintEventLabel=function(evt,text,left,top,width,height,theme,labelDivClassName,highlightIndex){var doc=this._timeline.getDocument();
+var labelDiv=doc.createElement("div");
+labelDiv.className=labelDivClassName;
+labelDiv.id=this._encodeEventElID("label",evt);
+labelDiv.style.left=left+"px";
+labelDiv.style.width=width+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=text;
+if(evt._title!=null){labelDiv.title=evt._title;
+}var color=evt.getTextColor();
+if(color==null){color=evt.getColor();
+}if(color!=null){labelDiv.style.color=color;
+}if(theme.event.highlightLabelBackground&&highlightIndex>=0){labelDiv.style.background=this._getHighlightColor(highlightIndex,theme);
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.OriginalEventPainter.prototype._paintEventTape=function(evt,iconTrack,startPixel,endPixel,color,opacity,metrics,theme,tape_index){var tapeWidth=endPixel-startPixel;
+var tapeHeight=theme.event.tape.height;
+var top=metrics.trackOffset+iconTrack*metrics.trackIncrement;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className=this._getElClassName("timeline-event-tape",evt,"tape");
+tapeDiv.id=this._encodeEventElID("tape"+tape_index,evt);
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.width=tapeWidth+"px";
+tapeDiv.style.height=tapeHeight+"px";
+tapeDiv.style.top=top+"px";
+if(evt._title!=null){tapeDiv.title=evt._title;
+}if(color!=null){tapeDiv.style.backgroundColor=color;
+}var backgroundImage=evt.getTapeImage();
+var backgroundRepeat=evt.getTapeRepeat();
+backgroundRepeat=backgroundRepeat!=null?backgroundRepeat:"repeat";
+if(backgroundImage!=null){tapeDiv.style.backgroundImage="url("+backgroundImage+")";
+tapeDiv.style.backgroundRepeat=backgroundRepeat;
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:tapeWidth,height:tapeHeight,elmt:tapeDiv};
+};
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(evt){return this._getElClassName("timeline-event-label",evt,"label");
+};
+Timeline.OriginalEventPainter.prototype._getElClassName=function(elClassName,evt,prefix){var evt_classname=evt.getClassName(),pieces=[];
+if(evt_classname){if(prefix){pieces.push(prefix+"-"+evt_classname+" ");
+}pieces.push(evt_classname+" ");
+}pieces.push(elClassName);
+return(pieces.join(""));
+};
+Timeline.OriginalEventPainter.prototype._getHighlightColor=function(highlightIndex,theme){var highlightColors=theme.event.highlightColors;
+return highlightColors[Math.min(highlightIndex,highlightColors.length-1)];
+};
+Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme,evt){var div=null;
+if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var color=this._getHighlightColor(highlightIndex,theme);
+div=doc.createElement("div");
+div.className=this._getElClassName("timeline-event-highlight",evt,"highlight");
+div.id=this._encodeEventElID("highlight0",evt);
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}return div;
+};
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.OriginalEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,evt);
+}};
+Timeline.OriginalEventPainter.prototype._showBubble=function(x,y,evt){var div=document.createElement("div");
+var themeBubble=this._params.theme.event.bubble;
+evt.fillInfoBubble(div,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,themeBubble.width,null,themeBubble.maxHeight);
+};
+Timeline.OriginalEventPainter.prototype._fireOnSelect=function(eventID){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventID);
+}};
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(op,evt,els){for(var i=0;
+i<this._eventPaintListeners.length;
+i++){this._eventPaintListeners[i](this._band,op,evt,els);
+}};
+Timeline.OverviewEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+};
+Timeline.OverviewEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._eventLayer=null;
+this._highlightLayer=null;
+};
+Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
+};
+Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._prepareForPainting();
+var eventTheme=this._params.theme.event;
+var metrics={trackOffset:eventTheme.overviewTrack.offset,trackHeight:eventTheme.overviewTrack.height,trackGap:eventTheme.overviewTrack.gap,trackIncrement:eventTheme.overviewTrack.height+eventTheme.overviewTrack.gap};
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,metrics.trackIncrement);
+};
+Timeline.OverviewEventPainter.prototype.softPaint=function(){};
+Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OverviewEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var color=evt.getColor(),klassName=evt.getClassName();
+if(klassName){color=null;
+}else{color=color!=null?color:theme.event.duration.color;
+}var tickElmtData=this._paintEventTick(evt,startPixel,color,100,metrics,theme);
+this._createHighlightDiv(highlightIndex,tickElmtData,theme);
+};
+Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){var latestStartDate=evt.getLatestStart();
+var earliestEndDate=evt.getEarliestEnd();
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var tapeTrack=0;
+for(;
+tapeTrack<this._tracks.length;
+tapeTrack++){if(earliestEndPixel<this._tracks[tapeTrack]){break;
+}}this._tracks[tapeTrack]=earliestEndPixel;
+var color=evt.getColor(),klassName=evt.getClassName();
+if(klassName){color=null;
+}else{color=color!=null?color:theme.event.duration.color;
+}var tapeElmtData=this._paintEventTape(evt,tapeTrack,latestStartPixel,earliestEndPixel,color,100,metrics,theme,klassName);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+};
+Timeline.OverviewEventPainter.prototype._paintEventTape=function(evt,track,left,right,color,opacity,metrics,theme,klassName){var top=metrics.trackOffset+track*metrics.trackIncrement;
+var width=right-left;
+var height=metrics.trackHeight;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className="timeline-small-event-tape";
+if(klassName){tapeDiv.className+=" small-"+klassName;
+}tapeDiv.style.left=left+"px";
+tapeDiv.style.width=width+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.height=height+"px";
+if(color){tapeDiv.style.backgroundColor=color;
+}if(opacity<100){SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+}this._eventLayer.appendChild(tapeDiv);
+return{left:left,top:top,width:width,height:height,elmt:tapeDiv};
+};
+Timeline.OverviewEventPainter.prototype._paintEventTick=function(evt,left,color,opacity,metrics,theme){var height=theme.event.overviewTrack.tickHeight;
+var top=metrics.trackOffset-height;
+var width=1;
+var tickDiv=this._timeline.getDocument().createElement("div");
+tickDiv.className="timeline-small-event-icon";
+tickDiv.style.left=left+"px";
+tickDiv.style.top=top+"px";
+var klassName=evt.getClassName();
+if(klassName){tickDiv.className+=" small-"+klassName;
+}if(opacity<100){SimileAjax.Graphics.setOpacity(tickDiv,opacity);
+}this._eventLayer.appendChild(tickDiv);
+return{left:left,top:top,width:width,height:height,elmt:tickDiv};
+};
+Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-1)+"px";
+div.style.width=(dimensions.width+2)+"px";
+div.style.top=(dimensions.top-1)+"px";
+div.style.height=(dimensions.height+2)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}};
+Timeline.OverviewEventPainter.prototype.showBubble=function(evt){};
+Timeline.DefaultEventSource=function(eventIndex){this._events=(eventIndex instanceof Object)?eventIndex:new SimileAjax.EventIndex();
+this._listeners=[];
+};
+Timeline.DefaultEventSource.prototype.addListener=function(listener){this._listeners.push(listener);
+};
+Timeline.DefaultEventSource.prototype.removeListener=function(listener){for(var i=0;
+i<this._listeners.length;
+i++){if(this._listeners[i]==listener){this._listeners.splice(i,1);
+break;
+}}};
+Timeline.DefaultEventSource.prototype.loadXML=function(xml,url){var base=this._getBaseURL(url);
+var wikiURL=xml.documentElement.getAttribute("wiki-url");
+var wikiSection=xml.documentElement.getAttribute("wiki-section");
+var dateTimeFormat=xml.documentElement.getAttribute("date-time-format");
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+var node=xml.documentElement.firstChild;
+var added=false;
+while(node!=null){if(node.nodeType==1){var description="";
+if(node.firstChild!=null&&node.firstChild.nodeType==3){description=node.firstChild.nodeValue;
+}var instant=(node.getAttribute("isDuration")===null&&node.getAttribute("durationEvent")===null)||node.getAttribute("isDuration")=="false"||node.getAttribute("durationEvent")=="false";
+var evt=new Timeline.DefaultEventSource.Event({id:node.getAttribute("id"),start:parseDateTimeFunction(node.getAttribute("start")),end:parseDateTimeFunction(node.getAttribute("end")),latestStart:parseDateTimeFunction(node.getAttribute("latestStart")),earliestEnd:parseDateTimeFunction(node.getAttribute("earliestEnd")),instant:instant,text:node.getAttribute("title"),description:description,image:this._resolveRelativeURL(node.getAttribute("image"),base),link:this._resolveRelativeURL(node.getAttribute("link"),base),icon:this._resolveRelativeURL(node.getAttribute("icon"),base),color:node.getAttribute("color"),textColor:node.getAttribute("textColor"),hoverText:node.getAttribute("hoverText"),classname:node.getAttribute("classname"),tapeImage:node.getAttribute("tapeImage"),tapeRepeat:node.getAttribute("tapeRepeat"),caption:node.getAttribute("caption"),eventID:node.getAttribute("eventID"),trackNum:node.getAttribute("trackNum")});
+evt._node=node;
+evt.getProperty=function(name){return this._node.getAttribute(name);
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}node=node.nextSibling;
+}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadJSON=function(data,url){var base=this._getBaseURL(url);
+var added=false;
+if(data&&data.events){var wikiURL=("wikiURL" in data)?data.wikiURL:null;
+var wikiSection=("wikiSection" in data)?data.wikiSection:null;
+var dateTimeFormat=("dateTimeFormat" in data)?data.dateTimeFormat:null;
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+for(var i=0;
+i<data.events.length;
+i++){var evnt=data.events[i];
+var instant=evnt.isDuration||(("durationEvent" in evnt)&&!evnt.durationEvent)||(("de" in evnt)&&!evnt.de);
+var evt=new Timeline.DefaultEventSource.Event({id:("id" in evnt)?evnt.id:undefined,start:parseDateTimeFunction(evnt.start||evnt.s),end:parseDateTimeFunction(evnt.end||evnt.e),latestStart:parseDateTimeFunction(evnt.latestStart||evnt.ls),earliestEnd:parseDateTimeFunction(evnt.earliestEnd||evnt.ee),instant:instant,text:evnt.title||evnt.t,description:evnt.description||evnt.d,image:this._resolveRelativeURL(evnt.image,base),link:this._resolveRelativeURL(evnt.link,base),icon:this._resolveRelativeURL(evnt.icon,base),color:evnt.color,textColor:evnt.textColor,hoverText:evnt.hoverText,classname:evnt.classname||evnt.c,tapeImage:evnt.tapeImage,tapeRepeat:evnt.tapeRepeat,caption:evnt.caption,eventID:evnt.eventID||evnt.eid,trackNum:evnt.trackNum});
+evt._obj=evnt;
+evt.getProperty=function(name){return this._obj[name];
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadSPARQL=function(xml,url){var base=this._getBaseURL(url);
+var dateTimeFormat="iso8601";
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+if(xml==null){return ;
+}var node=xml.documentElement.firstChild;
+while(node!=null&&(node.nodeType!=1||node.nodeName!="results")){node=node.nextSibling;
+}var wikiURL=null;
+var wikiSection=null;
+if(node!=null){wikiURL=node.getAttribute("wiki-url");
+wikiSection=node.getAttribute("wiki-section");
+node=node.firstChild;
+}var added=false;
+while(node!=null){if(node.nodeType==1){var bindings={};
+var binding=node.firstChild;
+while(binding!=null){if(binding.nodeType==1&&binding.firstChild!=null&&binding.firstChild.nodeType==1&&binding.firstChild.firstChild!=null&&binding.firstChild.firstChild.nodeType==3){bindings[binding.getAttribute("name")]=binding.firstChild.firstChild.nodeValue;
+}binding=binding.nextSibling;
+}if(bindings["start"]==null&&bindings["date"]!=null){bindings["start"]=bindings["date"];
+}var instant=(bindings["isDuration"]===null&&bindings["durationEvent"]===null)||bindings["isDuration"]=="false"||bindings["durationEvent"]=="false";
+var evt=new Timeline.DefaultEventSource.Event({id:bindings["id"],start:parseDateTimeFunction(bindings["start"]),end:parseDateTimeFunction(bindings["end"]),latestStart:parseDateTimeFunction(bindings["latestStart"]),earliestEnd:parseDateTimeFunction(bindings["earliestEnd"]),instant:instant,text:bindings["title"],description:bindings["description"],image:this._resolveRelativeURL(bindings["image"],base),link:this._resolveRelativeURL(bindings["link"],base),icon:this._resolveRelativeURL(bindings["icon"],base),color:bindings["color"],textColor:bindings["textColor"],hoverText:bindings["hoverText"],caption:bindings["caption"],classname:bindings["classname"],tapeImage:bindings["tapeImage"],tapeRepeat:bindings["tapeRepeat"],eventID:bindings["eventID"],trackNum:bindings["trackNum"]});
+evt._bindings=bindings;
+evt.getProperty=function(name){return this._bindings[name];
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}node=node.nextSibling;
+}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.add=function(evt){this._events.add(evt);
+this._fire("onAddOne",[evt]);
+};
+Timeline.DefaultEventSource.prototype.addMany=function(events){for(var i=0;
+i<events.length;
+i++){this._events.add(events[i]);
+}this._fire("onAddMany",[]);
+};
+Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
+this._fire("onClear",[]);
+};
+Timeline.DefaultEventSource.prototype.getEvent=function(id){return this._events.getEvent(id);
+};
+Timeline.DefaultEventSource.prototype.getEventIterator=function(startDate,endDate){return this._events.getIterator(startDate,endDate);
+};
+Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(startDate,endDate){return this._events.getReverseIterator(startDate,endDate);
+};
+Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
+};
+Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
+};
+Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
+};
+Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
+};
+Timeline.DefaultEventSource.prototype._fire=function(handlerName,args){for(var i=0;
+i<this._listeners.length;
+i++){var listener=this._listeners[i];
+if(handlerName in listener){try{listener[handlerName].apply(listener,args);
+}catch(e){SimileAjax.Debug.exception(e);
+}}}};
+Timeline.DefaultEventSource.prototype._getBaseURL=function(url){if(url.indexOf("://")<0){var url2=this._getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}var i=url.lastIndexOf("/");
+if(i<0){return"";
+}else{return url.substr(0,i+1);
+}};
+Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(url,base){if(url==null||url==""){return url;
+}else{if(url.indexOf("://")>0){return url;
+}else{if(url.substr(0,1)=="/"){return base.substr(0,base.indexOf("/",base.indexOf("://")+3))+url;
+}else{return base+url;
+}}}};
+Timeline.DefaultEventSource.Event=function(args){function cleanArg(arg){return(args[arg]!=null&&args[arg]!="")?args[arg]:null;
+}var id=args.id?args.id.trim():"";
+this._id=id.length>0?id:Timeline.EventUtils.getNewEventID();
+this._instant=args.instant||(args.end==null);
+this._start=args.start;
+this._end=(args.end!=null)?args.end:args.start;
+this._latestStart=(args.latestStart!=null)?args.latestStart:(args.instant?this._end:this._start);
+this._earliestEnd=(args.earliestEnd!=null)?args.earliestEnd:this._end;
+var err=[];
+if(this._start>this._latestStart){this._latestStart=this._start;
+err.push("start is > latestStart");
+}if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
+err.push("start is > earliestEnd");
+}if(this._start>this._end){this._end=this._earliestEnd;
+err.push("start is > end");
+}if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
+err.push("latestStart is > earliestEnd");
+}if(this._latestStart>this._end){this._end=this._earliestEnd;
+err.push("latestStart is > end");
+}if(this._earliestEnd>this._end){this._end=this._earliestEnd;
+err.push("earliestEnd is > end");
+}this._eventID=cleanArg("eventID");
+this._text=(args.text!=null)?SimileAjax.HTML.deEntify(args.text):"";
+if(err.length>0){this._text+=" PROBLEM: "+err.join(", ");
+}this._description=SimileAjax.HTML.deEntify(args.description);
+this._image=cleanArg("image");
+this._link=cleanArg("link");
+this._title=cleanArg("hoverText");
+this._title=cleanArg("caption");
+this._icon=cleanArg("icon");
+this._color=cleanArg("color");
+this._textColor=cleanArg("textColor");
+this._classname=cleanArg("classname");
+this._tapeImage=cleanArg("tapeImage");
+this._tapeRepeat=cleanArg("tapeRepeat");
+this._trackNum=cleanArg("trackNum");
+if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
+}this._wikiURL=null;
+this._wikiSection=null;
+};
+Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
+},isInstant:function(){return this._instant;
+},isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
+},getStart:function(){return this._start;
+},getEnd:function(){return this._end;
+},getLatestStart:function(){return this._latestStart;
+},getEarliestEnd:function(){return this._earliestEnd;
+},getEventID:function(){return this._eventID;
+},getText:function(){return this._text;
+},getDescription:function(){return this._description;
+},getImage:function(){return this._image;
+},getLink:function(){return this._link;
+},getIcon:function(){return this._icon;
+},getColor:function(){return this._color;
+},getTextColor:function(){return this._textColor;
+},getClassName:function(){return this._classname;
+},getTapeImage:function(){return this._tapeImage;
+},getTapeRepeat:function(){return this._tapeRepeat;
+},getTrackNum:function(){return this._trackNum;
+},getProperty:function(name){return null;
+},getWikiURL:function(){return this._wikiURL;
+},getWikiSection:function(){return this._wikiSection;
+},setWikiInfo:function(wikiURL,wikiSection){this._wikiURL=wikiURL;
+this._wikiSection=wikiSection;
+},fillDescription:function(elmt){if(this._description){elmt.innerHTML=this._description;
+}},fillWikiInfo:function(elmt){elmt.style.display="none";
+if(this._wikiURL==null||this._wikiSection==null){return ;
+}var wikiID=this.getProperty("wikiID");
+if(wikiID==null||wikiID.length==0){wikiID=this.getText();
+}if(wikiID==null||wikiID.length==0){return ;
+}elmt.style.display="inline";
+wikiID=wikiID.replace(/\s/g,"_");
+var url=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+wikiID;
+var a=document.createElement("a");
+a.href=url;
+a.target="new";
+a.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+elmt.appendChild(document.createTextNode("["));
+elmt.appendChild(a);
+elmt.appendChild(document.createTextNode("]"));
+},fillTime:function(elmt,labeller){if(this._instant){if(this.isImprecise()){elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+}else{elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+}}else{if(this.isImprecise()){elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)+" ~ "+labeller.labelPrecise(this._latestStart)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._earliestEnd)+" ~ "+labeller.labelPrecise(this._end)));
+}else{elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+}}},fillInfoBubble:function(elmt,theme,labeller){var doc=elmt.ownerDocument;
+var title=this.getText();
+var link=this.getLink();
+var image=this.getImage();
+if(image!=null){var img=doc.createElement("img");
+img.src=image;
+theme.event.bubble.imageStyler(img);
+elmt.appendChild(img);
+}var divTitle=doc.createElement("div");
+var textTitle=doc.createTextNode(title);
+if(link!=null){var a=doc.createElement("a");
+a.href=link;
+a.appendChild(textTitle);
+divTitle.appendChild(a);
+}else{divTitle.appendChild(textTitle);
+}theme.event.bubble.titleStyler(divTitle);
+elmt.appendChild(divTitle);
+var divBody=doc.createElement("div");
+this.fillDescription(divBody);
+theme.event.bubble.bodyStyler(divBody);
+elmt.appendChild(divBody);
+var divTime=doc.createElement("div");
+this.fillTime(divTime,labeller);
+theme.event.bubble.timeStyler(divTime);
+elmt.appendChild(divTime);
+var divWiki=doc.createElement("div");
+this.fillWikiInfo(divWiki);
+theme.event.bubble.wikiStyler(divWiki);
+elmt.appendChild(divWiki);
+}};
+Timeline.ClassicTheme=new Object();
+Timeline.ClassicTheme.implementations=[];
+Timeline.ClassicTheme.create=function(locale){if(locale==null){locale=Timeline.getDefaultLocale();
+}var f=Timeline.ClassicTheme.implementations[locale];
+if(f==null){f=Timeline.ClassicTheme._Impl;
+}return new f();
+};
+Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
+this.autoWidth=false;
+this.autoWidthAnimationTime=500;
+this.timeline_start=null;
+this.timeline_stop=null;
+this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
+this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"images/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(elmt){elmt.className="timeline-event-bubble-title";
+},bodyStyler:function(elmt){elmt.className="timeline-event-bubble-body";
+},imageStyler:function(elmt){elmt.className="timeline-event-bubble-image";
+},wikiStyler:function(elmt){elmt.className="timeline-event-bubble-wiki";
+},timeStyler:function(elmt){elmt.className="timeline-event-bubble-time";
+}}};
+this.mouseWheel="scroll";
+};
+Timeline.version="pre 2.4.0";
+Timeline.ajax_lib_version=SimileAjax.version;
+Timeline.display_version=Timeline.version+" (with Ajax lib "+Timeline.ajax_lib_version+")";
+Timeline.strings={};
+Timeline.HORIZONTAL=0;
+Timeline.VERTICAL=1;
+Timeline._defaultTheme=null;
+Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
+};
+Timeline.create=function(elmt,bandInfos,orientation,unit){if(Timeline.timelines==null){Timeline.timelines=[];
+}var timelineID=Timeline.timelines.length;
+Timeline.timelines[timelineID]=null;
+var new_tl=new Timeline._Impl(elmt,bandInfos,orientation,unit,timelineID);
+Timeline.timelines[timelineID]=new_tl;
+return new_tl;
+};
+Timeline.createBandInfo=function(params){var theme=("theme" in params)?params.theme:Timeline.getDefaultTheme();
+var decorators=("decorators" in params)?params.decorators:[];
+var eventSource=("eventSource" in params)?params.eventSource:null;
+var ether=new Timeline.LinearEther({centersOn:("date" in params)?params.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],pixelsPerInterval:params.intervalPixels,theme:theme});
+var etherPainter=new Timeline.GregorianEtherPainter({unit:params.intervalUnit,multiple:("multiple" in params)?params.multiple:1,theme:theme,align:("align" in params)?params.align:undefined});
+var eventPainterParams={showText:("showEventText" in params)?params.showEventText:true,theme:theme};
+if("eventPainterParams" in params){for(var prop in params.eventPainterParams){eventPainterParams[prop]=params.eventPainterParams[prop];
+}}if("trackHeight" in params){eventPainterParams.trackHeight=params.trackHeight;
+}if("trackGap" in params){eventPainterParams.trackGap=params.trackGap;
+}var layout=("overview" in params&&params.overview)?"overview":("layout" in params?params.layout:"original");
+var eventPainter;
+if("eventPainter" in params){eventPainter=new params.eventPainter(eventPainterParams);
+}else{switch(layout){case"overview":eventPainter=new Timeline.OverviewEventPainter(eventPainterParams);
+break;
+case"detailed":eventPainter=new Timeline.DetailedEventPainter(eventPainterParams);
+break;
+default:eventPainter=new Timeline.OriginalEventPainter(eventPainterParams);
+}}return{width:params.width,eventSource:eventSource,timeZone:("timeZone" in params)?params.timeZone:0,ether:ether,etherPainter:etherPainter,eventPainter:eventPainter,theme:theme,decorators:decorators,zoomIndex:("zoomIndex" in params)?params.zoomIndex:0,zoomSteps:("zoomSteps" in params)?params.zoomSteps:null};
+};
+Timeline.createHotZoneBandInfo=function(params){var theme=("theme" in params)?params.theme:Timeline.getDefaultTheme();
+var eventSource=("eventSource" in params)?params.eventSource:null;
+var ether=new Timeline.HotZoneEther({centersOn:("date" in params)?params.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],pixelsPerInterval:params.intervalPixels,zones:params.zones,theme:theme});
+var etherPainter=new Timeline.HotZoneGregorianEtherPainter({unit:params.intervalUnit,zones:params.zones,theme:theme,align:("align" in params)?params.align:undefined});
+var eventPainterParams={showText:("showEventText" in params)?params.showEventText:true,theme:theme};
+if("eventPainterParams" in params){for(var prop in params.eventPainterParams){eventPainterParams[prop]=params.eventPainterParams[prop];
+}}if("trackHeight" in params){eventPainterParams.trackHeight=params.trackHeight;
+}if("trackGap" in params){eventPainterParams.trackGap=params.trackGap;
+}var layout=("overview" in params&&params.overview)?"overview":("layout" in params?params.layout:"original");
+var eventPainter;
+if("eventPainter" in params){eventPainter=new params.eventPainter(eventPainterParams);
+}else{switch(layout){case"overview":eventPainter=new Timeline.OverviewEventPainter(eventPainterParams);
+break;
+case"detailed":eventPainter=new Timeline.DetailedEventPainter(eventPainterParams);
+break;
+default:eventPainter=new Timeline.OriginalEventPainter(eventPainterParams);
+}}return{width:params.width,eventSource:eventSource,timeZone:("timeZone" in params)?params.timeZone:0,ether:ether,etherPainter:etherPainter,eventPainter:eventPainter,theme:theme,zoomIndex:("zoomIndex" in params)?params.zoomIndex:0,zoomSteps:("zoomSteps" in params)?params.zoomSteps:null};
+};
+Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+}return Timeline._defaultTheme;
+};
+Timeline.setDefaultTheme=function(theme){Timeline._defaultTheme=theme;
+};
+Timeline.loadXML=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load data xml from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){var xml=xmlhttp.responseXML;
+if(!xml.documentElement&&xmlhttp.responseStream){xml.load(xmlhttp.responseStream);
+}f(xml,url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.getTimelineFromID=function(timelineID){return Timeline.timelines[timelineID];
+};
+Timeline.writeVersion=function(el_id){document.getElementById(el_id).innerHTML=this.display_version;
+};
+Timeline._Impl=function(elmt,bandInfos,orientation,unit,timelineID){SimileAjax.WindowManager.initialize();
+this._containerDiv=elmt;
+this._bandInfos=bandInfos;
+this._orientation=orientation==null?Timeline.HORIZONTAL:orientation;
+this._unit=(unit!=null)?unit:SimileAjax.NativeDateUnit;
+this._starting=true;
+this._autoResizing=false;
+this.autoWidth=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.autoWidth;
+this.autoWidthAnimationTime=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.autoWidthAnimationTime;
+this.timelineID=timelineID;
+this.timeline_start=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.timeline_start;
+this.timeline_stop=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.timeline_stop;
+this.timeline_at_start=false;
+this.timeline_at_stop=false;
+this._initialize();
+};
+Timeline._Impl.prototype.dispose=function(){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].dispose();
+}this._bands=null;
+this._bandInfos=null;
+this._containerDiv.innerHTML="";
+Timeline.timelines[this.timelineID]=null;
+};
+Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
+};
+Timeline._Impl.prototype.getBand=function(index){return this._bands[index];
+};
+Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
+this._starting=false;
+};
+Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
+this._distributeWidths();
+};
+Timeline._Impl.prototype.paint=function(){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].paint();
+}};
+Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
+};
+Timeline._Impl.prototype.addDiv=function(div){this._containerDiv.appendChild(div);
+};
+Timeline._Impl.prototype.removeDiv=function(div){this._containerDiv.removeChild(div);
+};
+Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
+};
+Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
+};
+Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getUnit=function(){return this._unit;
+};
+Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
+};
+Timeline._Impl.prototype.loadXML=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load data xml from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{var xml=xmlhttp.responseXML;
+if(!xml.documentElement&&xmlhttp.responseStream){xml.load(xmlhttp.responseStream);
+}f(xml,url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype._autoWidthScrollListener=function(band){band.getTimeline()._autoWidthCheck(false);
+};
+Timeline._Impl.prototype._autoWidthCheck=function(okToShrink){var timeline=this;
+var immediateChange=timeline._starting;
+var newWidth=0;
+function changeTimelineWidth(){var widthStyle=timeline.getWidthStyle();
+if(immediateChange){timeline._containerDiv.style[widthStyle]=newWidth+"px";
+}else{timeline._autoResizing=true;
+var animateParam={};
+animateParam[widthStyle]=newWidth+"px";
+SimileAjax.jQuery(timeline._containerDiv).animate(animateParam,timeline.autoWidthAnimationTime,"linear",function(){timeline._autoResizing=false;
+});
+}}function checkTimelineWidth(){var targetWidth=0;
+var currentWidth=timeline.getPixelWidth();
+if(timeline._autoResizing){return ;
+}for(var i=0;
+i<timeline._bands.length;
+i++){timeline._bands[i].checkAutoWidth();
+targetWidth+=timeline._bandInfos[i].width;
+}if(targetWidth>currentWidth||okToShrink){newWidth=targetWidth;
+changeTimelineWidth();
+timeline._distributeWidths();
+}}if(!timeline.autoWidth){return ;
+}checkTimelineWidth();
+};
+Timeline._Impl.prototype._initialize=function(){var containerDiv=this._containerDiv;
+var doc=containerDiv.ownerDocument;
+containerDiv.className=containerDiv.className.split(" ").concat("timeline-container").join(" ");
+var orientation=(this.isHorizontal())?"horizontal":"vertical";
+containerDiv.className+=" timeline-"+orientation;
+while(containerDiv.firstChild){containerDiv.removeChild(containerDiv.firstChild);
+}var elmtCopyright=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"images/copyright-vertical.png":"images/copyright.png"));
+elmtCopyright.className="timeline-copyright";
+elmtCopyright.title="SIMILE Timeline - http://www.simile-widgets.org/";
+SimileAjax.DOM.registerEvent(elmtCopyright,"click",function(){window.location="http://www.simile-widgets.org/";
+});
+containerDiv.appendChild(elmtCopyright);
+this._bands=[];
+for(var i=0;
+i<this._bandInfos.length;
+i++){var band=new Timeline._Band(this,this._bandInfos[i],i);
+this._bands.push(band);
+}this._distributeWidths();
+for(var i=0;
+i<this._bandInfos.length;
+i++){var bandInfo=this._bandInfos[i];
+if("syncWith" in bandInfo){this._bands[i].setSyncWithBand(this._bands[bandInfo.syncWith],("highlight" in bandInfo)?bandInfo.highlight:false);
+}}if(this.autoWidth){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].addOnScrollListener(this._autoWidthScrollListener);
+}}var message=SimileAjax.Graphics.createMessageBubble(doc);
+message.containerDiv.className="timeline-message-container";
+containerDiv.appendChild(message.containerDiv);
+message.contentDiv.className="timeline-message";
+message.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"images/progress-running.gif' /> Loading...";
+this.showLoadingMessage=function(){message.containerDiv.style.display="block";
+};
+this.hideLoadingMessage=function(){message.containerDiv.style.display="none";
+};
+};
+Timeline._Impl.prototype._distributeWidths=function(){var length=this.getPixelLength();
+var width=this.getPixelWidth();
+var cumulativeWidth=0;
+for(var i=0;
+i<this._bands.length;
+i++){var band=this._bands[i];
+var bandInfos=this._bandInfos[i];
+var widthString=bandInfos.width;
+var bandWidth;
+if(typeof widthString=="string"){var x=widthString.indexOf("%");
+if(x>0){var percent=parseInt(widthString.substr(0,x));
+bandWidth=Math.round(percent*width/100);
+}else{bandWidth=parseInt(widthString);
+}}else{bandWidth=widthString;
+}band.setBandShiftAndWidth(cumulativeWidth,bandWidth);
+band.setViewLength(length);
+cumulativeWidth+=bandWidth;
+}};
+Timeline._Impl.prototype.shiftOK=function(index,shift){var going_back=shift>0,going_forward=shift<0;
+if((going_back&&this.timeline_start==null)||(going_forward&&this.timeline_stop==null)||(shift==0)){return(true);
+}var secondary_shift=false;
+for(var i=0;
+i<this._bands.length&&!secondary_shift;
+i++){secondary_shift=this._bands[i].busy();
+}if(secondary_shift){return(true);
+}if((going_back&&this.timeline_at_start)||(going_forward&&this.timeline_at_stop)){return(false);
+}var ok=false;
+for(var i=0;
+i<this._bands.length&&!ok;
+i++){var band=this._bands[i];
+if(going_back){ok=(i==index?band.getMinVisibleDateAfterDelta(shift):band.getMinVisibleDate())>=this.timeline_start;
+}else{ok=(i==index?band.getMaxVisibleDateAfterDelta(shift):band.getMaxVisibleDate())<=this.timeline_stop;
+}}if(going_back){this.timeline_at_start=!ok;
+this.timeline_at_stop=false;
+}else{this.timeline_at_stop=!ok;
+this.timeline_at_start=false;
+}return(ok);
+};
+Timeline._Impl.prototype.zoom=function(zoomIn,x,y,target){var matcher=new RegExp("^timeline-band-([0-9]+)$");
+var bandIndex=null;
+var result=matcher.exec(target.id);
+if(result){bandIndex=parseInt(result[1]);
+}if(bandIndex!=null){this._bands[bandIndex].zoom(zoomIn,x,y,target);
+}this.paint();
+};
+
+
+/* labellers.js */
+Timeline.GregorianDateLabeller.monthNames["en"]=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Timeline.GregorianDateLabeller.dayNames["en"]=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+
+
+/* timeline.js */
+Timeline.strings["en"]={wikiLinkLabel:"Discuss"};
+
+
+/* compile-epilog.js */
+(function(){var f=null;
+if("SimileWidgets_onLoad" in window){if(typeof SimileWidgets_onLoad=="string"){f=eval(SimileWidgets_onLoad);
+SimileWidgets_onLoad=null;
+}else{if(typeof SimileWidgets_onLoad=="function"){f=SimileWidgets_onLoad;
+SimileWidgets_onLoad=null;
+}}}if(f!=null){f();
+}})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.css
new file mode 100644
index 00000000..b5cd3d32
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.css
@@ -0,0 +1,243 @@
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+ position:absolute;
+ background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+ position:absolute;
+ overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+ set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+ top:0;
+ height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+ width:100%;
+ left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+ position:absolute; overflow:hidden; font-size:200%;
+ font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+ position: absolute;
+ border: solid #aaa;
+ color: #aaa;
+ width: 5em;
+ height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+ position:absolute;
+ cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ background-color:#58A0DC;
+ overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+}.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input {
+ width: 0;
+}
+
+.timeline-band-scrollbar {
+ display: none;
+ position: absolute;
+ background: #f8f8f8;
+ z-index: 100;
+ overflow: hidden;
+}
+
+.timeline-band-scrollbar-thumb {
+ margin: 2px;
+ background: #666;
+ position: relative;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.js
new file mode 100644
index 00000000..959725fb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compilations/timeline-en-compilation.js
@@ -0,0 +1,3039 @@
+
+
+/* compile-prolog.js */
+window.Timeline_isCompiled=true;
+
+
+/* timeline-api.js */
+(function(){var C="2.2.1";
+var D=("Timeline_isCompiled" in window)&&window.Timeline_isCompiled;
+var I=false;
+if(document.location.search.length>0){var B=document.location.search.substr(1).split("&");
+for(var E=0;
+E<B.length;
+E++){if(B[E]=="timeline-use-local-resources"){I=true;
+}}}var H=function(){if("Timeline" in window){return ;
+}window.Timeline=new Object();
+window.Timeline.DateTime=window.SimileAjax.DateTime;
+var V=false;
+var S=["timeline.js","band.js","themes.js","ethers.js","ether-painters.js","event-utils.js","labellers.js","sources.js","original-painter.js","detailed-painter.js","overview-painter.js","compact-painter.js","decorators.js","units.js"];
+var O=["timeline.css","ethers.css","events.css"];
+var Q=["timeline.js","labellers.js"];
+var X=[];
+var U=["cs","de","en","es","fr","it","nl","ru","se","tr","vi","zh"];
+try{var L=["en"],K="en",c=null;
+var M=function(d){var g=d.split("&");
+for(var e=0;
+e<g.length;
+e++){var f=g[e].split("=");
+if(f[0]=="locales"){L=L.concat(f[1].split(","));
+}else{if(f[0]=="defaultLocale"){K=f[1];
+}else{if(f[0]=="forceLocale"){c=f[1];
+L=L.concat(f[1].split(","));
+}else{if(f[0]=="bundle"){V=f[1]!="false";
+}}}}}};
+(function(){if(typeof Timeline_urlPrefix=="string"){Timeline.urlPrefix=Timeline_urlPrefix;
+if(typeof Timeline_parameters=="string"){M(Timeline_parameters);
+}}else{var k=document.documentElement.getElementsByTagName("head");
+for(var j=0;
+j<k.length;
+j++){var d=k[j].getElementsByTagName("script");
+for(var g=0;
+g<d.length;
+g++){var e=d[g].src;
+var f=e.indexOf("timeline-api.js");
+if(f>=0){Timeline.urlPrefix=e.substr(0,f);
+var l=e.indexOf("?");
+if(l>0){M(e.substr(l+1));
+}return ;
+}}}throw new Error("Failed to derive URL prefix for Timeline API code files");
+}})();
+var J=function(d,e){SimileAjax.includeJavascriptFiles(document,d,e);
+};
+var b=function(d,e){SimileAjax.includeCssFiles(document,d,e);
+};
+if(!D){if(V){J(Timeline.urlPrefix,["timeline-bundle.js"]);
+b(Timeline.urlPrefix,["timeline-bundle.css"]);
+}else{J(Timeline.urlPrefix+"scripts/",S);
+b(Timeline.urlPrefix+"styles/",O);
+}}var R=[];
+R[K]=true;
+var P=function(d){for(var e=0;
+e<U.length;
+e++){if(d==U[e]){R[d]=true;
+return true;
+}}return false;
+};
+var W=function(d){if(P(d)){return d;
+}var e=d.indexOf("-");
+if(e>0&&P(d.substr(0,e))){return d.substr(0,e);
+}return null;
+};
+for(var Y=0;
+Y<L.length;
+Y++){W(L[Y]);
+}var N=K;
+var T=("language" in navigator?navigator.language:navigator.browserLanguage).split(";");
+for(var Y=0;
+Y<T.length;
+Y++){var Z=W(T[Y]);
+if(Z!=null){N=Z;
+break;
+}}if(!D){for(var Y=0;
+Y<U.length;
+Y++){var Z=U[Y];
+if(R[Z]){J(Timeline.urlPrefix+"scripts/l10n/"+Z+"/",Q);
+b(Timeline.urlPrefix+"styles/l10n/"+Z+"/",X);
+}}}if(c==null){Timeline.serverLocale=K;
+Timeline.clientLocale=N;
+}else{Timeline.serverLocale=c;
+Timeline.clientLocale=c;
+}}catch(a){alert(a);
+}};
+if(typeof SimileAjax=="undefined"&&!D){window.SimileAjax_onLoad=H;
+var A=I?"http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false":"http://api.simile-widgets.org/ajax/"+C+"/simile-ajax-api.js";
+if(typeof Timeline_ajax_url=="string"){A=Timeline_ajax_url;
+}var G=function(){var J=document.createElement("script");
+J.type="text/javascript";
+J.language="JavaScript";
+J.src=A;
+document.getElementsByTagName("head")[0].appendChild(J);
+};
+if(document.body==null){try{document.write("<script src='"+A+"' type='text/javascript'><\/script>");
+}catch(F){G();
+}}else{G();
+}}else{H();
+}})();
+
+
+/* timeline-bundle.js */
+Timeline._Band=function(K,J,O){if(K.autoWidth&&typeof J.width=="string"){J.width=J.width.indexOf("%")>-1?0:parseInt(J.width);
+}this._timeline=K;
+this._bandInfo=J;
+this._index=O;
+this._locale=("locale" in J)?J.locale:Timeline.getDefaultLocale();
+this._timeZone=("timeZone" in J)?J.timeZone:0;
+this._labeller=("labeller" in J)?J.labeller:(("createLabeller" in K.getUnit())?K.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
+this._theme=J.theme;
+this._zoomIndex=("zoomIndex" in J)?J.zoomIndex:0;
+this._zoomSteps=("zoomSteps" in J)?J.zoomSteps:null;
+this._dragging=false;
+this._changing=false;
+this._originalScrollSpeed=5;
+this._scrollSpeed=this._originalScrollSpeed;
+this._onScrollListeners=[];
+this._orthogonalDragging=false;
+this._viewOrthogonalOffset=0;
+this._onOrthogonalScrollListeners=[];
+var I=this;
+this._syncWithBand=null;
+this._syncWithBandHandler=function(A){I._onHighlightBandScroll();
+};
+this._syncWithBandOrthogonalScrollHandler=function(A){I._onHighlightBandOrthogonalScroll();
+};
+this._selectorListener=function(A){I._onHighlightBandScroll();
+};
+var M=this._timeline.getDocument().createElement("div");
+M.className="timeline-band-input";
+this._timeline.addDiv(M);
+this._keyboardInput=document.createElement("input");
+this._keyboardInput.type="text";
+M.appendChild(this._keyboardInput);
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
+this._div=this._timeline.getDocument().createElement("div");
+this._div.id="timeline-band-"+O;
+this._div.className="timeline-band timeline-band-"+O;
+this._timeline.addDiv(this._div);
+SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
+SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
+SimileAjax.DOM.registerEventWithObject(document.body,"mousemove",this,"_onMouseMove");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseup",this,"_onMouseUp");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseout",this,"_onMouseOut");
+var L=this._theme!=null?this._theme.mouseWheel:"scroll";
+if(L==="zoom"||L==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
+}else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
+}}this._innerDiv=this._timeline.getDocument().createElement("div");
+this._innerDiv.className="timeline-band-inner";
+this._div.appendChild(this._innerDiv);
+this._ether=J.ether;
+J.ether.initialize(this,K);
+this._etherPainter=J.etherPainter;
+J.etherPainter.initialize(this,K);
+this._eventSource=J.eventSource;
+if(this._eventSource){this._eventListener={onAddMany:function(){I._onAddMany();
+},onClear:function(){I._onClear();
+}};
+this._eventSource.addListener(this._eventListener);
+}this._eventPainter=J.eventPainter;
+this._eventTracksNeeded=0;
+this._eventTrackIncrement=0;
+J.eventPainter.initialize(this,K);
+this._decorators=("decorators" in J)?J.decorators:[];
+for(var N=0;
+N<this._decorators.length;
+N++){this._decorators[N].initialize(this,K);
+}this._supportsOrthogonalScrolling=("supportsOrthogonalScrolling" in this._eventPainter)&&this._eventPainter.supportsOrthogonalScrolling();
+if(this._supportsOrthogonalScrolling){this._scrollBar=this._timeline.getDocument().createElement("div");
+this._scrollBar.id="timeline-band-scrollbar-"+O;
+this._scrollBar.className="timeline-band-scrollbar";
+this._timeline.addDiv(this._scrollBar);
+this._scrollBar.innerHTML='<div class="timeline-band-scrollbar-thumb"> </div>';
+var P=this._scrollBar.firstChild;
+if(SimileAjax.Platform.browser.isIE){P.style.cursor="move";
+}else{P.style.cursor="-moz-grab";
+}SimileAjax.DOM.registerEventWithObject(P,"mousedown",this,"_onScrollBarMouseDown");
+}};
+Timeline._Band.SCROLL_MULTIPLES=5;
+Timeline._Band.prototype.dispose=function(){this.closeBubble();
+if(this._eventSource){this._eventSource.removeListener(this._eventListener);
+this._eventListener=null;
+this._eventSource=null;
+}this._timeline=null;
+this._bandInfo=null;
+this._labeller=null;
+this._ether=null;
+this._etherPainter=null;
+this._eventPainter=null;
+this._decorators=null;
+this._onScrollListeners=null;
+this._syncWithBandHandler=null;
+this._syncWithBandOrthogonalScrollHandler=null;
+this._selectorListener=null;
+this._div=null;
+this._innerDiv=null;
+this._keyboardInput=null;
+this._scrollBar=null;
+};
+Timeline._Band.prototype.addOnScrollListener=function(B){this._onScrollListeners.push(B);
+};
+Timeline._Band.prototype.removeOnScrollListener=function(D){for(var C=0;
+C<this._onScrollListeners.length;
+C++){if(this._onScrollListeners[C]==D){this._onScrollListeners.splice(C,1);
+break;
+}}};
+Timeline._Band.prototype.addOnOrthogonalScrollListener=function(B){this._onOrthogonalScrollListeners.push(B);
+};
+Timeline._Band.prototype.removeOnOrthogonalScrollListener=function(D){for(var C=0;
+C<this._onOrthogonalScrollListeners.length;
+C++){if(this._onOrthogonalScrollListeners[C]==D){this._onOrthogonalScrollListeners.splice(C,1);
+break;
+}}};
+Timeline._Band.prototype.setSyncWithBand=function(D,C){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.removeOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+}this._syncWithBand=D;
+this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.addOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+this._highlight=C;
+this._positionHighlight();
+};
+Timeline._Band.prototype.getLocale=function(){return this._locale;
+};
+Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
+};
+Timeline._Band.prototype.getLabeller=function(){return this._labeller;
+};
+Timeline._Band.prototype.getIndex=function(){return this._index;
+};
+Timeline._Band.prototype.getEther=function(){return this._ether;
+};
+Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
+};
+Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
+};
+Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
+};
+Timeline._Band.prototype.getTimeline=function(){return this._timeline;
+};
+Timeline._Band.prototype.updateEventTrackInfo=function(D,C){this._eventTrackIncrement=C;
+if(D>this._eventTracksNeeded){this._eventTracksNeeded=D;
+}};
+Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
+}var E=this._eventPainter.getType()=="overview";
+var G=E?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
+var H=Math.ceil((this._eventTracksNeeded+G)*this._eventTrackIncrement);
+H+=E?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
+var F=this._bandInfo;
+if(H!=F.width){F.width=H;
+}};
+Timeline._Band.prototype.layout=function(){this.paint();
+};
+Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
+this._paintDecorators();
+this._paintEvents();
+};
+Timeline._Band.prototype.softLayout=function(){this.softPaint();
+};
+Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
+this._softPaintDecorators();
+this._softPaintEvents();
+};
+Timeline._Band.prototype.setBandShiftAndWidth=function(E,F){var G=this._keyboardInput.parentNode;
+var H=E+Math.floor(F/2);
+if(this._timeline.isHorizontal()){this._div.style.top=E+"px";
+this._div.style.height=F+"px";
+G.style.top=H+"px";
+G.style.left="-1em";
+}else{this._div.style.left=E+"px";
+this._div.style.width=F+"px";
+G.style.left=H+"px";
+G.style.top="-1em";
+}};
+Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
+}else{return this._div.offsetWidth;
+}};
+Timeline._Band.prototype.setViewLength=function(B){this._viewLength=B;
+this._recenterDiv();
+this._onChanging();
+};
+Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
+};
+Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
+};
+Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
+};
+Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
+};
+Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
+};
+Timeline._Band.prototype.getMinVisibleDateAfterDelta=function(B){return this._ether.pixelOffsetToDate(B);
+};
+Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
+};
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta=function(B){return this._ether.pixelOffsetToDate(this._viewLength+B);
+};
+Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
+};
+Timeline._Band.prototype.setMinVisibleDate=function(B){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(B)));
+}};
+Timeline._Band.prototype.setMaxVisibleDate=function(B){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(B)));
+}};
+Timeline._Band.prototype.setCenterVisibleDate=function(B){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(B)));
+}};
+Timeline._Band.prototype.dateToPixelOffset=function(B){return this._ether.dateToPixelOffset(B)-this._viewOffset;
+};
+Timeline._Band.prototype.pixelOffsetToDate=function(B){return this._ether.pixelOffsetToDate(B+this._viewOffset);
+};
+Timeline._Band.prototype.getViewOrthogonalOffset=function(){return this._viewOrthogonalOffset;
+};
+Timeline._Band.prototype.setViewOrthogonalOffset=function(B){this._viewOrthogonalOffset=Math.max(0,B);
+};
+Timeline._Band.prototype.createLayerDiv=function(F,H){var G=this._timeline.getDocument().createElement("div");
+G.className="timeline-band-layer"+(typeof H=="string"?(" "+H):"");
+G.style.zIndex=F;
+this._innerDiv.appendChild(G);
+var E=this._timeline.getDocument().createElement("div");
+E.className="timeline-band-layer-inner";
+if(SimileAjax.Platform.browser.isIE){E.style.cursor="move";
+}else{E.style.cursor="-moz-grab";
+}G.appendChild(E);
+return E;
+};
+Timeline._Band.prototype.removeLayerDiv=function(B){this._innerDiv.removeChild(B.parentNode);
+};
+Timeline._Band.prototype.scrollToCenter=function(F,E){var D=this._ether.dateToPixelOffset(F);
+if(D<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(D+this._viewLength));
+}else{if(D>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(D-this._viewLength));
+}}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(F)),E);
+};
+Timeline._Band.prototype.showBubbleForEvent=function(E){var D=this.getEventSource().getEvent(E);
+if(D){var F=this;
+this.scrollToCenter(D.getStart(),function(){F._eventPainter.showBubble(D);
+});
+}};
+Timeline._Band.prototype.zoom=function(H,G,I,K){if(!this._zoomSteps){return ;
+}G+=this._viewOffset;
+var J=this._ether.pixelOffsetToDate(G);
+var L=this._ether.zoom(H);
+this._etherPainter.zoom(L);
+this._moveEther(Math.round(-this._ether.dateToPixelOffset(J)));
+this._moveEther(G);
+};
+Timeline._Band.prototype._onMouseDown=function(F,D,E){if(!this._dragging){this.closeBubble();
+this._dragging=true;
+this._dragX=D.clientX;
+this._dragY=D.clientY;
+return this._cancelEvent(D);
+}};
+Timeline._Band.prototype._onMouseMove=function(K,H,I){if(this._dragging||this._orthogonalDragging){var L=H.clientX-this._dragX;
+var N=H.clientY-this._dragY;
+this._dragX=H.clientX;
+this._dragY=H.clientY;
+}if(this._dragging){if(this._timeline.isHorizontal()){this._moveEther(L,N);
+}else{this._moveEther(N,L);
+}}else{if(this._orthogonalDragging){var J=this.getViewWidth();
+var M=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._moveEther(0,-N*J/M.offsetHeight);
+}else{this._moveEther(0,-L*J/M.offsetWidth);
+}}else{return ;
+}}this._positionHighlight();
+this._showScrollbar();
+return this._cancelEvent(H);
+};
+Timeline._Band.prototype._onMouseUp=function(F,D,E){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._keyboardInput.focus();
+this._bounceBack();
+return this._cancelEvent(D);
+};
+Timeline._Band.prototype._onMouseOut=function(F,D,E){if(E==document.body){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._bounceBack();
+return this._cancelEvent(D);
+}};
+Timeline._Band.prototype._onScrollBarMouseDown=function(F,D,E){if(!this._orthogonalDragging){this.closeBubble();
+this._orthogonalDragging=true;
+this._dragX=D.clientX;
+this._dragY=D.clientY;
+return this._cancelEvent(D);
+}};
+Timeline._Band.prototype._onMouseScroll=function(P,N,R){var M=new Date();
+M=M.getTime();
+if(!this._lastScrollTime||((M-this._lastScrollTime)>50)){this._lastScrollTime=M;
+var O=0;
+if(N.wheelDelta){O=N.wheelDelta/120;
+}else{if(N.detail){O=-N.detail/3;
+}}var Q=this._theme.mouseWheel;
+if(this._zoomSteps||Q==="zoom"){var J=SimileAjax.DOM.getEventRelativeCoordinates(N,P);
+if(O!=0){var K;
+if(O>0){K=true;
+}if(O<0){K=false;
+}this._timeline.zoom(K,J.x,J.y,P);
+}}else{if(Q==="scroll"){var L=50*(O<0?-1:1);
+this._moveEther(L);
+}}}if(N.stopPropagation){N.stopPropagation();
+}N.cancelBubble=true;
+if(N.preventDefault){N.preventDefault();
+}N.returnValue=false;
+};
+Timeline._Band.prototype._onDblClick=function(J,F,H){var I=SimileAjax.DOM.getEventRelativeCoordinates(F,J);
+var G=I.x-(this._viewLength/2-this._viewOffset);
+this._autoScroll(-G);
+};
+Timeline._Band.prototype._onKeyDown=function(F,D,E){if(!this._dragging){switch(D.keyCode){case 27:break;
+case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(D);
+return false;
+}return true;
+};
+Timeline._Band.prototype._onKeyUp=function(F,D,E){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
+switch(D.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
+break;
+case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+break;
+case 33:this._autoScroll(this._timeline.getPixelLength());
+break;
+case 34:this._autoScroll(-this._timeline.getPixelLength());
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(D);
+return false;
+}return true;
+};
+Timeline._Band.prototype._autoScroll=function(F,G){var E=this;
+var H=SimileAjax.Graphics.createAnimation(function(B,A){E._moveEther(A);
+},0,F,1000,G);
+H.run();
+};
+Timeline._Band.prototype._moveEther=function(C,D){if(D===undefined){D=0;
+}this.closeBubble();
+if(!this._timeline.shiftOK(this._index,C)){return ;
+}this._viewOffset+=C;
+this._ether.shiftPixels(-C);
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+}if(this._supportsOrthogonalScrolling){if(this._eventPainter.getOrthogonalExtent()<=this.getViewWidth()){this._viewOrthogonalOffset=0;
+}else{this._viewOrthogonalOffset=this._viewOrthogonalOffset+D;
+}}if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
+}else{this.softLayout();
+}this._onChanging();
+};
+Timeline._Band.prototype._onChanging=function(){this._changing=true;
+this._fireOnScroll();
+this._setSyncWithBandDate();
+this._changing=false;
+};
+Timeline._Band.prototype.busy=function(){return(this._changing);
+};
+Timeline._Band.prototype._fireOnScroll=function(){for(var B=0;
+B<this._onScrollListeners.length;
+B++){this._onScrollListeners[B](this);
+}};
+Timeline._Band.prototype._fireOnOrthogonalScroll=function(){for(var B=0;
+B<this._onOrthogonalScrollListeners.length;
+B++){this._onOrthogonalScrollListeners[B](this);
+}};
+Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var B=this._ether.pixelOffsetToDate(this.getViewLength()/2);
+this._syncWithBand.setCenterVisibleDate(B);
+}};
+Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var C=this._syncWithBand.getCenterVisibleDate();
+var D=this._ether.dateToPixelOffset(C);
+this._moveEther(Math.round(this._viewLength/2-D));
+this._positionHighlight();
+}};
+Timeline._Band.prototype._onHighlightBandOrthogonalScroll=function(){if(this._syncWithBand){this._positionHighlight();
+}};
+Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
+};
+Timeline._Band.prototype._onClear=function(){this._paintEvents();
+};
+Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var O=this._syncWithBand.getMinVisibleDate();
+var K=this._syncWithBand.getMaxVisibleDate();
+if(this._highlight){var J=0;
+var L=1;
+var P=this._syncWithBand.getEventPainter();
+if("supportsOrthogonalScrolling" in P&&P.supportsOrthogonalScrolling()){var M=P.getOrthogonalExtent();
+var N=this._syncWithBand.getViewWidth();
+var I=Math.max(N,M);
+L=N/I;
+J=-this._syncWithBand.getViewOrthogonalOffset()/I;
+}this._etherPainter.setHighlight(O,K,J,L);
+}}};
+Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}this.layout();
+};
+Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
+this._showScrollbar();
+this._fireOnOrthogonalScroll();
+};
+Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
+};
+Timeline._Band.prototype._paintDecorators=function(){for(var B=0;
+B<this._decorators.length;
+B++){this._decorators[B].paint();
+}};
+Timeline._Band.prototype._softPaintDecorators=function(){for(var B=0;
+B<this._decorators.length;
+B++){this._decorators[B].softPaint();
+}};
+Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
+};
+Timeline._Band.prototype._bounceBack=function(G){if(!this._supportsOrthogonalScrolling){return ;
+}var F=0;
+if(this._viewOrthogonalOffset<0){var H=this._eventPainter.getOrthogonalExtent();
+if(this._viewOrthogonalOffset+H>=this.getViewWidth()){F=this._viewOrthogonalOffset;
+}else{F=Math.min(0,this.getViewWidth()-H);
+}}if(F!=this._viewOrthogonalOffset){var E=this;
+SimileAjax.Graphics.createAnimation(function(B,A){E._viewOrthogonalOffset=B;
+E._eventPainter.softPaint();
+E._showScrollbar();
+E._fireOnOrthogonalScroll();
+},this._viewOrthogonalOffset,F,300,function(){E._hideScrollbar();
+}).run();
+}else{this._hideScrollbar();
+}};
+Timeline._Band.prototype._showScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}var M=this._eventPainter.getOrthogonalExtent();
+var N=this.getViewWidth();
+var P=Math.max(N,M);
+var K=(N/P);
+var L=Math.round(N*K)+"px";
+var J=Math.round(-this._viewOrthogonalOffset*K)+"px";
+var I=12;
+var O=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._scrollBar.style.top=this._div.style.top;
+this._scrollBar.style.height=this._div.style.height;
+this._scrollBar.style.right="0px";
+this._scrollBar.style.width=I+"px";
+O.style.top=J;
+O.style.height=L;
+}else{this._scrollBar.style.left=this._div.style.left;
+this._scrollBar.style.width=this._div.style.width;
+this._scrollBar.style.bottom="0px";
+this._scrollBar.style.height=I+"px";
+O.style.left=J;
+O.style.width=L;
+}if(K>=1&&this._viewOrthogonalOffset==0){this._scrollBar.style.display="none";
+}else{this._scrollBar.style.display="block";
+}};
+Timeline._Band.prototype._hideScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}};
+Timeline._Band.prototype._cancelEvent=function(B){SimileAjax.DOM.cancelEvent(B);
+return false;
+};
+Timeline.CompactEventPainter=function(B){this._params=B;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.CompactEventPainter.prototype.getType=function(){return"compact";
+};
+Timeline.CompactEventPainter.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.CompactEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.CompactEventPainter.prototype.addOnSelectListener=function(B){this._onSelectListeners.push(B);
+};
+Timeline.CompactEventPainter.prototype.removeOnSelectListener=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){if(this._onSelectListeners[C]==D){this._onSelectListeners.splice(C,1);
+break;
+}}};
+Timeline.CompactEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.setFilterMatcher=function(B){this._filterMatcher=B;
+};
+Timeline.CompactEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.setHighlightMatcher=function(B){this._highlightMatcher=B;
+};
+Timeline.CompactEventPainter.prototype.paint=function(){var S=this._band.getEventSource();
+if(S==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var Y=this._computeMetrics();
+var f=this._band.getMinDate();
+var T=this._band.getMaxDate();
+var V=(this._filterMatcher!=null)?this._filterMatcher:function(A){return true;
+};
+var Z=(this._highlightMatcher!=null)?this._highlightMatcher:function(A){return -1;
+};
+var c=S.getEventIterator(f,T);
+var X="stackConcurrentPreciseInstantEvents" in this._params&&typeof this._params.stackConcurrentPreciseInstantEvents=="object";
+var a="collapseConcurrentPreciseInstantEvents" in this._params&&this._params.collapseConcurrentPreciseInstantEvents;
+if(a||X){var U=[];
+var R=null;
+while(c.hasNext()){var W=c.next();
+if(V(W)){if(!W.isInstant()||W.isImprecise()){this.paintEvent(W,Y,this._params.theme,Z(W));
+}else{if(R!=null&&R.getStart().getTime()==W.getStart().getTime()){U[U.length-1].push(W);
+}else{U.push([W]);
+R=W;
+}}}}for(var e=0;
+e<U.length;
+e++){var b=U[e];
+if(b.length==1){this.paintEvent(b[0],Y,this._params.theme,Z(W));
+}else{var d=-1;
+for(var Q=0;
+d<0&&Q<b.length;
+Q++){d=Z(b[Q]);
+}if(X){this.paintStackedPreciseInstantEvents(b,Y,this._params.theme,d);
+}else{this.paintCompositePreciseInstantEvents(b,Y,this._params.theme,d);
+}}}}else{while(c.hasNext()){var W=c.next();
+if(V(W)){this.paintEvent(W,Y,this._params.theme,Z(W));
+}}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._setOrthogonalOffset(Y);
+};
+Timeline.CompactEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.CompactEventPainter.prototype.getOrthogonalExtent=function(){var B=this._computeMetrics();
+return 2*B.trackOffset+this._tracks.length*B.trackHeight;
+};
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset=function(C){var D=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=D+"px";
+};
+Timeline.CompactEventPainter.prototype._computeMetrics=function(){var F=this._params.theme;
+var E=F.event;
+var D={trackOffset:"trackOffset" in this._params?this._params.trackOffset:10,trackHeight:"trackHeight" in this._params?this._params.trackHeight:10,tapeHeight:F.event.tape.height,tapeBottomMargin:"tapeBottomMargin" in this._params?this._params.tapeBottomMargin:2,labelBottomMargin:"labelBottomMargin" in this._params?this._params.labelBottomMargin:5,labelRightMargin:"labelRightMargin" in this._params?this._params.labelRightMargin:5,defaultIcon:E.instant.icon,defaultIconWidth:E.instant.iconWidth,defaultIconHeight:E.instant.iconHeight,customIconWidth:"iconWidth" in this._params?this._params.iconWidth:E.instant.iconWidth,customIconHeight:"iconHeight" in this._params?this._params.iconHeight:E.instant.iconHeight,iconLabelGap:"iconLabelGap" in this._params?this._params.iconLabelGap:2,iconBottomMargin:"iconBottomMargin" in this._params?this._params.iconBottomMargin:2};
+if("compositeIcon" in this._params){D.compositeIcon=this._params.compositeIcon;
+D.compositeIconWidth=this._params.compositeIconWidth||D.customIconWidth;
+D.compositeIconHeight=this._params.compositeIconHeight||D.customIconHeight;
+}else{D.compositeIcon=D.defaultIcon;
+D.compositeIconWidth=D.defaultIconWidth;
+D.compositeIconHeight=D.defaultIconHeight;
+}D.defaultStackIcon=("stackConcurrentPreciseInstantEvents" in this._params&&"icon" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.icon:D.defaultIcon;
+D.defaultStackIconWidth=("stackConcurrentPreciseInstantEvents" in this._params&&"iconWidth" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconWidth:D.defaultIconWidth;
+D.defaultStackIconHeight=("stackConcurrentPreciseInstantEvents" in this._params&&"iconHeight" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconHeight:D.defaultIconHeight;
+return D;
+};
+Timeline.CompactEventPainter.prototype._prepareForPainting=function(){var D=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var C=document.createElement("span");
+C.className="timeline-event-label";
+this._backLayer.appendChild(C);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(C);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){D.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=D.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){D.removeLayerDiv(this._lineLayer);
+}this._lineLayer=D.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){D.removeLayerDiv(this._eventLayer);
+}this._eventLayer=D.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.CompactEventPainter.prototype.paintEvent=function(H,G,F,E){if(H.isInstant()){this.paintInstantEvent(H,G,F,E);
+}else{this.paintDurationEvent(H,G,F,E);
+}};
+Timeline.CompactEventPainter.prototype.paintInstantEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseInstantEvent(H,G,F,E);
+}else{this.paintPreciseInstantEvent(H,G,F,E);
+}};
+Timeline.CompactEventPainter.prototype.paintDurationEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseDurationEvent(H,G,F,E);
+}else{this.paintPreciseDurationEvent(H,G,F,E);
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent=function(Q,S,L,M){var K={tooltip:Q.getProperty("tooltip")||Q.getText()};
+var N={url:Q.getIcon()};
+if(N.url==null){N.url=S.defaultIcon;
+N.width=S.defaultIconWidth;
+N.height=S.defaultIconHeight;
+N.className="timeline-event-icon-default";
+}else{N.width=Q.getProperty("iconWidth")||S.customIconWidth;
+N.height=Q.getProperty("iconHeight")||S.customIconHeight;
+}var R={text:Q.getText(),color:Q.getTextColor()||Q.getColor(),className:Q.getClassName()};
+var O=this.paintTapeIconLabel(Q.getStart(),K,null,N,R,S,L,M);
+var P=this;
+var T=function(B,A,C){return P._onClickInstantEvent(O.iconElmtData.elmt,A,Q);
+};
+SimileAjax.DOM.registerEvent(O.iconElmtData.elmt,"mousedown",T);
+SimileAjax.DOM.registerEvent(O.labelElmtData.elmt,"mousedown",T);
+this._eventIdToElmt[Q.getID()]=O.iconElmtData.elmt;
+};
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents=function(S,W,O,P){var U=S[0];
+var X=[];
+for(var N=0;
+N<S.length;
+N++){X.push(S[N].getProperty("tooltip")||S[N].getText());
+}var Z={tooltip:X.join("; ")};
+var Q={url:W.compositeIcon,width:W.compositeIconWidth,height:W.compositeIconHeight,className:"timeline-event-icon-composite"};
+var V={text:String.substitute(this._params.compositeEventLabelTemplate,[S.length])};
+var R=this.paintTapeIconLabel(U.getStart(),Z,null,Q,V,W,O,P);
+var T=this;
+var Y=function(C,B,A){return T._onClickMultiplePreciseInstantEvent(R.iconElmtData.elmt,B,S);
+};
+SimileAjax.DOM.registerEvent(R.iconElmtData.elmt,"mousedown",Y);
+SimileAjax.DOM.registerEvent(R.labelElmtData.elmt,"mousedown",Y);
+for(var N=0;
+N<S.length;
+N++){this._eventIdToElmt[S[N].getID()]=R.iconElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents=function(s,AW,Ae,AL){var x="limit" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.limit:10;
+var AH="moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate:"%0 More Events";
+var AA=x<=s.length-2;
+var AN=this._band;
+var Ab=function(A){return Math.round(AN.dateToPixelOffset(A));
+};
+var AC=function(A){var B={url:A.getIcon()};
+if(B.url==null){B.url=AW.defaultStackIcon;
+B.width=AW.defaultStackIconWidth;
+B.height=AW.defaultStackIconHeight;
+B.className="timeline-event-icon-stack timeline-event-icon-default";
+}else{B.width=A.getProperty("iconWidth")||AW.customIconWidth;
+B.height=A.getProperty("iconHeight")||AW.customIconHeight;
+B.className="timeline-event-icon-stack";
+}return B;
+};
+var AJ=AC(s[0]);
+var u=5;
+var AK=0;
+var AF=0;
+var AQ=0;
+var t=0;
+var AU=[];
+for(var AR=0;
+AR<s.length&&(!AA||AR<x);
+AR++){var Af=s[AR];
+var i=Af.getText();
+var v=AC(Af);
+var w=this._frc.computeSize(i);
+var AZ={text:i,iconData:v,labelSize:w,iconLeft:AJ.width+AR*u-v.width};
+AZ.labelLeft=AJ.width+AR*u+AW.iconLabelGap;
+AZ.top=AQ;
+AU.push(AZ);
+AK=Math.min(AK,AZ.iconLeft);
+AQ+=w.height;
+AF=Math.max(AF,AZ.labelLeft+w.width);
+t=Math.max(t,AZ.top+v.height);
+}if(AA){var AE=String.substitute(AH,[s.length-x]);
+var AV=this._frc.computeSize(AE);
+var AY=AJ.width+(x-1)*u+AW.iconLabelGap;
+var AS=AQ;
+AQ+=AV.height;
+AF=Math.max(AF,AY+AV.width);
+}AF+=AW.labelRightMargin;
+AQ+=AW.labelBottomMargin;
+t+=AW.iconBottomMargin;
+var AT=Ab(s[0].getStart());
+var y=[];
+var AD=Math.ceil(Math.max(t,AQ)/AW.trackHeight);
+var Ac=AJ.width+(s.length-1)*u;
+for(var AR=0;
+AR<AD;
+AR++){y.push({start:AK,end:Ac});
+}var Aa=Math.ceil(AQ/AW.trackHeight);
+for(var AR=0;
+AR<Aa;
+AR++){var AB=y[AR];
+AB.end=Math.max(AB.end,AF);
+}var AI=this._fitTracks(AT,y);
+var r=AI*AW.trackHeight+AW.trackOffset;
+var AP=this._timeline.getDocument().createElement("div");
+AP.className="timeline-event-icon-stack";
+AP.style.position="absolute";
+AP.style.overflow="visible";
+AP.style.left=AT+"px";
+AP.style.top=r+"px";
+AP.style.width=Ac+"px";
+AP.style.height=t+"px";
+AP.innerHTML="<div style='position: relative'></div>";
+this._eventLayer.appendChild(AP);
+var AG=this;
+var z=function(E){try{var A=parseInt(this.getAttribute("index"));
+var C=AP.firstChild.childNodes;
+for(var F=0;
+F<C.length;
+F++){var B=C[F];
+if(F==A){B.style.zIndex=C.length;
+}else{B.style.zIndex=C.length-F;
+}}}catch(D){}};
+var Ad=function(C){var H=AU[C];
+var F=s[C];
+var B=F.getProperty("tooltip")||F.getText();
+var D=AG._paintEventLabel({tooltip:B},{text:H.text},AT+H.labelLeft,r+H.top,H.labelSize.width,H.labelSize.height,Ae);
+D.elmt.setAttribute("index",C);
+D.elmt.onmouseover=z;
+var E=SimileAjax.Graphics.createTranslucentImage(H.iconData.url);
+var G=AG._timeline.getDocument().createElement("div");
+G.className="timeline-event-icon"+("className" in H.iconData?(" "+H.iconData.className):"");
+G.style.left=H.iconLeft+"px";
+G.style.top=H.top+"px";
+G.style.zIndex=(AU.length-C);
+G.appendChild(E);
+G.setAttribute("index",C);
+G.onmouseover=z;
+AP.firstChild.appendChild(G);
+var A=function(K,J,I){return AG._onClickInstantEvent(D.elmt,J,F);
+};
+SimileAjax.DOM.registerEvent(G,"mousedown",A);
+SimileAjax.DOM.registerEvent(D.elmt,"mousedown",A);
+AG._eventIdToElmt[F.getID()]=G;
+};
+for(var AR=0;
+AR<AU.length;
+AR++){Ad(AR);
+}if(AA){var AM=s.slice(x);
+var AO=this._paintEventLabel({tooltip:AE},{text:AE},AT+AY,r+AS,AV.width,AV.height,Ae);
+var AX=function(A,C,B){return AG._onClickMultiplePreciseInstantEvent(AO.elmt,C,AM);
+};
+SimileAjax.DOM.registerEvent(AO.elmt,"mousedown",AX);
+for(var AR=0;
+AR<AM.length;
+AR++){this._eventIdToElmt[AM[AR].getID()]=AO.elmt;
+}}};
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent=function(R,T,L,M){var V={tooltip:R.getProperty("tooltip")||R.getText()};
+var O={start:R.getStart(),end:R.getEnd(),latestStart:R.getLatestStart(),earliestEnd:R.getEarliestEnd(),color:R.getColor()||R.getTextColor(),isInstant:true};
+var N={url:R.getIcon()};
+if(N.url==null){N=null;
+}else{N.width=R.getProperty("iconWidth")||T.customIconWidth;
+N.height=R.getProperty("iconHeight")||T.customIconHeight;
+}var S={text:R.getText(),color:R.getTextColor()||R.getColor(),className:R.getClassName()};
+var P=this.paintTapeIconLabel(R.getStart(),V,O,N,S,T,L,M);
+var Q=this;
+var U=N!=null?function(A,C,B){return Q._onClickInstantEvent(P.iconElmtData.elmt,C,R);
+}:function(A,C,B){return Q._onClickInstantEvent(P.labelElmtData.elmt,C,R);
+};
+SimileAjax.DOM.registerEvent(P.labelElmtData.elmt,"mousedown",U);
+SimileAjax.DOM.registerEvent(P.impreciseTapeElmtData.elmt,"mousedown",U);
+if(N!=null){SimileAjax.DOM.registerEvent(P.iconElmtData.elmt,"mousedown",U);
+this._eventIdToElmt[R.getID()]=P.iconElmtData.elmt;
+}else{this._eventIdToElmt[R.getID()]=P.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent=function(R,T,L,M){var V={tooltip:R.getProperty("tooltip")||R.getText()};
+var O={start:R.getStart(),end:R.getEnd(),color:R.getColor()||R.getTextColor(),isInstant:false};
+var N={url:R.getIcon()};
+if(N.url==null){N=null;
+}else{N.width=R.getProperty("iconWidth")||T.customIconWidth;
+N.height=R.getProperty("iconHeight")||T.customIconHeight;
+}var S={text:R.getText(),color:R.getTextColor()||R.getColor(),className:R.getClassName()};
+var P=this.paintTapeIconLabel(R.getLatestStart(),V,O,N,S,T,L,M);
+var Q=this;
+var U=N!=null?function(A,C,B){return Q._onClickInstantEvent(P.iconElmtData.elmt,C,R);
+}:function(A,C,B){return Q._onClickInstantEvent(P.labelElmtData.elmt,C,R);
+};
+SimileAjax.DOM.registerEvent(P.labelElmtData.elmt,"mousedown",U);
+SimileAjax.DOM.registerEvent(P.tapeElmtData.elmt,"mousedown",U);
+if(N!=null){SimileAjax.DOM.registerEvent(P.iconElmtData.elmt,"mousedown",U);
+this._eventIdToElmt[R.getID()]=P.iconElmtData.elmt;
+}else{this._eventIdToElmt[R.getID()]=P.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent=function(R,T,L,M){var V={tooltip:R.getProperty("tooltip")||R.getText()};
+var O={start:R.getStart(),end:R.getEnd(),latestStart:R.getLatestStart(),earliestEnd:R.getEarliestEnd(),color:R.getColor()||R.getTextColor(),isInstant:false};
+var N={url:R.getIcon()};
+if(N.url==null){N=null;
+}else{N.width=R.getProperty("iconWidth")||T.customIconWidth;
+N.height=R.getProperty("iconHeight")||T.customIconHeight;
+}var S={text:R.getText(),color:R.getTextColor()||R.getColor(),className:R.getClassName()};
+var P=this.paintTapeIconLabel(R.getLatestStart(),V,O,N,S,T,L,M);
+var Q=this;
+var U=N!=null?function(A,C,B){return Q._onClickInstantEvent(P.iconElmtData.elmt,C,R);
+}:function(A,C,B){return Q._onClickInstantEvent(P.labelElmtData.elmt,C,R);
+};
+SimileAjax.DOM.registerEvent(P.labelElmtData.elmt,"mousedown",U);
+SimileAjax.DOM.registerEvent(P.tapeElmtData.elmt,"mousedown",U);
+if(N!=null){SimileAjax.DOM.registerEvent(P.iconElmtData.elmt,"mousedown",U);
+this._eventIdToElmt[R.getID()]=P.iconElmtData.elmt;
+}else{this._eventIdToElmt[R.getID()]=P.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel=function(AH,r,AE,z,g,i,AF,f){var m=this._band;
+var t=function(A){return Math.round(m.dateToPixelOffset(A));
+};
+var l=t(AH);
+var AG=[];
+var e=0;
+var p=0;
+var q=0;
+if(AE!=null){e=i.tapeHeight+i.tapeBottomMargin;
+p=Math.ceil(i.tapeHeight/i.trackHeight);
+var AD=t(AE.end)-l;
+var AA=t(AE.start)-l;
+for(var n=0;
+n<p;
+n++){AG.push({start:AA,end:AD});
+}q=i.trackHeight-(e%i.tapeHeight);
+}var AC=0;
+var j=0;
+if(z!=null){if("iconAlign" in z&&z.iconAlign=="center"){AC=-Math.floor(z.width/2);
+}j=AC+z.width+i.iconLabelGap;
+if(p>0){AG[p-1].end=Math.max(AG[p-1].end,j);
+}var u=z.height+i.iconBottomMargin+q;
+while(u>0){AG.push({start:AC,end:j});
+u-=i.trackHeight;
+}}var o=g.text;
+var x=this._frc.computeSize(o);
+var AB=x.height+i.labelBottomMargin+q;
+var y=j+x.width+i.labelRightMargin;
+if(p>0){AG[p-1].end=Math.max(AG[p-1].end,y);
+}for(var h=0;
+AB>0;
+h++){if(p+h<AG.length){var k=AG[p+h];
+k.end=y;
+}else{AG.push({start:0,end:y});
+}AB-=i.trackHeight;
+}var v=this._fitTracks(l,AG);
+var w=v*i.trackHeight+i.trackOffset;
+var s={};
+s.labelElmtData=this._paintEventLabel(r,g,l+j,w+e,x.width,x.height,AF);
+if(AE!=null){if("latestStart" in AE||"earliestEnd" in AE){s.impreciseTapeElmtData=this._paintEventTape(r,AE,i.tapeHeight,w,t(AE.start),t(AE.end),AF.event.duration.impreciseColor,AF.event.duration.impreciseOpacity,i,AF);
+}if(!AE.isInstant&&"start" in AE&&"end" in AE){s.tapeElmtData=this._paintEventTape(r,AE,i.tapeHeight,w,l,t("earliestEnd" in AE?AE.earliestEnd:AE.end),AE.color,100,i,AF);
+}}if(z!=null){s.iconElmtData=this._paintEventIcon(r,z,w+e,l+AC,i,AF);
+}return s;
+};
+Timeline.CompactEventPainter.prototype._fitTracks=function(I,L){var J;
+for(J=0;
+J<this._tracks.length;
+J++){var M=true;
+for(var O=0;
+O<L.length&&(J+O)<this._tracks.length;
+O++){var K=this._tracks[J+O];
+var P=L[O];
+if(I+P.start<K){M=false;
+break;
+}}if(M){break;
+}}for(var N=0;
+N<L.length;
+N++){this._tracks[J+N]=I+L[N].end;
+}return J;
+};
+Timeline.CompactEventPainter.prototype._paintEventIcon=function(O,N,J,K,M,L){var P=SimileAjax.Graphics.createTranslucentImage(N.url);
+var I=this._timeline.getDocument().createElement("div");
+I.className="timeline-event-icon"+("className" in N?(" "+N.className):"");
+I.style.left=K+"px";
+I.style.top=J+"px";
+I.appendChild(P);
+if("tooltip" in O&&typeof O.tooltip=="string"){I.title=O.tooltip;
+}this._eventLayer.appendChild(I);
+return{left:K,top:J,width:M.iconWidth,height:M.iconHeight,elmt:I};
+};
+Timeline.CompactEventPainter.prototype._paintEventLabel=function(J,P,L,Q,M,N,K){var O=this._timeline.getDocument();
+var R=O.createElement("div");
+R.className="timeline-event-label";
+R.style.left=L+"px";
+R.style.width=(M+1)+"px";
+R.style.top=Q+"px";
+R.innerHTML=P.text;
+if("tooltip" in J&&typeof J.tooltip=="string"){R.title=J.tooltip;
+}if("color" in P&&typeof P.color=="string"){R.style.color=P.color;
+}if("className" in P&&typeof P.className=="string"){R.className+=" "+P.className;
+}this._eventLayer.appendChild(R);
+return{left:L,top:Q,width:M,height:N,elmt:R};
+};
+Timeline.CompactEventPainter.prototype._paintEventTape=function(V,O,Q,S,W,P,M,U,T,X){var N=P-W;
+var R=this._timeline.getDocument().createElement("div");
+R.className="timeline-event-tape";
+R.style.left=W+"px";
+R.style.top=S+"px";
+R.style.width=N+"px";
+R.style.height=Q+"px";
+if("tooltip" in V&&typeof V.tooltip=="string"){R.title=V.tooltip;
+}if(M!=null&&typeof O.color=="string"){R.style.backgroundColor=M;
+}if("backgroundImage" in O&&typeof O.backgroundImage=="string"){R.style.backgroundImage="url("+backgroundImage+")";
+R.style.backgroundRepeat=("backgroundRepeat" in O&&typeof O.backgroundRepeat=="string")?O.backgroundRepeat:"repeat";
+}SimileAjax.Graphics.setOpacity(R,U);
+if("className" in O&&typeof O.className=="string"){R.className+=" "+O.className;
+}this._eventLayer.appendChild(R);
+return{left:W,top:S,width:N,height:Q,elmt:R};
+};
+Timeline.CompactEventPainter.prototype._createHighlightDiv=function(H,M,K){if(H>=0){var L=this._timeline.getDocument();
+var I=K.event;
+var N=I.highlightColors[Math.min(H,I.highlightColors.length-1)];
+var J=L.createElement("div");
+J.style.position="absolute";
+J.style.overflow="hidden";
+J.style.left=(M.left-2)+"px";
+J.style.width=(M.width+4)+"px";
+J.style.top=(M.top-2)+"px";
+J.style.height=(M.height+4)+"px";
+this._highlightLayer.appendChild(J);
+}};
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent=function(J,I,L){var H=SimileAjax.DOM.getPageCoordinates(J);
+this._showBubble(H.left+Math.ceil(J.offsetWidth/2),H.top+Math.ceil(J.offsetHeight/2),L);
+var K=[];
+for(var G=0;
+G<L.length;
+G++){K.push(L[G].getID());
+}this._fireOnSelect(K);
+I.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(I);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickInstantEvent=function(H,G,E){var F=SimileAjax.DOM.getPageCoordinates(H);
+this._showBubble(F.left+Math.ceil(H.offsetWidth/2),F.top+Math.ceil(H.offsetHeight/2),[E]);
+this._fireOnSelect([E.getID()]);
+G.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(G);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickDurationEvent=function(J,K,L){if("pageX" in K){var G=K.pageX;
+var H=K.pageY;
+}else{var I=SimileAjax.DOM.getPageCoordinates(J);
+var G=K.offsetX+I.left;
+var H=K.offsetY+I.top;
+}this._showBubble(G,H,[L]);
+this._fireOnSelect([L.getID()]);
+K.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(K);
+return false;
+};
+Timeline.CompactEventPainter.prototype.showBubble=function(D){var F=this._eventIdToElmt[D.getID()];
+if(F){var E=SimileAjax.DOM.getPageCoordinates(F);
+this._showBubble(E.left+F.offsetWidth/2,E.top+F.offsetHeight/2,[D]);
+}};
+Timeline.CompactEventPainter.prototype._showBubble=function(G,H,L){var I=document.createElement("div");
+L=("fillInfoBubble" in L)?[L]:L;
+for(var J=0;
+J<L.length;
+J++){var K=document.createElement("div");
+I.appendChild(K);
+L[J].fillInfoBubble(K,this._params.theme,this._band.getLabeller());
+}SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(I,G,H,this._params.theme.event.bubble.width);
+};
+Timeline.CompactEventPainter.prototype._fireOnSelect=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){this._onSelectListeners[C](D);
+}};
+Timeline.SpanHighlightDecorator=function(B){this._unit=B.unit!=null?B.unit:SimileAjax.NativeDateUnit;
+this._startDate=(typeof B.startDate=="string")?this._unit.parseFromObject(B.startDate):B.startDate;
+this._endDate=(typeof B.endDate=="string")?this._unit.parseFromObject(B.endDate):B.endDate;
+this._startLabel=B.startLabel!=null?B.startLabel:"";
+this._endLabel=B.endLabel!=null?B.endLabel:"";
+this._color=B.color;
+this._cssClass=B.cssClass!=null?B.cssClass:null;
+this._opacity=B.opacity!=null?B.opacity:100;
+this._zIndex=(B.inFront!=null&&B.inFront)?113:10;
+};
+Timeline.SpanHighlightDecorator.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._layerDiv=null;
+};
+Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(this._zIndex);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var U=this._band.getMinDate();
+var M=this._band.getMaxDate();
+if(this._unit.compare(this._startDate,M)<0&&this._unit.compare(this._endDate,U)>0){U=this._unit.later(U,this._startDate);
+M=this._unit.earlier(M,this._endDate);
+var L=this._band.dateToPixelOffset(U);
+var P=this._band.dateToPixelOffset(M);
+var R=this._timeline.getDocument();
+var S=function(){var A=R.createElement("table");
+A.insertRow(0).insertCell(0);
+return A;
+};
+var N=R.createElement("div");
+N.className="timeline-highlight-decorator";
+if(this._cssClass){N.className+=" "+this._cssClass;
+}if(this._color!=null){N.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(N,this._opacity);
+}this._layerDiv.appendChild(N);
+var Q=S();
+Q.className="timeline-highlight-label timeline-highlight-label-start";
+var T=Q.rows[0].cells[0];
+T.innerHTML=this._startLabel;
+if(this._cssClass){T.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(Q);
+var O=S();
+O.className="timeline-highlight-label timeline-highlight-label-end";
+var V=O.rows[0].cells[0];
+V.innerHTML=this._endLabel;
+if(this._cssClass){V.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(O);
+if(this._timeline.isHorizontal()){N.style.left=L+"px";
+N.style.width=(P-L)+"px";
+Q.style.right=(this._band.getTotalViewLength()-L)+"px";
+Q.style.width=(this._startLabel.length)+"em";
+O.style.left=P+"px";
+O.style.width=(this._endLabel.length)+"em";
+}else{N.style.top=L+"px";
+N.style.height=(P-L)+"px";
+Q.style.bottom=L+"px";
+Q.style.height="1.5px";
+O.style.top=P+"px";
+O.style.height="1.5px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
+Timeline.PointHighlightDecorator=function(B){this._unit=B.unit!=null?B.unit:SimileAjax.NativeDateUnit;
+this._date=(typeof B.date=="string")?this._unit.parseFromObject(B.date):B.date;
+this._width=B.width!=null?B.width:10;
+this._color=B.color;
+this._cssClass=B.cssClass!=null?B.cssClass:"";
+this._opacity=B.opacity!=null?B.opacity:100;
+};
+Timeline.PointHighlightDecorator.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._layerDiv=null;
+};
+Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(10);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var K=this._band.getMinDate();
+var I=this._band.getMaxDate();
+if(this._unit.compare(this._date,I)<0&&this._unit.compare(this._date,K)>0){var L=this._band.dateToPixelOffset(this._date);
+var G=L-Math.round(this._width/2);
+var J=this._timeline.getDocument();
+var H=J.createElement("div");
+H.className="timeline-highlight-point-decorator";
+H.className+=" "+this._cssClass;
+if(this._color!=null){H.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(H,this._opacity);
+}this._layerDiv.appendChild(H);
+if(this._timeline.isHorizontal()){H.style.left=G+"px";
+H.style.width=this._width+"px";
+}else{H.style.top=G+"px";
+H.style.height=this._width+"px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter=function(B){this._params=B;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.DetailedEventPainter.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
+};
+Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(B){this._onSelectListeners.push(B);
+};
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){if(this._onSelectListeners[C]==D){this._onSelectListeners.splice(C,1);
+break;
+}}};
+Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(B){this._filterMatcher=B;
+};
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(B){this._highlightMatcher=B;
+};
+Timeline.DetailedEventPainter.prototype.paint=function(){var M=this._band.getEventSource();
+if(M==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var P=this._params.theme.event;
+var R=Math.max(P.track.height,this._frc.getLineHeight());
+var S={trackOffset:Math.round(this._band.getViewWidth()/2-R/2),trackHeight:R,trackGap:P.track.gap,trackIncrement:R+P.track.gap,icon:P.instant.icon,iconWidth:P.instant.iconWidth,iconHeight:P.instant.iconHeight,labelWidth:P.label.width};
+var L=this._band.getMinDate();
+var N=this._band.getMaxDate();
+var O=(this._filterMatcher!=null)?this._filterMatcher:function(A){return true;
+};
+var T=(this._highlightMatcher!=null)?this._highlightMatcher:function(A){return -1;
+};
+var K=M.getEventReverseIterator(L,N);
+while(K.hasNext()){var Q=K.next();
+if(O(Q)){this.paintEvent(Q,S,this._params.theme,T(Q));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,S.trackIncrement);
+};
+Timeline.DetailedEventPainter.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var D=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var C=document.createElement("span");
+C.className="timeline-event-label";
+this._backLayer.appendChild(C);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(C);
+}this._frc.update();
+this._lowerTracks=[];
+this._upperTracks=[];
+if(this._highlightLayer!=null){D.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=D.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){D.removeLayerDiv(this._lineLayer);
+}this._lineLayer=D.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){D.removeLayerDiv(this._eventLayer);
+}this._eventLayer=D.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.DetailedEventPainter.prototype.paintEvent=function(H,G,F,E){if(H.isInstant()){this.paintInstantEvent(H,G,F,E);
+}else{this.paintDurationEvent(H,G,F,E);
+}};
+Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseInstantEvent(H,G,F,E);
+}else{this.paintPreciseInstantEvent(H,G,F,E);
+}};
+Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseDurationEvent(H,G,F,E);
+}else{this.paintPreciseDurationEvent(H,G,F,E);
+}};
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(d,a,X,Z){var V=this._timeline.getDocument();
+var e=d.getText();
+var j=d.getStart();
+var l=Math.round(this._band.dateToPixelOffset(j));
+var n=Math.round(l+a.iconWidth/2);
+var f=Math.round(l-a.iconWidth/2);
+var h=this._frc.computeSize(e);
+var k=this._findFreeTrackForSolid(n,l);
+var m=this._paintEventIcon(d,k,f,a,X);
+var U=n+X.event.label.offsetFromLine;
+var Y=k;
+var i=this._getTrackData(k);
+if(Math.min(i.solid,i.text)>=U+h.width){i.solid=f;
+i.text=U;
+}else{i.solid=f;
+U=l+X.event.label.offsetFromLine;
+Y=this._findFreeTrackForText(k,U+h.width,function(A){A.line=l-2;
+});
+this._getTrackData(Y).text=f;
+this._paintEventLine(d,l,k,Y,a,X);
+}var W=Math.round(a.trackOffset+Y*a.trackIncrement+a.trackHeight/2-h.height/2);
+var b=this._paintEventLabel(d,e,U,W,h.width,h.height,X);
+var c=this;
+var g=function(C,B,A){return c._onClickInstantEvent(m.elmt,B,d);
+};
+SimileAjax.DOM.registerEvent(m.elmt,"mousedown",g);
+SimileAjax.DOM.registerEvent(b.elmt,"mousedown",g);
+this._createHighlightDiv(Z,m,X);
+this._eventIdToElmt[d.getID()]=m.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(i,f,a,e){var Y=this._timeline.getDocument();
+var j=i.getText();
+var o=i.getStart();
+var d=i.getEnd();
+var r=Math.round(this._band.dateToPixelOffset(o));
+var u=Math.round(this._band.dateToPixelOffset(d));
+var v=Math.round(r+f.iconWidth/2);
+var k=Math.round(r-f.iconWidth/2);
+var m=this._frc.computeSize(j);
+var q=this._findFreeTrackForSolid(u,r);
+var p=this._paintEventTape(i,q,r,u,a.event.instant.impreciseColor,a.event.instant.impreciseOpacity,f,a);
+var t=this._paintEventIcon(i,q,k,f,a);
+var n=this._getTrackData(q);
+n.solid=k;
+var Z=v+a.event.label.offsetFromLine;
+var s=Z+m.width;
+var c;
+if(s<u){c=q;
+}else{Z=r+a.event.label.offsetFromLine;
+s=Z+m.width;
+c=this._findFreeTrackForText(q,s,function(A){A.line=r-2;
+});
+this._getTrackData(c).text=k;
+this._paintEventLine(i,r,q,c,f,a);
+}var b=Math.round(f.trackOffset+c*f.trackIncrement+f.trackHeight/2-m.height/2);
+var g=this._paintEventLabel(i,j,Z,b,m.width,m.height,a);
+var h=this;
+var l=function(C,B,A){return h._onClickInstantEvent(t.elmt,B,i);
+};
+SimileAjax.DOM.registerEvent(t.elmt,"mousedown",l);
+SimileAjax.DOM.registerEvent(p.elmt,"mousedown",l);
+SimileAjax.DOM.registerEvent(g.elmt,"mousedown",l);
+this._createHighlightDiv(e,t,a);
+this._eventIdToElmt[i.getID()]=t.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(g,d,X,b){var W=this._timeline.getDocument();
+var h=g.getText();
+var m=g.getStart();
+var a=g.getEnd();
+var o=Math.round(this._band.dateToPixelOffset(m));
+var p=Math.round(this._band.dateToPixelOffset(a));
+var k=this._frc.computeSize(h);
+var l=this._findFreeTrackForSolid(p);
+var c=g.getColor();
+c=c!=null?c:X.event.duration.color;
+var n=this._paintEventTape(g,l,o,p,c,100,d,X);
+var i=this._getTrackData(l);
+i.solid=o;
+var V=o+X.event.label.offsetFromLine;
+var Z=this._findFreeTrackForText(l,V+k.width,function(A){A.line=o-2;
+});
+this._getTrackData(Z).text=o-2;
+this._paintEventLine(g,o,l,Z,d,X);
+var Y=Math.round(d.trackOffset+Z*d.trackIncrement+d.trackHeight/2-k.height/2);
+var e=this._paintEventLabel(g,h,V,Y,k.width,k.height,X);
+var f=this;
+var j=function(B,A,C){return f._onClickDurationEvent(n.elmt,A,g);
+};
+SimileAjax.DOM.registerEvent(n.elmt,"mousedown",j);
+SimileAjax.DOM.registerEvent(e.elmt,"mousedown",j);
+this._createHighlightDiv(b,n,X);
+this._eventIdToElmt[g.getID()]=n.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(o,k,d,h){var a=this._timeline.getDocument();
+var p=o.getText();
+var w=o.getStart();
+var j=o.getLatestStart();
+var g=o.getEnd();
+var c=o.getEarliestEnd();
+var y=Math.round(this._band.dateToPixelOffset(w));
+var u=Math.round(this._band.dateToPixelOffset(j));
+var z=Math.round(this._band.dateToPixelOffset(g));
+var t=Math.round(this._band.dateToPixelOffset(c));
+var s=this._frc.computeSize(p);
+var v=this._findFreeTrackForSolid(z);
+var i=o.getColor();
+i=i!=null?i:d.event.duration.color;
+var l=this._paintEventTape(o,v,y,z,d.event.duration.impreciseColor,d.event.duration.impreciseOpacity,k,d);
+var x=this._paintEventTape(o,v,u,t,i,100,k,d);
+var q=this._getTrackData(v);
+q.solid=y;
+var b=u+d.event.label.offsetFromLine;
+var f=this._findFreeTrackForText(v,b+s.width,function(A){A.line=u-2;
+});
+this._getTrackData(f).text=u-2;
+this._paintEventLine(o,u,v,f,k,d);
+var e=Math.round(k.trackOffset+f*k.trackIncrement+k.trackHeight/2-s.height/2);
+var m=this._paintEventLabel(o,p,b,e,s.width,s.height,d);
+var n=this;
+var r=function(B,A,C){return n._onClickDurationEvent(x.elmt,A,o);
+};
+SimileAjax.DOM.registerEvent(x.elmt,"mousedown",r);
+SimileAjax.DOM.registerEvent(m.elmt,"mousedown",r);
+this._createHighlightDiv(h,x,d);
+this._eventIdToElmt[o.getID()]=x.elmt;
+};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(H,E){for(var F=0;
+true;
+F++){if(F<this._lowerTracks.length){var G=this._lowerTracks[F];
+if(Math.min(G.solid,G.text)>H&&(!(E)||G.line>E)){return F;
+}}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return F;
+}if(F<this._upperTracks.length){var G=this._upperTracks[F];
+if(Math.min(G.solid,G.text)>H&&(!(E)||G.line>E)){return -1-F;
+}}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return -1-F;
+}}};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(K,L,Q){var S;
+var R;
+var M;
+var O;
+if(K<0){S=true;
+M=-K;
+R=this._findFreeUpperTrackForText(M,L);
+O=-1-R;
+}else{if(K>0){S=false;
+M=K+1;
+R=this._findFreeLowerTrackForText(M,L);
+O=R;
+}else{var N=this._findFreeUpperTrackForText(0,L);
+var P=this._findFreeLowerTrackForText(1,L);
+if(P-1<=N){S=false;
+M=1;
+R=P;
+O=R;
+}else{S=true;
+M=0;
+R=N;
+O=-1-R;
+}}}if(S){if(R==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var T=M;
+T<R;
+T++){Q(this._upperTracks[T]);
+}}else{if(R==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var T=M;
+T<R;
+T++){Q(this._lowerTracks[T]);
+}}return O;
+};
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(D,E){for(;
+D<this._lowerTracks.length;
+D++){var F=this._lowerTracks[D];
+if(Math.min(F.solid,F.text)>=E){break;
+}}return D;
+};
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(D,E){for(;
+D<this._upperTracks.length;
+D++){var F=this._upperTracks[D];
+if(Math.min(F.solid,F.text)>=E){break;
+}}return D;
+};
+Timeline.DetailedEventPainter.prototype._getTrackData=function(B){return(B<0)?this._upperTracks[-B-1]:this._lowerTracks[B];
+};
+Timeline.DetailedEventPainter.prototype._paintEventLine=function(P,L,S,N,R,K){var Q=Math.round(R.trackOffset+S*R.trackIncrement+R.trackHeight/2);
+var O=Math.round(Math.abs(N-S)*R.trackIncrement);
+var T="1px solid "+K.event.label.lineColor;
+var M=this._timeline.getDocument().createElement("div");
+M.style.position="absolute";
+M.style.left=L+"px";
+M.style.width=K.event.label.offsetFromLine+"px";
+M.style.height=O+"px";
+if(S>N){M.style.top=(Q-O)+"px";
+M.style.borderTop=T;
+}else{M.style.top=Q+"px";
+M.style.borderBottom=T;
+}M.style.borderLeft=T;
+this._lineLayer.appendChild(M);
+};
+Timeline.DetailedEventPainter.prototype._paintEventIcon=function(P,T,M,S,K){var Q=P.getIcon();
+Q=Q!=null?Q:S.icon;
+var O=S.trackOffset+T*S.trackIncrement+S.trackHeight/2;
+var R=Math.round(O-S.iconHeight/2);
+var L=SimileAjax.Graphics.createTranslucentImage(Q);
+var N=this._timeline.getDocument().createElement("div");
+N.style.position="absolute";
+N.style.left=M+"px";
+N.style.top=R+"px";
+N.appendChild(L);
+N.style.cursor="pointer";
+if(P._title!=null){N.title=P._title;
+}this._eventLayer.appendChild(N);
+return{left:M,top:R,width:S.iconWidth,height:S.iconHeight,elmt:N};
+};
+Timeline.DetailedEventPainter.prototype._paintEventLabel=function(S,R,N,U,O,Q,L){var T=this._timeline.getDocument();
+var P=T.createElement("div");
+P.style.position="absolute";
+P.style.left=N+"px";
+P.style.width=O+"px";
+P.style.top=U+"px";
+P.style.height=Q+"px";
+P.style.backgroundColor=L.event.label.backgroundColor;
+SimileAjax.Graphics.setOpacity(P,L.event.label.backgroundOpacity);
+this._eventLayer.appendChild(P);
+var V=T.createElement("div");
+V.style.position="absolute";
+V.style.left=N+"px";
+V.style.width=O+"px";
+V.style.top=U+"px";
+V.innerHTML=R;
+V.style.cursor="pointer";
+if(S._title!=null){V.title=S._title;
+}var M=S.getTextColor();
+if(M==null){M=S.getColor();
+}if(M!=null){V.style.color=M;
+}this._eventLayer.appendChild(V);
+return{left:N,top:U,width:O,height:Q,elmt:V};
+};
+Timeline.DetailedEventPainter.prototype._paintEventTape=function(S,W,Z,Q,O,X,V,Y){var P=Q-Z;
+var N=Y.event.tape.height;
+var R=V.trackOffset+W*V.trackIncrement+V.trackHeight/2;
+var U=Math.round(R-N/2);
+var T=this._timeline.getDocument().createElement("div");
+T.style.position="absolute";
+T.style.left=Z+"px";
+T.style.width=P+"px";
+T.style.top=U+"px";
+T.style.height=N+"px";
+T.style.backgroundColor=O;
+T.style.overflow="hidden";
+T.style.cursor="pointer";
+if(S._title!=null){T.title=S._title;
+}SimileAjax.Graphics.setOpacity(T,X);
+this._eventLayer.appendChild(T);
+return{left:Z,top:U,width:P,height:N,elmt:T};
+};
+Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(H,M,K){if(H>=0){var L=this._timeline.getDocument();
+var I=K.event;
+var N=I.highlightColors[Math.min(H,I.highlightColors.length-1)];
+var J=L.createElement("div");
+J.style.position="absolute";
+J.style.overflow="hidden";
+J.style.left=(M.left-2)+"px";
+J.style.width=(M.width+4)+"px";
+J.style.top=(M.top-2)+"px";
+J.style.height=(M.height+4)+"px";
+J.style.background=N;
+this._highlightLayer.appendChild(J);
+}};
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(H,G,E){var F=SimileAjax.DOM.getPageCoordinates(H);
+this._showBubble(F.left+Math.ceil(H.offsetWidth/2),F.top+Math.ceil(H.offsetHeight/2),E);
+this._fireOnSelect(E.getID());
+G.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(G);
+return false;
+};
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(J,K,L){if("pageX" in K){var G=K.pageX;
+var H=K.pageY;
+}else{var I=SimileAjax.DOM.getPageCoordinates(J);
+var G=K.offsetX+I.left;
+var H=K.offsetY+I.top;
+}this._showBubble(G,H,L);
+this._fireOnSelect(L.getID());
+K.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(K);
+return false;
+};
+Timeline.DetailedEventPainter.prototype.showBubble=function(D){var F=this._eventIdToElmt[D.getID()];
+if(F){var E=SimileAjax.DOM.getPageCoordinates(F);
+this._showBubble(E.left+F.offsetWidth/2,E.top+F.offsetHeight/2,D);
+}};
+Timeline.DetailedEventPainter.prototype._showBubble=function(F,G,J){var H=document.createElement("div");
+var I=this._params.theme.event.bubble;
+J.fillInfoBubble(H,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(H,F,G,I.width,null,I.maxHeight);
+};
+Timeline.DetailedEventPainter.prototype._fireOnSelect=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){this._onSelectListeners[C](D);
+}};
+Timeline.GregorianEtherPainter=function(B){this._params=B;
+this._theme=B.theme;
+this._unit=B.unit;
+this._multiple=("multiple" in B)?B.multiple:1;
+};
+Timeline.GregorianEtherPainter.prototype.initialize=function(G,H){this._band=G;
+this._timeline=H;
+this._backgroundLayer=G.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var F=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[H.isHorizontal()?"hAlign":"vAlign"];
+var E=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,F,E);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.GregorianEtherPainter.prototype.setHighlight=function(E,F,G,H){this._highlight.position(E,F,G,H);
+};
+Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var K=this._band.getMinDate();
+var H=this._band.getMaxDate();
+var L=this._band.getTimeZone();
+var I=this._band.getLabeller();
+SimileAjax.DateTime.roundDownToInterval(K,this._unit,L,this._multiple,this._theme.firstDayOfWeek);
+var J=this;
+var G=function(B){for(var A=0;
+A<J._multiple;
+A++){SimileAjax.DateTime.incrementByInterval(B,J._unit);
+}};
+while(K.getTime()<H.getTime()){this._intervalMarkerLayout.createIntervalMarker(K,I,this._unit,this._markerLayer,this._lineLayer);
+G(K);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.GregorianEtherPainter.prototype.zoom=function(B){if(B!=0){this._unit+=B;
+}};
+Timeline.HotZoneGregorianEtherPainter=function(I){this._params=I;
+this._theme=I.theme;
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:I.unit,multiple:1}];
+for(var K=0;
+K<I.zones.length;
+K++){var N=I.zones[K];
+var L=SimileAjax.DateTime.parseGregorianDateTime(N.start).getTime();
+var J=SimileAjax.DateTime.parseGregorianDateTime(N.end).getTime();
+for(var M=0;
+M<this._zones.length&&J>L;
+M++){var H=this._zones[M];
+if(L<H.endTime){if(L>H.startTime){this._zones.splice(M,0,{startTime:H.startTime,endTime:L,unit:H.unit,multiple:H.multiple});
+M++;
+H.startTime=L;
+}if(J<H.endTime){this._zones.splice(M,0,{startTime:L,endTime:J,unit:N.unit,multiple:(N.multiple)?N.multiple:1});
+M++;
+H.startTime=J;
+L=J;
+}else{H.multiple=N.multiple;
+H.unit=N.unit;
+L=H.endTime;
+}}}}};
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(G,H){this._band=G;
+this._timeline=H;
+this._backgroundLayer=G.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var F=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[H.isHorizontal()?"hAlign":"vAlign"];
+var E=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,F,E);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(C,D){this._highlight.position(C,D);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var M=this._band.getMinDate();
+var P=this._band.getMaxDate();
+var R=this._band.getTimeZone();
+var T=this._band.getLabeller();
+var O=this;
+var Q=function(B,C){for(var A=0;
+A<C.multiple;
+A++){SimileAjax.DateTime.incrementByInterval(B,C.unit);
+}};
+var N=0;
+while(N<this._zones.length){if(M.getTime()<this._zones[N].endTime){break;
+}N++;
+}var X=this._zones.length-1;
+while(X>=0){if(P.getTime()>this._zones[X].startTime){break;
+}X--;
+}for(var U=N;
+U<=X;
+U++){var V=this._zones[U];
+var S=new Date(Math.max(M.getTime(),V.startTime));
+var W=new Date(Math.min(P.getTime(),V.endTime));
+SimileAjax.DateTime.roundDownToInterval(S,V.unit,R,V.multiple,this._theme.firstDayOfWeek);
+SimileAjax.DateTime.roundUpToInterval(W,V.unit,R,V.multiple,this._theme.firstDayOfWeek);
+while(S.getTime()<W.getTime()){this._intervalMarkerLayout.createIntervalMarker(S,T,V.unit,this._markerLayer,this._lineLayer);
+Q(S,V);
+}}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(D){if(D!=0){for(var C=0;
+C<this._zones.length;
+++C){if(this._zones[C]){this._zones[C].unit+=D;
+}}}};
+Timeline.YearCountEtherPainter=function(B){this._params=B;
+this._theme=B.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(B.startDate);
+this._multiple=("multiple" in B)?B.multiple:1;
+};
+Timeline.YearCountEtherPainter.prototype.initialize=function(G,H){this._band=G;
+this._timeline=H;
+this._backgroundLayer=G.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var F=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[H.isHorizontal()?"hAlign":"vAlign"];
+var E=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,F,E);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.YearCountEtherPainter.prototype.setHighlight=function(C,D){this._highlight.position(C,D);
+};
+Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var L=new Date(this._startDate.getTime());
+var H=this._band.getMaxDate();
+var I=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
+L.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-I%this._multiple);
+var K=this;
+var G=function(B){for(var A=0;
+A<K._multiple;
+A++){SimileAjax.DateTime.incrementByInterval(B,SimileAjax.DateTime.YEAR);
+}};
+var J={labelInterval:function(C,A){var B=C.getUTCFullYear()-K._startDate.getUTCFullYear();
+return{text:B,emphasized:B==0};
+}};
+while(L.getTime()<H.getTime()){this._intervalMarkerLayout.createIntervalMarker(L,J,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+G(L);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
+Timeline.QuarterlyEtherPainter=function(B){this._params=B;
+this._theme=B.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(B.startDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.initialize=function(G,H){this._band=G;
+this._timeline=H;
+this._backgroundLayer=G.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var F=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[H.isHorizontal()?"hAlign":"vAlign"];
+var E=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,F,E);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(C,D){this._highlight.position(C,D);
+};
+Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var J=new Date(0);
+var G=this._band.getMaxDate();
+J.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
+J.setUTCMonth(this._startDate.getUTCMonth());
+var I=this;
+var F=function(A){A.setUTCMonth(A.getUTCMonth()+3);
+};
+var H={labelInterval:function(C,A){var B=(4+(C.getUTCMonth()-I._startDate.getUTCMonth())/3)%4;
+if(B!=0){return{text:"Q"+(B+1),emphasized:false};
+}else{return{text:"Y"+(C.getUTCFullYear()-I._startDate.getUTCFullYear()+1),emphasized:true};
+}}};
+while(J.getTime()<G.getTime()){this._intervalMarkerLayout.createIntervalMarker(J,H,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+F(J);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
+Timeline.EtherIntervalMarkerLayout=function(R,S,O,Z,W){var Q=R.isHorizontal();
+if(Q){if(Z=="Top"){this.positionDiv=function(A,B){A.style.left=B+"px";
+A.style.top="0px";
+};
+}else{this.positionDiv=function(A,B){A.style.left=B+"px";
+A.style.bottom="0px";
+};
+}}else{if(Z=="Left"){this.positionDiv=function(A,B){A.style.top=B+"px";
+A.style.left="0px";
+};
+}else{this.positionDiv=function(A,B){A.style.top=B+"px";
+A.style.right="0px";
+};
+}}var N=O.ether.interval.marker;
+var V=O.ether.interval.line;
+var P=O.ether.interval.weekend;
+var T=(Q?"h":"v")+Z;
+var X=N[T+"Styler"];
+var U=N[T+"EmphasizedStyler"];
+var Y=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+this.createIntervalMarker=function(G,f,e,d,J){var F=Math.round(S.dateToPixelOffset(G));
+if(W&&e!=SimileAjax.DateTime.WEEK){var E=R.getDocument().createElement("div");
+E.className="timeline-ether-lines";
+if(V.opacity<100){SimileAjax.Graphics.setOpacity(E,V.opacity);
+}if(Q){E.style.left=F+"px";
+}else{E.style.top=F+"px";
+}J.appendChild(E);
+}if(e==SimileAjax.DateTime.WEEK){var M=O.firstDayOfWeek;
+var D=new Date(G.getTime()+(6-M-7)*Y);
+var A=new Date(D.getTime()+2*Y);
+var C=Math.round(S.dateToPixelOffset(D));
+var H=Math.round(S.dateToPixelOffset(A));
+var I=Math.max(1,H-C);
+var K=R.getDocument().createElement("div");
+K.className="timeline-ether-weekends";
+if(P.opacity<100){SimileAjax.Graphics.setOpacity(K,P.opacity);
+}if(Q){K.style.left=C+"px";
+K.style.width=I+"px";
+}else{K.style.top=C+"px";
+K.style.height=I+"px";
+}J.appendChild(K);
+}var B=f.labelInterval(G,e);
+var L=R.getDocument().createElement("div");
+L.innerHTML=B.text;
+L.className="timeline-date-label";
+if(B.emphasized){L.className+=" timeline-date-label-em";
+}this.positionDiv(L,F);
+d.appendChild(L);
+return L;
+};
+};
+Timeline.EtherHighlight=function(I,G,H,J){var F=I.isHorizontal();
+this._highlightDiv=null;
+this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=I.getDocument().createElement("div");
+this._highlightDiv.setAttribute("name","ether-highlight");
+this._highlightDiv.className="timeline-ether-highlight";
+var A=H.ether.highlightOpacity;
+if(A<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,A);
+}J.appendChild(this._highlightDiv);
+}};
+this.position=function(N,A,B,E){B=B||0;
+E=E||1;
+this._createHighlightDiv();
+var P=Math.round(G.dateToPixelOffset(N));
+var C=Math.round(G.dateToPixelOffset(A));
+var D=Math.max(C-P,3);
+var O=G.getViewWidth()-4;
+if(F){this._highlightDiv.style.left=P+"px";
+this._highlightDiv.style.width=D+"px";
+this._highlightDiv.style.top=Math.round(B*O)+"px";
+this._highlightDiv.style.height=Math.round(E*O)+"px";
+}else{this._highlightDiv.style.top=P+"px";
+this._highlightDiv.style.height=D+"px";
+this._highlightDiv.style.left=Math.round(B*O)+"px";
+this._highlightDiv.style.width=Math.round(E*O)+"px";
+}};
+};
+Timeline.LinearEther=function(B){this._params=B;
+this._interval=B.interval;
+this._pixelsPerInterval=B.pixelsPerInterval;
+};
+Timeline.LinearEther.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._unit=C.getUnit();
+if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.LinearEther.prototype.setDate=function(B){this._start=this._unit.cloneValue(B);
+};
+Timeline.LinearEther.prototype.shiftPixels=function(D){var C=this._interval*D/this._pixelsPerInterval;
+this._start=this._unit.change(this._start,C);
+};
+Timeline.LinearEther.prototype.dateToPixelOffset=function(C){var D=this._unit.compare(C,this._start);
+return this._pixelsPerInterval*D/this._interval;
+};
+Timeline.LinearEther.prototype.pixelOffsetToDate=function(D){var C=D*this._interval/this._pixelsPerInterval;
+return this._unit.change(this._start,C);
+};
+Timeline.LinearEther.prototype.zoom=function(F){var H=0;
+var E=this._band._zoomIndex;
+var G=E;
+if(F&&(E>0)){G=E-1;
+}if(!F&&(E<(this._band._zoomSteps.length-1))){G=E+1;
+}this._band._zoomIndex=G;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[G].unit];
+this._pixelsPerInterval=this._band._zoomSteps[G].pixelsPerInterval;
+H=this._band._zoomSteps[G].unit-this._band._zoomSteps[E].unit;
+return H;
+};
+Timeline.HotZoneEther=function(B){this._params=B;
+this._interval=B.interval;
+this._pixelsPerInterval=B.pixelsPerInterval;
+this._theme=B.theme;
+};
+Timeline.HotZoneEther.prototype.initialize=function(O,N){this._band=O;
+this._timeline=N;
+this._unit=N.getUnit();
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
+var L=this._params;
+for(var J=0;
+J<L.zones.length;
+J++){var P=L.zones[J];
+var R=this._unit.parseFromObject(P.start);
+var Q=this._unit.parseFromObject(P.end);
+for(var K=0;
+K<this._zones.length&&this._unit.compare(Q,R)>0;
+K++){var M=this._zones[K];
+if(this._unit.compare(R,M.endTime)<0){if(this._unit.compare(R,M.startTime)>0){this._zones.splice(K,0,{startTime:M.startTime,endTime:R,magnify:M.magnify});
+K++;
+M.startTime=R;
+}if(this._unit.compare(Q,M.endTime)<0){this._zones.splice(K,0,{startTime:R,endTime:Q,magnify:P.magnify*M.magnify});
+K++;
+M.startTime=Q;
+R=Q;
+}else{M.magnify*=P.magnify;
+R=M.endTime;
+}}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.HotZoneEther.prototype.setDate=function(B){this._start=this._unit.cloneValue(B);
+};
+Timeline.HotZoneEther.prototype.shiftPixels=function(B){this._start=this.pixelOffsetToDate(B);
+};
+Timeline.HotZoneEther.prototype.dateToPixelOffset=function(B){return this._dateDiffToPixelOffset(this._start,B);
+};
+Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(B){return this._pixelOffsetToDate(B,this._start);
+};
+Timeline.HotZoneEther.prototype.zoom=function(F){var H=0;
+var E=this._band._zoomIndex;
+var G=E;
+if(F&&(E>0)){G=E-1;
+}if(!F&&(E<(this._band._zoomSteps.length-1))){G=E+1;
+}this._band._zoomIndex=G;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[G].unit];
+this._pixelsPerInterval=this._band._zoomSteps[G].pixelsPerInterval;
+H=this._band._zoomSteps[G].unit-this._band._zoomSteps[E].unit;
+return H;
+};
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(N,J){var L=this._getScale();
+var O=N;
+var K=J;
+var M=0;
+if(this._unit.compare(O,K)<0){var P=0;
+while(P<this._zones.length){if(this._unit.compare(O,this._zones[P].endTime)<0){break;
+}P++;
+}while(this._unit.compare(O,K)<0){var R=this._zones[P];
+var Q=this._unit.earlier(K,R.endTime);
+M+=(this._unit.compare(Q,O)/(L/R.magnify));
+O=Q;
+P++;
+}}else{var P=this._zones.length-1;
+while(P>=0){if(this._unit.compare(O,this._zones[P].startTime)>0){break;
+}P--;
+}while(this._unit.compare(O,K)>0){var R=this._zones[P];
+var Q=this._unit.later(K,R.startTime);
+M+=(this._unit.compare(Q,O)/(L/R.magnify));
+O=Q;
+P--;
+}}return M;
+};
+Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(J,O){var K=this._getScale();
+var M=O;
+if(J>0){var L=0;
+while(L<this._zones.length){if(this._unit.compare(M,this._zones[L].endTime)<0){break;
+}L++;
+}while(J>0){var I=this._zones[L];
+var N=K/I.magnify;
+if(I.endTime==Number.POSITIVE_INFINITY){M=this._unit.change(M,J*N);
+J=0;
+}else{var P=this._unit.compare(I.endTime,M)/N;
+if(P>J){M=this._unit.change(M,J*N);
+J=0;
+}else{M=I.endTime;
+J-=P;
+}}L++;
+}}else{var L=this._zones.length-1;
+while(L>=0){if(this._unit.compare(M,this._zones[L].startTime)>0){break;
+}L--;
+}J=-J;
+while(J>0){var I=this._zones[L];
+var N=K/I.magnify;
+if(I.startTime==Number.NEGATIVE_INFINITY){M=this._unit.change(M,-J*N);
+J=0;
+}else{var P=this._unit.compare(M,I.startTime)/N;
+if(P>J){M=this._unit.change(M,-J*N);
+J=0;
+}else{M=I.startTime;
+J-=P;
+}}L--;
+}}return M;
+};
+Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
+};
+Timeline.EventUtils={};
+Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
+}this._lastEventID+=1;
+return"e"+this._lastEventID;
+};
+Timeline.EventUtils.decodeEventElID=function(J){var H=J.split("-");
+if(H[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
+return{band:null,evt:null};
+}var I=Timeline.getTimelineFromID(H[2]);
+var G=I.getBand(H[3]);
+var F=G.getEventSource.getEvent(H[4]);
+return{band:G,evt:F};
+};
+Timeline.EventUtils.encodeEventElID=function(G,F,H,E){return H+"-tl-"+G.timelineID+"-"+F.getIndex()+"-"+E.getID();
+};
+Timeline.GregorianDateLabeller=function(C,D){this._locale=C;
+this._timeZone=D;
+};
+Timeline.GregorianDateLabeller.monthNames=[];
+Timeline.GregorianDateLabeller.dayNames=[];
+Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
+Timeline.GregorianDateLabeller.getMonthName=function(D,C){return Timeline.GregorianDateLabeller.monthNames[C][D];
+};
+Timeline.GregorianDateLabeller.prototype.labelInterval=function(D,E){var F=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+if(F==null){F=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+}return F.call(this,D,E);
+};
+Timeline.GregorianDateLabeller.prototype.labelPrecise=function(B){return SimileAjax.DateTime.removeTimeZoneOffset(B,this._timeZone).toUTCString();
+};
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(L,H){var K;
+var I=false;
+L=SimileAjax.DateTime.removeTimeZoneOffset(L,this._timeZone);
+switch(H){case SimileAjax.DateTime.MILLISECOND:K=L.getUTCMilliseconds();
+break;
+case SimileAjax.DateTime.SECOND:K=L.getUTCSeconds();
+break;
+case SimileAjax.DateTime.MINUTE:var G=L.getUTCMinutes();
+if(G==0){K=L.getUTCHours()+":00";
+I=true;
+}else{K=G;
+}break;
+case SimileAjax.DateTime.HOUR:K=L.getUTCHours()+"hr";
+break;
+case SimileAjax.DateTime.DAY:K=Timeline.GregorianDateLabeller.getMonthName(L.getUTCMonth(),this._locale)+" "+L.getUTCDate();
+break;
+case SimileAjax.DateTime.WEEK:K=Timeline.GregorianDateLabeller.getMonthName(L.getUTCMonth(),this._locale)+" "+L.getUTCDate();
+break;
+case SimileAjax.DateTime.MONTH:var G=L.getUTCMonth();
+if(G!=0){K=Timeline.GregorianDateLabeller.getMonthName(G,this._locale);
+break;
+}case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var J=L.getUTCFullYear();
+if(J>0){K=L.getUTCFullYear();
+}else{K=(1-J)+"BC";
+}I=(H==SimileAjax.DateTime.MONTH)||(H==SimileAjax.DateTime.DECADE&&J%100==0)||(H==SimileAjax.DateTime.CENTURY&&J%1000==0);
+break;
+default:K=L.toUTCString();
+}return{text:K,emphasized:I};
+};
+Timeline.OriginalEventPainter=function(B){this._params=B;
+this._onSelectListeners=[];
+this._eventPaintListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.OriginalEventPainter.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
+};
+Timeline.OriginalEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(B){this._onSelectListeners.push(B);
+};
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){if(this._onSelectListeners[C]==D){this._onSelectListeners.splice(C,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(B){this._eventPaintListeners.push(B);
+};
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(D){for(var C=0;
+C<this._eventPaintListeners.length;
+C++){if(this._eventPaintListeners[C]==D){this._eventPaintListeners.splice(C,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(B){this._filterMatcher=B;
+};
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(B){this._highlightMatcher=B;
+};
+Timeline.OriginalEventPainter.prototype.paint=function(){var L=this._band.getEventSource();
+if(L==null){return ;
+}this._eventIdToElmt={};
+this._fireEventPaintListeners("paintStarting",null,null);
+this._prepareForPainting();
+var N=this._computeMetrics();
+var M=this._band.getMinDate();
+var J=this._band.getMaxDate();
+var P=(this._filterMatcher!=null)?this._filterMatcher:function(A){return true;
+};
+var K=(this._highlightMatcher!=null)?this._highlightMatcher:function(A){return -1;
+};
+var O=L.getEventReverseIterator(M,J);
+while(O.hasNext()){var I=O.next();
+if(P(I)){this.paintEvent(I,N,this._params.theme,K(I));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,N.trackIncrement);
+this._fireEventPaintListeners("paintEnded",null,null);
+this._setOrthogonalOffset(N);
+};
+Timeline.OriginalEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.OriginalEventPainter.prototype.getOrthogonalExtent=function(){var B=this._computeMetrics();
+return 2*B.trackOffset+this._tracks.length*B.trackIncrement;
+};
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset=function(C){var D=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=D+"px";
+};
+Timeline.OriginalEventPainter.prototype._computeMetrics=function(){var E=this._params.theme.event;
+var F=Math.max(E.track.height,E.tape.height+this._frc.getLineHeight());
+var D={trackOffset:E.track.offset,trackHeight:F,trackGap:E.track.gap,trackIncrement:F+E.track.gap,icon:E.instant.icon,iconWidth:E.instant.iconWidth,iconHeight:E.instant.iconHeight,labelWidth:E.label.width,maxLabelChar:E.label.maxLabelChar,impreciseIconMargin:E.instant.impreciseIconMargin};
+return D;
+};
+Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var D=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var C=document.createElement("span");
+C.className="timeline-event-label";
+this._backLayer.appendChild(C);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(C);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){D.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=D.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){D.removeLayerDiv(this._lineLayer);
+}this._lineLayer=D.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){D.removeLayerDiv(this._eventLayer);
+}this._eventLayer=D.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OriginalEventPainter.prototype.paintEvent=function(H,G,F,E){if(H.isInstant()){this.paintInstantEvent(H,G,F,E);
+}else{this.paintDurationEvent(H,G,F,E);
+}};
+Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseInstantEvent(H,G,F,E);
+}else{this.paintPreciseInstantEvent(H,G,F,E);
+}};
+Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(H,G,F,E){if(H.isImprecise()){this.paintImpreciseDurationEvent(H,G,F,E);
+}else{this.paintPreciseDurationEvent(H,G,F,E);
+}};
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(h,d,b,c){var Y=this._timeline.getDocument();
+var i=h.getText();
+var p=h.getStart();
+var r=Math.round(this._band.dateToPixelOffset(p));
+var t=Math.round(r+d.iconWidth/2);
+var j=Math.round(r-d.iconWidth/2);
+var m=this._getLabelDivClassName(h);
+var l=this._frc.computeSize(i,m);
+var X=t+b.event.label.offsetFromLine;
+var q=X+l.width;
+var Z=q;
+var f=this._findFreeTrack(h,Z);
+var a=Math.round(d.trackOffset+f*d.trackIncrement+d.trackHeight/2-l.height/2);
+var s=this._paintEventIcon(h,f,j,d,b,0);
+var e=this._paintEventLabel(h,i,X,a,l.width,l.height,b,m,c);
+var o=[s.elmt,e.elmt];
+var g=this;
+var k=function(C,B,A){return g._onClickInstantEvent(s.elmt,B,h);
+};
+SimileAjax.DOM.registerEvent(s.elmt,"mousedown",k);
+SimileAjax.DOM.registerEvent(e.elmt,"mousedown",k);
+var n=this._createHighlightDiv(c,s,b,h);
+if(n!=null){o.push(n);
+}this._fireEventPaintListeners("paintedEvent",h,o);
+this._eventIdToElmt[h.getID()]=s.elmt;
+this._tracks[f]=j;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(m,i,d,g){var AD=this._timeline.getDocument();
+var o=m.getText();
+var v=m.getStart();
+var f=m.getEnd();
+var y=Math.round(this._band.dateToPixelOffset(v));
+var AA=Math.round(this._band.dateToPixelOffset(f));
+var AB=Math.round(y+i.iconWidth/2);
+var p=Math.round(y-i.iconWidth/2);
+var s=this._getLabelDivClassName(m);
+var r=this._frc.computeSize(o,s);
+var AC=AB+d.event.label.offsetFromLine;
+var x=AC+r.width;
+var c=Math.max(x,AA);
+var k=this._findFreeTrack(m,c);
+var n=d.event.tape.height;
+var e=Math.round(i.trackOffset+k*i.trackIncrement+n);
+var z=this._paintEventIcon(m,k,p,i,d,n);
+var j=this._paintEventLabel(m,o,AC,e,r.width,r.height,d,s,g);
+var h=m.getColor();
+h=h!=null?h:d.event.instant.impreciseColor;
+var w=this._paintEventTape(m,k,y,AA,h,d.event.instant.impreciseOpacity,i,d,0);
+var u=[z.elmt,j.elmt,w.elmt];
+var l=this;
+var q=function(C,B,A){return l._onClickInstantEvent(z.elmt,B,m);
+};
+SimileAjax.DOM.registerEvent(z.elmt,"mousedown",q);
+SimileAjax.DOM.registerEvent(w.elmt,"mousedown",q);
+SimileAjax.DOM.registerEvent(j.elmt,"mousedown",q);
+var t=this._createHighlightDiv(g,z,d,m);
+if(t!=null){u.push(t);
+}this._fireEventPaintListeners("paintedEvent",m,u);
+this._eventIdToElmt[m.getID()]=z.elmt;
+this._tracks[k]=p;
+};
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(k,g,c,e){var Z=this._timeline.getDocument();
+var l=k.getText();
+var r=k.getStart();
+var d=k.getEnd();
+var u=Math.round(this._band.dateToPixelOffset(r));
+var v=Math.round(this._band.dateToPixelOffset(d));
+var o=this._getLabelDivClassName(k);
+var n=this._frc.computeSize(l,o);
+var Y=u;
+var t=Y+n.width;
+var a=Math.max(t,v);
+var i=this._findFreeTrack(k,a);
+var b=Math.round(g.trackOffset+i*g.trackIncrement+c.event.tape.height);
+var f=k.getColor();
+f=f!=null?f:c.event.duration.color;
+var s=this._paintEventTape(k,i,u,v,f,100,g,c,0);
+var h=this._paintEventLabel(k,l,Y,b,n.width,n.height,c,o,e);
+var q=[s.elmt,h.elmt];
+var j=this;
+var m=function(C,B,A){return j._onClickDurationEvent(s.elmt,B,k);
+};
+SimileAjax.DOM.registerEvent(s.elmt,"mousedown",m);
+SimileAjax.DOM.registerEvent(h.elmt,"mousedown",m);
+var p=this._createHighlightDiv(e,s,c,k);
+if(p!=null){q.push(p);
+}this._fireEventPaintListeners("paintedEvent",k,q);
+this._eventIdToElmt[k.getID()]=s.elmt;
+this._tracks[i]=u;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(p,k,e,h){var AE=this._timeline.getDocument();
+var q=p.getText();
+var y=p.getStart();
+var j=p.getLatestStart();
+var g=p.getEnd();
+var AF=p.getEarliestEnd();
+var AA=Math.round(this._band.dateToPixelOffset(y));
+var w=Math.round(this._band.dateToPixelOffset(j));
+var AC=Math.round(this._band.dateToPixelOffset(g));
+var v=Math.round(this._band.dateToPixelOffset(AF));
+var t=this._getLabelDivClassName(p);
+var s=this._frc.computeSize(q,t);
+var AD=w;
+var AB=AD+s.width;
+var d=Math.max(AB,AC);
+var n=this._findFreeTrack(p,d);
+var f=Math.round(k.trackOffset+n*k.trackIncrement+e.event.tape.height);
+var i=p.getColor();
+i=i!=null?i:e.event.duration.color;
+var l=this._paintEventTape(p,n,AA,AC,e.event.duration.impreciseColor,e.event.duration.impreciseOpacity,k,e,0);
+var z=this._paintEventTape(p,n,w,v,i,100,k,e,1);
+var m=this._paintEventLabel(p,q,AD,f,s.width,s.height,e,t,h);
+var x=[l.elmt,z.elmt,m.elmt];
+var o=this;
+var r=function(C,B,A){return o._onClickDurationEvent(z.elmt,B,p);
+};
+SimileAjax.DOM.registerEvent(z.elmt,"mousedown",r);
+SimileAjax.DOM.registerEvent(m.elmt,"mousedown",r);
+var u=this._createHighlightDiv(h,z,e,p);
+if(u!=null){x.push(u);
+}this._fireEventPaintListeners("paintedEvent",p,x);
+this._eventIdToElmt[p.getID()]=z.elmt;
+this._tracks[n]=AA;
+};
+Timeline.OriginalEventPainter.prototype._encodeEventElID=function(D,C){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,D,C);
+};
+Timeline.OriginalEventPainter.prototype._findFreeTrack=function(G,F){var H=G.getTrackNum();
+if(H!=null){return H;
+}for(var I=0;
+I<this._tracks.length;
+I++){var J=this._tracks[I];
+if(J>F){break;
+}}return I;
+};
+Timeline.OriginalEventPainter.prototype._paintEventIcon=function(Q,U,N,T,V,M){var R=Q.getIcon();
+R=R!=null?R:T.icon;
+var S;
+if(M>0){S=T.trackOffset+U*T.trackIncrement+M+T.impreciseIconMargin;
+}else{var P=T.trackOffset+U*T.trackIncrement+T.trackHeight/2;
+S=Math.round(P-T.iconHeight/2);
+}var L=SimileAjax.Graphics.createTranslucentImage(R);
+var O=this._timeline.getDocument().createElement("div");
+O.className=this._getElClassName("timeline-event-icon",Q,"icon");
+O.id=this._encodeEventElID("icon",Q);
+O.style.left=N+"px";
+O.style.top=S+"px";
+O.appendChild(L);
+if(Q._title!=null){O.title=Q._title;
+}this._eventLayer.appendChild(O);
+return{left:N,top:S,width:T.iconWidth,height:T.iconHeight,elmt:O};
+};
+Timeline.OriginalEventPainter.prototype._paintEventLabel=function(S,R,N,U,P,Q,X,W,O){var T=this._timeline.getDocument();
+var V=T.createElement("div");
+V.className=W;
+V.id=this._encodeEventElID("label",S);
+V.style.left=N+"px";
+V.style.width=P+"px";
+V.style.top=U+"px";
+V.innerHTML=R;
+if(S._title!=null){V.title=S._title;
+}var M=S.getTextColor();
+if(M==null){M=S.getColor();
+}if(M!=null){V.style.color=M;
+}if(X.event.highlightLabelBackground&&O>=0){V.style.background=this._getHighlightColor(O,X);
+}this._eventLayer.appendChild(V);
+return{left:N,top:U,width:P,height:Q,elmt:V};
+};
+Timeline.OriginalEventPainter.prototype._paintEventTape=function(U,Z,c,S,Q,a,Y,b,T){var R=S-c;
+var d=b.event.tape.height;
+var X=Y.trackOffset+Z*Y.trackIncrement;
+var V=this._timeline.getDocument().createElement("div");
+V.className=this._getElClassName("timeline-event-tape",U,"tape");
+V.id=this._encodeEventElID("tape"+T,U);
+V.style.left=c+"px";
+V.style.width=R+"px";
+V.style.height=d+"px";
+V.style.top=X+"px";
+if(U._title!=null){V.title=U._title;
+}if(Q!=null){V.style.backgroundColor=Q;
+}var W=U.getTapeImage();
+var P=U.getTapeRepeat();
+P=P!=null?P:"repeat";
+if(W!=null){V.style.backgroundImage="url("+W+")";
+V.style.backgroundRepeat=P;
+}SimileAjax.Graphics.setOpacity(V,a);
+this._eventLayer.appendChild(V);
+return{left:c,top:X,width:R,height:d,elmt:V};
+};
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(B){return this._getElClassName("timeline-event-label",B,"label");
+};
+Timeline.OriginalEventPainter.prototype._getElClassName=function(J,F,H){var G=F.getClassName(),I=[];
+if(G){if(H){I.push(H+"-"+G+" ");
+}I.push(G+" ");
+}I.push(J);
+return(I.join(""));
+};
+Timeline.OriginalEventPainter.prototype._getHighlightColor=function(D,E){var F=E.event.highlightColors;
+return F[Math.min(D,F.length-1)];
+};
+Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(H,L,J,N){var I=null;
+if(H>=0){var K=this._timeline.getDocument();
+var M=this._getHighlightColor(H,J);
+I=K.createElement("div");
+I.className=this._getElClassName("timeline-event-highlight",N,"highlight");
+I.id=this._encodeEventElID("highlight0",N);
+I.style.position="absolute";
+I.style.overflow="hidden";
+I.style.left=(L.left-2)+"px";
+I.style.width=(L.width+4)+"px";
+I.style.top=(L.top-2)+"px";
+I.style.height=(L.height+4)+"px";
+I.style.background=M;
+this._highlightLayer.appendChild(I);
+}return I;
+};
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(H,G,E){var F=SimileAjax.DOM.getPageCoordinates(H);
+this._showBubble(F.left+Math.ceil(H.offsetWidth/2),F.top+Math.ceil(H.offsetHeight/2),E);
+this._fireOnSelect(E.getID());
+G.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(G);
+return false;
+};
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(J,K,L){if("pageX" in K){var G=K.pageX;
+var H=K.pageY;
+}else{var I=SimileAjax.DOM.getPageCoordinates(J);
+var G=K.offsetX+I.left;
+var H=K.offsetY+I.top;
+}this._showBubble(G,H,L);
+this._fireOnSelect(L.getID());
+K.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(K);
+return false;
+};
+Timeline.OriginalEventPainter.prototype.showBubble=function(D){var F=this._eventIdToElmt[D.getID()];
+if(F){var E=SimileAjax.DOM.getPageCoordinates(F);
+this._showBubble(E.left+F.offsetWidth/2,E.top+F.offsetHeight/2,D);
+}};
+Timeline.OriginalEventPainter.prototype._showBubble=function(F,G,J){var H=document.createElement("div");
+var I=this._params.theme.event.bubble;
+J.fillInfoBubble(H,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(H,F,G,I.width,null,I.maxHeight);
+};
+Timeline.OriginalEventPainter.prototype._fireOnSelect=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){this._onSelectListeners[C](D);
+}};
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(F,E,G){for(var H=0;
+H<this._eventPaintListeners.length;
+H++){this._eventPaintListeners[H](this._band,F,E,G);
+}};
+Timeline.OverviewEventPainter=function(B){this._params=B;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+};
+Timeline.OverviewEventPainter.prototype.initialize=function(D,C){this._band=D;
+this._timeline=C;
+this._eventLayer=null;
+this._highlightLayer=null;
+};
+Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
+};
+Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(B){this._onSelectListeners.push(B);
+};
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(D){for(var C=0;
+C<this._onSelectListeners.length;
+C++){if(this._onSelectListeners[C]==D){this._onSelectListeners.splice(C,1);
+break;
+}}};
+Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(B){this._filterMatcher=B;
+};
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(B){this._highlightMatcher=B;
+};
+Timeline.OverviewEventPainter.prototype.paint=function(){var L=this._band.getEventSource();
+if(L==null){return ;
+}this._prepareForPainting();
+var O=this._params.theme.event;
+var Q={trackOffset:O.overviewTrack.offset,trackHeight:O.overviewTrack.height,trackGap:O.overviewTrack.gap,trackIncrement:O.overviewTrack.height+O.overviewTrack.gap};
+var K=this._band.getMinDate();
+var M=this._band.getMaxDate();
+var N=(this._filterMatcher!=null)?this._filterMatcher:function(A){return true;
+};
+var R=(this._highlightMatcher!=null)?this._highlightMatcher:function(A){return -1;
+};
+var J=L.getEventReverseIterator(K,M);
+while(J.hasNext()){var P=J.next();
+if(N(P)){this.paintEvent(P,Q,this._params.theme,R(P));
+}}this._highlightLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,Q.trackIncrement);
+};
+Timeline.OverviewEventPainter.prototype.softPaint=function(){};
+Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var B=this._band;
+this._tracks=[];
+if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
+}this._eventLayer=B.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OverviewEventPainter.prototype.paintEvent=function(H,G,F,E){if(H.isInstant()){this.paintInstantEvent(H,G,F,E);
+}else{this.paintDurationEvent(H,G,F,E);
+}};
+Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(N,O,Q,M){var L=N.getStart();
+var R=Math.round(this._band.dateToPixelOffset(L));
+var J=N.getColor(),K=N.getClassName();
+if(K){J=null;
+}else{J=J!=null?J:Q.event.duration.color;
+}var P=this._paintEventTick(N,R,J,100,O,Q);
+this._createHighlightDiv(M,P,Q);
+};
+Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(Q,R,S,M){var P=Q.getLatestStart();
+var N=Q.getEarliestEnd();
+var O=Math.round(this._band.dateToPixelOffset(P));
+var X=Math.round(this._band.dateToPixelOffset(N));
+var T=0;
+for(;
+T<this._tracks.length;
+T++){if(X<this._tracks[T]){break;
+}}this._tracks[T]=X;
+var U=Q.getColor(),V=Q.getClassName();
+if(V){U=null;
+}else{U=U!=null?U:S.event.duration.color;
+}var W=this._paintEventTape(Q,T,O,X,U,100,R,S,V);
+this._createHighlightDiv(M,W,S);
+};
+Timeline.OverviewEventPainter.prototype._paintEventTape=function(S,P,O,T,Z,X,W,Y,N){var V=W.trackOffset+P*W.trackIncrement;
+var Q=T-O;
+var R=W.trackHeight;
+var U=this._timeline.getDocument().createElement("div");
+U.className="timeline-small-event-tape";
+if(N){U.className+=" small-"+N;
+}U.style.left=O+"px";
+U.style.width=Q+"px";
+U.style.top=V+"px";
+U.style.height=R+"px";
+if(Z){U.style.backgroundColor=Z;
+}if(X<100){SimileAjax.Graphics.setOpacity(U,X);
+}this._eventLayer.appendChild(U);
+return{left:O,top:V,width:Q,height:R,elmt:U};
+};
+Timeline.OverviewEventPainter.prototype._paintEventTick=function(Q,N,L,U,T,V){var P=V.event.overviewTrack.tickHeight;
+var S=T.trackOffset-P;
+var O=1;
+var R=this._timeline.getDocument().createElement("div");
+R.className="timeline-small-event-icon";
+R.style.left=N+"px";
+R.style.top=S+"px";
+var M=Q.getClassName();
+if(M){R.className+=" small-"+M;
+}if(U<100){SimileAjax.Graphics.setOpacity(R,U);
+}this._eventLayer.appendChild(R);
+return{left:N,top:S,width:O,height:P,elmt:R};
+};
+Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(H,M,K){if(H>=0){var L=this._timeline.getDocument();
+var I=K.event;
+var N=I.highlightColors[Math.min(H,I.highlightColors.length-1)];
+var J=L.createElement("div");
+J.style.position="absolute";
+J.style.overflow="hidden";
+J.style.left=(M.left-1)+"px";
+J.style.width=(M.width+2)+"px";
+J.style.top=(M.top-1)+"px";
+J.style.height=(M.height+2)+"px";
+J.style.background=N;
+this._highlightLayer.appendChild(J);
+}};
+Timeline.OverviewEventPainter.prototype.showBubble=function(B){};
+Timeline.DefaultEventSource=function(B){this._events=(B instanceof Object)?B:new SimileAjax.EventIndex();
+this._listeners=[];
+};
+Timeline.DefaultEventSource.prototype.addListener=function(B){this._listeners.push(B);
+};
+Timeline.DefaultEventSource.prototype.removeListener=function(D){for(var C=0;
+C<this._listeners.length;
+C++){if(this._listeners[C]==D){this._listeners.splice(C,1);
+break;
+}}};
+Timeline.DefaultEventSource.prototype.loadXML=function(V,P){var N=this._getBaseURL(P);
+var U=V.documentElement.getAttribute("wiki-url");
+var Q=V.documentElement.getAttribute("wiki-section");
+var X=V.documentElement.getAttribute("date-time-format");
+var W=this._events.getUnit().getParser(X);
+var M=V.documentElement.firstChild;
+var T=false;
+while(M!=null){if(M.nodeType==1){var R="";
+if(M.firstChild!=null&&M.firstChild.nodeType==3){R=M.firstChild.nodeValue;
+}var O=(M.getAttribute("isDuration")===null&&M.getAttribute("durationEvent")===null)||M.getAttribute("isDuration")=="false"||M.getAttribute("durationEvent")=="false";
+var S=new Timeline.DefaultEventSource.Event({id:M.getAttribute("id"),start:W(M.getAttribute("start")),end:W(M.getAttribute("end")),latestStart:W(M.getAttribute("latestStart")),earliestEnd:W(M.getAttribute("earliestEnd")),instant:O,text:M.getAttribute("title"),description:R,image:this._resolveRelativeURL(M.getAttribute("image"),N),link:this._resolveRelativeURL(M.getAttribute("link"),N),icon:this._resolveRelativeURL(M.getAttribute("icon"),N),color:M.getAttribute("color"),textColor:M.getAttribute("textColor"),hoverText:M.getAttribute("hoverText"),classname:M.getAttribute("classname"),tapeImage:M.getAttribute("tapeImage"),tapeRepeat:M.getAttribute("tapeRepeat"),caption:M.getAttribute("caption"),eventID:M.getAttribute("eventID"),trackNum:M.getAttribute("trackNum")});
+S._node=M;
+S.getProperty=function(A){return this._node.getAttribute(A);
+};
+S.setWikiInfo(U,Q);
+this._events.add(S);
+T=true;
+}M=M.nextSibling;
+}if(T){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadJSON=function(W,P){var N=this._getBaseURL(P);
+var T=false;
+if(W&&W.events){var U=("wikiURL" in W)?W.wikiURL:null;
+var R=("wikiSection" in W)?W.wikiSection:null;
+var M=("dateTimeFormat" in W)?W.dateTimeFormat:null;
+var V=this._events.getUnit().getParser(M);
+for(var X=0;
+X<W.events.length;
+X++){var Q=W.events[X];
+var O=Q.isDuration||(("durationEvent" in Q)&&!Q.durationEvent)||(("de" in Q)&&!Q.de);
+var S=new Timeline.DefaultEventSource.Event({id:("id" in Q)?Q.id:undefined,start:V(Q.start||Q.s),end:V(Q.end||Q.e),latestStart:V(Q.latestStart||Q.ls),earliestEnd:V(Q.earliestEnd||Q.ee),instant:O,text:Q.title||Q.t,description:Q.description||Q.d,image:this._resolveRelativeURL(Q.image,N),link:this._resolveRelativeURL(Q.link,N),icon:this._resolveRelativeURL(Q.icon,N),color:Q.color,textColor:Q.textColor,hoverText:Q.hoverText,classname:Q.classname||Q.c,tapeImage:Q.tapeImage,tapeRepeat:Q.tapeRepeat,caption:Q.caption,eventID:Q.eventID||Q.eid,trackNum:Q.trackNum});
+S._obj=Q;
+S.getProperty=function(A){return this._obj[A];
+};
+S.setWikiInfo(U,R);
+this._events.add(S);
+T=true;
+}}if(T){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadSPARQL=function(W,Q){var N=this._getBaseURL(Q);
+var Y="iso8601";
+var X=this._events.getUnit().getParser(Y);
+if(W==null){return ;
+}var Z=W.documentElement.firstChild;
+while(Z!=null&&(Z.nodeType!=1||Z.nodeName!="results")){Z=Z.nextSibling;
+}var U=null;
+var R=null;
+if(Z!=null){U=Z.getAttribute("wiki-url");
+R=Z.getAttribute("wiki-section");
+Z=Z.firstChild;
+}var T=false;
+while(Z!=null){if(Z.nodeType==1){var O={};
+var V=Z.firstChild;
+while(V!=null){if(V.nodeType==1&&V.firstChild!=null&&V.firstChild.nodeType==1&&V.firstChild.firstChild!=null&&V.firstChild.firstChild.nodeType==3){O[V.getAttribute("name")]=V.firstChild.firstChild.nodeValue;
+}V=V.nextSibling;
+}if(O["start"]==null&&O["date"]!=null){O["start"]=O["date"];
+}var P=(O["isDuration"]===null&&O["durationEvent"]===null)||O["isDuration"]=="false"||O["durationEvent"]=="false";
+var S=new Timeline.DefaultEventSource.Event({id:O["id"],start:X(O["start"]),end:X(O["end"]),latestStart:X(O["latestStart"]),earliestEnd:X(O["earliestEnd"]),instant:P,text:O["title"],description:O["description"],image:this._resolveRelativeURL(O["image"],N),link:this._resolveRelativeURL(O["link"],N),icon:this._resolveRelativeURL(O["icon"],N),color:O["color"],textColor:O["textColor"],hoverText:O["hoverText"],caption:O["caption"],classname:O["classname"],tapeImage:O["tapeImage"],tapeRepeat:O["tapeRepeat"],eventID:O["eventID"],trackNum:O["trackNum"]});
+S._bindings=O;
+S.getProperty=function(A){return this._bindings[A];
+};
+S.setWikiInfo(U,R);
+this._events.add(S);
+T=true;
+}Z=Z.nextSibling;
+}if(T){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.add=function(B){this._events.add(B);
+this._fire("onAddOne",[B]);
+};
+Timeline.DefaultEventSource.prototype.addMany=function(D){for(var C=0;
+C<D.length;
+C++){this._events.add(D[C]);
+}this._fire("onAddMany",[]);
+};
+Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
+this._fire("onClear",[]);
+};
+Timeline.DefaultEventSource.prototype.getEvent=function(B){return this._events.getEvent(B);
+};
+Timeline.DefaultEventSource.prototype.getEventIterator=function(C,D){return this._events.getIterator(C,D);
+};
+Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(C,D){return this._events.getReverseIterator(C,D);
+};
+Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
+};
+Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
+};
+Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
+};
+Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
+};
+Timeline.DefaultEventSource.prototype._fire=function(J,F){for(var I=0;
+I<this._listeners.length;
+I++){var H=this._listeners[I];
+if(J in H){try{H[J].apply(H,F);
+}catch(G){SimileAjax.Debug.exception(G);
+}}}};
+Timeline.DefaultEventSource.prototype._getBaseURL=function(D){if(D.indexOf("://")<0){var E=this._getBaseURL(document.location.href);
+if(D.substr(0,1)=="/"){D=E.substr(0,E.indexOf("/",E.indexOf("://")+3))+D;
+}else{D=E+D;
+}}var F=D.lastIndexOf("/");
+if(F<0){return"";
+}else{return D.substr(0,F+1);
+}};
+Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(C,D){if(C==null||C==""){return C;
+}else{if(C.indexOf("://")>0){return C;
+}else{if(C.substr(0,1)=="/"){return D.substr(0,D.indexOf("/",D.indexOf("://")+3))+C;
+}else{return D+C;
+}}}};
+Timeline.DefaultEventSource.Event=function(E){function F(A){return(E[A]!=null&&E[A]!="")?E[A]:null;
+}var G=E.id?E.id.trim():"";
+this._id=G.length>0?G:Timeline.EventUtils.getNewEventID();
+this._instant=E.instant||(E.end==null);
+this._start=E.start;
+this._end=(E.end!=null)?E.end:E.start;
+this._latestStart=(E.latestStart!=null)?E.latestStart:(E.instant?this._end:this._start);
+this._earliestEnd=(E.earliestEnd!=null)?E.earliestEnd:this._end;
+var H=[];
+if(this._start>this._latestStart){this._latestStart=this._start;
+H.push("start is > latestStart");
+}if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
+H.push("start is > earliestEnd");
+}if(this._start>this._end){this._end=this._earliestEnd;
+H.push("start is > end");
+}if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
+H.push("latestStart is > earliestEnd");
+}if(this._latestStart>this._end){this._end=this._earliestEnd;
+H.push("latestStart is > end");
+}if(this._earliestEnd>this._end){this._end=this._earliestEnd;
+H.push("earliestEnd is > end");
+}this._eventID=F("eventID");
+this._text=(E.text!=null)?SimileAjax.HTML.deEntify(E.text):"";
+if(H.length>0){this._text+=" PROBLEM: "+H.join(", ");
+}this._description=SimileAjax.HTML.deEntify(E.description);
+this._image=F("image");
+this._link=F("link");
+this._title=F("hoverText");
+this._title=F("caption");
+this._icon=F("icon");
+this._color=F("color");
+this._textColor=F("textColor");
+this._classname=F("classname");
+this._tapeImage=F("tapeImage");
+this._tapeRepeat=F("tapeRepeat");
+this._trackNum=F("trackNum");
+if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
+}this._wikiURL=null;
+this._wikiSection=null;
+};
+Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
+},isInstant:function(){return this._instant;
+},isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
+},getStart:function(){return this._start;
+},getEnd:function(){return this._end;
+},getLatestStart:function(){return this._latestStart;
+},getEarliestEnd:function(){return this._earliestEnd;
+},getEventID:function(){return this._eventID;
+},getText:function(){return this._text;
+},getDescription:function(){return this._description;
+},getImage:function(){return this._image;
+},getLink:function(){return this._link;
+},getIcon:function(){return this._icon;
+},getColor:function(){return this._color;
+},getTextColor:function(){return this._textColor;
+},getClassName:function(){return this._classname;
+},getTapeImage:function(){return this._tapeImage;
+},getTapeRepeat:function(){return this._tapeRepeat;
+},getTrackNum:function(){return this._trackNum;
+},getProperty:function(B){return null;
+},getWikiURL:function(){return this._wikiURL;
+},getWikiSection:function(){return this._wikiSection;
+},setWikiInfo:function(D,C){this._wikiURL=D;
+this._wikiSection=C;
+},fillDescription:function(B){if(this._description){B.innerHTML=this._description;
+}},fillWikiInfo:function(F){F.style.display="none";
+if(this._wikiURL==null||this._wikiSection==null){return ;
+}var G=this.getProperty("wikiID");
+if(G==null||G.length==0){G=this.getText();
+}if(G==null||G.length==0){return ;
+}F.style.display="inline";
+G=G.replace(/\s/g,"_");
+var H=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+G;
+var E=document.createElement("a");
+E.href=H;
+E.target="new";
+E.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+F.appendChild(document.createTextNode("["));
+F.appendChild(E);
+F.appendChild(document.createTextNode("]"));
+},fillTime:function(C,D){if(this._instant){if(this.isImprecise()){C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._start)));
+C.appendChild(C.ownerDocument.createElement("br"));
+C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._end)));
+}else{C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._start)));
+}}else{if(this.isImprecise()){C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._start)+" ~ "+D.labelPrecise(this._latestStart)));
+C.appendChild(C.ownerDocument.createElement("br"));
+C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._earliestEnd)+" ~ "+D.labelPrecise(this._end)));
+}else{C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._start)));
+C.appendChild(C.ownerDocument.createElement("br"));
+C.appendChild(C.ownerDocument.createTextNode(D.labelPrecise(this._end)));
+}}},fillInfoBubble:function(R,O,V){var U=R.ownerDocument;
+var W=this.getText();
+var Y=this.getLink();
+var P=this.getImage();
+if(P!=null){var b=U.createElement("img");
+b.src=P;
+O.event.bubble.imageStyler(b);
+R.appendChild(b);
+}var T=U.createElement("div");
+var Q=U.createTextNode(W);
+if(Y!=null){var X=U.createElement("a");
+X.href=Y;
+X.appendChild(Q);
+T.appendChild(X);
+}else{T.appendChild(Q);
+}O.event.bubble.titleStyler(T);
+R.appendChild(T);
+var S=U.createElement("div");
+this.fillDescription(S);
+O.event.bubble.bodyStyler(S);
+R.appendChild(S);
+var Z=U.createElement("div");
+this.fillTime(Z,V);
+O.event.bubble.timeStyler(Z);
+R.appendChild(Z);
+var a=U.createElement("div");
+this.fillWikiInfo(a);
+O.event.bubble.wikiStyler(a);
+R.appendChild(a);
+}};
+Timeline.ClassicTheme=new Object();
+Timeline.ClassicTheme.implementations=[];
+Timeline.ClassicTheme.create=function(C){if(C==null){C=Timeline.getDefaultLocale();
+}var D=Timeline.ClassicTheme.implementations[C];
+if(D==null){D=Timeline.ClassicTheme._Impl;
+}return new D();
+};
+Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
+this.autoWidth=false;
+this.autoWidthAnimationTime=500;
+this.timeline_start=null;
+this.timeline_stop=null;
+this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
+this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"images/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(B){B.className="timeline-event-bubble-title";
+},bodyStyler:function(B){B.className="timeline-event-bubble-body";
+},imageStyler:function(B){B.className="timeline-event-bubble-image";
+},wikiStyler:function(B){B.className="timeline-event-bubble-wiki";
+},timeStyler:function(B){B.className="timeline-event-bubble-time";
+}}};
+this.mouseWheel="scroll";
+};
+Timeline.version="pre 2.4.0";
+Timeline.ajax_lib_version=SimileAjax.version;
+Timeline.display_version=Timeline.version+" (with Ajax lib "+Timeline.ajax_lib_version+")";
+Timeline.strings={};
+Timeline.HORIZONTAL=0;
+Timeline.VERTICAL=1;
+Timeline._defaultTheme=null;
+Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
+};
+Timeline.create=function(J,K,L,H){if(Timeline.timelines==null){Timeline.timelines=[];
+}var G=Timeline.timelines.length;
+Timeline.timelines[G]=null;
+var I=new Timeline._Impl(J,K,L,H,G);
+Timeline.timelines[G]=I;
+return I;
+};
+Timeline.createBandInfo=function(K){var T=("theme" in K)?K.theme:Timeline.getDefaultTheme();
+var P=("decorators" in K)?K.decorators:[];
+var M=("eventSource" in K)?K.eventSource:null;
+var S=new Timeline.LinearEther({centersOn:("date" in K)?K.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[K.intervalUnit],pixelsPerInterval:K.intervalPixels,theme:T});
+var R=new Timeline.GregorianEtherPainter({unit:K.intervalUnit,multiple:("multiple" in K)?K.multiple:1,theme:T,align:("align" in K)?K.align:undefined});
+var O={showText:("showEventText" in K)?K.showEventText:true,theme:T};
+if("eventPainterParams" in K){for(var N in K.eventPainterParams){O[N]=K.eventPainterParams[N];
+}}if("trackHeight" in K){O.trackHeight=K.trackHeight;
+}if("trackGap" in K){O.trackGap=K.trackGap;
+}var Q=("overview" in K&&K.overview)?"overview":("layout" in K?K.layout:"original");
+var L;
+if("eventPainter" in K){L=new K.eventPainter(O);
+}else{switch(Q){case"overview":L=new Timeline.OverviewEventPainter(O);
+break;
+case"detailed":L=new Timeline.DetailedEventPainter(O);
+break;
+default:L=new Timeline.OriginalEventPainter(O);
+}}return{width:K.width,eventSource:M,timeZone:("timeZone" in K)?K.timeZone:0,ether:S,etherPainter:R,eventPainter:L,theme:T,decorators:P,zoomIndex:("zoomIndex" in K)?K.zoomIndex:0,zoomSteps:("zoomSteps" in K)?K.zoomSteps:null};
+};
+Timeline.createHotZoneBandInfo=function(J){var R=("theme" in J)?J.theme:Timeline.getDefaultTheme();
+var L=("eventSource" in J)?J.eventSource:null;
+var Q=new Timeline.HotZoneEther({centersOn:("date" in J)?J.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[J.intervalUnit],pixelsPerInterval:J.intervalPixels,zones:J.zones,theme:R});
+var P=new Timeline.HotZoneGregorianEtherPainter({unit:J.intervalUnit,zones:J.zones,theme:R,align:("align" in J)?J.align:undefined});
+var N={showText:("showEventText" in J)?J.showEventText:true,theme:R};
+if("eventPainterParams" in J){for(var M in J.eventPainterParams){N[M]=J.eventPainterParams[M];
+}}if("trackHeight" in J){N.trackHeight=J.trackHeight;
+}if("trackGap" in J){N.trackGap=J.trackGap;
+}var O=("overview" in J&&J.overview)?"overview":("layout" in J?J.layout:"original");
+var K;
+if("eventPainter" in J){K=new J.eventPainter(N);
+}else{switch(O){case"overview":K=new Timeline.OverviewEventPainter(N);
+break;
+case"detailed":K=new Timeline.DetailedEventPainter(N);
+break;
+default:K=new Timeline.OriginalEventPainter(N);
+}}return{width:J.width,eventSource:L,timeZone:("timeZone" in J)?J.timeZone:0,ether:Q,etherPainter:P,eventPainter:K,theme:R,zoomIndex:("zoomIndex" in J)?J.zoomIndex:0,zoomSteps:("zoomSteps" in J)?J.zoomSteps:null};
+};
+Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+}return Timeline._defaultTheme;
+};
+Timeline.setDefaultTheme=function(B){Timeline._defaultTheme=B;
+};
+Timeline.loadXML=function(E,G){var F=function(A,C,B){alert("Failed to load data xml from "+E+"\n"+A);
+};
+var H=function(A){var B=A.responseXML;
+if(!B.documentElement&&A.responseStream){B.load(A.responseStream);
+}G(B,E);
+};
+SimileAjax.XmlHttp.get(E,F,H);
+};
+Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.getTimelineFromID=function(B){return Timeline.timelines[B];
+};
+Timeline.writeVersion=function(B){document.getElementById(B).innerHTML=this.display_version;
+};
+Timeline._Impl=function(H,I,J,G,F){SimileAjax.WindowManager.initialize();
+this._containerDiv=H;
+this._bandInfos=I;
+this._orientation=J==null?Timeline.HORIZONTAL:J;
+this._unit=(G!=null)?G:SimileAjax.NativeDateUnit;
+this._starting=true;
+this._autoResizing=false;
+this.autoWidth=I&&I[0]&&I[0].theme&&I[0].theme.autoWidth;
+this.autoWidthAnimationTime=I&&I[0]&&I[0].theme&&I[0].theme.autoWidthAnimationTime;
+this.timelineID=F;
+this.timeline_start=I&&I[0]&&I[0].theme&&I[0].theme.timeline_start;
+this.timeline_stop=I&&I[0]&&I[0].theme&&I[0].theme.timeline_stop;
+this.timeline_at_start=false;
+this.timeline_at_stop=false;
+this._initialize();
+};
+Timeline._Impl.prototype.dispose=function(){for(var B=0;
+B<this._bands.length;
+B++){this._bands[B].dispose();
+}this._bands=null;
+this._bandInfos=null;
+this._containerDiv.innerHTML="";
+Timeline.timelines[this.timelineID]=null;
+};
+Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
+};
+Timeline._Impl.prototype.getBand=function(B){return this._bands[B];
+};
+Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
+this._starting=false;
+};
+Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
+this._distributeWidths();
+};
+Timeline._Impl.prototype.paint=function(){for(var B=0;
+B<this._bands.length;
+B++){this._bands[B].paint();
+}};
+Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
+};
+Timeline._Impl.prototype.addDiv=function(B){this._containerDiv.appendChild(B);
+};
+Timeline._Impl.prototype.removeDiv=function(B){this._containerDiv.removeChild(B);
+};
+Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
+};
+Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
+};
+Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getUnit=function(){return this._unit;
+};
+Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
+};
+Timeline._Impl.prototype.loadXML=function(J,H){var F=this;
+var G=function(A,C,B){alert("Failed to load data xml from "+J+"\n"+A);
+F.hideLoadingMessage();
+};
+var I=function(A){try{var B=A.responseXML;
+if(!B.documentElement&&A.responseStream){B.load(A.responseStream);
+}H(B,J);
+}finally{F.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(J,G,I);
+},0);
+};
+Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype._autoWidthScrollListener=function(B){B.getTimeline()._autoWidthCheck(false);
+};
+Timeline._Impl.prototype._autoWidthCheck=function(K){var I=this;
+var L=I._starting;
+var J=0;
+function G(){var A=I.getWidthStyle();
+if(L){I._containerDiv.style[A]=J+"px";
+}else{I._autoResizing=true;
+var B={};
+B[A]=J+"px";
+SimileAjax.jQuery(I._containerDiv).animate(B,I.autoWidthAnimationTime,"linear",function(){I._autoResizing=false;
+});
+}}function H(){var A=0;
+var C=I.getPixelWidth();
+if(I._autoResizing){return ;
+}for(var B=0;
+B<I._bands.length;
+B++){I._bands[B].checkAutoWidth();
+A+=I._bandInfos[B].width;
+}if(A>C||K){J=A;
+G();
+I._distributeWidths();
+}}if(!I.autoWidth){return ;
+}H();
+};
+Timeline._Impl.prototype._initialize=function(){var J=this._containerDiv;
+var M=J.ownerDocument;
+J.className=J.className.split(" ").concat("timeline-container").join(" ");
+var P=(this.isHorizontal())?"horizontal":"vertical";
+J.className+=" timeline-"+P;
+while(J.firstChild){J.removeChild(J.firstChild);
+}var I=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"images/copyright-vertical.png":"images/copyright.png"));
+I.className="timeline-copyright";
+I.title="SIMILE Timeline - http://www.simile-widgets.org/";
+SimileAjax.DOM.registerEvent(I,"click",function(){window.location="http://www.simile-widgets.org/";
+});
+J.appendChild(I);
+this._bands=[];
+for(var O=0;
+O<this._bandInfos.length;
+O++){var K=new Timeline._Band(this,this._bandInfos[O],O);
+this._bands.push(K);
+}this._distributeWidths();
+for(var O=0;
+O<this._bandInfos.length;
+O++){var L=this._bandInfos[O];
+if("syncWith" in L){this._bands[O].setSyncWithBand(this._bands[L.syncWith],("highlight" in L)?L.highlight:false);
+}}if(this.autoWidth){for(var O=0;
+O<this._bands.length;
+O++){this._bands[O].addOnScrollListener(this._autoWidthScrollListener);
+}}var N=SimileAjax.Graphics.createMessageBubble(M);
+N.containerDiv.className="timeline-message-container";
+J.appendChild(N.containerDiv);
+N.contentDiv.className="timeline-message";
+N.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"images/progress-running.gif' /> Loading...";
+this.showLoadingMessage=function(){N.containerDiv.style.display="block";
+};
+this.hideLoadingMessage=function(){N.containerDiv.style.display="none";
+};
+};
+Timeline._Impl.prototype._distributeWidths=function(){var M=this.getPixelLength();
+var N=this.getPixelWidth();
+var L=0;
+for(var T=0;
+T<this._bands.length;
+T++){var P=this._bands[T];
+var O=this._bandInfos[T];
+var S=O.width;
+var K;
+if(typeof S=="string"){var Q=S.indexOf("%");
+if(Q>0){var R=parseInt(S.substr(0,Q));
+K=Math.round(R*N/100);
+}else{K=parseInt(S);
+}}else{K=S;
+}P.setBandShiftAndWidth(L,K);
+P.setViewLength(M);
+L+=K;
+}};
+Timeline._Impl.prototype.shiftOK=function(N,P){var O=P>0,I=P<0;
+if((O&&this.timeline_start==null)||(I&&this.timeline_stop==null)||(P==0)){return(true);
+}var K=false;
+for(var L=0;
+L<this._bands.length&&!K;
+L++){K=this._bands[L].busy();
+}if(K){return(true);
+}if((O&&this.timeline_at_start)||(I&&this.timeline_at_stop)){return(false);
+}var M=false;
+for(var L=0;
+L<this._bands.length&&!M;
+L++){var J=this._bands[L];
+if(O){M=(L==N?J.getMinVisibleDateAfterDelta(P):J.getMinVisibleDate())>=this.timeline_start;
+}else{M=(L==N?J.getMaxVisibleDateAfterDelta(P):J.getMaxVisibleDate())<=this.timeline_stop;
+}}if(O){this.timeline_at_start=!M;
+this.timeline_at_stop=false;
+}else{this.timeline_at_stop=!M;
+this.timeline_at_start=false;
+}return(M);
+};
+Timeline._Impl.prototype.zoom=function(I,N,J,L){var M=new RegExp("^timeline-band-([0-9]+)$");
+var K=null;
+var H=M.exec(L.id);
+if(H){K=parseInt(H[1]);
+}if(K!=null){this._bands[K].zoom(I,N,J,L);
+}this.paint();
+};
+
+
+/* labellers.js */
+Timeline.GregorianDateLabeller.monthNames["en"]=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+Timeline.GregorianDateLabeller.dayNames["en"]=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+
+
+/* timeline.js */
+Timeline.strings["en"]={wikiLinkLabel:"Discuss"};
+
+
+/* compile-epilog.js */
+(function(){var f=null;
+if("SimileWidgets_onLoad" in window){if(typeof SimileWidgets_onLoad=="string"){f=eval(SimileWidgets_onLoad);
+SimileWidgets_onLoad=null;
+}else{if(typeof SimileWidgets_onLoad=="function"){f=SimileWidgets_onLoad;
+SimileWidgets_onLoad=null;
+}}}if(f!=null){f();
+}})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-epilog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-epilog.js
new file mode 100644
index 00000000..d1a70927
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-epilog.js
@@ -0,0 +1,16 @@
+(function() {
+ var f = null;
+ if ("SimileWidgets_onLoad" in window) {
+ if (typeof SimileWidgets_onLoad == "string") {
+ f = eval(SimileWidgets_onLoad);
+ SimileWidgets_onLoad = null;
+ } else if (typeof SimileWidgets_onLoad == "function") {
+ f = SimileWidgets_onLoad;
+ SimileWidgets_onLoad = null;
+ }
+ }
+
+ if (f != null) {
+ f();
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-prolog.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-prolog.js
new file mode 100644
index 00000000..b1f7f0df
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/compile-prolog.js
@@ -0,0 +1 @@
+window.Timeline_isCompiled = true; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/geochrono-api.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/geochrono-api.js
new file mode 100644
index 00000000..b16a2c3f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/geochrono-api.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Geochrono Extension
+ *
+ * This file will load all the Javascript files
+ * necessary to make the extension work.
+ *
+ *==================================================
+ */
+
+(function() {
+ var javascriptFiles = [
+ "geochrono.js",
+ "units.js",
+ "ether-painters.js",
+ "labellers.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var localizedJavascriptFiles = [
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en" // English
+ ];
+
+ try {
+ var includeJavascriptFile = function(filename) {
+ document.write("<script src='" + Timeline.urlPrefix + "ext/geochrono/scripts/" + filename + "' type='text/javascript'></script>");
+ };
+ var includeCssFile = function(filename) {
+ document.write("<link rel='stylesheet' href='" + Timeline.urlPrefix + "ext/geochrono/styles/" + filename + "' type='text/css'/>");
+ }
+
+ /*
+ * Include non-localized files
+ */
+ for (var i = 0; i < javascriptFiles.length; i++) {
+ includeJavascriptFile(javascriptFiles[i]);
+ }
+ for (var i = 0; i < cssFiles.length; i++) {
+ includeCssFile(cssFiles[i]);
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ tryLocale(Timeline.serverLocale);
+ tryLocale(Timeline.clientLocale);
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ for (var i = 0; i < localizedJavascriptFiles.length; i++) {
+ includeJavascriptFile("l10n/" + locale + "/" + localizedJavascriptFiles[i]);
+ }
+ for (var i = 0; i < localizedCssFiles.length; i++) {
+ includeCssFile("l10n/" + locale + "/" + localizedCssFiles[i]);
+ }
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/ether-painters.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/ether-painters.js
new file mode 100644
index 00000000..ee66ff50
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/ether-painters.js
@@ -0,0 +1,204 @@
+/*==================================================
+ * Geochrono Ether Painter
+ *==================================================
+ */
+
+Timeline.GeochronoEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._intervalUnit = params.intervalUnit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+ this._theme = params.theme;
+};
+
+Timeline.GeochronoEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && typeof this._params.align == "string") ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.GeochronoEtherMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GeochronoEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.GeochronoEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = Math.ceil(Timeline.GeochronoUnit.toNumber(this._band.getMinDate()));
+ var maxDate = Math.floor(Timeline.GeochronoUnit.toNumber(this._band.getMaxDate()));
+
+ var increment;
+ var hasMore;
+ (function(intervalUnit, multiple) {
+ var dates;
+
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons; break;
+ default:
+ hasMore = function() {
+ return minDate > 0 && minDate > maxDate;
+ }
+ increment = function() {
+ minDate -= multiple;
+ };
+ return;
+ }
+
+ var startIndex = dates.length - 1;
+ while (startIndex > 0) {
+ if (minDate <= dates[startIndex].start) {
+ break;
+ }
+ startIndex--;
+ }
+
+ minDate = dates[startIndex].start;
+ hasMore = function() {
+ return startIndex < (dates.length - 1) && minDate > maxDate;
+ };
+ increment = function() {
+ startIndex++;
+ minDate = dates[startIndex].start;
+ };
+ })(this._intervalUnit, this._multiple);
+
+ var labeller = this._band.getLabeller();
+ while (true) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ Timeline.GeochronoUnit.fromNumber(minDate),
+ labeller,
+ this._intervalUnit,
+ this._markerLayer,
+ this._lineLayer
+ );
+ if (hasMore()) {
+ increment();
+ } else {
+ break;
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GeochronoEtherPainter.prototype.softPaint = function() {
+};
+
+
+/*==================================================
+ * Geochrono Ether Marker Layout
+ *==================================================
+ */
+
+Timeline.GeochronoEtherMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ //(label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/geochrono.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/geochrono.js
new file mode 100644
index 00000000..dc9716a4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/geochrono.js
@@ -0,0 +1,518 @@
+/*==================================================
+ * Geochrono
+ *==================================================
+ */
+Timeline.Geochrono = new Object();
+Timeline.Geochrono.eons = [
+ { name: "Proterozoic",
+ start: 2500.000
+ },
+ { name: "Phanerozoic",
+ start: 542.000
+ }
+];
+Timeline.Geochrono.eras = [
+ { name: "Paleoarchean",
+ start: 3600.000
+ },
+ { name: "Mesoarchean",
+ start: 3200.000
+ },
+ { name: "Neoarchean",
+ start: 2800.000
+ },
+ { name: "Paleoproterozoic",
+ start: 2500.000
+ },
+ { name: "Mesoproterozoic",
+ start: 1600.000
+ },
+ { name: "Neoproterozoic",
+ start: 1000.000
+ },
+ { name: "Paleozoic",
+ start: 542.000
+ },
+ { name: "Mesozoic",
+ start: 251.000
+ },
+ { name: "Cenozoic",
+ start: 65.500
+ }
+];
+Timeline.Geochrono.periods = [
+ { name: "Siderian",
+ start: 2500.000
+ },
+ { name: "Rhyacian",
+ start: 2300.000
+ },
+ { name: "Orosirian",
+ start: 2050.000
+ },
+ { name: "Statherian",
+ start: 1800.000
+ },
+ { name: "Calymmian",
+ start: 1600.000
+ },
+ { name: "Ectasian",
+ start: 1400.000
+ },
+ { name: "Stenian",
+ start: 1200.000
+ },
+ { name: "Tonian",
+ start: 1000.000
+ },
+ { name: "Cryogenian",
+ start: 850.000
+ },
+ { name: "Ediacaran",
+ start: 600.000
+ },
+ { name: "Cambrian",
+ start: 542.000
+ },
+ { name: "Ordovician",
+ start: 488.300
+ },
+ { name: "Silurian",
+ start: 443.700
+ },
+ { name: "Devonian",
+ start: 416.000
+ },
+ { name: "Carboniferous",
+ start: 359.200
+ },
+ { name: "Permian",
+ start: 299.000
+ },
+ { name: "Triassic",
+ start: 251.000
+ },
+ { name: "Jurassic",
+ start: 199.600
+ },
+ { name: "Cretaceous",
+ start: 145.500
+ },
+ { name: "Paleogene",
+ start: 65.500
+ },
+ { name: "Neogene",
+ start: 23.030
+ }
+];
+Timeline.Geochrono.epoches = [
+ { name: "Lower Cambrian",
+ start: 542.000
+ },
+ { name: "Middle Cambrian",
+ start: 513.000
+ },
+ { name: "Furongian",
+ start: 501.000
+ },
+ { name: "Lower Ordovician",
+ start: 488.300
+ },
+ { name: "Middle Ordovician",
+ start: 471.800
+ },
+ { name: "Upper Ordovician",
+ start: 460.900
+ },
+ { name: "Llandovery",
+ start: 443.700
+ },
+ { name: "Wenlock",
+ start: 428.200
+ },
+ { name: "Ludlow",
+ start: 422.900
+ },
+ { name: "Pridoli",
+ start: 418.700
+ },
+ { name: "Lower Devonian",
+ start: 416.000
+ },
+ { name: "Middle Devonian",
+ start: 397.500
+ },
+ { name: "Upper Devonian",
+ start: 385.300
+ },
+ { name: "Mississippian",
+ start: 359.200
+ },
+ { name: "Pennsylvanian",
+ start: 318.100
+ },
+ { name: "Cisuralian",
+ start: 299.000
+ },
+ { name: "Guadalupian",
+ start: 270.600
+ },
+ { name: "Lopingian",
+ start: 260.400
+ },
+ { name: "Lower Triassic",
+ start: 251.000
+ },
+ { name: "Middle Triassic",
+ start: 245.000
+ },
+ { name: "Upper Triassic",
+ start: 228.000
+ },
+ { name: "Lower Jurassic",
+ start: 199.600
+ },
+ { name: "Middle Jurassic",
+ start: 175.600
+ },
+ { name: "Upper Jurassic",
+ start: 161.200
+ },
+ { name: "Lower Cretaceous",
+ start: 145.500
+ },
+ { name: "Upper Cretaceous",
+ start: 99.600
+ },
+ { name: "Paleocene",
+ start: 65.500
+ },
+ { name: "Eocene",
+ start: 55.800
+ },
+ { name: "Oligocene",
+ start: 33.900
+ },
+ { name: "Miocene",
+ start: 23.030
+ },
+ { name: "Pliocene",
+ start: 5.332
+ },
+ { name: "Pleistocene",
+ start: 1.806
+ },
+ { name: "Holocene",
+ start: 0.012
+ }
+];
+Timeline.Geochrono.ages = [
+ { name: "-",
+ start: 542.000
+ },
+ { name: "-",
+ start: 513.000
+ },
+ { name: "Paibian",
+ start: 501.000
+ },
+ { name: "Tremadocian",
+ start: 488.300
+ },
+ { name: "-",
+ start: 478.600
+ },
+ { name: "-",
+ start: 471.800
+ },
+ { name: "Darriwilian",
+ start: 468.100
+ },
+ { name: "-",
+ start: 460.900
+ },
+ { name: "-",
+ start: 455.800
+ },
+ { name: "Hirnantian",
+ start: 445.600
+ },
+ { name: "Rhuddanian",
+ start: 443.700
+ },
+ { name: "Aeronian",
+ start: 439.000
+ },
+ { name: "Telychian",
+ start: 436.100
+ },
+ { name: "Sheinwoodian",
+ start: 428.200
+ },
+ { name: "Homerian",
+ start: 426.200
+ },
+ { name: "Gorstian",
+ start: 422.900
+ },
+ { name: "Ludfordian",
+ start: 421.300
+ },
+ { name: "-",
+ start: 418.700
+ },
+ { name: "Lochkovian",
+ start: 416.000
+ },
+ { name: "Pragian",
+ start: 411.200
+ },
+ { name: "Emsian",
+ start: 407.000
+ },
+ { name: "Eifelian",
+ start: 397.500
+ },
+ { name: "Givetian",
+ start: 391.800
+ },
+ { name: "Frasnian",
+ start: 385.300
+ },
+ { name: "Famennian",
+ start: 374.500
+ },
+ { name: "Tournaisian",
+ start: 359.200
+ },
+ { name: "Visean",
+ start: 345.300
+ },
+ { name: "Serpukhovian",
+ start: 326.400
+ },
+ { name: "Bashkirian",
+ start: 318.100
+ },
+ { name: "Moscovian",
+ start: 311.700
+ },
+ { name: "Kazimovian",
+ start: 306.500
+ },
+ { name: "Gzhelian",
+ start: 303.900
+ },
+ { name: "Asselian",
+ start: 299.000
+ },
+ { name: "Sakmarian",
+ start: 294.600
+ },
+ { name: "Artinskian",
+ start: 284.400
+ },
+ { name: "Kungurian",
+ start: 275.600
+ },
+ { name: "Roadian",
+ start: 270.600
+ },
+ { name: "Wordian",
+ start: 268.000
+ },
+ { name: "Capitanian",
+ start: 265.800
+ },
+ { name: "Wuchiapingian",
+ start: 260.400
+ },
+ { name: "Changhsingian",
+ start: 253.800
+ },
+ { name: "Induan",
+ start: 251.000
+ },
+ { name: "Olenekian",
+ start: 249.700
+ },
+ { name: "Anisian",
+ start: 245.000
+ },
+ { name: "Ladinian",
+ start: 237.000
+ },
+ { name: "Carnian",
+ start: 228.000
+ },
+ { name: "Norian",
+ start: 216.500
+ },
+ { name: "Rhaetian",
+ start: 203.600
+ },
+ { name: "Hettangian",
+ start: 199.600
+ },
+ { name: "Sinemurian",
+ start: 196.500
+ },
+ { name: "Pliensbachian",
+ start: 189.600
+ },
+ { name: "Toarcian",
+ start: 183.000
+ },
+ { name: "Aalenian",
+ start: 175.600
+ },
+ { name: "Bajocian",
+ start: 171.600
+ },
+ { name: "Bathonian",
+ start: 167.700
+ },
+ { name: "Callovian",
+ start: 164.700
+ },
+ { name: "Oxfordian",
+ start: 161.200
+ },
+ { name: "Kimmeridgian",
+ start: 155.000
+ },
+ { name: "Tithonian",
+ start: 150.800
+ },
+ { name: "Berriasian",
+ start: 145.500
+ },
+ { name: "Valanginian",
+ start: 140.200
+ },
+ { name: "Hauterivian",
+ start: 136.400
+ },
+ { name: "Barremian",
+ start: 130.000
+ },
+ { name: "Aptian",
+ start: 125.000
+ },
+ { name: "Albian",
+ start: 112.000
+ },
+ { name: "Cenomanian",
+ start: 99.600
+ },
+ { name: "Turonian",
+ start: 93.500
+ },
+ { name: "Coniacian",
+ start: 89.300
+ },
+ { name: "Santonian",
+ start: 85.800
+ },
+ { name: "Campanian",
+ start: 83.500
+ },
+ { name: "Maastrichtian",
+ start: 70.600
+ },
+ { name: "Danian",
+ start: 65.500
+ },
+ { name: "Selandian",
+ start: 61.700
+ },
+ { name: "Thanetian",
+ start: 58.700
+ },
+ { name: "Ypresian",
+ start: 55.800
+ },
+ { name: "Lutetian",
+ start: 48.600
+ },
+ { name: "Bartonian",
+ start: 40.400
+ },
+ { name: "Priabonian",
+ start: 37.200
+ },
+ { name: "Rupelian",
+ start: 33.900
+ },
+ { name: "Chattian",
+ start: 28.400
+ },
+ { name: "Aquitanian",
+ start: 23.030
+ },
+ { name: "Burdigalian",
+ start: 20.430
+ },
+ { name: "Langhian",
+ start: 15.970
+ },
+ { name: "Serravallian",
+ start: 13.650
+ },
+ { name: "Tortonian",
+ start: 11.608
+ },
+ { name: "Messinian",
+ start: 7.246
+ },
+ { name: "Zanclean",
+ start: 5.332
+ },
+ { name: "Piacenzian",
+ start: 3.600
+ },
+ { name: "Gelasian",
+ start: 2.588
+ }
+];
+
+Timeline.Geochrono.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : Timeline.GeochronoUnit.makeDefaultValue(),
+ interval: 1,
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.GeochronoEtherPainter({
+ intervalUnit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ align: params.align,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = ("overview" in params && params.overview) ?
+ new Timeline.OverviewEventPainter(eventPainterParams) :
+ new Timeline.DetailedEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/l10n/en/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/l10n/en/labellers.js
new file mode 100644
index 00000000..7e667010
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/l10n/en/labellers.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Localization of Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller.eonNames["en"] = Timeline.Geochrono.eons;
+Timeline.GeochronoLabeller.eraNames["en"] = Timeline.Geochrono.eras;
+Timeline.GeochronoLabeller.periodNames["en"] = Timeline.Geochrono.periods;
+Timeline.GeochronoLabeller.epochNames["en"] = Timeline.Geochrono.epoches;
+Timeline.GeochronoLabeller.ageNames["en"] = Timeline.Geochrono.ages;
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/labellers.js
new file mode 100644
index 00000000..60f8012b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/labellers.js
@@ -0,0 +1,52 @@
+/*==================================================
+ * Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller = function(locale) {
+ this._locale = locale;
+};
+
+Timeline.GeochronoLabeller.eonNames = [];
+Timeline.GeochronoLabeller.eraNames = [];
+Timeline.GeochronoLabeller.periodNames = [];
+Timeline.GeochronoLabeller.epochNames = [];
+Timeline.GeochronoLabeller.ageNames = [];
+
+Timeline.GeochronoLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var n = Timeline.GeochronoUnit.toNumber(date);
+ var dates, names;
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages;
+ names = Timeline.GeochronoLabeller.ageNames; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches;
+ names = Timeline.GeochronoLabeller.epochNames; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods;
+ names = Timeline.GeochronoLabeller.periodNames; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras;
+ names = Timeline.GeochronoLabeller.eraNames; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons;
+ names = Timeline.GeochronoLabeller.eonNames; break;
+ default:
+ return { text: n, emphasized: false };
+ }
+
+ for (var i = dates.length - 1; i >= 0; i--) {
+ if (n <= dates[i].start) {
+ return {
+ text: names[this._locale][i].name,
+ emphasized: n == dates[i].start
+ }
+ }
+ }
+ return { text: n, emphasized: false };
+};
+
+Timeline.GeochronoLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.GeochronoUnit.toNumber(date) + "ma";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/units.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/units.js
new file mode 100644
index 00000000..d36952bc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/geochrono/scripts/units.js
@@ -0,0 +1,86 @@
+/*==================================================
+ * Geochrono Unit
+ *==================================================
+ */
+
+Timeline.GeochronoUnit = new Object();
+
+Timeline.GeochronoUnit.MA = 0;
+Timeline.GeochronoUnit.AGE = 1;
+Timeline.GeochronoUnit.EPOCH = 2;
+Timeline.GeochronoUnit.PERIOD = 3;
+Timeline.GeochronoUnit.ERA = 4;
+Timeline.GeochronoUnit.EON = 5;
+
+Timeline.GeochronoUnit.getParser = function(format) {
+ return Timeline.GeochronoUnit.parseFromObject;
+};
+
+Timeline.GeochronoUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.GeochronoLabeller(locale);
+};
+
+Timeline.GeochronoUnit.wrapMA = function (n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.makeDefaultValue = function () {
+ return Timeline.GeochronoUnit.wrapMA(0);
+};
+
+Timeline.GeochronoUnit.cloneValue = function (v) {
+ return new Timeline.GeochronoUnit._MA(v._n);
+};
+
+Timeline.GeochronoUnit.parseFromObject = function(o) {
+ if (o instanceof Timeline.GeochronoUnit._MA) {
+ return o;
+ } else if (typeof o == "number") {
+ return Timeline.GeochronoUnit.wrapMA(o);
+ } else if (typeof o == "string" && o.length > 0) {
+ return Timeline.GeochronoUnit.wrapMA(Number(o));
+ } else {
+ return null;
+ }
+};
+
+Timeline.GeochronoUnit.toNumber = function(v) {
+ return v._n;
+};
+
+Timeline.GeochronoUnit.fromNumber = function(n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1._n;
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2._n;
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n2 - n1;
+};
+
+Timeline.GeochronoUnit.earlier = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.later = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.change = function(v, n) {
+ return new Timeline.GeochronoUnit._MA(v._n - n);
+};
+
+Timeline.GeochronoUnit._MA = function(n) {
+ this._n = n;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/planning-api.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/planning-api.js
new file mode 100644
index 00000000..9d926811
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/planning-api.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Planning Extension
+ *
+ * This file will load all the Javascript files
+ * necessary to make the extension work.
+ *
+ *==================================================
+ */
+
+(function() {
+ var javascriptFiles = [
+ "planning.js",
+ "units.js",
+ "ether-painters.js",
+ "labellers.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var localizedJavascriptFiles = [
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en" // English
+ ];
+
+ try {
+ var includeJavascriptFile = function(filename) {
+ document.write("<script src='" + Timeline.urlPrefix + "ext/planning/scripts/" + filename + "' type='text/javascript'></script>");
+ };
+ var includeCssFile = function(filename) {
+ document.write("<link rel='stylesheet' href='" + Timeline.urlPrefix + "ext/planning/styles/" + filename + "' type='text/css'/>");
+ }
+
+ /*
+ * Include non-localized files
+ */
+ for (var i = 0; i < javascriptFiles.length; i++) {
+ includeJavascriptFile(javascriptFiles[i]);
+ }
+ for (var i = 0; i < cssFiles.length; i++) {
+ includeCssFile(cssFiles[i]);
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ tryLocale(Timeline.serverLocale);
+ tryLocale(Timeline.clientLocale);
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ for (var i = 0; i < localizedJavascriptFiles.length; i++) {
+ includeJavascriptFile("l10n/" + locale + "/" + localizedJavascriptFiles[i]);
+ }
+ for (var i = 0; i < localizedCssFiles.length; i++) {
+ includeCssFile("l10n/" + locale + "/" + localizedCssFiles[i]);
+ }
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/ether-painters.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/ether-painters.js
new file mode 100644
index 00000000..75c2a623
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/ether-painters.js
@@ -0,0 +1,176 @@
+/*==================================================
+ * Planning Ether Painter
+ *==================================================
+ */
+
+Timeline.PlanningEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._intervalUnit = params.intervalUnit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+ this._theme = params.theme;
+};
+
+Timeline.PlanningEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && typeof this._params.align == "string") ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.PlanningEtherMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.PlanningEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.PlanningEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = Math.max(0, Math.ceil(Timeline.PlanningUnit.toNumber(this._band.getMinDate())));
+ var maxDate = Math.floor(Timeline.PlanningUnit.toNumber(this._band.getMaxDate()));
+
+ var hasMore = function() {
+ return minDate < maxDate;
+ };
+ var change = 1;
+ var multiple = this._multiple;
+ switch (this._intervalUnit) {
+ case Timeline.PlanningUnit.DAY: change = 1; break;
+ case Timeline.PlanningUnit.WEEK: change = 7; break;
+ case Timeline.PlanningUnit.MONTH: change = 28; break;
+ case Timeline.PlanningUnit.QUARTER: change = 28 * 3; break;
+ case Timeline.PlanningUnit.YEAR: change = 28 * 12; break;
+ }
+ var increment = function() {
+ minDate += change * multiple;
+ };
+
+ var labeller = this._band.getLabeller();
+ while (true) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ Timeline.PlanningUnit.fromNumber(minDate),
+ labeller,
+ this._intervalUnit,
+ this._markerLayer,
+ this._lineLayer
+ );
+ if (hasMore()) {
+ increment();
+ } else {
+ break;
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.PlanningEtherPainter.prototype.softPaint = function() {
+};
+
+
+/*==================================================
+ * Planning Ether Marker Layout
+ *==================================================
+ */
+
+Timeline.PlanningEtherMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ Timeline.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ (label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/l10n/en/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/l10n/en/labellers.js
new file mode 100644
index 00000000..cdbac8cb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/l10n/en/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of Planning Labeller
+ *==================================================
+ */
+
+Timeline.PlanningLabeller.labels["en"] = {
+ dayPrefix: "d",
+ weekPrefix: "w",
+ monthPrefix: "m",
+ quarterPrefix: "q",
+ yearPrefix: "y"
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/labellers.js
new file mode 100644
index 00000000..c6916025
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/labellers.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Planning Labeller
+ *==================================================
+ */
+
+Timeline.PlanningLabeller = function(locale) {
+ this._locale = locale;
+};
+
+Timeline.PlanningLabeller.labels = [];
+
+Timeline.PlanningLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var n = Timeline.PlanningUnit.toNumber(date);
+
+ var prefix = "";
+ var divider = 1;
+ var divider2 = 7;
+ var labels = Timeline.PlanningLabeller.labels[this._locale];
+
+ switch (intervalUnit) {
+ case Timeline.PlanningUnit.DAY: prefix = labels.dayPrefix; break;
+ case Timeline.PlanningUnit.WEEK: prefix = labels.weekPrefix; divider = 7; divider2 = divider * 4; break;
+ case Timeline.PlanningUnit.MONTH: prefix = labels.monthPrefix; divider = 28; divider2 = divider * 3; break;
+ case Timeline.PlanningUnit.QUARTER: prefix = labels.quarterPrefix; divider = 28 * 3; divider2 = divider * 4; break;
+ case Timeline.PlanningUnit.YEAR: prefix = labels.yearPrefix; divider = 28 * 12; divider2 = divider * 5; break;
+ }
+ return { text: prefix + Math.floor(n / divider), emphasized: (n % divider2) == 0 };
+};
+
+Timeline.PlanningLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.PlanningLabeller.labels[this._locale].dayPrefix +
+ Timeline.PlanningUnit.toNumber(date);
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/planning.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/planning.js
new file mode 100644
index 00000000..4201f923
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/planning.js
@@ -0,0 +1,47 @@
+/*==================================================
+ * Planning
+ *==================================================
+ */
+
+Timeline.Planning = new Object();
+
+Timeline.Planning.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : Timeline.PlanningUnit.makeDefaultValue(),
+ interval: 1,
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.PlanningEtherPainter({
+ intervalUnit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ align: params.align,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = ("overview" in params && params.overview) ?
+ new Timeline.OverviewEventPainter(eventPainterParams) :
+ new Timeline.DetailedEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/units.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/units.js
new file mode 100644
index 00000000..13c31c1b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/ext/planning/scripts/units.js
@@ -0,0 +1,66 @@
+/*==================================================
+ * Planning Unit
+ *==================================================
+ */
+
+Timeline.PlanningUnit = new Object();
+
+Timeline.PlanningUnit.DAY = 0;
+Timeline.PlanningUnit.WEEK = 1;
+Timeline.PlanningUnit.MONTH = 2;
+Timeline.PlanningUnit.QUARTER = 3;
+Timeline.PlanningUnit.YEAR = 4;
+
+Timeline.PlanningUnit.getParser = function(format) {
+ return Timeline.PlanningUnit.parseFromObject;
+};
+
+Timeline.PlanningUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.PlanningLabeller(locale);
+};
+
+Timeline.PlanningUnit.makeDefaultValue = function () {
+ return 0;
+};
+
+Timeline.PlanningUnit.cloneValue = function (v) {
+ return v;
+};
+
+Timeline.PlanningUnit.parseFromObject = function(o) {
+ if (o == null) {
+ return null;
+ } else if (typeof o == "number") {
+ return o;
+ } else {
+ try {
+ return parseInt(o);
+ } catch (e) {
+ return null;
+ }
+ }
+};
+
+Timeline.PlanningUnit.toNumber = function(v) {
+ return v
+};
+
+Timeline.PlanningUnit.fromNumber = function(n) {
+ return n;
+};
+
+Timeline.PlanningUnit.compare = function(v1, v2) {
+ return v1 - v2;
+};
+
+Timeline.PlanningUnit.earlier = function(v1, v2) {
+ return Timeline.PlanningUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.PlanningUnit.later = function(v1, v2) {
+ return Timeline.PlanningUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.PlanningUnit.change = function(v, n) {
+ return v + n;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/blue-circle.png
new file mode 100644
index 00000000..0851cc65
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-arrow.png
new file mode 100644
index 00000000..c82d04d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-left.png
new file mode 100644
index 00000000..e338f86b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-right.png
new file mode 100644
index 00000000..e5dc1367
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom.png
new file mode 100644
index 00000000..7d8ef71e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-bottom.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left-arrow.png
new file mode 100644
index 00000000..3370c726
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left.png
new file mode 100644
index 00000000..772bf23a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right-arrow.png
new file mode 100644
index 00000000..1f1017d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right.png
new file mode 100644
index 00000000..83954b64
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-arrow.png
new file mode 100644
index 00000000..0eadf3f1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-left.png
new file mode 100644
index 00000000..53313719
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-right.png
new file mode 100644
index 00000000..72be593e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top.png
new file mode 100644
index 00000000..afc8cf74
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/bubble-top.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/close-button.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/close-button.png
new file mode 100644
index 00000000..2c6f9e1a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/close-button.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright-vertical.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright-vertical.png
new file mode 100644
index 00000000..c2738f93
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright-vertical.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright.png
new file mode 100644
index 00000000..1132a4e5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/copyright.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-blue-circle.png
new file mode 100644
index 00000000..33e50dbc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-green-circle.png
new file mode 100644
index 00000000..e9d4f2ec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-red-circle.png
new file mode 100644
index 00000000..e71b4ff6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dark-red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-blue-circle.png
new file mode 100644
index 00000000..5d3d4835
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-green-circle.png
new file mode 100644
index 00000000..86d211cb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-red-circle.png
new file mode 100644
index 00000000..11f82922
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/dull-red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/gray-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/gray-circle.png
new file mode 100644
index 00000000..6266621d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/gray-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/green-circle.png
new file mode 100644
index 00000000..8f14eabe
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-left.png
new file mode 100644
index 00000000..4f8c64a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-right.png
new file mode 100644
index 00000000..a8834bb6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-left.png
new file mode 100644
index 00000000..b6416aab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-right.png
new file mode 100644
index 00000000..729524bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-left.png
new file mode 100644
index 00000000..b0501341
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-right.png
new file mode 100644
index 00000000..01a82ab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/message-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/progress-running.gif b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/progress-running.gif
new file mode 100644
index 00000000..f7429ebc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/progress-running.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/red-circle.png
new file mode 100644
index 00000000..d7d58937
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/top-bubble.png b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/top-bubble.png
new file mode 100644
index 00000000..078b578f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/images/top-bubble.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/band.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/band.js
new file mode 100644
index 00000000..a16a4b12
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/band.js
@@ -0,0 +1,960 @@
+/*=================================================
+ *
+ * Coding standards:
+ *
+ * We aim towards Douglas Crockford's Javascript conventions.
+ * See: http://javascript.crockford.com/code.html
+ * See also: http://www.crockford.com/javascript/javascript.html
+ *
+ * That said, this JS code was written before some recent JS
+ * support libraries became widely used or available.
+ * In particular, the _ character is used to indicate a class function or
+ * variable that should be considered private to the class.
+ *
+ * The code mostly uses accessor methods for getting/setting the private
+ * class variables.
+ *
+ * Over time, we'd like to formalize the convention by using support libraries
+ * which enforce privacy in objects.
+ *
+ * We also want to use jslint: http://www.jslint.com/
+ *
+ *
+ *==================================================
+ */
+
+
+
+/*==================================================
+ * Band
+ *==================================================
+ */
+Timeline._Band = function(timeline, bandInfo, index) {
+ // Set up the band's object
+
+ // Munge params: If autoWidth is on for the Timeline, then ensure that
+ // bandInfo.width is an integer
+ if (timeline.autoWidth && typeof bandInfo.width == 'string') {
+ bandInfo.width = bandInfo.width.indexOf("%") > -1 ? 0 : parseInt(bandInfo.width);
+ }
+
+ this._timeline = timeline;
+ this._bandInfo = bandInfo;
+
+ this._index = index;
+
+ this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.getDefaultLocale();
+ this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0;
+ this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller :
+ (("createLabeller" in timeline.getUnit()) ?
+ timeline.getUnit().createLabeller(this._locale, this._timeZone) :
+ new Timeline.GregorianDateLabeller(this._locale, this._timeZone));
+ this._theme = bandInfo.theme;
+ this._zoomIndex = ("zoomIndex" in bandInfo) ? bandInfo.zoomIndex : 0;
+ this._zoomSteps = ("zoomSteps" in bandInfo) ? bandInfo.zoomSteps : null;
+
+ this._dragging = false;
+ this._changing = false;
+ this._originalScrollSpeed = 5; // pixels
+ this._scrollSpeed = this._originalScrollSpeed;
+ this._onScrollListeners = [];
+
+ this._orthogonalDragging = false;
+ this._viewOrthogonalOffset = 0; // vertical offset if the timeline is horizontal, and vice versa
+ this._onOrthogonalScrollListeners = [];
+
+ var b = this;
+ this._syncWithBand = null;
+ this._syncWithBandHandler = function(band) {
+ b._onHighlightBandScroll();
+ };
+ this._syncWithBandOrthogonalScrollHandler = function(band) {
+ b._onHighlightBandOrthogonalScroll();
+ };
+ this._selectorListener = function(band) {
+ b._onHighlightBandScroll();
+ };
+
+ /*
+ * Install a textbox to capture keyboard events
+ */
+ var inputDiv = this._timeline.getDocument().createElement("div");
+ inputDiv.className = "timeline-band-input";
+ this._timeline.addDiv(inputDiv);
+
+ this._keyboardInput = document.createElement("input");
+ this._keyboardInput.type = "text";
+ inputDiv.appendChild(this._keyboardInput);
+ SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, "_onKeyDown");
+ SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, "_onKeyUp");
+
+ /*
+ * The band's outer most div that slides with respect to the timeline's div
+ */
+ this._div = this._timeline.getDocument().createElement("div");
+ this._div.id = "timeline-band-" + index;
+ this._div.className = "timeline-band timeline-band-" + index;
+ this._timeline.addDiv(this._div);
+
+ SimileAjax.DOM.registerEventWithObject(this._div, "dblclick", this, "_onDblClick");
+ SimileAjax.DOM.registerEventWithObject(this._div, "mousedown", this, "_onMouseDown");
+ SimileAjax.DOM.registerEventWithObject(document.body, "mousemove", this, "_onMouseMove");
+ SimileAjax.DOM.registerEventWithObject(document.body, "mouseup", this, "_onMouseUp");
+ SimileAjax.DOM.registerEventWithObject(document.body, "mouseout", this, "_onMouseOut");
+
+ var mouseWheel = this._theme!= null ? this._theme.mouseWheel : 'scroll'; // theme is not always defined
+ if (mouseWheel === 'zoom' || mouseWheel === 'scroll' || this._zoomSteps) {
+ // capture mouse scroll
+ if (SimileAjax.Platform.browser.isFirefox) {
+ SimileAjax.DOM.registerEventWithObject(this._div, "DOMMouseScroll", this, "_onMouseScroll");
+ } else {
+ SimileAjax.DOM.registerEventWithObject(this._div, "mousewheel", this, "_onMouseScroll");
+ }
+ }
+
+ /*
+ * The inner div that contains layers
+ */
+ this._innerDiv = this._timeline.getDocument().createElement("div");
+ this._innerDiv.className = "timeline-band-inner";
+ this._div.appendChild(this._innerDiv);
+
+ /*
+ * Initialize parts of the band
+ */
+ this._ether = bandInfo.ether;
+ bandInfo.ether.initialize(this, timeline);
+
+ this._etherPainter = bandInfo.etherPainter;
+ bandInfo.etherPainter.initialize(this, timeline);
+
+ this._eventSource = bandInfo.eventSource;
+ if (this._eventSource) {
+ this._eventListener = {
+ onAddMany: function() { b._onAddMany(); },
+ onClear: function() { b._onClear(); }
+ }
+ this._eventSource.addListener(this._eventListener);
+ }
+
+ this._eventPainter = bandInfo.eventPainter;
+ this._eventTracksNeeded = 0; // set by painter via updateEventTrackInfo
+ this._eventTrackIncrement = 0;
+ bandInfo.eventPainter.initialize(this, timeline);
+
+ this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : [];
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].initialize(this, timeline);
+ }
+
+ this._supportsOrthogonalScrolling = ("supportsOrthogonalScrolling" in this._eventPainter) &&
+ this._eventPainter.supportsOrthogonalScrolling();
+
+ if (this._supportsOrthogonalScrolling) {
+ this._scrollBar = this._timeline.getDocument().createElement("div");
+ this._scrollBar.id = "timeline-band-scrollbar-" + index;
+ this._scrollBar.className = "timeline-band-scrollbar";
+ this._timeline.addDiv(this._scrollBar);
+
+ this._scrollBar.innerHTML = '<div class="timeline-band-scrollbar-thumb"> </div>'
+
+ var scrollbarThumb = this._scrollBar.firstChild;
+ if (SimileAjax.Platform.browser.isIE) {
+ scrollbarThumb.style.cursor = "move";
+ } else {
+ scrollbarThumb.style.cursor = "-moz-grab";
+ }
+ SimileAjax.DOM.registerEventWithObject(scrollbarThumb, "mousedown", this, "_onScrollBarMouseDown");
+ }
+};
+
+Timeline._Band.SCROLL_MULTIPLES = 5;
+
+Timeline._Band.prototype.dispose = function() {
+ this.closeBubble();
+
+ if (this._eventSource) {
+ this._eventSource.removeListener(this._eventListener);
+ this._eventListener = null;
+ this._eventSource = null;
+ }
+
+ this._timeline = null;
+ this._bandInfo = null;
+
+ this._labeller = null;
+ this._ether = null;
+ this._etherPainter = null;
+ this._eventPainter = null;
+ this._decorators = null;
+
+ this._onScrollListeners = null;
+ this._syncWithBandHandler = null;
+ this._syncWithBandOrthogonalScrollHandler = null;
+ this._selectorListener = null;
+
+ this._div = null;
+ this._innerDiv = null;
+ this._keyboardInput = null;
+ this._scrollBar = null;
+};
+
+Timeline._Band.prototype.addOnScrollListener = function(listener) {
+ this._onScrollListeners.push(listener);
+};
+
+Timeline._Band.prototype.removeOnScrollListener = function(listener) {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ if (this._onScrollListeners[i] == listener) {
+ this._onScrollListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline._Band.prototype.addOnOrthogonalScrollListener = function(listener) {
+ this._onOrthogonalScrollListeners.push(listener);
+};
+
+Timeline._Band.prototype.removeOnOrthogonalScrollListener = function(listener) {
+ for (var i = 0; i < this._onOrthogonalScrollListeners.length; i++) {
+ if (this._onOrthogonalScrollListeners[i] == listener) {
+ this._onOrthogonalScrollListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline._Band.prototype.setSyncWithBand = function(band, highlight) {
+ if (this._syncWithBand) {
+ this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+ this._syncWithBand.removeOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+ }
+
+ this._syncWithBand = band;
+ this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+ this._syncWithBand.addOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+ this._highlight = highlight;
+ this._positionHighlight();
+};
+
+Timeline._Band.prototype.getLocale = function() {
+ return this._locale;
+};
+
+Timeline._Band.prototype.getTimeZone = function() {
+ return this._timeZone;
+};
+
+Timeline._Band.prototype.getLabeller = function() {
+ return this._labeller;
+};
+
+Timeline._Band.prototype.getIndex = function() {
+ return this._index;
+};
+
+Timeline._Band.prototype.getEther = function() {
+ return this._ether;
+};
+
+Timeline._Band.prototype.getEtherPainter = function() {
+ return this._etherPainter;
+};
+
+Timeline._Band.prototype.getEventSource = function() {
+ return this._eventSource;
+};
+
+Timeline._Band.prototype.getEventPainter = function() {
+ return this._eventPainter;
+};
+
+Timeline._Band.prototype.getTimeline = function() {
+ return this._timeline;
+};
+
+// Autowidth support
+Timeline._Band.prototype.updateEventTrackInfo = function(tracks, increment) {
+ this._eventTrackIncrement = increment; // doesn't vary for a specific band
+
+ if (tracks > this._eventTracksNeeded) {
+ this._eventTracksNeeded = tracks;
+ }
+};
+
+// Autowidth support
+Timeline._Band.prototype.checkAutoWidth = function() {
+ // if a new (larger) width is needed by the band
+ // then: a) updates the band's bandInfo.width
+ //
+ // desiredWidth for the band is
+ // (number of tracks + margin) * track increment
+ if (! this._timeline.autoWidth) {
+ return; // early return
+ }
+
+ var overviewBand = this._eventPainter.getType() == 'overview';
+ var margin = overviewBand ?
+ this._theme.event.overviewTrack.autoWidthMargin :
+ this._theme.event.track.autoWidthMargin;
+ var desiredWidth = Math.ceil((this._eventTracksNeeded + margin) *
+ this._eventTrackIncrement);
+ // add offset amount (additional margin)
+ desiredWidth += overviewBand ? this._theme.event.overviewTrack.offset :
+ this._theme.event.track.offset;
+ var bandInfo = this._bandInfo;
+
+ if (desiredWidth != bandInfo.width) {
+ bandInfo.width = desiredWidth;
+ }
+};
+
+Timeline._Band.prototype.layout = function() {
+ this.paint();
+};
+
+Timeline._Band.prototype.paint = function() {
+ this._etherPainter.paint();
+ this._paintDecorators();
+ this._paintEvents();
+};
+
+Timeline._Band.prototype.softLayout = function() {
+ this.softPaint();
+};
+
+Timeline._Band.prototype.softPaint = function() {
+ this._etherPainter.softPaint();
+ this._softPaintDecorators();
+ this._softPaintEvents();
+};
+
+Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) {
+ var inputDiv = this._keyboardInput.parentNode;
+ var middle = shift + Math.floor(width / 2);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.top = shift + "px";
+ this._div.style.height = width + "px";
+
+ inputDiv.style.top = middle + "px";
+ inputDiv.style.left = "-1em";
+ } else {
+ this._div.style.left = shift + "px";
+ this._div.style.width = width + "px";
+
+ inputDiv.style.left = middle + "px";
+ inputDiv.style.top = "-1em";
+ }
+};
+
+Timeline._Band.prototype.getViewWidth = function() {
+ if (this._timeline.isHorizontal()) {
+ return this._div.offsetHeight;
+ } else {
+ return this._div.offsetWidth;
+ }
+};
+
+Timeline._Band.prototype.setViewLength = function(length) {
+ this._viewLength = length;
+ this._recenterDiv();
+ this._onChanging();
+};
+
+Timeline._Band.prototype.getViewLength = function() {
+ return this._viewLength;
+};
+
+Timeline._Band.prototype.getTotalViewLength = function() {
+ return Timeline._Band.SCROLL_MULTIPLES * this._viewLength;
+};
+
+Timeline._Band.prototype.getViewOffset = function() {
+ return this._viewOffset;
+};
+
+Timeline._Band.prototype.getMinDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+
+Timeline._Band.prototype.getMaxDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength);
+};
+
+Timeline._Band.prototype.getMinVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(0);
+};
+
+Timeline._Band.prototype.getMinVisibleDateAfterDelta = function(delta) {
+ return this._ether.pixelOffsetToDate(delta);
+};
+
+Timeline._Band.prototype.getMaxVisibleDate = function() {
+ // Max date currently visible on band
+ return this._ether.pixelOffsetToDate(this._viewLength);
+};
+
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta = function(delta) {
+ // Max date visible on band after delta px view change is applied
+ return this._ether.pixelOffsetToDate(this._viewLength + delta);
+};
+
+Timeline._Band.prototype.getCenterVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewLength / 2);
+};
+
+Timeline._Band.prototype.setMinVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setMaxVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setCenterVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.dateToPixelOffset = function(date) {
+ return this._ether.dateToPixelOffset(date) - this._viewOffset;
+};
+
+Timeline._Band.prototype.pixelOffsetToDate = function(pixels) {
+ return this._ether.pixelOffsetToDate(pixels + this._viewOffset);
+};
+
+Timeline._Band.prototype.getViewOrthogonalOffset = function() {
+ return this._viewOrthogonalOffset;
+};
+
+Timeline._Band.prototype.setViewOrthogonalOffset = function(offset) {
+ this._viewOrthogonalOffset = Math.max(0, offset);
+};
+
+Timeline._Band.prototype.createLayerDiv = function(zIndex, className) {
+ var div = this._timeline.getDocument().createElement("div");
+ div.className = "timeline-band-layer" + (typeof className == "string" ? (" " + className) : "");
+ div.style.zIndex = zIndex;
+ this._innerDiv.appendChild(div);
+
+ var innerDiv = this._timeline.getDocument().createElement("div");
+ innerDiv.className = "timeline-band-layer-inner";
+ if (SimileAjax.Platform.browser.isIE) {
+ innerDiv.style.cursor = "move";
+ } else {
+ innerDiv.style.cursor = "-moz-grab";
+ }
+ div.appendChild(innerDiv);
+
+ return innerDiv;
+};
+
+Timeline._Band.prototype.removeLayerDiv = function(div) {
+ this._innerDiv.removeChild(div.parentNode);
+};
+
+Timeline._Band.prototype.scrollToCenter = function(date, f) {
+ var pixelOffset = this._ether.dateToPixelOffset(date);
+ if (pixelOffset < -this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength));
+ } else if (pixelOffset > 3 * this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength));
+ }
+ this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)), f);
+};
+
+Timeline._Band.prototype.showBubbleForEvent = function(eventID) {
+ var evt = this.getEventSource().getEvent(eventID);
+ if (evt) {
+ var self = this;
+ this.scrollToCenter(evt.getStart(), function() {
+ self._eventPainter.showBubble(evt);
+ });
+ }
+};
+
+Timeline._Band.prototype.zoom = function(zoomIn, x, y, target) {
+ if (!this._zoomSteps) {
+ // zoom disabled
+ return;
+ }
+
+ // shift the x value by our offset
+ x += this._viewOffset;
+
+ var zoomDate = this._ether.pixelOffsetToDate(x);
+ var netIntervalChange = this._ether.zoom(zoomIn);
+ this._etherPainter.zoom(netIntervalChange);
+
+ // shift our zoom date to the far left
+ this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
+ // then shift it back to where the mouse was
+ this._moveEther(x);
+};
+
+Timeline._Band.prototype._onMouseDown = function(elmt, evt, target) {
+ if (!this._dragging) {
+ this.closeBubble();
+
+ this._dragging = true;
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+
+ return this._cancelEvent(evt);
+ }
+};
+
+Timeline._Band.prototype._onMouseMove = function(elmt, evt, target) {
+ if (this._dragging || this._orthogonalDragging) {
+ var diffX = evt.clientX - this._dragX;
+ var diffY = evt.clientY - this._dragY;
+
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+ }
+
+ if (this._dragging) {
+ if (this._timeline.isHorizontal()) {
+ this._moveEther(diffX, diffY);
+ } else {
+ this._moveEther(diffY, diffX);
+ }
+ } else if (this._orthogonalDragging) {
+ var viewWidth = this.getViewWidth();
+ var scrollbarThumb = this._scrollBar.firstChild;
+ if (this._timeline.isHorizontal()) {
+ this._moveEther(0, -diffY * viewWidth / scrollbarThumb.offsetHeight);
+ } else {
+ this._moveEther(0, -diffX * viewWidth / scrollbarThumb.offsetWidth);
+ }
+ } else {
+ return;
+ }
+
+ this._positionHighlight();
+ this._showScrollbar();
+
+ return this._cancelEvent(evt);
+};
+
+Timeline._Band.prototype._onMouseUp = function(elmt, evt, target) {
+ if (this._dragging) {
+ this._dragging = false;
+ } else if (this._orthogonalDragging) {
+ this._orthogonalDragging = false;
+ } else {
+ return;
+ }
+ this._keyboardInput.focus();
+ this._bounceBack();
+
+ return this._cancelEvent(evt);
+};
+
+Timeline._Band.prototype._onMouseOut = function(elmt, evt, target) {
+ if (target == document.body) {
+ if (this._dragging) {
+ this._dragging = false;
+ } else if (this._orthogonalDragging) {
+ this._orthogonalDragging = false;
+ } else {
+ return;
+ }
+ this._bounceBack();
+
+ return this._cancelEvent(evt);
+ }
+};
+
+Timeline._Band.prototype._onScrollBarMouseDown = function(elmt, evt, target) {
+ if (!this._orthogonalDragging) {
+ this.closeBubble();
+
+ this._orthogonalDragging = true;
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+
+ return this._cancelEvent(evt);
+ }
+};
+
+Timeline._Band.prototype._onMouseScroll = function(innerFrame, evt, target) {
+ var now = new Date();
+ now = now.getTime();
+
+ if (!this._lastScrollTime || ((now - this._lastScrollTime) > 50)) {
+ // limit 1 scroll per 200ms due to FF3 sending multiple events back to back
+ this._lastScrollTime = now;
+
+ var delta = 0;
+ if (evt.wheelDelta) {
+ delta = evt.wheelDelta/120;
+ } else if (evt.detail) {
+ delta = -evt.detail/3;
+ }
+
+ // either scroll or zoom
+ var mouseWheel = this._theme.mouseWheel;
+
+ if (this._zoomSteps || mouseWheel === 'zoom') {
+ var loc = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ if (delta != 0) {
+ var zoomIn;
+ if (delta > 0)
+ zoomIn = true;
+ if (delta < 0)
+ zoomIn = false;
+ // call zoom on the timeline so we could zoom multiple bands if desired
+ this._timeline.zoom(zoomIn, loc.x, loc.y, innerFrame);
+ }
+ }
+ else if (mouseWheel === 'scroll') {
+ var move_amt = 50 * (delta < 0 ? -1 : 1);
+ this._moveEther(move_amt);
+ }
+ }
+
+ // prevent bubble
+ if (evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ evt.cancelBubble = true;
+
+ // prevent the default action
+ if (evt.preventDefault) {
+ evt.preventDefault();
+ }
+ evt.returnValue = false;
+};
+
+Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) {
+ var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ var distance = coords.x - (this._viewLength / 2 - this._viewOffset);
+
+ this._autoScroll(-distance);
+};
+
+Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ switch (evt.keyCode) {
+ case 27: // ESC
+ break;
+ case 37: // left arrow
+ case 38: // up arrow
+ this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ case 39: // right arrow
+ case 40: // down arrow
+ this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ default:
+ return true;
+ }
+ this.closeBubble();
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ this._scrollSpeed = this._originalScrollSpeed;
+
+ switch (evt.keyCode) {
+ case 35: // end
+ this.setCenterVisibleDate(this._eventSource.getLatestDate());
+ break;
+ case 36: // home
+ this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+ break;
+ case 33: // page up
+ this._autoScroll(this._timeline.getPixelLength());
+ break;
+ case 34: // page down
+ this._autoScroll(-this._timeline.getPixelLength());
+ break;
+ default:
+ return true;
+ }
+
+ this.closeBubble();
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._autoScroll = function(distance, f) {
+ var b = this;
+ var a = SimileAjax.Graphics.createAnimation(
+ function(abs, diff) {
+ b._moveEther(diff);
+ },
+ 0,
+ distance,
+ 1000,
+ f
+ );
+ a.run();
+};
+
+Timeline._Band.prototype._moveEther = function(shift, orthogonalShift) {
+ if (orthogonalShift === undefined) {
+ orthogonalShift = 0;
+ }
+
+ this.closeBubble();
+
+ // A positive shift means back in time
+ // Check that we're not moving beyond Timeline's limits
+ if (!this._timeline.shiftOK(this._index, shift)) {
+ return; // early return
+ }
+
+ this._viewOffset += shift;
+ this._ether.shiftPixels(-shift);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ }
+
+ if (this._supportsOrthogonalScrolling) {
+ if (this._eventPainter.getOrthogonalExtent() <= this.getViewWidth()) {
+ this._viewOrthogonalOffset = 0;
+ } else {
+ this._viewOrthogonalOffset = this._viewOrthogonalOffset + orthogonalShift;
+ }
+ }
+
+ if (this._viewOffset > -this._viewLength * 0.5 ||
+ this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) {
+
+ this._recenterDiv();
+ } else {
+ this.softLayout();
+ }
+
+ this._onChanging();
+}
+
+Timeline._Band.prototype._onChanging = function() {
+ this._changing = true;
+
+ this._fireOnScroll();
+ this._setSyncWithBandDate();
+
+ this._changing = false;
+};
+
+Timeline._Band.prototype.busy = function() {
+ // Is this band busy changing other bands?
+ return(this._changing);
+};
+
+Timeline._Band.prototype._fireOnScroll = function() {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ this._onScrollListeners[i](this);
+ }
+};
+
+Timeline._Band.prototype._fireOnOrthogonalScroll = function() {
+ for (var i = 0; i < this._onOrthogonalScrollListeners.length; i++) {
+ this._onOrthogonalScrollListeners[i](this);
+ }
+};
+
+Timeline._Band.prototype._setSyncWithBandDate = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2);
+ this._syncWithBand.setCenterVisibleDate(centerDate);
+ }
+};
+
+Timeline._Band.prototype._onHighlightBandScroll = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._syncWithBand.getCenterVisibleDate();
+ var centerPixelOffset = this._ether.dateToPixelOffset(centerDate);
+
+ this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset));
+ this._positionHighlight();
+ }
+};
+
+Timeline._Band.prototype._onHighlightBandOrthogonalScroll = function() {
+ if (this._syncWithBand) {
+ this._positionHighlight();
+ }
+};
+
+Timeline._Band.prototype._onAddMany = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._onClear = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._positionHighlight = function() {
+ if (this._syncWithBand) {
+ var startDate = this._syncWithBand.getMinVisibleDate();
+ var endDate = this._syncWithBand.getMaxVisibleDate();
+
+ if (this._highlight) {
+ var offset = 0; // percent
+ var extent = 1.0; // percent
+ var syncEventPainter = this._syncWithBand.getEventPainter();
+ if ("supportsOrthogonalScrolling" in syncEventPainter &&
+ syncEventPainter.supportsOrthogonalScrolling()) {
+
+ var orthogonalExtent = syncEventPainter.getOrthogonalExtent();
+ var visibleWidth = this._syncWithBand.getViewWidth();
+ var totalWidth = Math.max(visibleWidth, orthogonalExtent);
+ extent = visibleWidth / totalWidth;
+ offset = -this._syncWithBand.getViewOrthogonalOffset() / totalWidth;
+ }
+
+ this._etherPainter.setHighlight(startDate, endDate, offset, extent);
+ }
+ }
+};
+
+Timeline._Band.prototype._recenterDiv = function() {
+ this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2;
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ }
+ this.layout();
+};
+
+Timeline._Band.prototype._paintEvents = function() {
+ this._eventPainter.paint();
+ this._showScrollbar();
+ this._fireOnOrthogonalScroll();
+};
+
+Timeline._Band.prototype._softPaintEvents = function() {
+ this._eventPainter.softPaint();
+};
+
+Timeline._Band.prototype._paintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].paint();
+ }
+};
+
+Timeline._Band.prototype._softPaintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].softPaint();
+ }
+};
+
+Timeline._Band.prototype.closeBubble = function() {
+ SimileAjax.WindowManager.cancelPopups();
+};
+
+Timeline._Band.prototype._bounceBack = function(f) {
+ if (!this._supportsOrthogonalScrolling) {
+ return;
+ }
+
+ var target = 0;
+ if (this._viewOrthogonalOffset < 0) {
+ var orthogonalExtent = this._eventPainter.getOrthogonalExtent();
+ if (this._viewOrthogonalOffset + orthogonalExtent >= this.getViewWidth()) {
+ target = this._viewOrthogonalOffset;
+ } else {
+ target = Math.min(0, this.getViewWidth() - orthogonalExtent);
+ }
+ }
+
+ if (target != this._viewOrthogonalOffset) {
+ var self = this;
+ SimileAjax.Graphics.createAnimation(
+ function(abs, diff) {
+ self._viewOrthogonalOffset = abs;
+ self._eventPainter.softPaint();
+ self._showScrollbar();
+ self._fireOnOrthogonalScroll();
+ },
+ this._viewOrthogonalOffset,
+ target,
+ 300,
+ function() {
+ self._hideScrollbar();
+ }
+ ).run();
+ } else {
+ this._hideScrollbar();
+ }
+};
+
+Timeline._Band.prototype._showScrollbar = function() {
+ if (!this._supportsOrthogonalScrolling) {
+ return;
+ }
+
+ var orthogonalExtent = this._eventPainter.getOrthogonalExtent();
+ var visibleWidth = this.getViewWidth();
+ var totalWidth = Math.max(visibleWidth, orthogonalExtent);
+ var ratio = (visibleWidth / totalWidth);
+ var thumbWidth = Math.round(visibleWidth * ratio) + "px";
+ var thumbOffset = Math.round(-this._viewOrthogonalOffset * ratio) + "px";
+ var thumbThickness = 12;
+
+ var thumb = this._scrollBar.firstChild;
+ if (this._timeline.isHorizontal()) {
+ this._scrollBar.style.top = this._div.style.top;
+ this._scrollBar.style.height = this._div.style.height;
+
+ this._scrollBar.style.right = "0px";
+ this._scrollBar.style.width = thumbThickness + "px";
+
+ thumb.style.top = thumbOffset;
+ thumb.style.height = thumbWidth;
+ } else {
+ this._scrollBar.style.left = this._div.style.left;
+ this._scrollBar.style.width = this._div.style.width;
+
+ this._scrollBar.style.bottom = "0px";
+ this._scrollBar.style.height = thumbThickness + "px";
+
+ thumb.style.left = thumbOffset;
+ thumb.style.width = thumbWidth;
+ }
+
+ if (ratio >= 1 && this._viewOrthogonalOffset == 0) {
+ this._scrollBar.style.display = "none";
+ } else {
+ this._scrollBar.style.display = "block";
+ }
+};
+
+Timeline._Band.prototype._hideScrollbar = function() {
+ if (!this._supportsOrthogonalScrolling) {
+ return;
+ }
+ //this._scrollBar.style.display = "none";
+};
+
+Timeline._Band.prototype._cancelEvent = function(evt) {
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/compact-painter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/compact-painter.js
new file mode 100644
index 00000000..3a30ae36
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/compact-painter.js
@@ -0,0 +1,1074 @@
+/*==================================================
+ * Compact Event Painter
+ *==================================================
+ */
+
+Timeline.CompactEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
+
+ this._eventIdToElmt = {};
+};
+
+Timeline.CompactEventPainter.prototype.getType = function() {
+ return 'compact';
+};
+
+Timeline.CompactEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backLayer = null;
+ this._eventLayer = null;
+ this._lineLayer = null;
+ this._highlightLayer = null;
+
+ this._eventIdToElmt = null;
+};
+
+Timeline.CompactEventPainter.prototype.supportsOrthogonalScrolling = function() {
+ return true;
+};
+
+Timeline.CompactEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.CompactEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.CompactEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._eventIdToElmt = {};
+ this._prepareForPainting();
+
+ var metrics = this._computeMetrics();
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventIterator(minDate, maxDate);
+
+ var stackConcurrentPreciseInstantEvents = "stackConcurrentPreciseInstantEvents" in this._params && typeof this._params.stackConcurrentPreciseInstantEvents == "object";
+ var collapseConcurrentPreciseInstantEvents = "collapseConcurrentPreciseInstantEvents" in this._params && this._params.collapseConcurrentPreciseInstantEvents;
+ if (collapseConcurrentPreciseInstantEvents || stackConcurrentPreciseInstantEvents) {
+ var bufferedEvents = [];
+ var previousInstantEvent = null;
+
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ if (!evt.isInstant() || evt.isImprecise()) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ } else if (previousInstantEvent != null &&
+ previousInstantEvent.getStart().getTime() == evt.getStart().getTime()) {
+ bufferedEvents[bufferedEvents.length - 1].push(evt);
+ } else {
+ bufferedEvents.push([ evt ]);
+ previousInstantEvent = evt;
+ }
+ }
+ }
+
+ for (var i = 0; i < bufferedEvents.length; i++) {
+ var compositeEvents = bufferedEvents[i];
+ if (compositeEvents.length == 1) {
+ this.paintEvent(compositeEvents[0], metrics, this._params.theme, highlightMatcher(evt));
+ } else {
+ var match = -1;
+ for (var j = 0; match < 0 && j < compositeEvents.length; j++) {
+ match = highlightMatcher(compositeEvents[j]);
+ }
+
+ if (stackConcurrentPreciseInstantEvents) {
+ this.paintStackedPreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+ } else {
+ this.paintCompositePreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+ }
+ }
+ }
+ } else {
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+
+ this._setOrthogonalOffset(metrics);
+};
+
+Timeline.CompactEventPainter.prototype.softPaint = function() {
+ this._setOrthogonalOffset(this._computeMetrics());
+};
+
+Timeline.CompactEventPainter.prototype.getOrthogonalExtent = function() {
+ var metrics = this._computeMetrics();
+ return 2 * metrics.trackOffset + this._tracks.length * metrics.trackHeight;
+};
+
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset = function(metrics) {
+ var orthogonalOffset = this._band.getViewOrthogonalOffset();
+
+ this._highlightLayer.style.top =
+ this._lineLayer.style.top =
+ this._eventLayer.style.top =
+ orthogonalOffset + "px";
+};
+
+Timeline.CompactEventPainter.prototype._computeMetrics = function() {
+ var theme = this._params.theme;
+ var eventTheme = theme.event;
+
+ var metrics = {
+ trackOffset: "trackOffset" in this._params ? this._params.trackOffset : 10,
+ trackHeight: "trackHeight" in this._params ? this._params.trackHeight : 10,
+
+ tapeHeight: theme.event.tape.height,
+ tapeBottomMargin: "tapeBottomMargin" in this._params ? this._params.tapeBottomMargin : 2,
+
+ labelBottomMargin: "labelBottomMargin" in this._params ? this._params.labelBottomMargin : 5,
+ labelRightMargin: "labelRightMargin" in this._params ? this._params.labelRightMargin : 5,
+
+ defaultIcon: eventTheme.instant.icon,
+ defaultIconWidth: eventTheme.instant.iconWidth,
+ defaultIconHeight: eventTheme.instant.iconHeight,
+
+ customIconWidth: "iconWidth" in this._params ? this._params.iconWidth : eventTheme.instant.iconWidth,
+ customIconHeight: "iconHeight" in this._params ? this._params.iconHeight : eventTheme.instant.iconHeight,
+
+ iconLabelGap: "iconLabelGap" in this._params ? this._params.iconLabelGap : 2,
+ iconBottomMargin: "iconBottomMargin" in this._params ? this._params.iconBottomMargin : 2
+ };
+ if ("compositeIcon" in this._params) {
+ metrics.compositeIcon = this._params.compositeIcon;
+ metrics.compositeIconWidth = this._params.compositeIconWidth || metrics.customIconWidth;
+ metrics.compositeIconHeight = this._params.compositeIconHeight || metrics.customIconHeight;
+ } else {
+ metrics.compositeIcon = metrics.defaultIcon;
+ metrics.compositeIconWidth = metrics.defaultIconWidth;
+ metrics.compositeIconHeight = metrics.defaultIconHeight;
+ }
+ metrics.defaultStackIcon = ("stackConcurrentPreciseInstantEvents" in this._params && "icon" in this._params.stackConcurrentPreciseInstantEvents) ?
+ this._params.stackConcurrentPreciseInstantEvents.icon : metrics.defaultIcon;
+ metrics.defaultStackIconWidth = ("stackConcurrentPreciseInstantEvents" in this._params && "iconWidth" in this._params.stackConcurrentPreciseInstantEvents) ?
+ this._params.stackConcurrentPreciseInstantEvents.iconWidth : metrics.defaultIconWidth;
+ metrics.defaultStackIconHeight = ("stackConcurrentPreciseInstantEvents" in this._params && "iconHeight" in this._params.stackConcurrentPreciseInstantEvents) ?
+ this._params.stackConcurrentPreciseInstantEvents.iconHeight : metrics.defaultIconHeight;
+
+ return metrics;
+};
+
+Timeline.CompactEventPainter.prototype._prepareForPainting = function() {
+ var band = this._band;
+
+ if (this._backLayer == null) {
+ this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+ this._backLayer.style.visibility = "hidden";
+
+ var eventLabelPrototype = document.createElement("span");
+ eventLabelPrototype.className = "timeline-event-label";
+ this._backLayer.appendChild(eventLabelPrototype);
+ this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+ }
+ this._frc.update();
+ this._tracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._lineLayer != null) {
+ band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+ this._lineLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.CompactEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.CompactEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData.url = metrics.defaultIcon;
+ iconData.width = metrics.defaultIconWidth;
+ iconData.height = metrics.defaultIconHeight;
+ iconData.className = "timeline-event-icon-default";
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ null, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+};
+
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+ var evt = events[0];
+
+ var tooltips = [];
+ for (var i = 0; i < events.length; i++) {
+ tooltips.push(events[i].getProperty("tooltip") || events[i].getText());
+ }
+ var commonData = {
+ tooltip: tooltips.join("; ")
+ };
+
+ var iconData = {
+ url: metrics.compositeIcon,
+ width: metrics.compositeIconWidth,
+ height: metrics.compositeIconHeight,
+ className: "timeline-event-icon-composite"
+ };
+
+ var labelData = {
+ text: String.substitute(this._params.compositeEventLabelTemplate, [ events.length ])
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ null, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt, domEvt, events);
+ };
+
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+ for (var i = 0; i < events.length; i++) {
+ this._eventIdToElmt[events[i].getID()] = result.iconElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+ var limit = "limit" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.limit : 10;
+ var moreMessageTemplate = "moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate : "%0 More Events";
+ var showMoreMessage = limit <= events.length - 2; // We want at least 2 more events above the limit.
+ // Otherwise we'd need the singular case of "1 More Event"
+
+ var band = this._band;
+ var getPixelOffset = function(date) {
+ return Math.round(band.dateToPixelOffset(date));
+ };
+ var getIconData = function(evt) {
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData.url = metrics.defaultStackIcon;
+ iconData.width = metrics.defaultStackIconWidth;
+ iconData.height = metrics.defaultStackIconHeight;
+ iconData.className = "timeline-event-icon-stack timeline-event-icon-default";
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ iconData.className = "timeline-event-icon-stack";
+ }
+ return iconData;
+ };
+
+ var firstIconData = getIconData(events[0]);
+ var horizontalIncrement = 5;
+ var leftIconEdge = 0;
+ var totalLabelWidth = 0;
+ var totalLabelHeight = 0;
+ var totalIconHeight = 0;
+
+ var records = [];
+ for (var i = 0; i < events.length && (!showMoreMessage || i < limit); i++) {
+ var evt = events[i];
+ var text = evt.getText();
+ var iconData = getIconData(evt);
+ var labelSize = this._frc.computeSize(text);
+ var record = {
+ text: text,
+ iconData: iconData,
+ labelSize: labelSize,
+ iconLeft: firstIconData.width + i * horizontalIncrement - iconData.width
+ };
+ record.labelLeft = firstIconData.width + i * horizontalIncrement + metrics.iconLabelGap;
+ record.top = totalLabelHeight;
+ records.push(record);
+
+ leftIconEdge = Math.min(leftIconEdge, record.iconLeft);
+ totalLabelHeight += labelSize.height;
+ totalLabelWidth = Math.max(totalLabelWidth, record.labelLeft + labelSize.width);
+ totalIconHeight = Math.max(totalIconHeight, record.top + iconData.height);
+ }
+ if (showMoreMessage) {
+ var moreMessage = String.substitute(moreMessageTemplate, [ events.length - limit ]);
+
+ var moreMessageLabelSize = this._frc.computeSize(moreMessage);
+ var moreMessageLabelLeft = firstIconData.width + (limit - 1) * horizontalIncrement + metrics.iconLabelGap;
+ var moreMessageLabelTop = totalLabelHeight;
+
+ totalLabelHeight += moreMessageLabelSize.height;
+ totalLabelWidth = Math.max(totalLabelWidth, moreMessageLabelLeft + moreMessageLabelSize.width);
+ }
+ totalLabelWidth += metrics.labelRightMargin;
+ totalLabelHeight += metrics.labelBottomMargin;
+ totalIconHeight += metrics.iconBottomMargin;
+
+ var anchorPixel = getPixelOffset(events[0].getStart());
+ var newTracks = [];
+
+ var trackCount = Math.ceil(Math.max(totalIconHeight, totalLabelHeight) / metrics.trackHeight);
+ var rightIconEdge = firstIconData.width + (events.length - 1) * horizontalIncrement;
+ for (var i = 0; i < trackCount; i++) {
+ newTracks.push({ start: leftIconEdge, end: rightIconEdge });
+ }
+ var labelTrackCount = Math.ceil(totalLabelHeight / metrics.trackHeight);
+ for (var i = 0; i < labelTrackCount; i++) {
+ var track = newTracks[i];
+ track.end = Math.max(track.end, totalLabelWidth);
+ }
+
+ var firstTrack = this._fitTracks(anchorPixel, newTracks);
+ var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+
+ var iconStackDiv = this._timeline.getDocument().createElement("div");
+ iconStackDiv.className = 'timeline-event-icon-stack';
+ iconStackDiv.style.position = "absolute";
+ iconStackDiv.style.overflow = "visible";
+ iconStackDiv.style.left = anchorPixel + "px";
+ iconStackDiv.style.top = verticalPixelOffset + "px";
+ iconStackDiv.style.width = rightIconEdge + "px";
+ iconStackDiv.style.height = totalIconHeight + "px";
+ iconStackDiv.innerHTML = "<div style='position: relative'></div>";
+ this._eventLayer.appendChild(iconStackDiv);
+
+ var self = this;
+ var onMouseOver = function(domEvt) {
+ try {
+ var n = parseInt(this.getAttribute("index"));
+ var childNodes = iconStackDiv.firstChild.childNodes;
+ for (var i = 0; i < childNodes.length; i++) {
+ var child = childNodes[i];
+ if (i == n) {
+ child.style.zIndex = childNodes.length;
+ } else {
+ child.style.zIndex = childNodes.length - i;
+ }
+ }
+ } catch (e) {
+ }
+ };
+ var paintEvent = function(index) {
+ var record = records[index];
+ var evt = events[index];
+ var tooltip = evt.getProperty("tooltip") || evt.getText();
+
+ var labelElmtData = self._paintEventLabel(
+ { tooltip: tooltip },
+ { text: record.text },
+ anchorPixel + record.labelLeft,
+ verticalPixelOffset + record.top,
+ record.labelSize.width,
+ record.labelSize.height,
+ theme
+ );
+ labelElmtData.elmt.setAttribute("index", index);
+ labelElmtData.elmt.onmouseover = onMouseOver;
+
+ var img = SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
+ var iconDiv = self._timeline.getDocument().createElement("div");
+ iconDiv.className = 'timeline-event-icon' + ("className" in record.iconData ? (" " + record.iconData.className) : "");
+ iconDiv.style.left = record.iconLeft + "px";
+ iconDiv.style.top = record.top + "px";
+ iconDiv.style.zIndex = (records.length - index);
+ iconDiv.appendChild(img);
+ iconDiv.setAttribute("index", index);
+ iconDiv.onmouseover = onMouseOver;
+
+ iconStackDiv.firstChild.appendChild(iconDiv);
+
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(iconDiv, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ self._eventIdToElmt[evt.getID()] = iconDiv;
+ };
+ for (var i = 0; i < records.length; i++) {
+ paintEvent(i);
+ }
+
+ if (showMoreMessage) {
+ var moreEvents = events.slice(limit);
+ var moreMessageLabelElmtData = this._paintEventLabel(
+ { tooltip: moreMessage },
+ { text: moreMessage },
+ anchorPixel + moreMessageLabelLeft,
+ verticalPixelOffset + moreMessageLabelTop,
+ moreMessageLabelSize.width,
+ moreMessageLabelSize.height,
+ theme
+ );
+
+ var moreMessageClickHandler = function(elmt, domEvt, target) {
+ return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt, domEvt, moreEvents);
+ };
+ SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt, "mousedown", moreMessageClickHandler);
+
+ for (var i = 0; i < moreEvents.length; i++) {
+ this._eventIdToElmt[moreEvents[i].getID()] = moreMessageLabelElmtData.elmt;
+ }
+ }
+ //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ latestStart: evt.getLatestStart(),
+ earliestEnd: evt.getEarliestEnd(),
+ color: evt.getColor() || evt.getTextColor(),
+ isInstant: true
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ tapeData,
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ color: evt.getColor() || evt.getTextColor(),
+ isInstant: false
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getLatestStart(),
+ commonData,
+ tapeData,
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ latestStart: evt.getLatestStart(),
+ earliestEnd: evt.getEarliestEnd(),
+ color: evt.getColor() || evt.getTextColor(),
+ isInstant: false
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getLatestStart(),
+ commonData,
+ tapeData,
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel = function(
+ anchorDate,
+ commonData,
+ tapeData,
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+) {
+ var band = this._band;
+ var getPixelOffset = function(date) {
+ return Math.round(band.dateToPixelOffset(date));
+ };
+
+ var anchorPixel = getPixelOffset(anchorDate);
+ var newTracks = [];
+
+ var tapeHeightOccupied = 0; // how many pixels (vertically) the tape occupies, including bottom margin
+ var tapeTrackCount = 0; // how many tracks the tape takes up, usually just 1
+ var tapeLastTrackExtraSpace = 0; // on the last track that the tape occupies, how many pixels are left (for icon and label to occupy as well)
+ if (tapeData != null) {
+ tapeHeightOccupied = metrics.tapeHeight + metrics.tapeBottomMargin;
+ tapeTrackCount = Math.ceil(metrics.tapeHeight / metrics.trackHeight);
+
+ var tapeEndPixelOffset = getPixelOffset(tapeData.end) - anchorPixel;
+ var tapeStartPixelOffset = getPixelOffset(tapeData.start) - anchorPixel;
+
+ for (var t = 0; t < tapeTrackCount; t++) {
+ newTracks.push({ start: tapeStartPixelOffset, end: tapeEndPixelOffset });
+ }
+
+ tapeLastTrackExtraSpace = metrics.trackHeight - (tapeHeightOccupied % metrics.tapeHeight);
+ }
+
+ var iconStartPixelOffset = 0; // where the icon starts compared to the anchor pixel;
+ // this can be negative if the icon is center-aligned around the anchor
+ var iconHorizontalSpaceOccupied = 0; // how many pixels the icon take up from the anchor pixel,
+ // including the gap between the icon and the label
+ if (iconData != null) {
+ if ("iconAlign" in iconData && iconData.iconAlign == "center") {
+ iconStartPixelOffset = -Math.floor(iconData.width / 2);
+ }
+ iconHorizontalSpaceOccupied = iconStartPixelOffset + iconData.width + metrics.iconLabelGap;
+
+ if (tapeTrackCount > 0) {
+ newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, iconHorizontalSpaceOccupied);
+ }
+
+ var iconHeight = iconData.height + metrics.iconBottomMargin + tapeLastTrackExtraSpace;
+ while (iconHeight > 0) {
+ newTracks.push({ start: iconStartPixelOffset, end: iconHorizontalSpaceOccupied });
+ iconHeight -= metrics.trackHeight;
+ }
+ }
+
+ var text = labelData.text;
+ var labelSize = this._frc.computeSize(text);
+ var labelHeight = labelSize.height + metrics.labelBottomMargin + tapeLastTrackExtraSpace;
+ var labelEndPixelOffset = iconHorizontalSpaceOccupied + labelSize.width + metrics.labelRightMargin;
+ if (tapeTrackCount > 0) {
+ newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, labelEndPixelOffset);
+ }
+ for (var i = 0; labelHeight > 0; i++) {
+ if (tapeTrackCount + i < newTracks.length) {
+ var track = newTracks[tapeTrackCount + i];
+ track.end = labelEndPixelOffset;
+ } else {
+ newTracks.push({ start: 0, end: labelEndPixelOffset });
+ }
+ labelHeight -= metrics.trackHeight;
+ }
+
+ /*
+ * Try to fit the new track on top of the existing tracks, then
+ * render the various elements.
+ */
+ var firstTrack = this._fitTracks(anchorPixel, newTracks);
+ var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+ var result = {};
+
+ result.labelElmtData = this._paintEventLabel(
+ commonData,
+ labelData,
+ anchorPixel + iconHorizontalSpaceOccupied,
+ verticalPixelOffset + tapeHeightOccupied,
+ labelSize.width,
+ labelSize.height,
+ theme
+ );
+
+ if (tapeData != null) {
+ if ("latestStart" in tapeData || "earliestEnd" in tapeData) {
+ result.impreciseTapeElmtData = this._paintEventTape(
+ commonData,
+ tapeData,
+ metrics.tapeHeight,
+ verticalPixelOffset,
+ getPixelOffset(tapeData.start),
+ getPixelOffset(tapeData.end),
+ theme.event.duration.impreciseColor,
+ theme.event.duration.impreciseOpacity,
+ metrics,
+ theme
+ );
+ }
+ if (!tapeData.isInstant && "start" in tapeData && "end" in tapeData) {
+ result.tapeElmtData = this._paintEventTape(
+ commonData,
+ tapeData,
+ metrics.tapeHeight,
+ verticalPixelOffset,
+ anchorPixel,
+ getPixelOffset("earliestEnd" in tapeData ? tapeData.earliestEnd : tapeData.end),
+ tapeData.color,
+ 100,
+ metrics,
+ theme
+ );
+ }
+ }
+
+ if (iconData != null) {
+ result.iconElmtData = this._paintEventIcon(
+ commonData,
+ iconData,
+ verticalPixelOffset + tapeHeightOccupied,
+ anchorPixel + iconStartPixelOffset,
+ metrics,
+ theme
+ );
+ }
+ //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ return result;
+};
+
+Timeline.CompactEventPainter.prototype._fitTracks = function(anchorPixel, newTracks) {
+ var firstTrack;
+ for (firstTrack = 0; firstTrack < this._tracks.length; firstTrack++) {
+ var fit = true;
+ for (var j = 0; j < newTracks.length && (firstTrack + j) < this._tracks.length; j++) {
+ var existingTrack = this._tracks[firstTrack + j];
+ var newTrack = newTracks[j];
+ if (anchorPixel + newTrack.start < existingTrack) {
+ fit = false;
+ break;
+ }
+ }
+
+ if (fit) {
+ break;
+ }
+ }
+ for (var i = 0; i < newTracks.length; i++) {
+ this._tracks[firstTrack + i] = anchorPixel + newTracks[i].end;
+ }
+
+ return firstTrack;
+};
+
+
+Timeline.CompactEventPainter.prototype._paintEventIcon = function(commonData, iconData, top, left, metrics, theme) {
+ var img = SimileAjax.Graphics.createTranslucentImage(iconData.url);
+ var iconDiv = this._timeline.getDocument().createElement("div");
+ iconDiv.className = 'timeline-event-icon' + ("className" in iconData ? (" " + iconData.className) : "");
+ iconDiv.style.left = left + "px";
+ iconDiv.style.top = top + "px";
+ iconDiv.appendChild(img);
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ iconDiv.title = commonData.tooltip;
+ }
+
+ this._eventLayer.appendChild(iconDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: metrics.iconWidth,
+ height: metrics.iconHeight,
+ elmt: iconDiv
+ };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventLabel = function(commonData, labelData, left, top, width, height, theme) {
+ var doc = this._timeline.getDocument();
+
+ var labelDiv = doc.createElement("div");
+ labelDiv.className = 'timeline-event-label';
+
+ labelDiv.style.left = left + "px";
+ labelDiv.style.width = (width + 1) + "px";
+ labelDiv.style.top = top + "px";
+ labelDiv.innerHTML = labelData.text;
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ labelDiv.title = commonData.tooltip;
+ }
+ if ("color" in labelData && typeof labelData.color == "string") {
+ labelDiv.style.color = labelData.color;
+ }
+ if ("className" in labelData && typeof labelData.className == "string") {
+ labelDiv.className += ' ' + labelData.className;
+ }
+
+ this._eventLayer.appendChild(labelDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: labelDiv
+ };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventTape = function(
+ commonData, tapeData, height, top, startPixel, endPixel, color, opacity, metrics, theme) {
+
+ var width = endPixel - startPixel;
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.className = "timeline-event-tape"
+
+ tapeDiv.style.left = startPixel + "px";
+ tapeDiv.style.top = top + "px";
+ tapeDiv.style.width = width + "px";
+ tapeDiv.style.height = height + "px";
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ tapeDiv.title = commonData.tooltip;
+ }
+ if (color != null && typeof tapeData.color == "string") {
+ tapeDiv.style.backgroundColor = color;
+ }
+
+ if ("backgroundImage" in tapeData && typeof tapeData.backgroundImage == "string") {
+ tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
+ tapeDiv.style.backgroundRepeat =
+ ("backgroundRepeat" in tapeData && typeof tapeData.backgroundRepeat == "string")
+ ? tapeData.backgroundRepeat : 'repeat';
+ }
+
+ SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ if ("className" in tapeData && typeof tapeData.className == "string") {
+ tapeDiv.className += ' ' + tapeData.className;
+ }
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: startPixel,
+ top: top,
+ width: width,
+ height: height,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.CompactEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var eventTheme = theme.event;
+
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 2) + "px";
+ div.style.width = (dimensions.width + 4) + "px";
+ div.style.top = (dimensions.top - 2) + "px";
+ div.style.height = (dimensions.height + 4) + "px";
+// div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+};
+
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent = function(icon, domEvt, events) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ events
+ );
+
+ var ids = [];
+ for (var i = 0; i < events.length; i++) {
+ ids.push(events[i].getID());
+ }
+ this._fireOnSelect(ids);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ [evt]
+ );
+ this._fireOnSelect([evt.getID()]);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = SimileAjax.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, [evt]);
+ this._fireOnSelect([evt.getID()]);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype.showBubble = function(evt) {
+ var elmt = this._eventIdToElmt[evt.getID()];
+ if (elmt) {
+ var c = SimileAjax.DOM.getPageCoordinates(elmt);
+ this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, [evt]);
+ }
+};
+
+Timeline.CompactEventPainter.prototype._showBubble = function(x, y, evts) {
+ var div = document.createElement("div");
+
+ evts = ("fillInfoBubble" in evts) ? [evts] : evts;
+ for (var i = 0; i < evts.length; i++) {
+ var div2 = document.createElement("div");
+ div.appendChild(div2);
+
+ evts[i].fillInfoBubble(div2, this._params.theme, this._band.getLabeller());
+ }
+
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, this._params.theme.event.bubble.width);
+};
+
+Timeline.CompactEventPainter.prototype._fireOnSelect = function(eventIDs) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ this._onSelectListeners[i](eventIDs);
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/decorators.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/decorators.js
new file mode 100644
index 00000000..1646418b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/decorators.js
@@ -0,0 +1,184 @@
+/*==================================================
+ * Span Highlight Decorator
+ *==================================================
+ */
+
+Timeline.SpanHighlightDecorator = function(params) {
+ // When evaluating params, test against null. Not "p in params". Testing against
+ // null enables caller to explicitly request the default. Testing against "in" means
+ // that the param has to be ommitted to get the default.
+ this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+ this._startDate = (typeof params.startDate == "string") ?
+ this._unit.parseFromObject(params.startDate) : params.startDate;
+ this._endDate = (typeof params.endDate == "string") ?
+ this._unit.parseFromObject(params.endDate) : params.endDate;
+ this._startLabel = params.startLabel != null ? params.startLabel : ""; // not null!
+ this._endLabel = params.endLabel != null ? params.endLabel : ""; // not null!
+ this._color = params.color;
+ this._cssClass = params.cssClass != null ? params.cssClass : null;
+ this._opacity = params.opacity != null ? params.opacity : 100;
+ // Default z is 10, behind everything but background grid.
+ // If inFront, then place just behind events, in front of everything else
+ this._zIndex = (params.inFront != null && params.inFront) ? 113 : 10;
+};
+
+Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._layerDiv = null;
+};
+
+Timeline.SpanHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(this._zIndex);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._unit.compare(this._startDate, maxDate) < 0 &&
+ this._unit.compare(this._endDate, minDate) > 0) {
+
+ minDate = this._unit.later(minDate, this._startDate);
+ maxDate = this._unit.earlier(maxDate, this._endDate);
+
+ var minPixel = this._band.dateToPixelOffset(minDate);
+ var maxPixel = this._band.dateToPixelOffset(maxDate);
+
+ var doc = this._timeline.getDocument();
+
+ var createTable = function() {
+ var table = doc.createElement("table");
+ table.insertRow(0).insertCell(0);
+ return table;
+ };
+
+ var div = doc.createElement("div");
+ div.className='timeline-highlight-decorator'
+ if(this._cssClass) {
+ div.className += ' ' + this._cssClass;
+ }
+ if(this._color != null) {
+ div.style.backgroundColor = this._color;
+ }
+ if (this._opacity < 100) {
+ SimileAjax.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ var tableStartLabel = createTable();
+ tableStartLabel.className = 'timeline-highlight-label timeline-highlight-label-start'
+ var tdStart = tableStartLabel.rows[0].cells[0]
+ tdStart.innerHTML = this._startLabel;
+ if (this._cssClass) {
+ tdStart.className = 'label_' + this._cssClass;
+ }
+ this._layerDiv.appendChild(tableStartLabel);
+
+ var tableEndLabel = createTable();
+ tableEndLabel.className = 'timeline-highlight-label timeline-highlight-label-end'
+ var tdEnd = tableEndLabel.rows[0].cells[0]
+ tdEnd.innerHTML = this._endLabel;
+ if (this._cssClass) {
+ tdEnd.className = 'label_' + this._cssClass;
+ }
+ this._layerDiv.appendChild(tableEndLabel);
+
+ if (this._timeline.isHorizontal()){
+ div.style.left = minPixel + "px";
+ div.style.width = (maxPixel - minPixel) + "px";
+
+ tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px";
+ tableStartLabel.style.width = (this._startLabel.length) + "em";
+
+ tableEndLabel.style.left = maxPixel + "px";
+ tableEndLabel.style.width = (this._endLabel.length) + "em";
+
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = (maxPixel - minPixel) + "px";
+
+ tableStartLabel.style.bottom = minPixel + "px";
+ tableStartLabel.style.height = "1.5px";
+
+ tableEndLabel.style.top = maxPixel + "px";
+ tableEndLabel.style.height = "1.5px";
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Point Highlight Decorator
+ *==================================================
+ */
+
+Timeline.PointHighlightDecorator = function(params) {
+ this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+ this._date = (typeof params.date == "string") ?
+ this._unit.parseFromObject(params.date) : params.date;
+ this._width = params.width != null ? params.width : 10;
+ // Since the width is used to calculate placements (see minPixel, below), we
+ // specify width here, not in css.
+ this._color = params.color;
+ this._cssClass = params.cssClass != null ? params.cssClass : '';
+ this._opacity = params.opacity != null ? params.opacity : 100;
+};
+
+Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+ this._layerDiv = null;
+};
+
+Timeline.PointHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(10);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._unit.compare(this._date, maxDate) < 0 &&
+ this._unit.compare(this._date, minDate) > 0) {
+
+ var pixel = this._band.dateToPixelOffset(this._date);
+ var minPixel = pixel - Math.round(this._width / 2);
+
+ var doc = this._timeline.getDocument();
+
+ var div = doc.createElement("div");
+ div.className='timeline-highlight-point-decorator';
+ div.className += ' ' + this._cssClass;
+
+ if(this._color != null) {
+ div.style.backgroundColor = this._color;
+ }
+ if (this._opacity < 100) {
+ SimileAjax.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ if (this._timeline.isHorizontal()) {
+ div.style.left = minPixel + "px";
+ div.style.width = this._width + "px";
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = this._width + "px";
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.PointHighlightDecorator.prototype.softPaint = function() {
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/detailed-painter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/detailed-painter.js
new file mode 100644
index 00000000..3a3368bf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/detailed-painter.js
@@ -0,0 +1,691 @@
+/*==================================================
+ * Detailed Event Painter
+ *==================================================
+ */
+
+// Note: a number of features from original-painter
+// are not yet implemented in detailed painter.
+// Eg classname, id attributes for icons, labels, tapes
+
+Timeline.DetailedEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
+
+ this._eventIdToElmt = {};
+};
+
+Timeline.DetailedEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backLayer = null;
+ this._eventLayer = null;
+ this._lineLayer = null;
+ this._highlightLayer = null;
+
+ this._eventIdToElmt = null;
+};
+
+Timeline.DetailedEventPainter.prototype.getType = function() {
+ return 'detailed';
+};
+
+Timeline.DetailedEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.DetailedEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._eventIdToElmt = {};
+ this._prepareForPainting();
+
+ var eventTheme = this._params.theme.event;
+ var trackHeight = Math.max(eventTheme.track.height, this._frc.getLineHeight());
+ var metrics = {
+ trackOffset: Math.round(this._band.getViewWidth() / 2 - trackHeight / 2),
+ trackHeight: trackHeight,
+ trackGap: eventTheme.track.gap,
+ trackIncrement: trackHeight + eventTheme.track.gap,
+ icon: eventTheme.instant.icon,
+ iconWidth: eventTheme.instant.iconWidth,
+ iconHeight: eventTheme.instant.iconHeight,
+ labelWidth: eventTheme.label.width
+ }
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+ // update the band object for max number of tracks in this section of the ether
+ this._band.updateEventTrackInfo(this._lowerTracks.length + this._upperTracks.length,
+ metrics.trackIncrement);
+};
+
+Timeline.DetailedEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.DetailedEventPainter.prototype._prepareForPainting = function() {
+ var band = this._band;
+
+ if (this._backLayer == null) {
+ this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+ this._backLayer.style.visibility = "hidden";
+
+ var eventLabelPrototype = document.createElement("span");
+ eventLabelPrototype.className = "timeline-event-label";
+ this._backLayer.appendChild(eventLabelPrototype);
+ this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+ }
+ this._frc.update();
+ this._lowerTracks = [];
+ this._upperTracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._lineLayer != null) {
+ band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+ this._lineLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.DetailedEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.DetailedEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelSize = this._frc.computeSize(text);
+ var iconTrack = this._findFreeTrackForSolid(iconRightEdge, startPixel);
+ var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelTrack = iconTrack;
+
+ var iconTrackData = this._getTrackData(iconTrack);
+ if (Math.min(iconTrackData.solid, iconTrackData.text) >= labelLeft + labelSize.width) { // label on the same track, to the right of icon
+ iconTrackData.solid = iconLeftEdge;
+ iconTrackData.text = labelLeft;
+ } else { // label on a different track, below icon
+ iconTrackData.solid = iconLeftEdge;
+
+ labelLeft = startPixel + theme.event.label.offsetFromLine;
+ labelTrack = this._findFreeTrackForText(iconTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = iconLeftEdge;
+
+ this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+ }
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelSize = this._frc.computeSize(text);
+ var iconTrack = this._findFreeTrackForSolid(endPixel, startPixel);
+
+ var tapeElmtData = this._paintEventTape(evt, iconTrack, startPixel, endPixel,
+ theme.event.instant.impreciseColor, theme.event.instant.impreciseOpacity, metrics, theme);
+ var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+ var iconTrackData = this._getTrackData(iconTrack);
+ iconTrackData.solid = iconLeftEdge;
+
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelRight = labelLeft + labelSize.width;
+ var labelTrack;
+ if (labelRight < endPixel) {
+ labelTrack = iconTrack;
+ } else {
+ labelLeft = startPixel + theme.event.label.offsetFromLine;
+ labelRight = labelLeft + labelSize.width;
+
+ labelTrack = this._findFreeTrackForText(iconTrack, labelRight, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = iconLeftEdge;
+
+ this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+ }
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var labelSize = this._frc.computeSize(text);
+ var tapeTrack = this._findFreeTrackForSolid(endPixel);
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ var tapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel, color, 100, metrics, theme);
+
+ var tapeTrackData = this._getTrackData(tapeTrack);
+ tapeTrackData.solid = startPixel;
+
+ var labelLeft = startPixel + theme.event.label.offsetFromLine;
+ var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = startPixel - 2;
+
+ this._paintEventLine(evt, startPixel, tapeTrack, labelTrack, metrics, theme);
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var latestStartDate = evt.getLatestStart();
+ var endDate = evt.getEnd();
+ var earliestEndDate = evt.getEarliestEnd();
+
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+ var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+ var labelSize = this._frc.computeSize(text);
+ var tapeTrack = this._findFreeTrackForSolid(endPixel);
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ var impreciseTapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel,
+ theme.event.duration.impreciseColor, theme.event.duration.impreciseOpacity, metrics, theme);
+ var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel, color, 100, metrics, theme);
+
+ var tapeTrackData = this._getTrackData(tapeTrack);
+ tapeTrackData.solid = startPixel;
+
+ var labelLeft = latestStartPixel + theme.event.label.offsetFromLine;
+ var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = latestStartPixel - 2; });
+ this._getTrackData(labelTrack).text = latestStartPixel - 2;
+
+ this._paintEventLine(evt, latestStartPixel, tapeTrack, labelTrack, metrics, theme);
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid = function(solidEdge, softEdge) {
+ for (var i = 0; true; i++) {
+ if (i < this._lowerTracks.length) {
+ var t = this._lowerTracks[i];
+ if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+ return i;
+ }
+ } else {
+ this._lowerTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+
+ return i;
+ }
+
+ if (i < this._upperTracks.length) {
+ var t = this._upperTracks[i];
+ if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+ return -1 - i;
+ }
+ } else {
+ this._upperTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+
+ return -1 - i;
+ }
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText = function(fromTrack, edge, occupiedTrackVisitor) {
+ var extendUp;
+ var index;
+ var firstIndex;
+ var result;
+
+ if (fromTrack < 0) {
+ extendUp = true;
+ firstIndex = -fromTrack;
+
+ index = this._findFreeUpperTrackForText(firstIndex, edge);
+ result = -1 - index;
+ } else if (fromTrack > 0) {
+ extendUp = false;
+ firstIndex = fromTrack + 1;
+
+ index = this._findFreeLowerTrackForText(firstIndex, edge);
+ result = index;
+ } else {
+ var upIndex = this._findFreeUpperTrackForText(0, edge);
+ var downIndex = this._findFreeLowerTrackForText(1, edge);
+
+ if (downIndex - 1 <= upIndex) {
+ extendUp = false;
+ firstIndex = 1;
+ index = downIndex;
+ result = index;
+ } else {
+ extendUp = true;
+ firstIndex = 0;
+ index = upIndex;
+ result = -1 - index;
+ }
+ }
+
+ if (extendUp) {
+ if (index == this._upperTracks.length) {
+ this._upperTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+ }
+ for (var i = firstIndex; i < index; i++) {
+ occupiedTrackVisitor(this._upperTracks[i]);
+ }
+ } else {
+ if (index == this._lowerTracks.length) {
+ this._lowerTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+ }
+ for (var i = firstIndex; i < index; i++) {
+ occupiedTrackVisitor(this._lowerTracks[i]);
+ }
+ }
+ return result;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText = function(index, edge) {
+ for (; index < this._lowerTracks.length; index++) {
+ var t = this._lowerTracks[index];
+ if (Math.min(t.solid, t.text) >= edge) {
+ break;
+ }
+ }
+ return index;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText = function(index, edge) {
+ for (; index < this._upperTracks.length; index++) {
+ var t = this._upperTracks[index];
+ if (Math.min(t.solid, t.text) >= edge) {
+ break;
+ }
+ }
+ return index;
+};
+
+Timeline.DetailedEventPainter.prototype._getTrackData = function(index) {
+ return (index < 0) ? this._upperTracks[-index - 1] : this._lowerTracks[index];
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLine = function(evt, left, startTrack, endTrack, metrics, theme) {
+ var top = Math.round(metrics.trackOffset + startTrack * metrics.trackIncrement + metrics.trackHeight / 2);
+ var height = Math.round(Math.abs(endTrack - startTrack) * metrics.trackIncrement);
+
+ var lineStyle = "1px solid " + theme.event.label.lineColor;
+ var lineDiv = this._timeline.getDocument().createElement("div");
+ lineDiv.style.position = "absolute";
+ lineDiv.style.left = left + "px";
+ lineDiv.style.width = theme.event.label.offsetFromLine + "px";
+ lineDiv.style.height = height + "px";
+ if (startTrack > endTrack) {
+ lineDiv.style.top = (top - height) + "px";
+ lineDiv.style.borderTop = lineStyle;
+ } else {
+ lineDiv.style.top = top + "px";
+ lineDiv.style.borderBottom = lineStyle;
+ }
+ lineDiv.style.borderLeft = lineStyle;
+ this._lineLayer.appendChild(lineDiv);
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme) {
+ var icon = evt.getIcon();
+ icon = icon != null ? icon : metrics.icon;
+
+ var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+ var top = Math.round(middle - metrics.iconHeight / 2);
+
+ var img = SimileAjax.Graphics.createTranslucentImage(icon);
+ var iconDiv = this._timeline.getDocument().createElement("div");
+ iconDiv.style.position = "absolute";
+ iconDiv.style.left = left + "px";
+ iconDiv.style.top = top + "px";
+ iconDiv.appendChild(img);
+ iconDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ iconDiv.title = evt._title
+
+ this._eventLayer.appendChild(iconDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: metrics.iconWidth,
+ height: metrics.iconHeight,
+ elmt: iconDiv
+ };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width, height, theme) {
+ var doc = this._timeline.getDocument();
+
+ var labelBackgroundDiv = doc.createElement("div");
+ labelBackgroundDiv.style.position = "absolute";
+ labelBackgroundDiv.style.left = left + "px";
+ labelBackgroundDiv.style.width = width + "px";
+ labelBackgroundDiv.style.top = top + "px";
+ labelBackgroundDiv.style.height = height + "px";
+ labelBackgroundDiv.style.backgroundColor = theme.event.label.backgroundColor;
+ SimileAjax.Graphics.setOpacity(labelBackgroundDiv, theme.event.label.backgroundOpacity);
+ this._eventLayer.appendChild(labelBackgroundDiv);
+
+ var labelDiv = doc.createElement("div");
+ labelDiv.style.position = "absolute";
+ labelDiv.style.left = left + "px";
+ labelDiv.style.width = width + "px";
+ labelDiv.style.top = top + "px";
+ labelDiv.innerHTML = text;
+ labelDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ labelDiv.title = evt._title;
+
+ var color = evt.getTextColor();
+ if (color == null) {
+ color = evt.getColor();
+ }
+ if (color != null) {
+ labelDiv.style.color = color;
+ }
+
+ this._eventLayer.appendChild(labelDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: labelDiv
+ };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventTape = function(
+ evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme) {
+
+ var tapeWidth = endPixel - startPixel;
+ var tapeHeight = theme.event.tape.height;
+ var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+ var top = Math.round(middle - tapeHeight / 2);
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.style.position = "absolute";
+ tapeDiv.style.left = startPixel + "px";
+ tapeDiv.style.width = tapeWidth + "px";
+ tapeDiv.style.top = top + "px";
+ tapeDiv.style.height = tapeHeight + "px";
+ tapeDiv.style.backgroundColor = color;
+ tapeDiv.style.overflow = "hidden";
+ tapeDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ tapeDiv.title = evt._title;
+
+ SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: startPixel,
+ top: top,
+ width: tapeWidth,
+ height: tapeHeight,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.DetailedEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var eventTheme = theme.event;
+
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 2) + "px";
+ div.style.width = (dimensions.width + 4) + "px";
+ div.style.top = (dimensions.top - 2) + "px";
+ div.style.height = (dimensions.height + 4) + "px";
+ div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ evt
+ );
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = SimileAjax.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, evt);
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.DetailedEventPainter.prototype.showBubble = function(evt) {
+ var elmt = this._eventIdToElmt[evt.getID()];
+ if (elmt) {
+ var c = SimileAjax.DOM.getPageCoordinates(elmt);
+ this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._showBubble = function(x, y, evt) {
+ var div = document.createElement("div");
+ var themeBubble = this._params.theme.event.bubble;
+ evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
+ themeBubble.width, null, themeBubble.maxHeight);
+};
+
+Timeline.DetailedEventPainter.prototype._fireOnSelect = function(eventID) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ this._onSelectListeners[i](eventID);
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ether-painters.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ether-painters.js
new file mode 100644
index 00000000..e08a025d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ether-painters.js
@@ -0,0 +1,582 @@
+/*==================================================
+ * Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.GregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._unit = params.unit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.GregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GregorianEtherPainter.prototype.setHighlight = function(startDate, endDate, orthogonalOffset, orthogonalExtent) {
+ this._highlight.position(startDate, endDate, orthogonalOffset, orthogonalExtent);
+}
+
+Timeline.GregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ SimileAjax.DateTime.roundDownToInterval(minDate, this._unit, timeZone, this._multiple, this._theme.firstDayOfWeek);
+
+ var p = this;
+ var incrementDate = function(date) {
+ for (var i = 0; i < p._multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, p._unit);
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, this._unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.GregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+ if (netIntervalChange != 0) {
+ this._unit += netIntervalChange;
+ }
+};
+
+
+/*==================================================
+ * Hot Zone Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.HotZoneGregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+
+ this._zones = [{
+ startTime: Number.NEGATIVE_INFINITY,
+ endTime: Number.POSITIVE_INFINITY,
+ unit: params.unit,
+ multiple: 1
+ }];
+ for (var i = 0; i < params.zones.length; i++) {
+ var zone = params.zones[i];
+ var zoneStart = SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
+ var zoneEnd = SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
+
+ for (var j = 0; j < this._zones.length && zoneEnd > zoneStart; j++) {
+ var zone2 = this._zones[j];
+
+ if (zoneStart < zone2.endTime) {
+ if (zoneStart > zone2.startTime) {
+ this._zones.splice(j, 0, {
+ startTime: zone2.startTime,
+ endTime: zoneStart,
+ unit: zone2.unit,
+ multiple: zone2.multiple
+ });
+ j++;
+
+ zone2.startTime = zoneStart;
+ }
+
+ if (zoneEnd < zone2.endTime) {
+ this._zones.splice(j, 0, {
+ startTime: zoneStart,
+ endTime: zoneEnd,
+ unit: zone.unit,
+ multiple: (zone.multiple) ? zone.multiple : 1
+ });
+ j++;
+
+ zone2.startTime = zoneEnd;
+ zoneStart = zoneEnd;
+ } else {
+ zone2.multiple = zone.multiple;
+ zone2.unit = zone.unit;
+ zoneStart = zone2.endTime;
+ }
+ } // else, try the next existing zone
+ }
+ }
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className ='timeline-ether-bg';
+ //this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ var p = this;
+ var incrementDate = function(date, zone) {
+ for (var i = 0; i < zone.multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, zone.unit);
+ }
+ };
+
+ var zStart = 0;
+ while (zStart < this._zones.length) {
+ if (minDate.getTime() < this._zones[zStart].endTime) {
+ break;
+ }
+ zStart++;
+ }
+ var zEnd = this._zones.length - 1;
+ while (zEnd >= 0) {
+ if (maxDate.getTime() > this._zones[zEnd].startTime) {
+ break;
+ }
+ zEnd--;
+ }
+
+ for (var z = zStart; z <= zEnd; z++) {
+ var zone = this._zones[z];
+
+ var minDate2 = new Date(Math.max(minDate.getTime(), zone.startTime));
+ var maxDate2 = new Date(Math.min(maxDate.getTime(), zone.endTime));
+
+ SimileAjax.DateTime.roundDownToInterval(minDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+ SimileAjax.DateTime.roundUpToInterval(maxDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+
+ while (minDate2.getTime() < maxDate2.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate2, labeller, zone.unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate2, zone);
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+ if (netIntervalChange != 0) {
+ for (var i = 0; i < this._zones.length; ++i) {
+ if (this._zones[i]) {
+ this._zones[i].unit += netIntervalChange;
+ }
+ }
+ }
+};
+
+/*==================================================
+ * Year Count Ether Painter
+ *==================================================
+ */
+
+Timeline.YearCountEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.YearCountEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.YearCountEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.YearCountEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(this._startDate.getTime());
+ var maxDate = this._band.getMaxDate();
+ var yearDiff = this._band.getMinDate().getUTCFullYear() - this._startDate.getUTCFullYear();
+ minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear() - yearDiff % this._multiple);
+
+ var p = this;
+ var incrementDate = function(date) {
+ for (var i = 0; i < p._multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, SimileAjax.DateTime.YEAR);
+ }
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var diff = date.getUTCFullYear() - p._startDate.getUTCFullYear();
+ return {
+ text: diff,
+ emphasized: diff == 0
+ };
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.YearCountEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Quarterly Ether Painter
+ *==================================================
+ */
+
+Timeline.QuarterlyEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(0);
+ var maxDate = this._band.getMaxDate();
+
+ minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(), this._band.getMinDate().getUTCFullYear()));
+ minDate.setUTCMonth(this._startDate.getUTCMonth());
+
+ var p = this;
+ var incrementDate = function(date) {
+ date.setUTCMonth(date.getUTCMonth() + 3);
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var quarters = (4 + (date.getUTCMonth() - p._startDate.getUTCMonth()) / 3) % 4;
+ if (quarters != 0) {
+ return { text: "Q" + (quarters + 1), emphasized: false };
+ } else {
+ return { text: "Y" + (date.getUTCFullYear() - p._startDate.getUTCFullYear() + 1), emphasized: true };
+ }
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Ether Interval Marker Layout
+ *==================================================
+ */
+
+Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+ var weekendTheme = theme.ether.interval.weekend;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+ var day = SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine && unit != SimileAjax.DateTime.WEEK) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.className = "timeline-ether-lines";
+
+ if (lineTheme.opacity < 100) {
+ SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ //divLine.className += " timeline-ether-lines-vertical";
+ divLine.style.left = offset + "px";
+ } else {
+ //divLine.className += " timeline-ether-lines-horizontal";
+ divLine.style.top = offset + "px";
+ }
+ lineDiv.appendChild(divLine);
+ }
+ if (unit == SimileAjax.DateTime.WEEK) {
+ var firstDayOfWeek = theme.firstDayOfWeek;
+
+ var saturday = new Date(date.getTime() + (6 - firstDayOfWeek - 7) * day);
+ var monday = new Date(saturday.getTime() + 2 * day);
+
+ var saturdayPixel = Math.round(band.dateToPixelOffset(saturday));
+ var mondayPixel = Math.round(band.dateToPixelOffset(monday));
+ var length = Math.max(1, mondayPixel - saturdayPixel);
+
+ var divWeekend = timeline.getDocument().createElement("div");
+ divWeekend.className = 'timeline-ether-weekends'
+
+ if (weekendTheme.opacity < 100) {
+ SimileAjax.Graphics.setOpacity(divWeekend, weekendTheme.opacity);
+ }
+
+ if (horizontal) {
+ divWeekend.style.left = saturdayPixel + "px";
+ divWeekend.style.width = length + "px";
+ } else {
+ divWeekend.style.top = saturdayPixel + "px";
+ divWeekend.style.height = length + "px";
+ }
+ lineDiv.appendChild(divWeekend);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+
+
+
+ div.className = 'timeline-date-label'
+ if(label.emphasized) div.className += ' timeline-date-label-em'
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+};
+
+/*==================================================
+ * Ether Highlight Layout
+ *==================================================
+ */
+
+Timeline.EtherHighlight = function(timeline, band, theme, backgroundLayer) {
+ var horizontal = timeline.isHorizontal();
+
+ this._highlightDiv = null;
+ this._createHighlightDiv = function() {
+ if (this._highlightDiv == null) {
+ this._highlightDiv = timeline.getDocument().createElement("div");
+ this._highlightDiv.setAttribute("name", "ether-highlight"); // for debugging
+ this._highlightDiv.className = 'timeline-ether-highlight'
+
+ var opacity = theme.ether.highlightOpacity;
+ if (opacity < 100) {
+ SimileAjax.Graphics.setOpacity(this._highlightDiv, opacity);
+ }
+
+ backgroundLayer.appendChild(this._highlightDiv);
+ }
+ }
+
+ this.position = function(startDate, endDate, orthogonalOffset, orthogonalExtent) {
+ orthogonalOffset = orthogonalOffset || 0;
+ orthogonalExtent = orthogonalExtent || 1.0;
+
+ this._createHighlightDiv();
+
+ var startPixel = Math.round(band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(band.dateToPixelOffset(endDate));
+ var length = Math.max(endPixel - startPixel, 3);
+ var totalWidth = band.getViewWidth() - 4;
+ if (horizontal) {
+ this._highlightDiv.style.left = startPixel + "px";
+ this._highlightDiv.style.width = length + "px";
+ this._highlightDiv.style.top = Math.round(orthogonalOffset * totalWidth) + "px";
+ this._highlightDiv.style.height = Math.round(orthogonalExtent * totalWidth) + "px";
+ } else {
+ this._highlightDiv.style.top = startPixel + "px";
+ this._highlightDiv.style.height = length + "px";
+ this._highlightDiv.style.left = Math.round(orthogonalOffset * totalWidth) + "px";
+ this._highlightDiv.style.width = Math.round(orthogonalExtent * totalWidth) + "px";
+ }
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ethers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ethers.js
new file mode 100644
index 00000000..1294cdae
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ethers.js
@@ -0,0 +1,305 @@
+/*==================================================
+ * An "ether" is a object that maps date/time to pixel coordinates.
+ *==================================================
+ */
+
+/*==================================================
+ * Linear Ether
+ *==================================================
+ */
+
+Timeline.LinearEther = function(params) {
+ this._params = params;
+ this._interval = params.interval;
+ this._pixelsPerInterval = params.pixelsPerInterval;
+};
+
+Timeline.LinearEther.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+ this._unit = timeline.getUnit();
+
+ if ("startsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.startsOn);
+ } else if ("endsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.endsOn);
+ this.shiftPixels(-this._timeline.getPixelLength());
+ } else if ("centersOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.centersOn);
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ } else {
+ this._start = this._unit.makeDefaultValue();
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ }
+};
+
+Timeline.LinearEther.prototype.setDate = function(date) {
+ this._start = this._unit.cloneValue(date);
+};
+
+Timeline.LinearEther.prototype.shiftPixels = function(pixels) {
+ var numeric = this._interval * pixels / this._pixelsPerInterval;
+ this._start = this._unit.change(this._start, numeric);
+};
+
+Timeline.LinearEther.prototype.dateToPixelOffset = function(date) {
+ var numeric = this._unit.compare(date, this._start);
+ return this._pixelsPerInterval * numeric / this._interval;
+};
+
+Timeline.LinearEther.prototype.pixelOffsetToDate = function(pixels) {
+ var numeric = pixels * this._interval / this._pixelsPerInterval;
+ return this._unit.change(this._start, numeric);
+};
+
+Timeline.LinearEther.prototype.zoom = function(zoomIn) {
+ var netIntervalChange = 0;
+ var currentZoomIndex = this._band._zoomIndex;
+ var newZoomIndex = currentZoomIndex;
+
+ if (zoomIn && (currentZoomIndex > 0)) {
+ newZoomIndex = currentZoomIndex - 1;
+ }
+
+ if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
+ newZoomIndex = currentZoomIndex + 1;
+ }
+
+ this._band._zoomIndex = newZoomIndex;
+ this._interval =
+ SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+ this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+ netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
+ this._band._zoomSteps[currentZoomIndex].unit;
+
+ return netIntervalChange;
+};
+
+
+/*==================================================
+ * Hot Zone Ether
+ *==================================================
+ */
+
+Timeline.HotZoneEther = function(params) {
+ this._params = params;
+ this._interval = params.interval;
+ this._pixelsPerInterval = params.pixelsPerInterval;
+ this._theme = params.theme;
+};
+
+Timeline.HotZoneEther.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+ this._unit = timeline.getUnit();
+
+ this._zones = [{
+ startTime: Number.NEGATIVE_INFINITY,
+ endTime: Number.POSITIVE_INFINITY,
+ magnify: 1
+ }];
+ var params = this._params;
+ for (var i = 0; i < params.zones.length; i++) {
+ var zone = params.zones[i];
+ var zoneStart = this._unit.parseFromObject(zone.start);
+ var zoneEnd = this._unit.parseFromObject(zone.end);
+
+ for (var j = 0; j < this._zones.length && this._unit.compare(zoneEnd, zoneStart) > 0; j++) {
+ var zone2 = this._zones[j];
+
+ if (this._unit.compare(zoneStart, zone2.endTime) < 0) {
+ if (this._unit.compare(zoneStart, zone2.startTime) > 0) {
+ this._zones.splice(j, 0, {
+ startTime: zone2.startTime,
+ endTime: zoneStart,
+ magnify: zone2.magnify
+ });
+ j++;
+
+ zone2.startTime = zoneStart;
+ }
+
+ if (this._unit.compare(zoneEnd, zone2.endTime) < 0) {
+ this._zones.splice(j, 0, {
+ startTime: zoneStart,
+ endTime: zoneEnd,
+ magnify: zone.magnify * zone2.magnify
+ });
+ j++;
+
+ zone2.startTime = zoneEnd;
+ zoneStart = zoneEnd;
+ } else {
+ zone2.magnify *= zone.magnify;
+ zoneStart = zone2.endTime;
+ }
+ } // else, try the next existing zone
+ }
+ }
+
+ if ("startsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.startsOn);
+ } else if ("endsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.endsOn);
+ this.shiftPixels(-this._timeline.getPixelLength());
+ } else if ("centersOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.centersOn);
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ } else {
+ this._start = this._unit.makeDefaultValue();
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ }
+};
+
+Timeline.HotZoneEther.prototype.setDate = function(date) {
+ this._start = this._unit.cloneValue(date);
+};
+
+Timeline.HotZoneEther.prototype.shiftPixels = function(pixels) {
+ this._start = this.pixelOffsetToDate(pixels);
+};
+
+Timeline.HotZoneEther.prototype.dateToPixelOffset = function(date) {
+ return this._dateDiffToPixelOffset(this._start, date);
+};
+
+Timeline.HotZoneEther.prototype.pixelOffsetToDate = function(pixels) {
+ return this._pixelOffsetToDate(pixels, this._start);
+};
+
+Timeline.HotZoneEther.prototype.zoom = function(zoomIn) {
+ var netIntervalChange = 0;
+ var currentZoomIndex = this._band._zoomIndex;
+ var newZoomIndex = currentZoomIndex;
+
+ if (zoomIn && (currentZoomIndex > 0)) {
+ newZoomIndex = currentZoomIndex - 1;
+ }
+
+ if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
+ newZoomIndex = currentZoomIndex + 1;
+ }
+
+ this._band._zoomIndex = newZoomIndex;
+ this._interval =
+ SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+ this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+ netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
+ this._band._zoomSteps[currentZoomIndex].unit;
+
+ return netIntervalChange;
+};
+
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset = function(fromDate, toDate) {
+ var scale = this._getScale();
+ var fromTime = fromDate;
+ var toTime = toDate;
+
+ var pixels = 0;
+ if (this._unit.compare(fromTime, toTime) < 0) {
+ var z = 0;
+ while (z < this._zones.length) {
+ if (this._unit.compare(fromTime, this._zones[z].endTime) < 0) {
+ break;
+ }
+ z++;
+ }
+
+ while (this._unit.compare(fromTime, toTime) < 0) {
+ var zone = this._zones[z];
+ var toTime2 = this._unit.earlier(toTime, zone.endTime);
+
+ pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+ fromTime = toTime2;
+ z++;
+ }
+ } else {
+ var z = this._zones.length - 1;
+ while (z >= 0) {
+ if (this._unit.compare(fromTime, this._zones[z].startTime) > 0) {
+ break;
+ }
+ z--;
+ }
+
+ while (this._unit.compare(fromTime, toTime) > 0) {
+ var zone = this._zones[z];
+ var toTime2 = this._unit.later(toTime, zone.startTime);
+
+ pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+ fromTime = toTime2;
+ z--;
+ }
+ }
+ return pixels;
+};
+
+Timeline.HotZoneEther.prototype._pixelOffsetToDate = function(pixels, fromDate) {
+ var scale = this._getScale();
+ var time = fromDate;
+ if (pixels > 0) {
+ var z = 0;
+ while (z < this._zones.length) {
+ if (this._unit.compare(time, this._zones[z].endTime) < 0) {
+ break;
+ }
+ z++;
+ }
+
+ while (pixels > 0) {
+ var zone = this._zones[z];
+ var scale2 = scale / zone.magnify;
+
+ if (zone.endTime == Number.POSITIVE_INFINITY) {
+ time = this._unit.change(time, pixels * scale2);
+ pixels = 0;
+ } else {
+ var pixels2 = this._unit.compare(zone.endTime, time) / scale2;
+ if (pixels2 > pixels) {
+ time = this._unit.change(time, pixels * scale2);
+ pixels = 0;
+ } else {
+ time = zone.endTime;
+ pixels -= pixels2;
+ }
+ }
+ z++;
+ }
+ } else {
+ var z = this._zones.length - 1;
+ while (z >= 0) {
+ if (this._unit.compare(time, this._zones[z].startTime) > 0) {
+ break;
+ }
+ z--;
+ }
+
+ pixels = -pixels;
+ while (pixels > 0) {
+ var zone = this._zones[z];
+ var scale2 = scale / zone.magnify;
+
+ if (zone.startTime == Number.NEGATIVE_INFINITY) {
+ time = this._unit.change(time, -pixels * scale2);
+ pixels = 0;
+ } else {
+ var pixels2 = this._unit.compare(time, zone.startTime) / scale2;
+ if (pixels2 > pixels) {
+ time = this._unit.change(time, -pixels * scale2);
+ pixels = 0;
+ } else {
+ time = zone.startTime;
+ pixels -= pixels2;
+ }
+ }
+ z--;
+ }
+ }
+ return time;
+};
+
+Timeline.HotZoneEther.prototype._getScale = function() {
+ return this._interval / this._pixelsPerInterval;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/event-utils.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/event-utils.js
new file mode 100644
index 00000000..db3b8242
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/event-utils.js
@@ -0,0 +1,64 @@
+/*==================================================
+ * Event Utils
+ *==================================================
+ */
+Timeline.EventUtils = {};
+
+Timeline.EventUtils.getNewEventID = function() {
+ // global across page
+ if (this._lastEventID == null) {
+ this._lastEventID = 0;
+ }
+
+ this._lastEventID += 1;
+ return "e" + this._lastEventID;
+};
+
+Timeline.EventUtils.decodeEventElID = function(elementID) {
+ /*==================================================
+ *
+ * Use this function to decode an event element's id on a band (label div,
+ * tape div or icon img).
+ *
+ * Returns {band: <bandObj>, evt: <eventObj>}
+ *
+ * To enable a single event listener to monitor everything
+ * on a Timeline, a set format is used for the id's of the
+ * elements on the Timeline--
+ *
+ * element id format for labels, icons, tapes:
+ * labels: label-tl-<timelineID>-<band_index>-<evt.id>
+ * icons: icon-tl-<timelineID>-<band_index>-<evt.id>
+ * tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
+ * tape2-tl-<timelineID>-<band_index>-<evt.id>
+ * // some events have more than one tape
+ * highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
+ * highlight2-tl-<timelineID>-<band_index>-<evt.id>
+ * // some events have more than one highlight div (future)
+ * Note: use split('-') to get array of the format's parts
+ *
+ * You can then retrieve the timeline object and event object
+ * by using Timeline.getTimeline, Timeline.getBand, or
+ * Timeline.getEvent and passing in the element's id
+ *
+ *==================================================
+ */
+
+ var parts = elementID.split('-');
+ if (parts[1] != 'tl') {
+ alert("Internal Timeline problem 101, please consult support");
+ return {band: null, evt: null}; // early return
+ }
+
+ var timeline = Timeline.getTimelineFromID(parts[2]);
+ var band = timeline.getBand(parts[3]);
+ var evt = band.getEventSource.getEvent(parts[4]);
+
+ return {band: band, evt: evt};
+};
+
+Timeline.EventUtils.encodeEventElID = function(timeline, band, elType, evt) {
+ // elType should be one of {label | icon | tapeN | highlightN}
+ return elType + "-tl-" + timeline.timelineID +
+ "-" + band.getIndex() + "-" + evt.getID();
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ext/japanese-eras.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ext/japanese-eras.js
new file mode 100644
index 00000000..437f44ed
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/ext/japanese-eras.js
@@ -0,0 +1,395 @@
+/*==================================================
+ * Japanese Era Date Labeller
+ *==================================================
+ */
+
+Timeline.JapaneseEraDateLabeller = function(locale, timeZone, useRomanizedName) {
+ var o = new Timeline.GregorianDateLabeller(locale, timeZone);
+
+ o._useRomanizedName = (useRomanizedName);
+ o._oldLabelInterval = o.labelInterval;
+ o.labelInterval = Timeline.JapaneseEraDateLabeller._labelInterval;
+
+ return o;
+};
+
+Timeline.JapaneseEraDateLabeller._labelInterval = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.YEAR:
+ case Timeline.DateTime.DECADE:
+ case Timeline.DateTime.CENTURY:
+ case Timeline.DateTime.MILLENNIUM:
+ var y = date2.getUTCFullYear();
+ if (y >= Timeline.JapaneseEraDateLabeller._eras.elementAt(0).startingYear) {
+ var eraIndex = Timeline.JapaneseEraDateLabeller._eras.find(function(era) {
+ return era.startingYear - y;
+ }
+ );
+ if (eraIndex < Timeline.JapaneseEraDateLabeller._eras.length()) {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex);
+ if (y < era.startingYear) {
+ era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex - 1);
+ }
+ } else {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex - 1);
+ }
+
+ text = (this._useRomanizedName ? era.romanizedName : era.japaneseName) + " " + (y - era.startingYear + 1);
+ emphasized = intervalUnit == Timeline.DateTime.YEAR && y == era.startingYear;
+ break;
+ } // else, fall through
+ default:
+ return this._oldLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+};
+
+/*==================================================
+ * Japanese Era Ether Painter
+ *==================================================
+ */
+
+Timeline.JapaneseEraEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._theme = params.theme;
+};
+
+Timeline.JapaneseEraEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.JapaneseEraEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.JapaneseEraEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minYear = this._band.getMinDate().getUTCFullYear();
+ var maxYear = this._band.getMaxDate().getUTCFullYear();
+ var eraIndex = Timeline.JapaneseEraDateLabeller._eras.find(function(era) {
+ return era.startingYear - minYear;
+ }
+ );
+
+ var l = Timeline.JapaneseEraDateLabeller._eras.length();
+ for (var i = eraIndex; i < l; i++) {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(i);
+ if (era.startingYear > maxYear) {
+ break;
+ }
+
+ var d = new Date(0);
+ d.setUTCFullYear(era.startingYear);
+
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ return {
+ text: era.japaneseName,
+ emphasized: true
+ };
+ }
+ };
+
+ this._intervalMarkerLayout.createIntervalMarker(
+ d, labeller, Timeline.DateTime.YEAR, this._markerLayer, this._lineLayer);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.JapaneseEraEtherPainter.prototype.softPaint = function() {
+};
+
+
+Timeline.JapaneseEraDateLabeller._eras = new Timeline.SortedArray(
+ function(e1, e2) {
+ return e1.startingYear - e2.startingYear;
+ },
+ [
+ { startingYear: 645, japaneseName: '大化', romanizedName: "Taika" },
+ { startingYear: 650, japaneseName: '白雉', romanizedName: "Hakuchi" },
+ { startingYear: 686, japaneseName: '朱鳥', romanizedName: "ShuchÅ" },
+ { startingYear: 701, japaneseName: '大å®', romanizedName: "TaihÅ" },
+ { startingYear: 704, japaneseName: '慶雲', romanizedName: "Keiun" },
+ { startingYear: 708, japaneseName: '和銅', romanizedName: "WadÅ" },
+ { startingYear: 715, japaneseName: '霊亀', romanizedName: "Reiki" },
+ { startingYear: 717, japaneseName: '養è€', romanizedName: "YÅrÅ" },
+ { startingYear: 724, japaneseName: '神亀', romanizedName: "Jinki" },
+ { startingYear: 729, japaneseName: '天平', romanizedName: "TenpyÅ" },
+ { startingYear: 749, japaneseName: '天平感å®', romanizedName: "TenpyÅ-kanpÅ" },
+ { startingYear: 749, japaneseName: '天平å‹å®', romanizedName: "TenpyÅ-shÅhÅ" },
+ { startingYear: 757, japaneseName: '天平å®å­—', romanizedName: "TenpyÅ-hÅji" },
+ { startingYear: 765, japaneseName: '天平神護', romanizedName: "TenpyÅ-jingo" },
+ { startingYear: 767, japaneseName: '神護景雲', romanizedName: "Jingo-keiun" },
+ { startingYear: 770, japaneseName: 'å®äº€', romanizedName: "HÅki" },
+ { startingYear: 781, japaneseName: '天応', romanizedName: "Ten'Å" },
+ { startingYear: 782, japaneseName: '延暦', romanizedName: "Enryaku" },
+ { startingYear: 806, japaneseName: '大åŒ', romanizedName: "DaidÅ" },
+ { startingYear: 810, japaneseName: '弘ä»', romanizedName: "KÅnin" },
+ { startingYear: 824, japaneseName: '天長', romanizedName: "TenchÅ" },
+ { startingYear: 834, japaneseName: '承和', romanizedName: "JÅwa" },
+ { startingYear: 848, japaneseName: '嘉祥', romanizedName: "KajÅ" },
+ { startingYear: 851, japaneseName: 'ä»å¯¿', romanizedName: "Ninju" },
+ { startingYear: 854, japaneseName: '斉衡', romanizedName: "SaikÅ" },
+ { startingYear: 857, japaneseName: '天安', romanizedName: "Tennan" },
+ { startingYear: 859, japaneseName: '貞観', romanizedName: "JÅgan" },
+ { startingYear: 877, japaneseName: '元慶', romanizedName: "GangyÅ" },
+ { startingYear: 885, japaneseName: 'ä»å’Œ', romanizedName: "Ninna" },
+ { startingYear: 889, japaneseName: '寛平', romanizedName: "KanpyÅ" },
+ { startingYear: 898, japaneseName: '昌泰', romanizedName: "ShÅtai" },
+ { startingYear: 901, japaneseName: '延喜', romanizedName: "Engi" },
+ { startingYear: 923, japaneseName: '延長', romanizedName: "EnchÅ" },
+ { startingYear: 931, japaneseName: '承平', romanizedName: "JÅhei" },
+ { startingYear: 938, japaneseName: '天慶', romanizedName: "TengyÅ" },
+ { startingYear: 947, japaneseName: '天暦', romanizedName: "Tenryaku" },
+ { startingYear: 957, japaneseName: '天徳', romanizedName: "Tentoku" },
+ { startingYear: 961, japaneseName: '応和', romanizedName: "Ōwa" },
+ { startingYear: 964, japaneseName: '康ä¿', romanizedName: "KÅhÅ" },
+ { startingYear: 968, japaneseName: '安和', romanizedName: "Anna" },
+ { startingYear: 970, japaneseName: '天禄', romanizedName: "Tenroku" },
+ { startingYear: 973, japaneseName: '天延', romanizedName: "Ten'en" },
+ { startingYear: 976, japaneseName: '貞元', romanizedName: "JÅgen" },
+ { startingYear: 978, japaneseName: '天元', romanizedName: "Tengen" },
+ { startingYear: 983, japaneseName: '永観', romanizedName: "Eikan" },
+ { startingYear: 985, japaneseName: '寛和', romanizedName: "Kanna" },
+ { startingYear: 987, japaneseName: '永延', romanizedName: "Eien" },
+ { startingYear: 988, japaneseName: '永祚', romanizedName: "Eiso" },
+ { startingYear: 990, japaneseName: '正暦', romanizedName: "ShÅryaku" },
+ { startingYear: 995, japaneseName: 'é•·å¾³', romanizedName: "ChÅtoku" },
+ { startingYear: 999, japaneseName: 'é•·ä¿', romanizedName: "ChÅhÅ" },
+ { startingYear: 1004, japaneseName: '寛弘', romanizedName: "KankÅ" },
+ { startingYear: 1012, japaneseName: 'é•·å’Œ', romanizedName: "ChÅwa" },
+ { startingYear: 1017, japaneseName: '寛ä»', romanizedName: "Kannin" },
+ { startingYear: 1021, japaneseName: '治安', romanizedName: "Jian" },
+ { startingYear: 1024, japaneseName: '万寿', romanizedName: "Manju" },
+ { startingYear: 1028, japaneseName: 'é•·å…ƒ', romanizedName: "ChÅgen" },
+ { startingYear: 1037, japaneseName: '長暦', romanizedName: "ChÅryaku" },
+ { startingYear: 1040, japaneseName: 'é•·ä¹…', romanizedName: "ChÅkyÅ«" },
+ { startingYear: 1044, japaneseName: '寛徳', romanizedName: "Kantoku" },
+ { startingYear: 1046, japaneseName: '永承', romanizedName: "EishÅ" },
+ { startingYear: 1053, japaneseName: '天喜', romanizedName: "Tengi" },
+ { startingYear: 1058, japaneseName: '康平', romanizedName: "KÅhei" },
+ { startingYear: 1065, japaneseName: '治暦', romanizedName: "Jiryaku" },
+ { startingYear: 1069, japaneseName: '延久', romanizedName: "Enkyū" },
+ { startingYear: 1074, japaneseName: '承ä¿', romanizedName: "JÅhÅ" },
+ { startingYear: 1077, japaneseName: '承暦', romanizedName: "JÅryaku" },
+ { startingYear: 1081, japaneseName: 'æ°¸ä¿', romanizedName: "EihÅ" },
+ { startingYear: 1084, japaneseName: '応徳', romanizedName: "Ōtoku" },
+ { startingYear: 1087, japaneseName: '寛治', romanizedName: "Kanji" },
+ { startingYear: 1094, japaneseName: '嘉ä¿', romanizedName: "KahÅ" },
+ { startingYear: 1096, japaneseName: '永長', romanizedName: "EichÅ" },
+ { startingYear: 1097, japaneseName: '承徳', romanizedName: "JÅtoku" },
+ { startingYear: 1099, japaneseName: '康和', romanizedName: "KÅwa" },
+ { startingYear: 1104, japaneseName: 'é•·æ²»', romanizedName: "ChÅji" },
+ { startingYear: 1106, japaneseName: '嘉承', romanizedName: "KajÅ" },
+ { startingYear: 1108, japaneseName: '天ä»', romanizedName: "Tennin" },
+ { startingYear: 1110, japaneseName: '天永', romanizedName: "Ten'ei" },
+ { startingYear: 1113, japaneseName: '永久', romanizedName: "Eikyū" },
+ { startingYear: 1118, japaneseName: '元永', romanizedName: "Gen'ei" },
+ { startingYear: 1120, japaneseName: 'ä¿å®‰', romanizedName: "HÅan" },
+ { startingYear: 1124, japaneseName: '天治', romanizedName: "Tenji" },
+ { startingYear: 1126, japaneseName: '大治', romanizedName: "Daiji" },
+ { startingYear: 1131, japaneseName: '天承', romanizedName: "TenshÅ" },
+ { startingYear: 1132, japaneseName: '長承', romanizedName: "ChÅshÅ" },
+ { startingYear: 1135, japaneseName: 'ä¿å»¶', romanizedName: "HÅen" },
+ { startingYear: 1141, japaneseName: '永治', romanizedName: "Eiji" },
+ { startingYear: 1142, japaneseName: '康治', romanizedName: "KÅji" },
+ { startingYear: 1144, japaneseName: '天養', romanizedName: "Ten'yÅ" },
+ { startingYear: 1145, japaneseName: '久安', romanizedName: "Kyūan" },
+ { startingYear: 1151, japaneseName: 'ä»å¹³', romanizedName: "Ninpei" },
+ { startingYear: 1154, japaneseName: '久寿', romanizedName: "Kyūju" },
+ { startingYear: 1156, japaneseName: 'ä¿å…ƒ', romanizedName: "HÅgen" },
+ { startingYear: 1159, japaneseName: '平治', romanizedName: "Heiji" },
+ { startingYear: 1160, japaneseName: '永暦', romanizedName: "Eiryaku" },
+ { startingYear: 1161, japaneseName: 'å¿œä¿', romanizedName: "ÅŒhÅ" },
+ { startingYear: 1163, japaneseName: '長寛', romanizedName: "ChÅkan" },
+ { startingYear: 1165, japaneseName: '永万', romanizedName: "Eiman" },
+ { startingYear: 1166, japaneseName: 'ä»å®‰', romanizedName: "Ninnan" },
+ { startingYear: 1169, japaneseName: '嘉応', romanizedName: "KaÅ" },
+ { startingYear: 1171, japaneseName: '承安', romanizedName: "JÅan" },
+ { startingYear: 1175, japaneseName: '安元', romanizedName: "Angen" },
+ { startingYear: 1177, japaneseName: '治承', romanizedName: "JishÅ" },
+ { startingYear: 1181, japaneseName: '養和', romanizedName: "YÅwa" },
+ { startingYear: 1182, japaneseName: '寿永', romanizedName: "Juei" },
+ { startingYear: 1184, japaneseName: '元暦', romanizedName: "Genryaku" },
+ { startingYear: 1185, japaneseName: '文治', romanizedName: "Bunji" },
+ { startingYear: 1190, japaneseName: '建久', romanizedName: "Kenkyū" },
+ { startingYear: 1199, japaneseName: '正治', romanizedName: "ShÅji" },
+ { startingYear: 1201, japaneseName: '建ä»', romanizedName: "Kennin" },
+ { startingYear: 1204, japaneseName: '元久', romanizedName: "Genkyū" },
+ { startingYear: 1206, japaneseName: '建永', romanizedName: "Ken'ei" },
+ { startingYear: 1207, japaneseName: '承元', romanizedName: "JÅgen" },
+ { startingYear: 1211, japaneseName: '建暦', romanizedName: "Kenryaku" },
+ { startingYear: 1213, japaneseName: '建ä¿', romanizedName: "KenpÅ" },
+ { startingYear: 1219, japaneseName: '承久', romanizedName: "JÅkyÅ«" },
+ { startingYear: 1222, japaneseName: '貞応', romanizedName: "JÅÅ" },
+ { startingYear: 1224, japaneseName: 'å…ƒä»', romanizedName: "Gennin" },
+ { startingYear: 1225, japaneseName: '嘉禄', romanizedName: "Karoku" },
+ { startingYear: 1227, japaneseName: '安貞', romanizedName: "Antei" },
+ { startingYear: 1229, japaneseName: '寛喜', romanizedName: "Kanki" },
+ { startingYear: 1232, japaneseName: '貞永', romanizedName: "JÅei" },
+ { startingYear: 1233, japaneseName: '天ç¦', romanizedName: "Tenpuku" },
+ { startingYear: 1234, japaneseName: '文暦', romanizedName: "Bunryaku" },
+ { startingYear: 1235, japaneseName: '嘉禎', romanizedName: "Katei" },
+ { startingYear: 1238, japaneseName: '暦ä»', romanizedName: "Ryakunin" },
+ { startingYear: 1239, japaneseName: '延応', romanizedName: "En'Å" },
+ { startingYear: 1240, japaneseName: 'ä»æ²»', romanizedName: "Ninji" },
+ { startingYear: 1243, japaneseName: '寛元', romanizedName: "Kangen" },
+ { startingYear: 1247, japaneseName: 'å®æ²»', romanizedName: "HÅji" },
+ { startingYear: 1249, japaneseName: '建長', romanizedName: "KenchÅ" },
+ { startingYear: 1256, japaneseName: '康元', romanizedName: "KÅgen" },
+ { startingYear: 1257, japaneseName: '正嘉', romanizedName: "ShÅka" },
+ { startingYear: 1259, japaneseName: '正元', romanizedName: "ShÅgen" },
+ { startingYear: 1260, japaneseName: '文応', romanizedName: "Bun'Å" },
+ { startingYear: 1261, japaneseName: '弘長', romanizedName: "KÅcho" },
+ { startingYear: 1264, japaneseName: '文永', romanizedName: "Bun'ei" },
+ { startingYear: 1275, japaneseName: '建治', romanizedName: "Kenji" },
+ { startingYear: 1278, japaneseName: '弘安', romanizedName: "KÅan" },
+ { startingYear: 1288, japaneseName: '正応', romanizedName: "ShÅÅ" },
+ { startingYear: 1293, japaneseName: 'æ°¸ä»', romanizedName: "Einin" },
+ { startingYear: 1299, japaneseName: '正安', romanizedName: "ShÅan" },
+ { startingYear: 1302, japaneseName: '乾元', romanizedName: "Kengen" },
+ { startingYear: 1303, japaneseName: '嘉元', romanizedName: "Kagen" },
+ { startingYear: 1306, japaneseName: '徳治', romanizedName: "Tokuji" },
+ { startingYear: 1308, japaneseName: '延慶', romanizedName: "Enkei" },
+ { startingYear: 1311, japaneseName: '応長', romanizedName: "ÅŒchÅ" },
+ { startingYear: 1312, japaneseName: '正和', romanizedName: "ShÅwa" },
+ { startingYear: 1317, japaneseName: 'æ–‡ä¿', romanizedName: "BunpÅ" },
+ { startingYear: 1319, japaneseName: '元応', romanizedName: "Gen'Å" },
+ { startingYear: 1321, japaneseName: '元亨', romanizedName: "GenkyÅ" },
+ { startingYear: 1324, japaneseName: '正中', romanizedName: "ShÅchÅ«" },
+ { startingYear: 1326, japaneseName: '嘉暦', romanizedName: "Karyaku" },
+ { startingYear: 1329, japaneseName: '元徳', romanizedName: "Gentoku" },
+ { startingYear: 1331, japaneseName: '元弘', romanizedName: "GenkÅ" },
+ { startingYear: 1334, japaneseName: '建武', romanizedName: "Kenmu" },
+ { startingYear: 1336, japaneseName: '延元', romanizedName: "Engen" },
+ { startingYear: 1340, japaneseName: '興国', romanizedName: "KÅkoku" },
+ { startingYear: 1346, japaneseName: '正平', romanizedName: "ShÅhei" },
+ { startingYear: 1370, japaneseName: '建徳', romanizedName: "Kentoku" },
+ { startingYear: 1372, japaneseName: '文中', romanizedName: "Bunchū" },
+ { startingYear: 1375, japaneseName: '天授', romanizedName: "Tenju" },
+ { startingYear: 1381, japaneseName: '弘和', romanizedName: "KÅwa" },
+ { startingYear: 1384, japaneseName: '元中', romanizedName: "Genchū" },
+ { startingYear: 1332, japaneseName: '正慶', romanizedName: "ShÅkei" },
+ { startingYear: 1338, japaneseName: '暦応', romanizedName: "RyakuÅ" },
+ { startingYear: 1342, japaneseName: '康永', romanizedName: "KÅei" },
+ { startingYear: 1345, japaneseName: '貞和', romanizedName: "JÅwa" },
+ { startingYear: 1350, japaneseName: '観応', romanizedName: "Kan'Å" },
+ { startingYear: 1352, japaneseName: '文和', romanizedName: "Bunna" },
+ { startingYear: 1356, japaneseName: '延文', romanizedName: "Enbun" },
+ { startingYear: 1361, japaneseName: '康安', romanizedName: "KÅan" },
+ { startingYear: 1362, japaneseName: '貞治', romanizedName: "JÅji" },
+ { startingYear: 1368, japaneseName: '応安', romanizedName: "Ōan" },
+ { startingYear: 1375, japaneseName: '永和', romanizedName: "Eiwa" },
+ { startingYear: 1379, japaneseName: '康暦', romanizedName: "KÅryaku" },
+ { startingYear: 1381, japaneseName: '永徳', romanizedName: "Eitoku" },
+ { startingYear: 1384, japaneseName: '至徳', romanizedName: "Shitoku" },
+ { startingYear: 1387, japaneseName: '嘉慶', romanizedName: "Kakei" },
+ { startingYear: 1389, japaneseName: '康応', romanizedName: "KÅÅ" },
+ { startingYear: 1390, japaneseName: '明徳', romanizedName: "Meitoku" },
+ { startingYear: 1394, japaneseName: '応永', romanizedName: "Ōei" },
+ { startingYear: 1428, japaneseName: '正長', romanizedName: "ShÅchÅ" },
+ { startingYear: 1429, japaneseName: '永享', romanizedName: "EikyÅ" },
+ { startingYear: 1441, japaneseName: '嘉å‰', romanizedName: "Kakitsu" },
+ { startingYear: 1444, japaneseName: '文安', romanizedName: "Bunnan" },
+ { startingYear: 1449, japaneseName: 'å®å¾³', romanizedName: "HÅtoku" },
+ { startingYear: 1452, japaneseName: '享徳', romanizedName: "KyÅtoku" },
+ { startingYear: 1455, japaneseName: '康正', romanizedName: "KÅshÅ" },
+ { startingYear: 1457, japaneseName: '長禄', romanizedName: "ChÅroku" },
+ { startingYear: 1460, japaneseName: '寛正', romanizedName: "KanshÅ" },
+ { startingYear: 1466, japaneseName: '文正', romanizedName: "BunshÅ" },
+ { startingYear: 1467, japaneseName: 'å¿œä»', romanizedName: "ÅŒnin" },
+ { startingYear: 1469, japaneseName: '文明', romanizedName: "Bunmei" },
+ { startingYear: 1487, japaneseName: '長享', romanizedName: "ChÅkyÅ" },
+ { startingYear: 1489, japaneseName: '延徳', romanizedName: "Entoku" },
+ { startingYear: 1492, japaneseName: '明応', romanizedName: "MeiÅ" },
+ { startingYear: 1501, japaneseName: '文亀', romanizedName: "Bunki" },
+ { startingYear: 1504, japaneseName: '永正', romanizedName: "EishÅ" },
+ { startingYear: 1521, japaneseName: '大永', romanizedName: "Daiei" },
+ { startingYear: 1528, japaneseName: '享禄', romanizedName: "KyÅroku" },
+ { startingYear: 1532, japaneseName: '天文', romanizedName: "Tenbun" },
+ { startingYear: 1555, japaneseName: '弘治', romanizedName: "KÅji" },
+ { startingYear: 1558, japaneseName: '永禄', romanizedName: "Eiroku" },
+ { startingYear: 1570, japaneseName: '元亀', romanizedName: "Genki" },
+ { startingYear: 1573, japaneseName: '天正', romanizedName: "TenshÅ" },
+ { startingYear: 1592, japaneseName: '文禄', romanizedName: "Bunroku" },
+ { startingYear: 1596, japaneseName: '慶長', romanizedName: "KeichÅ" },
+ { startingYear: 1615, japaneseName: '元和', romanizedName: "Genna" },
+ { startingYear: 1624, japaneseName: '寛永', romanizedName: "Kan'ei" },
+ { startingYear: 1644, japaneseName: 'æ­£ä¿', romanizedName: "ShÅhÅ" },
+ { startingYear: 1648, japaneseName: '慶安', romanizedName: "Keian" },
+ { startingYear: 1652, japaneseName: '承応', romanizedName: "JÅÅ" },
+ { startingYear: 1655, japaneseName: '明暦', romanizedName: "Meireki" },
+ { startingYear: 1658, japaneseName: '万治', romanizedName: "Manji" },
+ { startingYear: 1661, japaneseName: '寛文', romanizedName: "Kanbun" },
+ { startingYear: 1673, japaneseName: '延å®', romanizedName: "EnpÅ" },
+ { startingYear: 1681, japaneseName: '天和', romanizedName: "Tenna" },
+ { startingYear: 1684, japaneseName: '貞享', romanizedName: "JÅkyÅ" },
+ { startingYear: 1688, japaneseName: '元禄', romanizedName: "Genroku" },
+ { startingYear: 1704, japaneseName: 'å®æ°¸', romanizedName: "HÅei" },
+ { startingYear: 1711, japaneseName: '正徳', romanizedName: "ShÅtoku" },
+ { startingYear: 1716, japaneseName: '享ä¿', romanizedName: "KyÅhÅ" },
+ { startingYear: 1736, japaneseName: '元文', romanizedName: "Genbun" },
+ { startingYear: 1741, japaneseName: '寛ä¿', romanizedName: "KanpÅ" },
+ { startingYear: 1744, japaneseName: '延享', romanizedName: "EnkyÅ" },
+ { startingYear: 1748, japaneseName: '寛延', romanizedName: "Kan'en" },
+ { startingYear: 1751, japaneseName: 'å®æš¦', romanizedName: "HÅreki" },
+ { startingYear: 1764, japaneseName: '明和', romanizedName: "Meiwa" },
+ { startingYear: 1772, japaneseName: '安永', romanizedName: "An'ei" },
+ { startingYear: 1781, japaneseName: '天明', romanizedName: "Tenmei" },
+ { startingYear: 1789, japaneseName: '寛政', romanizedName: "Kansei" },
+ { startingYear: 1801, japaneseName: '享和', romanizedName: "KyÅwa" },
+ { startingYear: 1804, japaneseName: '文化', romanizedName: "Bunka" },
+ { startingYear: 1818, japaneseName: '文政', romanizedName: "Bunsei" },
+ { startingYear: 1830, japaneseName: '天ä¿', romanizedName: "TenpÅ" },
+ { startingYear: 1844, japaneseName: '弘化', romanizedName: "KÅka" },
+ { startingYear: 1848, japaneseName: '嘉永', romanizedName: "Kaei" },
+ { startingYear: 1854, japaneseName: '安政', romanizedName: "Ansei" },
+ { startingYear: 1860, japaneseName: '万延', romanizedName: "Man'en" },
+ { startingYear: 1861, japaneseName: '文久', romanizedName: "Bunkyū" },
+ { startingYear: 1864, japaneseName: '元治', romanizedName: "Genji" },
+ { startingYear: 1865, japaneseName: '慶応', romanizedName: "KeiÅ" },
+ { startingYear: 1868, japaneseName: '明治', romanizedName: "Meiji" },
+ { startingYear: 1912, japaneseName: '大正', romanizedName: "TaishÅ" },
+ { startingYear: 1926, japaneseName: '昭和', romanizedName: "ShÅwa" },
+ { startingYear: 1989, japaneseName: 'å¹³æˆ', romanizedName: "Heisei" }
+ ]
+);
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/labellers.js
new file mode 100644
index 00000000..cc757857
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/labellers.js
@@ -0,0 +1,30 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["cs"] = [
+ "Leden", "Únor", "Bøezen", "Duben", "Kvìten", "Èerven", "Èervenec", "Srpen", "Záøí", "Øíjen", "Listopad", "Prosinec"
+];
+
+Timeline.GregorianDateLabeller.dayNames["cs"] = [
+ "Ne", "Po", "Út", "St", "Èt", "Pá", "So"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["cs"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = date2.getUTCDate() + ". " + (date2.getUTCMonth() + 1) + ".";
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/timeline.js
new file mode 100644
index 00000000..21d41a4e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/cs/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["cs"] = {
+ wikiLinkLabel: "Diskuze"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/labellers.js
new file mode 100644
index 00000000..f0eb7df1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/labellers.js
@@ -0,0 +1,27 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["de"] = [
+ "Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["de"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = date2.getUTCDate() + ". " +
+ Timeline.GregorianDateLabeller.getMonthName(date2.getUTCMonth(), this._locale);
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/timeline.js
new file mode 100644
index 00000000..7292cef2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/de/timeline.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["de"] = {
+ wikiLinkLabel: "Diskutieren"
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/labellers.js
new file mode 100644
index 00000000..899b950e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["en"] = [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+];
+
+Timeline.GregorianDateLabeller.dayNames["en"] = [
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/timeline.js
new file mode 100644
index 00000000..c6b70dda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/en/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["en"] = {
+ wikiLinkLabel: "Discuss"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/labellers.js
new file mode 100644
index 00000000..963038e2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["es"] = [
+ "Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/timeline.js
new file mode 100644
index 00000000..2a5183c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/es/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["es"] = {
+ wikiLinkLabel: "Discute"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/labellers.js
new file mode 100644
index 00000000..5e7392a7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["fr"] = [
+ "jan", "fev", "mar", "avr", "mai", "jui", "jui", "aou", "sep", "oct", "nov", "dec"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/timeline.js
new file mode 100644
index 00000000..459cc384
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/fr/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["fr"] = {
+ wikiLinkLabel: "Discute"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/labellers.js
new file mode 100644
index 00000000..85d50d47
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["it"] = [
+ "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/timeline.js
new file mode 100644
index 00000000..69582dc6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/it/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["it"] = {
+ wikiLinkLabel: "Discuti"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/labellers.js
new file mode 100644
index 00000000..007c91ba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/labellers.js
@@ -0,0 +1,11 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+/* The Dutch do not capitalize months
+*/
+
+Timeline.GregorianDateLabeller.monthNames["nl"] = [
+ "jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/timeline.js
new file mode 100644
index 00000000..e2799e38
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/nl/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["nl"] = {
+ wikiLinkLabel: "Discussieer"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/labellers.js
new file mode 100644
index 00000000..b6d0c1f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["pt_BR"] = [
+ "Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"
+];
+
+Timeline.GregorianDateLabeller.dayNames["pt_BR"] = [
+ "Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/timeline.js
new file mode 100644
index 00000000..02f08119
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/pt_BR/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["pt_BR"] = {
+ wikiLinkLabel: "Discutir"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/labellers.js
new file mode 100644
index 00000000..1ca79037
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/labellers.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Localization of labellers.js
+ *
+ * UTF-8 encoded
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["ru"] = [
+ "Янв", "Фев", "Мар", "Ðпр", "Май", "Июн", "Июл", "Ðвг", "Сен", "Окт", "ÐоÑ", "Дек"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/timeline.js
new file mode 100644
index 00000000..ed3e5894
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/ru/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["ru"] = {
+ wikiLinkLabel: "обÑудите"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/labellers.js
new file mode 100644
index 00000000..4b38cb13
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["se"] = [
+ "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"
+];
+
+Timeline.GregorianDateLabeller.dayNames["se"] = [
+ "Sön", "Mån", "Tis", "Ons", "Tors", "Fre", "Lör"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/timeline.js
new file mode 100644
index 00000000..31751ac1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/se/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["se"] = {
+ wikiLinkLabel: "Discuss"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/labellers.js
new file mode 100644
index 00000000..5d4dd72f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["tr"] = [
+ "Ock", "Åžbt", "Mrt", "Nsn", "Mys", "Hzr", "Tem", "AÄŸs", "Eyl", "Ekm", "Ksm", "Arl"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/timeline.js
new file mode 100644
index 00000000..696dc34e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/tr/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["tr"] = {
+ wikiLinkLabel: "Tartış"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/labellers.js
new file mode 100644
index 00000000..6cd57fda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/labellers.js
@@ -0,0 +1,26 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["vi"] = [
+ "Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["vi"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = date2.getUTCDate() + "/" + (date2.getUTCMonth() + 1);
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/timeline.js
new file mode 100644
index 00000000..2d5b3bd4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/vi/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["vi"] = {
+ wikiLinkLabel: "Bàn luận"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/labellers.js
new file mode 100644
index 00000000..9fc881b6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/labellers.js
@@ -0,0 +1,27 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["zh"] = [
+ "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["zh"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = Timeline.GregorianDateLabeller.getMonthName(date2.getUTCMonth(), this._locale) +
+ date2.getUTCDate() + "æ—¥";
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/timeline.js
new file mode 100644
index 00000000..7d6c7f94
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/l10n/zh/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["zh"] = {
+ wikiLinkLabel: "讨论"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/labellers.js
new file mode 100644
index 00000000..284d5a82
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/labellers.js
@@ -0,0 +1,91 @@
+/*==================================================
+ * Gregorian Date Labeller
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller = function(locale, timeZone) {
+ this._locale = locale;
+ this._timeZone = timeZone;
+};
+
+Timeline.GregorianDateLabeller.monthNames = [];
+Timeline.GregorianDateLabeller.dayNames = [];
+Timeline.GregorianDateLabeller.labelIntervalFunctions = [];
+
+Timeline.GregorianDateLabeller.getMonthName = function(month, locale) {
+ return Timeline.GregorianDateLabeller.monthNames[locale][month];
+};
+
+Timeline.GregorianDateLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var f = Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+ if (f == null) {
+ f = Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+ }
+ return f.call(this, date, intervalUnit);
+};
+
+Timeline.GregorianDateLabeller.prototype.labelPrecise = function(date) {
+ return SimileAjax.DateTime.removeTimeZoneOffset(
+ date,
+ this._timeZone //+ (new Date().getTimezoneOffset() / 60)
+ ).toUTCString();
+};
+
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ date = SimileAjax.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case SimileAjax.DateTime.MILLISECOND:
+ text = date.getUTCMilliseconds();
+ break;
+ case SimileAjax.DateTime.SECOND:
+ text = date.getUTCSeconds();
+ break;
+ case SimileAjax.DateTime.MINUTE:
+ var m = date.getUTCMinutes();
+ if (m == 0) {
+ text = date.getUTCHours() + ":00";
+ emphasized = true;
+ } else {
+ text = m;
+ }
+ break;
+ case SimileAjax.DateTime.HOUR:
+ text = date.getUTCHours() + "hr";
+ break;
+ case SimileAjax.DateTime.DAY:
+ text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+ break;
+ case SimileAjax.DateTime.WEEK:
+ text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+ break;
+ case SimileAjax.DateTime.MONTH:
+ var m = date.getUTCMonth();
+ if (m != 0) {
+ text = Timeline.GregorianDateLabeller.getMonthName(m, this._locale);
+ break;
+ } // else, fall through
+ case SimileAjax.DateTime.YEAR:
+ case SimileAjax.DateTime.DECADE:
+ case SimileAjax.DateTime.CENTURY:
+ case SimileAjax.DateTime.MILLENNIUM:
+ var y = date.getUTCFullYear();
+ if (y > 0) {
+ text = date.getUTCFullYear();
+ } else {
+ text = (1 - y) + "BC";
+ }
+ emphasized =
+ (intervalUnit == SimileAjax.DateTime.MONTH) ||
+ (intervalUnit == SimileAjax.DateTime.DECADE && y % 100 == 0) ||
+ (intervalUnit == SimileAjax.DateTime.CENTURY && y % 1000 == 0);
+ break;
+ default:
+ text = date.toUTCString();
+ }
+ return { text: text, emphasized: emphasized };
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/original-painter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/original-painter.js
new file mode 100644
index 00000000..323749f0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/original-painter.js
@@ -0,0 +1,700 @@
+/*==================================================
+ * Original Event Painter
+ *==================================================
+ */
+
+/*==================================================
+ *
+ * To enable a single event listener to monitor everything
+ * on a Timeline, we need a way to map from an event's icon,
+ * label or tape element to the associated timeline, band and
+ * specific event.
+ *
+ * Thus a set format is used for the id's of the
+ * events' elements on the Timeline--
+ *
+ * element id format for labels, icons, tapes:
+ * labels: label-tl-<timelineID>-<band_index>-<evt.id>
+ * icons: icon-tl-<timelineID>-<band_index>-<evt.id>
+ * tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
+ * tape2-tl-<timelineID>-<band_index>-<evt.id>
+ * // some events have more than one tape
+ * highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
+ * highlight2-tl-<timelineID>-<band_index>-<evt.id>
+ * // some events have more than one highlight div (future)
+ * You can then retrieve the band/timeline objects and event object
+ * by using Timeline.EventUtils.decodeEventElID
+ *
+ *==================================================
+ */
+
+/*
+ * eventPaintListener functions receive calls about painting.
+ * function(band, op, evt, els)
+ * context: 'this' will be an OriginalEventPainter object.
+ * It has properties and methods for obtaining
+ * the relevant band, timeline, etc
+ * band = the band being painted
+ * op = 'paintStarting' // the painter is about to remove
+ * all previously painted events, if any. It will
+ * then start painting all of the visible events that
+ * pass the filter.
+ * evt = null, els = null
+ * op = 'paintEnded' // the painter has finished painting
+ * all of the visible events that passed the filter
+ * evt = null, els = null
+ * op = 'paintedEvent' // the painter just finished painting an event
+ * evt = event just painted
+ * els = array of painted elements' divs. Depending on the event,
+ * the array could be just a tape or icon (if no label).
+ * Or could include label, multiple tape divs (imprecise event),
+ * highlight divs. The array is not ordered. The meaning of
+ * each el is available by decoding the el's id
+ * Note that there may be no paintedEvent calls if no events were visible
+ * or passed the filter.
+ */
+
+Timeline.OriginalEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+ this._eventPaintListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
+
+ this._eventIdToElmt = {};
+};
+
+Timeline.OriginalEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backLayer = null;
+ this._eventLayer = null;
+ this._lineLayer = null;
+ this._highlightLayer = null;
+
+ this._eventIdToElmt = null;
+};
+
+Timeline.OriginalEventPainter.prototype.getType = function() {
+ return 'original';
+};
+
+Timeline.OriginalEventPainter.prototype.supportsOrthogonalScrolling = function() {
+ return true;
+};
+
+Timeline.OriginalEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.OriginalEventPainter.prototype.addEventPaintListener = function(listener) {
+ this._eventPaintListeners.push(listener);
+};
+
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener = function(listener) {
+ for (var i = 0; i < this._eventPaintListeners.length; i++) {
+ if (this._eventPaintListeners[i] == listener) {
+ this._eventPaintListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.OriginalEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.paint = function() {
+ // Paints the events for a given section of the band--what is
+ // visible on screen and some extra.
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._eventIdToElmt = {};
+ this._fireEventPaintListeners('paintStarting', null, null);
+ this._prepareForPainting();
+
+ var metrics = this._computeMetrics();
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+ // update the band object for max number of tracks in this section of the ether
+ this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
+ this._fireEventPaintListeners('paintEnded', null, null);
+
+ this._setOrthogonalOffset(metrics);
+};
+
+Timeline.OriginalEventPainter.prototype.softPaint = function() {
+ this._setOrthogonalOffset(this._computeMetrics());
+};
+
+Timeline.OriginalEventPainter.prototype.getOrthogonalExtent = function() {
+ var metrics = this._computeMetrics();
+ return 2 * metrics.trackOffset + this._tracks.length * metrics.trackIncrement;
+};
+
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset = function(metrics) {
+ var orthogonalOffset = this._band.getViewOrthogonalOffset();
+
+ this._highlightLayer.style.top =
+ this._lineLayer.style.top =
+ this._eventLayer.style.top =
+ orthogonalOffset + "px";
+};
+
+Timeline.OriginalEventPainter.prototype._computeMetrics = function() {
+ var eventTheme = this._params.theme.event;
+ var trackHeight = Math.max(eventTheme.track.height, eventTheme.tape.height +
+ this._frc.getLineHeight());
+ var metrics = {
+ trackOffset: eventTheme.track.offset,
+ trackHeight: trackHeight,
+ trackGap: eventTheme.track.gap,
+ trackIncrement: trackHeight + eventTheme.track.gap,
+ icon: eventTheme.instant.icon,
+ iconWidth: eventTheme.instant.iconWidth,
+ iconHeight: eventTheme.instant.iconHeight,
+ labelWidth: eventTheme.label.width,
+ maxLabelChar: eventTheme.label.maxLabelChar,
+ impreciseIconMargin: eventTheme.instant.impreciseIconMargin
+ };
+
+ return metrics;
+};
+
+Timeline.OriginalEventPainter.prototype._prepareForPainting = function() {
+ // Remove everything previously painted: highlight, line and event layers.
+ // Prepare blank layers for painting.
+ var band = this._band;
+
+ if (this._backLayer == null) {
+ this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+ this._backLayer.style.visibility = "hidden";
+
+ var eventLabelPrototype = document.createElement("span");
+ eventLabelPrototype.className = "timeline-event-label";
+ this._backLayer.appendChild(eventLabelPrototype);
+ this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+ }
+ this._frc.update();
+ this._tracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._lineLayer != null) {
+ band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+ this._lineLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.OriginalEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.OriginalEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.OriginalEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelDivClassName = this._getLabelDivClassName(evt);
+ var labelSize = this._frc.computeSize(text, labelDivClassName);
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelRight = labelLeft + labelSize.width;
+
+ var rightEdge = labelRight;
+ var track = this._findFreeTrack(evt, rightEdge);
+
+ var labelTop = Math.round(
+ metrics.trackOffset + track * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, 0);
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+ labelSize.height, theme, labelDivClassName, highlightIndex);
+ var els = [iconElmtData.elmt, labelElmtData.elmt];
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
+ if (hDiv != null) {els.push(hDiv);}
+ this._fireEventPaintListeners('paintedEvent', evt, els);
+
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+ this._tracks[track] = iconLeftEdge;
+};
+
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelDivClassName = this._getLabelDivClassName(evt);
+ var labelSize = this._frc.computeSize(text, labelDivClassName);
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelRight = labelLeft + labelSize.width;
+
+ var rightEdge = Math.max(labelRight, endPixel);
+ var track = this._findFreeTrack(evt, rightEdge);
+ var tapeHeight = theme.event.tape.height;
+ var labelTop = Math.round(
+ metrics.trackOffset + track * metrics.trackIncrement + tapeHeight);
+
+ var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, tapeHeight);
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+ labelSize.height, theme, labelDivClassName, highlightIndex);
+
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.instant.impreciseColor;
+
+ var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
+ color, theme.event.instant.impreciseOpacity, metrics, theme, 0);
+ var els = [iconElmtData.elmt, labelElmtData.elmt, tapeElmtData.elmt];
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
+ if (hDiv != null) {els.push(hDiv);}
+ this._fireEventPaintListeners('paintedEvent', evt, els);
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+ this._tracks[track] = iconLeftEdge;
+};
+
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var labelDivClassName = this._getLabelDivClassName(evt);
+ var labelSize = this._frc.computeSize(text, labelDivClassName);
+ var labelLeft = startPixel;
+ var labelRight = labelLeft + labelSize.width;
+
+ var rightEdge = Math.max(labelRight, endPixel);
+ var track = this._findFreeTrack(evt, rightEdge);
+ var labelTop = Math.round(
+ metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
+
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel, color, 100, metrics, theme, 0);
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+ labelSize.height, theme, labelDivClassName, highlightIndex);
+ var els = [tapeElmtData.elmt, labelElmtData.elmt];
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
+ if (hDiv != null) {els.push(hDiv);}
+ this._fireEventPaintListeners('paintedEvent', evt, els);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+ this._tracks[track] = startPixel;
+};
+
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var latestStartDate = evt.getLatestStart();
+ var endDate = evt.getEnd();
+ var earliestEndDate = evt.getEarliestEnd();
+
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+ var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+ var labelDivClassName = this._getLabelDivClassName(evt);
+ var labelSize = this._frc.computeSize(text, labelDivClassName);
+ var labelLeft = latestStartPixel;
+ var labelRight = labelLeft + labelSize.width;
+
+ var rightEdge = Math.max(labelRight, endPixel);
+ var track = this._findFreeTrack(evt, rightEdge);
+ var labelTop = Math.round(
+ metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
+
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ // Imprecise events can have two event tapes
+ // The imprecise dates tape, uses opacity to be dimmer than precise dates
+ var impreciseTapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
+ theme.event.duration.impreciseColor,
+ theme.event.duration.impreciseOpacity, metrics, theme, 0);
+ // The precise dates tape, regular (100%) opacity
+ var tapeElmtData = this._paintEventTape(evt, track, latestStartPixel,
+ earliestEndPixel, color, 100, metrics, theme, 1);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop,
+ labelSize.width, labelSize.height, theme, labelDivClassName, highlightIndex);
+ var els = [impreciseTapeElmtData.elmt, tapeElmtData.elmt, labelElmtData.elmt];
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
+ if (hDiv != null) {els.push(hDiv);}
+ this._fireEventPaintListeners('paintedEvent', evt, els);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+ this._tracks[track] = startPixel;
+};
+
+Timeline.OriginalEventPainter.prototype._encodeEventElID = function(elType, evt) {
+ return Timeline.EventUtils.encodeEventElID(this._timeline, this._band, elType, evt);
+};
+
+Timeline.OriginalEventPainter.prototype._findFreeTrack = function(event, rightEdge) {
+ var trackAttribute = event.getTrackNum();
+ if (trackAttribute != null) {
+ return trackAttribute; // early return since event includes track number
+ }
+
+ // normal case: find an open track
+ for (var i = 0; i < this._tracks.length; i++) {
+ var t = this._tracks[i];
+ if (t > rightEdge) {
+ break;
+ }
+ }
+ return i;
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme, tapeHeight) {
+ // If no tape, then paint the icon in the middle of the track.
+ // If there is a tape, paint the icon below the tape + impreciseIconMargin
+ var icon = evt.getIcon();
+ icon = icon != null ? icon : metrics.icon;
+
+ var top; // top of the icon
+ if (tapeHeight > 0) {
+ top = metrics.trackOffset + iconTrack * metrics.trackIncrement +
+ tapeHeight + metrics.impreciseIconMargin;
+ } else {
+ var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2;
+ top = Math.round(middle - metrics.iconHeight / 2);
+ }
+ var img = SimileAjax.Graphics.createTranslucentImage(icon);
+ var iconDiv = this._timeline.getDocument().createElement("div");
+ iconDiv.className = this._getElClassName('timeline-event-icon', evt, 'icon');
+ iconDiv.id = this._encodeEventElID('icon', evt);
+ iconDiv.style.left = left + "px";
+ iconDiv.style.top = top + "px";
+ iconDiv.appendChild(img);
+
+ if(evt._title != null)
+ iconDiv.title = evt._title;
+
+ this._eventLayer.appendChild(iconDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: metrics.iconWidth,
+ height: metrics.iconHeight,
+ elmt: iconDiv
+ };
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width,
+ height, theme, labelDivClassName, highlightIndex) {
+ var doc = this._timeline.getDocument();
+
+ var labelDiv = doc.createElement("div");
+ labelDiv.className = labelDivClassName;
+ labelDiv.id = this._encodeEventElID('label', evt);
+ labelDiv.style.left = left + "px";
+ labelDiv.style.width = width + "px";
+ labelDiv.style.top = top + "px";
+ labelDiv.innerHTML = text;
+
+ if(evt._title != null)
+ labelDiv.title = evt._title;
+
+ var color = evt.getTextColor();
+ if (color == null) {
+ color = evt.getColor();
+ }
+ if (color != null) {
+ labelDiv.style.color = color;
+ }
+ if (theme.event.highlightLabelBackground && highlightIndex >= 0) {
+ labelDiv.style.background = this._getHighlightColor(highlightIndex, theme);
+ }
+
+ this._eventLayer.appendChild(labelDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: labelDiv
+ };
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventTape = function(
+ evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme, tape_index) {
+
+ var tapeWidth = endPixel - startPixel;
+ var tapeHeight = theme.event.tape.height;
+ var top = metrics.trackOffset + iconTrack * metrics.trackIncrement;
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.className = this._getElClassName('timeline-event-tape', evt, 'tape');
+ tapeDiv.id = this._encodeEventElID('tape' + tape_index, evt);
+ tapeDiv.style.left = startPixel + "px";
+ tapeDiv.style.width = tapeWidth + "px";
+ tapeDiv.style.height = tapeHeight + "px";
+ tapeDiv.style.top = top + "px";
+
+ if(evt._title != null)
+ tapeDiv.title = evt._title;
+
+ if(color != null) {
+ tapeDiv.style.backgroundColor = color;
+ }
+
+ var backgroundImage = evt.getTapeImage();
+ var backgroundRepeat = evt.getTapeRepeat();
+ backgroundRepeat = backgroundRepeat != null ? backgroundRepeat : 'repeat';
+ if(backgroundImage != null) {
+ tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
+ tapeDiv.style.backgroundRepeat = backgroundRepeat;
+ }
+
+ SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: startPixel,
+ top: top,
+ width: tapeWidth,
+ height: tapeHeight,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName = function(evt) {
+ return this._getElClassName('timeline-event-label', evt, 'label');
+};
+
+Timeline.OriginalEventPainter.prototype._getElClassName = function(elClassName, evt, prefix) {
+ // Prefix and '_' is added to the event's classname. Set to null for no prefix
+ var evt_classname = evt.getClassName(),
+ pieces = [];
+
+ if (evt_classname) {
+ if (prefix) {pieces.push(prefix + '-' + evt_classname + ' ');}
+ pieces.push(evt_classname + ' ');
+ }
+ pieces.push(elClassName);
+ return(pieces.join(''));
+};
+
+Timeline.OriginalEventPainter.prototype._getHighlightColor = function(highlightIndex, theme) {
+ var highlightColors = theme.event.highlightColors;
+ return highlightColors[Math.min(highlightIndex, highlightColors.length - 1)];
+};
+
+Timeline.OriginalEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme, evt) {
+ var div = null;
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var color = this._getHighlightColor(highlightIndex, theme);
+
+ div = doc.createElement("div");
+ div.className = this._getElClassName('timeline-event-highlight', evt, 'highlight');
+ div.id = this._encodeEventElID('highlight0', evt); // in future will have other
+ // highlight divs for tapes + icons
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 2) + "px";
+ div.style.width = (dimensions.width + 4) + "px";
+ div.style.top = (dimensions.top - 2) + "px";
+ div.style.height = (dimensions.height + 4) + "px";
+ div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+ return div;
+};
+
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ evt
+ );
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = SimileAjax.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, evt);
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.OriginalEventPainter.prototype.showBubble = function(evt) {
+ var elmt = this._eventIdToElmt[evt.getID()];
+ if (elmt) {
+ var c = SimileAjax.DOM.getPageCoordinates(elmt);
+ this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
+ }
+};
+
+Timeline.OriginalEventPainter.prototype._showBubble = function(x, y, evt) {
+ var div = document.createElement("div");
+ var themeBubble = this._params.theme.event.bubble;
+ evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
+ themeBubble.width, null, themeBubble.maxHeight);
+};
+
+Timeline.OriginalEventPainter.prototype._fireOnSelect = function(eventID) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ this._onSelectListeners[i](eventID);
+ }
+};
+
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners = function(op, evt, els) {
+ for (var i = 0; i < this._eventPaintListeners.length; i++) {
+ this._eventPaintListeners[i](this._band, op, evt, els);
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/overview-painter.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/overview-painter.js
new file mode 100644
index 00000000..37af92d8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/overview-painter.js
@@ -0,0 +1,258 @@
+/*==================================================
+ * Overview Event Painter
+ *==================================================
+ */
+
+Timeline.OverviewEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+};
+
+Timeline.OverviewEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._eventLayer = null;
+ this._highlightLayer = null;
+};
+
+Timeline.OverviewEventPainter.prototype.getType = function() {
+ return 'overview';
+};
+
+Timeline.OverviewEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.OverviewEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._prepareForPainting();
+
+ var eventTheme = this._params.theme.event;
+ var metrics = {
+ trackOffset: eventTheme.overviewTrack.offset,
+ trackHeight: eventTheme.overviewTrack.height,
+ trackGap: eventTheme.overviewTrack.gap,
+ trackIncrement: eventTheme.overviewTrack.height + eventTheme.overviewTrack.gap
+ }
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+ // update the band object for max number of tracks in this section of the ether
+ this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
+};
+
+Timeline.OverviewEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.OverviewEventPainter.prototype._prepareForPainting = function() {
+ var band = this._band;
+
+ this._tracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.OverviewEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.OverviewEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var startDate = evt.getStart();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+
+ var color = evt.getColor(),
+ klassName = evt.getClassName();
+ if (klassName) {
+ color = null;
+ } else {
+ color = color != null ? color : theme.event.duration.color;
+ }
+
+ var tickElmtData = this._paintEventTick(evt, startPixel, color, 100, metrics, theme);
+
+ this._createHighlightDiv(highlightIndex, tickElmtData, theme);
+};
+
+Timeline.OverviewEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var latestStartDate = evt.getLatestStart();
+ var earliestEndDate = evt.getEarliestEnd();
+
+ var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+ var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+ var tapeTrack = 0;
+ for (; tapeTrack < this._tracks.length; tapeTrack++) {
+ if (earliestEndPixel < this._tracks[tapeTrack]) {
+ break;
+ }
+ }
+ this._tracks[tapeTrack] = earliestEndPixel;
+
+ var color = evt.getColor(),
+ klassName = evt.getClassName();
+ if (klassName) {
+ color = null;
+ } else {
+ color = color != null ? color : theme.event.duration.color;
+ }
+
+ var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel,
+ color, 100, metrics, theme, klassName);
+
+ this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+};
+
+Timeline.OverviewEventPainter.prototype._paintEventTape = function(
+ evt, track, left, right, color, opacity, metrics, theme, klassName) {
+
+ var top = metrics.trackOffset + track * metrics.trackIncrement;
+ var width = right - left;
+ var height = metrics.trackHeight;
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.className = 'timeline-small-event-tape'
+ if (klassName) {tapeDiv.className += ' small-' + klassName;}
+ tapeDiv.style.left = left + "px";
+ tapeDiv.style.width = width + "px";
+ tapeDiv.style.top = top + "px";
+ tapeDiv.style.height = height + "px";
+
+ if (color) {
+ tapeDiv.style.backgroundColor = color; // set color here if defined by event. Else use css
+ }
+ // tapeDiv.style.overflow = "hidden"; // now set in css
+ // tapeDiv.style.position = "absolute";
+ if(opacity<100) SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.OverviewEventPainter.prototype._paintEventTick = function(
+ evt, left, color, opacity, metrics, theme) {
+
+ var height = theme.event.overviewTrack.tickHeight;
+ var top = metrics.trackOffset - height;
+ var width = 1;
+
+ var tickDiv = this._timeline.getDocument().createElement("div");
+ tickDiv.className = 'timeline-small-event-icon'
+ tickDiv.style.left = left + "px";
+ tickDiv.style.top = top + "px";
+ // tickDiv.style.width = width + "px";
+ // tickDiv.style.position = "absolute";
+ // tickDiv.style.height = height + "px";
+ // tickDiv.style.backgroundColor = color;
+ // tickDiv.style.overflow = "hidden";
+
+ var klassName = evt.getClassName()
+ if (klassName) {tickDiv.className +=' small-' + klassName}
+
+ if(opacity<100) {SimileAjax.Graphics.setOpacity(tickDiv, opacity)};
+
+ this._eventLayer.appendChild(tickDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: tickDiv
+ };
+}
+
+Timeline.OverviewEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var eventTheme = theme.event;
+
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 1) + "px";
+ div.style.width = (dimensions.width + 2) + "px";
+ div.style.top = (dimensions.top - 1) + "px";
+ div.style.height = (dimensions.height + 2) + "px";
+ div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+};
+
+Timeline.OverviewEventPainter.prototype.showBubble = function(evt) {
+ // not implemented
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/sources.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/sources.js
new file mode 100644
index 00000000..29df903f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/sources.js
@@ -0,0 +1,583 @@
+/*==================================================
+ * Default Event Source
+ *==================================================
+ */
+
+
+Timeline.DefaultEventSource = function(eventIndex) {
+ this._events = (eventIndex instanceof Object) ? eventIndex : new SimileAjax.EventIndex();
+ this._listeners = [];
+};
+
+Timeline.DefaultEventSource.prototype.addListener = function(listener) {
+ this._listeners.push(listener);
+};
+
+Timeline.DefaultEventSource.prototype.removeListener = function(listener) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ if (this._listeners[i] == listener) {
+ this._listeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.DefaultEventSource.prototype.loadXML = function(xml, url) {
+ var base = this._getBaseURL(url);
+
+ var wikiURL = xml.documentElement.getAttribute("wiki-url");
+ var wikiSection = xml.documentElement.getAttribute("wiki-section");
+
+ var dateTimeFormat = xml.documentElement.getAttribute("date-time-format");
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ var node = xml.documentElement.firstChild;
+ var added = false;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ var description = "";
+ if (node.firstChild != null && node.firstChild.nodeType == 3) {
+ description = node.firstChild.nodeValue;
+ }
+ // instant event: default is true. Or use values from isDuration or durationEvent
+ var instant = (node.getAttribute("isDuration") === null &&
+ node.getAttribute("durationEvent") === null) ||
+ node.getAttribute("isDuration") == "false" ||
+ node.getAttribute("durationEvent") == "false";
+
+ var evt = new Timeline.DefaultEventSource.Event( {
+ id: node.getAttribute("id"),
+ start: parseDateTimeFunction(node.getAttribute("start")),
+ end: parseDateTimeFunction(node.getAttribute("end")),
+ latestStart: parseDateTimeFunction(node.getAttribute("latestStart")),
+ earliestEnd: parseDateTimeFunction(node.getAttribute("earliestEnd")),
+ instant: instant,
+ text: node.getAttribute("title"),
+ description: description,
+ image: this._resolveRelativeURL(node.getAttribute("image"), base),
+ link: this._resolveRelativeURL(node.getAttribute("link") , base),
+ icon: this._resolveRelativeURL(node.getAttribute("icon") , base),
+ color: node.getAttribute("color"),
+ textColor: node.getAttribute("textColor"),
+ hoverText: node.getAttribute("hoverText"),
+ classname: node.getAttribute("classname"),
+ tapeImage: node.getAttribute("tapeImage"),
+ tapeRepeat: node.getAttribute("tapeRepeat"),
+ caption: node.getAttribute("caption"),
+ eventID: node.getAttribute("eventID"),
+ trackNum: node.getAttribute("trackNum")
+ });
+
+ evt._node = node;
+ evt.getProperty = function(name) {
+ return this._node.getAttribute(name);
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+
+ added = true;
+ }
+ node = node.nextSibling;
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+
+Timeline.DefaultEventSource.prototype.loadJSON = function(data, url) {
+ var base = this._getBaseURL(url);
+ var added = false;
+ if (data && data.events){
+ var wikiURL = ("wikiURL" in data) ? data.wikiURL : null;
+ var wikiSection = ("wikiSection" in data) ? data.wikiSection : null;
+
+ var dateTimeFormat = ("dateTimeFormat" in data) ? data.dateTimeFormat : null;
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ for (var i=0; i < data.events.length; i++){
+ var evnt = data.events[i];
+
+ // New feature: attribute synonyms. The following attribute names are interchangable.
+ // The shorter names enable smaller load files.
+ // eid -- eventID
+ // s -- start
+ // e -- end
+ // ls -- latestStart
+ // ee -- earliestEnd
+ // d -- description
+ // de -- durationEvent
+ // t -- title,
+ // c -- classname
+
+ // Fixing issue 33:
+ // instant event: default (for JSON only) is false. Or use values from isDuration or durationEvent
+ // isDuration was negated (see issue 33, so keep that interpretation
+ var instant = evnt.isDuration ||
+ (('durationEvent' in evnt) && !evnt.durationEvent) ||
+ (('de' in evnt) && !evnt.de);
+ var evt = new Timeline.DefaultEventSource.Event({
+ id: ("id" in evnt) ? evnt.id : undefined,
+ start: parseDateTimeFunction(evnt.start || evnt.s),
+ end: parseDateTimeFunction(evnt.end || evnt.e),
+ latestStart: parseDateTimeFunction(evnt.latestStart || evnt.ls),
+ earliestEnd: parseDateTimeFunction(evnt.earliestEnd || evnt.ee),
+ instant: instant,
+ text: evnt.title || evnt.t,
+ description: evnt.description || evnt.d,
+ image: this._resolveRelativeURL(evnt.image, base),
+ link: this._resolveRelativeURL(evnt.link , base),
+ icon: this._resolveRelativeURL(evnt.icon , base),
+ color: evnt.color,
+ textColor: evnt.textColor,
+ hoverText: evnt.hoverText,
+ classname: evnt.classname || evnt.c,
+ tapeImage: evnt.tapeImage,
+ tapeRepeat: evnt.tapeRepeat,
+ caption: evnt.caption,
+ eventID: evnt.eventID || evnt.eid,
+ trackNum: evnt.trackNum
+ });
+ evt._obj = evnt;
+ evt.getProperty = function(name) {
+ return this._obj[name];
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+ added = true;
+ }
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+/*
+ * Contributed by Morten Frederiksen, http://www.wasab.dk/morten/
+ */
+Timeline.DefaultEventSource.prototype.loadSPARQL = function(xml, url) {
+ var base = this._getBaseURL(url);
+
+ var dateTimeFormat = 'iso8601';
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ if (xml == null) {
+ return;
+ }
+
+ /*
+ * Find <results> tag
+ */
+ var node = xml.documentElement.firstChild;
+ while (node != null && (node.nodeType != 1 || node.nodeName != 'results')) {
+ node = node.nextSibling;
+ }
+
+ var wikiURL = null;
+ var wikiSection = null;
+ if (node != null) {
+ wikiURL = node.getAttribute("wiki-url");
+ wikiSection = node.getAttribute("wiki-section");
+
+ node = node.firstChild;
+ }
+
+ var added = false;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ var bindings = { };
+ var binding = node.firstChild;
+ while (binding != null) {
+ if (binding.nodeType == 1 &&
+ binding.firstChild != null &&
+ binding.firstChild.nodeType == 1 &&
+ binding.firstChild.firstChild != null &&
+ binding.firstChild.firstChild.nodeType == 3) {
+ bindings[binding.getAttribute('name')] = binding.firstChild.firstChild.nodeValue;
+ }
+ binding = binding.nextSibling;
+ }
+
+ if (bindings["start"] == null && bindings["date"] != null) {
+ bindings["start"] = bindings["date"];
+ }
+
+ // instant event: default is true. Or use values from isDuration or durationEvent
+ var instant = (bindings["isDuration"] === null &&
+ bindings["durationEvent"] === null) ||
+ bindings["isDuration"] == "false" ||
+ bindings["durationEvent"] == "false";
+
+ var evt = new Timeline.DefaultEventSource.Event({
+ id: bindings["id"],
+ start: parseDateTimeFunction(bindings["start"]),
+ end: parseDateTimeFunction(bindings["end"]),
+ latestStart: parseDateTimeFunction(bindings["latestStart"]),
+ earliestEnd: parseDateTimeFunction(bindings["earliestEnd"]),
+ instant: instant, // instant
+ text: bindings["title"], // text
+ description: bindings["description"],
+ image: this._resolveRelativeURL(bindings["image"], base),
+ link: this._resolveRelativeURL(bindings["link"] , base),
+ icon: this._resolveRelativeURL(bindings["icon"] , base),
+ color: bindings["color"],
+ textColor: bindings["textColor"],
+ hoverText: bindings["hoverText"],
+ caption: bindings["caption"],
+ classname: bindings["classname"],
+ tapeImage: bindings["tapeImage"],
+ tapeRepeat: bindings["tapeRepeat"],
+ eventID: bindings["eventID"],
+ trackNum: bindings["trackNum"]
+ });
+ evt._bindings = bindings;
+ evt.getProperty = function(name) {
+ return this._bindings[name];
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+ added = true;
+ }
+ node = node.nextSibling;
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+Timeline.DefaultEventSource.prototype.add = function(evt) {
+ this._events.add(evt);
+ this._fire("onAddOne", [evt]);
+};
+
+Timeline.DefaultEventSource.prototype.addMany = function(events) {
+ for (var i = 0; i < events.length; i++) {
+ this._events.add(events[i]);
+ }
+ this._fire("onAddMany", []);
+};
+
+Timeline.DefaultEventSource.prototype.clear = function() {
+ this._events.removeAll();
+ this._fire("onClear", []);
+};
+
+Timeline.DefaultEventSource.prototype.getEvent = function(id) {
+ return this._events.getEvent(id);
+};
+
+Timeline.DefaultEventSource.prototype.getEventIterator = function(startDate, endDate) {
+ return this._events.getIterator(startDate, endDate);
+};
+
+Timeline.DefaultEventSource.prototype.getEventReverseIterator = function(startDate, endDate) {
+ return this._events.getReverseIterator(startDate, endDate);
+};
+
+Timeline.DefaultEventSource.prototype.getAllEventIterator = function() {
+ return this._events.getAllIterator();
+};
+
+Timeline.DefaultEventSource.prototype.getCount = function() {
+ return this._events.getCount();
+};
+
+Timeline.DefaultEventSource.prototype.getEarliestDate = function() {
+ return this._events.getEarliestDate();
+};
+
+Timeline.DefaultEventSource.prototype.getLatestDate = function() {
+ return this._events.getLatestDate();
+};
+
+Timeline.DefaultEventSource.prototype._fire = function(handlerName, args) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ var listener = this._listeners[i];
+ if (handlerName in listener) {
+ try {
+ listener[handlerName].apply(listener, args);
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+ }
+};
+
+Timeline.DefaultEventSource.prototype._getBaseURL = function(url) {
+ if (url.indexOf("://") < 0) {
+ var url2 = this._getBaseURL(document.location.href);
+ if (url.substr(0,1) == "/") {
+ url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
+ } else {
+ url = url2 + url;
+ }
+ }
+
+ var i = url.lastIndexOf("/");
+ if (i < 0) {
+ return "";
+ } else {
+ return url.substr(0, i+1);
+ }
+};
+
+Timeline.DefaultEventSource.prototype._resolveRelativeURL = function(url, base) {
+ if (url == null || url == "") {
+ return url;
+ } else if (url.indexOf("://") > 0) {
+ return url;
+ } else if (url.substr(0,1) == "/") {
+ return base.substr(0, base.indexOf("/", base.indexOf("://") + 3)) + url;
+ } else {
+ return base + url;
+ }
+};
+
+
+Timeline.DefaultEventSource.Event = function(args) {
+ //
+ // Attention developers!
+ // If you add a new event attribute, please be sure to add it to
+ // all three load functions: loadXML, loadSPARCL, loadJSON.
+ // Thanks!
+ //
+ // args is a hash/object. It supports the following keys. Most are optional
+ // id -- an internal id. Really shouldn't be used by events.
+ // Timeline library clients should use eventID
+ // eventID -- For use by library client when writing custom painters or
+ // custom fillInfoBubble
+ // start
+ // end
+ // latestStart
+ // earliestEnd
+ // instant -- boolean. Controls precise/non-precise logic & duration/instant issues
+ // text -- event source attribute 'title' -- used as the label on Timelines and in bubbles.
+ // description -- used in bubbles
+ // image -- used in bubbles
+ // link -- used in bubbles
+ // icon -- on the Timeline
+ // color -- Timeline label and tape color
+ // textColor -- Timeline label color, overrides color attribute
+ // hoverText -- deprecated, here for backwards compatibility.
+ // Superceeded by caption
+ // caption -- tooltip-like caption on the Timeline. Uses HTML title attribute
+ // classname -- used to set classname in Timeline. Enables better CSS selector rules
+ // tapeImage -- background image of the duration event's tape div on the Timeline
+ // tapeRepeat -- repeat attribute for tapeImage. {repeat | repeat-x | repeat-y }
+
+ function cleanArg(arg) {
+ // clean up an arg
+ return (args[arg] != null && args[arg] != "") ? args[arg] : null;
+ }
+
+ var id = args.id ? args.id.trim() : "";
+ this._id = id.length > 0 ? id : Timeline.EventUtils.getNewEventID();
+
+ this._instant = args.instant || (args.end == null);
+
+ this._start = args.start;
+ this._end = (args.end != null) ? args.end : args.start;
+
+ this._latestStart = (args.latestStart != null) ?
+ args.latestStart : (args.instant ? this._end : this._start);
+ this._earliestEnd = (args.earliestEnd != null) ? args.earliestEnd : this._end;
+
+ // check sanity of dates since incorrect dates will later cause calculation errors
+ // when painting
+ var err=[];
+ if (this._start > this._latestStart) {
+ this._latestStart = this._start;
+ err.push("start is > latestStart");}
+ if (this._start > this._earliestEnd) {
+ this._earliestEnd = this._latestStart;
+ err.push("start is > earliestEnd");}
+ if (this._start > this._end) {
+ this._end = this._earliestEnd;
+ err.push("start is > end");}
+ if (this._latestStart > this._earliestEnd) {
+ this._earliestEnd = this._latestStart;
+ err.push("latestStart is > earliestEnd");}
+ if (this._latestStart > this._end) {
+ this._end = this._earliestEnd;
+ err.push("latestStart is > end");}
+ if (this._earliestEnd > this._end) {
+ this._end = this._earliestEnd;
+ err.push("earliestEnd is > end");}
+
+ this._eventID = cleanArg('eventID');
+ this._text = (args.text != null) ? SimileAjax.HTML.deEntify(args.text) : ""; // Change blank titles to ""
+ if (err.length > 0) {
+ this._text += " PROBLEM: " + err.join(", ");
+ }
+
+ this._description = SimileAjax.HTML.deEntify(args.description);
+ this._image = cleanArg('image');
+ this._link = cleanArg('link');
+ this._title = cleanArg('hoverText');
+ this._title = cleanArg('caption');
+
+ this._icon = cleanArg('icon');
+ this._color = cleanArg('color');
+ this._textColor = cleanArg('textColor');
+ this._classname = cleanArg('classname');
+ this._tapeImage = cleanArg('tapeImage');
+ this._tapeRepeat = cleanArg('tapeRepeat');
+ this._trackNum = cleanArg('trackNum');
+ if (this._trackNum != null) {
+ this._trackNum = parseInt(this._trackNum);
+ }
+
+ this._wikiURL = null;
+ this._wikiSection = null;
+};
+
+Timeline.DefaultEventSource.Event.prototype = {
+ getID: function() { return this._id; },
+
+ isInstant: function() { return this._instant; },
+ isImprecise: function() { return this._start != this._latestStart || this._end != this._earliestEnd; },
+
+ getStart: function() { return this._start; },
+ getEnd: function() { return this._end; },
+ getLatestStart: function() { return this._latestStart; },
+ getEarliestEnd: function() { return this._earliestEnd; },
+
+ getEventID: function() { return this._eventID; },
+ getText: function() { return this._text; }, // title
+ getDescription: function() { return this._description; },
+ getImage: function() { return this._image; },
+ getLink: function() { return this._link; },
+
+ getIcon: function() { return this._icon; },
+ getColor: function() { return this._color; },
+ getTextColor: function() { return this._textColor; },
+ getClassName: function() { return this._classname; },
+ getTapeImage: function() { return this._tapeImage; },
+ getTapeRepeat: function() { return this._tapeRepeat; },
+ getTrackNum: function() { return this._trackNum; },
+
+ getProperty: function(name) { return null; },
+
+ getWikiURL: function() { return this._wikiURL; },
+ getWikiSection: function() { return this._wikiSection; },
+ setWikiInfo: function(wikiURL, wikiSection) {
+ this._wikiURL = wikiURL;
+ this._wikiSection = wikiSection;
+ },
+
+ fillDescription: function(elmt) {
+ if (this._description) {
+ elmt.innerHTML = this._description;
+ }
+ },
+ fillWikiInfo: function(elmt) {
+ // Many bubbles will not support a wiki link.
+ //
+ // Strategy: assume no wiki link. If we do have
+ // enough parameters for one, then create it.
+ elmt.style.display = "none"; // default
+
+ if (this._wikiURL == null || this._wikiSection == null) {
+ return; // EARLY RETURN
+ }
+
+ // create the wikiID from the property or from the event text (the title)
+ var wikiID = this.getProperty("wikiID");
+ if (wikiID == null || wikiID.length == 0) {
+ wikiID = this.getText(); // use the title as the backup wiki id
+ }
+
+ if (wikiID == null || wikiID.length == 0) {
+ return; // No wikiID. Thus EARLY RETURN
+ }
+
+ // ready to go...
+ elmt.style.display = "inline";
+ wikiID = wikiID.replace(/\s/g, "_");
+ var url = this._wikiURL + this._wikiSection.replace(/\s/g, "_") + "/" + wikiID;
+ var a = document.createElement("a");
+ a.href = url;
+ a.target = "new";
+ a.innerHTML = Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+
+ elmt.appendChild(document.createTextNode("["));
+ elmt.appendChild(a);
+ elmt.appendChild(document.createTextNode("]"));
+ },
+
+ fillTime: function(elmt, labeller) {
+ if (this._instant) {
+ if (this.isImprecise()) {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+ } else {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ }
+ } else {
+ if (this.isImprecise()) {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(
+ labeller.labelPrecise(this._start) + " ~ " + labeller.labelPrecise(this._latestStart)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(
+ labeller.labelPrecise(this._earliestEnd) + " ~ " + labeller.labelPrecise(this._end)));
+ } else {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+ }
+ }
+ },
+
+ fillInfoBubble: function(elmt, theme, labeller) {
+ var doc = elmt.ownerDocument;
+
+ var title = this.getText();
+ var link = this.getLink();
+ var image = this.getImage();
+
+ if (image != null) {
+ var img = doc.createElement("img");
+ img.src = image;
+
+ theme.event.bubble.imageStyler(img);
+ elmt.appendChild(img);
+ }
+
+ var divTitle = doc.createElement("div");
+ var textTitle = doc.createTextNode(title);
+ if (link != null) {
+ var a = doc.createElement("a");
+ a.href = link;
+ a.appendChild(textTitle);
+ divTitle.appendChild(a);
+ } else {
+ divTitle.appendChild(textTitle);
+ }
+ theme.event.bubble.titleStyler(divTitle);
+ elmt.appendChild(divTitle);
+
+ var divBody = doc.createElement("div");
+ this.fillDescription(divBody);
+ theme.event.bubble.bodyStyler(divBody);
+ elmt.appendChild(divBody);
+
+ var divTime = doc.createElement("div");
+ this.fillTime(divTime, labeller);
+ theme.event.bubble.timeStyler(divTime);
+ elmt.appendChild(divTime);
+
+ var divWiki = doc.createElement("div");
+ this.fillWikiInfo(divWiki);
+ theme.event.bubble.wikiStyler(divWiki);
+ elmt.appendChild(divWiki);
+ }
+};
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/themes.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/themes.js
new file mode 100644
index 00000000..7c30f6a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/themes.js
@@ -0,0 +1,180 @@
+/*==================================================
+ * Classic Theme
+ *==================================================
+ */
+
+
+
+Timeline.ClassicTheme = new Object();
+
+Timeline.ClassicTheme.implementations = [];
+
+Timeline.ClassicTheme.create = function(locale) {
+ if (locale == null) {
+ locale = Timeline.getDefaultLocale();
+ }
+
+ var f = Timeline.ClassicTheme.implementations[locale];
+ if (f == null) {
+ f = Timeline.ClassicTheme._Impl;
+ }
+ return new f();
+};
+
+Timeline.ClassicTheme._Impl = function() {
+ this.firstDayOfWeek = 0; // Sunday
+
+ // Note: Many styles previously set here are now set using CSS
+ // The comments indicate settings controlled by CSS, not
+ // lines to be un-commented.
+ //
+ //
+ // Attributes autoWidth, autoWidthAnimationTime, timeline_start
+ // and timeline_stop must be set on the first band's theme.
+ // The other attributes can be set differently for each
+ // band by using different themes for the bands.
+ this.autoWidth = false; // Should the Timeline automatically grow itself, as
+ // needed when too many events for the available width
+ // are painted on the visible part of the Timeline?
+ this.autoWidthAnimationTime = 500; // mSec
+ this.timeline_start = null; // Setting a date, eg new Date(Date.UTC(2008,0,17,20,00,00,0)) will prevent the
+ // Timeline from being moved to anytime before the date.
+ this.timeline_stop = null; // Use for setting a maximum date. The Timeline will not be able
+ // to be moved to anytime after this date.
+ this.ether = {
+ backgroundColors: [
+ // "#EEE",
+ // "#DDD",
+ // "#CCC",
+ // "#AAA"
+ ],
+ // highlightColor: "white",
+ highlightOpacity: 50,
+ interval: {
+ line: {
+ show: true,
+ opacity: 25
+ // color: "#aaa",
+ },
+ weekend: {
+ opacity: 30
+ // color: "#FFFFE0",
+ },
+ marker: {
+ hAlign: "Bottom",
+ vAlign: "Right"
+ /*
+ hBottomStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-bottom";
+ },
+ hBottomEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-bottom-emphasized";
+ },
+ hTopStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-top";
+ },
+ hTopEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-top-emphasized";
+ },
+ */
+
+
+ /*
+ vRightStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-right";
+ },
+ vRightEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-right-emphasized";
+ },
+ vLeftStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-left";
+ },
+ vLeftEmphasizedStyler:function(elmt) {
+ elmt.className = "timeline-ether-marker-left-emphasized";
+ }
+ */
+ }
+ }
+ };
+
+ this.event = {
+ track: {
+ height: 10, // px. You will need to change the track
+ // height if you change the tape height.
+ gap: 2, // px. Gap between tracks
+ offset: 2, // px. top margin above tapes
+ autoWidthMargin: 1.5
+ /* autoWidthMargin is only used if autoWidth (see above) is true.
+ The autoWidthMargin setting is used to set how close the bottom of the
+ lowest track is to the edge of the band's div. The units are total track
+ width (tape + label + gap). A min of 0.5 is suggested. Use this setting to
+ move the bottom track's tapes above the axis markers, if needed for your
+ Timeline.
+ */
+ },
+ overviewTrack: {
+ offset: 20, // px -- top margin above tapes
+ tickHeight: 6, // px
+ height: 2, // px
+ gap: 1, // px
+ autoWidthMargin: 5 // This attribute is only used if autoWidth (see above) is true.
+ },
+ tape: {
+ height: 4 // px. For thicker tapes, remember to change track height too.
+ },
+ instant: {
+ icon: Timeline.urlPrefix + "images/dull-blue-circle.png",
+ // default icon. Icon can also be specified per event
+ iconWidth: 10,
+ iconHeight: 10,
+ impreciseOpacity: 20, // opacity of the tape when durationEvent is false
+ impreciseIconMargin: 3 // A tape and an icon are painted for imprecise instant
+ // events. This attribute is the margin between the
+ // bottom of the tape and the top of the icon in that
+ // case.
+ // color: "#58A0DC",
+ // impreciseColor: "#58A0DC",
+ },
+ duration: {
+ impreciseOpacity: 20 // tape opacity for imprecise part of duration events
+ // color: "#58A0DC",
+ // impreciseColor: "#58A0DC",
+ },
+ label: {
+ backgroundOpacity: 50,// only used in detailed painter
+ offsetFromLine: 3 // px left margin amount from icon's right edge
+ // backgroundColor: "white",
+ // lineColor: "#58A0DC",
+ },
+ highlightColors: [ // Use with getEventPainter().setHighlightMatcher
+ // See webapp/examples/examples.js
+ "#FFFF00",
+ "#FFC000",
+ "#FF0000",
+ "#0000FF"
+ ],
+ highlightLabelBackground: false, // When highlighting an event, also change the event's label background?
+ bubble: {
+ width: 250, // px
+ maxHeight: 0, // px Maximum height of bubbles. 0 means no max height.
+ // scrollbar will be added for taller bubbles
+ titleStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-title";
+ },
+ bodyStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-body";
+ },
+ imageStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-image";
+ },
+ wikiStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-wiki";
+ },
+ timeStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-time";
+ }
+ }
+ };
+
+ this.mouseWheel = 'scroll'; // 'default', 'zoom', 'scroll'
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/timeline.js
new file mode 100644
index 00000000..173041a6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/scripts/timeline.js
@@ -0,0 +1,648 @@
+/*=================================================
+ *
+ * Coding standards:
+ *
+ * We aim towards Douglas Crockford's Javascript conventions.
+ * See: http://javascript.crockford.com/code.html
+ * See also: http://www.crockford.com/javascript/javascript.html
+ *
+ * That said, this JS code was written before some recent JS
+ * support libraries became widely used or available.
+ * In particular, the _ character is used to indicate a class function or
+ * variable that should be considered private to the class.
+ *
+ * The code mostly uses accessor methods for getting/setting the private
+ * class variables.
+ *
+ * Over time, we'd like to formalize the convention by using support libraries
+ * which enforce privacy in objects.
+ *
+ * We also want to use jslint: http://www.jslint.com/
+ *
+ *
+ *==================================================
+ */
+
+
+
+/*==================================================
+ * Timeline VERSION
+ *==================================================
+ */
+// Note: version is also stored in the build.xml file
+Timeline.version = 'pre 2.4.0'; // use format 'pre 1.2.3' for trunk versions
+Timeline.ajax_lib_version = SimileAjax.version;
+Timeline.display_version = Timeline.version + ' (with Ajax lib ' + Timeline.ajax_lib_version + ')';
+ // cf method Timeline.writeVersion
+
+/*==================================================
+ * Timeline
+ *==================================================
+ */
+Timeline.strings = {}; // localization string tables
+Timeline.HORIZONTAL = 0;
+Timeline.VERTICAL = 1;
+Timeline._defaultTheme = null;
+
+Timeline.getDefaultLocale = function() {
+ return Timeline.clientLocale;
+};
+
+Timeline.create = function(elmt, bandInfos, orientation, unit) {
+ if (Timeline.timelines == null) {
+ Timeline.timelines = [];
+ // Timeline.timelines array can have null members--Timelines that
+ // once existed on the page, but were later disposed of.
+ }
+
+ var timelineID = Timeline.timelines.length;
+ Timeline.timelines[timelineID] = null; // placeholder until we have the object
+ var new_tl = new Timeline._Impl(elmt, bandInfos, orientation, unit,
+ timelineID);
+ Timeline.timelines[timelineID] = new_tl;
+ return new_tl;
+};
+
+Timeline.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var decorators = ("decorators" in params) ? params.decorators : [];
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : new Date(),
+ interval: SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
+ pixelsPerInterval: params.intervalPixels,
+ theme: theme
+ });
+
+ var etherPainter = new Timeline.GregorianEtherPainter({
+ unit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ theme: theme,
+ align: ("align" in params) ? params.align : undefined
+ });
+
+ var eventPainterParams = {
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ theme: theme
+ };
+ // pass in custom parameters for the event painter
+ if ("eventPainterParams" in params) {
+ for (var prop in params.eventPainterParams) {
+ eventPainterParams[prop] = params.eventPainterParams[prop];
+ }
+ }
+
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+
+ var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
+ var eventPainter;
+ if ("eventPainter" in params) {
+ eventPainter = new params.eventPainter(eventPainterParams);
+ } else {
+ switch (layout) {
+ case "overview" :
+ eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
+ break;
+ case "detailed" :
+ eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
+ break;
+ default:
+ eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
+ }
+ }
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter,
+ theme: theme,
+ decorators: decorators,
+ zoomIndex: ("zoomIndex" in params) ? params.zoomIndex : 0,
+ zoomSteps: ("zoomSteps" in params) ? params.zoomSteps : null
+ };
+};
+
+Timeline.createHotZoneBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.HotZoneEther({
+ centersOn: ("date" in params) ? params.date : new Date(),
+ interval: SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
+ pixelsPerInterval: params.intervalPixels,
+ zones: params.zones,
+ theme: theme
+ });
+
+ var etherPainter = new Timeline.HotZoneGregorianEtherPainter({
+ unit: params.intervalUnit,
+ zones: params.zones,
+ theme: theme,
+ align: ("align" in params) ? params.align : undefined
+ });
+
+ var eventPainterParams = {
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ theme: theme
+ };
+ // pass in custom parameters for the event painter
+ if ("eventPainterParams" in params) {
+ for (var prop in params.eventPainterParams) {
+ eventPainterParams[prop] = params.eventPainterParams[prop];
+ }
+ }
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+
+ var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
+ var eventPainter;
+ if ("eventPainter" in params) {
+ eventPainter = new params.eventPainter(eventPainterParams);
+ } else {
+ switch (layout) {
+ case "overview" :
+ eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
+ break;
+ case "detailed" :
+ eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
+ break;
+ default:
+ eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
+ }
+ }
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter,
+ theme: theme,
+ zoomIndex: ("zoomIndex" in params) ? params.zoomIndex : 0,
+ zoomSteps: ("zoomSteps" in params) ? params.zoomSteps : null
+ };
+};
+
+Timeline.getDefaultTheme = function() {
+ if (Timeline._defaultTheme == null) {
+ Timeline._defaultTheme = Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+ }
+ return Timeline._defaultTheme;
+};
+
+Timeline.setDefaultTheme = function(theme) {
+ Timeline._defaultTheme = theme;
+};
+
+Timeline.loadXML = function(url, f) {
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load data xml from " + url + "\n" + statusText);
+ };
+ var fDone = function(xmlhttp) {
+ var xml = xmlhttp.responseXML;
+ if (!xml.documentElement && xmlhttp.responseStream) {
+ xml.load(xmlhttp.responseStream);
+ }
+ f(xml, url);
+ };
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+};
+
+
+Timeline.loadJSON = function(url, f) {
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load json data from " + url + "\n" + statusText);
+ };
+ var fDone = function(xmlhttp) {
+ f(eval('(' + xmlhttp.responseText + ')'), url);
+ };
+ SimileAjax.XmlHttp.get(url, fError, fDone);
+};
+
+Timeline.getTimelineFromID = function(timelineID) {
+ return Timeline.timelines[timelineID];
+};
+
+// Write the current Timeline version as the contents of element with id el_id
+Timeline.writeVersion = function(el_id) {
+ document.getElementById(el_id).innerHTML = this.display_version;
+};
+
+
+
+/*==================================================
+ * Timeline Implementation object
+ *==================================================
+ */
+Timeline._Impl = function(elmt, bandInfos, orientation, unit, timelineID) {
+ SimileAjax.WindowManager.initialize();
+
+ this._containerDiv = elmt;
+
+ this._bandInfos = bandInfos;
+ this._orientation = orientation == null ? Timeline.HORIZONTAL : orientation;
+ this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
+ this._starting = true; // is the Timeline being created? Used by autoWidth
+ // functions
+ this._autoResizing = false;
+
+ // autoWidth is a "public" property of the Timeline object
+ this.autoWidth = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+ bandInfos[0].theme.autoWidth;
+ this.autoWidthAnimationTime = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+ bandInfos[0].theme.autoWidthAnimationTime;
+ this.timelineID = timelineID; // also public attribute
+ this.timeline_start = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+ bandInfos[0].theme.timeline_start;
+ this.timeline_stop = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+ bandInfos[0].theme.timeline_stop;
+ this.timeline_at_start = false; // already at start or stop? Then won't
+ this.timeline_at_stop = false; // try to move further in the wrong direction
+
+ this._initialize();
+};
+
+//
+// Public functions used by client sw
+//
+Timeline._Impl.prototype.dispose = function() {
+ for (var i = 0; i < this._bands.length; i++) {
+ this._bands[i].dispose();
+ }
+ this._bands = null;
+ this._bandInfos = null;
+ this._containerDiv.innerHTML = "";
+ // remove from array of Timelines
+ Timeline.timelines[this.timelineID] = null;
+};
+
+Timeline._Impl.prototype.getBandCount = function() {
+ return this._bands.length;
+};
+
+Timeline._Impl.prototype.getBand = function(index) {
+ return this._bands[index];
+};
+
+Timeline._Impl.prototype.finishedEventLoading = function() {
+ // Called by client after events have been loaded into Timeline
+ // Only used if the client has set autoWidth
+ // Sets width to Timeline's requested amount and will shrink down the div if
+ // need be.
+ this._autoWidthCheck(true);
+ this._starting = false;
+};
+
+Timeline._Impl.prototype.layout = function() {
+ // called by client when browser is resized
+ this._autoWidthCheck(true);
+ this._distributeWidths();
+};
+
+Timeline._Impl.prototype.paint = function() {
+ for (var i = 0; i < this._bands.length; i++) {
+ this._bands[i].paint();
+ }
+};
+
+Timeline._Impl.prototype.getDocument = function() {
+ return this._containerDiv.ownerDocument;
+};
+
+Timeline._Impl.prototype.addDiv = function(div) {
+ this._containerDiv.appendChild(div);
+};
+
+Timeline._Impl.prototype.removeDiv = function(div) {
+ this._containerDiv.removeChild(div);
+};
+
+Timeline._Impl.prototype.isHorizontal = function() {
+ return this._orientation == Timeline.HORIZONTAL;
+};
+
+Timeline._Impl.prototype.isVertical = function() {
+ return this._orientation == Timeline.VERTICAL;
+};
+
+Timeline._Impl.prototype.getPixelLength = function() {
+ return this._orientation == Timeline.HORIZONTAL ?
+ this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getPixelWidth = function() {
+ return this._orientation == Timeline.VERTICAL ?
+ this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getUnit = function() {
+ return this._unit;
+};
+
+Timeline._Impl.prototype.getWidthStyle = function() {
+ // which element.style attribute should be changed to affect Timeline's "width"
+ return this._orientation == Timeline.HORIZONTAL ? 'height' : 'width';
+};
+
+Timeline._Impl.prototype.loadXML = function(url, f) {
+ var tl = this;
+
+
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load data xml from " + url + "\n" + statusText);
+ tl.hideLoadingMessage();
+ };
+ var fDone = function(xmlhttp) {
+ try {
+ var xml = xmlhttp.responseXML;
+ if (!xml.documentElement && xmlhttp.responseStream) {
+ xml.load(xmlhttp.responseStream);
+ }
+ f(xml, url);
+ } finally {
+ tl.hideLoadingMessage();
+ }
+ };
+
+ this.showLoadingMessage();
+ window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+Timeline._Impl.prototype.loadJSON = function(url, f) {
+ var tl = this;
+
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load json data from " + url + "\n" + statusText);
+ tl.hideLoadingMessage();
+ };
+ var fDone = function(xmlhttp) {
+ try {
+ f(eval('(' + xmlhttp.responseText + ')'), url);
+ } finally {
+ tl.hideLoadingMessage();
+ }
+ };
+
+ this.showLoadingMessage();
+ window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+
+//
+// Private functions used by Timeline object functions
+//
+
+Timeline._Impl.prototype._autoWidthScrollListener = function(band) {
+ band.getTimeline()._autoWidthCheck(false);
+};
+
+// called to re-calculate auto width and adjust the overall Timeline div if needed
+Timeline._Impl.prototype._autoWidthCheck = function(okToShrink) {
+ var timeline = this; // this Timeline
+ var immediateChange = timeline._starting;
+ var newWidth = 0;
+
+ function changeTimelineWidth() {
+ var widthStyle = timeline.getWidthStyle();
+ if (immediateChange) {
+ timeline._containerDiv.style[widthStyle] = newWidth + 'px';
+ } else {
+ // animate change
+ timeline._autoResizing = true;
+ var animateParam ={};
+ animateParam[widthStyle] = newWidth + 'px';
+
+ SimileAjax.jQuery(timeline._containerDiv).animate(
+ animateParam, timeline.autoWidthAnimationTime,
+ 'linear', function(){timeline._autoResizing = false;});
+ }
+ }
+
+ function checkTimelineWidth() {
+ var targetWidth = 0; // the new desired width
+ var currentWidth = timeline.getPixelWidth();
+
+ if (timeline._autoResizing) {
+ return; // early return
+ }
+
+ // compute targetWidth
+ for (var i = 0; i < timeline._bands.length; i++) {
+ timeline._bands[i].checkAutoWidth();
+ targetWidth += timeline._bandInfos[i].width;
+ }
+
+ if (targetWidth > currentWidth || okToShrink) {
+ // yes, let's change the size
+ newWidth = targetWidth;
+ changeTimelineWidth();
+ timeline._distributeWidths();
+ }
+ }
+
+ // function's mainline
+ if (!timeline.autoWidth) {
+ return; // early return
+ }
+
+ checkTimelineWidth();
+};
+
+Timeline._Impl.prototype._initialize = function() {
+ var containerDiv = this._containerDiv;
+ var doc = containerDiv.ownerDocument;
+
+ containerDiv.className =
+ containerDiv.className.split(" ").concat("timeline-container").join(" ");
+
+ /**
+ * Set css-class on container div that will define orientation
+ */
+ var orientation = (this.isHorizontal()) ? 'horizontal' : 'vertical'
+ containerDiv.className +=' timeline-'+orientation;
+
+
+ while (containerDiv.firstChild) {
+ containerDiv.removeChild(containerDiv.firstChild);
+ }
+
+ /*
+ * inserting copyright and link
+ */
+ var elmtCopyright = SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix + (this.isHorizontal() ? "images/copyright-vertical.png" : "images/copyright.png"));
+ elmtCopyright.className = "timeline-copyright";
+ elmtCopyright.title = "SIMILE Timeline - http://www.simile-widgets.org/";
+ SimileAjax.DOM.registerEvent(elmtCopyright, "click", function() { window.location = "http://www.simile-widgets.org/"; });
+ containerDiv.appendChild(elmtCopyright);
+
+ /*
+ * creating bands
+ */
+ this._bands = [];
+ for (var i = 0; i < this._bandInfos.length; i++) {
+ var band = new Timeline._Band(this, this._bandInfos[i], i);
+ this._bands.push(band);
+ }
+ this._distributeWidths();
+
+ /*
+ * sync'ing bands
+ */
+ for (var i = 0; i < this._bandInfos.length; i++) {
+ var bandInfo = this._bandInfos[i];
+ if ("syncWith" in bandInfo) {
+ this._bands[i].setSyncWithBand(
+ this._bands[bandInfo.syncWith],
+ ("highlight" in bandInfo) ? bandInfo.highlight : false
+ );
+ }
+ }
+
+
+ if (this.autoWidth) {
+ for (var i = 0; i < this._bands.length; i++) {
+ this._bands[i].addOnScrollListener(this._autoWidthScrollListener);
+ }
+ }
+
+
+ /*
+ * creating loading UI
+ */
+ var message = SimileAjax.Graphics.createMessageBubble(doc);
+ message.containerDiv.className = "timeline-message-container";
+ containerDiv.appendChild(message.containerDiv);
+
+ message.contentDiv.className = "timeline-message";
+ message.contentDiv.innerHTML = "<img src='" + Timeline.urlPrefix + "images/progress-running.gif' /> Loading...";
+
+ this.showLoadingMessage = function() { message.containerDiv.style.display = "block"; };
+ this.hideLoadingMessage = function() { message.containerDiv.style.display = "none"; };
+};
+
+Timeline._Impl.prototype._distributeWidths = function() {
+ var length = this.getPixelLength();
+ var width = this.getPixelWidth();
+ var cumulativeWidth = 0;
+
+ for (var i = 0; i < this._bands.length; i++) {
+ var band = this._bands[i];
+ var bandInfos = this._bandInfos[i];
+ var widthString = bandInfos.width;
+ var bandWidth;
+
+ if (typeof widthString == 'string') {
+ var x = widthString.indexOf("%");
+ if (x > 0) {
+ var percent = parseInt(widthString.substr(0, x));
+ bandWidth = Math.round(percent * width / 100);
+ } else {
+ bandWidth = parseInt(widthString);
+ }
+ } else {
+ // was given an integer
+ bandWidth = widthString;
+ }
+
+ band.setBandShiftAndWidth(cumulativeWidth, bandWidth);
+ band.setViewLength(length);
+
+ cumulativeWidth += bandWidth;
+ }
+};
+
+Timeline._Impl.prototype.shiftOK = function(index, shift) {
+ // Returns true if the proposed shift is ok
+ //
+ // Positive shift means going back in time
+ var going_back = shift > 0,
+ going_forward = shift < 0;
+
+ // Is there an edge?
+ if ((going_back && this.timeline_start == null) ||
+ (going_forward && this.timeline_stop == null) ||
+ (shift == 0)) {
+ return (true); // early return
+ }
+
+ // If any of the bands has noted that it is changing the others,
+ // then this shift is a secondary shift in reaction to the real shift,
+ // which already happened. In such cases, ignore it. (The issue is
+ // that a positive original shift can cause a negative secondary shift,
+ // as the bands adjust.)
+ var secondary_shift = false;
+ for (var i = 0; i < this._bands.length && !secondary_shift; i++) {
+ secondary_shift = this._bands[i].busy();
+ }
+ if (secondary_shift) {
+ return(true); // early return
+ }
+
+ // If we are already at an edge, then don't even think about going any further
+ if ((going_back && this.timeline_at_start) ||
+ (going_forward && this.timeline_at_stop)) {
+ return (false); // early return
+ }
+
+ // Need to check all the bands
+ var ok = false; // return value
+ // If any of the bands will be or are showing an ok date, then let the shift proceed.
+ for (var i = 0; i < this._bands.length && !ok; i++) {
+ var band = this._bands[i];
+ if (going_back) {
+ ok = (i == index ? band.getMinVisibleDateAfterDelta(shift) : band.getMinVisibleDate())
+ >= this.timeline_start;
+ } else {
+ ok = (i == index ? band.getMaxVisibleDateAfterDelta(shift) : band.getMaxVisibleDate())
+ <= this.timeline_stop;
+ }
+ }
+
+ // process results
+ if (going_back) {
+ this.timeline_at_start = !ok;
+ this.timeline_at_stop = false;
+ } else {
+ this.timeline_at_stop = !ok;
+ this.timeline_at_start = false;
+ }
+ // This is where you could have an effect once per hitting an
+ // edge of the Timeline. Eg jitter the Timeline
+ //if (!ok) {
+ //alert(going_back ? "At beginning" : "At end");
+ //}
+ return (ok);
+};
+
+Timeline._Impl.prototype.zoom = function (zoomIn, x, y, target) {
+ var matcher = new RegExp("^timeline-band-([0-9]+)$");
+ var bandIndex = null;
+
+ var result = matcher.exec(target.id);
+ if (result) {
+ bandIndex = parseInt(result[1]);
+ }
+
+ if (bandIndex != null) {
+ this._bands[bandIndex].zoom(zoomIn, x, y, target);
+ }
+
+ this.paint();
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/ethers.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/ethers.css
new file mode 100644
index 00000000..a464b501
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/ethers.css
@@ -0,0 +1,120 @@
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+ position:absolute;
+ background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+ position:absolute;
+ overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+ set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+ top:0;
+ height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+ width:100%;
+ left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+ position:absolute; overflow:hidden; font-size:200%;
+ font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+ position: absolute;
+ border: solid #aaa;
+ color: #aaa;
+ width: 5em;
+ height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+ position:absolute;
+ cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ background-color:#58A0DC;
+ overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/events.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/events.css
new file mode 100644
index 00000000..68e7581a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/events.css
@@ -0,0 +1,45 @@
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/timeline.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/timeline.css
new file mode 100644
index 00000000..e16c4827
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/styles/timeline.css
@@ -0,0 +1,79 @@
+.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input {
+ width: 0;
+}
+
+.timeline-band-scrollbar {
+ display: none;
+ position: absolute;
+ background: #f8f8f8;
+ z-index: 100;
+ overflow: hidden;
+}
+
+.timeline-band-scrollbar-thumb {
+ margin: 2px;
+ background: #666;
+ position: relative;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-api.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-api.js
new file mode 100644
index 00000000..fea02a46
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-api.js
@@ -0,0 +1,303 @@
+/*==================================================
+ *
+ * Timeline API
+ * ------------
+ *
+ * This file will load all the Javascript files
+ * necessary to make the standard timeline work.
+ * It also detects the default locale.
+ *
+ * To run Timeline directly from the www.simile-widgets.org server
+ * include this fragment in your HTML file as follows:
+ *
+ * <script src="http://api.simile-widgets.org/timeline/2.3.1/timeline-api.js"
+ * type="text/javascript"></script>
+ *
+ *
+ * To host the Timeline files on your own server:
+ *
+ * 1) Install the Timeline files onto your webserver using
+ * the minimal distribution "timeline_<version>_minimal.(zip|tar.gz)" found at
+ *
+ * http://code.google.com/p/simile-widgets/downloads/list
+ *
+ * 2) Set the following global js variable used to send parameters to this script:
+ * var Timeline_ajax_url -- URL for simile-ajax-api.js
+ * var Timeline_urlPrefix -- URL for the *directory* that contains timeline-api.js
+ * on your web site (including the trailing slash!)
+ *
+ * eg your HTML page would include
+ *
+ * <script>
+ * var Timeline_ajax_url="http://YOUR_SERVER/apis/timeline/ajax/simile-ajax-api.js";
+ * var Timeline_urlPrefix='http://YOUR_SERVER/apis/timeline/';
+ * </script>
+ * <script src="http://YOUR_SERVER/javascripts/timeline/timeline-api.js"
+ * type="text/javascript">
+ * </script>
+ *
+ * SCRIPT PARAMETERS
+ *
+ * This script auto-magically figures out locale and has defaults for other parameters
+ * To set parameters explicity, set js global variable Timeline_parameters or include as
+ * parameters on the url using GET style. Eg the two next lines pass the same parameters:
+ * Timeline_parameters='bundle=true'; // pass parameter via js variable
+ * <script src="http://....timeline-api.js?bundle=true" // pass parameter via url
+ *
+ * Parameters
+ * timeline-use-local-resources --
+ * bundle -- true: use the single js bundle file; false: load individual files (for debugging)
+ * locales --
+ * defaultLocale --
+ * forceLocale -- force locale to be a particular value--used for debugging. Normally locale is determined
+ * by browser's and server's locale settings.
+ *
+ * DEBUGGING
+ *
+ * If you have a problem with Timeline, the first step is to use the unbundled Javascript files. To do so:
+ * To use the unbundled Timeline and Ajax libraries
+ * Change
+ * <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=true" type="text/javascript"></script>
+ * To
+ * <script>var Timeline_ajax_url = "http://api.simile-widgets.org/ajax/2.2.1/simile-ajax-api.js?bundle=false"</script>
+ * <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=false" type="text/javascript"></script>
+ *
+ * Note that the Ajax version is usually NOT the same as the Timeline version.
+ * See variable simile_ajax_ver below for the current version
+ *
+ *==================================================
+ */
+
+(function() {
+
+ var simile_ajax_ver = "2.2.1"; // ===========>>> current Simile-Ajax version
+
+ var isCompiled = ("Timeline_isCompiled" in window) && window.Timeline_isCompiled;
+
+ var useLocalResources = false;
+ if (document.location.search.length > 0) {
+ var params = document.location.search.substr(1).split("&");
+ for (var i = 0; i < params.length; i++) {
+ if (params[i] == "timeline-use-local-resources") {
+ useLocalResources = true;
+ }
+ }
+ }
+ var loadMe = function() {
+ if ("Timeline" in window) {
+ return;
+ }
+
+ window.Timeline = new Object();
+ window.Timeline.DateTime = window.SimileAjax.DateTime; // for backward compatibility
+
+ var bundle = false;
+ var javascriptFiles = [
+ "timeline.js",
+ "band.js",
+ "themes.js",
+ "ethers.js",
+ "ether-painters.js",
+ "event-utils.js",
+ "labellers.js",
+ "sources.js",
+ "original-painter.js",
+ "detailed-painter.js",
+ "overview-painter.js",
+ "compact-painter.js",
+ "decorators.js"
+ ];
+ var cssFiles = [
+ "timeline.css",
+ "ethers.css",
+ "events.css"
+ ];
+
+ var localizedJavascriptFiles = [
+ "timeline.js",
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "cs", // Czech
+ "de", // German
+ "en", // English
+ "es", // Spanish
+ "fr", // French
+ "it", // Italian
+ "nl", // Dutch (The Netherlands)
+ "ru", // Russian
+ "se", // Swedish
+ "tr", // Turkish
+ "vi", // Vietnamese
+ "zh" // Chinese
+ ];
+
+ try {
+ var desiredLocales = [ "en" ],
+ defaultServerLocale = "en",
+ forceLocale = null;
+
+ var parseURLParameters = function(parameters) {
+ var params = parameters.split("&");
+ for (var p = 0; p < params.length; p++) {
+ var pair = params[p].split("=");
+ if (pair[0] == "locales") {
+ desiredLocales = desiredLocales.concat(pair[1].split(","));
+ } else if (pair[0] == "defaultLocale") {
+ defaultServerLocale = pair[1];
+ } else if (pair[0] == "forceLocale") {
+ forceLocale = pair[1];
+ desiredLocales = desiredLocales.concat(pair[1].split(","));
+ } else if (pair[0] == "bundle") {
+ bundle = pair[1] != "false";
+ }
+ }
+ };
+
+ (function() {
+ if (typeof Timeline_urlPrefix == "string") {
+ Timeline.urlPrefix = Timeline_urlPrefix;
+ if (typeof Timeline_parameters == "string") {
+ parseURLParameters(Timeline_parameters);
+ }
+ } else {
+ var heads = document.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var scripts = heads[h].getElementsByTagName("script");
+ for (var s = 0; s < scripts.length; s++) {
+ var url = scripts[s].src;
+ var i = url.indexOf("timeline-api.js");
+ if (i >= 0) {
+ Timeline.urlPrefix = url.substr(0, i);
+ var q = url.indexOf("?");
+ if (q > 0) {
+ parseURLParameters(url.substr(q + 1));
+ }
+ return;
+ }
+ }
+ }
+ throw new Error("Failed to derive URL prefix for Timeline API code files");
+ }
+ })();
+
+ var includeJavascriptFiles = function(urlPrefix, filenames) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, filenames);
+ }
+ var includeCssFiles = function(urlPrefix, filenames) {
+ SimileAjax.includeCssFiles(document, urlPrefix, filenames);
+ }
+
+ /*
+ * Include non-localized files
+ */
+ if (!isCompiled) {
+ if (bundle) {
+ includeJavascriptFiles(Timeline.urlPrefix, [ "timeline-bundle.js" ]);
+ includeCssFiles(Timeline.urlPrefix, [ "timeline-bundle.css" ]);
+ } else {
+ includeJavascriptFiles(Timeline.urlPrefix + "scripts/", javascriptFiles);
+ includeCssFiles(Timeline.urlPrefix + "styles/", cssFiles);
+ }
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ loadLocale[defaultServerLocale] = true;
+
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ for (var l = 0; l < desiredLocales.length; l++) {
+ tryLocale(desiredLocales[l]);
+ }
+
+ var defaultClientLocale = defaultServerLocale;
+ var defaultClientLocales = ("language" in navigator ? navigator.language : navigator.browserLanguage).split(";");
+ for (var l = 0; l < defaultClientLocales.length; l++) {
+ var locale = tryLocale(defaultClientLocales[l]);
+ if (locale != null) {
+ defaultClientLocale = locale;
+ break;
+ }
+ }
+
+ if (!isCompiled) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ includeJavascriptFiles(Timeline.urlPrefix + "scripts/l10n/" + locale + "/", localizedJavascriptFiles);
+ includeCssFiles(Timeline.urlPrefix + "styles/l10n/" + locale + "/", localizedCssFiles);
+ }
+ }
+ }
+
+ if (forceLocale == null) {
+ Timeline.serverLocale = defaultServerLocale;
+ Timeline.clientLocale = defaultClientLocale;
+ } else {
+ Timeline.serverLocale = forceLocale;
+ Timeline.clientLocale = forceLocale;
+ }
+ } catch (e) {
+ alert(e);
+ }
+ };
+
+ /*
+ * Load SimileAjax if it's not already loaded
+ */
+ if (typeof SimileAjax == "undefined" && !isCompiled) {
+ window.SimileAjax_onLoad = loadMe;
+
+ var url = useLocalResources ?
+ "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
+ "http://api.simile-widgets.org/ajax/" + simile_ajax_ver + "/simile-ajax-api.js";
+ if (typeof Timeline_ajax_url == "string") {
+ url = Timeline_ajax_url;
+ }
+ var createScriptElement = function() {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.language = "JavaScript";
+ script.src = url;
+ document.getElementsByTagName("head")[0].appendChild(script);
+ }
+ if (document.body == null) {
+ try {
+ document.write("<script src='" + url + "' type='text/javascript'></script>");
+ } catch (e) {
+ createScriptElement();
+ }
+ } else {
+ createScriptElement();
+ }
+ } else {
+ loadMe();
+ }
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.css
new file mode 100644
index 00000000..b5cd3d32
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.css
@@ -0,0 +1,243 @@
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+ position:absolute;
+ background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+ position:absolute;
+ overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+ set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+ top:0;
+ height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+ width:100%;
+ left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+ position:absolute; overflow:hidden; font-size:200%;
+ font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+ position: absolute;
+ border: solid #aaa;
+ color: #aaa;
+ width: 5em;
+ height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+ position:absolute;
+ cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ background-color:#58A0DC;
+ overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+}.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input {
+ width: 0;
+}
+
+.timeline-band-scrollbar {
+ display: none;
+ position: absolute;
+ background: #f8f8f8;
+ z-index: 100;
+ overflow: hidden;
+}
+
+.timeline-band-scrollbar-thumb {
+ margin: 2px;
+ background: #666;
+ position: relative;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.js
new file mode 100644
index 00000000..e55930fc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle-debug.js
@@ -0,0 +1,2950 @@
+
+
+/* band.js */
+Timeline._Band=function(timeline,bandInfo,index){if(timeline.autoWidth&&typeof bandInfo.width=="string"){bandInfo.width=bandInfo.width.indexOf("%")>-1?0:parseInt(bandInfo.width);
+}this._timeline=timeline;
+this._bandInfo=bandInfo;
+this._index=index;
+this._locale=("locale" in bandInfo)?bandInfo.locale:Timeline.getDefaultLocale();
+this._timeZone=("timeZone" in bandInfo)?bandInfo.timeZone:0;
+this._labeller=("labeller" in bandInfo)?bandInfo.labeller:(("createLabeller" in timeline.getUnit())?timeline.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
+this._theme=bandInfo.theme;
+this._zoomIndex=("zoomIndex" in bandInfo)?bandInfo.zoomIndex:0;
+this._zoomSteps=("zoomSteps" in bandInfo)?bandInfo.zoomSteps:null;
+this._dragging=false;
+this._changing=false;
+this._originalScrollSpeed=5;
+this._scrollSpeed=this._originalScrollSpeed;
+this._onScrollListeners=[];
+this._orthogonalDragging=false;
+this._viewOrthogonalOffset=0;
+this._onOrthogonalScrollListeners=[];
+var b=this;
+this._syncWithBand=null;
+this._syncWithBandHandler=function(band){b._onHighlightBandScroll();
+};
+this._syncWithBandOrthogonalScrollHandler=function(band){b._onHighlightBandOrthogonalScroll();
+};
+this._selectorListener=function(band){b._onHighlightBandScroll();
+};
+var inputDiv=this._timeline.getDocument().createElement("div");
+inputDiv.className="timeline-band-input";
+this._timeline.addDiv(inputDiv);
+this._keyboardInput=document.createElement("input");
+this._keyboardInput.type="text";
+inputDiv.appendChild(this._keyboardInput);
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
+this._div=this._timeline.getDocument().createElement("div");
+this._div.id="timeline-band-"+index;
+this._div.className="timeline-band timeline-band-"+index;
+this._timeline.addDiv(this._div);
+SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
+SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
+SimileAjax.DOM.registerEventWithObject(document.body,"mousemove",this,"_onMouseMove");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseup",this,"_onMouseUp");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseout",this,"_onMouseOut");
+var mouseWheel=this._theme!=null?this._theme.mouseWheel:"scroll";
+if(mouseWheel==="zoom"||mouseWheel==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
+}else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
+}}this._innerDiv=this._timeline.getDocument().createElement("div");
+this._innerDiv.className="timeline-band-inner";
+this._div.appendChild(this._innerDiv);
+this._ether=bandInfo.ether;
+bandInfo.ether.initialize(this,timeline);
+this._etherPainter=bandInfo.etherPainter;
+bandInfo.etherPainter.initialize(this,timeline);
+this._eventSource=bandInfo.eventSource;
+if(this._eventSource){this._eventListener={onAddMany:function(){b._onAddMany();
+},onClear:function(){b._onClear();
+}};
+this._eventSource.addListener(this._eventListener);
+}this._eventPainter=bandInfo.eventPainter;
+this._eventTracksNeeded=0;
+this._eventTrackIncrement=0;
+bandInfo.eventPainter.initialize(this,timeline);
+this._decorators=("decorators" in bandInfo)?bandInfo.decorators:[];
+for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].initialize(this,timeline);
+}this._supportsOrthogonalScrolling=("supportsOrthogonalScrolling" in this._eventPainter)&&this._eventPainter.supportsOrthogonalScrolling();
+if(this._supportsOrthogonalScrolling){this._scrollBar=this._timeline.getDocument().createElement("div");
+this._scrollBar.id="timeline-band-scrollbar-"+index;
+this._scrollBar.className="timeline-band-scrollbar";
+this._timeline.addDiv(this._scrollBar);
+this._scrollBar.innerHTML='<div class="timeline-band-scrollbar-thumb"> </div>';
+var scrollbarThumb=this._scrollBar.firstChild;
+if(SimileAjax.Platform.browser.isIE){scrollbarThumb.style.cursor="move";
+}else{scrollbarThumb.style.cursor="-moz-grab";
+}SimileAjax.DOM.registerEventWithObject(scrollbarThumb,"mousedown",this,"_onScrollBarMouseDown");
+}};
+Timeline._Band.SCROLL_MULTIPLES=5;
+Timeline._Band.prototype.dispose=function(){this.closeBubble();
+if(this._eventSource){this._eventSource.removeListener(this._eventListener);
+this._eventListener=null;
+this._eventSource=null;
+}this._timeline=null;
+this._bandInfo=null;
+this._labeller=null;
+this._ether=null;
+this._etherPainter=null;
+this._eventPainter=null;
+this._decorators=null;
+this._onScrollListeners=null;
+this._syncWithBandHandler=null;
+this._syncWithBandOrthogonalScrollHandler=null;
+this._selectorListener=null;
+this._div=null;
+this._innerDiv=null;
+this._keyboardInput=null;
+this._scrollBar=null;
+};
+Timeline._Band.prototype.addOnScrollListener=function(listener){this._onScrollListeners.push(listener);
+};
+Timeline._Band.prototype.removeOnScrollListener=function(listener){for(var i=0;
+i<this._onScrollListeners.length;
+i++){if(this._onScrollListeners[i]==listener){this._onScrollListeners.splice(i,1);
+break;
+}}};
+Timeline._Band.prototype.addOnOrthogonalScrollListener=function(listener){this._onOrthogonalScrollListeners.push(listener);
+};
+Timeline._Band.prototype.removeOnOrthogonalScrollListener=function(listener){for(var i=0;
+i<this._onOrthogonalScrollListeners.length;
+i++){if(this._onOrthogonalScrollListeners[i]==listener){this._onOrthogonalScrollListeners.splice(i,1);
+break;
+}}};
+Timeline._Band.prototype.setSyncWithBand=function(band,highlight){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.removeOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+}this._syncWithBand=band;
+this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.addOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+this._highlight=highlight;
+this._positionHighlight();
+};
+Timeline._Band.prototype.getLocale=function(){return this._locale;
+};
+Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
+};
+Timeline._Band.prototype.getLabeller=function(){return this._labeller;
+};
+Timeline._Band.prototype.getIndex=function(){return this._index;
+};
+Timeline._Band.prototype.getEther=function(){return this._ether;
+};
+Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
+};
+Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
+};
+Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
+};
+Timeline._Band.prototype.getTimeline=function(){return this._timeline;
+};
+Timeline._Band.prototype.updateEventTrackInfo=function(tracks,increment){this._eventTrackIncrement=increment;
+if(tracks>this._eventTracksNeeded){this._eventTracksNeeded=tracks;
+}};
+Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
+}var overviewBand=this._eventPainter.getType()=="overview";
+var margin=overviewBand?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
+var desiredWidth=Math.ceil((this._eventTracksNeeded+margin)*this._eventTrackIncrement);
+desiredWidth+=overviewBand?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
+var bandInfo=this._bandInfo;
+if(desiredWidth!=bandInfo.width){bandInfo.width=desiredWidth;
+}};
+Timeline._Band.prototype.layout=function(){this.paint();
+};
+Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
+this._paintDecorators();
+this._paintEvents();
+};
+Timeline._Band.prototype.softLayout=function(){this.softPaint();
+};
+Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
+this._softPaintDecorators();
+this._softPaintEvents();
+};
+Timeline._Band.prototype.setBandShiftAndWidth=function(shift,width){var inputDiv=this._keyboardInput.parentNode;
+var middle=shift+Math.floor(width/2);
+if(this._timeline.isHorizontal()){this._div.style.top=shift+"px";
+this._div.style.height=width+"px";
+inputDiv.style.top=middle+"px";
+inputDiv.style.left="-1em";
+}else{this._div.style.left=shift+"px";
+this._div.style.width=width+"px";
+inputDiv.style.left=middle+"px";
+inputDiv.style.top="-1em";
+}};
+Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
+}else{return this._div.offsetWidth;
+}};
+Timeline._Band.prototype.setViewLength=function(length){this._viewLength=length;
+this._recenterDiv();
+this._onChanging();
+};
+Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
+};
+Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
+};
+Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
+};
+Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
+};
+Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
+};
+Timeline._Band.prototype.getMinVisibleDateAfterDelta=function(delta){return this._ether.pixelOffsetToDate(delta);
+};
+Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
+};
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta=function(delta){return this._ether.pixelOffsetToDate(this._viewLength+delta);
+};
+Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
+};
+Timeline._Band.prototype.setMinVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.setMaxVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.setCenterVisibleDate=function(date){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(date)));
+}};
+Timeline._Band.prototype.dateToPixelOffset=function(date){return this._ether.dateToPixelOffset(date)-this._viewOffset;
+};
+Timeline._Band.prototype.pixelOffsetToDate=function(pixels){return this._ether.pixelOffsetToDate(pixels+this._viewOffset);
+};
+Timeline._Band.prototype.getViewOrthogonalOffset=function(){return this._viewOrthogonalOffset;
+};
+Timeline._Band.prototype.setViewOrthogonalOffset=function(offset){this._viewOrthogonalOffset=Math.max(0,offset);
+};
+Timeline._Band.prototype.createLayerDiv=function(zIndex,className){var div=this._timeline.getDocument().createElement("div");
+div.className="timeline-band-layer"+(typeof className=="string"?(" "+className):"");
+div.style.zIndex=zIndex;
+this._innerDiv.appendChild(div);
+var innerDiv=this._timeline.getDocument().createElement("div");
+innerDiv.className="timeline-band-layer-inner";
+if(SimileAjax.Platform.browser.isIE){innerDiv.style.cursor="move";
+}else{innerDiv.style.cursor="-moz-grab";
+}div.appendChild(innerDiv);
+return innerDiv;
+};
+Timeline._Band.prototype.removeLayerDiv=function(div){this._innerDiv.removeChild(div.parentNode);
+};
+Timeline._Band.prototype.scrollToCenter=function(date,f){var pixelOffset=this._ether.dateToPixelOffset(date);
+if(pixelOffset<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset+this._viewLength));
+}else{if(pixelOffset>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset-this._viewLength));
+}}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(date)),f);
+};
+Timeline._Band.prototype.showBubbleForEvent=function(eventID){var evt=this.getEventSource().getEvent(eventID);
+if(evt){var self=this;
+this.scrollToCenter(evt.getStart(),function(){self._eventPainter.showBubble(evt);
+});
+}};
+Timeline._Band.prototype.zoom=function(zoomIn,x,y,target){if(!this._zoomSteps){return ;
+}x+=this._viewOffset;
+var zoomDate=this._ether.pixelOffsetToDate(x);
+var netIntervalChange=this._ether.zoom(zoomIn);
+this._etherPainter.zoom(netIntervalChange);
+this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
+this._moveEther(x);
+};
+Timeline._Band.prototype._onMouseDown=function(elmt,evt,target){if(!this._dragging){this.closeBubble();
+this._dragging=true;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onMouseMove=function(elmt,evt,target){if(this._dragging||this._orthogonalDragging){var diffX=evt.clientX-this._dragX;
+var diffY=evt.clientY-this._dragY;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+}if(this._dragging){if(this._timeline.isHorizontal()){this._moveEther(diffX,diffY);
+}else{this._moveEther(diffY,diffX);
+}}else{if(this._orthogonalDragging){var viewWidth=this.getViewWidth();
+var scrollbarThumb=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._moveEther(0,-diffY*viewWidth/scrollbarThumb.offsetHeight);
+}else{this._moveEther(0,-diffX*viewWidth/scrollbarThumb.offsetWidth);
+}}else{return ;
+}}this._positionHighlight();
+this._showScrollbar();
+return this._cancelEvent(evt);
+};
+Timeline._Band.prototype._onMouseUp=function(elmt,evt,target){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._keyboardInput.focus();
+this._bounceBack();
+return this._cancelEvent(evt);
+};
+Timeline._Band.prototype._onMouseOut=function(elmt,evt,target){if(target==document.body){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._bounceBack();
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onScrollBarMouseDown=function(elmt,evt,target){if(!this._orthogonalDragging){this.closeBubble();
+this._orthogonalDragging=true;
+this._dragX=evt.clientX;
+this._dragY=evt.clientY;
+return this._cancelEvent(evt);
+}};
+Timeline._Band.prototype._onMouseScroll=function(innerFrame,evt,target){var now=new Date();
+now=now.getTime();
+if(!this._lastScrollTime||((now-this._lastScrollTime)>50)){this._lastScrollTime=now;
+var delta=0;
+if(evt.wheelDelta){delta=evt.wheelDelta/120;
+}else{if(evt.detail){delta=-evt.detail/3;
+}}var mouseWheel=this._theme.mouseWheel;
+if(this._zoomSteps||mouseWheel==="zoom"){var loc=SimileAjax.DOM.getEventRelativeCoordinates(evt,innerFrame);
+if(delta!=0){var zoomIn;
+if(delta>0){zoomIn=true;
+}if(delta<0){zoomIn=false;
+}this._timeline.zoom(zoomIn,loc.x,loc.y,innerFrame);
+}}else{if(mouseWheel==="scroll"){var move_amt=50*(delta<0?-1:1);
+this._moveEther(move_amt);
+}}}if(evt.stopPropagation){evt.stopPropagation();
+}evt.cancelBubble=true;
+if(evt.preventDefault){evt.preventDefault();
+}evt.returnValue=false;
+};
+Timeline._Band.prototype._onDblClick=function(innerFrame,evt,target){var coords=SimileAjax.DOM.getEventRelativeCoordinates(evt,innerFrame);
+var distance=coords.x-(this._viewLength/2-this._viewOffset);
+this._autoScroll(-distance);
+};
+Timeline._Band.prototype._onKeyDown=function(keyboardInput,evt,target){if(!this._dragging){switch(evt.keyCode){case 27:break;
+case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+}return true;
+};
+Timeline._Band.prototype._onKeyUp=function(keyboardInput,evt,target){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
+switch(evt.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
+break;
+case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+break;
+case 33:this._autoScroll(this._timeline.getPixelLength());
+break;
+case 34:this._autoScroll(-this._timeline.getPixelLength());
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(evt);
+return false;
+}return true;
+};
+Timeline._Band.prototype._autoScroll=function(distance,f){var b=this;
+var a=SimileAjax.Graphics.createAnimation(function(abs,diff){b._moveEther(diff);
+},0,distance,1000,f);
+a.run();
+};
+Timeline._Band.prototype._moveEther=function(shift,orthogonalShift){if(orthogonalShift===undefined){orthogonalShift=0;
+}this.closeBubble();
+if(!this._timeline.shiftOK(this._index,shift)){return ;
+}this._viewOffset+=shift;
+this._ether.shiftPixels(-shift);
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+}if(this._supportsOrthogonalScrolling){if(this._eventPainter.getOrthogonalExtent()<=this.getViewWidth()){this._viewOrthogonalOffset=0;
+}else{this._viewOrthogonalOffset=this._viewOrthogonalOffset+orthogonalShift;
+}}if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
+}else{this.softLayout();
+}this._onChanging();
+};
+Timeline._Band.prototype._onChanging=function(){this._changing=true;
+this._fireOnScroll();
+this._setSyncWithBandDate();
+this._changing=false;
+};
+Timeline._Band.prototype.busy=function(){return(this._changing);
+};
+Timeline._Band.prototype._fireOnScroll=function(){for(var i=0;
+i<this._onScrollListeners.length;
+i++){this._onScrollListeners[i](this);
+}};
+Timeline._Band.prototype._fireOnOrthogonalScroll=function(){for(var i=0;
+i<this._onOrthogonalScrollListeners.length;
+i++){this._onOrthogonalScrollListeners[i](this);
+}};
+Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var centerDate=this._ether.pixelOffsetToDate(this.getViewLength()/2);
+this._syncWithBand.setCenterVisibleDate(centerDate);
+}};
+Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var centerDate=this._syncWithBand.getCenterVisibleDate();
+var centerPixelOffset=this._ether.dateToPixelOffset(centerDate);
+this._moveEther(Math.round(this._viewLength/2-centerPixelOffset));
+this._positionHighlight();
+}};
+Timeline._Band.prototype._onHighlightBandOrthogonalScroll=function(){if(this._syncWithBand){this._positionHighlight();
+}};
+Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
+};
+Timeline._Band.prototype._onClear=function(){this._paintEvents();
+};
+Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var startDate=this._syncWithBand.getMinVisibleDate();
+var endDate=this._syncWithBand.getMaxVisibleDate();
+if(this._highlight){var offset=0;
+var extent=1;
+var syncEventPainter=this._syncWithBand.getEventPainter();
+if("supportsOrthogonalScrolling" in syncEventPainter&&syncEventPainter.supportsOrthogonalScrolling()){var orthogonalExtent=syncEventPainter.getOrthogonalExtent();
+var visibleWidth=this._syncWithBand.getViewWidth();
+var totalWidth=Math.max(visibleWidth,orthogonalExtent);
+extent=visibleWidth/totalWidth;
+offset=-this._syncWithBand.getViewOrthogonalOffset()/totalWidth;
+}this._etherPainter.setHighlight(startDate,endDate,offset,extent);
+}}};
+Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}this.layout();
+};
+Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
+this._showScrollbar();
+this._fireOnOrthogonalScroll();
+};
+Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
+};
+Timeline._Band.prototype._paintDecorators=function(){for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].paint();
+}};
+Timeline._Band.prototype._softPaintDecorators=function(){for(var i=0;
+i<this._decorators.length;
+i++){this._decorators[i].softPaint();
+}};
+Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
+};
+Timeline._Band.prototype._bounceBack=function(f){if(!this._supportsOrthogonalScrolling){return ;
+}var target=0;
+if(this._viewOrthogonalOffset<0){var orthogonalExtent=this._eventPainter.getOrthogonalExtent();
+if(this._viewOrthogonalOffset+orthogonalExtent>=this.getViewWidth()){target=this._viewOrthogonalOffset;
+}else{target=Math.min(0,this.getViewWidth()-orthogonalExtent);
+}}if(target!=this._viewOrthogonalOffset){var self=this;
+SimileAjax.Graphics.createAnimation(function(abs,diff){self._viewOrthogonalOffset=abs;
+self._eventPainter.softPaint();
+self._showScrollbar();
+self._fireOnOrthogonalScroll();
+},this._viewOrthogonalOffset,target,300,function(){self._hideScrollbar();
+}).run();
+}else{this._hideScrollbar();
+}};
+Timeline._Band.prototype._showScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}var orthogonalExtent=this._eventPainter.getOrthogonalExtent();
+var visibleWidth=this.getViewWidth();
+var totalWidth=Math.max(visibleWidth,orthogonalExtent);
+var ratio=(visibleWidth/totalWidth);
+var thumbWidth=Math.round(visibleWidth*ratio)+"px";
+var thumbOffset=Math.round(-this._viewOrthogonalOffset*ratio)+"px";
+var thumbThickness=12;
+var thumb=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._scrollBar.style.top=this._div.style.top;
+this._scrollBar.style.height=this._div.style.height;
+this._scrollBar.style.right="0px";
+this._scrollBar.style.width=thumbThickness+"px";
+thumb.style.top=thumbOffset;
+thumb.style.height=thumbWidth;
+}else{this._scrollBar.style.left=this._div.style.left;
+this._scrollBar.style.width=this._div.style.width;
+this._scrollBar.style.bottom="0px";
+this._scrollBar.style.height=thumbThickness+"px";
+thumb.style.left=thumbOffset;
+thumb.style.width=thumbWidth;
+}if(ratio>=1&&this._viewOrthogonalOffset==0){this._scrollBar.style.display="none";
+}else{this._scrollBar.style.display="block";
+}};
+Timeline._Band.prototype._hideScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}};
+Timeline._Band.prototype._cancelEvent=function(evt){SimileAjax.DOM.cancelEvent(evt);
+return false;
+};
+
+
+/* compact-painter.js */
+Timeline.CompactEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.CompactEventPainter.prototype.getType=function(){return"compact";
+};
+Timeline.CompactEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.CompactEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.CompactEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.CompactEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.CompactEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var metrics=this._computeMetrics();
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventIterator(minDate,maxDate);
+var stackConcurrentPreciseInstantEvents="stackConcurrentPreciseInstantEvents" in this._params&&typeof this._params.stackConcurrentPreciseInstantEvents=="object";
+var collapseConcurrentPreciseInstantEvents="collapseConcurrentPreciseInstantEvents" in this._params&&this._params.collapseConcurrentPreciseInstantEvents;
+if(collapseConcurrentPreciseInstantEvents||stackConcurrentPreciseInstantEvents){var bufferedEvents=[];
+var previousInstantEvent=null;
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){if(!evt.isInstant()||evt.isImprecise()){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}else{if(previousInstantEvent!=null&&previousInstantEvent.getStart().getTime()==evt.getStart().getTime()){bufferedEvents[bufferedEvents.length-1].push(evt);
+}else{bufferedEvents.push([evt]);
+previousInstantEvent=evt;
+}}}}for(var i=0;
+i<bufferedEvents.length;
+i++){var compositeEvents=bufferedEvents[i];
+if(compositeEvents.length==1){this.paintEvent(compositeEvents[0],metrics,this._params.theme,highlightMatcher(evt));
+}else{var match=-1;
+for(var j=0;
+match<0&&j<compositeEvents.length;
+j++){match=highlightMatcher(compositeEvents[j]);
+}if(stackConcurrentPreciseInstantEvents){this.paintStackedPreciseInstantEvents(compositeEvents,metrics,this._params.theme,match);
+}else{this.paintCompositePreciseInstantEvents(compositeEvents,metrics,this._params.theme,match);
+}}}}else{while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._setOrthogonalOffset(metrics);
+};
+Timeline.CompactEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.CompactEventPainter.prototype.getOrthogonalExtent=function(){var metrics=this._computeMetrics();
+return 2*metrics.trackOffset+this._tracks.length*metrics.trackHeight;
+};
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset=function(metrics){var orthogonalOffset=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=orthogonalOffset+"px";
+};
+Timeline.CompactEventPainter.prototype._computeMetrics=function(){var theme=this._params.theme;
+var eventTheme=theme.event;
+var metrics={trackOffset:"trackOffset" in this._params?this._params.trackOffset:10,trackHeight:"trackHeight" in this._params?this._params.trackHeight:10,tapeHeight:theme.event.tape.height,tapeBottomMargin:"tapeBottomMargin" in this._params?this._params.tapeBottomMargin:2,labelBottomMargin:"labelBottomMargin" in this._params?this._params.labelBottomMargin:5,labelRightMargin:"labelRightMargin" in this._params?this._params.labelRightMargin:5,defaultIcon:eventTheme.instant.icon,defaultIconWidth:eventTheme.instant.iconWidth,defaultIconHeight:eventTheme.instant.iconHeight,customIconWidth:"iconWidth" in this._params?this._params.iconWidth:eventTheme.instant.iconWidth,customIconHeight:"iconHeight" in this._params?this._params.iconHeight:eventTheme.instant.iconHeight,iconLabelGap:"iconLabelGap" in this._params?this._params.iconLabelGap:2,iconBottomMargin:"iconBottomMargin" in this._params?this._params.iconBottomMargin:2};
+if("compositeIcon" in this._params){metrics.compositeIcon=this._params.compositeIcon;
+metrics.compositeIconWidth=this._params.compositeIconWidth||metrics.customIconWidth;
+metrics.compositeIconHeight=this._params.compositeIconHeight||metrics.customIconHeight;
+}else{metrics.compositeIcon=metrics.defaultIcon;
+metrics.compositeIconWidth=metrics.defaultIconWidth;
+metrics.compositeIconHeight=metrics.defaultIconHeight;
+}metrics.defaultStackIcon=("stackConcurrentPreciseInstantEvents" in this._params&&"icon" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.icon:metrics.defaultIcon;
+metrics.defaultStackIconWidth=("stackConcurrentPreciseInstantEvents" in this._params&&"iconWidth" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconWidth:metrics.defaultIconWidth;
+metrics.defaultStackIconHeight=("stackConcurrentPreciseInstantEvents" in this._params&&"iconHeight" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconHeight:metrics.defaultIconHeight;
+return metrics;
+};
+Timeline.CompactEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.CompactEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData.url=metrics.defaultIcon;
+iconData.width=metrics.defaultIconWidth;
+iconData.height=metrics.defaultIconHeight;
+iconData.className="timeline-event-icon-default";
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,null,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+};
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents=function(events,metrics,theme,highlightIndex){var evt=events[0];
+var tooltips=[];
+for(var i=0;
+i<events.length;
+i++){tooltips.push(events[i].getProperty("tooltip")||events[i].getText());
+}var commonData={tooltip:tooltips.join("; ")};
+var iconData={url:metrics.compositeIcon,width:metrics.compositeIconWidth,height:metrics.compositeIconHeight,className:"timeline-event-icon-composite"};
+var labelData={text:String.substitute(this._params.compositeEventLabelTemplate,[events.length])};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,null,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt,domEvt,events);
+};
+SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+for(var i=0;
+i<events.length;
+i++){this._eventIdToElmt[events[i].getID()]=result.iconElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents=function(events,metrics,theme,highlightIndex){var limit="limit" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.limit:10;
+var moreMessageTemplate="moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate:"%0 More Events";
+var showMoreMessage=limit<=events.length-2;
+var band=this._band;
+var getPixelOffset=function(date){return Math.round(band.dateToPixelOffset(date));
+};
+var getIconData=function(evt){var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData.url=metrics.defaultStackIcon;
+iconData.width=metrics.defaultStackIconWidth;
+iconData.height=metrics.defaultStackIconHeight;
+iconData.className="timeline-event-icon-stack timeline-event-icon-default";
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+iconData.className="timeline-event-icon-stack";
+}return iconData;
+};
+var firstIconData=getIconData(events[0]);
+var horizontalIncrement=5;
+var leftIconEdge=0;
+var totalLabelWidth=0;
+var totalLabelHeight=0;
+var totalIconHeight=0;
+var records=[];
+for(var i=0;
+i<events.length&&(!showMoreMessage||i<limit);
+i++){var evt=events[i];
+var text=evt.getText();
+var iconData=getIconData(evt);
+var labelSize=this._frc.computeSize(text);
+var record={text:text,iconData:iconData,labelSize:labelSize,iconLeft:firstIconData.width+i*horizontalIncrement-iconData.width};
+record.labelLeft=firstIconData.width+i*horizontalIncrement+metrics.iconLabelGap;
+record.top=totalLabelHeight;
+records.push(record);
+leftIconEdge=Math.min(leftIconEdge,record.iconLeft);
+totalLabelHeight+=labelSize.height;
+totalLabelWidth=Math.max(totalLabelWidth,record.labelLeft+labelSize.width);
+totalIconHeight=Math.max(totalIconHeight,record.top+iconData.height);
+}if(showMoreMessage){var moreMessage=String.substitute(moreMessageTemplate,[events.length-limit]);
+var moreMessageLabelSize=this._frc.computeSize(moreMessage);
+var moreMessageLabelLeft=firstIconData.width+(limit-1)*horizontalIncrement+metrics.iconLabelGap;
+var moreMessageLabelTop=totalLabelHeight;
+totalLabelHeight+=moreMessageLabelSize.height;
+totalLabelWidth=Math.max(totalLabelWidth,moreMessageLabelLeft+moreMessageLabelSize.width);
+}totalLabelWidth+=metrics.labelRightMargin;
+totalLabelHeight+=metrics.labelBottomMargin;
+totalIconHeight+=metrics.iconBottomMargin;
+var anchorPixel=getPixelOffset(events[0].getStart());
+var newTracks=[];
+var trackCount=Math.ceil(Math.max(totalIconHeight,totalLabelHeight)/metrics.trackHeight);
+var rightIconEdge=firstIconData.width+(events.length-1)*horizontalIncrement;
+for(var i=0;
+i<trackCount;
+i++){newTracks.push({start:leftIconEdge,end:rightIconEdge});
+}var labelTrackCount=Math.ceil(totalLabelHeight/metrics.trackHeight);
+for(var i=0;
+i<labelTrackCount;
+i++){var track=newTracks[i];
+track.end=Math.max(track.end,totalLabelWidth);
+}var firstTrack=this._fitTracks(anchorPixel,newTracks);
+var verticalPixelOffset=firstTrack*metrics.trackHeight+metrics.trackOffset;
+var iconStackDiv=this._timeline.getDocument().createElement("div");
+iconStackDiv.className="timeline-event-icon-stack";
+iconStackDiv.style.position="absolute";
+iconStackDiv.style.overflow="visible";
+iconStackDiv.style.left=anchorPixel+"px";
+iconStackDiv.style.top=verticalPixelOffset+"px";
+iconStackDiv.style.width=rightIconEdge+"px";
+iconStackDiv.style.height=totalIconHeight+"px";
+iconStackDiv.innerHTML="<div style='position: relative'></div>";
+this._eventLayer.appendChild(iconStackDiv);
+var self=this;
+var onMouseOver=function(domEvt){try{var n=parseInt(this.getAttribute("index"));
+var childNodes=iconStackDiv.firstChild.childNodes;
+for(var i=0;
+i<childNodes.length;
+i++){var child=childNodes[i];
+if(i==n){child.style.zIndex=childNodes.length;
+}else{child.style.zIndex=childNodes.length-i;
+}}}catch(e){}};
+var paintEvent=function(index){var record=records[index];
+var evt=events[index];
+var tooltip=evt.getProperty("tooltip")||evt.getText();
+var labelElmtData=self._paintEventLabel({tooltip:tooltip},{text:record.text},anchorPixel+record.labelLeft,verticalPixelOffset+record.top,record.labelSize.width,record.labelSize.height,theme);
+labelElmtData.elmt.setAttribute("index",index);
+labelElmtData.elmt.onmouseover=onMouseOver;
+var img=SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
+var iconDiv=self._timeline.getDocument().createElement("div");
+iconDiv.className="timeline-event-icon"+("className" in record.iconData?(" "+record.iconData.className):"");
+iconDiv.style.left=record.iconLeft+"px";
+iconDiv.style.top=record.top+"px";
+iconDiv.style.zIndex=(records.length-index);
+iconDiv.appendChild(img);
+iconDiv.setAttribute("index",index);
+iconDiv.onmouseover=onMouseOver;
+iconStackDiv.firstChild.appendChild(iconDiv);
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconDiv,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+self._eventIdToElmt[evt.getID()]=iconDiv;
+};
+for(var i=0;
+i<records.length;
+i++){paintEvent(i);
+}if(showMoreMessage){var moreEvents=events.slice(limit);
+var moreMessageLabelElmtData=this._paintEventLabel({tooltip:moreMessage},{text:moreMessage},anchorPixel+moreMessageLabelLeft,verticalPixelOffset+moreMessageLabelTop,moreMessageLabelSize.width,moreMessageLabelSize.height,theme);
+var moreMessageClickHandler=function(elmt,domEvt,target){return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt,domEvt,moreEvents);
+};
+SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt,"mousedown",moreMessageClickHandler);
+for(var i=0;
+i<moreEvents.length;
+i++){this._eventIdToElmt[moreEvents[i].getID()]=moreMessageLabelElmtData.elmt;
+}}};
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),latestStart:evt.getLatestStart(),earliestEnd:evt.getEarliestEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:true};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:false};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getLatestStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var commonData={tooltip:evt.getProperty("tooltip")||evt.getText()};
+var tapeData={start:evt.getStart(),end:evt.getEnd(),latestStart:evt.getLatestStart(),earliestEnd:evt.getEarliestEnd(),color:evt.getColor()||evt.getTextColor(),isInstant:false};
+var iconData={url:evt.getIcon()};
+if(iconData.url==null){iconData=null;
+}else{iconData.width=evt.getProperty("iconWidth")||metrics.customIconWidth;
+iconData.height=evt.getProperty("iconHeight")||metrics.customIconHeight;
+}var labelData={text:evt.getText(),color:evt.getTextColor()||evt.getColor(),className:evt.getClassName()};
+var result=this.paintTapeIconLabel(evt.getLatestStart(),commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex);
+var self=this;
+var clickHandler=iconData!=null?function(elmt,domEvt,target){return self._onClickInstantEvent(result.iconElmtData.elmt,domEvt,evt);
+}:function(elmt,domEvt,target){return self._onClickInstantEvent(result.labelElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(result.labelElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt,"mousedown",clickHandler);
+if(iconData!=null){SimileAjax.DOM.registerEvent(result.iconElmtData.elmt,"mousedown",clickHandler);
+this._eventIdToElmt[evt.getID()]=result.iconElmtData.elmt;
+}else{this._eventIdToElmt[evt.getID()]=result.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel=function(anchorDate,commonData,tapeData,iconData,labelData,metrics,theme,highlightIndex){var band=this._band;
+var getPixelOffset=function(date){return Math.round(band.dateToPixelOffset(date));
+};
+var anchorPixel=getPixelOffset(anchorDate);
+var newTracks=[];
+var tapeHeightOccupied=0;
+var tapeTrackCount=0;
+var tapeLastTrackExtraSpace=0;
+if(tapeData!=null){tapeHeightOccupied=metrics.tapeHeight+metrics.tapeBottomMargin;
+tapeTrackCount=Math.ceil(metrics.tapeHeight/metrics.trackHeight);
+var tapeEndPixelOffset=getPixelOffset(tapeData.end)-anchorPixel;
+var tapeStartPixelOffset=getPixelOffset(tapeData.start)-anchorPixel;
+for(var t=0;
+t<tapeTrackCount;
+t++){newTracks.push({start:tapeStartPixelOffset,end:tapeEndPixelOffset});
+}tapeLastTrackExtraSpace=metrics.trackHeight-(tapeHeightOccupied%metrics.tapeHeight);
+}var iconStartPixelOffset=0;
+var iconHorizontalSpaceOccupied=0;
+if(iconData!=null){if("iconAlign" in iconData&&iconData.iconAlign=="center"){iconStartPixelOffset=-Math.floor(iconData.width/2);
+}iconHorizontalSpaceOccupied=iconStartPixelOffset+iconData.width+metrics.iconLabelGap;
+if(tapeTrackCount>0){newTracks[tapeTrackCount-1].end=Math.max(newTracks[tapeTrackCount-1].end,iconHorizontalSpaceOccupied);
+}var iconHeight=iconData.height+metrics.iconBottomMargin+tapeLastTrackExtraSpace;
+while(iconHeight>0){newTracks.push({start:iconStartPixelOffset,end:iconHorizontalSpaceOccupied});
+iconHeight-=metrics.trackHeight;
+}}var text=labelData.text;
+var labelSize=this._frc.computeSize(text);
+var labelHeight=labelSize.height+metrics.labelBottomMargin+tapeLastTrackExtraSpace;
+var labelEndPixelOffset=iconHorizontalSpaceOccupied+labelSize.width+metrics.labelRightMargin;
+if(tapeTrackCount>0){newTracks[tapeTrackCount-1].end=Math.max(newTracks[tapeTrackCount-1].end,labelEndPixelOffset);
+}for(var i=0;
+labelHeight>0;
+i++){if(tapeTrackCount+i<newTracks.length){var track=newTracks[tapeTrackCount+i];
+track.end=labelEndPixelOffset;
+}else{newTracks.push({start:0,end:labelEndPixelOffset});
+}labelHeight-=metrics.trackHeight;
+}var firstTrack=this._fitTracks(anchorPixel,newTracks);
+var verticalPixelOffset=firstTrack*metrics.trackHeight+metrics.trackOffset;
+var result={};
+result.labelElmtData=this._paintEventLabel(commonData,labelData,anchorPixel+iconHorizontalSpaceOccupied,verticalPixelOffset+tapeHeightOccupied,labelSize.width,labelSize.height,theme);
+if(tapeData!=null){if("latestStart" in tapeData||"earliestEnd" in tapeData){result.impreciseTapeElmtData=this._paintEventTape(commonData,tapeData,metrics.tapeHeight,verticalPixelOffset,getPixelOffset(tapeData.start),getPixelOffset(tapeData.end),theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme);
+}if(!tapeData.isInstant&&"start" in tapeData&&"end" in tapeData){result.tapeElmtData=this._paintEventTape(commonData,tapeData,metrics.tapeHeight,verticalPixelOffset,anchorPixel,getPixelOffset("earliestEnd" in tapeData?tapeData.earliestEnd:tapeData.end),tapeData.color,100,metrics,theme);
+}}if(iconData!=null){result.iconElmtData=this._paintEventIcon(commonData,iconData,verticalPixelOffset+tapeHeightOccupied,anchorPixel+iconStartPixelOffset,metrics,theme);
+}return result;
+};
+Timeline.CompactEventPainter.prototype._fitTracks=function(anchorPixel,newTracks){var firstTrack;
+for(firstTrack=0;
+firstTrack<this._tracks.length;
+firstTrack++){var fit=true;
+for(var j=0;
+j<newTracks.length&&(firstTrack+j)<this._tracks.length;
+j++){var existingTrack=this._tracks[firstTrack+j];
+var newTrack=newTracks[j];
+if(anchorPixel+newTrack.start<existingTrack){fit=false;
+break;
+}}if(fit){break;
+}}for(var i=0;
+i<newTracks.length;
+i++){this._tracks[firstTrack+i]=anchorPixel+newTracks[i].end;
+}return firstTrack;
+};
+Timeline.CompactEventPainter.prototype._paintEventIcon=function(commonData,iconData,top,left,metrics,theme){var img=SimileAjax.Graphics.createTranslucentImage(iconData.url);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.className="timeline-event-icon"+("className" in iconData?(" "+iconData.className):"");
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){iconDiv.title=commonData.tooltip;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.CompactEventPainter.prototype._paintEventLabel=function(commonData,labelData,left,top,width,height,theme){var doc=this._timeline.getDocument();
+var labelDiv=doc.createElement("div");
+labelDiv.className="timeline-event-label";
+labelDiv.style.left=left+"px";
+labelDiv.style.width=(width+1)+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=labelData.text;
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){labelDiv.title=commonData.tooltip;
+}if("color" in labelData&&typeof labelData.color=="string"){labelDiv.style.color=labelData.color;
+}if("className" in labelData&&typeof labelData.className=="string"){labelDiv.className+=" "+labelData.className;
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.CompactEventPainter.prototype._paintEventTape=function(commonData,tapeData,height,top,startPixel,endPixel,color,opacity,metrics,theme){var width=endPixel-startPixel;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className="timeline-event-tape";
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.width=width+"px";
+tapeDiv.style.height=height+"px";
+if("tooltip" in commonData&&typeof commonData.tooltip=="string"){tapeDiv.title=commonData.tooltip;
+}if(color!=null&&typeof tapeData.color=="string"){tapeDiv.style.backgroundColor=color;
+}if("backgroundImage" in tapeData&&typeof tapeData.backgroundImage=="string"){tapeDiv.style.backgroundImage="url("+backgroundImage+")";
+tapeDiv.style.backgroundRepeat=("backgroundRepeat" in tapeData&&typeof tapeData.backgroundRepeat=="string")?tapeData.backgroundRepeat:"repeat";
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+if("className" in tapeData&&typeof tapeData.className=="string"){tapeDiv.className+=" "+tapeData.className;
+}this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:width,height:height,elmt:tapeDiv};
+};
+Timeline.CompactEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+this._highlightLayer.appendChild(div);
+}};
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent=function(icon,domEvt,events){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),events);
+var ids=[];
+for(var i=0;
+i<events.length;
+i++){ids.push(events[i].getID());
+}this._fireOnSelect(ids);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),[evt]);
+this._fireOnSelect([evt.getID()]);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,[evt]);
+this._fireOnSelect([evt.getID()]);
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.CompactEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,[evt]);
+}};
+Timeline.CompactEventPainter.prototype._showBubble=function(x,y,evts){var div=document.createElement("div");
+evts=("fillInfoBubble" in evts)?[evts]:evts;
+for(var i=0;
+i<evts.length;
+i++){var div2=document.createElement("div");
+div.appendChild(div2);
+evts[i].fillInfoBubble(div2,this._params.theme,this._band.getLabeller());
+}SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,this._params.theme.event.bubble.width);
+};
+Timeline.CompactEventPainter.prototype._fireOnSelect=function(eventIDs){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventIDs);
+}};
+
+
+/* decorators.js */
+Timeline.SpanHighlightDecorator=function(params){this._unit=params.unit!=null?params.unit:SimileAjax.NativeDateUnit;
+this._startDate=(typeof params.startDate=="string")?this._unit.parseFromObject(params.startDate):params.startDate;
+this._endDate=(typeof params.endDate=="string")?this._unit.parseFromObject(params.endDate):params.endDate;
+this._startLabel=params.startLabel!=null?params.startLabel:"";
+this._endLabel=params.endLabel!=null?params.endLabel:"";
+this._color=params.color;
+this._cssClass=params.cssClass!=null?params.cssClass:null;
+this._opacity=params.opacity!=null?params.opacity:100;
+this._zIndex=(params.inFront!=null&&params.inFront)?113:10;
+};
+Timeline.SpanHighlightDecorator.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._layerDiv=null;
+};
+Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(this._zIndex);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+if(this._unit.compare(this._startDate,maxDate)<0&&this._unit.compare(this._endDate,minDate)>0){minDate=this._unit.later(minDate,this._startDate);
+maxDate=this._unit.earlier(maxDate,this._endDate);
+var minPixel=this._band.dateToPixelOffset(minDate);
+var maxPixel=this._band.dateToPixelOffset(maxDate);
+var doc=this._timeline.getDocument();
+var createTable=function(){var table=doc.createElement("table");
+table.insertRow(0).insertCell(0);
+return table;
+};
+var div=doc.createElement("div");
+div.className="timeline-highlight-decorator";
+if(this._cssClass){div.className+=" "+this._cssClass;
+}if(this._color!=null){div.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(div,this._opacity);
+}this._layerDiv.appendChild(div);
+var tableStartLabel=createTable();
+tableStartLabel.className="timeline-highlight-label timeline-highlight-label-start";
+var tdStart=tableStartLabel.rows[0].cells[0];
+tdStart.innerHTML=this._startLabel;
+if(this._cssClass){tdStart.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(tableStartLabel);
+var tableEndLabel=createTable();
+tableEndLabel.className="timeline-highlight-label timeline-highlight-label-end";
+var tdEnd=tableEndLabel.rows[0].cells[0];
+tdEnd.innerHTML=this._endLabel;
+if(this._cssClass){tdEnd.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(tableEndLabel);
+if(this._timeline.isHorizontal()){div.style.left=minPixel+"px";
+div.style.width=(maxPixel-minPixel)+"px";
+tableStartLabel.style.right=(this._band.getTotalViewLength()-minPixel)+"px";
+tableStartLabel.style.width=(this._startLabel.length)+"em";
+tableEndLabel.style.left=maxPixel+"px";
+tableEndLabel.style.width=(this._endLabel.length)+"em";
+}else{div.style.top=minPixel+"px";
+div.style.height=(maxPixel-minPixel)+"px";
+tableStartLabel.style.bottom=minPixel+"px";
+tableStartLabel.style.height="1.5px";
+tableEndLabel.style.top=maxPixel+"px";
+tableEndLabel.style.height="1.5px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
+Timeline.PointHighlightDecorator=function(params){this._unit=params.unit!=null?params.unit:SimileAjax.NativeDateUnit;
+this._date=(typeof params.date=="string")?this._unit.parseFromObject(params.date):params.date;
+this._width=params.width!=null?params.width:10;
+this._color=params.color;
+this._cssClass=params.cssClass!=null?params.cssClass:"";
+this._opacity=params.opacity!=null?params.opacity:100;
+};
+Timeline.PointHighlightDecorator.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._layerDiv=null;
+};
+Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(10);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+if(this._unit.compare(this._date,maxDate)<0&&this._unit.compare(this._date,minDate)>0){var pixel=this._band.dateToPixelOffset(this._date);
+var minPixel=pixel-Math.round(this._width/2);
+var doc=this._timeline.getDocument();
+var div=doc.createElement("div");
+div.className="timeline-highlight-point-decorator";
+div.className+=" "+this._cssClass;
+if(this._color!=null){div.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(div,this._opacity);
+}this._layerDiv.appendChild(div);
+if(this._timeline.isHorizontal()){div.style.left=minPixel+"px";
+div.style.width=this._width+"px";
+}else{div.style.top=minPixel+"px";
+div.style.height=this._width+"px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
+
+
+/* detailed-painter.js */
+Timeline.DetailedEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.DetailedEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
+};
+Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var eventTheme=this._params.theme.event;
+var trackHeight=Math.max(eventTheme.track.height,this._frc.getLineHeight());
+var metrics={trackOffset:Math.round(this._band.getViewWidth()/2-trackHeight/2),trackHeight:trackHeight,trackGap:eventTheme.track.gap,trackIncrement:trackHeight+eventTheme.track.gap,icon:eventTheme.instant.icon,iconWidth:eventTheme.instant.iconWidth,iconHeight:eventTheme.instant.iconHeight,labelWidth:eventTheme.label.width};
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,metrics.trackIncrement);
+};
+Timeline.DetailedEventPainter.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._lowerTracks=[];
+this._upperTracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.DetailedEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelSize=this._frc.computeSize(text);
+var iconTrack=this._findFreeTrackForSolid(iconRightEdge,startPixel);
+var iconElmtData=this._paintEventIcon(evt,iconTrack,iconLeftEdge,metrics,theme);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelTrack=iconTrack;
+var iconTrackData=this._getTrackData(iconTrack);
+if(Math.min(iconTrackData.solid,iconTrackData.text)>=labelLeft+labelSize.width){iconTrackData.solid=iconLeftEdge;
+iconTrackData.text=labelLeft;
+}else{iconTrackData.solid=iconLeftEdge;
+labelLeft=startPixel+theme.event.label.offsetFromLine;
+labelTrack=this._findFreeTrackForText(iconTrack,labelLeft+labelSize.width,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=iconLeftEdge;
+this._paintEventLine(evt,startPixel,iconTrack,labelTrack,metrics,theme);
+}var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,iconElmtData,theme);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelSize=this._frc.computeSize(text);
+var iconTrack=this._findFreeTrackForSolid(endPixel,startPixel);
+var tapeElmtData=this._paintEventTape(evt,iconTrack,startPixel,endPixel,theme.event.instant.impreciseColor,theme.event.instant.impreciseOpacity,metrics,theme);
+var iconElmtData=this._paintEventIcon(evt,iconTrack,iconLeftEdge,metrics,theme);
+var iconTrackData=this._getTrackData(iconTrack);
+iconTrackData.solid=iconLeftEdge;
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var labelTrack;
+if(labelRight<endPixel){labelTrack=iconTrack;
+}else{labelLeft=startPixel+theme.event.label.offsetFromLine;
+labelRight=labelLeft+labelSize.width;
+labelTrack=this._findFreeTrackForText(iconTrack,labelRight,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=iconLeftEdge;
+this._paintEventLine(evt,startPixel,iconTrack,labelTrack,metrics,theme);
+}var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,iconElmtData,theme);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var labelSize=this._frc.computeSize(text);
+var tapeTrack=this._findFreeTrackForSolid(endPixel);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var tapeElmtData=this._paintEventTape(evt,tapeTrack,startPixel,endPixel,color,100,metrics,theme);
+var tapeTrackData=this._getTrackData(tapeTrack);
+tapeTrackData.solid=startPixel;
+var labelLeft=startPixel+theme.event.label.offsetFromLine;
+var labelTrack=this._findFreeTrackForText(tapeTrack,labelLeft+labelSize.width,function(t){t.line=startPixel-2;
+});
+this._getTrackData(labelTrack).text=startPixel-2;
+this._paintEventLine(evt,startPixel,tapeTrack,labelTrack,metrics,theme);
+var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var latestStartDate=evt.getLatestStart();
+var endDate=evt.getEnd();
+var earliestEndDate=evt.getEarliestEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var labelSize=this._frc.computeSize(text);
+var tapeTrack=this._findFreeTrackForSolid(endPixel);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var impreciseTapeElmtData=this._paintEventTape(evt,tapeTrack,startPixel,endPixel,theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme);
+var tapeElmtData=this._paintEventTape(evt,tapeTrack,latestStartPixel,earliestEndPixel,color,100,metrics,theme);
+var tapeTrackData=this._getTrackData(tapeTrack);
+tapeTrackData.solid=startPixel;
+var labelLeft=latestStartPixel+theme.event.label.offsetFromLine;
+var labelTrack=this._findFreeTrackForText(tapeTrack,labelLeft+labelSize.width,function(t){t.line=latestStartPixel-2;
+});
+this._getTrackData(labelTrack).text=latestStartPixel-2;
+this._paintEventLine(evt,latestStartPixel,tapeTrack,labelTrack,metrics,theme);
+var labelTop=Math.round(metrics.trackOffset+labelTrack*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme);
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(solidEdge,softEdge){for(var i=0;
+true;
+i++){if(i<this._lowerTracks.length){var t=this._lowerTracks[i];
+if(Math.min(t.solid,t.text)>solidEdge&&(!(softEdge)||t.line>softEdge)){return i;
+}}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return i;
+}if(i<this._upperTracks.length){var t=this._upperTracks[i];
+if(Math.min(t.solid,t.text)>solidEdge&&(!(softEdge)||t.line>softEdge)){return -1-i;
+}}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return -1-i;
+}}};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(fromTrack,edge,occupiedTrackVisitor){var extendUp;
+var index;
+var firstIndex;
+var result;
+if(fromTrack<0){extendUp=true;
+firstIndex=-fromTrack;
+index=this._findFreeUpperTrackForText(firstIndex,edge);
+result=-1-index;
+}else{if(fromTrack>0){extendUp=false;
+firstIndex=fromTrack+1;
+index=this._findFreeLowerTrackForText(firstIndex,edge);
+result=index;
+}else{var upIndex=this._findFreeUpperTrackForText(0,edge);
+var downIndex=this._findFreeLowerTrackForText(1,edge);
+if(downIndex-1<=upIndex){extendUp=false;
+firstIndex=1;
+index=downIndex;
+result=index;
+}else{extendUp=true;
+firstIndex=0;
+index=upIndex;
+result=-1-index;
+}}}if(extendUp){if(index==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var i=firstIndex;
+i<index;
+i++){occupiedTrackVisitor(this._upperTracks[i]);
+}}else{if(index==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var i=firstIndex;
+i<index;
+i++){occupiedTrackVisitor(this._lowerTracks[i]);
+}}return result;
+};
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(index,edge){for(;
+index<this._lowerTracks.length;
+index++){var t=this._lowerTracks[index];
+if(Math.min(t.solid,t.text)>=edge){break;
+}}return index;
+};
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(index,edge){for(;
+index<this._upperTracks.length;
+index++){var t=this._upperTracks[index];
+if(Math.min(t.solid,t.text)>=edge){break;
+}}return index;
+};
+Timeline.DetailedEventPainter.prototype._getTrackData=function(index){return(index<0)?this._upperTracks[-index-1]:this._lowerTracks[index];
+};
+Timeline.DetailedEventPainter.prototype._paintEventLine=function(evt,left,startTrack,endTrack,metrics,theme){var top=Math.round(metrics.trackOffset+startTrack*metrics.trackIncrement+metrics.trackHeight/2);
+var height=Math.round(Math.abs(endTrack-startTrack)*metrics.trackIncrement);
+var lineStyle="1px solid "+theme.event.label.lineColor;
+var lineDiv=this._timeline.getDocument().createElement("div");
+lineDiv.style.position="absolute";
+lineDiv.style.left=left+"px";
+lineDiv.style.width=theme.event.label.offsetFromLine+"px";
+lineDiv.style.height=height+"px";
+if(startTrack>endTrack){lineDiv.style.top=(top-height)+"px";
+lineDiv.style.borderTop=lineStyle;
+}else{lineDiv.style.top=top+"px";
+lineDiv.style.borderBottom=lineStyle;
+}lineDiv.style.borderLeft=lineStyle;
+this._lineLayer.appendChild(lineDiv);
+};
+Timeline.DetailedEventPainter.prototype._paintEventIcon=function(evt,iconTrack,left,metrics,theme){var icon=evt.getIcon();
+icon=icon!=null?icon:metrics.icon;
+var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+var top=Math.round(middle-metrics.iconHeight/2);
+var img=SimileAjax.Graphics.createTranslucentImage(icon);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.style.position="absolute";
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+iconDiv.style.cursor="pointer";
+if(evt._title!=null){iconDiv.title=evt._title;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.DetailedEventPainter.prototype._paintEventLabel=function(evt,text,left,top,width,height,theme){var doc=this._timeline.getDocument();
+var labelBackgroundDiv=doc.createElement("div");
+labelBackgroundDiv.style.position="absolute";
+labelBackgroundDiv.style.left=left+"px";
+labelBackgroundDiv.style.width=width+"px";
+labelBackgroundDiv.style.top=top+"px";
+labelBackgroundDiv.style.height=height+"px";
+labelBackgroundDiv.style.backgroundColor=theme.event.label.backgroundColor;
+SimileAjax.Graphics.setOpacity(labelBackgroundDiv,theme.event.label.backgroundOpacity);
+this._eventLayer.appendChild(labelBackgroundDiv);
+var labelDiv=doc.createElement("div");
+labelDiv.style.position="absolute";
+labelDiv.style.left=left+"px";
+labelDiv.style.width=width+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=text;
+labelDiv.style.cursor="pointer";
+if(evt._title!=null){labelDiv.title=evt._title;
+}var color=evt.getTextColor();
+if(color==null){color=evt.getColor();
+}if(color!=null){labelDiv.style.color=color;
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.DetailedEventPainter.prototype._paintEventTape=function(evt,iconTrack,startPixel,endPixel,color,opacity,metrics,theme){var tapeWidth=endPixel-startPixel;
+var tapeHeight=theme.event.tape.height;
+var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+var top=Math.round(middle-tapeHeight/2);
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.style.position="absolute";
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.width=tapeWidth+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.height=tapeHeight+"px";
+tapeDiv.style.backgroundColor=color;
+tapeDiv.style.overflow="hidden";
+tapeDiv.style.cursor="pointer";
+if(evt._title!=null){tapeDiv.title=evt._title;
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:tapeWidth,height:tapeHeight,elmt:tapeDiv};
+};
+Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}};
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.DetailedEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,evt);
+}};
+Timeline.DetailedEventPainter.prototype._showBubble=function(x,y,evt){var div=document.createElement("div");
+var themeBubble=this._params.theme.event.bubble;
+evt.fillInfoBubble(div,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,themeBubble.width,null,themeBubble.maxHeight);
+};
+Timeline.DetailedEventPainter.prototype._fireOnSelect=function(eventID){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventID);
+}};
+
+
+/* ether-painters.js */
+Timeline.GregorianEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._unit=params.unit;
+this._multiple=("multiple" in params)?params.multiple:1;
+};
+Timeline.GregorianEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.GregorianEtherPainter.prototype.setHighlight=function(startDate,endDate,orthogonalOffset,orthogonalExtent){this._highlight.position(startDate,endDate,orthogonalOffset,orthogonalExtent);
+};
+Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var timeZone=this._band.getTimeZone();
+var labeller=this._band.getLabeller();
+SimileAjax.DateTime.roundDownToInterval(minDate,this._unit,timeZone,this._multiple,this._theme.firstDayOfWeek);
+var p=this;
+var incrementDate=function(date){for(var i=0;
+i<p._multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,p._unit);
+}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,this._unit,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.GregorianEtherPainter.prototype.zoom=function(netIntervalChange){if(netIntervalChange!=0){this._unit+=netIntervalChange;
+}};
+Timeline.HotZoneGregorianEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:params.unit,multiple:1}];
+for(var i=0;
+i<params.zones.length;
+i++){var zone=params.zones[i];
+var zoneStart=SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
+var zoneEnd=SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
+for(var j=0;
+j<this._zones.length&&zoneEnd>zoneStart;
+j++){var zone2=this._zones[j];
+if(zoneStart<zone2.endTime){if(zoneStart>zone2.startTime){this._zones.splice(j,0,{startTime:zone2.startTime,endTime:zoneStart,unit:zone2.unit,multiple:zone2.multiple});
+j++;
+zone2.startTime=zoneStart;
+}if(zoneEnd<zone2.endTime){this._zones.splice(j,0,{startTime:zoneStart,endTime:zoneEnd,unit:zone.unit,multiple:(zone.multiple)?zone.multiple:1});
+j++;
+zone2.startTime=zoneEnd;
+zoneStart=zoneEnd;
+}else{zone2.multiple=zone.multiple;
+zone2.unit=zone.unit;
+zoneStart=zone2.endTime;
+}}}}};
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var timeZone=this._band.getTimeZone();
+var labeller=this._band.getLabeller();
+var p=this;
+var incrementDate=function(date,zone){for(var i=0;
+i<zone.multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,zone.unit);
+}};
+var zStart=0;
+while(zStart<this._zones.length){if(minDate.getTime()<this._zones[zStart].endTime){break;
+}zStart++;
+}var zEnd=this._zones.length-1;
+while(zEnd>=0){if(maxDate.getTime()>this._zones[zEnd].startTime){break;
+}zEnd--;
+}for(var z=zStart;
+z<=zEnd;
+z++){var zone=this._zones[z];
+var minDate2=new Date(Math.max(minDate.getTime(),zone.startTime));
+var maxDate2=new Date(Math.min(maxDate.getTime(),zone.endTime));
+SimileAjax.DateTime.roundDownToInterval(minDate2,zone.unit,timeZone,zone.multiple,this._theme.firstDayOfWeek);
+SimileAjax.DateTime.roundUpToInterval(maxDate2,zone.unit,timeZone,zone.multiple,this._theme.firstDayOfWeek);
+while(minDate2.getTime()<maxDate2.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate2,labeller,zone.unit,this._markerLayer,this._lineLayer);
+incrementDate(minDate2,zone);
+}}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(netIntervalChange){if(netIntervalChange!=0){for(var i=0;
+i<this._zones.length;
+++i){if(this._zones[i]){this._zones[i].unit+=netIntervalChange;
+}}}};
+Timeline.YearCountEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+this._multiple=("multiple" in params)?params.multiple:1;
+};
+Timeline.YearCountEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.YearCountEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=new Date(this._startDate.getTime());
+var maxDate=this._band.getMaxDate();
+var yearDiff=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
+minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-yearDiff%this._multiple);
+var p=this;
+var incrementDate=function(date){for(var i=0;
+i<p._multiple;
+i++){SimileAjax.DateTime.incrementByInterval(date,SimileAjax.DateTime.YEAR);
+}};
+var labeller={labelInterval:function(date,intervalUnit){var diff=date.getUTCFullYear()-p._startDate.getUTCFullYear();
+return{text:diff,emphasized:diff==0};
+}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
+Timeline.QuarterlyEtherPainter=function(params){this._params=params;
+this._theme=params.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backgroundLayer=band.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var align=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[timeline.isHorizontal()?"hAlign":"vAlign"];
+var showLine=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,align,showLine);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(startDate,endDate){this._highlight.position(startDate,endDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var minDate=new Date(0);
+var maxDate=this._band.getMaxDate();
+minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
+minDate.setUTCMonth(this._startDate.getUTCMonth());
+var p=this;
+var incrementDate=function(date){date.setUTCMonth(date.getUTCMonth()+3);
+};
+var labeller={labelInterval:function(date,intervalUnit){var quarters=(4+(date.getUTCMonth()-p._startDate.getUTCMonth())/3)%4;
+if(quarters!=0){return{text:"Q"+(quarters+1),emphasized:false};
+}else{return{text:"Y"+(date.getUTCFullYear()-p._startDate.getUTCFullYear()+1),emphasized:true};
+}}};
+while(minDate.getTime()<maxDate.getTime()){this._intervalMarkerLayout.createIntervalMarker(minDate,labeller,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+incrementDate(minDate);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
+Timeline.EtherIntervalMarkerLayout=function(timeline,band,theme,align,showLine){var horizontal=timeline.isHorizontal();
+if(horizontal){if(align=="Top"){this.positionDiv=function(div,offset){div.style.left=offset+"px";
+div.style.top="0px";
+};
+}else{this.positionDiv=function(div,offset){div.style.left=offset+"px";
+div.style.bottom="0px";
+};
+}}else{if(align=="Left"){this.positionDiv=function(div,offset){div.style.top=offset+"px";
+div.style.left="0px";
+};
+}else{this.positionDiv=function(div,offset){div.style.top=offset+"px";
+div.style.right="0px";
+};
+}}var markerTheme=theme.ether.interval.marker;
+var lineTheme=theme.ether.interval.line;
+var weekendTheme=theme.ether.interval.weekend;
+var stylePrefix=(horizontal?"h":"v")+align;
+var labelStyler=markerTheme[stylePrefix+"Styler"];
+var emphasizedLabelStyler=markerTheme[stylePrefix+"EmphasizedStyler"];
+var day=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+this.createIntervalMarker=function(date,labeller,unit,markerDiv,lineDiv){var offset=Math.round(band.dateToPixelOffset(date));
+if(showLine&&unit!=SimileAjax.DateTime.WEEK){var divLine=timeline.getDocument().createElement("div");
+divLine.className="timeline-ether-lines";
+if(lineTheme.opacity<100){SimileAjax.Graphics.setOpacity(divLine,lineTheme.opacity);
+}if(horizontal){divLine.style.left=offset+"px";
+}else{divLine.style.top=offset+"px";
+}lineDiv.appendChild(divLine);
+}if(unit==SimileAjax.DateTime.WEEK){var firstDayOfWeek=theme.firstDayOfWeek;
+var saturday=new Date(date.getTime()+(6-firstDayOfWeek-7)*day);
+var monday=new Date(saturday.getTime()+2*day);
+var saturdayPixel=Math.round(band.dateToPixelOffset(saturday));
+var mondayPixel=Math.round(band.dateToPixelOffset(monday));
+var length=Math.max(1,mondayPixel-saturdayPixel);
+var divWeekend=timeline.getDocument().createElement("div");
+divWeekend.className="timeline-ether-weekends";
+if(weekendTheme.opacity<100){SimileAjax.Graphics.setOpacity(divWeekend,weekendTheme.opacity);
+}if(horizontal){divWeekend.style.left=saturdayPixel+"px";
+divWeekend.style.width=length+"px";
+}else{divWeekend.style.top=saturdayPixel+"px";
+divWeekend.style.height=length+"px";
+}lineDiv.appendChild(divWeekend);
+}var label=labeller.labelInterval(date,unit);
+var div=timeline.getDocument().createElement("div");
+div.innerHTML=label.text;
+div.className="timeline-date-label";
+if(label.emphasized){div.className+=" timeline-date-label-em";
+}this.positionDiv(div,offset);
+markerDiv.appendChild(div);
+return div;
+};
+};
+Timeline.EtherHighlight=function(timeline,band,theme,backgroundLayer){var horizontal=timeline.isHorizontal();
+this._highlightDiv=null;
+this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=timeline.getDocument().createElement("div");
+this._highlightDiv.setAttribute("name","ether-highlight");
+this._highlightDiv.className="timeline-ether-highlight";
+var opacity=theme.ether.highlightOpacity;
+if(opacity<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,opacity);
+}backgroundLayer.appendChild(this._highlightDiv);
+}};
+this.position=function(startDate,endDate,orthogonalOffset,orthogonalExtent){orthogonalOffset=orthogonalOffset||0;
+orthogonalExtent=orthogonalExtent||1;
+this._createHighlightDiv();
+var startPixel=Math.round(band.dateToPixelOffset(startDate));
+var endPixel=Math.round(band.dateToPixelOffset(endDate));
+var length=Math.max(endPixel-startPixel,3);
+var totalWidth=band.getViewWidth()-4;
+if(horizontal){this._highlightDiv.style.left=startPixel+"px";
+this._highlightDiv.style.width=length+"px";
+this._highlightDiv.style.top=Math.round(orthogonalOffset*totalWidth)+"px";
+this._highlightDiv.style.height=Math.round(orthogonalExtent*totalWidth)+"px";
+}else{this._highlightDiv.style.top=startPixel+"px";
+this._highlightDiv.style.height=length+"px";
+this._highlightDiv.style.left=Math.round(orthogonalOffset*totalWidth)+"px";
+this._highlightDiv.style.width=Math.round(orthogonalExtent*totalWidth)+"px";
+}};
+};
+
+
+/* ethers.js */
+Timeline.LinearEther=function(params){this._params=params;
+this._interval=params.interval;
+this._pixelsPerInterval=params.pixelsPerInterval;
+};
+Timeline.LinearEther.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._unit=timeline.getUnit();
+if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.LinearEther.prototype.setDate=function(date){this._start=this._unit.cloneValue(date);
+};
+Timeline.LinearEther.prototype.shiftPixels=function(pixels){var numeric=this._interval*pixels/this._pixelsPerInterval;
+this._start=this._unit.change(this._start,numeric);
+};
+Timeline.LinearEther.prototype.dateToPixelOffset=function(date){var numeric=this._unit.compare(date,this._start);
+return this._pixelsPerInterval*numeric/this._interval;
+};
+Timeline.LinearEther.prototype.pixelOffsetToDate=function(pixels){var numeric=pixels*this._interval/this._pixelsPerInterval;
+return this._unit.change(this._start,numeric);
+};
+Timeline.LinearEther.prototype.zoom=function(zoomIn){var netIntervalChange=0;
+var currentZoomIndex=this._band._zoomIndex;
+var newZoomIndex=currentZoomIndex;
+if(zoomIn&&(currentZoomIndex>0)){newZoomIndex=currentZoomIndex-1;
+}if(!zoomIn&&(currentZoomIndex<(this._band._zoomSteps.length-1))){newZoomIndex=currentZoomIndex+1;
+}this._band._zoomIndex=newZoomIndex;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+this._pixelsPerInterval=this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+netIntervalChange=this._band._zoomSteps[newZoomIndex].unit-this._band._zoomSteps[currentZoomIndex].unit;
+return netIntervalChange;
+};
+Timeline.HotZoneEther=function(params){this._params=params;
+this._interval=params.interval;
+this._pixelsPerInterval=params.pixelsPerInterval;
+this._theme=params.theme;
+};
+Timeline.HotZoneEther.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._unit=timeline.getUnit();
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
+var params=this._params;
+for(var i=0;
+i<params.zones.length;
+i++){var zone=params.zones[i];
+var zoneStart=this._unit.parseFromObject(zone.start);
+var zoneEnd=this._unit.parseFromObject(zone.end);
+for(var j=0;
+j<this._zones.length&&this._unit.compare(zoneEnd,zoneStart)>0;
+j++){var zone2=this._zones[j];
+if(this._unit.compare(zoneStart,zone2.endTime)<0){if(this._unit.compare(zoneStart,zone2.startTime)>0){this._zones.splice(j,0,{startTime:zone2.startTime,endTime:zoneStart,magnify:zone2.magnify});
+j++;
+zone2.startTime=zoneStart;
+}if(this._unit.compare(zoneEnd,zone2.endTime)<0){this._zones.splice(j,0,{startTime:zoneStart,endTime:zoneEnd,magnify:zone.magnify*zone2.magnify});
+j++;
+zone2.startTime=zoneEnd;
+zoneStart=zoneEnd;
+}else{zone2.magnify*=zone.magnify;
+zoneStart=zone2.endTime;
+}}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.HotZoneEther.prototype.setDate=function(date){this._start=this._unit.cloneValue(date);
+};
+Timeline.HotZoneEther.prototype.shiftPixels=function(pixels){this._start=this.pixelOffsetToDate(pixels);
+};
+Timeline.HotZoneEther.prototype.dateToPixelOffset=function(date){return this._dateDiffToPixelOffset(this._start,date);
+};
+Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(pixels){return this._pixelOffsetToDate(pixels,this._start);
+};
+Timeline.HotZoneEther.prototype.zoom=function(zoomIn){var netIntervalChange=0;
+var currentZoomIndex=this._band._zoomIndex;
+var newZoomIndex=currentZoomIndex;
+if(zoomIn&&(currentZoomIndex>0)){newZoomIndex=currentZoomIndex-1;
+}if(!zoomIn&&(currentZoomIndex<(this._band._zoomSteps.length-1))){newZoomIndex=currentZoomIndex+1;
+}this._band._zoomIndex=newZoomIndex;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+this._pixelsPerInterval=this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+netIntervalChange=this._band._zoomSteps[newZoomIndex].unit-this._band._zoomSteps[currentZoomIndex].unit;
+return netIntervalChange;
+};
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(fromDate,toDate){var scale=this._getScale();
+var fromTime=fromDate;
+var toTime=toDate;
+var pixels=0;
+if(this._unit.compare(fromTime,toTime)<0){var z=0;
+while(z<this._zones.length){if(this._unit.compare(fromTime,this._zones[z].endTime)<0){break;
+}z++;
+}while(this._unit.compare(fromTime,toTime)<0){var zone=this._zones[z];
+var toTime2=this._unit.earlier(toTime,zone.endTime);
+pixels+=(this._unit.compare(toTime2,fromTime)/(scale/zone.magnify));
+fromTime=toTime2;
+z++;
+}}else{var z=this._zones.length-1;
+while(z>=0){if(this._unit.compare(fromTime,this._zones[z].startTime)>0){break;
+}z--;
+}while(this._unit.compare(fromTime,toTime)>0){var zone=this._zones[z];
+var toTime2=this._unit.later(toTime,zone.startTime);
+pixels+=(this._unit.compare(toTime2,fromTime)/(scale/zone.magnify));
+fromTime=toTime2;
+z--;
+}}return pixels;
+};
+Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(pixels,fromDate){var scale=this._getScale();
+var time=fromDate;
+if(pixels>0){var z=0;
+while(z<this._zones.length){if(this._unit.compare(time,this._zones[z].endTime)<0){break;
+}z++;
+}while(pixels>0){var zone=this._zones[z];
+var scale2=scale/zone.magnify;
+if(zone.endTime==Number.POSITIVE_INFINITY){time=this._unit.change(time,pixels*scale2);
+pixels=0;
+}else{var pixels2=this._unit.compare(zone.endTime,time)/scale2;
+if(pixels2>pixels){time=this._unit.change(time,pixels*scale2);
+pixels=0;
+}else{time=zone.endTime;
+pixels-=pixels2;
+}}z++;
+}}else{var z=this._zones.length-1;
+while(z>=0){if(this._unit.compare(time,this._zones[z].startTime)>0){break;
+}z--;
+}pixels=-pixels;
+while(pixels>0){var zone=this._zones[z];
+var scale2=scale/zone.magnify;
+if(zone.startTime==Number.NEGATIVE_INFINITY){time=this._unit.change(time,-pixels*scale2);
+pixels=0;
+}else{var pixels2=this._unit.compare(time,zone.startTime)/scale2;
+if(pixels2>pixels){time=this._unit.change(time,-pixels*scale2);
+pixels=0;
+}else{time=zone.startTime;
+pixels-=pixels2;
+}}z--;
+}}return time;
+};
+Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
+};
+
+
+/* event-utils.js */
+Timeline.EventUtils={};
+Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
+}this._lastEventID+=1;
+return"e"+this._lastEventID;
+};
+Timeline.EventUtils.decodeEventElID=function(elementID){var parts=elementID.split("-");
+if(parts[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
+return{band:null,evt:null};
+}var timeline=Timeline.getTimelineFromID(parts[2]);
+var band=timeline.getBand(parts[3]);
+var evt=band.getEventSource.getEvent(parts[4]);
+return{band:band,evt:evt};
+};
+Timeline.EventUtils.encodeEventElID=function(timeline,band,elType,evt){return elType+"-tl-"+timeline.timelineID+"-"+band.getIndex()+"-"+evt.getID();
+};
+
+
+/* labellers.js */
+Timeline.GregorianDateLabeller=function(locale,timeZone){this._locale=locale;
+this._timeZone=timeZone;
+};
+Timeline.GregorianDateLabeller.monthNames=[];
+Timeline.GregorianDateLabeller.dayNames=[];
+Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
+Timeline.GregorianDateLabeller.getMonthName=function(month,locale){return Timeline.GregorianDateLabeller.monthNames[locale][month];
+};
+Timeline.GregorianDateLabeller.prototype.labelInterval=function(date,intervalUnit){var f=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+if(f==null){f=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+}return f.call(this,date,intervalUnit);
+};
+Timeline.GregorianDateLabeller.prototype.labelPrecise=function(date){return SimileAjax.DateTime.removeTimeZoneOffset(date,this._timeZone).toUTCString();
+};
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(date,intervalUnit){var text;
+var emphasized=false;
+date=SimileAjax.DateTime.removeTimeZoneOffset(date,this._timeZone);
+switch(intervalUnit){case SimileAjax.DateTime.MILLISECOND:text=date.getUTCMilliseconds();
+break;
+case SimileAjax.DateTime.SECOND:text=date.getUTCSeconds();
+break;
+case SimileAjax.DateTime.MINUTE:var m=date.getUTCMinutes();
+if(m==0){text=date.getUTCHours()+":00";
+emphasized=true;
+}else{text=m;
+}break;
+case SimileAjax.DateTime.HOUR:text=date.getUTCHours()+"hr";
+break;
+case SimileAjax.DateTime.DAY:text=Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(),this._locale)+" "+date.getUTCDate();
+break;
+case SimileAjax.DateTime.WEEK:text=Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(),this._locale)+" "+date.getUTCDate();
+break;
+case SimileAjax.DateTime.MONTH:var m=date.getUTCMonth();
+if(m!=0){text=Timeline.GregorianDateLabeller.getMonthName(m,this._locale);
+break;
+}case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var y=date.getUTCFullYear();
+if(y>0){text=date.getUTCFullYear();
+}else{text=(1-y)+"BC";
+}emphasized=(intervalUnit==SimileAjax.DateTime.MONTH)||(intervalUnit==SimileAjax.DateTime.DECADE&&y%100==0)||(intervalUnit==SimileAjax.DateTime.CENTURY&&y%1000==0);
+break;
+default:text=date.toUTCString();
+}return{text:text,emphasized:emphasized};
+};
+
+
+/* original-painter.js */
+Timeline.OriginalEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._eventPaintListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.OriginalEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
+};
+Timeline.OriginalEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(listener){this._eventPaintListeners.push(listener);
+};
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(listener){for(var i=0;
+i<this._eventPaintListeners.length;
+i++){if(this._eventPaintListeners[i]==listener){this._eventPaintListeners.splice(i,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._eventIdToElmt={};
+this._fireEventPaintListeners("paintStarting",null,null);
+this._prepareForPainting();
+var metrics=this._computeMetrics();
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,metrics.trackIncrement);
+this._fireEventPaintListeners("paintEnded",null,null);
+this._setOrthogonalOffset(metrics);
+};
+Timeline.OriginalEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.OriginalEventPainter.prototype.getOrthogonalExtent=function(){var metrics=this._computeMetrics();
+return 2*metrics.trackOffset+this._tracks.length*metrics.trackIncrement;
+};
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset=function(metrics){var orthogonalOffset=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=orthogonalOffset+"px";
+};
+Timeline.OriginalEventPainter.prototype._computeMetrics=function(){var eventTheme=this._params.theme.event;
+var trackHeight=Math.max(eventTheme.track.height,eventTheme.tape.height+this._frc.getLineHeight());
+var metrics={trackOffset:eventTheme.track.offset,trackHeight:trackHeight,trackGap:eventTheme.track.gap,trackIncrement:trackHeight+eventTheme.track.gap,icon:eventTheme.instant.icon,iconWidth:eventTheme.instant.iconWidth,iconHeight:eventTheme.instant.iconHeight,labelWidth:eventTheme.label.width,maxLabelChar:eventTheme.label.maxLabelChar,impreciseIconMargin:eventTheme.instant.impreciseIconMargin};
+return metrics;
+};
+Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var eventLabelPrototype=document.createElement("span");
+eventLabelPrototype.className="timeline-event-label";
+this._backLayer.appendChild(eventLabelPrototype);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=band.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OriginalEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseInstantEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){if(evt.isImprecise()){this.paintImpreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintPreciseDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=labelRight;
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+metrics.trackHeight/2-labelSize.height/2);
+var iconElmtData=this._paintEventIcon(evt,track,iconLeftEdge,metrics,theme,0);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[iconElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,iconElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+this._tracks[track]=iconLeftEdge;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var iconRightEdge=Math.round(startPixel+metrics.iconWidth/2);
+var iconLeftEdge=Math.round(startPixel-metrics.iconWidth/2);
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=iconRightEdge+theme.event.label.offsetFromLine;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var tapeHeight=theme.event.tape.height;
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+tapeHeight);
+var iconElmtData=this._paintEventIcon(evt,track,iconLeftEdge,metrics,theme,tapeHeight);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var color=evt.getColor();
+color=color!=null?color:theme.event.instant.impreciseColor;
+var tapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,color,theme.event.instant.impreciseOpacity,metrics,theme,0);
+var els=[iconElmtData.elmt,labelElmtData.elmt,tapeElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickInstantEvent(iconElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(iconElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,iconElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=iconElmtData.elmt;
+this._tracks[track]=iconLeftEdge;
+};
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var endDate=evt.getEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=startPixel;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+theme.event.tape.height);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var tapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,color,100,metrics,theme,0);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[tapeElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,tapeElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+this._tracks[track]=startPixel;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(evt,metrics,theme,highlightIndex){var doc=this._timeline.getDocument();
+var text=evt.getText();
+var startDate=evt.getStart();
+var latestStartDate=evt.getLatestStart();
+var endDate=evt.getEnd();
+var earliestEndDate=evt.getEarliestEnd();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var endPixel=Math.round(this._band.dateToPixelOffset(endDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var labelDivClassName=this._getLabelDivClassName(evt);
+var labelSize=this._frc.computeSize(text,labelDivClassName);
+var labelLeft=latestStartPixel;
+var labelRight=labelLeft+labelSize.width;
+var rightEdge=Math.max(labelRight,endPixel);
+var track=this._findFreeTrack(evt,rightEdge);
+var labelTop=Math.round(metrics.trackOffset+track*metrics.trackIncrement+theme.event.tape.height);
+var color=evt.getColor();
+color=color!=null?color:theme.event.duration.color;
+var impreciseTapeElmtData=this._paintEventTape(evt,track,startPixel,endPixel,theme.event.duration.impreciseColor,theme.event.duration.impreciseOpacity,metrics,theme,0);
+var tapeElmtData=this._paintEventTape(evt,track,latestStartPixel,earliestEndPixel,color,100,metrics,theme,1);
+var labelElmtData=this._paintEventLabel(evt,text,labelLeft,labelTop,labelSize.width,labelSize.height,theme,labelDivClassName,highlightIndex);
+var els=[impreciseTapeElmtData.elmt,tapeElmtData.elmt,labelElmtData.elmt];
+var self=this;
+var clickHandler=function(elmt,domEvt,target){return self._onClickDurationEvent(tapeElmtData.elmt,domEvt,evt);
+};
+SimileAjax.DOM.registerEvent(tapeElmtData.elmt,"mousedown",clickHandler);
+SimileAjax.DOM.registerEvent(labelElmtData.elmt,"mousedown",clickHandler);
+var hDiv=this._createHighlightDiv(highlightIndex,tapeElmtData,theme,evt);
+if(hDiv!=null){els.push(hDiv);
+}this._fireEventPaintListeners("paintedEvent",evt,els);
+this._eventIdToElmt[evt.getID()]=tapeElmtData.elmt;
+this._tracks[track]=startPixel;
+};
+Timeline.OriginalEventPainter.prototype._encodeEventElID=function(elType,evt){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,elType,evt);
+};
+Timeline.OriginalEventPainter.prototype._findFreeTrack=function(event,rightEdge){var trackAttribute=event.getTrackNum();
+if(trackAttribute!=null){return trackAttribute;
+}for(var i=0;
+i<this._tracks.length;
+i++){var t=this._tracks[i];
+if(t>rightEdge){break;
+}}return i;
+};
+Timeline.OriginalEventPainter.prototype._paintEventIcon=function(evt,iconTrack,left,metrics,theme,tapeHeight){var icon=evt.getIcon();
+icon=icon!=null?icon:metrics.icon;
+var top;
+if(tapeHeight>0){top=metrics.trackOffset+iconTrack*metrics.trackIncrement+tapeHeight+metrics.impreciseIconMargin;
+}else{var middle=metrics.trackOffset+iconTrack*metrics.trackIncrement+metrics.trackHeight/2;
+top=Math.round(middle-metrics.iconHeight/2);
+}var img=SimileAjax.Graphics.createTranslucentImage(icon);
+var iconDiv=this._timeline.getDocument().createElement("div");
+iconDiv.className=this._getElClassName("timeline-event-icon",evt,"icon");
+iconDiv.id=this._encodeEventElID("icon",evt);
+iconDiv.style.left=left+"px";
+iconDiv.style.top=top+"px";
+iconDiv.appendChild(img);
+if(evt._title!=null){iconDiv.title=evt._title;
+}this._eventLayer.appendChild(iconDiv);
+return{left:left,top:top,width:metrics.iconWidth,height:metrics.iconHeight,elmt:iconDiv};
+};
+Timeline.OriginalEventPainter.prototype._paintEventLabel=function(evt,text,left,top,width,height,theme,labelDivClassName,highlightIndex){var doc=this._timeline.getDocument();
+var labelDiv=doc.createElement("div");
+labelDiv.className=labelDivClassName;
+labelDiv.id=this._encodeEventElID("label",evt);
+labelDiv.style.left=left+"px";
+labelDiv.style.width=width+"px";
+labelDiv.style.top=top+"px";
+labelDiv.innerHTML=text;
+if(evt._title!=null){labelDiv.title=evt._title;
+}var color=evt.getTextColor();
+if(color==null){color=evt.getColor();
+}if(color!=null){labelDiv.style.color=color;
+}if(theme.event.highlightLabelBackground&&highlightIndex>=0){labelDiv.style.background=this._getHighlightColor(highlightIndex,theme);
+}this._eventLayer.appendChild(labelDiv);
+return{left:left,top:top,width:width,height:height,elmt:labelDiv};
+};
+Timeline.OriginalEventPainter.prototype._paintEventTape=function(evt,iconTrack,startPixel,endPixel,color,opacity,metrics,theme,tape_index){var tapeWidth=endPixel-startPixel;
+var tapeHeight=theme.event.tape.height;
+var top=metrics.trackOffset+iconTrack*metrics.trackIncrement;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className=this._getElClassName("timeline-event-tape",evt,"tape");
+tapeDiv.id=this._encodeEventElID("tape"+tape_index,evt);
+tapeDiv.style.left=startPixel+"px";
+tapeDiv.style.width=tapeWidth+"px";
+tapeDiv.style.height=tapeHeight+"px";
+tapeDiv.style.top=top+"px";
+if(evt._title!=null){tapeDiv.title=evt._title;
+}if(color!=null){tapeDiv.style.backgroundColor=color;
+}var backgroundImage=evt.getTapeImage();
+var backgroundRepeat=evt.getTapeRepeat();
+backgroundRepeat=backgroundRepeat!=null?backgroundRepeat:"repeat";
+if(backgroundImage!=null){tapeDiv.style.backgroundImage="url("+backgroundImage+")";
+tapeDiv.style.backgroundRepeat=backgroundRepeat;
+}SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+this._eventLayer.appendChild(tapeDiv);
+return{left:startPixel,top:top,width:tapeWidth,height:tapeHeight,elmt:tapeDiv};
+};
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(evt){return this._getElClassName("timeline-event-label",evt,"label");
+};
+Timeline.OriginalEventPainter.prototype._getElClassName=function(elClassName,evt,prefix){var evt_classname=evt.getClassName(),pieces=[];
+if(evt_classname){if(prefix){pieces.push(prefix+"-"+evt_classname+" ");
+}pieces.push(evt_classname+" ");
+}pieces.push(elClassName);
+return(pieces.join(""));
+};
+Timeline.OriginalEventPainter.prototype._getHighlightColor=function(highlightIndex,theme){var highlightColors=theme.event.highlightColors;
+return highlightColors[Math.min(highlightIndex,highlightColors.length-1)];
+};
+Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme,evt){var div=null;
+if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var color=this._getHighlightColor(highlightIndex,theme);
+div=doc.createElement("div");
+div.className=this._getElClassName("timeline-event-highlight",evt,"highlight");
+div.id=this._encodeEventElID("highlight0",evt);
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-2)+"px";
+div.style.width=(dimensions.width+4)+"px";
+div.style.top=(dimensions.top-2)+"px";
+div.style.height=(dimensions.height+4)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}return div;
+};
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(icon,domEvt,evt){var c=SimileAjax.DOM.getPageCoordinates(icon);
+this._showBubble(c.left+Math.ceil(icon.offsetWidth/2),c.top+Math.ceil(icon.offsetHeight/2),evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(target,domEvt,evt){if("pageX" in domEvt){var x=domEvt.pageX;
+var y=domEvt.pageY;
+}else{var c=SimileAjax.DOM.getPageCoordinates(target);
+var x=domEvt.offsetX+c.left;
+var y=domEvt.offsetY+c.top;
+}this._showBubble(x,y,evt);
+this._fireOnSelect(evt.getID());
+domEvt.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(domEvt);
+return false;
+};
+Timeline.OriginalEventPainter.prototype.showBubble=function(evt){var elmt=this._eventIdToElmt[evt.getID()];
+if(elmt){var c=SimileAjax.DOM.getPageCoordinates(elmt);
+this._showBubble(c.left+elmt.offsetWidth/2,c.top+elmt.offsetHeight/2,evt);
+}};
+Timeline.OriginalEventPainter.prototype._showBubble=function(x,y,evt){var div=document.createElement("div");
+var themeBubble=this._params.theme.event.bubble;
+evt.fillInfoBubble(div,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(div,x,y,themeBubble.width,null,themeBubble.maxHeight);
+};
+Timeline.OriginalEventPainter.prototype._fireOnSelect=function(eventID){for(var i=0;
+i<this._onSelectListeners.length;
+i++){this._onSelectListeners[i](eventID);
+}};
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(op,evt,els){for(var i=0;
+i<this._eventPaintListeners.length;
+i++){this._eventPaintListeners[i](this._band,op,evt,els);
+}};
+
+
+/* overview-painter.js */
+Timeline.OverviewEventPainter=function(params){this._params=params;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+};
+Timeline.OverviewEventPainter.prototype.initialize=function(band,timeline){this._band=band;
+this._timeline=timeline;
+this._eventLayer=null;
+this._highlightLayer=null;
+};
+Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
+};
+Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(listener){this._onSelectListeners.push(listener);
+};
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(listener){for(var i=0;
+i<this._onSelectListeners.length;
+i++){if(this._onSelectListeners[i]==listener){this._onSelectListeners.splice(i,1);
+break;
+}}};
+Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(filterMatcher){this._filterMatcher=filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(highlightMatcher){this._highlightMatcher=highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.paint=function(){var eventSource=this._band.getEventSource();
+if(eventSource==null){return ;
+}this._prepareForPainting();
+var eventTheme=this._params.theme.event;
+var metrics={trackOffset:eventTheme.overviewTrack.offset,trackHeight:eventTheme.overviewTrack.height,trackGap:eventTheme.overviewTrack.gap,trackIncrement:eventTheme.overviewTrack.height+eventTheme.overviewTrack.gap};
+var minDate=this._band.getMinDate();
+var maxDate=this._band.getMaxDate();
+var filterMatcher=(this._filterMatcher!=null)?this._filterMatcher:function(evt){return true;
+};
+var highlightMatcher=(this._highlightMatcher!=null)?this._highlightMatcher:function(evt){return -1;
+};
+var iterator=eventSource.getEventReverseIterator(minDate,maxDate);
+while(iterator.hasNext()){var evt=iterator.next();
+if(filterMatcher(evt)){this.paintEvent(evt,metrics,this._params.theme,highlightMatcher(evt));
+}}this._highlightLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,metrics.trackIncrement);
+};
+Timeline.OverviewEventPainter.prototype.softPaint=function(){};
+Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var band=this._band;
+this._tracks=[];
+if(this._highlightLayer!=null){band.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=band.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._eventLayer!=null){band.removeLayerDiv(this._eventLayer);
+}this._eventLayer=band.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OverviewEventPainter.prototype.paintEvent=function(evt,metrics,theme,highlightIndex){if(evt.isInstant()){this.paintInstantEvent(evt,metrics,theme,highlightIndex);
+}else{this.paintDurationEvent(evt,metrics,theme,highlightIndex);
+}};
+Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(evt,metrics,theme,highlightIndex){var startDate=evt.getStart();
+var startPixel=Math.round(this._band.dateToPixelOffset(startDate));
+var color=evt.getColor(),klassName=evt.getClassName();
+if(klassName){color=null;
+}else{color=color!=null?color:theme.event.duration.color;
+}var tickElmtData=this._paintEventTick(evt,startPixel,color,100,metrics,theme);
+this._createHighlightDiv(highlightIndex,tickElmtData,theme);
+};
+Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(evt,metrics,theme,highlightIndex){var latestStartDate=evt.getLatestStart();
+var earliestEndDate=evt.getEarliestEnd();
+var latestStartPixel=Math.round(this._band.dateToPixelOffset(latestStartDate));
+var earliestEndPixel=Math.round(this._band.dateToPixelOffset(earliestEndDate));
+var tapeTrack=0;
+for(;
+tapeTrack<this._tracks.length;
+tapeTrack++){if(earliestEndPixel<this._tracks[tapeTrack]){break;
+}}this._tracks[tapeTrack]=earliestEndPixel;
+var color=evt.getColor(),klassName=evt.getClassName();
+if(klassName){color=null;
+}else{color=color!=null?color:theme.event.duration.color;
+}var tapeElmtData=this._paintEventTape(evt,tapeTrack,latestStartPixel,earliestEndPixel,color,100,metrics,theme,klassName);
+this._createHighlightDiv(highlightIndex,tapeElmtData,theme);
+};
+Timeline.OverviewEventPainter.prototype._paintEventTape=function(evt,track,left,right,color,opacity,metrics,theme,klassName){var top=metrics.trackOffset+track*metrics.trackIncrement;
+var width=right-left;
+var height=metrics.trackHeight;
+var tapeDiv=this._timeline.getDocument().createElement("div");
+tapeDiv.className="timeline-small-event-tape";
+if(klassName){tapeDiv.className+=" small-"+klassName;
+}tapeDiv.style.left=left+"px";
+tapeDiv.style.width=width+"px";
+tapeDiv.style.top=top+"px";
+tapeDiv.style.height=height+"px";
+if(color){tapeDiv.style.backgroundColor=color;
+}if(opacity<100){SimileAjax.Graphics.setOpacity(tapeDiv,opacity);
+}this._eventLayer.appendChild(tapeDiv);
+return{left:left,top:top,width:width,height:height,elmt:tapeDiv};
+};
+Timeline.OverviewEventPainter.prototype._paintEventTick=function(evt,left,color,opacity,metrics,theme){var height=theme.event.overviewTrack.tickHeight;
+var top=metrics.trackOffset-height;
+var width=1;
+var tickDiv=this._timeline.getDocument().createElement("div");
+tickDiv.className="timeline-small-event-icon";
+tickDiv.style.left=left+"px";
+tickDiv.style.top=top+"px";
+var klassName=evt.getClassName();
+if(klassName){tickDiv.className+=" small-"+klassName;
+}if(opacity<100){SimileAjax.Graphics.setOpacity(tickDiv,opacity);
+}this._eventLayer.appendChild(tickDiv);
+return{left:left,top:top,width:width,height:height,elmt:tickDiv};
+};
+Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(highlightIndex,dimensions,theme){if(highlightIndex>=0){var doc=this._timeline.getDocument();
+var eventTheme=theme.event;
+var color=eventTheme.highlightColors[Math.min(highlightIndex,eventTheme.highlightColors.length-1)];
+var div=doc.createElement("div");
+div.style.position="absolute";
+div.style.overflow="hidden";
+div.style.left=(dimensions.left-1)+"px";
+div.style.width=(dimensions.width+2)+"px";
+div.style.top=(dimensions.top-1)+"px";
+div.style.height=(dimensions.height+2)+"px";
+div.style.background=color;
+this._highlightLayer.appendChild(div);
+}};
+Timeline.OverviewEventPainter.prototype.showBubble=function(evt){};
+
+
+/* sources.js */
+Timeline.DefaultEventSource=function(eventIndex){this._events=(eventIndex instanceof Object)?eventIndex:new SimileAjax.EventIndex();
+this._listeners=[];
+};
+Timeline.DefaultEventSource.prototype.addListener=function(listener){this._listeners.push(listener);
+};
+Timeline.DefaultEventSource.prototype.removeListener=function(listener){for(var i=0;
+i<this._listeners.length;
+i++){if(this._listeners[i]==listener){this._listeners.splice(i,1);
+break;
+}}};
+Timeline.DefaultEventSource.prototype.loadXML=function(xml,url){var base=this._getBaseURL(url);
+var wikiURL=xml.documentElement.getAttribute("wiki-url");
+var wikiSection=xml.documentElement.getAttribute("wiki-section");
+var dateTimeFormat=xml.documentElement.getAttribute("date-time-format");
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+var node=xml.documentElement.firstChild;
+var added=false;
+while(node!=null){if(node.nodeType==1){var description="";
+if(node.firstChild!=null&&node.firstChild.nodeType==3){description=node.firstChild.nodeValue;
+}var instant=(node.getAttribute("isDuration")===null&&node.getAttribute("durationEvent")===null)||node.getAttribute("isDuration")=="false"||node.getAttribute("durationEvent")=="false";
+var evt=new Timeline.DefaultEventSource.Event({id:node.getAttribute("id"),start:parseDateTimeFunction(node.getAttribute("start")),end:parseDateTimeFunction(node.getAttribute("end")),latestStart:parseDateTimeFunction(node.getAttribute("latestStart")),earliestEnd:parseDateTimeFunction(node.getAttribute("earliestEnd")),instant:instant,text:node.getAttribute("title"),description:description,image:this._resolveRelativeURL(node.getAttribute("image"),base),link:this._resolveRelativeURL(node.getAttribute("link"),base),icon:this._resolveRelativeURL(node.getAttribute("icon"),base),color:node.getAttribute("color"),textColor:node.getAttribute("textColor"),hoverText:node.getAttribute("hoverText"),classname:node.getAttribute("classname"),tapeImage:node.getAttribute("tapeImage"),tapeRepeat:node.getAttribute("tapeRepeat"),caption:node.getAttribute("caption"),eventID:node.getAttribute("eventID"),trackNum:node.getAttribute("trackNum")});
+evt._node=node;
+evt.getProperty=function(name){return this._node.getAttribute(name);
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}node=node.nextSibling;
+}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadJSON=function(data,url){var base=this._getBaseURL(url);
+var added=false;
+if(data&&data.events){var wikiURL=("wikiURL" in data)?data.wikiURL:null;
+var wikiSection=("wikiSection" in data)?data.wikiSection:null;
+var dateTimeFormat=("dateTimeFormat" in data)?data.dateTimeFormat:null;
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+for(var i=0;
+i<data.events.length;
+i++){var evnt=data.events[i];
+var instant=evnt.isDuration||(("durationEvent" in evnt)&&!evnt.durationEvent)||(("de" in evnt)&&!evnt.de);
+var evt=new Timeline.DefaultEventSource.Event({id:("id" in evnt)?evnt.id:undefined,start:parseDateTimeFunction(evnt.start||evnt.s),end:parseDateTimeFunction(evnt.end||evnt.e),latestStart:parseDateTimeFunction(evnt.latestStart||evnt.ls),earliestEnd:parseDateTimeFunction(evnt.earliestEnd||evnt.ee),instant:instant,text:evnt.title||evnt.t,description:evnt.description||evnt.d,image:this._resolveRelativeURL(evnt.image,base),link:this._resolveRelativeURL(evnt.link,base),icon:this._resolveRelativeURL(evnt.icon,base),color:evnt.color,textColor:evnt.textColor,hoverText:evnt.hoverText,classname:evnt.classname||evnt.c,tapeImage:evnt.tapeImage,tapeRepeat:evnt.tapeRepeat,caption:evnt.caption,eventID:evnt.eventID||evnt.eid,trackNum:evnt.trackNum});
+evt._obj=evnt;
+evt.getProperty=function(name){return this._obj[name];
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadSPARQL=function(xml,url){var base=this._getBaseURL(url);
+var dateTimeFormat="iso8601";
+var parseDateTimeFunction=this._events.getUnit().getParser(dateTimeFormat);
+if(xml==null){return ;
+}var node=xml.documentElement.firstChild;
+while(node!=null&&(node.nodeType!=1||node.nodeName!="results")){node=node.nextSibling;
+}var wikiURL=null;
+var wikiSection=null;
+if(node!=null){wikiURL=node.getAttribute("wiki-url");
+wikiSection=node.getAttribute("wiki-section");
+node=node.firstChild;
+}var added=false;
+while(node!=null){if(node.nodeType==1){var bindings={};
+var binding=node.firstChild;
+while(binding!=null){if(binding.nodeType==1&&binding.firstChild!=null&&binding.firstChild.nodeType==1&&binding.firstChild.firstChild!=null&&binding.firstChild.firstChild.nodeType==3){bindings[binding.getAttribute("name")]=binding.firstChild.firstChild.nodeValue;
+}binding=binding.nextSibling;
+}if(bindings["start"]==null&&bindings["date"]!=null){bindings["start"]=bindings["date"];
+}var instant=(bindings["isDuration"]===null&&bindings["durationEvent"]===null)||bindings["isDuration"]=="false"||bindings["durationEvent"]=="false";
+var evt=new Timeline.DefaultEventSource.Event({id:bindings["id"],start:parseDateTimeFunction(bindings["start"]),end:parseDateTimeFunction(bindings["end"]),latestStart:parseDateTimeFunction(bindings["latestStart"]),earliestEnd:parseDateTimeFunction(bindings["earliestEnd"]),instant:instant,text:bindings["title"],description:bindings["description"],image:this._resolveRelativeURL(bindings["image"],base),link:this._resolveRelativeURL(bindings["link"],base),icon:this._resolveRelativeURL(bindings["icon"],base),color:bindings["color"],textColor:bindings["textColor"],hoverText:bindings["hoverText"],caption:bindings["caption"],classname:bindings["classname"],tapeImage:bindings["tapeImage"],tapeRepeat:bindings["tapeRepeat"],eventID:bindings["eventID"],trackNum:bindings["trackNum"]});
+evt._bindings=bindings;
+evt.getProperty=function(name){return this._bindings[name];
+};
+evt.setWikiInfo(wikiURL,wikiSection);
+this._events.add(evt);
+added=true;
+}node=node.nextSibling;
+}if(added){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.add=function(evt){this._events.add(evt);
+this._fire("onAddOne",[evt]);
+};
+Timeline.DefaultEventSource.prototype.addMany=function(events){for(var i=0;
+i<events.length;
+i++){this._events.add(events[i]);
+}this._fire("onAddMany",[]);
+};
+Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
+this._fire("onClear",[]);
+};
+Timeline.DefaultEventSource.prototype.getEvent=function(id){return this._events.getEvent(id);
+};
+Timeline.DefaultEventSource.prototype.getEventIterator=function(startDate,endDate){return this._events.getIterator(startDate,endDate);
+};
+Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(startDate,endDate){return this._events.getReverseIterator(startDate,endDate);
+};
+Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
+};
+Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
+};
+Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
+};
+Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
+};
+Timeline.DefaultEventSource.prototype._fire=function(handlerName,args){for(var i=0;
+i<this._listeners.length;
+i++){var listener=this._listeners[i];
+if(handlerName in listener){try{listener[handlerName].apply(listener,args);
+}catch(e){SimileAjax.Debug.exception(e);
+}}}};
+Timeline.DefaultEventSource.prototype._getBaseURL=function(url){if(url.indexOf("://")<0){var url2=this._getBaseURL(document.location.href);
+if(url.substr(0,1)=="/"){url=url2.substr(0,url2.indexOf("/",url2.indexOf("://")+3))+url;
+}else{url=url2+url;
+}}var i=url.lastIndexOf("/");
+if(i<0){return"";
+}else{return url.substr(0,i+1);
+}};
+Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(url,base){if(url==null||url==""){return url;
+}else{if(url.indexOf("://")>0){return url;
+}else{if(url.substr(0,1)=="/"){return base.substr(0,base.indexOf("/",base.indexOf("://")+3))+url;
+}else{return base+url;
+}}}};
+Timeline.DefaultEventSource.Event=function(args){function cleanArg(arg){return(args[arg]!=null&&args[arg]!="")?args[arg]:null;
+}var id=args.id?args.id.trim():"";
+this._id=id.length>0?id:Timeline.EventUtils.getNewEventID();
+this._instant=args.instant||(args.end==null);
+this._start=args.start;
+this._end=(args.end!=null)?args.end:args.start;
+this._latestStart=(args.latestStart!=null)?args.latestStart:(args.instant?this._end:this._start);
+this._earliestEnd=(args.earliestEnd!=null)?args.earliestEnd:this._end;
+var err=[];
+if(this._start>this._latestStart){this._latestStart=this._start;
+err.push("start is > latestStart");
+}if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
+err.push("start is > earliestEnd");
+}if(this._start>this._end){this._end=this._earliestEnd;
+err.push("start is > end");
+}if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
+err.push("latestStart is > earliestEnd");
+}if(this._latestStart>this._end){this._end=this._earliestEnd;
+err.push("latestStart is > end");
+}if(this._earliestEnd>this._end){this._end=this._earliestEnd;
+err.push("earliestEnd is > end");
+}this._eventID=cleanArg("eventID");
+this._text=(args.text!=null)?SimileAjax.HTML.deEntify(args.text):"";
+if(err.length>0){this._text+=" PROBLEM: "+err.join(", ");
+}this._description=SimileAjax.HTML.deEntify(args.description);
+this._image=cleanArg("image");
+this._link=cleanArg("link");
+this._title=cleanArg("hoverText");
+this._title=cleanArg("caption");
+this._icon=cleanArg("icon");
+this._color=cleanArg("color");
+this._textColor=cleanArg("textColor");
+this._classname=cleanArg("classname");
+this._tapeImage=cleanArg("tapeImage");
+this._tapeRepeat=cleanArg("tapeRepeat");
+this._trackNum=cleanArg("trackNum");
+if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
+}this._wikiURL=null;
+this._wikiSection=null;
+};
+Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
+},isInstant:function(){return this._instant;
+},isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
+},getStart:function(){return this._start;
+},getEnd:function(){return this._end;
+},getLatestStart:function(){return this._latestStart;
+},getEarliestEnd:function(){return this._earliestEnd;
+},getEventID:function(){return this._eventID;
+},getText:function(){return this._text;
+},getDescription:function(){return this._description;
+},getImage:function(){return this._image;
+},getLink:function(){return this._link;
+},getIcon:function(){return this._icon;
+},getColor:function(){return this._color;
+},getTextColor:function(){return this._textColor;
+},getClassName:function(){return this._classname;
+},getTapeImage:function(){return this._tapeImage;
+},getTapeRepeat:function(){return this._tapeRepeat;
+},getTrackNum:function(){return this._trackNum;
+},getProperty:function(name){return null;
+},getWikiURL:function(){return this._wikiURL;
+},getWikiSection:function(){return this._wikiSection;
+},setWikiInfo:function(wikiURL,wikiSection){this._wikiURL=wikiURL;
+this._wikiSection=wikiSection;
+},fillDescription:function(elmt){if(this._description){elmt.innerHTML=this._description;
+}},fillWikiInfo:function(elmt){elmt.style.display="none";
+if(this._wikiURL==null||this._wikiSection==null){return ;
+}var wikiID=this.getProperty("wikiID");
+if(wikiID==null||wikiID.length==0){wikiID=this.getText();
+}if(wikiID==null||wikiID.length==0){return ;
+}elmt.style.display="inline";
+wikiID=wikiID.replace(/\s/g,"_");
+var url=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+wikiID;
+var a=document.createElement("a");
+a.href=url;
+a.target="new";
+a.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+elmt.appendChild(document.createTextNode("["));
+elmt.appendChild(a);
+elmt.appendChild(document.createTextNode("]"));
+},fillTime:function(elmt,labeller){if(this._instant){if(this.isImprecise()){elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+}else{elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+}}else{if(this.isImprecise()){elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)+" ~ "+labeller.labelPrecise(this._latestStart)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._earliestEnd)+" ~ "+labeller.labelPrecise(this._end)));
+}else{elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+elmt.appendChild(elmt.ownerDocument.createElement("br"));
+elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+}}},fillInfoBubble:function(elmt,theme,labeller){var doc=elmt.ownerDocument;
+var title=this.getText();
+var link=this.getLink();
+var image=this.getImage();
+if(image!=null){var img=doc.createElement("img");
+img.src=image;
+theme.event.bubble.imageStyler(img);
+elmt.appendChild(img);
+}var divTitle=doc.createElement("div");
+var textTitle=doc.createTextNode(title);
+if(link!=null){var a=doc.createElement("a");
+a.href=link;
+a.appendChild(textTitle);
+divTitle.appendChild(a);
+}else{divTitle.appendChild(textTitle);
+}theme.event.bubble.titleStyler(divTitle);
+elmt.appendChild(divTitle);
+var divBody=doc.createElement("div");
+this.fillDescription(divBody);
+theme.event.bubble.bodyStyler(divBody);
+elmt.appendChild(divBody);
+var divTime=doc.createElement("div");
+this.fillTime(divTime,labeller);
+theme.event.bubble.timeStyler(divTime);
+elmt.appendChild(divTime);
+var divWiki=doc.createElement("div");
+this.fillWikiInfo(divWiki);
+theme.event.bubble.wikiStyler(divWiki);
+elmt.appendChild(divWiki);
+}};
+
+
+/* themes.js */
+Timeline.ClassicTheme=new Object();
+Timeline.ClassicTheme.implementations=[];
+Timeline.ClassicTheme.create=function(locale){if(locale==null){locale=Timeline.getDefaultLocale();
+}var f=Timeline.ClassicTheme.implementations[locale];
+if(f==null){f=Timeline.ClassicTheme._Impl;
+}return new f();
+};
+Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
+this.autoWidth=false;
+this.autoWidthAnimationTime=500;
+this.timeline_start=null;
+this.timeline_stop=null;
+this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
+this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"images/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(elmt){elmt.className="timeline-event-bubble-title";
+},bodyStyler:function(elmt){elmt.className="timeline-event-bubble-body";
+},imageStyler:function(elmt){elmt.className="timeline-event-bubble-image";
+},wikiStyler:function(elmt){elmt.className="timeline-event-bubble-wiki";
+},timeStyler:function(elmt){elmt.className="timeline-event-bubble-time";
+}}};
+this.mouseWheel="scroll";
+};
+
+
+/* timeline.js */
+Timeline.version="pre 2.4.0";
+Timeline.ajax_lib_version=SimileAjax.version;
+Timeline.display_version=Timeline.version+" (with Ajax lib "+Timeline.ajax_lib_version+")";
+Timeline.strings={};
+Timeline.HORIZONTAL=0;
+Timeline.VERTICAL=1;
+Timeline._defaultTheme=null;
+Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
+};
+Timeline.create=function(elmt,bandInfos,orientation,unit){if(Timeline.timelines==null){Timeline.timelines=[];
+}var timelineID=Timeline.timelines.length;
+Timeline.timelines[timelineID]=null;
+var new_tl=new Timeline._Impl(elmt,bandInfos,orientation,unit,timelineID);
+Timeline.timelines[timelineID]=new_tl;
+return new_tl;
+};
+Timeline.createBandInfo=function(params){var theme=("theme" in params)?params.theme:Timeline.getDefaultTheme();
+var decorators=("decorators" in params)?params.decorators:[];
+var eventSource=("eventSource" in params)?params.eventSource:null;
+var ether=new Timeline.LinearEther({centersOn:("date" in params)?params.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],pixelsPerInterval:params.intervalPixels,theme:theme});
+var etherPainter=new Timeline.GregorianEtherPainter({unit:params.intervalUnit,multiple:("multiple" in params)?params.multiple:1,theme:theme,align:("align" in params)?params.align:undefined});
+var eventPainterParams={showText:("showEventText" in params)?params.showEventText:true,theme:theme};
+if("eventPainterParams" in params){for(var prop in params.eventPainterParams){eventPainterParams[prop]=params.eventPainterParams[prop];
+}}if("trackHeight" in params){eventPainterParams.trackHeight=params.trackHeight;
+}if("trackGap" in params){eventPainterParams.trackGap=params.trackGap;
+}var layout=("overview" in params&&params.overview)?"overview":("layout" in params?params.layout:"original");
+var eventPainter;
+if("eventPainter" in params){eventPainter=new params.eventPainter(eventPainterParams);
+}else{switch(layout){case"overview":eventPainter=new Timeline.OverviewEventPainter(eventPainterParams);
+break;
+case"detailed":eventPainter=new Timeline.DetailedEventPainter(eventPainterParams);
+break;
+default:eventPainter=new Timeline.OriginalEventPainter(eventPainterParams);
+}}return{width:params.width,eventSource:eventSource,timeZone:("timeZone" in params)?params.timeZone:0,ether:ether,etherPainter:etherPainter,eventPainter:eventPainter,theme:theme,decorators:decorators,zoomIndex:("zoomIndex" in params)?params.zoomIndex:0,zoomSteps:("zoomSteps" in params)?params.zoomSteps:null};
+};
+Timeline.createHotZoneBandInfo=function(params){var theme=("theme" in params)?params.theme:Timeline.getDefaultTheme();
+var eventSource=("eventSource" in params)?params.eventSource:null;
+var ether=new Timeline.HotZoneEther({centersOn:("date" in params)?params.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],pixelsPerInterval:params.intervalPixels,zones:params.zones,theme:theme});
+var etherPainter=new Timeline.HotZoneGregorianEtherPainter({unit:params.intervalUnit,zones:params.zones,theme:theme,align:("align" in params)?params.align:undefined});
+var eventPainterParams={showText:("showEventText" in params)?params.showEventText:true,theme:theme};
+if("eventPainterParams" in params){for(var prop in params.eventPainterParams){eventPainterParams[prop]=params.eventPainterParams[prop];
+}}if("trackHeight" in params){eventPainterParams.trackHeight=params.trackHeight;
+}if("trackGap" in params){eventPainterParams.trackGap=params.trackGap;
+}var layout=("overview" in params&&params.overview)?"overview":("layout" in params?params.layout:"original");
+var eventPainter;
+if("eventPainter" in params){eventPainter=new params.eventPainter(eventPainterParams);
+}else{switch(layout){case"overview":eventPainter=new Timeline.OverviewEventPainter(eventPainterParams);
+break;
+case"detailed":eventPainter=new Timeline.DetailedEventPainter(eventPainterParams);
+break;
+default:eventPainter=new Timeline.OriginalEventPainter(eventPainterParams);
+}}return{width:params.width,eventSource:eventSource,timeZone:("timeZone" in params)?params.timeZone:0,ether:ether,etherPainter:etherPainter,eventPainter:eventPainter,theme:theme,zoomIndex:("zoomIndex" in params)?params.zoomIndex:0,zoomSteps:("zoomSteps" in params)?params.zoomSteps:null};
+};
+Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+}return Timeline._defaultTheme;
+};
+Timeline.setDefaultTheme=function(theme){Timeline._defaultTheme=theme;
+};
+Timeline.loadXML=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load data xml from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){var xml=xmlhttp.responseXML;
+if(!xml.documentElement&&xmlhttp.responseStream){xml.load(xmlhttp.responseStream);
+}f(xml,url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.getTimelineFromID=function(timelineID){return Timeline.timelines[timelineID];
+};
+Timeline.writeVersion=function(el_id){document.getElementById(el_id).innerHTML=this.display_version;
+};
+Timeline._Impl=function(elmt,bandInfos,orientation,unit,timelineID){SimileAjax.WindowManager.initialize();
+this._containerDiv=elmt;
+this._bandInfos=bandInfos;
+this._orientation=orientation==null?Timeline.HORIZONTAL:orientation;
+this._unit=(unit!=null)?unit:SimileAjax.NativeDateUnit;
+this._starting=true;
+this._autoResizing=false;
+this.autoWidth=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.autoWidth;
+this.autoWidthAnimationTime=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.autoWidthAnimationTime;
+this.timelineID=timelineID;
+this.timeline_start=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.timeline_start;
+this.timeline_stop=bandInfos&&bandInfos[0]&&bandInfos[0].theme&&bandInfos[0].theme.timeline_stop;
+this.timeline_at_start=false;
+this.timeline_at_stop=false;
+this._initialize();
+};
+Timeline._Impl.prototype.dispose=function(){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].dispose();
+}this._bands=null;
+this._bandInfos=null;
+this._containerDiv.innerHTML="";
+Timeline.timelines[this.timelineID]=null;
+};
+Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
+};
+Timeline._Impl.prototype.getBand=function(index){return this._bands[index];
+};
+Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
+this._starting=false;
+};
+Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
+this._distributeWidths();
+};
+Timeline._Impl.prototype.paint=function(){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].paint();
+}};
+Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
+};
+Timeline._Impl.prototype.addDiv=function(div){this._containerDiv.appendChild(div);
+};
+Timeline._Impl.prototype.removeDiv=function(div){this._containerDiv.removeChild(div);
+};
+Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
+};
+Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
+};
+Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getUnit=function(){return this._unit;
+};
+Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
+};
+Timeline._Impl.prototype.loadXML=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load data xml from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{var xml=xmlhttp.responseXML;
+if(!xml.documentElement&&xmlhttp.responseStream){xml.load(xmlhttp.responseStream);
+}f(xml,url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype._autoWidthScrollListener=function(band){band.getTimeline()._autoWidthCheck(false);
+};
+Timeline._Impl.prototype._autoWidthCheck=function(okToShrink){var timeline=this;
+var immediateChange=timeline._starting;
+var newWidth=0;
+function changeTimelineWidth(){var widthStyle=timeline.getWidthStyle();
+if(immediateChange){timeline._containerDiv.style[widthStyle]=newWidth+"px";
+}else{timeline._autoResizing=true;
+var animateParam={};
+animateParam[widthStyle]=newWidth+"px";
+SimileAjax.jQuery(timeline._containerDiv).animate(animateParam,timeline.autoWidthAnimationTime,"linear",function(){timeline._autoResizing=false;
+});
+}}function checkTimelineWidth(){var targetWidth=0;
+var currentWidth=timeline.getPixelWidth();
+if(timeline._autoResizing){return ;
+}for(var i=0;
+i<timeline._bands.length;
+i++){timeline._bands[i].checkAutoWidth();
+targetWidth+=timeline._bandInfos[i].width;
+}if(targetWidth>currentWidth||okToShrink){newWidth=targetWidth;
+changeTimelineWidth();
+timeline._distributeWidths();
+}}if(!timeline.autoWidth){return ;
+}checkTimelineWidth();
+};
+Timeline._Impl.prototype._initialize=function(){var containerDiv=this._containerDiv;
+var doc=containerDiv.ownerDocument;
+containerDiv.className=containerDiv.className.split(" ").concat("timeline-container").join(" ");
+var orientation=(this.isHorizontal())?"horizontal":"vertical";
+containerDiv.className+=" timeline-"+orientation;
+while(containerDiv.firstChild){containerDiv.removeChild(containerDiv.firstChild);
+}var elmtCopyright=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"images/copyright-vertical.png":"images/copyright.png"));
+elmtCopyright.className="timeline-copyright";
+elmtCopyright.title="SIMILE Timeline - http://www.simile-widgets.org/";
+SimileAjax.DOM.registerEvent(elmtCopyright,"click",function(){window.location="http://www.simile-widgets.org/";
+});
+containerDiv.appendChild(elmtCopyright);
+this._bands=[];
+for(var i=0;
+i<this._bandInfos.length;
+i++){var band=new Timeline._Band(this,this._bandInfos[i],i);
+this._bands.push(band);
+}this._distributeWidths();
+for(var i=0;
+i<this._bandInfos.length;
+i++){var bandInfo=this._bandInfos[i];
+if("syncWith" in bandInfo){this._bands[i].setSyncWithBand(this._bands[bandInfo.syncWith],("highlight" in bandInfo)?bandInfo.highlight:false);
+}}if(this.autoWidth){for(var i=0;
+i<this._bands.length;
+i++){this._bands[i].addOnScrollListener(this._autoWidthScrollListener);
+}}var message=SimileAjax.Graphics.createMessageBubble(doc);
+message.containerDiv.className="timeline-message-container";
+containerDiv.appendChild(message.containerDiv);
+message.contentDiv.className="timeline-message";
+message.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"images/progress-running.gif' /> Loading...";
+this.showLoadingMessage=function(){message.containerDiv.style.display="block";
+};
+this.hideLoadingMessage=function(){message.containerDiv.style.display="none";
+};
+};
+Timeline._Impl.prototype._distributeWidths=function(){var length=this.getPixelLength();
+var width=this.getPixelWidth();
+var cumulativeWidth=0;
+for(var i=0;
+i<this._bands.length;
+i++){var band=this._bands[i];
+var bandInfos=this._bandInfos[i];
+var widthString=bandInfos.width;
+var bandWidth;
+if(typeof widthString=="string"){var x=widthString.indexOf("%");
+if(x>0){var percent=parseInt(widthString.substr(0,x));
+bandWidth=Math.round(percent*width/100);
+}else{bandWidth=parseInt(widthString);
+}}else{bandWidth=widthString;
+}band.setBandShiftAndWidth(cumulativeWidth,bandWidth);
+band.setViewLength(length);
+cumulativeWidth+=bandWidth;
+}};
+Timeline._Impl.prototype.shiftOK=function(index,shift){var going_back=shift>0,going_forward=shift<0;
+if((going_back&&this.timeline_start==null)||(going_forward&&this.timeline_stop==null)||(shift==0)){return(true);
+}var secondary_shift=false;
+for(var i=0;
+i<this._bands.length&&!secondary_shift;
+i++){secondary_shift=this._bands[i].busy();
+}if(secondary_shift){return(true);
+}if((going_back&&this.timeline_at_start)||(going_forward&&this.timeline_at_stop)){return(false);
+}var ok=false;
+for(var i=0;
+i<this._bands.length&&!ok;
+i++){var band=this._bands[i];
+if(going_back){ok=(i==index?band.getMinVisibleDateAfterDelta(shift):band.getMinVisibleDate())>=this.timeline_start;
+}else{ok=(i==index?band.getMaxVisibleDateAfterDelta(shift):band.getMaxVisibleDate())<=this.timeline_stop;
+}}if(going_back){this.timeline_at_start=!ok;
+this.timeline_at_stop=false;
+}else{this.timeline_at_stop=!ok;
+this.timeline_at_start=false;
+}return(ok);
+};
+Timeline._Impl.prototype.zoom=function(zoomIn,x,y,target){var matcher=new RegExp("^timeline-band-([0-9]+)$");
+var bandIndex=null;
+var result=matcher.exec(target.id);
+if(result){bandIndex=parseInt(result[1]);
+}if(bandIndex!=null){this._bands[bandIndex].zoom(zoomIn,x,y,target);
+}this.paint();
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.css b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.css
new file mode 100644
index 00000000..b5cd3d32
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.css
@@ -0,0 +1,243 @@
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+ position:absolute;
+ background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+ position:absolute;
+ overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+ set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+ top:0;
+ height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+ width:100%;
+ left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+ position:absolute; overflow:hidden; font-size:200%;
+ font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+ position: absolute;
+ border: solid #aaa;
+ color: #aaa;
+ width: 5em;
+ height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+ position:absolute;
+ cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ background-color:#58A0DC;
+ overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+ position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+}.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input {
+ width: 0;
+}
+
+.timeline-band-scrollbar {
+ display: none;
+ position: absolute;
+ background: #f8f8f8;
+ z-index: 100;
+ overflow: hidden;
+}
+
+.timeline-band-scrollbar-thumb {
+ margin: 2px;
+ background: #666;
+ position: relative;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.js b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.js
new file mode 100644
index 00000000..095294cc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Exhibit/timeline/api/timeline-bundle.js
@@ -0,0 +1,2950 @@
+
+
+/* band.js */
+Timeline._Band=function(G,H,C){if(G.autoWidth&&typeof H.width=="string"){H.width=H.width.indexOf("%")>-1?0:parseInt(H.width);
+}this._timeline=G;
+this._bandInfo=H;
+this._index=C;
+this._locale=("locale" in H)?H.locale:Timeline.getDefaultLocale();
+this._timeZone=("timeZone" in H)?H.timeZone:0;
+this._labeller=("labeller" in H)?H.labeller:(("createLabeller" in G.getUnit())?G.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
+this._theme=H.theme;
+this._zoomIndex=("zoomIndex" in H)?H.zoomIndex:0;
+this._zoomSteps=("zoomSteps" in H)?H.zoomSteps:null;
+this._dragging=false;
+this._changing=false;
+this._originalScrollSpeed=5;
+this._scrollSpeed=this._originalScrollSpeed;
+this._onScrollListeners=[];
+this._orthogonalDragging=false;
+this._viewOrthogonalOffset=0;
+this._onOrthogonalScrollListeners=[];
+var A=this;
+this._syncWithBand=null;
+this._syncWithBandHandler=function(I){A._onHighlightBandScroll();
+};
+this._syncWithBandOrthogonalScrollHandler=function(I){A._onHighlightBandOrthogonalScroll();
+};
+this._selectorListener=function(I){A._onHighlightBandScroll();
+};
+var E=this._timeline.getDocument().createElement("div");
+E.className="timeline-band-input";
+this._timeline.addDiv(E);
+this._keyboardInput=document.createElement("input");
+this._keyboardInput.type="text";
+E.appendChild(this._keyboardInput);
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
+SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
+this._div=this._timeline.getDocument().createElement("div");
+this._div.id="timeline-band-"+C;
+this._div.className="timeline-band timeline-band-"+C;
+this._timeline.addDiv(this._div);
+SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
+SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
+SimileAjax.DOM.registerEventWithObject(document.body,"mousemove",this,"_onMouseMove");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseup",this,"_onMouseUp");
+SimileAjax.DOM.registerEventWithObject(document.body,"mouseout",this,"_onMouseOut");
+var F=this._theme!=null?this._theme.mouseWheel:"scroll";
+if(F==="zoom"||F==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
+}else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
+}}this._innerDiv=this._timeline.getDocument().createElement("div");
+this._innerDiv.className="timeline-band-inner";
+this._div.appendChild(this._innerDiv);
+this._ether=H.ether;
+H.ether.initialize(this,G);
+this._etherPainter=H.etherPainter;
+H.etherPainter.initialize(this,G);
+this._eventSource=H.eventSource;
+if(this._eventSource){this._eventListener={onAddMany:function(){A._onAddMany();
+},onClear:function(){A._onClear();
+}};
+this._eventSource.addListener(this._eventListener);
+}this._eventPainter=H.eventPainter;
+this._eventTracksNeeded=0;
+this._eventTrackIncrement=0;
+H.eventPainter.initialize(this,G);
+this._decorators=("decorators" in H)?H.decorators:[];
+for(var D=0;
+D<this._decorators.length;
+D++){this._decorators[D].initialize(this,G);
+}this._supportsOrthogonalScrolling=("supportsOrthogonalScrolling" in this._eventPainter)&&this._eventPainter.supportsOrthogonalScrolling();
+if(this._supportsOrthogonalScrolling){this._scrollBar=this._timeline.getDocument().createElement("div");
+this._scrollBar.id="timeline-band-scrollbar-"+C;
+this._scrollBar.className="timeline-band-scrollbar";
+this._timeline.addDiv(this._scrollBar);
+this._scrollBar.innerHTML='<div class="timeline-band-scrollbar-thumb"> </div>';
+var B=this._scrollBar.firstChild;
+if(SimileAjax.Platform.browser.isIE){B.style.cursor="move";
+}else{B.style.cursor="-moz-grab";
+}SimileAjax.DOM.registerEventWithObject(B,"mousedown",this,"_onScrollBarMouseDown");
+}};
+Timeline._Band.SCROLL_MULTIPLES=5;
+Timeline._Band.prototype.dispose=function(){this.closeBubble();
+if(this._eventSource){this._eventSource.removeListener(this._eventListener);
+this._eventListener=null;
+this._eventSource=null;
+}this._timeline=null;
+this._bandInfo=null;
+this._labeller=null;
+this._ether=null;
+this._etherPainter=null;
+this._eventPainter=null;
+this._decorators=null;
+this._onScrollListeners=null;
+this._syncWithBandHandler=null;
+this._syncWithBandOrthogonalScrollHandler=null;
+this._selectorListener=null;
+this._div=null;
+this._innerDiv=null;
+this._keyboardInput=null;
+this._scrollBar=null;
+};
+Timeline._Band.prototype.addOnScrollListener=function(A){this._onScrollListeners.push(A);
+};
+Timeline._Band.prototype.removeOnScrollListener=function(B){for(var A=0;
+A<this._onScrollListeners.length;
+A++){if(this._onScrollListeners[A]==B){this._onScrollListeners.splice(A,1);
+break;
+}}};
+Timeline._Band.prototype.addOnOrthogonalScrollListener=function(A){this._onOrthogonalScrollListeners.push(A);
+};
+Timeline._Band.prototype.removeOnOrthogonalScrollListener=function(B){for(var A=0;
+A<this._onOrthogonalScrollListeners.length;
+A++){if(this._onOrthogonalScrollListeners[A]==B){this._onOrthogonalScrollListeners.splice(A,1);
+break;
+}}};
+Timeline._Band.prototype.setSyncWithBand=function(B,A){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.removeOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+}this._syncWithBand=B;
+this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+this._syncWithBand.addOnOrthogonalScrollListener(this._syncWithBandOrthogonalScrollHandler);
+this._highlight=A;
+this._positionHighlight();
+};
+Timeline._Band.prototype.getLocale=function(){return this._locale;
+};
+Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
+};
+Timeline._Band.prototype.getLabeller=function(){return this._labeller;
+};
+Timeline._Band.prototype.getIndex=function(){return this._index;
+};
+Timeline._Band.prototype.getEther=function(){return this._ether;
+};
+Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
+};
+Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
+};
+Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
+};
+Timeline._Band.prototype.getTimeline=function(){return this._timeline;
+};
+Timeline._Band.prototype.updateEventTrackInfo=function(B,A){this._eventTrackIncrement=A;
+if(B>this._eventTracksNeeded){this._eventTracksNeeded=B;
+}};
+Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
+}var A=this._eventPainter.getType()=="overview";
+var C=A?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
+var B=Math.ceil((this._eventTracksNeeded+C)*this._eventTrackIncrement);
+B+=A?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
+var D=this._bandInfo;
+if(B!=D.width){D.width=B;
+}};
+Timeline._Band.prototype.layout=function(){this.paint();
+};
+Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
+this._paintDecorators();
+this._paintEvents();
+};
+Timeline._Band.prototype.softLayout=function(){this.softPaint();
+};
+Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
+this._softPaintDecorators();
+this._softPaintEvents();
+};
+Timeline._Band.prototype.setBandShiftAndWidth=function(A,D){var C=this._keyboardInput.parentNode;
+var B=A+Math.floor(D/2);
+if(this._timeline.isHorizontal()){this._div.style.top=A+"px";
+this._div.style.height=D+"px";
+C.style.top=B+"px";
+C.style.left="-1em";
+}else{this._div.style.left=A+"px";
+this._div.style.width=D+"px";
+C.style.left=B+"px";
+C.style.top="-1em";
+}};
+Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
+}else{return this._div.offsetWidth;
+}};
+Timeline._Band.prototype.setViewLength=function(A){this._viewLength=A;
+this._recenterDiv();
+this._onChanging();
+};
+Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
+};
+Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
+};
+Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
+};
+Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
+};
+Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
+};
+Timeline._Band.prototype.getMinVisibleDateAfterDelta=function(A){return this._ether.pixelOffsetToDate(A);
+};
+Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
+};
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta=function(A){return this._ether.pixelOffsetToDate(this._viewLength+A);
+};
+Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
+};
+Timeline._Band.prototype.setMinVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(A)));
+}};
+Timeline._Band.prototype.setMaxVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(A)));
+}};
+Timeline._Band.prototype.setCenterVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(A)));
+}};
+Timeline._Band.prototype.dateToPixelOffset=function(A){return this._ether.dateToPixelOffset(A)-this._viewOffset;
+};
+Timeline._Band.prototype.pixelOffsetToDate=function(A){return this._ether.pixelOffsetToDate(A+this._viewOffset);
+};
+Timeline._Band.prototype.getViewOrthogonalOffset=function(){return this._viewOrthogonalOffset;
+};
+Timeline._Band.prototype.setViewOrthogonalOffset=function(A){this._viewOrthogonalOffset=Math.max(0,A);
+};
+Timeline._Band.prototype.createLayerDiv=function(D,B){var C=this._timeline.getDocument().createElement("div");
+C.className="timeline-band-layer"+(typeof B=="string"?(" "+B):"");
+C.style.zIndex=D;
+this._innerDiv.appendChild(C);
+var A=this._timeline.getDocument().createElement("div");
+A.className="timeline-band-layer-inner";
+if(SimileAjax.Platform.browser.isIE){A.style.cursor="move";
+}else{A.style.cursor="-moz-grab";
+}C.appendChild(A);
+return A;
+};
+Timeline._Band.prototype.removeLayerDiv=function(A){this._innerDiv.removeChild(A.parentNode);
+};
+Timeline._Band.prototype.scrollToCenter=function(B,C){var A=this._ether.dateToPixelOffset(B);
+if(A<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A+this._viewLength));
+}else{if(A>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A-this._viewLength));
+}}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(B)),C);
+};
+Timeline._Band.prototype.showBubbleForEvent=function(C){var A=this.getEventSource().getEvent(C);
+if(A){var B=this;
+this.scrollToCenter(A.getStart(),function(){B._eventPainter.showBubble(A);
+});
+}};
+Timeline._Band.prototype.zoom=function(F,A,E,C){if(!this._zoomSteps){return ;
+}A+=this._viewOffset;
+var D=this._ether.pixelOffsetToDate(A);
+var B=this._ether.zoom(F);
+this._etherPainter.zoom(B);
+this._moveEther(Math.round(-this._ether.dateToPixelOffset(D)));
+this._moveEther(A);
+};
+Timeline._Band.prototype._onMouseDown=function(B,A,C){if(!this._dragging){this.closeBubble();
+this._dragging=true;
+this._dragX=A.clientX;
+this._dragY=A.clientY;
+return this._cancelEvent(A);
+}};
+Timeline._Band.prototype._onMouseMove=function(E,A,G){if(this._dragging||this._orthogonalDragging){var D=A.clientX-this._dragX;
+var B=A.clientY-this._dragY;
+this._dragX=A.clientX;
+this._dragY=A.clientY;
+}if(this._dragging){if(this._timeline.isHorizontal()){this._moveEther(D,B);
+}else{this._moveEther(B,D);
+}}else{if(this._orthogonalDragging){var F=this.getViewWidth();
+var C=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._moveEther(0,-B*F/C.offsetHeight);
+}else{this._moveEther(0,-D*F/C.offsetWidth);
+}}else{return ;
+}}this._positionHighlight();
+this._showScrollbar();
+return this._cancelEvent(A);
+};
+Timeline._Band.prototype._onMouseUp=function(B,A,C){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._keyboardInput.focus();
+this._bounceBack();
+return this._cancelEvent(A);
+};
+Timeline._Band.prototype._onMouseOut=function(B,A,C){if(C==document.body){if(this._dragging){this._dragging=false;
+}else{if(this._orthogonalDragging){this._orthogonalDragging=false;
+}else{return ;
+}}this._bounceBack();
+return this._cancelEvent(A);
+}};
+Timeline._Band.prototype._onScrollBarMouseDown=function(B,A,C){if(!this._orthogonalDragging){this.closeBubble();
+this._orthogonalDragging=true;
+this._dragX=A.clientX;
+this._dragY=A.clientY;
+return this._cancelEvent(A);
+}};
+Timeline._Band.prototype._onMouseScroll=function(G,I,E){var A=new Date();
+A=A.getTime();
+if(!this._lastScrollTime||((A-this._lastScrollTime)>50)){this._lastScrollTime=A;
+var H=0;
+if(I.wheelDelta){H=I.wheelDelta/120;
+}else{if(I.detail){H=-I.detail/3;
+}}var F=this._theme.mouseWheel;
+if(this._zoomSteps||F==="zoom"){var D=SimileAjax.DOM.getEventRelativeCoordinates(I,G);
+if(H!=0){var C;
+if(H>0){C=true;
+}if(H<0){C=false;
+}this._timeline.zoom(C,D.x,D.y,G);
+}}else{if(F==="scroll"){var B=50*(H<0?-1:1);
+this._moveEther(B);
+}}}if(I.stopPropagation){I.stopPropagation();
+}I.cancelBubble=true;
+if(I.preventDefault){I.preventDefault();
+}I.returnValue=false;
+};
+Timeline._Band.prototype._onDblClick=function(B,A,D){var C=SimileAjax.DOM.getEventRelativeCoordinates(A,B);
+var E=C.x-(this._viewLength/2-this._viewOffset);
+this._autoScroll(-E);
+};
+Timeline._Band.prototype._onKeyDown=function(B,A,C){if(!this._dragging){switch(A.keyCode){case 27:break;
+case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
+this._moveEther(this._scrollSpeed);
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(A);
+return false;
+}return true;
+};
+Timeline._Band.prototype._onKeyUp=function(B,A,C){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
+switch(A.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
+break;
+case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+break;
+case 33:this._autoScroll(this._timeline.getPixelLength());
+break;
+case 34:this._autoScroll(-this._timeline.getPixelLength());
+break;
+default:return true;
+}this.closeBubble();
+SimileAjax.DOM.cancelEvent(A);
+return false;
+}return true;
+};
+Timeline._Band.prototype._autoScroll=function(D,C){var A=this;
+var B=SimileAjax.Graphics.createAnimation(function(E,F){A._moveEther(F);
+},0,D,1000,C);
+B.run();
+};
+Timeline._Band.prototype._moveEther=function(A,B){if(B===undefined){B=0;
+}this.closeBubble();
+if(!this._timeline.shiftOK(this._index,A)){return ;
+}this._viewOffset+=A;
+this._ether.shiftPixels(-A);
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+}if(this._supportsOrthogonalScrolling){if(this._eventPainter.getOrthogonalExtent()<=this.getViewWidth()){this._viewOrthogonalOffset=0;
+}else{this._viewOrthogonalOffset=this._viewOrthogonalOffset+B;
+}}if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
+}else{this.softLayout();
+}this._onChanging();
+};
+Timeline._Band.prototype._onChanging=function(){this._changing=true;
+this._fireOnScroll();
+this._setSyncWithBandDate();
+this._changing=false;
+};
+Timeline._Band.prototype.busy=function(){return(this._changing);
+};
+Timeline._Band.prototype._fireOnScroll=function(){for(var A=0;
+A<this._onScrollListeners.length;
+A++){this._onScrollListeners[A](this);
+}};
+Timeline._Band.prototype._fireOnOrthogonalScroll=function(){for(var A=0;
+A<this._onOrthogonalScrollListeners.length;
+A++){this._onOrthogonalScrollListeners[A](this);
+}};
+Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var A=this._ether.pixelOffsetToDate(this.getViewLength()/2);
+this._syncWithBand.setCenterVisibleDate(A);
+}};
+Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var A=this._syncWithBand.getCenterVisibleDate();
+var B=this._ether.dateToPixelOffset(A);
+this._moveEther(Math.round(this._viewLength/2-B));
+this._positionHighlight();
+}};
+Timeline._Band.prototype._onHighlightBandOrthogonalScroll=function(){if(this._syncWithBand){this._positionHighlight();
+}};
+Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
+};
+Timeline._Band.prototype._onClear=function(){this._paintEvents();
+};
+Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var C=this._syncWithBand.getMinVisibleDate();
+var G=this._syncWithBand.getMaxVisibleDate();
+if(this._highlight){var H=0;
+var F=1;
+var B=this._syncWithBand.getEventPainter();
+if("supportsOrthogonalScrolling" in B&&B.supportsOrthogonalScrolling()){var E=B.getOrthogonalExtent();
+var D=this._syncWithBand.getViewWidth();
+var A=Math.max(D,E);
+F=D/A;
+H=-this._syncWithBand.getViewOrthogonalOffset()/A;
+}this._etherPainter.setHighlight(C,G,H,F);
+}}};
+Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
+if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
+this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}else{this._div.style.top=this._viewOffset+"px";
+this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
+}this.layout();
+};
+Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
+this._showScrollbar();
+this._fireOnOrthogonalScroll();
+};
+Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
+};
+Timeline._Band.prototype._paintDecorators=function(){for(var A=0;
+A<this._decorators.length;
+A++){this._decorators[A].paint();
+}};
+Timeline._Band.prototype._softPaintDecorators=function(){for(var A=0;
+A<this._decorators.length;
+A++){this._decorators[A].softPaint();
+}};
+Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
+};
+Timeline._Band.prototype._bounceBack=function(C){if(!this._supportsOrthogonalScrolling){return ;
+}var D=0;
+if(this._viewOrthogonalOffset<0){var B=this._eventPainter.getOrthogonalExtent();
+if(this._viewOrthogonalOffset+B>=this.getViewWidth()){D=this._viewOrthogonalOffset;
+}else{D=Math.min(0,this.getViewWidth()-B);
+}}if(D!=this._viewOrthogonalOffset){var A=this;
+SimileAjax.Graphics.createAnimation(function(E,F){A._viewOrthogonalOffset=E;
+A._eventPainter.softPaint();
+A._showScrollbar();
+A._fireOnOrthogonalScroll();
+},this._viewOrthogonalOffset,D,300,function(){A._hideScrollbar();
+}).run();
+}else{this._hideScrollbar();
+}};
+Timeline._Band.prototype._showScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}var E=this._eventPainter.getOrthogonalExtent();
+var D=this.getViewWidth();
+var B=Math.max(D,E);
+var G=(D/B);
+var F=Math.round(D*G)+"px";
+var H=Math.round(-this._viewOrthogonalOffset*G)+"px";
+var A=12;
+var C=this._scrollBar.firstChild;
+if(this._timeline.isHorizontal()){this._scrollBar.style.top=this._div.style.top;
+this._scrollBar.style.height=this._div.style.height;
+this._scrollBar.style.right="0px";
+this._scrollBar.style.width=A+"px";
+C.style.top=H;
+C.style.height=F;
+}else{this._scrollBar.style.left=this._div.style.left;
+this._scrollBar.style.width=this._div.style.width;
+this._scrollBar.style.bottom="0px";
+this._scrollBar.style.height=A+"px";
+C.style.left=H;
+C.style.width=F;
+}if(G>=1&&this._viewOrthogonalOffset==0){this._scrollBar.style.display="none";
+}else{this._scrollBar.style.display="block";
+}};
+Timeline._Band.prototype._hideScrollbar=function(){if(!this._supportsOrthogonalScrolling){return ;
+}};
+Timeline._Band.prototype._cancelEvent=function(A){SimileAjax.DOM.cancelEvent(A);
+return false;
+};
+
+
+/* compact-painter.js */
+Timeline.CompactEventPainter=function(A){this._params=A;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.CompactEventPainter.prototype.getType=function(){return"compact";
+};
+Timeline.CompactEventPainter.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.CompactEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.CompactEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
+};
+Timeline.CompactEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
+break;
+}}};
+Timeline.CompactEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.CompactEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
+};
+Timeline.CompactEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.CompactEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
+};
+Timeline.CompactEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
+if(B==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var L=this._computeMetrics();
+var E=this._band.getMinDate();
+var A=this._band.getMaxDate();
+var O=(this._filterMatcher!=null)?this._filterMatcher:function(Q){return true;
+};
+var K=(this._highlightMatcher!=null)?this._highlightMatcher:function(Q){return -1;
+};
+var H=B.getEventIterator(E,A);
+var M="stackConcurrentPreciseInstantEvents" in this._params&&typeof this._params.stackConcurrentPreciseInstantEvents=="object";
+var J="collapseConcurrentPreciseInstantEvents" in this._params&&this._params.collapseConcurrentPreciseInstantEvents;
+if(J||M){var P=[];
+var C=null;
+while(H.hasNext()){var N=H.next();
+if(O(N)){if(!N.isInstant()||N.isImprecise()){this.paintEvent(N,L,this._params.theme,K(N));
+}else{if(C!=null&&C.getStart().getTime()==N.getStart().getTime()){P[P.length-1].push(N);
+}else{P.push([N]);
+C=N;
+}}}}for(var F=0;
+F<P.length;
+F++){var I=P[F];
+if(I.length==1){this.paintEvent(I[0],L,this._params.theme,K(N));
+}else{var G=-1;
+for(var D=0;
+G<0&&D<I.length;
+D++){G=K(I[D]);
+}if(M){this.paintStackedPreciseInstantEvents(I,L,this._params.theme,G);
+}else{this.paintCompositePreciseInstantEvents(I,L,this._params.theme,G);
+}}}}else{while(H.hasNext()){var N=H.next();
+if(O(N)){this.paintEvent(N,L,this._params.theme,K(N));
+}}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._setOrthogonalOffset(L);
+};
+Timeline.CompactEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.CompactEventPainter.prototype.getOrthogonalExtent=function(){var A=this._computeMetrics();
+return 2*A.trackOffset+this._tracks.length*A.trackHeight;
+};
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset=function(A){var B=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=B+"px";
+};
+Timeline.CompactEventPainter.prototype._computeMetrics=function(){var B=this._params.theme;
+var C=B.event;
+var A={trackOffset:"trackOffset" in this._params?this._params.trackOffset:10,trackHeight:"trackHeight" in this._params?this._params.trackHeight:10,tapeHeight:B.event.tape.height,tapeBottomMargin:"tapeBottomMargin" in this._params?this._params.tapeBottomMargin:2,labelBottomMargin:"labelBottomMargin" in this._params?this._params.labelBottomMargin:5,labelRightMargin:"labelRightMargin" in this._params?this._params.labelRightMargin:5,defaultIcon:C.instant.icon,defaultIconWidth:C.instant.iconWidth,defaultIconHeight:C.instant.iconHeight,customIconWidth:"iconWidth" in this._params?this._params.iconWidth:C.instant.iconWidth,customIconHeight:"iconHeight" in this._params?this._params.iconHeight:C.instant.iconHeight,iconLabelGap:"iconLabelGap" in this._params?this._params.iconLabelGap:2,iconBottomMargin:"iconBottomMargin" in this._params?this._params.iconBottomMargin:2};
+if("compositeIcon" in this._params){A.compositeIcon=this._params.compositeIcon;
+A.compositeIconWidth=this._params.compositeIconWidth||A.customIconWidth;
+A.compositeIconHeight=this._params.compositeIconHeight||A.customIconHeight;
+}else{A.compositeIcon=A.defaultIcon;
+A.compositeIconWidth=A.defaultIconWidth;
+A.compositeIconHeight=A.defaultIconHeight;
+}A.defaultStackIcon=("stackConcurrentPreciseInstantEvents" in this._params&&"icon" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.icon:A.defaultIcon;
+A.defaultStackIconWidth=("stackConcurrentPreciseInstantEvents" in this._params&&"iconWidth" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconWidth:A.defaultIconWidth;
+A.defaultStackIconHeight=("stackConcurrentPreciseInstantEvents" in this._params&&"iconHeight" in this._params.stackConcurrentPreciseInstantEvents)?this._params.stackConcurrentPreciseInstantEvents.iconHeight:A.defaultIconHeight;
+return A;
+};
+Timeline.CompactEventPainter.prototype._prepareForPainting=function(){var B=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var A=document.createElement("span");
+A.className="timeline-event-label";
+this._backLayer.appendChild(A);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
+}this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
+}this._eventLayer=B.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.CompactEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
+}else{this.paintDurationEvent(B,C,D,A);
+}};
+Timeline.CompactEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
+}else{this.paintPreciseInstantEvent(B,C,D,A);
+}};
+Timeline.CompactEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
+}else{this.paintPreciseDurationEvent(B,C,D,A);
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent=function(H,F,C,B){var D={tooltip:H.getProperty("tooltip")||H.getText()};
+var A={url:H.getIcon()};
+if(A.url==null){A.url=F.defaultIcon;
+A.width=F.defaultIconWidth;
+A.height=F.defaultIconHeight;
+A.className="timeline-event-icon-default";
+}else{A.width=H.getProperty("iconWidth")||F.customIconWidth;
+A.height=H.getProperty("iconHeight")||F.customIconHeight;
+}var G={text:H.getText(),color:H.getTextColor()||H.getColor(),className:H.getClassName()};
+var J=this.paintTapeIconLabel(H.getStart(),D,null,A,G,F,C,B);
+var I=this;
+var E=function(K,L,M){return I._onClickInstantEvent(J.iconElmtData.elmt,L,H);
+};
+SimileAjax.DOM.registerEvent(J.iconElmtData.elmt,"mousedown",E);
+SimileAjax.DOM.registerEvent(J.labelElmtData.elmt,"mousedown",E);
+this._eventIdToElmt[H.getID()]=J.iconElmtData.elmt;
+};
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents=function(L,H,C,B){var J=L[0];
+var G=[];
+for(var D=0;
+D<L.length;
+D++){G.push(L[D].getProperty("tooltip")||L[D].getText());
+}var E={tooltip:G.join("; ")};
+var A={url:H.compositeIcon,width:H.compositeIconWidth,height:H.compositeIconHeight,className:"timeline-event-icon-composite"};
+var I={text:String.substitute(this._params.compositeEventLabelTemplate,[L.length])};
+var M=this.paintTapeIconLabel(J.getStart(),E,null,A,I,H,C,B);
+var K=this;
+var F=function(N,O,P){return K._onClickMultiplePreciseInstantEvent(M.iconElmtData.elmt,O,L);
+};
+SimileAjax.DOM.registerEvent(M.iconElmtData.elmt,"mousedown",F);
+SimileAjax.DOM.registerEvent(M.labelElmtData.elmt,"mousedown",F);
+for(var D=0;
+D<L.length;
+D++){this._eventIdToElmt[L[D].getID()]=M.iconElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents=function(X,k,b,E){var S="limit" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.limit:10;
+var I="moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents?this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate:"%0 More Events";
+var P=S<=X.length-2;
+var C=this._band;
+var e=function(i){return Math.round(C.dateToPixelOffset(i));
+};
+var N=function(i){var r={url:i.getIcon()};
+if(r.url==null){r.url=k.defaultStackIcon;
+r.width=k.defaultStackIconWidth;
+r.height=k.defaultStackIconHeight;
+r.className="timeline-event-icon-stack timeline-event-icon-default";
+}else{r.width=i.getProperty("iconWidth")||k.customIconWidth;
+r.height=i.getProperty("iconHeight")||k.customIconHeight;
+r.className="timeline-event-icon-stack";
+}return r;
+};
+var G=N(X[0]);
+var V=5;
+var F=0;
+var K=0;
+var q=0;
+var W=0;
+var m=[];
+for(var p=0;
+p<X.length&&(!P||p<S);
+p++){var a=X[p];
+var Z=a.getText();
+var U=N(a);
+var T=this._frc.computeSize(Z);
+var g={text:Z,iconData:U,labelSize:T,iconLeft:G.width+p*V-U.width};
+g.labelLeft=G.width+p*V+k.iconLabelGap;
+g.top=q;
+m.push(g);
+F=Math.min(F,g.iconLeft);
+q+=T.height;
+K=Math.max(K,g.labelLeft+T.width);
+W=Math.max(W,g.top+U.height);
+}if(P){var L=String.substitute(I,[X.length-S]);
+var l=this._frc.computeSize(L);
+var h=G.width+(S-1)*V+k.iconLabelGap;
+var o=q;
+q+=l.height;
+K=Math.max(K,h+l.width);
+}K+=k.labelRightMargin;
+q+=k.labelBottomMargin;
+W+=k.iconBottomMargin;
+var n=e(X[0].getStart());
+var R=[];
+var M=Math.ceil(Math.max(W,q)/k.trackHeight);
+var d=G.width+(X.length-1)*V;
+for(var p=0;
+p<M;
+p++){R.push({start:F,end:d});
+}var f=Math.ceil(q/k.trackHeight);
+for(var p=0;
+p<f;
+p++){var O=R[p];
+O.end=Math.max(O.end,K);
+}var H=this._fitTracks(n,R);
+var Y=H*k.trackHeight+k.trackOffset;
+var A=this._timeline.getDocument().createElement("div");
+A.className="timeline-event-icon-stack";
+A.style.position="absolute";
+A.style.overflow="visible";
+A.style.left=n+"px";
+A.style.top=Y+"px";
+A.style.width=d+"px";
+A.style.height=W+"px";
+A.innerHTML="<div style='position: relative'></div>";
+this._eventLayer.appendChild(A);
+var J=this;
+var Q=function(s){try{var w=parseInt(this.getAttribute("index"));
+var u=A.firstChild.childNodes;
+for(var r=0;
+r<u.length;
+r++){var v=u[r];
+if(r==w){v.style.zIndex=u.length;
+}else{v.style.zIndex=u.length-r;
+}}}catch(t){}};
+var c=function(v){var r=m[v];
+var i=X[v];
+var w=i.getProperty("tooltip")||i.getText();
+var u=J._paintEventLabel({tooltip:w},{text:r.text},n+r.labelLeft,Y+r.top,r.labelSize.width,r.labelSize.height,b);
+u.elmt.setAttribute("index",v);
+u.elmt.onmouseover=Q;
+var t=SimileAjax.Graphics.createTranslucentImage(r.iconData.url);
+var s=J._timeline.getDocument().createElement("div");
+s.className="timeline-event-icon"+("className" in r.iconData?(" "+r.iconData.className):"");
+s.style.left=r.iconLeft+"px";
+s.style.top=r.top+"px";
+s.style.zIndex=(m.length-v);
+s.appendChild(t);
+s.setAttribute("index",v);
+s.onmouseover=Q;
+A.firstChild.appendChild(s);
+var x=function(y,z,AA){return J._onClickInstantEvent(u.elmt,z,i);
+};
+SimileAjax.DOM.registerEvent(s,"mousedown",x);
+SimileAjax.DOM.registerEvent(u.elmt,"mousedown",x);
+J._eventIdToElmt[i.getID()]=s;
+};
+for(var p=0;
+p<m.length;
+p++){c(p);
+}if(P){var D=X.slice(S);
+var B=this._paintEventLabel({tooltip:L},{text:L},n+h,Y+o,l.width,l.height,b);
+var j=function(i,r,s){return J._onClickMultiplePreciseInstantEvent(B.elmt,r,D);
+};
+SimileAjax.DOM.registerEvent(B.elmt,"mousedown",j);
+for(var p=0;
+p<D.length;
+p++){this._eventIdToElmt[D[p].getID()]=B.elmt;
+}}};
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent=function(I,G,D,C){var E={tooltip:I.getProperty("tooltip")||I.getText()};
+var A={start:I.getStart(),end:I.getEnd(),latestStart:I.getLatestStart(),earliestEnd:I.getEarliestEnd(),color:I.getColor()||I.getTextColor(),isInstant:true};
+var B={url:I.getIcon()};
+if(B.url==null){B=null;
+}else{B.width=I.getProperty("iconWidth")||G.customIconWidth;
+B.height=I.getProperty("iconHeight")||G.customIconHeight;
+}var H={text:I.getText(),color:I.getTextColor()||I.getColor(),className:I.getClassName()};
+var K=this.paintTapeIconLabel(I.getStart(),E,A,B,H,G,D,C);
+var J=this;
+var F=B!=null?function(L,M,N){return J._onClickInstantEvent(K.iconElmtData.elmt,M,I);
+}:function(L,M,N){return J._onClickInstantEvent(K.labelElmtData.elmt,M,I);
+};
+SimileAjax.DOM.registerEvent(K.labelElmtData.elmt,"mousedown",F);
+SimileAjax.DOM.registerEvent(K.impreciseTapeElmtData.elmt,"mousedown",F);
+if(B!=null){SimileAjax.DOM.registerEvent(K.iconElmtData.elmt,"mousedown",F);
+this._eventIdToElmt[I.getID()]=K.iconElmtData.elmt;
+}else{this._eventIdToElmt[I.getID()]=K.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent=function(I,G,D,C){var E={tooltip:I.getProperty("tooltip")||I.getText()};
+var A={start:I.getStart(),end:I.getEnd(),color:I.getColor()||I.getTextColor(),isInstant:false};
+var B={url:I.getIcon()};
+if(B.url==null){B=null;
+}else{B.width=I.getProperty("iconWidth")||G.customIconWidth;
+B.height=I.getProperty("iconHeight")||G.customIconHeight;
+}var H={text:I.getText(),color:I.getTextColor()||I.getColor(),className:I.getClassName()};
+var K=this.paintTapeIconLabel(I.getLatestStart(),E,A,B,H,G,D,C);
+var J=this;
+var F=B!=null?function(L,M,N){return J._onClickInstantEvent(K.iconElmtData.elmt,M,I);
+}:function(L,M,N){return J._onClickInstantEvent(K.labelElmtData.elmt,M,I);
+};
+SimileAjax.DOM.registerEvent(K.labelElmtData.elmt,"mousedown",F);
+SimileAjax.DOM.registerEvent(K.tapeElmtData.elmt,"mousedown",F);
+if(B!=null){SimileAjax.DOM.registerEvent(K.iconElmtData.elmt,"mousedown",F);
+this._eventIdToElmt[I.getID()]=K.iconElmtData.elmt;
+}else{this._eventIdToElmt[I.getID()]=K.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent=function(I,G,D,C){var E={tooltip:I.getProperty("tooltip")||I.getText()};
+var A={start:I.getStart(),end:I.getEnd(),latestStart:I.getLatestStart(),earliestEnd:I.getEarliestEnd(),color:I.getColor()||I.getTextColor(),isInstant:false};
+var B={url:I.getIcon()};
+if(B.url==null){B=null;
+}else{B.width=I.getProperty("iconWidth")||G.customIconWidth;
+B.height=I.getProperty("iconHeight")||G.customIconHeight;
+}var H={text:I.getText(),color:I.getTextColor()||I.getColor(),className:I.getClassName()};
+var K=this.paintTapeIconLabel(I.getLatestStart(),E,A,B,H,G,D,C);
+var J=this;
+var F=B!=null?function(L,M,N){return J._onClickInstantEvent(K.iconElmtData.elmt,M,I);
+}:function(L,M,N){return J._onClickInstantEvent(K.labelElmtData.elmt,M,I);
+};
+SimileAjax.DOM.registerEvent(K.labelElmtData.elmt,"mousedown",F);
+SimileAjax.DOM.registerEvent(K.tapeElmtData.elmt,"mousedown",F);
+if(B!=null){SimileAjax.DOM.registerEvent(K.iconElmtData.elmt,"mousedown",F);
+this._eventIdToElmt[I.getID()]=K.iconElmtData.elmt;
+}else{this._eventIdToElmt[I.getID()]=K.labelElmtData.elmt;
+}};
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel=function(a,M,d,E,X,V,c,Y){var R=this._band;
+var K=function(e){return Math.round(R.dateToPixelOffset(e));
+};
+var S=K(a);
+var b=[];
+var Z=0;
+var O=0;
+var N=0;
+if(d!=null){Z=V.tapeHeight+V.tapeBottomMargin;
+O=Math.ceil(V.tapeHeight/V.trackHeight);
+var A=K(d.end)-S;
+var D=K(d.start)-S;
+for(var Q=0;
+Q<O;
+Q++){b.push({start:D,end:A});
+}N=V.trackHeight-(Z%V.tapeHeight);
+}var B=0;
+var U=0;
+if(E!=null){if("iconAlign" in E&&E.iconAlign=="center"){B=-Math.floor(E.width/2);
+}U=B+E.width+V.iconLabelGap;
+if(O>0){b[O-1].end=Math.max(b[O-1].end,U);
+}var J=E.height+V.iconBottomMargin+N;
+while(J>0){b.push({start:B,end:U});
+J-=V.trackHeight;
+}}var P=X.text;
+var G=this._frc.computeSize(P);
+var C=G.height+V.labelBottomMargin+N;
+var F=U+G.width+V.labelRightMargin;
+if(O>0){b[O-1].end=Math.max(b[O-1].end,F);
+}for(var W=0;
+C>0;
+W++){if(O+W<b.length){var T=b[O+W];
+T.end=F;
+}else{b.push({start:0,end:F});
+}C-=V.trackHeight;
+}var I=this._fitTracks(S,b);
+var H=I*V.trackHeight+V.trackOffset;
+var L={};
+L.labelElmtData=this._paintEventLabel(M,X,S+U,H+Z,G.width,G.height,c);
+if(d!=null){if("latestStart" in d||"earliestEnd" in d){L.impreciseTapeElmtData=this._paintEventTape(M,d,V.tapeHeight,H,K(d.start),K(d.end),c.event.duration.impreciseColor,c.event.duration.impreciseOpacity,V,c);
+}if(!d.isInstant&&"start" in d&&"end" in d){L.tapeElmtData=this._paintEventTape(M,d,V.tapeHeight,H,S,K("earliestEnd" in d?d.earliestEnd:d.end),d.color,100,V,c);
+}}if(E!=null){L.iconElmtData=this._paintEventIcon(M,E,H+Z,S+B,V,c);
+}return L;
+};
+Timeline.CompactEventPainter.prototype._fitTracks=function(A,F){var H;
+for(H=0;
+H<this._tracks.length;
+H++){var E=true;
+for(var C=0;
+C<F.length&&(H+C)<this._tracks.length;
+C++){var G=this._tracks[H+C];
+var B=F[C];
+if(A+B.start<G){E=false;
+break;
+}}if(E){break;
+}}for(var D=0;
+D<F.length;
+D++){this._tracks[H+D]=A+F[D].end;
+}return H;
+};
+Timeline.CompactEventPainter.prototype._paintEventIcon=function(C,D,H,G,E,F){var B=SimileAjax.Graphics.createTranslucentImage(D.url);
+var A=this._timeline.getDocument().createElement("div");
+A.className="timeline-event-icon"+("className" in D?(" "+D.className):"");
+A.style.left=G+"px";
+A.style.top=H+"px";
+A.appendChild(B);
+if("tooltip" in C&&typeof C.tooltip=="string"){A.title=C.tooltip;
+}this._eventLayer.appendChild(A);
+return{left:G,top:H,width:E.iconWidth,height:E.iconHeight,elmt:A};
+};
+Timeline.CompactEventPainter.prototype._paintEventLabel=function(D,G,B,F,A,I,C){var H=this._timeline.getDocument();
+var E=H.createElement("div");
+E.className="timeline-event-label";
+E.style.left=B+"px";
+E.style.width=(A+1)+"px";
+E.style.top=F+"px";
+E.innerHTML=G.text;
+if("tooltip" in D&&typeof D.tooltip=="string"){E.title=D.tooltip;
+}if("color" in G&&typeof G.color=="string"){E.style.color=G.color;
+}if("className" in G&&typeof G.className=="string"){E.className+=" "+G.className;
+}this._eventLayer.appendChild(E);
+return{left:B,top:F,width:A,height:I,elmt:E};
+};
+Timeline.CompactEventPainter.prototype._paintEventTape=function(G,B,L,J,F,A,D,H,I,E){var C=A-F;
+var K=this._timeline.getDocument().createElement("div");
+K.className="timeline-event-tape";
+K.style.left=F+"px";
+K.style.top=J+"px";
+K.style.width=C+"px";
+K.style.height=L+"px";
+if("tooltip" in G&&typeof G.tooltip=="string"){K.title=G.tooltip;
+}if(D!=null&&typeof B.color=="string"){K.style.backgroundColor=D;
+}if("backgroundImage" in B&&typeof B.backgroundImage=="string"){K.style.backgroundImage="url("+backgroundImage+")";
+K.style.backgroundRepeat=("backgroundRepeat" in B&&typeof B.backgroundRepeat=="string")?B.backgroundRepeat:"repeat";
+}SimileAjax.Graphics.setOpacity(K,H);
+if("className" in B&&typeof B.className=="string"){K.className+=" "+B.className;
+}this._eventLayer.appendChild(K);
+return{left:F,top:J,width:C,height:L,elmt:K};
+};
+Timeline.CompactEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
+var G=E.event;
+var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
+var F=D.createElement("div");
+F.style.position="absolute";
+F.style.overflow="hidden";
+F.style.left=(C.left-2)+"px";
+F.style.width=(C.width+4)+"px";
+F.style.top=(C.top-2)+"px";
+F.style.height=(C.height+4)+"px";
+this._highlightLayer.appendChild(F);
+}};
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent=function(D,E,B){var F=SimileAjax.DOM.getPageCoordinates(D);
+this._showBubble(F.left+Math.ceil(D.offsetWidth/2),F.top+Math.ceil(D.offsetHeight/2),B);
+var C=[];
+for(var A=0;
+A<B.length;
+A++){C.push(B[A].getID());
+}this._fireOnSelect(C);
+E.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(E);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),[A]);
+this._fireOnSelect([A.getID()]);
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.CompactEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
+var F=C.pageY;
+}else{var E=SimileAjax.DOM.getPageCoordinates(D);
+var A=C.offsetX+E.left;
+var F=C.offsetY+E.top;
+}this._showBubble(A,F,[B]);
+this._fireOnSelect([B.getID()]);
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.CompactEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
+if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,[A]);
+}};
+Timeline.CompactEventPainter.prototype._showBubble=function(A,F,B){var E=document.createElement("div");
+B=("fillInfoBubble" in B)?[B]:B;
+for(var D=0;
+D<B.length;
+D++){var C=document.createElement("div");
+E.appendChild(C);
+B[D].fillInfoBubble(C,this._params.theme,this._band.getLabeller());
+}SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(E,A,F,this._params.theme.event.bubble.width);
+};
+Timeline.CompactEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){this._onSelectListeners[A](B);
+}};
+
+
+/* decorators.js */
+Timeline.SpanHighlightDecorator=function(A){this._unit=A.unit!=null?A.unit:SimileAjax.NativeDateUnit;
+this._startDate=(typeof A.startDate=="string")?this._unit.parseFromObject(A.startDate):A.startDate;
+this._endDate=(typeof A.endDate=="string")?this._unit.parseFromObject(A.endDate):A.endDate;
+this._startLabel=A.startLabel!=null?A.startLabel:"";
+this._endLabel=A.endLabel!=null?A.endLabel:"";
+this._color=A.color;
+this._cssClass=A.cssClass!=null?A.cssClass:null;
+this._opacity=A.opacity!=null?A.opacity:100;
+this._zIndex=(A.inFront!=null&&A.inFront)?113:10;
+};
+Timeline.SpanHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._layerDiv=null;
+};
+Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(this._zIndex);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var F=this._band.getMinDate();
+var C=this._band.getMaxDate();
+if(this._unit.compare(this._startDate,C)<0&&this._unit.compare(this._endDate,F)>0){F=this._unit.later(F,this._startDate);
+C=this._unit.earlier(C,this._endDate);
+var D=this._band.dateToPixelOffset(F);
+var K=this._band.dateToPixelOffset(C);
+var I=this._timeline.getDocument();
+var H=function(){var L=I.createElement("table");
+L.insertRow(0).insertCell(0);
+return L;
+};
+var B=I.createElement("div");
+B.className="timeline-highlight-decorator";
+if(this._cssClass){B.className+=" "+this._cssClass;
+}if(this._color!=null){B.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(B,this._opacity);
+}this._layerDiv.appendChild(B);
+var J=H();
+J.className="timeline-highlight-label timeline-highlight-label-start";
+var G=J.rows[0].cells[0];
+G.innerHTML=this._startLabel;
+if(this._cssClass){G.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(J);
+var A=H();
+A.className="timeline-highlight-label timeline-highlight-label-end";
+var E=A.rows[0].cells[0];
+E.innerHTML=this._endLabel;
+if(this._cssClass){E.className="label_"+this._cssClass;
+}this._layerDiv.appendChild(A);
+if(this._timeline.isHorizontal()){B.style.left=D+"px";
+B.style.width=(K-D)+"px";
+J.style.right=(this._band.getTotalViewLength()-D)+"px";
+J.style.width=(this._startLabel.length)+"em";
+A.style.left=K+"px";
+A.style.width=(this._endLabel.length)+"em";
+}else{B.style.top=D+"px";
+B.style.height=(K-D)+"px";
+J.style.bottom=D+"px";
+J.style.height="1.5px";
+A.style.top=K+"px";
+A.style.height="1.5px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
+Timeline.PointHighlightDecorator=function(A){this._unit=A.unit!=null?A.unit:SimileAjax.NativeDateUnit;
+this._date=(typeof A.date=="string")?this._unit.parseFromObject(A.date):A.date;
+this._width=A.width!=null?A.width:10;
+this._color=A.color;
+this._cssClass=A.cssClass!=null?A.cssClass:"";
+this._opacity=A.opacity!=null?A.opacity:100;
+};
+Timeline.PointHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._layerDiv=null;
+};
+Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
+}this._layerDiv=this._band.createLayerDiv(10);
+this._layerDiv.setAttribute("name","span-highlight-decorator");
+this._layerDiv.style.display="none";
+var C=this._band.getMinDate();
+var E=this._band.getMaxDate();
+if(this._unit.compare(this._date,E)<0&&this._unit.compare(this._date,C)>0){var B=this._band.dateToPixelOffset(this._date);
+var A=B-Math.round(this._width/2);
+var D=this._timeline.getDocument();
+var F=D.createElement("div");
+F.className="timeline-highlight-point-decorator";
+F.className+=" "+this._cssClass;
+if(this._color!=null){F.style.backgroundColor=this._color;
+}if(this._opacity<100){SimileAjax.Graphics.setOpacity(F,this._opacity);
+}this._layerDiv.appendChild(F);
+if(this._timeline.isHorizontal()){F.style.left=A+"px";
+F.style.width=this._width+"px";
+}else{F.style.top=A+"px";
+F.style.height=this._width+"px";
+}}this._layerDiv.style.display="block";
+};
+Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
+
+
+/* detailed-painter.js */
+Timeline.DetailedEventPainter=function(A){this._params=A;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.DetailedEventPainter.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
+};
+Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
+};
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
+break;
+}}};
+Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
+};
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
+};
+Timeline.DetailedEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
+if(B==null){return ;
+}this._eventIdToElmt={};
+this._prepareForPainting();
+var I=this._params.theme.event;
+var G=Math.max(I.track.height,this._frc.getLineHeight());
+var F={trackOffset:Math.round(this._band.getViewWidth()/2-G/2),trackHeight:G,trackGap:I.track.gap,trackIncrement:G+I.track.gap,icon:I.instant.icon,iconWidth:I.instant.iconWidth,iconHeight:I.instant.iconHeight,labelWidth:I.label.width};
+var C=this._band.getMinDate();
+var A=this._band.getMaxDate();
+var J=(this._filterMatcher!=null)?this._filterMatcher:function(K){return true;
+};
+var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(K){return -1;
+};
+var D=B.getEventReverseIterator(C,A);
+while(D.hasNext()){var H=D.next();
+if(J(H)){this.paintEvent(H,F,this._params.theme,E(H));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,F.trackIncrement);
+};
+Timeline.DetailedEventPainter.prototype.softPaint=function(){};
+Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var B=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var A=document.createElement("span");
+A.className="timeline-event-label";
+this._backLayer.appendChild(A);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
+}this._frc.update();
+this._lowerTracks=[];
+this._upperTracks=[];
+if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
+}this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
+}this._eventLayer=B.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.DetailedEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
+}else{this.paintDurationEvent(B,C,D,A);
+}};
+Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
+}else{this.paintPreciseInstantEvent(B,C,D,A);
+}};
+Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
+}else{this.paintPreciseDurationEvent(B,C,D,A);
+}};
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(K,N,Q,O){var S=this._timeline.getDocument();
+var J=K.getText();
+var E=K.getStart();
+var C=Math.round(this._band.dateToPixelOffset(E));
+var A=Math.round(C+N.iconWidth/2);
+var I=Math.round(C-N.iconWidth/2);
+var G=this._frc.computeSize(J);
+var D=this._findFreeTrackForSolid(A,C);
+var B=this._paintEventIcon(K,D,I,N,Q);
+var T=A+Q.event.label.offsetFromLine;
+var P=D;
+var F=this._getTrackData(D);
+if(Math.min(F.solid,F.text)>=T+G.width){F.solid=I;
+F.text=T;
+}else{F.solid=I;
+T=C+Q.event.label.offsetFromLine;
+P=this._findFreeTrackForText(D,T+G.width,function(U){U.line=C-2;
+});
+this._getTrackData(P).text=I;
+this._paintEventLine(K,C,D,P,N,Q);
+}var R=Math.round(N.trackOffset+P*N.trackIncrement+N.trackHeight/2-G.height/2);
+var M=this._paintEventLabel(K,J,T,R,G.width,G.height,Q);
+var L=this;
+var H=function(U,V,W){return L._onClickInstantEvent(B.elmt,V,K);
+};
+SimileAjax.DOM.registerEvent(B.elmt,"mousedown",H);
+SimileAjax.DOM.registerEvent(M.elmt,"mousedown",H);
+this._createHighlightDiv(O,B,Q);
+this._eventIdToElmt[K.getID()]=B.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(N,Q,V,R){var X=this._timeline.getDocument();
+var M=N.getText();
+var H=N.getStart();
+var S=N.getEnd();
+var E=Math.round(this._band.dateToPixelOffset(H));
+var B=Math.round(this._band.dateToPixelOffset(S));
+var A=Math.round(E+Q.iconWidth/2);
+var L=Math.round(E-Q.iconWidth/2);
+var J=this._frc.computeSize(M);
+var F=this._findFreeTrackForSolid(B,E);
+var G=this._paintEventTape(N,F,E,B,V.event.instant.impreciseColor,V.event.instant.impreciseOpacity,Q,V);
+var C=this._paintEventIcon(N,F,L,Q,V);
+var I=this._getTrackData(F);
+I.solid=L;
+var W=A+V.event.label.offsetFromLine;
+var D=W+J.width;
+var T;
+if(D<B){T=F;
+}else{W=E+V.event.label.offsetFromLine;
+D=W+J.width;
+T=this._findFreeTrackForText(F,D,function(Y){Y.line=E-2;
+});
+this._getTrackData(T).text=L;
+this._paintEventLine(N,E,F,T,Q,V);
+}var U=Math.round(Q.trackOffset+T*Q.trackIncrement+Q.trackHeight/2-J.height/2);
+var P=this._paintEventLabel(N,M,W,U,J.width,J.height,V);
+var O=this;
+var K=function(Y,Z,a){return O._onClickInstantEvent(C.elmt,Z,N);
+};
+SimileAjax.DOM.registerEvent(C.elmt,"mousedown",K);
+SimileAjax.DOM.registerEvent(G.elmt,"mousedown",K);
+SimileAjax.DOM.registerEvent(P.elmt,"mousedown",K);
+this._createHighlightDiv(R,C,V);
+this._eventIdToElmt[N.getID()]=C.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(J,M,S,O){var T=this._timeline.getDocument();
+var I=J.getText();
+var D=J.getStart();
+var P=J.getEnd();
+var B=Math.round(this._band.dateToPixelOffset(D));
+var A=Math.round(this._band.dateToPixelOffset(P));
+var F=this._frc.computeSize(I);
+var E=this._findFreeTrackForSolid(A);
+var N=J.getColor();
+N=N!=null?N:S.event.duration.color;
+var C=this._paintEventTape(J,E,B,A,N,100,M,S);
+var H=this._getTrackData(E);
+H.solid=B;
+var U=B+S.event.label.offsetFromLine;
+var Q=this._findFreeTrackForText(E,U+F.width,function(V){V.line=B-2;
+});
+this._getTrackData(Q).text=B-2;
+this._paintEventLine(J,B,E,Q,M,S);
+var R=Math.round(M.trackOffset+Q*M.trackIncrement+M.trackHeight/2-F.height/2);
+var L=this._paintEventLabel(J,I,U,R,F.width,F.height,S);
+var K=this;
+var G=function(V,W,X){return K._onClickDurationEvent(C.elmt,W,J);
+};
+SimileAjax.DOM.registerEvent(C.elmt,"mousedown",G);
+SimileAjax.DOM.registerEvent(L.elmt,"mousedown",G);
+this._createHighlightDiv(O,C,S);
+this._eventIdToElmt[J.getID()]=C.elmt;
+};
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(L,P,W,S){var Z=this._timeline.getDocument();
+var K=L.getText();
+var D=L.getStart();
+var Q=L.getLatestStart();
+var T=L.getEnd();
+var X=L.getEarliestEnd();
+var B=Math.round(this._band.dateToPixelOffset(D));
+var F=Math.round(this._band.dateToPixelOffset(Q));
+var A=Math.round(this._band.dateToPixelOffset(T));
+var G=Math.round(this._band.dateToPixelOffset(X));
+var H=this._frc.computeSize(K);
+var E=this._findFreeTrackForSolid(A);
+var R=L.getColor();
+R=R!=null?R:W.event.duration.color;
+var O=this._paintEventTape(L,E,B,A,W.event.duration.impreciseColor,W.event.duration.impreciseOpacity,P,W);
+var C=this._paintEventTape(L,E,F,G,R,100,P,W);
+var J=this._getTrackData(E);
+J.solid=B;
+var Y=F+W.event.label.offsetFromLine;
+var U=this._findFreeTrackForText(E,Y+H.width,function(a){a.line=F-2;
+});
+this._getTrackData(U).text=F-2;
+this._paintEventLine(L,F,E,U,P,W);
+var V=Math.round(P.trackOffset+U*P.trackIncrement+P.trackHeight/2-H.height/2);
+var N=this._paintEventLabel(L,K,Y,V,H.width,H.height,W);
+var M=this;
+var I=function(a,b,c){return M._onClickDurationEvent(C.elmt,b,L);
+};
+SimileAjax.DOM.registerEvent(C.elmt,"mousedown",I);
+SimileAjax.DOM.registerEvent(N.elmt,"mousedown",I);
+this._createHighlightDiv(S,C,W);
+this._eventIdToElmt[L.getID()]=C.elmt;
+};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(B,A){for(var D=0;
+true;
+D++){if(D<this._lowerTracks.length){var C=this._lowerTracks[D];
+if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return D;
+}}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return D;
+}if(D<this._upperTracks.length){var C=this._upperTracks[D];
+if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return -1-D;
+}}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+return -1-D;
+}}};
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(D,C,H){var F;
+var G;
+var B;
+var J;
+if(D<0){F=true;
+B=-D;
+G=this._findFreeUpperTrackForText(B,C);
+J=-1-G;
+}else{if(D>0){F=false;
+B=D+1;
+G=this._findFreeLowerTrackForText(B,C);
+J=G;
+}else{var A=this._findFreeUpperTrackForText(0,C);
+var I=this._findFreeLowerTrackForText(1,C);
+if(I-1<=A){F=false;
+B=1;
+G=I;
+J=G;
+}else{F=true;
+B=0;
+G=A;
+J=-1-G;
+}}}if(F){if(G==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var E=B;
+E<G;
+E++){H(this._upperTracks[E]);
+}}else{if(G==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
+}for(var E=B;
+E<G;
+E++){H(this._lowerTracks[E]);
+}}return J;
+};
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(A,C){for(;
+A<this._lowerTracks.length;
+A++){var B=this._lowerTracks[A];
+if(Math.min(B.solid,B.text)>=C){break;
+}}return A;
+};
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(A,C){for(;
+A<this._upperTracks.length;
+A++){var B=this._upperTracks[A];
+if(Math.min(B.solid,B.text)>=C){break;
+}}return A;
+};
+Timeline.DetailedEventPainter.prototype._getTrackData=function(A){return(A<0)?this._upperTracks[-A-1]:this._lowerTracks[A];
+};
+Timeline.DetailedEventPainter.prototype._paintEventLine=function(I,C,F,A,G,D){var H=Math.round(G.trackOffset+F*G.trackIncrement+G.trackHeight/2);
+var J=Math.round(Math.abs(A-F)*G.trackIncrement);
+var E="1px solid "+D.event.label.lineColor;
+var B=this._timeline.getDocument().createElement("div");
+B.style.position="absolute";
+B.style.left=C+"px";
+B.style.width=D.event.label.offsetFromLine+"px";
+B.style.height=J+"px";
+if(F>A){B.style.top=(H-J)+"px";
+B.style.borderTop=E;
+}else{B.style.top=H+"px";
+B.style.borderBottom=E;
+}B.style.borderLeft=E;
+this._lineLayer.appendChild(B);
+};
+Timeline.DetailedEventPainter.prototype._paintEventIcon=function(I,E,B,F,D){var H=I.getIcon();
+H=H!=null?H:F.icon;
+var J=F.trackOffset+E*F.trackIncrement+F.trackHeight/2;
+var G=Math.round(J-F.iconHeight/2);
+var C=SimileAjax.Graphics.createTranslucentImage(H);
+var A=this._timeline.getDocument().createElement("div");
+A.style.position="absolute";
+A.style.left=B+"px";
+A.style.top=G+"px";
+A.appendChild(C);
+A.style.cursor="pointer";
+if(I._title!=null){A.title=I._title;
+}this._eventLayer.appendChild(A);
+return{left:B,top:G,width:F.iconWidth,height:F.iconHeight,elmt:A};
+};
+Timeline.DetailedEventPainter.prototype._paintEventLabel=function(H,I,B,F,A,J,D){var G=this._timeline.getDocument();
+var K=G.createElement("div");
+K.style.position="absolute";
+K.style.left=B+"px";
+K.style.width=A+"px";
+K.style.top=F+"px";
+K.style.height=J+"px";
+K.style.backgroundColor=D.event.label.backgroundColor;
+SimileAjax.Graphics.setOpacity(K,D.event.label.backgroundOpacity);
+this._eventLayer.appendChild(K);
+var E=G.createElement("div");
+E.style.position="absolute";
+E.style.left=B+"px";
+E.style.width=A+"px";
+E.style.top=F+"px";
+E.innerHTML=I;
+E.style.cursor="pointer";
+if(H._title!=null){E.title=H._title;
+}var C=H.getTextColor();
+if(C==null){C=H.getColor();
+}if(C!=null){E.style.color=C;
+}this._eventLayer.appendChild(E);
+return{left:B,top:F,width:A,height:J,elmt:E};
+};
+Timeline.DetailedEventPainter.prototype._paintEventTape=function(L,H,E,A,C,G,I,F){var B=A-E;
+var D=F.event.tape.height;
+var M=I.trackOffset+H*I.trackIncrement+I.trackHeight/2;
+var J=Math.round(M-D/2);
+var K=this._timeline.getDocument().createElement("div");
+K.style.position="absolute";
+K.style.left=E+"px";
+K.style.width=B+"px";
+K.style.top=J+"px";
+K.style.height=D+"px";
+K.style.backgroundColor=C;
+K.style.overflow="hidden";
+K.style.cursor="pointer";
+if(L._title!=null){K.title=L._title;
+}SimileAjax.Graphics.setOpacity(K,G);
+this._eventLayer.appendChild(K);
+return{left:E,top:J,width:B,height:D,elmt:K};
+};
+Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
+var G=E.event;
+var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
+var F=D.createElement("div");
+F.style.position="absolute";
+F.style.overflow="hidden";
+F.style.left=(C.left-2)+"px";
+F.style.width=(C.width+4)+"px";
+F.style.top=(C.top-2)+"px";
+F.style.height=(C.height+4)+"px";
+F.style.background=B;
+this._highlightLayer.appendChild(F);
+}};
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
+this._fireOnSelect(A.getID());
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
+var F=C.pageY;
+}else{var E=SimileAjax.DOM.getPageCoordinates(D);
+var A=C.offsetX+E.left;
+var F=C.offsetY+E.top;
+}this._showBubble(A,F,B);
+this._fireOnSelect(B.getID());
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.DetailedEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
+if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
+}};
+Timeline.DetailedEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
+var C=this._params.theme.event.bubble;
+B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
+};
+Timeline.DetailedEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){this._onSelectListeners[A](B);
+}};
+
+
+/* ether-painters.js */
+Timeline.GregorianEtherPainter=function(A){this._params=A;
+this._theme=A.theme;
+this._unit=A.unit;
+this._multiple=("multiple" in A)?A.multiple:1;
+};
+Timeline.GregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
+this._timeline=B;
+this._backgroundLayer=C.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
+var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.GregorianEtherPainter.prototype.setHighlight=function(A,D,C,B){this._highlight.position(A,D,C,B);
+};
+Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var C=this._band.getMinDate();
+var F=this._band.getMaxDate();
+var B=this._band.getTimeZone();
+var E=this._band.getLabeller();
+SimileAjax.DateTime.roundDownToInterval(C,this._unit,B,this._multiple,this._theme.firstDayOfWeek);
+var D=this;
+var A=function(G){for(var H=0;
+H<D._multiple;
+H++){SimileAjax.DateTime.incrementByInterval(G,D._unit);
+}};
+while(C.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(C,E,this._unit,this._markerLayer,this._lineLayer);
+A(C);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.GregorianEtherPainter.prototype.zoom=function(A){if(A!=0){this._unit+=A;
+}};
+Timeline.HotZoneGregorianEtherPainter=function(G){this._params=G;
+this._theme=G.theme;
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:G.unit,multiple:1}];
+for(var E=0;
+E<G.zones.length;
+E++){var B=G.zones[E];
+var D=SimileAjax.DateTime.parseGregorianDateTime(B.start).getTime();
+var F=SimileAjax.DateTime.parseGregorianDateTime(B.end).getTime();
+for(var C=0;
+C<this._zones.length&&F>D;
+C++){var A=this._zones[C];
+if(D<A.endTime){if(D>A.startTime){this._zones.splice(C,0,{startTime:A.startTime,endTime:D,unit:A.unit,multiple:A.multiple});
+C++;
+A.startTime=D;
+}if(F<A.endTime){this._zones.splice(C,0,{startTime:D,endTime:F,unit:B.unit,multiple:(B.multiple)?B.multiple:1});
+C++;
+A.startTime=F;
+D=F;
+}else{A.multiple=B.multiple;
+A.unit=B.unit;
+D=A.endTime;
+}}}}};
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
+this._timeline=B;
+this._backgroundLayer=C.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
+var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var D=this._band.getMinDate();
+var A=this._band.getMaxDate();
+var K=this._band.getTimeZone();
+var I=this._band.getLabeller();
+var B=this;
+var L=function(N,M){for(var O=0;
+O<M.multiple;
+O++){SimileAjax.DateTime.incrementByInterval(N,M.unit);
+}};
+var C=0;
+while(C<this._zones.length){if(D.getTime()<this._zones[C].endTime){break;
+}C++;
+}var E=this._zones.length-1;
+while(E>=0){if(A.getTime()>this._zones[E].startTime){break;
+}E--;
+}for(var H=C;
+H<=E;
+H++){var G=this._zones[H];
+var J=new Date(Math.max(D.getTime(),G.startTime));
+var F=new Date(Math.min(A.getTime(),G.endTime));
+SimileAjax.DateTime.roundDownToInterval(J,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
+SimileAjax.DateTime.roundUpToInterval(F,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
+while(J.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(J,I,G.unit,this._markerLayer,this._lineLayer);
+L(J,G);
+}}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(B){if(B!=0){for(var A=0;
+A<this._zones.length;
+++A){if(this._zones[A]){this._zones[A].unit+=B;
+}}}};
+Timeline.YearCountEtherPainter=function(A){this._params=A;
+this._theme=A.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
+this._multiple=("multiple" in A)?A.multiple:1;
+};
+Timeline.YearCountEtherPainter.prototype.initialize=function(C,B){this._band=C;
+this._timeline=B;
+this._backgroundLayer=C.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
+var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.YearCountEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
+};
+Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var B=new Date(this._startDate.getTime());
+var F=this._band.getMaxDate();
+var E=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
+B.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-E%this._multiple);
+var C=this;
+var A=function(G){for(var H=0;
+H<C._multiple;
+H++){SimileAjax.DateTime.incrementByInterval(G,SimileAjax.DateTime.YEAR);
+}};
+var D={labelInterval:function(G,I){var H=G.getUTCFullYear()-C._startDate.getUTCFullYear();
+return{text:H,emphasized:H==0};
+}};
+while(B.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+A(B);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
+Timeline.QuarterlyEtherPainter=function(A){this._params=A;
+this._theme=A.theme;
+this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
+};
+Timeline.QuarterlyEtherPainter.prototype.initialize=function(C,B){this._band=C;
+this._timeline=B;
+this._backgroundLayer=C.createLayerDiv(0);
+this._backgroundLayer.setAttribute("name","ether-background");
+this._backgroundLayer.className="timeline-ether-bg";
+this._markerLayer=null;
+this._lineLayer=null;
+var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
+var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
+this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
+this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
+};
+Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
+};
+Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
+}this._markerLayer=this._band.createLayerDiv(100);
+this._markerLayer.setAttribute("name","ether-markers");
+this._markerLayer.style.display="none";
+if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
+}this._lineLayer=this._band.createLayerDiv(1);
+this._lineLayer.setAttribute("name","ether-lines");
+this._lineLayer.style.display="none";
+var B=new Date(0);
+var E=this._band.getMaxDate();
+B.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
+B.setUTCMonth(this._startDate.getUTCMonth());
+var C=this;
+var A=function(F){F.setUTCMonth(F.getUTCMonth()+3);
+};
+var D={labelInterval:function(F,H){var G=(4+(F.getUTCMonth()-C._startDate.getUTCMonth())/3)%4;
+if(G!=0){return{text:"Q"+(G+1),emphasized:false};
+}else{return{text:"Y"+(F.getUTCFullYear()-C._startDate.getUTCFullYear()+1),emphasized:true};
+}}};
+while(B.getTime()<E.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
+A(B);
+}this._markerLayer.style.display="block";
+this._lineLayer.style.display="block";
+};
+Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
+Timeline.EtherIntervalMarkerLayout=function(M,L,C,E,H){var A=M.isHorizontal();
+if(A){if(E=="Top"){this.positionDiv=function(O,N){O.style.left=N+"px";
+O.style.top="0px";
+};
+}else{this.positionDiv=function(O,N){O.style.left=N+"px";
+O.style.bottom="0px";
+};
+}}else{if(E=="Left"){this.positionDiv=function(O,N){O.style.top=N+"px";
+O.style.left="0px";
+};
+}else{this.positionDiv=function(O,N){O.style.top=N+"px";
+O.style.right="0px";
+};
+}}var D=C.ether.interval.marker;
+var I=C.ether.interval.line;
+var B=C.ether.interval.weekend;
+var K=(A?"h":"v")+E;
+var G=D[K+"Styler"];
+var J=D[K+"EmphasizedStyler"];
+var F=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+this.createIntervalMarker=function(T,a,b,c,Q){var U=Math.round(L.dateToPixelOffset(T));
+if(H&&b!=SimileAjax.DateTime.WEEK){var V=M.getDocument().createElement("div");
+V.className="timeline-ether-lines";
+if(I.opacity<100){SimileAjax.Graphics.setOpacity(V,I.opacity);
+}if(A){V.style.left=U+"px";
+}else{V.style.top=U+"px";
+}Q.appendChild(V);
+}if(b==SimileAjax.DateTime.WEEK){var N=C.firstDayOfWeek;
+var W=new Date(T.getTime()+(6-N-7)*F);
+var Z=new Date(W.getTime()+2*F);
+var X=Math.round(L.dateToPixelOffset(W));
+var S=Math.round(L.dateToPixelOffset(Z));
+var R=Math.max(1,S-X);
+var P=M.getDocument().createElement("div");
+P.className="timeline-ether-weekends";
+if(B.opacity<100){SimileAjax.Graphics.setOpacity(P,B.opacity);
+}if(A){P.style.left=X+"px";
+P.style.width=R+"px";
+}else{P.style.top=X+"px";
+P.style.height=R+"px";
+}Q.appendChild(P);
+}var Y=a.labelInterval(T,b);
+var O=M.getDocument().createElement("div");
+O.innerHTML=Y.text;
+O.className="timeline-date-label";
+if(Y.emphasized){O.className+=" timeline-date-label-em";
+}this.positionDiv(O,U);
+c.appendChild(O);
+return O;
+};
+};
+Timeline.EtherHighlight=function(C,E,D,B){var A=C.isHorizontal();
+this._highlightDiv=null;
+this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=C.getDocument().createElement("div");
+this._highlightDiv.setAttribute("name","ether-highlight");
+this._highlightDiv.className="timeline-ether-highlight";
+var F=D.ether.highlightOpacity;
+if(F<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,F);
+}B.appendChild(this._highlightDiv);
+}};
+this.position=function(G,L,K,H){K=K||0;
+H=H||1;
+this._createHighlightDiv();
+var M=Math.round(E.dateToPixelOffset(G));
+var J=Math.round(E.dateToPixelOffset(L));
+var I=Math.max(J-M,3);
+var F=E.getViewWidth()-4;
+if(A){this._highlightDiv.style.left=M+"px";
+this._highlightDiv.style.width=I+"px";
+this._highlightDiv.style.top=Math.round(K*F)+"px";
+this._highlightDiv.style.height=Math.round(H*F)+"px";
+}else{this._highlightDiv.style.top=M+"px";
+this._highlightDiv.style.height=I+"px";
+this._highlightDiv.style.left=Math.round(K*F)+"px";
+this._highlightDiv.style.width=Math.round(H*F)+"px";
+}};
+};
+
+
+/* ethers.js */
+Timeline.LinearEther=function(A){this._params=A;
+this._interval=A.interval;
+this._pixelsPerInterval=A.pixelsPerInterval;
+};
+Timeline.LinearEther.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._unit=A.getUnit();
+if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.LinearEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
+};
+Timeline.LinearEther.prototype.shiftPixels=function(B){var A=this._interval*B/this._pixelsPerInterval;
+this._start=this._unit.change(this._start,A);
+};
+Timeline.LinearEther.prototype.dateToPixelOffset=function(A){var B=this._unit.compare(A,this._start);
+return this._pixelsPerInterval*B/this._interval;
+};
+Timeline.LinearEther.prototype.pixelOffsetToDate=function(B){var A=B*this._interval/this._pixelsPerInterval;
+return this._unit.change(this._start,A);
+};
+Timeline.LinearEther.prototype.zoom=function(D){var B=0;
+var A=this._band._zoomIndex;
+var C=A;
+if(D&&(A>0)){C=A-1;
+}if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
+}this._band._zoomIndex=C;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
+this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
+B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
+return B;
+};
+Timeline.HotZoneEther=function(A){this._params=A;
+this._interval=A.interval;
+this._pixelsPerInterval=A.pixelsPerInterval;
+this._theme=A.theme;
+};
+Timeline.HotZoneEther.prototype.initialize=function(H,I){this._band=H;
+this._timeline=I;
+this._unit=I.getUnit();
+this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
+var B=this._params;
+for(var D=0;
+D<B.zones.length;
+D++){var G=B.zones[D];
+var E=this._unit.parseFromObject(G.start);
+var F=this._unit.parseFromObject(G.end);
+for(var C=0;
+C<this._zones.length&&this._unit.compare(F,E)>0;
+C++){var A=this._zones[C];
+if(this._unit.compare(E,A.endTime)<0){if(this._unit.compare(E,A.startTime)>0){this._zones.splice(C,0,{startTime:A.startTime,endTime:E,magnify:A.magnify});
+C++;
+A.startTime=E;
+}if(this._unit.compare(F,A.endTime)<0){this._zones.splice(C,0,{startTime:E,endTime:F,magnify:G.magnify*A.magnify});
+C++;
+A.startTime=F;
+E=F;
+}else{A.magnify*=G.magnify;
+E=A.endTime;
+}}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
+}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
+this.shiftPixels(-this._timeline.getPixelLength());
+}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}else{this._start=this._unit.makeDefaultValue();
+this.shiftPixels(-this._timeline.getPixelLength()/2);
+}}}};
+Timeline.HotZoneEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
+};
+Timeline.HotZoneEther.prototype.shiftPixels=function(A){this._start=this.pixelOffsetToDate(A);
+};
+Timeline.HotZoneEther.prototype.dateToPixelOffset=function(A){return this._dateDiffToPixelOffset(this._start,A);
+};
+Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(A){return this._pixelOffsetToDate(A,this._start);
+};
+Timeline.HotZoneEther.prototype.zoom=function(D){var B=0;
+var A=this._band._zoomIndex;
+var C=A;
+if(D&&(A>0)){C=A-1;
+}if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
+}this._band._zoomIndex=C;
+this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
+this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
+B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
+return B;
+};
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(I,D){var B=this._getScale();
+var H=I;
+var C=D;
+var A=0;
+if(this._unit.compare(H,C)<0){var G=0;
+while(G<this._zones.length){if(this._unit.compare(H,this._zones[G].endTime)<0){break;
+}G++;
+}while(this._unit.compare(H,C)<0){var E=this._zones[G];
+var F=this._unit.earlier(C,E.endTime);
+A+=(this._unit.compare(F,H)/(B/E.magnify));
+H=F;
+G++;
+}}else{var G=this._zones.length-1;
+while(G>=0){if(this._unit.compare(H,this._zones[G].startTime)>0){break;
+}G--;
+}while(this._unit.compare(H,C)>0){var E=this._zones[G];
+var F=this._unit.later(C,E.startTime);
+A+=(this._unit.compare(F,H)/(B/E.magnify));
+H=F;
+G--;
+}}return A;
+};
+Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(H,C){var G=this._getScale();
+var E=C;
+if(H>0){var F=0;
+while(F<this._zones.length){if(this._unit.compare(E,this._zones[F].endTime)<0){break;
+}F++;
+}while(H>0){var A=this._zones[F];
+var D=G/A.magnify;
+if(A.endTime==Number.POSITIVE_INFINITY){E=this._unit.change(E,H*D);
+H=0;
+}else{var B=this._unit.compare(A.endTime,E)/D;
+if(B>H){E=this._unit.change(E,H*D);
+H=0;
+}else{E=A.endTime;
+H-=B;
+}}F++;
+}}else{var F=this._zones.length-1;
+while(F>=0){if(this._unit.compare(E,this._zones[F].startTime)>0){break;
+}F--;
+}H=-H;
+while(H>0){var A=this._zones[F];
+var D=G/A.magnify;
+if(A.startTime==Number.NEGATIVE_INFINITY){E=this._unit.change(E,-H*D);
+H=0;
+}else{var B=this._unit.compare(E,A.startTime)/D;
+if(B>H){E=this._unit.change(E,-H*D);
+H=0;
+}else{E=A.startTime;
+H-=B;
+}}F--;
+}}return E;
+};
+Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
+};
+
+
+/* event-utils.js */
+Timeline.EventUtils={};
+Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
+}this._lastEventID+=1;
+return"e"+this._lastEventID;
+};
+Timeline.EventUtils.decodeEventElID=function(B){var D=B.split("-");
+if(D[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
+return{band:null,evt:null};
+}var C=Timeline.getTimelineFromID(D[2]);
+var E=C.getBand(D[3]);
+var A=E.getEventSource.getEvent(D[4]);
+return{band:E,evt:A};
+};
+Timeline.EventUtils.encodeEventElID=function(C,D,B,A){return B+"-tl-"+C.timelineID+"-"+D.getIndex()+"-"+A.getID();
+};
+
+
+/* labellers.js */
+Timeline.GregorianDateLabeller=function(A,B){this._locale=A;
+this._timeZone=B;
+};
+Timeline.GregorianDateLabeller.monthNames=[];
+Timeline.GregorianDateLabeller.dayNames=[];
+Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
+Timeline.GregorianDateLabeller.getMonthName=function(B,A){return Timeline.GregorianDateLabeller.monthNames[A][B];
+};
+Timeline.GregorianDateLabeller.prototype.labelInterval=function(A,C){var B=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+if(B==null){B=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+}return B.call(this,A,C);
+};
+Timeline.GregorianDateLabeller.prototype.labelPrecise=function(A){return SimileAjax.DateTime.removeTimeZoneOffset(A,this._timeZone).toUTCString();
+};
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(B,F){var C;
+var E=false;
+B=SimileAjax.DateTime.removeTimeZoneOffset(B,this._timeZone);
+switch(F){case SimileAjax.DateTime.MILLISECOND:C=B.getUTCMilliseconds();
+break;
+case SimileAjax.DateTime.SECOND:C=B.getUTCSeconds();
+break;
+case SimileAjax.DateTime.MINUTE:var A=B.getUTCMinutes();
+if(A==0){C=B.getUTCHours()+":00";
+E=true;
+}else{C=A;
+}break;
+case SimileAjax.DateTime.HOUR:C=B.getUTCHours()+"hr";
+break;
+case SimileAjax.DateTime.DAY:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
+break;
+case SimileAjax.DateTime.WEEK:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
+break;
+case SimileAjax.DateTime.MONTH:var A=B.getUTCMonth();
+if(A!=0){C=Timeline.GregorianDateLabeller.getMonthName(A,this._locale);
+break;
+}case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var D=B.getUTCFullYear();
+if(D>0){C=B.getUTCFullYear();
+}else{C=(1-D)+"BC";
+}E=(F==SimileAjax.DateTime.MONTH)||(F==SimileAjax.DateTime.DECADE&&D%100==0)||(F==SimileAjax.DateTime.CENTURY&&D%1000==0);
+break;
+default:C=B.toUTCString();
+}return{text:C,emphasized:E};
+};
+
+
+/* original-painter.js */
+Timeline.OriginalEventPainter=function(A){this._params=A;
+this._onSelectListeners=[];
+this._eventPaintListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+this._frc=null;
+this._eventIdToElmt={};
+};
+Timeline.OriginalEventPainter.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._backLayer=null;
+this._eventLayer=null;
+this._lineLayer=null;
+this._highlightLayer=null;
+this._eventIdToElmt=null;
+};
+Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
+};
+Timeline.OriginalEventPainter.prototype.supportsOrthogonalScrolling=function(){return true;
+};
+Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
+};
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(A){this._eventPaintListeners.push(A);
+};
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(B){for(var A=0;
+A<this._eventPaintListeners.length;
+A++){if(this._eventPaintListeners[A]==B){this._eventPaintListeners.splice(A,1);
+break;
+}}};
+Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
+};
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
+};
+Timeline.OriginalEventPainter.prototype.paint=function(){var F=this._band.getEventSource();
+if(F==null){return ;
+}this._eventIdToElmt={};
+this._fireEventPaintListeners("paintStarting",null,null);
+this._prepareForPainting();
+var D=this._computeMetrics();
+var E=this._band.getMinDate();
+var H=this._band.getMaxDate();
+var B=(this._filterMatcher!=null)?this._filterMatcher:function(I){return true;
+};
+var G=(this._highlightMatcher!=null)?this._highlightMatcher:function(I){return -1;
+};
+var C=F.getEventReverseIterator(E,H);
+while(C.hasNext()){var A=C.next();
+if(B(A)){this.paintEvent(A,D,this._params.theme,G(A));
+}}this._highlightLayer.style.display="block";
+this._lineLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,D.trackIncrement);
+this._fireEventPaintListeners("paintEnded",null,null);
+this._setOrthogonalOffset(D);
+};
+Timeline.OriginalEventPainter.prototype.softPaint=function(){this._setOrthogonalOffset(this._computeMetrics());
+};
+Timeline.OriginalEventPainter.prototype.getOrthogonalExtent=function(){var A=this._computeMetrics();
+return 2*A.trackOffset+this._tracks.length*A.trackIncrement;
+};
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset=function(A){var B=this._band.getViewOrthogonalOffset();
+this._highlightLayer.style.top=this._lineLayer.style.top=this._eventLayer.style.top=B+"px";
+};
+Timeline.OriginalEventPainter.prototype._computeMetrics=function(){var C=this._params.theme.event;
+var B=Math.max(C.track.height,C.tape.height+this._frc.getLineHeight());
+var A={trackOffset:C.track.offset,trackHeight:B,trackGap:C.track.gap,trackIncrement:B+C.track.gap,icon:C.instant.icon,iconWidth:C.instant.iconWidth,iconHeight:C.instant.iconHeight,labelWidth:C.label.width,maxLabelChar:C.label.maxLabelChar,impreciseIconMargin:C.instant.impreciseIconMargin};
+return A;
+};
+Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var B=this._band;
+if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
+this._backLayer.style.visibility="hidden";
+var A=document.createElement("span");
+A.className="timeline-event-label";
+this._backLayer.appendChild(A);
+this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
+}this._frc.update();
+this._tracks=[];
+if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
+}this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
+this._lineLayer.style.display="none";
+if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
+}this._eventLayer=B.createLayerDiv(115,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OriginalEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
+}else{this.paintDurationEvent(B,C,D,A);
+}};
+Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
+}else{this.paintPreciseInstantEvent(B,C,D,A);
+}};
+Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
+}else{this.paintPreciseDurationEvent(B,C,D,A);
+}};
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(M,Q,S,R){var V=this._timeline.getDocument();
+var L=M.getText();
+var E=M.getStart();
+var C=Math.round(this._band.dateToPixelOffset(E));
+var A=Math.round(C+Q.iconWidth/2);
+var K=Math.round(C-Q.iconWidth/2);
+var H=this._getLabelDivClassName(M);
+var I=this._frc.computeSize(L,H);
+var W=A+S.event.label.offsetFromLine;
+var D=W+I.width;
+var U=D;
+var O=this._findFreeTrack(M,U);
+var T=Math.round(Q.trackOffset+O*Q.trackIncrement+Q.trackHeight/2-I.height/2);
+var B=this._paintEventIcon(M,O,K,Q,S,0);
+var P=this._paintEventLabel(M,L,W,T,I.width,I.height,S,H,R);
+var F=[B.elmt,P.elmt];
+var N=this;
+var J=function(X,Y,Z){return N._onClickInstantEvent(B.elmt,Y,M);
+};
+SimileAjax.DOM.registerEvent(B.elmt,"mousedown",J);
+SimileAjax.DOM.registerEvent(P.elmt,"mousedown",J);
+var G=this._createHighlightDiv(R,B,S,M);
+if(G!=null){F.push(G);
+}this._fireEventPaintListeners("paintedEvent",M,F);
+this._eventIdToElmt[M.getID()]=B.elmt;
+this._tracks[O]=K;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(P,T,Y,V){var a=this._timeline.getDocument();
+var N=P.getText();
+var G=P.getStart();
+var W=P.getEnd();
+var D=Math.round(this._band.dateToPixelOffset(G));
+var B=Math.round(this._band.dateToPixelOffset(W));
+var A=Math.round(D+T.iconWidth/2);
+var M=Math.round(D-T.iconWidth/2);
+var J=this._getLabelDivClassName(P);
+var K=this._frc.computeSize(N,J);
+var b=A+Y.event.label.offsetFromLine;
+var E=b+K.width;
+var Z=Math.max(E,B);
+var R=this._findFreeTrack(P,Z);
+var O=Y.event.tape.height;
+var X=Math.round(T.trackOffset+R*T.trackIncrement+O);
+var C=this._paintEventIcon(P,R,M,T,Y,O);
+var S=this._paintEventLabel(P,N,b,X,K.width,K.height,Y,J,V);
+var U=P.getColor();
+U=U!=null?U:Y.event.instant.impreciseColor;
+var F=this._paintEventTape(P,R,D,B,U,Y.event.instant.impreciseOpacity,T,Y,0);
+var H=[C.elmt,S.elmt,F.elmt];
+var Q=this;
+var L=function(c,d,e){return Q._onClickInstantEvent(C.elmt,d,P);
+};
+SimileAjax.DOM.registerEvent(C.elmt,"mousedown",L);
+SimileAjax.DOM.registerEvent(F.elmt,"mousedown",L);
+SimileAjax.DOM.registerEvent(S.elmt,"mousedown",L);
+var I=this._createHighlightDiv(V,C,Y,P);
+if(I!=null){H.push(I);
+}this._fireEventPaintListeners("paintedEvent",P,H);
+this._eventIdToElmt[P.getID()]=C.elmt;
+this._tracks[R]=M;
+};
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(L,P,T,R){var W=this._timeline.getDocument();
+var K=L.getText();
+var E=L.getStart();
+var S=L.getEnd();
+var B=Math.round(this._band.dateToPixelOffset(E));
+var A=Math.round(this._band.dateToPixelOffset(S));
+var H=this._getLabelDivClassName(L);
+var I=this._frc.computeSize(K,H);
+var X=B;
+var C=X+I.width;
+var V=Math.max(C,A);
+var N=this._findFreeTrack(L,V);
+var U=Math.round(P.trackOffset+N*P.trackIncrement+T.event.tape.height);
+var Q=L.getColor();
+Q=Q!=null?Q:T.event.duration.color;
+var D=this._paintEventTape(L,N,B,A,Q,100,P,T,0);
+var O=this._paintEventLabel(L,K,X,U,I.width,I.height,T,H,R);
+var F=[D.elmt,O.elmt];
+var M=this;
+var J=function(Y,Z,a){return M._onClickDurationEvent(D.elmt,Z,L);
+};
+SimileAjax.DOM.registerEvent(D.elmt,"mousedown",J);
+SimileAjax.DOM.registerEvent(O.elmt,"mousedown",J);
+var G=this._createHighlightDiv(R,D,T,L);
+if(G!=null){F.push(G);
+}this._fireEventPaintListeners("paintedEvent",L,F);
+this._eventIdToElmt[L.getID()]=D.elmt;
+this._tracks[N]=B;
+};
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(N,S,Y,V){var b=this._timeline.getDocument();
+var M=N.getText();
+var E=N.getStart();
+var T=N.getLatestStart();
+var W=N.getEnd();
+var a=N.getEarliestEnd();
+var C=Math.round(this._band.dateToPixelOffset(E));
+var G=Math.round(this._band.dateToPixelOffset(T));
+var A=Math.round(this._band.dateToPixelOffset(W));
+var H=Math.round(this._band.dateToPixelOffset(a));
+var J=this._getLabelDivClassName(N);
+var K=this._frc.computeSize(M,J);
+var c=G;
+var B=c+K.width;
+var Z=Math.max(B,A);
+var P=this._findFreeTrack(N,Z);
+var X=Math.round(S.trackOffset+P*S.trackIncrement+Y.event.tape.height);
+var U=N.getColor();
+U=U!=null?U:Y.event.duration.color;
+var R=this._paintEventTape(N,P,C,A,Y.event.duration.impreciseColor,Y.event.duration.impreciseOpacity,S,Y,0);
+var D=this._paintEventTape(N,P,G,H,U,100,S,Y,1);
+var Q=this._paintEventLabel(N,M,c,X,K.width,K.height,Y,J,V);
+var F=[R.elmt,D.elmt,Q.elmt];
+var O=this;
+var L=function(d,e,f){return O._onClickDurationEvent(D.elmt,e,N);
+};
+SimileAjax.DOM.registerEvent(D.elmt,"mousedown",L);
+SimileAjax.DOM.registerEvent(Q.elmt,"mousedown",L);
+var I=this._createHighlightDiv(V,D,Y,N);
+if(I!=null){F.push(I);
+}this._fireEventPaintListeners("paintedEvent",N,F);
+this._eventIdToElmt[N.getID()]=D.elmt;
+this._tracks[P]=C;
+};
+Timeline.OriginalEventPainter.prototype._encodeEventElID=function(B,A){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,B,A);
+};
+Timeline.OriginalEventPainter.prototype._findFreeTrack=function(E,A){var D=E.getTrackNum();
+if(D!=null){return D;
+}for(var C=0;
+C<this._tracks.length;
+C++){var B=this._tracks[C];
+if(B>A){break;
+}}return C;
+};
+Timeline.OriginalEventPainter.prototype._paintEventIcon=function(J,F,B,G,E,C){var I=J.getIcon();
+I=I!=null?I:G.icon;
+var H;
+if(C>0){H=G.trackOffset+F*G.trackIncrement+C+G.impreciseIconMargin;
+}else{var K=G.trackOffset+F*G.trackIncrement+G.trackHeight/2;
+H=Math.round(K-G.iconHeight/2);
+}var D=SimileAjax.Graphics.createTranslucentImage(I);
+var A=this._timeline.getDocument().createElement("div");
+A.className=this._getElClassName("timeline-event-icon",J,"icon");
+A.id=this._encodeEventElID("icon",J);
+A.style.left=B+"px";
+A.style.top=H+"px";
+A.appendChild(D);
+if(J._title!=null){A.title=J._title;
+}this._eventLayer.appendChild(A);
+return{left:B,top:H,width:G.iconWidth,height:G.iconHeight,elmt:A};
+};
+Timeline.OriginalEventPainter.prototype._paintEventLabel=function(J,K,C,H,A,L,E,F,B){var I=this._timeline.getDocument();
+var G=I.createElement("div");
+G.className=F;
+G.id=this._encodeEventElID("label",J);
+G.style.left=C+"px";
+G.style.width=A+"px";
+G.style.top=H+"px";
+G.innerHTML=K;
+if(J._title!=null){G.title=J._title;
+}var D=J.getTextColor();
+if(D==null){D=J.getColor();
+}if(D!=null){G.style.color=D;
+}if(E.event.highlightLabelBackground&&B>=0){G.style.background=this._getHighlightColor(B,E);
+}this._eventLayer.appendChild(G);
+return{left:C,top:H,width:A,height:L,elmt:G};
+};
+Timeline.OriginalEventPainter.prototype._paintEventTape=function(N,I,F,A,C,H,J,G,O){var B=A-F;
+var E=G.event.tape.height;
+var K=J.trackOffset+I*J.trackIncrement;
+var M=this._timeline.getDocument().createElement("div");
+M.className=this._getElClassName("timeline-event-tape",N,"tape");
+M.id=this._encodeEventElID("tape"+O,N);
+M.style.left=F+"px";
+M.style.width=B+"px";
+M.style.height=E+"px";
+M.style.top=K+"px";
+if(N._title!=null){M.title=N._title;
+}if(C!=null){M.style.backgroundColor=C;
+}var L=N.getTapeImage();
+var D=N.getTapeRepeat();
+D=D!=null?D:"repeat";
+if(L!=null){M.style.backgroundImage="url("+L+")";
+M.style.backgroundRepeat=D;
+}SimileAjax.Graphics.setOpacity(M,H);
+this._eventLayer.appendChild(M);
+return{left:F,top:K,width:B,height:E,elmt:M};
+};
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(A){return this._getElClassName("timeline-event-label",A,"label");
+};
+Timeline.OriginalEventPainter.prototype._getElClassName=function(B,A,D){var E=A.getClassName(),C=[];
+if(E){if(D){C.push(D+"-"+E+" ");
+}C.push(E+" ");
+}C.push(B);
+return(C.join(""));
+};
+Timeline.OriginalEventPainter.prototype._getHighlightColor=function(A,C){var B=C.event.highlightColors;
+return B[Math.min(A,B.length-1)];
+};
+Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(A,D,F,B){var G=null;
+if(A>=0){var E=this._timeline.getDocument();
+var C=this._getHighlightColor(A,F);
+G=E.createElement("div");
+G.className=this._getElClassName("timeline-event-highlight",B,"highlight");
+G.id=this._encodeEventElID("highlight0",B);
+G.style.position="absolute";
+G.style.overflow="hidden";
+G.style.left=(D.left-2)+"px";
+G.style.width=(D.width+4)+"px";
+G.style.top=(D.top-2)+"px";
+G.style.height=(D.height+4)+"px";
+G.style.background=C;
+this._highlightLayer.appendChild(G);
+}return G;
+};
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
+this._fireOnSelect(A.getID());
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
+var F=C.pageY;
+}else{var E=SimileAjax.DOM.getPageCoordinates(D);
+var A=C.offsetX+E.left;
+var F=C.offsetY+E.top;
+}this._showBubble(A,F,B);
+this._fireOnSelect(B.getID());
+C.cancelBubble=true;
+SimileAjax.DOM.cancelEvent(C);
+return false;
+};
+Timeline.OriginalEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
+if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
+this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
+}};
+Timeline.OriginalEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
+var C=this._params.theme.event.bubble;
+B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
+SimileAjax.WindowManager.cancelPopups();
+SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
+};
+Timeline.OriginalEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){this._onSelectListeners[A](B);
+}};
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(D,A,C){for(var B=0;
+B<this._eventPaintListeners.length;
+B++){this._eventPaintListeners[B](this._band,D,A,C);
+}};
+
+
+/* overview-painter.js */
+Timeline.OverviewEventPainter=function(A){this._params=A;
+this._onSelectListeners=[];
+this._filterMatcher=null;
+this._highlightMatcher=null;
+};
+Timeline.OverviewEventPainter.prototype.initialize=function(B,A){this._band=B;
+this._timeline=A;
+this._eventLayer=null;
+this._highlightLayer=null;
+};
+Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
+};
+Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
+};
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
+A<this._onSelectListeners.length;
+A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
+break;
+}}};
+Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
+};
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
+};
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
+};
+Timeline.OverviewEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
+if(B==null){return ;
+}this._prepareForPainting();
+var H=this._params.theme.event;
+var F={trackOffset:H.overviewTrack.offset,trackHeight:H.overviewTrack.height,trackGap:H.overviewTrack.gap,trackIncrement:H.overviewTrack.height+H.overviewTrack.gap};
+var C=this._band.getMinDate();
+var A=this._band.getMaxDate();
+var I=(this._filterMatcher!=null)?this._filterMatcher:function(J){return true;
+};
+var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(J){return -1;
+};
+var D=B.getEventReverseIterator(C,A);
+while(D.hasNext()){var G=D.next();
+if(I(G)){this.paintEvent(G,F,this._params.theme,E(G));
+}}this._highlightLayer.style.display="block";
+this._eventLayer.style.display="block";
+this._band.updateEventTrackInfo(this._tracks.length,F.trackIncrement);
+};
+Timeline.OverviewEventPainter.prototype.softPaint=function(){};
+Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var A=this._band;
+this._tracks=[];
+if(this._highlightLayer!=null){A.removeLayerDiv(this._highlightLayer);
+}this._highlightLayer=A.createLayerDiv(105,"timeline-band-highlights");
+this._highlightLayer.style.display="none";
+if(this._eventLayer!=null){A.removeLayerDiv(this._eventLayer);
+}this._eventLayer=A.createLayerDiv(110,"timeline-band-events");
+this._eventLayer.style.display="none";
+};
+Timeline.OverviewEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
+}else{this.paintDurationEvent(B,C,D,A);
+}};
+Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(I,H,F,A){var B=I.getStart();
+var E=Math.round(this._band.dateToPixelOffset(B));
+var D=I.getColor(),C=I.getClassName();
+if(C){D=null;
+}else{D=D!=null?D:F.event.duration.color;
+}var G=this._paintEventTick(I,E,D,100,H,F);
+this._createHighlightDiv(A,G,F);
+};
+Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(L,K,J,D){var A=L.getLatestStart();
+var C=L.getEarliestEnd();
+var B=Math.round(this._band.dateToPixelOffset(A));
+var E=Math.round(this._band.dateToPixelOffset(C));
+var I=0;
+for(;
+I<this._tracks.length;
+I++){if(E<this._tracks[I]){break;
+}}this._tracks[I]=E;
+var H=L.getColor(),G=L.getClassName();
+if(G){H=null;
+}else{H=H!=null?H:J.event.duration.color;
+}var F=this._paintEventTape(L,I,B,E,H,100,K,J,G);
+this._createHighlightDiv(D,F,J);
+};
+Timeline.OverviewEventPainter.prototype._paintEventTape=function(L,B,C,K,E,G,H,F,D){var I=H.trackOffset+B*H.trackIncrement;
+var A=K-C;
+var M=H.trackHeight;
+var J=this._timeline.getDocument().createElement("div");
+J.className="timeline-small-event-tape";
+if(D){J.className+=" small-"+D;
+}J.style.left=C+"px";
+J.style.width=A+"px";
+J.style.top=I+"px";
+J.style.height=M+"px";
+if(E){J.style.backgroundColor=E;
+}if(G<100){SimileAjax.Graphics.setOpacity(J,G);
+}this._eventLayer.appendChild(J);
+return{left:C,top:I,width:A,height:M,elmt:J};
+};
+Timeline.OverviewEventPainter.prototype._paintEventTick=function(J,B,D,F,G,E){var K=E.event.overviewTrack.tickHeight;
+var H=G.trackOffset-K;
+var A=1;
+var I=this._timeline.getDocument().createElement("div");
+I.className="timeline-small-event-icon";
+I.style.left=B+"px";
+I.style.top=H+"px";
+var C=J.getClassName();
+if(C){I.className+=" small-"+C;
+}if(F<100){SimileAjax.Graphics.setOpacity(I,F);
+}this._eventLayer.appendChild(I);
+return{left:B,top:H,width:A,height:K,elmt:I};
+};
+Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
+var G=E.event;
+var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
+var F=D.createElement("div");
+F.style.position="absolute";
+F.style.overflow="hidden";
+F.style.left=(C.left-1)+"px";
+F.style.width=(C.width+2)+"px";
+F.style.top=(C.top-1)+"px";
+F.style.height=(C.height+2)+"px";
+F.style.background=B;
+this._highlightLayer.appendChild(F);
+}};
+Timeline.OverviewEventPainter.prototype.showBubble=function(A){};
+
+
+/* sources.js */
+Timeline.DefaultEventSource=function(A){this._events=(A instanceof Object)?A:new SimileAjax.EventIndex();
+this._listeners=[];
+};
+Timeline.DefaultEventSource.prototype.addListener=function(A){this._listeners.push(A);
+};
+Timeline.DefaultEventSource.prototype.removeListener=function(B){for(var A=0;
+A<this._listeners.length;
+A++){if(this._listeners[A]==B){this._listeners.splice(A,1);
+break;
+}}};
+Timeline.DefaultEventSource.prototype.loadXML=function(G,A){var C=this._getBaseURL(A);
+var H=G.documentElement.getAttribute("wiki-url");
+var L=G.documentElement.getAttribute("wiki-section");
+var E=G.documentElement.getAttribute("date-time-format");
+var F=this._events.getUnit().getParser(E);
+var D=G.documentElement.firstChild;
+var I=false;
+while(D!=null){if(D.nodeType==1){var K="";
+if(D.firstChild!=null&&D.firstChild.nodeType==3){K=D.firstChild.nodeValue;
+}var B=(D.getAttribute("isDuration")===null&&D.getAttribute("durationEvent")===null)||D.getAttribute("isDuration")=="false"||D.getAttribute("durationEvent")=="false";
+var J=new Timeline.DefaultEventSource.Event({id:D.getAttribute("id"),start:F(D.getAttribute("start")),end:F(D.getAttribute("end")),latestStart:F(D.getAttribute("latestStart")),earliestEnd:F(D.getAttribute("earliestEnd")),instant:B,text:D.getAttribute("title"),description:K,image:this._resolveRelativeURL(D.getAttribute("image"),C),link:this._resolveRelativeURL(D.getAttribute("link"),C),icon:this._resolveRelativeURL(D.getAttribute("icon"),C),color:D.getAttribute("color"),textColor:D.getAttribute("textColor"),hoverText:D.getAttribute("hoverText"),classname:D.getAttribute("classname"),tapeImage:D.getAttribute("tapeImage"),tapeRepeat:D.getAttribute("tapeRepeat"),caption:D.getAttribute("caption"),eventID:D.getAttribute("eventID"),trackNum:D.getAttribute("trackNum")});
+J._node=D;
+J.getProperty=function(M){return this._node.getAttribute(M);
+};
+J.setWikiInfo(H,L);
+this._events.add(J);
+I=true;
+}D=D.nextSibling;
+}if(I){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadJSON=function(F,A){var C=this._getBaseURL(A);
+var I=false;
+if(F&&F.events){var H=("wikiURL" in F)?F.wikiURL:null;
+var K=("wikiSection" in F)?F.wikiSection:null;
+var D=("dateTimeFormat" in F)?F.dateTimeFormat:null;
+var G=this._events.getUnit().getParser(D);
+for(var E=0;
+E<F.events.length;
+E++){var L=F.events[E];
+var B=L.isDuration||(("durationEvent" in L)&&!L.durationEvent)||(("de" in L)&&!L.de);
+var J=new Timeline.DefaultEventSource.Event({id:("id" in L)?L.id:undefined,start:G(L.start||L.s),end:G(L.end||L.e),latestStart:G(L.latestStart||L.ls),earliestEnd:G(L.earliestEnd||L.ee),instant:B,text:L.title||L.t,description:L.description||L.d,image:this._resolveRelativeURL(L.image,C),link:this._resolveRelativeURL(L.link,C),icon:this._resolveRelativeURL(L.icon,C),color:L.color,textColor:L.textColor,hoverText:L.hoverText,classname:L.classname||L.c,tapeImage:L.tapeImage,tapeRepeat:L.tapeRepeat,caption:L.caption,eventID:L.eventID||L.eid,trackNum:L.trackNum});
+J._obj=L;
+J.getProperty=function(M){return this._obj[M];
+};
+J.setWikiInfo(H,K);
+this._events.add(J);
+I=true;
+}}if(I){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.loadSPARQL=function(H,A){var D=this._getBaseURL(A);
+var F="iso8601";
+var G=this._events.getUnit().getParser(F);
+if(H==null){return ;
+}var E=H.documentElement.firstChild;
+while(E!=null&&(E.nodeType!=1||E.nodeName!="results")){E=E.nextSibling;
+}var J=null;
+var M=null;
+if(E!=null){J=E.getAttribute("wiki-url");
+M=E.getAttribute("wiki-section");
+E=E.firstChild;
+}var K=false;
+while(E!=null){if(E.nodeType==1){var C={};
+var I=E.firstChild;
+while(I!=null){if(I.nodeType==1&&I.firstChild!=null&&I.firstChild.nodeType==1&&I.firstChild.firstChild!=null&&I.firstChild.firstChild.nodeType==3){C[I.getAttribute("name")]=I.firstChild.firstChild.nodeValue;
+}I=I.nextSibling;
+}if(C["start"]==null&&C["date"]!=null){C["start"]=C["date"];
+}var B=(C["isDuration"]===null&&C["durationEvent"]===null)||C["isDuration"]=="false"||C["durationEvent"]=="false";
+var L=new Timeline.DefaultEventSource.Event({id:C["id"],start:G(C["start"]),end:G(C["end"]),latestStart:G(C["latestStart"]),earliestEnd:G(C["earliestEnd"]),instant:B,text:C["title"],description:C["description"],image:this._resolveRelativeURL(C["image"],D),link:this._resolveRelativeURL(C["link"],D),icon:this._resolveRelativeURL(C["icon"],D),color:C["color"],textColor:C["textColor"],hoverText:C["hoverText"],caption:C["caption"],classname:C["classname"],tapeImage:C["tapeImage"],tapeRepeat:C["tapeRepeat"],eventID:C["eventID"],trackNum:C["trackNum"]});
+L._bindings=C;
+L.getProperty=function(N){return this._bindings[N];
+};
+L.setWikiInfo(J,M);
+this._events.add(L);
+K=true;
+}E=E.nextSibling;
+}if(K){this._fire("onAddMany",[]);
+}};
+Timeline.DefaultEventSource.prototype.add=function(A){this._events.add(A);
+this._fire("onAddOne",[A]);
+};
+Timeline.DefaultEventSource.prototype.addMany=function(B){for(var A=0;
+A<B.length;
+A++){this._events.add(B[A]);
+}this._fire("onAddMany",[]);
+};
+Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
+this._fire("onClear",[]);
+};
+Timeline.DefaultEventSource.prototype.getEvent=function(A){return this._events.getEvent(A);
+};
+Timeline.DefaultEventSource.prototype.getEventIterator=function(A,B){return this._events.getIterator(A,B);
+};
+Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(A,B){return this._events.getReverseIterator(A,B);
+};
+Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
+};
+Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
+};
+Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
+};
+Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
+};
+Timeline.DefaultEventSource.prototype._fire=function(B,A){for(var C=0;
+C<this._listeners.length;
+C++){var D=this._listeners[C];
+if(B in D){try{D[B].apply(D,A);
+}catch(E){SimileAjax.Debug.exception(E);
+}}}};
+Timeline.DefaultEventSource.prototype._getBaseURL=function(A){if(A.indexOf("://")<0){var C=this._getBaseURL(document.location.href);
+if(A.substr(0,1)=="/"){A=C.substr(0,C.indexOf("/",C.indexOf("://")+3))+A;
+}else{A=C+A;
+}}var B=A.lastIndexOf("/");
+if(B<0){return"";
+}else{return A.substr(0,B+1);
+}};
+Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(A,B){if(A==null||A==""){return A;
+}else{if(A.indexOf("://")>0){return A;
+}else{if(A.substr(0,1)=="/"){return B.substr(0,B.indexOf("/",B.indexOf("://")+3))+A;
+}else{return B+A;
+}}}};
+Timeline.DefaultEventSource.Event=function(A){function D(E){return(A[E]!=null&&A[E]!="")?A[E]:null;
+}var C=A.id?A.id.trim():"";
+this._id=C.length>0?C:Timeline.EventUtils.getNewEventID();
+this._instant=A.instant||(A.end==null);
+this._start=A.start;
+this._end=(A.end!=null)?A.end:A.start;
+this._latestStart=(A.latestStart!=null)?A.latestStart:(A.instant?this._end:this._start);
+this._earliestEnd=(A.earliestEnd!=null)?A.earliestEnd:this._end;
+var B=[];
+if(this._start>this._latestStart){this._latestStart=this._start;
+B.push("start is > latestStart");
+}if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
+B.push("start is > earliestEnd");
+}if(this._start>this._end){this._end=this._earliestEnd;
+B.push("start is > end");
+}if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
+B.push("latestStart is > earliestEnd");
+}if(this._latestStart>this._end){this._end=this._earliestEnd;
+B.push("latestStart is > end");
+}if(this._earliestEnd>this._end){this._end=this._earliestEnd;
+B.push("earliestEnd is > end");
+}this._eventID=D("eventID");
+this._text=(A.text!=null)?SimileAjax.HTML.deEntify(A.text):"";
+if(B.length>0){this._text+=" PROBLEM: "+B.join(", ");
+}this._description=SimileAjax.HTML.deEntify(A.description);
+this._image=D("image");
+this._link=D("link");
+this._title=D("hoverText");
+this._title=D("caption");
+this._icon=D("icon");
+this._color=D("color");
+this._textColor=D("textColor");
+this._classname=D("classname");
+this._tapeImage=D("tapeImage");
+this._tapeRepeat=D("tapeRepeat");
+this._trackNum=D("trackNum");
+if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
+}this._wikiURL=null;
+this._wikiSection=null;
+};
+Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
+},isInstant:function(){return this._instant;
+},isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
+},getStart:function(){return this._start;
+},getEnd:function(){return this._end;
+},getLatestStart:function(){return this._latestStart;
+},getEarliestEnd:function(){return this._earliestEnd;
+},getEventID:function(){return this._eventID;
+},getText:function(){return this._text;
+},getDescription:function(){return this._description;
+},getImage:function(){return this._image;
+},getLink:function(){return this._link;
+},getIcon:function(){return this._icon;
+},getColor:function(){return this._color;
+},getTextColor:function(){return this._textColor;
+},getClassName:function(){return this._classname;
+},getTapeImage:function(){return this._tapeImage;
+},getTapeRepeat:function(){return this._tapeRepeat;
+},getTrackNum:function(){return this._trackNum;
+},getProperty:function(A){return null;
+},getWikiURL:function(){return this._wikiURL;
+},getWikiSection:function(){return this._wikiSection;
+},setWikiInfo:function(B,A){this._wikiURL=B;
+this._wikiSection=A;
+},fillDescription:function(A){if(this._description){A.innerHTML=this._description;
+}},fillWikiInfo:function(D){D.style.display="none";
+if(this._wikiURL==null||this._wikiSection==null){return ;
+}var C=this.getProperty("wikiID");
+if(C==null||C.length==0){C=this.getText();
+}if(C==null||C.length==0){return ;
+}D.style.display="inline";
+C=C.replace(/\s/g,"_");
+var B=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+C;
+var A=document.createElement("a");
+A.href=B;
+A.target="new";
+A.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+D.appendChild(document.createTextNode("["));
+D.appendChild(A);
+D.appendChild(document.createTextNode("]"));
+},fillTime:function(A,B){if(this._instant){if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
+A.appendChild(A.ownerDocument.createElement("br"));
+A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
+}else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
+}}else{if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)+" ~ "+B.labelPrecise(this._latestStart)));
+A.appendChild(A.ownerDocument.createElement("br"));
+A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._earliestEnd)+" ~ "+B.labelPrecise(this._end)));
+}else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
+A.appendChild(A.ownerDocument.createElement("br"));
+A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
+}}},fillInfoBubble:function(A,D,K){var L=A.ownerDocument;
+var J=this.getText();
+var H=this.getLink();
+var C=this.getImage();
+if(C!=null){var E=L.createElement("img");
+E.src=C;
+D.event.bubble.imageStyler(E);
+A.appendChild(E);
+}var M=L.createElement("div");
+var B=L.createTextNode(J);
+if(H!=null){var I=L.createElement("a");
+I.href=H;
+I.appendChild(B);
+M.appendChild(I);
+}else{M.appendChild(B);
+}D.event.bubble.titleStyler(M);
+A.appendChild(M);
+var N=L.createElement("div");
+this.fillDescription(N);
+D.event.bubble.bodyStyler(N);
+A.appendChild(N);
+var G=L.createElement("div");
+this.fillTime(G,K);
+D.event.bubble.timeStyler(G);
+A.appendChild(G);
+var F=L.createElement("div");
+this.fillWikiInfo(F);
+D.event.bubble.wikiStyler(F);
+A.appendChild(F);
+}};
+
+
+/* themes.js */
+Timeline.ClassicTheme=new Object();
+Timeline.ClassicTheme.implementations=[];
+Timeline.ClassicTheme.create=function(A){if(A==null){A=Timeline.getDefaultLocale();
+}var B=Timeline.ClassicTheme.implementations[A];
+if(B==null){B=Timeline.ClassicTheme._Impl;
+}return new B();
+};
+Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
+this.autoWidth=false;
+this.autoWidthAnimationTime=500;
+this.timeline_start=null;
+this.timeline_stop=null;
+this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
+this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"images/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(A){A.className="timeline-event-bubble-title";
+},bodyStyler:function(A){A.className="timeline-event-bubble-body";
+},imageStyler:function(A){A.className="timeline-event-bubble-image";
+},wikiStyler:function(A){A.className="timeline-event-bubble-wiki";
+},timeStyler:function(A){A.className="timeline-event-bubble-time";
+}}};
+this.mouseWheel="scroll";
+};
+
+
+/* timeline.js */
+Timeline.version="pre 2.4.0";
+Timeline.ajax_lib_version=SimileAjax.version;
+Timeline.display_version=Timeline.version+" (with Ajax lib "+Timeline.ajax_lib_version+")";
+Timeline.strings={};
+Timeline.HORIZONTAL=0;
+Timeline.VERTICAL=1;
+Timeline._defaultTheme=null;
+Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
+};
+Timeline.create=function(D,C,B,F){if(Timeline.timelines==null){Timeline.timelines=[];
+}var A=Timeline.timelines.length;
+Timeline.timelines[A]=null;
+var E=new Timeline._Impl(D,C,B,F,A);
+Timeline.timelines[A]=E;
+return E;
+};
+Timeline.createBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
+var I=("decorators" in D)?D.decorators:[];
+var B=("eventSource" in D)?D.eventSource:null;
+var F=new Timeline.LinearEther({centersOn:("date" in D)?D.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,theme:E});
+var G=new Timeline.GregorianEtherPainter({unit:D.intervalUnit,multiple:("multiple" in D)?D.multiple:1,theme:E,align:("align" in D)?D.align:undefined});
+var J={showText:("showEventText" in D)?D.showEventText:true,theme:E};
+if("eventPainterParams" in D){for(var A in D.eventPainterParams){J[A]=D.eventPainterParams[A];
+}}if("trackHeight" in D){J.trackHeight=D.trackHeight;
+}if("trackGap" in D){J.trackGap=D.trackGap;
+}var H=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
+var C;
+if("eventPainter" in D){C=new D.eventPainter(J);
+}else{switch(H){case"overview":C=new Timeline.OverviewEventPainter(J);
+break;
+case"detailed":C=new Timeline.DetailedEventPainter(J);
+break;
+default:C=new Timeline.OriginalEventPainter(J);
+}}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:F,etherPainter:G,eventPainter:C,theme:E,decorators:I,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
+};
+Timeline.createHotZoneBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
+var B=("eventSource" in D)?D.eventSource:null;
+var F=new Timeline.HotZoneEther({centersOn:("date" in D)?D.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,zones:D.zones,theme:E});
+var G=new Timeline.HotZoneGregorianEtherPainter({unit:D.intervalUnit,zones:D.zones,theme:E,align:("align" in D)?D.align:undefined});
+var I={showText:("showEventText" in D)?D.showEventText:true,theme:E};
+if("eventPainterParams" in D){for(var A in D.eventPainterParams){I[A]=D.eventPainterParams[A];
+}}if("trackHeight" in D){I.trackHeight=D.trackHeight;
+}if("trackGap" in D){I.trackGap=D.trackGap;
+}var H=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
+var C;
+if("eventPainter" in D){C=new D.eventPainter(I);
+}else{switch(H){case"overview":C=new Timeline.OverviewEventPainter(I);
+break;
+case"detailed":C=new Timeline.DetailedEventPainter(I);
+break;
+default:C=new Timeline.OriginalEventPainter(I);
+}}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:F,etherPainter:G,eventPainter:C,theme:E,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
+};
+Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+}return Timeline._defaultTheme;
+};
+Timeline.setDefaultTheme=function(A){Timeline._defaultTheme=A;
+};
+Timeline.loadXML=function(A,C){var D=function(G,E,F){alert("Failed to load data xml from "+A+"\n"+G);
+};
+var B=function(F){var E=F.responseXML;
+if(!E.documentElement&&F.responseStream){E.load(F.responseStream);
+}C(E,A);
+};
+SimileAjax.XmlHttp.get(A,D,B);
+};
+Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+};
+var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
+};
+SimileAjax.XmlHttp.get(url,fError,fDone);
+};
+Timeline.getTimelineFromID=function(A){return Timeline.timelines[A];
+};
+Timeline.writeVersion=function(A){document.getElementById(A).innerHTML=this.display_version;
+};
+Timeline._Impl=function(D,C,B,E,A){SimileAjax.WindowManager.initialize();
+this._containerDiv=D;
+this._bandInfos=C;
+this._orientation=B==null?Timeline.HORIZONTAL:B;
+this._unit=(E!=null)?E:SimileAjax.NativeDateUnit;
+this._starting=true;
+this._autoResizing=false;
+this.autoWidth=C&&C[0]&&C[0].theme&&C[0].theme.autoWidth;
+this.autoWidthAnimationTime=C&&C[0]&&C[0].theme&&C[0].theme.autoWidthAnimationTime;
+this.timelineID=A;
+this.timeline_start=C&&C[0]&&C[0].theme&&C[0].theme.timeline_start;
+this.timeline_stop=C&&C[0]&&C[0].theme&&C[0].theme.timeline_stop;
+this.timeline_at_start=false;
+this.timeline_at_stop=false;
+this._initialize();
+};
+Timeline._Impl.prototype.dispose=function(){for(var A=0;
+A<this._bands.length;
+A++){this._bands[A].dispose();
+}this._bands=null;
+this._bandInfos=null;
+this._containerDiv.innerHTML="";
+Timeline.timelines[this.timelineID]=null;
+};
+Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
+};
+Timeline._Impl.prototype.getBand=function(A){return this._bands[A];
+};
+Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
+this._starting=false;
+};
+Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
+this._distributeWidths();
+};
+Timeline._Impl.prototype.paint=function(){for(var A=0;
+A<this._bands.length;
+A++){this._bands[A].paint();
+}};
+Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
+};
+Timeline._Impl.prototype.addDiv=function(A){this._containerDiv.appendChild(A);
+};
+Timeline._Impl.prototype.removeDiv=function(A){this._containerDiv.removeChild(A);
+};
+Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
+};
+Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
+};
+Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
+};
+Timeline._Impl.prototype.getUnit=function(){return this._unit;
+};
+Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
+};
+Timeline._Impl.prototype.loadXML=function(B,D){var A=this;
+var E=function(H,F,G){alert("Failed to load data xml from "+B+"\n"+H);
+A.hideLoadingMessage();
+};
+var C=function(G){try{var F=G.responseXML;
+if(!F.documentElement&&G.responseStream){F.load(G.responseStream);
+}D(F,B);
+}finally{A.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(B,E,C);
+},0);
+};
+Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
+var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
+tl.hideLoadingMessage();
+};
+var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
+}finally{tl.hideLoadingMessage();
+}};
+this.showLoadingMessage();
+window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
+},0);
+};
+Timeline._Impl.prototype._autoWidthScrollListener=function(A){A.getTimeline()._autoWidthCheck(false);
+};
+Timeline._Impl.prototype._autoWidthCheck=function(C){var E=this;
+var B=E._starting;
+var D=0;
+function A(){var H=E.getWidthStyle();
+if(B){E._containerDiv.style[H]=D+"px";
+}else{E._autoResizing=true;
+var G={};
+G[H]=D+"px";
+SimileAjax.jQuery(E._containerDiv).animate(G,E.autoWidthAnimationTime,"linear",function(){E._autoResizing=false;
+});
+}}function F(){var I=0;
+var G=E.getPixelWidth();
+if(E._autoResizing){return ;
+}for(var H=0;
+H<E._bands.length;
+H++){E._bands[H].checkAutoWidth();
+I+=E._bandInfos[H].width;
+}if(I>G||C){D=I;
+A();
+E._distributeWidths();
+}}if(!E.autoWidth){return ;
+}F();
+};
+Timeline._Impl.prototype._initialize=function(){var H=this._containerDiv;
+var E=H.ownerDocument;
+H.className=H.className.split(" ").concat("timeline-container").join(" ");
+var B=(this.isHorizontal())?"horizontal":"vertical";
+H.className+=" timeline-"+B;
+while(H.firstChild){H.removeChild(H.firstChild);
+}var A=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"images/copyright-vertical.png":"images/copyright.png"));
+A.className="timeline-copyright";
+A.title="SIMILE Timeline - http://www.simile-widgets.org/";
+SimileAjax.DOM.registerEvent(A,"click",function(){window.location="http://www.simile-widgets.org/";
+});
+H.appendChild(A);
+this._bands=[];
+for(var C=0;
+C<this._bandInfos.length;
+C++){var G=new Timeline._Band(this,this._bandInfos[C],C);
+this._bands.push(G);
+}this._distributeWidths();
+for(var C=0;
+C<this._bandInfos.length;
+C++){var F=this._bandInfos[C];
+if("syncWith" in F){this._bands[C].setSyncWithBand(this._bands[F.syncWith],("highlight" in F)?F.highlight:false);
+}}if(this.autoWidth){for(var C=0;
+C<this._bands.length;
+C++){this._bands[C].addOnScrollListener(this._autoWidthScrollListener);
+}}var D=SimileAjax.Graphics.createMessageBubble(E);
+D.containerDiv.className="timeline-message-container";
+H.appendChild(D.containerDiv);
+D.contentDiv.className="timeline-message";
+D.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"images/progress-running.gif' /> Loading...";
+this.showLoadingMessage=function(){D.containerDiv.style.display="block";
+};
+this.hideLoadingMessage=function(){D.containerDiv.style.display="none";
+};
+};
+Timeline._Impl.prototype._distributeWidths=function(){var B=this.getPixelLength();
+var A=this.getPixelWidth();
+var C=0;
+for(var E=0;
+E<this._bands.length;
+E++){var I=this._bands[E];
+var J=this._bandInfos[E];
+var F=J.width;
+var D;
+if(typeof F=="string"){var H=F.indexOf("%");
+if(H>0){var G=parseInt(F.substr(0,H));
+D=Math.round(G*A/100);
+}else{D=parseInt(F);
+}}else{D=F;
+}I.setBandShiftAndWidth(C,D);
+I.setViewLength(B);
+C+=D;
+}};
+Timeline._Impl.prototype.shiftOK=function(D,B){var C=B>0,A=B<0;
+if((C&&this.timeline_start==null)||(A&&this.timeline_stop==null)||(B==0)){return(true);
+}var G=false;
+for(var F=0;
+F<this._bands.length&&!G;
+F++){G=this._bands[F].busy();
+}if(G){return(true);
+}if((C&&this.timeline_at_start)||(A&&this.timeline_at_stop)){return(false);
+}var E=false;
+for(var F=0;
+F<this._bands.length&&!E;
+F++){var H=this._bands[F];
+if(C){E=(F==D?H.getMinVisibleDateAfterDelta(B):H.getMinVisibleDate())>=this.timeline_start;
+}else{E=(F==D?H.getMaxVisibleDateAfterDelta(B):H.getMaxVisibleDate())<=this.timeline_stop;
+}}if(C){this.timeline_at_start=!E;
+this.timeline_at_stop=false;
+}else{this.timeline_at_stop=!E;
+this.timeline_at_start=false;
+}return(E);
+};
+Timeline._Impl.prototype.zoom=function(G,B,F,D){var C=new RegExp("^timeline-band-([0-9]+)$");
+var E=null;
+var A=C.exec(D.id);
+if(A){E=parseInt(A[1]);
+}if(E!=null){this._bands[E].zoom(G,B,F,D);
+}this.paint();
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Gantt/GanttPrinter.php b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/GanttPrinter.php
new file mode 100644
index 00000000..9b59fdf0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/GanttPrinter.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * SMW result printer for Gantt Diagrams using mermaidjs.
+ * https://github.com/knsv/mermaid
+ *
+ * In order to use this printer you need to have
+ * the Mermaid MediaWiki extension installed.
+ * https://www.mediawiki.org/wiki/Extension:Mermaid
+ *
+ * @file Gantt.php
+ * @ingroup SemanticResultFormats
+ *
+ * @licence GNU GPL v2+
+ * @author Sebastian Schmid
+ */
+
+namespace SRF\Gantt;
+
+use SMWOutputs;
+use SMWQueryResult;
+use SMWResultPrinter;
+use SMWDITime;
+use SMWDIBlob;
+use Html;
+
+class GanttPrinter extends SMWResultPrinter {
+
+ protected $mGantt = null;
+ protected $mErrors = [];
+
+ public function getName() {
+ return wfMessage( 'srf-printername-gantt' )->text();
+ }
+
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params[] = [
+ 'type' => 'string',
+ 'name' => 'diagramtitle',
+ 'message' => 'srf-paramdesc-gantt-diagramtitle',
+ 'default' => ''
+ ];
+
+ $params[] = [
+ 'type' => 'string',
+ 'name' => 'theme',
+ 'message' => 'srf-paramdesc-gantt-diagramtheme',
+ 'default' => 'default'
+ ];
+
+ $params[] = [
+ 'type' => 'string',
+ 'name' => 'axisformat',
+ 'message' => 'srf-paramdesc-gantt-axisformat',
+ 'default' => '%m/%d/%Y'
+ ];
+
+ $params[] = [
+ 'type' => 'string',
+ 'name' => 'statusmapping',
+ 'message' => 'srf-paramdesc-gantt-statusmapping',
+ 'default' => ''
+ ];
+
+ $params[] = [
+ 'type' => 'string',
+ 'name' => 'prioritymapping',
+ 'message' => 'srf-paramdesc-gantt-prioritymapping',
+ 'default' => ''
+ ];
+
+ $params[] = [
+ 'type' => 'integer',
+ 'name' => 'titletopmargin',
+ 'message' => 'srf-paramdesc-gantt-titletopmargin',
+ 'default' => 25
+ ];
+
+ $params[] = [
+ 'type' => 'integer',
+ 'name' => 'barheight',
+ 'message' => 'srf-paramdesc-gantt-barheight',
+ 'default' => 20
+ ];
+
+ $params[] = [
+ 'type' => 'integer',
+ 'name' => 'leftpadding',
+ 'message' => 'srf-paramdesc-gantt-leftpadding',
+ 'default' => 75
+ ];
+
+ $params[] = [
+ 'type' => 'integer',
+ 'name' => 'bargap',
+ 'message' => 'srf-paramdesc-gantt-bargap',
+ 'default' => 4
+ ];
+
+ return $params;
+ }
+
+ /**
+ * Handle (set) the result format parameters
+ *
+ * @see SMWResultPrinter::handleParameters()
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+
+ //Set header params
+ $this->params['title'] = trim( $params['diagramtitle'] );
+ $this->params['axisformat'] = trim( $params['axisformat'] );
+ $this->params['statusmapping'] = $this->getValidatedMapping( $params[ 'statusmapping' ], 'statusmapping', [ 'active', 'done' ] );
+ $this->params['prioritymapping'] = $this->getValidatedMapping( $params[ 'prioritymapping' ], 'prioritymapping', [ 'crit' ] );
+ $this->params['theme'] = $this->getValidatedTheme($params['theme']);
+
+ $this->mGantt = $this->getGantt();
+ }
+
+ /**
+ * Return serialised results in specified format.
+ * @param SMWQueryResult $queryResult
+ * @param $outputmode
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $queryResult, $outputmode ) {
+
+ // Show warning if Extension:Mermaid is not available
+ if ( !class_exists( 'Mermaid' ) && !class_exists( 'Mermaid\\MermaidParserFunction' ) ) {
+ $queryResult->addErrors( [wfMessage('')->text()] );
+ return '';
+ }
+
+ // Load general Modules
+ SMWOutputs::requireResource( 'ext.srf.gantt' );
+
+ //Add Tasks & Sections
+ while ( $row = $queryResult->getNext() ) {
+
+ $status = [];
+ $priority = [];
+ $startDate = '';
+ $endDate = '';
+ $taskID = '';
+ $taskTitle = '';
+ $sections = [];
+
+ // Loop through all field of a row
+ foreach ( $row as $field ) {
+
+ $fieldLabel = $field->getPrintRequest()->getLabel();
+
+ //get values
+ foreach ( $field->getContent() as $dataItem ) {
+
+ switch ( $fieldLabel ) {
+ case 'section':
+ $sections[$dataItem->getTitle()->getPrefixedDBKey()] = $dataItem->getSortKey();
+ break;
+ case 'task':
+ if ( $dataItem instanceof SMWDIBlob ) {
+ $taskTitle = $dataItem->getString();
+ $taskID = $field->getResultSubject()->getTitle()->getPrefixedDBKey();
+ }
+ break;
+ case 'startdate':
+ if ( $dataItem instanceof SMWDITime ) {
+ $startDate = $dataItem->getMwTimestamp();
+ }
+ break;
+ case 'enddate':
+ if ( $dataItem instanceof SMWDITime ) {
+ $endDate = $dataItem->getMwTimestamp();
+ }
+ break;
+ case 'status':
+ if ( $dataItem instanceof SMWDIBlob ) {
+ $status[] = $dataItem->getString();
+ }
+ break;
+ case 'priority':
+ if ( $dataItem instanceof SMWDIBlob ) {
+ $priority[] = $dataItem->getString();
+ }
+ break;
+ }
+ }
+ }
+
+ // Add section/Task
+ // Title, TaskID, StartDate and EndDate are required
+ if ( $taskID !== '' && $taskTitle !== '' && $startDate !== '' && $endDate !== '' ) {
+ $this->mGantt->addTask( $taskID, $taskTitle, $status, $priority, $startDate, $endDate );
+
+ // If no section was found, put task into a dummy section object
+ // "gantt-no-section#21780240" is used to identify Tasks that with no section (dummy section)
+ if ( count( $sections ) == 0 ) {
+ $this->mGantt->addSection( 'gantt-no-section#21780240', '', $startDate, $endDate, $taskID );
+ } else {
+ foreach ( $sections as $sectionID => $sectionTitle ) {
+ $this->mGantt->addSection( $sectionID, $sectionTitle, $startDate, $endDate, $taskID );
+ }
+ }
+ }
+ }
+
+ // Improve unique id by adding a random number
+ $id = uniqid( 'srf-gantt-' . rand( 1, 10000 ) );
+
+ // Add gantt configurations
+ $config = [
+ 'theme' => $this->params['theme'],
+ 'gantt' => [
+ 'leftPadding' => intval( $this->params['leftpadding'] ),
+ 'titleTopMargin' => intval( $this->params['titletopmargin'] ),
+ 'barHeight' => intval( $this->params['barheight'] ),
+ 'barGap' => intval( $this->params['bargap'] )
+ ]
+ ];
+
+
+ // Manage Output
+ if ( !empty( $this->mErrors ) ) {
+ return $queryResult->addErrors( $this->mErrors );
+ } else {
+ return Html::rawElement( 'div', [
+ 'id' => $id,
+ 'class' => 'srf-gantt',
+ 'data-mermaid' => html_entity_decode( json_encode( [
+ 'content' => $this->mGantt->getGanttOutput(),
+ 'config' => $config
+ ]))
+ ], Html::rawElement( 'div', [ 'class' => 'mermaid-dots' ]));
+ }
+ }
+
+ private function getGantt(){
+ return new Gantt( $this->params );
+ }
+
+ /**
+ * Return valid theme as string
+ * @param String $theme
+ *
+ * @return string
+ */
+ private function getValidatedTheme( $theme ) {
+ $theme = trim( $theme );
+
+ if ( !in_array( $this->params['theme'], [ 'default', 'neutral', 'dark', 'forest' ] ) ) {
+ $this->mErrors[] = wfMessage( 'srf-error-gantt-theme' )->text();
+ }
+
+ return $theme;
+ }
+
+
+ private function getValidatedMapping( $params, $mappingType, array $mappingKeys){
+ //Validate mapping
+ $mapping = [];
+
+ if ( !empty( $params ) ) {
+ $paramMapping = explode( ';', trim( $params ) );
+
+ foreach ( $paramMapping as $pm ) {
+ $pmKeyVal = explode( '=>', $pm, 2);
+
+ // if no key value pair
+ if ( count( $pmKeyVal ) !== 2 ) {
+ $this->mErrors[] = wfMessage( 'srf-error-gantt-mapping-assignment', $mappingType )->text();
+ } else {
+ $mapping[trim( $pmKeyVal[0] )] = trim( $pmKeyVal[1] );
+
+ if(!in_array(trim( $pmKeyVal[1] ), $mappingKeys)){
+ $this->mErrors[] = wfMessage( 'srf-error-gantt-mapping-keywords' )->text();
+ }
+ }
+ }
+ return $mapping;
+ }
+ return '';
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Gantt/resources/ext.gantt.js b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/resources/ext.gantt.js
new file mode 100644
index 00000000..77067319
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/resources/ext.gantt.js
@@ -0,0 +1,81 @@
+/*!
+ * @file
+ * @ingroup SMW
+ *
+ * @licence GNU GPL v2+
+ * @author Sebastian Schmid
+ */
+
+( function ($, mw) {
+
+ 'use strict';
+
+ mw.loader.using(['mediawiki.api', 'ext.mermaid']).then(function () {
+
+ $(document).ready(function () {
+
+ $('.srf-gantt').each(function () {
+
+ var id = $(this).attr('id') + '-diagram';
+ var data = $(this).data('mermaid');
+
+ $(this).find('.mermaid-dots').hide();
+ $(this).append('<div id=' + id + '> ' + data.content + ' </div>');
+ mermaid.initialize(data.config);
+ mermaid.init(undefined, $("#" + id));
+
+ // replace <esc>35</esc> with # Tag
+ $(".srf-gantt svg text:contains('<esc>35</esc>')").each(function () {
+ var text = $(this).text().replace('<esc>35</esc>', '#');
+ $(this).text(text);
+ });
+
+ // word wrapping in <text>
+ $('.srf-gantt text.sectionTitle').each(function(index, value){
+ forceTextWrappingOn( this, data.config.gantt.leftPadding);
+ });
+ });
+ });
+ });
+
+ /*
+ * Credits
+ * Project: https://gist.github.com/jkappers/3892971
+ * Author jkappers (Joshua Kappers)
+ */
+ function forceTextWrappingOn(node, width) {
+ var svgns = "http://www.w3.org/2000/svg";
+
+ if(node.firstChild != null){
+ var chars = node.firstChild.nodeValue.split(' '),
+ x = parseInt(node.getAttribute('x'), 10),
+ y = parseInt(node.getAttribute('y'), 10),
+ nodeBB = node.getBBox(),
+ index = 0,
+ tspan, tspanWidth, textNode;
+
+ node.removeChild(node.firstChild);
+
+ for (var c in chars) {
+ if (chars.hasOwnProperty(c)) {
+ tspanWidth = tspan == null ? 0 : tspan.getComputedTextLength();
+ if (tspanWidth > width || tspanWidth === 0) {
+ if(index !== 0){
+ y = y + nodeBB.height;
+ }
+ tspan = document.createElementNS(svgns, 'tspan');
+ tspan.setAttribute('x', x);
+ tspan.setAttribute('y', y);
+ node.appendChild(tspan);
+ index = 0;
+ }
+
+ textNode = document.createTextNode(index === 0 ? chars[c] : " " + chars[c]);
+ tspan.appendChild(textNode);
+ index++;
+ }
+ }
+ }
+ }
+
+}(jQuery, mediaWiki) );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/Gantt.php b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/Gantt.php
new file mode 100644
index 00000000..28e6f95f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/Gantt.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * File holding the Gantt class
+ *
+ * - Add sections and tasks and
+ * manage the relations between them
+ * - Sort elements based on the sortkey
+ * - Creates config for gantt diagram
+ *
+ * @author Sebastian Schmid
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+namespace SRF\Gantt;
+
+class Gantt {
+
+ private $mTitle;
+ private $mAxisFormat;
+ private $mSections = [];
+ private $mTasks = [];
+ private $mPriorityMapping;
+ private $mStatusMapping;
+
+ public function __construct( $headerParam ) {
+ $this->setTitle( $headerParam['title'] );
+ $this->setAxisFormat( $headerParam['axisformat'] );
+ $this->setStatusMapping( $headerParam['statusmapping'] );
+ $this->setPriorityMapping( $headerParam['prioritymapping'] );
+ }
+
+ private function setPriorityMapping( $priorityMapping ) {
+ $this->mPriorityMapping = $priorityMapping;
+ }
+
+ private function getPriorityMapping() {
+ return $this->mPriorityMapping;
+ }
+
+ private function setStatusMapping( $statusMapping ) {
+ $this->mStatusMapping = $statusMapping;
+ }
+
+ private function getStatusMapping() {
+ return $this->mStatusMapping;
+ }
+
+ private function setAxisFormat( $axisFormat ) {
+ $this->mAxisFormat = $axisFormat;
+ }
+
+ private function getAxisFormat() {
+ return $this->mAxisFormat;
+ }
+
+ private function setTitle( $title ) {
+ $this->mTitle = $title;
+ }
+
+ private function getTitle() {
+ return $this->mTitle;
+ }
+
+ private function getSections() {
+ return $this->mSections;
+ }
+
+ private function getTasks() {
+ return $this->mTasks;
+ }
+
+ /**
+ * Adds a new Task to array
+ *
+ * @param string $taskID
+ * @param string $taskTitle
+ * @param array $status
+ * @param array $priority
+ * @param string $startDate
+ * @param string $endDate
+ *
+ */
+
+ public function addTask( $taskID, $taskTitle, $status, $priority, $startDate, $endDate ) {
+ $task = new GanttTask();
+ $task->setID( $taskID );
+ $task->setTitle( $taskTitle );
+ $task->setTaskParam( $status, $this->getStatusMapping(), 'status' );
+ $task->setTaskParam( $priority, $this->getPriorityMapping(), 'priority' );
+ $task->setStartDate( $startDate );
+ $task->setEndDate( $endDate );
+ $this->mTasks[$taskID] = $task;
+ }
+
+
+ /**
+ * Creats a new Section with related tasks
+ *
+ * @param string $sectionID
+ * @param string $sectionTitle
+ * @param string $startDate
+ * @param string $endDate
+ * @param string $taskID
+ *
+ */
+ public function addSection( $sectionID, $sectionTitle, $startDate, $endDate, $taskID ) {
+
+ $sections = $this->getSections();
+
+ if ( array_key_exists( $sectionID, $sections ) ) {
+
+ if ( $sections[$sectionID]->getEarliestStartDate() > $startDate ) {
+ $sections[$sectionID]->setEarliestStartDate( $startDate );
+ }
+ if ( $sections[$sectionID]->getLatestEndDate() < $endDate ) {
+ $sections[$sectionID]->setLatestEndDate( $endDate );
+ }
+ $sections[$sectionID]->addTask( $taskID );
+
+ } else {
+ $this->createNewSection( $sectionID, $sectionTitle, $startDate, $endDate, $taskID );
+ }
+ }
+
+ private function createNewSection( $sectionID, $sectionTitle, $startDate, $endDate, $taskID ) {
+ $ganttSection = new GanttSection();
+ //check if the id in the object is realy needed or is it enough to have it as array key
+ $ganttSection->setID( $sectionID );
+ $ganttSection->setTitle( $sectionTitle );
+ $ganttSection->setEarliestStartDate( $startDate );
+ $ganttSection->setLatestEndDate( $endDate );
+ $ganttSection->addTask( $taskID );
+
+ $this->mSections[$sectionID] = $ganttSection;
+ }
+
+ /**
+ * Creates output for mermaidjs
+ *
+ * @return string
+ */
+ public function getGanttOutput() {
+
+ $sections = $this->getSections();
+ $tasks = $this->getTasks();
+
+ /*
+ * Bring the "section" with no title to the first position.
+ * This "section" is the one that hold tasks without any section.
+ * If we don't display it at the beginning we have to put them into a dummy section
+ */
+ foreach ( $sections as $key => $section ) {
+ if ( $section->getTitle() === '' ) {
+ $noSection = $section;
+ unset( $sections[$key] );
+ }
+ }
+ // push now the dummy task to the first place of the array
+ if ( isset( $noSection ) ) {
+ array_unshift( $sections, $noSection );
+ }
+
+ $title = $this->getTitle();
+ $axisFormat = $this->getAxisFormat();
+
+ $mermaidOut = "gantt\n";
+ $mermaidOut .= "dateFormat YYYY-MM-DD\n";
+ $mermaidOut .= ( !empty( $title ) ) ? "title $title\n" : '';
+ $mermaidOut .= "axisFormat $axisFormat\n";
+
+ // Output section and all related Issues
+ foreach ( $sections as $section ) {
+ if ( $section->getTitle() !== "" ) {
+ $mermaidOut .= 'section ' . $section->getTitle() . "\n";
+ }
+
+ //loop through related section tasks
+ foreach ( $section->getTasks() as $sectionTask ) {
+
+ $status = $tasks[$sectionTask]->getStatus();
+
+ // Get Date from timestamp
+ $date = date_create();
+ date_timestamp_set( $date, $tasks[$sectionTask]->getStartDate() );
+ $startDate = date_format( $date, 'Y-m-d' ) . ', ';
+ date_timestamp_set( $date, $tasks[$sectionTask]->getEndDate() );
+ $endDate = date_format( $date, 'Y-m-d' );
+
+ //get Priority
+ $priority = $tasks[$sectionTask]->getPriority();
+
+ $mermaidOut .= $tasks[$sectionTask]->getTitle() . "\t :" . $priority . $status . $startDate . $endDate .
+ "\n";
+ }
+ }
+
+ //Hashtags mark a Comment in Mermaid, so we need to replace it with <esc>35</esc> to replace it again after rendering
+ $mermaidOut = str_replace( '#', '<esc>35</esc>', $mermaidOut );
+
+ return $mermaidOut;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttSection.php b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttSection.php
new file mode 100644
index 00000000..a7938117
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttSection.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * File holding the GanttSection class
+ *
+ * Creats Section with params
+ *
+ * @author Sebastian Schmid
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+namespace SRF\Gantt;
+
+class GanttSection {
+
+ private $mTitle;
+ private $mID;
+ private $mEarliestStartDate;
+ private $mLatestEndDate;
+ private $mTasks = [];
+
+ public function setTitle( $title ) {
+ $this->mTitle = $title;
+ }
+
+ public function getTitle() {
+ return $this->mTitle;
+ }
+
+ public function setID( $id ) {
+ $this->mID = $id;
+ }
+
+ public function getID() {
+ return $this->mID;
+ }
+
+ public function setEarliestStartDate( $earliestStartDate ) {
+ $this->mEarliestStartDate = $earliestStartDate;
+ }
+
+ public function getEarliestStartDate() {
+ return $this->mEarliestStartDate;
+ }
+
+ public function setLatestEndDate( $latestEndDate ) {
+ $this->mLatestEndDate = $latestEndDate;
+ }
+
+ public function getLatestEndDate() {
+ return $this->mLatestEndDate;
+ }
+
+ public function getTasks() {
+ return $this->mTasks;
+ }
+
+ // If we reorder the tasks we need to reset it with the ordered tasks
+ public function setTasks( $tasks ) {
+ $this->mTasks = $tasks;
+ }
+
+ public function addTask( $task ) {
+ $this->mTasks[] = $task;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttTask.php b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttTask.php
new file mode 100644
index 00000000..964f493a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/Gantt/src/GanttTask.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * File holding the GanttTask class
+ *
+ * Creates Tasks with params
+ *
+ * @author Sebastian Schmid
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+namespace SRF\Gantt;
+
+
+class GanttTask {
+
+ private $mTitle;
+ private $mID;
+ private $mStatus = '';
+ private $mPriority = '';
+ private $mStartDate;
+ private $mEndDate;
+
+
+ public function setTitle( $title ) {
+ $this->mTitle = $title;
+ }
+
+ public function getTitle() {
+ return $this->mTitle;
+ }
+
+ public function setID( $id ) {
+ $this->mID = $id;
+ }
+
+ public function getID() {
+ return $this->mID;
+ }
+
+ public function setStatus($status){
+ $this->mStatus = $this->mStatus . $status . ', ';
+ }
+
+ public function setPriority($priority){
+ $this->mPriority = $this->mPriority . $priority . ', ';
+ }
+
+ /**
+ * Either set the status or priority of the task
+ *
+ * @param array $params
+ * @param string $paramMapping
+ * @param string $type
+ *
+ */
+ public function setTaskParam( $params, $paramMapping, $type ) {
+
+ // skip if $paramMapping is empty and
+ // output errormessage if wrong mapping
+ if ( !empty( $paramMapping ) ) {
+
+ foreach ( $paramMapping as $pKey => $pVal ) {
+ if ( in_array( $pKey, $params ) ) {
+ if ( $type === 'status' ) {
+ $this->setStatus( trim( $pVal ) );
+ }
+ if ( $type === 'priority' ) {
+ $this->setPriority( trim( $pVal ) );
+ }
+ }
+ }
+ }
+ }
+
+ public function getStatus() {
+ return $this->mStatus;
+ }
+
+ public function getPriority() {
+ return $this->mPriority;
+ }
+
+ public function setStartDate( $startDate ) {
+ $this->mStartDate = $startDate;
+ }
+
+ public function getStartDate() {
+ return $this->mStartDate;
+ }
+
+ public function setEndDate( $endDate ) {
+ $this->mEndDate = $endDate;
+ }
+
+ public function getEndDate() {
+ return $this->mEndDate;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/Extras/excanvas.js b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/Extras/excanvas.js
new file mode 100644
index 00000000..92c0418c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/Extras/excanvas.js
@@ -0,0 +1,1415 @@
+// Copyright 2006 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// Known Issues:
+//
+// * Patterns only support repeat.
+// * Radial gradient are not implemented. The VML version of these look very
+// different from the canvas one.
+// * Clipping paths are not implemented.
+// * Coordsize. The width and height attribute have higher priority than the
+// width and height style values which isn't correct.
+// * Painting mode isn't implemented.
+// * Canvas width/height should is using content-box by default. IE in
+// Quirks mode will draw the canvas using border-box. Either change your
+// doctype to HTML5
+// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
+// or use Box Sizing Behavior from WebFX
+// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
+// * Non uniform scaling does not correctly scale strokes.
+// * Optimize. There is always room for speed improvements.
+
+// Only add this code if we do not already have a canvas implementation
+if (!document.createElement('canvas').getContext) {
+
+(function() {
+
+ // alias some functions to make (compiled) code shorter
+ var m = Math;
+ var mr = m.round;
+ var ms = m.sin;
+ var mc = m.cos;
+ var abs = m.abs;
+ var sqrt = m.sqrt;
+
+ // this is used for sub pixel precision
+ var Z = 10;
+ var Z2 = Z / 2;
+
+ var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
+
+ /**
+ * This funtion is assigned to the <canvas> elements as element.getContext().
+ * @this {HTMLElement}
+ * @return {CanvasRenderingContext2D_}
+ */
+ function getContext() {
+ return this.context_ ||
+ (this.context_ = new CanvasRenderingContext2D_(this));
+ }
+
+ var slice = Array.prototype.slice;
+
+ /**
+ * Binds a function to an object. The returned function will always use the
+ * passed in {@code obj} as {@code this}.
+ *
+ * Example:
+ *
+ * g = bind(f, obj, a, b)
+ * g(c, d) // will do f.call(obj, a, b, c, d)
+ *
+ * @param {Function} f The function to bind the object to
+ * @param {Object} obj The object that should act as this when the function
+ * is called
+ * @param {*} var_args Rest arguments that will be used as the initial
+ * arguments when the function is called
+ * @return {Function} A new function that has bound this
+ */
+ function bind(f, obj, var_args) {
+ var a = slice.call(arguments, 2);
+ return function() {
+ return f.apply(obj, a.concat(slice.call(arguments)));
+ };
+ }
+
+ function encodeHtmlAttribute(s) {
+ return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+ }
+
+ function addNamespace(doc, prefix, urn) {
+ if (!doc.namespaces[prefix]) {
+ doc.namespaces.add(prefix, urn, '#default#VML');
+ }
+ }
+
+ function addNamespacesAndStylesheet(doc) {
+ addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
+ addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
+
+ // Setup default CSS. Only add one style sheet per document
+ if (!doc.styleSheets['ex_canvas_']) {
+ var ss = doc.createStyleSheet();
+ ss.owningElement.id = 'ex_canvas_';
+ ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
+ // default size is 300x150 in Gecko and Opera
+ 'text-align:left;width:300px;height:150px}';
+ }
+ }
+
+ // Add namespaces and stylesheet at startup.
+ addNamespacesAndStylesheet(document);
+
+ var G_vmlCanvasManager_ = {
+ init: function(opt_doc) {
+ var doc = opt_doc || document;
+ // Create a dummy element so that IE will allow canvas elements to be
+ // recognized.
+ doc.createElement('canvas');
+ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
+ },
+
+ init_: function(doc) {
+ // find all canvas elements
+ var els = doc.getElementsByTagName('canvas');
+ for (var i = 0; i < els.length; i++) {
+ this.initElement(els[i]);
+ }
+ },
+
+ /**
+ * Public initializes a canvas element so that it can be used as canvas
+ * element from now on. This is called automatically before the page is
+ * loaded but if you are creating elements using createElement you need to
+ * make sure this is called on the element.
+ * @param {HTMLElement} el The canvas element to initialize.
+ * @return {HTMLElement} the element that was created.
+ */
+ initElement: function(el) {
+ if (!el.getContext) {
+ el.getContext = getContext;
+
+ // Add namespaces and stylesheet to document of the element.
+ addNamespacesAndStylesheet(el.ownerDocument);
+
+ // Remove fallback content. There is no way to hide text nodes so we
+ // just remove all childNodes. We could hide all elements and remove
+ // text nodes but who really cares about the fallback content.
+ el.innerHTML = '';
+
+ // do not use inline function because that will leak memory
+ el.attachEvent('onpropertychange', onPropertyChange);
+ el.attachEvent('onresize', onResize);
+
+ var attrs = el.attributes;
+ if (attrs.width && attrs.width.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setWidth_(attrs.width.nodeValue);
+ el.style.width = attrs.width.nodeValue + 'px';
+ } else {
+ el.width = el.clientWidth;
+ }
+ if (attrs.height && attrs.height.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setHeight_(attrs.height.nodeValue);
+ el.style.height = attrs.height.nodeValue + 'px';
+ } else {
+ el.height = el.clientHeight;
+ }
+ //el.getContext().setCoordsize_()
+ }
+ return el;
+ }
+ };
+
+ function onPropertyChange(e) {
+ var el = e.srcElement;
+
+ switch (e.propertyName) {
+ case 'width':
+ el.getContext().clearRect();
+ el.style.width = el.attributes.width.nodeValue + 'px';
+ // In IE8 this does not trigger onresize.
+ el.firstChild.style.width = el.clientWidth + 'px';
+ break;
+ case 'height':
+ el.getContext().clearRect();
+ el.style.height = el.attributes.height.nodeValue + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ break;
+ }
+ }
+
+ function onResize(e) {
+ var el = e.srcElement;
+ if (el.firstChild) {
+ el.firstChild.style.width = el.clientWidth + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ }
+ }
+
+ G_vmlCanvasManager_.init();
+
+ // precompute "00" to "FF"
+ var decToHex = [];
+ for (var i = 0; i < 16; i++) {
+ for (var j = 0; j < 16; j++) {
+ decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
+ }
+ }
+
+ function createMatrixIdentity() {
+ return [
+ [1, 0, 0],
+ [0, 1, 0],
+ [0, 0, 1]
+ ];
+ }
+
+ function matrixMultiply(m1, m2) {
+ var result = createMatrixIdentity();
+
+ for (var x = 0; x < 3; x++) {
+ for (var y = 0; y < 3; y++) {
+ var sum = 0;
+
+ for (var z = 0; z < 3; z++) {
+ sum += m1[x][z] * m2[z][y];
+ }
+
+ result[x][y] = sum;
+ }
+ }
+ return result;
+ }
+
+ function copyState(o1, o2) {
+ o2.fillStyle = o1.fillStyle;
+ o2.lineCap = o1.lineCap;
+ o2.lineJoin = o1.lineJoin;
+ o2.lineWidth = o1.lineWidth;
+ o2.miterLimit = o1.miterLimit;
+ o2.shadowBlur = o1.shadowBlur;
+ o2.shadowColor = o1.shadowColor;
+ o2.shadowOffsetX = o1.shadowOffsetX;
+ o2.shadowOffsetY = o1.shadowOffsetY;
+ o2.strokeStyle = o1.strokeStyle;
+ o2.globalAlpha = o1.globalAlpha;
+ o2.font = o1.font;
+ o2.textAlign = o1.textAlign;
+ o2.textBaseline = o1.textBaseline;
+ o2.arcScaleX_ = o1.arcScaleX_;
+ o2.arcScaleY_ = o1.arcScaleY_;
+ o2.lineScale_ = o1.lineScale_;
+ }
+
+ var colorData = {
+ aliceblue: '#F0F8FF',
+ antiquewhite: '#FAEBD7',
+ aquamarine: '#7FFFD4',
+ azure: '#F0FFFF',
+ beige: '#F5F5DC',
+ bisque: '#FFE4C4',
+ black: '#000000',
+ blanchedalmond: '#FFEBCD',
+ blueviolet: '#8A2BE2',
+ brown: '#A52A2A',
+ burlywood: '#DEB887',
+ cadetblue: '#5F9EA0',
+ chartreuse: '#7FFF00',
+ chocolate: '#D2691E',
+ coral: '#FF7F50',
+ cornflowerblue: '#6495ED',
+ cornsilk: '#FFF8DC',
+ crimson: '#DC143C',
+ cyan: '#00FFFF',
+ darkblue: '#00008B',
+ darkcyan: '#008B8B',
+ darkgoldenrod: '#B8860B',
+ darkgray: '#A9A9A9',
+ darkgreen: '#006400',
+ darkgrey: '#A9A9A9',
+ darkkhaki: '#BDB76B',
+ darkmagenta: '#8B008B',
+ darkolivegreen: '#556B2F',
+ darkorange: '#FF8C00',
+ darkorchid: '#9932CC',
+ darkred: '#8B0000',
+ darksalmon: '#E9967A',
+ darkseagreen: '#8FBC8F',
+ darkslateblue: '#483D8B',
+ darkslategray: '#2F4F4F',
+ darkslategrey: '#2F4F4F',
+ darkturquoise: '#00CED1',
+ darkviolet: '#9400D3',
+ deeppink: '#FF1493',
+ deepskyblue: '#00BFFF',
+ dimgray: '#696969',
+ dimgrey: '#696969',
+ dodgerblue: '#1E90FF',
+ firebrick: '#B22222',
+ floralwhite: '#FFFAF0',
+ forestgreen: '#228B22',
+ gainsboro: '#DCDCDC',
+ ghostwhite: '#F8F8FF',
+ gold: '#FFD700',
+ goldenrod: '#DAA520',
+ grey: '#808080',
+ greenyellow: '#ADFF2F',
+ honeydew: '#F0FFF0',
+ hotpink: '#FF69B4',
+ indianred: '#CD5C5C',
+ indigo: '#4B0082',
+ ivory: '#FFFFF0',
+ khaki: '#F0E68C',
+ lavender: '#E6E6FA',
+ lavenderblush: '#FFF0F5',
+ lawngreen: '#7CFC00',
+ lemonchiffon: '#FFFACD',
+ lightblue: '#ADD8E6',
+ lightcoral: '#F08080',
+ lightcyan: '#E0FFFF',
+ lightgoldenrodyellow: '#FAFAD2',
+ lightgreen: '#90EE90',
+ lightgrey: '#D3D3D3',
+ lightpink: '#FFB6C1',
+ lightsalmon: '#FFA07A',
+ lightseagreen: '#20B2AA',
+ lightskyblue: '#87CEFA',
+ lightslategray: '#778899',
+ lightslategrey: '#778899',
+ lightsteelblue: '#B0C4DE',
+ lightyellow: '#FFFFE0',
+ limegreen: '#32CD32',
+ linen: '#FAF0E6',
+ magenta: '#FF00FF',
+ mediumaquamarine: '#66CDAA',
+ mediumblue: '#0000CD',
+ mediumorchid: '#BA55D3',
+ mediumpurple: '#9370DB',
+ mediumseagreen: '#3CB371',
+ mediumslateblue: '#7B68EE',
+ mediumspringgreen: '#00FA9A',
+ mediumturquoise: '#48D1CC',
+ mediumvioletred: '#C71585',
+ midnightblue: '#191970',
+ mintcream: '#F5FFFA',
+ mistyrose: '#FFE4E1',
+ moccasin: '#FFE4B5',
+ navajowhite: '#FFDEAD',
+ oldlace: '#FDF5E6',
+ olivedrab: '#6B8E23',
+ orange: '#FFA500',
+ orangered: '#FF4500',
+ orchid: '#DA70D6',
+ palegoldenrod: '#EEE8AA',
+ palegreen: '#98FB98',
+ paleturquoise: '#AFEEEE',
+ palevioletred: '#DB7093',
+ papayawhip: '#FFEFD5',
+ peachpuff: '#FFDAB9',
+ peru: '#CD853F',
+ pink: '#FFC0CB',
+ plum: '#DDA0DD',
+ powderblue: '#B0E0E6',
+ rosybrown: '#BC8F8F',
+ royalblue: '#4169E1',
+ saddlebrown: '#8B4513',
+ salmon: '#FA8072',
+ sandybrown: '#F4A460',
+ seagreen: '#2E8B57',
+ seashell: '#FFF5EE',
+ sienna: '#A0522D',
+ skyblue: '#87CEEB',
+ slateblue: '#6A5ACD',
+ slategray: '#708090',
+ slategrey: '#708090',
+ snow: '#FFFAFA',
+ springgreen: '#00FF7F',
+ steelblue: '#4682B4',
+ tan: '#D2B48C',
+ thistle: '#D8BFD8',
+ tomato: '#FF6347',
+ turquoise: '#40E0D0',
+ violet: '#EE82EE',
+ wheat: '#F5DEB3',
+ whitesmoke: '#F5F5F5',
+ yellowgreen: '#9ACD32'
+ };
+
+
+ function getRgbHslContent(styleString) {
+ var start = styleString.indexOf('(', 3);
+ var end = styleString.indexOf(')', start + 1);
+ var parts = styleString.substring(start + 1, end).split(',');
+ // add alpha if needed
+ if (parts.length != 4 || styleString.charAt(3) != 'a') {
+ parts[3] = 1;
+ }
+ return parts;
+ }
+
+ function percent(s) {
+ return parseFloat(s) / 100;
+ }
+
+ function clamp(v, min, max) {
+ return Math.min(max, Math.max(min, v));
+ }
+
+ function hslToRgb(parts){
+ var r, g, b, h, s, l;
+ h = parseFloat(parts[0]) / 360 % 360;
+ if (h < 0)
+ h++;
+ s = clamp(percent(parts[1]), 0, 1);
+ l = clamp(percent(parts[2]), 0, 1);
+ if (s == 0) {
+ r = g = b = l; // achromatic
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hueToRgb(p, q, h + 1 / 3);
+ g = hueToRgb(p, q, h);
+ b = hueToRgb(p, q, h - 1 / 3);
+ }
+
+ return '#' + decToHex[Math.floor(r * 255)] +
+ decToHex[Math.floor(g * 255)] +
+ decToHex[Math.floor(b * 255)];
+ }
+
+ function hueToRgb(m1, m2, h) {
+ if (h < 0)
+ h++;
+ if (h > 1)
+ h--;
+
+ if (6 * h < 1)
+ return m1 + (m2 - m1) * 6 * h;
+ else if (2 * h < 1)
+ return m2;
+ else if (3 * h < 2)
+ return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+ else
+ return m1;
+ }
+
+ var processStyleCache = {};
+
+ function processStyle(styleString) {
+ if (styleString in processStyleCache) {
+ return processStyleCache[styleString];
+ }
+
+ var str, alpha = 1;
+
+ styleString = String(styleString);
+ if (styleString.charAt(0) == '#') {
+ str = styleString;
+ } else if (/^rgb/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ var str = '#', n;
+ for (var i = 0; i < 3; i++) {
+ if (parts[i].indexOf('%') != -1) {
+ n = Math.floor(percent(parts[i]) * 255);
+ } else {
+ n = +parts[i];
+ }
+ str += decToHex[clamp(n, 0, 255)];
+ }
+ alpha = +parts[3];
+ } else if (/^hsl/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ str = hslToRgb(parts);
+ alpha = parts[3];
+ } else {
+ str = colorData[styleString] || styleString;
+ }
+ return processStyleCache[styleString] = {color: str, alpha: alpha};
+ }
+
+ var DEFAULT_STYLE = {
+ style: 'normal',
+ variant: 'normal',
+ weight: 'normal',
+ size: 10,
+ family: 'sans-serif'
+ };
+
+ // Internal text style cache
+ var fontStyleCache = {};
+
+ function processFontStyle(styleString) {
+ if (fontStyleCache[styleString]) {
+ return fontStyleCache[styleString];
+ }
+
+ var el = document.createElement('div');
+ var style = el.style;
+ try {
+ style.font = styleString;
+ } catch (ex) {
+ // Ignore failures to set to invalid font.
+ }
+
+ return fontStyleCache[styleString] = {
+ style: style.fontStyle || DEFAULT_STYLE.style,
+ variant: style.fontVariant || DEFAULT_STYLE.variant,
+ weight: style.fontWeight || DEFAULT_STYLE.weight,
+ size: style.fontSize || DEFAULT_STYLE.size,
+ family: style.fontFamily || DEFAULT_STYLE.family
+ };
+ }
+
+ function getComputedStyle(style, element) {
+ var computedStyle = {};
+
+ for (var p in style) {
+ computedStyle[p] = style[p];
+ }
+
+ // Compute the size
+ var canvasFontSize = parseFloat(element.currentStyle.fontSize),
+ fontSize = parseFloat(style.size);
+
+ if (typeof style.size == 'number') {
+ computedStyle.size = style.size;
+ } else if (style.size.indexOf('px') != -1) {
+ computedStyle.size = fontSize;
+ } else if (style.size.indexOf('em') != -1) {
+ computedStyle.size = canvasFontSize * fontSize;
+ } else if(style.size.indexOf('%') != -1) {
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
+ } else if (style.size.indexOf('pt') != -1) {
+ computedStyle.size = fontSize / .75;
+ } else {
+ computedStyle.size = canvasFontSize;
+ }
+
+ // Different scaling between normal text and VML text. This was found using
+ // trial and error to get the same size as non VML text.
+ computedStyle.size *= 0.981;
+
+ return computedStyle;
+ }
+
+ function buildStyle(style) {
+ return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
+ style.size + 'px ' + style.family;
+ }
+
+ var lineCapMap = {
+ 'butt': 'flat',
+ 'round': 'round'
+ };
+
+ function processLineCap(lineCap) {
+ return lineCapMap[lineCap] || 'square';
+ }
+
+ /**
+ * This class implements CanvasRenderingContext2D interface as described by
+ * the WHATWG.
+ * @param {HTMLElement} canvasElement The element that the 2D context should
+ * be associated with
+ */
+ function CanvasRenderingContext2D_(canvasElement) {
+ this.m_ = createMatrixIdentity();
+
+ this.mStack_ = [];
+ this.aStack_ = [];
+ this.currentPath_ = [];
+
+ // Canvas context properties
+ this.strokeStyle = '#000';
+ this.fillStyle = '#000';
+
+ this.lineWidth = 1;
+ this.lineJoin = 'miter';
+ this.lineCap = 'butt';
+ this.miterLimit = Z * 1;
+ this.globalAlpha = 1;
+ this.font = '10px sans-serif';
+ this.textAlign = 'left';
+ this.textBaseline = 'alphabetic';
+ this.canvas = canvasElement;
+
+ var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
+ canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
+ var el = canvasElement.ownerDocument.createElement('div');
+ el.style.cssText = cssText;
+ canvasElement.appendChild(el);
+
+ var overlayEl = el.cloneNode(false);
+ // Use a non transparent background.
+ overlayEl.style.backgroundColor = 'red';
+ overlayEl.style.filter = 'alpha(opacity=0)';
+ canvasElement.appendChild(overlayEl);
+
+ this.element_ = el;
+ this.arcScaleX_ = 1;
+ this.arcScaleY_ = 1;
+ this.lineScale_ = 1;
+ }
+
+ var contextPrototype = CanvasRenderingContext2D_.prototype;
+ contextPrototype.clearRect = function() {
+ if (this.textMeasureEl_) {
+ this.textMeasureEl_.removeNode(true);
+ this.textMeasureEl_ = null;
+ }
+ this.element_.innerHTML = '';
+ };
+
+ contextPrototype.beginPath = function() {
+ // TODO: Branch current matrix so that save/restore has no effect
+ // as per safari docs.
+ this.currentPath_ = [];
+ };
+
+ contextPrototype.moveTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.lineTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
+
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+ aCP2x, aCP2y,
+ aX, aY) {
+ var p = getCoords(this, aX, aY);
+ var cp1 = getCoords(this, aCP1x, aCP1y);
+ var cp2 = getCoords(this, aCP2x, aCP2y);
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ // Helper function that takes the already fixed cordinates.
+ function bezierCurveTo(self, cp1, cp2, p) {
+ self.currentPath_.push({
+ type: 'bezierCurveTo',
+ cp1x: cp1.x,
+ cp1y: cp1.y,
+ cp2x: cp2.x,
+ cp2y: cp2.y,
+ x: p.x,
+ y: p.y
+ });
+ self.currentX_ = p.x;
+ self.currentY_ = p.y;
+ }
+
+ contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
+ // the following is lifted almost directly from
+ // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
+
+ var cp = getCoords(this, aCPx, aCPy);
+ var p = getCoords(this, aX, aY);
+
+ var cp1 = {
+ x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
+ y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
+ };
+ var cp2 = {
+ x: cp1.x + (p.x - this.currentX_) / 3.0,
+ y: cp1.y + (p.y - this.currentY_) / 3.0
+ };
+
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ contextPrototype.arc = function(aX, aY, aRadius,
+ aStartAngle, aEndAngle, aClockwise) {
+ aRadius *= Z;
+ var arcType = aClockwise ? 'at' : 'wa';
+
+ var xStart = aX + mc(aStartAngle) * aRadius - Z2;
+ var yStart = aY + ms(aStartAngle) * aRadius - Z2;
+
+ var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
+ var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
+
+ // IE won't render arches drawn counter clockwise if xStart == xEnd.
+ if (xStart == xEnd && !aClockwise) {
+ xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
+ // that can be represented in binary
+ }
+
+ var p = getCoords(this, aX, aY);
+ var pStart = getCoords(this, xStart, yStart);
+ var pEnd = getCoords(this, xEnd, yEnd);
+
+ this.currentPath_.push({type: arcType,
+ x: p.x,
+ y: p.y,
+ radius: aRadius,
+ xStart: pStart.x,
+ yStart: pStart.y,
+ xEnd: pEnd.x,
+ yEnd: pEnd.y});
+
+ };
+
+ contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ };
+
+ contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.stroke();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.fill();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+ var gradient = new CanvasGradient_('gradient');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ return gradient;
+ };
+
+ contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
+ aX1, aY1, aR1) {
+ var gradient = new CanvasGradient_('gradientradial');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.r0_ = aR0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ gradient.r1_ = aR1;
+ return gradient;
+ };
+
+ contextPrototype.drawImage = function(image, var_args) {
+ var dx, dy, dw, dh, sx, sy, sw, sh;
+
+ // to find the original width we overide the width and height
+ var oldRuntimeWidth = image.runtimeStyle.width;
+ var oldRuntimeHeight = image.runtimeStyle.height;
+ image.runtimeStyle.width = 'auto';
+ image.runtimeStyle.height = 'auto';
+
+ // get the original size
+ var w = image.width;
+ var h = image.height;
+
+ // and remove overides
+ image.runtimeStyle.width = oldRuntimeWidth;
+ image.runtimeStyle.height = oldRuntimeHeight;
+
+ if (arguments.length == 3) {
+ dx = arguments[1];
+ dy = arguments[2];
+ sx = sy = 0;
+ sw = dw = w;
+ sh = dh = h;
+ } else if (arguments.length == 5) {
+ dx = arguments[1];
+ dy = arguments[2];
+ dw = arguments[3];
+ dh = arguments[4];
+ sx = sy = 0;
+ sw = w;
+ sh = h;
+ } else if (arguments.length == 9) {
+ sx = arguments[1];
+ sy = arguments[2];
+ sw = arguments[3];
+ sh = arguments[4];
+ dx = arguments[5];
+ dy = arguments[6];
+ dw = arguments[7];
+ dh = arguments[8];
+ } else {
+ throw Error('Invalid number of arguments');
+ }
+
+ var d = getCoords(this, dx, dy);
+
+ var w2 = sw / 2;
+ var h2 = sh / 2;
+
+ var vmlStr = [];
+
+ var W = 10;
+ var H = 10;
+
+ // For some reason that I've now forgotten, using divs didn't work
+ vmlStr.push(' <g_vml_:group',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' coordorigin="0,0"' ,
+ ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
+
+ // If filters are necessary (rotation exists), create them
+ // filters are bog-slow, so only create them if abbsolutely necessary
+ // The following check doesn't account for skews (which don't exist
+ // in the canvas spec (yet) anyway.
+
+ if (this.m_[0][0] != 1 || this.m_[0][1] ||
+ this.m_[1][1] != 1 || this.m_[1][0]) {
+ var filter = [];
+
+ // Note the 12/21 reversal
+ filter.push('M11=', this.m_[0][0], ',',
+ 'M12=', this.m_[1][0], ',',
+ 'M21=', this.m_[0][1], ',',
+ 'M22=', this.m_[1][1], ',',
+ 'Dx=', mr(d.x / Z), ',',
+ 'Dy=', mr(d.y / Z), '');
+
+ // Bounding box calculation (need to minimize displayed area so that
+ // filters don't waste time on unused pixels.
+ var max = d;
+ var c2 = getCoords(this, dx + dw, dy);
+ var c3 = getCoords(this, dx, dy + dh);
+ var c4 = getCoords(this, dx + dw, dy + dh);
+
+ max.x = m.max(max.x, c2.x, c3.x, c4.x);
+ max.y = m.max(max.y, c2.y, c3.y, c4.y);
+
+ vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
+ 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
+ filter.join(''), ", sizingmethod='clip');");
+
+ } else {
+ vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
+ }
+
+ vmlStr.push(' ">' ,
+ '<g_vml_:image src="', image.src, '"',
+ ' style="width:', Z * dw, 'px;',
+ ' height:', Z * dh, 'px"',
+ ' cropleft="', sx / w, '"',
+ ' croptop="', sy / h, '"',
+ ' cropright="', (w - sx - sw) / w, '"',
+ ' cropbottom="', (h - sy - sh) / h, '"',
+ ' />',
+ '</g_vml_:group>');
+
+ this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
+ };
+
+ contextPrototype.stroke = function(aFill) {
+ var lineStr = [];
+ var lineOpen = false;
+
+ var W = 10;
+ var H = 10;
+
+ lineStr.push('<g_vml_:shape',
+ ' filled="', !!aFill, '"',
+ ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
+ ' coordorigin="0,0"',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' stroked="', !aFill, '"',
+ ' path="');
+
+ var newSeq = false;
+ var min = {x: null, y: null};
+ var max = {x: null, y: null};
+
+ for (var i = 0; i < this.currentPath_.length; i++) {
+ var p = this.currentPath_[i];
+ var c;
+
+ switch (p.type) {
+ case 'moveTo':
+ c = p;
+ lineStr.push(' m ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'lineTo':
+ lineStr.push(' l ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'close':
+ lineStr.push(' x ');
+ p = null;
+ break;
+ case 'bezierCurveTo':
+ lineStr.push(' c ',
+ mr(p.cp1x), ',', mr(p.cp1y), ',',
+ mr(p.cp2x), ',', mr(p.cp2y), ',',
+ mr(p.x), ',', mr(p.y));
+ break;
+ case 'at':
+ case 'wa':
+ lineStr.push(' ', p.type, ' ',
+ mr(p.x - this.arcScaleX_ * p.radius), ',',
+ mr(p.y - this.arcScaleY_ * p.radius), ' ',
+ mr(p.x + this.arcScaleX_ * p.radius), ',',
+ mr(p.y + this.arcScaleY_ * p.radius), ' ',
+ mr(p.xStart), ',', mr(p.yStart), ' ',
+ mr(p.xEnd), ',', mr(p.yEnd));
+ break;
+ }
+
+
+ // TODO: Following is broken for curves due to
+ // move to proper paths.
+
+ // Figure out dimensions so we can do gradient fills
+ // properly
+ if (p) {
+ if (min.x == null || p.x < min.x) {
+ min.x = p.x;
+ }
+ if (max.x == null || p.x > max.x) {
+ max.x = p.x;
+ }
+ if (min.y == null || p.y < min.y) {
+ min.y = p.y;
+ }
+ if (max.y == null || p.y > max.y) {
+ max.y = p.y;
+ }
+ }
+ }
+ lineStr.push(' ">');
+
+ if (!aFill) {
+ appendStroke(this, lineStr);
+ } else {
+ appendFill(this, lineStr, min, max);
+ }
+
+ lineStr.push('</g_vml_:shape>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ function appendStroke(ctx, lineStr) {
+ var a = processStyle(ctx.strokeStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ var lineWidth = ctx.lineScale_ * ctx.lineWidth;
+
+ // VML cannot correctly render a line if the width is less than 1px.
+ // In that case, we dilute the color to make the line look thinner.
+ if (lineWidth < 1) {
+ opacity *= lineWidth;
+ }
+
+ lineStr.push(
+ '<g_vml_:stroke',
+ ' opacity="', opacity, '"',
+ ' joinstyle="', ctx.lineJoin, '"',
+ ' miterlimit="', ctx.miterLimit, '"',
+ ' endcap="', processLineCap(ctx.lineCap), '"',
+ ' weight="', lineWidth, 'px"',
+ ' color="', color, '" />'
+ );
+ }
+
+ function appendFill(ctx, lineStr, min, max) {
+ var fillStyle = ctx.fillStyle;
+ var arcScaleX = ctx.arcScaleX_;
+ var arcScaleY = ctx.arcScaleY_;
+ var width = max.x - min.x;
+ var height = max.y - min.y;
+ if (fillStyle instanceof CanvasGradient_) {
+ // TODO: Gradients transformed with the transformation matrix.
+ var angle = 0;
+ var focus = {x: 0, y: 0};
+
+ // additional offset
+ var shift = 0;
+ // scale factor for offset
+ var expansion = 1;
+
+ if (fillStyle.type_ == 'gradient') {
+ var x0 = fillStyle.x0_ / arcScaleX;
+ var y0 = fillStyle.y0_ / arcScaleY;
+ var x1 = fillStyle.x1_ / arcScaleX;
+ var y1 = fillStyle.y1_ / arcScaleY;
+ var p0 = getCoords(ctx, x0, y0);
+ var p1 = getCoords(ctx, x1, y1);
+ var dx = p1.x - p0.x;
+ var dy = p1.y - p0.y;
+ angle = Math.atan2(dx, dy) * 180 / Math.PI;
+
+ // The angle should be a non-negative number.
+ if (angle < 0) {
+ angle += 360;
+ }
+
+ // Very small angles produce an unexpected result because they are
+ // converted to a scientific notation string.
+ if (angle < 1e-6) {
+ angle = 0;
+ }
+ } else {
+ var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
+ focus = {
+ x: (p0.x - min.x) / width,
+ y: (p0.y - min.y) / height
+ };
+
+ width /= arcScaleX * Z;
+ height /= arcScaleY * Z;
+ var dimension = m.max(width, height);
+ shift = 2 * fillStyle.r0_ / dimension;
+ expansion = 2 * fillStyle.r1_ / dimension - shift;
+ }
+
+ // We need to sort the color stops in ascending order by offset,
+ // otherwise IE won't interpret it correctly.
+ var stops = fillStyle.colors_;
+ stops.sort(function(cs1, cs2) {
+ return cs1.offset - cs2.offset;
+ });
+
+ var length = stops.length;
+ var color1 = stops[0].color;
+ var color2 = stops[length - 1].color;
+ var opacity1 = stops[0].alpha * ctx.globalAlpha;
+ var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
+
+ var colors = [];
+ for (var i = 0; i < length; i++) {
+ var stop = stops[i];
+ colors.push(stop.offset * expansion + shift + ' ' + stop.color);
+ }
+
+ // When colors attribute is used, the meanings of opacity and o:opacity2
+ // are reversed.
+ lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
+ ' method="none" focus="100%"',
+ ' color="', color1, '"',
+ ' color2="', color2, '"',
+ ' colors="', colors.join(','), '"',
+ ' opacity="', opacity2, '"',
+ ' g_o_:opacity2="', opacity1, '"',
+ ' angle="', angle, '"',
+ ' focusposition="', focus.x, ',', focus.y, '" />');
+ } else if (fillStyle instanceof CanvasPattern_) {
+ if (width && height) {
+ var deltaLeft = -min.x;
+ var deltaTop = -min.y;
+ lineStr.push('<g_vml_:fill',
+ ' position="',
+ deltaLeft / width * arcScaleX * arcScaleX, ',',
+ deltaTop / height * arcScaleY * arcScaleY, '"',
+ ' type="tile"',
+ // TODO: Figure out the correct size to fit the scale.
+ //' size="', w, 'px ', h, 'px"',
+ ' src="', fillStyle.src_, '" />');
+ }
+ } else {
+ var a = processStyle(ctx.fillStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
+ '" />');
+ }
+ }
+
+ contextPrototype.fill = function() {
+ this.stroke(true);
+ };
+
+ contextPrototype.closePath = function() {
+ this.currentPath_.push({type: 'close'});
+ };
+
+ function getCoords(ctx, aX, aY) {
+ var m = ctx.m_;
+ return {
+ x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
+ y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
+ };
+ }
+ contextPrototype.save = function() {
+ var o = {};
+ copyState(this, o);
+ this.aStack_.push(o);
+ this.mStack_.push(this.m_);
+ this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
+ };
+
+ contextPrototype.restore = function() {
+ if (this.aStack_.length) {
+ copyState(this.aStack_.pop(), this);
+ this.m_ = this.mStack_.pop();
+ }
+ };
+
+ function matrixIsFinite(m) {
+ return isFinite(m[0][0]) && isFinite(m[0][1]) &&
+ isFinite(m[1][0]) && isFinite(m[1][1]) &&
+ isFinite(m[2][0]) && isFinite(m[2][1]);
+ }
+
+ function setM(ctx, m, updateLineScale) {
+ if (!matrixIsFinite(m)) {
+ return;
+ }
+ ctx.m_ = m;
+
+ if (updateLineScale) {
+ // Get the line scale.
+ // Determinant of this.m_ means how much the area is enlarged by the
+ // transformation. So its square root can be used as a scale factor
+ // for width.
+ var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
+ ctx.lineScale_ = sqrt(abs(det));
+ }
+ }
+
+ contextPrototype.translate = function(aX, aY) {
+ var m1 = [
+ [1, 0, 0],
+ [0, 1, 0],
+ [aX, aY, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.rotate = function(aRot) {
+ var c = mc(aRot);
+ var s = ms(aRot);
+
+ var m1 = [
+ [c, s, 0],
+ [-s, c, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.scale = function(aX, aY) {
+ this.arcScaleX_ *= aX;
+ this.arcScaleY_ *= aY;
+ var m1 = [
+ [aX, 0, 0],
+ [0, aY, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
+ var m1 = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
+ var m = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, m, true);
+ };
+
+ /**
+ * The text drawing function.
+ * The maxWidth argument isn't taken in account, since no browser supports
+ * it yet.
+ */
+ contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
+ var m = this.m_,
+ delta = 1000,
+ left = 0,
+ right = delta,
+ offset = {x: 0, y: 0},
+ lineStr = [];
+
+ var fontStyle = getComputedStyle(processFontStyle(this.font),
+ this.element_);
+
+ var fontStyleString = buildStyle(fontStyle);
+
+ var elementStyle = this.element_.currentStyle;
+ var textAlign = this.textAlign.toLowerCase();
+ switch (textAlign) {
+ case 'left':
+ case 'center':
+ case 'right':
+ break;
+ case 'end':
+ textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
+ break;
+ case 'start':
+ textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
+ break;
+ default:
+ textAlign = 'left';
+ }
+
+ // 1.75 is an arbitrary number, as there is no info about the text baseline
+ switch (this.textBaseline) {
+ case 'hanging':
+ case 'top':
+ offset.y = fontStyle.size / 1.75;
+ break;
+ case 'middle':
+ break;
+ default:
+ case null:
+ case 'alphabetic':
+ case 'ideographic':
+ case 'bottom':
+ offset.y = -fontStyle.size / 2.25;
+ break;
+ }
+
+ switch(textAlign) {
+ case 'right':
+ left = delta;
+ right = 0.05;
+ break;
+ case 'center':
+ left = right = delta / 2;
+ break;
+ }
+
+ var d = getCoords(this, x + offset.x, y + offset.y);
+
+ lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
+ ' coordsize="100 100" coordorigin="0 0"',
+ ' filled="', !stroke, '" stroked="', !!stroke,
+ '" style="position:absolute;width:1px;height:1px;">');
+
+ if (stroke) {
+ appendStroke(this, lineStr);
+ } else {
+ // TODO: Fix the min and max params.
+ appendFill(this, lineStr, {x: -left, y: 0},
+ {x: right, y: fontStyle.size});
+ }
+
+ var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
+ m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
+
+ var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
+
+ lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
+ ' offset="', skewOffset, '" origin="', left ,' 0" />',
+ '<g_vml_:path textpathok="true" />',
+ '<g_vml_:textpath on="true" string="',
+ encodeHtmlAttribute(text),
+ '" style="v-text-align:', textAlign,
+ ';font:', encodeHtmlAttribute(fontStyleString),
+ '" /></g_vml_:line>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ contextPrototype.fillText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, false);
+ };
+
+ contextPrototype.strokeText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, true);
+ };
+
+ contextPrototype.measureText = function(text) {
+ if (!this.textMeasureEl_) {
+ var s = '<span style="position:absolute;' +
+ 'top:-20000px;left:0;padding:0;margin:0;border:none;' +
+ 'white-space:pre;"></span>';
+ this.element_.insertAdjacentHTML('beforeEnd', s);
+ this.textMeasureEl_ = this.element_.lastChild;
+ }
+ var doc = this.element_.ownerDocument;
+ this.textMeasureEl_.innerHTML = '';
+ this.textMeasureEl_.style.font = this.font;
+ // Don't use innerHTML or innerText because they allow markup/whitespace.
+ this.textMeasureEl_.appendChild(doc.createTextNode(text));
+ return {width: this.textMeasureEl_.offsetWidth};
+ };
+
+ /******** STUBS ********/
+ contextPrototype.clip = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.arcTo = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.createPattern = function(image, repetition) {
+ return new CanvasPattern_(image, repetition);
+ };
+
+ // Gradient / Pattern Stubs
+ function CanvasGradient_(aType) {
+ this.type_ = aType;
+ this.x0_ = 0;
+ this.y0_ = 0;
+ this.r0_ = 0;
+ this.x1_ = 0;
+ this.y1_ = 0;
+ this.r1_ = 0;
+ this.colors_ = [];
+ }
+
+ CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
+ aColor = processStyle(aColor);
+ this.colors_.push({offset: aOffset,
+ color: aColor.color,
+ alpha: aColor.alpha});
+ };
+
+ function CanvasPattern_(image, repetition) {
+ assertImageIsValid(image);
+ switch (repetition) {
+ case 'repeat':
+ case null:
+ case '':
+ this.repetition_ = 'repeat';
+ break
+ case 'repeat-x':
+ case 'repeat-y':
+ case 'no-repeat':
+ this.repetition_ = repetition;
+ break;
+ default:
+ throwException('SYNTAX_ERR');
+ }
+
+ this.src_ = image.src;
+ this.width_ = image.width;
+ this.height_ = image.height;
+ }
+
+ function throwException(s) {
+ throw new DOMException_(s);
+ }
+
+ function assertImageIsValid(img) {
+ if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
+ throwException('TYPE_MISMATCH_ERR');
+ }
+ if (img.readyState != 'complete') {
+ throwException('INVALID_STATE_ERR');
+ }
+ }
+
+ function DOMException_(s) {
+ this.code = this[s];
+ this.message = s +': DOM Exception ' + this.code;
+ }
+ var p = DOMException_.prototype = new Error;
+ p.INDEX_SIZE_ERR = 1;
+ p.DOMSTRING_SIZE_ERR = 2;
+ p.HIERARCHY_REQUEST_ERR = 3;
+ p.WRONG_DOCUMENT_ERR = 4;
+ p.INVALID_CHARACTER_ERR = 5;
+ p.NO_DATA_ALLOWED_ERR = 6;
+ p.NO_MODIFICATION_ALLOWED_ERR = 7;
+ p.NOT_FOUND_ERR = 8;
+ p.NOT_SUPPORTED_ERR = 9;
+ p.INUSE_ATTRIBUTE_ERR = 10;
+ p.INVALID_STATE_ERR = 11;
+ p.SYNTAX_ERR = 12;
+ p.INVALID_MODIFICATION_ERR = 13;
+ p.NAMESPACE_ERR = 14;
+ p.INVALID_ACCESS_ERR = 15;
+ p.VALIDATION_ERR = 16;
+ p.TYPE_MISMATCH_ERR = 17;
+
+ // set up externs
+ G_vmlCanvasManager = G_vmlCanvasManager_;
+ CanvasRenderingContext2D = CanvasRenderingContext2D_;
+ CanvasGradient = CanvasGradient_;
+ CanvasPattern = CanvasPattern_;
+ DOMException = DOMException_;
+})();
+
+} // if \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit-yc.js b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit-yc.js
new file mode 100644
index 00000000..abdcf7a0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit-yc.js
@@ -0,0 +1,23 @@
+/*
+Copyright (c) 2011 Sencha Inc. - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)
+
+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.
+
+ */
+ (function(){window.$jit=function(x){x=x||window;for(var y in $jit){if($jit[y].$extend){x[y]=$jit[y]}}};$jit.version="2.0.1";var c=function(w){return document.getElementById(w)};c.empty=function(){};c.extend=function(y,w){for(var x in (w||{})){y[x]=w[x]}return y};c.lambda=function(w){return(typeof w=="function")?w:function(){return w}};c.time=Date.now||function(){return +new Date};c.splat=function(x){var w=c.type(x);return w?((w!="array")?[x]:x):[]};c.type=function(x){var w=c.type.s.call(x).match(/^\[object\s(.*)\]$/)[1].toLowerCase();if(w!="object"){return w}if(x&&x.$$family){return x.$$family}return(x&&x.nodeName&&x.nodeType==1)?"element":w};c.type.s=Object.prototype.toString;c.each=function(B,A){var z=c.type(B);if(z=="object"){for(var y in B){A(B[y],y)}}else{for(var x=0,w=B.length;x<w;x++){A(B[x],x)}}};c.indexOf=function(z,y){if(Array.indexOf){return z.indexOf(y)}for(var x=0,w=z.length;x<w;x++){if(z[x]===y){return x}}return -1};c.map=function(y,x){var w=[];c.each(y,function(A,z){w.push(x(A,z))});return w};c.reduce=function(A,y,x){var w=A.length;if(w==0){return x}var z=arguments.length==3?x:A[--w];while(w--){z=y(z,A[w])}return z};c.merge=function(){var A={};for(var z=0,w=arguments.length;z<w;z++){var x=arguments[z];if(c.type(x)!="object"){continue}for(var y in x){var C=x[y],B=A[y];A[y]=(B&&c.type(C)=="object"&&c.type(B)=="object")?c.merge(B,C):c.unlink(C)}}return A};c.unlink=function(y){var x;switch(c.type(y)){case"object":x={};for(var A in y){x[A]=c.unlink(y[A])}break;case"array":x=[];for(var z=0,w=y.length;z<w;z++){x[z]=c.unlink(y[z])}break;default:return y}return x};c.zip=function(){if(arguments.length===0){return[]}for(var y=0,x=[],w=arguments.length,B=arguments[0].length;y<B;y++){for(var z=0,A=[];z<w;z++){A.push(arguments[z][y])}x.push(A)}return x};c.rgbToHex=function(A,z){if(A.length<3){return null}if(A.length==4&&A[3]==0&&!z){return"transparent"}var x=[];for(var w=0;w<3;w++){var y=(A[w]-0).toString(16);x.push(y.length==1?"0"+y:y)}return z?x:"#"+x.join("")};c.hexToRgb=function(y){if(y.length!=7){y=y.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);y.shift();if(y.length!=3){return null}var w=[];for(var x=0;x<3;x++){var z=y[x];if(z.length==1){z+=z}w.push(parseInt(z,16))}return w}else{y=parseInt(y.slice(1),16);return[y>>16,y>>8&255,y&255]}};c.destroy=function(w){c.clean(w);if(w.parentNode){w.parentNode.removeChild(w)}if(w.clearAttributes){w.clearAttributes()}};c.clean=function(z){for(var y=z.childNodes,x=0,w=y.length;x<w;x++){c.destroy(y[x])}};c.addEvent=function(y,x,w){if(y.addEventListener){y.addEventListener(x,w,false)}else{y.attachEvent("on"+x,w)}};c.addEvents=function(x,y){for(var w in y){c.addEvent(x,w,y[w])}};c.hasClass=function(x,w){return(" "+x.className+" ").indexOf(" "+w+" ")>-1};c.addClass=function(x,w){if(!c.hasClass(x,w)){x.className=(x.className+" "+w)}};c.removeClass=function(x,w){x.className=x.className.replace(new RegExp("(^|\\s)"+w+"(?:\\s|$)"),"$1")};c.getPos=function(y){var B=A(y);var w=z(y);return{x:B.x-w.x,y:B.y-w.y};function A(D){var C={x:0,y:0};while(D&&!x(D)){C.x+=D.offsetLeft;C.y+=D.offsetTop;D=D.offsetParent}return C}function z(D){var C={x:0,y:0};while(D&&!x(D)){C.x+=D.scrollLeft;C.y+=D.scrollTop;D=D.parentNode}return C}function x(C){return(/^(?:body|html)$/i).test(C.tagName)}};c.event={get:function(x,w){w=w||window;return x||w.event},getWheel:function(w){return w.wheelDelta?w.wheelDelta/120:-(w.detail||0)/3},isRightClick:function(w){return(w.which==3||w.button==2)},getPos:function(z,y){y=y||window;z=z||y.event;var x=y.document;x=x.documentElement||x.body;if(z.touches&&z.touches.length){z=z.touches[0]}var w={x:z.pageX||(z.clientX+x.scrollLeft),y:z.pageY||(z.clientY+x.scrollTop)};return w},stop:function(w){if(w.stopPropagation){w.stopPropagation()}w.cancelBubble=true;if(w.preventDefault){w.preventDefault()}else{w.returnValue=false}}};$jit.util=$jit.id=c;var q=function(x){x=x||{};var w=function(){for(var A in this){if(typeof this[A]!="function"){this[A]=c.unlink(this[A])}}this.constructor=w;if(q.prototyping){return this}var z=this.initialize?this.initialize.apply(this,arguments):this;this.$$family="class";return z};for(var y in q.Mutators){if(!x[y]){continue}x=q.Mutators[y](x,x[y]);delete x[y]}c.extend(w,this);w.constructor=q;w.prototype=x;return w};q.Mutators={Implements:function(w,x){c.each(c.splat(x),function(z){q.prototyping=z;var y=(typeof z=="function")?new z:z;for(var A in y){if(!(A in w)){w[A]=y[A]}}delete q.prototyping});return w}};c.extend(q,{inherit:function(w,z){for(var y in z){var x=z[y];var B=w[y];var A=c.type(x);if(B&&A=="function"){if(x!=B){q.override(w,y,x)}}else{if(A=="object"){w[y]=c.merge(B,x)}else{w[y]=x}}}return w},override:function(x,w,A){var z=q.prototyping;if(z&&x[w]!=z[w]){z=null}var y=function(){var B=this.parent;this.parent=z?z[w]:x[w];var C=A.apply(this,arguments);this.parent=B;return C};x[w]=y}});q.prototype.implement=function(){var w=this.prototype;c.each(Array.prototype.slice.call(arguments||[]),function(x){q.inherit(w,x)});return this};$jit.Class=q;$jit.json={prune:function(x,w){this.each(x,function(z,y){if(y==w&&z.children){delete z.children;z.children=[]}})},getParent:function(w,A){if(w.id==A){return false}var z=w.children;if(z&&z.length>0){for(var y=0;y<z.length;y++){if(z[y].id==A){return w}else{var x=this.getParent(z[y],A);if(x){return x}}}}return false},getSubtree:function(w,A){if(w.id==A){return w}for(var y=0,z=w.children;z&&y<z.length;y++){var x=this.getSubtree(z[y],A);if(x!=null){return x}}return null},eachLevel:function(w,B,y,A){if(B<=y){A(w,B);if(!w.children){return}for(var x=0,z=w.children;x<z.length;x++){this.eachLevel(z[x],B+1,y,A)}}},each:function(w,x){this.eachLevel(w,0,Number.MAX_VALUE,x)}};$jit.Trans={$extend:true,linear:function(w){return w}};var i=$jit.Trans;(function(){var w=function(z,y){y=c.splat(y);return c.extend(z,{easeIn:function(A){return z(A,y)},easeOut:function(A){return 1-z(1-A,y)},easeInOut:function(A){return(A<=0.5)?z(2*A,y)/2:(2-z(2*(1-A),y))/2}})};var x={Pow:function(z,y){return Math.pow(z,y[0]||6)},Expo:function(y){return Math.pow(2,8*(y-1))},Circ:function(y){return 1-Math.sin(Math.acos(y))},Sine:function(y){return 1-Math.sin((1-y)*Math.PI/2)},Back:function(z,y){y=y[0]||1.618;return Math.pow(z,2)*((y+1)*z-y)},Bounce:function(B){var A;for(var z=0,y=1;1;z+=y,y/=2){if(B>=(7-4*z)/11){A=y*y-Math.pow((11-6*z-11*B)/4,2);break}}return A},Elastic:function(z,y){return Math.pow(2,10*--z)*Math.cos(20*z*Math.PI*(y[0]||1)/3)}};c.each(x,function(z,y){i[y]=w(z)});c.each(["Quad","Cubic","Quart","Quint"],function(z,y){i[z]=w(function(A){return Math.pow(A,[y+2])})})})();var u=new q({initialize:function(w){this.setOptions(w)},setOptions:function(w){var x={duration:2500,fps:40,transition:i.Quart.easeInOut,compute:c.empty,complete:c.empty,link:"ignore"};this.opt=c.merge(x,w||{});return this},step:function(){var x=c.time(),w=this.opt;if(x<this.time+w.duration){var y=w.transition((x-this.time)/w.duration);w.compute(y)}else{this.timer=clearInterval(this.timer);w.compute(1);w.complete()}},start:function(){if(!this.check()){return this}this.time=0;this.startTimer();return this},startTimer:function(){var w=this,x=this.opt.fps;if(this.timer){return false}this.time=c.time()-this.time;this.timer=setInterval((function(){w.step()}),Math.round(1000/x));return true},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=c.time()-this.time;this.timer=clearInterval(this.timer);return true},check:function(){if(!this.timer){return true}if(this.opt.link=="cancel"){this.stopTimer();return true}return false}});var n=function(){var y=arguments;for(var A=0,w=y.length,x={};A<w;A++){var z=n[y[A]];if(z.$extend){c.extend(x,z)}else{x[y[A]]=z}}return x};n.AreaChart={$extend:true,animate:true,labelOffset:3,type:"stacked",Tips:{enable:false,onShow:c.empty,onHide:c.empty},Events:{enable:false,onClick:c.empty},selectOnHover:true,showAggregates:true,showLabels:true,filterOnClick:false,restoreOnRightClick:false};n.Margin={$extend:false,top:0,left:0,right:0,bottom:0};n.Canvas={$extend:true,injectInto:"id",type:"2D",width:false,height:false,useCanvas:false,withLabels:true,background:false,Scene:{Lighting:{enable:false,ambient:[1,1,1],directional:{direction:{x:-100,y:-100,z:-100},color:[0.5,0.3,0.1]}}}};n.Tree={$extend:true,orientation:"left",subtreeOffset:8,siblingOffset:5,indent:10,multitree:false,align:"center"};n.Node={$extend:false,overridable:false,type:"circle",color:"#ccb",alpha:1,dim:3,height:20,width:90,autoHeight:false,autoWidth:false,lineWidth:1,transform:true,align:"center",angularWidth:1,span:1,CanvasStyles:{}};n.Edge={$extend:false,overridable:false,type:"line",color:"#ccb",lineWidth:1,dim:15,alpha:1,epsilon:7,CanvasStyles:{}};n.Fx={$extend:true,fps:40,duration:2500,transition:$jit.Trans.Quart.easeInOut,clearCanvas:true};n.Label={$extend:false,overridable:false,type:"HTML",style:" ",size:10,family:"sans-serif",textAlign:"center",textBaseline:"alphabetic",color:"#fff"};n.Tips={$extend:false,enable:false,type:"auto",offsetX:20,offsetY:20,force:false,onShow:c.empty,onHide:c.empty};n.NodeStyles={$extend:false,enable:false,type:"auto",stylesHover:false,stylesClick:false};n.Events={$extend:false,enable:false,enableForEdges:false,type:"auto",onClick:c.empty,onRightClick:c.empty,onMouseMove:c.empty,onMouseEnter:c.empty,onMouseLeave:c.empty,onDragStart:c.empty,onDragMove:c.empty,onDragCancel:c.empty,onDragEnd:c.empty,onTouchStart:c.empty,onTouchMove:c.empty,onTouchEnd:c.empty,onMouseWheel:c.empty};n.Navigation={$extend:false,enable:false,type:"auto",panning:false,zooming:false};n.Controller={$extend:true,onBeforeCompute:c.empty,onAfterCompute:c.empty,onCreateLabel:c.empty,onPlaceLabel:c.empty,onComplete:c.empty,onBeforePlotLine:c.empty,onAfterPlotLine:c.empty,onBeforePlotNode:c.empty,onAfterPlotNode:c.empty,request:false};var t={initialize:function(y,w){this.viz=w;this.canvas=w.canvas;this.config=w.config[y];this.nodeTypes=w.fx.nodeTypes;var x=this.config.type;this.dom=x=="auto"?(w.config.Label.type!="Native"):(x!="Native");this.labelContainer=this.dom&&w.labels.getLabelContainer();this.isEnabled()&&this.initializePost()},initializePost:c.empty,setAsProperty:c.lambda(false),isEnabled:function(){return this.config.enable},isLabel:function(B,A,z){B=c.event.get(B,A);var w=this.labelContainer,y=B.target||B.srcElement,x=B.relatedTarget;if(z){return x&&x==this.viz.canvas.getCtx().canvas&&!!y&&this.isDescendantOf(y,w)}else{return this.isDescendantOf(y,w)}},isDescendantOf:function(x,w){while(x&&x.parentNode){if(x.parentNode==w){return x}x=x.parentNode}return false}};var h={onMouseUp:c.empty,onMouseDown:c.empty,onMouseMove:c.empty,onMouseOver:c.empty,onMouseOut:c.empty,onMouseWheel:c.empty,onTouchStart:c.empty,onTouchMove:c.empty,onTouchEnd:c.empty,onTouchCancel:c.empty};var s=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.node=false;this.edge=false;this.registeredObjects=[];this.attachEvents()},attachEvents:function(){var y=this.canvas.getElement(),x=this;y.oncontextmenu=c.lambda(false);c.addEvents(y,{mouseup:function(B,A){var z=c.event.get(B,A);x.handleEvent("MouseUp",B,A,x.makeEventObject(B,A),c.event.isRightClick(z))},mousedown:function(B,A){var z=c.event.get(B,A);x.handleEvent("MouseDown",B,A,x.makeEventObject(B,A),c.event.isRightClick(z))},mousemove:function(A,z){x.handleEvent("MouseMove",A,z,x.makeEventObject(A,z))},mouseover:function(A,z){x.handleEvent("MouseOver",A,z,x.makeEventObject(A,z))},mouseout:function(A,z){x.handleEvent("MouseOut",A,z,x.makeEventObject(A,z))},touchstart:function(A,z){x.handleEvent("TouchStart",A,z,x.makeEventObject(A,z))},touchmove:function(A,z){x.handleEvent("TouchMove",A,z,x.makeEventObject(A,z))},touchend:function(A,z){x.handleEvent("TouchEnd",A,z,x.makeEventObject(A,z))}});var w=function(C,B){var A=c.event.get(C,B);var z=c.event.getWheel(A);x.handleEvent("MouseWheel",C,B,z)};if(!document.getBoxObjectFor&&window.mozInnerScreenX==null){c.addEvent(y,"mousewheel",w)}else{y.addEventListener("DOMMouseScroll",w,false)}},register:function(w){this.registeredObjects.push(w)},handleEvent:function(){var x=Array.prototype.slice.call(arguments),A=x.shift();for(var z=0,y=this.registeredObjects,w=y.length;z<w;z++){y[z]["on"+A].apply(y[z],x)}},makeEventObject:function(C,B){var z=this,A=this.viz.graph,y=this.viz.fx,x=y.nodeTypes,w=y.edgeTypes;return{pos:false,node:false,edge:false,contains:false,getNodeCalled:false,getEdgeCalled:false,getPos:function(){var F=z.viz.canvas,G=F.getSize(),H=F.getPos(),E=F.translateOffsetX,D=F.translateOffsetY,K=F.scaleOffsetX,I=F.scaleOffsetY,J=c.event.getPos(C,B);this.pos={x:(J.x-H.x-G.width/2-E)*1/K,y:(J.y-H.y-G.height/2-D)*1/I};return this.pos},getNode:function(){if(this.getNodeCalled){return this.node}this.getNodeCalled=true;for(var G in A.nodes){var F=A.nodes[G],E=F&&x[F.getData("type")],D=E&&E.contains&&E.contains.call(y,F,this.getPos());if(D){this.contains=D;return z.node=this.node=F}}return z.node=this.node=false},getEdge:function(){if(this.getEdgeCalled){return this.edge}this.getEdgeCalled=true;var F={};for(var J in A.edges){var H=A.edges[J];F[J]=true;for(var I in H){if(I in F){continue}var G=H[I],E=G&&w[G.getData("type")],D=E&&E.contains&&E.contains.call(y,G,this.getPos());if(D){this.contains=D;return z.edge=this.edge=G}}}return z.edge=this.edge=false},getContains:function(){if(this.getNodeCalled){return this.contains}this.getNode();return this.contains}}}});var o={initializeExtras:function(){var x=new s(this),w=this;c.each(["NodeStyles","Tips","Navigation","Events"],function(y){var z=new o.Classes[y](y,w);if(z.isEnabled()){x.register(z)}if(z.setAsProperty()){w[y.toLowerCase()]=z}})}};o.Classes={};o.Classes.Events=new q({Implements:[t,h],initializePost:function(){this.fx=this.viz.fx;this.ntypes=this.viz.fx.nodeTypes;this.etypes=this.viz.fx.edgeTypes;this.hovered=false;this.pressed=false;this.touched=false;this.touchMoved=false;this.moved=false},setAsProperty:c.lambda(true),onMouseUp:function(A,z,x,y){var w=c.event.get(A,z);if(!this.moved){if(y){this.config.onRightClick(this.hovered,x,w)}else{this.config.onClick(this.pressed,x,w)}}if(this.pressed){if(this.moved){this.config.onDragEnd(this.pressed,x,w)}else{this.config.onDragCancel(this.pressed,x,w)}this.pressed=this.moved=false}},onMouseOut:function(B,A,z){var x=c.event.get(B,A),y;if(this.dom&&(y=this.isLabel(B,A,true))){this.config.onMouseLeave(this.viz.graph.getNode(y.id),z,x);this.hovered=false;return}var w=x.relatedTarget,C=this.canvas.getElement();while(w&&w.parentNode){if(C==w.parentNode){return}w=w.parentNode}if(this.hovered){this.config.onMouseLeave(this.hovered,z,x);this.hovered=false}},onMouseOver:function(A,z,y){var w=c.event.get(A,z),x;if(this.dom&&(x=this.isLabel(A,z,true))){this.hovered=this.viz.graph.getNode(x.id);this.config.onMouseEnter(this.hovered,y,w)}},onMouseMove:function(C,B,A){var x,w=c.event.get(C,B);if(this.pressed){this.moved=true;this.config.onDragMove(this.pressed,A,w);return}if(this.dom){this.config.onMouseMove(this.hovered,A,w)}else{if(this.hovered){var D=this.hovered;var z=D.nodeFrom?this.etypes[D.getData("type")]:this.ntypes[D.getData("type")];var y=z&&z.contains&&z.contains.call(this.fx,D,A.getPos());if(y){this.config.onMouseMove(D,A,w);return}else{this.config.onMouseLeave(D,A,w);this.hovered=false}}if(this.hovered=(A.getNode()||(this.config.enableForEdges&&A.getEdge()))){this.config.onMouseEnter(this.hovered,A,w)}else{this.config.onMouseMove(false,A,w)}}},onMouseWheel:function(x,w,y){this.config.onMouseWheel(y,c.event.get(x,w))},onMouseDown:function(A,z,y){var w=c.event.get(A,z),x;if(this.dom){if(x=this.isLabel(A,z)){this.pressed=this.viz.graph.getNode(x.id)}}else{this.pressed=y.getNode()||(this.config.enableForEdges&&y.getEdge())}this.pressed&&this.config.onDragStart(this.pressed,y,w)},onTouchStart:function(A,z,y){var w=c.event.get(A,z),x;if(this.dom&&(x=this.isLabel(A,z))){this.touched=this.viz.graph.getNode(x.id)}else{this.touched=y.getNode()||(this.config.enableForEdges&&y.getEdge())}this.touched&&this.config.onTouchStart(this.touched,y,w)},onTouchMove:function(z,y,x){var w=c.event.get(z,y);if(this.touched){this.touchMoved=true;this.config.onTouchMove(this.touched,x,w)}},onTouchEnd:function(z,y,x){var w=c.event.get(z,y);if(this.touched){if(this.touchMoved){this.config.onTouchEnd(this.touched,x,w)}else{this.config.onTouchCancel(this.touched,x,w)}this.touched=this.touchMoved=false}}});o.Classes.Tips=new q({Implements:[t,h],initializePost:function(){if(document.body){var w=c("_tooltip")||document.createElement("div");w.id="_tooltip";w.className="tip";c.extend(w.style,{position:"absolute",display:"none",zIndex:13000});document.body.appendChild(w);this.tip=w;this.node=false}},setAsProperty:c.lambda(true),onMouseOut:function(z,y){var x=c.event.get(z,y);if(this.dom&&this.isLabel(z,y,true)){this.hide(true);return}var w=z.relatedTarget,A=this.canvas.getElement();while(w&&w.parentNode){if(A==w.parentNode){return}w=w.parentNode}this.hide(false)},onMouseOver:function(y,x){var w;if(this.dom&&(w=this.isLabel(y,x,false))){this.node=this.viz.graph.getNode(w.id);this.config.onShow(this.tip,this.node,w)}},onMouseMove:function(z,y,w){if(this.dom&&this.isLabel(z,y)){this.setTooltipPosition(c.event.getPos(z,y))}if(!this.dom){var x=w.getNode();if(!x){this.hide(true);return}if(this.config.force||!this.node||this.node.id!=x.id){this.node=x;this.config.onShow(this.tip,x,w.getContains())}this.setTooltipPosition(c.event.getPos(z,y))}},setTooltipPosition:function(F){var B=this.tip,A=B.style,z=this.config;A.display="";var D={height:document.body.clientHeight,width:document.body.clientWidth};var C={width:B.offsetWidth,height:B.offsetHeight};var w=z.offsetX,E=z.offsetY;A.top=((F.y+E+C.height>D.height)?(F.y-C.height-E):F.y+E)+"px";A.left=((F.x+C.width+w>D.width)?(F.x-C.width-w):F.x+w)+"px"},hide:function(w){this.tip.style.display="none";w&&this.config.onHide()}});o.Classes.NodeStyles=new q({Implements:[t,h],initializePost:function(){this.fx=this.viz.fx;this.types=this.viz.fx.nodeTypes;this.nStyles=this.config;this.nodeStylesOnHover=this.nStyles.stylesHover;this.nodeStylesOnClick=this.nStyles.stylesClick;this.hoveredNode=false;this.fx.nodeFxAnimation=new u();this.down=false;this.move=false},onMouseOut:function(y,x){this.down=this.move=false;if(!this.hoveredNode){return}if(this.dom&&this.isLabel(y,x,true)){this.toggleStylesOnHover(this.hoveredNode,false)}var w=y.relatedTarget,z=this.canvas.getElement();while(w&&w.parentNode){if(z==w.parentNode){return}w=w.parentNode}this.toggleStylesOnHover(this.hoveredNode,false);this.hoveredNode=false},onMouseOver:function(z,y){var w;if(this.dom&&(w=this.isLabel(z,y,true))){var x=this.viz.graph.getNode(w.id);if(x.selected){return}this.hoveredNode=x;this.toggleStylesOnHover(this.hoveredNode,true)}},onMouseDown:function(A,z,x,y){if(y){return}var w;if(this.dom&&(w=this.isLabel(A,z))){this.down=this.viz.graph.getNode(w.id)}else{if(!this.dom){this.down=x.getNode()}}this.move=false},onMouseUp:function(z,y,w,x){if(x){return}if(!this.move){this.onClick(w.getNode())}this.down=this.move=false},getRestoredStyles:function(x,w){var z={},y=this["nodeStylesOn"+w];for(var A in y){z[A]=x.styles["$"+A]}return z},toggleStylesOnHover:function(w,x){if(this.nodeStylesOnHover){this.toggleStylesOn("Hover",w,x)}},toggleStylesOnClick:function(w,x){if(this.nodeStylesOnClick){this.toggleStylesOn("Click",w,x)}},toggleStylesOn:function(A,w,C){var D=this.viz;var B=this.nStyles;if(C){var z=this;if(!w.styles){w.styles=c.merge(w.data,{})}for(var E in this["nodeStylesOn"+A]){var x="$"+E;if(!(x in w.styles)){w.styles[x]=w.getData(E)}}D.fx.nodeFx(c.extend({elements:{id:w.id,properties:z["nodeStylesOn"+A]},transition:i.Quart.easeOut,duration:300,fps:40},this.config))}else{var y=this.getRestoredStyles(w,A);D.fx.nodeFx(c.extend({elements:{id:w.id,properties:y},transition:i.Quart.easeOut,duration:300,fps:40},this.config))}},onClick:function(w){if(!w){return}var x=this.nodeStylesOnClick;if(!x){return}if(w.selected){this.toggleStylesOnClick(w,false);delete w.selected}else{this.viz.graph.eachNode(function(z){if(z.selected){for(var y in x){z.setData(y,z.styles["$"+y],"end")}delete z.selected}});this.toggleStylesOnClick(w,true);w.selected=true;delete w.hovered;this.hoveredNode=false}},onMouseMove:function(C,B,z){if(this.down){this.move=true}if(this.dom&&this.isLabel(C,B)){return}var A=this.nodeStylesOnHover;if(!A){return}if(!this.dom){if(this.hoveredNode){var x=this.types[this.hoveredNode.getData("type")];var w=x&&x.contains&&x.contains.call(this.fx,this.hoveredNode,z.getPos());if(w){return}}var y=z.getNode();if(!this.hoveredNode&&!y){return}if(y.hovered){return}if(y&&!y.selected){this.fx.nodeFxAnimation.stopTimer();this.viz.graph.eachNode(function(E){if(E.hovered&&!E.selected){for(var D in A){E.setData(D,E.styles["$"+D],"end")}delete E.hovered}});y.hovered=true;this.hoveredNode=y;this.toggleStylesOnHover(y,true)}else{if(this.hoveredNode&&!this.hoveredNode.selected){this.fx.nodeFxAnimation.stopTimer();this.toggleStylesOnHover(this.hoveredNode,false);delete this.hoveredNode.hovered;this.hoveredNode=false}}}}});o.Classes.Navigation=new q({Implements:[t,h],initializePost:function(){this.pos=false;this.pressed=false},onMouseWheel:function(z,y,w){if(!this.config.zooming){return}c.event.stop(c.event.get(z,y));var A=this.config.zooming/1000,x=1+w*A;this.canvas.scale(x,x)},onMouseDown:function(B,A,z){if(!this.config.panning){return}if(this.config.panning=="avoid nodes"&&(this.dom?this.isLabel(B,A):z.getNode())){return}this.pressed=true;this.pos=z.getPos();var y=this.canvas,x=y.translateOffsetX,w=y.translateOffsetY,D=y.scaleOffsetX,C=y.scaleOffsetY;this.pos.x*=D;this.pos.x+=x;this.pos.y*=C;this.pos.y+=w},onMouseMove:function(D,C,F){if(!this.config.panning){return}if(!this.pressed){return}if(this.config.panning=="avoid nodes"&&(this.dom?this.isLabel(D,C):F.getNode())){return}var B=this.pos,E=F.getPos(),z=this.canvas,A=z.translateOffsetX,w=z.translateOffsetY,J=z.scaleOffsetX,H=z.scaleOffsetY;E.x*=J;E.y*=H;E.x+=A;E.y+=w;var I=E.x-B.x,G=E.y-B.y;this.pos=E;this.canvas.translate(I*1/J,G*1/H)},onMouseUp:function(z,y,x,w){if(!this.config.panning){return}this.pressed=false}});var l;(function(){var w=typeof HTMLCanvasElement,y=(w=="object"||w=="function");function x(z,A){var B=document.createElement(z);for(var C in A){if(typeof A[C]=="object"){c.extend(B[C],A[C])}else{B[C]=A[C]}}if(z=="canvas"&&!y&&G_vmlCanvasManager){B=G_vmlCanvasManager.initElement(document.body.appendChild(B))}return B}$jit.Canvas=l=new q({canvases:[],pos:false,element:false,labelContainer:false,translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(L,E){this.viz=L;this.opt=this.config=E;var B=c.type(E.injectInto)=="string"?E.injectInto:E.injectInto.id,K=E.type,C=B+"-label",z=c(B),D=E.width||z.offsetWidth,M=E.height||z.offsetHeight;this.id=B;var F={injectInto:B,width:D,height:M};this.element=x("div",{id:B+"-canvaswidget",style:{position:"relative",width:D+"px",height:M+"px"}});this.labelContainer=this.createLabelContainer(E.Label.type,C,F);this.canvases.push(new l.Base[K]({config:c.extend({idSuffix:"-canvas"},F),plot:function(N){L.fx.plot()},resize:function(){L.refresh()}}));var G=E.background;if(G){var J=new l.Background[G.type](L,c.extend(G,F));this.canvases.push(new l.Base[K](J))}var I=this.canvases.length;while(I--){this.element.appendChild(this.canvases[I].canvas);if(I>0){this.canvases[I].plot()}}this.element.appendChild(this.labelContainer);z.appendChild(this.element);var A=null,H=this;c.addEvent(window,"scroll",function(){clearTimeout(A);A=setTimeout(function(){H.getPos(true)},500)})},getCtx:function(z){return this.canvases[z||0].getCtx()},getConfig:function(){return this.opt},getElement:function(){return this.element},getSize:function(z){return this.canvases[z||0].getSize()},resize:function(D,z){this.getPos(true);this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;for(var B=0,A=this.canvases.length;B<A;B++){this.canvases[B].resize(D,z)}var C=this.element.style;C.width=D+"px";C.height=z+"px";if(this.labelContainer){this.labelContainer.style.width=D+"px"}},translate:function(z,D,C){this.translateOffsetX+=z*this.scaleOffsetX;this.translateOffsetY+=D*this.scaleOffsetY;for(var B=0,A=this.canvases.length;B<A;B++){this.canvases[B].translate(z,D,C)}},scale:function(E,B,C){var F=this.scaleOffsetX*E,D=this.scaleOffsetY*B;var H=this.translateOffsetX*(E-1)/F,G=this.translateOffsetY*(B-1)/D;this.scaleOffsetX=F;this.scaleOffsetY=D;for(var A=0,z=this.canvases.length;A<z;A++){this.canvases[A].scale(E,B,true)}this.translate(H,G,false)},getPos:function(z){if(z||!this.pos){return this.pos=c.getPos(this.getElement())}return this.pos},clear:function(z){this.canvases[z||0].clear()},path:function(A,B){var z=this.canvases[0].getCtx();z.beginPath();B(z);z[A]();z.closePath()},createLabelContainer:function(B,F,E){var D="http://www.w3.org/2000/svg";if(B=="HTML"||B=="Native"){return x("div",{id:F,style:{overflow:"visible",position:"absolute",top:0,left:0,width:E.width+"px",height:0}})}else{if(B=="SVG"){var C=document.createElementNS(D,"svg:svg");C.setAttribute("width",E.width);C.setAttribute("height",E.height);var A=C.style;A.position="absolute";A.left=A.top="0px";var z=document.createElementNS(D,"svg:g");z.setAttribute("width",E.width);z.setAttribute("height",E.height);z.setAttribute("x",0);z.setAttribute("y",0);z.setAttribute("id",F);C.appendChild(z);return C}}}});l.Base={};l.Base["2D"]=new q({translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(z){this.viz=z;this.opt=z.config;this.size=false;this.createCanvas();this.translateToCenter()},createCanvas:function(){var A=this.opt,B=A.width,z=A.height;this.canvas=x("canvas",{id:A.injectInto+A.idSuffix,width:B,height:z,style:{position:"absolute",top:0,left:0,width:B+"px",height:z+"px"}})},getCtx:function(){if(!this.ctx){return this.ctx=this.canvas.getContext("2d")}return this.ctx},getSize:function(){if(this.size){return this.size}var z=this.canvas;return this.size={width:z.width,height:z.height}},translateToCenter:function(C){var A=this.getSize(),B=C?(A.width-C.width-this.translateOffsetX*2):A.width;height=C?(A.height-C.height-this.translateOffsetY*2):A.height;var z=this.getCtx();C&&z.scale(1/this.scaleOffsetX,1/this.scaleOffsetY);z.translate(B/2,height/2)},resize:function(C,z){var B=this.getSize(),A=this.canvas,D=A.style;this.size=false;A.width=C;A.height=z;D.width=C+"px";D.height=z+"px";if(!y){this.translateToCenter(B)}else{this.translateToCenter()}this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;this.clear();this.viz.resize(C,z,this)},translate:function(z,D,A){var C=this.scaleOffsetX,B=this.scaleOffsetY;this.translateOffsetX+=z*C;this.translateOffsetY+=D*B;this.getCtx().translate(z,D);!A&&this.plot()},scale:function(z,B,A){this.scaleOffsetX*=z;this.scaleOffsetY*=B;this.getCtx().scale(z,B);!A&&this.plot()},clear:function(){var B=this.getSize(),A=this.translateOffsetX,z=this.translateOffsetY,D=this.scaleOffsetX,C=this.scaleOffsetY;this.getCtx().clearRect((-B.width/2-A)*1/D,(-B.height/2-z)*1/C,B.width*1/D,B.height*1/C)},plot:function(){this.clear();this.viz.plot(this)}});l.Background={};l.Background.Circles=new q({initialize:function(z,A){this.viz=z;this.config=c.merge({idSuffix:"-bkcanvas",levelDistance:100,numberOfCircles:6,CanvasStyles:{},offset:0},A)},resize:function(A,z,B){this.plot(B)},plot:function(z){var A=z.canvas,G=z.getCtx(),D=this.config,F=D.CanvasStyles;for(var H in F){G[H]=F[H]}var B=D.numberOfCircles,E=D.levelDistance;for(var C=1;C<=B;C++){G.beginPath();G.arc(0,0,E*C,0,2*Math.PI,false);G.stroke();G.closePath()}}})})();var b=function(x,w){this.theta=x||0;this.rho=w||0};$jit.Polar=b;b.prototype={getc:function(w){return this.toComplex(w)},getp:function(){return this},set:function(w){w=w.getp();this.theta=w.theta;this.rho=w.rho},setc:function(w,z){this.rho=Math.sqrt(w*w+z*z);this.theta=Math.atan2(z,w);if(this.theta<0){this.theta+=Math.PI*2}},setp:function(x,w){this.theta=x;this.rho=w},clone:function(){return new b(this.theta,this.rho)},toComplex:function(A){var w=Math.cos(this.theta)*this.rho;var z=Math.sin(this.theta)*this.rho;if(A){return{x:w,y:z}}return new p(w,z)},add:function(w){return new b(this.theta+w.theta,this.rho+w.rho)},scale:function(w){return new b(this.theta,this.rho*w)},equals:function(w){return this.theta==w.theta&&this.rho==w.rho},$add:function(w){this.theta=this.theta+w.theta;this.rho+=w.rho;return this},$madd:function(w){this.theta=(this.theta+w.theta)%(Math.PI*2);this.rho+=w.rho;return this},$scale:function(w){this.rho*=w;return this},isZero:function(){var x=0.0001,w=Math.abs;return w(this.theta)<x&&w(this.rho)<x},interpolate:function(y,F){var z=Math.PI,C=z*2;var x=function(H){var G=(H<0)?(H%C)+C:H%C;return G};var B=this.theta,E=y.theta;var A,D=Math.abs(B-E);if(D==z){if(B>E){A=x((E+((B-C)-E)*F))}else{A=x((E-C+(B-(E))*F))}}else{if(D>=z){if(B>E){A=x((E+((B-C)-E)*F))}else{A=x((E-C+(B-(E-C))*F))}}else{A=x((E+(B-E)*F))}}var w=(this.rho-y.rho)*F+y.rho;return{theta:A,rho:w}}};var k=function(x,w){return new b(x,w)};b.KER=k(0,0);var p=function(w,z){this.x=w||0;this.y=z||0};$jit.Complex=p;p.prototype={getc:function(){return this},getp:function(w){return this.toPolar(w)},set:function(w){w=w.getc(true);this.x=w.x;this.y=w.y},setc:function(w,z){this.x=w;this.y=z},setp:function(x,w){this.x=Math.cos(x)*w;this.y=Math.sin(x)*w},clone:function(){return new p(this.x,this.y)},toPolar:function(y){var w=this.norm();var x=Math.atan2(this.y,this.x);if(x<0){x+=Math.PI*2}if(y){return{theta:x,rho:w}}return new b(x,w)},norm:function(){return Math.sqrt(this.squaredNorm())},squaredNorm:function(){return this.x*this.x+this.y*this.y},add:function(w){return new p(this.x+w.x,this.y+w.y)},prod:function(w){return new p(this.x*w.x-this.y*w.y,this.y*w.x+this.x*w.y)},conjugate:function(){return new p(this.x,-this.y)},scale:function(w){return new p(this.x*w,this.y*w)},equals:function(w){return this.x==w.x&&this.y==w.y},$add:function(w){this.x+=w.x;this.y+=w.y;return this},$prod:function(A){var w=this.x,z=this.y;this.x=w*A.x-z*A.y;this.y=z*A.x+w*A.y;return this},$conjugate:function(){this.y=-this.y;return this},$scale:function(w){this.x*=w;this.y*=w;return this},$div:function(B){var w=this.x,A=this.y;var z=B.squaredNorm();this.x=w*B.x+A*B.y;this.y=A*B.x-w*B.y;return this.$scale(1/z)},isZero:function(){var x=0.0001,w=Math.abs;return w(this.x)<x&&w(this.y)<x}};var r=function(x,w){return new p(x,w)};p.KER=r(0,0);$jit.Graph=new q({initialize:function(y,x,w,C){var A={klass:p,Node:{}};this.Node=x;this.Edge=w;this.Label=C;this.opt=c.merge(A,y||{});this.nodes={};this.edges={};var z=this;this.nodeList={};for(var B in j){z.nodeList[B]=(function(D){return function(){var E=Array.prototype.slice.call(arguments);z.eachNode(function(F){F[D].apply(F,E)})}})(B)}},getNode:function(w){if(this.hasNode(w)){return this.nodes[w]}return false},get:function(w){return this.getNode(w)},getByName:function(w){for(var y in this.nodes){var x=this.nodes[y];if(x.name==w){return x}}return false},getAdjacence:function(x,w){if(x in this.edges){return this.edges[x][w]}return false},addNode:function(x){if(!this.nodes[x.id]){var w=this.edges[x.id]={};this.nodes[x.id]=new e.Node(c.extend({id:x.id,name:x.name,data:c.merge(x.data||{},{}),adjacencies:w},this.opt.Node),this.opt.klass,this.Node,this.Edge,this.Label)}return this.nodes[x.id]},addAdjacence:function(z,y,x){if(!this.hasNode(z.id)){this.addNode(z)}if(!this.hasNode(y.id)){this.addNode(y)}z=this.nodes[z.id];y=this.nodes[y.id];if(!z.adjacentTo(y)){var A=this.edges[z.id]=this.edges[z.id]||{};var w=this.edges[y.id]=this.edges[y.id]||{};A[y.id]=w[z.id]=new e.Adjacence(z,y,x,this.Edge,this.Label);return A[y.id]}return this.edges[z.id][y.id]},removeNode:function(y){if(this.hasNode(y)){delete this.nodes[y];var x=this.edges[y];for(var w in x){delete this.edges[w][y]}delete this.edges[y]}},removeAdjacence:function(x,w){delete this.edges[x][w];delete this.edges[w][x]},hasNode:function(w){return w in this.nodes},empty:function(){this.nodes={};this.edges={}}});var e=$jit.Graph;var j;(function(){var w=function(D,F,A,C,E){var B;A=A||"current";D="$"+(D?D+"-":"");if(A=="current"){B=this.data}else{if(A=="start"){B=this.startData}else{if(A=="end"){B=this.endData}}}var z=D+F;if(C){return B[z]}if(!this.Config.overridable){return E[F]||0}return(z in B)?B[z]:((z in this.data)?this.data[z]:(E[F]||0))};var y=function(C,D,B,z){z=z||"current";C="$"+(C?C+"-":"");var A;if(z=="current"){A=this.data}else{if(z=="start"){A=this.startData}else{if(z=="end"){A=this.endData}}}A[C+D]=B};var x=function(B,z){B="$"+(B?B+"-":"");var A=this;c.each(z,function(D){var C=B+D;delete A.data[C];delete A.endData[C];delete A.startData[C]})};j={getData:function(B,z,A){return w.call(this,"",B,z,A,this.Config)},setData:function(B,A,z){y.call(this,"",B,A,z)},setDataset:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setData(z,E[B],C[B])}}},removeData:function(){x.call(this,"",Array.prototype.slice.call(arguments))},getCanvasStyle:function(B,z,A){return w.call(this,"canvas",B,z,A,this.Config.CanvasStyles)},setCanvasStyle:function(B,A,z){y.call(this,"canvas",B,A,z)},setCanvasStyles:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setCanvasStyle(z,E[B],C[B])}}},removeCanvasStyle:function(){x.call(this,"canvas",Array.prototype.slice.call(arguments))},getLabelData:function(B,z,A){return w.call(this,"label",B,z,A,this.Label)},setLabelData:function(B,A,z){y.call(this,"label",B,A,z)},setLabelDataset:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setLabelData(z,E[B],C[B])}}},removeLabelData:function(){x.call(this,"label",Array.prototype.slice.call(arguments))}}})();e.Node=new q({initialize:function(z,w,y,x,B){var A={id:"",name:"",data:{},startData:{},endData:{},adjacencies:{},selected:false,drawn:false,exist:false,angleSpan:{begin:0,end:0},pos:new w,startPos:new w,endPos:new w};c.extend(this,c.extend(A,z));this.Config=this.Node=y;this.Edge=x;this.Label=B},adjacentTo:function(w){return w.id in this.adjacencies},getAdjacency:function(w){return this.adjacencies[w]},getPos:function(w){w=w||"current";if(w=="current"){return this.pos}else{if(w=="end"){return this.endPos}else{if(w=="start"){return this.startPos}}}},setPos:function(x,w){w=w||"current";var y;if(w=="current"){y=this.pos}else{if(w=="end"){y=this.endPos}else{if(w=="start"){y=this.startPos}}}y.set(x)}});e.Node.implement(j);e.Adjacence=new q({initialize:function(x,A,y,w,z){this.nodeFrom=x;this.nodeTo=A;this.data=y||{};this.startData={};this.endData={};this.Config=this.Edge=w;this.Label=z}});e.Adjacence.implement(j);e.Util={filter:function(x){if(!x||!(c.type(x)=="string")){return function(){return true}}var w=x.split(" ");return function(z){for(var y=0;y<w.length;y++){if(z[w[y]]){return false}}return true}},getNode:function(w,x){return w.nodes[x]},eachNode:function(A,z,w){var y=this.filter(w);for(var x in A.nodes){if(y(A.nodes[x])){z(A.nodes[x])}}},each:function(y,x,w){this.eachNode(y,x,w)},eachAdjacency:function(B,C,x){var y=B.adjacencies,A=this.filter(x);for(var D in y){var w=y[D];if(A(w)){if(w.nodeFrom!=B){var z=w.nodeFrom;w.nodeFrom=w.nodeTo;w.nodeTo=z}C(w,D)}}},computeLevels:function(C,D,z,y){z=z||0;var A=this.filter(y);this.eachNode(C,function(E){E._flag=false;E._depth=-1},y);var x=C.getNode(D);x._depth=z;var w=[x];while(w.length!=0){var B=w.pop();B._flag=true;this.eachAdjacency(B,function(E){var F=E.nodeTo;if(F._flag==false&&A(F)){if(F._depth<0){F._depth=B._depth+1+z}w.unshift(F)}},y)}},eachBFS:function(B,C,A,x){var y=this.filter(x);this.clean(B);var w=[B.getNode(C)];while(w.length!=0){var z=w.pop();z._flag=true;A(z,z._depth);this.eachAdjacency(z,function(D){var E=D.nodeTo;if(E._flag==false&&y(E)){E._flag=true;w.unshift(E)}},x)}},eachLevel:function(A,E,x,B,z){var D=A._depth,w=this.filter(z),C=this;x=x===false?Number.MAX_VALUE-D:x;(function y(H,F,G){var I=H._depth;if(I>=F&&I<=G&&w(H)){B(H,I)}if(I<G){C.eachAdjacency(H,function(J){var K=J.nodeTo;if(K._depth>I){y(K,F,G)}})}})(A,E+D,x+D)},eachSubgraph:function(x,y,w){this.eachLevel(x,0,false,y,w)},eachSubnode:function(x,y,w){this.eachLevel(x,1,1,y,w)},anySubnode:function(z,y,x){var w=false;y=y||c.lambda(true);var A=c.type(y)=="string"?function(B){return B[y]}:y;this.eachSubnode(z,function(B){if(A(B)){w=true}},x);return w},getSubnodes:function(B,C,w){var y=[],A=this;C=C||0;var z,x;if(c.type(C)=="array"){z=C[0];x=C[1]}else{z=C;x=Number.MAX_VALUE-B._depth}this.eachLevel(B,z,x,function(D){y.push(D)},w);return y},getParents:function(x){var w=[];this.eachAdjacency(x,function(y){var z=y.nodeTo;if(z._depth<x._depth){w.push(z)}});return w},isDescendantOf:function(z,A){if(z.id==A){return true}var y=this.getParents(z),w=false;for(var x=0;!w&&x<y.length;x++){w=w||this.isDescendantOf(y[x],A)}return w},clean:function(w){this.eachNode(w,function(x){x._flag=false})},getClosestNodeToOrigin:function(x,y,w){return this.getClosestNodeToPos(x,b.KER,y,w)},getClosestNodeToPos:function(y,B,A,w){var x=null;A=A||"current";B=B&&B.getc(true)||p.KER;var z=function(D,C){var F=D.x-C.x,E=D.y-C.y;return F*F+E*E};this.eachNode(y,function(C){x=(x==null||z(C.getPos(A).getc(true),B)<z(x.getPos(A).getc(true),B))?C:x},w);return x}};c.each(["get","getNode","each","eachNode","computeLevels","eachBFS","clean","getClosestNodeToPos","getClosestNodeToOrigin"],function(w){e.prototype[w]=function(){return e.Util[w].apply(e.Util,[this].concat(Array.prototype.slice.call(arguments)))}});c.each(["eachAdjacency","eachLevel","eachSubgraph","eachSubnode","anySubnode","getSubnodes","getParents","isDescendantOf"],function(w){e.Node.prototype[w]=function(){return e.Util[w].apply(e.Util,[this].concat(Array.prototype.slice.call(arguments)))}});e.Op={options:{type:"nothing",duration:2000,hideLabels:true,fps:30},initialize:function(w){this.viz=w},removeNode:function(B,z){var w=this.viz;var x=c.merge(this.options,w.controller,z);var D=c.splat(B);var y,A,C;switch(x.type){case"nothing":for(y=0;y<D.length;y++){w.graph.removeNode(D[y])}break;case"replot":this.removeNode(D,{type:"nothing"});w.labels.clearLabels();w.refresh(true);break;case"fade:seq":case"fade":A=this;for(y=0;y<D.length;y++){C=w.graph.getNode(D[y]);C.setData("alpha",0,"end")}w.fx.animate(c.merge(x,{modes:["node-property:alpha"],onComplete:function(){A.removeNode(D,{type:"nothing"});w.labels.clearLabels();w.reposition();w.fx.animate(c.merge(x,{modes:["linear"]}))}}));break;case"fade:con":A=this;for(y=0;y<D.length;y++){C=w.graph.getNode(D[y]);C.setData("alpha",0,"end");C.ignore=true}w.reposition();w.fx.animate(c.merge(x,{modes:["node-property:alpha","linear"],onComplete:function(){A.removeNode(D,{type:"nothing"});x.onComplete&&x.onComplete()}}));break;case"iter":A=this;w.fx.sequence({condition:function(){return D.length!=0},step:function(){A.removeNode(D.shift(),{type:"nothing"});w.labels.clearLabels()},onComplete:function(){x.onComplete&&x.onComplete()},duration:Math.ceil(x.duration/D.length)});break;default:this.doError()}},removeEdge:function(D,B){var w=this.viz;var z=c.merge(this.options,w.controller,B);var y=(c.type(D[0])=="string")?[D]:D;var A,C,x;switch(z.type){case"nothing":for(A=0;A<y.length;A++){w.graph.removeAdjacence(y[A][0],y[A][1])}break;case"replot":this.removeEdge(y,{type:"nothing"});w.refresh(true);break;case"fade:seq":case"fade":C=this;for(A=0;A<y.length;A++){x=w.graph.getAdjacence(y[A][0],y[A][1]);if(x){x.setData("alpha",0,"end")}}w.fx.animate(c.merge(z,{modes:["edge-property:alpha"],onComplete:function(){C.removeEdge(y,{type:"nothing"});w.reposition();w.fx.animate(c.merge(z,{modes:["linear"]}))}}));break;case"fade:con":C=this;for(A=0;A<y.length;A++){x=w.graph.getAdjacence(y[A][0],y[A][1]);if(x){x.setData("alpha",0,"end");x.ignore=true}}w.reposition();w.fx.animate(c.merge(z,{modes:["edge-property:alpha","linear"],onComplete:function(){C.removeEdge(y,{type:"nothing"});z.onComplete&&z.onComplete()}}));break;case"iter":C=this;w.fx.sequence({condition:function(){return y.length!=0},step:function(){C.removeEdge(y.shift(),{type:"nothing"});w.labels.clearLabels()},onComplete:function(){z.onComplete()},duration:Math.ceil(z.duration/y.length)});break;default:this.doError()}},sum:function(A,z){var w=this.viz;var y=c.merge(this.options,w.controller,z),x=w.root;var C;w.root=z.id||w.root;switch(y.type){case"nothing":C=w.construct(A);C.eachNode(function(E){E.eachAdjacency(function(F){w.graph.addAdjacence(F.nodeFrom,F.nodeTo,F.data)})});break;case"replot":w.refresh(true);this.sum(A,{type:"nothing"});w.refresh(true);break;case"fade:seq":case"fade":case"fade:con":that=this;C=w.construct(A);var D=this.preprocessSum(C);var B=!D?["node-property:alpha"]:["node-property:alpha","edge-property:alpha"];w.reposition();if(y.type!="fade:con"){w.fx.animate(c.merge(y,{modes:["linear"],onComplete:function(){w.fx.animate(c.merge(y,{modes:B,onComplete:function(){y.onComplete()}}))}}))}else{w.graph.eachNode(function(E){if(E.id!=x&&E.pos.isZero()){E.pos.set(E.endPos);E.startPos.set(E.endPos)}});w.fx.animate(c.merge(y,{modes:["linear"].concat(B)}))}break;default:this.doError()}},morph:function(E,x,z){z=z||{};var B=this.viz;var F=c.merge(this.options,B.controller,x),A=B.root;var C;B.root=x.id||B.root;switch(F.type){case"nothing":C=B.construct(E);C.eachNode(function(I){var H=B.graph.hasNode(I.id);I.eachAdjacency(function(M){var L=!!B.graph.getAdjacence(M.nodeFrom.id,M.nodeTo.id);B.graph.addAdjacence(M.nodeFrom,M.nodeTo,M.data);if(L){var K=B.graph.getAdjacence(M.nodeFrom.id,M.nodeTo.id);for(var N in (M.data||{})){K.data[N]=M.data[N]}}});if(H){var G=B.graph.getNode(I.id);for(var J in (I.data||{})){G.data[J]=I.data[J]}}});B.graph.eachNode(function(G){G.eachAdjacency(function(H){if(!C.getAdjacence(H.nodeFrom.id,H.nodeTo.id)){B.graph.removeAdjacence(H.nodeFrom.id,H.nodeTo.id)}});if(!C.hasNode(G.id)){B.graph.removeNode(G.id)}});break;case"replot":B.labels.clearLabels(true);this.morph(E,{type:"nothing"});B.refresh(true);B.refresh(true);break;case"fade:seq":case"fade":case"fade:con":that=this;C=B.construct(E);var D=("node-property" in z)&&c.map(c.splat(z["node-property"]),function(G){return"$"+G});B.graph.eachNode(function(H){var I=C.getNode(H.id);if(!I){H.setData("alpha",1);H.setData("alpha",1,"start");H.setData("alpha",0,"end");H.ignore=true}else{var G=I.data;for(var J in G){if(D&&(c.indexOf(D,J)>-1)){H.endData[J]=G[J]}else{H.data[J]=G[J]}}}});B.graph.eachNode(function(G){if(G.ignore){return}G.eachAdjacency(function(H){if(H.nodeFrom.ignore||H.nodeTo.ignore){return}var I=C.getNode(H.nodeFrom.id);var J=C.getNode(H.nodeTo.id);if(!I.adjacentTo(J)){var H=B.graph.getAdjacence(I.id,J.id);w=true;H.setData("alpha",1);H.setData("alpha",1,"start");H.setData("alpha",0,"end")}})});var w=this.preprocessSum(C);var y=!w?["node-property:alpha"]:["node-property:alpha","edge-property:alpha"];y[0]=y[0]+(("node-property" in z)?(":"+c.splat(z["node-property"]).join(":")):"");y[1]=(y[1]||"edge-property:alpha")+(("edge-property" in z)?(":"+c.splat(z["edge-property"]).join(":")):"");if("label-property" in z){y.push("label-property:"+c.splat(z["label-property"]).join(":"))}if(B.reposition){B.reposition()}else{B.compute("end")}B.graph.eachNode(function(G){if(G.id!=A&&G.pos.getp().equals(b.KER)){G.pos.set(G.endPos);G.startPos.set(G.endPos)}});B.fx.animate(c.merge(F,{modes:[z.position||"polar"].concat(y),onComplete:function(){B.graph.eachNode(function(G){if(G.ignore){B.graph.removeNode(G.id)}});B.graph.eachNode(function(G){G.eachAdjacency(function(H){if(H.ignore){B.graph.removeAdjacence(H.nodeFrom.id,H.nodeTo.id)}})});F.onComplete()}}));break;default:}},contract:function(y,x){var w=this.viz;if(y.collapsed||!y.anySubnode(c.lambda(true))){return}x=c.merge(this.options,w.config,x||{},{modes:["node-property:alpha:span","linear"]});y.collapsed=true;(function z(A){A.eachSubnode(function(B){B.ignore=true;B.setData("alpha",0,x.type=="animate"?"end":"current");z(B)})})(y);if(x.type=="animate"){w.compute("end");if(w.rotated){w.rotate(w.rotated,"none",{property:"end"})}(function z(A){A.eachSubnode(function(B){B.setPos(y.getPos("end"),"end");z(B)})})(y);w.fx.animate(x)}else{if(x.type=="replot"){w.refresh()}}},expand:function(y,x){if(!("collapsed" in y)){return}var w=this.viz;x=c.merge(this.options,w.config,x||{},{modes:["node-property:alpha:span","linear"]});delete y.collapsed;(function z(A){A.eachSubnode(function(B){delete B.ignore;B.setData("alpha",1,x.type=="animate"?"end":"current");z(B)})})(y);if(x.type=="animate"){w.compute("end");if(w.rotated){w.rotate(w.rotated,"none",{property:"end"})}w.fx.animate(x)}else{if(x.type=="replot"){w.refresh()}}},preprocessSum:function(x){var w=this.viz;x.eachNode(function(z){if(!w.graph.hasNode(z.id)){w.graph.addNode(z);var A=w.graph.getNode(z.id);A.setData("alpha",0);A.setData("alpha",0,"start");A.setData("alpha",1,"end")}});var y=false;x.eachNode(function(z){z.eachAdjacency(function(A){var B=w.graph.getNode(A.nodeFrom.id);var C=w.graph.getNode(A.nodeTo.id);if(!B.adjacentTo(C)){var A=w.graph.addAdjacence(B,C,A.data);if(B.startAlpha==B.endAlpha&&C.startAlpha==C.endAlpha){y=true;A.setData("alpha",0);A.setData("alpha",0,"start");A.setData("alpha",1,"end")}}})});return y}};var a={none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(z,A,w,y){var x=y.getCtx();x.beginPath();x.arc(A.x,A.y,w,0,Math.PI*2,true);x.closePath();x[z]()},contains:function(B,A,w){var y=B.x-A.x,x=B.y-A.y,z=y*y+x*x;return z<=w*w}},ellipse:{render:function(C,E,w,F,x){var G=x.getCtx(),z=1,y=1,D=1,B=1,A=0;if(w>F){A=w/2;y=F/w;B=w/F}else{A=F/2;z=w/F;D=F/w}G.save();G.scale(z,y);G.beginPath();G.arc(E.x*D,E.y*B,A,0,Math.PI*2,true);G.closePath();G[C]();G.restore()},contains:function(w,D,x,F){var C=0,B=1,A=1,z=0,y=0,E=0;if(x>F){C=x/2;A=F/x}else{C=F/2;B=x/F}z=(w.x-D.x)*(1/B);y=(w.y-D.y)*(1/A);E=z*z+y*y;return E<=C*C}},square:{render:function(x,z,y,w){w.getCtx()[x+"Rect"](z.x-y,z.y-y,2*y,2*y)},contains:function(y,x,w){return Math.abs(x.x-y.x)<=w&&Math.abs(x.y-y.y)<=w}},rectangle:{render:function(z,A,y,w,x){x.getCtx()[z+"Rect"](A.x-y/2,A.y-w/2,y,w)},contains:function(z,y,x,w){return Math.abs(y.x-z.x)<=x/2&&Math.abs(y.y-z.y)<=w/2}},triangle:{render:function(C,D,z,w){var G=w.getCtx(),y=D.x,x=D.y-z,F=y-z,E=D.y+z,B=y+z,A=E;G.beginPath();G.moveTo(y,x);G.lineTo(F,E);G.lineTo(B,A);G.closePath();G[C]()},contains:function(y,x,w){return a.circle.contains(y,x,w)}},star:{render:function(A,C,B,x){var w=x.getCtx(),z=Math.PI/5;w.save();w.translate(C.x,C.y);w.beginPath();w.moveTo(B,0);for(var y=0;y<9;y++){w.rotate(z);if(y%2==0){w.lineTo((B/0.525731)*0.200811,0)}else{w.lineTo(B,0)}}w.closePath();w[A]();w.restore()},contains:function(y,x,w){return a.circle.contains(y,x,w)}}};var m={line:{render:function(z,y,x){var w=x.getCtx();w.beginPath();w.moveTo(z.x,z.y);w.lineTo(y.x,y.y);w.stroke()},contains:function(G,y,B,E){var z=Math.min,C=Math.max,x=z(G.x,y.x),F=C(G.x,y.x),w=z(G.y,y.y),D=C(G.y,y.y);if(B.x>=x&&B.x<=F&&B.y>=w&&B.y<=D){if(Math.abs(y.x-G.x)<=E){return true}var A=(y.y-G.y)/(y.x-G.x)*(B.x-G.x)+G.y;return Math.abs(A-B.y)<=E}return false}},arrow:{render:function(F,G,z,x,w){var H=w.getCtx();if(x){var y=F;F=G;G=y}var C=new p(G.x-F.x,G.y-F.y);C.$scale(z/C.norm());var A=new p(G.x-C.x,G.y-C.y),B=new p(-C.y/2,C.x/2),E=A.add(B),D=A.$add(B.$scale(-1));H.beginPath();H.moveTo(F.x,F.y);H.lineTo(G.x,G.y);H.stroke();H.beginPath();H.moveTo(E.x,E.y);H.lineTo(D.x,D.y);H.lineTo(G.x,G.y);H.closePath();H.fill()},contains:function(x,w,z,y){return m.line.contains(x,w,z,y)}},hyperline:{render:function(D,E,w,y){var F=y.getCtx();var z=A(D,E);if(z.a>1000||z.b>1000||z.ratio<0){F.beginPath();F.moveTo(D.x*w,D.y*w);F.lineTo(E.x*w,E.y*w);F.stroke()}else{var C=Math.atan2(E.y-z.y,E.x-z.x);var B=Math.atan2(D.y-z.y,D.x-z.x);var x=x(C,B);F.beginPath();F.arc(z.x*w,z.y*w,z.ratio*w,C,B,x);F.stroke()}function A(S,R){var K=(S.x*R.y-S.y*R.x),G=K;var J=S.squaredNorm(),I=R.squaredNorm();if(K==0){return{x:0,y:0,ratio:-1}}var Q=(S.y*I-R.y*J+S.y-R.y)/K;var O=(R.x*J-S.x*I+R.x-S.x)/G;var P=-Q/2;var N=-O/2;var M=(Q*Q+O*O)/4-1;if(M<0){return{x:0,y:0,ratio:-1}}var L=Math.sqrt(M);var H={x:P,y:N,ratio:L>1000?-1:L,a:Q,b:O};return H}function x(G,H){return(G<H)?((G+Math.PI>H)?false:true):((H+Math.PI>G)?true:false)}},contains:c.lambda(false)}};e.Plot={initialize:function(x,w){this.viz=x;this.config=x.config;this.node=x.config.Node;this.edge=x.config.Edge;this.animation=new u;this.nodeTypes=new w.Plot.NodeTypes;this.edgeTypes=new w.Plot.EdgeTypes;this.labels=x.labels},nodeHelper:a,edgeHelper:m,Interpolator:{map:{border:"color",color:"color",width:"number",height:"number",dim:"number",alpha:"number",lineWidth:"number",angularWidth:"number",span:"number",valueArray:"array-number",dimArray:"array-number"},canvas:{globalAlpha:"number",fillStyle:"color",strokeStyle:"color",lineWidth:"number",shadowBlur:"number",shadowColor:"color",shadowOffsetX:"number",shadowOffsetY:"number",miterLimit:"number"},label:{size:"number",color:"color"},compute:function(y,x,w){return y+(x-y)*w},moebius:function(D,C,F,z){var B=z.scale(-F);if(B.norm()<1){var w=B.x,E=B.y;var A=D.startPos.getc().moebiusTransformation(B);D.pos.setc(A.x,A.y);B.x=w;B.y=E}},linear:function(x,w,A){var z=x.startPos.getc(true);var y=x.endPos.getc(true);x.pos.setc(this.compute(z.x,y.x,A),this.compute(z.y,y.y,A))},polar:function(y,x,B){var A=y.startPos.getp(true);var z=y.endPos.getp();var w=z.interpolate(A,B);y.pos.setp(w.theta,w.rho)},number:function(x,C,B,w,A){var z=x[w](C,"start");var y=x[w](C,"end");x[A](C,this.compute(z,y,B))},color:function(y,w,E,B,z){var C=c.hexToRgb(y[B](w,"start"));var D=c.hexToRgb(y[B](w,"end"));var A=this.compute;var x=c.rgbToHex([parseInt(A(C[0],D[0],E)),parseInt(A(C[1],D[1],E)),parseInt(A(C[2],D[2],E))]);y[z](w,x)},"array-number":function(z,y,J,G,B){var H=z[G](y,"start"),I=z[G](y,"end"),K=[];for(var E=0,A=H.length;E<A;E++){var x=H[E],w=I[E];if(x.length){for(var D=0,F=x.length,C=[];D<F;D++){C.push(this.compute(x[D],w[D],J))}K.push(C)}else{K.push(this.compute(x,w,J))}}z[B](y,K)},node:function(x,C,E,w,D,y){w=this[w];if(C){var B=C.length;for(var z=0;z<B;z++){var A=C[z];this[w[A]](x,A,E,D,y)}}else{for(var A in w){this[w[A]](x,A,E,D,y)}}},edge:function(y,x,D,z,w,C){var B=y.adjacencies;for(var A in B){this["node"](B[A],x,D,z,w,C)}},"node-property":function(x,w,y){this["node"](x,w,y,"map","getData","setData")},"edge-property":function(x,w,y){this["edge"](x,w,y,"map","getData","setData")},"label-property":function(x,w,y){this["node"](x,w,y,"label","getLabelData","setLabelData")},"node-style":function(x,w,y){this["node"](x,w,y,"canvas","getCanvasStyle","setCanvasStyle")},"edge-style":function(x,w,y){this["edge"](x,w,y,"canvas","getCanvasStyle","setCanvasStyle")}},sequence:function(x){var y=this;x=c.merge({condition:c.lambda(false),step:c.empty,onComplete:c.empty,duration:200},x||{});var w=setInterval(function(){if(x.condition()){x.step()}else{clearInterval(w);x.onComplete()}y.viz.refresh(true)},x.duration)},prepare:function(C){var B=this.viz.graph,z={"node-property":{getter:"getData",setter:"setData"},"edge-property":{getter:"getData",setter:"setData"},"node-style":{getter:"getCanvasStyle",setter:"setCanvasStyle"},"edge-style":{getter:"getCanvasStyle",setter:"setCanvasStyle"}};var x={};if(c.type(C)=="array"){for(var A=0,w=C.length;A<w;A++){var y=C[A].split(":");x[y.shift()]=y}}else{for(var D in C){if(D=="position"){x[C.position]=[]}else{x[D]=c.splat(C[D])}}}B.eachNode(function(E){E.startPos.set(E.pos);c.each(["node-property","node-style"],function(H){if(H in x){var I=x[H];for(var G=0,F=I.length;G<F;G++){E[z[H].setter](I[G],E[z[H].getter](I[G]),"start")}}});c.each(["edge-property","edge-style"],function(F){if(F in x){var G=x[F];E.eachAdjacency(function(I){for(var J=0,H=G.length;J<H;J++){I[z[F].setter](G[J],I[z[F].getter](G[J]),"start")}})}})});return x},animate:function(z,y){z=c.merge(this.viz.config,z||{});var A=this,x=this.viz,C=x.graph,D=this.Interpolator,B=z.type==="nodefx"?this.nodeFxAnimation:this.animation;var w=this.prepare(z.modes);if(z.hideLabels){this.labels.hideLabels(true)}B.setOptions(c.extend(z,{$animating:false,compute:function(E){C.eachNode(function(F){for(var G in w){D[G](F,w[G],E,y)}});A.plot(z,this.$animating,E);this.$animating=true},complete:function(){if(z.hideLabels){A.labels.hideLabels(false)}A.plot(z);z.onComplete()}})).start()},nodeFx:function(y){var D=this.viz,E=D.graph,B=this.nodeFxAnimation,F=c.merge(this.viz.config,{elements:{id:false,properties:{}},reposition:false});y=c.merge(F,y||{},{onBeforeCompute:c.empty,onAfterCompute:c.empty});B.stopTimer();var C=y.elements.properties;if(!y.elements.id){E.eachNode(function(H){for(var G in C){H.setData(G,C[G],"end")}})}else{var w=c.splat(y.elements.id);c.each(w,function(I){var H=E.getNode(I);if(H){for(var G in C){H.setData(G,C[G],"end")}}})}var A=[];for(var x in C){A.push(x)}var z=["node-property:"+A.join(":")];if(y.reposition){z.push("linear");D.compute("end")}this.animate(c.merge(y,{modes:z,type:"nodefx"}))},plot:function(x,G){var E=this.viz,B=E.graph,y=E.canvas,w=E.root,C=this,F=y.getCtx(),A=Math.min,x=x||this.viz.controller;x.clearCanvas&&y.clear();var D=B.getNode(w);if(!D){return}var z=!!D.visited;B.eachNode(function(I){var H=I.getData("alpha");I.eachAdjacency(function(J){var K=J.nodeTo;if(!!K.visited===z&&I.drawn&&K.drawn){!G&&x.onBeforePlotLine(J);C.plotLine(J,y,G);!G&&x.onAfterPlotLine(J)}});if(I.drawn){!G&&x.onBeforePlotNode(I);C.plotNode(I,y,G);!G&&x.onAfterPlotNode(I)}if(!C.labelsHidden&&x.withLabels){if(I.drawn&&H>=0.95){C.labels.plotLabel(y,I,x)}else{C.labels.hideLabel(I,false)}}I.visited=!z})},plotTree:function(A,x,E){var B=this,C=this.viz,y=C.canvas,z=this.config,D=y.getCtx();var w=A.getData("alpha");A.eachSubnode(function(G){if(x.plotSubtree(A,G)&&G.exist&&G.drawn){var F=A.getAdjacency(G.id);!E&&x.onBeforePlotLine(F);B.plotLine(F,y,E);!E&&x.onAfterPlotLine(F);B.plotTree(G,x,E)}});if(A.drawn){!E&&x.onBeforePlotNode(A);this.plotNode(A,y,E);!E&&x.onAfterPlotNode(A);if(!x.hideLabels&&x.withLabels&&w>=0.95){this.labels.plotLabel(y,A,x)}else{this.labels.hideLabel(A,false)}}else{this.labels.hideLabel(A,true)}},plotNode:function(y,x,F){var C=y.getData("type"),B=this.node.CanvasStyles;if(C!="none"){var w=y.getData("lineWidth"),A=y.getData("color"),z=y.getData("alpha"),D=x.getCtx();D.save();D.lineWidth=w;D.fillStyle=D.strokeStyle=A;D.globalAlpha=z;for(var E in B){D[E]=y.getCanvasStyle(E)}this.nodeTypes[C].render.call(this,y,x,F);D.restore()}},plotLine:function(C,x,G){var B=C.getData("type"),z=this.edge.CanvasStyles;if(B!="none"){var w=C.getData("lineWidth"),y=C.getData("color"),E=x.getCtx(),A=C.nodeFrom,D=C.nodeTo;E.save();E.lineWidth=w;E.fillStyle=E.strokeStyle=y;E.globalAlpha=Math.min(A.getData("alpha"),D.getData("alpha"),C.getData("alpha"));for(var F in z){E[F]=C.getCanvasStyle(F)}this.edgeTypes[B].render.call(this,C,x,G);E.restore()}}};e.Plot3D=c.merge(e.Plot,{Interpolator:{linear:function(x,w,A){var z=x.startPos.getc(true);var y=x.endPos.getc(true);x.pos.setc(this.compute(z.x,y.x,A),this.compute(z.y,y.y,A),this.compute(z.z,y.z,A))}},plotNode:function(x,w){if(x.getData("type")=="none"){return}this.plotElement(x,w,{getAlpha:function(){return x.getData("alpha")}})},plotLine:function(w,x){if(w.getData("type")=="none"){return}this.plotElement(w,x,{getAlpha:function(){return Math.min(w.nodeFrom.getData("alpha"),w.nodeTo.getData("alpha"),w.getData("alpha"))}})},plotElement:function(Y,E,z){var V=E.getCtx(),F=new Matrix4,x=E.config.Scene.Lighting,Z=E.canvases[0],K=Z.program,X=Z.camera;if(!Y.geometry){Y.geometry=new O3D[Y.getData("type")]}Y.geometry.update(Y);if(!Y.webGLVertexBuffer){var J=[],B=[],P=[],N=0,S=Y.geometry;for(var W=0,U=S.vertices,H=S.faces,G=H.length;W<G;W++){var M=H[W],D=U[M.a],C=U[M.b],A=U[M.c],y=M.d?U[M.d]:false,R=M.normal;J.push(D.x,D.y,D.z);J.push(C.x,C.y,C.z);J.push(A.x,A.y,A.z);if(y){J.push(y.x,y.y,y.z)}P.push(R.x,R.y,R.z);P.push(R.x,R.y,R.z);P.push(R.x,R.y,R.z);if(y){P.push(R.x,R.y,R.z)}B.push(N,N+1,N+2);if(y){B.push(N,N+2,N+3);N+=4}else{N+=3}}Y.webGLVertexBuffer=V.createBuffer();V.bindBuffer(V.ARRAY_BUFFER,Y.webGLVertexBuffer);V.bufferData(V.ARRAY_BUFFER,new Float32Array(J),V.STATIC_DRAW);Y.webGLFaceBuffer=V.createBuffer();V.bindBuffer(V.ELEMENT_ARRAY_BUFFER,Y.webGLFaceBuffer);V.bufferData(V.ELEMENT_ARRAY_BUFFER,new Uint16Array(B),V.STATIC_DRAW);Y.webGLFaceCount=B.length;Y.webGLNormalBuffer=V.createBuffer();V.bindBuffer(V.ARRAY_BUFFER,Y.webGLNormalBuffer);V.bufferData(V.ARRAY_BUFFER,new Float32Array(P),V.STATIC_DRAW)}F.multiply(X.matrix,Y.geometry.matrix);V.uniformMatrix4fv(K.viewMatrix,false,F.flatten());V.uniformMatrix4fv(K.projectionMatrix,false,X.projectionMatrix.flatten());var L=Matrix4.makeInvert(F);L.$transpose();V.uniformMatrix4fv(K.normalMatrix,false,L.flatten());var T=c.hexToRgb(Y.getData("color"));T.push(z.getAlpha());V.uniform4f(K.color,T[0]/255,T[1]/255,T[2]/255,T[3]);V.uniform1i(K.enableLighting,x.enable);if(x.enable){if(x.ambient){var O=x.ambient;V.uniform3f(K.ambientColor,O[0],O[1],O[2])}if(x.directional){var Q=x.directional,T=Q.color,I=Q.direction,w=new Vector3(I.x,I.y,I.z).normalize().$scale(-1);V.uniform3f(K.lightingDirection,w.x,w.y,w.z);V.uniform3f(K.directionalColor,T[0],T[1],T[2])}}V.bindBuffer(V.ARRAY_BUFFER,Y.webGLVertexBuffer);V.vertexAttribPointer(K.position,3,V.FLOAT,false,0,0);V.bindBuffer(V.ARRAY_BUFFER,Y.webGLNormalBuffer);V.vertexAttribPointer(K.normal,3,V.FLOAT,false,0,0);V.bindBuffer(V.ELEMENT_ARRAY_BUFFER,Y.webGLFaceBuffer);V.drawElements(V.TRIANGLES,Y.webGLFaceCount,V.UNSIGNED_SHORT,0)}});e.Label={};e.Label.Native=new q({initialize:function(w){this.viz=w},plotLabel:function(y,z,x){var w=y.getCtx();var A=z.pos.getc(true);w.font=z.getLabelData("style")+" "+z.getLabelData("size")+"px "+z.getLabelData("family");w.textAlign=z.getLabelData("textAlign");w.fillStyle=w.strokeStyle=z.getLabelData("color");w.textBaseline=z.getLabelData("textBaseline");this.renderLabel(y,z,x)},renderLabel:function(y,z,x){var w=y.getCtx();var A=z.pos.getc(true);w.fillText(z.name,A.x,A.y+z.getData("height")/2)},hideLabel:c.empty,hideLabels:c.empty});e.Label.DOM=new q({labelsHidden:false,labelContainer:false,labels:{},getLabelContainer:function(){return this.labelContainer?this.labelContainer:this.labelContainer=document.getElementById(this.viz.config.labelContainer)},getLabel:function(w){return(w in this.labels&&this.labels[w]!=null)?this.labels[w]:this.labels[w]=document.getElementById(w)},hideLabels:function(x){var w=this.getLabelContainer();if(x){w.style.display="none"}else{w.style.display=""}this.labelsHidden=x},clearLabels:function(w){for(var x in this.labels){if(w||!this.viz.graph.hasNode(x)){this.disposeLabel(x);delete this.labels[x]}}},disposeLabel:function(x){var w=this.getLabel(x);if(w&&w.parentNode){w.parentNode.removeChild(w)}},hideLabel:function(A,w){A=c.splat(A);var x=w?"":"none",y,z=this;c.each(A,function(C){var B=z.getLabel(C.id);if(B){B.style.display=x}})},fitsInCanvas:function(y,w){var x=w.getSize();if(y.x>=x.width||y.x<0||y.y>=x.height||y.y<0){return false}return true}});e.Label.HTML=new q({Implements:e.Label.DOM,plotLabel:function(z,A,y){var B=A.id,w=this.getLabel(B);if(!w&&!(w=document.getElementById(B))){w=document.createElement("div");var x=this.getLabelContainer();w.id=B;w.className="node";w.style.position="absolute";y.onCreateLabel(w,A);x.appendChild(w);this.labels[A.id]=w}this.placeLabel(w,A,y)}});e.Label.SVG=new q({Implements:e.Label.DOM,plotLabel:function(z,B,y){var D=B.id,w=this.getLabel(D);if(!w&&!(w=document.getElementById(D))){var A="http://www.w3.org/2000/svg";w=document.createElementNS(A,"svg:text");var C=document.createElementNS(A,"svg:tspan");w.appendChild(C);var x=this.getLabelContainer();w.setAttribute("id",D);w.setAttribute("class","node");x.appendChild(w);y.onCreateLabel(w,B);this.labels[B.id]=w}this.placeLabel(w,B,y)}});e.Geom=new q({initialize:function(w){this.viz=w;this.config=w.config;this.node=w.config.Node;this.edge=w.config.Edge},translate:function(x,w){w=c.splat(w);this.viz.graph.eachNode(function(y){c.each(w,function(z){y.getPos(z).$add(x)})})},setRightLevelToShow:function(z,w,B){var A=this.getRightLevelToShow(z,w),y=this.viz.labels,x=c.merge({execShow:true,execHide:true,onHide:c.empty,onShow:c.empty},B||{});z.eachLevel(0,this.config.levelsToShow,function(D){var C=D._depth-z._depth;if(C>A){x.onHide(D);if(x.execHide){D.drawn=false;D.exist=false;y.hideLabel(D,false)}}else{x.onShow(D);if(x.execShow){D.exist=true}}});z.drawn=true},getRightLevelToShow:function(z,x){var w=this.config;var A=w.levelsToShow;var y=w.constrained;if(!y){return A}while(!this.treeFitsInCanvas(z,x,A)&&A>1){A--}return A}});var d={construct:function(x){var y=(c.type(x)=="array");var w=new e(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);if(!y){(function(z,B){z.addNode(B);if(B.children){for(var A=0,C=B.children;A<C.length;A++){z.addAdjacence(B,C[A]);arguments.callee(z,C[A])}}})(w,x)}else{(function(H,I){var A=function(M){for(var L=0,J=I.length;L<J;L++){if(I[L].id==M){return I[L]}}var K={id:M,name:M};return H.addNode(K)};for(var E=0,B=I.length;E<B;E++){H.addNode(I[E]);var F=I[E].adjacencies;if(F){for(var C=0,G=F.length;C<G;C++){var z=F[C],D={};if(typeof F[C]!="string"){D=c.merge(z.data,{});z=z.nodeTo}H.addAdjacence(I[E],A(z),D)}}}})(w,x)}return w},loadJSON:function(x,w){this.json=x;if(this.labels&&this.labels.clearLabels){this.labels.clearLabels(true)}this.graph=this.construct(x);if(c.type(x)!="array"){this.root=x.id}else{this.root=x[w?w:0].id}},toJSON:function(A){A=A||"tree";if(A=="tree"){var y={};var x=this.graph.getNode(this.root);var y=(function w(D){var B={};B.id=D.id;B.name=D.name;B.data=D.data;var C=[];D.eachSubnode(function(E){C.push(w(E))});B.children=C;return B})(x);return y}else{var y=[];var z=!!this.graph.getNode(this.root).visited;this.graph.eachNode(function(C){var B={};B.id=C.id;B.name=C.name;B.data=C.data;var D=[];C.eachAdjacency(function(E){var G=E.nodeTo;if(!!G.visited===z){var F={};F.nodeTo=G.id;F.data=E.data;D.push(F)}});B.adjacencies=D;y.push(B);C.visited=!z});return y}}};var g=$jit.Layouts={};var f={label:null,compute:function(z,A,x){this.initializeLabel(x);var w=this.label,y=w.style;z.eachNode(function(D){var H=D.getData("autoWidth"),I=D.getData("autoHeight");if(H||I){delete D.data.$width;delete D.data.$height;delete D.data.$dim;var B=D.getData("width"),J=D.getData("height");y.width=H?"auto":B+"px";y.height=I?"auto":J+"px";w.innerHTML=D.name;var F=w.offsetWidth,C=w.offsetHeight;var G=D.getData("type");if(c.indexOf(["circle","square","triangle","star"],G)===-1){D.setData("width",F);D.setData("height",C)}else{var E=F>C?F:C;D.setData("width",E);D.setData("height",E);D.setData("dim",E)}}})},initializeLabel:function(w){if(!this.label){this.label=document.createElement("div");document.body.appendChild(this.label)}this.setLabelStyles(w)},setLabelStyles:function(w){c.extend(this.label.style,{visibility:"hidden",position:"absolute",width:"auto",height:"auto"});this.label.className="jit-autoadjust-label"}};g.Tree=(function(){var F=Array.prototype.slice;function D(P,K,H,N,I){var M=K.Node;var J=K.multitree;if(M.overridable){var O=-1,L=-1;P.eachNode(function(S){if(S._depth==H&&(!J||("$orn" in S.data)&&S.data.$orn==N)){var Q=S.getData("width",I);var R=S.getData("height",I);O=(O<Q)?Q:O;L=(L<R)?R:L}});return{width:O<0?M.width:O,height:L<0?M.height:L}}else{return M}}function G(I,L,K,H){var J=(H=="left"||H=="right")?"y":"x";I.getPos(L)[J]+=K}function B(I,J){var H=[];c.each(I,function(K){K=F.call(K);K[0]+=J;K[1]+=J;H.push(K)});return H}function E(K,H){if(K.length==0){return H}if(H.length==0){return K}var J=K.shift(),I=H.shift();return[[J[0],I[1]]].concat(E(K,H))}function z(H,I){I=I||[];if(H.length==0){return I}var J=H.pop();return z(H,E(J,I))}function C(K,I,L,H,J){if(K.length<=J||I.length<=J){return 0}var N=K[J][1],M=I[J][0];return Math.max(C(K,I,L,H,++J)+L,N-M+H)}function A(K,I,H){function J(N,P,M){if(P.length<=M){return[]}var O=P[M],L=C(N,O,I,H,0);return[L].concat(J(E(N,B(O,L)),P,++M))}return J([],K,0)}function x(L,K,J){function H(O,Q,N){if(Q.length<=N){return[]}var P=Q[N],M=-C(P,O,K,J,0);return[M].concat(H(E(B(P,M),O),Q,++N))}L=F.call(L);var I=H([],L.reverse(),0);return I.reverse()}function w(N,L,I,O){var J=A(N,L,I),M=x(N,L,I);if(O=="left"){M=J}else{if(O=="right"){J=M}}for(var K=0,H=[];K<J.length;K++){H[K]=(J[K]+M[K])/2}return H}function y(H,R,I,Y,W){var K=Y.multitree;var Q=["x","y"],N=["width","height"];var J=+(W=="left"||W=="right");var O=Q[J],X=Q[1-J];var T=Y.Node;var M=N[J],V=N[1-J];var L=Y.siblingOffset;var U=Y.subtreeOffset;var S=Y.align;function P(ab,af,aj){var aa=ab.getData(M,I);var ai=af||(ab.getData(V,I));var am=[],ak=[],ag=false;var Z=ai+Y.levelDistance;ab.eachSubnode(function(ao){if(ao.exist&&(!K||("$orn" in ao.data)&&ao.data.$orn==W)){if(!ag){ag=D(H,Y,ao._depth,W,I)}var an=P(ao,ag[V],aj+Z);am.push(an.tree);ak.push(an.extent)}});var ae=w(ak,U,L,S);for(var ad=0,ac=[],ah=[];ad<am.length;ad++){G(am[ad],I,ae[ad],W);ah.push(B(ak[ad],ae[ad]))}var al=[[-aa/2,aa/2]].concat(z(ah));ab.getPos(I)[O]=0;if(W=="top"||W=="left"){ab.getPos(I)[X]=aj}else{ab.getPos(I)[X]=-aj}return{tree:ab,extent:al}}P(R,false,0)}return new q({compute:function(J,I){var K=J||"start";var H=this.graph.getNode(this.root);c.extend(H,{drawn:true,exist:true,selected:true});f.compute(this.graph,K,this.config);if(!!I||!("_depth" in H)){this.graph.computeLevels(this.root,0,"ignore")}this.computePositions(H,K)},computePositions:function(L,H){var J=this.config;var I=J.multitree;var O=J.align;var K=O!=="center"&&J.indent;var P=J.orientation;var N=I?["top","right","bottom","left"]:[P];var M=this;c.each(N,function(Q){y(M.graph,L,H,M.config,Q,H);var R=["x","y"][+(Q=="left"||Q=="right")];(function S(T){T.eachSubnode(function(U){if(U.exist&&(!I||("$orn" in U.data)&&U.data.$orn==Q)){U.getPos(H)[R]+=T.getPos(H)[R];if(K){U.getPos(H)[R]+=O=="left"?K:-K}S(U)}})})(L)})}})})();$jit.ST=(function(){var x=[];function y(D){D=D||this.clickedNode;if(!this.config.constrained){return[]}var A=this.geom;var H=this.graph;var B=this.canvas;var z=D._depth,E=[];H.eachNode(function(I){if(I.exist&&!I.selected){if(I.isDescendantOf(D.id)){if(I._depth<=z){E.push(I)}}else{E.push(I)}}});var F=A.getRightLevelToShow(D,B);D.eachLevel(F,F,function(I){if(I.exist&&!I.selected){E.push(I)}});for(var G=0;G<x.length;G++){var C=this.graph.getNode(x[G]);if(!C.isDescendantOf(D.id)){E.push(C)}}return E}function w(B){var A=[],z=this.config;B=B||this.clickedNode;this.clickedNode.eachLevel(0,z.levelsToShow,function(C){if(z.multitree&&!("$orn" in C.data)&&C.anySubnode(function(D){return D.exist&&!D.drawn})){A.push(C)}else{if(C.drawn&&!C.anySubnode("drawn")){A.push(C)}}});return A}return new q({Implements:[d,o,g.Tree],initialize:function(z){var B=$jit.ST;var A={levelsToShow:2,levelDistance:30,constrained:true,Node:{type:"rectangle"},duration:700,offsetX:0,offsetY:0};this.controller=this.config=c.merge(n("Canvas","Fx","Tree","Node","Edge","Controller","Tips","NodeStyles","Events","Navigation","Label"),A,z);var C=this.config;if(C.useCanvas){this.canvas=C.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(C.background){C.background=c.merge({type:"Circles"},C.background)}this.canvas=new l(this,C);this.config.labelContainer=(typeof C.injectInto=="string"?C.injectInto:C.injectInto.id)+"-label"}this.graphOptions={klass:p};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new B.Label[C.Label.type](this);this.fx=new B.Plot(this,B);this.op=new B.Op(this);this.group=new B.Group(this);this.geom=new B.Geom(this);this.clickedNode=null;this.initializeExtras()},plot:function(){this.fx.plot(this.controller)},switchPosition:function(E,D,C){var z=this.geom,A=this.fx,B=this;if(!A.busy){A.busy=true;this.contract({onComplete:function(){z.switchOrientation(E);B.compute("end",false);A.busy=false;if(D=="animate"){B.onClick(B.clickedNode.id,C)}else{if(D=="replot"){B.select(B.clickedNode.id,C)}}}},E)}},switchAlignment:function(B,A,z){this.config.align=B;if(A=="animate"){this.select(this.clickedNode.id,z)}else{if(A=="replot"){this.onClick(this.clickedNode.id,z)}}},addNodeInPath:function(z){x.push(z);this.select((this.clickedNode&&this.clickedNode.id)||this.root)},clearNodesInPath:function(z){x.length=0;this.select((this.clickedNode&&this.clickedNode.id)||this.root)},refresh:function(){this.reposition();this.select((this.clickedNode&&this.clickedNode.id)||this.root)},reposition:function(){this.graph.computeLevels(this.root,0,"ignore");this.geom.setRightLevelToShow(this.clickedNode,this.canvas);this.graph.eachNode(function(z){if(z.exist){z.drawn=true}});this.compute("end")},requestNodes:function(B,C){var A=c.merge(this.controller,C),z=this.config.levelsToShow;if(A.request){var E=[],D=B._depth;B.eachLevel(0,z,function(F){if(F.drawn&&!F.anySubnode()){E.push(F);F._level=z-(F._depth-D)}});this.group.requestNodes(E,A)}else{A.onComplete()}},contract:function(D,E){var C=this.config.orientation;var z=this.geom,B=this.group;if(E){z.switchOrientation(E)}var A=y.call(this);if(E){z.switchOrientation(C)}B.contract(A,c.merge(this.controller,D))},move:function(A,B){this.compute("end",false);var z=B.Move,C={x:z.offsetX,y:z.offsetY};if(z.enable){this.geom.translate(A.endPos.add(C).$scale(-1),"end")}this.fx.animate(c.merge(this.controller,{modes:["linear"]},B))},expand:function(A,B){var z=w.call(this,A);this.group.expand(z,c.merge(this.controller,B))},selectPath:function(C){var B=this;this.graph.eachNode(function(E){E.selected=false});function D(F){if(F==null||F.selected){return}F.selected=true;c.each(B.group.getSiblings([F])[F.id],function(G){G.exist=true;G.drawn=true});var E=F.getParents();E=(E.length>0)?E[0]:null;D(E)}for(var z=0,A=[C.id].concat(x);z<A.length;z++){D(this.graph.getNode(A[z]))}},setRoot:function(G,F,E){if(this.busy){return}this.busy=true;var D=this,B=this.canvas;var z=this.graph.getNode(this.root);var A=this.graph.getNode(G);function C(){if(this.config.multitree&&A.data.$orn){var I=A.data.$orn;var J={left:"right",right:"left",top:"bottom",bottom:"top"}[I];z.data.$orn=J;(function H(K){K.eachSubnode(function(L){if(L.id!=G){L.data.$orn=J;H(L)}})})(z);delete A.data.$orn}this.root=G;this.clickedNode=A;this.graph.computeLevels(this.root,0,"ignore");this.geom.setRightLevelToShow(A,B,{execHide:false,onShow:function(K){if(!K.drawn){K.drawn=true;K.setData("alpha",1,"end");K.setData("alpha",0);K.pos.setc(A.pos.x,A.pos.y)}}});this.compute("end");this.busy=true;this.fx.animate({modes:["linear","node-property:alpha"],onComplete:function(){D.busy=false;D.onClick(G,{onComplete:function(){E&&E.onComplete()}})}})}delete z.data.$orns;if(F=="animate"){C.call(this);D.selectPath(A)}else{if(F=="replot"){C.call(this);this.select(this.root)}}},addSubtree:function(z,B,A){if(B=="replot"){this.op.sum(z,c.extend({type:"replot"},A||{}))}else{if(B=="animate"){this.op.sum(z,c.extend({type:"fade:seq"},A||{}))}}},removeSubtree:function(E,A,D,C){var B=this.graph.getNode(E),z=[];B.eachLevel(+!A,false,function(F){z.push(F.id)});if(D=="replot"){this.op.removeNode(z,c.extend({type:"replot"},C||{}))}else{if(D=="animate"){this.op.removeNode(z,c.extend({type:"fade:seq"},C||{}))}}},select:function(z,C){var H=this.group,F=this.geom;var D=this.graph.getNode(z),B=this.canvas;var G=this.graph.getNode(this.root);var A=c.merge(this.controller,C);var E=this;A.onBeforeCompute(D);this.selectPath(D);this.clickedNode=D;this.requestNodes(D,{onComplete:function(){H.hide(H.prepare(y.call(E)),A);F.setRightLevelToShow(D,B);E.compute("current");E.graph.eachNode(function(K){var J=K.pos.getc(true);K.startPos.setc(J.x,J.y);K.endPos.setc(J.x,J.y);K.visited=false});var I={x:A.offsetX,y:A.offsetY};E.geom.translate(D.endPos.add(I).$scale(-1),["start","current","end"]);H.show(w.call(E));E.plot();A.onAfterCompute(E.clickedNode);A.onComplete()}})},onClick:function(A,H){var C=this.canvas,G=this,z=this.geom,D=this.config;var F={Move:{enable:true,offsetX:D.offsetX||0,offsetY:D.offsetY||0},setRightLevelToShowConfig:false,onBeforeRequest:c.empty,onBeforeContract:c.empty,onBeforeMove:c.empty,onBeforeExpand:c.empty};var B=c.merge(this.controller,F,H);if(!this.busy){this.busy=true;var E=this.graph.getNode(A);this.selectPath(E,this.clickedNode);this.clickedNode=E;B.onBeforeCompute(E);B.onBeforeRequest(E);this.requestNodes(E,{onComplete:function(){B.onBeforeContract(E);G.contract({onComplete:function(){z.setRightLevelToShow(E,C,B.setRightLevelToShowConfig);B.onBeforeMove(E);G.move(E,{Move:B.Move,onComplete:function(){B.onBeforeExpand(E);G.expand(E,{onComplete:function(){G.busy=false;B.onAfterCompute(A);B.onComplete()}})}})}})}})}}})})();$jit.ST.$extend=true;$jit.ST.Op=new q({Implements:e.Op});$jit.ST.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config;this.animation=new u;this.nodes=null},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){w.graph.computeLevels(w.root,0);y()}}})}},contract:function(y,x){var w=this.viz;var z=this;y=this.prepare(y);this.animation.setOptions(c.merge(x,{$animating:false,compute:function(A){if(A==1){A=0.99}z.plotStep(1-A,x,this.$animating);this.$animating="contract"},complete:function(){z.hide(y,x)}})).start()},hide:function(y,x){var w=this.viz;for(var z=0;z<y.length;z++){if(true||!x||!x.request){y[z].eachLevel(1,false,function(B){if(B.exist){c.extend(B,{drawn:false,exist:false})}})}else{var A=[];y[z].eachLevel(1,false,function(B){A.push(B.id)});w.op.removeNode(A,{type:"nothing"});w.labels.clearLabels()}}x.onComplete()},expand:function(x,w){var y=this;this.show(x);this.animation.setOptions(c.merge(w,{$animating:false,compute:function(z){y.plotStep(z,w,this.$animating);this.$animating="expand"},complete:function(){y.plotStep(undefined,w,false);w.onComplete()}})).start()},show:function(w){var x=this.config;this.prepare(w);c.each(w,function(z){if(x.multitree&&!("$orn" in z.data)){delete z.data.$orns;var y=" ";z.eachSubnode(function(A){if(("$orn" in A.data)&&y.indexOf(A.data.$orn)<0&&A.exist&&!A.drawn){y+=A.data.$orn+" "}});z.data.$orns=y}z.eachLevel(0,x.levelsToShow,function(A){if(A.exist){A.drawn=true}})})},prepare:function(w){this.nodes=this.getNodesWithChildren(w);return this.nodes},getNodesWithChildren:function(y){var x=[],A=this.config,w=this.viz.root;y.sort(function(E,D){return(E._depth<=D._depth)-(E._depth>=D._depth)});for(var B=0;B<y.length;B++){if(y[B].anySubnode("exist")){for(var z=B+1,C=false;!C&&z<y.length;z++){if(!A.multitree||"$orn" in y[z].data){C=C||y[B].isDescendantOf(y[z].id)}}if(!C){x.push(y[B])}}}return x},plotStep:function(G,C,I){var F=this.viz,z=this.config,y=F.canvas,H=y.getCtx(),w=this.nodes;var B,A;var x={};for(B=0;B<w.length;B++){A=w[B];x[A.id]=[];var E=z.multitree&&!("$orn" in A.data);var D=E&&A.data.$orns;A.eachSubgraph(function(J){if(E&&D&&D.indexOf(J.data.$orn)>0&&J.drawn){J.drawn=false;x[A.id].push(J)}else{if((!E||!D)&&J.drawn){J.drawn=false;x[A.id].push(J)}}});A.drawn=true}if(w.length>0){F.fx.plot()}for(B in x){c.each(x[B],function(J){J.drawn=true})}for(B=0;B<w.length;B++){A=w[B];H.save();F.fx.plotSubtree(A,C,G,I);H.restore()}},getSiblings:function(w){var x={};c.each(w,function(A){var z=A.getParents();if(z.length==0){x[A.id]=[A]}else{var y=[];z[0].eachSubnode(function(B){y.push(B)});x[A.id]=y}});return x}});$jit.ST.Geom=new q({Implements:e.Geom,switchOrientation:function(w){this.config.orientation=w},dispatch:function(){var x=Array.prototype.slice.call(arguments);var y=x.shift(),w=x.length;var z=function(A){return typeof A=="function"?A():A};if(w==2){return(y=="top"||y=="bottom")?z(x[0]):z(x[1])}else{if(w==4){switch(y){case"top":return z(x[0]);case"right":return z(x[1]);case"bottom":return z(x[2]);case"left":return z(x[3])}}}return undefined},getSize:function(E,D){var C=E.data,z=this.config;var y=z.siblingOffset;var B=(z.multitree&&("$orn" in C)&&C.$orn)||z.orientation;var x=E.getData("width")+y;var A=E.getData("height")+y;if(!D){return this.dispatch(B,A,x)}else{return this.dispatch(B,x,A)}},getTreeBaseSize:function(A,B,x){var y=this.getSize(A,true),w=0,z=this;if(x(B,A)){return y}if(B===0){return 0}A.eachSubnode(function(C){w+=z.getTreeBaseSize(C,B-1,x)});return(y>w?y:w)+this.config.subtreeOffset},getEdge:function(C,B,A){var y=function(E,w){return function(){return C.pos.add(new p(E,w))}};var D=this.node;var x=C.getData("width");var z=C.getData("height");if(B=="begin"){if(D.align=="center"){return this.dispatch(A,y(0,z/2),y(-x/2,0),y(0,-z/2),y(x/2,0))}else{if(D.align=="left"){return this.dispatch(A,y(0,z),y(0,0),y(0,0),y(x,0))}else{if(D.align=="right"){return this.dispatch(A,y(0,0),y(-x,0),y(0,-z),y(0,0))}else{throw"align: not implemented"}}}}else{if(B=="end"){if(D.align=="center"){return this.dispatch(A,y(0,-z/2),y(x/2,0),y(0,z/2),y(-x/2,0))}else{if(D.align=="left"){return this.dispatch(A,y(0,0),y(x,0),y(0,z),y(0,0))}else{if(D.align=="right"){return this.dispatch(A,y(0,-z),y(0,0),y(0,0),y(-x,0))}else{throw"align: not implemented"}}}}}},getScaledTreePosition:function(B,D){var C=this.node;var x=B.getData("width");var A=B.getData("height");var z=(this.config.multitree&&("$orn" in B.data)&&B.data.$orn)||this.config.orientation;var y=function(E,w){return function(){return B.pos.add(new p(E,w)).$scale(1-D)}};if(C.align=="left"){return this.dispatch(z,y(0,A),y(0,0),y(0,0),y(x,0))}else{if(C.align=="center"){return this.dispatch(z,y(0,A/2),y(-x/2,0),y(0,-A/2),y(x/2,0))}else{if(C.align=="right"){return this.dispatch(z,y(0,0),y(-x,0),y(0,-A),y(0,0))}else{throw"align: not implemented"}}}},treeFitsInCanvas:function(B,w,C){var y=w.getSize();var z=(this.config.multitree&&("$orn" in B.data)&&B.data.$orn)||this.config.orientation;var x=this.dispatch(z,y.width,y.height);var A=this.getTreeBaseSize(B,C,function(E,D){return E===0||!D.anySubnode()});return(A<x)}});$jit.ST.Plot=new q({Implements:e.Plot,plotSubtree:function(z,w,A,E){var C=this.viz,x=C.canvas,y=C.config;A=Math.min(Math.max(0.001,A),1);if(A>=0){z.drawn=false;var D=x.getCtx();var B=C.geom.getScaledTreePosition(z,A);D.translate(B.x,B.y);D.scale(A,A)}this.plotTree(z,c.merge(w,{withLabels:true,hideLabels:!!A,plotSubtree:function(I,G){var F=y.multitree&&!("$orn" in z.data);var H=F&&z.getData("orns");return !F||H.indexOf(z.getData("orn"))>-1}}),E);if(A>=0){z.drawn=true}},getAlignedPos:function(B,z,w){var y=this.node;var A,x;if(y.align=="center"){A={x:B.x-z/2,y:B.y-w/2}}else{if(y.align=="left"){x=this.config.orientation;if(x=="bottom"||x=="top"){A={x:B.x-z/2,y:B.y}}else{A={x:B.x,y:B.y-w/2}}}else{if(y.align=="right"){x=this.config.orientation;if(x=="bottom"||x=="top"){A={x:B.x-z/2,y:B.y-w}}else{A={x:B.x-z,y:B.y-w/2}}}else{throw"align: not implemented"}}}return A},getOrientation:function(w){var y=this.config;var x=y.orientation;if(y.multitree){var z=w.nodeFrom;var A=w.nodeTo;x=(("$orn" in z.data)&&z.data.$orn)||(("$orn" in A.data)&&A.data.$orn)}return x}});$jit.ST.Label={};$jit.ST.Label.Native=new q({Implements:e.Label.Native,renderLabel:function(z,B,y){var x=z.getCtx(),D=B.pos.getc(true),A=B.getData("width"),w=B.getData("height"),C=this.viz.fx.getAlignedPos(D,A,w);x.fillText(B.name,C.x+A/2,C.y+w/2)}});$jit.ST.Label.DOM=new q({Implements:e.Label.DOM,placeLabel:function(P,J,F){var B=J.pos.getc(true),O=this.viz.config,K=O.Node,x=this.viz.canvas,C=J.getData("width"),M=J.getData("height"),y=x.getSize(),G,N;var A=x.translateOffsetX,z=x.translateOffsetY,E=x.scaleOffsetX,D=x.scaleOffsetY,I=B.x*E+A,H=B.y*D+z;if(K.align=="center"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H-M/2+y.height/2)}}else{if(K.align=="left"){N=O.orientation;if(N=="bottom"||N=="top"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H+y.height/2)}}else{G={x:Math.round(I+y.width/2),y:Math.round(H-M/2+y.height/2)}}}else{if(K.align=="right"){N=O.orientation;if(N=="bottom"||N=="top"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H-M+y.height/2)}}else{G={x:Math.round(I-C+y.width/2),y:Math.round(H-M/2+y.height/2)}}}else{throw"align: not implemented"}}}var L=P.style;L.left=G.x+"px";L.top=G.y+"px";L.display=this.fitsInCanvas(G,x)?"":"none";F.onPlaceLabel(P,J)}});$jit.ST.Label.SVG=new q({Implements:[$jit.ST.Label.DOM,e.Label.SVG],initialize:function(w){this.viz=w}});$jit.ST.Label.HTML=new q({Implements:[$jit.ST.Label.DOM,e.Label.HTML],initialize:function(w){this.viz=w}});$jit.ST.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(x,w){var z=x.getData("dim"),A=this.getAlignedPos(x.pos.getc(true),z,z),y=z/2;this.nodeHelper.circle.render("fill",{x:A.x+y,y:A.y+y},y,w)},contains:function(w,A){var y=w.getData("dim"),z=this.getAlignedPos(w.pos.getc(true),y,y),x=y/2;this.nodeHelper.circle.contains({x:z.x+x,y:z.y+x},A,x)}},square:{render:function(x,w){var z=x.getData("dim"),y=z/2,A=this.getAlignedPos(x.pos.getc(true),z,z);this.nodeHelper.square.render("fill",{x:A.x+y,y:A.y+y},y,w)},contains:function(w,A){var y=w.getData("dim"),z=this.getAlignedPos(w.pos.getc(true),y,y),x=y/2;this.nodeHelper.square.contains({x:z.x+x,y:z.y+x},A,x)}},ellipse:{render:function(z,x){var y=z.getData("width"),w=z.getData("height"),A=this.getAlignedPos(z.pos.getc(true),y,w);this.nodeHelper.ellipse.render("fill",{x:A.x+y/2,y:A.y+w/2},y,w,x)},contains:function(y,A){var x=y.getData("width"),w=y.getData("height"),z=this.getAlignedPos(y.pos.getc(true),x,w);this.nodeHelper.ellipse.contains({x:z.x+x/2,y:z.y+w/2},A,x,w)}},rectangle:{render:function(z,x){var y=z.getData("width"),w=z.getData("height"),A=this.getAlignedPos(z.pos.getc(true),y,w);this.nodeHelper.rectangle.render("fill",{x:A.x+y/2,y:A.y+w/2},y,w,x)},contains:function(y,A){var x=y.getData("width"),w=y.getData("height"),z=this.getAlignedPos(y.pos.getc(true),x,w);this.nodeHelper.rectangle.contains({x:z.x+x/2,y:z.y+w/2},A,x,w)}}});$jit.ST.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,z){var y=this.getOrientation(x),A=x.nodeFrom,B=x.nodeTo,w=A._depth<B._depth,D=this.viz.geom.getEdge(w?A:B,"begin",y),C=this.viz.geom.getEdge(w?B:A,"end",y);this.edgeHelper.line.render(D,C,z)},contains:function(x,D){var y=this.getOrientation(x),z=x.nodeFrom,A=x.nodeTo,w=z._depth<A._depth,C=this.viz.geom.getEdge(w?z:A,"begin",y),B=this.viz.geom.getEdge(w?A:z,"end",y);return this.edgeHelper.line.contains(C,B,D,this.edge.epsilon)}},arrow:{render:function(C,x){var B=this.getOrientation(C),y=C.nodeFrom,w=C.nodeTo,A=C.getData("dim"),E=this.viz.geom.getEdge(y,"begin",B),F=this.viz.geom.getEdge(w,"end",B),D=C.data.$direction,z=(D&&D.length>1&&D[0]!=y.id);this.edgeHelper.arrow.render(E,F,A,z,x)},contains:function(x,D){var y=this.getOrientation(x),z=x.nodeFrom,A=x.nodeTo,w=z._depth<A._depth,C=this.viz.geom.getEdge(w?z:A,"begin",y),B=this.viz.geom.getEdge(w?A:z,"end",y);return this.edgeHelper.arrow.contains(C,B,D,this.edge.epsilon)}},"quadratic:begin":{render:function(C,w){var B=this.getOrientation(C);var A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.quadraticCurveTo(x.x+z,x.y,y.x,y.y);break;case"right":E.quadraticCurveTo(x.x-z,x.y,y.x,y.y);break;case"top":E.quadraticCurveTo(x.x,x.y+z,y.x,y.y);break;case"bottom":E.quadraticCurveTo(x.x,x.y-z,y.x,y.y);break}E.stroke()}},"quadratic:end":{render:function(C,w){var B=this.getOrientation(C);var A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.quadraticCurveTo(y.x-z,y.y,y.x,y.y);break;case"right":E.quadraticCurveTo(y.x+z,y.y,y.x,y.y);break;case"top":E.quadraticCurveTo(y.x,y.y-z,y.x,y.y);break;case"bottom":E.quadraticCurveTo(y.x,y.y+z,y.x,y.y);break}E.stroke()}},bezier:{render:function(C,w){var B=this.getOrientation(C),A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.bezierCurveTo(x.x+z,x.y,y.x-z,y.y,y.x,y.y);break;case"right":E.bezierCurveTo(x.x-z,x.y,y.x+z,y.y,y.x,y.y);break;case"top":E.bezierCurveTo(x.x,x.y+z,y.x,y.y-z,y.x,y.y);break;case"bottom":E.bezierCurveTo(x.x,x.y-z,y.x,y.y+z,y.x,y.y);break}E.stroke()}}});$jit.ST.Plot.NodeTypes.implement({"areachart-stacked":{render:function(W,D){var U=W.pos.getc(true),w=W.getData("width"),A=W.getData("height"),G=this.getAlignedPos(U,w,A),ab=G.x,aa=G.y,L=W.getData("stringArray"),F=W.getData("dimArray"),B=W.getData("valueArray"),ad=c.reduce(B,function(aj,ak){return aj+ak[0]},0),ac=c.reduce(B,function(aj,ak){return aj+ak[1]},0),I=W.getData("colorArray"),C=I.length,Y=W.getData("config"),J=W.getData("gradient"),ai=Y.showLabels,N=Y.showAggregates,ae=Y.Label,T=W.getData("prev");var M=D.getCtx(),H=W.getData("border");if(I&&F&&L){for(var ah=0,af=F.length,K=0,E=0,X=0;ah<af;ah++){M.fillStyle=M.strokeStyle=I[ah%C];M.save();if(J&&(F[ah][0]>0||F[ah][1]>0)){var R=K+F[ah][0],P=E+F[ah][1],ag=Math.atan((P-R)/w),Z=55;var V=M.createLinearGradient(ab+w/2,aa-(R+P)/2,ab+w/2+Z*Math.sin(ag),aa-(R+P)/2+Z*Math.cos(ag));var Q=c.rgbToHex(c.map(c.hexToRgb(I[ah%C].slice(1)),function(x){return(x*0.85)>>0}));V.addColorStop(0,I[ah%C]);V.addColorStop(1,Q);M.fillStyle=V}M.beginPath();M.moveTo(ab,aa-K);M.lineTo(ab+w,aa-E);M.lineTo(ab+w,aa-E-F[ah][1]);M.lineTo(ab,aa-K-F[ah][0]);M.lineTo(ab,aa-K);M.fill();M.restore();if(H){var S=H.name==L[ah];var z=S?0.7:0.8;var Q=c.rgbToHex(c.map(c.hexToRgb(I[ah%C].slice(1)),function(x){return(x*z)>>0}));M.strokeStyle=Q;M.lineWidth=S?4:1;M.save();M.beginPath();if(H.index===0){M.moveTo(ab,aa-K);M.lineTo(ab,aa-K-F[ah][0])}else{M.moveTo(ab+w,aa-E);M.lineTo(ab+w,aa-E-F[ah][1])}M.stroke();M.restore()}K+=(F[ah][0]||0);E+=(F[ah][1]||0);if(F[ah][0]>0){X+=(B[ah][0]||0)}}if(T&&ae.type=="Native"){M.save();M.beginPath();M.fillStyle=M.strokeStyle=ae.color;M.font=ae.style+" "+ae.size+"px "+ae.family;M.textAlign="center";M.textBaseline="middle";var O=N(W.name,ad,ac,W,X);if(O!==false){M.fillText(O!==true?O:X,ab,aa-K-Y.labelOffset-ae.size/2,w)}if(ai(W.name,ad,ac,W)){M.fillText(W.name,ab,aa+ae.size/2+Y.labelOffset)}M.restore()}}},contains:function(C,E){var J=C.pos.getc(true),z=C.getData("width"),N=C.getData("height"),M=this.getAlignedPos(J,z,N),L=M.x,K=M.y,O=C.getData("dimArray"),w=E.x-L;if(E.x<L||E.x>L+z||E.y>K||E.y<K-N){return false}for(var F=0,D=O.length,I=K,A=K;F<D;F++){var B=O[F];I-=B[0];A-=B[1];var G=I+(A-I)*w/z;if(E.y>=G){var H=+(w>z/2);return{name:C.getData("stringArray")[F],color:C.getData("colorArray")[F],value:C.getData("valueArray")[F][H],index:H}}}return false}}});$jit.AreaChart=new q({st:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(y){this.controller=this.config=c.merge(n("Canvas","Margin","Label","AreaChart"),{Label:{type:"Native"}},y);var z=this.config.showLabels,x=c.type(z),A=this.config.showAggregates,w=c.type(A);this.config.showLabels=x=="function"?z:c.lambda(z);this.config.showAggregates=w=="function"?A:c.lambda(A);this.initializeViz()},initializeViz:function(){var x=this.config,B=this,w=x.type.split(":")[0],A={};var z=new $jit.ST({injectInto:x.injectInto,width:x.width,height:x.height,orientation:"bottom",levelDistance:0,siblingOffset:0,subtreeOffset:0,withLabels:x.Label.type!="Native",useCanvas:x.useCanvas,Label:{type:x.Label.type},Node:{overridable:true,type:"areachart-"+w,align:"left",width:1,height:1},Edge:{type:"none"},Tips:{enable:x.Tips.enable,type:"Native",force:true,onShow:function(G,F,D){var E=D;x.Tips.onShow(G,E,F)}},Events:{enable:true,type:"Native",onClick:function(F,G,D){if(!x.filterOnClick&&!x.Events.enable){return}var E=G.getContains();if(E){x.filterOnClick&&B.filter(E.name)}x.Events.enable&&x.Events.onClick(E,G,D)},onRightClick:function(E,F,D){if(!x.restoreOnRightClick){return}B.restore()},onMouseMove:function(F,G,D){if(!x.selectOnHover){return}if(F){var E=G.getContains();B.select(F.id,E.name,E.index)}else{B.select(false,false,false)}}},onCreateLabel:function(J,G){var P=x.Label,O=G.getData("valueArray"),H=c.reduce(O,function(Q,R){return Q+R[0]},0),M=c.reduce(O,function(Q,R){return Q+R[1]},0);if(G.getData("prev")){var L={wrapper:document.createElement("div"),aggregate:document.createElement("div"),label:document.createElement("div")};var D=L.wrapper,N=L.label,E=L.aggregate,F=D.style,K=N.style,I=E.style;A[G.id]=L;D.appendChild(N);D.appendChild(E);if(!x.showLabels(G.name,H,M,G)){N.style.display="none"}if(!x.showAggregates(G.name,H,M,G)){E.style.display="none"}F.position="relative";F.overflow="visible";F.fontSize=P.size+"px";F.fontFamily=P.family;F.color=P.color;F.textAlign="center";I.position=K.position="absolute";J.style.width=G.getData("width")+"px";J.style.height=G.getData("height")+"px";N.innerHTML=G.name;J.appendChild(D)}},onPlaceLabel:function(V,P){if(!P.getData("prev")){return}var T=A[P.id],E=T.wrapper.style,D=T.label.style,O=T.aggregate.style,M=P.getData("width"),K=P.getData("height"),J=P.getData("dimArray"),G=P.getData("valueArray"),L=c.reduce(G,function(W,X){return W+X[0]},0),H=c.reduce(G,function(W,X){return W+X[1]},0),I=parseInt(E.fontSize,10),N=V.style;if(J&&G){if(x.showLabels(P.name,L,H,P)){D.display=""}else{D.display="none"}var F=x.showAggregates(P.name,L,H,P);if(F!==false){O.display=""}else{O.display="none"}E.width=O.width=D.width=V.style.width=M+"px";O.left=D.left=-M/2+"px";for(var S=0,Q=G.length,R=0,U=0;S<Q;S++){if(J[S][0]>0){R+=G[S][0];U+=J[S][0]}}O.top=(-I-x.labelOffset)+"px";D.top=(x.labelOffset+U)+"px";V.style.top=parseInt(V.style.top,10)-U+"px";V.style.height=E.height=U+"px";T.aggregate.innerHTML=F!==true?F:R}}});var y=z.canvas.getSize(),C=x.Margin;z.config.offsetY=-y.height/2+C.bottom+(x.showLabels&&(x.labelOffset+x.Label.size));z.config.offsetX=(C.right-C.left)/2;this.delegate=z;this.canvas=this.delegate.canvas},loadJSON:function(N){var J=c.time(),B=[],M=this.delegate,Q=c.splat(N.label),I=c.splat(N.color||this.colors),O=this.config,x=!!O.type.split(":")[1],z=O.animate;for(var K=0,y=N.values,H=y.length;K<H-1;K++){var P=y[K],E=y[K-1],F=y[K+1];var L=c.splat(y[K].values),w=c.splat(y[K+1].values);var A=c.zip(L,w);var D=0,C=0;B.push({id:J+P.label,name:P.label,data:{value:A,"$valueArray":A,"$colorArray":I,"$stringArray":Q,"$next":F.label,"$prev":E?E.label:false,"$config":O,"$gradient":x},children:[]})}var G={id:J+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:B};M.loadJSON(G);this.normalizeDims();M.compute();M.select(M.root);if(z){M.fx.animate({modes:["node-property:height:dimArray"],duration:1500})}},updateJSON:function(G,x){if(this.busy){return}this.busy=true;var D=this.delegate,F=D.graph,A=G.label&&c.splat(G.label),E=G.values,w=this.config.animate,C=this,B={};for(var z=0,y=E.length;z<y;z++){B[E[z].label]=E[z]}F.eachNode(function(L){var H=B[L.name],I=L.getData("stringArray"),K=L.getData("valueArray"),J=L.getData("next");if(H){H.values=c.splat(H.values);c.each(K,function(M,N){M[0]=H.values[N];if(A){I[N]=A[N]}});L.setData("valueArray",K)}if(J){H=B[J];if(H){c.each(K,function(M,N){M[1]=H.values[N]})}}});this.normalizeDims();D.compute();D.select(D.root);if(w){D.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){C.busy=false;x&&x.onComplete()}})}},filter:function(z,A){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.delegate.tips.hide()}this.select(false,false,false);var x=c.splat(z);var w=this.delegate.graph.getNode(this.delegate.root);var y=this;this.normalizeDims();w.eachAdjacency(function(B){var E=B.nodeTo,D=E.getData("dimArray","end"),C=E.getData("stringArray");E.setData("dimArray",c.map(D,function(G,F){return(c.indexOf(x,C[F])>-1)?G:[0,0]}),"end")});this.delegate.fx.animate({modes:["node-property:dimArray"],duration:1500,onComplete:function(){y.busy=false;A&&A.onComplete()}})},restore:function(x){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.delegate.tips.hide()}this.select(false,false,false);this.normalizeDims();var w=this;this.delegate.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){w.busy=false;x&&x.onComplete()}})},select:function(B,x,w){if(!this.config.selectOnHover){return}var y=this.selected;if(y.id!=B||y.name!=x||y.index!=w){y.id=B;y.name=x;y.index=w;this.delegate.graph.eachNode(function(C){C.setData("border",false)});if(B){var A=this.delegate.graph.getNode(B);A.setData("border",y);var z=w===0?"prev":"next";z=A.getData(z);if(z){A=this.delegate.graph.getByName(z);if(A){A.setData("border",{name:x,index:1-w})}}}this.delegate.plot()}},getLegend:function(){var y={};var z;this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var w=0;this.delegate.graph.eachNode(function(B){var y=B.getData("valueArray"),x=0,A=0;c.each(y,function(C){x+=+C[0];A+=+C[1]});var z=A>x?A:x;w=w>z?w:z});return w},normalizeDims:function(){var C=this.delegate.graph.getNode(this.delegate.root),z=0;C.eachAdjacency(function(){z++});var B=this.getMaxValue()||1,F=this.delegate.canvas.getSize(),y=this.config,A=y.Margin,D=y.labelOffset+y.Label.size,w=(F.width-(A.left+A.right))/z,x=y.animate,E=F.height-(A.top+A.bottom)-(y.showAggregates&&D)-(y.showLabels&&D);this.delegate.graph.eachNode(function(L){var I=0,K=0,G=[];c.each(L.getData("valueArray"),function(M){I+=+M[0];K+=+M[1];G.push([0,0])});var J=K>I?K:I;L.setData("width",w);if(x){L.setData("height",J*E/B,"end");L.setData("dimArray",c.map(L.getData("valueArray"),function(M){return[M[0]*E/B,M[1]*E/B]}),"end");var H=L.getData("dimArray");if(!H){L.setData("dimArray",G)}}else{L.setData("height",J*E/B);L.setData("dimArray",c.map(L.getData("valueArray"),function(M){return[M[0]*E/B,M[1]*E/B]}))}})}});n.BarChart={$extend:true,animate:true,type:"stacked",labelOffset:3,barsOffset:0,hoveredColor:"#9fd4ff",orientation:"horizontal",showAggregates:true,showLabels:true,Tips:{enable:false,onShow:c.empty,onHide:c.empty},Events:{enable:false,onClick:c.empty}};$jit.ST.Plot.NodeTypes.implement({"barchart-stacked":{render:function(R,C){var H=R.pos.getc(true),Q=R.getData("width"),O=R.getData("height"),M=this.getAlignedPos(H,Q,O),L=M.x,K=M.y,N=R.getData("dimArray"),F=R.getData("valueArray"),E=R.getData("colorArray"),B=E.length,Y=R.getData("stringArray");var T=C.getCtx(),w={},U=R.getData("border"),z=R.getData("gradient"),aa=R.getData("config"),A=aa.orientation=="horizontal",D=aa.showAggregates,P=aa.showLabels,J=aa.Label;if(E&&N&&Y){for(var X=0,S=N.length,W=0,G=0;X<S;X++){T.fillStyle=T.strokeStyle=E[X%B];if(z){var Z;if(A){Z=T.createLinearGradient(L+W+N[X]/2,K,L+W+N[X]/2,K+O)}else{Z=T.createLinearGradient(L,K-W-N[X]/2,L+Q,K-W-N[X]/2)}var V=c.rgbToHex(c.map(c.hexToRgb(E[X%B].slice(1)),function(x){return(x*0.5)>>0}));Z.addColorStop(0,V);Z.addColorStop(0.5,E[X%B]);Z.addColorStop(1,V);T.fillStyle=Z}if(A){T.fillRect(L+W,K,N[X],O)}else{T.fillRect(L,K-W-N[X],Q,N[X])}if(U&&U.name==Y[X]){w.acum=W;w.dimValue=N[X]}W+=(N[X]||0);G+=(F[X]||0)}if(U){T.save();T.lineWidth=2;T.strokeStyle=U.color;if(A){T.strokeRect(L+w.acum+1,K+1,w.dimValue-2,O-2)}else{T.strokeRect(L+1,K-w.acum-w.dimValue+1,Q-2,w.dimValue-2)}T.restore()}if(J.type=="Native"){T.save();T.fillStyle=T.strokeStyle=J.color;T.font=J.style+" "+J.size+"px "+J.family;T.textBaseline="middle";var I=D(R.name,G,R);if(I!==false){I=I!==true?I:G;if(A){T.textAlign="right";T.fillText(I,L+W-aa.labelOffset,K+O/2)}else{T.textAlign="center";T.fillText(I,L+Q/2,K-O-J.size/2-aa.labelOffset)}}if(P(R.name,G,R)){if(A){T.textAlign="center";T.translate(L-aa.labelOffset-J.size/2,K+O/2);T.rotate(Math.PI/2);T.fillText(R.name,0,0)}else{T.textAlign="center";T.fillText(R.name,L+Q/2,K+J.size/2+aa.labelOffset)}}T.restore()}}},contains:function(D,F){var I=D.pos.getc(true),A=D.getData("width"),N=D.getData("height"),M=this.getAlignedPos(I,A,N),L=M.x,J=M.y,O=D.getData("dimArray"),B=D.getData("config"),z=F.x-L,w=B.orientation=="horizontal";if(w){if(F.x<L||F.x>L+A||F.y>J+N||F.y<J){return false}}else{if(F.x<L||F.x>L+A||F.y>J||F.y<J-N){return false}}for(var G=0,E=O.length,K=(w?L:J);G<E;G++){var C=O[G];if(w){K+=C;var H=K;if(F.x<=H){return{name:D.getData("stringArray")[G],color:D.getData("colorArray")[G],value:D.getData("valueArray")[G],label:D.name}}}else{K-=C;var H=K;if(F.y>=H){return{name:D.getData("stringArray")[G],color:D.getData("colorArray")[G],value:D.getData("valueArray")[G],label:D.name}}}}return false}},"barchart-grouped":{render:function(S,C){var I=S.pos.getc(true),R=S.getData("width"),P=S.getData("height"),N=this.getAlignedPos(I,R,P),M=N.x,L=N.y,O=S.getData("dimArray"),G=S.getData("valueArray"),Y=G.length,F=S.getData("colorArray"),B=F.length,aa=S.getData("stringArray");var U=C.getCtx(),w={},V=S.getData("border"),z=S.getData("gradient"),ac=S.getData("config"),A=ac.orientation=="horizontal",E=ac.showAggregates,Q=ac.showLabels,K=ac.Label,D=(A?P:R)/Y;if(F&&O&&aa){for(var Z=0,T=Y,X=0,H=0;Z<T;Z++){U.fillStyle=U.strokeStyle=F[Z%B];if(z){var ab;if(A){ab=U.createLinearGradient(M+O[Z]/2,L+D*Z,M+O[Z]/2,L+D*(Z+1))}else{ab=U.createLinearGradient(M+D*Z,L-O[Z]/2,M+D*(Z+1),L-O[Z]/2)}var W=c.rgbToHex(c.map(c.hexToRgb(F[Z%B].slice(1)),function(x){return(x*0.5)>>0}));ab.addColorStop(0,W);ab.addColorStop(0.5,F[Z%B]);ab.addColorStop(1,W);U.fillStyle=ab}if(A){U.fillRect(M,L+D*Z,O[Z],D)}else{U.fillRect(M+D*Z,L-O[Z],D,O[Z])}if(V&&V.name==aa[Z]){w.acum=D*Z;w.dimValue=O[Z]}X+=(O[Z]||0);H+=(G[Z]||0)}if(V){U.save();U.lineWidth=2;U.strokeStyle=V.color;if(A){U.strokeRect(M+1,L+w.acum+1,w.dimValue-2,D-2)}else{U.strokeRect(M+w.acum+1,L-w.dimValue+1,D-2,w.dimValue-2)}U.restore()}if(K.type=="Native"){U.save();U.fillStyle=U.strokeStyle=K.color;U.font=K.style+" "+K.size+"px "+K.family;U.textBaseline="middle";var J=E(S.name,H,S);if(J!==false){J=J!==true?J:H;if(A){U.textAlign="right";U.fillText(J,M+Math.max.apply(null,O)-ac.labelOffset,L+P/2)}else{U.textAlign="center";U.fillText(J,M+R/2,L-Math.max.apply(null,O)-K.size/2-ac.labelOffset)}}if(Q(S.name,H,S)){if(A){U.textAlign="center";U.translate(M-ac.labelOffset-K.size/2,L+P/2);U.rotate(Math.PI/2);U.fillText(S.name,0,0)}else{U.textAlign="center";U.fillText(S.name,M+R/2,L+K.size/2+ac.labelOffset)}}U.restore()}}},contains:function(J,F){var B=J.pos.getc(true),I=J.getData("width"),H=J.getData("height"),E=this.getAlignedPos(B,I,H),D=E.x,C=E.y,G=J.getData("dimArray"),M=G.length,P=J.getData("config"),A=F.x-D,w=P.orientation=="horizontal",z=(w?H:I)/M;if(w){if(F.x<D||F.x>D+I||F.y>C+H||F.y<C){return false}}else{if(F.x<D||F.x>D+I||F.y>C||F.y<C-H){return false}}for(var L=0,K=G.length;L<K;L++){var O=G[L];if(w){var N=C+z*L;if(F.x<=D+O&&F.y>=N&&F.y<=N+z){return{name:J.getData("stringArray")[L],color:J.getData("colorArray")[L],value:J.getData("valueArray")[L],label:J.name}}}else{var N=D+z*L;if(F.x>=N&&F.x<=N+z&&F.y>=C-O){return{name:J.getData("stringArray")[L],color:J.getData("colorArray")[L],value:J.getData("valueArray")[L],label:J.name}}}}return false}}});$jit.BarChart=new q({st:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(y){this.controller=this.config=c.merge(n("Canvas","Margin","Label","BarChart"),{Label:{type:"Native"}},y);var z=this.config.showLabels,x=c.type(z),A=this.config.showAggregates,w=c.type(A);this.config.showLabels=x=="function"?z:c.lambda(z);this.config.showAggregates=w=="function"?A:c.lambda(A);this.initializeViz()},initializeViz:function(){var x=this.config,B=this;var w=x.type.split(":")[0],D=x.orientation=="horizontal",A={};var z=new $jit.ST({injectInto:x.injectInto,width:x.width,height:x.height,orientation:D?"left":"bottom",levelDistance:0,siblingOffset:x.barsOffset,subtreeOffset:0,withLabels:x.Label.type!="Native",useCanvas:x.useCanvas,Label:{type:x.Label.type},Node:{overridable:true,type:"barchart-"+w,align:"left",width:1,height:1},Edge:{type:"none"},Tips:{enable:x.Tips.enable,type:"Native",force:true,onShow:function(H,G,E){var F=E;x.Tips.onShow(H,F,G)}},Events:{enable:true,type:"Native",onClick:function(G,H,E){if(!x.Events.enable){return}var F=H.getContains();x.Events.onClick(F,H,E)},onMouseMove:function(G,H,E){if(!x.hoveredColor){return}if(G){var F=H.getContains();B.select(G.id,F.name,F.index)}else{B.select(false,false,false)}}},onCreateLabel:function(J,H){var P=x.Label,N=H.getData("valueArray"),M=c.reduce(N,function(Q,R){return Q+R},0);var L={wrapper:document.createElement("div"),aggregate:document.createElement("div"),label:document.createElement("div")};var E=L.wrapper,O=L.label,F=L.aggregate,G=E.style,K=O.style,I=F.style;A[H.id]=L;E.appendChild(O);E.appendChild(F);if(!x.showLabels(H.name,M,H)){K.display="none"}if(!x.showAggregates(H.name,M,H)){I.display="none"}G.position="relative";G.overflow="visible";G.fontSize=P.size+"px";G.fontFamily=P.family;G.color=P.color;G.textAlign="center";I.position=K.position="absolute";J.style.width=H.getData("width")+"px";J.style.height=H.getData("height")+"px";I.left=K.left="0px";O.innerHTML=H.name;J.appendChild(E)},onPlaceLabel:function(U,P){if(!A[P.id]){return}var T=A[P.id],G=T.wrapper.style,E=T.label.style,O=T.aggregate.style,V=x.type.split(":")[0]=="grouped",F=x.orientation=="horizontal",K=P.getData("dimArray"),I=P.getData("valueArray"),M=(V&&F)?Math.max.apply(null,K):P.getData("width"),L=(V&&!F)?Math.max.apply(null,K):P.getData("height"),J=parseInt(G.fontSize,10),N=U.style;if(K&&I){G.width=O.width=E.width=U.style.width=M+"px";for(var S=0,Q=I.length,R=0;S<Q;S++){if(K[S]>0){R+=I[S]}}if(x.showLabels(P.name,R,P)){E.display=""}else{E.display="none"}var H=x.showAggregates(P.name,R,P);if(H!==false){O.display=""}else{O.display="none"}if(x.orientation=="horizontal"){O.textAlign="right";E.textAlign="left";E.textIndex=O.textIndent=x.labelOffset+"px";O.top=E.top=(L-J)/2+"px";U.style.height=G.height=L+"px"}else{O.top=(-J-x.labelOffset)+"px";E.top=(x.labelOffset+L)+"px";U.style.top=parseInt(U.style.top,10)-L+"px";U.style.height=G.height=L+"px"}T.aggregate.innerHTML=H!==true?H:R}}});var y=z.canvas.getSize(),C=x.Margin;if(D){z.config.offsetX=y.width/2-C.left-(x.showLabels&&(x.labelOffset+x.Label.size));z.config.offsetY=(C.bottom-C.top)/2}else{z.config.offsetY=-y.height/2+C.bottom+(x.showLabels&&(x.labelOffset+x.Label.size));z.config.offsetX=(C.right-C.left)/2}this.delegate=z;this.canvas=this.delegate.canvas},loadJSON:function(K){if(this.busy){return}this.busy=true;var H=c.time(),C=[],J=this.delegate,N=c.splat(K.label),G=c.splat(K.color||this.colors),L=this.config,w=!!L.type.split(":")[1],z=L.animate,y=L.orientation=="horizontal",A=this;for(var I=0,x=K.values,E=x.length;I<E;I++){var M=x[I];var B=c.splat(x[I].values);var F=0;C.push({id:H+M.label,name:M.label,data:{value:B,"$valueArray":B,"$colorArray":G,"$stringArray":N,"$gradient":w,"$config":L},children:[]})}var D={id:H+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:C};J.loadJSON(D);this.normalizeDims();J.compute();J.select(J.root);if(z){if(y){J.fx.animate({modes:["node-property:width:dimArray"],duration:1500,onComplete:function(){A.busy=false}})}else{J.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){A.busy=false}})}}else{this.busy=false}},updateJSON:function(y,C){if(this.busy){return}this.busy=true;this.select(false,false,false);var z=this.delegate;var B=z.graph;var x=y.values;var w=this.config.animate;var A=this;var D=this.config.orientation=="horizontal";c.each(x,function(E){var F=B.getByName(E.label);if(F){F.setData("valueArray",c.splat(E.values));if(y.label){F.setData("stringArray",c.splat(y.label))}}});this.normalizeDims();z.compute();z.select(z.root);if(w){if(D){z.fx.animate({modes:["node-property:width:dimArray"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}else{z.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}}},select:function(y,w){if(!this.config.hoveredColor){return}var x=this.selected;if(x.id!=y||x.name!=w){x.id=y;x.name=w;x.color=this.config.hoveredColor;this.delegate.graph.eachNode(function(z){if(y==z.id){z.setData("border",x)}else{z.setData("border",false)}});this.delegate.plot()}},getLegend:function(){var y={};var z;this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var x=0,w=this.config.type.split(":")[0]=="stacked";this.delegate.graph.eachNode(function(A){var y=A.getData("valueArray"),z=0;if(!y){return}if(w){c.each(y,function(B){z+=+B})}else{z=Math.max.apply(null,y)}x=x>z?x:z});return x},setBarType:function(w){this.config.type=w;this.delegate.config.Node.type="barchart-"+w.split(":")[0]},normalizeDims:function(){var G=this.delegate.graph.getNode(this.delegate.root),B=0;G.eachAdjacency(function(){B++});var D=this.getMaxValue()||1,J=this.delegate.canvas.getSize(),z=this.config,C=z.Margin,H=C.left+C.right,A=C.top+C.bottom,x=z.orientation=="horizontal",w=(J[x?"height":"width"]-(x?A:H)-(B-1)*z.barsOffset)/B,y=z.animate,I=J[x?"width":"height"]-(x?H:A)-(!x&&z.showAggregates&&(z.Label.size+z.labelOffset))-(z.showLabels&&(z.Label.size+z.labelOffset)),F=x?"height":"width",E=x?"width":"height";this.delegate.graph.eachNode(function(N){var M=0,K=[];c.each(N.getData("valueArray"),function(O){M+=+O;K.push(0)});N.setData(F,w);if(y){N.setData(E,M*I/D,"end");N.setData("dimArray",c.map(N.getData("valueArray"),function(O){return O*I/D}),"end");var L=N.getData("dimArray");if(!L){N.setData("dimArray",K)}}else{N.setData(E,M*I/D);N.setData("dimArray",c.map(N.getData("valueArray"),function(O){return O*I/D}))}})}});n.PieChart={$extend:true,animate:true,offset:25,sliceOffset:0,labelOffset:3,type:"stacked",hoveredColor:"#9fd4ff",Events:{enable:false,onClick:c.empty},Tips:{enable:false,onShow:c.empty,onHide:c.empty},showLabels:true,resizeLabels:false,updateHeights:false};g.Radial=new q({compute:function(x){var y=c.splat(x||["current","start","end"]);f.compute(this.graph,y,this.config);this.graph.computeLevels(this.root,0,"ignore");var w=this.createLevelDistanceFunc();this.computeAngularWidths(y);this.computePositions(y,w)},computePositions:function(D,A){var F=D;var E=this.graph;var B=E.getNode(this.root);var C=this.parent;var w=this.config;for(var y=0,x=F.length;y<x;y++){var z=F[y];B.setPos(k(0,0),z);B.setData("span",Math.PI*2,z)}B.angleSpan={begin:0,end:2*Math.PI};E.eachBFS(this.root,function(K){var Q=K.angleSpan.end-K.angleSpan.begin;var S=K.angleSpan.begin;var R=A(K);var T=0,G=[],J={};K.eachSubnode(function(W){T+=W._treeAngularWidth;for(var X=0,V=F.length;X<V;X++){var Z=F[X],Y=W.getData("dim",Z);J[Z]=(Z in J)?(Y>J[Z]?Y:J[Z]):Y}G.push(W)},"ignore");if(C&&C.id==K.id&&G.length>0&&G[0].dist){G.sort(function(W,V){return(W.dist>=V.dist)-(W.dist<=V.dist)})}for(var M=0,O=G.length;M<O;M++){var I=G[M];if(!I._flag){var U=I._treeAngularWidth/T*Q;var H=S+U/2;for(var N=0,L=F.length;N<L;N++){var P=F[N];I.setPos(k(H,R),P);I.setData("span",U,P);I.setData("dim-quotient",I.getData("dim",P)/J[P],P)}I.angleSpan={begin:S,end:S+U};S+=U}}},"ignore")},setAngularWidthForNodes:function(w){this.graph.eachBFS(this.root,function(z,x){var y=z.getData("angularWidth",w[0])||5;z._angularWidth=y/x},"ignore")},setSubtreesAngularWidth:function(){var w=this;this.graph.eachNode(function(x){w.setSubtreeAngularWidth(x)},"ignore")},setSubtreeAngularWidth:function(z){var y=this,x=z._angularWidth,w=0;z.eachSubnode(function(A){y.setSubtreeAngularWidth(A);w+=A._treeAngularWidth},"ignore");z._treeAngularWidth=Math.max(x,w)},computeAngularWidths:function(w){this.setAngularWidthForNodes(w);this.setSubtreesAngularWidth()}});$jit.Sunburst=new q({Implements:[d,o,g.Radial],initialize:function(w){var y=$jit.Sunburst;var x={interpolation:"linear",levelDistance:100,Node:{type:"multipie",height:0},Edge:{type:"none"},Label:{textAlign:"start",textBaseline:"middle"}};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),x,w);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={klass:b,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new y.Label[z.Label.type](this);this.fx=new y.Plot(this,y);this.op=new y.Op(this);this.json=null;this.root=null;this.rotated=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var w=this.config.levelDistance;return function(x){return(x._depth+1)*w}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},rotate:function(y,z,x){var w=y.getPos(x.property||"current").getp(true).theta;this.rotated=y;this.rotateAngle(-w,z,x)},rotateAngle:function(y,B,x){var z=this;var w=c.merge(this.config,x||{},{modes:["polar"]});var A=x.property||(B==="animate"?"end":"current");if(B==="animate"){this.fx.animation.pause()}this.graph.eachNode(function(D){var C=D.getPos(A);C.theta+=y;if(C.theta<0){C.theta+=Math.PI*2}});if(B=="animate"){this.fx.animate(w)}else{if(B=="replot"){this.fx.plot();this.busy=false}}},plot:function(){this.fx.plot()}});$jit.Sunburst.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native,initialize:function(x){this.viz=x;this.label=x.config.Label;this.config=x.config},renderLabel:function(C,E,G){var N=E.getData("span");if(N<Math.PI/2&&Math.tan(N)*this.config.levelDistance*E._depth<10){return}var O=C.getCtx();var A=O.measureText(E.name);if(E.id==this.viz.root){var M=-A.width/2,K=0,L=0;var z=0}else{var D=5;var z=G.levelDistance-D;var J=E.pos.clone();J.rho+=D;var B=J.getp(true);var H=J.getc(true);var M=H.x,K=H.y;var F=Math.PI;var I=(B.theta>F/2&&B.theta<3*F/2);var L=I?B.theta+F:B.theta;if(I){M-=Math.abs(Math.cos(B.theta)*A.width);K+=Math.sin(B.theta)*A.width}else{if(E.id==this.viz.root){M-=A.width/2}}}O.save();O.translate(M,K);O.rotate(L);O.fillText(E.name,0,0);O.restore()}});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(N,C,E){var J=C.pos.getc(true),M=this.viz,A=this.viz.canvas;var F=A.getSize();var B={x:Math.round(J.x+F.width/2),y:Math.round(J.y+F.height/2)};N.setAttribute("x",B.x);N.setAttribute("y",B.y);var G=N.getBBox();if(G){var L=N.getAttribute("x");var I=N.getAttribute("y");var z=C.pos.getp(true);var D=Math.PI;var H=(z.theta>D/2&&z.theta<3*D/2);if(H){N.setAttribute("x",L-G.width);N.setAttribute("y",I-G.height)}else{if(C.id==M.root){N.setAttribute("x",L-G.width/2)}}var K=H?z.theta+D:z.theta;if(C._depth){N.setAttribute("transform","rotate("+K*360/(2*D)+" "+L+" "+I+")")}}E.onPlaceLabel(N,C)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(G,A,C){var E=A.pos.clone(),y=this.viz.canvas,F=A.getData("height"),B=((F||A._depth==0)?F:this.viz.config.levelDistance)/2,D=y.getSize();E.rho+=B;E=E.getc(true);var z={x:Math.round(E.x+D.width/2),y:Math.round(E.y+D.height/2)};var x=G.style;x.left=z.x+"px";x.top=z.y+"px";x.display=this.fitsInCanvas(z,y)?"":"none";C.onPlaceLabel(G,A)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false),anglecontains:function(B,D){var A=B.getData("span")/2,y=B.pos.theta;var z=y-A,x=y+A;if(z<0){z+=Math.PI*2}var C=Math.atan2(D.y,D.x);if(C<0){C+=Math.PI*2}if(z>x){return(C>z&&C<=Math.PI*2)||C<x}else{return C>z&&C<x}}},pie:{render:function(C,A){var G=C.getData("span")/2,z=C.pos.theta;var B=z-G,D=z+G;var F=C.pos.getp(true);var x=new b(F.rho,B);var y=x.getc(true);x.theta=D;var E=x.getc(true);var H=A.getCtx();H.beginPath();H.moveTo(0,0);H.lineTo(y.x,y.y);H.moveTo(0,0);H.lineTo(E.x,E.y);H.moveTo(0,0);H.arc(0,0,F.rho*C.getData("dim-quotient"),B,D,false);H.fill()},contains:function(z,B){if(this.nodeTypes.none.anglecontains.call(this,z,B)){var x=Math.sqrt(B.x*B.x+B.y*B.y);var y=this.config.levelDistance,A=z._depth;return(x<=y*A)}return false}},multipie:{render:function(D,B){var K=D.getData("height");var E=K?K:this.config.levelDistance;var J=D.getData("span")/2,A=D.pos.theta;var C=A-J,G=A+J;var I=D.pos.getp(true);var y=new b(I.rho,C);var z=y.getc(true);y.theta=G;var H=y.getc(true);y.rho+=E;var x=y.getc(true);y.theta=C;var F=y.getc(true);var L=B.getCtx();L.moveTo(0,0);L.beginPath();L.arc(0,0,I.rho,C,G,false);L.arc(0,0,I.rho+E,G,C,true);L.moveTo(z.x,z.y);L.lineTo(F.x,F.y);L.moveTo(H.x,H.y);L.lineTo(x.x,x.y);L.fill();if(D.collapsed){L.save();L.lineWidth=2;L.moveTo(0,0);L.beginPath();L.arc(0,0,I.rho+E+5,G-0.01,C+0.01,true);L.stroke();L.restore()}},contains:function(A,D){if(this.nodeTypes.none.anglecontains.call(this,A,D)){var y=Math.sqrt(D.x*D.x+D.y*D.y);var x=A.getData("height");var B=x?x:this.config.levelDistance;var z=this.config.levelDistance,C=A._depth;return(y>=z*C)&&(y<=(z*C+B))}return false}},"gradient-multipie":{render:function(A,x){var F=x.getCtx();var E=A.getData("height");var B=E?E:this.config.levelDistance;var y=F.createRadialGradient(0,0,A.getPos().rho,0,0,A.getPos().rho+B);var D=c.hexToRgb(A.getData("color")),C=[];c.each(D,function(G){C.push(parseInt(G*0.5,10))});var z=c.rgbToHex(C);y.addColorStop(0,z);y.addColorStop(1,A.getData("color"));F.fillStyle=y;this.nodeTypes.multipie.render.call(this,A,x)},contains:function(x,y){return this.nodeTypes.multipie.contains.call(this,x,y)}},"gradient-pie":{render:function(C,z){var x=z.getCtx();var D=x.createRadialGradient(0,0,0,0,0,C.getPos().rho);var B=c.hexToRgb(C.getData("color")),y=[];c.each(B,function(E){y.push(parseInt(E*0.5,10))});var A=c.rgbToHex(y);D.addColorStop(1,A);D.addColorStop(0,C.getData("color"));x.fillStyle=D;this.nodeTypes.pie.render.call(this,C,z)},contains:function(x,y){return this.nodeTypes.pie.contains.call(this,x,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}},hyperline:{render:function(x,y){var B=x.nodeFrom.pos.getc(),A=x.nodeTo.pos.getc(),z=Math.max(B.norm(),A.norm());this.edgeHelper.hyperline.render(B.$scale(1/z),A.$scale(1/z),z,y)},contains:c.lambda(false)}})})($jit.Sunburst);$jit.Sunburst.Plot.NodeTypes.implement({"piechart-stacked":{render:function(U,A){var T=U.pos.getp(true),C=U.getData("dimArray"),S=U.getData("valueArray"),G=U.getData("colorArray"),z=G.length,M=U.getData("stringArray"),P=U.getData("span")/2,K=U.pos.theta,F=K-P,J=K+P,R=new b;var N=A.getCtx(),L={},I=U.getData("gradient"),D=U.getData("border"),Z=U.getData("config"),ai=Z.showLabels,Y=Z.resizeLabels,ab=Z.Label;var ae=Z.sliceOffset*Math.cos((F+J)/2);var E=Z.sliceOffset*Math.sin((F+J)/2);if(G&&C&&M){for(var af=0,ac=C.length,w=0,X=0;af<ac;af++){var B=C[af],ag=G[af%z];if(B<=0){continue}N.fillStyle=N.strokeStyle=ag;if(I&&B){var ad=N.createRadialGradient(ae,E,w+Z.sliceOffset,ae,E,w+B+Z.sliceOffset);var x=c.hexToRgb(ag),W=c.map(x,function(al){return(al*0.8)>>0}),y=c.rgbToHex(W);ad.addColorStop(0,ag);ad.addColorStop(0.5,ag);ad.addColorStop(1,y);N.fillStyle=ad}R.rho=w+Z.sliceOffset;R.theta=F;var ah=R.getc(true);R.theta=J;var O=R.getc(true);R.rho+=B;var aj=R.getc(true);R.theta=F;var Q=R.getc(true);N.beginPath();N.arc(ae,E,w+0.01,F,J,false);N.arc(ae,E,w+B+0.01,J,F,true);N.fill();if(D&&D.name==M[af]){L.acum=w;L.dimValue=C[af];L.begin=F;L.end=J}w+=(B||0);X+=(S[af]||0)}if(D){N.save();N.globalCompositeOperation="source-over";N.lineWidth=2;N.strokeStyle=D.color;var aa=F<J?1:-1;N.beginPath();N.arc(ae,E,L.acum+0.01+1,L.begin,L.end,false);N.arc(ae,E,L.acum+L.dimValue+0.01-1,L.end,L.begin,true);N.closePath();N.stroke();N.restore()}if(ai&&ab.type=="Native"){N.save();N.fillStyle=N.strokeStyle=ab.color;var V=Y?U.getData("normalizedDim"):1,H=(ab.size*V)>>0;H=H<+Y?+Y:H;N.font=ab.style+" "+H+"px "+ab.family;N.textBaseline="middle";N.textAlign="center";R.rho=w+Z.labelOffset+Z.sliceOffset;R.theta=U.pos.theta;var ak=R.getc(true);N.fillText(U.name,ak.x,ak.y);N.restore()}}},contains:function(z,D){if(this.nodeTypes.none.anglecontains.call(this,z,D)){var F=Math.sqrt(D.x*D.x+D.y*D.y);var w=this.config.levelDistance,C=z._depth;var x=z.getData("config");if(F<=w*C+x.sliceOffset){var G=z.getData("dimArray");for(var B=0,A=G.length,E=x.sliceOffset;B<A;B++){var y=G[B];if(F>=E&&F<=E+y){return{name:z.getData("stringArray")[B],color:z.getData("colorArray")[B],value:z.getData("valueArray")[B],label:z.name}}E+=y}}return false}return false}}});$jit.PieChart=new q({sb:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(w){this.controller=this.config=c.merge(n("Canvas","PieChart","Label"),{Label:{type:"Native"}},w);this.initializeViz()},initializeViz:function(){var x=this.config,B=this;var w=x.type.split(":")[0];var A=new $jit.Sunburst({injectInto:x.injectInto,width:x.width,height:x.height,useCanvas:x.useCanvas,withLabels:x.Label.type!="Native",Label:{type:x.Label.type},Node:{overridable:true,type:"piechart-"+w,width:1,height:1},Edge:{type:"none"},Tips:{enable:x.Tips.enable,type:"Native",force:true,onShow:function(F,E,C){var D=C;x.Tips.onShow(F,D,E)}},Events:{enable:true,type:"Native",onClick:function(E,F,C){if(!x.Events.enable){return}var D=F.getContains();x.Events.onClick(D,F,C)},onMouseMove:function(E,F,C){if(!x.hoveredColor){return}if(E){var D=F.getContains();B.select(E.id,D.name,D.index)}else{B.select(false,false,false)}}},onCreateLabel:function(F,E){var C=x.Label;if(x.showLabels){var D=F.style;D.fontSize=C.size+"px";D.fontFamily=C.family;D.color=C.color;D.textAlign="center";F.innerHTML=E.name}},onPlaceLabel:function(S,M){if(!x.showLabels){return}var G=M.pos.getp(true),J=M.getData("dimArray"),P=M.getData("span")/2,H=M.pos.theta,R=H-P,D=H+P,U=new b;var L=x.showLabels,F=x.resizeLabels,I=x.Label;if(J){for(var Q=0,N=J.length,O=0;Q<N;Q++){O+=J[Q]}var T=F?M.getData("normalizedDim"):1,C=(I.size*T)>>0;C=C<+F?+F:C;S.style.fontSize=C+"px";U.rho=O+x.labelOffset+x.sliceOffset;U.theta=(R+D)/2;var G=U.getc(true);var E=B.canvas.getSize();var K={x:Math.round(G.x+E.width/2),y:Math.round(G.y+E.height/2)};S.style.left=K.x+"px";S.style.top=K.y+"px"}}});var z=A.canvas.getSize(),y=Math.min;A.config.levelDistance=y(z.width,z.height)/2-x.offset-x.sliceOffset;this.delegate=A;this.canvas=this.delegate.canvas;this.canvas.getCtx().globalCompositeOperation="lighter"},loadJSON:function(K){var H=c.time(),B=[],J=this.delegate,N=c.splat(K.label),D=N.length,G=c.splat(K.color||this.colors),y=G.length,L=this.config,w=!!L.type.split(":")[1],z=L.animate,F=D==1;for(var I=0,x=K.values,E=x.length;I<E;I++){var M=x[I];var A=c.splat(M.values);B.push({id:H+M.label,name:M.label,data:{value:A,"$valueArray":A,"$colorArray":F?c.splat(G[I%y]):G,"$stringArray":N,"$gradient":w,"$config":L,"$angularWidth":c.reduce(A,function(O,P){return O+P})},children:[]})}var C={id:H+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:B};J.loadJSON(C);this.normalizeDims();J.refresh();if(z){J.fx.animate({modes:["node-property:dimArray"],duration:1500})}},updateJSON:function(y,C){if(this.busy){return}this.busy=true;var z=this.delegate;var B=z.graph;var x=y.values;var w=this.config.animate;var A=this;c.each(x,function(D){var F=B.getByName(D.label),E=c.splat(D.values);if(F){F.setData("valueArray",E);F.setData("angularWidth",c.reduce(E,function(G,H){return G+H}));if(y.label){F.setData("stringArray",c.splat(y.label))}}});this.normalizeDims();if(w){z.compute("end");z.fx.animate({modes:["node-property:dimArray:span","linear"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}else{z.refresh()}},select:function(y,w){if(!this.config.hoveredColor){return}var x=this.selected;if(x.id!=y||x.name!=w){x.id=y;x.name=w;x.color=this.config.hoveredColor;this.delegate.graph.eachNode(function(z){if(y==z.id){z.setData("border",x)}else{z.setData("border",false)}});this.delegate.plot()}},getLegend:function(){var y={};var z;this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var w=0;this.delegate.graph.eachNode(function(z){var x=z.getData("valueArray"),y=0;c.each(x,function(A){y+=+A});w=w>y?w:y});return w},normalizeDims:function(){var x=this.delegate.graph.getNode(this.delegate.root),w=0;x.eachAdjacency(function(){w++});var B=this.getMaxValue()||1,A=this.config,y=A.animate,z=this.delegate.config.levelDistance;this.delegate.graph.eachNode(function(G){var F=0,C=[];c.each(G.getData("valueArray"),function(H){F+=+H;C.push(1)});var E=(C.length==1)&&!A.updateHeights;if(y){G.setData("dimArray",c.map(G.getData("valueArray"),function(H){return E?z:(H*z/B)}),"end");var D=G.getData("dimArray");if(!D){G.setData("dimArray",C)}}else{G.setData("dimArray",c.map(G.getData("valueArray"),function(H){return E?z:(H*z/B)}))}G.setData("normalizedDim",F/B)})}});g.TM={};g.TM.SliceAndDice=new q({compute:function(B){var x=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(x);var z=this.canvas.getSize(),y=this.config,A=z.width,w=z.height;this.graph.computeLevels(this.root,0,"ignore");x.getPos(B).setc(-A/2,-w/2);x.setData("width",A,B);x.setData("height",w+y.titleHeight,B);this.computePositions(x,x,this.layout.orientation,B);this.controller.onAfterCompute(x)},computePositions:function(F,D,P,y){var M=0;F.eachSubnode(function(R){M+=R.getData("area",y)});var Q=this.config,N=Q.offset,J=F.getData("width",y),H=Math.max(F.getData("height",y)-Q.titleHeight,0),x=F==D?1:(D.getData("area",y)/M);var I,G,L,B,A,E,C;var O=(P=="h");if(O){P="v";I=H;G=J*x;L="height";B="y";A="x";E=Q.titleHeight;C=0}else{P="h";I=H*x;G=J;L="width";B="x";A="y";E=0;C=Q.titleHeight}var w=D.getPos(y);D.setData("width",G,y);D.setData("height",I,y);var K=0,z=this;D.eachSubnode(function(S){var R=S.getPos(y);R[B]=K+w[B]+E;R[A]=w[A]+C;z.computePositions(D,S,P,y);K+=S.getData(L,y)})}});g.TM.Area={compute:function(w){w=w||"current";var C=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(C);var y=this.config,F=this.canvas.getSize(),x=F.width,E=F.height,D=y.offset,z=x-D,B=E-D;this.graph.computeLevels(this.root,0,"ignore");C.getPos(w).setc(-x/2,-E/2);C.setData("width",x,w);C.setData("height",E,w);var A={top:-E/2+y.titleHeight,left:-x/2,width:z,height:B-y.titleHeight};this.computePositions(C,A,w);this.controller.onAfterCompute(C)},computeDim:function(B,C,E,A,z,x){if(B.length+C.length==1){var y=(B.length==1)?B:C;this.layoutLast(y,E,A,x);return}if(B.length>=2&&C.length==0){C=[B.shift()]}if(B.length==0){if(C.length>0){this.layoutRow(C,E,A,x)}return}var D=B[0];if(z(C,E)>=z([D].concat(C),E)){this.computeDim(B.slice(1),C.concat([D]),E,A,z,x)}else{var F=this.layoutRow(C,E,A,x);this.computeDim(B,[],F.dim,F,z,x)}},worstAspectRatio:function(x,F){if(!x||x.length==0){return Number.MAX_VALUE}var y=0,G=0,B=Number.MAX_VALUE;for(var D=0,C=x.length;D<C;D++){var z=x[D]._area;y+=z;B=B<z?B:z;G=G>z?G:z}var E=F*F,A=y*y;return Math.max(E*G/A,A/(E*B))},avgAspectRatio:function(B,y){if(!B||B.length==0){return Number.MAX_VALUE}var D=0;for(var z=0,x=B.length;z<x;z++){var C=B[z]._area;var A=C/y;D+=y>A?y/A:A/y}return D/x},layoutLast:function(y,x,B,A){var z=y[0];z.getPos(A).setc(B.left,B.top);z.setData("width",B.width,A);z.setData("height",B.height,A)}};g.TM.Squarified=new q({Implements:g.TM.Area,computePositions:function(A,D,x){var z=this.config,F=Math.max;if(D.width>=D.height){this.layout.orientation="h"}else{this.layout.orientation="v"}var w=A.getSubnodes([1,1],"ignore");if(w.length>0){this.processChildrenLayout(A,w,D,x);for(var C=0,B=w.length;C<B;C++){var G=w[C],H=z.offset,I=F(G.getData("height",x)-H-z.titleHeight,0),y=F(G.getData("width",x)-H,0),E=G.getPos(x);D={width:y,height:I,top:E.y+z.titleHeight,left:E.x};this.computePositions(G,D,x)}}},processChildrenLayout:function(G,w,C,x){var A=C.width*C.height;var B,y=w.length,D=0,H=[];for(B=0;B<y;B++){H[B]=parseFloat(w[B].getData("area",x));D+=H[B]}for(B=0;B<y;B++){w[B]._area=A*H[B]/D}var z=this.layout.horizontal()?C.height:C.width;w.sort(function(J,I){var K=I._area-J._area;return K?K:(I.id==J.id?0:(I.id<J.id?1:-1))});var F=[w[0]];var E=w.slice(1);this.squarify(E,F,z,C,x)},squarify:function(y,B,x,A,z){this.computeDim(y,B,x,A,this.worstAspectRatio,z)},layoutRow:function(y,x,A,z){if(this.layout.horizontal()){return this.layoutV(y,x,A,z)}else{return this.layoutH(y,x,A,z)}},layoutV:function(x,I,E,y){var J=0,A=function(w){return w};c.each(x,function(w){J+=w._area});var z=A(J/I),F=0;for(var C=0,B=x.length;C<B;C++){var D=A(x[C]._area/z);var G=x[C];G.getPos(y).setc(E.left,E.top+F);G.setData("width",z,y);G.setData("height",D,y);F+=D}var H={height:E.height,width:E.width-z,top:E.top,left:E.left+z};H.dim=Math.min(H.width,H.height);if(H.dim!=H.height){this.layout.change()}return H},layoutH:function(x,G,C,y){var I=0;c.each(x,function(w){I+=w._area});var H=I/G,D=C.top,z=0;for(var B=0,A=x.length;B<A;B++){var E=x[B];var G=E._area/H;E.getPos(y).setc(C.left+z,D);E.setData("width",G,y);E.setData("height",H,y);z+=G}var F={height:C.height-H,width:C.width,top:C.top+H,left:C.left};F.dim=Math.min(F.width,F.height);if(F.dim!=F.width){this.layout.change()}return F}});g.TM.Strip=new q({Implements:g.TM.Area,computePositions:function(A,D,x){var w=A.getSubnodes([1,1],"ignore"),z=this.config,F=Math.max;if(w.length>0){this.processChildrenLayout(A,w,D,x);for(var C=0,B=w.length;C<B;C++){var G=w[C];var H=z.offset,I=F(G.getData("height",x)-H-z.titleHeight,0),y=F(G.getData("width",x)-H,0);var E=G.getPos(x);D={width:y,height:I,top:E.y+z.titleHeight,left:E.x};this.computePositions(G,D,x)}}},processChildrenLayout:function(G,w,B,x){var z=B.width*B.height;var A,y=w.length,C=0,H=[];for(A=0;A<y;A++){H[A]=+w[A].getData("area",x);C+=H[A]}for(A=0;A<y;A++){w[A]._area=z*H[A]/C}var F=this.layout.horizontal()?B.width:B.height;var E=[w[0]];var D=w.slice(1);this.stripify(D,E,F,B,x)},stripify:function(y,B,x,A,z){this.computeDim(y,B,x,A,this.avgAspectRatio,z)},layoutRow:function(y,x,A,z){if(this.layout.horizontal()){return this.layoutH(y,x,A,z)}else{return this.layoutV(y,x,A,z)}},layoutV:function(x,G,D,y){var H=0;c.each(x,function(w){H+=w._area});var z=H/G,E=0;for(var B=0,A=x.length;B<A;B++){var F=x[B];var C=F._area/z;F.getPos(y).setc(D.left,D.top+(G-C-E));F.setData("width",z,y);F.setData("height",C,y);E+=C}return{height:D.height,width:D.width-z,top:D.top,left:D.left+z,dim:G}},layoutH:function(x,F,C,y){var H=0;c.each(x,function(w){H+=w._area});var G=H/F,D=C.height-G,z=0;for(var B=0,A=x.length;B<A;B++){var E=x[B];var I=E._area/G;E.getPos(y).setc(C.left+z,C.top+D);E.setData("width",I,y);E.setData("height",G,y);z+=I}return{height:C.height-G,width:C.width,top:C.top,left:C.left,dim:F}}});g.Icicle=new q({compute:function(E){E=E||"current";var D=this.graph.getNode(this.root),z=this.config,H=this.canvas.getSize(),w=H.width,G=H.height,A=z.offset,C=z.constrained?z.levelsToShow:Number.MAX_VALUE;this.controller.onBeforeCompute(D);e.Util.computeLevels(this.graph,D.id,0,"ignore");var F=0;e.Util.eachLevel(D,0,false,function(J,I){if(I>F){F=I}});var y=this.graph.getNode(this.clickedNode&&this.clickedNode.id||D.id);var x=Math.min(F,C-1);var B=y._depth;if(this.layout.horizontal()){this.computeSubtree(y,-w/2,-G/2,w/(x+1),G,B,x,E)}else{this.computeSubtree(y,-w/2,-G/2,w,G/(x+1),B,x,E)}},computeSubtree:function(G,I,F,w,L,E,A,H){G.getPos(H).setc(I,F);G.setData("width",w,H);G.setData("height",L,H);var C,K=0,J=0;var z=e.Util.getSubnodes(G,[1,1],"ignore");if(!z.length){return}c.each(z,function(x){J+=x.getData("dim")});for(var D=0,B=z.length;D<B;D++){if(this.layout.horizontal()){C=L*z[D].getData("dim")/J;this.computeSubtree(z[D],I+w,F,w,C,E,A,H);F+=C}else{C=w*z[D].getData("dim")/J;this.computeSubtree(z[D],I,F+L,C,L,E,A,H);I+=C}}}});$jit.Icicle=new q({Implements:[d,o,g.Icicle],layout:{orientation:"h",vertical:function(){return this.orientation=="v"},horizontal:function(){return this.orientation=="h"},change:function(){this.orientation=this.vertical()?"h":"v"}},initialize:function(w){var x={animate:false,orientation:"h",offset:2,levelsToShow:Number.MAX_VALUE,constrained:false,Node:{type:"rectangle",overridable:true},Edge:{type:"none"},Label:{type:"Native"},duration:700,fps:45};var z=n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label");this.controller=this.config=c.merge(z,x,w);this.layout.orientation=this.config.orientation;var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={klass:p,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);this.labels=new $jit.Icicle.Label[this.config.Label.type](this);this.fx=new $jit.Icicle.Plot(this,$jit.Icicle);this.op=new $jit.Icicle.Op(this);this.group=new $jit.Icicle.Group(this);this.clickedNode=null;this.initializeExtras()},refresh:function(){var w=this.config.Label.type;if(w!="Native"){var x=this;this.graph.eachNode(function(y){x.labels.hideLabel(y,false)})}this.compute();this.plot()},plot:function(){this.fx.plot(this.config)},enter:function(y){if(this.busy){return}this.busy=true;var x=this,w=this.config;var z={onComplete:function(){if(w.request){x.compute()}if(w.animate){x.graph.nodeList.setDataset(["current","end"],{alpha:[1,0]});e.Util.eachSubgraph(y,function(A){A.setData("alpha",1,"end")},"ignore");x.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){x.clickedNode=y;x.compute("end");x.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){x.busy=false;x.clickedNode=y}})}})}else{x.clickedNode=y;x.busy=false;x.refresh()}}};if(w.request){this.requestNodes(clickedNode,z)}else{z.onComplete()}},out:function(){if(this.busy){return}var B=this,A=e.Util,y=this.config,D=this.graph,x=A.getParents(D.getNode(this.clickedNode&&this.clickedNode.id||this.root)),z=x[0],w=z,C=this.clickedNode;this.busy=true;this.events.hoveredNode=false;if(!z){this.busy=false;return}callback={onComplete:function(){B.clickedNode=z;if(y.request){B.requestNodes(z,{onComplete:function(){B.compute();B.plot();B.busy=false}})}else{B.compute();B.plot();B.busy=false}}};if(y.animate){this.clickedNode=w;this.compute("end");this.clickedNode=C;this.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){B.clickedNode=w;D.nodeList.setDataset(["current","end"],{alpha:[0,1]});A.eachSubgraph(C,function(E){E.setData("alpha",1)},"ignore");B.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(y,z){var x=c.merge(this.controller,z),w=this.config.constrained?this.config.levelsToShow:Number.MAX_VALUE;if(x.request){var B=[],A=y._depth;e.Util.eachLevel(y,0,w,function(C){if(C.drawn&&!e.Util.anySubnode(C)){B.push(C);C._level=C._depth-A;if(this.config.constrained){C._level=w-C._level}}});this.group.requestNodes(B,x)}else{x.onComplete()}}});$jit.Icicle.Op=new q({Implements:e.Op});$jit.Icicle.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){e.Util.computeLevels(w.graph,w.root,0);y()}}})}}});$jit.Icicle.Plot=new q({Implements:e.Plot,plot:function(A,y){A=A||this.viz.controller;var w=this.viz,B=w.graph,x=B.getNode(w.clickedNode&&w.clickedNode.id||w.root),z=x._depth;w.canvas.clear();this.plotTree(x,c.merge(A,{withLabels:true,hideLabels:false,plotSubtree:function(C,D){return !w.config.constrained||(D._depth-z<w.config.levelsToShow)}}),y)}});$jit.Icicle.Label={};$jit.Icicle.Label.Native=new q({Implements:e.Label.Native,renderLabel:function(x,y,A){var D=x.getCtx(),w=y.getData("width"),C=y.getData("height"),E=y.getLabelData("size"),z=D.measureText(y.name);if(C<(E*1.5)||w<z.width){return}var B=y.pos.getc(true);D.fillText(y.name,B.x+w/2,B.y+C/2)}});$jit.Icicle.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(w){this.viz=w},placeLabel:function(x,A,y){var C=A.pos.getc(true),z=this.viz.canvas;var w=z.getSize();var B={x:Math.round(C.x+w.width/2),y:Math.round(C.y+w.height/2)};x.setAttribute("x",B.x);x.setAttribute("y",B.y);y.onPlaceLabel(x,A)}});$jit.Icicle.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(w){this.viz=w},placeLabel:function(x,B,y){var D=B.pos.getc(true),z=this.viz.canvas;var w=z.getSize();var C={x:Math.round(D.x+w.width/2),y:Math.round(D.y+w.height/2)};var A=x.style;A.left=C.x+"px";A.top=C.y+"px";A.display="";y.onPlaceLabel(x,B)}});$jit.Icicle.Plot.NodeTypes=new q({none:{render:c.empty},rectangle:{render:function(z,x,K){var y=this.viz.config;var C=y.offset;var w=z.getData("width");var H=z.getData("height");var B=z.getData("border");var G=z.pos.getc(true);var F=G.x+C/2,D=G.y+C/2;var J=x.getCtx();if(w-C<2||H-C<2){return}if(y.cushion){var A=z.getData("color");var I=J.createRadialGradient(F+(w-C)/2,D+(H-C)/2,1,F+(w-C)/2,D+(H-C)/2,w<H?H:w);var E=c.rgbToHex(c.map(c.hexToRgb(A),function(L){return L*0.3>>0}));I.addColorStop(0,A);I.addColorStop(1,E);J.fillStyle=I}if(B){J.strokeStyle=B;J.lineWidth=3}J.fillRect(F,D,Math.max(0,w-C),Math.max(0,H-C));B&&J.strokeRect(G.x,G.y,w,H)},contains:function(y,A){if(this.viz.clickedNode&&!$jit.Graph.Util.isDescendantOf(y,this.viz.clickedNode.id)){return false}var z=y.pos.getc(true),x=y.getData("width"),w=y.getData("height");return this.nodeHelper.rectangle.contains({x:z.x+x/2,y:z.y+w/2},A,x,w)}}});$jit.Icicle.Plot.EdgeTypes=new q({none:c.empty});g.ForceDirected=new q({getOptions:function(D){var B=this.canvas.getSize();var y=B.width,A=B.height;var C=0;this.graph.eachNode(function(w){C++});var E=y*A/C,z=Math.sqrt(E);var x=this.config.levelDistance;return{width:y,height:A,tstart:y*0.1,nodef:function(w){return E/(w||1)},edgef:function(w){return z*(w-x)}}},compute:function(x,y){var z=c.splat(x||["current","start","end"]);var w=this.getOptions();f.compute(this.graph,z,this.config);this.graph.computeLevels(this.root,0,"ignore");this.graph.eachNode(function(A){c.each(z,function(B){var C=A.getPos(B);if(C.equals(p.KER)){C.x=w.width/5*(Math.random()-0.5);C.y=w.height/5*(Math.random()-0.5)}A.disp={};c.each(z,function(D){A.disp[D]=r(0,0)})})});this.computePositions(z,w,y)},computePositions:function(A,y,B){var C=this.config.iterations,x=0,z=this;if(B){(function w(){for(var E=B.iter,D=0;D<E;D++){y.t=y.tstart;if(C){y.t*=(1-x++/(C-1))}z.computePositionStep(A,y);if(C&&x>=C){B.onComplete();return}}B.onStep(Math.round(x/(C-1)*100));setTimeout(w,1)})()}else{for(;x<C;x++){y.t=y.tstart*(1-x/(C-1));this.computePositionStep(A,y)}}},computePositionStep:function(D,w){var E=this.graph;var y=Math.min,C=Math.max;var B=r(0,0);E.eachNode(function(G){c.each(D,function(H){G.disp[H].x=0;G.disp[H].y=0});E.eachNode(function(H){if(H.id!=G.id){c.each(D,function(L){var J=G.getPos(L),I=H.getPos(L);B.x=J.x-I.x;B.y=J.y-I.y;var K=B.norm()||1;G.disp[L].$add(B.$scale(w.nodef(K)/K))})}})});var x=!!E.getNode(this.root).visited;E.eachNode(function(G){G.eachAdjacency(function(H){var I=H.nodeTo;if(!!I.visited===x){c.each(D,function(M){var K=G.getPos(M),J=I.getPos(M);B.x=K.x-J.x;B.y=K.y-J.y;var L=B.norm()||1;G.disp[M].$add(B.$scale(-w.edgef(L)/L));I.disp[M].$add(B.$scale(-1))})}});G.visited=!x});var F=w.t,z=w.width/2,A=w.height/2;E.eachNode(function(G){c.each(D,function(J){var H=G.disp[J];var I=H.norm()||1;var J=G.getPos(J);J.$add(r(H.x*y(Math.abs(H.x),F)/I,H.y*y(Math.abs(H.y),F)/I));J.x=y(z,C(-z,J.x));J.y=y(A,C(-A,J.y))})})}});$jit.ForceDirected=new q({Implements:[d,o,g.ForceDirected],initialize:function(x){var w=$jit.ForceDirected;var y={iterations:50,levelDistance:50};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),y,x);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={klass:p,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new w.Label[z.Label.type](this);this.fx=new w.Plot(this,w);this.op=new w.Op(this);this.json=null;this.busy=false;this.initializeExtras()},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},computeIncremental:function(w){w=c.merge({iter:20,property:"end",onStep:c.empty,onComplete:c.empty},w||{});this.config.onBeforeCompute(this.graph.getNode(this.root));this.compute(w.property,w)},plot:function(){this.fx.plot()},animate:function(w){this.fx.animate(c.merge({modes:["linear"]},w||{}))}});$jit.ForceDirected.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};H.setAttribute("x",A.x);H.setAttribute("y",A.y);C.onPlaceLabel(H,B)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize();var B={x:Math.round(G.x*H+A+E.width/2),y:Math.round(G.y*F+y+E.height/2)};var x=I.style;x.left=B.x+"px";x.top=B.y+"px";x.display=this.fitsInCanvas(B,z)?"":"none";D.onPlaceLabel(I,C)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.circle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.ellipse.contains(A,B,y,x)}},square:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.square.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.rectangle.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.rectangle.contains(A,B,y,x)}},triangle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.triangle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.star.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}}})})($jit.ForceDirected);$jit.TM={};var v=$jit.TM;$jit.TM.$extend=true;v.Base={layout:{orientation:"h",vertical:function(){return this.orientation=="v"},horizontal:function(){return this.orientation=="h"},change:function(){this.orientation=this.vertical()?"h":"v"}},initialize:function(w){var x={orientation:"h",titleHeight:13,offset:2,levelsToShow:0,constrained:false,animate:false,Node:{type:"rectangle",overridable:true,width:3,height:3,color:"#444"},Label:{textAlign:"center",textBaseline:"top"},Edge:{type:"none"},duration:700,fps:45};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),x,w);this.layout.orientation=this.config.orientation;var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(y.background){y.background=c.merge({type:"Circles"},y.background)}this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={klass:p,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new v.Label[y.Label.type](this);this.fx=new v.Plot(this);this.op=new v.Op(this);this.group=new v.Group(this);this.geom=new v.Geom(this);this.clickedNode=null;this.busy=false;this.initializeExtras()},refresh:function(){if(this.busy){return}this.busy=true;var x=this;if(this.config.animate){this.compute("end");this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.fx.animate(c.merge(this.config,{modes:["linear","node-property:width:height"],onComplete:function(){x.busy=false}}))}else{var w=this.config.Label.type;if(w!="Native"){var x=this;this.graph.eachNode(function(y){x.labels.hideLabel(y,false)})}this.busy=false;this.compute();this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.plot()}},plot:function(){this.fx.plot()},leaf:function(w){return w.getSubnodes([1,1],"ignore").length==0},enter:function(C){if(this.busy){return}this.busy=true;var y=this,x=this.config,A=this.graph,w=C,z=this.clickedNode;var B={onComplete:function(){if(x.levelsToShow>0){y.geom.setRightLevelToShow(C)}if(x.levelsToShow>0||x.request){y.compute()}if(x.animate){A.nodeList.setData("alpha",0,"end");C.eachSubgraph(function(D){D.setData("alpha",1,"end")},"ignore");y.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){y.clickedNode=w;y.compute("end");y.clickedNode=z;y.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){y.busy=false;y.clickedNode=w}})}})}else{y.busy=false;y.clickedNode=C;y.refresh()}}};if(x.request){this.requestNodes(w,B)}else{B.onComplete()}},out:function(){if(this.busy){return}this.busy=true;this.events.hoveredNode=false;var A=this,y=this.config,C=this.graph,x=C.getNode(this.clickedNode&&this.clickedNode.id||this.root).getParents(),z=x[0],w=z,B=this.clickedNode;if(!z){this.busy=false;return}callback={onComplete:function(){A.clickedNode=z;if(y.request){A.requestNodes(z,{onComplete:function(){A.compute();A.plot();A.busy=false}})}else{A.compute();A.plot();A.busy=false}}};if(y.levelsToShow>0){this.geom.setRightLevelToShow(z)}if(y.animate){this.clickedNode=w;this.compute("end");this.clickedNode=B;this.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){A.clickedNode=w;C.eachNode(function(D){D.setDataset(["current","end"],{alpha:[0,1]})},"ignore");B.eachSubgraph(function(D){D.setData("alpha",1)},"ignore");A.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(y,z){var x=c.merge(this.controller,z),w=this.config.levelsToShow;if(x.request){var B=[],A=y._depth;y.eachLevel(0,w,function(D){var C=w-(D._depth-A);if(D.drawn&&!D.anySubnode()&&C>0){B.push(D);D._level=C}});this.group.requestNodes(B,x)}else{x.onComplete()}},reposition:function(){this.compute("end")}};v.Op=new q({Implements:e.Op,initialize:function(w){this.viz=w}});v.Geom=new q({Implements:e.Geom,getRightLevelToShow:function(){return this.viz.config.levelsToShow},setRightLevelToShow:function(x){var y=this.getRightLevelToShow(),w=this.viz.labels;x.eachLevel(0,y+1,function(A){var z=A._depth-x._depth;if(z>y){A.drawn=false;A.exist=false;A.ignore=true;w.hideLabel(A,false)}else{A.drawn=true;A.exist=true;delete A.ignore}});x.drawn=true;delete x.ignore}});v.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){w.graph.computeLevels(w.root,0);y()}}})}}});v.Plot=new q({Implements:e.Plot,initialize:function(w){this.viz=w;this.config=w.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new u;this.nodeTypes=new v.Plot.NodeTypes;this.edgeTypes=new v.Plot.EdgeTypes;this.labels=w.labels},plot:function(y,x){var w=this.viz,z=w.graph;w.canvas.clear();this.plotTree(z.getNode(w.clickedNode&&w.clickedNode.id||w.root),c.merge(w.config,y||{},{withLabels:true,hideLabels:false,plotSubtree:function(B,A){return B.anySubnode("exist")}}),x)}});v.Label={};v.Label.Native=new q({Implements:e.Label.Native,initialize:function(w){this.config=w.config;this.leaf=w.leaf},renderLabel:function(z,A,B){if(!this.leaf(A)&&!this.config.titleHeight){return}var D=A.pos.getc(true),G=z.getCtx(),w=A.getData("width"),F=A.getData("height"),E=D.x+w/2,C=D.y;G.fillText(A.name,E,C,w)}});v.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(w){this.viz=w;this.leaf=w.leaf;this.config=w.config},placeLabel:function(G,A,B){var E=A.pos.getc(true),x=this.viz.canvas,y=x.translateOffsetX,w=x.translateOffsetY,F=x.scaleOffsetX,D=x.scaleOffsetY,C=x.getSize();var z={x:Math.round(E.x*F+y+C.width/2),y:Math.round(E.y*D+w+C.height/2)};G.setAttribute("x",z.x);G.setAttribute("y",z.y);if(!this.leaf(A)&&!this.config.titleHeight){G.style.display="none"}B.onPlaceLabel(G,A)}});v.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(w){this.viz=w;this.leaf=w.leaf;this.config=w.config},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};var w=H.style;w.left=A.x+"px";w.top=A.y+"px";w.width=B.getData("width")*G+"px";w.height=B.getData("height")*E+"px";w.zIndex=B._depth*100;w.display="";if(!this.leaf(B)&&!this.config.titleHeight){H.style.display="none"}C.onPlaceLabel(H,B)}});v.Plot.NodeTypes=new q({none:{render:c.empty},rectangle:{render:function(z,x,M){var D=this.viz.leaf(z),y=this.config,I=y.offset,C=y.titleHeight,H=z.pos.getc(true),w=z.getData("width"),J=z.getData("height"),B=z.getData("border"),L=x.getCtx(),G=H.x+I/2,E=H.y+I/2;if(w<=I||J<=I){return}if(D){if(y.cushion){var K=L.createRadialGradient(G+(w-I)/2,E+(J-I)/2,1,G+(w-I)/2,E+(J-I)/2,w<J?J:w);var A=z.getData("color");var F=c.rgbToHex(c.map(c.hexToRgb(A),function(N){return N*0.2>>0}));K.addColorStop(0,A);K.addColorStop(1,F);L.fillStyle=K}L.fillRect(G,E,w-I,J-I);if(B){L.save();L.strokeStyle=B;L.strokeRect(G,E,w-I,J-I);L.restore()}}else{if(C>0){L.fillRect(H.x+I/2,H.y+I/2,w-I,C-I);if(B){L.save();L.strokeStyle=B;L.strokeRect(H.x+I/2,H.y+I/2,w-I,J-I);L.restore()}}}},contains:function(z,B){if(this.viz.clickedNode&&!z.isDescendantOf(this.viz.clickedNode.id)||z.ignore){return false}var A=z.pos.getc(true),y=z.getData("width"),x=this.viz.leaf(z),w=x?z.getData("height"):this.config.titleHeight;return this.nodeHelper.rectangle.contains({x:A.x+y/2,y:A.y+w/2},B,y,w)}}});v.Plot.EdgeTypes=new q({none:c.empty});v.SliceAndDice=new q({Implements:[d,o,v.Base,g.TM.SliceAndDice]});v.Squarified=new q({Implements:[d,o,v.Base,g.TM.Squarified]});v.Strip=new q({Implements:[d,o,v.Base,g.TM.Strip]});$jit.RGraph=new q({Implements:[d,o,g.Radial],initialize:function(w){var x=$jit.RGraph;var y={interpolation:"linear",levelDistance:100};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),y,w);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={klass:b,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new x.Label[z.Label.type](this);this.fx=new x.Plot(this,x);this.op=new x.Op(this);this.json=null;this.root=null;this.busy=false;this.parent=false;this.initializeExtras()},createLevelDistanceFunc:function(){var w=this.config.levelDistance;return function(x){return(x._depth+1)*w}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},plot:function(){this.fx.plot()},getNodeAndParentAngle:function(D){var y=false;var C=this.graph.getNode(D);var A=C.getParents();var z=(A.length>0)?A[0]:false;if(z){var w=z.pos.getc(),B=C.pos.getc();var x=w.add(B.scale(-1));y=Math.atan2(x.y,x.x);if(y<0){y+=2*Math.PI}}return{parent:z,theta:y}},tagChildren:function(A,C){if(A.angleSpan){var B=[];A.eachAdjacency(function(D){B.push(D.nodeTo)},"ignore");var w=B.length;for(var z=0;z<w&&C!=B[z].id;z++){}for(var y=(z+1)%w,x=0;C!=B[y].id;y=(y+1)%w){B[y].dist=x++}}},onClick:function(B,x){if(this.root!=B&&!this.busy){this.busy=true;this.root=B;var y=this;this.controller.onBeforeCompute(this.graph.getNode(B));var z=this.getNodeAndParentAngle(B);this.tagChildren(z.parent,B);this.parent=z.parent;this.compute("end");var w=z.theta-z.parent.endPos.theta;this.graph.eachNode(function(C){C.endPos.set(C.endPos.getp().add(k(w,0)))});var A=this.config.interpolation;x=c.merge({onComplete:c.empty},x||{});this.fx.animate(c.merge({hideLabels:true,modes:[A]},x,{onComplete:function(){y.busy=false;x.onComplete()}}))}}});$jit.RGraph.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};H.setAttribute("x",A.x);H.setAttribute("y",A.y);C.onPlaceLabel(H,B)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize();var B={x:Math.round(G.x*H+A+E.width/2),y:Math.round(G.y*F+y+E.height/2)};var x=I.style;x.left=B.x+"px";x.top=B.y+"px";x.display=this.fitsInCanvas(B,z)?"":"none";D.onPlaceLabel(I,C)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.circle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.ellipse.contains(A,B,y,x)}},square:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.square.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.rectangle.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.rectangle.contains(A,B,y,x)}},triangle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.triangle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.star.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}}})})($jit.RGraph);p.prototype.moebiusTransformation=function(y){var w=this.add(y);var x=y.$conjugate().$prod(this);x.x++;return w.$div(x)};e.Util.moebiusTransformation=function(y,A,z,x,w){this.eachNode(y,function(C){for(var B=0;B<z.length;B++){var E=A[B].scale(-1),D=x?x:z[B];C.getPos(z[B]).set(C.getPos(D).getc().moebiusTransformation(E))}},w)};$jit.Hypertree=new q({Implements:[d,o,g.Radial],initialize:function(w){var z=$jit.Hypertree;var x={radius:"auto",offset:0,Edge:{type:"hyperline"},duration:1500,fps:35};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),x,w);var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(y.background){y.background=c.merge({type:"Circles"},y.background)}this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={klass:b,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new z.Label[y.Label.type](this);this.fx=new z.Plot(this,z);this.op=new z.Op(this);this.json=null;this.root=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var A=this.getRadius();var C=0,w=Math.max,x=this.config;this.graph.eachNode(function(D){C=w(D._depth,C)},"ignore");C++;var B=function(D){return function(F){F.scale=A;var H=F._depth+1;var G=0,E=Math.pow;while(H){G+=E(D,H--)}return G-x.offset}};for(var z=0.51;z<=1;z+=0.01){var y=(1-Math.pow(z,C))/(1-z);if(y>=2){return B(z-0.01)}}return B(0.75)},getRadius:function(){var w=this.config.radius;if(w!=="auto"){return w}var x=this.canvas.getSize();return Math.min(x.width,x.height)/2},refresh:function(w){if(w){this.reposition();this.graph.eachNode(function(x){x.startPos.rho=x.pos.rho=x.endPos.rho;x.startPos.theta=x.pos.theta=x.endPos.theta})}else{this.compute()}this.plot()},reposition:function(){this.compute("end");var w=this.graph.getNode(this.root).pos.getc().scale(-1);e.Util.moebiusTransformation(this.graph,[w],["end"],"end","ignore");this.graph.eachNode(function(x){if(x.ignore){x.endPos.rho=x.pos.rho;x.endPos.theta=x.pos.theta}})},plot:function(){this.fx.plot()},onClick:function(y,w){var x=this.graph.getNode(y).pos.getc(true);this.move(x,w)},move:function(A,y){var x=r(A.x,A.y);if(this.busy===false&&x.norm()<1){this.busy=true;var w=this.graph.getClosestNodeToPos(x),z=this;this.graph.computeLevels(w.id,0);this.controller.onBeforeCompute(w);y=c.merge({onComplete:c.empty},y||{});this.fx.animate(c.merge({modes:["moebius"],hideLabels:true},y,{onComplete:function(){z.busy=false;y.onComplete()}}),x)}}});$jit.Hypertree.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native,initialize:function(x){this.viz=x},renderLabel:function(z,B,y){var x=z.getCtx();var C=B.pos.getc(true);var A=this.viz.getRadius();x.fillText(B.name,C.x*A,C.y*A)}});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize(),x=this.viz.getRadius();var B={x:Math.round((G.x*H)*x+A+E.width/2),y:Math.round((G.y*F)*x+y+E.height/2)};I.setAttribute("x",B.x);I.setAttribute("y",B.y);D.onPlaceLabel(I,C)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(J,D,E){var H=D.pos.getc(true),A=this.viz.canvas,B=A.translateOffsetX,z=A.translateOffsetY,I=A.scaleOffsetX,G=A.scaleOffsetY,F=A.getSize(),x=this.viz.getRadius();var C={x:Math.round((H.x*I)*x+B+F.width/2),y:Math.round((H.y*G)*x+z+F.height/2)};var y=J.style;y.left=C.x+"px";y.top=C.y+"px";y.display=this.fitsInCanvas(C,A)?"":"none";E.onPlaceLabel(J,D)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.circle.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc().$scale(A.scale),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var y=z.getData("width"),x=z.getData("height"),A=z.pos.getc().$scale(z.scale);return this.nodeHelper.circle.contains(A,B,y,x)}},square:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.square.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(B,y){var A=this.node,z=B.getData("width"),x=B.getData("height"),C=B.pos.getc();z=A.transform?z*(1-C.squaredNorm()):z;x=A.transform?x*(1-C.squaredNorm()):x;C.$scale(B.scale);if(z>0.2&&x>0.2){this.nodeHelper.rectangle.render("fill",C,z,x,y)}},contains:function(z,B){var y=z.getData("width"),x=z.getData("height"),A=z.pos.getc().$scale(z.scale);return this.nodeHelper.rectangle.contains(A,B,y,x)}},triangle:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.triangle.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.star.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var B=x.nodeFrom.pos.getc(true),A=x.nodeTo.pos.getc(true),z=x.nodeFrom.scale;this.edgeHelper.line.render({x:B.x*z,y:B.y*z},{x:A.x*z,y:A.y*z},y)},contains:function(x,B){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true),y=x.nodeFrom.scale;this.edgeHelper.line.contains({x:A.x*y,y:A.y*y},{x:z.x*y,y:z.y*y},B,this.edge.epsilon)}},arrow:{render:function(y,z){var E=y.nodeFrom.pos.getc(true),D=y.nodeTo.pos.getc(true),A=y.nodeFrom.scale,C=y.getData("dim"),B=y.data.$direction,x=(B&&B.length>1&&B[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render({x:E.x*A,y:E.y*A},{x:D.x*A,y:D.y*A},C,x,z)},contains:function(x,B){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true),y=x.nodeFrom.scale;this.edgeHelper.arrow.contains({x:A.x*y,y:A.y*y},{x:z.x*y,y:z.y*y},B,this.edge.epsilon)}},hyperline:{render:function(x,y){var B=x.nodeFrom.pos.getc(),A=x.nodeTo.pos.getc(),z=this.viz.getRadius();this.edgeHelper.hyperline.render(B,A,z,y)},contains:c.lambda(false)}})})($jit.Hypertree)})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit.js b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit.js
new file mode 100644
index 00000000..57a6c392
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/Jit/jit.js
@@ -0,0 +1,17162 @@
+/*
+Copyright (c) 2011 Sencha Inc. - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)
+
+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.
+
+ */
+ (function () {
+
+/*
+ File: Core.js
+
+ */
+
+/*
+ Object: $jit
+
+ Defines the namespace for all library Classes and Objects.
+ This variable is the *only* global variable defined in the Toolkit.
+ There are also other interesting properties attached to this variable described below.
+ */
+window.$jit = function(w) {
+ w = w || window;
+ for(var k in $jit) {
+ if($jit[k].$extend) {
+ w[k] = $jit[k];
+ }
+ }
+};
+
+$jit.version = '2.0.1';
+/*
+ Object: $jit.id
+
+ Works just like *document.getElementById*
+
+ Example:
+ (start code js)
+ var element = $jit.id('elementId');
+ (end code)
+
+*/
+
+/*
+ Object: $jit.util
+
+ Contains utility functions.
+
+ Some of the utility functions and the Class system were based in the MooTools Framework
+ <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>.
+ MIT license <http://mootools.net/license.txt>.
+
+ These methods are generally also implemented in DOM manipulation frameworks like JQuery, MooTools and Prototype.
+ I'd suggest you to use the functions from those libraries instead of using these, since their functions
+ are widely used and tested in many different platforms/browsers. Use these functions only if you have to.
+
+ */
+var $ = function(d) {
+ return document.getElementById(d);
+};
+
+$.empty = function() {
+};
+
+/*
+ Method: extend
+
+ Augment an object by appending another object's properties.
+
+ Parameters:
+
+ original - (object) The object to be extended.
+ extended - (object) An object which properties are going to be appended to the original object.
+
+ Example:
+ (start code js)
+ $jit.util.extend({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }
+ (end code)
+*/
+$.extend = function(original, extended) {
+ for ( var key in (extended || {}))
+ original[key] = extended[key];
+ return original;
+};
+
+$.lambda = function(value) {
+ return (typeof value == 'function') ? value : function() {
+ return value;
+ };
+};
+
+$.time = Date.now || function() {
+ return +new Date;
+};
+
+/*
+ Method: splat
+
+ Returns an array wrapping *obj* if *obj* is not an array. Returns *obj* otherwise.
+
+ Parameters:
+
+ obj - (mixed) The object to be wrapped in an array.
+
+ Example:
+ (start code js)
+ $jit.util.splat(3); //[3]
+ $jit.util.splat([3]); //[3]
+ (end code)
+*/
+$.splat = function(obj) {
+ var type = $.type(obj);
+ return type ? ((type != 'array') ? [ obj ] : obj) : [];
+};
+
+$.type = function(elem) {
+ var type = $.type.s.call(elem).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
+ if(type != 'object') return type;
+ if(elem && elem.$$family) return elem.$$family;
+ return (elem && elem.nodeName && elem.nodeType == 1)? 'element' : type;
+};
+$.type.s = Object.prototype.toString;
+
+/*
+ Method: each
+
+ Iterates through an iterable applying *f*.
+
+ Parameters:
+
+ iterable - (array) The original array.
+ fn - (function) The function to apply to the array elements.
+
+ Example:
+ (start code js)
+ $jit.util.each([3, 4, 5], function(n) { alert('number ' + n); });
+ (end code)
+*/
+$.each = function(iterable, fn) {
+ var type = $.type(iterable);
+ if (type == 'object') {
+ for ( var key in iterable)
+ fn(iterable[key], key);
+ } else {
+ for ( var i = 0, l = iterable.length; i < l; i++)
+ fn(iterable[i], i);
+ }
+};
+
+$.indexOf = function(array, item) {
+ if(Array.indexOf) return array.indexOf(item);
+ for(var i=0,l=array.length; i<l; i++) {
+ if(array[i] === item) return i;
+ }
+ return -1;
+};
+
+/*
+ Method: map
+
+ Maps or collects an array by applying *f*.
+
+ Parameters:
+
+ array - (array) The original array.
+ f - (function) The function to apply to the array elements.
+
+ Example:
+ (start code js)
+ $jit.util.map([3, 4, 5], function(n) { return n*n; }); //[9, 16, 25]
+ (end code)
+*/
+$.map = function(array, f) {
+ var ans = [];
+ $.each(array, function(elem, i) {
+ ans.push(f(elem, i));
+ });
+ return ans;
+};
+
+/*
+ Method: reduce
+
+ Iteratively applies the binary function *f* storing the result in an accumulator.
+
+ Parameters:
+
+ array - (array) The original array.
+ f - (function) The function to apply to the array elements.
+ opt - (optional|mixed) The starting value for the acumulator.
+
+ Example:
+ (start code js)
+ $jit.util.reduce([3, 4, 5], function(x, y) { return x + y; }, 0); //12
+ (end code)
+*/
+$.reduce = function(array, f, opt) {
+ var l = array.length;
+ if(l==0) return opt;
+ var acum = arguments.length == 3? opt : array[--l];
+ while(l--) {
+ acum = f(acum, array[l]);
+ }
+ return acum;
+};
+
+/*
+ Method: merge
+
+ Merges n-objects and their sub-objects creating a new, fresh object.
+
+ Parameters:
+
+ An arbitrary number of objects.
+
+ Example:
+ (start code js)
+ $jit.util.merge({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }
+ (end code)
+*/
+$.merge = function() {
+ var mix = {};
+ for ( var i = 0, l = arguments.length; i < l; i++) {
+ var object = arguments[i];
+ if ($.type(object) != 'object')
+ continue;
+ for ( var key in object) {
+ var op = object[key], mp = mix[key];
+ mix[key] = (mp && $.type(op) == 'object' && $.type(mp) == 'object') ? $
+ .merge(mp, op) : $.unlink(op);
+ }
+ }
+ return mix;
+};
+
+$.unlink = function(object) {
+ var unlinked;
+ switch ($.type(object)) {
+ case 'object':
+ unlinked = {};
+ for ( var p in object)
+ unlinked[p] = $.unlink(object[p]);
+ break;
+ case 'array':
+ unlinked = [];
+ for ( var i = 0, l = object.length; i < l; i++)
+ unlinked[i] = $.unlink(object[i]);
+ break;
+ default:
+ return object;
+ }
+ return unlinked;
+};
+
+$.zip = function() {
+ if(arguments.length === 0) return [];
+ for(var j=0, ans=[], l=arguments.length, ml=arguments[0].length; j<ml; j++) {
+ for(var i=0, row=[]; i<l; i++) {
+ row.push(arguments[i][j]);
+ }
+ ans.push(row);
+ }
+ return ans;
+};
+
+/*
+ Method: rgbToHex
+
+ Converts an RGB array into a Hex string.
+
+ Parameters:
+
+ srcArray - (array) An array with R, G and B values
+
+ Example:
+ (start code js)
+ $jit.util.rgbToHex([255, 255, 255]); //'#ffffff'
+ (end code)
+*/
+$.rgbToHex = function(srcArray, array) {
+ if (srcArray.length < 3)
+ return null;
+ if (srcArray.length == 4 && srcArray[3] == 0 && !array)
+ return 'transparent';
+ var hex = [];
+ for ( var i = 0; i < 3; i++) {
+ var bit = (srcArray[i] - 0).toString(16);
+ hex.push(bit.length == 1 ? '0' + bit : bit);
+ }
+ return array ? hex : '#' + hex.join('');
+};
+
+/*
+ Method: hexToRgb
+
+ Converts an Hex color string into an RGB array.
+
+ Parameters:
+
+ hex - (string) A color hex string.
+
+ Example:
+ (start code js)
+ $jit.util.hexToRgb('#fff'); //[255, 255, 255]
+ (end code)
+*/
+$.hexToRgb = function(hex) {
+ if (hex.length != 7) {
+ hex = hex.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
+ hex.shift();
+ if (hex.length != 3)
+ return null;
+ var rgb = [];
+ for ( var i = 0; i < 3; i++) {
+ var value = hex[i];
+ if (value.length == 1)
+ value += value;
+ rgb.push(parseInt(value, 16));
+ }
+ return rgb;
+ } else {
+ hex = parseInt(hex.slice(1), 16);
+ return [ hex >> 16, hex >> 8 & 0xff, hex & 0xff ];
+ }
+};
+
+$.destroy = function(elem) {
+ $.clean(elem);
+ if (elem.parentNode)
+ elem.parentNode.removeChild(elem);
+ if (elem.clearAttributes)
+ elem.clearAttributes();
+};
+
+$.clean = function(elem) {
+ for (var ch = elem.childNodes, i = 0, l = ch.length; i < l; i++) {
+ $.destroy(ch[i]);
+ }
+};
+
+/*
+ Method: addEvent
+
+ Cross-browser add event listener.
+
+ Parameters:
+
+ obj - (obj) The Element to attach the listener to.
+ type - (string) The listener type. For example 'click', or 'mousemove'.
+ fn - (function) The callback function to be used when the event is fired.
+
+ Example:
+ (start code js)
+ $jit.util.addEvent(elem, 'click', function(){ alert('hello'); });
+ (end code)
+*/
+$.addEvent = function(obj, type, fn) {
+ if (obj.addEventListener)
+ obj.addEventListener(type, fn, false);
+ else
+ obj.attachEvent('on' + type, fn);
+};
+
+$.addEvents = function(obj, typeObj) {
+ for(var type in typeObj) {
+ $.addEvent(obj, type, typeObj[type]);
+ }
+};
+
+$.hasClass = function(obj, klass) {
+ return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1;
+};
+
+$.addClass = function(obj, klass) {
+ if (!$.hasClass(obj, klass))
+ obj.className = (obj.className + " " + klass);
+};
+
+$.removeClass = function(obj, klass) {
+ obj.className = obj.className.replace(new RegExp(
+ '(^|\\s)' + klass + '(?:\\s|$)'), '$1');
+};
+
+$.getPos = function(elem) {
+ var offset = getOffsets(elem);
+ var scroll = getScrolls(elem);
+ return {
+ x: offset.x - scroll.x,
+ y: offset.y - scroll.y
+ };
+
+ function getOffsets(elem) {
+ var position = {
+ x: 0,
+ y: 0
+ };
+ while (elem && !isBody(elem)) {
+ position.x += elem.offsetLeft;
+ position.y += elem.offsetTop;
+ elem = elem.offsetParent;
+ }
+ return position;
+ }
+
+ function getScrolls(elem) {
+ var position = {
+ x: 0,
+ y: 0
+ };
+ while (elem && !isBody(elem)) {
+ position.x += elem.scrollLeft;
+ position.y += elem.scrollTop;
+ elem = elem.parentNode;
+ }
+ return position;
+ }
+
+ function isBody(element) {
+ return (/^(?:body|html)$/i).test(element.tagName);
+ }
+};
+
+$.event = {
+ get: function(e, win) {
+ win = win || window;
+ return e || win.event;
+ },
+ getWheel: function(e) {
+ return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3;
+ },
+ isRightClick: function(e) {
+ return (e.which == 3 || e.button == 2);
+ },
+ getPos: function(e, win) {
+ // get mouse position
+ win = win || window;
+ e = e || win.event;
+ var doc = win.document;
+ doc = doc.documentElement || doc.body;
+ //TODO(nico): make touch event handling better
+ if(e.touches && e.touches.length) {
+ e = e.touches[0];
+ }
+ var page = {
+ x: e.pageX || (e.clientX + doc.scrollLeft),
+ y: e.pageY || (e.clientY + doc.scrollTop)
+ };
+ return page;
+ },
+ stop: function(e) {
+ if (e.stopPropagation) e.stopPropagation();
+ e.cancelBubble = true;
+ if (e.preventDefault) e.preventDefault();
+ else e.returnValue = false;
+ }
+};
+
+$jit.util = $jit.id = $;
+
+var Class = function(properties) {
+ properties = properties || {};
+ var klass = function() {
+ for ( var key in this) {
+ if (typeof this[key] != 'function')
+ this[key] = $.unlink(this[key]);
+ }
+ this.constructor = klass;
+ if (Class.prototyping)
+ return this;
+ var instance = this.initialize ? this.initialize.apply(this, arguments)
+ : this;
+ //typize
+ this.$$family = 'class';
+ return instance;
+ };
+
+ for ( var mutator in Class.Mutators) {
+ if (!properties[mutator])
+ continue;
+ properties = Class.Mutators[mutator](properties, properties[mutator]);
+ delete properties[mutator];
+ }
+
+ $.extend(klass, this);
+ klass.constructor = Class;
+ klass.prototype = properties;
+ return klass;
+};
+
+Class.Mutators = {
+
+ Implements: function(self, klasses) {
+ $.each($.splat(klasses), function(klass) {
+ Class.prototyping = klass;
+ var instance = (typeof klass == 'function') ? new klass : klass;
+ for ( var prop in instance) {
+ if (!(prop in self)) {
+ self[prop] = instance[prop];
+ }
+ }
+ delete Class.prototyping;
+ });
+ return self;
+ }
+
+};
+
+$.extend(Class, {
+
+ inherit: function(object, properties) {
+ for ( var key in properties) {
+ var override = properties[key];
+ var previous = object[key];
+ var type = $.type(override);
+ if (previous && type == 'function') {
+ if (override != previous) {
+ Class.override(object, key, override);
+ }
+ } else if (type == 'object') {
+ object[key] = $.merge(previous, override);
+ } else {
+ object[key] = override;
+ }
+ }
+ return object;
+ },
+
+ override: function(object, name, method) {
+ var parent = Class.prototyping;
+ if (parent && object[name] != parent[name])
+ parent = null;
+ var override = function() {
+ var previous = this.parent;
+ this.parent = parent ? parent[name] : object[name];
+ var value = method.apply(this, arguments);
+ this.parent = previous;
+ return value;
+ };
+ object[name] = override;
+ }
+
+});
+
+Class.prototype.implement = function() {
+ var proto = this.prototype;
+ $.each(Array.prototype.slice.call(arguments || []), function(properties) {
+ Class.inherit(proto, properties);
+ });
+ return this;
+};
+
+$jit.Class = Class;
+
+/*
+ Object: $jit.json
+
+ Provides JSON utility functions.
+
+ Most of these functions are JSON-tree traversal and manipulation functions.
+*/
+$jit.json = {
+ /*
+ Method: prune
+
+ Clears all tree nodes having depth greater than maxLevel.
+
+ Parameters:
+
+ tree - (object) A JSON tree object. For more information please see <Loader.loadJSON>.
+ maxLevel - (number) An integer specifying the maximum level allowed for this tree. All nodes having depth greater than max level will be deleted.
+
+ */
+ prune: function(tree, maxLevel) {
+ this.each(tree, function(elem, i) {
+ if (i == maxLevel && elem.children) {
+ delete elem.children;
+ elem.children = [];
+ }
+ });
+ },
+ /*
+ Method: getParent
+
+ Returns the parent node of the node having _id_ as id.
+
+ Parameters:
+
+ tree - (object) A JSON tree object. See also <Loader.loadJSON>.
+ id - (string) The _id_ of the child node whose parent will be returned.
+
+ Returns:
+
+ A tree JSON node if any, or false otherwise.
+
+ */
+ getParent: function(tree, id) {
+ if (tree.id == id)
+ return false;
+ var ch = tree.children;
+ if (ch && ch.length > 0) {
+ for ( var i = 0; i < ch.length; i++) {
+ if (ch[i].id == id)
+ return tree;
+ else {
+ var ans = this.getParent(ch[i], id);
+ if (ans)
+ return ans;
+ }
+ }
+ }
+ return false;
+ },
+ /*
+ Method: getSubtree
+
+ Returns the subtree that matches the given id.
+
+ Parameters:
+
+ tree - (object) A JSON tree object. See also <Loader.loadJSON>.
+ id - (string) A node *unique* identifier.
+
+ Returns:
+
+ A subtree having a root node matching the given id. Returns null if no subtree matching the id is found.
+
+ */
+ getSubtree: function(tree, id) {
+ if (tree.id == id)
+ return tree;
+ for ( var i = 0, ch = tree.children; ch && i < ch.length; i++) {
+ var t = this.getSubtree(ch[i], id);
+ if (t != null)
+ return t;
+ }
+ return null;
+ },
+ /*
+ Method: eachLevel
+
+ Iterates on tree nodes with relative depth less or equal than a specified level.
+
+ Parameters:
+
+ tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.
+ initLevel - (number) An integer specifying the initial relative level. Usually zero.
+ toLevel - (number) An integer specifying a top level. This method will iterate only through nodes with depth less than or equal this number.
+ action - (function) A function that receives a node and an integer specifying the actual level of the node.
+
+ Example:
+ (start code js)
+ $jit.json.eachLevel(tree, 0, 3, function(node, depth) {
+ alert(node.name + ' ' + depth);
+ });
+ (end code)
+ */
+ eachLevel: function(tree, initLevel, toLevel, action) {
+ if (initLevel <= toLevel) {
+ action(tree, initLevel);
+ if(!tree.children) return;
+ for ( var i = 0, ch = tree.children; i < ch.length; i++) {
+ this.eachLevel(ch[i], initLevel + 1, toLevel, action);
+ }
+ }
+ },
+ /*
+ Method: each
+
+ A JSON tree iterator.
+
+ Parameters:
+
+ tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.
+ action - (function) A function that receives a node.
+
+ Example:
+ (start code js)
+ $jit.json.each(tree, function(node) {
+ alert(node.name);
+ });
+ (end code)
+
+ */
+ each: function(tree, action) {
+ this.eachLevel(tree, 0, Number.MAX_VALUE, action);
+ }
+};
+
+
+/*
+ An object containing multiple type of transformations.
+*/
+
+$jit.Trans = {
+ $extend: true,
+
+ linear: function(p){
+ return p;
+ }
+};
+
+var Trans = $jit.Trans;
+
+(function(){
+
+ var makeTrans = function(transition, params){
+ params = $.splat(params);
+ return $.extend(transition, {
+ easeIn: function(pos){
+ return transition(pos, params);
+ },
+ easeOut: function(pos){
+ return 1 - transition(1 - pos, params);
+ },
+ easeInOut: function(pos){
+ return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition(
+ 2 * (1 - pos), params)) / 2;
+ }
+ });
+ };
+
+ var transitions = {
+
+ Pow: function(p, x){
+ return Math.pow(p, x[0] || 6);
+ },
+
+ Expo: function(p){
+ return Math.pow(2, 8 * (p - 1));
+ },
+
+ Circ: function(p){
+ return 1 - Math.sin(Math.acos(p));
+ },
+
+ Sine: function(p){
+ return 1 - Math.sin((1 - p) * Math.PI / 2);
+ },
+
+ Back: function(p, x){
+ x = x[0] || 1.618;
+ return Math.pow(p, 2) * ((x + 1) * p - x);
+ },
+
+ Bounce: function(p){
+ var value;
+ for ( var a = 0, b = 1; 1; a += b, b /= 2) {
+ if (p >= (7 - 4 * a) / 11) {
+ value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
+ break;
+ }
+ }
+ return value;
+ },
+
+ Elastic: function(p, x){
+ return Math.pow(2, 10 * --p)
+ * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
+ }
+
+ };
+
+ $.each(transitions, function(val, key){
+ Trans[key] = makeTrans(val);
+ });
+
+ $.each( [
+ 'Quad', 'Cubic', 'Quart', 'Quint'
+ ], function(elem, i){
+ Trans[elem] = makeTrans(function(p){
+ return Math.pow(p, [
+ i + 2
+ ]);
+ });
+ });
+
+})();
+
+/*
+ A Class that can perform animations for generic objects.
+
+ If you are looking for animation transitions please take a look at the <Trans> object.
+
+ Used by:
+
+ <Graph.Plot>
+
+ Based on:
+
+ The Animation class is based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.
+
+*/
+
+var Animation = new Class( {
+
+ initialize: function(options){
+ this.setOptions(options);
+ },
+
+ setOptions: function(options){
+ var opt = {
+ duration: 2500,
+ fps: 40,
+ transition: Trans.Quart.easeInOut,
+ compute: $.empty,
+ complete: $.empty,
+ link: 'ignore'
+ };
+ this.opt = $.merge(opt, options || {});
+ return this;
+ },
+
+ step: function(){
+ var time = $.time(), opt = this.opt;
+ if (time < this.time + opt.duration) {
+ var delta = opt.transition((time - this.time) / opt.duration);
+ opt.compute(delta);
+ } else {
+ this.timer = clearInterval(this.timer);
+ opt.compute(1);
+ opt.complete();
+ }
+ },
+
+ start: function(){
+ if (!this.check())
+ return this;
+ this.time = 0;
+ this.startTimer();
+ return this;
+ },
+
+ startTimer: function(){
+ var that = this, fps = this.opt.fps;
+ if (this.timer)
+ return false;
+ this.time = $.time() - this.time;
+ this.timer = setInterval((function(){
+ that.step();
+ }), Math.round(1000 / fps));
+ return true;
+ },
+
+ pause: function(){
+ this.stopTimer();
+ return this;
+ },
+
+ resume: function(){
+ this.startTimer();
+ return this;
+ },
+
+ stopTimer: function(){
+ if (!this.timer)
+ return false;
+ this.time = $.time() - this.time;
+ this.timer = clearInterval(this.timer);
+ return true;
+ },
+
+ check: function(){
+ if (!this.timer)
+ return true;
+ if (this.opt.link == 'cancel') {
+ this.stopTimer();
+ return true;
+ }
+ return false;
+ }
+});
+
+
+var Options = function() {
+ var args = arguments;
+ for(var i=0, l=args.length, ans={}; i<l; i++) {
+ var opt = Options[args[i]];
+ if(opt.$extend) {
+ $.extend(ans, opt);
+ } else {
+ ans[args[i]] = opt;
+ }
+ }
+ return ans;
+};
+
+/*
+ * File: Options.AreaChart.js
+ *
+*/
+
+/*
+ Object: Options.AreaChart
+
+ <AreaChart> options.
+ Other options included in the AreaChart are <Options.Canvas>, <Options.Label>, <Options.Margin>, <Options.Tips> and <Options.Events>.
+
+ Syntax:
+
+ (start code js)
+
+ Options.AreaChart = {
+ animate: true,
+ labelOffset: 3,
+ type: 'stacked',
+ selectOnHover: true,
+ showAggregates: true,
+ showLabels: true,
+ filterOnClick: false,
+ restoreOnRightClick: false
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+
+ var areaChart = new $jit.AreaChart({
+ animate: true,
+ type: 'stacked:gradient',
+ selectOnHover: true,
+ filterOnClick: true,
+ restoreOnRightClick: true
+ });
+
+ (end code)
+
+ Parameters:
+
+ animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks.
+ labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.
+ type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients.
+ selectOnHover - (boolean) Default's *true*. If true, it will add a mark to the hovered stack.
+ showAggregates - (boolean, function) Default's *true*. Display the values of the stacks. Can also be a function that returns *true* or *false* to display or filter some values. That same function can also return a string with the formatted value.
+ showLabels - (boolean, function) Default's *true*. Display the name of the slots. Can also be a function that returns *true* or *false* to display or not each label.
+ filterOnClick - (boolean) Default's *true*. Select the clicked stack by hiding all other stacks.
+ restoreOnRightClick - (boolean) Default's *true*. Show all stacks by right clicking.
+
+*/
+
+Options.AreaChart = {
+ $extend: true,
+
+ animate: true,
+ labelOffset: 3, // label offset
+ type: 'stacked', // gradient
+ Tips: {
+ enable: false,
+ onShow: $.empty,
+ onHide: $.empty
+ },
+ Events: {
+ enable: false,
+ onClick: $.empty
+ },
+ selectOnHover: true,
+ showAggregates: true,
+ showLabels: true,
+ filterOnClick: false,
+ restoreOnRightClick: false
+};
+
+/*
+ * File: Options.Margin.js
+ *
+*/
+
+/*
+ Object: Options.Margin
+
+ Canvas drawing margins.
+
+ Syntax:
+
+ (start code js)
+
+ Options.Margin = {
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+
+ var viz = new $jit.Viz({
+ Margin: {
+ right: 10,
+ bottom: 20
+ }
+ });
+
+ (end code)
+
+ Parameters:
+
+ top - (number) Default's *0*. Top margin.
+ left - (number) Default's *0*. Left margin.
+ right - (number) Default's *0*. Right margin.
+ bottom - (number) Default's *0*. Bottom margin.
+
+*/
+
+Options.Margin = {
+ $extend: false,
+
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0
+};
+
+/*
+ * File: Options.Canvas.js
+ *
+*/
+
+/*
+ Object: Options.Canvas
+
+ These are Canvas general options, like where to append it in the DOM, its dimensions, background,
+ and other more advanced options.
+
+ Syntax:
+
+ (start code js)
+
+ Options.Canvas = {
+ injectInto: 'id',
+ type: '2D', //'3D'
+ width: false,
+ height: false,
+ useCanvas: false,
+ withLabels: true,
+ background: false
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ injectInto: 'someContainerId',
+ width: 500,
+ height: 700
+ });
+ (end code)
+
+ Parameters:
+
+ injectInto - *required* (string|element) The id of the DOM container for the visualization. It can also be an Element provided that it has an id.
+ type - (string) Context type. Default's 2D but can be 3D for webGL enabled browsers.
+ width - (number) Default's to the *container's offsetWidth*. The width of the canvas.
+ height - (number) Default's to the *container's offsetHeight*. The height of the canvas.
+ useCanvas - (boolean|object) Default's *false*. You can pass another <Canvas> instance to be used by the visualization.
+ withLabels - (boolean) Default's *true*. Whether to use a label container for the visualization.
+ background - (boolean|object) Default's *false*. An object containing information about the rendering of a background canvas.
+*/
+
+Options.Canvas = {
+ $extend: true,
+
+ injectInto: 'id',
+ type: '2D',
+ width: false,
+ height: false,
+ useCanvas: false,
+ withLabels: true,
+ background: false,
+
+ Scene: {
+ Lighting: {
+ enable: false,
+ ambient: [1, 1, 1],
+ directional: {
+ direction: { x: -100, y: -100, z: -100 },
+ color: [0.5, 0.3, 0.1]
+ }
+ }
+ }
+};
+
+/*
+ * File: Options.Tree.js
+ *
+*/
+
+/*
+ Object: Options.Tree
+
+ Options related to (strict) Tree layout algorithms. These options are used by the <ST> visualization.
+
+ Syntax:
+
+ (start code js)
+ Options.Tree = {
+ orientation: "left",
+ subtreeOffset: 8,
+ siblingOffset: 5,
+ indent:10,
+ multitree: false,
+ align:"center"
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var st = new $jit.ST({
+ orientation: 'left',
+ subtreeOffset: 1,
+ siblingOFfset: 5,
+ multitree: true
+ });
+ (end code)
+
+ Parameters:
+
+ subtreeOffset - (number) Default's 8. Separation offset between subtrees.
+ siblingOffset - (number) Default's 5. Separation offset between siblings.
+ orientation - (string) Default's 'left'. Tree orientation layout. Possible values are 'left', 'top', 'right', 'bottom'.
+ align - (string) Default's *center*. Whether the tree alignment is 'left', 'center' or 'right'.
+ indent - (number) Default's 10. Used when *align* is left or right and shows an indentation between parent and children.
+ multitree - (boolean) Default's *false*. Used with the node $orn data property for creating multitrees.
+
+*/
+Options.Tree = {
+ $extend: true,
+
+ orientation: "left",
+ subtreeOffset: 8,
+ siblingOffset: 5,
+ indent:10,
+ multitree: false,
+ align:"center"
+};
+
+
+/*
+ * File: Options.Node.js
+ *
+*/
+
+/*
+ Object: Options.Node
+
+ Provides Node rendering options for Tree and Graph based visualizations.
+
+ Syntax:
+
+ (start code js)
+ Options.Node = {
+ overridable: false,
+ type: 'circle',
+ color: '#ccb',
+ alpha: 1,
+ dim: 3,
+ height: 20,
+ width: 90,
+ autoHeight: false,
+ autoWidth: false,
+ lineWidth: 1,
+ transform: true,
+ align: "center",
+ angularWidth:1,
+ span:1,
+ CanvasStyles: {}
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Node: {
+ overridable: true,
+ width: 30,
+ autoHeight: true,
+ type: 'rectangle'
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ overridable - (boolean) Default's *false*. Determine whether or not general node properties can be overridden by a particular <Graph.Node>.
+ type - (string) Default's *circle*. Node's shape. Node built-in types include 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star'. The default Node type might vary in each visualization. You can also implement (non built-in) custom Node types into your visualizations.
+ color - (string) Default's *#ccb*. Node color.
+ alpha - (number) Default's *1*. The Node's alpha value. *1* is for full opacity.
+ dim - (number) Default's *3*. An extra parameter used by 'circle', 'square', 'triangle' and 'star' node types. Depending on each shape, this parameter can set the radius of a circle, half the length of the side of a square, half the base and half the height of a triangle or the length of a side of a star (concave decagon).
+ height - (number) Default's *20*. Used by 'rectangle' and 'ellipse' node types. The height of the node shape.
+ width - (number) Default's *90*. Used by 'rectangle' and 'ellipse' node types. The width of the node shape.
+ autoHeight - (boolean) Default's *false*. Whether to set an auto height for the node depending on the content of the Node's label.
+ autoWidth - (boolean) Default's *false*. Whether to set an auto width for the node depending on the content of the Node's label.
+ lineWidth - (number) Default's *1*. Used only by some Node shapes. The line width of the strokes of a node.
+ transform - (boolean) Default's *true*. Only used by the <Hypertree> visualization. Whether to scale the nodes according to the moebius transformation.
+ align - (string) Default's *center*. Possible values are 'center', 'left' or 'right'. Used only by the <ST> visualization, these parameters are used for aligning nodes when some of they dimensions vary.
+ angularWidth - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The amount of relative 'space' set for a node.
+ span - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The angle span amount set for a node.
+ CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting a Node.
+
+*/
+Options.Node = {
+ $extend: false,
+
+ overridable: false,
+ type: 'circle',
+ color: '#ccb',
+ alpha: 1,
+ dim: 3,
+ height: 20,
+ width: 90,
+ autoHeight: false,
+ autoWidth: false,
+ lineWidth: 1,
+ transform: true,
+ align: "center",
+ angularWidth:1,
+ span:1,
+ //Raw canvas styles to be
+ //applied to the context instance
+ //before plotting a node
+ CanvasStyles: {}
+};
+
+
+/*
+ * File: Options.Edge.js
+ *
+*/
+
+/*
+ Object: Options.Edge
+
+ Provides Edge rendering options for Tree and Graph based visualizations.
+
+ Syntax:
+
+ (start code js)
+ Options.Edge = {
+ overridable: false,
+ type: 'line',
+ color: '#ccb',
+ lineWidth: 1,
+ dim:15,
+ alpha: 1,
+ CanvasStyles: {}
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Edge: {
+ overridable: true,
+ type: 'line',
+ color: '#fff',
+ CanvasStyles: {
+ shadowColor: '#ccc',
+ shadowBlur: 10
+ }
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ overridable - (boolean) Default's *false*. Determine whether or not general edges properties can be overridden by a particular <Graph.Adjacence>.
+ type - (string) Default's 'line'. Edge styles include 'line', 'hyperline', 'arrow'. The default Edge type might vary in each visualization. You can also implement custom Edge types.
+ color - (string) Default's '#ccb'. Edge color.
+ lineWidth - (number) Default's *1*. Line/Edge width.
+ alpha - (number) Default's *1*. The Edge's alpha value. *1* is for full opacity.
+ dim - (number) Default's *15*. An extra parameter used by other complex shapes such as quadratic, bezier or arrow, to determine the shape's diameter.
+ epsilon - (number) Default's *7*. Only used when using *enableForEdges* in <Options.Events>. This dimension is used to create an area for the line where the contains method for the edge returns *true*.
+ CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting an Edge.
+
+ See also:
+
+ If you want to know more about how to customize Node/Edge data per element, in the JSON or programmatically, take a look at this article.
+*/
+Options.Edge = {
+ $extend: false,
+
+ overridable: false,
+ type: 'line',
+ color: '#ccb',
+ lineWidth: 1,
+ dim:15,
+ alpha: 1,
+ epsilon: 7,
+
+ //Raw canvas styles to be
+ //applied to the context instance
+ //before plotting an edge
+ CanvasStyles: {}
+};
+
+
+/*
+ * File: Options.Fx.js
+ *
+*/
+
+/*
+ Object: Options.Fx
+
+ Provides animation options like duration of the animations, frames per second and animation transitions.
+
+ Syntax:
+
+ (start code js)
+ Options.Fx = {
+ fps:40,
+ duration: 2500,
+ transition: $jit.Trans.Quart.easeInOut,
+ clearCanvas: true
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ duration: 1000,
+ fps: 35,
+ transition: $jit.Trans.linear
+ });
+ (end code)
+
+ Parameters:
+
+ clearCanvas - (boolean) Default's *true*. Whether to clear the frame/canvas when the viz is plotted or animated.
+ duration - (number) Default's *2500*. Duration of the animation in milliseconds.
+ fps - (number) Default's *40*. Frames per second.
+ transition - (object) Default's *$jit.Trans.Quart.easeInOut*. The transition used for the animations. See below for a more detailed explanation.
+
+ Object: $jit.Trans
+
+ This object is used for specifying different animation transitions in all visualizations.
+
+ There are many different type of animation transitions.
+
+ linear:
+
+ Displays a linear transition
+
+ >Trans.linear
+
+ (see Linear.png)
+
+ Quad:
+
+ Displays a Quadratic transition.
+
+ >Trans.Quad.easeIn
+ >Trans.Quad.easeOut
+ >Trans.Quad.easeInOut
+
+ (see Quad.png)
+
+ Cubic:
+
+ Displays a Cubic transition.
+
+ >Trans.Cubic.easeIn
+ >Trans.Cubic.easeOut
+ >Trans.Cubic.easeInOut
+
+ (see Cubic.png)
+
+ Quart:
+
+ Displays a Quartetic transition.
+
+ >Trans.Quart.easeIn
+ >Trans.Quart.easeOut
+ >Trans.Quart.easeInOut
+
+ (see Quart.png)
+
+ Quint:
+
+ Displays a Quintic transition.
+
+ >Trans.Quint.easeIn
+ >Trans.Quint.easeOut
+ >Trans.Quint.easeInOut
+
+ (see Quint.png)
+
+ Expo:
+
+ Displays an Exponential transition.
+
+ >Trans.Expo.easeIn
+ >Trans.Expo.easeOut
+ >Trans.Expo.easeInOut
+
+ (see Expo.png)
+
+ Circ:
+
+ Displays a Circular transition.
+
+ >Trans.Circ.easeIn
+ >Trans.Circ.easeOut
+ >Trans.Circ.easeInOut
+
+ (see Circ.png)
+
+ Sine:
+
+ Displays a Sineousidal transition.
+
+ >Trans.Sine.easeIn
+ >Trans.Sine.easeOut
+ >Trans.Sine.easeInOut
+
+ (see Sine.png)
+
+ Back:
+
+ >Trans.Back.easeIn
+ >Trans.Back.easeOut
+ >Trans.Back.easeInOut
+
+ (see Back.png)
+
+ Bounce:
+
+ Bouncy transition.
+
+ >Trans.Bounce.easeIn
+ >Trans.Bounce.easeOut
+ >Trans.Bounce.easeInOut
+
+ (see Bounce.png)
+
+ Elastic:
+
+ Elastic curve.
+
+ >Trans.Elastic.easeIn
+ >Trans.Elastic.easeOut
+ >Trans.Elastic.easeInOut
+
+ (see Elastic.png)
+
+ Based on:
+
+ Easing and Transition animation methods are based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.
+
+
+*/
+Options.Fx = {
+ $extend: true,
+
+ fps:40,
+ duration: 2500,
+ transition: $jit.Trans.Quart.easeInOut,
+ clearCanvas: true
+};
+
+/*
+ * File: Options.Label.js
+ *
+*/
+/*
+ Object: Options.Label
+
+ Provides styling for Labels such as font size, family, etc. Also sets Node labels as HTML, SVG or Native canvas elements.
+
+ Syntax:
+
+ (start code js)
+ Options.Label = {
+ overridable: false,
+ type: 'HTML', //'SVG', 'Native'
+ style: ' ',
+ size: 10,
+ family: 'sans-serif',
+ textAlign: 'center',
+ textBaseline: 'alphabetic',
+ color: '#fff'
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Label: {
+ type: 'Native',
+ size: 11,
+ color: '#ccc'
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ overridable - (boolean) Default's *false*. Determine whether or not general label properties can be overridden by a particular <Graph.Node>.
+ type - (string) Default's *HTML*. The type for the labels. Can be 'HTML', 'SVG' or 'Native' canvas labels.
+ style - (string) Default's *empty string*. Can be 'italic' or 'bold'. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
+ size - (number) Default's *10*. The font's size. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
+ family - (string) Default's *sans-serif*. The font's family. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
+ color - (string) Default's *#fff*. The font's color. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
+*/
+Options.Label = {
+ $extend: false,
+
+ overridable: false,
+ type: 'HTML', //'SVG', 'Native'
+ style: ' ',
+ size: 10,
+ family: 'sans-serif',
+ textAlign: 'center',
+ textBaseline: 'alphabetic',
+ color: '#fff'
+};
+
+
+/*
+ * File: Options.Tips.js
+ *
+ */
+
+/*
+ Object: Options.Tips
+
+ Tips options
+
+ Syntax:
+
+ (start code js)
+ Options.Tips = {
+ enable: false,
+ type: 'auto',
+ offsetX: 20,
+ offsetY: 20,
+ onShow: $.empty,
+ onHide: $.empty
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Tips: {
+ enable: true,
+ type: 'Native',
+ offsetX: 10,
+ offsetY: 10,
+ onShow: function(tip, node) {
+ tip.innerHTML = node.name;
+ }
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ enable - (boolean) Default's *false*. If *true*, a tooltip will be shown when a node is hovered. The tooltip is a div DOM element having "tip" as CSS class.
+ type - (string) Default's *auto*. Defines where to attach the MouseEnter/Leave tooltip events. Possible values are 'Native' to attach them to the canvas or 'HTML' to attach them to DOM label elements (if defined). 'auto' sets this property to the value of <Options.Label>'s *type* property.
+ offsetX - (number) Default's *20*. An offset added to the current tooltip x-position (which is the same as the current mouse position). Default's 20.
+ offsetY - (number) Default's *20*. An offset added to the current tooltip y-position (which is the same as the current mouse position). Default's 20.
+ onShow(tip, node) - This callack is used right before displaying a tooltip. The first formal parameter is the tip itself (which is a DivElement). The second parameter may be a <Graph.Node> for graph based visualizations or an object with label, value properties for charts.
+ onHide() - This callack is used when hiding a tooltip.
+
+*/
+Options.Tips = {
+ $extend: false,
+
+ enable: false,
+ type: 'auto',
+ offsetX: 20,
+ offsetY: 20,
+ force: false,
+ onShow: $.empty,
+ onHide: $.empty
+};
+
+
+/*
+ * File: Options.NodeStyles.js
+ *
+ */
+
+/*
+ Object: Options.NodeStyles
+
+ Apply different styles when a node is hovered or selected.
+
+ Syntax:
+
+ (start code js)
+ Options.NodeStyles = {
+ enable: false,
+ type: 'auto',
+ stylesHover: false,
+ stylesClick: false
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ NodeStyles: {
+ enable: true,
+ type: 'Native',
+ stylesHover: {
+ dim: 30,
+ color: '#fcc'
+ },
+ duration: 600
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ enable - (boolean) Default's *false*. Whether to enable this option.
+ type - (string) Default's *auto*. Use this to attach the hover/click events in the nodes or the nodes labels (if they have been defined as DOM elements: 'HTML' or 'SVG', see <Options.Label> for more details). The default 'auto' value will set NodeStyles to the same type defined for <Options.Label>.
+ stylesHover - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.
+ stylesClick - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.
+*/
+
+Options.NodeStyles = {
+ $extend: false,
+
+ enable: false,
+ type: 'auto',
+ stylesHover: false,
+ stylesClick: false
+};
+
+
+/*
+ * File: Options.Events.js
+ *
+*/
+
+/*
+ Object: Options.Events
+
+ Configuration for adding mouse/touch event handlers to Nodes.
+
+ Syntax:
+
+ (start code js)
+ Options.Events = {
+ enable: false,
+ enableForEdges: false,
+ type: 'auto',
+ onClick: $.empty,
+ onRightClick: $.empty,
+ onMouseMove: $.empty,
+ onMouseEnter: $.empty,
+ onMouseLeave: $.empty,
+ onDragStart: $.empty,
+ onDragMove: $.empty,
+ onDragCancel: $.empty,
+ onDragEnd: $.empty,
+ onTouchStart: $.empty,
+ onTouchMove: $.empty,
+ onTouchEnd: $.empty,
+ onTouchCancel: $.empty,
+ onMouseWheel: $.empty
+ };
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Events: {
+ enable: true,
+ onClick: function(node, eventInfo, e) {
+ viz.doSomething();
+ },
+ onMouseEnter: function(node, eventInfo, e) {
+ viz.canvas.getElement().style.cursor = 'pointer';
+ },
+ onMouseLeave: function(node, eventInfo, e) {
+ viz.canvas.getElement().style.cursor = '';
+ }
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ enable - (boolean) Default's *false*. Whether to enable the Event system.
+ enableForEdges - (boolean) Default's *false*. Whether to track events also in arcs. If *true* the same callbacks -described below- are used for nodes *and* edges. A simple duck type check for edges is to check for *node.nodeFrom*.
+ type - (string) Default's 'auto'. Whether to attach the events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. 'auto' is set when you let the <Options.Label> *type* parameter decide this.
+ onClick(node, eventInfo, e) - Triggered when a user performs a click in the canvas. *node* is the <Graph.Node> clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onRightClick(node, eventInfo, e) - Triggered when a user performs a right click in the canvas. *node* is the <Graph.Node> right clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onMouseMove(node, eventInfo, e) - Triggered when the user moves the mouse. *node* is the <Graph.Node> under the cursor as it's moving over the canvas or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onMouseEnter(node, eventInfo, e) - Triggered when a user moves the mouse over a node. *node* is the <Graph.Node> that the mouse just entered. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onMouseLeave(node, eventInfo, e) - Triggered when the user mouse-outs a node. *node* is the <Graph.Node> 'mouse-outed'. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onDragStart(node, eventInfo, e) - Triggered when the user mouse-downs over a node. *node* is the <Graph.Node> being pressed. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onDragMove(node, eventInfo, e) - Triggered when a user, after pressing the mouse button over a node, moves the mouse around. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onDragEnd(node, eventInfo, e) - Triggered when a user finished dragging a node. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onDragCancel(node, eventInfo, e) - Triggered when the user releases the mouse button over a <Graph.Node> that wasn't dragged (i.e. the user didn't perform any mouse movement after pressing the mouse button). *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
+ onTouchStart(node, eventInfo, e) - Behaves just like onDragStart.
+ onTouchMove(node, eventInfo, e) - Behaves just like onDragMove.
+ onTouchEnd(node, eventInfo, e) - Behaves just like onDragEnd.
+ onTouchCancel(node, eventInfo, e) - Behaves just like onDragCancel.
+ onMouseWheel(delta, e) - Triggered when the user uses the mouse scroll over the canvas. *delta* is 1 or -1 depending on the sense of the mouse scroll.
+*/
+
+Options.Events = {
+ $extend: false,
+
+ enable: false,
+ enableForEdges: false,
+ type: 'auto',
+ onClick: $.empty,
+ onRightClick: $.empty,
+ onMouseMove: $.empty,
+ onMouseEnter: $.empty,
+ onMouseLeave: $.empty,
+ onDragStart: $.empty,
+ onDragMove: $.empty,
+ onDragCancel: $.empty,
+ onDragEnd: $.empty,
+ onTouchStart: $.empty,
+ onTouchMove: $.empty,
+ onTouchEnd: $.empty,
+ onMouseWheel: $.empty
+};
+
+/*
+ * File: Options.Navigation.js
+ *
+*/
+
+/*
+ Object: Options.Navigation
+
+ Panning and zooming options for Graph/Tree based visualizations. These options are implemented
+ by all visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).
+
+ Syntax:
+
+ (start code js)
+
+ Options.Navigation = {
+ enable: false,
+ type: 'auto',
+ panning: false, //true, 'avoid nodes'
+ zooming: false
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ Navigation: {
+ enable: true,
+ panning: 'avoid nodes',
+ zooming: 20
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ enable - (boolean) Default's *false*. Whether to enable Navigation capabilities.
+ type - (string) Default's 'auto'. Whether to attach the navigation events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. When 'auto' set when you let the <Options.Label> *type* parameter decide this.
+ panning - (boolean|string) Default's *false*. Set this property to *true* if you want to add Drag and Drop panning support to the visualization. You can also set this parameter to 'avoid nodes' to enable DnD panning but disable it if the DnD is taking place over a node. This is useful when some other events like Drag & Drop for nodes are added to <Graph.Nodes>.
+ zooming - (boolean|number) Default's *false*. Set this property to a numeric value to turn mouse-scroll zooming on. The number will be proportional to the mouse-scroll sensitivity.
+
+*/
+
+Options.Navigation = {
+ $extend: false,
+
+ enable: false,
+ type: 'auto',
+ panning: false, //true | 'avoid nodes'
+ zooming: false
+};
+
+/*
+ * File: Options.Controller.js
+ *
+*/
+
+/*
+ Object: Options.Controller
+
+ Provides controller methods. Controller methods are callback functions that get called at different stages
+ of the animation, computing or plotting of the visualization.
+
+ Implemented by:
+
+ All visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).
+
+ Syntax:
+
+ (start code js)
+
+ Options.Controller = {
+ onBeforeCompute: $.empty,
+ onAfterCompute: $.empty,
+ onCreateLabel: $.empty,
+ onPlaceLabel: $.empty,
+ onComplete: $.empty,
+ onBeforePlotLine:$.empty,
+ onAfterPlotLine: $.empty,
+ onBeforePlotNode:$.empty,
+ onAfterPlotNode: $.empty,
+ request: false
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz({
+ onBeforePlotNode: function(node) {
+ if(node.selected) {
+ node.setData('color', '#ffc');
+ } else {
+ node.removeData('color');
+ }
+ },
+ onBeforePlotLine: function(adj) {
+ if(adj.nodeFrom.selected && adj.nodeTo.selected) {
+ adj.setData('color', '#ffc');
+ } else {
+ adj.removeData('color');
+ }
+ },
+ onAfterCompute: function() {
+ alert("computed!");
+ }
+ });
+ (end code)
+
+ Parameters:
+
+ onBeforeCompute(node) - This method is called right before performing all computations and animations. The selected <Graph.Node> is passed as parameter.
+ onAfterCompute() - This method is triggered after all animations or computations ended.
+ onCreateLabel(domElement, node) - This method receives a new label DIV element as first parameter, and the corresponding <Graph.Node> as second parameter. This method will only be called once for each label. This method is useful when adding events or styles to the labels used by the JIT.
+ onPlaceLabel(domElement, node) - This method receives a label DIV element as first parameter and the corresponding <Graph.Node> as second parameter. This method is called each time a label has been placed in the visualization, for example at each step of an animation, and thus it allows you to update the labels properties, such as size or position. Note that onPlaceLabel will be triggered after updating the labels positions. That means that, for example, the left and top css properties are already updated to match the nodes positions. Width and height properties are not set however.
+ onBeforePlotNode(node) - This method is triggered right before plotting each <Graph.Node>. This method is useful for changing a node style right before plotting it.
+ onAfterPlotNode(node) - This method is triggered right after plotting each <Graph.Node>.
+ onBeforePlotLine(adj) - This method is triggered right before plotting a <Graph.Adjacence>. This method is useful for adding some styles to a particular edge before being plotted.
+ onAfterPlotLine(adj) - This method is triggered right after plotting a <Graph.Adjacence>.
+
+ *Used in <ST>, <TM.Base> and <Icicle> visualizations*
+
+ request(nodeId, level, onComplete) - This method is used for buffering information into the visualization. When clicking on an empty node, the visualization will make a request for this node's subtrees, specifying a given level for this subtree (defined by _levelsToShow_). Once the request is completed, the onComplete callback should be called with the given result. This is useful to provide on-demand information into the visualizations withought having to load the entire information from start. The parameters used by this method are _nodeId_, which is the id of the root of the subtree to request, _level_ which is the depth of the subtree to be requested (0 would mean just the root node). _onComplete_ is an object having the callback method _onComplete.onComplete(json)_ that should be called once the json has been retrieved.
+
+ */
+Options.Controller = {
+ $extend: true,
+
+ onBeforeCompute: $.empty,
+ onAfterCompute: $.empty,
+ onCreateLabel: $.empty,
+ onPlaceLabel: $.empty,
+ onComplete: $.empty,
+ onBeforePlotLine:$.empty,
+ onAfterPlotLine: $.empty,
+ onBeforePlotNode:$.empty,
+ onAfterPlotNode: $.empty,
+ request: false
+};
+
+
+/*
+ * File: Extras.js
+ *
+ * Provides Extras such as Tips and Style Effects.
+ *
+ * Description:
+ *
+ * Provides the <Tips> and <NodeStyles> classes and functions.
+ *
+ */
+
+/*
+ * Manager for mouse events (clicking and mouse moving).
+ *
+ * This class is used for registering objects implementing onClick
+ * and onMousemove methods. These methods are called when clicking or
+ * moving the mouse around the Canvas.
+ * For now, <Tips> and <NodeStyles> are classes implementing these methods.
+ *
+ */
+var ExtrasInitializer = {
+ initialize: function(className, viz) {
+ this.viz = viz;
+ this.canvas = viz.canvas;
+ this.config = viz.config[className];
+ this.nodeTypes = viz.fx.nodeTypes;
+ var type = this.config.type;
+ this.dom = type == 'auto'? (viz.config.Label.type != 'Native') : (type != 'Native');
+ this.labelContainer = this.dom && viz.labels.getLabelContainer();
+ this.isEnabled() && this.initializePost();
+ },
+ initializePost: $.empty,
+ setAsProperty: $.lambda(false),
+ isEnabled: function() {
+ return this.config.enable;
+ },
+ isLabel: function(e, win, group) {
+ e = $.event.get(e, win);
+ var labelContainer = this.labelContainer,
+ target = e.target || e.srcElement,
+ related = e.relatedTarget;
+ if(group) {
+ return related && related == this.viz.canvas.getCtx().canvas
+ && !!target && this.isDescendantOf(target, labelContainer);
+ } else {
+ return this.isDescendantOf(target, labelContainer);
+ }
+ },
+ isDescendantOf: function(elem, par) {
+ while(elem && elem.parentNode) {
+ if(elem.parentNode == par)
+ return elem;
+ elem = elem.parentNode;
+ }
+ return false;
+ }
+};
+
+var EventsInterface = {
+ onMouseUp: $.empty,
+ onMouseDown: $.empty,
+ onMouseMove: $.empty,
+ onMouseOver: $.empty,
+ onMouseOut: $.empty,
+ onMouseWheel: $.empty,
+ onTouchStart: $.empty,
+ onTouchMove: $.empty,
+ onTouchEnd: $.empty,
+ onTouchCancel: $.empty
+};
+
+var MouseEventsManager = new Class({
+ initialize: function(viz) {
+ this.viz = viz;
+ this.canvas = viz.canvas;
+ this.node = false;
+ this.edge = false;
+ this.registeredObjects = [];
+ this.attachEvents();
+ },
+
+ attachEvents: function() {
+ var htmlCanvas = this.canvas.getElement(),
+ that = this;
+ htmlCanvas.oncontextmenu = $.lambda(false);
+ $.addEvents(htmlCanvas, {
+ 'mouseup': function(e, win) {
+ var event = $.event.get(e, win);
+ that.handleEvent('MouseUp', e, win,
+ that.makeEventObject(e, win),
+ $.event.isRightClick(event));
+ },
+ 'mousedown': function(e, win) {
+ var event = $.event.get(e, win);
+ that.handleEvent('MouseDown', e, win, that.makeEventObject(e, win),
+ $.event.isRightClick(event));
+ },
+ 'mousemove': function(e, win) {
+ that.handleEvent('MouseMove', e, win, that.makeEventObject(e, win));
+ },
+ 'mouseover': function(e, win) {
+ that.handleEvent('MouseOver', e, win, that.makeEventObject(e, win));
+ },
+ 'mouseout': function(e, win) {
+ that.handleEvent('MouseOut', e, win, that.makeEventObject(e, win));
+ },
+ 'touchstart': function(e, win) {
+ that.handleEvent('TouchStart', e, win, that.makeEventObject(e, win));
+ },
+ 'touchmove': function(e, win) {
+ that.handleEvent('TouchMove', e, win, that.makeEventObject(e, win));
+ },
+ 'touchend': function(e, win) {
+ that.handleEvent('TouchEnd', e, win, that.makeEventObject(e, win));
+ }
+ });
+ //attach mousewheel event
+ var handleMouseWheel = function(e, win) {
+ var event = $.event.get(e, win);
+ var wheel = $.event.getWheel(event);
+ that.handleEvent('MouseWheel', e, win, wheel);
+ };
+ //TODO(nico): this is a horrible check for non-gecko browsers!
+ if(!document.getBoxObjectFor && window.mozInnerScreenX == null) {
+ $.addEvent(htmlCanvas, 'mousewheel', handleMouseWheel);
+ } else {
+ htmlCanvas.addEventListener('DOMMouseScroll', handleMouseWheel, false);
+ }
+ },
+
+ register: function(obj) {
+ this.registeredObjects.push(obj);
+ },
+
+ handleEvent: function() {
+ var args = Array.prototype.slice.call(arguments),
+ type = args.shift();
+ for(var i=0, regs=this.registeredObjects, l=regs.length; i<l; i++) {
+ regs[i]['on' + type].apply(regs[i], args);
+ }
+ },
+
+ makeEventObject: function(e, win) {
+ var that = this,
+ graph = this.viz.graph,
+ fx = this.viz.fx,
+ ntypes = fx.nodeTypes,
+ etypes = fx.edgeTypes;
+ return {
+ pos: false,
+ node: false,
+ edge: false,
+ contains: false,
+ getNodeCalled: false,
+ getEdgeCalled: false,
+ getPos: function() {
+ //TODO(nico): check why this can't be cache anymore when using edge detection
+ //if(this.pos) return this.pos;
+ var canvas = that.viz.canvas,
+ s = canvas.getSize(),
+ p = canvas.getPos(),
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ pos = $.event.getPos(e, win);
+ this.pos = {
+ x: (pos.x - p.x - s.width/2 - ox) * 1/sx,
+ y: (pos.y - p.y - s.height/2 - oy) * 1/sy
+ };
+ return this.pos;
+ },
+ getNode: function() {
+ if(this.getNodeCalled) return this.node;
+ this.getNodeCalled = true;
+ for(var id in graph.nodes) {
+ var n = graph.nodes[id],
+ geom = n && ntypes[n.getData('type')],
+ contains = geom && geom.contains && geom.contains.call(fx, n, this.getPos());
+ if(contains) {
+ this.contains = contains;
+ return that.node = this.node = n;
+ }
+ }
+ return that.node = this.node = false;
+ },
+ getEdge: function() {
+ if(this.getEdgeCalled) return this.edge;
+ this.getEdgeCalled = true;
+ var hashset = {};
+ for(var id in graph.edges) {
+ var edgeFrom = graph.edges[id];
+ hashset[id] = true;
+ for(var edgeId in edgeFrom) {
+ if(edgeId in hashset) continue;
+ var e = edgeFrom[edgeId],
+ geom = e && etypes[e.getData('type')],
+ contains = geom && geom.contains && geom.contains.call(fx, e, this.getPos());
+ if(contains) {
+ this.contains = contains;
+ return that.edge = this.edge = e;
+ }
+ }
+ }
+ return that.edge = this.edge = false;
+ },
+ getContains: function() {
+ if(this.getNodeCalled) return this.contains;
+ this.getNode();
+ return this.contains;
+ }
+ };
+ }
+});
+
+/*
+ * Provides the initialization function for <NodeStyles> and <Tips> implemented
+ * by all main visualizations.
+ *
+ */
+var Extras = {
+ initializeExtras: function() {
+ var mem = new MouseEventsManager(this), that = this;
+ $.each(['NodeStyles', 'Tips', 'Navigation', 'Events'], function(k) {
+ var obj = new Extras.Classes[k](k, that);
+ if(obj.isEnabled()) {
+ mem.register(obj);
+ }
+ if(obj.setAsProperty()) {
+ that[k.toLowerCase()] = obj;
+ }
+ });
+ }
+};
+
+Extras.Classes = {};
+/*
+ Class: Events
+
+ This class defines an Event API to be accessed by the user.
+ The methods implemented are the ones defined in the <Options.Events> object.
+*/
+
+Extras.Classes.Events = new Class({
+ Implements: [ExtrasInitializer, EventsInterface],
+
+ initializePost: function() {
+ this.fx = this.viz.fx;
+ this.ntypes = this.viz.fx.nodeTypes;
+ this.etypes = this.viz.fx.edgeTypes;
+
+ this.hovered = false;
+ this.pressed = false;
+ this.touched = false;
+
+ this.touchMoved = false;
+ this.moved = false;
+
+ },
+
+ setAsProperty: $.lambda(true),
+
+ onMouseUp: function(e, win, event, isRightClick) {
+ var evt = $.event.get(e, win);
+ if(!this.moved) {
+ if(isRightClick) {
+ this.config.onRightClick(this.hovered, event, evt);
+ } else {
+ this.config.onClick(this.pressed, event, evt);
+ }
+ }
+ if(this.pressed) {
+ if(this.moved) {
+ this.config.onDragEnd(this.pressed, event, evt);
+ } else {
+ this.config.onDragCancel(this.pressed, event, evt);
+ }
+ this.pressed = this.moved = false;
+ }
+ },
+
+ onMouseOut: function(e, win, event) {
+ //mouseout a label
+ var evt = $.event.get(e, win), label;
+ if(this.dom && (label = this.isLabel(e, win, true))) {
+ this.config.onMouseLeave(this.viz.graph.getNode(label.id),
+ event, evt);
+ this.hovered = false;
+ return;
+ }
+ //mouseout canvas
+ var rt = evt.relatedTarget,
+ canvasWidget = this.canvas.getElement();
+ while(rt && rt.parentNode) {
+ if(canvasWidget == rt.parentNode) return;
+ rt = rt.parentNode;
+ }
+ if(this.hovered) {
+ this.config.onMouseLeave(this.hovered,
+ event, evt);
+ this.hovered = false;
+ }
+ },
+
+ onMouseOver: function(e, win, event) {
+ //mouseover a label
+ var evt = $.event.get(e, win), label;
+ if(this.dom && (label = this.isLabel(e, win, true))) {
+ this.hovered = this.viz.graph.getNode(label.id);
+ this.config.onMouseEnter(this.hovered,
+ event, evt);
+ }
+ },
+
+ onMouseMove: function(e, win, event) {
+ var label, evt = $.event.get(e, win);
+ if(this.pressed) {
+ this.moved = true;
+ this.config.onDragMove(this.pressed, event, evt);
+ return;
+ }
+ if(this.dom) {
+ this.config.onMouseMove(this.hovered,
+ event, evt);
+ } else {
+ if(this.hovered) {
+ var hn = this.hovered;
+ var geom = hn.nodeFrom? this.etypes[hn.getData('type')] : this.ntypes[hn.getData('type')];
+ var contains = geom && geom.contains
+ && geom.contains.call(this.fx, hn, event.getPos());
+ if(contains) {
+ this.config.onMouseMove(hn, event, evt);
+ return;
+ } else {
+ this.config.onMouseLeave(hn, event, evt);
+ this.hovered = false;
+ }
+ }
+ if(this.hovered = (event.getNode() || (this.config.enableForEdges && event.getEdge()))) {
+ this.config.onMouseEnter(this.hovered, event, evt);
+ } else {
+ this.config.onMouseMove(false, event, evt);
+ }
+ }
+ },
+
+ onMouseWheel: function(e, win, delta) {
+ this.config.onMouseWheel(delta, $.event.get(e, win));
+ },
+
+ onMouseDown: function(e, win, event) {
+ var evt = $.event.get(e, win), label;
+ if(this.dom) {
+ if(label = this.isLabel(e, win)) {
+ this.pressed = this.viz.graph.getNode(label.id);
+ }
+ } else {
+ this.pressed = event.getNode() || (this.config.enableForEdges && event.getEdge());
+ }
+ this.pressed && this.config.onDragStart(this.pressed, event, evt);
+ },
+
+ onTouchStart: function(e, win, event) {
+ var evt = $.event.get(e, win), label;
+ if(this.dom && (label = this.isLabel(e, win))) {
+ this.touched = this.viz.graph.getNode(label.id);
+ } else {
+ this.touched = event.getNode() || (this.config.enableForEdges && event.getEdge());
+ }
+ this.touched && this.config.onTouchStart(this.touched, event, evt);
+ },
+
+ onTouchMove: function(e, win, event) {
+ var evt = $.event.get(e, win);
+ if(this.touched) {
+ this.touchMoved = true;
+ this.config.onTouchMove(this.touched, event, evt);
+ }
+ },
+
+ onTouchEnd: function(e, win, event) {
+ var evt = $.event.get(e, win);
+ if(this.touched) {
+ if(this.touchMoved) {
+ this.config.onTouchEnd(this.touched, event, evt);
+ } else {
+ this.config.onTouchCancel(this.touched, event, evt);
+ }
+ this.touched = this.touchMoved = false;
+ }
+ }
+});
+
+/*
+ Class: Tips
+
+ A class containing tip related functions. This class is used internally.
+
+ Used by:
+
+ <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>
+
+ See also:
+
+ <Options.Tips>
+*/
+
+Extras.Classes.Tips = new Class({
+ Implements: [ExtrasInitializer, EventsInterface],
+
+ initializePost: function() {
+ //add DOM tooltip
+ if(document.body) {
+ var tip = $('_tooltip') || document.createElement('div');
+ tip.id = '_tooltip';
+ tip.className = 'tip';
+ $.extend(tip.style, {
+ position: 'absolute',
+ display: 'none',
+ zIndex: 13000
+ });
+ document.body.appendChild(tip);
+ this.tip = tip;
+ this.node = false;
+ }
+ },
+
+ setAsProperty: $.lambda(true),
+
+ onMouseOut: function(e, win) {
+ //mouseout a label
+ var evt = $.event.get(e, win);
+ if(this.dom && this.isLabel(e, win, true)) {
+ this.hide(true);
+ return;
+ }
+ //mouseout canvas
+ var rt = e.relatedTarget,
+ canvasWidget = this.canvas.getElement();
+ while(rt && rt.parentNode) {
+ if(canvasWidget == rt.parentNode) return;
+ rt = rt.parentNode;
+ }
+ this.hide(false);
+ },
+
+ onMouseOver: function(e, win) {
+ //mouseover a label
+ var label;
+ if(this.dom && (label = this.isLabel(e, win, false))) {
+ this.node = this.viz.graph.getNode(label.id);
+ this.config.onShow(this.tip, this.node, label);
+ }
+ },
+
+ onMouseMove: function(e, win, opt) {
+ if(this.dom && this.isLabel(e, win)) {
+ this.setTooltipPosition($.event.getPos(e, win));
+ }
+ if(!this.dom) {
+ var node = opt.getNode();
+ if(!node) {
+ this.hide(true);
+ return;
+ }
+ if(this.config.force || !this.node || this.node.id != node.id) {
+ this.node = node;
+ this.config.onShow(this.tip, node, opt.getContains());
+ }
+ this.setTooltipPosition($.event.getPos(e, win));
+ }
+ },
+
+ setTooltipPosition: function(pos) {
+ var tip = this.tip,
+ style = tip.style,
+ cont = this.config;
+ style.display = '';
+ //get window dimensions
+ var win = {
+ 'height': document.body.clientHeight,
+ 'width': document.body.clientWidth
+ };
+ //get tooltip dimensions
+ var obj = {
+ 'width': tip.offsetWidth,
+ 'height': tip.offsetHeight
+ };
+ //set tooltip position
+ var x = cont.offsetX, y = cont.offsetY;
+ style.top = ((pos.y + y + obj.height > win.height)?
+ (pos.y - obj.height - y) : pos.y + y) + 'px';
+ style.left = ((pos.x + obj.width + x > win.width)?
+ (pos.x - obj.width - x) : pos.x + x) + 'px';
+ },
+
+ hide: function(triggerCallback) {
+ this.tip.style.display = 'none';
+ triggerCallback && this.config.onHide();
+ }
+});
+
+/*
+ Class: NodeStyles
+
+ Change node styles when clicking or hovering a node. This class is used internally.
+
+ Used by:
+
+ <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>
+
+ See also:
+
+ <Options.NodeStyles>
+*/
+Extras.Classes.NodeStyles = new Class({
+ Implements: [ExtrasInitializer, EventsInterface],
+
+ initializePost: function() {
+ this.fx = this.viz.fx;
+ this.types = this.viz.fx.nodeTypes;
+ this.nStyles = this.config;
+ this.nodeStylesOnHover = this.nStyles.stylesHover;
+ this.nodeStylesOnClick = this.nStyles.stylesClick;
+ this.hoveredNode = false;
+ this.fx.nodeFxAnimation = new Animation();
+
+ this.down = false;
+ this.move = false;
+ },
+
+ onMouseOut: function(e, win) {
+ this.down = this.move = false;
+ if(!this.hoveredNode) return;
+ //mouseout a label
+ if(this.dom && this.isLabel(e, win, true)) {
+ this.toggleStylesOnHover(this.hoveredNode, false);
+ }
+ //mouseout canvas
+ var rt = e.relatedTarget,
+ canvasWidget = this.canvas.getElement();
+ while(rt && rt.parentNode) {
+ if(canvasWidget == rt.parentNode) return;
+ rt = rt.parentNode;
+ }
+ this.toggleStylesOnHover(this.hoveredNode, false);
+ this.hoveredNode = false;
+ },
+
+ onMouseOver: function(e, win) {
+ //mouseover a label
+ var label;
+ if(this.dom && (label = this.isLabel(e, win, true))) {
+ var node = this.viz.graph.getNode(label.id);
+ if(node.selected) return;
+ this.hoveredNode = node;
+ this.toggleStylesOnHover(this.hoveredNode, true);
+ }
+ },
+
+ onMouseDown: function(e, win, event, isRightClick) {
+ if(isRightClick) return;
+ var label;
+ if(this.dom && (label = this.isLabel(e, win))) {
+ this.down = this.viz.graph.getNode(label.id);
+ } else if(!this.dom) {
+ this.down = event.getNode();
+ }
+ this.move = false;
+ },
+
+ onMouseUp: function(e, win, event, isRightClick) {
+ if(isRightClick) return;
+ if(!this.move) {
+ this.onClick(event.getNode());
+ }
+ this.down = this.move = false;
+ },
+
+ getRestoredStyles: function(node, type) {
+ var restoredStyles = {},
+ nStyles = this['nodeStylesOn' + type];
+ for(var prop in nStyles) {
+ restoredStyles[prop] = node.styles['$' + prop];
+ }
+ return restoredStyles;
+ },
+
+ toggleStylesOnHover: function(node, set) {
+ if(this.nodeStylesOnHover) {
+ this.toggleStylesOn('Hover', node, set);
+ }
+ },
+
+ toggleStylesOnClick: function(node, set) {
+ if(this.nodeStylesOnClick) {
+ this.toggleStylesOn('Click', node, set);
+ }
+ },
+
+ toggleStylesOn: function(type, node, set) {
+ var viz = this.viz;
+ var nStyles = this.nStyles;
+ if(set) {
+ var that = this;
+ if(!node.styles) {
+ node.styles = $.merge(node.data, {});
+ }
+ for(var s in this['nodeStylesOn' + type]) {
+ var $s = '$' + s;
+ if(!($s in node.styles)) {
+ node.styles[$s] = node.getData(s);
+ }
+ }
+ viz.fx.nodeFx($.extend({
+ 'elements': {
+ 'id': node.id,
+ 'properties': that['nodeStylesOn' + type]
+ },
+ transition: Trans.Quart.easeOut,
+ duration:300,
+ fps:40
+ }, this.config));
+ } else {
+ var restoredStyles = this.getRestoredStyles(node, type);
+ viz.fx.nodeFx($.extend({
+ 'elements': {
+ 'id': node.id,
+ 'properties': restoredStyles
+ },
+ transition: Trans.Quart.easeOut,
+ duration:300,
+ fps:40
+ }, this.config));
+ }
+ },
+
+ onClick: function(node) {
+ if(!node) return;
+ var nStyles = this.nodeStylesOnClick;
+ if(!nStyles) return;
+ //if the node is selected then unselect it
+ if(node.selected) {
+ this.toggleStylesOnClick(node, false);
+ delete node.selected;
+ } else {
+ //unselect all selected nodes...
+ this.viz.graph.eachNode(function(n) {
+ if(n.selected) {
+ for(var s in nStyles) {
+ n.setData(s, n.styles['$' + s], 'end');
+ }
+ delete n.selected;
+ }
+ });
+ //select clicked node
+ this.toggleStylesOnClick(node, true);
+ node.selected = true;
+ delete node.hovered;
+ this.hoveredNode = false;
+ }
+ },
+
+ onMouseMove: function(e, win, event) {
+ //if mouse button is down and moving set move=true
+ if(this.down) this.move = true;
+ //already handled by mouseover/out
+ if(this.dom && this.isLabel(e, win)) return;
+ var nStyles = this.nodeStylesOnHover;
+ if(!nStyles) return;
+
+ if(!this.dom) {
+ if(this.hoveredNode) {
+ var geom = this.types[this.hoveredNode.getData('type')];
+ var contains = geom && geom.contains && geom.contains.call(this.fx,
+ this.hoveredNode, event.getPos());
+ if(contains) return;
+ }
+ var node = event.getNode();
+ //if no node is being hovered then just exit
+ if(!this.hoveredNode && !node) return;
+ //if the node is hovered then exit
+ if(node.hovered) return;
+ //select hovered node
+ if(node && !node.selected) {
+ //check if an animation is running and exit it
+ this.fx.nodeFxAnimation.stopTimer();
+ //unselect all hovered nodes...
+ this.viz.graph.eachNode(function(n) {
+ if(n.hovered && !n.selected) {
+ for(var s in nStyles) {
+ n.setData(s, n.styles['$' + s], 'end');
+ }
+ delete n.hovered;
+ }
+ });
+ //select hovered node
+ node.hovered = true;
+ this.hoveredNode = node;
+ this.toggleStylesOnHover(node, true);
+ } else if(this.hoveredNode && !this.hoveredNode.selected) {
+ //check if an animation is running and exit it
+ this.fx.nodeFxAnimation.stopTimer();
+ //unselect hovered node
+ this.toggleStylesOnHover(this.hoveredNode, false);
+ delete this.hoveredNode.hovered;
+ this.hoveredNode = false;
+ }
+ }
+ }
+});
+
+Extras.Classes.Navigation = new Class({
+ Implements: [ExtrasInitializer, EventsInterface],
+
+ initializePost: function() {
+ this.pos = false;
+ this.pressed = false;
+ },
+
+ onMouseWheel: function(e, win, scroll) {
+ if(!this.config.zooming) return;
+ $.event.stop($.event.get(e, win));
+ var val = this.config.zooming / 1000,
+ ans = 1 + scroll * val;
+ this.canvas.scale(ans, ans);
+ },
+
+ onMouseDown: function(e, win, eventInfo) {
+ if(!this.config.panning) return;
+ if(this.config.panning == 'avoid nodes' && (this.dom? this.isLabel(e, win) : eventInfo.getNode())) return;
+ this.pressed = true;
+ this.pos = eventInfo.getPos();
+ var canvas = this.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY;
+ this.pos.x *= sx;
+ this.pos.x += ox;
+ this.pos.y *= sy;
+ this.pos.y += oy;
+ },
+
+ onMouseMove: function(e, win, eventInfo) {
+ if(!this.config.panning) return;
+ if(!this.pressed) return;
+ if(this.config.panning == 'avoid nodes' && (this.dom? this.isLabel(e, win) : eventInfo.getNode())) return;
+ var thispos = this.pos,
+ currentPos = eventInfo.getPos(),
+ canvas = this.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY;
+ currentPos.x *= sx;
+ currentPos.y *= sy;
+ currentPos.x += ox;
+ currentPos.y += oy;
+ var x = currentPos.x - thispos.x,
+ y = currentPos.y - thispos.y;
+ this.pos = currentPos;
+ this.canvas.translate(x * 1/sx, y * 1/sy);
+ },
+
+ onMouseUp: function(e, win, eventInfo, isRightClick) {
+ if(!this.config.panning) return;
+ this.pressed = false;
+ }
+});
+
+
+/*
+ * File: Canvas.js
+ *
+ */
+
+/*
+ Class: Canvas
+
+ A canvas widget used by all visualizations. The canvas object can be accessed by doing *viz.canvas*. If you want to
+ know more about <Canvas> options take a look at <Options.Canvas>.
+
+ A canvas widget is a set of DOM elements that wrap the native canvas DOM Element providing a consistent API and behavior
+ across all browsers. It can also include Elements to add DOM (SVG or HTML) label support to all visualizations.
+
+ Example:
+
+ Suppose we have this HTML
+
+ (start code xml)
+ <div id="infovis"></div>
+ (end code)
+
+ Now we create a new Visualization
+
+ (start code js)
+ var viz = new $jit.Viz({
+ //Where to inject the canvas. Any div container will do.
+ 'injectInto':'infovis',
+ //width and height for canvas.
+ //Default's to the container offsetWidth and Height.
+ 'width': 900,
+ 'height':500
+ });
+ (end code)
+
+ The generated HTML will look like this
+
+ (start code xml)
+ <div id="infovis">
+ <div id="infovis-canvaswidget" style="position:relative;">
+ <canvas id="infovis-canvas" width=900 height=500
+ style="position:absolute; top:0; left:0; width:900px; height:500px;" />
+ <div id="infovis-label"
+ style="overflow:visible; position:absolute; top:0; left:0; width:900px; height:0px">
+ </div>
+ </div>
+ </div>
+ (end code)
+
+ As you can see, the generated HTML consists of a canvas DOM Element of id *infovis-canvas* and a div label container
+ of id *infovis-label*, wrapped in a main div container of id *infovis-canvaswidget*.
+ */
+
+var Canvas;
+(function() {
+ //check for native canvas support
+ var canvasType = typeof HTMLCanvasElement,
+ supportsCanvas = (canvasType == 'object' || canvasType == 'function');
+ //create element function
+ function $E(tag, props) {
+ var elem = document.createElement(tag);
+ for(var p in props) {
+ if(typeof props[p] == "object") {
+ $.extend(elem[p], props[p]);
+ } else {
+ elem[p] = props[p];
+ }
+ }
+ if (tag == "canvas" && !supportsCanvas && G_vmlCanvasManager) {
+ elem = G_vmlCanvasManager.initElement(document.body.appendChild(elem));
+ }
+ return elem;
+ }
+ //canvas widget which we will call just Canvas
+ $jit.Canvas = Canvas = new Class({
+ canvases: [],
+ pos: false,
+ element: false,
+ labelContainer: false,
+ translateOffsetX: 0,
+ translateOffsetY: 0,
+ scaleOffsetX: 1,
+ scaleOffsetY: 1,
+
+ initialize: function(viz, opt) {
+ this.viz = viz;
+ this.opt = this.config = opt;
+ var id = $.type(opt.injectInto) == 'string'?
+ opt.injectInto:opt.injectInto.id,
+ type = opt.type,
+ idLabel = id + "-label",
+ wrapper = $(id),
+ width = opt.width || wrapper.offsetWidth,
+ height = opt.height || wrapper.offsetHeight;
+ this.id = id;
+ //canvas options
+ var canvasOptions = {
+ injectInto: id,
+ width: width,
+ height: height
+ };
+ //create main wrapper
+ this.element = $E('div', {
+ 'id': id + '-canvaswidget',
+ 'style': {
+ 'position': 'relative',
+ 'width': width + 'px',
+ 'height': height + 'px'
+ }
+ });
+ //create label container
+ this.labelContainer = this.createLabelContainer(opt.Label.type,
+ idLabel, canvasOptions);
+ //create primary canvas
+ this.canvases.push(new Canvas.Base[type]({
+ config: $.extend({idSuffix: '-canvas'}, canvasOptions),
+ plot: function(base) {
+ viz.fx.plot();
+ },
+ resize: function() {
+ viz.refresh();
+ }
+ }));
+ //create secondary canvas
+ var back = opt.background;
+ if(back) {
+ var backCanvas = new Canvas.Background[back.type](viz, $.extend(back, canvasOptions));
+ this.canvases.push(new Canvas.Base[type](backCanvas));
+ }
+ //insert canvases
+ var len = this.canvases.length;
+ while(len--) {
+ this.element.appendChild(this.canvases[len].canvas);
+ if(len > 0) {
+ this.canvases[len].plot();
+ }
+ }
+ this.element.appendChild(this.labelContainer);
+ wrapper.appendChild(this.element);
+ //Update canvas position when the page is scrolled.
+ var timer = null, that = this;
+ $.addEvent(window, 'scroll', function() {
+ clearTimeout(timer);
+ timer = setTimeout(function() {
+ that.getPos(true); //update canvas position
+ }, 500);
+ });
+ },
+ /*
+ Method: getCtx
+
+ Returns the main canvas context object
+
+ Example:
+
+ (start code js)
+ var ctx = canvas.getCtx();
+ //Now I can use the native canvas context
+ //and for example change some canvas styles
+ ctx.globalAlpha = 1;
+ (end code)
+ */
+ getCtx: function(i) {
+ return this.canvases[i || 0].getCtx();
+ },
+ /*
+ Method: getConfig
+
+ Returns the current Configuration for this Canvas Widget.
+
+ Example:
+
+ (start code js)
+ var config = canvas.getConfig();
+ (end code)
+ */
+ getConfig: function() {
+ return this.opt;
+ },
+ /*
+ Method: getElement
+
+ Returns the main Canvas DOM wrapper
+
+ Example:
+
+ (start code js)
+ var wrapper = canvas.getElement();
+ //Returns <div id="infovis-canvaswidget" ... >...</div> as element
+ (end code)
+ */
+ getElement: function() {
+ return this.element;
+ },
+ /*
+ Method: getSize
+
+ Returns canvas dimensions.
+
+ Returns:
+
+ An object with *width* and *height* properties.
+
+ Example:
+ (start code js)
+ canvas.getSize(); //returns { width: 900, height: 500 }
+ (end code)
+ */
+ getSize: function(i) {
+ return this.canvases[i || 0].getSize();
+ },
+ /*
+ Method: resize
+
+ Resizes the canvas.
+
+ Parameters:
+
+ width - New canvas width.
+ height - New canvas height.
+
+ Example:
+
+ (start code js)
+ canvas.resize(width, height);
+ (end code)
+
+ */
+ resize: function(width, height) {
+ this.getPos(true);
+ this.translateOffsetX = this.translateOffsetY = 0;
+ this.scaleOffsetX = this.scaleOffsetY = 1;
+ for(var i=0, l=this.canvases.length; i<l; i++) {
+ this.canvases[i].resize(width, height);
+ }
+ var style = this.element.style;
+ style.width = width + 'px';
+ style.height = height + 'px';
+ if(this.labelContainer)
+ this.labelContainer.style.width = width + 'px';
+ },
+ /*
+ Method: translate
+
+ Applies a translation to the canvas.
+
+ Parameters:
+
+ x - (number) x offset.
+ y - (number) y offset.
+ disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.
+
+ Example:
+
+ (start code js)
+ canvas.translate(30, 30);
+ (end code)
+
+ */
+ translate: function(x, y, disablePlot) {
+ this.translateOffsetX += x*this.scaleOffsetX;
+ this.translateOffsetY += y*this.scaleOffsetY;
+ for(var i=0, l=this.canvases.length; i<l; i++) {
+ this.canvases[i].translate(x, y, disablePlot);
+ }
+ },
+ /*
+ Method: scale
+
+ Scales the canvas.
+
+ Parameters:
+
+ x - (number) scale value.
+ y - (number) scale value.
+ disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.
+
+ Example:
+
+ (start code js)
+ canvas.scale(0.5, 0.5);
+ (end code)
+
+ */
+ scale: function(x, y, disablePlot) {
+ var px = this.scaleOffsetX * x,
+ py = this.scaleOffsetY * y;
+ var dx = this.translateOffsetX * (x -1) / px,
+ dy = this.translateOffsetY * (y -1) / py;
+ this.scaleOffsetX = px;
+ this.scaleOffsetY = py;
+ for(var i=0, l=this.canvases.length; i<l; i++) {
+ this.canvases[i].scale(x, y, true);
+ }
+ this.translate(dx, dy, false);
+ },
+ /*
+ Method: getPos
+
+ Returns the canvas position as an *x, y* object.
+
+ Parameters:
+
+ force - (boolean) Default's *false*. Set this to *true* if you want to recalculate the position without using any cache information.
+
+ Returns:
+
+ An object with *x* and *y* properties.
+
+ Example:
+ (start code js)
+ canvas.getPos(true); //returns { x: 900, y: 500 }
+ (end code)
+ */
+ getPos: function(force){
+ if(force || !this.pos) {
+ return this.pos = $.getPos(this.getElement());
+ }
+ return this.pos;
+ },
+ /*
+ Method: clear
+
+ Clears the canvas.
+ */
+ clear: function(i){
+ this.canvases[i||0].clear();
+ },
+
+ path: function(type, action){
+ var ctx = this.canvases[0].getCtx();
+ ctx.beginPath();
+ action(ctx);
+ ctx[type]();
+ ctx.closePath();
+ },
+
+ createLabelContainer: function(type, idLabel, dim) {
+ var NS = 'http://www.w3.org/2000/svg';
+ if(type == 'HTML' || type == 'Native') {
+ return $E('div', {
+ 'id': idLabel,
+ 'style': {
+ 'overflow': 'visible',
+ 'position': 'absolute',
+ 'top': 0,
+ 'left': 0,
+ 'width': dim.width + 'px',
+ 'height': 0
+ }
+ });
+ } else if(type == 'SVG') {
+ var svgContainer = document.createElementNS(NS, 'svg:svg');
+ svgContainer.setAttribute("width", dim.width);
+ svgContainer.setAttribute('height', dim.height);
+ var style = svgContainer.style;
+ style.position = 'absolute';
+ style.left = style.top = '0px';
+ var labelContainer = document.createElementNS(NS, 'svg:g');
+ labelContainer.setAttribute('width', dim.width);
+ labelContainer.setAttribute('height', dim.height);
+ labelContainer.setAttribute('x', 0);
+ labelContainer.setAttribute('y', 0);
+ labelContainer.setAttribute('id', idLabel);
+ svgContainer.appendChild(labelContainer);
+ return svgContainer;
+ }
+ }
+ });
+ //base canvas wrapper
+ Canvas.Base = {};
+ Canvas.Base['2D'] = new Class({
+ translateOffsetX: 0,
+ translateOffsetY: 0,
+ scaleOffsetX: 1,
+ scaleOffsetY: 1,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ this.opt = viz.config;
+ this.size = false;
+ this.createCanvas();
+ this.translateToCenter();
+ },
+ createCanvas: function() {
+ var opt = this.opt,
+ width = opt.width,
+ height = opt.height;
+ this.canvas = $E('canvas', {
+ 'id': opt.injectInto + opt.idSuffix,
+ 'width': width,
+ 'height': height,
+ 'style': {
+ 'position': 'absolute',
+ 'top': 0,
+ 'left': 0,
+ 'width': width + 'px',
+ 'height': height + 'px'
+ }
+ });
+ },
+ getCtx: function() {
+ if(!this.ctx)
+ return this.ctx = this.canvas.getContext('2d');
+ return this.ctx;
+ },
+ getSize: function() {
+ if(this.size) return this.size;
+ var canvas = this.canvas;
+ return this.size = {
+ width: canvas.width,
+ height: canvas.height
+ };
+ },
+ translateToCenter: function(ps) {
+ var size = this.getSize(),
+ width = ps? (size.width - ps.width - this.translateOffsetX*2) : size.width;
+ height = ps? (size.height - ps.height - this.translateOffsetY*2) : size.height;
+ var ctx = this.getCtx();
+ ps && ctx.scale(1/this.scaleOffsetX, 1/this.scaleOffsetY);
+ ctx.translate(width/2, height/2);
+ },
+ resize: function(width, height) {
+ var size = this.getSize(),
+ canvas = this.canvas,
+ styles = canvas.style;
+ this.size = false;
+ canvas.width = width;
+ canvas.height = height;
+ styles.width = width + "px";
+ styles.height = height + "px";
+ //small ExCanvas fix
+ if(!supportsCanvas) {
+ this.translateToCenter(size);
+ } else {
+ this.translateToCenter();
+ }
+ this.translateOffsetX =
+ this.translateOffsetY = 0;
+ this.scaleOffsetX =
+ this.scaleOffsetY = 1;
+ this.clear();
+ this.viz.resize(width, height, this);
+ },
+ translate: function(x, y, disablePlot) {
+ var sx = this.scaleOffsetX,
+ sy = this.scaleOffsetY;
+ this.translateOffsetX += x*sx;
+ this.translateOffsetY += y*sy;
+ this.getCtx().translate(x, y);
+ !disablePlot && this.plot();
+ },
+ scale: function(x, y, disablePlot) {
+ this.scaleOffsetX *= x;
+ this.scaleOffsetY *= y;
+ this.getCtx().scale(x, y);
+ !disablePlot && this.plot();
+ },
+ clear: function(){
+ var size = this.getSize(),
+ ox = this.translateOffsetX,
+ oy = this.translateOffsetY,
+ sx = this.scaleOffsetX,
+ sy = this.scaleOffsetY;
+ this.getCtx().clearRect((-size.width / 2 - ox) * 1/sx,
+ (-size.height / 2 - oy) * 1/sy,
+ size.width * 1/sx, size.height * 1/sy);
+ },
+ plot: function() {
+ this.clear();
+ this.viz.plot(this);
+ }
+ });
+ //background canvases
+ //TODO(nico): document this!
+ Canvas.Background = {};
+ Canvas.Background.Circles = new Class({
+ initialize: function(viz, options) {
+ this.viz = viz;
+ this.config = $.merge({
+ idSuffix: '-bkcanvas',
+ levelDistance: 100,
+ numberOfCircles: 6,
+ CanvasStyles: {},
+ offset: 0
+ }, options);
+ },
+ resize: function(width, height, base) {
+ this.plot(base);
+ },
+ plot: function(base) {
+ var canvas = base.canvas,
+ ctx = base.getCtx(),
+ conf = this.config,
+ styles = conf.CanvasStyles;
+ //set canvas styles
+ for(var s in styles) ctx[s] = styles[s];
+ var n = conf.numberOfCircles,
+ rho = conf.levelDistance;
+ for(var i=1; i<=n; i++) {
+ ctx.beginPath();
+ ctx.arc(0, 0, rho * i, 0, 2 * Math.PI, false);
+ ctx.stroke();
+ ctx.closePath();
+ }
+ //TODO(nico): print labels too!
+ }
+ });
+})();
+
+
+/*
+ * File: Polar.js
+ *
+ * Defines the <Polar> class.
+ *
+ * Description:
+ *
+ * The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+ *
+ * See also:
+ *
+ * <http://en.wikipedia.org/wiki/Polar_coordinates>
+ *
+*/
+
+/*
+ Class: Polar
+
+ A multi purpose polar representation.
+
+ Description:
+
+ The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Polar_coordinates>
+
+ Parameters:
+
+ theta - An angle.
+ rho - The norm.
+*/
+
+var Polar = function(theta, rho) {
+ this.theta = theta || 0;
+ this.rho = rho || 0;
+};
+
+$jit.Polar = Polar;
+
+Polar.prototype = {
+ /*
+ Method: getc
+
+ Returns a complex number.
+
+ Parameters:
+
+ simple - _optional_ If *true*, this method will return only an object holding x and y properties and not a <Complex> instance. Default's *false*.
+
+ Returns:
+
+ A complex number.
+ */
+ getc: function(simple) {
+ return this.toComplex(simple);
+ },
+
+ /*
+ Method: getp
+
+ Returns a <Polar> representation.
+
+ Returns:
+
+ A variable in polar coordinates.
+ */
+ getp: function() {
+ return this;
+ },
+
+
+ /*
+ Method: set
+
+ Sets a number.
+
+ Parameters:
+
+ v - A <Complex> or <Polar> instance.
+
+ */
+ set: function(v) {
+ v = v.getp();
+ this.theta = v.theta; this.rho = v.rho;
+ },
+
+ /*
+ Method: setc
+
+ Sets a <Complex> number.
+
+ Parameters:
+
+ x - A <Complex> number real part.
+ y - A <Complex> number imaginary part.
+
+ */
+ setc: function(x, y) {
+ this.rho = Math.sqrt(x * x + y * y);
+ this.theta = Math.atan2(y, x);
+ if(this.theta < 0) this.theta += Math.PI * 2;
+ },
+
+ /*
+ Method: setp
+
+ Sets a polar number.
+
+ Parameters:
+
+ theta - A <Polar> number angle property.
+ rho - A <Polar> number rho property.
+
+ */
+ setp: function(theta, rho) {
+ this.theta = theta;
+ this.rho = rho;
+ },
+
+ /*
+ Method: clone
+
+ Returns a copy of the current object.
+
+ Returns:
+
+ A copy of the real object.
+ */
+ clone: function() {
+ return new Polar(this.theta, this.rho);
+ },
+
+ /*
+ Method: toComplex
+
+ Translates from polar to cartesian coordinates and returns a new <Complex> instance.
+
+ Parameters:
+
+ simple - _optional_ If *true* this method will only return an object with x and y properties (and not the whole <Complex> instance). Default's *false*.
+
+ Returns:
+
+ A new <Complex> instance.
+ */
+ toComplex: function(simple) {
+ var x = Math.cos(this.theta) * this.rho;
+ var y = Math.sin(this.theta) * this.rho;
+ if(simple) return { 'x': x, 'y': y};
+ return new Complex(x, y);
+ },
+
+ /*
+ Method: add
+
+ Adds two <Polar> instances.
+
+ Parameters:
+
+ polar - A <Polar> number.
+
+ Returns:
+
+ A new Polar instance.
+ */
+ add: function(polar) {
+ return new Polar(this.theta + polar.theta, this.rho + polar.rho);
+ },
+
+ /*
+ Method: scale
+
+ Scales a polar norm.
+
+ Parameters:
+
+ number - A scale factor.
+
+ Returns:
+
+ A new Polar instance.
+ */
+ scale: function(number) {
+ return new Polar(this.theta, this.rho * number);
+ },
+
+ /*
+ Method: equals
+
+ Comparison method.
+
+ Returns *true* if the theta and rho properties are equal.
+
+ Parameters:
+
+ c - A <Polar> number.
+
+ Returns:
+
+ *true* if the theta and rho parameters for these objects are equal. *false* otherwise.
+ */
+ equals: function(c) {
+ return this.theta == c.theta && this.rho == c.rho;
+ },
+
+ /*
+ Method: $add
+
+ Adds two <Polar> instances affecting the current object.
+
+ Paramters:
+
+ polar - A <Polar> instance.
+
+ Returns:
+
+ The changed object.
+ */
+ $add: function(polar) {
+ this.theta = this.theta + polar.theta; this.rho += polar.rho;
+ return this;
+ },
+
+ /*
+ Method: $madd
+
+ Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.
+
+ Parameters:
+
+ polar - A <Polar> instance.
+
+ Returns:
+
+ The changed object.
+ */
+ $madd: function(polar) {
+ this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;
+ return this;
+ },
+
+
+ /*
+ Method: $scale
+
+ Scales a polar instance affecting the object.
+
+ Parameters:
+
+ number - A scaling factor.
+
+ Returns:
+
+ The changed object.
+ */
+ $scale: function(number) {
+ this.rho *= number;
+ return this;
+ },
+
+ /*
+ Method: isZero
+
+ Returns *true* if the number is zero.
+
+ */
+ isZero: function () {
+ var almostZero = 0.0001, abs = Math.abs;
+ return abs(this.theta) < almostZero && abs(this.rho) < almostZero;
+ },
+
+ /*
+ Method: interpolate
+
+ Calculates a polar interpolation between two points at a given delta moment.
+
+ Parameters:
+
+ elem - A <Polar> instance.
+ delta - A delta factor ranging [0, 1].
+
+ Returns:
+
+ A new <Polar> instance representing an interpolation between _this_ and _elem_
+ */
+ interpolate: function(elem, delta) {
+ var pi = Math.PI, pi2 = pi * 2;
+ var ch = function(t) {
+ var a = (t < 0)? (t % pi2) + pi2 : t % pi2;
+ return a;
+ };
+ var tt = this.theta, et = elem.theta;
+ var sum, diff = Math.abs(tt - et);
+ if(diff == pi) {
+ if(tt > et) {
+ sum = ch((et + ((tt - pi2) - et) * delta)) ;
+ } else {
+ sum = ch((et - pi2 + (tt - (et)) * delta));
+ }
+ } else if(diff >= pi) {
+ if(tt > et) {
+ sum = ch((et + ((tt - pi2) - et) * delta)) ;
+ } else {
+ sum = ch((et - pi2 + (tt - (et - pi2)) * delta));
+ }
+ } else {
+ sum = ch((et + (tt - et) * delta)) ;
+ }
+ var r = (this.rho - elem.rho) * delta + elem.rho;
+ return {
+ 'theta': sum,
+ 'rho': r
+ };
+ }
+};
+
+
+var $P = function(a, b) { return new Polar(a, b); };
+
+Polar.KER = $P(0, 0);
+
+
+
+/*
+ * File: Complex.js
+ *
+ * Defines the <Complex> class.
+ *
+ * Description:
+ *
+ * The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+ *
+ * See also:
+ *
+ * <http://en.wikipedia.org/wiki/Complex_number>
+ *
+*/
+
+/*
+ Class: Complex
+
+ A multi-purpose Complex Class with common methods.
+
+ Description:
+
+ The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Complex_number>
+
+ Parameters:
+
+ x - _optional_ A Complex number real part.
+ y - _optional_ A Complex number imaginary part.
+
+*/
+
+var Complex = function(x, y) {
+ this.x = x || 0;
+ this.y = y || 0;
+};
+
+$jit.Complex = Complex;
+
+Complex.prototype = {
+ /*
+ Method: getc
+
+ Returns a complex number.
+
+ Returns:
+
+ A complex number.
+ */
+ getc: function() {
+ return this;
+ },
+
+ /*
+ Method: getp
+
+ Returns a <Polar> representation of this number.
+
+ Parameters:
+
+ simple - _optional_ If *true*, this method will return only an object holding theta and rho properties and not a <Polar> instance. Default's *false*.
+
+ Returns:
+
+ A variable in <Polar> coordinates.
+ */
+ getp: function(simple) {
+ return this.toPolar(simple);
+ },
+
+
+ /*
+ Method: set
+
+ Sets a number.
+
+ Parameters:
+
+ c - A <Complex> or <Polar> instance.
+
+ */
+ set: function(c) {
+ c = c.getc(true);
+ this.x = c.x;
+ this.y = c.y;
+ },
+
+ /*
+ Method: setc
+
+ Sets a complex number.
+
+ Parameters:
+
+ x - A <Complex> number Real part.
+ y - A <Complex> number Imaginary part.
+
+ */
+ setc: function(x, y) {
+ this.x = x;
+ this.y = y;
+ },
+
+ /*
+ Method: setp
+
+ Sets a polar number.
+
+ Parameters:
+
+ theta - A <Polar> number theta property.
+ rho - A <Polar> number rho property.
+
+ */
+ setp: function(theta, rho) {
+ this.x = Math.cos(theta) * rho;
+ this.y = Math.sin(theta) * rho;
+ },
+
+ /*
+ Method: clone
+
+ Returns a copy of the current object.
+
+ Returns:
+
+ A copy of the real object.
+ */
+ clone: function() {
+ return new Complex(this.x, this.y);
+ },
+
+ /*
+ Method: toPolar
+
+ Transforms cartesian to polar coordinates.
+
+ Parameters:
+
+ simple - _optional_ If *true* this method will only return an object with theta and rho properties (and not the whole <Polar> instance). Default's *false*.
+
+ Returns:
+
+ A new <Polar> instance.
+ */
+
+ toPolar: function(simple) {
+ var rho = this.norm();
+ var atan = Math.atan2(this.y, this.x);
+ if(atan < 0) atan += Math.PI * 2;
+ if(simple) return { 'theta': atan, 'rho': rho };
+ return new Polar(atan, rho);
+ },
+ /*
+ Method: norm
+
+ Calculates a <Complex> number norm.
+
+ Returns:
+
+ A real number representing the complex norm.
+ */
+ norm: function () {
+ return Math.sqrt(this.squaredNorm());
+ },
+
+ /*
+ Method: squaredNorm
+
+ Calculates a <Complex> number squared norm.
+
+ Returns:
+
+ A real number representing the complex squared norm.
+ */
+ squaredNorm: function () {
+ return this.x*this.x + this.y*this.y;
+ },
+
+ /*
+ Method: add
+
+ Returns the result of adding two complex numbers.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of adding two complex numbers.
+ */
+ add: function(pos) {
+ return new Complex(this.x + pos.x, this.y + pos.y);
+ },
+
+ /*
+ Method: prod
+
+ Returns the result of multiplying two <Complex> numbers.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of multiplying two complex numbers.
+ */
+ prod: function(pos) {
+ return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);
+ },
+
+ /*
+ Method: conjugate
+
+ Returns the conjugate of this <Complex> number.
+
+ Does not alter the original object.
+
+ Returns:
+
+ The conjugate of this <Complex> number.
+ */
+ conjugate: function() {
+ return new Complex(this.x, -this.y);
+ },
+
+
+ /*
+ Method: scale
+
+ Returns the result of scaling a <Complex> instance.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ factor - A scale factor.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ scale: function(factor) {
+ return new Complex(this.x * factor, this.y * factor);
+ },
+
+ /*
+ Method: equals
+
+ Comparison method.
+
+ Returns *true* if both real and imaginary parts are equal.
+
+ Parameters:
+
+ c - A <Complex> instance.
+
+ Returns:
+
+ A boolean instance indicating if both <Complex> numbers are equal.
+ */
+ equals: function(c) {
+ return this.x == c.x && this.y == c.y;
+ },
+
+ /*
+ Method: $add
+
+ Returns the result of adding two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of adding two complex numbers.
+ */
+ $add: function(pos) {
+ this.x += pos.x; this.y += pos.y;
+ return this;
+ },
+
+ /*
+ Method: $prod
+
+ Returns the result of multiplying two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of multiplying two complex numbers.
+ */
+ $prod:function(pos) {
+ var x = this.x, y = this.y;
+ this.x = x*pos.x - y*pos.y;
+ this.y = y*pos.x + x*pos.y;
+ return this;
+ },
+
+ /*
+ Method: $conjugate
+
+ Returns the conjugate for this <Complex>.
+
+ Alters the original object.
+
+ Returns:
+
+ The conjugate for this complex.
+ */
+ $conjugate: function() {
+ this.y = -this.y;
+ return this;
+ },
+
+ /*
+ Method: $scale
+
+ Returns the result of scaling a <Complex> instance.
+
+ Alters the original object.
+
+ Parameters:
+
+ factor - A scale factor.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ $scale: function(factor) {
+ this.x *= factor; this.y *= factor;
+ return this;
+ },
+
+ /*
+ Method: $div
+
+ Returns the division of two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> number.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ $div: function(pos) {
+ var x = this.x, y = this.y;
+ var sq = pos.squaredNorm();
+ this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;
+ return this.$scale(1 / sq);
+ },
+
+ /*
+ Method: isZero
+
+ Returns *true* if the number is zero.
+
+ */
+ isZero: function () {
+ var almostZero = 0.0001, abs = Math.abs;
+ return abs(this.x) < almostZero && abs(this.y) < almostZero;
+ }
+};
+
+var $C = function(a, b) { return new Complex(a, b); };
+
+Complex.KER = $C(0, 0);
+
+
+
+/*
+ * File: Graph.js
+ *
+*/
+
+/*
+ Class: Graph
+
+ A Graph Class that provides useful manipulation functions. You can find more manipulation methods in the <Graph.Util> object.
+
+ An instance of this class can be accessed by using the *graph* parameter of any tree or graph visualization.
+
+ Example:
+
+ (start code js)
+ //create new visualization
+ var viz = new $jit.Viz(options);
+ //load JSON data
+ viz.loadJSON(json);
+ //access model
+ viz.graph; //<Graph> instance
+ (end code)
+
+ Implements:
+
+ The following <Graph.Util> methods are implemented in <Graph>
+
+ - <Graph.Util.getNode>
+ - <Graph.Util.eachNode>
+ - <Graph.Util.computeLevels>
+ - <Graph.Util.eachBFS>
+ - <Graph.Util.clean>
+ - <Graph.Util.getClosestNodeToPos>
+ - <Graph.Util.getClosestNodeToOrigin>
+
+*/
+
+$jit.Graph = new Class({
+
+ initialize: function(opt, Node, Edge, Label) {
+ var innerOptions = {
+ 'klass': Complex,
+ 'Node': {}
+ };
+ this.Node = Node;
+ this.Edge = Edge;
+ this.Label = Label;
+ this.opt = $.merge(innerOptions, opt || {});
+ this.nodes = {};
+ this.edges = {};
+
+ //add nodeList methods
+ var that = this;
+ this.nodeList = {};
+ for(var p in Accessors) {
+ that.nodeList[p] = (function(p) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments);
+ that.eachNode(function(n) {
+ n[p].apply(n, args);
+ });
+ };
+ })(p);
+ }
+
+ },
+
+/*
+ Method: getNode
+
+ Returns a <Graph.Node> by *id*.
+
+ Parameters:
+
+ id - (string) A <Graph.Node> id.
+
+ Example:
+
+ (start code js)
+ var node = graph.getNode('nodeId');
+ (end code)
+*/
+ getNode: function(id) {
+ if(this.hasNode(id)) return this.nodes[id];
+ return false;
+ },
+
+ /*
+ Method: get
+
+ An alias for <Graph.Util.getNode>. Returns a node by *id*.
+
+ Parameters:
+
+ id - (string) A <Graph.Node> id.
+
+ Example:
+
+ (start code js)
+ var node = graph.get('nodeId');
+ (end code)
+*/
+ get: function(id) {
+ return this.getNode(id);
+ },
+
+ /*
+ Method: getByName
+
+ Returns a <Graph.Node> by *name*.
+
+ Parameters:
+
+ name - (string) A <Graph.Node> name.
+
+ Example:
+
+ (start code js)
+ var node = graph.getByName('someName');
+ (end code)
+ */
+ getByName: function(name) {
+ for(var id in this.nodes) {
+ var n = this.nodes[id];
+ if(n.name == name) return n;
+ }
+ return false;
+ },
+
+/*
+ Method: getAdjacence
+
+ Returns a <Graph.Adjacence> object connecting nodes with ids *id* and *id2*.
+
+ Parameters:
+
+ id - (string) A <Graph.Node> id.
+ id2 - (string) A <Graph.Node> id.
+*/
+ getAdjacence: function (id, id2) {
+ if(id in this.edges) {
+ return this.edges[id][id2];
+ }
+ return false;
+ },
+
+ /*
+ Method: addNode
+
+ Adds a node.
+
+ Parameters:
+
+ obj - An object with the properties described below
+
+ id - (string) A node id
+ name - (string) A node's name
+ data - (object) A node's data hash
+
+ See also:
+ <Graph.Node>
+
+ */
+ addNode: function(obj) {
+ if(!this.nodes[obj.id]) {
+ var edges = this.edges[obj.id] = {};
+ this.nodes[obj.id] = new Graph.Node($.extend({
+ 'id': obj.id,
+ 'name': obj.name,
+ 'data': $.merge(obj.data || {}, {}),
+ 'adjacencies': edges
+ }, this.opt.Node),
+ this.opt.klass,
+ this.Node,
+ this.Edge,
+ this.Label);
+ }
+ return this.nodes[obj.id];
+ },
+
+ /*
+ Method: addAdjacence
+
+ Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.
+
+ Parameters:
+
+ obj - (object) A <Graph.Node> object.
+ obj2 - (object) Another <Graph.Node> object.
+ data - (object) A data object. Used to store some extra information in the <Graph.Adjacence> object created.
+
+ See also:
+
+ <Graph.Node>, <Graph.Adjacence>
+ */
+ addAdjacence: function (obj, obj2, data) {
+ if(!this.hasNode(obj.id)) { this.addNode(obj); }
+ if(!this.hasNode(obj2.id)) { this.addNode(obj2); }
+ obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
+ if(!obj.adjacentTo(obj2)) {
+ var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {};
+ var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {};
+ adjsObj[obj2.id] = adjsObj2[obj.id] = new Graph.Adjacence(obj, obj2, data, this.Edge, this.Label);
+ return adjsObj[obj2.id];
+ }
+ return this.edges[obj.id][obj2.id];
+ },
+
+ /*
+ Method: removeNode
+
+ Removes a <Graph.Node> matching the specified *id*.
+
+ Parameters:
+
+ id - (string) A node's id.
+
+ */
+ removeNode: function(id) {
+ if(this.hasNode(id)) {
+ delete this.nodes[id];
+ var adjs = this.edges[id];
+ for(var to in adjs) {
+ delete this.edges[to][id];
+ }
+ delete this.edges[id];
+ }
+ },
+
+/*
+ Method: removeAdjacence
+
+ Removes a <Graph.Adjacence> matching *id1* and *id2*.
+
+ Parameters:
+
+ id1 - (string) A <Graph.Node> id.
+ id2 - (string) A <Graph.Node> id.
+*/
+ removeAdjacence: function(id1, id2) {
+ delete this.edges[id1][id2];
+ delete this.edges[id2][id1];
+ },
+
+ /*
+ Method: hasNode
+
+ Returns a boolean indicating if the node belongs to the <Graph> or not.
+
+ Parameters:
+
+ id - (string) Node id.
+ */
+ hasNode: function(id) {
+ return id in this.nodes;
+ },
+
+ /*
+ Method: empty
+
+ Empties the Graph
+
+ */
+ empty: function() { this.nodes = {}; this.edges = {};}
+
+});
+
+var Graph = $jit.Graph;
+
+/*
+ Object: Accessors
+
+ Defines a set of methods for data, canvas and label styles manipulation implemented by <Graph.Node> and <Graph.Adjacence> instances.
+
+ */
+var Accessors;
+
+(function () {
+ var getDataInternal = function(prefix, prop, type, force, prefixConfig) {
+ var data;
+ type = type || 'current';
+ prefix = "$" + (prefix ? prefix + "-" : "");
+
+ if(type == 'current') {
+ data = this.data;
+ } else if(type == 'start') {
+ data = this.startData;
+ } else if(type == 'end') {
+ data = this.endData;
+ }
+
+ var dollar = prefix + prop;
+
+ if(force) {
+ return data[dollar];
+ }
+
+ if(!this.Config.overridable)
+ return prefixConfig[prop] || 0;
+
+ return (dollar in data) ?
+ data[dollar] : ((dollar in this.data) ? this.data[dollar] : (prefixConfig[prop] || 0));
+ }
+
+ var setDataInternal = function(prefix, prop, value, type) {
+ type = type || 'current';
+ prefix = '$' + (prefix ? prefix + '-' : '');
+
+ var data;
+
+ if(type == 'current') {
+ data = this.data;
+ } else if(type == 'start') {
+ data = this.startData;
+ } else if(type == 'end') {
+ data = this.endData;
+ }
+
+ data[prefix + prop] = value;
+ }
+
+ var removeDataInternal = function(prefix, properties) {
+ prefix = '$' + (prefix ? prefix + '-' : '');
+ var that = this;
+ $.each(properties, function(prop) {
+ var pref = prefix + prop;
+ delete that.data[pref];
+ delete that.endData[pref];
+ delete that.startData[pref];
+ });
+ }
+
+ Accessors = {
+ /*
+ Method: getData
+
+ Returns the specified data value property.
+ This is useful for querying special/reserved <Graph.Node> data properties
+ (i.e dollar prefixed properties).
+
+ Parameters:
+
+ prop - (string) The name of the property. The dollar sign is not needed. For
+ example *getData(width)* will return *data.$width*.
+ type - (string) The type of the data property queried. Default's "current". You can access *start* and *end*
+ data properties also. These properties are used when making animations.
+ force - (boolean) Whether to obtain the true value of the property (equivalent to
+ *data.$prop*) or to check for *node.overridable = true* first.
+
+ Returns:
+
+ The value of the dollar prefixed property or the global Node/Edge property
+ value if *overridable=false*
+
+ Example:
+ (start code js)
+ node.getData('width'); //will return node.data.$width if Node.overridable=true;
+ (end code)
+ */
+ getData: function(prop, type, force) {
+ return getDataInternal.call(this, "", prop, type, force, this.Config);
+ },
+
+
+ /*
+ Method: setData
+
+ Sets the current data property with some specific value.
+ This method is only useful for reserved (dollar prefixed) properties.
+
+ Parameters:
+
+ prop - (string) The name of the property. The dollar sign is not necessary. For
+ example *setData(width)* will set *data.$width*.
+ value - (mixed) The value to store.
+ type - (string) The type of the data property to store. Default's "current" but
+ can also be "start" or "end".
+
+ Example:
+
+ (start code js)
+ node.setData('width', 30);
+ (end code)
+
+ If we were to make an animation of a node/edge width then we could do
+
+ (start code js)
+ var node = viz.getNode('nodeId');
+ //set start and end values
+ node.setData('width', 10, 'start');
+ node.setData('width', 30, 'end');
+ //will animate nodes width property
+ viz.fx.animate({
+ modes: ['node-property:width'],
+ duration: 1000
+ });
+ (end code)
+ */
+ setData: function(prop, value, type) {
+ setDataInternal.call(this, "", prop, value, type);
+ },
+
+ /*
+ Method: setDataset
+
+ Convenience method to set multiple data values at once.
+
+ Parameters:
+
+ types - (array|string) A set of 'current', 'end' or 'start' values.
+ obj - (object) A hash containing the names and values of the properties to be altered.
+
+ Example:
+ (start code js)
+ node.setDataset(['current', 'end'], {
+ 'width': [100, 5],
+ 'color': ['#fff', '#ccc']
+ });
+ //...or also
+ node.setDataset('end', {
+ 'width': 5,
+ 'color': '#ccc'
+ });
+ (end code)
+
+ See also:
+
+ <Accessors.setData>
+
+ */
+ setDataset: function(types, obj) {
+ types = $.splat(types);
+ for(var attr in obj) {
+ for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
+ this.setData(attr, val[i], types[i]);
+ }
+ }
+ },
+
+ /*
+ Method: removeData
+
+ Remove data properties.
+
+ Parameters:
+
+ One or more property names as arguments. The dollar sign is not needed.
+
+ Example:
+ (start code js)
+ node.removeData('width'); //now the default width value is returned
+ (end code)
+ */
+ removeData: function() {
+ removeDataInternal.call(this, "", Array.prototype.slice.call(arguments));
+ },
+
+ /*
+ Method: getCanvasStyle
+
+ Returns the specified canvas style data value property. This is useful for
+ querying special/reserved <Graph.Node> canvas style data properties (i.e.
+ dollar prefixed properties that match with $canvas-<name of canvas style>).
+
+ Parameters:
+
+ prop - (string) The name of the property. The dollar sign is not needed. For
+ example *getCanvasStyle(shadowBlur)* will return *data[$canvas-shadowBlur]*.
+ type - (string) The type of the data property queried. Default's *current*. You can access *start* and *end*
+ data properties also.
+
+ Example:
+ (start code js)
+ node.getCanvasStyle('shadowBlur');
+ (end code)
+
+ See also:
+
+ <Accessors.getData>
+ */
+ getCanvasStyle: function(prop, type, force) {
+ return getDataInternal.call(
+ this, 'canvas', prop, type, force, this.Config.CanvasStyles);
+ },
+
+ /*
+ Method: setCanvasStyle
+
+ Sets the canvas style data property with some specific value.
+ This method is only useful for reserved (dollar prefixed) properties.
+
+ Parameters:
+
+ prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
+ value - (mixed) The value to set to the property.
+ type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
+
+ Example:
+
+ (start code js)
+ node.setCanvasStyle('shadowBlur', 30);
+ (end code)
+
+ If we were to make an animation of a node/edge shadowBlur canvas style then we could do
+
+ (start code js)
+ var node = viz.getNode('nodeId');
+ //set start and end values
+ node.setCanvasStyle('shadowBlur', 10, 'start');
+ node.setCanvasStyle('shadowBlur', 30, 'end');
+ //will animate nodes canvas style property for nodes
+ viz.fx.animate({
+ modes: ['node-style:shadowBlur'],
+ duration: 1000
+ });
+ (end code)
+
+ See also:
+
+ <Accessors.setData>.
+ */
+ setCanvasStyle: function(prop, value, type) {
+ setDataInternal.call(this, 'canvas', prop, value, type);
+ },
+
+ /*
+ Method: setCanvasStyles
+
+ Convenience method to set multiple styles at once.
+
+ Parameters:
+
+ types - (array|string) A set of 'current', 'end' or 'start' values.
+ obj - (object) A hash containing the names and values of the properties to be altered.
+
+ See also:
+
+ <Accessors.setDataset>.
+ */
+ setCanvasStyles: function(types, obj) {
+ types = $.splat(types);
+ for(var attr in obj) {
+ for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
+ this.setCanvasStyle(attr, val[i], types[i]);
+ }
+ }
+ },
+
+ /*
+ Method: removeCanvasStyle
+
+ Remove canvas style properties from data.
+
+ Parameters:
+
+ A variable number of canvas style strings.
+
+ See also:
+
+ <Accessors.removeData>.
+ */
+ removeCanvasStyle: function() {
+ removeDataInternal.call(this, 'canvas', Array.prototype.slice.call(arguments));
+ },
+
+ /*
+ Method: getLabelData
+
+ Returns the specified label data value property. This is useful for
+ querying special/reserved <Graph.Node> label options (i.e.
+ dollar prefixed properties that match with $label-<name of label style>).
+
+ Parameters:
+
+ prop - (string) The name of the property. The dollar sign prefix is not needed. For
+ example *getLabelData(size)* will return *data[$label-size]*.
+ type - (string) The type of the data property queried. Default's *current*. You can access *start* and *end*
+ data properties also.
+
+ See also:
+
+ <Accessors.getData>.
+ */
+ getLabelData: function(prop, type, force) {
+ return getDataInternal.call(
+ this, 'label', prop, type, force, this.Label);
+ },
+
+ /*
+ Method: setLabelData
+
+ Sets the current label data with some specific value.
+ This method is only useful for reserved (dollar prefixed) properties.
+
+ Parameters:
+
+ prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
+ value - (mixed) The value to set to the property.
+ type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
+
+ Example:
+
+ (start code js)
+ node.setLabelData('size', 30);
+ (end code)
+
+ If we were to make an animation of a node label size then we could do
+
+ (start code js)
+ var node = viz.getNode('nodeId');
+ //set start and end values
+ node.setLabelData('size', 10, 'start');
+ node.setLabelData('size', 30, 'end');
+ //will animate nodes label size
+ viz.fx.animate({
+ modes: ['label-property:size'],
+ duration: 1000
+ });
+ (end code)
+
+ See also:
+
+ <Accessors.setData>.
+ */
+ setLabelData: function(prop, value, type) {
+ setDataInternal.call(this, 'label', prop, value, type);
+ },
+
+ /*
+ Method: setLabelDataset
+
+ Convenience function to set multiple label data at once.
+
+ Parameters:
+
+ types - (array|string) A set of 'current', 'end' or 'start' values.
+ obj - (object) A hash containing the names and values of the properties to be altered.
+
+ See also:
+
+ <Accessors.setDataset>.
+ */
+ setLabelDataset: function(types, obj) {
+ types = $.splat(types);
+ for(var attr in obj) {
+ for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
+ this.setLabelData(attr, val[i], types[i]);
+ }
+ }
+ },
+
+ /*
+ Method: removeLabelData
+
+ Remove label properties from data.
+
+ Parameters:
+
+ A variable number of label property strings.
+
+ See also:
+
+ <Accessors.removeData>.
+ */
+ removeLabelData: function() {
+ removeDataInternal.call(this, 'label', Array.prototype.slice.call(arguments));
+ }
+ };
+})();
+
+/*
+ Class: Graph.Node
+
+ A <Graph> node.
+
+ Implements:
+
+ <Accessors> methods.
+
+ The following <Graph.Util> methods are implemented by <Graph.Node>
+
+ - <Graph.Util.eachAdjacency>
+ - <Graph.Util.eachLevel>
+ - <Graph.Util.eachSubgraph>
+ - <Graph.Util.eachSubnode>
+ - <Graph.Util.anySubnode>
+ - <Graph.Util.getSubnodes>
+ - <Graph.Util.getParents>
+ - <Graph.Util.isDescendantOf>
+*/
+Graph.Node = new Class({
+
+ initialize: function(opt, klass, Node, Edge, Label) {
+ var innerOptions = {
+ 'id': '',
+ 'name': '',
+ 'data': {},
+ 'startData': {},
+ 'endData': {},
+ 'adjacencies': {},
+
+ 'selected': false,
+ 'drawn': false,
+ 'exist': false,
+
+ 'angleSpan': {
+ 'begin': 0,
+ 'end' : 0
+ },
+
+ 'pos': new klass,
+ 'startPos': new klass,
+ 'endPos': new klass
+ };
+
+ $.extend(this, $.extend(innerOptions, opt));
+ this.Config = this.Node = Node;
+ this.Edge = Edge;
+ this.Label = Label;
+ },
+
+ /*
+ Method: adjacentTo
+
+ Indicates if the node is adjacent to the node specified by id
+
+ Parameters:
+
+ id - (string) A node id.
+
+ Example:
+ (start code js)
+ node.adjacentTo('nodeId') == true;
+ (end code)
+ */
+ adjacentTo: function(node) {
+ return node.id in this.adjacencies;
+ },
+
+ /*
+ Method: getAdjacency
+
+ Returns a <Graph.Adjacence> object connecting the current <Graph.Node> and the node having *id* as id.
+
+ Parameters:
+
+ id - (string) A node id.
+ */
+ getAdjacency: function(id) {
+ return this.adjacencies[id];
+ },
+
+ /*
+ Method: getPos
+
+ Returns the position of the node.
+
+ Parameters:
+
+ type - (string) Default's *current*. Possible values are "start", "end" or "current".
+
+ Returns:
+
+ A <Complex> or <Polar> instance.
+
+ Example:
+ (start code js)
+ var pos = node.getPos('end');
+ (end code)
+ */
+ getPos: function(type) {
+ type = type || "current";
+ if(type == "current") {
+ return this.pos;
+ } else if(type == "end") {
+ return this.endPos;
+ } else if(type == "start") {
+ return this.startPos;
+ }
+ },
+ /*
+ Method: setPos
+
+ Sets the node's position.
+
+ Parameters:
+
+ value - (object) A <Complex> or <Polar> instance.
+ type - (string) Default's *current*. Possible values are "start", "end" or "current".
+
+ Example:
+ (start code js)
+ node.setPos(new $jit.Complex(0, 0), 'end');
+ (end code)
+ */
+ setPos: function(value, type) {
+ type = type || "current";
+ var pos;
+ if(type == "current") {
+ pos = this.pos;
+ } else if(type == "end") {
+ pos = this.endPos;
+ } else if(type == "start") {
+ pos = this.startPos;
+ }
+ pos.set(value);
+ }
+});
+
+Graph.Node.implement(Accessors);
+
+/*
+ Class: Graph.Adjacence
+
+ A <Graph> adjacence (or edge) connecting two <Graph.Nodes>.
+
+ Implements:
+
+ <Accessors> methods.
+
+ See also:
+
+ <Graph>, <Graph.Node>
+
+ Properties:
+
+ nodeFrom - A <Graph.Node> connected by this edge.
+ nodeTo - Another <Graph.Node> connected by this edge.
+ data - Node data property containing a hash (i.e {}) with custom options.
+*/
+Graph.Adjacence = new Class({
+
+ initialize: function(nodeFrom, nodeTo, data, Edge, Label) {
+ this.nodeFrom = nodeFrom;
+ this.nodeTo = nodeTo;
+ this.data = data || {};
+ this.startData = {};
+ this.endData = {};
+ this.Config = this.Edge = Edge;
+ this.Label = Label;
+ }
+});
+
+Graph.Adjacence.implement(Accessors);
+
+/*
+ Object: Graph.Util
+
+ <Graph> traversal and processing utility object.
+
+ Note:
+
+ For your convenience some of these methods have also been appended to <Graph> and <Graph.Node> classes.
+*/
+Graph.Util = {
+ /*
+ filter
+
+ For internal use only. Provides a filtering function based on flags.
+ */
+ filter: function(param) {
+ if(!param || !($.type(param) == 'string')) return function() { return true; };
+ var props = param.split(" ");
+ return function(elem) {
+ for(var i=0; i<props.length; i++) {
+ if(elem[props[i]]) {
+ return false;
+ }
+ }
+ return true;
+ };
+ },
+ /*
+ Method: getNode
+
+ Returns a <Graph.Node> by *id*.
+
+ Also implemented by:
+
+ <Graph>
+
+ Parameters:
+
+ graph - (object) A <Graph> instance.
+ id - (string) A <Graph.Node> id.
+
+ Example:
+
+ (start code js)
+ $jit.Graph.Util.getNode(graph, 'nodeid');
+ //or...
+ graph.getNode('nodeid');
+ (end code)
+ */
+ getNode: function(graph, id) {
+ return graph.nodes[id];
+ },
+
+ /*
+ Method: eachNode
+
+ Iterates over <Graph> nodes performing an *action*.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+
+ graph - (object) A <Graph> instance.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.eachNode(graph, function(node) {
+ alert(node.name);
+ });
+ //or...
+ graph.eachNode(function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachNode: function(graph, action, flags) {
+ var filter = this.filter(flags);
+ for(var i in graph.nodes) {
+ if(filter(graph.nodes[i])) action(graph.nodes[i]);
+ }
+ },
+
+ /*
+ Method: each
+
+ Iterates over <Graph> nodes performing an *action*. It's an alias for <Graph.Util.eachNode>.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+
+ graph - (object) A <Graph> instance.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.each(graph, function(node) {
+ alert(node.name);
+ });
+ //or...
+ graph.each(function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ each: function(graph, action, flags) {
+ this.eachNode(graph, action, flags);
+ },
+
+ /*
+ Method: eachAdjacency
+
+ Iterates over <Graph.Node> adjacencies applying the *action* function.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ action - (function) A callback function having <Graph.Adjacence> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.eachAdjacency(node, function(adj) {
+ alert(adj.nodeTo.name);
+ });
+ //or...
+ node.eachAdjacency(function(adj) {
+ alert(adj.nodeTo.name);
+ });
+ (end code)
+ */
+ eachAdjacency: function(node, action, flags) {
+ var adj = node.adjacencies, filter = this.filter(flags);
+ for(var id in adj) {
+ var a = adj[id];
+ if(filter(a)) {
+ if(a.nodeFrom != node) {
+ var tmp = a.nodeFrom;
+ a.nodeFrom = a.nodeTo;
+ a.nodeTo = tmp;
+ }
+ action(a, id);
+ }
+ }
+ },
+
+ /*
+ Method: computeLevels
+
+ Performs a BFS traversal setting the correct depth for each node.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Note:
+
+ The depth of each node can then be accessed by
+ >node._depth
+
+ Parameters:
+
+ graph - (object) A <Graph>.
+ id - (string) A starting node id for the BFS traversal.
+ startDepth - (optional|number) A minimum depth value. Default's 0.
+
+ */
+ computeLevels: function(graph, id, startDepth, flags) {
+ startDepth = startDepth || 0;
+ var filter = this.filter(flags);
+ this.eachNode(graph, function(elem) {
+ elem._flag = false;
+ elem._depth = -1;
+ }, flags);
+ var root = graph.getNode(id);
+ root._depth = startDepth;
+ var queue = [root];
+ while(queue.length != 0) {
+ var node = queue.pop();
+ node._flag = true;
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._flag == false && filter(n)) {
+ if(n._depth < 0) n._depth = node._depth + 1 + startDepth;
+ queue.unshift(n);
+ }
+ }, flags);
+ }
+ },
+
+ /*
+ Method: eachBFS
+
+ Performs a BFS traversal applying *action* to each <Graph.Node>.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+
+ graph - (object) A <Graph>.
+ id - (string) A starting node id for the BFS traversal.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.eachBFS(graph, 'mynodeid', function(node) {
+ alert(node.name);
+ });
+ //or...
+ graph.eachBFS('mynodeid', function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachBFS: function(graph, id, action, flags) {
+ var filter = this.filter(flags);
+ this.clean(graph);
+ var queue = [graph.getNode(id)];
+ while(queue.length != 0) {
+ var node = queue.pop();
+ node._flag = true;
+ action(node, node._depth);
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._flag == false && filter(n)) {
+ n._flag = true;
+ queue.unshift(n);
+ }
+ }, flags);
+ }
+ },
+
+ /*
+ Method: eachLevel
+
+ Iterates over a node's subgraph applying *action* to the nodes of relative depth between *levelBegin* and *levelEnd*.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ levelBegin - (number) A relative level value.
+ levelEnd - (number) A relative level value.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ */
+ eachLevel: function(node, levelBegin, levelEnd, action, flags) {
+ var d = node._depth, filter = this.filter(flags), that = this;
+ levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd;
+ (function loopLevel(node, levelBegin, levelEnd) {
+ var d = node._depth;
+ if(d >= levelBegin && d <= levelEnd && filter(node)) action(node, d);
+ if(d < levelEnd) {
+ that.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._depth > d) loopLevel(n, levelBegin, levelEnd);
+ });
+ }
+ })(node, levelBegin + d, levelEnd + d);
+ },
+
+ /*
+ Method: eachSubgraph
+
+ Iterates over a node's children recursively.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.eachSubgraph(node, function(node) {
+ alert(node.name);
+ });
+ //or...
+ node.eachSubgraph(function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachSubgraph: function(node, action, flags) {
+ this.eachLevel(node, 0, false, action, flags);
+ },
+
+ /*
+ Method: eachSubnode
+
+ Iterates over a node's children (without deeper recursion).
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+ action - (function) A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.eachSubnode(node, function(node) {
+ alert(node.name);
+ });
+ //or...
+ node.eachSubnode(function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachSubnode: function(node, action, flags) {
+ this.eachLevel(node, 1, 1, action, flags);
+ },
+
+ /*
+ Method: anySubnode
+
+ Returns *true* if any subnode matches the given condition.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+ cond - (function) A callback function returning a Boolean instance. This function has as first formal parameter a <Graph.Node>.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.anySubnode(node, function(node) { return node.name == "mynodename"; });
+ //or...
+ node.anySubnode(function(node) { return node.name == 'mynodename'; });
+ (end code)
+ */
+ anySubnode: function(node, cond, flags) {
+ var flag = false;
+ cond = cond || $.lambda(true);
+ var c = $.type(cond) == 'string'? function(n) { return n[cond]; } : cond;
+ this.eachSubnode(node, function(elem) {
+ if(c(elem)) flag = true;
+ }, flags);
+ return flag;
+ },
+
+ /*
+ Method: getSubnodes
+
+ Collects all subnodes for a specified node.
+ The *level* parameter filters nodes having relative depth of *level* from the root node.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+ level - (optional|number) Default's *0*. A starting relative depth for collecting nodes.
+
+ Returns:
+ An array of nodes.
+
+ */
+ getSubnodes: function(node, level, flags) {
+ var ans = [], that = this;
+ level = level || 0;
+ var levelStart, levelEnd;
+ if($.type(level) == 'array') {
+ levelStart = level[0];
+ levelEnd = level[1];
+ } else {
+ levelStart = level;
+ levelEnd = Number.MAX_VALUE - node._depth;
+ }
+ this.eachLevel(node, levelStart, levelEnd, function(n) {
+ ans.push(n);
+ }, flags);
+ return ans;
+ },
+
+
+ /*
+ Method: getParents
+
+ Returns an Array of <Graph.Nodes> which are parents of the given node.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+
+ Returns:
+ An Array of <Graph.Nodes>.
+
+ Example:
+ (start code js)
+ var pars = $jit.Graph.Util.getParents(node);
+ //or...
+ var pars = node.getParents();
+
+ if(pars.length > 0) {
+ //do stuff with parents
+ }
+ (end code)
+ */
+ getParents: function(node) {
+ var ans = [];
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._depth < node._depth) ans.push(n);
+ });
+ return ans;
+ },
+
+ /*
+ Method: isDescendantOf
+
+ Returns a boolean indicating if some node is descendant of the node with the given id.
+
+ Also implemented by:
+
+ <Graph.Node>.
+
+
+ Parameters:
+ node - (object) A <Graph.Node>.
+ id - (string) A <Graph.Node> id.
+
+ Example:
+ (start code js)
+ $jit.Graph.Util.isDescendantOf(node, "nodeid"); //true|false
+ //or...
+ node.isDescendantOf('nodeid');//true|false
+ (end code)
+ */
+ isDescendantOf: function(node, id) {
+ if(node.id == id) return true;
+ var pars = this.getParents(node), ans = false;
+ for ( var i = 0; !ans && i < pars.length; i++) {
+ ans = ans || this.isDescendantOf(pars[i], id);
+ }
+ return ans;
+ },
+
+ /*
+ Method: clean
+
+ Cleans flags from nodes.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+ graph - A <Graph> instance.
+ */
+ clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); },
+
+ /*
+ Method: getClosestNodeToOrigin
+
+ Returns the closest node to the center of canvas.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+
+ graph - (object) A <Graph> instance.
+ prop - (optional|string) Default's 'current'. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
+
+ */
+ getClosestNodeToOrigin: function(graph, prop, flags) {
+ return this.getClosestNodeToPos(graph, Polar.KER, prop, flags);
+ },
+
+ /*
+ Method: getClosestNodeToPos
+
+ Returns the closest node to the given position.
+
+ Also implemented by:
+
+ <Graph>.
+
+ Parameters:
+
+ graph - (object) A <Graph> instance.
+ pos - (object) A <Complex> or <Polar> instance.
+ prop - (optional|string) Default's *current*. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
+
+ */
+ getClosestNodeToPos: function(graph, pos, prop, flags) {
+ var node = null;
+ prop = prop || 'current';
+ pos = pos && pos.getc(true) || Complex.KER;
+ var distance = function(a, b) {
+ var d1 = a.x - b.x, d2 = a.y - b.y;
+ return d1 * d1 + d2 * d2;
+ };
+ this.eachNode(graph, function(elem) {
+ node = (node == null || distance(elem.getPos(prop).getc(true), pos) < distance(
+ node.getPos(prop).getc(true), pos)) ? elem : node;
+ }, flags);
+ return node;
+ }
+};
+
+//Append graph methods to <Graph>
+$.each(['get', 'getNode', 'each', 'eachNode', 'computeLevels', 'eachBFS', 'clean', 'getClosestNodeToPos', 'getClosestNodeToOrigin'], function(m) {
+ Graph.prototype[m] = function() {
+ return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
+ };
+});
+
+//Append node methods to <Graph.Node>
+$.each(['eachAdjacency', 'eachLevel', 'eachSubgraph', 'eachSubnode', 'anySubnode', 'getSubnodes', 'getParents', 'isDescendantOf'], function(m) {
+ Graph.Node.prototype[m] = function() {
+ return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
+ };
+});
+
+/*
+ * File: Graph.Op.js
+ *
+*/
+
+/*
+ Object: Graph.Op
+
+ Perform <Graph> operations like adding/removing <Graph.Nodes> or <Graph.Adjacences>,
+ morphing a <Graph> into another <Graph>, contracting or expanding subtrees, etc.
+
+*/
+Graph.Op = {
+
+ options: {
+ type: 'nothing',
+ duration: 2000,
+ hideLabels: true,
+ fps:30
+ },
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ /*
+ Method: removeNode
+
+ Removes one or more <Graph.Nodes> from the visualization.
+ It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
+
+ Parameters:
+
+ node - (string|array) The node's id. Can also be an array having many ids.
+ opt - (object) Animation options. It's an object with optional properties described below
+ type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter".
+ duration - Described in <Options.Fx>.
+ fps - Described in <Options.Fx>.
+ transition - Described in <Options.Fx>.
+ hideLabels - (boolean) Default's *true*. Hide labels during the animation.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.op.removeNode('nodeId', {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ //or also
+ viz.op.removeNode(['someId', 'otherId'], {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+ */
+
+ removeNode: function(node, opt) {
+ var viz = this.viz;
+ var options = $.merge(this.options, viz.controller, opt);
+ var n = $.splat(node);
+ var i, that, nodeObj;
+ switch(options.type) {
+ case 'nothing':
+ for(i=0; i<n.length; i++) viz.graph.removeNode(n[i]);
+ break;
+
+ case 'replot':
+ this.removeNode(n, { type: 'nothing' });
+ viz.labels.clearLabels();
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade':
+ that = this;
+ //set alpha to 0 for nodes to remove.
+ for(i=0; i<n.length; i++) {
+ nodeObj = viz.graph.getNode(n[i]);
+ nodeObj.setData('alpha', 0, 'end');
+ }
+ viz.fx.animate($.merge(options, {
+ modes: ['node-property:alpha'],
+ onComplete: function() {
+ that.removeNode(n, { type: 'nothing' });
+ viz.labels.clearLabels();
+ viz.reposition();
+ viz.fx.animate($.merge(options, {
+ modes: ['linear']
+ }));
+ }
+ }));
+ break;
+
+ case 'fade:con':
+ that = this;
+ //set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.
+ for(i=0; i<n.length; i++) {
+ nodeObj = viz.graph.getNode(n[i]);
+ nodeObj.setData('alpha', 0, 'end');
+ nodeObj.ignore = true;
+ }
+ viz.reposition();
+ viz.fx.animate($.merge(options, {
+ modes: ['node-property:alpha', 'linear'],
+ onComplete: function() {
+ that.removeNode(n, { type: 'nothing' });
+ options.onComplete && options.onComplete();
+ }
+ }));
+ break;
+
+ case 'iter':
+ that = this;
+ viz.fx.sequence({
+ condition: function() { return n.length != 0; },
+ step: function() { that.removeNode(n.shift(), { type: 'nothing' }); viz.labels.clearLabels(); },
+ onComplete: function() { options.onComplete && options.onComplete(); },
+ duration: Math.ceil(options.duration / n.length)
+ });
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: removeEdge
+
+ Removes one or more <Graph.Adjacences> from the visualization.
+ It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
+
+ Parameters:
+
+ vertex - (array) An array having two strings which are the ids of the nodes connected by this edge (i.e ['id1', 'id2']). Can also be a two dimensional array holding many edges (i.e [['id1', 'id2'], ['id3', 'id4'], ...]).
+ opt - (object) Animation options. It's an object with optional properties described below
+ type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter".
+ duration - Described in <Options.Fx>.
+ fps - Described in <Options.Fx>.
+ transition - Described in <Options.Fx>.
+ hideLabels - (boolean) Default's *true*. Hide labels during the animation.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.op.removeEdge(['nodeId', 'otherId'], {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ //or also
+ viz.op.removeEdge([['someId', 'otherId'], ['id3', 'id4']], {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+
+ */
+ removeEdge: function(vertex, opt) {
+ var viz = this.viz;
+ var options = $.merge(this.options, viz.controller, opt);
+ var v = ($.type(vertex[0]) == 'string')? [vertex] : vertex;
+ var i, that, adj;
+ switch(options.type) {
+ case 'nothing':
+ for(i=0; i<v.length; i++) viz.graph.removeAdjacence(v[i][0], v[i][1]);
+ break;
+
+ case 'replot':
+ this.removeEdge(v, { type: 'nothing' });
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade':
+ that = this;
+ //set alpha to 0 for edges to remove.
+ for(i=0; i<v.length; i++) {
+ adj = viz.graph.getAdjacence(v[i][0], v[i][1]);
+ if(adj) {
+ adj.setData('alpha', 0,'end');
+ }
+ }
+ viz.fx.animate($.merge(options, {
+ modes: ['edge-property:alpha'],
+ onComplete: function() {
+ that.removeEdge(v, { type: 'nothing' });
+ viz.reposition();
+ viz.fx.animate($.merge(options, {
+ modes: ['linear']
+ }));
+ }
+ }));
+ break;
+
+ case 'fade:con':
+ that = this;
+ //set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.
+ for(i=0; i<v.length; i++) {
+ adj = viz.graph.getAdjacence(v[i][0], v[i][1]);
+ if(adj) {
+ adj.setData('alpha',0 ,'end');
+ adj.ignore = true;
+ }
+ }
+ viz.reposition();
+ viz.fx.animate($.merge(options, {
+ modes: ['edge-property:alpha', 'linear'],
+ onComplete: function() {
+ that.removeEdge(v, { type: 'nothing' });
+ options.onComplete && options.onComplete();
+ }
+ }));
+ break;
+
+ case 'iter':
+ that = this;
+ viz.fx.sequence({
+ condition: function() { return v.length != 0; },
+ step: function() { that.removeEdge(v.shift(), { type: 'nothing' }); viz.labels.clearLabels(); },
+ onComplete: function() { options.onComplete(); },
+ duration: Math.ceil(options.duration / v.length)
+ });
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: sum
+
+ Adds a new graph to the visualization.
+ The JSON graph (or tree) must at least have a common node with the current graph plotted by the visualization.
+ The resulting graph can be defined as follows <http://mathworld.wolfram.com/GraphSum.html>
+
+ Parameters:
+
+ json - (object) A json tree or graph structure. See also <Loader.loadJSON>.
+ opt - (object) Animation options. It's an object with optional properties described below
+ type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con".
+ duration - Described in <Options.Fx>.
+ fps - Described in <Options.Fx>.
+ transition - Described in <Options.Fx>.
+ hideLabels - (boolean) Default's *true*. Hide labels during the animation.
+
+ Example:
+ (start code js)
+ //...json contains a tree or graph structure...
+
+ var viz = new $jit.Viz(options);
+ viz.op.sum(json, {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ //or also
+ viz.op.sum(json, {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+
+ */
+ sum: function(json, opt) {
+ var viz = this.viz;
+ var options = $.merge(this.options, viz.controller, opt), root = viz.root;
+ var graph;
+ viz.root = opt.id || viz.root;
+ switch(options.type) {
+ case 'nothing':
+ graph = viz.construct(json);
+ graph.eachNode(function(elem) {
+ elem.eachAdjacency(function(adj) {
+ viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
+ });
+ });
+ break;
+
+ case 'replot':
+ viz.refresh(true);
+ this.sum(json, { type: 'nothing' });
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade': case 'fade:con':
+ that = this;
+ graph = viz.construct(json);
+
+ //set alpha to 0 for nodes to add.
+ var fadeEdges = this.preprocessSum(graph);
+ var modes = !fadeEdges? ['node-property:alpha'] : ['node-property:alpha', 'edge-property:alpha'];
+ viz.reposition();
+ if(options.type != 'fade:con') {
+ viz.fx.animate($.merge(options, {
+ modes: ['linear'],
+ onComplete: function() {
+ viz.fx.animate($.merge(options, {
+ modes: modes,
+ onComplete: function() {
+ options.onComplete();
+ }
+ }));
+ }
+ }));
+ } else {
+ viz.graph.eachNode(function(elem) {
+ if (elem.id != root && elem.pos.isZero()) {
+ elem.pos.set(elem.endPos);
+ elem.startPos.set(elem.endPos);
+ }
+ });
+ viz.fx.animate($.merge(options, {
+ modes: ['linear'].concat(modes)
+ }));
+ }
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: morph
+
+ This method will transform the current visualized graph into the new JSON representation passed in the method.
+ The JSON object must at least have the root node in common with the current visualized graph.
+
+ Parameters:
+
+ json - (object) A json tree or graph structure. See also <Loader.loadJSON>.
+ opt - (object) Animation options. It's an object with optional properties described below
+ type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:con".
+ duration - Described in <Options.Fx>.
+ fps - Described in <Options.Fx>.
+ transition - Described in <Options.Fx>.
+ hideLabels - (boolean) Default's *true*. Hide labels during the animation.
+ id - (string) The shared <Graph.Node> id between both graphs.
+
+ extraModes - (optional|object) When morphing with an animation, dollar prefixed data parameters are added to
+ *endData* and not *data* itself. This way you can animate dollar prefixed parameters during your morphing operation.
+ For animating these extra-parameters you have to specify an object that has animation groups as keys and animation
+ properties as values, just like specified in <Graph.Plot.animate>.
+
+ Example:
+ (start code js)
+ //...json contains a tree or graph structure...
+
+ var viz = new $jit.Viz(options);
+ viz.op.morph(json, {
+ type: 'fade',
+ duration: 1000,
+ hideLabels: false,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ //or also
+ viz.op.morph(json, {
+ type: 'fade',
+ duration: 1500
+ });
+ //if the json data contains dollar prefixed params
+ //like $width or $height these too can be animated
+ viz.op.morph(json, {
+ type: 'fade',
+ duration: 1500
+ }, {
+ 'node-property': ['width', 'height']
+ });
+ (end code)
+
+ */
+ morph: function(json, opt, extraModes) {
+ extraModes = extraModes || {};
+ var viz = this.viz;
+ var options = $.merge(this.options, viz.controller, opt), root = viz.root;
+ var graph;
+ //TODO(nico) this hack makes morphing work with the Hypertree.
+ //Need to check if it has been solved and this can be removed.
+ viz.root = opt.id || viz.root;
+ switch(options.type) {
+ case 'nothing':
+ graph = viz.construct(json);
+ graph.eachNode(function(elem) {
+ var nodeExists = viz.graph.hasNode(elem.id);
+ elem.eachAdjacency(function(adj) {
+ var adjExists = !!viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
+ //Update data properties if the node existed
+ if(adjExists) {
+ var addedAdj = viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ for(var prop in (adj.data || {})) {
+ addedAdj.data[prop] = adj.data[prop];
+ }
+ }
+ });
+ //Update data properties if the node existed
+ if(nodeExists) {
+ var addedNode = viz.graph.getNode(elem.id);
+ for(var prop in (elem.data || {})) {
+ addedNode.data[prop] = elem.data[prop];
+ }
+ }
+ });
+ viz.graph.eachNode(function(elem) {
+ elem.eachAdjacency(function(adj) {
+ if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
+ viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ }
+ });
+ if(!graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);
+ });
+
+ break;
+
+ case 'replot':
+ viz.labels.clearLabels(true);
+ this.morph(json, { type: 'nothing' });
+ viz.refresh(true);
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade': case 'fade:con':
+ that = this;
+ graph = viz.construct(json);
+ //preprocessing for nodes to delete.
+ //get node property modes to interpolate
+ var nodeModes = ('node-property' in extraModes)
+ && $.map($.splat(extraModes['node-property']),
+ function(n) { return '$' + n; });
+ viz.graph.eachNode(function(elem) {
+ var graphNode = graph.getNode(elem.id);
+ if(!graphNode) {
+ elem.setData('alpha', 1);
+ elem.setData('alpha', 1, 'start');
+ elem.setData('alpha', 0, 'end');
+ elem.ignore = true;
+ } else {
+ //Update node data information
+ var graphNodeData = graphNode.data;
+ for(var prop in graphNodeData) {
+ if(nodeModes && ($.indexOf(nodeModes, prop) > -1)) {
+ elem.endData[prop] = graphNodeData[prop];
+ } else {
+ elem.data[prop] = graphNodeData[prop];
+ }
+ }
+ }
+ });
+ viz.graph.eachNode(function(elem) {
+ if(elem.ignore) return;
+ elem.eachAdjacency(function(adj) {
+ if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;
+ var nodeFrom = graph.getNode(adj.nodeFrom.id);
+ var nodeTo = graph.getNode(adj.nodeTo.id);
+ if(!nodeFrom.adjacentTo(nodeTo)) {
+ var adj = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
+ fadeEdges = true;
+ adj.setData('alpha', 1);
+ adj.setData('alpha', 1, 'start');
+ adj.setData('alpha', 0, 'end');
+ }
+ });
+ });
+ //preprocessing for adding nodes.
+ var fadeEdges = this.preprocessSum(graph);
+
+ var modes = !fadeEdges? ['node-property:alpha'] :
+ ['node-property:alpha',
+ 'edge-property:alpha'];
+ //Append extra node-property animations (if any)
+ modes[0] = modes[0] + (('node-property' in extraModes)?
+ (':' + $.splat(extraModes['node-property']).join(':')) : '');
+ //Append extra edge-property animations (if any)
+ modes[1] = (modes[1] || 'edge-property:alpha') + (('edge-property' in extraModes)?
+ (':' + $.splat(extraModes['edge-property']).join(':')) : '');
+ //Add label-property animations (if any)
+ if('label-property' in extraModes) {
+ modes.push('label-property:' + $.splat(extraModes['label-property']).join(':'))
+ }
+ //only use reposition if its implemented.
+ if (viz.reposition) {
+ viz.reposition();
+ } else {
+ viz.compute('end');
+ }
+ viz.graph.eachNode(function(elem) {
+ if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {
+ elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);
+ }
+ });
+ viz.fx.animate($.merge(options, {
+ modes: [extraModes.position || 'polar'].concat(modes),
+ onComplete: function() {
+ viz.graph.eachNode(function(elem) {
+ if(elem.ignore) viz.graph.removeNode(elem.id);
+ });
+ viz.graph.eachNode(function(elem) {
+ elem.eachAdjacency(function(adj) {
+ if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ });
+ });
+ options.onComplete();
+ }
+ }));
+ break;
+
+default:
+ }
+ },
+
+
+ /*
+ Method: contract
+
+ Collapses the subtree of the given node. The node will have a _collapsed=true_ property.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ opt - (object) An object containing options described below
+ type - (string) Whether to 'replot' or 'animate' the contraction.
+
+ There are also a number of Animation options. For more information see <Options.Fx>.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.op.contract(node, {
+ type: 'animate',
+ duration: 1000,
+ hideLabels: true,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ (end code)
+
+ */
+ contract: function(node, opt) {
+ var viz = this.viz;
+ if(node.collapsed || !node.anySubnode($.lambda(true))) return;
+ opt = $.merge(this.options, viz.config, opt || {}, {
+ 'modes': ['node-property:alpha:span', 'linear']
+ });
+ node.collapsed = true;
+ (function subn(n) {
+ n.eachSubnode(function(ch) {
+ ch.ignore = true;
+ ch.setData('alpha', 0, opt.type == 'animate'? 'end' : 'current');
+ subn(ch);
+ });
+ })(node);
+ if(opt.type == 'animate') {
+ viz.compute('end');
+ if(viz.rotated) {
+ viz.rotate(viz.rotated, 'none', {
+ 'property':'end'
+ });
+ }
+ (function subn(n) {
+ n.eachSubnode(function(ch) {
+ ch.setPos(node.getPos('end'), 'end');
+ subn(ch);
+ });
+ })(node);
+ viz.fx.animate(opt);
+ } else if(opt.type == 'replot'){
+ viz.refresh();
+ }
+ },
+
+ /*
+ Method: expand
+
+ Expands the previously contracted subtree. The given node must have the _collapsed=true_ property.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ opt - (object) An object containing options described below
+ type - (string) Whether to 'replot' or 'animate'.
+
+ There are also a number of Animation options. For more information see <Options.Fx>.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.op.expand(node, {
+ type: 'animate',
+ duration: 1000,
+ hideLabels: true,
+ transition: $jit.Trans.Quart.easeOut
+ });
+ (end code)
+
+ */
+ expand: function(node, opt) {
+ if(!('collapsed' in node)) return;
+ var viz = this.viz;
+ opt = $.merge(this.options, viz.config, opt || {}, {
+ 'modes': ['node-property:alpha:span', 'linear']
+ });
+ delete node.collapsed;
+ (function subn(n) {
+ n.eachSubnode(function(ch) {
+ delete ch.ignore;
+ ch.setData('alpha', 1, opt.type == 'animate'? 'end' : 'current');
+ subn(ch);
+ });
+ })(node);
+ if(opt.type == 'animate') {
+ viz.compute('end');
+ if(viz.rotated) {
+ viz.rotate(viz.rotated, 'none', {
+ 'property':'end'
+ });
+ }
+ viz.fx.animate(opt);
+ } else if(opt.type == 'replot'){
+ viz.refresh();
+ }
+ },
+
+ preprocessSum: function(graph) {
+ var viz = this.viz;
+ graph.eachNode(function(elem) {
+ if(!viz.graph.hasNode(elem.id)) {
+ viz.graph.addNode(elem);
+ var n = viz.graph.getNode(elem.id);
+ n.setData('alpha', 0);
+ n.setData('alpha', 0, 'start');
+ n.setData('alpha', 1, 'end');
+ }
+ });
+ var fadeEdges = false;
+ graph.eachNode(function(elem) {
+ elem.eachAdjacency(function(adj) {
+ var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
+ var nodeTo = viz.graph.getNode(adj.nodeTo.id);
+ if(!nodeFrom.adjacentTo(nodeTo)) {
+ var adj = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
+ if(nodeFrom.startAlpha == nodeFrom.endAlpha
+ && nodeTo.startAlpha == nodeTo.endAlpha) {
+ fadeEdges = true;
+ adj.setData('alpha', 0);
+ adj.setData('alpha', 0, 'start');
+ adj.setData('alpha', 1, 'end');
+ }
+ }
+ });
+ });
+ return fadeEdges;
+ }
+};
+
+
+
+/*
+ File: Helpers.js
+
+ Helpers are objects that contain rendering primitives (like rectangles, ellipses, etc), for plotting nodes and edges.
+ Helpers also contain implementations of the *contains* method, a method returning a boolean indicating whether the mouse
+ position is over the rendered shape.
+
+ Helpers are very useful when implementing new NodeTypes, since you can access them through *this.nodeHelper* and
+ *this.edgeHelper* <Graph.Plot> properties, providing you with simple primitives and mouse-position check functions.
+
+ Example:
+ (start code js)
+ //implement a new node type
+ $jit.Viz.Plot.NodeTypes.implement({
+ 'customNodeType': {
+ 'render': function(node, canvas) {
+ this.nodeHelper.circle.render ...
+ },
+ 'contains': function(node, pos) {
+ this.nodeHelper.circle.contains ...
+ }
+ }
+ });
+ //implement an edge type
+ $jit.Viz.Plot.EdgeTypes.implement({
+ 'customNodeType': {
+ 'render': function(node, canvas) {
+ this.edgeHelper.circle.render ...
+ },
+ //optional
+ 'contains': function(node, pos) {
+ this.edgeHelper.circle.contains ...
+ }
+ }
+ });
+ (end code)
+
+*/
+
+/*
+ Object: NodeHelper
+
+ Contains rendering and other type of primitives for simple shapes.
+ */
+var NodeHelper = {
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false)
+ },
+ /*
+ Object: NodeHelper.circle
+ */
+ 'circle': {
+ /*
+ Method: render
+
+ Renders a circle into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the circle.
+ radius - (number) The radius of the circle to be rendered.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.circle.render('fill', { x: 10, y: 30 }, 30, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, radius, canvas){
+ var ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2, true);
+ ctx.closePath();
+ ctx[type]();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ radius - (number) The radius of the rendered circle.
+
+ Example:
+ (start code js)
+ NodeHelper.circle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); //true
+ (end code)
+ */
+ 'contains': function(npos, pos, radius){
+ var diffx = npos.x - pos.x,
+ diffy = npos.y - pos.y,
+ diff = diffx * diffx + diffy * diffy;
+ return diff <= radius * radius;
+ }
+ },
+ /*
+ Object: NodeHelper.ellipse
+ */
+ 'ellipse': {
+ /*
+ Method: render
+
+ Renders an ellipse into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the ellipse.
+ width - (number) The width of the ellipse.
+ height - (number) The height of the ellipse.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.ellipse.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, width, height, canvas){
+ var ctx = canvas.getCtx(),
+ scalex = 1,
+ scaley = 1,
+ scaleposx = 1,
+ scaleposy = 1,
+ radius = 0;
+
+ if (width > height) {
+ radius = width / 2;
+ scaley = height / width;
+ scaleposy = width / height;
+ } else {
+ radius = height / 2;
+ scalex = width / height;
+ scaleposx = height / width;
+ }
+
+ ctx.save();
+ ctx.scale(scalex, scaley);
+ ctx.beginPath();
+ ctx.arc(pos.x * scaleposx, pos.y * scaleposy, radius, 0, Math.PI * 2, true);
+ ctx.closePath();
+ ctx[type]();
+ ctx.restore();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ width - (number) The width of the rendered ellipse.
+ height - (number) The height of the rendered ellipse.
+
+ Example:
+ (start code js)
+ NodeHelper.ellipse.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40);
+ (end code)
+ */
+ 'contains': function(npos, pos, width, height){
+ var radius = 0,
+ scalex = 1,
+ scaley = 1,
+ diffx = 0,
+ diffy = 0,
+ diff = 0;
+
+ if (width > height) {
+ radius = width / 2;
+ scaley = height / width;
+ } else {
+ radius = height / 2;
+ scalex = width / height;
+ }
+
+ diffx = (npos.x - pos.x) * (1 / scalex);
+ diffy = (npos.y - pos.y) * (1 / scaley);
+ diff = diffx * diffx + diffy * diffy;
+ return diff <= radius * radius;
+ }
+ },
+ /*
+ Object: NodeHelper.square
+ */
+ 'square': {
+ /*
+ Method: render
+
+ Renders a square into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the square.
+ dim - (number) The radius (or half-diameter) of the square.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.square.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, dim, canvas){
+ canvas.getCtx()[type + "Rect"](pos.x - dim, pos.y - dim, 2*dim, 2*dim);
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ dim - (number) The radius (or half-diameter) of the square.
+
+ Example:
+ (start code js)
+ NodeHelper.square.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': function(npos, pos, dim){
+ return Math.abs(pos.x - npos.x) <= dim && Math.abs(pos.y - npos.y) <= dim;
+ }
+ },
+ /*
+ Object: NodeHelper.rectangle
+ */
+ 'rectangle': {
+ /*
+ Method: render
+
+ Renders a rectangle into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the rectangle.
+ width - (number) The width of the rectangle.
+ height - (number) The height of the rectangle.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.rectangle.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, width, height, canvas){
+ canvas.getCtx()[type + "Rect"](pos.x - width / 2, pos.y - height / 2,
+ width, height);
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ width - (number) The width of the rendered rectangle.
+ height - (number) The height of the rendered rectangle.
+
+ Example:
+ (start code js)
+ NodeHelper.rectangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40);
+ (end code)
+ */
+ 'contains': function(npos, pos, width, height){
+ return Math.abs(pos.x - npos.x) <= width / 2
+ && Math.abs(pos.y - npos.y) <= height / 2;
+ }
+ },
+ /*
+ Object: NodeHelper.triangle
+ */
+ 'triangle': {
+ /*
+ Method: render
+
+ Renders a triangle into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the triangle.
+ dim - (number) Half the base and half the height of the triangle.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.triangle.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, dim, canvas){
+ var ctx = canvas.getCtx(),
+ c1x = pos.x,
+ c1y = pos.y - dim,
+ c2x = c1x - dim,
+ c2y = pos.y + dim,
+ c3x = c1x + dim,
+ c3y = c2y;
+ ctx.beginPath();
+ ctx.moveTo(c1x, c1y);
+ ctx.lineTo(c2x, c2y);
+ ctx.lineTo(c3x, c3y);
+ ctx.closePath();
+ ctx[type]();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ dim - (number) Half the base and half the height of the triangle.
+
+ Example:
+ (start code js)
+ NodeHelper.triangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': function(npos, pos, dim) {
+ return NodeHelper.circle.contains(npos, pos, dim);
+ }
+ },
+ /*
+ Object: NodeHelper.star
+ */
+ 'star': {
+ /*
+ Method: render
+
+ Renders a star (concave decagon) into the canvas.
+
+ Parameters:
+
+ type - (string) Possible options are 'fill' or 'stroke'.
+ pos - (object) An *x*, *y* object with the position of the center of the star.
+ dim - (number) The length of a side of a concave decagon.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ NodeHelper.star.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);
+ (end code)
+ */
+ 'render': function(type, pos, dim, canvas){
+ var ctx = canvas.getCtx(),
+ pi5 = Math.PI / 5;
+ ctx.save();
+ ctx.translate(pos.x, pos.y);
+ ctx.beginPath();
+ ctx.moveTo(dim, 0);
+ for (var i = 0; i < 9; i++) {
+ ctx.rotate(pi5);
+ if (i % 2 == 0) {
+ ctx.lineTo((dim / 0.525731) * 0.200811, 0);
+ } else {
+ ctx.lineTo(dim, 0);
+ }
+ }
+ ctx.closePath();
+ ctx[type]();
+ ctx.restore();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ npos - (object) An *x*, *y* object with the <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ dim - (number) The length of a side of a concave decagon.
+
+ Example:
+ (start code js)
+ NodeHelper.star.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': function(npos, pos, dim) {
+ return NodeHelper.circle.contains(npos, pos, dim);
+ }
+ }
+};
+
+/*
+ Object: EdgeHelper
+
+ Contains rendering primitives for simple edge shapes.
+*/
+var EdgeHelper = {
+ /*
+ Object: EdgeHelper.line
+ */
+ 'line': {
+ /*
+ Method: render
+
+ Renders a line into the canvas.
+
+ Parameters:
+
+ from - (object) An *x*, *y* object with the starting position of the line.
+ to - (object) An *x*, *y* object with the ending position of the line.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ EdgeHelper.line.render({ x: 10, y: 30 }, { x: 10, y: 50 }, viz.canvas);
+ (end code)
+ */
+ 'render': function(from, to, canvas){
+ var ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.moveTo(from.x, from.y);
+ ctx.lineTo(to.x, to.y);
+ ctx.stroke();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ posFrom - (object) An *x*, *y* object with a <Graph.Node> position.
+ posTo - (object) An *x*, *y* object with a <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ epsilon - (number) The dimension of the shape.
+
+ Example:
+ (start code js)
+ EdgeHelper.line.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': function(posFrom, posTo, pos, epsilon) {
+ var min = Math.min,
+ max = Math.max,
+ minPosX = min(posFrom.x, posTo.x),
+ maxPosX = max(posFrom.x, posTo.x),
+ minPosY = min(posFrom.y, posTo.y),
+ maxPosY = max(posFrom.y, posTo.y);
+
+ if(pos.x >= minPosX && pos.x <= maxPosX
+ && pos.y >= minPosY && pos.y <= maxPosY) {
+ if(Math.abs(posTo.x - posFrom.x) <= epsilon) {
+ return true;
+ }
+ var dist = (posTo.y - posFrom.y) / (posTo.x - posFrom.x) * (pos.x - posFrom.x) + posFrom.y;
+ return Math.abs(dist - pos.y) <= epsilon;
+ }
+ return false;
+ }
+ },
+ /*
+ Object: EdgeHelper.arrow
+ */
+ 'arrow': {
+ /*
+ Method: render
+
+ Renders an arrow into the canvas.
+
+ Parameters:
+
+ from - (object) An *x*, *y* object with the starting position of the arrow.
+ to - (object) An *x*, *y* object with the ending position of the arrow.
+ dim - (number) The dimension of the arrow.
+ swap - (boolean) Whether to set the arrow pointing to the starting position or the ending position.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ EdgeHelper.arrow.render({ x: 10, y: 30 }, { x: 10, y: 50 }, 13, false, viz.canvas);
+ (end code)
+ */
+ 'render': function(from, to, dim, swap, canvas){
+ var ctx = canvas.getCtx();
+ // invert edge direction
+ if (swap) {
+ var tmp = from;
+ from = to;
+ to = tmp;
+ }
+ var vect = new Complex(to.x - from.x, to.y - from.y);
+ vect.$scale(dim / vect.norm());
+ var intermediatePoint = new Complex(to.x - vect.x, to.y - vect.y),
+ normal = new Complex(-vect.y / 2, vect.x / 2),
+ v1 = intermediatePoint.add(normal),
+ v2 = intermediatePoint.$add(normal.$scale(-1));
+
+ ctx.beginPath();
+ ctx.moveTo(from.x, from.y);
+ ctx.lineTo(to.x, to.y);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(v1.x, v1.y);
+ ctx.lineTo(v2.x, v2.y);
+ ctx.lineTo(to.x, to.y);
+ ctx.closePath();
+ ctx.fill();
+ },
+ /*
+ Method: contains
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ posFrom - (object) An *x*, *y* object with a <Graph.Node> position.
+ posTo - (object) An *x*, *y* object with a <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ epsilon - (number) The dimension of the shape.
+
+ Example:
+ (start code js)
+ EdgeHelper.arrow.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': function(posFrom, posTo, pos, epsilon) {
+ return EdgeHelper.line.contains(posFrom, posTo, pos, epsilon);
+ }
+ },
+ /*
+ Object: EdgeHelper.hyperline
+ */
+ 'hyperline': {
+ /*
+ Method: render
+
+ Renders a hyperline into the canvas. A hyperline are the lines drawn for the <Hypertree> visualization.
+
+ Parameters:
+
+ from - (object) An *x*, *y* object with the starting position of the hyperline. *x* and *y* must belong to [0, 1).
+ to - (object) An *x*, *y* object with the ending position of the hyperline. *x* and *y* must belong to [0, 1).
+ r - (number) The scaling factor.
+ canvas - (object) A <Canvas> instance.
+
+ Example:
+ (start code js)
+ EdgeHelper.hyperline.render({ x: 10, y: 30 }, { x: 10, y: 50 }, 100, viz.canvas);
+ (end code)
+ */
+ 'render': function(from, to, r, canvas){
+ var ctx = canvas.getCtx();
+ var centerOfCircle = computeArcThroughTwoPoints(from, to);
+ if (centerOfCircle.a > 1000 || centerOfCircle.b > 1000
+ || centerOfCircle.ratio < 0) {
+ ctx.beginPath();
+ ctx.moveTo(from.x * r, from.y * r);
+ ctx.lineTo(to.x * r, to.y * r);
+ ctx.stroke();
+ } else {
+ var angleBegin = Math.atan2(to.y - centerOfCircle.y, to.x
+ - centerOfCircle.x);
+ var angleEnd = Math.atan2(from.y - centerOfCircle.y, from.x
+ - centerOfCircle.x);
+ var sense = sense(angleBegin, angleEnd);
+ ctx.beginPath();
+ ctx.arc(centerOfCircle.x * r, centerOfCircle.y * r, centerOfCircle.ratio
+ * r, angleBegin, angleEnd, sense);
+ ctx.stroke();
+ }
+ /*
+ Calculates the arc parameters through two points.
+
+ More information in <http://en.wikipedia.org/wiki/Poincar%C3%A9_disc_model#Analytic_geometry_constructions_in_the_hyperbolic_plane>
+
+ Parameters:
+
+ p1 - A <Complex> instance.
+ p2 - A <Complex> instance.
+ scale - The Disk's diameter.
+
+ Returns:
+
+ An object containing some arc properties.
+ */
+ function computeArcThroughTwoPoints(p1, p2){
+ var aDen = (p1.x * p2.y - p1.y * p2.x), bDen = aDen;
+ var sq1 = p1.squaredNorm(), sq2 = p2.squaredNorm();
+ // Fall back to a straight line
+ if (aDen == 0)
+ return {
+ x: 0,
+ y: 0,
+ ratio: -1
+ };
+
+ var a = (p1.y * sq2 - p2.y * sq1 + p1.y - p2.y) / aDen;
+ var b = (p2.x * sq1 - p1.x * sq2 + p2.x - p1.x) / bDen;
+ var x = -a / 2;
+ var y = -b / 2;
+ var squaredRatio = (a * a + b * b) / 4 - 1;
+ // Fall back to a straight line
+ if (squaredRatio < 0)
+ return {
+ x: 0,
+ y: 0,
+ ratio: -1
+ };
+ var ratio = Math.sqrt(squaredRatio);
+ var out = {
+ x: x,
+ y: y,
+ ratio: ratio > 1000? -1 : ratio,
+ a: a,
+ b: b
+ };
+
+ return out;
+ }
+ /*
+ Sets angle direction to clockwise (true) or counterclockwise (false).
+
+ Parameters:
+
+ angleBegin - Starting angle for drawing the arc.
+ angleEnd - The HyperLine will be drawn from angleBegin to angleEnd.
+
+ Returns:
+
+ A Boolean instance describing the sense for drawing the HyperLine.
+ */
+ function sense(angleBegin, angleEnd){
+ return (angleBegin < angleEnd)? ((angleBegin + Math.PI > angleEnd)? false
+ : true) : ((angleEnd + Math.PI > angleBegin)? true : false);
+ }
+ },
+ /*
+ Method: contains
+
+ Not Implemented
+
+ Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
+
+ Parameters:
+
+ posFrom - (object) An *x*, *y* object with a <Graph.Node> position.
+ posTo - (object) An *x*, *y* object with a <Graph.Node> position.
+ pos - (object) An *x*, *y* object with the position to check.
+ epsilon - (number) The dimension of the shape.
+
+ Example:
+ (start code js)
+ EdgeHelper.hyperline.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30);
+ (end code)
+ */
+ 'contains': $.lambda(false)
+ }
+};
+
+
+/*
+ * File: Graph.Plot.js
+ */
+
+/*
+ Object: Graph.Plot
+
+ <Graph> rendering and animation methods.
+
+ Properties:
+
+ nodeHelper - <NodeHelper> object.
+ edgeHelper - <EdgeHelper> object.
+*/
+Graph.Plot = {
+ //Default initializer
+ initialize: function(viz, klass){
+ this.viz = viz;
+ this.config = viz.config;
+ this.node = viz.config.Node;
+ this.edge = viz.config.Edge;
+ this.animation = new Animation;
+ this.nodeTypes = new klass.Plot.NodeTypes;
+ this.edgeTypes = new klass.Plot.EdgeTypes;
+ this.labels = viz.labels;
+ },
+
+ //Add helpers
+ nodeHelper: NodeHelper,
+ edgeHelper: EdgeHelper,
+
+ Interpolator: {
+ //node/edge property parsers
+ 'map': {
+ 'border': 'color',
+ 'color': 'color',
+ 'width': 'number',
+ 'height': 'number',
+ 'dim': 'number',
+ 'alpha': 'number',
+ 'lineWidth': 'number',
+ 'angularWidth':'number',
+ 'span':'number',
+ 'valueArray':'array-number',
+ 'dimArray':'array-number'
+ //'colorArray':'array-color'
+ },
+
+ //canvas specific parsers
+ 'canvas': {
+ 'globalAlpha': 'number',
+ 'fillStyle': 'color',
+ 'strokeStyle': 'color',
+ 'lineWidth': 'number',
+ 'shadowBlur': 'number',
+ 'shadowColor': 'color',
+ 'shadowOffsetX': 'number',
+ 'shadowOffsetY': 'number',
+ 'miterLimit': 'number'
+ },
+
+ //label parsers
+ 'label': {
+ 'size': 'number',
+ 'color': 'color'
+ },
+
+ //Number interpolator
+ 'compute': function(from, to, delta) {
+ return from + (to - from) * delta;
+ },
+
+ //Position interpolators
+ 'moebius': function(elem, props, delta, vector) {
+ var v = vector.scale(-delta);
+ if(v.norm() < 1) {
+ var x = v.x, y = v.y;
+ var ans = elem.startPos
+ .getc().moebiusTransformation(v);
+ elem.pos.setc(ans.x, ans.y);
+ v.x = x; v.y = y;
+ }
+ },
+
+ 'linear': function(elem, props, delta) {
+ var from = elem.startPos.getc(true);
+ var to = elem.endPos.getc(true);
+ elem.pos.setc(this.compute(from.x, to.x, delta),
+ this.compute(from.y, to.y, delta));
+ },
+
+ 'polar': function(elem, props, delta) {
+ var from = elem.startPos.getp(true);
+ var to = elem.endPos.getp();
+ var ans = to.interpolate(from, delta);
+ elem.pos.setp(ans.theta, ans.rho);
+ },
+
+ //Graph's Node/Edge interpolators
+ 'number': function(elem, prop, delta, getter, setter) {
+ var from = elem[getter](prop, 'start');
+ var to = elem[getter](prop, 'end');
+ elem[setter](prop, this.compute(from, to, delta));
+ },
+
+ 'color': function(elem, prop, delta, getter, setter) {
+ var from = $.hexToRgb(elem[getter](prop, 'start'));
+ var to = $.hexToRgb(elem[getter](prop, 'end'));
+ var comp = this.compute;
+ var val = $.rgbToHex([parseInt(comp(from[0], to[0], delta)),
+ parseInt(comp(from[1], to[1], delta)),
+ parseInt(comp(from[2], to[2], delta))]);
+
+ elem[setter](prop, val);
+ },
+
+ 'array-number': function(elem, prop, delta, getter, setter) {
+ var from = elem[getter](prop, 'start'),
+ to = elem[getter](prop, 'end'),
+ cur = [];
+ for(var i=0, l=from.length; i<l; i++) {
+ var fromi = from[i], toi = to[i];
+ if(fromi.length) {
+ for(var j=0, len=fromi.length, curi=[]; j<len; j++) {
+ curi.push(this.compute(fromi[j], toi[j], delta));
+ }
+ cur.push(curi);
+ } else {
+ cur.push(this.compute(fromi, toi, delta));
+ }
+ }
+ elem[setter](prop, cur);
+ },
+
+ 'node': function(elem, props, delta, map, getter, setter) {
+ map = this[map];
+ if(props) {
+ var len = props.length;
+ for(var i=0; i<len; i++) {
+ var pi = props[i];
+ this[map[pi]](elem, pi, delta, getter, setter);
+ }
+ } else {
+ for(var pi in map) {
+ this[map[pi]](elem, pi, delta, getter, setter);
+ }
+ }
+ },
+
+ 'edge': function(elem, props, delta, mapKey, getter, setter) {
+ var adjs = elem.adjacencies;
+ for(var id in adjs) this['node'](adjs[id], props, delta, mapKey, getter, setter);
+ },
+
+ 'node-property': function(elem, props, delta) {
+ this['node'](elem, props, delta, 'map', 'getData', 'setData');
+ },
+
+ 'edge-property': function(elem, props, delta) {
+ this['edge'](elem, props, delta, 'map', 'getData', 'setData');
+ },
+
+ 'label-property': function(elem, props, delta) {
+ this['node'](elem, props, delta, 'label', 'getLabelData', 'setLabelData');
+ },
+
+ 'node-style': function(elem, props, delta) {
+ this['node'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');
+ },
+
+ 'edge-style': function(elem, props, delta) {
+ this['edge'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');
+ }
+ },
+
+
+ /*
+ sequence
+
+ Iteratively performs an action while refreshing the state of the visualization.
+
+ Parameters:
+
+ options - (object) An object containing some sequence options described below
+ condition - (function) A function returning a boolean instance in order to stop iterations.
+ step - (function) A function to execute on each step of the iteration.
+ onComplete - (function) A function to execute when the sequence finishes.
+ duration - (number) Duration (in milliseconds) of each step.
+
+ Example:
+ (start code js)
+ var rg = new $jit.RGraph(options);
+ var i = 0;
+ rg.fx.sequence({
+ condition: function() {
+ return i == 10;
+ },
+ step: function() {
+ alert(i++);
+ },
+ onComplete: function() {
+ alert('done!');
+ }
+ });
+ (end code)
+
+ */
+ sequence: function(options) {
+ var that = this;
+ options = $.merge({
+ condition: $.lambda(false),
+ step: $.empty,
+ onComplete: $.empty,
+ duration: 200
+ }, options || {});
+
+ var interval = setInterval(function() {
+ if(options.condition()) {
+ options.step();
+ } else {
+ clearInterval(interval);
+ options.onComplete();
+ }
+ that.viz.refresh(true);
+ }, options.duration);
+ },
+
+ /*
+ prepare
+
+ Prepare graph position and other attribute values before performing an Animation.
+ This method is used internally by the Toolkit.
+
+ See also:
+
+ <Animation>, <Graph.Plot.animate>
+
+ */
+ prepare: function(modes) {
+ var graph = this.viz.graph,
+ accessors = {
+ 'node-property': {
+ 'getter': 'getData',
+ 'setter': 'setData'
+ },
+ 'edge-property': {
+ 'getter': 'getData',
+ 'setter': 'setData'
+ },
+ 'node-style': {
+ 'getter': 'getCanvasStyle',
+ 'setter': 'setCanvasStyle'
+ },
+ 'edge-style': {
+ 'getter': 'getCanvasStyle',
+ 'setter': 'setCanvasStyle'
+ }
+ };
+
+ //parse modes
+ var m = {};
+ if($.type(modes) == 'array') {
+ for(var i=0, len=modes.length; i < len; i++) {
+ var elems = modes[i].split(':');
+ m[elems.shift()] = elems;
+ }
+ } else {
+ for(var p in modes) {
+ if(p == 'position') {
+ m[modes.position] = [];
+ } else {
+ m[p] = $.splat(modes[p]);
+ }
+ }
+ }
+
+ graph.eachNode(function(node) {
+ node.startPos.set(node.pos);
+ $.each(['node-property', 'node-style'], function(p) {
+ if(p in m) {
+ var prop = m[p];
+ for(var i=0, l=prop.length; i < l; i++) {
+ node[accessors[p].setter](prop[i], node[accessors[p].getter](prop[i]), 'start');
+ }
+ }
+ });
+ $.each(['edge-property', 'edge-style'], function(p) {
+ if(p in m) {
+ var prop = m[p];
+ node.eachAdjacency(function(adj) {
+ for(var i=0, l=prop.length; i < l; i++) {
+ adj[accessors[p].setter](prop[i], adj[accessors[p].getter](prop[i]), 'start');
+ }
+ });
+ }
+ });
+ });
+ return m;
+ },
+
+ /*
+ Method: animate
+
+ Animates a <Graph> by interpolating some <Graph.Node>, <Graph.Adjacence> or <Graph.Label> properties.
+
+ Parameters:
+
+ opt - (object) Animation options. The object properties are described below
+ duration - (optional) Described in <Options.Fx>.
+ fps - (optional) Described in <Options.Fx>.
+ hideLabels - (optional|boolean) Whether to hide labels during the animation.
+ modes - (required|object) An object with animation modes (described below).
+
+ Animation modes:
+
+ Animation modes are strings representing different node/edge and graph properties that you'd like to animate.
+ They are represented by an object that has as keys main categories of properties to animate and as values a list
+ of these specific properties. The properties are described below
+
+ position - Describes the way nodes' positions must be interpolated. Possible values are 'linear', 'polar' or 'moebius'.
+ node-property - Describes which Node properties will be interpolated. These properties can be any of the ones defined in <Options.Node>.
+ edge-property - Describes which Edge properties will be interpolated. These properties can be any the ones defined in <Options.Edge>.
+ label-property - Describes which Label properties will be interpolated. These properties can be any of the ones defined in <Options.Label> like color or size.
+ node-style - Describes which Node Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.
+ edge-style - Describes which Edge Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ //...tweak some Data, CanvasStyles or LabelData properties...
+ viz.fx.animate({
+ modes: {
+ 'position': 'linear',
+ 'node-property': ['width', 'height'],
+ 'node-style': 'shadowColor',
+ 'label-property': 'size'
+ },
+ hideLabels: false
+ });
+ //...can also be written like this...
+ viz.fx.animate({
+ modes: ['linear',
+ 'node-property:width:height',
+ 'node-style:shadowColor',
+ 'label-property:size'],
+ hideLabels: false
+ });
+ (end code)
+ */
+ animate: function(opt, versor) {
+ opt = $.merge(this.viz.config, opt || {});
+ var that = this,
+ viz = this.viz,
+ graph = viz.graph,
+ interp = this.Interpolator,
+ animation = opt.type === 'nodefx'? this.nodeFxAnimation : this.animation;
+ //prepare graph values
+ var m = this.prepare(opt.modes);
+
+ //animate
+ if(opt.hideLabels) this.labels.hideLabels(true);
+ animation.setOptions($.extend(opt, {
+ $animating: false,
+ compute: function(delta) {
+ graph.eachNode(function(node) {
+ for(var p in m) {
+ interp[p](node, m[p], delta, versor);
+ }
+ });
+ that.plot(opt, this.$animating, delta);
+ this.$animating = true;
+ },
+ complete: function() {
+ if(opt.hideLabels) that.labels.hideLabels(false);
+ that.plot(opt);
+ opt.onComplete();
+ //TODO(nico): This shouldn't be here!
+ //opt.onAfterCompute();
+ }
+ })).start();
+ },
+
+ /*
+ nodeFx
+
+ Apply animation to node properties like color, width, height, dim, etc.
+
+ Parameters:
+
+ options - Animation options. This object properties is described below
+ elements - The Elements to be transformed. This is an object that has a properties
+
+ (start code js)
+ 'elements': {
+ //can also be an array of ids
+ 'id': 'id-of-node-to-transform',
+ //properties to be modified. All properties are optional.
+ 'properties': {
+ 'color': '#ccc', //some color
+ 'width': 10, //some width
+ 'height': 10, //some height
+ 'dim': 20, //some dim
+ 'lineWidth': 10 //some line width
+ }
+ }
+ (end code)
+
+ - _reposition_ Whether to recalculate positions and add a motion animation.
+ This might be used when changing _width_ or _height_ properties in a <Layouts.Tree> like layout. Default's *false*.
+
+ - _onComplete_ A method that is called when the animation completes.
+
+ ...and all other <Graph.Plot.animate> options like _duration_, _fps_, _transition_, etc.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ rg.fx.nodeFx({
+ 'elements': {
+ 'id':'mynodeid',
+ 'properties': {
+ 'color':'#ccf'
+ },
+ 'transition': Trans.Quart.easeOut
+ }
+ });
+ (end code)
+ */
+ nodeFx: function(opt) {
+ var viz = this.viz,
+ graph = viz.graph,
+ animation = this.nodeFxAnimation,
+ options = $.merge(this.viz.config, {
+ 'elements': {
+ 'id': false,
+ 'properties': {}
+ },
+ 'reposition': false
+ });
+ opt = $.merge(options, opt || {}, {
+ onBeforeCompute: $.empty,
+ onAfterCompute: $.empty
+ });
+ //check if an animation is running
+ animation.stopTimer();
+ var props = opt.elements.properties;
+ //set end values for nodes
+ if(!opt.elements.id) {
+ graph.eachNode(function(n) {
+ for(var prop in props) {
+ n.setData(prop, props[prop], 'end');
+ }
+ });
+ } else {
+ var ids = $.splat(opt.elements.id);
+ $.each(ids, function(id) {
+ var n = graph.getNode(id);
+ if(n) {
+ for(var prop in props) {
+ n.setData(prop, props[prop], 'end');
+ }
+ }
+ });
+ }
+ //get keys
+ var propnames = [];
+ for(var prop in props) propnames.push(prop);
+ //add node properties modes
+ var modes = ['node-property:' + propnames.join(':')];
+ //set new node positions
+ if(opt.reposition) {
+ modes.push('linear');
+ viz.compute('end');
+ }
+ //animate
+ this.animate($.merge(opt, {
+ modes: modes,
+ type: 'nodefx'
+ }));
+ },
+
+
+ /*
+ Method: plot
+
+ Plots a <Graph>.
+
+ Parameters:
+
+ opt - (optional) Plotting options. Most of them are described in <Options.Fx>.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.fx.plot();
+ (end code)
+
+ */
+ plot: function(opt, animating) {
+ var viz = this.viz,
+ aGraph = viz.graph,
+ canvas = viz.canvas,
+ id = viz.root,
+ that = this,
+ ctx = canvas.getCtx(),
+ min = Math.min,
+ opt = opt || this.viz.controller;
+
+ opt.clearCanvas && canvas.clear();
+
+ var root = aGraph.getNode(id);
+ if(!root) return;
+
+ var T = !!root.visited;
+ aGraph.eachNode(function(node) {
+ var nodeAlpha = node.getData('alpha');
+ node.eachAdjacency(function(adj) {
+ var nodeTo = adj.nodeTo;
+ if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
+ !animating && opt.onBeforePlotLine(adj);
+ that.plotLine(adj, canvas, animating);
+ !animating && opt.onAfterPlotLine(adj);
+ }
+ });
+ if(node.drawn) {
+ !animating && opt.onBeforePlotNode(node);
+ that.plotNode(node, canvas, animating);
+ !animating && opt.onAfterPlotNode(node);
+ }
+ if(!that.labelsHidden && opt.withLabels) {
+ if(node.drawn && nodeAlpha >= 0.95) {
+ that.labels.plotLabel(canvas, node, opt);
+ } else {
+ that.labels.hideLabel(node, false);
+ }
+ }
+ node.visited = !T;
+ });
+ },
+
+ /*
+ Plots a Subtree.
+ */
+ plotTree: function(node, opt, animating) {
+ var that = this,
+ viz = this.viz,
+ canvas = viz.canvas,
+ config = this.config,
+ ctx = canvas.getCtx();
+ var nodeAlpha = node.getData('alpha');
+ node.eachSubnode(function(elem) {
+ if(opt.plotSubtree(node, elem) && elem.exist && elem.drawn) {
+ var adj = node.getAdjacency(elem.id);
+ !animating && opt.onBeforePlotLine(adj);
+ that.plotLine(adj, canvas, animating);
+ !animating && opt.onAfterPlotLine(adj);
+ that.plotTree(elem, opt, animating);
+ }
+ });
+ if(node.drawn) {
+ !animating && opt.onBeforePlotNode(node);
+ this.plotNode(node, canvas, animating);
+ !animating && opt.onAfterPlotNode(node);
+ if(!opt.hideLabels && opt.withLabels && nodeAlpha >= 0.95)
+ this.labels.plotLabel(canvas, node, opt);
+ else
+ this.labels.hideLabel(node, false);
+ } else {
+ this.labels.hideLabel(node, true);
+ }
+ },
+
+ /*
+ Method: plotNode
+
+ Plots a <Graph.Node>.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ canvas - (object) A <Canvas> element.
+
+ */
+ plotNode: function(node, canvas, animating) {
+ var f = node.getData('type'),
+ ctxObj = this.node.CanvasStyles;
+ if(f != 'none') {
+ var width = node.getData('lineWidth'),
+ color = node.getData('color'),
+ alpha = node.getData('alpha'),
+ ctx = canvas.getCtx();
+ ctx.save();
+ ctx.lineWidth = width;
+ ctx.fillStyle = ctx.strokeStyle = color;
+ ctx.globalAlpha = alpha;
+
+ for(var s in ctxObj) {
+ ctx[s] = node.getCanvasStyle(s);
+ }
+
+ this.nodeTypes[f].render.call(this, node, canvas, animating);
+ ctx.restore();
+ }
+ },
+
+ /*
+ Method: plotLine
+
+ Plots a <Graph.Adjacence>.
+
+ Parameters:
+
+ adj - (object) A <Graph.Adjacence>.
+ canvas - (object) A <Canvas> instance.
+
+ */
+ plotLine: function(adj, canvas, animating) {
+ var f = adj.getData('type'),
+ ctxObj = this.edge.CanvasStyles;
+ if(f != 'none') {
+ var width = adj.getData('lineWidth'),
+ color = adj.getData('color'),
+ ctx = canvas.getCtx(),
+ nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo;
+
+ ctx.save();
+ ctx.lineWidth = width;
+ ctx.fillStyle = ctx.strokeStyle = color;
+ ctx.globalAlpha = Math.min(nodeFrom.getData('alpha'),
+ nodeTo.getData('alpha'),
+ adj.getData('alpha'));
+
+ for(var s in ctxObj) {
+ ctx[s] = adj.getCanvasStyle(s);
+ }
+
+ this.edgeTypes[f].render.call(this, adj, canvas, animating);
+ ctx.restore();
+ }
+ }
+
+};
+
+/*
+ Object: Graph.Plot3D
+
+ <Graph> 3D rendering and animation methods.
+
+ Properties:
+
+ nodeHelper - <NodeHelper> object.
+ edgeHelper - <EdgeHelper> object.
+
+*/
+Graph.Plot3D = $.merge(Graph.Plot, {
+ Interpolator: {
+ 'linear': function(elem, props, delta) {
+ var from = elem.startPos.getc(true);
+ var to = elem.endPos.getc(true);
+ elem.pos.setc(this.compute(from.x, to.x, delta),
+ this.compute(from.y, to.y, delta),
+ this.compute(from.z, to.z, delta));
+ }
+ },
+
+ plotNode: function(node, canvas) {
+ if(node.getData('type') == 'none') return;
+ this.plotElement(node, canvas, {
+ getAlpha: function() {
+ return node.getData('alpha');
+ }
+ });
+ },
+
+ plotLine: function(adj, canvas) {
+ if(adj.getData('type') == 'none') return;
+ this.plotElement(adj, canvas, {
+ getAlpha: function() {
+ return Math.min(adj.nodeFrom.getData('alpha'),
+ adj.nodeTo.getData('alpha'),
+ adj.getData('alpha'));
+ }
+ });
+ },
+
+ plotElement: function(elem, canvas, opt) {
+ var gl = canvas.getCtx(),
+ viewMatrix = new Matrix4,
+ lighting = canvas.config.Scene.Lighting,
+ wcanvas = canvas.canvases[0],
+ program = wcanvas.program,
+ camera = wcanvas.camera;
+
+ if(!elem.geometry) {
+ elem.geometry = new O3D[elem.getData('type')];
+ }
+ elem.geometry.update(elem);
+ if(!elem.webGLVertexBuffer) {
+ var vertices = [],
+ faces = [],
+ normals = [],
+ vertexIndex = 0,
+ geom = elem.geometry;
+
+ for(var i=0, vs=geom.vertices, fs=geom.faces, fsl=fs.length; i<fsl; i++) {
+ var face = fs[i],
+ v1 = vs[face.a],
+ v2 = vs[face.b],
+ v3 = vs[face.c],
+ v4 = face.d? vs[face.d] : false,
+ n = face.normal;
+
+ vertices.push(v1.x, v1.y, v1.z);
+ vertices.push(v2.x, v2.y, v2.z);
+ vertices.push(v3.x, v3.y, v3.z);
+ if(v4) vertices.push(v4.x, v4.y, v4.z);
+
+ normals.push(n.x, n.y, n.z);
+ normals.push(n.x, n.y, n.z);
+ normals.push(n.x, n.y, n.z);
+ if(v4) normals.push(n.x, n.y, n.z);
+
+ faces.push(vertexIndex, vertexIndex +1, vertexIndex +2);
+ if(v4) {
+ faces.push(vertexIndex, vertexIndex +2, vertexIndex +3);
+ vertexIndex += 4;
+ } else {
+ vertexIndex += 3;
+ }
+ }
+ //create and store vertex data
+ elem.webGLVertexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLVertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+ //create and store faces index data
+ elem.webGLFaceBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elem.webGLFaceBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(faces), gl.STATIC_DRAW);
+ elem.webGLFaceCount = faces.length;
+ //calculate vertex normals and store them
+ elem.webGLNormalBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLNormalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
+ }
+ viewMatrix.multiply(camera.matrix, elem.geometry.matrix);
+ //send matrix data
+ gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.flatten());
+ gl.uniformMatrix4fv(program.projectionMatrix, false, camera.projectionMatrix.flatten());
+ //send normal matrix for lighting
+ var normalMatrix = Matrix4.makeInvert(viewMatrix);
+ normalMatrix.$transpose();
+ gl.uniformMatrix4fv(program.normalMatrix, false, normalMatrix.flatten());
+ //send color data
+ var color = $.hexToRgb(elem.getData('color'));
+ color.push(opt.getAlpha());
+ gl.uniform4f(program.color, color[0] / 255, color[1] / 255, color[2] / 255, color[3]);
+ //send lighting data
+ gl.uniform1i(program.enableLighting, lighting.enable);
+ if(lighting.enable) {
+ //set ambient light color
+ if(lighting.ambient) {
+ var acolor = lighting.ambient;
+ gl.uniform3f(program.ambientColor, acolor[0], acolor[1], acolor[2]);
+ }
+ //set directional light
+ if(lighting.directional) {
+ var dir = lighting.directional,
+ color = dir.color,
+ pos = dir.direction,
+ vd = new Vector3(pos.x, pos.y, pos.z).normalize().$scale(-1);
+ gl.uniform3f(program.lightingDirection, vd.x, vd.y, vd.z);
+ gl.uniform3f(program.directionalColor, color[0], color[1], color[2]);
+ }
+ }
+ //send vertices data
+ gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLVertexBuffer);
+ gl.vertexAttribPointer(program.position, 3, gl.FLOAT, false, 0, 0);
+ //send normals data
+ gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLNormalBuffer);
+ gl.vertexAttribPointer(program.normal, 3, gl.FLOAT, false, 0, 0);
+ //draw!
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elem.webGLFaceBuffer );
+ gl.drawElements(gl.TRIANGLES, elem.webGLFaceCount, gl.UNSIGNED_SHORT, 0);
+ }
+});
+
+
+/*
+ * File: Graph.Label.js
+ *
+*/
+
+/*
+ Object: Graph.Label
+
+ An interface for plotting/hiding/showing labels.
+
+ Description:
+
+ This is a generic interface for plotting/hiding/showing labels.
+ The <Graph.Label> interface is implemented in multiple ways to provide
+ different label types.
+
+ For example, the Graph.Label interface is implemented as <Graph.Label.HTML> to provide
+ HTML label elements. Also we provide the <Graph.Label.SVG> interface for SVG type labels.
+ The <Graph.Label.Native> interface implements these methods with the native Canvas text rendering functions.
+
+ All subclasses (<Graph.Label.HTML>, <Graph.Label.SVG> and <Graph.Label.Native>) implement the method plotLabel.
+*/
+
+Graph.Label = {};
+
+/*
+ Class: Graph.Label.Native
+
+ Implements labels natively, using the Canvas text API.
+*/
+Graph.Label.Native = new Class({
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ /*
+ Method: plotLabel
+
+ Plots a label for a given node.
+
+ Parameters:
+
+ canvas - (object) A <Canvas> instance.
+ node - (object) A <Graph.Node>.
+ controller - (object) A configuration object.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ var node = viz.graph.getNode('nodeId');
+ viz.labels.plotLabel(viz.canvas, node, viz.config);
+ (end code)
+ */
+ plotLabel: function(canvas, node, controller) {
+ var ctx = canvas.getCtx();
+ var pos = node.pos.getc(true);
+
+ ctx.font = node.getLabelData('style') + ' ' + node.getLabelData('size') + 'px ' + node.getLabelData('family');
+ ctx.textAlign = node.getLabelData('textAlign');
+ ctx.fillStyle = ctx.strokeStyle = node.getLabelData('color');
+ ctx.textBaseline = node.getLabelData('textBaseline');
+
+ this.renderLabel(canvas, node, controller);
+ },
+
+ /*
+ renderLabel
+
+ Does the actual rendering of the label in the canvas. The default
+ implementation renders the label close to the position of the node, this
+ method should be overriden to position the labels differently.
+
+ Parameters:
+
+ canvas - A <Canvas> instance.
+ node - A <Graph.Node>.
+ controller - A configuration object. See also <Hypertree>, <RGraph>, <ST>.
+ */
+ renderLabel: function(canvas, node, controller) {
+ var ctx = canvas.getCtx();
+ var pos = node.pos.getc(true);
+ ctx.fillText(node.name, pos.x, pos.y + node.getData("height") / 2);
+ },
+
+ hideLabel: $.empty,
+ hideLabels: $.empty
+});
+
+/*
+ Class: Graph.Label.DOM
+
+ Abstract Class implementing some DOM label methods.
+
+ Implemented by:
+
+ <Graph.Label.HTML> and <Graph.Label.SVG>.
+
+*/
+Graph.Label.DOM = new Class({
+ //A flag value indicating if node labels are being displayed or not.
+ labelsHidden: false,
+ //Label container
+ labelContainer: false,
+ //Label elements hash.
+ labels: {},
+
+ /*
+ Method: getLabelContainer
+
+ Lazy fetcher for the label container.
+
+ Returns:
+
+ The label container DOM element.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ var labelContainer = viz.labels.getLabelContainer();
+ alert(labelContainer.innerHTML);
+ (end code)
+ */
+ getLabelContainer: function() {
+ return this.labelContainer ?
+ this.labelContainer :
+ this.labelContainer = document.getElementById(this.viz.config.labelContainer);
+ },
+
+ /*
+ Method: getLabel
+
+ Lazy fetcher for the label element.
+
+ Parameters:
+
+ id - (string) The label id (which is also a <Graph.Node> id).
+
+ Returns:
+
+ The label element.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ var label = viz.labels.getLabel('someid');
+ alert(label.innerHTML);
+ (end code)
+
+ */
+ getLabel: function(id) {
+ return (id in this.labels && this.labels[id] != null) ?
+ this.labels[id] :
+ this.labels[id] = document.getElementById(id);
+ },
+
+ /*
+ Method: hideLabels
+
+ Hides all labels (by hiding the label container).
+
+ Parameters:
+
+ hide - (boolean) A boolean value indicating if the label container must be hidden or not.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ rg.labels.hideLabels(true);
+ (end code)
+
+ */
+ hideLabels: function (hide) {
+ var container = this.getLabelContainer();
+ if(hide)
+ container.style.display = 'none';
+ else
+ container.style.display = '';
+ this.labelsHidden = hide;
+ },
+
+ /*
+ Method: clearLabels
+
+ Clears the label container.
+
+ Useful when using a new visualization with the same canvas element/widget.
+
+ Parameters:
+
+ force - (boolean) Forces deletion of all labels.
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.labels.clearLabels();
+ (end code)
+ */
+ clearLabels: function(force) {
+ for(var id in this.labels) {
+ if (force || !this.viz.graph.hasNode(id)) {
+ this.disposeLabel(id);
+ delete this.labels[id];
+ }
+ }
+ },
+
+ /*
+ Method: disposeLabel
+
+ Removes a label.
+
+ Parameters:
+
+ id - (string) A label id (which generally is also a <Graph.Node> id).
+
+ Example:
+ (start code js)
+ var viz = new $jit.Viz(options);
+ viz.labels.disposeLabel('labelid');
+ (end code)
+ */
+ disposeLabel: function(id) {
+ var elem = this.getLabel(id);
+ if(elem && elem.parentNode) {
+ elem.parentNode.removeChild(elem);
+ }
+ },
+
+ /*
+ Method: hideLabel
+
+ Hides the corresponding <Graph.Node> label.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>. Can also be an array of <Graph.Nodes>.
+ show - (boolean) If *true*, nodes will be shown. Otherwise nodes will be hidden.
+
+ Example:
+ (start code js)
+ var rg = new $jit.Viz(options);
+ viz.labels.hideLabel(viz.graph.getNode('someid'), false);
+ (end code)
+ */
+ hideLabel: function(node, show) {
+ node = $.splat(node);
+ var st = show ? "" : "none", lab, that = this;
+ $.each(node, function(n) {
+ var lab = that.getLabel(n.id);
+ if (lab) {
+ lab.style.display = st;
+ }
+ });
+ },
+
+ /*
+ fitsInCanvas
+
+ Returns _true_ or _false_ if the label for the node is contained in the canvas dom element or not.
+
+ Parameters:
+
+ pos - A <Complex> instance (I'm doing duck typing here so any object with _x_ and _y_ parameters will do).
+ canvas - A <Canvas> instance.
+
+ Returns:
+
+ A boolean value specifying if the label is contained in the <Canvas> DOM element or not.
+
+ */
+ fitsInCanvas: function(pos, canvas) {
+ var size = canvas.getSize();
+ if(pos.x >= size.width || pos.x < 0
+ || pos.y >= size.height || pos.y < 0) return false;
+ return true;
+ }
+});
+
+/*
+ Class: Graph.Label.HTML
+
+ Implements HTML labels.
+
+ Extends:
+
+ All <Graph.Label.DOM> methods.
+
+*/
+Graph.Label.HTML = new Class({
+ Implements: Graph.Label.DOM,
+
+ /*
+ Method: plotLabel
+
+ Plots a label for a given node.
+
+ Parameters:
+
+ canvas - (object) A <Canvas> instance.
+ node - (object) A <Graph.Node>.
+ controller - (object) A configuration object.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ var node = viz.graph.getNode('nodeId');
+ viz.labels.plotLabel(viz.canvas, node, viz.config);
+ (end code)
+
+
+ */
+ plotLabel: function(canvas, node, controller) {
+ var id = node.id, tag = this.getLabel(id);
+
+ if(!tag && !(tag = document.getElementById(id))) {
+ tag = document.createElement('div');
+ var container = this.getLabelContainer();
+ tag.id = id;
+ tag.className = 'node';
+ tag.style.position = 'absolute';
+ controller.onCreateLabel(tag, node);
+ container.appendChild(tag);
+ this.labels[node.id] = tag;
+ }
+
+ this.placeLabel(tag, node, controller);
+ }
+});
+
+/*
+ Class: Graph.Label.SVG
+
+ Implements SVG labels.
+
+ Extends:
+
+ All <Graph.Label.DOM> methods.
+*/
+Graph.Label.SVG = new Class({
+ Implements: Graph.Label.DOM,
+
+ /*
+ Method: plotLabel
+
+ Plots a label for a given node.
+
+ Parameters:
+
+ canvas - (object) A <Canvas> instance.
+ node - (object) A <Graph.Node>.
+ controller - (object) A configuration object.
+
+ Example:
+
+ (start code js)
+ var viz = new $jit.Viz(options);
+ var node = viz.graph.getNode('nodeId');
+ viz.labels.plotLabel(viz.canvas, node, viz.config);
+ (end code)
+
+
+ */
+ plotLabel: function(canvas, node, controller) {
+ var id = node.id, tag = this.getLabel(id);
+ if(!tag && !(tag = document.getElementById(id))) {
+ var ns = 'http://www.w3.org/2000/svg';
+ tag = document.createElementNS(ns, 'svg:text');
+ var tspan = document.createElementNS(ns, 'svg:tspan');
+ tag.appendChild(tspan);
+ var container = this.getLabelContainer();
+ tag.setAttribute('id', id);
+ tag.setAttribute('class', 'node');
+ container.appendChild(tag);
+ controller.onCreateLabel(tag, node);
+ this.labels[node.id] = tag;
+ }
+ this.placeLabel(tag, node, controller);
+ }
+});
+
+
+
+Graph.Geom = new Class({
+
+ initialize: function(viz) {
+ this.viz = viz;
+ this.config = viz.config;
+ this.node = viz.config.Node;
+ this.edge = viz.config.Edge;
+ },
+ /*
+ Applies a translation to the tree.
+
+ Parameters:
+
+ pos - A <Complex> number specifying translation vector.
+ prop - A <Graph.Node> position property ('pos', 'start' or 'end').
+
+ Example:
+
+ (start code js)
+ st.geom.translate(new Complex(300, 100), 'end');
+ (end code)
+ */
+ translate: function(pos, prop) {
+ prop = $.splat(prop);
+ this.viz.graph.eachNode(function(elem) {
+ $.each(prop, function(p) { elem.getPos(p).$add(pos); });
+ });
+ },
+ /*
+ Hides levels of the tree until it properly fits in canvas.
+ */
+ setRightLevelToShow: function(node, canvas, callback) {
+ var level = this.getRightLevelToShow(node, canvas),
+ fx = this.viz.labels,
+ opt = $.merge({
+ execShow:true,
+ execHide:true,
+ onHide: $.empty,
+ onShow: $.empty
+ }, callback || {});
+ node.eachLevel(0, this.config.levelsToShow, function(n) {
+ var d = n._depth - node._depth;
+ if(d > level) {
+ opt.onHide(n);
+ if(opt.execHide) {
+ n.drawn = false;
+ n.exist = false;
+ fx.hideLabel(n, false);
+ }
+ } else {
+ opt.onShow(n);
+ if(opt.execShow) {
+ n.exist = true;
+ }
+ }
+ });
+ node.drawn= true;
+ },
+ /*
+ Returns the right level to show for the current tree in order to fit in canvas.
+ */
+ getRightLevelToShow: function(node, canvas) {
+ var config = this.config;
+ var level = config.levelsToShow;
+ var constrained = config.constrained;
+ if(!constrained) return level;
+ while(!this.treeFitsInCanvas(node, canvas, level) && level > 1) { level-- ; }
+ return level;
+ }
+});
+
+/*
+ * File: Loader.js
+ *
+ */
+
+/*
+ Object: Loader
+
+ Provides methods for loading and serving JSON data.
+*/
+var Loader = {
+ construct: function(json) {
+ var isGraph = ($.type(json) == 'array');
+ var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
+ if(!isGraph)
+ //make tree
+ (function (ans, json) {
+ ans.addNode(json);
+ if(json.children) {
+ for(var i=0, ch = json.children; i<ch.length; i++) {
+ ans.addAdjacence(json, ch[i]);
+ arguments.callee(ans, ch[i]);
+ }
+ }
+ })(ans, json);
+ else
+ //make graph
+ (function (ans, json) {
+ var getNode = function(id) {
+ for(var i=0, l=json.length; i<l; i++) {
+ if(json[i].id == id) {
+ return json[i];
+ }
+ }
+ // The node was not defined in the JSON
+ // Let's create it
+ var newNode = {
+ "id" : id,
+ "name" : id
+ };
+ return ans.addNode(newNode);
+ };
+
+ for(var i=0, l=json.length; i<l; i++) {
+ ans.addNode(json[i]);
+ var adj = json[i].adjacencies;
+ if (adj) {
+ for(var j=0, lj=adj.length; j<lj; j++) {
+ var node = adj[j], data = {};
+ if(typeof adj[j] != 'string') {
+ data = $.merge(node.data, {});
+ node = node.nodeTo;
+ }
+ ans.addAdjacence(json[i], getNode(node), data);
+ }
+ }
+ }
+ })(ans, json);
+
+ return ans;
+ },
+
+ /*
+ Method: loadJSON
+
+ Loads a JSON structure to the visualization. The JSON structure can be a JSON *tree* or *graph* structure.
+
+ A JSON tree or graph structure consists of nodes, each having as properties
+
+ id - (string) A unique identifier for the node
+ name - (string) A node's name
+ data - (object) The data optional property contains a hash (i.e {})
+ where you can store all the information you want about this node.
+
+ For JSON *Tree* structures, there's an extra optional property *children* of type Array which contains the node's children.
+
+ Example:
+
+ (start code js)
+ var json = {
+ "id": "aUniqueIdentifier",
+ "name": "usually a nodes name",
+ "data": {
+ "some key": "some value",
+ "some other key": "some other value"
+ },
+ "children": [ *other nodes or empty* ]
+ };
+ (end code)
+
+ JSON *Graph* structures consist of an array of nodes, each specifying the nodes to which the current node is connected.
+ For JSON *Graph* structures, the *children* property is replaced by the *adjacencies* property.
+
+ There are two types of *Graph* structures, *simple* and *extended* graph structures.
+
+ For *simple* Graph structures, the adjacencies property contains an array of strings, each specifying the
+ id of the node connected to the main node.
+
+ Example:
+
+ (start code js)
+ var json = [
+ {
+ "id": "aUniqueIdentifier",
+ "name": "usually a nodes name",
+ "data": {
+ "some key": "some value",
+ "some other key": "some other value"
+ },
+ "adjacencies": ["anotherUniqueIdentifier", "yetAnotherUniqueIdentifier", 'etc']
+ },
+
+ 'other nodes go here...'
+ ];
+ (end code)
+
+ For *extended Graph structures*, the adjacencies property contains an array of Adjacency objects that have as properties
+
+ nodeTo - (string) The other node connected by this adjacency.
+ data - (object) A data property, where we can store custom key/value information.
+
+ Example:
+
+ (start code js)
+ var json = [
+ {
+ "id": "aUniqueIdentifier",
+ "name": "usually a nodes name",
+ "data": {
+ "some key": "some value",
+ "some other key": "some other value"
+ },
+ "adjacencies": [
+ {
+ nodeTo:"aNodeId",
+ data: {} //put whatever you want here
+ },
+ 'other adjacencies go here...'
+ },
+
+ 'other nodes go here...'
+ ];
+ (end code)
+
+ About the data property:
+
+ As described before, you can store custom data in the *data* property of JSON *nodes* and *adjacencies*.
+ You can use almost any string as key for the data object. Some keys though are reserved by the toolkit, and
+ have special meanings. This is the case for keys starting with a dollar sign, for example, *$width*.
+
+ For JSON *node* objects, adding dollar prefixed properties that match the names of the options defined in
+ <Options.Node> will override the general value for that option with that particular value. For this to work
+ however, you do have to set *overridable = true* in <Options.Node>.
+
+ The same thing is true for JSON adjacencies. Dollar prefixed data properties will alter values set in <Options.Edge>
+ if <Options.Edge> has *overridable = true*.
+
+ When loading JSON data into TreeMaps, the *data* property must contain a value for the *$area* key,
+ since this is the value which will be taken into account when creating the layout.
+ The same thing goes for the *$color* parameter.
+
+ In JSON Nodes you can use also *$label-* prefixed properties to refer to <Options.Label> properties. For example,
+ *$label-size* will refer to <Options.Label> size property. Also, in JSON nodes and adjacencies you can set
+ canvas specific properties individually by using the *$canvas-* prefix. For example, *$canvas-shadowBlur* will refer
+ to the *shadowBlur* property.
+
+ These properties can also be accessed after loading the JSON data from <Graph.Nodes> and <Graph.Adjacences>
+ by using <Accessors>. For more information take a look at the <Graph> and <Accessors> documentation.
+
+ Finally, these properties can also be used to create advanced animations like with <Options.NodeStyles>. For more
+ information about creating animations please take a look at the <Graph.Plot> and <Graph.Plot.animate> documentation.
+
+ loadJSON Parameters:
+
+ json - A JSON Tree or Graph structure.
+ i - For Graph structures only. Sets the indexed node as root for the visualization.
+
+ */
+ loadJSON: function(json, i) {
+ this.json = json;
+ //if they're canvas labels erase them.
+ if(this.labels && this.labels.clearLabels) {
+ this.labels.clearLabels(true);
+ }
+ this.graph = this.construct(json);
+ if($.type(json) != 'array'){
+ this.root = json.id;
+ } else {
+ this.root = json[i? i : 0].id;
+ }
+ },
+
+ /*
+ Method: toJSON
+
+ Returns a JSON tree/graph structure from the visualization's <Graph>.
+ See <Loader.loadJSON> for the graph formats available.
+
+ See also:
+
+ <Loader.loadJSON>
+
+ Parameters:
+
+ type - (string) Default's "tree". The type of the JSON structure to be returned.
+ Possible options are "tree" or "graph".
+ */
+ toJSON: function(type) {
+ type = type || "tree";
+ if(type == 'tree') {
+ var ans = {};
+ var rootNode = this.graph.getNode(this.root);
+ var ans = (function recTree(node) {
+ var ans = {};
+ ans.id = node.id;
+ ans.name = node.name;
+ ans.data = node.data;
+ var ch =[];
+ node.eachSubnode(function(n) {
+ ch.push(recTree(n));
+ });
+ ans.children = ch;
+ return ans;
+ })(rootNode);
+ return ans;
+ } else {
+ var ans = [];
+ var T = !!this.graph.getNode(this.root).visited;
+ this.graph.eachNode(function(node) {
+ var ansNode = {};
+ ansNode.id = node.id;
+ ansNode.name = node.name;
+ ansNode.data = node.data;
+ var adjs = [];
+ node.eachAdjacency(function(adj) {
+ var nodeTo = adj.nodeTo;
+ if(!!nodeTo.visited === T) {
+ var ansAdj = {};
+ ansAdj.nodeTo = nodeTo.id;
+ ansAdj.data = adj.data;
+ adjs.push(ansAdj);
+ }
+ });
+ ansNode.adjacencies = adjs;
+ ans.push(ansNode);
+ node.visited = !T;
+ });
+ return ans;
+ }
+ }
+};
+
+
+
+/*
+ * File: Layouts.js
+ *
+ * Implements base Tree and Graph layouts.
+ *
+ * Description:
+ *
+ * Implements base Tree and Graph layouts like Radial, Tree, etc.
+ *
+ */
+
+/*
+ * Object: Layouts
+ *
+ * Parent object for common layouts.
+ *
+ */
+var Layouts = $jit.Layouts = {};
+
+
+//Some util shared layout functions are defined here.
+var NodeDim = {
+ label: null,
+
+ compute: function(graph, prop, opt) {
+ this.initializeLabel(opt);
+ var label = this.label, style = label.style;
+ graph.eachNode(function(n) {
+ var autoWidth = n.getData('autoWidth'),
+ autoHeight = n.getData('autoHeight');
+ if(autoWidth || autoHeight) {
+ //delete dimensions since these are
+ //going to be overridden now.
+ delete n.data.$width;
+ delete n.data.$height;
+ delete n.data.$dim;
+
+ var width = n.getData('width'),
+ height = n.getData('height');
+ //reset label dimensions
+ style.width = autoWidth? 'auto' : width + 'px';
+ style.height = autoHeight? 'auto' : height + 'px';
+
+ //TODO(nico) should let the user choose what to insert here.
+ label.innerHTML = n.name;
+
+ var offsetWidth = label.offsetWidth,
+ offsetHeight = label.offsetHeight;
+ var type = n.getData('type');
+ if($.indexOf(['circle', 'square', 'triangle', 'star'], type) === -1) {
+ n.setData('width', offsetWidth);
+ n.setData('height', offsetHeight);
+ } else {
+ var dim = offsetWidth > offsetHeight? offsetWidth : offsetHeight;
+ n.setData('width', dim);
+ n.setData('height', dim);
+ n.setData('dim', dim);
+ }
+ }
+ });
+ },
+
+ initializeLabel: function(opt) {
+ if(!this.label) {
+ this.label = document.createElement('div');
+ document.body.appendChild(this.label);
+ }
+ this.setLabelStyles(opt);
+ },
+
+ setLabelStyles: function(opt) {
+ $.extend(this.label.style, {
+ 'visibility': 'hidden',
+ 'position': 'absolute',
+ 'width': 'auto',
+ 'height': 'auto'
+ });
+ this.label.className = 'jit-autoadjust-label';
+ }
+};
+
+
+/*
+ * Class: Layouts.Tree
+ *
+ * Implements a Tree Layout.
+ *
+ * Implemented By:
+ *
+ * <ST>
+ *
+ * Inspired by:
+ *
+ * Drawing Trees (Andrew J. Kennedy) <http://research.microsoft.com/en-us/um/people/akenn/fun/drawingtrees.pdf>
+ *
+ */
+Layouts.Tree = (function() {
+ //Layout functions
+ var slice = Array.prototype.slice;
+
+ /*
+ Calculates the max width and height nodes for a tree level
+ */
+ function getBoundaries(graph, config, level, orn, prop) {
+ var dim = config.Node;
+ var multitree = config.multitree;
+ if (dim.overridable) {
+ var w = -1, h = -1;
+ graph.eachNode(function(n) {
+ if (n._depth == level
+ && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {
+ var dw = n.getData('width', prop);
+ var dh = n.getData('height', prop);
+ w = (w < dw) ? dw : w;
+ h = (h < dh) ? dh : h;
+ }
+ });
+ return {
+ 'width' : w < 0 ? dim.width : w,
+ 'height' : h < 0 ? dim.height : h
+ };
+ } else {
+ return dim;
+ }
+ }
+
+
+ function movetree(node, prop, val, orn) {
+ var p = (orn == "left" || orn == "right") ? "y" : "x";
+ node.getPos(prop)[p] += val;
+ }
+
+
+ function moveextent(extent, val) {
+ var ans = [];
+ $.each(extent, function(elem) {
+ elem = slice.call(elem);
+ elem[0] += val;
+ elem[1] += val;
+ ans.push(elem);
+ });
+ return ans;
+ }
+
+
+ function merge(ps, qs) {
+ if (ps.length == 0)
+ return qs;
+ if (qs.length == 0)
+ return ps;
+ var p = ps.shift(), q = qs.shift();
+ return [ [ p[0], q[1] ] ].concat(merge(ps, qs));
+ }
+
+
+ function mergelist(ls, def) {
+ def = def || [];
+ if (ls.length == 0)
+ return def;
+ var ps = ls.pop();
+ return mergelist(ls, merge(ps, def));
+ }
+
+
+ function fit(ext1, ext2, subtreeOffset, siblingOffset, i) {
+ if (ext1.length <= i || ext2.length <= i)
+ return 0;
+
+ var p = ext1[i][1], q = ext2[i][0];
+ return Math.max(fit(ext1, ext2, subtreeOffset, siblingOffset, ++i)
+ + subtreeOffset, p - q + siblingOffset);
+ }
+
+
+ function fitlistl(es, subtreeOffset, siblingOffset) {
+ function $fitlistl(acc, es, i) {
+ if (es.length <= i)
+ return [];
+ var e = es[i], ans = fit(acc, e, subtreeOffset, siblingOffset, 0);
+ return [ ans ].concat($fitlistl(merge(acc, moveextent(e, ans)), es, ++i));
+ }
+ return $fitlistl( [], es, 0);
+ }
+
+
+ function fitlistr(es, subtreeOffset, siblingOffset) {
+ function $fitlistr(acc, es, i) {
+ if (es.length <= i)
+ return [];
+ var e = es[i], ans = -fit(e, acc, subtreeOffset, siblingOffset, 0);
+ return [ ans ].concat($fitlistr(merge(moveextent(e, ans), acc), es, ++i));
+ }
+ es = slice.call(es);
+ var ans = $fitlistr( [], es.reverse(), 0);
+ return ans.reverse();
+ }
+
+
+ function fitlist(es, subtreeOffset, siblingOffset, align) {
+ var esl = fitlistl(es, subtreeOffset, siblingOffset), esr = fitlistr(es,
+ subtreeOffset, siblingOffset);
+
+ if (align == "left")
+ esr = esl;
+ else if (align == "right")
+ esl = esr;
+
+ for ( var i = 0, ans = []; i < esl.length; i++) {
+ ans[i] = (esl[i] + esr[i]) / 2;
+ }
+ return ans;
+ }
+
+
+ function design(graph, node, prop, config, orn) {
+ var multitree = config.multitree;
+ var auxp = [ 'x', 'y' ], auxs = [ 'width', 'height' ];
+ var ind = +(orn == "left" || orn == "right");
+ var p = auxp[ind], notp = auxp[1 - ind];
+
+ var cnode = config.Node;
+ var s = auxs[ind], nots = auxs[1 - ind];
+
+ var siblingOffset = config.siblingOffset;
+ var subtreeOffset = config.subtreeOffset;
+ var align = config.align;
+
+ function $design(node, maxsize, acum) {
+ var sval = node.getData(s, prop);
+ var notsval = maxsize
+ || (node.getData(nots, prop));
+
+ var trees = [], extents = [], chmaxsize = false;
+ var chacum = notsval + config.levelDistance;
+ node.eachSubnode(function(n) {
+ if (n.exist
+ && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {
+
+ if (!chmaxsize)
+ chmaxsize = getBoundaries(graph, config, n._depth, orn, prop);
+
+ var s = $design(n, chmaxsize[nots], acum + chacum);
+ trees.push(s.tree);
+ extents.push(s.extent);
+ }
+ });
+ var positions = fitlist(extents, subtreeOffset, siblingOffset, align);
+ for ( var i = 0, ptrees = [], pextents = []; i < trees.length; i++) {
+ movetree(trees[i], prop, positions[i], orn);
+ pextents.push(moveextent(extents[i], positions[i]));
+ }
+ var resultextent = [ [ -sval / 2, sval / 2 ] ]
+ .concat(mergelist(pextents));
+ node.getPos(prop)[p] = 0;
+
+ if (orn == "top" || orn == "left") {
+ node.getPos(prop)[notp] = acum;
+ } else {
+ node.getPos(prop)[notp] = -acum;
+ }
+
+ return {
+ tree : node,
+ extent : resultextent
+ };
+ }
+
+ $design(node, false, 0);
+ }
+
+
+ return new Class({
+ /*
+ Method: compute
+
+ Computes nodes' positions.
+
+ */
+ compute : function(property, computeLevels) {
+ var prop = property || 'start';
+ var node = this.graph.getNode(this.root);
+ $.extend(node, {
+ 'drawn' : true,
+ 'exist' : true,
+ 'selected' : true
+ });
+ NodeDim.compute(this.graph, prop, this.config);
+ if (!!computeLevels || !("_depth" in node)) {
+ this.graph.computeLevels(this.root, 0, "ignore");
+ }
+
+ this.computePositions(node, prop);
+ },
+
+ computePositions : function(node, prop) {
+ var config = this.config;
+ var multitree = config.multitree;
+ var align = config.align;
+ var indent = align !== 'center' && config.indent;
+ var orn = config.orientation;
+ var orns = multitree ? [ 'top', 'right', 'bottom', 'left' ] : [ orn ];
+ var that = this;
+ $.each(orns, function(orn) {
+ //calculate layout
+ design(that.graph, node, prop, that.config, orn, prop);
+ var i = [ 'x', 'y' ][+(orn == "left" || orn == "right")];
+ //absolutize
+ (function red(node) {
+ node.eachSubnode(function(n) {
+ if (n.exist
+ && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {
+
+ n.getPos(prop)[i] += node.getPos(prop)[i];
+ if (indent) {
+ n.getPos(prop)[i] += align == 'left' ? indent : -indent;
+ }
+ red(n);
+ }
+ });
+ })(node);
+ });
+ }
+ });
+
+})();
+
+/*
+ * File: Spacetree.js
+ */
+
+/*
+ Class: ST
+
+ A Tree layout with advanced contraction and expansion animations.
+
+ Inspired by:
+
+ SpaceTree: Supporting Exploration in Large Node Link Tree, Design Evolution and Empirical Evaluation (Catherine Plaisant, Jesse Grosjean, Benjamin B. Bederson)
+ <http://hcil.cs.umd.edu/trs/2002-05/2002-05.pdf>
+
+ Drawing Trees (Andrew J. Kennedy) <http://research.microsoft.com/en-us/um/people/akenn/fun/drawingtrees.pdf>
+
+ Note:
+
+ This visualization was built and engineered from scratch, taking only the papers as inspiration, and only shares some features with the visualization described in those papers.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Tree>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ constrained - (boolean) Default's *true*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.
+ levelsToShow - (number) Default's *2*. The number of levels to show for a subtree. This number is relative to the selected node.
+ levelDistance - (number) Default's *30*. The distance between two consecutive levels of the tree.
+ Node.type - Described in <Options.Node>. Default's set to *rectangle*.
+ offsetX - (number) Default's *0*. The x-offset distance from the selected node to the center of the canvas.
+ offsetY - (number) Default's *0*. The y-offset distance from the selected node to the center of the canvas.
+ duration - Described in <Options.Fx>. It's default value has been changed to *700*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <ST.Op> instance.
+ fx - Access a <ST.Plot> instance.
+ labels - Access a <ST.Label> interface implementation.
+
+ */
+
+$jit.ST= (function() {
+ // Define some private methods first...
+ // Nodes in path
+ var nodesInPath = [];
+ // Nodes to contract
+ function getNodesToHide(node) {
+ node = node || this.clickedNode;
+ if(!this.config.constrained) {
+ return [];
+ }
+ var Geom = this.geom;
+ var graph = this.graph;
+ var canvas = this.canvas;
+ var level = node._depth, nodeArray = [];
+ graph.eachNode(function(n) {
+ if(n.exist && !n.selected) {
+ if(n.isDescendantOf(node.id)) {
+ if(n._depth <= level) nodeArray.push(n);
+ } else {
+ nodeArray.push(n);
+ }
+ }
+ });
+ var leafLevel = Geom.getRightLevelToShow(node, canvas);
+ node.eachLevel(leafLevel, leafLevel, function(n) {
+ if(n.exist && !n.selected) nodeArray.push(n);
+ });
+
+ for (var i = 0; i < nodesInPath.length; i++) {
+ var n = this.graph.getNode(nodesInPath[i]);
+ if(!n.isDescendantOf(node.id)) {
+ nodeArray.push(n);
+ }
+ }
+ return nodeArray;
+
+}
+ // Nodes to expand
+ function getNodesToShow(node) {
+ var nodeArray = [], config = this.config;
+ node = node || this.clickedNode;
+ this.clickedNode.eachLevel(0, config.levelsToShow, function(n) {
+ if(config.multitree && !('$orn' in n.data)
+ && n.anySubnode(function(ch){ return ch.exist && !ch.drawn; })) {
+ nodeArray.push(n);
+ } else if(n.drawn && !n.anySubnode("drawn")) {
+ nodeArray.push(n);
+ }
+ });
+ return nodeArray;
+ }
+ // Now define the actual class.
+ return new Class({
+
+ Implements: [Loader, Extras, Layouts.Tree],
+
+ initialize: function(controller) {
+ var $ST = $jit.ST;
+
+ var config= {
+ levelsToShow: 2,
+ levelDistance: 30,
+ constrained: true,
+ Node: {
+ type: 'rectangle'
+ },
+ duration: 700,
+ offsetX: 0,
+ offsetY: 0
+ };
+
+ this.controller = this.config = $.merge(
+ Options("Canvas", "Fx", "Tree", "Node", "Edge", "Controller",
+ "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
+
+ var canvasConfig = this.config;
+ if(canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Complex
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
+ this.labels = new $ST.Label[canvasConfig.Label.type](this);
+ this.fx = new $ST.Plot(this, $ST);
+ this.op = new $ST.Op(this);
+ this.group = new $ST.Group(this);
+ this.geom = new $ST.Geom(this);
+ this.clickedNode= null;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+ Method: plot
+
+ Plots the <ST>. This is a shortcut to *fx.plot*.
+
+ */
+ plot: function() { this.fx.plot(this.controller); },
+
+
+ /*
+ Method: switchPosition
+
+ Switches the tree orientation.
+
+ Parameters:
+
+ pos - (string) The new tree orientation. Possible values are "top", "left", "right" and "bottom".
+ method - (string) Set this to "animate" if you want to animate the tree when switching its position. You can also set this parameter to "replot" to just replot the subtree.
+ onComplete - (optional|object) This callback is called once the "switching" animation is complete.
+
+ Example:
+
+ (start code js)
+ st.switchPosition("right", "animate", {
+ onComplete: function() {
+ alert('completed!');
+ }
+ });
+ (end code)
+ */
+ switchPosition: function(pos, method, onComplete) {
+ var Geom = this.geom, Plot = this.fx, that = this;
+ if(!Plot.busy) {
+ Plot.busy = true;
+ this.contract({
+ onComplete: function() {
+ Geom.switchOrientation(pos);
+ that.compute('end', false);
+ Plot.busy = false;
+ if(method == 'animate') {
+ that.onClick(that.clickedNode.id, onComplete);
+ } else if(method == 'replot') {
+ that.select(that.clickedNode.id, onComplete);
+ }
+ }
+ }, pos);
+ }
+ },
+
+ /*
+ Method: switchAlignment
+
+ Switches the tree alignment.
+
+ Parameters:
+
+ align - (string) The new tree alignment. Possible values are "left", "center" and "right".
+ method - (string) Set this to "animate" if you want to animate the tree after aligning its position. You can also set this parameter to "replot" to just replot the subtree.
+ onComplete - (optional|object) This callback is called once the "switching" animation is complete.
+
+ Example:
+
+ (start code js)
+ st.switchAlignment("right", "animate", {
+ onComplete: function() {
+ alert('completed!');
+ }
+ });
+ (end code)
+ */
+ switchAlignment: function(align, method, onComplete) {
+ this.config.align = align;
+ if(method == 'animate') {
+ this.select(this.clickedNode.id, onComplete);
+ } else if(method == 'replot') {
+ this.onClick(this.clickedNode.id, onComplete);
+ }
+ },
+
+ /*
+ Method: addNodeInPath
+
+ Adds a node to the current path as selected node. The selected node will be visible (as in non-collapsed) at all times.
+
+
+ Parameters:
+
+ id - (string) A <Graph.Node> id.
+
+ Example:
+
+ (start code js)
+ st.addNodeInPath("nodeId");
+ (end code)
+ */
+ addNodeInPath: function(id) {
+ nodesInPath.push(id);
+ this.select((this.clickedNode && this.clickedNode.id) || this.root);
+ },
+
+ /*
+ Method: clearNodesInPath
+
+ Removes all nodes tagged as selected by the <ST.addNodeInPath> method.
+
+ See also:
+
+ <ST.addNodeInPath>
+
+ Example:
+
+ (start code js)
+ st.clearNodesInPath();
+ (end code)
+ */
+ clearNodesInPath: function(id) {
+ nodesInPath.length = 0;
+ this.select((this.clickedNode && this.clickedNode.id) || this.root);
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+
+ */
+ refresh: function() {
+ this.reposition();
+ this.select((this.clickedNode && this.clickedNode.id) || this.root);
+ },
+
+ reposition: function() {
+ this.graph.computeLevels(this.root, 0, "ignore");
+ this.geom.setRightLevelToShow(this.clickedNode, this.canvas);
+ this.graph.eachNode(function(n) {
+ if(n.exist) n.drawn = true;
+ });
+ this.compute('end');
+ },
+
+ requestNodes: function(node, onComplete) {
+ var handler = $.merge(this.controller, onComplete),
+ lev = this.config.levelsToShow;
+ if(handler.request) {
+ var leaves = [], d = node._depth;
+ node.eachLevel(0, lev, function(n) {
+ if(n.drawn &&
+ !n.anySubnode()) {
+ leaves.push(n);
+ n._level = lev - (n._depth - d);
+ }
+ });
+ this.group.requestNodes(leaves, handler);
+ }
+ else
+ handler.onComplete();
+ },
+
+ contract: function(onComplete, switched) {
+ var orn = this.config.orientation;
+ var Geom = this.geom, Group = this.group;
+ if(switched) Geom.switchOrientation(switched);
+ var nodes = getNodesToHide.call(this);
+ if(switched) Geom.switchOrientation(orn);
+ Group.contract(nodes, $.merge(this.controller, onComplete));
+ },
+
+ move: function(node, onComplete) {
+ this.compute('end', false);
+ var move = onComplete.Move, offset = {
+ 'x': move.offsetX,
+ 'y': move.offsetY
+ };
+ if(move.enable) {
+ this.geom.translate(node.endPos.add(offset).$scale(-1), "end");
+ }
+ this.fx.animate($.merge(this.controller, { modes: ['linear'] }, onComplete));
+ },
+
+ expand: function (node, onComplete) {
+ var nodeArray = getNodesToShow.call(this, node);
+ this.group.expand(nodeArray, $.merge(this.controller, onComplete));
+ },
+
+ selectPath: function(node) {
+ var that = this;
+ this.graph.eachNode(function(n) { n.selected = false; });
+ function path(node) {
+ if(node == null || node.selected) return;
+ node.selected = true;
+ $.each(that.group.getSiblings([node])[node.id],
+ function(n) {
+ n.exist = true;
+ n.drawn = true;
+ });
+ var parents = node.getParents();
+ parents = (parents.length > 0)? parents[0] : null;
+ path(parents);
+ }
+ for(var i=0, ns = [node.id].concat(nodesInPath); i < ns.length; i++) {
+ path(this.graph.getNode(ns[i]));
+ }
+ },
+
+ /*
+ Method: setRoot
+
+ Switches the current root node. Changes the topology of the Tree.
+
+ Parameters:
+ id - (string) The id of the node to be set as root.
+ method - (string) Set this to "animate" if you want to animate the tree after adding the subtree. You can also set this parameter to "replot" to just replot the subtree.
+ onComplete - (optional|object) An action to perform after the animation (if any).
+
+ Example:
+
+ (start code js)
+ st.setRoot('nodeId', 'animate', {
+ onComplete: function() {
+ alert('complete!');
+ }
+ });
+ (end code)
+ */
+ setRoot: function(id, method, onComplete) {
+ if(this.busy) return;
+ this.busy = true;
+ var that = this, canvas = this.canvas;
+ var rootNode = this.graph.getNode(this.root);
+ var clickedNode = this.graph.getNode(id);
+ function $setRoot() {
+ if(this.config.multitree && clickedNode.data.$orn) {
+ var orn = clickedNode.data.$orn;
+ var opp = {
+ 'left': 'right',
+ 'right': 'left',
+ 'top': 'bottom',
+ 'bottom': 'top'
+ }[orn];
+ rootNode.data.$orn = opp;
+ (function tag(rootNode) {
+ rootNode.eachSubnode(function(n) {
+ if(n.id != id) {
+ n.data.$orn = opp;
+ tag(n);
+ }
+ });
+ })(rootNode);
+ delete clickedNode.data.$orn;
+ }
+ this.root = id;
+ this.clickedNode = clickedNode;
+ this.graph.computeLevels(this.root, 0, "ignore");
+ this.geom.setRightLevelToShow(clickedNode, canvas, {
+ execHide: false,
+ onShow: function(node) {
+ if(!node.drawn) {
+ node.drawn = true;
+ node.setData('alpha', 1, 'end');
+ node.setData('alpha', 0);
+ node.pos.setc(clickedNode.pos.x, clickedNode.pos.y);
+ }
+ }
+ });
+ this.compute('end');
+ this.busy = true;
+ this.fx.animate({
+ modes: ['linear', 'node-property:alpha'],
+ onComplete: function() {
+ that.busy = false;
+ that.onClick(id, {
+ onComplete: function() {
+ onComplete && onComplete.onComplete();
+ }
+ });
+ }
+ });
+ }
+
+ // delete previous orientations (if any)
+ delete rootNode.data.$orns;
+
+ if(method == 'animate') {
+ $setRoot.call(this);
+ that.selectPath(clickedNode);
+ } else if(method == 'replot') {
+ $setRoot.call(this);
+ this.select(this.root);
+ }
+ },
+
+ /*
+ Method: addSubtree
+
+ Adds a subtree.
+
+ Parameters:
+ subtree - (object) A JSON Tree object. See also <Loader.loadJSON>.
+ method - (string) Set this to "animate" if you want to animate the tree after adding the subtree. You can also set this parameter to "replot" to just replot the subtree.
+ onComplete - (optional|object) An action to perform after the animation (if any).
+
+ Example:
+
+ (start code js)
+ st.addSubtree(json, 'animate', {
+ onComplete: function() {
+ alert('complete!');
+ }
+ });
+ (end code)
+ */
+ addSubtree: function(subtree, method, onComplete) {
+ if(method == 'replot') {
+ this.op.sum(subtree, $.extend({ type: 'replot' }, onComplete || {}));
+ } else if (method == 'animate') {
+ this.op.sum(subtree, $.extend({ type: 'fade:seq' }, onComplete || {}));
+ }
+ },
+
+ /*
+ Method: removeSubtree
+
+ Removes a subtree.
+
+ Parameters:
+ id - (string) The _id_ of the subtree to be removed.
+ removeRoot - (boolean) Default's *false*. Remove the root of the subtree or only its subnodes.
+ method - (string) Set this to "animate" if you want to animate the tree after removing the subtree. You can also set this parameter to "replot" to just replot the subtree.
+ onComplete - (optional|object) An action to perform after the animation (if any).
+
+ Example:
+
+ (start code js)
+ st.removeSubtree('idOfSubtreeToBeRemoved', false, 'animate', {
+ onComplete: function() {
+ alert('complete!');
+ }
+ });
+ (end code)
+
+ */
+ removeSubtree: function(id, removeRoot, method, onComplete) {
+ var node = this.graph.getNode(id), subids = [];
+ node.eachLevel(+!removeRoot, false, function(n) {
+ subids.push(n.id);
+ });
+ if(method == 'replot') {
+ this.op.removeNode(subids, $.extend({ type: 'replot' }, onComplete || {}));
+ } else if (method == 'animate') {
+ this.op.removeNode(subids, $.extend({ type: 'fade:seq'}, onComplete || {}));
+ }
+ },
+
+ /*
+ Method: select
+
+ Selects a node in the <ST> without performing an animation. Useful when selecting
+ nodes which are currently hidden or deep inside the tree.
+
+ Parameters:
+ id - (string) The id of the node to select.
+ onComplete - (optional|object) an onComplete callback.
+
+ Example:
+ (start code js)
+ st.select('mynodeid', {
+ onComplete: function() {
+ alert('complete!');
+ }
+ });
+ (end code)
+ */
+ select: function(id, onComplete) {
+ var group = this.group, geom = this.geom;
+ var node= this.graph.getNode(id), canvas = this.canvas;
+ var root = this.graph.getNode(this.root);
+ var complete = $.merge(this.controller, onComplete);
+ var that = this;
+
+ complete.onBeforeCompute(node);
+ this.selectPath(node);
+ this.clickedNode= node;
+ this.requestNodes(node, {
+ onComplete: function(){
+ group.hide(group.prepare(getNodesToHide.call(that)), complete);
+ geom.setRightLevelToShow(node, canvas);
+ that.compute("current");
+ that.graph.eachNode(function(n) {
+ var pos = n.pos.getc(true);
+ n.startPos.setc(pos.x, pos.y);
+ n.endPos.setc(pos.x, pos.y);
+ n.visited = false;
+ });
+ var offset = { x: complete.offsetX, y: complete.offsetY };
+ that.geom.translate(node.endPos.add(offset).$scale(-1), ["start", "current", "end"]);
+ group.show(getNodesToShow.call(that));
+ that.plot();
+ complete.onAfterCompute(that.clickedNode);
+ complete.onComplete();
+ }
+ });
+ },
+
+ /*
+ Method: onClick
+
+ Animates the <ST> to center the node specified by *id*.
+
+ Parameters:
+
+ id - (string) A node id.
+ options - (optional|object) A group of options and callbacks described below.
+ onComplete - (object) An object callback called when the animation finishes.
+ Move - (object) An object that has as properties _offsetX_ or _offsetY_ for adding some offset position to the centered node.
+
+ Example:
+
+ (start code js)
+ st.onClick('mynodeid', {
+ Move: {
+ enable: true,
+ offsetX: 30,
+ offsetY: 5
+ },
+ onComplete: function() {
+ alert('yay!');
+ }
+ });
+ (end code)
+
+ */
+ onClick: function (id, options) {
+ var canvas = this.canvas, that = this, Geom = this.geom, config = this.config;
+ var innerController = {
+ Move: {
+ enable: true,
+ offsetX: config.offsetX || 0,
+ offsetY: config.offsetY || 0
+ },
+ setRightLevelToShowConfig: false,
+ onBeforeRequest: $.empty,
+ onBeforeContract: $.empty,
+ onBeforeMove: $.empty,
+ onBeforeExpand: $.empty
+ };
+ var complete = $.merge(this.controller, innerController, options);
+
+ if(!this.busy) {
+ this.busy = true;
+ var node = this.graph.getNode(id);
+ this.selectPath(node, this.clickedNode);
+ this.clickedNode = node;
+ complete.onBeforeCompute(node);
+ complete.onBeforeRequest(node);
+ this.requestNodes(node, {
+ onComplete: function() {
+ complete.onBeforeContract(node);
+ that.contract({
+ onComplete: function() {
+ Geom.setRightLevelToShow(node, canvas, complete.setRightLevelToShowConfig);
+ complete.onBeforeMove(node);
+ that.move(node, {
+ Move: complete.Move,
+ onComplete: function() {
+ complete.onBeforeExpand(node);
+ that.expand(node, {
+ onComplete: function() {
+ that.busy = false;
+ complete.onAfterCompute(id);
+ complete.onComplete();
+ }
+ }); // expand
+ }
+ }); // move
+ }
+ });// contract
+ }
+ });// request
+ }
+ }
+ });
+
+})();
+
+$jit.ST.$extend = true;
+
+/*
+ Class: ST.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+*/
+$jit.ST.Op = new Class({
+
+ Implements: Graph.Op
+
+});
+
+/*
+
+ Performs operations on group of nodes.
+
+*/
+$jit.ST.Group = new Class({
+
+ initialize: function(viz) {
+ this.viz = viz;
+ this.canvas = viz.canvas;
+ this.config = viz.config;
+ this.animation = new Animation;
+ this.nodes = null;
+ },
+
+ /*
+
+ Calls the request method on the controller to request a subtree for each node.
+ */
+ requestNodes: function(nodes, controller) {
+ var counter = 0, len = nodes.length, nodeSelected = {};
+ var complete = function() { controller.onComplete(); };
+ var viz = this.viz;
+ if(len == 0) complete();
+ for(var i=0; i<len; i++) {
+ nodeSelected[nodes[i].id] = nodes[i];
+ controller.request(nodes[i].id, nodes[i]._level, {
+ onComplete: function(nodeId, data) {
+ if(data && data.children) {
+ data.id = nodeId;
+ viz.op.sum(data, { type: 'nothing' });
+ }
+ if(++counter == len) {
+ viz.graph.computeLevels(viz.root, 0);
+ complete();
+ }
+ }
+ });
+ }
+ },
+
+ /*
+
+ Collapses group of nodes.
+ */
+ contract: function(nodes, controller) {
+ var viz = this.viz;
+ var that = this;
+
+ nodes = this.prepare(nodes);
+ this.animation.setOptions($.merge(controller, {
+ $animating: false,
+ compute: function(delta) {
+ if(delta == 1) delta = 0.99;
+ that.plotStep(1 - delta, controller, this.$animating);
+ this.$animating = 'contract';
+ },
+
+ complete: function() {
+ that.hide(nodes, controller);
+ }
+ })).start();
+ },
+
+ hide: function(nodes, controller) {
+ var viz = this.viz;
+ for(var i=0; i<nodes.length; i++) {
+ // TODO nodes are requested on demand, but not
+ // deleted when hidden. Would that be a good feature?
+ // Currently that feature is buggy, so I'll turn it off
+ // Actually this feature is buggy because trimming should take
+ // place onAfterCompute and not right after collapsing nodes.
+ if (true || !controller || !controller.request) {
+ nodes[i].eachLevel(1, false, function(elem){
+ if (elem.exist) {
+ $.extend(elem, {
+ 'drawn': false,
+ 'exist': false
+ });
+ }
+ });
+ } else {
+ var ids = [];
+ nodes[i].eachLevel(1, false, function(n) {
+ ids.push(n.id);
+ });
+ viz.op.removeNode(ids, { 'type': 'nothing' });
+ viz.labels.clearLabels();
+ }
+ }
+ controller.onComplete();
+ },
+
+
+ /*
+ Expands group of nodes.
+ */
+ expand: function(nodes, controller) {
+ var that = this;
+ this.show(nodes);
+ this.animation.setOptions($.merge(controller, {
+ $animating: false,
+ compute: function(delta) {
+ that.plotStep(delta, controller, this.$animating);
+ this.$animating = 'expand';
+ },
+
+ complete: function() {
+ that.plotStep(undefined, controller, false);
+ controller.onComplete();
+ }
+ })).start();
+
+ },
+
+ show: function(nodes) {
+ var config = this.config;
+ this.prepare(nodes);
+ $.each(nodes, function(n) {
+ // check for root nodes if multitree
+ if(config.multitree && !('$orn' in n.data)) {
+ delete n.data.$orns;
+ var orns = ' ';
+ n.eachSubnode(function(ch) {
+ if(('$orn' in ch.data)
+ && orns.indexOf(ch.data.$orn) < 0
+ && ch.exist && !ch.drawn) {
+ orns += ch.data.$orn + ' ';
+ }
+ });
+ n.data.$orns = orns;
+ }
+ n.eachLevel(0, config.levelsToShow, function(n) {
+ if(n.exist) n.drawn = true;
+ });
+ });
+ },
+
+ prepare: function(nodes) {
+ this.nodes = this.getNodesWithChildren(nodes);
+ return this.nodes;
+ },
+
+ /*
+ Filters an array of nodes leaving only nodes with children.
+ */
+ getNodesWithChildren: function(nodes) {
+ var ans = [], config = this.config, root = this.viz.root;
+ nodes.sort(function(a, b) { return (a._depth <= b._depth) - (a._depth >= b._depth); });
+ for(var i=0; i<nodes.length; i++) {
+ if(nodes[i].anySubnode("exist")) {
+ for (var j = i+1, desc = false; !desc && j < nodes.length; j++) {
+ if(!config.multitree || '$orn' in nodes[j].data) {
+ desc = desc || nodes[i].isDescendantOf(nodes[j].id);
+ }
+ }
+ if(!desc) ans.push(nodes[i]);
+ }
+ }
+ return ans;
+ },
+
+ plotStep: function(delta, controller, animating) {
+ var viz = this.viz,
+ config = this.config,
+ canvas = viz.canvas,
+ ctx = canvas.getCtx(),
+ nodes = this.nodes;
+ var i, node;
+ // hide nodes that are meant to be collapsed/expanded
+ var nds = {};
+ for(i=0; i<nodes.length; i++) {
+ node = nodes[i];
+ nds[node.id] = [];
+ var root = config.multitree && !('$orn' in node.data);
+ var orns = root && node.data.$orns;
+ node.eachSubgraph(function(n) {
+ // TODO(nico): Cleanup
+ // special check for root node subnodes when
+ // multitree is checked.
+ if(root && orns && orns.indexOf(n.data.$orn) > 0
+ && n.drawn) {
+ n.drawn = false;
+ nds[node.id].push(n);
+ } else if((!root || !orns) && n.drawn) {
+ n.drawn = false;
+ nds[node.id].push(n);
+ }
+ });
+ node.drawn = true;
+ }
+ // plot the whole (non-scaled) tree
+ if(nodes.length > 0) viz.fx.plot();
+ // show nodes that were previously hidden
+ for(i in nds) {
+ $.each(nds[i], function(n) { n.drawn = true; });
+ }
+ // plot each scaled subtree
+ for(i=0; i<nodes.length; i++) {
+ node = nodes[i];
+ ctx.save();
+ viz.fx.plotSubtree(node, controller, delta, animating);
+ ctx.restore();
+ }
+ },
+
+ getSiblings: function(nodes) {
+ var siblings = {};
+ $.each(nodes, function(n) {
+ var par = n.getParents();
+ if (par.length == 0) {
+ siblings[n.id] = [n];
+ } else {
+ var ans = [];
+ par[0].eachSubnode(function(sn) {
+ ans.push(sn);
+ });
+ siblings[n.id] = ans;
+ }
+ });
+ return siblings;
+ }
+});
+
+/*
+ ST.Geom
+
+ Performs low level geometrical computations.
+
+ Access:
+
+ This instance can be accessed with the _geom_ parameter of the st instance created.
+
+ Example:
+
+ (start code js)
+ var st = new ST(canvas, config);
+ st.geom.translate //or can also call any other <ST.Geom> method
+ (end code)
+
+*/
+
+$jit.ST.Geom = new Class({
+ Implements: Graph.Geom,
+ /*
+ Changes the tree current orientation to the one specified.
+
+ You should usually use <ST.switchPosition> instead.
+ */
+ switchOrientation: function(orn) {
+ this.config.orientation = orn;
+ },
+
+ /*
+ Makes a value dispatch according to the current layout
+ Works like a CSS property, either _top-right-bottom-left_ or _top|bottom - left|right_.
+ */
+ dispatch: function() {
+ // TODO(nico) should store Array.prototype.slice.call somewhere.
+ var args = Array.prototype.slice.call(arguments);
+ var s = args.shift(), len = args.length;
+ var val = function(a) { return typeof a == 'function'? a() : a; };
+ if(len == 2) {
+ return (s == "top" || s == "bottom")? val(args[0]) : val(args[1]);
+ } else if(len == 4) {
+ switch(s) {
+ case "top": return val(args[0]);
+ case "right": return val(args[1]);
+ case "bottom": return val(args[2]);
+ case "left": return val(args[3]);
+ }
+ }
+ return undefined;
+ },
+
+ /*
+ Returns label height or with, depending on the tree current orientation.
+ */
+ getSize: function(n, invert) {
+ var data = n.data, config = this.config;
+ var siblingOffset = config.siblingOffset;
+ var s = (config.multitree
+ && ('$orn' in data)
+ && data.$orn) || config.orientation;
+ var w = n.getData('width') + siblingOffset;
+ var h = n.getData('height') + siblingOffset;
+ if(!invert)
+ return this.dispatch(s, h, w);
+ else
+ return this.dispatch(s, w, h);
+ },
+
+ /*
+ Calculates a subtree base size. This is an utility function used by _getBaseSize_
+ */
+ getTreeBaseSize: function(node, level, leaf) {
+ var size = this.getSize(node, true), baseHeight = 0, that = this;
+ if(leaf(level, node)) return size;
+ if(level === 0) return 0;
+ node.eachSubnode(function(elem) {
+ baseHeight += that.getTreeBaseSize(elem, level -1, leaf);
+ });
+ return (size > baseHeight? size : baseHeight) + this.config.subtreeOffset;
+ },
+
+
+ /*
+ getEdge
+
+ Returns a Complex instance with the begin or end position of the edge to be plotted.
+
+ Parameters:
+
+ node - A <Graph.Node> that is connected to this edge.
+ type - Returns the begin or end edge position. Possible values are 'begin' or 'end'.
+
+ Returns:
+
+ A <Complex> number specifying the begin or end position.
+ */
+ getEdge: function(node, type, s) {
+ var $C = function(a, b) {
+ return function(){
+ return node.pos.add(new Complex(a, b));
+ };
+ };
+ var dim = this.node;
+ var w = node.getData('width');
+ var h = node.getData('height');
+
+ if(type == 'begin') {
+ if(dim.align == "center") {
+ return this.dispatch(s, $C(0, h/2), $C(-w/2, 0),
+ $C(0, -h/2),$C(w/2, 0));
+ } else if(dim.align == "left") {
+ return this.dispatch(s, $C(0, h), $C(0, 0),
+ $C(0, 0), $C(w, 0));
+ } else if(dim.align == "right") {
+ return this.dispatch(s, $C(0, 0), $C(-w, 0),
+ $C(0, -h),$C(0, 0));
+ } else throw "align: not implemented";
+
+
+ } else if(type == 'end') {
+ if(dim.align == "center") {
+ return this.dispatch(s, $C(0, -h/2), $C(w/2, 0),
+ $C(0, h/2), $C(-w/2, 0));
+ } else if(dim.align == "left") {
+ return this.dispatch(s, $C(0, 0), $C(w, 0),
+ $C(0, h), $C(0, 0));
+ } else if(dim.align == "right") {
+ return this.dispatch(s, $C(0, -h),$C(0, 0),
+ $C(0, 0), $C(-w, 0));
+ } else throw "align: not implemented";
+ }
+ },
+
+ /*
+ Adjusts the tree position due to canvas scaling or translation.
+ */
+ getScaledTreePosition: function(node, scale) {
+ var dim = this.node;
+ var w = node.getData('width');
+ var h = node.getData('height');
+ var s = (this.config.multitree
+ && ('$orn' in node.data)
+ && node.data.$orn) || this.config.orientation;
+
+ var $C = function(a, b) {
+ return function(){
+ return node.pos.add(new Complex(a, b)).$scale(1 - scale);
+ };
+ };
+ if(dim.align == "left") {
+ return this.dispatch(s, $C(0, h), $C(0, 0),
+ $C(0, 0), $C(w, 0));
+ } else if(dim.align == "center") {
+ return this.dispatch(s, $C(0, h / 2), $C(-w / 2, 0),
+ $C(0, -h / 2),$C(w / 2, 0));
+ } else if(dim.align == "right") {
+ return this.dispatch(s, $C(0, 0), $C(-w, 0),
+ $C(0, -h),$C(0, 0));
+ } else throw "align: not implemented";
+ },
+
+ /*
+ treeFitsInCanvas
+
+ Returns a Boolean if the current subtree fits in canvas.
+
+ Parameters:
+
+ node - A <Graph.Node> which is the current root of the subtree.
+ canvas - The <Canvas> object.
+ level - The depth of the subtree to be considered.
+ */
+ treeFitsInCanvas: function(node, canvas, level) {
+ var csize = canvas.getSize();
+ var s = (this.config.multitree
+ && ('$orn' in node.data)
+ && node.data.$orn) || this.config.orientation;
+
+ var size = this.dispatch(s, csize.width, csize.height);
+ var baseSize = this.getTreeBaseSize(node, level, function(level, node) {
+ return level === 0 || !node.anySubnode();
+ });
+ return (baseSize < size);
+ }
+});
+
+/*
+ Class: ST.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+*/
+$jit.ST.Plot = new Class({
+
+ Implements: Graph.Plot,
+
+ /*
+ Plots a subtree from the spacetree.
+ */
+ plotSubtree: function(node, opt, scale, animating) {
+ var viz = this.viz, canvas = viz.canvas, config = viz.config;
+ scale = Math.min(Math.max(0.001, scale), 1);
+ if(scale >= 0) {
+ node.drawn = false;
+ var ctx = canvas.getCtx();
+ var diff = viz.geom.getScaledTreePosition(node, scale);
+ ctx.translate(diff.x, diff.y);
+ ctx.scale(scale, scale);
+ }
+ this.plotTree(node, $.merge(opt, {
+ 'withLabels': true,
+ 'hideLabels': !!scale,
+ 'plotSubtree': function(n, ch) {
+ var root = config.multitree && !('$orn' in node.data);
+ var orns = root && node.getData('orns');
+ return !root || orns.indexOf(node.getData('orn')) > -1;
+ }
+ }), animating);
+ if(scale >= 0) node.drawn = true;
+ },
+
+ /*
+ Method: getAlignedPos
+
+ Returns a *x, y* object with the position of the top/left corner of a <ST> node.
+
+ Parameters:
+
+ pos - (object) A <Graph.Node> position.
+ width - (number) The width of the node.
+ height - (number) The height of the node.
+
+ */
+ getAlignedPos: function(pos, width, height) {
+ var nconfig = this.node;
+ var square, orn;
+ if(nconfig.align == "center") {
+ square = {
+ x: pos.x - width / 2,
+ y: pos.y - height / 2
+ };
+ } else if (nconfig.align == "left") {
+ orn = this.config.orientation;
+ if(orn == "bottom" || orn == "top") {
+ square = {
+ x: pos.x - width / 2,
+ y: pos.y
+ };
+ } else {
+ square = {
+ x: pos.x,
+ y: pos.y - height / 2
+ };
+ }
+ } else if(nconfig.align == "right") {
+ orn = this.config.orientation;
+ if(orn == "bottom" || orn == "top") {
+ square = {
+ x: pos.x - width / 2,
+ y: pos.y - height
+ };
+ } else {
+ square = {
+ x: pos.x - width,
+ y: pos.y - height / 2
+ };
+ }
+ } else throw "align: not implemented";
+
+ return square;
+ },
+
+ getOrientation: function(adj) {
+ var config = this.config;
+ var orn = config.orientation;
+
+ if(config.multitree) {
+ var nodeFrom = adj.nodeFrom;
+ var nodeTo = adj.nodeTo;
+ orn = (('$orn' in nodeFrom.data)
+ && nodeFrom.data.$orn)
+ || (('$orn' in nodeTo.data)
+ && nodeTo.data.$orn);
+ }
+
+ return orn;
+ }
+});
+
+/*
+ Class: ST.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+ */
+$jit.ST.Label = {};
+
+/*
+ ST.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+*/
+$jit.ST.Label.Native = new Class({
+ Implements: Graph.Label.Native,
+
+ renderLabel: function(canvas, node, controller) {
+ var ctx = canvas.getCtx(),
+ coord = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ pos = this.viz.fx.getAlignedPos(coord, width, height);
+ ctx.fillText(node.name, pos.x + width / 2, pos.y + height / 2);
+ }
+});
+
+$jit.ST.Label.DOM = new Class({
+ Implements: Graph.Label.DOM,
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true),
+ config = this.viz.config,
+ dim = config.Node,
+ canvas = this.viz.canvas,
+ w = node.getData('width'),
+ h = node.getData('height'),
+ radius = canvas.getSize(),
+ labelPos, orn;
+
+ var ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ posx = pos.x * sx + ox,
+ posy = pos.y * sy + oy;
+
+ if(dim.align == "center") {
+ labelPos= {
+ x: Math.round(posx - w / 2 + radius.width/2),
+ y: Math.round(posy - h / 2 + radius.height/2)
+ };
+ } else if (dim.align == "left") {
+ orn = config.orientation;
+ if(orn == "bottom" || orn == "top") {
+ labelPos= {
+ x: Math.round(posx - w / 2 + radius.width/2),
+ y: Math.round(posy + radius.height/2)
+ };
+ } else {
+ labelPos= {
+ x: Math.round(posx + radius.width/2),
+ y: Math.round(posy - h / 2 + radius.height/2)
+ };
+ }
+ } else if(dim.align == "right") {
+ orn = config.orientation;
+ if(orn == "bottom" || orn == "top") {
+ labelPos= {
+ x: Math.round(posx - w / 2 + radius.width/2),
+ y: Math.round(posy - h + radius.height/2)
+ };
+ } else {
+ labelPos= {
+ x: Math.round(posx - w + radius.width/2),
+ y: Math.round(posy - h / 2 + radius.height/2)
+ };
+ }
+ } else throw "align: not implemented";
+
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
+ controller.onPlaceLabel(tag, node);
+ }
+});
+
+/*
+ ST.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+*/
+$jit.ST.Label.SVG = new Class({
+ Implements: [$jit.ST.Label.DOM, Graph.Label.SVG],
+
+ initialize: function(viz) {
+ this.viz = viz;
+ }
+});
+
+/*
+ ST.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+*/
+$jit.ST.Label.HTML = new Class({
+ Implements: [$jit.ST.Label.DOM, Graph.Label.HTML],
+
+ initialize: function(viz) {
+ this.viz = viz;
+ }
+});
+
+
+/*
+ Class: ST.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'circle', 'rectangle', 'ellipse' and 'square'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ ST.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+*/
+$jit.ST.Plot.NodeTypes = new Class({
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false)
+ },
+ 'circle': {
+ 'render': function(node, canvas) {
+ var dim = node.getData('dim'),
+ pos = this.getAlignedPos(node.pos.getc(true), dim, dim),
+ dim2 = dim/2;
+ this.nodeHelper.circle.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas);
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = this.getAlignedPos(node.pos.getc(true), dim, dim),
+ dim2 = dim/2;
+ this.nodeHelper.circle.contains({x:npos.x+dim2, y:npos.y+dim2}, pos, dim2);
+ }
+ },
+ 'square': {
+ 'render': function(node, canvas) {
+ var dim = node.getData('dim'),
+ dim2 = dim/2,
+ pos = this.getAlignedPos(node.pos.getc(true), dim, dim);
+ this.nodeHelper.square.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas);
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = this.getAlignedPos(node.pos.getc(true), dim, dim),
+ dim2 = dim/2;
+ this.nodeHelper.square.contains({x:npos.x+dim2, y:npos.y+dim2}, pos, dim2);
+ }
+ },
+ 'ellipse': {
+ 'render': function(node, canvas) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ pos = this.getAlignedPos(node.pos.getc(true), width, height);
+ this.nodeHelper.ellipse.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas);
+ },
+ 'contains': function(node, pos) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ npos = this.getAlignedPos(node.pos.getc(true), width, height);
+ this.nodeHelper.ellipse.contains({x:npos.x+width/2, y:npos.y+height/2}, pos, width, height);
+ }
+ },
+ 'rectangle': {
+ 'render': function(node, canvas) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ pos = this.getAlignedPos(node.pos.getc(true), width, height);
+ this.nodeHelper.rectangle.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas);
+ },
+ 'contains': function(node, pos) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ npos = this.getAlignedPos(node.pos.getc(true), width, height);
+ this.nodeHelper.rectangle.contains({x:npos.x+width/2, y:npos.y+height/2}, pos, width, height);
+ }
+ }
+});
+
+/*
+ Class: ST.Plot.EdgeTypes
+
+ This class contains a list of <Graph.Adjacence> built-in types.
+ Edge types implemented are 'none', 'line', 'arrow', 'quadratic:begin', 'quadratic:end', 'bezier'.
+
+ You can add your custom edge types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ ST.Plot.EdgeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(adj, canvas) {
+ //print your custom edge to canvas
+ },
+ //optional
+ 'contains': function(adj, pos) {
+ //return true if pos is inside the arc or false otherwise
+ }
+ }
+ });
+ (end code)
+
+*/
+$jit.ST.Plot.EdgeTypes = new Class({
+ 'none': $.empty,
+ 'line': {
+ 'render': function(adj, canvas) {
+ var orn = this.getOrientation(adj),
+ nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn);
+ this.edgeHelper.line.render(from, to, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var orn = this.getOrientation(adj),
+ nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn);
+ return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'arrow': {
+ 'render': function(adj, canvas) {
+ var orn = this.getOrientation(adj),
+ node = adj.nodeFrom,
+ child = adj.nodeTo,
+ dim = adj.getData('dim'),
+ from = this.viz.geom.getEdge(node, 'begin', orn),
+ to = this.viz.geom.getEdge(child, 'end', orn),
+ direction = adj.data.$direction,
+ inv = (direction && direction.length>1 && direction[0] != node.id);
+ this.edgeHelper.arrow.render(from, to, dim, inv, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var orn = this.getOrientation(adj),
+ nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ to = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn);
+ return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'quadratic:begin': {
+ 'render': function(adj, canvas) {
+ var orn = this.getOrientation(adj);
+ var nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),
+ dim = adj.getData('dim'),
+ ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.moveTo(begin.x, begin.y);
+ switch(orn) {
+ case "left":
+ ctx.quadraticCurveTo(begin.x + dim, begin.y, end.x, end.y);
+ break;
+ case "right":
+ ctx.quadraticCurveTo(begin.x - dim, begin.y, end.x, end.y);
+ break;
+ case "top":
+ ctx.quadraticCurveTo(begin.x, begin.y + dim, end.x, end.y);
+ break;
+ case "bottom":
+ ctx.quadraticCurveTo(begin.x, begin.y - dim, end.x, end.y);
+ break;
+ }
+ ctx.stroke();
+ }
+ },
+ 'quadratic:end': {
+ 'render': function(adj, canvas) {
+ var orn = this.getOrientation(adj);
+ var nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),
+ dim = adj.getData('dim'),
+ ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.moveTo(begin.x, begin.y);
+ switch(orn) {
+ case "left":
+ ctx.quadraticCurveTo(end.x - dim, end.y, end.x, end.y);
+ break;
+ case "right":
+ ctx.quadraticCurveTo(end.x + dim, end.y, end.x, end.y);
+ break;
+ case "top":
+ ctx.quadraticCurveTo(end.x, end.y - dim, end.x, end.y);
+ break;
+ case "bottom":
+ ctx.quadraticCurveTo(end.x, end.y + dim, end.x, end.y);
+ break;
+ }
+ ctx.stroke();
+ }
+ },
+ 'bezier': {
+ 'render': function(adj, canvas) {
+ var orn = this.getOrientation(adj),
+ nodeFrom = adj.nodeFrom,
+ nodeTo = adj.nodeTo,
+ rel = nodeFrom._depth < nodeTo._depth,
+ begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),
+ end = this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),
+ dim = adj.getData('dim'),
+ ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.moveTo(begin.x, begin.y);
+ switch(orn) {
+ case "left":
+ ctx.bezierCurveTo(begin.x + dim, begin.y, end.x - dim, end.y, end.x, end.y);
+ break;
+ case "right":
+ ctx.bezierCurveTo(begin.x - dim, begin.y, end.x + dim, end.y, end.x, end.y);
+ break;
+ case "top":
+ ctx.bezierCurveTo(begin.x, begin.y + dim, end.x, end.y - dim, end.x, end.y);
+ break;
+ case "bottom":
+ ctx.bezierCurveTo(begin.x, begin.y - dim, end.x, end.y + dim, end.x, end.y);
+ break;
+ }
+ ctx.stroke();
+ }
+ }
+});
+
+
+
+/*
+ * File: AreaChart.js
+ *
+*/
+
+$jit.ST.Plot.NodeTypes.implement({
+ 'areachart-stacked' : {
+ 'render' : function(node, canvas) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ stringArray = node.getData('stringArray'),
+ dimArray = node.getData('dimArray'),
+ valArray = node.getData('valueArray'),
+ valLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0),
+ valRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0),
+ colorArray = node.getData('colorArray'),
+ colorLength = colorArray.length,
+ config = node.getData('config'),
+ gradient = node.getData('gradient'),
+ showLabels = config.showLabels,
+ aggregates = config.showAggregates,
+ label = config.Label,
+ prev = node.getData('prev');
+
+ var ctx = canvas.getCtx(), border = node.getData('border');
+ if (colorArray && dimArray && stringArray) {
+ for (var i=0, l=dimArray.length, acumLeft=0, acumRight=0, valAcum=0; i<l; i++) {
+ ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
+ ctx.save();
+ if(gradient && (dimArray[i][0] > 0 || dimArray[i][1] > 0)) {
+ var h1 = acumLeft + dimArray[i][0],
+ h2 = acumRight + dimArray[i][1],
+ alpha = Math.atan((h2 - h1) / width),
+ delta = 55;
+ var linear = ctx.createLinearGradient(x + width/2,
+ y - (h1 + h2)/2,
+ x + width/2 + delta * Math.sin(alpha),
+ y - (h1 + h2)/2 + delta * Math.cos(alpha));
+ var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),
+ function(v) { return (v * 0.85) >> 0; }));
+ linear.addColorStop(0, colorArray[i % colorLength]);
+ linear.addColorStop(1, color);
+ ctx.fillStyle = linear;
+ }
+ ctx.beginPath();
+ ctx.moveTo(x, y - acumLeft);
+ ctx.lineTo(x + width, y - acumRight);
+ ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);
+ ctx.lineTo(x, y - acumLeft - dimArray[i][0]);
+ ctx.lineTo(x, y - acumLeft);
+ ctx.fill();
+ ctx.restore();
+ if(border) {
+ var strong = border.name == stringArray[i];
+ var perc = strong? 0.7 : 0.8;
+ var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),
+ function(v) { return (v * perc) >> 0; }));
+ ctx.strokeStyle = color;
+ ctx.lineWidth = strong? 4 : 1;
+ ctx.save();
+ ctx.beginPath();
+ if(border.index === 0) {
+ ctx.moveTo(x, y - acumLeft);
+ ctx.lineTo(x, y - acumLeft - dimArray[i][0]);
+ } else {
+ ctx.moveTo(x + width, y - acumRight);
+ ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);
+ }
+ ctx.stroke();
+ ctx.restore();
+ }
+ acumLeft += (dimArray[i][0] || 0);
+ acumRight += (dimArray[i][1] || 0);
+
+ if(dimArray[i][0] > 0)
+ valAcum += (valArray[i][0] || 0);
+ }
+ if(prev && label.type == 'Native') {
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = ctx.strokeStyle = label.color;
+ ctx.font = label.style + ' ' + label.size + 'px ' + label.family;
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ var aggValue = aggregates(node.name, valLeft, valRight, node, valAcum);
+ if(aggValue !== false) {
+ ctx.fillText(aggValue !== true? aggValue : valAcum, x, y - acumLeft - config.labelOffset - label.size/2, width);
+ }
+ if(showLabels(node.name, valLeft, valRight, node)) {
+ ctx.fillText(node.name, x, y + label.size/2 + config.labelOffset);
+ }
+ ctx.restore();
+ }
+ }
+ },
+ 'contains': function(node, mpos) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ dimArray = node.getData('dimArray'),
+ rx = mpos.x - x;
+ //bounding box check
+ if(mpos.x < x || mpos.x > x + width
+ || mpos.y > y || mpos.y < y - height) {
+ return false;
+ }
+ //deep check
+ for(var i=0, l=dimArray.length, lAcum=y, rAcum=y; i<l; i++) {
+ var dimi = dimArray[i];
+ lAcum -= dimi[0];
+ rAcum -= dimi[1];
+ var intersec = lAcum + (rAcum - lAcum) * rx / width;
+ if(mpos.y >= intersec) {
+ var index = +(rx > width/2);
+ return {
+ 'name': node.getData('stringArray')[i],
+ 'color': node.getData('colorArray')[i],
+ 'value': node.getData('valueArray')[i][index],
+ 'index': index
+ };
+ }
+ }
+ return false;
+ }
+ }
+});
+
+/*
+ Class: AreaChart
+
+ A visualization that displays stacked area charts.
+
+ Constructor Options:
+
+ See <Options.AreaChart>.
+
+*/
+$jit.AreaChart = new Class({
+ st: null,
+ colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
+ selected: {},
+ busy: false,
+
+ initialize: function(opt) {
+ this.controller = this.config =
+ $.merge(Options("Canvas", "Margin", "Label", "AreaChart"), {
+ Label: { type: 'Native' }
+ }, opt);
+ //set functions for showLabels and showAggregates
+ var showLabels = this.config.showLabels,
+ typeLabels = $.type(showLabels),
+ showAggregates = this.config.showAggregates,
+ typeAggregates = $.type(showAggregates);
+ this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels);
+ this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates);
+
+ this.initializeViz();
+ },
+
+ initializeViz: function() {
+ var config = this.config,
+ that = this,
+ nodeType = config.type.split(":")[0],
+ nodeLabels = {};
+
+ var delegate = new $jit.ST({
+ injectInto: config.injectInto,
+ width: config.width,
+ height: config.height,
+ orientation: "bottom",
+ levelDistance: 0,
+ siblingOffset: 0,
+ subtreeOffset: 0,
+ withLabels: config.Label.type != 'Native',
+ useCanvas: config.useCanvas,
+ Label: {
+ type: config.Label.type
+ },
+ Node: {
+ overridable: true,
+ type: 'areachart-' + nodeType,
+ align: 'left',
+ width: 1,
+ height: 1
+ },
+ Edge: {
+ type: 'none'
+ },
+ Tips: {
+ enable: config.Tips.enable,
+ type: 'Native',
+ force: true,
+ onShow: function(tip, node, contains) {
+ var elem = contains;
+ config.Tips.onShow(tip, elem, node);
+ }
+ },
+ Events: {
+ enable: true,
+ type: 'Native',
+ onClick: function(node, eventInfo, evt) {
+ if(!config.filterOnClick && !config.Events.enable) return;
+ var elem = eventInfo.getContains();
+ if(elem) config.filterOnClick && that.filter(elem.name);
+ config.Events.enable && config.Events.onClick(elem, eventInfo, evt);
+ },
+ onRightClick: function(node, eventInfo, evt) {
+ if(!config.restoreOnRightClick) return;
+ that.restore();
+ },
+ onMouseMove: function(node, eventInfo, evt) {
+ if(!config.selectOnHover) return;
+ if(node) {
+ var elem = eventInfo.getContains();
+ that.select(node.id, elem.name, elem.index);
+ } else {
+ that.select(false, false, false);
+ }
+ }
+ },
+ onCreateLabel: function(domElement, node) {
+ var labelConf = config.Label,
+ valueArray = node.getData('valueArray'),
+ acumLeft = $.reduce(valueArray, function(x, y) { return x + y[0]; }, 0),
+ acumRight = $.reduce(valueArray, function(x, y) { return x + y[1]; }, 0);
+ if(node.getData('prev')) {
+ var nlbs = {
+ wrapper: document.createElement('div'),
+ aggregate: document.createElement('div'),
+ label: document.createElement('div')
+ };
+ var wrapper = nlbs.wrapper,
+ label = nlbs.label,
+ aggregate = nlbs.aggregate,
+ wrapperStyle = wrapper.style,
+ labelStyle = label.style,
+ aggregateStyle = aggregate.style;
+ //store node labels
+ nodeLabels[node.id] = nlbs;
+ //append labels
+ wrapper.appendChild(label);
+ wrapper.appendChild(aggregate);
+ if(!config.showLabels(node.name, acumLeft, acumRight, node)) {
+ label.style.display = 'none';
+ }
+ if(!config.showAggregates(node.name, acumLeft, acumRight, node)) {
+ aggregate.style.display = 'none';
+ }
+ wrapperStyle.position = 'relative';
+ wrapperStyle.overflow = 'visible';
+ wrapperStyle.fontSize = labelConf.size + 'px';
+ wrapperStyle.fontFamily = labelConf.family;
+ wrapperStyle.color = labelConf.color;
+ wrapperStyle.textAlign = 'center';
+ aggregateStyle.position = labelStyle.position = 'absolute';
+
+ domElement.style.width = node.getData('width') + 'px';
+ domElement.style.height = node.getData('height') + 'px';
+ label.innerHTML = node.name;
+
+ domElement.appendChild(wrapper);
+ }
+ },
+ onPlaceLabel: function(domElement, node) {
+ if(!node.getData('prev')) return;
+ var labels = nodeLabels[node.id],
+ wrapperStyle = labels.wrapper.style,
+ labelStyle = labels.label.style,
+ aggregateStyle = labels.aggregate.style,
+ width = node.getData('width'),
+ height = node.getData('height'),
+ dimArray = node.getData('dimArray'),
+ valArray = node.getData('valueArray'),
+ acumLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0),
+ acumRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0),
+ font = parseInt(wrapperStyle.fontSize, 10),
+ domStyle = domElement.style;
+
+ if(dimArray && valArray) {
+ if(config.showLabels(node.name, acumLeft, acumRight, node)) {
+ labelStyle.display = '';
+ } else {
+ labelStyle.display = 'none';
+ }
+ var aggValue = config.showAggregates(node.name, acumLeft, acumRight, node);
+ if(aggValue !== false) {
+ aggregateStyle.display = '';
+ } else {
+ aggregateStyle.display = 'none';
+ }
+ wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px';
+ aggregateStyle.left = labelStyle.left = -width/2 + 'px';
+ for(var i=0, l=valArray.length, acum=0, leftAcum=0; i<l; i++) {
+ if(dimArray[i][0] > 0) {
+ acum+= valArray[i][0];
+ leftAcum+= dimArray[i][0];
+ }
+ }
+ aggregateStyle.top = (-font - config.labelOffset) + 'px';
+ labelStyle.top = (config.labelOffset + leftAcum) + 'px';
+ domElement.style.top = parseInt(domElement.style.top, 10) - leftAcum + 'px';
+ domElement.style.height = wrapperStyle.height = leftAcum + 'px';
+ labels.aggregate.innerHTML = aggValue !== true? aggValue : acum;
+ }
+ }
+ });
+
+ var size = delegate.canvas.getSize(),
+ margin = config.Margin;
+ delegate.config.offsetY = -size.height/2 + margin.bottom
+ + (config.showLabels && (config.labelOffset + config.Label.size));
+ delegate.config.offsetX = (margin.right - margin.left)/2;
+ this.delegate = delegate;
+ this.canvas = this.delegate.canvas;
+ },
+
+ /*
+ Method: loadJSON
+
+ Loads JSON data into the visualization.
+
+ Parameters:
+
+ json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.
+
+ Example:
+ (start code js)
+ var areaChart = new $jit.AreaChart(options);
+ areaChart.loadJSON(json);
+ (end code)
+ */
+ loadJSON: function(json) {
+ var prefix = $.time(),
+ ch = [],
+ delegate = this.delegate,
+ name = $.splat(json.label),
+ color = $.splat(json.color || this.colors),
+ config = this.config,
+ gradient = !!config.type.split(":")[1],
+ animate = config.animate;
+
+ for(var i=0, values=json.values, l=values.length; i<l-1; i++) {
+ var val = values[i], prev = values[i-1], next = values[i+1];
+ var valLeft = $.splat(values[i].values), valRight = $.splat(values[i+1].values);
+ var valArray = $.zip(valLeft, valRight);
+ var acumLeft = 0, acumRight = 0;
+ ch.push({
+ 'id': prefix + val.label,
+ 'name': val.label,
+ 'data': {
+ 'value': valArray,
+ '$valueArray': valArray,
+ '$colorArray': color,
+ '$stringArray': name,
+ '$next': next.label,
+ '$prev': prev? prev.label:false,
+ '$config': config,
+ '$gradient': gradient
+ },
+ 'children': []
+ });
+ }
+ var root = {
+ 'id': prefix + '$root',
+ 'name': '',
+ 'data': {
+ '$type': 'none',
+ '$width': 1,
+ '$height': 1
+ },
+ 'children': ch
+ };
+ delegate.loadJSON(root);
+
+ this.normalizeDims();
+ delegate.compute();
+ delegate.select(delegate.root);
+ if(animate) {
+ delegate.fx.animate({
+ modes: ['node-property:height:dimArray'],
+ duration:1500
+ });
+ }
+ },
+
+ /*
+ Method: updateJSON
+
+ Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.
+
+ Parameters:
+
+ json - (object) JSON data to be updated. The JSON format corresponds to the one described in <AreaChart.loadJSON>.
+ onComplete - (object) A callback object to be called when the animation transition when updating the data end.
+
+ Example:
+
+ (start code js)
+ areaChart.updateJSON(json, {
+ onComplete: function() {
+ alert('update complete!');
+ }
+ });
+ (end code)
+ */
+ updateJSON: function(json, onComplete) {
+ if(this.busy) return;
+ this.busy = true;
+
+ var delegate = this.delegate,
+ graph = delegate.graph,
+ labels = json.label && $.splat(json.label),
+ values = json.values,
+ animate = this.config.animate,
+ that = this,
+ hashValues = {};
+
+ //convert the whole thing into a hash
+ for (var i = 0, l = values.length; i < l; i++) {
+ hashValues[values[i].label] = values[i];
+ }
+
+ graph.eachNode(function(n) {
+ var v = hashValues[n.name],
+ stringArray = n.getData('stringArray'),
+ valArray = n.getData('valueArray'),
+ next = n.getData('next');
+
+ if (v) {
+ v.values = $.splat(v.values);
+ $.each(valArray, function(a, i) {
+ a[0] = v.values[i];
+ if(labels) stringArray[i] = labels[i];
+ });
+ n.setData('valueArray', valArray);
+ }
+
+ if(next) {
+ v = hashValues[next];
+ if(v) {
+ $.each(valArray, function(a, i) {
+ a[1] = v.values[i];
+ });
+ }
+ }
+ });
+ this.normalizeDims();
+ delegate.compute();
+ delegate.select(delegate.root);
+ if(animate) {
+ delegate.fx.animate({
+ modes: ['node-property:height:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ onComplete && onComplete.onComplete();
+ }
+ });
+ }
+ },
+
+/*
+ Method: filter
+
+ Filter selected stacks, collapsing all other stacks. You can filter multiple stacks at the same time.
+
+ Parameters:
+
+ filters - (array) An array of strings with the name of the stacks to be filtered.
+ callback - (object) An object with an *onComplete* callback method.
+
+ Example:
+
+ (start code js)
+ areaChart.filter(['label A', 'label C'], {
+ onComplete: function() {
+ console.log('done!');
+ }
+ });
+ (end code)
+
+ See also:
+
+ <AreaChart.restore>.
+ */
+ filter: function(filters, callback) {
+ if(this.busy) return;
+ this.busy = true;
+ if(this.config.Tips.enable) this.delegate.tips.hide();
+ this.select(false, false, false);
+ var args = $.splat(filters);
+ var rt = this.delegate.graph.getNode(this.delegate.root);
+ var that = this;
+ this.normalizeDims();
+ rt.eachAdjacency(function(adj) {
+ var n = adj.nodeTo,
+ dimArray = n.getData('dimArray', 'end'),
+ stringArray = n.getData('stringArray');
+ n.setData('dimArray', $.map(dimArray, function(d, i) {
+ return ($.indexOf(args, stringArray[i]) > -1)? d:[0, 0];
+ }), 'end');
+ });
+ this.delegate.fx.animate({
+ modes: ['node-property:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ callback && callback.onComplete();
+ }
+ });
+ },
+
+ /*
+ Method: restore
+
+ Sets all stacks that could have been filtered visible.
+
+ Example:
+
+ (start code js)
+ areaChart.restore();
+ (end code)
+
+ See also:
+
+ <AreaChart.filter>.
+ */
+ restore: function(callback) {
+ if(this.busy) return;
+ this.busy = true;
+ if(this.config.Tips.enable) this.delegate.tips.hide();
+ this.select(false, false, false);
+ this.normalizeDims();
+ var that = this;
+ this.delegate.fx.animate({
+ modes: ['node-property:height:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ callback && callback.onComplete();
+ }
+ });
+ },
+ //adds the little brown bar when hovering the node
+ select: function(id, name, index) {
+ if(!this.config.selectOnHover) return;
+ var s = this.selected;
+ if(s.id != id || s.name != name
+ || s.index != index) {
+ s.id = id;
+ s.name = name;
+ s.index = index;
+ this.delegate.graph.eachNode(function(n) {
+ n.setData('border', false);
+ });
+ if(id) {
+ var n = this.delegate.graph.getNode(id);
+ n.setData('border', s);
+ var link = index === 0? 'prev':'next';
+ link = n.getData(link);
+ if(link) {
+ n = this.delegate.graph.getByName(link);
+ if(n) {
+ n.setData('border', {
+ name: name,
+ index: 1-index
+ });
+ }
+ }
+ }
+ this.delegate.plot();
+ }
+ },
+
+ /*
+ Method: getLegend
+
+ Returns an object containing as keys the legend names and as values hex strings with color values.
+
+ Example:
+
+ (start code js)
+ var legend = areaChart.getLegend();
+ (end code)
+ */
+ getLegend: function() {
+ var legend = {};
+ var n;
+ this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
+ n = adj.nodeTo;
+ });
+ var colors = n.getData('colorArray'),
+ len = colors.length;
+ $.each(n.getData('stringArray'), function(s, i) {
+ legend[s] = colors[i % len];
+ });
+ return legend;
+ },
+
+ /*
+ Method: getMaxValue
+
+ Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.
+
+ Example:
+
+ (start code js)
+ var ans = areaChart.getMaxValue();
+ (end code)
+
+ In some cases it could be useful to override this method to normalize heights for a group of AreaCharts, like when doing small multiples.
+
+ Example:
+
+ (start code js)
+ //will return 100 for all AreaChart instances,
+ //displaying all of them with the same scale
+ $jit.AreaChart.implement({
+ 'getMaxValue': function() {
+ return 100;
+ }
+ });
+ (end code)
+
+*/
+ getMaxValue: function() {
+ var maxValue = 0;
+ this.delegate.graph.eachNode(function(n) {
+ var valArray = n.getData('valueArray'),
+ acumLeft = 0, acumRight = 0;
+ $.each(valArray, function(v) {
+ acumLeft += +v[0];
+ acumRight += +v[1];
+ });
+ var acum = acumRight>acumLeft? acumRight:acumLeft;
+ maxValue = maxValue>acum? maxValue:acum;
+ });
+ return maxValue;
+ },
+
+ normalizeDims: function() {
+ //number of elements
+ var root = this.delegate.graph.getNode(this.delegate.root), l=0;
+ root.eachAdjacency(function() {
+ l++;
+ });
+ var maxValue = this.getMaxValue() || 1,
+ size = this.delegate.canvas.getSize(),
+ config = this.config,
+ margin = config.Margin,
+ labelOffset = config.labelOffset + config.Label.size,
+ fixedDim = (size.width - (margin.left + margin.right)) / l,
+ animate = config.animate,
+ height = size.height - (margin.top + margin.bottom) - (config.showAggregates && labelOffset)
+ - (config.showLabels && labelOffset);
+ this.delegate.graph.eachNode(function(n) {
+ var acumLeft = 0, acumRight = 0, animateValue = [];
+ $.each(n.getData('valueArray'), function(v) {
+ acumLeft += +v[0];
+ acumRight += +v[1];
+ animateValue.push([0, 0]);
+ });
+ var acum = acumRight>acumLeft? acumRight:acumLeft;
+ n.setData('width', fixedDim);
+ if(animate) {
+ n.setData('height', acum * height / maxValue, 'end');
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return [n[0] * height / maxValue, n[1] * height / maxValue];
+ }), 'end');
+ var dimArray = n.getData('dimArray');
+ if(!dimArray) {
+ n.setData('dimArray', animateValue);
+ }
+ } else {
+ n.setData('height', acum * height / maxValue);
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return [n[0] * height / maxValue, n[1] * height / maxValue];
+ }));
+ }
+ });
+ }
+});
+
+
+/*
+ * File: Options.BarChart.js
+ *
+*/
+
+/*
+ Object: Options.BarChart
+
+ <BarChart> options.
+ Other options included in the BarChart are <Options.Canvas>, <Options.Label>, <Options.Margin>, <Options.Tips> and <Options.Events>.
+
+ Syntax:
+
+ (start code js)
+
+ Options.BarChart = {
+ animate: true,
+ labelOffset: 3,
+ barsOffset: 0,
+ type: 'stacked',
+ hoveredColor: '#9fd4ff',
+ orientation: 'horizontal',
+ showAggregates: true,
+ showLabels: true
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+
+ var barChart = new $jit.BarChart({
+ animate: true,
+ barsOffset: 10,
+ type: 'stacked:gradient'
+ });
+
+ (end code)
+
+ Parameters:
+
+ animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks.
+ offset - (number) Default's *25*. Adds margin between the visualization and the canvas.
+ labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.
+ barsOffset - (number) Default's *0*. Separation between bars.
+ type - (string) Default's *'stacked'*. Stack or grouped styles. Posible values are 'stacked', 'grouped', 'stacked:gradient', 'grouped:gradient' to add gradients.
+ hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered bar stack.
+ orientation - (string) Default's 'horizontal'. Sets the direction of the bars. Possible options are 'vertical' or 'horizontal'.
+ showAggregates - (boolean, function) Default's *true*. Display the sum the values of each bar. Can also be a function that returns *true* or *false* to display the value of the bar or not. That same function can also return a string with the formatted data to be added.
+ showLabels - (boolean, function) Default's *true*. Display the name of the slots. Can also be a function that returns *true* or *false* for each bar to decide whether to show the label or not.
+
+*/
+
+Options.BarChart = {
+ $extend: true,
+
+ animate: true,
+ type: 'stacked', //stacked, grouped, : gradient
+ labelOffset: 3, //label offset
+ barsOffset: 0, //distance between bars
+ hoveredColor: '#9fd4ff',
+ orientation: 'horizontal',
+ showAggregates: true,
+ showLabels: true,
+ Tips: {
+ enable: false,
+ onShow: $.empty,
+ onHide: $.empty
+ },
+ Events: {
+ enable: false,
+ onClick: $.empty
+ }
+};
+
+/*
+ * File: BarChart.js
+ *
+*/
+
+$jit.ST.Plot.NodeTypes.implement({
+ 'barchart-stacked' : {
+ 'render' : function(node, canvas) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ dimArray = node.getData('dimArray'),
+ valueArray = node.getData('valueArray'),
+ colorArray = node.getData('colorArray'),
+ colorLength = colorArray.length,
+ stringArray = node.getData('stringArray');
+
+ var ctx = canvas.getCtx(),
+ opt = {},
+ border = node.getData('border'),
+ gradient = node.getData('gradient'),
+ config = node.getData('config'),
+ horz = config.orientation == 'horizontal',
+ aggregates = config.showAggregates,
+ showLabels = config.showLabels,
+ label = config.Label;
+
+ if (colorArray && dimArray && stringArray) {
+ for (var i=0, l=dimArray.length, acum=0, valAcum=0; i<l; i++) {
+ ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
+ if(gradient) {
+ var linear;
+ if(horz) {
+ linear = ctx.createLinearGradient(x + acum + dimArray[i]/2, y,
+ x + acum + dimArray[i]/2, y + height);
+ } else {
+ linear = ctx.createLinearGradient(x, y - acum - dimArray[i]/2,
+ x + width, y - acum- dimArray[i]/2);
+ }
+ var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),
+ function(v) { return (v * 0.5) >> 0; }));
+ linear.addColorStop(0, color);
+ linear.addColorStop(0.5, colorArray[i % colorLength]);
+ linear.addColorStop(1, color);
+ ctx.fillStyle = linear;
+ }
+ if(horz) {
+ ctx.fillRect(x + acum, y, dimArray[i], height);
+ } else {
+ ctx.fillRect(x, y - acum - dimArray[i], width, dimArray[i]);
+ }
+ if(border && border.name == stringArray[i]) {
+ opt.acum = acum;
+ opt.dimValue = dimArray[i];
+ }
+ acum += (dimArray[i] || 0);
+ valAcum += (valueArray[i] || 0);
+ }
+ if(border) {
+ ctx.save();
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = border.color;
+ if(horz) {
+ ctx.strokeRect(x + opt.acum + 1, y + 1, opt.dimValue -2, height - 2);
+ } else {
+ ctx.strokeRect(x + 1, y - opt.acum - opt.dimValue + 1, width -2, opt.dimValue -2);
+ }
+ ctx.restore();
+ }
+ if(label.type == 'Native') {
+ ctx.save();
+ ctx.fillStyle = ctx.strokeStyle = label.color;
+ ctx.font = label.style + ' ' + label.size + 'px ' + label.family;
+ ctx.textBaseline = 'middle';
+ var aggValue = aggregates(node.name, valAcum, node);
+ if(aggValue !== false) {
+ aggValue = aggValue !== true? aggValue : valAcum;
+ if(horz) {
+ ctx.textAlign = 'right';
+ ctx.fillText(aggValue, x + acum - config.labelOffset, y + height/2);
+ } else {
+ ctx.textAlign = 'center';
+ ctx.fillText(aggValue, x + width/2, y - height - label.size/2 - config.labelOffset);
+ }
+ }
+ if(showLabels(node.name, valAcum, node)) {
+ if(horz) {
+ ctx.textAlign = 'center';
+ ctx.translate(x - config.labelOffset - label.size/2, y + height/2);
+ ctx.rotate(Math.PI / 2);
+ ctx.fillText(node.name, 0, 0);
+ } else {
+ ctx.textAlign = 'center';
+ ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset);
+ }
+ }
+ ctx.restore();
+ }
+ }
+ },
+ 'contains': function(node, mpos) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ dimArray = node.getData('dimArray'),
+ config = node.getData('config'),
+ rx = mpos.x - x,
+ horz = config.orientation == 'horizontal';
+ //bounding box check
+ if(horz) {
+ if(mpos.x < x || mpos.x > x + width
+ || mpos.y > y + height || mpos.y < y) {
+ return false;
+ }
+ } else {
+ if(mpos.x < x || mpos.x > x + width
+ || mpos.y > y || mpos.y < y - height) {
+ return false;
+ }
+ }
+ //deep check
+ for(var i=0, l=dimArray.length, acum=(horz? x:y); i<l; i++) {
+ var dimi = dimArray[i];
+ if(horz) {
+ acum += dimi;
+ var intersec = acum;
+ if(mpos.x <= intersec) {
+ return {
+ 'name': node.getData('stringArray')[i],
+ 'color': node.getData('colorArray')[i],
+ 'value': node.getData('valueArray')[i],
+ 'label': node.name
+ };
+ }
+ } else {
+ acum -= dimi;
+ var intersec = acum;
+ if(mpos.y >= intersec) {
+ return {
+ 'name': node.getData('stringArray')[i],
+ 'color': node.getData('colorArray')[i],
+ 'value': node.getData('valueArray')[i],
+ 'label': node.name
+ };
+ }
+ }
+ }
+ return false;
+ }
+ },
+ 'barchart-grouped' : {
+ 'render' : function(node, canvas) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ dimArray = node.getData('dimArray'),
+ valueArray = node.getData('valueArray'),
+ valueLength = valueArray.length,
+ colorArray = node.getData('colorArray'),
+ colorLength = colorArray.length,
+ stringArray = node.getData('stringArray');
+
+ var ctx = canvas.getCtx(),
+ opt = {},
+ border = node.getData('border'),
+ gradient = node.getData('gradient'),
+ config = node.getData('config'),
+ horz = config.orientation == 'horizontal',
+ aggregates = config.showAggregates,
+ showLabels = config.showLabels,
+ label = config.Label,
+ fixedDim = (horz? height : width) / valueLength;
+
+ if (colorArray && dimArray && stringArray) {
+ for (var i=0, l=valueLength, acum=0, valAcum=0; i<l; i++) {
+ ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
+ if(gradient) {
+ var linear;
+ if(horz) {
+ linear = ctx.createLinearGradient(x + dimArray[i]/2, y + fixedDim * i,
+ x + dimArray[i]/2, y + fixedDim * (i + 1));
+ } else {
+ linear = ctx.createLinearGradient(x + fixedDim * i, y - dimArray[i]/2,
+ x + fixedDim * (i + 1), y - dimArray[i]/2);
+ }
+ var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),
+ function(v) { return (v * 0.5) >> 0; }));
+ linear.addColorStop(0, color);
+ linear.addColorStop(0.5, colorArray[i % colorLength]);
+ linear.addColorStop(1, color);
+ ctx.fillStyle = linear;
+ }
+ if(horz) {
+ ctx.fillRect(x, y + fixedDim * i, dimArray[i], fixedDim);
+ } else {
+ ctx.fillRect(x + fixedDim * i, y - dimArray[i], fixedDim, dimArray[i]);
+ }
+ if(border && border.name == stringArray[i]) {
+ opt.acum = fixedDim * i;
+ opt.dimValue = dimArray[i];
+ }
+ acum += (dimArray[i] || 0);
+ valAcum += (valueArray[i] || 0);
+ }
+ if(border) {
+ ctx.save();
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = border.color;
+ if(horz) {
+ ctx.strokeRect(x + 1, y + opt.acum + 1, opt.dimValue -2, fixedDim - 2);
+ } else {
+ ctx.strokeRect(x + opt.acum + 1, y - opt.dimValue + 1, fixedDim -2, opt.dimValue -2);
+ }
+ ctx.restore();
+ }
+ if(label.type == 'Native') {
+ ctx.save();
+ ctx.fillStyle = ctx.strokeStyle = label.color;
+ ctx.font = label.style + ' ' + label.size + 'px ' + label.family;
+ ctx.textBaseline = 'middle';
+ var aggValue = aggregates(node.name, valAcum, node);
+ if(aggValue !== false) {
+ aggValue = aggValue !== true? aggValue : valAcum;
+ if(horz) {
+ ctx.textAlign = 'right';
+ ctx.fillText(aggValue, x + Math.max.apply(null, dimArray) - config.labelOffset, y + height/2);
+ } else {
+ ctx.textAlign = 'center';
+ ctx.fillText(aggValue, x + width/2, y - Math.max.apply(null, dimArray) - label.size/2 - config.labelOffset);
+ }
+ }
+ if(showLabels(node.name, valAcum, node)) {
+ if(horz) {
+ ctx.textAlign = 'center';
+ ctx.translate(x - config.labelOffset - label.size/2, y + height/2);
+ ctx.rotate(Math.PI / 2);
+ ctx.fillText(node.name, 0, 0);
+ } else {
+ ctx.textAlign = 'center';
+ ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset);
+ }
+ }
+ ctx.restore();
+ }
+ }
+ },
+ 'contains': function(node, mpos) {
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ algnPos = this.getAlignedPos(pos, width, height),
+ x = algnPos.x, y = algnPos.y,
+ dimArray = node.getData('dimArray'),
+ len = dimArray.length,
+ config = node.getData('config'),
+ rx = mpos.x - x,
+ horz = config.orientation == 'horizontal',
+ fixedDim = (horz? height : width) / len;
+ //bounding box check
+ if(horz) {
+ if(mpos.x < x || mpos.x > x + width
+ || mpos.y > y + height || mpos.y < y) {
+ return false;
+ }
+ } else {
+ if(mpos.x < x || mpos.x > x + width
+ || mpos.y > y || mpos.y < y - height) {
+ return false;
+ }
+ }
+ //deep check
+ for(var i=0, l=dimArray.length; i<l; i++) {
+ var dimi = dimArray[i];
+ if(horz) {
+ var limit = y + fixedDim * i;
+ if(mpos.x <= x+ dimi && mpos.y >= limit && mpos.y <= limit + fixedDim) {
+ return {
+ 'name': node.getData('stringArray')[i],
+ 'color': node.getData('colorArray')[i],
+ 'value': node.getData('valueArray')[i],
+ 'label': node.name
+ };
+ }
+ } else {
+ var limit = x + fixedDim * i;
+ if(mpos.x >= limit && mpos.x <= limit + fixedDim && mpos.y >= y - dimi) {
+ return {
+ 'name': node.getData('stringArray')[i],
+ 'color': node.getData('colorArray')[i],
+ 'value': node.getData('valueArray')[i],
+ 'label': node.name
+ };
+ }
+ }
+ }
+ return false;
+ }
+ }
+});
+
+/*
+ Class: BarChart
+
+ A visualization that displays stacked bar charts.
+
+ Constructor Options:
+
+ See <Options.BarChart>.
+
+*/
+$jit.BarChart = new Class({
+ st: null,
+ colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
+ selected: {},
+ busy: false,
+
+ initialize: function(opt) {
+ this.controller = this.config =
+ $.merge(Options("Canvas", "Margin", "Label", "BarChart"), {
+ Label: { type: 'Native' }
+ }, opt);
+ //set functions for showLabels and showAggregates
+ var showLabels = this.config.showLabels,
+ typeLabels = $.type(showLabels),
+ showAggregates = this.config.showAggregates,
+ typeAggregates = $.type(showAggregates);
+ this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels);
+ this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates);
+
+ this.initializeViz();
+ },
+
+ initializeViz: function() {
+ var config = this.config, that = this;
+ var nodeType = config.type.split(":")[0],
+ horz = config.orientation == 'horizontal',
+ nodeLabels = {};
+
+ var delegate = new $jit.ST({
+ injectInto: config.injectInto,
+ width: config.width,
+ height: config.height,
+ orientation: horz? 'left' : 'bottom',
+ levelDistance: 0,
+ siblingOffset: config.barsOffset,
+ subtreeOffset: 0,
+ withLabels: config.Label.type != 'Native',
+ useCanvas: config.useCanvas,
+ Label: {
+ type: config.Label.type
+ },
+ Node: {
+ overridable: true,
+ type: 'barchart-' + nodeType,
+ align: 'left',
+ width: 1,
+ height: 1
+ },
+ Edge: {
+ type: 'none'
+ },
+ Tips: {
+ enable: config.Tips.enable,
+ type: 'Native',
+ force: true,
+ onShow: function(tip, node, contains) {
+ var elem = contains;
+ config.Tips.onShow(tip, elem, node);
+ }
+ },
+ Events: {
+ enable: true,
+ type: 'Native',
+ onClick: function(node, eventInfo, evt) {
+ if(!config.Events.enable) return;
+ var elem = eventInfo.getContains();
+ config.Events.onClick(elem, eventInfo, evt);
+ },
+ onMouseMove: function(node, eventInfo, evt) {
+ if(!config.hoveredColor) return;
+ if(node) {
+ var elem = eventInfo.getContains();
+ that.select(node.id, elem.name, elem.index);
+ } else {
+ that.select(false, false, false);
+ }
+ }
+ },
+ onCreateLabel: function(domElement, node) {
+ var labelConf = config.Label,
+ valueArray = node.getData('valueArray'),
+ acum = $.reduce(valueArray, function(x, y) { return x + y; }, 0);
+ var nlbs = {
+ wrapper: document.createElement('div'),
+ aggregate: document.createElement('div'),
+ label: document.createElement('div')
+ };
+ var wrapper = nlbs.wrapper,
+ label = nlbs.label,
+ aggregate = nlbs.aggregate,
+ wrapperStyle = wrapper.style,
+ labelStyle = label.style,
+ aggregateStyle = aggregate.style;
+ //store node labels
+ nodeLabels[node.id] = nlbs;
+ //append labels
+ wrapper.appendChild(label);
+ wrapper.appendChild(aggregate);
+ if(!config.showLabels(node.name, acum, node)) {
+ labelStyle.display = 'none';
+ }
+ if(!config.showAggregates(node.name, acum, node)) {
+ aggregateStyle.display = 'none';
+ }
+ wrapperStyle.position = 'relative';
+ wrapperStyle.overflow = 'visible';
+ wrapperStyle.fontSize = labelConf.size + 'px';
+ wrapperStyle.fontFamily = labelConf.family;
+ wrapperStyle.color = labelConf.color;
+ wrapperStyle.textAlign = 'center';
+ aggregateStyle.position = labelStyle.position = 'absolute';
+
+ domElement.style.width = node.getData('width') + 'px';
+ domElement.style.height = node.getData('height') + 'px';
+ aggregateStyle.left = labelStyle.left = '0px';
+
+ label.innerHTML = node.name;
+
+ domElement.appendChild(wrapper);
+ },
+ onPlaceLabel: function(domElement, node) {
+ if(!nodeLabels[node.id]) return;
+ var labels = nodeLabels[node.id],
+ wrapperStyle = labels.wrapper.style,
+ labelStyle = labels.label.style,
+ aggregateStyle = labels.aggregate.style,
+ grouped = config.type.split(':')[0] == 'grouped',
+ horz = config.orientation == 'horizontal',
+ dimArray = node.getData('dimArray'),
+ valArray = node.getData('valueArray'),
+ width = (grouped && horz)? Math.max.apply(null, dimArray) : node.getData('width'),
+ height = (grouped && !horz)? Math.max.apply(null, dimArray) : node.getData('height'),
+ font = parseInt(wrapperStyle.fontSize, 10),
+ domStyle = domElement.style;
+
+
+ if(dimArray && valArray) {
+ wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px';
+ for(var i=0, l=valArray.length, acum=0; i<l; i++) {
+ if(dimArray[i] > 0) {
+ acum+= valArray[i];
+ }
+ }
+ if(config.showLabels(node.name, acum, node)) {
+ labelStyle.display = '';
+ } else {
+ labelStyle.display = 'none';
+ }
+ var aggValue = config.showAggregates(node.name, acum, node);
+ if(aggValue !== false) {
+ aggregateStyle.display = '';
+ } else {
+ aggregateStyle.display = 'none';
+ }
+ if(config.orientation == 'horizontal') {
+ aggregateStyle.textAlign = 'right';
+ labelStyle.textAlign = 'left';
+ labelStyle.textIndex = aggregateStyle.textIndent = config.labelOffset + 'px';
+ aggregateStyle.top = labelStyle.top = (height-font)/2 + 'px';
+ domElement.style.height = wrapperStyle.height = height + 'px';
+ } else {
+ aggregateStyle.top = (-font - config.labelOffset) + 'px';
+ labelStyle.top = (config.labelOffset + height) + 'px';
+ domElement.style.top = parseInt(domElement.style.top, 10) - height + 'px';
+ domElement.style.height = wrapperStyle.height = height + 'px';
+ }
+ labels.aggregate.innerHTML = aggValue !== true? aggValue : acum;
+ }
+ }
+ });
+
+ var size = delegate.canvas.getSize(),
+ margin = config.Margin;
+ if(horz) {
+ delegate.config.offsetX = size.width/2 - margin.left
+ - (config.showLabels && (config.labelOffset + config.Label.size));
+ delegate.config.offsetY = (margin.bottom - margin.top)/2;
+ } else {
+ delegate.config.offsetY = -size.height/2 + margin.bottom
+ + (config.showLabels && (config.labelOffset + config.Label.size));
+ delegate.config.offsetX = (margin.right - margin.left)/2;
+ }
+ this.delegate = delegate;
+ this.canvas = this.delegate.canvas;
+ },
+
+ /*
+ Method: loadJSON
+
+ Loads JSON data into the visualization.
+
+ Parameters:
+
+ json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.
+
+ Example:
+ (start code js)
+ var barChart = new $jit.BarChart(options);
+ barChart.loadJSON(json);
+ (end code)
+ */
+ loadJSON: function(json) {
+ if(this.busy) return;
+ this.busy = true;
+
+ var prefix = $.time(),
+ ch = [],
+ delegate = this.delegate,
+ name = $.splat(json.label),
+ color = $.splat(json.color || this.colors),
+ config = this.config,
+ gradient = !!config.type.split(":")[1],
+ animate = config.animate,
+ horz = config.orientation == 'horizontal',
+ that = this;
+
+ for(var i=0, values=json.values, l=values.length; i<l; i++) {
+ var val = values[i]
+ var valArray = $.splat(values[i].values);
+ var acum = 0;
+ ch.push({
+ 'id': prefix + val.label,
+ 'name': val.label,
+ 'data': {
+ 'value': valArray,
+ '$valueArray': valArray,
+ '$colorArray': color,
+ '$stringArray': name,
+ '$gradient': gradient,
+ '$config': config
+ },
+ 'children': []
+ });
+ }
+ var root = {
+ 'id': prefix + '$root',
+ 'name': '',
+ 'data': {
+ '$type': 'none',
+ '$width': 1,
+ '$height': 1
+ },
+ 'children': ch
+ };
+ delegate.loadJSON(root);
+
+ this.normalizeDims();
+ delegate.compute();
+ delegate.select(delegate.root);
+ if(animate) {
+ if(horz) {
+ delegate.fx.animate({
+ modes: ['node-property:width:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ }
+ });
+ } else {
+ delegate.fx.animate({
+ modes: ['node-property:height:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ }
+ });
+ }
+ } else {
+ this.busy = false;
+ }
+ },
+
+ /*
+ Method: updateJSON
+
+ Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.
+
+ Parameters:
+
+ json - (object) JSON data to be updated. The JSON format corresponds to the one described in <BarChart.loadJSON>.
+ onComplete - (object) A callback object to be called when the animation transition when updating the data end.
+
+ Example:
+
+ (start code js)
+ barChart.updateJSON(json, {
+ onComplete: function() {
+ alert('update complete!');
+ }
+ });
+ (end code)
+ */
+ updateJSON: function(json, onComplete) {
+ if(this.busy) return;
+ this.busy = true;
+ this.select(false, false, false);
+ var delegate = this.delegate;
+ var graph = delegate.graph;
+ var values = json.values;
+ var animate = this.config.animate;
+ var that = this;
+ var horz = this.config.orientation == 'horizontal';
+ $.each(values, function(v) {
+ var n = graph.getByName(v.label);
+ if(n) {
+ n.setData('valueArray', $.splat(v.values));
+ if(json.label) {
+ n.setData('stringArray', $.splat(json.label));
+ }
+ }
+ });
+ this.normalizeDims();
+ delegate.compute();
+ delegate.select(delegate.root);
+ if(animate) {
+ if(horz) {
+ delegate.fx.animate({
+ modes: ['node-property:width:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ onComplete && onComplete.onComplete();
+ }
+ });
+ } else {
+ delegate.fx.animate({
+ modes: ['node-property:height:dimArray'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ onComplete && onComplete.onComplete();
+ }
+ });
+ }
+ }
+ },
+
+ //adds the little brown bar when hovering the node
+ select: function(id, name) {
+ if(!this.config.hoveredColor) return;
+ var s = this.selected;
+ if(s.id != id || s.name != name) {
+ s.id = id;
+ s.name = name;
+ s.color = this.config.hoveredColor;
+ this.delegate.graph.eachNode(function(n) {
+ if(id == n.id) {
+ n.setData('border', s);
+ } else {
+ n.setData('border', false);
+ }
+ });
+ this.delegate.plot();
+ }
+ },
+
+ /*
+ Method: getLegend
+
+ Returns an object containing as keys the legend names and as values hex strings with color values.
+
+ Example:
+
+ (start code js)
+ var legend = barChart.getLegend();
+ (end code)
+ */
+ getLegend: function() {
+ var legend = {};
+ var n;
+ this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
+ n = adj.nodeTo;
+ });
+ var colors = n.getData('colorArray'),
+ len = colors.length;
+ $.each(n.getData('stringArray'), function(s, i) {
+ legend[s] = colors[i % len];
+ });
+ return legend;
+ },
+
+ /*
+ Method: getMaxValue
+
+ Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.
+
+ Example:
+
+ (start code js)
+ var ans = barChart.getMaxValue();
+ (end code)
+
+ In some cases it could be useful to override this method to normalize heights for a group of BarCharts, like when doing small multiples.
+
+ Example:
+
+ (start code js)
+ //will return 100 for all BarChart instances,
+ //displaying all of them with the same scale
+ $jit.BarChart.implement({
+ 'getMaxValue': function() {
+ return 100;
+ }
+ });
+ (end code)
+
+ */
+ getMaxValue: function() {
+ var maxValue = 0, stacked = this.config.type.split(':')[0] == 'stacked';
+ this.delegate.graph.eachNode(function(n) {
+ var valArray = n.getData('valueArray'),
+ acum = 0;
+ if(!valArray) return;
+ if(stacked) {
+ $.each(valArray, function(v) {
+ acum += +v;
+ });
+ } else {
+ acum = Math.max.apply(null, valArray);
+ }
+ maxValue = maxValue>acum? maxValue:acum;
+ });
+ return maxValue;
+ },
+
+ setBarType: function(type) {
+ this.config.type = type;
+ this.delegate.config.Node.type = 'barchart-' + type.split(':')[0];
+ },
+
+ normalizeDims: function() {
+ //number of elements
+ var root = this.delegate.graph.getNode(this.delegate.root), l=0;
+ root.eachAdjacency(function() {
+ l++;
+ });
+ var maxValue = this.getMaxValue() || 1,
+ size = this.delegate.canvas.getSize(),
+ config = this.config,
+ margin = config.Margin,
+ marginWidth = margin.left + margin.right,
+ marginHeight = margin.top + margin.bottom,
+ horz = config.orientation == 'horizontal',
+ fixedDim = (size[horz? 'height':'width'] - (horz? marginHeight:marginWidth) - (l -1) * config.barsOffset) / l,
+ animate = config.animate,
+ height = size[horz? 'width':'height'] - (horz? marginWidth:marginHeight)
+ - (!horz && config.showAggregates && (config.Label.size + config.labelOffset))
+ - (config.showLabels && (config.Label.size + config.labelOffset)),
+ dim1 = horz? 'height':'width',
+ dim2 = horz? 'width':'height';
+ this.delegate.graph.eachNode(function(n) {
+ var acum = 0, animateValue = [];
+ $.each(n.getData('valueArray'), function(v) {
+ acum += +v;
+ animateValue.push(0);
+ });
+ n.setData(dim1, fixedDim);
+ if(animate) {
+ n.setData(dim2, acum * height / maxValue, 'end');
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return n * height / maxValue;
+ }), 'end');
+ var dimArray = n.getData('dimArray');
+ if(!dimArray) {
+ n.setData('dimArray', animateValue);
+ }
+ } else {
+ n.setData(dim2, acum * height / maxValue);
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return n * height / maxValue;
+ }));
+ }
+ });
+ }
+});
+
+
+/*
+ * File: Options.PieChart.js
+ *
+*/
+/*
+ Object: Options.PieChart
+
+ <PieChart> options.
+ Other options included in the PieChart are <Options.Canvas>, <Options.Label>, <Options.Tips> and <Options.Events>.
+
+ Syntax:
+
+ (start code js)
+
+ Options.PieChart = {
+ animate: true,
+ offset: 25,
+ sliceOffset:0,
+ labelOffset: 3,
+ type: 'stacked',
+ hoveredColor: '#9fd4ff',
+ showLabels: true,
+ resizeLabels: false,
+ updateHeights: false
+ };
+
+ (end code)
+
+ Example:
+
+ (start code js)
+
+ var pie = new $jit.PieChart({
+ animate: true,
+ sliceOffset: 5,
+ type: 'stacked:gradient'
+ });
+
+ (end code)
+
+ Parameters:
+
+ animate - (boolean) Default's *true*. Whether to add animated transitions when plotting/updating the visualization.
+ offset - (number) Default's *25*. Adds margin between the visualization and the canvas.
+ sliceOffset - (number) Default's *0*. Separation between the center of the canvas and each pie slice.
+ labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.
+ type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients.
+ hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered pie stack.
+ showLabels - (boolean) Default's *true*. Display the name of the slots.
+ resizeLabels - (boolean|number) Default's *false*. Resize the pie labels according to their stacked values. Set a number for *resizeLabels* to set a font size minimum.
+ updateHeights - (boolean) Default's *false*. Only for mono-valued (most common) pie charts. Resize the height of the pie slices according to their current values.
+
+*/
+Options.PieChart = {
+ $extend: true,
+
+ animate: true,
+ offset: 25, // page offset
+ sliceOffset:0,
+ labelOffset: 3, // label offset
+ type: 'stacked', // gradient
+ hoveredColor: '#9fd4ff',
+ Events: {
+ enable: false,
+ onClick: $.empty
+ },
+ Tips: {
+ enable: false,
+ onShow: $.empty,
+ onHide: $.empty
+ },
+ showLabels: true,
+ resizeLabels: false,
+
+ //only valid for mono-valued datasets
+ updateHeights: false
+};
+
+/*
+ * Class: Layouts.Radial
+ *
+ * Implements a Radial Layout.
+ *
+ * Implemented By:
+ *
+ * <RGraph>, <Hypertree>
+ *
+ */
+Layouts.Radial = new Class({
+
+ /*
+ * Method: compute
+ *
+ * Computes nodes' positions.
+ *
+ * Parameters:
+ *
+ * property - _optional_ A <Graph.Node> position property to store the new
+ * positions. Possible values are 'pos', 'end' or 'start'.
+ *
+ */
+ compute : function(property) {
+ var prop = $.splat(property || [ 'current', 'start', 'end' ]);
+ NodeDim.compute(this.graph, prop, this.config);
+ this.graph.computeLevels(this.root, 0, "ignore");
+ var lengthFunc = this.createLevelDistanceFunc();
+ this.computeAngularWidths(prop);
+ this.computePositions(prop, lengthFunc);
+ },
+
+ /*
+ * computePositions
+ *
+ * Performs the main algorithm for computing node positions.
+ */
+ computePositions : function(property, getLength) {
+ var propArray = property;
+ var graph = this.graph;
+ var root = graph.getNode(this.root);
+ var parent = this.parent;
+ var config = this.config;
+
+ for ( var i=0, l=propArray.length; i < l; i++) {
+ var pi = propArray[i];
+ root.setPos($P(0, 0), pi);
+ root.setData('span', Math.PI * 2, pi);
+ }
+
+ root.angleSpan = {
+ begin : 0,
+ end : 2 * Math.PI
+ };
+
+ graph.eachBFS(this.root, function(elem) {
+ var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
+ var angleInit = elem.angleSpan.begin;
+ var len = getLength(elem);
+ //Calculate the sum of all angular widths
+ var totalAngularWidths = 0, subnodes = [], maxDim = {};
+ elem.eachSubnode(function(sib) {
+ totalAngularWidths += sib._treeAngularWidth;
+ //get max dim
+ for ( var i=0, l=propArray.length; i < l; i++) {
+ var pi = propArray[i], dim = sib.getData('dim', pi);
+ maxDim[pi] = (pi in maxDim)? (dim > maxDim[pi]? dim : maxDim[pi]) : dim;
+ }
+ subnodes.push(sib);
+ }, "ignore");
+ //Maintain children order
+ //Second constraint for <http://bailando.sims.berkeley.edu/papers/infovis01.htm>
+ if (parent && parent.id == elem.id && subnodes.length > 0
+ && subnodes[0].dist) {
+ subnodes.sort(function(a, b) {
+ return (a.dist >= b.dist) - (a.dist <= b.dist);
+ });
+ }
+ //Calculate nodes positions.
+ for (var k = 0, ls=subnodes.length; k < ls; k++) {
+ var child = subnodes[k];
+ if (!child._flag) {
+ var angleProportion = child._treeAngularWidth / totalAngularWidths * angleSpan;
+ var theta = angleInit + angleProportion / 2;
+
+ for ( var i=0, l=propArray.length; i < l; i++) {
+ var pi = propArray[i];
+ child.setPos($P(theta, len), pi);
+ child.setData('span', angleProportion, pi);
+ child.setData('dim-quotient', child.getData('dim', pi) / maxDim[pi], pi);
+ }
+
+ child.angleSpan = {
+ begin : angleInit,
+ end : angleInit + angleProportion
+ };
+ angleInit += angleProportion;
+ }
+ }
+ }, "ignore");
+ },
+
+ /*
+ * Method: setAngularWidthForNodes
+ *
+ * Sets nodes angular widths.
+ */
+ setAngularWidthForNodes : function(prop) {
+ this.graph.eachBFS(this.root, function(elem, i) {
+ var diamValue = elem.getData('angularWidth', prop[0]) || 5;
+ elem._angularWidth = diamValue / i;
+ }, "ignore");
+ },
+
+ /*
+ * Method: setSubtreesAngularWidth
+ *
+ * Sets subtrees angular widths.
+ */
+ setSubtreesAngularWidth : function() {
+ var that = this;
+ this.graph.eachNode(function(elem) {
+ that.setSubtreeAngularWidth(elem);
+ }, "ignore");
+ },
+
+ /*
+ * Method: setSubtreeAngularWidth
+ *
+ * Sets the angular width for a subtree.
+ */
+ setSubtreeAngularWidth : function(elem) {
+ var that = this, nodeAW = elem._angularWidth, sumAW = 0;
+ elem.eachSubnode(function(child) {
+ that.setSubtreeAngularWidth(child);
+ sumAW += child._treeAngularWidth;
+ }, "ignore");
+ elem._treeAngularWidth = Math.max(nodeAW, sumAW);
+ },
+
+ /*
+ * Method: computeAngularWidths
+ *
+ * Computes nodes and subtrees angular widths.
+ */
+ computeAngularWidths : function(prop) {
+ this.setAngularWidthForNodes(prop);
+ this.setSubtreesAngularWidth();
+ }
+
+});
+
+
+/*
+ * File: Sunburst.js
+ */
+
+/*
+ Class: Sunburst
+
+ A radial space filling tree visualization.
+
+ Inspired by:
+
+ Sunburst <http://www.cc.gatech.edu/gvu/ii/sunburst/>.
+
+ Note:
+
+ This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'.
+ levelDistance - (number) Default's *100*. The distance between levels of the tree.
+ Node.type - Described in <Options.Node>. Default's to *multipie*.
+ Node.height - Described in <Options.Node>. Default's *0*.
+ Edge.type - Described in <Options.Edge>. Default's *none*.
+ Label.textAlign - Described in <Options.Label>. Default's *start*.
+ Label.textBaseline - Described in <Options.Label>. Default's *middle*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <Sunburst.Op> instance.
+ fx - Access a <Sunburst.Plot> instance.
+ labels - Access a <Sunburst.Label> interface implementation.
+
+*/
+
+$jit.Sunburst = new Class({
+
+ Implements: [ Loader, Extras, Layouts.Radial ],
+
+ initialize: function(controller) {
+ var $Sunburst = $jit.Sunburst;
+
+ var config = {
+ interpolation: 'linear',
+ levelDistance: 100,
+ Node: {
+ 'type': 'multipie',
+ 'height':0
+ },
+ Edge: {
+ 'type': 'none'
+ },
+ Label: {
+ textAlign: 'start',
+ textBaseline: 'middle'
+ }
+ };
+
+ this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
+ "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
+
+ var canvasConfig = this.config;
+ if(canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Polar,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node,
+ this.config.Edge);
+ this.labels = new $Sunburst.Label[canvasConfig.Label.type](this);
+ this.fx = new $Sunburst.Plot(this, $Sunburst);
+ this.op = new $Sunburst.Op(this);
+ this.json = null;
+ this.root = null;
+ this.rotated = null;
+ this.busy = false;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+
+ createLevelDistanceFunc
+
+ Returns the levelDistance function used for calculating a node distance
+ to its origin. This function returns a function that is computed
+ per level and not per node, such that all nodes with the same depth will have the
+ same distance to the origin. The resulting function gets the
+ parent node as parameter and returns a float.
+
+ */
+ createLevelDistanceFunc: function() {
+ var ld = this.config.levelDistance;
+ return function(elem) {
+ return (elem._depth + 1) * ld;
+ };
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+
+ */
+ refresh: function() {
+ this.compute();
+ this.plot();
+ },
+
+ /*
+ reposition
+
+ An alias for computing new positions to _endPos_
+
+ See also:
+
+ <Sunburst.compute>
+
+ */
+ reposition: function() {
+ this.compute('end');
+ },
+
+ /*
+ Method: rotate
+
+ Rotates the graph so that the selected node is horizontal on the right.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ method - (string) Whether to perform an animation or just replot the graph. Possible values are "replot" or "animate".
+ opt - (object) Configuration options merged with this visualization configuration options.
+
+ See also:
+
+ <Sunburst.rotateAngle>
+
+ */
+ rotate: function(node, method, opt) {
+ var theta = node.getPos(opt.property || 'current').getp(true).theta;
+ this.rotated = node;
+ this.rotateAngle(-theta, method, opt);
+ },
+
+ /*
+ Method: rotateAngle
+
+ Rotates the graph of an angle theta.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+ method - (string) Whether to perform an animation or just replot the graph. Possible values are "replot" or "animate".
+ opt - (object) Configuration options merged with this visualization configuration options.
+
+ See also:
+
+ <Sunburst.rotate>
+
+ */
+ rotateAngle: function(theta, method, opt) {
+ var that = this;
+ var options = $.merge(this.config, opt || {}, {
+ modes: [ 'polar' ]
+ });
+ var prop = opt.property || (method === "animate" ? 'end' : 'current');
+ if(method === 'animate') {
+ this.fx.animation.pause();
+ }
+ this.graph.eachNode(function(n) {
+ var p = n.getPos(prop);
+ p.theta += theta;
+ if (p.theta < 0) {
+ p.theta += Math.PI * 2;
+ }
+ });
+ if (method == 'animate') {
+ this.fx.animate(options);
+ } else if (method == 'replot') {
+ this.fx.plot();
+ this.busy = false;
+ }
+ },
+
+ /*
+ Method: plot
+
+ Plots the Sunburst. This is a shortcut to *fx.plot*.
+ */
+ plot: function() {
+ this.fx.plot();
+ }
+});
+
+$jit.Sunburst.$extend = true;
+
+(function(Sunburst) {
+
+ /*
+ Class: Sunburst.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+ Sunburst.Op = new Class( {
+
+ Implements: Graph.Op
+
+ });
+
+ /*
+ Class: Sunburst.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+ Sunburst.Plot = new Class( {
+
+ Implements: Graph.Plot
+
+ });
+
+ /*
+ Class: Sunburst.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+ */
+ Sunburst.Label = {};
+
+ /*
+ Sunburst.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+ */
+ Sunburst.Label.Native = new Class( {
+ Implements: Graph.Label.Native,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ this.label = viz.config.Label;
+ this.config = viz.config;
+ },
+
+ renderLabel: function(canvas, node, controller) {
+ var span = node.getData('span');
+ if(span < Math.PI /2 && Math.tan(span) *
+ this.config.levelDistance * node._depth < 10) {
+ return;
+ }
+ var ctx = canvas.getCtx();
+ var measure = ctx.measureText(node.name);
+ if (node.id == this.viz.root) {
+ var x = -measure.width / 2, y = 0, thetap = 0;
+ var ld = 0;
+ } else {
+ var indent = 5;
+ var ld = controller.levelDistance - indent;
+ var clone = node.pos.clone();
+ clone.rho += indent;
+ var p = clone.getp(true);
+ var ct = clone.getc(true);
+ var x = ct.x, y = ct.y;
+ // get angle in degrees
+ var pi = Math.PI;
+ var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2);
+ var thetap = cond ? p.theta + pi : p.theta;
+ if (cond) {
+ x -= Math.abs(Math.cos(p.theta) * measure.width);
+ y += Math.sin(p.theta) * measure.width;
+ } else if (node.id == this.viz.root) {
+ x -= measure.width / 2;
+ }
+ }
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(thetap);
+ ctx.fillText(node.name, 0, 0);
+ ctx.restore();
+ }
+ });
+
+ /*
+ Sunburst.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+
+ */
+ Sunburst.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true), viz = this.viz, canvas = this.viz.canvas;
+ var radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x + radius.width / 2),
+ y: Math.round(pos.y + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+
+ var bb = tag.getBBox();
+ if (bb) {
+ // center the label
+ var x = tag.getAttribute('x');
+ var y = tag.getAttribute('y');
+ // get polar coordinates
+ var p = node.pos.getp(true);
+ // get angle in degrees
+ var pi = Math.PI;
+ var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2);
+ if (cond) {
+ tag.setAttribute('x', x - bb.width);
+ tag.setAttribute('y', y - bb.height);
+ } else if (node.id == viz.root) {
+ tag.setAttribute('x', x - bb.width / 2);
+ }
+
+ var thetap = cond ? p.theta + pi : p.theta;
+ if(node._depth)
+ tag.setAttribute('transform', 'rotate(' + thetap * 360 / (2 * pi) + ' ' + x
+ + ' ' + y + ')');
+ }
+
+ controller.onPlaceLabel(tag, node);
+}
+ });
+
+ /*
+ Sunburst.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+ */
+ Sunburst.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.clone(),
+ canvas = this.viz.canvas,
+ height = node.getData('height'),
+ ldist = ((height || node._depth == 0)? height : this.viz.config.levelDistance) /2,
+ radius = canvas.getSize();
+ pos.rho += ldist;
+ pos = pos.getc(true);
+
+ var labelPos = {
+ x: Math.round(pos.x + radius.width / 2),
+ y: Math.round(pos.y + radius.height / 2)
+ };
+
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ Class: Sunburst.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'pie', 'multipie', 'gradient-pie' and 'gradient-multipie'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ Sunburst.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ Sunburst.Plot.NodeTypes = new Class( {
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false),
+ 'anglecontains': function(node, pos) {
+ var span = node.getData('span') / 2, theta = node.pos.theta;
+ var begin = theta - span, end = theta + span;
+ if (begin < 0)
+ begin += Math.PI * 2;
+ var atan = Math.atan2(pos.y, pos.x);
+ if (atan < 0)
+ atan += Math.PI * 2;
+ if (begin > end) {
+ return (atan > begin && atan <= Math.PI * 2) || atan < end;
+ } else {
+ return atan > begin && atan < end;
+ }
+ }
+ },
+
+ 'pie': {
+ 'render': function(node, canvas) {
+ var span = node.getData('span') / 2, theta = node.pos.theta;
+ var begin = theta - span, end = theta + span;
+ var polarNode = node.pos.getp(true);
+ var polar = new Polar(polarNode.rho, begin);
+ var p1coord = polar.getc(true);
+ polar.theta = end;
+ var p2coord = polar.getc(true);
+
+ var ctx = canvas.getCtx();
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(p1coord.x, p1coord.y);
+ ctx.moveTo(0, 0);
+ ctx.lineTo(p2coord.x, p2coord.y);
+ ctx.moveTo(0, 0);
+ ctx.arc(0, 0, polarNode.rho * node.getData('dim-quotient'), begin, end,
+ false);
+ ctx.fill();
+ },
+ 'contains': function(node, pos) {
+ if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {
+ var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
+ var ld = this.config.levelDistance, d = node._depth;
+ return (rho <= ld * d);
+ }
+ return false;
+ }
+ },
+ 'multipie': {
+ 'render': function(node, canvas) {
+ var height = node.getData('height');
+ var ldist = height? height : this.config.levelDistance;
+ var span = node.getData('span') / 2, theta = node.pos.theta;
+ var begin = theta - span, end = theta + span;
+ var polarNode = node.pos.getp(true);
+
+ var polar = new Polar(polarNode.rho, begin);
+ var p1coord = polar.getc(true);
+
+ polar.theta = end;
+ var p2coord = polar.getc(true);
+
+ polar.rho += ldist;
+ var p3coord = polar.getc(true);
+
+ polar.theta = begin;
+ var p4coord = polar.getc(true);
+
+ var ctx = canvas.getCtx();
+ ctx.moveTo(0, 0);
+ ctx.beginPath();
+ ctx.arc(0, 0, polarNode.rho, begin, end, false);
+ ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true);
+ ctx.moveTo(p1coord.x, p1coord.y);
+ ctx.lineTo(p4coord.x, p4coord.y);
+ ctx.moveTo(p2coord.x, p2coord.y);
+ ctx.lineTo(p3coord.x, p3coord.y);
+ ctx.fill();
+
+ if (node.collapsed) {
+ ctx.save();
+ ctx.lineWidth = 2;
+ ctx.moveTo(0, 0);
+ ctx.beginPath();
+ ctx.arc(0, 0, polarNode.rho + ldist + 5, end - 0.01, begin + 0.01,
+ true);
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ 'contains': function(node, pos) {
+ if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {
+ var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
+ var height = node.getData('height');
+ var ldist = height? height : this.config.levelDistance;
+ var ld = this.config.levelDistance, d = node._depth;
+ return (rho >= ld * d) && (rho <= (ld * d + ldist));
+ }
+ return false;
+ }
+ },
+
+ 'gradient-multipie': {
+ 'render': function(node, canvas) {
+ var ctx = canvas.getCtx();
+ var height = node.getData('height');
+ var ldist = height? height : this.config.levelDistance;
+ var radialGradient = ctx.createRadialGradient(0, 0, node.getPos().rho,
+ 0, 0, node.getPos().rho + ldist);
+
+ var colorArray = $.hexToRgb(node.getData('color')), ans = [];
+ $.each(colorArray, function(i) {
+ ans.push(parseInt(i * 0.5, 10));
+ });
+ var endColor = $.rgbToHex(ans);
+ radialGradient.addColorStop(0, endColor);
+ radialGradient.addColorStop(1, node.getData('color'));
+ ctx.fillStyle = radialGradient;
+ this.nodeTypes['multipie'].render.call(this, node, canvas);
+ },
+ 'contains': function(node, pos) {
+ return this.nodeTypes['multipie'].contains.call(this, node, pos);
+ }
+ },
+
+ 'gradient-pie': {
+ 'render': function(node, canvas) {
+ var ctx = canvas.getCtx();
+ var radialGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, node
+ .getPos().rho);
+
+ var colorArray = $.hexToRgb(node.getData('color')), ans = [];
+ $.each(colorArray, function(i) {
+ ans.push(parseInt(i * 0.5, 10));
+ });
+ var endColor = $.rgbToHex(ans);
+ radialGradient.addColorStop(1, endColor);
+ radialGradient.addColorStop(0, node.getData('color'));
+ ctx.fillStyle = radialGradient;
+ this.nodeTypes['pie'].render.call(this, node, canvas);
+ },
+ 'contains': function(node, pos) {
+ return this.nodeTypes['pie'].contains.call(this, node, pos);
+ }
+ }
+ });
+
+ /*
+ Class: Sunburst.Plot.EdgeTypes
+
+ This class contains a list of <Graph.Adjacence> built-in types.
+ Edge types implemented are 'none', 'line' and 'arrow'.
+
+ You can add your custom edge types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ Sunburst.Plot.EdgeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(adj, canvas) {
+ //print your custom edge to canvas
+ },
+ //optional
+ 'contains': function(adj, pos) {
+ //return true if pos is inside the arc or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ Sunburst.Plot.EdgeTypes = new Class({
+ 'none': $.empty,
+ 'line': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ this.edgeHelper.line.render(from, to, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'arrow': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ dim = adj.getData('dim'),
+ direction = adj.data.$direction,
+ inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);
+ this.edgeHelper.arrow.render(from, to, dim, inv, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'hyperline': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(),
+ to = adj.nodeTo.pos.getc(),
+ dim = Math.max(from.norm(), to.norm());
+ this.edgeHelper.hyperline.render(from.$scale(1/dim), to.$scale(1/dim), dim, canvas);
+ },
+ 'contains': $.lambda(false) //TODO(nico): Implement this!
+ }
+ });
+
+})($jit.Sunburst);
+
+
+/*
+ * File: PieChart.js
+ *
+*/
+
+$jit.Sunburst.Plot.NodeTypes.implement({
+ 'piechart-stacked' : {
+ 'render' : function(node, canvas) {
+ var pos = node.pos.getp(true),
+ dimArray = node.getData('dimArray'),
+ valueArray = node.getData('valueArray'),
+ colorArray = node.getData('colorArray'),
+ colorLength = colorArray.length,
+ stringArray = node.getData('stringArray'),
+ span = node.getData('span') / 2,
+ theta = node.pos.theta,
+ begin = theta - span,
+ end = theta + span,
+ polar = new Polar;
+
+ var ctx = canvas.getCtx(),
+ opt = {},
+ gradient = node.getData('gradient'),
+ border = node.getData('border'),
+ config = node.getData('config'),
+ showLabels = config.showLabels,
+ resizeLabels = config.resizeLabels,
+ label = config.Label;
+
+ var xpos = config.sliceOffset * Math.cos((begin + end) /2);
+ var ypos = config.sliceOffset * Math.sin((begin + end) /2);
+
+ if (colorArray && dimArray && stringArray) {
+ for (var i=0, l=dimArray.length, acum=0, valAcum=0; i<l; i++) {
+ var dimi = dimArray[i], colori = colorArray[i % colorLength];
+ if(dimi <= 0) continue;
+ ctx.fillStyle = ctx.strokeStyle = colori;
+ if(gradient && dimi) {
+ var radialGradient = ctx.createRadialGradient(xpos, ypos, acum + config.sliceOffset,
+ xpos, ypos, acum + dimi + config.sliceOffset);
+ var colorRgb = $.hexToRgb(colori),
+ ans = $.map(colorRgb, function(i) { return (i * 0.8) >> 0; }),
+ endColor = $.rgbToHex(ans);
+
+ radialGradient.addColorStop(0, colori);
+ radialGradient.addColorStop(0.5, colori);
+ radialGradient.addColorStop(1, endColor);
+ ctx.fillStyle = radialGradient;
+ }
+
+ polar.rho = acum + config.sliceOffset;
+ polar.theta = begin;
+ var p1coord = polar.getc(true);
+ polar.theta = end;
+ var p2coord = polar.getc(true);
+ polar.rho += dimi;
+ var p3coord = polar.getc(true);
+ polar.theta = begin;
+ var p4coord = polar.getc(true);
+
+ ctx.beginPath();
+ //fixing FF arc method + fill
+ ctx.arc(xpos, ypos, acum + .01, begin, end, false);
+ ctx.arc(xpos, ypos, acum + dimi + .01, end, begin, true);
+ ctx.fill();
+ if(border && border.name == stringArray[i]) {
+ opt.acum = acum;
+ opt.dimValue = dimArray[i];
+ opt.begin = begin;
+ opt.end = end;
+ }
+ acum += (dimi || 0);
+ valAcum += (valueArray[i] || 0);
+ }
+ if(border) {
+ ctx.save();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = border.color;
+ var s = begin < end? 1 : -1;
+ ctx.beginPath();
+ //fixing FF arc method + fill
+ ctx.arc(xpos, ypos, opt.acum + .01 + 1, opt.begin, opt.end, false);
+ ctx.arc(xpos, ypos, opt.acum + opt.dimValue + .01 - 1, opt.end, opt.begin, true);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore();
+ }
+ if(showLabels && label.type == 'Native') {
+ ctx.save();
+ ctx.fillStyle = ctx.strokeStyle = label.color;
+ var scale = resizeLabels? node.getData('normalizedDim') : 1,
+ fontSize = (label.size * scale) >> 0;
+ fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize;
+
+ ctx.font = label.style + ' ' + fontSize + 'px ' + label.family;
+ ctx.textBaseline = 'middle';
+ ctx.textAlign = 'center';
+
+ polar.rho = acum + config.labelOffset + config.sliceOffset;
+ polar.theta = node.pos.theta;
+ var cart = polar.getc(true);
+
+ ctx.fillText(node.name, cart.x, cart.y);
+ ctx.restore();
+ }
+ }
+ },
+ 'contains': function(node, pos) {
+ if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {
+ var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
+ var ld = this.config.levelDistance, d = node._depth;
+ var config = node.getData('config');
+ if(rho <=ld * d + config.sliceOffset) {
+ var dimArray = node.getData('dimArray');
+ for(var i=0,l=dimArray.length,acum=config.sliceOffset; i<l; i++) {
+ var dimi = dimArray[i];
+ if(rho >= acum && rho <= acum + dimi) {
+ return {
+ name: node.getData('stringArray')[i],
+ color: node.getData('colorArray')[i],
+ value: node.getData('valueArray')[i],
+ label: node.name
+ };
+ }
+ acum += dimi;
+ }
+ }
+ return false;
+
+ }
+ return false;
+ }
+ }
+});
+
+/*
+ Class: PieChart
+
+ A visualization that displays stacked bar charts.
+
+ Constructor Options:
+
+ See <Options.PieChart>.
+
+*/
+$jit.PieChart = new Class({
+ sb: null,
+ colors: ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
+ selected: {},
+ busy: false,
+
+ initialize: function(opt) {
+ this.controller = this.config =
+ $.merge(Options("Canvas", "PieChart", "Label"), {
+ Label: { type: 'Native' }
+ }, opt);
+ this.initializeViz();
+ },
+
+ initializeViz: function() {
+ var config = this.config, that = this;
+ var nodeType = config.type.split(":")[0];
+ var delegate = new $jit.Sunburst({
+ injectInto: config.injectInto,
+ width: config.width,
+ height: config.height,
+ useCanvas: config.useCanvas,
+ withLabels: config.Label.type != 'Native',
+ Label: {
+ type: config.Label.type
+ },
+ Node: {
+ overridable: true,
+ type: 'piechart-' + nodeType,
+ width: 1,
+ height: 1
+ },
+ Edge: {
+ type: 'none'
+ },
+ Tips: {
+ enable: config.Tips.enable,
+ type: 'Native',
+ force: true,
+ onShow: function(tip, node, contains) {
+ var elem = contains;
+ config.Tips.onShow(tip, elem, node);
+ }
+ },
+ Events: {
+ enable: true,
+ type: 'Native',
+ onClick: function(node, eventInfo, evt) {
+ if(!config.Events.enable) return;
+ var elem = eventInfo.getContains();
+ config.Events.onClick(elem, eventInfo, evt);
+ },
+ onMouseMove: function(node, eventInfo, evt) {
+ if(!config.hoveredColor) return;
+ if(node) {
+ var elem = eventInfo.getContains();
+ that.select(node.id, elem.name, elem.index);
+ } else {
+ that.select(false, false, false);
+ }
+ }
+ },
+ onCreateLabel: function(domElement, node) {
+ var labelConf = config.Label;
+ if(config.showLabels) {
+ var style = domElement.style;
+ style.fontSize = labelConf.size + 'px';
+ style.fontFamily = labelConf.family;
+ style.color = labelConf.color;
+ style.textAlign = 'center';
+ domElement.innerHTML = node.name;
+ }
+ },
+ onPlaceLabel: function(domElement, node) {
+ if(!config.showLabels) return;
+ var pos = node.pos.getp(true),
+ dimArray = node.getData('dimArray'),
+ span = node.getData('span') / 2,
+ theta = node.pos.theta,
+ begin = theta - span,
+ end = theta + span,
+ polar = new Polar;
+
+ var showLabels = config.showLabels,
+ resizeLabels = config.resizeLabels,
+ label = config.Label;
+
+ if (dimArray) {
+ for (var i=0, l=dimArray.length, acum=0; i<l; i++) {
+ acum += dimArray[i];
+ }
+ var scale = resizeLabels? node.getData('normalizedDim') : 1,
+ fontSize = (label.size * scale) >> 0;
+ fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize;
+ domElement.style.fontSize = fontSize + 'px';
+ polar.rho = acum + config.labelOffset + config.sliceOffset;
+ polar.theta = (begin + end) / 2;
+ var pos = polar.getc(true);
+ var radius = that.canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x + radius.width / 2),
+ y: Math.round(pos.y + radius.height / 2)
+ };
+ domElement.style.left = labelPos.x + 'px';
+ domElement.style.top = labelPos.y + 'px';
+ }
+ }
+ });
+
+ var size = delegate.canvas.getSize(),
+ min = Math.min;
+ delegate.config.levelDistance = min(size.width, size.height)/2
+ - config.offset - config.sliceOffset;
+ this.delegate = delegate;
+ this.canvas = this.delegate.canvas;
+ this.canvas.getCtx().globalCompositeOperation = 'lighter';
+ },
+
+ /*
+ Method: loadJSON
+
+ Loads JSON data into the visualization.
+
+ Parameters:
+
+ json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.
+
+ Example:
+ (start code js)
+ var pieChart = new $jit.PieChart(options);
+ pieChart.loadJSON(json);
+ (end code)
+ */
+ loadJSON: function(json) {
+ var prefix = $.time(),
+ ch = [],
+ delegate = this.delegate,
+ name = $.splat(json.label),
+ nameLength = name.length,
+ color = $.splat(json.color || this.colors),
+ colorLength = color.length,
+ config = this.config,
+ gradient = !!config.type.split(":")[1],
+ animate = config.animate,
+ mono = nameLength == 1;
+
+ for(var i=0, values=json.values, l=values.length; i<l; i++) {
+ var val = values[i];
+ var valArray = $.splat(val.values);
+ ch.push({
+ 'id': prefix + val.label,
+ 'name': val.label,
+ 'data': {
+ 'value': valArray,
+ '$valueArray': valArray,
+ '$colorArray': mono? $.splat(color[i % colorLength]) : color,
+ '$stringArray': name,
+ '$gradient': gradient,
+ '$config': config,
+ '$angularWidth': $.reduce(valArray, function(x,y){return x+y;})
+ },
+ 'children': []
+ });
+ }
+ var root = {
+ 'id': prefix + '$root',
+ 'name': '',
+ 'data': {
+ '$type': 'none',
+ '$width': 1,
+ '$height': 1
+ },
+ 'children': ch
+ };
+ delegate.loadJSON(root);
+
+ this.normalizeDims();
+ delegate.refresh();
+ if(animate) {
+ delegate.fx.animate({
+ modes: ['node-property:dimArray'],
+ duration:1500
+ });
+ }
+ },
+
+ /*
+ Method: updateJSON
+
+ Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.
+
+ Parameters:
+
+ json - (object) JSON data to be updated. The JSON format corresponds to the one described in <PieChart.loadJSON>.
+ onComplete - (object) A callback object to be called when the animation transition when updating the data end.
+
+ Example:
+
+ (start code js)
+ pieChart.updateJSON(json, {
+ onComplete: function() {
+ alert('update complete!');
+ }
+ });
+ (end code)
+ */
+ updateJSON: function(json, onComplete) {
+ if(this.busy) return;
+ this.busy = true;
+
+ var delegate = this.delegate;
+ var graph = delegate.graph;
+ var values = json.values;
+ var animate = this.config.animate;
+ var that = this;
+ $.each(values, function(v) {
+ var n = graph.getByName(v.label),
+ vals = $.splat(v.values);
+ if(n) {
+ n.setData('valueArray', vals);
+ n.setData('angularWidth', $.reduce(vals, function(x,y){return x+y;}));
+ if(json.label) {
+ n.setData('stringArray', $.splat(json.label));
+ }
+ }
+ });
+ this.normalizeDims();
+ if(animate) {
+ delegate.compute('end');
+ delegate.fx.animate({
+ modes: ['node-property:dimArray:span', 'linear'],
+ duration:1500,
+ onComplete: function() {
+ that.busy = false;
+ onComplete && onComplete.onComplete();
+ }
+ });
+ } else {
+ delegate.refresh();
+ }
+ },
+
+ //adds the little brown bar when hovering the node
+ select: function(id, name) {
+ if(!this.config.hoveredColor) return;
+ var s = this.selected;
+ if(s.id != id || s.name != name) {
+ s.id = id;
+ s.name = name;
+ s.color = this.config.hoveredColor;
+ this.delegate.graph.eachNode(function(n) {
+ if(id == n.id) {
+ n.setData('border', s);
+ } else {
+ n.setData('border', false);
+ }
+ });
+ this.delegate.plot();
+ }
+ },
+
+ /*
+ Method: getLegend
+
+ Returns an object containing as keys the legend names and as values hex strings with color values.
+
+ Example:
+
+ (start code js)
+ var legend = pieChart.getLegend();
+ (end code)
+ */
+ getLegend: function() {
+ var legend = {};
+ var n;
+ this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
+ n = adj.nodeTo;
+ });
+ var colors = n.getData('colorArray'),
+ len = colors.length;
+ $.each(n.getData('stringArray'), function(s, i) {
+ legend[s] = colors[i % len];
+ });
+ return legend;
+ },
+
+ /*
+ Method: getMaxValue
+
+ Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.
+
+ Example:
+
+ (start code js)
+ var ans = pieChart.getMaxValue();
+ (end code)
+
+ In some cases it could be useful to override this method to normalize heights for a group of PieCharts, like when doing small multiples.
+
+ Example:
+
+ (start code js)
+ //will return 100 for all PieChart instances,
+ //displaying all of them with the same scale
+ $jit.PieChart.implement({
+ 'getMaxValue': function() {
+ return 100;
+ }
+ });
+ (end code)
+
+ */
+ getMaxValue: function() {
+ var maxValue = 0;
+ this.delegate.graph.eachNode(function(n) {
+ var valArray = n.getData('valueArray'),
+ acum = 0;
+ $.each(valArray, function(v) {
+ acum += +v;
+ });
+ maxValue = maxValue>acum? maxValue:acum;
+ });
+ return maxValue;
+ },
+
+ normalizeDims: function() {
+ //number of elements
+ var root = this.delegate.graph.getNode(this.delegate.root), l=0;
+ root.eachAdjacency(function() {
+ l++;
+ });
+ var maxValue = this.getMaxValue() || 1,
+ config = this.config,
+ animate = config.animate,
+ rho = this.delegate.config.levelDistance;
+ this.delegate.graph.eachNode(function(n) {
+ var acum = 0, animateValue = [];
+ $.each(n.getData('valueArray'), function(v) {
+ acum += +v;
+ animateValue.push(1);
+ });
+ var stat = (animateValue.length == 1) && !config.updateHeights;
+ if(animate) {
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return stat? rho: (n * rho / maxValue);
+ }), 'end');
+ var dimArray = n.getData('dimArray');
+ if(!dimArray) {
+ n.setData('dimArray', animateValue);
+ }
+ } else {
+ n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {
+ return stat? rho : (n * rho / maxValue);
+ }));
+ }
+ n.setData('normalizedDim', acum / maxValue);
+ });
+ }
+});
+
+
+/*
+ * Class: Layouts.TM
+ *
+ * Implements TreeMaps layouts (SliceAndDice, Squarified, Strip).
+ *
+ * Implemented By:
+ *
+ * <TM>
+ *
+ */
+Layouts.TM = {};
+
+Layouts.TM.SliceAndDice = new Class({
+ compute: function(prop) {
+ var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
+ this.controller.onBeforeCompute(root);
+ var size = this.canvas.getSize(),
+ config = this.config,
+ width = size.width,
+ height = size.height;
+ this.graph.computeLevels(this.root, 0, "ignore");
+ //set root position and dimensions
+ root.getPos(prop).setc(-width/2, -height/2);
+ root.setData('width', width, prop);
+ root.setData('height', height + config.titleHeight, prop);
+ this.computePositions(root, root, this.layout.orientation, prop);
+ this.controller.onAfterCompute(root);
+ },
+
+ computePositions: function(par, ch, orn, prop) {
+ //compute children areas
+ var totalArea = 0;
+ par.eachSubnode(function(n) {
+ totalArea += n.getData('area', prop);
+ });
+
+ var config = this.config,
+ offst = config.offset,
+ width = par.getData('width', prop),
+ height = Math.max(par.getData('height', prop) - config.titleHeight, 0),
+ fact = par == ch? 1 : (ch.getData('area', prop) / totalArea);
+
+ var otherSize, size, dim, pos, pos2, posth, pos2th;
+ var horizontal = (orn == "h");
+ if(horizontal) {
+ orn = 'v';
+ otherSize = height;
+ size = width * fact;
+ dim = 'height';
+ pos = 'y';
+ pos2 = 'x';
+ posth = config.titleHeight;
+ pos2th = 0;
+ } else {
+ orn = 'h';
+ otherSize = height * fact;
+ size = width;
+ dim = 'width';
+ pos = 'x';
+ pos2 = 'y';
+ posth = 0;
+ pos2th = config.titleHeight;
+ }
+ var cpos = ch.getPos(prop);
+ ch.setData('width', size, prop);
+ ch.setData('height', otherSize, prop);
+ var offsetSize = 0, tm = this;
+ ch.eachSubnode(function(n) {
+ var p = n.getPos(prop);
+ p[pos] = offsetSize + cpos[pos] + posth;
+ p[pos2] = cpos[pos2] + pos2th;
+ tm.computePositions(ch, n, orn, prop);
+ offsetSize += n.getData(dim, prop);
+ });
+ }
+
+});
+
+Layouts.TM.Area = {
+ /*
+ Method: compute
+
+ Called by loadJSON to calculate recursively all node positions and lay out the tree.
+
+ Parameters:
+
+ json - A JSON tree. See also <Loader.loadJSON>.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ compute: function(prop) {
+ prop = prop || "current";
+ var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
+ this.controller.onBeforeCompute(root);
+ var config = this.config,
+ size = this.canvas.getSize(),
+ width = size.width,
+ height = size.height,
+ offst = config.offset,
+ offwdth = width - offst,
+ offhght = height - offst;
+ this.graph.computeLevels(this.root, 0, "ignore");
+ //set root position and dimensions
+ root.getPos(prop).setc(-width/2, -height/2);
+ root.setData('width', width, prop);
+ root.setData('height', height, prop);
+ //create a coordinates object
+ var coord = {
+ 'top': -height/2 + config.titleHeight,
+ 'left': -width/2,
+ 'width': offwdth,
+ 'height': offhght - config.titleHeight
+ };
+ this.computePositions(root, coord, prop);
+ this.controller.onAfterCompute(root);
+ },
+
+ /*
+ Method: computeDim
+
+ Computes dimensions and positions of a group of nodes
+ according to a custom layout row condition.
+
+ Parameters:
+
+ tail - An array of nodes.
+ initElem - An array of nodes (containing the initial node to be laid).
+ w - A fixed dimension where nodes will be layed out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ comp - A custom comparison function
+ */
+ computeDim: function(tail, initElem, w, coord, comp, prop) {
+ if(tail.length + initElem.length == 1) {
+ var l = (tail.length == 1)? tail : initElem;
+ this.layoutLast(l, w, coord, prop);
+ return;
+ }
+ if(tail.length >= 2 && initElem.length == 0) {
+ initElem = [tail.shift()];
+ }
+ if(tail.length == 0) {
+ if(initElem.length > 0) this.layoutRow(initElem, w, coord, prop);
+ return;
+ }
+ var c = tail[0];
+ if(comp(initElem, w) >= comp([c].concat(initElem), w)) {
+ this.computeDim(tail.slice(1), initElem.concat([c]), w, coord, comp, prop);
+ } else {
+ var newCoords = this.layoutRow(initElem, w, coord, prop);
+ this.computeDim(tail, [], newCoords.dim, newCoords, comp, prop);
+ }
+ },
+
+
+ /*
+ Method: worstAspectRatio
+
+ Calculates the worst aspect ratio of a group of rectangles.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Aspect_ratio>
+
+ Parameters:
+
+ ch - An array of nodes.
+ w - The fixed dimension where rectangles are being laid out.
+
+ Returns:
+
+ The worst aspect ratio.
+
+
+ */
+ worstAspectRatio: function(ch, w) {
+ if(!ch || ch.length == 0) return Number.MAX_VALUE;
+ var areaSum = 0, maxArea = 0, minArea = Number.MAX_VALUE;
+ for(var i=0, l=ch.length; i<l; i++) {
+ var area = ch[i]._area;
+ areaSum += area;
+ minArea = minArea < area? minArea : area;
+ maxArea = maxArea > area? maxArea : area;
+ }
+ var sqw = w * w, sqAreaSum = areaSum * areaSum;
+ return Math.max(sqw * maxArea / sqAreaSum,
+ sqAreaSum / (sqw * minArea));
+ },
+
+ /*
+ Method: avgAspectRatio
+
+ Calculates the average aspect ratio of a group of rectangles.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Aspect_ratio>
+
+ Parameters:
+
+ ch - An array of nodes.
+ w - The fixed dimension where rectangles are being laid out.
+
+ Returns:
+
+ The average aspect ratio.
+
+
+ */
+ avgAspectRatio: function(ch, w) {
+ if(!ch || ch.length == 0) return Number.MAX_VALUE;
+ var arSum = 0;
+ for(var i=0, l=ch.length; i<l; i++) {
+ var area = ch[i]._area;
+ var h = area / w;
+ arSum += w > h? w / h : h / w;
+ }
+ return arSum / l;
+ },
+
+ /*
+ layoutLast
+
+ Performs the layout of the last computed sibling.
+
+ Parameters:
+
+ ch - An array of nodes.
+ w - A fixed dimension where nodes will be layed out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ layoutLast: function(ch, w, coord, prop) {
+ var child = ch[0];
+ child.getPos(prop).setc(coord.left, coord.top);
+ child.setData('width', coord.width, prop);
+ child.setData('height', coord.height, prop);
+ }
+};
+
+
+Layouts.TM.Squarified = new Class({
+ Implements: Layouts.TM.Area,
+
+ computePositions: function(node, coord, prop) {
+ var config = this.config,
+ max = Math.max;
+
+ if (coord.width >= coord.height)
+ this.layout.orientation = 'h';
+ else
+ this.layout.orientation = 'v';
+
+ var ch = node.getSubnodes([1, 1], "ignore");
+ if(ch.length > 0) {
+ this.processChildrenLayout(node, ch, coord, prop);
+ for(var i=0, l=ch.length; i<l; i++) {
+ var chi = ch[i],
+ offst = config.offset,
+ height = max(chi.getData('height', prop) - offst - config.titleHeight, 0),
+ width = max(chi.getData('width', prop) - offst, 0),
+ chipos = chi.getPos(prop);
+
+ coord = {
+ 'width': width,
+ 'height': height,
+ 'top': chipos.y + config.titleHeight,
+ 'left': chipos.x
+ };
+ this.computePositions(chi, coord, prop);
+ }
+ }
+ },
+
+ /*
+ Method: processChildrenLayout
+
+ Computes children real areas and other useful parameters for performing the Squarified algorithm.
+
+ Parameters:
+
+ par - The parent node of the json subtree.
+ ch - An Array of nodes
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ processChildrenLayout: function(par, ch, coord, prop) {
+ //compute children real areas
+ var parentArea = coord.width * coord.height;
+ var i, l=ch.length, totalChArea=0, chArea = [];
+ for(i=0; i<l; i++) {
+ chArea[i] = parseFloat(ch[i].getData('area', prop));
+ totalChArea += chArea[i];
+ }
+ for(i=0; i<l; i++) {
+ ch[i]._area = parentArea * chArea[i] / totalChArea;
+ }
+ var minimumSideValue = this.layout.horizontal()? coord.height : coord.width;
+ ch.sort(function(a, b) {
+ var diff = b._area - a._area;
+ return diff? diff : (b.id == a.id? 0 : (b.id < a.id? 1 : -1));
+ });
+ var initElem = [ch[0]];
+ var tail = ch.slice(1);
+ this.squarify(tail, initElem, minimumSideValue, coord, prop);
+ },
+
+ /*
+ Method: squarify
+
+ Performs an heuristic method to calculate div elements sizes in order to have a good aspect ratio.
+
+ Parameters:
+
+ tail - An array of nodes.
+ initElem - An array of nodes, containing the initial node to be laid out.
+ w - A fixed dimension where nodes will be laid out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ squarify: function(tail, initElem, w, coord, prop) {
+ this.computeDim(tail, initElem, w, coord, this.worstAspectRatio, prop);
+ },
+
+ /*
+ Method: layoutRow
+
+ Performs the layout of an array of nodes.
+
+ Parameters:
+
+ ch - An array of nodes.
+ w - A fixed dimension where nodes will be laid out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ layoutRow: function(ch, w, coord, prop) {
+ if(this.layout.horizontal()) {
+ return this.layoutV(ch, w, coord, prop);
+ } else {
+ return this.layoutH(ch, w, coord, prop);
+ }
+ },
+
+ layoutV: function(ch, w, coord, prop) {
+ var totalArea = 0, rnd = function(x) { return x; };
+ $.each(ch, function(elem) { totalArea += elem._area; });
+ var width = rnd(totalArea / w), top = 0;
+ for(var i=0, l=ch.length; i<l; i++) {
+ var h = rnd(ch[i]._area / width);
+ var chi = ch[i];
+ chi.getPos(prop).setc(coord.left, coord.top + top);
+ chi.setData('width', width, prop);
+ chi.setData('height', h, prop);
+ top += h;
+ }
+ var ans = {
+ 'height': coord.height,
+ 'width': coord.width - width,
+ 'top': coord.top,
+ 'left': coord.left + width
+ };
+ //take minimum side value.
+ ans.dim = Math.min(ans.width, ans.height);
+ if(ans.dim != ans.height) this.layout.change();
+ return ans;
+ },
+
+ layoutH: function(ch, w, coord, prop) {
+ var totalArea = 0;
+ $.each(ch, function(elem) { totalArea += elem._area; });
+ var height = totalArea / w,
+ top = coord.top,
+ left = 0;
+
+ for(var i=0, l=ch.length; i<l; i++) {
+ var chi = ch[i];
+ var w = chi._area / height;
+ chi.getPos(prop).setc(coord.left + left, top);
+ chi.setData('width', w, prop);
+ chi.setData('height', height, prop);
+ left += w;
+ }
+ var ans = {
+ 'height': coord.height - height,
+ 'width': coord.width,
+ 'top': coord.top + height,
+ 'left': coord.left
+ };
+ ans.dim = Math.min(ans.width, ans.height);
+ if(ans.dim != ans.width) this.layout.change();
+ return ans;
+ }
+});
+
+Layouts.TM.Strip = new Class({
+ Implements: Layouts.TM.Area,
+
+ /*
+ Method: compute
+
+ Called by loadJSON to calculate recursively all node positions and lay out the tree.
+
+ Parameters:
+
+ json - A JSON subtree. See also <Loader.loadJSON>.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ computePositions: function(node, coord, prop) {
+ var ch = node.getSubnodes([1, 1], "ignore"),
+ config = this.config,
+ max = Math.max;
+ if(ch.length > 0) {
+ this.processChildrenLayout(node, ch, coord, prop);
+ for(var i=0, l=ch.length; i<l; i++) {
+ var chi = ch[i];
+ var offst = config.offset,
+ height = max(chi.getData('height', prop) - offst - config.titleHeight, 0),
+ width = max(chi.getData('width', prop) - offst, 0);
+ var chipos = chi.getPos(prop);
+ coord = {
+ 'width': width,
+ 'height': height,
+ 'top': chipos.y + config.titleHeight,
+ 'left': chipos.x
+ };
+ this.computePositions(chi, coord, prop);
+ }
+ }
+ },
+
+ /*
+ Method: processChildrenLayout
+
+ Computes children real areas and other useful parameters for performing the Strip algorithm.
+
+ Parameters:
+
+ par - The parent node of the json subtree.
+ ch - An Array of nodes
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ processChildrenLayout: function(par, ch, coord, prop) {
+ //compute children real areas
+ var parentArea = coord.width * coord.height;
+ var i, l=ch.length, totalChArea=0, chArea = [];
+ for(i=0; i<l; i++) {
+ chArea[i] = +ch[i].getData('area', prop);
+ totalChArea += chArea[i];
+ }
+ for(i=0; i<l; i++) {
+ ch[i]._area = parentArea * chArea[i] / totalChArea;
+ }
+ var side = this.layout.horizontal()? coord.width : coord.height;
+ var initElem = [ch[0]];
+ var tail = ch.slice(1);
+ this.stripify(tail, initElem, side, coord, prop);
+ },
+
+ /*
+ Method: stripify
+
+ Performs an heuristic method to calculate div elements sizes in order to have
+ a good compromise between aspect ratio and order.
+
+ Parameters:
+
+ tail - An array of nodes.
+ initElem - An array of nodes.
+ w - A fixed dimension where nodes will be layed out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ stripify: function(tail, initElem, w, coord, prop) {
+ this.computeDim(tail, initElem, w, coord, this.avgAspectRatio, prop);
+ },
+
+ /*
+ Method: layoutRow
+
+ Performs the layout of an array of nodes.
+
+ Parameters:
+
+ ch - An array of nodes.
+ w - A fixed dimension where nodes will be laid out.
+ coord - A coordinates object specifying width, height, left and top style properties.
+ */
+ layoutRow: function(ch, w, coord, prop) {
+ if(this.layout.horizontal()) {
+ return this.layoutH(ch, w, coord, prop);
+ } else {
+ return this.layoutV(ch, w, coord, prop);
+ }
+ },
+
+ layoutV: function(ch, w, coord, prop) {
+ var totalArea = 0;
+ $.each(ch, function(elem) { totalArea += elem._area; });
+ var width = totalArea / w, top = 0;
+ for(var i=0, l=ch.length; i<l; i++) {
+ var chi = ch[i];
+ var h = chi._area / width;
+ chi.getPos(prop).setc(coord.left,
+ coord.top + (w - h - top));
+ chi.setData('width', width, prop);
+ chi.setData('height', h, prop);
+ top += h;
+ }
+
+ return {
+ 'height': coord.height,
+ 'width': coord.width - width,
+ 'top': coord.top,
+ 'left': coord.left + width,
+ 'dim': w
+ };
+ },
+
+ layoutH: function(ch, w, coord, prop) {
+ var totalArea = 0;
+ $.each(ch, function(elem) { totalArea += elem._area; });
+ var height = totalArea / w,
+ top = coord.height - height,
+ left = 0;
+
+ for(var i=0, l=ch.length; i<l; i++) {
+ var chi = ch[i];
+ var s = chi._area / height;
+ chi.getPos(prop).setc(coord.left + left, coord.top + top);
+ chi.setData('width', s, prop);
+ chi.setData('height', height, prop);
+ left += s;
+ }
+ return {
+ 'height': coord.height - height,
+ 'width': coord.width,
+ 'top': coord.top,
+ 'left': coord.left,
+ 'dim': w
+ };
+ }
+ });
+
+
+/*
+ * Class: Layouts.Icicle
+ *
+ * Implements the icicle tree layout.
+ *
+ * Implemented By:
+ *
+ * <Icicle>
+ *
+ */
+
+Layouts.Icicle = new Class({
+ /*
+ * Method: compute
+ *
+ * Called by loadJSON to calculate all node positions.
+ *
+ * Parameters:
+ *
+ * posType - The nodes' position to compute. Either "start", "end" or
+ * "current". Defaults to "current".
+ */
+ compute: function(posType) {
+ posType = posType || "current";
+
+ var root = this.graph.getNode(this.root),
+ config = this.config,
+ size = this.canvas.getSize(),
+ width = size.width,
+ height = size.height,
+ offset = config.offset,
+ levelsToShow = config.constrained ? config.levelsToShow : Number.MAX_VALUE;
+
+ this.controller.onBeforeCompute(root);
+
+ Graph.Util.computeLevels(this.graph, root.id, 0, "ignore");
+
+ var treeDepth = 0;
+
+ Graph.Util.eachLevel(root, 0, false, function (n, d) { if(d > treeDepth) treeDepth = d; });
+
+ var startNode = this.graph.getNode(this.clickedNode && this.clickedNode.id || root.id);
+ var maxDepth = Math.min(treeDepth, levelsToShow-1);
+ var initialDepth = startNode._depth;
+ if(this.layout.horizontal()) {
+ this.computeSubtree(startNode, -width/2, -height/2, width/(maxDepth+1), height, initialDepth, maxDepth, posType);
+ } else {
+ this.computeSubtree(startNode, -width/2, -height/2, width, height/(maxDepth+1), initialDepth, maxDepth, posType);
+ }
+ },
+
+ computeSubtree: function (root, x, y, width, height, initialDepth, maxDepth, posType) {
+ root.getPos(posType).setc(x, y);
+ root.setData('width', width, posType);
+ root.setData('height', height, posType);
+
+ var nodeLength, prevNodeLength = 0, totalDim = 0;
+ var children = Graph.Util.getSubnodes(root, [1, 1], 'ignore'); // next level from this node
+
+ if(!children.length)
+ return;
+
+ $.each(children, function(e) { totalDim += e.getData('dim'); });
+
+ for(var i=0, l=children.length; i < l; i++) {
+ if(this.layout.horizontal()) {
+ nodeLength = height * children[i].getData('dim') / totalDim;
+ this.computeSubtree(children[i], x+width, y, width, nodeLength, initialDepth, maxDepth, posType);
+ y += nodeLength;
+ } else {
+ nodeLength = width * children[i].getData('dim') / totalDim;
+ this.computeSubtree(children[i], x, y+height, nodeLength, height, initialDepth, maxDepth, posType);
+ x += nodeLength;
+ }
+ }
+ }
+});
+
+
+
+/*
+ * File: Icicle.js
+ *
+*/
+
+/*
+ Class: Icicle
+
+ Icicle space filling visualization.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'.
+ offset - (number) Default's *2*. Boxes offset.
+ constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.
+ levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node.
+ animate - (boolean) Default's *false*. Whether to animate transitions.
+ Node.type - Described in <Options.Node>. Default's *rectangle*.
+ Label.type - Described in <Options.Label>. Default's *Native*.
+ duration - Described in <Options.Fx>. Default's *700*.
+ fps - Described in <Options.Fx>. Default's *45*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <Icicle.Op> instance.
+ fx - Access a <Icicle.Plot> instance.
+ labels - Access a <Icicle.Label> interface implementation.
+
+*/
+
+$jit.Icicle = new Class({
+ Implements: [ Loader, Extras, Layouts.Icicle ],
+
+ layout: {
+ orientation: "h",
+ vertical: function(){
+ return this.orientation == "v";
+ },
+ horizontal: function(){
+ return this.orientation == "h";
+ },
+ change: function(){
+ this.orientation = this.vertical()? "h" : "v";
+ }
+ },
+
+ initialize: function(controller) {
+ var config = {
+ animate: false,
+ orientation: "h",
+ offset: 2,
+ levelsToShow: Number.MAX_VALUE,
+ constrained: false,
+ Node: {
+ type: 'rectangle',
+ overridable: true
+ },
+ Edge: {
+ type: 'none'
+ },
+ Label: {
+ type: 'Native'
+ },
+ duration: 700,
+ fps: 45
+ };
+
+ var opts = Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles",
+ "Events", "Navigation", "Controller", "Label");
+ this.controller = this.config = $.merge(opts, config, controller);
+ this.layout.orientation = this.config.orientation;
+
+ var canvasConfig = this.config;
+ if (canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Complex,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+
+ this.graph = new Graph(
+ this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
+
+ this.labels = new $jit.Icicle.Label[this.config.Label.type](this);
+ this.fx = new $jit.Icicle.Plot(this, $jit.Icicle);
+ this.op = new $jit.Icicle.Op(this);
+ this.group = new $jit.Icicle.Group(this);
+ this.clickedNode = null;
+
+ this.initializeExtras();
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+ */
+ refresh: function(){
+ var labelType = this.config.Label.type;
+ if(labelType != 'Native') {
+ var that = this;
+ this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); });
+ }
+ this.compute();
+ this.plot();
+ },
+
+ /*
+ Method: plot
+
+ Plots the Icicle visualization. This is a shortcut to *fx.plot*.
+
+ */
+ plot: function(){
+ this.fx.plot(this.config);
+ },
+
+ /*
+ Method: enter
+
+ Sets the node as root.
+
+ Parameters:
+
+ node - (object) A <Graph.Node>.
+
+ */
+ enter: function (node) {
+ if (this.busy)
+ return;
+ this.busy = true;
+
+ var that = this,
+ config = this.config;
+
+ var callback = {
+ onComplete: function() {
+ //compute positions of newly inserted nodes
+ if(config.request)
+ that.compute();
+
+ if(config.animate) {
+ that.graph.nodeList.setDataset(['current', 'end'], {
+ 'alpha': [1, 0] //fade nodes
+ });
+
+ Graph.Util.eachSubgraph(node, function(n) {
+ n.setData('alpha', 1, 'end');
+ }, "ignore");
+
+ that.fx.animate({
+ duration: 500,
+ modes:['node-property:alpha'],
+ onComplete: function() {
+ that.clickedNode = node;
+ that.compute('end');
+
+ that.fx.animate({
+ modes:['linear', 'node-property:width:height'],
+ duration: 1000,
+ onComplete: function() {
+ that.busy = false;
+ that.clickedNode = node;
+ }
+ });
+ }
+ });
+ } else {
+ that.clickedNode = node;
+ that.busy = false;
+ that.refresh();
+ }
+ }
+ };
+
+ if(config.request) {
+ this.requestNodes(clickedNode, callback);
+ } else {
+ callback.onComplete();
+ }
+ },
+
+ /*
+ Method: out
+
+ Sets the parent node of the current selected node as root.
+
+ */
+ out: function(){
+ if(this.busy)
+ return;
+
+ var that = this,
+ GUtil = Graph.Util,
+ config = this.config,
+ graph = this.graph,
+ parents = GUtil.getParents(graph.getNode(this.clickedNode && this.clickedNode.id || this.root)),
+ parent = parents[0],
+ clickedNode = parent,
+ previousClickedNode = this.clickedNode;
+
+ this.busy = true;
+ this.events.hoveredNode = false;
+
+ if(!parent) {
+ this.busy = false;
+ return;
+ }
+
+ //final plot callback
+ callback = {
+ onComplete: function() {
+ that.clickedNode = parent;
+ if(config.request) {
+ that.requestNodes(parent, {
+ onComplete: function() {
+ that.compute();
+ that.plot();
+ that.busy = false;
+ }
+ });
+ } else {
+ that.compute();
+ that.plot();
+ that.busy = false;
+ }
+ }
+ };
+
+ //animate node positions
+ if(config.animate) {
+ this.clickedNode = clickedNode;
+ this.compute('end');
+ //animate the visible subtree only
+ this.clickedNode = previousClickedNode;
+ this.fx.animate({
+ modes:['linear', 'node-property:width:height'],
+ duration: 1000,
+ onComplete: function() {
+ //animate the parent subtree
+ that.clickedNode = clickedNode;
+ //change nodes alpha
+ graph.nodeList.setDataset(['current', 'end'], {
+ 'alpha': [0, 1]
+ });
+ GUtil.eachSubgraph(previousClickedNode, function(node) {
+ node.setData('alpha', 1);
+ }, "ignore");
+ that.fx.animate({
+ duration: 500,
+ modes:['node-property:alpha'],
+ onComplete: function() {
+ callback.onComplete();
+ }
+ });
+ }
+ });
+ } else {
+ callback.onComplete();
+ }
+ },
+ requestNodes: function(node, onComplete){
+ var handler = $.merge(this.controller, onComplete),
+ levelsToShow = this.config.constrained ? this.config.levelsToShow : Number.MAX_VALUE;
+
+ if (handler.request) {
+ var leaves = [], d = node._depth;
+ Graph.Util.eachLevel(node, 0, levelsToShow, function(n){
+ if (n.drawn && !Graph.Util.anySubnode(n)) {
+ leaves.push(n);
+ n._level = n._depth - d;
+ if (this.config.constrained)
+ n._level = levelsToShow - n._level;
+
+ }
+ });
+ this.group.requestNodes(leaves, handler);
+ } else {
+ handler.onComplete();
+ }
+ }
+});
+
+/*
+ Class: Icicle.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+$jit.Icicle.Op = new Class({
+
+ Implements: Graph.Op
+
+});
+
+/*
+ * Performs operations on group of nodes.
+ */
+$jit.Icicle.Group = new Class({
+
+ initialize: function(viz){
+ this.viz = viz;
+ this.canvas = viz.canvas;
+ this.config = viz.config;
+ },
+
+ /*
+ * Calls the request method on the controller to request a subtree for each node.
+ */
+ requestNodes: function(nodes, controller){
+ var counter = 0, len = nodes.length, nodeSelected = {};
+ var complete = function(){
+ controller.onComplete();
+ };
+ var viz = this.viz;
+ if (len == 0)
+ complete();
+ for(var i = 0; i < len; i++) {
+ nodeSelected[nodes[i].id] = nodes[i];
+ controller.request(nodes[i].id, nodes[i]._level, {
+ onComplete: function(nodeId, data){
+ if (data && data.children) {
+ data.id = nodeId;
+ viz.op.sum(data, {
+ type: 'nothing'
+ });
+ }
+ if (++counter == len) {
+ Graph.Util.computeLevels(viz.graph, viz.root, 0);
+ complete();
+ }
+ }
+ });
+ }
+ }
+});
+
+/*
+ Class: Icicle.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+$jit.Icicle.Plot = new Class({
+ Implements: Graph.Plot,
+
+ plot: function(opt, animating){
+ opt = opt || this.viz.controller;
+ var viz = this.viz,
+ graph = viz.graph,
+ root = graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root),
+ initialDepth = root._depth;
+
+ viz.canvas.clear();
+ this.plotTree(root, $.merge(opt, {
+ 'withLabels': true,
+ 'hideLabels': false,
+ 'plotSubtree': function(root, node) {
+ return !viz.config.constrained ||
+ (node._depth - initialDepth < viz.config.levelsToShow);
+ }
+ }), animating);
+ }
+});
+
+/*
+ Class: Icicle.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+ */
+$jit.Icicle.Label = {};
+
+/*
+ Icicle.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+
+ */
+$jit.Icicle.Label.Native = new Class({
+ Implements: Graph.Label.Native,
+
+ renderLabel: function(canvas, node, controller) {
+ var ctx = canvas.getCtx(),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ size = node.getLabelData('size'),
+ m = ctx.measureText(node.name);
+
+ // Guess as much as possible if the label will fit in the node
+ if(height < (size * 1.5) || width < m.width)
+ return;
+
+ var pos = node.pos.getc(true);
+ ctx.fillText(node.name,
+ pos.x + width / 2,
+ pos.y + height / 2);
+ }
+});
+
+/*
+ Icicle.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+*/
+$jit.Icicle.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz){
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true), canvas = this.viz.canvas;
+ var radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x + radius.width / 2),
+ y: Math.round(pos.y + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+
+ controller.onPlaceLabel(tag, node);
+ }
+});
+
+/*
+ Icicle.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+ */
+$jit.Icicle.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz){
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true), canvas = this.viz.canvas;
+ var radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x + radius.width / 2),
+ y: Math.round(pos.y + radius.height / 2)
+ };
+
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = '';
+
+ controller.onPlaceLabel(tag, node);
+ }
+});
+
+/*
+ Class: Icicle.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'rectangle'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ Icicle.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+$jit.Icicle.Plot.NodeTypes = new Class( {
+ 'none': {
+ 'render': $.empty
+ },
+
+ 'rectangle': {
+ 'render': function(node, canvas, animating) {
+ var config = this.viz.config;
+ var offset = config.offset;
+ var width = node.getData('width');
+ var height = node.getData('height');
+ var border = node.getData('border');
+ var pos = node.pos.getc(true);
+ var posx = pos.x + offset / 2, posy = pos.y + offset / 2;
+ var ctx = canvas.getCtx();
+
+ if(width - offset < 2 || height - offset < 2) return;
+
+ if(config.cushion) {
+ var color = node.getData('color');
+ var lg = ctx.createRadialGradient(posx + (width - offset)/2,
+ posy + (height - offset)/2, 1,
+ posx + (width-offset)/2, posy + (height-offset)/2,
+ width < height? height : width);
+ var colorGrad = $.rgbToHex($.map($.hexToRgb(color),
+ function(r) { return r * 0.3 >> 0; }));
+ lg.addColorStop(0, color);
+ lg.addColorStop(1, colorGrad);
+ ctx.fillStyle = lg;
+ }
+
+ if (border) {
+ ctx.strokeStyle = border;
+ ctx.lineWidth = 3;
+ }
+
+ ctx.fillRect(posx, posy, Math.max(0, width - offset), Math.max(0, height - offset));
+ border && ctx.strokeRect(pos.x, pos.y, width, height);
+ },
+
+ 'contains': function(node, pos) {
+ if(this.viz.clickedNode && !$jit.Graph.Util.isDescendantOf(node, this.viz.clickedNode.id)) return false;
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height);
+ }
+ }
+});
+
+$jit.Icicle.Plot.EdgeTypes = new Class( {
+ 'none': $.empty
+});
+
+
+
+/*
+ * File: Layouts.ForceDirected.js
+ *
+*/
+
+/*
+ * Class: Layouts.ForceDirected
+ *
+ * Implements a Force Directed Layout.
+ *
+ * Implemented By:
+ *
+ * <ForceDirected>
+ *
+ * Credits:
+ *
+ * Marcus Cobden <http://marcuscobden.co.uk>
+ *
+ */
+Layouts.ForceDirected = new Class({
+
+ getOptions: function(random) {
+ var s = this.canvas.getSize();
+ var w = s.width, h = s.height;
+ //count nodes
+ var count = 0;
+ this.graph.eachNode(function(n) {
+ count++;
+ });
+ var k2 = w * h / count, k = Math.sqrt(k2);
+ var l = this.config.levelDistance;
+
+ return {
+ width: w,
+ height: h,
+ tstart: w * 0.1,
+ nodef: function(x) { return k2 / (x || 1); },
+ edgef: function(x) { return /* x * x / k; */ k * (x - l); }
+ };
+ },
+
+ compute: function(property, incremental) {
+ var prop = $.splat(property || ['current', 'start', 'end']);
+ var opt = this.getOptions();
+ NodeDim.compute(this.graph, prop, this.config);
+ this.graph.computeLevels(this.root, 0, "ignore");
+ this.graph.eachNode(function(n) {
+ $.each(prop, function(p) {
+ var pos = n.getPos(p);
+ if(pos.equals(Complex.KER)) {
+ pos.x = opt.width/5 * (Math.random() - 0.5);
+ pos.y = opt.height/5 * (Math.random() - 0.5);
+ }
+ //initialize disp vector
+ n.disp = {};
+ $.each(prop, function(p) {
+ n.disp[p] = $C(0, 0);
+ });
+ });
+ });
+ this.computePositions(prop, opt, incremental);
+ },
+
+ computePositions: function(property, opt, incremental) {
+ var times = this.config.iterations, i = 0, that = this;
+ if(incremental) {
+ (function iter() {
+ for(var total=incremental.iter, j=0; j<total; j++) {
+ opt.t = opt.tstart;
+ if(times) opt.t *= (1 - i++/(times -1));
+ that.computePositionStep(property, opt);
+ if(times && i >= times) {
+ incremental.onComplete();
+ return;
+ }
+ }
+ incremental.onStep(Math.round(i / (times -1) * 100));
+ setTimeout(iter, 1);
+ })();
+ } else {
+ for(; i < times; i++) {
+ opt.t = opt.tstart * (1 - i/(times -1));
+ this.computePositionStep(property, opt);
+ }
+ }
+ },
+
+ computePositionStep: function(property, opt) {
+ var graph = this.graph;
+ var min = Math.min, max = Math.max;
+ var dpos = $C(0, 0);
+ //calculate repulsive forces
+ graph.eachNode(function(v) {
+ //initialize disp
+ $.each(property, function(p) {
+ v.disp[p].x = 0; v.disp[p].y = 0;
+ });
+ graph.eachNode(function(u) {
+ if(u.id != v.id) {
+ $.each(property, function(p) {
+ var vp = v.getPos(p), up = u.getPos(p);
+ dpos.x = vp.x - up.x;
+ dpos.y = vp.y - up.y;
+ var norm = dpos.norm() || 1;
+ v.disp[p].$add(dpos
+ .$scale(opt.nodef(norm) / norm));
+ });
+ }
+ });
+ });
+ //calculate attractive forces
+ var T = !!graph.getNode(this.root).visited;
+ graph.eachNode(function(node) {
+ node.eachAdjacency(function(adj) {
+ var nodeTo = adj.nodeTo;
+ if(!!nodeTo.visited === T) {
+ $.each(property, function(p) {
+ var vp = node.getPos(p), up = nodeTo.getPos(p);
+ dpos.x = vp.x - up.x;
+ dpos.y = vp.y - up.y;
+ var norm = dpos.norm() || 1;
+ node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm));
+ nodeTo.disp[p].$add(dpos.$scale(-1));
+ });
+ }
+ });
+ node.visited = !T;
+ });
+ //arrange positions to fit the canvas
+ var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2;
+ graph.eachNode(function(u) {
+ $.each(property, function(p) {
+ var disp = u.disp[p];
+ var norm = disp.norm() || 1;
+ var p = u.getPos(p);
+ p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm,
+ disp.y * min(Math.abs(disp.y), t) / norm));
+ p.x = min(w2, max(-w2, p.x));
+ p.y = min(h2, max(-h2, p.y));
+ });
+ });
+ }
+});
+
+/*
+ * File: ForceDirected.js
+ */
+
+/*
+ Class: ForceDirected
+
+ A visualization that lays graphs using a Force-Directed layout algorithm.
+
+ Inspired by:
+
+ Force-Directed Drawing Algorithms (Stephen G. Kobourov) <http://www.cs.brown.edu/~rt/gdhandbook/chapters/force-directed.pdf>
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are two parameters
+
+ levelDistance - (number) Default's *50*. The natural length desired for the edges.
+ iterations - (number) Default's *50*. The number of iterations for the spring layout simulation. Depending on the browser's speed you could set this to a more 'interesting' number, like *200*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <ForceDirected.Op> instance.
+ fx - Access a <ForceDirected.Plot> instance.
+ labels - Access a <ForceDirected.Label> interface implementation.
+
+*/
+
+$jit.ForceDirected = new Class( {
+
+ Implements: [ Loader, Extras, Layouts.ForceDirected ],
+
+ initialize: function(controller) {
+ var $ForceDirected = $jit.ForceDirected;
+
+ var config = {
+ iterations: 50,
+ levelDistance: 50
+ };
+
+ this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
+ "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
+
+ var canvasConfig = this.config;
+ if(canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Complex,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node,
+ this.config.Edge);
+ this.labels = new $ForceDirected.Label[canvasConfig.Label.type](this);
+ this.fx = new $ForceDirected.Plot(this, $ForceDirected);
+ this.op = new $ForceDirected.Op(this);
+ this.json = null;
+ this.busy = false;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+ */
+ refresh: function() {
+ this.compute();
+ this.plot();
+ },
+
+ reposition: function() {
+ this.compute('end');
+ },
+
+/*
+ Method: computeIncremental
+
+ Performs the Force Directed algorithm incrementally.
+
+ Description:
+
+ ForceDirected algorithms can perform many computations and lead to JavaScript taking too much time to complete.
+ This method splits the algorithm into smaller parts allowing the user to track the evolution of the algorithm and
+ avoiding browser messages such as "This script is taking too long to complete".
+
+ Parameters:
+
+ opt - (object) The object properties are described below
+
+ iter - (number) Default's *20*. Split the algorithm into pieces of _iter_ iterations. For example, if the _iterations_ configuration property
+ of your <ForceDirected> class is 100, then you could set _iter_ to 20 to split the main algorithm into 5 smaller pieces.
+
+ property - (string) Default's *end*. Whether to update starting, current or ending node positions. Possible values are 'end', 'start', 'current'.
+ You can also set an array of these properties. If you'd like to keep the current node positions but to perform these
+ computations for final animation positions then you can just choose 'end'.
+
+ onStep - (function) A callback function called when each "small part" of the algorithm completed. This function gets as first formal
+ parameter a percentage value.
+
+ onComplete - A callback function called when the algorithm completed.
+
+ Example:
+
+ In this example I calculate the end positions and then animate the graph to those positions
+
+ (start code js)
+ var fd = new $jit.ForceDirected(...);
+ fd.computeIncremental({
+ iter: 20,
+ property: 'end',
+ onStep: function(perc) {
+ Log.write("loading " + perc + "%");
+ },
+ onComplete: function() {
+ Log.write("done");
+ fd.animate();
+ }
+ });
+ (end code)
+
+ In this example I calculate all positions and (re)plot the graph
+
+ (start code js)
+ var fd = new ForceDirected(...);
+ fd.computeIncremental({
+ iter: 20,
+ property: ['end', 'start', 'current'],
+ onStep: function(perc) {
+ Log.write("loading " + perc + "%");
+ },
+ onComplete: function() {
+ Log.write("done");
+ fd.plot();
+ }
+ });
+ (end code)
+
+ */
+ computeIncremental: function(opt) {
+ opt = $.merge( {
+ iter: 20,
+ property: 'end',
+ onStep: $.empty,
+ onComplete: $.empty
+ }, opt || {});
+
+ this.config.onBeforeCompute(this.graph.getNode(this.root));
+ this.compute(opt.property, opt);
+ },
+
+ /*
+ Method: plot
+
+ Plots the ForceDirected graph. This is a shortcut to *fx.plot*.
+ */
+ plot: function() {
+ this.fx.plot();
+ },
+
+ /*
+ Method: animate
+
+ Animates the graph from the current positions to the 'end' node positions.
+ */
+ animate: function(opt) {
+ this.fx.animate($.merge( {
+ modes: [ 'linear' ]
+ }, opt || {}));
+ }
+});
+
+$jit.ForceDirected.$extend = true;
+
+(function(ForceDirected) {
+
+ /*
+ Class: ForceDirected.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+ ForceDirected.Op = new Class( {
+
+ Implements: Graph.Op
+
+ });
+
+ /*
+ Class: ForceDirected.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+ ForceDirected.Plot = new Class( {
+
+ Implements: Graph.Plot
+
+ });
+
+ /*
+ Class: ForceDirected.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+ */
+ ForceDirected.Label = {};
+
+ /*
+ ForceDirected.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+
+ */
+ ForceDirected.Label.Native = new Class( {
+ Implements: Graph.Label.Native
+ });
+
+ /*
+ ForceDirected.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+
+ */
+ ForceDirected.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Label>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ ForceDirected.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+ */
+ ForceDirected.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ Class: ForceDirected.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ ForceDirected.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ ForceDirected.Plot.NodeTypes = new Class({
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false)
+ },
+ 'circle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.circle.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.circle.contains(npos, pos, dim);
+ }
+ },
+ 'ellipse': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ return this.nodeHelper.ellipse.contains(npos, pos, width, height);
+ }
+ },
+ 'square': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.square.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.square.contains(npos, pos, dim);
+ }
+ },
+ 'rectangle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ return this.nodeHelper.rectangle.contains(npos, pos, width, height);
+ }
+ },
+ 'triangle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.triangle.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos) {
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.triangle.contains(npos, pos, dim);
+ }
+ },
+ 'star': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.star.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos) {
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.star.contains(npos, pos, dim);
+ }
+ }
+ });
+
+ /*
+ Class: ForceDirected.Plot.EdgeTypes
+
+ This class contains a list of <Graph.Adjacence> built-in types.
+ Edge types implemented are 'none', 'line' and 'arrow'.
+
+ You can add your custom edge types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ ForceDirected.Plot.EdgeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(adj, canvas) {
+ //print your custom edge to canvas
+ },
+ //optional
+ 'contains': function(adj, pos) {
+ //return true if pos is inside the arc or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ ForceDirected.Plot.EdgeTypes = new Class({
+ 'none': $.empty,
+ 'line': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ this.edgeHelper.line.render(from, to, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'arrow': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ dim = adj.getData('dim'),
+ direction = adj.data.$direction,
+ inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);
+ this.edgeHelper.arrow.render(from, to, dim, inv, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon);
+ }
+ }
+ });
+
+})($jit.ForceDirected);
+
+
+/*
+ * File: Treemap.js
+ *
+*/
+
+$jit.TM = {};
+
+var TM = $jit.TM;
+
+$jit.TM.$extend = true;
+
+/*
+ Class: TM.Base
+
+ Abstract class providing base functionality for <TM.Squarified>, <TM.Strip> and <TM.SliceAndDice> visualizations.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'.
+ titleHeight - (number) Default's *13*. The height of the title rectangle for inner (non-leaf) nodes.
+ offset - (number) Default's *2*. Boxes offset.
+ constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.
+ levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node.
+ animate - (boolean) Default's *false*. Whether to animate transitions.
+ Node.type - Described in <Options.Node>. Default's *rectangle*.
+ duration - Described in <Options.Fx>. Default's *700*.
+ fps - Described in <Options.Fx>. Default's *45*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <TM.Op> instance.
+ fx - Access a <TM.Plot> instance.
+ labels - Access a <TM.Label> interface implementation.
+
+ Inspired by:
+
+ Squarified Treemaps (Mark Bruls, Kees Huizing, and Jarke J. van Wijk) <http://www.win.tue.nl/~vanwijk/stm.pdf>
+
+ Tree visualization with tree-maps: 2-d space-filling approach (Ben Shneiderman) <http://hcil.cs.umd.edu/trs/91-03/91-03.html>
+
+ Note:
+
+ This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.
+
+*/
+TM.Base = {
+ layout: {
+ orientation: "h",
+ vertical: function(){
+ return this.orientation == "v";
+ },
+ horizontal: function(){
+ return this.orientation == "h";
+ },
+ change: function(){
+ this.orientation = this.vertical()? "h" : "v";
+ }
+ },
+
+ initialize: function(controller){
+ var config = {
+ orientation: "h",
+ titleHeight: 13,
+ offset: 2,
+ levelsToShow: 0,
+ constrained: false,
+ animate: false,
+ Node: {
+ type: 'rectangle',
+ overridable: true,
+ //we all know why this is not zero,
+ //right, Firefox?
+ width: 3,
+ height: 3,
+ color: '#444'
+ },
+ Label: {
+ textAlign: 'center',
+ textBaseline: 'top'
+ },
+ Edge: {
+ type: 'none'
+ },
+ duration: 700,
+ fps: 45
+ };
+
+ this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
+ "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
+ this.layout.orientation = this.config.orientation;
+
+ var canvasConfig = this.config;
+ if (canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Complex,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node,
+ this.config.Edge);
+ this.labels = new TM.Label[canvasConfig.Label.type](this);
+ this.fx = new TM.Plot(this);
+ this.op = new TM.Op(this);
+ this.group = new TM.Group(this);
+ this.geom = new TM.Geom(this);
+ this.clickedNode = null;
+ this.busy = false;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+ */
+ refresh: function(){
+ if(this.busy) return;
+ this.busy = true;
+ var that = this;
+ if(this.config.animate) {
+ this.compute('end');
+ this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode
+ && this.clickedNode.id || this.root));
+ this.fx.animate($.merge(this.config, {
+ modes: ['linear', 'node-property:width:height'],
+ onComplete: function() {
+ that.busy = false;
+ }
+ }));
+ } else {
+ var labelType = this.config.Label.type;
+ if(labelType != 'Native') {
+ var that = this;
+ this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); });
+ }
+ this.busy = false;
+ this.compute();
+ this.config.levelsToShow > 0 && this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode
+ && this.clickedNode.id || this.root));
+ this.plot();
+ }
+ },
+
+ /*
+ Method: plot
+
+ Plots the TreeMap. This is a shortcut to *fx.plot*.
+
+ */
+ plot: function(){
+ this.fx.plot();
+ },
+
+ /*
+ Method: leaf
+
+ Returns whether the node is a leaf.
+
+ Parameters:
+
+ n - (object) A <Graph.Node>.
+
+ */
+ leaf: function(n){
+ return n.getSubnodes([
+ 1, 1
+ ], "ignore").length == 0;
+ },
+
+ /*
+ Method: enter
+
+ Sets the node as root.
+
+ Parameters:
+
+ n - (object) A <Graph.Node>.
+
+ */
+ enter: function(n){
+ if(this.busy) return;
+ this.busy = true;
+
+ var that = this,
+ config = this.config,
+ graph = this.graph,
+ clickedNode = n,
+ previousClickedNode = this.clickedNode;
+
+ var callback = {
+ onComplete: function() {
+ //ensure that nodes are shown for that level
+ if(config.levelsToShow > 0) {
+ that.geom.setRightLevelToShow(n);
+ }
+ //compute positions of newly inserted nodes
+ if(config.levelsToShow > 0 || config.request) that.compute();
+ if(config.animate) {
+ //fade nodes
+ graph.nodeList.setData('alpha', 0, 'end');
+ n.eachSubgraph(function(n) {
+ n.setData('alpha', 1, 'end');
+ }, "ignore");
+ that.fx.animate({
+ duration: 500,
+ modes:['node-property:alpha'],
+ onComplete: function() {
+ //compute end positions
+ that.clickedNode = clickedNode;
+ that.compute('end');
+ //animate positions
+ //TODO(nico) commenting this line didn't seem to throw errors...
+ that.clickedNode = previousClickedNode;
+ that.fx.animate({
+ modes:['linear', 'node-property:width:height'],
+ duration: 1000,
+ onComplete: function() {
+ that.busy = false;
+ //TODO(nico) check comment above
+ that.clickedNode = clickedNode;
+ }
+ });
+ }
+ });
+ } else {
+ that.busy = false;
+ that.clickedNode = n;
+ that.refresh();
+ }
+ }
+ };
+ if(config.request) {
+ this.requestNodes(clickedNode, callback);
+ } else {
+ callback.onComplete();
+ }
+ },
+
+ /*
+ Method: out
+
+ Sets the parent node of the current selected node as root.
+
+ */
+ out: function(){
+ if(this.busy) return;
+ this.busy = true;
+ this.events.hoveredNode = false;
+ var that = this,
+ config = this.config,
+ graph = this.graph,
+ parents = graph.getNode(this.clickedNode
+ && this.clickedNode.id || this.root).getParents(),
+ parent = parents[0],
+ clickedNode = parent,
+ previousClickedNode = this.clickedNode;
+
+ //if no parents return
+ if(!parent) {
+ this.busy = false;
+ return;
+ }
+ //final plot callback
+ callback = {
+ onComplete: function() {
+ that.clickedNode = parent;
+ if(config.request) {
+ that.requestNodes(parent, {
+ onComplete: function() {
+ that.compute();
+ that.plot();
+ that.busy = false;
+ }
+ });
+ } else {
+ that.compute();
+ that.plot();
+ that.busy = false;
+ }
+ }
+ };
+ //prune tree
+ if (config.levelsToShow > 0)
+ this.geom.setRightLevelToShow(parent);
+ //animate node positions
+ if(config.animate) {
+ this.clickedNode = clickedNode;
+ this.compute('end');
+ //animate the visible subtree only
+ this.clickedNode = previousClickedNode;
+ this.fx.animate({
+ modes:['linear', 'node-property:width:height'],
+ duration: 1000,
+ onComplete: function() {
+ //animate the parent subtree
+ that.clickedNode = clickedNode;
+ //change nodes alpha
+ graph.eachNode(function(n) {
+ n.setDataset(['current', 'end'], {
+ 'alpha': [0, 1]
+ });
+ }, "ignore");
+ previousClickedNode.eachSubgraph(function(node) {
+ node.setData('alpha', 1);
+ }, "ignore");
+ that.fx.animate({
+ duration: 500,
+ modes:['node-property:alpha'],
+ onComplete: function() {
+ callback.onComplete();
+ }
+ });
+ }
+ });
+ } else {
+ callback.onComplete();
+ }
+ },
+
+ requestNodes: function(node, onComplete){
+ var handler = $.merge(this.controller, onComplete),
+ lev = this.config.levelsToShow;
+ if (handler.request) {
+ var leaves = [], d = node._depth;
+ node.eachLevel(0, lev, function(n){
+ var nodeLevel = lev - (n._depth - d);
+ if (n.drawn && !n.anySubnode() && nodeLevel > 0) {
+ leaves.push(n);
+ n._level = nodeLevel;
+ }
+ });
+ this.group.requestNodes(leaves, handler);
+ } else {
+ handler.onComplete();
+ }
+ },
+
+ reposition: function() {
+ this.compute('end');
+ }
+};
+
+/*
+ Class: TM.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+TM.Op = new Class({
+ Implements: Graph.Op,
+
+ initialize: function(viz){
+ this.viz = viz;
+ }
+});
+
+//extend level methods of Graph.Geom
+TM.Geom = new Class({
+ Implements: Graph.Geom,
+
+ getRightLevelToShow: function() {
+ return this.viz.config.levelsToShow;
+ },
+
+ setRightLevelToShow: function(node) {
+ var level = this.getRightLevelToShow(),
+ fx = this.viz.labels;
+ node.eachLevel(0, level+1, function(n) {
+ var d = n._depth - node._depth;
+ if(d > level) {
+ n.drawn = false;
+ n.exist = false;
+ n.ignore = true;
+ fx.hideLabel(n, false);
+ } else {
+ n.drawn = true;
+ n.exist = true;
+ delete n.ignore;
+ }
+ });
+ node.drawn = true;
+ delete node.ignore;
+ }
+});
+
+/*
+
+Performs operations on group of nodes.
+
+*/
+TM.Group = new Class( {
+
+ initialize: function(viz){
+ this.viz = viz;
+ this.canvas = viz.canvas;
+ this.config = viz.config;
+ },
+
+ /*
+
+ Calls the request method on the controller to request a subtree for each node.
+ */
+ requestNodes: function(nodes, controller){
+ var counter = 0, len = nodes.length, nodeSelected = {};
+ var complete = function(){
+ controller.onComplete();
+ };
+ var viz = this.viz;
+ if (len == 0)
+ complete();
+ for ( var i = 0; i < len; i++) {
+ nodeSelected[nodes[i].id] = nodes[i];
+ controller.request(nodes[i].id, nodes[i]._level, {
+ onComplete: function(nodeId, data){
+ if (data && data.children) {
+ data.id = nodeId;
+ viz.op.sum(data, {
+ type: 'nothing'
+ });
+ }
+ if (++counter == len) {
+ viz.graph.computeLevels(viz.root, 0);
+ complete();
+ }
+ }
+ });
+ }
+ }
+});
+
+/*
+ Class: TM.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+TM.Plot = new Class({
+
+ Implements: Graph.Plot,
+
+ initialize: function(viz){
+ this.viz = viz;
+ this.config = viz.config;
+ this.node = this.config.Node;
+ this.edge = this.config.Edge;
+ this.animation = new Animation;
+ this.nodeTypes = new TM.Plot.NodeTypes;
+ this.edgeTypes = new TM.Plot.EdgeTypes;
+ this.labels = viz.labels;
+ },
+
+ plot: function(opt, animating){
+ var viz = this.viz,
+ graph = viz.graph;
+ viz.canvas.clear();
+ this.plotTree(graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root), $.merge(viz.config, opt || {}, {
+ 'withLabels': true,
+ 'hideLabels': false,
+ 'plotSubtree': function(n, ch){
+ return n.anySubnode("exist");
+ }
+ }), animating);
+ }
+});
+
+/*
+ Class: TM.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+*/
+TM.Label = {};
+
+/*
+ TM.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+*/
+TM.Label.Native = new Class({
+ Implements: Graph.Label.Native,
+
+ initialize: function(viz) {
+ this.config = viz.config;
+ this.leaf = viz.leaf;
+ },
+
+ renderLabel: function(canvas, node, controller){
+ if(!this.leaf(node) && !this.config.titleHeight) return;
+ var pos = node.pos.getc(true),
+ ctx = canvas.getCtx(),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ x = pos.x + width/2,
+ y = pos.y;
+
+ ctx.fillText(node.name, x, y, width);
+ }
+});
+
+/*
+ TM.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+*/
+TM.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz){
+ this.viz = viz;
+ this.leaf = viz.leaf;
+ this.config = viz.config;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+
+ if(!this.leaf(node) && !this.config.titleHeight) {
+ tag.style.display = 'none';
+ }
+ controller.onPlaceLabel(tag, node);
+ }
+});
+
+/*
+ TM.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+*/
+TM.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz){
+ this.viz = viz;
+ this.leaf = viz.leaf;
+ this.config = viz.config;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.width = node.getData('width') * sx + 'px';
+ style.height = node.getData('height') * sy + 'px';
+ style.zIndex = node._depth * 100;
+ style.display = '';
+
+ if(!this.leaf(node) && !this.config.titleHeight) {
+ tag.style.display = 'none';
+ }
+ controller.onPlaceLabel(tag, node);
+ }
+});
+
+/*
+ Class: TM.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'rectangle'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ TM.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+*/
+TM.Plot.NodeTypes = new Class( {
+ 'none': {
+ 'render': $.empty
+ },
+
+ 'rectangle': {
+ 'render': function(node, canvas, animating){
+ var leaf = this.viz.leaf(node),
+ config = this.config,
+ offst = config.offset,
+ titleHeight = config.titleHeight,
+ pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height'),
+ border = node.getData('border'),
+ ctx = canvas.getCtx(),
+ posx = pos.x + offst / 2,
+ posy = pos.y + offst / 2;
+ if(width <= offst || height <= offst) return;
+ if (leaf) {
+ if(config.cushion) {
+ var lg = ctx.createRadialGradient(posx + (width-offst)/2, posy + (height-offst)/2, 1,
+ posx + (width-offst)/2, posy + (height-offst)/2, width < height? height : width);
+ var color = node.getData('color');
+ var colorGrad = $.rgbToHex($.map($.hexToRgb(color),
+ function(r) { return r * 0.2 >> 0; }));
+ lg.addColorStop(0, color);
+ lg.addColorStop(1, colorGrad);
+ ctx.fillStyle = lg;
+ }
+ ctx.fillRect(posx, posy, width - offst, height - offst);
+ if(border) {
+ ctx.save();
+ ctx.strokeStyle = border;
+ ctx.strokeRect(posx, posy, width - offst, height - offst);
+ ctx.restore();
+ }
+ } else if(titleHeight > 0){
+ ctx.fillRect(pos.x + offst / 2, pos.y + offst / 2, width - offst,
+ titleHeight - offst);
+ if(border) {
+ ctx.save();
+ ctx.strokeStyle = border;
+ ctx.strokeRect(pos.x + offst / 2, pos.y + offst / 2, width - offst,
+ height - offst);
+ ctx.restore();
+ }
+ }
+ },
+ 'contains': function(node, pos) {
+ if(this.viz.clickedNode && !node.isDescendantOf(this.viz.clickedNode.id) || node.ignore) return false;
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ leaf = this.viz.leaf(node),
+ height = leaf? node.getData('height') : this.config.titleHeight;
+ return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height);
+ }
+ }
+});
+
+TM.Plot.EdgeTypes = new Class( {
+ 'none': $.empty
+});
+
+/*
+ Class: TM.SliceAndDice
+
+ A slice and dice TreeMap visualization.
+
+ Implements:
+
+ All <TM.Base> methods and properties.
+*/
+TM.SliceAndDice = new Class( {
+ Implements: [
+ Loader, Extras, TM.Base, Layouts.TM.SliceAndDice
+ ]
+});
+
+/*
+ Class: TM.Squarified
+
+ A squarified TreeMap visualization.
+
+ Implements:
+
+ All <TM.Base> methods and properties.
+*/
+TM.Squarified = new Class( {
+ Implements: [
+ Loader, Extras, TM.Base, Layouts.TM.Squarified
+ ]
+});
+
+/*
+ Class: TM.Strip
+
+ A strip TreeMap visualization.
+
+ Implements:
+
+ All <TM.Base> methods and properties.
+*/
+TM.Strip = new Class( {
+ Implements: [
+ Loader, Extras, TM.Base, Layouts.TM.Strip
+ ]
+});
+
+
+/*
+ * File: RGraph.js
+ *
+ */
+
+/*
+ Class: RGraph
+
+ A radial graph visualization with advanced animations.
+
+ Inspired by:
+
+ Animated Exploration of Dynamic Graphs with Radial Layout (Ka-Ping Yee, Danyel Fisher, Rachna Dhamija, Marti Hearst) <http://bailando.sims.berkeley.edu/papers/infovis01.htm>
+
+ Note:
+
+ This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'.
+ levelDistance - (number) Default's *100*. The distance between levels of the tree.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <RGraph.Op> instance.
+ fx - Access a <RGraph.Plot> instance.
+ labels - Access a <RGraph.Label> interface implementation.
+*/
+
+$jit.RGraph = new Class( {
+
+ Implements: [
+ Loader, Extras, Layouts.Radial
+ ],
+
+ initialize: function(controller){
+ var $RGraph = $jit.RGraph;
+
+ var config = {
+ interpolation: 'linear',
+ levelDistance: 100
+ };
+
+ this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
+ "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
+
+ var canvasConfig = this.config;
+ if(canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Polar,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node,
+ this.config.Edge);
+ this.labels = new $RGraph.Label[canvasConfig.Label.type](this);
+ this.fx = new $RGraph.Plot(this, $RGraph);
+ this.op = new $RGraph.Op(this);
+ this.json = null;
+ this.root = null;
+ this.busy = false;
+ this.parent = false;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+
+ createLevelDistanceFunc
+
+ Returns the levelDistance function used for calculating a node distance
+ to its origin. This function returns a function that is computed
+ per level and not per node, such that all nodes with the same depth will have the
+ same distance to the origin. The resulting function gets the
+ parent node as parameter and returns a float.
+
+ */
+ createLevelDistanceFunc: function(){
+ var ld = this.config.levelDistance;
+ return function(elem){
+ return (elem._depth + 1) * ld;
+ };
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+
+ */
+ refresh: function(){
+ this.compute();
+ this.plot();
+ },
+
+ reposition: function(){
+ this.compute('end');
+ },
+
+ /*
+ Method: plot
+
+ Plots the RGraph. This is a shortcut to *fx.plot*.
+ */
+ plot: function(){
+ this.fx.plot();
+ },
+ /*
+ getNodeAndParentAngle
+
+ Returns the _parent_ of the given node, also calculating its angle span.
+ */
+ getNodeAndParentAngle: function(id){
+ var theta = false;
+ var n = this.graph.getNode(id);
+ var ps = n.getParents();
+ var p = (ps.length > 0)? ps[0] : false;
+ if (p) {
+ var posParent = p.pos.getc(), posChild = n.pos.getc();
+ var newPos = posParent.add(posChild.scale(-1));
+ theta = Math.atan2(newPos.y, newPos.x);
+ if (theta < 0)
+ theta += 2 * Math.PI;
+ }
+ return {
+ parent: p,
+ theta: theta
+ };
+ },
+ /*
+ tagChildren
+
+ Enumerates the children in order to maintain child ordering (second constraint of the paper).
+ */
+ tagChildren: function(par, id){
+ if (par.angleSpan) {
+ var adjs = [];
+ par.eachAdjacency(function(elem){
+ adjs.push(elem.nodeTo);
+ }, "ignore");
+ var len = adjs.length;
+ for ( var i = 0; i < len && id != adjs[i].id; i++)
+ ;
+ for ( var j = (i + 1) % len, k = 0; id != adjs[j].id; j = (j + 1) % len) {
+ adjs[j].dist = k++;
+ }
+ }
+ },
+ /*
+ Method: onClick
+
+ Animates the <RGraph> to center the node specified by *id*.
+
+ Parameters:
+
+ id - A <Graph.Node> id.
+ opt - (optional|object) An object containing some extra properties described below
+ hideLabels - (boolean) Default's *true*. Hide labels when performing the animation.
+
+ Example:
+
+ (start code js)
+ rgraph.onClick('someid');
+ //or also...
+ rgraph.onClick('someid', {
+ hideLabels: false
+ });
+ (end code)
+
+ */
+ onClick: function(id, opt){
+ if (this.root != id && !this.busy) {
+ this.busy = true;
+ this.root = id;
+ var that = this;
+ this.controller.onBeforeCompute(this.graph.getNode(id));
+ var obj = this.getNodeAndParentAngle(id);
+
+ // second constraint
+ this.tagChildren(obj.parent, id);
+ this.parent = obj.parent;
+ this.compute('end');
+
+ // first constraint
+ var thetaDiff = obj.theta - obj.parent.endPos.theta;
+ this.graph.eachNode(function(elem){
+ elem.endPos.set(elem.endPos.getp().add($P(thetaDiff, 0)));
+ });
+
+ var mode = this.config.interpolation;
+ opt = $.merge( {
+ onComplete: $.empty
+ }, opt || {});
+
+ this.fx.animate($.merge( {
+ hideLabels: true,
+ modes: [
+ mode
+ ]
+ }, opt, {
+ onComplete: function(){
+ that.busy = false;
+ opt.onComplete();
+ }
+ }));
+ }
+ }
+});
+
+$jit.RGraph.$extend = true;
+
+(function(RGraph){
+
+ /*
+ Class: RGraph.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+ RGraph.Op = new Class( {
+
+ Implements: Graph.Op
+
+ });
+
+ /*
+ Class: RGraph.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+ RGraph.Plot = new Class( {
+
+ Implements: Graph.Plot
+
+ });
+
+ /*
+ Object: RGraph.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+ */
+ RGraph.Label = {};
+
+ /*
+ RGraph.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+
+ */
+ RGraph.Label.Native = new Class( {
+ Implements: Graph.Label.Native
+ });
+
+ /*
+ RGraph.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+
+ */
+ RGraph.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz){
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ RGraph.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+ */
+ RGraph.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz){
+ this.viz = viz;
+ },
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller){
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize();
+ var labelPos = {
+ x: Math.round(pos.x * sx + ox + radius.width / 2),
+ y: Math.round(pos.y * sy + oy + radius.height / 2)
+ };
+
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ Class: RGraph.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ RGraph.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ RGraph.Plot.NodeTypes = new Class({
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false)
+ },
+ 'circle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.circle.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.circle.contains(npos, pos, dim);
+ }
+ },
+ 'ellipse': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ return this.nodeHelper.ellipse.contains(npos, pos, width, height);
+ }
+ },
+ 'square': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.square.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.square.contains(npos, pos, dim);
+ }
+ },
+ 'rectangle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);
+ },
+ 'contains': function(node, pos){
+ var npos = node.pos.getc(true),
+ width = node.getData('width'),
+ height = node.getData('height');
+ return this.nodeHelper.rectangle.contains(npos, pos, width, height);
+ }
+ },
+ 'triangle': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.triangle.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos) {
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.triangle.contains(npos, pos, dim);
+ }
+ },
+ 'star': {
+ 'render': function(node, canvas){
+ var pos = node.pos.getc(true),
+ dim = node.getData('dim');
+ this.nodeHelper.star.render('fill', pos, dim, canvas);
+ },
+ 'contains': function(node, pos) {
+ var npos = node.pos.getc(true),
+ dim = node.getData('dim');
+ return this.nodeHelper.star.contains(npos, pos, dim);
+ }
+ }
+ });
+
+ /*
+ Class: RGraph.Plot.EdgeTypes
+
+ This class contains a list of <Graph.Adjacence> built-in types.
+ Edge types implemented are 'none', 'line' and 'arrow'.
+
+ You can add your custom edge types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ RGraph.Plot.EdgeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(adj, canvas) {
+ //print your custom edge to canvas
+ },
+ //optional
+ 'contains': function(adj, pos) {
+ //return true if pos is inside the arc or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ RGraph.Plot.EdgeTypes = new Class({
+ 'none': $.empty,
+ 'line': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ this.edgeHelper.line.render(from, to, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.line.contains(from, to, pos, this.edge.epsilon);
+ }
+ },
+ 'arrow': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ dim = adj.getData('dim'),
+ direction = adj.data.$direction,
+ inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);
+ this.edgeHelper.arrow.render(from, to, dim, inv, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true);
+ return this.edgeHelper.arrow.contains(from, to, pos, this.edge.epsilon);
+ }
+ }
+ });
+
+})($jit.RGraph);
+
+
+/*
+ * File: Hypertree.js
+ *
+*/
+
+/*
+ Complex
+
+ A multi-purpose Complex Class with common methods. Extended for the Hypertree.
+
+*/
+/*
+ moebiusTransformation
+
+ Calculates a moebius transformation for this point / complex.
+ For more information go to:
+ http://en.wikipedia.org/wiki/Moebius_transformation.
+
+ Parameters:
+
+ c - An initialized Complex instance representing a translation Vector.
+*/
+
+Complex.prototype.moebiusTransformation = function(c) {
+ var num = this.add(c);
+ var den = c.$conjugate().$prod(this);
+ den.x++;
+ return num.$div(den);
+};
+
+/*
+ moebiusTransformation
+
+ Calculates a moebius transformation for the hyperbolic tree.
+
+ <http://en.wikipedia.org/wiki/Moebius_transformation>
+
+ Parameters:
+
+ graph - A <Graph> instance.
+ pos - A <Complex>.
+ prop - A property array.
+ theta - Rotation angle.
+ startPos - _optional_ start position.
+*/
+Graph.Util.moebiusTransformation = function(graph, pos, prop, startPos, flags) {
+ this.eachNode(graph, function(elem) {
+ for ( var i = 0; i < prop.length; i++) {
+ var p = pos[i].scale(-1), property = startPos ? startPos : prop[i];
+ elem.getPos(prop[i]).set(elem.getPos(property).getc().moebiusTransformation(p));
+ }
+ }, flags);
+};
+
+/*
+ Class: Hypertree
+
+ A Hyperbolic Tree/Graph visualization.
+
+ Inspired by:
+
+ A Focus+Context Technique Based on Hyperbolic Geometry for Visualizing Large Hierarchies (John Lamping, Ramana Rao, and Peter Pirolli).
+ <http://www.cs.tau.ac.il/~asharf/shrek/Projects/HypBrowser/startree-chi95.pdf>
+
+ Note:
+
+ This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the Hypertree described in the paper.
+
+ Implements:
+
+ All <Loader> methods
+
+ Constructor Options:
+
+ Inherits options from
+
+ - <Options.Canvas>
+ - <Options.Controller>
+ - <Options.Node>
+ - <Options.Edge>
+ - <Options.Label>
+ - <Options.Events>
+ - <Options.Tips>
+ - <Options.NodeStyles>
+ - <Options.Navigation>
+
+ Additionally, there are other parameters and some default values changed
+
+ radius - (string|number) Default's *auto*. The radius of the disc to plot the <Hypertree> in. 'auto' will take the smaller value from the width and height canvas dimensions. You can also set this to a custom value, for example *250*.
+ offset - (number) Default's *0*. A number in the range [0, 1) that will be substracted to each node position to make a more compact <Hypertree>. This will avoid placing nodes too far from each other when a there's a selected node.
+ fps - Described in <Options.Fx>. It's default value has been changed to *35*.
+ duration - Described in <Options.Fx>. It's default value has been changed to *1500*.
+ Edge.type - Described in <Options.Edge>. It's default value has been changed to *hyperline*.
+
+ Instance Properties:
+
+ canvas - Access a <Canvas> instance.
+ graph - Access a <Graph> instance.
+ op - Access a <Hypertree.Op> instance.
+ fx - Access a <Hypertree.Plot> instance.
+ labels - Access a <Hypertree.Label> interface implementation.
+
+*/
+
+$jit.Hypertree = new Class( {
+
+ Implements: [ Loader, Extras, Layouts.Radial ],
+
+ initialize: function(controller) {
+ var $Hypertree = $jit.Hypertree;
+
+ var config = {
+ radius: "auto",
+ offset: 0,
+ Edge: {
+ type: 'hyperline'
+ },
+ duration: 1500,
+ fps: 35
+ };
+ this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
+ "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
+
+ var canvasConfig = this.config;
+ if(canvasConfig.useCanvas) {
+ this.canvas = canvasConfig.useCanvas;
+ this.config.labelContainer = this.canvas.id + '-label';
+ } else {
+ if(canvasConfig.background) {
+ canvasConfig.background = $.merge({
+ type: 'Circles'
+ }, canvasConfig.background);
+ }
+ this.canvas = new Canvas(this, canvasConfig);
+ this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
+ }
+
+ this.graphOptions = {
+ 'klass': Polar,
+ 'Node': {
+ 'selected': false,
+ 'exist': true,
+ 'drawn': true
+ }
+ };
+ this.graph = new Graph(this.graphOptions, this.config.Node,
+ this.config.Edge);
+ this.labels = new $Hypertree.Label[canvasConfig.Label.type](this);
+ this.fx = new $Hypertree.Plot(this, $Hypertree);
+ this.op = new $Hypertree.Op(this);
+ this.json = null;
+ this.root = null;
+ this.busy = false;
+ // initialize extras
+ this.initializeExtras();
+ },
+
+ /*
+
+ createLevelDistanceFunc
+
+ Returns the levelDistance function used for calculating a node distance
+ to its origin. This function returns a function that is computed
+ per level and not per node, such that all nodes with the same depth will have the
+ same distance to the origin. The resulting function gets the
+ parent node as parameter and returns a float.
+
+ */
+ createLevelDistanceFunc: function() {
+ // get max viz. length.
+ var r = this.getRadius();
+ // get max depth.
+ var depth = 0, max = Math.max, config = this.config;
+ this.graph.eachNode(function(node) {
+ depth = max(node._depth, depth);
+ }, "ignore");
+ depth++;
+ // node distance generator
+ var genDistFunc = function(a) {
+ return function(node) {
+ node.scale = r;
+ var d = node._depth + 1;
+ var acum = 0, pow = Math.pow;
+ while (d) {
+ acum += pow(a, d--);
+ }
+ return acum - config.offset;
+ };
+ };
+ // estimate better edge length.
+ for ( var i = 0.51; i <= 1; i += 0.01) {
+ var valSeries = (1 - Math.pow(i, depth)) / (1 - i);
+ if (valSeries >= 2) { return genDistFunc(i - 0.01); }
+ }
+ return genDistFunc(0.75);
+ },
+
+ /*
+ Method: getRadius
+
+ Returns the current radius of the visualization. If *config.radius* is *auto* then it
+ calculates the radius by taking the smaller size of the <Canvas> widget.
+
+ See also:
+
+ <Canvas.getSize>
+
+ */
+ getRadius: function() {
+ var rad = this.config.radius;
+ if (rad !== "auto") { return rad; }
+ var s = this.canvas.getSize();
+ return Math.min(s.width, s.height) / 2;
+ },
+
+ /*
+ Method: refresh
+
+ Computes positions and plots the tree.
+
+ Parameters:
+
+ reposition - (optional|boolean) Set this to *true* to force all positions (current, start, end) to match.
+
+ */
+ refresh: function(reposition) {
+ if (reposition) {
+ this.reposition();
+ this.graph.eachNode(function(node) {
+ node.startPos.rho = node.pos.rho = node.endPos.rho;
+ node.startPos.theta = node.pos.theta = node.endPos.theta;
+ });
+ } else {
+ this.compute();
+ }
+ this.plot();
+ },
+
+ /*
+ reposition
+
+ Computes nodes' positions and restores the tree to its previous position.
+
+ For calculating nodes' positions the root must be placed on its origin. This method does this
+ and then attemps to restore the hypertree to its previous position.
+
+ */
+ reposition: function() {
+ this.compute('end');
+ var vector = this.graph.getNode(this.root).pos.getc().scale(-1);
+ Graph.Util.moebiusTransformation(this.graph, [ vector ], [ 'end' ],
+ 'end', "ignore");
+ this.graph.eachNode(function(node) {
+ if (node.ignore) {
+ node.endPos.rho = node.pos.rho;
+ node.endPos.theta = node.pos.theta;
+ }
+ });
+ },
+
+ /*
+ Method: plot
+
+ Plots the <Hypertree>. This is a shortcut to *fx.plot*.
+
+ */
+ plot: function() {
+ this.fx.plot();
+ },
+
+ /*
+ Method: onClick
+
+ Animates the <Hypertree> to center the node specified by *id*.
+
+ Parameters:
+
+ id - A <Graph.Node> id.
+ opt - (optional|object) An object containing some extra properties described below
+ hideLabels - (boolean) Default's *true*. Hide labels when performing the animation.
+
+ Example:
+
+ (start code js)
+ ht.onClick('someid');
+ //or also...
+ ht.onClick('someid', {
+ hideLabels: false
+ });
+ (end code)
+
+ */
+ onClick: function(id, opt) {
+ var pos = this.graph.getNode(id).pos.getc(true);
+ this.move(pos, opt);
+ },
+
+ /*
+ Method: move
+
+ Translates the tree to the given position.
+
+ Parameters:
+
+ pos - (object) A *x, y* coordinate object where x, y in [0, 1), to move the tree to.
+ opt - This object has been defined in <Hypertree.onClick>
+
+ Example:
+
+ (start code js)
+ ht.move({ x: 0, y: 0.7 }, {
+ hideLabels: false
+ });
+ (end code)
+
+ */
+ move: function(pos, opt) {
+ var versor = $C(pos.x, pos.y);
+ if (this.busy === false && versor.norm() < 1) {
+ this.busy = true;
+ var root = this.graph.getClosestNodeToPos(versor), that = this;
+ this.graph.computeLevels(root.id, 0);
+ this.controller.onBeforeCompute(root);
+ opt = $.merge( {
+ onComplete: $.empty
+ }, opt || {});
+ this.fx.animate($.merge( {
+ modes: [ 'moebius' ],
+ hideLabels: true
+ }, opt, {
+ onComplete: function() {
+ that.busy = false;
+ opt.onComplete();
+ }
+ }), versor);
+ }
+ }
+});
+
+$jit.Hypertree.$extend = true;
+
+(function(Hypertree) {
+
+ /*
+ Class: Hypertree.Op
+
+ Custom extension of <Graph.Op>.
+
+ Extends:
+
+ All <Graph.Op> methods
+
+ See also:
+
+ <Graph.Op>
+
+ */
+ Hypertree.Op = new Class( {
+
+ Implements: Graph.Op
+
+ });
+
+ /*
+ Class: Hypertree.Plot
+
+ Custom extension of <Graph.Plot>.
+
+ Extends:
+
+ All <Graph.Plot> methods
+
+ See also:
+
+ <Graph.Plot>
+
+ */
+ Hypertree.Plot = new Class( {
+
+ Implements: Graph.Plot
+
+ });
+
+ /*
+ Object: Hypertree.Label
+
+ Custom extension of <Graph.Label>.
+ Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
+
+ Extends:
+
+ All <Graph.Label> methods and subclasses.
+
+ See also:
+
+ <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
+
+ */
+ Hypertree.Label = {};
+
+ /*
+ Hypertree.Label.Native
+
+ Custom extension of <Graph.Label.Native>.
+
+ Extends:
+
+ All <Graph.Label.Native> methods
+
+ See also:
+
+ <Graph.Label.Native>
+
+ */
+ Hypertree.Label.Native = new Class( {
+ Implements: Graph.Label.Native,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ renderLabel: function(canvas, node, controller) {
+ var ctx = canvas.getCtx();
+ var coord = node.pos.getc(true);
+ var s = this.viz.getRadius();
+ ctx.fillText(node.name, coord.x * s, coord.y * s);
+ }
+ });
+
+ /*
+ Hypertree.Label.SVG
+
+ Custom extension of <Graph.Label.SVG>.
+
+ Extends:
+
+ All <Graph.Label.SVG> methods
+
+ See also:
+
+ <Graph.Label.SVG>
+
+ */
+ Hypertree.Label.SVG = new Class( {
+ Implements: Graph.Label.SVG,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize(),
+ r = this.viz.getRadius();
+ var labelPos = {
+ x: Math.round((pos.x * sx) * r + ox + radius.width / 2),
+ y: Math.round((pos.y * sy) * r + oy + radius.height / 2)
+ };
+ tag.setAttribute('x', labelPos.x);
+ tag.setAttribute('y', labelPos.y);
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ Hypertree.Label.HTML
+
+ Custom extension of <Graph.Label.HTML>.
+
+ Extends:
+
+ All <Graph.Label.HTML> methods.
+
+ See also:
+
+ <Graph.Label.HTML>
+
+ */
+ Hypertree.Label.HTML = new Class( {
+ Implements: Graph.Label.HTML,
+
+ initialize: function(viz) {
+ this.viz = viz;
+ },
+ /*
+ placeLabel
+
+ Overrides abstract method placeLabel in <Graph.Plot>.
+
+ Parameters:
+
+ tag - A DOM label element.
+ node - A <Graph.Node>.
+ controller - A configuration/controller object passed to the visualization.
+
+ */
+ placeLabel: function(tag, node, controller) {
+ var pos = node.pos.getc(true),
+ canvas = this.viz.canvas,
+ ox = canvas.translateOffsetX,
+ oy = canvas.translateOffsetY,
+ sx = canvas.scaleOffsetX,
+ sy = canvas.scaleOffsetY,
+ radius = canvas.getSize(),
+ r = this.viz.getRadius();
+ var labelPos = {
+ x: Math.round((pos.x * sx) * r + ox + radius.width / 2),
+ y: Math.round((pos.y * sy) * r + oy + radius.height / 2)
+ };
+ var style = tag.style;
+ style.left = labelPos.x + 'px';
+ style.top = labelPos.y + 'px';
+ style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';
+
+ controller.onPlaceLabel(tag, node);
+ }
+ });
+
+ /*
+ Class: Hypertree.Plot.NodeTypes
+
+ This class contains a list of <Graph.Node> built-in types.
+ Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.
+
+ You can add your custom node types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ Hypertree.Plot.NodeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(node, canvas) {
+ //print your custom node to canvas
+ },
+ //optional
+ 'contains': function(node, pos) {
+ //return true if pos is inside the node or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ Hypertree.Plot.NodeTypes = new Class({
+ 'none': {
+ 'render': $.empty,
+ 'contains': $.lambda(false)
+ },
+ 'circle': {
+ 'render': function(node, canvas) {
+ var nconfig = this.node,
+ dim = node.getData('dim'),
+ p = node.pos.getc();
+ dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;
+ p.$scale(node.scale);
+ if (dim > 0.2) {
+ this.nodeHelper.circle.render('fill', p, dim, canvas);
+ }
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.circle.contains(npos, pos, dim);
+ }
+ },
+ 'ellipse': {
+ 'render': function(node, canvas) {
+ var pos = node.pos.getc().$scale(node.scale),
+ width = node.getData('width'),
+ height = node.getData('height');
+ this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);
+ },
+ 'contains': function(node, pos) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.circle.contains(npos, pos, width, height);
+ }
+ },
+ 'square': {
+ 'render': function(node, canvas) {
+ var nconfig = this.node,
+ dim = node.getData('dim'),
+ p = node.pos.getc();
+ dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;
+ p.$scale(node.scale);
+ if (dim > 0.2) {
+ this.nodeHelper.square.render('fill', p, dim, canvas);
+ }
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.square.contains(npos, pos, dim);
+ }
+ },
+ 'rectangle': {
+ 'render': function(node, canvas) {
+ var nconfig = this.node,
+ width = node.getData('width'),
+ height = node.getData('height'),
+ pos = node.pos.getc();
+ width = nconfig.transform? width * (1 - pos.squaredNorm()) : width;
+ height = nconfig.transform? height * (1 - pos.squaredNorm()) : height;
+ pos.$scale(node.scale);
+ if (width > 0.2 && height > 0.2) {
+ this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);
+ }
+ },
+ 'contains': function(node, pos) {
+ var width = node.getData('width'),
+ height = node.getData('height'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.rectangle.contains(npos, pos, width, height);
+ }
+ },
+ 'triangle': {
+ 'render': function(node, canvas) {
+ var nconfig = this.node,
+ dim = node.getData('dim'),
+ p = node.pos.getc();
+ dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;
+ p.$scale(node.scale);
+ if (dim > 0.2) {
+ this.nodeHelper.triangle.render('fill', p, dim, canvas);
+ }
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.triangle.contains(npos, pos, dim);
+ }
+ },
+ 'star': {
+ 'render': function(node, canvas) {
+ var nconfig = this.node,
+ dim = node.getData('dim'),
+ p = node.pos.getc();
+ dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;
+ p.$scale(node.scale);
+ if (dim > 0.2) {
+ this.nodeHelper.star.render('fill', p, dim, canvas);
+ }
+ },
+ 'contains': function(node, pos) {
+ var dim = node.getData('dim'),
+ npos = node.pos.getc().$scale(node.scale);
+ return this.nodeHelper.star.contains(npos, pos, dim);
+ }
+ }
+ });
+
+ /*
+ Class: Hypertree.Plot.EdgeTypes
+
+ This class contains a list of <Graph.Adjacence> built-in types.
+ Edge types implemented are 'none', 'line', 'arrow' and 'hyperline'.
+
+ You can add your custom edge types, customizing your visualization to the extreme.
+
+ Example:
+
+ (start code js)
+ Hypertree.Plot.EdgeTypes.implement({
+ 'mySpecialType': {
+ 'render': function(adj, canvas) {
+ //print your custom edge to canvas
+ },
+ //optional
+ 'contains': function(adj, pos) {
+ //return true if pos is inside the arc or false otherwise
+ }
+ }
+ });
+ (end code)
+
+ */
+ Hypertree.Plot.EdgeTypes = new Class({
+ 'none': $.empty,
+ 'line': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ r = adj.nodeFrom.scale;
+ this.edgeHelper.line.render({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ r = adj.nodeFrom.scale;
+ this.edgeHelper.line.contains({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, pos, this.edge.epsilon);
+ }
+ },
+ 'arrow': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ r = adj.nodeFrom.scale,
+ dim = adj.getData('dim'),
+ direction = adj.data.$direction,
+ inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);
+ this.edgeHelper.arrow.render({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, dim, inv, canvas);
+ },
+ 'contains': function(adj, pos) {
+ var from = adj.nodeFrom.pos.getc(true),
+ to = adj.nodeTo.pos.getc(true),
+ r = adj.nodeFrom.scale;
+ this.edgeHelper.arrow.contains({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, pos, this.edge.epsilon);
+ }
+ },
+ 'hyperline': {
+ 'render': function(adj, canvas) {
+ var from = adj.nodeFrom.pos.getc(),
+ to = adj.nodeTo.pos.getc(),
+ dim = this.viz.getRadius();
+ this.edgeHelper.hyperline.render(from, to, dim, canvas);
+ },
+ 'contains': $.lambda(false)
+ }
+ });
+
+})($jit.Hypertree);
+
+
+
+
+ })(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/README b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/README
new file mode 100644
index 00000000..776cf2cd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/README
@@ -0,0 +1,11 @@
+= JitGraph =
+
+This code provides the result format "jitgraph" which enables
+inline query results to be output in a form of interactive graphs.
+
+== Credits ==
+
+JitGraph PHP code has been written by Alex Shapovalov (shapov1@gmail.com).
+
+The JitGraph result format employs a JavaScript library
+provided by SenchaLabs (http://http://thejit.org/).
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.js b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.js
new file mode 100644
index 00000000..092d65c1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.js
@@ -0,0 +1,208 @@
+var labelType, useGradients, nativeTextSupport, animate;
+
+(function() {
+ var ua = navigator.userAgent,
+ iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
+ typeOfCanvas = typeof HTMLCanvasElement,
+ nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
+ textSupport = nativeCanvasSupport
+ && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
+ //I'm setting this based on the fact that ExCanvas provides text support for IE
+ //and that as of today iPhone/iPad current text support is lame
+ labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
+ nativeTextSupport = labelType == 'Native';
+ useGradients = nativeCanvasSupport;
+ animate = !(iStuff || !nativeCanvasSupport);
+})();
+
+var Log = {
+ elem: false,
+ write: function(text){
+ if (!this.elem)
+ this.elem = document.getElementById('log');
+ this.elem.innerHTML = text;
+ this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
+ }
+};
+
+
+function init(json, userSettings){
+ // init data
+
+ // end
+ // init ForceDirected
+
+
+ /*
+ var settings = {
+ "divID": "infovis",
+ "edgeColor": "#23A4FF",
+ "edgeWidth": 2,
+ "edgeLength": 150,
+ "navigation": true,
+ "zooming": false,
+ "panning": "avoid nodes",
+ "labelcolor": "#000000"
+ };
+ */
+
+ var settings = userSettings;
+ var divID = '#progress-'+settings.d_id;
+ var prg_bar = jQuery(divID);
+
+ //alert(settings.edgeColor)
+
+ var fd = new $jit.ForceDirected({
+ //id of the visualization container
+ injectInto: settings.divID,
+ //Enable zooming and panning
+ //by scrolling and DnD
+ Navigation: {
+ enable: settings.navigation,
+ //Enable panning events only if we're dragging the empty
+ //canvas (and not a node).
+ panning: settings.panning,
+ zooming: settings.zooming //zoom speed. higher is more sensible
+ },
+ // Change node and edge styles such as
+ // color and width.
+ // These properties are also set per node
+ // with dollar prefixed data-properties in the
+ // JSON structure.
+ Node: {
+ overridable: true,
+ color: '#005588',
+ dim: 7
+ },
+ Edge: {
+ overridable: false,
+ color: settings.edgeColor,
+ lineWidth: settings.edgeWidth
+ },
+ //Native canvas text styling
+ Label: {
+ type: labelType, //Native or HTML
+ size: 16,
+ style: 'normal',
+ textAlign: 'center',
+ color: settings.labelColor
+ },
+ //Add Tips
+ Tips: {
+ enable: true,
+ onShow: function(tip, node) {
+ //count connections
+ var count = 0;
+ node.eachAdjacency(function() { count++; });
+ //display node info in tooltip
+
+ var tipHTML = "<div class=\"tip-title\">" + node.name + "</div>"
+ + "<div class=\"tip-text\"><b>connections:</b> " + count + "</div>"
+ + "<div class=\"tip-text\"><ol>";
+
+
+ var counter = 0;
+
+ node.eachAdjacency(function(adj){
+ counter ++;
+ var nodeToName = adj.nodeTo.name;
+ var nodeFromName = adj.nodeFrom.name;
+ var edgeType = adj.nodeTo.getData("edgeType");
+ tipHTML += "<li>"+nodeToName+"</li>";
+ //tipHTML += "<li>Connection "+ counter +": "+nodeFromName +" "+ edgeType+" " +nodeToName+"</li>";
+ //list.push(adj.nodeTo.name);
+ });
+
+ tipHTML += "</ol></div>";
+ tip.innerHTML = tipHTML;
+ }
+ },
+ // Add node events
+ Events: {
+ enable: true,
+ type: 'Native',
+ //Change cursor style when hovering a node
+ onMouseEnter: function() {
+ fd.canvas.getElement().style.cursor = '';
+ },
+ onMouseLeave: function() {
+ fd.canvas.getElement().style.cursor = '';
+ },
+ //Update node positions when dragged
+ onDragMove: function(node, eventInfo, e) {
+ var pos = eventInfo.getPos();
+ node.pos.setc(pos.x, pos.y);
+ fd.plot();
+ },
+ //Implement the same handler for touchscreens
+ onTouchMove: function(node, eventInfo, e) {
+ $jit.util.event.stop(e); //stop default touchmove event
+ this.onDragMove(node, eventInfo, e);
+ },
+ //Add also a click handler to nodes
+ onClick: function(node) {
+ if(!node) return;
+ // Build the right column relations list.
+ // This is done by traversing the clicked node connections.
+ var html = "<h4>" + node.name + "</h4><b> connections:</b>",
+ list = [];
+ node.eachAdjacency(function(adj){
+ list.push(adj.nodeTo.name);
+ });
+
+ //append connections information
+ //$jit.id('inner-details').innerHTML = html + list.join("</li><li>") + "</li></ul>";
+ window.location = node.getData("url");
+ }
+ },
+ //Number of iterations for the FD algorithm
+ iterations: 200,
+ //Edge length
+ levelDistance: settings.edgeLength,
+ // Add text to the labels. This method is only triggered
+ // on label creation and only for DOM labels (not native canvas ones).
+ onCreateLabel: function(domElement, node){
+ domElement.innerHTML = node.name;
+ var style = domElement.style;
+ style.fontSize = "0.8em";
+ style.color = "#ddd";
+ },
+ // Change node styles when DOM labels are placed
+ // or moved.
+ onPlaceLabel: function(domElement, node){
+ var style = domElement.style;
+ var left = parseInt(style.left);
+ var top = parseInt(style.top);
+ var w = domElement.offsetWidth;
+ style.left = (left - w / 2) + 'px';
+ style.top = (top + 10) + 'px';
+ style.display = '';
+ }
+ });
+ // load JSON data.
+ fd.loadJSON(json);
+ // compute positions incrementally and animate.
+ fd.computeIncremental({
+ iter: 40,
+ property: 'end',
+ onStep: function(perc){
+ //alert(divID);
+ prg_bar.progressBar(perc);
+ //alert(perc + '% loaded…');
+ //Log.write(perc + '% loaded...');
+ },
+ onComplete: function(){
+ //Log.write('done');
+ prg_bar.progressBar(100);
+ var divID = '#progress-'+settings.d_id;
+ var t = setTimeout("jQuery('"+divID+"').hide('slow');", 3000);
+ //var t = setTimeout("", 3000);
+ fd.animate({
+ modes: ['linear'],
+ transition: $jit.Trans.Elastic.easeOut,
+ duration: 3000
+ });
+ }
+ });
+ // end
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.php b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.php
new file mode 100644
index 00000000..98f62cd5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/SRF_JitGraph.php
@@ -0,0 +1,385 @@
+<?php
+/**
+ * Print query results in interactive graph using the
+ * JavaScript InfoVis Toolkit (http://thejit.org)
+ *
+ * @since 1.7.1
+ *
+ * @file SRF_JitGraph.php
+ * @ingroup SemanticResultFormats
+ */
+
+/**
+ * Result printer for timeline data.
+ *
+ * @ingroup SemanticResultFormats
+ */
+class SRFJitGraph extends SMWResultPrinter {
+
+ public static $NODE_SHAPES = [ 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star' ];
+
+ protected $m_graphName = '227';
+ protected $m_graphLabel = false;
+ protected $m_graphColor = false;
+ protected $m_graphLegend = false;
+ protected $m_graphLink = false;
+ protected $m_rankdir = "LR";
+ protected $m_graphSize = "";
+ protected $m_labelArray = [];
+ protected $m_graphNodeType = 'circle';
+ protected $m_graphNodeSize = 12;
+ protected $m_graphRootNode = false;
+ protected $m_nodeTypes = [ 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star' ];
+
+ protected $m_nodeColorArray = [
+ 'black' => '#00FF00',
+ 'red' => '#CF2A2A',
+ 'green' => '#558800',
+ 'blue' => '#005588' ];
+ protected $m_rootNodeColor = '#CF2A2A'; //Red
+ protected $m_graphNodeColor = '#005588'; //Blue
+
+ protected $m_settings = [
+ "divID" => "infovis",
+ "edgeColor" => "#23A4FF",
+ "edgeWidth" => 2,
+ "edgeLength" => 150,
+ "navigation" => true,
+ "zooming" => false,
+ "panning" => "avoid nodes",
+ "labelColor" => "#000000"
+ ];
+
+ protected $m_edgeColors = [];
+ protected $m_edgeNames = [];
+
+ protected $debug_out = '';
+
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ if ( array_key_exists( 'graphname', $params ) ) {
+ $this->m_graphName = trim( $params['graphname'] );
+ }
+
+ $this->m_graphNodeType = $params['graphnodetype'];
+
+// if ( array_key_exists( 'graphnodetype', $params ) ) {
+// $userType = strtolower( trim( $params['graphnodetype'] ) );
+// if ( in_array($userType, $this->m_nodeTypes) ) {
+// $this->m_graphNodeType = $userType;
+// }
+//
+// }
+
+ if ( array_key_exists( 'graphnodesize', $params ) ) {
+
+ $userSize = intval( trim( $params['graphnodesize'] ) );
+ if ( $userSize > 0 ) {
+ $this->m_graphNodeSize = $userSize;
+ }
+ }
+ if ( array_key_exists( 'graphsize', $params ) ) {
+
+ $this->m_graphSize = trim( $params['graphsize'] );
+
+ }
+ if ( array_key_exists( 'graphrootnode', $params ) ) {
+
+ if ( strtolower( trim( $params['graphrootnode'] ) ) == 'yes' ) {
+ $this->m_graphRootNode = true;
+ }
+
+ }
+ if ( array_key_exists( 'graphlegend', $params ) ) {
+
+ if ( strtolower( trim( $params['graphlegend'] ) ) == 'yes' ) {
+ $this->m_graphLegend = true;
+ }
+
+ }
+
+ if ( array_key_exists( 'graphlabel', $params ) ) {
+
+ if ( strtolower( trim( $params['graphlabel'] ) ) == 'yes' ) {
+ $this->m_graphLabel = true;
+ }
+
+ }
+ if ( array_key_exists( 'graphnodecolor', $params ) ) {
+ $userNodeColor = strtolower( trim( $params['graphnodecolor'] ) );
+ if ( array_key_exists( $userNodeColor, $this->m_nodeColorArray ) ) {
+ $this->m_graphNodeColor = $this->m_nodeColorArray[$userNodeColor];
+ $this->debug_out .= "graphNodeColor: " . $this->m_graphNodeColor . " | ";
+ }
+ }
+ if ( array_key_exists( 'rootnodecolor', $params ) ) {
+ $userRootNodeColor = strtolower( trim( $params['rootnodecolor'] ) );
+ if ( array_key_exists( $userRootNodeColor, $this->m_nodeColorArray ) ) {
+ $this->m_rootNodeColor = $this->m_nodeColorArray[$userRootNodeColor];
+ }
+ }
+ if ( array_key_exists( 'graphlink', $params ) ) {
+
+ if ( strtolower( trim( $params['graphlink'] ) ) == 'yes' ) {
+ $this->m_graphLink = true;
+ }
+
+ }
+ if ( array_key_exists( 'graphcolor', $params ) ) {
+
+ if ( strtolower( trim( $params['graphcolor'] ) ) == 'yes' ) {
+ $this->m_graphColor = true;
+ }
+
+ }
+
+ }
+
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf_printername_outline, srf_printername_sum, srf_printername_average, srf_printername_max
+ return wfMessage( 'srf_printername_' . $this->mFormat )->text();
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ global $wgTitle, $wgOut;
+
+ if ( class_exists( 'ResourceLoader' ) ) {
+ $wgOut->addModules( 'ext.srf.jitgraph' );
+ } else {
+ //Include javascript files in the HTML header
+ $this->includeJS();
+ }
+
+ $json = "[";
+ $jsonLeafs = "";
+
+ while ( $row = $res->getNext() ) {
+
+ $firstcol = true;
+
+ foreach ( $row as $field ) {
+ while ( ( $object = $field->getNextDataValue() ) !== false ) {
+ $text = $object->getShortText( $outputmode );
+
+ $nodeLinkTitle = Title::newFromText( $text );
+ $nodeLinkURL = $nodeLinkTitle->getFullURL();
+
+ if ( $firstcol ) {
+ $firstcolvalue = $object->getShortText( $outputmode );
+
+ //Title of the page where the result format is being displayed
+ $thisPageTitle = $wgTitle->getPrefixedText();
+
+ //This little block adds the name of the current edge to the list later used to compile the graph legend
+ $req = $field->getPrintRequest();
+ $labelName = trim( $req->getLabel() );
+
+ //Different color options and formatting for the page currently on.
+ if ( strcmp( $thisPageTitle, $text ) == 0 && $this->m_graphRootNode ) {
+ $json .= "{ \"id\":\"$text\", ";
+ $json .= "\"name\":\"$text\", ";
+ $json .= "\"data\":{\"\$color\": \"$this->m_rootNodeColor\", ";
+ $json .= "\"\$type\":\"$this->m_graphNodeType\", ";
+ $json .= "\"\$dim\":\"17\", ";
+ $json .= "\"\$url\":\"$nodeLinkURL\", ";
+ $json .= "\"\$edgeType\":\"$labelName\" ";
+ } else {
+ $json .= "{ \"id\":\"$text\", ";
+ $json .= "\"name\":\"$text\", ";
+ $json .= "\"data\":{\"\$color\": \"$this->m_graphNodeColor\", ";
+ $json .= "\"\$type\":\"$this->m_graphNodeType\", ";
+ $json .= "\"\$dim\":\"$this->m_graphNodeSize\", ";
+ $json .= "\"\$url\":\"$nodeLinkURL\", ";
+ $json .= "\"\$edgeType\":\"$labelName\" ";
+
+ if ( !in_array( $labelName, $this->m_edgeNames ) && strlen( $labelName ) > 0 ) {
+ $this->m_edgeNames[] = $labelName;
+ }
+ }
+
+ $json .= "}, ";
+ $json .= "\"adjacencies\":[ ";
+ }
+
+ if ( !$firstcol ) {
+
+ $json .= "{ \"nodeTo\":\"$text\", ";
+ $json .= "\"nodeFrom\":\"$firstcolvalue\", ";
+ $json .= "\"data\":{\"\$color\":\"#$this->m_rootNodeColor\",\"\$url\":\"$nodeLinkURL\"}},";
+ if ( ( $this->m_graphLabel == true ) || ( $this->m_graphColor == true ) ) {
+ $req = $field->getPrintRequest();
+ $labelName = $req->getLabel();
+
+ if ( array_search( $labelName, $this->m_labelArray, true ) === false ) {
+ $this->m_labelArray[] = $labelName;
+ }
+ $key = array_search( $labelName, $this->m_labelArray, true );
+
+ if ( $this->m_graphLabel == true ) {
+
+ }
+ if ( $this->m_graphColor == true ) {
+
+ }
+ }
+
+ //Create an explicit node for each leaf.
+ $jsonLeafs .= "{ \"id\":\"$text\", ";
+ $jsonLeafs .= "\"name\":\"$text\", ";
+
+ if ( strcmp( $thisPageTitle, $text ) == 0 ) {
+ $rootNodeSize = $this->m_graphNodeSize + 5;
+ $jsonLeafs .= "\"data\":{\"\$color\": \"$this->m_rootNodeColor\", ";
+ $jsonLeafs .= "\"\$dim\":\"$rootNodeSize\", ";
+ } else {
+ $jsonLeafs .= "\"data\":{\"\$color\": \"$this->m_graphNodeColor\", ";
+ $jsonLeafs .= "\"\$dim\":\"$this->m_graphNodeSize\", ";
+ }
+ $jsonLeafs .= "\"\$type\":\"$this->m_graphNodeType\", ";
+ $jsonLeafs .= "\"\$url\":\"$nodeLinkURL\", ";
+ $jsonLeafs .= "\"\$edgeType\":\"$labelName\" ";
+ $jsonLeafs .= "}, ";
+ $jsonLeafs .= "\"adjacencies\":[]},";
+
+ //This little block adds the name of the current edge to the list later used to compile the graph legend
+ $req = $field->getPrintRequest();
+ $labelName = trim( $req->getLabel() );
+ if ( !in_array( $labelName, $this->m_edgeNames ) && strlen( $labelName ) > 0 ) {
+ $this->m_edgeNames[] = $labelName;
+ }
+ }
+ }
+
+ $firstcol = false;
+ }
+ $json = substr( $json, 0, -1 ); // Trim the comma after the last item in the list
+ $json .= "]},"; //close adjacencies array
+
+ //Append the leaf nodes.
+ //$jsonLeafs = substr($jsonLeafs,0,-1); // Trim the comma after the last item in the list
+ $json .= $jsonLeafs;
+ $jsonLeafs = "";
+ }
+ $json = substr( $json, 0, -1 ); // Trim the comma after the last item in the list
+ $json .= "]"; //close the json object array
+
+ $result = '';
+
+ if ( $this->m_graphLabel || true ) {
+ $result .= '<h3>' . $this->m_graphName . '</h3>';
+ }
+
+ $d_id = rand( 1000, 9999 );
+ $divID = 'infovis-' . $d_id; //generate a random id to have the ability to display multiple graphs on a single page.
+ $this->m_settings['d_id'] = $d_id;
+ $this->m_settings['divID'] = $divID;
+
+ //User Settings
+ $userSettings = "var graphSettings = {";
+ foreach ( $this->m_settings as $key => $value ) {
+ $userSettings .= "\"$key\": \"$value\",";
+ }
+ substr( $userSettings, 0, -1 );
+ $userSettings .= "};";
+
+ $result .= '<div id="center-container" class="className"><span class="progressBar" id="progress-' . $d_id . '">0%</span><div id="' . $this->m_settings['divID'] . '" class="infovis"></div>' . '' . '</div>';
+
+ $result .= "<script>";
+ $result .= $userSettings;
+ // FIXME: init function cannot be called here, use JS in a separate file and bind to the onload event.
+ $result .= "var json=" . $json . "; this.init(json, graphSettings);" . 'jQuery("#progress-' . $d_id . '").progressBar();';
+ $result .= 'jQuery(document).load(function() {});';
+ //$result .= '$("#progress1").progressBar();';
+ $result .= "</script>";
+
+ // yes, our code can be viewed as HTML if requested, no more parsing needed
+ //$this->isHTML = $outputmode == SMW_OUTPUT_HTML;
+
+ $this->isHTML = true;
+
+ return $result;
+ }
+
+ protected function includeJS() {
+ SMWOutputs::requireHeadItem( SMW_HEADER_STYLE );
+
+ //$wgOut->addModules( 'ext.srf.jitgraph' );
+
+ global $srfgScriptPath;
+
+ SMWOutputs::requireHeadItem(
+ 'smw_jgcss',
+ '<link rel="stylesheet" type="text/css" href="' . $srfgScriptPath .
+ '/JitGraph/base.css"></link>'
+ );
+ SMWOutputs::requireHeadItem(
+ 'smw_jgloader',
+ '<script type="text/javascript" src="' . $srfgScriptPath .
+ '/JitGraph/jquery.progressbar.js"></script>'
+ );
+ SMWOutputs::requireHeadItem(
+ 'smw_jg',
+ '<script type="text/javascript" src="' . $srfgScriptPath .
+ '/JitGraph/Jit/jit.js"></script>'
+ );
+ SMWOutputs::requireHeadItem(
+ 'smw_jghelper',
+ '<script type="text/javascript" src="' . $srfgScriptPath .
+ '/JitGraph/SRF_JitGraph.js"></script>'
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['graphname'] = [
+ 'default' => 'GraphName',
+ 'message' => 'srf_paramdesc_graphname',
+ ];
+
+ $params['graphnodetype'] = [
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graph-graphnodetype',
+ 'values' => self::$NODE_SHAPES,
+ ];
+
+ $params['graphsize'] = [
+ 'type' => 'integer',
+ 'default' => '',
+ 'manipulatedefault' => false,
+ 'message' => 'srf_paramdesc_graphsize',
+ ];
+
+ $params['graphlegend'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf_paramdesc_graphlegend',
+ ];
+
+ $params['graphlabel'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf_paramdesc_graphlabel',
+ ];
+
+ $params['graphcolor'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf_paramdesc_graphcolor',
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/base.css b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/base.css
new file mode 100644
index 00000000..2b482c2a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/base.css
@@ -0,0 +1,85 @@
+div#center-container {
+ width:100%;
+ /* height:600px; */
+ display: block;
+ /* background-color:#1a1a1a; */
+ background-color:#eee;
+ border: 1px solid #94B8DC;
+ color:#ccc;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ position: relative;
+}
+
+div.graph_legend {
+ display: block;
+ margin: 5px;
+ padding: 5px;
+}
+
+div.graph_legend ul{
+ display: block;
+ color: red;
+}
+
+div.graph_legend ul li {
+ color: red;
+}
+
+.text {
+ margin: 7px;
+}
+
+#inner-details {
+ font-size:0.8em;
+ list-style:none;
+ margin:7px;
+}
+
+#log {
+ position:absolute;
+ top:10px;
+ font-size:1.0em;
+ font-weight:bold;
+ color:#23A4FF;
+}
+
+
+div.infovis {
+ position:relative;
+ width:100%;
+ height:600px;
+ margin:auto;
+ overflow:hidden;
+}
+
+/*TOOLTIPS*/
+.tip {
+ color: #111;
+ width: 139px;
+ background-color: white;
+ border:1px solid #ccc;
+ -moz-box-shadow:#555 2px 2px 8px;
+ -webkit-box-shadow:#555 2px 2px 8px;
+ -o-box-shadow:#555 2px 2px 8px;
+ box-shadow:#555 2px 2px 8px;
+ opacity:0.9;
+ filter:alpha(opacity=90);
+ font-size:10px;
+ font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
+ padding:7px;
+}
+
+span.progressBar {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+}
+
+img.progressGreen {
+ background: url(images/progressbg_green.gif) top left no-repeat;
+}
+
+span.progressText{
+ color: #000000;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbar.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbar.gif
new file mode 100644
index 00000000..abe588c1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbar.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_black.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_black.gif
new file mode 100644
index 00000000..74fd1f9b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_black.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_green.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_green.gif
new file mode 100644
index 00000000..f3f3bf68
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_green.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_orange.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_orange.gif
new file mode 100644
index 00000000..808cac7c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_orange.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_red.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_red.gif
new file mode 100644
index 00000000..54dfa135
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_red.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_yellow.gif b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_yellow.gif
new file mode 100644
index 00000000..fdb0dfc9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/images/progressbg_yellow.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/jquery.progressbar.js b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/jquery.progressbar.js
new file mode 100644
index 00000000..e15e99e9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/JitGraph/jquery.progressbar.js
@@ -0,0 +1,132 @@
+/*
+ * jQuery Progress Bar plugin
+ * Version 1.1.0 (06/20/2008)
+ * @requires jQuery v1.2.1 or later
+ *
+ * Copyright (c) 2008 Gary Teo
+ * http://t.wits.sg
+
+USAGE:
+ $(".someclass").progressBar();
+ $("#progressbar").progressBar();
+ $("#progressbar").progressBar(45); // percentage
+ $("#progressbar").progressBar({showText: false }); // percentage with config
+ $("#progressbar").progressBar(45, {showText: false }); // percentage with config
+*/
+(function($) {
+ $.extend({
+ progressBar: new function() {
+
+ this.defaults = {
+ increment : 20,
+ speed : 1,
+ showText : true, // show text with percentage in next to the progressbar? - default : true
+ width : 120, // Width of the progressbar - don't forget to adjust your image too!!!
+ boxImage : './images/progressbar.gif', // boxImage : image around the progress bar
+ barImage : './images/progressbg_green.gif', // Image to use in the progressbar. Can be an array of images too.
+ height : 12 // Height of the progressbar - don't forget to adjust your image too!!!
+ };
+
+ /* public methods */
+ this.construct = function(arg1, arg2) {
+ var argpercentage = null;
+ var argconfig = null;
+
+ if (arg1 != null) {
+ if (!isNaN(arg1)) {
+ argpercentage = arg1;
+ if (arg2 != null) {
+ argconfig = arg2; }
+ } else {
+ argconfig = arg1;
+ }
+ }
+
+ return this.each(function(child) {
+ var pb = this;
+ if (argpercentage != null && this.bar != null && this.config != null) {
+ this.config.tpercentage = argpercentage;
+ if (argconfig != null)
+ pb.config = $.extend(this.config, argconfig);
+ } else {
+ var $this = $(this);
+ var config = $.extend({}, $.progressBar.defaults, argconfig);
+ var percentage = argpercentage;
+ if (argpercentage == null)
+ var percentage = $this.html().replace("%",""); // parsed percentage
+
+
+ $this.html("");
+ var bar = document.createElement('img');
+ var text = document.createElement('span');
+ bar.id = this.id + "_percentImage";
+ text.id = this.id + "_percentText";
+ //bar.src = config.boxImage;
+ bar.width = config.width;
+ var $bar = $(bar);
+ var $text = $(text);
+
+ this.bar = $bar;
+ this.ntext = $text;
+ this.config = config;
+ this.config.cpercentage = 0;
+ this.config.tpercentage = percentage;
+
+ $bar.css("width", config.width + "px");
+ $bar.css("height", config.height + "px");
+ //$bar.css("background-image", "url(" + config.barImage + ")");
+ $bar.addClass("progressGreen");
+ $text.addClass("progressText");
+ $bar.css("padding", "0");
+ $bar.css("margin", "0");
+ $this.append($bar);
+ $this.append($text);
+
+ bar.alt = this.tpercentage;
+ bar.title = this.tpercentage;
+ }
+
+
+
+ var t = setInterval(function() {
+ var config = pb.config;
+ var cpercentage = parseInt(config.cpercentage);
+ var tpercentage = parseInt(config.tpercentage);
+ var increment = parseInt(config.increment);
+ var bar = pb.bar;
+ var text = pb.ntext;
+ var pixels = config.width / 100; // Define how many pixels go into 1%
+
+ bar.css("background-position", (((config.width * -1)) + (cpercentage * pixels)) + 'px 50%');
+
+ if (config.showText)
+ text.html(" " + Math.round(cpercentage) + "%");
+
+ if (cpercentage > tpercentage) {
+ if (cpercentage - increment < tpercentage) {
+ pb.config.cpercentage = 0 + tpercentage
+ } else {
+ pb.config.cpercentage -= increment;
+ }
+ }
+ else if (pb.config.cpercentage < pb.config.tpercentage) {
+ if (cpercentage + increment > tpercentage) {
+ pb.config.cpercentage = tpercentage
+ } else {
+ pb.config.cpercentage += increment;
+ }
+ }
+ else {
+ clearInterval(t);
+ }
+ }, pb.config.speed);
+ });
+ };
+ }
+ });
+
+ $.fn.extend({
+ progressBar: $.progressBar.construct
+ });
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Array.php b/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Array.php
new file mode 100644
index 00000000..af6e63d0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Array.php
@@ -0,0 +1,469 @@
+<?php
+/**
+ * Query format for arrays with features for Extensions 'Arrays' and 'HashTables'
+ *
+ * @file
+ * @ingroup SemanticResultFormats
+ * @author Daniel Werner < danweetz@web.de >
+ *
+ * Doesn't require 'Arrays' nor 'HashTables' exytensions but has additional features
+ * ('name' parameter in either result format) if they are available.
+ *
+ * Arrays 2.0+ and HashTables 1.0+ are recommended but not necessary.
+ */
+
+/**
+ * Array format
+ */
+class SRFArray extends SMWResultPrinter {
+
+ protected static $mDefaultSeps = [];
+ protected $mSep;
+ protected $mPropSep;
+ protected $mManySep;
+ protected $mRecordSep;
+ protected $mHeaderSep;
+ protected $mArrayName = null;
+ protected $mShowPageTitles;
+
+ protected $mHideRecordGaps;
+ protected $mHidePropertyGaps;
+
+ /**
+ * @var Boolean true if 'mainlabel' parameter is set to '-'
+ */
+ protected $mMainLabelHack = false;
+
+ public function __construct( $format, $inline = true ) {
+ parent::__construct( $format, $inline );
+ //overwrite parent default behavior for linking:
+ $this->mLinkFirst = false;
+ $this->mLinkOthers = false;
+ }
+
+ public function getQueryMode( $context ) {
+ return SMWQuery::MODE_INSTANCES;
+ }
+
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf_printername_array, srf_printername_hash
+ return wfMessage( 'srf_printername_' . $this->mFormat )->text();
+ }
+
+ /*
+ // By overwriting this function, we disable default searchlabel handling?
+ public function getResult( SMWQueryResult $results, array $params, $outputmode ) {
+ $this->handleParameters( $params, $outputmode );
+ return $this->getResultText( $results, $outputmode );
+ }
+ */
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ /*
+ * @todo
+ * labels of requested properties could define default values. Seems not possible at the moment because
+ * SMWPrintRequest::getLable() always returns the property name even if no specific label is defined.
+ */
+
+ $perPage_items = [];
+
+ //for each page:
+ while ( $row = $res->getNext() ) {
+ $perProperty_items = [];
+
+ /**
+ * first field is always the page title, except, mainlabel is set to '-'
+ *
+ * @todo Is there some other way to check the data value directly for being the
+ * page title or not? SMWs behavior could change on mainlabel handling...
+ */
+ $isPageTitle = !$this->mMainLabelHack;
+
+ //for each property on that page:
+ foreach ( $row as $field ) { // $row is array(), $field of type SMWResultArray
+ $manyValue_items = [];
+ $isMissingProperty = false;
+
+ $manyValues = $field->getContent();
+
+ //If property is not set (has no value) on a page:
+ if ( empty( $manyValues ) ) {
+ $delivery = $this->deliverMissingProperty( $field );
+ $manyValue_items = $this->fillDeliveryArray( $manyValue_items, $delivery );
+ $isMissingProperty = true;
+ } else //otherwise collect property value (potentially many values):
+ {
+ while ( $obj = $field->getNextDataValue() ) {
+
+ $value_items = [];
+ $isRecord = false;
+
+ // handle page Title:
+ if ( $isPageTitle ) {
+ if ( !$this->mShowPageTitles ) {
+ $isPageTitle = false;
+ continue 2; //next property
+ }
+ $value_items = $this->fillDeliveryArray(
+ $value_items,
+ $this->deliverPageTitle( $obj, $this->mLinkFirst )
+ );
+ } // handle record values:
+ elseif ( $obj instanceof SMWRecordValue ) {
+ $recordItems = $obj->getDataItems();
+ // walk all single values of the record set:
+ foreach ( $recordItems as $dataItem ) {
+ $recordField = $dataItem !== null ? SMWDataValueFactory::getInstance(
+ )->newDataValueByItem( $dataItem, null ) : null;
+ $value_items = $this->fillDeliveryArray(
+ $value_items,
+ $this->deliverRecordField( $recordField, $this->mLinkOthers )
+ );
+ }
+ $isRecord = true;
+ } // handle normal data values:
+ else {
+ $value_items = $this->fillDeliveryArray(
+ $value_items,
+ $this->deliverSingleValue( $obj, $this->mLinkOthers )
+ );
+ }
+ $delivery = $this->deliverSingleManyValuesData( $value_items, $isRecord, $isPageTitle );
+ $manyValue_items = $this->fillDeliveryArray( $manyValue_items, $delivery );
+ }
+ } // foreach...
+ $delivery = $this->deliverPropertiesManyValues(
+ $manyValue_items,
+ $isMissingProperty,
+ $isPageTitle,
+ $field
+ );
+ $perProperty_items = $this->fillDeliveryArray( $perProperty_items, $delivery );
+ $isPageTitle = false; // next one could be record or normal value
+ } // foreach...
+ $delivery = $this->deliverPageProperties( $perProperty_items );
+ $perPage_items = $this->fillDeliveryArray( $perPage_items, $delivery );
+ } // while...
+
+ $output = $this->deliverQueryResultPages( $perPage_items );
+
+ return $output;
+ }
+
+ protected function fillDeliveryArray( $array = [], $value = null ) {
+ if ( !is_null( $value ) ) { //don't create any empty entries
+ $array[] = $value;
+ }
+ return $array;
+ }
+
+ protected function deliverPageTitle( $value, $link = false ) {
+ return $this->deliverSingleValue( $value, $link );
+ }
+
+ protected function deliverRecordField( $value, $link = false ) {
+ if ( $value !== null ) // contains value
+ {
+ return $this->deliverSingleValue( $value, $link );
+ } elseif ( $this->mHideRecordGaps ) {
+ return null;
+ } // hide gap
+ else {
+ return '';
+ } // empty string will make sure that record value separators are generated
+ }
+
+ protected function deliverSingleValue( $value, $link = false ) {
+ //return trim( $value->getShortWikiText( $link ) );
+ return trim(
+ Sanitizer::decodeCharReferences( $value->getShortWikiText( $link ) )
+ ); // decode: better for further processing with array extension
+ }
+
+ // Property not declared on a page:
+ protected function deliverMissingProperty( SMWResultArray $field ) {
+ if ( $this->mHidePropertyGaps ) {
+ return null;
+ } else {
+ return '';
+ } //empty string will make sure that array separator will be generated
+ /** @ToDo: System for Default values?... * */
+ }
+
+ //represented by an array of record fields or just a single array value:
+ protected function deliverSingleManyValuesData( $value_items, $containsRecord, $isPageTitle ) {
+ if ( empty( $value_items ) ) //happens when one of the higher functions delivers null
+ {
+ return null;
+ }
+ return implode( $this->mRecordSep, $value_items );
+ }
+
+ protected function deliverPropertiesManyValues( $manyValue_items, $isMissingProperty, $isPageTitle, SMWResultArray $data ) {
+ if ( empty( $manyValue_items ) ) {
+ return null;
+ }
+
+ $text = implode( $this->mManySep, $manyValue_items );
+
+ // if property names should be displayed and this is not the page titles value:
+ if ( $this->mShowHeaders != SMW_HEADERS_HIDE && !$isPageTitle ) {
+ $linker = $this->mShowHeaders == SMW_HEADERS_PLAIN ? null : $this->mLinker;
+ $text = $data->getPrintRequest()->getText( SMW_OUTPUT_WIKI, $linker ) . $this->mHeaderSep . $text;
+ }
+ return $text;
+ }
+
+ protected function deliverPageProperties( $perProperty_items ) {
+ if ( empty( $perProperty_items ) ) {
+ return null;
+ }
+ return implode( $this->mPropSep, $perProperty_items );
+ }
+
+ protected function deliverQueryResultPages( $perPage_items ) {
+ if ( $this->mArrayName !== null ) {
+ $this->createArray( $perPage_items ); //create Array
+ return '';
+ } else {
+ return implode( $this->mSep, $perPage_items );
+ }
+ }
+
+ /**
+ * Helper function to create a new Array within 'Arrays' extension. Takes care of different versions
+ * as well as the old 'ArrayExtension'.
+ */
+ protected function createArray( $array ) {
+ global $wgArrayExtension;
+
+ $arrayId = $this->mArrayName;
+
+ if ( defined( 'ExtArrays::VERSION' ) ) {
+ // 'Arrays' extension 2+
+ global $wgParser;
+ /** ToDo: is there a way to get the actual parser which has started the query? */
+ ExtArrays::get( $wgParser )->createArray( $arrayId, $array );
+ return true;
+ }
+
+ // compatbility to 'ArrayExtension' extension before 2.0:
+
+ if ( !isset( $wgArrayExtension ) ) {
+ //Hash extension is not installed in this wiki
+ return false;
+ }
+ $version = null;
+ if ( defined( 'ArrayExtension::VERSION' ) ) {
+ $version = ArrayExtension::VERSION;
+ } elseif ( defined( 'ExtArrayExtension::VERSION' ) ) {
+ $version = ExtArrayExtension::VERSION;
+ }
+ if ( $version !== null && version_compare( $version, '1.3.2', '>=' ) ) {
+ // ArrayExtension 1.3.2+
+ $wgArrayExtension->createArray( $arrayId, $array );
+ } else {
+ // dirty way
+ $wgArrayExtension->mArrays[trim( $arrayId )] = $array;
+ }
+ return true;
+ }
+
+ protected function initializeCfgValue( $dfltVal, $dfltCacheKey ) {
+ $cache = &self::$mDefaultSeps[$dfltCacheKey];
+ if ( !isset( $cache ) ) {
+ $cache = $this->getCfgSepText( $dfltVal );
+ if ( $cache === null ) {
+ // cache can't be initialized, propably function-reference in userconfig
+ // but format is not used in inline context, use fallback in this case:
+ global $srfgArraySepTextualFallbacks;
+ $cache = $srfgArraySepTextualFallbacks[$dfltCacheKey];
+ }
+ }
+ return $cache;
+ }
+
+ protected function getCfgSepText( $obj ) {
+ if ( is_array( $obj ) ) {
+ // invalid definition:
+ if ( !array_key_exists( 0, $obj ) ) {
+ return null;
+ }
+
+ // check for config-defined arguments to pass to the page before processing it:
+ if ( array_key_exists( 'args', $obj ) && is_array( $obj['args'] ) ) {
+ $params = $obj['args'];
+ } else {
+ $params = [];
+ } // no arguments
+
+ // create title of page whose text should be used as separator:
+ $obj = Title::newFromText( $obj[0], ( array_key_exists( 1, $obj ) ? $obj[1] : NS_MAIN ) );
+ }
+ if ( $obj instanceof Title ) {
+ $article = new Article( $obj );
+ } elseif ( $obj instanceof Article ) {
+ $article = $obj;
+ } else {
+ return $obj; //only text
+ }
+
+ global $wgParser;
+ /*
+ * Feature to use page value as separator only works if Parser::parse() is running!
+ * That's not the case on semantic search special page for example!
+ */
+ // can't use $this->mInline here since SMW 1.6.2 had a bug setting it to false in most cases!
+ if ( !isset( $wgParser->mOptions ) ) {
+ //if( ! $this->mInline ) {
+ return null;
+ }
+
+ /*
+ * parse page as if it were included like a template. Never use Parser::recursiveTagParse() or similar
+ * for this since it would call hooks we don't want to call and won't return wiki text for inclusion!
+ */
+ $frame = $wgParser->getPreprocessor()->newCustomFrame( $params );
+ // compatibility for 1.19, getContent() was implemented in 1.21.
+ // FIXME: Remove when support for MediaWiki 1.19 is dropped
+ if ( method_exists( $article, 'getContent' ) ) {
+ $content = $article->getContent( Revision::RAW )->getNativeData();
+ } else {
+ $content = $article->getRawText();
+ }
+ $text = $wgParser->preprocessToDom( $content, Parser::PTD_FOR_INCLUSION );
+ $text = trim( $frame->expand( $text ) );
+
+ return $text;
+ }
+
+ protected function handleParameters( array $params, $outputmode ) {
+ // does the link parameter:
+ parent::handleParameters( $params, $outputmode );
+
+ //separators:
+ $this->mSep = $params['sep'];
+ $this->mPropSep = $params['propsep'];
+ $this->mManySep = $params['manysep'];
+ $this->mRecordSep = $params['recordsep'];
+ $this->mHeaderSep = $params['headersep'];
+
+ // only use this in inline mode, if text is given. Since SMW 1.6.2 '' is given, so if
+ // we wouldn't check, we would always end up with an array instead of visible output
+ if ( $params['name'] !== false && ( $this->mInline || trim( $params['name'] ) !== '' ) ) {
+ $this->mArrayName = trim( $params['name'] );
+ $this->createArray(
+ []
+ ); //create empty array in case we get no result so we won't have an undefined array in the end.
+ }
+
+ // if mainlabel set to '-', this will cause the titles not to appear, so make sure we catch this!
+ $this->mMainLabelHack = trim( $params['mainlabel'] ) === '-';
+
+ // whether or not to display the page title:
+ $this->mShowPageTitles = strtolower( $params['titles'] ) != 'hide';
+
+ switch ( strtolower( $params['hidegaps'] ) ) {
+ case 'none':
+ $this->mHideRecordGaps = false;
+ $this->mHidePropertyGaps = false;
+ break;
+ case 'all':
+ $this->mHideRecordGaps = true;
+ $this->mHidePropertyGaps = true;
+ break;
+ case 'property':
+ case 'prop':
+ case 'attribute':
+ case 'attr':
+ $this->mHideRecordGaps = false;
+ $this->mHidePropertyGaps = true;
+ break;
+ case 'record':
+ case 'rec':
+ case 'rcrd':
+ case 'n-ary':
+ case 'nary':
+ $this->mHideRecordGaps = true;
+ $this->mHidePropertyGaps = false;
+ break;
+ }
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ ### adjusted basic SMW params: ###
+
+ $definitions['limit']->setDefault( $GLOBALS['smwgQMaxInlineLimit'] );
+ $definitions['link']->setDefault( 'none' );
+ $definitions['headers']->setDefault( 'hide' );
+
+ ### new params: ###
+
+ $params['titles'] = [
+ 'message' => 'srf_paramdesc_pagetitle',
+ 'values' => [ 'show', 'hide' ],
+ 'aliases' => [ 'pagetitle', 'pagetitles' ],
+ 'default' => 'show',
+ ];
+
+ $params['hidegaps'] = [
+ 'message' => 'srf_paramdesc_hidegaps',
+ 'values' => [ 'none', 'all', 'property', 'record' ],
+ 'default' => 'none',
+ ];
+
+ $params['name'] = [
+ 'message' => 'srf_paramdesc_arrayname',
+ 'default' => false,
+ 'manipulatedefault' => false,
+ ];
+
+ // separators (default values are defined in the following globals:)
+ global $srfgArraySep, $srfgArrayPropSep, $srfgArrayManySep, $srfgArrayRecordSep, $srfgArrayHeaderSep;
+
+ $params['sep'] = [
+ 'message' => 'smw-paramdesc-sep',
+ 'default' => $this->initializeCfgValue( $srfgArraySep, 'sep' ),
+ ];
+
+ $params['propsep'] = [
+ 'message' => 'srf_paramdesc_propsep',
+ 'default' => $this->initializeCfgValue( $srfgArrayPropSep, 'propsep' ),
+ ];
+
+ $params['manysep'] = [
+ 'message' => 'srf_paramdesc_manysep',
+ 'default' => $this->initializeCfgValue( $srfgArrayManySep, 'manysep' ),
+ ];
+
+ $params['recordsep'] = [
+ 'message' => 'srf_paramdesc_recordsep',
+ 'default' => $this->initializeCfgValue( $srfgArrayRecordSep, 'recordsep' ),
+ 'aliases' => [ 'narysep', 'rcrdsep', 'recsep' ],
+ ];
+
+ $params['headersep'] = [
+ 'message' => 'srf_paramdesc_headersep',
+ 'default' => $this->initializeCfgValue( $srfgArrayHeaderSep, 'headersep' ),
+ 'aliases' => [ 'narysep', 'rcrdsep', 'recsep' ],
+ ];
+
+ return $params;
+ }
+
+}
+
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Hash.php b/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Hash.php
new file mode 100644
index 00000000..0d3083fa
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/array/SRF_Hash.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * Query format for arrays with features for Extensions 'Arrays' and 'HashTables'
+ *
+ * @file
+ * @ingroup SemanticResultFormats
+ * @author Daniel Werner < danweetz@web.de >
+ *
+ * Doesn't require 'Arrays' nor 'HashTables' exytensions but has additional features
+ * ('name' parameter in either result format) if they are available.
+ *
+ * Arrays 2.0+ and HashTables 1.0+ are recommended but not necessary.
+ */
+class SRFHash extends SRFArray {
+
+ protected $mLastPageTitle;
+
+ protected function deliverPageTitle( $value, $link = false ) {
+ $this->mLastPageTitle = $this->deliverSingleValue( $value, $link ); //remember the page title
+ return null; //don't add page title into property list
+ }
+
+ protected function deliverPageProperties( $perProperty_items ) {
+ if ( count( $perProperty_items ) < 1 ) {
+ return null;
+ }
+ return [ $this->mLastPageTitle, implode( $this->mPropSep, $perProperty_items ) ];
+ }
+
+ protected function deliverQueryResultPages( $perPage_items ) {
+ $hash = [];
+ foreach ( $perPage_items as $page ) {
+ $hash[$page[0]] = $page[1]; //name of page as key, Properties as value
+ }
+ return parent::deliverQueryResultPages( $hash );
+ }
+
+ protected function createArray( $hash ) {
+ global $wgHashTables;
+
+ $hashId = $this->mArrayName;
+ $version = null;
+ if ( defined( 'ExtHashTables::VERSION' ) ) {
+ $version = ExtHashTables::VERSION;
+ }
+ if ( $version !== null && version_compare( $version, '0.999', '>=' ) ) {
+ // Version 1.0+, doesn't use $wgHashTables anymore
+ global $wgParser;
+ /** ToDo: is there a way to get the actual parser which has started the query? */
+ ExtHashTables::get( $wgParser )->createHash( $hashId, $hash );
+ } elseif ( !isset( $wgHashTables ) ) {
+ // Hash extension is not installed in this wiki
+ return false;
+ } elseif ( $version !== null && version_compare( $version, '0.6', '>=' ) ) {
+ // HashTables 0.6 to 1.0
+ $wgHashTables->createHash( $hashId, $hash );
+ } else {
+ // old HashTables, dirty way
+ $wgHashTables->mHashTables[trim( $hashId )] = $hash;
+ }
+ return true;
+ }
+
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+ $this->mShowPageTitles = true;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param IParamDefinition[] $definitions
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ unset( $params['pagetitle'] ); // page title is Hash key, otherwise, just use Array format!
+ $params['name']['message'] = 'srf_paramdesc_hashname';
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/SRF_Boilerplate.php b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/SRF_Boilerplate.php
new file mode 100644
index 00000000..dc96a6b8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/SRF_Boilerplate.php
@@ -0,0 +1,296 @@
+<?php
+
+/**
+ * Boilerplate query printer
+ *
+ * Add your description here ...
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/Writing_result_printers
+ *
+ * @since 1.8
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+/**
+ * Description ... this part is used for the doxygen processor
+ *
+ * @ingroup SemanticResultFormats
+ */
+class SRFBoilerplate extends SMWResultPrinter {
+
+ /**
+ * @see SMWResultPrinter::getName
+ * @return string
+ */
+ public function getName() {
+ // Add your result printer name here
+ return wfMessage( 'srf-printername-boilerplate' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputMode ) {
+
+ // Data processing
+ // It is advisable to separate data processing from output logic
+ $data = $this->getResultData( $result, $outputMode );
+
+ // Check if the data processing returned any results otherwise just bailout
+ if ( $data === [] ) {
+ // Add an error message to return method
+ return $result->addErrors( [ wfMessage( 'srf-no-results' )->inContentLanguage()->text() ] );
+ } else {
+ // Add options if needed to format the output
+
+ // $outputMode can be specified as
+ // SMW_OUTPUT_HTML
+ // SMW_OUTPUT_FILE
+ // SMW_OUTPUT_WIKI
+
+ // For implementing template support this options has to be set but if you
+ // manipulate data via jQuery/JavaScript it is less likely that you need
+ // this option since templates will influence how wiki text is parsed
+ // but will have no influence in how a HTML representation is altered
+ // $this->hasTemplates = true;
+
+ $options = [
+ 'mode' => $outputMode
+ ];
+
+ // Return formatted results
+ return $this->getFormatOutput( $data, $options );
+ }
+ }
+
+ /**
+ * Returns an array with data
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultData( SMWQueryResult $result, $outputMode ) {
+
+ $data = [];
+
+ // This is an example implementation on how to select available data from
+ // a result set. Please make appropriate adoptions necessary for your
+ // application.
+
+ // Some methods are declared as private to show case which objects are
+ // directly accessible within SMWQueryResult
+
+ // Get all SMWDIWikiPage objects that make up the results
+ // $subjects = $this->getSubjects( $result->getResults() );
+
+ // Get all print requests property labels
+ // $labels = $this->getLabels( $result->getPrintRequests() );
+
+ /**
+ * Get all values for all rows that belong to the result set
+ *
+ * @var SMWResultArray $rows
+ */
+ while ( $rows = $result->getNext() ) {
+
+ /**
+ * @var SMWResultArray $field
+ * @var SMWDataValue $dataValue
+ */
+ foreach ( $rows as $field ) {
+
+ // Initialize the array each time it passes a new row to avoid data from
+ // a previous row is remaining
+ $rowData = [];
+
+ // Get the label for the current property
+ $propertyLabel = $field->getPrintRequest()->getLabel();
+
+ // Get the label for the current subject
+ // getTitle()->getText() will return only the main text without the
+ // fragment(#) which can be arbitrary in case subobjects are involved
+
+ // getTitle()->getFullText() will return the text with the fragment(#)
+ // which is important when using subobjects
+ $subjectLabel = $field->getResultSubject()->getTitle()->getFullText();
+
+ while ( ( $dataValue = $field->getNextDataValue() ) !== false ) {
+
+ // Get the data value item
+ $rowData[] = $this->getDataValueItem( $dataValue->getDataItem()->getDIType(), $dataValue );
+ }
+
+ // Example how to build a hierarchical array by collecting all values
+ // belonging to one subject/row using labels as array key representation
+ $data[$subjectLabel][$propertyLabel][] = $rowData;
+ }
+ }
+
+ // Return the data
+ // return array( 'labels' => $labels, 'subjects' => $subjects, 'data' => $data );
+ return $data;
+ }
+
+ /**
+ * A quick getway method to find all SMWDIWikiPage objects that make up the results
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ *
+ * @return array
+ */
+ private function getSubjects( $result ) {
+ $subjects = [];
+
+ foreach ( $result as $wikiDIPage ) {
+ $subjects[] = $wikiDIPage->getTitle()->getText();
+ }
+ return $subjects;
+ }
+
+ /**
+ * Get all print requests property labels
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ *
+ * @return array
+ */
+ private function getLabels( $result ) {
+ $printRequestsLabels = [];
+
+ foreach ( $result as $printRequests ) {
+ $printRequestsLabels[] = $printRequests->getLabel();
+ }
+ return $printRequestsLabels;
+ }
+
+ /**
+ * Get a single data value item
+ *
+ * @since 1.8
+ *
+ * @param integer $type
+ * @param SMWDataValue $dataValue
+ *
+ * @return mixed
+ */
+ private function getDataValueItem( $type, SMWDataValue $dataValue ) {
+
+ if ( $type == SMWDataItem::TYPE_NUMBER ) {
+
+ // Set unit if available
+ $dataValue->setOutputFormat( $this->params['unit'] );
+
+ // Check if unit is available and return the converted value otherwise
+ // just return a plain number
+ return $dataValue->getUnit() !== '' ? $dataValue->getShortWikiText() : $dataValue->getNumber();
+ } else {
+
+ // For all other data types return the wikivalue
+ return $dataValue->getWikiValue();
+ }
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ * @param array $options
+ *
+ * @return string
+ */
+ protected function getFormatOutput( $data, $options ) {
+
+ // The generated ID is to distinguish similar instances of the same
+ // printer that can appear within the same page
+ static $statNr = 0;
+ $ID = 'srf-boilerplate-' . ++$statNr;
+
+ // or use the PHP uniqid() to generate an unambiguous ID
+ // $ID = uniqid();
+
+ // Used to set that the output and being treated as HTML (opposed to plain wiki text)
+ $this->isHTML = true;
+
+ // Correct escaping is vital to minimize possibilites of malicious code snippets
+ // and also a coherent string evalution therefore it is recommended
+ // that data transferred to the JS plugin is JSON encoded
+
+ // Assign the ID to make a data instance readly available and distinguishable
+ // from other content within the same page
+ $requireHeadItem = [ $ID => FormatJson::encode( $data ) ];
+ SMWOutputs::requireHeadItem( $ID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // Add resource definitions that has been registered with SRF_Resource.php
+ // Resource definitions contain scripts, styles, messages etc.
+ // SMWOutputs::requireResource( 'ext.srf.boilerplate.namespace' );
+ SMWOutputs::requireResource( 'ext.srf.boilerplate.simple' );
+
+ // Prepares an HTML element showing a rotating spinner indicating that something
+ // will appear at this placeholder. The element will be visible as for as
+ // long as jquery is not loaded and the JS plugin did not hide/removed the element.
+ $processing = SRFUtils::htmlProcessingElement();
+
+ // Add two elements a outer wrapper that is assigned a class which the JS plugin
+ // can select and will fetch all instances of the same result printer and an innner
+ // container which is set invisible (display=none) for as long as the JS plugin
+ // holds the content hidden. It is normally the place where the "hard work"
+ // is done hidden from the user until it is ready.
+ // The JS plugin can prepare the output within this container without presenting
+ // unfinished visual content, to avoid screen clutter and improve user experience.
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-boilerplate'
+ ],
+ $processing . Html::element(
+ 'div',
+ [
+ 'id' => $ID,
+ 'class' => 'container',
+ 'style' => 'display:none;'
+ ],
+ null
+ )
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ // Add your parameters here
+
+ // Example of a unit paramter
+ $params['unit'] = [
+ 'message' => 'srf-paramdesc-unit',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.css b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.css
new file mode 100644
index 00000000..3eddcfdb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.css
@@ -0,0 +1,11 @@
+/**
+ * CSS for SRF boilerplate
+ *
+ * @since 1.8
+ * @release 0.2
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+/* Place your CSS in here ... */ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.namespace.js b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.namespace.js
new file mode 100644
index 00000000..d2b1e66b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.namespace.js
@@ -0,0 +1,109 @@
+/**
+ * JavaScript for SRF boilerplate format using the semanticFormats namespace
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Boilerplate format
+ *
+ * Please remember to add your documentation to http://www.semantic-mediawiki.org
+ *
+ * @since 1.8
+ * @release 0.1
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+
+ // Use EcmaScript 5 to improve code quality and check with jshint/jslint
+ // if the code adheres standard coding conventions
+
+ // Strict mode eliminates some JavaScript pitfalls
+ 'use strict';
+
+ // Passing jshint
+ /*global mediaWiki:true, semanticFormats:true*/
+
+ /**
+ * Module for formats extensions
+ * @since 1.8
+ * @type Object
+ */
+
+ // Ensure the namespace is initialized and available
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a boilerplate instance
+ * @since 1.8
+ * @type Object
+ */
+
+ // If you have default values to be set during the instantiation
+ // $.extend ... can be used here
+ srf.formats.boilerplate = function() {};
+
+ srf.formats.boilerplate.prototype = {
+ // Specify your functions and parameters
+ show: function( context ) {
+ return context.each( function() {
+
+ // Ensure variables have only local scope otherwise leaked content might
+ // cause issues for other plugins
+ var $this = $( this );
+
+ // Find the container instance that was created by the PHP output
+ // and store it as "container" variable which all preceding steps
+ // working on a localized instance
+ var container = $this.find( '.container' );
+
+ // Find the ID that connects to the current instance with the published data
+ var ID = container.attr( 'id' );
+
+ // Fetch the stored data with help of mw.config.get() method and the current instance ID
+ // @see http://www.mediawiki.org/wiki/ResourceLoader/Default_modules#mediaWiki.config
+ var json = mw.config.get( ID );
+
+ // Parse the fetched json string and convert it back into objects/arrays
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ // Hide the spinner which belongs to the outer wrapper
+ // Use the utility function here which makes it easier as no explicit knowledge
+ // of a class selector is needed
+ util.spinner.hide( { context: $this } );
+
+ // You got everything you need to work your magic
+ // A clean instance, data from the wiki, and a separate container
+
+ // If you need to see what data you've got from your result printer
+ // it is always helpfull to do
+
+ // console.log( data );
+
+ // Happy coding ...
+
+ } );
+ }
+ };
+
+ /**
+ * Implementation and representation of the boilerplate instance
+ * @since 1.8
+ * @type Object
+ */
+
+ // Create class instance
+ var boilerplate = new srf.formats.boilerplate();
+
+ // Get access to SRF specific utilities function
+ var util = new srf.util();
+
+ $( document ).ready(function() {
+
+ // Use the class selector to find all instances relevant to the "boilerplate" printer
+ // since a wiki page can have more than one instance of the same result printer
+ // .each() ensures instances are handled separately
+ $( '.srf-boilerplate' ).each(function() {
+
+ // Access methods available through the boilerplate class
+ boilerplate.show( $( this ) );
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.simple.js b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.simple.js
new file mode 100644
index 00000000..c7d9b3de
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/boilerplate/resources/ext.srf.boilerplate.simple.js
@@ -0,0 +1,70 @@
+/**
+ * JavaScript for SRF boilerplate format
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Boilerplate format
+ *
+ * Please remember to add your documentation to http://www.semantic-mediawiki.org
+ *
+ * @since 1.8
+ * @release 0.1
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $ ) {
+
+ // Use EcmaScript 5 to improve code quality and check with jshint/jslint
+ // if the code adheres standard coding conventions
+
+ // Strict mode eliminates some JavaScript pitfalls
+ 'use strict';
+
+ // Passing jshint
+ /*global mw:true */
+
+ /**
+ * Document ready instance
+ * @since 1.8
+ * @type Object
+ */
+ $( document ).ready( function() {
+
+ // Use the class selector to find all instances relevant to the "boilerplate" printer
+ // since a wiki page can have more than one instance of the same result printer
+ // .each() ensures instances are handled separately
+ $( '.srf-boilerplate' ).each( function() {
+
+ // Ensure variables have only local scope otherwise leaked content might
+ // cause issues for other plugins
+ var $this = $( this );
+
+ // Find the container instance that was created by the PHP output
+ // and store it as "container" variable which all preceding steps
+ // working on a localized instance
+ var container = $this.find( '.container' );
+
+ // Find the ID that connects to the current instance with the published data
+ var ID = container.attr( 'id' );
+
+ // Fetch the stored data with help of mw.config.get() method and the current instance ID
+ // @see http://www.mediawiki.org/wiki/ResourceLoader/Default_modules#mediaWiki.config
+ var json = mw.config.get( ID );
+
+ // Parse the fetched json string and convert it back into objects/arrays
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ // Hide the spinner which belongs to the outer wrapper
+ $this.find( '.srf-spinner' ).hide();
+
+ // You got everything you need to work your magic
+ // A clean instance, data from the wiki, and a separate container
+
+ // If you need to see what data you've got from your result printer it is
+ // always helpfull to do
+
+ // console.log( data );
+
+ // Happy coding ...
+
+ } );
+ } );
+} )( jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/EventCalendar.php b/www/wiki/extensions/SemanticResultFormats/formats/calendar/EventCalendar.php
new file mode 100644
index 00000000..f9e1a795
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/EventCalendar.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace SRF;
+
+use Html;
+use SMW\ResultPrinter;
+use SMWQueryResult as QueryResult;
+
+/**
+ * An event calendar printer using the FullCalendar JavaScript library
+ * and SMWAPI.
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup QueryPrinter
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Query printer supporting a JavaScript Event calendar using the
+ * Semantic MediaWiki Api
+ *
+ * @ingroup QueryPrinter
+ */
+class EventCalendar extends ResultPrinter {
+
+ /**
+ * @see ResultPrinter::getName
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return $this->msg( 'srf-printername-eventcalendar' )->text();
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['defaultview'] = [
+ 'message' => 'srf-paramdesc-calendardefaultview',
+ 'default' => 'month',
+ 'values' => [
+ 'month',
+ 'basicweek',
+ 'basicday',
+ 'agendaweek',
+ 'agendaday',
+ 'listday',
+ 'listweek',
+ 'listmonth' ]
+ ];
+
+ $params['views'] = [
+ 'message' => 'srf-paramdesc-calendarviews',
+ 'default' => 'month,basicWeek,agendaDay'
+ ];
+ $params['firstday'] = [
+ 'message' => 'srf-paramdesc-calendarfirstday',
+ 'default' => 'Sunday',
+ 'values' => [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]
+ ];
+
+ $params['start'] = [
+ 'message' => 'srf-paramdesc-calendarstart',
+ 'default' => 'current',
+ 'values' => [ 'current', 'earliest', 'latest' ]
+ ];
+
+ $params['legend'] = [
+ 'message' => 'srf-paramdesc-calendarlegend',
+ 'default' => 'none',
+ 'values' => [ 'none', 'top', 'bottom', 'tooltip', 'pane' ]
+ ];
+
+ $params['dayview'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-dayview',
+ 'default' => false
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['theme'] = [
+ 'message' => 'srf-paramdesc-theme',
+ 'default' => 'basic',
+ 'values' => [ 'basic', 'vector' ]
+ ];
+
+ $params['clicktarget'] = [
+ 'message' => 'srf-paramdesc-clicktarget',
+ 'default' => 'none'
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ *
+ * {@inheritDoc}
+ */
+ protected function getResultText( QueryResult $res, $outputmode ) {
+
+ $resourceFormatter = new ResourceFormatter();
+ $data = $resourceFormatter->getData( $res, $outputmode, $this->params );
+
+ $this->isHTML = true;
+ $id = $resourceFormatter->session();
+
+ // Add options
+ $data['version'] = '0.8.0';
+
+ // Encode data object
+ $resourceFormatter->encode( $id, $data );
+
+ // Init RL module
+ $resourceFormatter->registerResources( [ 'ext.srf.eventcalendar' ] );
+
+ // Element includes info, spinner, and container placeholder
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-eventcalendar',
+ 'data-external-class' => ( $this->params['class'] ? $this->params['class'] : '' )
+ ],
+ Html::element(
+ 'div',
+ [
+ 'class' => 'srf-top'
+ ],
+ ''
+ ) . $resourceFormatter->placeholder() . Html::element(
+ 'div',
+ [
+ 'id' => $id,
+ 'class' => 'srf-container',
+ 'style' => 'display:none;'
+ ]
+ )
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRFC_HistoricalDate.php b/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRFC_HistoricalDate.php
new file mode 100644
index 00000000..7622a66b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRFC_HistoricalDate.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * SRFC_HistoricalDate.php
+ *
+ * This code is lifted from Terry Hurlbut's 'SMW_DV_HxDate.php' class;
+ * that code was itself adapted from the Fourmilab Calendar Converter
+ * Javascripts by John Walker, who wrote them in 1999 and released them
+ * to the public domain.
+ *
+ * The internal value, unlike that of the standard SMW Date type, is a
+ * 64-bit PHP float. The characteristic gives the days since
+ * the epoch.
+ *
+ * Technically, the Julian calendar is valid only beginning January 1, 45 BC,
+ * when Julius Caesar established it as per a formal Senatus consultum. But
+ * currently this is the only calendar currently projectible to earlier times;
+ * therefore Julian dates are valid for any year in the Julian Period.
+ *
+ * @author Terry A. Hurlbut
+ * @author Yaron Koren
+ */
+class SRFCHistoricalDate {
+
+ const GREGORIAN_EPOCH = 1721425.5; // equivalent to 1 AD
+
+ protected $m_date; // the Julian day
+
+ function create( $year, $month, $day ) {
+ if ( $year < 1582 ||
+ ( $year == 1582 && ( $month < 10 || ( $month == 10 && $day < 15 ) ) ) ) {
+ $this->createFromJulian( $year, $month, $day );
+ } else {
+ $this->createFromGregorian( $year, $month, $day );
+ }
+ }
+
+ static protected function leap_gregorian( $year ) {
+ return ( ( $year % 4 ) == 0 ) && ( !( ( ( $year % 100 ) == 0 ) && ( ( $year % 400 ) != 0 ) ) );
+ }
+
+ static protected function leap_julian( $year ) {
+ return ( ( $year % 4 ) == ( ( $year > 0 ) ? 0 : 3 ) );
+ }
+
+ static protected function leap_jul_greg( $year ) {
+ return ( ( $year < 1582 ) ? SRFCHistoricalDate::leap_julian( $year ) : SRFCHistoricalDate::leap_gregorian(
+ $year
+ ) );
+ }
+
+ protected function createFromGregorian( $year, $month, $day ) {
+ $this->m_date = ( self::GREGORIAN_EPOCH - 1 ) +
+ ( 365 * ( $year - 1 ) ) +
+ floor( ( $year - 1 ) / 4 ) +
+ ( -floor( ( $year - 1 ) / 100 ) ) +
+ floor( ( $year - 1 ) / 400 ) +
+ floor(
+ ( ( ( 367 * $month ) - 362 ) / 12 ) +
+ ( ( $month <= 2 ) ? 0 :
+ ( SRFCHistoricalDate::leap_gregorian( $year ) ? -1 : -2 )
+ ) + $day
+ );
+ }
+
+ protected function createFromJulian( $year, $month, $day ) {
+
+ /* Adjust negative common era years to the zero-based notation we use. */
+ if ( $year < 1 ) {
+ $year++;
+ }
+
+ /* Algorithm as given in Meeus, Astronomical Algorithms, Chapter 7, page 61 */
+ if ( $month <= 2 ) {
+ $year--;
+ $month += 12;
+ }
+
+ $this->m_date = ( ( floor( ( 365.25 * ( $year + 4716 ) ) ) +
+ floor( ( 30.6001 * ( $month + 1 ) ) ) +
+ $day ) - 1524.5 );
+ }
+
+ public function getDayOfWeek() {
+ return ( floor( $this->m_date + 1.5 ) % 7 );
+ }
+
+ static function daysInMonth( $year, $month ) {
+ if ( $month == 4 || $month == 6 || $month == 9 || $month == 11 ) {
+ return 30;
+ }
+ if ( $month == 2 ) {
+ return ( SRFCHistoricalDate::leap_jul_greg( $year ) ) ? 29 : 28;
+ }
+ return 31;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRF_Calendar.php b/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRF_Calendar.php
new file mode 100644
index 00000000..31579286
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/SRF_Calendar.php
@@ -0,0 +1,694 @@
+<?php
+
+$wgAutoloadClasses['SRFCHistoricalDate'] = dirname( __FILE__ )
+ . '/SRFC_HistoricalDate.php';
+
+/**
+ * Result printer that prints query results as a monthly calendar.
+ *
+ * @file SRF_Calendar.php
+ * @ingroup SemanticResultFormats
+ *
+ * @author Yaron Koren
+ */
+class SRFCalendar extends SMWResultPrinter {
+
+ protected $mTemplate;
+ protected $mUserParam;
+ protected $mRealUserLang = null;
+ protected $mStartMonth;
+ protected $mStartYear;
+
+ protected function setColors( $colorsText ) {
+ $colors = [];
+ $colorElements = explode( ',', $colorsText );
+ foreach ( $colorElements as $colorElem ) {
+ $propAndColor = explode( '=>', $colorElem );
+ if ( count( $propAndColor ) == 2 ) {
+ $colors[$propAndColor[0]] = $propAndColor[1];
+ }
+ }
+ $this->mColors = $colors;
+ }
+
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ $this->mTemplate = trim( $params['template'] );
+ $this->mUserParam = trim( $params['userparam'] );
+ // startmonth is initialized with current month by default
+ $this->mStartMonth = trim( $params['startmonth'] );
+ // startyear is initialized with current year by default
+ $this->mStartYear = trim( $params['startyear'] );
+
+ if ( $params['lang'] !== false ) {
+ global $wgLang;
+ // Store the actual user's language, so we can revert
+ // back to it after printing the calendar.
+ $this->mRealUserLang = clone ( $wgLang );
+ $wgLang = Language::factory( trim( $params['lang'] ) );
+ }
+
+ $this->setColors( $params['colors'] );
+ }
+
+ public function getName() {
+ return wfMessage( 'srf_printername_calendar' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::buildResult
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $results
+ *
+ * @return string
+ */
+ protected function buildResult( SMWQueryResult $results ) {
+ $this->isHTML = false;
+ $this->hasTemplates = false;
+
+ // Skip checks - results with 0 entries are normal.
+ return $this->getResultText( $results, SMW_OUTPUT_HTML );
+ }
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getResultText()
+ *
+ * @todo Split up megamoth
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ $events = [];
+
+ // Print all result rows.
+ while ( $row = $res->getNext() ) {
+ $dates = [];
+ $title = $text = $color = '';
+
+ if ( $this->mTemplate != '' ) {
+ // Build template code
+ $this->hasTemplates = true;
+
+ if ( $this->mUserParam ) {
+ $text = "|userparam=$this->mUserParam";
+ }
+
+ foreach ( $row as $i => $field ) {
+ $pr = $field->getPrintRequest();
+ $text .= '|' . ( $i + 1 ) . '=';
+
+ while (
+ ( $object = $field->getNextDataValue() ) !== false
+ ) {
+ if ( $object->getTypeID() == '_dat' ) {
+ $text .= $object->getLongWikiText();
+
+ // use shorter "LongText" for wikipage
+ } elseif ( $object->getTypeID() == '_wpg' ) {
+ // handling of "link=" param
+ if ( $this->mLinkOthers ) {
+ $text .=
+ $object->getLongText( $outputmode, null );
+ } else {
+ $text .= $object->getWikiValue();
+ }
+ } else {
+ $text .= $object->getShortText( $outputmode, null );
+ }
+
+ if (
+ $pr->getMode() == SMWPrintRequest::PRINT_PROP &&
+ $pr->getTypeID() == '_dat'
+ ) {
+ $datePropLabel = $pr->getLabel();
+ if ( !array_key_exists( $datePropLabel, $dates ) ) {
+ $dates[$datePropLabel] = [];
+ }
+ $dates[$datePropLabel][] =
+ $this->formatDateStr( $object );
+ }
+ }
+ }
+ } else {
+ // Build simple text.
+ $numNonDateProperties = 0;
+ // Cycle through a 'row', which is the page
+ // name (the first field) plus all its
+ // properties.
+ foreach ( $row as $i => $field ) {
+ $pr = $field->getPrintRequest();
+ // A property can have more than one
+ // value - cycle through all the values
+ // for this property.
+ $textForProperty = '';
+
+ while (
+ ( $object = $field->getNextDataValue() ) !== false
+ ) {
+ if ( $object->getTypeID() == '_dat' ) {
+ // Don't add date values to the display.
+
+ // use shorter "LongText" for wikipage
+ } elseif ( $object->getTypeID() == '_wpg' ) {
+ if ( $i == 0 ) {
+ $title = Title::newFromText(
+ $object->getShortWikiText( false )
+ );
+ } else {
+ $numNonDateProperties++;
+
+ // handling of "headers=" param
+ if ( $this->mShowHeaders == SMW_HEADERS_SHOW ) {
+ $textForProperty .= $pr->getHTMLText(
+ smwfGetLinker()
+ ) . ' ';
+ } elseif (
+ $this->mShowHeaders == SMW_HEADERS_PLAIN
+ ) {
+ $textForProperty .= $pr->getLabel() . ' ';
+ }
+
+ // If $this->mShowHeaders == SMW_HEADERS_HIDE,
+ // print nothing.
+ // handling of "link=" param
+ if ( $this->mLinkOthers ) {
+ $textForProperty .= $object->getLongText(
+ $outputmode,
+ smwfGetLinker()
+ );
+ } else {
+ $textForProperty .= $object->getWikiValue();
+ }
+ }
+ } else {
+ $numNonDateProperties++;
+ $textForProperty .=
+ $pr->getHTMLText( smwfGetLinker() )
+ . ' ' . $object->getShortText(
+ $outputmode,
+ smwfGetLinker()
+ );
+ }
+ if (
+ $pr->getMode() == SMWPrintRequest::PRINT_PROP &&
+ $pr->getTypeID() == '_dat'
+ ) {
+ $datePropLabel = $pr->getLabel();
+ if ( !array_key_exists( $datePropLabel, $dates ) ) {
+ $dates[$datePropLabel] = [];
+ }
+ $dates[$datePropLabel][] =
+ $this->formatDateStr( $object );
+ }
+ }
+
+ // Add the text for this property to
+ // the main text, adding on parentheses
+ // or commas as needed.
+ if ( $numNonDateProperties == 1 ) {
+ $text .= ' (';
+ } elseif ( $numNonDateProperties > 1 ) {
+ $text .= ', ';
+ }
+ $text .= $textForProperty;
+ }
+ if ( $numNonDateProperties > 0 ) {
+ $text .= ')';
+ }
+ }
+
+ if ( count( $dates ) > 0 ) {
+ // Handle the 'color=' value, whether it came
+ // from a compound query or a regular one.
+ $resSubject = $field->getResultSubject();
+ if ( isset( $resSubject->display_options )
+ && is_array( $resSubject->display_options ) ) {
+ if ( array_key_exists(
+ 'color',
+ $resSubject->display_options
+ )
+ ) {
+ $color = $resSubject->display_options['color'];
+ }
+ if (
+ array_key_exists(
+ 'colors',
+ $resSubject->display_options
+ )
+ ) {
+ $this->setColors(
+ $resSubject->display_options['colors']
+ );
+ }
+ }
+
+ foreach ( $dates as $label => $datesForLabel ) {
+ foreach ( $datesForLabel as $date ) {
+ $curText = $text;
+ // If there's more than one
+ // label, i.e. more than one
+ // date property being displayed,
+ // show the name of the current
+ // property in parentheses.
+ if ( count( $dates ) > 1 ) {
+ $curText = "($label) " . $curText;
+ }
+ $curColor = $color;
+ if ( array_key_exists( $label, $this->mColors ) ) {
+ $curColor = $this->mColors[$label];
+ }
+ $events[] = [ $title, $curText, $date, $curColor ];
+ }
+ }
+ }
+ }
+
+ $result = $this->displayCalendar( $events );
+
+ // Go back to the actual user's language, in case a different
+ // language had been specified for this calendar.
+ if ( !is_null( $this->mRealUserLang ) ) {
+ global $wgLang;
+ $wgLang = $this->mRealUserLang;
+ }
+
+ global $wgParser;
+
+ if ( is_null( $wgParser->getTitle() ) ) {
+ return $result;
+ } else {
+ return [ $result, 'noparse' => 'true', 'isHTML' => 'true' ];
+ }
+ }
+
+ protected static function intToMonth( $int ) {
+ $months = [
+ '1' => 'january',
+ '2' => 'february',
+ '3' => 'march',
+ '4' => 'april',
+ '5' => 'may_long',
+ '6' => 'june',
+ '7' => 'july',
+ '8' => 'august',
+ '9' => 'september',
+ '10' => 'october',
+ '11' => 'november',
+ '12' => 'december',
+ ];
+
+ return wfMessage(
+ array_key_exists( $int, $months )
+ ? $months[$int]
+ : 'january'
+ )->inContentLanguage()->text();
+ }
+
+ function formatDateStr( $object ) {
+ // For some reason, getMonth() and getDay() sometimes return a
+ // number with a leading zero - get rid of it using (int)
+ return $object->getYear()
+ . '-' . (int)$object->getMonth() . '-' . (int)$object->getDay();
+ }
+
+ function displayCalendar( $events ) {
+ global $wgParser;
+ global $srfgFirstDayOfWeek;
+ global $srfgScriptPath;
+
+ $context = RequestContext::getMain();
+ $request = $context->getRequest();
+ if ( !$wgParser->mFirstCall ) {
+ $wgParser->disableCache();
+ }
+
+ $context->getOutput()->addLink(
+ [
+ 'rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'media' => 'screen, print',
+ 'href' => $srfgScriptPath
+ . '/formats/calendar/resources/ext.srf.calendar.css'
+ ]
+ );
+
+ // Set variables differently depending on whether this is
+ // being called from a regular page, via #ask, or from a
+ // special page: most likely either Special:Ask or
+ // Special:RunQuery.
+ $pageTitle = $context->getTitle();
+ if ( !$pageTitle ) {
+ $pageTitle = $wgParser->getTitle();
+ }
+ $additionalQueryString = '';
+ $hiddenInputs = '';
+
+ if ( $pageTitle->isSpecialPage() ) {
+ $requestValues = $request->getValues();
+ // Also go through the predefined PHP variable
+ // $_REQUEST, because $request->getValues() for
+ // some reason doesn't return array values - is
+ // there a better (less hacky) way to do this?
+ foreach ( $_REQUEST as $key => $value ) {
+ if ( is_array( $value ) ) {
+ foreach ( $value as $k2 => $v2 ) {
+ $newKey = $key . '[' . $k2 . ']';
+ $requestValues[$newKey] = $v2;
+ }
+ }
+ }
+
+ foreach ( $requestValues as $key => $value ) {
+ if ( $key != 'month' && $key != 'year'
+ // values from 'RunQuery'
+ && $key != 'query' && $key != 'free_text'
+ ) {
+ $additionalQueryString .= "&$key=$value";
+ $hiddenInputs .= "<input type=\"hidden\" " .
+ "name=\"$key\" value=\"$value\" />";
+ }
+ }
+ }
+
+ // Set days of the week.
+ $weekDayNames = [
+ 1 => wfMessage( 'sunday' )->text(),
+ 2 => wfMessage( 'monday' )->text(),
+ 3 => wfMessage( 'tuesday' )->text(),
+ 4 => wfMessage( 'wednesday' )->text(),
+ 5 => wfMessage( 'thursday' )->text(),
+ 6 => wfMessage( 'friday' )->text(),
+ 7 => wfMessage( 'saturday' )->text()
+ ];
+ if ( empty( $srfgFirstDayOfWeek ) ) {
+ $firstDayOfWeek = 1;
+ $lastDayOfWeek = 7;
+ } else {
+ $firstDayOfWeek =
+ array_search( $srfgFirstDayOfWeek, $weekDayNames );
+ if ( $firstDayOfWeek === false ) {
+ // Bad value for $srfgFirstDayOfWeek!
+ print 'Warning: Bad value for $srfgFirstDayOfWeek "' .
+ '(' . $srfgFirstDayOfWeek . '")';
+ $firstDayOfWeek = 1;
+ }
+ if ( $firstDayOfWeek == 1 ) {
+ $lastDayOfWeek = 7;
+ } else {
+ $lastDayOfWeek = $firstDayOfWeek - 1;
+ }
+ }
+
+ // Now create the actual array of days of the week, based on
+ // the start day
+ $weekDays = [];
+ for ( $i = 1; $i <= 7; $i++ ) {
+ $curDay = ( ( $firstDayOfWeek + $i - 2 ) % 7 ) + 1;
+ $weekDays[$i] = $weekDayNames[$curDay];
+ }
+
+ // Get all the date-based values we need - the current month
+ // and year (i.e., the one the user is looking at - not
+ // necessarily the "current" ones), the previous and next months
+ // and years (same - note that the previous or next month could
+ // be in a different year), the number of days in the current,
+ // previous and next months, etc.
+
+ if ( is_numeric( $this->mStartMonth ) &&
+ ( intval( $this->mStartMonth ) == $this->mStartMonth ) &&
+ $this->mStartMonth >= 1 && $this->mStartMonth <= 12
+ ) {
+ $curMonthNum = $this->mStartMonth;
+ } else {
+ $curMonthNum = date( 'n' );
+ }
+ if ( $request->getCheck( 'month' ) ) {
+ $queryMonth = $request->getVal( 'month' );
+ if ( is_numeric( $queryMonth ) &&
+ ( intval( $queryMonth ) == $queryMonth ) &&
+ $queryMonth >= 1 && $queryMonth <= 12
+ ) {
+ $curMonthNum = $request->getVal( 'month' );
+ }
+ }
+
+ $curMonth = self::intToMonth( $curMonthNum );
+
+ if ( is_numeric( $this->mStartYear ) &&
+ ( intval( $this->mStartYear ) == $this->mStartYear )
+ ) {
+ $curYear = $this->mStartYear;
+ } else {
+ $curYear = date( 'Y' );
+ }
+ if ( $request->getCheck( 'year' ) ) {
+ $queryYear = $request->getVal( 'year' );
+ if ( is_numeric( $queryYear ) &&
+ intval( $queryYear ) == $queryYear
+ ) {
+ $curYear = $request->getVal( 'year' );
+ }
+ }
+
+ if ( $curMonthNum == '1' ) {
+ $prevMonthNum = '12';
+ $prevYear = $curYear - 1;
+ } else {
+ $prevMonthNum = $curMonthNum - 1;
+ $prevYear = $curYear;
+ }
+
+ if ( $curMonthNum == '12' ) {
+ $nextMonthNum = '1';
+ $nextYear = $curYear + 1;
+ } else {
+ $nextMonthNum = $curMonthNum + 1;
+ $nextYear = $curYear;
+ }
+
+ // There's no year '0' - change it to '1' or '-1'.
+ if ( $curYear == '0' ) {
+ $curYear = '1';
+ }
+ if ( $nextYear == '0' ) {
+ $nextYear = '1';
+ }
+ if ( $prevYear == '0' ) {
+ $prevYear = '-1';
+ }
+
+ $prevMonthUrl = $pageTitle->getLocalURL(
+ "month=$prevMonthNum&year=$prevYear" .
+ $additionalQueryString
+ );
+ $nextMonthUrl = $pageTitle->getLocalURL(
+ "month=$nextMonthNum&year=$nextYear" .
+ $additionalQueryString
+ );
+ $todayUrl = $pageTitle->getLocalURL( $additionalQueryString );
+
+ $todayText = wfMessage( 'srfc_today' )->text();
+ $prevMonthText = wfMessage( 'srfc_previousmonth' )->text();
+ $nextMonthText = wfMessage( 'srfc_nextmonth' )->text();
+ $goToMonthText = wfMessage( 'srfc_gotomonth' )->text();
+
+ // Get day of the week that the first of this month falls on.
+ $firstDay = new SRFCHistoricalDate();
+ $firstDay->create( $curYear, $curMonthNum, 1 );
+ $startDay = $firstDayOfWeek - $firstDay->getDayOfWeek();
+ if ( $startDay > 0 ) {
+ $startDay -= 7;
+ }
+ $daysInPrevMonth =
+ SRFCHistoricalDate::daysInMonth( $prevYear, $prevMonthNum );
+ $daysInCurMonth =
+ SRFCHistoricalDate::daysInMonth( $curYear, $curMonthNum );
+ $todayString = date( 'Y n j', time() );
+ $pageName = $pageTitle->getPrefixedDbKey();
+
+ // Create table for holding title and navigation information.
+ $text = <<<END
+<table class="navigation_table">
+<tr><td class="month_name">$curMonth $curYear</td>
+<td class="nav_links"><a href="$prevMonthUrl" title="$prevMonthText">
+<img src="{$srfgScriptPath}/formats/calendar/resources/images/left-arrow.png" border="0" />
+</a>&#160;<a href="$todayUrl">$todayText</a>&#160;
+<a href="$nextMonthUrl" title="$nextMonthText">
+<img src="{$srfgScriptPath}/formats/calendar/resources/images/right-arrow.png" border="0" />
+</a></td><td class="nav_form"><form>
+<input type="hidden" name="title" value="$pageName">
+<select name="month">
+
+END;
+ for ( $i = 1; $i <= 12; $i++ ) {
+ $monthName = self::intToMonth( $i );
+ $selectedStr = ( $i == $curMonthNum ) ? "selected" : "";
+ $text .= "<option value=\"$i\" $selectedStr>
+ $monthName</option>\n";
+ }
+ $text .= <<<END
+</select>
+<input name="year" type="text" value="$curYear" size="4">
+$hiddenInputs
+<input type="submit" value="$goToMonthText">
+</form>
+</td>
+</tr>
+</table>
+
+<table class="month_calendar">
+<tr class="weekdays">
+
+END;
+ // First row of the main table holds the days of the week
+ foreach ( $weekDays as $weekDay ) {
+ $text .= "<td>$weekDay</td>";
+ }
+ $text .= "</tr>\n";
+
+ // Now, create the calendar itself -
+ // loop through a set of weeks, from a "Sunday" (which might be
+ // before the beginning of the month) to a "Saturday" (which
+ // might be after the end of the month).
+ // "Sunday" and "Saturday" are in quotes because the actual
+ // start and end days of the week can be set by the admin.
+ $dayOfTheWeek = $firstDayOfWeek;
+ $isLastWeek = false;
+ for ( $day = $startDay;
+ ( !$isLastWeek || $dayOfTheWeek != $firstDayOfWeek );
+ $day++ ) {
+ if ( $dayOfTheWeek == $firstDayOfWeek ) {
+ $text .= "<tr>\n";
+ }
+ if ( "$curYear $curMonthNum $day" == $todayString ) {
+ $text .= "<td class=\"today\">\n";
+ } elseif ( $dayOfTheWeek == 1 || $dayOfTheWeek == 7 ) {
+ $text .= "<td class=\"weekend_day\">\n";
+ } else {
+ $text .= "<td>\n";
+ }
+ if ( $day == $daysInCurMonth || $day > 50 ) {
+ $isLastWeek = true;
+ }
+ // If this day is before or after the current month,
+ // set a "display day" to show on the calendar, and
+ // use a different CSS style for it.
+ if ( $day > $daysInCurMonth || $day < 1 ) {
+ if ( $day < 1 ) {
+ $displayDay = $day + $daysInPrevMonth;
+ $dateStr =
+ $prevYear . '-' . $prevMonthNum . '-' . $displayDay;
+ }
+ if ( $day > $daysInCurMonth ) {
+ $displayDay = $day - $daysInCurMonth;
+ $dateStr =
+ $nextYear . '-' . $nextMonthNum . '-' . $displayDay;
+ }
+ $text .=
+ "<div class=\"day day_other_month\">$displayDay</div>\n";
+ } else {
+ $dateStr = $curYear . '-' . $curMonthNum . '-' . $day;
+ $text .= "<div class=\"day\">$day</div>\n";
+ }
+ // Finally, the most important step - get the events
+ // that match this date, and the given set of criteria,
+ // and display them in this date's box.
+ $text .= "<div class=\"main\">\n";
+ if ( $events == null ) {
+ $events = [];
+ }
+ foreach ( $events as $event ) {
+ list( $eventTitle, $otherText, $eventDate, $color ) = $event;
+ if ( $eventDate == $dateStr ) {
+ if ( $this->mTemplate != '' ) {
+ $templatetext = '{{' . $this->mTemplate . $otherText .
+ '|thisdate=' . $dateStr . '}}';
+ $templatetext =
+ $wgParser->replaceVariables( $templatetext );
+ $templatetext =
+ $wgParser->recursiveTagParse( $templatetext );
+ $text .= $templatetext;
+ } else {
+ $eventStr = Linker::link( $eventTitle );
+ if ( $color != '' ) {
+ $text .= "<div class=\"colored-entry\">
+ <p style=\"border-left: 7px $color solid;\">
+ $eventStr $otherText</p></div>\n";
+ } else {
+ $text .= "$eventStr $otherText\n\n";
+ }
+ }
+ }
+ }
+ $text .= <<<END
+</div>
+</td>
+
+END;
+ if ( $dayOfTheWeek == $lastDayOfWeek ) {
+ $text .= "</tr>\n";
+ }
+ if ( $dayOfTheWeek == 7 ) {
+ $dayOfTheWeek = 1;
+ } else {
+ $dayOfTheWeek++;
+ }
+ }
+ $text .= "</table>\n";
+
+ return $text;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['lang'] = [
+ 'message' => 'srf_paramdesc_calendarlang',
+ 'default' => false,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['template'] = [
+ 'message' => 'smw-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params['userparam'] = [
+ 'message' => 'smw-paramdesc-userparam',
+ 'default' => '',
+ ];
+
+ $params['color'] = [
+ 'message' => 'srf-paramdesc-color',
+ 'default' => '',
+ ];
+
+ $params['colors'] = [
+ 'message' => 'srf_paramdesc_calendarcolors',
+ 'default' => '',
+ ];
+
+ $params['startmonth'] = [
+ 'message' => 'srf-paramdesc-calendar-startmonth',
+ 'default' => date( 'n' ),
+ ];
+
+ $params['startyear'] = [
+ 'message' => 'srf-paramdesc-calendar-startyear',
+ 'default' => date( 'Y' ),
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.calendar.css b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.calendar.css
new file mode 100644
index 00000000..52098830
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.calendar.css
@@ -0,0 +1,100 @@
+/**
+ * The main CSS file for the Semantic Calendar extension.
+ */
+
+table.navigation_table {
+ width: 100%;
+ padding-bottom: 20px;
+}
+table.navigation_table tr td.month_name {
+ font-size: xx-large;
+}
+table.navigation_table tr td.nav_links {
+ text-align: center;
+ font-weight: bold;
+}
+table.navigation_table tr td.nav_form {
+ text-align: right;
+}
+table.month_calendar {
+ border-collapse: collapse;
+}
+table.month_calendar tr {
+}
+table.month_calendar td {
+ width: 150px;
+ border: 1px #888888 solid;
+ padding: 0px;
+ vertical-align: top;
+}
+table.month_calendar td div.day {
+ background: white;
+ min-height: 15px;
+ min-width: 15px;
+ padding: 5px;
+ margin: 0px 0px 3px 3px;
+ float: right;
+ text-align: center;
+ vertical-align: middle;
+ font-weight: bold;
+ font-size: larger;
+ color: #555555;
+ border-left: 1px #cccccc solid;
+ border-bottom: 1px #cccccc solid;
+}
+table.month_calendar td div.day_other_month {
+ background: #eeeeee;
+ color: #aaaaaa;
+ border: none;
+}
+table.month_calendar td div.day_other_month {
+ background: #fcffb1;
+ color: #aaaaaa;
+}
+table.month_calendar td div.main {
+ min-height: 80px;
+ padding: 4px;
+ height: 100%;
+}
+table.month_calendar td div.main p {
+ line-height: 125%;
+}
+table.month_calendar td.today div.day {
+ background: #dbe8f9;
+ color: black;
+ border-left: 1px #999999 solid;
+ border-bottom: 1px #999999 solid;
+}
+table.month_calendar td.today div.main {
+ background: #f9f9f9;
+}
+table.month_calendar tr.header {
+ vertical-align: middle;
+}
+table.month_calendar tr.header td {
+ padding: 30px 10px 10px 10px;
+ border: 0;
+ text-align: center;
+ font-size: x-large;
+}
+table.month_calendar tr.weekdays {
+ border-top: 1px black solid;
+ font-weight: bold;
+ background: #dbe8f9;
+}
+table.month_calendar tr.weekdays td {
+ border: 0;
+ text-align: center;
+ vertical-align: middle;
+ color: #555555;
+ padding: 8px 2px 2px 2px;
+}
+table.month_calendar td div.colored-entry {
+ border: 1px #f4f4d2 solid;
+ background: #ffffdd;
+ margin: 4px 0 4px 0;
+}
+table.month_calendar td div.colored-entry p {
+ margin: 0;
+ padding: 2px 0 2px 6px;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.css b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.css
new file mode 100644
index 00000000..5b3ddb58
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.css
@@ -0,0 +1,360 @@
+/**
+ * CSS for the SRF event calendar module
+ *
+ * @since 1.9
+ * @release 0.7.4
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+.srf-top {
+ margin-bottom: 5px;
+}
+
+.srf-bottom {
+ margin-bottom: 5px;
+}
+
+.srf-ui-legendList, .srf-ui-legendList-sel {
+ color: #222;
+ /*line-height: 30px;*/
+ /* background-color: #eee; */
+}
+
+.srf-ui-legendList.top {
+ margin: 0 0 10px 0;
+}
+
+.srf-ui-legendList.bottom {
+ margin: 10px 0 0 0;
+}
+
+.srf-ui-legendList.basic {
+ background-color: #fff;
+ border: 1px solid gainsboro;
+ -moz-border-radius: 1px;
+ -webkit-border-radius: 1px;
+ border-radius: 1px;
+}
+
+.srf-ui-legendList.top.basic {
+ background-image: -webkit-linear-gradient(top,white,#F6F8F9);
+ background-image: linear-gradient(top,white,#F6F8F9);
+}
+
+.srf-ui-legendList.bottom.basic {
+ background-image: -webkit-linear-gradient(bottom,white,#F6F8F9);
+ background-image: linear-gradient(bottom,white,#F6F8F9);
+}
+
+.srf-ui-legendList ul {
+ list-style-type: none;
+ list-style-image: none;
+ margin: .3em 0 0 0.6em;
+ width: 100%; /* room for 3 columns */
+ overflow: hidden;
+}
+
+.srf-ui-legendList ul li {
+ float: left;
+ width: 23%; /* accommodate the widest item */
+ margin-right: 15px;
+ font-size: 90%;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+.srf-ui-legend-label, .srf-ui-legend-label-sel {
+ font-size: 12px;
+ font-family: Arial,sans-serif;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+.srf-ui-legend-square {
+ list-style-type: square;
+ background: white;
+ /*border: 1px solid gainsboro;*/
+ height: 10px;
+ margin-right: 4px;
+ position: relative;
+ top: 3px;
+ width: 10px;
+ -moz-border-radius: 1px;
+ -webkit-border-radius: 1px;
+ border-radius: 10px;
+ float: left;
+ padding: 1px;
+}
+
+.srf-ui-legend-tooltip-content ul {
+ list-style-type: none;
+ list-style-image: none;
+ width: 100%; /* room for 3 columns */
+ overflow: hidden;
+ margin: .3em 0 0 0.6em;
+}
+
+.srf-ui-legend-tooltip-content ul li {
+ margin-right: 15px;
+ font-size: 90%;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+.srf-ui-legend-tooltip-content {
+ display:none;
+}
+
+.srf-ui-square {
+ position: relative;
+ float: left;
+ top: 25%;
+ border: 3px solid #48A0D5;
+ width: 6px;
+ height: 6px;
+}
+
+.srf-ui-circle {
+ position: relative;
+ top: 25%;
+ border-radius: 6px; /* border-radius value should be in px/em because some browsers do not support */
+ width: 12px;
+ height: 12px;
+ background: #BF381A;
+}
+
+/* @since 0.7.3, using widget class */
+
+.srf-calendarpane {
+ overflow: hidden;
+ float: left;
+ margin-right: 10px;
+ display:none;
+ min-width: 17em; /* Min width for the paneView */
+}
+
+.srf-calendarpane fieldset {
+ border: 1px solid #2F6FAB;
+ margin: 0.1em 0.1em 0.1em 0.1em;
+ padding: 0 0.5em 0.5em 0.5em;
+ line-height: 1.5em;
+ border: 1px solid gainsboro;
+ -moz-border-radius: 1px;
+ -webkit-border-radius: 1px;
+ border-radius: 1px;
+
+}
+
+.srf-calendarpane fieldset label {
+ vertical-align: top;
+}
+
+.srf-calendarpane .section-header {
+ color: black;
+ background: none;
+ font-weight: normal;
+ margin: 0;
+ overflow: hidden;
+ padding-top: .5em;
+ padding-bottom: .17em;
+ border-bottom: none;
+ font-weight: bold;
+ font-size: 132%;
+}
+
+.srf-calendarpane .ui-sortable-placeholder {
+ border: 1px dotted black;
+ visibility: visible !important;
+ height: 50px !important;
+}
+
+.srf-calendarpane .ui-sortable-placeholder {
+ visibility: hidden;
+}
+
+.srf-calendarpane .reset-link {
+ background-color:white;
+ border:0;
+ color:blue;
+ text-decoration:underline;
+ font-size:1em;
+ font-family:inherit;
+ cursor:pointer;
+ float: right;
+ margin-right: 3px;
+}
+
+.srf-calendarpane .mini-calendar {
+ background-color: #fff;
+}
+
+.srf-calendarpane .mini-calendar .options {
+ margin-top: 0px;
+ width: 100%;
+}
+
+.srf-calendarpane .mini-calendar .options input {
+ padding: 3px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ border: 1px solid #CECECE;
+ outline: none;
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+
+.srf-calendarpane .select-wrap-chrome, .srfcalendar-pane .select-wrap-safari {
+ padding-bottom: 4px;
+}
+
+.srf-calendarpane .select-wrap-firefox {
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+.srf-calendarpane select {
+ width: 100%;
+ padding: 2px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ border: 1px solid #CECECE;
+ outline: none;
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset, 0 1px 0 rgba(255, 255, 255, 0.2);
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+
+.srf-calendarpane .mini-calendar .options .input-right {
+ float:right;
+}
+
+.srf-calendarpane input[readonly="readonly"] {
+ background-color: #eee;
+}
+
+.srf-calendarpane .legend {
+ margin-top: 5px;
+ margin-bottom: 0px;
+}
+
+.srf-calendarpane .legend fieldset {
+ background-color: #fff;
+}
+
+.srf-calendarpane .parameters {
+ margin-top: 5px;
+}
+
+.srf-calendarpane .parameters fieldset {
+ background-color: #fff;
+}
+
+.srf-calendarpane .parameters .limitparam {
+ padding: 0.5em;
+}
+
+.srf-calendarpane .parameters .label {
+ overflow: hidden;
+ float:left;
+ margin-right: 5px;
+}
+
+.srf-calendarpane .parameters .limitparam .value {
+ overflow: hidden;
+ float:left;
+ margin-right: 5px;
+}
+
+.srf-calendarpane .parameters .limitparam .count {
+ float:right;
+}
+
+.srf-calendarpane .parameters .slider {
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 3px;
+}
+
+.srf-ui-legendList.pane {
+ margin-top: 0px;
+}
+
+.srf-ui-legendList.pane ul {
+ list-style-type: none;
+ list-style-image: none;
+ margin: .3em 0 0 0.6em;
+ width: 100%; /* room for 3 columns */
+ overflow: hidden;
+}
+
+.srf-ui-legendList.pane ul li {
+ float: none;
+ width: 100%;
+ margin-right: 15px;
+ font-size: 90%;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+.srf-legend-item input {
+ /* float: left; */
+ margin-right: 5px;
+}
+
+/* Datepicker uses auto width */
+.srf-calendarpane .ui-datepicker {
+ width: auto;
+}
+
+.srf-calendarpane .slider.ui-slider.ui-slider-horizontal.ui-widget.ui-widget-content.ui-corner-all, .srf-calendarpane a.ui-slider-handle {
+ border-bottom-right-radius: 2px;
+ border-bottom-left-radius: 2px;
+ border-top-right-radius: 2px;
+ border-top-left-radius: 2px;
+}
+
+.srf-calendarpane .parameter-section {
+ font-size: 110%;
+}
+
+.srf-calendarpane .limitparam .parameter-section {
+ margin-left: 0;
+ margin-top: 5px;
+ margin-bottom:5px;
+}
+
+.srf-calendarpane .minmax .parameter-section {
+ margin-left: 5px;
+ margin-top: 0;
+ margin-bottom:5px;
+}
+
+.srf-calendarpane .filterparam .parameter-section {
+ margin-left: 5px;
+ margin-top: 10px;
+ margin-bottom:5px;
+}
+
+.srf-calendarpane .mini-calendar .options input#to {
+ margin-left: 5px;
+}
+
+fieldset input#max {
+ margin-left: 5px;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.js
new file mode 100644
index 00000000..1867ad8f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.formats.eventcalendar.js
@@ -0,0 +1,1124 @@
+/**
+ * SRF JavaScript for event calendar module which uses the fullcalendar library
+ *
+ * @see http://arshaw.com/fullcalendar/docs/
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Eventcalendar_format
+ *
+ * Please be aware that release 0.6 will break with the SRF 1.8 Event calendar
+ * implementation
+ *
+ * @since 1.8
+ * @version 0.8
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /* Private methods and objects */
+
+ /**
+ * Helper objects
+ *
+ * @since 1.9
+ *
+ * @ignore
+ * @private
+ * @static
+ */
+ var html = mw.html,
+ profile = $.client.profile(),
+ smwApi = new smw.api(),
+ util = new srf.util();
+
+ /**
+ * Calendar related utility functions
+ *
+ * @since 1.9
+ * @type Object
+ */
+ var _calendar = {
+
+ /**
+ * Returns default settings
+ *
+ * @since 1.9
+ */
+ defaults: {
+ color: '#48a0d5',
+ dateFormat: 'yy-mm-dd',
+ descriptionLength: 100,
+ paneView: mw.user.options.get( 'srf-prefs-eventcalendar-options-paneview-default' ),
+ slider: {
+ max: 1000,
+ step:50
+ },
+
+ /**
+ * Convenience setter for default values
+ *
+ * @since 1.9
+ * @type Object
+ */
+ set: function ( data ){
+ var weekDay = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ that = {};
+
+ // Set theme
+ var parameters = data.query.ask.parameters;
+ that.theme = parameters.theme === 'vector' ? 'ui' : 'fc';
+ that.themeSystem = parameters.theme === 'vector' ? 'jquery-ui' : 'standard';
+
+ that.defaultView = parameters.defaultview
+ .replace( 'day', 'Day')
+ .replace( 'week', 'Week' )
+ .replace( 'tmonth', 'tMonth' );
+
+ that.view = parameters.views
+ .replace( /day/g, 'Day')
+ .replace( /week/g, 'Week' )
+ .replace( /tmonth/g, 'tMonth' );
+
+ that.firstday = $.inArray( parameters.firstday, weekDay );
+
+ // Set calendar start
+ that.calendarStart = _calendar.data.startDate( data.dates ).get( parameters.start );
+
+ // Google holiday calendar url
+ that.holiday = parameters.gcalurl === null ? '' : parameters.gcalurl;
+
+ $.extend( this, that );
+ }
+ },
+
+ /**
+ * Returns ID
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getID: function( container ) {
+ return container.attr( 'id' );
+ },
+
+ /**
+ * Returns container data
+ *
+ * @private
+ * @return {object}
+ */
+ getData: function( container ) {
+ return mw.config.get( this.getID( container ) );
+ },
+
+ /**
+ * Returns truncated version of string for tooltip description of month view
+ *
+ * @private
+ * @param str string to be truncated
+ * @param maxChars max number of characters to be returned (excluding ' ...')
+ * @return {string}
+ */
+ getTruncatedSentence: function( str, maxChars ) {
+ var truncated = str.substr( 0, maxChars );
+ if ( str.length > maxChars ) {
+ var truncatedEnd = truncated.lastIndexOf( " " );
+ if( truncatedEnd != -1 ) {
+ truncated = str.substring( 0, truncatedEnd );
+ }
+ return truncated + ' ...';
+ }else{
+ return truncated;
+ }
+ },
+
+ /**
+ * Contains methods linked to the parsing of objects
+ *
+ * @since 1.9
+ * @type Object
+ */
+ parse: {
+
+ /**
+ * Returns a parsed query result object
+ *
+ * The array output index corresponds to FullCalendar
+ * eventObject specification
+ *
+ * id - Uniquely identifies the given event
+ * title - Required, The text on an event's element
+ * start - Required, The date/time an event begins
+ * end - Optional, The date/time an event ends
+ * url - Optional, A URL that will be used as href for when
+ * the event is clicked
+ * className - A CSS class (or array of classes) that will
+ * be attached to this event's element
+ * color - Sets an event's background and border color
+ * description is a non-standard Event Object field
+ * allDay if set false it will show the time
+ *
+ * @see http://arshaw.com/fullcalendar/docs/event_data/Event_Object/
+ * @see http://arshaw.com/fullcalendar/docs/event_rendering/eventRender/
+ *
+ * @since 1.9
+ * @type Object
+ */
+ api: function( data ) {
+
+ // Transform results into the calendar specific array format
+ function getResults( parameters, results ){
+
+ var events = [],
+ dates = [],
+ legend = {};
+
+ $.each( results, function( subjectName, subject ) {
+ var rowData = {},
+ rowDesc = [],
+ metaData = [],
+ prevElement = '';
+
+ // Subject
+ if ( rowData.url === undefined && subject instanceof smw.dataItem.wikiPage ) {
+ rowData.url = parameters.link === 'none' ? null : subject.getUri();
+ rowData.title = subject.getHtml();
+ }
+
+ if ( $.inArray( 'printouts', subject ) ) {
+ $.each ( subject.printouts, function( property, values ) {
+
+ $.map ( values, function( value ) {
+
+ // Time type properties
+ if ( value instanceof smw.dataItem.time && value.getDate() !== undefined ) {
+ if ( rowData.start === undefined ){
+ rowData.start = value.getDate().toISOString();
+ dates.push( value.getMwTimestamp() );
+ rowData.allDay = true;
+ } else {
+ rowData.end = value.getDate().toISOString();
+ dates.push( value.getMwTimestamp() );
+ var test = value.getISO8601Date();
+ rowData.allDay = test.indexOf( '00:00:00' ) !== -1 || false;
+ }
+ // Page type properties
+ } else if ( value instanceof smw.dataItem.wikiPage ) {
+
+ if ( property === 'title' && value.getName() !== undefined ) {
+ rowData.title = value.getFullText();
+ } else if ( property === 'icon' ){
+ rowData.eventicon = value.getFullText();
+ } else if ( property === data.query.ask.parameters.filterProperty ) {
+ rowData.filter = {
+ 'value' : value.getFullText(),
+ 'option': ( data.query.ask.parameters.filterType === 'filter' ? true: false )
+ };
+ } else if ( property !== '' ) {
+ rowDesc.push( parameters.headers === 'hide' ? value.getFullText() : property + ':' + value.getFullText() );
+ }
+
+ } else if ( $.type( value ) === 'object' ) {
+ if ( property === 'title' ){
+ rowData.title = value.getValue();
+ } else if ( property === 'color' ) {
+ rowData.color = value.getValue();
+ } else if ( property === 'iconclass' ) {
+ rowData.eventIconClass = value.getValue();
+ } else if ( property === data.query.ask.parameters.filterProperty ) {
+ rowData.filter = {
+ 'value' : value.getValue(),
+ 'option': ( data.query.ask.parameters.filterType === 'filter' ? true: false )
+ };
+ } else if ( property !== '' ) {
+ // Items without fixed identifiers remain part of a description
+ rowDesc.push( parameters.headers === 'hide' ? value.getValue() : property + ':' + value.getValue() );
+ }
+ }
+
+ } );
+ } );
+ // Collect all descriptions
+ rowData.description = rowDesc.join(',');
+ }
+
+ // Only care for entries that have at least a start date
+ if ( rowData !== {} &&
+ $.inArray( 'start', rowData ) &&
+ rowData.start !== null &&
+ rowData.start !== undefined ) {
+
+ if ( $.inArray( 'filter', rowData ) && rowData.filter !== undefined ){
+ var filter = rowData.filter,
+ color = $.inArray( 'color', rowData ) ? rowData.color : null;
+ rowData.filter = filter.value;
+ if ( filter.value !== undefined && color !== undefined ){
+ // Collect the filter and the assigned color, colors are stored as
+ // array so that if a filter has assigned different colors are
+ // stored together
+ if ( legend[filter.value] === undefined ){
+ legend[filter.value] = { 'color' : [color] , 'filter': filter.option };
+ }else{
+ legend[filter.value].color.push( color );
+ }
+ }
+ }
+ // Collect events
+ events.push( rowData );
+ }
+ } );
+
+ return { 'events': events, 'legend': legend, 'dates': dates };
+ }
+
+ // Parse and return results
+ return getResults( data.query.ask.parameters, data.query.result.results );
+ }
+ },
+
+ /**
+ * Contains methods related to the data object literal
+ *
+ * @since 1.9
+ * @type Object
+ */
+ data: {
+
+ startDate: function( dates ) {
+ var self = this;
+
+ return {
+
+ /**
+ * Return min/max values of an object array
+ * @return object
+ */
+ minmax: function(){
+ var min = 0,
+ max = 0;
+ $.map ( dates, function( value ) {
+ if ( value !== '' ) {
+ // 0 would be always (in the context given) min
+ // but this is not what is of interest here therefore
+ // in case min is 0 set it to the next value known
+ min = parseInt( value, 10 ) < parseInt ( min, 10 ) ? value : min === 0 ? value : min;
+ max = parseInt( value, 10 ) > parseInt ( max, 10 ) ? value : max;
+ }
+ } );
+ return { 'min': min, 'max': max };
+ },
+
+ /**
+ * Returns start date
+ *
+ * @since 1.9
+ * @param type
+ * @return Date
+ */
+ get: function ( type ){
+ var values = this.minmax(),
+ date = type === '' ? null : type === 'earliest' ? values.min : type === 'latest' ? values.max : null;
+ return date !== null ? _calendar.api.results.dataValues.time.parseDate( date ) : new Date();
+ }
+ }
+ },
+
+ /**
+ * Refresh internal objects
+ *
+ * @since 1.9
+ * @type Object
+ * @type Object
+ * @type Object
+ */
+ refresh: function( context, container, data, message ){
+
+ var startDate = new Date();
+
+ // Re-parse data and merge them
+ $.extend( data, _calendar.parse.api( data ) );
+
+ // Displayed only while in debug mode
+ srf.log( 'Parse: ' + ( new Date().getTime() - startDate.getTime() ) + ' ms' );
+
+ // @todo Check hash from current data object with the newly
+ // arrived result hash and bail-out in case the hash match each other
+
+ // Update defaults
+ _calendar.defaults.set( data );
+
+ // Legend update (widget)
+ context.calendarlegend( 'option', 'list', {
+ 'type': data.query.ask.parameters.filterType,
+ 'list': data.legend
+ } );
+
+ // Limit/count display update (widget)
+ context.find( '.parameters > fieldset' ).calendarparameters(
+ 'option', 'limit', {
+ 'limit': data.query.ask.parameters.limit,
+ 'count': data.query.result.meta.count
+ } ) ;
+
+ _calendar.fullCalendar( context, container, data ).update();
+
+ if ( message ){
+ _calendar.util.notification.create ( {
+ content: message
+ } );
+ }
+ }
+ },
+
+ /**
+ * Internationalization (i18n) support
+ *
+ * @see http://arshaw.com/fullcalendar/docs/text/
+ *
+ * @since 1.8
+ */
+ messages: {
+ monthNames: [ mw.msg( 'january' ), mw.msg( 'february' ), mw.msg( 'march' ),
+ mw.msg( 'april' ), mw.msg( 'may_long' ), mw.msg( 'june' ),
+ mw.msg( 'july' ), mw.msg( 'august' ), mw.msg( 'september' ),
+ mw.msg( 'october' ), mw.msg( 'november' ), mw.msg( 'december' )
+ ],
+ monthNamesShort:[ mw.msg( 'jan' ), mw.msg( 'feb' ), mw.msg( 'mar' ),
+ mw.msg( 'apr' ), mw.msg( 'may' ), mw.msg( 'jun' ),
+ mw.msg( 'jul' ), mw.msg( 'aug' ), mw.msg( 'sep' ),
+ mw.msg( 'oct' ), mw.msg( 'nov' ), mw.msg( 'dec' )
+ ],
+ dayNames: [ mw.msg( 'sunday' ), mw.msg( 'monday' ), mw.msg( 'tuesday' ),
+ mw.msg( 'wednesday' ), mw.msg( 'thursday' ), mw.msg( 'friday' ), mw.msg( 'saturday' )
+ ],
+ dayNamesShort: [ mw.msg( 'sun' ), mw.msg( 'mon' ), mw.msg( 'tue' ),
+ mw.msg( 'wed' ), mw.msg( 'thu' ), mw.msg( 'fri' ), mw.msg( 'sat' )
+ ],
+ buttonText : {
+ today: mw.msg( 'srf-ui-eventcalendar-label-today' ),
+ month: mw.msg( 'srf-ui-eventcalendar-label-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-label-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-label-day' ),
+ listMonth: mw.msg( 'srf-ui-eventcalendar-label-listmonth' ),
+ listWeek: mw.msg( 'srf-ui-eventcalendar-label-listweek' ),
+ listDay: mw.msg( 'srf-ui-eventcalendar-label-listday' )
+ },
+ allDayText : mw.msg( 'srf-ui-eventcalendar-label-allday' ),
+ timeFormat : mw.msg( 'srf-ui-eventcalendar-format-time' ),
+ axisFormat: mw.msg( 'srf-ui-eventcalendar-format-axis' ),
+ titleFormat: {
+ month: mw.msg( 'srf-ui-eventcalendar-format-title-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-format-title-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-format-title-day' )
+ },
+ columnFormat: {
+ month: mw.msg( 'srf-ui-eventcalendar-format-column-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-format-column-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-format-column-day' )
+ },
+ clickPopup: {
+ popup: mw.msg( 'srf-ui-eventcalendar-click-popup' )
+ }
+ },
+ /**
+ * Handles redirect to a clicktarget URL.
+ */
+ onDayClick: function( date, data, clickPopup ){
+ var clicktarget = data.query.ask.parameters.clicktarget;
+
+ // Moment.js
+ if ( typeof date.getUTCHours !== 'function' ) {
+ date = new Date( date.toDate() );
+ };
+
+ if( clicktarget !== 'none' ){
+ var h = date.getUTCHours() + 1;
+ var m = date.getUTCMinutes();
+ var s = date.getUTCSeconds();
+ var hms;
+
+ if( h == 24 ){
+ // avoid switch to next day
+ hms = "T"+ "13" + ":" + m + ":" + s;
+ } else {
+ hms = "T"+ h + ":" + m + ":" + s;
+ }
+
+ clicktarget = clicktarget.replace( /%clickyear%/g, date.getFullYear() )
+ .replace( /%clickmonth%/g, date.getMonth() + 1 )
+ .replace( /%clickday%/g, date.getDate() )
+ .replace( /%clicktime%/g, hms );
+
+ var wgArticlePath = mw.config.get( 'wgArticlePath' ).replace( '$1', '' ).trim();
+ var wgServer = mw.config.get( 'wgServer' );
+
+ var clicktargetURL = wgServer + wgArticlePath + clicktarget;
+ /* DONE: i18n */
+ var r = confirm( clickPopup.popup );
+ if ( r == true ){
+ window.open( clicktargetURL, '_self' );
+ }
+ }
+
+ },
+ /**
+ * Handles fullCalendar tasks
+ *
+ * @since 1.9
+ */
+ fullCalendar: function( context, container, data ){
+ var self = this;
+ var holidays = [];
+ if ( typeof( self.defaults.holiday ) != 'undefined' ) {
+ holidays = self.defaults.holiday;
+ }
+ return {
+ /**
+ * Get the calendar rolling
+ *
+ * @since 1.9
+ */
+ init: function(){
+ var that = this;
+
+ container.fullCalendar( {
+ header: {
+ right: 'prev,next today',
+ center: 'title',
+ left: self.defaults.view
+ },
+ isRTL: context.attr( 'dir' ) === 'rtl' || false,
+ height: context.height(),
+ defaultView: self.defaults.defaultView,
+ firstDay: self.defaults.firstday,
+ monthNames: self.messages.monthNames,
+ monthNamesShort: self.messages.monthNamesShort,
+ dayNames: self.messages.dayNames,
+ dayNamesShort: self.messages.dayNamesShort,
+ buttonText: self.messages.buttonText,
+ allDayText: self.messages.allDayText,
+ timeFormat: self.messages.timeFormat,
+ views: {
+ basic: {
+ titleFormat: self.messages.titleFormat.day,
+ columnHeaderFormat: self.messages.columnFormat.day
+ },
+ month: {
+ titleFormat: self.messages.titleFormat.month,
+ columnHeaderFormat: self.messages.columnFormat.month
+ },
+ agendaWeek: {
+ titleFormat: self.messages.titleFormat.week,
+ columnHeaderFormat: self.messages.columnFormat.week
+ },
+ week: {
+ titleFormat: self.messages.titleFormat.week,
+ columnHeaderFormat: self.messages.columnFormat.week
+ },
+ day: {
+ titleFormat: self.messages.titleFormat.day,
+ columnHeaderFormat: self.messages.columnFormat.day
+ },
+ agendaDay: {
+ titleFormat: self.messages.titleFormat.day,
+ columnHeaderFormat: self.messages.columnFormat.day
+ },
+ agenda: {
+ titleFormat: self.messages.titleFormat.agenda,
+ columnHeaderFormat: self.messages.columnFormat.agenda
+ }
+ },
+ clickPopup: self.messages.clickPopup,
+ themeSystem: self.defaults.themeSystem,
+ editable: false,
+ defaultDate: self.defaults.calendarStart.toISOString(),
+ eventColor: self.defaults.color,
+ eventSources: [ {'events': data.events, 'holidays' : holidays } ],
+ eventRender: function( event, element, view ) {
+ that.event( event, element, view ).icon();
+ that.event( event, element, view ).description();
+
+ // Custom event hook
+ container.trigger( 'srf.eventcalendar.eventRender', { event: event, element: element, data: data } );
+ },
+ navLinks: data.query.ask.parameters.dayview,
+ dayClick: function( date, allDay, jsEvent ) {
+ // If the day number (where available) is clicked then switch to the daily view
+ if ( allDay && data.query.ask.parameters.dayview && $( jsEvent.target ).is( 'div.fc-day-number' ) ) {
+ container.fullCalendar( 'changeView', 'agendaDay'/* or 'basicDay' */).fullCalendar( 'gotoDate', date );
+ } else {
+ // redirect to a clicktarget URL if defined.
+ self.onDayClick( date, data, self.messages.clickPopup );
+ }
+ }
+ } );
+ },
+
+ /**
+ * Collection of all procedures necessary for an fc update
+ *
+ * Remove and add source data at once, no incremental update,
+ * All existing events are replaced with new event data
+ *
+ * @since 1.9
+ */
+ update: function(){
+ container.fullCalendar( 'removeEvents' );
+ container.fullCalendar( 'addEventSource', data.events );
+
+ // Moves the calendar to an arbitrary year/month/date
+ if ( _calendar.defaults.calendarStart !== null ){
+ container.fullCalendar( 'gotoDate', _calendar.defaults.calendarStart );
+ }
+ // Init resize
+ this.resize();
+ },
+
+ /**
+ * resize
+ * Adopt the display size only in case where the pane is visible
+ *
+ * @since 1.9
+ */
+ resize: function(){
+
+ var offset = mw.config.get( 'wgCanonicalNamespace' ) === 'Special' ? 8 : 1;
+
+ if ( context.find( '.srf-top' ).calendarpane( 'context' ).css( 'display' ) !== 'none' ){
+ var height = context.find( '.srf-top' ).calendarpane( 'context' ).height() - offset;
+ container.fullCalendar('option', 'height', Math.round( height ) );
+ context.height( ( height > container.height() ? height : container.height() ) + offset );
+ } else if( context.data( 'height' ) !== null ) {
+ container.fullCalendar( 'option', 'height', Math.round( context.data( 'height' ) ) );
+ context.height( ( context.data( 'height' ) > container.height() ? context.data( 'height' ) : container.height() ) );
+ } else {
+ container.fullCalendar( 'option', 'height', Math.round( context.height() ) );
+ }
+
+ container.resize();
+ },
+
+ /**
+ * eventRender
+ * Triggered while an event is being rendered.
+ *
+ * @since 1.9
+ */
+ event: function( event, element, view ){
+ return {
+ icon: function(){
+ // Manage icon elements
+ if ( event.eventicon ) {
+ // Find image url of the icon and an instance to the event
+ self.util.getImageURL( { 'title': event.eventicon },
+ function( url ) { if ( url !== false ) {
+ if ( element.find( '.fc-event-time' ).length ) {
+ element.find( '.fc-event-time' ).before( $( '<img src=' + url + ' />' ) );
+ } else {
+ element.find( '.fc-event-title' ).before( $( '<img src=' + url + ' />' ) );
+ }
+ }
+ } );
+ }
+ },
+ description: function(){
+ // Manage description elements
+ if ( event.description ) {
+ // Show the tooltip for the month view and render any additional description
+ // into the event for all other views
+ if ( element.find( '.fc-event-title' ).length && view.name !== 'month' && view.name.indexOf( 'Day' ) >= 0 ) {
+ element.find( '.fc-event-title' ).after( html.element( 'span', { 'class': 'srf-fc-description', 'property': 'v:description' }, event.description ) );
+ } else {
+ // Tooltip
+ self.tooltip.show( {
+ context: element,
+ content: _calendar.getTruncatedSentence( event.description, self.defaults.descriptionLength ),
+ title: mw.msg( 'smw-ui-tooltip-title-event' ),
+ button: false
+ } );
+ }
+ }
+ }
+ };
+ }
+ };
+ },
+
+ /**
+ * Returns srf.util class reference
+ *
+ * @since 1.9
+ */
+ util: new srf.util(),
+
+ /**
+ * Returns srf.api class reference
+ *
+ * @since 1.9
+ */
+ api: {
+ results: new srf.api.results(),
+ query: new srf.api.query(),
+ util: new srf.api.util()
+ },
+
+ /**
+ * Returns smw.tooltip class reference
+ *
+ * @since 1.9
+ */
+ tooltip: new smw.util.tooltip()
+ };
+
+ /**
+ * Inheritance class for the srf.formats constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @abstract
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Class that contains the Eventcalendar JavaScript result printer
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ * @extends srf.formats
+ */
+ srf.formats.eventcalendar = function() {};
+
+ /* Public methods */
+
+ srf.formats.eventcalendar.prototype = {
+
+ /**
+ * Default settings
+ *
+ * @since 1.9
+ *
+ * @property
+ */
+ defaults: {
+ autoUpdate: mw.user.options.get( 'srf-prefs-eventcalendar-options-update-default' ),
+ },
+
+ /**
+ * Initializes the DataTables instance
+ *
+ * @since 1.9
+ *
+ * @param {array} context
+ * @param {array} container
+ * @param {array} data
+ */
+ init: function( context, container, data ) {
+
+ // Hide loading spinner
+ context.find( '.srf-loading-dots' ).hide();
+
+ // Show container
+ container.css( { 'display' : 'block' , overflow: 'hidden' } );
+
+ // Set defaults
+ _calendar.defaults.set( data );
+
+ // Init fullCalendar container
+ _calendar.fullCalendar( context, container, data ).init();
+
+ // Add portlet sections using the calendarpane $.widget
+ var pane = context.find( '.srf-top' );
+ pane.calendarpane( {
+ 'show': _calendar.defaults.paneView
+ } );
+
+ // The legend portlet is managed by the srf.calendarlegend $.widget
+
+ // Add buttons using the calendarbutton $.widget
+ // Add paneView button
+ context.find( '.fc-right' ).append( '<div class="fc-button-group srf-button-group" ></div>' );
+ var group = context.find( '.srf-button-group' );
+
+ group.calendarbutton( {
+ 'class': 'pane',
+ left: true,
+ right: false,
+ icon : 'ui-icon ui-icon-bookmark',
+ title: mw.msg( 'srf-ui-common-label-paneview' ),
+ theme: _calendar.defaults.theme
+ } )
+ .on( 'click', '.srf-calendarbutton-pane' , function( event ) {
+ pane.calendarpane( 'toggle' );
+ _calendar.fullCalendar( context, container ).resize();
+ event.preventDefault();
+ } );
+
+ // Add refresh button
+ group.calendarbutton( {
+ 'class': 'refresh',
+ left: false,
+ right: true,
+ icon : 'ui-icon ui-icon-refresh',
+ title: mw.msg( 'srf-ui-common-label-refresh' ),
+ theme: _calendar.defaults.theme
+ } )
+ .on( 'click', '.srf-calendarbutton-refresh', function( event ) {
+ calendar.update( context, container, data );
+ event.preventDefault();
+ } );
+
+ // Add parameters using the calendarparameters $.widget
+
+ // Get all date properties from the api/results
+ var datePropertyList = _calendar.api.query.printouts.search.type(
+ data.query.ask.printouts,
+ data.query.result.printrequests,
+ ['_dat'] );
+
+ // Reassign original condition
+ var condition = {};
+ condition.description = data.query.ask.conditions;
+
+ // Datepicker and date selection
+ var datepicker = pane.calendarpane( 'portlet', {
+ 'class' : 'mini-calendar',
+ 'title' : '',
+ 'fieldset': false
+ } ).calendarparameters();
+
+ datepicker.calendarparameters( 'dateSelection', {
+ list : datePropertyList,
+ browser : profile.name,
+ dateFormat: _calendar.defaults.dateFormat,
+ gotoDate: function( date ) {
+ container.fullCalendar( 'gotoDate', date );
+ },
+ onReset: function() {
+ condition['start'] = '';
+ condition['end'] = '';
+ data.query.ask.conditions = condition;
+ calendar.update( context, container, data );
+ },
+ onSelect: function( ui ) {
+ // Reassign information received from the dateSelection portlet
+ if ( ui.fromProperty && ui.fromDate ){
+ condition['start'] = _calendar.api.query.conditions.build( ui.fromProperty, ui.fromDate, '::>' );
+ } else if( ui.toProperty && ui.toDate ){
+ condition['end'] = _calendar.api.query.conditions.build( ui.toProperty, ui.toDate, '::<' );
+ }
+ data.query.ask.conditions = condition;
+ if ( condition['start'] && condition['end'] ){
+ // Do an update via Ajax when conditions are met (from/to date)
+ calendar.update( context, container, data );
+ }
+ }
+ } );
+
+ // Init srf.calendarparameters widget
+ var param = pane.calendarpane( 'portlet', {
+ 'class' : 'parameters',
+ 'title' : mw.msg( 'srf-ui-common-label-parameters' ),
+ 'fieldset': true
+ } ).find( 'fieldset' ).calendarparameters();
+
+ // Start parameter
+ param.calendarparameters( 'eventStart', {
+ type: data.query.ask.parameters.start,
+ change: function( type ){
+ container.fullCalendar( 'gotoDate', _calendar.data.startDate( data.dates ).get( type ) );
+ data.query.ask.parameters.start = type;
+ _calendar.fullCalendar( context, container ).resize();
+ },
+ reset: function(){
+ data.query.ask.parameters.start = '';
+ container.fullCalendar( 'gotoDate', new Date() );
+ }
+ } );
+
+ // Limit parameter
+ param.calendarparameters( 'limit', {
+ limit : data.query.ask.parameters.limit,
+ count : data.query.result.meta.count,
+ max : _calendar.defaults.slider.max,
+ step : _calendar.defaults.slider.step,
+ change: function( event, value ) {
+ data.query.ask.parameters.limit = value ;
+ calendar.update( context, container, data );
+ }
+ } );
+
+ // Legend filter parameter
+ var filterList = _calendar.api.query.printouts.search.type(
+ data.query.ask.printouts,
+ data.query.result.printrequests,
+ ['_wpg', '_str', '_txt'] );
+
+ param.calendarparameters( 'colorFilter', {
+ list : filterList,
+ browser : profile.name,
+ onChange: function( event, ui ) {
+ data.query.ask.parameters.filterProperty = filterList[ ui.propertyIndex ];
+ data.query.ask.parameters.filterType = ui.filterType;
+ if ( ui.filterType !== undefined && ui.propertyIndex !== '' ){
+ _calendar.data.refresh( context, container, data, 'The filter settings were changed.' ); // @note mw.msg
+ }
+ },
+ onReset: function( event, ui ) {
+ data.query.ask.parameters.filterProperty = '';
+ data.query.ask.parameters.filterType = '';
+ _calendar.data.refresh( context, container, data, 'The filter settings were changed.' ); // @note mw.msg
+ }
+ } );
+
+ // Show colorFilter parameters only where a printrequest identifier
+ // 'color' has been found and where parameter=legend is not none
+ param.calendarparameters(
+ 'option', 'colorFilter', {
+ 'hide' : !( _calendar.api.query.printouts.search.identifier( data.query.ask.printouts, 'color' ) ) || data.query.ask.parameters.legend === 'none'
+ } );
+
+ // Legend
+ // Filters are checked by default, find filter elements in the original
+ // data source and add newly selected elements
+ context.calendarlegend( {
+ position: data.query.ask.parameters.legend,
+ wrapper: data.query.ask.parameters.legend === 'pane' ? 'srf-top' : 'srf-container',
+ list: data.legend,
+ defaultColor: _calendar.defaults.color,
+ theme : _calendar.defaults.theme,
+ onFilter: function( event, status, filter ) {
+ if ( status ){
+ var source = $.map( data.events, function( event ) {
+ if ( event.filter === filter ){
+ return event;
+ }
+ } );
+
+ // Add selected source data
+ container.fullCalendar( 'addEventSource', source );
+
+ } else {
+ // Unchecked status therefore remove elemtents with the specified filter
+ container.fullCalendar( 'removeEvents', function( event ) {
+ return event.filter === filter;
+ } );
+ }
+ }
+ } );
+
+ // Only IE: We need to set the width explicitly
+ if ( profile.name === 'msie' ){
+ var paneWidth = context.find( '.srf-calendarpane' ).width();
+ context.find( '.srf-calendarpane' ).css( { 'width' : paneWidth } );
+ }
+
+ // Resize for a better look and feel
+ _calendar.fullCalendar( context, container ).resize();
+
+ // Attach click event on the fc-buttons to ensure that
+ // a resize is being carried out each time the view is changed
+ container.find( '.fc-button-group' ).click( function() {
+ _calendar.fullCalendar( context, container ).resize();
+ } );
+ },
+
+ /**
+ * Public method to initiate a calendar update
+ *
+ * @since 1.9
+ *
+ * @param {Array} context
+ * @param {Array} container
+ * @param {Array} data
+ * @return {void}
+ */
+ update: function ( context, container, data ){
+ var self = this;
+
+ // Lock the current context to avoid queuing issues during the update
+ // process (e.g another button is pressed )
+ context.block( {
+ message: html.element( 'span', { 'class': 'mw-ajax-loader' }, '' ),
+ css: {
+ border: '2px solid #DDD',
+ height: '20px', 'padding-top' : '35px',
+ opacity: 0.8, '-webkit-border-radius': '5px',
+ '-moz-border-radius': '5px',
+ 'border-radius' : '5px'
+ },
+ overlayCSS: {
+ backgroundColor: '#fff',
+ opacity: 0.6,
+ cursor: 'wait'
+ }
+ } );
+
+ // Collect query information
+ var conditions = data.query.ask.conditions,
+ printouts = data.query.ask.printouts,
+ parameters = {
+ 'limit' : data.query.ask.parameters.limit,
+ 'offset': data.query.ask.parameters.offset
+ };
+
+ if ( data.query.ask.parameters.hasOwnProperty( 'sort' ) ) {
+ parameters.sort = data.query.ask.parameters.sort;
+ };
+
+ if ( data.query.ask.parameters.hasOwnProperty( 'order' ) ) {
+ parameters.order = data.query.ask.parameters.order;
+ };
+
+ // Stringify the query
+ var query = new smw.query( printouts, parameters, conditions ).toString();
+
+ var startDate = new Date();
+ srf.log( 'Query: ' + query );
+
+ // Fetch data via Ajax/SMWAPI
+ smwApi.fetch( query )
+ .done( function ( result ) {
+
+ srf.log( 'Api : ' + ( new Date().getTime() - startDate.getTime() ) + ' ms ' + '( ' + result.query.meta.count + ' object )' );
+
+ // Reassign api query data into the data array
+ $.extend( data.query.result, result.query );
+
+ // Refresh all internal objects
+ _calendar.data.refresh( context, container, data );
+
+ container.trigger( 'srf.eventcalendar.updateAfterParse' );
+
+ context.unblock( {
+ onUnblock: function(){ util.notification.create ( {
+ content: mw.msg( 'srf-ui-eventcalendar-label-update-success' )
+ } );
+ }
+ } );
+ } )
+ .fail( function ( error ) {
+ context.unblock( {
+ onUnblock: function(){ util.notification.create ( {
+ content: mw.msg( 'srf-ui-eventcalendar-label-update-error' ),
+ color: '#BF381A'
+ } );
+ }
+ } );
+ } );
+ },
+
+ /**
+ * Test interface which enables some internal methods / objects
+ * to be tested via qunit
+ *
+ * @since 1.9
+ *
+ * @ignore
+ */
+ test: {
+ _parse: _calendar.parse,
+ _getData: function( container ) { return smwApi.parse( _calendar.getData( container ) ) },
+ _startDate: function( dates ) { return _calendar.data.startDate( dates ) }
+ }
+ };
+
+ /**
+ * eventCalendar implementation
+ *
+ * @ignore
+ */
+ var calendar = new srf.formats.eventcalendar();
+
+ $( document ).ready( function() {
+ $( '.srf-eventcalendar' ).each( function() {
+
+ // The container and data object are specified as super-local
+ // object, this ensures that for this context instance any update
+ // is made made available for any other local function within the same
+ // instance
+ var context = $( this ),
+ container = context.find( '.srf-container' ),
+ data = smwApi.parse( _calendar.getData( container ) );
+
+ context.addClass( context.data( 'external-class' ) );
+
+ // An external class that sets a height less 350px is invalid as it
+ // causes inline distortion therefore set min height
+ if ( context.data( 'external-class' ) !== '' && context.height() < 350 ) {
+ context.removeClass( context.data( 'external-class' ) );
+ context.height( 350 );
+ }
+
+ // Whether a fixed height has been defined
+ if ( context.data( 'external-class' ) === '' ) {
+ context.data( 'height', 600 );
+ };
+
+ if ( data.query.ask.parameters.defaultview.indexOf( 'list' ) == 0 && context.height() < 350 ) {
+ context.data( 'height', 350 );
+ };
+
+ // Add bottom element to clear preceding elements and avoid display clutter
+ context.after( html.element( 'div', { 'class': 'srf-eventcalendar-clear srf-bottom', 'style': 'clear:both' } ) );
+
+ // Adopt directionality which ensures that all elements within this context
+ // are appropriately displayed
+ context.prop( 'dir', $( 'html' ).attr( 'dir' ) );
+
+ // Precautionary measure to make sure that no old content is used
+ if ( ( data === null || data.version === undefined || data.version < '0.8' ) ||
+ ( profile.name === 'msie' && profile.versionNumber < 9 ) ){
+ context.find( '.srf-loading-dots' ).hide();
+ _calendar.util.message.exception( {
+ context: context.find( '.srf-top' ),
+ message: ( profile.name === 'msie' && profile.versionNumber < 9 ) ? 'Your IE (' + profile.versionNumber + ') version is not supported!' : 'Please update your page content! This is required due to some internal changes.'
+ } );
+ }
+
+ // Parse JS array and merge with the data array
+ $.extend( data, _calendar.parse.api( data ) );
+
+ if ( data.events.length > 0 ) {
+ // Initial calendar setup
+
+ // Seen some race-conditions in 1.22 ResourceLoader therefore
+ // make sure that CSS/JS dependencies are "really" loaded before
+ // continuing
+ mw.loader.using( 'ext.srf.eventcalendar', function(){
+ calendar.init( context, container, data );
+
+ // Auto update if enabled via user-preference will ensure that events
+ // are properly updated and not used from an outdated parser cache
+ // where the initial array content was stored
+ if ( calendar.defaults.autoUpdate ) {
+ calendar.update( context, container, data );
+ }
+ } );
+
+ } else {
+ context.find( '.srf-loading-dots' ).hide();
+ _calendar.util.message.set( {
+ context: context.find( '.srf-top' ),
+ message: 'No results'
+ } );
+ }
+
+ // Allow to fetch the `srf.eventcalendar.fullCalendarRefresh` and trigger a click
+ // event to restore the fullCalendar in case the instance was part of tab (hidden
+ // during initialization)
+ $( document ).on( 'srf.eventcalendar.fullCalendarRefresh', function( event ) {
+ context.find( '.srf-calendarbutton-refresh' ).trigger( 'click' );
+ } );
+
+ // console.log( 'Data', data, 'Objects', _calendar );
+
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.hooks.eventcalendar.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.hooks.eventcalendar.js
new file mode 100644
index 00000000..b0a65864
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.hooks.eventcalendar.js
@@ -0,0 +1,48 @@
+/**
+ * Custom eventCalendar hook
+ *
+ * Those registered custom events/hooks be used for individual
+ * adjustment of event items
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ var html = mw.html;
+
+ var customHandler = {
+
+ // Experimental feature to encapsulate an event with an rdfa declaration
+ eventMetaData: function( handler ){
+ // Vocabulary
+ handler.element.wrap('<div xmlns:v="http://rdf.data-vocabulary.org/#" typeof="v:Event" />');
+ handler.element.attr( { 'rel': 'v:url', 'property' : 'v:summary' } );
+ var content = handler.element.find( '.fc-event-content');
+ // The date is not part of the event representation therefore we add this here
+ // to have a full set of properties assigned to an event
+ $( html.element( 'span', { 'style': 'display:none;', 'property': 'v:startDate' }, handler.event.start.toISOString() ) ).appendTo( handler.element );
+
+ if ( handler.event.end !== null ){
+ $( html.element( 'span', { 'style': 'display:none;', 'property': 'v:endDate' }, handler.event.end.toISOString() ) ).appendTo( handler.element );
+ }
+ }
+ }
+
+ $( document ).ready( function() {
+ $( '.srf-eventcalendar' ).each( function() {
+ var $this = $( this );
+
+ // eventcalendarEventRender customer trigger/hook
+ $this.on( "srf.eventcalendar.eventRender", '.container', function( event, dataHandler ) {
+ customHandler.eventMetaData( dataHandler );
+ } );
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarbutton.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarbutton.js
new file mode 100644
index 00000000..02685463
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarbutton.js
@@ -0,0 +1,113 @@
+/**
+ * SRF JavaScript for srf.calendarbutton widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* global mw:true, smw:true, mediaWiki:true, semanticMediawiki:true, semanticFormats:true */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE OBJECTS ////////////////////////
+
+ var html = mw.html;
+
+ ////////////////////////// FACTORY METHOD ////////////////////////
+
+ $.widget( 'srf.calendarbutton', {
+ options:{
+ right: true,
+ left: true
+ },
+
+ _init: function() {
+ var self = this,
+ el = self.element;
+
+ // Returns button element
+ function _element ( buttonClass, contentClass, title, theme ) {
+ return html.element( 'span', { 'class': buttonClass, 'title': title }, new html.Raw(
+ html.element( 'button', { 'class': 'fc-button ' + theme + '-state-default ' + ( self.options.left ? theme + '-corner-left ' : '' ) + ( self.options.right ? theme + '-corner-right' : '' ) }, new html.Raw(
+ html.element( 'span', { 'class': 'fc-button-inner' }, new html.Raw(
+ html.element( 'span', { 'class': 'fc-button-content' }, new html.Raw(
+ html.element( 'span', { 'class': 'fc-icon-wrap' }, new html.Raw(
+ html.element( 'div', { 'class': contentClass }, new html.Raw( '&nbsp;' ) ) ) ) ) ) +
+ html.element( 'span', { 'class': 'fc-button-effect' }, new html.Raw( html.element( 'span', {}, '' ) ) )
+ ) )
+ ) )
+ )
+ );
+ }
+
+ // Returns space element
+ function _space () {
+ return html.element( 'span', { 'class' : 'fc-header-space' }, '' );
+ }
+
+ // The tooltip button needs a special treatment as it is placed in between elements
+ if ( self.options.tooltip ){
+ this.button = $( _element ( self.widgetBaseClass + '-' + self.options['class'], self.options.icon, self.options.title, self.options.theme ) )
+ .insertAfter( el );
+ } else {
+ this.button = $( _space() + _element ( self.widgetBaseClass + '-' + self.options['class'], self.options.icon, self.options.title, self.options.theme ) )
+ .appendTo( el );
+ }
+
+ return this._hover();
+ },
+
+ /**
+ * Imitate fc hover button functionality
+ *
+ * @since 1.9
+ */
+ _hover: function( ) {
+ var self = this;
+ this.button = this.button || $();
+
+ var instance = this.button.find( '.fc-button' );
+ return instance
+ .mousedown( function() {
+ instance
+ .not( '.' + self.options.theme + '-state-active' )
+ .not( '.' + self.options.theme + '-state-disabled' )
+ .addClass( self.options.theme + '-state-down' );
+ } )
+ .mouseup( function() {
+ instance.removeClass( self.options.theme + '-state-down');
+ } )
+ .hover(
+ function() {
+ instance.addClass( self.options.theme + '-state-hover' );
+ },
+ function() {
+ instance
+ .removeClass( self.options.theme + '-state-hover')
+ .removeClass( self.options.theme + '-state-down');
+ }
+ );
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ var self = this;
+
+ if ( options['class'] ){
+ $( '.' + self.widgetBaseClass + '-' + options['class'] , this.element ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarlegend.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarlegend.js
new file mode 100644
index 00000000..aca2a65e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarlegend.js
@@ -0,0 +1,196 @@
+/**
+ * SRF JavaScript for srf.calendarlegend widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /* Private methods and objects */
+
+ /**
+ * Helper objects
+ *
+ * @since 1.9
+ *
+ * @ignore
+ * @private
+ * @static
+ */
+ var html = mw.html,
+ api = new srf.api.util(),
+ tooltip = new smw.util.tooltip();
+
+ /**
+ * $.widget function
+ *
+ * @since 1.9
+ * @type Object
+ */
+ $.widget( 'srf.calendarlegend', {
+ options:{
+ _BASE : 'srf-ui-legendList'
+ },
+
+ // Creates the outer frame which depends on the wrapper used to select its position
+ // The tooltip will initiate only if the _setOption detects a list{} object
+ // and initiates _refreshTooltip which ensures that qtip always holds the list{}
+ // content
+ _create: function() {
+ var self = this,
+ el = self.element;
+
+ if ( self.options.position === 'top' ) {
+ this.legend = $( html.element( 'div',{ 'class': self.options._BASE } , '') ).prependTo( $( '.' + self.options.wrapper , el ) );
+ this.legend.addClass( self.options.theme !== 'fc' ? 'top ui-state-default' : 'top basic' );
+ } else if ( self.options.position === 'bottom' ) {
+ this.legend = $( html.element( 'div',{ 'class': self.options._BASE } , '') ).appendTo( $( '.' + self.options.wrapper , el ) );
+ this.legend.addClass( self.options.theme !== 'fc' ? 'bottom ui-state-default' : 'bottom basic' );
+ } else if ( self.options.position === 'pane' ) {
+ el.find( '.' + self.options.wrapper ).calendarpane( 'portlet', {
+ 'class' : self.options._BASE + ' pane',
+ 'title' : 'Legend',
+ 'fieldset': true
+ } );
+ }
+ self.legend = this.legend;
+ this._refreshList( self.options.list );
+ },
+
+ // Something has to be done here, the current implementation
+ // could be improved but foremost it works therefore I don't bother
+ _refreshTooltip: function( list ){
+ var self = this,
+ el = self.element;
+
+ // Add button
+ el.find( '.fc-header-right > .fc-button-today' ).next().calendarbutton( {
+ 'class': 'tooltip',
+ 'icon' : 'ui-icon ui-icon-gear',
+ 'title': '',
+ 'theme': this.options.theme,
+ 'right': false,
+ 'tooltip': true
+ } );
+
+ // Add tooltip instance for legend/filters
+ tooltip.add( {
+ contextClass: 'srf-ui-legend-tooltip',
+ contentClass: 'srf-ui-legend-tooltip-content',
+ targetClass : 'srf-calendarbutton-tooltip',
+ context: el,
+ title: 'Legend',
+ type: 'info',
+ //event: 'click',
+ button: true,
+ content: list
+ } );
+
+ },
+
+ // Generate the filter/legend content
+ _refreshList:function( options ){
+ var self = this,
+ el = self.element;
+
+ // Returns coloured square element(s)
+ function itemSquare( colors, defaultColor ){
+ var element = '';
+ $.each( api.array.unique( colors ), function( i, value ) {
+ element = element + '<span class="srf-ui-legend-square" style="background-color:' + ( value || defaultColor ) + '";></span>';
+ } );
+ return element;
+ }
+
+ // Returns a list of legend/filter elements
+ function itemList( list, type, defaultColor ) {
+ if ( list !== undefined ) {
+ var elements = [];
+
+ $.each( list, function( key, item ) {
+ if ( key !== '' ) {
+ elements.push(
+ ( type === 'filter' ? '<input type="checkbox" checked="checked" name="' + key + '"/>' : '' ) +
+ itemSquare( item.color, defaultColor ) + '<span class="srf-ui-legend-label">' + key + '</span>'
+ );
+ }
+ } );
+ return '<ul><li class="srf-legend-item">'+ elements.join('</li><li class="srf-legend-item">') + '</li></ul>';
+ }
+ }
+
+ // Only do a refresh for a non-empty list otherwise hide
+ if ( !$.isEmptyObject( options.list ) ) {
+ $( '.' + this.options._BASE , this.element ).show();
+
+ if ( this.options.position === 'pane' ){
+ this.legend = $( itemList( options.list, options.type, this.options.defaultColor ) ).insertAfter( $( '.' + self.options._BASE + '> fieldset > legend' , el ) );
+ } else if ( this.options.position === 'tooltip' ){
+ this._refreshTooltip( itemList( options.list, options.type, this.options.defaultColor ) );
+ self.legend = $( '.srf-ui-legend-tooltip-content', el );
+ } else {
+ this.legend = $( itemList( options.list, options.type, this.options.defaultColor ) ).prependTo( $( '.' + self.options._BASE , el ) );
+ }
+
+ // Enable a callback to manipulate the event source in accordance
+ // with its assigned/unassigned filter
+ // returns true/false status
+ self.legend.on( 'click', ':checkbox', function( event ){
+ var state = $( this ),
+ filter = state.attr( 'name' );
+
+ if ( $.isFunction( self.options.onFilter ) ){
+ self.options.onFilter( event, state.is( ':checked' ), filter );
+ }
+ } );
+ } else {
+ $( '.' + this.options._BASE , this.element ).hide();
+ }
+ },
+
+ // Remove list items from the main element
+ _remove: function(){
+ var self = this,
+ el = self.element;
+
+ if ( this.options.position === 'pane' ){
+ $( '.' + this.options._BASE + ' > fieldset > ul' , this.element ).remove();
+ } else if ( this.options.position === 'tooltip' ){
+ el.find( '.fc-header-right' ).calendarbutton( 'destroy', { 'class' : 'tooltip' } );
+ el.find( '.srf-ui-legend-tooltip' ).remove();
+ } else{
+ $( '.' + this.options._BASE + ' > ul' , this.element ).remove();
+ }
+ },
+
+ // Receives update information from outside
+ _setOption: function ( name, value ) {
+ if( name === 'list') {
+ this._remove( );
+ this._refreshList( value );
+ }
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ /**
+ * Removes instance objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.pane ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarpane.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarpane.js
new file mode 100644
index 00000000..f2164c89
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarpane.js
@@ -0,0 +1,109 @@
+/**
+ * SRF JavaScript srf.eventcalendarpane widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Html element generation
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ */
+ $.widget( 'srf.calendarpane', {
+
+ /**
+ * Create methods runs once during initialization
+ *
+ * @return object
+ */
+ _create: function() {
+ var self = this,
+ el = self.element;
+
+ this.pane = $(
+ html.element( 'div', { 'class': self.widgetBaseClass }, '' )
+ ).insertAfter( el );
+ return this.pane.css( {
+ 'display' : ( this.options.show ? 'block' : 'none' )
+ } )
+ },
+
+ /**
+ * Returns the pane context
+ *
+ * @since 1.9
+ * @return object
+ */
+ context: function( ) {
+ return this.pane;
+ },
+
+ /**
+ * Adds a portlet
+ *
+ * @since 1.9
+ * @var options
+ */
+ portlet: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Specify the pane instance
+ this.pane = this.pane || $();
+
+ // Append
+ this.panePortlet = $(
+ html.element( 'div', {
+ 'id': self.widgetBaseClass + '-' + options['class'],
+ 'class': options['class'] },
+ new html.Raw( ( options['fieldset'] ? html.element( 'fieldset', {},
+ new html.Raw( html.element( 'legend', { }, options['title'] ) ) ) : ''
+ )
+ )
+ )
+ ).appendTo( this.pane );
+
+ self.panePortlet = this.panePortlet;
+ return options.hide ? self.panePortlet.hide() : self.panePortlet.show() ;
+ },
+
+ /**
+ * Depending on its state toggle show/hide
+ *
+ * @since 1.9
+ */
+ toggle: function() {
+ return this.pane.css( 'display' ) === 'none' ? this.pane.show(): this.pane.hide();
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.pane ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarparameters.js b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarparameters.js
new file mode 100644
index 00000000..25fa333f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/ext.srf.widgets.calendarparameters.js
@@ -0,0 +1,351 @@
+/**
+ * SRF JavaScript for srf.calendarparameters widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* global mw:true, smw:true, mediaWiki:true, semanticMediawiki:true, semanticFormats:true */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE OBJECTS ////////////////////////
+
+ var html = mw.html;
+ var util = new srf.util();
+
+ ////////////////////////// FACTORY METHOD ////////////////////////
+
+ $.widget( 'srf.calendarparameters', {
+
+ _init: function() {
+ var self = this,
+ el = self.element;
+ return el;
+ },
+
+ /**
+ * Datepicker/date selection portlet input methods
+ *
+ * @since 1.9
+ */
+ dateSelection: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Date range input elements
+ function dateInput( list, name ){
+ return html.element( 'fieldset', {}, new html.Raw(
+ html.element( 'legend', { }, mw.msg( 'srf-ui-common-label-daterange' ) ) +
+ html.element( 'input', { 'type': 'radio', 'name': 'option', 'id': 'from', 'value': 'f' }, '' ) +
+ html.element( 'label', { 'for' : 'from'}, 'From' ) +
+ html.element( 'input', { 'type': 'radio', 'name': 'option', 'id': 'to', 'value': 't' }, '' ) +
+ html.element( 'label', { 'for' : 'to'}, 'to' ) +
+ html.element( 'span', { 'class': 'reset-link' }, 'Reset' ) + '<br />' +
+ util.html.dropdown( {
+ list: list,
+ id: 'printouts',
+ selectClass: 'printouts',
+ browser: name,
+ disabled: 'disabled'
+ } ) +
+ html.element( 'input', { 'id': 'mini-calendar-from', 'size': '8', 'readonly': 'readonly' }, '' ) +
+ html.element( 'input', { 'id': 'mini-calendar-to', 'class': 'input-right', 'size': '8', 'readonly': 'readonly' }, '' )
+ ) );
+ }
+
+ self.calendar = $( html.element( 'div', { 'class' : 'datepicker' }, '' ) ).appendTo( el );
+ self.input = $( html.element( 'div', { 'class' : 'options' }, new html.Raw( dateInput( options.list, options.browser ) ) ) ).appendTo( el );
+
+ // Datepicker module
+ self.calendar.datepicker( {
+ inline: true,
+ showOtherMonths: true,
+ changeMonth: true,
+ changeYear: true,
+ dateFormat: options.dateFormat ,
+ onChangeMonthYear: function( year, month, inst ) {
+ // @note Something for later var date = new Date(); container.fullCalendar('gotoDate', year, month, date.getDate());
+ },
+ onSelect: function( dateText, inst){
+ var date = new Date(dateText),
+ option = $( 'input:radio[name=option]:checked', self.input ).val();
+
+ // Use the stored index to find the related property
+ var fromProperty = options.list[ $( '#mini-calendar-from', self.input ).data( 'property' ) ],
+ toProperty = options.list[ $( '#mini-calendar-to', self.input ).data( 'property' ) ];
+
+ if ( option === 'f' && fromProperty !== undefined ){
+ $( '#mini-calendar-from', self.input ).val( dateText ); // updates the date
+ $( 'input:radio[name=option]', self.input ).prop( 'checked', false ); // uncheck this option
+ $( '#printouts', self.input ).prop( 'disabled', true ); // disables the dropdown
+ self.calendar.datepicker( "option", { "maxDate": null, "minDate": null } ); // set datepicker min/max values to null
+ // Use the onSelect callback
+ if ( $.isFunction( options.onSelect ) ){
+ options.onSelect( { fromProperty: fromProperty, fromDate: dateText } );
+ }
+ } else if( option === 't' && toProperty !== undefined ){
+ $( '#mini-calendar-to', self.input ).val( dateText ); // updates the date
+ $( 'input:radio[name=option]', self.input ).prop( 'checked', false ); // uncheck this option
+ $( '#printouts', self.input ).prop( 'disabled', true ); // disables the dropdown
+ self.calendar.datepicker( "option", { "maxDate": null, "minDate": null } ); // set datepicker min/max values to null
+ // Use the onSelect callback
+ if ( $.isFunction( options.onSelect ) ){
+ options.onSelect( { toProperty: toProperty, toDate: dateText } );
+ }
+ } else if ( option === undefined ) {
+ // Use the gotoDate callback since in the current state
+ // all actions are related to date navigation only
+ if ( $.isFunction( options.gotoDate ) ){
+ options.gotoDate( date );
+ }
+ }
+ // @note Something for later var view = container.fullCalendar('getView'); if ( view.name == 'agendaWeek' ){ container.fullCalendar( 'changeView', 'agendaWeek' );} else { container.fullCalendar( 'changeView', 'agendaDay' ); }
+ }
+ } );
+
+ // Handle events for when the printout dropdown is changed
+ // This way we know which printout property belongs to the from or to
+ // option and store it to the associated .data() element
+ self.input.on( 'change', '#printouts', function( event ){
+ var option = $( 'input:radio[name=option]:checked', self.input ).val();
+ if ( option === 'f' ){
+ $( '#mini-calendar-from', self.input ).data( 'property', $( this ).val() );
+ } else if( option === 't' ){
+ $( '#mini-calendar-to', self.input ).data( 'property', $( this ).val() );
+ }
+ } );
+
+ // Handle events for the radio/reset in order to determine which
+ // dropdown selection belongs to which from/to property and store those
+ // information as .data() so that when the datepicker triggers a onSelect
+ // event those data together with the date selected will be sent back to
+ // the callback
+ self.input.on( 'click', 'input:radio[name=option], .reset-link', function( event ){
+ var fromDate = $( '#mini-calendar-from', self.input ).val(),
+ toDate = $( '#mini-calendar-to', self.input ).val(),
+ option = $( this ).val();
+
+ if ( option === 'f' ){
+ self.calendar.datepicker( "setDate", fromDate );
+ self.calendar.datepicker( "option", { "maxDate": toDate, "minDate": null } );
+ // Reset dropdown value to the stored property for this option
+ $( '#printouts', self.input ).prop( 'disabled', false ).val( $( '#mini-calendar-from', self.input ).data( 'property' ) );
+ } else if( option === 't' ){
+ self.calendar.datepicker( "setDate", toDate );
+ self.calendar.datepicker( "option", { "maxDate": null, "minDate": fromDate } );
+ $( '#printouts', self.input ).prop( 'disabled', false ).val( $( '#mini-calendar-to', self.input ).data( 'property' ) );
+ } else {
+ // Reset all values and conditions related to date selection
+ $( '#mini-calendar-from', self.input ).val( '' ).data( 'property', '' );
+ $( '#mini-calendar-to', self.input ).val( '' ).data( 'property', '' );
+ $( '#printouts', self.input ).val( '' ).prop( 'disabled', true );
+ $( 'input:radio[name=option]', self.input ).prop( 'checked', false );
+ self.calendar.datepicker( "option", { "maxDate": null, "minDate": null } );
+ // Use the onReset callback
+ if ( $.isFunction( options.onReset ) ){
+ options.onReset( event );
+ }
+ }
+ } );
+ },
+
+ /**
+ * Limit paramter
+ *
+ * @since 1.9
+ */
+ limit: function( options ) {
+ var self = this,
+ el = self.element;
+
+ function element(){
+ return html.element( 'div', { 'class': 'limitparam' }, new html.Raw(
+ html.element( 'div', { 'class' : 'parameter-section' }, 'Limit parameter' ) + // @note mw.msg
+ html.element( 'div', { 'class': 'label' }, 'Limit' ) + // @note mw.msg
+ html.element( 'span', { 'class': 'value' }, '' ) +
+ html.element( 'span', { 'class': 'count' }, '' ) + '<br/>' +
+ html.element( 'div', { 'class': 'slider' }, '' )
+ ) );
+ }
+
+ this.limit = $( element() ).appendTo( el );
+
+ this.limit.find( '.slider' ).slider( {
+ range: 'min',
+ value: options.limit,
+ min: 1,
+ max: options.max,
+ step: options.step,
+ slide: function( event, ui ){
+ self._limitParameterUpdate( { limit: self._limitConstrain( ui.value ) } );
+ },
+ change: function( event, ui ){
+ if ( $.isFunction( options.change ) ){
+ options.change( event, self._limitConstrain( ui.value ) );
+ }
+ }
+ } );
+
+ // Show initial limit/count
+ this._limitParameterUpdate( { limit: options.limit, count: options.count } );
+ },
+
+ /**
+ * Limit/count value update
+ *
+ * @since 1.9
+ */
+ _limitParameterUpdate: function( options ){
+ var self = this,
+ el = self.element;
+
+ $( '.value', self.element ).text( options.limit );
+
+ if ( options.count ){
+ $( '.count', self.element ).text( '[ ' + options.count + ' ]' );
+ } else {
+ $( '.count', self.element ).text( '' );
+ }
+ },
+
+ _limitConstrain: function( value ){
+ return value > 1 ? value - 1 : value;
+ },
+
+ /**
+ * Start (earliest/latest) paramter portlet content
+ *
+ * @since 1.9
+ */
+ eventStart: function( options ){
+ var self = this,
+ _BASE = self.widgetBaseClass + '-minmax',
+ el = self.element;
+
+ function element(){
+ return html.element( 'div', { 'class': 'minmax' }, new html.Raw(
+ html.element( 'div', { 'class' : 'parameter-section' }, 'Start parameter' ) + // @note mw.msg
+ html.element( 'input', { 'type': 'radio', 'name': 'minmax', 'id': 'min', 'value': 'earliest'}, '' ) +
+ html.element( 'label', { 'for' : 'min'}, 'Earliest' ) + // @note mw.msg
+ html.element( 'input', { 'type': 'radio', 'name': 'minmax', 'id': 'max', 'value': 'latest' }, '' ) +
+ html.element( 'label', { 'for' : 'max'}, 'Latest' ) + // @note mw.msg
+ html.element( 'span', { 'class': 'reset-link' }, 'Reset' ) + '<br />' // @note mw.msg
+ ) );
+ }
+
+ // Add the element
+ this.minmax = $( element() ).appendTo( el );
+ self.minmax = this.minmax;
+
+ // Set options default
+ if ( options.type === 'earliest' ){
+ $( '#min', self.minmax ).prop( 'checked', true );
+ } else if ( options.type === 'latest' ){
+ $( '#max', self.minmax ).prop( 'checked', true );
+ }
+
+ // Event handling
+ self.minmax.on( 'change', '#min, #max' ,function ( event ) {
+ if ( $.isFunction( options.change ) ){
+ options.change( $( 'input:radio[name=minmax]:checked', self.minmax ).val() );
+ }
+ } )
+ .on( 'click', '.reset-link' ,function ( event ) {
+ $( 'input:radio[name=minmax]', self.minmax ).prop( 'checked', false );
+ if ( $.isFunction( options.reset ) ){
+ options.reset();
+ }
+ } );
+ },
+
+
+ /**
+ * colorFilter portlet content
+ *
+ * @since 1.9
+ */
+ colorFilter: function( options ){
+ var self = this,
+ _BASE = self.widgetBaseClass + '-filter',
+ el = self.element;
+
+ function element( list, name ){
+ return html.element( 'div', { 'class': 'filterparam' }, new html.Raw(
+ html.element( 'div', { 'class' : 'parameter-section' }, 'Filter parameter' ) + // @note mw.msg
+ html.element( 'input', { 'type': 'radio', 'name': 'filterType', 'id': 'legend', 'value': 'legend'}, '' ) +
+ html.element( 'label', { 'for' : 'legend'}, 'Legend' ) + // @note mw.msg
+ html.element( 'input', { 'type': 'radio', 'name': 'filterType', 'id': 'filter', 'value': 'filter' }, '' ) +
+ html.element( 'label', { 'for' : 'filter'}, 'Filter' ) + // @note mw.msg
+ html.element( 'span', { 'class': 'reset-link' }, 'Reset' ) + '<br />' + // @note mw.msg
+ util.html.dropdown( {
+ list: list,
+ id: 'filterproperty',
+ selectClass: 'filter',
+ browser: name,
+ disabled: 'disabled'
+ } )
+ ) );
+ }
+
+ // Add the element
+ this.filterparam = $( element( options.list, options.browser ) ).appendTo( el );
+
+ self.filterparam = this.filterparam;
+
+ // Radio button, dropdown change handling
+ self.filterparam.on( 'change', '#filterproperty, #legend, #filter' ,function ( event ) {
+ var propertyIndex = $( '#filterproperty', self.filterparam ).val(),
+ filterType = $( 'input:radio[name=filterType]:checked', self.filterparam ).val();
+ $( '#filterproperty', self.filterparam ).prop( 'disabled', false );
+ if ( $.isFunction( options.onChange ) ){
+ options.onChange( event, { propertyIndex: propertyIndex, filterType: filterType } );
+ }
+ } )
+ .on( 'click', '.reset-link' ,function ( event ) {
+ // Handle reset option (all values and conditions are set to null)
+ if( $( '#filterproperty', self.filterparam ).val() && $( 'input:radio[name=filterType]:checked', self.filterparam ).val() ){
+ $( '#filterproperty', self.filterparam ).val( '' ).prop( 'disabled', true );
+ $( 'input:radio[name=filterType]', self.filterparam ).prop( 'checked', false );
+ if ( $.isFunction( options.onReset ) ){
+ options.onReset( event );
+ }
+ }
+ } );
+ },
+
+ _setOption: function ( name, value ) {
+ switch( name ){
+ case 'limit':
+ this._limitParameterUpdate( value );
+ break;
+ case 'colorFilter':
+ value.hide ? this.filterparam.hide() : this.filterparam.show();
+ break;
+ case 'eventStart':
+ this.eventStart( value );
+ break;
+ }
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.pane ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/left-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/left-arrow.png
new file mode 100644
index 00000000..f48c7c86
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/left-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/right-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/right-arrow.png
new file mode 100644
index 00000000..bbb48c57
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/calendar/resources/images/right-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/SRF_D3Chart.php b/www/wiki/extensions/SemanticResultFormats/formats/d3/SRF_D3Chart.php
new file mode 100644
index 00000000..43fb9e60
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/SRF_D3Chart.php
@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * A query printer for D3 charts using the D3 JavaScript library
+ * and SMWAggregatablePrinter.
+ *
+ * @file SRF_D3Chart.php
+ * @ingroup SemanticResultFormats
+ * @licence GNU GPL v2 or later
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ */
+class SRFD3Chart extends SMWAggregatablePrinter {
+
+ /*
+ * @see SMWResultPrinter::getName
+ *
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-d3chart' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getFormatOutput
+ *
+ * @since 1.8
+ *
+ * @param array $data label => value
+ *
+ * @return string
+ */
+ protected function getFormatOutput( array $data ) {
+
+ // Object count
+ static $statNr = 0;
+ $d3chartID = 'd3-chart-' . ++$statNr;
+
+ $this->isHTML = true;
+
+ // Reorganize the raw data
+ foreach ( $data as $name => $value ) {
+ if ( $value >= $this->params['min'] ) {
+ $dataObject[] = [ 'label' => $name, 'value' => $value ];
+ }
+ }
+
+ // Ensure right conversion
+ $width = strstr( $this->params['width'], "%" ) ? $this->params['width'] : $this->params['width'] . 'px';
+
+ // Prepare transfer objects
+ $d3data = [
+ 'data' => $dataObject,
+ 'parameters' => [
+ 'colorscheme' => $this->params['colorscheme'] ? $this->params['colorscheme'] : null,
+ 'charttitle' => $this->params['charttitle'],
+ 'charttext' => $this->params['charttext'],
+ 'datalabels' => $this->params['datalabels']
+ ]
+ ];
+
+ // Encoding
+ $requireHeadItem = [ $d3chartID => FormatJson::encode( $d3data ) ];
+ SMWOutputs::requireHeadItem( $d3chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // RL module
+ $resource = 'ext.srf.d3.chart.' . $this->params['charttype'];
+ SMWOutputs::requireResource( $resource );
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [
+ 'id' => $d3chartID,
+ 'class' => 'container',
+ 'style' => 'display:none;'
+ ],
+ null
+ );
+
+ // Processing placeholder
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // Beautify class selector
+ $class = $this->params['charttype'] ? '-' . $this->params['charttype'] : '';
+ $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class . ' d3-chart-common';
+
+ // D3 wrappper
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-d3-chart' . $class,
+ 'style' => "width:{$width}; height:{$this->params['height']}px;"
+ ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-minvalue',
+ 'default' => false,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['charttype'] = [
+ 'message' => 'srf-paramdesc-charttype',
+ 'default' => 'treemap',
+ 'values' => [ 'treemap', 'bubble' ],
+ ];
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_chartheight',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ $params['width'] = [
+ 'message' => 'srf_paramdesc_chartwidth',
+ 'default' => '100%',
+ ];
+
+ $params['charttitle'] = [
+ 'message' => 'srf_paramdesc_charttitle',
+ 'default' => '',
+ ];
+
+ $params['charttext'] = [
+ 'message' => 'srf-paramdesc-charttext',
+ 'default' => '',
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['datalabels'] = [
+ 'message' => 'srf-paramdesc-datalabels',
+ 'default' => 'none',
+ 'values' => [ 'value', 'label' ],
+ ];
+
+ $params['colorscheme'] = [
+ 'message' => 'srf-paramdesc-colorscheme',
+ 'default' => '',
+ 'values' => $GLOBALS['srfgColorScheme'],
+ ];
+
+ $params['chartcolor'] = [
+ 'message' => 'srf-paramdesc-chartcolor',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/LICENSE ColorBrewer b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/LICENSE ColorBrewer
new file mode 100644
index 00000000..2ac775d6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/LICENSE ColorBrewer
@@ -0,0 +1,38 @@
+Apache-Style Software License for ColorBrewer software and ColorBrewer Color
+Schemes
+
+Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State
+University.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions as source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. The end-user documentation included with the redistribution, if any, must
+include the following acknowledgment: "This product includes color
+specifications and designs developed by Cynthia Brewer
+(http://colorbrewer.org/)." Alternately, this acknowledgment may appear in the
+software itself, if and wherever such third-party acknowledgments normally
+appear.
+
+4. The name "ColorBrewer" must not be used to endorse or promote products
+derived from this software without prior written permission. For written
+permission, please contact Cynthia Brewer at cbrewer@psu.edu.
+
+5. Products derived from this software may not be called "ColorBrewer", nor
+may "ColorBrewer" appear in their name, without prior written permission of
+Cynthia Brewer.
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.css b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.css
new file mode 100644
index 00000000..0f385465
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.css
@@ -0,0 +1,31 @@
+/**
+ * CSS for SRF D3 module
+ *
+ * Based on the official D3 Bar Chart tutorial
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.1
+ */
+.srf-d3-chart-bubble circle {
+ fill: rgb(31, 119, 180);
+ fill-opacity: .25;
+ stroke: rgb(31, 119, 180);
+ stroke-width: 1px;
+}
+
+.srf-d3-chart-bubble .node circle {
+ fill: transparency;
+ stroke: transparency;
+ stroke-width: 0px;
+}
+
+.srf-d3-chart-bubble .leaf circle {
+ fill: #ff7f0e;
+ fill-opacity: 1;
+}
+
+.srf-d3-chart-bubble text {
+ font: 10px sans-serif;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.js b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.js
new file mode 100644
index 00000000..c158030d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.bubble.js
@@ -0,0 +1,122 @@
+/**
+ * JavaScript for SRF D3 chart bubble module using d3 v2
+ * @see http://www.semantic-mediawiki.org/wiki/Help:D3chart format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, srf ) {
+ 'use strict';
+
+ /*global d3:true, mw:true, colorscheme:true*/
+ /**
+ * Module for formats extensions
+ * @since 1.8
+ * @type Object
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a d3 instance
+ * @since 1.8
+ * @type Object
+ */
+ srf.formats.d3 = function() {};
+
+ srf.formats.d3.prototype = {
+ bubble: function( context ) {
+ return context.each( function() {
+ var width = $( this ).width(),
+ height = $( this ).height(),
+ chart = $( this ).find( '.container' ),
+ d3ID = chart.attr( 'id' ),
+ json = mw.config.get( d3ID );
+
+ // Parse json string and convert it back
+ var container = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ var charttitle = container.parameters.charttitle,
+ charttext = container.parameters.charttext,
+ datalabels = container.parameters.datalabels,
+ colors = container.parameters.colorscheme === null ? colorscheme[0] : colorscheme[container.parameters.colorscheme][9];
+
+ // Release the graph
+ util.spinner.hide( { context: $( this ) } );
+ $( this ).css( 'width', width ).css( 'height', height);
+ chart.show();
+
+ // Add chart title
+ if ( charttitle.length > 0 ) {
+ charttitle = '<span class="srf-d3-chart-title">' + charttitle + '</span>';
+ $( this ).find( '#' + d3ID ).before( charttitle );
+ }
+
+ // Add bottom chart text
+ if ( charttext.length > 0 ) {
+ charttext = '<span class="srf-d3-chart-text">' + charttext + '</span>';
+ $( this ).find( '#' + d3ID ).after( charttext );
+ }
+
+ // Calculate height
+ height = height - ( $( this ).find( '.srf-d3-chart-title' ).height() + $( this ).find( '.srf-d3-chart-text' ).height() );
+
+ // Create an ordinal color array and set formatting
+ var color = d3.scale.ordinal().range( colors ),
+ format = d3.format( ",d" );
+
+ // Data array definition
+ var packlayout = [];
+ packlayout.push( {
+ label: charttitle !== '' ? container.parameters.charttitle : mw.config.get ( 'wgTitle' ),
+ children: container.data
+ } );
+
+ var pack = d3.layout.pack()
+ .size([width - 4, height - 4])
+ .value( function( d ) { return d.value; } );
+
+ var vis = d3.select( "#" + d3ID ).append( "svg" )
+ .attr( "width", width )
+ .attr( "height", height )
+ .attr( "class", "pack" )
+ .append( "g" )
+ .attr( "transform", "translate(2, 2)" );
+
+ var node = vis.data(packlayout).selectAll("g.node")
+ .data( pack.nodes )
+ .enter().append("g")
+ .attr( "class", function( d ) { return d.children ? "node" : "leaf node"; } )
+ .attr( "transform", function( d ) { return "translate(" + d.x + "," + d.y + ")"; } );
+
+ node.append("title")
+ .text(function( d ) { return d.label + ( d.children ? "" : ": " + format( d.value ) ); } );
+
+ node.append( "circle" )
+ .attr( "r" , function( d ) { return d.r; } )
+ .style( "fill" , function( d ) { return d.children ? null : color( d.label ); } );
+
+ node.filter(function( d ) { return !d.children; } ).append("text")
+ .attr( "text-anchor", "middle" )
+ .attr( "dy", ".3em" )
+ .text( function( d ) { return d.children ? null : datalabels === 'value' ? d.value : d.label.substring( 0, d.r / 3 ); } );
+ } );
+ }
+ };
+
+ /**
+ * Implementation and representation of the d3 treemap instance
+ * @since 1.8
+ * @type Object
+ */
+ var srfD3 = new srf.formats.d3();
+ var util = new srf.util();
+
+ $(document).ready(function() {
+ $( '.srf-d3-chart-bubble' ).each(function() {
+ srfD3.bubble( $( this ) );
+ } );
+ } );
+} )( jQuery, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.css b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.css
new file mode 100644
index 00000000..eed5f0ee
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.css
@@ -0,0 +1,18 @@
+/**
+ * CSS for SRF D3 module
+ *
+ * Based on the official D3 treemap chart tutorial
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.1
+ */
+.srf-d3-chart-treemap .cell {
+ border: solid 1px white;
+ font: 10px sans-serif;
+ line-height: 12px;
+ overflow: hidden;
+ position: absolute;
+ text-indent: 2px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.js b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.js
new file mode 100644
index 00000000..6055b31f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.chart.treemap.js
@@ -0,0 +1,127 @@
+/**
+ * JavaScript for SRF D3 chart treemap module using d3 v2
+ * @see http://www.semantic-mediawiki.org/wiki/Help:D3chart format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, srf ) {
+ 'use strict';
+
+ /*global d3:true, mw:true, colorscheme:true*/
+
+ /**
+ * Module for formats extensions
+ * @since 1.8
+ * @type Object
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a d3 instance
+ * @since 1.8
+ * @type Object
+ */
+ srf.formats.d3 = function() {};
+
+ srf.formats.d3.prototype = {
+ treemap: function( context ) {
+ return context.each( function() {
+ var width = $( this ).width(),
+ height = $( this ).height(),
+ chart = $( this ).find( '.container' ),
+ d3ID = chart.attr( 'id' ),
+ json = mw.config.get( d3ID );
+
+ // Parse json string and convert it back
+ var container = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ var charttitle = container.parameters.charttitle,
+ charttext = container.parameters.charttext,
+ datalabels = container.parameters.datalabels,
+ colors = container.parameters.colorscheme === null ? colorscheme[0] : colorscheme[container.parameters.colorscheme][9];
+
+ // Release the graph
+ util.spinner.hide( { context: $( this ) } );
+ $( this ).css( 'width', width ).css( 'height', height);
+ chart.show();
+
+ // Add chart title
+ if ( charttitle.length > 0 ) {
+ charttitle = '<span class="srf-d3-chart-title">' + charttitle + '</span>';
+ $( this ).find( '#' + d3ID ).before( charttitle );
+ }
+
+ // Add bottom chart text
+ if ( charttext.length > 0 ) {
+ charttext = '<span class="srf-d3-chart-text">' + charttext + '</span>';
+ $( this ).find( '#' + d3ID ).after( charttext );
+ }
+
+ // Calculate height
+ height = height - ( $( this ).find( '.srf-d3-chart-title' ).height() + $( this ).find( '.srf-d3-chart-text' ).height() );
+
+ // Create an ordinal color array and set formatting
+ var color = d3.scale.ordinal().range( colors ),
+ format = d3.format( ',d' );
+
+ // Data array definition
+ var treeArray = [];
+ treeArray.push( {
+ label: charttitle !== '' ? container.parameters.charttitle : mw.config.get ( 'wgTitle' ),
+ children: container.data
+ } );
+
+ // Init layout
+ var treemap = d3.layout.treemap()
+ .padding( 4 )
+ .size([ width , height ])
+ .value( function( d ) { return d.value; } );
+
+ var svg = d3.select( '#' + d3ID ).append( 'svg' )
+ .attr( 'width', width )
+ .attr( 'height', height )
+ .append( 'g' )
+ .attr( 'transform', 'translate(-.5,-.5)' );
+
+ var cell = svg.data( treeArray ).selectAll( 'g' )
+ .data( treemap )
+ .enter().append( 'g' )
+ .attr( 'class', 'cell' )
+ .attr( 'transform', function( d ) { return 'translate(' + d.x + ',' + d.y + ')'; } );
+
+ cell.append( 'title' )
+ .text( function( d ) { return d.label + ( d.children ? '' : ': ' + format( d.value ) ); } );
+
+ cell.append( 'rect' )
+ .attr( 'width', function( d ) { return d.dx; } )
+ .attr( 'height', function( d ) { return d.dy; } )
+ .style( 'fill', function( d ) { return d.label ? color( d.label ) : color( d.label ); } );
+
+ cell.append( 'text' )
+ .attr( 'x', function( d ) { return d.dx / 2; } )
+ .attr( 'y', function( d ) { return d.dy / 2; } )
+ .attr( 'dy', '.35em' )
+ .attr( 'text-anchor', 'middle' )
+ .text( function( d ) { return d.children ? null : datalabels === 'value' ? d.value : d.label ; } );
+ } );
+ }
+ };
+
+ /**
+ * Implementation and representation of the d3 treemap instance
+ * @since 1.8
+ * @type Object
+ */
+ var srfD3 = new srf.formats.d3();
+ var util = new srf.util();
+
+ $(document).ready(function() {
+ $( '.srf-d3-chart-treemap' ).each(function() {
+ srfD3.treemap( $( this ) );
+ } );
+ } );
+} )( jQuery, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.css b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.css
new file mode 100644
index 00000000..dd9c7dd6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.css
@@ -0,0 +1,31 @@
+/**
+ * CSS for SRF D3 module
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @since: 1.8
+ *
+ * @release: 0.1
+ */
+.srf-d3-chart-title {
+ text-align:center;
+ font-weight: bold;
+ color:grey;
+ margin-left:10px;
+ margin-bottom:5px;
+ display:block;
+ position:relative;
+ font-size:110%;
+}
+
+.srf-d3-chart-text {
+ color:grey;
+ display:block;
+ position:relative;
+ font-size:90%;
+}
+
+.d3-chart-common {
+ margin: 10px 0px 10px 10px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.js b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.js
new file mode 100644
index 00000000..4f1dd509
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/d3/resources/ext.srf.d3.common.js
@@ -0,0 +1,60 @@
+/**
+ * JavaSript for SRF color schemes
+ *
+ * Schemes marked with cc corresponds to numbers from the ColorCombo website
+ *
+ * Includes color specifications and designs developed by Cynthia Brewer
+ * See also http://colorbrewer.org/ and its license
+ *
+ * @release: 0.2
+ */
+(function( $ ) {
+
+ $(document).ready(function() {
+
+ $( "[class^=srf-d3]" ).each(function() {
+
+ colorscheme = {
+ 0: [ '#1f77b4', '#aec7e8', '#ff7f0e', '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896', '#9467bd', '#c5b0d5', '#8c564b', '#c49c94', '#e377c2', '#f7b6d2', '#7f7f7f', '#c7c7c7', '#bcbd22', '#dbdb8d', '#17becf', '#9edae5' ] ,
+ cc124:{9: [ '#E8D0A9', '#B7AFA3', '#C1DAD6', '#F5FAFA', '#ACD1E9', '#6D929B' ] },
+ cc128:{9: [ '#7D9C9F', '#BDD8DA', '#DFEFF0', '#AD235E', '#ECECEC', '#B1B1B1' ] },
+ cc129:{9: [ '#6194BC', '#A5D1F3', '#D0EAFF', '#E4001B', '#ECECEC', '#606060' ] },
+ cc173:{9: [ '#206BA4', '#BBD9EE', '#EBF4FA', '#C0C0C0', '#E7E4D3', '#F1EFE2' ] },
+ cc210:{9: [ '#660F57', '#663366', '#003366', '#E7EBF0', '#B1BDCD', '#5B7290' ] },
+ cc267:{9: [ '#757116', '#AEBC21', '#D9DB56', '#00477F', '#4C88BE', '#8DC3E9' ] },
+ cc294:{9: [ '#B7C68B', '#F4F0CB', '#DED29E', '#B3A580', '#685642' ] },
+ cc252:{9: [ '#9C9284', '#CCCC99', '#E6E6CC', '#6699CC', '#FF9900' ] },
+ cc303:{9: [ '#7A3E48', '#EECD86', '#E18942', '#B95835', '#3D3242' ] },
+ cc327:{9: [ '#9D2E2C', '#F9EA99', '#7DB6D5', '#E7A555', '#4A4747' ] },
+ ylgn:{3:["rgb(247,252,185)","rgb(173,221,142)","rgb(49,163,84)"],4:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(35,132,67)"],5:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],6:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],7:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],8:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],9:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,104,55)","rgb(0,69,41)"]},
+ ylgnbu:{3:["rgb(237,248,177)","rgb(127,205,187)","rgb(44,127,184)"],4:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(34,94,168)"],5:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],6:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],7:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],8:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],9:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(37,52,148)","rgb(8,29,88)"]},
+ gnbu:{3:["rgb(224,243,219)","rgb(168,221,181)","rgb(67,162,202)"],4:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(43,140,190)"],5:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],6:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],7:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],8:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],9:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,104,172)","rgb(8,64,129)"]},
+ bugn:{3:["rgb(229,245,249)","rgb(153,216,201)","rgb(44,162,95)"],4:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(35,139,69)"],5:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],6:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],7:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],8:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],9:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},
+ pubugn:{3:["rgb(236,226,240)","rgb(166,189,219)","rgb(28,144,153)"],4:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(2,129,138)"],5:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],6:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],7:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],8:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],9:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,108,89)","rgb(1,70,54)"]},
+ pubu:{3:["rgb(236,231,242)","rgb(166,189,219)","rgb(43,140,190)"],4:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(5,112,176)"],5:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],6:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],7:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],8:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],9:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(4,90,141)","rgb(2,56,88)"]},
+ bupu:{3:["rgb(224,236,244)","rgb(158,188,218)","rgb(136,86,167)"],4:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,65,157)"],5:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],6:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],7:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],8:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],9:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(129,15,124)","rgb(77,0,75)"]},
+ rdpu:{3:["rgb(253,224,221)","rgb(250,159,181)","rgb(197,27,138)"],4:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(174,1,126)"],5:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],6:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],7:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],8:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],9:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)","rgb(73,0,106)"]},
+ purd:{3:["rgb(231,225,239)","rgb(201,148,199)","rgb(221,28,119)"],4:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(206,18,86)"],5:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],6:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],7:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],8:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],9:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(152,0,67)","rgb(103,0,31)"]},
+ orrd:{3:["rgb(254,232,200)","rgb(253,187,132)","rgb(227,74,51)"],4:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(215,48,31)"],5:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],6:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],7:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],8:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],9:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(179,0,0)","rgb(127,0,0)"]},
+ ylorrd:{3:["rgb(255,237,160)","rgb(254,178,76)","rgb(240,59,32)"],4:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(227,26,28)"],5:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],6:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],7:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],8:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],9:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(189,0,38)","rgb(128,0,38)"]},
+ ylorbr:{3:["rgb(255,247,188)","rgb(254,196,79)","rgb(217,95,14)"],4:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(204,76,2)"],5:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],6:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],7:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],8:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],9:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(153,52,4)","rgb(102,37,6)"]},
+ purples:{3:["rgb(239,237,245)","rgb(188,189,220)","rgb(117,107,177)"],4:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(106,81,163)"],5:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],6:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],7:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],8:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],9:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(84,39,143)","rgb(63,0,125)"]},
+ blues:{3:["rgb(222,235,247)","rgb(158,202,225)","rgb(49,130,189)"],4:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(33,113,181)"],5:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],6:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],7:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],8:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],9:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,81,156)","rgb(8,48,107)"]},
+ greens:{3:["rgb(229,245,224)","rgb(161,217,155)","rgb(49,163,84)"],4:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(35,139,69)"],5:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],6:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],7:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],8:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],9:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},
+ oranges:{3:["rgb(254,230,206)","rgb(253,174,107)","rgb(230,85,13)"],4:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(217,71,1)"],5:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],6:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],7:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],8:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],9:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(166,54,3)","rgb(127,39,4)"]},
+ reds:{3:["rgb(254,224,210)","rgb(252,146,114)","rgb(222,45,38)"],4:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(203,24,29)"],5:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],6:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],7:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],8:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],9:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(165,15,21)","rgb(103,0,13)"]},
+ greys:{3:["rgb(240,240,240)","rgb(189,189,189)","rgb(99,99,99)"],4:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(82,82,82)"],5:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],6:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],7:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],8:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],9:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)","rgb(0,0,0)"]},
+ puor:{3:["rgb(241,163,64)","rgb(247,247,247)","rgb(153,142,195)"],4:["rgb(230,97,1)","rgb(253,184,99)","rgb(178,171,210)","rgb(94,60,153)"],5:["rgb(230,97,1)","rgb(253,184,99)","rgb(247,247,247)","rgb(178,171,210)","rgb(94,60,153)"],6:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],7:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],8:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],9:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],10:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"],11:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"]},
+ brbg:{3:["rgb(216,179,101)","rgb(245,245,245)","rgb(90,180,172)"],4:["rgb(166,97,26)","rgb(223,194,125)","rgb(128,205,193)","rgb(1,133,113)"],5:["rgb(166,97,26)","rgb(223,194,125)","rgb(245,245,245)","rgb(128,205,193)","rgb(1,133,113)"],6:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],7:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],8:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],9:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],10:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"],11:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"]},
+ prgn:{3:["rgb(175,141,195)","rgb(247,247,247)","rgb(127,191,123)"],4:["rgb(123,50,148)","rgb(194,165,207)","rgb(166,219,160)","rgb(0,136,55)"],5:["rgb(123,50,148)","rgb(194,165,207)","rgb(247,247,247)","rgb(166,219,160)","rgb(0,136,55)"],6:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],7:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],8:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],9:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],10:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"],11:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"]},
+ piyg:{3:["rgb(233,163,201)","rgb(247,247,247)","rgb(161,215,106)"],4:["rgb(208,28,139)","rgb(241,182,218)","rgb(184,225,134)","rgb(77,172,38)"],5:["rgb(208,28,139)","rgb(241,182,218)","rgb(247,247,247)","rgb(184,225,134)","rgb(77,172,38)"],6:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],7:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],8:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],9:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],10:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"],11:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"]},
+ rdbu:{3:["rgb(239,138,98)","rgb(247,247,247)","rgb(103,169,207)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(146,197,222)","rgb(5,113,176)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(247,247,247)","rgb(146,197,222)","rgb(5,113,176)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"]},
+ rdgy:{3:["rgb(239,138,98)","rgb(255,255,255)","rgb(153,153,153)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(186,186,186)","rgb(64,64,64)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(255,255,255)","rgb(186,186,186)","rgb(64,64,64)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"]},
+ rdylbu:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,191,219)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,217,233)","rgb(44,123,182)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,217,233)","rgb(44,123,182)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"]},
+ spectral:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(153,213,148)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,221,164)","rgb(43,131,186)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,221,164)","rgb(43,131,186)"],6:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],7:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],8:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],9:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],10:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"],11:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"]},
+ rdylgn:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,207,96)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(166,217,106)","rgb(26,150,65)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(166,217,106)","rgb(26,150,65)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"]}
+ };
+
+ } ); // end of initilized $this object
+ } ); // end $(document).ready
+} )( window.jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/datatables/DataTables.php b/www/wiki/extensions/SemanticResultFormats/formats/datatables/DataTables.php
new file mode 100644
index 00000000..1d0e530e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/datatables/DataTables.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace SRF;
+
+use Html;
+use SMW\ResultPrinter;
+use SMWQueryResult as QueryResult;
+
+/**
+ * DataTables and SMWAPI.
+ *
+ * @since 1.9
+ * @licence GNU GPL v2 or later
+ *
+ * @author mwjames
+ */
+class DataTables extends ResultPrinter {
+
+ /**
+ * @see ResultPrinter::getName
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return $this->msg( 'srf-printername-datatables' )->text();
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['theme'] = [
+ 'message' => 'srf-paramdesc-theme',
+ 'default' => 'bootstrap',
+ 'values' => [ 'bootstrap' ] // feel free to add more designs
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ *
+ * {@inheritDoc}
+ */
+ protected function getResultText( QueryResult $res, $outputmode ) {
+
+ $resourceFormatter = new ResourceFormatter();
+ $data = $resourceFormatter->getData( $res, $outputmode, $this->params );
+
+ $this->isHTML = true;
+ $id = $resourceFormatter->session();
+
+ // Add options
+ $data['version'] = '0.2.5';
+
+ // Encode data object
+ $resourceFormatter->encode( $id, $data );
+
+ // Init RL module
+ $resourceFormatter->registerResources( [ 'ext.srf.datatables' ] );
+
+ // Element includes info, spinner, and container placeholder
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-datatables' . ( $this->params['class'] ? ' ' . $this->params['class'] : '' ),
+ 'data-theme' => $this->params['theme'],
+ ],
+ Html::element(
+ 'div',
+ [
+ 'class' => 'top'
+ ],
+ ''
+ ) . $resourceFormatter->placeholder() . Html::element(
+ 'div',
+ [
+ 'id' => $id,
+ 'class' => 'container',
+ 'style' => 'display:none;'
+ ]
+ )
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.css b/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.css
new file mode 100644
index 00000000..8ae42718
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.css
@@ -0,0 +1,292 @@
+/**
+ * CSS for the SRF dataTables module
+ *
+ * @since 1.9
+ * @version 0.2.5
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+/* Type dependant formatting */
+.srf-datatables .smwtype_num {
+ text-align: right;
+}
+
+/* Basis setting */
+.srf-datatables .button-space {
+ margin-left: 10px;
+ float: right;
+ width: 5px;
+ height: 5px;
+}
+
+.srf-datatables .button {
+ float: right;
+ width: 5px;
+ height: 14px;
+}
+
+.srf-datatables .srf-panel {
+ overflow: hidden;
+ float: left;
+ margin-right: 10px;
+ display:none;
+ min-width: 17em;
+ margin-top: 0px;
+}
+
+.srf-datatables .srf-panel fieldset {
+ border: 1px solid #2F6FAB;
+ margin: 0.1em 0.1em 0.1em 0.1em;
+ padding: 0 0.5em 0.5em 0.5em;
+ line-height: 1.5em;
+ border: 1px solid gainsboro;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.srf-datatables .srf-panel fieldset label {
+ vertical-align: top;
+}
+
+.srf-datatables legend {
+ display: block;
+ font-size: 110%;
+ line-height: 16px;
+ color: #333;
+}
+
+.srf-datatables .srf-panel .query-link {
+ margin-left: 5px;
+ margin-right: 5px;
+}
+
+.srf-datatables .srf-panel .export {
+ padding: 0.35em 0.3em 0.35em 0.3em;
+ border: 1px solid gainsboro;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.srf-datatables .parameters .label {
+ overflow: hidden;
+ float:left;
+ margin-right: 5px;
+}
+
+.srf-datatables .parameters .limit-parameter .value {
+ overflow: hidden;
+ float: right;
+ margin-right: 3px;
+}
+
+.srf-datatables .parameters .limit-parameter .count {
+ float: left;
+}
+
+.srf-datatables .parameter-section {
+ font-size: 110%;
+ margin-bottom: 5px;
+}
+
+.srf-datatables .limit-parameter .slider {
+ margin-top:5px;
+ margin-right:3px;
+}
+
+.srf-datatables .columnfilter input[type="checkbox"], input[type="radio"] {
+ width: auto;
+ height: auto;
+ padding: 0;
+ margin: 3px 5px 0 0;
+ line-height: normal;
+ border: none;
+}
+
+.srf-datatables .columnfilter ul {
+ list-style-type: none;
+ list-style-image: none;
+ margin: .3em 0 0 0.6em;
+ width: 100%; /* room for 3 columns */
+ overflow: hidden;
+}
+
+.srf-datatables .columnfilter ul li {
+ float: none;
+ width: 100%;
+ margin-right: 15px;
+ font-size: 90%;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+.srf-datatables .srf-panel .head {
+ height: 16px;
+ font-size: 20px;
+ color: #333;
+ font-weight: bold;
+ text-rendering: optimizelegibility;
+ border-bottom: 0px solid gainsboro;
+ padding: 2px 8px 8px 12px;
+ -moz-border-radius: 0px;
+ -webkit-border-radius: 0px;
+ border-radius: 0px;
+}
+
+.srf-datatables .srf-panel .information p {
+ padding: 1px 3px 1px 3px;
+ word-wrap: break-word;
+ text-align: justify;
+ width: 200px;
+}
+
+.srf-datatables .srf-panel .content-source.cache {
+ color: rgba(141, 192, 219, 0.85);
+}
+
+.srf-datatables .conditions textarea {
+ word-wrap: break-word;
+ height: 75px;
+}
+
+/* Bootstrap aligned query panel design */
+
+.srf-datatables .srf-panel.bootstrap{
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-style: solid;
+ border-right-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-top-color: #DDD;
+ border-right-color: #DDD;
+ border-bottom-color: #DDD;
+ border-left-color: #DDD;
+ border-collapse: separate;
+ border-top-left-radius: 4px 4px;
+ border-top-right-radius: 4px 4px;
+ border-bottom-right-radius: 4px 4px;
+ border-bottom-left-radius: 4px 4px;
+ margin-top: 42px;
+ display: block;
+}
+
+.srf-datatables .srf-panel.bootstrap fieldset {
+ border: 0px solid gainsboro;
+ margin-top: 5px;
+ padding: 0 0.5em 0.0em 0.5em;
+}
+
+.srf-datatables .srf-panel.bootstrap legend {
+ padding: .5em 0 0.5em 0.3em;
+ display: block;
+ font-size: 120%;
+ line-height: 16px;
+ color: #333;
+ background-color: rgba(141, 192, 219, 0.25);
+ width: 100%;
+ font-weight: bold;
+ margin-left: -3px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-style: solid;
+ border-right-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-top-color: #DDD;
+ border-right-color: #DDD;
+ border-bottom-color: #DDD;
+ border-left-color: #DDD;
+ border-collapse: separate;
+ border-top-left-radius: 4px 4px;
+ border-top-right-radius: 4px 4px;
+ border-bottom-right-radius: 4px 4px;
+ border-bottom-left-radius: 4px 4px;
+
+}
+
+.srf-datatables .srf-panel.bootstrap .conditions textarea {
+ margin-top: 10px;
+}
+
+.srf-datatables .srf-panel.bootstrap .limit-parameter {
+ padding: 8px 0 5px 5px
+}
+
+.srf-datatables .srf-panel.bootstrap .columnfilter ul {
+ margin: .3em 0 0 0.3em;
+}
+
+.srf-datatables .srf-panel .columnfilter input {
+ margin-left: 0;
+ margin-top: 0.6em;
+ margin-bottom: 0.3em;
+ width: 195px;
+}
+
+.srf-datatables .srf-panel .columnfilter select {
+ margin-top: 0.2em;
+ width: 205px;
+}
+
+.srf-datatables .srf-panel .columnfilter .ui-multiselect {
+ height: 29px;
+ padding: 4px;
+ font-size: 13px;
+ line-height: 18px;
+ color: gray;
+ border: 1px solid #CCC;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ padding: 0.2;
+ margin-bottom: 0.5em;
+}
+
+.srf-datatables .srf-panel .conditions textarea {
+ width: 195px;
+}
+
+/* Yet another query panel design */
+
+.srf-datatables .srf-panel.bootstrap.flags {
+ border-top-width: 0px;
+ border-right-width: 1px;
+ border-bottom-width: 0px;
+ border-left-width: 0px;
+ border-top-style: none;
+ border-right-style: solid;
+ border-bottom-style: none;
+ border-left-style: none;
+ border-top-color: #DDD;
+ border-right-color: #DDD;
+ border-bottom-color: #DDD;
+ border-left-color: #DDD;
+ border-collapse: separate;
+ border-top-left-radius: 0px 0px;
+ border-top-right-radius: 4px 4px;
+ border-bottom-right-radius: 0px 0px;
+ border-bottom-left-radius: 0px 0px;
+ margin-top: 0;
+ display: block;
+}
+
+.srf-datatables .srf-panel.bootstrap.flags fieldset {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+
+.srf-datatables .srf-panel.bootstrap.flags legend{
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ font-weight: normal;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.js b/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.js
new file mode 100644
index 00000000..8b3773d0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/datatables/resources/ext.srf.formats.datatables.js
@@ -0,0 +1,768 @@
+/**
+ * SRF DataTables JavaScript Printer using the SMWAPI
+ *
+ * @see http://datatables.net/
+ *
+ * @since 1.9
+ * @version 0.2.5
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /* Private methods and objects */
+
+ /**
+ * Helper objects
+ *
+ * @since 1.9
+ *
+ * @ignore
+ * @private
+ * @static
+ */
+ var html = mw.html,
+ profile = $.client.profile(),
+ smwApi = new smw.api(),
+ util = new srf.util();
+
+ /**
+ * Container for all non-public objects and methods
+ *
+ * @private
+ * @member srf.formats.datatables
+ */
+ var _datatables = {
+
+ /**
+ * Returns ID
+ *
+ * @private
+ * @return {string}
+ */
+ getID: function( container ) {
+ return container.attr( 'id' );
+ },
+
+ /**
+ * Returns container data
+ *
+ * @private
+ * @return {object}
+ */
+ getData: function( container ) {
+ return mw.config.get( this.getID( container ) );
+ },
+
+ /**
+ * Contains methods linked to the parsing of objects
+ *
+ * @private
+ * @type {object}
+ * @return void
+ */
+ parse: {
+
+ /**
+ * Returns a html element from the MWAPI imageinfo prop
+ *
+ * @private
+ * @param {object}
+ * @return {html|null}
+ */
+ thumbnail: function( info ){
+ if( $.type( info.imageinfo ) === 'array' ){
+ var imageInfo = info ? info.imageinfo[0] : null;
+ if ( $.inArray( 'thumburl', imageInfo ) ) {
+ return html.element( 'a', {
+ 'href': imageInfo.descriptionurl
+ }, new html.Raw( html.element( 'img', {
+ 'src': imageInfo.thumburl
+ } ) )
+ );
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Returns a parsed result object that was received
+ * using the SMWAPI
+ *
+ * @private
+ * @param {object}
+ * @param {object}
+ * @return {array}
+ */
+ results: function( context, data ) {
+ var self = this;
+
+ // Returns a text or a href element
+ // Try to resolve image/thumbnail information by fetching its
+ // imageInfo from the back-end
+ function createLink( wikiPage, linker, options ){
+ if ( wikiPage.getNamespaceId() === 6 && linker ) {
+ var imageInfo = getImageInfo( wikiPage.getName(), options );
+ if ( imageInfo !== null && imageInfo !== undefined ) {
+ var imageLink = self.thumbnail( imageInfo );
+ return imageLink !== null ? imageLink : wikiPage.getHtml( linker );
+ }
+ }
+ return wikiPage.getHtml( linker );
+ }
+
+ // Returns a thumbnail image location and in case the info was
+ // cached the result is returned immediately otherwise an event
+ // is triggered to ensure that result parsing is responsive
+ // and without any delay
+ function getImageInfo( title, options ) {
+ var imageInfo = null;
+
+ util.image.imageInfo( {
+ 'cache': datatables.defaults.cacheImageInfo,
+ 'width': datatables.defaults.thumbSize,
+ 'title': title
+ }, function( isCached, info ) {
+ if ( isCached ){
+ imageInfo = info;
+ } else {
+ // This info wasn't in cache so we can't wait on the response
+ // and sent therefore a trigger event
+ context.trigger( 'srf.datatables.afterImageInfoFetch', {
+ column: options.column,
+ row: options.row,
+ info: info
+ } );
+ }
+ } );
+ return imageInfo;
+ }
+
+ // Transform results into a specific aaData format
+ function getResults( parameters, results, printreqs ){
+
+ var aaData = [],
+ i = 0;
+ $.each( results, function( subjectName, subject ) {
+ var rowData = {},
+ linker = parameters.link === 'all' || false,
+ columnIndex = 0,
+ rowIndex = i++;
+
+ // Subject
+ if ( parameters.mainlabel !== '-' ) {
+ var mainLabel = parameters.mainlabel !== '' ? parameters.mainlabel : '';
+ if ( subject instanceof smw.dataItem.wikiPage ){
+ rowData[mainLabel] = createLink( subject, linker || parameters.link === 'subject', {
+ column: columnIndex,
+ row: rowIndex
+ } );
+ }
+ }
+
+ // Property printouts
+ if ( $.inArray( 'printouts', subject ) ) {
+ // Find column (properties)
+ $.each( printreqs, function( index, propertyObj ) {
+ columnIndex++;
+ var collectedValueItem = '';
+ var property = propertyObj.label;
+ var values = subject.printouts[property];
+ if ( values == null ) {
+ rowData[property] = createLink( subject, linker, {
+ column: columnIndex,
+ row: rowIndex
+ } );
+ } else {
+ $.map ( values, function( DI, key ) {
+ // For multiple values within one row/column use a separator
+ collectedValueItem += collectedValueItem !== '' && key >= 0 ? '<br />' : '';
+
+ // dataItem
+ if ( DI instanceof smw.dataItem.time ){
+ collectedValueItem += DI.getMediaWikiDate();
+ } else if ( DI instanceof smw.dataItem.wikiPage ){
+ collectedValueItem += createLink( DI, linker, {
+ column: columnIndex,
+ row: rowIndex
+ } );
+ } else if ( DI instanceof smw.dataItem.uri ){
+ collectedValueItem += DI.getHtml( linker );
+ } else if ( DI instanceof smw.dataItem.text ){
+ collectedValueItem += DI.getText();
+ } else if ( DI instanceof smw.dataItem.number ){
+ collectedValueItem += DI.getNumber();
+ } else if ( DI instanceof smw.dataValue.quantity ){
+ collectedValueItem += DI.getUnit() !== '' ? DI.getValue() + ' ' + DI.getUnit() : DI.getValue();
+ } else if ( DI instanceof smw.dataItem.unknown ){
+ collectedValueItem += DI.getValue();
+ }
+
+ } );
+ // For empty values ensure to use "-" otherwise
+ // dataTables will show an error
+ rowData[property] = collectedValueItem !== '' ? collectedValueItem : '-';
+ }
+ } );
+ }
+
+ // Only care for entries that are not empty
+ if ( !$.isEmptyObject( rowData ) ) {
+ // Collect events
+ aaData.push( rowData );
+ } else {
+ // In case the array was empty reset the row counter
+ rowIndex--;
+ }
+ } );
+
+ return { 'aaData': aaData };
+ }
+ // Create column definitions (see aoColumnDefs)
+ // @see http://www.datatables.net/usage/columns
+ var aoColumnDefs = [];
+ $.map ( data.query.result.printrequests, function( property, index ) {
+ aoColumnDefs.push( {
+ 'mData': property.label,
+ 'sTitle': property.label,
+ 'sClass': 'smwtype' + property.typeid,
+ 'aTargets': [index]
+ } );
+ } );
+ data.aoColumnDefs = aoColumnDefs;
+ // Parse and return results
+ return getResults( data.query.ask.parameters, data.query.result.results, data.query.result.printrequests );
+ }
+ },
+
+ /**
+ * Export links
+ *
+ * Depending on the event that invokes a change, adopt the link query
+ *
+ * @private
+ * @return void
+ */
+ exportlinks: function( context, data ) {
+ var exportLinks = context.find( '#srf-panel-export > .center' ),
+ parameters = {},
+ printouts = [];
+
+ // Clone data into new object in order to keep it local
+ $.extend( true, parameters, data.query.ask.parameters );
+
+ // Only columns that are visible are supposed to be part of the export links
+ $.each( data.table.fnSettings().aoColumns, function( index, column ) {
+ if ( column.bVisible ){
+ printouts.push( data.query.ask.printouts[index] );
+ }
+ } ) ;
+
+ // Manage individual links
+ $.each( datatables.defaults.exportFormats, function( format, name ) {
+ var formatLink = exportLinks.find( '.' + format );
+
+ // Create element if it doesn't exists
+ if ( formatLink.length === 0 ) {
+ formatLink = exportLinks.append( html.element( 'span', { 'class': format } ) ).find( '.' + format );
+ }
+
+ // Set name and format
+ parameters.format = format;
+ parameters.searchlabel = name;
+
+ // Create link
+ var link = new smw.Query(
+ printouts,
+ parameters,
+ data.query.ask.conditions ).getLink();
+
+ // Remove previous link and append with an updated one
+ formatLink.find( 'a' ).remove();
+ formatLink.append( link );
+ } ) ;
+ },
+
+ /**
+ * Internationalization
+ * @see http://datatables.net/usage/i18n
+ *
+ * @private
+ * @return {object}
+ */
+ oLanguage: {
+ oAria: {
+ sSortAscending : mw.msg( 'srf-ui-datatables-label-oAria-sSortAscending' ),
+ sSortDescending: mw.msg( 'srf-ui-datatables-label-oAria-sSortDescending' )
+ },
+ oPaginate: {
+ sFirst: mw.msg( 'srf-ui-datatables-label-oPaginate-sFirst' ),
+ sLast : mw.msg( 'srf-ui-datatables-label-oPaginate-sLast' ),
+ sNext: mw.msg( 'srf-ui-datatables-label-oPaginate-sNext' ),
+ sPrevious: mw.msg( 'srf-ui-datatables-label-oPaginate-sPrevious' )
+ },
+ sEmptyTable: mw.msg( 'srf-ui-datatables-label-sEmptyTable' ),
+ sInfo: mw.msg( 'srf-ui-datatables-label-sInfo' ),
+ sInfoEmpty: mw.msg( 'srf-ui-datatables-label-sInfoEmpty' ),
+ sInfoFiltered: mw.msg( 'srf-ui-datatables-label-sInfoFiltered' ),
+ sInfoPostFix: mw.msg( 'srf-ui-datatables-label-sInfoPostFix' ),
+ sInfoThousands: mw.msg( 'srf-ui-datatables-label-sInfoThousands' ),
+ sLengthMenu: mw.msg( 'srf-ui-datatables-label-sLengthMenu' ),
+ sLoadingRecords: mw.msg( 'srf-ui-datatables-label-sLoadingRecords' ),
+ sProcessing: mw.msg( 'srf-ui-datatables-label-sProcessing' ),
+ sSearch: mw.msg( 'srf-ui-datatables-label-sSearch' ),
+ sZeroRecords: mw.msg( 'srf-ui-datatables-label-sZeroRecords' )
+ },
+
+ /**
+ * UI components
+ *
+ * @private
+ * @param {array} context
+ * @param {array} container
+ * @param {array} data
+ */
+ ui: function( context, container, data ){
+
+ // Setup the query panel
+ var queryPanel = context.find( '.top' );
+ queryPanel.panel( {
+ 'show': false
+ } );
+
+ // Add exportFormat portlet
+ queryPanel.panel( 'portlet', {
+ 'class' : 'export',
+ 'fieldset': false
+ } )
+ .append( html.element( 'div', { 'class': 'center' } ) );
+
+ // Init export links
+ _datatables.exportlinks( context, data );
+
+ // Map available columns
+ var columnList = [];
+ $.each( data.table.fnSettings().aoColumns, function( key, item ) {
+ if ( key !== '' ) {
+ columnList.push( item.mData !== '' ? item.mData : '#' );
+ }
+ } );
+
+ // Column filter
+ var columnFilter,
+ columnSearchFilter,
+ columnSearchInput;
+
+ // Add column portlet
+ columnFilter = queryPanel.panel( 'portlet', {
+ 'class' : 'columnfilter',
+ 'title' : mw.msg( 'srf-ui-datatables-label-filters' ),
+ 'fieldset': true
+ } ).find( 'fieldset' );
+
+ // Add column visibility select options list
+ columnFilter.optionslist()
+ .optionslist( 'selectlist', {
+ 'list' : columnList,
+ 'class': 'columnfilter',
+ 'multiple': true,
+ 'selectedAll': true,
+ 'null': false
+ } )
+ .multiselect( {
+ header: mw.msg( 'srf-ui-datatables-label-multiselect-column-header' ),
+ noneSelectedText: mw.msg( 'srf-ui-datatables-label-multiselect-column-noneselectedtext' ),
+ selectedText: '# ' + mw.msg( 'srf-ui-datatables-label-multiselect-column-selectedtext' ),
+ height: columnList.length > 5 ? undefined : 'auto',
+ minWidth: 'auto',
+ click: function( event, ui ) {
+ var bVis = data.table.fnSettings().aoColumns[ui.value].bVisible;
+ data.table.fnSetColumnVis( ui.value, !bVis );
+
+ // Update export links
+ _datatables.exportlinks( context, data );
+ }
+ } );
+
+ // Multiselect minWidth didn't work in FF therefore we fix it here
+ columnFilter.find( '.ui-multiselect' ).css( 'width', '205px' );
+
+ // Add column search filter
+ columnFilter.append( '<br>' )
+ .optionslist( 'selectlist', {
+ 'list' : columnList,
+ 'class': 'columnsearchfilter',
+ 'selectedAll': false,
+ 'null': true,
+ change: function( event, ui ) {
+ // Clear previous fields before storing a new filter set
+ data.table.fnFilter( '', columnSearchFilter );
+ columnSearchFilter = ui.value;
+ var disabled = columnSearchFilter ? '' : 'disabled';
+ columnFilter.find( '#columnsearchinput' ).prop( 'disabled', disabled ).val( '' );
+ }
+ } );
+
+ // Add column search input
+ columnFilter.append( '<br>' )
+ .append( html.element( 'input', {
+ 'id': 'columnsearchinput',
+ 'placeholder': mw.msg( 'srf-ui-datatables-label-placeholder-column-search' ),
+ 'disabled': 'disabled'
+ }, '' ) + '<br>' )
+ .on( 'input propertychange', '#columnsearchinput', function( event ) {
+ columnSearchInput = $( this ).val();
+ if( columnSearchInput !== '' && columnSearchFilter !== '' ){
+ // Apply search to the selected column
+ data.table.fnFilter( columnSearchInput, columnSearchFilter );
+ } else {
+ // Reset the search term to null
+ data.table.fnFilter( '', columnSearchFilter );
+ }
+ } );
+
+ // Query conditions portlet
+ var conditionsPortlet = queryPanel.panel( 'portlet', {
+ 'class' : 'conditions',
+ 'title' : mw.msg( 'srf-ui-datatables-label-conditions' ),
+ 'fieldset': true
+ } );
+
+ // Only allow logged-in users to alter query conditions via the
+ // text input
+ $( html.element( 'textarea', {
+ 'id': 'condition',
+ 'disabled': !datatables.defaults.userIsKnown
+ }, data.query.ask.conditions
+ ) )
+ .insertAfter( conditionsPortlet.find( 'fieldset > legend' ) )
+ .on( 'input propertychange', function( event ) {
+ var conditions = $( this ).val();
+ // Store the input only where it contains content
+ data.query.ask.conditions = conditions !== '' ? conditions : data.query.ask.conditions;
+ } );
+
+ // Parameters portlet
+ var parametersPortlet = queryPanel.panel( 'portlet', {
+ 'class' : 'parameters',
+ 'title' : mw.msg( 'srf-ui-datatables-label-parameters' ),
+ 'fieldset': true
+ } ).find( 'fieldset' ).parameters();
+
+ // Limit parameter
+ parametersPortlet.parameters( 'limit', {
+ limit : data.query.ask.parameters.limit,
+ count : data.query.result.meta.count,
+ max : datatables.defaults.inlineLimit,
+ step : datatables.defaults.inlineLimit / ( datatables.defaults.inlineLimit > 1000 ? 100 : 10 ),
+ change: function( event, ui ) {
+ data.query.ask.parameters.limit = ui.value ;
+ // As soon as the limit changes, trigger an update
+ datatables.update( context, data );
+ event.preventDefault();
+ }
+ } );
+
+ // Disclaimer and content source text
+ queryPanel.panel( 'portlet', {
+ 'class' : 'information',
+ 'title' : mw.msg( 'srf-ui-datatables-label-information' ),
+ 'fieldset': true
+ } )
+ .find( 'fieldset > legend' )
+ .after(
+ html.element( 'p', { 'class': 'disclaimer' }, mw.msg( 'srf-ui-datatables-panel-disclaimer' ) )
+ )
+ .after(
+ html.element( 'p', { 'class': 'content-source' }, mw.msg( 'srf-ui-datatables-label-content-server' ) )
+ );
+
+ // Refresh button
+ $( html.element( 'span', { 'class': 'button' } ) )
+ .insertBefore( container.find( '.span-select' ) )
+ .button( {
+ icons: { primary: 'ui-icon-refresh' },
+ text: false
+ } )
+ .removeClass( 'ui-corner-all' )
+ .addClass( 'ui-corner-right' )
+ .on( 'click', function( event ){
+ datatables.update( context, data );
+ } );
+
+ // Panel switch button
+ $( html.element( 'span', {'class': 'button' } ) )
+ .insertBefore( container.find( '.span-select' ) )
+ .button( {
+ icons: { primary: 'ui-icon-bookmark' },
+ text: false
+ } )
+ .removeClass( 'ui-corner-all' )
+ .addClass( 'ui-corner-left' )
+ .on( 'click', function( event ){
+ queryPanel.panel( 'toggle' );
+ } );
+
+ // Insert space between search field and button
+ $( html.element( 'span', {'class': 'button-space' } ) )
+ .insertBefore( container.find( '.span-select' ) );
+ }
+ };
+
+ /**
+ * Inheritance class for the srf.formats constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @abstract
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Class that contains the DataTables JavaScript result printer
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ * @extends srf.formats
+ */
+ srf.formats.datatables = function() {};
+
+ /* Public methods */
+
+ srf.formats.datatables.prototype = {
+
+ /**
+ * Default settings
+ *
+ * @note MW 1.21 vs MW 1.20
+ * Apparently mw.config.get( 'srf' )/mw.config.get( 'smw' ) does only work
+ * in MW 1.21 therefore instead of being customizable those settings are
+ * going to be fixed
+ *
+ * TTL (if enabled) cache for resultObject is set to be 15 min by default
+ * TTL (if enabled) cache for imageInfo is set to be 24 h
+ *
+ * @since 1.9
+ *
+ * @property
+ */
+ defaults: {
+ autoUpdate: mw.user.options.get( 'srf-prefs-datatables-options-update-default' ),
+ userIsKnown: mw.config.get( 'wgUserName' ),
+ cacheImageInfo: mw.user.options.get( 'srf-prefs-datatables-options-cache-default' ) ? 86400000 : false,
+ cacheApi: mw.user.options.get( 'srf-prefs-datatables-options-cache-default' ),
+ // thumbSize: mw.config.get( 'srf' ).options.thumbsize[mw.user.options.get( 'thumbsize' )],
+ // inlineLimit: mw.config.get( 'smw' ).options['QMaxInlineLimit']
+ thumbSize: 180,
+ inlineLimit: 750,
+ exportFormats: { 'csv': 'CSV', 'rss': 'RSS', 'json': 'JSON', 'rdf': 'RDF' }
+ },
+
+ /**
+ * Initializes the DataTables instance
+ *
+ * @since 1.9
+ *
+ * @param {array} context
+ * @param {array} container
+ * @param {array} data
+ */
+ init: function( context, container, data ) {
+ var self = this;
+
+ // Hide loading spinner
+ context.find( '.srf-loading-dots' ).hide();
+
+ // Show container
+ container.css( { 'display' : 'block' , overflow: 'hidden' } );
+
+ // Setup a raw table
+ container.html( html.element( 'table', {
+ 'class': 'bordered-table zebra-striped',
+ 'cellpadding': '0',
+ 'cellspacing': '0',
+ 'border': '0'
+ }
+ ) );
+
+ // Parse JS array and merge with the data array
+ $.extend( data, _datatables.parse.results( context, data ) );
+
+ //console.log( 'Data', data, 'Objects', _datatables );
+
+ if ( data.aaData.length > 0 ){
+ //@note Do something here
+ }
+
+ // Init dataTables
+ var sDom = context.data( 'theme' ) === 'bootstrap'? "<'row'<'span-select'l><'span-search'f>r>t<'row'<'span-list'i><'span-page'p>>" : 'lfrtip';
+ data.table = container.find( 'table' ).dataTable( {
+ 'sDom': sDom,
+ 'sPaginationType': context.data( 'theme' ) === 'bootstrap' ? 'bootstrap' : 'full_numbers',
+ 'bAutoWidth': false,
+ 'oLanguage': _datatables.oLanguage,
+ 'aaData': data.aaData,
+ 'aoColumnDefs': data.aoColumnDefs
+ } );
+ // Bind the imageInfo trigger and update the appropriate table cell
+ context.on( 'srf.datatables.afterImageInfoFetch', function( event, handler ) {
+ // If the image/thumbnail info array was empty don't bother with an update
+ if( handler.info.imageinfo ){
+ data.table.fnUpdate( _datatables.parse.thumbnail( handler.info ), handler.row, handler.column );
+ }
+ } );
+
+ // Add UI components
+ _datatables.ui( context, container, data );
+ },
+
+ /**
+ * Handles updates via Ajax
+ *
+ * @since 1.9
+ *
+ * @param {array} context
+ * @param {array} data
+ */
+ update: function( context, data ){
+ var self = this;
+
+ // Lock the current context to avoid queuing issues during the update
+ // process (e.g another button is pressed )
+ context.block( {
+ message: html.element( 'span', { 'class': 'mw-ajax-loader' }, '' ),
+ css: {
+ border: '2px solid #DDD',
+ height: '20px', 'padding-top' : '35px',
+ opacity: 0.8, '-webkit-border-radius': '5px',
+ '-moz-border-radius': '5px',
+ 'border-radius' : '5px'
+ },
+ overlayCSS: {
+ backgroundColor: '#fff',
+ opacity: 0.6,
+ cursor: 'wait'
+ }
+ } );
+
+ // Collect query information
+ var conditions = data.query.ask.conditions,
+ printouts = data.query.ask.printouts,
+ parameters = {
+ 'limit' : data.query.ask.parameters.limit,
+ 'offset': data.query.ask.parameters.offset
+ };
+
+ // Stringify the query
+ var queryString = new smw.Query( printouts, parameters, conditions ).toString();
+
+ // Fetch data via Ajax/SMWAPI
+ smwApi.fetch( queryString, datatables.defaults.cacheApi )
+ .done( function ( result ) {
+
+ // Copy result query data and run a result parse
+ $.extend( data.query.result, result.query );
+ $.extend( data, _datatables.parse.results( context, data ) );
+
+ // Refresh datatables
+ data.table.fnClearTable();
+ data.table.fnAddData( data.aaData );
+ data.table.fnDraw();
+
+ // Update information from where the content was derived
+ context.find( '#srf-panel-information .content-source' )
+ .toggleClass( 'cache', result.isCached )
+ .text( result.isCached ? mw.msg( 'srf-ui-datatables-label-content-cache' ) : mw.msg( 'srf-ui-datatables-label-content-server' ) );
+
+ // Update conditions text-field content
+ context.find( '#condition' ).val( data.query.ask.conditions );
+
+ // Update limit parameter (widget)
+ context.find( '.parameters > fieldset' ).parameters(
+ 'option', 'limit', {
+ 'limit': data.query.ask.parameters.limit,
+ 'count': data.query.result.meta.count
+ } ) ;
+
+ // Update export links
+ _datatables.exportlinks( context, data );
+
+ context.unblock( {
+ onUnblock: function(){ util.notification.create ( {
+ content: mw.msg( 'srf-ui-datatables-label-update-success' )
+ } );
+ }
+ } );
+ } )
+ .fail( function ( error ) {
+ context.unblock( {
+ onUnblock: function(){ util.notification.create ( {
+ content: mw.msg( 'srf-ui-datatables-label-update-error' ),
+ color: '#BF381A'
+ } );
+ }
+ } );
+ } );
+ },
+
+ /**
+ * Test interface which enables some internal methods / objects
+ * to be tested via qunit
+ *
+ * @since 1.9
+ *
+ * @ignore
+ */
+ test: {
+ _parse: _datatables.parse,
+ }
+ };
+
+ /**
+ * dataTables implementation
+ *
+ * @ignore
+ */
+ var datatables = new srf.formats.datatables();
+
+ $( document ).ready( function() {
+ $( '.srf-datatables' ).each( function() {
+
+ var context = $( this ),
+ container = context.find( '.container' ),
+ data = smwApi.parse( _datatables.getData( container ) );
+
+ // Add bottom element to avoid display clutter on succeeding elements
+ $( html.element( 'div', {
+ 'class': 'bottom',
+ 'style': 'clear:both'
+ }
+ ) ).appendTo( context );
+
+ // Adopt directionality which ensures that all elements within its context
+ // are appropriately displayed
+ context.prop( 'dir', $( 'html' ).attr( 'dir' ) );
+ context.prop( 'lang', $( 'html' ).attr( 'lang' ) );
+
+ // Ensures that CSS/JS dependencies are "really" loaded before
+ // dataTables gets initialized
+ mw.loader.using( 'ext.srf.datatables.' + context.data( 'theme' ), function(){
+ datatables.init( context, container, data );
+
+ // Do an auto update if enabled via user-preferences
+ if ( datatables.defaults.autoUpdate ) {
+ datatables.update( context, data );
+ }
+ } );
+
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/SRF_Dygraphs.php b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/SRF_Dygraphs.php
new file mode 100644
index 00000000..02ca3f1b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/SRF_Dygraphs.php
@@ -0,0 +1,330 @@
+<?php
+
+/**
+ * A query printer that uses the dygraphs JavaScript library
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Flot_timeseries_chart
+ * @licence GNU GPL v2 or later
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ */
+class SRFDygraphs extends SMWResultPrinter {
+
+ /**
+ * @see SMWResultPrinter::getName
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-dygraphs' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputMode ) {
+
+ // Output mode is fixed
+ $outputMode = SMW_OUTPUT_HTML;
+
+ // Data processing
+ $data = $this->getResultData( $result, $outputMode );
+
+ // Post-data processing check
+ if ( $data === [] ) {
+ return $result->addErrors( [ wfMessage( 'srf-warn-empy-chart' )->inContentLanguage()->text() ] );
+ } else {
+ $options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) );
+ return $this->getFormatOutput( $data, $options );
+ }
+ }
+
+ /**
+ * Returns an array with numerical data
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultData( SMWQueryResult $result, $outputMode ) {
+ $aggregatedValues = [];
+
+ while ( $rows = $result->getNext() ) { // Objects (pages)
+ $annotation = [];
+ $dataSource = false;
+
+ /**
+ * @var SMWResultArray $field
+ * @var SMWDataValue $dataValue
+ */
+ foreach ( $rows as $field ) {
+
+ // Use the subject marker to identify a possible data file
+ $subject = $field->getResultSubject();
+ if ( $this->params['datasource'] === 'file' && $subject->getTitle()->getNamespace(
+ ) === NS_FILE && !$dataSource ) {
+ $aggregatedValues['subject'] = $this->makePageFromTitle( $subject->getTitle() )->getLongHTMLText(
+ $this->getLinker( $field->getResultSubject() )
+ );
+ $aggregatedValues['url'] = wfFindFile( $subject->getTitle() )->getUrl();
+ $dataSource = true;
+ }
+
+ // Proceed only where a label is known otherwise items are of no use
+ // for being a potential object identifier
+ if ( $field->getPrintRequest()->getLabel() !== '' ) {
+ $propertyLabel = $field->getPrintRequest()->getLabel();
+ } else {
+ continue;
+ }
+
+ while ( ( $dataValue = $field->getNextDataValue() ) !== false ) { // Data values
+
+ // Jump the column (indicated by continue) because we don't want the data source being part of the annotation array
+ $dataItem = $dataValue->getDataItem();
+
+ if ( $dataItem->getDIType() === SMWDataItem::TYPE_WIKIPAGE ) {
+ $title = $dataItem->getTitle();
+ }
+
+ if ( $dataItem->getDIType() == SMWDataItem::TYPE_WIKIPAGE && $this->params['datasource'] === 'raw' && !$dataSource ) {
+ // Support data source = raw which pulls the url from a wikipage in raw format
+ $aggregatedValues['subject'] = $this->makePageFromTitle(
+ $title
+ )->getLongHTMLText( $this->getLinker( $field->getResultSubject() ) );
+ $aggregatedValues['url'] = $title->getLocalURL( 'action=raw' );
+ $dataSource = true;
+ continue;
+ } elseif ( $dataItem->getDIType() == SMWDataItem::TYPE_WIKIPAGE && $this->params['datasource'] === 'file' && $title->getNamespace() === NS_FILE && !$dataSource ) {
+ // Support data source = file which pulls the url from a uploaded file
+ $aggregatedValues['subject'] = $this->makePageFromTitle(
+ $title
+ )->getLongHTMLText( $this->getLinker( $field->getResultSubject() ) );
+ $aggregatedValues['url'] = wfFindFile( $title )->getUrl();
+ $dataSource = true;
+ continue;
+ } elseif ( $dataItem->getDIType() == SMWDataItem::TYPE_URI && $this->params['datasource'] === 'url' && !$dataSource ) {
+ // Support data source = url, pointing to an url data source
+ $aggregatedValues['link'] = $dataValue->getShortHTMLText( $this->getLinker( false ) );
+ $aggregatedValues['url'] = $dataValue->getURL();
+ $dataSource = true;
+ continue;
+ }
+
+ // The annotation should adhere outlined conventions as the label identifies the array object key
+ // series -> Required The name of the series to which the annotated point belongs
+ // x -> Required The x value of the point
+ // shortText -> Text that will appear as annotation flag
+ // text -> A longer description of the annotation
+ // @see http://dygraphs.com/annotations.html
+ if ( in_array( $propertyLabel, [ 'series', 'x', 'shortText', 'text' ] ) ) {
+ if ( $dataItem->getDIType() == SMWDataItem::TYPE_NUMBER ) {
+ // Set unit if available
+ $dataValue->setOutputFormat( $this->params['unit'] );
+ // Check if unit is available
+ $annotation[$propertyLabel] = $dataValue->getUnit() !== '' ? $dataValue->getShortWikiText(
+ ) : $dataValue->getNumber();
+ } else {
+ $annotation[$propertyLabel] = $dataValue->getWikiValue();
+ }
+ }
+ }
+ }
+ // Sum-up collected row items in a single array
+ if ( $annotation !== [] ) {
+ $aggregatedValues['annotation'][] = $annotation;
+ }
+ }
+ return $aggregatedValues;
+ }
+
+ private function makePageFromTitle( \Title $title ) {
+ $dataValue = new SMWWikiPageValue( '_wpg' );
+ $dataItem = SMWDIWikiPage::newFromTitle( $title );
+ $dataValue->setDataItem( $dataItem );
+ return $dataValue;
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ protected function getFormatOutput( $data, $options ) {
+
+ // Object count
+ static $statNr = 0;
+ $chartID = 'srf-dygraphs-' . ++$statNr;
+
+ $this->isHTML = true;
+
+ // Reorganize the raw data
+ if ( $this->params['datasource'] === 'page' ) {
+ foreach ( $data as $key => $values ) {
+ $dataObject[] = [ 'label' => $key, 'data' => $values ];
+ }
+ } else {
+ $dataObject['source'] = $data;
+ }
+
+ // Prepare transfer array
+ $chartData = [
+ 'data' => $dataObject,
+ 'sask' => $options['sask'],
+ 'parameters' => [
+ 'width' => $this->params['width'],
+ 'height' => $this->params['height'],
+ 'xlabel' => $this->params['xlabel'],
+ 'ylabel' => $this->params['ylabel'],
+ 'charttitle' => $this->params['charttitle'],
+ 'charttext' => $this->params['charttext'],
+ 'infotext' => $this->params['infotext'],
+ 'datasource' => $this->params['datasource'],
+ 'rollerperiod' => $this->params['mavg'],
+ 'gridview' => $this->params['gridview'],
+ 'errorbar' => $this->params['errorbar'],
+ ]
+ ];
+
+ // Array encoding and output
+ $requireHeadItem = [ $chartID => FormatJson::encode( $chartData ) ];
+ SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ SMWOutputs::requireResource( 'ext.srf.dygraphs' );
+
+ if ( $this->params['gridview'] === 'tabs' ) {
+ SMWOutputs::requireResource( 'ext.srf.util.grid' );
+ }
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [ 'id' => $chartID, 'class' => 'container', 'style' => "display:none;" ],
+ null
+ );
+
+ // Processing/loading image
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // Beautify class selector
+ $class = $this->params['class'] ? ' ' . $this->params['class'] : ' dygraphs-common';
+
+ // General output marker
+ return Html::rawElement(
+ 'div',
+ [ 'class' => 'srf-dygraphs' . $class ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['datasource'] = [
+ 'message' => 'srf-paramdesc-datasource',
+ 'default' => 'file',
+ 'values' => [ 'file', 'raw', 'url' ],
+ ];
+
+ $params['errorbar'] = [
+ 'message' => 'srf-paramdesc-errorbar',
+ 'default' => '',
+ 'values' => [ 'fraction', 'sigma', 'range' ],
+ ];
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-minvalue',
+ 'default' => '',
+ ];
+
+ $params['mavg'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-movingaverage',
+ 'default' => 14,
+ 'lowerbound' => 0,
+ ];
+
+ $params['gridview'] = [
+ 'message' => 'srf-paramdesc-gridview',
+ 'default' => 'none',
+ 'values' => [ 'none', 'tabs' ],
+ ];
+
+ $params['infotext'] = [
+ 'message' => 'srf-paramdesc-infotext',
+ 'default' => '',
+ ];
+
+ $params['unit'] = [
+ 'message' => 'srf-paramdesc-unit',
+ 'default' => '',
+ ];
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_chartheight',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ $params['width'] = [
+ 'message' => 'srf_paramdesc_chartwidth',
+ 'default' => '100%',
+ ];
+
+ $params['charttitle'] = [
+ 'message' => 'srf_paramdesc_charttitle',
+ 'default' => '',
+ ];
+
+ $params['charttext'] = [
+ 'message' => 'srf-paramdesc-charttext',
+ 'default' => '',
+ ];
+
+ $params['infotext'] = [
+ 'message' => 'srf-paramdesc-infotext',
+ 'default' => '',
+ ];
+
+ $params['ylabel'] = [
+ 'message' => 'srf-paramdesc-yaxislabel',
+ 'default' => '',
+ ];
+
+ $params['xlabel'] = [
+ 'message' => 'srf-paramdesc-xaxislabel',
+ 'default' => '',
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.css b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.css
new file mode 100644
index 00000000..afc74310
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.css
@@ -0,0 +1,43 @@
+/**
+ * CSS for SRF dygraphs module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Dygraphs format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+.srf-ui-chart-source {
+ float: right;
+ clear:both;
+ font-size: 12px;
+}
+
+.srf-ui-chart-text{
+ float: left;
+ margin-right: 5px;
+}
+
+.srf-dygraphs-series-content {
+ display:none;
+}
+
+/* Tooltip icon defaults*/
+.srf-dygraphs.series {
+ float: right;
+ margin-left:10px;
+ vertical-align:bottom;
+ padding:16px 16px 0 0;
+ white-space:nowrap;
+}
+
+/* Individual assigned icons ( inline-block is important because the icon <span> is empty) */
+.srf-dygraphs.series.icon {
+ display:inline-block;
+ clear:both;
+ /* @embed */ background: url(images/check.png) no-repeat left bottom;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.js b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.js
new file mode 100644
index 00000000..2763bd3d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/ext.srf.dygraphs.js
@@ -0,0 +1,416 @@
+/**
+ * JavaScript for SRF dygraphs module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Dygraphs format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /*global mw:true Dygraph:true mediaWiki:true*/
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ var util = new srf.util();
+ var tooltip = new smw.util.tooltip();
+
+ /**
+ * Add icon image
+ *
+ * @return object
+ */
+ var _addIcon = function( options ){
+ var h = mw.html,
+ icon = h.element( 'span', { 'class' : options.className, 'style': 'display:inline;' },
+ new h.Raw( h.element( 'img', {
+ src: mw.config.get( 'wgExtensionAssetsPath' ) + '/SemanticMediaWiki/resources/images/' + options.image,
+ title: options.title
+ }
+ ) )
+ );
+ return icon;
+ },
+
+ /**
+ * Add checkbox element
+ *
+ * @return object
+ */
+ _addCheckboxItem = function( options ){
+ var item = '';
+ $.each( options.array, function( index, value ) {
+ item +='<input type=checkbox class="' + options.className + '" id=' + index + ' checked><label for="' + index +'">'+ value + '</label><br />';
+ } );
+ return item;
+ },
+
+ /**
+ * Add chart text element
+ *
+ * @return number
+ */
+ _addChartText = function( options ){
+ if( options.text.length > 0 ){
+ options.instance.after( '<span class="' + options.className + ' ' + options.extraClass + '">' + options.text + '</span>' );
+ return options.instance.next().height();
+ } else {
+ return 0;
+ }
+ },
+
+ /**
+ * Add chart source element
+ *
+ * @return number
+ */
+ _addChartSource = function( options ){
+ if( options.source.length > 0 ){
+ options.instance
+ .after( '<span class="' + options.className + ' ' + options.extraClass + '">' + '[ ' + options.source + ' ]</span>' );
+
+ // Don't browse the whole DOM tree, just use the next element we created
+ // and adopt the title
+ var object = options.instance.next();
+ object.find( 'a' ).text( options.sourceTitle );
+ return object.height();
+ } else {
+ return 0;
+ }
+ };
+
+ ////////////////////////// PUBLIC METHODS ////////////////////////
+
+ $.fn.extend( {
+ srfdygraphs: function( options ) {
+ return this.each( function() {
+
+ var chart = $(this),
+ container = chart.find( '.container' ),
+ chartID = container.attr( 'id' ),
+ json = mw.config.get( chartID );
+
+ // Parse json string
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ /**
+ * @var plotClass identifies the class that holds the plot
+ * @var plotID identifies the ID that holds the plot mainly used by dygraphs
+ *
+ * Instances
+ *
+ * plotInstance = plotting area
+ * container = all additional elements
+ * chart = container + processing
+ */
+ var plotClass = 'srf-dygraphs-plot',
+ plotInstance = '',
+ seriesInstance = '',
+ plotID = chartID + '-plot',
+ width = data.parameters.width,
+ height = data.parameters.height,
+ h = mw.html;
+
+ // Fetch the data from the source
+ getData( data );
+
+ /**
+ * Release the container and hide the processing image
+ *
+ */
+ function showContainer(){
+ container.show();
+ util.spinner.hide( { context: chart } );
+ }
+
+ /**
+ * Instead of dygraphs making a var req = new XMLHttpRequest()
+ * we fetch the data via ajax
+ *
+ */
+ function getData( options ){
+
+ var jqxhr = $.ajax( {
+ url: options.data.source.url
+ } )
+ .done(function( data ) {
+
+ // What we try to do here is that people might start adding [[Category]] or worst
+ // {{#subobject}} annotions within the same raw data and to avoid any possible
+ // interference delete all [[]] and {{}} tags from the raw data
+ var rawData = data.replace(/\[\[(.*)\]\]|\{\{(.*)\}\}/igm, '' );
+
+ // Try the filter first line and find the labels used
+ var line_delimiter = Dygraph.detectLineDelimiter( rawData );
+ var delim = ',';
+ var lines = rawData.split( line_delimiter || "\n", 1 );
+ var labels = lines[0].split( delim );
+
+ // In aynchronous mode only now are we able to proceed
+ prepareContainer( { labels: labels } );
+ initGraph( { data: rawData, labels: labels } );
+ } )
+ .fail(function( error ) {
+ // Release visual container
+ showContainer();
+
+ var responseText = error.responseText !== '' ? ' (' + error.responseText + ')' : '';
+
+ // Init error tooltip
+ tooltip.add( {
+ targetClass: 'smwtticon warning',
+ context: container,
+ title: mw.msg( 'smw-ui-tooltip-title-warning' ),
+ type: 'warning',
+ button: true,
+ content: mw.msg(
+ 'srf-ui-common-label-ajax-error',
+ h.element( 'a', { 'href' : options.data.source.url }, mw.msg( 'srf-ui-common-label-request-object', responseText ) ),
+ h.element( 'a', { 'href' : 'http://www.semantic-mediawiki.org/wiki/Help:Ajax' }, mw.msg( 'srf-ui-common-label-help-section' ) ) )
+ } );
+ } )
+ .always(function( complete ) {
+ } );
+ }
+
+ /**
+ * Visual instance for displaying the container content
+ *
+ */
+ function prepareContainer( options ){
+
+ // Set overall chart height and width
+ chart.css( { 'height': height , 'width': width } );
+
+ // Add the plotting area
+ container.prepend( h.element( 'div', { 'id': plotID , 'class' : plotClass }, null ) );
+ plotInstance = container.find( '.' + plotClass );
+
+ // Adjustments for cases where jquery ui is involved
+ // @var addedHeight collects heights of objects other that the chart in order
+ width = chart.width() - ( data.parameters.gridview === 'tabs' ? 30 : 0 );
+ height = height - ( data.parameters.gridview === 'tabs' ? 20 : 20 );
+
+ // Release container in order to measure adjustments
+ showContainer();
+
+ height = height - _addChartSource( {
+ instance: plotInstance,
+ source: ( data.data.source.subject !== undefined ? data.data.source.subject : data.data.source.link !== undefined ? data.data.source.link : null ),
+ extraClass: data.parameters.gridview,
+ sourceTitle: mw.msg( 'srf-ui-common-label-datasource' ),
+ className: 'srf-ui-chart-source'
+ } );
+
+ height = height - _addChartText( {
+ instance: plotInstance,
+ text: data.parameters.charttext,
+ extraClass: data.parameters.gridview,
+ className: 'srf-ui-chart-text'
+ } );
+
+ // Adjust height and width after text etc. has been generated
+ container.css( { 'height': height, 'width': width } );
+
+ // Fit the plotting area
+ container.find( '.' + plotClass ).css( { 'height': height , 'width': width } );
+ }
+
+ /**
+ * GridView plugin
+ *
+ */
+ function initGridView(){
+ var dataSeries = [],
+ dataTable = [];
+
+ // Prepare datatable
+ if ( data.data.source.annotation !== undefined ){
+ $.map( data.data.source.annotation , function( val ){
+ dataSeries.push ( { label: val.series } );
+ dataTable.push ( [[ val.shortText + ' (' + val.text + ')', val.x]] );
+ } );
+ }
+
+ // Set options
+ var gridOptions = {
+ 'context' : chart,
+ 'id' : chartID,
+ 'container' : container,
+ 'info' : data.parameters.infotext,
+ 'data' : {
+ 'series': dataSeries,
+ 'data' : dataTable,
+ 'sask' : data.sask
+ }
+ };
+
+ // Grid view instance
+ new srf.util.grid( gridOptions );
+ }
+
+ /**
+ * Prepare annotations
+ *
+ */
+ function getAnnotations ( annotations ){
+ if ( annotations !== undefined ){
+ $.map( annotations , function(key){
+ // Determine correct width of the shortText (use a <div> as vehicle)
+ // and not the length (such as key.shortText.length)
+ var o = $('<div>' + key.shortText + '</div>')
+ .css( {'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden'} )
+ .appendTo( container );
+ key.width = o.width() + 5;
+ o.remove();
+ } );
+ return annotations;
+ }
+ }
+
+ /**
+ * Generate checkboxes from available lables and initialize/show
+ * the tooltip with available options
+ *
+ */
+ function getSeries( options ){
+ // Slice from position 1 because the 0 is the x-value descriptor wich is not needed here
+ var seriesItem = _addCheckboxItem( {
+ array : options.labels.slice(1),
+ className : 'srf-dygraphs-series-item'
+ } );
+
+ // Create option set which is displayed as tooltip to safe space and
+ // only displays it when the user demands it
+ tooltip.add( {
+ contextClass: 'srf-dygraphs-series',
+ contentClass: 'srf-dygraphs-series-content',
+ targetClass : 'srf-dygraphs series icon',
+ context: container.find( '.srf-ui-chart-source' ),
+ title: mw.msg( 'srf-ui-tooltip-title-scope' ),
+ type: 'info',
+ button: true,
+ content: seriesItem
+ } );
+
+ // Store seriesInstance
+ seriesInstance = container.find( '.srf-dygraphs-series-item' );
+ }
+
+ /**
+ * Create dygraph instance
+ *
+ * @see http://dygraphs.com/
+ *
+ */
+ function initGraph( options ){
+
+ var g = new Dygraph(
+ document.getElementById( plotID ),
+ function() { return options.data; },{
+ rollPeriod: data.parameters.rollerperiod,
+ showRoller: data.parameters.rollerperiod > 0 ? true : false,
+ title: data.parameters.charttitle,
+ ylabel: data.parameters.ylabel,
+ xlabel: data.parameters.xlabel,
+ labelsKMB: true,
+ customBars: data.parameters.errorbar === 'range',
+ fractions: data.parameters.errorbar === 'fraction',
+ errorBars: data.parameters.errorbar === 'sigma',
+ legend: 'always',
+ //labels: data.parameters.group === 'label' ? dataSeriesLabel : data.parameters.datasource !== 'file' ? null : dataSeriesLabel,
+ labelsDivStyles: { 'textAlign': 'right', 'background': 'transparent' },
+ labelsSeparateLines: true,
+ underlayCallback: function(canvas, area, g) {
+
+ // Allow background to be white
+ canvas.fillStyle = 'white';
+ canvas.fillRect(area.x, area.y, area.w, area.h);
+ },
+
+ // drawCallback gets called every time the dygraph is drawn. This includes
+ // the initial draw, after zooming and repeatedly while panning
+ // @see http://dygraphs.com/options.html#Callbacks
+ drawCallback: function(g, is_initial) {
+ if ( !is_initial ){
+ return;
+ } else {
+
+ // GridView plug-in processing
+ if ( data.parameters.gridview === 'tabs' ) {
+ initGridView();
+ }
+
+ // Adjust table height due to possible changes initiated by the
+ // jquery ui tabs
+ var tabsHeight = chart.find( '.ui-tabs-nav' ).outerHeight() ;
+ plotInstance.css( { height: plotInstance.height() - tabsHeight } );
+ g.resize();
+
+ // Create and display annotations
+ var annotations = getAnnotations( data.data.source.annotation );
+ if ( annotations !== undefined ){
+ g.setAnnotations( annotations );
+ }
+ }
+ }
+ }
+ );
+
+ // Get series labels and create series label tooltip
+ getSeries( {labels: options.labels } );
+
+ // Catch series label toggle change and set visibility
+ seriesInstance.change( function( el ){
+ g.setVisibility( $(this).attr('id'), el.currentTarget.checked );
+ } );
+ }
+ } );
+ }
+ } );
+
+ ////////////////////////// IMPLEMENTATION ////////////////////////
+
+ /**
+ * Dygraphs
+ *
+ * If eachAsync is available call each instance as async in order
+ * to increase browsers responsiveness
+ */
+ var dygraphs = {
+ init: function () {
+ $( document ).ready( function() {
+ if( $.isFunction( $.fn.eachAsync ) ){
+ $( '.srf-dygraphs' ).eachAsync( {
+ delay: 100,
+ bulk: 0,
+ loop: function(){
+ $( this ).srfdygraphs();
+ }
+ } );
+ } else {
+ $( '.srf-dygraphs' ).each( function() {
+ $( this ).srfdygraphs();
+ } );
+ }
+ } );
+ } };
+
+ /**
+ * Check browser profile
+ *
+ * IE sucks because of that we have to jump some loops here to ensure that
+ * for < IE9 excanvas module is loaded
+ */
+ var p = $.client.profile();
+
+ if ( p.name === 'msie' && p.versionNumber < 9 ) {
+ // mw.loader.using( 'ext.dygraphs.excanvas', dygraphs.init );
+ dygraphs.init();
+ } else {
+ dygraphs.init();
+ }
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.png b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.png
new file mode 100644
index 00000000..b5be279e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.psd b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.psd
new file mode 100644
index 00000000..dc3a6558
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/dygraphs/resources/images/check.psd
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/README.md b/www/wiki/extensions/SemanticResultFormats/formats/filtered/README.md
new file mode 100644
index 00000000..5c46bf1d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/README.md
@@ -0,0 +1,179 @@
+# Parameters
+
+Parameters to the `#ask` function can apply to the `filtered` format as a whole
+(format level) or to only one specific printout (printout level). On format
+level there are some generic parameters that are common to all result formats
+and some format specific parameters that are used only by the `filtered` format.
+
+Consider the following query:
+```
+{{#ask:[[SomeCondition]]
+|? SomePrintout |+filter=number
+|? Position
+|format=filtered
+|limit=100
+|views=map
+|mapviewmarkerpositionproperty=Position
+}}
+```
+
+In this query `limit=100` is on format level (generic), `views=map` is on format
+level (format specific) and `+filter=number` is on printout level.
+
+## Format level - Generic:
+
+Supported:
+* format
+* mainlabel
+* sort
+* order
+* intro
+* outro
+* limit
+* offset
+* headers (Table view)
+
+Not supported by the `filtered` format:
+* source
+* link
+* searchlabel
+* default
+
+## Format level - Format specific:
+* views (`list`|`calendar`|`table`|`map`)
+* filter position (`top`|`bottom`)
+
+### List view
+
+* list view type
+* list view template
+* list view named args
+* list view introtemplate
+* list view outrotemplate
+
+### Calendar view
+
+* calendar view start
+* calendar view end
+* calendar view title
+* calendar view title template
+
+### Table view
+
+* table view class
+
+### Map view
+
+This view is only available if `$srfgMapProvider` is set in `LocalSettings.php`,
+e.g. `$srfgMapProvider='OpenStreetMap.HOT';`<br>
+See the [list of available
+providers](http://leaflet-extras.github.io/leaflet-providers/preview/index.html)
+
+* map view marker position property
+* map view marker icon property
+* map view marker icons
+* map view height
+* map view zoom
+* map view min zoom
+* map view max zoom
+* map view marker cluster (`true`|`false`)
+* map view marker cluster max zoom
+* map view marker cluster max radius
+* map view marker cluster zoom on click (`true`|`false`)
+
+## Printout level
+
+* filter (comma-separated list of `value`, `distance`, and/or `number`)
+* hide (`yes`|`no`)
+* align (`right`|`left`|`center`) (Table view only)
+* show if undefined (`yes`|`no`)
+
+### Value filter
+
+* value filter collapsible (`collapsed`|`uncollapsed`)
+* value filter switches (comma-separated list of `and or` and/or `on off`)
+* value filter values (list of strings)
+* value filter max checkboxes (number. Default: 5)
+
+### Distance filter
+
+* distance filter origin (lat lon): *Required*
+* distance filter collapsible (`collapsed`|`uncollapsed`)
+* distance filter switches (`on off`)
+* distance filter initial value (number)
+* distance filter max distance (number)
+* distance filter unit (`m`|`km`|`mi`|`nm`)
+
+### Number filter
+
+* number filter collapsible (`collapsed`|`uncollapsed`)
+* number filter switches (`on off`)
+* number filter min value (number)
+* number filter max value (number)
+* number filter step (number)
+* number filter values (`auto`|comma-separated list of values):
+ If this parameter is specified, min, max and step will be ignored.
+* number filter sliders (`min`|`max`|`range`|`select`)
+* number filter label (string)
+
+# Building
+
+This is only required for development, not for simple installation and usage.
+
+From the `.../SemanticResultFormats/formats/filtered` directory run
+ ```
+ npm install
+ ```
+
+# Running tests
+
+## JavaScript
+
+JavaScript tests use the QUnit test environment of MediaWiki. To enable the test
+environment add the following to `LocalSettings.php`:
+``` PHP
+$wgEnableJavaScriptTest = true;
+```
+
+Then the easiest way to run tests is to go to
+`http://127.0.0.1/wiki/Special:JavaScriptTest/qunit/plain?module=ext.srf.formats.filtered`
+(with server and path modified as necessary).
+
+
+To at some point allow for continuous integration testing the tests can also be
+run from the command line on a headless browser. Google Chrome 59 (currently in
+Beta status) allows headless execution. It will forward anything written to the
+JavaScript console to the CLI standard output. So, to run tests from the command
+line install Chrome Beta and run
+
+```
+google-chrome-beta \
+--headless \
+--disable-gpu \
+--remote-debugging-port=9222 \
+'http://127.0.0.1/wiki/Special:JavaScriptTest/qunit/plain?debug=true&module=ext.srf.formats.filtered'
+```
+
+Chrome will remain running, so when the test run is finished it has to be
+force-stopped.
+See https://developers.google.com/web/updates/2017/04/headless-chrome for
+details on headless Chrome.
+
+## PHP
+
+PHP tests use PHPUnit. The easiest way to run all SRF tests including the tests
+for the Filtered format is to run `composer phpunit` from the SRF directory.
+However, for the tests to run it has to be ensured, that the `$srfgMapProvider`
+configuration variable is not set in `LocalSettings.php`.
+
+#Credits
+
+The Filtered format contains the following software libraries:
+* Leaflet by Vladimir Agafonkin (http://leafletjs.com/)
+* Leaflet Marker Cluster Plugin by Dave Leaver (https://github.com/Leaflet/Leaflet.markercluster)
+* Leaflet Providers Plugin by Leaflet Providers contributors (https://github.com/leaflet-extras/leaflet-providers)
+* Ion.RangeSlider by Denis Ineshin (http://ionden.com)
+* Select2 by Kevin Brown, Igor Vaynberg, and Select2 contributors (https://select2.github.io/)
+
+Several other libraries are used for the build process. See the devDependencies
+in the package.json file. \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/gulpfile.js b/www/wiki/extensions/SemanticResultFormats/formats/filtered/gulpfile.js
new file mode 100644
index 00000000..d3b1f697
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/gulpfile.js
@@ -0,0 +1,154 @@
+var gulp = require( 'gulp' );
+
+var browserify = require( 'browserify' );
+var tsify = require( 'tsify' );
+var uglify = require( 'gulp-uglify' );
+var concat = require( 'gulp-concat' );
+var replace = require( 'gulp-replace' );
+var sourcemaps = require( 'gulp-sourcemaps' );
+var source = require( 'vinyl-source-stream' );
+var buffer = require( 'vinyl-buffer' );
+
+
+gulp.task( 'buildFiltered', function () {
+
+ return browserify( {
+ basedir: '.',
+ debug: true, // true, to enable source mapping
+ entries: [ 'resources/ts/bootstrap.ts' ],
+ cache: {},
+ packageCache: {}
+ } )
+ .exclude( 'jquery' )
+ .plugin( tsify )
+ .bundle()
+
+ .pipe( source( 'ext.srf.filtered.js' ) )
+ .pipe( buffer() )
+ .pipe( sourcemaps.init( { loadMaps: true } ) )
+ // .pipe( uglify() )
+ .pipe( sourcemaps.write( './' ) )
+ .pipe( gulp.dest( 'resources/js' ) );
+
+} );
+
+gulp.task( 'buildFilteredTests', function () {
+
+ return browserify( {
+ basedir: '.',
+ debug: false, // false, to disable source mapping
+ entries: [ 'tests/qunit/bootstrap.ts' ],
+ cache: {},
+ packageCache: {}
+ } )
+ // .exclude( 'jquery' )
+ .plugin( tsify )
+ .bundle()
+
+ .pipe( source( 'ext.srf.formats.filtered.test.js' ) )
+ // .pipe( buffer() )
+ // .pipe( sourcemaps.init( { loadMaps: true } ) )
+ // .pipe( uglify() )
+ // .pipe( sourcemaps.write( './' ) )
+ .pipe( gulp.dest( '../../tests/qunit/formats' ) );
+
+} );
+
+gulp.task( 'buildExternalJS', function () {
+
+ var config = {
+ 'ext.srf.filtered.leaflet.js': [
+ 'node_modules/leaflet/dist/leaflet-src.js',
+ 'node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.js',
+ 'node_modules/leaflet-providers/leaflet-providers.js'
+ ],
+ 'ext.srf.filtered.slider.js': [
+ 'node_modules/ion-rangeslider/js/ion.rangeSlider.js'
+ ],
+ 'ext.srf.filtered.select.js': [
+ 'node_modules/select2/dist/js/select2.js'
+ ]
+ };
+
+ var res = true;
+
+ for ( var target in config ) {
+
+ res = res && gulp.src( config[ [ target ] ] )
+ .pipe( concat( target ) )
+ // .pipe( uglify() )
+ .pipe( gulp.dest( 'resources/js' ) );
+
+ }
+
+ return res;
+
+} );
+
+gulp.task( 'buildLeafletCSS', function () {
+
+ return gulp
+ .src( [
+ 'node_modules/leaflet/dist/leaflet.css',
+ 'node_modules/leaflet.markercluster/dist/MarkerCluster.css',
+ 'node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css'
+ ] )
+ .pipe( concat( 'ext.srf.filtered.leaflet.css' ) )
+ .pipe( gulp.dest( 'resources/css' ) );
+
+} );
+
+gulp.task( 'buildSliderCSS', function () {
+
+ return gulp
+ .src( [
+ 'node_modules/ion-rangeslider/css/ion.rangeSlider.css',
+ 'node_modules/ion-rangeslider/css/ion.rangeSlider.skinNice.css'
+ ] )
+ .pipe( concat( 'ext.srf.filtered.slider.css' ) )
+ // Need to remove some upstream CSS:
+ .pipe( replace( '.irs-line-mid,\n' +
+ '.irs-line-left,\n' +
+ '.irs-line-right,\n' +
+ '.irs-bar,\n' +
+ '.irs-bar-edge,\n' +
+ '.irs-slider {\n' +
+ ' background: url(../img/sprite-skin-nice.png) repeat-x;\n' +
+ '}\n' +
+ '\n', '' ) )
+ .pipe( gulp.dest( 'resources/css' ) );
+} );
+
+gulp.task( 'buildSelectCSS', function () {
+
+ return gulp
+ .src( [ 'node_modules/select2/dist/css/select2.css' ] )
+ .pipe( concat( 'ext.srf.filtered.select.css' ) )
+ .pipe( gulp.dest( 'resources/css' ) );
+
+} );
+
+gulp.task( 'copyExternalImages', function () {
+
+ var config = {
+ 'ext.srf.filtered.leaflet.css': [
+ 'node_modules/leaflet/dist/images/*'
+ ],
+ // 'ext.srf.filtered.slider.css': [
+ // 'node_modules/ion-rangeslider/img/*nice.png'
+ // ]
+ };
+
+ var ret = true;
+
+ for ( var target in config ) {
+
+ ret = ret && gulp.src( config[ target ] )
+ .pipe( gulp.dest( 'resources/css/images' ) );
+ }
+
+ return ret;
+} );
+
+gulp.task( 'buildExternalCSS', gulp.parallel( 'buildLeafletCSS', 'buildSliderCSS', 'buildSelectCSS' ) );
+gulp.task( 'default', gulp.parallel( 'buildFiltered', 'buildFilteredTests', 'buildExternalJS', 'buildExternalCSS', 'copyExternalImages' ) );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/package-lock.json b/www/wiki/extensions/SemanticResultFormats/formats/filtered/package-lock.json
new file mode 100644
index 00000000..d8f395f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/package-lock.json
@@ -0,0 +1,5174 @@
+{
+ "name": "filtered",
+ "version": "2.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@gulp-sourcemaps/identity-map": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz",
+ "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==",
+ "dev": true,
+ "requires": {
+ "acorn": "^5.0.3",
+ "css": "^2.2.1",
+ "normalize-path": "^2.1.1",
+ "source-map": "^0.6.0",
+ "through2": "^2.0.3"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "@gulp-sourcemaps/map-sources": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz",
+ "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^2.0.1",
+ "through2": "^2.0.3"
+ }
+ },
+ "@types/fullcalendar": {
+ "version": "2.7.42",
+ "resolved": "https://registry.npmjs.org/@types/fullcalendar/-/fullcalendar-2.7.42.tgz",
+ "integrity": "sha1-UqE+n9sykJ1gxe93wca7W4njCwY=",
+ "dev": true,
+ "requires": {
+ "@types/jquery": "*",
+ "moment": ">=2.14.0"
+ }
+ },
+ "@types/geojson": {
+ "version": "7946.0.7",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
+ "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
+ "dev": true
+ },
+ "@types/ion.rangeslider": {
+ "version": "2.0.29",
+ "resolved": "https://registry.npmjs.org/@types/ion.rangeslider/-/ion.rangeslider-2.0.29.tgz",
+ "integrity": "sha512-80jBkEUCyhOvpPL7Q5KnN4qRruDAcIw5coh8+0IH4pxruTTXrQt4sLEnPcZ4SYYNPJG9kcoaAm3EU60tkQD+DQ==",
+ "dev": true
+ },
+ "@types/jquery": {
+ "version": "2.0.53",
+ "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-2.0.53.tgz",
+ "integrity": "sha512-MZKPWUhp5TKkoJ/58NSq6io+CSUCOHm2b3Z6U4+r9v70kktB0JM+eRjdp6YmDHtw0kK2XB7L2K7/FMIoziHjUA==",
+ "dev": true
+ },
+ "@types/jqueryui": {
+ "version": "1.12.7",
+ "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.7.tgz",
+ "integrity": "sha512-MpHuknhR20kBNsDA2VAM6WZGc+CMApzfKfTZuzMOH2dEUzo5POPGicfGJ647wvl2T6ZgQKPCSWmCUhna3XpX0Q==",
+ "dev": true,
+ "requires": {
+ "@types/jquery": "*"
+ }
+ },
+ "@types/leaflet": {
+ "version": "1.0.69",
+ "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.0.69.tgz",
+ "integrity": "sha512-QZI7kBAaXFtJMZmbc7zgirBDnV7oM2jZZjTMSBM6KOJXNbYMJToWb+cU+TnzoDigq52jdWhT+yPOp8hznJiGFQ==",
+ "dev": true,
+ "requires": {
+ "@types/geojson": "*"
+ }
+ },
+ "@types/leaflet-providers": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@types/leaflet-providers/-/leaflet-providers-1.1.3.tgz",
+ "integrity": "sha512-18bbaaCjnbsNRl/jJZ31WUY1dFUvOoxBM2K5y+At1oqIQlwXeOPEKNUmrvMSzJ/4C/gtUc0qdqOZ7a+aF6AOLA==",
+ "dev": true,
+ "requires": {
+ "@types/leaflet": "*"
+ }
+ },
+ "@types/leaflet.markercluster": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@types/leaflet.markercluster/-/leaflet.markercluster-1.0.0.tgz",
+ "integrity": "sha1-+n+U3CtHvEJJX5O6sAAzeYnlq48=",
+ "dev": true,
+ "requires": {
+ "@types/leaflet": "*"
+ }
+ },
+ "@types/qunit": {
+ "version": "1.16.31",
+ "resolved": "https://registry.npmjs.org/@types/qunit/-/qunit-1.16.31.tgz",
+ "integrity": "sha1-FpunnfVvJfQFVsOcVE4Bi7Y5B5I=",
+ "dev": true
+ },
+ "@types/requirejs": {
+ "version": "2.1.31",
+ "resolved": "https://registry.npmjs.org/@types/requirejs/-/requirejs-2.1.31.tgz",
+ "integrity": "sha512-b2soeyuU76rMbcRJ4e0hEl0tbMhFwZeTC0VZnfuWlfGlk6BwWNsev6kFu/twKABPX29wkX84wU2o+cEJoXsiTw==",
+ "dev": true
+ },
+ "@types/select2": {
+ "version": "4.0.48",
+ "resolved": "https://registry.npmjs.org/@types/select2/-/select2-4.0.48.tgz",
+ "integrity": "sha512-C1cUbfwKBqlO+/3OWQKMajA4D/d5SvI9rSGoXCa7FQI9B1p1iRqZzetkfpGPY44BP1Y8emHL17rdUJYZEyzN+Q==",
+ "dev": true,
+ "requires": {
+ "@types/jquery": "*",
+ "@types/requirejs": "*"
+ }
+ },
+ "JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "acorn": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+ "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+ "dev": true
+ },
+ "acorn-dynamic-import": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
+ "dev": true
+ },
+ "acorn-node": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz",
+ "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.2",
+ "acorn-dynamic-import": "^4.0.0",
+ "acorn-walk": "^6.1.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "acorn-walk": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+ "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
+ "dev": true
+ },
+ "align-text": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2",
+ "longest": "^1.0.1",
+ "repeat-string": "^1.5.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "almond": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz",
+ "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=",
+ "dev": true
+ },
+ "ansi-colors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+ "dev": true,
+ "requires": {
+ "ansi-wrap": "^0.1.0"
+ }
+ },
+ "ansi-gray": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+ "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
+ "dev": true,
+ "requires": {
+ "ansi-wrap": "0.1.0"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-wrap": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+ "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
+ "dev": true
+ },
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "append-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+ "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
+ "dev": true,
+ "requires": {
+ "buffer-equal": "^1.0.0"
+ }
+ },
+ "archy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
+ "dev": true
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "arr-filter": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
+ "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
+ "dev": true,
+ "requires": {
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-map": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
+ "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
+ "dev": true,
+ "requires": {
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+ "dev": true
+ },
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+ "dev": true
+ },
+ "array-initial": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
+ "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=",
+ "dev": true,
+ "requires": {
+ "array-slice": "^1.0.0",
+ "is-number": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ }
+ }
+ },
+ "array-last": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+ "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
+ "dev": true,
+ "requires": {
+ "is-number": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ }
+ }
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+ "dev": true
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+ "dev": true
+ },
+ "array-slice": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+ "dev": true
+ },
+ "array-sort": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+ "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
+ "dev": true,
+ "requires": {
+ "default-compare": "^1.0.0",
+ "get-value": "^2.0.6",
+ "kind-of": "^5.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+ "dev": true,
+ "requires": {
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "async-done": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz",
+ "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.2",
+ "process-nextick-args": "^1.0.7",
+ "stream-exhaust": "^1.0.1"
+ },
+ "dependencies": {
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+ "dev": true
+ }
+ }
+ },
+ "async-each": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz",
+ "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==",
+ "dev": true
+ },
+ "async-settle": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
+ "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
+ "dev": true,
+ "requires": {
+ "async-done": "^1.2.2"
+ }
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "bach": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+ "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
+ "dev": true,
+ "requires": {
+ "arr-filter": "^1.1.1",
+ "arr-flatten": "^1.0.1",
+ "arr-map": "^2.0.0",
+ "array-each": "^1.0.0",
+ "array-initial": "^1.0.0",
+ "array-last": "^1.1.1",
+ "async-done": "^1.2.2",
+ "async-settle": "^1.0.0",
+ "now-and-later": "^2.0.0"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz",
+ "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==",
+ "dev": true
+ },
+ "binaryextensions": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz",
+ "integrity": "sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=",
+ "dev": true
+ },
+ "bl": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+ "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browser-pack": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz",
+ "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "combine-source-map": "~0.8.0",
+ "defined": "^1.0.0",
+ "safe-buffer": "^5.1.1",
+ "through2": "^2.0.0",
+ "umd": "^3.0.0"
+ }
+ },
+ "browser-resolve": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
+ "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
+ "dev": true,
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ }
+ }
+ },
+ "browserify": {
+ "version": "16.2.3",
+ "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz",
+ "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "assert": "^1.4.0",
+ "browser-pack": "^6.0.1",
+ "browser-resolve": "^1.11.0",
+ "browserify-zlib": "~0.2.0",
+ "buffer": "^5.0.2",
+ "cached-path-relative": "^1.0.0",
+ "concat-stream": "^1.6.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "~1.0.0",
+ "crypto-browserify": "^3.0.0",
+ "defined": "^1.0.0",
+ "deps-sort": "^2.0.0",
+ "domain-browser": "^1.2.0",
+ "duplexer2": "~0.1.2",
+ "events": "^2.0.0",
+ "glob": "^7.1.0",
+ "has": "^1.0.0",
+ "htmlescape": "^1.1.0",
+ "https-browserify": "^1.0.0",
+ "inherits": "~2.0.1",
+ "insert-module-globals": "^7.0.0",
+ "labeled-stream-splicer": "^2.0.0",
+ "mkdirp": "^0.5.0",
+ "module-deps": "^6.0.0",
+ "os-browserify": "~0.3.0",
+ "parents": "^1.0.1",
+ "path-browserify": "~0.0.0",
+ "process": "~0.11.0",
+ "punycode": "^1.3.2",
+ "querystring-es3": "~0.2.0",
+ "read-only-stream": "^2.0.0",
+ "readable-stream": "^2.0.2",
+ "resolve": "^1.1.4",
+ "shasum": "^1.0.0",
+ "shell-quote": "^1.6.1",
+ "stream-browserify": "^2.0.0",
+ "stream-http": "^2.0.0",
+ "string_decoder": "^1.1.1",
+ "subarg": "^1.0.0",
+ "syntax-error": "^1.1.1",
+ "through2": "^2.0.0",
+ "timers-browserify": "^1.0.1",
+ "tty-browserify": "0.0.1",
+ "url": "~0.11.0",
+ "util": "~0.10.1",
+ "vm-browserify": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.1",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.2",
+ "elliptic": "^6.0.0",
+ "inherits": "^2.0.1",
+ "parse-asn1": "^5.0.0"
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+ "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4"
+ }
+ },
+ "buffer-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
+ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "cached-path-relative": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz",
+ "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+ "dev": true
+ },
+ "center-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "dev": true,
+ "requires": {
+ "align-text": "^0.1.3",
+ "lazy-cache": "^1.0.3"
+ }
+ },
+ "chokidar": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz",
+ "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ }
+ }
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+ "dev": true
+ },
+ "clone-buffer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+ "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
+ "dev": true
+ },
+ "clone-stats": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+ "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
+ "dev": true
+ },
+ "cloneable-readable": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz",
+ "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "process-nextick-args": "^2.0.0",
+ "readable-stream": "^2.3.5"
+ }
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "collection-map": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+ "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
+ "dev": true,
+ "requires": {
+ "arr-map": "^2.0.2",
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "dev": true
+ },
+ "combine-source-map": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
+ "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "~1.1.0",
+ "inline-source-map": "~0.6.0",
+ "lodash.memoize": "~3.0.3",
+ "source-map": "~0.5.3"
+ }
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "concat-with-sourcemaps": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+ "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "dev": true,
+ "requires": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
+ "dev": true
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "copy-props": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz",
+ "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==",
+ "dev": true,
+ "requires": {
+ "each-props": "^1.3.0",
+ "is-plain-object": "^2.0.1"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "css": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
+ "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "source-map": "^0.6.1",
+ "source-map-resolve": "^0.5.2",
+ "urix": "^0.1.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "d": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+ "dev": true,
+ "requires": {
+ "es5-ext": "^0.10.9"
+ }
+ },
+ "dash-ast": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz",
+ "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==",
+ "dev": true
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "debug-fabulous": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz",
+ "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==",
+ "dev": true,
+ "requires": {
+ "debug": "3.X",
+ "memoizee": "0.4.X",
+ "object-assign": "4.X"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ }
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "default-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+ "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^5.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "default-resolution": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
+ "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=",
+ "dev": true
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "defined": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+ "dev": true
+ },
+ "deps-sort": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+ "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "shasum": "^1.0.0",
+ "subarg": "^1.0.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "des.js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+ "dev": true
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+ "dev": true
+ },
+ "detective": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
+ "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.6.1",
+ "defined": "^1.0.0",
+ "minimist": "^1.1.1"
+ }
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true
+ },
+ "duplexer2": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "each-props": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+ "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.1",
+ "object.defaults": "^1.1.0"
+ }
+ },
+ "elliptic": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
+ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "end-of-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.49",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.49.tgz",
+ "integrity": "sha512-3NMEhi57E31qdzmYp2jwRArIUsj1HI/RxbQ4bgnSB+AIKIxsAmTiK83bYMifIcpWvEc3P1X30DhUKOqEtF/kvg==",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.1",
+ "next-tick": "^1.0.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.14",
+ "es6-iterator": "^2.0.1",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "events": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
+ "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==",
+ "dev": true
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "fancy-log": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+ "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+ "dev": true,
+ "requires": {
+ "ansi-gray": "^0.1.1",
+ "color-support": "^1.1.3",
+ "parse-node-version": "^1.0.0",
+ "time-stamp": "^1.0.0"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+ "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "fined": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz",
+ "integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "is-plain-object": "^2.0.3",
+ "object.defaults": "^1.1.0",
+ "object.pick": "^1.2.0",
+ "parse-filepath": "^1.0.1"
+ }
+ },
+ "flagged-respawn": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+ "dev": true
+ },
+ "flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fs-mkdirp-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+ "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "through2": "^2.0.3"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
+ "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "^2.9.2",
+ "node-pre-gyp": "^0.10.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "needle": {
+ "version": "2.2.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.10.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "semver": {
+ "version": "5.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "4.4.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.4",
+ "minizlib": "^1.1.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "get-assigned-identifiers": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz",
+ "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+ "dev": true
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "glob-stream": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+ "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.0",
+ "glob": "^7.1.1",
+ "glob-parent": "^3.1.0",
+ "is-negated-glob": "^1.0.0",
+ "ordered-read-streams": "^1.0.0",
+ "pumpify": "^1.3.5",
+ "readable-stream": "^2.1.5",
+ "remove-trailing-separator": "^1.0.1",
+ "to-absolute-glob": "^2.0.0",
+ "unique-stream": "^2.0.2"
+ }
+ },
+ "glob-watcher": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
+ "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-done": "^1.2.0",
+ "chokidar": "^2.0.0",
+ "is-negated-glob": "^1.0.0",
+ "just-debounce": "^1.0.0",
+ "object.defaults": "^1.1.0"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "glogg": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
+ "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
+ "dev": true,
+ "requires": {
+ "sparkles": "^1.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ },
+ "gulp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz",
+ "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=",
+ "dev": true,
+ "requires": {
+ "glob-watcher": "^5.0.0",
+ "gulp-cli": "^2.0.0",
+ "undertaker": "^1.0.0",
+ "vinyl-fs": "^3.0.0"
+ }
+ },
+ "gulp-cli": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.1.0.tgz",
+ "integrity": "sha512-txzgdFVlEPShBZus6JJyGyKJoBVDq6Do0ZQgIgx5RAsmhNVTDjymmOxpQvo3c20m66FldilS68ZXj2Q9w5dKbA==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^1.0.1",
+ "archy": "^1.0.0",
+ "array-sort": "^1.0.0",
+ "color-support": "^1.1.3",
+ "concat-stream": "^1.6.0",
+ "copy-props": "^2.0.1",
+ "fancy-log": "^1.3.2",
+ "gulplog": "^1.0.0",
+ "interpret": "^1.1.0",
+ "isobject": "^3.0.1",
+ "liftoff": "^3.1.0",
+ "matchdep": "^2.0.0",
+ "mute-stdout": "^1.0.0",
+ "pretty-hrtime": "^1.0.0",
+ "replace-homedir": "^1.0.0",
+ "semver-greatest-satisfied-range": "^1.1.0",
+ "v8flags": "^3.0.1",
+ "yargs": "^7.1.0"
+ }
+ },
+ "gulp-concat": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
+ "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=",
+ "dev": true,
+ "requires": {
+ "concat-with-sourcemaps": "^1.0.0",
+ "through2": "^2.0.0",
+ "vinyl": "^2.0.0"
+ }
+ },
+ "gulp-replace": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-0.6.1.tgz",
+ "integrity": "sha1-Eb+Mj85TPjPi9qjy9DC5VboL4GY=",
+ "dev": true,
+ "requires": {
+ "istextorbinary": "1.0.2",
+ "readable-stream": "^2.0.1",
+ "replacestream": "^4.0.0"
+ }
+ },
+ "gulp-sourcemaps": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz",
+ "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==",
+ "dev": true,
+ "requires": {
+ "@gulp-sourcemaps/identity-map": "1.X",
+ "@gulp-sourcemaps/map-sources": "1.X",
+ "acorn": "5.X",
+ "convert-source-map": "1.X",
+ "css": "2.X",
+ "debug-fabulous": "1.X",
+ "detect-newline": "2.X",
+ "graceful-fs": "4.X",
+ "source-map": "~0.6.0",
+ "strip-bom-string": "1.X",
+ "through2": "2.X"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "gulp-uglify": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-2.1.2.tgz",
+ "integrity": "sha1-bbhbHQ7mPRgFhZK2WGSdZcLsRUE=",
+ "dev": true,
+ "requires": {
+ "gulplog": "^1.0.0",
+ "has-gulplog": "^0.1.0",
+ "lodash": "^4.13.1",
+ "make-error-cause": "^1.1.1",
+ "through2": "^2.0.0",
+ "uglify-js": "~2.8.10",
+ "uglify-save-license": "^0.4.1",
+ "vinyl-sourcemaps-apply": "^0.2.0"
+ }
+ },
+ "gulplog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+ "dev": true,
+ "requires": {
+ "glogg": "^1.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-gulplog": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
+ "dev": true,
+ "requires": {
+ "sparkles": "^1.0.0"
+ }
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+ "dev": true
+ },
+ "htmlescape": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=",
+ "dev": true
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "inline-source-map": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+ "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
+ "dev": true,
+ "requires": {
+ "source-map": "~0.5.3"
+ }
+ },
+ "insert-module-globals": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz",
+ "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "acorn-node": "^1.5.2",
+ "combine-source-map": "^0.8.0",
+ "concat-stream": "^1.6.1",
+ "is-buffer": "^1.1.0",
+ "path-is-absolute": "^1.0.1",
+ "process": "~0.11.0",
+ "through2": "^2.0.0",
+ "undeclared-identifiers": "^1.1.2",
+ "xtend": "^4.0.0"
+ }
+ },
+ "interpret": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
+ "dev": true
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+ "dev": true
+ },
+ "ion-rangeslider": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/ion-rangeslider/-/ion-rangeslider-2.2.0.tgz",
+ "integrity": "sha1-OI8SzXBZOmGzNo+tbE8wpdqLl8k=",
+ "dev": true,
+ "requires": {
+ "jquery": ">=1.8"
+ }
+ },
+ "is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "dev": true,
+ "requires": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-negated-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
+ "dev": true
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "dev": true,
+ "requires": {
+ "is-unc-path": "^1.0.0"
+ }
+ },
+ "is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "dev": true,
+ "requires": {
+ "unc-path-regex": "^0.1.2"
+ }
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "is-valid-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+ "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "istextorbinary": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz",
+ "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=",
+ "dev": true,
+ "requires": {
+ "binaryextensions": "~1.0.0",
+ "textextensions": "~1.0.0"
+ }
+ },
+ "jquery": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
+ "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
+ "dev": true
+ },
+ "jquery-mousewheel": {
+ "version": "3.1.13",
+ "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz",
+ "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=",
+ "dev": true
+ },
+ "json-stable-stringify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+ "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+ "dev": true,
+ "requires": {
+ "jsonify": "~0.0.0"
+ }
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "dev": true
+ },
+ "just-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
+ "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ },
+ "labeled-stream-splicer": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz",
+ "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "isarray": "^2.0.4",
+ "stream-splicer": "^2.0.0"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz",
+ "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==",
+ "dev": true
+ }
+ }
+ },
+ "last-run": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
+ "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
+ "dev": true,
+ "requires": {
+ "default-resolution": "^2.0.0",
+ "es6-weak-map": "^2.0.1"
+ }
+ },
+ "lazy-cache": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+ "dev": true
+ },
+ "lazystream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.5"
+ }
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "dev": true,
+ "requires": {
+ "invert-kv": "^1.0.0"
+ }
+ },
+ "lead": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+ "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
+ "dev": true,
+ "requires": {
+ "flush-write-stream": "^1.0.2"
+ }
+ },
+ "leaflet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.4.0.tgz",
+ "integrity": "sha512-x9j9tGY1+PDLN9pcWTx9/y6C5nezoTMB8BLK5jTakx+H7bPlnbCHfi9Hjg+Qt36sgDz/cb9lrSpNQXmk45Tvhw==",
+ "dev": true
+ },
+ "leaflet-providers": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.5.0.tgz",
+ "integrity": "sha512-btncloSyOHrgYNexoz2dRpCl+U9iDQME91RsOWQWNAD9jQUPAkq9mxuTvL/O9VOwrqcEtzhvuHBHIOacJAZDxQ==",
+ "dev": true
+ },
+ "leaflet.markercluster": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.2.0.tgz",
+ "integrity": "sha512-lNUzM7LMsKRzCNPjrzk5x3bADDO2TuEpyDgyGekL4JbOK0Z2HL4rVxQYcVGy/tR29RMDkXuwwE/7QFz5HJcNFg==",
+ "dev": true
+ },
+ "liftoff": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+ "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.0",
+ "findup-sync": "^3.0.0",
+ "fined": "^1.0.1",
+ "flagged-respawn": "^1.0.0",
+ "is-plain-object": "^2.0.4",
+ "object.map": "^1.0.0",
+ "rechoir": "^0.6.2",
+ "resolve": "^1.1.7"
+ }
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "dev": true
+ },
+ "lodash.memoize": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
+ "dev": true
+ },
+ "longest": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+ "dev": true
+ },
+ "lru-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
+ "dev": true,
+ "requires": {
+ "es5-ext": "~0.10.2"
+ }
+ },
+ "make-error": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
+ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
+ "dev": true
+ },
+ "make-error-cause": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
+ "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=",
+ "dev": true,
+ "requires": {
+ "make-error": "^1.2.0"
+ }
+ },
+ "make-iterator": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.2"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "matchdep": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
+ "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
+ "dev": true,
+ "requires": {
+ "findup-sync": "^2.0.0",
+ "micromatch": "^3.0.4",
+ "resolve": "^1.4.0",
+ "stack-trace": "0.0.10"
+ },
+ "dependencies": {
+ "findup-sync": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^3.1.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "memoizee": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz",
+ "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.45",
+ "es6-weak-map": "^2.0.2",
+ "event-emitter": "^0.3.5",
+ "is-promise": "^2.1",
+ "lru-queue": "0.1",
+ "next-tick": "1",
+ "timers-ext": "^0.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ }
+ }
+ },
+ "module-deps": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz",
+ "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "browser-resolve": "^1.7.0",
+ "cached-path-relative": "^1.0.0",
+ "concat-stream": "~1.6.0",
+ "defined": "^1.0.0",
+ "detective": "^5.0.2",
+ "duplexer2": "^0.1.2",
+ "inherits": "^2.0.1",
+ "parents": "^1.0.0",
+ "readable-stream": "^2.0.2",
+ "resolve": "^1.4.0",
+ "stream-combiner2": "^1.1.1",
+ "subarg": "^1.0.0",
+ "through2": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "moment": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "mute-stdout": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+ "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.13.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
+ "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==",
+ "dev": true,
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "nouislider": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-10.1.0.tgz",
+ "integrity": "sha512-lENwxlpoYg4/5gjdaY/PMNHeVL+CMJyrO+7RzXi1MqhSSGwuJsQSJteXCQV5bE2UKEdSLARWrqIF8XSWAq7h+A==",
+ "dev": true
+ },
+ "now-and-later": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz",
+ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.2"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
+ "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==",
+ "dev": true
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ }
+ },
+ "object.defaults": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+ "dev": true,
+ "requires": {
+ "array-each": "^1.0.1",
+ "array-slice": "^1.0.0",
+ "for-own": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+ "dev": true,
+ "requires": {
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "object.reduce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+ "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
+ "dev": true,
+ "requires": {
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "ordered-read-streams": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+ "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "os-locale": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+ "dev": true,
+ "requires": {
+ "lcid": "^1.0.0"
+ }
+ },
+ "pako": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+ "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
+ "dev": true
+ },
+ "parents": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+ "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
+ "dev": true,
+ "requires": {
+ "path-platform": "~0.11.15"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
+ "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==",
+ "dev": true,
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "parse-filepath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+ "dev": true,
+ "requires": {
+ "is-absolute": "^1.0.0",
+ "map-cache": "^0.2.0",
+ "path-root": "^0.1.1"
+ }
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "parse-node-version": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+ "dev": true
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+ "dev": true
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-platform": {
+ "version": "0.11.15",
+ "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+ "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
+ "dev": true
+ },
+ "path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+ "dev": true,
+ "requires": {
+ "path-root-regex": "^0.1.0"
+ }
+ },
+ "path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pbkdf2": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "pretty-hrtime": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
+ "dev": true
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "dev": true
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "dev": true,
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ }
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "read-only-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+ "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.1.6"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "remove-bom-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5",
+ "is-utf8": "^0.2.1"
+ }
+ },
+ "remove-bom-stream": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+ "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
+ "dev": true,
+ "requires": {
+ "remove-bom-buffer": "^3.0.0",
+ "safe-buffer": "^5.1.0",
+ "through2": "^2.0.3"
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "dev": true
+ },
+ "replace-homedir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
+ "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1",
+ "is-absolute": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0"
+ }
+ },
+ "replacestream": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz",
+ "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.3",
+ "object-assign": "^4.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
+ "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-options": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+ "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
+ "dev": true,
+ "requires": {
+ "value-or-function": "^3.0.0"
+ }
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "right-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+ "dev": true,
+ "requires": {
+ "align-text": "^0.1.1"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "select2": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.3.tgz",
+ "integrity": "sha1-IHcz/pHqy5yxoT8SRjQB9HJEng8=",
+ "dev": true,
+ "requires": {
+ "almond": "~0.3.1",
+ "jquery-mousewheel": "~3.1.13"
+ }
+ },
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "dev": true
+ },
+ "semver-greatest-satisfied-range": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+ "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
+ "dev": true,
+ "requires": {
+ "sver-compat": "^1.5.0"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shasum": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+ "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "~0.0.0",
+ "sha.js": "~2.4.4"
+ }
+ },
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "dev": true,
+ "requires": {
+ "array-filter": "~0.0.0",
+ "array-map": "~0.0.0",
+ "array-reduce": "~0.0.0",
+ "jsonify": "~0.0.0"
+ }
+ },
+ "simple-concat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
+ "dev": true
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "sparkles": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+ "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz",
+ "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==",
+ "dev": true
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+ "dev": true
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-combiner2": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+ "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+ "dev": true,
+ "requires": {
+ "duplexer2": "~0.1.0",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-exhaust": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+ "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+ "dev": true
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
+ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
+ "dev": true
+ },
+ "stream-splicer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
+ "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
+ "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true
+ },
+ "subarg": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.1.0"
+ }
+ },
+ "sver-compat": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+ "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "^2.0.1",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "syntax-error": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
+ "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.2.0"
+ }
+ },
+ "textextensions": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz",
+ "integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "through2-filter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+ "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+ "dev": true,
+ "requires": {
+ "through2": "~2.0.0",
+ "xtend": "~4.0.0"
+ }
+ },
+ "time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
+ "dev": true
+ },
+ "timers-browserify": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+ "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
+ "dev": true,
+ "requires": {
+ "process": "~0.11.0"
+ }
+ },
+ "timers-ext": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+ "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+ "dev": true,
+ "requires": {
+ "es5-ext": "~0.10.46",
+ "next-tick": "1"
+ }
+ },
+ "to-absolute-glob": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
+ "dev": true,
+ "requires": {
+ "is-absolute": "^1.0.0",
+ "is-negated-glob": "^1.0.0"
+ }
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "to-through": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
+ "dev": true,
+ "requires": {
+ "through2": "^2.0.3"
+ }
+ },
+ "tsconfig": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz",
+ "integrity": "sha1-X0J45wGACWeo/Dg/0ZZIh48qbjo=",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.3.0",
+ "parse-json": "^2.2.0",
+ "strip-bom": "^2.0.0",
+ "strip-json-comments": "^2.0.0"
+ }
+ },
+ "tsify": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/tsify/-/tsify-3.0.4.tgz",
+ "integrity": "sha512-y75+qgB41YS8HJck+jmSIn395I4qRGtm5ZELzvNh80Llzh8ojPWp47jm0ZoIJesNYVzbqEyLzgYXV9d/calvVg==",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "^1.1.0",
+ "fs.realpath": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "semver": "^5.1.0",
+ "through2": "^2.0.0",
+ "tsconfig": "^5.0.3"
+ }
+ },
+ "tty-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
+ "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "typescript": {
+ "version": "3.3.4000",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.4000.tgz",
+ "integrity": "sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "2.8.29",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+ "dev": true,
+ "requires": {
+ "source-map": "~0.5.1",
+ "uglify-to-browserify": "~1.0.0",
+ "yargs": "~3.10.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "dev": true,
+ "requires": {
+ "center-align": "^0.1.1",
+ "right-align": "^0.1.1",
+ "wordwrap": "0.0.2"
+ }
+ },
+ "yargs": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^1.0.2",
+ "cliui": "^2.1.0",
+ "decamelize": "^1.0.0",
+ "window-size": "0.1.0"
+ }
+ }
+ }
+ },
+ "uglify-save-license": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz",
+ "integrity": "sha1-lXJsF8xv0XHDYX479NjYKqjEzOE=",
+ "dev": true
+ },
+ "uglify-to-browserify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+ "dev": true,
+ "optional": true
+ },
+ "umd": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz",
+ "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
+ "dev": true
+ },
+ "unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+ "dev": true
+ },
+ "undeclared-identifiers": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz",
+ "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.3.0",
+ "dash-ast": "^1.0.0",
+ "get-assigned-identifiers": "^1.2.0",
+ "simple-concat": "^1.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "undertaker": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz",
+ "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1",
+ "arr-map": "^2.0.0",
+ "bach": "^1.0.0",
+ "collection-map": "^1.0.0",
+ "es6-weak-map": "^2.0.1",
+ "last-run": "^1.1.0",
+ "object.defaults": "^1.0.0",
+ "object.reduce": "^1.0.0",
+ "undertaker-registry": "^1.0.0"
+ }
+ },
+ "undertaker-registry": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
+ "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=",
+ "dev": true
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "unique-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+ "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "through2-filter": "^3.0.0"
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
+ "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
+ "dev": true
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "v8flags": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz",
+ "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "value-or-function": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+ "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
+ "dev": true
+ },
+ "vinyl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
+ "dev": true,
+ "requires": {
+ "clone": "^2.1.1",
+ "clone-buffer": "^1.0.0",
+ "clone-stats": "^1.0.0",
+ "cloneable-readable": "^1.0.0",
+ "remove-trailing-separator": "^1.0.1",
+ "replace-ext": "^1.0.0"
+ }
+ },
+ "vinyl-buffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz",
+ "integrity": "sha1-lsGjR5uMU5JULGEgKQE7Wyf4i78=",
+ "dev": true,
+ "requires": {
+ "bl": "^1.2.1",
+ "through2": "^2.0.3"
+ }
+ },
+ "vinyl-fs": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+ "dev": true,
+ "requires": {
+ "fs-mkdirp-stream": "^1.0.0",
+ "glob-stream": "^6.1.0",
+ "graceful-fs": "^4.0.0",
+ "is-valid-glob": "^1.0.0",
+ "lazystream": "^1.0.0",
+ "lead": "^1.0.0",
+ "object.assign": "^4.0.4",
+ "pumpify": "^1.3.5",
+ "readable-stream": "^2.3.3",
+ "remove-bom-buffer": "^3.0.0",
+ "remove-bom-stream": "^1.2.0",
+ "resolve-options": "^1.1.0",
+ "through2": "^2.0.0",
+ "to-through": "^2.0.0",
+ "value-or-function": "^3.0.0",
+ "vinyl": "^2.0.0",
+ "vinyl-sourcemap": "^1.1.0"
+ }
+ },
+ "vinyl-source-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz",
+ "integrity": "sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=",
+ "dev": true,
+ "requires": {
+ "through2": "^2.0.3",
+ "vinyl": "^2.1.0"
+ }
+ },
+ "vinyl-sourcemap": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
+ "dev": true,
+ "requires": {
+ "append-buffer": "^1.0.2",
+ "convert-source-map": "^1.5.0",
+ "graceful-fs": "^4.1.6",
+ "normalize-path": "^2.1.1",
+ "now-and-later": "^2.0.0",
+ "remove-bom-buffer": "^3.0.0",
+ "vinyl": "^2.0.0"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ }
+ }
+ },
+ "vinyl-sourcemaps-apply": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+ "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.5.1"
+ }
+ },
+ "vm-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz",
+ "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+ "dev": true
+ },
+ "window-size": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+ "dev": true
+ },
+ "y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+ "dev": true
+ },
+ "yargs": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
+ "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^3.0.0",
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^1.4.0",
+ "read-pkg-up": "^1.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^1.0.2",
+ "which-module": "^1.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^5.0.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
+ "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^3.0.0"
+ }
+ }
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/package.json b/www/wiki/extensions/SemanticResultFormats/formats/filtered/package.json
new file mode 100644
index 00000000..052ac757
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "filtered",
+ "version": "2.0.0",
+ "description": "Displays SMW query results in switchable views and offers client-side (JavaScript based) filtering",
+ "main": "ext.srf.filtered.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "postinstall": "gulp"
+ },
+ "author": "Stephan Gambke",
+ "license": "GPL-2.0-or-later",
+ "dependencies": {},
+ "devDependencies": {
+ "@types/fullcalendar": "2.7.42",
+ "@types/ion.rangeslider": "^2.0.29",
+ "@types/jquery": "^2.0.51",
+ "@types/jqueryui": "^1.12.5",
+ "@types/leaflet": "~1.0.60",
+ "@types/leaflet-providers": "^1.1.0",
+ "@types/leaflet.markercluster": "1.0.0",
+ "@types/qunit": "^1.16.31",
+ "@types/select2": "^4.0.47",
+ "browserify": "^16.2.3",
+ "gulp": "^4.0.0",
+ "gulp-cli": "^2.0.1",
+ "gulp-concat": "^2.6.1",
+ "gulp-replace": "^0.6.1",
+ "gulp-sourcemaps": "^2.4.1",
+ "gulp-uglify": "^2.1.2",
+ "ion-rangeslider": "^2.2.0",
+ "leaflet": "^1.3.4",
+ "leaflet-providers": "^1.4.0",
+ "leaflet.markercluster": "~1.2",
+ "nouislider": "^10.1.0",
+ "select2": "4.0.3",
+ "tsify": "^3.0.1",
+ "typescript": "^3.1.3",
+ "vinyl-buffer": "^1.0.0",
+ "vinyl-source-stream": "^2.0.0"
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.calendar-view.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.calendar-view.less
new file mode 100644
index 00000000..f011aa92
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.calendar-view.less
@@ -0,0 +1,10 @@
+/*
+ Stylesheet for the calendar view
+*/
+
+a.fc-event-hori, .fc-event-hori a {
+ color: #ffffff;
+ font-weight: bold;
+ padding: 0 2px;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.distance-filter.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.distance-filter.less
new file mode 100644
index 00000000..b497d70c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.distance-filter.less
@@ -0,0 +1,50 @@
+/*
+ Stylesheet for the value filter
+*/
+.filtered-filters .filtered-distance {
+
+ overflow: visible;
+ border: 1px solid #aaaaaa;
+ padding: 1em 1em 0.5em;
+ margin: 1em;
+
+ .ui-slider-handle {
+ outline: none;
+ text-decoration: none;
+ width: 0;
+ padding: 0 0.6em;
+ }
+
+ .filtered-distance-readout {
+ margin: 0;
+ text-align: center;
+ position: relative;
+ top: 1em;
+ left: -50px;
+ width: 100px;
+ color: #000000;
+ }
+
+ .filtered-distance-table {
+ border-collapse: collapse;
+ }
+
+ .filtered-distance-slider-cell {
+ width: 100%;
+ height: 2.2em;
+ }
+
+ .filtered-distance-slider {
+ border: 1px solid #aaaaaa;
+ border-radius: 3px;
+ background: #f1f2ff;
+ margin: 0 1em;
+ }
+
+ .filtered-distance-unit-cell {
+ height: 2.2em;
+ text-align: center;
+ vertical-align: bottom;
+ }
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.leaflet.css b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.leaflet.css
new file mode 100644
index 00000000..99786d4c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.leaflet.css
@@ -0,0 +1,711 @@
+/* required styles */
+
+.leaflet-pane,
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow,
+.leaflet-tile-container,
+.leaflet-pane > svg,
+.leaflet-pane > canvas,
+.leaflet-zoom-box,
+.leaflet-image-layer,
+.leaflet-layer {
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+.leaflet-container {
+ overflow: hidden;
+ }
+.leaflet-tile,
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ -webkit-user-drag: none;
+ }
+/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
+.leaflet-safari .leaflet-tile {
+ image-rendering: -webkit-optimize-contrast;
+ }
+/* hack that prevents hw layers "stretching" when loading new tiles */
+.leaflet-safari .leaflet-tile-container {
+ width: 1600px;
+ height: 1600px;
+ -webkit-transform-origin: 0 0;
+ }
+.leaflet-marker-icon,
+.leaflet-marker-shadow {
+ display: block;
+ }
+/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
+/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
+.leaflet-container .leaflet-overlay-pane svg,
+.leaflet-container .leaflet-marker-pane img,
+.leaflet-container .leaflet-shadow-pane img,
+.leaflet-container .leaflet-tile-pane img,
+.leaflet-container img.leaflet-image-layer,
+.leaflet-container .leaflet-tile {
+ max-width: none !important;
+ max-height: none !important;
+ }
+
+.leaflet-container.leaflet-touch-zoom {
+ -ms-touch-action: pan-x pan-y;
+ touch-action: pan-x pan-y;
+ }
+.leaflet-container.leaflet-touch-drag {
+ -ms-touch-action: pinch-zoom;
+ /* Fallback for FF which doesn't support pinch-zoom */
+ touch-action: none;
+ touch-action: pinch-zoom;
+}
+.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
+ -ms-touch-action: none;
+ touch-action: none;
+}
+.leaflet-container {
+ -webkit-tap-highlight-color: transparent;
+}
+.leaflet-container a {
+ -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
+}
+.leaflet-tile {
+ filter: inherit;
+ visibility: hidden;
+ }
+.leaflet-tile-loaded {
+ visibility: inherit;
+ }
+.leaflet-zoom-box {
+ width: 0;
+ height: 0;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ z-index: 800;
+ }
+/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
+.leaflet-overlay-pane svg {
+ -moz-user-select: none;
+ }
+
+.leaflet-pane { z-index: 400; }
+
+.leaflet-tile-pane { z-index: 200; }
+.leaflet-overlay-pane { z-index: 400; }
+.leaflet-shadow-pane { z-index: 500; }
+.leaflet-marker-pane { z-index: 600; }
+.leaflet-tooltip-pane { z-index: 650; }
+.leaflet-popup-pane { z-index: 700; }
+
+.leaflet-map-pane canvas { z-index: 100; }
+.leaflet-map-pane svg { z-index: 200; }
+
+.leaflet-vml-shape {
+ width: 1px;
+ height: 1px;
+ }
+.lvml {
+ behavior: url(#default#VML);
+ display: inline-block;
+ position: absolute;
+ }
+
+
+/* control positioning */
+
+.leaflet-control {
+ position: relative;
+ z-index: 800;
+ pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
+ pointer-events: auto;
+ }
+.leaflet-top,
+.leaflet-bottom {
+ position: absolute;
+ z-index: 1000;
+ pointer-events: none;
+ }
+.leaflet-top {
+ top: 0;
+ }
+.leaflet-right {
+ right: 0;
+ }
+.leaflet-bottom {
+ bottom: 0;
+ }
+.leaflet-left {
+ left: 0;
+ }
+.leaflet-control {
+ float: left;
+ clear: both;
+ }
+.leaflet-right .leaflet-control {
+ float: right;
+ }
+.leaflet-top .leaflet-control {
+ margin-top: 10px;
+ }
+.leaflet-bottom .leaflet-control {
+ margin-bottom: 10px;
+ }
+.leaflet-left .leaflet-control {
+ margin-left: 10px;
+ }
+.leaflet-right .leaflet-control {
+ margin-right: 10px;
+ }
+
+
+/* zoom and fade animations */
+
+.leaflet-fade-anim .leaflet-tile {
+ will-change: opacity;
+ }
+.leaflet-fade-anim .leaflet-popup {
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+ }
+.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
+ opacity: 1;
+ }
+.leaflet-zoom-animated {
+ -webkit-transform-origin: 0 0;
+ -ms-transform-origin: 0 0;
+ transform-origin: 0 0;
+ }
+.leaflet-zoom-anim .leaflet-zoom-animated {
+ will-change: transform;
+ }
+.leaflet-zoom-anim .leaflet-zoom-animated {
+ -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
+ -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
+ transition: transform 0.25s cubic-bezier(0,0,0.25,1);
+ }
+.leaflet-zoom-anim .leaflet-tile,
+.leaflet-pan-anim .leaflet-tile {
+ -webkit-transition: none;
+ -moz-transition: none;
+ transition: none;
+ }
+
+.leaflet-zoom-anim .leaflet-zoom-hide {
+ visibility: hidden;
+ }
+
+
+/* cursors */
+
+.leaflet-interactive {
+ cursor: pointer;
+ }
+.leaflet-grab {
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
+ cursor: grab;
+ }
+.leaflet-crosshair,
+.leaflet-crosshair .leaflet-interactive {
+ cursor: crosshair;
+ }
+.leaflet-popup-pane,
+.leaflet-control {
+ cursor: auto;
+ }
+.leaflet-dragging .leaflet-grab,
+.leaflet-dragging .leaflet-grab .leaflet-interactive,
+.leaflet-dragging .leaflet-marker-draggable {
+ cursor: move;
+ cursor: -webkit-grabbing;
+ cursor: -moz-grabbing;
+ cursor: grabbing;
+ }
+
+/* marker & overlays interactivity */
+.leaflet-marker-icon,
+.leaflet-marker-shadow,
+.leaflet-image-layer,
+.leaflet-pane > svg path,
+.leaflet-tile-container {
+ pointer-events: none;
+ }
+
+.leaflet-marker-icon.leaflet-interactive,
+.leaflet-image-layer.leaflet-interactive,
+.leaflet-pane > svg path.leaflet-interactive {
+ pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
+ pointer-events: auto;
+ }
+
+/* visual tweaks */
+
+.leaflet-container {
+ background: #ddd;
+ outline: 0;
+ }
+.leaflet-container a {
+ color: #0078A8;
+ }
+.leaflet-container a.leaflet-active {
+ outline: 2px solid orange;
+ }
+.leaflet-zoom-box {
+ border: 2px dotted #38f;
+ background: rgba(255,255,255,0.5);
+ }
+
+
+/* general typography */
+.leaflet-container {
+ font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
+ }
+
+
+/* general toolbar styles */
+
+.leaflet-bar {
+ box-shadow: 0 1px 5px rgba(0,0,0,0.65);
+ border-radius: 4px;
+ }
+.leaflet-bar a,
+.leaflet-bar a:hover {
+ background-color: #fff;
+ border-bottom: 1px solid #ccc;
+ width: 26px;
+ height: 26px;
+ line-height: 26px;
+ display: block;
+ text-align: center;
+ text-decoration: none;
+ color: black;
+ }
+.leaflet-bar a,
+.leaflet-control-layers-toggle {
+ background-position: 50% 50%;
+ background-repeat: no-repeat;
+ display: block;
+ }
+.leaflet-bar a:hover {
+ background-color: #f4f4f4;
+ }
+.leaflet-bar a:first-child {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ }
+.leaflet-bar a:last-child {
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ border-bottom: none;
+ }
+.leaflet-bar a.leaflet-disabled {
+ cursor: default;
+ background-color: #f4f4f4;
+ color: #bbb;
+ }
+
+.leaflet-touch .leaflet-bar a {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+ }
+.leaflet-touch .leaflet-bar a:first-child {
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+ }
+.leaflet-touch .leaflet-bar a:last-child {
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+ }
+
+/* zoom control */
+
+.leaflet-control-zoom-in,
+.leaflet-control-zoom-out {
+ font: bold 18px 'Lucida Console', Monaco, monospace;
+ text-indent: 1px;
+ }
+
+.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
+ font-size: 22px;
+ }
+
+
+/* layers control */
+
+.leaflet-control-layers {
+ box-shadow: 0 1px 5px rgba(0,0,0,0.4);
+ background: #fff;
+ border-radius: 5px;
+ }
+.leaflet-control-layers-toggle {
+ background-image: url(images/layers.png);
+ width: 36px;
+ height: 36px;
+ }
+.leaflet-retina .leaflet-control-layers-toggle {
+ background-image: url(images/layers-2x.png);
+ background-size: 26px 26px;
+ }
+.leaflet-touch .leaflet-control-layers-toggle {
+ width: 44px;
+ height: 44px;
+ }
+.leaflet-control-layers .leaflet-control-layers-list,
+.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
+ display: none;
+ }
+.leaflet-control-layers-expanded .leaflet-control-layers-list {
+ display: block;
+ position: relative;
+ }
+.leaflet-control-layers-expanded {
+ padding: 6px 10px 6px 6px;
+ color: #333;
+ background: #fff;
+ }
+.leaflet-control-layers-scrollbar {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ padding-right: 5px;
+ }
+.leaflet-control-layers-selector {
+ margin-top: 2px;
+ position: relative;
+ top: 1px;
+ }
+.leaflet-control-layers label {
+ display: block;
+ }
+.leaflet-control-layers-separator {
+ height: 0;
+ border-top: 1px solid #ddd;
+ margin: 5px -10px 5px -6px;
+ }
+
+/* Default icon URLs */
+.leaflet-default-icon-path {
+ background-image: url(images/marker-icon.png);
+ }
+
+
+/* attribution and scale controls */
+
+.leaflet-container .leaflet-control-attribution {
+ background: #fff;
+ background: rgba(255, 255, 255, 0.7);
+ margin: 0;
+ }
+.leaflet-control-attribution,
+.leaflet-control-scale-line {
+ padding: 0 5px;
+ color: #333;
+ }
+.leaflet-control-attribution a {
+ text-decoration: none;
+ }
+.leaflet-control-attribution a:hover {
+ text-decoration: underline;
+ }
+.leaflet-container .leaflet-control-attribution,
+.leaflet-container .leaflet-control-scale {
+ font-size: 11px;
+ }
+.leaflet-left .leaflet-control-scale {
+ margin-left: 5px;
+ }
+.leaflet-bottom .leaflet-control-scale {
+ margin-bottom: 5px;
+ }
+.leaflet-control-scale-line {
+ border: 2px solid #777;
+ border-top: none;
+ line-height: 1.1;
+ padding: 2px 5px 1px;
+ font-size: 11px;
+ white-space: nowrap;
+ overflow: hidden;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+
+ background: #fff;
+ background: rgba(255, 255, 255, 0.5);
+ }
+.leaflet-control-scale-line:not(:first-child) {
+ border-top: 2px solid #777;
+ border-bottom: none;
+ margin-top: -2px;
+ }
+.leaflet-control-scale-line:not(:first-child):not(:last-child) {
+ border-bottom: 2px solid #777;
+ }
+
+.leaflet-touch .leaflet-control-attribution,
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+ box-shadow: none;
+ }
+.leaflet-touch .leaflet-control-layers,
+.leaflet-touch .leaflet-bar {
+ border: 2px solid rgba(0,0,0,0.2);
+ background-clip: padding-box;
+ }
+
+
+/* popup */
+
+.leaflet-popup {
+ position: absolute;
+ text-align: center;
+ margin-bottom: 20px;
+ }
+.leaflet-popup-content-wrapper {
+ padding: 1px;
+ text-align: left;
+ border-radius: 12px;
+ }
+.leaflet-popup-content {
+ margin: 13px 19px;
+ line-height: 1.4;
+ }
+.leaflet-popup-content p {
+ margin: 18px 0;
+ }
+.leaflet-popup-tip-container {
+ width: 40px;
+ height: 20px;
+ position: absolute;
+ left: 50%;
+ margin-left: -20px;
+ overflow: hidden;
+ pointer-events: none;
+ }
+.leaflet-popup-tip {
+ width: 17px;
+ height: 17px;
+ padding: 1px;
+
+ margin: -10px auto 0;
+
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+ }
+.leaflet-popup-content-wrapper,
+.leaflet-popup-tip {
+ background: white;
+ color: #333;
+ box-shadow: 0 3px 14px rgba(0,0,0,0.4);
+ }
+.leaflet-container a.leaflet-popup-close-button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 4px 4px 0 0;
+ border: none;
+ text-align: center;
+ width: 18px;
+ height: 14px;
+ font: 16px/14px Tahoma, Verdana, sans-serif;
+ color: #c3c3c3;
+ text-decoration: none;
+ font-weight: bold;
+ background: transparent;
+ }
+.leaflet-container a.leaflet-popup-close-button:hover {
+ color: #999;
+ }
+.leaflet-popup-scrolled {
+ overflow: auto;
+ border-bottom: 1px solid #ddd;
+ border-top: 1px solid #ddd;
+ }
+
+.leaflet-oldie .leaflet-popup-content-wrapper {
+ zoom: 1;
+ }
+.leaflet-oldie .leaflet-popup-tip {
+ width: 24px;
+ margin: 0 auto;
+
+ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
+ filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
+ }
+.leaflet-oldie .leaflet-popup-tip-container {
+ margin-top: -1px;
+ }
+
+.leaflet-oldie .leaflet-control-zoom,
+.leaflet-oldie .leaflet-control-layers,
+.leaflet-oldie .leaflet-popup-content-wrapper,
+.leaflet-oldie .leaflet-popup-tip {
+ border: 1px solid #999;
+ }
+
+
+/* div icon */
+
+.leaflet-div-icon {
+ background: #fff;
+ border: 1px solid #666;
+ }
+
+
+/* Tooltip */
+/* Base styles for the element that has a tooltip */
+.leaflet-tooltip {
+ position: absolute;
+ padding: 6px;
+ background-color: #fff;
+ border: 1px solid #fff;
+ border-radius: 3px;
+ color: #222;
+ white-space: nowrap;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ pointer-events: none;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.4);
+ }
+.leaflet-tooltip.leaflet-clickable {
+ cursor: pointer;
+ pointer-events: auto;
+ }
+.leaflet-tooltip-top:before,
+.leaflet-tooltip-bottom:before,
+.leaflet-tooltip-left:before,
+.leaflet-tooltip-right:before {
+ position: absolute;
+ pointer-events: none;
+ border: 6px solid transparent;
+ background: transparent;
+ content: "";
+ }
+
+/* Directions */
+
+.leaflet-tooltip-bottom {
+ margin-top: 6px;
+}
+.leaflet-tooltip-top {
+ margin-top: -6px;
+}
+.leaflet-tooltip-bottom:before,
+.leaflet-tooltip-top:before {
+ left: 50%;
+ margin-left: -6px;
+ }
+.leaflet-tooltip-top:before {
+ bottom: 0;
+ margin-bottom: -12px;
+ border-top-color: #fff;
+ }
+.leaflet-tooltip-bottom:before {
+ top: 0;
+ margin-top: -12px;
+ margin-left: -6px;
+ border-bottom-color: #fff;
+ }
+.leaflet-tooltip-left {
+ margin-left: -6px;
+}
+.leaflet-tooltip-right {
+ margin-left: 6px;
+}
+.leaflet-tooltip-left:before,
+.leaflet-tooltip-right:before {
+ top: 50%;
+ margin-top: -6px;
+ }
+.leaflet-tooltip-left:before {
+ right: 0;
+ margin-right: -12px;
+ border-left-color: #fff;
+ }
+.leaflet-tooltip-right:before {
+ left: 0;
+ margin-left: -12px;
+ border-right-color: #fff;
+ }
+
+.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
+ -webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
+ -moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
+ -o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
+ transition: transform 0.3s ease-out, opacity 0.3s ease-in;
+}
+
+.leaflet-cluster-spider-leg {
+ /* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
+ -webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
+ -moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
+ -o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
+ transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
+}
+
+.marker-cluster-small {
+ background-color: rgba(181, 226, 140, 0.6);
+ }
+.marker-cluster-small div {
+ background-color: rgba(110, 204, 57, 0.6);
+ }
+
+.marker-cluster-medium {
+ background-color: rgba(241, 211, 87, 0.6);
+ }
+.marker-cluster-medium div {
+ background-color: rgba(240, 194, 12, 0.6);
+ }
+
+.marker-cluster-large {
+ background-color: rgba(253, 156, 115, 0.6);
+ }
+.marker-cluster-large div {
+ background-color: rgba(241, 128, 23, 0.6);
+ }
+
+ /* IE 6-8 fallback colors */
+.leaflet-oldie .marker-cluster-small {
+ background-color: rgb(181, 226, 140);
+ }
+.leaflet-oldie .marker-cluster-small div {
+ background-color: rgb(110, 204, 57);
+ }
+
+.leaflet-oldie .marker-cluster-medium {
+ background-color: rgb(241, 211, 87);
+ }
+.leaflet-oldie .marker-cluster-medium div {
+ background-color: rgb(240, 194, 12);
+ }
+
+.leaflet-oldie .marker-cluster-large {
+ background-color: rgb(253, 156, 115);
+ }
+.leaflet-oldie .marker-cluster-large div {
+ background-color: rgb(241, 128, 23);
+}
+
+.marker-cluster {
+ background-clip: padding-box;
+ border-radius: 20px;
+ }
+.marker-cluster div {
+ width: 30px;
+ height: 30px;
+ margin-left: 5px;
+ margin-top: 5px;
+
+ text-align: center;
+ border-radius: 15px;
+ font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
+ }
+.marker-cluster span {
+ line-height: 30px;
+ } \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.less
new file mode 100644
index 00000000..f08e09bf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.less
@@ -0,0 +1,166 @@
+/*
+ Main stylesheet for the filtered query printer
+*/
+.filtered {
+
+ height: 100%;
+ position: relative;
+
+ .filtered-filters {
+
+ height: 40%;
+ overflow: hidden;
+ border: 1px solid #aaaaaa;
+ margin: 1em;
+ position: relative;
+ top: 0;
+ left: 0;
+
+ &:empty {
+ display: none;
+ }
+
+ .filtered-filter {
+ position: relative;
+
+ .filtered-filter-label {
+
+ height: 1em;
+ position: absolute;
+ top: -.7em;
+ background: #ffffff;
+ padding: 0 1em;
+ font-weight: bold;
+
+ }
+
+ .filtered-filter-onoff {
+ position: absolute;
+ top: -9px;
+ left: -9px;
+ width: 0;
+ height: 0;
+
+ &::before {
+ background: #ffffff;
+ width: 18px;
+ height: 18px;
+ display: inline-block;
+ text-align: center;
+ cursor: pointer;
+ }
+
+ }
+
+ &.enabled {
+ .filtered-filter-onoff::before {
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABaAAAAWgBwI7h9AAAAB3RJTUUH4QoWDTUvLzYe2QAABG9JREFUSMddlW1sFUUUhp+Z2bv3lrbcFpBSigElgilBQaJ8GIwkFwWNQJUIMdEI+EWDghFECUSIGmokGogYCEUTYjAUQRATiGkkoAbiD6lRMYRIEFO+bIu05dK9uzvjj7O0XObPuzvzzjnvnHNmjspNb9qdm04GGT0J/obFYXWGGE1s6/CweHyXrA8V+HWHYOaA4OjdKFIoaglpJ6QSjzI8vQmNh7Z3olAoKnFYHCUai8bSgwUsWzEYjG7Fx8e3d5HGkn6oEXDQOBOIIO3EoV6VCHoJg8VkPwFC2PE8hv6YaQPxifHtBDxiPL0TiIFvhM91jQEMa4HroDbgU4HvzhEREH28lxiIj0wEFNQ5HD6OjsTx+AS7CNGE6goOcLPvQwHq+/2E+ISbv6IMnzLVwmUKXGYIFg/Ldk1ED5FaJhvdafK0k9/2GQ6FW1Yn9lsXCNZPxRBjgoHy7/0umBpJPwz9/lsj+xb+KPPnynE4XP1TdBDS8XkDAf0IeIB2oF1d00AaXAWKDOqZlRLqRcfEwOlVaCz6wS9QaNSuzVgUNjk3blTyMZeAiACIMER71hJgCCafEkEnZwnt2QEMJWLognVUElPpXtNc4CoX9EcoHGrFoRumiVBEL9xOhEf0d4TFYv1/KBpuTIIjxRHgEeGlnOT+fI2sL4r6tqBwywfTRZYuf5ammizVExskx+NahNW8hjSa9NF6KR6TRKTgFQtQZxI83zuVxZINB4kjb7bYPX5QFr/dLwetfYUyOimbckGjidBjG4sNH36ZmJgYJOTqPSkqomLetUUJ9k11ouikCo1Dk0FhUb1223p5Goe+V2nJbTYoNtwx5pZQN8pJmFQ8/+hUwYeX9wUFgyKJjHvjptCDa5/f+x+jiLPzPPloezxRnIzqwi2hHkFEFxEOxxAcNB95+rHmIx0VNxi5GU27cjOAbhzdODJARk26SRio6mM36HI72lTisqWl2OH0N9GEaJAHw57CMhjL/RQopQC5XFNTLqdGJziePJY8GoOPoUpy7V5NXtBkPNInSKPQvwzUlHCGkhNTROMPnbI6eR0WHzv7IjGG2I7A5xq+/wQZ/iWjSzCEGPc6BoVxL+Kj8dUVUhRI+fNwGFy8UW7RzHFid1qZ4M9fs4W9bDl+SNPDiKQDOFi/pzgS237CoDETPsDh4QpvoQHtTtCfUvqzhDQeaZYk1/APedILH0ovuWcdYGH7qF6TClDrP2UxdSzmSy0O9FE5ycGFwnq/VgTd9qTchsO1KCLU6uHEOOJhZwlpJTT10ivMMOHXLJaUrTwjNXX0YlJTu6TYN5Ti0Lh9zSJFb/Row9BmF1CFpUrPkWa0eh8BMcHl45LLhpOy4d2zeDi8d+bQzSC6Ww0Qg3tbulzN3VLtqTvEcXBJUrFiKVe5xNUNeUrJUqprKCdLud3pMYCAAfxFhCOyYwlJEZrnRPGmyVJEh+ZL1S4tEcOzWkXQ8PIksCmB85uFd6BBhG8sIyYi/nMTWSrImrlAGuJK8gTk2fY/1Ja2dn2c6dIAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMTAtMjJUMTM6NTM6NDctMDc6MDCZnZ5EAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTEwLTIyVDEzOjUzOjQ3LTA3OjAw6MAm+AAAACZ0RVh0c3ZnOmJhc2UtdXJpAGZpbGU6Ly8vdG1wL1NWRzVLV080Mi5zdmfPk46jAAAAAElFTkSuQmCC);
+ }
+ }
+
+ &.disabled {
+ .filtered-filter-onoff::before {
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAQAAADlauupAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAAAFoAAABaAHAjuH0AAAAHdElNRQfhChYOBDf4QT9kAAAC7ElEQVQ4yy3QW4jVdRTF8c/vdy4z46ijjWheAknSUCxtKtMwlLKS8oaGVgTa1LGkJiOzsASFHnyQQtOHcrSQCMosL0UiZTRFIz3UVFKJYGTNaGDjJca5nv+vh+PTXnux+O7FDqWVqgU9kl8UY7XqbIkeRzGGn/ZSfZhJ+zBZZrgYt4vZ9RiOmqioR5W35GK7i9kNuu9qlprnU5WIG1CS6nawd6Xc3Hr9WYO++L6yQwZ0Rz02qQtbHUtn1L3xsfD1DGFJEnRiOv4TwwUW3SIdO6i48yODQpuia0W7oxjW+iedMm/XHmHtEtpXSWtm01tP/gSFCXovbhQe/5YzQ6Q1S/W9swW3y4euqJCGyT/yEo2tnNpg4M73+GCnBGkiliki7d8kzDzJrwt57Br9qzbrT01RfXxd7sUjID5xnfyfAxT/AtIU0gQQComOsTQOVPZ1Iw0tLow6Z2yRprXxxUb5ljVyuVapL18BhNOEDnClf4SUX8Txz/n0oDT5KZdnnY3S1OZK+KvV+lAOr4kqV3Q10lWRNUah+mr2fIV/c4hCXW/F7JxytXazzB0Vfd9s5qwDZadJL1T8f1dUZt3yvHj+ARnC6L7K48J4QyWXeHt35zAoNaJKMhAq4DC6VXKPdD5Eqa0NZPPWG4mq7KSzbhMplcKkUilM1yPqNEo+PasW2b1XQT/UR3U/zpK+uSzM3OzsonOuZOMNLi4g1gjped3pSbXhgrricll5myvzpwlzB/P9J+mV40dyDVOQzk0UHp0u3n1UONYg/f0yTqj1oOAzKSyQlRtlN20W9mUMeYhnmkLL74dyDbfGFuHUYqnwoXD/DuHhC0LuO/6YLXUN83PsMGrMl+LTrcKeo4x4V9paK//mSTFuC6UmE1yKU8kOqGpqZUsLNesZWEx7TkrzhLE3UphD71Lp1XEGbd2uL47Vk40LpdVIFgu5ofLlvQYmrpA9d0BY2M64ISgIHTulw4eVtw1W+G0/uWW6y8Ox63+sdBL0yUwzIgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0xMC0yMlQxNDowNDo1NS0wNzowMCxQPpAAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMTAtMjJUMTQ6MDQ6NTUtMDc6MDBdDYYsAAAAJnRFWHRzdmc6YmFzZS11cmkAZmlsZTovLy90bXAvU1ZHWnhtWk45LnN2ZwRBziMAAAAASUVORK5CYII=);
+ }
+
+ .filtered-filter-collapse {
+ display: none;
+ }
+ }
+
+ .filtered-filter-collapse:before {
+ margin: 0;
+ background-color: #ffffff;
+ width: 1.5em;
+ float: right;
+ position: absolute;
+ top: -0.8em;
+ right: 1em;
+ text-align: center;
+ cursor: pointer;
+ }
+
+ .filtered-filter-collapse.collapsed:before {
+ content: '[+]';
+ }
+
+ .filtered-filter-collapse.uncollapsed:before {
+ content: '[-]';
+ }
+ }
+
+ .filtered-filter-spinner {
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: #ffffff;
+ height: 100%;
+ width: 100%;
+ z-index: 1001;
+ opacity: .7;
+ }
+
+ }
+
+ .filtered-views {
+
+ height: 60%;
+ overflow: auto;
+ border: 1px solid #aaaaaa;
+ margin: 1em;
+
+ .filtered-views-selectors-container {
+
+ border-bottom: 1px solid #aaaaaa;
+ overflow: hidden;
+
+ &:empty {
+ display: none;
+ }
+
+ .filtered-view-selector {
+
+ border-right: 1px solid #aaaaaa;
+ padding: 1em;
+ float: left;
+ cursor: pointer;
+
+ &.selected {
+ background-color: #f3f3f3;
+ }
+
+ &.active {
+ background-color: #f0f7ff;
+ }
+ }
+ }
+
+ .filtered-views-container {
+
+ padding: 1em;
+
+ &:empty {
+ display: none;
+ }
+
+ .filtered-view {
+ &.active {
+ display: block;
+ }
+
+ &.inactive {
+ display: none;
+ }
+ }
+ }
+ }
+
+ .filtered-spinner {
+ height: 100px;
+ width: auto;
+ position: relative;
+ top: 0;
+ left: 0;
+ margin: 1em;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.map-view.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.map-view.less
new file mode 100644
index 00000000..566074f5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.map-view.less
@@ -0,0 +1,3 @@
+.filtered-view.filtered-map {
+ min-height: 400px;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.number-filter.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.number-filter.less
new file mode 100644
index 00000000..ad8e3861
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.number-filter.less
@@ -0,0 +1,96 @@
+/*
+ Stylesheet for the number filter
+*/
+.filtered-filters .filtered-number {
+
+ overflow: visible;
+ border: 1px solid #aaaaaa;
+ padding: 1em 1em 0.5em;
+ margin: 1em;
+
+ .filtered-number-caption {
+ line-height: 2em;
+ text-align: center;
+ }
+
+ .filtered-number-slider {
+
+ .irs-line-mid,
+ .irs-line-left,
+ .irs-line-right,
+ .irs-bar,
+ .irs-bar-edge,
+ .irs-slider {
+ background: none;
+ }
+
+ .irs-bar,
+ .irs-bar-edge {
+ border-top: 1px solid #aaaaaa;
+ border-bottom: 1px solid #aaaaaa;
+ }
+
+ .irs-bar-edge {
+ border-radius: 3px 0 0 3px;
+ border-left: 1px solid #aaaaaa;
+ }
+
+ .irs-line {
+ border: 1px solid #aaaaaa;
+ border-radius: 3px;
+ }
+
+ &.mode-min {
+ .irs-bar,
+ .irs-bar-edge {
+ background: #ffffff;
+ }
+ .irs-line {
+ background: #dddddd;
+ }
+ }
+
+ &.mode-max,
+ &.mode-range {
+ .irs-bar,
+ .irs-bar-edge {
+ background: #dddddd;
+ }
+ .irs-line {
+ background: #ffffff;
+ }
+ }
+
+ &.mode-select {
+ .irs-line {
+ background: #ffffff;
+ }
+ }
+
+ .irs-slider {
+ width: 20px;
+ height: 20px;
+ top: 18px;
+ background-position: 0 -120px;
+ border: 1px solid #cccccc;
+ border-radius: 10px;
+ background: #ffffff;
+
+ &::after {
+ content: '';
+ background: #9aa4bd;
+ position: absolute;
+ display: block;
+ top: 5px;
+ left: 5px;
+ right: 5px;
+ bottom: 5px;
+ border-radius: 5px;
+ }
+
+ &:hover::after {
+ background: #bb0000;
+ }
+ }
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.select.css b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.select.css
new file mode 100644
index 00000000..447b2b86
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.select.css
@@ -0,0 +1,484 @@
+.select2-container {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle; }
+ .select2-container .select2-selection--single {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: 28px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--single .select2-selection__rendered {
+ display: block;
+ padding-left: 8px;
+ padding-right: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-selection--single .select2-selection__clear {
+ position: relative; }
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 8px;
+ padding-left: 20px; }
+ .select2-container .select2-selection--multiple {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ min-height: 32px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
+ display: inline-block;
+ overflow: hidden;
+ padding-left: 8px;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-search--inline {
+ float: left; }
+ .select2-container .select2-search--inline .select2-search__field {
+ box-sizing: border-box;
+ border: none;
+ font-size: 100%;
+ margin-top: 5px;
+ padding: 0; }
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+.select2-dropdown {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ left: -100000px;
+ width: 100%;
+ z-index: 1051; }
+
+.select2-results {
+ display: block; }
+
+.select2-results__options {
+ list-style: none;
+ margin: 0;
+ padding: 0; }
+
+.select2-results__option {
+ padding: 6px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-results__option[aria-selected] {
+ cursor: pointer; }
+
+.select2-container--open .select2-dropdown {
+ left: 0; }
+
+.select2-container--open .select2-dropdown--above {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--open .select2-dropdown--below {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-search--dropdown {
+ display: block;
+ padding: 4px; }
+ .select2-search--dropdown .select2-search__field {
+ padding: 4px;
+ width: 100%;
+ box-sizing: border-box; }
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+ .select2-search--dropdown.select2-search--hide {
+ display: none; }
+
+.select2-close-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ display: block;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 99;
+ background-color: #fff;
+ filter: alpha(opacity=0); }
+
+.select2-hidden-accessible {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ height: 1px !important;
+ margin: -1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ width: 1px !important; }
+
+.select2-container--default .select2-selection--single {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ border-radius: 4px; }
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--default .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold; }
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto; }
+
+.select2-container--default.select2-container--disabled .select2-selection--single {
+ background-color: #eee;
+ cursor: default; }
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none; }
+
+.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--default .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none; }
+ .select2-container--default .select2-selection--multiple .select2-selection__placeholder {
+ color: #999;
+ margin-top: 5px;
+ float: left; }
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-top: 5px;
+ margin-right: 10px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #999;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #333; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border: solid black 1px;
+ outline: 0; }
+
+.select2-container--default.select2-container--disabled .select2-selection--multiple {
+ background-color: #eee;
+ cursor: default; }
+
+.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
+ display: none; }
+
+.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--default .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa; }
+
+.select2-container--default .select2-search--inline .select2-search__field {
+ background: transparent;
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield; }
+
+.select2-container--default .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--default .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999; }
+
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd; }
+
+.select2-container--default .select2-results__option .select2-results__option {
+ padding-left: 1em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em; }
+
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #5897fb;
+ color: white; }
+
+.select2-container--default .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic .select2-selection--single {
+ background-color: #f7f7f7;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ outline: 0;
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+ .select2-container--classic .select2-selection--single:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-right: 10px; }
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
+ background-color: #ddd;
+ border: none;
+ border-left: 1px solid #aaa;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ border: none;
+ border-right: 1px solid #aaa;
+ border-radius: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ left: 1px;
+ right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--single {
+ border: 1px solid #5897fb; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
+ background: transparent;
+ border: none; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
+
+.select2-container--classic .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text;
+ outline: 0; }
+ .select2-container--classic .select2-selection--multiple:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
+ list-style: none;
+ margin: 0;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
+ display: none; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
+ color: #888;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #555; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ float: right; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--multiple {
+ border: 1px solid #5897fb; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--classic .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa;
+ outline: 0; }
+
+.select2-container--classic .select2-search--inline .select2-search__field {
+ outline: 0;
+ box-shadow: none; }
+
+.select2-container--classic .select2-dropdown {
+ background-color: white;
+ border: 1px solid transparent; }
+
+.select2-container--classic .select2-dropdown--above {
+ border-bottom: none; }
+
+.select2-container--classic .select2-dropdown--below {
+ border-top: none; }
+
+.select2-container--classic .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--classic .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--classic .select2-results__option[aria-disabled=true] {
+ color: grey; }
+
+.select2-container--classic .select2-results__option--highlighted[aria-selected] {
+ background-color: #3875d7;
+ color: white; }
+
+.select2-container--classic .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic.select2-container--open .select2-dropdown {
+ border-color: #5897fb; }
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.slider.css b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.slider.css
new file mode 100644
index 00000000..4b981f17
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.slider.css
@@ -0,0 +1,244 @@
+/* Ion.RangeSlider
+// css version 2.0.3
+// © 2013-2014 Denis Ineshin | IonDen.com
+// ===================================================================================================================*/
+
+/* =====================================================================================================================
+// RangeSlider */
+
+.irs {
+ position: relative; display: block;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+ .irs-line {
+ position: relative; display: block;
+ overflow: hidden;
+ outline: none !important;
+ }
+ .irs-line-left, .irs-line-mid, .irs-line-right {
+ position: absolute; display: block;
+ top: 0;
+ }
+ .irs-line-left {
+ left: 0; width: 11%;
+ }
+ .irs-line-mid {
+ left: 9%; width: 82%;
+ }
+ .irs-line-right {
+ right: 0; width: 11%;
+ }
+
+ .irs-bar {
+ position: absolute; display: block;
+ left: 0; width: 0;
+ }
+ .irs-bar-edge {
+ position: absolute; display: block;
+ top: 0; left: 0;
+ }
+
+ .irs-shadow {
+ position: absolute; display: none;
+ left: 0; width: 0;
+ }
+
+ .irs-slider {
+ position: absolute; display: block;
+ cursor: default;
+ z-index: 1;
+ }
+ .irs-slider.single {
+
+ }
+ .irs-slider.from {
+
+ }
+ .irs-slider.to {
+
+ }
+ .irs-slider.type_last {
+ z-index: 2;
+ }
+
+ .irs-min {
+ position: absolute; display: block;
+ left: 0;
+ cursor: default;
+ }
+ .irs-max {
+ position: absolute; display: block;
+ right: 0;
+ cursor: default;
+ }
+
+ .irs-from, .irs-to, .irs-single {
+ position: absolute; display: block;
+ top: 0; left: 0;
+ cursor: default;
+ white-space: nowrap;
+ }
+
+.irs-grid {
+ position: absolute; display: none;
+ bottom: 0; left: 0;
+ width: 100%; height: 20px;
+}
+.irs-with-grid .irs-grid {
+ display: block;
+}
+ .irs-grid-pol {
+ position: absolute;
+ top: 0; left: 0;
+ width: 1px; height: 8px;
+ background: #000;
+ }
+ .irs-grid-pol.small {
+ height: 4px;
+ }
+ .irs-grid-text {
+ position: absolute;
+ bottom: 0; left: 0;
+ white-space: nowrap;
+ text-align: center;
+ font-size: 9px; line-height: 9px;
+ padding: 0 3px;
+ color: #000;
+ }
+
+.irs-disable-mask {
+ position: absolute; display: block;
+ top: 0; left: -1%;
+ width: 102%; height: 100%;
+ cursor: default;
+ background: rgba(0,0,0,0.0);
+ z-index: 2;
+}
+.lt-ie9 .irs-disable-mask {
+ background: #000;
+ filter: alpha(opacity=0);
+ cursor: not-allowed;
+}
+
+.irs-disabled {
+ opacity: 0.4;
+}
+
+
+.irs-hidden-input {
+ position: absolute !important;
+ display: block !important;
+ top: 0 !important;
+ left: 0 !important;
+ width: 0 !important;
+ height: 0 !important;
+ font-size: 0 !important;
+ line-height: 0 !important;
+ padding: 0 !important;
+ margin: 0 !important;
+ overflow: hidden;
+ outline: none !important;
+ z-index: -9999 !important;
+ background: none !important;
+ border-style: solid !important;
+ border-color: transparent !important;
+}
+
+/* Ion.RangeSlider, Nice Skin
+// css version 2.0.3
+// © Denis Ineshin, 2014 https://github.com/IonDen
+// ===================================================================================================================*/
+
+/* =====================================================================================================================
+// Skin details */
+
+.irs {
+ height: 40px;
+}
+.irs-with-grid {
+ height: 60px;
+}
+.irs-line {
+ height: 8px; top: 25px;
+}
+ .irs-line-left {
+ height: 8px;
+ background-position: 0 -30px;
+ }
+ .irs-line-mid {
+ height: 8px;
+ background-position: 0 0;
+ }
+ .irs-line-right {
+ height: 8px;
+ background-position: 100% -30px;
+ }
+
+.irs-bar {
+ height: 8px; top: 25px;
+ background-position: 0 -60px;
+}
+ .irs-bar-edge {
+ top: 25px;
+ height: 8px; width: 11px;
+ background-position: 0 -90px;
+ }
+
+.irs-shadow {
+ height: 1px; top: 34px;
+ background: #000;
+ opacity: 0.15;
+}
+.lt-ie9 .irs-shadow {
+ filter: alpha(opacity=15);
+}
+
+.irs-slider {
+ width: 22px; height: 22px;
+ top: 17px;
+ background-position: 0 -120px;
+}
+.irs-slider.state_hover, .irs-slider:hover {
+ background-position: 0 -150px;
+}
+
+.irs-min, .irs-max {
+ color: #999;
+ font-size: 10px; line-height: 1.333;
+ text-shadow: none;
+ top: 0; padding: 1px 3px;
+ background: rgba(0,0,0,0.1);
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.lt-ie9 .irs-min, .lt-ie9 .irs-max {
+ background: #ccc;
+}
+
+.irs-from, .irs-to, .irs-single {
+ color: #fff;
+ font-size: 10px; line-height: 1.333;
+ text-shadow: none;
+ padding: 1px 5px;
+ background: rgba(0,0,0,0.3);
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.lt-ie9 .irs-from, .lt-ie9 .irs-to, .lt-ie9 .irs-single {
+ background: #999;
+}
+
+.irs-grid-pol {
+ background: #99a4ac;
+}
+.irs-grid-text {
+ color: #99a4ac;
+}
+
+.irs-disabled {
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.value-filter.less b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.value-filter.less
new file mode 100644
index 00000000..6c07b982
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/ext.srf.filtered.value-filter.less
@@ -0,0 +1,79 @@
+/*
+ Stylesheet for the value filter
+*/
+.filtered-filters .filtered-value {
+
+ overflow: visible;
+ border: 1px solid #aaaaaa;
+ padding: 1em;
+ margin: 1em;
+
+ .filtered-value-switches {
+
+ border-bottom: 1px solid #aaaaaa;
+ font-weight: bold;
+ padding: 0.5em 1em;
+ margin-bottom: 1em;
+
+ .filtered-value-andor {
+
+ label {
+ margin-right: 3em;
+ vertical-align: bottom;
+ margin-top: 0;
+ margin-bottom: 0;
+ line-height: 100%;
+ }
+
+ input {
+ margin-right: 1em;
+ }
+
+ input[type="radio"] {
+ vertical-align: bottom;
+ margin-top: 0;
+ margin-bottom: 0;
+ line-height: 100%;
+ }
+ }
+ }
+
+ /* styles for checkboxes */
+ .filtered-value-option {
+ display: inline-block;
+ padding: 0 1em;
+ width: 20%;
+ min-width: -moz-min-content;
+ min-width: -webkit-min-content;
+ min-width: min-content;
+ white-space: nowrap;
+
+ .filtered-value-option-label {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0;
+ line-height: 100%;
+ white-space: normal;
+ }
+
+ input {
+ vertical-align: sub;
+ margin-right: 1em;
+ }
+ }
+
+ /* styles for Select2 */
+ .select2-container--default.select2-container--focus {
+ .select2-selection--multiple {
+ border: solid #777777 1px;
+ }
+ }
+
+ .select2-container .select2-search--inline {
+ float: none;
+ }
+
+ .select2-search__field {
+ width: 100% !important;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers-2x.png b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers-2x.png
new file mode 100644
index 00000000..200c333d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers-2x.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers.png b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers.png
new file mode 100644
index 00000000..1a72e578
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/layers.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon-2x.png b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon-2x.png
new file mode 100644
index 00000000..88f9e501
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon-2x.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon.png b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon.png
new file mode 100644
index 00000000..950edf24
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-icon.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-shadow.png b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-shadow.png
new file mode 100644
index 00000000..9fd29795
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/css/images/marker-shadow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js
new file mode 100644
index 00000000..5ded9ad3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js
@@ -0,0 +1,1456 @@
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+"use strict";
+/// <reference types="jquery" />
+exports.__esModule = true;
+var View_1 = require("./View/View");
+var Controller = /** @class */ (function () {
+ function Controller(target, data, printRequests) {
+ this.target = undefined;
+ this.filterSpinner = undefined;
+ this.views = {};
+ this.filters = {};
+ this.currentView = undefined;
+ this.target = target;
+ if (this.target !== undefined) {
+ this.filterSpinner = this.target.find('div.filtered-filter-spinner');
+ }
+ this.data = data;
+ this.printRequests = printRequests;
+ for (var rowId in this.data) {
+ if (!this.data[rowId].hasOwnProperty('visible')) {
+ this.data[rowId].visible = {};
+ }
+ }
+ }
+ Controller.prototype.getData = function () {
+ return this.data;
+ };
+ Controller.prototype.getPrintRequests = function () {
+ return this.printRequests;
+ };
+ Controller.prototype.getPath = function () {
+ return srf.settings.get('srfgScriptPath') + '/formats/filtered/resources/';
+ };
+ Controller.prototype.attachView = function (viewid, view) {
+ this.views[viewid] = view;
+ if (this.currentView === undefined) {
+ this.currentView = view;
+ view.show();
+ }
+ else {
+ view.hide();
+ }
+ return this;
+ };
+ Controller.prototype.getView = function (viewId) {
+ return this.views[viewId];
+ };
+ Controller.prototype.attachFilter = function (filter) {
+ var filterId = filter.getId();
+ this.filters[filterId] = filter;
+ filter.init();
+ return this.onFilterUpdated(filterId);
+ };
+ Controller.prototype.getFilter = function (filterId) {
+ return this.filters[filterId];
+ };
+ Controller.prototype.show = function () {
+ this.initializeFilters();
+ this.target.children('.filtered-spinner').remove();
+ this.target.children().show();
+ this.switchToView(this.currentView);
+ };
+ Controller.prototype.switchToView = function (view) {
+ if (this.currentView instanceof View_1.View) {
+ this.currentView.hide();
+ }
+ this.currentView = view;
+ if (this.currentView instanceof View_1.View) {
+ view.show();
+ }
+ };
+ Controller.prototype.initializeFilters = function () {
+ var toShow = [];
+ var toHide = [];
+ for (var rowId in this.data) {
+ for (var filterId in this.filters) {
+ this.data[rowId].visible[filterId] = this.filters[filterId].isDisabled() || this.filters[filterId].isVisible(rowId);
+ }
+ if (this.isVisible(rowId)) {
+ toShow.push(rowId);
+ }
+ else {
+ toHide.push(rowId);
+ }
+ }
+ this.hideRows(toHide);
+ this.showRows(toShow);
+ };
+ Controller.prototype.onViewSelected = function (viewID) {
+ this.switchToView(this.views[viewID]);
+ };
+ Controller.prototype.onFilterUpdated = function (filterId) {
+ var _this = this;
+ return this.showSpinner()
+ .then(function () {
+ var toShow = [];
+ var toHide = [];
+ var disabled = _this.filters[filterId].isDisabled();
+ for (var rowId in _this.data) {
+ var newVisible = disabled || _this.filters[filterId].isVisible(rowId);
+ if (_this.data[rowId].visible[filterId] !== newVisible) {
+ _this.data[rowId].visible[filterId] = newVisible;
+ if (newVisible && _this.isVisible(rowId)) {
+ toShow.push(rowId);
+ }
+ else {
+ toHide.push(rowId);
+ }
+ }
+ }
+ _this.hideRows(toHide);
+ _this.showRows(toShow);
+ })
+ .then(function () { _this.hideSpinner(); });
+ };
+ Controller.prototype.isVisible = function (rowId) {
+ for (var filterId in this.data[rowId].visible) {
+ if (!this.data[rowId].visible[filterId]) {
+ return false;
+ }
+ }
+ return true;
+ };
+ Controller.prototype.hideRows = function (rowIds) {
+ if (rowIds.length === 0) {
+ return;
+ }
+ for (var viewId in this.views) {
+ this.views[viewId].hideRows(rowIds);
+ }
+ };
+ Controller.prototype.showRows = function (rowIds) {
+ if (rowIds.length === 0) {
+ return;
+ }
+ for (var viewId in this.views) {
+ this.views[viewId].showRows(rowIds);
+ }
+ };
+ Controller.prototype.showSpinner = function () {
+ return this.animateSpinner();
+ };
+ Controller.prototype.hideSpinner = function () {
+ return this.animateSpinner(false);
+ };
+ Controller.prototype.animateSpinner = function (show) {
+ if (show === void 0) { show = true; }
+ if (this.filterSpinner === undefined) {
+ return jQuery.when();
+ }
+ if (show) {
+ return this.filterSpinner.fadeIn(200).promise();
+ }
+ return this.filterSpinner.fadeOut(200).promise();
+ };
+ return Controller;
+}());
+exports.Controller = Controller;
+
+},{"./View/View":11}],2:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var Filter_1 = require("./Filter");
+var DistanceFilter = /** @class */ (function (_super) {
+ __extends(DistanceFilter, _super);
+ function DistanceFilter() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.earthRadiusValue = DistanceFilter.earthRadius.km;
+ _this.filterValue = 0;
+ return _this;
+ }
+ DistanceFilter.prototype.init = function () {
+ var values = this.controller.getData();
+ var origin = this.options['origin'];
+ if (!(origin !== undefined && origin.hasOwnProperty('lat') && origin.hasOwnProperty('lng'))) {
+ this.target.detach();
+ return;
+ }
+ var unit = 'km';
+ if (this.options['unit'] && DistanceFilter.earthRadius[this.options['unit']]) {
+ unit = this.options['unit'];
+ }
+ this.earthRadiusValue = DistanceFilter.earthRadius[unit];
+ var maxValue = this.updateDistances(origin);
+ var precision = Math.pow(10, (Math.floor(Math.log(maxValue) * Math.LOG10E) - 1));
+ if (this.options['max'] !== undefined && this.options['max'] > maxValue) {
+ maxValue = this.options['max'];
+ }
+ else {
+ maxValue = Math.ceil(maxValue / precision) * precision;
+ }
+ this.filterValue = this.options['initial value'] ? Math.min(this.options['initial value'], maxValue) : maxValue;
+ // build filter controls
+ var filtercontrols = this.buildEmptyControl();
+ var readout = $('<div class="filtered-distance-readout">' + this.filterValue + '</div>');
+ var table = $('<table class="filtered-distance-table"><tbody><tr><td class="filtered-distance-min-cell">0</td>' +
+ '<td class="filtered-distance-slider-cell"><div class="filtered-distance-slider"></div></td>' +
+ '<td class="filtered-distance-max-cell">' + maxValue + '</td></tr>' +
+ '<tr><td colspan=3 class="filtered-distance-unit-cell">' + unit + '</td></tr></tbody></table>');
+ filtercontrols.append(table);
+ var that = this;
+ mw.loader.using('jquery.ui.slider').then(function () {
+ table.find('.filtered-distance-slider')
+ .slider({
+ animate: true,
+ max: maxValue,
+ value: that.filterValue,
+ step: precision / 100
+ })
+ .on('slidechange', undefined, { 'filter': that }, function (eventObject, ui) {
+ eventObject.data.ui = ui;
+ eventObject.data.filter.onFilterUpdated(eventObject);
+ })
+ .on('slide', undefined, { 'filter': that }, function (eventObject, ui) {
+ readout.text(ui.value);
+ })
+ .find('.ui-slider-handle')
+ .append(readout);
+ });
+ return this;
+ };
+ DistanceFilter.prototype.updateDistances = function (origin) {
+ var _this = this;
+ var values = this.controller.getData();
+ var max = 1;
+ var prId = this.printrequestId;
+ for (var rowId in values) {
+ if (values[rowId].data.hasOwnProperty(this.filterId)) {
+ var distances = values[rowId].data[this.filterId].positions.map(function (pos) { return _this.distance(origin, pos); });
+ var dist = Math.min.apply(Math, distances);
+ values[rowId].data[this.filterId].distance = dist;
+ max = Math.max(max, dist);
+ }
+ else {
+ values[rowId].data[this.filterId].distance = Infinity;
+ }
+ }
+ return max;
+ };
+ DistanceFilter.prototype.onFilterUpdated = function (eventObject) {
+ this.filterValue = eventObject.data.ui.value;
+ this.controller.onFilterUpdated(this.getId());
+ };
+ DistanceFilter.prototype.distance = function (a, b) {
+ var DEG2RAD = Math.PI / 180.0;
+ function squared(x) {
+ return x * x;
+ }
+ var f = squared(Math.sin((b.lat - a.lat) * DEG2RAD / 2.0)) +
+ Math.cos(a.lat * DEG2RAD) * Math.cos(b.lat * DEG2RAD) *
+ squared(Math.sin((b.lng - a.lng) * DEG2RAD / 2.0));
+ return this.earthRadiusValue * 2 * Math.atan2(Math.sqrt(f), Math.sqrt(1 - f));
+ };
+ DistanceFilter.prototype.isVisible = function (rowId) {
+ var rowdata = this.controller.getData()[rowId].data;
+ if (rowdata.hasOwnProperty(this.filterId)) {
+ return rowdata[this.filterId].distance <= this.filterValue;
+ }
+ return _super.prototype.isVisible.call(this, rowId);
+ };
+ DistanceFilter.earthRadius = {
+ m: 6371008.8,
+ km: 6371.0088,
+ mi: 3958.7613,
+ nm: 3440.0695,
+ Ã…: 63710088000000000
+ };
+ return DistanceFilter;
+}(Filter_1.Filter));
+exports.DistanceFilter = DistanceFilter;
+
+},{"./Filter":3}],3:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var Filter = /** @class */ (function () {
+ function Filter(filterId, target, printrequestId, controller, options) {
+ this.outerTarget = undefined;
+ this.target = undefined;
+ this.options = undefined;
+ this.disabled = false;
+ this.collapsed = false;
+ this.target = target;
+ this.outerTarget = target;
+ this.filterId = filterId;
+ this.printrequestId = printrequestId;
+ this.controller = controller;
+ this.options = options || {};
+ }
+ Filter.prototype.init = function () { };
+ ;
+ Filter.prototype.isDisabled = function () {
+ return this.disabled;
+ };
+ Filter.prototype.disable = function () {
+ var _this = this;
+ this.disabled = true;
+ this.outerTarget
+ .removeClass('enabled')
+ .addClass('disabled');
+ this.collapse();
+ this.target.promise().then(function () { return _this.controller.onFilterUpdated(_this.filterId); });
+ };
+ Filter.prototype.enable = function () {
+ var _this = this;
+ this.disabled = false;
+ this.outerTarget
+ .removeClass('disabled')
+ .addClass('enabled');
+ if (!this.collapsed) {
+ this.uncollapse();
+ }
+ this.target.promise().then(function () { return _this.controller.onFilterUpdated(_this.filterId); });
+ };
+ Filter.prototype.collapse = function (duration) {
+ var _this = this;
+ if (duration === void 0) { duration = 400; }
+ if (!this.collapsed) {
+ this.outerTarget.promise()
+ .then(function () {
+ _this.target.slideUp(duration);
+ _this.outerTarget.animate({
+ 'padding-top': 0,
+ 'padding-bottom': 0,
+ 'margin-bottom': '2em'
+ }, duration);
+ });
+ }
+ };
+ Filter.prototype.uncollapse = function () {
+ var _this = this;
+ this.outerTarget.promise()
+ .then(function () {
+ _this.target.slideDown();
+ var style = _this.outerTarget.attr('style');
+ _this.outerTarget.removeAttr('style');
+ var uncollapsedCss = _this.outerTarget.css(['padding-top', 'padding-bottom', 'margin-bottom']);
+ _this.outerTarget.attr('style', style);
+ _this.outerTarget.animate(uncollapsedCss);
+ });
+ };
+ Filter.prototype.isVisible = function (rowId) {
+ return this.options.hasOwnProperty('show if undefined') && this.options['show if undefined'] === true;
+ };
+ Filter.prototype.getId = function () {
+ return this.filterId;
+ };
+ Filter.prototype.buildEmptyControl = function () {
+ this.target = $('<div class="filtered-filter-container">');
+ this.outerTarget
+ .append(this.target)
+ .addClass('enabled');
+ this.addOnOffSwitch();
+ this.addLabel();
+ this.addControlForCollapsing();
+ return this.target;
+ };
+ Filter.prototype.addLabel = function () {
+ // insert the label of the printout this filter filters on
+ this.target.before("<div class=\"filtered-filter-label\">" + this.options['label'] + "</div>");
+ };
+ Filter.prototype.addOnOffSwitch = function () {
+ var _this = this;
+ if (this.options.hasOwnProperty('switches')) {
+ var switches = this.options['switches'];
+ if (switches.length > 0 && $.inArray('on off', switches) >= 0) {
+ var onOffControl = $("<div class=\"filtered-filter-onoff on\"></div>");
+ this.target.before(onOffControl);
+ onOffControl.click(function () {
+ if (_this.outerTarget.hasClass('enabled')) {
+ _this.disable();
+ }
+ else {
+ _this.enable();
+ }
+ });
+ }
+ }
+ };
+ Filter.prototype.addControlForCollapsing = function () {
+ var _this = this;
+ var collapsible = this.options.hasOwnProperty('collapsible') ? this.options['collapsible'] : undefined;
+ if (collapsible === 'collapsed' || collapsible === 'uncollapsed') {
+ var collapseControl_1 = $('<span class="filtered-filter-collapse">');
+ this.target.before(collapseControl_1);
+ collapseControl_1.click(function () {
+ if (collapseControl_1.hasClass('collapsed')) {
+ _this.uncollapse();
+ _this.collapsed = false;
+ collapseControl_1
+ .removeClass('collapsed')
+ .addClass('uncollapsed');
+ }
+ else {
+ _this.collapse();
+ _this.collapsed = true;
+ collapseControl_1
+ .removeClass('uncollapsed')
+ .addClass('collapsed');
+ }
+ });
+ if (collapsible === 'collapsed') {
+ this.collapse(0);
+ this.collapsed = true;
+ collapseControl_1.addClass('collapsed');
+ }
+ else {
+ collapseControl_1.addClass('uncollapsed');
+ }
+ }
+ };
+ return Filter;
+}());
+exports.Filter = Filter;
+
+},{}],4:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+///<reference path="../../../../node_modules/@types/ion.rangeslider/index.d.ts"/>
+var Filter_1 = require("./Filter");
+var NumberFilter = /** @class */ (function (_super) {
+ __extends(NumberFilter, _super);
+ function NumberFilter() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.MODE_RANGE = 0;
+ _this.MODE_MIN = 1;
+ _this.MODE_MAX = 2;
+ _this.MODE_SELECT = 3;
+ _this.filterValueUpper = 0;
+ _this.filterValueLower = 0;
+ _this.mode = _this.MODE_RANGE;
+ return _this;
+ }
+ NumberFilter.prototype.init = function () {
+ var values = this.getValues();
+ var _a = this.getRangeParameters(values), minValue = _a.minValue, maxValue = _a.maxValue, precision = _a.precision;
+ var sliderOptions = {
+ prettify_enabled: false,
+ force_edges: true,
+ grid: true
+ };
+ if (this.options.hasOwnProperty('values')) {
+ sliderOptions = this.adjustSliderOptionsFromValues(sliderOptions, values);
+ }
+ else {
+ sliderOptions = this.adjustSliderOptionsFromRangeParameters(sliderOptions, minValue, maxValue, precision);
+ }
+ switch (this.options['sliders']) {
+ case "min":
+ this.mode = this.MODE_MIN;
+ sliderOptions.type = 'single';
+ break;
+ case "max":
+ this.mode = this.MODE_MAX;
+ sliderOptions.from = sliderOptions.to;
+ sliderOptions.type = 'single';
+ break;
+ case "select":
+ this.mode = this.MODE_SELECT;
+ maxValue = minValue;
+ sliderOptions.type = 'single';
+ break;
+ default: // == case "range"
+ this.mode = this.MODE_RANGE;
+ sliderOptions.type = 'double';
+ }
+ this.buildFilterControls(sliderOptions);
+ this.filterValueLower = minValue;
+ this.filterValueUpper = maxValue;
+ return this;
+ };
+ NumberFilter.prototype.adjustSliderOptionsFromRangeParameters = function (sliderOptions, minValue, maxValue, precision) {
+ var _this = this;
+ sliderOptions.min = minValue;
+ sliderOptions.max = maxValue;
+ sliderOptions.step = this.getStep(precision);
+ sliderOptions.grid_num = Math.min(4, Math.round((maxValue - minValue) / sliderOptions.step));
+ sliderOptions.from = minValue;
+ sliderOptions.to = maxValue;
+ sliderOptions.onFinish = function (data) { return _this.onFilterUpdated(data.from, data.to); };
+ return sliderOptions;
+ };
+ NumberFilter.prototype.adjustSliderOptionsFromValues = function (sliderOptions, values) {
+ var _this = this;
+ sliderOptions.values = values;
+ sliderOptions.from = 0;
+ sliderOptions.to = values.length - 1;
+ sliderOptions.onFinish = function (data) { return _this.onFilterUpdated(data.from_value, data.to_value); };
+ return sliderOptions;
+ };
+ NumberFilter.prototype.getRangeParameters = function (values) {
+ var minValue = values[0];
+ var maxValue = values[values.length - 1];
+ var precision = this.getPrecision(minValue, maxValue);
+ if (!this.options.hasOwnProperty('values')) {
+ minValue = this.getMinSliderValue(minValue, precision);
+ maxValue = this.getMaxSliderValue(maxValue, precision);
+ }
+ return { minValue: minValue, maxValue: maxValue, precision: precision };
+ };
+ NumberFilter.prototype.getValues = function () {
+ var values;
+ if (this.options.hasOwnProperty('values') && this.options['values'][0] !== 'auto') {
+ values = this.options['values'];
+ }
+ else {
+ values = this.getSortedValues();
+ }
+ if (values.length === 0) {
+ values = [0, 0];
+ }
+ else if (values.length === 1) {
+ values.push(values[0]);
+ }
+ return values;
+ };
+ NumberFilter.prototype.buildFilterControls = function (sliderOptions) {
+ var filterClassNames = {};
+ filterClassNames[this.MODE_MIN.toString()] = "mode-min";
+ filterClassNames[this.MODE_MAX] = "mode-max";
+ filterClassNames[this.MODE_RANGE] = "mode-range";
+ filterClassNames[this.MODE_SELECT] = "mode-select";
+ var filtercontrols = this.buildEmptyControl();
+ var slider = $('<input type="text" value="" />');
+ var sliderContainer = $("<div class=\"filtered-number-slider " + filterClassNames[this.mode] + "\" />").append(slider);
+ filtercontrols.append(sliderContainer);
+ if (this.options.hasOwnProperty('caption')) {
+ var caption = "<div class=\"filtered-number-caption\">" + this.options['caption'] + "</div>";
+ filtercontrols.append(caption);
+ }
+ mw.loader.using('ext.srf.filtered.slider').then(function () { return slider.ionRangeSlider(sliderOptions); });
+ };
+ NumberFilter.prototype.getMinSliderValue = function (minValue, precision) {
+ var requestedMin = this.options['min'];
+ if (requestedMin === undefined || isNaN(Number(requestedMin))) {
+ return Math.floor(minValue / precision) * precision;
+ }
+ return Math.min(requestedMin, minValue);
+ };
+ NumberFilter.prototype.getMaxSliderValue = function (maxValue, precision) {
+ var requestedMax = this.options['max'];
+ if (requestedMax === undefined || isNaN(Number(requestedMax))) {
+ return Math.ceil(maxValue / precision) * precision;
+ }
+ return Math.max(requestedMax, maxValue);
+ };
+ NumberFilter.prototype.getPrecision = function (minValue, maxValue) {
+ if (maxValue - minValue > 0) {
+ return Math.pow(10, (Math.floor(Math.log(maxValue - minValue) * Math.LOG10E) - 1));
+ }
+ else {
+ return 1;
+ }
+ };
+ NumberFilter.prototype.getStep = function (precision) {
+ var step = this.options['step'];
+ if (step !== undefined) {
+ step = Number(step);
+ if (!isNaN(step)) {
+ return step;
+ }
+ }
+ return precision / 10;
+ };
+ NumberFilter.prototype.getRangeFromValues = function () {
+ var rows = this.controller.getData();
+ var min = Infinity;
+ var max = -Infinity;
+ for (var rowId in rows) {
+ if (rows[rowId].data.hasOwnProperty(this.filterId)) {
+ var values = rows[rowId].data[this.filterId].values;
+ min = Math.min.apply(Math, [min].concat(values));
+ max = Math.max.apply(Math, [max].concat(values));
+ }
+ }
+ return [min, max];
+ };
+ NumberFilter.prototype.getSortedValues = function () {
+ var valueArray = [];
+ var rows = this.controller.getData();
+ for (var rowId in rows) {
+ var cells = rows[rowId].data;
+ if (cells.hasOwnProperty(this.filterId)) {
+ var values = cells[this.filterId].values;
+ for (var valueId in values) {
+ var value = Number(values[valueId]);
+ if (valueArray.indexOf(value) === -1) {
+ valueArray.push(value);
+ }
+ }
+ }
+ }
+ return valueArray.sort(function (a, b) { return a - b; });
+ };
+ NumberFilter.prototype.onFilterUpdated = function (from, to) {
+ switch (this.mode) {
+ case this.MODE_MIN:
+ this.filterValueLower = from;
+ break;
+ case this.MODE_MAX:
+ this.filterValueUpper = from;
+ break;
+ case this.MODE_SELECT:
+ this.filterValueLower = from;
+ this.filterValueUpper = from;
+ break;
+ default: // case this.MODE_RANGE:
+ this.filterValueLower = from;
+ this.filterValueUpper = to;
+ }
+ this.controller.onFilterUpdated(this.getId());
+ };
+ NumberFilter.prototype.isVisible = function (rowId) {
+ var rowdata = this.controller.getData()[rowId].data;
+ if (rowdata.hasOwnProperty(this.filterId) && rowdata[this.filterId].values.length > 0) {
+ for (var _i = 0, _a = rowdata[this.filterId].values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ if (value >= this.filterValueLower && value <= this.filterValueUpper) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return _super.prototype.isVisible.call(this, rowId);
+ };
+ return NumberFilter;
+}(Filter_1.Filter));
+exports.NumberFilter = NumberFilter;
+
+},{"./Filter":3}],5:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var Filter_1 = require("./Filter");
+var ValueFilter = /** @class */ (function (_super) {
+ __extends(ValueFilter, _super);
+ function ValueFilter() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.values = {};
+ _this.visibleValues = [];
+ _this._useOr = true;
+ return _this;
+ }
+ ValueFilter.prototype.init = function () {
+ this.values = this.getSortedValues();
+ this.buildControl();
+ };
+ ValueFilter.prototype.useOr = function (useOr) {
+ this._useOr = useOr;
+ this.controller.onFilterUpdated(this.getId());
+ };
+ ValueFilter.prototype.getSortedValues = function () {
+ /** Map of value => label distinct values */
+ var distinctValues = {};
+ /** Map of value => sort value distinct values */
+ var distinctSortValues = {};
+ if (this.options.hasOwnProperty('values')) {
+ return this.options['values'].map(function (item) {
+ return {
+ printoutValue: item,
+ formattedValue: item
+ };
+ });
+ }
+ else {
+ // build filter values from available values in result set
+ var data = this.controller.getData();
+ var sortedEntries = [];
+ for (var id in data) {
+ var printoutValues = data[id]['printouts'][this.printrequestId]['values'];
+ var printoutFormattedValues = data[id]['printouts'][this.printrequestId]['formatted values'];
+ var printoutSortValues = data[id]['printouts'][this.printrequestId]['sort values'];
+ for (var i in printoutValues) {
+ var printoutFormattedValue = printoutFormattedValues[i];
+ if (printoutFormattedValue.indexOf('<a') > -1) {
+ printoutFormattedValue = /<a.*>(.*?)<\/a>/.exec(printoutFormattedValue)[1];
+ }
+ distinctValues[printoutValues[i]] = printoutFormattedValue;
+ distinctSortValues[printoutValues[i]] = printoutSortValues[i];
+ }
+ }
+ for (var printoutValue in distinctSortValues) {
+ sortedEntries.push({
+ printoutValue: printoutValue,
+ sortValue: distinctSortValues[printoutValue],
+ formattedValue: distinctValues[printoutValue]
+ });
+ }
+ sortedEntries.sort(function (a, b) {
+ return a.sortValue.localeCompare(b.sortValue);
+ });
+ return sortedEntries;
+ }
+ };
+ ValueFilter.prototype.buildControl = function () {
+ var filtercontrols = this.buildEmptyControl();
+ filtercontrols = this.addControlForSwitches(filtercontrols);
+ var maxCheckboxes = this.options.hasOwnProperty('max checkboxes') ? this.options['max checkboxes'] : 5;
+ if (this.values.length > maxCheckboxes) {
+ filtercontrols.append(this.getSelected2Control());
+ }
+ else {
+ filtercontrols.append(this.getCheckboxesControl());
+ }
+ };
+ ValueFilter.prototype.getCheckboxesControl = function () {
+ var _this = this;
+ var checkboxes = $('<div class="filtered-value-checkboxes" style="width: 100%;">');
+ // insert options (checkboxes and labels)
+ for (var _i = 0, _a = this.values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ checkboxes.append("<div class=\"filtered-value-option\"><label><input type=\"checkbox\" value=\"" + value.printoutValue + "\" ><div class=\"filtered-value-option-label\">" + (value.formattedValue || value.printoutValue) + "</div></label></div>");
+ }
+ // attach event handler
+ checkboxes
+ .on('change', ':checkbox', function (eventObject) {
+ var checkboxElement = eventObject.currentTarget;
+ _this.onFilterUpdated(checkboxElement.value, checkboxElement.checked);
+ });
+ return checkboxes;
+ };
+ ValueFilter.prototype.getSelected2Control = function () {
+ var _this = this;
+ var select = $('<select class="filtered-value-select" style="width: 100%;">');
+ var data = [];
+ // insert options (checkboxes and labels) and attach event handlers
+ for (var _i = 0, _a = this.values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ // Try to get label, if not fall back to value id
+ var label = value.formattedValue || value.printoutValue;
+ data.push({ id: value.printoutValue, text: label });
+ }
+ mw.loader.using('ext.srf.filtered.value-filter.select').then(function () {
+ select.select2({
+ multiple: true,
+ placeholder: mw.message('srf-filtered-value-filter-placeholder').text(),
+ data: data
+ });
+ select.on("select2:select", function (e) {
+ _this.onFilterUpdated(e.params.data.id, true);
+ });
+ select.on("select2:unselect", function (e) {
+ _this.onFilterUpdated(e.params.data.id, false);
+ });
+ });
+ return select;
+ };
+ ValueFilter.prototype.addControlForSwitches = function (filtercontrols) {
+ // insert switches
+ var switches = this.options.hasOwnProperty('switches') ? this.options['switches'] : undefined;
+ if (switches !== undefined && $.inArray('and or', switches) >= 0) {
+ var switchControls = $('<div class="filtered-value-switches">');
+ var andorControl = $('<div class="filtered-value-andor">');
+ var orControl = this.getRadioControl('or', true);
+ var andControl = this.getRadioControl('and');
+ andorControl
+ .append(orControl)
+ .append(andControl)
+ .appendTo(switchControls);
+ andorControl
+ .find('input')
+ .on('change', undefined, { 'filter': this }, function (eventObject) {
+ return eventObject.data.filter.useOr(eventObject.target.getAttribute('value') === 'or');
+ });
+ filtercontrols.append(switchControls);
+ }
+ return filtercontrols;
+ };
+ ValueFilter.prototype.getRadioControl = function (type, isChecked) {
+ if (isChecked === void 0) { isChecked = false; }
+ var checkedAttr = isChecked ? 'checked' : '';
+ var labelText = mw.message('srf-filtered-value-filter-' + type).text();
+ var controlText = "<label for=\"filtered-value-" + type + "-" + this.printrequestId + "\">" +
+ ("<input type=\"radio\" name=\"filtered-value-" + this.printrequestId + "\" class=\"filtered-value-" + type + "\" id=\"filtered-value-" + type + "-" + this.printrequestId + "\" value=\"" + type + "\" " + checkedAttr + ">") +
+ (labelText + "</label>");
+ return $(controlText);
+ };
+ ValueFilter.prototype.isVisible = function (rowId) {
+ if (this.visibleValues.length === 0) {
+ return true;
+ }
+ var values = this.controller.getData()[rowId].printouts[this.printrequestId].values;
+ if (values.length === 0) {
+ return _super.prototype.isVisible.call(this, rowId);
+ }
+ if (this._useOr) {
+ for (var _i = 0, _a = this.visibleValues; _i < _a.length; _i++) {
+ var expectedValue = _a[_i];
+ if (values.indexOf(expectedValue) >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ else {
+ for (var _b = 0, _c = this.visibleValues; _b < _c.length; _b++) {
+ var expectedValue = _c[_b];
+ if (values.indexOf(expectedValue) < 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ ValueFilter.prototype.onFilterUpdated = function (value, isChecked) {
+ var index = this.visibleValues.indexOf(value);
+ if (isChecked && index === -1) {
+ this.visibleValues.push(value);
+ }
+ else if (!isChecked && index >= 0) {
+ this.visibleValues.splice(index, 1);
+ }
+ this.controller.onFilterUpdated(this.getId());
+ };
+ return ValueFilter;
+}(Filter_1.Filter));
+exports.ValueFilter = ValueFilter;
+
+},{"./Filter":3}],6:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var Controller_1 = require("./Controller");
+var ViewSelector_1 = require("./ViewSelector");
+var View_1 = require("./View/View");
+var ListView_1 = require("./View/ListView");
+var TableView_1 = require("./View/TableView");
+var MapView_1 = require("./View/MapView");
+var CalendarView_1 = require("./View/CalendarView");
+var ValueFilter_1 = require("./Filter/ValueFilter");
+var DistanceFilter_1 = require("./Filter/DistanceFilter");
+var NumberFilter_1 = require("./Filter/NumberFilter");
+/**
+ * Central Filtered class
+ *
+ * Factory to setup everyhting else
+ */
+var Filtered = /** @class */ (function () {
+ /**
+ *
+ * @param target
+ * @param config
+ */
+ function Filtered(target, config) {
+ this.viewTypes = {
+ table: TableView_1.TableView,
+ list: ListView_1.ListView,
+ map: MapView_1.MapView,
+ calendar: CalendarView_1.CalendarView
+ };
+ this.filterTypes = {
+ value: ValueFilter_1.ValueFilter,
+ distance: DistanceFilter_1.DistanceFilter,
+ number: NumberFilter_1.NumberFilter
+ };
+ this.config = config;
+ this.target = target;
+ }
+ Filtered.prototype.run = function () {
+ var controller = new Controller_1.Controller(this.target, this.config.data, this.config.printrequests);
+ this.attachFilters(controller, this.target.children('div.filtered-filters'));
+ this.attachViewSelector(controller, this.target.find('div.filtered-views-selectors-container'));
+ this.attachViews(controller, this.target.find('div.filtered-views-container'));
+ // lift-off
+ controller.show();
+ };
+ Filtered.prototype.attachFilters = function (controller, filtersContainer) {
+ for (var prId in this.config.printrequests) {
+ var pr = this.config.printrequests[prId];
+ if (pr.hasOwnProperty('filters')) {
+ for (var filterid in pr.filters) {
+ if (pr.filters.hasOwnProperty(filterid) &&
+ pr.filters[filterid].hasOwnProperty('type') &&
+ this.filterTypes.hasOwnProperty(pr.filters[filterid].type)) {
+ // target: JQuery, printrequest: string,
+ // controller: Controller, options?: Options
+ var filter = new this.filterTypes[pr.filters[filterid].type](filterid, filtersContainer.children('#' + filterid), prId, controller, pr.filters[filterid]);
+ controller.attachFilter(filter);
+ }
+ }
+ }
+ }
+ };
+ Filtered.prototype.attachViewSelector = function (controller, viewSelectorContainer) {
+ var viewSelector = new ViewSelector_1.ViewSelector(viewSelectorContainer, Object.keys(this.config.views), controller);
+ viewSelector.init();
+ };
+ Filtered.prototype.attachViews = function (controller, viewsContainer) {
+ // attach views
+ for (var viewid in this.config.views) {
+ var viewtype = this.config.views[viewid]['type'];
+ var viewHandlerClass = this.viewTypes.hasOwnProperty(viewtype) ? this.viewTypes[viewtype] : View_1.View;
+ var view = new viewHandlerClass(viewid, viewsContainer.children('#' + viewid), controller, this.config.views[viewid]);
+ view.init();
+ controller.attachView(viewid, view);
+ }
+ };
+ return Filtered;
+}());
+exports.Filtered = Filtered;
+
+},{"./Controller":1,"./Filter/DistanceFilter":2,"./Filter/NumberFilter":4,"./Filter/ValueFilter":5,"./View/CalendarView":7,"./View/ListView":8,"./View/MapView":9,"./View/TableView":10,"./View/View":11,"./ViewSelector":12}],7:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var View_1 = require("./View");
+var CalendarView = /** @class */ (function (_super) {
+ __extends(CalendarView, _super);
+ function CalendarView() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ CalendarView.prototype.getI18N = function () {
+ return {
+ monthNames: [mw.msg('january'), mw.msg('february'), mw.msg('march'),
+ mw.msg('april'), mw.msg('may_long'), mw.msg('june'),
+ mw.msg('july'), mw.msg('august'), mw.msg('september'),
+ mw.msg('october'), mw.msg('november'), mw.msg('december')
+ ],
+ monthNamesShort: [mw.msg('jan'), mw.msg('feb'), mw.msg('mar'),
+ mw.msg('apr'), mw.msg('may'), mw.msg('jun'),
+ mw.msg('jul'), mw.msg('aug'), mw.msg('sep'),
+ mw.msg('oct'), mw.msg('nov'), mw.msg('dec')
+ ],
+ dayNames: [mw.msg('sunday'), mw.msg('monday'), mw.msg('tuesday'),
+ mw.msg('wednesday'), mw.msg('thursday'), mw.msg('friday'), mw.msg('saturday')
+ ],
+ dayNamesShort: [mw.msg('sun'), mw.msg('mon'), mw.msg('tue'),
+ mw.msg('wed'), mw.msg('thu'), mw.msg('fri'), mw.msg('sat')
+ ],
+ buttonText: {
+ today: mw.msg('srf-ui-eventcalendar-label-today'),
+ month: mw.msg('srf-ui-eventcalendar-label-month'),
+ week: mw.msg('srf-ui-eventcalendar-label-week'),
+ day: mw.msg('srf-ui-eventcalendar-label-day')
+ },
+ allDayText: mw.msg('srf-ui-eventcalendar-label-allday'),
+ timeFormat: {
+ '': mw.msg('srf-ui-eventcalendar-format-time'),
+ agenda: mw.msg('srf-ui-eventcalendar-format-time-agenda')
+ },
+ axisFormat: mw.msg('srf-ui-eventcalendar-format-axis'),
+ titleFormat: {
+ month: mw.msg('srf-ui-eventcalendar-format-title-month'),
+ week: mw.msg('srf-ui-eventcalendar-format-title-week'),
+ day: mw.msg('srf-ui-eventcalendar-format-title-day')
+ },
+ columnFormat: {
+ month: mw.msg('srf-ui-eventcalendar-format-column-month'),
+ week: mw.msg('srf-ui-eventcalendar-format-column-week'),
+ day: mw.msg('srf-ui-eventcalendar-format-column-day')
+ }
+ };
+ };
+ CalendarView.prototype.init = function () {
+ var _i18n = this.getI18N();
+ // initialize the calendar
+ this.target.fullCalendar({
+ firstDay: this.options.firstDay,
+ isRTL: this.options.isRTL,
+ monthNames: _i18n.monthNames,
+ monthNamesShort: _i18n.monthNamesShort,
+ dayNames: _i18n.dayNames,
+ dayNamesShort: _i18n.dayNamesShort,
+ buttonText: _i18n.buttonText,
+ allDayText: _i18n.allDayText,
+ timeFormat: _i18n.timeFormat,
+ titleFormat: _i18n.titleFormat,
+ columnFormat: _i18n.columnFormat
+ });
+ };
+ CalendarView.prototype.getEvent = function (rowId, rowData) {
+ var eventdata = {
+ id: rowId,
+ title: rowData['title'],
+ start: rowData['start'],
+ className: rowId
+ };
+ if (rowData.hasOwnProperty('end')) {
+ eventdata['end'] = rowData['end'];
+ }
+ if (rowData.hasOwnProperty('url')) {
+ eventdata['url'] = rowData['url'];
+ }
+ return eventdata;
+ };
+ CalendarView.prototype.showRows = function (rowIds) {
+ var _this = this;
+ var events = [];
+ rowIds.forEach(function (rowId) {
+ var rowData = _this.controller.getData()[rowId].data[_this.id];
+ if (rowData.hasOwnProperty('start')) {
+ events.push(_this.getEvent(rowId, rowData));
+ }
+ });
+ this.target.fullCalendar('addEventSource', events);
+ };
+ CalendarView.prototype.hideRows = function (rowIds) {
+ this.target.fullCalendar('removeEvents', function (e) { return (rowIds.indexOf(e._id) >= 0); });
+ };
+ CalendarView.prototype.show = function () {
+ _super.prototype.show.call(this);
+ this.target.fullCalendar('render');
+ };
+ CalendarView.prototype.hide = function () {
+ return _super.prototype.hide.call(this);
+ };
+ return CalendarView;
+}(View_1.View));
+exports.CalendarView = CalendarView;
+
+},{"./View":11}],8:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var View_1 = require("./View");
+var ListView = /** @class */ (function (_super) {
+ __extends(ListView, _super);
+ function ListView() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ ListView.prototype.getItemClassName = function () {
+ return '.filtered-list-item';
+ };
+ return ListView;
+}(View_1.View));
+exports.ListView = ListView;
+
+},{"./View":11}],9:[function(require,module,exports){
+"use strict";
+/// <reference types="leaflet" />
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var View_1 = require("./View");
+var MapView = /** @class */ (function (_super) {
+ __extends(MapView, _super);
+ function MapView() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.map = undefined;
+ _this.icon = undefined;
+ _this.markers = undefined;
+ _this.markerClusterGroup = undefined;
+ _this.bounds = undefined;
+ _this.initialized = false;
+ _this.zoom = -1;
+ _this.minZoom = -1;
+ _this.maxZoom = -1;
+ _this.leafletPromise = undefined;
+ return _this;
+ }
+ MapView.prototype.init = function () {
+ var _this = this;
+ var data = this.controller.getData();
+ var markers = {};
+ if (this.options.hasOwnProperty('height')) {
+ this.target.height(this.options.height);
+ }
+ this.leafletPromise = mw.loader.using('ext.srf.filtered.map-view.leaflet')
+ .then(function () {
+ var bounds = undefined;
+ var disableClusteringAtZoom = _this.getZoomForUnclustering();
+ var clusterOptions = {
+ animateAddingMarkers: true,
+ disableClusteringAtZoom: disableClusteringAtZoom,
+ spiderfyOnMaxZoom: disableClusteringAtZoom === null
+ };
+ clusterOptions = _this.getOptions(['maxClusterRadius', 'zoomToBoundsOnClick'], clusterOptions);
+ var markerClusterGroup = L.markerClusterGroup(clusterOptions);
+ for (var rowId in data) {
+ if (data[rowId]['data'].hasOwnProperty(_this.id)) {
+ var positions = data[rowId]['data'][_this.id]['positions'];
+ markers[rowId] = [];
+ for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {
+ var pos = positions_1[_i];
+ bounds = (bounds === undefined) ? new L.LatLngBounds(pos, pos) : bounds.extend(pos);
+ var marker = _this.getMarker(pos, data[rowId]);
+ markers[rowId].push(marker);
+ markerClusterGroup.addLayer(marker);
+ }
+ }
+ }
+ _this.markerClusterGroup = markerClusterGroup;
+ _this.markers = markers;
+ _this.bounds = (bounds === undefined) ? new L.LatLngBounds([-180, -90], [180, 90]) : bounds;
+ });
+ return this.leafletPromise;
+ };
+ MapView.prototype.getZoomForUnclustering = function () {
+ if (this.options.hasOwnProperty('marker cluster') && this.options['marker cluster'] === false) {
+ return 0;
+ }
+ if (this.options.hasOwnProperty('marker cluster max zoom')) {
+ return this.options['marker cluster max zoom'] + 1;
+ }
+ return null;
+ };
+ MapView.prototype.getIcon = function (row) {
+ if (this.icon === undefined) {
+ this.buildIconList();
+ }
+ if (this.options.hasOwnProperty('marker icon property')) {
+ var vals = row['printouts'][this.options['marker icon property']]['values'];
+ if (vals.length > 0 && this.icon.hasOwnProperty(vals[0])) {
+ return this.icon[vals[0]];
+ }
+ }
+ return this.icon['default'];
+ };
+ MapView.prototype.buildIconList = function () {
+ this.icon = {};
+ var iconPath = this.controller.getPath() + 'css/images/';
+ this.icon['default'] = new L.Icon({
+ 'iconUrl': iconPath + 'marker-icon.png',
+ 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [25, 41],
+ 'iconAnchor': [12, 41],
+ 'popupAnchor': [1, -34],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [41, 41]
+ });
+ if (this.options.hasOwnProperty('marker icons')) {
+ for (var value in this.options['marker icons']) {
+ this.icon[value] = new L.Icon({
+ 'iconUrl': this.options['marker icons'][value],
+ // 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [32, 32],
+ 'iconAnchor': [16, 32],
+ 'popupAnchor': [1, -30],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [41, 41],
+ 'shadowAnchor': [12, 41]
+ });
+ }
+ }
+ };
+ MapView.prototype.getMarker = function (latLng, row) {
+ var title = undefined;
+ var popup = [];
+ // TODO: Use <div> instead of <b> and do CSS styling
+ for (var prId in row['printouts']) {
+ var printrequest = (this.controller.getPrintRequests())[prId];
+ if (!printrequest.hasOwnProperty('hide') || printrequest.hide === false) {
+ var printouts = row['printouts'][prId];
+ if (title === undefined) {
+ title = printouts['values'].join(', ');
+ popup.push('<b>' + printouts['formatted values'].join(', ') + '</b>');
+ }
+ else {
+ popup.push((printouts.label ? '<b>' + printouts.label + ':</b> ' : '') + printouts['formatted values'].join(', '));
+ }
+ }
+ }
+ var marker = L.marker(latLng, { title: title, alt: title });
+ marker.bindPopup(popup.join('<br>'));
+ marker.setIcon(this.getIcon(row));
+ return marker;
+ };
+ MapView.prototype.lateInit = function () {
+ var _this = this;
+ if (this.initialized) {
+ return;
+ }
+ this.initialized = true;
+ var that = this;
+ this.leafletPromise.then(function () {
+ var mapOptions = {
+ center: _this.bounds !== undefined ? _this.bounds.getCenter() : [0, 0]
+ };
+ mapOptions = that.getOptions(['zoom', 'minZoom', 'maxZoom'], mapOptions);
+ // TODO: Limit zoom values to map max zoom
+ that.map = L.map(that.getTargetElement().get(0), mapOptions);
+ that.map.addLayer(that.markerClusterGroup);
+ if (_this.options.hasOwnProperty('map provider')) {
+ L.tileLayer.provider(_this.options['map provider']).addTo(that.map);
+ }
+ if (!mapOptions.hasOwnProperty('zoom')) {
+ that.map.fitBounds(that.bounds);
+ }
+ });
+ };
+ MapView.prototype.getOptions = function (keys, defaults) {
+ if (defaults === void 0) { defaults = {}; }
+ for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
+ var key = keys_1[_i];
+ if (this.options.hasOwnProperty(key)) {
+ defaults[key] = this.options[key];
+ }
+ }
+ return defaults;
+ };
+ MapView.prototype.showRows = function (rowIds) {
+ var _this = this;
+ this.leafletPromise.then(function () {
+ _this.manipulateLayers(rowIds, function (layers) {
+ _this.markerClusterGroup.addLayers(layers);
+ });
+ });
+ };
+ MapView.prototype.hideRows = function (rowIds) {
+ var _this = this;
+ this.leafletPromise.then(function () {
+ _this.manipulateLayers(rowIds, function (layers) {
+ _this.markerClusterGroup.removeLayers(layers);
+ });
+ });
+ };
+ MapView.prototype.manipulateLayers = function (rowIds, cb) {
+ var layersFromRowIds = this.getLayersFromRowIds(rowIds);
+ if (layersFromRowIds.length > 0) {
+ cb(layersFromRowIds);
+ }
+ };
+ MapView.prototype.getLayersFromRowIds = function (rowIds) {
+ return this.flatten(this.getLayersFromRowIdsRaw(rowIds));
+ };
+ MapView.prototype.getLayersFromRowIdsRaw = function (rowIds) {
+ var _this = this;
+ return rowIds.map(function (rowId) { return _this.markers[rowId] ? _this.markers[rowId] : []; });
+ };
+ MapView.prototype.flatten = function (markers) {
+ return markers.reduce(function (result, layers) { return result.concat(layers); }, []);
+ };
+ MapView.prototype.show = function () {
+ _super.prototype.show.call(this);
+ this.lateInit();
+ };
+ return MapView;
+}(View_1.View));
+exports.MapView = MapView;
+
+},{"./View":11}],10:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var View_1 = require("./View");
+var TableView = /** @class */ (function (_super) {
+ __extends(TableView, _super);
+ function TableView() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ TableView.prototype.getItemClassName = function () {
+ return '.filtered-table-item';
+ };
+ return TableView;
+}(View_1.View));
+exports.TableView = TableView;
+
+},{"./View":11}],11:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var View = /** @class */ (function () {
+ function View(id, target, c, options) {
+ if (options === void 0) { options = {}; }
+ this.id = undefined;
+ this.target = undefined;
+ this.controller = undefined;
+ this.options = undefined;
+ this.visible = false;
+ this.rows = {};
+ this.id = id;
+ this.target = target;
+ this.controller = c;
+ this.options = options;
+ }
+ View.prototype.init = function () {
+ var _this = this;
+ var rowIds = Object.keys(this.controller.getData());
+ var rows = this.target.find(this.getItemClassName());
+ rows.each(function (index, elem) {
+ var classes = elem.classList;
+ for (var i = 0; i < classes.length; i++) {
+ if (rowIds.indexOf(classes[i]) >= 0) {
+ _this.rows[classes[i]] = $(rows[index]);
+ }
+ }
+ });
+ };
+ View.prototype.getItemClassName = function () {
+ return '.filtered-item';
+ };
+ View.prototype.getTargetElement = function () {
+ return this.target;
+ };
+ View.prototype.showRows = function (rowIds) {
+ var _this = this;
+ if (this.visible && rowIds.length < 200) {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].slideDown(400);
+ });
+ }
+ else {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].css('display', '');
+ });
+ }
+ };
+ View.prototype.hideRows = function (rowIds) {
+ var _this = this;
+ if (this.visible && rowIds.length < 200) {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].slideUp(400);
+ });
+ }
+ else {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].css('display', 'none');
+ });
+ }
+ };
+ View.prototype.show = function () {
+ this.target.show();
+ this.visible = true;
+ };
+ View.prototype.hide = function () {
+ this.target.hide();
+ this.visible = false;
+ };
+ return View;
+}());
+exports.View = View;
+
+},{}],12:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var ViewSelector = /** @class */ (function () {
+ function ViewSelector(target, viewIDs, controller) {
+ this.target = undefined;
+ this.viewIDs = undefined;
+ this.controller = undefined;
+ this.target = target;
+ this.viewIDs = viewIDs;
+ this.controller = controller;
+ }
+ ViewSelector.prototype.init = function () {
+ var _this = this;
+ if (this.viewIDs.length > 1) {
+ this.viewIDs.forEach(function (id) { _this.target.on('click', '.' + id, { 'target': id, 'controller': _this.controller }, ViewSelector.onSelectorSelected); });
+ this.target.children().first().addClass('selected');
+ this.target.show();
+ }
+ };
+ ViewSelector.onSelectorSelected = function (event) {
+ event.data.controller.onViewSelected(event.data.target);
+ $(event.target)
+ .addClass('selected')
+ .siblings().removeClass('selected');
+ event.stopPropagation();
+ event.preventDefault();
+ };
+ return ViewSelector;
+}());
+exports.ViewSelector = ViewSelector;
+
+},{}],13:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var Filtered_1 = require("./Filtered/Filtered");
+var config = mw.config.get('srfFilteredConfig');
+var _loop_1 = function (id) {
+ if (config.hasOwnProperty(id)) {
+ var f_1 = new Filtered_1.Filtered($('#' + id), config[id]);
+ mw.hook('wikipage.content').add(function () { return f_1.run(); });
+ }
+};
+for (var id in config) {
+ _loop_1(id);
+}
+
+},{"./Filtered/Filtered":6}]},{},[13])
+
+//# sourceMappingURL=ext.srf.filtered.js.map
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js.map b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js.map
new file mode 100644
index 00000000..20964633
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["node_modules/browser-pack/_prelude.js","resources/ts/Filtered/Controller.ts","resources/ts/Filtered/Filter/DistanceFilter.ts","resources/ts/Filtered/Filter/Filter.ts","resources/ts/Filtered/Filter/NumberFilter.ts","resources/ts/Filtered/Filter/ValueFilter.ts","resources/ts/Filtered/Filtered.ts","resources/ts/Filtered/View/CalendarView.ts","resources/ts/Filtered/View/ListView.ts","resources/ts/Filtered/View/MapView.ts","resources/ts/Filtered/View/TableView.ts","resources/ts/Filtered/View/View.ts","resources/ts/Filtered/ViewSelector.ts","resources/ts/bootstrap.ts"],"names":[],"mappings":"AAAA;;ACAA,gCAAgC;;AAKhC,oCAAmC;AAGnC;IAUC,oBAAoB,MAAc,EAAE,IAAgB,EAAE,aAAsB;QATpE,WAAM,GAAW,SAAS,CAAC;QAC3B,kBAAa,GAAW,SAAS,CAAC;QAElC,UAAK,GAA4B,EAAE,CAAC;QACpC,YAAO,GAA8B,EAAE,CAAC;QACxC,gBAAW,GAAS,SAAS,CAAC;QAKrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAK,IAAI,CAAC,MAAM,KAAK,SAAS,EAAG;YAChC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAE,6BAA6B,CAAE,CAAC;SACvE;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QAEnC,KAAM,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,EAAG;YAC9B,IAAK,CAAC,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,cAAc,CAAE,SAAS,CAAE,EAAG;gBACtD,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,GAAG,EAAE,CAAC;aAChC;SACD;IACF,CAAC;IAEM,4BAAO,GAAd;QACC,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAEM,qCAAgB,GAAvB;QACC,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEM,4BAAO,GAAd;QACC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAE,gBAAgB,CAAE,GAAG,8BAA8B,CAAC;IAC9E,CAAC;IAEM,+BAAU,GAAjB,UAAmB,MAAc,EAAE,IAAU;QAE5C,IAAI,CAAC,KAAK,CAAE,MAAM,CAAE,GAAG,IAAI,CAAC;QAE5B,IAAK,IAAI,CAAC,WAAW,KAAK,SAAS,EAAG;YACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,IAAI,EAAE,CAAC;SACZ;aAAM;YACN,IAAI,CAAC,IAAI,EAAE,CAAC;SACZ;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,4BAAO,GAAd,UAAgB,MAAc;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAE,MAAM,CAAE,CAAC;IAC7B,CAAC;IAEM,iCAAY,GAAnB,UAAqB,MAAc;QAClC,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAE9B,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,GAAG,MAAM,CAAC;QAElC,MAAM,CAAC,IAAI,EAAE,CAAC;QAEd,OAAO,IAAI,CAAC,eAAe,CAAE,QAAQ,CAAE,CAAC;IACzC,CAAC;IAEM,8BAAS,GAAhB,UAAkB,QAAgB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC;IACjC,CAAC;IAEM,yBAAI,GAAX;QACC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAE,mBAAmB,CAAE,CAAC,MAAM,EAAE,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,CAAE,IAAI,CAAC,WAAW,CAAE,CAAC;IACvC,CAAC;IAEO,iCAAY,GAApB,UAAsB,IAAU;QAE/B,IAAK,IAAI,CAAC,WAAW,YAAY,WAAI,EAAG;YACvC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;SACxB;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAExB,IAAK,IAAI,CAAC,WAAW,YAAY,WAAI,EAAG;YACvC,IAAI,CAAC,IAAI,EAAE,CAAC;SACZ;IAEF,CAAC;IAEO,sCAAiB,GAAzB;QACC,IAAI,MAAM,GAAa,EAAE,CAAC;QAC1B,IAAI,MAAM,GAAa,EAAE,CAAC;QAE1B,KAAM,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,EAAG;YAC9B,KAAM,IAAI,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAG;gBACpC,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,GAAG,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,SAAS,CAAE,KAAK,CAAE,CAAC;aAC9H;YACD,IAAK,IAAI,CAAC,SAAS,CAAE,KAAK,CAAE,EAAG;gBAC9B,MAAM,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;aACrB;iBAAM;gBACN,MAAM,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;aACrB;SACD;QAED,IAAI,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;IACzB,CAAC;IAEM,mCAAc,GAArB,UAAuB,MAAc;QACpC,IAAI,CAAC,YAAY,CAAE,IAAI,CAAC,KAAK,CAAE,MAAM,CAAE,CAAE,CAAC;IAC3C,CAAC;IAEM,oCAAe,GAAtB,UAAwB,QAAgB;QAAxC,iBA8BC;QA5BA,OAAO,IAAI,CAAC,WAAW,EAAE;aACxB,IAAI,CAAC;YAEL,IAAI,MAAM,GAAa,EAAE,CAAC;YAC1B,IAAI,MAAM,GAAa,EAAE,CAAC;YAE1B,IAAI,QAAQ,GAAG,KAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,UAAU,EAAE,CAAC;YAErD,KAAM,IAAI,KAAK,IAAI,KAAI,CAAC,IAAI,EAAG;gBAE9B,IAAI,UAAU,GAAY,QAAQ,IAAI,KAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,SAAS,CAAE,KAAK,CAAE,CAAC;gBAElF,IAAK,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,KAAK,UAAU,EAAG;oBAE5D,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,GAAG,UAAU,CAAC;oBAEpD,IAAK,UAAU,IAAI,KAAI,CAAC,SAAS,CAAE,KAAK,CAAE,EAAG;wBAC5C,MAAM,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;qBACrB;yBAAM;wBACN,MAAM,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;qBACrB;iBACD;aACD;YAED,KAAI,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;YACxB,KAAI,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;QACzB,CAAC,CAAC;aACD,IAAI,CAAE,cAAQ,KAAI,CAAC,WAAW,EAAE,CAAA,CAAC,CAAC,CAAE,CAAC;IACvC,CAAC;IAEM,8BAAS,GAAhB,UAAkB,KAAU;QAC3B,KAAM,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,EAAG;YAClD,IAAK,CAAC,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,EAAG;gBAC9C,OAAO,KAAK,CAAC;aACb;SACD;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,6BAAQ,GAAhB,UAAkB,MAAgB;QACjC,IAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG;YAC1B,OAAO;SACP;QACD,KAAM,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,EAAG;YAChC,IAAI,CAAC,KAAK,CAAE,MAAM,CAAE,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;SACxC;IACF,CAAC;IAEO,6BAAQ,GAAhB,UAAkB,MAAgB;QACjC,IAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG;YAC1B,OAAO;SACP;QACD,KAAM,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,EAAG;YAChC,IAAI,CAAC,KAAK,CAAE,MAAM,CAAE,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;SACxC;IACF,CAAC;IAEO,gCAAW,GAAnB;QACC,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;IAC9B,CAAC;IAEO,gCAAW,GAAnB;QACC,OAAO,IAAI,CAAC,cAAc,CAAE,KAAK,CAAE,CAAC;IACrC,CAAC;IAEO,mCAAc,GAAtB,UAAwB,IAAoB;QAApB,qBAAA,EAAA,WAAoB;QAE3C,IAAK,IAAI,CAAC,aAAa,KAAK,SAAS,EAAG;YACvC,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;SACrB;QAED,IAAK,IAAI,EAAG;YACX,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAE,GAAG,CAAE,CAAC,OAAO,EAAE,CAAC;SAClD;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAE,GAAG,CAAE,CAAC,OAAO,EAAE,CAAC;IACpD,CAAC;IAEF,iBAAC;AAAD,CAnMA,AAmMC,IAAA;AAnMY,gCAAU;;;;;;;;;;;;;;;;;;ACRvB,mCAAkC;AAIlC;IAAoC,kCAAM;IAA1C;QAAA,qEAyIC;QA/HQ,sBAAgB,GAAW,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;QACzD,iBAAW,GAAW,CAAC,CAAC;;IA8HjC,CAAC;IA5HO,6BAAI,GAAX;QAEC,IAAI,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QAEvC,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC;QAEtC,IAAK,CAAC,CAAE,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,CAAE,KAAK,CAAE,IAAI,MAAM,CAAC,cAAc,CAAE,KAAK,CAAE,CAAE,EAAG;YACpG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO;SACP;QAED,IAAI,IAAI,GAAG,IAAI,CAAC;QAEhB,IAAK,IAAI,CAAC,OAAO,CAAE,MAAM,CAAE,IAAI,cAAc,CAAC,WAAW,CAAE,IAAI,CAAC,OAAO,CAAE,MAAM,CAAE,CAAE,EAAG;YACrF,IAAI,GAAG,IAAI,CAAC,OAAO,CAAE,MAAM,CAAE,CAAC;SAC9B;QAED,IAAI,CAAC,gBAAgB,GAAG,cAAc,CAAC,WAAW,CAAE,IAAI,CAAE,CAAC;QAE3D,IAAI,QAAQ,GAAW,IAAI,CAAC,eAAe,CAAE,MAAM,CAAE,CAAC;QAEtD,IAAI,SAAS,GAAG,SAAA,EAAE,EAAI,CAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,GAAG,CAAE,QAAQ,CAAE,GAAG,IAAI,CAAC,MAAM,CAAE,GAAG,CAAC,CAAC,CAAA,CAAC;QAE9E,IAAK,IAAI,CAAC,OAAO,CAAE,KAAK,CAAE,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAE,KAAK,CAAE,GAAG,QAAQ,EAAG;YAC9E,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;SACjC;aAAM;YACN,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAE,QAAQ,GAAG,SAAS,CAAE,GAAG,SAAS,CAAC;SACzD;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAE,eAAe,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAE,IAAI,CAAC,OAAO,CAAE,eAAe,CAAE,EAAE,QAAQ,CAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;QAEtH,wBAAwB;QACxB,IAAI,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE9C,IAAI,OAAO,GAAG,CAAC,CAAE,yCAAyC,GAAG,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAE,CAAC;QAE3F,IAAI,KAAK,GAAG,CAAC,CAAE,iGAAiG;YAC/G,6FAA6F;YAC7F,yCAAyC,GAAG,QAAQ,GAAG,YAAY;YACnE,wDAAwD,GAAG,IAAI,GAAG,4BAA4B,CAAE,CAAC;QAElG,cAAc,CAAC,MAAM,CAAE,KAAK,CAAE,CAAC;QAE/B,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAE,kBAAkB,CAAE,CAAC,IAAI,CAAE;YAE3C,KAAK,CAAC,IAAI,CAAE,2BAA2B,CAAE;iBACxC,MAAM,CAAE;gBACR,OAAO,EAAE,IAAI;gBACb,GAAG,EAAE,QAAQ;gBACb,KAAK,EAAE,IAAI,CAAC,WAAW;gBACvB,IAAI,EAAE,SAAS,GAAG,GAAG;aACrB,CAAE;iBACF,EAAE,CAAE,aAAa,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,UAAW,WAA8B,EAAE,EAAO;gBACpG,WAAW,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;gBACzB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAE,WAAW,CAAE,CAAC;YACxD,CAAC,CAAE;iBACF,EAAE,CAAE,OAAO,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,UAAW,WAA8B,EAAE,EAAO;gBAC9F,OAAO,CAAC,IAAI,CAAE,EAAE,CAAC,KAAK,CAAE,CAAC;YAC1B,CAAC,CAAE;iBACF,IAAI,CAAE,mBAAmB,CAAE;iBAC3B,MAAM,CAAE,OAAO,CAAE,CAAC;QAEpB,CAAC,CAAE,CAAC;QAEJ,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,wCAAe,GAAvB,UAAyB,MAAuB;QAAhD,iBAqBC;QAnBA,IAAI,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,GAAG,GAAG,CAAC,CAAC;QAEZ,IAAI,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC;QAE/B,KAAM,IAAI,KAAK,IAAI,MAAM,EAAG;YAE3B,IAAK,MAAM,CAAE,KAAK,CAAE,CAAC,IAAI,CAAC,cAAc,CAAE,IAAI,CAAC,QAAQ,CAAE,EAAG;gBAC3D,IAAI,SAAS,GAAa,MAAM,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,SAAS,CAAC,GAAG,CAAE,UAAE,GAAoB,IAAM,OAAA,KAAI,CAAC,QAAQ,CAAE,MAAM,EAAE,GAAG,CAAE,EAA5B,CAA4B,CAAE,CAAC;gBAC1I,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,OAAR,IAAI,EAAS,SAAS,CAAE,CAAC;gBAEpC,MAAM,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACtD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAE,GAAG,EAAE,IAAI,CAAE,CAAC;aAC5B;iBAAM;gBACN,MAAM,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,QAAQ,GAAG,QAAQ,CAAC;aAC1D;SACD;QAED,OAAO,GAAG,CAAC;IACZ,CAAC;IAEM,wCAAe,GAAtB,UAAwB,WAA8B;QACrD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;QAC7C,IAAI,CAAC,UAAU,CAAC,eAAe,CAAE,IAAI,CAAC,KAAK,EAAE,CAAE,CAAC;IACjD,CAAC;IAEO,iCAAQ,GAAhB,UAAkB,CAAkB,EAAE,CAAkB;QAEvD,IAAM,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;QAEhC,SAAS,OAAO,CAAE,CAAS;YAC1B,OAAO,CAAC,GAAG,CAAC,CAAA;QACb,CAAC;QAED,IAAI,CAAC,GACJ,OAAO,CAAE,IAAI,CAAC,GAAG,CAAE,CAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAE,GAAG,OAAO,GAAG,GAAG,CAAE,CAAE;YACxD,IAAI,CAAC,GAAG,CAAE,CAAC,CAAC,GAAG,GAAG,OAAO,CAAE,GAAG,IAAI,CAAC,GAAG,CAAE,CAAC,CAAC,GAAG,GAAG,OAAO,CAAE;gBACzD,OAAO,CAAE,IAAI,CAAC,GAAG,CAAE,CAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAE,GAAG,OAAO,GAAG,GAAG,CAAE,CAAE,CAAC;QAE1D,OAAO,IAAI,CAAC,gBAAgB,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,IAAI,CAAE,CAAC,CAAE,EAAE,IAAI,CAAC,IAAI,CAAE,CAAC,GAAG,CAAC,CAAE,CAAE,CAAC;IACrF,CAAC;IAEM,kCAAS,GAAhB,UAAkB,KAAa;QAE9B,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAE,KAAK,CAAE,CAAC,IAAI,CAAC;QAEtD,IAAK,OAAO,CAAC,cAAc,CAAE,IAAI,CAAC,QAAQ,CAAE,EAAG;YAC9C,OAAO,OAAO,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC;SAC7D;QAED,OAAO,iBAAM,SAAS,YAAE,KAAK,CAAE,CAAC;IAEjC,CAAC;IArIuB,0BAAW,GAA8B;QAChE,CAAC,EAAE,SAAS;QACZ,EAAE,EAAE,SAAS;QACb,EAAE,EAAE,SAAS;QACb,EAAE,EAAE,SAAS;QACb,CAAC,EAAE,iBAAiB;KACpB,CAAC;IAiIH,qBAAC;CAzID,AAyIC,CAzImC,eAAM,GAyIzC;AAzIY,wCAAc;;;;;ACD3B;IAWC,gBAAoB,QAAgB,EAAE,MAAc,EAAE,cAAsB,EAAE,UAAsB,EAAE,OAAiB;QAT/G,gBAAW,GAAW,SAAS,CAAC;QAC9B,WAAM,GAAW,SAAS,CAAC;QAI3B,YAAO,GAAY,SAAS,CAAC;QAC7B,aAAQ,GAAY,KAAK,CAAC;QAC1B,cAAS,GAAY,KAAK,CAAC;QAGpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC;IAC9B,CAAC;IAEM,qBAAI,GAAX,cAAe,CAAC;IAAA,CAAC;IAEV,2BAAU,GAAjB;QACC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,wBAAO,GAAd;QAAA,iBAUC;QATA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,WAAW;aACf,WAAW,CAAE,SAAS,CAAE;aACxB,QAAQ,CAAE,UAAU,CAAE,CAAC;QAExB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAE,cAAM,OAAA,KAAI,CAAC,UAAU,CAAC,eAAe,CAAE,KAAI,CAAC,QAAQ,CAAE,EAAhD,CAAgD,CAAE,CAAC;IACtF,CAAC;IAEM,uBAAM,GAAb;QAAA,iBAYC;QAXA,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAEtB,IAAI,CAAC,WAAW;aACf,WAAW,CAAE,UAAU,CAAE;aACzB,QAAQ,CAAE,SAAS,CAAE,CAAC;QAEvB,IAAK,CAAE,IAAI,CAAC,SAAS,EAAG;YACvB,IAAI,CAAC,UAAU,EAAE,CAAC;SAClB;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAE,cAAM,OAAA,KAAI,CAAC,UAAU,CAAC,eAAe,CAAE,KAAI,CAAC,QAAQ,CAAE,EAAhD,CAAgD,CAAE,CAAC;IACtF,CAAC;IAEO,yBAAQ,GAAhB,UAAkB,QAAuB;QAAzC,iBAgBC;QAhBiB,yBAAA,EAAA,cAAuB;QAExC,IAAK,CAAE,IAAI,CAAC,SAAS,EAAG;YAEvB,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;iBACzB,IAAI,CAAE;gBAEN,KAAI,CAAC,MAAM,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC;gBAEhC,KAAI,CAAC,WAAW,CAAC,OAAO,CAAE;oBACzB,aAAa,EAAE,CAAC;oBAChB,gBAAgB,EAAE,CAAC;oBACnB,eAAe,EAAE,KAAK;iBACtB,EAAE,QAAQ,CAAE,CAAC;YACf,CAAC,CAAE,CAAC;SACJ;IACF,CAAC;IAEO,2BAAU,GAAlB;QAAA,iBAYC;QAXA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;aACzB,IAAI,CAAE;YACN,KAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAExB,IAAI,KAAK,GAAG,KAAI,CAAC,WAAW,CAAC,IAAI,CAAE,OAAO,CAAE,CAAC;YAC7C,KAAI,CAAC,WAAW,CAAC,UAAU,CAAE,OAAO,CAAE,CAAC;YACvC,IAAI,cAAc,GAAG,KAAI,CAAC,WAAW,CAAC,GAAG,CAAE,CAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,CAAE,CAAE,CAAC;YAClG,KAAI,CAAC,WAAW,CAAC,IAAI,CAAE,OAAO,EAAE,KAAK,CAAE,CAAC;YAExC,KAAI,CAAC,WAAW,CAAC,OAAO,CAAE,cAAc,CAAE,CAAC;QAC5C,CAAC,CAAE,CAAC;IACL,CAAC;IAEM,0BAAS,GAAhB,UAAkB,KAAa;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,mBAAmB,CAAE,IAAI,IAAI,CAAC,OAAO,CAAE,mBAAmB,CAAE,KAAK,IAAI,CAAC;IAC3G,CAAC;IAEM,sBAAK,GAAZ;QACC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAES,kCAAiB,GAA3B;QAEC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,yCAAyC,CAAE,CAAC;QAE7D,IAAI,CAAC,WAAW;aACf,MAAM,CAAE,IAAI,CAAC,MAAM,CAAE;aACrB,QAAQ,CAAE,SAAS,CAAE,CAAC;QAEvB,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAE/B,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEO,yBAAQ,GAAhB;QACC,0DAA0D;QAC1D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,0CAAsC,IAAI,CAAC,OAAO,CAAE,OAAO,CAAE,WAAQ,CAAE,CAAC;IAC7F,CAAC;IAES,+BAAc,GAAxB;QAAA,iBAuBC;QArBA,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,UAAU,CAAE,EAAG;YAEhD,IAAI,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAE,UAAU,CAAE,CAAC;YAE1C,IAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAE,QAAQ,EAAE,QAAQ,CAAE,IAAI,CAAC,EAAG;gBAElE,IAAI,YAAY,GAAG,CAAC,CAAE,gDAA8C,CAAE,CAAC;gBAEvE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,YAAY,CAAE,CAAC;gBAEnC,YAAY,CAAC,KAAK,CAAE;oBAEnB,IAAK,KAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAE,EAAG;wBAC5C,KAAI,CAAC,OAAO,EAAE,CAAC;qBACf;yBAAM;wBACN,KAAI,CAAC,MAAM,EAAE,CAAC;qBACd;gBAEF,CAAC,CAAE,CAAC;aACJ;SACD;IACF,CAAC;IAES,wCAAuB,GAAjC;QAAA,iBAqCC;QApCA,IAAI,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,aAAa,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAE,aAAa,CAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3G,IAAK,WAAW,KAAK,WAAW,IAAI,WAAW,KAAK,aAAa,EAAG;YAEnE,IAAI,iBAAe,GAAG,CAAC,CAAE,yCAAyC,CAAE,CAAC;YAErE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,iBAAe,CAAE,CAAC;YAEtC,iBAAe,CAAC,KAAK,CAAE;gBACtB,IAAK,iBAAe,CAAC,QAAQ,CAAE,WAAW,CAAE,EAAG;oBAC9C,KAAI,CAAC,UAAU,EAAE,CAAC;oBAClB,KAAI,CAAC,SAAS,GAAG,KAAK,CAAC;oBAEvB,iBAAe;yBACd,WAAW,CAAE,WAAW,CAAE;yBAC1B,QAAQ,CAAE,aAAa,CAAE,CAAC;iBAC3B;qBAAM;oBACN,KAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,KAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBAEtB,iBAAe;yBACd,WAAW,CAAE,aAAa,CAAE;yBAC5B,QAAQ,CAAE,WAAW,CAAE,CAAC;iBACzB;YAEF,CAAC,CAAE,CAAC;YAEJ,IAAK,WAAW,KAAK,WAAW,EAAG;gBAElC,IAAI,CAAC,QAAQ,CAAE,CAAC,CAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;gBACtB,iBAAe,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;aAEtC;iBAAM;gBACN,iBAAe,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;aACxC;SACD;IACF,CAAC;IAEF,aAAC;AAAD,CAhLA,AAgLC,IAAA;AAhLqB,wBAAM;;;;;;;;;;;;;;;;;;ACH5B,iFAAiF;AACjF,mCAAkC;AAKlC;IAAkC,gCAAM;IAAxC;QAAA,qEAyRC;QAvRQ,gBAAU,GAAG,CAAC,CAAC;QACf,cAAQ,GAAG,CAAC,CAAC;QACb,cAAQ,GAAG,CAAC,CAAC;QACb,iBAAW,GAAG,CAAC,CAAC;QAEhB,sBAAgB,GAAW,CAAC,CAAC;QAC7B,sBAAgB,GAAW,CAAC,CAAC;QAC7B,UAAI,GAAG,KAAI,CAAC,UAAU,CAAC;;IAgRhC,CAAC;IA9QO,2BAAI,GAAX;QAEC,IAAI,MAAM,GAAa,IAAI,CAAC,SAAS,EAAE,CAAC;QAEpC,IAAA,oCAAqE,EAAnE,sBAAQ,EAAE,sBAAQ,EAAE,wBAA+C,CAAC;QAE1E,IAAI,aAAa,GAA0B;YAC1C,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,IAAI;YACjB,IAAI,EAAE,IAAI;SACV,CAAC;QAEF,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE,EAAG;YAC9C,aAAa,GAAG,IAAI,CAAC,6BAA6B,CAAE,aAAa,EAAE,MAAM,CAAE,CAAC;SAE5E;aAAM;YACN,aAAa,GAAG,IAAI,CAAC,sCAAsC,CAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAE,CAAC;SAC5G;QAED,QAAQ,IAAI,CAAC,OAAO,CAAE,SAAS,CAAE,EAAG;YAEnC,KAAK,KAAK;gBAET,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC1B,aAAa,CAAC,IAAI,GAAG,QAAQ,CAAC;gBAC9B,MAAM;YAEP,KAAK,KAAK;gBAET,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC1B,aAAa,CAAC,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC;gBACtC,aAAa,CAAC,IAAI,GAAG,QAAQ,CAAC;gBAC9B,MAAM;YAEP,KAAK,QAAQ;gBAEZ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;gBAC7B,QAAQ,GAAG,QAAQ,CAAC;gBACpB,aAAa,CAAC,IAAI,GAAG,QAAQ,CAAC;gBAC9B,MAAM;YAEP,SAAS,kBAAkB;gBAE1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC5B,aAAa,CAAC,IAAI,GAAG,QAAQ,CAAC;SAC/B;QAED,IAAI,CAAC,mBAAmB,CAAE,aAAa,CAAE,CAAC;QAE1C,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QAEjC,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,6DAAsC,GAA9C,UAAgD,aAAoC,EAAE,QAAgB,EAAE,QAAgB,EAAE,SAAiB;QAA3I,iBAaC;QAXA,aAAa,CAAC,GAAG,GAAG,QAAQ,CAAC;QAC7B,aAAa,CAAC,GAAG,GAAG,QAAQ,CAAC;QAC7B,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAE,SAAS,CAAE,CAAC;QAC/C,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,CAAE,QAAQ,GAAG,QAAQ,CAAE,GAAG,aAAa,CAAC,IAAI,CAAE,CAAE,CAAC;QAEnG,aAAa,CAAC,IAAI,GAAG,QAAQ,CAAC;QAC9B,aAAa,CAAC,EAAE,GAAG,QAAQ,CAAC;QAE5B,aAAa,CAAC,QAAQ,GAAG,UAAE,IAAyB,IAAM,OAAA,KAAI,CAAC,eAAe,CAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAE,EAA1C,CAA0C,CAAC;QAErG,OAAO,aAAa,CAAC;IACtB,CAAC;IAEO,oDAA6B,GAArC,UAAuC,aAAoC,EAAE,MAAgB;QAA7F,iBAUC;QARA,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC;QAE9B,aAAa,CAAC,IAAI,GAAG,CAAC,CAAC;QACvB,aAAa,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAErC,aAAa,CAAC,QAAQ,GAAG,UAAE,IAAyB,IAAM,OAAA,KAAI,CAAC,eAAe,CAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAE,EAAtD,CAAsD,CAAC;QAEjH,OAAO,aAAa,CAAC;IACtB,CAAC;IAEO,yCAAkB,GAA1B,UAA4B,MAAgB;QAE3C,IAAI,QAAQ,GAAG,MAAM,CAAE,CAAC,CAAE,CAAC;QAC3B,IAAI,QAAQ,GAAG,MAAM,CAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;QAC3C,IAAI,SAAS,GAAW,IAAI,CAAC,YAAY,CAAE,QAAQ,EAAE,QAAQ,CAAE,CAAC;QAEhE,IAAK,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE,EAAG;YAC/C,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAE,QAAQ,EAAE,SAAS,CAAE,CAAC;YACzD,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAE,QAAQ,EAAE,SAAS,CAAE,CAAC;SACzD;QAED,OAAO,EAAE,QAAQ,UAAA,EAAE,QAAQ,UAAA,EAAE,SAAS,WAAA,EAAE,CAAC;IAC1C,CAAC;IAEO,gCAAS,GAAjB;QACC,IAAI,MAAgB,CAAC;QACrB,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE,IAAI,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,CAAC,CAAC,KAAK,MAAM,EAAG;YACxF,MAAM,GAAI,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAA;SAClC;aAAM;YACN,MAAM,GAAI,IAAI,CAAC,eAAe,EAAE,CAAC;SACjC;QAED,IAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG;YAC1B,MAAM,GAAG,CAAE,CAAC,EAAE,CAAC,CAAE,CAAC;SAClB;aAAM,IAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG;YACjC,MAAM,CAAC,IAAI,CAAE,MAAM,CAAE,CAAC,CAAE,CAAE,CAAC;SAC3B;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEO,0CAAmB,GAA3B,UAA6B,aAAoC;QAEhE,IAAI,gBAAgB,GAAQ,EAAE,CAAC;QAC/B,gBAAgB,CAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAE,GAAG,UAAU,CAAC;QAC1D,gBAAgB,CAAE,IAAI,CAAC,QAAQ,CAAE,GAAG,UAAU,CAAC;QAC/C,gBAAgB,CAAE,IAAI,CAAC,UAAU,CAAE,GAAG,YAAY,CAAC;QACnD,gBAAgB,CAAE,IAAI,CAAC,WAAW,CAAE,GAAG,aAAa,CAAC;QAErD,IAAI,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE9C,IAAI,MAAM,GAAG,CAAC,CAAE,gCAAgC,CAAE,CAAC;QACnD,IAAI,eAAe,GAAG,CAAC,CAAE,yCAAsC,gBAAgB,CAAE,IAAI,CAAC,IAAI,CAAE,UAAM,CAAE,CAAC,MAAM,CAAE,MAAM,CAAE,CAAC;QACtH,cAAc,CAAC,MAAM,CAAE,eAAe,CAAE,CAAC;QAEzC,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,SAAS,CAAE,EAAG;YAC/C,IAAI,OAAO,GAAG,4CAAwC,IAAI,CAAC,OAAO,CAAE,SAAS,CAAE,WAAQ,CAAC;YACxF,cAAc,CAAC,MAAM,CAAE,OAAO,CAAE,CAAC;SACjC;QAED,EAAE,CAAC,MAAM,CAAC,KAAK,CAAE,yBAAyB,CAAE,CAAC,IAAI,CAAE,cAAM,OAAA,MAAM,CAAC,cAAc,CAAE,aAAa,CAAE,EAAtC,CAAsC,CAAE,CAAC;IACnG,CAAC;IAEO,wCAAiB,GAAzB,UAA2B,QAAgB,EAAE,SAAiB;QAC7D,IAAI,YAAY,GAAG,IAAI,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;QAEzC,IAAK,YAAY,KAAK,SAAS,IAAI,KAAK,CAAE,MAAM,CAAE,YAAY,CAAE,CAAE,EAAG;YACpE,OAAO,IAAI,CAAC,KAAK,CAAE,QAAQ,GAAG,SAAS,CAAE,GAAG,SAAS,CAAC;SACtD;QAED,OAAO,IAAI,CAAC,GAAG,CAAE,YAAY,EAAE,QAAQ,CAAE,CAAC;IAC3C,CAAC;IAEO,wCAAiB,GAAzB,UAA2B,QAAgB,EAAE,SAAiB;QAC7D,IAAI,YAAY,GAAG,IAAI,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;QAEzC,IAAK,YAAY,KAAK,SAAS,IAAI,KAAK,CAAE,MAAM,CAAE,YAAY,CAAE,CAAE,EAAG;YACpE,OAAO,IAAI,CAAC,IAAI,CAAE,QAAQ,GAAG,SAAS,CAAE,GAAG,SAAS,CAAC;SACrD;QAED,OAAO,IAAI,CAAC,GAAG,CAAE,YAAY,EAAE,QAAQ,CAAE,CAAC;IAC3C,CAAC;IAEO,mCAAY,GAApB,UAAsB,QAAgB,EAAE,QAAgB;QACvD,IAAK,QAAQ,GAAG,QAAQ,GAAG,CAAC,EAAG;YAC9B,OAAO,SAAA,EAAE,EAAI,CAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,GAAG,CAAE,QAAQ,GAAG,QAAQ,CAAE,GAAG,IAAI,CAAC,MAAM,CAAE,GAAG,CAAC,CAAE,CAAA,CAAC;SACjF;aAAM;YACN,OAAO,CAAC,CAAC;SACT;IACF,CAAC;IAEO,8BAAO,GAAf,UAAiB,SAAiB;QAEjC,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAE,MAAM,CAAE,CAAC;QAElC,IAAK,IAAI,KAAK,SAAS,EAAG;YAEzB,IAAI,GAAG,MAAM,CAAE,IAAI,CAAE,CAAC;YAEtB,IAAK,CAAC,KAAK,CAAE,IAAI,CAAE,EAAG;gBACrB,OAAO,IAAI,CAAC;aACZ;SACD;QAED,OAAO,SAAS,GAAG,EAAE,CAAC;IACvB,CAAC;IAEO,yCAAkB,GAA1B;QAEC,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,GAAG,GAAG,QAAQ,CAAC;QACnB,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QAEpB,KAAM,IAAI,KAAK,IAAI,IAAI,EAAG;YAEzB,IAAK,IAAI,CAAE,KAAK,CAAE,CAAC,IAAI,CAAC,cAAc,CAAE,IAAI,CAAC,QAAQ,CAAE,EAAG;gBACzD,IAAI,MAAM,GAAa,IAAI,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,MAAM,CAAC;gBAClE,GAAG,GAAG,IAAI,CAAC,GAAG,OAAR,IAAI,GAAM,GAAG,SAAK,MAAM,EAAE,CAAC;gBACjC,GAAG,GAAG,IAAI,CAAC,GAAG,OAAR,IAAI,GAAM,GAAG,SAAK,MAAM,EAAE,CAAC;aACjC;SACD;QAED,OAAO,CAAE,GAAG,EAAE,GAAG,CAAE,CAAC;IACrB,CAAC;IAEO,sCAAe,GAAvB;QAEC,IAAI,UAAU,GAAa,EAAE,CAAC;QAC9B,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QAErC,KAAM,IAAI,KAAK,IAAI,IAAI,EAAG;YAEzB,IAAI,KAAK,GAAG,IAAI,CAAE,KAAK,CAAE,CAAC,IAAI,CAAC;YAE/B,IAAK,KAAK,CAAC,cAAc,CAAE,IAAI,CAAC,QAAQ,CAAE,EAAG;gBAE5C,IAAI,MAAM,GAAG,KAAK,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,MAAM,CAAC;gBAE3C,KAAM,IAAI,OAAO,IAAI,MAAM,EAAG;oBAE7B,IAAI,KAAK,GAAG,MAAM,CAAE,MAAM,CAAE,OAAO,CAAE,CAAE,CAAC;oBAExC,IAAK,UAAU,CAAC,OAAO,CAAE,KAAK,CAAE,KAAK,CAAC,CAAC,EAAG;wBACzC,UAAU,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;qBACzB;iBACD;aACD;SACD;QAED,OAAO,UAAU,CAAC,IAAI,CAAE,UAAE,CAAM,EAAE,CAAM,IAAM,OAAA,CAAC,GAAG,CAAC,EAAL,CAAK,CAAE,CAAC;IACvD,CAAC;IAEM,sCAAe,GAAtB,UAAwB,IAAY,EAAE,EAAU;QAE/C,QAAS,IAAI,CAAC,IAAI,EAAG;YAEpB,KAAK,IAAI,CAAC,QAAQ;gBAEjB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,MAAM;YAEP,KAAK,IAAI,CAAC,QAAQ;gBAEjB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,MAAM;YAEP,KAAK,IAAI,CAAC,WAAW;gBAEpB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,MAAM;YAEP,SAAS,wBAAwB;gBAEhC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;SAC5B;QAED,IAAI,CAAC,UAAU,CAAC,eAAe,CAAE,IAAI,CAAC,KAAK,EAAE,CAAE,CAAC;IACjD,CAAC;IAEM,gCAAS,GAAhB,UAAkB,KAAa;QAC9B,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAE,KAAK,CAAE,CAAC,IAAI,CAAC;QAEtD,IAAK,OAAO,CAAC,cAAc,CAAE,IAAI,CAAC,QAAQ,CAAE,IAAI,OAAO,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAG;YAE5F,KAAmB,UAA+B,EAA/B,KAAA,OAAO,CAAE,IAAI,CAAC,QAAQ,CAAE,CAAC,MAAM,EAA/B,cAA+B,EAA/B,IAA+B,EAAG;gBAA/C,IAAI,KAAK,SAAA;gBACd,IAAK,KAAK,IAAI,IAAI,CAAC,gBAAgB,IAAI,KAAK,IAAI,IAAI,CAAC,gBAAgB,EAAG;oBACvE,OAAO,IAAI,CAAC;iBACZ;aACD;YAED,OAAO,KAAK,CAAC;SACb;QAED,OAAO,iBAAM,SAAS,YAAE,KAAK,CAAE,CAAC;IACjC,CAAC;IAEF,mBAAC;AAAD,CAzRA,AAyRC,CAzRiC,eAAM,GAyRvC;AAzRY,oCAAY;;;;;;;;;;;;;;;;;;ACNzB,mCAAkC;AAKlC;IAAiC,+BAAM;IAAvC;QAAA,qEAuOC;QArOQ,YAAM,GAAQ,EAAE,CAAC;QACjB,mBAAa,GAAa,EAAE,CAAC;QAE7B,YAAM,GAAG,IAAI,CAAC;;IAkOvB,CAAC;IAhOO,0BAAI,GAAX;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrC,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAEM,2BAAK,GAAZ,UAAc,KAAc;QAC3B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,UAAU,CAAC,eAAe,CAAE,IAAI,CAAC,KAAK,EAAE,CAAE,CAAC;IACjD,CAAC;IAEO,qCAAe,GAAvB;QAEC,4CAA4C;QAC5C,IAAI,cAAc,GAAQ,EAAE,CAAC;QAC7B,iDAAiD;QACjD,IAAI,kBAAkB,GAAQ,EAAE,CAAC;QAEjC,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE,EAAG;YAE9C,OAAO,IAAI,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,GAAG,CAClC,UAAE,IAAY;gBACb,OAAO;oBACN,aAAa,EAAE,IAAI;oBACnB,cAAc,EAAE,IAAI;iBACpB,CAAC;YACH,CAAC,CACD,CAAC;SAEF;aAAM;YACN,0DAA0D;YAC1D,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,aAAa,GAAU,EAAE,CAAC;YAC9B,KAAM,IAAI,EAAE,IAAI,IAAI,EAAG;gBAEtB,IAAI,cAAc,GAAQ,IAAI,CAAE,EAAE,CAAE,CAAE,WAAW,CAAE,CAAE,IAAI,CAAC,cAAc,CAAE,CAAE,QAAQ,CAAE,CAAC;gBACvF,IAAI,uBAAuB,GAAG,IAAI,CAAE,EAAE,CAAE,CAAE,WAAW,CAAE,CAAE,IAAI,CAAC,cAAc,CAAE,CAAE,kBAAkB,CAAE,CAAC;gBACrG,IAAI,kBAAkB,GAAQ,IAAI,CAAE,EAAE,CAAE,CAAE,WAAW,CAAE,CAAE,IAAI,CAAC,cAAc,CAAE,CAAE,aAAa,CAAE,CAAC;gBAEhG,KAAM,IAAI,CAAC,IAAI,cAAc,EAAG;oBAC/B,IAAI,sBAAsB,GAAG,uBAAuB,CAAE,CAAC,CAAE,CAAC;oBAE1D,IAAK,sBAAsB,CAAC,OAAO,CAAE,IAAI,CAAE,GAAG,CAAC,CAAC,EAAG;wBAClD,sBAAsB,GAAG,iBAAiB,CAAC,IAAI,CAAE,sBAAsB,CAAE,CAAE,CAAC,CAAE,CAAC;qBAC/E;oBAED,cAAc,CAAE,cAAc,CAAE,CAAC,CAAE,CAAE,GAAG,sBAAsB,CAAC;oBAC/D,kBAAkB,CAAE,cAAc,CAAE,CAAC,CAAE,CAAE,GAAG,kBAAkB,CAAE,CAAC,CAAE,CAAC;iBACpE;aAED;YAED,KAAM,IAAI,aAAa,IAAI,kBAAkB,EAAG;gBAC/C,aAAa,CAAC,IAAI,CAAE;oBACnB,aAAa,EAAE,aAAa;oBAC5B,SAAS,EAAE,kBAAkB,CAAE,aAAa,CAAE;oBAC9C,cAAc,EAAE,cAAc,CAAE,aAAa,CAAE;iBAC/C,CAAE,CAAC;aACJ;YAED,aAAa,CAAC,IAAI,CACjB,UAAE,CAAM,EAAE,CAAM;gBACf,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAE,CAAC,CAAC,SAAS,CAAE,CAAC;YACjD,CAAC,CAAE,CAAC;YACL,OAAO,aAAa,CAAC;SAErB;IAEF,CAAC;IAEO,kCAAY,GAApB;QAEC,IAAI,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE9C,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAAE,cAAc,CAAE,CAAC;QAE9D,IAAI,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,gBAAgB,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAE,gBAAgB,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3G,IAAK,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,aAAa,EAAG;YACzC,cAAc,CAAC,MAAM,CAAE,IAAI,CAAC,mBAAmB,EAAE,CAAE,CAAC;SACpD;aAAM;YACN,cAAc,CAAC,MAAM,CAAE,IAAI,CAAC,oBAAoB,EAAE,CAAE,CAAC;SACrD;IAEF,CAAC;IAEO,0CAAoB,GAA5B;QAAA,iBAiBC;QAfA,IAAI,UAAU,GAAG,CAAC,CAAE,8DAA8D,CAAE,CAAC;QAErF,yCAAyC;QACzC,KAAmB,UAAW,EAAX,KAAA,IAAI,CAAC,MAAM,EAAX,cAAW,EAAX,IAAW,EAAG;YAA3B,IAAI,KAAK,SAAA;YACd,UAAU,CAAC,MAAM,CAAE,kFAA2E,KAAK,CAAC,aAAa,wDAA+C,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,aAAa,0BAAsB,CAAE,CAAC;SACpO;QAED,uBAAuB;QACvB,UAAU;aACT,EAAE,CAAE,QAAQ,EAAE,WAAW,EAAE,UAAE,WAA8B;YAC3D,IAAI,eAAe,GAAsB,WAAW,CAAC,aAAa,CAAC;YACnE,KAAI,CAAC,eAAe,CAAE,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAE,CAAC;QACxE,CAAC,CAAE,CAAC;QAEJ,OAAO,UAAU,CAAC;IACnB,CAAC;IAEO,yCAAmB,GAA3B;QAAA,iBAiCC;QA/BA,IAAI,MAAM,GAAG,CAAC,CAAE,6DAA6D,CAAE,CAAC;QAEhF,IAAI,IAAI,GAAiB,EAAE,CAAC;QAE5B,mEAAmE;QACnE,KAAmB,UAAW,EAAX,KAAA,IAAI,CAAC,MAAM,EAAX,cAAW,EAAX,IAAW,EAAG;YAA3B,IAAI,KAAK,SAAA;YACd,iDAAiD;YACjD,IAAI,KAAK,GAAG,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,aAAa,CAAC;YACxD,IAAI,CAAC,IAAI,CAAE,EAAE,EAAE,EAAE,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,CAAE,CAAC;SAEtD;QAED,EAAE,CAAC,MAAM,CAAC,KAAK,CAAE,sCAAsC,CAAE,CAAC,IAAI,CAAE;YAE/D,MAAM,CAAC,OAAO,CAAE;gBACf,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,EAAE,CAAC,OAAO,CAAE,uCAAuC,CAAE,CAAC,IAAI,EAAE;gBACzE,IAAI,EAAE,IAAI;aACV,CAAE,CAAC;YAEJ,MAAM,CAAC,EAAE,CAAE,gBAAgB,EAAE,UAAE,CAAM;gBACpC,KAAI,CAAC,eAAe,CAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAE,CAAC;YAChD,CAAC,CAAE,CAAC;YAEJ,MAAM,CAAC,EAAE,CAAE,kBAAkB,EAAE,UAAE,CAAM;gBACtC,KAAI,CAAC,eAAe,CAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAE,CAAC;YACjD,CAAC,CAAE,CAAC;QAEL,CAAC,CAAE,CAAC;QAEJ,OAAO,MAAM,CAAC;IACf,CAAC;IAEO,2CAAqB,GAA7B,UAA+B,cAAsB;QACpD,kBAAkB;QAClB,IAAI,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,UAAU,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAE,UAAU,CAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAElG,IAAK,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,CAAE,QAAQ,EAAE,QAAQ,CAAE,IAAI,CAAC,EAAG;YAErE,IAAI,cAAc,GAAG,CAAC,CAAE,uCAAuC,CAAE,CAAC;YAElE,IAAI,YAAY,GAAG,CAAC,CAAE,oCAAoC,CAAE,CAAC;YAE7D,IAAI,SAAS,GAAG,IAAI,CAAC,eAAe,CAAE,IAAI,EAAE,IAAI,CAAE,CAAC;YACnD,IAAI,UAAU,GAAG,IAAI,CAAC,eAAe,CAAE,KAAK,CAAE,CAAC;YAE/C,YAAY;iBACX,MAAM,CAAE,SAAS,CAAE;iBACnB,MAAM,CAAE,UAAU,CAAE;iBACpB,QAAQ,CAAE,cAAc,CAAE,CAAC;YAE5B,YAAY;iBACX,IAAI,CAAE,OAAO,CAAE;iBACf,EAAE,CAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,UAAE,WAA8B;gBAC7E,OAAA,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,WAAW,CAAC,MAAM,CAAC,YAAY,CAAE,OAAO,CAAE,KAAK,IAAI,CAAE;YAApF,CAAoF,CACpF,CAAC;YAGF,cAAc,CAAC,MAAM,CAAE,cAAc,CAAE,CAAC;SACxC;QAED,OAAO,cAAc,CAAC;IACvB,CAAC;IAEO,qCAAe,GAAvB,UAAyB,IAAY,EAAE,SAA0B;QAA1B,0BAAA,EAAA,iBAA0B;QAEhE,IAAI,WAAW,GAAG,SAAS,CAAA,CAAC,CAAA,SAAS,CAAA,CAAC,CAAA,EAAE,CAAC;QACzC,IAAI,SAAS,GAAG,EAAE,CAAC,OAAO,CAAE,4BAA4B,GAAG,IAAI,CAAE,CAAC,IAAI,EAAE,CAAC;QAEzE,IAAI,WAAW,GACd,iCAA8B,IAAI,SAAI,IAAI,CAAC,cAAc,QAAI;aAC7D,iDAA4C,IAAI,CAAC,cAAc,mCAA4B,IAAI,+BAAwB,IAAI,SAAI,IAAI,CAAC,cAAc,mBAAY,IAAI,WAAK,WAAW,MAAG,CAAA;aAClL,SAAS,aAAU,CAAA,CAAC;QAExB,OAAO,CAAC,CAAE,WAAW,CAAE,CAAC;IACzB,CAAC;IAEM,+BAAS,GAAhB,UAAkB,KAAa;QAE9B,IAAK,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAG;YACtC,OAAO,IAAI,CAAC;SACZ;QAED,IAAI,MAAM,GAAa,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAE,KAAK,CAAE,CAAC,SAAS,CAAE,IAAI,CAAC,cAAc,CAAE,CAAC,MAAM,CAAC;QAElG,IAAK,MAAM,CAAC,MAAM,KAAK,CAAC,EAAG;YAC1B,OAAO,iBAAM,SAAS,YAAE,KAAK,CAAE,CAAC;SAChC;QAGD,IAAK,IAAI,CAAC,MAAM,EAAG;YAClB,KAA2B,UAAkB,EAAlB,KAAA,IAAI,CAAC,aAAa,EAAlB,cAAkB,EAAlB,IAAkB,EAAG;gBAA1C,IAAI,aAAa,SAAA;gBACtB,IAAK,MAAM,CAAC,OAAO,CAAE,aAAa,CAAE,IAAI,CAAC,EAAG;oBAC3C,OAAO,IAAI,CAAC;iBACZ;aACD;YACD,OAAO,KAAK,CAAC;SACb;aAAM;YACN,KAA2B,UAAkB,EAAlB,KAAA,IAAI,CAAC,aAAa,EAAlB,cAAkB,EAAlB,IAAkB,EAAG;gBAA1C,IAAI,aAAa,SAAA;gBACtB,IAAK,MAAM,CAAC,OAAO,CAAE,aAAa,CAAE,GAAG,CAAC,EAAG;oBAC1C,OAAO,KAAK,CAAC;iBACb;aACD;YACD,OAAO,IAAI,CAAC;SACZ;IACF,CAAC;IAEM,qCAAe,GAAtB,UAAwB,KAAa,EAAE,SAAkB;QACxD,IAAI,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;QAEhD,IAAK,SAAS,IAAI,KAAK,KAAK,CAAC,CAAC,EAAG;YAChC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC;SACjC;aAAM,IAAK,CAAC,SAAS,IAAI,KAAK,IAAI,CAAC,EAAG;YACtC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAE,KAAK,EAAE,CAAC,CAAE,CAAC;SACtC;QAED,IAAI,CAAC,UAAU,CAAC,eAAe,CAAE,IAAI,CAAC,KAAK,EAAE,CAAE,CAAC;IACjD,CAAC;IACF,kBAAC;AAAD,CAvOA,AAuOC,CAvOgC,eAAM,GAuOtC;AAvOY,kCAAW;;;;;ACJxB,2CAA0C;AAC1C,+CAA8C;AAC9C,oCAAmC;AACnC,4CAA2C;AAC3C,8CAA6C;AAC7C,0CAAyC;AACzC,oDAAmD;AAEnD,oDAAmD;AACnD,0DAAyD;AACzD,sDAAqD;AAErD;;;;GAIG;AACH;IAkBC;;;;OAIG;IACH,kBAAoB,MAAc,EAAE,MAAW;QAlBvC,cAAS,GAAwG;YACxH,KAAK,EAAE,qBAAS;YAChB,IAAI,EAAE,mBAAQ;YACd,GAAG,EAAE,iBAAO;YACZ,QAAQ,EAAE,2BAAY;SACtB,CAAC;QAEM,gBAAW,GAAsI;YACxJ,KAAK,EAAE,yBAAW;YAClB,QAAQ,EAAE,+BAAc;YACxB,MAAM,EAAE,2BAAY;SACpB,CAAC;QAQD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,sBAAG,GAAV;QAEC,IAAI,UAAU,GAAG,IAAI,uBAAU,CAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAE,CAAC;QAE5F,IAAI,CAAC,aAAa,CAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAE,sBAAsB,CAAE,CAAE,CAAC;QACjF,IAAI,CAAC,kBAAkB,CAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAE,wCAAwC,CAAE,CAAE,CAAC;QACpG,IAAI,CAAC,WAAW,CAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAE,8BAA8B,CAAE,CAAE,CAAC;QAEnF,WAAW;QACX,UAAU,CAAC,IAAI,EAAE,CAAC;IAEnB,CAAC;IAEO,gCAAa,GAArB,UAAuB,UAAsB,EAAE,gBAAwB;QAEtE,KAAM,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAG;YAE7C,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAE,IAAI,CAAE,CAAC;YAE3C,IAAK,EAAE,CAAC,cAAc,CAAE,SAAS,CAAE,EAAG;gBAErC,KAAM,IAAI,QAAQ,IAAI,EAAE,CAAC,OAAO,EAAG;oBAElC,IAAK,EAAE,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE;wBACzC,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,cAAc,CAAE,MAAM,CAAE;wBAC/C,IAAI,CAAC,WAAW,CAAC,cAAc,CAAE,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,IAAI,CAAE,EAAG;wBAEjE,yCAAyC;wBACzC,4CAA4C;wBAC5C,IAAI,MAAM,GAAW,IAAI,IAAI,CAAC,WAAW,CAAE,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAC,IAAI,CAAE,CAAE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAE,GAAG,GAAG,QAAQ,CAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,OAAO,CAAE,QAAQ,CAAE,CAAE,CAAC;wBAE5K,UAAU,CAAC,YAAY,CAAE,MAAM,CAAE,CAAC;qBAElC;iBACD;aACD;SAED;IACF,CAAC;IAEO,qCAAkB,GAA1B,UAA4B,UAAsB,EAAE,qBAA6B;QAChF,IAAI,YAAY,GAAG,IAAI,2BAAY,CAAE,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,EAAE,UAAU,CAAE,CAAC;QAC3G,YAAY,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAEO,8BAAW,GAAnB,UAAqB,UAAsB,EAAE,cAAsB;QAElE,eAAe;QACf,KAAM,IAAI,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAG;YAEvC,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,MAAM,CAAE,CAAE,MAAM,CAAE,CAAC;YACrD,IAAI,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAE,QAAQ,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAE,QAAQ,CAAE,CAAC,CAAC,CAAC,WAAI,CAAC;YAErG,IAAI,IAAI,GAAS,IAAI,gBAAgB,CAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAE,GAAG,GAAG,MAAM,CAAE,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,MAAM,CAAE,CAAE,CAAC;YAElI,IAAI,CAAC,IAAI,EAAE,CAAC;YAEZ,UAAU,CAAC,UAAU,CAAE,MAAM,EAAE,IAAI,CAAE,CAAC;SAEtC;IACF,CAAC;IACF,eAAC;AAAD,CAzFA,AAyFC,IAAA;AAzFY,4BAAQ;;;;;;;;;;;;;;;;;;AClBrB,+BAA8B;AAG9B;IAAkC,gCAAI;IAAtC;;IAsHA,CAAC;IApHQ,8BAAO,GAAf;QACC,OAAO;YACN,UAAU,EAAE,CAAE,EAAE,CAAC,GAAG,CAAE,SAAS,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,OAAO,CAAE;gBACzE,EAAE,CAAC,GAAG,CAAE,OAAO,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,MAAM,CAAE;gBACzD,EAAE,CAAC,GAAG,CAAE,MAAM,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,QAAQ,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,WAAW,CAAE;gBAC3D,EAAE,CAAC,GAAG,CAAE,SAAS,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE;aAC/D;YACD,eAAe,EAAE,CAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;gBACnE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;gBACjD,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;gBACjD,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;aACjD;YACD,QAAQ,EAAE,CAAE,EAAE,CAAC,GAAG,CAAE,QAAQ,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,QAAQ,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,SAAS,CAAE;gBACtE,EAAE,CAAC,GAAG,CAAE,WAAW,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,QAAQ,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,UAAU,CAAE;aACrF;YACD,aAAa,EAAE,CAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;gBACjE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE,EAAE,EAAE,CAAC,GAAG,CAAE,KAAK,CAAE;aAClE;YACD,UAAU,EAAE;gBACX,KAAK,EAAE,EAAE,CAAC,GAAG,CAAE,kCAAkC,CAAE;gBACnD,KAAK,EAAE,EAAE,CAAC,GAAG,CAAE,kCAAkC,CAAE;gBACnD,IAAI,EAAE,EAAE,CAAC,GAAG,CAAE,iCAAiC,CAAE;gBACjD,GAAG,EAAE,EAAE,CAAC,GAAG,CAAE,gCAAgC,CAAE;aAC/C;YAED,UAAU,EAAE,EAAE,CAAC,GAAG,CAAE,mCAAmC,CAAE;YACzD,UAAU,EAAE;gBACX,EAAE,EAAE,EAAE,CAAC,GAAG,CAAE,kCAAkC,CAAE;gBAChD,MAAM,EAAE,EAAE,CAAC,GAAG,CAAE,yCAAyC,CAAE;aAC3D;YAED,UAAU,EAAE,EAAE,CAAC,GAAG,CAAE,kCAAkC,CAAE;YACxD,WAAW,EAAE;gBACZ,KAAK,EAAE,EAAE,CAAC,GAAG,CAAE,yCAAyC,CAAE;gBAC1D,IAAI,EAAE,EAAE,CAAC,GAAG,CAAE,wCAAwC,CAAE;gBACxD,GAAG,EAAE,EAAE,CAAC,GAAG,CAAE,uCAAuC,CAAE;aACtD;YAED,YAAY,EAAE;gBACb,KAAK,EAAE,EAAE,CAAC,GAAG,CAAE,0CAA0C,CAAE;gBAC3D,IAAI,EAAE,EAAE,CAAC,GAAG,CAAE,yCAAyC,CAAE;gBACzD,GAAG,EAAE,EAAE,CAAC,GAAG,CAAE,wCAAwC,CAAE;aACvD;SACD,CAAC;IACH,CAAC;IAEM,2BAAI,GAAX;QAEC,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE3B,0BAA0B;QAC1B,IAAI,CAAC,MAAM,CAAC,YAAY,CAAE;YAEzB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAC/B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;YACzB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;SAChC,CAAE,CAAC;IACL,CAAC;IAEO,+BAAQ,GAAhB,UAAkB,KAAU,EAAE,OAAY;QAEzC,IAAI,SAAS,GAAQ;YACpB,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,OAAO,CAAE,OAAO,CAAE;YACzB,KAAK,EAAE,OAAO,CAAE,OAAO,CAAE;YACzB,SAAS,EAAE,KAAK;SAChB,CAAC;QAEF,IAAK,OAAO,CAAC,cAAc,CAAE,KAAK,CAAE,EAAG;YACtC,SAAS,CAAE,KAAK,CAAE,GAAG,OAAO,CAAE,KAAK,CAAE,CAAC;SACtC;QAED,IAAK,OAAO,CAAC,cAAc,CAAE,KAAK,CAAE,EAAG;YACtC,SAAS,CAAE,KAAK,CAAE,GAAG,OAAO,CAAE,KAAK,CAAE,CAAC;SACtC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAEM,+BAAQ,GAAf,UAAiB,MAAgB;QAAjC,iBAcC;QAZA,IAAI,MAAM,GAAU,EAAE,CAAC;QAEvB,MAAM,CAAC,OAAO,CAAE,UAAE,KAAa;YAE9B,IAAI,OAAO,GAAG,KAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,KAAI,CAAC,EAAE,CAAE,CAAC;YAEjE,IAAK,OAAO,CAAC,cAAc,CAAE,OAAO,CAAE,EAAG;gBACxC,MAAM,CAAC,IAAI,CAAE,KAAI,CAAC,QAAQ,CAAE,KAAK,EAAE,OAAO,CAAE,CAAE,CAAC;aAC/C;QACF,CAAC,CAAE,CAAC;QAEJ,IAAI,CAAC,MAAM,CAAC,YAAY,CAAE,gBAAgB,EAAE,MAAM,CAAE,CAAC;IACtD,CAAC;IAEM,+BAAQ,GAAf,UAAiB,MAAgB;QAChC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAE,cAAc,EAAE,UAAE,CAAM,IAAM,OAAA,CAAE,MAAM,CAAC,OAAO,CAAE,CAAC,CAAC,GAAG,CAAE,IAAI,CAAC,CAAE,EAAhC,CAAgC,CAAE,CAAC;IAC5F,CAAC;IAEM,2BAAI,GAAX;QACC,iBAAM,IAAI,WAAE,CAAC;QACb,IAAI,CAAC,MAAM,CAAC,YAAY,CAAE,QAAQ,CAAE,CAAC;IACtC,CAAC;IAEM,2BAAI,GAAX;QACC,OAAO,iBAAM,IAAI,WAAE,CAAC;IACrB,CAAC;IAEF,mBAAC;AAAD,CAtHA,AAsHC,CAtHiC,WAAI,GAsHrC;AAtHY,oCAAY;;;;;;;;;;;;;;;;;;ACHzB,+BAA8B;AAE9B;IAA8B,4BAAI;IAAlC;;IAOA,CAAC;IALU,mCAAgB,GAA1B;QACC,OAAO,qBAAqB,CAAC;IAC9B,CAAC;IAGF,eAAC;AAAD,CAPA,AAOC,CAP6B,WAAI,GAOjC;AAPY,4BAAQ;;;;ACFrB,iCAAiC;;;;;;;;;;;;;;;AAEjC,+BAA8B;AAK9B;IAA6B,2BAAI;IAAjC;QAAA,qEAuPC;QArPQ,SAAG,GAAU,SAAS,CAAC;QACvB,UAAI,GAA8B,SAAS,CAAC;QAC5C,aAAO,GAAkC,SAAS,CAAC;QACnD,wBAAkB,GAAyB,SAAS,CAAC;QACrD,YAAM,GAAmB,SAAS,CAAC;QACnC,iBAAW,GAAY,KAAK,CAAC;QAE7B,UAAI,GAAW,CAAC,CAAC,CAAC;QAClB,aAAO,GAAW,CAAC,CAAC,CAAC;QACrB,aAAO,GAAW,CAAC,CAAC,CAAC;QAErB,oBAAc,GAAiB,SAAS,CAAC;;IA0OlD,CAAC;IAxOO,sBAAI,GAAX;QAAA,iBAgDC;QA9CA,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,OAAO,GAAoC,EAAE,CAAC;QAElD,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,QAAQ,CAAE,EAAG;YAC9C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAE,CAAC;SAC1C;QAED,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAE,mCAAmC,CAAE;aAC3E,IAAI,CAAE;YAEN,IAAI,MAAM,GAAmB,SAAS,CAAC;YACvC,IAAI,uBAAuB,GAAG,KAAI,CAAC,sBAAsB,EAAE,CAAC;YAE5D,IAAI,cAAc,GAAY;gBAC7B,oBAAoB,EAAE,IAAI;gBAC1B,uBAAuB,EAAE,uBAAuB;gBAChD,iBAAiB,EAAE,uBAAuB,KAAK,IAAI;aACnD,CAAC;YAEF,cAAc,GAAG,KAAI,CAAC,UAAU,CAAE,CAAE,kBAAkB,EAAE,qBAAqB,CAAE,EAAE,cAAc,CAAE,CAAC;YAElG,IAAI,kBAAkB,GAAyB,CAAC,CAAC,kBAAkB,CAAE,cAAc,CAAE,CAAC;YAEtF,KAAM,IAAI,KAAK,IAAI,IAAI,EAAG;gBAEzB,IAAK,IAAI,CAAE,KAAK,CAAE,CAAE,MAAM,CAAE,CAAC,cAAc,CAAE,KAAI,CAAC,EAAE,CAAE,EAAG;oBACxD,IAAI,SAAS,GAAsB,IAAI,CAAE,KAAK,CAAE,CAAE,MAAM,CAAE,CAAE,KAAI,CAAC,EAAE,CAAE,CAAE,WAAW,CAAE,CAAC;oBACrF,OAAO,CAAE,KAAK,CAAE,GAAG,EAAE,CAAC;oBAEtB,KAAiB,UAAS,EAAT,uBAAS,EAAT,uBAAS,EAAT,IAAS,EAAG;wBAAvB,IAAI,GAAG,kBAAA;wBAEZ,MAAM,GAAG,CAAE,MAAM,KAAK,SAAS,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAE,GAAG,EAAE,GAAG,CAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAE,GAAG,CAAE,CAAC;wBAE1F,IAAI,MAAM,GAAG,KAAI,CAAC,SAAS,CAAE,GAAG,EAAE,IAAI,CAAE,KAAK,CAAE,CAAE,CAAC;wBAClD,OAAO,CAAE,KAAK,CAAE,CAAC,IAAI,CAAE,MAAM,CAAE,CAAC;wBAChC,kBAAkB,CAAC,QAAQ,CAAE,MAAM,CAAE,CAAC;qBACtC;iBACD;aACD;YAED,KAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;YAC7C,KAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACvB,KAAI,CAAC,MAAM,GAAG,CAAE,MAAM,KAAK,SAAS,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAE,CAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAE,EAAE,CAAE,GAAG,EAAE,EAAE,CAAE,CAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QACpG,CAAC,CAAE,CAAC;QAEJ,OAAO,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAEO,wCAAsB,GAA9B;QAEC,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,gBAAgB,CAAE,IAAI,IAAI,CAAC,OAAO,CAAE,gBAAgB,CAAE,KAAK,KAAK,EAAG;YACpG,OAAO,CAAC,CAAC;SACT;QAED,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,yBAAyB,CAAE,EAAG;YAC/D,OAAO,IAAI,CAAC,OAAO,CAAE,yBAAyB,CAAE,GAAG,CAAC,CAAC;SACrD;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,yBAAO,GAAf,UAAiB,GAAQ;QAExB,IAAK,IAAI,CAAC,IAAI,KAAK,SAAS,EAAG;YAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;SACrB;QAED,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,sBAAsB,CAAE,EAAG;YAE5D,IAAI,IAAI,GAAa,GAAG,CAAE,WAAW,CAAE,CAAE,IAAI,CAAC,OAAO,CAAE,sBAAsB,CAAE,CAAE,CAAE,QAAQ,CAAE,CAAC;YAE9F,IAAK,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,CAAE,IAAI,CAAE,CAAC,CAAE,CAAE,EAAG;gBAC/D,OAAO,IAAI,CAAC,IAAI,CAAE,IAAI,CAAE,CAAC,CAAE,CAAE,CAAC;aAC9B;SACD;QAED,OAAO,IAAI,CAAC,IAAI,CAAE,SAAS,CAAE,CAAC;IAC/B,CAAC;IAEO,+BAAa,GAArB;QACC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QAEf,IAAI,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC;QAEzD,IAAI,CAAC,IAAI,CAAE,SAAS,CAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAE;YACpC,SAAS,EAAE,QAAQ,GAAG,iBAAiB;YACvC,eAAe,EAAE,QAAQ,GAAG,oBAAoB;YAChD,WAAW,EAAE,QAAQ,GAAG,mBAAmB;YAC3C,UAAU,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;YACtB,YAAY,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;YACxB,aAAa,EAAE,CAAE,CAAC,EAAE,CAAC,EAAE,CAAE;YACzB,8BAA8B;YAC9B,YAAY,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;SACxB,CAAE,CAAC;QAEJ,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,cAAc,CAAE,EAAG;YAEpD,KAAM,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,CAAE,cAAc,CAAE,EAAG;gBACnD,IAAI,CAAC,IAAI,CAAE,KAAK,CAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAE;oBAChC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAE,cAAc,CAAE,CAAE,KAAK,CAAE;oBAClD,oDAAoD;oBACpD,WAAW,EAAE,QAAQ,GAAG,mBAAmB;oBAC3C,UAAU,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;oBACtB,YAAY,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;oBACxB,aAAa,EAAE,CAAE,CAAC,EAAE,CAAC,EAAE,CAAE;oBACzB,8BAA8B;oBAC9B,YAAY,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;oBACxB,cAAc,EAAE,CAAE,EAAE,EAAE,EAAE,CAAE;iBAC1B,CAAE,CAAC;aACJ;SACD;IACF,CAAC;IAEO,2BAAS,GAAjB,UAAmB,MAA0B,EAAE,GAAQ;QACtD,IAAI,KAAK,GAAG,SAAS,CAAC;QACtB,IAAI,KAAK,GAAG,EAAE,CAAC;QAEf,oDAAoD;QAEpD,KAAM,IAAI,IAAI,IAAI,GAAG,CAAE,WAAW,CAAE,EAAG;YACtC,IAAI,YAAY,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAAE,IAAI,CAAE,CAAC;YAEhE,IAAK,CAAE,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,IAAI,KAAK,KAAK,EAAG;gBAC3E,IAAI,SAAS,GAAG,GAAG,CAAE,WAAW,CAAE,CAAE,IAAI,CAAE,CAAC;gBAE3C,IAAK,KAAK,KAAK,SAAS,EAAG;oBAC1B,KAAK,GAAG,SAAS,CAAE,QAAQ,CAAE,CAAC,IAAI,CAAE,IAAI,CAAE,CAAC;oBAC3C,KAAK,CAAC,IAAI,CAAE,KAAK,GAAG,SAAS,CAAE,kBAAkB,CAAE,CAAC,IAAI,CAAE,IAAI,CAAE,GAAG,MAAM,CAAE,CAAC;iBAC5E;qBAAM;oBACN,KAAK,CAAC,IAAI,CAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAE,kBAAkB,CAAE,CAAC,IAAI,CAAE,IAAI,CAAE,CAAE,CAAA;iBACxH;aACD;SACD;QAED,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,CAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAE,CAAC;QAC9D,MAAM,CAAC,SAAS,CAAE,KAAK,CAAC,IAAI,CAAE,MAAM,CAAE,CAAE,CAAC;QAEzC,MAAM,CAAC,OAAO,CAAE,IAAI,CAAC,OAAO,CAAE,GAAG,CAAE,CAAE,CAAC;QACtC,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,0BAAQ,GAAf;QAAA,iBAiCC;QA/BA,IAAK,IAAI,CAAC,WAAW,EAAG;YACvB,OAAO;SACP;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAExB,IAAI,IAAI,GAAG,IAAI,CAAC;QAEhB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAE;YAEzB,IAAI,UAAU,GAAY;gBACzB,MAAM,EAAE,KAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAE;aACtE,CAAC;YAEF,UAAU,GAAG,IAAI,CAAC,UAAU,CAAE,CAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAE,EAAE,UAAU,CAAE,CAAC;YAE7E,0CAA0C;YAE1C,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAgB,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,CAAE,CAAC,CAAE,EAAE,UAAU,CAAE,CAAC;YAC/E,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAE,IAAI,CAAC,kBAAkB,CAAE,CAAC;YAE7C,IAAK,KAAI,CAAC,OAAO,CAAC,cAAc,CAAE,cAAc,CAAE,EAAG;gBACpD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAE,KAAI,CAAC,OAAO,CAAE,cAAc,CAAE,CAAE,CAAC,KAAK,CAAE,IAAI,CAAC,GAAG,CAAE,CAAC;aACzE;YAED,IAAK,CAAC,UAAU,CAAC,cAAc,CAAE,MAAM,CAAE,EAAG;gBAC3C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAE,IAAI,CAAC,MAAM,CAAE,CAAC;aAClC;QAEF,CAAC,CAAE,CAAC;IAEL,CAAC;IAEM,4BAAU,GAAjB,UAAmB,IAAc,EAAE,QAAsB;QAAtB,yBAAA,EAAA,aAAsB;QAExD,KAAiB,UAAI,EAAJ,aAAI,EAAJ,kBAAI,EAAJ,IAAI,EAAG;YAAlB,IAAI,GAAG,aAAA;YACZ,IAAK,IAAI,CAAC,OAAO,CAAC,cAAc,CAAE,GAAG,CAAE,EAAG;gBACzC,QAAQ,CAAE,GAAG,CAAE,GAAG,IAAI,CAAC,OAAO,CAAE,GAAG,CAAE,CAAC;aACtC;SACD;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC;IAEM,0BAAQ,GAAf,UAAiB,MAAgB;QAAjC,iBAMC;QALA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAE;YACzB,KAAI,CAAC,gBAAgB,CAAE,MAAM,EAAE,UAAE,MAAiB;gBACjD,KAAI,CAAC,kBAAkB,CAAC,SAAS,CAAE,MAAM,CAAE,CAAA;YAC5C,CAAC,CAAE,CAAA;QACJ,CAAC,CAAE,CAAC;IACL,CAAC;IAEM,0BAAQ,GAAf,UAAiB,MAAgB;QAAjC,iBAMC;QALA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAE;YACzB,KAAI,CAAC,gBAAgB,CAAE,MAAM,EAAE,UAAE,MAAiB;gBACjD,KAAI,CAAC,kBAAkB,CAAC,YAAY,CAAE,MAAM,CAAE,CAAA;YAC/C,CAAC,CAAE,CAAA;QACJ,CAAC,CAAE,CAAC;IACL,CAAC;IAEO,kCAAgB,GAAxB,UAA0B,MAAgB,EAAE,EAAiC;QAE5E,IAAI,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAE,MAAM,CAAE,CAAC;QAE1D,IAAK,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAG;YAClC,EAAE,CAAE,gBAAgB,CAAE,CAAC;SACvB;IAEF,CAAC;IAEO,qCAAmB,GAA3B,UAA6B,MAAgB;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAE,IAAI,CAAC,sBAAsB,CAAE,MAAM,CAAE,CAAE,CAAC;IAC9D,CAAC;IAEO,wCAAsB,GAA9B,UAAgC,MAAgB;QAAhD,iBAEC;QADA,OAAO,MAAM,CAAC,GAAG,CAAE,UAAE,KAAa,IAAM,OAAA,KAAI,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC,CAAC,CAAC,KAAI,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC,CAAC,CAAC,EAAE,EAAlD,CAAkD,CAAE,CAAC;IAC9F,CAAC;IAEO,yBAAO,GAAf,UAAiB,OAAoB;QACpC,OAAO,OAAO,CAAC,MAAM,CAAE,UAAE,MAAiB,EAAE,MAAiB,IAAM,OAAA,MAAM,CAAC,MAAM,CAAE,MAAM,CAAE,EAAvB,CAAuB,EAAE,EAAE,CAAE,CAAC;IAClG,CAAC;IAEM,sBAAI,GAAX;QACC,iBAAM,IAAI,WAAE,CAAC;QACb,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC;IAEF,cAAC;AAAD,CAvPA,AAuPC,CAvP4B,WAAI,GAuPhC;AAvPY,0BAAO;;;;;;;;;;;;;;;;;;ACPpB,+BAA8B;AAE9B;IAA+B,6BAAI;IAAnC;;IAMA,CAAC;IAJU,oCAAgB,GAA1B;QACC,OAAO,sBAAsB,CAAC;IAC/B,CAAC;IAEF,gBAAC;AAAD,CANA,AAMC,CAN8B,WAAI,GAMlC;AANY,8BAAS;;;;;ACCtB;IASC,cAAoB,EAAU,EAAE,MAAc,EAAE,CAAa,EAAE,OAAqB;QAArB,wBAAA,EAAA,YAAqB;QAP1E,OAAE,GAAW,SAAS,CAAC;QACvB,WAAM,GAAW,SAAS,CAAC;QAC3B,eAAU,GAAe,SAAS,CAAC;QACnC,YAAO,GAAY,SAAS,CAAC;QAC7B,YAAO,GAAY,KAAK,CAAC;QACzB,SAAI,GAAkC,EAAE,CAAC;QAGlD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAEM,mBAAI,GAAX;QAAA,iBAaC;QAXA,IAAI,MAAM,GAAG,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAE,CAAC;QACtD,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,gBAAgB,EAAE,CAAE,CAAC;QAEvD,IAAI,CAAC,IAAI,CAAE,UAAE,KAAK,EAAE,IAAI;YACvB,IAAI,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,KAAM,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAG;gBAC1C,IAAK,MAAM,CAAC,OAAO,CAAE,OAAO,CAAE,CAAC,CAAE,CAAE,IAAI,CAAC,EAAG;oBAC1C,KAAI,CAAC,IAAI,CAAE,OAAO,CAAE,CAAC,CAAE,CAAE,GAAG,CAAC,CAAE,IAAI,CAAE,KAAK,CAAE,CAAE,CAAC;iBAC/C;aACD;QACF,CAAC,CAAE,CAAC;IACL,CAAC;IAES,+BAAgB,GAA1B;QACC,OAAO,gBAAgB,CAAC;IACzB,CAAC;IAEM,+BAAgB,GAAvB;QACC,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,uBAAQ,GAAf,UAAiB,MAAgB;QAAjC,iBAeC;QAbA,IAAK,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAG;YAE1C,MAAM,CAAC,OAAO,CAAE,UAAE,KAAa;gBAC9B,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,SAAS,CAAE,GAAG,CAAE,CAAC;YACrC,CAAC,CAAE,CAAC;SAEJ;aAAM;YAEN,MAAM,CAAC,OAAO,CAAE,UAAE,KAAa;gBAC9B,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,GAAG,CAAE,SAAS,EAAE,EAAE,CAAC,CAAC;YACxC,CAAC,CAAE,CAAC;SAEJ;IACF,CAAC;IAEM,uBAAQ,GAAf,UAAiB,MAAgB;QAAjC,iBAeC;QAbA,IAAK,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAG;YAE1C,MAAM,CAAC,OAAO,CAAE,UAAE,KAAa;gBAC9B,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,OAAO,CAAE,GAAG,CAAE,CAAC;YACnC,CAAC,CAAE,CAAC;SAEJ;aAAM;YAEN,MAAM,CAAC,OAAO,CAAE,UAAE,KAAa;gBAC9B,KAAI,CAAC,IAAI,CAAE,KAAK,CAAE,CAAC,GAAG,CAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC,CAAE,CAAC;SAEJ;IACF,CAAC;IAEM,mBAAI,GAAX;QACC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,mBAAI,GAAX;QACC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IACF,WAAC;AAAD,CAlFA,AAkFC,IAAA;AAlFY,oBAAI;;;;;ACFjB;IAOC,sBAAoB,MAAc,EAAE,OAAiB,EAAE,UAAsB;QALrE,WAAM,GAAW,SAAS,CAAC;QAC3B,YAAO,GAAa,SAAS,CAAC;QAE9B,eAAU,GAAe,SAAS,CAAC;QAG1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC9B,CAAC;IAEM,2BAAI,GAAX;QAAA,iBAMC;QALA,IAAK,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAG;YAC9B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAE,UAAE,EAAU,IAAO,KAAI,CAAC,MAAM,CAAC,EAAE,CAAE,OAAO,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAG,KAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,kBAAkB,CAAE,CAAC,CAAC,CAAC,CAAE,CAAC;YACrK,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAE,UAAU,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;SACnB;IACF,CAAC;IAEc,+BAAkB,GAAjC,UAAmC,KAAwB;QAE1D,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAE,CAAC;QAE1D,CAAC,CAAE,KAAK,CAAC,MAAM,CAAE;aAChB,QAAQ,CAAE,UAAU,CAAC;aACrB,QAAQ,EAAE,CAAC,WAAW,CAAE,UAAU,CAAE,CAAC;QAEtC,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,KAAK,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEF,mBAAC;AAAD,CAjCA,AAiCC,IAAA;AAjCY,oCAAY;;;;;ACDzB,gDAA+C;AAG/C,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAE,mBAAmB,CAAE,CAAC;wBAExC,EAAE;IACX,IAAK,MAAM,CAAC,cAAc,CAAE,EAAE,CAAE,EAAG;QAClC,IAAI,GAAC,GAAG,IAAI,mBAAQ,CAAE,CAAC,CAAE,GAAG,GAAG,EAAE,CAAE,EAAE,MAAM,CAAE,EAAE,CAAE,CAAE,CAAC;QACpD,EAAE,CAAC,IAAI,CAAE,kBAAkB,CAAE,CAAC,GAAG,CAAE,cAAM,OAAA,GAAC,CAAC,GAAG,EAAE,EAAP,CAAO,CAAE,CAAC;KACnD;;AAJF,KAAM,IAAI,EAAE,IAAI,MAAM;YAAZ,EAAE;CAKX","file":"ext.srf.filtered.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/// <reference types=\"jquery\" />\n\nimport { Options, ResultData } from \"../types\";\ndeclare let srf: any;\n\nimport { View } from \"./View/View\";\nimport { Filter } from \"./Filter/Filter\";\n\nexport class Controller {\n\tprivate target: JQuery = undefined;\n\tprivate filterSpinner: JQuery = undefined;\n\n\tprivate views: { [key: string]: View } = {};\n\tprivate filters: { [key: string]: Filter } = {};\n\tprivate currentView: View = undefined;\n\tprivate data: ResultData;\n\tprivate printRequests: Options;\n\n\tpublic constructor( target: JQuery, data: ResultData, printRequests: Options ) {\n\t\tthis.target = target;\n\n\t\tif ( this.target !== undefined ) {\n\t\t\tthis.filterSpinner = this.target.find( 'div.filtered-filter-spinner' );\n\t\t}\n\n\t\tthis.data = data;\n\t\tthis.printRequests = printRequests;\n\n\t\tfor ( let rowId in this.data ) {\n\t\t\tif ( !this.data[ rowId ].hasOwnProperty( 'visible' ) ) {\n\t\t\t\tthis.data[ rowId ].visible = {};\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getData(): any {\n\t\treturn this.data;\n\t}\n\n\tpublic getPrintRequests(): Options {\n\t\treturn this.printRequests;\n\t}\n\n\tpublic getPath() {\n\t\treturn srf.settings.get( 'srfgScriptPath' ) + '/formats/filtered/resources/';\n\t}\n\n\tpublic attachView( viewid: string, view: View ) {\n\n\t\tthis.views[ viewid ] = view;\n\n\t\tif ( this.currentView === undefined ) {\n\t\t\tthis.currentView = view;\n\t\t\tview.show();\n\t\t} else {\n\t\t\tview.hide();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic getView( viewId: string ): View {\n\t\treturn this.views[ viewId ];\n\t}\n\n\tpublic attachFilter( filter: Filter ): JQueryPromise< void > {\n\t\tlet filterId = filter.getId();\n\n\t\tthis.filters[ filterId ] = filter;\n\n\t\tfilter.init();\n\n\t\treturn this.onFilterUpdated( filterId );\n\t}\n\n\tpublic getFilter( filterId: string ): Filter {\n\t\treturn this.filters[ filterId ];\n\t}\n\n\tpublic show() {\n\t\tthis.initializeFilters();\n\t\tthis.target.children( '.filtered-spinner' ).remove();\n\t\tthis.target.children().show();\n\t\tthis.switchToView( this.currentView );\n\t}\n\n\tprivate switchToView( view: View ) {\n\n\t\tif ( this.currentView instanceof View ) {\n\t\t\tthis.currentView.hide();\n\t\t}\n\n\t\tthis.currentView = view;\n\n\t\tif ( this.currentView instanceof View ) {\n\t\t\tview.show();\n\t\t}\n\n\t}\n\n\tprivate initializeFilters() {\n\t\tlet toShow: string[] = [];\n\t\tlet toHide: string[] = [];\n\n\t\tfor ( let rowId in this.data ) {\n\t\t\tfor ( let filterId in this.filters ) {\n\t\t\t\tthis.data[ rowId ].visible[ filterId ] = this.filters[ filterId ].isDisabled() || this.filters[ filterId ].isVisible( rowId );\n\t\t\t}\n\t\t\tif ( this.isVisible( rowId ) ) {\n\t\t\t\ttoShow.push( rowId );\n\t\t\t} else {\n\t\t\t\ttoHide.push( rowId );\n\t\t\t}\n\t\t}\n\n\t\tthis.hideRows( toHide );\n\t\tthis.showRows( toShow );\n\t}\n\n\tpublic onViewSelected( viewID: string ) {\n\t\tthis.switchToView( this.views[ viewID ] );\n\t}\n\n\tpublic onFilterUpdated( filterId: string ): JQueryPromise< void > {\n\n\t\treturn this.showSpinner()\n\t\t.then(() => {\n\n\t\t\tlet toShow: string[] = [];\n\t\t\tlet toHide: string[] = [];\n\n\t\t\tlet disabled = this.filters[ filterId ].isDisabled();\n\n\t\t\tfor ( let rowId in this.data ) {\n\n\t\t\t\tlet newVisible: boolean = disabled || this.filters[ filterId ].isVisible( rowId );\n\n\t\t\t\tif ( this.data[ rowId ].visible[ filterId ] !== newVisible ) {\n\n\t\t\t\t\tthis.data[ rowId ].visible[ filterId ] = newVisible;\n\n\t\t\t\t\tif ( newVisible && this.isVisible( rowId ) ) {\n\t\t\t\t\t\ttoShow.push( rowId );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttoHide.push( rowId );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.hideRows( toHide );\n\t\t\tthis.showRows( toShow );\n\t\t})\n\t\t.then( () => { this.hideSpinner() } );\n\t}\n\n\tpublic isVisible( rowId: any ) {\n\t\tfor ( let filterId in this.data[ rowId ].visible ) {\n\t\t\tif ( !this.data[ rowId ].visible[ filterId ] ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate hideRows( rowIds: string[] ) {\n\t\tif ( rowIds.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\tfor ( let viewId in this.views ) {\n\t\t\tthis.views[ viewId ].hideRows( rowIds );\n\t\t}\n\t}\n\n\tprivate showRows( rowIds: string[] ) {\n\t\tif ( rowIds.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\tfor ( let viewId in this.views ) {\n\t\t\tthis.views[ viewId ].showRows( rowIds );\n\t\t}\n\t}\n\n\tprivate showSpinner(): JQueryPromise< void > {\n\t\treturn this.animateSpinner();\n\t}\n\n\tprivate hideSpinner(): JQueryPromise< void > {\n\t\treturn this.animateSpinner( false );\n\t}\n\n\tprivate animateSpinner( show: boolean = true ): JQueryPromise< void > {\n\n\t\tif ( this.filterSpinner === undefined ) {\n\t\t\treturn jQuery.when();\n\t\t}\n\n\t\tif ( show ) {\n\t\t\treturn this.filterSpinner.fadeIn( 200 ).promise();\n\t\t}\n\n\t\treturn this.filterSpinner.fadeOut( 200 ).promise();\n\t}\n\n}\n","import { Filter } from \"./Filter\";\n\ndeclare let mw: any;\n\nexport class DistanceFilter extends Filter {\n\n\tprivate static readonly earthRadius: { [key: string]: number } = {\n\t\tm: 6371008.8,\n\t\tkm: 6371.0088,\n\t\tmi: 3958.7613,\n\t\tnm: 3440.0695,\n\t\tÃ…: 63710088000000000\n\t};\n\n\tprivate earthRadiusValue: number = DistanceFilter.earthRadius.km;\n\tprivate filterValue: number = 0;\n\n\tpublic init() {\n\n\t\tlet values = this.controller.getData();\n\n\t\tlet origin = this.options[ 'origin' ];\n\n\t\tif ( !( origin !== undefined && origin.hasOwnProperty( 'lat' ) && origin.hasOwnProperty( 'lng' ) ) ) {\n\t\t\tthis.target.detach();\n\t\t\treturn;\n\t\t}\n\n\t\tlet unit = 'km';\n\n\t\tif ( this.options[ 'unit' ] && DistanceFilter.earthRadius[ this.options[ 'unit' ] ] ) {\n\t\t\tunit = this.options[ 'unit' ];\n\t\t}\n\n\t\tthis.earthRadiusValue = DistanceFilter.earthRadius[ unit ];\n\n\t\tlet maxValue: number = this.updateDistances( origin );\n\n\t\tlet precision = 10 ** ( Math.floor( Math.log( maxValue ) * Math.LOG10E ) - 1);\n\n\t\tif ( this.options[ 'max' ] !== undefined && this.options[ 'max' ] > maxValue ) {\n\t\t\tmaxValue = this.options[ 'max' ];\n\t\t} else {\n\t\t\tmaxValue = Math.ceil( maxValue / precision ) * precision;\n\t\t}\n\n\t\tthis.filterValue = this.options[ 'initial value' ] ? Math.min( this.options[ 'initial value' ], maxValue ) : maxValue;\n\n\t\t// build filter controls\n\t\tlet filtercontrols = this.buildEmptyControl();\n\n\t\tlet readout = $( '<div class=\"filtered-distance-readout\">' + this.filterValue + '</div>' );\n\n\t\tlet table = $( '<table class=\"filtered-distance-table\"><tbody><tr><td class=\"filtered-distance-min-cell\">0</td>' +\n\t\t\t'<td class=\"filtered-distance-slider-cell\"><div class=\"filtered-distance-slider\"></div></td>' +\n\t\t\t'<td class=\"filtered-distance-max-cell\">' + maxValue + '</td></tr>' +\n\t\t\t'<tr><td colspan=3 class=\"filtered-distance-unit-cell\">' + unit + '</td></tr></tbody></table>' );\n\n\t\tfiltercontrols.append( table );\n\n\t\tlet that = this;\n\t\tmw.loader.using( 'jquery.ui.slider' ).then( function () {\n\n\t\t\ttable.find( '.filtered-distance-slider' )\n\t\t\t.slider( {\n\t\t\t\tanimate: true,\n\t\t\t\tmax: maxValue,\n\t\t\t\tvalue: that.filterValue,\n\t\t\t\tstep: precision / 100\n\t\t\t} )\n\t\t\t.on( 'slidechange', undefined, { 'filter': that }, function ( eventObject: JQueryEventObject, ui: any ) {\n\t\t\t\teventObject.data.ui = ui;\n\t\t\t\teventObject.data.filter.onFilterUpdated( eventObject );\n\t\t\t} )\n\t\t\t.on( 'slide', undefined, { 'filter': that }, function ( eventObject: JQueryEventObject, ui: any ) {\n\t\t\t\treadout.text( ui.value );\n\t\t\t} )\n\t\t\t.find( '.ui-slider-handle' )\n\t\t\t.append( readout );\n\n\t\t} );\n\n\t\treturn this;\n\t}\n\n\tprivate updateDistances( origin: L.LatLngLiteral ): number {\n\n\t\tlet values = this.controller.getData();\n\t\tlet max = 1;\n\n\t\tlet prId = this.printrequestId;\n\n\t\tfor ( let rowId in values ) {\n\n\t\t\tif ( values[ rowId ].data.hasOwnProperty( this.filterId ) ) {\n\t\t\t\tlet distances: number[] = values[ rowId ].data[ this.filterId ].positions.map( ( pos: L.LatLngLiteral ) => this.distance( origin, pos ) );\n\t\t\t\tlet dist = Math.min( ...distances );\n\n\t\t\t\tvalues[ rowId ].data[ this.filterId ].distance = dist;\n\t\t\t\tmax = Math.max( max, dist );\n\t\t\t} else {\n\t\t\t\tvalues[ rowId ].data[ this.filterId ].distance = Infinity;\n\t\t\t}\n\t\t}\n\n\t\treturn max;\n\t}\n\n\tpublic onFilterUpdated( eventObject: JQueryEventObject ) {\n\t\tthis.filterValue = eventObject.data.ui.value;\n\t\tthis.controller.onFilterUpdated( this.getId() );\n\t}\n\n\tprivate distance( a: L.LatLngLiteral, b: L.LatLngLiteral ) {\n\n\t\tconst DEG2RAD = Math.PI / 180.0;\n\n\t\tfunction squared( x: number ) {\n\t\t\treturn x * x\n\t\t}\n\n\t\tlet f =\n\t\t\tsquared( Math.sin( ( b.lat - a.lat ) * DEG2RAD / 2.0 ) ) +\n\t\t\tMath.cos( a.lat * DEG2RAD ) * Math.cos( b.lat * DEG2RAD ) *\n\t\t\tsquared( Math.sin( ( b.lng - a.lng ) * DEG2RAD / 2.0 ) );\n\n\t\treturn this.earthRadiusValue * 2 * Math.atan2( Math.sqrt( f ), Math.sqrt( 1 - f ) );\n\t}\n\n\tpublic isVisible( rowId: string ): boolean {\n\n\t\tlet rowdata = this.controller.getData()[ rowId ].data;\n\n\t\tif ( rowdata.hasOwnProperty( this.filterId ) ) {\n\t\t\treturn rowdata[ this.filterId ].distance <= this.filterValue;\n\t\t}\n\n\t\treturn super.isVisible( rowId );\n\n\t}\n\n}\n","import { Options } from \"../../types\";\nimport { Controller } from \"../Controller\";\n\nexport abstract class Filter{\n\n\tprivate outerTarget: JQuery = undefined;\n\tprotected target: JQuery = undefined;\n\tprotected filterId: string;\n\tprotected printrequestId: string;\n\tprotected controller: Controller;\n\tprotected options: Options = undefined;\n\tprotected disabled: boolean = false;\n\tprotected collapsed: boolean = false;\n\n\tpublic constructor( filterId: string, target: JQuery, printrequestId: string, controller: Controller, options?: Options ) {\n\t\tthis.target = target;\n\t\tthis.outerTarget = target;\n\t\tthis.filterId = filterId;\n\t\tthis.printrequestId = printrequestId;\n\t\tthis.controller = controller;\n\t\tthis.options = options || {};\n\t}\n\n\tpublic init() {};\n\n\tpublic isDisabled() : boolean {\n\t\treturn this.disabled;\n\t}\n\n\tpublic disable() {\n\t\tthis.disabled = true;\n\n\t\tthis.outerTarget\n\t\t.removeClass( 'enabled' )\n\t\t.addClass( 'disabled' );\n\n\t\tthis.collapse();\n\n\t\tthis.target.promise().then( () =>\tthis.controller.onFilterUpdated( this.filterId ) );\n\t}\n\n\tpublic enable() {\n\t\tthis.disabled = false;\n\n\t\tthis.outerTarget\n\t\t.removeClass( 'disabled' )\n\t\t.addClass( 'enabled' );\n\n\t\tif ( ! this.collapsed ) {\n\t\t\tthis.uncollapse();\n\t\t}\n\n\t\tthis.target.promise().then( () =>\tthis.controller.onFilterUpdated( this.filterId ) );\n\t}\n\n\tprivate collapse( duration : number = 400 ) {\n\n\t\tif ( ! this.collapsed ) {\n\n\t\t\tthis.outerTarget.promise()\n\t\t\t.then( () => {\n\n\t\t\t\tthis.target.slideUp( duration );\n\n\t\t\t\tthis.outerTarget.animate( {\n\t\t\t\t\t'padding-top': 0,\n\t\t\t\t\t'padding-bottom': 0,\n\t\t\t\t\t'margin-bottom': '2em'\n\t\t\t\t}, duration );\n\t\t\t} );\n\t\t}\n\t}\n\n\tprivate uncollapse() {\n\t\tthis.outerTarget.promise()\n\t\t.then( () => {\n\t\t\tthis.target.slideDown();\n\n\t\t\tlet style = this.outerTarget.attr( 'style' );\n\t\t\tthis.outerTarget.removeAttr( 'style' );\n\t\t\tlet uncollapsedCss = this.outerTarget.css( [ 'padding-top', 'padding-bottom', 'margin-bottom' ] );\n\t\t\tthis.outerTarget.attr( 'style', style );\n\n\t\t\tthis.outerTarget.animate( uncollapsedCss );\n\t\t} );\n\t}\n\n\tpublic isVisible( rowId: string ): boolean {\n\t\treturn this.options.hasOwnProperty( 'show if undefined' ) && this.options[ 'show if undefined' ] === true;\n\t}\n\n\tpublic getId() {\n\t\treturn this.filterId;\n\t}\n\n\tprotected buildEmptyControl() {\n\n\t\tthis.target = $( '<div class=\"filtered-filter-container\">' );\n\n\t\tthis.outerTarget\n\t\t.append( this.target )\n\t\t.addClass( 'enabled' );\n\n\t\tthis.addOnOffSwitch();\n\t\tthis.addLabel();\n\t\tthis.addControlForCollapsing();\n\n\t\treturn this.target;\n\t}\n\n\tprivate addLabel() {\n\t\t// insert the label of the printout this filter filters on\n\t\tthis.target.before( `<div class=\"filtered-filter-label\">${this.options[ 'label' ]}</div>` );\n\t}\n\n\tprotected addOnOffSwitch() {\n\n\t\tif ( this.options.hasOwnProperty( 'switches' ) ) {\n\n\t\t\tlet switches = this.options[ 'switches' ];\n\n\t\t\tif ( switches.length > 0 && $.inArray( 'on off', switches ) >= 0 ) {\n\n\t\t\t\tlet onOffControl = $( `<div class=\"filtered-filter-onoff on\"></div>` );\n\n\t\t\t\tthis.target.before( onOffControl );\n\n\t\t\t\tonOffControl.click( () => {\n\n\t\t\t\t\tif ( this.outerTarget.hasClass('enabled' ) ) {\n\t\t\t\t\t\tthis.disable();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.enable();\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected addControlForCollapsing() {\n\t\tlet collapsible = this.options.hasOwnProperty( 'collapsible' ) ? this.options[ 'collapsible' ] : undefined;\n\t\tif ( collapsible === 'collapsed' || collapsible === 'uncollapsed' ) {\n\n\t\t\tlet collapseControl = $( '<span class=\"filtered-filter-collapse\">' );\n\n\t\t\tthis.target.before( collapseControl );\n\n\t\t\tcollapseControl.click( () => {\n\t\t\t\tif ( collapseControl.hasClass( 'collapsed' ) ) {\n\t\t\t\t\tthis.uncollapse();\n\t\t\t\t\tthis.collapsed = false;\n\n\t\t\t\t\tcollapseControl\n\t\t\t\t\t.removeClass( 'collapsed' )\n\t\t\t\t\t.addClass( 'uncollapsed' );\n\t\t\t\t} else {\n\t\t\t\t\tthis.collapse();\n\t\t\t\t\tthis.collapsed = true;\n\n\t\t\t\t\tcollapseControl\n\t\t\t\t\t.removeClass( 'uncollapsed' )\n\t\t\t\t\t.addClass( 'collapsed' );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\tif ( collapsible === 'collapsed' ) {\n\n\t\t\t\tthis.collapse( 0 );\n\t\t\t\tthis.collapsed = true;\n\t\t\t\tcollapseControl.addClass('collapsed');\n\n\t\t\t} else {\n\t\t\t\tcollapseControl.addClass('uncollapsed');\n\t\t\t}\n\t\t}\n\t}\n\n}","///<reference path=\"../../../../node_modules/@types/ion.rangeslider/index.d.ts\"/>\nimport { Filter } from \"./Filter\";\nimport { Options } from \"../../types\";\n\ndeclare let mw: any;\n\nexport class NumberFilter extends Filter {\n\n\tprivate MODE_RANGE = 0;\n\tprivate MODE_MIN = 1;\n\tprivate MODE_MAX = 2;\n\tprivate MODE_SELECT = 3;\n\n\tprivate filterValueUpper: number = 0;\n\tprivate filterValueLower: number = 0;\n\tprivate mode = this.MODE_RANGE;\n\n\tpublic init() {\n\n\t\tlet values: number[] = this.getValues();\n\n\t\tlet { minValue, maxValue, precision } = this.getRangeParameters( values );\n\n\t\tlet sliderOptions: IonRangeSliderOptions = {\n\t\t\tprettify_enabled: false,\n\t\t\tforce_edges: true,\n\t\t\tgrid: true\n\t\t};\n\n\t\tif ( this.options.hasOwnProperty( 'values' ) ) {\n\t\t\tsliderOptions = this.adjustSliderOptionsFromValues( sliderOptions, values );\n\n\t\t} else {\n\t\t\tsliderOptions = this.adjustSliderOptionsFromRangeParameters( sliderOptions, minValue, maxValue, precision );\n\t\t}\n\n\t\tswitch( this.options[ 'sliders' ] ) {\n\n\t\t\tcase \"min\":\n\n\t\t\t\tthis.mode = this.MODE_MIN;\n\t\t\t\tsliderOptions.type = 'single';\n\t\t\t\tbreak;\n\n\t\t\tcase \"max\":\n\n\t\t\t\tthis.mode = this.MODE_MAX;\n\t\t\t\tsliderOptions.from = sliderOptions.to;\n\t\t\t\tsliderOptions.type = 'single';\n\t\t\t\tbreak;\n\n\t\t\tcase \"select\":\n\n\t\t\t\tthis.mode = this.MODE_SELECT;\n\t\t\t\tmaxValue = minValue;\n\t\t\t\tsliderOptions.type = 'single';\n\t\t\t\tbreak;\n\n\t\t\tdefault: // == case \"range\"\n\n\t\t\t\tthis.mode = this.MODE_RANGE;\n\t\t\t\tsliderOptions.type = 'double';\n\t\t}\n\n\t\tthis.buildFilterControls( sliderOptions );\n\n\t\tthis.filterValueLower = minValue;\n\t\tthis.filterValueUpper = maxValue;\n\n\t\treturn this;\n\t}\n\n\tprivate adjustSliderOptionsFromRangeParameters( sliderOptions: IonRangeSliderOptions, minValue: number, maxValue: number, precision: number ) {\n\n\t\tsliderOptions.min = minValue;\n\t\tsliderOptions.max = maxValue;\n\t\tsliderOptions.step = this.getStep( precision );\n\t\tsliderOptions.grid_num = Math.min( 4, Math.round( ( maxValue - minValue ) / sliderOptions.step ) );\n\n\t\tsliderOptions.from = minValue;\n\t\tsliderOptions.to = maxValue;\n\n\t\tsliderOptions.onFinish = ( data: IonRangeSliderEvent ) => this.onFilterUpdated( data.from, data.to );\n\n\t\treturn sliderOptions;\n\t}\n\n\tprivate adjustSliderOptionsFromValues( sliderOptions: IonRangeSliderOptions, values: number[] ) {\n\n\t\tsliderOptions.values = values;\n\n\t\tsliderOptions.from = 0;\n\t\tsliderOptions.to = values.length - 1;\n\n\t\tsliderOptions.onFinish = ( data: IonRangeSliderEvent ) => this.onFilterUpdated( data.from_value, data.to_value );\n\n\t\treturn sliderOptions;\n\t}\n\n\tprivate getRangeParameters( values: number[] ) {\n\n\t\tlet minValue = values[ 0 ];\n\t\tlet maxValue = values[ values.length - 1 ];\n\t\tlet precision: number = this.getPrecision( minValue, maxValue );\n\n\t\tif ( !this.options.hasOwnProperty( 'values' ) ) {\n\t\t\tminValue = this.getMinSliderValue( minValue, precision );\n\t\t\tmaxValue = this.getMaxSliderValue( maxValue, precision );\n\t\t}\n\n\t\treturn { minValue, maxValue, precision };\n\t}\n\n\tprivate getValues(): number[] {\n\t\tlet values: number[];\n\t\tif ( this.options.hasOwnProperty( 'values' ) && this.options[ 'values' ][0] !== 'auto' ) {\n\t\t\tvalues = this.options[ 'values' ]\n\t\t} else {\n\t\t\tvalues = this.getSortedValues();\n\t\t}\n\n\t\tif ( values.length === 0 ) {\n\t\t\tvalues = [ 0, 0 ];\n\t\t} else if ( values.length === 1 ) {\n\t\t\tvalues.push( values[ 0 ] );\n\t\t}\n\n\t\treturn values;\n\t}\n\n\tprivate buildFilterControls( sliderOptions: IonRangeSliderOptions ) {\n\n\t\tlet filterClassNames: any = {};\n\t\tfilterClassNames[ this.MODE_MIN.toString() ] = \"mode-min\";\n\t\tfilterClassNames[ this.MODE_MAX ] = \"mode-max\";\n\t\tfilterClassNames[ this.MODE_RANGE ] = \"mode-range\";\n\t\tfilterClassNames[ this.MODE_SELECT ] = \"mode-select\";\n\n\t\tlet filtercontrols = this.buildEmptyControl();\n\n\t\tlet slider = $( '<input type=\"text\" value=\"\" />' );\n\t\tlet sliderContainer = $( `<div class=\"filtered-number-slider ${filterClassNames[ this.mode ]}\" />` ).append( slider );\n\t\tfiltercontrols.append( sliderContainer );\n\n\t\tif ( this.options.hasOwnProperty( 'caption' ) ) {\n\t\t\tlet caption = `<div class=\"filtered-number-caption\">${this.options[ 'caption' ]}</div>`;\n\t\t\tfiltercontrols.append( caption );\n\t\t}\n\n\t\tmw.loader.using( 'ext.srf.filtered.slider' ).then( () => slider.ionRangeSlider( sliderOptions ) );\n\t}\n\n\tprivate getMinSliderValue( minValue: number, precision: number ) {\n\t\tlet requestedMin = this.options[ 'min' ];\n\n\t\tif ( requestedMin === undefined || isNaN( Number( requestedMin ) ) ) {\n\t\t\treturn Math.floor( minValue / precision ) * precision;\n\t\t}\n\n\t\treturn Math.min( requestedMin, minValue );\n\t}\n\n\tprivate getMaxSliderValue( maxValue: number, precision: number ) {\n\t\tlet requestedMax = this.options[ 'max' ];\n\n\t\tif ( requestedMax === undefined || isNaN( Number( requestedMax ) ) ) {\n\t\t\treturn Math.ceil( maxValue / precision ) * precision;\n\t\t}\n\n\t\treturn Math.max( requestedMax, maxValue );\n\t}\n\n\tprivate getPrecision( minValue: number, maxValue: number ): number {\n\t\tif ( maxValue - minValue > 0 ) {\n\t\t\treturn 10 ** ( Math.floor( Math.log( maxValue - minValue ) * Math.LOG10E ) - 1 );\n\t\t} else {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tprivate getStep( precision: number ): number {\n\n\t\tlet step = this.options[ 'step' ];\n\n\t\tif ( step !== undefined ) {\n\n\t\t\tstep = Number( step );\n\n\t\t\tif ( !isNaN( step ) ) {\n\t\t\t\treturn step;\n\t\t\t}\n\t\t}\n\n\t\treturn precision / 10;\n\t}\n\n\tprivate getRangeFromValues(): [ number, number ] {\n\n\t\tlet rows = this.controller.getData();\n\t\tlet min = Infinity;\n\t\tlet max = -Infinity;\n\n\t\tfor ( let rowId in rows ) {\n\n\t\t\tif ( rows[ rowId ].data.hasOwnProperty( this.filterId ) ) {\n\t\t\t\tlet values: number[] = rows[ rowId ].data[ this.filterId ].values;\n\t\t\t\tmin = Math.min( min, ...values );\n\t\t\t\tmax = Math.max( max, ...values );\n\t\t\t}\n\t\t}\n\n\t\treturn [ min, max ];\n\t}\n\n\tprivate getSortedValues(): number[] {\n\n\t\tlet valueArray: number[] = [];\n\t\tlet rows = this.controller.getData();\n\n\t\tfor ( let rowId in rows ) {\n\n\t\t\tlet cells = rows[ rowId ].data;\n\n\t\t\tif ( cells.hasOwnProperty( this.filterId ) ) {\n\n\t\t\t\tlet values = cells[ this.filterId ].values;\n\n\t\t\t\tfor ( let valueId in values ) {\n\n\t\t\t\t\tlet value = Number( values[ valueId ] );\n\n\t\t\t\t\tif ( valueArray.indexOf( value ) === -1 ) {\n\t\t\t\t\t\tvalueArray.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn valueArray.sort( ( a: any, b: any ) => a - b );\n\t}\n\n\tpublic onFilterUpdated( from: number, to: number ) {\n\n\t\tswitch ( this.mode ) {\n\n\t\t\tcase this.MODE_MIN:\n\n\t\t\t\tthis.filterValueLower = from;\n\t\t\t\tbreak;\n\n\t\t\tcase this.MODE_MAX:\n\n\t\t\t\tthis.filterValueUpper = from;\n\t\t\t\tbreak;\n\n\t\t\tcase this.MODE_SELECT:\n\n\t\t\t\tthis.filterValueLower = from;\n\t\t\t\tthis.filterValueUpper = from;\n\t\t\t\tbreak;\n\n\t\t\tdefault: // case this.MODE_RANGE:\n\n\t\t\t\tthis.filterValueLower = from;\n\t\t\t\tthis.filterValueUpper = to;\n\t\t}\n\n\t\tthis.controller.onFilterUpdated( this.getId() );\n\t}\n\n\tpublic isVisible( rowId: string ): boolean {\n\t\tlet rowdata = this.controller.getData()[ rowId ].data;\n\n\t\tif ( rowdata.hasOwnProperty( this.filterId ) && rowdata[ this.filterId ].values.length > 0 ) {\n\n\t\t\tfor ( let value of rowdata[ this.filterId ].values ) {\n\t\t\t\tif ( value >= this.filterValueLower && value <= this.filterValueUpper ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn super.isVisible( rowId );\n\t}\n\n}\n","import { Filter } from \"./Filter\";\nimport { IdTextPair } from \"select2\";\n\ndeclare let mw: any;\n\nexport class ValueFilter extends Filter {\n\n\tprivate values: any = {};\n\tprivate visibleValues: string[] = [];\n\n\tprivate _useOr = true;\n\n\tpublic init() {\n\t\tthis.values = this.getSortedValues();\n\t\tthis.buildControl();\n\t}\n\n\tpublic useOr( useOr: boolean ) {\n\t\tthis._useOr = useOr;\n\t\tthis.controller.onFilterUpdated( this.getId() );\n\t}\n\n\tprivate getSortedValues(): any {\n\n\t\t/** Map of value => label distinct values */\n\t\tlet distinctValues: any = {};\n\t\t/** Map of value => sort value distinct values */\n\t\tlet distinctSortValues: any = {};\n\n\t\tif ( this.options.hasOwnProperty( 'values' ) ) {\n\n\t\t\treturn this.options[ 'values' ].map(\n\t\t\t\t( item: string ) => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tprintoutValue: item,\n\t\t\t\t\t\tformattedValue: item\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t);\n\n\t\t} else {\n\t\t\t// build filter values from available values in result set\n\t\t\tlet data = this.controller.getData();\n\t\t\tlet sortedEntries: any[] = [];\n\t\t\tfor ( let id in data ) {\n\n\t\t\t\tlet printoutValues: any = data[ id ][ 'printouts' ][ this.printrequestId ][ 'values' ];\n\t\t\t\tlet printoutFormattedValues = data[ id ][ 'printouts' ][ this.printrequestId ][ 'formatted values' ];\n\t\t\t\tlet printoutSortValues: any = data[ id ][ 'printouts' ][ this.printrequestId ][ 'sort values' ];\n\n\t\t\t\tfor ( let i in printoutValues ) {\n\t\t\t\t\tlet printoutFormattedValue = printoutFormattedValues[ i ];\n\n\t\t\t\t\tif ( printoutFormattedValue.indexOf( '<a' ) > -1 ) {\n\t\t\t\t\t\tprintoutFormattedValue = /<a.*>(.*?)<\\/a>/.exec( printoutFormattedValue )[ 1 ];\n\t\t\t\t\t}\n\n\t\t\t\t\tdistinctValues[ printoutValues[ i ] ] = printoutFormattedValue;\n\t\t\t\t\tdistinctSortValues[ printoutValues[ i ] ] = printoutSortValues[ i ];\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( let printoutValue in distinctSortValues ) {\n\t\t\t\tsortedEntries.push( {\n\t\t\t\t\tprintoutValue: printoutValue,\n\t\t\t\t\tsortValue: distinctSortValues[ printoutValue ],\n\t\t\t\t\tformattedValue: distinctValues[ printoutValue ]\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tsortedEntries.sort(\n\t\t\t\t( a: any, b: any ) => {\n\t\t\t\t\treturn a.sortValue.localeCompare( b.sortValue );\n\t\t\t\t} );\n\t\t\treturn sortedEntries;\n\n\t\t}\n\n\t}\n\n\tprivate buildControl() {\n\n\t\tlet filtercontrols = this.buildEmptyControl();\n\n\t\tfiltercontrols = this.addControlForSwitches( filtercontrols );\n\n\t\tlet maxCheckboxes = this.options.hasOwnProperty( 'max checkboxes' ) ? this.options[ 'max checkboxes' ] : 5;\n\n\t\tif ( this.values.length > maxCheckboxes ) {\n\t\t\tfiltercontrols.append( this.getSelected2Control() );\n\t\t} else {\n\t\t\tfiltercontrols.append( this.getCheckboxesControl() );\n\t\t}\n\n\t}\n\n\tprivate getCheckboxesControl() {\n\n\t\tlet checkboxes = $( '<div class=\"filtered-value-checkboxes\" style=\"width: 100%;\">' );\n\n\t\t// insert options (checkboxes and labels)\n\t\tfor ( let value of this.values ) {\n\t\t\tcheckboxes.append( `<div class=\"filtered-value-option\"><label><input type=\"checkbox\" value=\"${value.printoutValue}\" ><div class=\"filtered-value-option-label\">${value.formattedValue || value.printoutValue}</div></label></div>` );\n\t\t}\n\n\t\t// attach event handler\n\t\tcheckboxes\n\t\t.on( 'change', ':checkbox', ( eventObject: JQueryEventObject ) => {\n\t\t\tlet checkboxElement = <HTMLInputElement> eventObject.currentTarget;\n\t\t\tthis.onFilterUpdated( checkboxElement.value, checkboxElement.checked );\n\t\t} );\n\n\t\treturn checkboxes;\n\t}\n\n\tprivate getSelected2Control() {\n\n\t\tlet select = $( '<select class=\"filtered-value-select\" style=\"width: 100%;\">' );\n\n\t\tlet data: IdTextPair[] = [];\n\n\t\t// insert options (checkboxes and labels) and attach event handlers\n\t\tfor ( let value of this.values ) {\n\t\t\t// Try to get label, if not fall back to value id\n\t\t\tlet label = value.formattedValue || value.printoutValue;\n\t\t\tdata.push( { id: value.printoutValue, text: label } );\n\n\t\t}\n\n\t\tmw.loader.using( 'ext.srf.filtered.value-filter.select' ).then( () => {\n\n\t\t\tselect.select2( {\n\t\t\t\tmultiple: true,\n\t\t\t\tplaceholder: mw.message( 'srf-filtered-value-filter-placeholder' ).text(),\n\t\t\t\tdata: data\n\t\t\t} );\n\n\t\t\tselect.on( \"select2:select\", ( e: any ) => {\n\t\t\t\tthis.onFilterUpdated( e.params.data.id, true );\n\t\t\t} );\n\n\t\t\tselect.on( \"select2:unselect\", ( e: any ) => {\n\t\t\t\tthis.onFilterUpdated( e.params.data.id, false );\n\t\t\t} );\n\n\t\t} );\n\n\t\treturn select;\n\t}\n\n\tprivate addControlForSwitches( filtercontrols: JQuery ): JQuery {\n\t\t// insert switches\n\t\tlet switches = this.options.hasOwnProperty( 'switches' ) ? this.options[ 'switches' ] : undefined;\n\n\t\tif ( switches !== undefined && $.inArray( 'and or', switches ) >= 0 ) {\n\n\t\t\tlet switchControls = $( '<div class=\"filtered-value-switches\">' );\n\n\t\t\tlet andorControl = $( '<div class=\"filtered-value-andor\">' );\n\n\t\t\tlet orControl = this.getRadioControl( 'or', true );\n\t\t\tlet andControl = this.getRadioControl( 'and' );\n\n\t\t\tandorControl\n\t\t\t.append( orControl )\n\t\t\t.append( andControl )\n\t\t\t.appendTo( switchControls );\n\n\t\t\tandorControl\n\t\t\t.find( 'input' )\n\t\t\t.on( 'change', undefined, { 'filter': this }, ( eventObject: JQueryEventObject ) =>\n\t\t\t\teventObject.data.filter.useOr( eventObject.target.getAttribute( 'value' ) === 'or' )\n\t\t\t);\n\n\n\t\t\tfiltercontrols.append( switchControls );\n\t\t}\n\n\t\treturn filtercontrols;\n\t}\n\n\tprivate getRadioControl( type: string, isChecked: boolean = false ) {\n\n\t\tlet checkedAttr = isChecked?'checked':'';\n\t\tlet labelText = mw.message( 'srf-filtered-value-filter-' + type ).text();\n\n\t\tlet controlText =\n\t\t\t`<label for=\"filtered-value-${type}-${this.printrequestId}\">` +\n\t\t\t`<input type=\"radio\" name=\"filtered-value-${this.printrequestId}\" class=\"filtered-value-${type}\" id=\"filtered-value-${type}-${this.printrequestId}\" value=\"${type}\" ${checkedAttr}>` +\n\t\t\t`${labelText}</label>`;\n\n\t\treturn $( controlText );\n\t}\n\n\tpublic isVisible( rowId: string ): boolean {\n\n\t\tif ( this.visibleValues.length === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tlet values: string[] = this.controller.getData()[ rowId ].printouts[ this.printrequestId ].values;\n\n\t\tif ( values.length === 0 ) {\n\t\t\treturn super.isVisible( rowId );\n\t\t}\n\n\n\t\tif ( this._useOr ) {\n\t\t\tfor ( let expectedValue of this.visibleValues ) {\n\t\t\t\tif ( values.indexOf( expectedValue ) >= 0 ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} else {\n\t\t\tfor ( let expectedValue of this.visibleValues ) {\n\t\t\t\tif ( values.indexOf( expectedValue ) < 0 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tpublic onFilterUpdated( value: string, isChecked: boolean ) {\n\t\tlet index = this.visibleValues.indexOf( value );\n\n\t\tif ( isChecked && index === -1 ) {\n\t\t\tthis.visibleValues.push( value );\n\t\t} else if ( !isChecked && index >= 0 ) {\n\t\t\tthis.visibleValues.splice( index, 1 );\n\t\t}\n\n\t\tthis.controller.onFilterUpdated( this.getId() );\n\t}\n}\n","import { Options } from \"../types\";\nimport { Controller } from \"./Controller\";\nimport { ViewSelector } from \"./ViewSelector\";\nimport { View } from \"./View/View\";\nimport { ListView } from \"./View/ListView\";\nimport { TableView } from \"./View/TableView\";\nimport { MapView } from \"./View/MapView\";\nimport { CalendarView } from \"./View/CalendarView\";\nimport { Filter } from \"./Filter/Filter\";\nimport { ValueFilter } from \"./Filter/ValueFilter\";\nimport { DistanceFilter } from \"./Filter/DistanceFilter\";\nimport { NumberFilter } from \"./Filter/NumberFilter\";\n\n/**\n * Central Filtered class\n *\n * Factory to setup everyhting else\n */\nexport class Filtered {\n\n\tprivate config: any;\n\tprivate target: JQuery;\n\n\tprivate viewTypes: { [key: string]: new( id: string, target: JQuery, controller: Controller, options?: any ) => View } = {\n\t\ttable: TableView,\n\t\tlist: ListView,\n\t\tmap: MapView,\n\t\tcalendar: CalendarView\n\t};\n\n\tprivate filterTypes: { [key: string]: new( id: string, target: JQuery, printrequestId: string, controller: Controller, options?: Options ) => Filter } = {\n\t\tvalue: ValueFilter,\n\t\tdistance: DistanceFilter,\n\t\tnumber: NumberFilter\n\t};\n\n\t/**\n\t *\n\t * @param target\n\t * @param config\n\t */\n\tpublic constructor( target: JQuery, config: any ) {\n\t\tthis.config = config;\n\t\tthis.target = target;\n\t}\n\n\tpublic run() {\n\n\t\tlet controller = new Controller( this.target, this.config.data, this.config.printrequests );\n\n\t\tthis.attachFilters( controller, this.target.children( 'div.filtered-filters' ) );\n\t\tthis.attachViewSelector( controller, this.target.find( 'div.filtered-views-selectors-container' ) );\n\t\tthis.attachViews( controller, this.target.find( 'div.filtered-views-container' ) );\n\n\t\t// lift-off\n\t\tcontroller.show();\n\n\t}\n\n\tprivate attachFilters( controller: Controller, filtersContainer: JQuery ) {\n\n\t\tfor ( let prId in this.config.printrequests ) {\n\n\t\t\tlet pr = this.config.printrequests[ prId ];\n\n\t\t\tif ( pr.hasOwnProperty( 'filters' ) ) {\n\n\t\t\t\tfor ( let filterid in pr.filters ) {\n\n\t\t\t\t\tif ( pr.filters.hasOwnProperty( filterid ) &&\n\t\t\t\t\t\tpr.filters[ filterid ].hasOwnProperty( 'type' ) &&\n\t\t\t\t\t\tthis.filterTypes.hasOwnProperty( pr.filters[ filterid ].type ) ) {\n\n\t\t\t\t\t\t// target: JQuery, printrequest: string,\n\t\t\t\t\t\t// controller: Controller, options?: Options\n\t\t\t\t\t\tlet filter: Filter = new this.filterTypes[ pr.filters[ filterid ].type ]( filterid, filtersContainer.children( '#' + filterid ), prId, controller, pr.filters[ filterid ] );\n\n\t\t\t\t\t\tcontroller.attachFilter( filter );\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\tprivate attachViewSelector( controller: Controller, viewSelectorContainer: JQuery ) {\n\t\tlet viewSelector = new ViewSelector( viewSelectorContainer, Object.keys( this.config.views ), controller );\n\t\tviewSelector.init();\n\t}\n\n\tprivate attachViews( controller: Controller, viewsContainer: JQuery ) {\n\n\t\t// attach views\n\t\tfor ( let viewid in this.config.views ) {\n\n\t\t\tlet viewtype = this.config.views[ viewid ][ 'type' ];\n\t\t\tlet viewHandlerClass = this.viewTypes.hasOwnProperty( viewtype ) ? this.viewTypes[ viewtype ] : View;\n\n\t\t\tlet view: View = new viewHandlerClass( viewid, viewsContainer.children( '#' + viewid ), controller, this.config.views[ viewid ] );\n\n\t\t\tview.init();\n\n\t\t\tcontroller.attachView( viewid, view );\n\n\t\t}\n\t}\n}\n","import { View } from \"./View\";\ndeclare let mw: any;\n\nexport class CalendarView extends View {\n\n\tprivate getI18N() {\n\t\treturn {\n\t\t\tmonthNames: [ mw.msg( 'january' ), mw.msg( 'february' ), mw.msg( 'march' ),\n\t\t\t\tmw.msg( 'april' ), mw.msg( 'may_long' ), mw.msg( 'june' ),\n\t\t\t\tmw.msg( 'july' ), mw.msg( 'august' ), mw.msg( 'september' ),\n\t\t\t\tmw.msg( 'october' ), mw.msg( 'november' ), mw.msg( 'december' )\n\t\t\t],\n\t\t\tmonthNamesShort: [ mw.msg( 'jan' ), mw.msg( 'feb' ), mw.msg( 'mar' ),\n\t\t\t\tmw.msg( 'apr' ), mw.msg( 'may' ), mw.msg( 'jun' ),\n\t\t\t\tmw.msg( 'jul' ), mw.msg( 'aug' ), mw.msg( 'sep' ),\n\t\t\t\tmw.msg( 'oct' ), mw.msg( 'nov' ), mw.msg( 'dec' )\n\t\t\t],\n\t\t\tdayNames: [ mw.msg( 'sunday' ), mw.msg( 'monday' ), mw.msg( 'tuesday' ),\n\t\t\t\tmw.msg( 'wednesday' ), mw.msg( 'thursday' ), mw.msg( 'friday' ), mw.msg( 'saturday' )\n\t\t\t],\n\t\t\tdayNamesShort: [ mw.msg( 'sun' ), mw.msg( 'mon' ), mw.msg( 'tue' ),\n\t\t\t\tmw.msg( 'wed' ), mw.msg( 'thu' ), mw.msg( 'fri' ), mw.msg( 'sat' )\n\t\t\t],\n\t\t\tbuttonText: {\n\t\t\t\ttoday: mw.msg( 'srf-ui-eventcalendar-label-today' ),\n\t\t\t\tmonth: mw.msg( 'srf-ui-eventcalendar-label-month' ),\n\t\t\t\tweek: mw.msg( 'srf-ui-eventcalendar-label-week' ),\n\t\t\t\tday: mw.msg( 'srf-ui-eventcalendar-label-day' )\n\t\t\t}\n\t\t\t,\n\t\t\tallDayText: mw.msg( 'srf-ui-eventcalendar-label-allday' ),\n\t\t\ttimeFormat: {\n\t\t\t\t'': mw.msg( 'srf-ui-eventcalendar-format-time' ),\n\t\t\t\tagenda: mw.msg( 'srf-ui-eventcalendar-format-time-agenda' )\n\t\t\t}\n\t\t\t,\n\t\t\taxisFormat: mw.msg( 'srf-ui-eventcalendar-format-axis' ),\n\t\t\ttitleFormat: {\n\t\t\t\tmonth: mw.msg( 'srf-ui-eventcalendar-format-title-month' ),\n\t\t\t\tweek: mw.msg( 'srf-ui-eventcalendar-format-title-week' ),\n\t\t\t\tday: mw.msg( 'srf-ui-eventcalendar-format-title-day' )\n\t\t\t}\n\t\t\t,\n\t\t\tcolumnFormat: {\n\t\t\t\tmonth: mw.msg( 'srf-ui-eventcalendar-format-column-month' ),\n\t\t\t\tweek: mw.msg( 'srf-ui-eventcalendar-format-column-week' ),\n\t\t\t\tday: mw.msg( 'srf-ui-eventcalendar-format-column-day' )\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic init() {\n\n\t\tlet _i18n = this.getI18N();\n\n\t\t// initialize the calendar\n\t\tthis.target.fullCalendar( {\n\n\t\t\tfirstDay: this.options.firstDay,\n\t\t\tisRTL: this.options.isRTL,\n\t\t\tmonthNames: _i18n.monthNames,\n\t\t\tmonthNamesShort: _i18n.monthNamesShort,\n\t\t\tdayNames: _i18n.dayNames,\n\t\t\tdayNamesShort: _i18n.dayNamesShort,\n\t\t\tbuttonText: _i18n.buttonText,\n\t\t\tallDayText: _i18n.allDayText,\n\t\t\ttimeFormat: _i18n.timeFormat,\n\t\t\ttitleFormat: _i18n.titleFormat,\n\t\t\tcolumnFormat: _i18n.columnFormat\n\t\t} );\n\t}\n\n\tprivate getEvent( rowId: any, rowData: any ) {\n\n\t\tlet eventdata: any = {\n\t\t\tid: rowId,\n\t\t\ttitle: rowData[ 'title' ],\n\t\t\tstart: rowData[ 'start' ],\n\t\t\tclassName: rowId\n\t\t};\n\n\t\tif ( rowData.hasOwnProperty( 'end' ) ) {\n\t\t\teventdata[ 'end' ] = rowData[ 'end' ];\n\t\t}\n\n\t\tif ( rowData.hasOwnProperty( 'url' ) ) {\n\t\t\teventdata[ 'url' ] = rowData[ 'url' ];\n\t\t}\n\n\t\treturn eventdata;\n\t}\n\n\tpublic showRows( rowIds: string[] ): any {\n\n\t\tlet events: any[] = [];\n\n\t\trowIds.forEach( ( rowId: string ) => {\n\n\t\t\tlet rowData = this.controller.getData()[ rowId ].data[ this.id ];\n\n\t\t\tif ( rowData.hasOwnProperty( 'start' ) ) {\n\t\t\t\tevents.push( this.getEvent( rowId, rowData ) );\n\t\t\t}\n\t\t} );\n\n\t\tthis.target.fullCalendar( 'addEventSource', events );\n\t}\n\n\tpublic hideRows( rowIds: string[] ): any {\n\t\tthis.target.fullCalendar( 'removeEvents', ( e: any ) => ( rowIds.indexOf( e._id ) >= 0 ) );\n\t}\n\n\tpublic show(): any {\n\t\tsuper.show();\n\t\tthis.target.fullCalendar( 'render' );\n\t}\n\n\tpublic hide(): any {\n\t\treturn super.hide();\n\t}\n\n}\n","import { View } from \"./View\";\n\nexport class ListView extends View {\n\n\tprotected getItemClassName() {\n\t\treturn '.filtered-list-item';\n\t}\n\n\n}\n","/// <reference types=\"leaflet\" />\n\nimport { View } from \"./View\";\nimport { Options } from \"../../types\"\n\ndeclare let mw: any;\n\nexport class MapView extends View {\n\n\tprivate map: L.Map = undefined;\n\tprivate icon: { [key: string]: L.Icon } = undefined;\n\tprivate markers: { [key: string]: L.Marker[] } = undefined;\n\tprivate markerClusterGroup: L.MarkerClusterGroup = undefined;\n\tprivate bounds: L.LatLngBounds = undefined;\n\tprivate initialized: boolean = false;\n\n\tprivate zoom: number = -1;\n\tprivate minZoom: number = -1;\n\tprivate maxZoom: number = -1;\n\n\tprivate leafletPromise: Promise<any> = undefined;\n\n\tpublic init(): Promise<any> {\n\n\t\tlet data = this.controller.getData();\n\t\tlet markers: { [rowId: string]: L.Marker[] } = {};\n\n\t\tif ( this.options.hasOwnProperty( 'height' ) ) {\n\t\t\tthis.target.height( this.options.height );\n\t\t}\n\n\t\tthis.leafletPromise = mw.loader.using( 'ext.srf.filtered.map-view.leaflet' )\n\t\t.then( () => {\n\n\t\t\tlet bounds: L.LatLngBounds = undefined;\n\t\t\tlet disableClusteringAtZoom = this.getZoomForUnclustering();\n\n\t\t\tlet clusterOptions: Options = {\n\t\t\t\tanimateAddingMarkers: true,\n\t\t\t\tdisableClusteringAtZoom: disableClusteringAtZoom,\n\t\t\t\tspiderfyOnMaxZoom: disableClusteringAtZoom === null\n\t\t\t};\n\n\t\t\tclusterOptions = this.getOptions( [ 'maxClusterRadius', 'zoomToBoundsOnClick' ], clusterOptions );\n\n\t\t\tlet markerClusterGroup: L.MarkerClusterGroup = L.markerClusterGroup( clusterOptions );\n\n\t\t\tfor ( let rowId in data ) {\n\n\t\t\t\tif ( data[ rowId ][ 'data' ].hasOwnProperty( this.id ) ) {\n\t\t\t\t\tlet positions: L.LatLngLiteral[] = data[ rowId ][ 'data' ][ this.id ][ 'positions' ];\n\t\t\t\t\tmarkers[ rowId ] = [];\n\n\t\t\t\t\tfor ( let pos of positions ) {\n\n\t\t\t\t\t\tbounds = ( bounds === undefined ) ? new L.LatLngBounds( pos, pos ) : bounds.extend( pos );\n\n\t\t\t\t\t\tlet marker = this.getMarker( pos, data[ rowId ] );\n\t\t\t\t\t\tmarkers[ rowId ].push( marker );\n\t\t\t\t\t\tmarkerClusterGroup.addLayer( marker );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.markerClusterGroup = markerClusterGroup;\n\t\t\tthis.markers = markers;\n\t\t\tthis.bounds = ( bounds === undefined ) ? new L.LatLngBounds( [ -180, -90 ], [ 180, 90 ] ) : bounds;\n\t\t} );\n\n\t\treturn this.leafletPromise;\n\t}\n\n\tprivate getZoomForUnclustering() {\n\n\t\tif ( this.options.hasOwnProperty( 'marker cluster' ) && this.options[ 'marker cluster' ] === false ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( this.options.hasOwnProperty( 'marker cluster max zoom' ) ) {\n\t\t\treturn this.options[ 'marker cluster max zoom' ] + 1;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate getIcon( row: any ) {\n\n\t\tif ( this.icon === undefined ) {\n\t\t\tthis.buildIconList();\n\t\t}\n\n\t\tif ( this.options.hasOwnProperty( 'marker icon property' ) ) {\n\n\t\t\tlet vals: string[] = row[ 'printouts' ][ this.options[ 'marker icon property' ] ][ 'values' ];\n\n\t\t\tif ( vals.length > 0 && this.icon.hasOwnProperty( vals[ 0 ] ) ) {\n\t\t\t\treturn this.icon[ vals[ 0 ] ];\n\t\t\t}\n\t\t}\n\n\t\treturn this.icon[ 'default' ];\n\t}\n\n\tprivate buildIconList() {\n\t\tthis.icon = {};\n\n\t\tlet iconPath = this.controller.getPath() + 'css/images/';\n\n\t\tthis.icon[ 'default' ] = new L.Icon( {\n\t\t\t'iconUrl': iconPath + 'marker-icon.png',\n\t\t\t'iconRetinaUrl': iconPath + 'marker-icon-2x.png',\n\t\t\t'shadowUrl': iconPath + 'marker-shadow.png',\n\t\t\t'iconSize': [ 25, 41 ],\n\t\t\t'iconAnchor': [ 12, 41 ],\n\t\t\t'popupAnchor': [ 1, -34 ],\n\t\t\t// 'tooltipAnchor': [16, -28],\n\t\t\t'shadowSize': [ 41, 41 ]\n\t\t} );\n\n\t\tif ( this.options.hasOwnProperty( 'marker icons' ) ) {\n\n\t\t\tfor ( let value in this.options[ 'marker icons' ] ) {\n\t\t\t\tthis.icon[ value ] = new L.Icon( {\n\t\t\t\t\t'iconUrl': this.options[ 'marker icons' ][ value ],\n\t\t\t\t\t// 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',\n\t\t\t\t\t'shadowUrl': iconPath + 'marker-shadow.png',\n\t\t\t\t\t'iconSize': [ 32, 32 ],\n\t\t\t\t\t'iconAnchor': [ 16, 32 ],\n\t\t\t\t\t'popupAnchor': [ 1, -30 ],\n\t\t\t\t\t// 'tooltipAnchor': [16, -28],\n\t\t\t\t\t'shadowSize': [ 41, 41 ],\n\t\t\t\t\t'shadowAnchor': [ 12, 41 ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getMarker( latLng: L.LatLngExpression, row: any ) {\n\t\tlet title = undefined;\n\t\tlet popup = [];\n\n\t\t// TODO: Use <div> instead of <b> and do CSS styling\n\n\t\tfor ( let prId in row[ 'printouts' ] ) {\n\t\t\tlet printrequest = (this.controller.getPrintRequests())[ prId ];\n\n\t\t\tif ( ! printrequest.hasOwnProperty('hide') || printrequest.hide === false ) {\n\t\t\t\tlet printouts = row[ 'printouts' ][ prId ];\n\n\t\t\t\tif ( title === undefined ) {\n\t\t\t\t\ttitle = printouts[ 'values' ].join( ', ' );\n\t\t\t\t\tpopup.push( '<b>' + printouts[ 'formatted values' ].join( ', ' ) + '</b>' );\n\t\t\t\t} else {\n\t\t\t\t\tpopup.push( (printouts.label ? '<b>' + printouts.label + ':</b> ' : '') + printouts[ 'formatted values' ].join( ', ' ) )\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet marker = L.marker( latLng, { title: title, alt: title } );\n\t\tmarker.bindPopup( popup.join( '<br>' ) );\n\n\t\tmarker.setIcon( this.getIcon( row ) );\n\t\treturn marker;\n\t}\n\n\tpublic lateInit() {\n\n\t\tif ( this.initialized ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.initialized = true;\n\n\t\tlet that = this;\n\n\t\tthis.leafletPromise.then( () => {\n\n\t\t\tlet mapOptions: Options = {\n\t\t\t\tcenter: this.bounds !== undefined ? this.bounds.getCenter() : [ 0, 0 ]\n\t\t\t};\n\n\t\t\tmapOptions = that.getOptions( [ 'zoom', 'minZoom', 'maxZoom' ], mapOptions );\n\n\t\t\t// TODO: Limit zoom values to map max zoom\n\n\t\t\tthat.map = L.map( <HTMLElement> that.getTargetElement().get( 0 ), mapOptions );\n\t\t\tthat.map.addLayer( that.markerClusterGroup );\n\n\t\t\tif ( this.options.hasOwnProperty( 'map provider' ) ) {\n\t\t\t\tL.tileLayer.provider( this.options[ 'map provider' ] ).addTo( that.map );\n\t\t\t}\n\n\t\t\tif ( !mapOptions.hasOwnProperty( 'zoom' ) ) {\n\t\t\t\tthat.map.fitBounds( that.bounds );\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n\tpublic getOptions( keys: string[], defaults: Options = {} ) {\n\n\t\tfor ( let key of keys ) {\n\t\t\tif ( this.options.hasOwnProperty( key ) ) {\n\t\t\t\tdefaults[ key ] = this.options[ key ];\n\t\t\t}\n\t\t}\n\n\t\treturn defaults;\n\t}\n\n\tpublic showRows( rowIds: string[] ) {\n\t\tthis.leafletPromise.then( () => {\n\t\t\tthis.manipulateLayers( rowIds, ( layers: L.Layer[] ) => {\n\t\t\t\tthis.markerClusterGroup.addLayers( layers )\n\t\t\t} )\n\t\t} );\n\t}\n\n\tpublic hideRows( rowIds: string[] ) {\n\t\tthis.leafletPromise.then( () => {\n\t\t\tthis.manipulateLayers( rowIds, ( layers: L.Layer[] ) => {\n\t\t\t\tthis.markerClusterGroup.removeLayers( layers )\n\t\t\t} )\n\t\t} );\n\t}\n\n\tprivate manipulateLayers( rowIds: string[], cb: ( layers: L.Layer[] ) => void ) {\n\n\t\tlet layersFromRowIds = this.getLayersFromRowIds( rowIds );\n\n\t\tif ( layersFromRowIds.length > 0 ) {\n\t\t\tcb( layersFromRowIds );\n\t\t}\n\n\t}\n\n\tprivate getLayersFromRowIds( rowIds: string[] ) {\n\t\treturn this.flatten( this.getLayersFromRowIdsRaw( rowIds ) );\n\t}\n\n\tprivate getLayersFromRowIdsRaw( rowIds: string[] ) {\n\t\treturn rowIds.map( ( rowId: string ) => this.markers[ rowId ] ? this.markers[ rowId ] : [] );\n\t}\n\n\tprivate flatten( markers: L.Layer[][] ): L.Layer[] {\n\t\treturn markers.reduce( ( result: L.Layer[], layers: L.Layer[] ) => result.concat( layers ), [] );\n\t}\n\n\tpublic show() {\n\t\tsuper.show();\n\t\tthis.lateInit();\n\t}\n\n}\n","import { View } from \"./View\";\n\nexport class TableView extends View {\n\n\tprotected getItemClassName() {\n\t\treturn '.filtered-table-item';\n\t}\n\n}","import { Options } from \"../../types\";\nimport { Controller } from \"../Controller\";\n\nexport class View {\n\n\tprotected id: string = undefined;\n\tprotected target: JQuery = undefined;\n\tprotected controller: Controller = undefined;\n\tprotected options: Options = undefined;\n\tprotected visible: boolean = false;\n\tprotected rows: { [ rowId: string ]: JQuery } = {};\n\n\tpublic constructor( id: string, target: JQuery, c: Controller, options: Options = {} ) {\n\t\tthis.id = id;\n\t\tthis.target = target;\n\t\tthis.controller = c;\n\t\tthis.options = options;\n\t}\n\n\tpublic init(): Promise<any>|void {\n\n\t\tlet rowIds = Object.keys( this.controller.getData() );\n\t\tlet rows = this.target.find( this.getItemClassName() );\n\n\t\trows.each( ( index, elem ) => {\n\t\t\tlet classes = elem.classList;\n\t\t\tfor ( let i = 0; i < classes.length; i++ ) {\n\t\t\t\tif ( rowIds.indexOf( classes[ i ] ) >= 0 ) {\n\t\t\t\t\tthis.rows[ classes[ i ] ] = $( rows[ index ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\tprotected getItemClassName() {\n\t\treturn '.filtered-item';\n\t}\n\n\tpublic getTargetElement(): JQuery {\n\t\treturn this.target;\n\t}\n\n\tpublic showRows( rowIds: string[] ) {\n\n\t\tif ( this.visible && rowIds.length < 200 ) {\n\n\t\t\trowIds.forEach( ( rowId: string ) => {\n\t\t\t\tthis.rows[ rowId ].slideDown( 400 );\n\t\t\t} );\n\n\t\t} else {\n\n\t\t\trowIds.forEach( ( rowId: string ) => {\n\t\t\t\tthis.rows[ rowId ].css( 'display', '');\n\t\t\t} );\n\n\t\t}\n\t}\n\n\tpublic hideRows( rowIds: string[] ) {\n\n\t\tif ( this.visible && rowIds.length < 200 ) {\n\n\t\t\trowIds.forEach( ( rowId: string ) => {\n\t\t\t\tthis.rows[ rowId ].slideUp( 400 );\n\t\t\t} );\n\n\t\t} else {\n\n\t\t\trowIds.forEach( ( rowId: string ) => {\n\t\t\t\tthis.rows[ rowId ].css( 'display', 'none');\n\t\t\t} );\n\n\t\t}\n\t}\n\n\tpublic show() {\n\t\tthis.target.show();\n\t\tthis.visible = true;\n\t}\n\n\tpublic hide() {\n\t\tthis.target.hide();\n\t\tthis.visible = false;\n\t}\n}\n","import { Controller } from \"./Controller\";\nexport class ViewSelector {\n\n\tprivate target: JQuery = undefined;\n\tprivate viewIDs: string[] = undefined;\n\n\tprivate controller: Controller = undefined;\n\n\tpublic constructor( target: JQuery, viewIDs: string[], controller: Controller ) {\n\t\tthis.target = target;\n\t\tthis.viewIDs = viewIDs;\n\t\tthis.controller = controller;\n\t}\n\n\tpublic init() {\n\t\tif ( this.viewIDs.length > 1 ) {\n\t\t\tthis.viewIDs.forEach( ( id: string) => { this.target.on( 'click', '.' + id, { 'target': id, 'controller' : this.controller }, ViewSelector.onSelectorSelected ); } );\n\t\t\tthis.target.children().first().addClass( 'selected');\n\t\t\tthis.target.show();\n\t\t}\n\t}\n\n\tprivate static onSelectorSelected( event: JQueryEventObject ) {\n\n\t\tevent.data.controller.onViewSelected( event.data.target );\n\n\t\t$( event.target )\n\t\t.addClass( 'selected')\n\t\t.siblings().removeClass( 'selected' );\n\n\t\tevent.stopPropagation();\n\t\tevent.preventDefault();\n\t}\n\n}","import { Filtered } from \"./Filtered/Filtered\";\n\ndeclare let mw: any;\nlet config = mw.config.get( 'srfFilteredConfig' );\n\nfor ( let id in config ) {\n\tif ( config.hasOwnProperty( id ) ) {\n\t\tlet f = new Filtered( $( '#' + id ), config[ id ] );\n\t\tmw.hook( 'wikipage.content' ).add( () => f.run() );\n\t}\n}"],"preExistingComment":"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJyZXNvdXJjZXMvdHMvRmlsdGVyZWQvQ29udHJvbGxlci50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9GaWx0ZXIvRGlzdGFuY2VGaWx0ZXIudHMiLCJyZXNvdXJjZXMvdHMvRmlsdGVyZWQvRmlsdGVyL0ZpbHRlci50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9GaWx0ZXIvTnVtYmVyRmlsdGVyLnRzIiwicmVzb3VyY2VzL3RzL0ZpbHRlcmVkL0ZpbHRlci9WYWx1ZUZpbHRlci50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9GaWx0ZXJlZC50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9WaWV3L0NhbGVuZGFyVmlldy50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9WaWV3L0xpc3RWaWV3LnRzIiwicmVzb3VyY2VzL3RzL0ZpbHRlcmVkL1ZpZXcvTWFwVmlldy50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9WaWV3L1RhYmxlVmlldy50cyIsInJlc291cmNlcy90cy9GaWx0ZXJlZC9WaWV3L1ZpZXcudHMiLCJyZXNvdXJjZXMvdHMvRmlsdGVyZWQvVmlld1NlbGVjdG9yLnRzIiwicmVzb3VyY2VzL3RzL2Jvb3RzdHJhcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQSxnQ0FBZ0M7O0FBS2hDLG9DQUFtQztBQUduQztJQVVDLG9CQUFvQixNQUFjLEVBQUUsSUFBZ0IsRUFBRSxhQUFzQjtRQVRwRSxXQUFNLEdBQVcsU0FBUyxDQUFDO1FBQzNCLGtCQUFhLEdBQVcsU0FBUyxDQUFDO1FBRWxDLFVBQUssR0FBNEIsRUFBRSxDQUFDO1FBQ3BDLFlBQU8sR0FBOEIsRUFBRSxDQUFDO1FBQ3hDLGdCQUFXLEdBQVMsU0FBUyxDQUFDO1FBS3JDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBRXJCLElBQUssSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUc7WUFDaEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBRSw2QkFBNkIsQ0FBRSxDQUFDO1NBQ3ZFO1FBRUQsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFFbkMsS0FBTSxJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFHO1lBQzlCLElBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLGNBQWMsQ0FBRSxTQUFTLENBQUUsRUFBRztnQkFDdEQsSUFBSSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2FBQ2hDO1NBQ0Q7SUFDRixDQUFDO0lBRU0sNEJBQU8sR0FBZDtRQUNDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQztJQUNsQixDQUFDO0lBRU0scUNBQWdCLEdBQXZCO1FBQ0MsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQzNCLENBQUM7SUFFTSw0QkFBTyxHQUFkO1FBQ0MsT0FBTyxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBRSxnQkFBZ0IsQ0FBRSxHQUFHLDhCQUE4QixDQUFDO0lBQzlFLENBQUM7SUFFTSwrQkFBVSxHQUFqQixVQUFtQixNQUFjLEVBQUUsSUFBVTtRQUU1QyxJQUFJLENBQUMsS0FBSyxDQUFFLE1BQU0sQ0FBRSxHQUFHLElBQUksQ0FBQztRQUU1QixJQUFLLElBQUksQ0FBQyxXQUFXLEtBQUssU0FBUyxFQUFHO1lBQ3JDLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUNaO2FBQU07WUFDTixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDWjtRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2IsQ0FBQztJQUVNLDRCQUFPLEdBQWQsVUFBZ0IsTUFBYztRQUM3QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUUsTUFBTSxDQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVNLGlDQUFZLEdBQW5CLFVBQXFCLE1BQWM7UUFDbEMsSUFBSSxRQUFRLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRTlCLElBQUksQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLEdBQUcsTUFBTSxDQUFDO1FBRWxDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUVkLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBRSxRQUFRLENBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRU0sOEJBQVMsR0FBaEIsVUFBa0IsUUFBZ0I7UUFDakMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFFLFFBQVEsQ0FBRSxDQUFDO0lBQ2pDLENBQUM7SUFFTSx5QkFBSSxHQUFYO1FBQ0MsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUUsbUJBQW1CLENBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzlCLElBQUksQ0FBQyxZQUFZLENBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxpQ0FBWSxHQUFwQixVQUFzQixJQUFVO1FBRS9CLElBQUssSUFBSSxDQUFDLFdBQVcsWUFBWSxXQUFJLEVBQUc7WUFDdkMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUN4QjtRQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBRXhCLElBQUssSUFBSSxDQUFDLFdBQVcsWUFBWSxXQUFJLEVBQUc7WUFDdkMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ1o7SUFFRixDQUFDO0lBRU8sc0NBQWlCLEdBQXpCO1FBQ0MsSUFBSSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBQzFCLElBQUksTUFBTSxHQUFhLEVBQUUsQ0FBQztRQUUxQixLQUFNLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUc7WUFDOUIsS0FBTSxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFHO2dCQUNwQyxJQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFFLFFBQVEsQ0FBRSxDQUFDLFVBQVUsRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUMsU0FBUyxDQUFFLEtBQUssQ0FBRSxDQUFDO2FBQzlIO1lBQ0QsSUFBSyxJQUFJLENBQUMsU0FBUyxDQUFFLEtBQUssQ0FBRSxFQUFHO2dCQUM5QixNQUFNLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDO2FBQ3JCO2lCQUFNO2dCQUNOLE1BQU0sQ0FBQyxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUM7YUFDckI7U0FDRDtRQUVELElBQUksQ0FBQyxRQUFRLENBQUUsTUFBTSxDQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLFFBQVEsQ0FBRSxNQUFNLENBQUUsQ0FBQztJQUN6QixDQUFDO0lBRU0sbUNBQWMsR0FBckIsVUFBdUIsTUFBYztRQUNwQyxJQUFJLENBQUMsWUFBWSxDQUFFLElBQUksQ0FBQyxLQUFLLENBQUUsTUFBTSxDQUFFLENBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRU0sb0NBQWUsR0FBdEIsVUFBd0IsUUFBZ0I7UUFBeEMsaUJBOEJDO1FBNUJBLE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRTthQUN4QixJQUFJLENBQUM7WUFFTCxJQUFJLE1BQU0sR0FBYSxFQUFFLENBQUM7WUFDMUIsSUFBSSxNQUFNLEdBQWEsRUFBRSxDQUFDO1lBRTFCLElBQUksUUFBUSxHQUFHLEtBQUksQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUMsVUFBVSxFQUFFLENBQUM7WUFFckQsS0FBTSxJQUFJLEtBQUssSUFBSSxLQUFJLENBQUMsSUFBSSxFQUFHO2dCQUU5QixJQUFJLFVBQVUsR0FBWSxRQUFRLElBQUksS0FBSSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsQ0FBQyxTQUFTLENBQUUsS0FBSyxDQUFFLENBQUM7Z0JBRWxGLElBQUssS0FBSSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLEtBQUssVUFBVSxFQUFHO29CQUU1RCxLQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsR0FBRyxVQUFVLENBQUM7b0JBRXBELElBQUssVUFBVSxJQUFJLEtBQUksQ0FBQyxTQUFTLENBQUUsS0FBSyxDQUFFLEVBQUc7d0JBQzVDLE1BQU0sQ0FBQyxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUM7cUJBQ3JCO3lCQUFNO3dCQUNOLE1BQU0sQ0FBQyxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUM7cUJBQ3JCO2lCQUNEO2FBQ0Q7WUFFRCxLQUFJLENBQUMsUUFBUSxDQUFFLE1BQU0sQ0FBRSxDQUFDO1lBQ3hCLEtBQUksQ0FBQyxRQUFRLENBQUUsTUFBTSxDQUFFLENBQUM7UUFDekIsQ0FBQyxDQUFDO2FBQ0QsSUFBSSxDQUFFLGNBQVEsS0FBSSxDQUFDLFdBQVcsRUFBRSxDQUFBLENBQUMsQ0FBQyxDQUFFLENBQUM7SUFDdkMsQ0FBQztJQUVNLDhCQUFTLEdBQWhCLFVBQWtCLEtBQVU7UUFDM0IsS0FBTSxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLE9BQU8sRUFBRztZQUNsRCxJQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLEVBQUc7Z0JBQzlDLE9BQU8sS0FBSyxDQUFDO2FBQ2I7U0FDRDtRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2IsQ0FBQztJQUVPLDZCQUFRLEdBQWhCLFVBQWtCLE1BQWdCO1FBQ2pDLElBQUssTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUc7WUFDMUIsT0FBTztTQUNQO1FBQ0QsS0FBTSxJQUFJLE1BQU0sSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFHO1lBQ2hDLElBQUksQ0FBQyxLQUFLLENBQUUsTUFBTSxDQUFFLENBQUMsUUFBUSxDQUFFLE1BQU0sQ0FBRSxDQUFDO1NBQ3hDO0lBQ0YsQ0FBQztJQUVPLDZCQUFRLEdBQWhCLFVBQWtCLE1BQWdCO1FBQ2pDLElBQUssTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUc7WUFDMUIsT0FBTztTQUNQO1FBQ0QsS0FBTSxJQUFJLE1BQU0sSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFHO1lBQ2hDLElBQUksQ0FBQyxLQUFLLENBQUUsTUFBTSxDQUFFLENBQUMsUUFBUSxDQUFFLE1BQU0sQ0FBRSxDQUFDO1NBQ3hDO0lBQ0YsQ0FBQztJQUVPLGdDQUFXLEdBQW5CO1FBQ0MsT0FBTyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVPLGdDQUFXLEdBQW5CO1FBQ0MsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFFLEtBQUssQ0FBRSxDQUFDO0lBQ3JDLENBQUM7SUFFTyxtQ0FBYyxHQUF0QixVQUF3QixJQUFvQjtRQUFwQixxQkFBQSxFQUFBLFdBQW9CO1FBRTNDLElBQUssSUFBSSxDQUFDLGFBQWEsS0FBSyxTQUFTLEVBQUc7WUFDdkMsT0FBTyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDckI7UUFFRCxJQUFLLElBQUksRUFBRztZQUNYLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUUsR0FBRyxDQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7U0FDbEQ7UUFFRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFFLEdBQUcsQ0FBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3BELENBQUM7SUFFRixpQkFBQztBQUFELENBbk1BLEFBbU1DLElBQUE7QUFuTVksZ0NBQVU7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQ1J2QixtQ0FBa0M7QUFJbEM7SUFBb0Msa0NBQU07SUFBMUM7UUFBQSxxRUF5SUM7UUEvSFEsc0JBQWdCLEdBQVcsY0FBYyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7UUFDekQsaUJBQVcsR0FBVyxDQUFDLENBQUM7O0lBOEhqQyxDQUFDO0lBNUhPLDZCQUFJLEdBQVg7UUFFQyxJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRXZDLElBQUksTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUM7UUFFdEMsSUFBSyxDQUFDLENBQUUsTUFBTSxLQUFLLFNBQVMsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFFLEtBQUssQ0FBRSxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUUsS0FBSyxDQUFFLENBQUUsRUFBRztZQUNwRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3JCLE9BQU87U0FDUDtRQUVELElBQUksSUFBSSxHQUFHLElBQUksQ0FBQztRQUVoQixJQUFLLElBQUksQ0FBQyxPQUFPLENBQUUsTUFBTSxDQUFFLElBQUksY0FBYyxDQUFDLFdBQVcsQ0FBRSxJQUFJLENBQUMsT0FBTyxDQUFFLE1BQU0sQ0FBRSxDQUFFLEVBQUc7WUFDckYsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsTUFBTSxDQUFFLENBQUM7U0FDOUI7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsY0FBYyxDQUFDLFdBQVcsQ0FBRSxJQUFJLENBQUUsQ0FBQztRQUUzRCxJQUFJLFFBQVEsR0FBVyxJQUFJLENBQUMsZUFBZSxDQUFFLE1BQU0sQ0FBRSxDQUFDO1FBRXRELElBQUksU0FBUyxHQUFHLFNBQUEsRUFBRSxFQUFJLENBQUUsSUFBSSxDQUFDLEtBQUssQ0FBRSxJQUFJLENBQUMsR0FBRyxDQUFFLFFBQVEsQ0FBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQSxDQUFDO1FBRTlFLElBQUssSUFBSSxDQUFDLE9BQU8sQ0FBRSxLQUFLLENBQUUsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBRSxLQUFLLENBQUUsR0FBRyxRQUFRLEVBQUc7WUFDOUUsUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUM7U0FDakM7YUFBTTtZQUNOLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFFLFFBQVEsR0FBRyxTQUFTLENBQUUsR0FBRyxTQUFTLENBQUM7U0FDekQ7UUFFRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsZUFBZSxDQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBRSxlQUFlLENBQUUsRUFBRSxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO1FBRXRILHdCQUF3QjtRQUN4QixJQUFJLGNBQWMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUU5QyxJQUFJLE9BQU8sR0FBRyxDQUFDLENBQUUseUNBQXlDLEdBQUcsSUFBSSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUUsQ0FBQztRQUUzRixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUUsaUdBQWlHO1lBQy9HLDZGQUE2RjtZQUM3Rix5Q0FBeUMsR0FBRyxRQUFRLEdBQUcsWUFBWTtZQUNuRSx3REFBd0QsR0FBRyxJQUFJLEdBQUcsNEJBQTRCLENBQUUsQ0FBQztRQUVsRyxjQUFjLENBQUMsTUFBTSxDQUFFLEtBQUssQ0FBRSxDQUFDO1FBRS9CLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQztRQUNoQixFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBRSxrQkFBa0IsQ0FBRSxDQUFDLElBQUksQ0FBRTtZQUUzQyxLQUFLLENBQUMsSUFBSSxDQUFFLDJCQUEyQixDQUFFO2lCQUN4QyxNQUFNLENBQUU7Z0JBQ1IsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsR0FBRyxFQUFFLFFBQVE7Z0JBQ2IsS0FBSyxFQUFFLElBQUksQ0FBQyxXQUFXO2dCQUN2QixJQUFJLEVBQUUsU0FBUyxHQUFHLEdBQUc7YUFDckIsQ0FBRTtpQkFDRixFQUFFLENBQUUsYUFBYSxFQUFFLFNBQVMsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFBRSxVQUFXLFdBQThCLEVBQUUsRUFBTztnQkFDcEcsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO2dCQUN6QixXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUUsV0FBVyxDQUFFLENBQUM7WUFDeEQsQ0FBQyxDQUFFO2lCQUNGLEVBQUUsQ0FBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxFQUFFLFVBQVcsV0FBOEIsRUFBRSxFQUFPO2dCQUM5RixPQUFPLENBQUMsSUFBSSxDQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUUsQ0FBQztZQUMxQixDQUFDLENBQUU7aUJBQ0YsSUFBSSxDQUFFLG1CQUFtQixDQUFFO2lCQUMzQixNQUFNLENBQUUsT0FBTyxDQUFFLENBQUM7UUFFcEIsQ0FBQyxDQUFFLENBQUM7UUFFSixPQUFPLElBQUksQ0FBQztJQUNiLENBQUM7SUFFTyx3Q0FBZSxHQUF2QixVQUF5QixNQUF1QjtRQUFoRCxpQkFxQkM7UUFuQkEsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN2QyxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFFWixJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBRS9CLEtBQU0sSUFBSSxLQUFLLElBQUksTUFBTSxFQUFHO1lBRTNCLElBQUssTUFBTSxDQUFFLEtBQUssQ0FBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBRSxFQUFHO2dCQUMzRCxJQUFJLFNBQVMsR0FBYSxNQUFNLENBQUUsS0FBSyxDQUFFLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFFLFVBQUUsR0FBb0IsSUFBTSxPQUFBLEtBQUksQ0FBQyxRQUFRLENBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBRSxFQUE1QixDQUE0QixDQUFFLENBQUM7Z0JBQzFJLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLE9BQVIsSUFBSSxFQUFTLFNBQVMsQ0FBRSxDQUFDO2dCQUVwQyxNQUFNLENBQUUsS0FBSyxDQUFFLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO2dCQUN0RCxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBRSxHQUFHLEVBQUUsSUFBSSxDQUFFLENBQUM7YUFDNUI7aUJBQU07Z0JBQ04sTUFBTSxDQUFFLEtBQUssQ0FBRSxDQUFDLElBQUksQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFFLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQzthQUMxRDtTQUNEO1FBRUQsT0FBTyxHQUFHLENBQUM7SUFDWixDQUFDO0lBRU0sd0NBQWUsR0FBdEIsVUFBd0IsV0FBOEI7UUFDckQsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUM7UUFDN0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFFLENBQUM7SUFDakQsQ0FBQztJQUVPLGlDQUFRLEdBQWhCLFVBQWtCLENBQWtCLEVBQUUsQ0FBa0I7UUFFdkQsSUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEVBQUUsR0FBRyxLQUFLLENBQUM7UUFFaEMsU0FBUyxPQUFPLENBQUUsQ0FBUztZQUMxQixPQUFPLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDYixDQUFDO1FBRUQsSUFBSSxDQUFDLEdBQ0osT0FBTyxDQUFFLElBQUksQ0FBQyxHQUFHLENBQUUsQ0FBRSxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUUsR0FBRyxPQUFPLEdBQUcsR0FBRyxDQUFFLENBQUU7WUFDeEQsSUFBSSxDQUFDLEdBQUcsQ0FBRSxDQUFDLENBQUMsR0FBRyxHQUFHLE9BQU8sQ0FBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUUsQ0FBQyxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUU7Z0JBQ3pELE9BQU8sQ0FBRSxJQUFJLENBQUMsR0FBRyxDQUFFLENBQUUsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFFLEdBQUcsT0FBTyxHQUFHLEdBQUcsQ0FBRSxDQUFFLENBQUM7UUFFMUQsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUUsSUFBSSxDQUFDLElBQUksQ0FBRSxDQUFDLENBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFFLENBQUMsR0FBRyxDQUFDLENBQUUsQ0FBRSxDQUFDO0lBQ3JGLENBQUM7SUFFTSxrQ0FBUyxHQUFoQixVQUFrQixLQUFhO1FBRTlCLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUUsS0FBSyxDQUFFLENBQUMsSUFBSSxDQUFDO1FBRXRELElBQUssT0FBTyxDQUFDLGNBQWMsQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFFLEVBQUc7WUFDOUMsT0FBTyxPQUFPLENBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBRSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDO1NBQzdEO1FBRUQsT0FBTyxpQkFBTSxTQUFTLFlBQUUsS0FBSyxDQUFFLENBQUM7SUFFakMsQ0FBQztJQXJJdUIsMEJBQVcsR0FBOEI7UUFDaEUsQ0FBQyxFQUFFLFNBQVM7UUFDWixFQUFFLEVBQUUsU0FBUztRQUNiLEVBQUUsRUFBRSxTQUFTO1FBQ2IsRUFBRSxFQUFFLFNBQVM7UUFDYixDQUFDLEVBQUUsaUJBQWlCO0tBQ3BCLENBQUM7SUFpSUgscUJBQUM7Q0F6SUQsQUF5SUMsQ0F6SW1DLGVBQU0sR0F5SXpDO0FBeklZLHdDQUFjOzs7OztBQ0QzQjtJQVdDLGdCQUFvQixRQUFnQixFQUFFLE1BQWMsRUFBRSxjQUFzQixFQUFFLFVBQXNCLEVBQUUsT0FBaUI7UUFUL0csZ0JBQVcsR0FBVyxTQUFTLENBQUM7UUFDOUIsV0FBTSxHQUFXLFNBQVMsQ0FBQztRQUkzQixZQUFPLEdBQVksU0FBUyxDQUFDO1FBQzdCLGFBQVEsR0FBWSxLQUFLLENBQUM7UUFDMUIsY0FBUyxHQUFZLEtBQUssQ0FBQztRQUdwQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQztRQUMxQixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUNyQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVNLHFCQUFJLEdBQVgsY0FBZSxDQUFDO0lBQUEsQ0FBQztJQUVWLDJCQUFVLEdBQWpCO1FBQ0MsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3RCLENBQUM7SUFFTSx3QkFBTyxHQUFkO1FBQUEsaUJBVUM7UUFUQSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUVyQixJQUFJLENBQUMsV0FBVzthQUNmLFdBQVcsQ0FBRSxTQUFTLENBQUU7YUFDeEIsUUFBUSxDQUFFLFVBQVUsQ0FBRSxDQUFDO1FBRXhCLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUVoQixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBRSxjQUFNLE9BQUEsS0FBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUUsS0FBSSxDQUFDLFFBQVEsQ0FBRSxFQUFoRCxDQUFnRCxDQUFFLENBQUM7SUFDdEYsQ0FBQztJQUVNLHVCQUFNLEdBQWI7UUFBQSxpQkFZQztRQVhBLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBRXRCLElBQUksQ0FBQyxXQUFXO2FBQ2YsV0FBVyxDQUFFLFVBQVUsQ0FBRTthQUN6QixRQUFRLENBQUUsU0FBUyxDQUFFLENBQUM7UUFFdkIsSUFBSyxDQUFFLElBQUksQ0FBQyxTQUFTLEVBQUc7WUFDdkIsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1NBQ2xCO1FBRUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUUsY0FBTSxPQUFBLEtBQUksQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFFLEtBQUksQ0FBQyxRQUFRLENBQUUsRUFBaEQsQ0FBZ0QsQ0FBRSxDQUFDO0lBQ3RGLENBQUM7SUFFTyx5QkFBUSxHQUFoQixVQUFrQixRQUF1QjtRQUF6QyxpQkFnQkM7UUFoQmlCLHlCQUFBLEVBQUEsY0FBdUI7UUFFeEMsSUFBSyxDQUFFLElBQUksQ0FBQyxTQUFTLEVBQUc7WUFFdkIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUU7aUJBQ3pCLElBQUksQ0FBRTtnQkFFTixLQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsQ0FBQztnQkFFaEMsS0FBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUU7b0JBQ3pCLGFBQWEsRUFBRSxDQUFDO29CQUNoQixnQkFBZ0IsRUFBRSxDQUFDO29CQUNuQixlQUFlLEVBQUUsS0FBSztpQkFDdEIsRUFBRSxRQUFRLENBQUUsQ0FBQztZQUNmLENBQUMsQ0FBRSxDQUFDO1NBQ0o7SUFDRixDQUFDO0lBRU8sMkJBQVUsR0FBbEI7UUFBQSxpQkFZQztRQVhBLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFO2FBQ3pCLElBQUksQ0FBRTtZQUNOLEtBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFFeEIsSUFBSSxLQUFLLEdBQUcsS0FBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUUsT0FBTyxDQUFFLENBQUM7WUFDN0MsS0FBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUUsT0FBTyxDQUFFLENBQUM7WUFDdkMsSUFBSSxjQUFjLEdBQUcsS0FBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUUsQ0FBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsZUFBZSxDQUFFLENBQUUsQ0FBQztZQUNsRyxLQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBRSxPQUFPLEVBQUUsS0FBSyxDQUFFLENBQUM7WUFFeEMsS0FBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUUsY0FBYyxDQUFFLENBQUM7UUFDNUMsQ0FBQyxDQUFFLENBQUM7SUFDTCxDQUFDO0lBRU0sMEJBQVMsR0FBaEIsVUFBa0IsS0FBYTtRQUM5QixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLG1CQUFtQixDQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBRSxtQkFBbUIsQ0FBRSxLQUFLLElBQUksQ0FBQztJQUMzRyxDQUFDO0lBRU0sc0JBQUssR0FBWjtRQUNDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN0QixDQUFDO0lBRVMsa0NBQWlCLEdBQTNCO1FBRUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUUseUNBQXlDLENBQUUsQ0FBQztRQUU3RCxJQUFJLENBQUMsV0FBVzthQUNmLE1BQU0sQ0FBRSxJQUFJLENBQUMsTUFBTSxDQUFFO2FBQ3JCLFFBQVEsQ0FBRSxTQUFTLENBQUUsQ0FBQztRQUV2QixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBRS9CLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNwQixDQUFDO0lBRU8seUJBQVEsR0FBaEI7UUFDQywwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUUsMENBQXNDLElBQUksQ0FBQyxPQUFPLENBQUUsT0FBTyxDQUFFLFdBQVEsQ0FBRSxDQUFDO0lBQzdGLENBQUM7SUFFUywrQkFBYyxHQUF4QjtRQUFBLGlCQXVCQztRQXJCQSxJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLFVBQVUsQ0FBRSxFQUFHO1lBRWhELElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsVUFBVSxDQUFFLENBQUM7WUFFMUMsSUFBSyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFFLFFBQVEsRUFBRSxRQUFRLENBQUUsSUFBSSxDQUFDLEVBQUc7Z0JBRWxFLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBRSxnREFBOEMsQ0FBRSxDQUFDO2dCQUV2RSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBRSxZQUFZLENBQUUsQ0FBQztnQkFFbkMsWUFBWSxDQUFDLEtBQUssQ0FBRTtvQkFFbkIsSUFBSyxLQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUUsRUFBRzt3QkFDNUMsS0FBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO3FCQUNmO3lCQUFNO3dCQUNOLEtBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztxQkFDZDtnQkFFRixDQUFDLENBQUUsQ0FBQzthQUNKO1NBQ0Q7SUFDRixDQUFDO0lBRVMsd0NBQXVCLEdBQWpDO1FBQUEsaUJBcUNDO1FBcENBLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLGFBQWEsQ0FBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFFLGFBQWEsQ0FBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDM0csSUFBSyxXQUFXLEtBQUssV0FBVyxJQUFJLFdBQVcsS0FBSyxhQUFhLEVBQUc7WUFFbkUsSUFBSSxpQkFBZSxHQUFHLENBQUMsQ0FBRSx5Q0FBeUMsQ0FBRSxDQUFDO1lBRXJFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFFLGlCQUFlLENBQUUsQ0FBQztZQUV0QyxpQkFBZSxDQUFDLEtBQUssQ0FBRTtnQkFDdEIsSUFBSyxpQkFBZSxDQUFDLFFBQVEsQ0FBRSxXQUFXLENBQUUsRUFBRztvQkFDOUMsS0FBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO29CQUNsQixLQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztvQkFFdkIsaUJBQWU7eUJBQ2QsV0FBVyxDQUFFLFdBQVcsQ0FBRTt5QkFDMUIsUUFBUSxDQUFFLGFBQWEsQ0FBRSxDQUFDO2lCQUMzQjtxQkFBTTtvQkFDTixLQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7b0JBQ2hCLEtBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO29CQUV0QixpQkFBZTt5QkFDZCxXQUFXLENBQUUsYUFBYSxDQUFFO3lCQUM1QixRQUFRLENBQUUsV0FBVyxDQUFFLENBQUM7aUJBQ3pCO1lBRUYsQ0FBQyxDQUFFLENBQUM7WUFFSixJQUFLLFdBQVcsS0FBSyxXQUFXLEVBQUc7Z0JBRWxDLElBQUksQ0FBQyxRQUFRLENBQUUsQ0FBQyxDQUFFLENBQUM7Z0JBQ25CLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO2dCQUN0QixpQkFBZSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQzthQUV0QztpQkFBTTtnQkFDTixpQkFBZSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQzthQUN4QztTQUNEO0lBQ0YsQ0FBQztJQUVGLGFBQUM7QUFBRCxDQWhMQSxBQWdMQyxJQUFBO0FBaExxQix3QkFBTTs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDSDVCLGlGQUFpRjtBQUNqRixtQ0FBa0M7QUFLbEM7SUFBa0MsZ0NBQU07SUFBeEM7UUFBQSxxRUF5UkM7UUF2UlEsZ0JBQVUsR0FBRyxDQUFDLENBQUM7UUFDZixjQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsY0FBUSxHQUFHLENBQUMsQ0FBQztRQUNiLGlCQUFXLEdBQUcsQ0FBQyxDQUFDO1FBRWhCLHNCQUFnQixHQUFXLENBQUMsQ0FBQztRQUM3QixzQkFBZ0IsR0FBVyxDQUFDLENBQUM7UUFDN0IsVUFBSSxHQUFHLEtBQUksQ0FBQyxVQUFVLENBQUM7O0lBZ1JoQyxDQUFDO0lBOVFPLDJCQUFJLEdBQVg7UUFFQyxJQUFJLE1BQU0sR0FBYSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFFcEMsSUFBQSxvQ0FBcUUsRUFBbkUsc0JBQVEsRUFBRSxzQkFBUSxFQUFFLHdCQUErQyxDQUFDO1FBRTFFLElBQUksYUFBYSxHQUEwQjtZQUMxQyxnQkFBZ0IsRUFBRSxLQUFLO1lBQ3ZCLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLElBQUksRUFBRSxJQUFJO1NBQ1YsQ0FBQztRQUVGLElBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsUUFBUSxDQUFFLEVBQUc7WUFDOUMsYUFBYSxHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FBRSxhQUFhLEVBQUUsTUFBTSxDQUFFLENBQUM7U0FFNUU7YUFBTTtZQUNOLGFBQWEsR0FBRyxJQUFJLENBQUMsc0NBQXNDLENBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFFLENBQUM7U0FDNUc7UUFFRCxRQUFRLElBQUksQ0FBQyxPQUFPLENBQUUsU0FBUyxDQUFFLEVBQUc7WUFFbkMsS0FBSyxLQUFLO2dCQUVULElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztnQkFDMUIsYUFBYSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUM7Z0JBQzlCLE1BQU07WUFFUCxLQUFLLEtBQUs7Z0JBRVQsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO2dCQUMxQixhQUFhLENBQUMsSUFBSSxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RDLGFBQWEsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDO2dCQUM5QixNQUFNO1lBRVAsS0FBSyxRQUFRO2dCQUVaLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztnQkFDN0IsUUFBUSxHQUFHLFFBQVEsQ0FBQztnQkFDcEIsYUFBYSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUM7Z0JBQzlCLE1BQU07WUFFUCxTQUFTLGtCQUFrQjtnQkFFMUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO2dCQUM1QixhQUFhLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQztTQUMvQjtRQUVELElBQUksQ0FBQyxtQkFBbUIsQ0FBRSxhQUFhLENBQUUsQ0FBQztRQUUxQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsUUFBUSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxRQUFRLENBQUM7UUFFakMsT0FBTyxJQUFJLENBQUM7SUFDYixDQUFDO0lBRU8sNkRBQXNDLEdBQTlDLFVBQWdELGFBQW9DLEVBQUUsUUFBZ0IsRUFBRSxRQUFnQixFQUFFLFNBQWlCO1FBQTNJLGlCQWFDO1FBWEEsYUFBYSxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUM7UUFDN0IsYUFBYSxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUM7UUFDN0IsYUFBYSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFFLFNBQVMsQ0FBRSxDQUFDO1FBQy9DLGFBQWEsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBRSxDQUFFLFFBQVEsR0FBRyxRQUFRLENBQUUsR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFFLENBQUUsQ0FBQztRQUVuRyxhQUFhLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQztRQUM5QixhQUFhLENBQUMsRUFBRSxHQUFHLFFBQVEsQ0FBQztRQUU1QixhQUFhLENBQUMsUUFBUSxHQUFHLFVBQUUsSUFBeUIsSUFBTSxPQUFBLEtBQUksQ0FBQyxlQUFlLENBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFFLEVBQTFDLENBQTBDLENBQUM7UUFFckcsT0FBTyxhQUFhLENBQUM7SUFDdEIsQ0FBQztJQUVPLG9EQUE2QixHQUFyQyxVQUF1QyxhQUFvQyxFQUFFLE1BQWdCO1FBQTdGLGlCQVVDO1FBUkEsYUFBYSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFFOUIsYUFBYSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUM7UUFDdkIsYUFBYSxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUVyQyxhQUFhLENBQUMsUUFBUSxHQUFHLFVBQUUsSUFBeUIsSUFBTSxPQUFBLEtBQUksQ0FBQyxlQUFlLENBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFFLEVBQXRELENBQXNELENBQUM7UUFFakgsT0FBTyxhQUFhLENBQUM7SUFDdEIsQ0FBQztJQUVPLHlDQUFrQixHQUExQixVQUE0QixNQUFnQjtRQUUzQyxJQUFJLFFBQVEsR0FBRyxNQUFNLENBQUUsQ0FBQyxDQUFFLENBQUM7UUFDM0IsSUFBSSxRQUFRLEdBQUcsTUFBTSxDQUFFLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFFLENBQUM7UUFDM0MsSUFBSSxTQUFTLEdBQVcsSUFBSSxDQUFDLFlBQVksQ0FBRSxRQUFRLEVBQUUsUUFBUSxDQUFFLENBQUM7UUFFaEUsSUFBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLFFBQVEsQ0FBRSxFQUFHO1lBQy9DLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBRSxDQUFDO1lBQ3pELFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBRSxDQUFDO1NBQ3pEO1FBRUQsT0FBTyxFQUFFLFFBQVEsVUFBQSxFQUFFLFFBQVEsVUFBQSxFQUFFLFNBQVMsV0FBQSxFQUFFLENBQUM7SUFDMUMsQ0FBQztJQUVPLGdDQUFTLEdBQWpCO1FBQ0MsSUFBSSxNQUFnQixDQUFDO1FBQ3JCLElBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsUUFBUSxDQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxNQUFNLEVBQUc7WUFDeEYsTUFBTSxHQUFJLElBQUksQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUE7U0FDbEM7YUFBTTtZQUNOLE1BQU0sR0FBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7U0FDakM7UUFFRCxJQUFLLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFHO1lBQzFCLE1BQU0sR0FBRyxDQUFFLENBQUMsRUFBRSxDQUFDLENBQUUsQ0FBQztTQUNsQjthQUFNLElBQUssTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUc7WUFDakMsTUFBTSxDQUFDLElBQUksQ0FBRSxNQUFNLENBQUUsQ0FBQyxDQUFFLENBQUUsQ0FBQztTQUMzQjtRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2YsQ0FBQztJQUVPLDBDQUFtQixHQUEzQixVQUE2QixhQUFvQztRQUVoRSxJQUFJLGdCQUFnQixHQUFRLEVBQUUsQ0FBQztRQUMvQixnQkFBZ0IsQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFFLEdBQUcsVUFBVSxDQUFDO1FBQzFELGdCQUFnQixDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsR0FBRyxVQUFVLENBQUM7UUFDL0MsZ0JBQWdCLENBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBRSxHQUFHLFlBQVksQ0FBQztRQUNuRCxnQkFBZ0IsQ0FBRSxJQUFJLENBQUMsV0FBVyxDQUFFLEdBQUcsYUFBYSxDQUFDO1FBRXJELElBQUksY0FBYyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBRTlDLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBRSxnQ0FBZ0MsQ0FBRSxDQUFDO1FBQ25ELElBQUksZUFBZSxHQUFHLENBQUMsQ0FBRSx5Q0FBc0MsZ0JBQWdCLENBQUUsSUFBSSxDQUFDLElBQUksQ0FBRSxVQUFNLENBQUUsQ0FBQyxNQUFNLENBQUUsTUFBTSxDQUFFLENBQUM7UUFDdEgsY0FBYyxDQUFDLE1BQU0sQ0FBRSxlQUFlLENBQUUsQ0FBQztRQUV6QyxJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLFNBQVMsQ0FBRSxFQUFHO1lBQy9DLElBQUksT0FBTyxHQUFHLDRDQUF3QyxJQUFJLENBQUMsT0FBTyxDQUFFLFNBQVMsQ0FBRSxXQUFRLENBQUM7WUFDeEYsY0FBYyxDQUFDLE1BQU0sQ0FBRSxPQUFPLENBQUUsQ0FBQztTQUNqQztRQUVELEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFFLHlCQUF5QixDQUFFLENBQUMsSUFBSSxDQUFFLGNBQU0sT0FBQSxNQUFNLENBQUMsY0FBYyxDQUFFLGFBQWEsQ0FBRSxFQUF0QyxDQUFzQyxDQUFFLENBQUM7SUFDbkcsQ0FBQztJQUVPLHdDQUFpQixHQUF6QixVQUEyQixRQUFnQixFQUFFLFNBQWlCO1FBQzdELElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUM7UUFFekMsSUFBSyxZQUFZLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBRSxNQUFNLENBQUUsWUFBWSxDQUFFLENBQUUsRUFBRztZQUNwRSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUUsUUFBUSxHQUFHLFNBQVMsQ0FBRSxHQUFHLFNBQVMsQ0FBQztTQUN0RDtRQUVELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBRSxZQUFZLEVBQUUsUUFBUSxDQUFFLENBQUM7SUFDM0MsQ0FBQztJQUVPLHdDQUFpQixHQUF6QixVQUEyQixRQUFnQixFQUFFLFNBQWlCO1FBQzdELElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUM7UUFFekMsSUFBSyxZQUFZLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBRSxNQUFNLENBQUUsWUFBWSxDQUFFLENBQUUsRUFBRztZQUNwRSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUUsUUFBUSxHQUFHLFNBQVMsQ0FBRSxHQUFHLFNBQVMsQ0FBQztTQUNyRDtRQUVELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBRSxZQUFZLEVBQUUsUUFBUSxDQUFFLENBQUM7SUFDM0MsQ0FBQztJQUVPLG1DQUFZLEdBQXBCLFVBQXNCLFFBQWdCLEVBQUUsUUFBZ0I7UUFDdkQsSUFBSyxRQUFRLEdBQUcsUUFBUSxHQUFHLENBQUMsRUFBRztZQUM5QixPQUFPLFNBQUEsRUFBRSxFQUFJLENBQUUsSUFBSSxDQUFDLEtBQUssQ0FBRSxJQUFJLENBQUMsR0FBRyxDQUFFLFFBQVEsR0FBRyxRQUFRLENBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFFLEdBQUcsQ0FBQyxDQUFFLENBQUEsQ0FBQztTQUNqRjthQUFNO1lBQ04sT0FBTyxDQUFDLENBQUM7U0FDVDtJQUNGLENBQUM7SUFFTyw4QkFBTyxHQUFmLFVBQWlCLFNBQWlCO1FBRWpDLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUUsTUFBTSxDQUFFLENBQUM7UUFFbEMsSUFBSyxJQUFJLEtBQUssU0FBUyxFQUFHO1lBRXpCLElBQUksR0FBRyxNQUFNLENBQUUsSUFBSSxDQUFFLENBQUM7WUFFdEIsSUFBSyxDQUFDLEtBQUssQ0FBRSxJQUFJLENBQUUsRUFBRztnQkFDckIsT0FBTyxJQUFJLENBQUM7YUFDWjtTQUNEO1FBRUQsT0FBTyxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFTyx5Q0FBa0IsR0FBMUI7UUFFQyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3JDLElBQUksR0FBRyxHQUFHLFFBQVEsQ0FBQztRQUNuQixJQUFJLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQztRQUVwQixLQUFNLElBQUksS0FBSyxJQUFJLElBQUksRUFBRztZQUV6QixJQUFLLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsRUFBRztnQkFDekQsSUFBSSxNQUFNLEdBQWEsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLElBQUksQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFFLENBQUMsTUFBTSxDQUFDO2dCQUNsRSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsT0FBUixJQUFJLEdBQU0sR0FBRyxTQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUNqQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsT0FBUixJQUFJLEdBQU0sR0FBRyxTQUFLLE1BQU0sRUFBRSxDQUFDO2FBQ2pDO1NBQ0Q7UUFFRCxPQUFPLENBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBRSxDQUFDO0lBQ3JCLENBQUM7SUFFTyxzQ0FBZSxHQUF2QjtRQUVDLElBQUksVUFBVSxHQUFhLEVBQUUsQ0FBQztRQUM5QixJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRXJDLEtBQU0sSUFBSSxLQUFLLElBQUksSUFBSSxFQUFHO1lBRXpCLElBQUksS0FBSyxHQUFHLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxJQUFJLENBQUM7WUFFL0IsSUFBSyxLQUFLLENBQUMsY0FBYyxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsRUFBRztnQkFFNUMsSUFBSSxNQUFNLEdBQUcsS0FBSyxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsQ0FBQyxNQUFNLENBQUM7Z0JBRTNDLEtBQU0sSUFBSSxPQUFPLElBQUksTUFBTSxFQUFHO29CQUU3QixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUUsTUFBTSxDQUFFLE9BQU8sQ0FBRSxDQUFFLENBQUM7b0JBRXhDLElBQUssVUFBVSxDQUFDLE9BQU8sQ0FBRSxLQUFLLENBQUUsS0FBSyxDQUFDLENBQUMsRUFBRzt3QkFDekMsVUFBVSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQztxQkFDekI7aUJBQ0Q7YUFDRDtTQUNEO1FBRUQsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFFLFVBQUUsQ0FBTSxFQUFFLENBQU0sSUFBTSxPQUFBLENBQUMsR0FBRyxDQUFDLEVBQUwsQ0FBSyxDQUFFLENBQUM7SUFDdkQsQ0FBQztJQUVNLHNDQUFlLEdBQXRCLFVBQXdCLElBQVksRUFBRSxFQUFVO1FBRS9DLFFBQVMsSUFBSSxDQUFDLElBQUksRUFBRztZQUVwQixLQUFLLElBQUksQ0FBQyxRQUFRO2dCQUVqQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDO2dCQUM3QixNQUFNO1lBRVAsS0FBSyxJQUFJLENBQUMsUUFBUTtnQkFFakIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztnQkFDN0IsTUFBTTtZQUVQLEtBQUssSUFBSSxDQUFDLFdBQVc7Z0JBRXBCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7Z0JBQzdCLE1BQU07WUFFUCxTQUFTLHdCQUF3QjtnQkFFaEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztnQkFDN0IsSUFBSSxDQUFDLGdCQUFnQixHQUFHLEVBQUUsQ0FBQztTQUM1QjtRQUVELElBQUksQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBRSxDQUFDO0lBQ2pELENBQUM7SUFFTSxnQ0FBUyxHQUFoQixVQUFrQixLQUFhO1FBQzlCLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUUsS0FBSyxDQUFFLENBQUMsSUFBSSxDQUFDO1FBRXRELElBQUssT0FBTyxDQUFDLGNBQWMsQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFFLElBQUksT0FBTyxDQUFFLElBQUksQ0FBQyxRQUFRLENBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRztZQUU1RixLQUFtQixVQUErQixFQUEvQixLQUFBLE9BQU8sQ0FBRSxJQUFJLENBQUMsUUFBUSxDQUFFLENBQUMsTUFBTSxFQUEvQixjQUErQixFQUEvQixJQUErQixFQUFHO2dCQUEvQyxJQUFJLEtBQUssU0FBQTtnQkFDZCxJQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsZ0JBQWdCLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRztvQkFDdkUsT0FBTyxJQUFJLENBQUM7aUJBQ1o7YUFDRDtZQUVELE9BQU8sS0FBSyxDQUFDO1NBQ2I7UUFFRCxPQUFPLGlCQUFNLFNBQVMsWUFBRSxLQUFLLENBQUUsQ0FBQztJQUNqQyxDQUFDO0lBRUYsbUJBQUM7QUFBRCxDQXpSQSxBQXlSQyxDQXpSaUMsZUFBTSxHQXlSdkM7QUF6Ulksb0NBQVk7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQ056QixtQ0FBa0M7QUFLbEM7SUFBaUMsK0JBQU07SUFBdkM7UUFBQSxxRUF1T0M7UUFyT1EsWUFBTSxHQUFRLEVBQUUsQ0FBQztRQUNqQixtQkFBYSxHQUFhLEVBQUUsQ0FBQztRQUU3QixZQUFNLEdBQUcsSUFBSSxDQUFDOztJQWtPdkIsQ0FBQztJQWhPTywwQkFBSSxHQUFYO1FBQ0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFTSwyQkFBSyxHQUFaLFVBQWMsS0FBYztRQUMzQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsVUFBVSxDQUFDLGVBQWUsQ0FBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUUsQ0FBQztJQUNqRCxDQUFDO0lBRU8scUNBQWUsR0FBdkI7UUFFQyw0Q0FBNEM7UUFDNUMsSUFBSSxjQUFjLEdBQVEsRUFBRSxDQUFDO1FBQzdCLGlEQUFpRDtRQUNqRCxJQUFJLGtCQUFrQixHQUFRLEVBQUUsQ0FBQztRQUVqQyxJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLFFBQVEsQ0FBRSxFQUFHO1lBRTlDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsQ0FBQyxHQUFHLENBQ2xDLFVBQUUsSUFBWTtnQkFDYixPQUFPO29CQUNOLGFBQWEsRUFBRSxJQUFJO29CQUNuQixjQUFjLEVBQUUsSUFBSTtpQkFDcEIsQ0FBQztZQUNILENBQUMsQ0FDRCxDQUFDO1NBRUY7YUFBTTtZQUNOLDBEQUEwRDtZQUMxRCxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3JDLElBQUksYUFBYSxHQUFVLEVBQUUsQ0FBQztZQUM5QixLQUFNLElBQUksRUFBRSxJQUFJLElBQUksRUFBRztnQkFFdEIsSUFBSSxjQUFjLEdBQVEsSUFBSSxDQUFFLEVBQUUsQ0FBRSxDQUFFLFdBQVcsQ0FBRSxDQUFFLElBQUksQ0FBQyxjQUFjLENBQUUsQ0FBRSxRQUFRLENBQUUsQ0FBQztnQkFDdkYsSUFBSSx1QkFBdUIsR0FBRyxJQUFJLENBQUUsRUFBRSxDQUFFLENBQUUsV0FBVyxDQUFFLENBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBRSxDQUFFLGtCQUFrQixDQUFFLENBQUM7Z0JBQ3JHLElBQUksa0JBQWtCLEdBQVEsSUFBSSxDQUFFLEVBQUUsQ0FBRSxDQUFFLFdBQVcsQ0FBRSxDQUFFLElBQUksQ0FBQyxjQUFjLENBQUUsQ0FBRSxhQUFhLENBQUUsQ0FBQztnQkFFaEcsS0FBTSxJQUFJLENBQUMsSUFBSSxjQUFjLEVBQUc7b0JBQy9CLElBQUksc0JBQXNCLEdBQUcsdUJBQXVCLENBQUUsQ0FBQyxDQUFFLENBQUM7b0JBRTFELElBQUssc0JBQXNCLENBQUMsT0FBTyxDQUFFLElBQUksQ0FBRSxHQUFHLENBQUMsQ0FBQyxFQUFHO3dCQUNsRCxzQkFBc0IsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUUsc0JBQXNCLENBQUUsQ0FBRSxDQUFDLENBQUUsQ0FBQztxQkFDL0U7b0JBRUQsY0FBYyxDQUFFLGNBQWMsQ0FBRSxDQUFDLENBQUUsQ0FBRSxHQUFHLHNCQUFzQixDQUFDO29CQUMvRCxrQkFBa0IsQ0FBRSxjQUFjLENBQUUsQ0FBQyxDQUFFLENBQUUsR0FBRyxrQkFBa0IsQ0FBRSxDQUFDLENBQUUsQ0FBQztpQkFDcEU7YUFFRDtZQUVELEtBQU0sSUFBSSxhQUFhLElBQUksa0JBQWtCLEVBQUc7Z0JBQy9DLGFBQWEsQ0FBQyxJQUFJLENBQUU7b0JBQ25CLGFBQWEsRUFBRSxhQUFhO29CQUM1QixTQUFTLEVBQUUsa0JBQWtCLENBQUUsYUFBYSxDQUFFO29CQUM5QyxjQUFjLEVBQUUsY0FBYyxDQUFFLGFBQWEsQ0FBRTtpQkFDL0MsQ0FBRSxDQUFDO2FBQ0o7WUFFRCxhQUFhLENBQUMsSUFBSSxDQUNqQixVQUFFLENBQU0sRUFBRSxDQUFNO2dCQUNmLE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBRSxDQUFDO1lBQ2pELENBQUMsQ0FBRSxDQUFDO1lBQ0wsT0FBTyxhQUFhLENBQUM7U0FFckI7SUFFRixDQUFDO0lBRU8sa0NBQVksR0FBcEI7UUFFQyxJQUFJLGNBQWMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUU5QyxjQUFjLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFFLGNBQWMsQ0FBRSxDQUFDO1FBRTlELElBQUksYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLGdCQUFnQixDQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUUsZ0JBQWdCLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTNHLElBQUssSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsYUFBYSxFQUFHO1lBQ3pDLGNBQWMsQ0FBQyxNQUFNLENBQUUsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUUsQ0FBQztTQUNwRDthQUFNO1lBQ04sY0FBYyxDQUFDLE1BQU0sQ0FBRSxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBRSxDQUFDO1NBQ3JEO0lBRUYsQ0FBQztJQUVPLDBDQUFvQixHQUE1QjtRQUFBLGlCQWlCQztRQWZBLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBRSw4REFBOEQsQ0FBRSxDQUFDO1FBRXJGLHlDQUF5QztRQUN6QyxLQUFtQixVQUFXLEVBQVgsS0FBQSxJQUFJLENBQUMsTUFBTSxFQUFYLGNBQVcsRUFBWCxJQUFXLEVBQUc7WUFBM0IsSUFBSSxLQUFLLFNBQUE7WUFDZCxVQUFVLENBQUMsTUFBTSxDQUFFLGtGQUEyRSxLQUFLLENBQUMsYUFBYSx3REFBK0MsS0FBSyxDQUFDLGNBQWMsSUFBSSxLQUFLLENBQUMsYUFBYSwwQkFBc0IsQ0FBRSxDQUFDO1NBQ3BPO1FBRUQsdUJBQXVCO1FBQ3ZCLFVBQVU7YUFDVCxFQUFFLENBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFFLFdBQThCO1lBQzNELElBQUksZUFBZSxHQUFzQixXQUFXLENBQUMsYUFBYSxDQUFDO1lBQ25FLEtBQUksQ0FBQyxlQUFlLENBQUUsZUFBZSxDQUFDLEtBQUssRUFBRSxlQUFlLENBQUMsT0FBTyxDQUFFLENBQUM7UUFDeEUsQ0FBQyxDQUFFLENBQUM7UUFFSixPQUFPLFVBQVUsQ0FBQztJQUNuQixDQUFDO0lBRU8seUNBQW1CLEdBQTNCO1FBQUEsaUJBaUNDO1FBL0JBLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBRSw2REFBNkQsQ0FBRSxDQUFDO1FBRWhGLElBQUksSUFBSSxHQUFpQixFQUFFLENBQUM7UUFFNUIsbUVBQW1FO1FBQ25FLEtBQW1CLFVBQVcsRUFBWCxLQUFBLElBQUksQ0FBQyxNQUFNLEVBQVgsY0FBVyxFQUFYLElBQVcsRUFBRztZQUEzQixJQUFJLEtBQUssU0FBQTtZQUNkLGlEQUFpRDtZQUNqRCxJQUFJLEtBQUssR0FBRyxLQUFLLENBQUMsY0FBYyxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUM7WUFDeEQsSUFBSSxDQUFDLElBQUksQ0FBRSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBRSxDQUFDO1NBRXREO1FBRUQsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUUsc0NBQXNDLENBQUUsQ0FBQyxJQUFJLENBQUU7WUFFL0QsTUFBTSxDQUFDLE9BQU8sQ0FBRTtnQkFDZixRQUFRLEVBQUUsSUFBSTtnQkFDZCxXQUFXLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBRSx1Q0FBdUMsQ0FBRSxDQUFDLElBQUksRUFBRTtnQkFDekUsSUFBSSxFQUFFLElBQUk7YUFDVixDQUFFLENBQUM7WUFFSixNQUFNLENBQUMsRUFBRSxDQUFFLGdCQUFnQixFQUFFLFVBQUUsQ0FBTTtnQkFDcEMsS0FBSSxDQUFDLGVBQWUsQ0FBRSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFFLENBQUM7WUFDaEQsQ0FBQyxDQUFFLENBQUM7WUFFSixNQUFNLENBQUMsRUFBRSxDQUFFLGtCQUFrQixFQUFFLFVBQUUsQ0FBTTtnQkFDdEMsS0FBSSxDQUFDLGVBQWUsQ0FBRSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFFLENBQUM7WUFDakQsQ0FBQyxDQUFFLENBQUM7UUFFTCxDQUFDLENBQUUsQ0FBQztRQUVKLE9BQU8sTUFBTSxDQUFDO0lBQ2YsQ0FBQztJQUVPLDJDQUFxQixHQUE3QixVQUErQixjQUFzQjtRQUNwRCxrQkFBa0I7UUFDbEIsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsVUFBVSxDQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUUsVUFBVSxDQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUVsRyxJQUFLLFFBQVEsS0FBSyxTQUFTLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBRSxRQUFRLEVBQUUsUUFBUSxDQUFFLElBQUksQ0FBQyxFQUFHO1lBRXJFLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBRSx1Q0FBdUMsQ0FBRSxDQUFDO1lBRWxFLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBRSxvQ0FBb0MsQ0FBRSxDQUFDO1lBRTdELElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUUsSUFBSSxFQUFFLElBQUksQ0FBRSxDQUFDO1lBQ25ELElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUUsS0FBSyxDQUFFLENBQUM7WUFFL0MsWUFBWTtpQkFDWCxNQUFNLENBQUUsU0FBUyxDQUFFO2lCQUNuQixNQUFNLENBQUUsVUFBVSxDQUFFO2lCQUNwQixRQUFRLENBQUUsY0FBYyxDQUFFLENBQUM7WUFFNUIsWUFBWTtpQkFDWCxJQUFJLENBQUUsT0FBTyxDQUFFO2lCQUNmLEVBQUUsQ0FBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxFQUFFLFVBQUUsV0FBOEI7Z0JBQzdFLE9BQUEsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFFLE9BQU8sQ0FBRSxLQUFLLElBQUksQ0FBRTtZQUFwRixDQUFvRixDQUNwRixDQUFDO1lBR0YsY0FBYyxDQUFDLE1BQU0sQ0FBRSxjQUFjLENBQUUsQ0FBQztTQUN4QztRQUVELE9BQU8sY0FBYyxDQUFDO0lBQ3ZCLENBQUM7SUFFTyxxQ0FBZSxHQUF2QixVQUF5QixJQUFZLEVBQUUsU0FBMEI7UUFBMUIsMEJBQUEsRUFBQSxpQkFBMEI7UUFFaEUsSUFBSSxXQUFXLEdBQUcsU0FBUyxDQUFBLENBQUMsQ0FBQSxTQUFTLENBQUEsQ0FBQyxDQUFBLEVBQUUsQ0FBQztRQUN6QyxJQUFJLFNBQVMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFFLDRCQUE0QixHQUFHLElBQUksQ0FBRSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRXpFLElBQUksV0FBVyxHQUNkLGlDQUE4QixJQUFJLFNBQUksSUFBSSxDQUFDLGNBQWMsUUFBSTthQUM3RCxpREFBNEMsSUFBSSxDQUFDLGNBQWMsbUNBQTRCLElBQUksK0JBQXdCLElBQUksU0FBSSxJQUFJLENBQUMsY0FBYyxtQkFBWSxJQUFJLFdBQUssV0FBVyxNQUFHLENBQUE7YUFDbEwsU0FBUyxhQUFVLENBQUEsQ0FBQztRQUV4QixPQUFPLENBQUMsQ0FBRSxXQUFXLENBQUUsQ0FBQztJQUN6QixDQUFDO0lBRU0sK0JBQVMsR0FBaEIsVUFBa0IsS0FBYTtRQUU5QixJQUFLLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRztZQUN0QyxPQUFPLElBQUksQ0FBQztTQUNaO1FBRUQsSUFBSSxNQUFNLEdBQWEsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBRSxLQUFLLENBQUUsQ0FBQyxTQUFTLENBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBRSxDQUFDLE1BQU0sQ0FBQztRQUVsRyxJQUFLLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFHO1lBQzFCLE9BQU8saUJBQU0sU0FBUyxZQUFFLEtBQUssQ0FBRSxDQUFDO1NBQ2hDO1FBR0QsSUFBSyxJQUFJLENBQUMsTUFBTSxFQUFHO1lBQ2xCLEtBQTJCLFVBQWtCLEVBQWxCLEtBQUEsSUFBSSxDQUFDLGFBQWEsRUFBbEIsY0FBa0IsRUFBbEIsSUFBa0IsRUFBRztnQkFBMUMsSUFBSSxhQUFhLFNBQUE7Z0JBQ3RCLElBQUssTUFBTSxDQUFDLE9BQU8sQ0FBRSxhQUFhLENBQUUsSUFBSSxDQUFDLEVBQUc7b0JBQzNDLE9BQU8sSUFBSSxDQUFDO2lCQUNaO2FBQ0Q7WUFDRCxPQUFPLEtBQUssQ0FBQztTQUNiO2FBQU07WUFDTixLQUEyQixVQUFrQixFQUFsQixLQUFBLElBQUksQ0FBQyxhQUFhLEVBQWxCLGNBQWtCLEVBQWxCLElBQWtCLEVBQUc7Z0JBQTFDLElBQUksYUFBYSxTQUFBO2dCQUN0QixJQUFLLE1BQU0sQ0FBQyxPQUFPLENBQUUsYUFBYSxDQUFFLEdBQUcsQ0FBQyxFQUFHO29CQUMxQyxPQUFPLEtBQUssQ0FBQztpQkFDYjthQUNEO1lBQ0QsT0FBTyxJQUFJLENBQUM7U0FDWjtJQUNGLENBQUM7SUFFTSxxQ0FBZSxHQUF0QixVQUF3QixLQUFhLEVBQUUsU0FBa0I7UUFDeEQsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUM7UUFFaEQsSUFBSyxTQUFTLElBQUksS0FBSyxLQUFLLENBQUMsQ0FBQyxFQUFHO1lBQ2hDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDO1NBQ2pDO2FBQU0sSUFBSyxDQUFDLFNBQVMsSUFBSSxLQUFLLElBQUksQ0FBQyxFQUFHO1lBQ3RDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFFLEtBQUssRUFBRSxDQUFDLENBQUUsQ0FBQztTQUN0QztRQUVELElBQUksQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBRSxDQUFDO0lBQ2pELENBQUM7SUFDRixrQkFBQztBQUFELENBdk9BLEFBdU9DLENBdk9nQyxlQUFNLEdBdU90QztBQXZPWSxrQ0FBVzs7Ozs7QUNKeEIsMkNBQTBDO0FBQzFDLCtDQUE4QztBQUM5QyxvQ0FBbUM7QUFDbkMsNENBQTJDO0FBQzNDLDhDQUE2QztBQUM3QywwQ0FBeUM7QUFDekMsb0RBQW1EO0FBRW5ELG9EQUFtRDtBQUNuRCwwREFBeUQ7QUFDekQsc0RBQXFEO0FBRXJEOzs7O0dBSUc7QUFDSDtJQWtCQzs7OztPQUlHO0lBQ0gsa0JBQW9CLE1BQWMsRUFBRSxNQUFXO1FBbEJ2QyxjQUFTLEdBQXdHO1lBQ3hILEtBQUssRUFBRSxxQkFBUztZQUNoQixJQUFJLEVBQUUsbUJBQVE7WUFDZCxHQUFHLEVBQUUsaUJBQU87WUFDWixRQUFRLEVBQUUsMkJBQVk7U0FDdEIsQ0FBQztRQUVNLGdCQUFXLEdBQXNJO1lBQ3hKLEtBQUssRUFBRSx5QkFBVztZQUNsQixRQUFRLEVBQUUsK0JBQWM7WUFDeEIsTUFBTSxFQUFFLDJCQUFZO1NBQ3BCLENBQUM7UUFRRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN0QixDQUFDO0lBRU0sc0JBQUcsR0FBVjtRQUVDLElBQUksVUFBVSxHQUFHLElBQUksdUJBQVUsQ0FBRSxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFFLENBQUM7UUFFNUYsSUFBSSxDQUFDLGFBQWEsQ0FBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUUsc0JBQXNCLENBQUUsQ0FBRSxDQUFDO1FBQ2pGLElBQUksQ0FBQyxrQkFBa0IsQ0FBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUUsd0NBQXdDLENBQUUsQ0FBRSxDQUFDO1FBQ3BHLElBQUksQ0FBQyxXQUFXLENBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFFLDhCQUE4QixDQUFFLENBQUUsQ0FBQztRQUVuRixXQUFXO1FBQ1gsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO0lBRW5CLENBQUM7SUFFTyxnQ0FBYSxHQUFyQixVQUF1QixVQUFzQixFQUFFLGdCQUF3QjtRQUV0RSxLQUFNLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFHO1lBRTdDLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFFLElBQUksQ0FBRSxDQUFDO1lBRTNDLElBQUssRUFBRSxDQUFDLGNBQWMsQ0FBRSxTQUFTLENBQUUsRUFBRztnQkFFckMsS0FBTSxJQUFJLFFBQVEsSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFHO29CQUVsQyxJQUFLLEVBQUUsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLFFBQVEsQ0FBRTt3QkFDekMsRUFBRSxDQUFDLE9BQU8sQ0FBRSxRQUFRLENBQUUsQ0FBQyxjQUFjLENBQUUsTUFBTSxDQUFFO3dCQUMvQyxJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBRSxFQUFFLENBQUMsT0FBTyxDQUFFLFFBQVEsQ0FBRSxDQUFDLElBQUksQ0FBRSxFQUFHO3dCQUVqRSx5Q0FBeUM7d0JBQ3pDLDRDQUE0Qzt3QkFDNUMsSUFBSSxNQUFNLEdBQVcsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUMsSUFBSSxDQUFFLENBQUUsUUFBUSxFQUFFLGdCQUFnQixDQUFDLFFBQVEsQ0FBRSxHQUFHLEdBQUcsUUFBUSxDQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFFLFFBQVEsQ0FBRSxDQUFFLENBQUM7d0JBRTVLLFVBQVUsQ0FBQyxZQUFZLENBQUUsTUFBTSxDQUFFLENBQUM7cUJBRWxDO2lCQUNEO2FBQ0Q7U0FFRDtJQUNGLENBQUM7SUFFTyxxQ0FBa0IsR0FBMUIsVUFBNEIsVUFBc0IsRUFBRSxxQkFBNkI7UUFDaEYsSUFBSSxZQUFZLEdBQUcsSUFBSSwyQkFBWSxDQUFFLHFCQUFxQixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUUsRUFBRSxVQUFVLENBQUUsQ0FBQztRQUMzRyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUVPLDhCQUFXLEdBQW5CLFVBQXFCLFVBQXNCLEVBQUUsY0FBc0I7UUFFbEUsZUFBZTtRQUNmLEtBQU0sSUFBSSxNQUFNLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUc7WUFFdkMsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUUsTUFBTSxDQUFFLENBQUUsTUFBTSxDQUFFLENBQUM7WUFDckQsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBRSxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBRSxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsV0FBSSxDQUFDO1lBRXJHLElBQUksSUFBSSxHQUFTLElBQUksZ0JBQWdCLENBQUUsTUFBTSxFQUFFLGNBQWMsQ0FBQyxRQUFRLENBQUUsR0FBRyxHQUFHLE1BQU0sQ0FBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBRSxNQUFNLENBQUUsQ0FBRSxDQUFDO1lBRWxJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUVaLFVBQVUsQ0FBQyxVQUFVLENBQUUsTUFBTSxFQUFFLElBQUksQ0FBRSxDQUFDO1NBRXRDO0lBQ0YsQ0FBQztJQUNGLGVBQUM7QUFBRCxDQXpGQSxBQXlGQyxJQUFBO0FBekZZLDRCQUFROzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUNsQnJCLCtCQUE4QjtBQUc5QjtJQUFrQyxnQ0FBSTtJQUF0Qzs7SUFzSEEsQ0FBQztJQXBIUSw4QkFBTyxHQUFmO1FBQ0MsT0FBTztZQUNOLFVBQVUsRUFBRSxDQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsU0FBUyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxVQUFVLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLE9BQU8sQ0FBRTtnQkFDekUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxPQUFPLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLFVBQVUsQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsTUFBTSxDQUFFO2dCQUN6RCxFQUFFLENBQUMsR0FBRyxDQUFFLE1BQU0sQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsUUFBUSxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxXQUFXLENBQUU7Z0JBQzNELEVBQUUsQ0FBQyxHQUFHLENBQUUsU0FBUyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxVQUFVLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLFVBQVUsQ0FBRTthQUMvRDtZQUNELGVBQWUsRUFBRSxDQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRTtnQkFDbkUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFO2dCQUNqRCxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUU7Z0JBQ2pELEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRTthQUNqRDtZQUNELFFBQVEsRUFBRSxDQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsUUFBUSxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxRQUFRLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLFNBQVMsQ0FBRTtnQkFDdEUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxXQUFXLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLFVBQVUsQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsUUFBUSxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxVQUFVLENBQUU7YUFDckY7WUFDRCxhQUFhLEVBQUUsQ0FBRSxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUU7Z0JBQ2pFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxLQUFLLENBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLEtBQUssQ0FBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsS0FBSyxDQUFFO2FBQ2xFO1lBQ0QsVUFBVSxFQUFFO2dCQUNYLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLGtDQUFrQyxDQUFFO2dCQUNuRCxLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSxrQ0FBa0MsQ0FBRTtnQkFDbkQsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsaUNBQWlDLENBQUU7Z0JBQ2pELEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLGdDQUFnQyxDQUFFO2FBQy9DO1lBRUQsVUFBVSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsbUNBQW1DLENBQUU7WUFDekQsVUFBVSxFQUFFO2dCQUNYLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLGtDQUFrQyxDQUFFO2dCQUNoRCxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSx5Q0FBeUMsQ0FBRTthQUMzRDtZQUVELFVBQVUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLGtDQUFrQyxDQUFFO1lBQ3hELFdBQVcsRUFBRTtnQkFDWixLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSx5Q0FBeUMsQ0FBRTtnQkFDMUQsSUFBSSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsd0NBQXdDLENBQUU7Z0JBQ3hELEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLHVDQUF1QyxDQUFFO2FBQ3REO1lBRUQsWUFBWSxFQUFFO2dCQUNiLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFFLDBDQUEwQyxDQUFFO2dCQUMzRCxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBRSx5Q0FBeUMsQ0FBRTtnQkFDekQsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUUsd0NBQXdDLENBQUU7YUFDdkQ7U0FDRCxDQUFDO0lBQ0gsQ0FBQztJQUVNLDJCQUFJLEdBQVg7UUFFQyxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFM0IsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFFO1lBRXpCLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVE7WUFDL0IsS0FBSyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSztZQUN6QixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7WUFDNUIsZUFBZSxFQUFFLEtBQUssQ0FBQyxlQUFlO1lBQ3RDLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtZQUN4QixhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7WUFDbEMsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO1lBQzVCLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtZQUM1QixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7WUFDNUIsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO1lBQzlCLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtTQUNoQyxDQUFFLENBQUM7SUFDTCxDQUFDO0lBRU8sK0JBQVEsR0FBaEIsVUFBa0IsS0FBVSxFQUFFLE9BQVk7UUFFekMsSUFBSSxTQUFTLEdBQVE7WUFDcEIsRUFBRSxFQUFFLEtBQUs7WUFDVCxLQUFLLEVBQUUsT0FBTyxDQUFFLE9BQU8sQ0FBRTtZQUN6QixLQUFLLEVBQUUsT0FBTyxDQUFFLE9BQU8sQ0FBRTtZQUN6QixTQUFTLEVBQUUsS0FBSztTQUNoQixDQUFDO1FBRUYsSUFBSyxPQUFPLENBQUMsY0FBYyxDQUFFLEtBQUssQ0FBRSxFQUFHO1lBQ3RDLFNBQVMsQ0FBRSxLQUFLLENBQUUsR0FBRyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUM7U0FDdEM7UUFFRCxJQUFLLE9BQU8sQ0FBQyxjQUFjLENBQUUsS0FBSyxDQUFFLEVBQUc7WUFDdEMsU0FBUyxDQUFFLEtBQUssQ0FBRSxHQUFHLE9BQU8sQ0FBRSxLQUFLLENBQUUsQ0FBQztTQUN0QztRQUVELE9BQU8sU0FBUyxDQUFDO0lBQ2xCLENBQUM7SUFFTSwrQkFBUSxHQUFmLFVBQWlCLE1BQWdCO1FBQWpDLGlCQWNDO1FBWkEsSUFBSSxNQUFNLEdBQVUsRUFBRSxDQUFDO1FBRXZCLE1BQU0sQ0FBQyxPQUFPLENBQUUsVUFBRSxLQUFhO1lBRTlCLElBQUksT0FBTyxHQUFHLEtBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUUsS0FBSyxDQUFFLENBQUMsSUFBSSxDQUFFLEtBQUksQ0FBQyxFQUFFLENBQUUsQ0FBQztZQUVqRSxJQUFLLE9BQU8sQ0FBQyxjQUFjLENBQUUsT0FBTyxDQUFFLEVBQUc7Z0JBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUUsS0FBSSxDQUFDLFFBQVEsQ0FBRSxLQUFLLEVBQUUsT0FBTyxDQUFFLENBQUUsQ0FBQzthQUMvQztRQUNGLENBQUMsQ0FBRSxDQUFDO1FBRUosSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUUsZ0JBQWdCLEVBQUUsTUFBTSxDQUFFLENBQUM7SUFDdEQsQ0FBQztJQUVNLCtCQUFRLEdBQWYsVUFBaUIsTUFBZ0I7UUFDaEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUUsY0FBYyxFQUFFLFVBQUUsQ0FBTSxJQUFNLE9BQUEsQ0FBRSxNQUFNLENBQUMsT0FBTyxDQUFFLENBQUMsQ0FBQyxHQUFHLENBQUUsSUFBSSxDQUFDLENBQUUsRUFBaEMsQ0FBZ0MsQ0FBRSxDQUFDO0lBQzVGLENBQUM7SUFFTSwyQkFBSSxHQUFYO1FBQ0MsaUJBQU0sSUFBSSxXQUFFLENBQUM7UUFDYixJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBRSxRQUFRLENBQUUsQ0FBQztJQUN0QyxDQUFDO0lBRU0sMkJBQUksR0FBWDtRQUNDLE9BQU8saUJBQU0sSUFBSSxXQUFFLENBQUM7SUFDckIsQ0FBQztJQUVGLG1CQUFDO0FBQUQsQ0F0SEEsQUFzSEMsQ0F0SGlDLFdBQUksR0FzSHJDO0FBdEhZLG9DQUFZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUNIekIsK0JBQThCO0FBRTlCO0lBQThCLDRCQUFJO0lBQWxDOztJQU9BLENBQUM7SUFMVSxtQ0FBZ0IsR0FBMUI7UUFDQyxPQUFPLHFCQUFxQixDQUFDO0lBQzlCLENBQUM7SUFHRixlQUFDO0FBQUQsQ0FQQSxBQU9DLENBUDZCLFdBQUksR0FPakM7QUFQWSw0QkFBUTs7OztBQ0ZyQixpQ0FBaUM7Ozs7Ozs7Ozs7Ozs7OztBQUVqQywrQkFBOEI7QUFLOUI7SUFBNkIsMkJBQUk7SUFBakM7UUFBQSxxRUF1UEM7UUFyUFEsU0FBRyxHQUFVLFNBQVMsQ0FBQztRQUN2QixVQUFJLEdBQThCLFNBQVMsQ0FBQztRQUM1QyxhQUFPLEdBQWtDLFNBQVMsQ0FBQztRQUNuRCx3QkFBa0IsR0FBeUIsU0FBUyxDQUFDO1FBQ3JELFlBQU0sR0FBbUIsU0FBUyxDQUFDO1FBQ25DLGlCQUFXLEdBQVksS0FBSyxDQUFDO1FBRTdCLFVBQUksR0FBVyxDQUFDLENBQUMsQ0FBQztRQUNsQixhQUFPLEdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDckIsYUFBTyxHQUFXLENBQUMsQ0FBQyxDQUFDO1FBRXJCLG9CQUFjLEdBQWlCLFNBQVMsQ0FBQzs7SUEwT2xELENBQUM7SUF4T08sc0JBQUksR0FBWDtRQUFBLGlCQWdEQztRQTlDQSxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3JDLElBQUksT0FBTyxHQUFvQyxFQUFFLENBQUM7UUFFbEQsSUFBSyxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBRSxRQUFRLENBQUUsRUFBRztZQUM5QyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBRSxDQUFDO1NBQzFDO1FBRUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBRSxtQ0FBbUMsQ0FBRTthQUMzRSxJQUFJLENBQUU7WUFFTixJQUFJLE1BQU0sR0FBbUIsU0FBUyxDQUFDO1lBQ3ZDLElBQUksdUJBQXVCLEdBQUcsS0FBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7WUFFNUQsSUFBSSxjQUFjLEdBQVk7Z0JBQzdCLG9CQUFvQixFQUFFLElBQUk7Z0JBQzFCLHVCQUF1QixFQUFFLHVCQUF1QjtnQkFDaEQsaUJBQWlCLEVBQUUsdUJBQXVCLEtBQUssSUFBSTthQUNuRCxDQUFDO1lBRUYsY0FBYyxHQUFHLEtBQUksQ0FBQyxVQUFVLENBQUUsQ0FBRSxrQkFBa0IsRUFBRSxxQkFBcUIsQ0FBRSxFQUFFLGNBQWMsQ0FBRSxDQUFDO1lBRWxHLElBQUksa0JBQWtCLEdBQXlCLENBQUMsQ0FBQyxrQkFBa0IsQ0FBRSxjQUFjLENBQUUsQ0FBQztZQUV0RixLQUFNLElBQUksS0FBSyxJQUFJLElBQUksRUFBRztnQkFFekIsSUFBSyxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUUsTUFBTSxDQUFFLENBQUMsY0FBYyxDQUFFLEtBQUksQ0FBQyxFQUFFLENBQUUsRUFBRztvQkFDeEQsSUFBSSxTQUFTLEdBQXNCLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBRSxNQUFNLENBQUUsQ0FBRSxLQUFJLENBQUMsRUFBRSxDQUFFLENBQUUsV0FBVyxDQUFFLENBQUM7b0JBQ3JGLE9BQU8sQ0FBRSxLQUFLLENBQUUsR0FBRyxFQUFFLENBQUM7b0JBRXRCLEtBQWlCLFVBQVMsRUFBVCx1QkFBUyxFQUFULHVCQUFTLEVBQVQsSUFBUyxFQUFHO3dCQUF2QixJQUFJLEdBQUcsa0JBQUE7d0JBRVosTUFBTSxHQUFHLENBQUUsTUFBTSxLQUFLLFNBQVMsQ0FBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxZQUFZLENBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFFLEdBQUcsQ0FBRSxDQUFDO3dCQUUxRixJQUFJLE1BQU0sR0FBRyxLQUFJLENBQUMsU0FBUyxDQUFFLEdBQUcsRUFBRSxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUUsQ0FBQzt3QkFDbEQsT0FBTyxDQUFFLEtBQUssQ0FBRSxDQUFDLElBQUksQ0FBRSxNQUFNLENBQUUsQ0FBQzt3QkFDaEMsa0JBQWtCLENBQUMsUUFBUSxDQUFFLE1BQU0sQ0FBRSxDQUFDO3FCQUN0QztpQkFDRDthQUNEO1lBRUQsS0FBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDO1lBQzdDLEtBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1lBQ3ZCLEtBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBRSxNQUFNLEtBQUssU0FBUyxDQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLFlBQVksQ0FBRSxDQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFFLEVBQUUsQ0FBRSxHQUFHLEVBQUUsRUFBRSxDQUFFLENBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ3BHLENBQUMsQ0FBRSxDQUFDO1FBRUosT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQzVCLENBQUM7SUFFTyx3Q0FBc0IsR0FBOUI7UUFFQyxJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLGdCQUFnQixDQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBRSxnQkFBZ0IsQ0FBRSxLQUFLLEtBQUssRUFBRztZQUNwRyxPQUFPLENBQUMsQ0FBQztTQUNUO1FBRUQsSUFBSyxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBRSx5QkFBeUIsQ0FBRSxFQUFHO1lBQy9ELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBRSx5QkFBeUIsQ0FBRSxHQUFHLENBQUMsQ0FBQztTQUNyRDtRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2IsQ0FBQztJQUVPLHlCQUFPLEdBQWYsVUFBaUIsR0FBUTtRQUV4QixJQUFLLElBQUksQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFHO1lBQzlCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztTQUNyQjtRQUVELElBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsc0JBQXNCLENBQUUsRUFBRztZQUU1RCxJQUFJLElBQUksR0FBYSxHQUFHLENBQUUsV0FBVyxDQUFFLENBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBRSxzQkFBc0IsQ0FBRSxDQUFFLENBQUUsUUFBUSxDQUFFLENBQUM7WUFFOUYsSUFBSyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBRSxJQUFJLENBQUUsQ0FBQyxDQUFFLENBQUUsRUFBRztnQkFDL0QsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBRSxDQUFDLENBQUUsQ0FBRSxDQUFDO2FBQzlCO1NBQ0Q7UUFFRCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUUsU0FBUyxDQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVPLCtCQUFhLEdBQXJCO1FBQ0MsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFZixJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxHQUFHLGFBQWEsQ0FBQztRQUV6RCxJQUFJLENBQUMsSUFBSSxDQUFFLFNBQVMsQ0FBRSxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBRTtZQUNwQyxTQUFTLEVBQUUsUUFBUSxHQUFHLGlCQUFpQjtZQUN2QyxlQUFlLEVBQUUsUUFBUSxHQUFHLG9CQUFvQjtZQUNoRCxXQUFXLEVBQUUsUUFBUSxHQUFHLG1CQUFtQjtZQUMzQyxVQUFVLEVBQUUsQ0FBRSxFQUFFLEVBQUUsRUFBRSxDQUFFO1lBQ3RCLFlBQVksRUFBRSxDQUFFLEVBQUUsRUFBRSxFQUFFLENBQUU7WUFDeEIsYUFBYSxFQUFFLENBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFFO1lBQ3pCLDhCQUE4QjtZQUM5QixZQUFZLEVBQUUsQ0FBRSxFQUFFLEVBQUUsRUFBRSxDQUFFO1NBQ3hCLENBQUUsQ0FBQztRQUVKLElBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsY0FBYyxDQUFFLEVBQUc7WUFFcEQsS0FBTSxJQUFJLEtBQUssSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFFLGNBQWMsQ0FBRSxFQUFHO2dCQUNuRCxJQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBRTtvQkFDaEMsU0FBUyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUUsY0FBYyxDQUFFLENBQUUsS0FBSyxDQUFFO29CQUNsRCxvREFBb0Q7b0JBQ3BELFdBQVcsRUFBRSxRQUFRLEdBQUcsbUJBQW1CO29CQUMzQyxVQUFVLEVBQUUsQ0FBRSxFQUFFLEVBQUUsRUFBRSxDQUFFO29CQUN0QixZQUFZLEVBQUUsQ0FBRSxFQUFFLEVBQUUsRUFBRSxDQUFFO29CQUN4QixhQUFhLEVBQUUsQ0FBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUU7b0JBQ3pCLDhCQUE4QjtvQkFDOUIsWUFBWSxFQUFFLENBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBRTtvQkFDeEIsY0FBYyxFQUFFLENBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBRTtpQkFDMUIsQ0FBRSxDQUFDO2FBQ0o7U0FDRDtJQUNGLENBQUM7SUFFTywyQkFBUyxHQUFqQixVQUFtQixNQUEwQixFQUFFLEdBQVE7UUFDdEQsSUFBSSxLQUFLLEdBQUcsU0FBUyxDQUFDO1FBQ3RCLElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUVmLG9EQUFvRDtRQUVwRCxLQUFNLElBQUksSUFBSSxJQUFJLEdBQUcsQ0FBRSxXQUFXLENBQUUsRUFBRztZQUN0QyxJQUFJLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFFLElBQUksQ0FBRSxDQUFDO1lBRWhFLElBQUssQ0FBRSxZQUFZLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVksQ0FBQyxJQUFJLEtBQUssS0FBSyxFQUFHO2dCQUMzRSxJQUFJLFNBQVMsR0FBRyxHQUFHLENBQUUsV0FBVyxDQUFFLENBQUUsSUFBSSxDQUFFLENBQUM7Z0JBRTNDLElBQUssS0FBSyxLQUFLLFNBQVMsRUFBRztvQkFDMUIsS0FBSyxHQUFHLFNBQVMsQ0FBRSxRQUFRLENBQUUsQ0FBQyxJQUFJLENBQUUsSUFBSSxDQUFFLENBQUM7b0JBQzNDLEtBQUssQ0FBQyxJQUFJLENBQUUsS0FBSyxHQUFHLFNBQVMsQ0FBRSxrQkFBa0IsQ0FBRSxDQUFDLElBQUksQ0FBRSxJQUFJLENBQUUsR0FBRyxNQUFNLENBQUUsQ0FBQztpQkFDNUU7cUJBQU07b0JBQ04sS0FBSyxDQUFDLElBQUksQ0FBRSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFFLGtCQUFrQixDQUFFLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBRSxDQUFFLENBQUE7aUJBQ3hIO2FBQ0Q7U0FDRDtRQUVELElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUUsTUFBTSxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUUsQ0FBQztRQUM5RCxNQUFNLENBQUMsU0FBUyxDQUFFLEtBQUssQ0FBQyxJQUFJLENBQUUsTUFBTSxDQUFFLENBQUUsQ0FBQztRQUV6QyxNQUFNLENBQUMsT0FBTyxDQUFFLElBQUksQ0FBQyxPQUFPLENBQUUsR0FBRyxDQUFFLENBQUUsQ0FBQztRQUN0QyxPQUFPLE1BQU0sQ0FBQztJQUNmLENBQUM7SUFFTSwwQkFBUSxHQUFmO1FBQUEsaUJBaUNDO1FBL0JBLElBQUssSUFBSSxDQUFDLFdBQVcsRUFBRztZQUN2QixPQUFPO1NBQ1A7UUFFRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUV4QixJQUFJLElBQUksR0FBRyxJQUFJLENBQUM7UUFFaEIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUU7WUFFekIsSUFBSSxVQUFVLEdBQVk7Z0JBQ3pCLE1BQU0sRUFBRSxLQUFJLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBRSxDQUFDLEVBQUUsQ0FBQyxDQUFFO2FBQ3RFLENBQUM7WUFFRixVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBRSxDQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFFLEVBQUUsVUFBVSxDQUFFLENBQUM7WUFFN0UsMENBQTBDO1lBRTFDLElBQUksQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBZ0IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUMsR0FBRyxDQUFFLENBQUMsQ0FBRSxFQUFFLFVBQVUsQ0FBRSxDQUFDO1lBQy9FLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBRSxDQUFDO1lBRTdDLElBQUssS0FBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUUsY0FBYyxDQUFFLEVBQUc7Z0JBQ3BELENBQUMsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFFLEtBQUksQ0FBQyxPQUFPLENBQUUsY0FBYyxDQUFFLENBQUUsQ0FBQyxLQUFLLENBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBRSxDQUFDO2FBQ3pFO1lBRUQsSUFBSyxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUUsTUFBTSxDQUFFLEVBQUc7Z0JBQzNDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFFLElBQUksQ0FBQyxNQUFNLENBQUUsQ0FBQzthQUNsQztRQUVGLENBQUMsQ0FBRSxDQUFDO0lBRUwsQ0FBQztJQUVNLDRCQUFVLEdBQWpCLFVBQW1CLElBQWMsRUFBRSxRQUFzQjtRQUF0Qix5QkFBQSxFQUFBLGFBQXNCO1FBRXhELEtBQWlCLFVBQUksRUFBSixhQUFJLEVBQUosa0JBQUksRUFBSixJQUFJLEVBQUc7WUFBbEIsSUFBSSxHQUFHLGFBQUE7WUFDWixJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFFLEdBQUcsQ0FBRSxFQUFHO2dCQUN6QyxRQUFRLENBQUUsR0FBRyxDQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBRSxHQUFHLENBQUUsQ0FBQzthQUN0QztTQUNEO1FBRUQsT0FBTyxRQUFRLENBQUM7SUFDakIsQ0FBQztJQUVNLDBCQUFRLEdBQWYsVUFBaUIsTUFBZ0I7UUFBakMsaUJBTUM7UUFMQSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBRTtZQUN6QixLQUFJLENBQUMsZ0JBQWdCLENBQUUsTUFBTSxFQUFFLFVBQUUsTUFBaUI7Z0JBQ2pELEtBQUksQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUUsTUFBTSxDQUFFLENBQUE7WUFDNUMsQ0FBQyxDQUFFLENBQUE7UUFDSixDQUFDLENBQUUsQ0FBQztJQUNMLENBQUM7SUFFTSwwQkFBUSxHQUFmLFVBQWlCLE1BQWdCO1FBQWpDLGlCQU1DO1FBTEEsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUU7WUFDekIsS0FBSSxDQUFDLGdCQUFnQixDQUFFLE1BQU0sRUFBRSxVQUFFLE1BQWlCO2dCQUNqRCxLQUFJLENBQUMsa0JBQWtCLENBQUMsWUFBWSxDQUFFLE1BQU0sQ0FBRSxDQUFBO1lBQy9DLENBQUMsQ0FBRSxDQUFBO1FBQ0osQ0FBQyxDQUFFLENBQUM7SUFDTCxDQUFDO0lBRU8sa0NBQWdCLEdBQXhCLFVBQTBCLE1BQWdCLEVBQUUsRUFBaUM7UUFFNUUsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUUsTUFBTSxDQUFFLENBQUM7UUFFMUQsSUFBSyxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFHO1lBQ2xDLEVBQUUsQ0FBRSxnQkFBZ0IsQ0FBRSxDQUFDO1NBQ3ZCO0lBRUYsQ0FBQztJQUVPLHFDQUFtQixHQUEzQixVQUE2QixNQUFnQjtRQUM1QyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFFLE1BQU0sQ0FBRSxDQUFFLENBQUM7SUFDOUQsQ0FBQztJQUVPLHdDQUFzQixHQUE5QixVQUFnQyxNQUFnQjtRQUFoRCxpQkFFQztRQURBLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBRSxVQUFFLEtBQWEsSUFBTSxPQUFBLEtBQUksQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUksQ0FBQyxPQUFPLENBQUUsS0FBSyxDQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBbEQsQ0FBa0QsQ0FBRSxDQUFDO0lBQzlGLENBQUM7SUFFTyx5QkFBTyxHQUFmLFVBQWlCLE9BQW9CO1FBQ3BDLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBRSxVQUFFLE1BQWlCLEVBQUUsTUFBaUIsSUFBTSxPQUFBLE1BQU0sQ0FBQyxNQUFNLENBQUUsTUFBTSxDQUFFLEVBQXZCLENBQXVCLEVBQUUsRUFBRSxDQUFFLENBQUM7SUFDbEcsQ0FBQztJQUVNLHNCQUFJLEdBQVg7UUFDQyxpQkFBTSxJQUFJLFdBQUUsQ0FBQztRQUNiLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNqQixDQUFDO0lBRUYsY0FBQztBQUFELENBdlBBLEFBdVBDLENBdlA0QixXQUFJLEdBdVBoQztBQXZQWSwwQkFBTzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDUHBCLCtCQUE4QjtBQUU5QjtJQUErQiw2QkFBSTtJQUFuQzs7SUFNQSxDQUFDO0lBSlUsb0NBQWdCLEdBQTFCO1FBQ0MsT0FBTyxzQkFBc0IsQ0FBQztJQUMvQixDQUFDO0lBRUYsZ0JBQUM7QUFBRCxDQU5BLEFBTUMsQ0FOOEIsV0FBSSxHQU1sQztBQU5ZLDhCQUFTOzs7OztBQ0N0QjtJQVNDLGNBQW9CLEVBQVUsRUFBRSxNQUFjLEVBQUUsQ0FBYSxFQUFFLE9BQXFCO1FBQXJCLHdCQUFBLEVBQUEsWUFBcUI7UUFQMUUsT0FBRSxHQUFXLFNBQVMsQ0FBQztRQUN2QixXQUFNLEdBQVcsU0FBUyxDQUFDO1FBQzNCLGVBQVUsR0FBZSxTQUFTLENBQUM7UUFDbkMsWUFBTyxHQUFZLFNBQVMsQ0FBQztRQUM3QixZQUFPLEdBQVksS0FBSyxDQUFDO1FBQ3pCLFNBQUksR0FBa0MsRUFBRSxDQUFDO1FBR2xELElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVNLG1CQUFJLEdBQVg7UUFBQSxpQkFhQztRQVhBLElBQUksTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBRSxDQUFDO1FBQ3RELElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFFLENBQUM7UUFFdkQsSUFBSSxDQUFDLElBQUksQ0FBRSxVQUFFLEtBQUssRUFBRSxJQUFJO1lBQ3ZCLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7WUFDN0IsS0FBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUc7Z0JBQzFDLElBQUssTUFBTSxDQUFDLE9BQU8sQ0FBRSxPQUFPLENBQUUsQ0FBQyxDQUFFLENBQUUsSUFBSSxDQUFDLEVBQUc7b0JBQzFDLEtBQUksQ0FBQyxJQUFJLENBQUUsT0FBTyxDQUFFLENBQUMsQ0FBRSxDQUFFLEdBQUcsQ0FBQyxDQUFFLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBRSxDQUFDO2lCQUMvQzthQUNEO1FBQ0YsQ0FBQyxDQUFFLENBQUM7SUFDTCxDQUFDO0lBRVMsK0JBQWdCLEdBQTFCO1FBQ0MsT0FBTyxnQkFBZ0IsQ0FBQztJQUN6QixDQUFDO0lBRU0sK0JBQWdCLEdBQXZCO1FBQ0MsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3BCLENBQUM7SUFFTSx1QkFBUSxHQUFmLFVBQWlCLE1BQWdCO1FBQWpDLGlCQWVDO1FBYkEsSUFBSyxJQUFJLENBQUMsT0FBTyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFHO1lBRTFDLE1BQU0sQ0FBQyxPQUFPLENBQUUsVUFBRSxLQUFhO2dCQUM5QixLQUFJLENBQUMsSUFBSSxDQUFFLEtBQUssQ0FBRSxDQUFDLFNBQVMsQ0FBRSxHQUFHLENBQUUsQ0FBQztZQUNyQyxDQUFDLENBQUUsQ0FBQztTQUVKO2FBQU07WUFFTixNQUFNLENBQUMsT0FBTyxDQUFFLFVBQUUsS0FBYTtnQkFDOUIsS0FBSSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxHQUFHLENBQUUsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLENBQUMsQ0FBRSxDQUFDO1NBRUo7SUFDRixDQUFDO0lBRU0sdUJBQVEsR0FBZixVQUFpQixNQUFnQjtRQUFqQyxpQkFlQztRQWJBLElBQUssSUFBSSxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLEdBQUcsRUFBRztZQUUxQyxNQUFNLENBQUMsT0FBTyxDQUFFLFVBQUUsS0FBYTtnQkFDOUIsS0FBSSxDQUFDLElBQUksQ0FBRSxLQUFLLENBQUUsQ0FBQyxPQUFPLENBQUUsR0FBRyxDQUFFLENBQUM7WUFDbkMsQ0FBQyxDQUFFLENBQUM7U0FFSjthQUFNO1lBRU4sTUFBTSxDQUFDLE9BQU8sQ0FBRSxVQUFFLEtBQWE7Z0JBQzlCLEtBQUksQ0FBQyxJQUFJLENBQUUsS0FBSyxDQUFFLENBQUMsR0FBRyxDQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUM1QyxDQUFDLENBQUUsQ0FBQztTQUVKO0lBQ0YsQ0FBQztJQUVNLG1CQUFJLEdBQVg7UUFDQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO0lBQ3JCLENBQUM7SUFFTSxtQkFBSSxHQUFYO1FBQ0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUN0QixDQUFDO0lBQ0YsV0FBQztBQUFELENBbEZBLEFBa0ZDLElBQUE7QUFsRlksb0JBQUk7Ozs7O0FDRmpCO0lBT0Msc0JBQW9CLE1BQWMsRUFBRSxPQUFpQixFQUFFLFVBQXNCO1FBTHJFLFdBQU0sR0FBVyxTQUFTLENBQUM7UUFDM0IsWUFBTyxHQUFhLFNBQVMsQ0FBQztRQUU5QixlQUFVLEdBQWUsU0FBUyxDQUFDO1FBRzFDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQzlCLENBQUM7SUFFTSwyQkFBSSxHQUFYO1FBQUEsaUJBTUM7UUFMQSxJQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRztZQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBRSxVQUFFLEVBQVUsSUFBTyxLQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBRSxPQUFPLEVBQUUsR0FBRyxHQUFHLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFHLEtBQUksQ0FBQyxVQUFVLEVBQUUsRUFBRSxZQUFZLENBQUMsa0JBQWtCLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBRSxDQUFDO1lBQ3JLLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3JELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDbkI7SUFDRixDQUFDO0lBRWMsK0JBQWtCLEdBQWpDLFVBQW1DLEtBQXdCO1FBRTFELEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBRSxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBRSxDQUFDO1FBRTFELENBQUMsQ0FBRSxLQUFLLENBQUMsTUFBTSxDQUFFO2FBQ2hCLFFBQVEsQ0FBRSxVQUFVLENBQUM7YUFDckIsUUFBUSxFQUFFLENBQUMsV0FBVyxDQUFFLFVBQVUsQ0FBRSxDQUFDO1FBRXRDLEtBQUssQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN4QixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVGLG1CQUFDO0FBQUQsQ0FqQ0EsQUFpQ0MsSUFBQTtBQWpDWSxvQ0FBWTs7Ozs7QUNEekIsZ0RBQStDO0FBRy9DLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFFLG1CQUFtQixDQUFFLENBQUM7d0JBRXhDLEVBQUU7SUFDWCxJQUFLLE1BQU0sQ0FBQyxjQUFjLENBQUUsRUFBRSxDQUFFLEVBQUc7UUFDbEMsSUFBSSxHQUFDLEdBQUcsSUFBSSxtQkFBUSxDQUFFLENBQUMsQ0FBRSxHQUFHLEdBQUcsRUFBRSxDQUFFLEVBQUUsTUFBTSxDQUFFLEVBQUUsQ0FBRSxDQUFFLENBQUM7UUFDcEQsRUFBRSxDQUFDLElBQUksQ0FBRSxrQkFBa0IsQ0FBRSxDQUFDLEdBQUcsQ0FBRSxjQUFNLE9BQUEsR0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFQLENBQU8sQ0FBRSxDQUFDO0tBQ25EOztBQUpGLEtBQU0sSUFBSSxFQUFFLElBQUksTUFBTTtZQUFaLEVBQUU7Q0FLWCIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSIsIi8vLyA8cmVmZXJlbmNlIHR5cGVzPVwianF1ZXJ5XCIgLz5cblxuaW1wb3J0IHsgT3B0aW9ucywgUmVzdWx0RGF0YSB9IGZyb20gXCIuLi90eXBlc1wiO1xuZGVjbGFyZSBsZXQgc3JmOiBhbnk7XG5cbmltcG9ydCB7IFZpZXcgfSBmcm9tIFwiLi9WaWV3L1ZpZXdcIjtcbmltcG9ydCB7IEZpbHRlciB9IGZyb20gXCIuL0ZpbHRlci9GaWx0ZXJcIjtcblxuZXhwb3J0IGNsYXNzIENvbnRyb2xsZXIge1xuXHRwcml2YXRlIHRhcmdldDogSlF1ZXJ5ID0gdW5kZWZpbmVkO1xuXHRwcml2YXRlIGZpbHRlclNwaW5uZXI6IEpRdWVyeSA9IHVuZGVmaW5lZDtcblxuXHRwcml2YXRlIHZpZXdzOiB7IFtrZXk6IHN0cmluZ106IFZpZXcgfSA9IHt9O1xuXHRwcml2YXRlIGZpbHRlcnM6IHsgW2tleTogc3RyaW5nXTogRmlsdGVyIH0gPSB7fTtcblx0cHJpdmF0ZSBjdXJyZW50VmlldzogVmlldyA9IHVuZGVmaW5lZDtcblx0cHJpdmF0ZSBkYXRhOiBSZXN1bHREYXRhO1xuXHRwcml2YXRlIHByaW50UmVxdWVzdHM6IE9wdGlvbnM7XG5cblx0cHVibGljIGNvbnN0cnVjdG9yKCB0YXJnZXQ6IEpRdWVyeSwgZGF0YTogUmVzdWx0RGF0YSwgcHJpbnRSZXF1ZXN0czogT3B0aW9ucyApIHtcblx0XHR0aGlzLnRhcmdldCA9IHRhcmdldDtcblxuXHRcdGlmICggdGhpcy50YXJnZXQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuZmlsdGVyU3Bpbm5lciA9IHRoaXMudGFyZ2V0LmZpbmQoICdkaXYuZmlsdGVyZWQtZmlsdGVyLXNwaW5uZXInICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5kYXRhID0gZGF0YTtcblx0XHR0aGlzLnByaW50UmVxdWVzdHMgPSBwcmludFJlcXVlc3RzO1xuXG5cdFx0Zm9yICggbGV0IHJvd0lkIGluIHRoaXMuZGF0YSApIHtcblx0XHRcdGlmICggIXRoaXMuZGF0YVsgcm93SWQgXS5oYXNPd25Qcm9wZXJ0eSggJ3Zpc2libGUnICkgKSB7XG5cdFx0XHRcdHRoaXMuZGF0YVsgcm93SWQgXS52aXNpYmxlID0ge307XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHVibGljIGdldERhdGEoKTogYW55IHtcblx0XHRyZXR1cm4gdGhpcy5kYXRhO1xuXHR9XG5cblx0cHVibGljIGdldFByaW50UmVxdWVzdHMoKTogT3B0aW9ucyB7XG5cdFx0cmV0dXJuIHRoaXMucHJpbnRSZXF1ZXN0cztcblx0fVxuXG5cdHB1YmxpYyBnZXRQYXRoKCkge1xuXHRcdHJldHVybiBzcmYuc2V0dGluZ3MuZ2V0KCAnc3JmZ1NjcmlwdFBhdGgnICkgKyAnL2Zvcm1hdHMvZmlsdGVyZWQvcmVzb3VyY2VzLyc7XG5cdH1cblxuXHRwdWJsaWMgYXR0YWNoVmlldyggdmlld2lkOiBzdHJpbmcsIHZpZXc6IFZpZXcgKSB7XG5cblx0XHR0aGlzLnZpZXdzWyB2aWV3aWQgXSA9IHZpZXc7XG5cblx0XHRpZiAoIHRoaXMuY3VycmVudFZpZXcgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuY3VycmVudFZpZXcgPSB2aWV3O1xuXHRcdFx0dmlldy5zaG93KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZpZXcuaGlkZSgpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIGdldFZpZXcoIHZpZXdJZDogc3RyaW5nICk6IFZpZXcge1xuXHRcdHJldHVybiB0aGlzLnZpZXdzWyB2aWV3SWQgXTtcblx0fVxuXG5cdHB1YmxpYyBhdHRhY2hGaWx0ZXIoIGZpbHRlcjogRmlsdGVyICk6IEpRdWVyeVByb21pc2U8IHZvaWQgPiB7XG5cdFx0bGV0IGZpbHRlcklkID0gZmlsdGVyLmdldElkKCk7XG5cblx0XHR0aGlzLmZpbHRlcnNbIGZpbHRlcklkIF0gPSBmaWx0ZXI7XG5cblx0XHRmaWx0ZXIuaW5pdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXMub25GaWx0ZXJVcGRhdGVkKCBmaWx0ZXJJZCApO1xuXHR9XG5cblx0cHVibGljIGdldEZpbHRlciggZmlsdGVySWQ6IHN0cmluZyApOiBGaWx0ZXIge1xuXHRcdHJldHVybiB0aGlzLmZpbHRlcnNbIGZpbHRlcklkIF07XG5cdH1cblxuXHRwdWJsaWMgc2hvdygpIHtcblx0XHR0aGlzLmluaXRpYWxpemVGaWx0ZXJzKCk7XG5cdFx0dGhpcy50YXJnZXQuY2hpbGRyZW4oICcuZmlsdGVyZWQtc3Bpbm5lcicgKS5yZW1vdmUoKTtcblx0XHR0aGlzLnRhcmdldC5jaGlsZHJlbigpLnNob3coKTtcblx0XHR0aGlzLnN3aXRjaFRvVmlldyggdGhpcy5jdXJyZW50VmlldyApO1xuXHR9XG5cblx0cHJpdmF0ZSBzd2l0Y2hUb1ZpZXcoIHZpZXc6IFZpZXcgKSB7XG5cblx0XHRpZiAoIHRoaXMuY3VycmVudFZpZXcgaW5zdGFuY2VvZiBWaWV3ICkge1xuXHRcdFx0dGhpcy5jdXJyZW50Vmlldy5oaWRlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5jdXJyZW50VmlldyA9IHZpZXc7XG5cblx0XHRpZiAoIHRoaXMuY3VycmVudFZpZXcgaW5zdGFuY2VvZiBWaWV3ICkge1xuXHRcdFx0dmlldy5zaG93KCk7XG5cdFx0fVxuXG5cdH1cblxuXHRwcml2YXRlIGluaXRpYWxpemVGaWx0ZXJzKCkge1xuXHRcdGxldCB0b1Nob3c6IHN0cmluZ1tdID0gW107XG5cdFx0bGV0IHRvSGlkZTogc3RyaW5nW10gPSBbXTtcblxuXHRcdGZvciAoIGxldCByb3dJZCBpbiB0aGlzLmRhdGEgKSB7XG5cdFx0XHRmb3IgKCBsZXQgZmlsdGVySWQgaW4gdGhpcy5maWx0ZXJzICkge1xuXHRcdFx0XHR0aGlzLmRhdGFbIHJvd0lkIF0udmlzaWJsZVsgZmlsdGVySWQgXSA9IHRoaXMuZmlsdGVyc1sgZmlsdGVySWQgXS5pc0Rpc2FibGVkKCkgfHwgdGhpcy5maWx0ZXJzWyBmaWx0ZXJJZCBdLmlzVmlzaWJsZSggcm93SWQgKTtcblx0XHRcdH1cblx0XHRcdGlmICggdGhpcy5pc1Zpc2libGUoIHJvd0lkICkgKSB7XG5cdFx0XHRcdHRvU2hvdy5wdXNoKCByb3dJZCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dG9IaWRlLnB1c2goIHJvd0lkICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5oaWRlUm93cyggdG9IaWRlICk7XG5cdFx0dGhpcy5zaG93Um93cyggdG9TaG93ICk7XG5cdH1cblxuXHRwdWJsaWMgb25WaWV3U2VsZWN0ZWQoIHZpZXdJRDogc3RyaW5nICkge1xuXHRcdHRoaXMuc3dpdGNoVG9WaWV3KCB0aGlzLnZpZXdzWyB2aWV3SUQgXSApO1xuXHR9XG5cblx0cHVibGljIG9uRmlsdGVyVXBkYXRlZCggZmlsdGVySWQ6IHN0cmluZyApOiBKUXVlcnlQcm9taXNlPCB2b2lkID4ge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2hvd1NwaW5uZXIoKVxuXHRcdC50aGVuKCgpID0+IHtcblxuXHRcdFx0bGV0IHRvU2hvdzogc3RyaW5nW10gPSBbXTtcblx0XHRcdGxldCB0b0hpZGU6IHN0cmluZ1tdID0gW107XG5cblx0XHRcdGxldCBkaXNhYmxlZCA9IHRoaXMuZmlsdGVyc1sgZmlsdGVySWQgXS5pc0Rpc2FibGVkKCk7XG5cblx0XHRcdGZvciAoIGxldCByb3dJZCBpbiB0aGlzLmRhdGEgKSB7XG5cblx0XHRcdFx0bGV0IG5ld1Zpc2libGU6IGJvb2xlYW4gPSBkaXNhYmxlZCB8fCB0aGlzLmZpbHRlcnNbIGZpbHRlcklkIF0uaXNWaXNpYmxlKCByb3dJZCApO1xuXG5cdFx0XHRcdGlmICggdGhpcy5kYXRhWyByb3dJZCBdLnZpc2libGVbIGZpbHRlcklkIF0gIT09IG5ld1Zpc2libGUgKSB7XG5cblx0XHRcdFx0XHR0aGlzLmRhdGFbIHJvd0lkIF0udmlzaWJsZVsgZmlsdGVySWQgXSA9IG5ld1Zpc2libGU7XG5cblx0XHRcdFx0XHRpZiAoIG5ld1Zpc2libGUgJiYgdGhpcy5pc1Zpc2libGUoIHJvd0lkICkgKSB7XG5cdFx0XHRcdFx0XHR0b1Nob3cucHVzaCggcm93SWQgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0dG9IaWRlLnB1c2goIHJvd0lkICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuaGlkZVJvd3MoIHRvSGlkZSApO1xuXHRcdFx0dGhpcy5zaG93Um93cyggdG9TaG93ICk7XG5cdFx0fSlcblx0XHQudGhlbiggKCkgPT4geyB0aGlzLmhpZGVTcGlubmVyKCkgfSApO1xuXHR9XG5cblx0cHVibGljIGlzVmlzaWJsZSggcm93SWQ6IGFueSApIHtcblx0XHRmb3IgKCBsZXQgZmlsdGVySWQgaW4gdGhpcy5kYXRhWyByb3dJZCBdLnZpc2libGUgKSB7XG5cdFx0XHRpZiAoICF0aGlzLmRhdGFbIHJvd0lkIF0udmlzaWJsZVsgZmlsdGVySWQgXSApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdHByaXZhdGUgaGlkZVJvd3MoIHJvd0lkczogc3RyaW5nW10gKSB7XG5cdFx0aWYgKCByb3dJZHMubGVuZ3RoID09PSAwICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRmb3IgKCBsZXQgdmlld0lkIGluIHRoaXMudmlld3MgKSB7XG5cdFx0XHR0aGlzLnZpZXdzWyB2aWV3SWQgXS5oaWRlUm93cyggcm93SWRzICk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBzaG93Um93cyggcm93SWRzOiBzdHJpbmdbXSApIHtcblx0XHRpZiAoIHJvd0lkcy5sZW5ndGggPT09IDAgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGZvciAoIGxldCB2aWV3SWQgaW4gdGhpcy52aWV3cyApIHtcblx0XHRcdHRoaXMudmlld3NbIHZpZXdJZCBdLnNob3dSb3dzKCByb3dJZHMgKTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIHNob3dTcGlubmVyKCk6IEpRdWVyeVByb21pc2U8IHZvaWQgPiB7XG5cdFx0cmV0dXJuIHRoaXMuYW5pbWF0ZVNwaW5uZXIoKTtcblx0fVxuXG5cdHByaXZhdGUgaGlkZVNwaW5uZXIoKTogSlF1ZXJ5UHJvbWlzZTwgdm9pZCA+IHtcblx0XHRyZXR1cm4gdGhpcy5hbmltYXRlU3Bpbm5lciggZmFsc2UgKTtcblx0fVxuXG5cdHByaXZhdGUgYW5pbWF0ZVNwaW5uZXIoIHNob3c6IGJvb2xlYW4gPSB0cnVlICk6IEpRdWVyeVByb21pc2U8IHZvaWQgPiB7XG5cblx0XHRpZiAoIHRoaXMuZmlsdGVyU3Bpbm5lciA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS53aGVuKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBzaG93ICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZmlsdGVyU3Bpbm5lci5mYWRlSW4oIDIwMCApLnByb21pc2UoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5maWx0ZXJTcGlubmVyLmZhZGVPdXQoIDIwMCApLnByb21pc2UoKTtcblx0fVxuXG59XG4iLCJpbXBvcnQgeyBGaWx0ZXIgfSBmcm9tIFwiLi9GaWx0ZXJcIjtcblxuZGVjbGFyZSBsZXQgbXc6IGFueTtcblxuZXhwb3J0IGNsYXNzIERpc3RhbmNlRmlsdGVyIGV4dGVuZHMgRmlsdGVyIHtcblxuXHRwcml2YXRlIHN0YXRpYyByZWFkb25seSBlYXJ0aFJhZGl1czogeyBba2V5OiBzdHJpbmddOiBudW1iZXIgfSA9IHtcblx0XHRtOiA2MzcxMDA4LjgsXG5cdFx0a206IDYzNzEuMDA4OCxcblx0XHRtaTogMzk1OC43NjEzLFxuXHRcdG5tOiAzNDQwLjA2OTUsXG5cdFx0w4U6IDYzNzEwMDg4MDAwMDAwMDAwXG5cdH07XG5cblx0cHJpdmF0ZSBlYXJ0aFJhZGl1c1ZhbHVlOiBudW1iZXIgPSBEaXN0YW5jZUZpbHRlci5lYXJ0aFJhZGl1cy5rbTtcblx0cHJpdmF0ZSBmaWx0ZXJWYWx1ZTogbnVtYmVyID0gMDtcblxuXHRwdWJsaWMgaW5pdCgpIHtcblxuXHRcdGxldCB2YWx1ZXMgPSB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpO1xuXG5cdFx0bGV0IG9yaWdpbiA9IHRoaXMub3B0aW9uc1sgJ29yaWdpbicgXTtcblxuXHRcdGlmICggISggb3JpZ2luICE9PSB1bmRlZmluZWQgJiYgb3JpZ2luLmhhc093blByb3BlcnR5KCAnbGF0JyApICYmIG9yaWdpbi5oYXNPd25Qcm9wZXJ0eSggJ2xuZycgKSApICkge1xuXHRcdFx0dGhpcy50YXJnZXQuZGV0YWNoKCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHVuaXQgPSAna20nO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnNbICd1bml0JyBdICYmIERpc3RhbmNlRmlsdGVyLmVhcnRoUmFkaXVzWyB0aGlzLm9wdGlvbnNbICd1bml0JyBdIF0gKSB7XG5cdFx0XHR1bml0ID0gdGhpcy5vcHRpb25zWyAndW5pdCcgXTtcblx0XHR9XG5cblx0XHR0aGlzLmVhcnRoUmFkaXVzVmFsdWUgPSBEaXN0YW5jZUZpbHRlci5lYXJ0aFJhZGl1c1sgdW5pdCBdO1xuXG5cdFx0bGV0IG1heFZhbHVlOiBudW1iZXIgPSB0aGlzLnVwZGF0ZURpc3RhbmNlcyggb3JpZ2luICk7XG5cblx0XHRsZXQgcHJlY2lzaW9uID0gMTAgKiogKCBNYXRoLmZsb29yKCBNYXRoLmxvZyggbWF4VmFsdWUgKSAqIE1hdGguTE9HMTBFICkgLSAxKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zWyAnbWF4JyBdICE9PSB1bmRlZmluZWQgJiYgdGhpcy5vcHRpb25zWyAnbWF4JyBdID4gbWF4VmFsdWUgKSB7XG5cdFx0XHRtYXhWYWx1ZSA9IHRoaXMub3B0aW9uc1sgJ21heCcgXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWF4VmFsdWUgPSBNYXRoLmNlaWwoIG1heFZhbHVlIC8gcHJlY2lzaW9uICkgKiBwcmVjaXNpb247XG5cdFx0fVxuXG5cdFx0dGhpcy5maWx0ZXJWYWx1ZSA9IHRoaXMub3B0aW9uc1sgJ2luaXRpYWwgdmFsdWUnIF0gPyBNYXRoLm1pbiggdGhpcy5vcHRpb25zWyAnaW5pdGlhbCB2YWx1ZScgXSwgbWF4VmFsdWUgKSA6IG1heFZhbHVlO1xuXG5cdFx0Ly8gYnVpbGQgZmlsdGVyIGNvbnRyb2xzXG5cdFx0bGV0IGZpbHRlcmNvbnRyb2xzID0gdGhpcy5idWlsZEVtcHR5Q29udHJvbCgpO1xuXG5cdFx0bGV0IHJlYWRvdXQgPSAkKCAnPGRpdiBjbGFzcz1cImZpbHRlcmVkLWRpc3RhbmNlLXJlYWRvdXRcIj4nICsgdGhpcy5maWx0ZXJWYWx1ZSArICc8L2Rpdj4nICk7XG5cblx0XHRsZXQgdGFibGUgPSAkKCAnPHRhYmxlIGNsYXNzPVwiZmlsdGVyZWQtZGlzdGFuY2UtdGFibGVcIj48dGJvZHk+PHRyPjx0ZCBjbGFzcz1cImZpbHRlcmVkLWRpc3RhbmNlLW1pbi1jZWxsXCI+MDwvdGQ+JyArXG5cdFx0XHQnPHRkIGNsYXNzPVwiZmlsdGVyZWQtZGlzdGFuY2Utc2xpZGVyLWNlbGxcIj48ZGl2IGNsYXNzPVwiZmlsdGVyZWQtZGlzdGFuY2Utc2xpZGVyXCI+PC9kaXY+PC90ZD4nICtcblx0XHRcdCc8dGQgY2xhc3M9XCJmaWx0ZXJlZC1kaXN0YW5jZS1tYXgtY2VsbFwiPicgKyBtYXhWYWx1ZSArICc8L3RkPjwvdHI+JyArXG5cdFx0XHQnPHRyPjx0ZCBjb2xzcGFuPTMgY2xhc3M9XCJmaWx0ZXJlZC1kaXN0YW5jZS11bml0LWNlbGxcIj4nICsgdW5pdCArICc8L3RkPjwvdHI+PC90Ym9keT48L3RhYmxlPicgKTtcblxuXHRcdGZpbHRlcmNvbnRyb2xzLmFwcGVuZCggdGFibGUgKTtcblxuXHRcdGxldCB0aGF0ID0gdGhpcztcblx0XHRtdy5sb2FkZXIudXNpbmcoICdqcXVlcnkudWkuc2xpZGVyJyApLnRoZW4oIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGFibGUuZmluZCggJy5maWx0ZXJlZC1kaXN0YW5jZS1zbGlkZXInIClcblx0XHRcdC5zbGlkZXIoIHtcblx0XHRcdFx0YW5pbWF0ZTogdHJ1ZSxcblx0XHRcdFx0bWF4OiBtYXhWYWx1ZSxcblx0XHRcdFx0dmFsdWU6IHRoYXQuZmlsdGVyVmFsdWUsXG5cdFx0XHRcdHN0ZXA6IHByZWNpc2lvbiAvIDEwMFxuXHRcdFx0fSApXG5cdFx0XHQub24oICdzbGlkZWNoYW5nZScsIHVuZGVmaW5lZCwgeyAnZmlsdGVyJzogdGhhdCB9LCBmdW5jdGlvbiAoIGV2ZW50T2JqZWN0OiBKUXVlcnlFdmVudE9iamVjdCwgdWk6IGFueSApIHtcblx0XHRcdFx0ZXZlbnRPYmplY3QuZGF0YS51aSA9IHVpO1xuXHRcdFx0XHRldmVudE9iamVjdC5kYXRhLmZpbHRlci5vbkZpbHRlclVwZGF0ZWQoIGV2ZW50T2JqZWN0ICk7XG5cdFx0XHR9IClcblx0XHRcdC5vbiggJ3NsaWRlJywgdW5kZWZpbmVkLCB7ICdmaWx0ZXInOiB0aGF0IH0sIGZ1bmN0aW9uICggZXZlbnRPYmplY3Q6IEpRdWVyeUV2ZW50T2JqZWN0LCB1aTogYW55ICkge1xuXHRcdFx0XHRyZWFkb3V0LnRleHQoIHVpLnZhbHVlICk7XG5cdFx0XHR9IClcblx0XHRcdC5maW5kKCAnLnVpLXNsaWRlci1oYW5kbGUnIClcblx0XHRcdC5hcHBlbmQoIHJlYWRvdXQgKTtcblxuXHRcdH0gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHJpdmF0ZSB1cGRhdGVEaXN0YW5jZXMoIG9yaWdpbjogTC5MYXRMbmdMaXRlcmFsICk6IG51bWJlciB7XG5cblx0XHRsZXQgdmFsdWVzID0gdGhpcy5jb250cm9sbGVyLmdldERhdGEoKTtcblx0XHRsZXQgbWF4ID0gMTtcblxuXHRcdGxldCBwcklkID0gdGhpcy5wcmludHJlcXVlc3RJZDtcblxuXHRcdGZvciAoIGxldCByb3dJZCBpbiB2YWx1ZXMgKSB7XG5cblx0XHRcdGlmICggdmFsdWVzWyByb3dJZCBdLmRhdGEuaGFzT3duUHJvcGVydHkoIHRoaXMuZmlsdGVySWQgKSApIHtcblx0XHRcdFx0bGV0IGRpc3RhbmNlczogbnVtYmVyW10gPSB2YWx1ZXNbIHJvd0lkIF0uZGF0YVsgdGhpcy5maWx0ZXJJZCBdLnBvc2l0aW9ucy5tYXAoICggcG9zOiBMLkxhdExuZ0xpdGVyYWwgKSA9PiB0aGlzLmRpc3RhbmNlKCBvcmlnaW4sIHBvcyApICk7XG5cdFx0XHRcdGxldCBkaXN0ID0gTWF0aC5taW4oIC4uLmRpc3RhbmNlcyApO1xuXG5cdFx0XHRcdHZhbHVlc1sgcm93SWQgXS5kYXRhWyB0aGlzLmZpbHRlcklkIF0uZGlzdGFuY2UgPSBkaXN0O1xuXHRcdFx0XHRtYXggPSBNYXRoLm1heCggbWF4LCBkaXN0ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR2YWx1ZXNbIHJvd0lkIF0uZGF0YVsgdGhpcy5maWx0ZXJJZCBdLmRpc3RhbmNlID0gSW5maW5pdHk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1heDtcblx0fVxuXG5cdHB1YmxpYyBvbkZpbHRlclVwZGF0ZWQoIGV2ZW50T2JqZWN0OiBKUXVlcnlFdmVudE9iamVjdCApIHtcblx0XHR0aGlzLmZpbHRlclZhbHVlID0gZXZlbnRPYmplY3QuZGF0YS51aS52YWx1ZTtcblx0XHR0aGlzLmNvbnRyb2xsZXIub25GaWx0ZXJVcGRhdGVkKCB0aGlzLmdldElkKCkgKTtcblx0fVxuXG5cdHByaXZhdGUgZGlzdGFuY2UoIGE6IEwuTGF0TG5nTGl0ZXJhbCwgYjogTC5MYXRMbmdMaXRlcmFsICkge1xuXG5cdFx0Y29uc3QgREVHMlJBRCA9IE1hdGguUEkgLyAxODAuMDtcblxuXHRcdGZ1bmN0aW9uIHNxdWFyZWQoIHg6IG51bWJlciApIHtcblx0XHRcdHJldHVybiB4ICogeFxuXHRcdH1cblxuXHRcdGxldCBmID1cblx0XHRcdHNxdWFyZWQoIE1hdGguc2luKCAoIGIubGF0IC0gYS5sYXQgKSAqIERFRzJSQUQgLyAyLjAgKSApICtcblx0XHRcdE1hdGguY29zKCBhLmxhdCAqIERFRzJSQUQgKSAqIE1hdGguY29zKCBiLmxhdCAqIERFRzJSQUQgKSAqXG5cdFx0XHRzcXVhcmVkKCBNYXRoLnNpbiggKCBiLmxuZyAtIGEubG5nICkgKiBERUcyUkFEIC8gMi4wICkgKTtcblxuXHRcdHJldHVybiB0aGlzLmVhcnRoUmFkaXVzVmFsdWUgKiAyICogTWF0aC5hdGFuMiggTWF0aC5zcXJ0KCBmICksIE1hdGguc3FydCggMSAtIGYgKSApO1xuXHR9XG5cblx0cHVibGljIGlzVmlzaWJsZSggcm93SWQ6IHN0cmluZyApOiBib29sZWFuIHtcblxuXHRcdGxldCByb3dkYXRhID0gdGhpcy5jb250cm9sbGVyLmdldERhdGEoKVsgcm93SWQgXS5kYXRhO1xuXG5cdFx0aWYgKCByb3dkYXRhLmhhc093blByb3BlcnR5KCB0aGlzLmZpbHRlcklkICkgKSB7XG5cdFx0XHRyZXR1cm4gcm93ZGF0YVsgdGhpcy5maWx0ZXJJZCBdLmRpc3RhbmNlIDw9IHRoaXMuZmlsdGVyVmFsdWU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHN1cGVyLmlzVmlzaWJsZSggcm93SWQgKTtcblxuXHR9XG5cbn1cbiIsImltcG9ydCB7IE9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IENvbnRyb2xsZXIgfSBmcm9tIFwiLi4vQ29udHJvbGxlclwiO1xuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmlsdGVye1xuXG5cdHByaXZhdGUgb3V0ZXJUYXJnZXQ6IEpRdWVyeSA9IHVuZGVmaW5lZDtcblx0cHJvdGVjdGVkIHRhcmdldDogSlF1ZXJ5ID0gdW5kZWZpbmVkO1xuXHRwcm90ZWN0ZWQgZmlsdGVySWQ6IHN0cmluZztcblx0cHJvdGVjdGVkIHByaW50cmVxdWVzdElkOiBzdHJpbmc7XG5cdHByb3RlY3RlZCBjb250cm9sbGVyOiBDb250cm9sbGVyO1xuXHRwcm90ZWN0ZWQgb3B0aW9uczogT3B0aW9ucyA9IHVuZGVmaW5lZDtcblx0cHJvdGVjdGVkIGRpc2FibGVkOiBib29sZWFuID0gZmFsc2U7XG5cdHByb3RlY3RlZCBjb2xsYXBzZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuXHRwdWJsaWMgY29uc3RydWN0b3IoIGZpbHRlcklkOiBzdHJpbmcsIHRhcmdldDogSlF1ZXJ5LCBwcmludHJlcXVlc3RJZDogc3RyaW5nLCBjb250cm9sbGVyOiBDb250cm9sbGVyLCBvcHRpb25zPzogT3B0aW9ucyApIHtcblx0XHR0aGlzLnRhcmdldCA9IHRhcmdldDtcblx0XHR0aGlzLm91dGVyVGFyZ2V0ID0gdGFyZ2V0O1xuXHRcdHRoaXMuZmlsdGVySWQgPSBmaWx0ZXJJZDtcblx0XHR0aGlzLnByaW50cmVxdWVzdElkID0gcHJpbnRyZXF1ZXN0SWQ7XG5cdFx0dGhpcy5jb250cm9sbGVyID0gY29udHJvbGxlcjtcblx0XHR0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXHR9XG5cblx0cHVibGljIGluaXQoKSB7fTtcblxuXHRwdWJsaWMgaXNEaXNhYmxlZCgpIDogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzYWJsZWQ7XG5cdH1cblxuXHRwdWJsaWMgZGlzYWJsZSgpIHtcblx0XHR0aGlzLmRpc2FibGVkID0gdHJ1ZTtcblxuXHRcdHRoaXMub3V0ZXJUYXJnZXRcblx0XHQucmVtb3ZlQ2xhc3MoICdlbmFibGVkJyApXG5cdFx0LmFkZENsYXNzKCAnZGlzYWJsZWQnICk7XG5cblx0XHR0aGlzLmNvbGxhcHNlKCk7XG5cblx0XHR0aGlzLnRhcmdldC5wcm9taXNlKCkudGhlbiggKCkgPT5cdHRoaXMuY29udHJvbGxlci5vbkZpbHRlclVwZGF0ZWQoIHRoaXMuZmlsdGVySWQgKSApO1xuXHR9XG5cblx0cHVibGljIGVuYWJsZSgpIHtcblx0XHR0aGlzLmRpc2FibGVkID0gZmFsc2U7XG5cblx0XHR0aGlzLm91dGVyVGFyZ2V0XG5cdFx0LnJlbW92ZUNsYXNzKCAnZGlzYWJsZWQnIClcblx0XHQuYWRkQ2xhc3MoICdlbmFibGVkJyApO1xuXG5cdFx0aWYgKCAhIHRoaXMuY29sbGFwc2VkICkge1xuXHRcdFx0dGhpcy51bmNvbGxhcHNlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy50YXJnZXQucHJvbWlzZSgpLnRoZW4oICgpID0+XHR0aGlzLmNvbnRyb2xsZXIub25GaWx0ZXJVcGRhdGVkKCB0aGlzLmZpbHRlcklkICkgKTtcblx0fVxuXG5cdHByaXZhdGUgY29sbGFwc2UoIGR1cmF0aW9uIDogbnVtYmVyID0gNDAwICkge1xuXG5cdFx0aWYgKCAhIHRoaXMuY29sbGFwc2VkICkge1xuXG5cdFx0XHR0aGlzLm91dGVyVGFyZ2V0LnByb21pc2UoKVxuXHRcdFx0LnRoZW4oICgpID0+IHtcblxuXHRcdFx0XHR0aGlzLnRhcmdldC5zbGlkZVVwKCBkdXJhdGlvbiApO1xuXG5cdFx0XHRcdHRoaXMub3V0ZXJUYXJnZXQuYW5pbWF0ZSgge1xuXHRcdFx0XHRcdCdwYWRkaW5nLXRvcCc6IDAsXG5cdFx0XHRcdFx0J3BhZGRpbmctYm90dG9tJzogMCxcblx0XHRcdFx0XHQnbWFyZ2luLWJvdHRvbSc6ICcyZW0nXG5cdFx0XHRcdH0sIGR1cmF0aW9uICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSB1bmNvbGxhcHNlKCkge1xuXHRcdHRoaXMub3V0ZXJUYXJnZXQucHJvbWlzZSgpXG5cdFx0LnRoZW4oICgpID0+IHtcblx0XHRcdHRoaXMudGFyZ2V0LnNsaWRlRG93bigpO1xuXG5cdFx0XHRsZXQgc3R5bGUgPSB0aGlzLm91dGVyVGFyZ2V0LmF0dHIoICdzdHlsZScgKTtcblx0XHRcdHRoaXMub3V0ZXJUYXJnZXQucmVtb3ZlQXR0ciggJ3N0eWxlJyApO1xuXHRcdFx0bGV0IHVuY29sbGFwc2VkQ3NzID0gdGhpcy5vdXRlclRhcmdldC5jc3MoIFsgJ3BhZGRpbmctdG9wJywgJ3BhZGRpbmctYm90dG9tJywgJ21hcmdpbi1ib3R0b20nIF0gKTtcblx0XHRcdHRoaXMub3V0ZXJUYXJnZXQuYXR0ciggJ3N0eWxlJywgc3R5bGUgKTtcblxuXHRcdFx0dGhpcy5vdXRlclRhcmdldC5hbmltYXRlKCB1bmNvbGxhcHNlZENzcyApO1xuXHRcdH0gKTtcblx0fVxuXG5cdHB1YmxpYyBpc1Zpc2libGUoIHJvd0lkOiBzdHJpbmcgKTogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ3Nob3cgaWYgdW5kZWZpbmVkJyApICYmIHRoaXMub3B0aW9uc1sgJ3Nob3cgaWYgdW5kZWZpbmVkJyBdID09PSB0cnVlO1xuXHR9XG5cblx0cHVibGljIGdldElkKCkge1xuXHRcdHJldHVybiB0aGlzLmZpbHRlcklkO1xuXHR9XG5cblx0cHJvdGVjdGVkIGJ1aWxkRW1wdHlDb250cm9sKCkge1xuXG5cdFx0dGhpcy50YXJnZXQgPSAkKCAnPGRpdiBjbGFzcz1cImZpbHRlcmVkLWZpbHRlci1jb250YWluZXJcIj4nICk7XG5cblx0XHR0aGlzLm91dGVyVGFyZ2V0XG5cdFx0LmFwcGVuZCggdGhpcy50YXJnZXQgKVxuXHRcdC5hZGRDbGFzcyggJ2VuYWJsZWQnICk7XG5cblx0XHR0aGlzLmFkZE9uT2ZmU3dpdGNoKCk7XG5cdFx0dGhpcy5hZGRMYWJlbCgpO1xuXHRcdHRoaXMuYWRkQ29udHJvbEZvckNvbGxhcHNpbmcoKTtcblxuXHRcdHJldHVybiB0aGlzLnRhcmdldDtcblx0fVxuXG5cdHByaXZhdGUgYWRkTGFiZWwoKSB7XG5cdFx0Ly8gaW5zZXJ0IHRoZSBsYWJlbCBvZiB0aGUgcHJpbnRvdXQgdGhpcyBmaWx0ZXIgZmlsdGVycyBvblxuXHRcdHRoaXMudGFyZ2V0LmJlZm9yZSggYDxkaXYgY2xhc3M9XCJmaWx0ZXJlZC1maWx0ZXItbGFiZWxcIj4ke3RoaXMub3B0aW9uc1sgJ2xhYmVsJyBdfTwvZGl2PmAgKTtcblx0fVxuXG5cdHByb3RlY3RlZCBhZGRPbk9mZlN3aXRjaCgpIHtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAnc3dpdGNoZXMnICkgKSB7XG5cblx0XHRcdGxldCBzd2l0Y2hlcyA9IHRoaXMub3B0aW9uc1sgJ3N3aXRjaGVzJyBdO1xuXG5cdFx0XHRpZiAoIHN3aXRjaGVzLmxlbmd0aCA+IDAgJiYgJC5pbkFycmF5KCAnb24gb2ZmJywgc3dpdGNoZXMgKSA+PSAwICkge1xuXG5cdFx0XHRcdGxldCBvbk9mZkNvbnRyb2wgPSAkKCBgPGRpdiBjbGFzcz1cImZpbHRlcmVkLWZpbHRlci1vbm9mZiBvblwiPjwvZGl2PmAgKTtcblxuXHRcdFx0XHR0aGlzLnRhcmdldC5iZWZvcmUoIG9uT2ZmQ29udHJvbCApO1xuXG5cdFx0XHRcdG9uT2ZmQ29udHJvbC5jbGljayggKCkgPT4ge1xuXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm91dGVyVGFyZ2V0Lmhhc0NsYXNzKCdlbmFibGVkJyApICkge1xuXHRcdFx0XHRcdFx0dGhpcy5kaXNhYmxlKCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRoaXMuZW5hYmxlKCk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRwcm90ZWN0ZWQgYWRkQ29udHJvbEZvckNvbGxhcHNpbmcoKSB7XG5cdFx0bGV0IGNvbGxhcHNpYmxlID0gdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAnY29sbGFwc2libGUnICkgPyB0aGlzLm9wdGlvbnNbICdjb2xsYXBzaWJsZScgXSA6IHVuZGVmaW5lZDtcblx0XHRpZiAoIGNvbGxhcHNpYmxlID09PSAnY29sbGFwc2VkJyB8fCBjb2xsYXBzaWJsZSA9PT0gJ3VuY29sbGFwc2VkJyApIHtcblxuXHRcdFx0bGV0IGNvbGxhcHNlQ29udHJvbCA9ICQoICc8c3BhbiBjbGFzcz1cImZpbHRlcmVkLWZpbHRlci1jb2xsYXBzZVwiPicgKTtcblxuXHRcdFx0dGhpcy50YXJnZXQuYmVmb3JlKCBjb2xsYXBzZUNvbnRyb2wgKTtcblxuXHRcdFx0Y29sbGFwc2VDb250cm9sLmNsaWNrKCAoKSA9PiB7XG5cdFx0XHRcdGlmICggY29sbGFwc2VDb250cm9sLmhhc0NsYXNzKCAnY29sbGFwc2VkJyApICkge1xuXHRcdFx0XHRcdHRoaXMudW5jb2xsYXBzZSgpO1xuXHRcdFx0XHRcdHRoaXMuY29sbGFwc2VkID0gZmFsc2U7XG5cblx0XHRcdFx0XHRjb2xsYXBzZUNvbnRyb2xcblx0XHRcdFx0XHQucmVtb3ZlQ2xhc3MoICdjb2xsYXBzZWQnIClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoICd1bmNvbGxhcHNlZCcgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLmNvbGxhcHNlKCk7XG5cdFx0XHRcdFx0dGhpcy5jb2xsYXBzZWQgPSB0cnVlO1xuXG5cdFx0XHRcdFx0Y29sbGFwc2VDb250cm9sXG5cdFx0XHRcdFx0LnJlbW92ZUNsYXNzKCAndW5jb2xsYXBzZWQnIClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoICdjb2xsYXBzZWQnICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSApO1xuXG5cdFx0XHRpZiAoIGNvbGxhcHNpYmxlID09PSAnY29sbGFwc2VkJyApIHtcblxuXHRcdFx0XHR0aGlzLmNvbGxhcHNlKCAwICk7XG5cdFx0XHRcdHRoaXMuY29sbGFwc2VkID0gdHJ1ZTtcblx0XHRcdFx0Y29sbGFwc2VDb250cm9sLmFkZENsYXNzKCdjb2xsYXBzZWQnKTtcblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29sbGFwc2VDb250cm9sLmFkZENsYXNzKCd1bmNvbGxhcHNlZCcpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG59IiwiLy8vPHJlZmVyZW5jZSBwYXRoPVwiLi4vLi4vLi4vLi4vbm9kZV9tb2R1bGVzL0B0eXBlcy9pb24ucmFuZ2VzbGlkZXIvaW5kZXguZC50c1wiLz5cbmltcG9ydCB7IEZpbHRlciB9IGZyb20gXCIuL0ZpbHRlclwiO1xuaW1wb3J0IHsgT3B0aW9ucyB9IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuXG5kZWNsYXJlIGxldCBtdzogYW55O1xuXG5leHBvcnQgY2xhc3MgTnVtYmVyRmlsdGVyIGV4dGVuZHMgRmlsdGVyIHtcblxuXHRwcml2YXRlIE1PREVfUkFOR0UgPSAwO1xuXHRwcml2YXRlIE1PREVfTUlOID0gMTtcblx0cHJpdmF0ZSBNT0RFX01BWCA9IDI7XG5cdHByaXZhdGUgTU9ERV9TRUxFQ1QgPSAzO1xuXG5cdHByaXZhdGUgZmlsdGVyVmFsdWVVcHBlcjogbnVtYmVyID0gMDtcblx0cHJpdmF0ZSBmaWx0ZXJWYWx1ZUxvd2VyOiBudW1iZXIgPSAwO1xuXHRwcml2YXRlIG1vZGUgPSB0aGlzLk1PREVfUkFOR0U7XG5cblx0cHVibGljIGluaXQoKSB7XG5cblx0XHRsZXQgdmFsdWVzOiBudW1iZXJbXSA9IHRoaXMuZ2V0VmFsdWVzKCk7XG5cblx0XHRsZXQgeyBtaW5WYWx1ZSwgbWF4VmFsdWUsIHByZWNpc2lvbiB9ID0gdGhpcy5nZXRSYW5nZVBhcmFtZXRlcnMoIHZhbHVlcyApO1xuXG5cdFx0bGV0IHNsaWRlck9wdGlvbnM6IElvblJhbmdlU2xpZGVyT3B0aW9ucyA9IHtcblx0XHRcdHByZXR0aWZ5X2VuYWJsZWQ6IGZhbHNlLFxuXHRcdFx0Zm9yY2VfZWRnZXM6IHRydWUsXG5cdFx0XHRncmlkOiB0cnVlXG5cdFx0fTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAndmFsdWVzJyApICkge1xuXHRcdFx0c2xpZGVyT3B0aW9ucyA9IHRoaXMuYWRqdXN0U2xpZGVyT3B0aW9uc0Zyb21WYWx1ZXMoIHNsaWRlck9wdGlvbnMsIHZhbHVlcyApO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdHNsaWRlck9wdGlvbnMgPSB0aGlzLmFkanVzdFNsaWRlck9wdGlvbnNGcm9tUmFuZ2VQYXJhbWV0ZXJzKCBzbGlkZXJPcHRpb25zLCBtaW5WYWx1ZSwgbWF4VmFsdWUsIHByZWNpc2lvbiApO1xuXHRcdH1cblxuXHRcdHN3aXRjaCggdGhpcy5vcHRpb25zWyAnc2xpZGVycycgXSApIHtcblxuXHRcdFx0Y2FzZSBcIm1pblwiOlxuXG5cdFx0XHRcdHRoaXMubW9kZSA9IHRoaXMuTU9ERV9NSU47XG5cdFx0XHRcdHNsaWRlck9wdGlvbnMudHlwZSA9ICdzaW5nbGUnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBcIm1heFwiOlxuXG5cdFx0XHRcdHRoaXMubW9kZSA9IHRoaXMuTU9ERV9NQVg7XG5cdFx0XHRcdHNsaWRlck9wdGlvbnMuZnJvbSA9IHNsaWRlck9wdGlvbnMudG87XG5cdFx0XHRcdHNsaWRlck9wdGlvbnMudHlwZSA9ICdzaW5nbGUnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBcInNlbGVjdFwiOlxuXG5cdFx0XHRcdHRoaXMubW9kZSA9IHRoaXMuTU9ERV9TRUxFQ1Q7XG5cdFx0XHRcdG1heFZhbHVlID0gbWluVmFsdWU7XG5cdFx0XHRcdHNsaWRlck9wdGlvbnMudHlwZSA9ICdzaW5nbGUnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0ZGVmYXVsdDogLy8gPT0gY2FzZSBcInJhbmdlXCJcblxuXHRcdFx0XHR0aGlzLm1vZGUgPSB0aGlzLk1PREVfUkFOR0U7XG5cdFx0XHRcdHNsaWRlck9wdGlvbnMudHlwZSA9ICdkb3VibGUnO1xuXHRcdH1cblxuXHRcdHRoaXMuYnVpbGRGaWx0ZXJDb250cm9scyggc2xpZGVyT3B0aW9ucyApO1xuXG5cdFx0dGhpcy5maWx0ZXJWYWx1ZUxvd2VyID0gbWluVmFsdWU7XG5cdFx0dGhpcy5maWx0ZXJWYWx1ZVVwcGVyID0gbWF4VmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHByaXZhdGUgYWRqdXN0U2xpZGVyT3B0aW9uc0Zyb21SYW5nZVBhcmFtZXRlcnMoIHNsaWRlck9wdGlvbnM6IElvblJhbmdlU2xpZGVyT3B0aW9ucywgbWluVmFsdWU6IG51bWJlciwgbWF4VmFsdWU6IG51bWJlciwgcHJlY2lzaW9uOiBudW1iZXIgKSB7XG5cblx0XHRzbGlkZXJPcHRpb25zLm1pbiA9IG1pblZhbHVlO1xuXHRcdHNsaWRlck9wdGlvbnMubWF4ID0gbWF4VmFsdWU7XG5cdFx0c2xpZGVyT3B0aW9ucy5zdGVwID0gdGhpcy5nZXRTdGVwKCBwcmVjaXNpb24gKTtcblx0XHRzbGlkZXJPcHRpb25zLmdyaWRfbnVtID0gTWF0aC5taW4oIDQsIE1hdGgucm91bmQoICggbWF4VmFsdWUgLSBtaW5WYWx1ZSApIC8gc2xpZGVyT3B0aW9ucy5zdGVwICkgKTtcblxuXHRcdHNsaWRlck9wdGlvbnMuZnJvbSA9IG1pblZhbHVlO1xuXHRcdHNsaWRlck9wdGlvbnMudG8gPSBtYXhWYWx1ZTtcblxuXHRcdHNsaWRlck9wdGlvbnMub25GaW5pc2ggPSAoIGRhdGE6IElvblJhbmdlU2xpZGVyRXZlbnQgKSA9PiB0aGlzLm9uRmlsdGVyVXBkYXRlZCggZGF0YS5mcm9tLCBkYXRhLnRvICk7XG5cblx0XHRyZXR1cm4gc2xpZGVyT3B0aW9ucztcblx0fVxuXG5cdHByaXZhdGUgYWRqdXN0U2xpZGVyT3B0aW9uc0Zyb21WYWx1ZXMoIHNsaWRlck9wdGlvbnM6IElvblJhbmdlU2xpZGVyT3B0aW9ucywgdmFsdWVzOiBudW1iZXJbXSApIHtcblxuXHRcdHNsaWRlck9wdGlvbnMudmFsdWVzID0gdmFsdWVzO1xuXG5cdFx0c2xpZGVyT3B0aW9ucy5mcm9tID0gMDtcblx0XHRzbGlkZXJPcHRpb25zLnRvID0gdmFsdWVzLmxlbmd0aCAtIDE7XG5cblx0XHRzbGlkZXJPcHRpb25zLm9uRmluaXNoID0gKCBkYXRhOiBJb25SYW5nZVNsaWRlckV2ZW50ICkgPT4gdGhpcy5vbkZpbHRlclVwZGF0ZWQoIGRhdGEuZnJvbV92YWx1ZSwgZGF0YS50b192YWx1ZSApO1xuXG5cdFx0cmV0dXJuIHNsaWRlck9wdGlvbnM7XG5cdH1cblxuXHRwcml2YXRlIGdldFJhbmdlUGFyYW1ldGVycyggdmFsdWVzOiBudW1iZXJbXSApIHtcblxuXHRcdGxldCBtaW5WYWx1ZSA9IHZhbHVlc1sgMCBdO1xuXHRcdGxldCBtYXhWYWx1ZSA9IHZhbHVlc1sgdmFsdWVzLmxlbmd0aCAtIDEgXTtcblx0XHRsZXQgcHJlY2lzaW9uOiBudW1iZXIgPSB0aGlzLmdldFByZWNpc2lvbiggbWluVmFsdWUsIG1heFZhbHVlICk7XG5cblx0XHRpZiAoICF0aGlzLm9wdGlvbnMuaGFzT3duUHJvcGVydHkoICd2YWx1ZXMnICkgKSB7XG5cdFx0XHRtaW5WYWx1ZSA9IHRoaXMuZ2V0TWluU2xpZGVyVmFsdWUoIG1pblZhbHVlLCBwcmVjaXNpb24gKTtcblx0XHRcdG1heFZhbHVlID0gdGhpcy5nZXRNYXhTbGlkZXJWYWx1ZSggbWF4VmFsdWUsIHByZWNpc2lvbiApO1xuXHRcdH1cblxuXHRcdHJldHVybiB7IG1pblZhbHVlLCBtYXhWYWx1ZSwgcHJlY2lzaW9uIH07XG5cdH1cblxuXHRwcml2YXRlIGdldFZhbHVlcygpOiBudW1iZXJbXSB7XG5cdFx0bGV0IHZhbHVlczogbnVtYmVyW107XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGFzT3duUHJvcGVydHkoICd2YWx1ZXMnICkgJiYgdGhpcy5vcHRpb25zWyAndmFsdWVzJyBdWzBdICE9PSAnYXV0bycgKSB7XG5cdFx0XHR2YWx1ZXMgPSAgdGhpcy5vcHRpb25zWyAndmFsdWVzJyBdXG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhbHVlcyA9ICB0aGlzLmdldFNvcnRlZFZhbHVlcygpO1xuXHRcdH1cblxuXHRcdGlmICggdmFsdWVzLmxlbmd0aCA9PT0gMCApIHtcblx0XHRcdHZhbHVlcyA9IFsgMCwgMCBdO1xuXHRcdH0gZWxzZSBpZiAoIHZhbHVlcy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHR2YWx1ZXMucHVzaCggdmFsdWVzWyAwIF0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdmFsdWVzO1xuXHR9XG5cblx0cHJpdmF0ZSBidWlsZEZpbHRlckNvbnRyb2xzKCBzbGlkZXJPcHRpb25zOiBJb25SYW5nZVNsaWRlck9wdGlvbnMgKSB7XG5cblx0XHRsZXQgZmlsdGVyQ2xhc3NOYW1lczogYW55ID0ge307XG5cdFx0ZmlsdGVyQ2xhc3NOYW1lc1sgdGhpcy5NT0RFX01JTi50b1N0cmluZygpIF0gPSBcIm1vZGUtbWluXCI7XG5cdFx0ZmlsdGVyQ2xhc3NOYW1lc1sgdGhpcy5NT0RFX01BWCBdID0gXCJtb2RlLW1heFwiO1xuXHRcdGZpbHRlckNsYXNzTmFtZXNbIHRoaXMuTU9ERV9SQU5HRSBdID0gXCJtb2RlLXJhbmdlXCI7XG5cdFx0ZmlsdGVyQ2xhc3NOYW1lc1sgdGhpcy5NT0RFX1NFTEVDVCBdID0gXCJtb2RlLXNlbGVjdFwiO1xuXG5cdFx0bGV0IGZpbHRlcmNvbnRyb2xzID0gdGhpcy5idWlsZEVtcHR5Q29udHJvbCgpO1xuXG5cdFx0bGV0IHNsaWRlciA9ICQoICc8aW5wdXQgdHlwZT1cInRleHRcIiB2YWx1ZT1cIlwiIC8+JyApO1xuXHRcdGxldCBzbGlkZXJDb250YWluZXIgPSAkKCBgPGRpdiBjbGFzcz1cImZpbHRlcmVkLW51bWJlci1zbGlkZXIgJHtmaWx0ZXJDbGFzc05hbWVzWyB0aGlzLm1vZGUgXX1cIiAvPmAgKS5hcHBlbmQoIHNsaWRlciApO1xuXHRcdGZpbHRlcmNvbnRyb2xzLmFwcGVuZCggc2xpZGVyQ29udGFpbmVyICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ2NhcHRpb24nICkgKSB7XG5cdFx0XHRsZXQgY2FwdGlvbiA9IGA8ZGl2IGNsYXNzPVwiZmlsdGVyZWQtbnVtYmVyLWNhcHRpb25cIj4ke3RoaXMub3B0aW9uc1sgJ2NhcHRpb24nIF19PC9kaXY+YDtcblx0XHRcdGZpbHRlcmNvbnRyb2xzLmFwcGVuZCggY2FwdGlvbiApO1xuXHRcdH1cblxuXHRcdG13LmxvYWRlci51c2luZyggJ2V4dC5zcmYuZmlsdGVyZWQuc2xpZGVyJyApLnRoZW4oICgpID0+IHNsaWRlci5pb25SYW5nZVNsaWRlciggc2xpZGVyT3B0aW9ucyApICk7XG5cdH1cblxuXHRwcml2YXRlIGdldE1pblNsaWRlclZhbHVlKCBtaW5WYWx1ZTogbnVtYmVyLCBwcmVjaXNpb246IG51bWJlciApIHtcblx0XHRsZXQgcmVxdWVzdGVkTWluID0gdGhpcy5vcHRpb25zWyAnbWluJyBdO1xuXG5cdFx0aWYgKCByZXF1ZXN0ZWRNaW4gPT09IHVuZGVmaW5lZCB8fCBpc05hTiggTnVtYmVyKCByZXF1ZXN0ZWRNaW4gKSApICkge1xuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoIG1pblZhbHVlIC8gcHJlY2lzaW9uICkgKiBwcmVjaXNpb247XG5cdFx0fVxuXG5cdFx0cmV0dXJuIE1hdGgubWluKCByZXF1ZXN0ZWRNaW4sIG1pblZhbHVlICk7XG5cdH1cblxuXHRwcml2YXRlIGdldE1heFNsaWRlclZhbHVlKCBtYXhWYWx1ZTogbnVtYmVyLCBwcmVjaXNpb246IG51bWJlciApIHtcblx0XHRsZXQgcmVxdWVzdGVkTWF4ID0gdGhpcy5vcHRpb25zWyAnbWF4JyBdO1xuXG5cdFx0aWYgKCByZXF1ZXN0ZWRNYXggPT09IHVuZGVmaW5lZCB8fCBpc05hTiggTnVtYmVyKCByZXF1ZXN0ZWRNYXggKSApICkge1xuXHRcdFx0cmV0dXJuIE1hdGguY2VpbCggbWF4VmFsdWUgLyBwcmVjaXNpb24gKSAqIHByZWNpc2lvbjtcblx0XHR9XG5cblx0XHRyZXR1cm4gTWF0aC5tYXgoIHJlcXVlc3RlZE1heCwgbWF4VmFsdWUgKTtcblx0fVxuXG5cdHByaXZhdGUgZ2V0UHJlY2lzaW9uKCBtaW5WYWx1ZTogbnVtYmVyLCBtYXhWYWx1ZTogbnVtYmVyICk6IG51bWJlciB7XG5cdFx0aWYgKCBtYXhWYWx1ZSAtIG1pblZhbHVlID4gMCApIHtcblx0XHRcdHJldHVybiAxMCAqKiAoIE1hdGguZmxvb3IoIE1hdGgubG9nKCBtYXhWYWx1ZSAtIG1pblZhbHVlICkgKiBNYXRoLkxPRzEwRSApIC0gMSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gMTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIGdldFN0ZXAoIHByZWNpc2lvbjogbnVtYmVyICk6IG51bWJlciB7XG5cblx0XHRsZXQgc3RlcCA9IHRoaXMub3B0aW9uc1sgJ3N0ZXAnIF07XG5cblx0XHRpZiAoIHN0ZXAgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c3RlcCA9IE51bWJlciggc3RlcCApO1xuXG5cdFx0XHRpZiAoICFpc05hTiggc3RlcCApICkge1xuXHRcdFx0XHRyZXR1cm4gc3RlcDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gcHJlY2lzaW9uIC8gMTA7XG5cdH1cblxuXHRwcml2YXRlIGdldFJhbmdlRnJvbVZhbHVlcygpOiBbIG51bWJlciwgbnVtYmVyIF0ge1xuXG5cdFx0bGV0IHJvd3MgPSB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpO1xuXHRcdGxldCBtaW4gPSBJbmZpbml0eTtcblx0XHRsZXQgbWF4ID0gLUluZmluaXR5O1xuXG5cdFx0Zm9yICggbGV0IHJvd0lkIGluIHJvd3MgKSB7XG5cblx0XHRcdGlmICggcm93c1sgcm93SWQgXS5kYXRhLmhhc093blByb3BlcnR5KCB0aGlzLmZpbHRlcklkICkgKSB7XG5cdFx0XHRcdGxldCB2YWx1ZXM6IG51bWJlcltdID0gcm93c1sgcm93SWQgXS5kYXRhWyB0aGlzLmZpbHRlcklkIF0udmFsdWVzO1xuXHRcdFx0XHRtaW4gPSBNYXRoLm1pbiggbWluLCAuLi52YWx1ZXMgKTtcblx0XHRcdFx0bWF4ID0gTWF0aC5tYXgoIG1heCwgLi4udmFsdWVzICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFsgbWluLCBtYXggXTtcblx0fVxuXG5cdHByaXZhdGUgZ2V0U29ydGVkVmFsdWVzKCk6IG51bWJlcltdIHtcblxuXHRcdGxldCB2YWx1ZUFycmF5OiBudW1iZXJbXSA9IFtdO1xuXHRcdGxldCByb3dzID0gdGhpcy5jb250cm9sbGVyLmdldERhdGEoKTtcblxuXHRcdGZvciAoIGxldCByb3dJZCBpbiByb3dzICkge1xuXG5cdFx0XHRsZXQgY2VsbHMgPSByb3dzWyByb3dJZCBdLmRhdGE7XG5cblx0XHRcdGlmICggY2VsbHMuaGFzT3duUHJvcGVydHkoIHRoaXMuZmlsdGVySWQgKSApIHtcblxuXHRcdFx0XHRsZXQgdmFsdWVzID0gY2VsbHNbIHRoaXMuZmlsdGVySWQgXS52YWx1ZXM7XG5cblx0XHRcdFx0Zm9yICggbGV0IHZhbHVlSWQgaW4gdmFsdWVzICkge1xuXG5cdFx0XHRcdFx0bGV0IHZhbHVlID0gTnVtYmVyKCB2YWx1ZXNbIHZhbHVlSWQgXSApO1xuXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZUFycmF5LmluZGV4T2YoIHZhbHVlICkgPT09IC0xICkge1xuXHRcdFx0XHRcdFx0dmFsdWVBcnJheS5wdXNoKCB2YWx1ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB2YWx1ZUFycmF5LnNvcnQoICggYTogYW55LCBiOiBhbnkgKSA9PiBhIC0gYiApO1xuXHR9XG5cblx0cHVibGljIG9uRmlsdGVyVXBkYXRlZCggZnJvbTogbnVtYmVyLCB0bzogbnVtYmVyICkge1xuXG5cdFx0c3dpdGNoICggdGhpcy5tb2RlICkge1xuXG5cdFx0XHRjYXNlIHRoaXMuTU9ERV9NSU46XG5cblx0XHRcdFx0dGhpcy5maWx0ZXJWYWx1ZUxvd2VyID0gZnJvbTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgdGhpcy5NT0RFX01BWDpcblxuXHRcdFx0XHR0aGlzLmZpbHRlclZhbHVlVXBwZXIgPSBmcm9tO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSB0aGlzLk1PREVfU0VMRUNUOlxuXG5cdFx0XHRcdHRoaXMuZmlsdGVyVmFsdWVMb3dlciA9IGZyb207XG5cdFx0XHRcdHRoaXMuZmlsdGVyVmFsdWVVcHBlciA9IGZyb207XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OiAvLyBjYXNlIHRoaXMuTU9ERV9SQU5HRTpcblxuXHRcdFx0XHR0aGlzLmZpbHRlclZhbHVlTG93ZXIgPSBmcm9tO1xuXHRcdFx0XHR0aGlzLmZpbHRlclZhbHVlVXBwZXIgPSB0bztcblx0XHR9XG5cblx0XHR0aGlzLmNvbnRyb2xsZXIub25GaWx0ZXJVcGRhdGVkKCB0aGlzLmdldElkKCkgKTtcblx0fVxuXG5cdHB1YmxpYyBpc1Zpc2libGUoIHJvd0lkOiBzdHJpbmcgKTogYm9vbGVhbiB7XG5cdFx0bGV0IHJvd2RhdGEgPSB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpWyByb3dJZCBdLmRhdGE7XG5cblx0XHRpZiAoIHJvd2RhdGEuaGFzT3duUHJvcGVydHkoIHRoaXMuZmlsdGVySWQgKSAmJiByb3dkYXRhWyB0aGlzLmZpbHRlcklkIF0udmFsdWVzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdGZvciAoIGxldCB2YWx1ZSBvZiByb3dkYXRhWyB0aGlzLmZpbHRlcklkIF0udmFsdWVzICkge1xuXHRcdFx0XHRpZiAoIHZhbHVlID49IHRoaXMuZmlsdGVyVmFsdWVMb3dlciAmJiB2YWx1ZSA8PSB0aGlzLmZpbHRlclZhbHVlVXBwZXIgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHJldHVybiBzdXBlci5pc1Zpc2libGUoIHJvd0lkICk7XG5cdH1cblxufVxuIiwiaW1wb3J0IHsgRmlsdGVyIH0gZnJvbSBcIi4vRmlsdGVyXCI7XG5pbXBvcnQgeyBJZFRleHRQYWlyIH0gZnJvbSBcInNlbGVjdDJcIjtcblxuZGVjbGFyZSBsZXQgbXc6IGFueTtcblxuZXhwb3J0IGNsYXNzIFZhbHVlRmlsdGVyIGV4dGVuZHMgRmlsdGVyIHtcblxuXHRwcml2YXRlIHZhbHVlczogYW55ID0ge307XG5cdHByaXZhdGUgdmlzaWJsZVZhbHVlczogc3RyaW5nW10gPSBbXTtcblxuXHRwcml2YXRlIF91c2VPciA9IHRydWU7XG5cblx0cHVibGljIGluaXQoKSB7XG5cdFx0dGhpcy52YWx1ZXMgPSB0aGlzLmdldFNvcnRlZFZhbHVlcygpO1xuXHRcdHRoaXMuYnVpbGRDb250cm9sKCk7XG5cdH1cblxuXHRwdWJsaWMgdXNlT3IoIHVzZU9yOiBib29sZWFuICkge1xuXHRcdHRoaXMuX3VzZU9yID0gdXNlT3I7XG5cdFx0dGhpcy5jb250cm9sbGVyLm9uRmlsdGVyVXBkYXRlZCggdGhpcy5nZXRJZCgpICk7XG5cdH1cblxuXHRwcml2YXRlIGdldFNvcnRlZFZhbHVlcygpOiBhbnkge1xuXG5cdFx0LyoqIE1hcCBvZiB2YWx1ZSA9PiBsYWJlbCBkaXN0aW5jdCB2YWx1ZXMgKi9cblx0XHRsZXQgZGlzdGluY3RWYWx1ZXM6IGFueSA9IHt9O1xuXHRcdC8qKiBNYXAgb2YgdmFsdWUgPT4gc29ydCB2YWx1ZSBkaXN0aW5jdCB2YWx1ZXMgKi9cblx0XHRsZXQgZGlzdGluY3RTb3J0VmFsdWVzOiBhbnkgPSB7fTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAndmFsdWVzJyApICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5vcHRpb25zWyAndmFsdWVzJyBdLm1hcChcblx0XHRcdFx0KCBpdGVtOiBzdHJpbmcgKSA9PiB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdHByaW50b3V0VmFsdWU6IGl0ZW0sXG5cdFx0XHRcdFx0XHRmb3JtYXR0ZWRWYWx1ZTogaXRlbVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblx0XHRcdCk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gYnVpbGQgZmlsdGVyIHZhbHVlcyBmcm9tIGF2YWlsYWJsZSB2YWx1ZXMgaW4gcmVzdWx0IHNldFxuXHRcdFx0bGV0IGRhdGEgPSB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpO1xuXHRcdFx0bGV0IHNvcnRlZEVudHJpZXM6IGFueVtdID0gW107XG5cdFx0XHRmb3IgKCBsZXQgaWQgaW4gZGF0YSApIHtcblxuXHRcdFx0XHRsZXQgcHJpbnRvdXRWYWx1ZXM6IGFueSA9IGRhdGFbIGlkIF1bICdwcmludG91dHMnIF1bIHRoaXMucHJpbnRyZXF1ZXN0SWQgXVsgJ3ZhbHVlcycgXTtcblx0XHRcdFx0bGV0IHByaW50b3V0Rm9ybWF0dGVkVmFsdWVzID0gZGF0YVsgaWQgXVsgJ3ByaW50b3V0cycgXVsgdGhpcy5wcmludHJlcXVlc3RJZCBdWyAnZm9ybWF0dGVkIHZhbHVlcycgXTtcblx0XHRcdFx0bGV0IHByaW50b3V0U29ydFZhbHVlczogYW55ID0gZGF0YVsgaWQgXVsgJ3ByaW50b3V0cycgXVsgdGhpcy5wcmludHJlcXVlc3RJZCBdWyAnc29ydCB2YWx1ZXMnIF07XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgaW4gcHJpbnRvdXRWYWx1ZXMgKSB7XG5cdFx0XHRcdFx0bGV0IHByaW50b3V0Rm9ybWF0dGVkVmFsdWUgPSBwcmludG91dEZvcm1hdHRlZFZhbHVlc1sgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCBwcmludG91dEZvcm1hdHRlZFZhbHVlLmluZGV4T2YoICc8YScgKSA+IC0xICkge1xuXHRcdFx0XHRcdFx0cHJpbnRvdXRGb3JtYXR0ZWRWYWx1ZSA9IC88YS4qPiguKj8pPFxcL2E+Ly5leGVjKCBwcmludG91dEZvcm1hdHRlZFZhbHVlIClbIDEgXTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRkaXN0aW5jdFZhbHVlc1sgcHJpbnRvdXRWYWx1ZXNbIGkgXSBdID0gcHJpbnRvdXRGb3JtYXR0ZWRWYWx1ZTtcblx0XHRcdFx0XHRkaXN0aW5jdFNvcnRWYWx1ZXNbIHByaW50b3V0VmFsdWVzWyBpIF0gXSA9IHByaW50b3V0U29ydFZhbHVlc1sgaSBdO1xuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggbGV0IHByaW50b3V0VmFsdWUgaW4gZGlzdGluY3RTb3J0VmFsdWVzICkge1xuXHRcdFx0XHRzb3J0ZWRFbnRyaWVzLnB1c2goIHtcblx0XHRcdFx0XHRwcmludG91dFZhbHVlOiBwcmludG91dFZhbHVlLFxuXHRcdFx0XHRcdHNvcnRWYWx1ZTogZGlzdGluY3RTb3J0VmFsdWVzWyBwcmludG91dFZhbHVlIF0sXG5cdFx0XHRcdFx0Zm9ybWF0dGVkVmFsdWU6IGRpc3RpbmN0VmFsdWVzWyBwcmludG91dFZhbHVlIF1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXG5cdFx0XHRzb3J0ZWRFbnRyaWVzLnNvcnQoXG5cdFx0XHRcdCggYTogYW55LCBiOiBhbnkgKSA9PiB7XG5cdFx0XHRcdFx0cmV0dXJuIGEuc29ydFZhbHVlLmxvY2FsZUNvbXBhcmUoIGIuc29ydFZhbHVlICk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdHJldHVybiBzb3J0ZWRFbnRyaWVzO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRwcml2YXRlIGJ1aWxkQ29udHJvbCgpIHtcblxuXHRcdGxldCBmaWx0ZXJjb250cm9scyA9IHRoaXMuYnVpbGRFbXB0eUNvbnRyb2woKTtcblxuXHRcdGZpbHRlcmNvbnRyb2xzID0gdGhpcy5hZGRDb250cm9sRm9yU3dpdGNoZXMoIGZpbHRlcmNvbnRyb2xzICk7XG5cblx0XHRsZXQgbWF4Q2hlY2tib3hlcyA9IHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ21heCBjaGVja2JveGVzJyApID8gdGhpcy5vcHRpb25zWyAnbWF4IGNoZWNrYm94ZXMnIF0gOiA1O1xuXG5cdFx0aWYgKCB0aGlzLnZhbHVlcy5sZW5ndGggPiBtYXhDaGVja2JveGVzICkge1xuXHRcdFx0ZmlsdGVyY29udHJvbHMuYXBwZW5kKCB0aGlzLmdldFNlbGVjdGVkMkNvbnRyb2woKSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmaWx0ZXJjb250cm9scy5hcHBlbmQoIHRoaXMuZ2V0Q2hlY2tib3hlc0NvbnRyb2woKSApO1xuXHRcdH1cblxuXHR9XG5cblx0cHJpdmF0ZSBnZXRDaGVja2JveGVzQ29udHJvbCgpIHtcblxuXHRcdGxldCBjaGVja2JveGVzID0gJCggJzxkaXYgY2xhc3M9XCJmaWx0ZXJlZC12YWx1ZS1jaGVja2JveGVzXCIgc3R5bGU9XCJ3aWR0aDogMTAwJTtcIj4nICk7XG5cblx0XHQvLyBpbnNlcnQgb3B0aW9ucyAoY2hlY2tib3hlcyBhbmQgbGFiZWxzKVxuXHRcdGZvciAoIGxldCB2YWx1ZSBvZiB0aGlzLnZhbHVlcyApIHtcblx0XHRcdGNoZWNrYm94ZXMuYXBwZW5kKCBgPGRpdiBjbGFzcz1cImZpbHRlcmVkLXZhbHVlLW9wdGlvblwiPjxsYWJlbD48aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgdmFsdWU9XCIke3ZhbHVlLnByaW50b3V0VmFsdWV9XCIgPjxkaXYgY2xhc3M9XCJmaWx0ZXJlZC12YWx1ZS1vcHRpb24tbGFiZWxcIj4ke3ZhbHVlLmZvcm1hdHRlZFZhbHVlIHx8IHZhbHVlLnByaW50b3V0VmFsdWV9PC9kaXY+PC9sYWJlbD48L2Rpdj5gICk7XG5cdFx0fVxuXG5cdFx0Ly8gYXR0YWNoIGV2ZW50IGhhbmRsZXJcblx0XHRjaGVja2JveGVzXG5cdFx0Lm9uKCAnY2hhbmdlJywgJzpjaGVja2JveCcsICggZXZlbnRPYmplY3Q6IEpRdWVyeUV2ZW50T2JqZWN0ICkgPT4ge1xuXHRcdFx0bGV0IGNoZWNrYm94RWxlbWVudCA9IDxIVE1MSW5wdXRFbGVtZW50PiBldmVudE9iamVjdC5jdXJyZW50VGFyZ2V0O1xuXHRcdFx0dGhpcy5vbkZpbHRlclVwZGF0ZWQoIGNoZWNrYm94RWxlbWVudC52YWx1ZSwgY2hlY2tib3hFbGVtZW50LmNoZWNrZWQgKTtcblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gY2hlY2tib3hlcztcblx0fVxuXG5cdHByaXZhdGUgZ2V0U2VsZWN0ZWQyQ29udHJvbCgpIHtcblxuXHRcdGxldCBzZWxlY3QgPSAkKCAnPHNlbGVjdCBjbGFzcz1cImZpbHRlcmVkLXZhbHVlLXNlbGVjdFwiIHN0eWxlPVwid2lkdGg6IDEwMCU7XCI+JyApO1xuXG5cdFx0bGV0IGRhdGE6IElkVGV4dFBhaXJbXSA9IFtdO1xuXG5cdFx0Ly8gaW5zZXJ0IG9wdGlvbnMgKGNoZWNrYm94ZXMgYW5kIGxhYmVscykgYW5kIGF0dGFjaCBldmVudCBoYW5kbGVyc1xuXHRcdGZvciAoIGxldCB2YWx1ZSBvZiB0aGlzLnZhbHVlcyApIHtcblx0XHRcdC8vIFRyeSB0byBnZXQgbGFiZWwsIGlmIG5vdCBmYWxsIGJhY2sgdG8gdmFsdWUgaWRcblx0XHRcdGxldCBsYWJlbCA9IHZhbHVlLmZvcm1hdHRlZFZhbHVlIHx8IHZhbHVlLnByaW50b3V0VmFsdWU7XG5cdFx0XHRkYXRhLnB1c2goIHsgaWQ6IHZhbHVlLnByaW50b3V0VmFsdWUsIHRleHQ6IGxhYmVsIH0gKTtcblxuXHRcdH1cblxuXHRcdG13LmxvYWRlci51c2luZyggJ2V4dC5zcmYuZmlsdGVyZWQudmFsdWUtZmlsdGVyLnNlbGVjdCcgKS50aGVuKCAoKSA9PiB7XG5cblx0XHRcdHNlbGVjdC5zZWxlY3QyKCB7XG5cdFx0XHRcdG11bHRpcGxlOiB0cnVlLFxuXHRcdFx0XHRwbGFjZWhvbGRlcjogbXcubWVzc2FnZSggJ3NyZi1maWx0ZXJlZC12YWx1ZS1maWx0ZXItcGxhY2Vob2xkZXInICkudGV4dCgpLFxuXHRcdFx0XHRkYXRhOiBkYXRhXG5cdFx0XHR9ICk7XG5cblx0XHRcdHNlbGVjdC5vbiggXCJzZWxlY3QyOnNlbGVjdFwiLCAoIGU6IGFueSApID0+IHtcblx0XHRcdFx0dGhpcy5vbkZpbHRlclVwZGF0ZWQoIGUucGFyYW1zLmRhdGEuaWQsIHRydWUgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0c2VsZWN0Lm9uKCBcInNlbGVjdDI6dW5zZWxlY3RcIiwgKCBlOiBhbnkgKSA9PiB7XG5cdFx0XHRcdHRoaXMub25GaWx0ZXJVcGRhdGVkKCBlLnBhcmFtcy5kYXRhLmlkLCBmYWxzZSApO1xuXHRcdFx0fSApO1xuXG5cdFx0fSApO1xuXG5cdFx0cmV0dXJuIHNlbGVjdDtcblx0fVxuXG5cdHByaXZhdGUgYWRkQ29udHJvbEZvclN3aXRjaGVzKCBmaWx0ZXJjb250cm9sczogSlF1ZXJ5ICk6IEpRdWVyeSB7XG5cdFx0Ly8gaW5zZXJ0IHN3aXRjaGVzXG5cdFx0bGV0IHN3aXRjaGVzID0gdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAnc3dpdGNoZXMnICkgPyB0aGlzLm9wdGlvbnNbICdzd2l0Y2hlcycgXSA6IHVuZGVmaW5lZDtcblxuXHRcdGlmICggc3dpdGNoZXMgIT09IHVuZGVmaW5lZCAmJiAkLmluQXJyYXkoICdhbmQgb3InLCBzd2l0Y2hlcyApID49IDAgKSB7XG5cblx0XHRcdGxldCBzd2l0Y2hDb250cm9scyA9ICQoICc8ZGl2IGNsYXNzPVwiZmlsdGVyZWQtdmFsdWUtc3dpdGNoZXNcIj4nICk7XG5cblx0XHRcdGxldCBhbmRvckNvbnRyb2wgPSAkKCAnPGRpdiBjbGFzcz1cImZpbHRlcmVkLXZhbHVlLWFuZG9yXCI+JyApO1xuXG5cdFx0XHRsZXQgb3JDb250cm9sID0gdGhpcy5nZXRSYWRpb0NvbnRyb2woICdvcicsIHRydWUgKTtcblx0XHRcdGxldCBhbmRDb250cm9sID0gdGhpcy5nZXRSYWRpb0NvbnRyb2woICdhbmQnICk7XG5cblx0XHRcdGFuZG9yQ29udHJvbFxuXHRcdFx0LmFwcGVuZCggb3JDb250cm9sIClcblx0XHRcdC5hcHBlbmQoIGFuZENvbnRyb2wgKVxuXHRcdFx0LmFwcGVuZFRvKCBzd2l0Y2hDb250cm9scyApO1xuXG5cdFx0XHRhbmRvckNvbnRyb2xcblx0XHRcdC5maW5kKCAnaW5wdXQnIClcblx0XHRcdC5vbiggJ2NoYW5nZScsIHVuZGVmaW5lZCwgeyAnZmlsdGVyJzogdGhpcyB9LCAoIGV2ZW50T2JqZWN0OiBKUXVlcnlFdmVudE9iamVjdCApID0+XG5cdFx0XHRcdGV2ZW50T2JqZWN0LmRhdGEuZmlsdGVyLnVzZU9yKCBldmVudE9iamVjdC50YXJnZXQuZ2V0QXR0cmlidXRlKCAndmFsdWUnICkgPT09ICdvcicgKVxuXHRcdFx0KTtcblxuXG5cdFx0XHRmaWx0ZXJjb250cm9scy5hcHBlbmQoIHN3aXRjaENvbnRyb2xzICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZpbHRlcmNvbnRyb2xzO1xuXHR9XG5cblx0cHJpdmF0ZSBnZXRSYWRpb0NvbnRyb2woIHR5cGU6IHN0cmluZywgaXNDaGVja2VkOiBib29sZWFuID0gZmFsc2UgKSB7XG5cblx0XHRsZXQgY2hlY2tlZEF0dHIgPSBpc0NoZWNrZWQ/J2NoZWNrZWQnOicnO1xuXHRcdGxldCBsYWJlbFRleHQgPSBtdy5tZXNzYWdlKCAnc3JmLWZpbHRlcmVkLXZhbHVlLWZpbHRlci0nICsgdHlwZSApLnRleHQoKTtcblxuXHRcdGxldCBjb250cm9sVGV4dCA9XG5cdFx0XHRgPGxhYmVsIGZvcj1cImZpbHRlcmVkLXZhbHVlLSR7dHlwZX0tJHt0aGlzLnByaW50cmVxdWVzdElkfVwiPmAgK1xuXHRcdFx0YDxpbnB1dCB0eXBlPVwicmFkaW9cIiBuYW1lPVwiZmlsdGVyZWQtdmFsdWUtJHt0aGlzLnByaW50cmVxdWVzdElkfVwiICBjbGFzcz1cImZpbHRlcmVkLXZhbHVlLSR7dHlwZX1cIiBpZD1cImZpbHRlcmVkLXZhbHVlLSR7dHlwZX0tJHt0aGlzLnByaW50cmVxdWVzdElkfVwiIHZhbHVlPVwiJHt0eXBlfVwiICR7Y2hlY2tlZEF0dHJ9PmAgK1xuXHRcdFx0YCR7bGFiZWxUZXh0fTwvbGFiZWw+YDtcblxuXHRcdHJldHVybiAkKCBjb250cm9sVGV4dCApO1xuXHR9XG5cblx0cHVibGljIGlzVmlzaWJsZSggcm93SWQ6IHN0cmluZyApOiBib29sZWFuIHtcblxuXHRcdGlmICggdGhpcy52aXNpYmxlVmFsdWVzLmxlbmd0aCA9PT0gMCApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdGxldCB2YWx1ZXM6IHN0cmluZ1tdID0gdGhpcy5jb250cm9sbGVyLmdldERhdGEoKVsgcm93SWQgXS5wcmludG91dHNbIHRoaXMucHJpbnRyZXF1ZXN0SWQgXS52YWx1ZXM7XG5cblx0XHRpZiAoIHZhbHVlcy5sZW5ndGggPT09IDAgKSB7XG5cdFx0XHRyZXR1cm4gc3VwZXIuaXNWaXNpYmxlKCByb3dJZCApO1xuXHRcdH1cblxuXG5cdFx0aWYgKCB0aGlzLl91c2VPciApIHtcblx0XHRcdGZvciAoIGxldCBleHBlY3RlZFZhbHVlIG9mIHRoaXMudmlzaWJsZVZhbHVlcyApIHtcblx0XHRcdFx0aWYgKCB2YWx1ZXMuaW5kZXhPZiggZXhwZWN0ZWRWYWx1ZSApID49IDAgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yICggbGV0IGV4cGVjdGVkVmFsdWUgb2YgdGhpcy52aXNpYmxlVmFsdWVzICkge1xuXHRcdFx0XHRpZiAoIHZhbHVlcy5pbmRleE9mKCBleHBlY3RlZFZhbHVlICkgPCAwICkge1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXHR9XG5cblx0cHVibGljIG9uRmlsdGVyVXBkYXRlZCggdmFsdWU6IHN0cmluZywgaXNDaGVja2VkOiBib29sZWFuICkge1xuXHRcdGxldCBpbmRleCA9IHRoaXMudmlzaWJsZVZhbHVlcy5pbmRleE9mKCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBpc0NoZWNrZWQgJiYgaW5kZXggPT09IC0xICkge1xuXHRcdFx0dGhpcy52aXNpYmxlVmFsdWVzLnB1c2goIHZhbHVlICk7XG5cdFx0fSBlbHNlIGlmICggIWlzQ2hlY2tlZCAmJiBpbmRleCA+PSAwICkge1xuXHRcdFx0dGhpcy52aXNpYmxlVmFsdWVzLnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHR9XG5cblx0XHR0aGlzLmNvbnRyb2xsZXIub25GaWx0ZXJVcGRhdGVkKCB0aGlzLmdldElkKCkgKTtcblx0fVxufVxuIiwiaW1wb3J0IHsgT3B0aW9ucyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgQ29udHJvbGxlciB9IGZyb20gXCIuL0NvbnRyb2xsZXJcIjtcbmltcG9ydCB7IFZpZXdTZWxlY3RvciB9IGZyb20gXCIuL1ZpZXdTZWxlY3RvclwiO1xuaW1wb3J0IHsgVmlldyB9IGZyb20gXCIuL1ZpZXcvVmlld1wiO1xuaW1wb3J0IHsgTGlzdFZpZXcgfSBmcm9tIFwiLi9WaWV3L0xpc3RWaWV3XCI7XG5pbXBvcnQgeyBUYWJsZVZpZXcgfSBmcm9tIFwiLi9WaWV3L1RhYmxlVmlld1wiO1xuaW1wb3J0IHsgTWFwVmlldyB9IGZyb20gXCIuL1ZpZXcvTWFwVmlld1wiO1xuaW1wb3J0IHsgQ2FsZW5kYXJWaWV3IH0gZnJvbSBcIi4vVmlldy9DYWxlbmRhclZpZXdcIjtcbmltcG9ydCB7IEZpbHRlciB9IGZyb20gXCIuL0ZpbHRlci9GaWx0ZXJcIjtcbmltcG9ydCB7IFZhbHVlRmlsdGVyIH0gZnJvbSBcIi4vRmlsdGVyL1ZhbHVlRmlsdGVyXCI7XG5pbXBvcnQgeyBEaXN0YW5jZUZpbHRlciB9IGZyb20gXCIuL0ZpbHRlci9EaXN0YW5jZUZpbHRlclwiO1xuaW1wb3J0IHsgTnVtYmVyRmlsdGVyIH0gZnJvbSBcIi4vRmlsdGVyL051bWJlckZpbHRlclwiO1xuXG4vKipcbiAqIENlbnRyYWwgRmlsdGVyZWQgY2xhc3NcbiAqXG4gKiBGYWN0b3J5IHRvIHNldHVwIGV2ZXJ5aHRpbmcgZWxzZVxuICovXG5leHBvcnQgY2xhc3MgRmlsdGVyZWQge1xuXG5cdHByaXZhdGUgY29uZmlnOiBhbnk7XG5cdHByaXZhdGUgdGFyZ2V0OiBKUXVlcnk7XG5cblx0cHJpdmF0ZSB2aWV3VHlwZXM6IHsgW2tleTogc3RyaW5nXTogbmV3KCBpZDogc3RyaW5nLCB0YXJnZXQ6IEpRdWVyeSwgY29udHJvbGxlcjogQ29udHJvbGxlciwgb3B0aW9ucz86IGFueSApID0+IFZpZXcgfSA9IHtcblx0XHR0YWJsZTogVGFibGVWaWV3LFxuXHRcdGxpc3Q6IExpc3RWaWV3LFxuXHRcdG1hcDogTWFwVmlldyxcblx0XHRjYWxlbmRhcjogQ2FsZW5kYXJWaWV3XG5cdH07XG5cblx0cHJpdmF0ZSBmaWx0ZXJUeXBlczogeyBba2V5OiBzdHJpbmddOiBuZXcoIGlkOiBzdHJpbmcsIHRhcmdldDogSlF1ZXJ5LCBwcmludHJlcXVlc3RJZDogc3RyaW5nLCBjb250cm9sbGVyOiBDb250cm9sbGVyLCBvcHRpb25zPzogT3B0aW9ucyApID0+IEZpbHRlciB9ID0ge1xuXHRcdHZhbHVlOiBWYWx1ZUZpbHRlcixcblx0XHRkaXN0YW5jZTogRGlzdGFuY2VGaWx0ZXIsXG5cdFx0bnVtYmVyOiBOdW1iZXJGaWx0ZXJcblx0fTtcblxuXHQvKipcblx0ICpcblx0ICogQHBhcmFtIHRhcmdldFxuXHQgKiBAcGFyYW0gY29uZmlnXG5cdCAqL1xuXHRwdWJsaWMgY29uc3RydWN0b3IoIHRhcmdldDogSlF1ZXJ5LCBjb25maWc6IGFueSApIHtcblx0XHR0aGlzLmNvbmZpZyA9IGNvbmZpZztcblx0XHR0aGlzLnRhcmdldCA9IHRhcmdldDtcblx0fVxuXG5cdHB1YmxpYyBydW4oKSB7XG5cblx0XHRsZXQgY29udHJvbGxlciA9IG5ldyBDb250cm9sbGVyKCB0aGlzLnRhcmdldCwgdGhpcy5jb25maWcuZGF0YSwgdGhpcy5jb25maWcucHJpbnRyZXF1ZXN0cyApO1xuXG5cdFx0dGhpcy5hdHRhY2hGaWx0ZXJzKCBjb250cm9sbGVyLCB0aGlzLnRhcmdldC5jaGlsZHJlbiggJ2Rpdi5maWx0ZXJlZC1maWx0ZXJzJyApICk7XG5cdFx0dGhpcy5hdHRhY2hWaWV3U2VsZWN0b3IoIGNvbnRyb2xsZXIsIHRoaXMudGFyZ2V0LmZpbmQoICdkaXYuZmlsdGVyZWQtdmlld3Mtc2VsZWN0b3JzLWNvbnRhaW5lcicgKSApO1xuXHRcdHRoaXMuYXR0YWNoVmlld3MoIGNvbnRyb2xsZXIsIHRoaXMudGFyZ2V0LmZpbmQoICdkaXYuZmlsdGVyZWQtdmlld3MtY29udGFpbmVyJyApICk7XG5cblx0XHQvLyBsaWZ0LW9mZlxuXHRcdGNvbnRyb2xsZXIuc2hvdygpO1xuXG5cdH1cblxuXHRwcml2YXRlIGF0dGFjaEZpbHRlcnMoIGNvbnRyb2xsZXI6IENvbnRyb2xsZXIsIGZpbHRlcnNDb250YWluZXI6IEpRdWVyeSApIHtcblxuXHRcdGZvciAoIGxldCBwcklkIGluIHRoaXMuY29uZmlnLnByaW50cmVxdWVzdHMgKSB7XG5cblx0XHRcdGxldCBwciA9IHRoaXMuY29uZmlnLnByaW50cmVxdWVzdHNbIHBySWQgXTtcblxuXHRcdFx0aWYgKCBwci5oYXNPd25Qcm9wZXJ0eSggJ2ZpbHRlcnMnICkgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGZpbHRlcmlkIGluIHByLmZpbHRlcnMgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHByLmZpbHRlcnMuaGFzT3duUHJvcGVydHkoIGZpbHRlcmlkICkgJiZcblx0XHRcdFx0XHRcdHByLmZpbHRlcnNbIGZpbHRlcmlkIF0uaGFzT3duUHJvcGVydHkoICd0eXBlJyApICYmXG5cdFx0XHRcdFx0XHR0aGlzLmZpbHRlclR5cGVzLmhhc093blByb3BlcnR5KCBwci5maWx0ZXJzWyBmaWx0ZXJpZCBdLnR5cGUgKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gIHRhcmdldDogSlF1ZXJ5LCBwcmludHJlcXVlc3Q6IHN0cmluZyxcblx0XHRcdFx0XHRcdC8vIGNvbnRyb2xsZXI6IENvbnRyb2xsZXIsIG9wdGlvbnM/OiBPcHRpb25zXG5cdFx0XHRcdFx0XHRsZXQgZmlsdGVyOiBGaWx0ZXIgPSBuZXcgdGhpcy5maWx0ZXJUeXBlc1sgcHIuZmlsdGVyc1sgZmlsdGVyaWQgXS50eXBlIF0oIGZpbHRlcmlkLCBmaWx0ZXJzQ29udGFpbmVyLmNoaWxkcmVuKCAnIycgKyBmaWx0ZXJpZCApLCBwcklkLCBjb250cm9sbGVyLCBwci5maWx0ZXJzWyBmaWx0ZXJpZCBdICk7XG5cblx0XHRcdFx0XHRcdGNvbnRyb2xsZXIuYXR0YWNoRmlsdGVyKCBmaWx0ZXIgKTtcblxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBhdHRhY2hWaWV3U2VsZWN0b3IoIGNvbnRyb2xsZXI6IENvbnRyb2xsZXIsIHZpZXdTZWxlY3RvckNvbnRhaW5lcjogSlF1ZXJ5ICkge1xuXHRcdGxldCB2aWV3U2VsZWN0b3IgPSBuZXcgVmlld1NlbGVjdG9yKCB2aWV3U2VsZWN0b3JDb250YWluZXIsIE9iamVjdC5rZXlzKCB0aGlzLmNvbmZpZy52aWV3cyApLCBjb250cm9sbGVyICk7XG5cdFx0dmlld1NlbGVjdG9yLmluaXQoKTtcblx0fVxuXG5cdHByaXZhdGUgYXR0YWNoVmlld3MoIGNvbnRyb2xsZXI6IENvbnRyb2xsZXIsIHZpZXdzQ29udGFpbmVyOiBKUXVlcnkgKSB7XG5cblx0XHQvLyBhdHRhY2ggdmlld3Ncblx0XHRmb3IgKCBsZXQgdmlld2lkIGluIHRoaXMuY29uZmlnLnZpZXdzICkge1xuXG5cdFx0XHRsZXQgdmlld3R5cGUgPSB0aGlzLmNvbmZpZy52aWV3c1sgdmlld2lkIF1bICd0eXBlJyBdO1xuXHRcdFx0bGV0IHZpZXdIYW5kbGVyQ2xhc3MgPSB0aGlzLnZpZXdUeXBlcy5oYXNPd25Qcm9wZXJ0eSggdmlld3R5cGUgKSA/IHRoaXMudmlld1R5cGVzWyB2aWV3dHlwZSBdIDogVmlldztcblxuXHRcdFx0bGV0IHZpZXc6IFZpZXcgPSBuZXcgdmlld0hhbmRsZXJDbGFzcyggdmlld2lkLCB2aWV3c0NvbnRhaW5lci5jaGlsZHJlbiggJyMnICsgdmlld2lkICksIGNvbnRyb2xsZXIsIHRoaXMuY29uZmlnLnZpZXdzWyB2aWV3aWQgXSApO1xuXG5cdFx0XHR2aWV3LmluaXQoKTtcblxuXHRcdFx0Y29udHJvbGxlci5hdHRhY2hWaWV3KCB2aWV3aWQsIHZpZXcgKTtcblxuXHRcdH1cblx0fVxufVxuIiwiaW1wb3J0IHsgVmlldyB9IGZyb20gXCIuL1ZpZXdcIjtcbmRlY2xhcmUgbGV0IG13OiBhbnk7XG5cbmV4cG9ydCBjbGFzcyBDYWxlbmRhclZpZXcgZXh0ZW5kcyBWaWV3IHtcblxuXHRwcml2YXRlIGdldEkxOE4oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdG1vbnRoTmFtZXM6IFsgbXcubXNnKCAnamFudWFyeScgKSwgbXcubXNnKCAnZmVicnVhcnknICksIG13Lm1zZyggJ21hcmNoJyApLFxuXHRcdFx0XHRtdy5tc2coICdhcHJpbCcgKSwgbXcubXNnKCAnbWF5X2xvbmcnICksIG13Lm1zZyggJ2p1bmUnICksXG5cdFx0XHRcdG13Lm1zZyggJ2p1bHknICksIG13Lm1zZyggJ2F1Z3VzdCcgKSwgbXcubXNnKCAnc2VwdGVtYmVyJyApLFxuXHRcdFx0XHRtdy5tc2coICdvY3RvYmVyJyApLCBtdy5tc2coICdub3ZlbWJlcicgKSwgbXcubXNnKCAnZGVjZW1iZXInIClcblx0XHRcdF0sXG5cdFx0XHRtb250aE5hbWVzU2hvcnQ6IFsgbXcubXNnKCAnamFuJyApLCBtdy5tc2coICdmZWInICksIG13Lm1zZyggJ21hcicgKSxcblx0XHRcdFx0bXcubXNnKCAnYXByJyApLCBtdy5tc2coICdtYXknICksIG13Lm1zZyggJ2p1bicgKSxcblx0XHRcdFx0bXcubXNnKCAnanVsJyApLCBtdy5tc2coICdhdWcnICksIG13Lm1zZyggJ3NlcCcgKSxcblx0XHRcdFx0bXcubXNnKCAnb2N0JyApLCBtdy5tc2coICdub3YnICksIG13Lm1zZyggJ2RlYycgKVxuXHRcdFx0XSxcblx0XHRcdGRheU5hbWVzOiBbIG13Lm1zZyggJ3N1bmRheScgKSwgbXcubXNnKCAnbW9uZGF5JyApLCBtdy5tc2coICd0dWVzZGF5JyApLFxuXHRcdFx0XHRtdy5tc2coICd3ZWRuZXNkYXknICksIG13Lm1zZyggJ3RodXJzZGF5JyApLCBtdy5tc2coICdmcmlkYXknICksIG13Lm1zZyggJ3NhdHVyZGF5JyApXG5cdFx0XHRdLFxuXHRcdFx0ZGF5TmFtZXNTaG9ydDogWyBtdy5tc2coICdzdW4nICksIG13Lm1zZyggJ21vbicgKSwgbXcubXNnKCAndHVlJyApLFxuXHRcdFx0XHRtdy5tc2coICd3ZWQnICksIG13Lm1zZyggJ3RodScgKSwgbXcubXNnKCAnZnJpJyApLCBtdy5tc2coICdzYXQnIClcblx0XHRcdF0sXG5cdFx0XHRidXR0b25UZXh0OiB7XG5cdFx0XHRcdHRvZGF5OiBtdy5tc2coICdzcmYtdWktZXZlbnRjYWxlbmRhci1sYWJlbC10b2RheScgKSxcblx0XHRcdFx0bW9udGg6IG13Lm1zZyggJ3NyZi11aS1ldmVudGNhbGVuZGFyLWxhYmVsLW1vbnRoJyApLFxuXHRcdFx0XHR3ZWVrOiBtdy5tc2coICdzcmYtdWktZXZlbnRjYWxlbmRhci1sYWJlbC13ZWVrJyApLFxuXHRcdFx0XHRkYXk6IG13Lm1zZyggJ3NyZi11aS1ldmVudGNhbGVuZGFyLWxhYmVsLWRheScgKVxuXHRcdFx0fVxuXHRcdFx0LFxuXHRcdFx0YWxsRGF5VGV4dDogbXcubXNnKCAnc3JmLXVpLWV2ZW50Y2FsZW5kYXItbGFiZWwtYWxsZGF5JyApLFxuXHRcdFx0dGltZUZvcm1hdDoge1xuXHRcdFx0XHQnJzogbXcubXNnKCAnc3JmLXVpLWV2ZW50Y2FsZW5kYXItZm9ybWF0LXRpbWUnICksXG5cdFx0XHRcdGFnZW5kYTogbXcubXNnKCAnc3JmLXVpLWV2ZW50Y2FsZW5kYXItZm9ybWF0LXRpbWUtYWdlbmRhJyApXG5cdFx0XHR9XG5cdFx0XHQsXG5cdFx0XHRheGlzRm9ybWF0OiBtdy5tc2coICdzcmYtdWktZXZlbnRjYWxlbmRhci1mb3JtYXQtYXhpcycgKSxcblx0XHRcdHRpdGxlRm9ybWF0OiB7XG5cdFx0XHRcdG1vbnRoOiBtdy5tc2coICdzcmYtdWktZXZlbnRjYWxlbmRhci1mb3JtYXQtdGl0bGUtbW9udGgnICksXG5cdFx0XHRcdHdlZWs6IG13Lm1zZyggJ3NyZi11aS1ldmVudGNhbGVuZGFyLWZvcm1hdC10aXRsZS13ZWVrJyApLFxuXHRcdFx0XHRkYXk6IG13Lm1zZyggJ3NyZi11aS1ldmVudGNhbGVuZGFyLWZvcm1hdC10aXRsZS1kYXknIClcblx0XHRcdH1cblx0XHRcdCxcblx0XHRcdGNvbHVtbkZvcm1hdDoge1xuXHRcdFx0XHRtb250aDogbXcubXNnKCAnc3JmLXVpLWV2ZW50Y2FsZW5kYXItZm9ybWF0LWNvbHVtbi1tb250aCcgKSxcblx0XHRcdFx0d2VlazogbXcubXNnKCAnc3JmLXVpLWV2ZW50Y2FsZW5kYXItZm9ybWF0LWNvbHVtbi13ZWVrJyApLFxuXHRcdFx0XHRkYXk6IG13Lm1zZyggJ3NyZi11aS1ldmVudGNhbGVuZGFyLWZvcm1hdC1jb2x1bW4tZGF5JyApXG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cdHB1YmxpYyBpbml0KCkge1xuXG5cdFx0bGV0IF9pMThuID0gdGhpcy5nZXRJMThOKCk7XG5cblx0XHQvLyBpbml0aWFsaXplIHRoZSBjYWxlbmRhclxuXHRcdHRoaXMudGFyZ2V0LmZ1bGxDYWxlbmRhcigge1xuXG5cdFx0XHRmaXJzdERheTogdGhpcy5vcHRpb25zLmZpcnN0RGF5LFxuXHRcdFx0aXNSVEw6IHRoaXMub3B0aW9ucy5pc1JUTCxcblx0XHRcdG1vbnRoTmFtZXM6IF9pMThuLm1vbnRoTmFtZXMsXG5cdFx0XHRtb250aE5hbWVzU2hvcnQ6IF9pMThuLm1vbnRoTmFtZXNTaG9ydCxcblx0XHRcdGRheU5hbWVzOiBfaTE4bi5kYXlOYW1lcyxcblx0XHRcdGRheU5hbWVzU2hvcnQ6IF9pMThuLmRheU5hbWVzU2hvcnQsXG5cdFx0XHRidXR0b25UZXh0OiBfaTE4bi5idXR0b25UZXh0LFxuXHRcdFx0YWxsRGF5VGV4dDogX2kxOG4uYWxsRGF5VGV4dCxcblx0XHRcdHRpbWVGb3JtYXQ6IF9pMThuLnRpbWVGb3JtYXQsXG5cdFx0XHR0aXRsZUZvcm1hdDogX2kxOG4udGl0bGVGb3JtYXQsXG5cdFx0XHRjb2x1bW5Gb3JtYXQ6IF9pMThuLmNvbHVtbkZvcm1hdFxuXHRcdH0gKTtcblx0fVxuXG5cdHByaXZhdGUgZ2V0RXZlbnQoIHJvd0lkOiBhbnksIHJvd0RhdGE6IGFueSApIHtcblxuXHRcdGxldCBldmVudGRhdGE6IGFueSA9IHtcblx0XHRcdGlkOiByb3dJZCxcblx0XHRcdHRpdGxlOiByb3dEYXRhWyAndGl0bGUnIF0sXG5cdFx0XHRzdGFydDogcm93RGF0YVsgJ3N0YXJ0JyBdLFxuXHRcdFx0Y2xhc3NOYW1lOiByb3dJZFxuXHRcdH07XG5cblx0XHRpZiAoIHJvd0RhdGEuaGFzT3duUHJvcGVydHkoICdlbmQnICkgKSB7XG5cdFx0XHRldmVudGRhdGFbICdlbmQnIF0gPSByb3dEYXRhWyAnZW5kJyBdO1xuXHRcdH1cblxuXHRcdGlmICggcm93RGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3VybCcgKSApIHtcblx0XHRcdGV2ZW50ZGF0YVsgJ3VybCcgXSA9IHJvd0RhdGFbICd1cmwnIF07XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50ZGF0YTtcblx0fVxuXG5cdHB1YmxpYyBzaG93Um93cyggcm93SWRzOiBzdHJpbmdbXSApOiBhbnkge1xuXG5cdFx0bGV0IGV2ZW50czogYW55W10gPSBbXTtcblxuXHRcdHJvd0lkcy5mb3JFYWNoKCAoIHJvd0lkOiBzdHJpbmcgKSA9PiB7XG5cblx0XHRcdGxldCByb3dEYXRhID0gdGhpcy5jb250cm9sbGVyLmdldERhdGEoKVsgcm93SWQgXS5kYXRhWyB0aGlzLmlkIF07XG5cblx0XHRcdGlmICggcm93RGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3N0YXJ0JyApICkge1xuXHRcdFx0XHRldmVudHMucHVzaCggdGhpcy5nZXRFdmVudCggcm93SWQsIHJvd0RhdGEgKSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMudGFyZ2V0LmZ1bGxDYWxlbmRhciggJ2FkZEV2ZW50U291cmNlJywgZXZlbnRzICk7XG5cdH1cblxuXHRwdWJsaWMgaGlkZVJvd3MoIHJvd0lkczogc3RyaW5nW10gKTogYW55IHtcblx0XHR0aGlzLnRhcmdldC5mdWxsQ2FsZW5kYXIoICdyZW1vdmVFdmVudHMnLCAoIGU6IGFueSApID0+ICggcm93SWRzLmluZGV4T2YoIGUuX2lkICkgPj0gMCApICk7XG5cdH1cblxuXHRwdWJsaWMgc2hvdygpOiBhbnkge1xuXHRcdHN1cGVyLnNob3coKTtcblx0XHR0aGlzLnRhcmdldC5mdWxsQ2FsZW5kYXIoICdyZW5kZXInICk7XG5cdH1cblxuXHRwdWJsaWMgaGlkZSgpOiBhbnkge1xuXHRcdHJldHVybiBzdXBlci5oaWRlKCk7XG5cdH1cblxufVxuIiwiaW1wb3J0IHsgVmlldyB9IGZyb20gXCIuL1ZpZXdcIjtcblxuZXhwb3J0IGNsYXNzIExpc3RWaWV3IGV4dGVuZHMgVmlldyB7XG5cblx0cHJvdGVjdGVkIGdldEl0ZW1DbGFzc05hbWUoKSB7XG5cdFx0cmV0dXJuICcuZmlsdGVyZWQtbGlzdC1pdGVtJztcblx0fVxuXG5cbn1cbiIsIi8vLyA8cmVmZXJlbmNlIHR5cGVzPVwibGVhZmxldFwiIC8+XG5cbmltcG9ydCB7IFZpZXcgfSBmcm9tIFwiLi9WaWV3XCI7XG5pbXBvcnQgeyBPcHRpb25zIH0gZnJvbSBcIi4uLy4uL3R5cGVzXCJcblxuZGVjbGFyZSBsZXQgbXc6IGFueTtcblxuZXhwb3J0IGNsYXNzIE1hcFZpZXcgZXh0ZW5kcyBWaWV3IHtcblxuXHRwcml2YXRlIG1hcDogTC5NYXAgPSB1bmRlZmluZWQ7XG5cdHByaXZhdGUgaWNvbjogeyBba2V5OiBzdHJpbmddOiBMLkljb24gfSA9IHVuZGVmaW5lZDtcblx0cHJpdmF0ZSBtYXJrZXJzOiB7IFtrZXk6IHN0cmluZ106IEwuTWFya2VyW10gfSA9IHVuZGVmaW5lZDtcblx0cHJpdmF0ZSBtYXJrZXJDbHVzdGVyR3JvdXA6IEwuTWFya2VyQ2x1c3Rlckdyb3VwID0gdW5kZWZpbmVkO1xuXHRwcml2YXRlIGJvdW5kczogTC5MYXRMbmdCb3VuZHMgPSB1bmRlZmluZWQ7XG5cdHByaXZhdGUgaW5pdGlhbGl6ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuXHRwcml2YXRlIHpvb206IG51bWJlciA9IC0xO1xuXHRwcml2YXRlIG1pblpvb206IG51bWJlciA9IC0xO1xuXHRwcml2YXRlIG1heFpvb206IG51bWJlciA9IC0xO1xuXG5cdHByaXZhdGUgbGVhZmxldFByb21pc2U6IFByb21pc2U8YW55PiA9IHVuZGVmaW5lZDtcblxuXHRwdWJsaWMgaW5pdCgpOiBQcm9taXNlPGFueT4ge1xuXG5cdFx0bGV0IGRhdGEgPSB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpO1xuXHRcdGxldCBtYXJrZXJzOiB7IFtyb3dJZDogc3RyaW5nXTogTC5NYXJrZXJbXSB9ID0ge307XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ2hlaWdodCcgKSApIHtcblx0XHRcdHRoaXMudGFyZ2V0LmhlaWdodCggdGhpcy5vcHRpb25zLmhlaWdodCApO1xuXHRcdH1cblxuXHRcdHRoaXMubGVhZmxldFByb21pc2UgPSBtdy5sb2FkZXIudXNpbmcoICdleHQuc3JmLmZpbHRlcmVkLm1hcC12aWV3LmxlYWZsZXQnIClcblx0XHQudGhlbiggKCkgPT4ge1xuXG5cdFx0XHRsZXQgYm91bmRzOiBMLkxhdExuZ0JvdW5kcyA9IHVuZGVmaW5lZDtcblx0XHRcdGxldCBkaXNhYmxlQ2x1c3RlcmluZ0F0Wm9vbSA9IHRoaXMuZ2V0Wm9vbUZvclVuY2x1c3RlcmluZygpO1xuXG5cdFx0XHRsZXQgY2x1c3Rlck9wdGlvbnM6IE9wdGlvbnMgPSB7XG5cdFx0XHRcdGFuaW1hdGVBZGRpbmdNYXJrZXJzOiB0cnVlLFxuXHRcdFx0XHRkaXNhYmxlQ2x1c3RlcmluZ0F0Wm9vbTogZGlzYWJsZUNsdXN0ZXJpbmdBdFpvb20sXG5cdFx0XHRcdHNwaWRlcmZ5T25NYXhab29tOiBkaXNhYmxlQ2x1c3RlcmluZ0F0Wm9vbSA9PT0gbnVsbFxuXHRcdFx0fTtcblxuXHRcdFx0Y2x1c3Rlck9wdGlvbnMgPSB0aGlzLmdldE9wdGlvbnMoIFsgJ21heENsdXN0ZXJSYWRpdXMnLCAnem9vbVRvQm91bmRzT25DbGljaycgXSwgY2x1c3Rlck9wdGlvbnMgKTtcblxuXHRcdFx0bGV0IG1hcmtlckNsdXN0ZXJHcm91cDogTC5NYXJrZXJDbHVzdGVyR3JvdXAgPSBMLm1hcmtlckNsdXN0ZXJHcm91cCggY2x1c3Rlck9wdGlvbnMgKTtcblxuXHRcdFx0Zm9yICggbGV0IHJvd0lkIGluIGRhdGEgKSB7XG5cblx0XHRcdFx0aWYgKCBkYXRhWyByb3dJZCBdWyAnZGF0YScgXS5oYXNPd25Qcm9wZXJ0eSggdGhpcy5pZCApICkge1xuXHRcdFx0XHRcdGxldCBwb3NpdGlvbnM6IEwuTGF0TG5nTGl0ZXJhbFtdID0gZGF0YVsgcm93SWQgXVsgJ2RhdGEnIF1bIHRoaXMuaWQgXVsgJ3Bvc2l0aW9ucycgXTtcblx0XHRcdFx0XHRtYXJrZXJzWyByb3dJZCBdID0gW107XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgcG9zIG9mIHBvc2l0aW9ucyApIHtcblxuXHRcdFx0XHRcdFx0Ym91bmRzID0gKCBib3VuZHMgPT09IHVuZGVmaW5lZCApID8gbmV3IEwuTGF0TG5nQm91bmRzKCBwb3MsIHBvcyApIDogYm91bmRzLmV4dGVuZCggcG9zICk7XG5cblx0XHRcdFx0XHRcdGxldCBtYXJrZXIgPSB0aGlzLmdldE1hcmtlciggcG9zLCBkYXRhWyByb3dJZCBdICk7XG5cdFx0XHRcdFx0XHRtYXJrZXJzWyByb3dJZCBdLnB1c2goIG1hcmtlciApO1xuXHRcdFx0XHRcdFx0bWFya2VyQ2x1c3Rlckdyb3VwLmFkZExheWVyKCBtYXJrZXIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5tYXJrZXJDbHVzdGVyR3JvdXAgPSBtYXJrZXJDbHVzdGVyR3JvdXA7XG5cdFx0XHR0aGlzLm1hcmtlcnMgPSBtYXJrZXJzO1xuXHRcdFx0dGhpcy5ib3VuZHMgPSAoIGJvdW5kcyA9PT0gdW5kZWZpbmVkICkgPyBuZXcgTC5MYXRMbmdCb3VuZHMoIFsgLTE4MCwgLTkwIF0sIFsgMTgwLCA5MCBdICkgOiBib3VuZHM7XG5cdFx0fSApO1xuXG5cdFx0cmV0dXJuIHRoaXMubGVhZmxldFByb21pc2U7XG5cdH1cblxuXHRwcml2YXRlIGdldFpvb21Gb3JVbmNsdXN0ZXJpbmcoKSB7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ21hcmtlciBjbHVzdGVyJyApICYmIHRoaXMub3B0aW9uc1sgJ21hcmtlciBjbHVzdGVyJyBdID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybiAwO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAnbWFya2VyIGNsdXN0ZXIgbWF4IHpvb20nICkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5vcHRpb25zWyAnbWFya2VyIGNsdXN0ZXIgbWF4IHpvb20nIF0gKyAxO1xuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0cHJpdmF0ZSBnZXRJY29uKCByb3c6IGFueSApIHtcblxuXHRcdGlmICggdGhpcy5pY29uID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLmJ1aWxkSWNvbkxpc3QoKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ21hcmtlciBpY29uIHByb3BlcnR5JyApICkge1xuXG5cdFx0XHRsZXQgdmFsczogc3RyaW5nW10gPSByb3dbICdwcmludG91dHMnIF1bIHRoaXMub3B0aW9uc1sgJ21hcmtlciBpY29uIHByb3BlcnR5JyBdIF1bICd2YWx1ZXMnIF07XG5cblx0XHRcdGlmICggdmFscy5sZW5ndGggPiAwICYmIHRoaXMuaWNvbi5oYXNPd25Qcm9wZXJ0eSggdmFsc1sgMCBdICkgKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLmljb25bIHZhbHNbIDAgXSBdO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmljb25bICdkZWZhdWx0JyBdO1xuXHR9XG5cblx0cHJpdmF0ZSBidWlsZEljb25MaXN0KCkge1xuXHRcdHRoaXMuaWNvbiA9IHt9O1xuXG5cdFx0bGV0IGljb25QYXRoID0gdGhpcy5jb250cm9sbGVyLmdldFBhdGgoKSArICdjc3MvaW1hZ2VzLyc7XG5cblx0XHR0aGlzLmljb25bICdkZWZhdWx0JyBdID0gbmV3IEwuSWNvbigge1xuXHRcdFx0J2ljb25VcmwnOiBpY29uUGF0aCArICdtYXJrZXItaWNvbi5wbmcnLFxuXHRcdFx0J2ljb25SZXRpbmFVcmwnOiBpY29uUGF0aCArICdtYXJrZXItaWNvbi0yeC5wbmcnLFxuXHRcdFx0J3NoYWRvd1VybCc6IGljb25QYXRoICsgJ21hcmtlci1zaGFkb3cucG5nJyxcblx0XHRcdCdpY29uU2l6ZSc6IFsgMjUsIDQxIF0sXG5cdFx0XHQnaWNvbkFuY2hvcic6IFsgMTIsIDQxIF0sXG5cdFx0XHQncG9wdXBBbmNob3InOiBbIDEsIC0zNCBdLFxuXHRcdFx0Ly8gJ3Rvb2x0aXBBbmNob3InOiBbMTYsIC0yOF0sXG5cdFx0XHQnc2hhZG93U2l6ZSc6IFsgNDEsIDQxIF1cblx0XHR9ICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSggJ21hcmtlciBpY29ucycgKSApIHtcblxuXHRcdFx0Zm9yICggbGV0IHZhbHVlIGluIHRoaXMub3B0aW9uc1sgJ21hcmtlciBpY29ucycgXSApIHtcblx0XHRcdFx0dGhpcy5pY29uWyB2YWx1ZSBdID0gbmV3IEwuSWNvbigge1xuXHRcdFx0XHRcdCdpY29uVXJsJzogdGhpcy5vcHRpb25zWyAnbWFya2VyIGljb25zJyBdWyB2YWx1ZSBdLFxuXHRcdFx0XHRcdC8vICdpY29uUmV0aW5hVXJsJzogaWNvblBhdGggKyAnbWFya2VyLWljb24tMngucG5nJyxcblx0XHRcdFx0XHQnc2hhZG93VXJsJzogaWNvblBhdGggKyAnbWFya2VyLXNoYWRvdy5wbmcnLFxuXHRcdFx0XHRcdCdpY29uU2l6ZSc6IFsgMzIsIDMyIF0sXG5cdFx0XHRcdFx0J2ljb25BbmNob3InOiBbIDE2LCAzMiBdLFxuXHRcdFx0XHRcdCdwb3B1cEFuY2hvcic6IFsgMSwgLTMwIF0sXG5cdFx0XHRcdFx0Ly8gJ3Rvb2x0aXBBbmNob3InOiBbMTYsIC0yOF0sXG5cdFx0XHRcdFx0J3NoYWRvd1NpemUnOiBbIDQxLCA0MSBdLFxuXHRcdFx0XHRcdCdzaGFkb3dBbmNob3InOiBbIDEyLCA0MSBdXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIGdldE1hcmtlciggbGF0TG5nOiBMLkxhdExuZ0V4cHJlc3Npb24sIHJvdzogYW55ICkge1xuXHRcdGxldCB0aXRsZSA9IHVuZGVmaW5lZDtcblx0XHRsZXQgcG9wdXAgPSBbXTtcblxuXHRcdC8vIFRPRE86IFVzZSA8ZGl2PiBpbnN0ZWFkIG9mIDxiPiBhbmQgZG8gQ1NTIHN0eWxpbmdcblxuXHRcdGZvciAoIGxldCBwcklkIGluIHJvd1sgJ3ByaW50b3V0cycgXSApIHtcblx0XHRcdGxldCBwcmludHJlcXVlc3QgPSAodGhpcy5jb250cm9sbGVyLmdldFByaW50UmVxdWVzdHMoKSlbIHBySWQgXTtcblxuXHRcdFx0aWYgKCAhIHByaW50cmVxdWVzdC5oYXNPd25Qcm9wZXJ0eSgnaGlkZScpIHx8IHByaW50cmVxdWVzdC5oaWRlID09PSBmYWxzZSApIHtcblx0XHRcdFx0bGV0IHByaW50b3V0cyA9IHJvd1sgJ3ByaW50b3V0cycgXVsgcHJJZCBdO1xuXG5cdFx0XHRcdGlmICggdGl0bGUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHR0aXRsZSA9IHByaW50b3V0c1sgJ3ZhbHVlcycgXS5qb2luKCAnLCAnICk7XG5cdFx0XHRcdFx0cG9wdXAucHVzaCggJzxiPicgKyBwcmludG91dHNbICdmb3JtYXR0ZWQgdmFsdWVzJyBdLmpvaW4oICcsICcgKSArICc8L2I+JyApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHBvcHVwLnB1c2goIChwcmludG91dHMubGFiZWwgPyAnPGI+JyArIHByaW50b3V0cy5sYWJlbCArICc6PC9iPiAnIDogJycpICsgcHJpbnRvdXRzWyAnZm9ybWF0dGVkIHZhbHVlcycgXS5qb2luKCAnLCAnICkgKVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0bGV0IG1hcmtlciA9IEwubWFya2VyKCBsYXRMbmcsIHsgdGl0bGU6IHRpdGxlLCBhbHQ6IHRpdGxlIH0gKTtcblx0XHRtYXJrZXIuYmluZFBvcHVwKCBwb3B1cC5qb2luKCAnPGJyPicgKSApO1xuXG5cdFx0bWFya2VyLnNldEljb24oIHRoaXMuZ2V0SWNvbiggcm93ICkgKTtcblx0XHRyZXR1cm4gbWFya2VyO1xuXHR9XG5cblx0cHVibGljIGxhdGVJbml0KCkge1xuXG5cdFx0aWYgKCB0aGlzLmluaXRpYWxpemVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuaW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0bGV0IHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5sZWFmbGV0UHJvbWlzZS50aGVuKCAoKSA9PiB7XG5cblx0XHRcdGxldCBtYXBPcHRpb25zOiBPcHRpb25zID0ge1xuXHRcdFx0XHRjZW50ZXI6IHRoaXMuYm91bmRzICE9PSB1bmRlZmluZWQgPyB0aGlzLmJvdW5kcy5nZXRDZW50ZXIoKSA6IFsgMCwgMCBdXG5cdFx0XHR9O1xuXG5cdFx0XHRtYXBPcHRpb25zID0gdGhhdC5nZXRPcHRpb25zKCBbICd6b29tJywgJ21pblpvb20nLCAnbWF4Wm9vbScgXSwgbWFwT3B0aW9ucyApO1xuXG5cdFx0XHQvLyBUT0RPOiBMaW1pdCB6b29tIHZhbHVlcyB0byBtYXAgbWF4IHpvb21cblxuXHRcdFx0dGhhdC5tYXAgPSBMLm1hcCggPEhUTUxFbGVtZW50PiB0aGF0LmdldFRhcmdldEVsZW1lbnQoKS5nZXQoIDAgKSwgbWFwT3B0aW9ucyApO1xuXHRcdFx0dGhhdC5tYXAuYWRkTGF5ZXIoIHRoYXQubWFya2VyQ2x1c3Rlckdyb3VwICk7XG5cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCAnbWFwIHByb3ZpZGVyJyApICkge1xuXHRcdFx0XHRMLnRpbGVMYXllci5wcm92aWRlciggdGhpcy5vcHRpb25zWyAnbWFwIHByb3ZpZGVyJyBdICkuYWRkVG8oIHRoYXQubWFwICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIW1hcE9wdGlvbnMuaGFzT3duUHJvcGVydHkoICd6b29tJyApICkge1xuXHRcdFx0XHR0aGF0Lm1hcC5maXRCb3VuZHMoIHRoYXQuYm91bmRzICk7XG5cdFx0XHR9XG5cblx0XHR9ICk7XG5cblx0fVxuXG5cdHB1YmxpYyBnZXRPcHRpb25zKCBrZXlzOiBzdHJpbmdbXSwgZGVmYXVsdHM6IE9wdGlvbnMgPSB7fSApIHtcblxuXHRcdGZvciAoIGxldCBrZXkgb2Yga2V5cyApIHtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhhc093blByb3BlcnR5KCBrZXkgKSApIHtcblx0XHRcdFx0ZGVmYXVsdHNbIGtleSBdID0gdGhpcy5vcHRpb25zWyBrZXkgXTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZGVmYXVsdHM7XG5cdH1cblxuXHRwdWJsaWMgc2hvd1Jvd3MoIHJvd0lkczogc3RyaW5nW10gKSB7XG5cdFx0dGhpcy5sZWFmbGV0UHJvbWlzZS50aGVuKCAoKSA9PiB7XG5cdFx0XHR0aGlzLm1hbmlwdWxhdGVMYXllcnMoIHJvd0lkcywgKCBsYXllcnM6IEwuTGF5ZXJbXSApID0+IHtcblx0XHRcdFx0dGhpcy5tYXJrZXJDbHVzdGVyR3JvdXAuYWRkTGF5ZXJzKCBsYXllcnMgKVxuXHRcdFx0fSApXG5cdFx0fSApO1xuXHR9XG5cblx0cHVibGljIGhpZGVSb3dzKCByb3dJZHM6IHN0cmluZ1tdICkge1xuXHRcdHRoaXMubGVhZmxldFByb21pc2UudGhlbiggKCkgPT4ge1xuXHRcdFx0dGhpcy5tYW5pcHVsYXRlTGF5ZXJzKCByb3dJZHMsICggbGF5ZXJzOiBMLkxheWVyW10gKSA9PiB7XG5cdFx0XHRcdHRoaXMubWFya2VyQ2x1c3Rlckdyb3VwLnJlbW92ZUxheWVycyggbGF5ZXJzIClcblx0XHRcdH0gKVxuXHRcdH0gKTtcblx0fVxuXG5cdHByaXZhdGUgbWFuaXB1bGF0ZUxheWVycyggcm93SWRzOiBzdHJpbmdbXSwgY2I6ICggbGF5ZXJzOiBMLkxheWVyW10gKSA9PiB2b2lkICkge1xuXG5cdFx0bGV0IGxheWVyc0Zyb21Sb3dJZHMgPSB0aGlzLmdldExheWVyc0Zyb21Sb3dJZHMoIHJvd0lkcyApO1xuXG5cdFx0aWYgKCBsYXllcnNGcm9tUm93SWRzLmxlbmd0aCA+IDAgKSB7XG5cdFx0XHRjYiggbGF5ZXJzRnJvbVJvd0lkcyApO1xuXHRcdH1cblxuXHR9XG5cblx0cHJpdmF0ZSBnZXRMYXllcnNGcm9tUm93SWRzKCByb3dJZHM6IHN0cmluZ1tdICkge1xuXHRcdHJldHVybiB0aGlzLmZsYXR0ZW4oIHRoaXMuZ2V0TGF5ZXJzRnJvbVJvd0lkc1Jhdyggcm93SWRzICkgKTtcblx0fVxuXG5cdHByaXZhdGUgZ2V0TGF5ZXJzRnJvbVJvd0lkc1Jhdyggcm93SWRzOiBzdHJpbmdbXSApIHtcblx0XHRyZXR1cm4gcm93SWRzLm1hcCggKCByb3dJZDogc3RyaW5nICkgPT4gdGhpcy5tYXJrZXJzWyByb3dJZCBdID8gdGhpcy5tYXJrZXJzWyByb3dJZCBdIDogW10gKTtcblx0fVxuXG5cdHByaXZhdGUgZmxhdHRlbiggbWFya2VyczogTC5MYXllcltdW10gKTogTC5MYXllcltdIHtcblx0XHRyZXR1cm4gbWFya2Vycy5yZWR1Y2UoICggcmVzdWx0OiBMLkxheWVyW10sIGxheWVyczogTC5MYXllcltdICkgPT4gcmVzdWx0LmNvbmNhdCggbGF5ZXJzICksIFtdICk7XG5cdH1cblxuXHRwdWJsaWMgc2hvdygpIHtcblx0XHRzdXBlci5zaG93KCk7XG5cdFx0dGhpcy5sYXRlSW5pdCgpO1xuXHR9XG5cbn1cbiIsImltcG9ydCB7IFZpZXcgfSBmcm9tIFwiLi9WaWV3XCI7XG5cbmV4cG9ydCBjbGFzcyBUYWJsZVZpZXcgZXh0ZW5kcyBWaWV3IHtcblxuXHRwcm90ZWN0ZWQgZ2V0SXRlbUNsYXNzTmFtZSgpIHtcblx0XHRyZXR1cm4gJy5maWx0ZXJlZC10YWJsZS1pdGVtJztcblx0fVxuXG59IiwiaW1wb3J0IHsgT3B0aW9ucyB9IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgQ29udHJvbGxlciB9IGZyb20gXCIuLi9Db250cm9sbGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBWaWV3IHtcblxuXHRwcm90ZWN0ZWQgaWQ6IHN0cmluZyA9IHVuZGVmaW5lZDtcblx0cHJvdGVjdGVkIHRhcmdldDogSlF1ZXJ5ID0gdW5kZWZpbmVkO1xuXHRwcm90ZWN0ZWQgY29udHJvbGxlcjogQ29udHJvbGxlciA9IHVuZGVmaW5lZDtcblx0cHJvdGVjdGVkIG9wdGlvbnM6IE9wdGlvbnMgPSB1bmRlZmluZWQ7XG5cdHByb3RlY3RlZCB2aXNpYmxlOiBib29sZWFuID0gZmFsc2U7XG5cdHByb3RlY3RlZCByb3dzOiB7IFsgcm93SWQ6IHN0cmluZyBdOiBKUXVlcnkgfSA9IHt9O1xuXG5cdHB1YmxpYyBjb25zdHJ1Y3RvciggaWQ6IHN0cmluZywgdGFyZ2V0OiBKUXVlcnksIGM6IENvbnRyb2xsZXIsIG9wdGlvbnM6IE9wdGlvbnMgPSB7fSApIHtcblx0XHR0aGlzLmlkID0gaWQ7XG5cdFx0dGhpcy50YXJnZXQgPSB0YXJnZXQ7XG5cdFx0dGhpcy5jb250cm9sbGVyID0gYztcblx0XHR0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXHR9XG5cblx0cHVibGljIGluaXQoKTogUHJvbWlzZTxhbnk+fHZvaWQge1xuXG5cdFx0bGV0IHJvd0lkcyA9IE9iamVjdC5rZXlzKCB0aGlzLmNvbnRyb2xsZXIuZ2V0RGF0YSgpICk7XG5cdFx0bGV0IHJvd3MgPSB0aGlzLnRhcmdldC5maW5kKCB0aGlzLmdldEl0ZW1DbGFzc05hbWUoKSApO1xuXG5cdFx0cm93cy5lYWNoKCAoIGluZGV4LCBlbGVtICkgPT4ge1xuXHRcdFx0bGV0IGNsYXNzZXMgPSBlbGVtLmNsYXNzTGlzdDtcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNsYXNzZXMubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGlmICggcm93SWRzLmluZGV4T2YoIGNsYXNzZXNbIGkgXSApID49IDAgKSB7XG5cdFx0XHRcdFx0dGhpcy5yb3dzWyBjbGFzc2VzWyBpIF0gXSA9ICQoIHJvd3NbIGluZGV4IF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblx0fVxuXG5cdHByb3RlY3RlZCBnZXRJdGVtQ2xhc3NOYW1lKCkge1xuXHRcdHJldHVybiAnLmZpbHRlcmVkLWl0ZW0nO1xuXHR9XG5cblx0cHVibGljIGdldFRhcmdldEVsZW1lbnQoKTogSlF1ZXJ5IHtcblx0XHRyZXR1cm4gdGhpcy50YXJnZXQ7XG5cdH1cblxuXHRwdWJsaWMgc2hvd1Jvd3MoIHJvd0lkczogc3RyaW5nW10gKSB7XG5cblx0XHRpZiAoIHRoaXMudmlzaWJsZSAmJiByb3dJZHMubGVuZ3RoIDwgMjAwICkge1xuXG5cdFx0XHRyb3dJZHMuZm9yRWFjaCggKCByb3dJZDogc3RyaW5nICkgPT4ge1xuXHRcdFx0XHR0aGlzLnJvd3NbIHJvd0lkIF0uc2xpZGVEb3duKCA0MDAgKTtcblx0XHRcdH0gKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJvd0lkcy5mb3JFYWNoKCAoIHJvd0lkOiBzdHJpbmcgKSA9PiB7XG5cdFx0XHRcdHRoaXMucm93c1sgcm93SWQgXS5jc3MoICdkaXNwbGF5JywgJycpO1xuXHRcdFx0fSApO1xuXG5cdFx0fVxuXHR9XG5cblx0cHVibGljIGhpZGVSb3dzKCByb3dJZHM6IHN0cmluZ1tdICkge1xuXG5cdFx0aWYgKCB0aGlzLnZpc2libGUgJiYgcm93SWRzLmxlbmd0aCA8IDIwMCApIHtcblxuXHRcdFx0cm93SWRzLmZvckVhY2goICggcm93SWQ6IHN0cmluZyApID0+IHtcblx0XHRcdFx0dGhpcy5yb3dzWyByb3dJZCBdLnNsaWRlVXAoIDQwMCApO1xuXHRcdFx0fSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cm93SWRzLmZvckVhY2goICggcm93SWQ6IHN0cmluZyApID0+IHtcblx0XHRcdFx0dGhpcy5yb3dzWyByb3dJZCBdLmNzcyggJ2Rpc3BsYXknLCAnbm9uZScpO1xuXHRcdFx0fSApO1xuXG5cdFx0fVxuXHR9XG5cblx0cHVibGljIHNob3coKSB7XG5cdFx0dGhpcy50YXJnZXQuc2hvdygpO1xuXHRcdHRoaXMudmlzaWJsZSA9IHRydWU7XG5cdH1cblxuXHRwdWJsaWMgaGlkZSgpIHtcblx0XHR0aGlzLnRhcmdldC5oaWRlKCk7XG5cdFx0dGhpcy52aXNpYmxlID0gZmFsc2U7XG5cdH1cbn1cbiIsImltcG9ydCB7IENvbnRyb2xsZXIgfSBmcm9tIFwiLi9Db250cm9sbGVyXCI7XG5leHBvcnQgY2xhc3MgVmlld1NlbGVjdG9yIHtcblxuXHRwcml2YXRlIHRhcmdldDogSlF1ZXJ5ID0gdW5kZWZpbmVkO1xuXHRwcml2YXRlIHZpZXdJRHM6IHN0cmluZ1tdID0gdW5kZWZpbmVkO1xuXG5cdHByaXZhdGUgY29udHJvbGxlcjogQ29udHJvbGxlciA9IHVuZGVmaW5lZDtcblxuXHRwdWJsaWMgY29uc3RydWN0b3IoIHRhcmdldDogSlF1ZXJ5LCB2aWV3SURzOiBzdHJpbmdbXSwgY29udHJvbGxlcjogQ29udHJvbGxlciApIHtcblx0XHR0aGlzLnRhcmdldCA9IHRhcmdldDtcblx0XHR0aGlzLnZpZXdJRHMgPSB2aWV3SURzO1xuXHRcdHRoaXMuY29udHJvbGxlciA9IGNvbnRyb2xsZXI7XG5cdH1cblxuXHRwdWJsaWMgaW5pdCgpIHtcblx0XHRpZiAoIHRoaXMudmlld0lEcy5sZW5ndGggPiAxICkge1xuXHRcdFx0dGhpcy52aWV3SURzLmZvckVhY2goICggaWQ6IHN0cmluZykgPT4geyB0aGlzLnRhcmdldC5vbiggJ2NsaWNrJywgJy4nICsgaWQsIHsgJ3RhcmdldCc6IGlkLCAnY29udHJvbGxlcicgOiB0aGlzLmNvbnRyb2xsZXIgfSwgVmlld1NlbGVjdG9yLm9uU2VsZWN0b3JTZWxlY3RlZCApOyB9ICk7XG5cdFx0XHR0aGlzLnRhcmdldC5jaGlsZHJlbigpLmZpcnN0KCkuYWRkQ2xhc3MoICdzZWxlY3RlZCcpO1xuXHRcdFx0dGhpcy50YXJnZXQuc2hvdygpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgc3RhdGljIG9uU2VsZWN0b3JTZWxlY3RlZCggZXZlbnQ6IEpRdWVyeUV2ZW50T2JqZWN0ICkge1xuXG5cdFx0ZXZlbnQuZGF0YS5jb250cm9sbGVyLm9uVmlld1NlbGVjdGVkKCBldmVudC5kYXRhLnRhcmdldCApO1xuXG5cdFx0JCggZXZlbnQudGFyZ2V0IClcblx0XHQuYWRkQ2xhc3MoICdzZWxlY3RlZCcpXG5cdFx0LnNpYmxpbmdzKCkucmVtb3ZlQ2xhc3MoICdzZWxlY3RlZCcgKTtcblxuXHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdH1cblxufSIsImltcG9ydCB7IEZpbHRlcmVkIH0gZnJvbSBcIi4vRmlsdGVyZWQvRmlsdGVyZWRcIjtcblxuZGVjbGFyZSBsZXQgbXc6IGFueTtcbmxldCBjb25maWcgPSBtdy5jb25maWcuZ2V0KCAnc3JmRmlsdGVyZWRDb25maWcnICk7XG5cbmZvciAoIGxldCBpZCBpbiBjb25maWcgKSB7XG5cdGlmICggY29uZmlnLmhhc093blByb3BlcnR5KCBpZCApICkge1xuXHRcdGxldCBmID0gbmV3IEZpbHRlcmVkKCAkKCAnIycgKyBpZCApLCBjb25maWdbIGlkIF0gKTtcblx0XHRtdy5ob29rKCAnd2lraXBhZ2UuY29udGVudCcgKS5hZGQoICgpID0+IGYucnVuKCkgKTtcblx0fVxufSJdfQ=="} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.leaflet.js b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.leaflet.js
new file mode 100644
index 00000000..09acf220
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.leaflet.js
@@ -0,0 +1,17397 @@
+/* @preserve
+ * Leaflet 1.4.0, a JS library for interactive maps. http://leafletjs.com
+ * (c) 2010-2018 Vladimir Agafonkin, (c) 2010-2011 CloudMade
+ */
+
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
+ (factory((global.L = {})));
+}(this, (function (exports) { 'use strict';
+
+var version = "1.4.0";
+
+/*
+ * @namespace Util
+ *
+ * Various utility functions, used by Leaflet internally.
+ */
+
+var freeze = Object.freeze;
+Object.freeze = function (obj) { return obj; };
+
+// @function extend(dest: Object, src?: Object): Object
+// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
+function extend(dest) {
+ var i, j, len, src;
+
+ for (j = 1, len = arguments.length; j < len; j++) {
+ src = arguments[j];
+ for (i in src) {
+ dest[i] = src[i];
+ }
+ }
+ return dest;
+}
+
+// @function create(proto: Object, properties?: Object): Object
+// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
+var create = Object.create || (function () {
+ function F() {}
+ return function (proto) {
+ F.prototype = proto;
+ return new F();
+ };
+})();
+
+// @function bind(fn: Function, …): Function
+// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
+// Has a `L.bind()` shortcut.
+function bind(fn, obj) {
+ var slice = Array.prototype.slice;
+
+ if (fn.bind) {
+ return fn.bind.apply(fn, slice.call(arguments, 1));
+ }
+
+ var args = slice.call(arguments, 2);
+
+ return function () {
+ return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
+ };
+}
+
+// @property lastId: Number
+// Last unique ID used by [`stamp()`](#util-stamp)
+var lastId = 0;
+
+// @function stamp(obj: Object): Number
+// Returns the unique ID of an object, assigning it one if it doesn't have it.
+function stamp(obj) {
+ /*eslint-disable */
+ obj._leaflet_id = obj._leaflet_id || ++lastId;
+ return obj._leaflet_id;
+ /* eslint-enable */
+}
+
+// @function throttle(fn: Function, time: Number, context: Object): Function
+// Returns a function which executes function `fn` with the given scope `context`
+// (so that the `this` keyword refers to `context` inside `fn`'s code). The function
+// `fn` will be called no more than one time per given amount of `time`. The arguments
+// received by the bound function will be any arguments passed when binding the
+// function, followed by any arguments passed when invoking the bound function.
+// Has an `L.throttle` shortcut.
+function throttle(fn, time, context) {
+ var lock, args, wrapperFn, later;
+
+ later = function () {
+ // reset lock and call if queued
+ lock = false;
+ if (args) {
+ wrapperFn.apply(context, args);
+ args = false;
+ }
+ };
+
+ wrapperFn = function () {
+ if (lock) {
+ // called too soon, queue to call later
+ args = arguments;
+
+ } else {
+ // call and lock until later
+ fn.apply(context, arguments);
+ setTimeout(later, time);
+ lock = true;
+ }
+ };
+
+ return wrapperFn;
+}
+
+// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
+// Returns the number `num` modulo `range` in such a way so it lies within
+// `range[0]` and `range[1]`. The returned value will be always smaller than
+// `range[1]` unless `includeMax` is set to `true`.
+function wrapNum(x, range, includeMax) {
+ var max = range[1],
+ min = range[0],
+ d = max - min;
+ return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
+}
+
+// @function falseFn(): Function
+// Returns a function which always returns `false`.
+function falseFn() { return false; }
+
+// @function formatNum(num: Number, digits?: Number): Number
+// Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default.
+function formatNum(num, digits) {
+ var pow = Math.pow(10, (digits === undefined ? 6 : digits));
+ return Math.round(num * pow) / pow;
+}
+
+// @function trim(str: String): String
+// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
+function trim(str) {
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
+}
+
+// @function splitWords(str: String): String[]
+// Trims and splits the string on whitespace and returns the array of parts.
+function splitWords(str) {
+ return trim(str).split(/\s+/);
+}
+
+// @function setOptions(obj: Object, options: Object): Object
+// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
+function setOptions(obj, options) {
+ if (!obj.hasOwnProperty('options')) {
+ obj.options = obj.options ? create(obj.options) : {};
+ }
+ for (var i in options) {
+ obj.options[i] = options[i];
+ }
+ return obj.options;
+}
+
+// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
+// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
+// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
+// be appended at the end. If `uppercase` is `true`, the parameter names will
+// be uppercased (e.g. `'?A=foo&B=bar'`)
+function getParamString(obj, existingUrl, uppercase) {
+ var params = [];
+ for (var i in obj) {
+ params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
+ }
+ return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
+}
+
+var templateRe = /\{ *([\w_-]+) *\}/g;
+
+// @function template(str: String, data: Object): String
+// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
+// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
+// `('Hello foo, bar')`. You can also specify functions instead of strings for
+// data values — they will be evaluated passing `data` as an argument.
+function template(str, data) {
+ return str.replace(templateRe, function (str, key) {
+ var value = data[key];
+
+ if (value === undefined) {
+ throw new Error('No value provided for variable ' + str);
+
+ } else if (typeof value === 'function') {
+ value = value(data);
+ }
+ return value;
+ });
+}
+
+// @function isArray(obj): Boolean
+// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
+var isArray = Array.isArray || function (obj) {
+ return (Object.prototype.toString.call(obj) === '[object Array]');
+};
+
+// @function indexOf(array: Array, el: Object): Number
+// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
+function indexOf(array, el) {
+ for (var i = 0; i < array.length; i++) {
+ if (array[i] === el) { return i; }
+ }
+ return -1;
+}
+
+// @property emptyImageUrl: String
+// Data URI string containing a base64-encoded empty GIF image.
+// Used as a hack to free memory from unused images on WebKit-powered
+// mobile devices (by setting image `src` to this string).
+var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
+
+// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+
+function getPrefixed(name) {
+ return window['webkit' + name] || window['moz' + name] || window['ms' + name];
+}
+
+var lastTime = 0;
+
+// fallback for IE 7-8
+function timeoutDefer(fn) {
+ var time = +new Date(),
+ timeToCall = Math.max(0, 16 - (time - lastTime));
+
+ lastTime = time + timeToCall;
+ return window.setTimeout(fn, timeToCall);
+}
+
+var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
+var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
+ getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
+
+// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
+// Schedules `fn` to be executed when the browser repaints. `fn` is bound to
+// `context` if given. When `immediate` is set, `fn` is called immediately if
+// the browser doesn't have native support for
+// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
+// otherwise it's delayed. Returns a request ID that can be used to cancel the request.
+function requestAnimFrame(fn, context, immediate) {
+ if (immediate && requestFn === timeoutDefer) {
+ fn.call(context);
+ } else {
+ return requestFn.call(window, bind(fn, context));
+ }
+}
+
+// @function cancelAnimFrame(id: Number): undefined
+// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
+function cancelAnimFrame(id) {
+ if (id) {
+ cancelFn.call(window, id);
+ }
+}
+
+
+var Util = (Object.freeze || Object)({
+ freeze: freeze,
+ extend: extend,
+ create: create,
+ bind: bind,
+ lastId: lastId,
+ stamp: stamp,
+ throttle: throttle,
+ wrapNum: wrapNum,
+ falseFn: falseFn,
+ formatNum: formatNum,
+ trim: trim,
+ splitWords: splitWords,
+ setOptions: setOptions,
+ getParamString: getParamString,
+ template: template,
+ isArray: isArray,
+ indexOf: indexOf,
+ emptyImageUrl: emptyImageUrl,
+ requestFn: requestFn,
+ cancelFn: cancelFn,
+ requestAnimFrame: requestAnimFrame,
+ cancelAnimFrame: cancelAnimFrame
+});
+
+// @class Class
+// @aka L.Class
+
+// @section
+// @uninheritable
+
+// Thanks to John Resig and Dean Edwards for inspiration!
+
+function Class() {}
+
+Class.extend = function (props) {
+
+ // @function extend(props: Object): Function
+ // [Extends the current class](#class-inheritance) given the properties to be included.
+ // Returns a Javascript function that is a class constructor (to be called with `new`).
+ var NewClass = function () {
+
+ // call the constructor
+ if (this.initialize) {
+ this.initialize.apply(this, arguments);
+ }
+
+ // call all constructor hooks
+ this.callInitHooks();
+ };
+
+ var parentProto = NewClass.__super__ = this.prototype;
+
+ var proto = create(parentProto);
+ proto.constructor = NewClass;
+
+ NewClass.prototype = proto;
+
+ // inherit parent's statics
+ for (var i in this) {
+ if (this.hasOwnProperty(i) && i !== 'prototype' && i !== '__super__') {
+ NewClass[i] = this[i];
+ }
+ }
+
+ // mix static properties into the class
+ if (props.statics) {
+ extend(NewClass, props.statics);
+ delete props.statics;
+ }
+
+ // mix includes into the prototype
+ if (props.includes) {
+ checkDeprecatedMixinEvents(props.includes);
+ extend.apply(null, [proto].concat(props.includes));
+ delete props.includes;
+ }
+
+ // merge options
+ if (proto.options) {
+ props.options = extend(create(proto.options), props.options);
+ }
+
+ // mix given properties into the prototype
+ extend(proto, props);
+
+ proto._initHooks = [];
+
+ // add method for calling all hooks
+ proto.callInitHooks = function () {
+
+ if (this._initHooksCalled) { return; }
+
+ if (parentProto.callInitHooks) {
+ parentProto.callInitHooks.call(this);
+ }
+
+ this._initHooksCalled = true;
+
+ for (var i = 0, len = proto._initHooks.length; i < len; i++) {
+ proto._initHooks[i].call(this);
+ }
+ };
+
+ return NewClass;
+};
+
+
+// @function include(properties: Object): this
+// [Includes a mixin](#class-includes) into the current class.
+Class.include = function (props) {
+ extend(this.prototype, props);
+ return this;
+};
+
+// @function mergeOptions(options: Object): this
+// [Merges `options`](#class-options) into the defaults of the class.
+Class.mergeOptions = function (options) {
+ extend(this.prototype.options, options);
+ return this;
+};
+
+// @function addInitHook(fn: Function): this
+// Adds a [constructor hook](#class-constructor-hooks) to the class.
+Class.addInitHook = function (fn) { // (Function) || (String, args...)
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ var init = typeof fn === 'function' ? fn : function () {
+ this[fn].apply(this, args);
+ };
+
+ this.prototype._initHooks = this.prototype._initHooks || [];
+ this.prototype._initHooks.push(init);
+ return this;
+};
+
+function checkDeprecatedMixinEvents(includes) {
+ if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
+
+ includes = isArray(includes) ? includes : [includes];
+
+ for (var i = 0; i < includes.length; i++) {
+ if (includes[i] === L.Mixin.Events) {
+ console.warn('Deprecated include of L.Mixin.Events: ' +
+ 'this property will be removed in future releases, ' +
+ 'please inherit from L.Evented instead.', new Error().stack);
+ }
+ }
+}
+
+/*
+ * @class Evented
+ * @aka L.Evented
+ * @inherits Class
+ *
+ * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).
+ *
+ * @example
+ *
+ * ```js
+ * map.on('click', function(e) {
+ * alert(e.latlng);
+ * } );
+ * ```
+ *
+ * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
+ *
+ * ```js
+ * function onClick(e) { ... }
+ *
+ * map.on('click', onClick);
+ * map.off('click', onClick);
+ * ```
+ */
+
+var Events = {
+ /* @method on(type: String, fn: Function, context?: Object): this
+ * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).
+ *
+ * @alternative
+ * @method on(eventMap: Object): this
+ * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
+ */
+ on: function (types, fn, context) {
+
+ // types can be a map of types/handlers
+ if (typeof types === 'object') {
+ for (var type in types) {
+ // we don't process space-separated events here for performance;
+ // it's a hot path since Layer uses the on(obj) syntax
+ this._on(type, types[type], fn);
+ }
+
+ } else {
+ // types can be a string of space-separated words
+ types = splitWords(types);
+
+ for (var i = 0, len = types.length; i < len; i++) {
+ this._on(types[i], fn, context);
+ }
+ }
+
+ return this;
+ },
+
+ /* @method off(type: String, fn?: Function, context?: Object): this
+ * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.
+ *
+ * @alternative
+ * @method off(eventMap: Object): this
+ * Removes a set of type/listener pairs.
+ *
+ * @alternative
+ * @method off: this
+ * Removes all listeners to all events on the object.
+ */
+ off: function (types, fn, context) {
+
+ if (!types) {
+ // clear all listeners if called without arguments
+ delete this._events;
+
+ } else if (typeof types === 'object') {
+ for (var type in types) {
+ this._off(type, types[type], fn);
+ }
+
+ } else {
+ types = splitWords(types);
+
+ for (var i = 0, len = types.length; i < len; i++) {
+ this._off(types[i], fn, context);
+ }
+ }
+
+ return this;
+ },
+
+ // attach listener (without syntactic sugar now)
+ _on: function (type, fn, context) {
+ this._events = this._events || {};
+
+ /* get/init listeners for type */
+ var typeListeners = this._events[type];
+ if (!typeListeners) {
+ typeListeners = [];
+ this._events[type] = typeListeners;
+ }
+
+ if (context === this) {
+ // Less memory footprint.
+ context = undefined;
+ }
+ var newListener = {fn: fn, ctx: context},
+ listeners = typeListeners;
+
+ // check if fn already there
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ if (listeners[i].fn === fn && listeners[i].ctx === context) {
+ return;
+ }
+ }
+
+ listeners.push(newListener);
+ },
+
+ _off: function (type, fn, context) {
+ var listeners,
+ i,
+ len;
+
+ if (!this._events) { return; }
+
+ listeners = this._events[type];
+
+ if (!listeners) {
+ return;
+ }
+
+ if (!fn) {
+ // Set all removed listeners to noop so they are not called if remove happens in fire
+ for (i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].fn = falseFn;
+ }
+ // clear all listeners for a type if function isn't specified
+ delete this._events[type];
+ return;
+ }
+
+ if (context === this) {
+ context = undefined;
+ }
+
+ if (listeners) {
+
+ // find fn and remove it
+ for (i = 0, len = listeners.length; i < len; i++) {
+ var l = listeners[i];
+ if (l.ctx !== context) { continue; }
+ if (l.fn === fn) {
+
+ // set the removed listener to noop so that's not called if remove happens in fire
+ l.fn = falseFn;
+
+ if (this._firingCount) {
+ /* copy array in case events are being fired */
+ this._events[type] = listeners = listeners.slice();
+ }
+ listeners.splice(i, 1);
+
+ return;
+ }
+ }
+ }
+ },
+
+ // @method fire(type: String, data?: Object, propagate?: Boolean): this
+ // Fires an event of the specified type. You can optionally provide an data
+ // object — the first argument of the listener function will contain its
+ // properties. The event can optionally be propagated to event parents.
+ fire: function (type, data, propagate) {
+ if (!this.listens(type, propagate)) { return this; }
+
+ var event = extend({}, data, {
+ type: type,
+ target: this,
+ sourceTarget: data && data.sourceTarget || this
+ });
+
+ if (this._events) {
+ var listeners = this._events[type];
+
+ if (listeners) {
+ this._firingCount = (this._firingCount + 1) || 1;
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ var l = listeners[i];
+ l.fn.call(l.ctx || this, event);
+ }
+
+ this._firingCount--;
+ }
+ }
+
+ if (propagate) {
+ // propagate the event to parents (set with addEventParent)
+ this._propagateEvent(event);
+ }
+
+ return this;
+ },
+
+ // @method listens(type: String): Boolean
+ // Returns `true` if a particular event type has any listeners attached to it.
+ listens: function (type, propagate) {
+ var listeners = this._events && this._events[type];
+ if (listeners && listeners.length) { return true; }
+
+ if (propagate) {
+ // also check parents for listeners if event propagates
+ for (var id in this._eventParents) {
+ if (this._eventParents[id].listens(type, propagate)) { return true; }
+ }
+ }
+ return false;
+ },
+
+ // @method once(…): this
+ // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
+ once: function (types, fn, context) {
+
+ if (typeof types === 'object') {
+ for (var type in types) {
+ this.once(type, types[type], fn);
+ }
+ return this;
+ }
+
+ var handler = bind(function () {
+ this
+ .off(types, fn, context)
+ .off(types, handler, context);
+ }, this);
+
+ // add a listener that's executed once and removed after that
+ return this
+ .on(types, fn, context)
+ .on(types, handler, context);
+ },
+
+ // @method addEventParent(obj: Evented): this
+ // Adds an event parent - an `Evented` that will receive propagated events
+ addEventParent: function (obj) {
+ this._eventParents = this._eventParents || {};
+ this._eventParents[stamp(obj)] = obj;
+ return this;
+ },
+
+ // @method removeEventParent(obj: Evented): this
+ // Removes an event parent, so it will stop receiving propagated events
+ removeEventParent: function (obj) {
+ if (this._eventParents) {
+ delete this._eventParents[stamp(obj)];
+ }
+ return this;
+ },
+
+ _propagateEvent: function (e) {
+ for (var id in this._eventParents) {
+ this._eventParents[id].fire(e.type, extend({
+ layer: e.target,
+ propagatedFrom: e.target
+ }, e), true);
+ }
+ }
+};
+
+// aliases; we should ditch those eventually
+
+// @method addEventListener(…): this
+// Alias to [`on(…)`](#evented-on)
+Events.addEventListener = Events.on;
+
+// @method removeEventListener(…): this
+// Alias to [`off(…)`](#evented-off)
+
+// @method clearAllEventListeners(…): this
+// Alias to [`off()`](#evented-off)
+Events.removeEventListener = Events.clearAllEventListeners = Events.off;
+
+// @method addOneTimeEventListener(…): this
+// Alias to [`once(…)`](#evented-once)
+Events.addOneTimeEventListener = Events.once;
+
+// @method fireEvent(…): this
+// Alias to [`fire(…)`](#evented-fire)
+Events.fireEvent = Events.fire;
+
+// @method hasEventListeners(…): Boolean
+// Alias to [`listens(…)`](#evented-listens)
+Events.hasEventListeners = Events.listens;
+
+var Evented = Class.extend(Events);
+
+/*
+ * @class Point
+ * @aka L.Point
+ *
+ * Represents a point with `x` and `y` coordinates in pixels.
+ *
+ * @example
+ *
+ * ```js
+ * var point = L.point(200, 300);
+ * ```
+ *
+ * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:
+ *
+ * ```js
+ * map.panBy([200, 300]);
+ * map.panBy(L.point(200, 300));
+ * ```
+ *
+ * Note that `Point` does not inherit from Leafet's `Class` object,
+ * which means new classes can't inherit from it, and new methods
+ * can't be added to it with the `include` function.
+ */
+
+function Point(x, y, round) {
+ // @property x: Number; The `x` coordinate of the point
+ this.x = (round ? Math.round(x) : x);
+ // @property y: Number; The `y` coordinate of the point
+ this.y = (round ? Math.round(y) : y);
+}
+
+var trunc = Math.trunc || function (v) {
+ return v > 0 ? Math.floor(v) : Math.ceil(v);
+};
+
+Point.prototype = {
+
+ // @method clone(): Point
+ // Returns a copy of the current point.
+ clone: function () {
+ return new Point(this.x, this.y);
+ },
+
+ // @method add(otherPoint: Point): Point
+ // Returns the result of addition of the current and the given points.
+ add: function (point) {
+ // non-destructive, returns a new point
+ return this.clone()._add(toPoint(point));
+ },
+
+ _add: function (point) {
+ // destructive, used directly for performance in situations where it's safe to modify existing point
+ this.x += point.x;
+ this.y += point.y;
+ return this;
+ },
+
+ // @method subtract(otherPoint: Point): Point
+ // Returns the result of subtraction of the given point from the current.
+ subtract: function (point) {
+ return this.clone()._subtract(toPoint(point));
+ },
+
+ _subtract: function (point) {
+ this.x -= point.x;
+ this.y -= point.y;
+ return this;
+ },
+
+ // @method divideBy(num: Number): Point
+ // Returns the result of division of the current point by the given number.
+ divideBy: function (num) {
+ return this.clone()._divideBy(num);
+ },
+
+ _divideBy: function (num) {
+ this.x /= num;
+ this.y /= num;
+ return this;
+ },
+
+ // @method multiplyBy(num: Number): Point
+ // Returns the result of multiplication of the current point by the given number.
+ multiplyBy: function (num) {
+ return this.clone()._multiplyBy(num);
+ },
+
+ _multiplyBy: function (num) {
+ this.x *= num;
+ this.y *= num;
+ return this;
+ },
+
+ // @method scaleBy(scale: Point): Point
+ // Multiply each coordinate of the current point by each coordinate of
+ // `scale`. In linear algebra terms, multiply the point by the
+ // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
+ // defined by `scale`.
+ scaleBy: function (point) {
+ return new Point(this.x * point.x, this.y * point.y);
+ },
+
+ // @method unscaleBy(scale: Point): Point
+ // Inverse of `scaleBy`. Divide each coordinate of the current point by
+ // each coordinate of `scale`.
+ unscaleBy: function (point) {
+ return new Point(this.x / point.x, this.y / point.y);
+ },
+
+ // @method round(): Point
+ // Returns a copy of the current point with rounded coordinates.
+ round: function () {
+ return this.clone()._round();
+ },
+
+ _round: function () {
+ this.x = Math.round(this.x);
+ this.y = Math.round(this.y);
+ return this;
+ },
+
+ // @method floor(): Point
+ // Returns a copy of the current point with floored coordinates (rounded down).
+ floor: function () {
+ return this.clone()._floor();
+ },
+
+ _floor: function () {
+ this.x = Math.floor(this.x);
+ this.y = Math.floor(this.y);
+ return this;
+ },
+
+ // @method ceil(): Point
+ // Returns a copy of the current point with ceiled coordinates (rounded up).
+ ceil: function () {
+ return this.clone()._ceil();
+ },
+
+ _ceil: function () {
+ this.x = Math.ceil(this.x);
+ this.y = Math.ceil(this.y);
+ return this;
+ },
+
+ // @method trunc(): Point
+ // Returns a copy of the current point with truncated coordinates (rounded towards zero).
+ trunc: function () {
+ return this.clone()._trunc();
+ },
+
+ _trunc: function () {
+ this.x = trunc(this.x);
+ this.y = trunc(this.y);
+ return this;
+ },
+
+ // @method distanceTo(otherPoint: Point): Number
+ // Returns the cartesian distance between the current and the given points.
+ distanceTo: function (point) {
+ point = toPoint(point);
+
+ var x = point.x - this.x,
+ y = point.y - this.y;
+
+ return Math.sqrt(x * x + y * y);
+ },
+
+ // @method equals(otherPoint: Point): Boolean
+ // Returns `true` if the given point has the same coordinates.
+ equals: function (point) {
+ point = toPoint(point);
+
+ return point.x === this.x &&
+ point.y === this.y;
+ },
+
+ // @method contains(otherPoint: Point): Boolean
+ // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
+ contains: function (point) {
+ point = toPoint(point);
+
+ return Math.abs(point.x) <= Math.abs(this.x) &&
+ Math.abs(point.y) <= Math.abs(this.y);
+ },
+
+ // @method toString(): String
+ // Returns a string representation of the point for debugging purposes.
+ toString: function () {
+ return 'Point(' +
+ formatNum(this.x) + ', ' +
+ formatNum(this.y) + ')';
+ }
+};
+
+// @factory L.point(x: Number, y: Number, round?: Boolean)
+// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.
+
+// @alternative
+// @factory L.point(coords: Number[])
+// Expects an array of the form `[x, y]` instead.
+
+// @alternative
+// @factory L.point(coords: Object)
+// Expects a plain object of the form `{x: Number, y: Number}` instead.
+function toPoint(x, y, round) {
+ if (x instanceof Point) {
+ return x;
+ }
+ if (isArray(x)) {
+ return new Point(x[0], x[1]);
+ }
+ if (x === undefined || x === null) {
+ return x;
+ }
+ if (typeof x === 'object' && 'x' in x && 'y' in x) {
+ return new Point(x.x, x.y);
+ }
+ return new Point(x, y, round);
+}
+
+/*
+ * @class Bounds
+ * @aka L.Bounds
+ *
+ * Represents a rectangular area in pixel coordinates.
+ *
+ * @example
+ *
+ * ```js
+ * var p1 = L.point(10, 10),
+ * p2 = L.point(40, 60),
+ * bounds = L.bounds(p1, p2);
+ * ```
+ *
+ * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
+ *
+ * ```js
+ * otherBounds.intersects([[10, 10], [40, 60]]);
+ * ```
+ *
+ * Note that `Bounds` does not inherit from Leafet's `Class` object,
+ * which means new classes can't inherit from it, and new methods
+ * can't be added to it with the `include` function.
+ */
+
+function Bounds(a, b) {
+ if (!a) { return; }
+
+ var points = b ? [a, b] : a;
+
+ for (var i = 0, len = points.length; i < len; i++) {
+ this.extend(points[i]);
+ }
+}
+
+Bounds.prototype = {
+ // @method extend(point: Point): this
+ // Extends the bounds to contain the given point.
+ extend: function (point) { // (Point)
+ point = toPoint(point);
+
+ // @property min: Point
+ // The top left corner of the rectangle.
+ // @property max: Point
+ // The bottom right corner of the rectangle.
+ if (!this.min && !this.max) {
+ this.min = point.clone();
+ this.max = point.clone();
+ } else {
+ this.min.x = Math.min(point.x, this.min.x);
+ this.max.x = Math.max(point.x, this.max.x);
+ this.min.y = Math.min(point.y, this.min.y);
+ this.max.y = Math.max(point.y, this.max.y);
+ }
+ return this;
+ },
+
+ // @method getCenter(round?: Boolean): Point
+ // Returns the center point of the bounds.
+ getCenter: function (round) {
+ return new Point(
+ (this.min.x + this.max.x) / 2,
+ (this.min.y + this.max.y) / 2, round);
+ },
+
+ // @method getBottomLeft(): Point
+ // Returns the bottom-left point of the bounds.
+ getBottomLeft: function () {
+ return new Point(this.min.x, this.max.y);
+ },
+
+ // @method getTopRight(): Point
+ // Returns the top-right point of the bounds.
+ getTopRight: function () { // -> Point
+ return new Point(this.max.x, this.min.y);
+ },
+
+ // @method getTopLeft(): Point
+ // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
+ getTopLeft: function () {
+ return this.min; // left, top
+ },
+
+ // @method getBottomRight(): Point
+ // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
+ getBottomRight: function () {
+ return this.max; // right, bottom
+ },
+
+ // @method getSize(): Point
+ // Returns the size of the given bounds
+ getSize: function () {
+ return this.max.subtract(this.min);
+ },
+
+ // @method contains(otherBounds: Bounds): Boolean
+ // Returns `true` if the rectangle contains the given one.
+ // @alternative
+ // @method contains(point: Point): Boolean
+ // Returns `true` if the rectangle contains the given point.
+ contains: function (obj) {
+ var min, max;
+
+ if (typeof obj[0] === 'number' || obj instanceof Point) {
+ obj = toPoint(obj);
+ } else {
+ obj = toBounds(obj);
+ }
+
+ if (obj instanceof Bounds) {
+ min = obj.min;
+ max = obj.max;
+ } else {
+ min = max = obj;
+ }
+
+ return (min.x >= this.min.x) &&
+ (max.x <= this.max.x) &&
+ (min.y >= this.min.y) &&
+ (max.y <= this.max.y);
+ },
+
+ // @method intersects(otherBounds: Bounds): Boolean
+ // Returns `true` if the rectangle intersects the given bounds. Two bounds
+ // intersect if they have at least one point in common.
+ intersects: function (bounds) { // (Bounds) -> Boolean
+ bounds = toBounds(bounds);
+
+ var min = this.min,
+ max = this.max,
+ min2 = bounds.min,
+ max2 = bounds.max,
+ xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
+ yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
+
+ return xIntersects && yIntersects;
+ },
+
+ // @method overlaps(otherBounds: Bounds): Boolean
+ // Returns `true` if the rectangle overlaps the given bounds. Two bounds
+ // overlap if their intersection is an area.
+ overlaps: function (bounds) { // (Bounds) -> Boolean
+ bounds = toBounds(bounds);
+
+ var min = this.min,
+ max = this.max,
+ min2 = bounds.min,
+ max2 = bounds.max,
+ xOverlaps = (max2.x > min.x) && (min2.x < max.x),
+ yOverlaps = (max2.y > min.y) && (min2.y < max.y);
+
+ return xOverlaps && yOverlaps;
+ },
+
+ isValid: function () {
+ return !!(this.min && this.max);
+ }
+};
+
+
+// @factory L.bounds(corner1: Point, corner2: Point)
+// Creates a Bounds object from two corners coordinate pairs.
+// @alternative
+// @factory L.bounds(points: Point[])
+// Creates a Bounds object from the given array of points.
+function toBounds(a, b) {
+ if (!a || a instanceof Bounds) {
+ return a;
+ }
+ return new Bounds(a, b);
+}
+
+/*
+ * @class LatLngBounds
+ * @aka L.LatLngBounds
+ *
+ * Represents a rectangular geographical area on a map.
+ *
+ * @example
+ *
+ * ```js
+ * var corner1 = L.latLng(40.712, -74.227),
+ * corner2 = L.latLng(40.774, -74.125),
+ * bounds = L.latLngBounds(corner1, corner2);
+ * ```
+ *
+ * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
+ *
+ * ```js
+ * map.fitBounds([
+ * [40.712, -74.227],
+ * [40.774, -74.125]
+ * ]);
+ * ```
+ *
+ * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.
+ *
+ * Note that `LatLngBounds` does not inherit from Leafet's `Class` object,
+ * which means new classes can't inherit from it, and new methods
+ * can't be added to it with the `include` function.
+ */
+
+function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
+ if (!corner1) { return; }
+
+ var latlngs = corner2 ? [corner1, corner2] : corner1;
+
+ for (var i = 0, len = latlngs.length; i < len; i++) {
+ this.extend(latlngs[i]);
+ }
+}
+
+LatLngBounds.prototype = {
+
+ // @method extend(latlng: LatLng): this
+ // Extend the bounds to contain the given point
+
+ // @alternative
+ // @method extend(otherBounds: LatLngBounds): this
+ // Extend the bounds to contain the given bounds
+ extend: function (obj) {
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2, ne2;
+
+ if (obj instanceof LatLng) {
+ sw2 = obj;
+ ne2 = obj;
+
+ } else if (obj instanceof LatLngBounds) {
+ sw2 = obj._southWest;
+ ne2 = obj._northEast;
+
+ if (!sw2 || !ne2) { return this; }
+
+ } else {
+ return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
+ }
+
+ if (!sw && !ne) {
+ this._southWest = new LatLng(sw2.lat, sw2.lng);
+ this._northEast = new LatLng(ne2.lat, ne2.lng);
+ } else {
+ sw.lat = Math.min(sw2.lat, sw.lat);
+ sw.lng = Math.min(sw2.lng, sw.lng);
+ ne.lat = Math.max(ne2.lat, ne.lat);
+ ne.lng = Math.max(ne2.lng, ne.lng);
+ }
+
+ return this;
+ },
+
+ // @method pad(bufferRatio: Number): LatLngBounds
+ // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
+ // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
+ // Negative values will retract the bounds.
+ pad: function (bufferRatio) {
+ var sw = this._southWest,
+ ne = this._northEast,
+ heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
+ widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
+
+ return new LatLngBounds(
+ new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
+ new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
+ },
+
+ // @method getCenter(): LatLng
+ // Returns the center point of the bounds.
+ getCenter: function () {
+ return new LatLng(
+ (this._southWest.lat + this._northEast.lat) / 2,
+ (this._southWest.lng + this._northEast.lng) / 2);
+ },
+
+ // @method getSouthWest(): LatLng
+ // Returns the south-west point of the bounds.
+ getSouthWest: function () {
+ return this._southWest;
+ },
+
+ // @method getNorthEast(): LatLng
+ // Returns the north-east point of the bounds.
+ getNorthEast: function () {
+ return this._northEast;
+ },
+
+ // @method getNorthWest(): LatLng
+ // Returns the north-west point of the bounds.
+ getNorthWest: function () {
+ return new LatLng(this.getNorth(), this.getWest());
+ },
+
+ // @method getSouthEast(): LatLng
+ // Returns the south-east point of the bounds.
+ getSouthEast: function () {
+ return new LatLng(this.getSouth(), this.getEast());
+ },
+
+ // @method getWest(): Number
+ // Returns the west longitude of the bounds
+ getWest: function () {
+ return this._southWest.lng;
+ },
+
+ // @method getSouth(): Number
+ // Returns the south latitude of the bounds
+ getSouth: function () {
+ return this._southWest.lat;
+ },
+
+ // @method getEast(): Number
+ // Returns the east longitude of the bounds
+ getEast: function () {
+ return this._northEast.lng;
+ },
+
+ // @method getNorth(): Number
+ // Returns the north latitude of the bounds
+ getNorth: function () {
+ return this._northEast.lat;
+ },
+
+ // @method contains(otherBounds: LatLngBounds): Boolean
+ // Returns `true` if the rectangle contains the given one.
+
+ // @alternative
+ // @method contains (latlng: LatLng): Boolean
+ // Returns `true` if the rectangle contains the given point.
+ contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
+ if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
+ obj = toLatLng(obj);
+ } else {
+ obj = toLatLngBounds(obj);
+ }
+
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2, ne2;
+
+ if (obj instanceof LatLngBounds) {
+ sw2 = obj.getSouthWest();
+ ne2 = obj.getNorthEast();
+ } else {
+ sw2 = ne2 = obj;
+ }
+
+ return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
+ (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
+ },
+
+ // @method intersects(otherBounds: LatLngBounds): Boolean
+ // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
+ intersects: function (bounds) {
+ bounds = toLatLngBounds(bounds);
+
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2 = bounds.getSouthWest(),
+ ne2 = bounds.getNorthEast(),
+
+ latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
+ lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
+
+ return latIntersects && lngIntersects;
+ },
+
+ // @method overlaps(otherBounds: Bounds): Boolean
+ // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
+ overlaps: function (bounds) {
+ bounds = toLatLngBounds(bounds);
+
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2 = bounds.getSouthWest(),
+ ne2 = bounds.getNorthEast(),
+
+ latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
+ lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
+
+ return latOverlaps && lngOverlaps;
+ },
+
+ // @method toBBoxString(): String
+ // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
+ toBBoxString: function () {
+ return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
+ },
+
+ // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
+ // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.
+ equals: function (bounds, maxMargin) {
+ if (!bounds) { return false; }
+
+ bounds = toLatLngBounds(bounds);
+
+ return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
+ this._northEast.equals(bounds.getNorthEast(), maxMargin);
+ },
+
+ // @method isValid(): Boolean
+ // Returns `true` if the bounds are properly initialized.
+ isValid: function () {
+ return !!(this._southWest && this._northEast);
+ }
+};
+
+// TODO International date line?
+
+// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
+// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
+
+// @alternative
+// @factory L.latLngBounds(latlngs: LatLng[])
+// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
+function toLatLngBounds(a, b) {
+ if (a instanceof LatLngBounds) {
+ return a;
+ }
+ return new LatLngBounds(a, b);
+}
+
+/* @class LatLng
+ * @aka L.LatLng
+ *
+ * Represents a geographical point with a certain latitude and longitude.
+ *
+ * @example
+ *
+ * ```
+ * var latlng = L.latLng(50.5, 30.5);
+ * ```
+ *
+ * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:
+ *
+ * ```
+ * map.panTo([50, 30]);
+ * map.panTo({lon: 30, lat: 50});
+ * map.panTo({lat: 50, lng: 30});
+ * map.panTo(L.latLng(50, 30));
+ * ```
+ *
+ * Note that `LatLng` does not inherit from Leaflet's `Class` object,
+ * which means new classes can't inherit from it, and new methods
+ * can't be added to it with the `include` function.
+ */
+
+function LatLng(lat, lng, alt) {
+ if (isNaN(lat) || isNaN(lng)) {
+ throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
+ }
+
+ // @property lat: Number
+ // Latitude in degrees
+ this.lat = +lat;
+
+ // @property lng: Number
+ // Longitude in degrees
+ this.lng = +lng;
+
+ // @property alt: Number
+ // Altitude in meters (optional)
+ if (alt !== undefined) {
+ this.alt = +alt;
+ }
+}
+
+LatLng.prototype = {
+ // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
+ // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.
+ equals: function (obj, maxMargin) {
+ if (!obj) { return false; }
+
+ obj = toLatLng(obj);
+
+ var margin = Math.max(
+ Math.abs(this.lat - obj.lat),
+ Math.abs(this.lng - obj.lng));
+
+ return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
+ },
+
+ // @method toString(): String
+ // Returns a string representation of the point (for debugging purposes).
+ toString: function (precision) {
+ return 'LatLng(' +
+ formatNum(this.lat, precision) + ', ' +
+ formatNum(this.lng, precision) + ')';
+ },
+
+ // @method distanceTo(otherLatLng: LatLng): Number
+ // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).
+ distanceTo: function (other) {
+ return Earth.distance(this, toLatLng(other));
+ },
+
+ // @method wrap(): LatLng
+ // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
+ wrap: function () {
+ return Earth.wrapLatLng(this);
+ },
+
+ // @method toBounds(sizeInMeters: Number): LatLngBounds
+ // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
+ toBounds: function (sizeInMeters) {
+ var latAccuracy = 180 * sizeInMeters / 40075017,
+ lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
+
+ return toLatLngBounds(
+ [this.lat - latAccuracy, this.lng - lngAccuracy],
+ [this.lat + latAccuracy, this.lng + lngAccuracy]);
+ },
+
+ clone: function () {
+ return new LatLng(this.lat, this.lng, this.alt);
+ }
+};
+
+
+
+// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
+// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
+
+// @alternative
+// @factory L.latLng(coords: Array): LatLng
+// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
+
+// @alternative
+// @factory L.latLng(coords: Object): LatLng
+// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
+
+function toLatLng(a, b, c) {
+ if (a instanceof LatLng) {
+ return a;
+ }
+ if (isArray(a) && typeof a[0] !== 'object') {
+ if (a.length === 3) {
+ return new LatLng(a[0], a[1], a[2]);
+ }
+ if (a.length === 2) {
+ return new LatLng(a[0], a[1]);
+ }
+ return null;
+ }
+ if (a === undefined || a === null) {
+ return a;
+ }
+ if (typeof a === 'object' && 'lat' in a) {
+ return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
+ }
+ if (b === undefined) {
+ return null;
+ }
+ return new LatLng(a, b, c);
+}
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.Base
+ * Object that defines coordinate reference systems for projecting
+ * geographical points into pixel (screen) coordinates and back (and to
+ * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
+ * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).
+ *
+ * Leaflet defines the most usual CRSs by default. If you want to use a
+ * CRS not defined by default, take a look at the
+ * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
+ *
+ * Note that the CRS instances do not inherit from Leafet's `Class` object,
+ * and can't be instantiated. Also, new classes can't inherit from them,
+ * and methods can't be added to them with the `include` function.
+ */
+
+var CRS = {
+ // @method latLngToPoint(latlng: LatLng, zoom: Number): Point
+ // Projects geographical coordinates into pixel coordinates for a given zoom.
+ latLngToPoint: function (latlng, zoom) {
+ var projectedPoint = this.projection.project(latlng),
+ scale = this.scale(zoom);
+
+ return this.transformation._transform(projectedPoint, scale);
+ },
+
+ // @method pointToLatLng(point: Point, zoom: Number): LatLng
+ // The inverse of `latLngToPoint`. Projects pixel coordinates on a given
+ // zoom into geographical coordinates.
+ pointToLatLng: function (point, zoom) {
+ var scale = this.scale(zoom),
+ untransformedPoint = this.transformation.untransform(point, scale);
+
+ return this.projection.unproject(untransformedPoint);
+ },
+
+ // @method project(latlng: LatLng): Point
+ // Projects geographical coordinates into coordinates in units accepted for
+ // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
+ project: function (latlng) {
+ return this.projection.project(latlng);
+ },
+
+ // @method unproject(point: Point): LatLng
+ // Given a projected coordinate returns the corresponding LatLng.
+ // The inverse of `project`.
+ unproject: function (point) {
+ return this.projection.unproject(point);
+ },
+
+ // @method scale(zoom: Number): Number
+ // Returns the scale used when transforming projected coordinates into
+ // pixel coordinates for a particular zoom. For example, it returns
+ // `256 * 2^zoom` for Mercator-based CRS.
+ scale: function (zoom) {
+ return 256 * Math.pow(2, zoom);
+ },
+
+ // @method zoom(scale: Number): Number
+ // Inverse of `scale()`, returns the zoom level corresponding to a scale
+ // factor of `scale`.
+ zoom: function (scale) {
+ return Math.log(scale / 256) / Math.LN2;
+ },
+
+ // @method getProjectedBounds(zoom: Number): Bounds
+ // Returns the projection's bounds scaled and transformed for the provided `zoom`.
+ getProjectedBounds: function (zoom) {
+ if (this.infinite) { return null; }
+
+ var b = this.projection.bounds,
+ s = this.scale(zoom),
+ min = this.transformation.transform(b.min, s),
+ max = this.transformation.transform(b.max, s);
+
+ return new Bounds(min, max);
+ },
+
+ // @method distance(latlng1: LatLng, latlng2: LatLng): Number
+ // Returns the distance between two geographical coordinates.
+
+ // @property code: String
+ // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
+ //
+ // @property wrapLng: Number[]
+ // An array of two numbers defining whether the longitude (horizontal) coordinate
+ // axis wraps around a given range and how. Defaults to `[-180, 180]` in most
+ // geographical CRSs. If `undefined`, the longitude axis does not wrap around.
+ //
+ // @property wrapLat: Number[]
+ // Like `wrapLng`, but for the latitude (vertical) axis.
+
+ // wrapLng: [min, max],
+ // wrapLat: [min, max],
+
+ // @property infinite: Boolean
+ // If true, the coordinate space will be unbounded (infinite in both axes)
+ infinite: false,
+
+ // @method wrapLatLng(latlng: LatLng): LatLng
+ // Returns a `LatLng` where lat and lng has been wrapped according to the
+ // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
+ wrapLatLng: function (latlng) {
+ var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
+ lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
+ alt = latlng.alt;
+
+ return new LatLng(lat, lng, alt);
+ },
+
+ // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
+ // Returns a `LatLngBounds` with the same size as the given one, ensuring
+ // that its center is within the CRS's bounds.
+ // Only accepts actual `L.LatLngBounds` instances, not arrays.
+ wrapLatLngBounds: function (bounds) {
+ var center = bounds.getCenter(),
+ newCenter = this.wrapLatLng(center),
+ latShift = center.lat - newCenter.lat,
+ lngShift = center.lng - newCenter.lng;
+
+ if (latShift === 0 && lngShift === 0) {
+ return bounds;
+ }
+
+ var sw = bounds.getSouthWest(),
+ ne = bounds.getNorthEast(),
+ newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),
+ newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
+
+ return new LatLngBounds(newSw, newNe);
+ }
+};
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.Earth
+ *
+ * Serves as the base for CRS that are global such that they cover the earth.
+ * Can only be used as the base for other CRS and cannot be used directly,
+ * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
+ * meters.
+ */
+
+var Earth = extend({}, CRS, {
+ wrapLng: [-180, 180],
+
+ // Mean Earth Radius, as recommended for use by
+ // the International Union of Geodesy and Geophysics,
+ // see http://rosettacode.org/wiki/Haversine_formula
+ R: 6371000,
+
+ // distance between two geographical points using spherical law of cosines approximation
+ distance: function (latlng1, latlng2) {
+ var rad = Math.PI / 180,
+ lat1 = latlng1.lat * rad,
+ lat2 = latlng2.lat * rad,
+ sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),
+ sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),
+ a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ return this.R * c;
+ }
+});
+
+/*
+ * @namespace Projection
+ * @projection L.Projection.SphericalMercator
+ *
+ * Spherical Mercator projection — the most common projection for online maps,
+ * used by almost all free and commercial tile providers. Assumes that Earth is
+ * a sphere. Used by the `EPSG:3857` CRS.
+ */
+
+var SphericalMercator = {
+
+ R: 6378137,
+ MAX_LATITUDE: 85.0511287798,
+
+ project: function (latlng) {
+ var d = Math.PI / 180,
+ max = this.MAX_LATITUDE,
+ lat = Math.max(Math.min(max, latlng.lat), -max),
+ sin = Math.sin(lat * d);
+
+ return new Point(
+ this.R * latlng.lng * d,
+ this.R * Math.log((1 + sin) / (1 - sin)) / 2);
+ },
+
+ unproject: function (point) {
+ var d = 180 / Math.PI;
+
+ return new LatLng(
+ (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
+ point.x * d / this.R);
+ },
+
+ bounds: (function () {
+ var d = 6378137 * Math.PI;
+ return new Bounds([-d, -d], [d, d]);
+ })()
+};
+
+/*
+ * @class Transformation
+ * @aka L.Transformation
+ *
+ * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
+ * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
+ * the reverse. Used by Leaflet in its projections code.
+ *
+ * @example
+ *
+ * ```js
+ * var transformation = L.transformation(2, 5, -1, 10),
+ * p = L.point(1, 2),
+ * p2 = transformation.transform(p), // L.point(7, 8)
+ * p3 = transformation.untransform(p2); // L.point(1, 2)
+ * ```
+ */
+
+
+// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
+// Creates a `Transformation` object with the given coefficients.
+function Transformation(a, b, c, d) {
+ if (isArray(a)) {
+ // use array properties
+ this._a = a[0];
+ this._b = a[1];
+ this._c = a[2];
+ this._d = a[3];
+ return;
+ }
+ this._a = a;
+ this._b = b;
+ this._c = c;
+ this._d = d;
+}
+
+Transformation.prototype = {
+ // @method transform(point: Point, scale?: Number): Point
+ // Returns a transformed point, optionally multiplied by the given scale.
+ // Only accepts actual `L.Point` instances, not arrays.
+ transform: function (point, scale) { // (Point, Number) -> Point
+ return this._transform(point.clone(), scale);
+ },
+
+ // destructive transform (faster)
+ _transform: function (point, scale) {
+ scale = scale || 1;
+ point.x = scale * (this._a * point.x + this._b);
+ point.y = scale * (this._c * point.y + this._d);
+ return point;
+ },
+
+ // @method untransform(point: Point, scale?: Number): Point
+ // Returns the reverse transformation of the given point, optionally divided
+ // by the given scale. Only accepts actual `L.Point` instances, not arrays.
+ untransform: function (point, scale) {
+ scale = scale || 1;
+ return new Point(
+ (point.x / scale - this._b) / this._a,
+ (point.y / scale - this._d) / this._c);
+ }
+};
+
+// factory L.transformation(a: Number, b: Number, c: Number, d: Number)
+
+// @factory L.transformation(a: Number, b: Number, c: Number, d: Number)
+// Instantiates a Transformation object with the given coefficients.
+
+// @alternative
+// @factory L.transformation(coefficients: Array): Transformation
+// Expects an coefficients array of the form
+// `[a: Number, b: Number, c: Number, d: Number]`.
+
+function toTransformation(a, b, c, d) {
+ return new Transformation(a, b, c, d);
+}
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.EPSG3857
+ *
+ * The most common CRS for online maps, used by almost all free and commercial
+ * tile providers. Uses Spherical Mercator projection. Set in by default in
+ * Map's `crs` option.
+ */
+
+var EPSG3857 = extend({}, Earth, {
+ code: 'EPSG:3857',
+ projection: SphericalMercator,
+
+ transformation: (function () {
+ var scale = 0.5 / (Math.PI * SphericalMercator.R);
+ return toTransformation(scale, 0.5, -scale, 0.5);
+ }())
+});
+
+var EPSG900913 = extend({}, EPSG3857, {
+ code: 'EPSG:900913'
+});
+
+// @namespace SVG; @section
+// There are several static functions which can be called without instantiating L.SVG:
+
+// @function create(name: String): SVGElement
+// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
+// corresponding to the class name passed. For example, using 'line' will return
+// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
+function svgCreate(name) {
+ return document.createElementNS('http://www.w3.org/2000/svg', name);
+}
+
+// @function pointsToPath(rings: Point[], closed: Boolean): String
+// Generates a SVG path string for multiple rings, with each ring turning
+// into "M..L..L.." instructions
+function pointsToPath(rings, closed) {
+ var str = '',
+ i, j, len, len2, points, p;
+
+ for (i = 0, len = rings.length; i < len; i++) {
+ points = rings[i];
+
+ for (j = 0, len2 = points.length; j < len2; j++) {
+ p = points[j];
+ str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
+ }
+
+ // closes the ring for polygons; "x" is VML syntax
+ str += closed ? (svg ? 'z' : 'x') : '';
+ }
+
+ // SVG complains about empty path strings
+ return str || 'M0 0';
+}
+
+/*
+ * @namespace Browser
+ * @aka L.Browser
+ *
+ * A namespace with static properties for browser/feature detection used by Leaflet internally.
+ *
+ * @example
+ *
+ * ```js
+ * if (L.Browser.ielt9) {
+ * alert('Upgrade your browser, dude!');
+ * }
+ * ```
+ */
+
+var style$1 = document.documentElement.style;
+
+// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
+var ie = 'ActiveXObject' in window;
+
+// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.
+var ielt9 = ie && !document.addEventListener;
+
+// @property edge: Boolean; `true` for the Edge web browser.
+var edge = 'msLaunchUri' in navigator && !('documentMode' in document);
+
+// @property webkit: Boolean;
+// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
+var webkit = userAgentContains('webkit');
+
+// @property android: Boolean
+// `true` for any browser running on an Android platform.
+var android = userAgentContains('android');
+
+// @property android23: Boolean; `true` for browsers running on Android 2 or Android 3.
+var android23 = userAgentContains('android 2') || userAgentContains('android 3');
+
+/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
+var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
+// @property androidStock: Boolean; `true` for the Android stock browser (i.e. not Chrome)
+var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
+
+// @property opera: Boolean; `true` for the Opera browser
+var opera = !!window.opera;
+
+// @property chrome: Boolean; `true` for the Chrome browser.
+var chrome = userAgentContains('chrome');
+
+// @property gecko: Boolean; `true` for gecko-based browsers like Firefox.
+var gecko = userAgentContains('gecko') && !webkit && !opera && !ie;
+
+// @property safari: Boolean; `true` for the Safari browser.
+var safari = !chrome && userAgentContains('safari');
+
+var phantom = userAgentContains('phantom');
+
+// @property opera12: Boolean
+// `true` for the Opera browser supporting CSS transforms (version 12 or later).
+var opera12 = 'OTransition' in style$1;
+
+// @property win: Boolean; `true` when the browser is running in a Windows platform
+var win = navigator.platform.indexOf('Win') === 0;
+
+// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
+var ie3d = ie && ('transition' in style$1);
+
+// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
+var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
+
+// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
+var gecko3d = 'MozPerspective' in style$1;
+
+// @property any3d: Boolean
+// `true` for all browsers supporting CSS transforms.
+var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
+
+// @property mobile: Boolean; `true` for all browsers running in a mobile device.
+var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');
+
+// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.
+var mobileWebkit = mobile && webkit;
+
+// @property mobileWebkit3d: Boolean
+// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
+var mobileWebkit3d = mobile && webkit3d;
+
+// @property msPointer: Boolean
+// `true` for browsers implementing the Microsoft touch events model (notably IE10).
+var msPointer = !window.PointerEvent && window.MSPointerEvent;
+
+// @property pointer: Boolean
+// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
+var pointer = !!(window.PointerEvent || msPointer);
+
+// @property touch: Boolean
+// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
+// This does not necessarily mean that the browser is running in a computer with
+// a touchscreen, it only means that the browser is capable of understanding
+// touch events.
+var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
+ (window.DocumentTouch && document instanceof window.DocumentTouch));
+
+// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
+var mobileOpera = mobile && opera;
+
+// @property mobileGecko: Boolean
+// `true` for gecko-based browsers running in a mobile device.
+var mobileGecko = mobile && gecko;
+
+// @property retina: Boolean
+// `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%.
+var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;
+
+
+// @property canvas: Boolean
+// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
+var canvas = (function () {
+ return !!document.createElement('canvas').getContext;
+}());
+
+// @property svg: Boolean
+// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
+var svg = !!(document.createElementNS && svgCreate('svg').createSVGRect);
+
+// @property vml: Boolean
+// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
+var vml = !svg && (function () {
+ try {
+ var div = document.createElement('div');
+ div.innerHTML = '<v:shape adj="1"/>';
+
+ var shape = div.firstChild;
+ shape.style.behavior = 'url(#default#VML)';
+
+ return shape && (typeof shape.adj === 'object');
+
+ } catch (e) {
+ return false;
+ }
+}());
+
+
+function userAgentContains(str) {
+ return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
+}
+
+
+var Browser = (Object.freeze || Object)({
+ ie: ie,
+ ielt9: ielt9,
+ edge: edge,
+ webkit: webkit,
+ android: android,
+ android23: android23,
+ androidStock: androidStock,
+ opera: opera,
+ chrome: chrome,
+ gecko: gecko,
+ safari: safari,
+ phantom: phantom,
+ opera12: opera12,
+ win: win,
+ ie3d: ie3d,
+ webkit3d: webkit3d,
+ gecko3d: gecko3d,
+ any3d: any3d,
+ mobile: mobile,
+ mobileWebkit: mobileWebkit,
+ mobileWebkit3d: mobileWebkit3d,
+ msPointer: msPointer,
+ pointer: pointer,
+ touch: touch,
+ mobileOpera: mobileOpera,
+ mobileGecko: mobileGecko,
+ retina: retina,
+ canvas: canvas,
+ svg: svg,
+ vml: vml
+});
+
+/*
+ * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
+ */
+
+
+var POINTER_DOWN = msPointer ? 'MSPointerDown' : 'pointerdown';
+var POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove';
+var POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup';
+var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
+var TAG_WHITE_LIST = ['INPUT', 'SELECT', 'OPTION'];
+
+var _pointers = {};
+var _pointerDocListener = false;
+
+// DomEvent.DoubleTap needs to know about this
+var _pointersCount = 0;
+
+// Provides a touch events wrapper for (ms)pointer events.
+// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
+
+function addPointerListener(obj, type, handler, id) {
+ if (type === 'touchstart') {
+ _addPointerStart(obj, handler, id);
+
+ } else if (type === 'touchmove') {
+ _addPointerMove(obj, handler, id);
+
+ } else if (type === 'touchend') {
+ _addPointerEnd(obj, handler, id);
+ }
+
+ return this;
+}
+
+function removePointerListener(obj, type, id) {
+ var handler = obj['_leaflet_' + type + id];
+
+ if (type === 'touchstart') {
+ obj.removeEventListener(POINTER_DOWN, handler, false);
+
+ } else if (type === 'touchmove') {
+ obj.removeEventListener(POINTER_MOVE, handler, false);
+
+ } else if (type === 'touchend') {
+ obj.removeEventListener(POINTER_UP, handler, false);
+ obj.removeEventListener(POINTER_CANCEL, handler, false);
+ }
+
+ return this;
+}
+
+function _addPointerStart(obj, handler, id) {
+ var onDown = bind(function (e) {
+ if (e.pointerType !== 'mouse' && e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
+ // In IE11, some touch events needs to fire for form controls, or
+ // the controls will stop working. We keep a whitelist of tag names that
+ // need these events. For other target tags, we prevent default on the event.
+ if (TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) {
+ preventDefault(e);
+ } else {
+ return;
+ }
+ }
+
+ _handlePointer(e, handler);
+ });
+
+ obj['_leaflet_touchstart' + id] = onDown;
+ obj.addEventListener(POINTER_DOWN, onDown, false);
+
+ // need to keep track of what pointers and how many are active to provide e.touches emulation
+ if (!_pointerDocListener) {
+ // we listen documentElement as any drags that end by moving the touch off the screen get fired there
+ document.documentElement.addEventListener(POINTER_DOWN, _globalPointerDown, true);
+ document.documentElement.addEventListener(POINTER_MOVE, _globalPointerMove, true);
+ document.documentElement.addEventListener(POINTER_UP, _globalPointerUp, true);
+ document.documentElement.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
+
+ _pointerDocListener = true;
+ }
+}
+
+function _globalPointerDown(e) {
+ _pointers[e.pointerId] = e;
+ _pointersCount++;
+}
+
+function _globalPointerMove(e) {
+ if (_pointers[e.pointerId]) {
+ _pointers[e.pointerId] = e;
+ }
+}
+
+function _globalPointerUp(e) {
+ delete _pointers[e.pointerId];
+ _pointersCount--;
+}
+
+function _handlePointer(e, handler) {
+ e.touches = [];
+ for (var i in _pointers) {
+ e.touches.push(_pointers[i]);
+ }
+ e.changedTouches = [e];
+
+ handler(e);
+}
+
+function _addPointerMove(obj, handler, id) {
+ var onMove = function (e) {
+ // don't fire touch moves when mouse isn't down
+ if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
+
+ _handlePointer(e, handler);
+ };
+
+ obj['_leaflet_touchmove' + id] = onMove;
+ obj.addEventListener(POINTER_MOVE, onMove, false);
+}
+
+function _addPointerEnd(obj, handler, id) {
+ var onUp = function (e) {
+ _handlePointer(e, handler);
+ };
+
+ obj['_leaflet_touchend' + id] = onUp;
+ obj.addEventListener(POINTER_UP, onUp, false);
+ obj.addEventListener(POINTER_CANCEL, onUp, false);
+}
+
+/*
+ * Extends the event handling code with double tap support for mobile browsers.
+ */
+
+var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
+var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
+var _pre = '_leaflet_';
+
+// inspired by Zepto touch code by Thomas Fuchs
+function addDoubleTapListener(obj, handler, id) {
+ var last, touch$$1,
+ doubleTap = false,
+ delay = 250;
+
+ function onTouchStart(e) {
+ var count;
+
+ if (pointer) {
+ if ((!edge) || e.pointerType === 'mouse') { return; }
+ count = _pointersCount;
+ } else {
+ count = e.touches.length;
+ }
+
+ if (count > 1) { return; }
+
+ var now = Date.now(),
+ delta = now - (last || now);
+
+ touch$$1 = e.touches ? e.touches[0] : e;
+ doubleTap = (delta > 0 && delta <= delay);
+ last = now;
+ }
+
+ function onTouchEnd(e) {
+ if (doubleTap && !touch$$1.cancelBubble) {
+ if (pointer) {
+ if ((!edge) || e.pointerType === 'mouse') { return; }
+ // work around .type being readonly with MSPointer* events
+ var newTouch = {},
+ prop, i;
+
+ for (i in touch$$1) {
+ prop = touch$$1[i];
+ newTouch[i] = prop && prop.bind ? prop.bind(touch$$1) : prop;
+ }
+ touch$$1 = newTouch;
+ }
+ touch$$1.type = 'dblclick';
+ handler(touch$$1);
+ last = null;
+ }
+ }
+
+ obj[_pre + _touchstart + id] = onTouchStart;
+ obj[_pre + _touchend + id] = onTouchEnd;
+ obj[_pre + 'dblclick' + id] = handler;
+
+ obj.addEventListener(_touchstart, onTouchStart, false);
+ obj.addEventListener(_touchend, onTouchEnd, false);
+
+ // On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),
+ // the browser doesn't fire touchend/pointerup events but does fire
+ // native dblclicks. See #4127.
+ // Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.
+ obj.addEventListener('dblclick', handler, false);
+
+ return this;
+}
+
+function removeDoubleTapListener(obj, id) {
+ var touchstart = obj[_pre + _touchstart + id],
+ touchend = obj[_pre + _touchend + id],
+ dblclick = obj[_pre + 'dblclick' + id];
+
+ obj.removeEventListener(_touchstart, touchstart, false);
+ obj.removeEventListener(_touchend, touchend, false);
+ if (!edge) {
+ obj.removeEventListener('dblclick', dblclick, false);
+ }
+
+ return this;
+}
+
+/*
+ * @namespace DomUtil
+ *
+ * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
+ * tree, used by Leaflet internally.
+ *
+ * Most functions expecting or returning a `HTMLElement` also work for
+ * SVG elements. The only difference is that classes refer to CSS classes
+ * in HTML and SVG classes in SVG.
+ */
+
+
+// @property TRANSFORM: String
+// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).
+var TRANSFORM = testProp(
+ ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
+
+// webkitTransition comes first because some browser versions that drop vendor prefix don't do
+// the same for the transitionend event, in particular the Android 4.1 stock browser
+
+// @property TRANSITION: String
+// Vendor-prefixed transition style name.
+var TRANSITION = testProp(
+ ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
+
+// @property TRANSITION_END: String
+// Vendor-prefixed transitionend event name.
+var TRANSITION_END =
+ TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';
+
+
+// @function get(id: String|HTMLElement): HTMLElement
+// Returns an element given its DOM id, or returns the element itself
+// if it was passed directly.
+function get(id) {
+ return typeof id === 'string' ? document.getElementById(id) : id;
+}
+
+// @function getStyle(el: HTMLElement, styleAttrib: String): String
+// Returns the value for a certain style attribute on an element,
+// including computed values or values set through CSS.
+function getStyle(el, style) {
+ var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
+
+ if ((!value || value === 'auto') && document.defaultView) {
+ var css = document.defaultView.getComputedStyle(el, null);
+ value = css ? css[style] : null;
+ }
+ return value === 'auto' ? null : value;
+}
+
+// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
+// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
+function create$1(tagName, className, container) {
+ var el = document.createElement(tagName);
+ el.className = className || '';
+
+ if (container) {
+ container.appendChild(el);
+ }
+ return el;
+}
+
+// @function remove(el: HTMLElement)
+// Removes `el` from its parent element
+function remove(el) {
+ var parent = el.parentNode;
+ if (parent) {
+ parent.removeChild(el);
+ }
+}
+
+// @function empty(el: HTMLElement)
+// Removes all of `el`'s children elements from `el`
+function empty(el) {
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
+}
+
+// @function toFront(el: HTMLElement)
+// Makes `el` the last child of its parent, so it renders in front of the other children.
+function toFront(el) {
+ var parent = el.parentNode;
+ if (parent && parent.lastChild !== el) {
+ parent.appendChild(el);
+ }
+}
+
+// @function toBack(el: HTMLElement)
+// Makes `el` the first child of its parent, so it renders behind the other children.
+function toBack(el) {
+ var parent = el.parentNode;
+ if (parent && parent.firstChild !== el) {
+ parent.insertBefore(el, parent.firstChild);
+ }
+}
+
+// @function hasClass(el: HTMLElement, name: String): Boolean
+// Returns `true` if the element's class attribute contains `name`.
+function hasClass(el, name) {
+ if (el.classList !== undefined) {
+ return el.classList.contains(name);
+ }
+ var className = getClass(el);
+ return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
+}
+
+// @function addClass(el: HTMLElement, name: String)
+// Adds `name` to the element's class attribute.
+function addClass(el, name) {
+ if (el.classList !== undefined) {
+ var classes = splitWords(name);
+ for (var i = 0, len = classes.length; i < len; i++) {
+ el.classList.add(classes[i]);
+ }
+ } else if (!hasClass(el, name)) {
+ var className = getClass(el);
+ setClass(el, (className ? className + ' ' : '') + name);
+ }
+}
+
+// @function removeClass(el: HTMLElement, name: String)
+// Removes `name` from the element's class attribute.
+function removeClass(el, name) {
+ if (el.classList !== undefined) {
+ el.classList.remove(name);
+ } else {
+ setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
+ }
+}
+
+// @function setClass(el: HTMLElement, name: String)
+// Sets the element's class.
+function setClass(el, name) {
+ if (el.className.baseVal === undefined) {
+ el.className = name;
+ } else {
+ // in case of SVG element
+ el.className.baseVal = name;
+ }
+}
+
+// @function getClass(el: HTMLElement): String
+// Returns the element's class.
+function getClass(el) {
+ // Check if the element is an SVGElementInstance and use the correspondingElement instead
+ // (Required for linked SVG elements in IE11.)
+ if (el.correspondingElement) {
+ el = el.correspondingElement;
+ }
+ return el.className.baseVal === undefined ? el.className : el.className.baseVal;
+}
+
+// @function setOpacity(el: HTMLElement, opacity: Number)
+// Set the opacity of an element (including old IE support).
+// `opacity` must be a number from `0` to `1`.
+function setOpacity(el, value) {
+ if ('opacity' in el.style) {
+ el.style.opacity = value;
+ } else if ('filter' in el.style) {
+ _setOpacityIE(el, value);
+ }
+}
+
+function _setOpacityIE(el, value) {
+ var filter = false,
+ filterName = 'DXImageTransform.Microsoft.Alpha';
+
+ // filters collection throws an error if we try to retrieve a filter that doesn't exist
+ try {
+ filter = el.filters.item(filterName);
+ } catch (e) {
+ // don't set opacity to 1 if we haven't already set an opacity,
+ // it isn't needed and breaks transparent pngs.
+ if (value === 1) { return; }
+ }
+
+ value = Math.round(value * 100);
+
+ if (filter) {
+ filter.Enabled = (value !== 100);
+ filter.Opacity = value;
+ } else {
+ el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
+ }
+}
+
+// @function testProp(props: String[]): String|false
+// Goes through the array of style names and returns the first name
+// that is a valid style name for an element. If no such name is found,
+// it returns false. Useful for vendor-prefixed styles like `transform`.
+function testProp(props) {
+ var style = document.documentElement.style;
+
+ for (var i = 0; i < props.length; i++) {
+ if (props[i] in style) {
+ return props[i];
+ }
+ }
+ return false;
+}
+
+// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
+// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
+// and optionally scaled by `scale`. Does not have an effect if the
+// browser doesn't support 3D CSS transforms.
+function setTransform(el, offset, scale) {
+ var pos = offset || new Point(0, 0);
+
+ el.style[TRANSFORM] =
+ (ie3d ?
+ 'translate(' + pos.x + 'px,' + pos.y + 'px)' :
+ 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
+ (scale ? ' scale(' + scale + ')' : '');
+}
+
+// @function setPosition(el: HTMLElement, position: Point)
+// Sets the position of `el` to coordinates specified by `position`,
+// using CSS translate or top/left positioning depending on the browser
+// (used by Leaflet internally to position its layers).
+function setPosition(el, point) {
+
+ /*eslint-disable */
+ el._leaflet_pos = point;
+ /* eslint-enable */
+
+ if (any3d) {
+ setTransform(el, point);
+ } else {
+ el.style.left = point.x + 'px';
+ el.style.top = point.y + 'px';
+ }
+}
+
+// @function getPosition(el: HTMLElement): Point
+// Returns the coordinates of an element previously positioned with setPosition.
+function getPosition(el) {
+ // this method is only used for elements previously positioned using setPosition,
+ // so it's safe to cache the position for performance
+
+ return el._leaflet_pos || new Point(0, 0);
+}
+
+// @function disableTextSelection()
+// Prevents the user from generating `selectstart` DOM events, usually generated
+// when the user drags the mouse through a page with text. Used internally
+// by Leaflet to override the behaviour of any click-and-drag interaction on
+// the map. Affects drag interactions on the whole document.
+
+// @function enableTextSelection()
+// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
+var disableTextSelection;
+var enableTextSelection;
+var _userSelect;
+if ('onselectstart' in document) {
+ disableTextSelection = function () {
+ on(window, 'selectstart', preventDefault);
+ };
+ enableTextSelection = function () {
+ off(window, 'selectstart', preventDefault);
+ };
+} else {
+ var userSelectProperty = testProp(
+ ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
+
+ disableTextSelection = function () {
+ if (userSelectProperty) {
+ var style = document.documentElement.style;
+ _userSelect = style[userSelectProperty];
+ style[userSelectProperty] = 'none';
+ }
+ };
+ enableTextSelection = function () {
+ if (userSelectProperty) {
+ document.documentElement.style[userSelectProperty] = _userSelect;
+ _userSelect = undefined;
+ }
+ };
+}
+
+// @function disableImageDrag()
+// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
+// for `dragstart` DOM events, usually generated when the user drags an image.
+function disableImageDrag() {
+ on(window, 'dragstart', preventDefault);
+}
+
+// @function enableImageDrag()
+// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
+function enableImageDrag() {
+ off(window, 'dragstart', preventDefault);
+}
+
+var _outlineElement;
+var _outlineStyle;
+// @function preventOutline(el: HTMLElement)
+// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
+// of the element `el` invisible. Used internally by Leaflet to prevent
+// focusable elements from displaying an outline when the user performs a
+// drag interaction on them.
+function preventOutline(element) {
+ while (element.tabIndex === -1) {
+ element = element.parentNode;
+ }
+ if (!element.style) { return; }
+ restoreOutline();
+ _outlineElement = element;
+ _outlineStyle = element.style.outline;
+ element.style.outline = 'none';
+ on(window, 'keydown', restoreOutline);
+}
+
+// @function restoreOutline()
+// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
+function restoreOutline() {
+ if (!_outlineElement) { return; }
+ _outlineElement.style.outline = _outlineStyle;
+ _outlineElement = undefined;
+ _outlineStyle = undefined;
+ off(window, 'keydown', restoreOutline);
+}
+
+// @function getSizedParentNode(el: HTMLElement): HTMLElement
+// Finds the closest parent node which size (width and height) is not null.
+function getSizedParentNode(element) {
+ do {
+ element = element.parentNode;
+ } while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);
+ return element;
+}
+
+// @function getScale(el: HTMLElement): Object
+// Computes the CSS scale currently applied on the element.
+// Returns an object with `x` and `y` members as horizontal and vertical scales respectively,
+// and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
+function getScale(element) {
+ var rect = element.getBoundingClientRect(); // Read-only in old browsers.
+
+ return {
+ x: rect.width / element.offsetWidth || 1,
+ y: rect.height / element.offsetHeight || 1,
+ boundingClientRect: rect
+ };
+}
+
+
+var DomUtil = (Object.freeze || Object)({
+ TRANSFORM: TRANSFORM,
+ TRANSITION: TRANSITION,
+ TRANSITION_END: TRANSITION_END,
+ get: get,
+ getStyle: getStyle,
+ create: create$1,
+ remove: remove,
+ empty: empty,
+ toFront: toFront,
+ toBack: toBack,
+ hasClass: hasClass,
+ addClass: addClass,
+ removeClass: removeClass,
+ setClass: setClass,
+ getClass: getClass,
+ setOpacity: setOpacity,
+ testProp: testProp,
+ setTransform: setTransform,
+ setPosition: setPosition,
+ getPosition: getPosition,
+ disableTextSelection: disableTextSelection,
+ enableTextSelection: enableTextSelection,
+ disableImageDrag: disableImageDrag,
+ enableImageDrag: enableImageDrag,
+ preventOutline: preventOutline,
+ restoreOutline: restoreOutline,
+ getSizedParentNode: getSizedParentNode,
+ getScale: getScale
+});
+
+/*
+ * @namespace DomEvent
+ * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
+ */
+
+// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
+
+// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
+// Adds a listener function (`fn`) to a particular DOM event type of the
+// element `el`. You can optionally specify the context of the listener
+// (object the `this` keyword will point to). You can also pass several
+// space-separated types (e.g. `'click dblclick'`).
+
+// @alternative
+// @function on(el: HTMLElement, eventMap: Object, context?: Object): this
+// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
+function on(obj, types, fn, context) {
+
+ if (typeof types === 'object') {
+ for (var type in types) {
+ addOne(obj, type, types[type], fn);
+ }
+ } else {
+ types = splitWords(types);
+
+ for (var i = 0, len = types.length; i < len; i++) {
+ addOne(obj, types[i], fn, context);
+ }
+ }
+
+ return this;
+}
+
+var eventsKey = '_leaflet_events';
+
+// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
+// Removes a previously added listener function.
+// Note that if you passed a custom context to on, you must pass the same
+// context to `off` in order to remove the listener.
+
+// @alternative
+// @function off(el: HTMLElement, eventMap: Object, context?: Object): this
+// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
+function off(obj, types, fn, context) {
+
+ if (typeof types === 'object') {
+ for (var type in types) {
+ removeOne(obj, type, types[type], fn);
+ }
+ } else if (types) {
+ types = splitWords(types);
+
+ for (var i = 0, len = types.length; i < len; i++) {
+ removeOne(obj, types[i], fn, context);
+ }
+ } else {
+ for (var j in obj[eventsKey]) {
+ removeOne(obj, j, obj[eventsKey][j]);
+ }
+ delete obj[eventsKey];
+ }
+
+ return this;
+}
+
+function addOne(obj, type, fn, context) {
+ var id = type + stamp(fn) + (context ? '_' + stamp(context) : '');
+
+ if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
+
+ var handler = function (e) {
+ return fn.call(context || obj, e || window.event);
+ };
+
+ var originalHandler = handler;
+
+ if (pointer && type.indexOf('touch') === 0) {
+ // Needs DomEvent.Pointer.js
+ addPointerListener(obj, type, handler, id);
+
+ } else if (touch && (type === 'dblclick') && addDoubleTapListener &&
+ !(pointer && chrome)) {
+ // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener
+ // See #5180
+ addDoubleTapListener(obj, handler, id);
+
+ } else if ('addEventListener' in obj) {
+
+ if (type === 'mousewheel') {
+ obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
+
+ } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
+ handler = function (e) {
+ e = e || window.event;
+ if (isExternalTarget(obj, e)) {
+ originalHandler(e);
+ }
+ };
+ obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false);
+
+ } else {
+ if (type === 'click' && android) {
+ handler = function (e) {
+ filterClick(e, originalHandler);
+ };
+ }
+ obj.addEventListener(type, handler, false);
+ }
+
+ } else if ('attachEvent' in obj) {
+ obj.attachEvent('on' + type, handler);
+ }
+
+ obj[eventsKey] = obj[eventsKey] || {};
+ obj[eventsKey][id] = handler;
+}
+
+function removeOne(obj, type, fn, context) {
+
+ var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''),
+ handler = obj[eventsKey] && obj[eventsKey][id];
+
+ if (!handler) { return this; }
+
+ if (pointer && type.indexOf('touch') === 0) {
+ removePointerListener(obj, type, id);
+
+ } else if (touch && (type === 'dblclick') && removeDoubleTapListener &&
+ !(pointer && chrome)) {
+ removeDoubleTapListener(obj, id);
+
+ } else if ('removeEventListener' in obj) {
+
+ if (type === 'mousewheel') {
+ obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
+
+ } else {
+ obj.removeEventListener(
+ type === 'mouseenter' ? 'mouseover' :
+ type === 'mouseleave' ? 'mouseout' : type, handler, false);
+ }
+
+ } else if ('detachEvent' in obj) {
+ obj.detachEvent('on' + type, handler);
+ }
+
+ obj[eventsKey][id] = null;
+}
+
+// @function stopPropagation(ev: DOMEvent): this
+// Stop the given event from propagation to parent elements. Used inside the listener functions:
+// ```js
+// L.DomEvent.on(div, 'click', function (ev) {
+// L.DomEvent.stopPropagation(ev);
+// });
+// ```
+function stopPropagation(e) {
+
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ } else if (e.originalEvent) { // In case of Leaflet event.
+ e.originalEvent._stopped = true;
+ } else {
+ e.cancelBubble = true;
+ }
+ skipped(e);
+
+ return this;
+}
+
+// @function disableScrollPropagation(el: HTMLElement): this
+// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants).
+function disableScrollPropagation(el) {
+ addOne(el, 'mousewheel', stopPropagation);
+ return this;
+}
+
+// @function disableClickPropagation(el: HTMLElement): this
+// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
+// `'mousedown'` and `'touchstart'` events (plus browser variants).
+function disableClickPropagation(el) {
+ on(el, 'mousedown touchstart dblclick', stopPropagation);
+ addOne(el, 'click', fakeStop);
+ return this;
+}
+
+// @function preventDefault(ev: DOMEvent): this
+// Prevents the default action of the DOM Event `ev` from happening (such as
+// following a link in the href of the a element, or doing a POST request
+// with page reload when a `<form>` is submitted).
+// Use it inside listener functions.
+function preventDefault(e) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ return this;
+}
+
+// @function stop(ev: DOMEvent): this
+// Does `stopPropagation` and `preventDefault` at the same time.
+function stop(e) {
+ preventDefault(e);
+ stopPropagation(e);
+ return this;
+}
+
+// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
+// Gets normalized mouse position from a DOM event relative to the
+// `container` (border excluded) or to the whole page if not specified.
+function getMousePosition(e, container) {
+ if (!container) {
+ return new Point(e.clientX, e.clientY);
+ }
+
+ var scale = getScale(container),
+ offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y)
+
+ return new Point(
+ // offset.left/top values are in page scale (like clientX/Y),
+ // whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
+ (e.clientX - offset.left) / scale.x - container.clientLeft,
+ (e.clientY - offset.top) / scale.y - container.clientTop
+ );
+}
+
+// Chrome on Win scrolls double the pixels as in other platforms (see #4538),
+// and Firefox scrolls device pixels, not CSS pixels
+var wheelPxFactor =
+ (win && chrome) ? 2 * window.devicePixelRatio :
+ gecko ? window.devicePixelRatio : 1;
+
+// @function getWheelDelta(ev: DOMEvent): Number
+// Gets normalized wheel delta from a mousewheel DOM event, in vertical
+// pixels scrolled (negative if scrolling down).
+// Events from pointing devices without precise scrolling are mapped to
+// a best guess of 60 pixels.
+function getWheelDelta(e) {
+ return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
+ (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
+ (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
+ (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
+ (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events
+ e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
+ (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
+ e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
+ 0;
+}
+
+var skipEvents = {};
+
+function fakeStop(e) {
+ // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e)
+ skipEvents[e.type] = true;
+}
+
+function skipped(e) {
+ var events = skipEvents[e.type];
+ // reset when checking, as it's only used in map container and propagates outside of the map
+ skipEvents[e.type] = false;
+ return events;
+}
+
+// check if element really left/entered the event target (for mouseenter/mouseleave)
+function isExternalTarget(el, e) {
+
+ var related = e.relatedTarget;
+
+ if (!related) { return true; }
+
+ try {
+ while (related && (related !== el)) {
+ related = related.parentNode;
+ }
+ } catch (err) {
+ return false;
+ }
+ return (related !== el);
+}
+
+var lastClick;
+
+// this is a horrible workaround for a bug in Android where a single touch triggers two click events
+function filterClick(e, handler) {
+ var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)),
+ elapsed = lastClick && (timeStamp - lastClick);
+
+ // are they closer together than 500ms yet more than 100ms?
+ // Android typically triggers them ~300ms apart while multiple listeners
+ // on the same event should be triggered far faster;
+ // or check if click is simulated on the element, and if it is, reject any non-simulated events
+
+ if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
+ stop(e);
+ return;
+ }
+ lastClick = timeStamp;
+
+ handler(e);
+}
+
+
+
+
+var DomEvent = (Object.freeze || Object)({
+ on: on,
+ off: off,
+ stopPropagation: stopPropagation,
+ disableScrollPropagation: disableScrollPropagation,
+ disableClickPropagation: disableClickPropagation,
+ preventDefault: preventDefault,
+ stop: stop,
+ getMousePosition: getMousePosition,
+ getWheelDelta: getWheelDelta,
+ fakeStop: fakeStop,
+ skipped: skipped,
+ isExternalTarget: isExternalTarget,
+ addListener: on,
+ removeListener: off
+});
+
+/*
+ * @class PosAnimation
+ * @aka L.PosAnimation
+ * @inherits Evented
+ * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
+ *
+ * @example
+ * ```js
+ * var fx = new L.PosAnimation();
+ * fx.run(el, [300, 500], 0.5);
+ * ```
+ *
+ * @constructor L.PosAnimation()
+ * Creates a `PosAnimation` object.
+ *
+ */
+
+var PosAnimation = Evented.extend({
+
+ // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
+ // Run an animation of a given element to a new position, optionally setting
+ // duration in seconds (`0.25` by default) and easing linearity factor (3rd
+ // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
+ // `0.5` by default).
+ run: function (el, newPos, duration, easeLinearity) {
+ this.stop();
+
+ this._el = el;
+ this._inProgress = true;
+ this._duration = duration || 0.25;
+ this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
+
+ this._startPos = getPosition(el);
+ this._offset = newPos.subtract(this._startPos);
+ this._startTime = +new Date();
+
+ // @event start: Event
+ // Fired when the animation starts
+ this.fire('start');
+
+ this._animate();
+ },
+
+ // @method stop()
+ // Stops the animation (if currently running).
+ stop: function () {
+ if (!this._inProgress) { return; }
+
+ this._step(true);
+ this._complete();
+ },
+
+ _animate: function () {
+ // animation loop
+ this._animId = requestAnimFrame(this._animate, this);
+ this._step();
+ },
+
+ _step: function (round) {
+ var elapsed = (+new Date()) - this._startTime,
+ duration = this._duration * 1000;
+
+ if (elapsed < duration) {
+ this._runFrame(this._easeOut(elapsed / duration), round);
+ } else {
+ this._runFrame(1);
+ this._complete();
+ }
+ },
+
+ _runFrame: function (progress, round) {
+ var pos = this._startPos.add(this._offset.multiplyBy(progress));
+ if (round) {
+ pos._round();
+ }
+ setPosition(this._el, pos);
+
+ // @event step: Event
+ // Fired continuously during the animation.
+ this.fire('step');
+ },
+
+ _complete: function () {
+ cancelAnimFrame(this._animId);
+
+ this._inProgress = false;
+ // @event end: Event
+ // Fired when the animation ends.
+ this.fire('end');
+ },
+
+ _easeOut: function (t) {
+ return 1 - Math.pow(1 - t, this._easeOutPower);
+ }
+});
+
+/*
+ * @class Map
+ * @aka L.Map
+ * @inherits Evented
+ *
+ * The central class of the API — it is used to create a map on a page and manipulate it.
+ *
+ * @example
+ *
+ * ```js
+ * // initialize the map on the "map" div with a given center and zoom
+ * var map = L.map('map', {
+ * center: [51.505, -0.09],
+ * zoom: 13
+ * });
+ * ```
+ *
+ */
+
+var Map = Evented.extend({
+
+ options: {
+ // @section Map State Options
+ // @option crs: CRS = L.CRS.EPSG3857
+ // The [Coordinate Reference System](#crs) to use. Don't change this if you're not
+ // sure what it means.
+ crs: EPSG3857,
+
+ // @option center: LatLng = undefined
+ // Initial geographic center of the map
+ center: undefined,
+
+ // @option zoom: Number = undefined
+ // Initial map zoom level
+ zoom: undefined,
+
+ // @option minZoom: Number = *
+ // Minimum zoom level of the map.
+ // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
+ // the lowest of their `minZoom` options will be used instead.
+ minZoom: undefined,
+
+ // @option maxZoom: Number = *
+ // Maximum zoom level of the map.
+ // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
+ // the highest of their `maxZoom` options will be used instead.
+ maxZoom: undefined,
+
+ // @option layers: Layer[] = []
+ // Array of layers that will be added to the map initially
+ layers: [],
+
+ // @option maxBounds: LatLngBounds = null
+ // When this option is set, the map restricts the view to the given
+ // geographical bounds, bouncing the user back if the user tries to pan
+ // outside the view. To set the restriction dynamically, use
+ // [`setMaxBounds`](#map-setmaxbounds) method.
+ maxBounds: undefined,
+
+ // @option renderer: Renderer = *
+ // The default method for drawing vector layers on the map. `L.SVG`
+ // or `L.Canvas` by default depending on browser support.
+ renderer: undefined,
+
+
+ // @section Animation Options
+ // @option zoomAnimation: Boolean = true
+ // Whether the map zoom animation is enabled. By default it's enabled
+ // in all browsers that support CSS3 Transitions except Android.
+ zoomAnimation: true,
+
+ // @option zoomAnimationThreshold: Number = 4
+ // Won't animate zoom if the zoom difference exceeds this value.
+ zoomAnimationThreshold: 4,
+
+ // @option fadeAnimation: Boolean = true
+ // Whether the tile fade animation is enabled. By default it's enabled
+ // in all browsers that support CSS3 Transitions except Android.
+ fadeAnimation: true,
+
+ // @option markerZoomAnimation: Boolean = true
+ // Whether markers animate their zoom with the zoom animation, if disabled
+ // they will disappear for the length of the animation. By default it's
+ // enabled in all browsers that support CSS3 Transitions except Android.
+ markerZoomAnimation: true,
+
+ // @option transform3DLimit: Number = 2^23
+ // Defines the maximum size of a CSS translation transform. The default
+ // value should not be changed unless a web browser positions layers in
+ // the wrong place after doing a large `panBy`.
+ transform3DLimit: 8388608, // Precision limit of a 32-bit float
+
+ // @section Interaction Options
+ // @option zoomSnap: Number = 1
+ // Forces the map's zoom level to always be a multiple of this, particularly
+ // right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
+ // By default, the zoom level snaps to the nearest integer; lower values
+ // (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
+ // means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
+ zoomSnap: 1,
+
+ // @option zoomDelta: Number = 1
+ // Controls how much the map's zoom level will change after a
+ // [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
+ // or `-` on the keyboard, or using the [zoom controls](#control-zoom).
+ // Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
+ zoomDelta: 1,
+
+ // @option trackResize: Boolean = true
+ // Whether the map automatically handles browser window resize to update itself.
+ trackResize: true
+ },
+
+ initialize: function (id, options) { // (HTMLElement or String, Object)
+ options = setOptions(this, options);
+
+ // Make sure to assign internal flags at the beginning,
+ // to avoid inconsistent state in some edge cases.
+ this._handlers = [];
+ this._layers = {};
+ this._zoomBoundLayers = {};
+ this._sizeChanged = true;
+
+ this._initContainer(id);
+ this._initLayout();
+
+ // hack for https://github.com/Leaflet/Leaflet/issues/1980
+ this._onResize = bind(this._onResize, this);
+
+ this._initEvents();
+
+ if (options.maxBounds) {
+ this.setMaxBounds(options.maxBounds);
+ }
+
+ if (options.zoom !== undefined) {
+ this._zoom = this._limitZoom(options.zoom);
+ }
+
+ if (options.center && options.zoom !== undefined) {
+ this.setView(toLatLng(options.center), options.zoom, {reset: true});
+ }
+
+ this.callInitHooks();
+
+ // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
+ this._zoomAnimated = TRANSITION && any3d && !mobileOpera &&
+ this.options.zoomAnimation;
+
+ // zoom transitions run with the same duration for all layers, so if one of transitionend events
+ // happens after starting zoom animation (propagating to the map pane), we know that it ended globally
+ if (this._zoomAnimated) {
+ this._createAnimProxy();
+ on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
+ }
+
+ this._addLayers(this.options.layers);
+ },
+
+
+ // @section Methods for modifying map state
+
+ // @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
+ // Sets the view of the map (geographical center and zoom) with the given
+ // animation options.
+ setView: function (center, zoom, options) {
+
+ zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
+ center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
+ options = options || {};
+
+ this._stop();
+
+ if (this._loaded && !options.reset && options !== true) {
+
+ if (options.animate !== undefined) {
+ options.zoom = extend({animate: options.animate}, options.zoom);
+ options.pan = extend({animate: options.animate, duration: options.duration}, options.pan);
+ }
+
+ // try animating pan or zoom
+ var moved = (this._zoom !== zoom) ?
+ this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
+ this._tryAnimatedPan(center, options.pan);
+
+ if (moved) {
+ // prevent resize handler call, the view will refresh after animation anyway
+ clearTimeout(this._sizeTimer);
+ return this;
+ }
+ }
+
+ // animation didn't start, just reset the map view
+ this._resetView(center, zoom);
+
+ return this;
+ },
+
+ // @method setZoom(zoom: Number, options?: Zoom/pan options): this
+ // Sets the zoom of the map.
+ setZoom: function (zoom, options) {
+ if (!this._loaded) {
+ this._zoom = zoom;
+ return this;
+ }
+ return this.setView(this.getCenter(), zoom, {zoom: options});
+ },
+
+ // @method zoomIn(delta?: Number, options?: Zoom options): this
+ // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
+ zoomIn: function (delta, options) {
+ delta = delta || (any3d ? this.options.zoomDelta : 1);
+ return this.setZoom(this._zoom + delta, options);
+ },
+
+ // @method zoomOut(delta?: Number, options?: Zoom options): this
+ // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
+ zoomOut: function (delta, options) {
+ delta = delta || (any3d ? this.options.zoomDelta : 1);
+ return this.setZoom(this._zoom - delta, options);
+ },
+
+ // @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
+ // Zooms the map while keeping a specified geographical point on the map
+ // stationary (e.g. used internally for scroll zoom and double-click zoom).
+ // @alternative
+ // @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
+ // Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
+ setZoomAround: function (latlng, zoom, options) {
+ var scale = this.getZoomScale(zoom),
+ viewHalf = this.getSize().divideBy(2),
+ containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
+
+ centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
+ newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
+
+ return this.setView(newCenter, zoom, {zoom: options});
+ },
+
+ _getBoundsCenterZoom: function (bounds, options) {
+
+ options = options || {};
+ bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
+
+ var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
+ paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
+
+ zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
+
+ zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
+
+ if (zoom === Infinity) {
+ return {
+ center: bounds.getCenter(),
+ zoom: zoom
+ };
+ }
+
+ var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
+
+ swPoint = this.project(bounds.getSouthWest(), zoom),
+ nePoint = this.project(bounds.getNorthEast(), zoom),
+ center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
+
+ return {
+ center: center,
+ zoom: zoom
+ };
+ },
+
+ // @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
+ // Sets a map view that contains the given geographical bounds with the
+ // maximum zoom level possible.
+ fitBounds: function (bounds, options) {
+
+ bounds = toLatLngBounds(bounds);
+
+ if (!bounds.isValid()) {
+ throw new Error('Bounds are not valid.');
+ }
+
+ var target = this._getBoundsCenterZoom(bounds, options);
+ return this.setView(target.center, target.zoom, options);
+ },
+
+ // @method fitWorld(options?: fitBounds options): this
+ // Sets a map view that mostly contains the whole world with the maximum
+ // zoom level possible.
+ fitWorld: function (options) {
+ return this.fitBounds([[-90, -180], [90, 180]], options);
+ },
+
+ // @method panTo(latlng: LatLng, options?: Pan options): this
+ // Pans the map to a given center.
+ panTo: function (center, options) { // (LatLng)
+ return this.setView(center, this._zoom, {pan: options});
+ },
+
+ // @method panBy(offset: Point, options?: Pan options): this
+ // Pans the map by a given number of pixels (animated).
+ panBy: function (offset, options) {
+ offset = toPoint(offset).round();
+ options = options || {};
+
+ if (!offset.x && !offset.y) {
+ return this.fire('moveend');
+ }
+ // If we pan too far, Chrome gets issues with tiles
+ // and makes them disappear or appear in the wrong place (slightly offset) #2602
+ if (options.animate !== true && !this.getSize().contains(offset)) {
+ this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
+ return this;
+ }
+
+ if (!this._panAnim) {
+ this._panAnim = new PosAnimation();
+
+ this._panAnim.on({
+ 'step': this._onPanTransitionStep,
+ 'end': this._onPanTransitionEnd
+ }, this);
+ }
+
+ // don't fire movestart if animating inertia
+ if (!options.noMoveStart) {
+ this.fire('movestart');
+ }
+
+ // animate pan unless animate: false specified
+ if (options.animate !== false) {
+ addClass(this._mapPane, 'leaflet-pan-anim');
+
+ var newPos = this._getMapPanePos().subtract(offset).round();
+ this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
+ } else {
+ this._rawPanBy(offset);
+ this.fire('move').fire('moveend');
+ }
+
+ return this;
+ },
+
+ // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
+ // Sets the view of the map (geographical center and zoom) performing a smooth
+ // pan-zoom animation.
+ flyTo: function (targetCenter, targetZoom, options) {
+
+ options = options || {};
+ if (options.animate === false || !any3d) {
+ return this.setView(targetCenter, targetZoom, options);
+ }
+
+ this._stop();
+
+ var from = this.project(this.getCenter()),
+ to = this.project(targetCenter),
+ size = this.getSize(),
+ startZoom = this._zoom;
+
+ targetCenter = toLatLng(targetCenter);
+ targetZoom = targetZoom === undefined ? startZoom : targetZoom;
+
+ var w0 = Math.max(size.x, size.y),
+ w1 = w0 * this.getZoomScale(startZoom, targetZoom),
+ u1 = (to.distanceTo(from)) || 1,
+ rho = 1.42,
+ rho2 = rho * rho;
+
+ function r(i) {
+ var s1 = i ? -1 : 1,
+ s2 = i ? w1 : w0,
+ t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
+ b1 = 2 * s2 * rho2 * u1,
+ b = t1 / b1,
+ sq = Math.sqrt(b * b + 1) - b;
+
+ // workaround for floating point precision bug when sq = 0, log = -Infinite,
+ // thus triggering an infinite loop in flyTo
+ var log = sq < 0.000000001 ? -18 : Math.log(sq);
+
+ return log;
+ }
+
+ function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
+ function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
+ function tanh(n) { return sinh(n) / cosh(n); }
+
+ var r0 = r(0);
+
+ function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
+ function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
+
+ function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
+
+ var start = Date.now(),
+ S = (r(1) - r0) / rho,
+ duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
+
+ function frame() {
+ var t = (Date.now() - start) / duration,
+ s = easeOut(t) * S;
+
+ if (t <= 1) {
+ this._flyToFrame = requestAnimFrame(frame, this);
+
+ this._move(
+ this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
+ this.getScaleZoom(w0 / w(s), startZoom),
+ {flyTo: true});
+
+ } else {
+ this
+ ._move(targetCenter, targetZoom)
+ ._moveEnd(true);
+ }
+ }
+
+ this._moveStart(true, options.noMoveStart);
+
+ frame.call(this);
+ return this;
+ },
+
+ // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
+ // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
+ // but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
+ flyToBounds: function (bounds, options) {
+ var target = this._getBoundsCenterZoom(bounds, options);
+ return this.flyTo(target.center, target.zoom, options);
+ },
+
+ // @method setMaxBounds(bounds: Bounds): this
+ // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
+ setMaxBounds: function (bounds) {
+ bounds = toLatLngBounds(bounds);
+
+ if (!bounds.isValid()) {
+ this.options.maxBounds = null;
+ return this.off('moveend', this._panInsideMaxBounds);
+ } else if (this.options.maxBounds) {
+ this.off('moveend', this._panInsideMaxBounds);
+ }
+
+ this.options.maxBounds = bounds;
+
+ if (this._loaded) {
+ this._panInsideMaxBounds();
+ }
+
+ return this.on('moveend', this._panInsideMaxBounds);
+ },
+
+ // @method setMinZoom(zoom: Number): this
+ // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
+ setMinZoom: function (zoom) {
+ var oldZoom = this.options.minZoom;
+ this.options.minZoom = zoom;
+
+ if (this._loaded && oldZoom !== zoom) {
+ this.fire('zoomlevelschange');
+
+ if (this.getZoom() < this.options.minZoom) {
+ return this.setZoom(zoom);
+ }
+ }
+
+ return this;
+ },
+
+ // @method setMaxZoom(zoom: Number): this
+ // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
+ setMaxZoom: function (zoom) {
+ var oldZoom = this.options.maxZoom;
+ this.options.maxZoom = zoom;
+
+ if (this._loaded && oldZoom !== zoom) {
+ this.fire('zoomlevelschange');
+
+ if (this.getZoom() > this.options.maxZoom) {
+ return this.setZoom(zoom);
+ }
+ }
+
+ return this;
+ },
+
+ // @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
+ // Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.
+ panInsideBounds: function (bounds, options) {
+ this._enforcingBounds = true;
+ var center = this.getCenter(),
+ newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
+
+ if (!center.equals(newCenter)) {
+ this.panTo(newCenter, options);
+ }
+
+ this._enforcingBounds = false;
+ return this;
+ },
+
+ // @method panInside(latlng: LatLng, options?: options): this
+ // Pans the map the minimum amount to make the `latlng` visible. Use
+ // `padding`, `paddingTopLeft` and `paddingTopRight` options to fit
+ // the display to more restricted bounds, like [`fitBounds`](#map-fitbounds).
+ // If `latlng` is already within the (optionally padded) display bounds,
+ // the map will not be panned.
+ panInside: function (latlng, options) {
+ options = options || {};
+
+ var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
+ paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
+ center = this.getCenter(),
+ pixelCenter = this.project(center),
+ pixelPoint = this.project(latlng),
+ pixelBounds = this.getPixelBounds(),
+ halfPixelBounds = pixelBounds.getSize().divideBy(2),
+ paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]);
+
+ if (!paddedBounds.contains(pixelPoint)) {
+ this._enforcingBounds = true;
+ var diff = pixelCenter.subtract(pixelPoint),
+ newCenter = toPoint(pixelPoint.x + diff.x, pixelPoint.y + diff.y);
+
+ if (pixelPoint.x < paddedBounds.min.x || pixelPoint.x > paddedBounds.max.x) {
+ newCenter.x = pixelCenter.x - diff.x;
+ if (diff.x > 0) {
+ newCenter.x += halfPixelBounds.x - paddingTL.x;
+ } else {
+ newCenter.x -= halfPixelBounds.x - paddingBR.x;
+ }
+ }
+ if (pixelPoint.y < paddedBounds.min.y || pixelPoint.y > paddedBounds.max.y) {
+ newCenter.y = pixelCenter.y - diff.y;
+ if (diff.y > 0) {
+ newCenter.y += halfPixelBounds.y - paddingTL.y;
+ } else {
+ newCenter.y -= halfPixelBounds.y - paddingBR.y;
+ }
+ }
+ this.panTo(this.unproject(newCenter), options);
+ this._enforcingBounds = false;
+ }
+ return this;
+ },
+
+ // @method invalidateSize(options: Zoom/pan options): this
+ // Checks if the map container size changed and updates the map if so —
+ // call it after you've changed the map size dynamically, also animating
+ // pan by default. If `options.pan` is `false`, panning will not occur.
+ // If `options.debounceMoveend` is `true`, it will delay `moveend` event so
+ // that it doesn't happen often even if the method is called many
+ // times in a row.
+
+ // @alternative
+ // @method invalidateSize(animate: Boolean): this
+ // Checks if the map container size changed and updates the map if so —
+ // call it after you've changed the map size dynamically, also animating
+ // pan by default.
+ invalidateSize: function (options) {
+ if (!this._loaded) { return this; }
+
+ options = extend({
+ animate: false,
+ pan: true
+ }, options === true ? {animate: true} : options);
+
+ var oldSize = this.getSize();
+ this._sizeChanged = true;
+ this._lastCenter = null;
+
+ var newSize = this.getSize(),
+ oldCenter = oldSize.divideBy(2).round(),
+ newCenter = newSize.divideBy(2).round(),
+ offset = oldCenter.subtract(newCenter);
+
+ if (!offset.x && !offset.y) { return this; }
+
+ if (options.animate && options.pan) {
+ this.panBy(offset);
+
+ } else {
+ if (options.pan) {
+ this._rawPanBy(offset);
+ }
+
+ this.fire('move');
+
+ if (options.debounceMoveend) {
+ clearTimeout(this._sizeTimer);
+ this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200);
+ } else {
+ this.fire('moveend');
+ }
+ }
+
+ // @section Map state change events
+ // @event resize: ResizeEvent
+ // Fired when the map is resized.
+ return this.fire('resize', {
+ oldSize: oldSize,
+ newSize: newSize
+ });
+ },
+
+ // @section Methods for modifying map state
+ // @method stop(): this
+ // Stops the currently running `panTo` or `flyTo` animation, if any.
+ stop: function () {
+ this.setZoom(this._limitZoom(this._zoom));
+ if (!this.options.zoomSnap) {
+ this.fire('viewreset');
+ }
+ return this._stop();
+ },
+
+ // @section Geolocation methods
+ // @method locate(options?: Locate options): this
+ // Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
+ // event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
+ // and optionally sets the map view to the user's location with respect to
+ // detection accuracy (or to the world view if geolocation failed).
+ // Note that, if your page doesn't use HTTPS, this method will fail in
+ // modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
+ // See `Locate options` for more details.
+ locate: function (options) {
+
+ options = this._locateOptions = extend({
+ timeout: 10000,
+ watch: false
+ // setView: false
+ // maxZoom: <Number>
+ // maximumAge: 0
+ // enableHighAccuracy: false
+ }, options);
+
+ if (!('geolocation' in navigator)) {
+ this._handleGeolocationError({
+ code: 0,
+ message: 'Geolocation not supported.'
+ });
+ return this;
+ }
+
+ var onResponse = bind(this._handleGeolocationResponse, this),
+ onError = bind(this._handleGeolocationError, this);
+
+ if (options.watch) {
+ this._locationWatchId =
+ navigator.geolocation.watchPosition(onResponse, onError, options);
+ } else {
+ navigator.geolocation.getCurrentPosition(onResponse, onError, options);
+ }
+ return this;
+ },
+
+ // @method stopLocate(): this
+ // Stops watching location previously initiated by `map.locate({watch: true})`
+ // and aborts resetting the map view if map.locate was called with
+ // `{setView: true}`.
+ stopLocate: function () {
+ if (navigator.geolocation && navigator.geolocation.clearWatch) {
+ navigator.geolocation.clearWatch(this._locationWatchId);
+ }
+ if (this._locateOptions) {
+ this._locateOptions.setView = false;
+ }
+ return this;
+ },
+
+ _handleGeolocationError: function (error) {
+ var c = error.code,
+ message = error.message ||
+ (c === 1 ? 'permission denied' :
+ (c === 2 ? 'position unavailable' : 'timeout'));
+
+ if (this._locateOptions.setView && !this._loaded) {
+ this.fitWorld();
+ }
+
+ // @section Location events
+ // @event locationerror: ErrorEvent
+ // Fired when geolocation (using the [`locate`](#map-locate) method) failed.
+ this.fire('locationerror', {
+ code: c,
+ message: 'Geolocation error: ' + message + '.'
+ });
+ },
+
+ _handleGeolocationResponse: function (pos) {
+ var lat = pos.coords.latitude,
+ lng = pos.coords.longitude,
+ latlng = new LatLng(lat, lng),
+ bounds = latlng.toBounds(pos.coords.accuracy * 2),
+ options = this._locateOptions;
+
+ if (options.setView) {
+ var zoom = this.getBoundsZoom(bounds);
+ this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
+ }
+
+ var data = {
+ latlng: latlng,
+ bounds: bounds,
+ timestamp: pos.timestamp
+ };
+
+ for (var i in pos.coords) {
+ if (typeof pos.coords[i] === 'number') {
+ data[i] = pos.coords[i];
+ }
+ }
+
+ // @event locationfound: LocationEvent
+ // Fired when geolocation (using the [`locate`](#map-locate) method)
+ // went successfully.
+ this.fire('locationfound', data);
+ },
+
+ // TODO Appropriate docs section?
+ // @section Other Methods
+ // @method addHandler(name: String, HandlerClass: Function): this
+ // Adds a new `Handler` to the map, given its name and constructor function.
+ addHandler: function (name, HandlerClass) {
+ if (!HandlerClass) { return this; }
+
+ var handler = this[name] = new HandlerClass(this);
+
+ this._handlers.push(handler);
+
+ if (this.options[name]) {
+ handler.enable();
+ }
+
+ return this;
+ },
+
+ // @method remove(): this
+ // Destroys the map and clears all related event listeners.
+ remove: function () {
+
+ this._initEvents(true);
+
+ if (this._containerId !== this._container._leaflet_id) {
+ throw new Error('Map container is being reused by another instance');
+ }
+
+ try {
+ // throws error in IE6-8
+ delete this._container._leaflet_id;
+ delete this._containerId;
+ } catch (e) {
+ /*eslint-disable */
+ this._container._leaflet_id = undefined;
+ /* eslint-enable */
+ this._containerId = undefined;
+ }
+
+ if (this._locationWatchId !== undefined) {
+ this.stopLocate();
+ }
+
+ this._stop();
+
+ remove(this._mapPane);
+
+ if (this._clearControlPos) {
+ this._clearControlPos();
+ }
+ if (this._resizeRequest) {
+ cancelAnimFrame(this._resizeRequest);
+ this._resizeRequest = null;
+ }
+
+ this._clearHandlers();
+
+ if (this._loaded) {
+ // @section Map state change events
+ // @event unload: Event
+ // Fired when the map is destroyed with [remove](#map-remove) method.
+ this.fire('unload');
+ }
+
+ var i;
+ for (i in this._layers) {
+ this._layers[i].remove();
+ }
+ for (i in this._panes) {
+ remove(this._panes[i]);
+ }
+
+ this._layers = [];
+ this._panes = [];
+ delete this._mapPane;
+ delete this._renderer;
+
+ return this;
+ },
+
+ // @section Other Methods
+ // @method createPane(name: String, container?: HTMLElement): HTMLElement
+ // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
+ // then returns it. The pane is created as a child of `container`, or
+ // as a child of the main map pane if not set.
+ createPane: function (name, container) {
+ var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
+ pane = create$1('div', className, container || this._mapPane);
+
+ if (name) {
+ this._panes[name] = pane;
+ }
+ return pane;
+ },
+
+ // @section Methods for Getting Map State
+
+ // @method getCenter(): LatLng
+ // Returns the geographical center of the map view
+ getCenter: function () {
+ this._checkIfLoaded();
+
+ if (this._lastCenter && !this._moved()) {
+ return this._lastCenter;
+ }
+ return this.layerPointToLatLng(this._getCenterLayerPoint());
+ },
+
+ // @method getZoom(): Number
+ // Returns the current zoom level of the map view
+ getZoom: function () {
+ return this._zoom;
+ },
+
+ // @method getBounds(): LatLngBounds
+ // Returns the geographical bounds visible in the current map view
+ getBounds: function () {
+ var bounds = this.getPixelBounds(),
+ sw = this.unproject(bounds.getBottomLeft()),
+ ne = this.unproject(bounds.getTopRight());
+
+ return new LatLngBounds(sw, ne);
+ },
+
+ // @method getMinZoom(): Number
+ // Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.
+ getMinZoom: function () {
+ return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
+ },
+
+ // @method getMaxZoom(): Number
+ // Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
+ getMaxZoom: function () {
+ return this.options.maxZoom === undefined ?
+ (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
+ this.options.maxZoom;
+ },
+
+ // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number
+ // Returns the maximum zoom level on which the given bounds fit to the map
+ // view in its entirety. If `inside` (optional) is set to `true`, the method
+ // instead returns the minimum zoom level on which the map view fits into
+ // the given bounds in its entirety.
+ getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
+ bounds = toLatLngBounds(bounds);
+ padding = toPoint(padding || [0, 0]);
+
+ var zoom = this.getZoom() || 0,
+ min = this.getMinZoom(),
+ max = this.getMaxZoom(),
+ nw = bounds.getNorthWest(),
+ se = bounds.getSouthEast(),
+ size = this.getSize().subtract(padding),
+ boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
+ snap = any3d ? this.options.zoomSnap : 1,
+ scalex = size.x / boundsSize.x,
+ scaley = size.y / boundsSize.y,
+ scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
+
+ zoom = this.getScaleZoom(scale, zoom);
+
+ if (snap) {
+ zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
+ zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
+ }
+
+ return Math.max(min, Math.min(max, zoom));
+ },
+
+ // @method getSize(): Point
+ // Returns the current size of the map container (in pixels).
+ getSize: function () {
+ if (!this._size || this._sizeChanged) {
+ this._size = new Point(
+ this._container.clientWidth || 0,
+ this._container.clientHeight || 0);
+
+ this._sizeChanged = false;
+ }
+ return this._size.clone();
+ },
+
+ // @method getPixelBounds(): Bounds
+ // Returns the bounds of the current map view in projected pixel
+ // coordinates (sometimes useful in layer and overlay implementations).
+ getPixelBounds: function (center, zoom) {
+ var topLeftPoint = this._getTopLeftPoint(center, zoom);
+ return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
+ },
+
+ // TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
+ // the map pane? "left point of the map layer" can be confusing, specially
+ // since there can be negative offsets.
+ // @method getPixelOrigin(): Point
+ // Returns the projected pixel coordinates of the top left point of
+ // the map layer (useful in custom layer and overlay implementations).
+ getPixelOrigin: function () {
+ this._checkIfLoaded();
+ return this._pixelOrigin;
+ },
+
+ // @method getPixelWorldBounds(zoom?: Number): Bounds
+ // Returns the world's bounds in pixel coordinates for zoom level `zoom`.
+ // If `zoom` is omitted, the map's current zoom level is used.
+ getPixelWorldBounds: function (zoom) {
+ return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
+ },
+
+ // @section Other Methods
+
+ // @method getPane(pane: String|HTMLElement): HTMLElement
+ // Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
+ getPane: function (pane) {
+ return typeof pane === 'string' ? this._panes[pane] : pane;
+ },
+
+ // @method getPanes(): Object
+ // Returns a plain object containing the names of all [panes](#map-pane) as keys and
+ // the panes as values.
+ getPanes: function () {
+ return this._panes;
+ },
+
+ // @method getContainer: HTMLElement
+ // Returns the HTML element that contains the map.
+ getContainer: function () {
+ return this._container;
+ },
+
+
+ // @section Conversion Methods
+
+ // @method getZoomScale(toZoom: Number, fromZoom: Number): Number
+ // Returns the scale factor to be applied to a map transition from zoom level
+ // `fromZoom` to `toZoom`. Used internally to help with zoom animations.
+ getZoomScale: function (toZoom, fromZoom) {
+ // TODO replace with universal implementation after refactoring projections
+ var crs = this.options.crs;
+ fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
+ return crs.scale(toZoom) / crs.scale(fromZoom);
+ },
+
+ // @method getScaleZoom(scale: Number, fromZoom: Number): Number
+ // Returns the zoom level that the map would end up at, if it is at `fromZoom`
+ // level and everything is scaled by a factor of `scale`. Inverse of
+ // [`getZoomScale`](#map-getZoomScale).
+ getScaleZoom: function (scale, fromZoom) {
+ var crs = this.options.crs;
+ fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
+ var zoom = crs.zoom(scale * crs.scale(fromZoom));
+ return isNaN(zoom) ? Infinity : zoom;
+ },
+
+ // @method project(latlng: LatLng, zoom: Number): Point
+ // Projects a geographical coordinate `LatLng` according to the projection
+ // of the map's CRS, then scales it according to `zoom` and the CRS's
+ // `Transformation`. The result is pixel coordinate relative to
+ // the CRS origin.
+ project: function (latlng, zoom) {
+ zoom = zoom === undefined ? this._zoom : zoom;
+ return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
+ },
+
+ // @method unproject(point: Point, zoom: Number): LatLng
+ // Inverse of [`project`](#map-project).
+ unproject: function (point, zoom) {
+ zoom = zoom === undefined ? this._zoom : zoom;
+ return this.options.crs.pointToLatLng(toPoint(point), zoom);
+ },
+
+ // @method layerPointToLatLng(point: Point): LatLng
+ // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
+ // returns the corresponding geographical coordinate (for the current zoom level).
+ layerPointToLatLng: function (point) {
+ var projectedPoint = toPoint(point).add(this.getPixelOrigin());
+ return this.unproject(projectedPoint);
+ },
+
+ // @method latLngToLayerPoint(latlng: LatLng): Point
+ // Given a geographical coordinate, returns the corresponding pixel coordinate
+ // relative to the [origin pixel](#map-getpixelorigin).
+ latLngToLayerPoint: function (latlng) {
+ var projectedPoint = this.project(toLatLng(latlng))._round();
+ return projectedPoint._subtract(this.getPixelOrigin());
+ },
+
+ // @method wrapLatLng(latlng: LatLng): LatLng
+ // Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
+ // map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
+ // CRS's bounds.
+ // By default this means longitude is wrapped around the dateline so its
+ // value is between -180 and +180 degrees.
+ wrapLatLng: function (latlng) {
+ return this.options.crs.wrapLatLng(toLatLng(latlng));
+ },
+
+ // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
+ // Returns a `LatLngBounds` with the same size as the given one, ensuring that
+ // its center is within the CRS's bounds.
+ // By default this means the center longitude is wrapped around the dateline so its
+ // value is between -180 and +180 degrees, and the majority of the bounds
+ // overlaps the CRS's bounds.
+ wrapLatLngBounds: function (latlng) {
+ return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
+ },
+
+ // @method distance(latlng1: LatLng, latlng2: LatLng): Number
+ // Returns the distance between two geographical coordinates according to
+ // the map's CRS. By default this measures distance in meters.
+ distance: function (latlng1, latlng2) {
+ return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
+ },
+
+ // @method containerPointToLayerPoint(point: Point): Point
+ // Given a pixel coordinate relative to the map container, returns the corresponding
+ // pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
+ containerPointToLayerPoint: function (point) { // (Point)
+ return toPoint(point).subtract(this._getMapPanePos());
+ },
+
+ // @method layerPointToContainerPoint(point: Point): Point
+ // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
+ // returns the corresponding pixel coordinate relative to the map container.
+ layerPointToContainerPoint: function (point) { // (Point)
+ return toPoint(point).add(this._getMapPanePos());
+ },
+
+ // @method containerPointToLatLng(point: Point): LatLng
+ // Given a pixel coordinate relative to the map container, returns
+ // the corresponding geographical coordinate (for the current zoom level).
+ containerPointToLatLng: function (point) {
+ var layerPoint = this.containerPointToLayerPoint(toPoint(point));
+ return this.layerPointToLatLng(layerPoint);
+ },
+
+ // @method latLngToContainerPoint(latlng: LatLng): Point
+ // Given a geographical coordinate, returns the corresponding pixel coordinate
+ // relative to the map container.
+ latLngToContainerPoint: function (latlng) {
+ return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
+ },
+
+ // @method mouseEventToContainerPoint(ev: MouseEvent): Point
+ // Given a MouseEvent object, returns the pixel coordinate relative to the
+ // map container where the event took place.
+ mouseEventToContainerPoint: function (e) {
+ return getMousePosition(e, this._container);
+ },
+
+ // @method mouseEventToLayerPoint(ev: MouseEvent): Point
+ // Given a MouseEvent object, returns the pixel coordinate relative to
+ // the [origin pixel](#map-getpixelorigin) where the event took place.
+ mouseEventToLayerPoint: function (e) {
+ return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
+ },
+
+ // @method mouseEventToLatLng(ev: MouseEvent): LatLng
+ // Given a MouseEvent object, returns geographical coordinate where the
+ // event took place.
+ mouseEventToLatLng: function (e) { // (MouseEvent)
+ return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
+ },
+
+
+ // map initialization methods
+
+ _initContainer: function (id) {
+ var container = this._container = get(id);
+
+ if (!container) {
+ throw new Error('Map container not found.');
+ } else if (container._leaflet_id) {
+ throw new Error('Map container is already initialized.');
+ }
+
+ on(container, 'scroll', this._onScroll, this);
+ this._containerId = stamp(container);
+ },
+
+ _initLayout: function () {
+ var container = this._container;
+
+ this._fadeAnimated = this.options.fadeAnimation && any3d;
+
+ addClass(container, 'leaflet-container' +
+ (touch ? ' leaflet-touch' : '') +
+ (retina ? ' leaflet-retina' : '') +
+ (ielt9 ? ' leaflet-oldie' : '') +
+ (safari ? ' leaflet-safari' : '') +
+ (this._fadeAnimated ? ' leaflet-fade-anim' : ''));
+
+ var position = getStyle(container, 'position');
+
+ if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
+ container.style.position = 'relative';
+ }
+
+ this._initPanes();
+
+ if (this._initControlPos) {
+ this._initControlPos();
+ }
+ },
+
+ _initPanes: function () {
+ var panes = this._panes = {};
+ this._paneRenderers = {};
+
+ // @section
+ //
+ // Panes are DOM elements used to control the ordering of layers on the map. You
+ // can access panes with [`map.getPane`](#map-getpane) or
+ // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
+ // [`map.createPane`](#map-createpane) method.
+ //
+ // Every map has the following default panes that differ only in zIndex.
+ //
+ // @pane mapPane: HTMLElement = 'auto'
+ // Pane that contains all other map panes
+
+ this._mapPane = this.createPane('mapPane', this._container);
+ setPosition(this._mapPane, new Point(0, 0));
+
+ // @pane tilePane: HTMLElement = 200
+ // Pane for `GridLayer`s and `TileLayer`s
+ this.createPane('tilePane');
+ // @pane overlayPane: HTMLElement = 400
+ // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
+ this.createPane('shadowPane');
+ // @pane shadowPane: HTMLElement = 500
+ // Pane for overlay shadows (e.g. `Marker` shadows)
+ this.createPane('overlayPane');
+ // @pane markerPane: HTMLElement = 600
+ // Pane for `Icon`s of `Marker`s
+ this.createPane('markerPane');
+ // @pane tooltipPane: HTMLElement = 650
+ // Pane for `Tooltip`s.
+ this.createPane('tooltipPane');
+ // @pane popupPane: HTMLElement = 700
+ // Pane for `Popup`s.
+ this.createPane('popupPane');
+
+ if (!this.options.markerZoomAnimation) {
+ addClass(panes.markerPane, 'leaflet-zoom-hide');
+ addClass(panes.shadowPane, 'leaflet-zoom-hide');
+ }
+ },
+
+
+ // private methods that modify map state
+
+ // @section Map state change events
+ _resetView: function (center, zoom) {
+ setPosition(this._mapPane, new Point(0, 0));
+
+ var loading = !this._loaded;
+ this._loaded = true;
+ zoom = this._limitZoom(zoom);
+
+ this.fire('viewprereset');
+
+ var zoomChanged = this._zoom !== zoom;
+ this
+ ._moveStart(zoomChanged, false)
+ ._move(center, zoom)
+ ._moveEnd(zoomChanged);
+
+ // @event viewreset: Event
+ // Fired when the map needs to redraw its content (this usually happens
+ // on map zoom or load). Very useful for creating custom overlays.
+ this.fire('viewreset');
+
+ // @event load: Event
+ // Fired when the map is initialized (when its center and zoom are set
+ // for the first time).
+ if (loading) {
+ this.fire('load');
+ }
+ },
+
+ _moveStart: function (zoomChanged, noMoveStart) {
+ // @event zoomstart: Event
+ // Fired when the map zoom is about to change (e.g. before zoom animation).
+ // @event movestart: Event
+ // Fired when the view of the map starts changing (e.g. user starts dragging the map).
+ if (zoomChanged) {
+ this.fire('zoomstart');
+ }
+ if (!noMoveStart) {
+ this.fire('movestart');
+ }
+ return this;
+ },
+
+ _move: function (center, zoom, data) {
+ if (zoom === undefined) {
+ zoom = this._zoom;
+ }
+ var zoomChanged = this._zoom !== zoom;
+
+ this._zoom = zoom;
+ this._lastCenter = center;
+ this._pixelOrigin = this._getNewPixelOrigin(center);
+
+ // @event zoom: Event
+ // Fired repeatedly during any change in zoom level, including zoom
+ // and fly animations.
+ if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530
+ this.fire('zoom', data);
+ }
+
+ // @event move: Event
+ // Fired repeatedly during any movement of the map, including pan and
+ // fly animations.
+ return this.fire('move', data);
+ },
+
+ _moveEnd: function (zoomChanged) {
+ // @event zoomend: Event
+ // Fired when the map has changed, after any animations.
+ if (zoomChanged) {
+ this.fire('zoomend');
+ }
+
+ // @event moveend: Event
+ // Fired when the center of the map stops changing (e.g. user stopped
+ // dragging the map).
+ return this.fire('moveend');
+ },
+
+ _stop: function () {
+ cancelAnimFrame(this._flyToFrame);
+ if (this._panAnim) {
+ this._panAnim.stop();
+ }
+ return this;
+ },
+
+ _rawPanBy: function (offset) {
+ setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
+ },
+
+ _getZoomSpan: function () {
+ return this.getMaxZoom() - this.getMinZoom();
+ },
+
+ _panInsideMaxBounds: function () {
+ if (!this._enforcingBounds) {
+ this.panInsideBounds(this.options.maxBounds);
+ }
+ },
+
+ _checkIfLoaded: function () {
+ if (!this._loaded) {
+ throw new Error('Set map center and zoom first.');
+ }
+ },
+
+ // DOM event handling
+
+ // @section Interaction events
+ _initEvents: function (remove$$1) {
+ this._targets = {};
+ this._targets[stamp(this._container)] = this;
+
+ var onOff = remove$$1 ? off : on;
+
+ // @event click: MouseEvent
+ // Fired when the user clicks (or taps) the map.
+ // @event dblclick: MouseEvent
+ // Fired when the user double-clicks (or double-taps) the map.
+ // @event mousedown: MouseEvent
+ // Fired when the user pushes the mouse button on the map.
+ // @event mouseup: MouseEvent
+ // Fired when the user releases the mouse button on the map.
+ // @event mouseover: MouseEvent
+ // Fired when the mouse enters the map.
+ // @event mouseout: MouseEvent
+ // Fired when the mouse leaves the map.
+ // @event mousemove: MouseEvent
+ // Fired while the mouse moves over the map.
+ // @event contextmenu: MouseEvent
+ // Fired when the user pushes the right mouse button on the map, prevents
+ // default browser context menu from showing if there are listeners on
+ // this event. Also fired on mobile when the user holds a single touch
+ // for a second (also called long press).
+ // @event keypress: KeyboardEvent
+ // Fired when the user presses a key from the keyboard while the map is focused.
+ onOff(this._container, 'click dblclick mousedown mouseup ' +
+ 'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this);
+
+ if (this.options.trackResize) {
+ onOff(window, 'resize', this._onResize, this);
+ }
+
+ if (any3d && this.options.transform3DLimit) {
+ (remove$$1 ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
+ }
+ },
+
+ _onResize: function () {
+ cancelAnimFrame(this._resizeRequest);
+ this._resizeRequest = requestAnimFrame(
+ function () { this.invalidateSize({debounceMoveend: true}); }, this);
+ },
+
+ _onScroll: function () {
+ this._container.scrollTop = 0;
+ this._container.scrollLeft = 0;
+ },
+
+ _onMoveEnd: function () {
+ var pos = this._getMapPanePos();
+ if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
+ // a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
+ this._resetView(this.getCenter(), this.getZoom());
+ }
+ },
+
+ _findEventTargets: function (e, type) {
+ var targets = [],
+ target,
+ isHover = type === 'mouseout' || type === 'mouseover',
+ src = e.target || e.srcElement,
+ dragging = false;
+
+ while (src) {
+ target = this._targets[stamp(src)];
+ if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
+ // Prevent firing click after you just dragged an object.
+ dragging = true;
+ break;
+ }
+ if (target && target.listens(type, true)) {
+ if (isHover && !isExternalTarget(src, e)) { break; }
+ targets.push(target);
+ if (isHover) { break; }
+ }
+ if (src === this._container) { break; }
+ src = src.parentNode;
+ }
+ if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) {
+ targets = [this];
+ }
+ return targets;
+ },
+
+ _handleDOMEvent: function (e) {
+ if (!this._loaded || skipped(e)) { return; }
+
+ var type = e.type;
+
+ if (type === 'mousedown' || type === 'keypress') {
+ // prevents outline when clicking on keyboard-focusable element
+ preventOutline(e.target || e.srcElement);
+ }
+
+ this._fireDOMEvent(e, type);
+ },
+
+ _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
+
+ _fireDOMEvent: function (e, type, targets) {
+
+ if (e.type === 'click') {
+ // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
+ // @event preclick: MouseEvent
+ // Fired before mouse click on the map (sometimes useful when you
+ // want something to happen on click before any existing click
+ // handlers start running).
+ var synth = extend({}, e);
+ synth.type = 'preclick';
+ this._fireDOMEvent(synth, synth.type, targets);
+ }
+
+ if (e._stopped) { return; }
+
+ // Find the layer the event is propagating from and its parents.
+ targets = (targets || []).concat(this._findEventTargets(e, type));
+
+ if (!targets.length) { return; }
+
+ var target = targets[0];
+ if (type === 'contextmenu' && target.listens(type, true)) {
+ preventDefault(e);
+ }
+
+ var data = {
+ originalEvent: e
+ };
+
+ if (e.type !== 'keypress') {
+ var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
+ data.containerPoint = isMarker ?
+ this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
+ data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
+ data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
+ }
+
+ for (var i = 0; i < targets.length; i++) {
+ targets[i].fire(type, data, true);
+ if (data.originalEvent._stopped ||
+ (targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
+ }
+ },
+
+ _draggableMoved: function (obj) {
+ obj = obj.dragging && obj.dragging.enabled() ? obj : this;
+ return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
+ },
+
+ _clearHandlers: function () {
+ for (var i = 0, len = this._handlers.length; i < len; i++) {
+ this._handlers[i].disable();
+ }
+ },
+
+ // @section Other Methods
+
+ // @method whenReady(fn: Function, context?: Object): this
+ // Runs the given function `fn` when the map gets initialized with
+ // a view (center and zoom) and at least one layer, or immediately
+ // if it's already initialized, optionally passing a function context.
+ whenReady: function (callback, context) {
+ if (this._loaded) {
+ callback.call(context || this, {target: this});
+ } else {
+ this.on('load', callback, context);
+ }
+ return this;
+ },
+
+
+ // private methods for getting map state
+
+ _getMapPanePos: function () {
+ return getPosition(this._mapPane) || new Point(0, 0);
+ },
+
+ _moved: function () {
+ var pos = this._getMapPanePos();
+ return pos && !pos.equals([0, 0]);
+ },
+
+ _getTopLeftPoint: function (center, zoom) {
+ var pixelOrigin = center && zoom !== undefined ?
+ this._getNewPixelOrigin(center, zoom) :
+ this.getPixelOrigin();
+ return pixelOrigin.subtract(this._getMapPanePos());
+ },
+
+ _getNewPixelOrigin: function (center, zoom) {
+ var viewHalf = this.getSize()._divideBy(2);
+ return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
+ },
+
+ _latLngToNewLayerPoint: function (latlng, zoom, center) {
+ var topLeft = this._getNewPixelOrigin(center, zoom);
+ return this.project(latlng, zoom)._subtract(topLeft);
+ },
+
+ _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
+ var topLeft = this._getNewPixelOrigin(center, zoom);
+ return toBounds([
+ this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
+ this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
+ this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
+ this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
+ ]);
+ },
+
+ // layer point of the current center
+ _getCenterLayerPoint: function () {
+ return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
+ },
+
+ // offset of the specified place to the current center in pixels
+ _getCenterOffset: function (latlng) {
+ return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
+ },
+
+ // adjust center for view to get inside bounds
+ _limitCenter: function (center, zoom, bounds) {
+
+ if (!bounds) { return center; }
+
+ var centerPoint = this.project(center, zoom),
+ viewHalf = this.getSize().divideBy(2),
+ viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
+ offset = this._getBoundsOffset(viewBounds, bounds, zoom);
+
+ // If offset is less than a pixel, ignore.
+ // This prevents unstable projections from getting into
+ // an infinite loop of tiny offsets.
+ if (offset.round().equals([0, 0])) {
+ return center;
+ }
+
+ return this.unproject(centerPoint.add(offset), zoom);
+ },
+
+ // adjust offset for view to get inside bounds
+ _limitOffset: function (offset, bounds) {
+ if (!bounds) { return offset; }
+
+ var viewBounds = this.getPixelBounds(),
+ newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
+
+ return offset.add(this._getBoundsOffset(newBounds, bounds));
+ },
+
+ // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
+ _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
+ var projectedMaxBounds = toBounds(
+ this.project(maxBounds.getNorthEast(), zoom),
+ this.project(maxBounds.getSouthWest(), zoom)
+ ),
+ minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
+ maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
+
+ dx = this._rebound(minOffset.x, -maxOffset.x),
+ dy = this._rebound(minOffset.y, -maxOffset.y);
+
+ return new Point(dx, dy);
+ },
+
+ _rebound: function (left, right) {
+ return left + right > 0 ?
+ Math.round(left - right) / 2 :
+ Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
+ },
+
+ _limitZoom: function (zoom) {
+ var min = this.getMinZoom(),
+ max = this.getMaxZoom(),
+ snap = any3d ? this.options.zoomSnap : 1;
+ if (snap) {
+ zoom = Math.round(zoom / snap) * snap;
+ }
+ return Math.max(min, Math.min(max, zoom));
+ },
+
+ _onPanTransitionStep: function () {
+ this.fire('move');
+ },
+
+ _onPanTransitionEnd: function () {
+ removeClass(this._mapPane, 'leaflet-pan-anim');
+ this.fire('moveend');
+ },
+
+ _tryAnimatedPan: function (center, options) {
+ // difference between the new and current centers in pixels
+ var offset = this._getCenterOffset(center)._trunc();
+
+ // don't animate too far unless animate: true specified in options
+ if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
+
+ this.panBy(offset, options);
+
+ return true;
+ },
+
+ _createAnimProxy: function () {
+
+ var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated');
+ this._panes.mapPane.appendChild(proxy);
+
+ this.on('zoomanim', function (e) {
+ var prop = TRANSFORM,
+ transform = this._proxy.style[prop];
+
+ setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
+
+ // workaround for case when transform is the same and so transitionend event is not fired
+ if (transform === this._proxy.style[prop] && this._animatingZoom) {
+ this._onZoomTransitionEnd();
+ }
+ }, this);
+
+ this.on('load moveend', function () {
+ var c = this.getCenter(),
+ z = this.getZoom();
+ setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
+ }, this);
+
+ this._on('unload', this._destroyAnimProxy, this);
+ },
+
+ _destroyAnimProxy: function () {
+ remove(this._proxy);
+ delete this._proxy;
+ },
+
+ _catchTransitionEnd: function (e) {
+ if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
+ this._onZoomTransitionEnd();
+ }
+ },
+
+ _nothingToAnimate: function () {
+ return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
+ },
+
+ _tryAnimatedZoom: function (center, zoom, options) {
+
+ if (this._animatingZoom) { return true; }
+
+ options = options || {};
+
+ // don't animate if disabled, not supported or zoom difference is too large
+ if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
+ Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
+
+ // offset is the pixel coords of the zoom origin relative to the current center
+ var scale = this.getZoomScale(zoom),
+ offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
+
+ // don't animate if the zoom origin isn't within one screen from the current center, unless forced
+ if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
+
+ requestAnimFrame(function () {
+ this
+ ._moveStart(true, false)
+ ._animateZoom(center, zoom, true);
+ }, this);
+
+ return true;
+ },
+
+ _animateZoom: function (center, zoom, startAnim, noUpdate) {
+ if (!this._mapPane) { return; }
+
+ if (startAnim) {
+ this._animatingZoom = true;
+
+ // remember what center/zoom to set after animation
+ this._animateToCenter = center;
+ this._animateToZoom = zoom;
+
+ addClass(this._mapPane, 'leaflet-zoom-anim');
+ }
+
+ // @event zoomanim: ZoomAnimEvent
+ // Fired at least once per zoom animation. For continous zoom, like pinch zooming, fired once per frame during zoom.
+ this.fire('zoomanim', {
+ center: center,
+ zoom: zoom,
+ noUpdate: noUpdate
+ });
+
+ // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
+ setTimeout(bind(this._onZoomTransitionEnd, this), 250);
+ },
+
+ _onZoomTransitionEnd: function () {
+ if (!this._animatingZoom) { return; }
+
+ if (this._mapPane) {
+ removeClass(this._mapPane, 'leaflet-zoom-anim');
+ }
+
+ this._animatingZoom = false;
+
+ this._move(this._animateToCenter, this._animateToZoom);
+
+ // This anim frame should prevent an obscure iOS webkit tile loading race condition.
+ requestAnimFrame(function () {
+ this._moveEnd(true);
+ }, this);
+ }
+});
+
+// @section
+
+// @factory L.map(id: String, options?: Map options)
+// Instantiates a map object given the DOM ID of a `<div>` element
+// and optionally an object literal with `Map options`.
+//
+// @alternative
+// @factory L.map(el: HTMLElement, options?: Map options)
+// Instantiates a map object given an instance of a `<div>` HTML element
+// and optionally an object literal with `Map options`.
+function createMap(id, options) {
+ return new Map(id, options);
+}
+
+/*
+ * @class Control
+ * @aka L.Control
+ * @inherits Class
+ *
+ * L.Control is a base class for implementing map controls. Handles positioning.
+ * All other controls extend from this class.
+ */
+
+var Control = Class.extend({
+ // @section
+ // @aka Control options
+ options: {
+ // @option position: String = 'topright'
+ // The position of the control (one of the map corners). Possible values are `'topleft'`,
+ // `'topright'`, `'bottomleft'` or `'bottomright'`
+ position: 'topright'
+ },
+
+ initialize: function (options) {
+ setOptions(this, options);
+ },
+
+ /* @section
+ * Classes extending L.Control will inherit the following methods:
+ *
+ * @method getPosition: string
+ * Returns the position of the control.
+ */
+ getPosition: function () {
+ return this.options.position;
+ },
+
+ // @method setPosition(position: string): this
+ // Sets the position of the control.
+ setPosition: function (position) {
+ var map = this._map;
+
+ if (map) {
+ map.removeControl(this);
+ }
+
+ this.options.position = position;
+
+ if (map) {
+ map.addControl(this);
+ }
+
+ return this;
+ },
+
+ // @method getContainer: HTMLElement
+ // Returns the HTMLElement that contains the control.
+ getContainer: function () {
+ return this._container;
+ },
+
+ // @method addTo(map: Map): this
+ // Adds the control to the given map.
+ addTo: function (map) {
+ this.remove();
+ this._map = map;
+
+ var container = this._container = this.onAdd(map),
+ pos = this.getPosition(),
+ corner = map._controlCorners[pos];
+
+ addClass(container, 'leaflet-control');
+
+ if (pos.indexOf('bottom') !== -1) {
+ corner.insertBefore(container, corner.firstChild);
+ } else {
+ corner.appendChild(container);
+ }
+
+ return this;
+ },
+
+ // @method remove: this
+ // Removes the control from the map it is currently active on.
+ remove: function () {
+ if (!this._map) {
+ return this;
+ }
+
+ remove(this._container);
+
+ if (this.onRemove) {
+ this.onRemove(this._map);
+ }
+
+ this._map = null;
+
+ return this;
+ },
+
+ _refocusOnMap: function (e) {
+ // if map exists and event is not a keyboard event
+ if (this._map && e && e.screenX > 0 && e.screenY > 0) {
+ this._map.getContainer().focus();
+ }
+ }
+});
+
+var control = function (options) {
+ return new Control(options);
+};
+
+/* @section Extension methods
+ * @uninheritable
+ *
+ * Every control should extend from `L.Control` and (re-)implement the following methods.
+ *
+ * @method onAdd(map: Map): HTMLElement
+ * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
+ *
+ * @method onRemove(map: Map)
+ * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
+ */
+
+/* @namespace Map
+ * @section Methods for Layers and Controls
+ */
+Map.include({
+ // @method addControl(control: Control): this
+ // Adds the given control to the map
+ addControl: function (control) {
+ control.addTo(this);
+ return this;
+ },
+
+ // @method removeControl(control: Control): this
+ // Removes the given control from the map
+ removeControl: function (control) {
+ control.remove();
+ return this;
+ },
+
+ _initControlPos: function () {
+ var corners = this._controlCorners = {},
+ l = 'leaflet-',
+ container = this._controlContainer =
+ create$1('div', l + 'control-container', this._container);
+
+ function createCorner(vSide, hSide) {
+ var className = l + vSide + ' ' + l + hSide;
+
+ corners[vSide + hSide] = create$1('div', className, container);
+ }
+
+ createCorner('top', 'left');
+ createCorner('top', 'right');
+ createCorner('bottom', 'left');
+ createCorner('bottom', 'right');
+ },
+
+ _clearControlPos: function () {
+ for (var i in this._controlCorners) {
+ remove(this._controlCorners[i]);
+ }
+ remove(this._controlContainer);
+ delete this._controlCorners;
+ delete this._controlContainer;
+ }
+});
+
+/*
+ * @class Control.Layers
+ * @aka L.Control.Layers
+ * @inherits Control
+ *
+ * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control/)). Extends `Control`.
+ *
+ * @example
+ *
+ * ```js
+ * var baseLayers = {
+ * "Mapbox": mapbox,
+ * "OpenStreetMap": osm
+ * };
+ *
+ * var overlays = {
+ * "Marker": marker,
+ * "Roads": roadsLayer
+ * };
+ *
+ * L.control.layers(baseLayers, overlays).addTo(map);
+ * ```
+ *
+ * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
+ *
+ * ```js
+ * {
+ * "<someName1>": layer1,
+ * "<someName2>": layer2
+ * }
+ * ```
+ *
+ * The layer names can contain HTML, which allows you to add additional styling to the items:
+ *
+ * ```js
+ * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
+ * ```
+ */
+
+var Layers = Control.extend({
+ // @section
+ // @aka Control.Layers options
+ options: {
+ // @option collapsed: Boolean = true
+ // If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
+ collapsed: true,
+ position: 'topright',
+
+ // @option autoZIndex: Boolean = true
+ // If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.
+ autoZIndex: true,
+
+ // @option hideSingleBase: Boolean = false
+ // If `true`, the base layers in the control will be hidden when there is only one.
+ hideSingleBase: false,
+
+ // @option sortLayers: Boolean = false
+ // Whether to sort the layers. When `false`, layers will keep the order
+ // in which they were added to the control.
+ sortLayers: false,
+
+ // @option sortFunction: Function = *
+ // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
+ // that will be used for sorting the layers, when `sortLayers` is `true`.
+ // The function receives both the `L.Layer` instances and their names, as in
+ // `sortFunction(layerA, layerB, nameA, nameB)`.
+ // By default, it sorts layers alphabetically by their name.
+ sortFunction: function (layerA, layerB, nameA, nameB) {
+ return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
+ }
+ },
+
+ initialize: function (baseLayers, overlays, options) {
+ setOptions(this, options);
+
+ this._layerControlInputs = [];
+ this._layers = [];
+ this._lastZIndex = 0;
+ this._handlingClick = false;
+
+ for (var i in baseLayers) {
+ this._addLayer(baseLayers[i], i);
+ }
+
+ for (i in overlays) {
+ this._addLayer(overlays[i], i, true);
+ }
+ },
+
+ onAdd: function (map) {
+ this._initLayout();
+ this._update();
+
+ this._map = map;
+ map.on('zoomend', this._checkDisabledLayers, this);
+
+ for (var i = 0; i < this._layers.length; i++) {
+ this._layers[i].layer.on('add remove', this._onLayerChange, this);
+ }
+
+ return this._container;
+ },
+
+ addTo: function (map) {
+ Control.prototype.addTo.call(this, map);
+ // Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
+ return this._expandIfNotCollapsed();
+ },
+
+ onRemove: function () {
+ this._map.off('zoomend', this._checkDisabledLayers, this);
+
+ for (var i = 0; i < this._layers.length; i++) {
+ this._layers[i].layer.off('add remove', this._onLayerChange, this);
+ }
+ },
+
+ // @method addBaseLayer(layer: Layer, name: String): this
+ // Adds a base layer (radio button entry) with the given name to the control.
+ addBaseLayer: function (layer, name) {
+ this._addLayer(layer, name);
+ return (this._map) ? this._update() : this;
+ },
+
+ // @method addOverlay(layer: Layer, name: String): this
+ // Adds an overlay (checkbox entry) with the given name to the control.
+ addOverlay: function (layer, name) {
+ this._addLayer(layer, name, true);
+ return (this._map) ? this._update() : this;
+ },
+
+ // @method removeLayer(layer: Layer): this
+ // Remove the given layer from the control.
+ removeLayer: function (layer) {
+ layer.off('add remove', this._onLayerChange, this);
+
+ var obj = this._getLayer(stamp(layer));
+ if (obj) {
+ this._layers.splice(this._layers.indexOf(obj), 1);
+ }
+ return (this._map) ? this._update() : this;
+ },
+
+ // @method expand(): this
+ // Expand the control container if collapsed.
+ expand: function () {
+ addClass(this._container, 'leaflet-control-layers-expanded');
+ this._section.style.height = null;
+ var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
+ if (acceptableHeight < this._section.clientHeight) {
+ addClass(this._section, 'leaflet-control-layers-scrollbar');
+ this._section.style.height = acceptableHeight + 'px';
+ } else {
+ removeClass(this._section, 'leaflet-control-layers-scrollbar');
+ }
+ this._checkDisabledLayers();
+ return this;
+ },
+
+ // @method collapse(): this
+ // Collapse the control container if expanded.
+ collapse: function () {
+ removeClass(this._container, 'leaflet-control-layers-expanded');
+ return this;
+ },
+
+ _initLayout: function () {
+ var className = 'leaflet-control-layers',
+ container = this._container = create$1('div', className),
+ collapsed = this.options.collapsed;
+
+ // makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
+ container.setAttribute('aria-haspopup', true);
+
+ disableClickPropagation(container);
+ disableScrollPropagation(container);
+
+ var section = this._section = create$1('section', className + '-list');
+
+ if (collapsed) {
+ this._map.on('click', this.collapse, this);
+
+ if (!android) {
+ on(container, {
+ mouseenter: this.expand,
+ mouseleave: this.collapse
+ }, this);
+ }
+ }
+
+ var link = this._layersLink = create$1('a', className + '-toggle', container);
+ link.href = '#';
+ link.title = 'Layers';
+
+ if (touch) {
+ on(link, 'click', stop);
+ on(link, 'click', this.expand, this);
+ } else {
+ on(link, 'focus', this.expand, this);
+ }
+
+ if (!collapsed) {
+ this.expand();
+ }
+
+ this._baseLayersList = create$1('div', className + '-base', section);
+ this._separator = create$1('div', className + '-separator', section);
+ this._overlaysList = create$1('div', className + '-overlays', section);
+
+ container.appendChild(section);
+ },
+
+ _getLayer: function (id) {
+ for (var i = 0; i < this._layers.length; i++) {
+
+ if (this._layers[i] && stamp(this._layers[i].layer) === id) {
+ return this._layers[i];
+ }
+ }
+ },
+
+ _addLayer: function (layer, name, overlay) {
+ if (this._map) {
+ layer.on('add remove', this._onLayerChange, this);
+ }
+
+ this._layers.push({
+ layer: layer,
+ name: name,
+ overlay: overlay
+ });
+
+ if (this.options.sortLayers) {
+ this._layers.sort(bind(function (a, b) {
+ return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
+ }, this));
+ }
+
+ if (this.options.autoZIndex && layer.setZIndex) {
+ this._lastZIndex++;
+ layer.setZIndex(this._lastZIndex);
+ }
+
+ this._expandIfNotCollapsed();
+ },
+
+ _update: function () {
+ if (!this._container) { return this; }
+
+ empty(this._baseLayersList);
+ empty(this._overlaysList);
+
+ this._layerControlInputs = [];
+ var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
+
+ for (i = 0; i < this._layers.length; i++) {
+ obj = this._layers[i];
+ this._addItem(obj);
+ overlaysPresent = overlaysPresent || obj.overlay;
+ baseLayersPresent = baseLayersPresent || !obj.overlay;
+ baseLayersCount += !obj.overlay ? 1 : 0;
+ }
+
+ // Hide base layers section if there's only one layer.
+ if (this.options.hideSingleBase) {
+ baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
+ this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
+ }
+
+ this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
+
+ return this;
+ },
+
+ _onLayerChange: function (e) {
+ if (!this._handlingClick) {
+ this._update();
+ }
+
+ var obj = this._getLayer(stamp(e.target));
+
+ // @namespace Map
+ // @section Layer events
+ // @event baselayerchange: LayersControlEvent
+ // Fired when the base layer is changed through the [layer control](#control-layers).
+ // @event overlayadd: LayersControlEvent
+ // Fired when an overlay is selected through the [layer control](#control-layers).
+ // @event overlayremove: LayersControlEvent
+ // Fired when an overlay is deselected through the [layer control](#control-layers).
+ // @namespace Control.Layers
+ var type = obj.overlay ?
+ (e.type === 'add' ? 'overlayadd' : 'overlayremove') :
+ (e.type === 'add' ? 'baselayerchange' : null);
+
+ if (type) {
+ this._map.fire(type, obj);
+ }
+ },
+
+ // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
+ _createRadioElement: function (name, checked) {
+
+ var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
+ name + '"' + (checked ? ' checked="checked"' : '') + '/>';
+
+ var radioFragment = document.createElement('div');
+ radioFragment.innerHTML = radioHtml;
+
+ return radioFragment.firstChild;
+ },
+
+ _addItem: function (obj) {
+ var label = document.createElement('label'),
+ checked = this._map.hasLayer(obj.layer),
+ input;
+
+ if (obj.overlay) {
+ input = document.createElement('input');
+ input.type = 'checkbox';
+ input.className = 'leaflet-control-layers-selector';
+ input.defaultChecked = checked;
+ } else {
+ input = this._createRadioElement('leaflet-base-layers', checked);
+ }
+
+ this._layerControlInputs.push(input);
+ input.layerId = stamp(obj.layer);
+
+ on(input, 'click', this._onInputClick, this);
+
+ var name = document.createElement('span');
+ name.innerHTML = ' ' + obj.name;
+
+ // Helps from preventing layer control flicker when checkboxes are disabled
+ // https://github.com/Leaflet/Leaflet/issues/2771
+ var holder = document.createElement('div');
+
+ label.appendChild(holder);
+ holder.appendChild(input);
+ holder.appendChild(name);
+
+ var container = obj.overlay ? this._overlaysList : this._baseLayersList;
+ container.appendChild(label);
+
+ this._checkDisabledLayers();
+ return label;
+ },
+
+ _onInputClick: function () {
+ var inputs = this._layerControlInputs,
+ input, layer;
+ var addedLayers = [],
+ removedLayers = [];
+
+ this._handlingClick = true;
+
+ for (var i = inputs.length - 1; i >= 0; i--) {
+ input = inputs[i];
+ layer = this._getLayer(input.layerId).layer;
+
+ if (input.checked) {
+ addedLayers.push(layer);
+ } else if (!input.checked) {
+ removedLayers.push(layer);
+ }
+ }
+
+ // Bugfix issue 2318: Should remove all old layers before readding new ones
+ for (i = 0; i < removedLayers.length; i++) {
+ if (this._map.hasLayer(removedLayers[i])) {
+ this._map.removeLayer(removedLayers[i]);
+ }
+ }
+ for (i = 0; i < addedLayers.length; i++) {
+ if (!this._map.hasLayer(addedLayers[i])) {
+ this._map.addLayer(addedLayers[i]);
+ }
+ }
+
+ this._handlingClick = false;
+
+ this._refocusOnMap();
+ },
+
+ _checkDisabledLayers: function () {
+ var inputs = this._layerControlInputs,
+ input,
+ layer,
+ zoom = this._map.getZoom();
+
+ for (var i = inputs.length - 1; i >= 0; i--) {
+ input = inputs[i];
+ layer = this._getLayer(input.layerId).layer;
+ input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
+ (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
+
+ }
+ },
+
+ _expandIfNotCollapsed: function () {
+ if (this._map && !this.options.collapsed) {
+ this.expand();
+ }
+ return this;
+ },
+
+ _expand: function () {
+ // Backward compatibility, remove me in 1.1.
+ return this.expand();
+ },
+
+ _collapse: function () {
+ // Backward compatibility, remove me in 1.1.
+ return this.collapse();
+ }
+
+});
+
+
+// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
+// Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.
+var layers = function (baseLayers, overlays, options) {
+ return new Layers(baseLayers, overlays, options);
+};
+
+/*
+ * @class Control.Zoom
+ * @aka L.Control.Zoom
+ * @inherits Control
+ *
+ * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.
+ */
+
+var Zoom = Control.extend({
+ // @section
+ // @aka Control.Zoom options
+ options: {
+ position: 'topleft',
+
+ // @option zoomInText: String = '+'
+ // The text set on the 'zoom in' button.
+ zoomInText: '+',
+
+ // @option zoomInTitle: String = 'Zoom in'
+ // The title set on the 'zoom in' button.
+ zoomInTitle: 'Zoom in',
+
+ // @option zoomOutText: String = '&#x2212;'
+ // The text set on the 'zoom out' button.
+ zoomOutText: '&#x2212;',
+
+ // @option zoomOutTitle: String = 'Zoom out'
+ // The title set on the 'zoom out' button.
+ zoomOutTitle: 'Zoom out'
+ },
+
+ onAdd: function (map) {
+ var zoomName = 'leaflet-control-zoom',
+ container = create$1('div', zoomName + ' leaflet-bar'),
+ options = this.options;
+
+ this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,
+ zoomName + '-in', container, this._zoomIn);
+ this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
+ zoomName + '-out', container, this._zoomOut);
+
+ this._updateDisabled();
+ map.on('zoomend zoomlevelschange', this._updateDisabled, this);
+
+ return container;
+ },
+
+ onRemove: function (map) {
+ map.off('zoomend zoomlevelschange', this._updateDisabled, this);
+ },
+
+ disable: function () {
+ this._disabled = true;
+ this._updateDisabled();
+ return this;
+ },
+
+ enable: function () {
+ this._disabled = false;
+ this._updateDisabled();
+ return this;
+ },
+
+ _zoomIn: function (e) {
+ if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
+ this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
+ }
+ },
+
+ _zoomOut: function (e) {
+ if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
+ this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
+ }
+ },
+
+ _createButton: function (html, title, className, container, fn) {
+ var link = create$1('a', className, container);
+ link.innerHTML = html;
+ link.href = '#';
+ link.title = title;
+
+ /*
+ * Will force screen readers like VoiceOver to read this as "Zoom in - button"
+ */
+ link.setAttribute('role', 'button');
+ link.setAttribute('aria-label', title);
+
+ disableClickPropagation(link);
+ on(link, 'click', stop);
+ on(link, 'click', fn, this);
+ on(link, 'click', this._refocusOnMap, this);
+
+ return link;
+ },
+
+ _updateDisabled: function () {
+ var map = this._map,
+ className = 'leaflet-disabled';
+
+ removeClass(this._zoomInButton, className);
+ removeClass(this._zoomOutButton, className);
+
+ if (this._disabled || map._zoom === map.getMinZoom()) {
+ addClass(this._zoomOutButton, className);
+ }
+ if (this._disabled || map._zoom === map.getMaxZoom()) {
+ addClass(this._zoomInButton, className);
+ }
+ }
+});
+
+// @namespace Map
+// @section Control options
+// @option zoomControl: Boolean = true
+// Whether a [zoom control](#control-zoom) is added to the map by default.
+Map.mergeOptions({
+ zoomControl: true
+});
+
+Map.addInitHook(function () {
+ if (this.options.zoomControl) {
+ // @section Controls
+ // @property zoomControl: Control.Zoom
+ // The default zoom control (only available if the
+ // [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).
+ this.zoomControl = new Zoom();
+ this.addControl(this.zoomControl);
+ }
+});
+
+// @namespace Control.Zoom
+// @factory L.control.zoom(options: Control.Zoom options)
+// Creates a zoom control
+var zoom = function (options) {
+ return new Zoom(options);
+};
+
+/*
+ * @class Control.Scale
+ * @aka L.Control.Scale
+ * @inherits Control
+ *
+ * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
+ *
+ * @example
+ *
+ * ```js
+ * L.control.scale().addTo(map);
+ * ```
+ */
+
+var Scale = Control.extend({
+ // @section
+ // @aka Control.Scale options
+ options: {
+ position: 'bottomleft',
+
+ // @option maxWidth: Number = 100
+ // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
+ maxWidth: 100,
+
+ // @option metric: Boolean = True
+ // Whether to show the metric scale line (m/km).
+ metric: true,
+
+ // @option imperial: Boolean = True
+ // Whether to show the imperial scale line (mi/ft).
+ imperial: true
+
+ // @option updateWhenIdle: Boolean = false
+ // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
+ },
+
+ onAdd: function (map) {
+ var className = 'leaflet-control-scale',
+ container = create$1('div', className),
+ options = this.options;
+
+ this._addScales(options, className + '-line', container);
+
+ map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
+ map.whenReady(this._update, this);
+
+ return container;
+ },
+
+ onRemove: function (map) {
+ map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
+ },
+
+ _addScales: function (options, className, container) {
+ if (options.metric) {
+ this._mScale = create$1('div', className, container);
+ }
+ if (options.imperial) {
+ this._iScale = create$1('div', className, container);
+ }
+ },
+
+ _update: function () {
+ var map = this._map,
+ y = map.getSize().y / 2;
+
+ var maxMeters = map.distance(
+ map.containerPointToLatLng([0, y]),
+ map.containerPointToLatLng([this.options.maxWidth, y]));
+
+ this._updateScales(maxMeters);
+ },
+
+ _updateScales: function (maxMeters) {
+ if (this.options.metric && maxMeters) {
+ this._updateMetric(maxMeters);
+ }
+ if (this.options.imperial && maxMeters) {
+ this._updateImperial(maxMeters);
+ }
+ },
+
+ _updateMetric: function (maxMeters) {
+ var meters = this._getRoundNum(maxMeters),
+ label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
+
+ this._updateScale(this._mScale, label, meters / maxMeters);
+ },
+
+ _updateImperial: function (maxMeters) {
+ var maxFeet = maxMeters * 3.2808399,
+ maxMiles, miles, feet;
+
+ if (maxFeet > 5280) {
+ maxMiles = maxFeet / 5280;
+ miles = this._getRoundNum(maxMiles);
+ this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
+
+ } else {
+ feet = this._getRoundNum(maxFeet);
+ this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
+ }
+ },
+
+ _updateScale: function (scale, text, ratio) {
+ scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
+ scale.innerHTML = text;
+ },
+
+ _getRoundNum: function (num) {
+ var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
+ d = num / pow10;
+
+ d = d >= 10 ? 10 :
+ d >= 5 ? 5 :
+ d >= 3 ? 3 :
+ d >= 2 ? 2 : 1;
+
+ return pow10 * d;
+ }
+});
+
+
+// @factory L.control.scale(options?: Control.Scale options)
+// Creates an scale control with the given options.
+var scale = function (options) {
+ return new Scale(options);
+};
+
+/*
+ * @class Control.Attribution
+ * @aka L.Control.Attribution
+ * @inherits Control
+ *
+ * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
+ */
+
+var Attribution = Control.extend({
+ // @section
+ // @aka Control.Attribution options
+ options: {
+ position: 'bottomright',
+
+ // @option prefix: String = 'Leaflet'
+ // The HTML text shown before the attributions. Pass `false` to disable.
+ prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
+ },
+
+ initialize: function (options) {
+ setOptions(this, options);
+
+ this._attributions = {};
+ },
+
+ onAdd: function (map) {
+ map.attributionControl = this;
+ this._container = create$1('div', 'leaflet-control-attribution');
+ disableClickPropagation(this._container);
+
+ // TODO ugly, refactor
+ for (var i in map._layers) {
+ if (map._layers[i].getAttribution) {
+ this.addAttribution(map._layers[i].getAttribution());
+ }
+ }
+
+ this._update();
+
+ return this._container;
+ },
+
+ // @method setPrefix(prefix: String): this
+ // Sets the text before the attributions.
+ setPrefix: function (prefix) {
+ this.options.prefix = prefix;
+ this._update();
+ return this;
+ },
+
+ // @method addAttribution(text: String): this
+ // Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
+ addAttribution: function (text) {
+ if (!text) { return this; }
+
+ if (!this._attributions[text]) {
+ this._attributions[text] = 0;
+ }
+ this._attributions[text]++;
+
+ this._update();
+
+ return this;
+ },
+
+ // @method removeAttribution(text: String): this
+ // Removes an attribution text.
+ removeAttribution: function (text) {
+ if (!text) { return this; }
+
+ if (this._attributions[text]) {
+ this._attributions[text]--;
+ this._update();
+ }
+
+ return this;
+ },
+
+ _update: function () {
+ if (!this._map) { return; }
+
+ var attribs = [];
+
+ for (var i in this._attributions) {
+ if (this._attributions[i]) {
+ attribs.push(i);
+ }
+ }
+
+ var prefixAndAttribs = [];
+
+ if (this.options.prefix) {
+ prefixAndAttribs.push(this.options.prefix);
+ }
+ if (attribs.length) {
+ prefixAndAttribs.push(attribs.join(', '));
+ }
+
+ this._container.innerHTML = prefixAndAttribs.join(' | ');
+ }
+});
+
+// @namespace Map
+// @section Control options
+// @option attributionControl: Boolean = true
+// Whether a [attribution control](#control-attribution) is added to the map by default.
+Map.mergeOptions({
+ attributionControl: true
+});
+
+Map.addInitHook(function () {
+ if (this.options.attributionControl) {
+ new Attribution().addTo(this);
+ }
+});
+
+// @namespace Control.Attribution
+// @factory L.control.attribution(options: Control.Attribution options)
+// Creates an attribution control.
+var attribution = function (options) {
+ return new Attribution(options);
+};
+
+Control.Layers = Layers;
+Control.Zoom = Zoom;
+Control.Scale = Scale;
+Control.Attribution = Attribution;
+
+control.layers = layers;
+control.zoom = zoom;
+control.scale = scale;
+control.attribution = attribution;
+
+/*
+ L.Handler is a base class for handler classes that are used internally to inject
+ interaction features like dragging to classes like Map and Marker.
+*/
+
+// @class Handler
+// @aka L.Handler
+// Abstract class for map interaction handlers
+
+var Handler = Class.extend({
+ initialize: function (map) {
+ this._map = map;
+ },
+
+ // @method enable(): this
+ // Enables the handler
+ enable: function () {
+ if (this._enabled) { return this; }
+
+ this._enabled = true;
+ this.addHooks();
+ return this;
+ },
+
+ // @method disable(): this
+ // Disables the handler
+ disable: function () {
+ if (!this._enabled) { return this; }
+
+ this._enabled = false;
+ this.removeHooks();
+ return this;
+ },
+
+ // @method enabled(): Boolean
+ // Returns `true` if the handler is enabled
+ enabled: function () {
+ return !!this._enabled;
+ }
+
+ // @section Extension methods
+ // Classes inheriting from `Handler` must implement the two following methods:
+ // @method addHooks()
+ // Called when the handler is enabled, should add event hooks.
+ // @method removeHooks()
+ // Called when the handler is disabled, should remove the event hooks added previously.
+});
+
+// @section There is static function which can be called without instantiating L.Handler:
+// @function addTo(map: Map, name: String): this
+// Adds a new Handler to the given map with the given name.
+Handler.addTo = function (map, name) {
+ map.addHandler(name, this);
+ return this;
+};
+
+var Mixin = {Events: Events};
+
+/*
+ * @class Draggable
+ * @aka L.Draggable
+ * @inherits Evented
+ *
+ * A class for making DOM elements draggable (including touch support).
+ * Used internally for map and marker dragging. Only works for elements
+ * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
+ *
+ * @example
+ * ```js
+ * var draggable = new L.Draggable(elementToDrag);
+ * draggable.enable();
+ * ```
+ */
+
+var START = touch ? 'touchstart mousedown' : 'mousedown';
+var END = {
+ mousedown: 'mouseup',
+ touchstart: 'touchend',
+ pointerdown: 'touchend',
+ MSPointerDown: 'touchend'
+};
+var MOVE = {
+ mousedown: 'mousemove',
+ touchstart: 'touchmove',
+ pointerdown: 'touchmove',
+ MSPointerDown: 'touchmove'
+};
+
+
+var Draggable = Evented.extend({
+
+ options: {
+ // @section
+ // @aka Draggable options
+ // @option clickTolerance: Number = 3
+ // The max number of pixels a user can shift the mouse pointer during a click
+ // for it to be considered a valid click (as opposed to a mouse drag).
+ clickTolerance: 3
+ },
+
+ // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
+ // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
+ initialize: function (element, dragStartTarget, preventOutline$$1, options) {
+ setOptions(this, options);
+
+ this._element = element;
+ this._dragStartTarget = dragStartTarget || element;
+ this._preventOutline = preventOutline$$1;
+ },
+
+ // @method enable()
+ // Enables the dragging ability
+ enable: function () {
+ if (this._enabled) { return; }
+
+ on(this._dragStartTarget, START, this._onDown, this);
+
+ this._enabled = true;
+ },
+
+ // @method disable()
+ // Disables the dragging ability
+ disable: function () {
+ if (!this._enabled) { return; }
+
+ // If we're currently dragging this draggable,
+ // disabling it counts as first ending the drag.
+ if (Draggable._dragging === this) {
+ this.finishDrag();
+ }
+
+ off(this._dragStartTarget, START, this._onDown, this);
+
+ this._enabled = false;
+ this._moved = false;
+ },
+
+ _onDown: function (e) {
+ // Ignore simulated events, since we handle both touch and
+ // mouse explicitly; otherwise we risk getting duplicates of
+ // touch events, see #4315.
+ // Also ignore the event if disabled; this happens in IE11
+ // under some circumstances, see #3666.
+ if (e._simulated || !this._enabled) { return; }
+
+ this._moved = false;
+
+ if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
+
+ if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
+ Draggable._dragging = this; // Prevent dragging multiple objects at once.
+
+ if (this._preventOutline) {
+ preventOutline(this._element);
+ }
+
+ disableImageDrag();
+ disableTextSelection();
+
+ if (this._moving) { return; }
+
+ // @event down: Event
+ // Fired when a drag is about to start.
+ this.fire('down');
+
+ var first = e.touches ? e.touches[0] : e,
+ sizedParent = getSizedParentNode(this._element);
+
+ this._startPoint = new Point(first.clientX, first.clientY);
+
+ // Cache the scale, so that we can continuously compensate for it during drag (_onMove).
+ this._parentScale = getScale(sizedParent);
+
+ on(document, MOVE[e.type], this._onMove, this);
+ on(document, END[e.type], this._onUp, this);
+ },
+
+ _onMove: function (e) {
+ // Ignore simulated events, since we handle both touch and
+ // mouse explicitly; otherwise we risk getting duplicates of
+ // touch events, see #4315.
+ // Also ignore the event if disabled; this happens in IE11
+ // under some circumstances, see #3666.
+ if (e._simulated || !this._enabled) { return; }
+
+ if (e.touches && e.touches.length > 1) {
+ this._moved = true;
+ return;
+ }
+
+ var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
+ offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);
+
+ if (!offset.x && !offset.y) { return; }
+ if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
+
+ // We assume that the parent container's position, border and scale do not change for the duration of the drag.
+ // Therefore there is no need to account for the position and border (they are eliminated by the subtraction)
+ // and we can use the cached value for the scale.
+ offset.x /= this._parentScale.x;
+ offset.y /= this._parentScale.y;
+
+ preventDefault(e);
+
+ if (!this._moved) {
+ // @event dragstart: Event
+ // Fired when a drag starts
+ this.fire('dragstart');
+
+ this._moved = true;
+ this._startPos = getPosition(this._element).subtract(offset);
+
+ addClass(document.body, 'leaflet-dragging');
+
+ this._lastTarget = e.target || e.srcElement;
+ // IE and Edge do not give the <use> element, so fetch it
+ // if necessary
+ if ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) {
+ this._lastTarget = this._lastTarget.correspondingUseElement;
+ }
+ addClass(this._lastTarget, 'leaflet-drag-target');
+ }
+
+ this._newPos = this._startPos.add(offset);
+ this._moving = true;
+
+ cancelAnimFrame(this._animRequest);
+ this._lastEvent = e;
+ this._animRequest = requestAnimFrame(this._updatePosition, this, true);
+ },
+
+ _updatePosition: function () {
+ var e = {originalEvent: this._lastEvent};
+
+ // @event predrag: Event
+ // Fired continuously during dragging *before* each corresponding
+ // update of the element's position.
+ this.fire('predrag', e);
+ setPosition(this._element, this._newPos);
+
+ // @event drag: Event
+ // Fired continuously during dragging.
+ this.fire('drag', e);
+ },
+
+ _onUp: function (e) {
+ // Ignore simulated events, since we handle both touch and
+ // mouse explicitly; otherwise we risk getting duplicates of
+ // touch events, see #4315.
+ // Also ignore the event if disabled; this happens in IE11
+ // under some circumstances, see #3666.
+ if (e._simulated || !this._enabled) { return; }
+ this.finishDrag();
+ },
+
+ finishDrag: function () {
+ removeClass(document.body, 'leaflet-dragging');
+
+ if (this._lastTarget) {
+ removeClass(this._lastTarget, 'leaflet-drag-target');
+ this._lastTarget = null;
+ }
+
+ for (var i in MOVE) {
+ off(document, MOVE[i], this._onMove, this);
+ off(document, END[i], this._onUp, this);
+ }
+
+ enableImageDrag();
+ enableTextSelection();
+
+ if (this._moved && this._moving) {
+ // ensure drag is not fired after dragend
+ cancelAnimFrame(this._animRequest);
+
+ // @event dragend: DragEndEvent
+ // Fired when the drag ends.
+ this.fire('dragend', {
+ distance: this._newPos.distanceTo(this._startPos)
+ });
+ }
+
+ this._moving = false;
+ Draggable._dragging = false;
+ }
+
+});
+
+/*
+ * @namespace LineUtil
+ *
+ * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
+ */
+
+// Simplify polyline with vertex reduction and Douglas-Peucker simplification.
+// Improves rendering performance dramatically by lessening the number of points to draw.
+
+// @function simplify(points: Point[], tolerance: Number): Point[]
+// Dramatically reduces the number of points in a polyline while retaining
+// its shape and returns a new array of simplified points, using the
+// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
+// Used for a huge performance boost when processing/displaying Leaflet polylines for
+// each zoom level and also reducing visual noise. tolerance affects the amount of
+// simplification (lesser value means higher quality but slower and with more points).
+// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
+function simplify(points, tolerance) {
+ if (!tolerance || !points.length) {
+ return points.slice();
+ }
+
+ var sqTolerance = tolerance * tolerance;
+
+ // stage 1: vertex reduction
+ points = _reducePoints(points, sqTolerance);
+
+ // stage 2: Douglas-Peucker simplification
+ points = _simplifyDP(points, sqTolerance);
+
+ return points;
+}
+
+// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
+// Returns the distance between point `p` and segment `p1` to `p2`.
+function pointToSegmentDistance(p, p1, p2) {
+ return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
+}
+
+// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
+// Returns the closest point from a point `p` on a segment `p1` to `p2`.
+function closestPointOnSegment(p, p1, p2) {
+ return _sqClosestPointOnSegment(p, p1, p2);
+}
+
+// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
+function _simplifyDP(points, sqTolerance) {
+
+ var len = points.length,
+ ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
+ markers = new ArrayConstructor(len);
+
+ markers[0] = markers[len - 1] = 1;
+
+ _simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
+
+ var i,
+ newPoints = [];
+
+ for (i = 0; i < len; i++) {
+ if (markers[i]) {
+ newPoints.push(points[i]);
+ }
+ }
+
+ return newPoints;
+}
+
+function _simplifyDPStep(points, markers, sqTolerance, first, last) {
+
+ var maxSqDist = 0,
+ index, i, sqDist;
+
+ for (i = first + 1; i <= last - 1; i++) {
+ sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
+
+ if (sqDist > maxSqDist) {
+ index = i;
+ maxSqDist = sqDist;
+ }
+ }
+
+ if (maxSqDist > sqTolerance) {
+ markers[index] = 1;
+
+ _simplifyDPStep(points, markers, sqTolerance, first, index);
+ _simplifyDPStep(points, markers, sqTolerance, index, last);
+ }
+}
+
+// reduce points that are too close to each other to a single point
+function _reducePoints(points, sqTolerance) {
+ var reducedPoints = [points[0]];
+
+ for (var i = 1, prev = 0, len = points.length; i < len; i++) {
+ if (_sqDist(points[i], points[prev]) > sqTolerance) {
+ reducedPoints.push(points[i]);
+ prev = i;
+ }
+ }
+ if (prev < len - 1) {
+ reducedPoints.push(points[len - 1]);
+ }
+ return reducedPoints;
+}
+
+var _lastCode;
+
+// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
+// Clips the segment a to b by rectangular bounds with the
+// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
+// (modifying the segment points directly!). Used by Leaflet to only show polyline
+// points that are on the screen or near, increasing performance.
+function clipSegment(a, b, bounds, useLastCode, round) {
+ var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
+ codeB = _getBitCode(b, bounds),
+
+ codeOut, p, newCode;
+
+ // save 2nd code to avoid calculating it on the next segment
+ _lastCode = codeB;
+
+ while (true) {
+ // if a,b is inside the clip window (trivial accept)
+ if (!(codeA | codeB)) {
+ return [a, b];
+ }
+
+ // if a,b is outside the clip window (trivial reject)
+ if (codeA & codeB) {
+ return false;
+ }
+
+ // other cases
+ codeOut = codeA || codeB;
+ p = _getEdgeIntersection(a, b, codeOut, bounds, round);
+ newCode = _getBitCode(p, bounds);
+
+ if (codeOut === codeA) {
+ a = p;
+ codeA = newCode;
+ } else {
+ b = p;
+ codeB = newCode;
+ }
+ }
+}
+
+function _getEdgeIntersection(a, b, code, bounds, round) {
+ var dx = b.x - a.x,
+ dy = b.y - a.y,
+ min = bounds.min,
+ max = bounds.max,
+ x, y;
+
+ if (code & 8) { // top
+ x = a.x + dx * (max.y - a.y) / dy;
+ y = max.y;
+
+ } else if (code & 4) { // bottom
+ x = a.x + dx * (min.y - a.y) / dy;
+ y = min.y;
+
+ } else if (code & 2) { // right
+ x = max.x;
+ y = a.y + dy * (max.x - a.x) / dx;
+
+ } else if (code & 1) { // left
+ x = min.x;
+ y = a.y + dy * (min.x - a.x) / dx;
+ }
+
+ return new Point(x, y, round);
+}
+
+function _getBitCode(p, bounds) {
+ var code = 0;
+
+ if (p.x < bounds.min.x) { // left
+ code |= 1;
+ } else if (p.x > bounds.max.x) { // right
+ code |= 2;
+ }
+
+ if (p.y < bounds.min.y) { // bottom
+ code |= 4;
+ } else if (p.y > bounds.max.y) { // top
+ code |= 8;
+ }
+
+ return code;
+}
+
+// square distance (to avoid unnecessary Math.sqrt calls)
+function _sqDist(p1, p2) {
+ var dx = p2.x - p1.x,
+ dy = p2.y - p1.y;
+ return dx * dx + dy * dy;
+}
+
+// return closest point on segment or distance to that point
+function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
+ var x = p1.x,
+ y = p1.y,
+ dx = p2.x - x,
+ dy = p2.y - y,
+ dot = dx * dx + dy * dy,
+ t;
+
+ if (dot > 0) {
+ t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
+
+ if (t > 1) {
+ x = p2.x;
+ y = p2.y;
+ } else if (t > 0) {
+ x += dx * t;
+ y += dy * t;
+ }
+ }
+
+ dx = p.x - x;
+ dy = p.y - y;
+
+ return sqDist ? dx * dx + dy * dy : new Point(x, y);
+}
+
+
+// @function isFlat(latlngs: LatLng[]): Boolean
+// Returns true if `latlngs` is a flat array, false is nested.
+function isFlat(latlngs) {
+ return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
+}
+
+function _flat(latlngs) {
+ console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
+ return isFlat(latlngs);
+}
+
+
+var LineUtil = (Object.freeze || Object)({
+ simplify: simplify,
+ pointToSegmentDistance: pointToSegmentDistance,
+ closestPointOnSegment: closestPointOnSegment,
+ clipSegment: clipSegment,
+ _getEdgeIntersection: _getEdgeIntersection,
+ _getBitCode: _getBitCode,
+ _sqClosestPointOnSegment: _sqClosestPointOnSegment,
+ isFlat: isFlat,
+ _flat: _flat
+});
+
+/*
+ * @namespace PolyUtil
+ * Various utility functions for polygon geometries.
+ */
+
+/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
+ * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
+ * Used by Leaflet to only show polygon points that are on the screen or near, increasing
+ * performance. Note that polygon points needs different algorithm for clipping
+ * than polyline, so there's a separate method for it.
+ */
+function clipPolygon(points, bounds, round) {
+ var clippedPoints,
+ edges = [1, 4, 2, 8],
+ i, j, k,
+ a, b,
+ len, edge, p;
+
+ for (i = 0, len = points.length; i < len; i++) {
+ points[i]._code = _getBitCode(points[i], bounds);
+ }
+
+ // for each edge (left, bottom, right, top)
+ for (k = 0; k < 4; k++) {
+ edge = edges[k];
+ clippedPoints = [];
+
+ for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
+ a = points[i];
+ b = points[j];
+
+ // if a is inside the clip window
+ if (!(a._code & edge)) {
+ // if b is outside the clip window (a->b goes out of screen)
+ if (b._code & edge) {
+ p = _getEdgeIntersection(b, a, edge, bounds, round);
+ p._code = _getBitCode(p, bounds);
+ clippedPoints.push(p);
+ }
+ clippedPoints.push(a);
+
+ // else if b is inside the clip window (a->b enters the screen)
+ } else if (!(b._code & edge)) {
+ p = _getEdgeIntersection(b, a, edge, bounds, round);
+ p._code = _getBitCode(p, bounds);
+ clippedPoints.push(p);
+ }
+ }
+ points = clippedPoints;
+ }
+
+ return points;
+}
+
+
+var PolyUtil = (Object.freeze || Object)({
+ clipPolygon: clipPolygon
+});
+
+/*
+ * @namespace Projection
+ * @section
+ * Leaflet comes with a set of already defined Projections out of the box:
+ *
+ * @projection L.Projection.LonLat
+ *
+ * Equirectangular, or Plate Carree projection — the most simple projection,
+ * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
+ * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
+ * `EPSG:4326` and `Simple` CRS.
+ */
+
+var LonLat = {
+ project: function (latlng) {
+ return new Point(latlng.lng, latlng.lat);
+ },
+
+ unproject: function (point) {
+ return new LatLng(point.y, point.x);
+ },
+
+ bounds: new Bounds([-180, -90], [180, 90])
+};
+
+/*
+ * @namespace Projection
+ * @projection L.Projection.Mercator
+ *
+ * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.
+ */
+
+var Mercator = {
+ R: 6378137,
+ R_MINOR: 6356752.314245179,
+
+ bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
+
+ project: function (latlng) {
+ var d = Math.PI / 180,
+ r = this.R,
+ y = latlng.lat * d,
+ tmp = this.R_MINOR / r,
+ e = Math.sqrt(1 - tmp * tmp),
+ con = e * Math.sin(y);
+
+ var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
+ y = -r * Math.log(Math.max(ts, 1E-10));
+
+ return new Point(latlng.lng * d * r, y);
+ },
+
+ unproject: function (point) {
+ var d = 180 / Math.PI,
+ r = this.R,
+ tmp = this.R_MINOR / r,
+ e = Math.sqrt(1 - tmp * tmp),
+ ts = Math.exp(-point.y / r),
+ phi = Math.PI / 2 - 2 * Math.atan(ts);
+
+ for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
+ con = e * Math.sin(phi);
+ con = Math.pow((1 - con) / (1 + con), e / 2);
+ dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
+ phi += dphi;
+ }
+
+ return new LatLng(phi * d, point.x * d / r);
+ }
+};
+
+/*
+ * @class Projection
+
+ * An object with methods for projecting geographical coordinates of the world onto
+ * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection).
+
+ * @property bounds: Bounds
+ * The bounds (specified in CRS units) where the projection is valid
+
+ * @method project(latlng: LatLng): Point
+ * Projects geographical coordinates into a 2D point.
+ * Only accepts actual `L.LatLng` instances, not arrays.
+
+ * @method unproject(point: Point): LatLng
+ * The inverse of `project`. Projects a 2D point into a geographical location.
+ * Only accepts actual `L.Point` instances, not arrays.
+
+ * Note that the projection instances do not inherit from Leafet's `Class` object,
+ * and can't be instantiated. Also, new classes can't inherit from them,
+ * and methods can't be added to them with the `include` function.
+
+ */
+
+
+
+
+var index = (Object.freeze || Object)({
+ LonLat: LonLat,
+ Mercator: Mercator,
+ SphericalMercator: SphericalMercator
+});
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.EPSG3395
+ *
+ * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
+ */
+var EPSG3395 = extend({}, Earth, {
+ code: 'EPSG:3395',
+ projection: Mercator,
+
+ transformation: (function () {
+ var scale = 0.5 / (Math.PI * Mercator.R);
+ return toTransformation(scale, 0.5, -scale, 0.5);
+ }())
+});
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.EPSG4326
+ *
+ * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
+ *
+ * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
+ * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer`
+ * with this CRS, ensure that there are two 256x256 pixel tiles covering the
+ * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
+ * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
+ */
+
+var EPSG4326 = extend({}, Earth, {
+ code: 'EPSG:4326',
+ projection: LonLat,
+ transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)
+});
+
+/*
+ * @namespace CRS
+ * @crs L.CRS.Simple
+ *
+ * A simple CRS that maps longitude and latitude into `x` and `y` directly.
+ * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
+ * axis should still be inverted (going from bottom to top). `distance()` returns
+ * simple euclidean distance.
+ */
+
+var Simple = extend({}, CRS, {
+ projection: LonLat,
+ transformation: toTransformation(1, 0, -1, 0),
+
+ scale: function (zoom) {
+ return Math.pow(2, zoom);
+ },
+
+ zoom: function (scale) {
+ return Math.log(scale) / Math.LN2;
+ },
+
+ distance: function (latlng1, latlng2) {
+ var dx = latlng2.lng - latlng1.lng,
+ dy = latlng2.lat - latlng1.lat;
+
+ return Math.sqrt(dx * dx + dy * dy);
+ },
+
+ infinite: true
+});
+
+CRS.Earth = Earth;
+CRS.EPSG3395 = EPSG3395;
+CRS.EPSG3857 = EPSG3857;
+CRS.EPSG900913 = EPSG900913;
+CRS.EPSG4326 = EPSG4326;
+CRS.Simple = Simple;
+
+/*
+ * @class Layer
+ * @inherits Evented
+ * @aka L.Layer
+ * @aka ILayer
+ *
+ * A set of methods from the Layer base class that all Leaflet layers use.
+ * Inherits all methods, options and events from `L.Evented`.
+ *
+ * @example
+ *
+ * ```js
+ * var layer = L.Marker(latlng).addTo(map);
+ * layer.addTo(map);
+ * layer.remove();
+ * ```
+ *
+ * @event add: Event
+ * Fired after the layer is added to a map
+ *
+ * @event remove: Event
+ * Fired after the layer is removed from a map
+ */
+
+
+var Layer = Evented.extend({
+
+ // Classes extending `L.Layer` will inherit the following options:
+ options: {
+ // @option pane: String = 'overlayPane'
+ // By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.
+ pane: 'overlayPane',
+
+ // @option attribution: String = null
+ // String to be shown in the attribution control, e.g. "© OpenStreetMap contributors". It describes the layer data and is often a legal obligation towards copyright holders and tile providers.
+ attribution: null,
+
+ bubblingMouseEvents: true
+ },
+
+ /* @section
+ * Classes extending `L.Layer` will inherit the following methods:
+ *
+ * @method addTo(map: Map|LayerGroup): this
+ * Adds the layer to the given map or layer group.
+ */
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ // @method remove: this
+ // Removes the layer from the map it is currently active on.
+ remove: function () {
+ return this.removeFrom(this._map || this._mapToAdd);
+ },
+
+ // @method removeFrom(map: Map): this
+ // Removes the layer from the given map
+ removeFrom: function (obj) {
+ if (obj) {
+ obj.removeLayer(this);
+ }
+ return this;
+ },
+
+ // @method getPane(name? : String): HTMLElement
+ // Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
+ getPane: function (name) {
+ return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
+ },
+
+ addInteractiveTarget: function (targetEl) {
+ this._map._targets[stamp(targetEl)] = this;
+ return this;
+ },
+
+ removeInteractiveTarget: function (targetEl) {
+ delete this._map._targets[stamp(targetEl)];
+ return this;
+ },
+
+ // @method getAttribution: String
+ // Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
+ getAttribution: function () {
+ return this.options.attribution;
+ },
+
+ _layerAdd: function (e) {
+ var map = e.target;
+
+ // check in case layer gets added and then removed before the map is ready
+ if (!map.hasLayer(this)) { return; }
+
+ this._map = map;
+ this._zoomAnimated = map._zoomAnimated;
+
+ if (this.getEvents) {
+ var events = this.getEvents();
+ map.on(events, this);
+ this.once('remove', function () {
+ map.off(events, this);
+ }, this);
+ }
+
+ this.onAdd(map);
+
+ if (this.getAttribution && map.attributionControl) {
+ map.attributionControl.addAttribution(this.getAttribution());
+ }
+
+ this.fire('add');
+ map.fire('layeradd', {layer: this});
+ }
+});
+
+/* @section Extension methods
+ * @uninheritable
+ *
+ * Every layer should extend from `L.Layer` and (re-)implement the following methods.
+ *
+ * @method onAdd(map: Map): this
+ * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).
+ *
+ * @method onRemove(map: Map): this
+ * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).
+ *
+ * @method getEvents(): Object
+ * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.
+ *
+ * @method getAttribution(): String
+ * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
+ *
+ * @method beforeAdd(map: Map): this
+ * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.
+ */
+
+
+/* @namespace Map
+ * @section Layer events
+ *
+ * @event layeradd: LayerEvent
+ * Fired when a new layer is added to the map.
+ *
+ * @event layerremove: LayerEvent
+ * Fired when some layer is removed from the map
+ *
+ * @section Methods for Layers and Controls
+ */
+Map.include({
+ // @method addLayer(layer: Layer): this
+ // Adds the given layer to the map
+ addLayer: function (layer) {
+ if (!layer._layerAdd) {
+ throw new Error('The provided object is not a Layer.');
+ }
+
+ var id = stamp(layer);
+ if (this._layers[id]) { return this; }
+ this._layers[id] = layer;
+
+ layer._mapToAdd = this;
+
+ if (layer.beforeAdd) {
+ layer.beforeAdd(this);
+ }
+
+ this.whenReady(layer._layerAdd, layer);
+
+ return this;
+ },
+
+ // @method removeLayer(layer: Layer): this
+ // Removes the given layer from the map.
+ removeLayer: function (layer) {
+ var id = stamp(layer);
+
+ if (!this._layers[id]) { return this; }
+
+ if (this._loaded) {
+ layer.onRemove(this);
+ }
+
+ if (layer.getAttribution && this.attributionControl) {
+ this.attributionControl.removeAttribution(layer.getAttribution());
+ }
+
+ delete this._layers[id];
+
+ if (this._loaded) {
+ this.fire('layerremove', {layer: layer});
+ layer.fire('remove');
+ }
+
+ layer._map = layer._mapToAdd = null;
+
+ return this;
+ },
+
+ // @method hasLayer(layer: Layer): Boolean
+ // Returns `true` if the given layer is currently added to the map
+ hasLayer: function (layer) {
+ return !!layer && (stamp(layer) in this._layers);
+ },
+
+ /* @method eachLayer(fn: Function, context?: Object): this
+ * Iterates over the layers of the map, optionally specifying context of the iterator function.
+ * ```
+ * map.eachLayer(function(layer){
+ * layer.bindPopup('Hello');
+ * });
+ * ```
+ */
+ eachLayer: function (method, context) {
+ for (var i in this._layers) {
+ method.call(context, this._layers[i]);
+ }
+ return this;
+ },
+
+ _addLayers: function (layers) {
+ layers = layers ? (isArray(layers) ? layers : [layers]) : [];
+
+ for (var i = 0, len = layers.length; i < len; i++) {
+ this.addLayer(layers[i]);
+ }
+ },
+
+ _addZoomLimit: function (layer) {
+ if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
+ this._zoomBoundLayers[stamp(layer)] = layer;
+ this._updateZoomLevels();
+ }
+ },
+
+ _removeZoomLimit: function (layer) {
+ var id = stamp(layer);
+
+ if (this._zoomBoundLayers[id]) {
+ delete this._zoomBoundLayers[id];
+ this._updateZoomLevels();
+ }
+ },
+
+ _updateZoomLevels: function () {
+ var minZoom = Infinity,
+ maxZoom = -Infinity,
+ oldZoomSpan = this._getZoomSpan();
+
+ for (var i in this._zoomBoundLayers) {
+ var options = this._zoomBoundLayers[i].options;
+
+ minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
+ maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
+ }
+
+ this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
+ this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
+
+ // @section Map state change events
+ // @event zoomlevelschange: Event
+ // Fired when the number of zoomlevels on the map is changed due
+ // to adding or removing a layer.
+ if (oldZoomSpan !== this._getZoomSpan()) {
+ this.fire('zoomlevelschange');
+ }
+
+ if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
+ this.setZoom(this._layersMaxZoom);
+ }
+ if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
+ this.setZoom(this._layersMinZoom);
+ }
+ }
+});
+
+/*
+ * @class LayerGroup
+ * @aka L.LayerGroup
+ * @inherits Layer
+ *
+ * Used to group several layers and handle them as one. If you add it to the map,
+ * any layers added or removed from the group will be added/removed on the map as
+ * well. Extends `Layer`.
+ *
+ * @example
+ *
+ * ```js
+ * L.layerGroup([marker1, marker2])
+ * .addLayer(polyline)
+ * .addTo(map);
+ * ```
+ */
+
+var LayerGroup = Layer.extend({
+
+ initialize: function (layers, options) {
+ setOptions(this, options);
+
+ this._layers = {};
+
+ var i, len;
+
+ if (layers) {
+ for (i = 0, len = layers.length; i < len; i++) {
+ this.addLayer(layers[i]);
+ }
+ }
+ },
+
+ // @method addLayer(layer: Layer): this
+ // Adds the given layer to the group.
+ addLayer: function (layer) {
+ var id = this.getLayerId(layer);
+
+ this._layers[id] = layer;
+
+ if (this._map) {
+ this._map.addLayer(layer);
+ }
+
+ return this;
+ },
+
+ // @method removeLayer(layer: Layer): this
+ // Removes the given layer from the group.
+ // @alternative
+ // @method removeLayer(id: Number): this
+ // Removes the layer with the given internal ID from the group.
+ removeLayer: function (layer) {
+ var id = layer in this._layers ? layer : this.getLayerId(layer);
+
+ if (this._map && this._layers[id]) {
+ this._map.removeLayer(this._layers[id]);
+ }
+
+ delete this._layers[id];
+
+ return this;
+ },
+
+ // @method hasLayer(layer: Layer): Boolean
+ // Returns `true` if the given layer is currently added to the group.
+ // @alternative
+ // @method hasLayer(id: Number): Boolean
+ // Returns `true` if the given internal ID is currently added to the group.
+ hasLayer: function (layer) {
+ return !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers);
+ },
+
+ // @method clearLayers(): this
+ // Removes all the layers from the group.
+ clearLayers: function () {
+ return this.eachLayer(this.removeLayer, this);
+ },
+
+ // @method invoke(methodName: String, …): this
+ // Calls `methodName` on every layer contained in this group, passing any
+ // additional parameters. Has no effect if the layers contained do not
+ // implement `methodName`.
+ invoke: function (methodName) {
+ var args = Array.prototype.slice.call(arguments, 1),
+ i, layer;
+
+ for (i in this._layers) {
+ layer = this._layers[i];
+
+ if (layer[methodName]) {
+ layer[methodName].apply(layer, args);
+ }
+ }
+
+ return this;
+ },
+
+ onAdd: function (map) {
+ this.eachLayer(map.addLayer, map);
+ },
+
+ onRemove: function (map) {
+ this.eachLayer(map.removeLayer, map);
+ },
+
+ // @method eachLayer(fn: Function, context?: Object): this
+ // Iterates over the layers of the group, optionally specifying context of the iterator function.
+ // ```js
+ // group.eachLayer(function (layer) {
+ // layer.bindPopup('Hello');
+ // });
+ // ```
+ eachLayer: function (method, context) {
+ for (var i in this._layers) {
+ method.call(context, this._layers[i]);
+ }
+ return this;
+ },
+
+ // @method getLayer(id: Number): Layer
+ // Returns the layer with the given internal ID.
+ getLayer: function (id) {
+ return this._layers[id];
+ },
+
+ // @method getLayers(): Layer[]
+ // Returns an array of all the layers added to the group.
+ getLayers: function () {
+ var layers = [];
+ this.eachLayer(layers.push, layers);
+ return layers;
+ },
+
+ // @method setZIndex(zIndex: Number): this
+ // Calls `setZIndex` on every layer contained in this group, passing the z-index.
+ setZIndex: function (zIndex) {
+ return this.invoke('setZIndex', zIndex);
+ },
+
+ // @method getLayerId(layer: Layer): Number
+ // Returns the internal ID for a layer
+ getLayerId: function (layer) {
+ return stamp(layer);
+ }
+});
+
+
+// @factory L.layerGroup(layers?: Layer[], options?: Object)
+// Create a layer group, optionally given an initial set of layers and an `options` object.
+var layerGroup = function (layers, options) {
+ return new LayerGroup(layers, options);
+};
+
+/*
+ * @class FeatureGroup
+ * @aka L.FeatureGroup
+ * @inherits LayerGroup
+ *
+ * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
+ * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
+ * * Events are propagated to the `FeatureGroup`, so if the group has an event
+ * handler, it will handle events from any of the layers. This includes mouse events
+ * and custom events.
+ * * Has `layeradd` and `layerremove` events
+ *
+ * @example
+ *
+ * ```js
+ * L.featureGroup([marker1, marker2, polyline])
+ * .bindPopup('Hello world!')
+ * .on('click', function() { alert('Clicked on a member of the group!'); })
+ * .addTo(map);
+ * ```
+ */
+
+var FeatureGroup = LayerGroup.extend({
+
+ addLayer: function (layer) {
+ if (this.hasLayer(layer)) {
+ return this;
+ }
+
+ layer.addEventParent(this);
+
+ LayerGroup.prototype.addLayer.call(this, layer);
+
+ // @event layeradd: LayerEvent
+ // Fired when a layer is added to this `FeatureGroup`
+ return this.fire('layeradd', {layer: layer});
+ },
+
+ removeLayer: function (layer) {
+ if (!this.hasLayer(layer)) {
+ return this;
+ }
+ if (layer in this._layers) {
+ layer = this._layers[layer];
+ }
+
+ layer.removeEventParent(this);
+
+ LayerGroup.prototype.removeLayer.call(this, layer);
+
+ // @event layerremove: LayerEvent
+ // Fired when a layer is removed from this `FeatureGroup`
+ return this.fire('layerremove', {layer: layer});
+ },
+
+ // @method setStyle(style: Path options): this
+ // Sets the given path options to each layer of the group that has a `setStyle` method.
+ setStyle: function (style) {
+ return this.invoke('setStyle', style);
+ },
+
+ // @method bringToFront(): this
+ // Brings the layer group to the top of all other layers
+ bringToFront: function () {
+ return this.invoke('bringToFront');
+ },
+
+ // @method bringToBack(): this
+ // Brings the layer group to the back of all other layers
+ bringToBack: function () {
+ return this.invoke('bringToBack');
+ },
+
+ // @method getBounds(): LatLngBounds
+ // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
+ getBounds: function () {
+ var bounds = new LatLngBounds();
+
+ for (var id in this._layers) {
+ var layer = this._layers[id];
+ bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
+ }
+ return bounds;
+ }
+});
+
+// @factory L.featureGroup(layers: Layer[])
+// Create a feature group, optionally given an initial set of layers.
+var featureGroup = function (layers) {
+ return new FeatureGroup(layers);
+};
+
+/*
+ * @class Icon
+ * @aka L.Icon
+ *
+ * Represents an icon to provide when creating a marker.
+ *
+ * @example
+ *
+ * ```js
+ * var myIcon = L.icon({
+ * iconUrl: 'my-icon.png',
+ * iconRetinaUrl: 'my-icon@2x.png',
+ * iconSize: [38, 95],
+ * iconAnchor: [22, 94],
+ * popupAnchor: [-3, -76],
+ * shadowUrl: 'my-icon-shadow.png',
+ * shadowRetinaUrl: 'my-icon-shadow@2x.png',
+ * shadowSize: [68, 95],
+ * shadowAnchor: [22, 94]
+ * });
+ *
+ * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
+ * ```
+ *
+ * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
+ *
+ */
+
+var Icon = Class.extend({
+
+ /* @section
+ * @aka Icon options
+ *
+ * @option iconUrl: String = null
+ * **(required)** The URL to the icon image (absolute or relative to your script path).
+ *
+ * @option iconRetinaUrl: String = null
+ * The URL to a retina sized version of the icon image (absolute or relative to your
+ * script path). Used for Retina screen devices.
+ *
+ * @option iconSize: Point = null
+ * Size of the icon image in pixels.
+ *
+ * @option iconAnchor: Point = null
+ * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
+ * will be aligned so that this point is at the marker's geographical location. Centered
+ * by default if size is specified, also can be set in CSS with negative margins.
+ *
+ * @option popupAnchor: Point = [0, 0]
+ * The coordinates of the point from which popups will "open", relative to the icon anchor.
+ *
+ * @option tooltipAnchor: Point = [0, 0]
+ * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
+ *
+ * @option shadowUrl: String = null
+ * The URL to the icon shadow image. If not specified, no shadow image will be created.
+ *
+ * @option shadowRetinaUrl: String = null
+ *
+ * @option shadowSize: Point = null
+ * Size of the shadow image in pixels.
+ *
+ * @option shadowAnchor: Point = null
+ * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
+ * as iconAnchor if not specified).
+ *
+ * @option className: String = ''
+ * A custom class name to assign to both icon and shadow images. Empty by default.
+ */
+
+ options: {
+ popupAnchor: [0, 0],
+ tooltipAnchor: [0, 0]
+ },
+
+ initialize: function (options) {
+ setOptions(this, options);
+ },
+
+ // @method createIcon(oldIcon?: HTMLElement): HTMLElement
+ // Called internally when the icon has to be shown, returns a `<img>` HTML element
+ // styled according to the options.
+ createIcon: function (oldIcon) {
+ return this._createIcon('icon', oldIcon);
+ },
+
+ // @method createShadow(oldIcon?: HTMLElement): HTMLElement
+ // As `createIcon`, but for the shadow beneath it.
+ createShadow: function (oldIcon) {
+ return this._createIcon('shadow', oldIcon);
+ },
+
+ _createIcon: function (name, oldIcon) {
+ var src = this._getIconUrl(name);
+
+ if (!src) {
+ if (name === 'icon') {
+ throw new Error('iconUrl not set in Icon options (see the docs).');
+ }
+ return null;
+ }
+
+ var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
+ this._setIconStyles(img, name);
+
+ return img;
+ },
+
+ _setIconStyles: function (img, name) {
+ var options = this.options;
+ var sizeOption = options[name + 'Size'];
+
+ if (typeof sizeOption === 'number') {
+ sizeOption = [sizeOption, sizeOption];
+ }
+
+ var size = toPoint(sizeOption),
+ anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
+ size && size.divideBy(2, true));
+
+ img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
+
+ if (anchor) {
+ img.style.marginLeft = (-anchor.x) + 'px';
+ img.style.marginTop = (-anchor.y) + 'px';
+ }
+
+ if (size) {
+ img.style.width = size.x + 'px';
+ img.style.height = size.y + 'px';
+ }
+ },
+
+ _createImg: function (src, el) {
+ el = el || document.createElement('img');
+ el.src = src;
+ return el;
+ },
+
+ _getIconUrl: function (name) {
+ return retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
+ }
+});
+
+
+// @factory L.icon(options: Icon options)
+// Creates an icon instance with the given options.
+function icon(options) {
+ return new Icon(options);
+}
+
+/*
+ * @miniclass Icon.Default (Icon)
+ * @aka L.Icon.Default
+ * @section
+ *
+ * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
+ * no icon is specified. Points to the blue marker image distributed with Leaflet
+ * releases.
+ *
+ * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
+ * (which is a set of `Icon options`).
+ *
+ * If you want to _completely_ replace the default icon, override the
+ * `L.Marker.prototype.options.icon` with your own icon instead.
+ */
+
+var IconDefault = Icon.extend({
+
+ options: {
+ iconUrl: 'marker-icon.png',
+ iconRetinaUrl: 'marker-icon-2x.png',
+ shadowUrl: 'marker-shadow.png',
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+ tooltipAnchor: [16, -28],
+ shadowSize: [41, 41]
+ },
+
+ _getIconUrl: function (name) {
+ if (!IconDefault.imagePath) { // Deprecated, backwards-compatibility only
+ IconDefault.imagePath = this._detectIconPath();
+ }
+
+ // @option imagePath: String
+ // `Icon.Default` will try to auto-detect the location of the
+ // blue icon images. If you are placing these images in a non-standard
+ // way, set this option to point to the right path.
+ return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
+ },
+
+ _detectIconPath: function () {
+ var el = create$1('div', 'leaflet-default-icon-path', document.body);
+ var path = getStyle(el, 'background-image') ||
+ getStyle(el, 'backgroundImage'); // IE8
+
+ document.body.removeChild(el);
+
+ if (path === null || path.indexOf('url') !== 0) {
+ path = '';
+ } else {
+ path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, '');
+ }
+
+ return path;
+ }
+});
+
+/*
+ * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
+ */
+
+
+/* @namespace Marker
+ * @section Interaction handlers
+ *
+ * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:
+ *
+ * ```js
+ * marker.dragging.disable();
+ * ```
+ *
+ * @property dragging: Handler
+ * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).
+ */
+
+var MarkerDrag = Handler.extend({
+ initialize: function (marker) {
+ this._marker = marker;
+ },
+
+ addHooks: function () {
+ var icon = this._marker._icon;
+
+ if (!this._draggable) {
+ this._draggable = new Draggable(icon, icon, true);
+ }
+
+ this._draggable.on({
+ dragstart: this._onDragStart,
+ predrag: this._onPreDrag,
+ drag: this._onDrag,
+ dragend: this._onDragEnd
+ }, this).enable();
+
+ addClass(icon, 'leaflet-marker-draggable');
+ },
+
+ removeHooks: function () {
+ this._draggable.off({
+ dragstart: this._onDragStart,
+ predrag: this._onPreDrag,
+ drag: this._onDrag,
+ dragend: this._onDragEnd
+ }, this).disable();
+
+ if (this._marker._icon) {
+ removeClass(this._marker._icon, 'leaflet-marker-draggable');
+ }
+ },
+
+ moved: function () {
+ return this._draggable && this._draggable._moved;
+ },
+
+ _adjustPan: function (e) {
+ var marker = this._marker,
+ map = marker._map,
+ speed = this._marker.options.autoPanSpeed,
+ padding = this._marker.options.autoPanPadding,
+ iconPos = getPosition(marker._icon),
+ bounds = map.getPixelBounds(),
+ origin = map.getPixelOrigin();
+
+ var panBounds = toBounds(
+ bounds.min._subtract(origin).add(padding),
+ bounds.max._subtract(origin).subtract(padding)
+ );
+
+ if (!panBounds.contains(iconPos)) {
+ // Compute incremental movement
+ var movement = toPoint(
+ (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -
+ (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
+
+ (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -
+ (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
+ ).multiplyBy(speed);
+
+ map.panBy(movement, {animate: false});
+
+ this._draggable._newPos._add(movement);
+ this._draggable._startPos._add(movement);
+
+ setPosition(marker._icon, this._draggable._newPos);
+ this._onDrag(e);
+
+ this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
+ }
+ },
+
+ _onDragStart: function () {
+ // @section Dragging events
+ // @event dragstart: Event
+ // Fired when the user starts dragging the marker.
+
+ // @event movestart: Event
+ // Fired when the marker starts moving (because of dragging).
+
+ this._oldLatLng = this._marker.getLatLng();
+ this._marker
+ .closePopup()
+ .fire('movestart')
+ .fire('dragstart');
+ },
+
+ _onPreDrag: function (e) {
+ if (this._marker.options.autoPan) {
+ cancelAnimFrame(this._panRequest);
+ this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
+ }
+ },
+
+ _onDrag: function (e) {
+ var marker = this._marker,
+ shadow = marker._shadow,
+ iconPos = getPosition(marker._icon),
+ latlng = marker._map.layerPointToLatLng(iconPos);
+
+ // update shadow position
+ if (shadow) {
+ setPosition(shadow, iconPos);
+ }
+
+ marker._latlng = latlng;
+ e.latlng = latlng;
+ e.oldLatLng = this._oldLatLng;
+
+ // @event drag: Event
+ // Fired repeatedly while the user drags the marker.
+ marker
+ .fire('move', e)
+ .fire('drag', e);
+ },
+
+ _onDragEnd: function (e) {
+ // @event dragend: DragEndEvent
+ // Fired when the user stops dragging the marker.
+
+ cancelAnimFrame(this._panRequest);
+
+ // @event moveend: Event
+ // Fired when the marker stops moving (because of dragging).
+ delete this._oldLatLng;
+ this._marker
+ .fire('moveend')
+ .fire('dragend', e);
+ }
+});
+
+/*
+ * @class Marker
+ * @inherits Interactive layer
+ * @aka L.Marker
+ * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
+ *
+ * @example
+ *
+ * ```js
+ * L.marker([50.5, 30.5]).addTo(map);
+ * ```
+ */
+
+var Marker = Layer.extend({
+
+ // @section
+ // @aka Marker options
+ options: {
+ // @option icon: Icon = *
+ // Icon instance to use for rendering the marker.
+ // See [Icon documentation](#L.Icon) for details on how to customize the marker icon.
+ // If not specified, a common instance of `L.Icon.Default` is used.
+ icon: new IconDefault(),
+
+ // Option inherited from "Interactive layer" abstract class
+ interactive: true,
+
+ // @option keyboard: Boolean = true
+ // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
+ keyboard: true,
+
+ // @option title: String = ''
+ // Text for the browser tooltip that appear on marker hover (no tooltip by default).
+ title: '',
+
+ // @option alt: String = ''
+ // Text for the `alt` attribute of the icon image (useful for accessibility).
+ alt: '',
+
+ // @option zIndexOffset: Number = 0
+ // By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).
+ zIndexOffset: 0,
+
+ // @option opacity: Number = 1.0
+ // The opacity of the marker.
+ opacity: 1,
+
+ // @option riseOnHover: Boolean = false
+ // If `true`, the marker will get on top of others when you hover the mouse over it.
+ riseOnHover: false,
+
+ // @option riseOffset: Number = 250
+ // The z-index offset used for the `riseOnHover` feature.
+ riseOffset: 250,
+
+ // @option pane: String = 'markerPane'
+ // `Map pane` where the markers icon will be added.
+ pane: 'markerPane',
+
+ // @option bubblingMouseEvents: Boolean = false
+ // When `true`, a mouse event on this marker will trigger the same event on the map
+ // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
+ bubblingMouseEvents: false,
+
+ // @section Draggable marker options
+ // @option draggable: Boolean = false
+ // Whether the marker is draggable with mouse/touch or not.
+ draggable: false,
+
+ // @option autoPan: Boolean = false
+ // Whether to pan the map when dragging this marker near its edge or not.
+ autoPan: false,
+
+ // @option autoPanPadding: Point = Point(50, 50)
+ // Distance (in pixels to the left/right and to the top/bottom) of the
+ // map edge to start panning the map.
+ autoPanPadding: [50, 50],
+
+ // @option autoPanSpeed: Number = 10
+ // Number of pixels the map should pan by.
+ autoPanSpeed: 10
+ },
+
+ /* @section
+ *
+ * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
+ */
+
+ initialize: function (latlng, options) {
+ setOptions(this, options);
+ this._latlng = toLatLng(latlng);
+ },
+
+ onAdd: function (map) {
+ this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
+
+ if (this._zoomAnimated) {
+ map.on('zoomanim', this._animateZoom, this);
+ }
+
+ this._initIcon();
+ this.update();
+ },
+
+ onRemove: function (map) {
+ if (this.dragging && this.dragging.enabled()) {
+ this.options.draggable = true;
+ this.dragging.removeHooks();
+ }
+ delete this.dragging;
+
+ if (this._zoomAnimated) {
+ map.off('zoomanim', this._animateZoom, this);
+ }
+
+ this._removeIcon();
+ this._removeShadow();
+ },
+
+ getEvents: function () {
+ return {
+ zoom: this.update,
+ viewreset: this.update
+ };
+ },
+
+ // @method getLatLng: LatLng
+ // Returns the current geographical position of the marker.
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ // @method setLatLng(latlng: LatLng): this
+ // Changes the marker position to the given point.
+ setLatLng: function (latlng) {
+ var oldLatLng = this._latlng;
+ this._latlng = toLatLng(latlng);
+ this.update();
+
+ // @event move: Event
+ // Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
+ return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
+ },
+
+ // @method setZIndexOffset(offset: Number): this
+ // Changes the [zIndex offset](#marker-zindexoffset) of the marker.
+ setZIndexOffset: function (offset) {
+ this.options.zIndexOffset = offset;
+ return this.update();
+ },
+
+ // @method setIcon(icon: Icon): this
+ // Changes the marker icon.
+ setIcon: function (icon) {
+
+ this.options.icon = icon;
+
+ if (this._map) {
+ this._initIcon();
+ this.update();
+ }
+
+ if (this._popup) {
+ this.bindPopup(this._popup, this._popup.options);
+ }
+
+ return this;
+ },
+
+ getElement: function () {
+ return this._icon;
+ },
+
+ update: function () {
+
+ if (this._icon && this._map) {
+ var pos = this._map.latLngToLayerPoint(this._latlng).round();
+ this._setPos(pos);
+ }
+
+ return this;
+ },
+
+ _initIcon: function () {
+ var options = this.options,
+ classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
+
+ var icon = options.icon.createIcon(this._icon),
+ addIcon = false;
+
+ // if we're not reusing the icon, remove the old one and init new one
+ if (icon !== this._icon) {
+ if (this._icon) {
+ this._removeIcon();
+ }
+ addIcon = true;
+
+ if (options.title) {
+ icon.title = options.title;
+ }
+
+ if (icon.tagName === 'IMG') {
+ icon.alt = options.alt || '';
+ }
+ }
+
+ addClass(icon, classToAdd);
+
+ if (options.keyboard) {
+ icon.tabIndex = '0';
+ }
+
+ this._icon = icon;
+
+ if (options.riseOnHover) {
+ this.on({
+ mouseover: this._bringToFront,
+ mouseout: this._resetZIndex
+ });
+ }
+
+ var newShadow = options.icon.createShadow(this._shadow),
+ addShadow = false;
+
+ if (newShadow !== this._shadow) {
+ this._removeShadow();
+ addShadow = true;
+ }
+
+ if (newShadow) {
+ addClass(newShadow, classToAdd);
+ newShadow.alt = '';
+ }
+ this._shadow = newShadow;
+
+
+ if (options.opacity < 1) {
+ this._updateOpacity();
+ }
+
+
+ if (addIcon) {
+ this.getPane().appendChild(this._icon);
+ }
+ this._initInteraction();
+ if (newShadow && addShadow) {
+ this.getPane('shadowPane').appendChild(this._shadow);
+ }
+ },
+
+ _removeIcon: function () {
+ if (this.options.riseOnHover) {
+ this.off({
+ mouseover: this._bringToFront,
+ mouseout: this._resetZIndex
+ });
+ }
+
+ remove(this._icon);
+ this.removeInteractiveTarget(this._icon);
+
+ this._icon = null;
+ },
+
+ _removeShadow: function () {
+ if (this._shadow) {
+ remove(this._shadow);
+ }
+ this._shadow = null;
+ },
+
+ _setPos: function (pos) {
+ setPosition(this._icon, pos);
+
+ if (this._shadow) {
+ setPosition(this._shadow, pos);
+ }
+
+ this._zIndex = pos.y + this.options.zIndexOffset;
+
+ this._resetZIndex();
+ },
+
+ _updateZIndex: function (offset) {
+ this._icon.style.zIndex = this._zIndex + offset;
+ },
+
+ _animateZoom: function (opt) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
+
+ this._setPos(pos);
+ },
+
+ _initInteraction: function () {
+
+ if (!this.options.interactive) { return; }
+
+ addClass(this._icon, 'leaflet-interactive');
+
+ this.addInteractiveTarget(this._icon);
+
+ if (MarkerDrag) {
+ var draggable = this.options.draggable;
+ if (this.dragging) {
+ draggable = this.dragging.enabled();
+ this.dragging.disable();
+ }
+
+ this.dragging = new MarkerDrag(this);
+
+ if (draggable) {
+ this.dragging.enable();
+ }
+ }
+ },
+
+ // @method setOpacity(opacity: Number): this
+ // Changes the opacity of the marker.
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+ if (this._map) {
+ this._updateOpacity();
+ }
+
+ return this;
+ },
+
+ _updateOpacity: function () {
+ var opacity = this.options.opacity;
+
+ setOpacity(this._icon, opacity);
+
+ if (this._shadow) {
+ setOpacity(this._shadow, opacity);
+ }
+ },
+
+ _bringToFront: function () {
+ this._updateZIndex(this.options.riseOffset);
+ },
+
+ _resetZIndex: function () {
+ this._updateZIndex(0);
+ },
+
+ _getPopupAnchor: function () {
+ return this.options.icon.options.popupAnchor;
+ },
+
+ _getTooltipAnchor: function () {
+ return this.options.icon.options.tooltipAnchor;
+ }
+});
+
+
+// factory L.marker(latlng: LatLng, options? : Marker options)
+
+// @factory L.marker(latlng: LatLng, options? : Marker options)
+// Instantiates a Marker object given a geographical point and optionally an options object.
+function marker(latlng, options) {
+ return new Marker(latlng, options);
+}
+
+/*
+ * @class Path
+ * @aka L.Path
+ * @inherits Interactive layer
+ *
+ * An abstract class that contains options and constants shared between vector
+ * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
+ */
+
+var Path = Layer.extend({
+
+ // @section
+ // @aka Path options
+ options: {
+ // @option stroke: Boolean = true
+ // Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
+ stroke: true,
+
+ // @option color: String = '#3388ff'
+ // Stroke color
+ color: '#3388ff',
+
+ // @option weight: Number = 3
+ // Stroke width in pixels
+ weight: 3,
+
+ // @option opacity: Number = 1.0
+ // Stroke opacity
+ opacity: 1,
+
+ // @option lineCap: String= 'round'
+ // A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
+ lineCap: 'round',
+
+ // @option lineJoin: String = 'round'
+ // A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
+ lineJoin: 'round',
+
+ // @option dashArray: String = null
+ // A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
+ dashArray: null,
+
+ // @option dashOffset: String = null
+ // A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
+ dashOffset: null,
+
+ // @option fill: Boolean = depends
+ // Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
+ fill: false,
+
+ // @option fillColor: String = *
+ // Fill color. Defaults to the value of the [`color`](#path-color) option
+ fillColor: null,
+
+ // @option fillOpacity: Number = 0.2
+ // Fill opacity.
+ fillOpacity: 0.2,
+
+ // @option fillRule: String = 'evenodd'
+ // A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
+ fillRule: 'evenodd',
+
+ // className: '',
+
+ // Option inherited from "Interactive layer" abstract class
+ interactive: true,
+
+ // @option bubblingMouseEvents: Boolean = true
+ // When `true`, a mouse event on this path will trigger the same event on the map
+ // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
+ bubblingMouseEvents: true
+ },
+
+ beforeAdd: function (map) {
+ // Renderer is set here because we need to call renderer.getEvents
+ // before this.getEvents.
+ this._renderer = map.getRenderer(this);
+ },
+
+ onAdd: function () {
+ this._renderer._initPath(this);
+ this._reset();
+ this._renderer._addPath(this);
+ },
+
+ onRemove: function () {
+ this._renderer._removePath(this);
+ },
+
+ // @method redraw(): this
+ // Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
+ redraw: function () {
+ if (this._map) {
+ this._renderer._updatePath(this);
+ }
+ return this;
+ },
+
+ // @method setStyle(style: Path options): this
+ // Changes the appearance of a Path based on the options in the `Path options` object.
+ setStyle: function (style) {
+ setOptions(this, style);
+ if (this._renderer) {
+ this._renderer._updateStyle(this);
+ }
+ return this;
+ },
+
+ // @method bringToFront(): this
+ // Brings the layer to the top of all path layers.
+ bringToFront: function () {
+ if (this._renderer) {
+ this._renderer._bringToFront(this);
+ }
+ return this;
+ },
+
+ // @method bringToBack(): this
+ // Brings the layer to the bottom of all path layers.
+ bringToBack: function () {
+ if (this._renderer) {
+ this._renderer._bringToBack(this);
+ }
+ return this;
+ },
+
+ getElement: function () {
+ return this._path;
+ },
+
+ _reset: function () {
+ // defined in child classes
+ this._project();
+ this._update();
+ },
+
+ _clickTolerance: function () {
+ // used when doing hit detection for Canvas layers
+ return (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance;
+ }
+});
+
+/*
+ * @class CircleMarker
+ * @aka L.CircleMarker
+ * @inherits Path
+ *
+ * A circle of a fixed size with radius specified in pixels. Extends `Path`.
+ */
+
+var CircleMarker = Path.extend({
+
+ // @section
+ // @aka CircleMarker options
+ options: {
+ fill: true,
+
+ // @option radius: Number = 10
+ // Radius of the circle marker, in pixels
+ radius: 10
+ },
+
+ initialize: function (latlng, options) {
+ setOptions(this, options);
+ this._latlng = toLatLng(latlng);
+ this._radius = this.options.radius;
+ },
+
+ // @method setLatLng(latLng: LatLng): this
+ // Sets the position of a circle marker to a new location.
+ setLatLng: function (latlng) {
+ this._latlng = toLatLng(latlng);
+ this.redraw();
+ return this.fire('move', {latlng: this._latlng});
+ },
+
+ // @method getLatLng(): LatLng
+ // Returns the current geographical position of the circle marker
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ // @method setRadius(radius: Number): this
+ // Sets the radius of a circle marker. Units are in pixels.
+ setRadius: function (radius) {
+ this.options.radius = this._radius = radius;
+ return this.redraw();
+ },
+
+ // @method getRadius(): Number
+ // Returns the current radius of the circle
+ getRadius: function () {
+ return this._radius;
+ },
+
+ setStyle : function (options) {
+ var radius = options && options.radius || this._radius;
+ Path.prototype.setStyle.call(this, options);
+ this.setRadius(radius);
+ return this;
+ },
+
+ _project: function () {
+ this._point = this._map.latLngToLayerPoint(this._latlng);
+ this._updateBounds();
+ },
+
+ _updateBounds: function () {
+ var r = this._radius,
+ r2 = this._radiusY || r,
+ w = this._clickTolerance(),
+ p = [r + w, r2 + w];
+ this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
+ },
+
+ _update: function () {
+ if (this._map) {
+ this._updatePath();
+ }
+ },
+
+ _updatePath: function () {
+ this._renderer._updateCircle(this);
+ },
+
+ _empty: function () {
+ return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
+ },
+
+ // Needed by the `Canvas` renderer for interactivity
+ _containsPoint: function (p) {
+ return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
+ }
+});
+
+
+// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
+// Instantiates a circle marker object given a geographical point, and an optional options object.
+function circleMarker(latlng, options) {
+ return new CircleMarker(latlng, options);
+}
+
+/*
+ * @class Circle
+ * @aka L.Circle
+ * @inherits CircleMarker
+ *
+ * A class for drawing circle overlays on a map. Extends `CircleMarker`.
+ *
+ * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
+ *
+ * @example
+ *
+ * ```js
+ * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
+ * ```
+ */
+
+var Circle = CircleMarker.extend({
+
+ initialize: function (latlng, options, legacyOptions) {
+ if (typeof options === 'number') {
+ // Backwards compatibility with 0.7.x factory (latlng, radius, options?)
+ options = extend({}, legacyOptions, {radius: options});
+ }
+ setOptions(this, options);
+ this._latlng = toLatLng(latlng);
+
+ if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
+
+ // @section
+ // @aka Circle options
+ // @option radius: Number; Radius of the circle, in meters.
+ this._mRadius = this.options.radius;
+ },
+
+ // @method setRadius(radius: Number): this
+ // Sets the radius of a circle. Units are in meters.
+ setRadius: function (radius) {
+ this._mRadius = radius;
+ return this.redraw();
+ },
+
+ // @method getRadius(): Number
+ // Returns the current radius of a circle. Units are in meters.
+ getRadius: function () {
+ return this._mRadius;
+ },
+
+ // @method getBounds(): LatLngBounds
+ // Returns the `LatLngBounds` of the path.
+ getBounds: function () {
+ var half = [this._radius, this._radiusY || this._radius];
+
+ return new LatLngBounds(
+ this._map.layerPointToLatLng(this._point.subtract(half)),
+ this._map.layerPointToLatLng(this._point.add(half)));
+ },
+
+ setStyle: Path.prototype.setStyle,
+
+ _project: function () {
+
+ var lng = this._latlng.lng,
+ lat = this._latlng.lat,
+ map = this._map,
+ crs = map.options.crs;
+
+ if (crs.distance === Earth.distance) {
+ var d = Math.PI / 180,
+ latR = (this._mRadius / Earth.R) / d,
+ top = map.project([lat + latR, lng]),
+ bottom = map.project([lat - latR, lng]),
+ p = top.add(bottom).divideBy(2),
+ lat2 = map.unproject(p).lat,
+ lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
+ (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
+
+ if (isNaN(lngR) || lngR === 0) {
+ lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
+ }
+
+ this._point = p.subtract(map.getPixelOrigin());
+ this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
+ this._radiusY = p.y - top.y;
+
+ } else {
+ var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
+
+ this._point = map.latLngToLayerPoint(this._latlng);
+ this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
+ }
+
+ this._updateBounds();
+ }
+});
+
+// @factory L.circle(latlng: LatLng, options?: Circle options)
+// Instantiates a circle object given a geographical point, and an options object
+// which contains the circle radius.
+// @alternative
+// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
+// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
+// Do not use in new applications or plugins.
+function circle(latlng, options, legacyOptions) {
+ return new Circle(latlng, options, legacyOptions);
+}
+
+/*
+ * @class Polyline
+ * @aka L.Polyline
+ * @inherits Path
+ *
+ * A class for drawing polyline overlays on a map. Extends `Path`.
+ *
+ * @example
+ *
+ * ```js
+ * // create a red polyline from an array of LatLng points
+ * var latlngs = [
+ * [45.51, -122.68],
+ * [37.77, -122.43],
+ * [34.04, -118.2]
+ * ];
+ *
+ * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
+ *
+ * // zoom the map to the polyline
+ * map.fitBounds(polyline.getBounds());
+ * ```
+ *
+ * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
+ *
+ * ```js
+ * // create a red polyline from an array of arrays of LatLng points
+ * var latlngs = [
+ * [[45.51, -122.68],
+ * [37.77, -122.43],
+ * [34.04, -118.2]],
+ * [[40.78, -73.91],
+ * [41.83, -87.62],
+ * [32.76, -96.72]]
+ * ];
+ * ```
+ */
+
+
+var Polyline = Path.extend({
+
+ // @section
+ // @aka Polyline options
+ options: {
+ // @option smoothFactor: Number = 1.0
+ // How much to simplify the polyline on each zoom level. More means
+ // better performance and smoother look, and less means more accurate representation.
+ smoothFactor: 1.0,
+
+ // @option noClip: Boolean = false
+ // Disable polyline clipping.
+ noClip: false
+ },
+
+ initialize: function (latlngs, options) {
+ setOptions(this, options);
+ this._setLatLngs(latlngs);
+ },
+
+ // @method getLatLngs(): LatLng[]
+ // Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
+ getLatLngs: function () {
+ return this._latlngs;
+ },
+
+ // @method setLatLngs(latlngs: LatLng[]): this
+ // Replaces all the points in the polyline with the given array of geographical points.
+ setLatLngs: function (latlngs) {
+ this._setLatLngs(latlngs);
+ return this.redraw();
+ },
+
+ // @method isEmpty(): Boolean
+ // Returns `true` if the Polyline has no LatLngs.
+ isEmpty: function () {
+ return !this._latlngs.length;
+ },
+
+ // @method closestLayerPoint(p: Point): Point
+ // Returns the point closest to `p` on the Polyline.
+ closestLayerPoint: function (p) {
+ var minDistance = Infinity,
+ minPoint = null,
+ closest = _sqClosestPointOnSegment,
+ p1, p2;
+
+ for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
+ var points = this._parts[j];
+
+ for (var i = 1, len = points.length; i < len; i++) {
+ p1 = points[i - 1];
+ p2 = points[i];
+
+ var sqDist = closest(p, p1, p2, true);
+
+ if (sqDist < minDistance) {
+ minDistance = sqDist;
+ minPoint = closest(p, p1, p2);
+ }
+ }
+ }
+ if (minPoint) {
+ minPoint.distance = Math.sqrt(minDistance);
+ }
+ return minPoint;
+ },
+
+ // @method getCenter(): LatLng
+ // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
+ getCenter: function () {
+ // throws error when not yet added to map as this center calculation requires projected coordinates
+ if (!this._map) {
+ throw new Error('Must add layer to map before using getCenter()');
+ }
+
+ var i, halfDist, segDist, dist, p1, p2, ratio,
+ points = this._rings[0],
+ len = points.length;
+
+ if (!len) { return null; }
+
+ // polyline centroid algorithm; only uses the first ring if there are multiple
+
+ for (i = 0, halfDist = 0; i < len - 1; i++) {
+ halfDist += points[i].distanceTo(points[i + 1]) / 2;
+ }
+
+ // The line is so small in the current view that all points are on the same pixel.
+ if (halfDist === 0) {
+ return this._map.layerPointToLatLng(points[0]);
+ }
+
+ for (i = 0, dist = 0; i < len - 1; i++) {
+ p1 = points[i];
+ p2 = points[i + 1];
+ segDist = p1.distanceTo(p2);
+ dist += segDist;
+
+ if (dist > halfDist) {
+ ratio = (dist - halfDist) / segDist;
+ return this._map.layerPointToLatLng([
+ p2.x - ratio * (p2.x - p1.x),
+ p2.y - ratio * (p2.y - p1.y)
+ ]);
+ }
+ }
+ },
+
+ // @method getBounds(): LatLngBounds
+ // Returns the `LatLngBounds` of the path.
+ getBounds: function () {
+ return this._bounds;
+ },
+
+ // @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
+ // Adds a given point to the polyline. By default, adds to the first ring of
+ // the polyline in case of a multi-polyline, but can be overridden by passing
+ // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
+ addLatLng: function (latlng, latlngs) {
+ latlngs = latlngs || this._defaultShape();
+ latlng = toLatLng(latlng);
+ latlngs.push(latlng);
+ this._bounds.extend(latlng);
+ return this.redraw();
+ },
+
+ _setLatLngs: function (latlngs) {
+ this._bounds = new LatLngBounds();
+ this._latlngs = this._convertLatLngs(latlngs);
+ },
+
+ _defaultShape: function () {
+ return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
+ },
+
+ // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
+ _convertLatLngs: function (latlngs) {
+ var result = [],
+ flat = isFlat(latlngs);
+
+ for (var i = 0, len = latlngs.length; i < len; i++) {
+ if (flat) {
+ result[i] = toLatLng(latlngs[i]);
+ this._bounds.extend(result[i]);
+ } else {
+ result[i] = this._convertLatLngs(latlngs[i]);
+ }
+ }
+
+ return result;
+ },
+
+ _project: function () {
+ var pxBounds = new Bounds();
+ this._rings = [];
+ this._projectLatlngs(this._latlngs, this._rings, pxBounds);
+
+ var w = this._clickTolerance(),
+ p = new Point(w, w);
+
+ if (this._bounds.isValid() && pxBounds.isValid()) {
+ pxBounds.min._subtract(p);
+ pxBounds.max._add(p);
+ this._pxBounds = pxBounds;
+ }
+ },
+
+ // recursively turns latlngs into a set of rings with projected coordinates
+ _projectLatlngs: function (latlngs, result, projectedBounds) {
+ var flat = latlngs[0] instanceof LatLng,
+ len = latlngs.length,
+ i, ring;
+
+ if (flat) {
+ ring = [];
+ for (i = 0; i < len; i++) {
+ ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
+ projectedBounds.extend(ring[i]);
+ }
+ result.push(ring);
+ } else {
+ for (i = 0; i < len; i++) {
+ this._projectLatlngs(latlngs[i], result, projectedBounds);
+ }
+ }
+ },
+
+ // clip polyline by renderer bounds so that we have less to render for performance
+ _clipPoints: function () {
+ var bounds = this._renderer._bounds;
+
+ this._parts = [];
+ if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
+ return;
+ }
+
+ if (this.options.noClip) {
+ this._parts = this._rings;
+ return;
+ }
+
+ var parts = this._parts,
+ i, j, k, len, len2, segment, points;
+
+ for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
+ points = this._rings[i];
+
+ for (j = 0, len2 = points.length; j < len2 - 1; j++) {
+ segment = clipSegment(points[j], points[j + 1], bounds, j, true);
+
+ if (!segment) { continue; }
+
+ parts[k] = parts[k] || [];
+ parts[k].push(segment[0]);
+
+ // if segment goes out of screen, or it's the last one, it's the end of the line part
+ if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
+ parts[k].push(segment[1]);
+ k++;
+ }
+ }
+ }
+ },
+
+ // simplify each clipped part of the polyline for performance
+ _simplifyPoints: function () {
+ var parts = this._parts,
+ tolerance = this.options.smoothFactor;
+
+ for (var i = 0, len = parts.length; i < len; i++) {
+ parts[i] = simplify(parts[i], tolerance);
+ }
+ },
+
+ _update: function () {
+ if (!this._map) { return; }
+
+ this._clipPoints();
+ this._simplifyPoints();
+ this._updatePath();
+ },
+
+ _updatePath: function () {
+ this._renderer._updatePoly(this);
+ },
+
+ // Needed by the `Canvas` renderer for interactivity
+ _containsPoint: function (p, closed) {
+ var i, j, k, len, len2, part,
+ w = this._clickTolerance();
+
+ if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
+
+ // hit detection for polylines
+ for (i = 0, len = this._parts.length; i < len; i++) {
+ part = this._parts[i];
+
+ for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
+ if (!closed && (j === 0)) { continue; }
+
+ if (pointToSegmentDistance(p, part[k], part[j]) <= w) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+});
+
+// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
+// Instantiates a polyline object given an array of geographical points and
+// optionally an options object. You can create a `Polyline` object with
+// multiple separate lines (`MultiPolyline`) by passing an array of arrays
+// of geographic points.
+function polyline(latlngs, options) {
+ return new Polyline(latlngs, options);
+}
+
+// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
+Polyline._flat = _flat;
+
+/*
+ * @class Polygon
+ * @aka L.Polygon
+ * @inherits Polyline
+ *
+ * A class for drawing polygon overlays on a map. Extends `Polyline`.
+ *
+ * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.
+ *
+ *
+ * @example
+ *
+ * ```js
+ * // create a red polygon from an array of LatLng points
+ * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
+ *
+ * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
+ *
+ * // zoom the map to the polygon
+ * map.fitBounds(polygon.getBounds());
+ * ```
+ *
+ * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:
+ *
+ * ```js
+ * var latlngs = [
+ * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
+ * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
+ * ];
+ * ```
+ *
+ * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
+ *
+ * ```js
+ * var latlngs = [
+ * [ // first polygon
+ * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
+ * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
+ * ],
+ * [ // second polygon
+ * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]
+ * ]
+ * ];
+ * ```
+ */
+
+var Polygon = Polyline.extend({
+
+ options: {
+ fill: true
+ },
+
+ isEmpty: function () {
+ return !this._latlngs.length || !this._latlngs[0].length;
+ },
+
+ getCenter: function () {
+ // throws error when not yet added to map as this center calculation requires projected coordinates
+ if (!this._map) {
+ throw new Error('Must add layer to map before using getCenter()');
+ }
+
+ var i, j, p1, p2, f, area, x, y, center,
+ points = this._rings[0],
+ len = points.length;
+
+ if (!len) { return null; }
+
+ // polygon centroid algorithm; only uses the first ring if there are multiple
+
+ area = x = y = 0;
+
+ for (i = 0, j = len - 1; i < len; j = i++) {
+ p1 = points[i];
+ p2 = points[j];
+
+ f = p1.y * p2.x - p2.y * p1.x;
+ x += (p1.x + p2.x) * f;
+ y += (p1.y + p2.y) * f;
+ area += f * 3;
+ }
+
+ if (area === 0) {
+ // Polygon is so small that all points are on same pixel.
+ center = points[0];
+ } else {
+ center = [x / area, y / area];
+ }
+ return this._map.layerPointToLatLng(center);
+ },
+
+ _convertLatLngs: function (latlngs) {
+ var result = Polyline.prototype._convertLatLngs.call(this, latlngs),
+ len = result.length;
+
+ // remove last point if it equals first one
+ if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {
+ result.pop();
+ }
+ return result;
+ },
+
+ _setLatLngs: function (latlngs) {
+ Polyline.prototype._setLatLngs.call(this, latlngs);
+ if (isFlat(this._latlngs)) {
+ this._latlngs = [this._latlngs];
+ }
+ },
+
+ _defaultShape: function () {
+ return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
+ },
+
+ _clipPoints: function () {
+ // polygons need a different clipping algorithm so we redefine that
+
+ var bounds = this._renderer._bounds,
+ w = this.options.weight,
+ p = new Point(w, w);
+
+ // increase clip padding by stroke width to avoid stroke on clip edges
+ bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));
+
+ this._parts = [];
+ if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
+ return;
+ }
+
+ if (this.options.noClip) {
+ this._parts = this._rings;
+ return;
+ }
+
+ for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
+ clipped = clipPolygon(this._rings[i], bounds, true);
+ if (clipped.length) {
+ this._parts.push(clipped);
+ }
+ }
+ },
+
+ _updatePath: function () {
+ this._renderer._updatePoly(this, true);
+ },
+
+ // Needed by the `Canvas` renderer for interactivity
+ _containsPoint: function (p) {
+ var inside = false,
+ part, p1, p2, i, j, k, len, len2;
+
+ if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
+
+ // ray casting algorithm for detecting if point is in polygon
+ for (i = 0, len = this._parts.length; i < len; i++) {
+ part = this._parts[i];
+
+ for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
+ p1 = part[j];
+ p2 = part[k];
+
+ if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
+ inside = !inside;
+ }
+ }
+ }
+
+ // also check if it's on polygon stroke
+ return inside || Polyline.prototype._containsPoint.call(this, p, true);
+ }
+
+});
+
+
+// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
+function polygon(latlngs, options) {
+ return new Polygon(latlngs, options);
+}
+
+/*
+ * @class GeoJSON
+ * @aka L.GeoJSON
+ * @inherits FeatureGroup
+ *
+ * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
+ * GeoJSON data and display it on the map. Extends `FeatureGroup`.
+ *
+ * @example
+ *
+ * ```js
+ * L.geoJSON(data, {
+ * style: function (feature) {
+ * return {color: feature.properties.color};
+ * }
+ * }).bindPopup(function (layer) {
+ * return layer.feature.properties.description;
+ * }).addTo(map);
+ * ```
+ */
+
+var GeoJSON = FeatureGroup.extend({
+
+ /* @section
+ * @aka GeoJSON options
+ *
+ * @option pointToLayer: Function = *
+ * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
+ * called when data is added, passing the GeoJSON point feature and its `LatLng`.
+ * The default is to spawn a default `Marker`:
+ * ```js
+ * function(geoJsonPoint, latlng) {
+ * return L.marker(latlng);
+ * }
+ * ```
+ *
+ * @option style: Function = *
+ * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
+ * called internally when data is added.
+ * The default value is to not override any defaults:
+ * ```js
+ * function (geoJsonFeature) {
+ * return {}
+ * }
+ * ```
+ *
+ * @option onEachFeature: Function = *
+ * A `Function` that will be called once for each created `Feature`, after it has
+ * been created and styled. Useful for attaching events and popups to features.
+ * The default is to do nothing with the newly created layers:
+ * ```js
+ * function (feature, layer) {}
+ * ```
+ *
+ * @option filter: Function = *
+ * A `Function` that will be used to decide whether to include a feature or not.
+ * The default is to include all features:
+ * ```js
+ * function (geoJsonFeature) {
+ * return true;
+ * }
+ * ```
+ * Note: dynamically changing the `filter` option will have effect only on newly
+ * added data. It will _not_ re-evaluate already included features.
+ *
+ * @option coordsToLatLng: Function = *
+ * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
+ * The default is the `coordsToLatLng` static method.
+ */
+
+ initialize: function (geojson, options) {
+ setOptions(this, options);
+
+ this._layers = {};
+
+ if (geojson) {
+ this.addData(geojson);
+ }
+ },
+
+ // @method addData( <GeoJSON> data ): this
+ // Adds a GeoJSON object to the layer.
+ addData: function (geojson) {
+ var features = isArray(geojson) ? geojson : geojson.features,
+ i, len, feature;
+
+ if (features) {
+ for (i = 0, len = features.length; i < len; i++) {
+ // only add this if geometry or geometries are set and not null
+ feature = features[i];
+ if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
+ this.addData(feature);
+ }
+ }
+ return this;
+ }
+
+ var options = this.options;
+
+ if (options.filter && !options.filter(geojson)) { return this; }
+
+ var layer = geometryToLayer(geojson, options);
+ if (!layer) {
+ return this;
+ }
+ layer.feature = asFeature(geojson);
+
+ layer.defaultOptions = layer.options;
+ this.resetStyle(layer);
+
+ if (options.onEachFeature) {
+ options.onEachFeature(geojson, layer);
+ }
+
+ return this.addLayer(layer);
+ },
+
+ // @method resetStyle( <Path> layer ): this
+ // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
+ resetStyle: function (layer) {
+ // reset any custom styles
+ layer.options = extend({}, layer.defaultOptions);
+ this._setLayerStyle(layer, this.options.style);
+ return this;
+ },
+
+ // @method setStyle( <Function> style ): this
+ // Changes styles of GeoJSON vector layers with the given style function.
+ setStyle: function (style) {
+ return this.eachLayer(function (layer) {
+ this._setLayerStyle(layer, style);
+ }, this);
+ },
+
+ _setLayerStyle: function (layer, style) {
+ if (typeof style === 'function') {
+ style = style(layer.feature);
+ }
+ if (layer.setStyle) {
+ layer.setStyle(style);
+ }
+ }
+});
+
+// @section
+// There are several static functions which can be called without instantiating L.GeoJSON:
+
+// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
+// Creates a `Layer` from a given GeoJSON feature. Can use a custom
+// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
+// functions if provided as options.
+function geometryToLayer(geojson, options) {
+
+ var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
+ coords = geometry ? geometry.coordinates : null,
+ layers = [],
+ pointToLayer = options && options.pointToLayer,
+ _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,
+ latlng, latlngs, i, len;
+
+ if (!coords && !geometry) {
+ return null;
+ }
+
+ switch (geometry.type) {
+ case 'Point':
+ latlng = _coordsToLatLng(coords);
+ return pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng);
+
+ case 'MultiPoint':
+ for (i = 0, len = coords.length; i < len; i++) {
+ latlng = _coordsToLatLng(coords[i]);
+ layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng));
+ }
+ return new FeatureGroup(layers);
+
+ case 'LineString':
+ case 'MultiLineString':
+ latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);
+ return new Polyline(latlngs, options);
+
+ case 'Polygon':
+ case 'MultiPolygon':
+ latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);
+ return new Polygon(latlngs, options);
+
+ case 'GeometryCollection':
+ for (i = 0, len = geometry.geometries.length; i < len; i++) {
+ var layer = geometryToLayer({
+ geometry: geometry.geometries[i],
+ type: 'Feature',
+ properties: geojson.properties
+ }, options);
+
+ if (layer) {
+ layers.push(layer);
+ }
+ }
+ return new FeatureGroup(layers);
+
+ default:
+ throw new Error('Invalid GeoJSON object.');
+ }
+}
+
+// @function coordsToLatLng(coords: Array): LatLng
+// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
+// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
+function coordsToLatLng(coords) {
+ return new LatLng(coords[1], coords[0], coords[2]);
+}
+
+// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
+// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
+// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
+// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
+function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
+ var latlngs = [];
+
+ for (var i = 0, len = coords.length, latlng; i < len; i++) {
+ latlng = levelsDeep ?
+ coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
+ (_coordsToLatLng || coordsToLatLng)(coords[i]);
+
+ latlngs.push(latlng);
+ }
+
+ return latlngs;
+}
+
+// @function latLngToCoords(latlng: LatLng, precision?: Number): Array
+// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
+function latLngToCoords(latlng, precision) {
+ precision = typeof precision === 'number' ? precision : 6;
+ return latlng.alt !== undefined ?
+ [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
+ [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
+}
+
+// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
+// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
+// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
+function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
+ var coords = [];
+
+ for (var i = 0, len = latlngs.length; i < len; i++) {
+ coords.push(levelsDeep ?
+ latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :
+ latLngToCoords(latlngs[i], precision));
+ }
+
+ if (!levelsDeep && closed) {
+ coords.push(coords[0]);
+ }
+
+ return coords;
+}
+
+function getFeature(layer, newGeometry) {
+ return layer.feature ?
+ extend({}, layer.feature, {geometry: newGeometry}) :
+ asFeature(newGeometry);
+}
+
+// @function asFeature(geojson: Object): Object
+// Normalize GeoJSON geometries/features into GeoJSON features.
+function asFeature(geojson) {
+ if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
+ return geojson;
+ }
+
+ return {
+ type: 'Feature',
+ properties: {},
+ geometry: geojson
+ };
+}
+
+var PointToGeoJSON = {
+ toGeoJSON: function (precision) {
+ return getFeature(this, {
+ type: 'Point',
+ coordinates: latLngToCoords(this.getLatLng(), precision)
+ });
+ }
+};
+
+// @namespace Marker
+// @method toGeoJSON(): Object
+// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
+Marker.include(PointToGeoJSON);
+
+// @namespace CircleMarker
+// @method toGeoJSON(): Object
+// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
+Circle.include(PointToGeoJSON);
+CircleMarker.include(PointToGeoJSON);
+
+
+// @namespace Polyline
+// @method toGeoJSON(): Object
+// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
+Polyline.include({
+ toGeoJSON: function (precision) {
+ var multi = !isFlat(this._latlngs);
+
+ var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
+
+ return getFeature(this, {
+ type: (multi ? 'Multi' : '') + 'LineString',
+ coordinates: coords
+ });
+ }
+});
+
+// @namespace Polygon
+// @method toGeoJSON(): Object
+// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
+Polygon.include({
+ toGeoJSON: function (precision) {
+ var holes = !isFlat(this._latlngs),
+ multi = holes && !isFlat(this._latlngs[0]);
+
+ var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
+
+ if (!holes) {
+ coords = [coords];
+ }
+
+ return getFeature(this, {
+ type: (multi ? 'Multi' : '') + 'Polygon',
+ coordinates: coords
+ });
+ }
+});
+
+
+// @namespace LayerGroup
+LayerGroup.include({
+ toMultiPoint: function (precision) {
+ var coords = [];
+
+ this.eachLayer(function (layer) {
+ coords.push(layer.toGeoJSON(precision).geometry.coordinates);
+ });
+
+ return getFeature(this, {
+ type: 'MultiPoint',
+ coordinates: coords
+ });
+ },
+
+ // @method toGeoJSON(): Object
+ // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
+ toGeoJSON: function (precision) {
+
+ var type = this.feature && this.feature.geometry && this.feature.geometry.type;
+
+ if (type === 'MultiPoint') {
+ return this.toMultiPoint(precision);
+ }
+
+ var isGeometryCollection = type === 'GeometryCollection',
+ jsons = [];
+
+ this.eachLayer(function (layer) {
+ if (layer.toGeoJSON) {
+ var json = layer.toGeoJSON(precision);
+ if (isGeometryCollection) {
+ jsons.push(json.geometry);
+ } else {
+ var feature = asFeature(json);
+ // Squash nested feature collections
+ if (feature.type === 'FeatureCollection') {
+ jsons.push.apply(jsons, feature.features);
+ } else {
+ jsons.push(feature);
+ }
+ }
+ }
+ });
+
+ if (isGeometryCollection) {
+ return getFeature(this, {
+ geometries: jsons,
+ type: 'GeometryCollection'
+ });
+ }
+
+ return {
+ type: 'FeatureCollection',
+ features: jsons
+ };
+ }
+});
+
+// @namespace GeoJSON
+// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
+// Creates a GeoJSON layer. Optionally accepts an object in
+// [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map
+// (you can alternatively add it later with `addData` method) and an `options` object.
+function geoJSON(geojson, options) {
+ return new GeoJSON(geojson, options);
+}
+
+// Backward compatibility.
+var geoJson = geoJSON;
+
+/*
+ * @class ImageOverlay
+ * @aka L.ImageOverlay
+ * @inherits Interactive layer
+ *
+ * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
+ *
+ * @example
+ *
+ * ```js
+ * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
+ * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
+ * L.imageOverlay(imageUrl, imageBounds).addTo(map);
+ * ```
+ */
+
+var ImageOverlay = Layer.extend({
+
+ // @section
+ // @aka ImageOverlay options
+ options: {
+ // @option opacity: Number = 1.0
+ // The opacity of the image overlay.
+ opacity: 1,
+
+ // @option alt: String = ''
+ // Text for the `alt` attribute of the image (useful for accessibility).
+ alt: '',
+
+ // @option interactive: Boolean = false
+ // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
+ interactive: false,
+
+ // @option crossOrigin: Boolean|String = false
+ // Whether the crossOrigin attribute will be added to the image.
+ // If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.
+ // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
+ crossOrigin: false,
+
+ // @option errorOverlayUrl: String = ''
+ // URL to the overlay image to show in place of the overlay that failed to load.
+ errorOverlayUrl: '',
+
+ // @option zIndex: Number = 1
+ // The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
+ zIndex: 1,
+
+ // @option className: String = ''
+ // A custom class name to assign to the image. Empty by default.
+ className: ''
+ },
+
+ initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
+ this._url = url;
+ this._bounds = toLatLngBounds(bounds);
+
+ setOptions(this, options);
+ },
+
+ onAdd: function () {
+ if (!this._image) {
+ this._initImage();
+
+ if (this.options.opacity < 1) {
+ this._updateOpacity();
+ }
+ }
+
+ if (this.options.interactive) {
+ addClass(this._image, 'leaflet-interactive');
+ this.addInteractiveTarget(this._image);
+ }
+
+ this.getPane().appendChild(this._image);
+ this._reset();
+ },
+
+ onRemove: function () {
+ remove(this._image);
+ if (this.options.interactive) {
+ this.removeInteractiveTarget(this._image);
+ }
+ },
+
+ // @method setOpacity(opacity: Number): this
+ // Sets the opacity of the overlay.
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+
+ if (this._image) {
+ this._updateOpacity();
+ }
+ return this;
+ },
+
+ setStyle: function (styleOpts) {
+ if (styleOpts.opacity) {
+ this.setOpacity(styleOpts.opacity);
+ }
+ return this;
+ },
+
+ // @method bringToFront(): this
+ // Brings the layer to the top of all overlays.
+ bringToFront: function () {
+ if (this._map) {
+ toFront(this._image);
+ }
+ return this;
+ },
+
+ // @method bringToBack(): this
+ // Brings the layer to the bottom of all overlays.
+ bringToBack: function () {
+ if (this._map) {
+ toBack(this._image);
+ }
+ return this;
+ },
+
+ // @method setUrl(url: String): this
+ // Changes the URL of the image.
+ setUrl: function (url) {
+ this._url = url;
+
+ if (this._image) {
+ this._image.src = url;
+ }
+ return this;
+ },
+
+ // @method setBounds(bounds: LatLngBounds): this
+ // Update the bounds that this ImageOverlay covers
+ setBounds: function (bounds) {
+ this._bounds = toLatLngBounds(bounds);
+
+ if (this._map) {
+ this._reset();
+ }
+ return this;
+ },
+
+ getEvents: function () {
+ var events = {
+ zoom: this._reset,
+ viewreset: this._reset
+ };
+
+ if (this._zoomAnimated) {
+ events.zoomanim = this._animateZoom;
+ }
+
+ return events;
+ },
+
+ // @method setZIndex(value: Number): this
+ // Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
+ setZIndex: function (value) {
+ this.options.zIndex = value;
+ this._updateZIndex();
+ return this;
+ },
+
+ // @method getBounds(): LatLngBounds
+ // Get the bounds that this ImageOverlay covers
+ getBounds: function () {
+ return this._bounds;
+ },
+
+ // @method getElement(): HTMLElement
+ // Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
+ // used by this overlay.
+ getElement: function () {
+ return this._image;
+ },
+
+ _initImage: function () {
+ var wasElementSupplied = this._url.tagName === 'IMG';
+ var img = this._image = wasElementSupplied ? this._url : create$1('img');
+
+ addClass(img, 'leaflet-image-layer');
+ if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }
+ if (this.options.className) { addClass(img, this.options.className); }
+
+ img.onselectstart = falseFn;
+ img.onmousemove = falseFn;
+
+ // @event load: Event
+ // Fired when the ImageOverlay layer has loaded its image
+ img.onload = bind(this.fire, this, 'load');
+ img.onerror = bind(this._overlayOnError, this, 'error');
+
+ if (this.options.crossOrigin || this.options.crossOrigin === '') {
+ img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
+ }
+
+ if (this.options.zIndex) {
+ this._updateZIndex();
+ }
+
+ if (wasElementSupplied) {
+ this._url = img.src;
+ return;
+ }
+
+ img.src = this._url;
+ img.alt = this.options.alt;
+ },
+
+ _animateZoom: function (e) {
+ var scale = this._map.getZoomScale(e.zoom),
+ offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
+
+ setTransform(this._image, offset, scale);
+ },
+
+ _reset: function () {
+ var image = this._image,
+ bounds = new Bounds(
+ this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
+ this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
+ size = bounds.getSize();
+
+ setPosition(image, bounds.min);
+
+ image.style.width = size.x + 'px';
+ image.style.height = size.y + 'px';
+ },
+
+ _updateOpacity: function () {
+ setOpacity(this._image, this.options.opacity);
+ },
+
+ _updateZIndex: function () {
+ if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {
+ this._image.style.zIndex = this.options.zIndex;
+ }
+ },
+
+ _overlayOnError: function () {
+ // @event error: Event
+ // Fired when the ImageOverlay layer fails to load its image
+ this.fire('error');
+
+ var errorUrl = this.options.errorOverlayUrl;
+ if (errorUrl && this._url !== errorUrl) {
+ this._url = errorUrl;
+ this._image.src = errorUrl;
+ }
+ }
+});
+
+// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
+// Instantiates an image overlay object given the URL of the image and the
+// geographical bounds it is tied to.
+var imageOverlay = function (url, bounds, options) {
+ return new ImageOverlay(url, bounds, options);
+};
+
+/*
+ * @class VideoOverlay
+ * @aka L.VideoOverlay
+ * @inherits ImageOverlay
+ *
+ * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.
+ *
+ * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)
+ * HTML5 element.
+ *
+ * @example
+ *
+ * ```js
+ * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
+ * videoBounds = [[ 32, -130], [ 13, -100]];
+ * L.videoOverlay(videoUrl, videoBounds ).addTo(map);
+ * ```
+ */
+
+var VideoOverlay = ImageOverlay.extend({
+
+ // @section
+ // @aka VideoOverlay options
+ options: {
+ // @option autoplay: Boolean = true
+ // Whether the video starts playing automatically when loaded.
+ autoplay: true,
+
+ // @option loop: Boolean = true
+ // Whether the video will loop back to the beginning when played.
+ loop: true
+ },
+
+ _initImage: function () {
+ var wasElementSupplied = this._url.tagName === 'VIDEO';
+ var vid = this._image = wasElementSupplied ? this._url : create$1('video');
+
+ addClass(vid, 'leaflet-image-layer');
+ if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }
+
+ vid.onselectstart = falseFn;
+ vid.onmousemove = falseFn;
+
+ // @event load: Event
+ // Fired when the video has finished loading the first frame
+ vid.onloadeddata = bind(this.fire, this, 'load');
+
+ if (wasElementSupplied) {
+ var sourceElements = vid.getElementsByTagName('source');
+ var sources = [];
+ for (var j = 0; j < sourceElements.length; j++) {
+ sources.push(sourceElements[j].src);
+ }
+
+ this._url = (sourceElements.length > 0) ? sources : [vid.src];
+ return;
+ }
+
+ if (!isArray(this._url)) { this._url = [this._url]; }
+
+ vid.autoplay = !!this.options.autoplay;
+ vid.loop = !!this.options.loop;
+ for (var i = 0; i < this._url.length; i++) {
+ var source = create$1('source');
+ source.src = this._url[i];
+ vid.appendChild(source);
+ }
+ }
+
+ // @method getElement(): HTMLVideoElement
+ // Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
+ // used by this overlay.
+});
+
+
+// @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)
+// Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the
+// geographical bounds it is tied to.
+
+function videoOverlay(video, bounds, options) {
+ return new VideoOverlay(video, bounds, options);
+}
+
+/*
+ * @class DivOverlay
+ * @inherits Layer
+ * @aka L.DivOverlay
+ * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
+ */
+
+// @namespace DivOverlay
+var DivOverlay = Layer.extend({
+
+ // @section
+ // @aka DivOverlay options
+ options: {
+ // @option offset: Point = Point(0, 7)
+ // The offset of the popup position. Useful to control the anchor
+ // of the popup when opening it on some overlays.
+ offset: [0, 7],
+
+ // @option className: String = ''
+ // A custom CSS class name to assign to the popup.
+ className: '',
+
+ // @option pane: String = 'popupPane'
+ // `Map pane` where the popup will be added.
+ pane: 'popupPane'
+ },
+
+ initialize: function (options, source) {
+ setOptions(this, options);
+
+ this._source = source;
+ },
+
+ onAdd: function (map) {
+ this._zoomAnimated = map._zoomAnimated;
+
+ if (!this._container) {
+ this._initLayout();
+ }
+
+ if (map._fadeAnimated) {
+ setOpacity(this._container, 0);
+ }
+
+ clearTimeout(this._removeTimeout);
+ this.getPane().appendChild(this._container);
+ this.update();
+
+ if (map._fadeAnimated) {
+ setOpacity(this._container, 1);
+ }
+
+ this.bringToFront();
+ },
+
+ onRemove: function (map) {
+ if (map._fadeAnimated) {
+ setOpacity(this._container, 0);
+ this._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200);
+ } else {
+ remove(this._container);
+ }
+ },
+
+ // @namespace Popup
+ // @method getLatLng: LatLng
+ // Returns the geographical point of popup.
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ // @method setLatLng(latlng: LatLng): this
+ // Sets the geographical point where the popup will open.
+ setLatLng: function (latlng) {
+ this._latlng = toLatLng(latlng);
+ if (this._map) {
+ this._updatePosition();
+ this._adjustPan();
+ }
+ return this;
+ },
+
+ // @method getContent: String|HTMLElement
+ // Returns the content of the popup.
+ getContent: function () {
+ return this._content;
+ },
+
+ // @method setContent(htmlContent: String|HTMLElement|Function): this
+ // Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
+ setContent: function (content) {
+ this._content = content;
+ this.update();
+ return this;
+ },
+
+ // @method getElement: String|HTMLElement
+ // Alias for [getContent()](#popup-getcontent)
+ getElement: function () {
+ return this._container;
+ },
+
+ // @method update: null
+ // Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
+ update: function () {
+ if (!this._map) { return; }
+
+ this._container.style.visibility = 'hidden';
+
+ this._updateContent();
+ this._updateLayout();
+ this._updatePosition();
+
+ this._container.style.visibility = '';
+
+ this._adjustPan();
+ },
+
+ getEvents: function () {
+ var events = {
+ zoom: this._updatePosition,
+ viewreset: this._updatePosition
+ };
+
+ if (this._zoomAnimated) {
+ events.zoomanim = this._animateZoom;
+ }
+ return events;
+ },
+
+ // @method isOpen: Boolean
+ // Returns `true` when the popup is visible on the map.
+ isOpen: function () {
+ return !!this._map && this._map.hasLayer(this);
+ },
+
+ // @method bringToFront: this
+ // Brings this popup in front of other popups (in the same map pane).
+ bringToFront: function () {
+ if (this._map) {
+ toFront(this._container);
+ }
+ return this;
+ },
+
+ // @method bringToBack: this
+ // Brings this popup to the back of other popups (in the same map pane).
+ bringToBack: function () {
+ if (this._map) {
+ toBack(this._container);
+ }
+ return this;
+ },
+
+ _updateContent: function () {
+ if (!this._content) { return; }
+
+ var node = this._contentNode;
+ var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
+
+ if (typeof content === 'string') {
+ node.innerHTML = content;
+ } else {
+ while (node.hasChildNodes()) {
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(content);
+ }
+ this.fire('contentupdate');
+ },
+
+ _updatePosition: function () {
+ if (!this._map) { return; }
+
+ var pos = this._map.latLngToLayerPoint(this._latlng),
+ offset = toPoint(this.options.offset),
+ anchor = this._getAnchor();
+
+ if (this._zoomAnimated) {
+ setPosition(this._container, pos.add(anchor));
+ } else {
+ offset = offset.add(pos).add(anchor);
+ }
+
+ var bottom = this._containerBottom = -offset.y,
+ left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
+
+ // bottom position the popup in case the height of the popup changes (images loading etc)
+ this._container.style.bottom = bottom + 'px';
+ this._container.style.left = left + 'px';
+ },
+
+ _getAnchor: function () {
+ return [0, 0];
+ }
+
+});
+
+/*
+ * @class Popup
+ * @inherits DivOverlay
+ * @aka L.Popup
+ * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
+ * open popups while making sure that only one popup is open at one time
+ * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
+ *
+ * @example
+ *
+ * If you want to just bind a popup to marker click and then open it, it's really easy:
+ *
+ * ```js
+ * marker.bindPopup(popupContent).openPopup();
+ * ```
+ * Path overlays like polylines also have a `bindPopup` method.
+ * Here's a more complicated way to open a popup on a map:
+ *
+ * ```js
+ * var popup = L.popup()
+ * .setLatLng(latlng)
+ * .setContent('<p>Hello world!<br />This is a nice popup.</p>')
+ * .openOn(map);
+ * ```
+ */
+
+
+// @namespace Popup
+var Popup = DivOverlay.extend({
+
+ // @section
+ // @aka Popup options
+ options: {
+ // @option maxWidth: Number = 300
+ // Max width of the popup, in pixels.
+ maxWidth: 300,
+
+ // @option minWidth: Number = 50
+ // Min width of the popup, in pixels.
+ minWidth: 50,
+
+ // @option maxHeight: Number = null
+ // If set, creates a scrollable container of the given height
+ // inside a popup if its content exceeds it.
+ maxHeight: null,
+
+ // @option autoPan: Boolean = true
+ // Set it to `false` if you don't want the map to do panning animation
+ // to fit the opened popup.
+ autoPan: true,
+
+ // @option autoPanPaddingTopLeft: Point = null
+ // The margin between the popup and the top left corner of the map
+ // view after autopanning was performed.
+ autoPanPaddingTopLeft: null,
+
+ // @option autoPanPaddingBottomRight: Point = null
+ // The margin between the popup and the bottom right corner of the map
+ // view after autopanning was performed.
+ autoPanPaddingBottomRight: null,
+
+ // @option autoPanPadding: Point = Point(5, 5)
+ // Equivalent of setting both top left and bottom right autopan padding to the same value.
+ autoPanPadding: [5, 5],
+
+ // @option keepInView: Boolean = false
+ // Set it to `true` if you want to prevent users from panning the popup
+ // off of the screen while it is open.
+ keepInView: false,
+
+ // @option closeButton: Boolean = true
+ // Controls the presence of a close button in the popup.
+ closeButton: true,
+
+ // @option autoClose: Boolean = true
+ // Set it to `false` if you want to override the default behavior of
+ // the popup closing when another popup is opened.
+ autoClose: true,
+
+ // @option closeOnEscapeKey: Boolean = true
+ // Set it to `false` if you want to override the default behavior of
+ // the ESC key for closing of the popup.
+ closeOnEscapeKey: true,
+
+ // @option closeOnClick: Boolean = *
+ // Set it if you want to override the default behavior of the popup closing when user clicks
+ // on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
+
+ // @option className: String = ''
+ // A custom CSS class name to assign to the popup.
+ className: ''
+ },
+
+ // @namespace Popup
+ // @method openOn(map: Map): this
+ // Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
+ openOn: function (map) {
+ map.openPopup(this);
+ return this;
+ },
+
+ onAdd: function (map) {
+ DivOverlay.prototype.onAdd.call(this, map);
+
+ // @namespace Map
+ // @section Popup events
+ // @event popupopen: PopupEvent
+ // Fired when a popup is opened in the map
+ map.fire('popupopen', {popup: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Popup events
+ // @event popupopen: PopupEvent
+ // Fired when a popup bound to this layer is opened
+ this._source.fire('popupopen', {popup: this}, true);
+ // For non-path layers, we toggle the popup when clicking
+ // again the layer, so prevent the map to reopen it.
+ if (!(this._source instanceof Path)) {
+ this._source.on('preclick', stopPropagation);
+ }
+ }
+ },
+
+ onRemove: function (map) {
+ DivOverlay.prototype.onRemove.call(this, map);
+
+ // @namespace Map
+ // @section Popup events
+ // @event popupclose: PopupEvent
+ // Fired when a popup in the map is closed
+ map.fire('popupclose', {popup: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Popup events
+ // @event popupclose: PopupEvent
+ // Fired when a popup bound to this layer is closed
+ this._source.fire('popupclose', {popup: this}, true);
+ if (!(this._source instanceof Path)) {
+ this._source.off('preclick', stopPropagation);
+ }
+ }
+ },
+
+ getEvents: function () {
+ var events = DivOverlay.prototype.getEvents.call(this);
+
+ if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
+ events.preclick = this._close;
+ }
+
+ if (this.options.keepInView) {
+ events.moveend = this._adjustPan;
+ }
+
+ return events;
+ },
+
+ _close: function () {
+ if (this._map) {
+ this._map.closePopup(this);
+ }
+ },
+
+ _initLayout: function () {
+ var prefix = 'leaflet-popup',
+ container = this._container = create$1('div',
+ prefix + ' ' + (this.options.className || '') +
+ ' leaflet-zoom-animated');
+
+ var wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container);
+ this._contentNode = create$1('div', prefix + '-content', wrapper);
+
+ disableClickPropagation(wrapper);
+ disableScrollPropagation(this._contentNode);
+ on(wrapper, 'contextmenu', stopPropagation);
+
+ this._tipContainer = create$1('div', prefix + '-tip-container', container);
+ this._tip = create$1('div', prefix + '-tip', this._tipContainer);
+
+ if (this.options.closeButton) {
+ var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);
+ closeButton.href = '#close';
+ closeButton.innerHTML = '&#215;';
+
+ on(closeButton, 'click', this._onCloseButtonClick, this);
+ }
+ },
+
+ _updateLayout: function () {
+ var container = this._contentNode,
+ style = container.style;
+
+ style.width = '';
+ style.whiteSpace = 'nowrap';
+
+ var width = container.offsetWidth;
+ width = Math.min(width, this.options.maxWidth);
+ width = Math.max(width, this.options.minWidth);
+
+ style.width = (width + 1) + 'px';
+ style.whiteSpace = '';
+
+ style.height = '';
+
+ var height = container.offsetHeight,
+ maxHeight = this.options.maxHeight,
+ scrolledClass = 'leaflet-popup-scrolled';
+
+ if (maxHeight && height > maxHeight) {
+ style.height = maxHeight + 'px';
+ addClass(container, scrolledClass);
+ } else {
+ removeClass(container, scrolledClass);
+ }
+
+ this._containerWidth = this._container.offsetWidth;
+ },
+
+ _animateZoom: function (e) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
+ anchor = this._getAnchor();
+ setPosition(this._container, pos.add(anchor));
+ },
+
+ _adjustPan: function () {
+ if (!this.options.autoPan) { return; }
+ if (this._map._panAnim) { this._map._panAnim.stop(); }
+
+ var map = this._map,
+ marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,
+ containerHeight = this._container.offsetHeight + marginBottom,
+ containerWidth = this._containerWidth,
+ layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);
+
+ layerPos._add(getPosition(this._container));
+
+ var containerPos = map.layerPointToContainerPoint(layerPos),
+ padding = toPoint(this.options.autoPanPadding),
+ paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),
+ paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),
+ size = map.getSize(),
+ dx = 0,
+ dy = 0;
+
+ if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
+ dx = containerPos.x + containerWidth - size.x + paddingBR.x;
+ }
+ if (containerPos.x - dx - paddingTL.x < 0) { // left
+ dx = containerPos.x - paddingTL.x;
+ }
+ if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
+ dy = containerPos.y + containerHeight - size.y + paddingBR.y;
+ }
+ if (containerPos.y - dy - paddingTL.y < 0) { // top
+ dy = containerPos.y - paddingTL.y;
+ }
+
+ // @namespace Map
+ // @section Popup events
+ // @event autopanstart: Event
+ // Fired when the map starts autopanning when opening a popup.
+ if (dx || dy) {
+ map
+ .fire('autopanstart')
+ .panBy([dx, dy]);
+ }
+ },
+
+ _onCloseButtonClick: function (e) {
+ this._close();
+ stop(e);
+ },
+
+ _getAnchor: function () {
+ // Where should we anchor the popup on the source layer?
+ return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
+ }
+
+});
+
+// @namespace Popup
+// @factory L.popup(options?: Popup options, source?: Layer)
+// Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.
+var popup = function (options, source) {
+ return new Popup(options, source);
+};
+
+
+/* @namespace Map
+ * @section Interaction Options
+ * @option closePopupOnClick: Boolean = true
+ * Set it to `false` if you don't want popups to close when user clicks the map.
+ */
+Map.mergeOptions({
+ closePopupOnClick: true
+});
+
+
+// @namespace Map
+// @section Methods for Layers and Controls
+Map.include({
+ // @method openPopup(popup: Popup): this
+ // Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
+ // @alternative
+ // @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
+ // Creates a popup with the specified content and options and opens it in the given point on a map.
+ openPopup: function (popup, latlng, options) {
+ if (!(popup instanceof Popup)) {
+ popup = new Popup(options).setContent(popup);
+ }
+
+ if (latlng) {
+ popup.setLatLng(latlng);
+ }
+
+ if (this.hasLayer(popup)) {
+ return this;
+ }
+
+ if (this._popup && this._popup.options.autoClose) {
+ this.closePopup();
+ }
+
+ this._popup = popup;
+ return this.addLayer(popup);
+ },
+
+ // @method closePopup(popup?: Popup): this
+ // Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
+ closePopup: function (popup) {
+ if (!popup || popup === this._popup) {
+ popup = this._popup;
+ this._popup = null;
+ }
+ if (popup) {
+ this.removeLayer(popup);
+ }
+ return this;
+ }
+});
+
+/*
+ * @namespace Layer
+ * @section Popup methods example
+ *
+ * All layers share a set of methods convenient for binding popups to it.
+ *
+ * ```js
+ * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
+ * layer.openPopup();
+ * layer.closePopup();
+ * ```
+ *
+ * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.
+ */
+
+// @section Popup methods
+Layer.include({
+
+ // @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
+ // Binds a popup to the layer with the passed `content` and sets up the
+ // necessary event listeners. If a `Function` is passed it will receive
+ // the layer as the first argument and should return a `String` or `HTMLElement`.
+ bindPopup: function (content, options) {
+
+ if (content instanceof Popup) {
+ setOptions(content, options);
+ this._popup = content;
+ content._source = this;
+ } else {
+ if (!this._popup || options) {
+ this._popup = new Popup(options, this);
+ }
+ this._popup.setContent(content);
+ }
+
+ if (!this._popupHandlersAdded) {
+ this.on({
+ click: this._openPopup,
+ keypress: this._onKeyPress,
+ remove: this.closePopup,
+ move: this._movePopup
+ });
+ this._popupHandlersAdded = true;
+ }
+
+ return this;
+ },
+
+ // @method unbindPopup(): this
+ // Removes the popup previously bound with `bindPopup`.
+ unbindPopup: function () {
+ if (this._popup) {
+ this.off({
+ click: this._openPopup,
+ keypress: this._onKeyPress,
+ remove: this.closePopup,
+ move: this._movePopup
+ });
+ this._popupHandlersAdded = false;
+ this._popup = null;
+ }
+ return this;
+ },
+
+ // @method openPopup(latlng?: LatLng): this
+ // Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
+ openPopup: function (layer, latlng) {
+ if (!(layer instanceof Layer)) {
+ latlng = layer;
+ layer = this;
+ }
+
+ if (layer instanceof FeatureGroup) {
+ for (var id in this._layers) {
+ layer = this._layers[id];
+ break;
+ }
+ }
+
+ if (!latlng) {
+ latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
+ }
+
+ if (this._popup && this._map) {
+ // set popup source to this layer
+ this._popup._source = layer;
+
+ // update the popup (content, layout, ect...)
+ this._popup.update();
+
+ // open the popup on the map
+ this._map.openPopup(this._popup, latlng);
+ }
+
+ return this;
+ },
+
+ // @method closePopup(): this
+ // Closes the popup bound to this layer if it is open.
+ closePopup: function () {
+ if (this._popup) {
+ this._popup._close();
+ }
+ return this;
+ },
+
+ // @method togglePopup(): this
+ // Opens or closes the popup bound to this layer depending on its current state.
+ togglePopup: function (target) {
+ if (this._popup) {
+ if (this._popup._map) {
+ this.closePopup();
+ } else {
+ this.openPopup(target);
+ }
+ }
+ return this;
+ },
+
+ // @method isPopupOpen(): boolean
+ // Returns `true` if the popup bound to this layer is currently open.
+ isPopupOpen: function () {
+ return (this._popup ? this._popup.isOpen() : false);
+ },
+
+ // @method setPopupContent(content: String|HTMLElement|Popup): this
+ // Sets the content of the popup bound to this layer.
+ setPopupContent: function (content) {
+ if (this._popup) {
+ this._popup.setContent(content);
+ }
+ return this;
+ },
+
+ // @method getPopup(): Popup
+ // Returns the popup bound to this layer.
+ getPopup: function () {
+ return this._popup;
+ },
+
+ _openPopup: function (e) {
+ var layer = e.layer || e.target;
+
+ if (!this._popup) {
+ return;
+ }
+
+ if (!this._map) {
+ return;
+ }
+
+ // prevent map click
+ stop(e);
+
+ // if this inherits from Path its a vector and we can just
+ // open the popup at the new location
+ if (layer instanceof Path) {
+ this.openPopup(e.layer || e.target, e.latlng);
+ return;
+ }
+
+ // otherwise treat it like a marker and figure out
+ // if we should toggle it open/closed
+ if (this._map.hasLayer(this._popup) && this._popup._source === layer) {
+ this.closePopup();
+ } else {
+ this.openPopup(layer, e.latlng);
+ }
+ },
+
+ _movePopup: function (e) {
+ this._popup.setLatLng(e.latlng);
+ },
+
+ _onKeyPress: function (e) {
+ if (e.originalEvent.keyCode === 13) {
+ this._openPopup(e);
+ }
+ }
+});
+
+/*
+ * @class Tooltip
+ * @inherits DivOverlay
+ * @aka L.Tooltip
+ * Used to display small texts on top of map layers.
+ *
+ * @example
+ *
+ * ```js
+ * marker.bindTooltip("my tooltip text").openTooltip();
+ * ```
+ * Note about tooltip offset. Leaflet takes two options in consideration
+ * for computing tooltip offsetting:
+ * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
+ * Add a positive x offset to move the tooltip to the right, and a positive y offset to
+ * move it to the bottom. Negatives will move to the left and top.
+ * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
+ * should adapt this value if you use a custom icon.
+ */
+
+
+// @namespace Tooltip
+var Tooltip = DivOverlay.extend({
+
+ // @section
+ // @aka Tooltip options
+ options: {
+ // @option pane: String = 'tooltipPane'
+ // `Map pane` where the tooltip will be added.
+ pane: 'tooltipPane',
+
+ // @option offset: Point = Point(0, 0)
+ // Optional offset of the tooltip position.
+ offset: [0, 0],
+
+ // @option direction: String = 'auto'
+ // Direction where to open the tooltip. Possible values are: `right`, `left`,
+ // `top`, `bottom`, `center`, `auto`.
+ // `auto` will dynamically switch between `right` and `left` according to the tooltip
+ // position on the map.
+ direction: 'auto',
+
+ // @option permanent: Boolean = false
+ // Whether to open the tooltip permanently or only on mouseover.
+ permanent: false,
+
+ // @option sticky: Boolean = false
+ // If true, the tooltip will follow the mouse instead of being fixed at the feature center.
+ sticky: false,
+
+ // @option interactive: Boolean = false
+ // If true, the tooltip will listen to the feature events.
+ interactive: false,
+
+ // @option opacity: Number = 0.9
+ // Tooltip container opacity.
+ opacity: 0.9
+ },
+
+ onAdd: function (map) {
+ DivOverlay.prototype.onAdd.call(this, map);
+ this.setOpacity(this.options.opacity);
+
+ // @namespace Map
+ // @section Tooltip events
+ // @event tooltipopen: TooltipEvent
+ // Fired when a tooltip is opened in the map.
+ map.fire('tooltipopen', {tooltip: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Tooltip events
+ // @event tooltipopen: TooltipEvent
+ // Fired when a tooltip bound to this layer is opened.
+ this._source.fire('tooltipopen', {tooltip: this}, true);
+ }
+ },
+
+ onRemove: function (map) {
+ DivOverlay.prototype.onRemove.call(this, map);
+
+ // @namespace Map
+ // @section Tooltip events
+ // @event tooltipclose: TooltipEvent
+ // Fired when a tooltip in the map is closed.
+ map.fire('tooltipclose', {tooltip: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Tooltip events
+ // @event tooltipclose: TooltipEvent
+ // Fired when a tooltip bound to this layer is closed.
+ this._source.fire('tooltipclose', {tooltip: this}, true);
+ }
+ },
+
+ getEvents: function () {
+ var events = DivOverlay.prototype.getEvents.call(this);
+
+ if (touch && !this.options.permanent) {
+ events.preclick = this._close;
+ }
+
+ return events;
+ },
+
+ _close: function () {
+ if (this._map) {
+ this._map.closeTooltip(this);
+ }
+ },
+
+ _initLayout: function () {
+ var prefix = 'leaflet-tooltip',
+ className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
+
+ this._contentNode = this._container = create$1('div', className);
+ },
+
+ _updateLayout: function () {},
+
+ _adjustPan: function () {},
+
+ _setPosition: function (pos) {
+ var map = this._map,
+ container = this._container,
+ centerPoint = map.latLngToContainerPoint(map.getCenter()),
+ tooltipPoint = map.layerPointToContainerPoint(pos),
+ direction = this.options.direction,
+ tooltipWidth = container.offsetWidth,
+ tooltipHeight = container.offsetHeight,
+ offset = toPoint(this.options.offset),
+ anchor = this._getAnchor();
+
+ if (direction === 'top') {
+ pos = pos.add(toPoint(-tooltipWidth / 2 + offset.x, -tooltipHeight + offset.y + anchor.y, true));
+ } else if (direction === 'bottom') {
+ pos = pos.subtract(toPoint(tooltipWidth / 2 - offset.x, -offset.y, true));
+ } else if (direction === 'center') {
+ pos = pos.subtract(toPoint(tooltipWidth / 2 + offset.x, tooltipHeight / 2 - anchor.y + offset.y, true));
+ } else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {
+ direction = 'right';
+ pos = pos.add(toPoint(offset.x + anchor.x, anchor.y - tooltipHeight / 2 + offset.y, true));
+ } else {
+ direction = 'left';
+ pos = pos.subtract(toPoint(tooltipWidth + anchor.x - offset.x, tooltipHeight / 2 - anchor.y - offset.y, true));
+ }
+
+ removeClass(container, 'leaflet-tooltip-right');
+ removeClass(container, 'leaflet-tooltip-left');
+ removeClass(container, 'leaflet-tooltip-top');
+ removeClass(container, 'leaflet-tooltip-bottom');
+ addClass(container, 'leaflet-tooltip-' + direction);
+ setPosition(container, pos);
+ },
+
+ _updatePosition: function () {
+ var pos = this._map.latLngToLayerPoint(this._latlng);
+ this._setPosition(pos);
+ },
+
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+
+ if (this._container) {
+ setOpacity(this._container, opacity);
+ }
+ },
+
+ _animateZoom: function (e) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
+ this._setPosition(pos);
+ },
+
+ _getAnchor: function () {
+ // Where should we anchor the tooltip on the source layer?
+ return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
+ }
+
+});
+
+// @namespace Tooltip
+// @factory L.tooltip(options?: Tooltip options, source?: Layer)
+// Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
+var tooltip = function (options, source) {
+ return new Tooltip(options, source);
+};
+
+// @namespace Map
+// @section Methods for Layers and Controls
+Map.include({
+
+ // @method openTooltip(tooltip: Tooltip): this
+ // Opens the specified tooltip.
+ // @alternative
+ // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
+ // Creates a tooltip with the specified content and options and open it.
+ openTooltip: function (tooltip, latlng, options) {
+ if (!(tooltip instanceof Tooltip)) {
+ tooltip = new Tooltip(options).setContent(tooltip);
+ }
+
+ if (latlng) {
+ tooltip.setLatLng(latlng);
+ }
+
+ if (this.hasLayer(tooltip)) {
+ return this;
+ }
+
+ return this.addLayer(tooltip);
+ },
+
+ // @method closeTooltip(tooltip?: Tooltip): this
+ // Closes the tooltip given as parameter.
+ closeTooltip: function (tooltip) {
+ if (tooltip) {
+ this.removeLayer(tooltip);
+ }
+ return this;
+ }
+
+});
+
+/*
+ * @namespace Layer
+ * @section Tooltip methods example
+ *
+ * All layers share a set of methods convenient for binding tooltips to it.
+ *
+ * ```js
+ * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
+ * layer.openTooltip();
+ * layer.closeTooltip();
+ * ```
+ */
+
+// @section Tooltip methods
+Layer.include({
+
+ // @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
+ // Binds a tooltip to the layer with the passed `content` and sets up the
+ // necessary event listeners. If a `Function` is passed it will receive
+ // the layer as the first argument and should return a `String` or `HTMLElement`.
+ bindTooltip: function (content, options) {
+
+ if (content instanceof Tooltip) {
+ setOptions(content, options);
+ this._tooltip = content;
+ content._source = this;
+ } else {
+ if (!this._tooltip || options) {
+ this._tooltip = new Tooltip(options, this);
+ }
+ this._tooltip.setContent(content);
+
+ }
+
+ this._initTooltipInteractions();
+
+ if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
+ this.openTooltip();
+ }
+
+ return this;
+ },
+
+ // @method unbindTooltip(): this
+ // Removes the tooltip previously bound with `bindTooltip`.
+ unbindTooltip: function () {
+ if (this._tooltip) {
+ this._initTooltipInteractions(true);
+ this.closeTooltip();
+ this._tooltip = null;
+ }
+ return this;
+ },
+
+ _initTooltipInteractions: function (remove$$1) {
+ if (!remove$$1 && this._tooltipHandlersAdded) { return; }
+ var onOff = remove$$1 ? 'off' : 'on',
+ events = {
+ remove: this.closeTooltip,
+ move: this._moveTooltip
+ };
+ if (!this._tooltip.options.permanent) {
+ events.mouseover = this._openTooltip;
+ events.mouseout = this.closeTooltip;
+ if (this._tooltip.options.sticky) {
+ events.mousemove = this._moveTooltip;
+ }
+ if (touch) {
+ events.click = this._openTooltip;
+ }
+ } else {
+ events.add = this._openTooltip;
+ }
+ this[onOff](events);
+ this._tooltipHandlersAdded = !remove$$1;
+ },
+
+ // @method openTooltip(latlng?: LatLng): this
+ // Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
+ openTooltip: function (layer, latlng) {
+ if (!(layer instanceof Layer)) {
+ latlng = layer;
+ layer = this;
+ }
+
+ if (layer instanceof FeatureGroup) {
+ for (var id in this._layers) {
+ layer = this._layers[id];
+ break;
+ }
+ }
+
+ if (!latlng) {
+ latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
+ }
+
+ if (this._tooltip && this._map) {
+
+ // set tooltip source to this layer
+ this._tooltip._source = layer;
+
+ // update the tooltip (content, layout, ect...)
+ this._tooltip.update();
+
+ // open the tooltip on the map
+ this._map.openTooltip(this._tooltip, latlng);
+
+ // Tooltip container may not be defined if not permanent and never
+ // opened.
+ if (this._tooltip.options.interactive && this._tooltip._container) {
+ addClass(this._tooltip._container, 'leaflet-clickable');
+ this.addInteractiveTarget(this._tooltip._container);
+ }
+ }
+
+ return this;
+ },
+
+ // @method closeTooltip(): this
+ // Closes the tooltip bound to this layer if it is open.
+ closeTooltip: function () {
+ if (this._tooltip) {
+ this._tooltip._close();
+ if (this._tooltip.options.interactive && this._tooltip._container) {
+ removeClass(this._tooltip._container, 'leaflet-clickable');
+ this.removeInteractiveTarget(this._tooltip._container);
+ }
+ }
+ return this;
+ },
+
+ // @method toggleTooltip(): this
+ // Opens or closes the tooltip bound to this layer depending on its current state.
+ toggleTooltip: function (target) {
+ if (this._tooltip) {
+ if (this._tooltip._map) {
+ this.closeTooltip();
+ } else {
+ this.openTooltip(target);
+ }
+ }
+ return this;
+ },
+
+ // @method isTooltipOpen(): boolean
+ // Returns `true` if the tooltip bound to this layer is currently open.
+ isTooltipOpen: function () {
+ return this._tooltip.isOpen();
+ },
+
+ // @method setTooltipContent(content: String|HTMLElement|Tooltip): this
+ // Sets the content of the tooltip bound to this layer.
+ setTooltipContent: function (content) {
+ if (this._tooltip) {
+ this._tooltip.setContent(content);
+ }
+ return this;
+ },
+
+ // @method getTooltip(): Tooltip
+ // Returns the tooltip bound to this layer.
+ getTooltip: function () {
+ return this._tooltip;
+ },
+
+ _openTooltip: function (e) {
+ var layer = e.layer || e.target;
+
+ if (!this._tooltip || !this._map) {
+ return;
+ }
+ this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
+ },
+
+ _moveTooltip: function (e) {
+ var latlng = e.latlng, containerPoint, layerPoint;
+ if (this._tooltip.options.sticky && e.originalEvent) {
+ containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
+ layerPoint = this._map.containerPointToLayerPoint(containerPoint);
+ latlng = this._map.layerPointToLatLng(layerPoint);
+ }
+ this._tooltip.setLatLng(latlng);
+ }
+});
+
+/*
+ * @class DivIcon
+ * @aka L.DivIcon
+ * @inherits Icon
+ *
+ * Represents a lightweight icon for markers that uses a simple `<div>`
+ * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
+ *
+ * @example
+ * ```js
+ * var myIcon = L.divIcon({className: 'my-div-icon'});
+ * // you can set .my-div-icon styles in CSS
+ *
+ * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
+ * ```
+ *
+ * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
+ */
+
+var DivIcon = Icon.extend({
+ options: {
+ // @section
+ // @aka DivIcon options
+ iconSize: [12, 12], // also can be set through CSS
+
+ // iconAnchor: (Point),
+ // popupAnchor: (Point),
+
+ // @option html: String = ''
+ // Custom HTML code to put inside the div element, empty by default.
+ html: false,
+
+ // @option bgPos: Point = [0, 0]
+ // Optional relative position of the background, in pixels
+ bgPos: null,
+
+ className: 'leaflet-div-icon'
+ },
+
+ createIcon: function (oldIcon) {
+ var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
+ options = this.options;
+
+ div.innerHTML = options.html !== false ? options.html : '';
+
+ if (options.bgPos) {
+ var bgPos = toPoint(options.bgPos);
+ div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
+ }
+ this._setIconStyles(div, 'icon');
+
+ return div;
+ },
+
+ createShadow: function () {
+ return null;
+ }
+});
+
+// @factory L.divIcon(options: DivIcon options)
+// Creates a `DivIcon` instance with the given options.
+function divIcon(options) {
+ return new DivIcon(options);
+}
+
+Icon.Default = IconDefault;
+
+/*
+ * @class GridLayer
+ * @inherits Layer
+ * @aka L.GridLayer
+ *
+ * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
+ * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.
+ *
+ *
+ * @section Synchronous usage
+ * @example
+ *
+ * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.
+ *
+ * ```js
+ * var CanvasLayer = L.GridLayer.extend({
+ * createTile: function(coords){
+ * // create a <canvas> element for drawing
+ * var tile = L.DomUtil.create('canvas', 'leaflet-tile');
+ *
+ * // setup tile width and height according to the options
+ * var size = this.getTileSize();
+ * tile.width = size.x;
+ * tile.height = size.y;
+ *
+ * // get a canvas context and draw something on it using coords.x, coords.y and coords.z
+ * var ctx = tile.getContext('2d');
+ *
+ * // return the tile so it can be rendered on screen
+ * return tile;
+ * }
+ * });
+ * ```
+ *
+ * @section Asynchronous usage
+ * @example
+ *
+ * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.
+ *
+ * ```js
+ * var CanvasLayer = L.GridLayer.extend({
+ * createTile: function(coords, done){
+ * var error;
+ *
+ * // create a <canvas> element for drawing
+ * var tile = L.DomUtil.create('canvas', 'leaflet-tile');
+ *
+ * // setup tile width and height according to the options
+ * var size = this.getTileSize();
+ * tile.width = size.x;
+ * tile.height = size.y;
+ *
+ * // draw something asynchronously and pass the tile to the done() callback
+ * setTimeout(function() {
+ * done(error, tile);
+ * }, 1000);
+ *
+ * return tile;
+ * }
+ * });
+ * ```
+ *
+ * @section
+ */
+
+
+var GridLayer = Layer.extend({
+
+ // @section
+ // @aka GridLayer options
+ options: {
+ // @option tileSize: Number|Point = 256
+ // Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
+ tileSize: 256,
+
+ // @option opacity: Number = 1.0
+ // Opacity of the tiles. Can be used in the `createTile()` function.
+ opacity: 1,
+
+ // @option updateWhenIdle: Boolean = (depends)
+ // Load new tiles only when panning ends.
+ // `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
+ // `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
+ // [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
+ updateWhenIdle: mobile,
+
+ // @option updateWhenZooming: Boolean = true
+ // By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.
+ updateWhenZooming: true,
+
+ // @option updateInterval: Number = 200
+ // Tiles will not update more than once every `updateInterval` milliseconds when panning.
+ updateInterval: 200,
+
+ // @option zIndex: Number = 1
+ // The explicit zIndex of the tile layer.
+ zIndex: 1,
+
+ // @option bounds: LatLngBounds = undefined
+ // If set, tiles will only be loaded inside the set `LatLngBounds`.
+ bounds: null,
+
+ // @option minZoom: Number = 0
+ // The minimum zoom level down to which this layer will be displayed (inclusive).
+ minZoom: 0,
+
+ // @option maxZoom: Number = undefined
+ // The maximum zoom level up to which this layer will be displayed (inclusive).
+ maxZoom: undefined,
+
+ // @option maxNativeZoom: Number = undefined
+ // Maximum zoom number the tile source has available. If it is specified,
+ // the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
+ // from `maxNativeZoom` level and auto-scaled.
+ maxNativeZoom: undefined,
+
+ // @option minNativeZoom: Number = undefined
+ // Minimum zoom number the tile source has available. If it is specified,
+ // the tiles on all zoom levels lower than `minNativeZoom` will be loaded
+ // from `minNativeZoom` level and auto-scaled.
+ minNativeZoom: undefined,
+
+ // @option noWrap: Boolean = false
+ // Whether the layer is wrapped around the antimeridian. If `true`, the
+ // GridLayer will only be displayed once at low zoom levels. Has no
+ // effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
+ // in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
+ // tiles outside the CRS limits.
+ noWrap: false,
+
+ // @option pane: String = 'tilePane'
+ // `Map pane` where the grid layer will be added.
+ pane: 'tilePane',
+
+ // @option className: String = ''
+ // A custom class name to assign to the tile layer. Empty by default.
+ className: '',
+
+ // @option keepBuffer: Number = 2
+ // When panning the map, keep this many rows and columns of tiles before unloading them.
+ keepBuffer: 2
+ },
+
+ initialize: function (options) {
+ setOptions(this, options);
+ },
+
+ onAdd: function () {
+ this._initContainer();
+
+ this._levels = {};
+ this._tiles = {};
+
+ this._resetView();
+ this._update();
+ },
+
+ beforeAdd: function (map) {
+ map._addZoomLimit(this);
+ },
+
+ onRemove: function (map) {
+ this._removeAllTiles();
+ remove(this._container);
+ map._removeZoomLimit(this);
+ this._container = null;
+ this._tileZoom = undefined;
+ },
+
+ // @method bringToFront: this
+ // Brings the tile layer to the top of all tile layers.
+ bringToFront: function () {
+ if (this._map) {
+ toFront(this._container);
+ this._setAutoZIndex(Math.max);
+ }
+ return this;
+ },
+
+ // @method bringToBack: this
+ // Brings the tile layer to the bottom of all tile layers.
+ bringToBack: function () {
+ if (this._map) {
+ toBack(this._container);
+ this._setAutoZIndex(Math.min);
+ }
+ return this;
+ },
+
+ // @method getContainer: HTMLElement
+ // Returns the HTML element that contains the tiles for this layer.
+ getContainer: function () {
+ return this._container;
+ },
+
+ // @method setOpacity(opacity: Number): this
+ // Changes the [opacity](#gridlayer-opacity) of the grid layer.
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+ this._updateOpacity();
+ return this;
+ },
+
+ // @method setZIndex(zIndex: Number): this
+ // Changes the [zIndex](#gridlayer-zindex) of the grid layer.
+ setZIndex: function (zIndex) {
+ this.options.zIndex = zIndex;
+ this._updateZIndex();
+
+ return this;
+ },
+
+ // @method isLoading: Boolean
+ // Returns `true` if any tile in the grid layer has not finished loading.
+ isLoading: function () {
+ return this._loading;
+ },
+
+ // @method redraw: this
+ // Causes the layer to clear all the tiles and request them again.
+ redraw: function () {
+ if (this._map) {
+ this._removeAllTiles();
+ this._update();
+ }
+ return this;
+ },
+
+ getEvents: function () {
+ var events = {
+ viewprereset: this._invalidateAll,
+ viewreset: this._resetView,
+ zoom: this._resetView,
+ moveend: this._onMoveEnd
+ };
+
+ if (!this.options.updateWhenIdle) {
+ // update tiles on move, but not more often than once per given interval
+ if (!this._onMove) {
+ this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);
+ }
+
+ events.move = this._onMove;
+ }
+
+ if (this._zoomAnimated) {
+ events.zoomanim = this._animateZoom;
+ }
+
+ return events;
+ },
+
+ // @section Extension methods
+ // Layers extending `GridLayer` shall reimplement the following method.
+ // @method createTile(coords: Object, done?: Function): HTMLElement
+ // Called only internally, must be overridden by classes extending `GridLayer`.
+ // Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
+ // is specified, it must be called when the tile has finished loading and drawing.
+ createTile: function () {
+ return document.createElement('div');
+ },
+
+ // @section
+ // @method getTileSize: Point
+ // Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
+ getTileSize: function () {
+ var s = this.options.tileSize;
+ return s instanceof Point ? s : new Point(s, s);
+ },
+
+ _updateZIndex: function () {
+ if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
+ this._container.style.zIndex = this.options.zIndex;
+ }
+ },
+
+ _setAutoZIndex: function (compare) {
+ // go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
+
+ var layers = this.getPane().children,
+ edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
+
+ for (var i = 0, len = layers.length, zIndex; i < len; i++) {
+
+ zIndex = layers[i].style.zIndex;
+
+ if (layers[i] !== this._container && zIndex) {
+ edgeZIndex = compare(edgeZIndex, +zIndex);
+ }
+ }
+
+ if (isFinite(edgeZIndex)) {
+ this.options.zIndex = edgeZIndex + compare(-1, 1);
+ this._updateZIndex();
+ }
+ },
+
+ _updateOpacity: function () {
+ if (!this._map) { return; }
+
+ // IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
+ if (ielt9) { return; }
+
+ setOpacity(this._container, this.options.opacity);
+
+ var now = +new Date(),
+ nextFrame = false,
+ willPrune = false;
+
+ for (var key in this._tiles) {
+ var tile = this._tiles[key];
+ if (!tile.current || !tile.loaded) { continue; }
+
+ var fade = Math.min(1, (now - tile.loaded) / 200);
+
+ setOpacity(tile.el, fade);
+ if (fade < 1) {
+ nextFrame = true;
+ } else {
+ if (tile.active) {
+ willPrune = true;
+ } else {
+ this._onOpaqueTile(tile);
+ }
+ tile.active = true;
+ }
+ }
+
+ if (willPrune && !this._noPrune) { this._pruneTiles(); }
+
+ if (nextFrame) {
+ cancelAnimFrame(this._fadeFrame);
+ this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
+ }
+ },
+
+ _onOpaqueTile: falseFn,
+
+ _initContainer: function () {
+ if (this._container) { return; }
+
+ this._container = create$1('div', 'leaflet-layer ' + (this.options.className || ''));
+ this._updateZIndex();
+
+ if (this.options.opacity < 1) {
+ this._updateOpacity();
+ }
+
+ this.getPane().appendChild(this._container);
+ },
+
+ _updateLevels: function () {
+
+ var zoom = this._tileZoom,
+ maxZoom = this.options.maxZoom;
+
+ if (zoom === undefined) { return undefined; }
+
+ for (var z in this._levels) {
+ if (this._levels[z].el.children.length || z === zoom) {
+ this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
+ this._onUpdateLevel(z);
+ } else {
+ remove(this._levels[z].el);
+ this._removeTilesAtZoom(z);
+ this._onRemoveLevel(z);
+ delete this._levels[z];
+ }
+ }
+
+ var level = this._levels[zoom],
+ map = this._map;
+
+ if (!level) {
+ level = this._levels[zoom] = {};
+
+ level.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
+ level.el.style.zIndex = maxZoom;
+
+ level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
+ level.zoom = zoom;
+
+ this._setZoomTransform(level, map.getCenter(), map.getZoom());
+
+ // force the browser to consider the newly added element for transition
+ falseFn(level.el.offsetWidth);
+
+ this._onCreateLevel(level);
+ }
+
+ this._level = level;
+
+ return level;
+ },
+
+ _onUpdateLevel: falseFn,
+
+ _onRemoveLevel: falseFn,
+
+ _onCreateLevel: falseFn,
+
+ _pruneTiles: function () {
+ if (!this._map) {
+ return;
+ }
+
+ var key, tile;
+
+ var zoom = this._map.getZoom();
+ if (zoom > this.options.maxZoom ||
+ zoom < this.options.minZoom) {
+ this._removeAllTiles();
+ return;
+ }
+
+ for (key in this._tiles) {
+ tile = this._tiles[key];
+ tile.retain = tile.current;
+ }
+
+ for (key in this._tiles) {
+ tile = this._tiles[key];
+ if (tile.current && !tile.active) {
+ var coords = tile.coords;
+ if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
+ this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
+ }
+ }
+ }
+
+ for (key in this._tiles) {
+ if (!this._tiles[key].retain) {
+ this._removeTile(key);
+ }
+ }
+ },
+
+ _removeTilesAtZoom: function (zoom) {
+ for (var key in this._tiles) {
+ if (this._tiles[key].coords.z !== zoom) {
+ continue;
+ }
+ this._removeTile(key);
+ }
+ },
+
+ _removeAllTiles: function () {
+ for (var key in this._tiles) {
+ this._removeTile(key);
+ }
+ },
+
+ _invalidateAll: function () {
+ for (var z in this._levels) {
+ remove(this._levels[z].el);
+ this._onRemoveLevel(z);
+ delete this._levels[z];
+ }
+ this._removeAllTiles();
+
+ this._tileZoom = undefined;
+ },
+
+ _retainParent: function (x, y, z, minZoom) {
+ var x2 = Math.floor(x / 2),
+ y2 = Math.floor(y / 2),
+ z2 = z - 1,
+ coords2 = new Point(+x2, +y2);
+ coords2.z = +z2;
+
+ var key = this._tileCoordsToKey(coords2),
+ tile = this._tiles[key];
+
+ if (tile && tile.active) {
+ tile.retain = true;
+ return true;
+
+ } else if (tile && tile.loaded) {
+ tile.retain = true;
+ }
+
+ if (z2 > minZoom) {
+ return this._retainParent(x2, y2, z2, minZoom);
+ }
+
+ return false;
+ },
+
+ _retainChildren: function (x, y, z, maxZoom) {
+
+ for (var i = 2 * x; i < 2 * x + 2; i++) {
+ for (var j = 2 * y; j < 2 * y + 2; j++) {
+
+ var coords = new Point(i, j);
+ coords.z = z + 1;
+
+ var key = this._tileCoordsToKey(coords),
+ tile = this._tiles[key];
+
+ if (tile && tile.active) {
+ tile.retain = true;
+ continue;
+
+ } else if (tile && tile.loaded) {
+ tile.retain = true;
+ }
+
+ if (z + 1 < maxZoom) {
+ this._retainChildren(i, j, z + 1, maxZoom);
+ }
+ }
+ }
+ },
+
+ _resetView: function (e) {
+ var animating = e && (e.pinch || e.flyTo);
+ this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
+ },
+
+ _animateZoom: function (e) {
+ this._setView(e.center, e.zoom, true, e.noUpdate);
+ },
+
+ _clampZoom: function (zoom) {
+ var options = this.options;
+
+ if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
+ return options.minNativeZoom;
+ }
+
+ if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
+ return options.maxNativeZoom;
+ }
+
+ return zoom;
+ },
+
+ _setView: function (center, zoom, noPrune, noUpdate) {
+ var tileZoom = this._clampZoom(Math.round(zoom));
+ if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
+ (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
+ tileZoom = undefined;
+ }
+
+ var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
+
+ if (!noUpdate || tileZoomChanged) {
+
+ this._tileZoom = tileZoom;
+
+ if (this._abortLoading) {
+ this._abortLoading();
+ }
+
+ this._updateLevels();
+ this._resetGrid();
+
+ if (tileZoom !== undefined) {
+ this._update(center);
+ }
+
+ if (!noPrune) {
+ this._pruneTiles();
+ }
+
+ // Flag to prevent _updateOpacity from pruning tiles during
+ // a zoom anim or a pinch gesture
+ this._noPrune = !!noPrune;
+ }
+
+ this._setZoomTransforms(center, zoom);
+ },
+
+ _setZoomTransforms: function (center, zoom) {
+ for (var i in this._levels) {
+ this._setZoomTransform(this._levels[i], center, zoom);
+ }
+ },
+
+ _setZoomTransform: function (level, center, zoom) {
+ var scale = this._map.getZoomScale(zoom, level.zoom),
+ translate = level.origin.multiplyBy(scale)
+ .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
+
+ if (any3d) {
+ setTransform(level.el, translate, scale);
+ } else {
+ setPosition(level.el, translate);
+ }
+ },
+
+ _resetGrid: function () {
+ var map = this._map,
+ crs = map.options.crs,
+ tileSize = this._tileSize = this.getTileSize(),
+ tileZoom = this._tileZoom;
+
+ var bounds = this._map.getPixelWorldBounds(this._tileZoom);
+ if (bounds) {
+ this._globalTileRange = this._pxBoundsToTileRange(bounds);
+ }
+
+ this._wrapX = crs.wrapLng && !this.options.noWrap && [
+ Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
+ Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
+ ];
+ this._wrapY = crs.wrapLat && !this.options.noWrap && [
+ Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
+ Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
+ ];
+ },
+
+ _onMoveEnd: function () {
+ if (!this._map || this._map._animatingZoom) { return; }
+
+ this._update();
+ },
+
+ _getTiledPixelBounds: function (center) {
+ var map = this._map,
+ mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
+ scale = map.getZoomScale(mapZoom, this._tileZoom),
+ pixelCenter = map.project(center, this._tileZoom).floor(),
+ halfSize = map.getSize().divideBy(scale * 2);
+
+ return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
+ },
+
+ // Private method to load tiles in the grid's active zoom level according to map bounds
+ _update: function (center) {
+ var map = this._map;
+ if (!map) { return; }
+ var zoom = this._clampZoom(map.getZoom());
+
+ if (center === undefined) { center = map.getCenter(); }
+ if (this._tileZoom === undefined) { return; } // if out of minzoom/maxzoom
+
+ var pixelBounds = this._getTiledPixelBounds(center),
+ tileRange = this._pxBoundsToTileRange(pixelBounds),
+ tileCenter = tileRange.getCenter(),
+ queue = [],
+ margin = this.options.keepBuffer,
+ noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
+ tileRange.getTopRight().add([margin, -margin]));
+
+ // Sanity check: panic if the tile range contains Infinity somewhere.
+ if (!(isFinite(tileRange.min.x) &&
+ isFinite(tileRange.min.y) &&
+ isFinite(tileRange.max.x) &&
+ isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
+
+ for (var key in this._tiles) {
+ var c = this._tiles[key].coords;
+ if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
+ this._tiles[key].current = false;
+ }
+ }
+
+ // _update just loads more tiles. If the tile zoom level differs too much
+ // from the map's, let _setView reset levels and prune old tiles.
+ if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
+
+ // create a queue of coordinates to load tiles from
+ for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
+ for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
+ var coords = new Point(i, j);
+ coords.z = this._tileZoom;
+
+ if (!this._isValidTile(coords)) { continue; }
+
+ var tile = this._tiles[this._tileCoordsToKey(coords)];
+ if (tile) {
+ tile.current = true;
+ } else {
+ queue.push(coords);
+ }
+ }
+ }
+
+ // sort tile queue to load tiles in order of their distance to center
+ queue.sort(function (a, b) {
+ return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
+ });
+
+ if (queue.length !== 0) {
+ // if it's the first batch of tiles to load
+ if (!this._loading) {
+ this._loading = true;
+ // @event loading: Event
+ // Fired when the grid layer starts loading tiles.
+ this.fire('loading');
+ }
+
+ // create DOM fragment to append tiles in one batch
+ var fragment = document.createDocumentFragment();
+
+ for (i = 0; i < queue.length; i++) {
+ this._addTile(queue[i], fragment);
+ }
+
+ this._level.el.appendChild(fragment);
+ }
+ },
+
+ _isValidTile: function (coords) {
+ var crs = this._map.options.crs;
+
+ if (!crs.infinite) {
+ // don't load tile if it's out of bounds and not wrapped
+ var bounds = this._globalTileRange;
+ if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
+ (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
+ }
+
+ if (!this.options.bounds) { return true; }
+
+ // don't load tile if it doesn't intersect the bounds in options
+ var tileBounds = this._tileCoordsToBounds(coords);
+ return toLatLngBounds(this.options.bounds).overlaps(tileBounds);
+ },
+
+ _keyToBounds: function (key) {
+ return this._tileCoordsToBounds(this._keyToTileCoords(key));
+ },
+
+ _tileCoordsToNwSe: function (coords) {
+ var map = this._map,
+ tileSize = this.getTileSize(),
+ nwPoint = coords.scaleBy(tileSize),
+ sePoint = nwPoint.add(tileSize),
+ nw = map.unproject(nwPoint, coords.z),
+ se = map.unproject(sePoint, coords.z);
+ return [nw, se];
+ },
+
+ // converts tile coordinates to its geographical bounds
+ _tileCoordsToBounds: function (coords) {
+ var bp = this._tileCoordsToNwSe(coords),
+ bounds = new LatLngBounds(bp[0], bp[1]);
+
+ if (!this.options.noWrap) {
+ bounds = this._map.wrapLatLngBounds(bounds);
+ }
+ return bounds;
+ },
+ // converts tile coordinates to key for the tile cache
+ _tileCoordsToKey: function (coords) {
+ return coords.x + ':' + coords.y + ':' + coords.z;
+ },
+
+ // converts tile cache key to coordinates
+ _keyToTileCoords: function (key) {
+ var k = key.split(':'),
+ coords = new Point(+k[0], +k[1]);
+ coords.z = +k[2];
+ return coords;
+ },
+
+ _removeTile: function (key) {
+ var tile = this._tiles[key];
+ if (!tile) { return; }
+
+ remove(tile.el);
+
+ delete this._tiles[key];
+
+ // @event tileunload: TileEvent
+ // Fired when a tile is removed (e.g. when a tile goes off the screen).
+ this.fire('tileunload', {
+ tile: tile.el,
+ coords: this._keyToTileCoords(key)
+ });
+ },
+
+ _initTile: function (tile) {
+ addClass(tile, 'leaflet-tile');
+
+ var tileSize = this.getTileSize();
+ tile.style.width = tileSize.x + 'px';
+ tile.style.height = tileSize.y + 'px';
+
+ tile.onselectstart = falseFn;
+ tile.onmousemove = falseFn;
+
+ // update opacity on tiles in IE7-8 because of filter inheritance problems
+ if (ielt9 && this.options.opacity < 1) {
+ setOpacity(tile, this.options.opacity);
+ }
+
+ // without this hack, tiles disappear after zoom on Chrome for Android
+ // https://github.com/Leaflet/Leaflet/issues/2078
+ if (android && !android23) {
+ tile.style.WebkitBackfaceVisibility = 'hidden';
+ }
+ },
+
+ _addTile: function (coords, container) {
+ var tilePos = this._getTilePos(coords),
+ key = this._tileCoordsToKey(coords);
+
+ var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));
+
+ this._initTile(tile);
+
+ // if createTile is defined with a second argument ("done" callback),
+ // we know that tile is async and will be ready later; otherwise
+ if (this.createTile.length < 2) {
+ // mark tile as ready, but delay one frame for opacity animation to happen
+ requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
+ }
+
+ setPosition(tile, tilePos);
+
+ // save tile in cache
+ this._tiles[key] = {
+ el: tile,
+ coords: coords,
+ current: true
+ };
+
+ container.appendChild(tile);
+ // @event tileloadstart: TileEvent
+ // Fired when a tile is requested and starts loading.
+ this.fire('tileloadstart', {
+ tile: tile,
+ coords: coords
+ });
+ },
+
+ _tileReady: function (coords, err, tile) {
+ if (err) {
+ // @event tileerror: TileErrorEvent
+ // Fired when there is an error loading a tile.
+ this.fire('tileerror', {
+ error: err,
+ tile: tile,
+ coords: coords
+ });
+ }
+
+ var key = this._tileCoordsToKey(coords);
+
+ tile = this._tiles[key];
+ if (!tile) { return; }
+
+ tile.loaded = +new Date();
+ if (this._map._fadeAnimated) {
+ setOpacity(tile.el, 0);
+ cancelAnimFrame(this._fadeFrame);
+ this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
+ } else {
+ tile.active = true;
+ this._pruneTiles();
+ }
+
+ if (!err) {
+ addClass(tile.el, 'leaflet-tile-loaded');
+
+ // @event tileload: TileEvent
+ // Fired when a tile loads.
+ this.fire('tileload', {
+ tile: tile.el,
+ coords: coords
+ });
+ }
+
+ if (this._noTilesToLoad()) {
+ this._loading = false;
+ // @event load: Event
+ // Fired when the grid layer loaded all visible tiles.
+ this.fire('load');
+
+ if (ielt9 || !this._map._fadeAnimated) {
+ requestAnimFrame(this._pruneTiles, this);
+ } else {
+ // Wait a bit more than 0.2 secs (the duration of the tile fade-in)
+ // to trigger a pruning.
+ setTimeout(bind(this._pruneTiles, this), 250);
+ }
+ }
+ },
+
+ _getTilePos: function (coords) {
+ return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
+ },
+
+ _wrapCoords: function (coords) {
+ var newCoords = new Point(
+ this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,
+ this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y);
+ newCoords.z = coords.z;
+ return newCoords;
+ },
+
+ _pxBoundsToTileRange: function (bounds) {
+ var tileSize = this.getTileSize();
+ return new Bounds(
+ bounds.min.unscaleBy(tileSize).floor(),
+ bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
+ },
+
+ _noTilesToLoad: function () {
+ for (var key in this._tiles) {
+ if (!this._tiles[key].loaded) { return false; }
+ }
+ return true;
+ }
+});
+
+// @factory L.gridLayer(options?: GridLayer options)
+// Creates a new instance of GridLayer with the supplied options.
+function gridLayer(options) {
+ return new GridLayer(options);
+}
+
+/*
+ * @class TileLayer
+ * @inherits GridLayer
+ * @aka L.TileLayer
+ * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.
+ *
+ * @example
+ *
+ * ```js
+ * L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'}).addTo(map);
+ * ```
+ *
+ * @section URL template
+ * @example
+ *
+ * A string of the following form:
+ *
+ * ```
+ * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
+ * ```
+ *
+ * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.
+ *
+ * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
+ *
+ * ```
+ * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
+ * ```
+ */
+
+
+var TileLayer = GridLayer.extend({
+
+ // @section
+ // @aka TileLayer options
+ options: {
+ // @option minZoom: Number = 0
+ // The minimum zoom level down to which this layer will be displayed (inclusive).
+ minZoom: 0,
+
+ // @option maxZoom: Number = 18
+ // The maximum zoom level up to which this layer will be displayed (inclusive).
+ maxZoom: 18,
+
+ // @option subdomains: String|String[] = 'abc'
+ // Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.
+ subdomains: 'abc',
+
+ // @option errorTileUrl: String = ''
+ // URL to the tile image to show in place of the tile that failed to load.
+ errorTileUrl: '',
+
+ // @option zoomOffset: Number = 0
+ // The zoom number used in tile URLs will be offset with this value.
+ zoomOffset: 0,
+
+ // @option tms: Boolean = false
+ // If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
+ tms: false,
+
+ // @option zoomReverse: Boolean = false
+ // If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
+ zoomReverse: false,
+
+ // @option detectRetina: Boolean = false
+ // If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
+ detectRetina: false,
+
+ // @option crossOrigin: Boolean|String = false
+ // Whether the crossOrigin attribute will be added to the tiles.
+ // If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
+ // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
+ crossOrigin: false
+ },
+
+ initialize: function (url, options) {
+
+ this._url = url;
+
+ options = setOptions(this, options);
+
+ // detecting retina displays, adjusting tileSize and zoom levels
+ if (options.detectRetina && retina && options.maxZoom > 0) {
+
+ options.tileSize = Math.floor(options.tileSize / 2);
+
+ if (!options.zoomReverse) {
+ options.zoomOffset++;
+ options.maxZoom--;
+ } else {
+ options.zoomOffset--;
+ options.minZoom++;
+ }
+
+ options.minZoom = Math.max(0, options.minZoom);
+ }
+
+ if (typeof options.subdomains === 'string') {
+ options.subdomains = options.subdomains.split('');
+ }
+
+ // for https://github.com/Leaflet/Leaflet/issues/137
+ if (!android) {
+ this.on('tileunload', this._onTileRemove);
+ }
+ },
+
+ // @method setUrl(url: String, noRedraw?: Boolean): this
+ // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
+ // If the URL does not change, the layer will not be redrawn unless
+ // the noRedraw parameter is set to false.
+ setUrl: function (url, noRedraw) {
+ if (this._url === url && noRedraw === undefined) {
+ noRedraw = true;
+ }
+
+ this._url = url;
+
+ if (!noRedraw) {
+ this.redraw();
+ }
+ return this;
+ },
+
+ // @method createTile(coords: Object, done?: Function): HTMLElement
+ // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
+ // to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
+ // callback is called when the tile has been loaded.
+ createTile: function (coords, done) {
+ var tile = document.createElement('img');
+
+ on(tile, 'load', bind(this._tileOnLoad, this, done, tile));
+ on(tile, 'error', bind(this._tileOnError, this, done, tile));
+
+ if (this.options.crossOrigin || this.options.crossOrigin === '') {
+ tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
+ }
+
+ /*
+ Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
+ http://www.w3.org/TR/WCAG20-TECHS/H67
+ */
+ tile.alt = '';
+
+ /*
+ Set role="presentation" to force screen readers to ignore this
+ https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
+ */
+ tile.setAttribute('role', 'presentation');
+
+ tile.src = this.getTileUrl(coords);
+
+ return tile;
+ },
+
+ // @section Extension methods
+ // @uninheritable
+ // Layers extending `TileLayer` might reimplement the following method.
+ // @method getTileUrl(coords: Object): String
+ // Called only internally, returns the URL for a tile given its coordinates.
+ // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
+ getTileUrl: function (coords) {
+ var data = {
+ r: retina ? '@2x' : '',
+ s: this._getSubdomain(coords),
+ x: coords.x,
+ y: coords.y,
+ z: this._getZoomForUrl()
+ };
+ if (this._map && !this._map.options.crs.infinite) {
+ var invertedY = this._globalTileRange.max.y - coords.y;
+ if (this.options.tms) {
+ data['y'] = invertedY;
+ }
+ data['-y'] = invertedY;
+ }
+
+ return template(this._url, extend(data, this.options));
+ },
+
+ _tileOnLoad: function (done, tile) {
+ // For https://github.com/Leaflet/Leaflet/issues/3332
+ if (ielt9) {
+ setTimeout(bind(done, this, null, tile), 0);
+ } else {
+ done(null, tile);
+ }
+ },
+
+ _tileOnError: function (done, tile, e) {
+ var errorUrl = this.options.errorTileUrl;
+ if (errorUrl && tile.getAttribute('src') !== errorUrl) {
+ tile.src = errorUrl;
+ }
+ done(e, tile);
+ },
+
+ _onTileRemove: function (e) {
+ e.tile.onload = null;
+ },
+
+ _getZoomForUrl: function () {
+ var zoom = this._tileZoom,
+ maxZoom = this.options.maxZoom,
+ zoomReverse = this.options.zoomReverse,
+ zoomOffset = this.options.zoomOffset;
+
+ if (zoomReverse) {
+ zoom = maxZoom - zoom;
+ }
+
+ return zoom + zoomOffset;
+ },
+
+ _getSubdomain: function (tilePoint) {
+ var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
+ return this.options.subdomains[index];
+ },
+
+ // stops loading all tiles in the background layer
+ _abortLoading: function () {
+ var i, tile;
+ for (i in this._tiles) {
+ if (this._tiles[i].coords.z !== this._tileZoom) {
+ tile = this._tiles[i].el;
+
+ tile.onload = falseFn;
+ tile.onerror = falseFn;
+
+ if (!tile.complete) {
+ tile.src = emptyImageUrl;
+ remove(tile);
+ delete this._tiles[i];
+ }
+ }
+ }
+ },
+
+ _removeTile: function (key) {
+ var tile = this._tiles[key];
+ if (!tile) { return; }
+
+ // Cancels any pending http requests associated with the tile
+ // unless we're on Android's stock browser,
+ // see https://github.com/Leaflet/Leaflet/issues/137
+ if (!androidStock) {
+ tile.el.setAttribute('src', emptyImageUrl);
+ }
+
+ return GridLayer.prototype._removeTile.call(this, key);
+ },
+
+ _tileReady: function (coords, err, tile) {
+ if (!this._map || (tile && tile.getAttribute('src') === emptyImageUrl)) {
+ return;
+ }
+
+ return GridLayer.prototype._tileReady.call(this, coords, err, tile);
+ }
+});
+
+
+// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
+// Instantiates a tile layer object given a `URL template` and optionally an options object.
+
+function tileLayer(url, options) {
+ return new TileLayer(url, options);
+}
+
+/*
+ * @class TileLayer.WMS
+ * @inherits TileLayer
+ * @aka L.TileLayer.WMS
+ * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
+ *
+ * @example
+ *
+ * ```js
+ * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
+ * layers: 'nexrad-n0r-900913',
+ * format: 'image/png',
+ * transparent: true,
+ * attribution: "Weather data © 2012 IEM Nexrad"
+ * });
+ * ```
+ */
+
+var TileLayerWMS = TileLayer.extend({
+
+ // @section
+ // @aka TileLayer.WMS options
+ // If any custom options not documented here are used, they will be sent to the
+ // WMS server as extra parameters in each request URL. This can be useful for
+ // [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
+ defaultWmsParams: {
+ service: 'WMS',
+ request: 'GetMap',
+
+ // @option layers: String = ''
+ // **(required)** Comma-separated list of WMS layers to show.
+ layers: '',
+
+ // @option styles: String = ''
+ // Comma-separated list of WMS styles.
+ styles: '',
+
+ // @option format: String = 'image/jpeg'
+ // WMS image format (use `'image/png'` for layers with transparency).
+ format: 'image/jpeg',
+
+ // @option transparent: Boolean = false
+ // If `true`, the WMS service will return images with transparency.
+ transparent: false,
+
+ // @option version: String = '1.1.1'
+ // Version of the WMS service to use
+ version: '1.1.1'
+ },
+
+ options: {
+ // @option crs: CRS = null
+ // Coordinate Reference System to use for the WMS requests, defaults to
+ // map CRS. Don't change this if you're not sure what it means.
+ crs: null,
+
+ // @option uppercase: Boolean = false
+ // If `true`, WMS request parameter keys will be uppercase.
+ uppercase: false
+ },
+
+ initialize: function (url, options) {
+
+ this._url = url;
+
+ var wmsParams = extend({}, this.defaultWmsParams);
+
+ // all keys that are not TileLayer options go to WMS params
+ for (var i in options) {
+ if (!(i in this.options)) {
+ wmsParams[i] = options[i];
+ }
+ }
+
+ options = setOptions(this, options);
+
+ var realRetina = options.detectRetina && retina ? 2 : 1;
+ var tileSize = this.getTileSize();
+ wmsParams.width = tileSize.x * realRetina;
+ wmsParams.height = tileSize.y * realRetina;
+
+ this.wmsParams = wmsParams;
+ },
+
+ onAdd: function (map) {
+
+ this._crs = this.options.crs || map.options.crs;
+ this._wmsVersion = parseFloat(this.wmsParams.version);
+
+ var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
+ this.wmsParams[projectionKey] = this._crs.code;
+
+ TileLayer.prototype.onAdd.call(this, map);
+ },
+
+ getTileUrl: function (coords) {
+
+ var tileBounds = this._tileCoordsToNwSe(coords),
+ crs = this._crs,
+ bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),
+ min = bounds.min,
+ max = bounds.max,
+ bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?
+ [min.y, min.x, max.y, max.x] :
+ [min.x, min.y, max.x, max.y]).join(','),
+ url = TileLayer.prototype.getTileUrl.call(this, coords);
+ return url +
+ getParamString(this.wmsParams, url, this.options.uppercase) +
+ (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
+ },
+
+ // @method setParams(params: Object, noRedraw?: Boolean): this
+ // Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
+ setParams: function (params, noRedraw) {
+
+ extend(this.wmsParams, params);
+
+ if (!noRedraw) {
+ this.redraw();
+ }
+
+ return this;
+ }
+});
+
+
+// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
+// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
+function tileLayerWMS(url, options) {
+ return new TileLayerWMS(url, options);
+}
+
+TileLayer.WMS = TileLayerWMS;
+tileLayer.wms = tileLayerWMS;
+
+/*
+ * @class Renderer
+ * @inherits Layer
+ * @aka L.Renderer
+ *
+ * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
+ * DOM container of the renderer, its bounds, and its zoom animation.
+ *
+ * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
+ * itself can be added or removed to the map. All paths use a renderer, which can
+ * be implicit (the map will decide the type of renderer and use it automatically)
+ * or explicit (using the [`renderer`](#path-renderer) option of the path).
+ *
+ * Do not use this class directly, use `SVG` and `Canvas` instead.
+ *
+ * @event update: Event
+ * Fired when the renderer updates its bounds, center and zoom, for example when
+ * its map has moved
+ */
+
+var Renderer = Layer.extend({
+
+ // @section
+ // @aka Renderer options
+ options: {
+ // @option padding: Number = 0.1
+ // How much to extend the clip area around the map view (relative to its size)
+ // e.g. 0.1 would be 10% of map view in each direction
+ padding: 0.1,
+
+ // @option tolerance: Number = 0
+ // How much to extend click tolerance round a path/object on the map
+ tolerance : 0
+ },
+
+ initialize: function (options) {
+ setOptions(this, options);
+ stamp(this);
+ this._layers = this._layers || {};
+ },
+
+ onAdd: function () {
+ if (!this._container) {
+ this._initContainer(); // defined by renderer implementations
+
+ if (this._zoomAnimated) {
+ addClass(this._container, 'leaflet-zoom-animated');
+ }
+ }
+
+ this.getPane().appendChild(this._container);
+ this._update();
+ this.on('update', this._updatePaths, this);
+ },
+
+ onRemove: function () {
+ this.off('update', this._updatePaths, this);
+ this._destroyContainer();
+ },
+
+ getEvents: function () {
+ var events = {
+ viewreset: this._reset,
+ zoom: this._onZoom,
+ moveend: this._update,
+ zoomend: this._onZoomEnd
+ };
+ if (this._zoomAnimated) {
+ events.zoomanim = this._onAnimZoom;
+ }
+ return events;
+ },
+
+ _onAnimZoom: function (ev) {
+ this._updateTransform(ev.center, ev.zoom);
+ },
+
+ _onZoom: function () {
+ this._updateTransform(this._map.getCenter(), this._map.getZoom());
+ },
+
+ _updateTransform: function (center, zoom) {
+ var scale = this._map.getZoomScale(zoom, this._zoom),
+ position = getPosition(this._container),
+ viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
+ currentCenterPoint = this._map.project(this._center, zoom),
+ destCenterPoint = this._map.project(center, zoom),
+ centerOffset = destCenterPoint.subtract(currentCenterPoint),
+
+ topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
+
+ if (any3d) {
+ setTransform(this._container, topLeftOffset, scale);
+ } else {
+ setPosition(this._container, topLeftOffset);
+ }
+ },
+
+ _reset: function () {
+ this._update();
+ this._updateTransform(this._center, this._zoom);
+
+ for (var id in this._layers) {
+ this._layers[id]._reset();
+ }
+ },
+
+ _onZoomEnd: function () {
+ for (var id in this._layers) {
+ this._layers[id]._project();
+ }
+ },
+
+ _updatePaths: function () {
+ for (var id in this._layers) {
+ this._layers[id]._update();
+ }
+ },
+
+ _update: function () {
+ // Update pixel bounds of renderer container (for positioning/sizing/clipping later)
+ // Subclasses are responsible of firing the 'update' event.
+ var p = this.options.padding,
+ size = this._map.getSize(),
+ min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
+
+ this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
+
+ this._center = this._map.getCenter();
+ this._zoom = this._map.getZoom();
+ }
+});
+
+/*
+ * @class Canvas
+ * @inherits Renderer
+ * @aka L.Canvas
+ *
+ * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
+ * Inherits `Renderer`.
+ *
+ * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
+ * available in all web browsers, notably IE8, and overlapping geometries might
+ * not display properly in some edge cases.
+ *
+ * @example
+ *
+ * Use Canvas by default for all paths in the map:
+ *
+ * ```js
+ * var map = L.map('map', {
+ * renderer: L.canvas()
+ * });
+ * ```
+ *
+ * Use a Canvas renderer with extra padding for specific vector geometries:
+ *
+ * ```js
+ * var map = L.map('map');
+ * var myRenderer = L.canvas({ padding: 0.5 });
+ * var line = L.polyline( coordinates, { renderer: myRenderer } );
+ * var circle = L.circle( center, { renderer: myRenderer } );
+ * ```
+ */
+
+var Canvas = Renderer.extend({
+ getEvents: function () {
+ var events = Renderer.prototype.getEvents.call(this);
+ events.viewprereset = this._onViewPreReset;
+ return events;
+ },
+
+ _onViewPreReset: function () {
+ // Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
+ this._postponeUpdatePaths = true;
+ },
+
+ onAdd: function () {
+ Renderer.prototype.onAdd.call(this);
+
+ // Redraw vectors since canvas is cleared upon removal,
+ // in case of removing the renderer itself from the map.
+ this._draw();
+ },
+
+ _initContainer: function () {
+ var container = this._container = document.createElement('canvas');
+
+ on(container, 'mousemove', throttle(this._onMouseMove, 32, this), this);
+ on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
+ on(container, 'mouseout', this._handleMouseOut, this);
+
+ this._ctx = container.getContext('2d');
+ },
+
+ _destroyContainer: function () {
+ cancelAnimFrame(this._redrawRequest);
+ delete this._ctx;
+ remove(this._container);
+ off(this._container);
+ delete this._container;
+ },
+
+ _updatePaths: function () {
+ if (this._postponeUpdatePaths) { return; }
+
+ var layer;
+ this._redrawBounds = null;
+ for (var id in this._layers) {
+ layer = this._layers[id];
+ layer._update();
+ }
+ this._redraw();
+ },
+
+ _update: function () {
+ if (this._map._animatingZoom && this._bounds) { return; }
+
+ Renderer.prototype._update.call(this);
+
+ var b = this._bounds,
+ container = this._container,
+ size = b.getSize(),
+ m = retina ? 2 : 1;
+
+ setPosition(container, b.min);
+
+ // set canvas size (also clearing it); use double size on retina
+ container.width = m * size.x;
+ container.height = m * size.y;
+ container.style.width = size.x + 'px';
+ container.style.height = size.y + 'px';
+
+ if (retina) {
+ this._ctx.scale(2, 2);
+ }
+
+ // translate so we use the same path coordinates after canvas element moves
+ this._ctx.translate(-b.min.x, -b.min.y);
+
+ // Tell paths to redraw themselves
+ this.fire('update');
+ },
+
+ _reset: function () {
+ Renderer.prototype._reset.call(this);
+
+ if (this._postponeUpdatePaths) {
+ this._postponeUpdatePaths = false;
+ this._updatePaths();
+ }
+ },
+
+ _initPath: function (layer) {
+ this._updateDashArray(layer);
+ this._layers[stamp(layer)] = layer;
+
+ var order = layer._order = {
+ layer: layer,
+ prev: this._drawLast,
+ next: null
+ };
+ if (this._drawLast) { this._drawLast.next = order; }
+ this._drawLast = order;
+ this._drawFirst = this._drawFirst || this._drawLast;
+ },
+
+ _addPath: function (layer) {
+ this._requestRedraw(layer);
+ },
+
+ _removePath: function (layer) {
+ var order = layer._order;
+ var next = order.next;
+ var prev = order.prev;
+
+ if (next) {
+ next.prev = prev;
+ } else {
+ this._drawLast = prev;
+ }
+ if (prev) {
+ prev.next = next;
+ } else {
+ this._drawFirst = next;
+ }
+
+ delete layer._order;
+
+ delete this._layers[stamp(layer)];
+
+ this._requestRedraw(layer);
+ },
+
+ _updatePath: function (layer) {
+ // Redraw the union of the layer's old pixel
+ // bounds and the new pixel bounds.
+ this._extendRedrawBounds(layer);
+ layer._project();
+ layer._update();
+ // The redraw will extend the redraw bounds
+ // with the new pixel bounds.
+ this._requestRedraw(layer);
+ },
+
+ _updateStyle: function (layer) {
+ this._updateDashArray(layer);
+ this._requestRedraw(layer);
+ },
+
+ _updateDashArray: function (layer) {
+ if (typeof layer.options.dashArray === 'string') {
+ var parts = layer.options.dashArray.split(/[, ]+/),
+ dashArray = [],
+ dashValue,
+ i;
+ for (i = 0; i < parts.length; i++) {
+ dashValue = Number(parts[i]);
+ // Ignore dash array containing invalid lengths
+ if (isNaN(dashValue)) { return; }
+ dashArray.push(dashValue);
+ }
+ layer.options._dashArray = dashArray;
+ } else {
+ layer.options._dashArray = layer.options.dashArray;
+ }
+ },
+
+ _requestRedraw: function (layer) {
+ if (!this._map) { return; }
+
+ this._extendRedrawBounds(layer);
+ this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);
+ },
+
+ _extendRedrawBounds: function (layer) {
+ if (layer._pxBounds) {
+ var padding = (layer.options.weight || 0) + 1;
+ this._redrawBounds = this._redrawBounds || new Bounds();
+ this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
+ this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
+ }
+ },
+
+ _redraw: function () {
+ this._redrawRequest = null;
+
+ if (this._redrawBounds) {
+ this._redrawBounds.min._floor();
+ this._redrawBounds.max._ceil();
+ }
+
+ this._clear(); // clear layers in redraw bounds
+ this._draw(); // draw layers
+
+ this._redrawBounds = null;
+ },
+
+ _clear: function () {
+ var bounds = this._redrawBounds;
+ if (bounds) {
+ var size = bounds.getSize();
+ this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
+ } else {
+ this._ctx.clearRect(0, 0, this._container.width, this._container.height);
+ }
+ },
+
+ _draw: function () {
+ var layer, bounds = this._redrawBounds;
+ this._ctx.save();
+ if (bounds) {
+ var size = bounds.getSize();
+ this._ctx.beginPath();
+ this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
+ this._ctx.clip();
+ }
+
+ this._drawing = true;
+
+ for (var order = this._drawFirst; order; order = order.next) {
+ layer = order.layer;
+ if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
+ layer._updatePath();
+ }
+ }
+
+ this._drawing = false;
+
+ this._ctx.restore(); // Restore state before clipping.
+ },
+
+ _updatePoly: function (layer, closed) {
+ if (!this._drawing) { return; }
+
+ var i, j, len2, p,
+ parts = layer._parts,
+ len = parts.length,
+ ctx = this._ctx;
+
+ if (!len) { return; }
+
+ ctx.beginPath();
+
+ for (i = 0; i < len; i++) {
+ for (j = 0, len2 = parts[i].length; j < len2; j++) {
+ p = parts[i][j];
+ ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
+ }
+ if (closed) {
+ ctx.closePath();
+ }
+ }
+
+ this._fillStroke(ctx, layer);
+
+ // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
+ },
+
+ _updateCircle: function (layer) {
+
+ if (!this._drawing || layer._empty()) { return; }
+
+ var p = layer._point,
+ ctx = this._ctx,
+ r = Math.max(Math.round(layer._radius), 1),
+ s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
+
+ if (s !== 1) {
+ ctx.save();
+ ctx.scale(1, s);
+ }
+
+ ctx.beginPath();
+ ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
+
+ if (s !== 1) {
+ ctx.restore();
+ }
+
+ this._fillStroke(ctx, layer);
+ },
+
+ _fillStroke: function (ctx, layer) {
+ var options = layer.options;
+
+ if (options.fill) {
+ ctx.globalAlpha = options.fillOpacity;
+ ctx.fillStyle = options.fillColor || options.color;
+ ctx.fill(options.fillRule || 'evenodd');
+ }
+
+ if (options.stroke && options.weight !== 0) {
+ if (ctx.setLineDash) {
+ ctx.setLineDash(layer.options && layer.options._dashArray || []);
+ }
+ ctx.globalAlpha = options.opacity;
+ ctx.lineWidth = options.weight;
+ ctx.strokeStyle = options.color;
+ ctx.lineCap = options.lineCap;
+ ctx.lineJoin = options.lineJoin;
+ ctx.stroke();
+ }
+ },
+
+ // Canvas obviously doesn't have mouse events for individual drawn objects,
+ // so we emulate that by calculating what's under the mouse on mousemove/click manually
+
+ _onClick: function (e) {
+ var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
+
+ for (var order = this._drawFirst; order; order = order.next) {
+ layer = order.layer;
+ if (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {
+ clickedLayer = layer;
+ }
+ }
+ if (clickedLayer) {
+ fakeStop(e);
+ this._fireEvent([clickedLayer], e);
+ }
+ },
+
+ _onMouseMove: function (e) {
+ if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
+
+ var point = this._map.mouseEventToLayerPoint(e);
+ this._handleMouseHover(e, point);
+ },
+
+
+ _handleMouseOut: function (e) {
+ var layer = this._hoveredLayer;
+ if (layer) {
+ // if we're leaving the layer, fire mouseout
+ removeClass(this._container, 'leaflet-interactive');
+ this._fireEvent([layer], e, 'mouseout');
+ this._hoveredLayer = null;
+ }
+ },
+
+ _handleMouseHover: function (e, point) {
+ var layer, candidateHoveredLayer;
+
+ for (var order = this._drawFirst; order; order = order.next) {
+ layer = order.layer;
+ if (layer.options.interactive && layer._containsPoint(point)) {
+ candidateHoveredLayer = layer;
+ }
+ }
+
+ if (candidateHoveredLayer !== this._hoveredLayer) {
+ this._handleMouseOut(e);
+
+ if (candidateHoveredLayer) {
+ addClass(this._container, 'leaflet-interactive'); // change cursor
+ this._fireEvent([candidateHoveredLayer], e, 'mouseover');
+ this._hoveredLayer = candidateHoveredLayer;
+ }
+ }
+
+ if (this._hoveredLayer) {
+ this._fireEvent([this._hoveredLayer], e);
+ }
+ },
+
+ _fireEvent: function (layers, e, type) {
+ this._map._fireDOMEvent(e, type || e.type, layers);
+ },
+
+ _bringToFront: function (layer) {
+ var order = layer._order;
+
+ if (!order) { return; }
+
+ var next = order.next;
+ var prev = order.prev;
+
+ if (next) {
+ next.prev = prev;
+ } else {
+ // Already last
+ return;
+ }
+ if (prev) {
+ prev.next = next;
+ } else if (next) {
+ // Update first entry unless this is the
+ // single entry
+ this._drawFirst = next;
+ }
+
+ order.prev = this._drawLast;
+ this._drawLast.next = order;
+
+ order.next = null;
+ this._drawLast = order;
+
+ this._requestRedraw(layer);
+ },
+
+ _bringToBack: function (layer) {
+ var order = layer._order;
+
+ if (!order) { return; }
+
+ var next = order.next;
+ var prev = order.prev;
+
+ if (prev) {
+ prev.next = next;
+ } else {
+ // Already first
+ return;
+ }
+ if (next) {
+ next.prev = prev;
+ } else if (prev) {
+ // Update last entry unless this is the
+ // single entry
+ this._drawLast = prev;
+ }
+
+ order.prev = null;
+
+ order.next = this._drawFirst;
+ this._drawFirst.prev = order;
+ this._drawFirst = order;
+
+ this._requestRedraw(layer);
+ }
+});
+
+// @factory L.canvas(options?: Renderer options)
+// Creates a Canvas renderer with the given options.
+function canvas$1(options) {
+ return canvas ? new Canvas(options) : null;
+}
+
+/*
+ * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
+ */
+
+
+var vmlCreate = (function () {
+ try {
+ document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
+ return function (name) {
+ return document.createElement('<lvml:' + name + ' class="lvml">');
+ };
+ } catch (e) {
+ return function (name) {
+ return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
+ };
+ }
+})();
+
+
+/*
+ * @class SVG
+ *
+ *
+ * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
+ * with old versions of Internet Explorer.
+ */
+
+// mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences
+var vmlMixin = {
+
+ _initContainer: function () {
+ this._container = create$1('div', 'leaflet-vml-container');
+ },
+
+ _update: function () {
+ if (this._map._animatingZoom) { return; }
+ Renderer.prototype._update.call(this);
+ this.fire('update');
+ },
+
+ _initPath: function (layer) {
+ var container = layer._container = vmlCreate('shape');
+
+ addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
+
+ container.coordsize = '1 1';
+
+ layer._path = vmlCreate('path');
+ container.appendChild(layer._path);
+
+ this._updateStyle(layer);
+ this._layers[stamp(layer)] = layer;
+ },
+
+ _addPath: function (layer) {
+ var container = layer._container;
+ this._container.appendChild(container);
+
+ if (layer.options.interactive) {
+ layer.addInteractiveTarget(container);
+ }
+ },
+
+ _removePath: function (layer) {
+ var container = layer._container;
+ remove(container);
+ layer.removeInteractiveTarget(container);
+ delete this._layers[stamp(layer)];
+ },
+
+ _updateStyle: function (layer) {
+ var stroke = layer._stroke,
+ fill = layer._fill,
+ options = layer.options,
+ container = layer._container;
+
+ container.stroked = !!options.stroke;
+ container.filled = !!options.fill;
+
+ if (options.stroke) {
+ if (!stroke) {
+ stroke = layer._stroke = vmlCreate('stroke');
+ }
+ container.appendChild(stroke);
+ stroke.weight = options.weight + 'px';
+ stroke.color = options.color;
+ stroke.opacity = options.opacity;
+
+ if (options.dashArray) {
+ stroke.dashStyle = isArray(options.dashArray) ?
+ options.dashArray.join(' ') :
+ options.dashArray.replace(/( *, *)/g, ' ');
+ } else {
+ stroke.dashStyle = '';
+ }
+ stroke.endcap = options.lineCap.replace('butt', 'flat');
+ stroke.joinstyle = options.lineJoin;
+
+ } else if (stroke) {
+ container.removeChild(stroke);
+ layer._stroke = null;
+ }
+
+ if (options.fill) {
+ if (!fill) {
+ fill = layer._fill = vmlCreate('fill');
+ }
+ container.appendChild(fill);
+ fill.color = options.fillColor || options.color;
+ fill.opacity = options.fillOpacity;
+
+ } else if (fill) {
+ container.removeChild(fill);
+ layer._fill = null;
+ }
+ },
+
+ _updateCircle: function (layer) {
+ var p = layer._point.round(),
+ r = Math.round(layer._radius),
+ r2 = Math.round(layer._radiusY || r);
+
+ this._setPath(layer, layer._empty() ? 'M0 0' :
+ 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
+ },
+
+ _setPath: function (layer, path) {
+ layer._path.v = path;
+ },
+
+ _bringToFront: function (layer) {
+ toFront(layer._container);
+ },
+
+ _bringToBack: function (layer) {
+ toBack(layer._container);
+ }
+};
+
+var create$2 = vml ? vmlCreate : svgCreate;
+
+/*
+ * @class SVG
+ * @inherits Renderer
+ * @aka L.SVG
+ *
+ * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
+ * Inherits `Renderer`.
+ *
+ * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
+ * available in all web browsers, notably Android 2.x and 3.x.
+ *
+ * Although SVG is not available on IE7 and IE8, these browsers support
+ * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
+ * (a now deprecated technology), and the SVG renderer will fall back to VML in
+ * this case.
+ *
+ * @example
+ *
+ * Use SVG by default for all paths in the map:
+ *
+ * ```js
+ * var map = L.map('map', {
+ * renderer: L.svg()
+ * });
+ * ```
+ *
+ * Use a SVG renderer with extra padding for specific vector geometries:
+ *
+ * ```js
+ * var map = L.map('map');
+ * var myRenderer = L.svg({ padding: 0.5 });
+ * var line = L.polyline( coordinates, { renderer: myRenderer } );
+ * var circle = L.circle( center, { renderer: myRenderer } );
+ * ```
+ */
+
+var SVG = Renderer.extend({
+
+ getEvents: function () {
+ var events = Renderer.prototype.getEvents.call(this);
+ events.zoomstart = this._onZoomStart;
+ return events;
+ },
+
+ _initContainer: function () {
+ this._container = create$2('svg');
+
+ // makes it possible to click through svg root; we'll reset it back in individual paths
+ this._container.setAttribute('pointer-events', 'none');
+
+ this._rootGroup = create$2('g');
+ this._container.appendChild(this._rootGroup);
+ },
+
+ _destroyContainer: function () {
+ remove(this._container);
+ off(this._container);
+ delete this._container;
+ delete this._rootGroup;
+ delete this._svgSize;
+ },
+
+ _onZoomStart: function () {
+ // Drag-then-pinch interactions might mess up the center and zoom.
+ // In this case, the easiest way to prevent this is re-do the renderer
+ // bounds and padding when the zooming starts.
+ this._update();
+ },
+
+ _update: function () {
+ if (this._map._animatingZoom && this._bounds) { return; }
+
+ Renderer.prototype._update.call(this);
+
+ var b = this._bounds,
+ size = b.getSize(),
+ container = this._container;
+
+ // set size of svg-container if changed
+ if (!this._svgSize || !this._svgSize.equals(size)) {
+ this._svgSize = size;
+ container.setAttribute('width', size.x);
+ container.setAttribute('height', size.y);
+ }
+
+ // movement: update container viewBox so that we don't have to change coordinates of individual layers
+ setPosition(container, b.min);
+ container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
+
+ this.fire('update');
+ },
+
+ // methods below are called by vector layers implementations
+
+ _initPath: function (layer) {
+ var path = layer._path = create$2('path');
+
+ // @namespace Path
+ // @option className: String = null
+ // Custom class name set on an element. Only for SVG renderer.
+ if (layer.options.className) {
+ addClass(path, layer.options.className);
+ }
+
+ if (layer.options.interactive) {
+ addClass(path, 'leaflet-interactive');
+ }
+
+ this._updateStyle(layer);
+ this._layers[stamp(layer)] = layer;
+ },
+
+ _addPath: function (layer) {
+ if (!this._rootGroup) { this._initContainer(); }
+ this._rootGroup.appendChild(layer._path);
+ layer.addInteractiveTarget(layer._path);
+ },
+
+ _removePath: function (layer) {
+ remove(layer._path);
+ layer.removeInteractiveTarget(layer._path);
+ delete this._layers[stamp(layer)];
+ },
+
+ _updatePath: function (layer) {
+ layer._project();
+ layer._update();
+ },
+
+ _updateStyle: function (layer) {
+ var path = layer._path,
+ options = layer.options;
+
+ if (!path) { return; }
+
+ if (options.stroke) {
+ path.setAttribute('stroke', options.color);
+ path.setAttribute('stroke-opacity', options.opacity);
+ path.setAttribute('stroke-width', options.weight);
+ path.setAttribute('stroke-linecap', options.lineCap);
+ path.setAttribute('stroke-linejoin', options.lineJoin);
+
+ if (options.dashArray) {
+ path.setAttribute('stroke-dasharray', options.dashArray);
+ } else {
+ path.removeAttribute('stroke-dasharray');
+ }
+
+ if (options.dashOffset) {
+ path.setAttribute('stroke-dashoffset', options.dashOffset);
+ } else {
+ path.removeAttribute('stroke-dashoffset');
+ }
+ } else {
+ path.setAttribute('stroke', 'none');
+ }
+
+ if (options.fill) {
+ path.setAttribute('fill', options.fillColor || options.color);
+ path.setAttribute('fill-opacity', options.fillOpacity);
+ path.setAttribute('fill-rule', options.fillRule || 'evenodd');
+ } else {
+ path.setAttribute('fill', 'none');
+ }
+ },
+
+ _updatePoly: function (layer, closed) {
+ this._setPath(layer, pointsToPath(layer._parts, closed));
+ },
+
+ _updateCircle: function (layer) {
+ var p = layer._point,
+ r = Math.max(Math.round(layer._radius), 1),
+ r2 = Math.max(Math.round(layer._radiusY), 1) || r,
+ arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
+
+ // drawing a circle with two half-arcs
+ var d = layer._empty() ? 'M0 0' :
+ 'M' + (p.x - r) + ',' + p.y +
+ arc + (r * 2) + ',0 ' +
+ arc + (-r * 2) + ',0 ';
+
+ this._setPath(layer, d);
+ },
+
+ _setPath: function (layer, path) {
+ layer._path.setAttribute('d', path);
+ },
+
+ // SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
+ _bringToFront: function (layer) {
+ toFront(layer._path);
+ },
+
+ _bringToBack: function (layer) {
+ toBack(layer._path);
+ }
+});
+
+if (vml) {
+ SVG.include(vmlMixin);
+}
+
+// @namespace SVG
+// @factory L.svg(options?: Renderer options)
+// Creates a SVG renderer with the given options.
+function svg$1(options) {
+ return svg || vml ? new SVG(options) : null;
+}
+
+Map.include({
+ // @namespace Map; @method getRenderer(layer: Path): Renderer
+ // Returns the instance of `Renderer` that should be used to render the given
+ // `Path`. It will ensure that the `renderer` options of the map and paths
+ // are respected, and that the renderers do exist on the map.
+ getRenderer: function (layer) {
+ // @namespace Path; @option renderer: Renderer
+ // Use this specific instance of `Renderer` for this path. Takes
+ // precedence over the map's [default renderer](#map-renderer).
+ var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
+
+ if (!renderer) {
+ renderer = this._renderer = this._createRenderer();
+ }
+
+ if (!this.hasLayer(renderer)) {
+ this.addLayer(renderer);
+ }
+ return renderer;
+ },
+
+ _getPaneRenderer: function (name) {
+ if (name === 'overlayPane' || name === undefined) {
+ return false;
+ }
+
+ var renderer = this._paneRenderers[name];
+ if (renderer === undefined) {
+ renderer = this._createRenderer({pane: name});
+ this._paneRenderers[name] = renderer;
+ }
+ return renderer;
+ },
+
+ _createRenderer: function (options) {
+ // @namespace Map; @option preferCanvas: Boolean = false
+ // Whether `Path`s should be rendered on a `Canvas` renderer.
+ // By default, all `Path`s are rendered in a `SVG` renderer.
+ return (this.options.preferCanvas && canvas$1(options)) || svg$1(options);
+ }
+});
+
+/*
+ * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
+ */
+
+/*
+ * @class Rectangle
+ * @aka L.Rectangle
+ * @inherits Polygon
+ *
+ * A class for drawing rectangle overlays on a map. Extends `Polygon`.
+ *
+ * @example
+ *
+ * ```js
+ * // define rectangle geographical bounds
+ * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
+ *
+ * // create an orange rectangle
+ * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
+ *
+ * // zoom the map to the rectangle bounds
+ * map.fitBounds(bounds);
+ * ```
+ *
+ */
+
+
+var Rectangle = Polygon.extend({
+ initialize: function (latLngBounds, options) {
+ Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
+ },
+
+ // @method setBounds(latLngBounds: LatLngBounds): this
+ // Redraws the rectangle with the passed bounds.
+ setBounds: function (latLngBounds) {
+ return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
+ },
+
+ _boundsToLatLngs: function (latLngBounds) {
+ latLngBounds = toLatLngBounds(latLngBounds);
+ return [
+ latLngBounds.getSouthWest(),
+ latLngBounds.getNorthWest(),
+ latLngBounds.getNorthEast(),
+ latLngBounds.getSouthEast()
+ ];
+ }
+});
+
+
+// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
+function rectangle(latLngBounds, options) {
+ return new Rectangle(latLngBounds, options);
+}
+
+SVG.create = create$2;
+SVG.pointsToPath = pointsToPath;
+
+GeoJSON.geometryToLayer = geometryToLayer;
+GeoJSON.coordsToLatLng = coordsToLatLng;
+GeoJSON.coordsToLatLngs = coordsToLatLngs;
+GeoJSON.latLngToCoords = latLngToCoords;
+GeoJSON.latLngsToCoords = latLngsToCoords;
+GeoJSON.getFeature = getFeature;
+GeoJSON.asFeature = asFeature;
+
+/*
+ * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
+ * (zoom to a selected bounding box), enabled by default.
+ */
+
+// @namespace Map
+// @section Interaction Options
+Map.mergeOptions({
+ // @option boxZoom: Boolean = true
+ // Whether the map can be zoomed to a rectangular area specified by
+ // dragging the mouse while pressing the shift key.
+ boxZoom: true
+});
+
+var BoxZoom = Handler.extend({
+ initialize: function (map) {
+ this._map = map;
+ this._container = map._container;
+ this._pane = map._panes.overlayPane;
+ this._resetStateTimeout = 0;
+ map.on('unload', this._destroy, this);
+ },
+
+ addHooks: function () {
+ on(this._container, 'mousedown', this._onMouseDown, this);
+ },
+
+ removeHooks: function () {
+ off(this._container, 'mousedown', this._onMouseDown, this);
+ },
+
+ moved: function () {
+ return this._moved;
+ },
+
+ _destroy: function () {
+ remove(this._pane);
+ delete this._pane;
+ },
+
+ _resetState: function () {
+ this._resetStateTimeout = 0;
+ this._moved = false;
+ },
+
+ _clearDeferredResetState: function () {
+ if (this._resetStateTimeout !== 0) {
+ clearTimeout(this._resetStateTimeout);
+ this._resetStateTimeout = 0;
+ }
+ },
+
+ _onMouseDown: function (e) {
+ if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
+
+ // Clear the deferred resetState if it hasn't executed yet, otherwise it
+ // will interrupt the interaction and orphan a box element in the container.
+ this._clearDeferredResetState();
+ this._resetState();
+
+ disableTextSelection();
+ disableImageDrag();
+
+ this._startPoint = this._map.mouseEventToContainerPoint(e);
+
+ on(document, {
+ contextmenu: stop,
+ mousemove: this._onMouseMove,
+ mouseup: this._onMouseUp,
+ keydown: this._onKeyDown
+ }, this);
+ },
+
+ _onMouseMove: function (e) {
+ if (!this._moved) {
+ this._moved = true;
+
+ this._box = create$1('div', 'leaflet-zoom-box', this._container);
+ addClass(this._container, 'leaflet-crosshair');
+
+ this._map.fire('boxzoomstart');
+ }
+
+ this._point = this._map.mouseEventToContainerPoint(e);
+
+ var bounds = new Bounds(this._point, this._startPoint),
+ size = bounds.getSize();
+
+ setPosition(this._box, bounds.min);
+
+ this._box.style.width = size.x + 'px';
+ this._box.style.height = size.y + 'px';
+ },
+
+ _finish: function () {
+ if (this._moved) {
+ remove(this._box);
+ removeClass(this._container, 'leaflet-crosshair');
+ }
+
+ enableTextSelection();
+ enableImageDrag();
+
+ off(document, {
+ contextmenu: stop,
+ mousemove: this._onMouseMove,
+ mouseup: this._onMouseUp,
+ keydown: this._onKeyDown
+ }, this);
+ },
+
+ _onMouseUp: function (e) {
+ if ((e.which !== 1) && (e.button !== 1)) { return; }
+
+ this._finish();
+
+ if (!this._moved) { return; }
+ // Postpone to next JS tick so internal click event handling
+ // still see it as "moved".
+ this._clearDeferredResetState();
+ this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);
+
+ var bounds = new LatLngBounds(
+ this._map.containerPointToLatLng(this._startPoint),
+ this._map.containerPointToLatLng(this._point));
+
+ this._map
+ .fitBounds(bounds)
+ .fire('boxzoomend', {boxZoomBounds: bounds});
+ },
+
+ _onKeyDown: function (e) {
+ if (e.keyCode === 27) {
+ this._finish();
+ }
+ }
+});
+
+// @section Handlers
+// @property boxZoom: Handler
+// Box (shift-drag with mouse) zoom handler.
+Map.addInitHook('addHandler', 'boxZoom', BoxZoom);
+
+/*
+ * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
+ */
+
+// @namespace Map
+// @section Interaction Options
+
+Map.mergeOptions({
+ // @option doubleClickZoom: Boolean|String = true
+ // Whether the map can be zoomed in by double clicking on it and
+ // zoomed out by double clicking while holding shift. If passed
+ // `'center'`, double-click zoom will zoom to the center of the
+ // view regardless of where the mouse was.
+ doubleClickZoom: true
+});
+
+var DoubleClickZoom = Handler.extend({
+ addHooks: function () {
+ this._map.on('dblclick', this._onDoubleClick, this);
+ },
+
+ removeHooks: function () {
+ this._map.off('dblclick', this._onDoubleClick, this);
+ },
+
+ _onDoubleClick: function (e) {
+ var map = this._map,
+ oldZoom = map.getZoom(),
+ delta = map.options.zoomDelta,
+ zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
+
+ if (map.options.doubleClickZoom === 'center') {
+ map.setZoom(zoom);
+ } else {
+ map.setZoomAround(e.containerPoint, zoom);
+ }
+ }
+});
+
+// @section Handlers
+//
+// Map properties include interaction handlers that allow you to control
+// interaction behavior in runtime, enabling or disabling certain features such
+// as dragging or touch zoom (see `Handler` methods). For example:
+//
+// ```js
+// map.doubleClickZoom.disable();
+// ```
+//
+// @property doubleClickZoom: Handler
+// Double click zoom handler.
+Map.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);
+
+/*
+ * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
+ */
+
+// @namespace Map
+// @section Interaction Options
+Map.mergeOptions({
+ // @option dragging: Boolean = true
+ // Whether the map be draggable with mouse/touch or not.
+ dragging: true,
+
+ // @section Panning Inertia Options
+ // @option inertia: Boolean = *
+ // If enabled, panning of the map will have an inertia effect where
+ // the map builds momentum while dragging and continues moving in
+ // the same direction for some time. Feels especially nice on touch
+ // devices. Enabled by default unless running on old Android devices.
+ inertia: !android23,
+
+ // @option inertiaDeceleration: Number = 3000
+ // The rate with which the inertial movement slows down, in pixels/second².
+ inertiaDeceleration: 3400, // px/s^2
+
+ // @option inertiaMaxSpeed: Number = Infinity
+ // Max speed of the inertial movement, in pixels/second.
+ inertiaMaxSpeed: Infinity, // px/s
+
+ // @option easeLinearity: Number = 0.2
+ easeLinearity: 0.2,
+
+ // TODO refactor, move to CRS
+ // @option worldCopyJump: Boolean = false
+ // With this option enabled, the map tracks when you pan to another "copy"
+ // of the world and seamlessly jumps to the original one so that all overlays
+ // like markers and vector layers are still visible.
+ worldCopyJump: false,
+
+ // @option maxBoundsViscosity: Number = 0.0
+ // If `maxBounds` is set, this option will control how solid the bounds
+ // are when dragging the map around. The default value of `0.0` allows the
+ // user to drag outside the bounds at normal speed, higher values will
+ // slow down map dragging outside bounds, and `1.0` makes the bounds fully
+ // solid, preventing the user from dragging outside the bounds.
+ maxBoundsViscosity: 0.0
+});
+
+var Drag = Handler.extend({
+ addHooks: function () {
+ if (!this._draggable) {
+ var map = this._map;
+
+ this._draggable = new Draggable(map._mapPane, map._container);
+
+ this._draggable.on({
+ dragstart: this._onDragStart,
+ drag: this._onDrag,
+ dragend: this._onDragEnd
+ }, this);
+
+ this._draggable.on('predrag', this._onPreDragLimit, this);
+ if (map.options.worldCopyJump) {
+ this._draggable.on('predrag', this._onPreDragWrap, this);
+ map.on('zoomend', this._onZoomEnd, this);
+
+ map.whenReady(this._onZoomEnd, this);
+ }
+ }
+ addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
+ this._draggable.enable();
+ this._positions = [];
+ this._times = [];
+ },
+
+ removeHooks: function () {
+ removeClass(this._map._container, 'leaflet-grab');
+ removeClass(this._map._container, 'leaflet-touch-drag');
+ this._draggable.disable();
+ },
+
+ moved: function () {
+ return this._draggable && this._draggable._moved;
+ },
+
+ moving: function () {
+ return this._draggable && this._draggable._moving;
+ },
+
+ _onDragStart: function () {
+ var map = this._map;
+
+ map._stop();
+ if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
+ var bounds = toLatLngBounds(this._map.options.maxBounds);
+
+ this._offsetLimit = toBounds(
+ this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
+ this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
+ .add(this._map.getSize()));
+
+ this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
+ } else {
+ this._offsetLimit = null;
+ }
+
+ map
+ .fire('movestart')
+ .fire('dragstart');
+
+ if (map.options.inertia) {
+ this._positions = [];
+ this._times = [];
+ }
+ },
+
+ _onDrag: function (e) {
+ if (this._map.options.inertia) {
+ var time = this._lastTime = +new Date(),
+ pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
+
+ this._positions.push(pos);
+ this._times.push(time);
+
+ this._prunePositions(time);
+ }
+
+ this._map
+ .fire('move', e)
+ .fire('drag', e);
+ },
+
+ _prunePositions: function (time) {
+ while (this._positions.length > 1 && time - this._times[0] > 50) {
+ this._positions.shift();
+ this._times.shift();
+ }
+ },
+
+ _onZoomEnd: function () {
+ var pxCenter = this._map.getSize().divideBy(2),
+ pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
+
+ this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
+ this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
+ },
+
+ _viscousLimit: function (value, threshold) {
+ return value - (value - threshold) * this._viscosity;
+ },
+
+ _onPreDragLimit: function () {
+ if (!this._viscosity || !this._offsetLimit) { return; }
+
+ var offset = this._draggable._newPos.subtract(this._draggable._startPos);
+
+ var limit = this._offsetLimit;
+ if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
+ if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
+ if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
+ if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
+
+ this._draggable._newPos = this._draggable._startPos.add(offset);
+ },
+
+ _onPreDragWrap: function () {
+ // TODO refactor to be able to adjust map pane position after zoom
+ var worldWidth = this._worldWidth,
+ halfWidth = Math.round(worldWidth / 2),
+ dx = this._initialWorldOffset,
+ x = this._draggable._newPos.x,
+ newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
+ newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
+ newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
+
+ this._draggable._absPos = this._draggable._newPos.clone();
+ this._draggable._newPos.x = newX;
+ },
+
+ _onDragEnd: function (e) {
+ var map = this._map,
+ options = map.options,
+
+ noInertia = !options.inertia || this._times.length < 2;
+
+ map.fire('dragend', e);
+
+ if (noInertia) {
+ map.fire('moveend');
+
+ } else {
+ this._prunePositions(+new Date());
+
+ var direction = this._lastPos.subtract(this._positions[0]),
+ duration = (this._lastTime - this._times[0]) / 1000,
+ ease = options.easeLinearity,
+
+ speedVector = direction.multiplyBy(ease / duration),
+ speed = speedVector.distanceTo([0, 0]),
+
+ limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
+ limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
+
+ decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
+ offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
+
+ if (!offset.x && !offset.y) {
+ map.fire('moveend');
+
+ } else {
+ offset = map._limitOffset(offset, map.options.maxBounds);
+
+ requestAnimFrame(function () {
+ map.panBy(offset, {
+ duration: decelerationDuration,
+ easeLinearity: ease,
+ noMoveStart: true,
+ animate: true
+ });
+ });
+ }
+ }
+ }
+});
+
+// @section Handlers
+// @property dragging: Handler
+// Map dragging handler (by both mouse and touch).
+Map.addInitHook('addHandler', 'dragging', Drag);
+
+/*
+ * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
+ */
+
+// @namespace Map
+// @section Keyboard Navigation Options
+Map.mergeOptions({
+ // @option keyboard: Boolean = true
+ // Makes the map focusable and allows users to navigate the map with keyboard
+ // arrows and `+`/`-` keys.
+ keyboard: true,
+
+ // @option keyboardPanDelta: Number = 80
+ // Amount of pixels to pan when pressing an arrow key.
+ keyboardPanDelta: 80
+});
+
+var Keyboard = Handler.extend({
+
+ keyCodes: {
+ left: [37],
+ right: [39],
+ down: [40],
+ up: [38],
+ zoomIn: [187, 107, 61, 171],
+ zoomOut: [189, 109, 54, 173]
+ },
+
+ initialize: function (map) {
+ this._map = map;
+
+ this._setPanDelta(map.options.keyboardPanDelta);
+ this._setZoomDelta(map.options.zoomDelta);
+ },
+
+ addHooks: function () {
+ var container = this._map._container;
+
+ // make the container focusable by tabbing
+ if (container.tabIndex <= 0) {
+ container.tabIndex = '0';
+ }
+
+ on(container, {
+ focus: this._onFocus,
+ blur: this._onBlur,
+ mousedown: this._onMouseDown
+ }, this);
+
+ this._map.on({
+ focus: this._addHooks,
+ blur: this._removeHooks
+ }, this);
+ },
+
+ removeHooks: function () {
+ this._removeHooks();
+
+ off(this._map._container, {
+ focus: this._onFocus,
+ blur: this._onBlur,
+ mousedown: this._onMouseDown
+ }, this);
+
+ this._map.off({
+ focus: this._addHooks,
+ blur: this._removeHooks
+ }, this);
+ },
+
+ _onMouseDown: function () {
+ if (this._focused) { return; }
+
+ var body = document.body,
+ docEl = document.documentElement,
+ top = body.scrollTop || docEl.scrollTop,
+ left = body.scrollLeft || docEl.scrollLeft;
+
+ this._map._container.focus();
+
+ window.scrollTo(left, top);
+ },
+
+ _onFocus: function () {
+ this._focused = true;
+ this._map.fire('focus');
+ },
+
+ _onBlur: function () {
+ this._focused = false;
+ this._map.fire('blur');
+ },
+
+ _setPanDelta: function (panDelta) {
+ var keys = this._panKeys = {},
+ codes = this.keyCodes,
+ i, len;
+
+ for (i = 0, len = codes.left.length; i < len; i++) {
+ keys[codes.left[i]] = [-1 * panDelta, 0];
+ }
+ for (i = 0, len = codes.right.length; i < len; i++) {
+ keys[codes.right[i]] = [panDelta, 0];
+ }
+ for (i = 0, len = codes.down.length; i < len; i++) {
+ keys[codes.down[i]] = [0, panDelta];
+ }
+ for (i = 0, len = codes.up.length; i < len; i++) {
+ keys[codes.up[i]] = [0, -1 * panDelta];
+ }
+ },
+
+ _setZoomDelta: function (zoomDelta) {
+ var keys = this._zoomKeys = {},
+ codes = this.keyCodes,
+ i, len;
+
+ for (i = 0, len = codes.zoomIn.length; i < len; i++) {
+ keys[codes.zoomIn[i]] = zoomDelta;
+ }
+ for (i = 0, len = codes.zoomOut.length; i < len; i++) {
+ keys[codes.zoomOut[i]] = -zoomDelta;
+ }
+ },
+
+ _addHooks: function () {
+ on(document, 'keydown', this._onKeyDown, this);
+ },
+
+ _removeHooks: function () {
+ off(document, 'keydown', this._onKeyDown, this);
+ },
+
+ _onKeyDown: function (e) {
+ if (e.altKey || e.ctrlKey || e.metaKey) { return; }
+
+ var key = e.keyCode,
+ map = this._map,
+ offset;
+
+ if (key in this._panKeys) {
+ if (!map._panAnim || !map._panAnim._inProgress) {
+ offset = this._panKeys[key];
+ if (e.shiftKey) {
+ offset = toPoint(offset).multiplyBy(3);
+ }
+
+ map.panBy(offset);
+
+ if (map.options.maxBounds) {
+ map.panInsideBounds(map.options.maxBounds);
+ }
+ }
+ } else if (key in this._zoomKeys) {
+ map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
+
+ } else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
+ map.closePopup();
+
+ } else {
+ return;
+ }
+
+ stop(e);
+ }
+});
+
+// @section Handlers
+// @section Handlers
+// @property keyboard: Handler
+// Keyboard navigation handler.
+Map.addInitHook('addHandler', 'keyboard', Keyboard);
+
+/*
+ * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
+ */
+
+// @namespace Map
+// @section Interaction Options
+Map.mergeOptions({
+ // @section Mousewheel options
+ // @option scrollWheelZoom: Boolean|String = true
+ // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
+ // it will zoom to the center of the view regardless of where the mouse was.
+ scrollWheelZoom: true,
+
+ // @option wheelDebounceTime: Number = 40
+ // Limits the rate at which a wheel can fire (in milliseconds). By default
+ // user can't zoom via wheel more often than once per 40 ms.
+ wheelDebounceTime: 40,
+
+ // @option wheelPxPerZoomLevel: Number = 60
+ // How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
+ // mean a change of one full zoom level. Smaller values will make wheel-zooming
+ // faster (and vice versa).
+ wheelPxPerZoomLevel: 60
+});
+
+var ScrollWheelZoom = Handler.extend({
+ addHooks: function () {
+ on(this._map._container, 'mousewheel', this._onWheelScroll, this);
+
+ this._delta = 0;
+ },
+
+ removeHooks: function () {
+ off(this._map._container, 'mousewheel', this._onWheelScroll, this);
+ },
+
+ _onWheelScroll: function (e) {
+ var delta = getWheelDelta(e);
+
+ var debounce = this._map.options.wheelDebounceTime;
+
+ this._delta += delta;
+ this._lastMousePos = this._map.mouseEventToContainerPoint(e);
+
+ if (!this._startTime) {
+ this._startTime = +new Date();
+ }
+
+ var left = Math.max(debounce - (+new Date() - this._startTime), 0);
+
+ clearTimeout(this._timer);
+ this._timer = setTimeout(bind(this._performZoom, this), left);
+
+ stop(e);
+ },
+
+ _performZoom: function () {
+ var map = this._map,
+ zoom = map.getZoom(),
+ snap = this._map.options.zoomSnap || 0;
+
+ map._stop(); // stop panning and fly animations if any
+
+ // map the delta with a sigmoid function to -4..4 range leaning on -1..1
+ var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
+ d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
+ d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
+ delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
+
+ this._delta = 0;
+ this._startTime = null;
+
+ if (!delta) { return; }
+
+ if (map.options.scrollWheelZoom === 'center') {
+ map.setZoom(zoom + delta);
+ } else {
+ map.setZoomAround(this._lastMousePos, zoom + delta);
+ }
+ }
+});
+
+// @section Handlers
+// @property scrollWheelZoom: Handler
+// Scroll wheel zoom handler.
+Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);
+
+/*
+ * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
+ */
+
+// @namespace Map
+// @section Interaction Options
+Map.mergeOptions({
+ // @section Touch interaction options
+ // @option tap: Boolean = true
+ // Enables mobile hacks for supporting instant taps (fixing 200ms click
+ // delay on iOS/Android) and touch holds (fired as `contextmenu` events).
+ tap: true,
+
+ // @option tapTolerance: Number = 15
+ // The max number of pixels a user can shift his finger during touch
+ // for it to be considered a valid tap.
+ tapTolerance: 15
+});
+
+var Tap = Handler.extend({
+ addHooks: function () {
+ on(this._map._container, 'touchstart', this._onDown, this);
+ },
+
+ removeHooks: function () {
+ off(this._map._container, 'touchstart', this._onDown, this);
+ },
+
+ _onDown: function (e) {
+ if (!e.touches) { return; }
+
+ preventDefault(e);
+
+ this._fireClick = true;
+
+ // don't simulate click or track longpress if more than 1 touch
+ if (e.touches.length > 1) {
+ this._fireClick = false;
+ clearTimeout(this._holdTimeout);
+ return;
+ }
+
+ var first = e.touches[0],
+ el = first.target;
+
+ this._startPos = this._newPos = new Point(first.clientX, first.clientY);
+
+ // if touching a link, highlight it
+ if (el.tagName && el.tagName.toLowerCase() === 'a') {
+ addClass(el, 'leaflet-active');
+ }
+
+ // simulate long hold but setting a timeout
+ this._holdTimeout = setTimeout(bind(function () {
+ if (this._isTapValid()) {
+ this._fireClick = false;
+ this._onUp();
+ this._simulateEvent('contextmenu', first);
+ }
+ }, this), 1000);
+
+ this._simulateEvent('mousedown', first);
+
+ on(document, {
+ touchmove: this._onMove,
+ touchend: this._onUp
+ }, this);
+ },
+
+ _onUp: function (e) {
+ clearTimeout(this._holdTimeout);
+
+ off(document, {
+ touchmove: this._onMove,
+ touchend: this._onUp
+ }, this);
+
+ if (this._fireClick && e && e.changedTouches) {
+
+ var first = e.changedTouches[0],
+ el = first.target;
+
+ if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
+ removeClass(el, 'leaflet-active');
+ }
+
+ this._simulateEvent('mouseup', first);
+
+ // simulate click if the touch didn't move too much
+ if (this._isTapValid()) {
+ this._simulateEvent('click', first);
+ }
+ }
+ },
+
+ _isTapValid: function () {
+ return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
+ },
+
+ _onMove: function (e) {
+ var first = e.touches[0];
+ this._newPos = new Point(first.clientX, first.clientY);
+ this._simulateEvent('mousemove', first);
+ },
+
+ _simulateEvent: function (type, e) {
+ var simulatedEvent = document.createEvent('MouseEvents');
+
+ simulatedEvent._simulated = true;
+ e.target._simulatedClick = true;
+
+ simulatedEvent.initMouseEvent(
+ type, true, true, window, 1,
+ e.screenX, e.screenY,
+ e.clientX, e.clientY,
+ false, false, false, false, 0, null);
+
+ e.target.dispatchEvent(simulatedEvent);
+ }
+});
+
+// @section Handlers
+// @property tap: Handler
+// Mobile touch hacks (quick tap and touch hold) handler.
+if (touch && !pointer) {
+ Map.addInitHook('addHandler', 'tap', Tap);
+}
+
+/*
+ * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
+ */
+
+// @namespace Map
+// @section Interaction Options
+Map.mergeOptions({
+ // @section Touch interaction options
+ // @option touchZoom: Boolean|String = *
+ // Whether the map can be zoomed by touch-dragging with two fingers. If
+ // passed `'center'`, it will zoom to the center of the view regardless of
+ // where the touch events (fingers) were. Enabled for touch-capable web
+ // browsers except for old Androids.
+ touchZoom: touch && !android23,
+
+ // @option bounceAtZoomLimits: Boolean = true
+ // Set it to false if you don't want the map to zoom beyond min/max zoom
+ // and then bounce back when pinch-zooming.
+ bounceAtZoomLimits: true
+});
+
+var TouchZoom = Handler.extend({
+ addHooks: function () {
+ addClass(this._map._container, 'leaflet-touch-zoom');
+ on(this._map._container, 'touchstart', this._onTouchStart, this);
+ },
+
+ removeHooks: function () {
+ removeClass(this._map._container, 'leaflet-touch-zoom');
+ off(this._map._container, 'touchstart', this._onTouchStart, this);
+ },
+
+ _onTouchStart: function (e) {
+ var map = this._map;
+ if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
+
+ var p1 = map.mouseEventToContainerPoint(e.touches[0]),
+ p2 = map.mouseEventToContainerPoint(e.touches[1]);
+
+ this._centerPoint = map.getSize()._divideBy(2);
+ this._startLatLng = map.containerPointToLatLng(this._centerPoint);
+ if (map.options.touchZoom !== 'center') {
+ this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
+ }
+
+ this._startDist = p1.distanceTo(p2);
+ this._startZoom = map.getZoom();
+
+ this._moved = false;
+ this._zooming = true;
+
+ map._stop();
+
+ on(document, 'touchmove', this._onTouchMove, this);
+ on(document, 'touchend', this._onTouchEnd, this);
+
+ preventDefault(e);
+ },
+
+ _onTouchMove: function (e) {
+ if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
+
+ var map = this._map,
+ p1 = map.mouseEventToContainerPoint(e.touches[0]),
+ p2 = map.mouseEventToContainerPoint(e.touches[1]),
+ scale = p1.distanceTo(p2) / this._startDist;
+
+ this._zoom = map.getScaleZoom(scale, this._startZoom);
+
+ if (!map.options.bounceAtZoomLimits && (
+ (this._zoom < map.getMinZoom() && scale < 1) ||
+ (this._zoom > map.getMaxZoom() && scale > 1))) {
+ this._zoom = map._limitZoom(this._zoom);
+ }
+
+ if (map.options.touchZoom === 'center') {
+ this._center = this._startLatLng;
+ if (scale === 1) { return; }
+ } else {
+ // Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
+ var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
+ if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
+ this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
+ }
+
+ if (!this._moved) {
+ map._moveStart(true, false);
+ this._moved = true;
+ }
+
+ cancelAnimFrame(this._animRequest);
+
+ var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
+ this._animRequest = requestAnimFrame(moveFn, this, true);
+
+ preventDefault(e);
+ },
+
+ _onTouchEnd: function () {
+ if (!this._moved || !this._zooming) {
+ this._zooming = false;
+ return;
+ }
+
+ this._zooming = false;
+ cancelAnimFrame(this._animRequest);
+
+ off(document, 'touchmove', this._onTouchMove);
+ off(document, 'touchend', this._onTouchEnd);
+
+ // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
+ if (this._map.options.zoomAnimation) {
+ this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
+ } else {
+ this._map._resetView(this._center, this._map._limitZoom(this._zoom));
+ }
+ }
+});
+
+// @section Handlers
+// @property touchZoom: Handler
+// Touch zoom handler.
+Map.addInitHook('addHandler', 'touchZoom', TouchZoom);
+
+Map.BoxZoom = BoxZoom;
+Map.DoubleClickZoom = DoubleClickZoom;
+Map.Drag = Drag;
+Map.Keyboard = Keyboard;
+Map.ScrollWheelZoom = ScrollWheelZoom;
+Map.Tap = Tap;
+Map.TouchZoom = TouchZoom;
+
+Object.freeze = freeze;
+
+exports.version = version;
+exports.Control = Control;
+exports.control = control;
+exports.Browser = Browser;
+exports.Evented = Evented;
+exports.Mixin = Mixin;
+exports.Util = Util;
+exports.Class = Class;
+exports.Handler = Handler;
+exports.extend = extend;
+exports.bind = bind;
+exports.stamp = stamp;
+exports.setOptions = setOptions;
+exports.DomEvent = DomEvent;
+exports.DomUtil = DomUtil;
+exports.PosAnimation = PosAnimation;
+exports.Draggable = Draggable;
+exports.LineUtil = LineUtil;
+exports.PolyUtil = PolyUtil;
+exports.Point = Point;
+exports.point = toPoint;
+exports.Bounds = Bounds;
+exports.bounds = toBounds;
+exports.Transformation = Transformation;
+exports.transformation = toTransformation;
+exports.Projection = index;
+exports.LatLng = LatLng;
+exports.latLng = toLatLng;
+exports.LatLngBounds = LatLngBounds;
+exports.latLngBounds = toLatLngBounds;
+exports.CRS = CRS;
+exports.GeoJSON = GeoJSON;
+exports.geoJSON = geoJSON;
+exports.geoJson = geoJson;
+exports.Layer = Layer;
+exports.LayerGroup = LayerGroup;
+exports.layerGroup = layerGroup;
+exports.FeatureGroup = FeatureGroup;
+exports.featureGroup = featureGroup;
+exports.ImageOverlay = ImageOverlay;
+exports.imageOverlay = imageOverlay;
+exports.VideoOverlay = VideoOverlay;
+exports.videoOverlay = videoOverlay;
+exports.DivOverlay = DivOverlay;
+exports.Popup = Popup;
+exports.popup = popup;
+exports.Tooltip = Tooltip;
+exports.tooltip = tooltip;
+exports.Icon = Icon;
+exports.icon = icon;
+exports.DivIcon = DivIcon;
+exports.divIcon = divIcon;
+exports.Marker = Marker;
+exports.marker = marker;
+exports.TileLayer = TileLayer;
+exports.tileLayer = tileLayer;
+exports.GridLayer = GridLayer;
+exports.gridLayer = gridLayer;
+exports.SVG = SVG;
+exports.svg = svg$1;
+exports.Renderer = Renderer;
+exports.Canvas = Canvas;
+exports.canvas = canvas$1;
+exports.Path = Path;
+exports.CircleMarker = CircleMarker;
+exports.circleMarker = circleMarker;
+exports.Circle = Circle;
+exports.circle = circle;
+exports.Polyline = Polyline;
+exports.polyline = polyline;
+exports.Polygon = Polygon;
+exports.polygon = polygon;
+exports.Rectangle = Rectangle;
+exports.rectangle = rectangle;
+exports.Map = Map;
+exports.map = createMap;
+
+var oldL = window.L;
+exports.noConflict = function() {
+ window.L = oldL;
+ return this;
+}
+
+// Always export us to window global (see #2364)
+window.L = exports;
+
+})));
+//# sourceMappingURL=leaflet-src.js.map
+
+/*
+ Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps.
+ https://github.com/Leaflet/Leaflet.markercluster
+ (c) 2012-2017, Dave Leaver
+*/
+(function (window, document, undefined) {/*
+ * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within
+ */
+
+L.MarkerClusterGroup = L.FeatureGroup.extend({
+
+ options: {
+ maxClusterRadius: 80, //A cluster will cover at most this many pixels from its center
+ iconCreateFunction: null,
+ clusterPane: L.Marker.prototype.options.pane,
+
+ spiderfyOnMaxZoom: true,
+ showCoverageOnHover: true,
+ zoomToBoundsOnClick: true,
+ singleMarkerMode: false,
+
+ disableClusteringAtZoom: null,
+
+ // Setting this to false prevents the removal of any clusters outside of the viewpoint, which
+ // is the default behaviour for performance reasons.
+ removeOutsideVisibleBounds: true,
+
+ // Set to false to disable all animations (zoom and spiderfy).
+ // If false, option animateAddingMarkers below has no effect.
+ // If L.DomUtil.TRANSITION is falsy, this option has no effect.
+ animate: true,
+
+ //Whether to animate adding markers after adding the MarkerClusterGroup to the map
+ // If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains.
+ animateAddingMarkers: false,
+
+ //Increase to increase the distance away that spiderfied markers appear from the center
+ spiderfyDistanceMultiplier: 1,
+
+ // Make it possible to specify a polyline options on a spider leg
+ spiderLegPolylineOptions: { weight: 1.5, color: '#222', opacity: 0.5 },
+
+ // When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeouts
+ chunkedLoading: false,
+ chunkInterval: 200, // process markers for a maximum of ~ n milliseconds (then trigger the chunkProgress callback)
+ chunkDelay: 50, // at the end of each interval, give n milliseconds back to system/browser
+ chunkProgress: null, // progress callback: function(processed, total, elapsed) (e.g. for a progress indicator)
+
+ //Options to pass to the L.Polygon constructor
+ polygonOptions: {}
+ },
+
+ initialize: function (options) {
+ L.Util.setOptions(this, options);
+ if (!this.options.iconCreateFunction) {
+ this.options.iconCreateFunction = this._defaultIconCreateFunction;
+ }
+
+ this._featureGroup = L.featureGroup();
+ this._featureGroup.addEventParent(this);
+
+ this._nonPointGroup = L.featureGroup();
+ this._nonPointGroup.addEventParent(this);
+
+ this._inZoomAnimation = 0;
+ this._needsClustering = [];
+ this._needsRemoving = []; //Markers removed while we aren't on the map need to be kept track of
+ //The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/move
+ this._currentShownBounds = null;
+
+ this._queue = [];
+
+ this._childMarkerEventHandlers = {
+ 'dragstart': this._childMarkerDragStart,
+ 'move': this._childMarkerMoved,
+ 'dragend': this._childMarkerDragEnd,
+ };
+
+ // Hook the appropriate animation methods.
+ var animate = L.DomUtil.TRANSITION && this.options.animate;
+ L.extend(this, animate ? this._withAnimation : this._noAnimation);
+ // Remember which MarkerCluster class to instantiate (animated or not).
+ this._markerCluster = animate ? L.MarkerCluster : L.MarkerClusterNonAnimated;
+ },
+
+ addLayer: function (layer) {
+
+ if (layer instanceof L.LayerGroup) {
+ return this.addLayers([layer]);
+ }
+
+ //Don't cluster non point data
+ if (!layer.getLatLng) {
+ this._nonPointGroup.addLayer(layer);
+ this.fire('layeradd', { layer: layer });
+ return this;
+ }
+
+ if (!this._map) {
+ this._needsClustering.push(layer);
+ this.fire('layeradd', { layer: layer });
+ return this;
+ }
+
+ if (this.hasLayer(layer)) {
+ return this;
+ }
+
+
+ //If we have already clustered we'll need to add this one to a cluster
+
+ if (this._unspiderfy) {
+ this._unspiderfy();
+ }
+
+ this._addLayer(layer, this._maxZoom);
+ this.fire('layeradd', { layer: layer });
+
+ // Refresh bounds and weighted positions.
+ this._topClusterLevel._recalculateBounds();
+
+ this._refreshClustersIcons();
+
+ //Work out what is visible
+ var visibleLayer = layer,
+ currentZoom = this._zoom;
+ if (layer.__parent) {
+ while (visibleLayer.__parent._zoom >= currentZoom) {
+ visibleLayer = visibleLayer.__parent;
+ }
+ }
+
+ if (this._currentShownBounds.contains(visibleLayer.getLatLng())) {
+ if (this.options.animateAddingMarkers) {
+ this._animationAddLayer(layer, visibleLayer);
+ } else {
+ this._animationAddLayerNonAnimated(layer, visibleLayer);
+ }
+ }
+ return this;
+ },
+
+ removeLayer: function (layer) {
+
+ if (layer instanceof L.LayerGroup) {
+ return this.removeLayers([layer]);
+ }
+
+ //Non point layers
+ if (!layer.getLatLng) {
+ this._nonPointGroup.removeLayer(layer);
+ this.fire('layerremove', { layer: layer });
+ return this;
+ }
+
+ if (!this._map) {
+ if (!this._arraySplice(this._needsClustering, layer) && this.hasLayer(layer)) {
+ this._needsRemoving.push({ layer: layer, latlng: layer._latlng });
+ }
+ this.fire('layerremove', { layer: layer });
+ return this;
+ }
+
+ if (!layer.__parent) {
+ return this;
+ }
+
+ if (this._unspiderfy) {
+ this._unspiderfy();
+ this._unspiderfyLayer(layer);
+ }
+
+ //Remove the marker from clusters
+ this._removeLayer(layer, true);
+ this.fire('layerremove', { layer: layer });
+
+ // Refresh bounds and weighted positions.
+ this._topClusterLevel._recalculateBounds();
+
+ this._refreshClustersIcons();
+
+ layer.off(this._childMarkerEventHandlers, this);
+
+ if (this._featureGroup.hasLayer(layer)) {
+ this._featureGroup.removeLayer(layer);
+ if (layer.clusterShow) {
+ layer.clusterShow();
+ }
+ }
+
+ return this;
+ },
+
+ //Takes an array of markers and adds them in bulk
+ addLayers: function (layersArray, skipLayerAddEvent) {
+ if (!L.Util.isArray(layersArray)) {
+ return this.addLayer(layersArray);
+ }
+
+ var fg = this._featureGroup,
+ npg = this._nonPointGroup,
+ chunked = this.options.chunkedLoading,
+ chunkInterval = this.options.chunkInterval,
+ chunkProgress = this.options.chunkProgress,
+ l = layersArray.length,
+ offset = 0,
+ originalArray = true,
+ m;
+
+ if (this._map) {
+ var started = (new Date()).getTime();
+ var process = L.bind(function () {
+ var start = (new Date()).getTime();
+ for (; offset < l; offset++) {
+ if (chunked && offset % 200 === 0) {
+ // every couple hundred markers, instrument the time elapsed since processing started:
+ var elapsed = (new Date()).getTime() - start;
+ if (elapsed > chunkInterval) {
+ break; // been working too hard, time to take a break :-)
+ }
+ }
+
+ m = layersArray[offset];
+
+ // Group of layers, append children to layersArray and skip.
+ // Side effects:
+ // - Total increases, so chunkProgress ratio jumps backward.
+ // - Groups are not included in this group, only their non-group child layers (hasLayer).
+ // Changing array length while looping does not affect performance in current browsers:
+ // http://jsperf.com/for-loop-changing-length/6
+ if (m instanceof L.LayerGroup) {
+ if (originalArray) {
+ layersArray = layersArray.slice();
+ originalArray = false;
+ }
+ this._extractNonGroupLayers(m, layersArray);
+ l = layersArray.length;
+ continue;
+ }
+
+ //Not point data, can't be clustered
+ if (!m.getLatLng) {
+ npg.addLayer(m);
+ if (!skipLayerAddEvent) {
+ this.fire('layeradd', { layer: m });
+ }
+ continue;
+ }
+
+ if (this.hasLayer(m)) {
+ continue;
+ }
+
+ this._addLayer(m, this._maxZoom);
+ if (!skipLayerAddEvent) {
+ this.fire('layeradd', { layer: m });
+ }
+
+ //If we just made a cluster of size 2 then we need to remove the other marker from the map (if it is) or we never will
+ if (m.__parent) {
+ if (m.__parent.getChildCount() === 2) {
+ var markers = m.__parent.getAllChildMarkers(),
+ otherMarker = markers[0] === m ? markers[1] : markers[0];
+ fg.removeLayer(otherMarker);
+ }
+ }
+ }
+
+ if (chunkProgress) {
+ // report progress and time elapsed:
+ chunkProgress(offset, l, (new Date()).getTime() - started);
+ }
+
+ // Completed processing all markers.
+ if (offset === l) {
+
+ // Refresh bounds and weighted positions.
+ this._topClusterLevel._recalculateBounds();
+
+ this._refreshClustersIcons();
+
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
+ } else {
+ setTimeout(process, this.options.chunkDelay);
+ }
+ }, this);
+
+ process();
+ } else {
+ var needsClustering = this._needsClustering;
+
+ for (; offset < l; offset++) {
+ m = layersArray[offset];
+
+ // Group of layers, append children to layersArray and skip.
+ if (m instanceof L.LayerGroup) {
+ if (originalArray) {
+ layersArray = layersArray.slice();
+ originalArray = false;
+ }
+ this._extractNonGroupLayers(m, layersArray);
+ l = layersArray.length;
+ continue;
+ }
+
+ //Not point data, can't be clustered
+ if (!m.getLatLng) {
+ npg.addLayer(m);
+ continue;
+ }
+
+ if (this.hasLayer(m)) {
+ continue;
+ }
+
+ needsClustering.push(m);
+ }
+ }
+ return this;
+ },
+
+ //Takes an array of markers and removes them in bulk
+ removeLayers: function (layersArray) {
+ var i, m,
+ l = layersArray.length,
+ fg = this._featureGroup,
+ npg = this._nonPointGroup,
+ originalArray = true;
+
+ if (!this._map) {
+ for (i = 0; i < l; i++) {
+ m = layersArray[i];
+
+ // Group of layers, append children to layersArray and skip.
+ if (m instanceof L.LayerGroup) {
+ if (originalArray) {
+ layersArray = layersArray.slice();
+ originalArray = false;
+ }
+ this._extractNonGroupLayers(m, layersArray);
+ l = layersArray.length;
+ continue;
+ }
+
+ this._arraySplice(this._needsClustering, m);
+ npg.removeLayer(m);
+ if (this.hasLayer(m)) {
+ this._needsRemoving.push({ layer: m, latlng: m._latlng });
+ }
+ this.fire('layerremove', { layer: m });
+ }
+ return this;
+ }
+
+ if (this._unspiderfy) {
+ this._unspiderfy();
+
+ // Work on a copy of the array, so that next loop is not affected.
+ var layersArray2 = layersArray.slice(),
+ l2 = l;
+ for (i = 0; i < l2; i++) {
+ m = layersArray2[i];
+
+ // Group of layers, append children to layersArray and skip.
+ if (m instanceof L.LayerGroup) {
+ this._extractNonGroupLayers(m, layersArray2);
+ l2 = layersArray2.length;
+ continue;
+ }
+
+ this._unspiderfyLayer(m);
+ }
+ }
+
+ for (i = 0; i < l; i++) {
+ m = layersArray[i];
+
+ // Group of layers, append children to layersArray and skip.
+ if (m instanceof L.LayerGroup) {
+ if (originalArray) {
+ layersArray = layersArray.slice();
+ originalArray = false;
+ }
+ this._extractNonGroupLayers(m, layersArray);
+ l = layersArray.length;
+ continue;
+ }
+
+ if (!m.__parent) {
+ npg.removeLayer(m);
+ this.fire('layerremove', { layer: m });
+ continue;
+ }
+
+ this._removeLayer(m, true, true);
+ this.fire('layerremove', { layer: m });
+
+ if (fg.hasLayer(m)) {
+ fg.removeLayer(m);
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+ }
+ }
+
+ // Refresh bounds and weighted positions.
+ this._topClusterLevel._recalculateBounds();
+
+ this._refreshClustersIcons();
+
+ //Fix up the clusters and markers on the map
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
+
+ return this;
+ },
+
+ //Removes all layers from the MarkerClusterGroup
+ clearLayers: function () {
+ //Need our own special implementation as the LayerGroup one doesn't work for us
+
+ //If we aren't on the map (yet), blow away the markers we know of
+ if (!this._map) {
+ this._needsClustering = [];
+ delete this._gridClusters;
+ delete this._gridUnclustered;
+ }
+
+ if (this._noanimationUnspiderfy) {
+ this._noanimationUnspiderfy();
+ }
+
+ //Remove all the visible layers
+ this._featureGroup.clearLayers();
+ this._nonPointGroup.clearLayers();
+
+ this.eachLayer(function (marker) {
+ marker.off(this._childMarkerEventHandlers, this);
+ delete marker.__parent;
+ }, this);
+
+ if (this._map) {
+ //Reset _topClusterLevel and the DistanceGrids
+ this._generateInitialClusters();
+ }
+
+ return this;
+ },
+
+ //Override FeatureGroup.getBounds as it doesn't work
+ getBounds: function () {
+ var bounds = new L.LatLngBounds();
+
+ if (this._topClusterLevel) {
+ bounds.extend(this._topClusterLevel._bounds);
+ }
+
+ for (var i = this._needsClustering.length - 1; i >= 0; i--) {
+ bounds.extend(this._needsClustering[i].getLatLng());
+ }
+
+ bounds.extend(this._nonPointGroup.getBounds());
+
+ return bounds;
+ },
+
+ //Overrides LayerGroup.eachLayer
+ eachLayer: function (method, context) {
+ var markers = this._needsClustering.slice(),
+ needsRemoving = this._needsRemoving,
+ thisNeedsRemoving, i, j;
+
+ if (this._topClusterLevel) {
+ this._topClusterLevel.getAllChildMarkers(markers);
+ }
+
+ for (i = markers.length - 1; i >= 0; i--) {
+ thisNeedsRemoving = true;
+
+ for (j = needsRemoving.length - 1; j >= 0; j--) {
+ if (needsRemoving[j].layer === markers[i]) {
+ thisNeedsRemoving = false;
+ break;
+ }
+ }
+
+ if (thisNeedsRemoving) {
+ method.call(context, markers[i]);
+ }
+ }
+
+ this._nonPointGroup.eachLayer(method, context);
+ },
+
+ //Overrides LayerGroup.getLayers
+ getLayers: function () {
+ var layers = [];
+ this.eachLayer(function (l) {
+ layers.push(l);
+ });
+ return layers;
+ },
+
+ //Overrides LayerGroup.getLayer, WARNING: Really bad performance
+ getLayer: function (id) {
+ var result = null;
+
+ id = parseInt(id, 10);
+
+ this.eachLayer(function (l) {
+ if (L.stamp(l) === id) {
+ result = l;
+ }
+ });
+
+ return result;
+ },
+
+ //Returns true if the given layer is in this MarkerClusterGroup
+ hasLayer: function (layer) {
+ if (!layer) {
+ return false;
+ }
+
+ var i, anArray = this._needsClustering;
+
+ for (i = anArray.length - 1; i >= 0; i--) {
+ if (anArray[i] === layer) {
+ return true;
+ }
+ }
+
+ anArray = this._needsRemoving;
+ for (i = anArray.length - 1; i >= 0; i--) {
+ if (anArray[i].layer === layer) {
+ return false;
+ }
+ }
+
+ return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer);
+ },
+
+ //Zoom down to show the given layer (spiderfying if necessary) then calls the callback
+ zoomToShowLayer: function (layer, callback) {
+
+ if (typeof callback !== 'function') {
+ callback = function () {};
+ }
+
+ var showMarker = function () {
+ if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) {
+ this._map.off('moveend', showMarker, this);
+ this.off('animationend', showMarker, this);
+
+ if (layer._icon) {
+ callback();
+ } else if (layer.__parent._icon) {
+ this.once('spiderfied', callback, this);
+ layer.__parent.spiderfy();
+ }
+ }
+ };
+
+ if (layer._icon && this._map.getBounds().contains(layer.getLatLng())) {
+ //Layer is visible ond on screen, immediate return
+ callback();
+ } else if (layer.__parent._zoom < Math.round(this._map._zoom)) {
+ //Layer should be visible at this zoom level. It must not be on screen so just pan over to it
+ this._map.on('moveend', showMarker, this);
+ this._map.panTo(layer.getLatLng());
+ } else {
+ this._map.on('moveend', showMarker, this);
+ this.on('animationend', showMarker, this);
+ layer.__parent.zoomToBounds();
+ }
+ },
+
+ //Overrides FeatureGroup.onAdd
+ onAdd: function (map) {
+ this._map = map;
+ var i, l, layer;
+
+ if (!isFinite(this._map.getMaxZoom())) {
+ throw "Map has no maxZoom specified";
+ }
+
+ this._featureGroup.addTo(map);
+ this._nonPointGroup.addTo(map);
+
+ if (!this._gridClusters) {
+ this._generateInitialClusters();
+ }
+
+ this._maxLat = map.options.crs.projection.MAX_LATITUDE;
+
+ //Restore all the positions as they are in the MCG before removing them
+ for (i = 0, l = this._needsRemoving.length; i < l; i++) {
+ layer = this._needsRemoving[i];
+ layer.newlatlng = layer.layer._latlng;
+ layer.layer._latlng = layer.latlng;
+ }
+ //Remove them, then restore their new positions
+ for (i = 0, l = this._needsRemoving.length; i < l; i++) {
+ layer = this._needsRemoving[i];
+ this._removeLayer(layer.layer, true);
+ layer.layer._latlng = layer.newlatlng;
+ }
+ this._needsRemoving = [];
+
+ //Remember the current zoom level and bounds
+ this._zoom = Math.round(this._map._zoom);
+ this._currentShownBounds = this._getExpandedVisibleBounds();
+
+ this._map.on('zoomend', this._zoomEnd, this);
+ this._map.on('moveend', this._moveEnd, this);
+
+ if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely
+ this._spiderfierOnAdd();
+ }
+
+ this._bindEvents();
+
+ //Actually add our markers to the map:
+ l = this._needsClustering;
+ this._needsClustering = [];
+ this.addLayers(l, true);
+ },
+
+ //Overrides FeatureGroup.onRemove
+ onRemove: function (map) {
+ map.off('zoomend', this._zoomEnd, this);
+ map.off('moveend', this._moveEnd, this);
+
+ this._unbindEvents();
+
+ //In case we are in a cluster animation
+ this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '');
+
+ if (this._spiderfierOnRemove) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely
+ this._spiderfierOnRemove();
+ }
+
+ delete this._maxLat;
+
+ //Clean up all the layers we added to the map
+ this._hideCoverage();
+ this._featureGroup.remove();
+ this._nonPointGroup.remove();
+
+ this._featureGroup.clearLayers();
+
+ this._map = null;
+ },
+
+ getVisibleParent: function (marker) {
+ var vMarker = marker;
+ while (vMarker && !vMarker._icon) {
+ vMarker = vMarker.__parent;
+ }
+ return vMarker || null;
+ },
+
+ //Remove the given object from the given array
+ _arraySplice: function (anArray, obj) {
+ for (var i = anArray.length - 1; i >= 0; i--) {
+ if (anArray[i] === obj) {
+ anArray.splice(i, 1);
+ return true;
+ }
+ }
+ },
+
+ /**
+ * Removes a marker from all _gridUnclustered zoom levels, starting at the supplied zoom.
+ * @param marker to be removed from _gridUnclustered.
+ * @param z integer bottom start zoom level (included)
+ * @private
+ */
+ _removeFromGridUnclustered: function (marker, z) {
+ var map = this._map,
+ gridUnclustered = this._gridUnclustered,
+ minZoom = Math.floor(this._map.getMinZoom());
+
+ for (; z >= minZoom; z--) {
+ if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) {
+ break;
+ }
+ }
+ },
+
+ _childMarkerDragStart: function (e) {
+ e.target.__dragStart = e.target._latlng;
+ },
+
+ _childMarkerMoved: function (e) {
+ if (!this._ignoreMove && !e.target.__dragStart) {
+ var isPopupOpen = e.target._popup && e.target._popup.isOpen();
+
+ this._moveChild(e.target, e.oldLatLng, e.latlng);
+
+ if (isPopupOpen) {
+ e.target.openPopup();
+ }
+ }
+ },
+
+ _moveChild: function (layer, from, to) {
+ layer._latlng = from;
+ this.removeLayer(layer);
+
+ layer._latlng = to;
+ this.addLayer(layer);
+ },
+
+ _childMarkerDragEnd: function (e) {
+ if (e.target.__dragStart) {
+ this._moveChild(e.target, e.target.__dragStart, e.target._latlng);
+ }
+ delete e.target.__dragStart;
+ },
+
+
+ //Internal function for removing a marker from everything.
+ //dontUpdateMap: set to true if you will handle updating the map manually (for bulk functions)
+ _removeLayer: function (marker, removeFromDistanceGrid, dontUpdateMap) {
+ var gridClusters = this._gridClusters,
+ gridUnclustered = this._gridUnclustered,
+ fg = this._featureGroup,
+ map = this._map,
+ minZoom = Math.floor(this._map.getMinZoom());
+
+ //Remove the marker from distance clusters it might be in
+ if (removeFromDistanceGrid) {
+ this._removeFromGridUnclustered(marker, this._maxZoom);
+ }
+
+ //Work our way up the clusters removing them as we go if required
+ var cluster = marker.__parent,
+ markers = cluster._markers,
+ otherMarker;
+
+ //Remove the marker from the immediate parents marker list
+ this._arraySplice(markers, marker);
+
+ while (cluster) {
+ cluster._childCount--;
+ cluster._boundsNeedUpdate = true;
+
+ if (cluster._zoom < minZoom) {
+ //Top level, do nothing
+ break;
+ } else if (removeFromDistanceGrid && cluster._childCount <= 1) { //Cluster no longer required
+ //We need to push the other marker up to the parent
+ otherMarker = cluster._markers[0] === marker ? cluster._markers[1] : cluster._markers[0];
+
+ //Update distance grid
+ gridClusters[cluster._zoom].removeObject(cluster, map.project(cluster._cLatLng, cluster._zoom));
+ gridUnclustered[cluster._zoom].addObject(otherMarker, map.project(otherMarker.getLatLng(), cluster._zoom));
+
+ //Move otherMarker up to parent
+ this._arraySplice(cluster.__parent._childClusters, cluster);
+ cluster.__parent._markers.push(otherMarker);
+ otherMarker.__parent = cluster.__parent;
+
+ if (cluster._icon) {
+ //Cluster is currently on the map, need to put the marker on the map instead
+ fg.removeLayer(cluster);
+ if (!dontUpdateMap) {
+ fg.addLayer(otherMarker);
+ }
+ }
+ } else {
+ cluster._iconNeedsUpdate = true;
+ }
+
+ cluster = cluster.__parent;
+ }
+
+ delete marker.__parent;
+ },
+
+ _isOrIsParent: function (el, oel) {
+ while (oel) {
+ if (el === oel) {
+ return true;
+ }
+ oel = oel.parentNode;
+ }
+ return false;
+ },
+
+ //Override L.Evented.fire
+ fire: function (type, data, propagate) {
+ if (data && data.layer instanceof L.MarkerCluster) {
+ //Prevent multiple clustermouseover/off events if the icon is made up of stacked divs (Doesn't work in ie <= 8, no relatedTarget)
+ if (data.originalEvent && this._isOrIsParent(data.layer._icon, data.originalEvent.relatedTarget)) {
+ return;
+ }
+ type = 'cluster' + type;
+ }
+
+ L.FeatureGroup.prototype.fire.call(this, type, data, propagate);
+ },
+
+ //Override L.Evented.listens
+ listens: function (type, propagate) {
+ return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate);
+ },
+
+ //Default functionality
+ _defaultIconCreateFunction: function (cluster) {
+ var childCount = cluster.getChildCount();
+
+ var c = ' marker-cluster-';
+ if (childCount < 10) {
+ c += 'small';
+ } else if (childCount < 100) {
+ c += 'medium';
+ } else {
+ c += 'large';
+ }
+
+ return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
+ },
+
+ _bindEvents: function () {
+ var map = this._map,
+ spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
+ showCoverageOnHover = this.options.showCoverageOnHover,
+ zoomToBoundsOnClick = this.options.zoomToBoundsOnClick;
+
+ //Zoom on cluster click or spiderfy if we are at the lowest level
+ if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
+ this.on('clusterclick', this._zoomOrSpiderfy, this);
+ }
+
+ //Show convex hull (boundary) polygon on mouse over
+ if (showCoverageOnHover) {
+ this.on('clustermouseover', this._showCoverage, this);
+ this.on('clustermouseout', this._hideCoverage, this);
+ map.on('zoomend', this._hideCoverage, this);
+ }
+ },
+
+ _zoomOrSpiderfy: function (e) {
+ var cluster = e.layer,
+ bottomCluster = cluster;
+
+ while (bottomCluster._childClusters.length === 1) {
+ bottomCluster = bottomCluster._childClusters[0];
+ }
+
+ if (bottomCluster._zoom === this._maxZoom &&
+ bottomCluster._childCount === cluster._childCount &&
+ this.options.spiderfyOnMaxZoom) {
+
+ // All child markers are contained in a single cluster from this._maxZoom to this cluster.
+ cluster.spiderfy();
+ } else if (this.options.zoomToBoundsOnClick) {
+ cluster.zoomToBounds();
+ }
+
+ // Focus the map again for keyboard users.
+ if (e.originalEvent && e.originalEvent.keyCode === 13) {
+ this._map._container.focus();
+ }
+ },
+
+ _showCoverage: function (e) {
+ var map = this._map;
+ if (this._inZoomAnimation) {
+ return;
+ }
+ if (this._shownPolygon) {
+ map.removeLayer(this._shownPolygon);
+ }
+ if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) {
+ this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions);
+ map.addLayer(this._shownPolygon);
+ }
+ },
+
+ _hideCoverage: function () {
+ if (this._shownPolygon) {
+ this._map.removeLayer(this._shownPolygon);
+ this._shownPolygon = null;
+ }
+ },
+
+ _unbindEvents: function () {
+ var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
+ showCoverageOnHover = this.options.showCoverageOnHover,
+ zoomToBoundsOnClick = this.options.zoomToBoundsOnClick,
+ map = this._map;
+
+ if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
+ this.off('clusterclick', this._zoomOrSpiderfy, this);
+ }
+ if (showCoverageOnHover) {
+ this.off('clustermouseover', this._showCoverage, this);
+ this.off('clustermouseout', this._hideCoverage, this);
+ map.off('zoomend', this._hideCoverage, this);
+ }
+ },
+
+ _zoomEnd: function () {
+ if (!this._map) { //May have been removed from the map by a zoomEnd handler
+ return;
+ }
+ this._mergeSplitClusters();
+
+ this._zoom = Math.round(this._map._zoom);
+ this._currentShownBounds = this._getExpandedVisibleBounds();
+ },
+
+ _moveEnd: function () {
+ if (this._inZoomAnimation) {
+ return;
+ }
+
+ var newBounds = this._getExpandedVisibleBounds();
+
+ this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, newBounds);
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, Math.round(this._map._zoom), newBounds);
+
+ this._currentShownBounds = newBounds;
+ return;
+ },
+
+ _generateInitialClusters: function () {
+ var maxZoom = Math.ceil(this._map.getMaxZoom()),
+ minZoom = Math.floor(this._map.getMinZoom()),
+ radius = this.options.maxClusterRadius,
+ radiusFn = radius;
+
+ //If we just set maxClusterRadius to a single number, we need to create
+ //a simple function to return that number. Otherwise, we just have to
+ //use the function we've passed in.
+ if (typeof radius !== "function") {
+ radiusFn = function () { return radius; };
+ }
+
+ if (this.options.disableClusteringAtZoom !== null) {
+ maxZoom = this.options.disableClusteringAtZoom - 1;
+ }
+ this._maxZoom = maxZoom;
+ this._gridClusters = {};
+ this._gridUnclustered = {};
+
+ //Set up DistanceGrids for each zoom
+ for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
+ this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom));
+ this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom));
+ }
+
+ // Instantiate the appropriate L.MarkerCluster class (animated or not).
+ this._topClusterLevel = new this._markerCluster(this, minZoom - 1);
+ },
+
+ //Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom)
+ _addLayer: function (layer, zoom) {
+ var gridClusters = this._gridClusters,
+ gridUnclustered = this._gridUnclustered,
+ minZoom = Math.floor(this._map.getMinZoom()),
+ markerPoint, z;
+
+ if (this.options.singleMarkerMode) {
+ this._overrideMarkerIcon(layer);
+ }
+
+ layer.on(this._childMarkerEventHandlers, this);
+
+ //Find the lowest zoom level to slot this one in
+ for (; zoom >= minZoom; zoom--) {
+ markerPoint = this._map.project(layer.getLatLng(), zoom); // calculate pixel position
+
+ //Try find a cluster close by
+ var closest = gridClusters[zoom].getNearObject(markerPoint);
+ if (closest) {
+ closest._addChild(layer);
+ layer.__parent = closest;
+ return;
+ }
+
+ //Try find a marker close by to form a new cluster with
+ closest = gridUnclustered[zoom].getNearObject(markerPoint);
+ if (closest) {
+ var parent = closest.__parent;
+ if (parent) {
+ this._removeLayer(closest, false);
+ }
+
+ //Create new cluster with these 2 in it
+
+ var newCluster = new this._markerCluster(this, zoom, closest, layer);
+ gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom));
+ closest.__parent = newCluster;
+ layer.__parent = newCluster;
+
+ //First create any new intermediate parent clusters that don't exist
+ var lastParent = newCluster;
+ for (z = zoom - 1; z > parent._zoom; z--) {
+ lastParent = new this._markerCluster(this, z, lastParent);
+ gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z));
+ }
+ parent._addChild(lastParent);
+
+ //Remove closest from this zoom level and any above that it is in, replace with newCluster
+ this._removeFromGridUnclustered(closest, zoom);
+
+ return;
+ }
+
+ //Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
+ gridUnclustered[zoom].addObject(layer, markerPoint);
+ }
+
+ //Didn't get in anything, add us to the top
+ this._topClusterLevel._addChild(layer);
+ layer.__parent = this._topClusterLevel;
+ return;
+ },
+
+ /**
+ * Refreshes the icon of all "dirty" visible clusters.
+ * Non-visible "dirty" clusters will be updated when they are added to the map.
+ * @private
+ */
+ _refreshClustersIcons: function () {
+ this._featureGroup.eachLayer(function (c) {
+ if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) {
+ c._updateIcon();
+ }
+ });
+ },
+
+ //Enqueue code to fire after the marker expand/contract has happened
+ _enqueue: function (fn) {
+ this._queue.push(fn);
+ if (!this._queueTimeout) {
+ this._queueTimeout = setTimeout(L.bind(this._processQueue, this), 300);
+ }
+ },
+ _processQueue: function () {
+ for (var i = 0; i < this._queue.length; i++) {
+ this._queue[i].call(this);
+ }
+ this._queue.length = 0;
+ clearTimeout(this._queueTimeout);
+ this._queueTimeout = null;
+ },
+
+ //Merge and split any existing clusters that are too big or small
+ _mergeSplitClusters: function () {
+ var mapZoom = Math.round(this._map._zoom);
+
+ //In case we are starting to split before the animation finished
+ this._processQueue();
+
+ if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { //Zoom in, split
+ this._animationStart();
+ //Remove clusters now off screen
+ this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, this._getExpandedVisibleBounds());
+
+ this._animationZoomIn(this._zoom, mapZoom);
+
+ } else if (this._zoom > mapZoom) { //Zoom out, merge
+ this._animationStart();
+
+ this._animationZoomOut(this._zoom, mapZoom);
+ } else {
+ this._moveEnd();
+ }
+ },
+
+ //Gets the maps visible bounds expanded in each direction by the size of the screen (so the user cannot see an area we do not cover in one pan)
+ _getExpandedVisibleBounds: function () {
+ if (!this.options.removeOutsideVisibleBounds) {
+ return this._mapBoundsInfinite;
+ } else if (L.Browser.mobile) {
+ return this._checkBoundsMaxLat(this._map.getBounds());
+ }
+
+ return this._checkBoundsMaxLat(this._map.getBounds().pad(1)); // Padding expands the bounds by its own dimensions but scaled with the given factor.
+ },
+
+ /**
+ * Expands the latitude to Infinity (or -Infinity) if the input bounds reach the map projection maximum defined latitude
+ * (in the case of Web/Spherical Mercator, it is 85.0511287798 / see https://en.wikipedia.org/wiki/Web_Mercator#Formulas).
+ * Otherwise, the removeOutsideVisibleBounds option will remove markers beyond that limit, whereas the same markers without
+ * this option (or outside MCG) will have their position floored (ceiled) by the projection and rendered at that limit,
+ * making the user think that MCG "eats" them and never displays them again.
+ * @param bounds L.LatLngBounds
+ * @returns {L.LatLngBounds}
+ * @private
+ */
+ _checkBoundsMaxLat: function (bounds) {
+ var maxLat = this._maxLat;
+
+ if (maxLat !== undefined) {
+ if (bounds.getNorth() >= maxLat) {
+ bounds._northEast.lat = Infinity;
+ }
+ if (bounds.getSouth() <= -maxLat) {
+ bounds._southWest.lat = -Infinity;
+ }
+ }
+
+ return bounds;
+ },
+
+ //Shared animation code
+ _animationAddLayerNonAnimated: function (layer, newCluster) {
+ if (newCluster === layer) {
+ this._featureGroup.addLayer(layer);
+ } else if (newCluster._childCount === 2) {
+ newCluster._addToMap();
+
+ var markers = newCluster.getAllChildMarkers();
+ this._featureGroup.removeLayer(markers[0]);
+ this._featureGroup.removeLayer(markers[1]);
+ } else {
+ newCluster._updateIcon();
+ }
+ },
+
+ /**
+ * Extracts individual (i.e. non-group) layers from a Layer Group.
+ * @param group to extract layers from.
+ * @param output {Array} in which to store the extracted layers.
+ * @returns {*|Array}
+ * @private
+ */
+ _extractNonGroupLayers: function (group, output) {
+ var layers = group.getLayers(),
+ i = 0,
+ layer;
+
+ output = output || [];
+
+ for (; i < layers.length; i++) {
+ layer = layers[i];
+
+ if (layer instanceof L.LayerGroup) {
+ this._extractNonGroupLayers(layer, output);
+ continue;
+ }
+
+ output.push(layer);
+ }
+
+ return output;
+ },
+
+ /**
+ * Implements the singleMarkerMode option.
+ * @param layer Marker to re-style using the Clusters iconCreateFunction.
+ * @returns {L.Icon} The newly created icon.
+ * @private
+ */
+ _overrideMarkerIcon: function (layer) {
+ var icon = layer.options.icon = this.options.iconCreateFunction({
+ getChildCount: function () {
+ return 1;
+ },
+ getAllChildMarkers: function () {
+ return [layer];
+ }
+ });
+
+ return icon;
+ }
+});
+
+// Constant bounds used in case option "removeOutsideVisibleBounds" is set to false.
+L.MarkerClusterGroup.include({
+ _mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.LatLng(Infinity, Infinity))
+});
+
+L.MarkerClusterGroup.include({
+ _noAnimation: {
+ //Non Animated versions of everything
+ _animationStart: function () {
+ //Do nothing...
+ },
+ _animationZoomIn: function (previousZoomLevel, newZoomLevel) {
+ this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel);
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
+
+ //We didn't actually animate, but we use this event to mean "clustering animations have finished"
+ this.fire('animationend');
+ },
+ _animationZoomOut: function (previousZoomLevel, newZoomLevel) {
+ this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel);
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
+
+ //We didn't actually animate, but we use this event to mean "clustering animations have finished"
+ this.fire('animationend');
+ },
+ _animationAddLayer: function (layer, newCluster) {
+ this._animationAddLayerNonAnimated(layer, newCluster);
+ }
+ },
+
+ _withAnimation: {
+ //Animated versions here
+ _animationStart: function () {
+ this._map._mapPane.className += ' leaflet-cluster-anim';
+ this._inZoomAnimation++;
+ },
+
+ _animationZoomIn: function (previousZoomLevel, newZoomLevel) {
+ var bounds = this._getExpandedVisibleBounds(),
+ fg = this._featureGroup,
+ minZoom = Math.floor(this._map.getMinZoom()),
+ i;
+
+ this._ignoreMove = true;
+
+ //Add all children of current clusters to map and remove those clusters from map
+ this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function (c) {
+ var startPos = c._latlng,
+ markers = c._markers,
+ m;
+
+ if (!bounds.contains(startPos)) {
+ startPos = null;
+ }
+
+ if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us
+ fg.removeLayer(c);
+ c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds);
+ } else {
+ //Fade out old cluster
+ c.clusterHide();
+ c._recursivelyAddChildrenToMap(startPos, newZoomLevel, bounds);
+ }
+
+ //Remove all markers that aren't visible any more
+ //TODO: Do we actually need to do this on the higher levels too?
+ for (i = markers.length - 1; i >= 0; i--) {
+ m = markers[i];
+ if (!bounds.contains(m._latlng)) {
+ fg.removeLayer(m);
+ }
+ }
+
+ });
+
+ this._forceLayout();
+
+ //Update opacities
+ this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel);
+ //TODO Maybe? Update markers in _recursivelyBecomeVisible
+ fg.eachLayer(function (n) {
+ if (!(n instanceof L.MarkerCluster) && n._icon) {
+ n.clusterShow();
+ }
+ });
+
+ //update the positions of the just added clusters/markers
+ this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) {
+ c._recursivelyRestoreChildPositions(newZoomLevel);
+ });
+
+ this._ignoreMove = false;
+
+ //Remove the old clusters and close the zoom animation
+ this._enqueue(function () {
+ //update the positions of the just added clusters/markers
+ this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function (c) {
+ fg.removeLayer(c);
+ c.clusterShow();
+ });
+
+ this._animationEnd();
+ });
+ },
+
+ _animationZoomOut: function (previousZoomLevel, newZoomLevel) {
+ this._animationZoomOutSingle(this._topClusterLevel, previousZoomLevel - 1, newZoomLevel);
+
+ //Need to add markers for those that weren't on the map before but are now
+ this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
+ //Remove markers that were on the map before but won't be now
+ this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel, this._getExpandedVisibleBounds());
+ },
+
+ _animationAddLayer: function (layer, newCluster) {
+ var me = this,
+ fg = this._featureGroup;
+
+ fg.addLayer(layer);
+ if (newCluster !== layer) {
+ if (newCluster._childCount > 2) { //Was already a cluster
+
+ newCluster._updateIcon();
+ this._forceLayout();
+ this._animationStart();
+
+ layer._setPos(this._map.latLngToLayerPoint(newCluster.getLatLng()));
+ layer.clusterHide();
+
+ this._enqueue(function () {
+ fg.removeLayer(layer);
+ layer.clusterShow();
+
+ me._animationEnd();
+ });
+
+ } else { //Just became a cluster
+ this._forceLayout();
+
+ me._animationStart();
+ me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._zoom);
+ }
+ }
+ }
+ },
+
+ // Private methods for animated versions.
+ _animationZoomOutSingle: function (cluster, previousZoomLevel, newZoomLevel) {
+ var bounds = this._getExpandedVisibleBounds(),
+ minZoom = Math.floor(this._map.getMinZoom());
+
+ //Animate all of the markers in the clusters to move to their cluster center point
+ cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, minZoom, previousZoomLevel + 1, newZoomLevel);
+
+ var me = this;
+
+ //Update the opacity (If we immediately set it they won't animate)
+ this._forceLayout();
+ cluster._recursivelyBecomeVisible(bounds, newZoomLevel);
+
+ //TODO: Maybe use the transition timing stuff to make this more reliable
+ //When the animations are done, tidy up
+ this._enqueue(function () {
+
+ //This cluster stopped being a cluster before the timeout fired
+ if (cluster._childCount === 1) {
+ var m = cluster._markers[0];
+ //If we were in a cluster animation at the time then the opacity and position of our child could be wrong now, so fix it
+ this._ignoreMove = true;
+ m.setLatLng(m.getLatLng());
+ this._ignoreMove = false;
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+ } else {
+ cluster._recursively(bounds, newZoomLevel, minZoom, function (c) {
+ c._recursivelyRemoveChildrenFromMap(bounds, minZoom, previousZoomLevel + 1);
+ });
+ }
+ me._animationEnd();
+ });
+ },
+
+ _animationEnd: function () {
+ if (this._map) {
+ this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '');
+ }
+ this._inZoomAnimation--;
+ this.fire('animationend');
+ },
+
+ //Force a browser layout of stuff in the map
+ // Should apply the current opacity and location to all elements so we can update them again for an animation
+ _forceLayout: function () {
+ //In my testing this works, infact offsetWidth of any element seems to work.
+ //Could loop all this._layers and do this for each _icon if it stops working
+
+ L.Util.falseFn(document.body.offsetWidth);
+ }
+});
+
+L.markerClusterGroup = function (options) {
+ return new L.MarkerClusterGroup(options);
+};
+
+
+L.MarkerCluster = L.Marker.extend({
+ initialize: function (group, zoom, a, b) {
+
+ L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0),
+ { icon: this, pane: group.options.clusterPane });
+
+ this._group = group;
+ this._zoom = zoom;
+
+ this._markers = [];
+ this._childClusters = [];
+ this._childCount = 0;
+ this._iconNeedsUpdate = true;
+ this._boundsNeedUpdate = true;
+
+ this._bounds = new L.LatLngBounds();
+
+ if (a) {
+ this._addChild(a);
+ }
+ if (b) {
+ this._addChild(b);
+ }
+ },
+
+ //Recursively retrieve all child markers of this cluster
+ getAllChildMarkers: function (storageArray) {
+ storageArray = storageArray || [];
+
+ for (var i = this._childClusters.length - 1; i >= 0; i--) {
+ this._childClusters[i].getAllChildMarkers(storageArray);
+ }
+
+ for (var j = this._markers.length - 1; j >= 0; j--) {
+ storageArray.push(this._markers[j]);
+ }
+
+ return storageArray;
+ },
+
+ //Returns the count of how many child markers we have
+ getChildCount: function () {
+ return this._childCount;
+ },
+
+ //Zoom to the minimum of showing all of the child markers, or the extents of this cluster
+ zoomToBounds: function (fitBoundsOptions) {
+ var childClusters = this._childClusters.slice(),
+ map = this._group._map,
+ boundsZoom = map.getBoundsZoom(this._bounds),
+ zoom = this._zoom + 1,
+ mapZoom = map.getZoom(),
+ i;
+
+ //calculate how far we need to zoom down to see all of the markers
+ while (childClusters.length > 0 && boundsZoom > zoom) {
+ zoom++;
+ var newClusters = [];
+ for (i = 0; i < childClusters.length; i++) {
+ newClusters = newClusters.concat(childClusters[i]._childClusters);
+ }
+ childClusters = newClusters;
+ }
+
+ if (boundsZoom > zoom) {
+ this._group._map.setView(this._latlng, zoom);
+ } else if (boundsZoom <= mapZoom) { //If fitBounds wouldn't zoom us down, zoom us down instead
+ this._group._map.setView(this._latlng, mapZoom + 1);
+ } else {
+ this._group._map.fitBounds(this._bounds, fitBoundsOptions);
+ }
+ },
+
+ getBounds: function () {
+ var bounds = new L.LatLngBounds();
+ bounds.extend(this._bounds);
+ return bounds;
+ },
+
+ _updateIcon: function () {
+ this._iconNeedsUpdate = true;
+ if (this._icon) {
+ this.setIcon(this);
+ }
+ },
+
+ //Cludge for Icon, we pretend to be an icon for performance
+ createIcon: function () {
+ if (this._iconNeedsUpdate) {
+ this._iconObj = this._group.options.iconCreateFunction(this);
+ this._iconNeedsUpdate = false;
+ }
+ return this._iconObj.createIcon();
+ },
+ createShadow: function () {
+ return this._iconObj.createShadow();
+ },
+
+
+ _addChild: function (new1, isNotificationFromChild) {
+
+ this._iconNeedsUpdate = true;
+
+ this._boundsNeedUpdate = true;
+ this._setClusterCenter(new1);
+
+ if (new1 instanceof L.MarkerCluster) {
+ if (!isNotificationFromChild) {
+ this._childClusters.push(new1);
+ new1.__parent = this;
+ }
+ this._childCount += new1._childCount;
+ } else {
+ if (!isNotificationFromChild) {
+ this._markers.push(new1);
+ }
+ this._childCount++;
+ }
+
+ if (this.__parent) {
+ this.__parent._addChild(new1, true);
+ }
+ },
+
+ /**
+ * Makes sure the cluster center is set. If not, uses the child center if it is a cluster, or the marker position.
+ * @param child L.MarkerCluster|L.Marker that will be used as cluster center if not defined yet.
+ * @private
+ */
+ _setClusterCenter: function (child) {
+ if (!this._cLatLng) {
+ // when clustering, take position of the first point as the cluster center
+ this._cLatLng = child._cLatLng || child._latlng;
+ }
+ },
+
+ /**
+ * Assigns impossible bounding values so that the next extend entirely determines the new bounds.
+ * This method avoids having to trash the previous L.LatLngBounds object and to create a new one, which is much slower for this class.
+ * As long as the bounds are not extended, most other methods would probably fail, as they would with bounds initialized but not extended.
+ * @private
+ */
+ _resetBounds: function () {
+ var bounds = this._bounds;
+
+ if (bounds._southWest) {
+ bounds._southWest.lat = Infinity;
+ bounds._southWest.lng = Infinity;
+ }
+ if (bounds._northEast) {
+ bounds._northEast.lat = -Infinity;
+ bounds._northEast.lng = -Infinity;
+ }
+ },
+
+ _recalculateBounds: function () {
+ var markers = this._markers,
+ childClusters = this._childClusters,
+ latSum = 0,
+ lngSum = 0,
+ totalCount = this._childCount,
+ i, child, childLatLng, childCount;
+
+ // Case where all markers are removed from the map and we are left with just an empty _topClusterLevel.
+ if (totalCount === 0) {
+ return;
+ }
+
+ // Reset rather than creating a new object, for performance.
+ this._resetBounds();
+
+ // Child markers.
+ for (i = 0; i < markers.length; i++) {
+ childLatLng = markers[i]._latlng;
+
+ this._bounds.extend(childLatLng);
+
+ latSum += childLatLng.lat;
+ lngSum += childLatLng.lng;
+ }
+
+ // Child clusters.
+ for (i = 0; i < childClusters.length; i++) {
+ child = childClusters[i];
+
+ // Re-compute child bounds and weighted position first if necessary.
+ if (child._boundsNeedUpdate) {
+ child._recalculateBounds();
+ }
+
+ this._bounds.extend(child._bounds);
+
+ childLatLng = child._wLatLng;
+ childCount = child._childCount;
+
+ latSum += childLatLng.lat * childCount;
+ lngSum += childLatLng.lng * childCount;
+ }
+
+ this._latlng = this._wLatLng = new L.LatLng(latSum / totalCount, lngSum / totalCount);
+
+ // Reset dirty flag.
+ this._boundsNeedUpdate = false;
+ },
+
+ //Set our markers position as given and add it to the map
+ _addToMap: function (startPos) {
+ if (startPos) {
+ this._backupLatlng = this._latlng;
+ this.setLatLng(startPos);
+ }
+ this._group._featureGroup.addLayer(this);
+ },
+
+ _recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) {
+ this._recursively(bounds, this._group._map.getMinZoom(), maxZoom - 1,
+ function (c) {
+ var markers = c._markers,
+ i, m;
+ for (i = markers.length - 1; i >= 0; i--) {
+ m = markers[i];
+
+ //Only do it if the icon is still on the map
+ if (m._icon) {
+ m._setPos(center);
+ m.clusterHide();
+ }
+ }
+ },
+ function (c) {
+ var childClusters = c._childClusters,
+ j, cm;
+ for (j = childClusters.length - 1; j >= 0; j--) {
+ cm = childClusters[j];
+ if (cm._icon) {
+ cm._setPos(center);
+ cm.clusterHide();
+ }
+ }
+ }
+ );
+ },
+
+ _recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, mapMinZoom, previousZoomLevel, newZoomLevel) {
+ this._recursively(bounds, newZoomLevel, mapMinZoom,
+ function (c) {
+ c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), previousZoomLevel);
+
+ //TODO: depthToAnimateIn affects _isSingleParent, if there is a multizoom we may/may not be.
+ //As a hack we only do a animation free zoom on a single level zoom, if someone does multiple levels then we always animate
+ if (c._isSingleParent() && previousZoomLevel - 1 === newZoomLevel) {
+ c.clusterShow();
+ c._recursivelyRemoveChildrenFromMap(bounds, mapMinZoom, previousZoomLevel); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds
+ } else {
+ c.clusterHide();
+ }
+
+ c._addToMap();
+ }
+ );
+ },
+
+ _recursivelyBecomeVisible: function (bounds, zoomLevel) {
+ this._recursively(bounds, this._group._map.getMinZoom(), zoomLevel, null, function (c) {
+ c.clusterShow();
+ });
+ },
+
+ _recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) {
+ this._recursively(bounds, this._group._map.getMinZoom() - 1, zoomLevel,
+ function (c) {
+ if (zoomLevel === c._zoom) {
+ return;
+ }
+
+ //Add our child markers at startPos (so they can be animated out)
+ for (var i = c._markers.length - 1; i >= 0; i--) {
+ var nm = c._markers[i];
+
+ if (!bounds.contains(nm._latlng)) {
+ continue;
+ }
+
+ if (startPos) {
+ nm._backupLatlng = nm.getLatLng();
+
+ nm.setLatLng(startPos);
+ if (nm.clusterHide) {
+ nm.clusterHide();
+ }
+ }
+
+ c._group._featureGroup.addLayer(nm);
+ }
+ },
+ function (c) {
+ c._addToMap(startPos);
+ }
+ );
+ },
+
+ _recursivelyRestoreChildPositions: function (zoomLevel) {
+ //Fix positions of child markers
+ for (var i = this._markers.length - 1; i >= 0; i--) {
+ var nm = this._markers[i];
+ if (nm._backupLatlng) {
+ nm.setLatLng(nm._backupLatlng);
+ delete nm._backupLatlng;
+ }
+ }
+
+ if (zoomLevel - 1 === this._zoom) {
+ //Reposition child clusters
+ for (var j = this._childClusters.length - 1; j >= 0; j--) {
+ this._childClusters[j]._restorePosition();
+ }
+ } else {
+ for (var k = this._childClusters.length - 1; k >= 0; k--) {
+ this._childClusters[k]._recursivelyRestoreChildPositions(zoomLevel);
+ }
+ }
+ },
+
+ _restorePosition: function () {
+ if (this._backupLatlng) {
+ this.setLatLng(this._backupLatlng);
+ delete this._backupLatlng;
+ }
+ },
+
+ //exceptBounds: If set, don't remove any markers/clusters in it
+ _recursivelyRemoveChildrenFromMap: function (previousBounds, mapMinZoom, zoomLevel, exceptBounds) {
+ var m, i;
+ this._recursively(previousBounds, mapMinZoom - 1, zoomLevel - 1,
+ function (c) {
+ //Remove markers at every level
+ for (i = c._markers.length - 1; i >= 0; i--) {
+ m = c._markers[i];
+ if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
+ c._group._featureGroup.removeLayer(m);
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+ }
+ }
+ },
+ function (c) {
+ //Remove child clusters at just the bottom level
+ for (i = c._childClusters.length - 1; i >= 0; i--) {
+ m = c._childClusters[i];
+ if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
+ c._group._featureGroup.removeLayer(m);
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+ }
+ }
+ }
+ );
+ },
+
+ //Run the given functions recursively to this and child clusters
+ // boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to
+ // zoomLevelToStart: zoom level to start running functions (inclusive)
+ // zoomLevelToStop: zoom level to stop running functions (inclusive)
+ // runAtEveryLevel: function that takes an L.MarkerCluster as an argument that should be applied on every level
+ // runAtBottomLevel: function that takes an L.MarkerCluster as an argument that should be applied at only the bottom level
+ _recursively: function (boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) {
+ var childClusters = this._childClusters,
+ zoom = this._zoom,
+ i, c;
+
+ if (zoomLevelToStart <= zoom) {
+ if (runAtEveryLevel) {
+ runAtEveryLevel(this);
+ }
+ if (runAtBottomLevel && zoom === zoomLevelToStop) {
+ runAtBottomLevel(this);
+ }
+ }
+
+ if (zoom < zoomLevelToStart || zoom < zoomLevelToStop) {
+ for (i = childClusters.length - 1; i >= 0; i--) {
+ c = childClusters[i];
+ if (boundsToApplyTo.intersects(c._bounds)) {
+ c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel);
+ }
+ }
+ }
+ },
+
+ //Returns true if we are the parent of only one cluster and that cluster is the same as us
+ _isSingleParent: function () {
+ //Don't need to check this._markers as the rest won't work if there are any
+ return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount;
+ }
+});
+
+
+
+/*
+* Extends L.Marker to include two extra methods: clusterHide and clusterShow.
+*
+* They work as setOpacity(0) and setOpacity(1) respectively, but
+* they will remember the marker's opacity when hiding and showing it again.
+*
+*/
+
+
+L.Marker.include({
+
+ clusterHide: function () {
+ this.options.opacityWhenUnclustered = this.options.opacity || 1;
+ return this.setOpacity(0);
+ },
+
+ clusterShow: function () {
+ var ret = this.setOpacity(this.options.opacity || this.options.opacityWhenUnclustered);
+ delete this.options.opacityWhenUnclustered;
+ return ret;
+ }
+
+});
+
+
+
+
+
+L.DistanceGrid = function (cellSize) {
+ this._cellSize = cellSize;
+ this._sqCellSize = cellSize * cellSize;
+ this._grid = {};
+ this._objectPoint = { };
+};
+
+L.DistanceGrid.prototype = {
+
+ addObject: function (obj, point) {
+ var x = this._getCoord(point.x),
+ y = this._getCoord(point.y),
+ grid = this._grid,
+ row = grid[y] = grid[y] || {},
+ cell = row[x] = row[x] || [],
+ stamp = L.Util.stamp(obj);
+
+ this._objectPoint[stamp] = point;
+
+ cell.push(obj);
+ },
+
+ updateObject: function (obj, point) {
+ this.removeObject(obj);
+ this.addObject(obj, point);
+ },
+
+ //Returns true if the object was found
+ removeObject: function (obj, point) {
+ var x = this._getCoord(point.x),
+ y = this._getCoord(point.y),
+ grid = this._grid,
+ row = grid[y] = grid[y] || {},
+ cell = row[x] = row[x] || [],
+ i, len;
+
+ delete this._objectPoint[L.Util.stamp(obj)];
+
+ for (i = 0, len = cell.length; i < len; i++) {
+ if (cell[i] === obj) {
+
+ cell.splice(i, 1);
+
+ if (len === 1) {
+ delete row[x];
+ }
+
+ return true;
+ }
+ }
+
+ },
+
+ eachObject: function (fn, context) {
+ var i, j, k, len, row, cell, removed,
+ grid = this._grid;
+
+ for (i in grid) {
+ row = grid[i];
+
+ for (j in row) {
+ cell = row[j];
+
+ for (k = 0, len = cell.length; k < len; k++) {
+ removed = fn.call(context, cell[k]);
+ if (removed) {
+ k--;
+ len--;
+ }
+ }
+ }
+ }
+ },
+
+ getNearObject: function (point) {
+ var x = this._getCoord(point.x),
+ y = this._getCoord(point.y),
+ i, j, k, row, cell, len, obj, dist,
+ objectPoint = this._objectPoint,
+ closestDistSq = this._sqCellSize,
+ closest = null;
+
+ for (i = y - 1; i <= y + 1; i++) {
+ row = this._grid[i];
+ if (row) {
+
+ for (j = x - 1; j <= x + 1; j++) {
+ cell = row[j];
+ if (cell) {
+
+ for (k = 0, len = cell.length; k < len; k++) {
+ obj = cell[k];
+ dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point);
+ if (dist < closestDistSq ||
+ dist <= closestDistSq && closest === null) {
+ closestDistSq = dist;
+ closest = obj;
+ }
+ }
+ }
+ }
+ }
+ }
+ return closest;
+ },
+
+ _getCoord: function (x) {
+ var coord = Math.floor(x / this._cellSize);
+ return isFinite(coord) ? coord : x;
+ },
+
+ _sqDist: function (p, p2) {
+ var dx = p2.x - p.x,
+ dy = p2.y - p.y;
+ return dx * dx + dy * dy;
+ }
+};
+
+
+/* Copyright (c) 2012 the authors listed at the following URL, and/or
+the authors of referenced articles or incorporated external code:
+http://en.literateprograms.org/Quickhull_(Javascript)?action=history&offset=20120410175256
+
+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.
+
+Retrieved from: http://en.literateprograms.org/Quickhull_(Javascript)?oldid=18434
+*/
+
+(function () {
+ L.QuickHull = {
+
+ /*
+ * @param {Object} cpt a point to be measured from the baseline
+ * @param {Array} bl the baseline, as represented by a two-element
+ * array of latlng objects.
+ * @returns {Number} an approximate distance measure
+ */
+ getDistant: function (cpt, bl) {
+ var vY = bl[1].lat - bl[0].lat,
+ vX = bl[0].lng - bl[1].lng;
+ return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng));
+ },
+
+ /*
+ * @param {Array} baseLine a two-element array of latlng objects
+ * representing the baseline to project from
+ * @param {Array} latLngs an array of latlng objects
+ * @returns {Object} the maximum point and all new points to stay
+ * in consideration for the hull.
+ */
+ findMostDistantPointFromBaseLine: function (baseLine, latLngs) {
+ var maxD = 0,
+ maxPt = null,
+ newPoints = [],
+ i, pt, d;
+
+ for (i = latLngs.length - 1; i >= 0; i--) {
+ pt = latLngs[i];
+ d = this.getDistant(pt, baseLine);
+
+ if (d > 0) {
+ newPoints.push(pt);
+ } else {
+ continue;
+ }
+
+ if (d > maxD) {
+ maxD = d;
+ maxPt = pt;
+ }
+ }
+
+ return { maxPoint: maxPt, newPoints: newPoints };
+ },
+
+
+ /*
+ * Given a baseline, compute the convex hull of latLngs as an array
+ * of latLngs.
+ *
+ * @param {Array} latLngs
+ * @returns {Array}
+ */
+ buildConvexHull: function (baseLine, latLngs) {
+ var convexHullBaseLines = [],
+ t = this.findMostDistantPointFromBaseLine(baseLine, latLngs);
+
+ if (t.maxPoint) { // if there is still a point "outside" the base line
+ convexHullBaseLines =
+ convexHullBaseLines.concat(
+ this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints)
+ );
+ convexHullBaseLines =
+ convexHullBaseLines.concat(
+ this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints)
+ );
+ return convexHullBaseLines;
+ } else { // if there is no more point "outside" the base line, the current base line is part of the convex hull
+ return [baseLine[0]];
+ }
+ },
+
+ /*
+ * Given an array of latlngs, compute a convex hull as an array
+ * of latlngs
+ *
+ * @param {Array} latLngs
+ * @returns {Array}
+ */
+ getConvexHull: function (latLngs) {
+ // find first baseline
+ var maxLat = false, minLat = false,
+ maxLng = false, minLng = false,
+ maxLatPt = null, minLatPt = null,
+ maxLngPt = null, minLngPt = null,
+ maxPt = null, minPt = null,
+ i;
+
+ for (i = latLngs.length - 1; i >= 0; i--) {
+ var pt = latLngs[i];
+ if (maxLat === false || pt.lat > maxLat) {
+ maxLatPt = pt;
+ maxLat = pt.lat;
+ }
+ if (minLat === false || pt.lat < minLat) {
+ minLatPt = pt;
+ minLat = pt.lat;
+ }
+ if (maxLng === false || pt.lng > maxLng) {
+ maxLngPt = pt;
+ maxLng = pt.lng;
+ }
+ if (minLng === false || pt.lng < minLng) {
+ minLngPt = pt;
+ minLng = pt.lng;
+ }
+ }
+
+ if (minLat !== maxLat) {
+ minPt = minLatPt;
+ maxPt = maxLatPt;
+ } else {
+ minPt = minLngPt;
+ maxPt = maxLngPt;
+ }
+
+ var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs),
+ this.buildConvexHull([maxPt, minPt], latLngs));
+ return ch;
+ }
+ };
+}());
+
+L.MarkerCluster.include({
+ getConvexHull: function () {
+ var childMarkers = this.getAllChildMarkers(),
+ points = [],
+ p, i;
+
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ p = childMarkers[i].getLatLng();
+ points.push(p);
+ }
+
+ return L.QuickHull.getConvexHull(points);
+ }
+});
+
+
+//This code is 100% based on https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet
+//Huge thanks to jawj for implementing it first to make my job easy :-)
+
+L.MarkerCluster.include({
+
+ _2PI: Math.PI * 2,
+ _circleFootSeparation: 25, //related to circumference of circle
+ _circleStartAngle: Math.PI / 6,
+
+ _spiralFootSeparation: 28, //related to size of spiral (experiment!)
+ _spiralLengthStart: 11,
+ _spiralLengthFactor: 5,
+
+ _circleSpiralSwitchover: 9, //show spiral instead of circle from this marker count upwards.
+ // 0 -> always spiral; Infinity -> always circle
+
+ spiderfy: function () {
+ if (this._group._spiderfied === this || this._group._inZoomAnimation) {
+ return;
+ }
+
+ var childMarkers = this.getAllChildMarkers(),
+ group = this._group,
+ map = group._map,
+ center = map.latLngToLayerPoint(this._latlng),
+ positions;
+
+ this._group._unspiderfy();
+ this._group._spiderfied = this;
+
+ //TODO Maybe: childMarkers order by distance to center
+
+ if (childMarkers.length >= this._circleSpiralSwitchover) {
+ positions = this._generatePointsSpiral(childMarkers.length, center);
+ } else {
+ center.y += 10; // Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons.
+ positions = this._generatePointsCircle(childMarkers.length, center);
+ }
+
+ this._animationSpiderfy(childMarkers, positions);
+ },
+
+ unspiderfy: function (zoomDetails) {
+ /// <param Name="zoomDetails">Argument from zoomanim if being called in a zoom animation or null otherwise</param>
+ if (this._group._inZoomAnimation) {
+ return;
+ }
+ this._animationUnspiderfy(zoomDetails);
+
+ this._group._spiderfied = null;
+ },
+
+ _generatePointsCircle: function (count, centerPt) {
+ var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count),
+ legLength = circumference / this._2PI, //radius from circumference
+ angleStep = this._2PI / count,
+ res = [],
+ i, angle;
+
+ res.length = count;
+
+ for (i = count - 1; i >= 0; i--) {
+ angle = this._circleStartAngle + i * angleStep;
+ res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round();
+ }
+
+ return res;
+ },
+
+ _generatePointsSpiral: function (count, centerPt) {
+ var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier,
+ legLength = spiderfyDistanceMultiplier * this._spiralLengthStart,
+ separation = spiderfyDistanceMultiplier * this._spiralFootSeparation,
+ lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI,
+ angle = 0,
+ res = [],
+ i;
+
+ res.length = count;
+
+ // Higher index, closer position to cluster center.
+ for (i = count - 1; i >= 0; i--) {
+ angle += separation / legLength + i * 0.0005;
+ res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round();
+ legLength += lengthFactor / angle;
+ }
+ return res;
+ },
+
+ _noanimationUnspiderfy: function () {
+ var group = this._group,
+ map = group._map,
+ fg = group._featureGroup,
+ childMarkers = this.getAllChildMarkers(),
+ m, i;
+
+ group._ignoreMove = true;
+
+ this.setOpacity(1);
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ m = childMarkers[i];
+
+ fg.removeLayer(m);
+
+ if (m._preSpiderfyLatlng) {
+ m.setLatLng(m._preSpiderfyLatlng);
+ delete m._preSpiderfyLatlng;
+ }
+ if (m.setZIndexOffset) {
+ m.setZIndexOffset(0);
+ }
+
+ if (m._spiderLeg) {
+ map.removeLayer(m._spiderLeg);
+ delete m._spiderLeg;
+ }
+ }
+
+ group.fire('unspiderfied', {
+ cluster: this,
+ markers: childMarkers
+ });
+ group._ignoreMove = false;
+ group._spiderfied = null;
+ }
+});
+
+//Non Animated versions of everything
+L.MarkerClusterNonAnimated = L.MarkerCluster.extend({
+ _animationSpiderfy: function (childMarkers, positions) {
+ var group = this._group,
+ map = group._map,
+ fg = group._featureGroup,
+ legOptions = this._group.options.spiderLegPolylineOptions,
+ i, m, leg, newPos;
+
+ group._ignoreMove = true;
+
+ // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
+ // The reverse order trick no longer improves performance on modern browsers.
+ for (i = 0; i < childMarkers.length; i++) {
+ newPos = map.layerPointToLatLng(positions[i]);
+ m = childMarkers[i];
+
+ // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
+ leg = new L.Polyline([this._latlng, newPos], legOptions);
+ map.addLayer(leg);
+ m._spiderLeg = leg;
+
+ // Now add the marker.
+ m._preSpiderfyLatlng = m._latlng;
+ m.setLatLng(newPos);
+ if (m.setZIndexOffset) {
+ m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
+ }
+
+ fg.addLayer(m);
+ }
+ this.setOpacity(0.3);
+
+ group._ignoreMove = false;
+ group.fire('spiderfied', {
+ cluster: this,
+ markers: childMarkers
+ });
+ },
+
+ _animationUnspiderfy: function () {
+ this._noanimationUnspiderfy();
+ }
+});
+
+//Animated versions here
+L.MarkerCluster.include({
+
+ _animationSpiderfy: function (childMarkers, positions) {
+ var me = this,
+ group = this._group,
+ map = group._map,
+ fg = group._featureGroup,
+ thisLayerLatLng = this._latlng,
+ thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng),
+ svg = L.Path.SVG,
+ legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions), // Copy the options so that we can modify them for animation.
+ finalLegOpacity = legOptions.opacity,
+ i, m, leg, legPath, legLength, newPos;
+
+ if (finalLegOpacity === undefined) {
+ finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity;
+ }
+
+ if (svg) {
+ // If the initial opacity of the spider leg is not 0 then it appears before the animation starts.
+ legOptions.opacity = 0;
+
+ // Add the class for CSS transitions.
+ legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg';
+ } else {
+ // Make sure we have a defined opacity.
+ legOptions.opacity = finalLegOpacity;
+ }
+
+ group._ignoreMove = true;
+
+ // Add markers and spider legs to map, hidden at our center point.
+ // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
+ // The reverse order trick no longer improves performance on modern browsers.
+ for (i = 0; i < childMarkers.length; i++) {
+ m = childMarkers[i];
+
+ newPos = map.layerPointToLatLng(positions[i]);
+
+ // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
+ leg = new L.Polyline([thisLayerLatLng, newPos], legOptions);
+ map.addLayer(leg);
+ m._spiderLeg = leg;
+
+ // Explanations: https://jakearchibald.com/2013/animated-line-drawing-svg/
+ // In our case the transition property is declared in the CSS file.
+ if (svg) {
+ legPath = leg._path;
+ legLength = legPath.getTotalLength() + 0.1; // Need a small extra length to avoid remaining dot in Firefox.
+ legPath.style.strokeDasharray = legLength; // Just 1 length is enough, it will be duplicated.
+ legPath.style.strokeDashoffset = legLength;
+ }
+
+ // If it is a marker, add it now and we'll animate it out
+ if (m.setZIndexOffset) {
+ m.setZIndexOffset(1000000); // Make normal markers appear on top of EVERYTHING
+ }
+ if (m.clusterHide) {
+ m.clusterHide();
+ }
+
+ // Vectors just get immediately added
+ fg.addLayer(m);
+
+ if (m._setPos) {
+ m._setPos(thisLayerPos);
+ }
+ }
+
+ group._forceLayout();
+ group._animationStart();
+
+ // Reveal markers and spider legs.
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ newPos = map.layerPointToLatLng(positions[i]);
+ m = childMarkers[i];
+
+ //Move marker to new position
+ m._preSpiderfyLatlng = m._latlng;
+ m.setLatLng(newPos);
+
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+
+ // Animate leg (animation is actually delegated to CSS transition).
+ if (svg) {
+ leg = m._spiderLeg;
+ legPath = leg._path;
+ legPath.style.strokeDashoffset = 0;
+ //legPath.style.strokeOpacity = finalLegOpacity;
+ leg.setStyle({opacity: finalLegOpacity});
+ }
+ }
+ this.setOpacity(0.3);
+
+ group._ignoreMove = false;
+
+ setTimeout(function () {
+ group._animationEnd();
+ group.fire('spiderfied', {
+ cluster: me,
+ markers: childMarkers
+ });
+ }, 200);
+ },
+
+ _animationUnspiderfy: function (zoomDetails) {
+ var me = this,
+ group = this._group,
+ map = group._map,
+ fg = group._featureGroup,
+ thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng),
+ childMarkers = this.getAllChildMarkers(),
+ svg = L.Path.SVG,
+ m, i, leg, legPath, legLength, nonAnimatable;
+
+ group._ignoreMove = true;
+ group._animationStart();
+
+ //Make us visible and bring the child markers back in
+ this.setOpacity(1);
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ m = childMarkers[i];
+
+ //Marker was added to us after we were spiderfied
+ if (!m._preSpiderfyLatlng) {
+ continue;
+ }
+
+ //Close any popup on the marker first, otherwise setting the location of the marker will make the map scroll
+ m.closePopup();
+
+ //Fix up the location to the real one
+ m.setLatLng(m._preSpiderfyLatlng);
+ delete m._preSpiderfyLatlng;
+
+ //Hack override the location to be our center
+ nonAnimatable = true;
+ if (m._setPos) {
+ m._setPos(thisLayerPos);
+ nonAnimatable = false;
+ }
+ if (m.clusterHide) {
+ m.clusterHide();
+ nonAnimatable = false;
+ }
+ if (nonAnimatable) {
+ fg.removeLayer(m);
+ }
+
+ // Animate the spider leg back in (animation is actually delegated to CSS transition).
+ if (svg) {
+ leg = m._spiderLeg;
+ legPath = leg._path;
+ legLength = legPath.getTotalLength() + 0.1;
+ legPath.style.strokeDashoffset = legLength;
+ leg.setStyle({opacity: 0});
+ }
+ }
+
+ group._ignoreMove = false;
+
+ setTimeout(function () {
+ //If we have only <= one child left then that marker will be shown on the map so don't remove it!
+ var stillThereChildCount = 0;
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ m = childMarkers[i];
+ if (m._spiderLeg) {
+ stillThereChildCount++;
+ }
+ }
+
+
+ for (i = childMarkers.length - 1; i >= 0; i--) {
+ m = childMarkers[i];
+
+ if (!m._spiderLeg) { //Has already been unspiderfied
+ continue;
+ }
+
+ if (m.clusterShow) {
+ m.clusterShow();
+ }
+ if (m.setZIndexOffset) {
+ m.setZIndexOffset(0);
+ }
+
+ if (stillThereChildCount > 1) {
+ fg.removeLayer(m);
+ }
+
+ map.removeLayer(m._spiderLeg);
+ delete m._spiderLeg;
+ }
+ group._animationEnd();
+ group.fire('unspiderfied', {
+ cluster: me,
+ markers: childMarkers
+ });
+ }, 200);
+ }
+});
+
+
+L.MarkerClusterGroup.include({
+ //The MarkerCluster currently spiderfied (if any)
+ _spiderfied: null,
+
+ unspiderfy: function () {
+ this._unspiderfy.apply(this, arguments);
+ },
+
+ _spiderfierOnAdd: function () {
+ this._map.on('click', this._unspiderfyWrapper, this);
+
+ if (this._map.options.zoomAnimation) {
+ this._map.on('zoomstart', this._unspiderfyZoomStart, this);
+ }
+ //Browsers without zoomAnimation or a big zoom don't fire zoomstart
+ this._map.on('zoomend', this._noanimationUnspiderfy, this);
+
+ if (!L.Browser.touch) {
+ this._map.getRenderer(this);
+ //Needs to happen in the pageload, not after, or animations don't work in webkit
+ // http://stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements
+ //Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable
+ }
+ },
+
+ _spiderfierOnRemove: function () {
+ this._map.off('click', this._unspiderfyWrapper, this);
+ this._map.off('zoomstart', this._unspiderfyZoomStart, this);
+ this._map.off('zoomanim', this._unspiderfyZoomAnim, this);
+ this._map.off('zoomend', this._noanimationUnspiderfy, this);
+
+ //Ensure that markers are back where they should be
+ // Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane
+ this._noanimationUnspiderfy();
+ },
+
+ //On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated)
+ //This means we can define the animation they do rather than Markers doing an animation to their actual location
+ _unspiderfyZoomStart: function () {
+ if (!this._map) { //May have been removed from the map by a zoomEnd handler
+ return;
+ }
+
+ this._map.on('zoomanim', this._unspiderfyZoomAnim, this);
+ },
+
+ _unspiderfyZoomAnim: function (zoomDetails) {
+ //Wait until the first zoomanim after the user has finished touch-zooming before running the animation
+ if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) {
+ return;
+ }
+
+ this._map.off('zoomanim', this._unspiderfyZoomAnim, this);
+ this._unspiderfy(zoomDetails);
+ },
+
+ _unspiderfyWrapper: function () {
+ /// <summary>_unspiderfy but passes no arguments</summary>
+ this._unspiderfy();
+ },
+
+ _unspiderfy: function (zoomDetails) {
+ if (this._spiderfied) {
+ this._spiderfied.unspiderfy(zoomDetails);
+ }
+ },
+
+ _noanimationUnspiderfy: function () {
+ if (this._spiderfied) {
+ this._spiderfied._noanimationUnspiderfy();
+ }
+ },
+
+ //If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc
+ _unspiderfyLayer: function (layer) {
+ if (layer._spiderLeg) {
+ this._featureGroup.removeLayer(layer);
+
+ if (layer.clusterShow) {
+ layer.clusterShow();
+ }
+ //Position will be fixed up immediately in _animationUnspiderfy
+ if (layer.setZIndexOffset) {
+ layer.setZIndexOffset(0);
+ }
+
+ this._map.removeLayer(layer._spiderLeg);
+ delete layer._spiderLeg;
+ }
+ }
+});
+
+
+/**
+ * Adds 1 public method to MCG and 1 to L.Marker to facilitate changing
+ * markers' icon options and refreshing their icon and their parent clusters
+ * accordingly (case where their iconCreateFunction uses data of childMarkers
+ * to make up the cluster icon).
+ */
+
+
+L.MarkerClusterGroup.include({
+ /**
+ * Updates the icon of all clusters which are parents of the given marker(s).
+ * In singleMarkerMode, also updates the given marker(s) icon.
+ * @param layers L.MarkerClusterGroup|L.LayerGroup|Array(L.Marker)|Map(L.Marker)|
+ * L.MarkerCluster|L.Marker (optional) list of markers (or single marker) whose parent
+ * clusters need to be updated. If not provided, retrieves all child markers of this.
+ * @returns {L.MarkerClusterGroup}
+ */
+ refreshClusters: function (layers) {
+ if (!layers) {
+ layers = this._topClusterLevel.getAllChildMarkers();
+ } else if (layers instanceof L.MarkerClusterGroup) {
+ layers = layers._topClusterLevel.getAllChildMarkers();
+ } else if (layers instanceof L.LayerGroup) {
+ layers = layers._layers;
+ } else if (layers instanceof L.MarkerCluster) {
+ layers = layers.getAllChildMarkers();
+ } else if (layers instanceof L.Marker) {
+ layers = [layers];
+ } // else: must be an Array(L.Marker)|Map(L.Marker)
+ this._flagParentsIconsNeedUpdate(layers);
+ this._refreshClustersIcons();
+
+ // In case of singleMarkerMode, also re-draw the markers.
+ if (this.options.singleMarkerMode) {
+ this._refreshSingleMarkerModeMarkers(layers);
+ }
+
+ return this;
+ },
+
+ /**
+ * Simply flags all parent clusters of the given markers as having a "dirty" icon.
+ * @param layers Array(L.Marker)|Map(L.Marker) list of markers.
+ * @private
+ */
+ _flagParentsIconsNeedUpdate: function (layers) {
+ var id, parent;
+
+ // Assumes layers is an Array or an Object whose prototype is non-enumerable.
+ for (id in layers) {
+ // Flag parent clusters' icon as "dirty", all the way up.
+ // Dumb process that flags multiple times upper parents, but still
+ // much more efficient than trying to be smart and make short lists,
+ // at least in the case of a hierarchy following a power law:
+ // http://jsperf.com/flag-nodes-in-power-hierarchy/2
+ parent = layers[id].__parent;
+ while (parent) {
+ parent._iconNeedsUpdate = true;
+ parent = parent.__parent;
+ }
+ }
+ },
+
+ /**
+ * Re-draws the icon of the supplied markers.
+ * To be used in singleMarkerMode only.
+ * @param layers Array(L.Marker)|Map(L.Marker) list of markers.
+ * @private
+ */
+ _refreshSingleMarkerModeMarkers: function (layers) {
+ var id, layer;
+
+ for (id in layers) {
+ layer = layers[id];
+
+ // Make sure we do not override markers that do not belong to THIS group.
+ if (this.hasLayer(layer)) {
+ // Need to re-create the icon first, then re-draw the marker.
+ layer.setIcon(this._overrideMarkerIcon(layer));
+ }
+ }
+ }
+});
+
+L.Marker.include({
+ /**
+ * Updates the given options in the marker's icon and refreshes the marker.
+ * @param options map object of icon options.
+ * @param directlyRefreshClusters boolean (optional) true to trigger
+ * MCG.refreshClustersOf() right away with this single marker.
+ * @returns {L.Marker}
+ */
+ refreshIconOptions: function (options, directlyRefreshClusters) {
+ var icon = this.options.icon;
+
+ L.setOptions(icon, options);
+
+ this.setIcon(icon);
+
+ // Shortcut to refresh the associated MCG clusters right away.
+ // To be used when refreshing a single marker.
+ // Otherwise, better use MCG.refreshClusters() once at the end with
+ // the list of modified markers.
+ if (directlyRefreshClusters && this.__parent) {
+ this.__parent._group.refreshClusters(this);
+ }
+
+ return this;
+ }
+});
+
+
+}(window, document));
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['leaflet'], factory);
+ } else if (typeof modules === 'object' && module.exports) {
+ // define a Common JS module that relies on 'leaflet'
+ module.exports = factory(require('leaflet'));
+ } else {
+ // Assume Leaflet is loaded into global object L already
+ factory(L);
+ }
+}(this, function (L) {
+ 'use strict';
+
+ L.TileLayer.Provider = L.TileLayer.extend({
+ initialize: function (arg, options) {
+ var providers = L.TileLayer.Provider.providers;
+
+ var parts = arg.split('.');
+
+ var providerName = parts[0];
+ var variantName = parts[1];
+
+ if (!providers[providerName]) {
+ throw 'No such provider (' + providerName + ')';
+ }
+
+ var provider = {
+ url: providers[providerName].url,
+ options: providers[providerName].options
+ };
+
+ // overwrite values in provider from variant.
+ if (variantName && 'variants' in providers[providerName]) {
+ if (!(variantName in providers[providerName].variants)) {
+ throw 'No such variant of ' + providerName + ' (' + variantName + ')';
+ }
+ var variant = providers[providerName].variants[variantName];
+ var variantOptions;
+ if (typeof variant === 'string') {
+ variantOptions = {
+ variant: variant
+ };
+ } else {
+ variantOptions = variant.options;
+ }
+ provider = {
+ url: variant.url || provider.url,
+ options: L.Util.extend({}, provider.options, variantOptions)
+ };
+ }
+
+ // replace attribution placeholders with their values from toplevel provider attribution,
+ // recursively
+ var attributionReplacer = function (attr) {
+ if (attr.indexOf('{attribution.') === -1) {
+ return attr;
+ }
+ return attr.replace(/\{attribution.(\w*)\}/,
+ function (match, attributionName) {
+ return attributionReplacer(providers[attributionName].options.attribution);
+ }
+ );
+ };
+ provider.options.attribution = attributionReplacer(provider.options.attribution);
+
+ // Compute final options combining provider options with any user overrides
+ var layerOpts = L.Util.extend({}, provider.options, options);
+ L.TileLayer.prototype.initialize.call(this, provider.url, layerOpts);
+ }
+ });
+
+ /**
+ * Definition of providers.
+ * see http://leafletjs.com/reference.html#tilelayer for options in the options map.
+ */
+
+ L.TileLayer.Provider.providers = {
+ OpenStreetMap: {
+ url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 19,
+ attribution:
+ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
+ },
+ variants: {
+ Mapnik: {},
+ BlackAndWhite: {
+ url: 'http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 18
+ }
+ },
+ DE: {
+ url: 'https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 18
+ }
+ },
+ CH: {
+ url: 'https://tile.osm.ch/switzerland/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 18,
+ bounds: [[45, 5], [48, 11]]
+ }
+ },
+ France: {
+ url: 'https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 20,
+ attribution: '&copy; Openstreetmap France | {attribution.OpenStreetMap}'
+ }
+ },
+ HOT: {
+ url: 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
+ options: {
+ attribution: '{attribution.OpenStreetMap}, Tiles courtesy of <a href="http://hot.openstreetmap.org/" target="_blank">Humanitarian OpenStreetMap Team</a>'
+ }
+ },
+ BZH: {
+ url: 'https://tile.openstreetmap.bzh/br/{z}/{x}/{y}.png',
+ options: {
+ attribution: '{attribution.OpenStreetMap}, Tiles courtesy of <a href="http://www.openstreetmap.bzh/" target="_blank">Breton OpenStreetMap Team</a>',
+ bounds: [[46.2, -5.5], [50, 0.7]]
+ }
+ }
+ }
+ },
+ OpenSeaMap: {
+ url: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png',
+ options: {
+ attribution: 'Map data: &copy; <a href="http://www.openseamap.org">OpenSeaMap</a> contributors'
+ }
+ },
+ OpenPtMap: {
+ url: 'http://openptmap.org/tiles/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 17,
+ attribution: 'Map data: &copy; <a href="http://www.openptmap.org">OpenPtMap</a> contributors'
+ }
+ },
+ OpenTopoMap: {
+ url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 17,
+ attribution: 'Map data: {attribution.OpenStreetMap}, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
+ }
+ },
+ OpenRailwayMap: {
+ url: 'https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 19,
+ attribution: 'Map data: {attribution.OpenStreetMap} | Map style: &copy; <a href="https://www.OpenRailwayMap.org">OpenRailwayMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
+ }
+ },
+ OpenFireMap: {
+ url: 'http://openfiremap.org/hytiles/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 19,
+ attribution: 'Map data: {attribution.OpenStreetMap} | Map style: &copy; <a href="http://www.openfiremap.org">OpenFireMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
+ }
+ },
+ SafeCast: {
+ url: 'https://s3.amazonaws.com/te512.safecast.org/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 16,
+ attribution: 'Map data: {attribution.OpenStreetMap} | Map style: &copy; <a href="https://blog.safecast.org/about/">SafeCast</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
+ }
+ },
+ Thunderforest: {
+ url: 'https://{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png?apikey={apikey}',
+ options: {
+ attribution:
+ '&copy; <a href="http://www.thunderforest.com/">Thunderforest</a>, {attribution.OpenStreetMap}',
+ variant: 'cycle',
+ apikey: '<insert your api key here>',
+ maxZoom: 22
+ },
+ variants: {
+ OpenCycleMap: 'cycle',
+ Transport: {
+ options: {
+ variant: 'transport'
+ }
+ },
+ TransportDark: {
+ options: {
+ variant: 'transport-dark'
+ }
+ },
+ SpinalMap: {
+ options: {
+ variant: 'spinal-map'
+ }
+ },
+ Landscape: 'landscape',
+ Outdoors: 'outdoors',
+ Pioneer: 'pioneer'
+ }
+ },
+ OpenMapSurfer: {
+ url: 'https://korona.geog.uni-heidelberg.de/tiles/{variant}/x={x}&y={y}&z={z}',
+ options: {
+ maxZoom: 20,
+ variant: 'roads',
+ attribution: 'Imagery from <a href="http://giscience.uni-hd.de/">GIScience Research Group @ University of Heidelberg</a> &mdash; Map data {attribution.OpenStreetMap}'
+ },
+ variants: {
+ Roads: 'roads',
+ AdminBounds: {
+ options: {
+ variant: 'adminb',
+ maxZoom: 19
+ }
+ },
+ Grayscale: {
+ options: {
+ variant: 'roadsg',
+ maxZoom: 19
+ }
+ }
+ }
+ },
+ Hydda: {
+ url: 'https://{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 18,
+ variant: 'full',
+ attribution: 'Tiles courtesy of <a href="http://openstreetmap.se/" target="_blank">OpenStreetMap Sweden</a> &mdash; Map data {attribution.OpenStreetMap}'
+ },
+ variants: {
+ Full: 'full',
+ Base: 'base',
+ RoadsAndLabels: 'roads_and_labels'
+ }
+ },
+ MapBox: {
+ url: 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}',
+ options: {
+ attribution:
+ 'Imagery from <a href="http://mapbox.com/about/maps/">MapBox</a> &mdash; ' +
+ 'Map data {attribution.OpenStreetMap}',
+ subdomains: 'abcd',
+ id: 'mapbox.streets',
+ accessToken: '<insert your access token here>',
+ }
+ },
+ Stamen: {
+ url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}{r}.{ext}',
+ options: {
+ attribution:
+ 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, ' +
+ '<a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash; ' +
+ 'Map data {attribution.OpenStreetMap}',
+ subdomains: 'abcd',
+ minZoom: 0,
+ maxZoom: 20,
+ variant: 'toner',
+ ext: 'png'
+ },
+ variants: {
+ Toner: 'toner',
+ TonerBackground: 'toner-background',
+ TonerHybrid: 'toner-hybrid',
+ TonerLines: 'toner-lines',
+ TonerLabels: 'toner-labels',
+ TonerLite: 'toner-lite',
+ Watercolor: {
+ url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}',
+ options: {
+ variant: 'watercolor',
+ ext: 'jpg',
+ minZoom: 1,
+ maxZoom: 16
+ }
+ },
+ Terrain: {
+ options: {
+ variant: 'terrain',
+ minZoom: 0,
+ maxZoom: 18
+ }
+ },
+ TerrainBackground: {
+ options: {
+ variant: 'terrain-background',
+ minZoom: 0,
+ maxZoom: 18
+ }
+ },
+ TopOSMRelief: {
+ url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}',
+ options: {
+ variant: 'toposm-color-relief',
+ ext: 'jpg',
+ bounds: [[22, -132], [51, -56]]
+ }
+ },
+ TopOSMFeatures: {
+ options: {
+ variant: 'toposm-features',
+ bounds: [[22, -132], [51, -56]],
+ opacity: 0.9
+ }
+ }
+ }
+ },
+ Esri: {
+ url: 'https://server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}',
+ options: {
+ variant: 'World_Street_Map',
+ attribution: 'Tiles &copy; Esri'
+ },
+ variants: {
+ WorldStreetMap: {
+ options: {
+ attribution:
+ '{attribution.Esri} &mdash; ' +
+ 'Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
+ }
+ },
+ DeLorme: {
+ options: {
+ variant: 'Specialty/DeLorme_World_Base_Map',
+ minZoom: 1,
+ maxZoom: 11,
+ attribution: '{attribution.Esri} &mdash; Copyright: &copy;2012 DeLorme'
+ }
+ },
+ WorldTopoMap: {
+ options: {
+ variant: 'World_Topo_Map',
+ attribution:
+ '{attribution.Esri} &mdash; ' +
+ 'Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community'
+ }
+ },
+ WorldImagery: {
+ options: {
+ variant: 'World_Imagery',
+ attribution:
+ '{attribution.Esri} &mdash; ' +
+ 'Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
+ }
+ },
+ WorldTerrain: {
+ options: {
+ variant: 'World_Terrain_Base',
+ maxZoom: 13,
+ attribution:
+ '{attribution.Esri} &mdash; ' +
+ 'Source: USGS, Esri, TANA, DeLorme, and NPS'
+ }
+ },
+ WorldShadedRelief: {
+ options: {
+ variant: 'World_Shaded_Relief',
+ maxZoom: 13,
+ attribution: '{attribution.Esri} &mdash; Source: Esri'
+ }
+ },
+ WorldPhysical: {
+ options: {
+ variant: 'World_Physical_Map',
+ maxZoom: 8,
+ attribution: '{attribution.Esri} &mdash; Source: US National Park Service'
+ }
+ },
+ OceanBasemap: {
+ options: {
+ variant: 'Ocean_Basemap',
+ maxZoom: 13,
+ attribution: '{attribution.Esri} &mdash; Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri'
+ }
+ },
+ NatGeoWorldMap: {
+ options: {
+ variant: 'NatGeo_World_Map',
+ maxZoom: 16,
+ attribution: '{attribution.Esri} &mdash; National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC'
+ }
+ },
+ WorldGrayCanvas: {
+ options: {
+ variant: 'Canvas/World_Light_Gray_Base',
+ maxZoom: 16,
+ attribution: '{attribution.Esri} &mdash; Esri, DeLorme, NAVTEQ'
+ }
+ }
+ }
+ },
+ OpenWeatherMap: {
+ url: 'http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png?appid={apiKey}',
+ options: {
+ maxZoom: 19,
+ attribution: 'Map data &copy; <a href="http://openweathermap.org">OpenWeatherMap</a>',
+ apiKey:'<insert your api key here>',
+ opacity: 0.5
+ },
+ variants: {
+ Clouds: 'clouds',
+ CloudsClassic: 'clouds_cls',
+ Precipitation: 'precipitation',
+ PrecipitationClassic: 'precipitation_cls',
+ Rain: 'rain',
+ RainClassic: 'rain_cls',
+ Pressure: 'pressure',
+ PressureContour: 'pressure_cntr',
+ Wind: 'wind',
+ Temperature: 'temp',
+ Snow: 'snow'
+ }
+ },
+ HERE: {
+ /*
+ * HERE maps, formerly Nokia maps.
+ * These basemaps are free, but you need an API key. Please sign up at
+ * https://developer.here.com/plans
+ */
+ url:
+ 'https://{s}.{base}.maps.api.here.com/maptile/2.1/' +
+ '{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' +
+ 'app_id={app_id}&app_code={app_code}&lg={language}',
+ options: {
+ attribution:
+ 'Map &copy; 1987-' + new Date().getFullYear() + ' <a href="http://developer.here.com">HERE</a>',
+ subdomains: '1234',
+ mapID: 'newest',
+ 'app_id': '<insert your app_id here>',
+ 'app_code': '<insert your app_code here>',
+ base: 'base',
+ variant: 'normal.day',
+ maxZoom: 20,
+ type: 'maptile',
+ language: 'eng',
+ format: 'png8',
+ size: '256'
+ },
+ variants: {
+ normalDay: 'normal.day',
+ normalDayCustom: 'normal.day.custom',
+ normalDayGrey: 'normal.day.grey',
+ normalDayMobile: 'normal.day.mobile',
+ normalDayGreyMobile: 'normal.day.grey.mobile',
+ normalDayTransit: 'normal.day.transit',
+ normalDayTransitMobile: 'normal.day.transit.mobile',
+ normalNight: 'normal.night',
+ normalNightMobile: 'normal.night.mobile',
+ normalNightGrey: 'normal.night.grey',
+ normalNightGreyMobile: 'normal.night.grey.mobile',
+ normalNightTransit: 'normal.night.transit',
+ normalNightTransitMobile: 'normal.night.transit.mobile',
+ reducedDay: 'reduced.day',
+ reducedNight: 'reduced.night',
+ basicMap: {
+ options: {
+ type: 'basetile'
+ }
+ },
+ mapLabels: {
+ options: {
+ type: 'labeltile',
+ format: 'png'
+ }
+ },
+ trafficFlow: {
+ options: {
+ base: 'traffic',
+ type: 'flowtile'
+ }
+ },
+ carnavDayGrey: 'carnav.day.grey',
+ hybridDay: {
+ options: {
+ base: 'aerial',
+ variant: 'hybrid.day'
+ }
+ },
+ hybridDayMobile: {
+ options: {
+ base: 'aerial',
+ variant: 'hybrid.day.mobile'
+ }
+ },
+ hybridDayTransit: {
+ options: {
+ base: 'aerial',
+ variant: 'hybrid.day.transit'
+ }
+ },
+ hybridDayGrey: {
+ options: {
+ base: 'aerial',
+ variant: 'hybrid.grey.day'
+ }
+ },
+ pedestrianDay: 'pedestrian.day',
+ pedestrianNight: 'pedestrian.night',
+ satelliteDay: {
+ options: {
+ base: 'aerial',
+ variant: 'satellite.day'
+ }
+ },
+ terrainDay: {
+ options: {
+ base: 'aerial',
+ variant: 'terrain.day'
+ }
+ },
+ terrainDayMobile: {
+ options: {
+ base: 'aerial',
+ variant: 'terrain.day.mobile'
+ }
+ }
+ }
+ },
+ FreeMapSK: {
+ url: 'http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg',
+ options: {
+ minZoom: 8,
+ maxZoom: 16,
+ subdomains: '1234',
+ bounds: [[47.204642, 15.996093], [49.830896, 22.576904]],
+ attribution:
+ '{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 <a href="http://freemap.sk">Freemap.sk</a>'
+ }
+ },
+ MtbMap: {
+ url: 'http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png',
+ options: {
+ attribution:
+ '{attribution.OpenStreetMap} &amp; USGS'
+ }
+ },
+ CartoDB: {
+ url: 'https://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}{r}.png',
+ options: {
+ attribution: '{attribution.OpenStreetMap} &copy; <a href="https://carto.com/attributions">CARTO</a>',
+ subdomains: 'abcd',
+ maxZoom: 19,
+ variant: 'light_all'
+ },
+ variants: {
+ Positron: 'light_all',
+ PositronNoLabels: 'light_nolabels',
+ PositronOnlyLabels: 'light_only_labels',
+ DarkMatter: 'dark_all',
+ DarkMatterNoLabels: 'dark_nolabels',
+ DarkMatterOnlyLabels: 'dark_only_labels',
+ Voyager: 'rastertiles/voyager',
+ VoyagerNoLabels: 'rastertiles/voyager_nolabels',
+ VoyagerOnlyLabels: 'rastertiles/voyager_only_labels',
+ VoyagerLabelsUnder: 'rastertiles/voyager_labels_under'
+ }
+ },
+ HikeBike: {
+ url: 'http://{s}.tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png',
+ options: {
+ maxZoom: 19,
+ attribution: '{attribution.OpenStreetMap}',
+ variant: 'hikebike'
+ },
+ variants: {
+ HikeBike: {},
+ HillShading: {
+ options: {
+ maxZoom: 15,
+ variant: 'hillshading'
+ }
+ }
+ }
+ },
+ BasemapAT: {
+ url: 'https://maps{s}.wien.gv.at/basemap/{variant}/normal/google3857/{z}/{y}/{x}.{format}',
+ options: {
+ maxZoom: 19,
+ attribution: 'Datenquelle: <a href="https://www.basemap.at">basemap.at</a>',
+ subdomains: ['', '1', '2', '3', '4'],
+ format: 'png',
+ bounds: [[46.358770, 8.782379], [49.037872, 17.189532]],
+ variant: 'geolandbasemap'
+ },
+ variants: {
+ basemap: {
+ options: {
+ maxZoom: 20, // currently only in Vienna
+ variant: 'geolandbasemap'
+ }
+ },
+ grau: 'bmapgrau',
+ overlay: 'bmapoverlay',
+ highdpi: {
+ options: {
+ variant: 'bmaphidpi',
+ format: 'jpeg'
+ }
+ },
+ orthofoto: {
+ options: {
+ maxZoom: 20, // currently only in Vienna
+ variant: 'bmaporthofoto30cm',
+ format: 'jpeg'
+ }
+ }
+ }
+ },
+ nlmaps: {
+ url: 'https://geodata.nationaalgeoregister.nl/tiles/service/wmts/{variant}/EPSG:3857/{z}/{x}/{y}.png',
+ options: {
+ minZoom: 6,
+ maxZoom: 19,
+ bounds: [[50.5, 3.25], [54, 7.6]],
+ attribution: 'Kaartgegevens &copy; <a href="kadaster.nl">Kadaster</a>'
+ },
+ variants: {
+ 'standaard': 'brtachtergrondkaart',
+ 'pastel': 'brtachtergrondkaartpastel',
+ 'grijs': 'brtachtergrondkaartgrijs',
+ 'luchtfoto': {
+ 'url': 'https://geodata.nationaalgeoregister.nl/luchtfoto/rgb/wmts/1.0.0/2016_ortho25/EPSG:3857/{z}/{x}/{y}.png',
+ }
+ }
+ },
+ NASAGIBS: {
+ url: 'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}',
+ options: {
+ attribution:
+ 'Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System ' +
+ '(<a href="https://earthdata.nasa.gov">ESDIS</a>) with funding provided by NASA/HQ.',
+ bounds: [[-85.0511287776, -179.999999975], [85.0511287776, 179.999999975]],
+ minZoom: 1,
+ maxZoom: 9,
+ format: 'jpg',
+ time: '',
+ tilematrixset: 'GoogleMapsCompatible_Level'
+ },
+ variants: {
+ ModisTerraTrueColorCR: 'MODIS_Terra_CorrectedReflectance_TrueColor',
+ ModisTerraBands367CR: 'MODIS_Terra_CorrectedReflectance_Bands367',
+ ViirsEarthAtNight2012: {
+ options: {
+ variant: 'VIIRS_CityLights_2012',
+ maxZoom: 8
+ }
+ },
+ ModisTerraLSTDay: {
+ options: {
+ variant: 'MODIS_Terra_Land_Surface_Temp_Day',
+ format: 'png',
+ maxZoom: 7,
+ opacity: 0.75
+ }
+ },
+ ModisTerraSnowCover: {
+ options: {
+ variant: 'MODIS_Terra_Snow_Cover',
+ format: 'png',
+ maxZoom: 8,
+ opacity: 0.75
+ }
+ },
+ ModisTerraAOD: {
+ options: {
+ variant: 'MODIS_Terra_Aerosol',
+ format: 'png',
+ maxZoom: 6,
+ opacity: 0.75
+ }
+ },
+ ModisTerraChlorophyll: {
+ options: {
+ variant: 'MODIS_Terra_Chlorophyll_A',
+ format: 'png',
+ maxZoom: 7,
+ opacity: 0.75
+ }
+ }
+ }
+ },
+ NLS: {
+ // NLS maps are copyright National library of Scotland.
+ // http://maps.nls.uk/projects/api/index.html
+ // Please contact NLS for anything other than non-commercial low volume usage
+ //
+ // Map sources: Ordnance Survey 1:1m to 1:63K, 1920s-1940s
+ // z0-9 - 1:1m
+ // z10-11 - quarter inch (1:253440)
+ // z12-18 - one inch (1:63360)
+ url: 'https://nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg',
+ options: {
+ attribution: '<a href="http://geo.nls.uk/maps/">National Library of Scotland Historic Maps</a>',
+ bounds: [[49.6, -12], [61.7, 3]],
+ minZoom: 1,
+ maxZoom: 18,
+ subdomains: '0123',
+ }
+ },
+ JusticeMap: {
+ // Justice Map (http://www.justicemap.org/)
+ // Visualize race and income data for your community, county and country.
+ // Includes tools for data journalists, bloggers and community activists.
+ url: 'http://www.justicemap.org/tile/{size}/{variant}/{z}/{x}/{y}.png',
+ options: {
+ attribution: '<a href="http://www.justicemap.org/terms.php">Justice Map</a>',
+ // one of 'county', 'tract', 'block'
+ size: 'county',
+ // Bounds for USA, including Alaska and Hawaii
+ bounds: [[14, -180], [72, -56]]
+ },
+ variants: {
+ income: 'income',
+ americanIndian: 'indian',
+ asian: 'asian',
+ black: 'black',
+ hispanic: 'hispanic',
+ multi: 'multi',
+ nonWhite: 'nonwhite',
+ white: 'white',
+ plurality: 'plural'
+ }
+ },
+ Wikimedia: {
+ url: 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png',
+ options: {
+ attribution: '<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia</a>',
+ minZoom: 1,
+ maxZoom: 19
+ }
+ },
+ GeoportailFrance: {
+ url: 'https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER={variant}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}',
+ options: {
+ attribution: '<a target="_blank" href="https://www.geoportail.gouv.fr/">Geoportail France</a>',
+ bounds: [[-75, -180], [81, 180]],
+ minZoom: 2,
+ maxZoom: 18,
+ // Get your own geoportail apikey here : http://professionnels.ign.fr/ign/contrats/
+ // NB : 'choisirgeoportail' is a demonstration key that comes with no guarantee
+ apikey: 'choisirgeoportail',
+ format: 'image/jpeg',
+ style : 'normal',
+ variant: 'GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD'
+ },
+ variants: {
+ parcels: {
+ options : {
+ variant: 'CADASTRALPARCELS.PARCELS',
+ maxZoom: 20,
+ style : 'bdparcellaire',
+ format: 'image/png'
+ }
+ },
+ ignMaps: 'GEOGRAPHICALGRIDSYSTEMS.MAPS',
+ maps: 'GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD',
+ orthos: {
+ options: {
+ maxZoom: 19,
+ variant: 'ORTHOIMAGERY.ORTHOPHOTOS'
+ }
+ }
+ }
+ },
+ OneMapSG: {
+ url: 'https://maps-{s}.onemap.sg/v3/{variant}/{z}/{x}/{y}.png',
+ options: {
+ variant: 'Default',
+ minZoom: 11,
+ maxZoom: 18,
+ bounds: [[1.56073, 104.11475], [1.16, 103.502]],
+ attribution: '<img src="https://docs.onemap.sg/maps/images/oneMap64-01.png" style="height:20px;width:20px;"/> New OneMap | Map data &copy; contributors, <a href="http://SLA.gov.sg">Singapore Land Authority</a>'
+ },
+ variants: {
+ Default: 'Default',
+ Night: 'Night',
+ Original: 'Original',
+ Grey: 'Grey',
+ LandLot: 'LandLot'
+ }
+ }
+ };
+
+ L.tileLayer.provider = function (provider, options) {
+ return new L.TileLayer.Provider(provider, options);
+ };
+
+ return L;
+}));
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.select.js b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.select.js
new file mode 100644
index 00000000..2b4557c5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.select.js
@@ -0,0 +1,5725 @@
+/*!
+ * Select2 4.0.3
+ * https://select2.github.io
+ *
+ * Released under the MIT license
+ * https://github.com/select2/select2/blob/master/LICENSE.md
+ */
+(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS
+ factory(require('jquery'));
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function (jQuery) {
+ // This is needed so we can catch the AMD loader configuration and use it
+ // The inner file should be wrapped (by `banner.start.js`) in a function that
+ // returns the AMD loader references.
+ var S2 =
+(function () {
+ // Restore the Select2 AMD loader so it can be used
+ // Needed mostly in the language files, where the loader is not inserted
+ if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
+ var S2 = jQuery.fn.select2.amd;
+ }
+var S2;(function () { if (!S2 || !S2.requirejs) {
+if (!S2) { S2 = {}; } else { require = S2; }
+/**
+ * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/almond for details
+ */
+//Going sloppy to avoid 'use strict' string cost, but strict practices should
+//be followed.
+/*jslint sloppy: true */
+/*global setTimeout: false */
+
+var requirejs, require, define;
+(function (undef) {
+ var main, req, makeMap, handlers,
+ defined = {},
+ waiting = {},
+ config = {},
+ defining = {},
+ hasOwn = Object.prototype.hasOwnProperty,
+ aps = [].slice,
+ jsSuffixRegExp = /\.js$/;
+
+ function hasProp(obj, prop) {
+ return hasOwn.call(obj, prop);
+ }
+
+ /**
+ * Given a relative module name, like ./something, normalize it to
+ * a real name that can be mapped to a path.
+ * @param {String} name the relative name
+ * @param {String} baseName a real name that the name arg is relative
+ * to.
+ * @returns {String} normalized name
+ */
+ function normalize(name, baseName) {
+ var nameParts, nameSegment, mapValue, foundMap, lastIndex,
+ foundI, foundStarMap, starI, i, j, part,
+ baseParts = baseName && baseName.split("/"),
+ map = config.map,
+ starMap = (map && map['*']) || {};
+
+ //Adjust any relative paths.
+ if (name && name.charAt(0) === ".") {
+ //If have a base name, try to normalize against it,
+ //otherwise, assume it is a top-level require that will
+ //be relative to baseUrl in the end.
+ if (baseName) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
+
+ // Node .js allowance:
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
+
+ //Lop off the last part of baseParts, so that . matches the
+ //"directory" and not name of the baseName's module. For instance,
+ //baseName of "one/two/three", maps to "one/two/three.js", but we
+ //want the directory, "one/two" for this normalization.
+ name = baseParts.slice(0, baseParts.length - 1).concat(name);
+
+ //start trimDots
+ for (i = 0; i < name.length; i += 1) {
+ part = name[i];
+ if (part === ".") {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === "..") {
+ if (i === 1 && (name[2] === '..' || name[0] === '..')) {
+ //End of the line. Keep at least one non-dot
+ //path segment at the front so it can be mapped
+ //correctly to disk. Otherwise, there is likely
+ //no path mapping for a path starting with '..'.
+ //This can still fail, but catches the most reasonable
+ //uses of ..
+ break;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
+ }
+ }
+ //end trimDots
+
+ name = name.join("/");
+ } else if (name.indexOf('./') === 0) {
+ // No baseName, so this is ID is resolved relative
+ // to baseUrl, pull off the leading dot.
+ name = name.substring(2);
+ }
+ }
+
+ //Apply map config if available.
+ if ((baseParts || starMap) && map) {
+ nameParts = name.split('/');
+
+ for (i = nameParts.length; i > 0; i -= 1) {
+ nameSegment = nameParts.slice(0, i).join("/");
+
+ if (baseParts) {
+ //Find the longest baseName segment match in the config.
+ //So, do joins on the biggest to smallest lengths of baseParts.
+ for (j = baseParts.length; j > 0; j -= 1) {
+ mapValue = map[baseParts.slice(0, j).join('/')];
+
+ //baseName segment has config, find if it has one for
+ //this name.
+ if (mapValue) {
+ mapValue = mapValue[nameSegment];
+ if (mapValue) {
+ //Match, update name to the new value.
+ foundMap = mapValue;
+ foundI = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundMap) {
+ break;
+ }
+
+ //Check for a star map match, but just hold on to it,
+ //if there is a shorter segment match later in a matching
+ //config, then favor over this star map.
+ if (!foundStarMap && starMap && starMap[nameSegment]) {
+ foundStarMap = starMap[nameSegment];
+ starI = i;
+ }
+ }
+
+ if (!foundMap && foundStarMap) {
+ foundMap = foundStarMap;
+ foundI = starI;
+ }
+
+ if (foundMap) {
+ nameParts.splice(0, foundI, foundMap);
+ name = nameParts.join('/');
+ }
+ }
+
+ return name;
+ }
+
+ function makeRequire(relName, forceSync) {
+ return function () {
+ //A version of a require function that passes a moduleName
+ //value for items that may need to
+ //look up paths relative to the moduleName
+ var args = aps.call(arguments, 0);
+
+ //If first arg is not require('string'), and there is only
+ //one arg, it is the array form without a callback. Insert
+ //a null so that the following concat is correct.
+ if (typeof args[0] !== 'string' && args.length === 1) {
+ args.push(null);
+ }
+ return req.apply(undef, args.concat([relName, forceSync]));
+ };
+ }
+
+ function makeNormalize(relName) {
+ return function (name) {
+ return normalize(name, relName);
+ };
+ }
+
+ function makeLoad(depName) {
+ return function (value) {
+ defined[depName] = value;
+ };
+ }
+
+ function callDep(name) {
+ if (hasProp(waiting, name)) {
+ var args = waiting[name];
+ delete waiting[name];
+ defining[name] = true;
+ main.apply(undef, args);
+ }
+
+ if (!hasProp(defined, name) && !hasProp(defining, name)) {
+ throw new Error('No ' + name);
+ }
+ return defined[name];
+ }
+
+ //Turns a plugin!resource to [plugin, resource]
+ //with the plugin being undefined if the name
+ //did not have a plugin prefix.
+ function splitPrefix(name) {
+ var prefix,
+ index = name ? name.indexOf('!') : -1;
+ if (index > -1) {
+ prefix = name.substring(0, index);
+ name = name.substring(index + 1, name.length);
+ }
+ return [prefix, name];
+ }
+
+ /**
+ * Makes a name map, normalizing the name, and using a plugin
+ * for normalization if necessary. Grabs a ref to plugin
+ * too, as an optimization.
+ */
+ makeMap = function (name, relName) {
+ var plugin,
+ parts = splitPrefix(name),
+ prefix = parts[0];
+
+ name = parts[1];
+
+ if (prefix) {
+ prefix = normalize(prefix, relName);
+ plugin = callDep(prefix);
+ }
+
+ //Normalize according
+ if (prefix) {
+ if (plugin && plugin.normalize) {
+ name = plugin.normalize(name, makeNormalize(relName));
+ } else {
+ name = normalize(name, relName);
+ }
+ } else {
+ name = normalize(name, relName);
+ parts = splitPrefix(name);
+ prefix = parts[0];
+ name = parts[1];
+ if (prefix) {
+ plugin = callDep(prefix);
+ }
+ }
+
+ //Using ridiculous property names for space reasons
+ return {
+ f: prefix ? prefix + '!' + name : name, //fullName
+ n: name,
+ pr: prefix,
+ p: plugin
+ };
+ };
+
+ function makeConfig(name) {
+ return function () {
+ return (config && config.config && config.config[name]) || {};
+ };
+ }
+
+ handlers = {
+ require: function (name) {
+ return makeRequire(name);
+ },
+ exports: function (name) {
+ var e = defined[name];
+ if (typeof e !== 'undefined') {
+ return e;
+ } else {
+ return (defined[name] = {});
+ }
+ },
+ module: function (name) {
+ return {
+ id: name,
+ uri: '',
+ exports: defined[name],
+ config: makeConfig(name)
+ };
+ }
+ };
+
+ main = function (name, deps, callback, relName) {
+ var cjsModule, depName, ret, map, i,
+ args = [],
+ callbackType = typeof callback,
+ usingExports;
+
+ //Use name if no relName
+ relName = relName || name;
+
+ //Call the callback to define the module, if necessary.
+ if (callbackType === 'undefined' || callbackType === 'function') {
+ //Pull out the defined dependencies and pass the ordered
+ //values to the callback.
+ //Default to [require, exports, module] if no deps
+ deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
+ for (i = 0; i < deps.length; i += 1) {
+ map = makeMap(deps[i], relName);
+ depName = map.f;
+
+ //Fast path CommonJS standard dependencies.
+ if (depName === "require") {
+ args[i] = handlers.require(name);
+ } else if (depName === "exports") {
+ //CommonJS module spec 1.1
+ args[i] = handlers.exports(name);
+ usingExports = true;
+ } else if (depName === "module") {
+ //CommonJS module spec 1.1
+ cjsModule = args[i] = handlers.module(name);
+ } else if (hasProp(defined, depName) ||
+ hasProp(waiting, depName) ||
+ hasProp(defining, depName)) {
+ args[i] = callDep(depName);
+ } else if (map.p) {
+ map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
+ args[i] = defined[depName];
+ } else {
+ throw new Error(name + ' missing ' + depName);
+ }
+ }
+
+ ret = callback ? callback.apply(defined[name], args) : undefined;
+
+ if (name) {
+ //If setting exports via "module" is in play,
+ //favor that over return value and exports. After that,
+ //favor a non-undefined return value over exports use.
+ if (cjsModule && cjsModule.exports !== undef &&
+ cjsModule.exports !== defined[name]) {
+ defined[name] = cjsModule.exports;
+ } else if (ret !== undef || !usingExports) {
+ //Use the return value from the function.
+ defined[name] = ret;
+ }
+ }
+ } else if (name) {
+ //May just be an object definition for the module. Only
+ //worry about defining if have a module name.
+ defined[name] = callback;
+ }
+ };
+
+ requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
+ if (typeof deps === "string") {
+ if (handlers[deps]) {
+ //callback in this case is really relName
+ return handlers[deps](callback);
+ }
+ //Just return the module wanted. In this scenario, the
+ //deps arg is the module name, and second arg (if passed)
+ //is just the relName.
+ //Normalize module name, if it contains . or ..
+ return callDep(makeMap(deps, callback).f);
+ } else if (!deps.splice) {
+ //deps is a config object, not an array.
+ config = deps;
+ if (config.deps) {
+ req(config.deps, config.callback);
+ }
+ if (!callback) {
+ return;
+ }
+
+ if (callback.splice) {
+ //callback is an array, which means it is a dependency list.
+ //Adjust args if there are dependencies
+ deps = callback;
+ callback = relName;
+ relName = null;
+ } else {
+ deps = undef;
+ }
+ }
+
+ //Support require(['a'])
+ callback = callback || function () {};
+
+ //If relName is a function, it is an errback handler,
+ //so remove it.
+ if (typeof relName === 'function') {
+ relName = forceSync;
+ forceSync = alt;
+ }
+
+ //Simulate async callback;
+ if (forceSync) {
+ main(undef, deps, callback, relName);
+ } else {
+ //Using a non-zero value because of concern for what old browsers
+ //do, and latest browsers "upgrade" to 4 if lower value is used:
+ //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
+ //If want a value immediately, use require('id') instead -- something
+ //that works in almond on the global level, but not guaranteed and
+ //unlikely to work in other AMD implementations.
+ setTimeout(function () {
+ main(undef, deps, callback, relName);
+ }, 4);
+ }
+
+ return req;
+ };
+
+ /**
+ * Just drops the config on the floor, but returns req in case
+ * the config return value is used.
+ */
+ req.config = function (cfg) {
+ return req(cfg);
+ };
+
+ /**
+ * Expose module registry for debugging and tooling
+ */
+ requirejs._defined = defined;
+
+ define = function (name, deps, callback) {
+ if (typeof name !== 'string') {
+ throw new Error('See almond README: incorrect module build, no module name');
+ }
+
+ //This module may not have dependencies
+ if (!deps.splice) {
+ //deps is not an array, so probably means
+ //an object literal or factory function for
+ //the value. Adjust args.
+ callback = deps;
+ deps = [];
+ }
+
+ if (!hasProp(defined, name) && !hasProp(waiting, name)) {
+ waiting[name] = [name, deps, callback];
+ }
+ };
+
+ define.amd = {
+ jQuery: true
+ };
+}());
+
+S2.requirejs = requirejs;S2.require = require;S2.define = define;
+}
+}());
+S2.define("almond", function(){});
+
+/* global jQuery:false, $:false */
+S2.define('jquery',[],function () {
+ var _$ = jQuery || $;
+
+ if (_$ == null && console && console.error) {
+ console.error(
+ 'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
+ 'found. Make sure that you are including jQuery before Select2 on your ' +
+ 'web page.'
+ );
+ }
+
+ return _$;
+});
+
+S2.define('select2/utils',[
+ 'jquery'
+], function ($) {
+ var Utils = {};
+
+ Utils.Extend = function (ChildClass, SuperClass) {
+ var __hasProp = {}.hasOwnProperty;
+
+ function BaseConstructor () {
+ this.constructor = ChildClass;
+ }
+
+ for (var key in SuperClass) {
+ if (__hasProp.call(SuperClass, key)) {
+ ChildClass[key] = SuperClass[key];
+ }
+ }
+
+ BaseConstructor.prototype = SuperClass.prototype;
+ ChildClass.prototype = new BaseConstructor();
+ ChildClass.__super__ = SuperClass.prototype;
+
+ return ChildClass;
+ };
+
+ function getMethods (theClass) {
+ var proto = theClass.prototype;
+
+ var methods = [];
+
+ for (var methodName in proto) {
+ var m = proto[methodName];
+
+ if (typeof m !== 'function') {
+ continue;
+ }
+
+ if (methodName === 'constructor') {
+ continue;
+ }
+
+ methods.push(methodName);
+ }
+
+ return methods;
+ }
+
+ Utils.Decorate = function (SuperClass, DecoratorClass) {
+ var decoratedMethods = getMethods(DecoratorClass);
+ var superMethods = getMethods(SuperClass);
+
+ function DecoratedClass () {
+ var unshift = Array.prototype.unshift;
+
+ var argCount = DecoratorClass.prototype.constructor.length;
+
+ var calledConstructor = SuperClass.prototype.constructor;
+
+ if (argCount > 0) {
+ unshift.call(arguments, SuperClass.prototype.constructor);
+
+ calledConstructor = DecoratorClass.prototype.constructor;
+ }
+
+ calledConstructor.apply(this, arguments);
+ }
+
+ DecoratorClass.displayName = SuperClass.displayName;
+
+ function ctr () {
+ this.constructor = DecoratedClass;
+ }
+
+ DecoratedClass.prototype = new ctr();
+
+ for (var m = 0; m < superMethods.length; m++) {
+ var superMethod = superMethods[m];
+
+ DecoratedClass.prototype[superMethod] =
+ SuperClass.prototype[superMethod];
+ }
+
+ var calledMethod = function (methodName) {
+ // Stub out the original method if it's not decorating an actual method
+ var originalMethod = function () {};
+
+ if (methodName in DecoratedClass.prototype) {
+ originalMethod = DecoratedClass.prototype[methodName];
+ }
+
+ var decoratedMethod = DecoratorClass.prototype[methodName];
+
+ return function () {
+ var unshift = Array.prototype.unshift;
+
+ unshift.call(arguments, originalMethod);
+
+ return decoratedMethod.apply(this, arguments);
+ };
+ };
+
+ for (var d = 0; d < decoratedMethods.length; d++) {
+ var decoratedMethod = decoratedMethods[d];
+
+ DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
+ }
+
+ return DecoratedClass;
+ };
+
+ var Observable = function () {
+ this.listeners = {};
+ };
+
+ Observable.prototype.on = function (event, callback) {
+ this.listeners = this.listeners || {};
+
+ if (event in this.listeners) {
+ this.listeners[event].push(callback);
+ } else {
+ this.listeners[event] = [callback];
+ }
+ };
+
+ Observable.prototype.trigger = function (event) {
+ var slice = Array.prototype.slice;
+ var params = slice.call(arguments, 1);
+
+ this.listeners = this.listeners || {};
+
+ // Params should always come in as an array
+ if (params == null) {
+ params = [];
+ }
+
+ // If there are no arguments to the event, use a temporary object
+ if (params.length === 0) {
+ params.push({});
+ }
+
+ // Set the `_type` of the first object to the event
+ params[0]._type = event;
+
+ if (event in this.listeners) {
+ this.invoke(this.listeners[event], slice.call(arguments, 1));
+ }
+
+ if ('*' in this.listeners) {
+ this.invoke(this.listeners['*'], arguments);
+ }
+ };
+
+ Observable.prototype.invoke = function (listeners, params) {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].apply(this, params);
+ }
+ };
+
+ Utils.Observable = Observable;
+
+ Utils.generateChars = function (length) {
+ var chars = '';
+
+ for (var i = 0; i < length; i++) {
+ var randomChar = Math.floor(Math.random() * 36);
+ chars += randomChar.toString(36);
+ }
+
+ return chars;
+ };
+
+ Utils.bind = function (func, context) {
+ return function () {
+ func.apply(context, arguments);
+ };
+ };
+
+ Utils._convertData = function (data) {
+ for (var originalKey in data) {
+ var keys = originalKey.split('-');
+
+ var dataLevel = data;
+
+ if (keys.length === 1) {
+ continue;
+ }
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+
+ // Lowercase the first letter
+ // By default, dash-separated becomes camelCase
+ key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+ if (!(key in dataLevel)) {
+ dataLevel[key] = {};
+ }
+
+ if (k == keys.length - 1) {
+ dataLevel[key] = data[originalKey];
+ }
+
+ dataLevel = dataLevel[key];
+ }
+
+ delete data[originalKey];
+ }
+
+ return data;
+ };
+
+ Utils.hasScroll = function (index, el) {
+ // Adapted from the function created by @ShadowScripter
+ // and adapted by @BillBarry on the Stack Exchange Code Review website.
+ // The original code can be found at
+ // http://codereview.stackexchange.com/q/13338
+ // and was designed to be used with the Sizzle selector engine.
+
+ var $el = $(el);
+ var overflowX = el.style.overflowX;
+ var overflowY = el.style.overflowY;
+
+ //Check both x and y declarations
+ if (overflowX === overflowY &&
+ (overflowY === 'hidden' || overflowY === 'visible')) {
+ return false;
+ }
+
+ if (overflowX === 'scroll' || overflowY === 'scroll') {
+ return true;
+ }
+
+ return ($el.innerHeight() < el.scrollHeight ||
+ $el.innerWidth() < el.scrollWidth);
+ };
+
+ Utils.escapeMarkup = function (markup) {
+ var replaceMap = {
+ '\\': '&#92;',
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ '\'': '&#39;',
+ '/': '&#47;'
+ };
+
+ // Do not try to escape the markup if it's not a string
+ if (typeof markup !== 'string') {
+ return markup;
+ }
+
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
+ return replaceMap[match];
+ });
+ };
+
+ // Append an array of jQuery nodes to a given element.
+ Utils.appendMany = function ($element, $nodes) {
+ // jQuery 1.7.x does not support $.fn.append() with an array
+ // Fall back to a jQuery object collection using $.fn.add()
+ if ($.fn.jquery.substr(0, 3) === '1.7') {
+ var $jqNodes = $();
+
+ $.map($nodes, function (node) {
+ $jqNodes = $jqNodes.add(node);
+ });
+
+ $nodes = $jqNodes;
+ }
+
+ $element.append($nodes);
+ };
+
+ return Utils;
+});
+
+S2.define('select2/results',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Results ($element, options, dataAdapter) {
+ this.$element = $element;
+ this.data = dataAdapter;
+ this.options = options;
+
+ Results.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Results, Utils.Observable);
+
+ Results.prototype.render = function () {
+ var $results = $(
+ '<ul class="select2-results__options" role="tree"></ul>'
+ );
+
+ if (this.options.get('multiple')) {
+ $results.attr('aria-multiselectable', 'true');
+ }
+
+ this.$results = $results;
+
+ return $results;
+ };
+
+ Results.prototype.clear = function () {
+ this.$results.empty();
+ };
+
+ Results.prototype.displayMessage = function (params) {
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ this.clear();
+ this.hideLoading();
+
+ var $message = $(
+ '<li role="treeitem" aria-live="assertive"' +
+ ' class="select2-results__option"></li>'
+ );
+
+ var message = this.options.get('translations').get(params.message);
+
+ $message.append(
+ escapeMarkup(
+ message(params.args)
+ )
+ );
+
+ $message[0].className += ' select2-results__message';
+
+ this.$results.append($message);
+ };
+
+ Results.prototype.hideMessages = function () {
+ this.$results.find('.select2-results__message').remove();
+ };
+
+ Results.prototype.append = function (data) {
+ this.hideLoading();
+
+ var $options = [];
+
+ if (data.results == null || data.results.length === 0) {
+ if (this.$results.children().length === 0) {
+ this.trigger('results:message', {
+ message: 'noResults'
+ });
+ }
+
+ return;
+ }
+
+ data.results = this.sort(data.results);
+
+ for (var d = 0; d < data.results.length; d++) {
+ var item = data.results[d];
+
+ var $option = this.option(item);
+
+ $options.push($option);
+ }
+
+ this.$results.append($options);
+ };
+
+ Results.prototype.position = function ($results, $dropdown) {
+ var $resultsContainer = $dropdown.find('.select2-results');
+ $resultsContainer.append($results);
+ };
+
+ Results.prototype.sort = function (data) {
+ var sorter = this.options.get('sorter');
+
+ return sorter(data);
+ };
+
+ Results.prototype.highlightFirstItem = function () {
+ var $options = this.$results
+ .find('.select2-results__option[aria-selected]');
+
+ var $selected = $options.filter('[aria-selected=true]');
+
+ // Check if there are any selected options
+ if ($selected.length > 0) {
+ // If there are selected options, highlight the first
+ $selected.first().trigger('mouseenter');
+ } else {
+ // If there are no selected options, highlight the first option
+ // in the dropdown
+ $options.first().trigger('mouseenter');
+ }
+
+ this.ensureHighlightVisible();
+ };
+
+ Results.prototype.setClasses = function () {
+ var self = this;
+
+ this.data.current(function (selected) {
+ var selectedIds = $.map(selected, function (s) {
+ return s.id.toString();
+ });
+
+ var $options = self.$results
+ .find('.select2-results__option[aria-selected]');
+
+ $options.each(function () {
+ var $option = $(this);
+
+ var item = $.data(this, 'data');
+
+ // id needs to be converted to a string when comparing
+ var id = '' + item.id;
+
+ if ((item.element != null && item.element.selected) ||
+ (item.element == null && $.inArray(id, selectedIds) > -1)) {
+ $option.attr('aria-selected', 'true');
+ } else {
+ $option.attr('aria-selected', 'false');
+ }
+ });
+
+ });
+ };
+
+ Results.prototype.showLoading = function (params) {
+ this.hideLoading();
+
+ var loadingMore = this.options.get('translations').get('searching');
+
+ var loading = {
+ disabled: true,
+ loading: true,
+ text: loadingMore(params)
+ };
+ var $loading = this.option(loading);
+ $loading.className += ' loading-results';
+
+ this.$results.prepend($loading);
+ };
+
+ Results.prototype.hideLoading = function () {
+ this.$results.find('.loading-results').remove();
+ };
+
+ Results.prototype.option = function (data) {
+ var option = document.createElement('li');
+ option.className = 'select2-results__option';
+
+ var attrs = {
+ 'role': 'treeitem',
+ 'aria-selected': 'false'
+ };
+
+ if (data.disabled) {
+ delete attrs['aria-selected'];
+ attrs['aria-disabled'] = 'true';
+ }
+
+ if (data.id == null) {
+ delete attrs['aria-selected'];
+ }
+
+ if (data._resultId != null) {
+ option.id = data._resultId;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ if (data.children) {
+ attrs.role = 'group';
+ attrs['aria-label'] = data.text;
+ delete attrs['aria-selected'];
+ }
+
+ for (var attr in attrs) {
+ var val = attrs[attr];
+
+ option.setAttribute(attr, val);
+ }
+
+ if (data.children) {
+ var $option = $(option);
+
+ var label = document.createElement('strong');
+ label.className = 'select2-results__group';
+
+ var $label = $(label);
+ this.template(data, label);
+
+ var $children = [];
+
+ for (var c = 0; c < data.children.length; c++) {
+ var child = data.children[c];
+
+ var $child = this.option(child);
+
+ $children.push($child);
+ }
+
+ var $childrenContainer = $('<ul></ul>', {
+ 'class': 'select2-results__options select2-results__options--nested'
+ });
+
+ $childrenContainer.append($children);
+
+ $option.append(label);
+ $option.append($childrenContainer);
+ } else {
+ this.template(data, option);
+ }
+
+ $.data(option, 'data', data);
+
+ return option;
+ };
+
+ Results.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var id = container.id + '-results';
+
+ this.$results.attr('id', id);
+
+ container.on('results:all', function (params) {
+ self.clear();
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('results:append', function (params) {
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ }
+ });
+
+ container.on('query', function (params) {
+ self.hideMessages();
+ self.showLoading(params);
+ });
+
+ container.on('select', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+ self.highlightFirstItem();
+ });
+
+ container.on('unselect', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+ self.highlightFirstItem();
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expended="true"
+ self.$results.attr('aria-expanded', 'true');
+ self.$results.attr('aria-hidden', 'false');
+
+ self.setClasses();
+ self.ensureHighlightVisible();
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expended="false"
+ self.$results.attr('aria-expanded', 'false');
+ self.$results.attr('aria-hidden', 'true');
+ self.$results.removeAttr('aria-activedescendant');
+ });
+
+ container.on('results:toggle', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ $highlighted.trigger('mouseup');
+ });
+
+ container.on('results:select', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var data = $highlighted.data('data');
+
+ if ($highlighted.attr('aria-selected') == 'true') {
+ self.trigger('close', {});
+ } else {
+ self.trigger('select', {
+ data: data
+ });
+ }
+ });
+
+ container.on('results:previous', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ // If we are already at te top, don't move further
+ if (currentIndex === 0) {
+ return;
+ }
+
+ var nextIndex = currentIndex - 1;
+
+ // If none are highlighted, highlight the first
+ if ($highlighted.length === 0) {
+ nextIndex = 0;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top;
+ var nextTop = $next.offset().top;
+ var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextTop - currentOffset < 0) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:next', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var nextIndex = currentIndex + 1;
+
+ // If we are at the last option, stay there
+ if (nextIndex >= $options.length) {
+ return;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top +
+ self.$results.outerHeight(false);
+ var nextBottom = $next.offset().top + $next.outerHeight(false);
+ var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextBottom > currentOffset) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ params.element.addClass('select2-results__option--highlighted');
+ });
+
+ container.on('results:message', function (params) {
+ self.displayMessage(params);
+ });
+
+ if ($.fn.mousewheel) {
+ this.$results.on('mousewheel', function (e) {
+ var top = self.$results.scrollTop();
+
+ var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
+
+ var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
+ var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
+
+ if (isAtTop) {
+ self.$results.scrollTop(0);
+
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (isAtBottom) {
+ self.$results.scrollTop(
+ self.$results.get(0).scrollHeight - self.$results.height()
+ );
+
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var $this = $(this);
+
+ var data = $this.data('data');
+
+ if ($this.attr('aria-selected') === 'true') {
+ if (self.options.get('multiple')) {
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ } else {
+ self.trigger('close', {});
+ }
+
+ return;
+ }
+
+ self.trigger('select', {
+ originalEvent: evt,
+ data: data
+ });
+ });
+
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var data = $(this).data('data');
+
+ self.getHighlightedResults()
+ .removeClass('select2-results__option--highlighted');
+
+ self.trigger('results:focus', {
+ data: data,
+ element: $(this)
+ });
+ });
+ };
+
+ Results.prototype.getHighlightedResults = function () {
+ var $highlighted = this.$results
+ .find('.select2-results__option--highlighted');
+
+ return $highlighted;
+ };
+
+ Results.prototype.destroy = function () {
+ this.$results.remove();
+ };
+
+ Results.prototype.ensureHighlightVisible = function () {
+ var $highlighted = this.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var $options = this.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var currentOffset = this.$results.offset().top;
+ var nextTop = $highlighted.offset().top;
+ var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
+
+ var offsetDelta = nextTop - currentOffset;
+ nextOffset -= $highlighted.outerHeight(false) * 2;
+
+ if (currentIndex <= 2) {
+ this.$results.scrollTop(0);
+ } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
+ this.$results.scrollTop(nextOffset);
+ }
+ };
+
+ Results.prototype.template = function (result, container) {
+ var template = this.options.get('templateResult');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ var content = template(result, container);
+
+ if (content == null) {
+ container.style.display = 'none';
+ } else if (typeof content === 'string') {
+ container.innerHTML = escapeMarkup(content);
+ } else {
+ $(container).append(content);
+ }
+ };
+
+ return Results;
+});
+
+S2.define('select2/keys',[
+
+], function () {
+ var KEYS = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ ESC: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ DELETE: 46
+ };
+
+ return KEYS;
+});
+
+S2.define('select2/selection/base',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function BaseSelection ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ BaseSelection.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseSelection, Utils.Observable);
+
+ BaseSelection.prototype.render = function () {
+ var $selection = $(
+ '<span class="select2-selection" role="combobox" ' +
+ ' aria-haspopup="true" aria-expanded="false">' +
+ '</span>'
+ );
+
+ this._tabindex = 0;
+
+ if (this.$element.data('old-tabindex') != null) {
+ this._tabindex = this.$element.data('old-tabindex');
+ } else if (this.$element.attr('tabindex') != null) {
+ this._tabindex = this.$element.attr('tabindex');
+ }
+
+ $selection.attr('title', this.$element.attr('title'));
+ $selection.attr('tabindex', this._tabindex);
+
+ this.$selection = $selection;
+
+ return $selection;
+ };
+
+ BaseSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var id = container.id + '-container';
+ var resultsId = container.id + '-results';
+
+ this.container = container;
+
+ this.$selection.on('focus', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('blur', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ if (evt.which === KEYS.SPACE) {
+ evt.preventDefault();
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ self.$selection.attr('aria-activedescendant', params.data._resultId);
+ });
+
+ container.on('selection:update', function (params) {
+ self.update(params.data);
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expanded="true"
+ self.$selection.attr('aria-expanded', 'true');
+ self.$selection.attr('aria-owns', resultsId);
+
+ self._attachCloseHandler(container);
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expanded="false"
+ self.$selection.attr('aria-expanded', 'false');
+ self.$selection.removeAttr('aria-activedescendant');
+ self.$selection.removeAttr('aria-owns');
+
+ self.$selection.focus();
+
+ self._detachCloseHandler(container);
+ });
+
+ container.on('enable', function () {
+ self.$selection.attr('tabindex', self._tabindex);
+ });
+
+ container.on('disable', function () {
+ self.$selection.attr('tabindex', '-1');
+ });
+ };
+
+ BaseSelection.prototype._handleBlur = function (evt) {
+ var self = this;
+
+ // This needs to be delayed as the active element is the body when the tab
+ // key is pressed, possibly along with others.
+ window.setTimeout(function () {
+ // Don't trigger `blur` if the focus is still in the selection
+ if (
+ (document.activeElement == self.$selection[0]) ||
+ ($.contains(self.$selection[0], document.activeElement))
+ ) {
+ return;
+ }
+
+ self.trigger('blur', evt);
+ }, 1);
+ };
+
+ BaseSelection.prototype._attachCloseHandler = function (container) {
+ var self = this;
+
+ $(document.body).on('mousedown.select2.' + container.id, function (e) {
+ var $target = $(e.target);
+
+ var $select = $target.closest('.select2');
+
+ var $all = $('.select2.select2-container--open');
+
+ $all.each(function () {
+ var $this = $(this);
+
+ if (this == $select[0]) {
+ return;
+ }
+
+ var $element = $this.data('element');
+
+ $element.select2('close');
+ });
+ });
+ };
+
+ BaseSelection.prototype._detachCloseHandler = function (container) {
+ $(document.body).off('mousedown.select2.' + container.id);
+ };
+
+ BaseSelection.prototype.position = function ($selection, $container) {
+ var $selectionContainer = $container.find('.selection');
+ $selectionContainer.append($selection);
+ };
+
+ BaseSelection.prototype.destroy = function () {
+ this._detachCloseHandler(this.container);
+ };
+
+ BaseSelection.prototype.update = function (data) {
+ throw new Error('The `update` method must be defined in child classes.');
+ };
+
+ return BaseSelection;
+});
+
+S2.define('select2/selection/single',[
+ 'jquery',
+ './base',
+ '../utils',
+ '../keys'
+], function ($, BaseSelection, Utils, KEYS) {
+ function SingleSelection () {
+ SingleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(SingleSelection, BaseSelection);
+
+ SingleSelection.prototype.render = function () {
+ var $selection = SingleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--single');
+
+ $selection.html(
+ '<span class="select2-selection__rendered"></span>' +
+ '<span class="select2-selection__arrow" role="presentation">' +
+ '<b role="presentation"></b>' +
+ '</span>'
+ );
+
+ return $selection;
+ };
+
+ SingleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ SingleSelection.__super__.bind.apply(this, arguments);
+
+ var id = container.id + '-container';
+
+ this.$selection.find('.select2-selection__rendered').attr('id', id);
+ this.$selection.attr('aria-labelledby', id);
+
+ this.$selection.on('mousedown', function (evt) {
+ // Only respond to left clicks
+ if (evt.which !== 1) {
+ return;
+ }
+
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on('focus', function (evt) {
+ // User focuses on the container
+ });
+
+ this.$selection.on('blur', function (evt) {
+ // User exits the container
+ });
+
+ container.on('focus', function (evt) {
+ if (!container.isOpen()) {
+ self.$selection.focus();
+ }
+ });
+
+ container.on('selection:update', function (params) {
+ self.update(params.data);
+ });
+ };
+
+ SingleSelection.prototype.clear = function () {
+ this.$selection.find('.select2-selection__rendered').empty();
+ };
+
+ SingleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ SingleSelection.prototype.selectionContainer = function () {
+ return $('<span></span>');
+ };
+
+ SingleSelection.prototype.update = function (data) {
+ if (data.length === 0) {
+ this.clear();
+ return;
+ }
+
+ var selection = data[0];
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ var formatted = this.display(selection, $rendered);
+
+ $rendered.empty().append(formatted);
+ $rendered.prop('title', selection.title || selection.text);
+ };
+
+ return SingleSelection;
+});
+
+S2.define('select2/selection/multiple',[
+ 'jquery',
+ './base',
+ '../utils'
+], function ($, BaseSelection, Utils) {
+ function MultipleSelection ($element, options) {
+ MultipleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(MultipleSelection, BaseSelection);
+
+ MultipleSelection.prototype.render = function () {
+ var $selection = MultipleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--multiple');
+
+ $selection.html(
+ '<ul class="select2-selection__rendered"></ul>'
+ );
+
+ return $selection;
+ };
+
+ MultipleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ MultipleSelection.__super__.bind.apply(this, arguments);
+
+ this.$selection.on('click', function (evt) {
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on(
+ 'click',
+ '.select2-selection__choice__remove',
+ function (evt) {
+ // Ignore the event if it is disabled
+ if (self.options.get('disabled')) {
+ return;
+ }
+
+ var $remove = $(this);
+ var $selection = $remove.parent();
+
+ var data = $selection.data('data');
+
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ }
+ );
+ };
+
+ MultipleSelection.prototype.clear = function () {
+ this.$selection.find('.select2-selection__rendered').empty();
+ };
+
+ MultipleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ MultipleSelection.prototype.selectionContainer = function () {
+ var $container = $(
+ '<li class="select2-selection__choice">' +
+ '<span class="select2-selection__choice__remove" role="presentation">' +
+ '&times;' +
+ '</span>' +
+ '</li>'
+ );
+
+ return $container;
+ };
+
+ MultipleSelection.prototype.update = function (data) {
+ this.clear();
+
+ if (data.length === 0) {
+ return;
+ }
+
+ var $selections = [];
+
+ for (var d = 0; d < data.length; d++) {
+ var selection = data[d];
+
+ var $selection = this.selectionContainer();
+ var formatted = this.display(selection, $selection);
+
+ $selection.append(formatted);
+ $selection.prop('title', selection.title || selection.text);
+
+ $selection.data('data', selection);
+
+ $selections.push($selection);
+ }
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+
+ Utils.appendMany($rendered, $selections);
+ };
+
+ return MultipleSelection;
+});
+
+S2.define('select2/selection/placeholder',[
+ '../utils'
+], function (Utils) {
+ function Placeholder (decorated, $element, options) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options);
+ }
+
+ Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
+ var $placeholder = this.selectionContainer();
+
+ $placeholder.html(this.display(placeholder));
+ $placeholder.addClass('select2-selection__placeholder')
+ .removeClass('select2-selection__choice');
+
+ return $placeholder;
+ };
+
+ Placeholder.prototype.update = function (decorated, data) {
+ var singlePlaceholder = (
+ data.length == 1 && data[0].id != this.placeholder.id
+ );
+ var multipleSelections = data.length > 1;
+
+ if (multipleSelections || singlePlaceholder) {
+ return decorated.call(this, data);
+ }
+
+ this.clear();
+
+ var $placeholder = this.createPlaceholder(this.placeholder);
+
+ this.$selection.find('.select2-selection__rendered').append($placeholder);
+ };
+
+ return Placeholder;
+});
+
+S2.define('select2/selection/allowClear',[
+ 'jquery',
+ '../keys'
+], function ($, KEYS) {
+ function AllowClear () { }
+
+ AllowClear.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ if (this.placeholder == null) {
+ if (this.options.get('debug') && window.console && console.error) {
+ console.error(
+ 'Select2: The `allowClear` option should be used in combination ' +
+ 'with the `placeholder` option.'
+ );
+ }
+ }
+
+ this.$selection.on('mousedown', '.select2-selection__clear',
+ function (evt) {
+ self._handleClear(evt);
+ });
+
+ container.on('keypress', function (evt) {
+ self._handleKeyboardClear(evt, container);
+ });
+ };
+
+ AllowClear.prototype._handleClear = function (_, evt) {
+ // Ignore the event if it is disabled
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ var $clear = this.$selection.find('.select2-selection__clear');
+
+ // Ignore the event if nothing has been selected
+ if ($clear.length === 0) {
+ return;
+ }
+
+ evt.stopPropagation();
+
+ var data = $clear.data('data');
+
+ for (var d = 0; d < data.length; d++) {
+ var unselectData = {
+ data: data[d]
+ };
+
+ // Trigger the `unselect` event, so people can prevent it from being
+ // cleared.
+ this.trigger('unselect', unselectData);
+
+ // If the event was prevented, don't clear it out.
+ if (unselectData.prevented) {
+ return;
+ }
+ }
+
+ this.$element.val(this.placeholder.id).trigger('change');
+
+ this.trigger('toggle', {});
+ };
+
+ AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
+ if (container.isOpen()) {
+ return;
+ }
+
+ if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
+ this._handleClear(evt);
+ }
+ };
+
+ AllowClear.prototype.update = function (decorated, data) {
+ decorated.call(this, data);
+
+ if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
+ data.length === 0) {
+ return;
+ }
+
+ var $remove = $(
+ '<span class="select2-selection__clear">' +
+ '&times;' +
+ '</span>'
+ );
+ $remove.data('data', data);
+
+ this.$selection.find('.select2-selection__rendered').prepend($remove);
+ };
+
+ return AllowClear;
+});
+
+S2.define('select2/selection/search',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function Search (decorated, $element, options) {
+ decorated.call(this, $element, options);
+ }
+
+ Search.prototype.render = function (decorated) {
+ var $search = $(
+ '<li class="select2-search select2-search--inline">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
+ ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
+ '</li>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ var $rendered = decorated.call(this);
+
+ this._transferTabIndex();
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self.$search.trigger('focus');
+ });
+
+ container.on('close', function () {
+ self.$search.val('');
+ self.$search.removeAttr('aria-activedescendant');
+ self.$search.trigger('focus');
+ });
+
+ container.on('enable', function () {
+ self.$search.prop('disabled', false);
+
+ self._transferTabIndex();
+ });
+
+ container.on('disable', function () {
+ self.$search.prop('disabled', true);
+ });
+
+ container.on('focus', function (evt) {
+ self.$search.trigger('focus');
+ });
+
+ container.on('results:focus', function (params) {
+ self.$search.attr('aria-activedescendant', params.id);
+ });
+
+ this.$selection.on('focusin', '.select2-search--inline', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('focusout', '.select2-search--inline', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', '.select2-search--inline', function (evt) {
+ evt.stopPropagation();
+
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+
+ var key = evt.which;
+
+ if (key === KEYS.BACKSPACE && self.$search.val() === '') {
+ var $previousChoice = self.$searchContainer
+ .prev('.select2-selection__choice');
+
+ if ($previousChoice.length > 0) {
+ var item = $previousChoice.data('data');
+
+ self.searchRemoveChoice(item);
+
+ evt.preventDefault();
+ }
+ }
+ });
+
+ // Try to detect the IE version should the `documentMode` property that
+ // is stored on the document. This is only implemented in IE and is
+ // slightly cleaner than doing a user agent check.
+ // This property is not available in Edge, but Edge also doesn't have
+ // this bug.
+ var msie = document.documentMode;
+ var disableInputEvents = msie && msie <= 11;
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$selection.on(
+ 'input.searchcheck',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents) {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ // Unbind the duplicated `keyup` event
+ self.$selection.off('keyup.search');
+ }
+ );
+
+ this.$selection.on(
+ 'keyup.search input.search',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents && evt.type === 'input') {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ var key = evt.which;
+
+ // We can freely ignore events from modifier keys
+ if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
+ return;
+ }
+
+ // Tabbing will be handled during the `keydown` phase
+ if (key == KEYS.TAB) {
+ return;
+ }
+
+ self.handleSearch(evt);
+ }
+ );
+ };
+
+ /**
+ * This method will transfer the tabindex attribute from the rendered
+ * selection to the search box. This allows for the search box to be used as
+ * the primary focus instead of the selection container.
+ *
+ * @private
+ */
+ Search.prototype._transferTabIndex = function (decorated) {
+ this.$search.attr('tabindex', this.$selection.attr('tabindex'));
+ this.$selection.attr('tabindex', '-1');
+ };
+
+ Search.prototype.createPlaceholder = function (decorated, placeholder) {
+ this.$search.attr('placeholder', placeholder.text);
+ };
+
+ Search.prototype.update = function (decorated, data) {
+ var searchHadFocus = this.$search[0] == document.activeElement;
+
+ this.$search.attr('placeholder', '');
+
+ decorated.call(this, data);
+
+ this.$selection.find('.select2-selection__rendered')
+ .append(this.$searchContainer);
+
+ this.resizeSearch();
+ if (searchHadFocus) {
+ this.$search.focus();
+ }
+ };
+
+ Search.prototype.handleSearch = function () {
+ this.resizeSearch();
+
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.searchRemoveChoice = function (decorated, item) {
+ this.trigger('unselect', {
+ data: item
+ });
+
+ this.$search.val(item.text);
+ this.handleSearch();
+ };
+
+ Search.prototype.resizeSearch = function () {
+ this.$search.css('width', '25px');
+
+ var width = '';
+
+ if (this.$search.attr('placeholder') !== '') {
+ width = this.$selection.find('.select2-selection__rendered').innerWidth();
+ } else {
+ var minimumWidth = this.$search.val().length + 1;
+
+ width = (minimumWidth * 0.75) + 'em';
+ }
+
+ this.$search.css('width', width);
+ };
+
+ return Search;
+});
+
+S2.define('select2/selection/eventRelay',[
+ 'jquery'
+], function ($) {
+ function EventRelay () { }
+
+ EventRelay.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+ var relayEvents = [
+ 'open', 'opening',
+ 'close', 'closing',
+ 'select', 'selecting',
+ 'unselect', 'unselecting'
+ ];
+
+ var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
+
+ decorated.call(this, container, $container);
+
+ container.on('*', function (name, params) {
+ // Ignore events that should not be relayed
+ if ($.inArray(name, relayEvents) === -1) {
+ return;
+ }
+
+ // The parameters should always be an object
+ params = params || {};
+
+ // Generate the jQuery event for the Select2 event
+ var evt = $.Event('select2:' + name, {
+ params: params
+ });
+
+ self.$element.trigger(evt);
+
+ // Only handle preventable events if it was one
+ if ($.inArray(name, preventableEvents) === -1) {
+ return;
+ }
+
+ params.prevented = evt.isDefaultPrevented();
+ });
+ };
+
+ return EventRelay;
+});
+
+S2.define('select2/translation',[
+ 'jquery',
+ 'require'
+], function ($, require) {
+ function Translation (dict) {
+ this.dict = dict || {};
+ }
+
+ Translation.prototype.all = function () {
+ return this.dict;
+ };
+
+ Translation.prototype.get = function (key) {
+ return this.dict[key];
+ };
+
+ Translation.prototype.extend = function (translation) {
+ this.dict = $.extend({}, translation.all(), this.dict);
+ };
+
+ // Static functions
+
+ Translation._cache = {};
+
+ Translation.loadPath = function (path) {
+ if (!(path in Translation._cache)) {
+ var translations = require(path);
+
+ Translation._cache[path] = translations;
+ }
+
+ return new Translation(Translation._cache[path]);
+ };
+
+ return Translation;
+});
+
+S2.define('select2/diacritics',[
+
+], function () {
+ var diacritics = {
+ '\u24B6': 'A',
+ '\uFF21': 'A',
+ '\u00C0': 'A',
+ '\u00C1': 'A',
+ '\u00C2': 'A',
+ '\u1EA6': 'A',
+ '\u1EA4': 'A',
+ '\u1EAA': 'A',
+ '\u1EA8': 'A',
+ '\u00C3': 'A',
+ '\u0100': 'A',
+ '\u0102': 'A',
+ '\u1EB0': 'A',
+ '\u1EAE': 'A',
+ '\u1EB4': 'A',
+ '\u1EB2': 'A',
+ '\u0226': 'A',
+ '\u01E0': 'A',
+ '\u00C4': 'A',
+ '\u01DE': 'A',
+ '\u1EA2': 'A',
+ '\u00C5': 'A',
+ '\u01FA': 'A',
+ '\u01CD': 'A',
+ '\u0200': 'A',
+ '\u0202': 'A',
+ '\u1EA0': 'A',
+ '\u1EAC': 'A',
+ '\u1EB6': 'A',
+ '\u1E00': 'A',
+ '\u0104': 'A',
+ '\u023A': 'A',
+ '\u2C6F': 'A',
+ '\uA732': 'AA',
+ '\u00C6': 'AE',
+ '\u01FC': 'AE',
+ '\u01E2': 'AE',
+ '\uA734': 'AO',
+ '\uA736': 'AU',
+ '\uA738': 'AV',
+ '\uA73A': 'AV',
+ '\uA73C': 'AY',
+ '\u24B7': 'B',
+ '\uFF22': 'B',
+ '\u1E02': 'B',
+ '\u1E04': 'B',
+ '\u1E06': 'B',
+ '\u0243': 'B',
+ '\u0182': 'B',
+ '\u0181': 'B',
+ '\u24B8': 'C',
+ '\uFF23': 'C',
+ '\u0106': 'C',
+ '\u0108': 'C',
+ '\u010A': 'C',
+ '\u010C': 'C',
+ '\u00C7': 'C',
+ '\u1E08': 'C',
+ '\u0187': 'C',
+ '\u023B': 'C',
+ '\uA73E': 'C',
+ '\u24B9': 'D',
+ '\uFF24': 'D',
+ '\u1E0A': 'D',
+ '\u010E': 'D',
+ '\u1E0C': 'D',
+ '\u1E10': 'D',
+ '\u1E12': 'D',
+ '\u1E0E': 'D',
+ '\u0110': 'D',
+ '\u018B': 'D',
+ '\u018A': 'D',
+ '\u0189': 'D',
+ '\uA779': 'D',
+ '\u01F1': 'DZ',
+ '\u01C4': 'DZ',
+ '\u01F2': 'Dz',
+ '\u01C5': 'Dz',
+ '\u24BA': 'E',
+ '\uFF25': 'E',
+ '\u00C8': 'E',
+ '\u00C9': 'E',
+ '\u00CA': 'E',
+ '\u1EC0': 'E',
+ '\u1EBE': 'E',
+ '\u1EC4': 'E',
+ '\u1EC2': 'E',
+ '\u1EBC': 'E',
+ '\u0112': 'E',
+ '\u1E14': 'E',
+ '\u1E16': 'E',
+ '\u0114': 'E',
+ '\u0116': 'E',
+ '\u00CB': 'E',
+ '\u1EBA': 'E',
+ '\u011A': 'E',
+ '\u0204': 'E',
+ '\u0206': 'E',
+ '\u1EB8': 'E',
+ '\u1EC6': 'E',
+ '\u0228': 'E',
+ '\u1E1C': 'E',
+ '\u0118': 'E',
+ '\u1E18': 'E',
+ '\u1E1A': 'E',
+ '\u0190': 'E',
+ '\u018E': 'E',
+ '\u24BB': 'F',
+ '\uFF26': 'F',
+ '\u1E1E': 'F',
+ '\u0191': 'F',
+ '\uA77B': 'F',
+ '\u24BC': 'G',
+ '\uFF27': 'G',
+ '\u01F4': 'G',
+ '\u011C': 'G',
+ '\u1E20': 'G',
+ '\u011E': 'G',
+ '\u0120': 'G',
+ '\u01E6': 'G',
+ '\u0122': 'G',
+ '\u01E4': 'G',
+ '\u0193': 'G',
+ '\uA7A0': 'G',
+ '\uA77D': 'G',
+ '\uA77E': 'G',
+ '\u24BD': 'H',
+ '\uFF28': 'H',
+ '\u0124': 'H',
+ '\u1E22': 'H',
+ '\u1E26': 'H',
+ '\u021E': 'H',
+ '\u1E24': 'H',
+ '\u1E28': 'H',
+ '\u1E2A': 'H',
+ '\u0126': 'H',
+ '\u2C67': 'H',
+ '\u2C75': 'H',
+ '\uA78D': 'H',
+ '\u24BE': 'I',
+ '\uFF29': 'I',
+ '\u00CC': 'I',
+ '\u00CD': 'I',
+ '\u00CE': 'I',
+ '\u0128': 'I',
+ '\u012A': 'I',
+ '\u012C': 'I',
+ '\u0130': 'I',
+ '\u00CF': 'I',
+ '\u1E2E': 'I',
+ '\u1EC8': 'I',
+ '\u01CF': 'I',
+ '\u0208': 'I',
+ '\u020A': 'I',
+ '\u1ECA': 'I',
+ '\u012E': 'I',
+ '\u1E2C': 'I',
+ '\u0197': 'I',
+ '\u24BF': 'J',
+ '\uFF2A': 'J',
+ '\u0134': 'J',
+ '\u0248': 'J',
+ '\u24C0': 'K',
+ '\uFF2B': 'K',
+ '\u1E30': 'K',
+ '\u01E8': 'K',
+ '\u1E32': 'K',
+ '\u0136': 'K',
+ '\u1E34': 'K',
+ '\u0198': 'K',
+ '\u2C69': 'K',
+ '\uA740': 'K',
+ '\uA742': 'K',
+ '\uA744': 'K',
+ '\uA7A2': 'K',
+ '\u24C1': 'L',
+ '\uFF2C': 'L',
+ '\u013F': 'L',
+ '\u0139': 'L',
+ '\u013D': 'L',
+ '\u1E36': 'L',
+ '\u1E38': 'L',
+ '\u013B': 'L',
+ '\u1E3C': 'L',
+ '\u1E3A': 'L',
+ '\u0141': 'L',
+ '\u023D': 'L',
+ '\u2C62': 'L',
+ '\u2C60': 'L',
+ '\uA748': 'L',
+ '\uA746': 'L',
+ '\uA780': 'L',
+ '\u01C7': 'LJ',
+ '\u01C8': 'Lj',
+ '\u24C2': 'M',
+ '\uFF2D': 'M',
+ '\u1E3E': 'M',
+ '\u1E40': 'M',
+ '\u1E42': 'M',
+ '\u2C6E': 'M',
+ '\u019C': 'M',
+ '\u24C3': 'N',
+ '\uFF2E': 'N',
+ '\u01F8': 'N',
+ '\u0143': 'N',
+ '\u00D1': 'N',
+ '\u1E44': 'N',
+ '\u0147': 'N',
+ '\u1E46': 'N',
+ '\u0145': 'N',
+ '\u1E4A': 'N',
+ '\u1E48': 'N',
+ '\u0220': 'N',
+ '\u019D': 'N',
+ '\uA790': 'N',
+ '\uA7A4': 'N',
+ '\u01CA': 'NJ',
+ '\u01CB': 'Nj',
+ '\u24C4': 'O',
+ '\uFF2F': 'O',
+ '\u00D2': 'O',
+ '\u00D3': 'O',
+ '\u00D4': 'O',
+ '\u1ED2': 'O',
+ '\u1ED0': 'O',
+ '\u1ED6': 'O',
+ '\u1ED4': 'O',
+ '\u00D5': 'O',
+ '\u1E4C': 'O',
+ '\u022C': 'O',
+ '\u1E4E': 'O',
+ '\u014C': 'O',
+ '\u1E50': 'O',
+ '\u1E52': 'O',
+ '\u014E': 'O',
+ '\u022E': 'O',
+ '\u0230': 'O',
+ '\u00D6': 'O',
+ '\u022A': 'O',
+ '\u1ECE': 'O',
+ '\u0150': 'O',
+ '\u01D1': 'O',
+ '\u020C': 'O',
+ '\u020E': 'O',
+ '\u01A0': 'O',
+ '\u1EDC': 'O',
+ '\u1EDA': 'O',
+ '\u1EE0': 'O',
+ '\u1EDE': 'O',
+ '\u1EE2': 'O',
+ '\u1ECC': 'O',
+ '\u1ED8': 'O',
+ '\u01EA': 'O',
+ '\u01EC': 'O',
+ '\u00D8': 'O',
+ '\u01FE': 'O',
+ '\u0186': 'O',
+ '\u019F': 'O',
+ '\uA74A': 'O',
+ '\uA74C': 'O',
+ '\u01A2': 'OI',
+ '\uA74E': 'OO',
+ '\u0222': 'OU',
+ '\u24C5': 'P',
+ '\uFF30': 'P',
+ '\u1E54': 'P',
+ '\u1E56': 'P',
+ '\u01A4': 'P',
+ '\u2C63': 'P',
+ '\uA750': 'P',
+ '\uA752': 'P',
+ '\uA754': 'P',
+ '\u24C6': 'Q',
+ '\uFF31': 'Q',
+ '\uA756': 'Q',
+ '\uA758': 'Q',
+ '\u024A': 'Q',
+ '\u24C7': 'R',
+ '\uFF32': 'R',
+ '\u0154': 'R',
+ '\u1E58': 'R',
+ '\u0158': 'R',
+ '\u0210': 'R',
+ '\u0212': 'R',
+ '\u1E5A': 'R',
+ '\u1E5C': 'R',
+ '\u0156': 'R',
+ '\u1E5E': 'R',
+ '\u024C': 'R',
+ '\u2C64': 'R',
+ '\uA75A': 'R',
+ '\uA7A6': 'R',
+ '\uA782': 'R',
+ '\u24C8': 'S',
+ '\uFF33': 'S',
+ '\u1E9E': 'S',
+ '\u015A': 'S',
+ '\u1E64': 'S',
+ '\u015C': 'S',
+ '\u1E60': 'S',
+ '\u0160': 'S',
+ '\u1E66': 'S',
+ '\u1E62': 'S',
+ '\u1E68': 'S',
+ '\u0218': 'S',
+ '\u015E': 'S',
+ '\u2C7E': 'S',
+ '\uA7A8': 'S',
+ '\uA784': 'S',
+ '\u24C9': 'T',
+ '\uFF34': 'T',
+ '\u1E6A': 'T',
+ '\u0164': 'T',
+ '\u1E6C': 'T',
+ '\u021A': 'T',
+ '\u0162': 'T',
+ '\u1E70': 'T',
+ '\u1E6E': 'T',
+ '\u0166': 'T',
+ '\u01AC': 'T',
+ '\u01AE': 'T',
+ '\u023E': 'T',
+ '\uA786': 'T',
+ '\uA728': 'TZ',
+ '\u24CA': 'U',
+ '\uFF35': 'U',
+ '\u00D9': 'U',
+ '\u00DA': 'U',
+ '\u00DB': 'U',
+ '\u0168': 'U',
+ '\u1E78': 'U',
+ '\u016A': 'U',
+ '\u1E7A': 'U',
+ '\u016C': 'U',
+ '\u00DC': 'U',
+ '\u01DB': 'U',
+ '\u01D7': 'U',
+ '\u01D5': 'U',
+ '\u01D9': 'U',
+ '\u1EE6': 'U',
+ '\u016E': 'U',
+ '\u0170': 'U',
+ '\u01D3': 'U',
+ '\u0214': 'U',
+ '\u0216': 'U',
+ '\u01AF': 'U',
+ '\u1EEA': 'U',
+ '\u1EE8': 'U',
+ '\u1EEE': 'U',
+ '\u1EEC': 'U',
+ '\u1EF0': 'U',
+ '\u1EE4': 'U',
+ '\u1E72': 'U',
+ '\u0172': 'U',
+ '\u1E76': 'U',
+ '\u1E74': 'U',
+ '\u0244': 'U',
+ '\u24CB': 'V',
+ '\uFF36': 'V',
+ '\u1E7C': 'V',
+ '\u1E7E': 'V',
+ '\u01B2': 'V',
+ '\uA75E': 'V',
+ '\u0245': 'V',
+ '\uA760': 'VY',
+ '\u24CC': 'W',
+ '\uFF37': 'W',
+ '\u1E80': 'W',
+ '\u1E82': 'W',
+ '\u0174': 'W',
+ '\u1E86': 'W',
+ '\u1E84': 'W',
+ '\u1E88': 'W',
+ '\u2C72': 'W',
+ '\u24CD': 'X',
+ '\uFF38': 'X',
+ '\u1E8A': 'X',
+ '\u1E8C': 'X',
+ '\u24CE': 'Y',
+ '\uFF39': 'Y',
+ '\u1EF2': 'Y',
+ '\u00DD': 'Y',
+ '\u0176': 'Y',
+ '\u1EF8': 'Y',
+ '\u0232': 'Y',
+ '\u1E8E': 'Y',
+ '\u0178': 'Y',
+ '\u1EF6': 'Y',
+ '\u1EF4': 'Y',
+ '\u01B3': 'Y',
+ '\u024E': 'Y',
+ '\u1EFE': 'Y',
+ '\u24CF': 'Z',
+ '\uFF3A': 'Z',
+ '\u0179': 'Z',
+ '\u1E90': 'Z',
+ '\u017B': 'Z',
+ '\u017D': 'Z',
+ '\u1E92': 'Z',
+ '\u1E94': 'Z',
+ '\u01B5': 'Z',
+ '\u0224': 'Z',
+ '\u2C7F': 'Z',
+ '\u2C6B': 'Z',
+ '\uA762': 'Z',
+ '\u24D0': 'a',
+ '\uFF41': 'a',
+ '\u1E9A': 'a',
+ '\u00E0': 'a',
+ '\u00E1': 'a',
+ '\u00E2': 'a',
+ '\u1EA7': 'a',
+ '\u1EA5': 'a',
+ '\u1EAB': 'a',
+ '\u1EA9': 'a',
+ '\u00E3': 'a',
+ '\u0101': 'a',
+ '\u0103': 'a',
+ '\u1EB1': 'a',
+ '\u1EAF': 'a',
+ '\u1EB5': 'a',
+ '\u1EB3': 'a',
+ '\u0227': 'a',
+ '\u01E1': 'a',
+ '\u00E4': 'a',
+ '\u01DF': 'a',
+ '\u1EA3': 'a',
+ '\u00E5': 'a',
+ '\u01FB': 'a',
+ '\u01CE': 'a',
+ '\u0201': 'a',
+ '\u0203': 'a',
+ '\u1EA1': 'a',
+ '\u1EAD': 'a',
+ '\u1EB7': 'a',
+ '\u1E01': 'a',
+ '\u0105': 'a',
+ '\u2C65': 'a',
+ '\u0250': 'a',
+ '\uA733': 'aa',
+ '\u00E6': 'ae',
+ '\u01FD': 'ae',
+ '\u01E3': 'ae',
+ '\uA735': 'ao',
+ '\uA737': 'au',
+ '\uA739': 'av',
+ '\uA73B': 'av',
+ '\uA73D': 'ay',
+ '\u24D1': 'b',
+ '\uFF42': 'b',
+ '\u1E03': 'b',
+ '\u1E05': 'b',
+ '\u1E07': 'b',
+ '\u0180': 'b',
+ '\u0183': 'b',
+ '\u0253': 'b',
+ '\u24D2': 'c',
+ '\uFF43': 'c',
+ '\u0107': 'c',
+ '\u0109': 'c',
+ '\u010B': 'c',
+ '\u010D': 'c',
+ '\u00E7': 'c',
+ '\u1E09': 'c',
+ '\u0188': 'c',
+ '\u023C': 'c',
+ '\uA73F': 'c',
+ '\u2184': 'c',
+ '\u24D3': 'd',
+ '\uFF44': 'd',
+ '\u1E0B': 'd',
+ '\u010F': 'd',
+ '\u1E0D': 'd',
+ '\u1E11': 'd',
+ '\u1E13': 'd',
+ '\u1E0F': 'd',
+ '\u0111': 'd',
+ '\u018C': 'd',
+ '\u0256': 'd',
+ '\u0257': 'd',
+ '\uA77A': 'd',
+ '\u01F3': 'dz',
+ '\u01C6': 'dz',
+ '\u24D4': 'e',
+ '\uFF45': 'e',
+ '\u00E8': 'e',
+ '\u00E9': 'e',
+ '\u00EA': 'e',
+ '\u1EC1': 'e',
+ '\u1EBF': 'e',
+ '\u1EC5': 'e',
+ '\u1EC3': 'e',
+ '\u1EBD': 'e',
+ '\u0113': 'e',
+ '\u1E15': 'e',
+ '\u1E17': 'e',
+ '\u0115': 'e',
+ '\u0117': 'e',
+ '\u00EB': 'e',
+ '\u1EBB': 'e',
+ '\u011B': 'e',
+ '\u0205': 'e',
+ '\u0207': 'e',
+ '\u1EB9': 'e',
+ '\u1EC7': 'e',
+ '\u0229': 'e',
+ '\u1E1D': 'e',
+ '\u0119': 'e',
+ '\u1E19': 'e',
+ '\u1E1B': 'e',
+ '\u0247': 'e',
+ '\u025B': 'e',
+ '\u01DD': 'e',
+ '\u24D5': 'f',
+ '\uFF46': 'f',
+ '\u1E1F': 'f',
+ '\u0192': 'f',
+ '\uA77C': 'f',
+ '\u24D6': 'g',
+ '\uFF47': 'g',
+ '\u01F5': 'g',
+ '\u011D': 'g',
+ '\u1E21': 'g',
+ '\u011F': 'g',
+ '\u0121': 'g',
+ '\u01E7': 'g',
+ '\u0123': 'g',
+ '\u01E5': 'g',
+ '\u0260': 'g',
+ '\uA7A1': 'g',
+ '\u1D79': 'g',
+ '\uA77F': 'g',
+ '\u24D7': 'h',
+ '\uFF48': 'h',
+ '\u0125': 'h',
+ '\u1E23': 'h',
+ '\u1E27': 'h',
+ '\u021F': 'h',
+ '\u1E25': 'h',
+ '\u1E29': 'h',
+ '\u1E2B': 'h',
+ '\u1E96': 'h',
+ '\u0127': 'h',
+ '\u2C68': 'h',
+ '\u2C76': 'h',
+ '\u0265': 'h',
+ '\u0195': 'hv',
+ '\u24D8': 'i',
+ '\uFF49': 'i',
+ '\u00EC': 'i',
+ '\u00ED': 'i',
+ '\u00EE': 'i',
+ '\u0129': 'i',
+ '\u012B': 'i',
+ '\u012D': 'i',
+ '\u00EF': 'i',
+ '\u1E2F': 'i',
+ '\u1EC9': 'i',
+ '\u01D0': 'i',
+ '\u0209': 'i',
+ '\u020B': 'i',
+ '\u1ECB': 'i',
+ '\u012F': 'i',
+ '\u1E2D': 'i',
+ '\u0268': 'i',
+ '\u0131': 'i',
+ '\u24D9': 'j',
+ '\uFF4A': 'j',
+ '\u0135': 'j',
+ '\u01F0': 'j',
+ '\u0249': 'j',
+ '\u24DA': 'k',
+ '\uFF4B': 'k',
+ '\u1E31': 'k',
+ '\u01E9': 'k',
+ '\u1E33': 'k',
+ '\u0137': 'k',
+ '\u1E35': 'k',
+ '\u0199': 'k',
+ '\u2C6A': 'k',
+ '\uA741': 'k',
+ '\uA743': 'k',
+ '\uA745': 'k',
+ '\uA7A3': 'k',
+ '\u24DB': 'l',
+ '\uFF4C': 'l',
+ '\u0140': 'l',
+ '\u013A': 'l',
+ '\u013E': 'l',
+ '\u1E37': 'l',
+ '\u1E39': 'l',
+ '\u013C': 'l',
+ '\u1E3D': 'l',
+ '\u1E3B': 'l',
+ '\u017F': 'l',
+ '\u0142': 'l',
+ '\u019A': 'l',
+ '\u026B': 'l',
+ '\u2C61': 'l',
+ '\uA749': 'l',
+ '\uA781': 'l',
+ '\uA747': 'l',
+ '\u01C9': 'lj',
+ '\u24DC': 'm',
+ '\uFF4D': 'm',
+ '\u1E3F': 'm',
+ '\u1E41': 'm',
+ '\u1E43': 'm',
+ '\u0271': 'm',
+ '\u026F': 'm',
+ '\u24DD': 'n',
+ '\uFF4E': 'n',
+ '\u01F9': 'n',
+ '\u0144': 'n',
+ '\u00F1': 'n',
+ '\u1E45': 'n',
+ '\u0148': 'n',
+ '\u1E47': 'n',
+ '\u0146': 'n',
+ '\u1E4B': 'n',
+ '\u1E49': 'n',
+ '\u019E': 'n',
+ '\u0272': 'n',
+ '\u0149': 'n',
+ '\uA791': 'n',
+ '\uA7A5': 'n',
+ '\u01CC': 'nj',
+ '\u24DE': 'o',
+ '\uFF4F': 'o',
+ '\u00F2': 'o',
+ '\u00F3': 'o',
+ '\u00F4': 'o',
+ '\u1ED3': 'o',
+ '\u1ED1': 'o',
+ '\u1ED7': 'o',
+ '\u1ED5': 'o',
+ '\u00F5': 'o',
+ '\u1E4D': 'o',
+ '\u022D': 'o',
+ '\u1E4F': 'o',
+ '\u014D': 'o',
+ '\u1E51': 'o',
+ '\u1E53': 'o',
+ '\u014F': 'o',
+ '\u022F': 'o',
+ '\u0231': 'o',
+ '\u00F6': 'o',
+ '\u022B': 'o',
+ '\u1ECF': 'o',
+ '\u0151': 'o',
+ '\u01D2': 'o',
+ '\u020D': 'o',
+ '\u020F': 'o',
+ '\u01A1': 'o',
+ '\u1EDD': 'o',
+ '\u1EDB': 'o',
+ '\u1EE1': 'o',
+ '\u1EDF': 'o',
+ '\u1EE3': 'o',
+ '\u1ECD': 'o',
+ '\u1ED9': 'o',
+ '\u01EB': 'o',
+ '\u01ED': 'o',
+ '\u00F8': 'o',
+ '\u01FF': 'o',
+ '\u0254': 'o',
+ '\uA74B': 'o',
+ '\uA74D': 'o',
+ '\u0275': 'o',
+ '\u01A3': 'oi',
+ '\u0223': 'ou',
+ '\uA74F': 'oo',
+ '\u24DF': 'p',
+ '\uFF50': 'p',
+ '\u1E55': 'p',
+ '\u1E57': 'p',
+ '\u01A5': 'p',
+ '\u1D7D': 'p',
+ '\uA751': 'p',
+ '\uA753': 'p',
+ '\uA755': 'p',
+ '\u24E0': 'q',
+ '\uFF51': 'q',
+ '\u024B': 'q',
+ '\uA757': 'q',
+ '\uA759': 'q',
+ '\u24E1': 'r',
+ '\uFF52': 'r',
+ '\u0155': 'r',
+ '\u1E59': 'r',
+ '\u0159': 'r',
+ '\u0211': 'r',
+ '\u0213': 'r',
+ '\u1E5B': 'r',
+ '\u1E5D': 'r',
+ '\u0157': 'r',
+ '\u1E5F': 'r',
+ '\u024D': 'r',
+ '\u027D': 'r',
+ '\uA75B': 'r',
+ '\uA7A7': 'r',
+ '\uA783': 'r',
+ '\u24E2': 's',
+ '\uFF53': 's',
+ '\u00DF': 's',
+ '\u015B': 's',
+ '\u1E65': 's',
+ '\u015D': 's',
+ '\u1E61': 's',
+ '\u0161': 's',
+ '\u1E67': 's',
+ '\u1E63': 's',
+ '\u1E69': 's',
+ '\u0219': 's',
+ '\u015F': 's',
+ '\u023F': 's',
+ '\uA7A9': 's',
+ '\uA785': 's',
+ '\u1E9B': 's',
+ '\u24E3': 't',
+ '\uFF54': 't',
+ '\u1E6B': 't',
+ '\u1E97': 't',
+ '\u0165': 't',
+ '\u1E6D': 't',
+ '\u021B': 't',
+ '\u0163': 't',
+ '\u1E71': 't',
+ '\u1E6F': 't',
+ '\u0167': 't',
+ '\u01AD': 't',
+ '\u0288': 't',
+ '\u2C66': 't',
+ '\uA787': 't',
+ '\uA729': 'tz',
+ '\u24E4': 'u',
+ '\uFF55': 'u',
+ '\u00F9': 'u',
+ '\u00FA': 'u',
+ '\u00FB': 'u',
+ '\u0169': 'u',
+ '\u1E79': 'u',
+ '\u016B': 'u',
+ '\u1E7B': 'u',
+ '\u016D': 'u',
+ '\u00FC': 'u',
+ '\u01DC': 'u',
+ '\u01D8': 'u',
+ '\u01D6': 'u',
+ '\u01DA': 'u',
+ '\u1EE7': 'u',
+ '\u016F': 'u',
+ '\u0171': 'u',
+ '\u01D4': 'u',
+ '\u0215': 'u',
+ '\u0217': 'u',
+ '\u01B0': 'u',
+ '\u1EEB': 'u',
+ '\u1EE9': 'u',
+ '\u1EEF': 'u',
+ '\u1EED': 'u',
+ '\u1EF1': 'u',
+ '\u1EE5': 'u',
+ '\u1E73': 'u',
+ '\u0173': 'u',
+ '\u1E77': 'u',
+ '\u1E75': 'u',
+ '\u0289': 'u',
+ '\u24E5': 'v',
+ '\uFF56': 'v',
+ '\u1E7D': 'v',
+ '\u1E7F': 'v',
+ '\u028B': 'v',
+ '\uA75F': 'v',
+ '\u028C': 'v',
+ '\uA761': 'vy',
+ '\u24E6': 'w',
+ '\uFF57': 'w',
+ '\u1E81': 'w',
+ '\u1E83': 'w',
+ '\u0175': 'w',
+ '\u1E87': 'w',
+ '\u1E85': 'w',
+ '\u1E98': 'w',
+ '\u1E89': 'w',
+ '\u2C73': 'w',
+ '\u24E7': 'x',
+ '\uFF58': 'x',
+ '\u1E8B': 'x',
+ '\u1E8D': 'x',
+ '\u24E8': 'y',
+ '\uFF59': 'y',
+ '\u1EF3': 'y',
+ '\u00FD': 'y',
+ '\u0177': 'y',
+ '\u1EF9': 'y',
+ '\u0233': 'y',
+ '\u1E8F': 'y',
+ '\u00FF': 'y',
+ '\u1EF7': 'y',
+ '\u1E99': 'y',
+ '\u1EF5': 'y',
+ '\u01B4': 'y',
+ '\u024F': 'y',
+ '\u1EFF': 'y',
+ '\u24E9': 'z',
+ '\uFF5A': 'z',
+ '\u017A': 'z',
+ '\u1E91': 'z',
+ '\u017C': 'z',
+ '\u017E': 'z',
+ '\u1E93': 'z',
+ '\u1E95': 'z',
+ '\u01B6': 'z',
+ '\u0225': 'z',
+ '\u0240': 'z',
+ '\u2C6C': 'z',
+ '\uA763': 'z',
+ '\u0386': '\u0391',
+ '\u0388': '\u0395',
+ '\u0389': '\u0397',
+ '\u038A': '\u0399',
+ '\u03AA': '\u0399',
+ '\u038C': '\u039F',
+ '\u038E': '\u03A5',
+ '\u03AB': '\u03A5',
+ '\u038F': '\u03A9',
+ '\u03AC': '\u03B1',
+ '\u03AD': '\u03B5',
+ '\u03AE': '\u03B7',
+ '\u03AF': '\u03B9',
+ '\u03CA': '\u03B9',
+ '\u0390': '\u03B9',
+ '\u03CC': '\u03BF',
+ '\u03CD': '\u03C5',
+ '\u03CB': '\u03C5',
+ '\u03B0': '\u03C5',
+ '\u03C9': '\u03C9',
+ '\u03C2': '\u03C3'
+ };
+
+ return diacritics;
+});
+
+S2.define('select2/data/base',[
+ '../utils'
+], function (Utils) {
+ function BaseAdapter ($element, options) {
+ BaseAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseAdapter, Utils.Observable);
+
+ BaseAdapter.prototype.current = function (callback) {
+ throw new Error('The `current` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.query = function (params, callback) {
+ throw new Error('The `query` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.bind = function (container, $container) {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.destroy = function () {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.generateResultId = function (container, data) {
+ var id = container.id + '-result-';
+
+ id += Utils.generateChars(4);
+
+ if (data.id != null) {
+ id += '-' + data.id.toString();
+ } else {
+ id += '-' + Utils.generateChars(4);
+ }
+ return id;
+ };
+
+ return BaseAdapter;
+});
+
+S2.define('select2/data/select',[
+ './base',
+ '../utils',
+ 'jquery'
+], function (BaseAdapter, Utils, $) {
+ function SelectAdapter ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ SelectAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(SelectAdapter, BaseAdapter);
+
+ SelectAdapter.prototype.current = function (callback) {
+ var data = [];
+ var self = this;
+
+ this.$element.find(':selected').each(function () {
+ var $option = $(this);
+
+ var option = self.item($option);
+
+ data.push(option);
+ });
+
+ callback(data);
+ };
+
+ SelectAdapter.prototype.select = function (data) {
+ var self = this;
+
+ data.selected = true;
+
+ // If data.element is a DOM node, use it instead
+ if ($(data.element).is('option')) {
+ data.element.selected = true;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ if (this.$element.prop('multiple')) {
+ this.current(function (currentData) {
+ var val = [];
+
+ data = [data];
+ data.push.apply(data, currentData);
+
+ for (var d = 0; d < data.length; d++) {
+ var id = data[d].id;
+
+ if ($.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+ self.$element.trigger('change');
+ });
+ } else {
+ var val = data.id;
+
+ this.$element.val(val);
+ this.$element.trigger('change');
+ }
+ };
+
+ SelectAdapter.prototype.unselect = function (data) {
+ var self = this;
+
+ if (!this.$element.prop('multiple')) {
+ return;
+ }
+
+ data.selected = false;
+
+ if ($(data.element).is('option')) {
+ data.element.selected = false;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ this.current(function (currentData) {
+ var val = [];
+
+ for (var d = 0; d < currentData.length; d++) {
+ var id = currentData[d].id;
+
+ if (id !== data.id && $.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+
+ self.$element.trigger('change');
+ });
+ };
+
+ SelectAdapter.prototype.bind = function (container, $container) {
+ var self = this;
+
+ this.container = container;
+
+ container.on('select', function (params) {
+ self.select(params.data);
+ });
+
+ container.on('unselect', function (params) {
+ self.unselect(params.data);
+ });
+ };
+
+ SelectAdapter.prototype.destroy = function () {
+ // Remove anything added to child elements
+ this.$element.find('*').each(function () {
+ // Remove any custom data set by Select2
+ $.removeData(this, 'data');
+ });
+ };
+
+ SelectAdapter.prototype.query = function (params, callback) {
+ var data = [];
+ var self = this;
+
+ var $options = this.$element.children();
+
+ $options.each(function () {
+ var $option = $(this);
+
+ if (!$option.is('option') && !$option.is('optgroup')) {
+ return;
+ }
+
+ var option = self.item($option);
+
+ var matches = self.matches(params, option);
+
+ if (matches !== null) {
+ data.push(matches);
+ }
+ });
+
+ callback({
+ results: data
+ });
+ };
+
+ SelectAdapter.prototype.addOptions = function ($options) {
+ Utils.appendMany(this.$element, $options);
+ };
+
+ SelectAdapter.prototype.option = function (data) {
+ var option;
+
+ if (data.children) {
+ option = document.createElement('optgroup');
+ option.label = data.text;
+ } else {
+ option = document.createElement('option');
+
+ if (option.textContent !== undefined) {
+ option.textContent = data.text;
+ } else {
+ option.innerText = data.text;
+ }
+ }
+
+ if (data.id) {
+ option.value = data.id;
+ }
+
+ if (data.disabled) {
+ option.disabled = true;
+ }
+
+ if (data.selected) {
+ option.selected = true;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ var $option = $(option);
+
+ var normalizedData = this._normalizeItem(data);
+ normalizedData.element = option;
+
+ // Override the option's data with the combined data
+ $.data(option, 'data', normalizedData);
+
+ return $option;
+ };
+
+ SelectAdapter.prototype.item = function ($option) {
+ var data = {};
+
+ data = $.data($option[0], 'data');
+
+ if (data != null) {
+ return data;
+ }
+
+ if ($option.is('option')) {
+ data = {
+ id: $option.val(),
+ text: $option.text(),
+ disabled: $option.prop('disabled'),
+ selected: $option.prop('selected'),
+ title: $option.prop('title')
+ };
+ } else if ($option.is('optgroup')) {
+ data = {
+ text: $option.prop('label'),
+ children: [],
+ title: $option.prop('title')
+ };
+
+ var $children = $option.children('option');
+ var children = [];
+
+ for (var c = 0; c < $children.length; c++) {
+ var $child = $($children[c]);
+
+ var child = this.item($child);
+
+ children.push(child);
+ }
+
+ data.children = children;
+ }
+
+ data = this._normalizeItem(data);
+ data.element = $option[0];
+
+ $.data($option[0], 'data', data);
+
+ return data;
+ };
+
+ SelectAdapter.prototype._normalizeItem = function (item) {
+ if (!$.isPlainObject(item)) {
+ item = {
+ id: item,
+ text: item
+ };
+ }
+
+ item = $.extend({}, {
+ text: ''
+ }, item);
+
+ var defaults = {
+ selected: false,
+ disabled: false
+ };
+
+ if (item.id != null) {
+ item.id = item.id.toString();
+ }
+
+ if (item.text != null) {
+ item.text = item.text.toString();
+ }
+
+ if (item._resultId == null && item.id && this.container != null) {
+ item._resultId = this.generateResultId(this.container, item);
+ }
+
+ return $.extend({}, defaults, item);
+ };
+
+ SelectAdapter.prototype.matches = function (params, data) {
+ var matcher = this.options.get('matcher');
+
+ return matcher(params, data);
+ };
+
+ return SelectAdapter;
+});
+
+S2.define('select2/data/array',[
+ './select',
+ '../utils',
+ 'jquery'
+], function (SelectAdapter, Utils, $) {
+ function ArrayAdapter ($element, options) {
+ var data = options.get('data') || [];
+
+ ArrayAdapter.__super__.constructor.call(this, $element, options);
+
+ this.addOptions(this.convertToOptions(data));
+ }
+
+ Utils.Extend(ArrayAdapter, SelectAdapter);
+
+ ArrayAdapter.prototype.select = function (data) {
+ var $option = this.$element.find('option').filter(function (i, elm) {
+ return elm.value == data.id.toString();
+ });
+
+ if ($option.length === 0) {
+ $option = this.option(data);
+
+ this.addOptions($option);
+ }
+
+ ArrayAdapter.__super__.select.call(this, data);
+ };
+
+ ArrayAdapter.prototype.convertToOptions = function (data) {
+ var self = this;
+
+ var $existing = this.$element.find('option');
+ var existingIds = $existing.map(function () {
+ return self.item($(this)).id;
+ }).get();
+
+ var $options = [];
+
+ // Filter out all items except for the one passed in the argument
+ function onlyItem (item) {
+ return function () {
+ return $(this).val() == item.id;
+ };
+ }
+
+ for (var d = 0; d < data.length; d++) {
+ var item = this._normalizeItem(data[d]);
+
+ // Skip items which were pre-loaded, only merge the data
+ if ($.inArray(item.id, existingIds) >= 0) {
+ var $existingOption = $existing.filter(onlyItem(item));
+
+ var existingData = this.item($existingOption);
+ var newData = $.extend(true, {}, item, existingData);
+
+ var $newOption = this.option(newData);
+
+ $existingOption.replaceWith($newOption);
+
+ continue;
+ }
+
+ var $option = this.option(item);
+
+ if (item.children) {
+ var $children = this.convertToOptions(item.children);
+
+ Utils.appendMany($option, $children);
+ }
+
+ $options.push($option);
+ }
+
+ return $options;
+ };
+
+ return ArrayAdapter;
+});
+
+S2.define('select2/data/ajax',[
+ './array',
+ '../utils',
+ 'jquery'
+], function (ArrayAdapter, Utils, $) {
+ function AjaxAdapter ($element, options) {
+ this.ajaxOptions = this._applyDefaults(options.get('ajax'));
+
+ if (this.ajaxOptions.processResults != null) {
+ this.processResults = this.ajaxOptions.processResults;
+ }
+
+ AjaxAdapter.__super__.constructor.call(this, $element, options);
+ }
+
+ Utils.Extend(AjaxAdapter, ArrayAdapter);
+
+ AjaxAdapter.prototype._applyDefaults = function (options) {
+ var defaults = {
+ data: function (params) {
+ return $.extend({}, params, {
+ q: params.term
+ });
+ },
+ transport: function (params, success, failure) {
+ var $request = $.ajax(params);
+
+ $request.then(success);
+ $request.fail(failure);
+
+ return $request;
+ }
+ };
+
+ return $.extend({}, defaults, options, true);
+ };
+
+ AjaxAdapter.prototype.processResults = function (results) {
+ return results;
+ };
+
+ AjaxAdapter.prototype.query = function (params, callback) {
+ var matches = [];
+ var self = this;
+
+ if (this._request != null) {
+ // JSONP requests cannot always be aborted
+ if ($.isFunction(this._request.abort)) {
+ this._request.abort();
+ }
+
+ this._request = null;
+ }
+
+ var options = $.extend({
+ type: 'GET'
+ }, this.ajaxOptions);
+
+ if (typeof options.url === 'function') {
+ options.url = options.url.call(this.$element, params);
+ }
+
+ if (typeof options.data === 'function') {
+ options.data = options.data.call(this.$element, params);
+ }
+
+ function request () {
+ var $request = options.transport(options, function (data) {
+ var results = self.processResults(data, params);
+
+ if (self.options.get('debug') && window.console && console.error) {
+ // Check to make sure that the response included a `results` key.
+ if (!results || !results.results || !$.isArray(results.results)) {
+ console.error(
+ 'Select2: The AJAX results did not return an array in the ' +
+ '`results` key of the response.'
+ );
+ }
+ }
+
+ callback(results);
+ }, function () {
+ // Attempt to detect if a request was aborted
+ // Only works if the transport exposes a status property
+ if ($request.status && $request.status === '0') {
+ return;
+ }
+
+ self.trigger('results:message', {
+ message: 'errorLoading'
+ });
+ });
+
+ self._request = $request;
+ }
+
+ if (this.ajaxOptions.delay && params.term != null) {
+ if (this._queryTimeout) {
+ window.clearTimeout(this._queryTimeout);
+ }
+
+ this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
+ } else {
+ request();
+ }
+ };
+
+ return AjaxAdapter;
+});
+
+S2.define('select2/data/tags',[
+ 'jquery'
+], function ($) {
+ function Tags (decorated, $element, options) {
+ var tags = options.get('tags');
+
+ var createTag = options.get('createTag');
+
+ if (createTag !== undefined) {
+ this.createTag = createTag;
+ }
+
+ var insertTag = options.get('insertTag');
+
+ if (insertTag !== undefined) {
+ this.insertTag = insertTag;
+ }
+
+ decorated.call(this, $element, options);
+
+ if ($.isArray(tags)) {
+ for (var t = 0; t < tags.length; t++) {
+ var tag = tags[t];
+ var item = this._normalizeItem(tag);
+
+ var $option = this.option(item);
+
+ this.$element.append($option);
+ }
+ }
+ }
+
+ Tags.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ this._removeOldTags();
+
+ if (params.term == null || params.page != null) {
+ decorated.call(this, params, callback);
+ return;
+ }
+
+ function wrapper (obj, child) {
+ var data = obj.results;
+
+ for (var i = 0; i < data.length; i++) {
+ var option = data[i];
+
+ var checkChildren = (
+ option.children != null &&
+ !wrapper({
+ results: option.children
+ }, true)
+ );
+
+ var checkText = option.text === params.term;
+
+ if (checkText || checkChildren) {
+ if (child) {
+ return false;
+ }
+
+ obj.data = data;
+ callback(obj);
+
+ return;
+ }
+ }
+
+ if (child) {
+ return true;
+ }
+
+ var tag = self.createTag(params);
+
+ if (tag != null) {
+ var $option = self.option(tag);
+ $option.attr('data-select2-tag', true);
+
+ self.addOptions([$option]);
+
+ self.insertTag(data, tag);
+ }
+
+ obj.results = data;
+
+ callback(obj);
+ }
+
+ decorated.call(this, params, wrapper);
+ };
+
+ Tags.prototype.createTag = function (decorated, params) {
+ var term = $.trim(params.term);
+
+ if (term === '') {
+ return null;
+ }
+
+ return {
+ id: term,
+ text: term
+ };
+ };
+
+ Tags.prototype.insertTag = function (_, data, tag) {
+ data.unshift(tag);
+ };
+
+ Tags.prototype._removeOldTags = function (_) {
+ var tag = this._lastTag;
+
+ var $options = this.$element.find('option[data-select2-tag]');
+
+ $options.each(function () {
+ if (this.selected) {
+ return;
+ }
+
+ $(this).remove();
+ });
+ };
+
+ return Tags;
+});
+
+S2.define('select2/data/tokenizer',[
+ 'jquery'
+], function ($) {
+ function Tokenizer (decorated, $element, options) {
+ var tokenizer = options.get('tokenizer');
+
+ if (tokenizer !== undefined) {
+ this.tokenizer = tokenizer;
+ }
+
+ decorated.call(this, $element, options);
+ }
+
+ Tokenizer.prototype.bind = function (decorated, container, $container) {
+ decorated.call(this, container, $container);
+
+ this.$search = container.dropdown.$search || container.selection.$search ||
+ $container.find('.select2-search__field');
+ };
+
+ Tokenizer.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ function createAndSelect (data) {
+ // Normalize the data object so we can use it for checks
+ var item = self._normalizeItem(data);
+
+ // Check if the data object already exists as a tag
+ // Select it if it doesn't
+ var $existingOptions = self.$element.find('option').filter(function () {
+ return $(this).val() === item.id;
+ });
+
+ // If an existing option wasn't found for it, create the option
+ if (!$existingOptions.length) {
+ var $option = self.option(item);
+ $option.attr('data-select2-tag', true);
+
+ self._removeOldTags();
+ self.addOptions([$option]);
+ }
+
+ // Select the item, now that we know there is an option for it
+ select(item);
+ }
+
+ function select (data) {
+ self.trigger('select', {
+ data: data
+ });
+ }
+
+ params.term = params.term || '';
+
+ var tokenData = this.tokenizer(params, this.options, createAndSelect);
+
+ if (tokenData.term !== params.term) {
+ // Replace the search term if we have the search box
+ if (this.$search.length) {
+ this.$search.val(tokenData.term);
+ this.$search.focus();
+ }
+
+ params.term = tokenData.term;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
+ var separators = options.get('tokenSeparators') || [];
+ var term = params.term;
+ var i = 0;
+
+ var createTag = this.createTag || function (params) {
+ return {
+ id: params.term,
+ text: params.term
+ };
+ };
+
+ while (i < term.length) {
+ var termChar = term[i];
+
+ if ($.inArray(termChar, separators) === -1) {
+ i++;
+
+ continue;
+ }
+
+ var part = term.substr(0, i);
+ var partParams = $.extend({}, params, {
+ term: part
+ });
+
+ var data = createTag(partParams);
+
+ if (data == null) {
+ i++;
+ continue;
+ }
+
+ callback(data);
+
+ // Reset the term to not include the tokenized portion
+ term = term.substr(i + 1) || '';
+ i = 0;
+ }
+
+ return {
+ term: term
+ };
+ };
+
+ return Tokenizer;
+});
+
+S2.define('select2/data/minimumInputLength',[
+
+], function () {
+ function MinimumInputLength (decorated, $e, options) {
+ this.minimumInputLength = options.get('minimumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MinimumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (params.term.length < this.minimumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooShort',
+ args: {
+ minimum: this.minimumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MinimumInputLength;
+});
+
+S2.define('select2/data/maximumInputLength',[
+
+], function () {
+ function MaximumInputLength (decorated, $e, options) {
+ this.maximumInputLength = options.get('maximumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (this.maximumInputLength > 0 &&
+ params.term.length > this.maximumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooLong',
+ args: {
+ maximum: this.maximumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MaximumInputLength;
+});
+
+S2.define('select2/data/maximumSelectionLength',[
+
+], function (){
+ function MaximumSelectionLength (decorated, $e, options) {
+ this.maximumSelectionLength = options.get('maximumSelectionLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumSelectionLength.prototype.query =
+ function (decorated, params, callback) {
+ var self = this;
+
+ this.current(function (currentData) {
+ var count = currentData != null ? currentData.length : 0;
+ if (self.maximumSelectionLength > 0 &&
+ count >= self.maximumSelectionLength) {
+ self.trigger('results:message', {
+ message: 'maximumSelected',
+ args: {
+ maximum: self.maximumSelectionLength
+ }
+ });
+ return;
+ }
+ decorated.call(self, params, callback);
+ });
+ };
+
+ return MaximumSelectionLength;
+});
+
+S2.define('select2/dropdown',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Dropdown ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ Dropdown.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Dropdown, Utils.Observable);
+
+ Dropdown.prototype.render = function () {
+ var $dropdown = $(
+ '<span class="select2-dropdown">' +
+ '<span class="select2-results"></span>' +
+ '</span>'
+ );
+
+ $dropdown.attr('dir', this.options.get('dir'));
+
+ this.$dropdown = $dropdown;
+
+ return $dropdown;
+ };
+
+ Dropdown.prototype.bind = function () {
+ // Should be implemented in subclasses
+ };
+
+ Dropdown.prototype.position = function ($dropdown, $container) {
+ // Should be implmented in subclasses
+ };
+
+ Dropdown.prototype.destroy = function () {
+ // Remove the dropdown from the DOM
+ this.$dropdown.remove();
+ };
+
+ return Dropdown;
+});
+
+S2.define('select2/dropdown/search',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function Search () { }
+
+ Search.prototype.render = function (decorated) {
+ var $rendered = decorated.call(this);
+
+ var $search = $(
+ '<span class="select2-search select2-search--dropdown">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
+ ' spellcheck="false" role="textbox" />' +
+ '</span>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ $rendered.prepend($search);
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ this.$search.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+ });
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$search.on('input', function (evt) {
+ // Unbind the duplicated `keyup` event
+ $(this).off('keyup');
+ });
+
+ this.$search.on('keyup input', function (evt) {
+ self.handleSearch(evt);
+ });
+
+ container.on('open', function () {
+ self.$search.attr('tabindex', 0);
+
+ self.$search.focus();
+
+ window.setTimeout(function () {
+ self.$search.focus();
+ }, 0);
+ });
+
+ container.on('close', function () {
+ self.$search.attr('tabindex', -1);
+
+ self.$search.val('');
+ });
+
+ container.on('focus', function () {
+ if (container.isOpen()) {
+ self.$search.focus();
+ }
+ });
+
+ container.on('results:all', function (params) {
+ if (params.query.term == null || params.query.term === '') {
+ var showSearch = self.showSearch(params);
+
+ if (showSearch) {
+ self.$searchContainer.removeClass('select2-search--hide');
+ } else {
+ self.$searchContainer.addClass('select2-search--hide');
+ }
+ }
+ });
+ };
+
+ Search.prototype.handleSearch = function (evt) {
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.showSearch = function (_, params) {
+ return true;
+ };
+
+ return Search;
+});
+
+S2.define('select2/dropdown/hidePlaceholder',[
+
+], function () {
+ function HidePlaceholder (decorated, $element, options, dataAdapter) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ HidePlaceholder.prototype.append = function (decorated, data) {
+ data.results = this.removePlaceholder(data.results);
+
+ decorated.call(this, data);
+ };
+
+ HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ HidePlaceholder.prototype.removePlaceholder = function (_, data) {
+ var modifiedData = data.slice(0);
+
+ for (var d = data.length - 1; d >= 0; d--) {
+ var item = data[d];
+
+ if (this.placeholder.id === item.id) {
+ modifiedData.splice(d, 1);
+ }
+ }
+
+ return modifiedData;
+ };
+
+ return HidePlaceholder;
+});
+
+S2.define('select2/dropdown/infiniteScroll',[
+ 'jquery'
+], function ($) {
+ function InfiniteScroll (decorated, $element, options, dataAdapter) {
+ this.lastParams = {};
+
+ decorated.call(this, $element, options, dataAdapter);
+
+ this.$loadingMore = this.createLoadingMore();
+ this.loading = false;
+ }
+
+ InfiniteScroll.prototype.append = function (decorated, data) {
+ this.$loadingMore.remove();
+ this.loading = false;
+
+ decorated.call(this, data);
+
+ if (this.showLoadingMore(data)) {
+ this.$results.append(this.$loadingMore);
+ }
+ };
+
+ InfiniteScroll.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('query', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ container.on('query:append', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ this.$results.on('scroll', function () {
+ var isLoadMoreVisible = $.contains(
+ document.documentElement,
+ self.$loadingMore[0]
+ );
+
+ if (self.loading || !isLoadMoreVisible) {
+ return;
+ }
+
+ var currentOffset = self.$results.offset().top +
+ self.$results.outerHeight(false);
+ var loadingMoreOffset = self.$loadingMore.offset().top +
+ self.$loadingMore.outerHeight(false);
+
+ if (currentOffset + 50 >= loadingMoreOffset) {
+ self.loadMore();
+ }
+ });
+ };
+
+ InfiniteScroll.prototype.loadMore = function () {
+ this.loading = true;
+
+ var params = $.extend({}, {page: 1}, this.lastParams);
+
+ params.page++;
+
+ this.trigger('query:append', params);
+ };
+
+ InfiniteScroll.prototype.showLoadingMore = function (_, data) {
+ return data.pagination && data.pagination.more;
+ };
+
+ InfiniteScroll.prototype.createLoadingMore = function () {
+ var $option = $(
+ '<li ' +
+ 'class="select2-results__option select2-results__option--load-more"' +
+ 'role="treeitem" aria-disabled="true"></li>'
+ );
+
+ var message = this.options.get('translations').get('loadingMore');
+
+ $option.html(message(this.lastParams));
+
+ return $option;
+ };
+
+ return InfiniteScroll;
+});
+
+S2.define('select2/dropdown/attachBody',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function AttachBody (decorated, $element, options) {
+ this.$dropdownParent = options.get('dropdownParent') || $(document.body);
+
+ decorated.call(this, $element, options);
+ }
+
+ AttachBody.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ var setupResultsEvents = false;
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self._showDropdown();
+ self._attachPositioningHandler(container);
+
+ if (!setupResultsEvents) {
+ setupResultsEvents = true;
+
+ container.on('results:all', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('results:append', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+ }
+ });
+
+ container.on('close', function () {
+ self._hideDropdown();
+ self._detachPositioningHandler(container);
+ });
+
+ this.$dropdownContainer.on('mousedown', function (evt) {
+ evt.stopPropagation();
+ });
+ };
+
+ AttachBody.prototype.destroy = function (decorated) {
+ decorated.call(this);
+
+ this.$dropdownContainer.remove();
+ };
+
+ AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+ // Clone all of the container classes
+ $dropdown.attr('class', $container.attr('class'));
+
+ $dropdown.removeClass('select2');
+ $dropdown.addClass('select2-container--open');
+
+ $dropdown.css({
+ position: 'absolute',
+ top: -999999
+ });
+
+ this.$container = $container;
+ };
+
+ AttachBody.prototype.render = function (decorated) {
+ var $container = $('<span></span>');
+
+ var $dropdown = decorated.call(this);
+ $container.append($dropdown);
+
+ this.$dropdownContainer = $container;
+
+ return $container;
+ };
+
+ AttachBody.prototype._hideDropdown = function (decorated) {
+ this.$dropdownContainer.detach();
+ };
+
+ AttachBody.prototype._attachPositioningHandler =
+ function (decorated, container) {
+ var self = this;
+
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.each(function () {
+ $(this).data('select2-scroll-position', {
+ x: $(this).scrollLeft(),
+ y: $(this).scrollTop()
+ });
+ });
+
+ $watchers.on(scrollEvent, function (ev) {
+ var position = $(this).data('select2-scroll-position');
+ $(this).scrollTop(position.y);
+ });
+
+ $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
+ function (e) {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+ };
+
+ AttachBody.prototype._detachPositioningHandler =
+ function (decorated, container) {
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.off(scrollEvent);
+
+ $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
+ };
+
+ AttachBody.prototype._positionDropdown = function () {
+ var $window = $(window);
+
+ var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
+ var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
+
+ var newDirection = null;
+
+ var offset = this.$container.offset();
+
+ offset.bottom = offset.top + this.$container.outerHeight(false);
+
+ var container = {
+ height: this.$container.outerHeight(false)
+ };
+
+ container.top = offset.top;
+ container.bottom = offset.top + container.height;
+
+ var dropdown = {
+ height: this.$dropdown.outerHeight(false)
+ };
+
+ var viewport = {
+ top: $window.scrollTop(),
+ bottom: $window.scrollTop() + $window.height()
+ };
+
+ var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
+ var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
+
+ var css = {
+ left: offset.left,
+ top: container.bottom
+ };
+
+ // Determine what the parent element is to use for calciulating the offset
+ var $offsetParent = this.$dropdownParent;
+
+ // For statically positoned elements, we need to get the element
+ // that is determining the offset
+ if ($offsetParent.css('position') === 'static') {
+ $offsetParent = $offsetParent.offsetParent();
+ }
+
+ var parentOffset = $offsetParent.offset();
+
+ css.top -= parentOffset.top;
+ css.left -= parentOffset.left;
+
+ if (!isCurrentlyAbove && !isCurrentlyBelow) {
+ newDirection = 'below';
+ }
+
+ if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
+ newDirection = 'above';
+ } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
+ newDirection = 'below';
+ }
+
+ if (newDirection == 'above' ||
+ (isCurrentlyAbove && newDirection !== 'below')) {
+ css.top = container.top - parentOffset.top - dropdown.height;
+ }
+
+ if (newDirection != null) {
+ this.$dropdown
+ .removeClass('select2-dropdown--below select2-dropdown--above')
+ .addClass('select2-dropdown--' + newDirection);
+ this.$container
+ .removeClass('select2-container--below select2-container--above')
+ .addClass('select2-container--' + newDirection);
+ }
+
+ this.$dropdownContainer.css(css);
+ };
+
+ AttachBody.prototype._resizeDropdown = function () {
+ var css = {
+ width: this.$container.outerWidth(false) + 'px'
+ };
+
+ if (this.options.get('dropdownAutoWidth')) {
+ css.minWidth = css.width;
+ css.position = 'relative';
+ css.width = 'auto';
+ }
+
+ this.$dropdown.css(css);
+ };
+
+ AttachBody.prototype._showDropdown = function (decorated) {
+ this.$dropdownContainer.appendTo(this.$dropdownParent);
+
+ this._positionDropdown();
+ this._resizeDropdown();
+ };
+
+ return AttachBody;
+});
+
+S2.define('select2/dropdown/minimumResultsForSearch',[
+
+], function () {
+ function countResults (data) {
+ var count = 0;
+
+ for (var d = 0; d < data.length; d++) {
+ var item = data[d];
+
+ if (item.children) {
+ count += countResults(item.children);
+ } else {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
+ this.minimumResultsForSearch = options.get('minimumResultsForSearch');
+
+ if (this.minimumResultsForSearch < 0) {
+ this.minimumResultsForSearch = Infinity;
+ }
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
+ if (countResults(params.data.results) < this.minimumResultsForSearch) {
+ return false;
+ }
+
+ return decorated.call(this, params);
+ };
+
+ return MinimumResultsForSearch;
+});
+
+S2.define('select2/dropdown/selectOnClose',[
+
+], function () {
+ function SelectOnClose () { }
+
+ SelectOnClose.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('close', function (params) {
+ self._handleSelectOnClose(params);
+ });
+ };
+
+ SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
+ if (params && params.originalSelect2Event != null) {
+ var event = params.originalSelect2Event;
+
+ // Don't select an item if the close event was triggered from a select or
+ // unselect event
+ if (event._type === 'select' || event._type === 'unselect') {
+ return;
+ }
+ }
+
+ var $highlightedResults = this.getHighlightedResults();
+
+ // Only select highlighted results
+ if ($highlightedResults.length < 1) {
+ return;
+ }
+
+ var data = $highlightedResults.data('data');
+
+ // Don't re-select already selected resulte
+ if (
+ (data.element != null && data.element.selected) ||
+ (data.element == null && data.selected)
+ ) {
+ return;
+ }
+
+ this.trigger('select', {
+ data: data
+ });
+ };
+
+ return SelectOnClose;
+});
+
+S2.define('select2/dropdown/closeOnSelect',[
+
+], function () {
+ function CloseOnSelect () { }
+
+ CloseOnSelect.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('select', function (evt) {
+ self._selectTriggered(evt);
+ });
+
+ container.on('unselect', function (evt) {
+ self._selectTriggered(evt);
+ });
+ };
+
+ CloseOnSelect.prototype._selectTriggered = function (_, evt) {
+ var originalEvent = evt.originalEvent;
+
+ // Don't close if the control key is being held
+ if (originalEvent && originalEvent.ctrlKey) {
+ return;
+ }
+
+ this.trigger('close', {
+ originalEvent: originalEvent,
+ originalSelect2Event: evt
+ });
+ };
+
+ return CloseOnSelect;
+});
+
+S2.define('select2/i18n/en',[],function () {
+ // English
+ return {
+ errorLoading: function () {
+ return 'The results could not be loaded.';
+ },
+ inputTooLong: function (args) {
+ var overChars = args.input.length - args.maximum;
+
+ var message = 'Please delete ' + overChars + ' character';
+
+ if (overChars != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ inputTooShort: function (args) {
+ var remainingChars = args.minimum - args.input.length;
+
+ var message = 'Please enter ' + remainingChars + ' or more characters';
+
+ return message;
+ },
+ loadingMore: function () {
+ return 'Loading more results…';
+ },
+ maximumSelected: function (args) {
+ var message = 'You can only select ' + args.maximum + ' item';
+
+ if (args.maximum != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ noResults: function () {
+ return 'No results found';
+ },
+ searching: function () {
+ return 'Searching…';
+ }
+ };
+});
+
+S2.define('select2/defaults',[
+ 'jquery',
+ 'require',
+
+ './results',
+
+ './selection/single',
+ './selection/multiple',
+ './selection/placeholder',
+ './selection/allowClear',
+ './selection/search',
+ './selection/eventRelay',
+
+ './utils',
+ './translation',
+ './diacritics',
+
+ './data/select',
+ './data/array',
+ './data/ajax',
+ './data/tags',
+ './data/tokenizer',
+ './data/minimumInputLength',
+ './data/maximumInputLength',
+ './data/maximumSelectionLength',
+
+ './dropdown',
+ './dropdown/search',
+ './dropdown/hidePlaceholder',
+ './dropdown/infiniteScroll',
+ './dropdown/attachBody',
+ './dropdown/minimumResultsForSearch',
+ './dropdown/selectOnClose',
+ './dropdown/closeOnSelect',
+
+ './i18n/en'
+], function ($, require,
+
+ ResultsList,
+
+ SingleSelection, MultipleSelection, Placeholder, AllowClear,
+ SelectionSearch, EventRelay,
+
+ Utils, Translation, DIACRITICS,
+
+ SelectData, ArrayData, AjaxData, Tags, Tokenizer,
+ MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
+
+ Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+ AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
+
+ EnglishTranslation) {
+ function Defaults () {
+ this.reset();
+ }
+
+ Defaults.prototype.apply = function (options) {
+ options = $.extend(true, {}, this.defaults, options);
+
+ if (options.dataAdapter == null) {
+ if (options.ajax != null) {
+ options.dataAdapter = AjaxData;
+ } else if (options.data != null) {
+ options.dataAdapter = ArrayData;
+ } else {
+ options.dataAdapter = SelectData;
+ }
+
+ if (options.minimumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MinimumInputLength
+ );
+ }
+
+ if (options.maximumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumInputLength
+ );
+ }
+
+ if (options.maximumSelectionLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumSelectionLength
+ );
+ }
+
+ if (options.tags) {
+ options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
+ }
+
+ if (options.tokenSeparators != null || options.tokenizer != null) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Tokenizer
+ );
+ }
+
+ if (options.query != null) {
+ var Query = require(options.amdBase + 'compat/query');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Query
+ );
+ }
+
+ if (options.initSelection != null) {
+ var InitSelection = require(options.amdBase + 'compat/initSelection');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ InitSelection
+ );
+ }
+ }
+
+ if (options.resultsAdapter == null) {
+ options.resultsAdapter = ResultsList;
+
+ if (options.ajax != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ InfiniteScroll
+ );
+ }
+
+ if (options.placeholder != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ HidePlaceholder
+ );
+ }
+
+ if (options.selectOnClose) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ SelectOnClose
+ );
+ }
+ }
+
+ if (options.dropdownAdapter == null) {
+ if (options.multiple) {
+ options.dropdownAdapter = Dropdown;
+ } else {
+ var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
+
+ options.dropdownAdapter = SearchableDropdown;
+ }
+
+ if (options.minimumResultsForSearch !== 0) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ MinimumResultsForSearch
+ );
+ }
+
+ if (options.closeOnSelect) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ CloseOnSelect
+ );
+ }
+
+ if (
+ options.dropdownCssClass != null ||
+ options.dropdownCss != null ||
+ options.adaptDropdownCssClass != null
+ ) {
+ var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ DropdownCSS
+ );
+ }
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ AttachBody
+ );
+ }
+
+ if (options.selectionAdapter == null) {
+ if (options.multiple) {
+ options.selectionAdapter = MultipleSelection;
+ } else {
+ options.selectionAdapter = SingleSelection;
+ }
+
+ // Add the placeholder mixin if a placeholder was specified
+ if (options.placeholder != null) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ Placeholder
+ );
+ }
+
+ if (options.allowClear) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ AllowClear
+ );
+ }
+
+ if (options.multiple) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ SelectionSearch
+ );
+ }
+
+ if (
+ options.containerCssClass != null ||
+ options.containerCss != null ||
+ options.adaptContainerCssClass != null
+ ) {
+ var ContainerCSS = require(options.amdBase + 'compat/containerCss');
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ ContainerCSS
+ );
+ }
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ EventRelay
+ );
+ }
+
+ if (typeof options.language === 'string') {
+ // Check if the language is specified with a region
+ if (options.language.indexOf('-') > 0) {
+ // Extract the region information if it is included
+ var languageParts = options.language.split('-');
+ var baseLanguage = languageParts[0];
+
+ options.language = [options.language, baseLanguage];
+ } else {
+ options.language = [options.language];
+ }
+ }
+
+ if ($.isArray(options.language)) {
+ var languages = new Translation();
+ options.language.push('en');
+
+ var languageNames = options.language;
+
+ for (var l = 0; l < languageNames.length; l++) {
+ var name = languageNames[l];
+ var language = {};
+
+ try {
+ // Try to load it with the original name
+ language = Translation.loadPath(name);
+ } catch (e) {
+ try {
+ // If we couldn't load it, check if it wasn't the full path
+ name = this.defaults.amdLanguageBase + name;
+ language = Translation.loadPath(name);
+ } catch (ex) {
+ // The translation could not be loaded at all. Sometimes this is
+ // because of a configuration problem, other times this can be
+ // because of how Select2 helps load all possible translation files.
+ if (options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The language file for "' + name + '" could not be ' +
+ 'automatically loaded. A fallback will be used instead.'
+ );
+ }
+
+ continue;
+ }
+ }
+
+ languages.extend(language);
+ }
+
+ options.translations = languages;
+ } else {
+ var baseTranslation = Translation.loadPath(
+ this.defaults.amdLanguageBase + 'en'
+ );
+ var customTranslation = new Translation(options.language);
+
+ customTranslation.extend(baseTranslation);
+
+ options.translations = customTranslation;
+ }
+
+ return options;
+ };
+
+ Defaults.prototype.reset = function () {
+ function stripDiacritics (text) {
+ // Used 'uni range + named function' from http://jsperf.com/diacritics/18
+ function match(a) {
+ return DIACRITICS[a] || a;
+ }
+
+ return text.replace(/[^\u0000-\u007E]/g, match);
+ }
+
+ function matcher (params, data) {
+ // Always return the object if there is nothing to compare
+ if ($.trim(params.term) === '') {
+ return data;
+ }
+
+ // Do a recursive check for options with children
+ if (data.children && data.children.length > 0) {
+ // Clone the data object if there are children
+ // This is required as we modify the object to remove any non-matches
+ var match = $.extend(true, {}, data);
+
+ // Check each child of the option
+ for (var c = data.children.length - 1; c >= 0; c--) {
+ var child = data.children[c];
+
+ var matches = matcher(params, child);
+
+ // If there wasn't a match, remove the object in the array
+ if (matches == null) {
+ match.children.splice(c, 1);
+ }
+ }
+
+ // If any children matched, return the new object
+ if (match.children.length > 0) {
+ return match;
+ }
+
+ // If there were no matching children, check just the plain object
+ return matcher(params, match);
+ }
+
+ var original = stripDiacritics(data.text).toUpperCase();
+ var term = stripDiacritics(params.term).toUpperCase();
+
+ // Check if the text contains the term
+ if (original.indexOf(term) > -1) {
+ return data;
+ }
+
+ // If it doesn't contain the term, don't return anything
+ return null;
+ }
+
+ this.defaults = {
+ amdBase: './',
+ amdLanguageBase: './i18n/',
+ closeOnSelect: true,
+ debug: false,
+ dropdownAutoWidth: false,
+ escapeMarkup: Utils.escapeMarkup,
+ language: EnglishTranslation,
+ matcher: matcher,
+ minimumInputLength: 0,
+ maximumInputLength: 0,
+ maximumSelectionLength: 0,
+ minimumResultsForSearch: 0,
+ selectOnClose: false,
+ sorter: function (data) {
+ return data;
+ },
+ templateResult: function (result) {
+ return result.text;
+ },
+ templateSelection: function (selection) {
+ return selection.text;
+ },
+ theme: 'default',
+ width: 'resolve'
+ };
+ };
+
+ Defaults.prototype.set = function (key, value) {
+ var camelKey = $.camelCase(key);
+
+ var data = {};
+ data[camelKey] = value;
+
+ var convertedData = Utils._convertData(data);
+
+ $.extend(this.defaults, convertedData);
+ };
+
+ var defaults = new Defaults();
+
+ return defaults;
+});
+
+S2.define('select2/options',[
+ 'require',
+ 'jquery',
+ './defaults',
+ './utils'
+], function (require, $, Defaults, Utils) {
+ function Options (options, $element) {
+ this.options = options;
+
+ if ($element != null) {
+ this.fromElement($element);
+ }
+
+ this.options = Defaults.apply(this.options);
+
+ if ($element && $element.is('input')) {
+ var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+ this.options.dataAdapter = Utils.Decorate(
+ this.options.dataAdapter,
+ InputCompat
+ );
+ }
+ }
+
+ Options.prototype.fromElement = function ($e) {
+ var excludedData = ['select2'];
+
+ if (this.options.multiple == null) {
+ this.options.multiple = $e.prop('multiple');
+ }
+
+ if (this.options.disabled == null) {
+ this.options.disabled = $e.prop('disabled');
+ }
+
+ if (this.options.language == null) {
+ if ($e.prop('lang')) {
+ this.options.language = $e.prop('lang').toLowerCase();
+ } else if ($e.closest('[lang]').prop('lang')) {
+ this.options.language = $e.closest('[lang]').prop('lang');
+ }
+ }
+
+ if (this.options.dir == null) {
+ if ($e.prop('dir')) {
+ this.options.dir = $e.prop('dir');
+ } else if ($e.closest('[dir]').prop('dir')) {
+ this.options.dir = $e.closest('[dir]').prop('dir');
+ } else {
+ this.options.dir = 'ltr';
+ }
+ }
+
+ $e.prop('disabled', this.options.disabled);
+ $e.prop('multiple', this.options.multiple);
+
+ if ($e.data('select2Tags')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-select2-tags` attribute has been changed to ' +
+ 'use the `data-data` and `data-tags="true"` attributes and will be ' +
+ 'removed in future versions of Select2.'
+ );
+ }
+
+ $e.data('data', $e.data('select2Tags'));
+ $e.data('tags', true);
+ }
+
+ if ($e.data('ajaxUrl')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-ajax-url` attribute has been changed to ' +
+ '`data-ajax--url` and support for the old attribute will be removed' +
+ ' in future versions of Select2.'
+ );
+ }
+
+ $e.attr('ajax--url', $e.data('ajaxUrl'));
+ $e.data('ajax--url', $e.data('ajaxUrl'));
+ }
+
+ var dataset = {};
+
+ // Prefer the element's `dataset` attribute if it exists
+ // jQuery 1.x does not correctly handle data attributes with multiple dashes
+ if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
+ dataset = $.extend(true, {}, $e[0].dataset, $e.data());
+ } else {
+ dataset = $e.data();
+ }
+
+ var data = $.extend(true, {}, dataset);
+
+ data = Utils._convertData(data);
+
+ for (var key in data) {
+ if ($.inArray(key, excludedData) > -1) {
+ continue;
+ }
+
+ if ($.isPlainObject(this.options[key])) {
+ $.extend(this.options[key], data[key]);
+ } else {
+ this.options[key] = data[key];
+ }
+ }
+
+ return this;
+ };
+
+ Options.prototype.get = function (key) {
+ return this.options[key];
+ };
+
+ Options.prototype.set = function (key, val) {
+ this.options[key] = val;
+ };
+
+ return Options;
+});
+
+S2.define('select2/core',[
+ 'jquery',
+ './options',
+ './utils',
+ './keys'
+], function ($, Options, Utils, KEYS) {
+ var Select2 = function ($element, options) {
+ if ($element.data('select2') != null) {
+ $element.data('select2').destroy();
+ }
+
+ this.$element = $element;
+
+ this.id = this._generateId($element);
+
+ options = options || {};
+
+ this.options = new Options(options, $element);
+
+ Select2.__super__.constructor.call(this);
+
+ // Set up the tabindex
+
+ var tabindex = $element.attr('tabindex') || 0;
+ $element.data('old-tabindex', tabindex);
+ $element.attr('tabindex', '-1');
+
+ // Set up containers and adapters
+
+ var DataAdapter = this.options.get('dataAdapter');
+ this.dataAdapter = new DataAdapter($element, this.options);
+
+ var $container = this.render();
+
+ this._placeContainer($container);
+
+ var SelectionAdapter = this.options.get('selectionAdapter');
+ this.selection = new SelectionAdapter($element, this.options);
+ this.$selection = this.selection.render();
+
+ this.selection.position(this.$selection, $container);
+
+ var DropdownAdapter = this.options.get('dropdownAdapter');
+ this.dropdown = new DropdownAdapter($element, this.options);
+ this.$dropdown = this.dropdown.render();
+
+ this.dropdown.position(this.$dropdown, $container);
+
+ var ResultsAdapter = this.options.get('resultsAdapter');
+ this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
+ this.$results = this.results.render();
+
+ this.results.position(this.$results, this.$dropdown);
+
+ // Bind events
+
+ var self = this;
+
+ // Bind the container to all of the adapters
+ this._bindAdapters();
+
+ // Register any DOM event handlers
+ this._registerDomEvents();
+
+ // Register any internal event handlers
+ this._registerDataEvents();
+ this._registerSelectionEvents();
+ this._registerDropdownEvents();
+ this._registerResultsEvents();
+ this._registerEvents();
+
+ // Set the initial state
+ this.dataAdapter.current(function (initialData) {
+ self.trigger('selection:update', {
+ data: initialData
+ });
+ });
+
+ // Hide the original select
+ $element.addClass('select2-hidden-accessible');
+ $element.attr('aria-hidden', 'true');
+
+ // Synchronize any monitored attributes
+ this._syncAttributes();
+
+ $element.data('select2', this);
+ };
+
+ Utils.Extend(Select2, Utils.Observable);
+
+ Select2.prototype._generateId = function ($element) {
+ var id = '';
+
+ if ($element.attr('id') != null) {
+ id = $element.attr('id');
+ } else if ($element.attr('name') != null) {
+ id = $element.attr('name') + '-' + Utils.generateChars(2);
+ } else {
+ id = Utils.generateChars(4);
+ }
+
+ id = id.replace(/(:|\.|\[|\]|,)/g, '');
+ id = 'select2-' + id;
+
+ return id;
+ };
+
+ Select2.prototype._placeContainer = function ($container) {
+ $container.insertAfter(this.$element);
+
+ var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+ if (width != null) {
+ $container.css('width', width);
+ }
+ };
+
+ Select2.prototype._resolveWidth = function ($element, method) {
+ var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+ if (method == 'resolve') {
+ var styleWidth = this._resolveWidth($element, 'style');
+
+ if (styleWidth != null) {
+ return styleWidth;
+ }
+
+ return this._resolveWidth($element, 'element');
+ }
+
+ if (method == 'element') {
+ var elementWidth = $element.outerWidth(false);
+
+ if (elementWidth <= 0) {
+ return 'auto';
+ }
+
+ return elementWidth + 'px';
+ }
+
+ if (method == 'style') {
+ var style = $element.attr('style');
+
+ if (typeof(style) !== 'string') {
+ return null;
+ }
+
+ var attrs = style.split(';');
+
+ for (var i = 0, l = attrs.length; i < l; i = i + 1) {
+ var attr = attrs[i].replace(/\s/g, '');
+ var matches = attr.match(WIDTH);
+
+ if (matches !== null && matches.length >= 1) {
+ return matches[1];
+ }
+ }
+
+ return null;
+ }
+
+ return method;
+ };
+
+ Select2.prototype._bindAdapters = function () {
+ this.dataAdapter.bind(this, this.$container);
+ this.selection.bind(this, this.$container);
+
+ this.dropdown.bind(this, this.$container);
+ this.results.bind(this, this.$container);
+ };
+
+ Select2.prototype._registerDomEvents = function () {
+ var self = this;
+
+ this.$element.on('change.select2', function () {
+ self.dataAdapter.current(function (data) {
+ self.trigger('selection:update', {
+ data: data
+ });
+ });
+ });
+
+ this.$element.on('focus.select2', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this._syncA = Utils.bind(this._syncAttributes, this);
+ this._syncS = Utils.bind(this._syncSubtree, this);
+
+ if (this.$element[0].attachEvent) {
+ this.$element[0].attachEvent('onpropertychange', this._syncA);
+ }
+
+ var observer = window.MutationObserver ||
+ window.WebKitMutationObserver ||
+ window.MozMutationObserver
+ ;
+
+ if (observer != null) {
+ this._observer = new observer(function (mutations) {
+ $.each(mutations, self._syncA);
+ $.each(mutations, self._syncS);
+ });
+ this._observer.observe(this.$element[0], {
+ attributes: true,
+ childList: true,
+ subtree: false
+ });
+ } else if (this.$element[0].addEventListener) {
+ this.$element[0].addEventListener(
+ 'DOMAttrModified',
+ self._syncA,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeInserted',
+ self._syncS,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeRemoved',
+ self._syncS,
+ false
+ );
+ }
+ };
+
+ Select2.prototype._registerDataEvents = function () {
+ var self = this;
+
+ this.dataAdapter.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerSelectionEvents = function () {
+ var self = this;
+ var nonRelayEvents = ['toggle', 'focus'];
+
+ this.selection.on('toggle', function () {
+ self.toggleDropdown();
+ });
+
+ this.selection.on('focus', function (params) {
+ self.focus(params);
+ });
+
+ this.selection.on('*', function (name, params) {
+ if ($.inArray(name, nonRelayEvents) !== -1) {
+ return;
+ }
+
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerDropdownEvents = function () {
+ var self = this;
+
+ this.dropdown.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerResultsEvents = function () {
+ var self = this;
+
+ this.results.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerEvents = function () {
+ var self = this;
+
+ this.on('open', function () {
+ self.$container.addClass('select2-container--open');
+ });
+
+ this.on('close', function () {
+ self.$container.removeClass('select2-container--open');
+ });
+
+ this.on('enable', function () {
+ self.$container.removeClass('select2-container--disabled');
+ });
+
+ this.on('disable', function () {
+ self.$container.addClass('select2-container--disabled');
+ });
+
+ this.on('blur', function () {
+ self.$container.removeClass('select2-container--focus');
+ });
+
+ this.on('query', function (params) {
+ if (!self.isOpen()) {
+ self.trigger('open', {});
+ }
+
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:all', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('query:append', function (params) {
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:append', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('keypress', function (evt) {
+ var key = evt.which;
+
+ if (self.isOpen()) {
+ if (key === KEYS.ESC || key === KEYS.TAB ||
+ (key === KEYS.UP && evt.altKey)) {
+ self.close();
+
+ evt.preventDefault();
+ } else if (key === KEYS.ENTER) {
+ self.trigger('results:select', {});
+
+ evt.preventDefault();
+ } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
+ self.trigger('results:toggle', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.UP) {
+ self.trigger('results:previous', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.DOWN) {
+ self.trigger('results:next', {});
+
+ evt.preventDefault();
+ }
+ } else {
+ if (key === KEYS.ENTER || key === KEYS.SPACE ||
+ (key === KEYS.DOWN && evt.altKey)) {
+ self.open();
+
+ evt.preventDefault();
+ }
+ }
+ });
+ };
+
+ Select2.prototype._syncAttributes = function () {
+ this.options.set('disabled', this.$element.prop('disabled'));
+
+ if (this.options.get('disabled')) {
+ if (this.isOpen()) {
+ this.close();
+ }
+
+ this.trigger('disable', {});
+ } else {
+ this.trigger('enable', {});
+ }
+ };
+
+ Select2.prototype._syncSubtree = function (evt, mutations) {
+ var changed = false;
+ var self = this;
+
+ // Ignore any mutation events raised for elements that aren't options or
+ // optgroups. This handles the case when the select element is destroyed
+ if (
+ evt && evt.target && (
+ evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
+ )
+ ) {
+ return;
+ }
+
+ if (!mutations) {
+ // If mutation events aren't supported, then we can only assume that the
+ // change affected the selections
+ changed = true;
+ } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
+ for (var n = 0; n < mutations.addedNodes.length; n++) {
+ var node = mutations.addedNodes[n];
+
+ if (node.selected) {
+ changed = true;
+ }
+ }
+ } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
+ changed = true;
+ }
+
+ // Only re-pull the data if we think there is a change
+ if (changed) {
+ this.dataAdapter.current(function (currentData) {
+ self.trigger('selection:update', {
+ data: currentData
+ });
+ });
+ }
+ };
+
+ /**
+ * Override the trigger method to automatically trigger pre-events when
+ * there are events that can be prevented.
+ */
+ Select2.prototype.trigger = function (name, args) {
+ var actualTrigger = Select2.__super__.trigger;
+ var preTriggerMap = {
+ 'open': 'opening',
+ 'close': 'closing',
+ 'select': 'selecting',
+ 'unselect': 'unselecting'
+ };
+
+ if (args === undefined) {
+ args = {};
+ }
+
+ if (name in preTriggerMap) {
+ var preTriggerName = preTriggerMap[name];
+ var preTriggerArgs = {
+ prevented: false,
+ name: name,
+ args: args
+ };
+
+ actualTrigger.call(this, preTriggerName, preTriggerArgs);
+
+ if (preTriggerArgs.prevented) {
+ args.prevented = true;
+
+ return;
+ }
+ }
+
+ actualTrigger.call(this, name, args);
+ };
+
+ Select2.prototype.toggleDropdown = function () {
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ if (this.isOpen()) {
+ this.close();
+ } else {
+ this.open();
+ }
+ };
+
+ Select2.prototype.open = function () {
+ if (this.isOpen()) {
+ return;
+ }
+
+ this.trigger('query', {});
+ };
+
+ Select2.prototype.close = function () {
+ if (!this.isOpen()) {
+ return;
+ }
+
+ this.trigger('close', {});
+ };
+
+ Select2.prototype.isOpen = function () {
+ return this.$container.hasClass('select2-container--open');
+ };
+
+ Select2.prototype.hasFocus = function () {
+ return this.$container.hasClass('select2-container--focus');
+ };
+
+ Select2.prototype.focus = function (data) {
+ // No need to re-trigger focus events if we are already focused
+ if (this.hasFocus()) {
+ return;
+ }
+
+ this.$container.addClass('select2-container--focus');
+ this.trigger('focus', {});
+ };
+
+ Select2.prototype.enable = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("enable")` method has been deprecated and will' +
+ ' be removed in later Select2 versions. Use $element.prop("disabled")' +
+ ' instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ args = [true];
+ }
+
+ var disabled = !args[0];
+
+ this.$element.prop('disabled', disabled);
+ };
+
+ Select2.prototype.data = function () {
+ if (this.options.get('debug') &&
+ arguments.length > 0 && window.console && console.warn) {
+ console.warn(
+ 'Select2: Data can no longer be set using `select2("data")`. You ' +
+ 'should consider setting the value instead using `$element.val()`.'
+ );
+ }
+
+ var data = [];
+
+ this.dataAdapter.current(function (currentData) {
+ data = currentData;
+ });
+
+ return data;
+ };
+
+ Select2.prototype.val = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("val")` method has been deprecated and will be' +
+ ' removed in later Select2 versions. Use $element.val() instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ return this.$element.val();
+ }
+
+ var newVal = args[0];
+
+ if ($.isArray(newVal)) {
+ newVal = $.map(newVal, function (obj) {
+ return obj.toString();
+ });
+ }
+
+ this.$element.val(newVal).trigger('change');
+ };
+
+ Select2.prototype.destroy = function () {
+ this.$container.remove();
+
+ if (this.$element[0].detachEvent) {
+ this.$element[0].detachEvent('onpropertychange', this._syncA);
+ }
+
+ if (this._observer != null) {
+ this._observer.disconnect();
+ this._observer = null;
+ } else if (this.$element[0].removeEventListener) {
+ this.$element[0]
+ .removeEventListener('DOMAttrModified', this._syncA, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeInserted', this._syncS, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeRemoved', this._syncS, false);
+ }
+
+ this._syncA = null;
+ this._syncS = null;
+
+ this.$element.off('.select2');
+ this.$element.attr('tabindex', this.$element.data('old-tabindex'));
+
+ this.$element.removeClass('select2-hidden-accessible');
+ this.$element.attr('aria-hidden', 'false');
+ this.$element.removeData('select2');
+
+ this.dataAdapter.destroy();
+ this.selection.destroy();
+ this.dropdown.destroy();
+ this.results.destroy();
+
+ this.dataAdapter = null;
+ this.selection = null;
+ this.dropdown = null;
+ this.results = null;
+ };
+
+ Select2.prototype.render = function () {
+ var $container = $(
+ '<span class="select2 select2-container">' +
+ '<span class="selection"></span>' +
+ '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
+ '</span>'
+ );
+
+ $container.attr('dir', this.options.get('dir'));
+
+ this.$container = $container;
+
+ this.$container.addClass('select2-container--' + this.options.get('theme'));
+
+ $container.data('element', this.$element);
+
+ return $container;
+ };
+
+ return Select2;
+});
+
+S2.define('jquery-mousewheel',[
+ 'jquery'
+], function ($) {
+ // Used to shim jQuery.mousewheel for non-full builds.
+ return $;
+});
+
+S2.define('jquery.select2',[
+ 'jquery',
+ 'jquery-mousewheel',
+
+ './select2/core',
+ './select2/defaults'
+], function ($, _, Select2, Defaults) {
+ if ($.fn.select2 == null) {
+ // All methods that should return the element
+ var thisMethods = ['open', 'close', 'destroy'];
+
+ $.fn.select2 = function (options) {
+ options = options || {};
+
+ if (typeof options === 'object') {
+ this.each(function () {
+ var instanceOptions = $.extend(true, {}, options);
+
+ var instance = new Select2($(this), instanceOptions);
+ });
+
+ return this;
+ } else if (typeof options === 'string') {
+ var ret;
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ this.each(function () {
+ var instance = $(this).data('select2');
+
+ if (instance == null && window.console && console.error) {
+ console.error(
+ 'The select2(\'' + options + '\') method was called on an ' +
+ 'element that is not using Select2.'
+ );
+ }
+
+ ret = instance[options].apply(instance, args);
+ });
+
+ // Check if we should be returning `this`
+ if ($.inArray(options, thisMethods) > -1) {
+ return this;
+ }
+
+ return ret;
+ } else {
+ throw new Error('Invalid arguments for Select2: ' + options);
+ }
+ };
+ }
+
+ if ($.fn.select2.defaults == null) {
+ $.fn.select2.defaults = Defaults;
+ }
+
+ return Select2;
+});
+
+ // Return the AMD loader configuration so it can be used outside of this file
+ return {
+ define: S2.define,
+ require: S2.require
+ };
+}());
+
+ // Autoload the jQuery bindings
+ // We know that all of the modules exist above this, so we're safe
+ var select2 = S2.require('jquery.select2');
+
+ // Hold the AMD module references on the jQuery function that was just loaded
+ // This allows Select2 to use the internal loader outside of this file, such
+ // as in the language files.
+ jQuery.fn.select2.amd = S2;
+
+ // Return the Select2 instance for anyone who is importing it.
+ return select2;
+}));
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.slider.js b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.slider.js
new file mode 100644
index 00000000..2fe2c8dd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/js/ext.srf.filtered.slider.js
@@ -0,0 +1,2450 @@
+// Ion.RangeSlider
+// version 2.2.0 Build: 380
+// © Denis Ineshin, 2017
+// https://github.com/IonDen
+//
+// Project page: http://ionden.com/a/plugins/ion.rangeSlider/en.html
+// GitHub page: https://github.com/IonDen/ion.rangeSlider
+//
+// Released under MIT licence:
+// http://ionden.com/a/plugins/licence-en.html
+// =====================================================================================================================
+
+;(function(factory) {
+ if (typeof define === "function" && define.amd) {
+ define(["jquery"], function (jQuery) {
+ return factory(jQuery, document, window, navigator);
+ });
+ } else if (typeof exports === "object") {
+ factory(require("jquery"), document, window, navigator);
+ } else {
+ factory(jQuery, document, window, navigator);
+ }
+} (function ($, document, window, navigator, undefined) {
+ "use strict";
+
+ // =================================================================================================================
+ // Service
+
+ var plugin_count = 0;
+
+ // IE8 fix
+ var is_old_ie = (function () {
+ var n = navigator.userAgent,
+ r = /msie\s\d+/i,
+ v;
+ if (n.search(r) > 0) {
+ v = r.exec(n).toString();
+ v = v.split(" ")[1];
+ if (v < 9) {
+ $("html").addClass("lt-ie9");
+ return true;
+ }
+ }
+ return false;
+ } ());
+ if (!Function.prototype.bind) {
+ Function.prototype.bind = function bind(that) {
+
+ var target = this;
+ var slice = [].slice;
+
+ if (typeof target != "function") {
+ throw new TypeError();
+ }
+
+ var args = slice.call(arguments, 1),
+ bound = function () {
+
+ if (this instanceof bound) {
+
+ var F = function(){};
+ F.prototype = target.prototype;
+ var self = new F();
+
+ var result = target.apply(
+ self,
+ args.concat(slice.call(arguments))
+ );
+ if (Object(result) === result) {
+ return result;
+ }
+ return self;
+
+ } else {
+
+ return target.apply(
+ that,
+ args.concat(slice.call(arguments))
+ );
+
+ }
+
+ };
+
+ return bound;
+ };
+ }
+ if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(searchElement, fromIndex) {
+ var k;
+ if (this == null) {
+ throw new TypeError('"this" is null or not defined');
+ }
+ var O = Object(this);
+ var len = O.length >>> 0;
+ if (len === 0) {
+ return -1;
+ }
+ var n = +fromIndex || 0;
+ if (Math.abs(n) === Infinity) {
+ n = 0;
+ }
+ if (n >= len) {
+ return -1;
+ }
+ k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
+ while (k < len) {
+ if (k in O && O[k] === searchElement) {
+ return k;
+ }
+ k++;
+ }
+ return -1;
+ };
+ }
+
+
+
+ // =================================================================================================================
+ // Template
+
+ var base_html =
+ '<span class="irs">' +
+ '<span class="irs-line" tabindex="0"><span class="irs-line-left"></span><span class="irs-line-mid"></span><span class="irs-line-right"></span></span>' +
+ '<span class="irs-min">0</span><span class="irs-max">1</span>' +
+ '<span class="irs-from">0</span><span class="irs-to">0</span><span class="irs-single">0</span>' +
+ '</span>' +
+ '<span class="irs-grid"></span>' +
+ '<span class="irs-bar"></span>';
+
+ var single_html =
+ '<span class="irs-bar-edge"></span>' +
+ '<span class="irs-shadow shadow-single"></span>' +
+ '<span class="irs-slider single"></span>';
+
+ var double_html =
+ '<span class="irs-shadow shadow-from"></span>' +
+ '<span class="irs-shadow shadow-to"></span>' +
+ '<span class="irs-slider from"></span>' +
+ '<span class="irs-slider to"></span>';
+
+ var disable_html =
+ '<span class="irs-disable-mask"></span>';
+
+
+
+ // =================================================================================================================
+ // Core
+
+ /**
+ * Main plugin constructor
+ *
+ * @param input {Object} link to base input element
+ * @param options {Object} slider config
+ * @param plugin_count {Number}
+ * @constructor
+ */
+ var IonRangeSlider = function (input, options, plugin_count) {
+ this.VERSION = "2.2.0";
+ this.input = input;
+ this.plugin_count = plugin_count;
+ this.current_plugin = 0;
+ this.calc_count = 0;
+ this.update_tm = 0;
+ this.old_from = 0;
+ this.old_to = 0;
+ this.old_min_interval = null;
+ this.raf_id = null;
+ this.dragging = false;
+ this.force_redraw = false;
+ this.no_diapason = false;
+ this.has_tab_index = true;
+ this.is_key = false;
+ this.is_update = false;
+ this.is_start = true;
+ this.is_finish = false;
+ this.is_active = false;
+ this.is_resize = false;
+ this.is_click = false;
+
+ options = options || {};
+
+ // cache for links to all DOM elements
+ this.$cache = {
+ win: $(window),
+ body: $(document.body),
+ input: $(input),
+ cont: null,
+ rs: null,
+ min: null,
+ max: null,
+ from: null,
+ to: null,
+ single: null,
+ bar: null,
+ line: null,
+ s_single: null,
+ s_from: null,
+ s_to: null,
+ shad_single: null,
+ shad_from: null,
+ shad_to: null,
+ edge: null,
+ grid: null,
+ grid_labels: []
+ };
+
+ // storage for measure variables
+ this.coords = {
+ // left
+ x_gap: 0,
+ x_pointer: 0,
+
+ // width
+ w_rs: 0,
+ w_rs_old: 0,
+ w_handle: 0,
+
+ // percents
+ p_gap: 0,
+ p_gap_left: 0,
+ p_gap_right: 0,
+ p_step: 0,
+ p_pointer: 0,
+ p_handle: 0,
+ p_single_fake: 0,
+ p_single_real: 0,
+ p_from_fake: 0,
+ p_from_real: 0,
+ p_to_fake: 0,
+ p_to_real: 0,
+ p_bar_x: 0,
+ p_bar_w: 0,
+
+ // grid
+ grid_gap: 0,
+ big_num: 0,
+ big: [],
+ big_w: [],
+ big_p: [],
+ big_x: []
+ };
+
+ // storage for labels measure variables
+ this.labels = {
+ // width
+ w_min: 0,
+ w_max: 0,
+ w_from: 0,
+ w_to: 0,
+ w_single: 0,
+
+ // percents
+ p_min: 0,
+ p_max: 0,
+ p_from_fake: 0,
+ p_from_left: 0,
+ p_to_fake: 0,
+ p_to_left: 0,
+ p_single_fake: 0,
+ p_single_left: 0
+ };
+
+
+
+ /**
+ * get and validate config
+ */
+ var $inp = this.$cache.input,
+ val = $inp.prop("value"),
+ config, config_from_data, prop;
+
+ // default config
+ config = {
+ type: "single",
+
+ min: 10,
+ max: 100,
+ from: null,
+ to: null,
+ step: 1,
+
+ min_interval: 0,
+ max_interval: 0,
+ drag_interval: false,
+
+ values: [],
+ p_values: [],
+
+ from_fixed: false,
+ from_min: null,
+ from_max: null,
+ from_shadow: false,
+
+ to_fixed: false,
+ to_min: null,
+ to_max: null,
+ to_shadow: false,
+
+ prettify_enabled: true,
+ prettify_separator: " ",
+ prettify: null,
+
+ force_edges: false,
+
+ keyboard: true,
+
+ grid: false,
+ grid_margin: true,
+ grid_num: 4,
+ grid_snap: false,
+
+ hide_min_max: false,
+ hide_from_to: false,
+
+ prefix: "",
+ postfix: "",
+ max_postfix: "",
+ decorate_both: true,
+ values_separator: " — ",
+
+ input_values_separator: ";",
+
+ disable: false,
+ block: false,
+
+ extra_classes: "",
+
+ scope: null,
+ onStart: null,
+ onChange: null,
+ onFinish: null,
+ onUpdate: null
+ };
+
+
+ // check if base element is input
+ if ($inp[0].nodeName !== "INPUT") {
+ console && console.warn && console.warn("Base element should be <input>!", $inp[0]);
+ }
+
+
+ // config from data-attributes extends js config
+ config_from_data = {
+ type: $inp.data("type"),
+
+ min: $inp.data("min"),
+ max: $inp.data("max"),
+ from: $inp.data("from"),
+ to: $inp.data("to"),
+ step: $inp.data("step"),
+
+ min_interval: $inp.data("minInterval"),
+ max_interval: $inp.data("maxInterval"),
+ drag_interval: $inp.data("dragInterval"),
+
+ values: $inp.data("values"),
+
+ from_fixed: $inp.data("fromFixed"),
+ from_min: $inp.data("fromMin"),
+ from_max: $inp.data("fromMax"),
+ from_shadow: $inp.data("fromShadow"),
+
+ to_fixed: $inp.data("toFixed"),
+ to_min: $inp.data("toMin"),
+ to_max: $inp.data("toMax"),
+ to_shadow: $inp.data("toShadow"),
+
+ prettify_enabled: $inp.data("prettifyEnabled"),
+ prettify_separator: $inp.data("prettifySeparator"),
+
+ force_edges: $inp.data("forceEdges"),
+
+ keyboard: $inp.data("keyboard"),
+
+ grid: $inp.data("grid"),
+ grid_margin: $inp.data("gridMargin"),
+ grid_num: $inp.data("gridNum"),
+ grid_snap: $inp.data("gridSnap"),
+
+ hide_min_max: $inp.data("hideMinMax"),
+ hide_from_to: $inp.data("hideFromTo"),
+
+ prefix: $inp.data("prefix"),
+ postfix: $inp.data("postfix"),
+ max_postfix: $inp.data("maxPostfix"),
+ decorate_both: $inp.data("decorateBoth"),
+ values_separator: $inp.data("valuesSeparator"),
+
+ input_values_separator: $inp.data("inputValuesSeparator"),
+
+ disable: $inp.data("disable"),
+ block: $inp.data("block"),
+
+ extra_classes: $inp.data("extraClasses"),
+ };
+ config_from_data.values = config_from_data.values && config_from_data.values.split(",");
+
+ for (prop in config_from_data) {
+ if (config_from_data.hasOwnProperty(prop)) {
+ if (config_from_data[prop] === undefined || config_from_data[prop] === "") {
+ delete config_from_data[prop];
+ }
+ }
+ }
+
+
+ // input value extends default config
+ if (val !== undefined && val !== "") {
+ val = val.split(config_from_data.input_values_separator || options.input_values_separator || ";");
+
+ if (val[0] && val[0] == +val[0]) {
+ val[0] = +val[0];
+ }
+ if (val[1] && val[1] == +val[1]) {
+ val[1] = +val[1];
+ }
+
+ if (options && options.values && options.values.length) {
+ config.from = val[0] && options.values.indexOf(val[0]);
+ config.to = val[1] && options.values.indexOf(val[1]);
+ } else {
+ config.from = val[0] && +val[0];
+ config.to = val[1] && +val[1];
+ }
+ }
+
+
+
+ // js config extends default config
+ $.extend(config, options);
+
+
+ // data config extends config
+ $.extend(config, config_from_data);
+ this.options = config;
+
+
+
+ // validate config, to be sure that all data types are correct
+ this.update_check = {};
+ this.validate();
+
+
+
+ // default result object, returned to callbacks
+ this.result = {
+ input: this.$cache.input,
+ slider: null,
+
+ min: this.options.min,
+ max: this.options.max,
+
+ from: this.options.from,
+ from_percent: 0,
+ from_value: null,
+
+ to: this.options.to,
+ to_percent: 0,
+ to_value: null
+ };
+
+
+
+ this.init();
+ };
+
+ IonRangeSlider.prototype = {
+
+ /**
+ * Starts or updates the plugin instance
+ *
+ * @param [is_update] {boolean}
+ */
+ init: function (is_update) {
+ this.no_diapason = false;
+ this.coords.p_step = this.convertToPercent(this.options.step, true);
+
+ this.target = "base";
+
+ this.toggleInput();
+ this.append();
+ this.setMinMax();
+
+ if (is_update) {
+ this.force_redraw = true;
+ this.calc(true);
+
+ // callbacks called
+ this.callOnUpdate();
+ } else {
+ this.force_redraw = true;
+ this.calc(true);
+
+ // callbacks called
+ this.callOnStart();
+ }
+
+ this.updateScene();
+ },
+
+ /**
+ * Appends slider template to a DOM
+ */
+ append: function () {
+ var container_html = '<span class="irs js-irs-' + this.plugin_count + ' ' + this.options.extra_classes + '"></span>';
+ this.$cache.input.before(container_html);
+ this.$cache.input.prop("readonly", true);
+ this.$cache.cont = this.$cache.input.prev();
+ this.result.slider = this.$cache.cont;
+
+ this.$cache.cont.html(base_html);
+ this.$cache.rs = this.$cache.cont.find(".irs");
+ this.$cache.min = this.$cache.cont.find(".irs-min");
+ this.$cache.max = this.$cache.cont.find(".irs-max");
+ this.$cache.from = this.$cache.cont.find(".irs-from");
+ this.$cache.to = this.$cache.cont.find(".irs-to");
+ this.$cache.single = this.$cache.cont.find(".irs-single");
+ this.$cache.bar = this.$cache.cont.find(".irs-bar");
+ this.$cache.line = this.$cache.cont.find(".irs-line");
+ this.$cache.grid = this.$cache.cont.find(".irs-grid");
+
+ if (this.options.type === "single") {
+ this.$cache.cont.append(single_html);
+ this.$cache.edge = this.$cache.cont.find(".irs-bar-edge");
+ this.$cache.s_single = this.$cache.cont.find(".single");
+ this.$cache.from[0].style.visibility = "hidden";
+ this.$cache.to[0].style.visibility = "hidden";
+ this.$cache.shad_single = this.$cache.cont.find(".shadow-single");
+ } else {
+ this.$cache.cont.append(double_html);
+ this.$cache.s_from = this.$cache.cont.find(".from");
+ this.$cache.s_to = this.$cache.cont.find(".to");
+ this.$cache.shad_from = this.$cache.cont.find(".shadow-from");
+ this.$cache.shad_to = this.$cache.cont.find(".shadow-to");
+
+ this.setTopHandler();
+ }
+
+ if (this.options.hide_from_to) {
+ this.$cache.from[0].style.display = "none";
+ this.$cache.to[0].style.display = "none";
+ this.$cache.single[0].style.display = "none";
+ }
+
+ this.appendGrid();
+
+ if (this.options.disable) {
+ this.appendDisableMask();
+ this.$cache.input[0].disabled = true;
+ } else {
+ this.$cache.input[0].disabled = false;
+ this.removeDisableMask();
+ this.bindEvents();
+ }
+
+ // block only if not disabled
+ if (!this.options.disable) {
+ if (this.options.block) {
+ this.appendDisableMask();
+ } else {
+ this.removeDisableMask();
+ }
+ }
+
+ if (this.options.drag_interval) {
+ this.$cache.bar[0].style.cursor = "ew-resize";
+ }
+ },
+
+ /**
+ * Determine which handler has a priority
+ * works only for double slider type
+ */
+ setTopHandler: function () {
+ var min = this.options.min,
+ max = this.options.max,
+ from = this.options.from,
+ to = this.options.to;
+
+ if (from > min && to === max) {
+ this.$cache.s_from.addClass("type_last");
+ } else if (to < max) {
+ this.$cache.s_to.addClass("type_last");
+ }
+ },
+
+ /**
+ * Determine which handles was clicked last
+ * and which handler should have hover effect
+ *
+ * @param target {String}
+ */
+ changeLevel: function (target) {
+ switch (target) {
+ case "single":
+ this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_single_fake);
+ this.$cache.s_single.addClass("state_hover");
+ break;
+ case "from":
+ this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake);
+ this.$cache.s_from.addClass("state_hover");
+ this.$cache.s_from.addClass("type_last");
+ this.$cache.s_to.removeClass("type_last");
+ break;
+ case "to":
+ this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_to_fake);
+ this.$cache.s_to.addClass("state_hover");
+ this.$cache.s_to.addClass("type_last");
+ this.$cache.s_from.removeClass("type_last");
+ break;
+ case "both":
+ this.coords.p_gap_left = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake);
+ this.coords.p_gap_right = this.toFixed(this.coords.p_to_fake - this.coords.p_pointer);
+ this.$cache.s_to.removeClass("type_last");
+ this.$cache.s_from.removeClass("type_last");
+ break;
+ }
+ },
+
+ /**
+ * Then slider is disabled
+ * appends extra layer with opacity
+ */
+ appendDisableMask: function () {
+ this.$cache.cont.append(disable_html);
+ this.$cache.cont.addClass("irs-disabled");
+ },
+
+ /**
+ * Then slider is not disabled
+ * remove disable mask
+ */
+ removeDisableMask: function () {
+ this.$cache.cont.remove(".irs-disable-mask");
+ this.$cache.cont.removeClass("irs-disabled");
+ },
+
+ /**
+ * Remove slider instance
+ * and unbind all events
+ */
+ remove: function () {
+ this.$cache.cont.remove();
+ this.$cache.cont = null;
+
+ this.$cache.line.off("keydown.irs_" + this.plugin_count);
+
+ this.$cache.body.off("touchmove.irs_" + this.plugin_count);
+ this.$cache.body.off("mousemove.irs_" + this.plugin_count);
+
+ this.$cache.win.off("touchend.irs_" + this.plugin_count);
+ this.$cache.win.off("mouseup.irs_" + this.plugin_count);
+
+ if (is_old_ie) {
+ this.$cache.body.off("mouseup.irs_" + this.plugin_count);
+ this.$cache.body.off("mouseleave.irs_" + this.plugin_count);
+ }
+
+ this.$cache.grid_labels = [];
+ this.coords.big = [];
+ this.coords.big_w = [];
+ this.coords.big_p = [];
+ this.coords.big_x = [];
+
+ cancelAnimationFrame(this.raf_id);
+ },
+
+ /**
+ * bind all slider events
+ */
+ bindEvents: function () {
+ if (this.no_diapason) {
+ return;
+ }
+
+ this.$cache.body.on("touchmove.irs_" + this.plugin_count, this.pointerMove.bind(this));
+ this.$cache.body.on("mousemove.irs_" + this.plugin_count, this.pointerMove.bind(this));
+
+ this.$cache.win.on("touchend.irs_" + this.plugin_count, this.pointerUp.bind(this));
+ this.$cache.win.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
+
+ this.$cache.line.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ this.$cache.line.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+
+ this.$cache.line.on("focus.irs_" + this.plugin_count, this.pointerFocus.bind(this));
+
+ if (this.options.drag_interval && this.options.type === "double") {
+ this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
+ this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
+ } else {
+ this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ }
+
+ if (this.options.type === "single") {
+ this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
+ this.$cache.s_single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
+ this.$cache.shad_single.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+
+ this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
+ this.$cache.s_single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
+ this.$cache.edge.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ this.$cache.shad_single.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ } else {
+ this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, null));
+ this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, null));
+
+ this.$cache.from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
+ this.$cache.s_from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
+ this.$cache.to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
+ this.$cache.s_to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
+ this.$cache.shad_from.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ this.$cache.shad_to.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+
+ this.$cache.from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
+ this.$cache.s_from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
+ this.$cache.to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
+ this.$cache.s_to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
+ this.$cache.shad_from.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ this.$cache.shad_to.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
+ }
+
+ if (this.options.keyboard) {
+ this.$cache.line.on("keydown.irs_" + this.plugin_count, this.key.bind(this, "keyboard"));
+ }
+
+ if (is_old_ie) {
+ this.$cache.body.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
+ this.$cache.body.on("mouseleave.irs_" + this.plugin_count, this.pointerUp.bind(this));
+ }
+ },
+
+ /**
+ * Focus with tabIndex
+ *
+ * @param e {Object} event object
+ */
+ pointerFocus: function (e) {
+ if (!this.target) {
+ var x;
+ var $handle;
+
+ if (this.options.type === "single") {
+ $handle = this.$cache.single;
+ } else {
+ $handle = this.$cache.from;
+ }
+
+ x = $handle.offset().left;
+ x += ($handle.width() / 2) - 1;
+
+ this.pointerClick("single", {preventDefault: function () {}, pageX: x});
+ }
+ },
+
+ /**
+ * Mousemove or touchmove
+ * only for handlers
+ *
+ * @param e {Object} event object
+ */
+ pointerMove: function (e) {
+ if (!this.dragging) {
+ return;
+ }
+
+ var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
+ this.coords.x_pointer = x - this.coords.x_gap;
+
+ this.calc();
+ },
+
+ /**
+ * Mouseup or touchend
+ * only for handlers
+ *
+ * @param e {Object} event object
+ */
+ pointerUp: function (e) {
+ if (this.current_plugin !== this.plugin_count) {
+ return;
+ }
+
+ if (this.is_active) {
+ this.is_active = false;
+ } else {
+ return;
+ }
+
+ this.$cache.cont.find(".state_hover").removeClass("state_hover");
+
+ this.force_redraw = true;
+
+ if (is_old_ie) {
+ $("*").prop("unselectable", false);
+ }
+
+ this.updateScene();
+ this.restoreOriginalMinInterval();
+
+ // callbacks call
+ if ($.contains(this.$cache.cont[0], e.target) || this.dragging) {
+ this.callOnFinish();
+ }
+
+ this.dragging = false;
+ },
+
+ /**
+ * Mousedown or touchstart
+ * only for handlers
+ *
+ * @param target {String|null}
+ * @param e {Object} event object
+ */
+ pointerDown: function (target, e) {
+ e.preventDefault();
+ var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
+ if (e.button === 2) {
+ return;
+ }
+
+ if (target === "both") {
+ this.setTempMinInterval();
+ }
+
+ if (!target) {
+ target = this.target || "from";
+ }
+
+ this.current_plugin = this.plugin_count;
+ this.target = target;
+
+ this.is_active = true;
+ this.dragging = true;
+
+ this.coords.x_gap = this.$cache.rs.offset().left;
+ this.coords.x_pointer = x - this.coords.x_gap;
+
+ this.calcPointerPercent();
+ this.changeLevel(target);
+
+ if (is_old_ie) {
+ $("*").prop("unselectable", true);
+ }
+
+ this.$cache.line.trigger("focus");
+
+ this.updateScene();
+ },
+
+ /**
+ * Mousedown or touchstart
+ * for other slider elements, like diapason line
+ *
+ * @param target {String}
+ * @param e {Object} event object
+ */
+ pointerClick: function (target, e) {
+ e.preventDefault();
+ var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
+ if (e.button === 2) {
+ return;
+ }
+
+ this.current_plugin = this.plugin_count;
+ this.target = target;
+
+ this.is_click = true;
+ this.coords.x_gap = this.$cache.rs.offset().left;
+ this.coords.x_pointer = +(x - this.coords.x_gap).toFixed();
+
+ this.force_redraw = true;
+ this.calc();
+
+ this.$cache.line.trigger("focus");
+ },
+
+ /**
+ * Keyborard controls for focused slider
+ *
+ * @param target {String}
+ * @param e {Object} event object
+ * @returns {boolean|undefined}
+ */
+ key: function (target, e) {
+ if (this.current_plugin !== this.plugin_count || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
+ return;
+ }
+
+ switch (e.which) {
+ case 83: // W
+ case 65: // A
+ case 40: // DOWN
+ case 37: // LEFT
+ e.preventDefault();
+ this.moveByKey(false);
+ break;
+
+ case 87: // S
+ case 68: // D
+ case 38: // UP
+ case 39: // RIGHT
+ e.preventDefault();
+ this.moveByKey(true);
+ break;
+ }
+
+ return true;
+ },
+
+ /**
+ * Move by key
+ *
+ * @param right {boolean} direction to move
+ */
+ moveByKey: function (right) {
+ var p = this.coords.p_pointer;
+ var p_step = (this.options.max - this.options.min) / 100;
+ p_step = this.options.step / p_step;
+
+ if (right) {
+ p += p_step;
+ } else {
+ p -= p_step;
+ }
+
+ this.coords.x_pointer = this.toFixed(this.coords.w_rs / 100 * p);
+ this.is_key = true;
+ this.calc();
+ },
+
+ /**
+ * Set visibility and content
+ * of Min and Max labels
+ */
+ setMinMax: function () {
+ if (!this.options) {
+ return;
+ }
+
+ if (this.options.hide_min_max) {
+ this.$cache.min[0].style.display = "none";
+ this.$cache.max[0].style.display = "none";
+ return;
+ }
+
+ if (this.options.values.length) {
+ this.$cache.min.html(this.decorate(this.options.p_values[this.options.min]));
+ this.$cache.max.html(this.decorate(this.options.p_values[this.options.max]));
+ } else {
+ var min_pretty = this._prettify(this.options.min);
+ var max_pretty = this._prettify(this.options.max);
+
+ this.result.min_pretty = min_pretty;
+ this.result.max_pretty = max_pretty;
+
+ this.$cache.min.html(this.decorate(min_pretty, this.options.min));
+ this.$cache.max.html(this.decorate(max_pretty, this.options.max));
+ }
+
+ this.labels.w_min = this.$cache.min.outerWidth(false);
+ this.labels.w_max = this.$cache.max.outerWidth(false);
+ },
+
+ /**
+ * Then dragging interval, prevent interval collapsing
+ * using min_interval option
+ */
+ setTempMinInterval: function () {
+ var interval = this.result.to - this.result.from;
+
+ if (this.old_min_interval === null) {
+ this.old_min_interval = this.options.min_interval;
+ }
+
+ this.options.min_interval = interval;
+ },
+
+ /**
+ * Restore min_interval option to original
+ */
+ restoreOriginalMinInterval: function () {
+ if (this.old_min_interval !== null) {
+ this.options.min_interval = this.old_min_interval;
+ this.old_min_interval = null;
+ }
+ },
+
+
+
+ // =============================================================================================================
+ // Calculations
+
+ /**
+ * All calculations and measures start here
+ *
+ * @param update {boolean=}
+ */
+ calc: function (update) {
+ if (!this.options) {
+ return;
+ }
+
+ this.calc_count++;
+
+ if (this.calc_count === 10 || update) {
+ this.calc_count = 0;
+ this.coords.w_rs = this.$cache.rs.outerWidth(false);
+
+ this.calcHandlePercent();
+ }
+
+ if (!this.coords.w_rs) {
+ return;
+ }
+
+ this.calcPointerPercent();
+ var handle_x = this.getHandleX();
+
+
+ if (this.target === "both") {
+ this.coords.p_gap = 0;
+ handle_x = this.getHandleX();
+ }
+
+ if (this.target === "click") {
+ this.coords.p_gap = this.coords.p_handle / 2;
+ handle_x = this.getHandleX();
+
+ if (this.options.drag_interval) {
+ this.target = "both_one";
+ } else {
+ this.target = this.chooseHandle(handle_x);
+ }
+ }
+
+ switch (this.target) {
+ case "base":
+ var w = (this.options.max - this.options.min) / 100,
+ f = (this.result.from - this.options.min) / w,
+ t = (this.result.to - this.options.min) / w;
+
+ this.coords.p_single_real = this.toFixed(f);
+ this.coords.p_from_real = this.toFixed(f);
+ this.coords.p_to_real = this.toFixed(t);
+
+ this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
+ this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
+ this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
+
+ this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real);
+ this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
+ this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
+
+ this.target = null;
+
+ break;
+
+ case "single":
+ if (this.options.from_fixed) {
+ break;
+ }
+
+ this.coords.p_single_real = this.convertToRealPercent(handle_x);
+ this.coords.p_single_real = this.calcWithStep(this.coords.p_single_real);
+ this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
+
+ this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real);
+
+ break;
+
+ case "from":
+ if (this.options.from_fixed) {
+ break;
+ }
+
+ this.coords.p_from_real = this.convertToRealPercent(handle_x);
+ this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real);
+ if (this.coords.p_from_real > this.coords.p_to_real) {
+ this.coords.p_from_real = this.coords.p_to_real;
+ }
+ this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
+ this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
+ this.coords.p_from_real = this.checkMaxInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
+
+ this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
+
+ break;
+
+ case "to":
+ if (this.options.to_fixed) {
+ break;
+ }
+
+ this.coords.p_to_real = this.convertToRealPercent(handle_x);
+ this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real);
+ if (this.coords.p_to_real < this.coords.p_from_real) {
+ this.coords.p_to_real = this.coords.p_from_real;
+ }
+ this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
+ this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
+ this.coords.p_to_real = this.checkMaxInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
+
+ this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
+
+ break;
+
+ case "both":
+ if (this.options.from_fixed || this.options.to_fixed) {
+ break;
+ }
+
+ handle_x = this.toFixed(handle_x + (this.coords.p_handle * 0.001));
+
+ this.coords.p_from_real = this.convertToRealPercent(handle_x) - this.coords.p_gap_left;
+ this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real);
+ this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
+ this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
+ this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
+
+ this.coords.p_to_real = this.convertToRealPercent(handle_x) + this.coords.p_gap_right;
+ this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real);
+ this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
+ this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
+ this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
+
+ break;
+
+ case "both_one":
+ if (this.options.from_fixed || this.options.to_fixed) {
+ break;
+ }
+
+ var real_x = this.convertToRealPercent(handle_x),
+ from = this.result.from_percent,
+ to = this.result.to_percent,
+ full = to - from,
+ half = full / 2,
+ new_from = real_x - half,
+ new_to = real_x + half;
+
+ if (new_from < 0) {
+ new_from = 0;
+ new_to = new_from + full;
+ }
+
+ if (new_to > 100) {
+ new_to = 100;
+ new_from = new_to - full;
+ }
+
+ this.coords.p_from_real = this.calcWithStep(new_from);
+ this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
+ this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
+
+ this.coords.p_to_real = this.calcWithStep(new_to);
+ this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
+ this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
+
+ break;
+ }
+
+ if (this.options.type === "single") {
+ this.coords.p_bar_x = (this.coords.p_handle / 2);
+ this.coords.p_bar_w = this.coords.p_single_fake;
+
+ this.result.from_percent = this.coords.p_single_real;
+ this.result.from = this.convertToValue(this.coords.p_single_real);
+ this.result.from_pretty = this._prettify(this.result.from);
+
+ if (this.options.values.length) {
+ this.result.from_value = this.options.values[this.result.from];
+ }
+ } else {
+ this.coords.p_bar_x = this.toFixed(this.coords.p_from_fake + (this.coords.p_handle / 2));
+ this.coords.p_bar_w = this.toFixed(this.coords.p_to_fake - this.coords.p_from_fake);
+
+ this.result.from_percent = this.coords.p_from_real;
+ this.result.from = this.convertToValue(this.coords.p_from_real);
+ this.result.from_pretty = this._prettify(this.result.from);
+ this.result.to_percent = this.coords.p_to_real;
+ this.result.to = this.convertToValue(this.coords.p_to_real);
+ this.result.to_pretty = this._prettify(this.result.to);
+
+ if (this.options.values.length) {
+ this.result.from_value = this.options.values[this.result.from];
+ this.result.to_value = this.options.values[this.result.to];
+ }
+ }
+
+ this.calcMinMax();
+ this.calcLabels();
+ },
+
+
+ /**
+ * calculates pointer X in percent
+ */
+ calcPointerPercent: function () {
+ if (!this.coords.w_rs) {
+ this.coords.p_pointer = 0;
+ return;
+ }
+
+ if (this.coords.x_pointer < 0 || isNaN(this.coords.x_pointer) ) {
+ this.coords.x_pointer = 0;
+ } else if (this.coords.x_pointer > this.coords.w_rs) {
+ this.coords.x_pointer = this.coords.w_rs;
+ }
+
+ this.coords.p_pointer = this.toFixed(this.coords.x_pointer / this.coords.w_rs * 100);
+ },
+
+ convertToRealPercent: function (fake) {
+ var full = 100 - this.coords.p_handle;
+ return fake / full * 100;
+ },
+
+ convertToFakePercent: function (real) {
+ var full = 100 - this.coords.p_handle;
+ return real / 100 * full;
+ },
+
+ getHandleX: function () {
+ var max = 100 - this.coords.p_handle,
+ x = this.toFixed(this.coords.p_pointer - this.coords.p_gap);
+
+ if (x < 0) {
+ x = 0;
+ } else if (x > max) {
+ x = max;
+ }
+
+ return x;
+ },
+
+ calcHandlePercent: function () {
+ if (this.options.type === "single") {
+ this.coords.w_handle = this.$cache.s_single.outerWidth(false);
+ } else {
+ this.coords.w_handle = this.$cache.s_from.outerWidth(false);
+ }
+
+ this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
+ },
+
+ /**
+ * Find closest handle to pointer click
+ *
+ * @param real_x {Number}
+ * @returns {String}
+ */
+ chooseHandle: function (real_x) {
+ if (this.options.type === "single") {
+ return "single";
+ } else {
+ var m_point = this.coords.p_from_real + ((this.coords.p_to_real - this.coords.p_from_real) / 2);
+ if (real_x >= m_point) {
+ return this.options.to_fixed ? "from" : "to";
+ } else {
+ return this.options.from_fixed ? "to" : "from";
+ }
+ }
+ },
+
+ /**
+ * Measure Min and Max labels width in percent
+ */
+ calcMinMax: function () {
+ if (!this.coords.w_rs) {
+ return;
+ }
+
+ this.labels.p_min = this.labels.w_min / this.coords.w_rs * 100;
+ this.labels.p_max = this.labels.w_max / this.coords.w_rs * 100;
+ },
+
+ /**
+ * Measure labels width and X in percent
+ */
+ calcLabels: function () {
+ if (!this.coords.w_rs || this.options.hide_from_to) {
+ return;
+ }
+
+ if (this.options.type === "single") {
+
+ this.labels.w_single = this.$cache.single.outerWidth(false);
+ this.labels.p_single_fake = this.labels.w_single / this.coords.w_rs * 100;
+ this.labels.p_single_left = this.coords.p_single_fake + (this.coords.p_handle / 2) - (this.labels.p_single_fake / 2);
+ this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single_fake);
+
+ } else {
+
+ this.labels.w_from = this.$cache.from.outerWidth(false);
+ this.labels.p_from_fake = this.labels.w_from / this.coords.w_rs * 100;
+ this.labels.p_from_left = this.coords.p_from_fake + (this.coords.p_handle / 2) - (this.labels.p_from_fake / 2);
+ this.labels.p_from_left = this.toFixed(this.labels.p_from_left);
+ this.labels.p_from_left = this.checkEdges(this.labels.p_from_left, this.labels.p_from_fake);
+
+ this.labels.w_to = this.$cache.to.outerWidth(false);
+ this.labels.p_to_fake = this.labels.w_to / this.coords.w_rs * 100;
+ this.labels.p_to_left = this.coords.p_to_fake + (this.coords.p_handle / 2) - (this.labels.p_to_fake / 2);
+ this.labels.p_to_left = this.toFixed(this.labels.p_to_left);
+ this.labels.p_to_left = this.checkEdges(this.labels.p_to_left, this.labels.p_to_fake);
+
+ this.labels.w_single = this.$cache.single.outerWidth(false);
+ this.labels.p_single_fake = this.labels.w_single / this.coords.w_rs * 100;
+ this.labels.p_single_left = ((this.labels.p_from_left + this.labels.p_to_left + this.labels.p_to_fake) / 2) - (this.labels.p_single_fake / 2);
+ this.labels.p_single_left = this.toFixed(this.labels.p_single_left);
+ this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single_fake);
+
+ }
+ },
+
+
+
+ // =============================================================================================================
+ // Drawings
+
+ /**
+ * Main function called in request animation frame
+ * to update everything
+ */
+ updateScene: function () {
+ if (this.raf_id) {
+ cancelAnimationFrame(this.raf_id);
+ this.raf_id = null;
+ }
+
+ clearTimeout(this.update_tm);
+ this.update_tm = null;
+
+ if (!this.options) {
+ return;
+ }
+
+ this.drawHandles();
+
+ if (this.is_active) {
+ this.raf_id = requestAnimationFrame(this.updateScene.bind(this));
+ } else {
+ this.update_tm = setTimeout(this.updateScene.bind(this), 300);
+ }
+ },
+
+ /**
+ * Draw handles
+ */
+ drawHandles: function () {
+ this.coords.w_rs = this.$cache.rs.outerWidth(false);
+
+ if (!this.coords.w_rs) {
+ return;
+ }
+
+ if (this.coords.w_rs !== this.coords.w_rs_old) {
+ this.target = "base";
+ this.is_resize = true;
+ }
+
+ if (this.coords.w_rs !== this.coords.w_rs_old || this.force_redraw) {
+ this.setMinMax();
+ this.calc(true);
+ this.drawLabels();
+ if (this.options.grid) {
+ this.calcGridMargin();
+ this.calcGridLabels();
+ }
+ this.force_redraw = true;
+ this.coords.w_rs_old = this.coords.w_rs;
+ this.drawShadow();
+ }
+
+ if (!this.coords.w_rs) {
+ return;
+ }
+
+ if (!this.dragging && !this.force_redraw && !this.is_key) {
+ return;
+ }
+
+ if (this.old_from !== this.result.from || this.old_to !== this.result.to || this.force_redraw || this.is_key) {
+
+ this.drawLabels();
+
+ this.$cache.bar[0].style.left = this.coords.p_bar_x + "%";
+ this.$cache.bar[0].style.width = this.coords.p_bar_w + "%";
+
+ if (this.options.type === "single") {
+ this.$cache.s_single[0].style.left = this.coords.p_single_fake + "%";
+
+ this.$cache.single[0].style.left = this.labels.p_single_left + "%";
+ } else {
+ this.$cache.s_from[0].style.left = this.coords.p_from_fake + "%";
+ this.$cache.s_to[0].style.left = this.coords.p_to_fake + "%";
+
+ if (this.old_from !== this.result.from || this.force_redraw) {
+ this.$cache.from[0].style.left = this.labels.p_from_left + "%";
+ }
+ if (this.old_to !== this.result.to || this.force_redraw) {
+ this.$cache.to[0].style.left = this.labels.p_to_left + "%";
+ }
+
+ this.$cache.single[0].style.left = this.labels.p_single_left + "%";
+ }
+
+ this.writeToInput();
+
+ if ((this.old_from !== this.result.from || this.old_to !== this.result.to) && !this.is_start) {
+ this.$cache.input.trigger("change");
+ this.$cache.input.trigger("input");
+ }
+
+ this.old_from = this.result.from;
+ this.old_to = this.result.to;
+
+ // callbacks call
+ if (!this.is_resize && !this.is_update && !this.is_start && !this.is_finish) {
+ this.callOnChange();
+ }
+ if (this.is_key || this.is_click) {
+ this.is_key = false;
+ this.is_click = false;
+ this.callOnFinish();
+ }
+
+ this.is_update = false;
+ this.is_resize = false;
+ this.is_finish = false;
+ }
+
+ this.is_start = false;
+ this.is_key = false;
+ this.is_click = false;
+ this.force_redraw = false;
+ },
+
+ /**
+ * Draw labels
+ * measure labels collisions
+ * collapse close labels
+ */
+ drawLabels: function () {
+ if (!this.options) {
+ return;
+ }
+
+ var values_num = this.options.values.length;
+ var p_values = this.options.p_values;
+ var text_single;
+ var text_from;
+ var text_to;
+ var from_pretty;
+ var to_pretty;
+
+ if (this.options.hide_from_to) {
+ return;
+ }
+
+ if (this.options.type === "single") {
+
+ if (values_num) {
+ text_single = this.decorate(p_values[this.result.from]);
+ this.$cache.single.html(text_single);
+ } else {
+ from_pretty = this._prettify(this.result.from);
+
+ text_single = this.decorate(from_pretty, this.result.from);
+ this.$cache.single.html(text_single);
+ }
+
+ this.calcLabels();
+
+ if (this.labels.p_single_left < this.labels.p_min + 1) {
+ this.$cache.min[0].style.visibility = "hidden";
+ } else {
+ this.$cache.min[0].style.visibility = "visible";
+ }
+
+ if (this.labels.p_single_left + this.labels.p_single_fake > 100 - this.labels.p_max - 1) {
+ this.$cache.max[0].style.visibility = "hidden";
+ } else {
+ this.$cache.max[0].style.visibility = "visible";
+ }
+
+ } else {
+
+ if (values_num) {
+
+ if (this.options.decorate_both) {
+ text_single = this.decorate(p_values[this.result.from]);
+ text_single += this.options.values_separator;
+ text_single += this.decorate(p_values[this.result.to]);
+ } else {
+ text_single = this.decorate(p_values[this.result.from] + this.options.values_separator + p_values[this.result.to]);
+ }
+ text_from = this.decorate(p_values[this.result.from]);
+ text_to = this.decorate(p_values[this.result.to]);
+
+ this.$cache.single.html(text_single);
+ this.$cache.from.html(text_from);
+ this.$cache.to.html(text_to);
+
+ } else {
+ from_pretty = this._prettify(this.result.from);
+ to_pretty = this._prettify(this.result.to);
+
+ if (this.options.decorate_both) {
+ text_single = this.decorate(from_pretty, this.result.from);
+ text_single += this.options.values_separator;
+ text_single += this.decorate(to_pretty, this.result.to);
+ } else {
+ text_single = this.decorate(from_pretty + this.options.values_separator + to_pretty, this.result.to);
+ }
+ text_from = this.decorate(from_pretty, this.result.from);
+ text_to = this.decorate(to_pretty, this.result.to);
+
+ this.$cache.single.html(text_single);
+ this.$cache.from.html(text_from);
+ this.$cache.to.html(text_to);
+
+ }
+
+ this.calcLabels();
+
+ var min = Math.min(this.labels.p_single_left, this.labels.p_from_left),
+ single_left = this.labels.p_single_left + this.labels.p_single_fake,
+ to_left = this.labels.p_to_left + this.labels.p_to_fake,
+ max = Math.max(single_left, to_left);
+
+ if (this.labels.p_from_left + this.labels.p_from_fake >= this.labels.p_to_left) {
+ this.$cache.from[0].style.visibility = "hidden";
+ this.$cache.to[0].style.visibility = "hidden";
+ this.$cache.single[0].style.visibility = "visible";
+
+ if (this.result.from === this.result.to) {
+ if (this.target === "from") {
+ this.$cache.from[0].style.visibility = "visible";
+ } else if (this.target === "to") {
+ this.$cache.to[0].style.visibility = "visible";
+ } else if (!this.target) {
+ this.$cache.from[0].style.visibility = "visible";
+ }
+ this.$cache.single[0].style.visibility = "hidden";
+ max = to_left;
+ } else {
+ this.$cache.from[0].style.visibility = "hidden";
+ this.$cache.to[0].style.visibility = "hidden";
+ this.$cache.single[0].style.visibility = "visible";
+ max = Math.max(single_left, to_left);
+ }
+ } else {
+ this.$cache.from[0].style.visibility = "visible";
+ this.$cache.to[0].style.visibility = "visible";
+ this.$cache.single[0].style.visibility = "hidden";
+ }
+
+ if (min < this.labels.p_min + 1) {
+ this.$cache.min[0].style.visibility = "hidden";
+ } else {
+ this.$cache.min[0].style.visibility = "visible";
+ }
+
+ if (max > 100 - this.labels.p_max - 1) {
+ this.$cache.max[0].style.visibility = "hidden";
+ } else {
+ this.$cache.max[0].style.visibility = "visible";
+ }
+
+ }
+ },
+
+ /**
+ * Draw shadow intervals
+ */
+ drawShadow: function () {
+ var o = this.options,
+ c = this.$cache,
+
+ is_from_min = typeof o.from_min === "number" && !isNaN(o.from_min),
+ is_from_max = typeof o.from_max === "number" && !isNaN(o.from_max),
+ is_to_min = typeof o.to_min === "number" && !isNaN(o.to_min),
+ is_to_max = typeof o.to_max === "number" && !isNaN(o.to_max),
+
+ from_min,
+ from_max,
+ to_min,
+ to_max;
+
+ if (o.type === "single") {
+ if (o.from_shadow && (is_from_min || is_from_max)) {
+ from_min = this.convertToPercent(is_from_min ? o.from_min : o.min);
+ from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min;
+ from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
+ from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
+ from_min = from_min + (this.coords.p_handle / 2);
+
+ c.shad_single[0].style.display = "block";
+ c.shad_single[0].style.left = from_min + "%";
+ c.shad_single[0].style.width = from_max + "%";
+ } else {
+ c.shad_single[0].style.display = "none";
+ }
+ } else {
+ if (o.from_shadow && (is_from_min || is_from_max)) {
+ from_min = this.convertToPercent(is_from_min ? o.from_min : o.min);
+ from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min;
+ from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
+ from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
+ from_min = from_min + (this.coords.p_handle / 2);
+
+ c.shad_from[0].style.display = "block";
+ c.shad_from[0].style.left = from_min + "%";
+ c.shad_from[0].style.width = from_max + "%";
+ } else {
+ c.shad_from[0].style.display = "none";
+ }
+
+ if (o.to_shadow && (is_to_min || is_to_max)) {
+ to_min = this.convertToPercent(is_to_min ? o.to_min : o.min);
+ to_max = this.convertToPercent(is_to_max ? o.to_max : o.max) - to_min;
+ to_min = this.toFixed(to_min - (this.coords.p_handle / 100 * to_min));
+ to_max = this.toFixed(to_max - (this.coords.p_handle / 100 * to_max));
+ to_min = to_min + (this.coords.p_handle / 2);
+
+ c.shad_to[0].style.display = "block";
+ c.shad_to[0].style.left = to_min + "%";
+ c.shad_to[0].style.width = to_max + "%";
+ } else {
+ c.shad_to[0].style.display = "none";
+ }
+ }
+ },
+
+
+
+ /**
+ * Write values to input element
+ */
+ writeToInput: function () {
+ if (this.options.type === "single") {
+ if (this.options.values.length) {
+ this.$cache.input.prop("value", this.result.from_value);
+ } else {
+ this.$cache.input.prop("value", this.result.from);
+ }
+ this.$cache.input.data("from", this.result.from);
+ } else {
+ if (this.options.values.length) {
+ this.$cache.input.prop("value", this.result.from_value + this.options.input_values_separator + this.result.to_value);
+ } else {
+ this.$cache.input.prop("value", this.result.from + this.options.input_values_separator + this.result.to);
+ }
+ this.$cache.input.data("from", this.result.from);
+ this.$cache.input.data("to", this.result.to);
+ }
+ },
+
+
+
+ // =============================================================================================================
+ // Callbacks
+
+ callOnStart: function () {
+ this.writeToInput();
+
+ if (this.options.onStart && typeof this.options.onStart === "function") {
+ if (this.options.scope) {
+ this.options.onStart.call(this.options.scope, this.result);
+ } else {
+ this.options.onStart(this.result);
+ }
+ }
+ },
+ callOnChange: function () {
+ this.writeToInput();
+
+ if (this.options.onChange && typeof this.options.onChange === "function") {
+ if (this.options.scope) {
+ this.options.onChange.call(this.options.scope, this.result);
+ } else {
+ this.options.onChange(this.result);
+ }
+ }
+ },
+ callOnFinish: function () {
+ this.writeToInput();
+
+ if (this.options.onFinish && typeof this.options.onFinish === "function") {
+ if (this.options.scope) {
+ this.options.onFinish.call(this.options.scope, this.result);
+ } else {
+ this.options.onFinish(this.result);
+ }
+ }
+ },
+ callOnUpdate: function () {
+ this.writeToInput();
+
+ if (this.options.onUpdate && typeof this.options.onUpdate === "function") {
+ if (this.options.scope) {
+ this.options.onUpdate.call(this.options.scope, this.result);
+ } else {
+ this.options.onUpdate(this.result);
+ }
+ }
+ },
+
+
+
+
+ // =============================================================================================================
+ // Service methods
+
+ toggleInput: function () {
+ this.$cache.input.toggleClass("irs-hidden-input");
+
+ if (this.has_tab_index) {
+ this.$cache.input.prop("tabindex", -1);
+ } else {
+ this.$cache.input.removeProp("tabindex");
+ }
+
+ this.has_tab_index = !this.has_tab_index;
+ },
+
+ /**
+ * Convert real value to percent
+ *
+ * @param value {Number} X in real
+ * @param no_min {boolean=} don't use min value
+ * @returns {Number} X in percent
+ */
+ convertToPercent: function (value, no_min) {
+ var diapason = this.options.max - this.options.min,
+ one_percent = diapason / 100,
+ val, percent;
+
+ if (!diapason) {
+ this.no_diapason = true;
+ return 0;
+ }
+
+ if (no_min) {
+ val = value;
+ } else {
+ val = value - this.options.min;
+ }
+
+ percent = val / one_percent;
+
+ return this.toFixed(percent);
+ },
+
+ /**
+ * Convert percent to real values
+ *
+ * @param percent {Number} X in percent
+ * @returns {Number} X in real
+ */
+ convertToValue: function (percent) {
+ var min = this.options.min,
+ max = this.options.max,
+ min_decimals = min.toString().split(".")[1],
+ max_decimals = max.toString().split(".")[1],
+ min_length, max_length,
+ avg_decimals = 0,
+ abs = 0;
+
+ if (percent === 0) {
+ return this.options.min;
+ }
+ if (percent === 100) {
+ return this.options.max;
+ }
+
+
+ if (min_decimals) {
+ min_length = min_decimals.length;
+ avg_decimals = min_length;
+ }
+ if (max_decimals) {
+ max_length = max_decimals.length;
+ avg_decimals = max_length;
+ }
+ if (min_length && max_length) {
+ avg_decimals = (min_length >= max_length) ? min_length : max_length;
+ }
+
+ if (min < 0) {
+ abs = Math.abs(min);
+ min = +(min + abs).toFixed(avg_decimals);
+ max = +(max + abs).toFixed(avg_decimals);
+ }
+
+ var number = ((max - min) / 100 * percent) + min,
+ string = this.options.step.toString().split(".")[1],
+ result;
+
+ if (string) {
+ number = +number.toFixed(string.length);
+ } else {
+ number = number / this.options.step;
+ number = number * this.options.step;
+
+ number = +number.toFixed(0);
+ }
+
+ if (abs) {
+ number -= abs;
+ }
+
+ if (string) {
+ result = +number.toFixed(string.length);
+ } else {
+ result = this.toFixed(number);
+ }
+
+ if (result < this.options.min) {
+ result = this.options.min;
+ } else if (result > this.options.max) {
+ result = this.options.max;
+ }
+
+ return result;
+ },
+
+ /**
+ * Round percent value with step
+ *
+ * @param percent {Number}
+ * @returns percent {Number} rounded
+ */
+ calcWithStep: function (percent) {
+ var rounded = Math.round(percent / this.coords.p_step) * this.coords.p_step;
+
+ if (rounded > 100) {
+ rounded = 100;
+ }
+ if (percent === 100) {
+ rounded = 100;
+ }
+
+ return this.toFixed(rounded);
+ },
+
+ checkMinInterval: function (p_current, p_next, type) {
+ var o = this.options,
+ current,
+ next;
+
+ if (!o.min_interval) {
+ return p_current;
+ }
+
+ current = this.convertToValue(p_current);
+ next = this.convertToValue(p_next);
+
+ if (type === "from") {
+
+ if (next - current < o.min_interval) {
+ current = next - o.min_interval;
+ }
+
+ } else {
+
+ if (current - next < o.min_interval) {
+ current = next + o.min_interval;
+ }
+
+ }
+
+ return this.convertToPercent(current);
+ },
+
+ checkMaxInterval: function (p_current, p_next, type) {
+ var o = this.options,
+ current,
+ next;
+
+ if (!o.max_interval) {
+ return p_current;
+ }
+
+ current = this.convertToValue(p_current);
+ next = this.convertToValue(p_next);
+
+ if (type === "from") {
+
+ if (next - current > o.max_interval) {
+ current = next - o.max_interval;
+ }
+
+ } else {
+
+ if (current - next > o.max_interval) {
+ current = next + o.max_interval;
+ }
+
+ }
+
+ return this.convertToPercent(current);
+ },
+
+ checkDiapason: function (p_num, min, max) {
+ var num = this.convertToValue(p_num),
+ o = this.options;
+
+ if (typeof min !== "number") {
+ min = o.min;
+ }
+
+ if (typeof max !== "number") {
+ max = o.max;
+ }
+
+ if (num < min) {
+ num = min;
+ }
+
+ if (num > max) {
+ num = max;
+ }
+
+ return this.convertToPercent(num);
+ },
+
+ toFixed: function (num) {
+ num = num.toFixed(20);
+ return +num;
+ },
+
+ _prettify: function (num) {
+ if (!this.options.prettify_enabled) {
+ return num;
+ }
+
+ if (this.options.prettify && typeof this.options.prettify === "function") {
+ return this.options.prettify(num);
+ } else {
+ return this.prettify(num);
+ }
+ },
+
+ prettify: function (num) {
+ var n = num.toString();
+ return n.replace(/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g, "$1" + this.options.prettify_separator);
+ },
+
+ checkEdges: function (left, width) {
+ if (!this.options.force_edges) {
+ return this.toFixed(left);
+ }
+
+ if (left < 0) {
+ left = 0;
+ } else if (left > 100 - width) {
+ left = 100 - width;
+ }
+
+ return this.toFixed(left);
+ },
+
+ validate: function () {
+ var o = this.options,
+ r = this.result,
+ v = o.values,
+ vl = v.length,
+ value,
+ i;
+
+ if (typeof o.min === "string") o.min = +o.min;
+ if (typeof o.max === "string") o.max = +o.max;
+ if (typeof o.from === "string") o.from = +o.from;
+ if (typeof o.to === "string") o.to = +o.to;
+ if (typeof o.step === "string") o.step = +o.step;
+
+ if (typeof o.from_min === "string") o.from_min = +o.from_min;
+ if (typeof o.from_max === "string") o.from_max = +o.from_max;
+ if (typeof o.to_min === "string") o.to_min = +o.to_min;
+ if (typeof o.to_max === "string") o.to_max = +o.to_max;
+
+ if (typeof o.grid_num === "string") o.grid_num = +o.grid_num;
+
+ if (o.max < o.min) {
+ o.max = o.min;
+ }
+
+ if (vl) {
+ o.p_values = [];
+ o.min = 0;
+ o.max = vl - 1;
+ o.step = 1;
+ o.grid_num = o.max;
+ o.grid_snap = true;
+
+ for (i = 0; i < vl; i++) {
+ value = +v[i];
+
+ if (!isNaN(value)) {
+ v[i] = value;
+ value = this._prettify(value);
+ } else {
+ value = v[i];
+ }
+
+ o.p_values.push(value);
+ }
+ }
+
+ if (typeof o.from !== "number" || isNaN(o.from)) {
+ o.from = o.min;
+ }
+
+ if (typeof o.to !== "number" || isNaN(o.to)) {
+ o.to = o.max;
+ }
+
+ if (o.type === "single") {
+
+ if (o.from < o.min) o.from = o.min;
+ if (o.from > o.max) o.from = o.max;
+
+ } else {
+
+ if (o.from < o.min) o.from = o.min;
+ if (o.from > o.max) o.from = o.max;
+
+ if (o.to < o.min) o.to = o.min;
+ if (o.to > o.max) o.to = o.max;
+
+ if (this.update_check.from) {
+
+ if (this.update_check.from !== o.from) {
+ if (o.from > o.to) o.from = o.to;
+ }
+ if (this.update_check.to !== o.to) {
+ if (o.to < o.from) o.to = o.from;
+ }
+
+ }
+
+ if (o.from > o.to) o.from = o.to;
+ if (o.to < o.from) o.to = o.from;
+
+ }
+
+ if (typeof o.step !== "number" || isNaN(o.step) || !o.step || o.step < 0) {
+ o.step = 1;
+ }
+
+ if (typeof o.from_min === "number" && o.from < o.from_min) {
+ o.from = o.from_min;
+ }
+
+ if (typeof o.from_max === "number" && o.from > o.from_max) {
+ o.from = o.from_max;
+ }
+
+ if (typeof o.to_min === "number" && o.to < o.to_min) {
+ o.to = o.to_min;
+ }
+
+ if (typeof o.to_max === "number" && o.from > o.to_max) {
+ o.to = o.to_max;
+ }
+
+ if (r) {
+ if (r.min !== o.min) {
+ r.min = o.min;
+ }
+
+ if (r.max !== o.max) {
+ r.max = o.max;
+ }
+
+ if (r.from < r.min || r.from > r.max) {
+ r.from = o.from;
+ }
+
+ if (r.to < r.min || r.to > r.max) {
+ r.to = o.to;
+ }
+ }
+
+ if (typeof o.min_interval !== "number" || isNaN(o.min_interval) || !o.min_interval || o.min_interval < 0) {
+ o.min_interval = 0;
+ }
+
+ if (typeof o.max_interval !== "number" || isNaN(o.max_interval) || !o.max_interval || o.max_interval < 0) {
+ o.max_interval = 0;
+ }
+
+ if (o.min_interval && o.min_interval > o.max - o.min) {
+ o.min_interval = o.max - o.min;
+ }
+
+ if (o.max_interval && o.max_interval > o.max - o.min) {
+ o.max_interval = o.max - o.min;
+ }
+ },
+
+ decorate: function (num, original) {
+ var decorated = "",
+ o = this.options;
+
+ if (o.prefix) {
+ decorated += o.prefix;
+ }
+
+ decorated += num;
+
+ if (o.max_postfix) {
+ if (o.values.length && num === o.p_values[o.max]) {
+ decorated += o.max_postfix;
+ if (o.postfix) {
+ decorated += " ";
+ }
+ } else if (original === o.max) {
+ decorated += o.max_postfix;
+ if (o.postfix) {
+ decorated += " ";
+ }
+ }
+ }
+
+ if (o.postfix) {
+ decorated += o.postfix;
+ }
+
+ return decorated;
+ },
+
+ updateFrom: function () {
+ this.result.from = this.options.from;
+ this.result.from_percent = this.convertToPercent(this.result.from);
+ this.result.from_pretty = this._prettify(this.result.from);
+ if (this.options.values) {
+ this.result.from_value = this.options.values[this.result.from];
+ }
+ },
+
+ updateTo: function () {
+ this.result.to = this.options.to;
+ this.result.to_percent = this.convertToPercent(this.result.to);
+ this.result.to_pretty = this._prettify(this.result.to);
+ if (this.options.values) {
+ this.result.to_value = this.options.values[this.result.to];
+ }
+ },
+
+ updateResult: function () {
+ this.result.min = this.options.min;
+ this.result.max = this.options.max;
+ this.updateFrom();
+ this.updateTo();
+ },
+
+
+ // =============================================================================================================
+ // Grid
+
+ appendGrid: function () {
+ if (!this.options.grid) {
+ return;
+ }
+
+ var o = this.options,
+ i, z,
+
+ total = o.max - o.min,
+ big_num = o.grid_num,
+ big_p = 0,
+ big_w = 0,
+
+ small_max = 4,
+ local_small_max,
+ small_p,
+ small_w = 0,
+
+ result,
+ html = '';
+
+
+
+ this.calcGridMargin();
+
+ if (o.grid_snap) {
+
+ if (total > 50) {
+ big_num = 50 / o.step;
+ big_p = this.toFixed(o.step / 0.5);
+ } else {
+ big_num = total / o.step;
+ big_p = this.toFixed(o.step / (total / 100));
+ }
+
+ } else {
+ big_p = this.toFixed(100 / big_num);
+ }
+
+ if (big_num > 4) {
+ small_max = 3;
+ }
+ if (big_num > 7) {
+ small_max = 2;
+ }
+ if (big_num > 14) {
+ small_max = 1;
+ }
+ if (big_num > 28) {
+ small_max = 0;
+ }
+
+ for (i = 0; i < big_num + 1; i++) {
+ local_small_max = small_max;
+
+ big_w = this.toFixed(big_p * i);
+
+ if (big_w > 100) {
+ big_w = 100;
+ }
+ this.coords.big[i] = big_w;
+
+ small_p = (big_w - (big_p * (i - 1))) / (local_small_max + 1);
+
+ for (z = 1; z <= local_small_max; z++) {
+ if (big_w === 0) {
+ break;
+ }
+
+ small_w = this.toFixed(big_w - (small_p * z));
+
+ html += '<span class="irs-grid-pol small" style="left: ' + small_w + '%"></span>';
+ }
+
+ html += '<span class="irs-grid-pol" style="left: ' + big_w + '%"></span>';
+
+ result = this.convertToValue(big_w);
+ if (o.values.length) {
+ result = o.p_values[result];
+ } else {
+ result = this._prettify(result);
+ }
+
+ html += '<span class="irs-grid-text js-grid-text-' + i + '" style="left: ' + big_w + '%">' + result + '</span>';
+ }
+ this.coords.big_num = Math.ceil(big_num + 1);
+
+
+
+ this.$cache.cont.addClass("irs-with-grid");
+ this.$cache.grid.html(html);
+ this.cacheGridLabels();
+ },
+
+ cacheGridLabels: function () {
+ var $label, i,
+ num = this.coords.big_num;
+
+ for (i = 0; i < num; i++) {
+ $label = this.$cache.grid.find(".js-grid-text-" + i);
+ this.$cache.grid_labels.push($label);
+ }
+
+ this.calcGridLabels();
+ },
+
+ calcGridLabels: function () {
+ var i, label, start = [], finish = [],
+ num = this.coords.big_num;
+
+ for (i = 0; i < num; i++) {
+ this.coords.big_w[i] = this.$cache.grid_labels[i].outerWidth(false);
+ this.coords.big_p[i] = this.toFixed(this.coords.big_w[i] / this.coords.w_rs * 100);
+ this.coords.big_x[i] = this.toFixed(this.coords.big_p[i] / 2);
+
+ start[i] = this.toFixed(this.coords.big[i] - this.coords.big_x[i]);
+ finish[i] = this.toFixed(start[i] + this.coords.big_p[i]);
+ }
+
+ if (this.options.force_edges) {
+ if (start[0] < -this.coords.grid_gap) {
+ start[0] = -this.coords.grid_gap;
+ finish[0] = this.toFixed(start[0] + this.coords.big_p[0]);
+
+ this.coords.big_x[0] = this.coords.grid_gap;
+ }
+
+ if (finish[num - 1] > 100 + this.coords.grid_gap) {
+ finish[num - 1] = 100 + this.coords.grid_gap;
+ start[num - 1] = this.toFixed(finish[num - 1] - this.coords.big_p[num - 1]);
+
+ this.coords.big_x[num - 1] = this.toFixed(this.coords.big_p[num - 1] - this.coords.grid_gap);
+ }
+ }
+
+ this.calcGridCollision(2, start, finish);
+ this.calcGridCollision(4, start, finish);
+
+ for (i = 0; i < num; i++) {
+ label = this.$cache.grid_labels[i][0];
+
+ if (this.coords.big_x[i] !== Number.POSITIVE_INFINITY) {
+ label.style.marginLeft = -this.coords.big_x[i] + "%";
+ }
+ }
+ },
+
+ // Collisions Calc Beta
+ // TODO: Refactor then have plenty of time
+ calcGridCollision: function (step, start, finish) {
+ var i, next_i, label,
+ num = this.coords.big_num;
+
+ for (i = 0; i < num; i += step) {
+ next_i = i + (step / 2);
+ if (next_i >= num) {
+ break;
+ }
+
+ label = this.$cache.grid_labels[next_i][0];
+
+ if (finish[i] <= start[next_i]) {
+ label.style.visibility = "visible";
+ } else {
+ label.style.visibility = "hidden";
+ }
+ }
+ },
+
+ calcGridMargin: function () {
+ if (!this.options.grid_margin) {
+ return;
+ }
+
+ this.coords.w_rs = this.$cache.rs.outerWidth(false);
+ if (!this.coords.w_rs) {
+ return;
+ }
+
+ if (this.options.type === "single") {
+ this.coords.w_handle = this.$cache.s_single.outerWidth(false);
+ } else {
+ this.coords.w_handle = this.$cache.s_from.outerWidth(false);
+ }
+ this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
+ this.coords.grid_gap = this.toFixed((this.coords.p_handle / 2) - 0.1);
+
+ this.$cache.grid[0].style.width = this.toFixed(100 - this.coords.p_handle) + "%";
+ this.$cache.grid[0].style.left = this.coords.grid_gap + "%";
+ },
+
+
+
+ // =============================================================================================================
+ // Public methods
+
+ update: function (options) {
+ if (!this.input) {
+ return;
+ }
+
+ this.is_update = true;
+
+ this.options.from = this.result.from;
+ this.options.to = this.result.to;
+ this.update_check.from = this.result.from;
+ this.update_check.to = this.result.to;
+
+ this.options = $.extend(this.options, options);
+ this.validate();
+ this.updateResult(options);
+
+ this.toggleInput();
+ this.remove();
+ this.init(true);
+ },
+
+ reset: function () {
+ if (!this.input) {
+ return;
+ }
+
+ this.updateResult();
+ this.update();
+ },
+
+ destroy: function () {
+ if (!this.input) {
+ return;
+ }
+
+ this.toggleInput();
+ this.$cache.input.prop("readonly", false);
+ $.data(this.input, "ionRangeSlider", null);
+
+ this.remove();
+ this.input = null;
+ this.options = null;
+ }
+ };
+
+ $.fn.ionRangeSlider = function (options) {
+ return this.each(function() {
+ if (!$.data(this, "ionRangeSlider")) {
+ $.data(this, "ionRangeSlider", new IonRangeSlider(this, options, plugin_count++));
+ }
+ });
+ };
+
+
+
+ // =================================================================================================================
+ // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
+
+ // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
+
+ // MIT license
+
+ (function() {
+ var lastTime = 0;
+ var vendors = ['ms', 'moz', 'webkit', 'o'];
+ for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
+ window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
+ window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
+ || window[vendors[x]+'CancelRequestAnimationFrame'];
+ }
+
+ if (!window.requestAnimationFrame)
+ window.requestAnimationFrame = function(callback, element) {
+ var currTime = new Date().getTime();
+ var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+ var id = window.setTimeout(function() { callback(currTime + timeToCall); },
+ timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+
+ if (!window.cancelAnimationFrame)
+ window.cancelAnimationFrame = function(id) {
+ clearTimeout(id);
+ };
+ }());
+
+}));
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Controller.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Controller.ts
new file mode 100644
index 00000000..338b8214
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Controller.ts
@@ -0,0 +1,204 @@
+/// <reference types="jquery" />
+
+import { Options, ResultData } from "../types";
+declare let srf: any;
+
+import { View } from "./View/View";
+import { Filter } from "./Filter/Filter";
+
+export class Controller {
+ private target: JQuery = undefined;
+ private filterSpinner: JQuery = undefined;
+
+ private views: { [key: string]: View } = {};
+ private filters: { [key: string]: Filter } = {};
+ private currentView: View = undefined;
+ private data: ResultData;
+ private printRequests: Options;
+
+ public constructor( target: JQuery, data: ResultData, printRequests: Options ) {
+ this.target = target;
+
+ if ( this.target !== undefined ) {
+ this.filterSpinner = this.target.find( 'div.filtered-filter-spinner' );
+ }
+
+ this.data = data;
+ this.printRequests = printRequests;
+
+ for ( let rowId in this.data ) {
+ if ( !this.data[ rowId ].hasOwnProperty( 'visible' ) ) {
+ this.data[ rowId ].visible = {};
+ }
+ }
+ }
+
+ public getData(): any {
+ return this.data;
+ }
+
+ public getPrintRequests(): Options {
+ return this.printRequests;
+ }
+
+ public getPath() {
+ return srf.settings.get( 'srfgScriptPath' ) + '/formats/filtered/resources/';
+ }
+
+ public attachView( viewid: string, view: View ) {
+
+ this.views[ viewid ] = view;
+
+ if ( this.currentView === undefined ) {
+ this.currentView = view;
+ view.show();
+ } else {
+ view.hide();
+ }
+
+ return this;
+ }
+
+ public getView( viewId: string ): View {
+ return this.views[ viewId ];
+ }
+
+ public attachFilter( filter: Filter ): JQueryPromise< void > {
+ let filterId = filter.getId();
+
+ this.filters[ filterId ] = filter;
+
+ filter.init();
+
+ return this.onFilterUpdated( filterId );
+ }
+
+ public getFilter( filterId: string ): Filter {
+ return this.filters[ filterId ];
+ }
+
+ public show() {
+ this.initializeFilters();
+ this.target.children( '.filtered-spinner' ).remove();
+ this.target.children().show();
+ this.switchToView( this.currentView );
+ }
+
+ private switchToView( view: View ) {
+
+ if ( this.currentView instanceof View ) {
+ this.currentView.hide();
+ }
+
+ this.currentView = view;
+
+ if ( this.currentView instanceof View ) {
+ view.show();
+ }
+
+ }
+
+ private initializeFilters() {
+ let toShow: string[] = [];
+ let toHide: string[] = [];
+
+ for ( let rowId in this.data ) {
+ for ( let filterId in this.filters ) {
+ this.data[ rowId ].visible[ filterId ] = this.filters[ filterId ].isDisabled() || this.filters[ filterId ].isVisible( rowId );
+ }
+ if ( this.isVisible( rowId ) ) {
+ toShow.push( rowId );
+ } else {
+ toHide.push( rowId );
+ }
+ }
+
+ this.hideRows( toHide );
+ this.showRows( toShow );
+ }
+
+ public onViewSelected( viewID: string ) {
+ this.switchToView( this.views[ viewID ] );
+ }
+
+ public onFilterUpdated( filterId: string ): JQueryPromise< void > {
+
+ return this.showSpinner()
+ .then(() => {
+
+ let toShow: string[] = [];
+ let toHide: string[] = [];
+
+ let disabled = this.filters[ filterId ].isDisabled();
+
+ for ( let rowId in this.data ) {
+
+ let newVisible: boolean = disabled || this.filters[ filterId ].isVisible( rowId );
+
+ if ( this.data[ rowId ].visible[ filterId ] !== newVisible ) {
+
+ this.data[ rowId ].visible[ filterId ] = newVisible;
+
+ if ( newVisible && this.isVisible( rowId ) ) {
+ toShow.push( rowId );
+ } else {
+ toHide.push( rowId );
+ }
+ }
+ }
+
+ this.hideRows( toHide );
+ this.showRows( toShow );
+ })
+ .then( () => { this.hideSpinner() } );
+ }
+
+ public isVisible( rowId: any ) {
+ for ( let filterId in this.data[ rowId ].visible ) {
+ if ( !this.data[ rowId ].visible[ filterId ] ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private hideRows( rowIds: string[] ) {
+ if ( rowIds.length === 0 ) {
+ return;
+ }
+ for ( let viewId in this.views ) {
+ this.views[ viewId ].hideRows( rowIds );
+ }
+ }
+
+ private showRows( rowIds: string[] ) {
+ if ( rowIds.length === 0 ) {
+ return;
+ }
+ for ( let viewId in this.views ) {
+ this.views[ viewId ].showRows( rowIds );
+ }
+ }
+
+ private showSpinner(): JQueryPromise< void > {
+ return this.animateSpinner();
+ }
+
+ private hideSpinner(): JQueryPromise< void > {
+ return this.animateSpinner( false );
+ }
+
+ private animateSpinner( show: boolean = true ): JQueryPromise< void > {
+
+ if ( this.filterSpinner === undefined ) {
+ return jQuery.when();
+ }
+
+ if ( show ) {
+ return this.filterSpinner.fadeIn( 200 ).promise();
+ }
+
+ return this.filterSpinner.fadeOut( 200 ).promise();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/DistanceFilter.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/DistanceFilter.ts
new file mode 100644
index 00000000..88c97257
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/DistanceFilter.ts
@@ -0,0 +1,142 @@
+import { Filter } from "./Filter";
+
+declare let mw: any;
+
+export class DistanceFilter extends Filter {
+
+ private static readonly earthRadius: { [key: string]: number } = {
+ m: 6371008.8,
+ km: 6371.0088,
+ mi: 3958.7613,
+ nm: 3440.0695,
+ Ã…: 63710088000000000
+ };
+
+ private earthRadiusValue: number = DistanceFilter.earthRadius.km;
+ private filterValue: number = 0;
+
+ public init() {
+
+ let values = this.controller.getData();
+
+ let origin = this.options[ 'origin' ];
+
+ if ( !( origin !== undefined && origin.hasOwnProperty( 'lat' ) && origin.hasOwnProperty( 'lng' ) ) ) {
+ this.target.detach();
+ return;
+ }
+
+ let unit = 'km';
+
+ if ( this.options[ 'unit' ] && DistanceFilter.earthRadius[ this.options[ 'unit' ] ] ) {
+ unit = this.options[ 'unit' ];
+ }
+
+ this.earthRadiusValue = DistanceFilter.earthRadius[ unit ];
+
+ let maxValue: number = this.updateDistances( origin );
+
+ let precision = 10 ** ( Math.floor( Math.log( maxValue ) * Math.LOG10E ) - 1);
+
+ if ( this.options[ 'max' ] !== undefined && this.options[ 'max' ] > maxValue ) {
+ maxValue = this.options[ 'max' ];
+ } else {
+ maxValue = Math.ceil( maxValue / precision ) * precision;
+ }
+
+ this.filterValue = this.options[ 'initial value' ] ? Math.min( this.options[ 'initial value' ], maxValue ) : maxValue;
+
+ // build filter controls
+ let filtercontrols = this.buildEmptyControl();
+
+ let readout = $( '<div class="filtered-distance-readout">' + this.filterValue + '</div>' );
+
+ let table = $( '<table class="filtered-distance-table"><tbody><tr><td class="filtered-distance-min-cell">0</td>' +
+ '<td class="filtered-distance-slider-cell"><div class="filtered-distance-slider"></div></td>' +
+ '<td class="filtered-distance-max-cell">' + maxValue + '</td></tr>' +
+ '<tr><td colspan=3 class="filtered-distance-unit-cell">' + unit + '</td></tr></tbody></table>' );
+
+ filtercontrols.append( table );
+
+ let that = this;
+ mw.loader.using( 'jquery.ui.slider' ).then( function () {
+
+ table.find( '.filtered-distance-slider' )
+ .slider( {
+ animate: true,
+ max: maxValue,
+ value: that.filterValue,
+ step: precision / 100
+ } )
+ .on( 'slidechange', undefined, { 'filter': that }, function ( eventObject: JQueryEventObject, ui: any ) {
+ eventObject.data.ui = ui;
+ eventObject.data.filter.onFilterUpdated( eventObject );
+ } )
+ .on( 'slide', undefined, { 'filter': that }, function ( eventObject: JQueryEventObject, ui: any ) {
+ readout.text( ui.value );
+ } )
+ .find( '.ui-slider-handle' )
+ .append( readout );
+
+ } );
+
+ return this;
+ }
+
+ private updateDistances( origin: L.LatLngLiteral ): number {
+
+ let values = this.controller.getData();
+ let max = 1;
+
+ let prId = this.printrequestId;
+
+ for ( let rowId in values ) {
+
+ if ( values[ rowId ].data.hasOwnProperty( this.filterId ) ) {
+ let distances: number[] = values[ rowId ].data[ this.filterId ].positions.map( ( pos: L.LatLngLiteral ) => this.distance( origin, pos ) );
+ let dist = Math.min( ...distances );
+
+ values[ rowId ].data[ this.filterId ].distance = dist;
+ max = Math.max( max, dist );
+ } else {
+ values[ rowId ].data[ this.filterId ].distance = Infinity;
+ }
+ }
+
+ return max;
+ }
+
+ public onFilterUpdated( eventObject: JQueryEventObject ) {
+ this.filterValue = eventObject.data.ui.value;
+ this.controller.onFilterUpdated( this.getId() );
+ }
+
+ private distance( a: L.LatLngLiteral, b: L.LatLngLiteral ) {
+
+ const DEG2RAD = Math.PI / 180.0;
+
+ function squared( x: number ) {
+ return x * x
+ }
+
+ let f =
+ squared( Math.sin( ( b.lat - a.lat ) * DEG2RAD / 2.0 ) ) +
+ Math.cos( a.lat * DEG2RAD ) * Math.cos( b.lat * DEG2RAD ) *
+ squared( Math.sin( ( b.lng - a.lng ) * DEG2RAD / 2.0 ) );
+
+ return this.earthRadiusValue * 2 * Math.atan2( Math.sqrt( f ), Math.sqrt( 1 - f ) );
+ }
+
+ public isVisible( rowId: string ): boolean {
+
+ let rowdata = this.controller.getData()[ rowId ].data;
+
+ if ( rowdata.hasOwnProperty( this.filterId ) ) {
+ return rowdata[ this.filterId ].distance <= this.filterValue;
+ }
+
+ return super.isVisible( rowId );
+
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/Filter.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/Filter.ts
new file mode 100644
index 00000000..f89488f7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/Filter.ts
@@ -0,0 +1,180 @@
+import { Options } from "../../types";
+import { Controller } from "../Controller";
+
+export abstract class Filter{
+
+ private outerTarget: JQuery = undefined;
+ protected target: JQuery = undefined;
+ protected filterId: string;
+ protected printrequestId: string;
+ protected controller: Controller;
+ protected options: Options = undefined;
+ protected disabled: boolean = false;
+ protected collapsed: boolean = false;
+
+ public constructor( filterId: string, target: JQuery, printrequestId: string, controller: Controller, options?: Options ) {
+ this.target = target;
+ this.outerTarget = target;
+ this.filterId = filterId;
+ this.printrequestId = printrequestId;
+ this.controller = controller;
+ this.options = options || {};
+ }
+
+ public init() {};
+
+ public isDisabled() : boolean {
+ return this.disabled;
+ }
+
+ public disable() {
+ this.disabled = true;
+
+ this.outerTarget
+ .removeClass( 'enabled' )
+ .addClass( 'disabled' );
+
+ this.collapse();
+
+ this.target.promise().then( () => this.controller.onFilterUpdated( this.filterId ) );
+ }
+
+ public enable() {
+ this.disabled = false;
+
+ this.outerTarget
+ .removeClass( 'disabled' )
+ .addClass( 'enabled' );
+
+ if ( ! this.collapsed ) {
+ this.uncollapse();
+ }
+
+ this.target.promise().then( () => this.controller.onFilterUpdated( this.filterId ) );
+ }
+
+ private collapse( duration : number = 400 ) {
+
+ if ( ! this.collapsed ) {
+
+ this.outerTarget.promise()
+ .then( () => {
+
+ this.target.slideUp( duration );
+
+ this.outerTarget.animate( {
+ 'padding-top': 0,
+ 'padding-bottom': 0,
+ 'margin-bottom': '2em'
+ }, duration );
+ } );
+ }
+ }
+
+ private uncollapse() {
+ this.outerTarget.promise()
+ .then( () => {
+ this.target.slideDown();
+
+ let style = this.outerTarget.attr( 'style' );
+ this.outerTarget.removeAttr( 'style' );
+ let uncollapsedCss = this.outerTarget.css( [ 'padding-top', 'padding-bottom', 'margin-bottom' ] );
+ this.outerTarget.attr( 'style', style );
+
+ this.outerTarget.animate( uncollapsedCss );
+ } );
+ }
+
+ public isVisible( rowId: string ): boolean {
+ return this.options.hasOwnProperty( 'show if undefined' ) && this.options[ 'show if undefined' ] === true;
+ }
+
+ public getId() {
+ return this.filterId;
+ }
+
+ protected buildEmptyControl() {
+
+ this.target = $( '<div class="filtered-filter-container">' );
+
+ this.outerTarget
+ .append( this.target )
+ .addClass( 'enabled' );
+
+ this.addOnOffSwitch();
+ this.addLabel();
+ this.addControlForCollapsing();
+
+ return this.target;
+ }
+
+ private addLabel() {
+ // insert the label of the printout this filter filters on
+ this.target.before( `<div class="filtered-filter-label">${this.options[ 'label' ]}</div>` );
+ }
+
+ protected addOnOffSwitch() {
+
+ if ( this.options.hasOwnProperty( 'switches' ) ) {
+
+ let switches = this.options[ 'switches' ];
+
+ if ( switches.length > 0 && $.inArray( 'on off', switches ) >= 0 ) {
+
+ let onOffControl = $( `<div class="filtered-filter-onoff on"></div>` );
+
+ this.target.before( onOffControl );
+
+ onOffControl.click( () => {
+
+ if ( this.outerTarget.hasClass('enabled' ) ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+
+ } );
+ }
+ }
+ }
+
+ protected addControlForCollapsing() {
+ let collapsible = this.options.hasOwnProperty( 'collapsible' ) ? this.options[ 'collapsible' ] : undefined;
+ if ( collapsible === 'collapsed' || collapsible === 'uncollapsed' ) {
+
+ let collapseControl = $( '<span class="filtered-filter-collapse">' );
+
+ this.target.before( collapseControl );
+
+ collapseControl.click( () => {
+ if ( collapseControl.hasClass( 'collapsed' ) ) {
+ this.uncollapse();
+ this.collapsed = false;
+
+ collapseControl
+ .removeClass( 'collapsed' )
+ .addClass( 'uncollapsed' );
+ } else {
+ this.collapse();
+ this.collapsed = true;
+
+ collapseControl
+ .removeClass( 'uncollapsed' )
+ .addClass( 'collapsed' );
+ }
+
+ } );
+
+ if ( collapsible === 'collapsed' ) {
+
+ this.collapse( 0 );
+ this.collapsed = true;
+ collapseControl.addClass('collapsed');
+
+ } else {
+ collapseControl.addClass('uncollapsed');
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/NumberFilter.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/NumberFilter.ts
new file mode 100644
index 00000000..faabce70
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/NumberFilter.ts
@@ -0,0 +1,288 @@
+///<reference path="../../../../node_modules/@types/ion.rangeslider/index.d.ts"/>
+import { Filter } from "./Filter";
+import { Options } from "../../types";
+
+declare let mw: any;
+
+export class NumberFilter extends Filter {
+
+ private MODE_RANGE = 0;
+ private MODE_MIN = 1;
+ private MODE_MAX = 2;
+ private MODE_SELECT = 3;
+
+ private filterValueUpper: number = 0;
+ private filterValueLower: number = 0;
+ private mode = this.MODE_RANGE;
+
+ public init() {
+
+ let values: number[] = this.getValues();
+
+ let { minValue, maxValue, precision } = this.getRangeParameters( values );
+
+ let sliderOptions: IonRangeSliderOptions = {
+ prettify_enabled: false,
+ force_edges: true,
+ grid: true
+ };
+
+ if ( this.options.hasOwnProperty( 'values' ) ) {
+ sliderOptions = this.adjustSliderOptionsFromValues( sliderOptions, values );
+
+ } else {
+ sliderOptions = this.adjustSliderOptionsFromRangeParameters( sliderOptions, minValue, maxValue, precision );
+ }
+
+ switch( this.options[ 'sliders' ] ) {
+
+ case "min":
+
+ this.mode = this.MODE_MIN;
+ sliderOptions.type = 'single';
+ break;
+
+ case "max":
+
+ this.mode = this.MODE_MAX;
+ sliderOptions.from = sliderOptions.to;
+ sliderOptions.type = 'single';
+ break;
+
+ case "select":
+
+ this.mode = this.MODE_SELECT;
+ maxValue = minValue;
+ sliderOptions.type = 'single';
+ break;
+
+ default: // == case "range"
+
+ this.mode = this.MODE_RANGE;
+ sliderOptions.type = 'double';
+ }
+
+ this.buildFilterControls( sliderOptions );
+
+ this.filterValueLower = minValue;
+ this.filterValueUpper = maxValue;
+
+ return this;
+ }
+
+ private adjustSliderOptionsFromRangeParameters( sliderOptions: IonRangeSliderOptions, minValue: number, maxValue: number, precision: number ) {
+
+ sliderOptions.min = minValue;
+ sliderOptions.max = maxValue;
+ sliderOptions.step = this.getStep( precision );
+ sliderOptions.grid_num = Math.min( 4, Math.round( ( maxValue - minValue ) / sliderOptions.step ) );
+
+ sliderOptions.from = minValue;
+ sliderOptions.to = maxValue;
+
+ sliderOptions.onFinish = ( data: IonRangeSliderEvent ) => this.onFilterUpdated( data.from, data.to );
+
+ return sliderOptions;
+ }
+
+ private adjustSliderOptionsFromValues( sliderOptions: IonRangeSliderOptions, values: number[] ) {
+
+ sliderOptions.values = values;
+
+ sliderOptions.from = 0;
+ sliderOptions.to = values.length - 1;
+
+ sliderOptions.onFinish = ( data: IonRangeSliderEvent ) => this.onFilterUpdated( data.from_value, data.to_value );
+
+ return sliderOptions;
+ }
+
+ private getRangeParameters( values: number[] ) {
+
+ let minValue = values[ 0 ];
+ let maxValue = values[ values.length - 1 ];
+ let precision: number = this.getPrecision( minValue, maxValue );
+
+ if ( !this.options.hasOwnProperty( 'values' ) ) {
+ minValue = this.getMinSliderValue( minValue, precision );
+ maxValue = this.getMaxSliderValue( maxValue, precision );
+ }
+
+ return { minValue, maxValue, precision };
+ }
+
+ private getValues(): number[] {
+ let values: number[];
+ if ( this.options.hasOwnProperty( 'values' ) && this.options[ 'values' ][0] !== 'auto' ) {
+ values = this.options[ 'values' ]
+ } else {
+ values = this.getSortedValues();
+ }
+
+ if ( values.length === 0 ) {
+ values = [ 0, 0 ];
+ } else if ( values.length === 1 ) {
+ values.push( values[ 0 ] );
+ }
+
+ return values;
+ }
+
+ private buildFilterControls( sliderOptions: IonRangeSliderOptions ) {
+
+ let filterClassNames: any = {};
+ filterClassNames[ this.MODE_MIN.toString() ] = "mode-min";
+ filterClassNames[ this.MODE_MAX ] = "mode-max";
+ filterClassNames[ this.MODE_RANGE ] = "mode-range";
+ filterClassNames[ this.MODE_SELECT ] = "mode-select";
+
+ let filtercontrols = this.buildEmptyControl();
+
+ let slider = $( '<input type="text" value="" />' );
+ let sliderContainer = $( `<div class="filtered-number-slider ${filterClassNames[ this.mode ]}" />` ).append( slider );
+ filtercontrols.append( sliderContainer );
+
+ if ( this.options.hasOwnProperty( 'caption' ) ) {
+ let caption = `<div class="filtered-number-caption">${this.options[ 'caption' ]}</div>`;
+ filtercontrols.append( caption );
+ }
+
+ mw.loader.using( 'ext.srf.filtered.slider' ).then( () => slider.ionRangeSlider( sliderOptions ) );
+ }
+
+ private getMinSliderValue( minValue: number, precision: number ) {
+ let requestedMin = this.options[ 'min' ];
+
+ if ( requestedMin === undefined || isNaN( Number( requestedMin ) ) ) {
+ return Math.floor( minValue / precision ) * precision;
+ }
+
+ return Math.min( requestedMin, minValue );
+ }
+
+ private getMaxSliderValue( maxValue: number, precision: number ) {
+ let requestedMax = this.options[ 'max' ];
+
+ if ( requestedMax === undefined || isNaN( Number( requestedMax ) ) ) {
+ return Math.ceil( maxValue / precision ) * precision;
+ }
+
+ return Math.max( requestedMax, maxValue );
+ }
+
+ private getPrecision( minValue: number, maxValue: number ): number {
+ if ( maxValue - minValue > 0 ) {
+ return 10 ** ( Math.floor( Math.log( maxValue - minValue ) * Math.LOG10E ) - 1 );
+ } else {
+ return 1;
+ }
+ }
+
+ private getStep( precision: number ): number {
+
+ let step = this.options[ 'step' ];
+
+ if ( step !== undefined ) {
+
+ step = Number( step );
+
+ if ( !isNaN( step ) ) {
+ return step;
+ }
+ }
+
+ return precision / 10;
+ }
+
+ private getRangeFromValues(): [ number, number ] {
+
+ let rows = this.controller.getData();
+ let min = Infinity;
+ let max = -Infinity;
+
+ for ( let rowId in rows ) {
+
+ if ( rows[ rowId ].data.hasOwnProperty( this.filterId ) ) {
+ let values: number[] = rows[ rowId ].data[ this.filterId ].values;
+ min = Math.min( min, ...values );
+ max = Math.max( max, ...values );
+ }
+ }
+
+ return [ min, max ];
+ }
+
+ private getSortedValues(): number[] {
+
+ let valueArray: number[] = [];
+ let rows = this.controller.getData();
+
+ for ( let rowId in rows ) {
+
+ let cells = rows[ rowId ].data;
+
+ if ( cells.hasOwnProperty( this.filterId ) ) {
+
+ let values = cells[ this.filterId ].values;
+
+ for ( let valueId in values ) {
+
+ let value = Number( values[ valueId ] );
+
+ if ( valueArray.indexOf( value ) === -1 ) {
+ valueArray.push( value );
+ }
+ }
+ }
+ }
+
+ return valueArray.sort( ( a: any, b: any ) => a - b );
+ }
+
+ public onFilterUpdated( from: number, to: number ) {
+
+ switch ( this.mode ) {
+
+ case this.MODE_MIN:
+
+ this.filterValueLower = from;
+ break;
+
+ case this.MODE_MAX:
+
+ this.filterValueUpper = from;
+ break;
+
+ case this.MODE_SELECT:
+
+ this.filterValueLower = from;
+ this.filterValueUpper = from;
+ break;
+
+ default: // case this.MODE_RANGE:
+
+ this.filterValueLower = from;
+ this.filterValueUpper = to;
+ }
+
+ this.controller.onFilterUpdated( this.getId() );
+ }
+
+ public isVisible( rowId: string ): boolean {
+ let rowdata = this.controller.getData()[ rowId ].data;
+
+ if ( rowdata.hasOwnProperty( this.filterId ) && rowdata[ this.filterId ].values.length > 0 ) {
+
+ for ( let value of rowdata[ this.filterId ].values ) {
+ if ( value >= this.filterValueLower && value <= this.filterValueUpper ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return super.isVisible( rowId );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/ValueFilter.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/ValueFilter.ts
new file mode 100644
index 00000000..8293fdf0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filter/ValueFilter.ts
@@ -0,0 +1,237 @@
+import { Filter } from "./Filter";
+import { IdTextPair } from "select2";
+
+declare let mw: any;
+
+export class ValueFilter extends Filter {
+
+ private values: any = {};
+ private visibleValues: string[] = [];
+
+ private _useOr = true;
+
+ public init() {
+ this.values = this.getSortedValues();
+ this.buildControl();
+ }
+
+ public useOr( useOr: boolean ) {
+ this._useOr = useOr;
+ this.controller.onFilterUpdated( this.getId() );
+ }
+
+ private getSortedValues(): any {
+
+ /** Map of value => label distinct values */
+ let distinctValues: any = {};
+ /** Map of value => sort value distinct values */
+ let distinctSortValues: any = {};
+
+ if ( this.options.hasOwnProperty( 'values' ) ) {
+
+ return this.options[ 'values' ].map(
+ ( item: string ) => {
+ return {
+ printoutValue: item,
+ formattedValue: item
+ };
+ }
+ );
+
+ } else {
+ // build filter values from available values in result set
+ let data = this.controller.getData();
+ let sortedEntries: any[] = [];
+ for ( let id in data ) {
+
+ let printoutValues: any = data[ id ][ 'printouts' ][ this.printrequestId ][ 'values' ];
+ let printoutFormattedValues = data[ id ][ 'printouts' ][ this.printrequestId ][ 'formatted values' ];
+ let printoutSortValues: any = data[ id ][ 'printouts' ][ this.printrequestId ][ 'sort values' ];
+
+ for ( let i in printoutValues ) {
+ let printoutFormattedValue = printoutFormattedValues[ i ];
+
+ if ( printoutFormattedValue.indexOf( '<a' ) > -1 ) {
+ printoutFormattedValue = /<a.*>(.*?)<\/a>/.exec( printoutFormattedValue )[ 1 ];
+ }
+
+ distinctValues[ printoutValues[ i ] ] = printoutFormattedValue;
+ distinctSortValues[ printoutValues[ i ] ] = printoutSortValues[ i ];
+ }
+
+ }
+
+ for ( let printoutValue in distinctSortValues ) {
+ sortedEntries.push( {
+ printoutValue: printoutValue,
+ sortValue: distinctSortValues[ printoutValue ],
+ formattedValue: distinctValues[ printoutValue ]
+ } );
+ }
+
+ sortedEntries.sort(
+ ( a: any, b: any ) => {
+ return a.sortValue.localeCompare( b.sortValue );
+ } );
+ return sortedEntries;
+
+ }
+
+ }
+
+ private buildControl() {
+
+ let filtercontrols = this.buildEmptyControl();
+
+ filtercontrols = this.addControlForSwitches( filtercontrols );
+
+ let maxCheckboxes = this.options.hasOwnProperty( 'max checkboxes' ) ? this.options[ 'max checkboxes' ] : 5;
+
+ if ( this.values.length > maxCheckboxes ) {
+ filtercontrols.append( this.getSelected2Control() );
+ } else {
+ filtercontrols.append( this.getCheckboxesControl() );
+ }
+
+ }
+
+ private getCheckboxesControl() {
+
+ let checkboxes = $( '<div class="filtered-value-checkboxes" style="width: 100%;">' );
+
+ // insert options (checkboxes and labels)
+ for ( let value of this.values ) {
+ checkboxes.append( `<div class="filtered-value-option"><label><input type="checkbox" value="${value.printoutValue}" ><div class="filtered-value-option-label">${value.formattedValue || value.printoutValue}</div></label></div>` );
+ }
+
+ // attach event handler
+ checkboxes
+ .on( 'change', ':checkbox', ( eventObject: JQueryEventObject ) => {
+ let checkboxElement = <HTMLInputElement> eventObject.currentTarget;
+ this.onFilterUpdated( checkboxElement.value, checkboxElement.checked );
+ } );
+
+ return checkboxes;
+ }
+
+ private getSelected2Control() {
+
+ let select = $( '<select class="filtered-value-select" style="width: 100%;">' );
+
+ let data: IdTextPair[] = [];
+
+ // insert options (checkboxes and labels) and attach event handlers
+ for ( let value of this.values ) {
+ // Try to get label, if not fall back to value id
+ let label = value.formattedValue || value.printoutValue;
+ data.push( { id: value.printoutValue, text: label } );
+
+ }
+
+ mw.loader.using( 'ext.srf.filtered.value-filter.select' ).then( () => {
+
+ select.select2( {
+ multiple: true,
+ placeholder: mw.message( 'srf-filtered-value-filter-placeholder' ).text(),
+ data: data
+ } );
+
+ select.on( "select2:select", ( e: any ) => {
+ this.onFilterUpdated( e.params.data.id, true );
+ } );
+
+ select.on( "select2:unselect", ( e: any ) => {
+ this.onFilterUpdated( e.params.data.id, false );
+ } );
+
+ } );
+
+ return select;
+ }
+
+ private addControlForSwitches( filtercontrols: JQuery ): JQuery {
+ // insert switches
+ let switches = this.options.hasOwnProperty( 'switches' ) ? this.options[ 'switches' ] : undefined;
+
+ if ( switches !== undefined && $.inArray( 'and or', switches ) >= 0 ) {
+
+ let switchControls = $( '<div class="filtered-value-switches">' );
+
+ let andorControl = $( '<div class="filtered-value-andor">' );
+
+ let orControl = this.getRadioControl( 'or', true );
+ let andControl = this.getRadioControl( 'and' );
+
+ andorControl
+ .append( orControl )
+ .append( andControl )
+ .appendTo( switchControls );
+
+ andorControl
+ .find( 'input' )
+ .on( 'change', undefined, { 'filter': this }, ( eventObject: JQueryEventObject ) =>
+ eventObject.data.filter.useOr( eventObject.target.getAttribute( 'value' ) === 'or' )
+ );
+
+
+ filtercontrols.append( switchControls );
+ }
+
+ return filtercontrols;
+ }
+
+ private getRadioControl( type: string, isChecked: boolean = false ) {
+
+ let checkedAttr = isChecked?'checked':'';
+ let labelText = mw.message( 'srf-filtered-value-filter-' + type ).text();
+
+ let controlText =
+ `<label for="filtered-value-${type}-${this.printrequestId}">` +
+ `<input type="radio" name="filtered-value-${this.printrequestId}" class="filtered-value-${type}" id="filtered-value-${type}-${this.printrequestId}" value="${type}" ${checkedAttr}>` +
+ `${labelText}</label>`;
+
+ return $( controlText );
+ }
+
+ public isVisible( rowId: string ): boolean {
+
+ if ( this.visibleValues.length === 0 ) {
+ return true;
+ }
+
+ let values: string[] = this.controller.getData()[ rowId ].printouts[ this.printrequestId ].values;
+
+ if ( values.length === 0 ) {
+ return super.isVisible( rowId );
+ }
+
+
+ if ( this._useOr ) {
+ for ( let expectedValue of this.visibleValues ) {
+ if ( values.indexOf( expectedValue ) >= 0 ) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ for ( let expectedValue of this.visibleValues ) {
+ if ( values.indexOf( expectedValue ) < 0 ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ public onFilterUpdated( value: string, isChecked: boolean ) {
+ let index = this.visibleValues.indexOf( value );
+
+ if ( isChecked && index === -1 ) {
+ this.visibleValues.push( value );
+ } else if ( !isChecked && index >= 0 ) {
+ this.visibleValues.splice( index, 1 );
+ }
+
+ this.controller.onFilterUpdated( this.getId() );
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filtered.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filtered.ts
new file mode 100644
index 00000000..6cc56bd6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/Filtered.ts
@@ -0,0 +1,108 @@
+import { Options } from "../types";
+import { Controller } from "./Controller";
+import { ViewSelector } from "./ViewSelector";
+import { View } from "./View/View";
+import { ListView } from "./View/ListView";
+import { TableView } from "./View/TableView";
+import { MapView } from "./View/MapView";
+import { CalendarView } from "./View/CalendarView";
+import { Filter } from "./Filter/Filter";
+import { ValueFilter } from "./Filter/ValueFilter";
+import { DistanceFilter } from "./Filter/DistanceFilter";
+import { NumberFilter } from "./Filter/NumberFilter";
+
+/**
+ * Central Filtered class
+ *
+ * Factory to setup everyhting else
+ */
+export class Filtered {
+
+ private config: any;
+ private target: JQuery;
+
+ private viewTypes: { [key: string]: new( id: string, target: JQuery, controller: Controller, options?: any ) => View } = {
+ table: TableView,
+ list: ListView,
+ map: MapView,
+ calendar: CalendarView
+ };
+
+ private filterTypes: { [key: string]: new( id: string, target: JQuery, printrequestId: string, controller: Controller, options?: Options ) => Filter } = {
+ value: ValueFilter,
+ distance: DistanceFilter,
+ number: NumberFilter
+ };
+
+ /**
+ *
+ * @param target
+ * @param config
+ */
+ public constructor( target: JQuery, config: any ) {
+ this.config = config;
+ this.target = target;
+ }
+
+ public run() {
+
+ let controller = new Controller( this.target, this.config.data, this.config.printrequests );
+
+ this.attachFilters( controller, this.target.children( 'div.filtered-filters' ) );
+ this.attachViewSelector( controller, this.target.find( 'div.filtered-views-selectors-container' ) );
+ this.attachViews( controller, this.target.find( 'div.filtered-views-container' ) );
+
+ // lift-off
+ controller.show();
+
+ }
+
+ private attachFilters( controller: Controller, filtersContainer: JQuery ) {
+
+ for ( let prId in this.config.printrequests ) {
+
+ let pr = this.config.printrequests[ prId ];
+
+ if ( pr.hasOwnProperty( 'filters' ) ) {
+
+ for ( let filterid in pr.filters ) {
+
+ if ( pr.filters.hasOwnProperty( filterid ) &&
+ pr.filters[ filterid ].hasOwnProperty( 'type' ) &&
+ this.filterTypes.hasOwnProperty( pr.filters[ filterid ].type ) ) {
+
+ // target: JQuery, printrequest: string,
+ // controller: Controller, options?: Options
+ let filter: Filter = new this.filterTypes[ pr.filters[ filterid ].type ]( filterid, filtersContainer.children( '#' + filterid ), prId, controller, pr.filters[ filterid ] );
+
+ controller.attachFilter( filter );
+
+ }
+ }
+ }
+
+ }
+ }
+
+ private attachViewSelector( controller: Controller, viewSelectorContainer: JQuery ) {
+ let viewSelector = new ViewSelector( viewSelectorContainer, Object.keys( this.config.views ), controller );
+ viewSelector.init();
+ }
+
+ private attachViews( controller: Controller, viewsContainer: JQuery ) {
+
+ // attach views
+ for ( let viewid in this.config.views ) {
+
+ let viewtype = this.config.views[ viewid ][ 'type' ];
+ let viewHandlerClass = this.viewTypes.hasOwnProperty( viewtype ) ? this.viewTypes[ viewtype ] : View;
+
+ let view: View = new viewHandlerClass( viewid, viewsContainer.children( '#' + viewid ), controller, this.config.views[ viewid ] );
+
+ view.init();
+
+ controller.attachView( viewid, view );
+
+ }
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/CalendarView.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/CalendarView.ts
new file mode 100644
index 00000000..da77614e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/CalendarView.ts
@@ -0,0 +1,122 @@
+import { View } from "./View";
+declare let mw: any;
+
+export class CalendarView extends View {
+
+ private getI18N() {
+ return {
+ monthNames: [ mw.msg( 'january' ), mw.msg( 'february' ), mw.msg( 'march' ),
+ mw.msg( 'april' ), mw.msg( 'may_long' ), mw.msg( 'june' ),
+ mw.msg( 'july' ), mw.msg( 'august' ), mw.msg( 'september' ),
+ mw.msg( 'october' ), mw.msg( 'november' ), mw.msg( 'december' )
+ ],
+ monthNamesShort: [ mw.msg( 'jan' ), mw.msg( 'feb' ), mw.msg( 'mar' ),
+ mw.msg( 'apr' ), mw.msg( 'may' ), mw.msg( 'jun' ),
+ mw.msg( 'jul' ), mw.msg( 'aug' ), mw.msg( 'sep' ),
+ mw.msg( 'oct' ), mw.msg( 'nov' ), mw.msg( 'dec' )
+ ],
+ dayNames: [ mw.msg( 'sunday' ), mw.msg( 'monday' ), mw.msg( 'tuesday' ),
+ mw.msg( 'wednesday' ), mw.msg( 'thursday' ), mw.msg( 'friday' ), mw.msg( 'saturday' )
+ ],
+ dayNamesShort: [ mw.msg( 'sun' ), mw.msg( 'mon' ), mw.msg( 'tue' ),
+ mw.msg( 'wed' ), mw.msg( 'thu' ), mw.msg( 'fri' ), mw.msg( 'sat' )
+ ],
+ buttonText: {
+ today: mw.msg( 'srf-ui-eventcalendar-label-today' ),
+ month: mw.msg( 'srf-ui-eventcalendar-label-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-label-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-label-day' )
+ }
+ ,
+ allDayText: mw.msg( 'srf-ui-eventcalendar-label-allday' ),
+ timeFormat: {
+ '': mw.msg( 'srf-ui-eventcalendar-format-time' ),
+ agenda: mw.msg( 'srf-ui-eventcalendar-format-time-agenda' )
+ }
+ ,
+ axisFormat: mw.msg( 'srf-ui-eventcalendar-format-axis' ),
+ titleFormat: {
+ month: mw.msg( 'srf-ui-eventcalendar-format-title-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-format-title-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-format-title-day' )
+ }
+ ,
+ columnFormat: {
+ month: mw.msg( 'srf-ui-eventcalendar-format-column-month' ),
+ week: mw.msg( 'srf-ui-eventcalendar-format-column-week' ),
+ day: mw.msg( 'srf-ui-eventcalendar-format-column-day' )
+ }
+ };
+ }
+
+ public init() {
+
+ let _i18n = this.getI18N();
+
+ // initialize the calendar
+ this.target.fullCalendar( {
+
+ firstDay: this.options.firstDay,
+ isRTL: this.options.isRTL,
+ monthNames: _i18n.monthNames,
+ monthNamesShort: _i18n.monthNamesShort,
+ dayNames: _i18n.dayNames,
+ dayNamesShort: _i18n.dayNamesShort,
+ buttonText: _i18n.buttonText,
+ allDayText: _i18n.allDayText,
+ timeFormat: _i18n.timeFormat,
+ titleFormat: _i18n.titleFormat,
+ columnFormat: _i18n.columnFormat
+ } );
+ }
+
+ private getEvent( rowId: any, rowData: any ) {
+
+ let eventdata: any = {
+ id: rowId,
+ title: rowData[ 'title' ],
+ start: rowData[ 'start' ],
+ className: rowId
+ };
+
+ if ( rowData.hasOwnProperty( 'end' ) ) {
+ eventdata[ 'end' ] = rowData[ 'end' ];
+ }
+
+ if ( rowData.hasOwnProperty( 'url' ) ) {
+ eventdata[ 'url' ] = rowData[ 'url' ];
+ }
+
+ return eventdata;
+ }
+
+ public showRows( rowIds: string[] ): any {
+
+ let events: any[] = [];
+
+ rowIds.forEach( ( rowId: string ) => {
+
+ let rowData = this.controller.getData()[ rowId ].data[ this.id ];
+
+ if ( rowData.hasOwnProperty( 'start' ) ) {
+ events.push( this.getEvent( rowId, rowData ) );
+ }
+ } );
+
+ this.target.fullCalendar( 'addEventSource', events );
+ }
+
+ public hideRows( rowIds: string[] ): any {
+ this.target.fullCalendar( 'removeEvents', ( e: any ) => ( rowIds.indexOf( e._id ) >= 0 ) );
+ }
+
+ public show(): any {
+ super.show();
+ this.target.fullCalendar( 'render' );
+ }
+
+ public hide(): any {
+ return super.hide();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/ListView.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/ListView.ts
new file mode 100644
index 00000000..05756b70
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/ListView.ts
@@ -0,0 +1,10 @@
+import { View } from "./View";
+
+export class ListView extends View {
+
+ protected getItemClassName() {
+ return '.filtered-list-item';
+ }
+
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/MapView.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/MapView.ts
new file mode 100644
index 00000000..57f3c97b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/MapView.ts
@@ -0,0 +1,255 @@
+/// <reference types="leaflet" />
+
+import { View } from "./View";
+import { Options } from "../../types"
+
+declare let mw: any;
+
+export class MapView extends View {
+
+ private map: L.Map = undefined;
+ private icon: { [key: string]: L.Icon } = undefined;
+ private markers: { [key: string]: L.Marker[] } = undefined;
+ private markerClusterGroup: L.MarkerClusterGroup = undefined;
+ private bounds: L.LatLngBounds = undefined;
+ private initialized: boolean = false;
+
+ private zoom: number = -1;
+ private minZoom: number = -1;
+ private maxZoom: number = -1;
+
+ private leafletPromise: Promise<any> = undefined;
+
+ public init(): Promise<any> {
+
+ let data = this.controller.getData();
+ let markers: { [rowId: string]: L.Marker[] } = {};
+
+ if ( this.options.hasOwnProperty( 'height' ) ) {
+ this.target.height( this.options.height );
+ }
+
+ this.leafletPromise = mw.loader.using( 'ext.srf.filtered.map-view.leaflet' )
+ .then( () => {
+
+ let bounds: L.LatLngBounds = undefined;
+ let disableClusteringAtZoom = this.getZoomForUnclustering();
+
+ let clusterOptions: Options = {
+ animateAddingMarkers: true,
+ disableClusteringAtZoom: disableClusteringAtZoom,
+ spiderfyOnMaxZoom: disableClusteringAtZoom === null
+ };
+
+ clusterOptions = this.getOptions( [ 'maxClusterRadius', 'zoomToBoundsOnClick' ], clusterOptions );
+
+ let markerClusterGroup: L.MarkerClusterGroup = L.markerClusterGroup( clusterOptions );
+
+ for ( let rowId in data ) {
+
+ if ( data[ rowId ][ 'data' ].hasOwnProperty( this.id ) ) {
+ let positions: L.LatLngLiteral[] = data[ rowId ][ 'data' ][ this.id ][ 'positions' ];
+ markers[ rowId ] = [];
+
+ for ( let pos of positions ) {
+
+ bounds = ( bounds === undefined ) ? new L.LatLngBounds( pos, pos ) : bounds.extend( pos );
+
+ let marker = this.getMarker( pos, data[ rowId ] );
+ markers[ rowId ].push( marker );
+ markerClusterGroup.addLayer( marker );
+ }
+ }
+ }
+
+ this.markerClusterGroup = markerClusterGroup;
+ this.markers = markers;
+ this.bounds = ( bounds === undefined ) ? new L.LatLngBounds( [ -180, -90 ], [ 180, 90 ] ) : bounds;
+ } );
+
+ return this.leafletPromise;
+ }
+
+ private getZoomForUnclustering() {
+
+ if ( this.options.hasOwnProperty( 'marker cluster' ) && this.options[ 'marker cluster' ] === false ) {
+ return 0;
+ }
+
+ if ( this.options.hasOwnProperty( 'marker cluster max zoom' ) ) {
+ return this.options[ 'marker cluster max zoom' ] + 1;
+ }
+
+ return null;
+ }
+
+ private getIcon( row: any ) {
+
+ if ( this.icon === undefined ) {
+ this.buildIconList();
+ }
+
+ if ( this.options.hasOwnProperty( 'marker icon property' ) ) {
+
+ let vals: string[] = row[ 'printouts' ][ this.options[ 'marker icon property' ] ][ 'values' ];
+
+ if ( vals.length > 0 && this.icon.hasOwnProperty( vals[ 0 ] ) ) {
+ return this.icon[ vals[ 0 ] ];
+ }
+ }
+
+ return this.icon[ 'default' ];
+ }
+
+ private buildIconList() {
+ this.icon = {};
+
+ let iconPath = this.controller.getPath() + 'css/images/';
+
+ this.icon[ 'default' ] = new L.Icon( {
+ 'iconUrl': iconPath + 'marker-icon.png',
+ 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [ 25, 41 ],
+ 'iconAnchor': [ 12, 41 ],
+ 'popupAnchor': [ 1, -34 ],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [ 41, 41 ]
+ } );
+
+ if ( this.options.hasOwnProperty( 'marker icons' ) ) {
+
+ for ( let value in this.options[ 'marker icons' ] ) {
+ this.icon[ value ] = new L.Icon( {
+ 'iconUrl': this.options[ 'marker icons' ][ value ],
+ // 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [ 32, 32 ],
+ 'iconAnchor': [ 16, 32 ],
+ 'popupAnchor': [ 1, -30 ],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [ 41, 41 ],
+ 'shadowAnchor': [ 12, 41 ]
+ } );
+ }
+ }
+ }
+
+ private getMarker( latLng: L.LatLngExpression, row: any ) {
+ let title = undefined;
+ let popup = [];
+
+ // TODO: Use <div> instead of <b> and do CSS styling
+
+ for ( let prId in row[ 'printouts' ] ) {
+ let printrequest = (this.controller.getPrintRequests())[ prId ];
+
+ if ( ! printrequest.hasOwnProperty('hide') || printrequest.hide === false ) {
+ let printouts = row[ 'printouts' ][ prId ];
+
+ if ( title === undefined ) {
+ title = printouts[ 'values' ].join( ', ' );
+ popup.push( '<b>' + printouts[ 'formatted values' ].join( ', ' ) + '</b>' );
+ } else {
+ popup.push( (printouts.label ? '<b>' + printouts.label + ':</b> ' : '') + printouts[ 'formatted values' ].join( ', ' ) )
+ }
+ }
+ }
+
+ let marker = L.marker( latLng, { title: title, alt: title } );
+ marker.bindPopup( popup.join( '<br>' ) );
+
+ marker.setIcon( this.getIcon( row ) );
+ return marker;
+ }
+
+ public lateInit() {
+
+ if ( this.initialized ) {
+ return;
+ }
+
+ this.initialized = true;
+
+ let that = this;
+
+ this.leafletPromise.then( () => {
+
+ let mapOptions: Options = {
+ center: this.bounds !== undefined ? this.bounds.getCenter() : [ 0, 0 ]
+ };
+
+ mapOptions = that.getOptions( [ 'zoom', 'minZoom', 'maxZoom' ], mapOptions );
+
+ // TODO: Limit zoom values to map max zoom
+
+ that.map = L.map( <HTMLElement> that.getTargetElement().get( 0 ), mapOptions );
+ that.map.addLayer( that.markerClusterGroup );
+
+ if ( this.options.hasOwnProperty( 'map provider' ) ) {
+ L.tileLayer.provider( this.options[ 'map provider' ] ).addTo( that.map );
+ }
+
+ if ( !mapOptions.hasOwnProperty( 'zoom' ) ) {
+ that.map.fitBounds( that.bounds );
+ }
+
+ } );
+
+ }
+
+ public getOptions( keys: string[], defaults: Options = {} ) {
+
+ for ( let key of keys ) {
+ if ( this.options.hasOwnProperty( key ) ) {
+ defaults[ key ] = this.options[ key ];
+ }
+ }
+
+ return defaults;
+ }
+
+ public showRows( rowIds: string[] ) {
+ this.leafletPromise.then( () => {
+ this.manipulateLayers( rowIds, ( layers: L.Layer[] ) => {
+ this.markerClusterGroup.addLayers( layers )
+ } )
+ } );
+ }
+
+ public hideRows( rowIds: string[] ) {
+ this.leafletPromise.then( () => {
+ this.manipulateLayers( rowIds, ( layers: L.Layer[] ) => {
+ this.markerClusterGroup.removeLayers( layers )
+ } )
+ } );
+ }
+
+ private manipulateLayers( rowIds: string[], cb: ( layers: L.Layer[] ) => void ) {
+
+ let layersFromRowIds = this.getLayersFromRowIds( rowIds );
+
+ if ( layersFromRowIds.length > 0 ) {
+ cb( layersFromRowIds );
+ }
+
+ }
+
+ private getLayersFromRowIds( rowIds: string[] ) {
+ return this.flatten( this.getLayersFromRowIdsRaw( rowIds ) );
+ }
+
+ private getLayersFromRowIdsRaw( rowIds: string[] ) {
+ return rowIds.map( ( rowId: string ) => this.markers[ rowId ] ? this.markers[ rowId ] : [] );
+ }
+
+ private flatten( markers: L.Layer[][] ): L.Layer[] {
+ return markers.reduce( ( result: L.Layer[], layers: L.Layer[] ) => result.concat( layers ), [] );
+ }
+
+ public show() {
+ super.show();
+ this.lateInit();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/TableView.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/TableView.ts
new file mode 100644
index 00000000..5737a2d9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/TableView.ts
@@ -0,0 +1,9 @@
+import { View } from "./View";
+
+export class TableView extends View {
+
+ protected getItemClassName() {
+ return '.filtered-table-item';
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/View.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/View.ts
new file mode 100644
index 00000000..fc43cdc2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/View/View.ts
@@ -0,0 +1,86 @@
+import { Options } from "../../types";
+import { Controller } from "../Controller";
+
+export class View {
+
+ protected id: string = undefined;
+ protected target: JQuery = undefined;
+ protected controller: Controller = undefined;
+ protected options: Options = undefined;
+ protected visible: boolean = false;
+ protected rows: { [ rowId: string ]: JQuery } = {};
+
+ public constructor( id: string, target: JQuery, c: Controller, options: Options = {} ) {
+ this.id = id;
+ this.target = target;
+ this.controller = c;
+ this.options = options;
+ }
+
+ public init(): Promise<any>|void {
+
+ let rowIds = Object.keys( this.controller.getData() );
+ let rows = this.target.find( this.getItemClassName() );
+
+ rows.each( ( index, elem ) => {
+ let classes = elem.classList;
+ for ( let i = 0; i < classes.length; i++ ) {
+ if ( rowIds.indexOf( classes[ i ] ) >= 0 ) {
+ this.rows[ classes[ i ] ] = $( rows[ index ] );
+ }
+ }
+ } );
+ }
+
+ protected getItemClassName() {
+ return '.filtered-item';
+ }
+
+ public getTargetElement(): JQuery {
+ return this.target;
+ }
+
+ public showRows( rowIds: string[] ) {
+
+ if ( this.visible && rowIds.length < 200 ) {
+
+ rowIds.forEach( ( rowId: string ) => {
+ this.rows[ rowId ].slideDown( 400 );
+ } );
+
+ } else {
+
+ rowIds.forEach( ( rowId: string ) => {
+ this.rows[ rowId ].css( 'display', '');
+ } );
+
+ }
+ }
+
+ public hideRows( rowIds: string[] ) {
+
+ if ( this.visible && rowIds.length < 200 ) {
+
+ rowIds.forEach( ( rowId: string ) => {
+ this.rows[ rowId ].slideUp( 400 );
+ } );
+
+ } else {
+
+ rowIds.forEach( ( rowId: string ) => {
+ this.rows[ rowId ].css( 'display', 'none');
+ } );
+
+ }
+ }
+
+ public show() {
+ this.target.show();
+ this.visible = true;
+ }
+
+ public hide() {
+ this.target.hide();
+ this.visible = false;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/ViewSelector.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/ViewSelector.ts
new file mode 100644
index 00000000..c97f2ab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/Filtered/ViewSelector.ts
@@ -0,0 +1,35 @@
+import { Controller } from "./Controller";
+export class ViewSelector {
+
+ private target: JQuery = undefined;
+ private viewIDs: string[] = undefined;
+
+ private controller: Controller = undefined;
+
+ public constructor( target: JQuery, viewIDs: string[], controller: Controller ) {
+ this.target = target;
+ this.viewIDs = viewIDs;
+ this.controller = controller;
+ }
+
+ public init() {
+ if ( this.viewIDs.length > 1 ) {
+ this.viewIDs.forEach( ( id: string) => { this.target.on( 'click', '.' + id, { 'target': id, 'controller' : this.controller }, ViewSelector.onSelectorSelected ); } );
+ this.target.children().first().addClass( 'selected');
+ this.target.show();
+ }
+ }
+
+ private static onSelectorSelected( event: JQueryEventObject ) {
+
+ event.data.controller.onViewSelected( event.data.target );
+
+ $( event.target )
+ .addClass( 'selected')
+ .siblings().removeClass( 'selected' );
+
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/bootstrap.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/bootstrap.ts
new file mode 100644
index 00000000..f804e549
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/bootstrap.ts
@@ -0,0 +1,11 @@
+import { Filtered } from "./Filtered/Filtered";
+
+declare let mw: any;
+let config = mw.config.get( 'srfFilteredConfig' );
+
+for ( let id in config ) {
+ if ( config.hasOwnProperty( id ) ) {
+ let f = new Filtered( $( '#' + id ), config[ id ] );
+ mw.hook( 'wikipage.content' ).add( () => f.run() );
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/types.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/types.ts
new file mode 100644
index 00000000..e824101b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/resources/ts/types.ts
@@ -0,0 +1,2 @@
+export type Options = { [key: string]: any };
+export type ResultData = { [ rowId: string ]:{ [ key: string ]: any } }; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filtered.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filtered.php
new file mode 100644
index 00000000..80d010f9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filtered.php
@@ -0,0 +1,494 @@
+<?php
+
+/**
+ * File holding the SRFFiltered class.
+ *
+ * @author Stephan Gambke
+ *
+ */
+
+namespace SRF\Filtered;
+
+use Exception;
+use Html;
+use SMW\Message;
+use SMW\Query\PrintRequest;
+use SMW\Query\QueryLinker;
+use SMW\Query\ResultPrinters\ResultPrinter;
+use SMWOutputs;
+use SMWPropertyValue;
+use SMWQueryResult;
+
+/**
+ * Result printer that displays results in switchable views and offers
+ * client-side (JavaScript based) filtering.
+ *
+ * This result printer is ultimately planned to replace exhibit. Currently only
+ * a list view is available. It is not yet possible to switch between views.
+ * There is also only the 'value' filter available yet.
+ *
+ * Syntax of the #ask call:
+ * (This is only a syntax example. For currently available features see the
+ * documentation of the various classes.)
+ *
+ * {{#ask:[[SomeCondition]]
+ * |? SomePrintout |+filter=value, someFutureFilter |+value filter switches=and or, disable, all, none |+someFutureFilter filter option=someOptionValue
+ * |? SomeOtherPrintout |+filter=value, someOtherFutureFilter |+someOtherFutureFilter filter option=someOptionValue
+ *
+ * |format=filtered
+ * |views=list, someFutureView, someOtherFutureView
+ *
+ * |list view type=list
+ * |list view template=ListItem
+ *
+ * |someFutureView view option=someOptionValue
+ *
+ * |someOtherFutureView view option=someOptionValue
+ *
+ * }}
+ *
+ * All format specific parameters are optional, although leaving the 'views'
+ * parameter empty probably does not make much sense.
+ *
+ */
+class Filtered extends ResultPrinter {
+
+ /**
+ * The available view types
+ *
+ * @var array of Strings
+ */
+ private $mViewTypes = [
+ 'list' => 'ListView',
+ 'calendar' => 'CalendarView',
+ 'table' => 'TableView',
+ 'map' => 'MapView',
+ ];
+
+ /**
+ * The available filter types
+ *
+ * @var array of Strings
+ */
+ private $mFilterTypes = [
+ 'value' => 'ValueFilter',
+ 'distance' => 'DistanceFilter',
+ 'number' => 'NumberFilter',
+ ];
+
+ private $viewNames;
+ private $parameters;
+ private $filtersOnTop;
+ private $printrequests;
+
+ private $parser;
+
+ /**
+ * @param string $valueList
+ * @param string $delimiter
+ *
+ * @return string[]
+ */
+ public function getArrayFromValueList( $valueList, $delimiter = ',' ) {
+ return array_map( 'trim', explode( $delimiter, $valueList ) );
+ }
+
+ /**
+ * @return \Parser | \StubObject | null
+ */
+ public function getParser() {
+
+ if ( $this->parser === null ) {
+ $this->setParser( $GLOBALS['wgParser'] );
+ }
+
+ return $this->parser;
+ }
+
+ /**
+ * @param \Parser | \StubObject $parser
+ */
+ public function setParser( $parser ) {
+ $this->parser = $parser;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrintrequests() {
+ return $this->printrequests;
+ }
+
+ public function hasTemplates( $hasTemplates = null ) {
+ $ret = $this->hasTemplates;
+ if ( is_bool( $hasTemplates ) ) {
+ $this->hasTemplates = $hasTemplates;
+ }
+ return $ret;
+ }
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-filtered' )->text();
+ }
+
+ /**
+ * Does any additional parameter handling that needs to be done before the
+ * actual result is build.
+ *
+ * @param array $params
+ * @param $outputMode
+ */
+ protected function handleParameters( array $params, $outputMode ) {
+ parent::handleParameters( $params, $outputMode );
+
+ // // Set in SMWResultPrinter:
+ // $this->mIntro = $params['intro'];
+ // $this->mOutro = $params['outro'];
+ // $this->mSearchlabel = $params['searchlabel'] === false ? null : $params['searchlabel'];
+ // $this->mLinkFirst = true | false;
+ // $this->mLinkOthers = true | false;
+ // $this->mDefault = str_replace( '_', ' ', $params['default'] );
+ // $this->mShowHeaders = SMW_HEADERS_HIDE | SMW_HEADERS_PLAIN | SMW_HEADERS_SHOW;
+
+ $this->mSearchlabel = null;
+
+ $this->parameters = $params;
+ $this->viewNames = explode( ',', $params['views'] );
+ $this->filtersOnTop = $params['filter position'] === 'top';
+
+ }
+
+ /**
+ * Return serialised results in specified format.
+ *
+ * @param SMWQueryResult $res
+ * @param $outputmode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+
+ // collect the query results in an array
+ /** @var ResultItem[] $resultItems */
+ $resultItems = [];
+ while ( $row = $res->getNext() ) {
+ $resultItems[$this->uniqid()] = new ResultItem( $row, $this );
+ usleep( 1 ); // This is ugly, but for now th opnly way to get all resultItems. See #288.
+ }
+
+ $config = [
+ 'query' => $res->getQueryString(),
+ 'printrequests' => [],
+ 'views' => [],
+ 'data' => [],
+ ];
+
+ list( $filterHtml, $printrequests ) = $this->getFilterHtml( $res, $resultItems );
+
+ $this->printrequests = $printrequests;
+ $config['printrequests'] = $printrequests;
+
+ list( $viewHtml, $config ) = $this->getViewHtml( $res, $resultItems, $config );
+
+ SMWOutputs::requireResource( 'ext.srf.filtered' );
+
+ $id = $this->uniqid();
+ // wrap all in a div
+ $html = '<div class="filtered-spinner"><div class="smw-overlay-spinner"></div></div>';
+ $html .= $this->filtersOnTop ? $filterHtml . $viewHtml : $viewHtml . $filterHtml;
+ $html = Html::rawElement( 'div', [ 'class' => 'filtered ' . $id, 'id' => $id ], $html );
+
+ $config['data'] = $this->getResultsForJs( $resultItems );
+
+ $config['filtersOnTop'] = $this->filtersOnTop;
+ $this->addConfigToOutput( $id, $config );
+
+ try {
+ $this->fullParams['limit']->getOriginalValue();
+ }
+ catch ( Exception $exception ) {
+ $res->getQuery()->setLimit( 0 );
+ }
+
+ $link = QueryLinker::get( $res->getQuery() );
+ $link->setCaption( Message::get( "srf-filtered-noscript-link-caption" ) );
+ $link->setParameter( 'table', 'format' );
+
+ SMWOutputs::requireResource( 'ext.srf.filtered' );
+ $this->registerResources( [], [ 'ext.srf.filtered' ] );
+
+ return $html;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ * @see DefaultConfig.php of param-processor/param-processor for allowed types
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'views',
+ 'message' => 'srf-paramdesc-filtered-views',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'filter position',
+ 'message' => 'srf-paramdesc-filtered-filter-position',
+ 'default' => 'top',
+ // 'islist' => false,
+ ];
+
+ foreach ( $this->mViewTypes as $viewType ) {
+ $params = array_merge( $params, call_user_func( [ 'SRF\Filtered\View\\' . $viewType, 'getParameters' ] ) );
+ }
+
+ return $params;
+ }
+
+ public function getLinker( $firstcol = false, $force = false ) {
+ return ( $force ) ? $this->mLinker : parent::getLinker( $firstcol );
+ }
+
+ private function addConfigToOutput( $id, $config ) {
+
+ if ( $this->getParser()->getOutput() !== null ) {
+ $getter = [ $this->getParser()->getOutput(), 'getExtensionData' ];
+ $setter = [ $this->getParser()->getOutput(), 'setExtensionData' ];
+ } else {
+ $getter = [ \RequestContext::getMain()->getOutput(), 'getProperty' ];
+ $setter = [ \RequestContext::getMain()->getOutput(), 'setProperty' ];
+ }
+
+ $previousConfig = call_user_func( $getter, 'srf-filtered-config' );
+
+ if ( $previousConfig === null ) {
+ $previousConfig = [];
+ }
+
+ $previousConfig[$id] = $config;
+
+ call_user_func( $setter, 'srf-filtered-config', $previousConfig );
+
+ }
+
+ /**
+ * @param string | string[] | null $resourceModules
+ */
+ protected function registerResourceModules( $resourceModules ) {
+
+ array_map( 'SMWOutputs::requireResource', (array)$resourceModules );
+ }
+
+ /**
+ * @param string|null $id
+ *
+ * @return string
+ */
+ public function uniqid( $id = null ) {
+ $hashedId = ( $id === null ) ? uniqid() : md5( $id );
+ return base_convert( $hashedId, 16, 36 );
+ }
+
+ /**
+ * @param ResultItem[] $result
+ *
+ * @return array
+ */
+ protected function getResultsForJs( $result ) {
+ $resultAsArray = [];
+ foreach ( $result as $id => $row ) {
+ $resultAsArray[$id] = $row->getArrayRepresentation();
+ }
+ return $resultAsArray;
+ }
+
+ public function addError( $errorMessage ) {
+ parent::addError( $errorMessage );
+ }
+
+ /**
+ * @param SMWQueryResult $res
+ * @param $result
+ *
+ * @return array
+ */
+ protected function getFilterHtml( SMWQueryResult $res, $result ) {
+
+ // prepare filter data for inclusion in HTML and JS
+ $filterHtml = '';
+
+ $printrequests = [];
+
+ /** @var PrintRequest $printRequest */
+ foreach ( $res->getPrintRequests() as $printRequest ) {
+
+ $prConfig = [
+ 'mode' => $printRequest->getMode(),
+ 'label' => $printRequest->getLabel(),
+ 'outputformat' => $printRequest->getOutputFormat(),
+ 'type' => $printRequest->getTypeID(),
+ ];
+
+ if ( $printRequest->getData() instanceof SMWPropertyValue ) {
+ $prConfig['property'] = $printRequest->getData()->getInceptiveProperty()->getKey();
+ }
+
+ if ( filter_var( $printRequest->getParameter( 'hide' ), FILTER_VALIDATE_BOOLEAN ) ) {
+ $prConfig['hide'] = true;
+ }
+
+ $filtersParam = $printRequest->getParameter( 'filter' );
+
+ if ( $filtersParam ) {
+
+ $filtersForPrintout = $this->getArrayFromValueList( $filtersParam );
+
+ foreach ( $filtersForPrintout as $filterName ) {
+
+ if ( array_key_exists( $filterName, $this->mFilterTypes ) ) {
+
+ /** @var \SRF\Filtered\Filter\Filter $filter */
+ $filterClassName = '\SRF\Filtered\Filter\\' . $this->mFilterTypes[$filterName];
+ $filter = new $filterClassName( $result, $printRequest, $this );
+
+ if ( $filter->isValidFilterForPropertyType() ) {
+
+ $this->registerResourceModules( $filter->getResourceModules() );
+
+ $filterid = $this->uniqid();
+ $filterHtml .= Html::rawElement(
+ 'div',
+ [ 'id' => $filterid, 'class' => "filtered-filter filtered-$filterName" ],
+ $filter->getResultText()
+ );
+
+ $filterdata = $filter->getJsConfig();
+ $filterdata['type'] = $filterName;
+ $filterdata['label'] = $printRequest->getLabel();
+
+ $prConfig['filters'][$filterid] = $filterdata;
+
+ foreach ( $result as $row ) {
+ $row->setData( $filterid, $filter->getJsDataForRow( $row ) );
+ }
+ } else {
+ // TODO: I18N
+ $this->addError(
+ "The '$filterName' filter can not be used on the '{$printRequest->getLabel()}' printout."
+ );
+ }
+
+ }
+ }
+ }
+
+ $printrequests[$this->uniqid( $printRequest->getHash() )] = $prConfig;
+ }
+
+ $filterHtml .= '<div class="filtered-filter-spinner" style="display: none;"><div class="smw-overlay-spinner"></div></div>';
+
+ // wrap filters in a div
+ $filterHtml = Html::rawElement(
+ 'div',
+ [ 'class' => 'filtered-filters', 'style' => 'display:none' ],
+ $filterHtml
+ );
+
+ return [ $filterHtml, $printrequests ];
+ }
+
+ /**
+ * @param SMWQueryResult $res
+ * @param $resultItems
+ * @param $config
+ *
+ * @return array
+ */
+ protected function getViewHtml( SMWQueryResult $res, $resultItems, $config ) {
+
+ // prepare view data for inclusion in HTML and JS
+ $viewHtml = '';
+ $viewSelectorsHtml = '';
+
+ foreach ( $this->viewNames as $viewName ) {
+
+ // cut off the selector label (if one was specified) from the actual view name
+ $viewnameComponents = explode( '=', $viewName, 2 );
+
+ $viewName = trim( $viewnameComponents[0] );
+
+ if ( array_key_exists( $viewName, $this->mViewTypes ) ) {
+
+ // generate unique id
+ $viewid = $this->uniqid();
+
+ if ( count( $viewnameComponents ) > 1 ) {
+ // a selector label was specified in the wiki text
+ $viewSelectorLabel = trim( $viewnameComponents[1] );
+ } else {
+ // use the default selector label
+ $viewSelectorLabel = Message::get( 'srf-filtered-selectorlabel-' . $viewName );
+ }
+
+ /** @var \SRF\Filtered\View\View $view */
+ $viewClassName = '\SRF\Filtered\View\\' . $this->mViewTypes[$viewName];
+ $view = new $viewClassName( $resultItems, $this->parameters, $this, $viewSelectorLabel );
+
+ $initErrorMsg = $view->getInitError();
+
+ if ( $initErrorMsg !== null ) {
+ $res->addErrors( [ $this->msg( $initErrorMsg )->text() ] );
+ } else {
+
+ $this->registerResourceModules( $view->getResourceModules() );
+
+ $viewHtml .= Html::rawElement(
+ 'div',
+ [ 'id' => $viewid, 'class' => "filtered-view filtered-$viewName $viewid" ],
+ $view->getResultText()
+ );
+ $viewSelectorsHtml .= Html::rawElement(
+ 'div',
+ [ 'class' => "filtered-view-selector filtered-$viewName $viewid" ],
+ $viewSelectorLabel
+ );
+
+ foreach ( $resultItems as $row ) {
+ $row->setData( $viewid, $view->getJsDataForRow( $row ) );
+ }
+
+ $config['views'][$viewid] = array_merge( [ 'type' => $viewName ], $view->getJsConfig() );
+ }
+ }
+ }
+
+ $viewHtml = Html::rawElement(
+ 'div',
+ [ 'class' => 'filtered-views', 'style' => 'display:none' ],
+ Html::rawElement(
+ 'div',
+ [ 'class' => 'filtered-views-selectors-container', 'style' => 'display:none' ],
+ $viewSelectorsHtml
+ ) .
+ Html::rawElement( 'div', [ 'class' => 'filtered-views-container' ], $viewHtml )
+ );
+ return [ $viewHtml, $config ];
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/DistanceFilter.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/DistanceFilter.php
new file mode 100644
index 00000000..2afb55eb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/DistanceFilter.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace SRF\Filtered\Filter;
+
+/**
+ * File holding the SRF_FF_Distance class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use DataValues\Geo\Parsers\LatLongParser;
+use Exception;
+use SMWPropertyValue;
+use SRF\Filtered\ResultItem;
+
+/**
+ * The SRF_FF_Distance class.
+ *
+ * Available parameters for this filter:
+ * distance filter origin: the point from which the distance is measured (address or geo coordinate)
+ * distance filter property: the property containing the point to which distance is measured - not implemented yet
+ * distance filter unit: the unit in which the distance is measured
+ *
+ * @ingroup SemanticResultFormats
+ */
+class DistanceFilter extends Filter {
+
+ private $jsConfig;
+
+ /**
+ * Returns the name (string) or names (array of strings) of the resource
+ * modules to load.
+ *
+ * @return string|array
+ */
+ public function getResourceModules() {
+ return 'ext.srf.filtered.distance-filter';
+ }
+
+ protected function buildJsConfig() {
+
+ parent::buildJsConfig();
+
+ if ( !array_key_exists( 'distance filter origin', $this->getActualParameters() ) ) {
+ $label = $this->getPrintRequest()->getLabel();
+ $this->getQueryPrinter()->addError( "Missing origin for distance filter on '$label'." );
+ return [];
+ }
+
+ try {
+
+ $geoCoordinateParser = new LatLongParser();
+
+ $callback = function ( $value ) use ( $geoCoordinateParser ) {
+ $latlng = $geoCoordinateParser->parse( $value );
+ return [ 'lat' => $latlng->getLatitude(), 'lng' => $latlng->getLongitude() ];
+ };
+
+ $this->addValueToJsConfig( 'distance filter origin', 'origin', null, $callback );
+
+ }
+ catch ( Exception $exception ) {
+ $label = $this->getPrintRequest()->getLabel();
+ $this->getQueryPrinter()->addError( "Distance filter on $label: " . $exception->getMessage() );
+ return [];
+ }
+
+ $this->addValueToJsConfig( 'distance filter collapsible', 'collapsible' );
+ $this->addValueToJsConfig( 'distance filter initial value', 'initial value' );
+ $this->addValueToJsConfig( 'distance filter max distance', 'max' );
+ $this->addValueToJsConfig( 'distance filter unit', 'unit' );
+ $this->addValueListToJsConfig( 'distance filter switches', 'switches' );
+
+ }
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return array|null
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+
+ $markerPositionPropertyName = $this->getPrintRequest()->getData()->getInceptiveProperty()->getKey();
+
+ foreach ( $row->getValue() as $field ) {
+
+ $printRequest = $field->getPrintRequest();
+ $field->reset();
+
+ $value = $field->getNextDataItem();
+ if ( $printRequest->getData() instanceof SMWPropertyValue &&
+ $printRequest->getData()->getInceptiveProperty()->getKey() === $markerPositionPropertyName &&
+ ( $value instanceof \SMWDIGeoCoord || $value instanceof \SMWDIBlob )
+ ) {
+ $values = []; // contains plain text
+
+ if ( $value instanceof \SMWDIGeoCoord ) {
+
+ while ( $value instanceof \SMWDIGeoCoord ) {
+ $values[] = [ 'lat' => $value->getLatitude(), 'lng' => $value->getLongitude() ];
+ $value = $field->getNextDataItem();
+ }
+
+ } else {
+
+ $coordParser = new LatLongParser();
+ while ( $value instanceof \SMWDataItem ) {
+ try {
+ $latlng = $coordParser->parse( $value->getSerialization() );
+ $values[] = [ 'lat' => $latlng->getLatitude(), 'lng' => $latlng->getLongitude() ];
+ }
+ catch ( \Exception $exception ) {
+ $this->getQueryPrinter()->addError( "Error on '$value': " . $exception->getMessage() );
+ }
+ $value = $field->getNextDataItem();
+ }
+
+ }
+
+ return [ 'positions' => $values, ];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isValidFilterForPropertyType() {
+ return $this->getPrintRequest()->getTypeID() === '_geo' || $this->getPrintRequest()->getTypeID() === '_txt';
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/Filter.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/Filter.php
new file mode 100644
index 00000000..8dda29ab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/Filter.php
@@ -0,0 +1,178 @@
+<?php
+
+namespace SRF\Filtered\Filter;
+
+/**
+ * File holding the SRF_Filtered_Filter class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use SMWPrintRequest;
+use SRF\Filtered\Filtered;
+use SRF\Filtered\ResultItem;
+
+/**
+ * The SRF_Filtered_Filter class.
+ *
+ * @ingroup SemanticResultFormats
+ */
+abstract class Filter {
+
+ private $resultItems = null;
+ private $printRequest = null;
+ private $queryPrinter = null;
+ private $jsConfig = null;
+
+ /**
+ * Filter constructor.
+ *
+ * @param ResultItem[] $results
+ * @param SMWPrintRequest $printRequest
+ * @param Filtered $queryPrinter
+ */
+ public function __construct( array &$results, SMWPrintRequest $printRequest, Filtered &$queryPrinter ) {
+ $this->resultItems = $results;
+ $this->printRequest = $printRequest;
+ $this->queryPrinter = $queryPrinter;
+ }
+
+ /**
+ * @return ResultItem[]
+ */
+ public function &getQueryResults() {
+ return $this->resultItems;
+ }
+
+ /**
+ * @return SMWPrintRequest
+ */
+ public function &getPrintRequest() {
+ return $this->printRequest;
+ }
+
+ /**
+ * @return Filtered
+ */
+ public function &getQueryPrinter() {
+ return $this->queryPrinter;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getActualParameters() {
+ return $this->printRequest->getParameters();
+ }
+
+ /**
+ * Returns the name (string) or names (array of strings) of the resource
+ * modules to load.
+ *
+ * @return string|string[]
+ */
+ public function getResourceModules() {
+ return null;
+ }
+
+ /**
+ * Returns the HTML text that is to be included for this filter.
+ *
+ * This text will appear on the page in a div that has the filter's id set
+ * as class.
+ *
+ * @return string
+ */
+ public function getResultText() {
+ return '';
+ }
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return null | string
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isValidFilterForPropertyType() {
+ return true;
+ }
+
+ /**
+ * Returns an array of config data for this filter to be stored in the JS
+ *
+ * @return string[]
+ */
+ public function getJsConfig() {
+
+ if ( $this->jsConfig === null ) {
+ $this->buildJsConfig();
+ }
+
+ return $this->jsConfig;
+ }
+
+ protected function buildJsConfig() {
+ $this->jsConfig = [];
+
+ $this->addValueToJsConfig(
+ 'show if undefined',
+ 'show if undefined',
+ null,
+ function ( $value ) { return filter_var( $value, FILTER_VALIDATE_BOOLEAN ); }
+ );
+ }
+
+ /**
+ * @param string $paramName
+ * @param string $configName
+ * @param mixed | null $default
+ * @param callable | null $callback
+ */
+ protected function addValueToJsConfig( $paramName, $configName, $default = null, $callback = null ) {
+
+ $params = $this->getActualParameters();
+
+ if ( array_key_exists( $paramName, $params ) ) {
+
+ $parsedValue = trim( $this->getQueryPrinter()->getParser()->recursiveTagParse( $params[$paramName] ) );
+
+ $this->jsConfig[$configName] = ( $callback !== null ) ? call_user_func(
+ $callback,
+ $parsedValue
+ ) : $parsedValue;
+
+ } elseif ( $default !== null ) {
+
+ $this->jsConfig[$configName] = $default;
+
+ }
+
+ }
+
+ /**
+ * @param $paramName
+ * @param $configName
+ * @param null $default
+ */
+ protected function addValueListToJsConfig( $paramName, $configName, $default = null, $callback = null ) {
+
+ $this->addValueToJsConfig(
+ $paramName,
+ $configName,
+ $default,
+ function ( $valueList ) use ( $callback ) {
+ $parsedValues = $this->getQueryPrinter()->getArrayFromValueList( $valueList );
+ return ( $callback !== null ) ? array_map( $callback, $parsedValues ) : $parsedValues;
+ }
+ );
+
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/NumberFilter.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/NumberFilter.php
new file mode 100644
index 00000000..cc90fc07
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/NumberFilter.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace SRF\Filtered\Filter;
+
+/**
+ * File holding the SRF_FF_Number class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use SMWPropertyValue;
+use SRF\Filtered\ResultItem;
+
+/**
+ * The SRF_FF_Number class.
+ *
+ * Available parameters for this filter:
+ * number filter origin: the point from which the number is measured (address or geo coordinate)
+ * number filter property: the property containing the point to which number is measured - not implemented yet
+ * number filter unit: the unit in which the number is measured
+ *
+ * @ingroup SemanticResultFormats
+ */
+class NumberFilter extends Filter {
+
+ /**
+ * Returns the name (string) or names (array of strings) of the resource
+ * modules to load.
+ *
+ * @return string|array
+ */
+ public function getResourceModules() {
+ return 'ext.srf.filtered.number-filter';
+ }
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return array|null
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+ $propertyName = $this->getPrintRequest()->getData()->getInceptiveProperty()->getKey();
+
+ foreach ( $row->getValue() as $field ) {
+
+ $printRequest = $field->getPrintRequest();
+
+ if ( $printRequest->getData() instanceof SMWPropertyValue &&
+ $printRequest->getData()->getInceptiveProperty()->getKey() === $propertyName &&
+ ( $field->reset() instanceof \SMWDINumber || $field->reset() instanceof \SMWDITime )
+ ) {
+
+ $values = []; // contains plain text
+ $value = $field->getNextDataValue();
+
+ while ( $value instanceof \SMWNumberValue || $value instanceof \SMWTimeValue ) {
+
+ if ( $value instanceof \SMWNumberValue ) {
+ $cuv = $value->getConvertedUnitValues();
+ $values[] = $cuv[$value->getCanonicalMainUnit()];
+ } else {
+ $values[] = $value->getYear();
+ }
+ $value = $field->getNextDataItem();
+ }
+
+ return [ 'values' => $values ];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isValidFilterForPropertyType() {
+ $typeID = $this->getPrintRequest()->getTypeID();
+ return $typeID === '_num' || $typeID === '_qty' || '_dat';
+ }
+
+ protected function buildJsConfig() {
+ parent::buildJsConfig();
+ $this->addValueToJsConfig( 'number filter collapsible', 'collapsible' );
+ $this->addValueToJsConfig( 'number filter max value', 'max' );
+ $this->addValueToJsConfig( 'number filter min value', 'min' );
+ $this->addValueToJsConfig( 'number filter step', 'step' );
+ $this->addValueToJsConfig( 'number filter sliders', 'sliders' );
+ $this->addValueToJsConfig( 'number filter label', 'caption', $this->getPrintRequest()->getOutputFormat() );
+ $this->addValueListToJsConfig( 'number filter values', 'values' );
+ $this->addValueListToJsConfig( 'number filter switches', 'switches' );
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/ValueFilter.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/ValueFilter.php
new file mode 100644
index 00000000..631f1219
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Filters/ValueFilter.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace SRF\Filtered\Filter;
+
+/**
+ * File holding the SRF_FF_Value class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+/**
+ * The SRF_FF_Value class.
+ *
+ * Available parameters for this filter:
+ * value filter switches: switches to be shown for this filter; currently only 'and or' supported
+ *
+ * @ingroup SemanticResultFormats
+ */
+class ValueFilter extends Filter {
+
+ /**
+ * Returns the name (string) or names (array of strings) of the resource
+ * modules to load.
+ *
+ * @return string|string[]
+ */
+ public function getResourceModules() {
+ return 'ext.srf.filtered.value-filter';
+ }
+
+ protected function buildJsConfig() {
+ parent::buildJsConfig();
+
+ $this->addValueListToJsConfig( 'value filter switches', 'switches' );
+ $this->addValueListToJsConfig( 'value filter values', 'values' );
+ $this->addValueListToJsConfig( 'value filter max checkboxes', 'max checkboxes' );
+ $this->addValueToJsConfig( 'value filter collapsible', 'collapsible' );
+
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Hooks.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Hooks.php
new file mode 100644
index 00000000..ffeefe0d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/Hooks.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: stephan
+ * Date: 2/24/17
+ * Time: 11:00 PM
+ */
+
+namespace SRF\Filtered;
+
+use OutputPage;
+use ParserOutput;
+
+class Hooks {
+
+ public static function onOutputPageParserOutput( OutputPage &$outputPage, ParserOutput $parserOutput ) {
+ $outputPage->setProperty( 'srf-filtered-config', $parserOutput->getExtensionData( 'srf-filtered-config' ) );
+ return true;
+ }
+
+ public static function onMakeGlobalVariablesScript( &$vars, OutputPage $output ) {
+ $vars['srfFilteredConfig'] = $output->getProperty( 'srf-filtered-config' );
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/ResultItem.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/ResultItem.php
new file mode 100644
index 00000000..ab5c57ba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/ResultItem.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace SRF\Filtered;
+
+use SMWDataValue;
+use SMWDIGeoCoord;
+use SMWDIWikiPage;
+use SMWErrorValue;
+use SMWResultArray;
+
+/**
+ * File holding the SRF_Filtered_Item class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+/**
+ * The SRF_Filtered_Item class.
+ *
+ * @ingroup SemanticResultFormats
+ */
+class ResultItem {
+
+ private $mResultArray;
+ private $mItemData = [];
+ private $mQueryPrinter;
+
+ /**
+ * @param SMWResultArray[] $resultArray
+ * @param Filtered $queryPrinter
+ */
+ public function __construct( array $resultArray, Filtered &$queryPrinter ) {
+ $this->mResultArray = $resultArray;
+ $this->mQueryPrinter = $queryPrinter;
+ }
+
+ public function setData( $viewOrFilterId, $data ) {
+ if ( $data === null ) {
+ $this->unsetData( $viewOrFilterId );
+ } else {
+ $this->mItemData[$viewOrFilterId] = $data;
+ }
+ }
+
+ public function unsetData( $viewOrFilterId ) {
+ unset( $this->mItemData[$viewOrFilterId] );
+ }
+
+ public function getData( $viewOrFilterId ) {
+ return $this->mItemData[$viewOrFilterId];
+ }
+
+ /**
+ * @return SMWResultArray[]
+ */
+ public function getValue() {
+ return $this->mResultArray;
+ }
+
+ public function getArrayRepresentation() {
+
+ $printouts = [];
+ $isFirstColumn = true;
+
+ foreach ( $this->mResultArray as $field ) {
+
+ $printRequest = $field->getPrintRequest();
+
+ $values = []; // contains plain text
+ $formatted = []; // may contain links
+ $sorted = []; // uses DEFAULTSORT when available
+
+ $field->reset();
+
+ while ( ( $dataValue = $field->getNextDataValue() ) instanceof SMWDataValue ) {
+
+ $dataItem = $dataValue->getDataItem();
+
+ if ( $dataItem instanceof SMWDIGeoCoord ) {
+ $values[] = [ 'lat' => $dataItem->getLatitude(), 'lng' => $dataItem->getLongitude() ];
+ $sorted[] = $dataItem->getSortKey();
+ } elseif ( $dataItem instanceof SMWDIWikiPage ) {
+ $values[] = $dataValue->getShortWikiText();
+ $sorted[] = $dataItem->getSortKey();
+ } else {
+ $values[] = $dataValue->getShortWikiText();
+ $sorted[] = $dataValue->getShortWikiText();
+ }
+
+ if ( $dataValue instanceof SMWErrorValue ) {
+ $formatted[] = $dataItem->getSerialization();
+ } else {
+ $formatted[] = $dataValue->getShortHTMLText( $this->mQueryPrinter->getLinker( $isFirstColumn ) );
+ }
+ }
+
+ $printouts[$this->mQueryPrinter->uniqid( $printRequest->getHash() )] = [
+ 'values' => $values,
+ 'formatted values' => $formatted,
+ 'sort values' => $sorted,
+ ];
+
+ $isFirstColumn = false;
+ }
+
+ return [
+ 'printouts' => $printouts,
+ 'data' => $this->mItemData,
+ ];
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/CalendarView.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/CalendarView.php
new file mode 100644
index 00000000..0ac5441b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/CalendarView.php
@@ -0,0 +1,271 @@
+<?php
+
+namespace SRF\Filtered\View;
+
+/**
+ * File holding the CalendarView class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use Message;
+use SRF\Filtered\ResultItem;
+
+/**
+ * The CalendarView class defines the List view.
+ *
+ * Available parameters for this view:
+ * list view type: list|ul|ol; default: list
+ * list view template: a template rendering a list item
+ * list view introtemplate: a template prepended to the list
+ * list view outrotemplate: a template appended to the list
+ * list view named args: use named args for templates
+ *
+ * @ingroup SemanticResultFormats
+ */
+class CalendarView extends View {
+
+ private $start;
+ private $end;
+ private $title;
+ private $titleTemplate;
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return array
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+
+ $value = $row->getValue();
+ $data = [];
+ $wikitext = '';
+
+ foreach ( $value as $valueId => $field ) {
+
+ $printRequest = $field->getPrintRequest();
+
+ $field->reset();
+ $datavalue = $field->getNextDataValue();
+
+ if ( $datavalue instanceof \SMWTimeValue &&
+ ( $printRequest->getLabel() === $this->start || $this->start === null && !array_key_exists(
+ 'start',
+ $data
+ ) )
+ ) {
+ // found specified column for start date
+ // OR no column for start date specified, take first available date value
+ $data['start'] = $datavalue->getISO8601Date();
+ }
+
+ if ( $datavalue instanceof \SMWTimeValue && $printRequest->getLabel() === $this->end ) {
+ // found specified column for end date
+ $data['end'] = $datavalue->getISO8601Date();
+ }
+
+ if ( $this->titleTemplate === null &&
+ ( $printRequest->getLabel() === $this->title || $this->title === null && !array_key_exists(
+ 'title',
+ $data
+ ) )
+ ) {
+ // found specified column for title
+ if ( $datavalue !== false ) {
+ if ( $datavalue instanceof \SMWWikiPageValue ) {
+ $data['url'] = $datavalue->getDataItem()->getTitle()->getLocalURL();
+ }
+ $data['title'] = $datavalue->getShortHTMLText();
+ }
+ }
+
+ // only add to title template if requested and if not hidden
+ if ( $this->titleTemplate !== null && filter_var(
+ $printRequest->getParameter( 'hide' ),
+ FILTER_VALIDATE_BOOLEAN
+ ) === false ) {
+
+ $params = [];
+ while ( ( $text = $field->getNextText(
+ SMW_OUTPUT_WIKI,
+ $this->getQueryPrinter()->getLinker( $valueId === 0 )
+ ) ) !== false ) {
+ $params[] = $text;
+ }
+ $wikitext .= '|' . ( $valueId + 1 ) . '=' . join( ',', $params );
+ }
+
+ }
+
+ // only add to title template if requested and if not hidden
+ if ( $this->titleTemplate !== null ) {
+// $wikitext .= "|#=$rownum";
+ $data['title'] = trim(
+ $this->getQueryPrinter()->getParser()->recursiveTagParse(
+ '{{' . $this->titleTemplate . $wikitext . '}}'
+ )
+ );
+ $this->getQueryPrinter()->getParser()->replaceLinkHolders( $data['title'] );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Transfers the parameters applicable to this view into internal variables.
+ */
+ protected function handleParameters() {
+
+ $params = $this->getActualParameters();
+ $parser = $this->getQueryPrinter()->getParser();
+
+ // find the hash for the printout containing the start date
+ if ( $params['calendar view start'] !== '' ) {
+ $this->start = trim( $parser->recursiveTagParse( $params['calendar view start'] ) );
+ }
+
+ // find the hash for the printout containing the start date
+ if ( $params['calendar view end'] !== '' ) {
+ $this->end = trim( $parser->recursiveTagParse( $params['calendar view end'] ) );
+ }
+
+ // find the hash for the printout containing the title of the element
+ if ( $params['calendar view title'] !== '' ) {
+ $this->title = trim( $parser->recursiveTagParse( $params['calendar view title'] ) );
+ }
+
+ // find the hash for the printout containing the title of the element
+ if ( $params['calendar view title template'] !== '' ) {
+ $this->titleTemplate = trim( $parser->recursiveTagParse( $params['calendar view title template'] ) );
+ }
+
+// $this->mTemplate = $params['list view template'];
+// $this->mIntroTemplate = $params['list view introtemplate'];
+// $this->mOutroTemplate = $params['list view outrotemplate'];
+// $this->mNamedArgs = $params['list view named args'];
+//
+// if ( $params['headers'] == 'hide' ) {
+// $this->mShowHeaders = SMW_HEADERS_HIDE;
+// } elseif ( $params['headers'] == 'plain' ) {
+// $this->mShowHeaders = SMW_HEADERS_PLAIN;
+// } else {
+// $this->mShowHeaders = SMW_HEADERS_SHOW;
+// }
+ }
+
+ /**
+ * A function to describe the allowed parameters of a query for this view.
+ *
+ * @return array of Parameter
+ */
+ public static function getParameters() {
+ $params = parent::getParameters();
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'calendar view start',
+ 'message' => 'srf-paramdesc-filtered-calendar-start',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'calendar view end',
+ 'message' => 'srf-paramdesc-filtered-calendar-end',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'calendar view title',
+ 'message' => 'srf-paramdesc-filtered-calendar-title',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'calendar view title template',
+ 'message' => 'srf-paramdesc-filtered-calendar-title-template',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ return $params;
+ }
+
+ /**
+ * Returns the name of the resource module to load for this view.
+ *
+ * @return string|array
+ */
+ public function getResourceModules() {
+ return 'ext.srf.filtered.calendar-view';
+ }
+
+ /**
+ * Returns an array of config data for this filter to be stored in the JS
+ *
+ * @return string[]
+ */
+ public function getJsConfig() {
+ global $wgAmericanDates;
+
+ return
+ $this->getParamHashes( $this->getQueryResults(), $this->getActualParameters() ) +
+ [
+ 'firstDay' => ( $wgAmericanDates ? '0' : Message::newFromKey(
+ 'srf-filtered-firstdayofweek'
+ )->inContentLanguage()->text() ),
+ 'isRTL' => wfGetLangObj( true )->isRTL(),
+ ];
+ }
+
+ /**
+ * @param ResultItem[] $results
+ * @param string[] $params
+ *
+ * @return string[]
+ */
+ private function getParamHashes( $results, $params ) {
+
+ if ( $results === null || count( $results ) < 1 ) {
+ return [];
+ }
+
+ if ( $params['calendar view title'] !== '' ) {
+
+ $titleLabel = trim(
+ $this->getQueryPrinter()->getParser()->recursiveTagParse( $params['calendar view title'] )
+ );
+
+ // find the hash for the printout containing the title of the element
+ foreach ( reset( $results )->getValue() as $printout ) {
+
+ if ( $printout->getPrintRequest()->getLabel() === $titleLabel ) {
+ return [ 'title' => $this->getQueryPrinter()->uniqid( $printout->getPrintRequest()->getHash() ) ];
+ }
+ }
+
+ } elseif ( $params['mainlabel'] !== '-' ) { // first column not suppressed
+ $value = reset( $results )->getValue();
+ return [ 'title' => $this->getQueryPrinter()->uniqid( reset( $value )->getPrintRequest()->getHash() ) ];
+ }
+
+ return [];
+ }
+
+ /**
+ * Returns the label of the selector for this view.
+ *
+ * @return String the selector label
+ */
+ public function getSelectorLabel() {
+ return Message::newFromKey( 'srf-filtered-selectorlabel-calendar' )->inContentLanguage()->text();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/ListView.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/ListView.php
new file mode 100644
index 00000000..c92d4f93
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/ListView.php
@@ -0,0 +1,272 @@
+<?php
+
+namespace SRF\Filtered\View;
+
+/**
+ * File holding the ListView class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use Message;
+
+/**
+ * The ListView class defines the List view.
+ *
+ * Available parameters for this view:
+ * list view type: list|ul|ol; default: list
+ * list view template: a template rendering a list item
+ * list view introtemplate: a template prepended to the list
+ * list view outrotemplate: a template appended to the list
+ * list view named args: use named args for templates
+ *
+ * @ingroup SemanticResultFormats
+ */
+class ListView extends View {
+
+ private $mFormat, $mTemplate, $mIntroTemplate, $mOutroTemplate, $mNamedArgs, $mShowHeaders;
+
+ /**
+ * Transfers the parameters applicable to this view into internal variables.
+ */
+ protected function handleParameters() {
+
+ $params = $this->getActualParameters();
+
+ $this->mFormat = $params['list view type'];
+ $this->mTemplate = $params['list view template'];
+ $this->mIntroTemplate = $params['list view introtemplate'];
+ $this->mOutroTemplate = $params['list view outrotemplate'];
+ $this->mNamedArgs = $params['list view named args'];
+
+ $this->mShowHeaders = $params['headers'];
+ }
+
+ public function getJsConfig() {
+ $this->handleParameters();
+ return [
+ 'format' => $this->mFormat,
+ 'named args' => $this->mNamedArgs,
+ 'show headers' => $this->mShowHeaders
+ ];
+ }
+
+ /**
+ * Returns the wiki text that is to be included for this view.
+ *
+ * @return string
+ */
+ public function getResultText() {
+
+ $this->handleParameters();
+
+ // Determine mark-up strings used around list items:
+ if ( ( $this->mFormat == 'ul' ) || ( $this->mFormat == 'ol' ) ) {
+ $header = "<" . $this->mFormat . ">\n";
+ $footer = "</" . $this->mFormat . ">\n";
+ $rowstart = "\t<li class='filtered-list-item ";
+ $rowend = "</li>\n";
+ $listsep = ', ';
+ } else { // "list" format
+ $header = '';
+ $footer = '';
+ $rowstart = "\t<div class='filtered-list-item ";
+ $rowend = "</div>\n";
+ $listsep = ', ';
+ }
+
+ // Initialise more values
+ $result = $header;
+
+ if ( $this->mIntroTemplate !== '' ) {
+ $result .= "{{" . $this->mIntroTemplate . "}}";
+ }
+
+ // Now print each row
+ $rownum = -1;
+
+ foreach ( $this->getQueryResults() as $id => $value ) {
+ $row = $value->getValue();
+
+ $this->printRow( $row, $rownum, $rowstart . $id . '\'>', $rowend, $result, $listsep );
+ }
+
+ if ( $this->mOutroTemplate !== '' ) {
+ $result .= "{{" . $this->mOutroTemplate . "}}";
+ }
+
+ // Print footer
+ if ( $footer !== '' ) {
+ $result .= $footer;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Prints one row of a list view.
+ *
+ * @param \SMWResultArray[] $row
+ * @param $rownum
+ * @param $rowstart
+ * @param $rowend
+ * @param $result
+ * @param $listsep
+ */
+ protected function printRow( $row, &$rownum, $rowstart, $rowend, &$result, $listsep ) {
+
+ $rownum++;
+
+ $result .= $rowstart;
+
+ if ( $this->mTemplate !== '' ) { // build template code
+ $this->getQueryPrinter()->hasTemplates( true );
+
+ // $wikitext = ( $this->mUserParam ) ? "|userparam=$this->mUserParam" : '';
+ $wikitext = '';
+
+ foreach ( $row as $fieldNumber => $field ) {
+
+ $printrequest = $field->getPrintRequest();
+
+ // only print value if not hidden
+ if ( filter_var( $printrequest->getParameter( 'hide' ), FILTER_VALIDATE_BOOLEAN ) === false ) {
+
+ $wikitext .= '|' . ( $this->mNamedArgs ? '?' . $printrequest->getLabel() : $fieldNumber + 1 ) . '=';
+ $isFirstValue = true;
+
+ $field->reset();
+ while ( ( $text = $field->getNextText(
+ SMW_OUTPUT_WIKI,
+ $this->getQueryPrinter()->getLinker( $fieldNumber == 0 )
+ ) ) !== false ) {
+ if ( $isFirstValue ) {
+ $isFirstValue = false;
+ } else {
+ $wikitext .= ', ';
+ }
+ $wikitext .= $text;
+ }
+ }
+ }
+
+ $wikitext .= "|#=$rownum";
+ $result .= '{{' . $this->mTemplate . $wikitext . '}}';
+
+ } else { // build simple list
+ $firstCol = true;
+ $foundValues = false; // has anything but the first column been printed?
+
+ foreach ( $row as $field ) {
+ $isFirstValue = true;
+
+ $printrequest = $field->getPrintRequest();
+
+ $field->reset();
+ while ( ( $text = $field->getNextText(
+ SMW_OUTPUT_WIKI,
+ $this->getQueryPrinter()->getLinker( $firstCol )
+ ) ) !== false ) {
+
+ // only print value if not hidden
+ if ( filter_var( $printrequest->getParameter( 'hide' ), FILTER_VALIDATE_BOOLEAN ) === false ) {
+
+ if ( !$firstCol && !$foundValues ) { // first values after first column
+ $result .= ' (';
+ $foundValues = true;
+ } elseif ( $foundValues || !$isFirstValue ) {
+ // any value after '(' or non-first values on first column
+ $result .= "$listsep ";
+ }
+
+ if ( $isFirstValue ) { // first value in any column, print header
+ $isFirstValue = false;
+
+ if ( ( $this->mShowHeaders != SMW_HEADERS_HIDE ) && ( $field->getPrintRequest()->getLabel(
+ ) !== '' ) ) {
+ $result .= $field->getPrintRequest()->getText(
+ SMW_OUTPUT_WIKI,
+ ( $this->mShowHeaders == SMW_HEADERS_PLAIN ? null : $this->getQueryPrinter(
+ )->getLinker( true, true ) )
+ ) . ' ';
+ }
+ }
+
+ $result .= $text; // actual output value
+ }
+ }
+
+ $firstCol = false;
+ }
+
+ if ( $foundValues ) {
+ $result .= ')';
+ }
+ }
+
+ $result .= $rowend;
+ }
+
+ /**
+ * A function to describe the allowed parameters of a query for this view.
+ *
+ * @return array of Parameter
+ */
+ public static function getParameters() {
+ $params = parent::getParameters();
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'list view type',
+ 'message' => 'srf-paramdesc-filtered-list-type',
+ 'default' => 'list',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ // 'type' => 'string',
+ 'name' => 'list view template',
+ 'message' => 'srf-paramdesc-filtered-list-template',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ 'type' => 'boolean',
+ 'name' => 'list view named args',
+ 'message' => 'srf-paramdesc-filtered-list-named-args',
+ 'default' => false,
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ //'type' => 'string',
+ 'name' => 'list view introtemplate',
+ 'message' => 'srf-paramdesc-filtered-list-introtemplate',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params[] = [
+ //'type' => 'string',
+ 'name' => 'list view outrotemplate',
+ 'message' => 'srf-paramdesc-filtered-list-outrotemplate',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ return $params;
+ }
+
+ /**
+ * Returns the label of the selector for this view.
+ *
+ * @return String the selector label
+ */
+ public function getSelectorLabel() {
+ return Message::newFromKey( 'srf-filtered-selectorlabel-list' )->inContentLanguage()->text();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/MapView.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/MapView.php
new file mode 100644
index 00000000..ceade356
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/MapView.php
@@ -0,0 +1,317 @@
+<?php
+
+namespace SRF\Filtered\View;
+
+use DataValues\Geo\Parsers\LatLongParser;
+use Exception;
+use SMWPropertyValue;
+use SRF\Filtered\ResultItem;
+
+class MapView extends View {
+
+ private static $viewParams = null;
+
+ private $mapProvider = null;
+
+ /**
+ * @param null $mapProvider
+ */
+ public function setMapProvider( $mapProvider ) {
+ $this->mapProvider = $mapProvider;
+ }
+
+ /**
+ * @return null
+ */
+ public function getMapProvider() {
+ if ( $this->mapProvider === null ) {
+ $this->setMapProvider( isset( $GLOBALS['srfgMapProvider'] ) ? $GLOBALS['srfgMapProvider'] : '' );
+ }
+
+ return $this->mapProvider;
+ }
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return array|null
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+
+ $markerPositionPropertyName = str_replace(
+ ' ',
+ '_',
+ $this->getActualParameters()['map view marker position property']
+ );
+
+ foreach ( $row->getValue() as $field ) {
+
+ $printRequest = $field->getPrintRequest();
+ $field->reset();
+
+ $value = $field->getNextDataItem();
+ if ( $printRequest->getData() instanceof SMWPropertyValue &&
+ $printRequest->getData()->getInceptiveProperty()->getKey() === $markerPositionPropertyName &&
+ ( $value instanceof \SMWDIGeoCoord || $value instanceof \SMWDIBlob )
+ ) {
+ $values = []; // contains plain text
+
+ if ( $value instanceof \SMWDIGeoCoord ) {
+
+ while ( $value instanceof \SMWDIGeoCoord ) {
+ $values[] = [ 'lat' => $value->getLatitude(), 'lng' => $value->getLongitude() ];
+ $value = $field->getNextDataItem();
+ }
+
+ } else {
+
+ $coordParser = new LatLongParser();
+ while ( $value instanceof \SMWDataItem ) {
+ try {
+ $latlng = $coordParser->parse( $value->getSerialization() );
+ $values[] = [ 'lat' => $latlng->getLatitude(), 'lng' => $latlng->getLongitude() ];
+ $value = $field->getNextDataItem();
+ }
+ catch ( Exception $exception ) {
+ $this->getQueryPrinter()->addError( "Error on '$value': " . $exception->getMessage() );
+ }
+ }
+
+ }
+
+ return [ 'positions' => $values, ];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns an array of config data for this view to be stored in the JS
+ *
+ * @return array
+ */
+ public function getJsConfig() {
+ $config = parent::getJsConfig();
+
+ $jsConfigKeys = [
+ 'height',
+ 'zoom',
+ 'minZoom',
+ 'maxZoom',
+ 'marker cluster',
+ 'marker cluster max zoom',
+ 'maxClusterRadius',
+ 'zoomToBoundsOnClick',
+ ];
+
+ foreach ( $jsConfigKeys as $key ) {
+ $this->addToConfig( $config, $key );
+ }
+
+ $this->addMarkerIconSetupToConfig( $config );
+
+ $config['map provider'] = $this->getMapProvider();
+
+ return $config;
+ }
+
+ /**
+ * A function to describe the allowed parameters of a query for this view.
+ *
+ * @return array of Parameter
+ */
+ public static function getParameters() {
+
+ if ( self::$viewParams === null ) {
+
+ $params = parent::getParameters();
+
+ $params['marker position property'] = [
+ // 'type' => 'string',
+ 'name' => 'map view marker position property',
+ 'message' => 'srf-paramdesc-filtered-map-position',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params['marker icon property'] = [
+ // 'type' => 'string',
+ 'name' => 'map view marker icon property',
+ 'message' => 'srf-paramdesc-filtered-map-icon',
+ 'default' => '',
+ // 'islist' => false,
+ ];
+
+ $params['marker icons'] = [
+ // 'type' => 'string',
+ 'name' => 'map view marker icons',
+ 'message' => 'srf-paramdesc-filtered-map-icons',
+ 'default' => [],
+ 'islist' => true,
+ ];
+
+ $params['height'] = [
+ 'type' => 'dimension',
+ 'name' => 'map view height',
+ 'message' => 'srf-paramdesc-filtered-map-height',
+ 'default' => 'auto',
+ ];
+
+ $params['zoom'] = [
+ 'type' => 'integer',
+ 'name' => 'map view zoom',
+ 'message' => 'srf-paramdesc-filtered-map-zoom',
+ 'default' => '',
+ ];
+
+ $params['minZoom'] = [
+ 'type' => 'integer',
+ 'name' => 'map view min zoom',
+ 'message' => 'srf-paramdesc-filtered-map-min-zoom',
+ 'default' => '',
+ ];
+
+ $params['maxZoom'] = [
+ 'type' => 'integer',
+ 'name' => 'map view max zoom',
+ 'message' => 'srf-paramdesc-filtered-map-max-zoom',
+ 'default' => '',
+ ];
+
+ //markercluster
+ $params['marker cluster'] = [
+ 'type' => 'boolean',
+ 'name' => 'map view marker cluster',
+ 'message' => 'srf-paramdesc-filtered-map-marker-cluster',
+ 'default' => true,
+ ];
+
+ $params['marker cluster max zoom'] = [
+ 'type' => 'integer',
+ 'name' => 'map view marker cluster max zoom',
+ 'message' => 'srf-paramdesc-filtered-map-marker-cluster-max-zoom',
+ 'default' => '',
+ ];
+
+ //clustermaxradius - maxClusterRadius: The maximum radius that a cluster will cover from the central marker (in pixels). Default 80.
+ $params['maxClusterRadius'] = [
+ 'type' => 'integer',
+ 'name' => 'map view marker cluster radius',
+ 'message' => 'srf-paramdesc-filtered-map-marker-cluster-max-radius',
+ 'default' => '',
+ ];
+
+ //clusterzoomonclick - zoomToBoundsOnClick: When you click a cluster we zoom to its bounds.
+ $params['zoomToBoundsOnClick'] = [
+ 'type' => 'boolean',
+ 'name' => 'map view marker cluster zoom on click',
+ 'message' => 'srf-paramdesc-filtered-map-marker-cluster-zoom-on-click',
+ 'default' => true,
+ ];
+
+ self::$viewParams = $params;
+ }
+
+ return self::$viewParams;
+ }
+
+ /**
+ * Returns the name of the resource module to load.
+ *
+ * @return string
+ */
+ public function getResourceModules() {
+ return 'ext.srf.filtered.map-view';
+ }
+
+ /**
+ * @param array $config
+ * @param string $key
+ */
+ private function addToConfig( &$config, $key ) {
+
+ $paramDefinition = self::getParameters()[$key];
+
+ $param = $this->getActualParameters()[$paramDefinition['name']];
+
+ if ( $param !== $paramDefinition['default'] ) {
+ $config[$key] = $param;
+ }
+
+ }
+
+ /**
+ * @param $config
+ */
+ protected function addMarkerIconSetupToConfig( &$config ) {
+
+ $param = $this->getActualParameters()['map view marker icon property'];
+
+ if ( $param !== '' ) {
+ $config['marker icon property'] = $this->getPropertyId( $param );
+ }
+
+ $config['marker icons'] = $this->getMarkerIcons();
+ }
+
+ /**
+ * @param $prop
+ *
+ * @return array
+ */
+ protected function getPropertyId( $prop ) {
+
+ $prop = strtr( $prop, ' ', '_' );
+
+ $printrequests = $this->getQueryPrinter()->getPrintrequests();
+ $cur = reset( $printrequests );
+
+ while ( $cur !== false && ( !array_key_exists( 'property', $cur ) || $cur['property'] !== $prop ) ) {
+ $cur = next( $printrequests );
+ }
+
+ return key( $printrequests );
+ }
+
+ /**
+ * @return array
+ */
+ private function getMarkerIcons() {
+
+ $ret = [];
+
+ $actualParameters = self::getActualParameters()['map view marker icons'];
+
+ foreach ( $actualParameters as $relation ) {
+
+ $relation = explode( '=', $relation, 2 );
+
+ if ( count( $relation ) === 1 ) {
+ $key = 'default';
+ $icon = $relation[0];
+ } else {
+ $key = $relation[0];
+ $icon = $relation[1];
+ }
+
+ $file = \WikiPage::factory( \Title::newFromText( $icon, NS_FILE ) )->getFile();
+
+ if ( $file->exists() ) {
+ $ret[$key] = $file->getUrl();
+ } else {
+ // TODO: $this->getQueryPrinter()->addError( NO_SUCH_FILE );
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getInitError() {
+ return $this->getMapProvider() === '' ? 'srf-filtered-map-provider-missing-error' : null;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/TableView.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/TableView.php
new file mode 100644
index 00000000..7f3c7664
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/TableView.php
@@ -0,0 +1,287 @@
+<?php
+
+namespace SRF\Filtered\View;
+
+/**
+ * File holding the TableView class
+ *
+ * @author Hans-Juergen Hartl (gesinn.it)
+ * @author Alexander Gesinn (gesinn.it)
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use Html;
+use Message;
+use SMW\Query\PrintRequest;
+use SMWPrintRequest;
+use SMWResultArray;
+use SRF\Filtered\ResultItem;
+use Xml;
+
+/**
+ * The TableView class defines the Table view.
+ *
+ * Available parameters for this view:
+ * headers: (show)|hide|plain
+ *
+ * @ingroup SemanticResultFormats
+ */
+class TableView extends View {
+
+ private $mShowHeaders;
+
+ /**
+ * @var string[]
+ */
+ private $columnClasses;
+
+ /**
+ * Transfers the parameters applicable to this view into internal variables.
+ */
+ protected function handleParameters() {
+
+ $params = $this->getActualParameters();
+
+ if ( $params['headers'] === 'hide' ) {
+ $this->mShowHeaders = SMW_HEADERS_HIDE;
+ } elseif ( $params['headers'] === 'plain' ) {
+ $this->mShowHeaders = SMW_HEADERS_PLAIN;
+ } else {
+ $this->mShowHeaders = SMW_HEADERS_SHOW;
+ }
+ }
+
+ /**
+ * Returns the wiki text that is to be included for this view.
+ *
+ * @return string
+ */
+ public function getResultText() {
+ $this->handleParameters();
+
+ // Initialise more values
+ $resultText = '';
+ $this->columnClasses = [];
+
+ // Table Header
+ if ( $this->mShowHeaders !== SMW_HEADERS_HIDE ) { // no headers when headers=hide
+ $resultText .= $this->getTableHeaders();
+ }
+
+ // Table Body
+ $resultText .= $this->getTableRowsHTML();
+
+ // Put the <table> tag around the whole thing and optionally add CSS class
+ $tableAttrs = null;
+ if ( array_key_exists( 'table view class', $this->getActualParameters() ) ) {
+ $tableAttrs = [ 'class' => $this->getActualParameters()['table view class'] ];
+ }
+
+ $resultText = Xml::tags( 'table', $tableAttrs, $resultText );
+
+ return $resultText;
+ }
+
+ private function getTableHeaders() {
+ $headers = [];
+
+ $queryResults = $this->getQueryResults();
+ $queryResultValue = reset( $queryResults );
+
+ if ( !is_a( $queryResultValue, ResultItem::class ) ) {
+ return '';
+ }
+
+ foreach ( $queryResultValue->getValue() as $field ) {
+ $printRequest = $field->getPrintRequest();
+ if ( filter_var( $printRequest->getParameter( 'hide' ), FILTER_VALIDATE_BOOLEAN ) === false ) {
+ $headers[] = $this->getTableHeader( $printRequest );
+ }
+ }
+
+ return "\n<tr>\n" . implode( "\n", $headers ) . "\n</tr>\n";
+ }
+
+ private function getTableHeader( PrintRequest $pr ) {
+ // build class attributes from header text assigned to each column's cell
+ $columnClass = $this->getColumnClass( $pr );
+
+ // Also add this to the array of classes, for
+ // use in displaying each row.
+ $this->columnClasses[] = $columnClass;
+
+ // get header text (and link to property)
+ $text = $pr->getText(
+ SMW_OUTPUT_WIKI,
+ $this->mShowHeaders === SMW_HEADERS_PLAIN ? null : $this->getQueryPrinter()->getLinker( false, true )
+ );
+
+ return Html::rawElement(
+ 'th',
+ [ 'class' => $columnClass ],
+ $text === '' ? '&nbsp;' : $text
+ );
+ }
+
+ private function getColumnClass( PrintRequest $pr ) {
+ return str_replace(
+ [ ' ', '_' ],
+ '-',
+ strip_tags( $pr->getText( SMW_OUTPUT_WIKI ) )
+ );
+ }
+
+ private function getTableRowsHTML() {
+ return implode(
+ "\n",
+ $this->getTableRows(
+ $this->getQueryResults(),
+ SMW_OUTPUT_WIKI,
+ $this->columnClasses
+ )
+ );
+ }
+
+ /**
+ * @param ResultItem[] $queryResults
+ * @param int $outputmode
+ * @param string[] $columnClasses
+ *
+ * @return array
+ */
+ private function getTableRows( $queryResults, $outputmode, $columnClasses ) {
+ $tableRows = [];
+
+ foreach ( $queryResults as $id => $value ) {
+ $cells = [];
+ $row = $value->getValue();
+
+ foreach ( $row as $fieldId => $field ) {
+
+ if ( filter_var(
+ $field->getPrintRequest()->getParameter( 'hide' ),
+ FILTER_VALIDATE_BOOLEAN
+ ) === false ) {
+
+ if ( array_key_exists( $fieldId, $columnClasses ) ) {
+ $columnClass = $columnClasses[$fieldId];
+ } else {
+ $columnClass = null;
+ }
+
+ $cells[] = $this->getCellForPropVals( $field, $outputmode, $columnClass );
+ }
+ }
+
+ $rowClass = 'filtered-table-item';
+ $tableRows[] = "<tr class=\"$rowClass $id\">\n\t" . implode( "\n\t", $cells ) . "\n</tr>";
+ }
+
+ return $tableRows;
+
+ }
+
+ /**
+ * Gets a table cell for all values of a property of a subject.
+ *
+ * @since 1.6.1
+ *
+ * @param SMWResultArray $resultArray
+ * @param $outputmode
+ * @param string | null $columnClass
+ *
+ * @return string
+ */
+ protected function getCellForPropVals( SMWResultArray $resultArray, $outputmode, $columnClass ) {
+
+ $resultArray->reset();
+
+ $dataValues = [];
+
+ while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) {
+ $dataValues[] = $dataValue;
+ }
+
+ $attribs = [];
+ $content = null;
+
+ if ( count( $dataValues ) > 0 ) {
+ $sortkey = $dataValues[0]->getDataItem()->getSortKey();
+
+ if ( is_numeric( $sortkey ) ) {
+ $attribs['data-sort-value'] = $sortkey;
+ }
+
+ $alignment = trim( $resultArray->getPrintRequest()->getParameter( 'align' ) );
+
+ if ( in_array( $alignment, [ 'right', 'left', 'center' ] ) ) {
+ $attribs['style'] = "text-align: $alignment;";
+ }
+
+ if ( $columnClass !== null ) {
+ $attribs['class'] = $columnClass;
+ }
+
+ $content = $this->getCellContent(
+ $dataValues,
+ $outputmode,
+ $resultArray->getPrintRequest()->getMode() === SMWPrintRequest::PRINT_THIS
+ );
+ }
+
+ return Html::rawElement(
+ 'td',
+ $attribs,
+ $content
+ );
+ }
+
+ /**
+ * Gets the contents for a table cell for all values of a property of a subject.
+ *
+ * @since 1.6.1
+ *
+ * @param \SMWDataValue[] $dataValues
+ * @param $outputmode
+ * @param boolean $isSubject
+ *
+ * @return string
+ */
+ protected function getCellContent( array $dataValues, $outputmode, $isSubject ) {
+ $values = [];
+
+ foreach ( $dataValues as $dataValue ) {
+ $values[] = $dataValue->getShortText( $outputmode, $this->getQueryPrinter()->getLinker( $isSubject ) );
+ }
+
+ return implode( '<br />', $values );
+ }
+
+ /**
+ * A function to describe the allowed parameters of a query for this view.
+ *
+ * @return array of Parameter
+ */
+ public static function getParameters() {
+ $params = parent::getParameters();
+
+ $params[] = [
+ 'name' => 'table view class',
+ 'message' => 'smw-paramdesc-table-class',
+ 'default' => 'wikitable sortable',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * Returns the label of the selector for this view.
+ *
+ * @return String the selector label
+ */
+ public function getSelectorLabel() {
+ return Message::newFromKey( 'srf-filtered-selectorlabel-table' )->inContentLanguage()->text();
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/View.php b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/View.php
new file mode 100644
index 00000000..8c98735d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/src/View/View.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace SRF\Filtered\View;
+
+/**
+ * File holding the SRF_Filtered_View class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+use SRF\Filtered\Filtered;
+use SRF\Filtered\ResultItem;
+
+/**
+ * The SRF_Filtered_View class.
+ *
+ * @ingroup SemanticResultFormats
+ */
+abstract class View {
+
+ private $mParameters;
+ private $mQueryPrinter;
+ private $mResults;
+
+ /**
+ * Constructor for the view.
+ *
+ * @param ResultItem[] $results
+ * @param string[] $params array of parameter values given as key-value-pairs
+ * @param Filtered $queryPrinter
+ */
+ public function __construct( array &$results, array &$params, Filtered &$queryPrinter ) {
+ $this->mResults = $results;
+ $this->mParameters = $params;
+ $this->mQueryPrinter = $queryPrinter;
+ }
+
+ /**
+ * @return ResultItem[]
+ */
+ public function &getQueryResults() { return $this->mResults; }
+
+ /**
+ * @return string[]
+ */
+ public function &getActualParameters() { return $this->mParameters; }
+
+ /**
+ * @return Filtered
+ */
+ public function &getQueryPrinter() { return $this->mQueryPrinter; }
+
+ /**
+ * Returns the name (string) or names (array of strings) of the resource
+ * modules to load.
+ *
+ * @return string|string[]|null
+ */
+ public function getResourceModules() {
+ return null;
+ }
+
+ /**
+ * A function to describe the allowed parameters of a query for this view.
+ *
+ * @see DefaultConfig.php of param-processor/param-processor for allowed types
+ *
+ * @return array of Parameter
+ */
+ public static function getParameters() {
+ return [];
+ }
+
+ /**
+ * Returns the HTML text that is to be included for this view.
+ *
+ * This text will appear on the page in a div that has the view's id set as
+ * class.
+ *
+ * @return string
+ */
+ public function getResultText() {
+ return '';
+ }
+
+ /**
+ * @param ResultItem $row
+ *
+ * @return null
+ */
+ public function getJsDataForRow( ResultItem $row ) {
+ return null;
+ }
+
+ /**
+ * Returns an array of config data for this view to be stored in the JS
+ *
+ * @return array
+ */
+ public function getJsConfig() {
+ return [];
+ }
+
+ /**
+ * Check if the view is ready to run, e.g. all required environment
+ * variables are set.
+ *
+ * @return string | null
+ */
+ public function getInitError() {
+ return null;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ControllerTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ControllerTest.ts
new file mode 100644
index 00000000..38b01f98
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ControllerTest.ts
@@ -0,0 +1,177 @@
+/// <reference types="qunit" />
+
+import { Controller } from "../../../resources/ts/Filtered/Controller";
+import { MockedFilter } from "../Util/MockedFilter";
+import { View } from "../../../resources/ts/Filtered/View/View";
+
+export class ControllerTest {
+
+ public runTests() {
+ QUnit.test( 'Controller: Can construct and attach data', this.testConstructAndAttachData );
+ QUnit.test( 'Controller: Attaching 3 views (foo, bar, baz) and switch between them', this.testAttachViewsAndSwitchToViews );
+ QUnit.test( 'Controller: Show', this.testShow );
+ QUnit.test( 'Controller: Attaching 3 filters (foo, bar, baz)', this.testAttachFilter );
+ return true;
+ }
+
+ /**
+ * @covers Controller.constructor
+ * @covers Controller.getData
+ */
+ public testConstructAndAttachData( assert: QUnitAssert ) {
+
+ // Setup
+ let data = { 'foo': {} };
+
+ // Run
+ let c = new Controller( undefined, data, {} );
+
+ // Assert: Can construct
+ assert.ok( c instanceof Controller, 'Can construct Controller.' );
+
+ // Assert: Data correctly attached and retained
+ assert.deepEqual( c.getData(), data, 'Returns result data as given to constructor.' );
+ }
+
+ /**
+ * @covers Controller.attachView
+ * @covers Controller.getView
+ * @covers Controller.onViewSelected
+ */
+ public testAttachViewsAndSwitchToViews( assert: QUnitAssert ) {
+
+ // Setup
+ let c = new Controller( undefined, undefined, undefined );
+ let viewIds = [ 'foo', 'bar', 'baz' ];
+ let viewsShown: View[] = [];
+ let viewsHidden: View[] = [];
+ let views: { [ id: string ]: View } = {};
+
+ viewIds.forEach( ( viewId ) => {
+
+ let v = new View( viewId, undefined, c, {} );
+
+ v.show = () => {
+
+ if ( viewsShown.indexOf( v ) === -1 ) {
+ viewsShown.push( v );
+ }
+
+ let index = viewsHidden.indexOf( v );
+ if ( index >= 0 ) {
+ viewsHidden.splice( index, 1 );
+ }
+ };
+
+ v.hide = () => {
+
+ if ( viewsHidden.indexOf( v ) === -1 ) {
+ viewsHidden.push( v );
+ }
+
+ let index = viewsShown.indexOf( v );
+ if ( index >= 0 ) {
+ viewsShown.splice( index, 1 );
+ }
+ };
+
+ views[ viewId ] = v;
+
+ // Run
+ c.attachView( viewId, v );
+ } );
+
+ // Assert: One view visible, all others hidden, i.e. none has undefined
+ // visibility
+ assert.strictEqual( viewsShown.length, 1, 'One view visible.' );
+ assert.strictEqual( viewsHidden.length, viewIds.length - 1, 'All but one view hidden.' );
+
+ for ( let viewId in views ) {
+ // Assert: View correctly attached and retained
+ assert.deepEqual( c.getView( viewId ), views[ viewId ], `Controller knows "${viewId}" view.` );
+ }
+
+ for ( let viewId in views ) {
+ // Run: Select view
+ c.onViewSelected( viewId );
+
+ // Assert: Only selected view visible, all others hidden, i.e. none
+ // has undefined visibility
+ assert.ok( viewsShown.length === 1 && viewsShown.indexOf( views[ viewId ] ) >= 0, 'Selected view visible.' );
+ assert.strictEqual( viewsHidden.length, viewIds.length - 1, 'All other views hidden.' );
+ }
+ }
+
+ /**
+ * @covers Controller.show
+ */
+ public testShow( assert: QUnitAssert ) {
+
+ // Setup
+ let targetElement = $();
+ let targetShown = false;
+
+ targetElement.children = function( selector?: string ) {
+
+ let targetChild = $();
+
+ targetChild.show = function () {
+ targetShown = true;
+ return targetChild;
+ };
+
+ return targetChild;
+ };
+
+
+ // Run
+ new Controller( targetElement, undefined, undefined ).show();
+
+ // Assert
+ assert.ok( targetShown, 'Container made visible.' );
+ }
+
+ /**
+ * @covers Controller.attachFilter
+ * @covers Controller.getFilter
+ */
+ public testAttachFilter( assert: QUnitAssert ) {
+
+ // Setup
+ let data = { 'foo': {} };
+ let controller = new Controller( undefined, data, {} );
+ let filterIds = [ 'foo', 'bar', 'baz' ];
+
+ let done = assert.async();
+
+ let promises: JQueryPromise< void >[] = [];
+
+ filterIds.forEach( ( filterId ) => {
+
+ let visibilityWasQueried = false;
+
+ let filter = new MockedFilter( filterId, undefined, undefined, controller );
+
+ filter.isVisible = function ( rowId ) {
+ visibilityWasQueried = true;
+ return true;
+ };
+
+ // Run
+
+ let promise = controller.attachFilter( filter )
+ .then( () => {
+ // Assert: Filter was queried for the visibility of result items
+ assert.ok( visibilityWasQueried, `Filter "${filterId}" was queried after attaching.` );
+ } );
+
+ promises.push( promise );
+
+ // Assert: Filter correctly attached and retained.
+ assert.deepEqual( controller.getFilter( filterId ), filter, `Controller knows "${filterId}" filter.` );
+ } );
+
+ jQuery.when( ...promises ).then( done );
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/Filter/ValueFilterTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/Filter/ValueFilterTest.ts
new file mode 100644
index 00000000..10d0c57c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/Filter/ValueFilterTest.ts
@@ -0,0 +1,88 @@
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+
+import { ValueFilter } from "../../../../resources/ts/Filtered/Filter/ValueFilter";
+import { Controller } from "../../../../resources/ts/Filtered/Controller";
+import { QUnitTest } from "../../Util/QUnitTest";
+
+export class ValueFilterTest extends QUnitTest {
+
+ // TODO:
+ // public isVisible( rowId: string ): boolean {
+ // public onFilterUpdated( eventObject: JQueryEventObject ) {
+
+ public runTests() {
+ QUnit.test( 'ValueFilter: Can construct', this.testCanConstruct );
+ QUnit.test( 'ValueFilter: Init', this.testInit );
+ QUnit.test( 'ValueFilter: Update on and/or switch.', this.testUseOr );
+ return true;
+ };
+
+ public testCanConstruct( assert: QUnitAssert ) {
+ let controller = undefined;
+ let options = {};
+
+ let f = new ValueFilter( 'foo', $(), 'fooPR', controller, options );
+
+ assert.ok( f instanceof ValueFilter, 'Can construct ValueFilter.' );
+ };
+
+ public testInit( assert: QUnitAssert ) {
+
+ // Setup
+ let controller = new Controller( $(), {}, {} );
+ let options = {
+ 'switches': [
+ 'and or'
+ ],
+ 'values': [
+ 'foo',
+ 'bar'
+ ],
+ 'collapsible': 'uncollapsed',
+ 'type': 'value',
+ 'label': 'FooLabel'
+ };
+ let target = $( '<div>' );
+ let f = new ValueFilter( 'foo', target, 'fooPR', controller, options );
+
+ // Run
+ f.init();
+
+ // Assert
+ assert.strictEqual( target.find( '.filtered-filter-container' ).length, 1, 'Added container for collapsable content.' );
+ assert.strictEqual( target.find( '.filtered-value-andor' ).length, 1, 'Added container for and/or switch.' );
+
+ let done = assert.async();
+ setTimeout( () => {
+ // Assert: One input added per value
+ for ( let value of options.values ) {
+ assert.strictEqual( target.find( "input[value=\"" + value + "\"]" ).length, 1, "Added option for value \"" + value + "\"." );
+ }
+ done();
+ }, 100);
+ };
+
+ public testUseOr( assert: QUnitAssert ) {
+
+ // Setup
+ let controller = new Controller( $(), {}, {} );
+ controller.onFilterUpdated = function ( filterId ): JQueryPromise< void > {
+ // Assert
+ assert.ok( true, 'Filter updated.' );
+
+ let d: JQueryDeferred< void > = jQuery.Deferred();
+ d.resolve();
+
+ return d.promise();
+ };
+
+ let f = new ValueFilter( 'foo', $(), 'fooPR', controller, {} );
+
+ assert.expect( 1 );
+
+ // Run
+ f.useOr( true );
+ };
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/MapViewTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/MapViewTest.ts
new file mode 100644
index 00000000..10832010
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/MapViewTest.ts
@@ -0,0 +1,23 @@
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+
+import { ViewTest } from "./ViewTest";
+import { MapView } from "../../../../resources/ts/Filtered/View/MapView";
+import { Controller } from "../../../../resources/ts/Filtered/Controller";
+import { Options } from "../../../../resources/ts/types";
+
+export class MapViewTest extends ViewTest {
+
+ // TODO:
+
+ public getTestObject( id: string = 'foo', target: JQuery = undefined, c: Controller = undefined, options: Options = {} ) {
+ c = c || new Controller( undefined, {}, undefined );
+ return new MapView( id, target, c, options );
+ };
+
+ public runTests() {
+ super.runTests();
+ return true;
+ };
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/ViewTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/ViewTest.ts
new file mode 100644
index 00000000..bce3c092
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/View/ViewTest.ts
@@ -0,0 +1,75 @@
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+
+import { QUnitTest } from "../../Util/QUnitTest";
+import { View } from "../../../../resources/ts/Filtered/View/View";
+import { Controller } from "../../../../resources/ts/Filtered/Controller";
+import { Options } from "../../../../resources/ts/types";
+
+export class ViewTest extends QUnitTest {
+
+ // Coverage:
+ // [x] public constructor( id: string, target: JQuery, c: Controller, options: Options = {} )
+ // [x] public init()
+ // [x] public getTargetElement(): JQuery
+ // [ ] public showRows( rowIds: string[] )
+ // [ ] public hideRows( rowIds: string[] )
+ // [x] public show()
+ // [x] public hide()
+
+ public getTestObject( id: string = 'foo', target: JQuery = undefined, c: Controller = undefined, options: Options = {} ) {
+ c = c || new Controller( undefined, {}, undefined );
+ return new View( id, target, c, options );
+ };
+
+ public runTests() {
+ let className = (<any> this.getTestObject().constructor)[ 'name' ];
+ let that: ViewTest = this;
+ QUnit.test( `${className}: Can construct, init and knows target element`, ( assert: QUnitAssert ) => { that.testBasics( assert, that ) } );
+ QUnit.test( `${className}: Show and Hide`, ( assert: QUnitAssert ) => { that.testShowAndHide ( assert, that ) } );
+ return true;
+ };
+
+ public testBasics( assert: QUnitAssert, that: ViewTest ) {
+
+ //Setup
+ let target = $( '<div>' );
+
+ // Run
+ let v = that.getTestObject( 'foo', target );
+ let ret : Promise<any>|void = v.init();
+
+ if ( ret !== undefined ) {
+ let done = assert.async();
+
+ (<Promise<any>>ret).then( () => {
+ assert.ok( v instanceof View, 'Can construct View. (P)' );
+ assert.strictEqual( v.getTargetElement(), target, 'View retains target element. (P)' );
+ done();
+ } );
+
+ } else {
+ // Assert
+ assert.ok( v instanceof View, 'Can construct View.' );
+ assert.strictEqual( v.getTargetElement(), target, 'View retains target element.' );
+ }
+ };
+
+ public testShowAndHide( assert: QUnitAssert, that: ViewTest ) {
+
+ // Setup
+ let target = $( '<div>' );
+
+ target.show = () => { assert.ok( true, 'Target element shown.'); return target; };
+ target.hide = () => { assert.ok( true, 'Target element hidden.'); return target; };
+
+ let v = that.getTestObject( 'foo', target );
+ v.init();
+
+ v.show();
+ v.hide();
+
+ assert.expect( 2 );
+ };
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ViewSelectorTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ViewSelectorTest.ts
new file mode 100644
index 00000000..f68a2ecb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Filtered/ViewSelectorTest.ts
@@ -0,0 +1,113 @@
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+
+import { ViewSelector } from "../../../resources/ts/Filtered/ViewSelector";
+import { Controller } from "../../../resources/ts/Filtered/Controller";
+
+export class ViewSelectorTest {
+
+ public runTests() {
+ QUnit.test( 'ViewSelector: Can construct', this.testCanConstruct );
+ QUnit.test( 'ViewSelector: Init for 1 view', this.testInitSingleView );
+ QUnit.test( 'ViewSelector: Init for 2 views', this.testInitMultipleViews );
+ QUnit.test( 'ViewSelector: Selecting views when clicked (3 views: foo, bar, baz)', this.testSelectViews );
+ return true;
+ }
+
+ public testCanConstruct( assert: QUnitAssert ) {
+ let v = new ViewSelector( undefined, [], undefined );
+ assert.ok( v instanceof ViewSelector, 'Can construct ViewSelector.' );
+ }
+
+ public testInitSingleView( assert: QUnitAssert ) {
+
+ // Setup
+ let callCount = 0;
+ let viewName = 'foo';
+
+ let target = $( '<div style="display:none">' );
+ target.append( '<div class="' + viewName + '">' );
+ target.on = function ( ...args: any[] ): JQuery {
+ callCount++;
+ return target;
+ };
+ target.appendTo( 'body' );
+
+ let v = new ViewSelector( target, [ viewName ], undefined );
+
+ // Run
+ v.init();
+
+ // Assert
+ assert.strictEqual( callCount, 0, 'Registers no Click events.' );
+ assert.ok( target.is( ':hidden' ), 'Target element is NOT visible.' );
+
+ // Tear down
+ target.remove();
+ }
+
+ public testInitMultipleViews( assert: QUnitAssert ) {
+
+ // Setup
+ let target: any = $( '<div style="display:none">' );
+ let viewSelectors: { [index: string]: JQuery } = {};
+ let viewIDs = [ 'foo', 'bar' ];
+ for ( let id of viewIDs ) {
+ viewSelectors[ id ] = $( '<div class="' + id + '">' );
+ target.append( viewSelectors[ id ] );
+ }
+ let eventRegistrationCount = 0;
+ target.origOn = target.on;
+ target.on = function ( ...args: any[] ) {
+ eventRegistrationCount++;
+ return target.origOn( ...args );
+ };
+ target.appendTo( 'body' );
+ let v = new ViewSelector( target, viewIDs, undefined );
+
+ // Run test: Initialize ViewSelector
+ v.init();
+
+ // Assert
+ assert.strictEqual( eventRegistrationCount, viewIDs.length, "Registers " + viewIDs.length + " Click events." );
+ assert.ok( target.children().first().hasClass( 'selected' ), 'First view selector is marked as selected.' );
+ assert.ok( target.is( ':visible' ), 'Target element is visible.' );
+
+ // Tear down
+ target.remove();
+ }
+
+ public testSelectViews( assert: QUnitAssert ) {
+
+ // Setup
+ let target = $( '<div style="display:none">' );
+ let viewSelectors:{ [index: string]: JQuery } = {};
+
+ let viewIDs = [ 'foo', 'bar', 'baz' ];
+ for ( let _i = 0, viewIDs_2 = viewIDs; _i < viewIDs_2.length; _i++ ) {
+ let id = viewIDs_2[ _i ];
+ viewSelectors[ id ] = $( '<div class="' + id + '">' );
+ target.append( viewSelectors[ id ] );
+ }
+
+ target.appendTo( 'body' );
+
+ let c = new Controller( undefined, undefined, undefined );
+ c.onViewSelected = function ( viewID ) {
+ // Assert that the ViewSelector called the Controller when clicked
+ assert.ok( true, "Controller was called to select view \"" + viewID + "\"." );
+ };
+ let v = new ViewSelector( target, viewIDs, c );
+ v.init();
+ // Run test: Select view
+ assert.expect( 6 );
+ for ( let id in viewSelectors ) {
+ viewSelectors[ id ].click();
+ // Assert: Only the clicked ViewController has class 'selected'
+ assert.ok( viewSelectors[ id ].hasClass( 'selected' ) && !viewSelectors[ id ].siblings().hasClass( 'selected' ), "View selector \"" + id + "\" marked as selected, siblings NOT marked as selected." );
+ }
+ // Tear down
+ target.remove();
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MWQunit.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MWQunit.ts
new file mode 100644
index 00000000..4d2458b5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MWQunit.ts
@@ -0,0 +1,5 @@
+/// <reference types="qunit" />
+
+export interface MWQunit extends QUnitStatic {
+ newMwEnvironment: () => LifecycleObject;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MockedFilter.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MockedFilter.ts
new file mode 100644
index 00000000..561148f5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/MockedFilter.ts
@@ -0,0 +1,3 @@
+import { Filter } from "../../../resources/ts/Filtered/Filter/Filter";
+
+export class MockedFilter extends Filter {} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTest.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTest.ts
new file mode 100644
index 00000000..6cc7013f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTest.ts
@@ -0,0 +1,3 @@
+export class QUnitTest {
+ public runTests(){};
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTestHandler.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTestHandler.ts
new file mode 100644
index 00000000..57590c54
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/Util/QUnitTestHandler.ts
@@ -0,0 +1,55 @@
+import { MWQunit } from "./MWQunit";
+import { QUnitTest } from "./QUnitTest";
+
+declare let QUnit: MWQunit;
+
+export class QUnitTestHandler {
+
+ isInitialised: boolean = false;
+ testclasses: (typeof QUnitTest)[];
+ moduleName: string;
+
+ constructor( moduleName: string, testclasses: (typeof QUnitTest)[] ) {
+ this.moduleName = moduleName;
+ this.testclasses = testclasses;
+ }
+
+ public init() {
+
+ if ( this.isInitialised ) {
+ return;
+ }
+
+ this.isInitialised = true;
+
+ QUnit.testDone( ( details: TestDoneCallbackObject ) => {
+ let message = `Pass: ${details.passed} Fail: ${details.failed} Total: ${details.total} ${details.module} - ${details.name} (${details.duration}ms)`;
+ this.reportResult( details.failed, message );
+ } );
+
+ QUnit.done( ( details: DoneCallbackObject ) => {
+ let message = `All tests finished. (${details.runtime}ms)\nPass: ${details.passed} Fail: ${details.failed} Total: ${details.total}`;
+ this.reportResult( details.failed, message );
+ } );
+ };
+
+ private reportResult( failed: number, message: string ) {
+ if ( failed === 0 ) {
+ console.log( message );
+ } else {
+ console.error( message );
+ }
+ }
+
+ public runTests() {
+
+ this.init();
+
+ QUnit.module( this.moduleName, QUnit.newMwEnvironment() );
+
+ this.testclasses.forEach( function ( testclass ) {
+ return new testclass().runTests();
+ } );
+ };
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/bootstrap.ts b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/bootstrap.ts
new file mode 100644
index 00000000..18559525
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tests/qunit/bootstrap.ts
@@ -0,0 +1,19 @@
+/// <reference types="qunit" />
+
+import { ViewSelectorTest } from "./Filtered/ViewSelectorTest";
+import { ControllerTest } from "./Filtered/ControllerTest";
+import { ValueFilterTest } from "./Filtered/Filter/ValueFilterTest";
+import { QUnitTestHandler } from "./Util/QUnitTestHandler";
+import { ViewTest } from "./Filtered/View/ViewTest";
+import { MapViewTest } from "./Filtered/View/MapViewTest";
+
+let testclasses = [
+ ViewSelectorTest,
+ ControllerTest,
+ ValueFilterTest,
+ ViewTest,
+ MapViewTest,
+];
+let testhandler = new QUnitTestHandler('ext.srf.formats.filtered', testclasses);
+
+testhandler.runTests();
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/filtered/tsconfig.json b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tsconfig.json
new file mode 100644
index 00000000..6b699b86
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/filtered/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "files": [
+ "resources/ts/bootstrap.ts"
+ ],
+ "compilerOptions": {
+ "noImplicitAny": true,
+ "target": "es3"
+ },
+ "exclude": [
+ "node_modules"
+ ]
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/Gallery.php b/www/wiki/extensions/SemanticResultFormats/formats/gallery/Gallery.php
new file mode 100644
index 00000000..0599c54f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/Gallery.php
@@ -0,0 +1,512 @@
+<?php
+
+namespace SRF;
+
+use Html;
+use SMW\ResultPrinter;
+use SMWDataItem;
+use SMWOutputs;
+use SMWPrintRequest;
+use SMWQueryResult;
+use SRFUtils;
+use Title;
+use TraditionalImageGallery;
+
+/**
+ * Result printer that outputs query results as a image gallery.
+ *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author mwjames
+ * @author Rowan Rodrik van der Molen
+ */
+class Gallery extends ResultPrinter {
+
+ /**
+ * @see SMWResultPrinter::getName
+ *
+ * @return string
+ */
+ public function getName() {
+ return $this->msg( 'srf_printername_gallery' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::buildResult
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $results
+ *
+ * @return string
+ */
+ protected function buildResult( SMWQueryResult $results ) {
+
+ // Intro/outro are not planned to work with the widget option
+ if ( ( $this->params['intro'] !== '' || $this->params['outro'] !== '' ) && $this->params['widget'] !== '' ) {
+ $results->addErrors(
+ [
+ $this->msg( 'srf-error-option-mix', 'widget' )->inContentLanguage()->text()
+ ]
+ );
+
+ return '';
+ };
+
+ return $this->getResultText( $results, $this->outputMode );
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param $results SMWQueryResult
+ * @param $outputmode integer
+ *
+ * @return string | array
+ */
+ public function getResultText( SMWQueryResult $results, $outputmode ) {
+
+ $ig = new TraditionalImageGallery();
+
+ $ig->setShowBytes( false );
+ $ig->setShowFilename( false );
+
+ if ( method_exists( $ig, 'setShowDimensions' ) ) {
+ $ig->setShowDimensions( false );
+ }
+
+ $ig->setCaption( $this->mIntro ); // set caption to IQ header
+
+ // No need for a special page to use the parser but for the "normal" page
+ // view we have to ensure caption text is parsed correctly through the parser
+ if ( !$this->isSpecialPage() ) {
+ $ig->setParser( $GLOBALS['wgParser'] );
+ }
+
+ $html = '';
+ $processing = '';
+
+ if ( $this->params['widget'] == 'carousel' ) {
+ // Carousel widget
+ $ig->setAttributes( $this->getCarouselWidget() );
+ } elseif ( $this->params['widget'] == 'slideshow' ) {
+ // Slideshow widget
+ $ig->setAttributes( $this->getSlideshowWidget() );
+ } else {
+
+ // Standard gallery attributes
+ $attribs = [
+ 'id' => uniqid(),
+ 'class' => $this->getImageOverlay(),
+ ];
+
+ $ig->setAttributes( $attribs );
+ }
+
+ // Only use redirects where the overlay option is not used and redirect
+ // thumb images towards a different target
+ if ( $this->params['redirects'] !== '' && !$this->params['overlay'] ) {
+ SMWOutputs::requireResource( 'ext.srf.gallery.redirect' );
+ }
+
+ // For the carousel widget, the perrow option should not be set
+ if ( $this->params['perrow'] !== '' && $this->params['widget'] !== 'carousel' ) {
+ $ig->setPerRow( $this->params['perrow'] );
+ }
+
+ if ( $this->params['widths'] !== '' ) {
+ $ig->setWidths( $this->params['widths'] );
+ }
+
+ if ( $this->params['heights'] !== '' ) {
+ $ig->setHeights( $this->params['heights'] );
+ }
+
+ $printReqLabels = [];
+ $redirectType = '';
+
+ /**
+ * @var SMWPrintRequest $printReq
+ */
+ foreach ( $results->getPrintRequests() as $printReq ) {
+ $printReqLabels[] = $printReq->getLabel();
+
+ // Get redirect type
+ if ( $this->params['redirects'] === $printReq->getLabel() ) {
+ $redirectType = $printReq->getTypeID();
+ }
+ }
+
+ if ( $this->params['imageproperty'] !== '' && in_array( $this->params['imageproperty'], $printReqLabels ) ||
+ $this->params['redirects'] !== '' && in_array( $this->params['redirects'], $printReqLabels ) ) {
+
+ $this->addImageProperties(
+ $results,
+ $ig,
+ $this->params['imageproperty'],
+ $this->params['captionproperty'],
+ $this->params['redirects'],
+ $outputmode
+ );
+ } else {
+ $this->addImagePages( $results, $ig );
+ }
+
+ // SRF Global settings
+ SRFUtils::addGlobalJSVariables();
+
+ // Display a processing image as long as the DOM is no ready
+ if ( $this->params['widget'] !== '' ) {
+ $processing = SRFUtils::htmlProcessingElement();
+ }
+
+ // Beautify the class selector
+ $class = $this->params['widget'] ? '-' . $this->params['widget'] . ' ' : '';
+ $class = $this->params['redirects'] !== '' && $this->params['overlay'] === false ? $class . ' srf-redirect' . ' ' : $class;
+ $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class;
+
+ // Separate content from result output
+ if ( !$ig->isEmpty() ) {
+ $attribs = [
+ 'class' => 'srf-gallery' . $class,
+ 'data-redirect-type' => $redirectType,
+ 'data-ns-text' => $this->getFileNsTextForPageLanguage()
+ ];
+
+ $html = Html::rawElement( 'div', $attribs, $processing . $ig->toHTML() );
+ }
+
+ // If available, create a link that points to further results
+ if ( $this->linkFurtherResults( $results ) ) {
+ $html .= $this->getLink( $results, SMW_OUTPUT_HTML )->getText( SMW_OUTPUT_HTML, $this->mLinker );
+ }
+
+ return [ $html, 'nowiki' => true, 'isHTML' => true ];
+ }
+
+ /**
+ * Handles queries where the images (and optionally their captions) are specified as properties.
+ *
+ * @since 1.5.3
+ *
+ * @param SMWQueryResult $results
+ * @param TraditionalImageGallery $ig
+ * @param string $imageProperty
+ * @param string $captionProperty
+ * @param string $redirectProperty
+ * @param $outputMode
+ */
+ protected function addImageProperties( SMWQueryResult $results, &$ig, $imageProperty, $captionProperty, $redirectProperty, $outputMode ) {
+ while ( /* array of SMWResultArray */
+ $rows = $results->getNext() ) { // Objects (pages)
+ $images = [];
+ $captions = [];
+ $redirects = [];
+
+ for ( $i = 0, $n = count( $rows ); $i < $n; $i++ ) { // Properties
+ /**
+ * @var \SMWResultArray $resultArray
+ * @var \SMWDataValue $dataValue
+ */
+ $resultArray = $rows[$i];
+
+ $label = $resultArray->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS
+ ? '-' : $resultArray->getPrintRequest()->getLabel();
+
+ // Make sure always use real label here otherwise it results in an empty array
+ if ( $resultArray->getPrintRequest()->getLabel() == $imageProperty ) {
+ while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
+ if ( $dataValue->getTypeID() == '_wpg' ) {
+ $images[] = $dataValue->getDataItem()->getTitle();
+ }
+ }
+ } elseif ( $label == $captionProperty ) {
+ while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
+ $captions[] = $dataValue->getShortText( $outputMode, $this->getLinker( true ) );
+ }
+ } elseif ( $label == $redirectProperty ) {
+ while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { // Property values
+ if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
+ $redirects[] = $dataValue->getTitle();
+ } elseif ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_URI ) {
+ $redirects[] = $dataValue->getURL();
+ }
+ }
+ }
+ }
+
+ // Check available matches against captions
+ $amountMatches = count( $captions ) == count( $images );
+ $hasCaption = $amountMatches || count( $captions ) > 0;
+
+ // Check available matches against redirects
+ $amountRedirects = count( $redirects ) == count( $images );
+ $hasRedirect = $amountRedirects || count( $redirects ) > 0;
+
+ /**
+ * @var Title $imgTitle
+ */
+ foreach ( $images as $imgTitle ) {
+ if ( $imgTitle->exists() ) {
+ $imgCaption = $hasCaption ? ( $amountMatches ? array_shift( $captions ) : $captions[0] ) : '';
+ $imgRedirect = $hasRedirect ? ( $amountRedirects ? array_shift( $redirects ) : $redirects[0] ) : '';
+ $this->addImageToGallery( $ig, $imgTitle, $imgCaption, $imgRedirect );
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles queries where the result objects are image pages.
+ *
+ * @since 1.5.3
+ *
+ * @param SMWQueryResult $results
+ * @param TraditionalImageGallery $ig
+ */
+ protected function addImagePages( SMWQueryResult $results, &$ig ) {
+ while ( $row = $results->getNext() ) {
+ /**
+ * @var \SMWResultArray $firstField
+ */
+ $firstField = $row[0];
+
+ /** @var \SMWDataValue $nextObject */
+ $nextObject = $firstField->getNextDataValue();
+
+ if ( $nextObject !== false ) {
+ $dataItem = $nextObject->getDataItem();
+ $imgTitle = method_exists( $dataItem, 'getTitle' ) ? $dataItem->getTitle() : null;
+
+ // Ensure the title belongs to the image namespace
+ if ( $imgTitle instanceof Title && $imgTitle->getNamespace() === NS_FILE ) {
+ $imgCaption = '';
+
+ // Is there a property queried for display with ?property
+ if ( isset( $row[1] ) ) {
+ $imgCaption = $row[1]->getNextDataValue();
+ if ( is_object( $imgCaption ) ) {
+ $imgCaption = $imgCaption->getShortText( $this->outputMode, $this->getLinker( true ) );
+ }
+ }
+
+ $this->addImageToGallery( $ig, $imgTitle, $imgCaption );
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a single image to the gallery.
+ * Takes care of automatically adding a caption when none is provided and parsing it's wikitext.
+ *
+ * @since 1.5.3
+ *
+ * @param TraditionalImageGallery $ig The gallery to add the image to
+ * @param Title $imgTitle The title object of the page of the image
+ * @param string $imgCaption An optional caption for the image
+ * @param string $imgRedirect
+ */
+ protected function addImageToGallery( &$ig, Title $imgTitle, $imgCaption, $imgRedirect = '' ) {
+
+ if ( empty( $imgCaption ) ) {
+ if ( $this->params['autocaptions'] ) {
+ $imgCaption = $imgTitle->getBaseText();
+
+ if ( !$this->params['fileextensions'] ) {
+ $imgCaption = preg_replace( '#\.[^.]+$#', '', $imgCaption );
+ }
+ } else {
+ $imgCaption = '';
+ }
+ } else {
+ if ( $imgTitle instanceof Title && $imgTitle->getNamespace() == NS_FILE && !$this->isSpecialPage() ) {
+ $imgCaption = $ig->mParser->recursiveTagParse( $imgCaption );
+ }
+ }
+ // Use image alt as helper for either text
+ $imgAlt = $this->params['redirects'] === '' ? $imgCaption : $imgRedirect !== '' ? $imgRedirect : '';
+ $ig->add( $imgTitle, $imgCaption, $imgAlt );
+ }
+
+ /**
+ * Returns the overlay setting
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ private function getImageOverlay() {
+ if ( array_key_exists( 'overlay', $this->params ) && $this->params['overlay'] == true ) {
+ SMWOutputs::requireResource( 'ext.srf.gallery.overlay' );
+ return ' srf-overlay';
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Init carousel widget
+ *
+ * @since 1.8
+ *
+ * @return string[]
+ */
+ private function getCarouselWidget() {
+
+ // Set attributes for jcarousel
+ $dataAttribs = [
+ 'wrap' => 'both', // Whether to wrap at the first/last item (or both) and jump back to the start/end.
+ 'vertical' => 'false', // Orientation: vertical = false means horizontal
+ 'rtl' => 'false', // Directionality: rtl = false means ltr
+ ];
+
+ // Use the perrow parameter to determine the scroll sequence.
+ if ( empty( $this->params['perrow'] ) ) {
+ $dataAttribs['scroll'] = 1; // default 1
+ } else {
+ $dataAttribs['scroll'] = $this->params['perrow'];
+ $dataAttribs['visible'] = $this->params['perrow'];
+ }
+
+ $attribs = [
+ 'id' => uniqid(),
+ 'class' => 'jcarousel jcarousel-skin-smw' . $this->getImageOverlay(),
+ 'style' => 'display:none;',
+ ];
+
+ foreach ( $dataAttribs as $name => $value ) {
+ $attribs['data-' . $name] = $value;
+ }
+
+ SMWOutputs::requireResource( 'ext.srf.gallery.carousel' );
+
+ return $attribs;
+ }
+
+ /**
+ * Init slideshow widget
+ *
+ * @since 1.8
+ *
+ * @return string[]
+ */
+ private function getSlideshowWidget() {
+
+ $attribs = [
+ 'id' => uniqid(),
+ 'class' => $this->getImageOverlay(),
+ 'style' => 'display:none;',
+ 'data-nav-control' => $this->params['navigation']
+ ];
+
+ SMWOutputs::requireResource( 'ext.srf.gallery.slideshow' );
+
+ return $attribs;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['class'] = [
+ 'type' => 'string',
+ 'message' => 'srf-paramdesc-class',
+ 'default' => ''
+ ];
+
+ $params['widget'] = [
+ 'type' => 'string',
+ 'default' => '',
+ 'message' => 'srf-paramdesc-widget',
+ 'values' => [ 'carousel', 'slideshow', '' ]
+ ];
+
+ $params['navigation'] = [
+ 'type' => 'string',
+ 'default' => 'nav',
+ 'message' => 'srf-paramdesc-navigation',
+ 'values' => [ 'nav', 'pager', 'auto' ]
+ ];
+
+ $params['overlay'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-overlay'
+ ];
+
+ $params['perrow'] = [
+ 'type' => 'integer',
+ 'default' => '',
+ 'message' => 'srf_paramdesc_perrow'
+ ];
+
+ $params['widths'] = [
+ 'type' => 'integer',
+ 'default' => '',
+ 'message' => 'srf_paramdesc_widths'
+ ];
+
+ $params['heights'] = [
+ 'type' => 'integer',
+ 'default' => '',
+ 'message' => 'srf_paramdesc_heights'
+ ];
+
+ $params['autocaptions'] = [
+ 'type' => 'boolean',
+ 'default' => true,
+ 'message' => 'srf_paramdesc_autocaptions'
+ ];
+
+ $params['fileextensions'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf_paramdesc_fileextensions'
+ ];
+
+ $params['captionproperty'] = [
+ 'type' => 'string',
+ 'default' => '',
+ 'message' => 'srf_paramdesc_captionproperty'
+ ];
+
+ $params['imageproperty'] = [
+ 'type' => 'string',
+ 'default' => '',
+ 'message' => 'srf_paramdesc_imageproperty'
+ ];
+
+ $params['redirects'] = [
+ 'type' => 'string',
+ 'default' => '',
+ 'message' => 'srf-paramdesc-redirects'
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @return bool
+ */
+ private function isSpecialPage() {
+ $title = $GLOBALS['wgTitle'];
+ return $title instanceof Title && $title->isSpecialPage();
+ }
+
+ /**
+ * @return bool|null|string
+ */
+ private function getFileNsTextForPageLanguage() {
+ $title = $GLOBALS['wgTitle'];
+ return $title instanceof Title ? $title->getPageLanguage()->getNsText( NS_FILE ) : null;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.formats.gallery.js b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.formats.gallery.js
new file mode 100644
index 00000000..7b168922
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.formats.gallery.js
@@ -0,0 +1,80 @@
+/**
+ * This file is part of the Semantic Result Formats Gallery module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Gallery_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Base srf.formats.gallery class that reserves the namespace
+ *
+ * There is a method ImageGallery->add which allows to override the
+ * image url but this feature is only introduced in MW 1.20 therefore
+ * we have to catch the "real" image location url from the api to be able
+ * to display the image in the fancybox
+ *
+ * @ignore
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Inheritance class for the srf.formats constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @abstract
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a gallery instance
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ * @extends srf.formats
+ */
+ srf.formats.gallery = function() {};
+
+ /**
+ * Public interface
+ *
+ * @ignore
+ */
+ srf.formats.gallery.prototype = {
+
+ /**
+ * Stores default values
+ *
+ * @property
+ * @type {Object}
+ */
+ defaults: {}
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.css b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.css
new file mode 100644
index 00000000..26b06a60
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.css
@@ -0,0 +1,296 @@
+/**
+ * This file is part of the SRF gallery carousel module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ *
+ * @ignore
+ */
+.jcarousel-skin-smw {
+ clear: both;
+}
+
+.jcarousel-skin-smw .jcarousel-container {
+ background: #ffffff;
+}
+
+.jcarousel-skin-smw .jcarousel-direction-rtl {
+ direction: rtl;
+}
+
+.jcarousel-list .jcarousel-list-horizontal {
+ margin-left:20px;
+}
+
+.jcarousel-skin-smw .jcarousel-container-horizontal {
+ width: 99.6%;
+ padding: 0px 1px;
+ margin-bottom:10px;
+ border: 1px solid #eee;
+
+}
+
+.jcarousel-skin-smw .jcarousel-container-vertical {
+ width: 155px;
+ height: 365px;
+ padding: 23px 15px;
+ margin-left:10px;
+ margin-bottom:10px;
+ border: 1px solid #eee;
+ float:right;
+}
+
+.jcarousel-skin-smw .jcarousel-clip {
+ overflow: hidden;
+}
+
+.jcarousel-skin-smw .jcarousel-clip-horizontal {
+ width: 97%;
+ height: auto;
+}
+
+.jcarousel-skin-smw .jcarousel-clip-vertical {
+ width: 160px;
+ height: 355px;
+}
+
+.jcarousel-skin-smw .jcarousel-item {
+ width: auto;
+ height: auto;
+}
+
+.jcarousel-skin-smw .jcarousel-item-horizontal {
+ margin-left: 23px;
+ margin-right: 0px;
+ margin-top: 4px;
+}
+
+.jcarousel-skin-smw .jcarousel-direction-rtl .jcarousel-item-horizontal {
+ margin-left: 0px;
+ margin-right: 23px;
+}
+
+.jcarousel-skin-smw .jcarousel-item-vertical {
+ margin-bottom: 10px;
+}
+
+.jcarousel-skin-smw .jcarousel-item-placeholder {
+ background: #fff;
+ color: #000;
+}
+
+/**
+ * Horizontal Buttons
+ * @ignore
+ */
+.jcarousel-skin-smw .jcarousel-next-horizontal {
+ position: absolute;
+ top: -1px;
+ right: -1px;
+ width: 32px;
+ height: 32px;
+ cursor: pointer;
+ background: transparent url(images/next-horizontal.png) no-repeat 0 0;
+ background-size:7px 11px;
+}
+
+.jcarousel-skin-smw .jcarousel-direction-rtl .jcarousel-next-horizontal {
+ left: -1px;
+ right: auto;
+ background-image: url(images/next-horizontal.png);
+}
+
+.jcarousel-skin-smw .jcarousel-next-horizontal:hover,
+.jcarousel-skin-smw .jcarousel-next-horizontal:focus {
+ background-position: -32px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-next-horizontal:active {
+ background-position: -64px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-next-disabled-horizontal,
+.jcarousel-skin-smw .jcarousel-next-disabled-horizontal:hover,
+.jcarousel-skin-smw .jcarousel-next-disabled-horizontal:focus,
+.jcarousel-skin-smw .jcarousel-next-disabled-horizontal:active {
+ cursor: default;
+ background-position: -96px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-horizontal {
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ width: 32px;
+ height: 32px;
+ cursor: pointer;
+ background: transparent url(images/prev-horizontal.png) no-repeat 0 0;
+ background-size:7px 11px;
+}
+
+.jcarousel-skin-smw .jcarousel-direction-rtl .jcarousel-prev-horizontal {
+ left: auto;
+ right: -1px;
+ background-image: url(images/prev-horizontal.png);
+}
+
+.jcarousel-skin-smw .jcarousel-prev-horizontal:hover,
+.jcarousel-skin-smw .jcarousel-prev-horizontal:focus {
+ background-position: -32px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-horizontal:active {
+ background-position: -64px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-disabled-horizontal,
+.jcarousel-skin-smw .jcarousel-prev-disabled-horizontal:hover,
+.jcarousel-skin-smw .jcarousel-prev-disabled-horizontal:focus,
+.jcarousel-skin-smw .jcarousel-prev-disabled-horizontal:active {
+ cursor: default;
+ background-position: -96px 0;
+}
+
+.jcarousel-skin-smw .jcarousel-next-horizontal,
+.jcarousel-skin-smw .jcarousel-prev-horizontal {
+ background-color: whiteSmoke;
+ background-position: center;
+ background-repeat: no-repeat;
+ border: 1px solid gainsboro;
+ color: #7B7B7B;
+ cursor: pointer;
+ font-size: 24px;
+ font-weight: bold;
+ height: 100%;
+ line-height: 216px;
+ text-align: center;
+ text-decoration: none;
+ position: absolute;
+ width: 23px;
+ border-radius: 2px 0 0 2px;
+ -moz-border-radius: 2px 0 0 2px;
+ -webkit-border-radius: 2px 0 0 2px;
+}
+
+.jcarousel-skin-smw .jcarousel-next-horizontal:hover,
+.jcarousel-skin-smw .jcarousel-prev-horizontal:hover {
+ background-color: #F8F8F8;
+ border-color: #D6D6D6;
+ box-shadow:inset 0 0 1px rgba(0, 0, 0, 0.1);
+ color: #4B4B4B;
+ text-decoration: none;
+}
+
+/**
+ * Vertical Buttons
+ * @ignore
+ */
+.jcarousel-skin-smw .jcarousel-next-vertical {
+ position: absolute;
+ bottom: -1px;
+ left: -1px;
+ width: 32px;
+ height: 32px;
+ cursor: pointer;
+ background: transparent url(images/next-vertical.png) no-repeat 0 0;
+ background-size:11px 7px;
+
+}
+
+.jcarousel-skin-smw .jcarousel-next-vertical:hover,
+.jcarousel-skin-smw .jcarousel-next-vertical:focus {
+ background-position: 0 -32px;
+}
+
+.jcarousel-skin-smw .jcarousel-next-vertical:active {
+ background-position: 0 -64px;
+}
+
+.jcarousel-skin-smw .jcarousel-next-disabled-vertical,
+.jcarousel-skin-smw .jcarousel-next-disabled-vertical:hover,
+.jcarousel-skin-smw .jcarousel-next-disabled-vertical:focus,
+.jcarousel-skin-smw .jcarousel-next-disabled-vertical:active {
+ cursor: default;
+ background-position: 0 -96px;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-vertical {
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ width: 32px;
+ height: 32px;
+ cursor: pointer;
+ background: transparent url(images/prev-vertical.png) no-repeat 0 0;
+ background-size:11px 7px;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-vertical:hover,
+.jcarousel-skin-smw .jcarousel-prev-vertical:focus {
+ background-position: 0 -32px;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-vertical:active {
+ background-position: 0 -64px;
+}
+
+.jcarousel-skin-smw .jcarousel-prev-disabled-vertical,
+.jcarousel-skin-smw .jcarousel-prev-disabled-vertical:hover,
+.jcarousel-skin-smw .jcarousel-prev-disabled-vertical:focus,
+.jcarousel-skin-smw .jcarousel-prev-disabled-vertical:active {
+ cursor: default;
+ background-position: 0 -96px;
+}
+
+.jcarousel-skin-smw .jcarousel-next-vertical,
+.jcarousel-skin-smw .jcarousel-prev-vertical {
+ background-color: whiteSmoke;
+ background-position: center;
+ background-repeat: no-repeat;
+ border: 1px solid gainsboro;
+ color: #7B7B7B;
+ cursor: pointer;
+ font-size: 24px;
+ font-weight: bold;
+ width: 100%;
+ line-height: 216px;
+ text-align: center;
+ text-decoration: none;
+ position: absolute;
+ height: 23px;
+ border-radius: 2px 0 0 2px;
+ -moz-border-radius: 2px 0 0 2px;
+ -webkit-border-radius: 2px 0 0 2px;
+}
+
+.jcarousel-skin-smw .jcarousel-next-vertical:hover,
+.jcarousel-skin-smw .jcarousel-prev-vertical:hover {
+ background-color: #F8F8F8;
+ border-color: #D6D6D6;
+ box-shadow:inset 0 0 1px rgba(0, 0, 0, 0.1);
+ color: #4B4B4B;
+ text-decoration: none;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.js b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.js
new file mode 100644
index 00000000..8db3ccbd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.carousel.js
@@ -0,0 +1,98 @@
+/**
+ * This file is part of the SRF gallery carousel module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Extends base class with a carousel function
+ *
+ * @class srf.formats.gallery.carousel
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * @class srf.formats.gallery
+ * @mixins srf.formats.gallery.carousel
+ */
+
+ $.extend( srf.formats.gallery.prototype, {
+
+ /**
+ * Provides the redirect functionality
+ *
+ * data-scroll Number of items to be scrolled
+ * data-visible Calculated and set visible elements
+ * data-wrap Options are "first", "last", "both" or "circular"
+ * data-vertical Whether the carousel appears in horizontal or vertical orientation
+ * data-rtl Directionality
+ *
+ * @since 1.8
+ *
+ * @param {string} context
+ *
+ * @return {Function}
+ */
+ carousel: function( context ) {
+ return context.each( function() {
+ var util = new srf.util();
+ var $this = $( this ),
+ fallbackDimension = srf.settings.get( 'wgThumbLimits' )[mw.user.options.get( 'thumbsize' )],
+ carousel = $this.find( '.jcarousel' );
+
+ util.spinner.hide( { context: $this } );
+
+ carousel.each( function() {
+ $( this ).show();
+ $( this ).jcarousel( {
+ scroll: parseInt( $( this ).attr( 'data-scroll' ), 10 ),
+ visible: parseInt( $( this ).attr( 'data-visible' ), 10 ),
+ wrap: $( this ).attr( 'data-wrap' ),
+ vertical: $( this ).attr( 'data-vertical' ) === 'true',
+ rtl: $( this ).attr( 'data-rtl' ) === 'true',
+ itemFallbackDimension: fallbackDimension
+ } );
+ } );
+ } );
+ }
+ } );
+
+ /**
+ * Implementation of an carousel instance
+ * @since 1.8
+ * @ignore
+ */
+ $( document ).ready( function() {
+ $( '.srf-gallery-carousel' ).each(function() {
+ var gallery = new srf.formats.gallery();
+ gallery.carousel( $( this ) );
+ } );
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.css b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.css
new file mode 100644
index 00000000..e7c7aa30
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.css
@@ -0,0 +1,68 @@
+/**
+ * This file is part of the SRF gallery overlay module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ *
+ * @ignore
+ */
+.srf-fancybox-title {
+ text-align: left;
+}
+
+.srf-fancybox-title b {
+ display: block;
+ margin-right: 80px;
+}
+
+.srf-fancybox-title .count{
+ text-align: left;
+ font-weight:lighter;
+}
+
+.srf-fancybox-title .button {
+ float: right;
+}
+
+.srf-overlay li.gallerybox div.thumb {
+ background-color: #fff;
+ background-image: -webkit-linear-gradient(top,white,#F6F8F9);
+ background-image: linear-gradient(top,white,#F6F8F9);
+}
+
+.srf-overlay li {
+ position: relative;
+}
+
+.srf-overlay .overlayicon {
+ position: absolute;
+ top:10px;
+ left:10px;
+ width: 16px;
+ height: 16px;
+ display:block;
+ /* @embed */ background: url(images/overlay-zoom.png) no-repeat left;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.js b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.js
new file mode 100644
index 00000000..e62feddb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.overlay.js
@@ -0,0 +1,158 @@
+/**
+ * This file is part of the SRF gallery overlay/fancybox module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Extends base class with an overlay function
+ *
+ * @class srf.formats.gallery.overlay
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * @class srf.formats.gallery
+ * @mixins srf.formats.gallery.overlay
+ */
+
+ $.extend( srf.formats.gallery.prototype, {
+
+ /**
+ * Provides the overlay functionality
+ *
+ * @since 1.8
+ *
+ * @param {string} context
+ * @param {string} ns
+ *
+ * @return {Function}
+ */
+ overlay: function( context, ns ) {
+ var self = this,
+ util = new srf.util();
+
+ // Override defaults
+ self.defaults = {
+ ns: ns,
+ path: srf.settings.get( 'srfgScriptPath' )
+ };
+
+ // Encode the namespace (NS_FILE) otherwise languages
+ // like Japanese, Chinese will fail
+ var encodedNsText = encodeURIComponent( ns );
+
+ context.each( function() {
+ var $this = $( this ),
+ galleryID = $this.attr( 'id' );
+
+ // Loop over all relevant gallery items
+ $this.find( '.gallerybox' ).each( function () {
+ var $this = $( this ),
+ h = mw.html,
+ image = $this.find( 'a.image' ),
+ imageText = $.trim( $this.find( '.gallerytext p' ).text() );
+
+ // Group images
+ image.attr( 'rel', image.has( 'img' ).length ? galleryID : '' );
+
+ // Copy text information for image text display
+ imageText = imageText !== null ? imageText : image.find( 'img' ).attr( 'alt' );
+ image.attr( 'title', imageText );
+
+ // Avoid undefined error
+ if ( image.attr( 'href' ) === undefined ) {
+ $this.html( '<span class="error">' + mw.message( 'srf-gallery-image-url-error' ).escaped() + '</span>' );
+ } else {
+
+ // There should be a better way to get the title object but there isn't
+ // var title = image.attr( 'href' ).replace(/.+?\File:(.*)$/, "$1" ).replace( "%27", "\'" ),
+ // Apparently Windows server uses %3A
+ var href = image.attr( 'href' ),
+ title = href.split( encodedNsText + ( href.indexOf( '%3A' ) >= 0 ? '%3A': ':' ) );
+
+ // Prepare overlay icon placeholder
+ image.before( h.element( 'a', { 'class': 'overlayicon', 'href': href }, null ) );
+ var overlayIcon = $this.find( '.overlayicon' ).hide();
+
+ // Add spinner while fetching the URL
+ util.spinner.create( { context: $this, selector: 'img' } );
+
+ // Re-assign image url
+ util.getImageURL( { 'title': ns + ':' + decodeURIComponent( title[1] ) },
+ function( url ) { if ( url === false ) {
+ image.attr( 'href', '' );
+ // Release thumb image
+ util.spinner.replace( { context: $this, selector: 'img' } );
+ } else {
+ image.attr( 'href', url );
+ // Release thumb image
+ util.spinner.replace( { context: $this, selector: 'img' } );
+ // Release overlay icon
+ overlayIcon.show();
+ }
+ } );
+ }
+ } );
+
+ // Formatting the title
+ function formatTitle( title, currentArray, currentIndex /*,currentOpts*/ ) {
+ return '<div class="srf-fancybox-title"><span class="button"><a href="javascript:;" onclick="$.fancybox.close();"><img src=' + self.defaults.path + '/resources/jquery/fancybox/closelabel.gif' + '></a></span>' + (title && title.length ? '<b>' + title : '' ) + '<span class="count"> (' + mw.msg( 'srf-gallery-overlay-count', (currentIndex + 1) , currentArray.length ) + ')</span></div>';
+ }
+
+ // Display all images related to a group
+ $this.find( "a[rel^=" + galleryID + "]" ).fancybox( {
+ 'showCloseButton' : false,
+ 'titlePosition' : 'inside',
+ 'titleFormat' : formatTitle
+ } );
+ } );
+ }
+ } );
+
+ /**
+ * Implementation of an overlay instance
+ * @since 1.8
+ * @ignore
+ */
+ $( document ).ready( function() {
+ var ns = 'File';
+
+ // Find the namespace used for the current instance
+ $( '.srf-gallery,.srf-gallery-slideshow,.srf-gallery-carousel' ).each( function() {
+ ns = $( this ).data( 'ns-text' );
+ } );
+
+ $( '.srf-overlay' ).each( function() {
+ var gallery = new srf.formats.gallery();
+ gallery.overlay( $( this ), ns );
+ } );
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.css b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.css
new file mode 100644
index 00000000..c5aa1eef
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.css
@@ -0,0 +1,44 @@
+/**
+ * This file is part of the SRF gallery redirect module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ *
+ * @ignore
+ */
+.srf-redirect li {
+ position: relative;
+}
+
+.srf-redirect .redirecticon {
+ position: absolute;
+ top:10px;
+ left:10px;
+ width: 16px;
+ height: 16px;
+ display:block;
+ /* @embed */ background: url(images/gallery-redirect.png) no-repeat left;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.js b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.js
new file mode 100644
index 00000000..8de2d3c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.redirect.js
@@ -0,0 +1,118 @@
+/**
+ * This file is part of the SRF gallery redirect module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Extends base class with a redirect function
+ *
+ * @class srf.formats.gallery.redirect
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * @class srf.formats.gallery
+ * @mixins srf.formats.gallery.redirect
+ */
+
+ $.extend( srf.formats.gallery.prototype, {
+
+ /**
+ * Provides the redirect functionality
+ *
+ * @since 1.8
+ *
+ * @param {string} context
+ *
+ * @return {Function}
+ */
+ redirect: function( context ) {
+ var util = new srf.util();
+ var type = context.data( 'redirect-type' );
+ return context.find( '.gallerybox' ).each( function() {
+ var $this = $( this ),
+ h = mw.html,
+ image = $this.find( 'a.image' );
+
+ // Avoid undefined error
+ if ( image.attr( 'href' ) === undefined ) {
+ $this.html( h.element( 'span', { 'class': 'error' }, mw.message( 'srf-gallery-image-url-error' ).escaped() ) );
+ } else {
+
+ // Per convention "alt" attribute contains the redirect title
+ var titleAlt = image.find( 'img' ).attr( 'alt' ),
+ titleStatus = titleAlt !== undefined && titleAlt.length > 0,
+ imageSource = image.attr( 'href' );
+
+ // Prepare and hide the redirect icon placeholder
+ image.before( h.element( 'a', { 'class': 'redirecticon', 'href': imageSource }, null ) );
+ var redirect = $this.find( '.redirecticon' ).hide();
+
+ if ( type === '_uri' && titleStatus ) {
+ // Direct assign redirect url
+ image.attr( 'href', titleAlt );
+ redirect.show();
+ } else if ( titleStatus ) {
+ // Assign redirect article url
+ // Show image spinner while fetching the URL
+ util.spinner.create( { context: $this, selector: 'img' } );
+
+ util.getTitleURL( { 'title': titleAlt },
+ function( url ) { if ( url === false ) {
+ image.attr( 'href', '' );
+ // Release thumb image
+ util.spinner.replace( { context: $this, selector: 'img' } );
+ } else {
+ image.attr( 'href', url );
+ // Release thumb image
+ util.spinner.replace( { context: $this, selector: 'img' } );
+ // Release redirect icon
+ redirect.show();
+ }
+ } );
+ }
+ }
+ } );
+ }
+ } );
+
+ /**
+ * Implementation of an redirect instance
+ * @since 1.8
+ * @ignore
+ */
+ $( document ).ready( function() {
+ $( '.srf-redirect' ).each(function() {
+ var gallery = new srf.formats.gallery();
+ gallery.redirect( $( this ) );
+ } );
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.css b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.css
new file mode 100644
index 00000000..280cbcec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.css
@@ -0,0 +1,103 @@
+/**
+ * This file is part of the SRF gallery slideshow module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ * @author viljamis
+ *
+ * @ignore
+ */
+.srf-gallery-slideshow ul.gallery {
+ padding: 0px 0px 0px 0px;
+}
+
+.srf-gallery-slideshow .prev {
+ overflow: hidden;
+ padding: 0px 6px;
+}
+
+.srf-gallery-slideshow .rslides {
+ position: relative;
+ z-index: 0;
+ list-style: none;
+ overflow: hidden;
+ width: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.srf-gallery-slideshow .rslides li {
+ position: absolute;
+ display: none;
+ width: 100%;
+ left: 0;
+ top: 0;
+}
+
+.srf-gallery-slideshow .rslides li:first-child {
+ position: relative;
+ display: block;
+ float: left;
+}
+
+/**
+ * Pager
+ * @ignore
+ */
+.srf-gallery-slideshow .rslides_tabs {
+ padding: 0;
+ margin: 1em 0;
+ clear: both;
+}
+
+.srf-gallery-slideshow ul.rslides_tabs {
+ padding: 0;
+ margin: .3em 0 0 4px;
+}
+
+.srf-gallery-slideshow .rslides_tabs li {
+ display: inline-block;
+ padding: 0 2px;
+}
+
+.srf-gallery-slideshow .rslides_tabs a {
+ background: #ddd;
+ display: inline-block;
+ height: 10px;
+ text-indent: -9999px;
+ width: 10px;
+ border-radius: 5px;
+}
+
+.ie .srf-gallery-slideshow .rslides_tabs li,
+.ie .srf-gallery-slideshow .rslides_tabs a {
+ display: block;
+ float: left;
+}
+
+.srf-gallery-slideshow .rslides_tabs .rslides_here a {
+ background: #777;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.js b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.js
new file mode 100644
index 00000000..9eac3fea
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/ext.srf.gallery.slideshow.js
@@ -0,0 +1,116 @@
+/**
+ * This file is part of the SRF gallery slideshow module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gallery_format
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.8
+ * @revision 0.4
+ *
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Extends base class with a slideshow function
+ *
+ * @class srf.formats.gallery.slideshow
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * @class srf.formats.gallery
+ * @mixins srf.formats.gallery.slideshow
+ */
+
+ $.extend( srf.formats.gallery.prototype, {
+
+ /**
+ * Provides the slideshow functionality
+ *
+ * @since 1.8
+ *
+ * @param {string} context
+ *
+ * @return {Function}
+ */
+ slideshow: function( context ) {
+ return context.each( function() {
+ var util = new srf.util();
+ var $this = $( this );
+ var maxHeight = 0;
+ var gallery = $this.find( 'ul' );
+ var galleryId = '#' + gallery.attr( 'id' );
+ var previous = $this.prev( 'p' ).children( 'br' );
+
+ // The gallery parser comes with a preceding empty <p> element
+ // this is a work-around to avoid
+ if ( previous.length == 1 ) {
+ previous.hide();
+ }
+
+ // Make elements visible / hide
+ util.spinner.hide( { context: $this } );
+ gallery.show();
+
+ // Loop over all the gallery items
+ gallery.find( 'li' ).each( function () {
+
+ // Text elements can vary in there height therefore determine max height
+ // for all images used in the same instance
+ if($(this).height() > maxHeight ) {
+ maxHeight = $( this ).height();
+ }
+ } );
+
+ // Set max height in order for all elements to be positioned equally
+ gallery.height( maxHeight );
+
+ if( !gallery.responsiveSlides({
+ pauseControls: gallery.attr( 'data-nav-control' ) === 'auto',
+ prevText: mw.msg( 'srf-gallery-navigation-previous' ),
+ nextText: mw.msg( 'srf-gallery-navigation-next' ),
+ auto: gallery.attr( 'data-nav-control' ) === 'auto',
+ pause: gallery.attr( 'data-nav-control' ) === 'auto',
+ pager: gallery.attr( 'data-nav-control' ) === 'pager',
+ nav: gallery.attr( 'data-nav-control' ) === 'nav'
+ } ) ) {
+ // something went wrong, hide the canvas container
+ $this.find( galleryId ).hide();
+ }
+ } );
+ }
+ } );
+
+ /**
+ * Implementation of an slideshow instance
+ * @since 1.8
+ * @ignore
+ */
+ $( document ).ready( function() {
+ $( '.srf-gallery-slideshow' ).each(function() {
+ var gallery = new srf.formats.gallery();
+ gallery.slideshow( $( this ) );
+ } );
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/gallery-redirect.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/gallery-redirect.png
new file mode 100644
index 00000000..7ce88243
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/gallery-redirect.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-horizontal.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-horizontal.png
new file mode 100644
index 00000000..64a4e490
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-horizontal.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-vertical.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-vertical.png
new file mode 100644
index 00000000..a76a8186
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/next-vertical.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/overlay-zoom.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/overlay-zoom.png
new file mode 100644
index 00000000..cae53d36
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/overlay-zoom.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-horizontal.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-horizontal.png
new file mode 100644
index 00000000..436b6b30
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-horizontal.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-vertical.png b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-vertical.png
new file mode 100644
index 00000000..ec33dcf4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/gallery/resources/images/prev-vertical.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/README b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/README
new file mode 100644
index 00000000..bcc20a4f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/README
@@ -0,0 +1,18 @@
+Google Charts are query printers for Semantic MediaWiki applying the Google Charts API
+documented at https://developers.google.com/chart/image/
+
+Important notes:
+* You must not forget that every time a user comes to a page embedding a Google chart,
+Google gets a ping. Moreover your data is being sent to Google in order to render it.
+!! The creator of Semantic Result Formats have not control over and cannot take any
+responsibility in case of any misuse resulting from this !!
+* As of April 20, 2012 the Google Charts API is deprecated and may be shut down
+without further notice. Thus you are advised to not rely on these two formats.
+* Do not forget also that these printers do not work offline, if you have a local wiki.
+
+Currently two query printers are available for bar and pie charts. For up-to-date
+documentation, please refer to:
+* https://www.semantic-mediawiki.org/wiki/Help:Google_bar_format for the Google bar format
+* https://www.semantic-mediawiki.org/wiki/Help:Google_pie_format for the Google pie format
+
+Semantic Result Formats provides these two legacy result printers for your convenience.
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GoogleBar.php b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GoogleBar.php
new file mode 100644
index 00000000..b14fd215
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GoogleBar.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * A query printer using the Google Chart API
+ *
+ * @note AUTOLOADED
+ */
+
+class SRFGoogleBar extends SMWResultPrinter {
+
+ protected $m_width;
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::handleParameters()
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ $this->m_width = $this->params['width'];
+ }
+
+ public function getName() {
+ return wfMessage( 'srf_printername_googlebar' )->text();
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ $this->isHTML = true;
+
+ $t = "";
+ $n = "";
+
+ // if there is only one column in the results then stop right away
+ if ( $res->getColumnCount() == 1 ) {
+ return "";
+ }
+
+ // print all result rows
+ $first = true;
+ $count = 0; // How many bars will they be? Needed to calculate the height of the image
+ $max = 0; // the biggest value. needed for scaling
+
+ while ( $row = $res->getNext() ) {
+ $name = $row[0]->getNextDataValue()->getShortWikiText();
+ foreach ( $row as $field ) {
+ while ( ( $object = $field->getNextDataValue() ) !== false ) {
+
+ // use numeric sortkey
+ if ( $object->isNumeric() ) {
+ $nr = $object->getDataItem()->getSortKey();
+
+ $count++;
+ $max = max( $max, $nr );
+
+ if ( $first ) {
+ $first = false;
+ $t .= $nr;
+ $n = $name;
+ } else {
+ $t = $nr . ',' . $t;
+ $n .= '|' . $name; // yes, this is correct, it needs to be the other way
+ }
+ }
+ }
+ }
+ }
+
+ $barwidth = 20; // width of each bar
+ $bardistance = 4; // distance between two bars
+ $height = $count * ( $barwidth + $bardistance ) + 15; // calculates the height of the image
+
+ return '<img src="https://chart.apis.google.com/chart?cht=bhs&chbh=' . $barwidth . ',' . $bardistance . '&chs=' . $this->m_width . 'x' . $height . '&chds=0,' . $max . '&chd=t:' . $t . '&chxt=y&chxl=0:|' . $n . '" width="' . $this->m_width . '" height="' . $height . '" />';
+
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['width'] = [
+ 'type' => 'integer',
+ 'default' => 250,
+ 'message' => 'srf_paramdesc_chartwidth',
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GooglePie.php b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GooglePie.php
new file mode 100644
index 00000000..6deda86b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/googlecharts/SRF_GooglePie.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * A query printer for pie charts using the Google Chart API
+ *
+ * @note AUTOLOADED
+ */
+
+class SRFGooglePie extends SMWResultPrinter {
+
+ protected $m_width = 250;
+ protected $m_heighth = 100;
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::handleParameters()
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ $this->m_width = $this->params['width'];
+ $this->m_height = $this->params['height'];
+ }
+
+ public function getName() {
+ return wfMessage( 'srf_printername_googlepie' )->text();
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ $this->isHTML = true;
+
+ $t = "";
+ $n = "";
+
+ // if there is only one column in the results then stop right away
+ if ( $res->getColumnCount() == 1 ) {
+ return "";
+ }
+
+ // print all result rows
+ $first = true;
+ $max = 0; // the biggest value. needed for scaling
+
+ while ( $row = $res->getNext() ) {
+ $name = $row[0]->getNextDataValue()->getShortWikiText();
+
+ foreach ( $row as $field ) {
+ while ( ( $object = $field->getNextDataValue() ) !== false ) {
+ // use numeric sortkey
+ if ( $object->isNumeric() ) {
+ $nr = $object->getDataItem()->getSortKey();
+
+ $max = max( $max, $nr );
+
+ if ( $first ) {
+ $first = false;
+ $t .= $nr;
+ $n = $name;
+ } else {
+ $t = $nr . ',' . $t;
+ $n = $name . '|' . $n;
+ }
+ }
+ }
+ }
+ }
+
+ return '<img src="https://chart.apis.google.com/chart?cht=p3&chs=' . $this->m_width . 'x' . $this->m_height . '&chds=0,' . $max . '&chd=t:' . $t . '&chl=' . $n . '" width="' . $this->m_width . '" height="' . $this->m_height . '" />';
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'default' => 100,
+ 'message' => 'srf_paramdesc_chartheight',
+ ];
+
+ $params['width'] = [
+ 'type' => 'integer',
+ 'default' => 250,
+ 'message' => 'srf_paramdesc_chartwidth',
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/README b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/README
new file mode 100644
index 00000000..3c9f9597
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/README
@@ -0,0 +1,23 @@
+Graph and Process are query printers for Semantic MediaWiki making use of
+GraphViz and Mscgen in order to create graphs and process graphs out of
+query results.
+
+== Installation ==
+For these two formats to work you do not just need the Semantic MediaWiki
+and the Semantic Result Formats extension to be installed but also the
+GraphViz extension and the ImageMap extension. Moreover the GraphViz extension
+requires the graphviz and mscgen packages to be installed on your server.
+
+The extensions mentioned are best installed using Composer. Please refer to
+the individual documentation on how to do this.
+
+The packages mentioned are best installed according to your servers operating
+system requirements. Please refer to the individual documentation for the
+packages on how to do this.
+
+== Usage ==
+For an up to date documentation concerning the Graph and Process formats please
+refer to the following pages:
+
+* https://www.semantic-mediawiki.org/wiki/Help:Graph_format
+* https://www.semantic-mediawiki.org/wiki/Help:Process_format
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/SRF_Process.php b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/SRF_Process.php
new file mode 100644
index 00000000..610ff187
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/SRF_Process.php
@@ -0,0 +1,1390 @@
+<?php
+/*******************************************************************************
+ * This file contains the Process Printer for SemanticResultFormats
+ * (https://www.mediawiki.org/wiki/Extension:Semantic_Result_Formats)
+ *
+ * Copyright (c) 2008 - 2009 Frank Dengler and Hans-Jörg Happel
+ *
+ * Process Printer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Printer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Printer. If not, see <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ die( 'Not an entry point.' );
+}
+
+/**
+ * This is a contribution to Semtantic Result Formats (SRF) which are an
+ * extension of Semantic MediaWiki (SMW) which in turn is an extension
+ * of MediaWiki
+ *
+ * SRF defines certain "printers" to render the results of SMW semantic
+ * "ASK"-queries. Some of these printers make use of the GraphViz/dot
+ * library (which is wrapped by a separate MediaWiki extension).
+ *
+ * The purpose of this extension, is to render results of ASK-Queries
+ * (e.g. Classes with Attributes) as GraphViz-layouted process graphs
+ *
+ *
+ * @author Frank Dengler
+ * @author Hans-Jörg Happel
+ * @ingroup SemanticResultFormats
+ *
+ * @note AUTOLOADED
+ */
+
+// global variable defining picture path
+
+$srfgPicturePath = "formats/graphviz/images/";
+
+class SRFProcess extends SMWResultPrinter {
+
+ // configuration variables
+ protected $m_graphValidation = false;
+ protected $m_isDebugSet = false;
+ protected $m_processCategory = 'Process'; // Category for processes - required for rendering compound nodes
+
+ // internal variables
+ protected $m_process; // process to be rendered
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::handleParameters()
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ // init process graph instance
+ $this->m_process = new ProcessGraph();
+
+ $this->m_process->setGraphName( trim( $params['graphname'] ) );
+ $this->m_process->setGraphSize( trim( $params['graphsize'] ) );
+ $this->m_process->setClusterColor( trim( $params['clustercolor'] ) );
+ $this->m_process->setRankdir( strtoupper( trim( $params['rankdir'] ) ) );
+ $this->m_process->setHighlightNode( trim( $params['highlight'] ) );
+ $this->m_process->setHighlightColor( trim( $params['highlightcolor'] ) );
+ $this->m_process->setHighlightColor( trim( $params['redlinkcolor'] ) );
+
+ $this->m_process->setShowRoles( $params['showroles'] );
+ $this->m_process->setShowStatus( $params['showstatus'] );
+ $this->m_process->setShowRessources( $params['showresources'] );
+ $this->m_process->setShowDiscussion( $params['showdiscussion'] );
+ $this->m_process->setShowRedLinks( $params['showredlinks'] );
+ $this->m_process->setShowCompound( $params['showcompound'] );
+
+ $this->m_processCategory = $params['processcat'];
+ $this->m_isDebugSet = $params['debug'];
+ $this->m_graphValidation = $params['graphvalidation'];
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['graphname'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-graphname',
+ ];
+
+ $params['rankdir'] = [
+ 'default' => 'TB',
+ 'message' => 'srf-paramdesc-rankdir',
+ ];
+
+ $params['graphsize'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-graphsize',
+ ];
+
+ $params['clustercolor'] = [
+ 'default' => 'lightgrey',
+ 'message' => 'srf-paramdesc-clustercolor',
+ ];
+
+ $params['highlight'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-highlight',
+ ];
+
+ $params['highlightcolor'] = [
+ 'default' => 'blue',
+ 'message' => 'srf-paramdesc-highlightcolor',
+ ];
+
+ $params['redlinkcolor'] = [
+ 'default' => 'red',
+ 'message' => 'srf-paramdesc-redlinkcolor',
+ ];
+
+ $params['processcat'] = [
+ 'default' => 'Process',
+ 'message' => 'srf-paramdesc-processcategory',
+ ];
+
+ $params['showroles'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-showroles',
+ ];
+
+ $params['showstatus'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-showstatus',
+ ];
+
+ $params['showresources'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-showresources',
+ ];
+
+ $params['showdiscussion'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-showdiscussion',
+ ];
+
+ $params['showredlinks'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-showredlinks',
+ ];
+
+ $params['showcompound'] = [
+ 'type' => 'boolean',
+ 'default' => true,
+ 'message' => 'srf-paramdesc-showcompound',
+ ];
+
+ $params['debug'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-debug',
+ ];
+
+ $params['graphvalidation'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graphvalidation',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * This method renders the result set provided by SMW according to the printer
+ *
+ * @param res SMWQueryResult, result set of the ask query provided by SMW
+ * @param outputmode ?
+ *
+ * @return String, rendered HTML output of this printer for the ask-query
+ *
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ if ( !is_callable( 'renderGraphviz' ) ) {
+ wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' );
+ return '';
+ }
+
+ global $wgContLang; // content language object
+
+ //
+ // GraphViz settings
+ //
+ $this->isHTML = true;
+
+ //
+ // Iterate all rows in result set
+ //
+
+ $row = $res->getNext(); // get initial row (i.e. array of SMWResultArray)
+
+ while ( $row !== false ) {
+ /* SMWDataItem */
+ $subject = $row[0]->getResultSubject(); // get Subject of the Result
+ // creates a new node if $val has type wikipage
+ if ( $subject->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
+ $wikiPageValue = new SMWWikiPageValue( '_wpg' );
+ $wikiPageValue->setDataItem( $subject );
+ $node = $this->m_process->makeNode(
+ $wikiPageValue->getShortWikiText(),
+ $wikiPageValue->getShortWikiText()
+ );
+ }
+
+ //
+ // Iterate all colums of the row (which describe properties of the proces node)
+ //
+
+ // FIXME: this does not work with SMW >= 1.6, see
+ // https://bugzilla.wikimedia.org/show_bug.cgi?id=35003
+
+ // FIXME: got _a bit_ of redundancy here looks like... :/
+
+ /**
+ * @var SMWResultArray $field
+ */
+ foreach ( $row as $field ) {
+
+ // check column title
+ $req = $field->getPrintRequest();
+ switch ( ( strtolower( $req->getLabel() ) ) ) {
+
+ case strtolower( $wgContLang->getNsText( NS_CATEGORY ) ):
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( '_wpg' );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ if ( $val == ( $wgContLang->getNsText( NS_CATEGORY ) . ':' . $this->m_processCategory ) ) {
+ $node->setAtomic( false );
+ }
+ }
+
+ break;
+
+ case "haslabel":
+ $value = current( $field->getContent() ); // save only the first
+
+ if ( ( $value !== false ) ) {
+ $wikiPageValue = new SMWWikiPageValue( '_wpg' );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getLongWikiText();
+
+ if ( $this->m_process->getUseOtherLabels() ) {
+ $val = str_replace( "&", "and", $val );
+ $node->setLabel( $val );
+ }
+ }
+ break;
+
+ case "hasrole":
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $role = $this->m_process->makeRole( $val, $val );
+ $node->addRole( $role );
+ }
+ break;
+
+ case "usesresource":
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $xres = $this->m_process->makeRessource( $val, $val );
+ $node->addUsedRessource( $xres );
+ }
+ break;
+
+ case "producesresource":
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $xres = $this->m_process->makeRessource( $val, $val );
+ $node->addProducedRessource( $xres );
+ }
+ break;
+
+ case "hassuccessor":
+
+ if ( count( $field->getContent() ) > 1 ) {
+
+ // SplitParallel
+ $edge = new SplitParallelEdge();
+ $edge->setFrom( $node );
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $edge->addTo( $this->m_process->makeNode( $val, $val ) );
+ }
+
+ } else {
+
+ // Sequence
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $edge = new SequentialEdge();
+ $edge->setFrom( $node );
+ $edge->setTo( $this->m_process->makeNode( $val, $val ) );
+ }
+ }
+
+ break;
+
+ case "hasorsuccessor":
+
+ if ( count( $field->getContent() ) > 0 ) {
+
+ // SplitExclusiveOr
+ $edge = new SplitExclusiveOrEdge();
+ $edge->setFrom( $node );
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $edge->addTo( $this->m_process->makeNode( $val, $val ) );
+ }
+ }
+
+ break;
+
+ case "hascontruesuccessor":
+
+ if ( count( $field->getContent() ) > 0 ) {
+
+ // SplitConditional
+ if ( !isset( $cond_edge ) ) {
+ $cond_edge = new SplitConditionalOrEdge();
+ $cond_edge->setFrom( $node );
+ }
+
+ // should be only one
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $cond_edge->setToTrue( $this->m_process->makeNode( $val, $val ) );
+ }
+
+ }
+
+ break;
+
+ case "hasconfalsesuccessor":
+
+ if ( count( $field->getContent() ) > 0 ) {
+
+ // SplitConditional
+ if ( !isset( $cond_edge ) ) {
+ $cond_edge = new SplitConditionalOrEdge();
+ $cond_edge->setFrom( $node );
+ }
+
+ // should be only one
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $cond_edge->setToFalse( $this->m_process->makeNode( $val, $val ) );
+ }
+ }
+
+ break;
+
+ case "hascondition":
+
+ if ( count( $field->getContent() ) > 0 ) {
+
+ // SplitConditional
+ if ( !isset( $cond_edge ) ) {
+ $cond_edge = new SplitConditionalOrEdge();
+ $cond_edge->setFrom( $node );
+ }
+
+ // should be only one
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $cond_edge->setConditionText( $val );
+
+ }
+ }
+
+ break;
+
+ case "hasstatus":
+
+ // should be only one
+ foreach ( $field->getContent() as $value ) {
+ $wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() );
+ $wikiPageValue->setDataItem( $value );
+ $val = $wikiPageValue->getShortWikiText();
+
+ $node->setStatus( $val );
+ }
+
+ break;
+
+ default:
+
+ // TODO - redundant column in result
+
+ }
+ }
+
+ // reset row variables
+ unset( $node );
+ unset( $cond_edge );
+
+ $row = $res->getNext(); // switch to next row
+ }
+
+ //
+ // generate graphInput
+ //
+ $graphInput = $this->m_process->getGraphVizCode();
+
+ //
+ // render graphViz code
+ //
+ $result = renderGraphviz( $graphInput );
+
+ $debug = '';
+ if ( $this->m_isDebugSet ) {
+ $debug = '<pre>' . $graphInput . '</pre>';
+ }
+
+ return $result . $debug;
+ }
+}
+
+/**
+ * Class representing a process graph
+ */
+class ProcessGraph {
+
+ // configuration variables
+ protected $m_graphName = '';
+ protected $m_rankdir = 'TB';
+ protected $m_graphSize = '';
+ protected $m_clusterColor = 'lightgrey';
+ protected $m_showStatus = false; // should status be rendered?
+ protected $m_showRoles = false; // should roles be rendered?
+ protected $m_showRessources = false; // should ressources be rendered?
+ protected $m_showDiscussion = false; // should discussion be rendered?
+ protected $m_highlightNode = ''; // node to be highlighted
+ protected $m_highlightColor = 'blue'; // highlight font color
+ protected $m_showRedLinks = false; // check and highlight red links?
+ protected $m_redLinkColor = 'red'; // red link font color
+ protected $m_showCompound = true; // highlight compound nodes (=subprocesses)
+
+ public $m_useHtmlNodes = true; // Set to false if you do not want to use HTML table nodes
+
+ // instance variables
+ protected $m_nodes = []; // list of all nodes
+ protected $m_startnodes = []; // list of start nodes
+ protected $m_endnodes = []; // list of end nodes
+ protected $m_ressources = []; // list of ressources
+ protected $m_roles = []; // list of roles
+ protected $m_errors = []; // list of errors
+
+ /**
+ * This method should be used for getting new or existing nodes
+ * If a node does not exist yet, it will be created
+ *
+ * @param $id string, node id
+ * @param $label string, node label
+ *
+ * @return Object of type ProcessNode
+ */
+ public function makeNode( $id, $label ) {
+ // check if node exists
+ if ( isset( $this->m_nodes[$id] ) ) {
+ // take existing node
+ $node = $this->m_nodes[$id];
+
+ } else {
+ // create new node
+
+ $node = new ProcessNode();
+ $node->setId( $id );
+ $node->setLabel( $label );
+ $node->setProcess( $this );
+
+ // is actual node name the same like the one to highlight?
+ if ( strcasecmp( $id, $this->m_highlightNode ) == 0 ) {
+ $node->setFontColor( $this->m_highlightColor );
+ }
+
+ // is the node a red link (i.e. corresponding wiki page does not yet exist)?
+ if ( $this->m_showRedLinks ) {
+ $title = Title::newFromDBkey( $id );
+ if ( isset( $title ) && ( !$title->exists() ) ) {
+ $node->setFontColor( $this->m_redLinkColor );
+ }
+ }
+
+ // add new node to process
+ $this->m_nodes[$id] = $node;
+ }
+
+ return $node;
+
+ }
+
+ public function makeRole( $id, $label ) {
+ // check if role exists
+ if ( isset( $this->m_roles[$id] ) ) {
+ // take existing roles
+ $role = $this->m_roles[$id];
+
+ } else {
+ $role = new ProcessRole();
+ $role->setId( $id );
+ $role->setLabel( $label );
+
+ // add new role to process
+ $this->m_roles[$id] = $role;
+ }
+
+ return $role;
+
+ }
+
+ public function makeRessource( $id, $label ) {
+ // check if res exists
+ if ( isset( $this->m_ressources[$id] ) ) {
+ // take existing res
+ $res = $this->m_ressources[$id];
+
+ } else {
+ $res = new ProcessRessource();
+ $res->setId( $id );
+ $res->setLabel( $label );
+
+ // add new res to process
+ $this->m_ressources[$id] = $res;
+
+ }
+
+ return $res;
+
+ }
+
+ public function getEndNodes() {
+ if ( count( $this->m_endnodes ) == 0 ) {
+ foreach ( $this->m_nodes as $node ) {
+ if ( count( $node->getSucc() ) == 0 ) {
+ $this->m_endnodes[] = $node;
+ }
+ }
+ }
+
+ return $this->m_endnodes;
+ }
+
+ public function getStartNodes() {
+
+ if ( count( $this->m_startnodes ) == 0 ) {
+ foreach ( $this->m_nodes as $node ) {
+ if ( count( $node->getPred() ) == 0 ) {
+ $this->m_startnodes[] = $node;
+ }
+ }
+ }
+
+ return $this->m_startnodes;
+ }
+
+ public function setShowStatus( $show ) {
+ $this->m_showStatus = $show;
+ }
+
+ public function getShowStatus() {
+ return $this->m_showStatus;
+ }
+
+ public function setShowRoles( $show ) {
+ $this->m_showRoles = $show;
+ }
+
+ public function getShowRoles() {
+ return $this->m_showRoles;
+ }
+
+ public function setShowCompound( $show ) {
+ $this->m_showCompound = $show;
+ }
+
+ public function getShowCompound() {
+ return $this->m_showCompound;
+ }
+
+ public function setShowDiscussion( $show ) {
+ $this->m_showDiscussion = $show;
+ }
+
+ public function getShowDiscussion() {
+ return $this->m_showDiscussion;
+ }
+
+ public function setShowRessources( $show ) {
+ $this->m_showRessources = $show;
+ }
+
+ public function getShowRessources() {
+ return $this->m_showRessources;
+ }
+
+ public function setGraphName( $name ) {
+ $this->m_graphName = $name;
+ }
+
+ public function getGraphName() {
+ if ( $this->m_graphName == '' ) {
+ $this->m_graphName = 'ProcessQueryResult' . rand( 1, 99999 );
+ }
+ return $this->m_graphName;
+ }
+
+ public function setGraphSize( $size ) {
+ $this->m_graphSize = $size;
+ }
+
+ public function setRankdir( $rankdir ) {
+ $this->m_rankdir = $rankdir;
+ }
+
+ public function setClusterColor( $color ) {
+ $this->m_clusterColor = $color;
+ }
+
+ public function setHighlightColor( $color ) {
+ $this->m_highlightColor = $color;
+ }
+
+ public function setRedLinkColor( $color ) {
+ $this->m_redLinkColor = $color;
+ }
+
+ public function setShowRedLinks( $show ) {
+ $this->m_showRedLinks = $show;
+ }
+
+ public function setHighlightNode( $name ) {
+ $this->m_highlightNode = $name;
+ }
+
+ public function addError( $error ) {
+ $this->m_errors[] = $error;
+ }
+
+ public function getErrors() {
+ return $this->m_errors;
+ }
+
+ public function getGraphVizCode() {
+ //
+ // header
+ //
+ $res = 'digraph ' . $this->getGraphName() . ' {
+
+ ranksep="0.5";';
+ if ( $this->m_graphSize != '' ) {
+ $res .= '
+ size="' . $this->m_graphSize . '";';
+ }
+ $res .= '
+ rankdir=' . $this->m_rankdir . ';
+ ';
+
+ //
+ // add startnodes
+ //
+ // TODO I18N
+ $res .= '
+ {rank=source; "Start";}
+ "Start"[shape=box,label="Start",style=filled,color=green];';
+
+ foreach ( $this->getStartNodes() as $node ) {
+ $res .= '
+ "Start" -> "' . $node->getId() . '":port1:n;';
+ }
+
+ $res .= '
+ ';
+
+ //
+ // add endnodes
+ //
+ // TODO I18N
+ $res .= '
+ {rank=sink; "End"; }
+ "End"[shape=box,label="End",style=filled,color=green];';
+
+ foreach ( $this->getEndNodes() as $node ) {
+ $res .= '
+ "' . $node->getId() . '":port1:s -> "End";';
+ }
+
+ $res .= '
+
+ ';
+
+ //
+ // add subnodes
+ //
+ foreach ( $this->m_nodes as $node ) {
+ $res .= $node->getGraphVizCode();
+ }
+
+ //
+ // add final stuff
+ //
+ $res .=
+ '
+ }';
+
+ return $res;
+
+ }
+
+}
+
+abstract class ProcessElement {
+
+ // TODO I18N
+ private $m_id = 'no_id';
+ private $m_label = 'unlabeled';
+ private $m_uid;
+
+ public function getUUID() {
+ if ( !isset( $this->m_uid ) ) {
+ $this->m_uid = sprintf(
+ '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0x0fff ) | 0x4000,
+ mt_rand( 0, 0x3fff ) | 0x8000,
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff )
+ );
+ }
+
+ return $this->m_uid;
+ }
+
+ public function getId() {
+ return $this->m_id;
+ }
+
+ public function setId( $id ) {
+ $this->m_id = $id;
+ }
+
+ public function getLabel() {
+ return $this->m_label;
+ }
+
+ public function setLabel( $label ) {
+ $this->m_label = $label;
+ }
+
+}
+
+class ProcessRessource extends ProcessElement {
+
+ private $m_usedby = [];
+ private $m_producedby = [];
+
+ public function getProducers() {
+ return $this->m_producedby;
+ }
+
+ public function getUsers() {
+ return $this->m_usedby;
+ }
+
+ public function addProducer( $node ) {
+ $this->m_producedby[] = $node;
+ }
+
+ public function addUser( $node ) {
+ $this->m_usedby[] = $node;
+ }
+
+}
+
+class ProcessRole extends ProcessElement {
+
+ private $m_nodes = [];
+
+ public function getNodes() {
+ return $this->m_nodes;
+ }
+
+ public function addNode( $node ) {
+ $this->m_nodes[] = $node;
+ }
+
+}
+
+class ProcessNode extends ProcessElement {
+
+ private $m_status; // status value
+ private $m_is_atomic = true; // set false if this is a compound node
+
+ private $m_process; // reference to parent process
+
+ private $m_fontColor = ''; // font color to render
+
+ private $m_usedressources = []; // ressources used by this node
+ private $m_producedressources = []; // ressources produces by this node
+ private $m_roles = []; // roles related to this node
+
+ private $m_edgeout; // outgoing edge (can be only one)
+ private $m_edgesin = []; // incoming edges (can be many)
+
+ public function setStatus( $status ) {
+ $this->m_status = $status;
+ }
+
+ public function getStatus() {
+ return $this->m_status;
+ }
+
+ public function setFontColor( $color ) {
+ $this->m_fontColor = $color;
+ }
+
+ public function setProcess( $proc ) {
+ $this->m_process = $proc;
+ }
+
+ public function getProcess() {
+ return $this->m_process;
+ }
+
+ public function getPred() {
+ $res = [];
+
+ foreach ( $this->m_edgesin as $edge ) {
+ $res = array_merge( $res, $edge->getPred() );
+ }
+
+ return $res;
+ }
+
+ public function getSucc() {
+ $res = [];
+
+ if ( isset( $this->m_edgeout ) ) {
+ $res = $this->m_edgeout->getSucc();
+ }
+
+ return $res;
+ }
+
+ public function setEdgeOut( $edge ) {
+ $this->m_edgeout = $edge;
+ }
+
+ public function getEdgeOut() {
+ return $this->m_edgeout;
+ }
+
+ public function addEdgeIn( $edge ) {
+ $this->m_edgesin[] = $edge;
+ }
+
+ public function getEdgesIn() {
+ return $this->m_edgesin;
+ }
+
+ public function addRole( $role ) {
+ $this->m_roles[] = $role;
+ $role->addNode( $this );
+ }
+
+ public function getRoles() {
+ return $this->m_roles;
+ }
+
+ public function addUsedRessource( $res ) {
+ $this->m_usedressources[] = $res;
+ $res->addUser( $this );
+ }
+
+ public function getUsedRessources() {
+ return $this->m_usedressources;
+ }
+
+ public function addProducedRessource( $res ) {
+ $this->m_producedressources[] = $res;
+ $res->addProducer( $this );
+ }
+
+ public function getProducedRessources() {
+ return $this->m_producedressources;
+ }
+
+ public function isAtomic() {
+ return $this->m_is_atomic;
+ }
+
+ public function setAtomic( $atomic ) {
+ $this->m_is_atomic = $atomic;
+ }
+
+ public function getGraphVizCode() {
+ global $IP, $srfgPicturePath, $srfgIP;
+ //
+ // show node status
+ //
+ $status = '';
+ if ( $this->getProcess()->getShowStatus() ) {
+
+ if ( file_exists( $IP . "/images/p000.png" ) ) {
+ $PicturePath = $IP . "/images/";
+ } elseif ( file_exists( $srfgIP . "/formats/graphviz/images/p000.png" ) ) {
+ $PicturePath = $srfgIP . "/formats/graphviz/images/";
+ } else {
+ $PicturePath = $IP . $srfgPicturePath;
+ }
+ // $color = 'grey' . $this->getStatus();
+ // $color = 'grey' . rand(1, 100);
+ // $status = ',style=filled,color=' . $color;
+ if ( $this->getStatus() != '' ) {
+ if ( $this->getStatus() < 25 ) {
+ $status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus(
+ ) . '%"><IMG SRC="' . $PicturePath . 'p000.png" /';
+ } elseif ( $this->getStatus() < 50 ) {
+ $status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus(
+ ) . '%"><IMG SRC="' . $PicturePath . 'p025.png" /';
+ } elseif ( $this->getStatus() < 75 ) {
+ $status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus(
+ ) . '%"><IMG SRC="' . $PicturePath . 'p050.png" /';
+ } elseif ( $this->getStatus() < 100 ) {
+ $status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus(
+ ) . '%"><IMG SRC="' . $PicturePath . 'p075.png" /';
+ } elseif ( $this->getStatus() == 100 ) {
+ $status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus(
+ ) . '%"><IMG SRC="' . $PicturePath . 'p100.png" /';
+ }
+ }
+
+ }
+
+ //
+ // show discussion page
+ //
+ $discussion = '';
+ if ( $this->getProcess()->getShowDiscussion() ) {
+
+ if ( file_exists( $IP . "/images/discuss_icon.png" ) ) {
+ $PicturePath = $IP . "/images/";
+ } elseif ( file_exists( $srfgIP . "/formats/graphviz/images/discuss_icon.png" ) ) {
+ $PicturePath = $srfgIP . "/formats/graphviz/images/";
+ } else {
+ $PicturePath = $IP . $srfgPicturePath;
+ }
+ $discussionTitle = Title::newFromText( 'Talk:' . $this->getId() . '' );
+ if ( $discussionTitle->isKnown() ) {
+ $discussion = ' HREF="[[Talk:' . $this->getId() . ']]" TOOLTIP="Talk:' . $this->getId(
+ ) . '"><IMG SRC="' . $PicturePath . 'discuss_icon.png" /';
+ } else {
+ $discussion = ' HREF="[[Talk:' . $this->getId() . ']]" TOOLTIP="Talk:' . $this->getId(
+ ) . '"><IMG SRC="' . $PicturePath . 'discuss_icon_grey.png" /';
+ }
+
+ }
+
+ // use highlight color if set (either CURRENTPAGE or REDLINK highlighting - see ProcessGraph::makeNode()
+ $high = '';
+ if ( $this->m_fontColor !== '' ) {
+ $high = ',fontcolor=' . $this->m_fontColor;
+ }
+
+ // insert icon for non-atomic nodes (i.e. subprocesses)
+ $compound = '<TR><TD ALIGN="LEFT" BORDER="0" WIDTH="20px">';
+ if ( $this->getProcess()->getShowCompound() ) {
+ if ( file_exists( $IP . "/images/subprocess.png" ) ) {
+ $PicturePath = $IP . "/images/";
+ } elseif ( file_exists( $srfgIP . "/formats/graphviz/images/subprocess.png" ) ) {
+ $PicturePath = $srfgIP . "/formats/graphviz/images/";
+ } else {
+ $PicturePath = $IP . $srfgPicturePath;
+ }
+ if ( !$this->isAtomic() ) {
+ $compound = '<TR><TD ALIGN="LEFT" BORDER="0" WIDTH="20px" HREF="[[' . $this->getId(
+ ) . ']]" TOOLTIP="sub process"><IMG SRC="' . $PicturePath . 'subprocess.png"/>';
+ }
+ }
+
+ //
+ // render node itself
+ //
+ if ( $this->m_process->m_useHtmlNodes ) {
+ $res =
+ '"' . $this->getId(
+ ) . '" [shape=plaintext,label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">' . $compound . '</TD><TD BORDER="0" WIDTH="80%"></TD><TD ALIGN="RIGHT" BORDER="0" WIDTH="20px"' . $status . '></TD><TD ALIGN="RIGHT" BORDER="0" WIDTH="20px"' . $discussion . '></TD></TR><TR><TD COLSPAN="4" PORT="port1" HREF="[[' . $this->getId(
+ ) . ']]" TOOLTIP="' . $this->getLabel() . '"><FONT' . $high . '>' . $this->getLabel() . '</FONT></TD> </TR></TABLE>>];
+ ';
+ } else {
+ $res =
+ '"' . $this->getId() . '"[label="' . $this->getLabel(
+ ) . '",shape=rect, height=1.5, URL="[[' . $this->getId() . ']]"];
+ ';
+ }
+
+ //
+ // render outgoing node
+ //
+ if ( isset( $this->m_edgeout ) ) {
+ $res .= $this->m_edgeout->getGraphVizCode();
+ }
+
+ //
+ // show cluster for roles and ressources
+ //
+ $rrcluster = false;
+ $rrcode = 'subgraph "cluster_role' . rand( 1, 9999 ) . '" { style=filled;color=lightgrey;';
+
+ // show roles
+ if ( $this->getProcess()->getShowRoles() ) {
+
+ foreach ( $this->getRoles() as $role ) {
+ $rrcluster = true;
+ $rrcode .= '
+ "' . $role->getId() . '"[label="' . $role->getLabel(
+ ) . '",shape=doubleoctagon, color=red, URL="[[' . $role->getId() . ']]"];
+ "' . $role->getId() . '" -> "' . $this->getId() . '":port1 [color=red,arrowhead = none,constraint=false];
+ ';
+
+ }
+ }
+
+ if ( $this->getProcess()->getShowRessources() ) {
+
+ foreach ( $this->getUsedRessources() as $xres ) {
+ $rrcluster = true;
+ $rrcode .= '
+ "' . $xres->getId() . '"[label="' . $xres->getLabel(
+ ) . '",shape=folder, color=blue, URL="[[' . $xres->getId() . ']]"];
+ "' . $xres->getId() . '" -> "' . $this->getId() . '":port1 [color=blue,constraint=false];
+ ';
+ }
+
+ foreach ( $this->getProducedRessources() as $xres ) {
+ $rrcluster = true;
+ $rrcode .= '
+ "' . $xres->getId() . '"[label="' . $xres->getLabel(
+ ) . '",shape=folder, color=blue, URL="[[' . $xres->getId() . ']]"];
+ "' . $this->getId() . '":port1 -> "' . $xres->getId() . '" [color=blue,constraint=false];
+ ';
+ }
+
+ }
+
+ if ( $rrcluster ) {
+ $res .= $rrcode . '}';
+ }
+
+ $res .= '
+ ';
+
+ return $res;
+ }
+
+}
+
+/**
+ * Abstract base class for edges in a process graph
+ */
+abstract class ProcessEdge {
+
+ private $m_id;
+ private $m_uid;
+
+ public function getId() {
+ if ( !isset( $this->m_id ) ) {
+ $this->m_id = 'edge' . rand( 1, 99999 );
+ }
+
+ return $this->m_id;
+ }
+
+ public function getUUID() {
+ if ( !isset( $this->m_uid ) ) {
+ $this->m_uid = sprintf(
+ '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0x0fff ) | 0x4000,
+ mt_rand( 0, 0x3fff ) | 0x8000,
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff ),
+ mt_rand( 0, 0xffff )
+ );
+ }
+
+ return $this->m_uid;
+ }
+
+ abstract public function getSucc();
+
+ abstract public function getPred();
+
+ abstract public function getGraphVizCode();
+}
+
+abstract class SplitEdge extends ProcessEdge {
+
+ protected $m_from;
+ protected $m_to = [];
+
+ public function setFrom( $node ) {
+ $this->m_from = $node;
+ $node->setEdgeOut( $this );
+ }
+
+ public function addTo( $node ) {
+ $this->m_to[] = $node;
+ $node->addEdgeIn( $this );
+ }
+
+ public function getPred() {
+ return [ $this->m_from ];
+ }
+
+ public function getSucc() {
+ return $this->m_to;
+ }
+
+}
+
+class SplitConditionalOrEdge extends ProcessEdge {
+
+ protected $m_from;
+ protected $m_to_true;
+ protected $m_to_false;
+ protected $m_con_text = 'empty_condition';
+
+ public function getSucc() {
+ return [ $this->m_to_false, $this->m_to_true ];
+ }
+
+ public function getPred() {
+ return [ $this->m_from ];
+ }
+
+ public function setFrom( $node ) {
+ $this->m_from = $node;
+ $node->setEdgeOut( $this );
+ }
+
+ public function setToFalse( $node ) {
+ $this->m_to_false = $node;
+ $node->addEdgeIn( $this );
+ }
+
+ public function setToTrue( $node ) {
+ $this->m_to_true = $node;
+ $node->addEdgeIn( $this );
+ }
+
+ public function setConditionText( $cond ) {
+ $this->m_con_text = $cond;
+ }
+
+ public function getGraphVizCode() {
+
+ $p = $this->m_from;
+
+ if ( ( !isset( $this->m_from ) ) || ( !isset( $this->m_to_false ) ) || ( !isset( $this->m_to_true ) ) ) {
+
+ echo "error with SplitConditionalOrEdge"; // TODO
+ exit;
+ }
+
+ $res =
+ 'subgraph "clus_' . $this->getId() . '" {
+ ';
+
+ // cond-Shape
+ $con = 'con' . rand( 1, 99999 );
+ $res .=
+ '"' . $con . '"[shape=diamond,label="' . $this->m_con_text . '",style=filled,color=skyblue];
+ "' . $p->getId() . '":port1:s -> "' . $con . '";
+ ';
+
+ // True Succ
+ $res .=
+ '"' . $this->m_to_true->getId() . '" [URL = "[[' . $this->m_to_true->getId() . ']]"];
+ ';
+
+ $res .=
+ '"' . $con . '" -> "' . $this->m_to_true->getId() . '":port1:n [label="true"];
+ ';
+
+ // False Succ
+ $res .=
+ '"' . $this->m_to_false->getId() . '" [URL = "[[' . $this->m_to_false->getId() . ']]"];
+ ';
+
+ $res .=
+ '"' . $con . '" -> "' . $this->m_to_false->getId() . '":port1:n [label="false"];';
+
+ $res .= '
+ }
+ ';
+
+ return $res;
+ }
+
+}
+
+class SplitExclusiveOrEdge extends SplitEdge {
+
+ public function getGraphVizCode() {
+ global $srfgShapeStyle;
+ $p = $this->getPred();
+ $p = $p[0];
+ if ( $srfgShapeStyle == '' ) {
+ $srfgShapeStyle = "box";
+ }
+ $res =
+ 'subgraph "clus_' . $this->getId() . '" {
+ ';
+
+ // add OR-Shape
+ $orx = 'or' . rand( 1, 99999 );
+ $res .=
+ '"' . $orx . '"[shape=' . $srfgShapeStyle . ',label="+",style=filled,color=gold];
+ "' . $p->getId() . '":port1:s -> "' . $orx . '";
+ ';
+
+ foreach ( $this->getSucc() as $s ) {
+ $res .=
+ '"' . $s->getId() . '" [URL="[[' . $s->getId() . ']]"];
+ ';
+
+ $res .=
+ '"' . $orx . '" -> "' . $s->getId() . '":port1:n;
+ ';
+ }
+
+ $res .= '
+ }
+ ';
+
+ return $res;
+ }
+
+}
+
+class SplitParallelEdge extends SplitEdge {
+
+ public function getGraphVizCode() {
+ global $srfgShapeStyle;
+ if ( $srfgShapeStyle == '' ) {
+ $srfgShapeStyle = "box";
+ }
+ $p = $this->getPred();
+ $p = $p[0];
+
+ $res =
+ 'subgraph "clus_' . $this->getId() . '" {
+ ';
+
+ // add AND-Shape
+ $and = 'and' . rand( 1, 99999 );
+ $res .=
+ '"' . $and . '"[shape=' . $srfgShapeStyle . ',label="||",style=filled,color=palegreen];
+ "' . $p->getId() . '":port1:s -> "' . $and . '";
+ ';
+
+ foreach ( $this->getSucc() as $s ) {
+ $res .=
+ '"' . $s->getId() . '" [URL = "[[' . $s->getId() . ']]"];
+ ';
+
+ $res .=
+ '"' . $and . '" -> "' . $s->getId() . '":port1:n;
+ ';
+ }
+
+ $res .= '
+ }
+ ';
+
+ return $res;
+ }
+
+}
+
+class SequentialEdge extends ProcessEdge {
+
+ private $m_from;
+ private $m_to;
+
+ public function setFrom( $node ) {
+ $this->m_from = $node;
+ $node->setEdgeOut( $this );
+ }
+
+ public function setTo( $node ) {
+ $this->m_to = $node;
+ $node->addEdgeIn( $this );
+ }
+
+ public function getPred() {
+ return [ $this->m_from ];
+ }
+
+ public function getSucc() {
+ return [ $this->m_to ];
+ }
+
+ public function getGraphVizCode() {
+
+ $p = $this->m_from;
+ $s = $this->m_to;
+
+ $res =
+ 'subgraph "clus_' . $this->getId() . '" {
+ ';
+
+ $res .=
+ '"' . $s->getId() . '" [URL = "[[' . $s->getId() . ']]"];
+ ';
+
+ $res .=
+ '"' . $p->getId() . '":port1:s -> "' . $s->getId() . '":port1:n;';
+
+ $res .= '
+ }
+ ';
+
+ return $res;
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/detail_icon.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/detail_icon.png
new file mode 100644
index 00000000..7ba87b9b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/detail_icon.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon.png
new file mode 100644
index 00000000..89085a35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon_grey.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon_grey.png
new file mode 100644
index 00000000..b7973447
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/discuss_icon_grey.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p000.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p000.png
new file mode 100644
index 00000000..60ebd416
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p000.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p025.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p025.png
new file mode 100644
index 00000000..f2fc0de6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p025.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p050.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p050.png
new file mode 100644
index 00000000..4d4cfaa2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p050.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p075.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p075.png
new file mode 100644
index 00000000..378a8e4b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p075.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p100.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p100.png
new file mode 100644
index 00000000..cc3f743b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/p100.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/subprocess.png b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/subprocess.png
new file mode 100644
index 00000000..9cb25b2d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/graphviz/images/subprocess.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/incoming/SRF_Incoming.php b/www/wiki/extensions/SemanticResultFormats/formats/incoming/SRF_Incoming.php
new file mode 100644
index 00000000..3d686943
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/incoming/SRF_Incoming.php
@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * @brief Find incoming properties to a result set
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ *
+ * @ingroup SemanticResultFormats
+ * @file SRF_Incoming.php
+ */
+class SRFIncoming extends SMWResultPrinter {
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-incoming' )->text();
+ }
+
+ /**
+ * Returns an array with an enhanced data set retrieved from the query result.
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputmode ) {
+ $data = $this->getResultData( $result, $outputmode );
+
+ // Bailout if we have no results
+ if ( $data === [] ) {
+ if ( $this->params['default'] !== '' ) {
+ return $this->escapeText( $this->params['default'], $outputmode );
+ } else {
+ $result->addErrors( [ wfMessage( 'smw_result_noresults' )->inContentLanguage()->text() ] );
+ return '';
+ }
+ } else {
+ return $this->getFormatOutput( $data );
+ }
+ }
+
+ /**
+ * Return relevant data set
+ *
+ * @param SMWQueryResult $res
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultData( SMWQueryResult $res, $outputMode ) {
+ // Init
+ $properties = [];
+ $excludeProperties = explode( $this->params['sep'], $this->params['exclude'] );
+
+ // Options used when retrieving data from the store
+ $reqOptions = new SMWRequestOptions();
+ $reqOptions->sort = true;
+ $reqOptions->limit = $this->params['limit'];
+
+ foreach ( $res->getResults() as $key => $page ) {
+
+ // Find properties assigned to selected subject page
+ foreach ( $res->getStore()->getInProperties( $page, $reqOptions ) as $property ) {
+
+ $propertyLabel = $property->getLabel();
+
+ // Exclude property from result set
+ if ( in_array( $propertyLabel, $excludeProperties ) ) {
+ continue;
+ }
+
+ // NOTE There could be thousands of incoming links for one property,
+ // counting the length of an array is inefficient but we don't want
+ // to implement any native db select outside of smw core and rather
+ // would like to see a counting method available but to counter
+ // any potential inefficiencies we curb the selection by using
+ // SMWRequestOptions -> limit as boundary
+ $count = count( $res->getStore()->getPropertySubjects( $property, $page, $reqOptions ) );
+
+ // Limit ouput by threshold
+ if ( $this->params['min'] <= $count ) {
+ $properties[$propertyLabel] = $count;
+ }
+ }
+ }
+
+ return $properties;
+ }
+
+ /**
+ * Create a template output
+ *
+ * @since 1.8
+ *
+ * @param $label
+ * @param $count
+ * @param $rownum
+ * @param $result
+ */
+ protected function initTemplateOutput( $label, $count, &$rownum, &$result ) {
+ $rownum++;
+ $wikitext = $this->params['userparam'] ? "|userparam=" . $this->params['userparam'] : '';
+ $wikitext .= $this->params['count'] ? "|count=" . $count : '';
+ $wikitext .= $this->params['sep'] ? "|sep=" . $this->params['sep'] : '';
+ $wikitext .= "|" . $label;
+ $wikitext .= "|#=$rownum";
+ $result .= '{{' . trim( $this->params['template'] ) . $wikitext . '}}';
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ */
+ protected function getFormatOutput( array $data ) {
+ // Init
+ $result = '';
+
+ // Build the template output
+ if ( $this->params['template'] !== '' ) {
+ $this->hasTemplates = true;
+ foreach ( $data as $propLabel => $propCount ) {
+ $this->initTemplateOutput( $propLabel, $propCount, $rownum, $result );
+ }
+ } else {
+ // Plain list output
+ $result = implode( $this->params['sep'], array_keys( $data ) );
+ }
+
+ // Beautify class selector
+ $class = $this->params['template'] ? 'srf-incoming ' . str_replace(
+ " ",
+ "-",
+ $this->params['template']
+ ) : 'srf-incoming';
+
+ // Output
+ return Html::rawElement(
+ 'div',
+ [ 'class' => $class ],
+ $result
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['sep'] = [
+ 'message' => 'smw-paramdesc-sep',
+ 'default' => ',',
+ ];
+
+ $params['exclude'] = [
+ 'message' => 'srf-paramdesc-excludeproperty',
+ 'default' => '',
+ ];
+
+ $params['min'] = [
+ 'message' => 'srf-paramdesc-min',
+ 'default' => '',
+ ];
+
+ $params['template'] = [
+ 'message' => 'smw-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params['userparam'] = [
+ 'message' => 'smw-paramdesc-userparam',
+ 'default' => '',
+ ];
+
+ $params['count'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-count',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlot.php b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlot.php
new file mode 100644
index 00000000..7dbf406d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlot.php
@@ -0,0 +1,195 @@
+<?php
+
+/**
+ * Abstract class to hold common functionality for the jqPlot result printers.
+ *
+ * @since 1.8
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Yaron Koren
+ * @author Sanyam Goyal
+ */
+abstract class SRFjqPlot extends SMWAggregatablePrinter {
+
+ public static function getCommonParams() {
+
+ $params = [];
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-minvalue',
+ 'default' => false,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['direction'] = [
+ 'message' => 'srf-paramdesc-direction',
+ 'default' => 'vertical',
+ 'values' => [ 'horizontal', 'vertical' ],
+ ];
+
+ $params['charttitle'] = [
+ 'message' => 'srf_paramdesc_charttitle',
+ 'default' => '',
+ ];
+
+ $params['charttext'] = [
+ 'message' => 'srf-paramdesc-charttext',
+ 'default' => '',
+ ];
+
+ $params['numbersaxislabel'] = [
+ 'message' => 'srf_paramdesc_barnumbersaxislabel',
+ 'default' => '',
+ ];
+
+ $params['labelaxislabel'] = [
+ 'message' => 'srf-paramdesc-labelaxislabel',
+ 'default' => '',
+ ];
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_chartheight',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ // TODO: this is a string to allow for %, but better handling would be nice
+ $params['width'] = [
+ 'message' => 'srf_paramdesc_chartwidth',
+ 'default' => '100%',
+ ];
+
+ $params['smoothlines'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-smoothlines',
+ 'default' => false,
+ ];
+
+ // %.2f round number to 2 digits after decimal point e.g. EUR %.2f, $ %.2f
+ // %d a signed integer, in decimal
+ $params['valueformat'] = [
+ 'message' => 'srf-paramdesc-valueformat',
+ 'default' => '%d',
+ ];
+
+ $params['ticklabels'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-ticklabels',
+ 'default' => true,
+ ];
+
+ $params['highlighter'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-highlighter',
+ 'default' => false,
+ ];
+
+ $params['theme'] = [
+ 'message' => 'srf-paramdesc-theme',
+ 'default' => '',
+ 'values' => [ '', 'vector', 'simple' ],
+ ];
+
+ $params['filling'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-filling',
+ 'default' => true,
+ ];
+
+ $params['chartlegend'] = [
+ 'message' => 'srf-paramdesc-chartlegend',
+ 'default' => 'none',
+ 'values' => [ 'none', 'nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w' ],
+ ];
+
+ $params['datalabels'] = [
+ 'message' => 'srf-paramdesc-datalabels',
+ 'default' => 'none',
+ 'values' => [ 'none', 'value', 'label', 'percent' ],
+ ];
+
+ $params['colorscheme'] = [
+ 'message' => 'srf-paramdesc-colorscheme',
+ 'default' => '',
+ 'values' => $GLOBALS['srfgColorScheme'],
+ ];
+
+ $params['chartcolor'] = [
+ 'message' => 'srf-paramdesc-chartcolor',
+ 'default' => '',
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * Prepare jqplot specific numbers ticks
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ * @param $minValue
+ * @param $maxValue
+ *
+ * @return array
+ */
+ public static function getNumbersTicks( $minValue, $maxValue ) {
+ $numbersticks = [];
+
+ // Calculate the tick values for the numbers, based on the
+ // lowest and highest number. jqPlot has its own option for
+ // calculating ticks automatically - "autoscale" - but it
+ // currently (September 2010, it also fails with the jpPlot 1.00b 2012)
+ // fails for numbers less than 1, and negative numbers.
+ // If both max and min are 0, just escape now.
+ if ( $maxValue == 0 && $minValue == 0 ) {
+ return null;
+ }
+
+ // Make the max and min slightly larger and bigger than the
+ // actual max and min, so that the bars don't directly touch
+ // the top and bottom of the graph
+ if ( $maxValue > 0 ) {
+ $maxValue += .001;
+ }
+
+ if ( $minValue < 0 ) {
+ $minValue -= .001;
+ }
+
+ if ( $maxValue == 0 ) {
+ $multipleOf10 = 0;
+ $maxAxis = 0;
+ } else {
+ $multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
+ $maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
+ }
+
+ if ( $minValue == 0 ) {
+ $negativeMultipleOf10 = 0;
+ $minAxis = 0;
+ } else {
+ $negativeMultipleOf10 = -1 * pow( 10, floor( log( ( abs( $minValue ) ), 10 ) ) );
+ $minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
+ }
+
+ $biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
+ $lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
+ $highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
+
+ for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
+ $numbersticks[] = ( $i * $biggerMultipleOf10 );
+ }
+
+ return $numbersticks;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotChart.php b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotChart.php
new file mode 100644
index 00000000..cea8d784
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotChart.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * A query printer for bar, line, pie and donut chart on aggregated values
+ * using the jqPlot JavaScript library.
+ *
+ * @since 1.8
+ *
+ * @file SRF_jqPlotChart.php
+ * @ingroup SemanticResultFormats
+ * @licence GNU GPL v2 or later
+ *
+ * @author mwjames
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Yaron Koren
+ * @author Sanyam Goyal
+ */
+class SRFjqPlotChart extends SRFjqPlot {
+
+ /**
+ * Corresponding message name
+ *
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-jqplotchart' )->text();
+ }
+
+ /**
+ * Prepare data output
+ *
+ * @since 1.8
+ *
+ * @param array $data label => value
+ */
+ protected function getFormatOutput( array $data ) {
+
+ static $statNr = 0;
+ $chartID = 'jqplot-' . $this->params['charttype'] . '-' . ++$statNr;
+
+ $this->isHTML = true;
+
+ // Prepare data objects
+ if ( in_array( $this->params['charttype'], [ 'bar', 'line' ] ) ) {
+ // Parse bar relevant data
+ $dataObject = $this->prepareBarData( $data );
+ } elseif ( in_array( $this->params['charttype'], [ 'pie', 'donut' ] ) ) {
+ //Parse pie/donut relevant data
+ $dataObject = $this->preparePieData( $data );
+ } else {
+ // Return with an error
+ return Html::rawElement(
+ 'span',
+ [
+ 'class' => "error"
+ ],
+ wfMessage( 'srf-error-missing-layout' )->inContentLanguage()->text()
+ );
+ }
+
+ // Encode data objects
+ $requireHeadItem = [ $chartID => FormatJson::encode( $dataObject ) ];
+ SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // Processing placeholder
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // Ensure right conversion
+ $width = strstr( $this->params['width'], "%" ) ? $this->params['width'] : $this->params['width'] . 'px';
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [
+ 'id' => $chartID,
+ 'class' => 'container',
+ 'style' => "display:none; width: {$width}; height: {$this->params['height']}px;"
+ ],
+ null
+ );
+
+ // Beautify class selector
+ $class = $this->params['charttype'] ? '-' . $this->params['charttype'] : '';
+ $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class . ' jqplot-common';
+
+ // Chart/graph wrappper
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-jqplot' . $class,
+ ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * Prepare pie/donut chart specific data and parameters
+ *
+ * @since 1.8
+ *
+ * @param array $rawdata label => value
+ *
+ * @return array
+ */
+ private function preparePieData( $rawdata ) {
+
+ // Init
+ $mode = 'single';
+
+ // Reorganize the data in accordance with the pie chart req.
+ foreach ( $rawdata as $name => $value ) {
+ if ( $value >= $this->params['min'] ) {
+ $data[] = [ $name, $value ];
+ }
+ }
+
+ if ( $this->params['charttype'] === 'donut' ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.donut' );
+ } else {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.pie' );
+ }
+
+ return [
+ 'data' => [ $data ],
+ 'renderer' => $this->params['charttype'],
+ 'mode' => $mode,
+ 'parameters' => $this->addCommonOptions()
+ ];
+ }
+
+ /**
+ * Prepare bar/line chart specific data and parameters
+ *
+ * Data can be an array of y values, or an array of [label, value] pairs;
+ * While labels are used only on the first series with labels on
+ * subsequent series being ignored
+ *
+ * @since 1.8
+ *
+ * @param array $rawdata label => value
+ *
+ * @return array
+ */
+ private function prepareBarData( $rawdata ) {
+
+ // Init
+ $total = 0;
+ $mode = 'single';
+
+ // Find min and max values to determine the graphs axis parameter
+ $maxValue = count( $rawdata ) == 0 ? 0 : max( $rawdata );
+
+ if ( $this->params['min'] === false ) {
+ $minValue = count( $rawdata ) == 0 ? 0 : min( $rawdata );
+ } else {
+ $minValue = $this->params['min'];
+ }
+
+ // Get number ticks
+ $data['numbersticks'] = SRFjqPlot::getNumbersTicks( $minValue, $maxValue );
+
+ // Reorganize the data in accordance with the bar/line chart req.
+ foreach ( $rawdata as $key => $value ) {
+ if ( $value >= $this->params['min'] ) {
+ $data['series'][] = [ $key, $value ];
+ $total = $total + $value;
+ }
+ }
+
+ // Bar/line module
+ SMWOutputs::requireResource( 'ext.srf.jqplot.bar' );
+
+ // Highlighter plugin
+ if ( $this->params['highlighter'] ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.highlighter' );
+ }
+
+ // Pointlabels plugin
+ if ( in_array( $this->params['datalabels'], [ 'value', 'label', 'percent' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.pointlabels' );
+ }
+
+ return [
+ 'data' => [ $data['series'] ],
+ 'ticks' => $data['numbersticks'],
+ 'labels' => array_keys( $data['series'] ),
+ 'numbers' => array_values( $data['series'] ),
+ 'max' => $maxValue,
+ 'total' => $total,
+ 'mode' => $mode,
+ 'series' => [],
+ 'renderer' => $this->params['charttype'],
+ 'parameters' => $this->addCommonOptions()
+ ];
+ }
+
+ /**
+ * jqPlot common parameters
+ *
+ * @since 1.8
+ *
+ */
+ private function addCommonOptions() {
+
+ // Series colour
+ $seriescolors = $this->params['chartcolor'] !== '' ? array_filter(
+ explode( ",", $this->params['chartcolor'] )
+ ) : null;
+
+ return [
+ 'numbersaxislabel' => $this->params['numbersaxislabel'],
+ 'labelaxislabel' => $this->params['labelaxislabel'],
+ 'charttitle' => $this->params['charttitle'],
+ 'charttext' => $this->params['charttext'],
+ 'theme' => $this->params['theme'] ? $this->params['theme'] : null,
+ 'ticklabels' => $this->params['ticklabels'],
+ 'highlighter' => $this->params['highlighter'],
+ 'direction' => $this->params['direction'],
+ 'smoothlines' => $this->params['smoothlines'],
+ 'filling' => $this->params['filling'],
+ 'datalabels' => $this->params['datalabels'],
+ 'valueformat' => $this->params['valueformat'],
+ 'chartlegend' => $this->params['chartlegend'] !== '' ? $this->params['chartlegend'] : 'none',
+ 'colorscheme' => $this->params['colorscheme'] !== '' ? $this->params['colorscheme'] : null,
+ 'pointlabels' => $this->params['datalabels'] === 'none' ? false : $this->params['datalabels'],
+ 'grid' => $this->params['theme'] === 'vector' ? [ 'borderColor' => '#a7d7f9' ] : ( $this->params['theme'] === 'simple' ? [ 'borderColor' => '#ddd' ] : null ),
+ 'seriescolors' => $seriescolors
+ ];
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = self::getCommonParams();
+
+ $params['charttype'] = [
+ 'message' => 'srf-paramdesc-charttype',
+ 'default' => 'bar',
+ 'values' => [ 'bar', 'line', 'pie', 'donut' ],
+ ];
+
+ return array_merge( parent::getParamDefinitions( $definitions ), $params );
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotSeries.php b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotSeries.php
new file mode 100644
index 00000000..5ea59493
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/SRF_jqPlotSeries.php
@@ -0,0 +1,427 @@
+<?php
+
+/**
+ * A query printer for charts series using the jqPlot JavaScript library.
+ *
+ * @since 1.8
+ * @licence GNU GPL v2 or later
+ *
+ * @author mwjames
+ */
+class SRFjqPlotSeries extends SMWResultPrinter {
+
+ /**
+ * @see SMWResultPrinter::getName
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-jqplotseries' )->text();
+ }
+
+ /**
+ * Returns an array with the numerical data in the query result.
+ *
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputMode ) {
+
+ // Get data set
+ $data = $this->getResultData( $result, $outputMode );
+
+ // Check data availability
+ if ( $data['series'] === [] ) {
+ return $result->addErrors(
+ [
+ wfMessage( 'srf-warn-empy-chart' )
+ ->inContentLanguage()->text() ]
+ );
+ } else {
+ $options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) );
+ return $this->getFormatOutput( $this->getFormatSettings( $this->getNumbersTicks( $data ), $options ) );
+ }
+ }
+
+ /**
+ * Returns an array with the numerical data
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultData( SMWQueryResult $res, $outputMode ) {
+ $data = [];
+ $data['series'] = [];
+
+ while ( $row = $res->getNext() ) {
+ // Loop over their fields (properties)
+ $label = '';
+ $i = 0;
+
+ foreach ( $row as /* SMWResultArray */
+ $field ) {
+ $i++;
+ $rowNumbers = [];
+
+ // Grouping by subject (page object) or property
+ if ( $this->params['group'] === 'subject' ) {
+ $groupedBy = $field->getResultSubject()->getTitle()->getText();
+ } else {
+ $groupedBy = $field->getPrintRequest()->getLabel();
+ }
+
+ // Property label
+ $property = $field->getPrintRequest()->getLabel();
+
+ // First column property typeid
+ $i == 1 ? $data['fcolumntypeid'] = $field->getPrintRequest()->getTypeID() : '';
+
+ // Loop over all values for the property.
+ while ( ( /* SMWDataValue */
+ $object = $field->getNextDataValue() ) !== false ) {
+
+ if ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_NUMBER ) {
+ $number = $object->getNumber();
+
+ // Checking against the row and in case the first column is a numeric
+ // value it is handled as label with the remaining steps continue to work
+ // as it were a text label
+ // The first column container will not be part of the series container
+ if ( $i == 1 ) {
+ $label = $number;
+ continue;
+ }
+
+ if ( $label !== '' && $number >= $this->params['min'] ) {
+
+ // Reference array summarize all items per row
+ $rowNumbers += [ 'subject' => $label, 'value' => $number, 'property' => $property ];
+
+ // Store plain numbers for simpler handling
+ $data['series'][$groupedBy][] = $number;
+ }
+ } elseif ( $object->getDataItem()->getDIType() == SMWDataItem::TYPE_TIME ) {
+ $label = $object->getShortWikiText();
+ } else {
+ $label = $object->getWikiValue();
+ }
+ }
+ // Only for array's with numbers
+ if ( count( $rowNumbers ) > 0 ) {
+
+ // For cases where mainlabel=- we assume that the subject should not be
+ // used as identifier and therefore we try to match the groupby
+ // with the first available text label
+ if ( $this->params['mainlabel'] == '-' && $this->params['group'] === 'subject' ) {
+ $data[$this->params['group']][$label][] = $rowNumbers;
+ } else {
+ $data[$this->params['group']][$groupedBy][] = $rowNumbers;
+ }
+ }
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Data set sorting
+ *
+ * @since 1.8
+ *
+ * @param array $data label => value
+ *
+ * @return array
+ */
+ private function getFormatSettings( $data, $options ) {
+
+ // Init
+ $dataSet = [];
+ $options['mode'] = 'series';
+ $options['autoscale'] = false;
+
+ // Available markers
+ $marker = [ 'circle', 'diamond', 'square', 'filledCircle', 'filledDiamond', 'filledSquare' ];
+
+ // Series colour(has to be null otherwise jqplot runs with a type error)
+ $seriescolors = $this->params['chartcolor'] !== '' ? array_filter(
+ explode( ",", $this->params['chartcolor'] )
+ ) : null;
+
+ // Re-grouping
+ foreach ( $data[$this->params['group']] as $rowKey => $row ) {
+ $values = [];
+
+ foreach ( $row as $key => $value ) {
+ // Switch labels according to the group parameter
+ $label = $this->params['grouplabel'] === 'property' ? $value['property'] : $value['subject'];
+ $values[] = [ $label, $value['value'] ];
+ }
+ $dataSet[] = $values;
+ }
+
+ // Series plotting parameters
+ foreach ( $data[$this->params['group']] as $key => $row ) {
+ $series[] = [
+ 'label' => $key,
+ 'xaxis' => 'xaxis', // xaxis could also be xaxis2 or ...
+ 'yaxis' => 'yaxis',
+ 'fill' => $this->params['stackseries'],
+ 'showLine' => $this->params['charttype'] !== 'scatter',
+ 'showMarker' => true,
+ 'trendline' => [
+ 'show' => in_array( $this->params['trendline'], [ 'exp', 'linear' ] ),
+ 'shadow' => $this->params['theme'] !== 'simple',
+ 'type' => $this->params['trendline'],
+ ],
+ 'markerOptions' => [
+ 'style' => $marker[array_rand( $marker )],
+ 'shadow' => $this->params['theme'] !== 'simple'
+ ],
+ 'rendererOptions' => [ 'barDirection' => $this->params['direction'] ]
+ ];
+ };
+
+ // Basic parameters
+ $parameters = [
+ 'numbersaxislabel' => $this->params['numbersaxislabel'],
+ 'labelaxislabel' => $this->params['labelaxislabel'],
+ 'charttitle' => $this->params['charttitle'],
+ 'charttext' => $this->params['charttext'],
+ 'infotext' => $this->params['infotext'],
+ 'theme' => $this->params['theme'] ? $this->params['theme'] : null,
+ 'valueformat' => $this->params['datalabels'] === 'label' ? '' : $this->params['valueformat'],
+ 'ticklabels' => $this->params['ticklabels'],
+ 'highlighter' => $this->params['highlighter'],
+ 'autoscale' => $options['autoscale'],
+ 'gridview' => $this->params['gridview'],
+ 'direction' => $this->params['direction'],
+ 'smoothlines' => $this->params['smoothlines'],
+ 'cursor' => $this->params['cursor'],
+ 'chartlegend' => $this->params['chartlegend'] !== '' ? $this->params['chartlegend'] : 'none',
+ 'colorscheme' => $this->params['colorscheme'] !== '' ? $this->params['colorscheme'] : null,
+ 'pointlabels' => $this->params['datalabels'] === 'none' ? false : $this->params['datalabels'],
+ 'datalabels' => $this->params['datalabels'],
+ 'stackseries' => $this->params['stackseries'],
+ 'grid' => $this->params['theme'] === 'vector' ? [ 'borderColor' => '#a7d7f9' ] : ( $this->params['theme'] === 'simple' ? [ 'borderColor' => '#ddd' ] : null ),
+ 'seriescolors' => $seriescolors
+ ];
+
+ return [
+ 'data' => $dataSet,
+ //'rawdata' => $data , // control array
+ 'series' => $series,
+ 'ticks' => $data['numbersticks'],
+ 'total' => $data['total'],
+ 'fcolumntypeid' => $data['fcolumntypeid'],
+ 'sask' => $options['sask'],
+ 'mode' => $options['mode'],
+ 'renderer' => $this->params['charttype'],
+ 'parameters' => $parameters
+ ];
+ }
+
+ /**
+ * Fetch numbers ticks
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ */
+ protected function getNumbersTicks( array $data ) {
+
+ // Only look for numeric values that have been stored
+ $numerics = array_values( $data['series'] );
+
+ // Find min and max values to determine the graphs axis parameter
+ $maxValue = count( $numerics ) == 0 ? 0 : max( array_map( "max", $numerics ) );
+
+ if ( $this->params['min'] === false ) {
+ $minValue = count( $numerics ) == 0 ? 0 : min( array_map( "min", $numerics ) );
+ } else {
+ $minValue = $this->params['min'];
+ }
+
+ // Get ticks info
+ $data['numbersticks'] = SRFjqPlot::getNumbersTicks( $minValue, $maxValue );
+ $data['total'] = array_sum( array_map( "array_sum", $numerics ) );
+
+ return $data;
+ }
+
+ /**
+ * Add resource definitions
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ protected function addResources() {
+ // RL module
+ switch ( $this->params['charttype'] ) {
+ case 'bubble':
+ SMWOutputs::requireResource( 'ext.srf.jqplot.bubble' );
+ break;
+ case 'donut':
+ SMWOutputs::requireResource( 'ext.srf.jqplot.donut' );
+ break;
+ case 'scatter':
+ case 'line':
+ case 'bar':
+ SMWOutputs::requireResource( 'ext.srf.jqplot.bar' );
+ break;
+ }
+
+ // Trendline plugin
+ if ( in_array( $this->params['trendline'], [ 'exp', 'linear' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.trendline' );
+ }
+
+ // Cursor plugin
+ if ( in_array( $this->params['cursor'], [ 'zoom', 'tooltip' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.cursor' );
+ }
+
+ // Highlighter plugin
+ if ( $this->params['highlighter'] ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.highlighter' );
+ }
+
+ // Enhancedlegend plugin
+ if ( $this->params['chartlegend'] ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.enhancedlegend' );
+ }
+
+ // gridview plugin
+ if ( in_array( $this->params['gridview'], [ 'tabs' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.util.grid' );
+ }
+
+ // Pointlabels plugin
+ if ( in_array( $this->params['datalabels'], [ 'value', 'label', 'percent' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.jqplot.pointlabels' );
+ }
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ protected function getFormatOutput( array $data ) {
+
+ $this->isHTML = true;
+
+ static $statNr = 0;
+ $chartID = 'jqplot-series-' . ++$statNr;
+
+ // Encoding
+ $requireHeadItem = [ $chartID => FormatJson::encode( $data ) ];
+ SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // Add RL resources
+ $this->addResources();
+
+ // Processing placeholder
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // Conversion due to a string as value that can contain %
+ $width = strstr( $this->params['width'], "%" ) ? $this->params['width'] : $this->params['width'] . 'px';
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [
+ 'id' => $chartID,
+ 'class' => 'container',
+ 'style' => "display:none; width: {$width}; height: {$this->params['height']}px;"
+ ],
+ null
+ );
+
+ // Beautify class selector
+ $class = $this->params['charttype'] ? '-' . $this->params['charttype'] : '';
+ $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class . ' jqplot-common';
+
+ // Chart/graph wrappper
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-jqplot' . $class,
+ ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = array_merge( parent::getParamDefinitions( $definitions ), SRFjqPlot::getCommonParams() );
+
+ $params['infotext'] = [
+ 'message' => 'srf-paramdesc-infotext',
+ 'default' => '',
+ ];
+
+ $params['stackseries'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-stackseries',
+ 'default' => false,
+ ];
+
+ $params['group'] = [
+ 'message' => 'srf-paramdesc-group',
+ 'default' => 'subject',
+ 'values' => [ 'property', 'subject' ],
+ ];
+
+ $params['grouplabel'] = [
+ 'message' => 'srf-paramdesc-grouplabel',
+ 'default' => 'subject',
+ 'values' => [ 'property', 'subject' ],
+ ];
+
+ $params['charttype'] = [
+ 'message' => 'srf-paramdesc-charttype',
+ 'default' => 'bar',
+ 'values' => [ 'bar', 'line', 'donut', 'bubble', 'scatter' ],
+ ];
+
+ $params['trendline'] = [
+ 'message' => 'srf-paramdesc-trendline',
+ 'default' => 'none',
+ 'values' => [ 'none', 'exp', 'linear' ],
+ ];
+
+ $params['cursor'] = [
+ 'message' => 'srf-paramdesc-chartcursor',
+ 'default' => 'none',
+ 'values' => [ 'none', 'zoom', 'tooltip' ],
+ ];
+
+ $params['gridview'] = [
+ 'message' => 'srf-paramdesc-gridview',
+ 'default' => 'none',
+ 'values' => [ 'none', 'tabs' ],
+ ];
+
+ return $params;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/LICENSE ColorBrewer b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/LICENSE ColorBrewer
new file mode 100644
index 00000000..2ac775d6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/LICENSE ColorBrewer
@@ -0,0 +1,38 @@
+Apache-Style Software License for ColorBrewer software and ColorBrewer Color
+Schemes
+
+Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State
+University.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions as source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. The end-user documentation included with the redistribution, if any, must
+include the following acknowledgment: "This product includes color
+specifications and designs developed by Cynthia Brewer
+(http://colorbrewer.org/)." Alternately, this acknowledgment may appear in the
+software itself, if and wherever such third-party acknowledgments normally
+appear.
+
+4. The name "ColorBrewer" must not be used to endorse or promote products
+derived from this software without prior written permission. For written
+permission, please contact Cynthia Brewer at cbrewer@psu.edu.
+
+5. Products derived from this software may not be called "ColorBrewer", nor
+may "ColorBrewer" appear in their name, without prior written permission of
+Cynthia Brewer.
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqlpot.chart.css b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqlpot.chart.css
new file mode 100644
index 00000000..9d611276
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqlpot.chart.css
@@ -0,0 +1,52 @@
+/**
+ * CSS for SRF jqplot module
+ * *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.1
+ */
+.srf-jqplot-plot.tabs {
+ margin-bottom: 10px;
+}
+
+.srf-jqplot-text-adjust {
+ height: 10px;
+}
+
+.srf-jqplot-chart-adjust.tabs {
+ height: 20px;
+ width: 15px;
+}
+
+.srf-jqplot-table-adjust.tabs {
+ width: 20px;
+}
+
+.srf-jqplot-table-adjust.tabs.chrome {
+ width: 25px;
+}
+
+.srf-jqplot-table-adjust.tabs.firefox {
+ width: 35px;
+}
+
+.srf-jqplot-chart-text {
+ color:grey;
+ display:block;
+ position:relative;
+ font-size:90%;
+ margin-bottom: 10px;
+ margin-right: 10px;
+}
+
+.srf-jqplot-chart-text.tabs {
+ font-size:120%;
+ margin-left: 10px;
+ margin-bottom: 10px;
+}
+
+.srf-jqplot-chart-text.pie,
+.srf-jqplot-chart-text.donut {
+ margin-left: 10px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bar.js b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bar.js
new file mode 100644
index 00000000..117285d4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bar.js
@@ -0,0 +1,255 @@
+/**
+ * JavaSript for SRF jqPlot bar/line/scatter module
+ *
+ * The script is designed to handle single and series data sets
+ *
+ * Release 0.6 has been checked agains jsHint which passed all conditions
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.6
+ */
+( function( $ ) {
+ "use strict";
+
+ /*global mw:true, colorscheme:true*/
+
+ // Bar/line data handling is separated from plotting because relevant data array
+ // can be checked and if necessary bailout and show an error message instead
+ // without causing any type errors
+ $.fn.srfjqPlotBarChartData = function( options ) {
+ var chartID = options.id,
+ height = options.height,
+ data = options.data,
+ width = options.width,
+ chart = options.chart;
+
+ // Global data array
+ var labels = [];
+
+ // Function handles all data array miracles
+ var errMsg = '',
+ dataRenderer = function() {
+ var jqplotdata = [],
+ ttLength = 0,
+ ptLength = 0;
+
+ // Count the amount of series
+ for ( var k = 0; k < data.data.length; ++k ) {
+ var ttData = [];
+ ttLength = data.data[k].length;
+
+ // Check if data series has the same length otherwise
+ // stackseries throws an error
+ if ( ttLength !== ptLength && k > 0 && data.parameters.stackseries === true ){
+ errMsg = mw.msg( 'srf-error-jqplot-stackseries-data-length' );
+ }
+
+ // Individual data within a series
+ for ( var j = 0; j < ttLength; ++j ) {
+ if ( data.parameters.direction === 'horizontal' ){
+ if ( data.fcolumntypeid === '_num' ){
+ // Numeric x-value is handled differently
+ ttData.push ( [data.data[k][j][1], data.data[k][j][0]] );
+ }else{
+ ttData.push ( [data.data[k][j][1], j+1] );
+ }
+ } else {
+ if ( data.fcolumntypeid === '_num' ){
+ // Numeric x-value is handled differently
+ ttData.push ( [data.data[k][j][0], data.data[k][j][1]] );
+ }else{
+ ttData[j] = data.data[k][j][1];
+ }
+ }
+ // Handle labels in extra array
+ labels[j] = data.data[k][j][0];
+ }
+ jqplotdata.push( ttData );
+ // Store previous length to compare both
+ ptLength = ttLength;
+ }
+ return jqplotdata;
+ };
+
+ // Get data array
+ var jqplotbardata = dataRenderer();
+
+ // Error message handling
+ if ( errMsg.length > 0 ){
+ this.html( errMsg ).css( { 'class' : 'error', 'height' : 20 , 'margin' : '5px 5px 5px 5px', 'color': 'red' } );
+ }else{
+ this.srfjqPlotBarChart( { 'id' : chartID, 'data' : data, 'barData' : jqplotbardata, 'labels' : labels, 'height' : height, 'width' : width, 'chart' : chart } );
+ }
+ };
+
+ // Bar/line/scatter plotting
+ $.fn.srfjqPlotBarChart = function( options ) {
+ var labels = options.labels,
+ data = options.data;
+
+ // Number axis
+ var numberaxis = {
+ ticks: data.parameters.stackseries || data.parameters.autoscale ? [] : data.ticks, // use autoscale for staked series
+ label: data.parameters.numbersaxislabel,
+ labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
+ autoscale: data.parameters.stackseries || data.parameters.autoscale ? true : false,
+ padMax: 0,
+ padMin: 0,
+ tickOptions: {
+ angle: data.parameters.direction === 'horizontal' ? 0 : -40,
+ formatString: !data.parameters.valueformat ? '%d' : data.parameters.valueformat // %d default
+ }
+ };
+
+ // Helper function to get the Max value of the Array
+ var max = function( array ){
+ return Math.max.apply( Math, array );
+ };
+
+ // Helper function to get the Min value of the Array
+ var min = function( array ){
+ return Math.min.apply( Math, array );
+ };
+
+ var base = Math.pow( 1, Math.floor( Math.log( max( labels ), 10 ) ) );
+
+ // Label axis
+ var labelaxis = {
+ // Depending on first column type values/labels are handled differently
+ renderer: data.fcolumntypeid === '_num' ? $.jqplot.LinearAxisRenderer : $.jqplot.CategoryAxisRenderer,
+ ticks: data.fcolumntypeid === '_num' ? [] : labels,
+ label: data.parameters.labelaxislabel,
+ tickRenderer: $.jqplot.CanvasAxisTickRenderer,
+ min: data.fcolumntypeid === '_num' ? Math.round( min( labels ) ) - base : '',
+ max: data.fcolumntypeid === '_num' ? Math.round( max( labels ) ) + base : '',
+ //tickInterval: 2,
+ tickOptions: {
+ angle: ( data.parameters.direction === 'horizontal' ? 0 : -40 ),
+ formatString: !data.parameters.valueformat ? '%d' : data.parameters.valueformat // %d default
+ }
+ };
+
+ // Required for horizontal view
+ var single = [ {
+ renderer: data.renderer === 'bar' ? $.jqplot.BarRenderer : $.jqplot.LineRenderer,
+ rendererOptions: {
+ barDirection: data.parameters.direction,
+ barPadding: 6,
+ barMargin: data.parameters.direction === 'horizontal' ? 8 : 6,
+ barWidth: data.renderer === 'vector' || data.renderer === 'simple' ? 20 : null,
+ smooth: data.parameters.smoothlines,
+ varyBarColor: true
+ }
+ } ];
+
+ var highlighter = {
+ show: data.parameters.highlighter && data.renderer === 'line' ? true : false,
+ showTooltip: data.parameters.highlighter,
+ tooltipLocation: 'w',
+ useAxesFormatters: data.parameters.highlighter,
+ tooltipAxes: data.parameters.direction === 'horizontal' ? 'x' : 'y'
+ };
+
+ // Format individual data labels
+ $.jqplot.LabelFormatter = function( format, val ) {
+ var num = typeof val === 'object' ? val[1] : val;
+
+ // Single mode
+ if ( data.mode === 'single' ){
+ if ( data.parameters.pointlabels === 'label' ){
+ return labels[num];
+ }else if ( data.parameters.pointlabels === 'percent' ) {
+ return ( num / data.total * 100 ).toFixed(2) + '% (' + num + ')';
+ } else {
+ return num;
+ }
+ }
+
+ // Series mode
+ if ( data.parameters.pointlabels === 'percent' ){
+ return ( num / data.total * 100 ).toFixed(2) + '% (' + num + ')';
+ } else if ( data.parameters.pointlabels === 'label' ){
+ return labels[num];
+ } else if ( data.parameters.direction === 'horizontal' && data.renderer === 'line' ){
+ // This case is weird because val returns with the index number and not with the value
+ // which means all values displayed do mislead
+ return '(n/a)';
+ }else{
+ return format !== '' ? val : val;
+ }
+ };
+
+ var pointLabels = {
+ show: data.parameters.pointlabels,
+ location: data.parameters.direction === 'vertical' ? 'n' : 'e',
+ edgeTolerance: data.renderer === 'bar' ? '-35': '-20',
+ formatString: data.parameters.valueformat === '' ? '%d' : data.parameters.valueformat,
+ formatter: $.jqplot.LabelFormatter,
+ labels: data.parameters.pointlabels === 'label' ? data.labels : data.numbers
+ };
+
+ var seriesDefaults = {
+ renderer: data.renderer === 'bar' ? $.jqplot.BarRenderer : $.jqplot.LineRenderer,
+ fillToZero: true,
+ shadow: data.parameters.theme !== 'simple',
+ rendererOptions: {
+ smooth: data.parameters.smoothlines
+ },
+ trendline: { show : false },
+ pointLabels: pointLabels
+ };
+
+ var legend = {
+ renderer: $.jqplot.EnhancedLegendRenderer,
+ show: data.parameters.chartlegend !== 'none',
+ location: data.parameters.chartlegend,
+ labels: data.legendLabels,
+ placement: 'inside',
+ xoffset: 10,
+ yoffset: 10
+ };
+
+ // Series information
+ var series = data.series;
+
+ // Color information
+ var seriesColors = data.parameters.seriescolors ? data.parameters.seriescolors : data.parameters.colorscheme === null ? null : colorscheme[data.parameters.colorscheme][9];
+
+ // Enable jqplot plugins
+ $.jqplot.config.enablePlugins = true;
+
+ // Now we are plotting
+ var jqplotbar = $.jqplot( options.id , options.barData , {
+ title: data.parameters.charttitle,
+ //dataRenderer: dataRenderer,
+ stackSeries: data.parameters.stackseries,
+ seriesColors: seriesColors,
+ axesDefaults: {
+ showTicks: data.parameters.ticklabels,
+ tickOptions: { showMark: false }
+ },
+ grid: data.parameters.grid,
+ highlighter: highlighter,
+ seriesDefaults: seriesDefaults,
+ cursor: {
+ show: $.inArray( data.parameters.cursor, ['zoom','tooltip'] ) > -1 && $.inArray( data.fcolumntypeid, ['_num','_dat'] ) > -1,
+ zoom: data.parameters.cursor === 'zoom',
+ looseZoom: data.parameters.cursor === 'zoom',
+ showTooltip: data.parameters.cursor === 'tooltip'
+ },
+ series: data.mode === 'single' ? single : series,
+ axes: {
+ xaxis : ( data.parameters.direction === 'vertical' ? labelaxis : numberaxis ),
+ yaxis : ( data.parameters.direction === 'vertical' ? numberaxis : labelaxis )
+ // x2axis : ( data.parameters.direction == 'vertical' ? label2axis : number2axis ) ,
+ // y2axis : ( data.parameters.direction == 'vertical' ? number2axis : label2axis )
+ },
+ legend: data.parameters.chartlegend === 'none' ? null : legend
+ } ); // enf of $.jqplot
+
+ // Call theming
+ this.srfjqPlotTheme( { 'plot' : jqplotbar, 'theme' : data.parameters.theme } );
+ };
+} )( window.jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bubble.js b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bubble.js
new file mode 100644
index 00000000..fa29114d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.bubble.js
@@ -0,0 +1,98 @@
+/**
+ * JavaSript for SRF jqPlot bubble module
+ *
+ * The script is designed to handle single and series data sets
+ *
+ * Release 0.6 has been checked agains jsHint which passed all conditions
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.6
+ */
+( function( $ ) {
+ "use strict";
+
+ // Only display errors
+ try { console.log('console ready'); } catch (e) { var console = { log: function () { } }; }
+
+ /*global mw:true, colorscheme:true*/
+
+ // Bubble chart data handling is separated from plotting because relevant data array
+ // can be checked and if necessary bailout and show an error message instead
+ // without causing any type errors
+ $.fn.srfjqPlotBubbleChartData = function( options ) {
+ var data = options.data;
+
+ // Data array handling
+ var errMsg = '',
+ dataRenderer = function() {
+ var bubbledata = [];
+
+ // Check to avoid TypeErrors
+ if ( typeof data.data[0] === 'undefined' ) {
+ errMsg = mw.msg( 'srf-error-jqplot-bubble-data-length' );
+ } else if ( typeof data.data[1] === 'undefined' ){
+ errMsg = mw.msg( 'srf-error-jqplot-bubble-data-length' );
+ } else if ( typeof data.data[2] === 'undefined' ){
+ errMsg = mw.msg( 'srf-error-jqplot-bubble-data-length' );
+ }
+
+ // Data manipulation
+ // Convert [x: [label, value ]], [y: [label, value ]], [radius: [label, value ]] into
+ // [x, y, radius, <label or object>]
+ if ( errMsg === '' ){
+ for ( var k = 0; k < data.data[0].length; ++k ) {
+ bubbledata.push( [data.data[0][k][1], data.data[1][k][1], data.data[2][k][1], data.data[0][k][0] ]);
+ }
+ }
+ return [bubbledata];
+ };
+
+ // Fetch data array, call it before any other routine otherwise no error msg
+ var jqplotbubbledata = dataRenderer();
+
+ // Error message handling
+ if ( errMsg.length > 0 ){
+ this.html( errMsg ).css( { 'class' : 'error', 'height' : 20 , 'margin' : '5px 5px 5px 5px', 'color': 'red' } );
+ }else{
+ this.srfjqPlotBubbleChart( { 'id' : options.id, 'barData' : jqplotbubbledata, 'data' : data } );
+ }
+ };
+
+ // Bubble plotting
+ $.fn.srfjqPlotBubbleChart = function( options ) {
+ var data = options.data;
+
+ $.jqplot.config.enablePlugins = true;
+
+ var jqplotbubble = $.jqplot( options.id , options.barData, {
+ // dataRenderer: dataRenderer,
+ title: data.parameters.charttitle,
+ seriesColors: data.parameters.seriescolors ? data.parameters.seriescolors : ( data.parameters.colorscheme === null ? null : colorscheme[data.parameters.colorscheme][9] ),
+ grid: data.parameters.grid,
+ seriesDefaults: {
+ renderer: data.renderer === 'bubble' ? $.jqplot.BubbleRenderer : $.jqplot.PieRenderer,
+ shadow: data.parameters.theme !== 'simple',
+ rendererOptions: {
+ autoscalePointsFactor: -0.15,
+ autoscaleMultiplier: 0.85,
+ highlightMouseOver: true,
+ bubbleGradients: true,
+ bubbleAlpha: 0.7
+ }
+ },
+ legend: {
+ show: data.parameters.chartlegend !== 'none',
+ location: data.parameters.chartlegend,
+ // labels: data['legendLabels'],
+ placement: 'inside',
+ xoffset: 10,
+ yoffset:10
+ }
+ } );
+
+ // Call theming
+ this.srfjqPlotTheme( { 'plot' : jqplotbubble, 'theme' : data.parameters.theme } );
+ };
+} )( window.jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.js b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.js
new file mode 100644
index 00000000..ee41f882
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.js
@@ -0,0 +1,162 @@
+/**
+ * JavaScript for SRF jqPlot chart/series module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Jqplotchart format
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Jplotseries format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, srf ) {
+ 'use strict';
+
+ /*global mw:true*/
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ var util = new srf.util();
+
+ // Browser information
+ var profile = $.client.profile();
+
+ // Attribute information can only be gathered after they have been applied to
+ // an element
+ function _getElementAttribute( options ){
+ var p = $("<p></p>").hide().appendTo( options.context ).addClass( options.className ),
+ value = parseInt( p.css( options.attribute ), 10 );
+ p.remove();
+ return value;
+ }
+
+ ////////////////////////// PUBLIC METHODS ////////////////////////
+
+ // Global jqplot container handling
+ $.fn.srfjqPlotChartContainer = function() {
+
+ var chart = this,
+ container = chart.find( ".container" ),
+ chartID = container.attr( "id" ),
+ height = container.height(),
+ width = container.width(),
+ json = mw.config.get( chartID );
+
+ // Parse json string and convert it back
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ var adjustChartElement = 'srf-jqplot-chart-adjust ' + data.parameters.gridview + ' ' + profile.name,
+ adjustTableElement = 'srf-jqplot-table-adjust ' + data.parameters.gridview + ' ' + profile.name,
+ adjustTextElement = 'srf-jqplot-text-adjust ' + data.parameters.gridview + ' ' + profile.name;
+
+ // Assign height/width important when dealing with % values
+ chart.css( { 'height': height , 'width': width } );
+ container.css( {
+ 'height': chart.height() - _getElementAttribute( { context: container, className: adjustChartElement, attribute: 'height' } ),
+ 'width': chart.width() - _getElementAttribute( { context: container, className: adjustChartElement, attribute: 'width' } )
+ } );
+
+ // Hide processing image
+ util.spinner.hide( { context: chart } );
+
+ // Release chart/graph
+ container.show();
+
+ // Was reported to solve some memory leak problems on IE in connection with
+ // canvas objects
+ container.find( 'canvas' ).remove();
+
+ // Call gridview plugin
+ if ( data.parameters.gridview === 'tabs' ){
+ // Set options
+ var options ={
+ 'context' : chart,
+ 'id' : chartID,
+ 'container' : container,
+ 'widthBorder': _getElementAttribute( { context: container, className: adjustTableElement, attribute: 'width' } ),
+ 'info' : data.parameters.infotext,
+ 'data' : data
+ };
+
+ // Grid view instance
+ new srf.util.grid( options );
+ }
+
+ // Tabs height can vary (due to CSS) therefore after tabs instance was
+ // created get the height
+ var _tabsHeight = chart.find( '.ui-tabs-nav' ).outerHeight();
+
+ // Add chart text
+ var chartText = data.parameters.charttext,
+ chartTextHeight = 0;
+ if ( chartText.length > 0 ) {
+ container.prepend( '<div id="' + chartID + '-text' + '" class="srf-jqplot-chart-text">' + chartText + '</div>' );
+ container.find( '.srf-jqplot-chart-text' )
+ .addClass( ( data.parameters.gridview === 'tabs' ? 'tabs ' + data.renderer : data.renderer ) );
+ chartTextHeight = container.find( '.srf-jqplot-chart-text' ).height() +
+ _getElementAttribute( { context: container, className: adjustTextElement, attribute: 'height' } ) ;
+ }
+
+ // Adjust height and width according to current customizing
+ container.css( { height: container.height() - _tabsHeight } );
+ // Get height,width for plotting area
+ width = container.width();
+ height = container.height() - chartTextHeight;
+
+ // Plotting area
+ var plotID = chartID + '-plot';
+ container.prepend( '<div id="' + plotID + '" class="srf-jqplot-plot"></div>' );
+ var plot = chart.find( '.srf-jqplot-plot' );
+ plot
+ .css( { 'height': height, 'width': width } )
+ .addClass( ( data.parameters.gridview === 'tabs' ? 'tabs ' + data.renderer : data.renderer ) );
+
+ // Chart plotting
+ if ( data.renderer === 'pie' || data.renderer === 'donut' ){
+ plot.srfjqPlotPieChart( { 'id' : plotID, 'height' : height, 'width' : width, 'chart' : container, 'data' : data } );
+ } else if ( data.renderer === 'bubble' ){
+ plot.srfjqPlotBubbleChartData( { 'id' : plotID, 'height' : height, 'width' : width, 'chart' : container, 'data' : data } );
+ } else {
+ plot.srfjqPlotBarChartData( { 'id' : plotID, 'height' : height , 'width' : width , 'chart' : container, 'data' : data } );
+ }
+
+ };
+
+ // Theming
+ $.fn.srfjqPlotTheme = function( options ) {
+ /*global simple:true, vector:true*/
+
+ // Reposition chart text to adjust for the tick label margin
+ var textmargin = this.find( '.jqplot-axis.jqplot-yaxis').width();
+ this.find( '.srf-jqplot-chart-text' ).css( { 'margin-left': textmargin , 'display': 'block'} );
+
+ // Theming support for commonly styled attributes of plot elements
+ // using jqPlot's "themeEngine"
+ options.plot.themeEngine.newTheme( 'simple', simple );
+ options.plot.themeEngine.newTheme( 'vector', vector );
+
+ // Only overwrite the default for cases with a theme
+ if ( options.theme !== null ){
+ options.plot.activateTheme( options.theme );
+ }
+ };
+
+ ////////////////////////// IMPLEMENTATION ////////////////////////
+
+ $( document ).ready( function() {
+ // Check if eachAsync exists, and if so use it to increase browsers responsiveness
+ if( $.isFunction( $.fn.eachAsync ) ){
+ $( "[class^=srf-jqplot]" ).eachAsync( {
+ delay: 100,
+ bulk: 0,
+ loop: function(){
+ $( this ).srfjqPlotChartContainer();
+ }
+ } );
+ }else{
+ $( "[class^=srf-jqplot]" ).each( function() {
+ $( this ).srfjqPlotChartContainer();
+ } );
+ }
+ } );
+} )( jQuery, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.pie.js b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.pie.js
new file mode 100644
index 00000000..91d43ed0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.chart.pie.js
@@ -0,0 +1,69 @@
+/**
+ * JavaSript for SRF jqPlot pie module
+ *
+ * The script is designed to handle single and series data sets
+ *
+ * Release 0.6 has been checked agains jsHint which passed all conditions
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.6
+ */
+( function( $ ) {
+ "use strict";
+
+ /*global colorscheme:true*/
+
+ // Pie/donut handling
+ $.fn.srfjqPlotPieChart = function( options ) {
+ var data = options.data;
+
+ // Handle data array
+ var jqplotpiedata = [];
+
+ var dataRenderer = function() {
+ jqplotpiedata = data.data;
+ // jqplotpiedata.push( data.data );
+ return jqplotpiedata;
+ };
+
+ // Default settings
+ var seriesDefaults = {
+ renderer: data.renderer === 'donut' ? $.jqplot.DonutRenderer : $.jqplot.PieRenderer,
+ shadow: data.parameters.theme !== 'simple',
+ rendererOptions: {
+ fill: data.parameters.filling,
+ lineWidth: 2,
+ showDataLabels: ( data.parameters.datalabels === 'percent' || data.parameters.datalabels === 'value' || data.parameters.datalabels === 'label' ? true : false ),
+ dataLabels: data.parameters.datalabels,
+ sliceMargin: 2,
+ dataLabelFormatString: data.parameters.datalabels === 'label' ? null : ( !data.parameters.valueformat ? '%d' : data.parameters.valueformat )
+ }
+ };
+
+ // Activate plug-ins
+ $.jqplot.config.enablePlugins = true;
+
+ // Render plot
+ var jqplotpie = $.jqplot( options.id, [] , {
+ dataRenderer: dataRenderer,
+ title: data.parameters.charttitle,
+ seriesColors: data.parameters.seriescolors ? data.parameters.seriescolors : ( data.parameters.colorscheme === null ? null : colorscheme[data.parameters.colorscheme][9] ),
+ grid: data.parameters.grid,
+ highlighter: { show: false },
+ cursor: { show: false },
+ seriesDefaults: seriesDefaults,
+ legend: {
+ show: data.parameters.chartlegend !== 'none',
+ location: data.parameters.chartlegend,
+ placement: 'inside',
+ xoffset: 10,
+ yoffset:10
+ }
+ } ); // end of jqplot object
+
+ // Call theming
+ this.srfjqPlotTheme( { 'plot' : jqplotpie, 'theme' : data.parameters.theme } );
+ };
+} )( window.jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.themes.js b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.themes.js
new file mode 100644
index 00000000..3ce47ad0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/jqplot/resources/ext.srf.jqplot.themes.js
@@ -0,0 +1,76 @@
+/**
+ * JavaSript for SRF jqPlot module
+ *
+ * jqPlot has basic theming support for commonly styled atributes of plot elements.
+ * A "themeEngine" controls modificaition, adding, removing and activating of
+ * plot themes
+ *
+ * A "style" object holds various plot elements and styles with each of
+ * those ojbects where the actual styling properties are attached.
+ *
+ * Color patterns with keys corresponding to the ColorCombo website
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.3
+ */
+(function( $ ) {
+
+ $(document).ready(function() {
+
+ $( "[class^=srf-jqplot]" ).each(function() {
+
+ colorscheme = {
+ 0: [ '#1f77b4', '#aec7e8', '#ff7f0e', '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896', '#9467bd', '#c5b0d5', '#8c564b', '#c49c94', '#e377c2', '#f7b6d2', '#7f7f7f', '#c7c7c7', '#bcbd22', '#dbdb8d', '#17becf', '#9edae5' ] ,
+ cc124:{9: [ '#E8D0A9', '#B7AFA3', '#C1DAD6', '#F5FAFA', '#ACD1E9', '#6D929B' ] },
+ cc128:{9: [ '#7D9C9F', '#BDD8DA', '#DFEFF0', '#AD235E', '#ECECEC', '#B1B1B1' ] },
+ cc129:{9: [ '#6194BC', '#A5D1F3', '#D0EAFF', '#E4001B', '#ECECEC', '#606060' ] },
+ cc173:{9: [ '#206BA4', '#BBD9EE', '#EBF4FA', '#C0C0C0', '#E7E4D3', '#F1EFE2' ] },
+ cc210:{9: [ '#660F57', '#663366', '#003366', '#E7EBF0', '#B1BDCD', '#5B7290' ] },
+ cc267:{9: [ '#757116', '#AEBC21', '#D9DB56', '#00477F', '#4C88BE', '#8DC3E9' ] },
+ cc294:{9: [ '#B7C68B', '#F4F0CB', '#DED29E', '#B3A580', '#685642' ] },
+ cc252:{9: [ '#9C9284', '#CCCC99', '#E6E6CC', '#6699CC', '#FF9900' ] },
+ cc303:{9: [ '#7A3E48', '#EECD86', '#E18942', '#B95835', '#3D3242' ] },
+ cc327:{9: [ '#9D2E2C', '#F9EA99', '#7DB6D5', '#E7A555', '#4A4747' ] },
+ ylgn:{3:["rgb(247,252,185)","rgb(173,221,142)","rgb(49,163,84)"],4:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(35,132,67)"],5:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],6:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],7:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],8:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],9:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,104,55)","rgb(0,69,41)"]},
+ ylgnbu:{3:["rgb(237,248,177)","rgb(127,205,187)","rgb(44,127,184)"],4:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(34,94,168)"],5:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],6:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],7:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],8:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],9:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(37,52,148)","rgb(8,29,88)"]},
+ gnbu:{3:["rgb(224,243,219)","rgb(168,221,181)","rgb(67,162,202)"],4:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(43,140,190)"],5:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],6:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],7:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],8:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],9:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,104,172)","rgb(8,64,129)"]},
+ bugn:{3:["rgb(229,245,249)","rgb(153,216,201)","rgb(44,162,95)"],4:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(35,139,69)"],5:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],6:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],7:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],8:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],9:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},
+ pubugn:{3:["rgb(236,226,240)","rgb(166,189,219)","rgb(28,144,153)"],4:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(2,129,138)"],5:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],6:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],7:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],8:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],9:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,108,89)","rgb(1,70,54)"]},
+ pubu:{3:["rgb(236,231,242)","rgb(166,189,219)","rgb(43,140,190)"],4:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(5,112,176)"],5:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],6:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],7:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],8:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],9:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(4,90,141)","rgb(2,56,88)"]},
+ bupu:{3:["rgb(224,236,244)","rgb(158,188,218)","rgb(136,86,167)"],4:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,65,157)"],5:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],6:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],7:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],8:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],9:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(129,15,124)","rgb(77,0,75)"]},
+ rdpu:{3:["rgb(253,224,221)","rgb(250,159,181)","rgb(197,27,138)"],4:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(174,1,126)"],5:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],6:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],7:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],8:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],9:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)","rgb(73,0,106)"]},
+ purd:{3:["rgb(231,225,239)","rgb(201,148,199)","rgb(221,28,119)"],4:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(206,18,86)"],5:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],6:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],7:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],8:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],9:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(152,0,67)","rgb(103,0,31)"]},
+ orrd:{3:["rgb(254,232,200)","rgb(253,187,132)","rgb(227,74,51)"],4:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(215,48,31)"],5:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],6:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],7:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],8:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],9:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(179,0,0)","rgb(127,0,0)"]},
+ ylorrd:{3:["rgb(255,237,160)","rgb(254,178,76)","rgb(240,59,32)"],4:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(227,26,28)"],5:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],6:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],7:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],8:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],9:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(189,0,38)","rgb(128,0,38)"]},
+ ylorbr:{3:["rgb(255,247,188)","rgb(254,196,79)","rgb(217,95,14)"],4:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(204,76,2)"],5:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],6:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],7:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],8:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],9:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(153,52,4)","rgb(102,37,6)"]},
+ purples:{3:["rgb(239,237,245)","rgb(188,189,220)","rgb(117,107,177)"],4:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(106,81,163)"],5:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],6:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],7:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],8:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],9:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(84,39,143)","rgb(63,0,125)"]},
+ blues:{3:["rgb(222,235,247)","rgb(158,202,225)","rgb(49,130,189)"],4:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(33,113,181)"],5:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],6:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],7:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],8:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],9:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,81,156)","rgb(8,48,107)"]},
+ greens:{3:["rgb(229,245,224)","rgb(161,217,155)","rgb(49,163,84)"],4:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(35,139,69)"],5:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],6:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],7:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],8:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],9:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},
+ oranges:{3:["rgb(254,230,206)","rgb(253,174,107)","rgb(230,85,13)"],4:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(217,71,1)"],5:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],6:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],7:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],8:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],9:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(166,54,3)","rgb(127,39,4)"]},
+ reds:{3:["rgb(254,224,210)","rgb(252,146,114)","rgb(222,45,38)"],4:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(203,24,29)"],5:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],6:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],7:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],8:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],9:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(165,15,21)","rgb(103,0,13)"]},
+ greys:{3:["rgb(240,240,240)","rgb(189,189,189)","rgb(99,99,99)"],4:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(82,82,82)"],5:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],6:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],7:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],8:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],9:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)","rgb(0,0,0)"]},
+ puor:{3:["rgb(241,163,64)","rgb(247,247,247)","rgb(153,142,195)"],4:["rgb(230,97,1)","rgb(253,184,99)","rgb(178,171,210)","rgb(94,60,153)"],5:["rgb(230,97,1)","rgb(253,184,99)","rgb(247,247,247)","rgb(178,171,210)","rgb(94,60,153)"],6:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],7:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],8:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],9:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],10:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"],11:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"]},
+ brbg:{3:["rgb(216,179,101)","rgb(245,245,245)","rgb(90,180,172)"],4:["rgb(166,97,26)","rgb(223,194,125)","rgb(128,205,193)","rgb(1,133,113)"],5:["rgb(166,97,26)","rgb(223,194,125)","rgb(245,245,245)","rgb(128,205,193)","rgb(1,133,113)"],6:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],7:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],8:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],9:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],10:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"],11:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"]},
+ prgn:{3:["rgb(175,141,195)","rgb(247,247,247)","rgb(127,191,123)"],4:["rgb(123,50,148)","rgb(194,165,207)","rgb(166,219,160)","rgb(0,136,55)"],5:["rgb(123,50,148)","rgb(194,165,207)","rgb(247,247,247)","rgb(166,219,160)","rgb(0,136,55)"],6:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],7:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],8:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],9:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],10:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"],11:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"]},
+ piyg:{3:["rgb(233,163,201)","rgb(247,247,247)","rgb(161,215,106)"],4:["rgb(208,28,139)","rgb(241,182,218)","rgb(184,225,134)","rgb(77,172,38)"],5:["rgb(208,28,139)","rgb(241,182,218)","rgb(247,247,247)","rgb(184,225,134)","rgb(77,172,38)"],6:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],7:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],8:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],9:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],10:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"],11:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"]},
+ rdbu:{3:["rgb(239,138,98)","rgb(247,247,247)","rgb(103,169,207)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(146,197,222)","rgb(5,113,176)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(247,247,247)","rgb(146,197,222)","rgb(5,113,176)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"]},
+ rdgy:{3:["rgb(239,138,98)","rgb(255,255,255)","rgb(153,153,153)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(186,186,186)","rgb(64,64,64)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(255,255,255)","rgb(186,186,186)","rgb(64,64,64)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"]},
+ rdylbu:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,191,219)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,217,233)","rgb(44,123,182)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,217,233)","rgb(44,123,182)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"]},
+ spectral:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(153,213,148)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,221,164)","rgb(43,131,186)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,221,164)","rgb(43,131,186)"],6:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],7:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],8:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],9:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],10:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"],11:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"]},
+ rdylgn:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,207,96)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(166,217,106)","rgb(26,150,65)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(166,217,106)","rgb(26,150,65)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"]}
+ };
+
+ simple = { grid: { drawBorder: 1, drawGridlines: 1, shadow: 0, borderWidth: 0.5, borderColor: '#ddd', backgroundColor: '#ffffff' },
+ axes: { xaxis: { borderColor: "#ddd", borderWidth: 1, label: { fontSize: '9pt', textColor: '#aaa' } },
+ yaxis: { borderColor: "#ddd", borderWidth: 1, label: { fontSize: '9pt', textColor: '#aaa' } } } };
+
+ vector = { axesStyles: { ticks: { fontSize: '9pt', textColor: '#999999' }, label: { textColor: '#999999' } },
+ grid: { drawBorder: 1, drawGridlines: 1, shadow: 0, borderWidth: 0.5, borderColor: '#a7d7f9', backgroundColor: '#fafafb' },
+ axes: { xaxis: { borderColor: "#a7d7f9", borderWidth: 1, label: { fontSize: '9pt', textColor: '#aaa' } },
+ yaxis: { borderColor: "#a7d7f9", borderWidth: 1, label: { fontSize: '9pt', textColor: '#aaa' } } } };
+
+ } ); // end of initilized $this object
+ } );
+})( window.jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/math/SRF_Math.php b/www/wiki/extensions/SemanticResultFormats/formats/math/SRF_Math.php
new file mode 100644
index 00000000..39685000
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/math/SRF_Math.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Various mathematical functions - sum, product, average, min and max.
+ *
+ * @licence GNU GPL v3+
+ *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Yaron Koren
+ * @author Nathan Yergler
+ */
+class SRFMath extends SMWResultPrinter {
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getName()
+ */
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf_printername_max, srf_printername_min, srf_printername_sum,
+ // srf_printername_product, srf_printername_average, srf_printername_median
+ return wfMessage( 'srf_printername_' . $this->mFormat )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::buildResult
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $results
+ *
+ * @return string
+ */
+ protected function buildResult( SMWQueryResult $results ) {
+
+ $number = $this->getResultText( $results, SMW_OUTPUT_HTML );
+
+ if ( count( $results->getPrintRequests() ) > 1 ) {
+ $outputformat = $results->getPrintRequests()[1]->getOutputFormat();
+ } else {
+ // no mainlabel
+ $outputformat = $results->getPrintRequests()[0]->getOutputFormat();
+ }
+
+ // if raw-format ("-") than skip formatNum()
+ if ( $outputformat != "-" ) {
+ $dataValue = \SMW\DataValueFactory::getInstance()->newDataValueByType( '_num' );
+ $number = $dataValue->getLocalizedFormattedNumber( $number );
+ }
+
+ return (string)$number;
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText()
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ $numbers = $this->getNumbers( $res );
+
+ if ( count( $numbers ) == 0 ) {
+ return $this->params['default'];
+ }
+
+ switch ( $this->mFormat ) {
+ case 'max':
+ return max( $numbers );
+ break;
+ case 'min':
+ return min( $numbers );
+ break;
+ case 'sum':
+ return array_sum( $numbers );
+ break;
+ case 'product':
+ return array_product( $numbers );
+ break;
+ case 'average':
+ return array_sum( $numbers ) / count( $numbers );
+ break;
+ case 'median':
+ sort( $numbers, SORT_NUMERIC );
+ $position = ( count( $numbers ) + 1 ) / 2 - 1;
+ return ( $numbers[ceil( $position )] + $numbers[floor( $position )] ) / 2;
+ break;
+ }
+ }
+
+ /**
+ * @param SMWQueryResult $res
+ *
+ * @return float[]
+ */
+ private function getNumbers( SMWQueryResult $res ) {
+ $numbers = [];
+
+ while ( $row = $res->getNext() ) {
+ foreach ( $row as $resultArray ) {
+ foreach ( $resultArray->getContent() as $dataItem ) {
+ self::addNumbersForDataItem( $dataItem, $numbers );
+ }
+ }
+ }
+
+ return $numbers;
+ }
+
+ /**
+ * @param SMWDataItem $dataItem
+ * @param float[] $numbers
+ */
+ private function addNumbersForDataItem( SMWDataItem $dataItem, array &$numbers ) {
+ switch ( $dataItem->getDIType() ) {
+ case SMWDataItem::TYPE_NUMBER:
+ $numbers[] = $dataItem->getNumber();
+ break;
+ case SMWDataItem::TYPE_CONTAINER:
+ foreach ( $dataItem->getDataItems() as $di ) {
+ self::addNumbersForDataItem( $di, $numbers );
+ }
+ break;
+ default:
+ }
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/media/MediaPlayer.php b/www/wiki/extensions/SemanticResultFormats/formats/media/MediaPlayer.php
new file mode 100644
index 00000000..613895d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/media/MediaPlayer.php
@@ -0,0 +1,358 @@
+<?php
+
+namespace SRF;
+
+use File;
+use FormatJson;
+use Html;
+use Skin;
+use SMW\ResultPrinter;
+use SMWDataItem;
+use SMWDataValue;
+use SMWOutputs;
+use SMWQueryResult;
+use SRFUtils;
+use Title;
+
+/**
+ * HTML5 Audio / Video media query printer
+ *
+ * This printer integrates jPlayer which is a HTML5 Audio / Video
+ * Javascript libray under GPL/MIT license.
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Media_format
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ * @ingroup QueryPrinter
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+/**
+ * This printer integrates jPlayer which is a HTML5 Audio / Video
+ * Javascript libray under GPL/MIT license.
+ *
+ * @ingroup SRF
+ * @ingroup QueryPrinter
+ */
+class MediaPlayer extends ResultPrinter {
+
+ /**
+ * Specifies valid mime types supported by jPlayer
+ *
+ * @var array
+ */
+ protected $validMimeTypes = [ 'mp3', 'mp4', 'webm', 'webma', 'webmv', 'ogg', 'oga', 'ogv', 'm4v', 'm4a' ];
+
+ /**
+ * @see SMWResultPrinter::getName
+ * @return string
+ */
+ public function getName() {
+ return $this->msg( 'srf-printername-media' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputMode ) {
+
+ // Data processing
+ $data = $this->getResultData( $result, $outputMode );
+
+ // Check if the data processing returned any results otherwise just bailout
+ if ( $data === [] ) {
+ if ( $this->params['default'] !== '' ) {
+ return $this->params['default'];
+ } else {
+ $result->addErrors( [ $this->msg( 'srf-no-results' )->inContentLanguage()->text() ] );
+ return '';
+ }
+ } else {
+ // Return formatted results
+ return $this->getFormatOutput( $data );
+ }
+ }
+
+ /**
+ * Returns an array with data
+ *
+ * @since 1.9
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultData( SMWQueryResult $result, $outputMode ) {
+
+ $data = [];
+
+ /**
+ * Get all values for all rows that belong to the result set
+ *
+ * @var SMWResultArray $rows
+ */
+ while ( $rows = $result->getNext() ) {
+ $rowData = [];
+ $mediaType = null;
+ $mimeType = null;
+
+ /**
+ * @var SMWResultArray $field
+ * @var SMWDataValue $dataValue
+ */
+ foreach ( $rows as $field ) {
+
+ // Label for the current property
+ $propertyLabel = $field->getPrintRequest()->getLabel();
+
+ // Label for the current subject
+ $subjectLabel = $field->getResultSubject()->getTitle()->getFullText();
+
+ if ( $propertyLabel === '' || $propertyLabel === '-' ) {
+ $propertyLabel = 'subject';
+ } elseif ( $propertyLabel === 'poster' ) {
+ // Label "poster" is a special case where we set the media type to video in order
+ // to use the same resources that can display video and cover art
+ // $data['mediaTypes'][] = 'video';
+ }
+
+ // Check if the subject itself is a media source
+ if ( $field->getResultSubject()->getTitle()->getNamespace() === NS_FILE && $mimeType === null ) {
+ list( $mediaType, $mimeType, $source ) = $this->getMediaSource(
+ $field->getResultSubject()->getTitle()
+ );
+ $rowData[$mimeType] = $source;
+ }
+
+ while ( ( $dataValue = $field->getNextDataValue() ) !== false ) {
+ // Get other data value item details
+ $value = $this->getDataValueItem(
+ $propertyLabel,
+ $dataValue,
+ $mediaType,
+ $mimeType,
+ $rowData
+ );
+ $rowData[$propertyLabel] = $value;
+ }
+ }
+
+ // Only select relevant source data that match the validMimeTypes
+ if ( $mimeType !== '' && in_array( $mimeType, $this->validMimeTypes ) ) {
+ $data['mimeTypes'][] = $mimeType;
+ $data['mediaTypes'][] = $mediaType;
+ $data[$subjectLabel] = $rowData;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Returns media source information
+ *
+ * @since 1.9
+ *
+ * @param Title $title
+ */
+ private function getMediaSource( Title $title ) {
+
+ // Find the file source
+ $source = wfFindFile( $title );
+ if ( $source ) {
+ // $source->getExtension() returns ogg even though it is a ogv/oga (same goes for m4p) file
+ // this doesn't help much therefore we do it ourselves
+ $extension = $source->getExtension();
+
+ if ( in_array( $extension, [ 'ogg', 'oga', 'ogv' ] ) ) {
+ $extension = strtolower( substr( $source->getName(), strrpos( $source->getName(), '.' ) + 1 ) );
+
+ // Xiph.Org recommends that .ogg only be used for Ogg Vorbis audio files
+ $extension = $extension === 'ogg' ? 'oga' : $extension;
+
+ $params = [ $extension === 'ogv' ? 'video' : 'audio', $extension, $source->getUrl() ];
+ } elseif ( in_array( $extension, [ 'm4v', 'm4a', 'm4p' ] ) ) {
+ $params = [ $extension === 'm4v' ? 'video' : 'audio', $extension, $source->getUrl() ];
+ } else {
+ list( $major, $minor ) = File::splitMime( $source->getMimeType() );
+ $params = [ $major, $extension, $source->getUrl() ];
+ }
+ } else {
+ $params = [];
+ }
+ return $params;
+ }
+
+ /**
+ * Returns single data value item
+ *
+ * @since 1.9
+ *
+ * @param string $label
+ * @param integer $type
+ * @param SMWDataValue $dataValue
+ * @param string $mediaType
+ * @param string $mimeType
+ *
+ * @return mixed
+ */
+ private function getDataValueItem( &$label, SMWDataValue $dataValue, &$mediaType, &$mimeType, &$rowData ) {
+
+ $dataItem = $dataValue->getDataItem();
+ $type = $dataItem->getDIType();
+
+ if ( $type === SMWDataItem::TYPE_WIKIPAGE ) {
+
+ $title = $dataItem->getTitle();
+
+ if ( $title instanceof Title && $title->getNamespace() === NS_FILE ) {
+
+ if ( $label === 'source' && $mimeType === null ) {
+
+ // Identify the media source
+ // and get media information
+ list( $mediaType, $mimeType, $source ) = $this->getMediaSource( $title );
+ $label = $mimeType;
+ return $source;
+ } elseif ( $label === 'poster' ) {
+ $mediaType = 'video';
+
+ // Get the cover art image url
+ $source = wfFindFile( $title );
+ return $source->getUrl();
+ }
+ }
+ }
+
+ if ( $type == SMWDataItem::TYPE_URI ) {
+
+ $source = $dataItem->getURI();
+ $mimeType = '';
+
+ // Get file extension from the URI
+ $extension = strtolower( substr( $source, strrpos( $source, '.' ) + 1 ) );
+
+ // Xiph.Org recommends that .ogg only be used for Ogg Vorbis audio files
+ if ( in_array( $extension, [ 'ogg', 'oga', 'ogv' ] ) ) {
+ $mimeType = $extension === 'ogg' ? 'oga' : $extension;
+ $mediaType = $extension === 'ogv' ? 'video' : 'audio';
+ } elseif ( in_array( $extension, [ 'm4v', 'm4a', 'm4p' ] ) ) {
+ $mimeType = $extension;
+ $mediaType = $extension === 'm4v' ? 'video' : 'audio';
+ } else {
+ $mimeType = $extension;
+ $mediaType = strpos( $extension, 'v' ) !== false ? 'video' : 'audio';
+ }
+
+ if ( $mimeType !== '' ) {
+ $rowData[$mimeType] = $source;
+ }
+
+ return $source;
+ }
+
+ return $dataValue->getWikiValue();
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.9
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ protected function getFormatOutput( $data ) {
+
+ $ID = 'srf-' . uniqid();
+ $this->isHTML = true;
+
+ // Get the media/mime types
+ if ( in_array( 'video', $data['mediaTypes'] ) ) {
+ $mediaType = 'video';
+ } else {
+ $mediaType = 'audio';
+ }
+ unset( $data['mediaTypes'] );
+
+ $mimeTypes = array_unique( $data['mimeTypes'] );
+ unset( $data['mimeTypes'] );
+
+ // Reassign output array
+ $output = [
+ 'data' => $data,
+ 'count' => count( $data ),
+ 'mediaType' => $mediaType,
+ 'mimeTypes' => implode( ',', $mimeTypes ),
+ 'inspector' => $this->params['inspector']
+ ];
+
+ $requireHeadItem = [ $ID => FormatJson::encode( $output ) ];
+ SMWOutputs::requireHeadItem( $ID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ SMWOutputs::requireResource( 'ext.jquery.jplayer.skin.' . $this->params['theme'] );
+ SMWOutputs::requireResource( 'ext.srf.formats.media' );
+
+ $processing = SRFUtils::htmlProcessingElement();
+
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => $this->params['class'] !== '' ? 'srf-media ' . $this->params['class'] : 'srf-media'
+ ],
+ $processing . Html::element(
+ 'div',
+ [
+ 'id' => $ID,
+ 'class' => 'media-container',
+ 'style' => 'display:none;'
+ ],
+ null
+ )
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.9
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['theme'] = [
+ 'message' => 'srf-paramdesc-theme',
+ 'default' => 'blue.monday',
+ 'values' => [ 'blue.monday', 'morning.light' ],
+ ];
+
+ $params['inspector'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-mediainspector',
+ 'default' => false,
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.css b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.css
new file mode 100644
index 00000000..0fdbba4a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.css
@@ -0,0 +1,39 @@
+/**
+ * This file is part of the Semantic Result Formats Media module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Media_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+div.jp-jplayer {
+ background-color: white;
+}
+
+div.jp-playlist ul {
+ list-style-image: none;
+}
+
+div.jp-type-single div.jp-playlist li {
+ border-bottom: 0px solid #EEE;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.js b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.js
new file mode 100644
index 00000000..751d1272
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.formats.media.js
@@ -0,0 +1,250 @@
+/**
+ * This file is part of the Semantic Result Formats Media module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Media_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /*global jPlayerPlaylist:true*/
+
+ /**
+ * Inheritance class for the srf.formats constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @abstract
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a media instance
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ * @extends srf.formats
+ */
+ srf.formats.media = function() {};
+
+ /**
+ * Public interface
+ * @ignore
+ */
+ srf.formats.media.prototype = {
+
+ /**
+ * Default values
+ *
+ * Size: The minimum size of jPlayer with the skin is
+ * 480x270px (270p)otherwise the controls do not have enough space
+ *
+ * @since 1.9
+ *
+ * @property
+ * @type Object
+ */
+ defaults: {
+ posterImage: srf.settings.get( 'srfgScriptPath' ) + '/formats/media/resources/images/audio.auto.cover.png',
+ size:{
+ '270p' : { width: '480', height: '270', cssClass: 'jp-video-270p' },
+ '360p' : { width: '640', height: '360', cssClass: 'jp-video-360p' }
+ },
+ jplayer : {
+ swfPath: srf.settings.get( 'srfgScriptPath' ) + '/resources/jquery/jplayer/jquery.jplayer.swf',
+ backgroundColor: '#FFFFFF',
+ wmode: 'window',
+ errorAlerts: smw.debug()
+ }
+ },
+
+ /**
+ * Returns an object from a parsed JSON string
+ *
+ * @since 1.9
+ *
+ * @param {string} context
+ *
+ * @return {Object}
+ */
+ parse: function( data ){
+ return typeof data === 'string' ? jQuery.parseJSON( data ) : data;
+ },
+
+ /**
+ * Return id's
+ *
+ * @since 1.9
+ *
+ * @param {string} ID
+ *
+ * @return Object
+ */
+ getId: function( ID ){
+ return {
+ 'playerId' : ID + '-player',
+ 'containerId' : ID + '-container',
+ 'inspectorId' : ID + '-inspector'
+ };
+ },
+
+ /**
+ * Returns player size
+ *
+ * @since 1.9
+ *
+ * @param {string} type
+ *
+ * @return {string}
+ */
+ getPlayerSize: function( type ){
+ return type === 'video' ? this.defaults.size['270p'] : '';
+ },
+
+ /**
+ * Returns adopted data array
+ *
+ * @since 1.9
+ *
+ * @param {string} source
+ * @param {string} mediaType
+ *
+ * @return Object
+ */
+ getData: function( source, mediaType ){
+ var data = [],
+ self = this;
+ $.each( source, function( index, value ) {
+
+ // Make sure we display a title
+ if ( value.title === undefined ) {
+ value.title = value.subject;
+ }
+
+ // Use a pseudo cover art in case audio and video display is mixed to avoid
+ // a black video screen for audio files with no cover art
+ if ( mediaType === 'video' && ( value.poster === undefined || value.poster.length === 0 ) ) {
+ value.poster = self.defaults.posterImage;
+ }
+ data.push ( value );
+ } );
+ return data;
+ },
+
+ /**
+ * Returns player template
+ *
+ * @since 1.9
+ *
+ * @param {string} ID
+ * @param {string} mediaType
+ * @param {string} mode
+ *
+ * @return Object
+ */
+ getPlayerTemplate: function( ID, mediaType, mode ){
+ var template = srf.template.jplayer[mediaType][mode];
+ return template( {
+ 'playerId': this.getId( ID ).playerId,
+ 'containerId': this.getId( ID ).containerId
+ } );
+ },
+
+ /**
+ * Media event inspector plugin displays information
+ * about the specified media element
+ *
+ * @since 1.9
+ *
+ * @param {string} ID
+ *
+ * @return Object
+ */
+ getInspector: function( ID ){
+ var self = this;
+ mw.loader.using( 'ext.jquery.jplayer.inspector', function () {
+ $( '#' + self.getId( ID ).inspectorId ).jPlayerInspector( {
+ jPlayer : $( '#' + self.getId( ID ).playerId )
+ } );
+ } );
+ return srf.template.jplayer.inspector( self.getId( ID ).inspectorId );
+ }
+ };
+
+ /**
+ * Implementation of a media instance
+ * @since 1.9
+ * @ignore
+ */
+ $( document ).ready( function() {
+
+ $( '.srf-media' ).each( function() {
+ var media = new srf.formats.media();
+
+ var $this = $( this ),
+ container = $this.find( '.media-container' ),
+ ID = container.attr( 'id' ),
+ json = media.parse( mw.config.get( ID ) ),
+ mode = json.count === 1 ? 'single' : 'multi';
+
+ // Specify jPlayer options
+ var jPlayerSelector = {
+ jPlayer: '#' + media.getId( ID ).playerId,
+ cssSelectorAncestor: '#' + media.getId( ID ).containerId
+ },
+ jPlayerOptions = {
+ size: media.getPlayerSize( json.mediaType ),
+ supplied: json.mimeTypes
+ };
+
+ // Init player template
+ if ( json.mediaType ){
+ container.prepend( media.getPlayerTemplate( ID, json.mediaType, mode ) );
+ }
+
+ // Init media event inspector
+ if ( json.inspector ){
+ container.append( media.getInspector( ID ) );
+ }
+
+ // Create jPlayer instance
+ var jPlayerInstance = new jPlayerPlaylist(
+ jPlayerSelector,
+ media.getData( json.data, json.mediaType ),
+ // Merge defaults and options, without modifying the defaults
+ $.extend( {}, media.defaults.jplayer, jPlayerOptions )
+ );
+
+ // Release container and hide the spinner
+ $this.find( '.srf-spinner' ).hide();
+ container.show();
+
+ } );
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.template.jplayer.js b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.template.jplayer.js
new file mode 100644
index 00000000..deda9971
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/ext.srf.template.jplayer.js
@@ -0,0 +1,242 @@
+/**
+ * This file is part of the Semantic Result Formats Media module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Media_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ignore
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /*jshint scripturl:true*/
+
+ /**
+ * Helper method
+ * @ignore
+ */
+ var h = mw.html;
+
+ /**
+ * Internationalization (i18n) support
+ *
+ * @since 1.9
+ * @ignore
+ */
+ var _i18n = {
+ 'previous' : mw.msg( 'srf-ui-mediaplayer-label-previous' ),
+ 'pause' : mw.msg( 'srf-ui-mediaplayer-label-pause' ),
+ 'play' : mw.msg( 'srf-ui-mediaplayer-label-play' ),
+ 'next' : mw.msg( 'srf-ui-mediaplayer-label-next' ),
+ 'stop' : mw.msg( 'srf-ui-mediaplayer-label-stop' ),
+ 'mute' : mw.msg( 'srf-ui-mediaplayer-label-mute' ),
+ 'unmute' : mw.msg( 'srf-ui-mediaplayer-label-unmute' ),
+ 'volumeMax' : mw.msg( 'srf-ui-mediaplayer-label-volume-max' ),
+ 'shuffle' : mw.msg( 'srf-ui-mediaplayer-label-shuffle' ),
+ 'shuffleOff' : mw.msg( 'srf-ui-mediaplayer-label-shuffle-off' ),
+ 'repeat' : mw.msg( 'srf-ui-mediaplayer-label-repeat' ),
+ 'repeatOff' : mw.msg( 'srf-ui-mediaplayer-label-repeat-off' ),
+ 'fullScreen' : mw.msg( 'srf-ui-mediaplayer-label-full-screen' ),
+ 'restoreScreen' : mw.msg( 'srf-ui-mediaplayer-label-restore-screen' )
+ };
+
+ /**
+ * Inheritance class for the srf.template constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @abstract
+ */
+ srf.template = srf.template || {};
+
+ /**
+ * Base constructor for objects representing a template instance
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ * @extends srf.template
+ */
+ srf.template.jplayer = {
+
+ /**
+ * Placeholder for the media inspector
+ *
+ * @return object
+ */
+ inspector : function( ID ) { return h.element( 'div', { 'id' : ID }, '' );
+ },
+
+ /**
+ * Audio player template
+ *
+ * @return object
+ */
+ audio: {
+ single : function( options ) { return h.element( 'div', { 'id' : options.playerId, 'class': 'jp-jplayer' } ) +
+ h.element( 'div', { 'id' : options.containerId , 'class': 'jp-audio' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-type-single' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-gui jp-interface' },
+ new h.Raw( h.element( 'ul', { 'class': 'jp-controls' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-play' , 'tabindex' : 1, 'title': _i18n.play }, _i18n.play ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-pause' , 'tabindex' : 1, 'title': _i18n.pause }, _i18n.pause ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-stop' , 'tabindex' : 1, 'title': _i18n.stop }, _i18n.stop ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-mute' , 'tabindex' : 1, 'title' : _i18n.mute }, _i18n.mute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-unmute' , 'tabindex' : 1, 'title': _i18n.unmute }, _i18n.unmute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-volume-max' , 'tabindex' : 1, 'title': _i18n.volumeMax }, _i18n.volumeMax ) ) )
+ ) ) +
+ // progress
+ h.element( 'div', { 'class': 'jp-progress' }, new h.Raw ( h.element( 'div', { 'class': 'jp-seek-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-play-bar' }, '' ) ) ) ) ) +
+ // Volumn
+ h.element( 'div', { 'class': 'jp-volume-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-volume-bar-value' }, '' ) ) ) +
+ // Time
+ h.element( 'div', { 'class': 'jp-time-holder' }, new h.Raw ( h.element( 'div', { 'class': 'jp-current-time' }, '' ) + h.element( 'div', { 'class': 'jp-duration' }, '' ) ) ) +
+ //
+ h.element( 'ul', { 'class': 'jp-toggles' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat' , 'tabindex' : 1, 'title' : _i18n.repeat }, _i18n.repeat ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat-off' , 'tabindex' : 1, 'title' : _i18n.repeatOff }, _i18n.repeatOff ) ) )
+ ) )
+ ) ) + h.element( 'div', { 'class': 'jp-playlist' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) ) );
+ },
+ multi : function( options ) { return h.element( 'div', { 'id' : options.playerId, 'class': 'jp-jplayer' } ) +
+ h.element( 'div', { 'id' : options.containerId , 'class': 'jp-audio' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-type-playlist' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-gui jp-interface' },
+ new h.Raw( h.element( 'ul', { 'class': 'jp-controls' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-previous' , 'tabindex' : 1, 'title': _i18n.previous }, _i18n.previous ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-play' , 'tabindex' : 1, 'title': _i18n.play }, _i18n.play ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-pause' , 'tabindex' : 1, 'title': _i18n.pause }, _i18n.pause ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-next' , 'tabindex' : 1, 'title': _i18n.next }, _i18n.next ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-stop' , 'tabindex' : 1, 'title': _i18n.stop }, _i18n.stop ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-mute' , 'tabindex' : 1, 'title' : _i18n.mute }, _i18n.mute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-unmute' , 'tabindex' : 1, 'title': _i18n.unmute }, _i18n.unmute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-volume-max' , 'tabindex' : 1, 'title': _i18n.volumeMax }, _i18n.volumeMax ) ) )
+ ) ) +
+ // progress
+ h.element( 'div', { 'class': 'jp-progress' }, new h.Raw ( h.element( 'div', { 'class': 'jp-seek-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-play-bar' }, '' ) ) ) ) ) +
+ // Volumn
+ h.element( 'div', { 'class': 'jp-volume-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-volume-bar-value' }, '' ) ) ) +
+ // Time
+ h.element( 'div', { 'class': 'jp-time-holder' }, new h.Raw ( h.element( 'div', { 'class': 'jp-current-time' }, '' ) + h.element( 'div', { 'class': 'jp-duration' }, '' ) ) ) +
+ //
+ h.element( 'ul', { 'class': 'jp-toggles' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-shuffle' , 'tabindex' : 1, 'title' : _i18n.shuffle }, _i18n.shuffle ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-shuffle-off' , 'tabindex' : 1, 'title' : _i18n.shuffleOff }, _i18n.shuffleOff ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat' , 'tabindex' : 1, 'title' : _i18n.repeat }, _i18n.repeat ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat-off' , 'tabindex' : 1, 'title' : _i18n.repeatOff }, _i18n.repeatOff ) ) )
+ ) )
+ ) ) + h.element( 'div', { 'class': 'jp-playlist' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) ) );
+ }
+ },
+
+ /**
+ * Video player template
+ *
+ * @return object
+ */
+ video: {
+ single : function( options ) { return h.element( 'div', { 'id' : options.containerId , 'class': 'jp-video' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-type-single' },
+ new h.Raw(
+ h.element( 'div', { 'id': options.playerId, 'class': 'jp-jplayer' } ) +
+ h.element( 'div', { 'class': 'jp-gui' },
+ new h.Raw(
+ h.element( 'div', { 'class': 'jp-video-play' }, new h.Raw( h.element( 'a', { 'href' : 'javascript:;', 'class' : 'jp-video-play-icon', 'tabindex' : 1 }, 'play' ) ) )+
+ h.element( 'div', { 'class': 'jp-interface' },
+ new h.Raw (
+ // progress
+ h.element( 'div', { 'class': 'jp-progress' }, new h.Raw ( h.element( 'div', { 'class': 'jp-seek-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-play-bar' }, '' ) ) ) ) ) +
+ h.element( 'div', { 'class': 'jp-current-time' }, '' ) +
+ h.element( 'div', { 'class': 'jp-duration' }, '' ) +
+ h.element( 'div', { 'class': 'jp-controls-holder' },
+ new h.Raw( h.element( 'ul', { 'class': 'jp-controls' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-play' , 'tabindex' : 1, 'title': _i18n.play }, _i18n.play ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-pause' , 'tabindex' : 1, 'title': _i18n.pause }, _i18n.pause ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-stop' , 'tabindex' : 1, 'title' : _i18n.stop }, _i18n.stop ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-mute' , 'tabindex' : 1, 'title' : _i18n.mute }, _i18n.mute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-unmute' , 'tabindex' : 1, 'title' : _i18n.unmute }, _i18n.unmute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-volume-max' , 'tabindex' : 1, 'title': _i18n.volumeMax }, _i18n.volumeMax ) ) )
+ ) ) + h.element( 'div', { 'class': 'jp-volume-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-volume-bar-value' }, '' ) ) ) +
+ h.element( 'ul', { 'class': 'jp-toggles' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-full-screen' , 'tabindex' : 1, 'title' : _i18n.fullScreen }, _i18n.fullScreen ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-restore-screen' , 'tabindex' : 1, 'title': _i18n.restoreScreen }, _i18n.restoreScreen ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat' , 'tabindex' : 1, 'title' : _i18n.repeat }, _i18n.repeat ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat-off' , 'tabindex' : 1, 'title': _i18n.repeatOff }, _i18n.repeatOff ) ) )
+ ) ) ) ) + h.element( 'div', { 'class': 'jp-title' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) ) ) +
+ h.element( 'div', { 'class': 'jp-playlist' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) ) );
+ },
+ multi : function( options ) { return h.element( 'div', { 'id' : options.containerId , 'class': 'jp-video' },
+ new h.Raw( h.element( 'div', { 'class': 'jp-type-playlist' },
+ new h.Raw(
+ h.element( 'div', { 'id': options.playerId, 'class': 'jp-jplayer' } ) +
+ h.element( 'div', { 'class': 'jp-gui' },
+ new h.Raw(
+ h.element( 'div', { 'class': 'jp-video-play' }, new h.Raw( h.element( 'a', { 'href' : 'javascript:;', 'class' : 'jp-video-play-icon', 'tabindex' : 1 }, 'play' ) ) )+
+ h.element( 'div', { 'class': 'jp-interface' },
+ new h.Raw (
+ // progress
+ h.element( 'div', { 'class': 'jp-progress' }, new h.Raw ( h.element( 'div', { 'class': 'jp-seek-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-play-bar' }, '' ) ) ) ) ) +
+ h.element( 'div', { 'class': 'jp-current-time' }, '' ) +
+ h.element( 'div', { 'class': 'jp-duration' }, '' ) +
+ h.element( 'div', { 'class': 'jp-controls-holder' },
+ new h.Raw( h.element( 'ul', { 'class': 'jp-controls' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-previous' , 'tabindex' : 1, 'title': _i18n.previous }, _i18n.previous ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-play' , 'tabindex' : 1, 'title': _i18n.play }, _i18n.play ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-pause' , 'tabindex' : 1, 'title': _i18n.pause }, _i18n.pause ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-next' , 'tabindex' : 1, 'title': _i18n.next }, _i18n.next ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-stop' , 'tabindex' : 1, 'title' : _i18n.stop }, _i18n.stop ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-mute' , 'tabindex' : 1, 'title' : _i18n.mute }, _i18n.mute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-unmute' , 'tabindex' : 1, 'title' : _i18n.unmute }, _i18n.unmute ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-volume-max' , 'tabindex' : 1, 'title': _i18n.volumeMax }, _i18n.volumeMax ) ) )
+ )
+ ) + h.element( 'div', { 'class': 'jp-volume-bar' }, new h.Raw ( h.element( 'div', { 'class': 'jp-volume-bar-value' }, '' ) ) ) +
+ h.element( 'ul', { 'class': 'jp-toggles' },
+ new h.Raw (
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-full-screen' , 'tabindex' : 1, 'title' : _i18n.fullScreen }, _i18n.fullScreen ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-restore-screen' , 'tabindex' : 1, 'title': _i18n.restoreScreen }, _i18n.restoreScreen ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-shuffle' , 'tabindex' : 1, 'title' : _i18n.shuffle }, _i18n.shuffle ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-shuffle-off' , 'tabindex' : 1, 'title': _i18n.shuffleOff }, _i18n.shuffleOff ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat' , 'tabindex' : 1, 'title' : _i18n.repeat }, _i18n.repeat ) ) ) +
+ h.element( 'li', {}, new h.Raw( h.element( 'a', { 'href' : 'javascript:', 'class' : 'jp-repeat-off' , 'tabindex' : 1, 'title': _i18n.repeatOff }, _i18n.repeatOff ) ) )
+ ) ) ) ) + h.element( 'div', { 'class': 'jp-title' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) )
+ ) + h.element( 'div', { 'class': 'jp-playlist' }, new h.Raw( h.element( 'ul', {}, new h.Raw( h.element( 'li', {}, '' ) ) ) ) ) )
+ ) ) );
+ }
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/media/resources/images/audio.auto.cover.png b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/images/audio.auto.cover.png
new file mode 100644
index 00000000..55b81776
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/media/resources/images/audio.auto.cover.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShow.php b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShow.php
new file mode 100644
index 00000000..81b92304
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShow.php
@@ -0,0 +1,182 @@
+<?php
+/**
+ * File holding the SRF_SlideShow class
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+/**
+ * The SRF_SlideShow class.
+ *
+ * @ingroup SemanticResultFormats
+ */
+class SRFSlideShow extends SMWResultPrinter {
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-slideshow' )->text();
+ }
+
+ /**
+ * Return serialised results in specified format.
+ * Implemented by subclasses.
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+
+ $html = '';
+ $id = uniqid();
+
+ // build an array of article IDs contained in the result set
+ $objects = [];
+ foreach ( $res->getResults() as $key => $dataItem ) {
+
+ $objects[] = [ $dataItem->getTitle()->getArticleId() ];
+
+ $html .= $key . ': ' . $dataItem->getSerialization() . "<br>\n";
+ }
+
+ // build an array of data about the printrequests
+ $printrequests = [];
+ foreach ( $res->getPrintRequests() as $key => $printrequest ) {
+ $data = $printrequest->getData();
+ if ( $data instanceof SMWPropertyValue ) {
+ $name = $data->getDataItem()->getKey();
+ } else {
+ $name = null;
+ }
+ $printrequests[] = [
+ $printrequest->getMode(),
+ $printrequest->getLabel(),
+ $name,
+ $printrequest->getOutputFormat(),
+ $printrequest->getParameters(),
+ ];
+
+ }
+
+ // write out results and query params into JS arrays
+ // Define the srf_filtered_values array
+ SMWOutputs::requireScript(
+ 'srf_slideshow',
+ Html::inlineScript(
+ 'srf_slideshow = {};'
+ )
+ );
+
+ SMWOutputs::requireScript(
+ 'srf_slideshow' . $id,
+ Html::inlineScript(
+ 'srf_slideshow["' . $id . '"] = ' . json_encode(
+ [
+ $objects,
+ $this->params['template'],
+ $this->params['delay'] * 1000,
+ $this->params['height'],
+ $this->params['width'],
+ $this->params['nav controls'],
+ $this->params['effect'],
+ json_encode( $printrequests ),
+ ]
+ ) . ';'
+ )
+ );
+
+ SMWOutputs::requireResource( 'ext.srf.slideshow' );
+
+ if ( $this->params['nav controls'] ) {
+ SMWOutputs::requireResource( 'jquery.ui.slider' );
+ }
+
+ return Html::element(
+ 'div',
+ [
+ 'id' => $id,
+ 'class' => 'srf-slideshow ' . $id . ' ' . $this->params['class']
+ ]
+ );
+ }
+
+ /**
+ * Check whether a "further results" link would normally be generated for this
+ * result set with the given parameters.
+ *
+ * @param SMWQueryResult $results
+ *
+ * @return boolean
+ */
+ protected function linkFurtherResults( SMWQueryResult $results ) {
+ return false;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['template'] = [
+ 'default' => '',
+ 'message' => 'smw_paramdesc_template',
+ ];
+
+ // TODO: Implement named args
+// $params['named args'] = new Parameter( 'named args', Parameter::TYPE_BOOLEAN, false );
+// $params['named args']->setMessage( 'smw_paramdesc_named_args' );
+
+ $params['class'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-class',
+ ];
+
+ $params['height'] = [
+ 'default' => '100px',
+ 'message' => 'srf-paramdesc-height',
+ ];
+
+ $params['width'] = [
+ 'default' => '200px',
+ 'message' => 'srf-paramdesc-width',
+ ];
+
+ $params['delay'] = [
+ 'type' => 'integer',
+ 'default' => 5,
+ 'message' => 'srf-paramdesc-delay',
+ ];
+
+ $params['nav controls'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-navigation-controls',
+ ];
+
+ $params['effect'] = [
+ 'default' => 'none',
+ 'message' => 'srf-paramdesc-effect',
+ 'values' => [
+ 'none',
+ 'slide left',
+ 'slide right',
+ 'slide up',
+ 'slide down',
+ 'fade',
+ 'hide',
+ ],
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShowApi.php b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShowApi.php
new file mode 100644
index 00000000..b1c2430c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/SRF_SlideShowApi.php
@@ -0,0 +1,184 @@
+<?php
+
+use ParamProcessor\ParamDefinition;
+use SMW\DataValueFactory;
+
+/**
+ * API module to retrieve formatted results for a given page, printouts and template.
+ *
+ * @author Stephan Gambke
+ * @ingroup SemanticResultFormats
+ */
+class SRFSlideShowApi extends ApiBase {
+
+ /**
+ * Evaluates the parameters, performs the query, and sets up the result.
+ *
+ * The result data is stored in the ApiResult object available through getResult().
+ */
+ public function execute() {
+
+ // get request parameters
+ $requestParams = $this->extractRequestParams();
+
+ $title = Title::newFromID( $requestParams['pageid'] )->getPrefixedText();
+
+ $rp = new SMWListResultPrinter( 'template', true );
+
+ // get defaults of parameters for the 'template' result format as array of ParamDefinition
+ $paramDefinitions = ParamDefinition::getCleanDefinitions( $rp->getParamDefinitions( [] ) );
+
+ // transform into normal key-value array
+ $queryParams = [];
+
+ foreach ( $paramDefinitions as $def ) {
+ $queryParams[$def->getName()] = $def->getDefault();
+ }
+
+ // add/set specific parameters for this call
+ $queryParams = array_merge(
+ $queryParams,
+ [
+ 'format' => 'template',
+ 'template' => $requestParams['template'],
+ 'mainlabel' => '',
+ 'sort' => '',
+ 'order' => '',
+ 'intro' => null,
+ 'outro' => null,
+ 'searchlabel' => null,
+ 'link' => null,
+ 'default' => null,
+ 'headers' => null,
+ 'introtemplate' => '',
+ 'outrotemplate' => '',
+ ]
+ );
+
+ // A bit of a hack since the parser isn't run, avoids [[SMW::off]]/[[SMW::on]]
+ $queryParams['import-annotation'] = 'true';
+
+ // transform query parameters into format suitable for SMWQueryProcessor
+ $queryParams = SMWQueryProcessor::getProcessedParams( $queryParams, [] );
+
+ // build array of printouts
+
+ $printoutsRaw = json_decode( $requestParams['printouts'], true );
+ $printouts = [];
+
+ foreach ( $printoutsRaw as $printoutData ) {
+
+ // if printout mode is PRINT_PROP
+ if ( $printoutData[0] == SMWPrintRequest::PRINT_PROP ) {
+ // create property from property key
+ $data = DataValueFactory::getInstance()->newPropertyValueByLabel( $printoutData[2] );
+ } else {
+ $data = null;
+ }
+
+ // create printrequest from request mode, label, property name, output format, parameters
+ $printouts[] = new SMWPrintRequest(
+ $printoutData[0],
+ $printoutData[1],
+ $data,
+ $printoutData[3],
+ $printoutData[4]
+ );
+ }
+
+ // query SMWQueryProcessor and set query result as API call result
+ $query = SMWQueryProcessor::createQuery(
+ '[[' . $title . ']]',
+ $queryParams,
+ SMWQueryProcessor::INLINE_QUERY,
+ '',
+ $printouts
+ );
+
+ $this->getResult()->addValue(
+ null,
+ $requestParams['pageid'],
+ SMWQueryProcessor::getResultFromQuery( $query, $queryParams, SMW_OUTPUT_HTML, SMWQueryProcessor::INLINE_QUERY )
+ );
+ }
+
+ /**
+ * Returns the description string for this module
+ *
+ * @return mixed string or array of strings
+ */
+ protected function getDescription() {
+ return [
+ 'API module used by the SlideShow result printer to retrieve formatted results.',
+ 'This module is should not be called directly.'
+ ];
+ }
+
+ /**
+ * Returns usage examples for this module. Return false if no examples are available.
+ *
+ * @return bool|string|array
+ */
+ protected function getExamples() {
+ return false;
+ }
+
+ public function getHelpUrls() {
+ return 'http://semantic-mediawiki.org/wiki/Help:Slideshow_format';
+ }
+
+ /**
+ * Returns an array of allowed parameters
+ *
+ * @return array|bool
+ */
+ protected function getAllowedParams() {
+ return [
+ 'pageid' => [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_ISMULTI => false,
+ ApiBase::PARAM_REQUIRED => true,
+ ],
+ 'template' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_ISMULTI => false,
+ ApiBase::PARAM_REQUIRED => true,
+ ],
+ 'printouts' => [
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_ISMULTI => false,
+ ApiBase::PARAM_REQUIRED => false,
+ ApiBase::PARAM_DFLT => '[]',
+ ],
+ ];
+ }
+
+ /**
+ * Returns an array of parameter descriptions.
+ * Don't call this function directly: use getFinalParamDescription() to
+ * allow hooks to modify descriptions as needed.
+ *
+ * @return array|bool False on no parameter descriptions
+ */
+ protected function getParamDescription() {
+ return [
+ 'pageid' => 'Id of the page (subject) to be displayed',
+ 'template' => 'Template to use for formatting',
+ 'printouts' => 'Printouts to send to the template',
+ ];
+ }
+
+ /**
+ * Returns a string that identifies the version of the extending class.
+ * Typically includes the class name, the svn revision, timestamp, and
+ * last author. Usually done with SVN's Id keyword
+ *
+ * @return string
+ */
+ public function getVersion() {
+ global $srfgIP;
+ $gitSha1 = SpecialVersion::getGitHeadSha1( $srfgIP );
+ return __CLASS__ . '-' . SRF_VERSION . ( $gitSha1 !== false ) ? ' (' . substr( $gitSha1, 0, 7 ) . ')' : '';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.css b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.css
new file mode 100644
index 00000000..8673db30
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.css
@@ -0,0 +1,43 @@
+/*
+ Main stylesheet for the slideshow query printer
+*/
+
+.srf-slideshow .slideshow-nav {
+ border: 1px solid #aaa;
+ border-radius: 3px;
+ background: #f1f2ff;
+ margin: 0 1em;
+}
+
+.srf-slideshow .ui-slider-handle {
+ outline: none;
+ text-decoration: none;
+ width: 0;
+ padding: 0 1em;
+}
+
+.srf-slideshow .slideshow-nav-readout {
+ margin: 0;
+ text-align: center;
+ position: relative;
+ top: -0.3em;
+ color: #000;
+}
+
+.srf-slideshow .slideshow-viewport {
+ position: relative;
+}
+
+.srf-slideshow .slideshow-element-wrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+}
+
+.srf-slideshow .slideshow-element {
+ background-color: white;
+ position: relative;
+ top:0;
+ left:0;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.js b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.js
new file mode 100644
index 00000000..4f019eba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/slideshow/resources/ext.srf.slideshow.js
@@ -0,0 +1,489 @@
+/**
+ * File holding the slideshow plugin
+ *
+ * @author Stephan Gambke
+ * @file
+ * @ingroup SemanticResultFormats
+ */
+
+/*global jQuery, mediaWiki */
+/*global srf_slideshow */
+( function ( $, mw ){
+
+ 'use strict';
+
+ $.fn.slideshow = function ( options ) {
+
+ var results = options.data[0];
+ var template = options.data[1];
+ var delay = options.data[2];
+ var height = options.data[3];
+ var width = options.data[4];
+ var navControls = options.data[5];
+ var effect = options.data[6];
+ var printrequests = options.data[7];
+
+ var requestedIndex = 0;
+ var timeout;
+ var nav = null;
+
+ var targetDiv = $( '<div class="slideshow-viewport" style="height: ' + height + '; width: ' + width + ';" >' );
+
+ // functions used
+ var fetchResult, restartTimer, switchTo;
+
+ fetchResult = function ( index, moveForward, speed ) {
+
+ // mark as loading
+ results[index][1] = true;
+
+ var pageId = results[index][0];
+
+ $.ajax( {
+ // request type
+ type: 'POST',
+
+ // the URL to which the request is sent
+ url: mw.util.wikiScript( 'api' ),
+
+ // data to be sent to the server
+ data: {
+ action: 'ext.srf.slideshow.show',
+ format: 'json',
+ pageid: pageId,
+ template: template,
+ printouts: printrequests
+ },
+
+ // type of data that we're expecting back from the server
+ dataType: 'json',
+
+ // Function to be called if the request succeeds
+ success: function ( result ){
+ // create element from returned text
+ var element;
+ if ( "error" in result ) {
+ element = $( '<div class="slideshow-element error">' + result[ "error" ][ "info" ] + '</div>' );
+ } else {
+ element = $( '<div class="slideshow-element">' + result[ pageId ] + '</div>' );
+ }
+
+ // create wrapper, basically a mask to hide the overflow when animating
+ var wrapper = $( '<div class="slideshow-element-wrapper">' );
+
+ // insert element
+ wrapper
+ .append( element );
+
+ // store the wrapper with the attached element
+ results[index][1] = wrapper;
+
+ // is the loaded item the requested one, switch to it immediately
+ if ( requestedIndex === index ) {
+ switchTo( requestedIndex, moveForward, speed );
+ }
+ }
+ } );
+
+ };
+
+ restartTimer = function (){
+
+ // if necessary clear runnning timeout
+ if ( typeof timeout !== 'undefined' ) {
+ window.clearTimeout( timeout );
+ }
+
+ if ( delay > 0 ) {
+
+ // wait some time then switch to next result item
+ timeout = window.setTimeout( function (){
+
+ var nextIndex = requestedIndex + 1;
+
+ if ( nextIndex >= results.length ) {
+ nextIndex = 0;
+ }
+
+ // switch to next item
+ if ( nav !== null ) {
+ switchTo( nextIndex, nextIndex > requestedIndex );
+ nav.slider( 'value', requestedIndex + 1 );
+ } else {
+ switchTo( nextIndex );
+ }
+
+ }, delay );
+ }
+ };
+
+ switchTo = function ( index, moveForward, speed ) {
+
+ var animateForward, animateBackward;
+
+ switch ( effect ) {
+ case 'slide left':
+ animateForward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'left': ( targetDiv.outerWidth() * 1.1 ) + 'px'} )
+ .animate( {'left': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'left': ( - oldWrapper.outerWidth() ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'left': ( - targetDiv.outerWidth() * 1.1 ) + 'px'} )
+ .animate( {'left': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'left': ( oldWrapper.outerWidth() ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ break;
+ case 'slide right':
+ animateForward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'left': ( - newWrapper.outerWidth() ) + 'px'} )
+ .animate( {'left': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'left': ( targetDiv.outerWidth() * 1.1 ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'left': ( newWrapper.outerWidth() ) + 'px'} )
+ .animate( {'left': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'left': ( - targetDiv.outerWidth() * 1.1 ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ break;
+ case 'slide up':
+ animateForward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'top': ( targetDiv.outerHeight() * 1.1 ) + 'px'} )
+ .animate( {'top': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'top': ( - oldWrapper.outerHeight() ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'top': ( - targetDiv.outerHeight() * 1.1 ) + 'px'} )
+ .animate( {'top': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'top': ( oldWrapper.outerHeight() ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ break;
+ case 'slide down':
+ animateForward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'top': ( - newWrapper.outerHeight() ) + 'px'} )
+ .animate( {'top': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'top': ( targetDiv.outerHeight() * 1.1 ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'top': ( newWrapper.outerHeight() ) + 'px'} )
+ .animate( {'top': '0px'}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .animate( {'top': ( - targetDiv.outerHeight() * 1.1 ) + 'px'}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }} );
+ };
+
+ break;
+ case 'fade':
+ animateForward = animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+ // need to set dimensions, might have changed since last cycle
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() );
+
+ newWrapper.children()
+ .css( {'opacity': 0} )
+ .animate( {'opacity': 1}, {duration: speed, easing:'linear', queue: true} );
+
+ // slide out old element, then detach it
+ oldWrapper.children()
+ .css( {'opacity': 1} )
+ .animate( {'opacity': 0}, {duration: speed, easing:'linear', queue: true, complete: function (){
+ $( this ).parent().detach();
+ }
+ } );
+ };
+
+ break;
+ case 'hide':
+ animateForward = animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+ // insert next result into document
+ targetDiv.append( newWrapper );
+
+// // need to set dimensions, might have changed since last cycle
+// newWrapper.children()
+// .width( targetDiv.width() )
+// .height( targetDiv.height() );
+//
+// // slide out old element, then detach it
+// oldWrapper.children()
+// .width( targetDiv.width() )
+// .height( targetDiv.height() );
+
+ // set start values
+ newWrapper
+ .width( 0 )
+ .height( 0 )
+ .css( {'opacity': 0} );
+
+
+ if ( oldWrapper.length > 0 ) {
+ oldWrapper
+ .animate( { 'opacity': 0, 'width': 0, 'height': 0 },
+ { duration: speed, easing:'linear', queue: true,
+ complete: function (){
+ $( this ).detach();
+
+ newWrapper
+ .css( { 'opacity': 0, 'width': 0, 'height': 0 } )
+ .animate( { 'opacity': 1, 'width': targetDiv.width(), 'height': targetDiv.height()}, {
+ duration: speed, easing:'linear', queue: true
+ } );
+ }
+ } );
+ } else {
+ newWrapper
+ .animate( { 'opacity': 1, 'width': targetDiv.width(), 'height': targetDiv.height()}, {
+ duration: speed, easing:'linear', queue: true
+ } );
+ }
+ };
+
+ break;
+ default:
+ animateForward = animateBackward = function ( targetDiv, oldWrapper, newWrapper, speed ) {
+
+ // need to set dimensions, might have changed since last cycle
+ // insert next result into document
+ newWrapper
+ .width( targetDiv.width() )
+ .height( targetDiv.height() )
+ .appendTo( targetDiv );
+
+ // slide out old element, then detach it
+ oldWrapper.detach();
+ };
+
+ break;
+ }
+
+ // set new requested index
+ requestedIndex = index;
+
+ // set speed to default if not given as param
+ if ( typeof speed === 'undefined' ) {
+ speed = 'slow';
+ }
+
+ // set speed to default if not given as param
+ if ( typeof moveForward === 'undefined' ) {
+ moveForward = true;
+ }
+
+ // if requested result item not available and not loading
+ if ( results[index].length === 1 ) {
+ // fetch it and switch immediately
+ fetchResult( index, moveForward, speed );
+ } else {
+ // is requested result item available?
+ if ( typeof results[index][1] !== 'boolean' ) {
+
+ // find next result
+ var newWrapper = results[index][1];
+
+ // if newWrapper still attached, detach it first
+ if ( newWrapper.parent().length > 0 ) {
+ newWrapper.detach();
+ }
+
+ // find current result (or sometimes current results)
+ var oldWrapper = targetDiv.children();
+
+ // set start position for animation and slide in
+ if ( moveForward ) {
+ animateForward( targetDiv, oldWrapper, newWrapper, speed );
+ } else {
+ animateBackward( targetDiv, oldWrapper, newWrapper, speed );
+ }
+
+ // calculate index of next result item
+ var nextIndex = index + 1;
+ if ( nextIndex >= results.length ) {
+ nextIndex = 0;
+ }
+
+ // preload of next item necessary?
+ if ( results[nextIndex].length === 1 ) {
+ fetchResult( nextIndex );
+ }
+
+ restartTimer();
+
+ } // else just wait until loading has finished
+ }
+ };
+
+ // Build widget
+
+ this
+ .width( width )
+ .append( targetDiv );
+
+ if ( navControls ) {
+ var slideshow = this;
+ mw.loader.using( 'jquery.ui.slider', function (){
+ var readout = $( '<div class="slideshow-nav-readout">' + 1 + '</div>' );
+ nav = $( '<div class="slideshow-nav" >' );
+
+ nav.slider( {
+ animate: true,
+ min: 1,
+ max: results.length,
+ value: 1,
+ slide: function ( event, ui ) {
+ readout.empty().append( ui.value );
+ switchTo( ui.value - 1, requestedIndex < ui.value - 1 );
+ },
+ change: function ( event, ui ) {
+ readout.empty().append( ui.value );
+ }
+ } );
+
+ nav.find( '.ui-slider-handle' )
+ .append( readout );
+
+ nav
+ .appendTo( slideshow );
+ } );
+
+ }
+
+ // start the show
+ switchTo( 0, true, 0 );
+
+
+
+
+ };
+
+ // initialize all slideshows
+ $( function (){
+ var id;
+ for ( id in srf_slideshow ) {
+ $( '#' + id ).slideshow( {
+ 'id' : id,
+ 'data' : srf_slideshow[ id ]
+ } );
+ }
+ } );
+
+}( jQuery, mediaWiki ) );
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/sparkline/SRF_Sparkline.php b/www/wiki/extensions/SemanticResultFormats/formats/sparkline/SRF_Sparkline.php
new file mode 100644
index 00000000..782e64ae
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/sparkline/SRF_Sparkline.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * A query printer for sparklines (small inline charts) using the sparkline
+ * JavaScript library.
+ *
+ * @since 1.8
+ * @licence GNU GPL v2 or later
+ *
+ * @author mwjames
+ */
+class SRFSparkline extends SMWAggregatablePrinter {
+
+ /**
+ * Corresponding message name
+ *
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-sparkline' )->text();
+ }
+
+ /**
+ * Prepare data output
+ *
+ * @since 1.8
+ *
+ * @param array $data label => value
+ */
+ protected function getFormatOutput( array $data ) {
+
+ //Init
+ $dataObject = [];
+
+ static $statNr = 0;
+ $chartID = 'sparkline-' . $this->params['charttype'] . '-' . ++$statNr;
+
+ $this->isHTML = true;
+
+ // Prepare data array
+ foreach ( $data as $key => $value ) {
+ if ( $value >= $this->params['min'] ) {
+ $dataObject['label'][] = $key;
+ $dataObject['value'][] = $value;
+ }
+ }
+
+ $dataObject['charttype'] = $this->params['charttype'];
+
+ // Encode data objects
+ $requireHeadItem = [ $chartID => FormatJson::encode( $dataObject ) ];
+ SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // RL module
+ SMWOutputs::requireResource( 'ext.srf.sparkline' );
+
+ // Processing placeholder
+ $processing = SRFUtils::htmlProcessingElement( false );
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [
+ 'id' => $chartID,
+ 'class' => 'sparkline-container',
+ 'style' => "display:none;"
+ ],
+ null
+ );
+
+ // Beautify class selector
+ $class = $this->params['class'] ? ' ' . $this->params['class'] : '';
+
+ // Chart/graph wrappper
+ return Html::rawElement(
+ 'span',
+ [
+ 'class' => 'srf-sparkline' . $class,
+ ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-minvalue',
+ 'default' => false,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['charttype'] = [
+ 'message' => 'srf-paramdesc-charttype',
+ 'default' => 'bar',
+ 'values' => [ 'bar', 'line', 'pie', 'discrete' ]
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/sparkline/resources/ext.srf.sparkline.js b/www/wiki/extensions/SemanticResultFormats/formats/sparkline/resources/ext.srf.sparkline.js
new file mode 100644
index 00000000..18aedc18
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/sparkline/resources/ext.srf.sparkline.js
@@ -0,0 +1,71 @@
+/**
+ * JavaSript for SRF sparkline format
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Sparkline format
+ *
+ * @since 1.8
+ * @release 0.2
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( srf, $ ) {
+ 'use strict';
+
+ /*global mw:true semanticFormats:true*/
+
+ ////////////////////////// PUBLIC METHODS ////////////////////////
+
+ srf.formats = srf.formats || {};
+
+ /**
+ * Constructor
+ * @var Object
+ */
+ srf.formats.sparkline = function( settings ) {
+ $.extend( this, settings );
+ this.init();
+ };
+
+ srf.formats.sparkline.prototype = {
+
+ init: function() {
+ return this.context.each( function() {
+ var chart = $( this ).find( '.sparkline-container' ),
+ chartID = chart.attr( 'id' ),
+ json = mw.config.get( chartID );
+
+ // Parse json string and convert it back
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ // Release graph and bottom text
+ util.spinner.hide( { context: $( this ) } );
+
+ // Release chart/graph
+ chart.show();
+ chart.sparkline( data.value , {
+ type: data.charttype,
+ tooltipFormat: '{{value}}{{y}} ({{offset:offset}})',
+ tooltipValueLookups: {
+ offset: data.label
+ }
+ } );
+ } );
+ }
+ };
+
+ /**
+ * Implementation and representation of the sparkline instance
+ * @since 1.8
+ * @type Object
+ */
+ var util = new srf.util();
+
+ $( document ).ready( function() {
+ $( '.srf-sparkline' ).each( function() {
+ new srf.formats.sparkline( { context: $( this ) } );
+ } );
+ } );
+} )( semanticFormats, jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/spreadsheet/SpreadsheetPrinter.php b/www/wiki/extensions/SemanticResultFormats/formats/spreadsheet/SpreadsheetPrinter.php
new file mode 100644
index 00000000..7a59bb63
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/spreadsheet/SpreadsheetPrinter.php
@@ -0,0 +1,461 @@
+<?php
+
+namespace SRF;
+
+use ImagePage;
+use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
+use PhpOffice\PhpSpreadsheet\Cell\Cell;
+use PhpOffice\PhpSpreadsheet\Cell\DataType;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
+use PhpOffice\PhpSpreadsheet\Worksheet\Row;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+use Sanitizer;
+use SMW\FileExportPrinter;
+use SMW\Query\ExportPrinter;
+use SMWDataValue;
+use SMWQueryResult;
+use SMWResultArray;
+use Title;
+
+/**
+ * @author Kim Eik
+ * @since 1.9
+ */
+class SpreadsheetPrinter extends FileExportPrinter {
+
+ const HEADER_ROW_OFFSET = 1;
+
+ protected $fileFormats = [
+ 'xlsx' => [
+ 'writer' => 'Xlsx',
+ 'mimetype' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'extension' => '.xlsx',
+ ],
+ 'xls' => [
+ 'writer' => 'Xls',
+ 'mimetype' => 'aapplication/vnd.ms-excel',
+ 'extension' => '.xls',
+ ],
+ 'ods' => [
+ 'writer' => 'Ods',
+ 'mimetype' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'extension' => '.ods',
+ ],
+ 'csv' => [
+ 'writer' => 'Csv',
+ 'mimetype' => 'text/csv',
+ 'extension' => '.csv',
+ ],
+ ];
+
+ protected $styled = false;
+ protected $fileFormat;
+
+ /**
+ * @see ExportPrinter::getMimeType()
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $queryResult
+ *
+ * @return string
+ */
+ public function getMimeType( SMWQueryResult $queryResult ) {
+ return $this->fileFormat[ 'mimetype' ];
+ }
+
+ /**
+ * @see ExportPrinter::getFileName
+ *
+ * @param SMWQueryResult $queryResult
+ *
+ * @return string
+ */
+ public function getFileName( SMWQueryResult $queryResult ) {
+ return ( $this->params[ 'filename' ] ?: base_convert( uniqid(), 16, 36 ) ) . $this->fileFormat[ 'extension' ];
+ }
+
+ /**
+ * @see ExportPrinter::outputAsFile
+ *
+ * @param SMWQueryResult $queryResult
+ * @param array $params
+ */
+ public function outputAsFile( SMWQueryResult $queryResult, array $params ) {
+
+ if ( array_key_exists( 'fileformat', $params) && array_key_exists( $params[ 'fileformat' ]->getValue(), $this->fileFormats )) {
+ $this->fileFormat = $this->fileFormats[ $params[ 'fileformat' ]->getValue() ];
+ } else {
+ $this->fileFormat = $this->fileFormats[ 'xlsx' ];
+ }
+
+ parent::outputAsFile( $queryResult, $params );
+ }
+
+ /**
+ * @param $definitions \ParamProcessor\ParamDefinition[]
+ *
+ * @return array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $definitions[ 'searchlabel' ]->setDefault( wfMessage( 'srf-spreadsheet-link' )->inContentLanguage()->text() );
+
+ $params[ 'templatefile' ] = [
+ 'type' => 'string',
+ 'name' => 'templatefile',
+ 'default' => '',
+ 'message' => 'srf-paramdesc-spreadsheet-templatefile',
+ ];
+
+ $params[ 'filename' ] = [
+ 'type' => 'string',
+ 'name' => 'filename',
+ 'default' => '',
+ 'message' => 'srf-paramdesc-spreadsheet-filename',
+ ];
+
+ $params[ 'fileformat' ] = [
+ 'type' => 'string',
+ 'name' => 'fileformat',
+ 'default' => 'xlsx',
+ 'tolower' => true,
+ 'message' => 'srf-paramdesc-spreadsheet-fileformat',
+ ];
+
+ return $params;
+ }
+
+ /*
+ * Turns the PhpSpreadsheet document object into a string
+ */
+
+ /**
+ * Return serialised results in specified format.
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+ */
+ protected function getResultText( SMWQueryResult $queryResult, $outputMode ) {
+
+ if ( $outputMode === SMW_OUTPUT_FILE ) {
+ return $this->getResultFileContents( $queryResult );
+ }
+
+ $this->isHTML = ( $outputMode === SMW_OUTPUT_HTML );
+ return $this->getLink( $queryResult, $outputMode )->getText( $outputMode, $this->mLinker );
+ }
+
+ /**
+ * @param SMWQueryResult $queryResult
+ *
+ * @return string
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+ */
+ protected function getResultFileContents( SMWQueryResult $queryResult ) {
+
+ $spreadsheet = $this->createSpreadsheet();
+ $worksheet = $spreadsheet->getSheet( 0 );
+
+ $this->populateWorksheet( $worksheet, $queryResult );
+
+ //$spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight();
+
+ for ( $i = 0; $i < count( $queryResult->getPrintRequests() ); $i++ ) {
+ $worksheet->getColumnDimensionByColumn( $i )->setAutoSize( true );
+ }
+
+ $result = $this->getStringFromSpreadsheet( $spreadsheet );
+ return $result;
+ }
+
+ /**
+ * Creates a new PhpSpreadsheet document and returns it
+ *
+ * @return Spreadsheet
+ * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+ */
+ protected function createSpreadsheet() {
+
+ $fileTitle = Title::newFromText( $this->params[ 'templatefile' ], NS_FILE );
+
+ if ( $fileTitle !== null && $fileTitle->exists() ) {
+
+ $spreadsheet = $this->createSpreadsheetFromTemplate( $fileTitle );
+
+ $this->styled = true;
+
+ } else {
+
+ $spreadsheet = new Spreadsheet();
+
+ }
+
+ // Set document properties
+ $spreadsheet->getProperties()->setCreator( 'SemanticMediaWiki Spreadsheet Export' );
+
+ return $spreadsheet;
+ }
+
+ /**
+ * @param $fileTitle
+ *
+ * @return Spreadsheet
+ * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+ */
+ private function createSpreadsheetFromTemplate( $fileTitle ) {
+ $filePage = new ImagePage( $fileTitle, $this );
+
+ $virtualFile = $filePage->getDisplayedFile();
+ $virtualFilePath = $virtualFile->getPath();
+
+ $localFile = $virtualFile->getRepo()->getLocalReference( $virtualFilePath );
+ $localFilePath = $localFile->getPath();
+
+ return IOFactory::load( $localFilePath );
+ }
+
+ /**
+ * @param SMWQueryResult $queryResult
+ * @param $worksheet
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function populateWorksheet( Worksheet $worksheet, SMWQueryResult $queryResult ) {
+
+ $rowIterator = $worksheet->getRowIterator( self::HEADER_ROW_OFFSET );
+
+ //Get headers
+ if ( $this->mShowHeaders ) {
+ $this->populateHeaderRow( $rowIterator->current(), $queryResult );
+ $rowIterator->next();
+ }
+
+ while ( $resultRow = $queryResult->getNext() ) {
+
+ //Get data rows
+ $this->populateRow( $rowIterator->current(), $resultRow );
+ $rowIterator->next();
+ }
+ }
+
+ /**
+ * Populates the PhpSpreadsheet sheet with the headers from the result query
+ *
+ * @param Row $row
+ * @param SMWQueryResult $queryResult The query result
+ *
+ * @return Row
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function populateHeaderRow( Row $row, SMWQueryResult $queryResult ) {
+
+ $printRequests = $queryResult->getPrintRequests();
+ $cellIterator = $row->getCellIterator();
+
+ foreach ( $printRequests as $printRequest ) {
+
+ $cell = $cellIterator->current();
+
+ $cell->setValue( $printRequest->getLabel() );
+
+ $cell->getStyle()
+ ->getFont()
+ ->setBold( true );
+
+ $cellIterator->next();
+
+ }
+
+ return $row;
+ }
+
+ /**
+ * Populates the PhpSpreadsheet document with the query data
+ *
+ * @param Row $row
+ * @param $resultRow
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function populateRow( Row $row, $resultRow ) {
+
+ $cellIterator = $row->getCellIterator();
+
+ foreach ( $resultRow as $resultField ) {
+
+ $this->populateCell( $cellIterator->current(), $resultField );
+ $cellIterator->next();
+ }
+ }
+
+ /**
+ * @param Cell $cell
+ * @param SMWResultArray $field
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function populateCell( Cell $cell, SMWResultArray $field ) {
+
+ $dataItems = $field->getContent();
+
+ if ( $dataItems === false ) {
+ return;
+ }
+
+ if ( count( $dataItems ) > 1 ) {
+
+ $values = [];
+
+ while ( $value = $field->getNextText( SMW_OUTPUT_FILE ) ) {
+ $values[] = $value;
+ }
+
+ $cell->setValueExplicit( join( ', ', $values ), DataType::TYPE_STRING );
+
+ } else {
+
+ $nextDataValue = $field->getNextDataValue();
+
+ if ( $nextDataValue !== false ) {
+ $this->populateCellAccordingToType( $cell, $nextDataValue );
+ }
+
+ }
+ }
+
+ /**
+ * Checks the type of the value, and set's it in the sheet accordingly
+ *
+ * @param Cell $cell
+ * @param SMWDataValue $value
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function populateCellAccordingToType( Cell $cell, SMWDataValue $value ) {
+
+ //NOTE: must check against subclasses before superclasses
+ if ( $value instanceof \SMWQuantityValue ) {
+
+ $this->setQuantityDataValue( $cell, $value );
+
+ } elseif ( $value instanceof \SMWNumberValue ) {
+
+ $this->setNumberDataValue( $cell, $value );
+
+ } elseif ( $value instanceof \SMWTimeValue ) {
+
+ $this->setTimeDataValue( $cell, $value );
+
+ } else {
+
+ $this->setStringDataValue( $cell, $value );
+
+ }
+
+ }
+
+ /**
+ * Sets a quantity value at the given col,row location
+ *
+ * @param Cell $cell
+ * @param \SMWQuantityValue $value SMWDataValue the raw data value object
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function setQuantityDataValue( Cell $cell, \SMWQuantityValue $value ) {
+
+ $type = DataType::TYPE_NUMERIC;
+ $unit = $value->getUnit();
+ $number = $value->getNumber();
+
+ $cell->setValueExplicit( $number, $type );
+
+ if ( !$this->styled ) {
+ $cell->getStyle()
+ ->getNumberFormat()
+ ->setFormatCode( '0 "' . $unit . '"' );
+ }
+ }
+
+ /**
+ * Sets a numeric value at the given col,row location
+ *
+ * @param Cell $cell
+ * @param \SMWNumberValue $value SMWDataValue the raw data value object
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function setNumberDataValue( Cell $cell, \SMWNumberValue $value ) {
+
+ $type = DataType::TYPE_NUMERIC;
+ $number = $value->getNumber();
+
+ $cell->setValueExplicit( $number, $type );
+ }
+
+ /**
+ * Sets a date/time value at the given col,row location
+ *
+ * @param Cell $cell
+ * @param \SMWTimeValue $value the raw data value object
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function setTimeDataValue( Cell $cell, \SMWTimeValue $value ) {
+
+ $type = DataType::TYPE_NUMERIC;
+ $number = DateTime::DATEVALUE( str_replace( 'T', ' ', $value->getISO8601Date() ) );
+
+ $cell->setValueExplicit( $number, $type );
+
+ if ( !$this->styled ) {
+ $cell->getStyle()
+ ->getNumberFormat()
+ ->setFormatCode( NumberFormat::FORMAT_DATE_DDMMYYYY );
+ }
+ }
+
+ /**
+ * Sets or appends a string value at the given col,row location
+ *
+ * If there already exists a value at a given col,row location, then
+ * convert the cell to a string and append the data value. Creating
+ * a list of comma separated entries.
+ *
+ * @param Cell $cell
+ * @param $value SMWDataValue the raw data value object
+ *
+ * @throws \PhpOffice\PhpSpreadsheet\Exception
+ */
+ protected function setStringDataValue( Cell $cell, SMWDataValue $value ) {
+
+ $type = DataType::TYPE_STRING;
+ $text = $value->getWikiValue();
+ $text = Sanitizer::decodeCharReferences( $text );
+ $text = DataType::checkString( $text );
+
+ $cell->setValueExplicit( $text, $type );
+ }
+
+ /**
+ * @param Spreadsheet $spreadsheet
+ *
+ * @return string
+ * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
+ */
+ protected function getStringFromSpreadsheet( Spreadsheet $spreadsheet ) {
+
+ $writer = IOFactory::createWriter( $spreadsheet, $this->fileFormat[ 'writer' ] );
+
+ ob_start();
+ $writer->save( 'php://output' );
+ return ob_get_clean();
+ }
+
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/TagCloud.php b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/TagCloud.php
new file mode 100644
index 00000000..a10a7ab7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/TagCloud.php
@@ -0,0 +1,465 @@
+<?php
+
+namespace SRF;
+
+use Html;
+use SMW\ResultPrinter;
+use SMWDataValue;
+use SMWOutputs;
+use SMWPrintRequest;
+use SMWQueryResult;
+use SMWResultArray;
+use SRFUtils;
+use Title;
+
+/**
+ * Result printer that prints query results as a tag cloud
+ *
+ * @since 1.5.3
+ *
+ * @ingroup SRF
+ * @ingroup QueryPrinter
+ *
+ * @licence GNU GPL v2 or later
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author mwjames
+ */
+class TagCloud extends ResultPrinter {
+
+ /**
+ * Contains html generated tags
+ *
+ * @var array
+ */
+ protected $tagsHtml = [];
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return $this->msg( 'srf_printername_tagcloud' )->text();
+ }
+
+ /**
+ * Return serialised results in specified format
+ *
+ * @param SMWQueryResult $queryResult
+ * @param $outputmode
+ *
+ * @return string
+ */
+ public function getResultText( SMWQueryResult $queryResult, $outputmode ) {
+
+ $tags = $this->getTags( $queryResult, $outputmode );
+
+ if ( $tags === [] ) {
+ $queryResult->addErrors( [ $this->msg( 'smw_result_noresults' )->inContentLanguage()->text() ] );
+ return '';
+ }
+
+ // Check output conditions
+ if ( ( $this->params['widget'] == 'sphere' ) &&
+ ( $this->params['link'] !== 'all' ) &&
+ ( $this->params['template'] === '' ) ) {
+ $queryResult->addErrors(
+ [ $this->msg( 'srf-error-option-link-all', 'sphere' )->inContentLanguage()->text() ]
+ );
+ return '';
+ }
+
+ // Template support
+ $this->hasTemplates = $this->params['template'] !== '';
+ $this->isHTML = $this->isHTML();
+
+ // Register RL module
+ if ( in_array( $this->params['widget'], [ 'sphere', 'wordcloud' ] ) ) {
+ SMWOutputs::requireResource( 'ext.srf.formats.tagcloud' );
+ }
+
+ return $this->getTagCloud( $this->getTagSizes( $tags ) );
+ }
+
+ private function isHTML() {
+ $title = $GLOBALS['wgTitle'];
+
+ if ( $title instanceof Title ) {
+ return $title->isSpecialPage() && !$this->hasTemplates;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an array with the tags (keys) and the number of times they occur (values).
+ *
+ * @param SMWQueryResult $queryResult
+ * @param $outputMode
+ *
+ * @return array
+ */
+ private function getTags( SMWQueryResult $queryResult, $outputMode ) {
+ $tags = [];
+ $excludetags = explode( ';', $this->params['excludetags'] );
+
+ /**
+ * @var SMWResultArray $row
+ * @var SMWDataValue $dataValue
+ */
+ while ( $row = $queryResult->getNext() ) { // Objects (pages)
+ for ( $i = 0, $n = count( $row ); $i < $n; $i++ ) { // SMWResultArray for a sinlge property
+
+ while ( ( $dataValue = $row[$i]->getNextDataValue() ) !== false ) { // Data values
+
+ $isSubject = $row[$i]->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS;
+
+ // If the main object should not be included, skip it.
+ if ( $i == 0 && !$this->params['includesubject'] && $isSubject ) {
+ continue;
+ }
+
+ $value = null;
+
+ // Get the HTML for the tag content. Pages are linked, other stuff is just plaintext.
+ if ( $dataValue->getTypeID() === '_wpg' ) {
+
+ $title = $dataValue->getDataItem()->getTitle();
+
+ if ( $title instanceof Title ) {
+ $value = $title->getPrefixedText();
+ $html = $dataValue->getLongText( $outputMode, $this->getLinker( $isSubject ) );
+ }
+ }
+
+ if ( $value === null ) {
+ $html = $dataValue->getShortText( $outputMode, $this->getLinker( false ) );
+ $value = $html;
+ }
+
+ // Exclude tags from result set
+ if ( in_array( $value, $excludetags ) ) {
+ continue;
+ }
+
+ // Replace content with template inclusion
+ $html = $this->params['template'] !== '' ? $this->addTemplateOutput( $value, $rownum ) : $html;
+
+ // Store the HTML separately, so sorting can be done easily
+ if ( !array_key_exists( $value, $tags ) ) {
+ $tags[$value] = 0;
+ $this->tagsHtml[$value] = $html;
+ }
+
+ $tags[$value]++;
+ }
+ }
+ }
+
+ foreach ( $tags as $name => $count ) {
+ if ( $count < $this->params['mincount'] ) {
+ unset( $tags[$name] );
+ }
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Determines the sizes of tags.
+ * This method is based on code from the FolkTagCloud extension by Katharina Wäschle.
+ *
+ * @param array $tags
+ *
+ * @return array
+ */
+ private function getTagSizes( array $tags ) {
+ if ( count( $tags ) == 0 ) {
+ return $tags;
+ }
+
+ // If the original order needs to be kept, we need a copy of the current order.
+ if ( $this->params['tagorder'] == 'unchanged' ) {
+ $unchangedTags = array_keys( $tags );
+ }
+
+ arsort( $tags, SORT_NUMERIC );
+
+ if ( count( $tags ) > $this->params['maxtags'] ) {
+ $tags = array_slice( $tags, 0, $this->params['maxtags'], true );
+ }
+
+ $min = end( $tags ) or $min = 0;
+ $max = reset( $tags ) or $max = 1;
+ $maxSizeIncrease = $this->params['maxsize'] - $this->params['minsize'];
+
+ // Loop over the tags, and replace their count by a size.
+ foreach ( $tags as &$tag ) {
+ switch ( $this->params['increase'] ) {
+ case 'linear':
+ $divisor = ( $max == $min ) ? 1 : $max - $min;
+ $tag = $this->params['minsize'] + $maxSizeIncrease * ( $tag - $min ) / $divisor;
+ break;
+ case 'log' :
+ default :
+ $divisor = ( $max == $min ) ? 1 : log( $max ) - log( $min );
+ $tag = $this->params['minsize'] + $maxSizeIncrease * ( log( $tag ) - log( $min ) ) / $divisor;
+ break;
+ }
+ }
+
+ switch ( $this->params['tagorder'] ) {
+ case 'desc' :
+ // Tags are already sorted desc
+ break;
+ case 'asc' :
+ asort( $tags );
+ break;
+ case 'alphabetical' :
+ $tagNames = array_keys( $tags );
+ natcasesort( $tagNames );
+ $newTags = [];
+
+ foreach ( $tagNames as $name ) {
+ $newTags[$name] = $tags[$name];
+ }
+
+ $tags = $newTags;
+ break;
+ case 'random' :
+ $tagSizes = $tags;
+ shuffle( $tagSizes );
+ $newTags = [];
+
+ foreach ( $tagSizes as $size ) {
+ foreach ( $tags as $tagName => $tagSize ) {
+ if ( $tagSize == $size ) {
+ $newTags[$tagName] = $tags[$tagName];
+ break;
+ }
+ }
+ }
+
+ $tags = $newTags;
+ break;
+ case 'unchanged' :
+ default : // Restore the original order.
+ $changedTags = $tags;
+ $tags = [];
+
+ foreach ( $unchangedTags as $name ) {
+ // Original tags might have been left out at this point, so only add remaining ones.
+ if ( array_key_exists( $name, $changedTags ) ) {
+ $tags[$name] = $changedTags[$name];
+ }
+ }
+ break;
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Returns the HTML for the tag cloud.
+ *
+ * @param array $tags
+ *
+ * @return string
+ */
+ private function getTagCloud( array $tags ) {
+
+ // Initialize
+ $htmlTags = [];
+ $processing = '';
+
+ // Count actual output and store div identifier
+ $tagId = 'srf-' . uniqid();
+
+ // Determine HTML element marker
+ $element = $this->params['widget'] !== '' ? 'li' : 'span';
+
+ // Add size information
+ foreach ( $tags as $name => $size ) {
+ $htmlTags[] = Html::rawElement(
+ $element,
+ [
+ 'style' => "font-size:$size%" ],
+ $this->tagsHtml[$name]
+ );
+ }
+
+ // Stringify
+ $htmlSTags = implode( ' ', $htmlTags );
+
+ // Handle sphere/canvas output objects
+ if ( in_array( $this->params['widget'], [ 'sphere', 'wordcloud' ] ) ) {
+
+ // Wrap LI/UL elements
+ $htmlCTags = Html::rawElement(
+ 'ul',
+ [
+ 'style' => 'display:none;'
+ ],
+ $htmlSTags
+ );
+
+ // Wrap tags
+ $htmlCTags = Html::rawElement(
+ 'div',
+ [
+ 'id' => $tagId . '-tags',
+ 'class' => 'srf-tags'
+ ],
+ $htmlCTags
+ );
+
+ // Wrap everything in a container object
+ $htmlSTags = Html::rawElement(
+ 'div',
+ [
+ 'id' => $tagId . '-container',
+ 'class' => 'srf-container',
+ 'data-width' => $this->params['width'],
+ 'data-height' => $this->params['height'],
+ 'data-font' => $this->params['font']
+ ],
+ $htmlCTags
+ );
+
+ // Processing placeholder
+ $processing = SRFUtils::htmlProcessingElement();
+ }
+
+ // Beautify class selector
+ $class = $this->params['widget'] ? '-' . $this->params['widget'] . ' ' : '';
+ $class = $this->params['class'] ? $class . ' ' . $this->params['class'] : $class;
+
+ // General placeholder
+ $attribs = [
+ 'class' => 'srf-tagcloud' . $class,
+ 'data-version' => '0.4.1'
+ ];
+
+ return Html::rawElement( 'div', $attribs, $processing . $htmlSTags );
+ }
+
+ /**
+ * @param string $value
+ * @param int $rowNumber
+ *
+ * @return string
+ */
+ private function addTemplateOutput( $value, &$rowNumber ) {
+ $rowNumber++;
+ $wikitext = $this->params['userparam'] ? "|userparam=" . $this->params['userparam'] : '';
+ $wikitext .= "|" . $value;
+ $wikitext .= "|#=$rowNumber";
+ return '{{' . trim( $this->params['template'] ) . $wikitext . '}}';
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['template'] = [
+ 'message' => 'srf-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params['userparam'] = [
+ 'message' => 'srf-paramdesc-userparam',
+ 'default' => '',
+ ];
+
+ $params['excludetags'] = [
+ 'message' => 'srf-paramdesc-excludetags',
+ 'default' => '',
+ ];
+
+ $params['includesubject'] = [
+ 'type' => 'boolean',
+ 'message' => 'srf-paramdesc-includesubject',
+ 'default' => false,
+ ];
+
+ $params['tagorder'] = [
+ 'message' => 'srf_paramdesc_tagorder',
+ 'default' => 'alphabetical',
+ 'values' => [ 'alphabetical', 'asc', 'desc', 'random', 'unchanged' ],
+ ];
+
+ $params['increase'] = [
+ 'message' => 'srf_paramdesc_increase',
+ 'default' => 'log',
+ 'values' => [ 'linear', 'log' ],
+ ];
+
+ $params['widget'] = [
+ 'message' => 'srf-paramdesc-widget',
+ 'default' => '',
+ 'values' => [ 'sphere', 'wordcloud' ],
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['font'] = [
+ 'message' => 'srf-paramdesc-font',
+ 'default' => 'impact',
+ ];
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-height',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ $params['width'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-width',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ $params['mincount'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_mincount',
+ 'default' => 1,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['minsize'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_minsize',
+ 'default' => 77,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['maxsize'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_maxsize',
+ 'default' => 242,
+ 'manipulatedefault' => false,
+ ];
+
+ $params['maxtags'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_maxtags',
+ 'default' => 1000,
+ 'lowerbound' => 1,
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.css b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.css
new file mode 100644
index 00000000..22e14d37
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.css
@@ -0,0 +1,52 @@
+/*!
+ * This file is part of the Semantic Result Formats Tagcloud module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Tagcloud_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.8
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+.srf-tagcloud ul {
+ float: left;
+ display: block;
+ width: 280px;
+ overflow: auto;
+ padding: 20px;
+ margin: 0 10px 20px 0;
+ background-color: #fff;
+ border: 4px solid #aaa;
+ border-radius: 20px;
+ -moz-border-radius: 20px;
+}
+.srf-tagcloud ul li {
+ display: inline;
+ white-space: nowrap;
+}
+.srf-tagcloud ul li a {
+ margin: 2px;
+}
+.srf-tagcloud-sphere canvas#gradient {
+ float: right;
+ border:1px solid #000;
+ margin: 2px 20px
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.js b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.js
new file mode 100644
index 00000000..5e4d60dc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tagcloud/resources/ext.srf.formats.tagcloud.js
@@ -0,0 +1,294 @@
+/*!
+ * This file is part of the Semantic Result Formats Tagcloud module
+ * @see https://www.semantic-mediawiki.org/wiki/Help:Tagcloud_formats
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /*global d3:true*/
+
+ /**
+ * Inheritance class for the srf.formats constructor
+ *
+ * @since 1.9
+ *
+ * @class
+ * @singleton
+ */
+ srf.formats = srf.formats || {};
+
+ /**
+ * Base constructor for objects representing a tagcloud instance
+ *
+ * @since 1.8
+ *
+ * @class
+ * @constructor
+ */
+ srf.formats.tagcloud = function() {};
+
+ /* Public interface */
+
+ srf.formats.tagcloud.prototype = {
+
+ /**
+ * Version
+ *
+ * @property
+ * @type {string}
+ */
+ version: '0.4.1',
+
+ /**
+ * Specifies default values
+ *
+ * @property
+ * @type {Object}
+ */
+ defaults: {},
+
+ /**
+ * Generates a sphere tag cloud using the Tagcanvas plug-in
+ *
+ * @see http://goo.gl/Uci76
+ *
+ * @param {Object} context
+ *
+ * @return {boolean}
+ */
+ sphere: function( context ) {
+
+ // Init
+ var container = context.find( '.srf-container' ),
+ tagsID = container.find( '.srf-tags' ).attr( 'id' ),
+ data = container.data();
+
+ context.css( { 'width': data.width, 'height': data.height } );
+
+ // Add canvas element
+ var canvas = $( '<canvas></canvas>' ).appendTo( container );
+ canvas.attr( {
+ id: container.attr( 'id' ) + '-canvas',
+ width: data.width,
+ height: data.height
+ } );
+
+
+ // Initialize tagcanvas instance
+ // Somewhere around here QUnit dies (with a time out) which
+ // makes it unattainable to run a successful test
+ if( !canvas.tagcanvas( {
+ textColour: null,
+ outlineColour: '#FF9D43',
+ textFont: data.font,
+ reverse: true,
+ weight: true,
+ shadow: '#ccf',
+ shadowBlur: 3,
+ depth: 0.3,
+ maxSpeed: 0.04
+ }, tagsID ) ) {
+ // something went wrong, hide the canvas container
+ container.hide();
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Generates a wordcloud using the D3.js cloud plug-in
+ *
+ * @see http://goo.gl/lbxjk
+ *
+ * @param {Object} context
+ *
+ * @return {boolean}
+ */
+ wordcloud: function( context ) {
+
+ // Init
+ var container = context.find( '.srf-container' ),
+ containerID = container.attr( 'id' ),
+ data = container.data(),
+ textFont = data.font.split(',');
+
+ context.css( { 'width': data.width, 'height': data.height } );
+
+ // Build array of tags, size, and href property
+ var arr = [];
+ container.find( 'li' ).each( function(){
+ arr.push( [ $( this ).text(), $( this ).css( 'font-size' ), $( this ).find( 'a' ).attr( 'href' ) ] );
+ } );
+
+ // Init the colour array
+ var fill = d3.scale.category20b();
+
+ // Set properties for the tags
+ function draw( words ) {
+ d3.select( '#' + containerID ).append( 'svg' )
+ .attr( 'width', data.width - 5 )
+ .attr( 'height', data.height - 5 )
+ .append( 'g' )
+ .attr( 'transform', 'translate(' + data.width / 2 + ',' + data.height / 2 + ')' )
+ .selectAll( 'text' )
+ .data( words )
+ .enter().append( 'text' )
+ .style( 'fill', function( d ) {
+ return fill(d.text.toLowerCase() );
+ } )
+ .style( 'font-size', function(d) {
+ return d.size + 'px';
+ } )
+ .attr( 'text-anchor', 'middle' )
+ .attr( 'transform', function( d ) {
+ return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')';
+ } )
+ .append( 'svg:a' )
+ .style( 'text-decoration', function( d ) {
+ return typeof d.href === 'undefined' ? 'none' : 'inherent';
+ } )
+ .attr( 'font-family', function(d) {
+ return d.font;
+ } )
+ .attr( 'target', data.target === undefined ? '' : '_blank' )
+ .attr( 'xlink:href', function( d ) {
+ return d.href !== '' ? d.href : '';
+ } )
+ .text( function(d) {
+ return d.text;
+ } );
+ }
+
+ // Build word cloud
+ // ~~ (bitwise not) is used instead of Math.floor because it is
+ // twice as fast as floor, "end" is fired when all words have been placed
+ var cloud = d3.layout.cloud().size( [ data.width - 5, data.height - 5 ] )
+ .words( arr.map( function( d ) { return {
+ text: d[0],
+ size: parseInt( d[1], 10 ),
+ href: d[2]
+ }; } ) )
+ .rotate( function() {
+ return ~~( Math.random() * 2 ) * 90;
+ } )
+ .fontSize( function(d) {
+ return d.size;
+ } )
+ .font( textFont[ ~~( Math.random() * textFont.length ) ] )
+ .on( 'end', draw );
+
+ // Create the cloud
+ cloud.start();
+
+ // Return success status
+ return true;
+ },
+
+ /**
+ * Initializes an instance, compares the required version, and loads
+ * mandatory RL module
+ *
+ * @param {Object} options
+ *
+ * -- options.context
+ * -- options.element
+ * -- options.module
+ * -- options.method
+ *
+ * @return {boolean}
+ */
+ load: function( options ) {
+ var self = this;
+ var util = new srf.util();
+
+ // Check version
+ if ( options.context.data( 'version' ) >= self.version ) {
+
+ if ( util.assert( options.element ) ) {
+ mw.loader.using( options.module, function() {
+ smw.async.load( options.context, function() {
+ util.spinner.hide( $( this ) );
+ options.method.call( this, $( this ) );
+ } );
+ } );
+ } else {
+ util.spinner.hide( options.context );
+ util.message.set( {
+ context: options.context,
+ type: 'error',
+ message: 'Your browser doesn\'t support ' + options.element
+ } );
+ }
+
+ return true;
+
+ } else {
+
+ util.spinner.hide( options.context );
+ util.message.set( {
+ context: options.context,
+ type: 'info',
+ message: 'The software has been updated ( ' + options.version + ' ), please refresh your page content'
+ } );
+
+ return false;
+ }
+ }
+ };
+
+ /**
+ * Implementation of a tagcloud instance
+ * @since 1.8
+ * @ignore
+ */
+ $( document ).ready( function() {
+ var tagcloud = new srf.formats.tagcloud();
+
+ // Tagcanvas
+ $( '.srf-tagcloud-sphere' ).each( function() {
+ tagcloud.load( {
+ context: $( this ),
+ element: 'canvas',
+ module: 'ext.jquery.tagcanvas',
+ method: tagcloud.sphere
+ } );
+ } );
+
+ // Wordcloud
+ $( '.srf-tagcloud-wordcloud' ).each( function() {
+ tagcloud.load( {
+ context: $( this ),
+ element: 'svg',
+ module: 'ext.d3.wordcloud',
+ method: tagcloud.wordcloud
+ } );
+ } );
+
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/time/SRF_Time.php b/www/wiki/extensions/SemanticResultFormats/formats/time/SRF_Time.php
new file mode 100644
index 00000000..f8bd8b55
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/time/SRF_Time.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * Formats that returns a time.
+ *
+ * @licence GNU GPL v3+
+ * @author nischayn22
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class SRFTime extends SMWResultPrinter {
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getName()
+ */
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf_printername_latest, srf_printername_earliest
+ return wfMessage( 'srf_printername_' . $this->mFormat )->text();
+ }
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getResultText()
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ $dataItems = $this->getSortKeys( $res );
+
+ if ( empty( $dataItems ) ) {
+ return $this->params['default'];
+ }
+
+ $sortKeys = array_keys( $dataItems );
+
+ switch ( $this->mFormat ) {
+ case 'latest':
+ $result = max( $sortKeys );
+ break;
+ case 'earliest':
+ $result = min( $sortKeys );
+ break;
+ }
+
+ $dataValue = SMWDataValueFactory::getInstance()->newDataValueByItem( $dataItems[$result], null );
+ return $dataValue->getLongHTMLText();
+ }
+
+ /**
+ * Returns an array with sortkeys for dates pointing to their source DataItems.
+ *
+ * @param SMWQueryResult $res
+ *
+ * @return array
+ */
+ protected function getSortKeys( SMWQueryResult $res ) {
+ $seconds = [];
+
+ while ( $row = $res->getNext() ) {
+ foreach ( $row as /* SMWResultArray */
+ $resultArray ) {
+ foreach ( $resultArray->getContent() as /* SMWDataItem */
+ $dataItem ) {
+ if ( $dataItem->getDIType() === SMWDataItem::TYPE_TIME ) {
+ $seconds[$dataItem->getSortKey()] = $dataItem;
+ }
+ }
+ }
+ }
+
+ return $seconds;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['limit'] = [
+ 'type' => 'integer',
+ 'default' => 1000,
+ 'message' => 'srf_paramdesc_limit',
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/README b/www/wiki/extensions/SemanticResultFormats/formats/timeline/README
new file mode 100644
index 00000000..07679534
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/README
@@ -0,0 +1,18 @@
+= Timeline =
+
+This code provides the result formats "timeline" and "eventline" that enable
+query outputs in interactive timelines. Queries should contain one or more
+outputs of type Type:Date for this to work.
+
+For usage and configuration, see
+http://semantic-mediawiki.org/wiki/Help:Timeline_format
+
+
+== Credits ==
+
+Timeline PHP code has been written by Markus Krötzsch.
+
+The JavaScript upon which the Timeline format of inline queries is based is
+provided by Simile (http://simile.mit.edu). Note that it is distributed with
+a BSD-style license, and not under the GPL that applies to most parts of
+Semantic MediaWiki. \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/SRF_Timeline.php b/www/wiki/extensions/SemanticResultFormats/formats/timeline/SRF_Timeline.php
new file mode 100644
index 00000000..0af1a110
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/SRF_Timeline.php
@@ -0,0 +1,427 @@
+<?php
+/**
+ * Print query results in interactive timelines.
+ *
+ * @file SRF_Timeline.php
+ * @ingroup SemanticResultFormats
+ *
+ * @author Markus Krötzsch
+ *
+ * FIXME: this code is just insane; rewrite from 0 is probably the only way to get it right
+ */
+
+/**
+ * Result printer for timeline data.
+ *
+ * @ingroup SemanticResultFormats
+ */
+class SRFTimeline extends SMWResultPrinter {
+
+ protected $m_tlstart = ''; // name of the start-date property if any
+ protected $m_tlend = ''; // name of the end-date property if any
+ protected $m_tlsize = ''; // CSS-compatible size (such as 400px)
+ protected $m_tlbands = ''; // array of band IDs (MONTH, YEAR, ...)
+ protected $m_tlpos = ''; // position identifier (start, end, today, middle)
+ protected $mTemplate;
+ protected $mNamedArgs;
+
+ /**
+ * @see SMWResultPrinter::handleParameters
+ *
+ * @since 1.6.3
+ *
+ * @param array $params
+ * @param $outputmode
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ $this->mTemplate = trim( $params['template'] );
+ $this->mNamedArgs = $params['named args'];
+ $this->m_tlstart = smwfNormalTitleDBKey( $params['timelinestart'] );
+ $this->m_tlend = smwfNormalTitleDBKey( $params['timelineend'] );
+ $this->m_tlbands = $params['timelinebands'];
+ $this->m_tlpos = strtolower( trim( $params['timelineposition'] ) );
+
+ // str_replace makes sure this is only one value, not mutliple CSS fields (prevent CSS attacks)
+ // / FIXME: this is either unsafe or redundant, since Timeline is Wiki-compatible. If the JavaScript makes user inputs to CSS then it is bad even if we block this injection path.
+ $this->m_tlsize = htmlspecialchars( str_replace( ';', ' ', strtolower( $params['timelinesize'] ) ) );
+ }
+
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf_printername_timeline, srf_printername_eventline
+ return wfMessage( 'srf_printername_' . $this->mFormat )->text();
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+
+ SMWOutputs::requireHeadItem( SMW_HEADER_STYLE );
+ SMWOutputs::requireResource( 'ext.srf.timeline' );
+
+ $isEventline = 'eventline' == $this->mFormat;
+ $id = uniqid();
+
+ if ( !$isEventline && ( $this->m_tlstart == '' ) ) { // seek defaults
+ foreach ( $res->getPrintRequests() as $pr ) {
+ if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID() == '_dat' ) ) {
+ $dataValue = $pr->getData();
+
+ $date_value = $dataValue->getDataItem()->getLabel();
+
+ if ( ( $this->m_tlend == '' ) && ( $this->m_tlstart != '' ) &&
+ ( $this->m_tlstart != $date_value ) ) {
+ $this->m_tlend = $date_value;
+ } elseif ( ( $this->m_tlstart == '' ) && ( $this->m_tlend != $date_value ) ) {
+ $this->m_tlstart = $date_value;
+ }
+ }
+ }
+ }
+
+ // print header
+ $result = "<div id=\"smwtimeline-$id\" class=\"smwtimeline is-disabled\" style=\"height: $this->m_tlsize\">";
+ $result .= '<span class="smw-overlay-spinner medium" style="top:40%; transform: translate(-50%, -50%);"></span>';
+
+ foreach ( $this->m_tlbands as $band ) {
+ $result .= '<span class="smwtlband" style="display:none;">' . htmlspecialchars( $band ) . '</span>';
+ // just print any "band" given, the JavaScript will figure out what to make of it
+ }
+
+ // print all result rows
+ if ( ( $this->m_tlstart != '' ) || $isEventline ) {
+ $result .= $this->getEventsHTML( $res, $outputmode, $isEventline );
+ }
+ // no further results displayed ...
+
+ // print footer
+ $result .= '</div>';
+
+ // yes, our code can be viewed as HTML if requested, no more parsing needed
+ $this->isHTML = $outputmode == SMW_OUTPUT_HTML;
+
+ return $result;
+ }
+
+ /**
+ * Returns the HTML for the events.
+ *
+ * @since 1.5.3
+ *
+ * @param SMWQueryResult $res
+ * @param $outputmode
+ * @param boolean $isEventline
+ *
+ * @return string
+ */
+ protected function getEventsHTML( SMWQueryResult $res, $outputmode, $isEventline ) {
+ global $curarticle, $cururl; // why not, code flow has reached max insanity already
+
+ $positions = []; // possible positions, collected to select one for centering
+ $curcolor = 0; // color cycling is used for eventline
+
+ $result = '';
+
+ $output = false; // true if output for the popup was given on current line
+ if ( $isEventline ) {
+ $events = [];
+ } // array of events that are to be printed
+
+ while ( $row = $res->getNext() ) { // Loop over the objcts (pages)
+ $hastime = false; // true as soon as some startdate value was found
+ $hastitle = false; // true as soon as some label for the event was found
+ $curdata = ''; // current *inner* print data (within some event span)
+ $curmeta = ''; // current event meta data
+ $cururl = '';
+ $curarticle = ''; // label of current article, if it was found; needed only for eventline labeling
+ $first_col = true;
+
+ if ( $this->mTemplate != '' ) {
+ $this->hasTemplates = true;
+ $template_text = '';
+ $i = 0;
+ }
+
+ foreach ( $row as $field ) { // Loop over the returned properties
+ $first_value = true;
+ $pr = $field->getPrintRequest();
+ $dataValue = $pr->getData();
+
+ if ( $dataValue == '' ) {
+ $date_value = null;
+ } else {
+ $date_value = $dataValue->getDataItem()->getLabel();
+ }
+
+ while ( ( $object = $field->getNextDataValue() ) !== false ) { // Loop over property values
+ $event = $this->handlePropertyValue(
+ $object,
+ $outputmode,
+ $pr,
+ $first_col,
+ $hastitle,
+ $hastime,
+ $first_value,
+ $isEventline,
+ $curmeta,
+ $curdata,
+ $date_value,
+ $output,
+ $positions
+ );
+
+ if ( $this->mTemplate != '' ) {
+ $template_text .= '|' . ( $this->mNamedArgs ? '?' . $field->getPrintRequest()->getLabel(
+ ) : $i + 1 ) . '=';
+ if ( !$first_value ) {
+ $template_text .= ', ';
+ }
+ $template_text .= $object->getShortText( SMW_OUTPUT_WIKI, $this->getLinker( $first_value ) );
+ $i++;
+ }
+
+ if ( $event !== false ) {
+ $events[] = $event;
+ }
+
+ $first_value = false;
+ }
+
+ if ( $output ) {
+ $curdata .= '<br />';
+ }
+
+ $output = false;
+ $first_col = false;
+ }
+
+ if ( $this->mTemplate != '' ) {
+ $curdata = '{{' . $this->mTemplate . $template_text . '}}';
+ }
+
+ if ( $hastime ) {
+ $result .= Html::rawElement(
+ 'span',
+ [ 'class' => 'smwtlevent', 'style' => 'display:none;' ],
+ $curmeta . Html::element(
+ 'span',
+ [ 'class' => 'smwtlcoloricon' ],
+ $curcolor
+ ) . $curdata
+ );
+ }
+
+ if ( $isEventline ) {
+ foreach ( $events as $event ) {
+ $result .= '<span class="smwtlevent" style="display:none;" ><span class="smwtlstart">' . $event[0] . '</span><span class="smwtlurl">' . $curarticle . '</span><span class="smwtlcoloricon">' . $curcolor . '</span>';
+ if ( $curarticle != '' ) {
+ $result .= '<span class="smwtlprefix">' . $curarticle . ' </span>';
+ }
+ $result .= $curdata . '</span>';
+ $positions[$event[2]] = $event[0];
+ }
+ $events = [];
+ $curcolor = ( $curcolor + 1 ) % 10;
+ }
+ }
+
+ if ( count( $positions ) > 0 ) {
+ ksort( $positions );
+ $positions = array_values( $positions );
+
+ switch ( $this->m_tlpos ) {
+ case 'start':
+ $result .= '<span class="smwtlposition" style="display:none;" >' . $positions[0] . '</span>';
+ break;
+ case 'end':
+ $result .= '<span class="smwtlposition" style="display:none;" >' . $positions[count(
+ $positions
+ ) - 1] . '</span>';
+ break;
+ case 'today':
+ break; // default
+ case 'middle':
+ default:
+ $result .= '<span class="smwtlposition" style="display:none;" >' . $positions[ceil(
+ count( $positions ) / 2
+ ) - 1] . '</span>';
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Hanldes a single property value. Returns an array with data for a single event or false.
+ *
+ * FIXME: 13 arguments, of which a whole bunch are byref... not a good design :)
+ *
+ * @since 1.5.3
+ *
+ * @param SMWDataValue $object
+ * @param $outputmode
+ * @param SMWPrintRequest $pr
+ * @param boolean $first_col
+ * @param boolean &$hastitle
+ * @param boolean &$hastime
+ * @param boolean $first_value
+ * @param boolean $isEventline
+ * @param string &$curmeta
+ * @param string &$curdata
+ * @param &$date_value
+ * @param boolean &$output
+ * @param array &$positions
+ *
+ * @return false or array
+ */
+ protected function handlePropertyValue( SMWDataValue $object, $outputmode, SMWPrintRequest $pr, $first_col,
+ &$hastitle, &$hastime, $first_value, $isEventline, &$curmeta, &$curdata, $date_value, &$output, array &$positions ) {
+ global $curarticle, $cururl;
+
+ $event = false;
+
+ $l = $this->getLinker( $first_col );
+
+ if ( !$hastitle && $object->getTypeID(
+ ) != '_wpg' ) { // "linking" non-pages in title positions confuses timeline scripts, don't try this
+ $l = null;
+ }
+
+ if ( $object->getTypeID() == '_wpg' ) { // use shorter "LongText" for wikipage
+ $objectlabel = $object->getLongText( $outputmode, $l );
+ } else {
+ $objectlabel = $object->getShortText( $outputmode, $l );
+ }
+
+ $urlobject = ( $l !== null );
+ $header = '';
+
+ if ( $first_value ) {
+ // find header for current value:
+ if ( $this->mShowHeaders && ( '' != $pr->getLabel() ) ) {
+ $header = $pr->getText( $outputmode, $this->mLinker ) . ': ';
+ }
+
+ // is this a start date?
+ if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
+ ( $date_value == $this->m_tlstart ) ) {
+ // FIXME: Timeline scripts should support XSD format explicitly. They
+ // currently seem to implement iso8601 which deviates from XSD in cases.
+ // NOTE: We can assume $object to be an SMWDataValue in this case.
+ $curmeta .= Html::element(
+ 'span',
+ [ 'class' => 'smwtlstart' ],
+ $object->getXMLSchemaDate()
+ );
+ $positions[$object->getHash()] = $object->getXMLSchemaDate();
+ $hastime = true;
+ }
+
+ // is this the end date?
+ if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
+ ( $date_value == $this->m_tlend ) ) {
+ // NOTE: We can assume $object to be an SMWDataValue in this case.
+ $curmeta .= Html::element(
+ 'span',
+ [ 'class' => 'smwtlend' ],
+ $object->getXMLSchemaDate( false )
+ );
+ }
+
+ // find title for displaying event
+ if ( !$hastitle ) {
+ $curmeta .= Html::rawElement(
+ 'span',
+ [
+ 'class' => $urlobject ? 'smwtlurl' : 'smwtltitle'
+ ],
+ $objectlabel
+ );
+
+ if ( $pr->getMode() == SMWPrintRequest::PRINT_THIS ) {
+ $curarticle = $object->getLongText( $outputmode, $l );
+ $cururl = $object->getDataItem()->getTitle()->getFullUrl();
+ }
+
+ // NOTE: type Title of $object implied
+ $hastitle = true;
+ }
+ } elseif ( $output ) {
+ // it *can* happen that output is false here, if the subject was not printed (fixed subject query) and mutliple items appear in the first row
+ $curdata .= ', ';
+ }
+
+ if ( !$first_col || !$first_value || $isEventline ) {
+ $curdata .= $header . $objectlabel;
+ $output = true;
+ }
+
+ if ( $isEventline && ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID(
+ ) == '_dat' ) && ( '' != $pr->getLabel(
+ ) ) && ( $date_value != $this->m_tlstart ) && ( $date_value != $this->m_tlend ) ) {
+ $event = [
+ $object->getXMLSchemaDate(),
+ $pr->getLabel(),
+ $object->getDataItem()->getSortKey(),
+ ];
+ }
+
+ return $event;
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['timelinesize'] = [
+ 'default' => '300px',
+ 'message' => 'srf_paramdesc_timelinesize',
+ ];
+
+ $params['timelineposition'] = [
+ 'default' => 'middle',
+ 'message' => 'srf_paramdesc_timelineposition',
+ 'values' => [ 'start', 'middle', 'end', 'today' ],
+ ];
+
+ $params['timelinestart'] = [
+ 'default' => '',
+ 'message' => 'srf_paramdesc_timelinestart',
+ ];
+
+ $params['timelineend'] = [
+ 'default' => '',
+ 'message' => 'srf_paramdesc_timelineend',
+ ];
+
+ $params['timelinebands'] = [
+ 'islist' => true,
+ 'default' => [ 'MONTH', 'YEAR' ],
+ 'message' => 'srf_paramdesc_timelinebands',
+ 'values' => [ 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'YEAR', 'DECADE' ],
+ ];
+
+ $params['template'] = [
+ 'message' => 'smw-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params['named args'] = [
+ 'type' => 'boolean',
+ 'message' => 'smw-paramdesc-named_args',
+ 'default' => false,
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/LICENSE b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/LICENSE
new file mode 100644
index 00000000..b9b28b0d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/LICENSE
@@ -0,0 +1,33 @@
+----
+The contents of this folder and all of its subfolders is subject to
+the following BSD-style license. In particular, it is not distributed
+under the GPL license that most other parts of Semantic MediaWiki are
+distributed as.
+----
+
+ © Copyright The SIMILE Project 2003-2005.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/geochrono-api.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/geochrono-api.js
new file mode 100644
index 00000000..3de9acad
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/geochrono-api.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Geochrono Extension
+ *
+ * This file will load all the Javascript files
+ * necessary to make the extension work.
+ *
+ *==================================================
+ */
+
+(function() {
+ var javascriptFiles = [
+ "geochrono.js",
+ "units.js",
+ "ether-painters.js",
+ "labellers.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var localizedJavascriptFiles = [
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en" // English
+ ];
+
+ try {
+ var includeJavascriptFile = function(filename) {
+ document.write("<script src='" + Timeline.urlPrefix + "ext/geochrono/scripts/" + filename + "' type='text/javascript'></script>");
+ };
+ var includeCssFile = function(filename) {
+ document.write("<link rel='stylesheet' href='" + Timeline.urlPrefix + "ext/geochrono/styles/" + filename + "' type='text/css'/>");
+ }
+
+ /*
+ * Include non-localized files
+ */
+ for (var i = 0; i < javascriptFiles.length; i++) {
+ includeJavascriptFile(javascriptFiles[i]);
+ }
+ for (var i = 0; i < cssFiles.length; i++) {
+ includeCssFile(cssFiles[i]);
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ tryLocale(Timeline.Platform.serverLocale);
+ tryLocale(Timeline.Platform.clientLocale);
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ for (var i = 0; i < localizedJavascriptFiles.length; i++) {
+ includeJavascriptFile("l10n/" + locale + "/" + localizedJavascriptFiles[i]);
+ }
+ for (var i = 0; i < localizedCssFiles.length; i++) {
+ includeCssFile("l10n/" + locale + "/" + localizedCssFiles[i]);
+ }
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/ether-painters.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/ether-painters.js
new file mode 100644
index 00000000..60e7a539
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/ether-painters.js
@@ -0,0 +1,204 @@
+/*==================================================
+ * Geochrono Ether Painter
+ *==================================================
+ */
+
+Timeline.GeochronoEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._intervalUnit = params.intervalUnit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+ this._theme = params.theme;
+};
+
+Timeline.GeochronoEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && typeof this._params.align == "string") ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.GeochronoEtherMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GeochronoEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.GeochronoEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = Math.ceil(Timeline.GeochronoUnit.toNumber(this._band.getMinDate()));
+ var maxDate = Math.floor(Timeline.GeochronoUnit.toNumber(this._band.getMaxDate()));
+
+ var increment;
+ var hasMore;
+ (function(intervalUnit, multiple) {
+ var dates;
+
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons; break;
+ default:
+ hasMore = function() {
+ return minDate > 0 && minDate > maxDate;
+ }
+ increment = function() {
+ minDate -= multiple;
+ };
+ return;
+ }
+
+ var startIndex = dates.length - 1;
+ while (startIndex > 0) {
+ if (minDate <= dates[startIndex].start) {
+ break;
+ }
+ startIndex--;
+ }
+
+ minDate = dates[startIndex].start;
+ hasMore = function() {
+ return startIndex < (dates.length - 1) && minDate > maxDate;
+ };
+ increment = function() {
+ startIndex++;
+ minDate = dates[startIndex].start;
+ };
+ })(this._intervalUnit, this._multiple);
+
+ var labeller = this._band.getLabeller();
+ while (true) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ Timeline.GeochronoUnit.fromNumber(minDate),
+ labeller,
+ this._intervalUnit,
+ this._markerLayer,
+ this._lineLayer
+ );
+ if (hasMore()) {
+ increment();
+ } else {
+ break;
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GeochronoEtherPainter.prototype.softPaint = function() {
+};
+
+
+/*==================================================
+ * Geochrono Ether Marker Layout
+ *==================================================
+ */
+
+Timeline.GeochronoEtherMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ Timeline.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ (label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/geochrono.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/geochrono.js
new file mode 100644
index 00000000..8c7be826
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/geochrono.js
@@ -0,0 +1,532 @@
+/*==================================================
+ * Geochrono
+ *==================================================
+ */
+
+Timeline.Geochrono = new Object();
+
+Timeline.Geochrono.eons = [
+ { name: "Proterozoic",
+ start: 2500.000
+ },
+ { name: "Phanerozoic",
+ start: 542.000
+ }
+];
+
+Timeline.Geochrono.eras = [
+ { name: "Paleoarchean",
+ start: 3600.000
+ },
+ { name: "Mesoarchean",
+ start: 3200.000
+ },
+ { name: "Neoarchean",
+ start: 2800.000
+ },
+ { name: "Paleoproterozoic",
+ start: 2500.000
+ },
+ { name: "Mesoproterozoic",
+ start: 1600.000
+ },
+ { name: "Neoproterozoic",
+ start: 1000.000
+ },
+ { name: "Paleozoic",
+ start: 542.000
+ },
+ { name: "Mesozoic",
+ start: 251.000
+ },
+ { name: "Cenozoic",
+ start: 65.500
+ }
+];
+
+Timeline.Geochrono.periods = [
+ { name: "Siderian",
+ start: 2500.000
+ },
+ { name: "Rhyacian",
+ start: 2300.000
+ },
+ { name: "Orosirian",
+ start: 2050.000
+ },
+ { name: "Statherian",
+ start: 1800.000
+ },
+ { name: "Calymmian",
+ start: 1600.000
+ },
+ { name: "Ectasian",
+ start: 1400.000
+ },
+ { name: "Stenian",
+ start: 1200.000
+ },
+ { name: "Tonian",
+ start: 1000.000
+ },
+ { name: "Cryogenian",
+ start: 850.000
+ },
+ { name: "Ediacaran",
+ start: 600.000
+ },
+ { name: "Cambrian",
+ start: 542.000
+ },
+ { name: "Ordovician",
+ start: 488.300
+ },
+ { name: "Silurian",
+ start: 443.700
+ },
+ { name: "Devonian",
+ start: 416.000
+ },
+ { name: "Carboniferous",
+ start: 359.200
+ },
+ { name: "Permian",
+ start: 299.000
+ },
+ { name: "Triassic",
+ start: 251.000
+ },
+ { name: "Jurassic",
+ start: 199.600
+ },
+ { name: "Cretaceous",
+ start: 145.500
+ },
+ { name: "Paleogene",
+ start: 65.500
+ },
+ { name: "Neogene",
+ start: 23.030
+ }
+];
+
+Timeline.Geochrono.epoches = [
+ { name: "Lower Cambrian",
+ start: 542.000
+ },
+ { name: "Middle Cambrian",
+ start: 513.000
+ },
+ { name: "Furongian",
+ start: 501.000
+ },
+ { name: "Lower Ordovician",
+ start: 488.300
+ },
+ { name: "Middle Ordovician",
+ start: 471.800
+ },
+ { name: "Upper Ordovician",
+ start: 460.900
+ },
+ { name: "Llandovery",
+ start: 443.700
+ },
+ { name: "Wenlock",
+ start: 428.200
+ },
+ { name: "Ludlow",
+ start: 422.900
+ },
+ { name: "Pridoli",
+ start: 418.700
+ },
+ { name: "Lower Devonian",
+ start: 416.000
+ },
+ { name: "Middle Devonian",
+ start: 397.500
+ },
+ { name: "Upper Devonian",
+ start: 385.300
+ },
+ { name: "Mississippian",
+ start: 359.200
+ },
+ { name: "Pennsylvanian",
+ start: 318.100
+ },
+ { name: "Cisuralian",
+ start: 299.000
+ },
+ { name: "Guadalupian",
+ start: 270.600
+ },
+ { name: "Lopingian",
+ start: 260.400
+ },
+ { name: "Lower Triassic",
+ start: 251.000
+ },
+ { name: "Middle Triassic",
+ start: 245.000
+ },
+ { name: "Upper Triassic",
+ start: 228.000
+ },
+ { name: "Lower Jurassic",
+ start: 199.600
+ },
+ { name: "Middle Jurassic",
+ start: 175.600
+ },
+ { name: "Upper Jurassic",
+ start: 161.200
+ },
+ { name: "Lower Cretaceous",
+ start: 145.500
+ },
+ { name: "Upper Cretaceous",
+ start: 99.600
+ },
+ { name: "Paleocene",
+ start: 65.500
+ },
+ { name: "Eocene",
+ start: 55.800
+ },
+ { name: "Oligocene",
+ start: 33.900
+ },
+ { name: "Miocene",
+ start: 23.030
+ },
+ { name: "Pliocene",
+ start: 5.332
+ },
+ { name: "Pleistocene",
+ start: 1.806
+ },
+ { name: "Holocene",
+ start: 0.012
+ }
+];
+
+Timeline.Geochrono.ages = [
+ { name: "-",
+ start: 542.000
+ },
+ { name: "-",
+ start: 513.000
+ },
+ { name: "Paibian",
+ start: 501.000
+ },
+ { name: "Tremadocian",
+ start: 488.300
+ },
+ { name: "-",
+ start: 478.600
+ },
+ { name: "-",
+ start: 471.800
+ },
+ { name: "Darriwilian",
+ start: 468.100
+ },
+ { name: "-",
+ start: 460.900
+ },
+ { name: "-",
+ start: 455.800
+ },
+ { name: "Hirnantian",
+ start: 445.600
+ },
+ { name: "Rhuddanian",
+ start: 443.700
+ },
+ { name: "Aeronian",
+ start: 439.000
+ },
+ { name: "Telychian",
+ start: 436.100
+ },
+ { name: "Sheinwoodian",
+ start: 428.200
+ },
+ { name: "Homerian",
+ start: 426.200
+ },
+ { name: "Gorstian",
+ start: 422.900
+ },
+ { name: "Ludfordian",
+ start: 421.300
+ },
+ { name: "-",
+ start: 418.700
+ },
+ { name: "Lochkovian",
+ start: 416.000
+ },
+ { name: "Pragian",
+ start: 411.200
+ },
+ { name: "Emsian",
+ start: 407.000
+ },
+ { name: "Eifelian",
+ start: 397.500
+ },
+ { name: "Givetian",
+ start: 391.800
+ },
+ { name: "Frasnian",
+ start: 385.300
+ },
+ { name: "Famennian",
+ start: 374.500
+ },
+ { name: "Tournaisian",
+ start: 359.200
+ },
+ { name: "Visean",
+ start: 345.300
+ },
+ { name: "Serpukhovian",
+ start: 326.400
+ },
+ { name: "Bashkirian",
+ start: 318.100
+ },
+ { name: "Moscovian",
+ start: 311.700
+ },
+ { name: "Kazimovian",
+ start: 306.500
+ },
+ { name: "Gzhelian",
+ start: 303.900
+ },
+ { name: "Asselian",
+ start: 299.000
+ },
+ { name: "Sakmarian",
+ start: 294.600
+ },
+ { name: "Artinskian",
+ start: 284.400
+ },
+ { name: "Kungurian",
+ start: 275.600
+ },
+ { name: "Roadian",
+ start: 270.600
+ },
+ { name: "Wordian",
+ start: 268.000
+ },
+ { name: "Capitanian",
+ start: 265.800
+ },
+ { name: "Wuchiapingian",
+ start: 260.400
+ },
+ { name: "Changhsingian",
+ start: 253.800
+ },
+ { name: "Induan",
+ start: 251.000
+ },
+ { name: "Olenekian",
+ start: 249.700
+ },
+ { name: "Anisian",
+ start: 245.000
+ },
+ { name: "Ladinian",
+ start: 237.000
+ },
+ { name: "Carnian",
+ start: 228.000
+ },
+ { name: "Norian",
+ start: 216.500
+ },
+ { name: "Rhaetian",
+ start: 203.600
+ },
+ { name: "Hettangian",
+ start: 199.600
+ },
+ { name: "Sinemurian",
+ start: 196.500
+ },
+ { name: "Pliensbachian",
+ start: 189.600
+ },
+ { name: "Toarcian",
+ start: 183.000
+ },
+ { name: "Aalenian",
+ start: 175.600
+ },
+ { name: "Bajocian",
+ start: 171.600
+ },
+ { name: "Bathonian",
+ start: 167.700
+ },
+ { name: "Callovian",
+ start: 164.700
+ },
+ { name: "Oxfordian",
+ start: 161.200
+ },
+ { name: "Kimmeridgian",
+ start: 155.000
+ },
+ { name: "Tithonian",
+ start: 150.800
+ },
+ { name: "Berriasian",
+ start: 145.500
+ },
+ { name: "Valanginian",
+ start: 140.200
+ },
+ { name: "Hauterivian",
+ start: 136.400
+ },
+ { name: "Barremian",
+ start: 130.000
+ },
+ { name: "Aptian",
+ start: 125.000
+ },
+ { name: "Albian",
+ start: 112.000
+ },
+ { name: "Cenomanian",
+ start: 99.600
+ },
+ { name: "Turonian",
+ start: 93.500
+ },
+ { name: "Coniacian",
+ start: 89.300
+ },
+ { name: "Santonian",
+ start: 85.800
+ },
+ { name: "Campanian",
+ start: 83.500
+ },
+ { name: "Maastrichtian",
+ start: 70.600
+ },
+ { name: "Danian",
+ start: 65.500
+ },
+ { name: "Selandian",
+ start: 61.700
+ },
+ { name: "Thanetian",
+ start: 58.700
+ },
+ { name: "Ypresian",
+ start: 55.800
+ },
+ { name: "Lutetian",
+ start: 48.600
+ },
+ { name: "Bartonian",
+ start: 40.400
+ },
+ { name: "Priabonian",
+ start: 37.200
+ },
+ { name: "Rupelian",
+ start: 33.900
+ },
+ { name: "Chattian",
+ start: 28.400
+ },
+ { name: "Aquitanian",
+ start: 23.030
+ },
+ { name: "Burdigalian",
+ start: 20.430
+ },
+ { name: "Langhian",
+ start: 15.970
+ },
+ { name: "Serravallian",
+ start: 13.650
+ },
+ { name: "Tortonian",
+ start: 11.608
+ },
+ { name: "Messinian",
+ start: 7.246
+ },
+ { name: "Zanclean",
+ start: 5.332
+ },
+ { name: "Piacenzian",
+ start: 3.600
+ },
+ { name: "Gelasian",
+ start: 2.588
+ }
+];
+
+
+Timeline.Geochrono.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : Timeline.GeochronoUnit.makeDefaultValue(),
+ interval: 1,
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.GeochronoEtherPainter({
+ intervalUnit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ align: params.align,
+ theme: theme
+ });
+
+ var layout = new Timeline.StaticTrackBasedLayout({
+ eventSource: eventSource,
+ ether: ether,
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ layout: layout,
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = new Timeline.DurationEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/l10n/en/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/l10n/en/labellers.js
new file mode 100644
index 00000000..7e667010
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/l10n/en/labellers.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Localization of Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller.eonNames["en"] = Timeline.Geochrono.eons;
+Timeline.GeochronoLabeller.eraNames["en"] = Timeline.Geochrono.eras;
+Timeline.GeochronoLabeller.periodNames["en"] = Timeline.Geochrono.periods;
+Timeline.GeochronoLabeller.epochNames["en"] = Timeline.Geochrono.epoches;
+Timeline.GeochronoLabeller.ageNames["en"] = Timeline.Geochrono.ages;
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/labellers.js
new file mode 100644
index 00000000..60f8012b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/labellers.js
@@ -0,0 +1,52 @@
+/*==================================================
+ * Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller = function(locale) {
+ this._locale = locale;
+};
+
+Timeline.GeochronoLabeller.eonNames = [];
+Timeline.GeochronoLabeller.eraNames = [];
+Timeline.GeochronoLabeller.periodNames = [];
+Timeline.GeochronoLabeller.epochNames = [];
+Timeline.GeochronoLabeller.ageNames = [];
+
+Timeline.GeochronoLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var n = Timeline.GeochronoUnit.toNumber(date);
+ var dates, names;
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages;
+ names = Timeline.GeochronoLabeller.ageNames; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches;
+ names = Timeline.GeochronoLabeller.epochNames; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods;
+ names = Timeline.GeochronoLabeller.periodNames; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras;
+ names = Timeline.GeochronoLabeller.eraNames; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons;
+ names = Timeline.GeochronoLabeller.eonNames; break;
+ default:
+ return { text: n, emphasized: false };
+ }
+
+ for (var i = dates.length - 1; i >= 0; i--) {
+ if (n <= dates[i].start) {
+ return {
+ text: names[this._locale][i].name,
+ emphasized: n == dates[i].start
+ }
+ }
+ }
+ return { text: n, emphasized: false };
+};
+
+Timeline.GeochronoLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.GeochronoUnit.toNumber(date) + "ma";
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/units.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/units.js
new file mode 100644
index 00000000..d36952bc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/ext/geochrono/scripts/units.js
@@ -0,0 +1,86 @@
+/*==================================================
+ * Geochrono Unit
+ *==================================================
+ */
+
+Timeline.GeochronoUnit = new Object();
+
+Timeline.GeochronoUnit.MA = 0;
+Timeline.GeochronoUnit.AGE = 1;
+Timeline.GeochronoUnit.EPOCH = 2;
+Timeline.GeochronoUnit.PERIOD = 3;
+Timeline.GeochronoUnit.ERA = 4;
+Timeline.GeochronoUnit.EON = 5;
+
+Timeline.GeochronoUnit.getParser = function(format) {
+ return Timeline.GeochronoUnit.parseFromObject;
+};
+
+Timeline.GeochronoUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.GeochronoLabeller(locale);
+};
+
+Timeline.GeochronoUnit.wrapMA = function (n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.makeDefaultValue = function () {
+ return Timeline.GeochronoUnit.wrapMA(0);
+};
+
+Timeline.GeochronoUnit.cloneValue = function (v) {
+ return new Timeline.GeochronoUnit._MA(v._n);
+};
+
+Timeline.GeochronoUnit.parseFromObject = function(o) {
+ if (o instanceof Timeline.GeochronoUnit._MA) {
+ return o;
+ } else if (typeof o == "number") {
+ return Timeline.GeochronoUnit.wrapMA(o);
+ } else if (typeof o == "string" && o.length > 0) {
+ return Timeline.GeochronoUnit.wrapMA(Number(o));
+ } else {
+ return null;
+ }
+};
+
+Timeline.GeochronoUnit.toNumber = function(v) {
+ return v._n;
+};
+
+Timeline.GeochronoUnit.fromNumber = function(n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1._n;
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2._n;
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n2 - n1;
+};
+
+Timeline.GeochronoUnit.earlier = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.later = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.change = function(v, n) {
+ return new Timeline.GeochronoUnit._MA(v._n - n);
+};
+
+Timeline.GeochronoUnit._MA = function(n) {
+ this._n = n;
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/blue-circle.png
new file mode 100644
index 00000000..16fc27cf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-arrow.png
new file mode 100644
index 00000000..c82d04d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-left.png
new file mode 100644
index 00000000..e338f86b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-right.png
new file mode 100644
index 00000000..e5dc1367
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom.png
new file mode 100644
index 00000000..7d8ef71e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-bottom.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left-arrow.png
new file mode 100644
index 00000000..3370c726
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left.png
new file mode 100644
index 00000000..772bf23a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right-arrow.png
new file mode 100644
index 00000000..1f1017d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right.png
new file mode 100644
index 00000000..83954b64
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-arrow.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-arrow.png
new file mode 100644
index 00000000..0eadf3f1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-arrow.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-left.png
new file mode 100644
index 00000000..53313719
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-right.png
new file mode 100644
index 00000000..72be593e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top.png
new file mode 100644
index 00000000..afc8cf74
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/bubble-top.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/close-button.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/close-button.png
new file mode 100644
index 00000000..2c6f9e1a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/close-button.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright-vertical.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright-vertical.png
new file mode 100644
index 00000000..c2738f93
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright-vertical.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright.png
new file mode 100644
index 00000000..1132a4e5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/copyright.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-blue-circle.png
new file mode 100644
index 00000000..719682bd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-green-circle.png
new file mode 100644
index 00000000..46da7812
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-red-circle.png
new file mode 100644
index 00000000..481dc810
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dark-red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-blue-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-blue-circle.png
new file mode 100644
index 00000000..dd8336b7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-blue-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-green-circle.png
new file mode 100644
index 00000000..5891980e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-red-circle.png
new file mode 100644
index 00000000..e637430e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/dull-red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/gray-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/gray-circle.png
new file mode 100644
index 00000000..99a394c3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/gray-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/green-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/green-circle.png
new file mode 100644
index 00000000..fccd61ba
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/green-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-left.png
new file mode 100644
index 00000000..4f8c64a1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-right.png
new file mode 100644
index 00000000..a8834bb6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-bottom-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-left.png
new file mode 100644
index 00000000..b6416aab
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-right.png
new file mode 100644
index 00000000..729524bb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-left.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-left.png
new file mode 100644
index 00000000..b0501341
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-right.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-right.png
new file mode 100644
index 00000000..01a82ab2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/message-top-right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/progress-running.gif b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/progress-running.gif
new file mode 100644
index 00000000..f7429ebc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/progress-running.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/red-circle.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/red-circle.png
new file mode 100644
index 00000000..7847d1f0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/red-circle.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/top-bubble.png b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/top-bubble.png
new file mode 100644
index 00000000..078b578f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/images/top-bubble.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/decorators.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/decorators.js
new file mode 100644
index 00000000..b76c0d68
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/decorators.js
@@ -0,0 +1,179 @@
+/*==================================================
+ * Span Highlight Decorator
+ *==================================================
+ */
+
+Timeline.SpanHighlightDecorator = function(params) {
+ this._startDate = Timeline.DateTime.parseGregorianDateTime(params.startDate);
+ this._endDate = Timeline.DateTime.parseGregorianDateTime(params.endDate);
+ this._startLabel = params.startLabel;
+ this._endLabel = params.endLabel;
+ this._color = params.color;
+ this._opacity = ("opacity" in params) ? params.opacity : 100;
+};
+
+Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._layerDiv = null;
+};
+
+Timeline.SpanHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(10);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._startDate.getTime() < maxDate.getTime() &&
+ this._endDate.getTime() > minDate.getTime()) {
+
+ minDate = new Date(Math.max(minDate.getTime(), this._startDate.getTime()));
+ maxDate = new Date(Math.min(maxDate.getTime(), this._endDate.getTime()));
+
+ var minPixel = this._band.dateToPixelOffset(minDate);
+ var maxPixel = this._band.dateToPixelOffset(maxDate);
+
+ var doc = this._timeline.getDocument();
+
+ var createTable = function() {
+ var table = doc.createElement("table");
+ table.insertRow(0).insertCell(0);
+ return table;
+ };
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.background = this._color;
+ if (this._opacity < 100) {
+ Timeline.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ var tableStartLabel = createTable();
+ tableStartLabel.style.position = "absolute";
+ tableStartLabel.style.overflow = "hidden";
+ tableStartLabel.style.fontSize = "300%";
+ tableStartLabel.style.fontWeight = "bold";
+ tableStartLabel.style.color = this._color;
+ tableStartLabel.rows[0].cells[0].innerHTML = this._startLabel;
+ this._layerDiv.appendChild(tableStartLabel);
+
+ var tableEndLabel = createTable();
+ tableEndLabel.style.position = "absolute";
+ tableEndLabel.style.overflow = "hidden";
+ tableEndLabel.style.fontSize = "300%";
+ tableEndLabel.style.fontWeight = "bold";
+ tableEndLabel.style.color = this._color;
+ tableEndLabel.rows[0].cells[0].innerHTML = this._endLabel;
+ this._layerDiv.appendChild(tableEndLabel);
+
+ if (this._timeline.isHorizontal()) {
+ div.style.left = minPixel + "px";
+ div.style.width = (maxPixel - minPixel) + "px";
+ div.style.top = "0px";
+ div.style.height = "100%";
+
+ tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px";
+ tableStartLabel.style.width = (this._startLabel.length) + "em";
+ tableStartLabel.style.top = "0px";
+ tableStartLabel.style.height = "100%";
+ tableStartLabel.style.textAlign = "right";
+
+ tableEndLabel.style.left = maxPixel + "px";
+ tableEndLabel.style.width = (this._endLabel.length) + "em";
+ tableEndLabel.style.top = "0px";
+ tableEndLabel.style.height = "100%";
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = (maxPixel - minPixel) + "px";
+ div.style.left = "0px";
+ div.style.width = "100%";
+
+ tableStartLabel.style.bottom = minPixel + "px";
+ tableStartLabel.style.height = "1.5px";
+ tableStartLabel.style.left = "0px";
+ tableStartLabel.style.width = "100%";
+
+ tableEndLabel.style.top = maxPixel + "px";
+ tableEndLabel.style.height = "1.5px";
+ tableEndLabel.style.left = "0px";
+ tableEndLabel.style.width = "100%";
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Point Highlight Decorator
+ *==================================================
+ */
+
+Timeline.PointHighlightDecorator = function(params) {
+ this._date = Timeline.DateTime.parseGregorianDateTime(params.date);
+ this._width = ("width" in params) ? params.width : 10;
+ this._color = params.color;
+ this._opacity = ("opacity" in params) ? params.opacity : 100;
+};
+
+Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._layerDiv = null;
+};
+
+Timeline.PointHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(10);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._date.getTime() < maxDate.getTime() &&
+ this._date.getTime() > minDate.getTime()) {
+
+ var pixel = this._band.dateToPixelOffset(this._date);
+ var minPixel = pixel - Math.round(this._width / 2);
+
+ var doc = this._timeline.getDocument();
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.background = this._color;
+ if (this._opacity < 100) {
+ Timeline.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ if (this._timeline.isHorizontal()) {
+ div.style.left = minPixel + "px";
+ div.style.width = this._width + "px";
+ div.style.top = "0px";
+ div.style.height = "100%";
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = this._width + "px";
+ div.style.left = "0px";
+ div.style.width = "100%";
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.PointHighlightDecorator.prototype.softPaint = function() {
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ether-painters.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ether-painters.js
new file mode 100644
index 00000000..83fcf55b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ether-painters.js
@@ -0,0 +1,563 @@
+/*==================================================
+ * Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.GregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._unit = params.unit;
+};
+
+Timeline.GregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.GregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ Timeline.DateTime.roundDownToInterval(minDate, this._unit, timeZone, 1, this._theme.firstDayOfWeek);
+
+ var p = this;
+ var incrementDate = function(date) {
+ Timeline.DateTime.incrementByInterval(date, p._unit);
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, this._unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GregorianEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Hot Zone Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.HotZoneGregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+
+ this._zones = [{
+ startTime: Number.NEGATIVE_INFINITY,
+ endTime: Number.POSITIVE_INFINITY,
+ unit: params.unit,
+ multiple: 1
+ }];
+ for (var i = 0; i < params.zones.length; i++) {
+ var zone = params.zones[i];
+ var zoneStart = Timeline.DateTime.parseGregorianDateTime(zone.start).getTime();
+ var zoneEnd = Timeline.DateTime.parseGregorianDateTime(zone.end).getTime();
+
+ for (var j = 0; j < this._zones.length && zoneEnd > zoneStart; j++) {
+ var zone2 = this._zones[j];
+
+ if (zoneStart < zone2.endTime) {
+ if (zoneStart > zone2.startTime) {
+ this._zones.splice(j, 0, {
+ startTime: zone2.startTime,
+ endTime: zoneStart,
+ unit: zone2.unit,
+ multiple: zone2.multiple
+ });
+ j++;
+
+ zone2.startTime = zoneStart;
+ }
+
+ if (zoneEnd < zone2.endTime) {
+ this._zones.splice(j, 0, {
+ startTime: zoneStart,
+ endTime: zoneEnd,
+ unit: zone.unit,
+ multiple: (zone.multiple) ? zone.multiple : 1
+ });
+ j++;
+
+ zone2.startTime = zoneEnd;
+ zoneStart = zoneEnd;
+ } else {
+ zone2.multiple = zone.multiple;
+ zone2.unit = zone.unit;
+ zoneStart = zone2.endTime;
+ }
+ } // else, try the next existing zone
+ }
+ }
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ var p = this;
+ var incrementDate = function(date, zone) {
+ for (var i = 0; i < zone.multiple; i++) {
+ Timeline.DateTime.incrementByInterval(date, zone.unit);
+ }
+ };
+
+ var zStart = 0;
+ while (zStart < this._zones.length) {
+ if (minDate.getTime() < this._zones[zStart].endTime) {
+ break;
+ }
+ zStart++;
+ }
+ var zEnd = this._zones.length - 1;
+ while (zEnd >= 0) {
+ if (maxDate.getTime() > this._zones[zEnd].startTime) {
+ break;
+ }
+ zEnd--;
+ }
+
+ for (var z = zStart; z <= zEnd; z++) {
+ var zone = this._zones[z];
+
+ var minDate2 = new Date(Math.max(minDate.getTime(), zone.startTime));
+ var maxDate2 = new Date(Math.min(maxDate.getTime(), zone.endTime));
+
+ Timeline.DateTime.roundDownToInterval(minDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+ Timeline.DateTime.roundUpToInterval(maxDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+
+ while (minDate2.getTime() < maxDate2.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate2, labeller, zone.unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate2, zone);
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Year Count Ether Painter
+ *==================================================
+ */
+
+Timeline.YearCountEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = Timeline.DateTime.parseGregorianDateTime(params.startDate);
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.YearCountEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.YearCountEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.YearCountEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(this._startDate.getTime());
+ var maxDate = this._band.getMaxDate();
+ var yearDiff = this._band.getMinDate().getUTCFullYear() - this._startDate.getUTCFullYear();
+ minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear() - yearDiff % this._multiple);
+
+ var p = this;
+ var incrementDate = function(date) {
+ for (var i = 0; i < p._multiple; i++) {
+ Timeline.DateTime.incrementByInterval(date, Timeline.DateTime.YEAR);
+ }
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var diff = date.getUTCFullYear() - p._startDate.getUTCFullYear();
+ return {
+ text: diff,
+ emphasized: diff == 0
+ };
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, Timeline.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.YearCountEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Quarterly Ether Painter
+ *==================================================
+ */
+
+Timeline.QuarterlyEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = Timeline.DateTime.parseGregorianDateTime(params.startDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(0);
+ var maxDate = this._band.getMaxDate();
+
+ minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(), this._band.getMinDate().getUTCFullYear()));
+ minDate.setUTCMonth(this._startDate.getUTCMonth());
+
+ var p = this;
+ var incrementDate = function(date) {
+ date.setUTCMonth(date.getUTCMonth() + 3);
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var quarters = (4 + (date.getUTCMonth() - p._startDate.getUTCMonth()) / 3) % 4;
+ if (quarters != 0) {
+ return { text: "Q" + (quarters + 1), emphasized: false };
+ } else {
+ return { text: "Y" + (date.getUTCFullYear() - p._startDate.getUTCFullYear() + 1), emphasized: true };
+ }
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, Timeline.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Ether Interval Marker Layout
+ *==================================================
+ */
+
+Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+ var weekendTheme = theme.ether.interval.weekend;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+ var day = Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.DAY];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine && unit != Timeline.DateTime.WEEK) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ Timeline.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+ if (unit == Timeline.DateTime.WEEK) {
+ var firstDayOfWeek = theme.firstDayOfWeek;
+
+ var saturday = new Date(date.getTime() + (6 - firstDayOfWeek - 7) * day);
+ var monday = new Date(saturday.getTime() + 2 * day);
+
+ var saturdayPixel = Math.round(band.dateToPixelOffset(saturday));
+ var mondayPixel = Math.round(band.dateToPixelOffset(monday));
+ var length = Math.max(1, mondayPixel - saturdayPixel);
+
+ var divWeekend = timeline.getDocument().createElement("div");
+ divWeekend.style.position = "absolute";
+
+ divWeekend.style.background = weekendTheme.color;
+ if (weekendTheme.opacity < 100) {
+ Timeline.Graphics.setOpacity(divWeekend, weekendTheme.opacity);
+ }
+
+ if (horizontal) {
+ divWeekend.style.left = saturdayPixel + "px";
+ divWeekend.style.width = length + "px";
+ divWeekend.style.top = "0px";
+ divWeekend.style.height = "100%";
+ } else {
+ divWeekend.style.top = saturdayPixel + "px";
+ divWeekend.style.height = length + "px";
+ divWeekend.style.left = "0px";
+ divWeekend.style.width = "100%";
+ }
+ lineDiv.appendChild(divWeekend);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ (label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+};
+
+/*==================================================
+ * Ether Highlight Layout
+ *==================================================
+ */
+
+Timeline.EtherHighlight = function(timeline, band, theme, backgroundLayer) {
+ var horizontal = timeline.isHorizontal();
+
+ this._highlightDiv = null;
+ this._createHighlightDiv = function() {
+ if (this._highlightDiv == null) {
+ this._highlightDiv = timeline.getDocument().createElement("div");
+ this._highlightDiv.setAttribute("name", "ether-highlight"); // for debugging
+ this._highlightDiv.style.position = "absolute";
+ this._highlightDiv.style.background = theme.ether.highlightColor;
+
+ var opacity = theme.ether.highlightOpacity;
+ if (opacity < 100) {
+ Timeline.Graphics.setOpacity(this._highlightDiv, opacity);
+ }
+
+ backgroundLayer.appendChild(this._highlightDiv);
+ }
+ }
+
+ this.position = function(startDate, endDate) {
+ this._createHighlightDiv();
+
+ var startPixel = Math.round(band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(band.dateToPixelOffset(endDate));
+ var length = Math.max(endPixel - startPixel, 3);
+ if (horizontal) {
+ this._highlightDiv.style.left = startPixel + "px";
+ this._highlightDiv.style.width = length + "px";
+ this._highlightDiv.style.top = "2px";
+ this._highlightDiv.style.height = (band.getViewWidth() - 4) + "px";
+ } else {
+ this._highlightDiv.style.top = startPixel + "px";
+ this._highlightDiv.style.height = length + "px";
+ this._highlightDiv.style.left = "2px";
+ this._highlightDiv.style.width = (band.getViewWidth() - 4) + "px";
+ }
+ }
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ethers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ethers.js
new file mode 100644
index 00000000..0721cf3f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ethers.js
@@ -0,0 +1,250 @@
+/*==================================================
+ * Linear Ether
+ *==================================================
+ */
+
+Timeline.LinearEther = function(params) {
+ this._params = params;
+ this._interval = params.interval;
+ this._pixelsPerInterval = params.pixelsPerInterval;
+};
+
+Timeline.LinearEther.prototype.initialize = function(timeline) {
+ this._timeline = timeline;
+ this._unit = timeline.getUnit();
+
+ if ("startsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.startsOn);
+ } else if ("endsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.endsOn);
+ this.shiftPixels(-this._timeline.getPixelLength());
+ } else if ("centersOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.centersOn);
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ } else {
+ this._start = this._unit.makeDefaultValue();
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ }
+};
+
+Timeline.LinearEther.prototype.setDate = function(date) {
+ this._start = this._unit.cloneValue(date);
+};
+
+Timeline.LinearEther.prototype.shiftPixels = function(pixels) {
+ var numeric = this._interval * pixels / this._pixelsPerInterval;
+ this._start = this._unit.change(this._start, numeric);
+};
+
+Timeline.LinearEther.prototype.dateToPixelOffset = function(date) {
+ var numeric = this._unit.compare(date, this._start);
+ return this._pixelsPerInterval * numeric / this._interval;
+};
+
+Timeline.LinearEther.prototype.pixelOffsetToDate = function(pixels) {
+ var numeric = pixels * this._interval / this._pixelsPerInterval;
+ return this._unit.change(this._start, numeric);
+};
+
+/*==================================================
+ * Hot Zone Ether
+ *==================================================
+ */
+
+Timeline.HotZoneEther = function(params) {
+ this._params = params;
+ this._interval = params.interval;
+ this._pixelsPerInterval = params.pixelsPerInterval;
+};
+
+Timeline.HotZoneEther.prototype.initialize = function(timeline) {
+ this._timeline = timeline;
+ this._unit = timeline.getUnit();
+
+ this._zones = [{
+ startTime: Number.NEGATIVE_INFINITY,
+ endTime: Number.POSITIVE_INFINITY,
+ magnify: 1
+ }];
+ var params = this._params;
+ for (var i = 0; i < params.zones.length; i++) {
+ var zone = params.zones[i];
+ var zoneStart = this._unit.parseFromObject(zone.start);
+ var zoneEnd = this._unit.parseFromObject(zone.end);
+
+ for (var j = 0; j < this._zones.length && this._unit.compare(zoneEnd, zoneStart) > 0; j++) {
+ var zone2 = this._zones[j];
+
+ if (this._unit.compare(zoneStart, zone2.endTime) < 0) {
+ if (this._unit.compare(zoneStart, zone2.startTime) > 0) {
+ this._zones.splice(j, 0, {
+ startTime: zone2.startTime,
+ endTime: zoneStart,
+ magnify: zone2.magnify
+ });
+ j++;
+
+ zone2.startTime = zoneStart;
+ }
+
+ if (this._unit.compare(zoneEnd, zone2.endTime) < 0) {
+ this._zones.splice(j, 0, {
+ startTime: zoneStart,
+ endTime: zoneEnd,
+ magnify: zone.magnify * zone2.magnify
+ });
+ j++;
+
+ zone2.startTime = zoneEnd;
+ zoneStart = zoneEnd;
+ } else {
+ zone2.magnify *= zone.magnify;
+ zoneStart = zone2.endTime;
+ }
+ } // else, try the next existing zone
+ }
+ }
+
+ if ("startsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.startsOn);
+ } else if ("endsOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.endsOn);
+ this.shiftPixels(-this._timeline.getPixelLength());
+ } else if ("centersOn" in this._params) {
+ this._start = this._unit.parseFromObject(this._params.centersOn);
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ } else {
+ this._start = this._unit.makeDefaultValue();
+ this.shiftPixels(-this._timeline.getPixelLength() / 2);
+ }
+};
+
+Timeline.HotZoneEther.prototype.setDate = function(date) {
+ this._start = this._unit.cloneValue(date);
+};
+
+Timeline.HotZoneEther.prototype.shiftPixels = function(pixels) {
+ this._start = this.pixelOffsetToDate(pixels);
+};
+
+Timeline.HotZoneEther.prototype.dateToPixelOffset = function(date) {
+ return this._dateDiffToPixelOffset(this._start, date);
+};
+
+Timeline.HotZoneEther.prototype.pixelOffsetToDate = function(pixels) {
+ return this._pixelOffsetToDate(pixels, this._start);
+};
+
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset = function(fromDate, toDate) {
+ var scale = this._getScale();
+ var fromTime = fromDate;
+ var toTime = toDate;
+
+ var pixels = 0;
+ if (this._unit.compare(fromTime, toTime) < 0) {
+ var z = 0;
+ while (z < this._zones.length) {
+ if (this._unit.compare(fromTime, this._zones[z].endTime) < 0) {
+ break;
+ }
+ z++;
+ }
+
+ while (this._unit.compare(fromTime, toTime) < 0) {
+ var zone = this._zones[z];
+ var toTime2 = this._unit.earlier(toTime, zone.endTime);
+
+ pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+ fromTime = toTime2;
+ z++;
+ }
+ } else {
+ var z = this._zones.length - 1;
+ while (z >= 0) {
+ if (this._unit.compare(fromTime, this._zones[z].startTime) > 0) {
+ break;
+ }
+ z--;
+ }
+
+ while (this._unit.compare(fromTime, toTime) > 0) {
+ var zone = this._zones[z];
+ var toTime2 = this._unit.later(toTime, zone.startTime);
+
+ pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+ fromTime = toTime2;
+ z--;
+ }
+ }
+ return pixels;
+};
+
+Timeline.HotZoneEther.prototype._pixelOffsetToDate = function(pixels, fromDate) {
+ var scale = this._getScale();
+ var time = fromDate;
+ if (pixels > 0) {
+ var z = 0;
+ while (z < this._zones.length) {
+ if (this._unit.compare(time, this._zones[z].endTime) < 0) {
+ break;
+ }
+ z++;
+ }
+
+ while (pixels > 0) {
+ var zone = this._zones[z];
+ var scale2 = scale / zone.magnify;
+
+ if (zone.endTime == Number.POSITIVE_INFINITY) {
+ time = this._unit.change(time, pixels * scale2);
+ pixels = 0;
+ } else {
+ var pixels2 = this._unit.compare(zone.endTime, time) / scale2;
+ if (pixels2 > pixels) {
+ time = this._unit.change(time, pixels * scale2);
+ pixels = 0;
+ } else {
+ time = zone.endTime;
+ pixels -= pixels2;
+ }
+ }
+ z++;
+ }
+ } else {
+ var z = this._zones.length - 1;
+ while (z >= 0) {
+ if (this._unit.compare(time, this._zones[z].startTime) > 0) {
+ break;
+ }
+ z--;
+ }
+
+ pixels = -pixels;
+ while (pixels > 0) {
+ var zone = this._zones[z];
+ var scale2 = scale / zone.magnify;
+
+ if (zone.startTime == Number.NEGATIVE_INFINITY) {
+ time = this._unit.change(time, -pixels * scale2);
+ pixels = 0;
+ } else {
+ var pixels2 = this._unit.compare(time, zone.startTime) / scale2;
+ if (pixels2 > pixels) {
+ time = this._unit.change(time, -pixels * scale2);
+ pixels = 0;
+ } else {
+ time = zone.startTime;
+ pixels -= pixels2;
+ }
+ }
+ z--;
+ }
+ }
+ return time;
+};
+
+Timeline.HotZoneEther.prototype._getScale = function() {
+ return this._interval / this._pixelsPerInterval;
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ext/japanese-eras.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ext/japanese-eras.js
new file mode 100644
index 00000000..437f44ed
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/ext/japanese-eras.js
@@ -0,0 +1,395 @@
+/*==================================================
+ * Japanese Era Date Labeller
+ *==================================================
+ */
+
+Timeline.JapaneseEraDateLabeller = function(locale, timeZone, useRomanizedName) {
+ var o = new Timeline.GregorianDateLabeller(locale, timeZone);
+
+ o._useRomanizedName = (useRomanizedName);
+ o._oldLabelInterval = o.labelInterval;
+ o.labelInterval = Timeline.JapaneseEraDateLabeller._labelInterval;
+
+ return o;
+};
+
+Timeline.JapaneseEraDateLabeller._labelInterval = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.YEAR:
+ case Timeline.DateTime.DECADE:
+ case Timeline.DateTime.CENTURY:
+ case Timeline.DateTime.MILLENNIUM:
+ var y = date2.getUTCFullYear();
+ if (y >= Timeline.JapaneseEraDateLabeller._eras.elementAt(0).startingYear) {
+ var eraIndex = Timeline.JapaneseEraDateLabeller._eras.find(function(era) {
+ return era.startingYear - y;
+ }
+ );
+ if (eraIndex < Timeline.JapaneseEraDateLabeller._eras.length()) {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex);
+ if (y < era.startingYear) {
+ era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex - 1);
+ }
+ } else {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(eraIndex - 1);
+ }
+
+ text = (this._useRomanizedName ? era.romanizedName : era.japaneseName) + " " + (y - era.startingYear + 1);
+ emphasized = intervalUnit == Timeline.DateTime.YEAR && y == era.startingYear;
+ break;
+ } // else, fall through
+ default:
+ return this._oldLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+};
+
+/*==================================================
+ * Japanese Era Ether Painter
+ *==================================================
+ */
+
+Timeline.JapaneseEraEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._theme = params.theme;
+};
+
+Timeline.JapaneseEraEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.JapaneseEraEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.JapaneseEraEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minYear = this._band.getMinDate().getUTCFullYear();
+ var maxYear = this._band.getMaxDate().getUTCFullYear();
+ var eraIndex = Timeline.JapaneseEraDateLabeller._eras.find(function(era) {
+ return era.startingYear - minYear;
+ }
+ );
+
+ var l = Timeline.JapaneseEraDateLabeller._eras.length();
+ for (var i = eraIndex; i < l; i++) {
+ var era = Timeline.JapaneseEraDateLabeller._eras.elementAt(i);
+ if (era.startingYear > maxYear) {
+ break;
+ }
+
+ var d = new Date(0);
+ d.setUTCFullYear(era.startingYear);
+
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ return {
+ text: era.japaneseName,
+ emphasized: true
+ };
+ }
+ };
+
+ this._intervalMarkerLayout.createIntervalMarker(
+ d, labeller, Timeline.DateTime.YEAR, this._markerLayer, this._lineLayer);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.JapaneseEraEtherPainter.prototype.softPaint = function() {
+};
+
+
+Timeline.JapaneseEraDateLabeller._eras = new Timeline.SortedArray(
+ function(e1, e2) {
+ return e1.startingYear - e2.startingYear;
+ },
+ [
+ { startingYear: 645, japaneseName: '大化', romanizedName: "Taika" },
+ { startingYear: 650, japaneseName: '白雉', romanizedName: "Hakuchi" },
+ { startingYear: 686, japaneseName: '朱鳥', romanizedName: "ShuchÅ" },
+ { startingYear: 701, japaneseName: '大å®', romanizedName: "TaihÅ" },
+ { startingYear: 704, japaneseName: '慶雲', romanizedName: "Keiun" },
+ { startingYear: 708, japaneseName: '和銅', romanizedName: "WadÅ" },
+ { startingYear: 715, japaneseName: '霊亀', romanizedName: "Reiki" },
+ { startingYear: 717, japaneseName: '養è€', romanizedName: "YÅrÅ" },
+ { startingYear: 724, japaneseName: '神亀', romanizedName: "Jinki" },
+ { startingYear: 729, japaneseName: '天平', romanizedName: "TenpyÅ" },
+ { startingYear: 749, japaneseName: '天平感å®', romanizedName: "TenpyÅ-kanpÅ" },
+ { startingYear: 749, japaneseName: '天平å‹å®', romanizedName: "TenpyÅ-shÅhÅ" },
+ { startingYear: 757, japaneseName: '天平å®å­—', romanizedName: "TenpyÅ-hÅji" },
+ { startingYear: 765, japaneseName: '天平神護', romanizedName: "TenpyÅ-jingo" },
+ { startingYear: 767, japaneseName: '神護景雲', romanizedName: "Jingo-keiun" },
+ { startingYear: 770, japaneseName: 'å®äº€', romanizedName: "HÅki" },
+ { startingYear: 781, japaneseName: '天応', romanizedName: "Ten'Å" },
+ { startingYear: 782, japaneseName: '延暦', romanizedName: "Enryaku" },
+ { startingYear: 806, japaneseName: '大åŒ', romanizedName: "DaidÅ" },
+ { startingYear: 810, japaneseName: '弘ä»', romanizedName: "KÅnin" },
+ { startingYear: 824, japaneseName: '天長', romanizedName: "TenchÅ" },
+ { startingYear: 834, japaneseName: '承和', romanizedName: "JÅwa" },
+ { startingYear: 848, japaneseName: '嘉祥', romanizedName: "KajÅ" },
+ { startingYear: 851, japaneseName: 'ä»å¯¿', romanizedName: "Ninju" },
+ { startingYear: 854, japaneseName: '斉衡', romanizedName: "SaikÅ" },
+ { startingYear: 857, japaneseName: '天安', romanizedName: "Tennan" },
+ { startingYear: 859, japaneseName: '貞観', romanizedName: "JÅgan" },
+ { startingYear: 877, japaneseName: '元慶', romanizedName: "GangyÅ" },
+ { startingYear: 885, japaneseName: 'ä»å’Œ', romanizedName: "Ninna" },
+ { startingYear: 889, japaneseName: '寛平', romanizedName: "KanpyÅ" },
+ { startingYear: 898, japaneseName: '昌泰', romanizedName: "ShÅtai" },
+ { startingYear: 901, japaneseName: '延喜', romanizedName: "Engi" },
+ { startingYear: 923, japaneseName: '延長', romanizedName: "EnchÅ" },
+ { startingYear: 931, japaneseName: '承平', romanizedName: "JÅhei" },
+ { startingYear: 938, japaneseName: '天慶', romanizedName: "TengyÅ" },
+ { startingYear: 947, japaneseName: '天暦', romanizedName: "Tenryaku" },
+ { startingYear: 957, japaneseName: '天徳', romanizedName: "Tentoku" },
+ { startingYear: 961, japaneseName: '応和', romanizedName: "Ōwa" },
+ { startingYear: 964, japaneseName: '康ä¿', romanizedName: "KÅhÅ" },
+ { startingYear: 968, japaneseName: '安和', romanizedName: "Anna" },
+ { startingYear: 970, japaneseName: '天禄', romanizedName: "Tenroku" },
+ { startingYear: 973, japaneseName: '天延', romanizedName: "Ten'en" },
+ { startingYear: 976, japaneseName: '貞元', romanizedName: "JÅgen" },
+ { startingYear: 978, japaneseName: '天元', romanizedName: "Tengen" },
+ { startingYear: 983, japaneseName: '永観', romanizedName: "Eikan" },
+ { startingYear: 985, japaneseName: '寛和', romanizedName: "Kanna" },
+ { startingYear: 987, japaneseName: '永延', romanizedName: "Eien" },
+ { startingYear: 988, japaneseName: '永祚', romanizedName: "Eiso" },
+ { startingYear: 990, japaneseName: '正暦', romanizedName: "ShÅryaku" },
+ { startingYear: 995, japaneseName: 'é•·å¾³', romanizedName: "ChÅtoku" },
+ { startingYear: 999, japaneseName: 'é•·ä¿', romanizedName: "ChÅhÅ" },
+ { startingYear: 1004, japaneseName: '寛弘', romanizedName: "KankÅ" },
+ { startingYear: 1012, japaneseName: 'é•·å’Œ', romanizedName: "ChÅwa" },
+ { startingYear: 1017, japaneseName: '寛ä»', romanizedName: "Kannin" },
+ { startingYear: 1021, japaneseName: '治安', romanizedName: "Jian" },
+ { startingYear: 1024, japaneseName: '万寿', romanizedName: "Manju" },
+ { startingYear: 1028, japaneseName: 'é•·å…ƒ', romanizedName: "ChÅgen" },
+ { startingYear: 1037, japaneseName: '長暦', romanizedName: "ChÅryaku" },
+ { startingYear: 1040, japaneseName: 'é•·ä¹…', romanizedName: "ChÅkyÅ«" },
+ { startingYear: 1044, japaneseName: '寛徳', romanizedName: "Kantoku" },
+ { startingYear: 1046, japaneseName: '永承', romanizedName: "EishÅ" },
+ { startingYear: 1053, japaneseName: '天喜', romanizedName: "Tengi" },
+ { startingYear: 1058, japaneseName: '康平', romanizedName: "KÅhei" },
+ { startingYear: 1065, japaneseName: '治暦', romanizedName: "Jiryaku" },
+ { startingYear: 1069, japaneseName: '延久', romanizedName: "Enkyū" },
+ { startingYear: 1074, japaneseName: '承ä¿', romanizedName: "JÅhÅ" },
+ { startingYear: 1077, japaneseName: '承暦', romanizedName: "JÅryaku" },
+ { startingYear: 1081, japaneseName: 'æ°¸ä¿', romanizedName: "EihÅ" },
+ { startingYear: 1084, japaneseName: '応徳', romanizedName: "Ōtoku" },
+ { startingYear: 1087, japaneseName: '寛治', romanizedName: "Kanji" },
+ { startingYear: 1094, japaneseName: '嘉ä¿', romanizedName: "KahÅ" },
+ { startingYear: 1096, japaneseName: '永長', romanizedName: "EichÅ" },
+ { startingYear: 1097, japaneseName: '承徳', romanizedName: "JÅtoku" },
+ { startingYear: 1099, japaneseName: '康和', romanizedName: "KÅwa" },
+ { startingYear: 1104, japaneseName: 'é•·æ²»', romanizedName: "ChÅji" },
+ { startingYear: 1106, japaneseName: '嘉承', romanizedName: "KajÅ" },
+ { startingYear: 1108, japaneseName: '天ä»', romanizedName: "Tennin" },
+ { startingYear: 1110, japaneseName: '天永', romanizedName: "Ten'ei" },
+ { startingYear: 1113, japaneseName: '永久', romanizedName: "Eikyū" },
+ { startingYear: 1118, japaneseName: '元永', romanizedName: "Gen'ei" },
+ { startingYear: 1120, japaneseName: 'ä¿å®‰', romanizedName: "HÅan" },
+ { startingYear: 1124, japaneseName: '天治', romanizedName: "Tenji" },
+ { startingYear: 1126, japaneseName: '大治', romanizedName: "Daiji" },
+ { startingYear: 1131, japaneseName: '天承', romanizedName: "TenshÅ" },
+ { startingYear: 1132, japaneseName: '長承', romanizedName: "ChÅshÅ" },
+ { startingYear: 1135, japaneseName: 'ä¿å»¶', romanizedName: "HÅen" },
+ { startingYear: 1141, japaneseName: '永治', romanizedName: "Eiji" },
+ { startingYear: 1142, japaneseName: '康治', romanizedName: "KÅji" },
+ { startingYear: 1144, japaneseName: '天養', romanizedName: "Ten'yÅ" },
+ { startingYear: 1145, japaneseName: '久安', romanizedName: "Kyūan" },
+ { startingYear: 1151, japaneseName: 'ä»å¹³', romanizedName: "Ninpei" },
+ { startingYear: 1154, japaneseName: '久寿', romanizedName: "Kyūju" },
+ { startingYear: 1156, japaneseName: 'ä¿å…ƒ', romanizedName: "HÅgen" },
+ { startingYear: 1159, japaneseName: '平治', romanizedName: "Heiji" },
+ { startingYear: 1160, japaneseName: '永暦', romanizedName: "Eiryaku" },
+ { startingYear: 1161, japaneseName: 'å¿œä¿', romanizedName: "ÅŒhÅ" },
+ { startingYear: 1163, japaneseName: '長寛', romanizedName: "ChÅkan" },
+ { startingYear: 1165, japaneseName: '永万', romanizedName: "Eiman" },
+ { startingYear: 1166, japaneseName: 'ä»å®‰', romanizedName: "Ninnan" },
+ { startingYear: 1169, japaneseName: '嘉応', romanizedName: "KaÅ" },
+ { startingYear: 1171, japaneseName: '承安', romanizedName: "JÅan" },
+ { startingYear: 1175, japaneseName: '安元', romanizedName: "Angen" },
+ { startingYear: 1177, japaneseName: '治承', romanizedName: "JishÅ" },
+ { startingYear: 1181, japaneseName: '養和', romanizedName: "YÅwa" },
+ { startingYear: 1182, japaneseName: '寿永', romanizedName: "Juei" },
+ { startingYear: 1184, japaneseName: '元暦', romanizedName: "Genryaku" },
+ { startingYear: 1185, japaneseName: '文治', romanizedName: "Bunji" },
+ { startingYear: 1190, japaneseName: '建久', romanizedName: "Kenkyū" },
+ { startingYear: 1199, japaneseName: '正治', romanizedName: "ShÅji" },
+ { startingYear: 1201, japaneseName: '建ä»', romanizedName: "Kennin" },
+ { startingYear: 1204, japaneseName: '元久', romanizedName: "Genkyū" },
+ { startingYear: 1206, japaneseName: '建永', romanizedName: "Ken'ei" },
+ { startingYear: 1207, japaneseName: '承元', romanizedName: "JÅgen" },
+ { startingYear: 1211, japaneseName: '建暦', romanizedName: "Kenryaku" },
+ { startingYear: 1213, japaneseName: '建ä¿', romanizedName: "KenpÅ" },
+ { startingYear: 1219, japaneseName: '承久', romanizedName: "JÅkyÅ«" },
+ { startingYear: 1222, japaneseName: '貞応', romanizedName: "JÅÅ" },
+ { startingYear: 1224, japaneseName: 'å…ƒä»', romanizedName: "Gennin" },
+ { startingYear: 1225, japaneseName: '嘉禄', romanizedName: "Karoku" },
+ { startingYear: 1227, japaneseName: '安貞', romanizedName: "Antei" },
+ { startingYear: 1229, japaneseName: '寛喜', romanizedName: "Kanki" },
+ { startingYear: 1232, japaneseName: '貞永', romanizedName: "JÅei" },
+ { startingYear: 1233, japaneseName: '天ç¦', romanizedName: "Tenpuku" },
+ { startingYear: 1234, japaneseName: '文暦', romanizedName: "Bunryaku" },
+ { startingYear: 1235, japaneseName: '嘉禎', romanizedName: "Katei" },
+ { startingYear: 1238, japaneseName: '暦ä»', romanizedName: "Ryakunin" },
+ { startingYear: 1239, japaneseName: '延応', romanizedName: "En'Å" },
+ { startingYear: 1240, japaneseName: 'ä»æ²»', romanizedName: "Ninji" },
+ { startingYear: 1243, japaneseName: '寛元', romanizedName: "Kangen" },
+ { startingYear: 1247, japaneseName: 'å®æ²»', romanizedName: "HÅji" },
+ { startingYear: 1249, japaneseName: '建長', romanizedName: "KenchÅ" },
+ { startingYear: 1256, japaneseName: '康元', romanizedName: "KÅgen" },
+ { startingYear: 1257, japaneseName: '正嘉', romanizedName: "ShÅka" },
+ { startingYear: 1259, japaneseName: '正元', romanizedName: "ShÅgen" },
+ { startingYear: 1260, japaneseName: '文応', romanizedName: "Bun'Å" },
+ { startingYear: 1261, japaneseName: '弘長', romanizedName: "KÅcho" },
+ { startingYear: 1264, japaneseName: '文永', romanizedName: "Bun'ei" },
+ { startingYear: 1275, japaneseName: '建治', romanizedName: "Kenji" },
+ { startingYear: 1278, japaneseName: '弘安', romanizedName: "KÅan" },
+ { startingYear: 1288, japaneseName: '正応', romanizedName: "ShÅÅ" },
+ { startingYear: 1293, japaneseName: 'æ°¸ä»', romanizedName: "Einin" },
+ { startingYear: 1299, japaneseName: '正安', romanizedName: "ShÅan" },
+ { startingYear: 1302, japaneseName: '乾元', romanizedName: "Kengen" },
+ { startingYear: 1303, japaneseName: '嘉元', romanizedName: "Kagen" },
+ { startingYear: 1306, japaneseName: '徳治', romanizedName: "Tokuji" },
+ { startingYear: 1308, japaneseName: '延慶', romanizedName: "Enkei" },
+ { startingYear: 1311, japaneseName: '応長', romanizedName: "ÅŒchÅ" },
+ { startingYear: 1312, japaneseName: '正和', romanizedName: "ShÅwa" },
+ { startingYear: 1317, japaneseName: 'æ–‡ä¿', romanizedName: "BunpÅ" },
+ { startingYear: 1319, japaneseName: '元応', romanizedName: "Gen'Å" },
+ { startingYear: 1321, japaneseName: '元亨', romanizedName: "GenkyÅ" },
+ { startingYear: 1324, japaneseName: '正中', romanizedName: "ShÅchÅ«" },
+ { startingYear: 1326, japaneseName: '嘉暦', romanizedName: "Karyaku" },
+ { startingYear: 1329, japaneseName: '元徳', romanizedName: "Gentoku" },
+ { startingYear: 1331, japaneseName: '元弘', romanizedName: "GenkÅ" },
+ { startingYear: 1334, japaneseName: '建武', romanizedName: "Kenmu" },
+ { startingYear: 1336, japaneseName: '延元', romanizedName: "Engen" },
+ { startingYear: 1340, japaneseName: '興国', romanizedName: "KÅkoku" },
+ { startingYear: 1346, japaneseName: '正平', romanizedName: "ShÅhei" },
+ { startingYear: 1370, japaneseName: '建徳', romanizedName: "Kentoku" },
+ { startingYear: 1372, japaneseName: '文中', romanizedName: "Bunchū" },
+ { startingYear: 1375, japaneseName: '天授', romanizedName: "Tenju" },
+ { startingYear: 1381, japaneseName: '弘和', romanizedName: "KÅwa" },
+ { startingYear: 1384, japaneseName: '元中', romanizedName: "Genchū" },
+ { startingYear: 1332, japaneseName: '正慶', romanizedName: "ShÅkei" },
+ { startingYear: 1338, japaneseName: '暦応', romanizedName: "RyakuÅ" },
+ { startingYear: 1342, japaneseName: '康永', romanizedName: "KÅei" },
+ { startingYear: 1345, japaneseName: '貞和', romanizedName: "JÅwa" },
+ { startingYear: 1350, japaneseName: '観応', romanizedName: "Kan'Å" },
+ { startingYear: 1352, japaneseName: '文和', romanizedName: "Bunna" },
+ { startingYear: 1356, japaneseName: '延文', romanizedName: "Enbun" },
+ { startingYear: 1361, japaneseName: '康安', romanizedName: "KÅan" },
+ { startingYear: 1362, japaneseName: '貞治', romanizedName: "JÅji" },
+ { startingYear: 1368, japaneseName: '応安', romanizedName: "Ōan" },
+ { startingYear: 1375, japaneseName: '永和', romanizedName: "Eiwa" },
+ { startingYear: 1379, japaneseName: '康暦', romanizedName: "KÅryaku" },
+ { startingYear: 1381, japaneseName: '永徳', romanizedName: "Eitoku" },
+ { startingYear: 1384, japaneseName: '至徳', romanizedName: "Shitoku" },
+ { startingYear: 1387, japaneseName: '嘉慶', romanizedName: "Kakei" },
+ { startingYear: 1389, japaneseName: '康応', romanizedName: "KÅÅ" },
+ { startingYear: 1390, japaneseName: '明徳', romanizedName: "Meitoku" },
+ { startingYear: 1394, japaneseName: '応永', romanizedName: "Ōei" },
+ { startingYear: 1428, japaneseName: '正長', romanizedName: "ShÅchÅ" },
+ { startingYear: 1429, japaneseName: '永享', romanizedName: "EikyÅ" },
+ { startingYear: 1441, japaneseName: '嘉å‰', romanizedName: "Kakitsu" },
+ { startingYear: 1444, japaneseName: '文安', romanizedName: "Bunnan" },
+ { startingYear: 1449, japaneseName: 'å®å¾³', romanizedName: "HÅtoku" },
+ { startingYear: 1452, japaneseName: '享徳', romanizedName: "KyÅtoku" },
+ { startingYear: 1455, japaneseName: '康正', romanizedName: "KÅshÅ" },
+ { startingYear: 1457, japaneseName: '長禄', romanizedName: "ChÅroku" },
+ { startingYear: 1460, japaneseName: '寛正', romanizedName: "KanshÅ" },
+ { startingYear: 1466, japaneseName: '文正', romanizedName: "BunshÅ" },
+ { startingYear: 1467, japaneseName: 'å¿œä»', romanizedName: "ÅŒnin" },
+ { startingYear: 1469, japaneseName: '文明', romanizedName: "Bunmei" },
+ { startingYear: 1487, japaneseName: '長享', romanizedName: "ChÅkyÅ" },
+ { startingYear: 1489, japaneseName: '延徳', romanizedName: "Entoku" },
+ { startingYear: 1492, japaneseName: '明応', romanizedName: "MeiÅ" },
+ { startingYear: 1501, japaneseName: '文亀', romanizedName: "Bunki" },
+ { startingYear: 1504, japaneseName: '永正', romanizedName: "EishÅ" },
+ { startingYear: 1521, japaneseName: '大永', romanizedName: "Daiei" },
+ { startingYear: 1528, japaneseName: '享禄', romanizedName: "KyÅroku" },
+ { startingYear: 1532, japaneseName: '天文', romanizedName: "Tenbun" },
+ { startingYear: 1555, japaneseName: '弘治', romanizedName: "KÅji" },
+ { startingYear: 1558, japaneseName: '永禄', romanizedName: "Eiroku" },
+ { startingYear: 1570, japaneseName: '元亀', romanizedName: "Genki" },
+ { startingYear: 1573, japaneseName: '天正', romanizedName: "TenshÅ" },
+ { startingYear: 1592, japaneseName: '文禄', romanizedName: "Bunroku" },
+ { startingYear: 1596, japaneseName: '慶長', romanizedName: "KeichÅ" },
+ { startingYear: 1615, japaneseName: '元和', romanizedName: "Genna" },
+ { startingYear: 1624, japaneseName: '寛永', romanizedName: "Kan'ei" },
+ { startingYear: 1644, japaneseName: 'æ­£ä¿', romanizedName: "ShÅhÅ" },
+ { startingYear: 1648, japaneseName: '慶安', romanizedName: "Keian" },
+ { startingYear: 1652, japaneseName: '承応', romanizedName: "JÅÅ" },
+ { startingYear: 1655, japaneseName: '明暦', romanizedName: "Meireki" },
+ { startingYear: 1658, japaneseName: '万治', romanizedName: "Manji" },
+ { startingYear: 1661, japaneseName: '寛文', romanizedName: "Kanbun" },
+ { startingYear: 1673, japaneseName: '延å®', romanizedName: "EnpÅ" },
+ { startingYear: 1681, japaneseName: '天和', romanizedName: "Tenna" },
+ { startingYear: 1684, japaneseName: '貞享', romanizedName: "JÅkyÅ" },
+ { startingYear: 1688, japaneseName: '元禄', romanizedName: "Genroku" },
+ { startingYear: 1704, japaneseName: 'å®æ°¸', romanizedName: "HÅei" },
+ { startingYear: 1711, japaneseName: '正徳', romanizedName: "ShÅtoku" },
+ { startingYear: 1716, japaneseName: '享ä¿', romanizedName: "KyÅhÅ" },
+ { startingYear: 1736, japaneseName: '元文', romanizedName: "Genbun" },
+ { startingYear: 1741, japaneseName: '寛ä¿', romanizedName: "KanpÅ" },
+ { startingYear: 1744, japaneseName: '延享', romanizedName: "EnkyÅ" },
+ { startingYear: 1748, japaneseName: '寛延', romanizedName: "Kan'en" },
+ { startingYear: 1751, japaneseName: 'å®æš¦', romanizedName: "HÅreki" },
+ { startingYear: 1764, japaneseName: '明和', romanizedName: "Meiwa" },
+ { startingYear: 1772, japaneseName: '安永', romanizedName: "An'ei" },
+ { startingYear: 1781, japaneseName: '天明', romanizedName: "Tenmei" },
+ { startingYear: 1789, japaneseName: '寛政', romanizedName: "Kansei" },
+ { startingYear: 1801, japaneseName: '享和', romanizedName: "KyÅwa" },
+ { startingYear: 1804, japaneseName: '文化', romanizedName: "Bunka" },
+ { startingYear: 1818, japaneseName: '文政', romanizedName: "Bunsei" },
+ { startingYear: 1830, japaneseName: '天ä¿', romanizedName: "TenpÅ" },
+ { startingYear: 1844, japaneseName: '弘化', romanizedName: "KÅka" },
+ { startingYear: 1848, japaneseName: '嘉永', romanizedName: "Kaei" },
+ { startingYear: 1854, japaneseName: '安政', romanizedName: "Ansei" },
+ { startingYear: 1860, japaneseName: '万延', romanizedName: "Man'en" },
+ { startingYear: 1861, japaneseName: '文久', romanizedName: "Bunkyū" },
+ { startingYear: 1864, japaneseName: '元治', romanizedName: "Genji" },
+ { startingYear: 1865, japaneseName: '慶応', romanizedName: "KeiÅ" },
+ { startingYear: 1868, japaneseName: '明治', romanizedName: "Meiji" },
+ { startingYear: 1912, japaneseName: '大正', romanizedName: "TaishÅ" },
+ { startingYear: 1926, japaneseName: '昭和', romanizedName: "ShÅwa" },
+ { startingYear: 1989, japaneseName: 'å¹³æˆ', romanizedName: "Heisei" }
+ ]
+);
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/labellers.js
new file mode 100644
index 00000000..3f1beb6e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["en"] = [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/timeline.js
new file mode 100644
index 00000000..c6b70dda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/en/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["en"] = {
+ wikiLinkLabel: "Discuss"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/labellers.js
new file mode 100644
index 00000000..963038e2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["es"] = [
+ "Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/timeline.js
new file mode 100644
index 00000000..2a5183c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/es/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["es"] = {
+ wikiLinkLabel: "Discute"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/labellers.js
new file mode 100644
index 00000000..5e7392a7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["fr"] = [
+ "jan", "fev", "mar", "avr", "mai", "jui", "jui", "aou", "sep", "oct", "nov", "dec"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/timeline.js
new file mode 100644
index 00000000..459cc384
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/fr/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["fr"] = {
+ wikiLinkLabel: "Discute"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/labellers.js
new file mode 100644
index 00000000..85d50d47
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/labellers.js
@@ -0,0 +1,8 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["it"] = [
+ "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/timeline.js
new file mode 100644
index 00000000..69582dc6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/it/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["it"] = {
+ wikiLinkLabel: "Discuti"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/labellers.js
new file mode 100644
index 00000000..1ca79037
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/labellers.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Localization of labellers.js
+ *
+ * UTF-8 encoded
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["ru"] = [
+ "Янв", "Фев", "Мар", "Ðпр", "Май", "Июн", "Июл", "Ðвг", "Сен", "Окт", "ÐоÑ", "Дек"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/timeline.js
new file mode 100644
index 00000000..ed3e5894
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/ru/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["ru"] = {
+ wikiLinkLabel: "обÑудите"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/labellers.js
new file mode 100644
index 00000000..4b38cb13
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["se"] = [
+ "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"
+];
+
+Timeline.GregorianDateLabeller.dayNames["se"] = [
+ "Sön", "Mån", "Tis", "Ons", "Tors", "Fre", "Lör"
+];
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/timeline.js
new file mode 100644
index 00000000..31751ac1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/se/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["se"] = {
+ wikiLinkLabel: "Discuss"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/labellers.js
new file mode 100644
index 00000000..6cd57fda
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/labellers.js
@@ -0,0 +1,26 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["vi"] = [
+ "Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["vi"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = date2.getUTCDate() + "/" + (date2.getUTCMonth() + 1);
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/timeline.js
new file mode 100644
index 00000000..2d5b3bd4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/vi/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["vi"] = {
+ wikiLinkLabel: "Bàn luận"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/labellers.js
new file mode 100644
index 00000000..9fc881b6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/labellers.js
@@ -0,0 +1,27 @@
+/*==================================================
+ * Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["zh"] = [
+ "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"
+];
+
+Timeline.GregorianDateLabeller.labelIntervalFunctions["zh"] = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ var date2 = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.DAY:
+ case Timeline.DateTime.WEEK:
+ text = Timeline.GregorianDateLabeller.getMonthName(date2.getUTCMonth(), this._locale) +
+ date2.getUTCDate() + "æ—¥";
+ break;
+ default:
+ return this.defaultLabelInterval(date, intervalUnit);
+ }
+
+ return { text: text, emphasized: emphasized };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/timeline.js
new file mode 100644
index 00000000..7d6c7f94
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/l10n/zh/timeline.js
@@ -0,0 +1,9 @@
+/*==================================================
+ * Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["zh"] = {
+ wikiLinkLabel: "讨论"
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/labellers.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/labellers.js
new file mode 100644
index 00000000..9147ff91
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/labellers.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Gregorian Date Labeller
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller = function(locale, timeZone) {
+ this._locale = locale;
+ this._timeZone = timeZone;
+};
+
+Timeline.GregorianDateLabeller.monthNames = [];
+Timeline.GregorianDateLabeller.dayNames = [];
+Timeline.GregorianDateLabeller.labelIntervalFunctions = [];
+
+Timeline.GregorianDateLabeller.getMonthName = function(month, locale) {
+ return Timeline.GregorianDateLabeller.monthNames[locale][month];
+};
+
+Timeline.GregorianDateLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var f = Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+ if (f == null) {
+ f = Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+ }
+ return f.call(this, date, intervalUnit);
+};
+
+Timeline.GregorianDateLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.DateTime.removeTimeZoneOffset(
+ date,
+ this._timeZone //+ (new Date().getTimezoneOffset() / 60)
+ ).toUTCString();
+};
+
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval = function(date, intervalUnit) {
+ var text;
+ var emphasized = false;
+
+ date = Timeline.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.MILLISECOND:
+ text = date.getUTCMilliseconds();
+ break;
+ case Timeline.DateTime.SECOND:
+ text = date.getUTCSeconds();
+ break;
+ case Timeline.DateTime.MINUTE:
+ var m = date.getUTCMinutes();
+ if (m == 0) {
+ text = date.getUTCHours() + ":00";
+ emphasized = true;
+ } else {
+ text = m;
+ }
+ break;
+ case Timeline.DateTime.HOUR:
+ text = date.getUTCHours() + "hr";
+ break;
+ case Timeline.DateTime.DAY:
+ text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+ break;
+ case Timeline.DateTime.WEEK:
+ text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+ break;
+ case Timeline.DateTime.MONTH:
+ var m = date.getUTCMonth();
+ if (m == 0) {
+ text = this.labelInterval(date, Timeline.DateTime.YEAR).text;
+ emphasized = true;
+ } else {
+ text = Timeline.GregorianDateLabeller.getMonthName(m, this._locale);
+ }
+ break;
+ case Timeline.DateTime.YEAR:
+ case Timeline.DateTime.DECADE:
+ case Timeline.DateTime.CENTURY:
+ case Timeline.DateTime.MILLENNIUM:
+ var y = date.getUTCFullYear();
+ if (y > 0) {
+ text = date.getUTCFullYear();
+ } else {
+ text = (1 - y) + "BC";
+ }
+ emphasized = (intervalUnit == Timeline.DateTime.DECADE && y % 100 == 0) ||
+ (intervalUnit == Timeline.DateTime.CENTURY && y % 1000 == 0);
+ break;
+ default:
+ text = date.toUTCString();
+ }
+ return { text: text, emphasized: emphasized };
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/layouts.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/layouts.js
new file mode 100644
index 00000000..9e96a755
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/layouts.js
@@ -0,0 +1,128 @@
+/*==================================================
+ * Static Track Based Layout
+ *==================================================
+ */
+
+
+Timeline.StaticTrackBasedLayout = function(params) {
+ this._eventSource = params.eventSource;
+ this._ether = params.ether;
+ this._theme = params.theme;
+ this._showText = ("showText" in params) ? params.showText : true;
+
+ this._laidout = false;
+
+ var layout = this;
+ if (this._eventSource != null) {
+ this._eventSource.addListener({
+ onAddMany: function() {
+ layout._laidout = false;
+ }
+ });
+ }
+};
+
+Timeline.StaticTrackBasedLayout.prototype.initialize = function(timeline) {
+ this._timeline = timeline;
+};
+
+Timeline.StaticTrackBasedLayout.prototype.getTrack = function(evt) {
+ if (!this._laidout) {
+ this._tracks = [];
+ this._layout();
+ this._laidout = true;
+ }
+ return this._tracks[evt.getID()];
+};
+
+Timeline.StaticTrackBasedLayout.prototype.getTrackCount = function() {
+ if (!this._laidout) {
+ this._tracks = [];
+ this._layout();
+ this._laidout = true;
+ }
+ return this._trackCount;
+};
+
+Timeline.StaticTrackBasedLayout.prototype._layout = function() {
+ if (this._eventSource == null) {
+ return;
+ }
+
+ var streams = [ Number.NEGATIVE_INFINITY ];
+ var layout = this;
+ var showText = this._showText;
+ var theme = this._theme;
+ var eventTheme = theme.event;
+
+ var layoutInstant = function(evt, startPixel, endPixel, streamOffset) {
+ var finalPixel = startPixel - 1;
+ if (evt.isImprecise()) { // imprecise time
+ finalPixel = endPixel;
+ }
+ if (showText) {
+ finalPixel = Math.max(finalPixel, startPixel + eventTheme.label.width);
+ }
+
+ return finalPixel;
+ };
+ var layoutDuration = function(evt, startPixel, endPixel, streamOffset) {
+ if (evt.isImprecise()) { // imprecise time
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+
+ var startPixel2 = Math.round(layout._ether.dateToPixelOffset(startDate));
+ var endPixel2 = Math.round(layout._ether.dateToPixelOffset(endDate));
+ } else {
+ var startPixel2 = startPixel;
+ var endPixel2 = endPixel;
+ }
+
+ var finalPixel = endPixel2;
+ var length = Math.max(endPixel2 - startPixel2, 1);
+
+ if (showText) {
+ if (length < eventTheme.label.width) {
+ finalPixel = endPixel2 + eventTheme.label.width;
+ }
+ }
+
+ return finalPixel;
+ };
+ var layoutEvent = function(evt) {
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+
+ var startPixel = Math.round(layout._ether.dateToPixelOffset(startDate));
+ var endPixel = Math.round(layout._ether.dateToPixelOffset(endDate));
+
+ var streamIndex = 0;
+ for (; streamIndex < streams.length; streamIndex++) {
+ if (streams[streamIndex] < startPixel) {
+ break;
+ }
+ }
+ if (streamIndex >= streams.length) {
+ streams.push(Number.NEGATIVE_INFINITY);
+ }
+
+ var streamOffset = (eventTheme.track.offset +
+ streamIndex * (eventTheme.track.height + eventTheme.track.gap)) + "em";
+
+ layout._tracks[evt.getID()] = streamIndex;
+
+ if (evt.isInstant()) {
+ streams[streamIndex] = layoutInstant(evt, startPixel, endPixel, streamOffset);
+ } else {
+ streams[streamIndex] = layoutDuration(evt, startPixel, endPixel, streamOffset);
+ }
+ };
+
+ var iterator = this._eventSource.getAllEventIterator();
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ layoutEvent(evt);
+ }
+
+ this._trackCount = streams.length;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/painters.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/painters.js
new file mode 100644
index 00000000..dd24f96f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/painters.js
@@ -0,0 +1,334 @@
+/*==================================================
+ * Duration Event Painter
+ *==================================================
+ */
+
+Timeline.DurationEventPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._layout = params.layout;
+
+ this._showText = params.showText;
+ this._showLineForNoText = ("showLineForNoText" in params) ?
+ params.showLineForNoText : params.theme.event.instant.showLineForNoText;
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+};
+
+Timeline.DurationEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+ this._layout.initialize(band, timeline);
+
+ this._eventLayer = null;
+ this._highlightLayer = null;
+};
+
+Timeline.DurationEventPainter.prototype.getLayout = function() {
+ return this._layout;
+};
+
+Timeline.DurationEventPainter.prototype.setLayout = function(layout) {
+ this._layout = layout;
+};
+
+Timeline.DurationEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.DurationEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.DurationEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.DurationEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.DurationEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ if (this._highlightLayer != null) {
+ this._band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = this._band.createLayerDiv(105);
+ this._highlightLayer.setAttribute("name", "event-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ this._band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = this._band.createLayerDiv(110);
+ this._eventLayer.setAttribute("name", "events");
+ this._eventLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var doc = this._timeline.getDocument();
+
+ var p = this;
+ var eventLayer = this._eventLayer;
+ var highlightLayer = this._highlightLayer;
+
+ var showText = this._showText;
+ var theme = this._params.theme;
+ var eventTheme = theme.event;
+ var trackOffset = eventTheme.track.offset;
+ var trackHeight = ("trackHeight" in this._params) ? this._params.trackHeight : eventTheme.track.height;
+ var trackGap = ("trackGap" in this._params) ? this._params.trackGap : eventTheme.track.gap;
+
+ //if (this._timeline.isHorizontal()) {
+ var appendIcon = function(evt, div) {
+ var icon = evt.getIcon();
+ var img = Timeline.Graphics.createTranslucentImage(
+ doc, icon != null ? icon : eventTheme.instant.icon
+ );
+ div.appendChild(img);
+ div.style.cursor = "pointer";
+
+ Timeline.DOM.registerEvent(div, "mousedown", function(elmt, domEvt, target) {
+ p._onClickInstantEvent(img, domEvt, evt);
+ });
+ };
+ var createHighlightDiv = function(highlightIndex, startPixel, length, highlightOffset, highlightWidth) {
+ if (highlightIndex >= 0) {
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (startPixel - 3) + "px";
+ div.style.width = (length + 6) + "px";
+ div.style.top = highlightOffset + "em";
+ div.style.height = highlightWidth + "em";
+ div.style.background = color;
+ //Timeline.Graphics.setOpacity(div, 50);
+
+ highlightLayer.appendChild(div);
+ }
+ };
+
+ var createInstantDiv = function(evt, startPixel, endPixel, streamOffset, highlightIndex, highlightOffset, highlightWidth) {
+ if (evt.isImprecise()) { // imprecise time
+ var length = Math.max(endPixel - startPixel, 1);
+
+ var divImprecise = doc.createElement("div");
+ divImprecise.style.position = "absolute";
+ divImprecise.style.overflow = "hidden";
+
+ divImprecise.style.top = streamOffset;
+ divImprecise.style.height = trackHeight + "em";
+ divImprecise.style.left = startPixel + "px";
+ divImprecise.style.width = length + "px";
+
+ divImprecise.style.background = eventTheme.instant.impreciseColor;
+ if (eventTheme.instant.impreciseOpacity < 100) {
+ Timeline.Graphics.setOpacity(divImprecise, eventTheme.instant.impreciseOpacity);
+ }
+
+ eventLayer.appendChild(divImprecise);
+ }
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ eventLayer.appendChild(div);
+
+ var foreground = evt.getTextColor();
+ var background = evt.getColor();
+
+ var realign = -8; // shift left so that icon is centered on startPixel
+ var length = 16;
+ if (showText) {
+ div.style.width = eventTheme.label.width + "px";
+ div.style.color = foreground != null ? foreground : eventTheme.label.outsideColor;
+
+ appendIcon(evt, div);
+ div.appendChild(doc.createTextNode(evt.getText()));
+ } else {
+ if (p._showLineForNoText) {
+ div.style.width = "1px";
+ div.style.borderLeft = "1px solid " + (background != null ? background : eventTheme.instant.lineColor);
+ realign = 0; // no shift
+ length = 1;
+ } else {
+ appendIcon(evt, div);
+ }
+ }
+
+ div.style.top = streamOffset;
+ div.style.height = trackHeight + "em";
+ div.style.left = (startPixel + realign) + "px";
+
+ createHighlightDiv(highlightIndex, (startPixel + realign), length, highlightOffset, highlightWidth);
+ };
+ var createDurationDiv = function(evt, startPixel, endPixel, streamOffset, highlightIndex, highlightOffset, highlightWidth) {
+ var attachClickEvent = function(elmt) {
+ elmt.style.cursor = "pointer";
+ Timeline.DOM.registerEvent(elmt, "mousedown", function(elmt, domEvt, target) {
+ p._onClickDurationEvent(domEvt, evt, target);
+ });
+ };
+
+ var length = Math.max(endPixel - startPixel, 1);
+ if (evt.isImprecise()) { // imprecise time
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+
+ div.style.top = streamOffset;
+ div.style.height = trackHeight + "em";
+ div.style.left = startPixel + "px";
+ div.style.width = length + "px";
+
+ div.style.background = eventTheme.duration.impreciseColor;
+ if (eventTheme.duration.impreciseOpacity < 100) {
+ Timeline.Graphics.setOpacity(div, eventTheme.duration.impreciseOpacity);
+ }
+
+ eventLayer.appendChild(div);
+
+ var startDate = evt.getLatestStart();
+ var endDate = evt.getEarliestEnd();
+
+ var startPixel2 = Math.round(p._band.dateToPixelOffset(startDate));
+ var endPixel2 = Math.round(p._band.dateToPixelOffset(endDate));
+ } else {
+ var startPixel2 = startPixel;
+ var endPixel2 = endPixel;
+ }
+
+ var foreground = evt.getTextColor();
+ var outside = true;
+ if (startPixel2 <= endPixel2) {
+ length = Math.max(endPixel2 - startPixel2, 1);
+ outside = !(length > eventTheme.label.width);
+
+ div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+
+ div.style.top = streamOffset;
+ div.style.height = trackHeight + "em";
+ div.style.left = startPixel2 + "px";
+ div.style.width = length + "px";
+
+ var background = evt.getColor();
+
+ div.style.background = background != null ? background : eventTheme.duration.color;
+ if (eventTheme.duration.opacity < 100) {
+ Timeline.Graphics.setOpacity(div, eventTheme.duration.opacity);
+ }
+
+ eventLayer.appendChild(div);
+ } else {
+ var temp = startPixel2;
+ startPixel2 = endPixel2;
+ endPixel2 = temp;
+ }
+ if (div == null) {
+ console.log(evt);
+ }
+ attachClickEvent(div);
+
+ if (showText) {
+ var divLabel = doc.createElement("div");
+ divLabel.style.position = "absolute";
+
+ divLabel.style.top = streamOffset;
+ divLabel.style.height = trackHeight + "em";
+ divLabel.style.left = ((length > eventTheme.label.width) ? startPixel2 : endPixel2) + "px";
+ divLabel.style.width = eventTheme.label.width + "px";
+ divLabel.style.color = foreground != null ? foreground : (outside ? eventTheme.label.outsideColor : eventTheme.label.insideColor);
+ divLabel.style.overflow = "hidden";
+ divLabel.appendChild(doc.createTextNode(evt.getText()));
+
+ eventLayer.appendChild(divLabel);
+ attachClickEvent(divLabel);
+ }
+
+ createHighlightDiv(highlightIndex, startPixel, endPixel - startPixel, highlightOffset, highlightWidth);
+ };
+ //}
+ var createEventDiv = function(evt, highlightIndex) {
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+
+ var startPixel = Math.round(p._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(p._band.dateToPixelOffset(endDate));
+
+ var streamOffset = (trackOffset +
+ p._layout.getTrack(evt) * (trackHeight + trackGap));
+
+ if (evt.isInstant()) {
+ createInstantDiv(evt, startPixel, endPixel, streamOffset + "em",
+ highlightIndex, streamOffset - trackGap, trackHeight + 2 * trackGap);
+ } else {
+ createDurationDiv(evt, startPixel, endPixel, streamOffset + "em",
+ highlightIndex, streamOffset - trackGap, trackHeight + 2 * trackGap);
+ }
+ };
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventIterator(minDate, maxDate);
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ createEventDiv(evt, highlightMatcher(evt));
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+};
+
+Timeline.DurationEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.DurationEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ domEvt.cancelBubble = true;
+
+ var c = Timeline.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ evt
+ );
+};
+
+Timeline.DurationEventPainter.prototype._onClickDurationEvent = function(domEvt, evt, target) {
+ domEvt.cancelBubble = true;
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = Timeline.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, evt);
+};
+
+Timeline.DurationEventPainter.prototype._showBubble = function(x, y, evt) {
+ var div = this._band.openBubbleForPoint(
+ x, y,
+ this._theme.event.bubble.width,
+ this._theme.event.bubble.height
+ );
+
+ evt.fillInfoBubble(div, this._theme, this._band.getLabeller());
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/sources.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/sources.js
new file mode 100644
index 00000000..7c95275e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/sources.js
@@ -0,0 +1,426 @@
+/*==================================================
+ * Default Event Source
+ *==================================================
+ */
+
+
+Timeline.DefaultEventSource = function(eventIndex) {
+ this._events = (eventIndex instanceof Object) ? eventIndex : new Timeline.EventIndex();
+ this._listeners = [];
+};
+
+Timeline.DefaultEventSource.prototype.addListener = function(listener) {
+ this._listeners.push(listener);
+};
+
+Timeline.DefaultEventSource.prototype.removeListener = function(listener) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ if (this._listeners[i] == listener) {
+ this._listeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.DefaultEventSource.prototype.loadXML = function(xml, url) {
+ var base = this._getBaseURL(url);
+
+ var wikiURL = xml.documentElement.getAttribute("wiki-url");
+ var wikiSection = xml.documentElement.getAttribute("wiki-section");
+
+ var dateTimeFormat = xml.documentElement.getAttribute("date-time-format");
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ var node = xml.documentElement.firstChild;
+ var added = false;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ var description = "";
+ if (node.firstChild != null && node.firstChild.nodeType == 3) {
+ description = node.firstChild.nodeValue;
+ }
+ var evt = new Timeline.DefaultEventSource.Event(
+ parseDateTimeFunction(node.getAttribute("start")),
+ parseDateTimeFunction(node.getAttribute("end")),
+ parseDateTimeFunction(node.getAttribute("latestStart")),
+ parseDateTimeFunction(node.getAttribute("earliestEnd")),
+ node.getAttribute("isDuration") != "true",
+ node.getAttribute("title"),
+ description,
+ this._resolveRelativeURL(node.getAttribute("image"), base),
+ this._resolveRelativeURL(node.getAttribute("link"), base),
+ this._resolveRelativeURL(node.getAttribute("icon"), base),
+ node.getAttribute("color"),
+ node.getAttribute("textColor")
+ );
+ evt._node = node;
+ evt.getProperty = function(name) {
+ return this._node.getAttribute(name);
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+
+ added = true;
+ }
+ node = node.nextSibling;
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+
+Timeline.DefaultEventSource.prototype.loadJSON = function(data, url) {
+ var base = this._getBaseURL(url);
+ var added = false;
+ if (data && data.events){
+ var wikiURL = ("wikiURL" in data) ? data.wikiURL : null;
+ var wikiSection = ("wikiSection" in data) ? data.wikiSection : null;
+
+ var dateTimeFormat = ("dateTimeFormat" in data) ? data.dateTimeFormat : null;
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ for (var i=0; i < data.events.length; i++){
+ var event = data.events[i];
+ var evt = new Timeline.DefaultEventSource.Event(
+ parseDateTimeFunction(event.start),
+ parseDateTimeFunction(event.end),
+ parseDateTimeFunction(event.latestStart),
+ parseDateTimeFunction(event.earliestEnd),
+ event.isDuration || false,
+ event.title,
+ event.description,
+ this._resolveRelativeURL(event.image, base),
+ this._resolveRelativeURL(event.link, base),
+ this._resolveRelativeURL(event.icon, base),
+ event.color,
+ event.textColor
+ );
+ evt._obj = event;
+ evt.getProperty = function(name) {
+ return this._obj[name];
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+ added = true;
+ }
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+/*
+ * Contributed by Morten Frederiksen, http://www.wasab.dk/morten/
+ */
+Timeline.DefaultEventSource.prototype.loadSPARQL = function(xml, url) {
+ var base = this._getBaseURL(url);
+
+ var dateTimeFormat = 'iso8601';
+ var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+ if (xml == null) {
+ return;
+ }
+
+ /*
+ * Find <results> tag
+ */
+ var node = xml.documentElement.firstChild;
+ while (node != null && (node.nodeType != 1 || node.nodeName != 'results')) {
+ node = node.nextSibling;
+ }
+
+ var wikiURL = null;
+ var wikiSection = null;
+ if (node != null) {
+ wikiURL = node.getAttribute("wiki-url");
+ wikiSection = node.getAttribute("wiki-section");
+
+ node = node.firstChild;
+ }
+
+ var added = false;
+ while (node != null) {
+ if (node.nodeType == 1) {
+ var bindings = { };
+ var binding = node.firstChild;
+ while (binding != null) {
+ if (binding.nodeType == 1 &&
+ binding.firstChild != null &&
+ binding.firstChild.nodeType == 1 &&
+ binding.firstChild.firstChild != null &&
+ binding.firstChild.firstChild.nodeType == 3) {
+ bindings[binding.getAttribute('name')] = binding.firstChild.firstChild.nodeValue;
+ }
+ binding = binding.nextSibling;
+ }
+
+ if (bindings["start"] == null && bindings["date"] != null) {
+ bindings["start"] = bindings["date"];
+ }
+
+ var evt = new Timeline.DefaultEventSource.Event(
+ parseDateTimeFunction(bindings["start"]),
+ parseDateTimeFunction(bindings["end"]),
+ parseDateTimeFunction(bindings["latestStart"]),
+ parseDateTimeFunction(bindings["earliestEnd"]),
+ bindings["isDuration"] != "true",
+ bindings["title"],
+ bindings["description"],
+ this._resolveRelativeURL(bindings["image"], base),
+ this._resolveRelativeURL(bindings["link"], base),
+ this._resolveRelativeURL(bindings["icon"], base),
+ bindings["color"],
+ bindings["textColor"]
+ );
+ evt._bindings = bindings;
+ evt.getProperty = function(name) {
+ return this._bindings[name];
+ };
+ evt.setWikiInfo(wikiURL, wikiSection);
+
+ this._events.add(evt);
+ added = true;
+ }
+ node = node.nextSibling;
+ }
+
+ if (added) {
+ this._fire("onAddMany", []);
+ }
+};
+
+Timeline.DefaultEventSource.prototype.add = function(evt) {
+ this._events.add(evt);
+ this._fire("onAddOne", [evt]);
+};
+
+Timeline.DefaultEventSource.prototype.addMany = function(events) {
+ for (var i = 0; i < events.length; i++) {
+ this._events.add(events[i]);
+ }
+ this._fire("onAddMany", []);
+};
+
+Timeline.DefaultEventSource.prototype.clear = function() {
+ this._events.removeAll();
+ this._fire("onClear", []);
+};
+
+Timeline.DefaultEventSource.prototype.getEventIterator = function(startDate, endDate) {
+ return this._events.getIterator(startDate, endDate);
+};
+
+Timeline.DefaultEventSource.prototype.getAllEventIterator = function() {
+ return this._events.getAllIterator();
+};
+
+Timeline.DefaultEventSource.prototype.getCount = function() {
+ return this._events.getCount();
+};
+
+Timeline.DefaultEventSource.prototype.getEarliestDate = function() {
+ return this._events.getEarliestDate();
+};
+
+Timeline.DefaultEventSource.prototype.getLatestDate = function() {
+ return this._events.getLatestDate();
+};
+
+Timeline.DefaultEventSource.prototype._fire = function(handlerName, args) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ var listener = this._listeners[i];
+ if (handlerName in listener) {
+ try {
+ listener[handlerName].apply(listener, args);
+ } catch (e) {
+ Timeline.Debug.exception(e);
+ }
+ }
+ }
+};
+
+Timeline.DefaultEventSource.prototype._getBaseURL = function(url) {
+ if (url.indexOf("://") < 0) {
+ var url2 = this._getBaseURL(document.location.href);
+ if (url.substr(0,1) == "/") {
+ url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
+ } else {
+ url = url2 + url;
+ }
+ }
+
+ var i = url.lastIndexOf("/");
+ if (i < 0) {
+ return "";
+ } else {
+ return url.substr(0, i+1);
+ }
+};
+
+Timeline.DefaultEventSource.prototype._resolveRelativeURL = function(url, base) {
+ if (url == null || url == "") {
+ return url;
+ } else if (url.indexOf("://") > 0) {
+ return url;
+ } else if (url.substr(0,1) == "/") {
+ return base.substr(0, base.indexOf("/", base.indexOf("://") + 3)) + url;
+ } else {
+ return base + url;
+ }
+};
+
+
+Timeline.DefaultEventSource.Event = function(
+ start, end, latestStart, earliestEnd, instant,
+ text, description, image, link,
+ icon, color, textColor) {
+
+ this._id = "e" + Math.floor(Math.random() * 1000000);
+
+ this._instant = instant || (end == null);
+
+ this._start = start;
+ this._end = (end != null) ? end : start;
+
+ this._latestStart = (latestStart != null) ? latestStart : (instant ? this._end : this._start);
+ this._earliestEnd = (earliestEnd != null) ? earliestEnd : (instant ? this._start : this._end);
+
+ this._text = text;
+ this._description = description;
+ this._image = (image != null && image != "") ? image : null;
+ this._link = (link != null && link != "") ? link : null;
+
+ this._icon = (icon != null && icon != "") ? icon : null;
+ this._color = (color != null && color != "") ? color : null;
+ this._textColor = (textColor != null && textColor != "") ? textColor : null;
+
+ this._wikiURL = null;
+ this._wikiSection = null;
+};
+
+Timeline.DefaultEventSource.Event.prototype = {
+ getID: function() { return this._id; },
+
+ isInstant: function() { return this._instant; },
+ isImprecise: function() { return this._start != this._latestStart || this._end != this._earliestEnd; },
+
+ getStart: function() { return this._start; },
+ getEnd: function() { return this._end; },
+ getLatestStart: function() { return this._latestStart; },
+ getEarliestEnd: function() { return this._earliestEnd; },
+
+ getText: function() { return this._text; },
+ getDescription: function() { return this._description; },
+ getImage: function() { return this._image; },
+ getLink: function() { return this._link; },
+
+ getIcon: function() { return this._icon; },
+ getColor: function() { return this._color; },
+ getTextColor: function() { return this._textColor; },
+
+ getProperty: function(name) { return null; },
+
+ getWikiURL: function() { return this._wikiURL; },
+ getWikiSection: function() { return this._wikiSection; },
+ setWikiInfo: function(wikiURL, wikiSection) {
+ this._wikiURL = wikiURL;
+ this._wikiSection = wikiSection;
+ },
+
+ fillDescription: function(elmt) {
+ elmt.innerHTML = this._description;
+ },
+ fillWikiInfo: function(elmt) {
+ if (this._wikiURL != null && this._wikiSection != null) {
+ var wikiID = this.getProperty("wikiID");
+ if (wikiID == null || wikiID.length == 0) {
+ wikiID = this.getText();
+ }
+ wikiID = wikiID.replace(/\s/g, "_");
+
+ var url = this._wikiURL + this._wikiSection.replace(/\s/g, "_") + "/" + wikiID;
+ var a = document.createElement("a");
+ a.href = url;
+ a.target = "new";
+ a.innerHTML = Timeline.strings[Timeline.Platform.clientLocale].wikiLinkLabel;
+
+ elmt.appendChild(document.createTextNode("["));
+ elmt.appendChild(a);
+ elmt.appendChild(document.createTextNode("]"));
+ } else {
+ elmt.style.display = "none";
+ }
+ },
+ fillTime: function(elmt, labeller) {
+ if (this._instant) {
+ if (this.isImprecise()) {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+ } else {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ }
+ } else {
+ if (this.isImprecise()) {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(
+ labeller.labelPrecise(this._start) + " ~ " + labeller.labelPrecise(this._latestStart)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(
+ labeller.labelPrecise(this._earliestEnd) + " ~ " + labeller.labelPrecise(this._end)));
+ } else {
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+ elmt.appendChild(elmt.ownerDocument.createElement("br"));
+ elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+ }
+ }
+ },
+ fillInfoBubble: function(elmt, theme, labeller) {
+ var doc = elmt.ownerDocument;
+
+ var title = this.getText();
+ var link = this.getLink();
+ var image = this.getImage();
+
+ if (image != null) {
+ var img = doc.createElement("img");
+ img.src = image;
+
+ theme.event.bubble.imageStyler(img);
+ elmt.appendChild(img);
+ }
+
+ var divTitle = doc.createElement("div");
+ var textTitle = doc.createTextNode(title);
+ if (link != null) {
+ var a = doc.createElement("a");
+ a.href = link;
+ a.appendChild(textTitle);
+ divTitle.appendChild(a);
+ } else {
+ divTitle.appendChild(textTitle);
+ }
+ theme.event.bubble.titleStyler(divTitle);
+ elmt.appendChild(divTitle);
+
+ var divBody = doc.createElement("div");
+ this.fillDescription(divBody);
+ theme.event.bubble.bodyStyler(divBody);
+ elmt.appendChild(divBody);
+
+ var divTime = doc.createElement("div");
+ this.fillTime(divTime, labeller);
+ theme.event.bubble.timeStyler(divTime);
+ elmt.appendChild(divTime);
+
+ var divWiki = doc.createElement("div");
+ this.fillWikiInfo(divWiki);
+ theme.event.bubble.wikiStyler(divWiki);
+ elmt.appendChild(divWiki);
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/themes.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/themes.js
new file mode 100644
index 00000000..5c40c396
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/themes.js
@@ -0,0 +1,127 @@
+/*==================================================
+ * Classic Theme
+ *==================================================
+ */
+
+
+Timeline.ClassicTheme = new Object();
+
+Timeline.ClassicTheme.implementations = [];
+
+Timeline.ClassicTheme.create = function(locale) {
+ if (locale == null) {
+ locale = Timeline.Platform.getDefaultLocale();
+ }
+
+ var f = Timeline.ClassicTheme.implementations[locale];
+ if (f == null) {
+ f = Timeline.ClassicTheme._Impl;
+ }
+ return new f();
+};
+
+Timeline.ClassicTheme._Impl = function() {
+ this.firstDayOfWeek = 0; // Sunday
+
+ this.ether = {
+ backgroundColors: [
+ "#EEE",
+ "#DDD",
+ "#CCC",
+ "#AAA"
+ ],
+ highlightColor: "white",
+ highlightOpacity: 50,
+ interval: {
+ line: {
+ show: true,
+ color: "#aaa",
+ opacity: 25
+ },
+ weekend: {
+ color: "#FFFFE0",
+ opacity: 30
+ },
+ marker: {
+ hAlign: "Bottom",
+ hBottomStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-bottom";
+ },
+ hBottomEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-bottom-emphasized";
+ },
+ hTopStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-top";
+ },
+ hTopEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-top-emphasized";
+ },
+
+ vAlign: "Right",
+ vRightStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-right";
+ },
+ vRightEmphasizedStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-right-emphasized";
+ },
+ vLeftStyler: function(elmt) {
+ elmt.className = "timeline-ether-marker-left";
+ },
+ vLeftEmphasizedStyler:function(elmt) {
+ elmt.className = "timeline-ether-marker-left-emphasized";
+ }
+ }
+ }
+ };
+
+ this.event = {
+ track: {
+ offset: 0.5, // em
+ height: 1.5, // em
+ gap: 0.5 // em
+ },
+ instant: {
+ icon: Timeline.urlPrefix + "images/dull-blue-circle.png",
+ lineColor: "#58A0DC",
+ impreciseColor: "#58A0DC",
+ impreciseOpacity: 20,
+ showLineForNoText: true
+ },
+ duration: {
+ color: "#58A0DC",
+ opacity: 100,
+ impreciseColor: "#58A0DC",
+ impreciseOpacity: 20
+ },
+ label: {
+ insideColor: "white",
+ outsideColor: "black",
+ width: 200 // px
+ },
+ highlightColors: [
+ "#FFFF00",
+ "#FFC000",
+ "#FF0000",
+ "#0000FF"
+ ],
+ bubble: {
+ width: 250, // px
+ height: 125, // px
+ titleStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-title";
+ },
+ bodyStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-body";
+ },
+ imageStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-image";
+ },
+ wikiStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-wiki";
+ },
+ timeStyler: function(elmt) {
+ elmt.className = "timeline-event-bubble-time";
+ }
+ }
+ };
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/timeline.js
new file mode 100644
index 00000000..ac3bf1a8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/timeline.js
@@ -0,0 +1,892 @@
+/*==================================================
+ * Timeline
+ *==================================================
+ */
+
+Timeline.strings = {}; // localization string tables
+
+Timeline.create = function(elmt, bandInfos, orientation, unit) {
+ return new Timeline._Impl(elmt, bandInfos, orientation, unit);
+};
+
+Timeline.HORIZONTAL = 0;
+Timeline.VERTICAL = 1;
+
+Timeline._defaultTheme = null;
+
+Timeline.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : new Date(),
+ interval: Timeline.DateTime.gregorianUnitLengths[params.intervalUnit],
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.GregorianEtherPainter({
+ unit: params.intervalUnit,
+ theme: theme
+ });
+
+ var layout = new Timeline.StaticTrackBasedLayout({
+ eventSource: eventSource,
+ ether: ether,
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ layout: layout,
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = new Timeline.DurationEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+};
+
+Timeline.createHotZoneBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.HotZoneEther({
+ centersOn: ("date" in params) ? params.date : new Date(),
+ interval: Timeline.DateTime.gregorianUnitLengths[params.intervalUnit],
+ pixelsPerInterval: params.intervalPixels,
+ zones: params.zones
+ });
+
+ var etherPainter = new Timeline.HotZoneGregorianEtherPainter({
+ unit: params.intervalUnit,
+ zones: params.zones,
+ theme: theme
+ });
+
+ var layout = new Timeline.StaticTrackBasedLayout({
+ eventSource: eventSource,
+ ether: ether,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ showText: ("showEventText" in params) ? params.showEventText : true,
+ layout: layout,
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = new Timeline.DurationEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+};
+
+Timeline.getDefaultTheme = function() {
+ if (Timeline._defaultTheme == null) {
+ Timeline._defaultTheme = Timeline.ClassicTheme.create(Timeline.Platform.getDefaultLocale());
+ }
+ return Timeline._defaultTheme;
+};
+
+Timeline.setDefaultTheme = function(theme) {
+ Timeline._defaultTheme = theme;
+};
+
+Timeline.loadXML = function(url, f) {
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load data xml from " + url + "\n" + statusText);
+ };
+ var fDone = function(xmlhttp) {
+ var xml = xmlhttp.responseXML;
+ if (!xml.documentElement && xmlhttp.responseStream) {
+ xml.load(xmlhttp.responseStream);
+ }
+ f(xml, url);
+ };
+ Timeline.XmlHttp.get(url, fError, fDone);
+};
+
+
+Timeline.loadJSON = function(url, f) {
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load json data from " + url + "\n" + statusText);
+ };
+ var fDone = function(xmlhttp) {
+ f(eval('(' + xmlhttp.responseText + ')'), url);
+ };
+ Timeline.XmlHttp.get(url, fError, fDone);
+};
+
+
+Timeline._Impl = function(elmt, bandInfos, orientation, unit) {
+ this._containerDiv = elmt;
+
+ this._bandInfos = bandInfos;
+ this._orientation = orientation == null ? Timeline.HORIZONTAL : orientation;
+ this._unit = (unit != null) ? unit : Timeline.NativeDateUnit;
+
+ this._initialize();
+};
+
+Timeline._Impl.prototype.dispose = function() {
+ for (var i = 0; i < this._bands.length; i++) {
+ this._bands[i].dispose();
+ }
+ this._bands = null;
+ this._bandInfos = null;
+ this._containerDiv.innerHTML = "";
+};
+
+Timeline._Impl.prototype.getBandCount = function() {
+ return this._bands.length;
+};
+
+Timeline._Impl.prototype.getBand = function(index) {
+ return this._bands[index];
+};
+
+Timeline._Impl.prototype.layout = function() {
+ this._distributeWidths();
+};
+
+Timeline._Impl.prototype.paint = function() {
+ for (var i = 0; i < this._bands.length; i++) {
+ this._bands[i].paint();
+ }
+};
+
+Timeline._Impl.prototype.getDocument = function() {
+ return this._containerDiv.ownerDocument;
+};
+
+Timeline._Impl.prototype.addDiv = function(div) {
+ this._containerDiv.appendChild(div);
+};
+
+Timeline._Impl.prototype.removeDiv = function(div) {
+ this._containerDiv.removeChild(div);
+};
+
+Timeline._Impl.prototype.isHorizontal = function() {
+ return this._orientation == Timeline.HORIZONTAL;
+};
+
+Timeline._Impl.prototype.isVertical = function() {
+ return this._orientation == Timeline.VERTICAL;
+};
+
+Timeline._Impl.prototype.getPixelLength = function() {
+ return this._orientation == Timeline.HORIZONTAL ?
+ this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getPixelWidth = function() {
+ return this._orientation == Timeline.VERTICAL ?
+ this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getUnit = function() {
+ return this._unit;
+};
+
+Timeline._Impl.prototype.loadXML = function(url, f) {
+ var tl = this;
+
+
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load data xml from " + url + "\n" + statusText);
+ tl.hideLoadingMessage();
+ };
+ var fDone = function(xmlhttp) {
+ try {
+ var xml = xmlhttp.responseXML;
+ if (!xml.documentElement && xmlhttp.responseStream) {
+ xml.load(xmlhttp.responseStream);
+ }
+ f(xml, url);
+ } finally {
+ tl.hideLoadingMessage();
+ }
+ };
+
+ this.showLoadingMessage();
+ window.setTimeout(function() { Timeline.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+Timeline._Impl.prototype.loadJSON = function(url, f) {
+ var tl = this;
+
+
+ var fError = function(statusText, status, xmlhttp) {
+ alert("Failed to load json data from " + url + "\n" + statusText);
+ tl.hideLoadingMessage();
+ };
+ var fDone = function(xmlhttp) {
+ try {
+ f(eval('(' + xmlhttp.responseText + ')'), url);
+ } finally {
+ tl.hideLoadingMessage();
+ }
+ };
+
+ this.showLoadingMessage();
+ window.setTimeout(function() { Timeline.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+Timeline._Impl.prototype._initialize = function() {
+ var containerDiv = this._containerDiv;
+ var doc = containerDiv.ownerDocument;
+
+ containerDiv.className =
+ containerDiv.className.split(" ").concat("timeline-container").join(" ");
+
+ while (containerDiv.firstChild) {
+ containerDiv.removeChild(containerDiv.firstChild);
+ }
+
+ /*
+ * inserting copyright and link to simile
+ */
+ var elmtCopyright = Timeline.Graphics.createTranslucentImage(doc, Timeline.urlPrefix + (this.isHorizontal() ? "images/copyright-vertical.png" : "images/copyright.png"));
+ elmtCopyright.className = "timeline-copyright";
+ elmtCopyright.title = "Timeline (c) SIMILE - http://simile.mit.edu/timeline/";
+ Timeline.DOM.registerEvent(elmtCopyright, "click", function() { window.location = "http://simile.mit.edu/timeline/"; });
+ containerDiv.appendChild(elmtCopyright);
+
+ /*
+ * creating bands
+ */
+ this._bands = [];
+ for (var i = 0; i < this._bandInfos.length; i++) {
+ var band = new Timeline._Band(this, this._bandInfos[i], i);
+ this._bands.push(band);
+ }
+ this._distributeWidths();
+
+ /*
+ * sync'ing bands
+ */
+ for (var i = 0; i < this._bandInfos.length; i++) {
+ var bandInfo = this._bandInfos[i];
+ if ("syncWith" in bandInfo) {
+ this._bands[i].setSyncWithBand(
+ this._bands[bandInfo.syncWith],
+ ("highlight" in bandInfo) ? bandInfo.highlight : false
+ );
+ }
+ }
+
+ /*
+ * creating loading UI
+ */
+ var message = Timeline.Graphics.createMessageBubble(doc);
+ message.containerDiv.className = "timeline-message-container";
+ containerDiv.appendChild(message.containerDiv);
+
+ message.contentDiv.className = "timeline-message";
+ message.contentDiv.innerHTML = "<img src='" + Timeline.urlPrefix + "images/progress-running.gif' /> Loading...";
+
+ this.showLoadingMessage = function() { message.containerDiv.style.display = "block"; };
+ this.hideLoadingMessage = function() { message.containerDiv.style.display = "none"; };
+};
+
+Timeline._Impl.prototype._distributeWidths = function() {
+ var length = this.getPixelLength();
+ var width = this.getPixelWidth();
+ var cumulativeWidth = 0;
+
+ for (var i = 0; i < this._bands.length; i++) {
+ var band = this._bands[i];
+ var bandInfos = this._bandInfos[i];
+ var widthString = bandInfos.width;
+
+ var x = widthString.indexOf("%");
+ if (x > 0) {
+ var percent = parseInt(widthString.substr(0, x));
+ var bandWidth = percent * width / 100;
+ } else {
+ var bandWidth = parseInt(widthString);
+ }
+
+ band.setBandShiftAndWidth(cumulativeWidth, bandWidth);
+ band.setViewLength(length);
+
+ cumulativeWidth += bandWidth;
+ }
+};
+
+/*==================================================
+ * Band
+ *==================================================
+ */
+Timeline._Band = function(timeline, bandInfo, index) {
+ this._timeline = timeline;
+ this._bandInfo = bandInfo;
+ this._index = index;
+
+ this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.Platform.getDefaultLocale();
+ this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0;
+ this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller :
+ timeline.getUnit().createLabeller(this._locale, this._timeZone);
+
+ this._dragging = false;
+ this._changing = false;
+ this._originalScrollSpeed = 5; // pixels
+ this._scrollSpeed = this._originalScrollSpeed;
+ this._onScrollListeners = [];
+
+ var b = this;
+ this._syncWithBand = null;
+ this._syncWithBandHandler = function(band) {
+ b._onHighlightBandScroll();
+ };
+ this._selectorListener = function(band) {
+ b._onHighlightBandScroll();
+ };
+
+ /*
+ * Install a textbox to capture keyboard events
+ */
+ var inputDiv = this._timeline.getDocument().createElement("div");
+ inputDiv.className = "timeline-band-input";
+ this._timeline.addDiv(inputDiv);
+
+ this._keyboardInput = document.createElement("input");
+ this._keyboardInput.type = "text";
+ inputDiv.appendChild(this._keyboardInput);
+ Timeline.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, this._onKeyDown);
+ Timeline.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, this._onKeyUp);
+
+ /*
+ * The band's outer most div that slides with respect to the timeline's div
+ */
+ this._div = this._timeline.getDocument().createElement("div");
+ this._div.className = "timeline-band";
+ this._timeline.addDiv(this._div);
+
+ Timeline.DOM.registerEventWithObject(this._div, "mousedown", this, this._onMouseDown);
+ Timeline.DOM.registerEventWithObject(this._div, "mousemove", this, this._onMouseMove);
+ Timeline.DOM.registerEventWithObject(this._div, "mouseup", this, this._onMouseUp);
+ Timeline.DOM.registerEventWithObject(this._div, "mouseout", this, this._onMouseOut);
+ Timeline.DOM.registerEventWithObject(this._div, "dblclick", this, this._onDblClick);
+
+ /*
+ * The inner div that contains layers
+ */
+ this._innerDiv = this._timeline.getDocument().createElement("div");
+ this._innerDiv.className = "timeline-band-inner";
+ this._div.appendChild(this._innerDiv);
+
+ /*
+ * Initialize parts of the band
+ */
+ this._ether = bandInfo.ether;
+ bandInfo.ether.initialize(timeline);
+
+ this._etherPainter = bandInfo.etherPainter;
+ bandInfo.etherPainter.initialize(this, timeline);
+
+ this._eventSource = bandInfo.eventSource;
+ if (this._eventSource) {
+ this._eventListener = {
+ onAddMany: function() { b._onAddMany(); },
+ onClear: function() { b._onClear(); }
+ }
+ this._eventSource.addListener(this._eventListener);
+ }
+
+ this._eventPainter = bandInfo.eventPainter;
+ bandInfo.eventPainter.initialize(this, timeline);
+
+ this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : [];
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].initialize(this, timeline);
+ }
+
+ this._bubble = null;
+};
+
+Timeline._Band.SCROLL_MULTIPLES = 5;
+
+Timeline._Band.prototype.dispose = function() {
+ this.closeBubble();
+
+ if (this._eventSource) {
+ this._eventSource.removeListener(this._eventListener);
+ this._eventListener = null;
+ this._eventSource = null;
+ }
+
+ this._timeline = null;
+ this._bandInfo = null;
+
+ this._labeller = null;
+ this._ether = null;
+ this._etherPainter = null;
+ this._eventPainter = null;
+ this._decorators = null;
+
+ this._onScrollListeners = null;
+ this._syncWithBandHandler = null;
+ this._selectorListener = null;
+
+ this._div = null;
+ this._innerDiv = null;
+ this._keyboardInput = null;
+ this._bubble = null;
+};
+
+Timeline._Band.prototype.addOnScrollListener = function(listener) {
+ this._onScrollListeners.push(listener);
+};
+
+Timeline._Band.prototype.removeOnScrollListener = function(listener) {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ if (this._onScrollListeners[i] == listener) {
+ this._onScrollListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline._Band.prototype.setSyncWithBand = function(band, highlight) {
+ if (this._syncWithBand) {
+ this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+ }
+
+ this._syncWithBand = band;
+ this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+ this._highlight = highlight;
+ this._positionHighlight();
+};
+
+Timeline._Band.prototype.getLocale = function() {
+ return this._locale;
+};
+
+Timeline._Band.prototype.getTimeZone = function() {
+ return this._timeZone;
+};
+
+Timeline._Band.prototype.getLabeller = function() {
+ return this._labeller;
+};
+
+Timeline._Band.prototype.getIndex = function() {
+ return this._index;
+};
+
+Timeline._Band.prototype.getEther = function() {
+ return this._ether;
+};
+
+Timeline._Band.prototype.getEtherPainter = function() {
+ return this._etherPainter;
+};
+
+Timeline._Band.prototype.getEventSource = function() {
+ return this._eventSource;
+};
+
+Timeline._Band.prototype.getEventPainter = function() {
+ return this._eventPainter;
+};
+
+Timeline._Band.prototype.layout = function() {
+ this.paint();
+};
+
+Timeline._Band.prototype.paint = function() {
+ this._etherPainter.paint();
+ this._paintDecorators();
+ this._paintEvents();
+};
+
+Timeline._Band.prototype.softLayout = function() {
+ this.softPaint();
+};
+
+Timeline._Band.prototype.softPaint = function() {
+ this._etherPainter.softPaint();
+ this._softPaintDecorators();
+ this._softPaintEvents();
+};
+
+Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) {
+ var inputDiv = this._keyboardInput.parentNode;
+ var middle = shift + Math.floor(width / 2);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.top = shift + "px";
+ this._div.style.height = width + "px";
+
+ inputDiv.style.top = middle + "px";
+ inputDiv.style.left = "-1em";
+ } else {
+ this._div.style.left = shift + "px";
+ this._div.style.width = width + "px";
+
+ inputDiv.style.left = middle + "px";
+ inputDiv.style.top = "-1em";
+ }
+};
+
+Timeline._Band.prototype.getViewWidth = function() {
+ if (this._timeline.isHorizontal()) {
+ return this._div.offsetHeight;
+ } else {
+ return this._div.offsetWidth;
+ }
+};
+
+Timeline._Band.prototype.setViewLength = function(length) {
+ this._viewLength = length;
+ this._recenterDiv();
+ this._onChanging();
+};
+
+Timeline._Band.prototype.getViewLength = function() {
+ return this._viewLength;
+};
+
+Timeline._Band.prototype.getTotalViewLength = function() {
+ return Timeline._Band.SCROLL_MULTIPLES * this._viewLength;
+};
+
+Timeline._Band.prototype.getViewOffset = function() {
+ return this._viewOffset;
+};
+
+Timeline._Band.prototype.getMinDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+
+Timeline._Band.prototype.getMaxDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength);
+};
+
+Timeline._Band.prototype.getMinVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(0);
+};
+
+Timeline._Band.prototype.getMaxVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewLength);
+};
+
+Timeline._Band.prototype.getCenterVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewLength / 2);
+};
+
+Timeline._Band.prototype.setMinVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setMaxVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setCenterVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.dateToPixelOffset = function(date) {
+ return this._ether.dateToPixelOffset(date) - this._viewOffset;
+};
+
+Timeline._Band.prototype.pixelOffsetToDate = function(pixels) {
+ return this._ether.pixelOffsetToDate(pixels + this._viewOffset);
+};
+
+Timeline._Band.prototype.createLayerDiv = function(zIndex) {
+ var div = this._timeline.getDocument().createElement("div");
+ div.className = "timeline-band-layer";
+ div.style.zIndex = zIndex;
+ this._innerDiv.appendChild(div);
+
+ var innerDiv = this._timeline.getDocument().createElement("div");
+ innerDiv.className = "timeline-band-layer-inner";
+ if (Timeline.Platform.browser.isIE) {
+ innerDiv.style.cursor = "move";
+ } else {
+ innerDiv.style.cursor = "-moz-grab";
+ }
+ div.appendChild(innerDiv);
+
+ return innerDiv;
+};
+
+Timeline._Band.prototype.removeLayerDiv = function(div) {
+ this._innerDiv.removeChild(div.parentNode);
+};
+
+Timeline._Band.prototype.closeBubble = function() {
+ if (this._bubble != null) {
+ this._bubble.close();
+ this._bubble = null;
+ }
+};
+
+Timeline._Band.prototype.openBubbleForPoint = function(pageX, pageY, width, height) {
+ this.closeBubble();
+
+ this._bubble = Timeline.Graphics.createBubbleForPoint(
+ this._timeline.getDocument(), pageX, pageY, width, height);
+
+ return this._bubble.content;
+};
+
+Timeline._Band.prototype.scrollToCenter = function(date) {
+ var pixelOffset = this._ether.dateToPixelOffset(date);
+ if (pixelOffset < -this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength));
+ } else if (pixelOffset > 3 * this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength));
+ }
+ this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
+};
+
+Timeline._Band.prototype._onMouseDown = function(innerFrame, evt, target) {
+ this.closeBubble();
+
+ this._dragging = true;
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+};
+
+Timeline._Band.prototype._onMouseMove = function(innerFrame, evt, target) {
+ if (this._dragging) {
+ var diffX = evt.clientX - this._dragX;
+ var diffY = evt.clientY - this._dragY;
+
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+
+ this._moveEther(this._timeline.isHorizontal() ? diffX : diffY);
+ this._positionHighlight();
+ }
+};
+
+Timeline._Band.prototype._onMouseUp = function(innerFrame, evt, target) {
+ this._dragging = false;
+ this._keyboardInput.focus();
+};
+
+Timeline._Band.prototype._onMouseOut = function(innerFrame, evt, target) {
+ var coords = Timeline.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ coords.x += this._viewOffset;
+ if (coords.x < 0 || coords.x > innerFrame.offsetWidth ||
+ coords.y < 0 || coords.y > innerFrame.offsetHeight) {
+ this._dragging = false;
+ }
+};
+
+Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) {
+ var coords = Timeline.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ var distance = coords.x - (this._viewLength / 2 - this._viewOffset);
+
+ this._autoScroll(-distance);
+};
+
+Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ switch (evt.keyCode) {
+ case 27: // ESC
+ break;
+ case 37: // left arrow
+ case 38: // up arrow
+ this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ case 39: // right arrow
+ case 40: // down arrow
+ this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ default:
+ return true;
+ }
+ this.closeBubble();
+
+ Timeline.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ this._scrollSpeed = this._originalScrollSpeed;
+
+ switch (evt.keyCode) {
+ case 35: // end
+ this.setCenterVisibleDate(this._eventSource.getLatestDate());
+ break;
+ case 36: // home
+ this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+ break;
+ case 33: // page up
+ this._autoScroll(this._timeline.getPixelLength());
+ break;
+ case 34: // page down
+ this._autoScroll(-this._timeline.getPixelLength());
+ break;
+ default:
+ return true;
+ }
+
+ this.closeBubble();
+
+ Timeline.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._autoScroll = function(distance) {
+ var b = this;
+ var a = Timeline.Graphics.createAnimation(function(abs, diff) {
+ b._moveEther(diff);
+ }, 0, distance, 1000);
+ a.run();
+};
+
+Timeline._Band.prototype._moveEther = function(shift) {
+ this.closeBubble();
+
+ this._viewOffset += shift;
+ this._ether.shiftPixels(-shift);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ }
+
+ if (this._viewOffset > -this._viewLength * 0.5 ||
+ this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) {
+
+ this._recenterDiv();
+ } else {
+ this.softLayout();
+ }
+
+ this._onChanging();
+}
+
+Timeline._Band.prototype._onChanging = function() {
+ this._changing = true;
+
+ this._fireOnScroll();
+ this._setSyncWithBandDate();
+
+ this._changing = false;
+};
+
+Timeline._Band.prototype._fireOnScroll = function() {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ this._onScrollListeners[i](this);
+ }
+};
+
+Timeline._Band.prototype._setSyncWithBandDate = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2);
+ this._syncWithBand.setCenterVisibleDate(centerDate);
+ }
+};
+
+Timeline._Band.prototype._onHighlightBandScroll = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._syncWithBand.getCenterVisibleDate();
+ var centerPixelOffset = this._ether.dateToPixelOffset(centerDate);
+
+ this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset));
+
+ if (this._highlight) {
+ this._etherPainter.setHighlight(
+ this._syncWithBand.getMinVisibleDate(),
+ this._syncWithBand.getMaxVisibleDate());
+ }
+ }
+};
+
+Timeline._Band.prototype._onAddMany = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._onClear = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._positionHighlight = function() {
+ if (this._syncWithBand) {
+ var startDate = this._syncWithBand.getMinVisibleDate();
+ var endDate = this._syncWithBand.getMaxVisibleDate();
+
+ if (this._highlight) {
+ this._etherPainter.setHighlight(startDate, endDate);
+ }
+ }
+};
+
+Timeline._Band.prototype._recenterDiv = function() {
+ this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2;
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ }
+ this.layout();
+};
+
+Timeline._Band.prototype._paintEvents = function() {
+ this._eventPainter.paint();
+};
+
+Timeline._Band.prototype._softPaintEvents = function() {
+ this._eventPainter.softPaint();
+};
+
+Timeline._Band.prototype._paintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].paint();
+ }
+};
+
+Timeline._Band.prototype._softPaintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].softPaint();
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/units.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/units.js
new file mode 100644
index 00000000..23f12a35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/units.js
@@ -0,0 +1,70 @@
+/*==================================================
+ * Default Unit
+ *==================================================
+ */
+
+Timeline.NativeDateUnit = new Object();
+
+Timeline.NativeDateUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.GregorianDateLabeller(locale, timeZone);
+};
+
+Timeline.NativeDateUnit.makeDefaultValue = function() {
+ return new Date();
+};
+
+Timeline.NativeDateUnit.cloneValue = function(v) {
+ return new Date(v.getTime());
+};
+
+Timeline.NativeDateUnit.getParser = function(format) {
+ if (typeof format == "string") {
+ format = format.toLowerCase();
+ }
+ return (format == "iso8601" || format == "iso 8601") ?
+ Timeline.DateTime.parseIso8601DateTime :
+ Timeline.DateTime.parseGregorianDateTime;
+};
+
+Timeline.NativeDateUnit.parseFromObject = function(o) {
+ return Timeline.DateTime.parseGregorianDateTime(o);
+ // The following does not work:
+ //return Timeline.DateTime.parseIso8601DateTime(o);
+};
+
+Timeline.NativeDateUnit.toNumber = function(v) {
+ return v.getTime();
+};
+
+Timeline.NativeDateUnit.fromNumber = function(n) {
+ return new Date(n);
+};
+
+Timeline.NativeDateUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1.getTime();
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2.getTime();
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n1 - n2;
+};
+
+Timeline.NativeDateUnit.earlier = function(v1, v2) {
+ return Timeline.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.NativeDateUnit.later = function(v1, v2) {
+ return Timeline.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.NativeDateUnit.change = function(v, n) {
+ return new Date(v.getTime() + n);
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/data-structure.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/data-structure.js
new file mode 100644
index 00000000..abe360fe
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/data-structure.js
@@ -0,0 +1,247 @@
+/*==================================================
+ * Sorted Array
+ *==================================================
+ */
+
+Timeline.SortedArray = function(compare, initialArray) {
+ this._a = (initialArray instanceof Array) ? initialArray : [];
+ this._compare = compare;
+};
+
+Timeline.SortedArray.prototype.add = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ if (index < this._a.length) {
+ this._a.splice(index, 0, elmt);
+ } else {
+ this._a.push(elmt);
+ }
+};
+
+Timeline.SortedArray.prototype.remove = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ while (index < this._a.length && this._compare(this._a[index], elmt) == 0) {
+ if (this._a[index] == elmt) {
+ this._a.splice(index, 1);
+ return true;
+ } else {
+ index++;
+ }
+ }
+ return false;
+};
+
+Timeline.SortedArray.prototype.removeAll = function() {
+ this._a = [];
+};
+
+Timeline.SortedArray.prototype.elementAt = function(index) {
+ return this._a[index];
+};
+
+Timeline.SortedArray.prototype.length = function() {
+ return this._a.length;
+};
+
+Timeline.SortedArray.prototype.find = function(compare) {
+ var a = 0;
+ var b = this._a.length;
+
+ while (a < b) {
+ var mid = Math.floor((a + b) / 2);
+ var c = compare(this._a[mid]);
+ if (mid == a) {
+ return c < 0 ? a+1 : a;
+ } else if (c < 0) {
+ a = mid;
+ } else {
+ b = mid;
+ }
+ }
+ return a;
+};
+
+Timeline.SortedArray.prototype.getFirst = function() {
+ return (this._a.length > 0) ? this._a[0] : null;
+};
+
+Timeline.SortedArray.prototype.getLast = function() {
+ return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
+};
+
+/*==================================================
+ * Event Index
+ *==================================================
+ */
+
+Timeline.EventIndex = function(unit) {
+ var eventIndex = this;
+
+ this._unit = (unit != null) ? unit : Timeline.NativeDateUnit;
+ this._events = new Timeline.SortedArray(
+ function(event1, event2) {
+ return eventIndex._unit.compare(event1.getStart(), event2.getStart());
+ }
+ );
+ this._indexed = true;
+};
+
+Timeline.EventIndex.prototype.getUnit = function() {
+ return this._unit;
+};
+
+Timeline.EventIndex.prototype.add = function(evt) {
+ this._events.add(evt);
+ this._indexed = false;
+};
+
+Timeline.EventIndex.prototype.removeAll = function() {
+ this._events.removeAll();
+ this._indexed = false;
+};
+
+Timeline.EventIndex.prototype.getCount = function() {
+ return this._events.length();
+};
+
+Timeline.EventIndex.prototype.getIterator = function(startDate, endDate) {
+ if (!this._indexed) {
+ this._index();
+ }
+ return new Timeline.EventIndex._Iterator(this._events, startDate, endDate, this._unit);
+};
+
+Timeline.EventIndex.prototype.getAllIterator = function() {
+ return new Timeline.EventIndex._AllIterator(this._events);
+};
+
+Timeline.EventIndex.prototype.getEarliestDate = function() {
+ var evt = this._events.getFirst();
+ return (evt == null) ? null : evt.getStart();
+};
+
+Timeline.EventIndex.prototype.getLatestDate = function() {
+ var evt = this._events.getLast();
+ if (evt == null) {
+ return null;
+ }
+
+ if (!this._indexed) {
+ this._index();
+ }
+
+ var index = evt._earliestOverlapIndex;
+ var date = this._events.elementAt(index).getEnd();
+ for (var i = index + 1; i < this._events.length(); i++) {
+ date = this._unit.later(date, this._events.elementAt(i).getEnd());
+ }
+
+ return date;
+};
+
+Timeline.EventIndex.prototype._index = function() {
+ /*
+ * For each event, we want to find the earliest preceding
+ * event that overlaps with it, if any.
+ */
+
+ var l = this._events.length();
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ evt._earliestOverlapIndex = i;
+ }
+
+ var toIndex = 1;
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ var end = evt.getEnd();
+
+ toIndex = Math.max(toIndex, i + 1);
+ while (toIndex < l) {
+ var evt2 = this._events.elementAt(toIndex);
+ var start2 = evt2.getStart();
+
+ if (this._unit.compare(start2, end) < 0) {
+ evt2._earliestOverlapIndex = i;
+ toIndex++;
+ } else {
+ break;
+ }
+ }
+ }
+ this._indexed = true;
+};
+
+Timeline.EventIndex._Iterator = function(events, startDate, endDate, unit) {
+ this._events = events;
+ this._startDate = startDate;
+ this._endDate = endDate;
+ this._unit = unit;
+
+ this._currentIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), startDate);
+ });
+ if (this._currentIndex - 1 >= 0) {
+ this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex;
+ }
+ this._currentIndex--;
+
+ this._maxIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), endDate);
+ });
+
+ this._hasNext = false;
+ this._next = null;
+ this._findNext();
+};
+
+Timeline.EventIndex._Iterator.prototype = {
+ hasNext: function() { return this._hasNext; },
+ next: function() {
+ if (this._hasNext) {
+ var next = this._next;
+ this._findNext();
+
+ return next;
+ } else {
+ return null;
+ }
+ },
+ _findNext: function() {
+ var unit = this._unit;
+ while ((++this._currentIndex) < this._maxIndex) {
+ var evt = this._events.elementAt(this._currentIndex);
+ if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+ unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+ this._next = evt;
+ this._hasNext = true;
+ return;
+ }
+ }
+ this._next = null;
+ this._hasNext = false;
+ }
+};
+
+Timeline.EventIndex._AllIterator = function(events) {
+ this._events = events;
+ this._index = 0;
+};
+
+Timeline.EventIndex._AllIterator.prototype = {
+ hasNext: function() {
+ return this._index < this._events.length();
+ },
+ next: function() {
+ return this._index < this._events.length() ?
+ this._events.elementAt(this._index++) : null;
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/date-time.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/date-time.js
new file mode 100644
index 00000000..215822de
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/date-time.js
@@ -0,0 +1,321 @@
+/*==================================================
+ * Date/Time Utility Functions and Constants
+ *==================================================
+ */
+
+Timeline.DateTime = new Object();
+
+Timeline.DateTime.MILLISECOND = 0;
+Timeline.DateTime.SECOND = 1;
+Timeline.DateTime.MINUTE = 2;
+Timeline.DateTime.HOUR = 3;
+Timeline.DateTime.DAY = 4;
+Timeline.DateTime.WEEK = 5;
+Timeline.DateTime.MONTH = 6;
+Timeline.DateTime.YEAR = 7;
+Timeline.DateTime.DECADE = 8;
+Timeline.DateTime.CENTURY = 9;
+Timeline.DateTime.MILLENNIUM = 10;
+
+Timeline.DateTime.EPOCH = -1;
+Timeline.DateTime.ERA = -2;
+
+Timeline.DateTime.gregorianUnitLengths = [];
+ (function() {
+ var d = Timeline.DateTime;
+ var a = d.gregorianUnitLengths;
+
+ a[d.MILLISECOND] = 1;
+ a[d.SECOND] = 1000;
+ a[d.MINUTE] = a[d.SECOND] * 60;
+ a[d.HOUR] = a[d.MINUTE] * 60;
+ a[d.DAY] = a[d.HOUR] * 24;
+ a[d.WEEK] = a[d.DAY] * 7;
+ a[d.MONTH] = a[d.DAY] * 31;
+ a[d.YEAR] = a[d.DAY] * 365;
+ a[d.DECADE] = a[d.YEAR] * 10;
+ a[d.CENTURY] = a[d.YEAR] * 100;
+ a[d.MILLENNIUM] = a[d.YEAR] * 1000;
+ })();
+
+Timeline.DateTime.parseGregorianDateTime = function(o) {
+ if (o == null) {
+ return null;
+ } else if (o instanceof Date) {
+ return o;
+ }
+
+ var s = o.toString();
+ if (s.length > 0 && s.length < 8) {
+ var space = s.indexOf(" ");
+ if (space > 0) {
+ var year = parseInt(s.substr(0, space));
+ var suffix = s.substr(space + 1);
+ if (suffix.toLowerCase() == "bc") {
+ year = 1 - year;
+ }
+ } else {
+ var year = parseInt(s);
+ }
+
+ var d = new Date(0);
+ d.setUTCFullYear(year);
+
+ return d;
+ }
+
+ try {
+ return new Date(Date.parse(s));
+ } catch (e) {
+ return null;
+ }
+};
+
+Timeline.DateTime.setIso8601Date = function(dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" +
+ "(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
+ var d = string.match(new RegExp(regexp));
+ if(!d) {
+ throw new Error("Invalid date string: " + string);
+ }
+
+ var year = d[1];
+ var month = d[4];
+ var date = d[6];
+ var dayofyear = d[8];
+ var week = d[10];
+ var dayofweek = (d[12]) ? d[12] : 1;
+
+ dateObject.setUTCFullYear(year);
+ if (dayofyear) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(Number(dayofyear));
+ } else if (week) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(1);
+ var gd = dateObject.getUTCDay();
+ var day = (gd) ? gd : 7;
+ var offset = Number(dayofweek) + (7 * Number(week));
+
+ if (day <= 4) {
+ dateObject.setUTCDate(offset + 1 - day);
+ } else {
+ dateObject.setUTCDate(offset + 8 - day);
+ }
+ } else {
+ if (month) {
+ dateObject.setUTCDate(1);
+ dateObject.setUTCMonth(month - 1);
+ }
+ if (date) {
+ dateObject.setUTCDate(date);
+ }
+ }
+
+ return dateObject;
+};
+
+Timeline.DateTime.setIso8601Time = function (dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ // first strip timezone info from the end
+ var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
+ var d = string.match(new RegExp(timezone));
+
+ var offset = 0; // local time if no tz info
+ if (d) {
+ if (d[0] != 'Z') {
+ offset = (Number(d[3]) * 60) + Number(d[5]);
+ offset *= ((d[2] == '-') ? 1 : -1);
+ }
+ string = string.substr(0, string.length - d[0].length);
+ }
+
+ // then work out the time
+ var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$";
+ var d = string.match(new RegExp(regexp));
+ if(!d) {
+ dojo.debug("invalid time string: " + string);
+ return false;
+ }
+ var hours = d[1];
+ var mins = Number((d[3]) ? d[3] : 0);
+ var secs = (d[5]) ? d[5] : 0;
+ var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+ dateObject.setUTCHours(hours);
+ dateObject.setUTCMinutes(mins);
+ dateObject.setUTCSeconds(secs);
+ dateObject.setUTCMilliseconds(ms);
+
+ return dateObject;
+};
+
+Timeline.DateTime.setIso8601 = function (dateObject, string){
+ /*
+ * This function has been copied from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
+
+ Timeline.DateTime.setIso8601Date(dateObject, comps[0]);
+ if (comps.length == 2) {
+ Timeline.DateTime.setIso8601Time(dateObject, comps[1]);
+ }
+ return dateObject;
+};
+
+Timeline.DateTime.parseIso8601DateTime = function (string) {
+ try {
+ return Timeline.DateTime.setIso8601(new Date(0), string);
+ } catch (e) {
+ return null;
+ }
+};
+
+Timeline.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var timeShift = timeZone *
+ Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.HOUR];
+
+ var date2 = new Date(date.getTime() + timeShift);
+ var clearInDay = function(d) {
+ d.setUTCMilliseconds(0);
+ d.setUTCSeconds(0);
+ d.setUTCMinutes(0);
+ d.setUTCHours(0);
+ };
+ var clearInYear = function(d) {
+ clearInDay(d);
+ d.setUTCDate(1);
+ d.setUTCMonth(0);
+ };
+
+ switch(intervalUnit) {
+ case Timeline.DateTime.MILLISECOND:
+ var x = date2.getUTCMilliseconds();
+ date2.setUTCMilliseconds(x - (x % multiple));
+ break;
+ case Timeline.DateTime.SECOND:
+ date2.setUTCMilliseconds(0);
+
+ var x = date2.getUTCSeconds();
+ date2.setUTCSeconds(x - (x % multiple));
+ break;
+ case Timeline.DateTime.MINUTE:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+
+ var x = date2.getUTCMinutes();
+ date2.setTime(date2.getTime() -
+ (x % multiple) * Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.MINUTE]);
+ break;
+ case Timeline.DateTime.HOUR:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+ date2.setUTCMinutes(0);
+
+ var x = date2.getUTCHours();
+ date2.setUTCHours(x - (x % multiple));
+ break;
+ case Timeline.DateTime.DAY:
+ clearInDay(date2);
+ break;
+ case Timeline.DateTime.WEEK:
+ clearInDay(date2);
+ var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
+ date2.setTime(date2.getTime() -
+ d * Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.DAY]);
+ break;
+ case Timeline.DateTime.MONTH:
+ clearInDay(date2);
+ date2.setUTCDate(1);
+
+ var x = date2.getUTCMonth();
+ date2.setUTCMonth(x - (x % multiple));
+ break;
+ case Timeline.DateTime.YEAR:
+ clearInYear(date2);
+
+ var x = date2.getUTCFullYear();
+ date2.setUTCFullYear(x - (x % multiple));
+ break;
+ case Timeline.DateTime.DECADE:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
+ break;
+ case Timeline.DateTime.CENTURY:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
+ break;
+ case Timeline.DateTime.MILLENNIUM:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
+ break;
+ }
+
+ date.setTime(date2.getTime() - timeShift);
+};
+
+Timeline.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var originalTime = date.getTime();
+ Timeline.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
+ if (date.getTime() < originalTime) {
+ date.setTime(date.getTime() +
+ Timeline.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
+ }
+};
+
+Timeline.DateTime.incrementByInterval = function(date, intervalUnit) {
+ switch(intervalUnit) {
+ case Timeline.DateTime.MILLISECOND:
+ date.setTime(date.getTime() + 1)
+ break;
+ case Timeline.DateTime.SECOND:
+ date.setTime(date.getTime() + 1000);
+ break;
+ case Timeline.DateTime.MINUTE:
+ date.setTime(date.getTime() +
+ Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.MINUTE]);
+ break;
+ case Timeline.DateTime.HOUR:
+ date.setTime(date.getTime() +
+ Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.HOUR]);
+ break;
+ case Timeline.DateTime.DAY:
+ date.setUTCDate(date.getUTCDate() + 1);
+ break;
+ case Timeline.DateTime.WEEK:
+ date.setUTCDate(date.getUTCDate() + 7);
+ break;
+ case Timeline.DateTime.MONTH:
+ date.setUTCMonth(date.getUTCMonth() + 1);
+ break;
+ case Timeline.DateTime.YEAR:
+ date.setUTCFullYear(date.getUTCFullYear() + 1);
+ break;
+ case Timeline.DateTime.DECADE:
+ date.setUTCFullYear(date.getUTCFullYear() + 10);
+ break;
+ case Timeline.DateTime.CENTURY:
+ date.setUTCFullYear(date.getUTCFullYear() + 100);
+ break;
+ case Timeline.DateTime.MILLENNIUM:
+ date.setUTCFullYear(date.getUTCFullYear() + 1000);
+ break;
+ }
+};
+
+Timeline.DateTime.removeTimeZoneOffset = function(date, timeZone) {
+ return new Date(date.getTime() +
+ timeZone * Timeline.DateTime.gregorianUnitLengths[Timeline.DateTime.HOUR]);
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/debug.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/debug.js
new file mode 100644
index 00000000..c216f83a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/debug.js
@@ -0,0 +1,14 @@
+/*==================================================
+ * Debug Utility Functions
+ *==================================================
+ */
+
+Timeline.Debug = new Object();
+
+Timeline.Debug.log = function(msg) {
+};
+
+Timeline.Debug.exception = function(e) {
+ alert("Caught exception: " + (Timeline.Platform.isIE ? e.message : e));
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/dom.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/dom.js
new file mode 100644
index 00000000..44d58ac1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/dom.js
@@ -0,0 +1,76 @@
+/*==================================================
+ * DOM Utility Functions
+ *==================================================
+ */
+
+Timeline.DOM = new Object();
+
+Timeline.DOM.registerEventWithObject = function(elmt, eventName, obj, handler) {
+ Timeline.DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) {
+ return handler.call(obj, elmt2, evt, target);
+ });
+};
+
+Timeline.DOM.registerEvent = function(elmt, eventName, handler) {
+ var handler2 = function(evt) {
+ evt = (evt) ? evt : ((event) ? event : null);
+ if (evt) {
+ var target = (evt.target) ?
+ evt.target : ((evt.srcElement) ? evt.srcElement : null);
+ if (target) {
+ target = (target.nodeType == 1 || target.nodeType == 9) ?
+ target : target.parentNode;
+ }
+
+ return handler(elmt, evt, target);
+ }
+ return true;
+ }
+
+ if (Timeline.Platform.browser.isIE) {
+ elmt.attachEvent("on" + eventName, handler2);
+ } else {
+ elmt.addEventListener(eventName, handler2, false);
+ }
+};
+
+Timeline.DOM.getPageCoordinates = function(elmt) {
+ var left = 0;
+ var top = 0;
+
+ if (elmt.nodeType != 1) {
+ elmt = elmt.parentNode;
+ }
+
+ while (elmt != null) {
+ left += elmt.offsetLeft;
+ top += elmt.offsetTop;
+
+ elmt = elmt.offsetParent;
+ }
+ return { left: left, top: top };
+};
+
+Timeline.DOM.getEventRelativeCoordinates = function(evt, elmt) {
+ if (Timeline.Platform.browser.isIE) {
+ return {
+ x: evt.offsetX,
+ y: evt.offsetY
+ };
+ } else {
+ var coords = Timeline.DOM.getPageCoordinates(elmt);
+ return {
+ x: evt.pageX - coords.left,
+ y: evt.pageY - coords.top
+ };
+ }
+};
+
+Timeline.DOM.cancelEvent = function(evt) {
+ evt.returnValue = false;
+ evt.cancelBubble = true;
+ if ("preventDefault" in evt) {
+ evt.preventDefault();
+ }
+};
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/graphics.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/graphics.js
new file mode 100644
index 00000000..5863ae36
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/graphics.js
@@ -0,0 +1,303 @@
+/*==================================================
+ * Graphics Utility Functions and Constants
+ *==================================================
+ */
+
+Timeline.Graphics = new Object();
+Timeline.Graphics.pngIsTranslucent = (!Timeline.Platform.browser.isIE) || (Timeline.Platform.browser.majorVersion > 6);
+
+Timeline.Graphics.createTranslucentImage = function(doc, url, verticalAlign) {
+ var elmt;
+ if (Timeline.Graphics.pngIsTranslucent) {
+ elmt = doc.createElement("img");
+ elmt.setAttribute("src", url);
+ } else {
+ elmt = doc.createElement("img");
+ elmt.style.display = "inline";
+ elmt.style.width = "1px"; // just so that IE will calculate the size property
+ elmt.style.height = "1px";
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
+ }
+ elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
+ return elmt;
+};
+
+Timeline.Graphics.setOpacity = function(elmt, opacity) {
+ if (Timeline.Platform.browser.isIE) {
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
+ } else {
+ var o = (opacity / 100).toString();
+ elmt.style.opacity = o;
+ elmt.style.MozOpacity = o;
+ }
+};
+
+Timeline.Graphics._bubbleMargins = {
+ top: 33,
+ bottom: 42,
+ left: 33,
+ right: 40
+}
+
+// pixels from boundary of the whole bubble div to the tip of the arrow
+Timeline.Graphics._arrowOffsets = {
+ top: 0,
+ bottom: 9,
+ left: 1,
+ right: 8
+}
+
+Timeline.Graphics._bubblePadding = 15;
+Timeline.Graphics._bubblePointOffset = 6;
+Timeline.Graphics._halfArrowWidth = 18;
+
+Timeline.Graphics.createBubbleForPoint = function(doc, pageX, pageY, contentWidth, contentHeight) {
+ var bubble = {
+ _closed: false,
+ _doc: doc,
+ close: function() {
+ if (!this._closed) {
+ this._doc.body.removeChild(this._div);
+ this._doc = null;
+ this._div = null;
+ this._content = null;
+ this._closed = true;
+ }
+ }
+ };
+
+ var docWidth = doc.body.offsetWidth;
+ var docHeight = doc.body.offsetHeight;
+
+ var margins = Timeline.Graphics._bubbleMargins;
+ var bubbleWidth = margins.left + contentWidth + margins.right;
+ var bubbleHeight = margins.top + contentHeight + margins.bottom;
+
+ var pngIsTranslucent = Timeline.Graphics.pngIsTranslucent;
+ var urlPrefix = Timeline.urlPrefix;
+
+ var setImg = function(elmt, url, width, height) {
+ elmt.style.position = "absolute";
+ elmt.style.width = width + "px";
+ elmt.style.height = height + "px";
+ if (pngIsTranslucent) {
+ elmt.style.background = "url(" + url + ")";
+ } else {
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='crop')";
+ }
+ }
+ var div = doc.createElement("div");
+ div.style.width = bubbleWidth + "px";
+ div.style.height = bubbleHeight + "px";
+ div.style.position = "absolute";
+ div.style.zIndex = 1000;
+ bubble._div = div;
+
+ var divInner = doc.createElement("div");
+ divInner.style.width = "100%";
+ divInner.style.height = "100%";
+ divInner.style.position = "relative";
+ div.appendChild(divInner);
+
+ var createImg = function(url, left, top, width, height) {
+ var divImg = doc.createElement("div");
+ divImg.style.left = left + "px";
+ divImg.style.top = top + "px";
+ setImg(divImg, url, width, height);
+ divInner.appendChild(divImg);
+ }
+
+ createImg(urlPrefix + "images/bubble-top-left.png", 0, 0, margins.left, margins.top);
+ createImg(urlPrefix + "images/bubble-top.png", margins.left, 0, contentWidth, margins.top);
+ createImg(urlPrefix + "images/bubble-top-right.png", margins.left + contentWidth, 0, margins.right, margins.top);
+
+ createImg(urlPrefix + "images/bubble-left.png", 0, margins.top, margins.left, contentHeight);
+ createImg(urlPrefix + "images/bubble-right.png", margins.left + contentWidth, margins.top, margins.right, contentHeight);
+
+ createImg(urlPrefix + "images/bubble-bottom-left.png", 0, margins.top + contentHeight, margins.left, margins.bottom);
+ createImg(urlPrefix + "images/bubble-bottom.png", margins.left, margins.top + contentHeight, contentWidth, margins.bottom);
+ createImg(urlPrefix + "images/bubble-bottom-right.png", margins.left + contentWidth, margins.top + contentHeight, margins.right, margins.bottom);
+
+ var divClose = doc.createElement("div");
+ divClose.style.left = (bubbleWidth - margins.right + Timeline.Graphics._bubblePadding - 16 - 2) + "px";
+ divClose.style.top = (margins.top - Timeline.Graphics._bubblePadding + 1) + "px";
+ divClose.style.cursor = "pointer";
+ setImg(divClose, urlPrefix + "images/close-button.png", 16, 16);
+ Timeline.DOM.registerEventWithObject(divClose, "click", bubble, bubble.close);
+ divInner.appendChild(divClose);
+
+ var divContent = doc.createElement("div");
+ divContent.style.position = "absolute";
+ divContent.style.left = margins.left + "px";
+ divContent.style.top = margins.top + "px";
+ divContent.style.width = contentWidth + "px";
+ divContent.style.height = contentHeight + "px";
+ divContent.style.overflow = "auto";
+ divContent.style.background = "white";
+ divInner.appendChild(divContent);
+ bubble.content = divContent;
+
+ (function() {
+ if (pageX - Timeline.Graphics._halfArrowWidth - Timeline.Graphics._bubblePadding > 0 &&
+ pageX + Timeline.Graphics._halfArrowWidth + Timeline.Graphics._bubblePadding < docWidth) {
+
+ var left = pageX - Math.round(contentWidth / 2) - margins.left;
+ left = pageX < (docWidth / 2) ?
+ Math.max(left, -(margins.left - Timeline.Graphics._bubblePadding)) :
+ Math.min(left, docWidth + (margins.right - Timeline.Graphics._bubblePadding) - bubbleWidth);
+
+ if (pageY - Timeline.Graphics._bubblePointOffset - bubbleHeight > 0) { // top
+ var divImg = doc.createElement("div");
+
+ divImg.style.left = (pageX - Timeline.Graphics._halfArrowWidth - left) + "px";
+ divImg.style.top = (margins.top + contentHeight) + "px";
+ setImg(divImg, urlPrefix + "images/bubble-bottom-arrow.png", 37, margins.bottom);
+ divInner.appendChild(divImg);
+
+ div.style.left = left + "px";
+ div.style.top = (pageY - Timeline.Graphics._bubblePointOffset - bubbleHeight +
+ Timeline.Graphics._arrowOffsets.bottom) + "px";
+
+ return;
+ } else if (pageY + Timeline.Graphics._bubblePointOffset + bubbleHeight < docHeight) { // bottom
+ var divImg = doc.createElement("div");
+
+ divImg.style.left = (pageX - Timeline.Graphics._halfArrowWidth - left) + "px";
+ divImg.style.top = "0px";
+ setImg(divImg, urlPrefix + "images/bubble-top-arrow.png", 37, margins.top);
+ divInner.appendChild(divImg);
+
+ div.style.left = left + "px";
+ div.style.top = (pageY + Timeline.Graphics._bubblePointOffset -
+ Timeline.Graphics._arrowOffsets.top) + "px";
+
+ return;
+ }
+ }
+
+ var top = pageY - Math.round(contentHeight / 2) - margins.top;
+ top = pageY < (docHeight / 2) ?
+ Math.max(top, -(margins.top - Timeline.Graphics._bubblePadding)) :
+ Math.min(top, docHeight + (margins.bottom - Timeline.Graphics._bubblePadding) - bubbleHeight);
+
+ if (pageX - Timeline.Graphics._bubblePointOffset - bubbleWidth > 0) { // left
+ var divImg = doc.createElement("div");
+
+ divImg.style.left = (margins.left + contentWidth) + "px";
+ divImg.style.top = (pageY - Timeline.Graphics._halfArrowWidth - top) + "px";
+ setImg(divImg, urlPrefix + "images/bubble-right-arrow.png", margins.right, 37);
+ divInner.appendChild(divImg);
+
+ div.style.left = (pageX - Timeline.Graphics._bubblePointOffset - bubbleWidth +
+ Timeline.Graphics._arrowOffsets.right) + "px";
+ div.style.top = top + "px";
+ } else { // right
+ var divImg = doc.createElement("div");
+
+ divImg.style.left = "0px";
+ divImg.style.top = (pageY - Timeline.Graphics._halfArrowWidth - top) + "px";
+ setImg(divImg, urlPrefix + "images/bubble-left-arrow.png", margins.left, 37);
+ divInner.appendChild(divImg);
+
+ div.style.left = (pageX + Timeline.Graphics._bubblePointOffset -
+ Timeline.Graphics._arrowOffsets.left) + "px";
+ div.style.top = top + "px";
+ }
+ })();
+
+ doc.body.appendChild(div);
+
+ return bubble;
+};
+
+Timeline.Graphics.createMessageBubble = function(doc) {
+ var containerDiv = doc.createElement("div");
+ if (Timeline.Graphics.pngIsTranslucent) {
+ var topDiv = doc.createElement("div");
+ topDiv.style.height = "33px";
+ topDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-top-left.png) top left no-repeat";
+ topDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(topDiv);
+
+ var topRightDiv = doc.createElement("div");
+ topRightDiv.style.height = "33px";
+ topRightDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-top-right.png) top right no-repeat";
+ topDiv.appendChild(topRightDiv);
+
+ var middleDiv = doc.createElement("div");
+ middleDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-left.png) top left repeat-y";
+ middleDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(middleDiv);
+
+ var middleRightDiv = doc.createElement("div");
+ middleRightDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-right.png) top right repeat-y";
+ middleRightDiv.style.paddingRight = "44px";
+ middleDiv.appendChild(middleRightDiv);
+
+ var contentDiv = doc.createElement("div");
+ middleRightDiv.appendChild(contentDiv);
+
+ var bottomDiv = doc.createElement("div");
+ bottomDiv.style.height = "55px";
+ bottomDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
+ bottomDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(bottomDiv);
+
+ var bottomRightDiv = doc.createElement("div");
+ bottomRightDiv.style.height = "55px";
+ bottomRightDiv.style.background = "url(" + Timeline.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
+ bottomDiv.appendChild(bottomRightDiv);
+ } else {
+ containerDiv.style.border = "2px solid #7777AA";
+ containerDiv.style.padding = "20px";
+ containerDiv.style.background = "white";
+ Timeline.Graphics.setOpacity(containerDiv, 90);
+
+ var contentDiv = doc.createElement("div");
+ containerDiv.appendChild(contentDiv);
+ }
+
+ return {
+ containerDiv: containerDiv,
+ contentDiv: contentDiv
+ };
+};
+
+Timeline.Graphics.createAnimation = function(f, from, to, duration) {
+ return new Timeline.Graphics._Animation(f, from, to, duration);
+};
+
+Timeline.Graphics._Animation = function(f, from, to, duration) {
+ this.f = f;
+
+ this.from = from;
+ this.to = to;
+ this.current = from;
+
+ this.duration = duration;
+ this.start = new Date().getTime();
+ this.timePassed = 0;
+};
+
+Timeline.Graphics._Animation.prototype.run = function() {
+ var a = this;
+ window.setTimeout(function() { a.step(); }, 100);
+};
+
+Timeline.Graphics._Animation.prototype.step = function() {
+ this.timePassed += 100;
+
+ var timePassedFraction = this.timePassed / this.duration;
+ var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
+ var current = parameterFraction * (this.to - this.from) + this.from;
+
+ try {
+ this.f(current, current - this.current);
+ } catch (e) {
+ }
+ this.current = current;
+
+ if (this.timePassed < this.duration) {
+ this.run();
+ }
+};
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/platform.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/platform.js
new file mode 100644
index 00000000..73e17cd5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/platform.js
@@ -0,0 +1,90 @@
+/*==================================================
+ * Platform Utility Functions and Constants
+ *==================================================
+ */
+
+Timeline.Platform.os = {
+ isMac: false,
+ isWin: false,
+ isWin32: false,
+ isUnix: false
+};
+Timeline.Platform.browser = {
+ isIE: false,
+ isNetscape: false,
+ isMozilla: false,
+ isFirefox: false,
+ isOpera: false,
+ isSafari: false,
+
+ majorVersion: 0,
+ minorVersion: 0
+};
+
+(function() {
+ var an = navigator.appName.toLowerCase();
+ var ua = navigator.userAgent.toLowerCase();
+
+ /*
+ * Operating system
+ */
+ Timeline.Platform.os.isMac = (ua.indexOf('mac') != -1);
+ Timeline.Platform.os.isWin = (ua.indexOf('win') != -1);
+ Timeline.Platform.os.isWin32 = Timeline.Platform.isWin && (
+ ua.indexOf('95') != -1 ||
+ ua.indexOf('98') != -1 ||
+ ua.indexOf('nt') != -1 ||
+ ua.indexOf('win32') != -1 ||
+ ua.indexOf('32bit') != -1
+ );
+ Timeline.Platform.os.isUnix = (ua.indexOf('x11') != -1);
+
+ /*
+ * Browser
+ */
+ Timeline.Platform.browser.isIE = (an.indexOf("microsoft") != -1);
+ Timeline.Platform.browser.isNetscape = (an.indexOf("netscape") != -1);
+ Timeline.Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1);
+ Timeline.Platform.browser.isFirefox = (ua.indexOf("firefox") != -1);
+ Timeline.Platform.browser.isOpera = (an.indexOf("opera") != -1);
+ //Timeline.Platform.browser.isSafari = (an.indexOf("safari") != -1);
+
+ var parseVersionString = function(s) {
+ var a = s.split(".");
+ Timeline.Platform.browser.majorVersion = parseInt(a[0]);
+ Timeline.Platform.browser.minorVersion = parseInt(a[1]);
+ };
+ var indexOf = function(s, sub, start) {
+ var i = s.indexOf(sub, start);
+ return i >= 0 ? i : s.length;
+ };
+
+ if (Timeline.Platform.browser.isMozilla) {
+ var offset = ua.indexOf("mozilla/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+ if (Timeline.Platform.browser.isIE) {
+ var offset = ua.indexOf("msie ");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset)));
+ }
+ }
+ if (Timeline.Platform.browser.isNetscape) {
+ var offset = ua.indexOf("rv:");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset)));
+ }
+ }
+ if (Timeline.Platform.browser.isFirefox) {
+ var offset = ua.indexOf("firefox/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+})();
+
+Timeline.Platform.getDefaultLocale = function() {
+ return Timeline.Platform.clientLocale;
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/xmlhttp.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/xmlhttp.js
new file mode 100644
index 00000000..660f19fc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/scripts/util/xmlhttp.js
@@ -0,0 +1,133 @@
+/*==================================================
+ * XmlHttp Utility Functions
+ *==================================================
+ */
+
+Timeline.XmlHttp = new Object();
+
+/**
+ * Callback for XMLHttp onRequestStateChange.
+ */
+Timeline.XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) {
+ switch (xmlhttp.readyState) {
+ // 1: Request not yet made
+ // 2: Contact established with server but nothing downloaded yet
+ // 3: Called multiple while downloading in progress
+
+ // Download complete
+ case 4:
+ try {
+ if (xmlhttp.status == 0 // file:// urls, works on Firefox
+ || xmlhttp.status == 200 // http:// urls
+ ) {
+ if (fDone) {
+ fDone(xmlhttp);
+ }
+ } else {
+ if (fError) {
+ fError(
+ xmlhttp.statusText,
+ xmlhttp.status,
+ xmlhttp
+ );
+ }
+ }
+ } catch (e) {
+ Timeline.Debug.exception(e);
+ }
+ break;
+ }
+};
+
+/**
+ * Creates an XMLHttpRequest object. On the first run, this
+ * function creates a platform-specific function for
+ * instantiating an XMLHttpRequest object and then replaces
+ * itself with that function.
+ */
+Timeline.XmlHttp._createRequest = function() {
+ if (Timeline.Platform.browser.isIE) {
+ var programIDs = [
+ "Msxml2.XMLHTTP",
+ "Microsoft.XMLHTTP",
+ "Msxml2.XMLHTTP.4.0"
+ ];
+ for (var i = 0; i < programIDs.length; i++) {
+ try {
+ var programID = programIDs[i];
+ var f = function() {
+ return new ActiveXObject(programID);
+ };
+ var o = f();
+
+ // We are replacing the Timeline._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ Timeline.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ // silent
+ }
+ }
+ throw new Error("Failed to create an XMLHttpRequest object");
+ } else {
+ try {
+ var f = function() {
+ return new XMLHttpRequest();
+ };
+ var o = f();
+
+ // We are replacing the Timeline._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ Timeline.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ throw new Error("Failed to create an XMLHttpRequest object");
+ }
+ }
+};
+
+/**
+ * Performs an asynchronous HTTP GET.
+ * fError is of the form function(statusText, statusCode, xmlhttp).
+ * fDone is of the form function(xmlhttp).
+ */
+Timeline.XmlHttp.get = function(url, fError, fDone) {
+ var xmlhttp = Timeline.XmlHttp._createRequest();
+
+ xmlhttp.open("GET", url, true);
+ xmlhttp.onreadystatechange = function() {
+ Timeline.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(null);
+};
+
+/**
+ * Performs an asynchronous HTTP POST.
+ * fError is of the form function(statusText, statusCode, xmlhttp).
+ * fDone is of the form function(xmlhttp).
+ */
+Timeline.XmlHttp.post = function(url, body, fError, fDone) {
+ var xmlhttp = Timeline.XmlHttp._createRequest();
+
+ xmlhttp.open("POST", url, true);
+ xmlhttp.onreadystatechange = function() {
+ Timeline.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(body);
+};
+
+Timeline.XmlHttp._forceXML = function(xmlhttp) {
+ try {
+ xmlhttp.overrideMimeType("text/xml");
+ } catch (e) {
+ xmlhttp.setrequestheader("Content-Type", "text/xml");
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/ethers.css b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/ethers.css
new file mode 100644
index 00000000..7d1671d7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/ethers.css
@@ -0,0 +1,63 @@
+.timeline-ether-marker-bottom {
+ width: 5em;
+ height: 1.5em;
+ border-left: 1px solid #aaa;
+ padding-left: 2px;
+ color: #aaa;
+}
+
+.timeline-ether-marker-bottom-emphasized {
+ width: 5em;
+ height: 2em;
+ border-left: 1px solid #aaa;
+ padding-left: 2px;
+ color: black;
+}
+
+.timeline-ether-marker-top {
+ width: 5em;
+ height: 1.5em;
+ border-left: 1px solid #aaa;
+ padding-left: 2px;
+ color: #aaa;
+}
+
+.timeline-ether-marker-top-emphasized {
+ width: 5em;
+ height: 2em;
+ border-left: 1px solid #aaa;
+ padding-left: 2px;
+ color: black;
+}
+
+
+.timeline-ether-marker-right {
+ width: 5em;
+ height: 1.5em;
+ border-top: 1px solid #aaa;
+ padding-top: 2px;
+ color: #aaa;
+}
+
+.timeline-ether-marker-right-emphasized {
+ width: 7em;
+ height: 1.5em;
+ border-top: 1px solid #aaa;
+ padding-top: 2px;
+ color: black;
+}
+.timeline-ether-marker-left {
+ width: 5em;
+ height: 1.5em;
+ border-top: 1px solid #aaa;
+ padding-top: 2px;
+ color: #aaa;
+}
+
+.timeline-ether-marker-left-emphasized {
+ width: 7em;
+ height: 1.5em;
+ border-top: 1px solid #aaa;
+ padding-top: 2px;
+ color: black;
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/events.css b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/events.css
new file mode 100644
index 00000000..68e7581a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/events.css
@@ -0,0 +1,45 @@
+.timeline-duration-event {
+ position: absolute;
+ overflow: hidden;
+ border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+ position: absolute;
+ overflow: hidden;
+ border-left: 1px solid blue;
+ padding-left: 2px;
+}
+
+.timeline-instant-event {
+ position: absolute;
+ overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+ font-weight: bold;
+ border-bottom: 1px solid #888;
+ margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+ margin: 0.5em;
+ text-align: right;
+ color: #A0A040;
+}
+.timeline-event-bubble-wiki a {
+ color: #A0A040;
+}
+
+.timeline-event-bubble-time {
+ color: #aaa;
+}
+
+.timeline-event-bubble-image {
+ float: right;
+ padding-left: 5px;
+ padding-bottom: 5px;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/timeline.css b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/timeline.css
new file mode 100644
index 00000000..04ef2e47
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/styles/timeline.css
@@ -0,0 +1,65 @@
+.timeline-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.timeline-copyright {
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ z-index: 1000;
+ cursor: pointer;
+}
+
+.timeline-message-container {
+ position: absolute;
+ top: 30%;
+ left: 35%;
+ right: 35%;
+ z-index: 1000;
+ display: none;
+}
+.timeline-message {
+ font-size: 120%;
+ font-weight: bold;
+ text-align: center;
+}
+.timeline-message img {
+ vertical-align: middle;
+}
+
+.timeline-band {
+ position: absolute;
+ background: #eee;
+ z-index: 10;
+}
+
+.timeline-band-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-input {
+ position: absolute;
+ width: 1em;
+ height: 1em;
+ overflow: hidden;
+ z-index: 0;
+}
+.timeline-band-input input{
+ width: 0;
+}
+
+.timeline-band-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.timeline-band-layer-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/timeline-api.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/timeline-api.js
new file mode 100644
index 00000000..78dbafe2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/timeline-api.js
@@ -0,0 +1,226 @@
+/*==================================================
+ * Timeline API
+ *
+ * This file will load all the Javascript files
+ * necessary to make the standard timeline work.
+ * It also detects the default locale.
+ *
+ * Include this file in your HTML file as follows:
+ *
+ * <script src="http://simile.mit.edu/timeline/api/scripts/timeline-api.js" type="text/javascript"></script>
+ *
+ *==================================================
+ */
+
+var Timeline_urlPrefix = mw.config.get( 'wgScriptPath') + "/extensions/SemanticResultFormats/formats/timeline/resources/SimileTimeline/";
+
+var Timeline = new Object();
+window.Timeline = Timeline; // Added to make this RL compatible.
+Timeline.Platform = new Object();
+ /*
+ HACK: We need these 2 things here because we cannot simply append
+ a <script> element containing code that accesses Timeline.Platform
+ to initialize it because IE executes that <script> code first
+ before it loads timeline.js and util/platform.js.
+ */
+
+(function() {
+ var javascriptFiles = [
+ "timeline.js",
+
+ "util/platform.js",
+ "util/debug.js",
+ "util/xmlhttp.js",
+ "util/dom.js",
+ "util/graphics.js",
+ "util/date-time.js",
+ "util/data-structure.js",
+
+ "units.js",
+ "themes.js",
+ "ethers.js",
+ "ether-painters.js",
+ "labellers.js",
+ "sources.js",
+ "layouts.js",
+ "painters.js",
+ "decorators.js"
+ ];
+ var cssFiles = [
+ "timeline.css",
+ "ethers.css",
+ "events.css"
+ ];
+
+ var localizedJavascriptFiles = [
+ "timeline.js",
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en", // English
+ "es", // Spanish
+ "fr", // French
+ "it", // Italian
+ "ru", // Russian
+ "se", // Swedish
+ "vi", // Vietnamese
+ "zh" // Chinese
+ ];
+
+ try {
+ var desiredLocales = [ "en" ];
+ var defaultServerLocale = "en";
+
+ var parseURLParameters = function(parameters) {
+ var params = parameters.split("&");
+ for (var p = 0; p < params.length; p++) {
+ var pair = params[p].split("=");
+ if (pair[0] == "locales") {
+ desiredLocales = desiredLocales.concat(pair[1].split(","));
+ } else if (pair[0] == "defaultLocale") {
+ defaultServerLocale = pair[1];
+ }
+ }
+ };
+
+ (function() {
+ if (typeof Timeline_urlPrefix == "string") {
+ Timeline.urlPrefix = Timeline_urlPrefix;
+ if (typeof Timeline_parameters == "string") {
+ parseURLParameters(Timeline_parameters);
+ }
+ } else {
+ var heads = document.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var scripts = heads[h].getElementsByTagName("script");
+ for (var s = 0; s < scripts.length; s++) {
+ var url = scripts[s].src;
+ var i = url.indexOf("timeline-api.js");
+ if (i >= 0) {
+ Timeline.urlPrefix = url.substr(0, i);
+ var q = url.indexOf("?");
+ if (q > 0) {
+ parseURLParameters(url.substr(q + 1));
+ }
+ return;
+ }
+ }
+ }
+ throw new Error("Failed to derive URL prefix for Timeline API code files");
+ }
+ })();
+
+ var includeJavascriptFiles;
+ var includeCssFiles;
+ if ("SimileAjax" in window) {
+ includeJavascriptFiles = function(urlPrefix, filenames) {
+ SimileAjax.includeJavascriptFiles(document, urlPrefix, filenames);
+ }
+ includeCssFiles = function(urlPrefix, filenames) {
+ SimileAjax.includeCssFiles(document, urlPrefix, filenames);
+ }
+ } else {
+ var getHead = function() {
+ return document.getElementsByTagName("head")[0];
+ };
+ var includeJavascriptFile = function(url) {
+ if (document.body == null) {
+ document.write("<script src='" + url + "' type='text/javascript'></script>");
+ } else {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.language = "JavaScript";
+ script.src = url;
+ getHead().appendChild(script);
+ }
+ };
+ var includeCssFile = function(url) {
+ if (document.body == null) {
+ document.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>");
+ } else {
+ var link = document.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("type", "text/css");
+ link.setAttribute("href", url);
+ getHead().appendChild(link);
+ }
+ }
+
+ includeJavascriptFiles = function(urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ includeJavascriptFile(urlPrefix + filenames[i]);
+ }
+ };
+ includeCssFiles = function(urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ includeCssFile(urlPrefix + filenames[i]);
+ }
+ };
+ }
+
+ /*
+ * Include non-localized files
+ */
+ includeJavascriptFiles(Timeline.urlPrefix + "scripts/", javascriptFiles);
+ includeCssFiles(Timeline.urlPrefix + "styles/", cssFiles);
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ loadLocale[defaultServerLocale] = true;
+
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ for (var l = 0; l < desiredLocales.length; l++) {
+ tryLocale(desiredLocales[l]);
+ }
+
+ var defaultClientLocale = defaultServerLocale;
+ var defaultClientLocales = ("language" in navigator ? navigator.language : navigator.browserLanguage).split(";");
+ for (var l = 0; l < defaultClientLocales.length; l++) {
+ var locale = tryLocale(defaultClientLocales[l]);
+ if (locale != null) {
+ defaultClientLocale = locale;
+ break;
+ }
+ }
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ includeJavascriptFiles(Timeline.urlPrefix + "scripts/l10n/" + locale + "/", localizedJavascriptFiles);
+ includeCssFiles(Timeline.urlPrefix + "styles/l10n/" + locale + "/", localizedCssFiles);
+ }
+ }
+
+ Timeline.Platform.serverLocale = defaultServerLocale;
+ Timeline.Platform.clientLocale = defaultClientLocale;
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/ext.srf.timeline.js b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/ext.srf.timeline.js
new file mode 100644
index 00000000..343f0c6c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeline/resources/ext.srf.timeline.js
@@ -0,0 +1,281 @@
+/**
+ * A script for scraping Simile Timeline suitable data from HTML, and
+ * for inserting the required Simile scripts if needed.
+ */
+
+( function( $, mw ) {
+
+ 'use strict';
+
+ mw.loader.using( [ 'ext.smile.timeline', 'ext.smile.timeline.core' ] ).then( function () {
+
+ $( document ).ready( function() {
+ $( '.smwtimeline' ).each( function() {
+
+ var context = $( this );
+ context.removeClass( 'is-disabled' );
+
+ smw_make_timeline( context[0] );
+ } );
+ } );
+
+ } );
+
+}( jQuery, mediaWiki ) );
+
+function smw_make_timeline(div) {
+ // extract relevant event data:
+ var eventSource = new Timeline.DefaultEventSource();
+
+ var theme = Timeline.ClassicTheme.create();
+ // make some elements opaque to unify look across platforms
+ // Timelines way of setting transparency fails on some browsers (some IE6s, Konquerors)
+ // Also, we use "imprecise instants" to display durations, since Timeline fails if
+ // only durations are used and multiple bands appear. See below.
+ theme.ether.highlightColor = "#E7E7E7";
+ theme.ether.highlightOpacity = 100;
+ theme.event.instant.impreciseOpacity = 100;
+ //theme.event.instant.icon = Timeline.urlPrefix + "images/blue-circle.png";
+ //theme.ether.interval.line.opacity = 100;
+ //theme.ether.interval.weekend.opacity = 100;
+ //theme.ether.interval.weekend.color = "#FFFFE0";
+
+ var childs = div.childNodes;
+ var l = childs.length;
+ var bands = [];
+ var bandcount = 0;
+ var position = new Date(); //fallback position: today;
+ for (var i = 0; i < childs.length; div.removeChild(childs[0])) {
+ switch (childs[i].nodeType) {
+ case 1: //ELEMENT_NODE -- an event or some general data
+ if (childs[i].className == "smwtlevent")
+ smw_add_event(childs[i],eventSource);
+ else if (childs[i].className == "smwtlband") {
+ switch (childs[i].firstChild.data) {
+ case "MILLISECOND": bands[bandcount] = Timeline.DateTime.MILLISECOND; break;
+ case "SECOND": bands[bandcount] = Timeline.DateTime.SECOND; break;
+ case "MINUTE": bands[bandcount] = Timeline.DateTime.MINUTE; break;
+ case "HOUR": bands[bandcount] = Timeline.DateTime.HOUR; break;
+ case "DAY": bands[bandcount] = Timeline.DateTime.DAY; break;
+ case "WEEK": bands[bandcount] = Timeline.DateTime.WEEK; break;
+ case "MONTH": bands[bandcount] = Timeline.DateTime.MONTH; break;
+ case "YEAR": bands[bandcount] = Timeline.DateTime.YEAR; break;
+ case "DECADE": bands[bandcount] = Timeline.DateTime.DECADE; break;
+ case "CENTURY": bands[bandcount] = Timeline.DateTime.CENTURY; break;
+ case "MILLENNIUM": bands[bandcount] = Timeline.DateTime.MILLENNIUM; break;
+ default: bandcount--; //dont count unrecognized bands
+ }
+ bandcount++;
+ } else if (childs[0].className == "smwtlposition") {
+ position = Timeline.DateTime.parseIso8601DateTime(childs[i].firstChild.data);
+ } /*else if (childs[i].className == "smwtlsize") {
+ div.setAttribute("style","height: " + childs[i].firstChild.data + ";");
+ }*/
+ break;
+ case 3: //TEXT_NODE -- ignore text on this level
+ break;
+ }
+
+ }
+
+ // create bands
+ var bandInfos = [];
+ var bandinfo;
+ for (var i = 0; i < bandcount; i++) {
+ if (i == 0) {
+ bandinfo = Timeline.createBandInfo({
+ eventSource: eventSource,
+ width: smw_get_bandwidth(i,bandcount),
+ intervalUnit: bands[i],
+ intervalPixels: 100,
+ date: position,
+ theme: theme
+ })
+ } else {
+ bandinfo = Timeline.createBandInfo({
+ showEventText: false,
+ trackHeight: 0.5,
+ trackGap: 0.2,
+ eventSource: eventSource,
+ width: smw_get_bandwidth(i,bandcount),
+ intervalUnit: bands[i],
+ intervalPixels: 100,
+ date: position,
+ theme: theme
+ })
+ bandinfo.syncWith = 0;
+ bandinfo.highlight = true;
+ }
+ bandInfos[i] = bandinfo;
+ }
+
+ // default band
+ if (bandcount == 0) {
+ bandInfos[0] = Timeline.createBandInfo({
+ eventSource: eventSource,
+ width: "100%",
+ intervalUnit: Timeline.DateTime.MONTH,
+ intervalPixels: 100,
+ theme: theme
+ })
+ }
+
+ Timeline.create(div, bandInfos);
+}
+
+function smw_get_bandwidth(number,count) {
+ switch (count) {
+ case 1: if (number == 0) return "100%"; else return "0%";
+ case 2:
+ switch (number) {
+ case 0: return "70%";
+ case 1: return "30%";
+ default: return "0%";
+ }
+ case 3:
+ switch (number) {
+ case 0: return "60%";
+ case 1: return "25%";
+ case 2: return "15%";
+ default: return "0%";
+ }
+ default: // dont support more than 4 bands
+ switch (number) {
+ case 0: return "50%";
+ case 1: return "25%";
+ case 2: return "15%";
+ case 3: return "10%";
+ default: return "0%";
+ }
+ }
+}
+
+function smw_add_event(evspan,evs) {
+ var startdate = null;
+ var enddate = null;
+ var desc = "";
+ var ttl = "";
+ var linkurl = "";
+ var prefix = "";
+ var postfix = "";
+ var icon = Timeline.urlPrefix + "images/dull-blue-circle.png";
+
+ var childs = evspan.childNodes;
+ for (var i = 0; i < childs.length; /* manual increment below */ ) {
+ if (childs[i].nodeType == 1) { //ELEMENT_NODE -- some data element
+ switch (childs[i].className) {
+ case "smwtlstart":
+ if (childs[i].firstChild.nodeType == 3)
+ startdate = childs[i].firstChild.data;
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtlend":
+ if (childs[i].firstChild.nodeType == 3)
+ enddate = childs[i].firstChild.data;
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtltitle":
+ if (childs[i].firstChild.nodeType == 3)
+ ttl = childs[i].firstChild.data;
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtlprefix":
+ if (childs[i].firstChild.nodeType == 3)
+ prefix = childs[i].firstChild.data;
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtlpostfix":
+ if (childs[i].firstChild.nodeType == 3)
+ postfix = childs[i].firstChild.data;
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtlurl": // accept both plain text and <a>, use text of <a> for title
+ if (childs[i].firstChild.nodeType == 3) {
+ linkurl = childs[i].firstChild.data;
+ } else {
+ linkurl = childs[i].firstChild.getAttribute("href");
+
+ if (childs[i].firstChild.hasChildNodes())
+ ttl = childs[i].firstChild.firstChild.data;
+ }
+
+ if ( linkurl === null && childs[i].firstChild.hasChildNodes() ) {
+ if ( childs[i].firstChild.firstChild.nodeType == 1 ) {
+ linkurl = childs[i].firstChild.firstChild.getAttribute( "href" );
+ ttl = childs[i].firstChild.firstChild.innerHTML;
+ } else {
+ ttl = childs[i].firstChild.firstChild.data;
+ }
+ };
+
+ evspan.removeChild(childs[i]);
+ break;
+ case "smwtlcoloricon":
+ if (childs[i].firstChild.nodeType == 3) {
+ switch ( childs[i].firstChild.data ) {
+ case "0": icon =Timeline.urlPrefix + "images/dull-blue-circle.png";
+ break;
+ case "1": icon =Timeline.urlPrefix + "images/dull-red-circle.png";
+ break;
+ case "2": icon =Timeline.urlPrefix + "images/dull-green-circle.png";
+ break;
+ case "3": icon =Timeline.urlPrefix + "images/gray-circle.png";
+ break;
+ case "4": icon =Timeline.urlPrefix + "images/dark-blue-circle.png";
+ break;
+ case "5": icon =Timeline.urlPrefix + "images/dark-red-circle.png";
+ break;
+ case "6": icon =Timeline.urlPrefix + "images/dark-green-circle.png";
+ break;
+ case "7": icon =Timeline.urlPrefix + "images/blue-circle.png";
+ break;
+ case "8": icon =Timeline.urlPrefix + "images/red-circle.png";
+ break;
+ case "9": icon =Timeline.urlPrefix + "images/green-circle.png";
+ break;
+ }
+ }
+ evspan.removeChild(childs[i]);
+ break;
+ default: //proceed
+ i++;
+ }
+ } else i++; //proceed
+ }
+ desc = evspan.innerHTML; // the remaining nodes form the description of the event
+
+ var parseDateTimeFunction = evs._events.getUnit().getParser("iso8601");
+ var evt = new Timeline.DefaultEventSource.Event(
+ parseDateTimeFunction(startdate),
+ parseDateTimeFunction(enddate),
+ parseDateTimeFunction(null),
+ parseDateTimeFunction(null),
+ true, //( enddate == null ), // FIXME: timeline currently fails if there are only durations and mutliple bands
+ prefix + ttl + postfix,
+ desc,
+ "", //no image
+ linkurl,
+ icon,
+ "",
+ ""
+ );
+// TODO: must the following have a meaningful definition?
+// evt.getProperty = function(name) {
+// return "";
+// };
+ evs._events.add(evt);
+}
+
+//FIXME: Not used at the moment. Is this needed?
+//addEvent(window, "resize", onResize);
+
+// var resizeTimerID = null;
+// function onResize() {
+// if (resizeTimerID == null) {
+// resizeTimerID = window.setTimeout(function() {
+// resizeTimerID = null;
+// smwtl.layout();
+// }, 500);
+// }
+// }
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeseries/SRF_Timeseries.php b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/SRF_Timeseries.php
new file mode 100644
index 00000000..7159cb57
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/SRF_Timeseries.php
@@ -0,0 +1,275 @@
+<?php
+
+/**
+ * A query printer for timeseries using the flot plotting JavaScript library
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Flot_timeseries_chart
+ * @licence GNU GPL v2 or later
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ */
+class SRFTimeseries extends SMWResultPrinter {
+
+ /**
+ * @see SMWResultPrinter::getName
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-timeseries' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $result, $outputMode ) {
+
+ // Data processing
+ $data = $this->getAggregatedTimeSeries( $result, $outputMode );
+
+ // Post-data processing check
+ if ( $data === [] ) {
+ return $result->addErrors( [ wfMessage( 'srf-warn-empy-chart' )->inContentLanguage()->text() ] );
+ } else {
+ $options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) );
+ return $this->getFormatOutput( $data, $options );
+ }
+ }
+
+ /**
+ * Returns an array with numerical data
+ *
+ * @since 1.8
+ *
+ * @param SMWQueryResult $result
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getAggregatedTimeSeries( SMWQueryResult $result, $outputMode ) {
+ $values = [];
+ $aggregatedValues = [];
+
+ while ( /* array of SMWResultArray */
+ $row = $result->getNext() ) { // Objects (pages)
+ $timeStamp = '';
+ $series = [];
+
+ foreach ( $row as /* SMWResultArray */
+ $field ) {
+ $sum = [];
+
+ // Group by subject (page object) or property
+ if ( $this->params['group'] == 'subject' ) {
+ $group = $field->getResultSubject()->getTitle()->getText();
+ } else {
+ $group = $field->getPrintRequest()->getLabel();
+ }
+
+ while ( ( /* SMWDataValue */
+ $dataValue = $field->getNextDataValue() ) !== false ) { // Data values
+
+ // Find the timestamp
+ if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_TIME ) {
+ // We work with a timestamp, we have to use intval because DataItem
+ // returns a string but we want a numeric representation of the timestamp
+ $timeStamp = intval( $dataValue->getDataItem()->getMwTimestamp() );
+ }
+
+ // Find the values (numbers only)
+ if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_NUMBER ) {
+ $sum[] = $dataValue->getNumber();
+ }
+ }
+ // Aggegate individual values into a sum
+ $rowSum = array_sum( $sum );
+
+ // Check the sum and threshold/min
+ if ( $timeStamp !== '' && $field->getPrintRequest()->getTypeID(
+ ) !== '_dat' && $rowSum >= $this->params['min'] ) {
+ $series[$group] = [ $timeStamp, $rowSum ];
+ }
+ }
+ $values[] = $series;
+ }
+
+ // Re-assign values according to their group
+ foreach ( $values as $key => $value ) {
+ foreach ( $values[$key] as $row => $rowvalue ) {
+ $aggregatedValues[$row][] = $rowvalue;
+ }
+ }
+ return $aggregatedValues;
+ }
+
+ /**
+ * Prepare data for the output
+ *
+ * @since 1.8
+ *
+ * @param array $data
+ *
+ * @return string
+ */
+ protected function getFormatOutput( array $data, $options ) {
+
+ // Object count
+ static $statNr = 0;
+ $chartID = 'timeseries-' . ++$statNr;
+
+ $this->isHTML = true;
+
+ // Reorganize the raw data
+ foreach ( $data as $key => $values ) {
+ $dataObject[] = [ 'label' => $key, 'data' => $values ];
+ }
+
+ // Series colour
+ $seriescolors = $this->params['chartcolor'] !== '' ? array_filter(
+ explode( ",", $this->params['chartcolor'] )
+ ) : [];
+
+ // Prepare transfer array
+ $chartData = [
+ 'data' => $dataObject,
+ 'fcolumntypeid' => '_dat',
+ 'sask' => $options['sask'],
+ 'parameters' => [
+ 'width' => $this->params['width'],
+ 'height' => $this->params['height'],
+ 'charttitle' => $this->params['charttitle'],
+ 'charttext' => $this->params['charttext'],
+ 'infotext' => $this->params['infotext'],
+ 'charttype' => $this->params['charttype'],
+ 'gridview' => $this->params['gridview'],
+ 'zoom' => $this->params['zoompane'],
+ 'seriescolors' => $seriescolors
+ ]
+ ];
+
+ // Array encoding and output
+ $requireHeadItem = [ $chartID => FormatJson::encode( $chartData ) ];
+ SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
+
+ // RL module
+ SMWOutputs::requireResource( 'ext.srf.timeseries.flot' );
+
+ if ( $this->params['gridview'] === 'tabs' ) {
+ SMWOutputs::requireResource( 'ext.srf.util.grid' );
+ }
+
+ // Chart/graph placeholder
+ $chart = Html::rawElement(
+ 'div',
+ [
+ 'id' => $chartID,
+ 'class' => 'container',
+ 'style' => "display:none;"
+ ],
+ null
+ );
+
+ // Processing/loading image
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // Beautify class selector
+ $class = $this->params['class'] ? ' ' . $this->params['class'] : ' flot-chart-common';
+
+ // General output marker
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-timeseries' . $class
+ ],
+ $processing . $chart
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['charttype'] = [
+ 'message' => 'srf-paramdesc-layout',
+ 'default' => 'line',
+ 'values' => [ 'line', 'bar' ],
+ ];
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'message' => 'srf-paramdesc-minvalue',
+ 'default' => '',
+ ];
+
+ $params['gridview'] = [
+ 'message' => 'srf-paramdesc-gridview',
+ 'default' => 'none',
+ 'values' => [ 'none', 'tabs' ],
+ ];
+
+ $params['group'] = [
+ 'message' => 'srf-paramdesc-group',
+ 'default' => 'subject',
+ 'values' => [ 'property', 'subject' ],
+ ];
+
+ $params['zoompane'] = [
+ 'message' => 'srf-paramdesc-zoompane',
+ 'default' => 'bottom',
+ 'values' => [ 'none', 'bottom', 'top' ],
+ ];
+
+ $params['height'] = [
+ 'type' => 'integer',
+ 'message' => 'srf_paramdesc_chartheight',
+ 'default' => 400,
+ 'lowerbound' => 1,
+ ];
+
+ $params['width'] = [
+ 'message' => 'srf_paramdesc_chartwidth',
+ 'default' => '100%',
+ ];
+
+ $params['charttitle'] = [
+ 'message' => 'srf_paramdesc_charttitle',
+ 'default' => '',
+ ];
+
+ $params['charttext'] = [
+ 'message' => 'srf-paramdesc-charttext',
+ 'default' => '',
+ ];
+
+ $params['infotext'] = [
+ 'message' => 'srf-paramdesc-infotext',
+ 'default' => '',
+ ];
+
+ $params['chartcolor'] = [
+ 'message' => 'srf-paramdesc-chartcolor',
+ 'default' => '',
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.flot.core.css b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.flot.core.css
new file mode 100644
index 00000000..e0502fcc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.flot.core.css
@@ -0,0 +1,63 @@
+/**
+ * CSS for SRF flot module
+ * *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @release: 0.1
+ */
+.srf-flot-chart-title {
+ text-align:center;
+ font-weight: bold;
+ color:grey;
+ margin-left:10px;
+ margin-bottom:5px;
+ display:block;
+ position:relative;
+ font-size:110%;
+}
+
+.srf-flot-note{
+ font-weight: bold;
+ color:red;
+ position:relative;
+ margin-bottom:5px;
+ margin-top:5px;
+}
+
+.srf-flot-chart-text {
+ color:grey;
+ display:block;
+ position:relative;
+ font-size:90%;
+ margin-left: 5px;
+}
+
+.srf-flot-tooltip {
+ background:#3f3f3f;
+ border:1px solid #222;
+ opacity:.8;
+ z-index:1000;
+ padding:5px 10px;
+ color:#fff
+ background-color: #C5E1EE;
+ margin-top: 5px;
+ padding: 4px; !important;
+ font-size: 75%;
+ font-weight: normal;
+ line-height: 1.5;
+ clear:both;
+ color: #464646;
+ -webkit-border-radius: 1.25em;
+ -moz-border-radius: 1.25em;
+ -o-border-radius: 1.25em;
+ border-radius: 1.25em;
+ border: 1px solid #DFDFDF;
+ background-color: #F1F1F1;
+ background-image: -ms-linear-gradient(top,#ffffff,#f6f8f9);
+ background-image: -moz-linear-gradient(top,#ffffff,#f6f8f9);
+ background-image: -o-linear-gradient(top,#ffffff,#f6f8f9);
+ background-image: -webkit-radient(linear,left top,left bottom,from(#ffffff),to(#f6f8f9));
+ background-image: -webkit-linear-gradient(top,#ffffff,#f6f8f9);
+ background-image: linear-gradient(top,#ffffff,#f6f8f9);
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.timeseries.flot.js b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.timeseries.flot.js
new file mode 100644
index 00000000..ec4b4f64
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/timeseries/resources/ext.srf.timeseries.flot.js
@@ -0,0 +1,342 @@
+/**
+ * JavaScript for SRF timeseries
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Timeseries format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, srf ) {
+ 'use strict';
+
+ /*global mw:true*/
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ var util = new srf.util();
+
+ var methods = {
+ /**
+ * Initialization method
+ *
+ * @since 1.8
+ */
+ init : function() {
+ var chart = this,
+ container = this.find( ".container" ),
+ chartID = container.attr( "id" ),
+ json = mw.config.get( chartID );
+
+ // Parse json string and convert it back
+ var data = typeof json === 'string' ? jQuery.parseJSON( json ) : json;
+
+ /**
+ * @var plotClass identifies class that holds the plot
+ * @var addedHeight collects heights of objects other that the chart in order
+ * to be able to adjust the height of the chart and sray within the limits
+ * specified by the query printer
+ */
+ var plotClass = 'srf-flot-plot',
+ addedHeight = 0,
+ width = data.parameters.width,
+ height = data.parameters.height;
+
+ // Extend option settings
+ var settings = $.extend( {
+ 'height' : height,
+ 'width' : width,
+ 'plotclass' : plotClass,
+ 'chartid' : chartID
+ }, data );
+
+ // Set chart height and width and reassign to catch px instead of % value
+ container.css( { 'height': height, 'width': width } );
+ chart.css( { 'height': container.height(), 'width': container.width() } );
+ container.css( {
+ 'height': height - ( data.parameters.gridview === 'tabs' ? 20 : 0 ),
+ 'width': chart.width() - ( data.parameters.gridview === 'tabs' ? 20 : 0 )
+ } );
+
+ // Make sure to keep converted px values because canvas elements can't deal with %
+ height = container.height();
+ width = container.width();
+
+ // Hide processing
+ util.spinner.hide( { context: chart } );
+
+ // Release chart container
+ container.show();
+
+ // Timeseries plot container
+ container.prepend( '<div class="' + plotClass + '"></span>' );
+
+ // Set-up chart title
+ var chartTitle = data.parameters.charttitle;
+ if ( chartTitle.length > 0 ) {
+ container.find( '.' + plotClass )
+ .before( '<span class="srf-flot-chart-title">' + chartTitle + '</span>' );
+ addedHeight += container.find( '.srf-flot-chart-title' ).height();
+ }
+
+ // Set-up chart text
+ var chartText = data.parameters.charttext;
+ if ( chartText.length > 0 ) {
+ container.find( '.' + plotClass )
+ .after( '<span class="srf-flot-chart-text">' + chartText + '</span>' );
+ container.find( '.srf-flot-chart-text' )
+ .addClass( ( data.parameters.gridview === 'tabs' ? 'tabs' : '' ) );
+ addedHeight += container.find( '.srf-flot-chart-text' ).height() - 20;
+ }
+
+ // Set-up zoom box
+ var zoom = '<div class="' + plotClass + '-zoom" style="height:50px"></div>';
+ if ( data.parameters.zoom === 'top'){
+ container.find( '.' + plotClass ).before( zoom ).css( 'width', width );
+ }else if ( data.parameters.zoom === 'bottom' ){
+ container.find( '.' + plotClass ).after( zoom ).css( 'width', width );
+ }
+ addedHeight += container.find( '.' + plotClass + '-zoom' ).height();
+
+ // Keep the overall height and width and apply possible changes onto the chart
+ height = height - addedHeight;
+
+ // Handle jqGrid table
+ if ( data.parameters.gridview === 'tabs' ) {
+ // gridview declaration
+ var dataSeries = [];
+ var dataTable = [];
+ var newRow = {};
+ for ( var j = 0; j < data.data.length; ++j ) {
+ newRow = { 'label' : data.data[j].label };
+ dataSeries.push ( newRow );
+ dataTable.push ( data.data[j].data );
+ }
+
+ // Set options
+ var gridOptions = {
+ 'context' : chart,
+ 'id' : chartID,
+ 'container' : container,
+ 'info' : data.parameters.infotext,
+ 'data' : {
+ 'series': dataSeries,
+ 'data' : dataTable,
+ 'fcolumntypeid': data.fcolumntypeid,
+ 'sask' : data.sask
+ }
+ };
+
+ // Grid view instance
+ new srf.util.grid( gridOptions );
+ }
+
+ // Tabs height can vary (due to CSS) therefore after tabs instance was
+ // created get the height
+ var _tabs = chart.find( '.ui-tabs-nav' );
+ if (_tabs.length > 0) {
+ height -= _tabs.outerHeight();
+ }
+ container.find( '.' + plotClass ).css( { 'height': height, 'width': width } );
+
+ // Draw chart
+ container.srfFlotTimeSeries( 'chart', settings );
+ },
+ /**
+ * Chart handling method
+ *
+ * @since 1.8
+ */
+ chart : function( content ) {
+ var plotArea = this.find( '.' + content.plotclass ),
+ plotZoomArea = this.find( '.' + content.plotclass + '-zoom' ),
+ data = content.data;
+
+ // Javascript timestamp is the number of milliseconds since
+ // January 1, 1970 00:00:00 UTC therefore * 1000
+ // correct timestamps daily midnights in UTC+0100, add one hour to hit
+ // the midnights in the plot
+ function convertData( tseries ) {
+ var ttData =[];
+ var max = 0;
+ var len=tseries.length;
+ for ( var j = 0; j < len; ++j ) {
+ ttData = tseries[j].data;
+ for ( var p = 0; p < ttData.length; ++p ) {
+ ttData[p][0] = ( ttData[p][0] * 1000 ) + ( 60 * 60 * 1000 );
+ max = max > ttData[p][1] ? max : ttData[p][1];
+ }
+ }
+ return ttData;
+ }
+
+ // Data conversion
+ convertData( data );
+
+ // Helper function for returning the weekends in a period
+ function weekendAreas(axes) {
+ var markings = [];
+ var d = new Date(axes.xaxis.min);
+
+ // go to the first Saturday
+ d.setUTCDate(d.getUTCDate() - ( ( d.getUTCDay() + 1 ) % 7) );
+ d.setUTCSeconds(0);
+ d.setUTCMinutes(0);
+ d.setUTCHours(0);
+ var i = d.getTime();
+ do {
+ // when we don't set yaxis, the rectangle automatically
+ // extends to infinity upwards and downwards
+ markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });
+ i += 7 * 24 * 60 * 60 * 1000;
+ } while (i < axes.xaxis.max);
+
+ return markings;
+ }
+
+ // Set-up plot options
+ var options = {
+ xaxis: { mode: "time", tickLength: 5 },
+ alignTicksWithAxis: 1,
+ selection: { mode: content.parameters.zoom === 'top' || content.parameters.zoom === 'bottom' ? "x" : null },
+ bars: content.parameters.charttype === 'bar' ? { show: true, barWidth: 0.6 } : false,
+ colors: content.parameters.seriescolors,
+ grid: { markings: weekendAreas, hoverable: true, clickable: true, borderColor: '#BBB', borderWidth: 1, backgroundColor: '#FFF' }
+ };
+
+ // Draw actual plot
+ var plot = $.plot( plotArea , data, options );
+
+ if ( content.parameters.zoom === 'top' || content.parameters.zoom === 'bottom' ){
+
+ // Init zoom box
+ var zoombox = $.plot( plotZoomArea , data , {
+ series: {
+ lines: content.parameters.charttype === 'bar' ? false: { show: true, lineWidth: 1 },
+ bars: content.parameters.charttype === 'bar' ? { show: true, barWidth: 0.6 } : false,
+ shadowSize: 0
+ },
+ grid: { borderColor: '#BBB', borderWidth: 1, backgroundColor: '#FFF' },
+ colors: content.parameters.seriescolors,
+ legend: { show: false },
+ xaxis: { ticks: [], mode: "time" , timeformat: "%y-%m-%d" },
+ yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
+ selection: { mode: "x" }
+ } );
+
+ // Connect zoom box and chart
+ this.bind("plotselected", function (event, ranges) {
+ if (ranges.xaxis.to - ranges.xaxis.from < 0.00001){
+ ranges.xaxis.to = ranges.xaxis.from + 0.00001;
+ }
+ if (ranges.yaxis.to - ranges.yaxis.from < 0.00001){
+ ranges.yaxis.to = ranges.yaxis.from + 0.00001;
+ }
+
+ // Calculate y-min and y-max for the selected x range
+ var ymin, ymax;
+ var plotdata = plot.getData();
+ $.each(plotdata, function (e, val) {
+ $.each(val.data, function (e1, val1) {
+ if ((val1[0] >= ranges.xaxis.from) && (val1[0] <= ranges.xaxis.to)) {
+ if (ymax == null || val1[1] > ymax) { ymax = val1[1]; }
+ if (ymin == null || val1[1] < ymin) { ymin = val1[1]; }
+ }
+ } );
+ } );
+
+ ranges.yaxis.from = Math.round( ymin ).toFixed(0);
+ ranges.yaxis.to = Math.round( ymax + ( ymax / Math.log(ymax)/Math.log(10) ) ).toFixed(0);
+
+ // Do the zooming
+ plot = $.plot( plotArea , data ,
+ $.extend(true, {}, options, {
+ xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
+ yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
+ } )
+ );
+
+ // Don't fire event on the overview to prevent eternal loop
+ zoombox.setSelection(ranges, true);
+ } );
+
+ plotZoomArea.bind("plotselected", function (event, ranges) {
+ plot.setSelection(ranges);
+ } );
+ }
+ // Tool tip for line chart
+ function showTooltip(x, y, contents) {
+ $('<div class="srf-flot-tooltip">' + contents + '</div>').css( {
+ position: 'absolute',
+ display: 'none',
+ top: y + 5,
+ left: x + 5,
+ //border: '1px solid #0070A3',
+ padding: '2px',
+ // 'background-color': '#fee',
+ opacity: 0.80
+ } ).appendTo("body").fadeIn(200);
+ }
+
+ var b = function (i) {
+ return i < 10 ? "0" + i : i;
+ },
+ h = function (i) {
+ var l = i.getUTCFullYear() + "-" + b(i.getUTCMonth() + 1);
+ return l + "-" + b( i.getUTCDate() );
+ };
+
+ var previousPoint = null;
+
+ $( "#" + content.chartid ).bind("plothover", function (event, pos, item) {
+ $("#x").text(pos.x.toFixed(2));
+ $("#y").text(pos.y.toFixed(2));
+ if (item) {
+ if (previousPoint !== item.datapoint) {
+ previousPoint = item.datapoint;
+ $( '.srf-flot-tooltip' ).remove();
+ var x = item.datapoint[0],
+ y = item.datapoint[1];
+ showTooltip(item.pageX, item.pageY, h( new Date( x ) ) + " : " + y );
+ }
+ } else {
+ $( '.srf-flot-tooltip' ).remove();
+ previousPoint = null;
+ }
+ } );
+ }
+ };
+
+ /**
+ * Method handling
+ *
+ * @since 1.8
+ */
+ $.fn.srfFlotTimeSeries = function( method ) {
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist within the jQuery.srf.plugin pool' );
+ }
+ };
+
+ $( document ).ready( function() {
+ // Check if eachAsync exists, and if so use it to increase browsers responsiveness
+ if( $.isFunction( $.fn.eachAsync ) ){
+ $( ".srf-timeseries" ).eachAsync( {
+ delay: 100,
+ bulk: 0,
+ loop: function(){
+ $( this ).srfFlotTimeSeries();
+ }
+ } );
+ }else{
+ $( ".srf-timeseries" ).each( function() {
+ $( this ).srfFlotTimeSeries();
+ } );
+ }
+ } );
+} )( jQuery, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNode.php b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNode.php
new file mode 100644
index 00000000..264487d8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNode.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace SRF\Formats\Tree;
+
+use Cdb\Exception;
+use Tree\Node\Node;
+use Tree\Node\NodeInterface;
+use Tree\Node\NodeTrait;
+
+class TreeNode extends Node {
+
+ /**
+ * SRFTreeElement constructor.
+ *
+ * @param \SMWResultArray[] | null $row
+ */
+ public function __construct( $row = null ) {
+ parent::__construct( $row );
+ }
+
+ /**
+ * @return string
+ */
+ public function getHash() {
+
+ $resultSubject = $this->getResultSubject();
+
+ if ( $resultSubject !== null ) {
+ return $resultSubject->getSerialization();
+ }
+
+ return '';
+ }
+
+ /**
+ * @return null|\SMWDIWikiPage
+ */
+ public function getResultSubject() {
+ /** @var \SMWResultArray[] | null $row */
+ $row = $this->getValue();
+
+ if ( $row !== null ) {
+ return $row[0]->getResultSubject();
+ }
+
+ return null;
+ }
+
+ /**
+ * @param NodeInterface $child
+ *
+ * @return NodeTrait
+ * @throws Exception
+ */
+ public function addChild( NodeInterface $child ) {
+
+ foreach ( $this->getAncestorsAndSelf() as $ancestor ) {
+ if ( $ancestor->getHash() === $child->getHash() ) {
+ throw new Exception( 'srf-tree-circledetected' );
+ }
+ }
+
+ return parent::addChild( $child );
+ }
+
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNodeVisitor.php b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNodeVisitor.php
new file mode 100644
index 00000000..6f07b588
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeNodeVisitor.php
@@ -0,0 +1,193 @@
+<?php
+
+namespace SRF\Formats\Tree;
+
+use Tree\Node\NodeInterface;
+use Tree\Visitor\Visitor;
+
+class TreeNodePrinter implements Visitor {
+
+ private $depth = 0;
+ private $rowNumber = 0;
+ private $configuration = null;
+ /**
+ * @var TreeResultPrinter
+ */
+ private $resultPrinter = null;
+ private $columnLabels = [];
+
+ public function __construct( TreeResultPrinter $resultPrinter, $configuration ) {
+ $this->configuration = $configuration;
+ $this->resultPrinter = $resultPrinter;
+ }
+
+ public function visit( NodeInterface $node ) {
+
+ $nodeTexts = [ $this->getTextForNode( $node ) ];
+
+ $this->depth++;
+ $this->rowNumber++;
+
+ foreach ( $node->getChildren() as $child ) {
+ $nodeTexts = array_merge(
+ $nodeTexts,
+ $child->accept( $this )
+ );
+ }
+
+ $this->depth--;
+
+ return $nodeTexts;
+ }
+
+ protected function getTextForNode( TreeNode $node ) {
+
+ /** @var \SMWResultArray[]|null $row */
+ $row = $node->getValue();
+
+ if ( $row === null ) {
+ return '';
+ }
+
+ $textForNode = str_repeat( ( $this->configuration['format'] === 'oltree' ) ? '#' : '*', $this->depth );
+
+ if ( $this->configuration['template'] === '' ) {
+ // build simple list
+ $textForNode .= $this->getTextForRowNoTemplate( $row );
+ } else {
+ // build template code
+ $textForNode .= $this->getTextForRowWithTemplate( $row );
+
+ }
+
+ return $textForNode;
+ }
+
+ /**
+ * @param \SMWResultArray[] $row
+ *
+ * @return string
+ */
+ protected function getTextForRowNoTemplate( $row ) {
+
+ $cellTexts = [];
+ foreach ( $row as $columnNumber => $cell ) {
+
+ $valuesText = $this->getValuesTextForCell( $cell, $columnNumber );
+
+ if ( $valuesText === '' ) {
+ continue;
+ }
+
+ $labelText = $this->getLabelForCell( $cell, $columnNumber );
+
+ $cellTexts[] = $labelText . $valuesText;
+ }
+
+ if ( count( $cellTexts ) > 0 ) {
+ $result = array_shift( $cellTexts );
+
+ if ( count( $cellTexts ) > 0 ) {
+ $result .= ' (' . join( $this->configuration['sep'], $cellTexts ) . ')';
+ }
+
+ } else {
+ $result = '';
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param \SMWResultArray[] $row
+ *
+ * @return string
+ */
+ protected function getTextForRowWithTemplate( $row ) {
+
+ $templateParams = [];
+ foreach ( $row as $columnNumber => $cell ) {
+
+ $valuesText = $this->getValuesTextForCell( $cell, $columnNumber );
+ $paramName = $this->getParamNameForCell( $cell, $columnNumber );
+
+ $templateParams[] = "$paramName=$valuesText ";
+ }
+
+ $templateParams[] = "#=$this->rowNumber ";
+
+ return $this->resultPrinter->getTemplateCall( $this->configuration['template'], $templateParams );
+ }
+
+ /**
+ * @param \SMWResultArray $cell
+ * @param int $columnNumber
+ *
+ * @return string
+ */
+ protected function getValuesTextForCell( \SMWResultArray $cell, $columnNumber ) {
+
+ $cell->reset();
+ $linker = $this->resultPrinter->getLinkerForColumn( $columnNumber );
+
+ $valueTexts = [];
+
+ while ( ( $text = $cell->getNextText( SMW_OUTPUT_WIKI, $linker ) ) !== false ) {
+ $valueTexts[] = $text;
+ }
+
+ $valuesText = join( $this->configuration['sep'], $valueTexts );
+ return $valuesText;
+ }
+
+ /**
+ * @param \SMWResultArray $cell
+ * @param int $columnNumber
+ *
+ * @return string
+ */
+ protected function getParamNameForCell( $cell, $columnNumber ) {
+
+ if ( !array_key_exists( $columnNumber, $this->columnLabels ) ) {
+
+ $label = $cell->getPrintRequest()->getLabel();
+
+ if ( $this->configuration[ 'named args' ] === true || ( $label === '' ) ) {
+ $paramName = $columnNumber + 1;
+ } else {
+ $paramName = $label;
+ }
+
+ $this->columnLabels[$columnNumber] = $paramName;
+ }
+
+ return $this->columnLabels[$columnNumber];
+ }
+
+ /**
+ * @param \SMWResultArray $cell
+ *
+ * @return string
+ */
+ protected function getLabelForCell( $cell, $columnNumber ) {
+
+ if ( !array_key_exists( $columnNumber, $this->columnLabels ) ) {
+
+ if ( $this->configuration['headers'] === 'hide' || $cell->getPrintRequest()->getLabel() === '' ) {
+ $labelText = '';
+ } elseif ( $this->configuration['headers'] === 'plain' ) {
+ $labelText = $cell->getPrintRequest()->getText( SMW_OUTPUT_WIKI ) . ': ';
+ } else { // $this->configuration[ 'headers' ] === 'link'
+ $labelText = $cell->getPrintRequest()->getText(
+ SMW_OUTPUT_WIKI,
+ $this->resultPrinter->getLinker()
+ ) . ': ';
+ }
+
+ $this->columnLabels[$columnNumber] = $labelText;
+ }
+
+ return $this->columnLabels[$columnNumber];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeResultPrinter.php b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeResultPrinter.php
new file mode 100644
index 00000000..a5011d0e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/tree/TreeResultPrinter.php
@@ -0,0 +1,384 @@
+<?php
+
+namespace SRF\Formats\Tree;
+
+/**
+ * File holding the Tree class.
+ *
+ * @author Stephan Gambke
+ */
+
+use Exception;
+use Html;
+use SMW\DIProperty;
+use SMW\DIWikiPage;
+use SMW\ListResultPrinter;
+use SMWQueryResult;
+use Title;
+
+/**
+ * Result printer that prints query results as a tree (nested html lists).
+ *
+ * The available formats are 'tree', 'ultree', 'oltree'. 'tree' is an alias of
+ * 'ultree'. In an #ask query the parameter 'parent' must be set to contain the
+ * name of the property, that gives the parent page of the subject page.
+ *
+ */
+class TreeResultPrinter extends ListResultPrinter {
+
+ private $standardTemplateParameters;
+
+ /**
+ * @var SMWQueryResult | null
+ */
+ private $queryResult = null;
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getName()
+ */
+ public function getName() {
+ // Give grep a chance to find the usages:
+ // srf-printername-tree, srf-printername-ultree, srf-printername-oltree
+ return \Message::newFromKey( 'srf-printername-' . $this->mFormat )->text();
+ }
+
+ /**
+ * @return SMWQueryResult
+ * @throws Exception
+ */
+ public function getQueryResult() {
+
+ if ( $this->queryResult === null ) {
+ throw new Exception( __METHOD__ . ' called outside of ' . __CLASS__ . '::getResultText().' );
+ }
+
+ return $this->queryResult;
+ }
+
+ /**
+ * @param SMWQueryResult | null $queryResult
+ */
+ public function setQueryResult( $queryResult ) {
+ $this->queryResult = $queryResult;
+ }
+
+ /**
+ * @see ResultPrinter::postProcessParameters()
+ */
+ protected function postProcessParameters() {
+
+ parent::postProcessParameters();
+
+ // Don't support pagination in trees
+ $this->mSearchlabel = null;
+
+ // Allow "_" for encoding spaces, as documented
+ $this->params['sep'] = str_replace( '_', ' ', $this->params['sep'] );
+
+ if ( !ctype_digit( strval( $this->params['start level'] ) ) || $this->params['start level'] < 1 ) {
+ $this->params['start level'] = 1;
+ }
+
+ }
+
+ /**
+ * Return serialised results in specified format.
+ *
+ * @param SMWQueryResult $queryResult
+ * @param $outputmode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $queryResult, $outputmode ) {
+
+ $this->setQueryResult( $queryResult );
+
+ if ( $this->params['parent'] === '' ) {
+ $this->addError( 'srf-tree-noparentprop' );
+ return '';
+ }
+
+ $rootHash = $this->getRootHash();
+
+ if ( $rootHash === false ) {
+ $this->addError( 'srf-tree-rootinvalid', $this->params['root'] );
+ return '';
+ }
+
+ $this->hasTemplates =
+ $this->params['introtemplate'] !== '' ||
+ $this->params['outrotemplate'] !== '' ||
+ $this->params['template'] !== '';
+
+ if ( $this->hasTemplates ) {
+ $this->initalizeStandardTemplateParameters();
+ }
+
+ $tree = $this->buildTreeFromQueryResult( $rootHash );
+ $lines = $this->buildLinesFromTree( $tree );
+
+ // Display default if the result is empty
+ if ( count( $lines ) === 0 ) {
+ return $this->params['default'];
+ }
+
+ // FIXME: Linking to further events ($this->linkFurtherResults())
+ // does not make sense for tree format. But maybe display a warning?
+
+ $resultText = join(
+ "\n",
+ array_merge(
+ [ $this->getTemplateCall( $this->params['introtemplate'] ) ],
+ $lines,
+ [ $this->getTemplateCall( $this->params['outrotemplate'] ) ]
+ )
+ );
+
+ $this->setQueryResult( null );
+
+ if ( trim( $this->params[ 'class' ] ) === '' ) {
+ return $resultText;
+ }
+
+ return Html::rawElement( 'div', [ 'class' => $this->params[ 'class' ] ], $resultText );
+ }
+
+ /**
+ * @param string $templateName
+ * @param string[] $params
+ *
+ * @return string
+ */
+ public function getTemplateCall( $templateName, $params = [] ) {
+
+ if ( $templateName === '' ) {
+ return '';
+ }
+
+ return '{{' . $templateName . '|' . join( '|', $params ) . $this->standardTemplateParameters . '}}';
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ * @throws Exception
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['parent'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-tree-parent',
+ ];
+
+ $params['root'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-tree-root',
+ ];
+
+ $params['start level'] = [
+ 'default' => 1,
+ 'message' => 'srf-paramdesc-tree-startlevel',
+ 'type' => 'integer',
+ ];
+
+ $params['sep'] = [
+ 'default' => ', ',
+ 'message' => 'smw-paramdesc-sep',
+ ];
+
+ $params['template arguments'] = [
+ 'default' => '',
+ 'message' => 'smw-paramdesc-template-arguments',
+ ];
+
+ $params['class'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-class',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @param string $rootHash
+ *
+ * @return TreeNode
+ */
+ protected function buildTreeFromQueryResult( $rootHash ) {
+
+ $nodes = $this->getHashOfNodes();
+
+ if ( $rootHash !== '' && !array_key_exists( $rootHash, $nodes ) ) {
+ return new TreeNode();
+ }
+
+ return $this->buildTreeFromNodeList( $rootHash, $nodes );
+ }
+
+ /**
+ * @return string | false
+ */
+ protected function getRootHash() {
+
+ if ( $this->params['root'] === '' ) {
+ return '';
+ }
+
+ // get the title object of the root page
+ $rootTitle = Title::newFromText( $this->params['root'] );
+
+ if ( $rootTitle !== null ) {
+ return DIWikiPage::newFromTitle( $rootTitle )->getSerialization();
+ }
+
+ return false;
+
+ }
+
+ /**
+ * @return TreeNode[]
+ */
+ protected function getHashOfNodes() {
+
+ /** @var TreeNode[] $nodes */
+ $nodes = [];
+
+ $queryResult = $this->getQueryResult();
+
+ $row = $queryResult->getNext();
+ while ( $row !== false ) {
+ $node = new TreeNode( $row );
+ $nodes[$node->getHash()] = $node;
+ $row = $queryResult->getNext();
+ }
+
+ return $nodes;
+ }
+
+ /**
+ * Returns a linker object for making hyperlinks
+ *
+ * @return \Linker
+ */
+ public function getLinker( $firstcol = false ) {
+ return $this->mLinker;
+ }
+
+ /**
+ * Depending on current linking settings, returns a linker object
+ * for making hyperlinks or NULL if no links should be created.
+ *
+ * @param int $column Column number
+ *
+ * @return \Linker|null
+ */
+ public function getLinkerForColumn( $column ) {
+ return parent::getLinker( $column === 0 );
+ }
+
+ private function initalizeStandardTemplateParameters() {
+
+ $query = $this->getQueryResult()->getQuery();
+ $userparam = trim( $this->params[ 'userparam' ] );
+
+ $this->standardTemplateParameters =
+ ( $userparam !== '' ? ( '|userparam=' . $userparam ) : '' ) .
+ '|smw-resultquerycondition=' . $query->getQueryString() .
+ '|smw-resultquerylimit=' . $query->getLimit() .
+ '|smw-resultqueryoffset=' . $query->getOffset();
+
+ }
+
+ /**
+ * @param string $rootHash
+ * @param TreeNode[] $nodes
+ *
+ * @return TreeNode
+ * @throws \Exception
+ */
+ protected function buildTreeFromNodeList( $rootHash, $nodes ) {
+
+ $isRootSpecified = $rootHash !== '';
+
+ $root = new TreeNode();
+ if ( $isRootSpecified ) {
+ $root->addChild( $nodes[$rootHash] );
+ }
+
+ $store = $this->getQueryResult()->getStore();
+ $parentPointerProperty = DIProperty::newFromUserLabel( $this->params['parent'] );
+
+ foreach ( $nodes as $hash => $node ) {
+
+ $parents = $store->getPropertyValues(
+ $node->getResultSubject(),
+ $parentPointerProperty
+ );
+
+ if ( empty( $parents ) && !$isRootSpecified ) {
+
+ $root->addChild( $node );
+
+ } else {
+
+ foreach ( $parents as $parent ) {
+
+ $parentHash = $parent->getSerialization();
+
+ try {
+ if ( array_key_exists( $parentHash, $nodes ) ) {
+ $nodes[$parentHash]->addChild( $node );
+ } elseif ( !$isRootSpecified ) {
+ $root->addChild( $node );
+ }
+ }
+ catch ( Exception $e ) {
+ $this->addError( $e->getMessage(), $node->getResultSubject()->getTitle()->getPrefixedText() );
+ }
+ }
+ }
+ }
+ return $root;
+ }
+
+ /**
+ * @param TreeNode $tree
+ *
+ * @return mixed
+ */
+ protected function buildLinesFromTree( $tree ) {
+ $nodePrinterConfiguration = [
+ 'format' => trim( $this->params['format'] ),
+ 'template' => trim( $this->params['template'] ),
+ 'headers' => $this->params['headers'],
+ 'named args' => $this->params['named args'],
+ 'sep' => $this->params['sep'],
+ ];
+
+ $visitor = new TreeNodePrinter( $this, $nodePrinterConfiguration );
+ $lines = $tree->accept( $visitor );
+ return $lines;
+ }
+
+ /**
+ * @param string $msgkey
+ * @param string | string[] $params
+ */
+ protected function addError( $msgkey, $params = [] ) {
+
+ parent::addError(
+ \Message::newFromKey( $msgkey )
+ ->params( $params )
+ ->inContentLanguage()->text()
+ );
+ }
+
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/valuerank/SRF_ValueRank.php b/www/wiki/extensions/SemanticResultFormats/formats/valuerank/SRF_ValueRank.php
new file mode 100644
index 00000000..eba7fd3f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/valuerank/SRF_ValueRank.php
@@ -0,0 +1,265 @@
+<?php
+
+/**
+ * Result printer that prints query results as a valuerank.
+ * In other words, it prints a list of all occuring values, with duplicates removed,
+ * together with their occurrence count.
+ *
+ * Build out of Tag Cloud Format by Jeroen De Dauw < jeroendedauw@gmail.com >
+ *
+ * For example, this result set: foo bar baz foo bar bar ohi
+ * Will be turned into
+ * * bar (3)
+ * * foo (2)
+ * * baz (1)
+ * * ohi (1)
+ *
+ * @since 1.7
+ *
+ * @licence GNU GPL v2
+ * @author DaSch < dasch@daschmedia.de >
+ * @author mwjames
+ */
+class SRFValueRank extends SMWResultPrinter {
+
+ /**
+ * @var array
+ */
+ protected $tagsHtml = [];
+
+ /**
+ * @see SMWResultPrinter::getName
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf_printername_valuerank' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @since 1.7
+ *
+ * @param SMWQueryResult $results
+ * @param $outputMode
+ *
+ * @return string
+ */
+ public function getResultText( SMWQueryResult $results, $outputMode ) {
+
+ // Template support
+ $this->hasTemplates = $this->params['template'] !== '';
+
+ // Prioritize HTML setting
+ $this->isHTML = $this->params['template'] === '';
+
+ $outputMode = SMW_OUTPUT_HTML;
+
+ return $this->getFormatOutput( $this->getValueRank( $this->getResultValues( $results, $outputMode ) ) );
+ }
+
+ /**
+ * Returns an array with the tags (keys) and the number of times they occur (values).
+ *
+ * @since 1.7
+ *
+ * @param SMWQueryResult $results
+ * @param $outputMode
+ *
+ * @return array
+ */
+ protected function getResultValues( SMWQueryResult $results, $outputMode ) {
+ $tags = [];
+
+ /**
+ * @var $row SMWResultArray Objects (pages)
+ * @var $dataValue SMWDataValue
+ *
+ * @return array
+ */
+ while ( $row = $results->getNext() ) {
+ // SMWResultArray for a sinlge property
+ for ( $i = 0, $n = count( $row ); $i < $n; $i++ ) {
+ while ( ( $dataValue = $row[$i]->getNextDataValue() ) !== false ) {
+
+ $isSubject = $row[$i]->getPrintRequest()->getMode() == SMWPrintRequest::PRINT_THIS;
+
+ // If the main object should not be included, skip it.
+ if ( $i == 0 && !$this->params['includesubject'] && $isSubject ) {
+ continue;
+ }
+
+ // Get the HTML for the tag content. Pages are linked, other stuff is just plaintext.
+ if ( $dataValue->getTypeID() == '_wpg' ) {
+ $value = $dataValue->getDataItem()->getTitle()->getText();
+ $html = $dataValue->getLongText( $outputMode, $this->getLinker( $isSubject ) );
+ } else {
+ $html = $dataValue->getShortText( $outputMode, $this->getLinker( false ) );
+ $value = $html;
+ }
+
+ if ( !array_key_exists( $value, $tags ) ) {
+ $tags[$value] = 0;
+ $this->tagsHtml[$value] = $html; // Store the HTML separetely, so sorting can be done easily.
+ }
+
+ $tags[$value]++;
+ }
+ }
+ }
+
+ foreach ( $tags as $name => $count ) {
+ if ( $count < $this->params['min'] ) {
+ unset( $tags[$name] );
+ }
+ }
+ return $tags;
+ }
+
+ /**
+ * Determine ranks
+ *
+ * @since 1.7
+ *
+ * @param array $tags
+ *
+ * @return array
+ */
+ protected function getValueRank( array $tags ) {
+ if ( count( $tags ) == 0 ) {
+ return $tags;
+ }
+
+ arsort( $tags, SORT_NUMERIC );
+
+ if ( count( $tags ) > $this->params['maxtags'] ) {
+ $tags = array_slice( $tags, 0, $this->params['maxtags'], true );
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Format the output representation
+ *
+ * @since 1.8
+ *
+ * @param array $tags
+ *
+ * @return string
+ */
+ protected function getFormatOutput( array $tags ) {
+ $htmlTags = [];
+
+ if ( $this->params['introtemplate'] !== '' && $this->params['template'] !== '' ) {
+ $htmlTags[] = "{{" . $this->params['introtemplate'] . "}}";
+ }
+
+ foreach ( $tags as $name => $size ) {
+ if ( $this->params['template'] !== '' ) {
+ $htmlTags[] = $this->addTemplateOutput( $name, $size, $rownum );
+ } else {
+ $htmlTags[] = Html::rawElement(
+ ( $this->params['liststyle'] === 'none' ? 'span' : 'li' ),
+ [ 'style' => "font-size:$size" ],
+ $this->tagsHtml[$name] . '&nbsp;(' . $size . ')'
+ );
+ }
+ }
+
+ if ( $this->params['outrotemplate'] !== '' && $this->params['template'] !== '' ) {
+ $htmlTags[] = "{{" . $this->params['outrotemplate'] . "}}";
+ }
+
+ return Html::rawElement(
+ ( $this->params['liststyle'] === 'none' ? 'div' : $this->params['liststyle'] ),
+ [ 'class' => $this->params['class'] ],
+ implode( '', $htmlTags )
+ );
+ }
+
+ /**
+ * Create a template output
+ *
+ * @since 1.8
+ *
+ * @param string $name
+ * @param integer $rank
+ * @param integer $rownum
+ *
+ * @return string
+ */
+ protected function addTemplateOutput( $name, $rank, &$rownum ) {
+ $rownum++;
+ $wikitext = $this->params['userparam'] ? "|userparam=" . $this->params['userparam'] : '';
+ $wikitext .= "|" . $name;
+ $wikitext .= "|rank=" . $rank;
+ $wikitext .= "|#=$rownum";
+ return '{{' . trim( $this->params['template'] ) . $wikitext . '}}';
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['includesubject'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf_paramdesc_includesubject',
+ ];
+
+ $params['min'] = [
+ 'type' => 'integer',
+ 'default' => 1,
+ 'message' => 'srf_paramdesc_mincount',
+ ];
+
+ $params['maxtags'] = [
+ 'type' => 'integer',
+ 'default' => 1000,
+ 'message' => 'srf_paramdesc_maxtags',
+ ];
+
+ $params['template'] = [
+ 'message' => 'srf-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params['userparam'] = [
+ 'message' => 'srf-paramdesc-userparam',
+ 'default' => '',
+ ];
+
+ $params['introtemplate'] = [
+ 'message' => 'smw-paramdesc-introtemplate',
+ 'default' => '',
+ ];
+
+ $params['outrotemplate'] = [
+ 'message' => 'smw-paramdesc-outrotemplate',
+ 'default' => '',
+ ];
+
+ $params['liststyle'] = [
+ 'message' => 'srf-paramdesc-liststyle',
+ 'default' => 'ul',
+ 'values' => [ 'ul', 'ol', 'none' ],
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_ListWidget.php b/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_ListWidget.php
new file mode 100644
index 00000000..e1e93c08
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_ListWidget.php
@@ -0,0 +1,132 @@
+<?php
+
+use SMW\Query\ResultPrinters\ListResultPrinter\ListResultBuilder;
+use SMW\Query\ResultPrinters\ResultPrinter;
+
+/**
+ * Extends the list result printer (SMW_QP_List.php) with a JavaScript
+ * navigation widget
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ *
+ * @ingroup SemanticResultFormats
+ * @file SRF_ListWidget.php
+ */
+class SRFListWidget extends ResultPrinter {
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-listwidget' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $res
+ * @param array $params
+ * @param $outputmode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+ // Initialize
+ static $statNr = 0;
+ //$this->isHTML = true;
+
+ $listType = $this->params[ 'listtype' ] === 'ordered' || $this->params[ 'listtype' ] === 'ol' ? 'ol' : 'ul';
+
+ $builder = new ListResultBuilder( $res, $this->mLinker );
+
+ $builder->set( $this->params );
+ $builder->set( [
+ 'format' => $listType,
+ 'link-first' => $this->mLinkFirst,
+ 'link-others' => $this->mLinkOthers,
+ 'show-headers' => $this->mShowHeaders,
+ ] );
+
+ // Get results from SMWListResultPrinter
+ $result = $builder->getResultText();
+
+ // Count widgets
+ $listwidgetID = 'listwidget-' . ++$statNr;
+
+ // OL/UL container items
+ $result = Html::rawElement(
+ 'div',
+ [
+ 'id' => $listwidgetID,
+ 'class' => 'listwidget-container',
+ 'style' => 'display:none; position: relative; margin-bottom:5px; margin-top:5px;'
+ ],
+ $result
+ );
+
+ // Placeholder
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // RL module
+ $resource = 'ext.srf.listwidget.' . $this->params['widget'];
+ SMWOutputs::requireResource( $resource );
+
+ // Wrap results
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-listwidget ' . htmlspecialchars( $this->params['class'] ),
+ 'data-listtype' => $listType,
+ 'data-widget' => $this->params['widget'],
+ 'data-pageitems' => $this->params['pageitems'],
+ ],
+ $processing . $result
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['class'] = [
+ 'name' => 'class',
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['listtype'] = [
+ 'name' => 'listtype',
+ 'message' => 'srf-paramdesc-listtype',
+ 'values' => [ 'unordered', 'ordered' ],
+ 'default' => 'unordered'
+ ];
+
+ $params['widget'] = [
+ 'name' => 'widget',
+ 'message' => 'srf-paramdesc-widget',
+ 'values' => [ 'alphabet', 'menu', 'pagination' ],
+ 'default' => 'alphabet'
+ ];
+
+ $params['pageitems'] = [
+ 'type' => 'integer',
+ 'name' => 'pageitems',
+ 'message' => 'srf-paramdesc-pageitems',
+ 'default' => 5,
+ ];
+
+ return $params;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_PageWidget.php b/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_PageWidget.php
new file mode 100644
index 00000000..34721849
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/SRF_PageWidget.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * Extends the SMWEmbeddedResultPrinter with a JavaScript carousel widget
+ *
+ * @since 1.8
+ *
+ * @author mwjames
+ *
+ * @ingroup SemanticResultFormats
+ * @file
+ */
+class SRFPageWidget extends SMWEmbeddedResultPrinter {
+
+ /**
+ * Get a human readable label for this printer.
+ *
+ * @return string
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-pagewidget' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getResultText
+ *
+ * @param SMWQueryResult $res
+ * @param $outputMode
+ *
+ * @return string
+ */
+ protected function getResultText( SMWQueryResult $res, $outputMode ) {
+
+ // Initialize
+ static $statNr = 0;
+
+ // Get results from SMWListResultPrinter
+ $result = parent::getResultText( $res, $outputMode );
+
+ // Count widgets
+ $widgetID = 'pagewidget-' . ++$statNr;
+
+ // Container items
+ $result = Html::rawElement(
+ 'div',
+ [
+ 'id' => $widgetID,
+ 'class' => 'pagewidget-container',
+ 'data-embedonly' => $this->params['embedonly'],
+ 'style' => 'display:none;'
+ ],
+ $result
+ );
+
+ // Placeholder
+ $processing = SRFUtils::htmlProcessingElement( $this->isHTML );
+
+ // RL module
+ SMWOutputs::requireResource( 'ext.srf.pagewidget.carousel' );
+
+ // Beautify class selector
+ $class = $this->params['class'] ? ' ' . $this->params['class'] : '';
+
+ // Wrap results
+ return Html::rawElement(
+ 'div',
+ [
+ 'class' => 'srf-pagewidget' . $class,
+ ],
+ $processing . $result
+ );
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['embedformat'] = [
+ 'message' => 'smw-paramdesc-embedformat',
+ 'default' => 'ul',
+ 'values' => [ 'ul' ],
+ ];
+
+ $params['class'] = [
+ 'message' => 'srf-paramdesc-class',
+ 'default' => '',
+ ];
+
+ $params['widget'] = [
+ 'message' => 'srf-paramdesc-widget',
+ 'default' => 'carousel',
+ 'values' => [ 'carousel' ],
+ ];
+
+ return $params;
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.css b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.css
new file mode 100644
index 00000000..3184572e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.css
@@ -0,0 +1,115 @@
+/**
+ * CSS for SRF ListNavigation module
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames and others
+ *
+ * @release: 0.1
+ */
+
+/**
+ * STYLE SHEET FOR IHWY JQUERY LISTNAV PLUGIN V 2.0, 3/2/2009
+ */
+.srf-listwidget-navigation {
+ margin:0 0 10px;
+}
+
+
+.srf-listwidget-navigation a:first-child,
+.srf-listwidget .lm-wrapper .lm-letters a:first-child {
+ border-left-width: 1px;
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+
+.srf-listwidget-navigation a:last-child,
+.srf-listwidget .lm-wrapper .lm-letters a:last-child {
+ -webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+
+.srf-listwidget-navigation .ln-letters { overflow:hidden; }
+.srf-listwidget-navigation .ln-letters a {
+ font-size:0.9em;
+ display:block;
+ float:left;
+ padding:4px 9px;
+ border:1px solid #DDD;
+ border-right:none;
+ text-decoration:none;
+}
+
+.srf-listwidget-navigation .ln-letters a.ln-last { border-right:1px solid #DDD; }
+.srf-listwidget-navigation .ln-letters a:hover,
+.srf-listwidget-navigation .ln-letters a.ln-selected { background-color:whiteSmoke; }
+.srf-listwidget-navigation .ln-letters a.ln-disabled { color:#ccc; }
+.srf-listwidget-navigation .ln-letter-count {
+ text-align:center;
+ font-size:0.8em;
+ line-height: 1;
+ margin-bottom:3px; color:#336699;
+}
+
+/**
+ * STYLE SHEET FOR IHWY JQUERY LISTMENU PLUGIN V 1.0, 3/2/2009
+ */
+.srf-listwidget .lm-wrapper { margin:0; padding:0; }
+.srf-listwidget .lm-wrapper .lm-letters { overflow:hidden; }
+.srf-listwidget * html .lm-wrapper .lm-letters { zoom:1; } /* for IE6 so that menu appears under letters */
+.srf-listwidget .lm-wrapper .lm-letters a {
+ font-size:0.9em;
+ display:block;
+ float:left;
+ padding:4px 9px;
+ border:1px solid #DDD;
+ border-right:none;
+ text-decoration:none;
+}
+.srf-listwidget .lm-wrapper .lm-letters a:hover,
+.srf-listwidget .lm-wrapper .lm-letters a.lm-selected { background-color:whiteSmoke; }
+.srf-listwidget .lm-wrapper .lm-letters a.lm-disabled { color:#ccc; }
+.srf-listwidget .lm-wrapper .lm-letters a.lm-last { border-right:1px solid #DDD; }
+.srf-listwidget .lm-wrapper .lm-letter-count {
+ text-align:center;
+ font-size:0.8em;
+ line-height:1;
+ margin-bottom:3px; color:#336699;
+}
+
+.srf-listwidget .lm-wrapper .lm-menu {
+ border:1px solid #DDD;
+ border-top:1px solid #DDD;
+ padding:15px;
+ z-index:10;
+ position:absolute;
+ margin-top:-1px;
+ background:#ffc;
+ display:none;
+}
+.srf-listwidget .lm-wrapper .lm-menu ul li { list-style-type:none; margin-bottom:5px; font-size:0.9em }
+.srf-listwidget .lm-wrapper .lm-menu ol li { margin-left:15px; }
+.srf-listwidget .lm-wrapper .lm-menu .lm-no-match { color:green; }
+.srf-listwidget .lm-wrapper .lm-menu a { text-decoration:none; }
+.srf-listwidget .lm-wrapper .lm-menu a:hover { text-decoration:underline; }
+.srf-listwidget .lm-wrapper .lm-menu .lm-submenu { overflow:hidden; }
+
+/**
+ * Pagination style sheet
+ */
+.srf-listwidget-navigation { overflow:hidden; }
+.srf-listwidget-navigation a, .ellipse {
+ font-size:0.9em;
+ display:block;
+ float:left;
+ padding:4px 9px;
+ border:1px solid #DDD;
+ border-right:none;
+ text-decoration:none;
+}
+
+.srf-listwidget-navigation a.last_link { border-right:1px solid #DDD; }
+.srf-listwidget-navigation a:hover,
+.srf-listwidget-navigation a.page_link.active_page { background-color:whiteSmoke; }
+.srf-listwidget-navigation a.ln-disabled { color:#ccc; } \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.js b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.js
new file mode 100644
index 00000000..719a87b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.listwidget.js
@@ -0,0 +1,76 @@
+/**
+ * JavaScript for SRF ListWidget module
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Listwidget format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /*global mw:true*/
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ var util = new srf.util();
+
+ ////////////////////////// PUBLIC METHODS ////////////////////////
+
+ $.fn.srfListwidget = function() {
+ var widgetID = this.find( '.listwidget-container' ).attr( 'id' ),
+ listType = this.data( 'listtype' ),
+ widget = this.data( 'widget' ),
+ pageitems = this.data( 'pageitems' ),
+ noMatch = mw.msg( 'srf-module-nomatch' );
+
+ // Update list with ID and class
+ this.find( listType ).attr( { 'id': widgetID, 'class' : widget + '-container' } );
+
+ // Navigation class
+ var navClass = widget === 'pagination' ? '.listwidget-container' : '.' + widget + '-container';
+
+ // Navigation element
+ var navigation = '<div id="' + widgetID + '-nav" class="srf-listwidget-navigation"></div>';
+ this.find( navClass ).before( navigation );
+
+ if ( widget === 'pagination' ) {
+ // Pagination widget
+ this.pajinate( {
+ items_per_page : pageitems,
+ item_container_id : '.pagination-container',
+ nav_panel_id : '#' + widgetID + '-nav'
+ } );
+
+ } else if ( widget === 'menu' ) {
+ // Alphabet menu navigation
+ this.find( listType ).listmenu( {
+ includeAll: false,
+ includeOther: true,
+ showCounts: false,
+ cols: { count:3, gutter:35 },
+ noMatchText: noMatch
+ } );
+ } else {
+ // Alphabet list navigation
+ this.find( listType ).listnav( {
+ includeAll: false,
+ includeOther: true,
+ noMatchText: noMatch
+ } );
+ }
+
+ // Release display
+ util.spinner.hide( { context: this } );
+ this.find( '.srf-listwidget-navigation' ).show();
+ this.find( '.listwidget-container' ).show();
+ };
+
+ $(document).ready( function() {
+ $( '.srf-listwidget' ).each( function() {
+ $( this ).srfListwidget();
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.css b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.css
new file mode 100644
index 00000000..1b3a2b61
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.css
@@ -0,0 +1,79 @@
+/**
+ * CSS for SRF PageWidget module
+ *
+ * @licence: GNU GPL v2 or later
+ * @author: mwjames
+ *
+ * @since: 1.8
+ *
+ * @release: 0.1
+ */
+
+ul.slidecontrols {
+ overflow: hidden;
+ margin: 0.3em 0 0 0;
+}
+
+.slidecontrols li {
+ display: inline;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.srf-pagewidget-carousel-source {
+ list-style: none;
+ font-size: 0.9em;
+ display: block;
+ width:67px;
+ clear:both;
+ padding: 4px 9px;
+ border: 1px solid #DDD;
+ text-decoration: none;
+ border-width: 1px;
+ -webkit-border-radius: 3px 3px 3px 3px;
+ -moz-border-radius: 3px 3px 3px 3px;
+ border-radius: 3px 3px 3px 3px;
+ border-right: 1px solid #DDD;
+}
+.srf-pagewidget-carousel-prev {
+ list-style: none;
+ font-size: 0.9em;
+ display: block;
+ float: left;
+ padding: 4px 9px;
+ border: 1px solid #DDD;
+ border-right: none;
+ text-decoration: none;
+ border-left-width: 1px;
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+
+.srf-pagewidget-carousel-next {
+ list-style: none;
+ font-size: 0.9em;
+ display: block;
+ float: left;
+ padding: 4px 9px;
+ border: 1px solid #DDD;
+ border-right: none;
+ text-decoration: none;
+ border-right: 1px solid #DDD;
+ webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+
+.srf-pagewidget-carousel-next:hover,
+.srf-pagewidget-carousel-prev:hover {
+ background-color: whiteSmoke;
+}
+
+.srf-pagewidget-carousel-disabled {
+ background-color: whiteSmoke;
+}
+
+.srf-pagewidget-carousel-active-slide {
+ margin: 0;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.js b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.js
new file mode 100644
index 00000000..fb99ad39
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/formats/widget/resources/ext.srf.pagewidget.carousel.js
@@ -0,0 +1,99 @@
+/**
+ * JavaScript for SRF PageWidget format
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Pagewidget format
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ var util = new srf.util();
+
+ function _moveSlide( slider, fancybox, event ){
+ var direction = null;
+
+ // Event collusion detection with fancybox, the .button will indicate an active
+ // overlay window and to avoid a conflict with both eventhandlers
+ // we will not respond to the event and bailout
+ if ( fancybox.find( '#fancybox-title' ).find( '.button' ).length > 0 ){
+ return true;
+ }
+
+ // Handle cursor keys
+ if ( event.keyCode == 37 || event.keyCode == 33 ) {
+ // Left
+ direction = 'prev';
+ } else if ( event.keyCode == 39 || event.keyCode == 34 ) {
+ // Right
+ direction = 'next';
+ }
+
+ if (direction !== null) {
+ slider.trigger( 'nextprev', { dir: direction } );
+ event.preventDefault();
+ }
+ }
+
+ ////////////////////////// IMPLEMENTATION ////////////////////////
+
+ $(document).ready( function() {
+ $( '.srf-pagewidget' ).each( function() {
+
+ var $this = $( this );
+ var container = $this.find( '.pagewidget-container' ),
+ embedonly = container.data( 'embedonly' );
+
+ // Update navigation control with class that is a direct child
+ $this.find( '.pagewidget-container > ul' ).attr( 'class', 'slider' );
+ container.find( 'ul.slider > li' ).attr( 'class', 'slide' ).css( { 'list-style': 'none' } );
+
+ // Iterate over available container objects
+ container.each( function() {
+ $( this ).carousel( {
+ namespace: 'srf-pagewidget-carousel',
+ slider: '.slider',
+ slide: '.slide'
+ } );
+ } );
+
+ // Release container
+ container.show();
+ util.spinner.hide( { context: $this } );
+
+ // Override static text with available translation
+ container.find( '.slidecontrols' ).find( 'li .srf-pagewidget-carousel-prev' ).text( mw.msg( 'srf-ui-navigation-prev' ) );
+ container.find( '.slidecontrols' ).find( 'li .srf-pagewidget-carousel-next' ).text( mw.msg( 'srf-ui-navigation-next' ) );
+
+ // Switch positions of the navigation control
+ container.find( '.slidecontrols' ).find( 'li .srf-pagewidget-carousel-next' ).before( container.find( '.slidecontrols' ).find( 'li .srf-pagewidget-carousel-prev' ) );
+
+ // If embedonly is undefined it means the first <a> element contains the link
+ // to the embedded source page
+ if ( embedonly === undefined ) {
+ container.find( 'ul.slider > li > a:first-child' )
+ .addClass( 'srf-pagewidget-carousel-source' )
+ .text( mw.msg( 'srf-ui-common-label-source' ) );
+ }
+
+ // Hide TOC as it will disturb the embedded display behavior
+ container.find ( '.toc' ).css ( { 'display': 'none' } );
+
+ // Current slider instance
+ var slider = $( '#' + container.find( '.slider' ).attr( 'id' ) );
+
+ // Find the fancybox instance for possible event collusion detection
+ var fancybox = $( '#fancybox-wrap' );
+
+ // Keyboard event listener which should work in all browsers
+ $( document.documentElement ).keyup( function( event ){
+ _moveSlide( slider, fancybox, event );
+ } );
+ } );
+ } );
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/af.json b/www/wiki/extensions/SemanticResultFormats/i18n/af.json
new file mode 100644
index 00000000..f5195a11
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/af.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "SPQRobin"
+ ]
+ },
+ "srfc_gotomonth": "Gaan na maand",
+ "srf_icalendar_link": "iKalender"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/am.json b/www/wiki/extensions/SemanticResultFormats/i18n/am.json
new file mode 100644
index 00000000..ab369e2d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/am.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Codex Sinaiticus"
+ ]
+ },
+ "srfc_today": "ዛሬ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ar.json b/www/wiki/extensions/SemanticResultFormats/i18n/ar.json
new file mode 100644
index 00000000..7961fa47
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ar.json
@@ -0,0 +1,348 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meno25",
+ "OsamaK",
+ "روخو",
+ "ديÙيد"
+ ]
+ },
+ "srf-desc": "صيغ نتائج إضاÙية لاستعلامات ميدياويكي الدلالية",
+ "prefs-srf": "صيغ النتيجة الدلالية",
+ "srf-prefs-intro-text": "لقد قمت بتثبيت ملحق صيغ النتائج الدلالية، الرجاء زيارة صÙحة المساعدة [https://www.semantic-mediawiki.org/wiki/Help:Result_formats صيغ النتائج] للحصول على مساعدة إضاÙية Ùيما يتعلق بتÙضيلات المستخدم.",
+ "prefs-srf-eventcalendar-options": "خيارات تقويم الحدث",
+ "srf-prefs-eventcalendar-options-update-default": "تمكين [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates التحديثات التلقائية] لأحداث التقويم أثناء تحديث الصÙحة",
+ "srf-prefs-eventcalendar-options-paneview-default": "تمكين عرض الجزء بشكل اÙتراضي",
+ "prefs-srf-datatables-options": "خيارات جداول البيانات",
+ "srf-prefs-datatables-options-update-default": "تمكين [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates التحديثات التلقائية] لمحتوى الجدول أثناء تحديث الصÙحة",
+ "srf-prefs-datatables-options-cache-default": "تمكين [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage التخزين المحلي] لتحسين وقت الاستجابة",
+ "srf-module-loading": "جار٠التحميل...",
+ "srf-paramdesc-layout": "التصميم المتاح",
+ "srf-paramdesc-height": "الارتÙاع",
+ "srf-paramdesc-width": "العرض",
+ "srf-paramdesc-class": "حدد Ùئة ورقة أنماط متتالية إضاÙية",
+ "srf-module-nomatch": "لم يتم العثور على تطابق",
+ "srf-paramdesc-charttype": "نوع المخطط المتاح",
+ "srf-navigation-previous": "السابق",
+ "srf-ui-navigation-prev": "السابق",
+ "srf-ui-navigation-next": "التالي",
+ "srf-ui-common-label-source": "المصدر",
+ "srf-ui-common-label-datasource": "مصدر البيانات",
+ "srf-ui-common-label-ajax-error": "أبلغ الخادم عن Ùشل الاتصال بهذا $1; تÙرجَى محاولة تحديث الصÙحة أو استشارة هذا $2.",
+ "srf-ui-common-label-request-object": "طلب كائن",
+ "srf-ui-common-label-help-section": "قسم المساعدة",
+ "srf-ui-tooltip-title-options": "خيارات",
+ "srf-ui-tooltip-title-scope": "نطاق",
+ "srf-ui-tooltip-title-legend": "عنوان تÙسيري",
+ "srf-ui-tooltip-title-filter": "مرشح",
+ "srf-ui-common-label-refresh": "تحديث",
+ "srf-ui-common-label-parameters": "وسائط",
+ "srf-ui-common-label-query": "استعلام",
+ "srf-ui-common-label-paneview": "عرض جزء",
+ "srf-ui-common-label-daterange": "النطاق الزمني",
+ "srf-ui-widgets-label-parameter-limit": "حد الوسيط",
+ "srf-error-option-mix": "الخيار ($1) غير متوÙر",
+ "srf-error-option-link-all": "الخيار ($1) يتطلب الوسيط \"وصلة\" ليتم تعيين \"الجميع\"",
+ "srf-error-missing-layout": "لا يمكن عرض المخطط أو الرسم البياني نظرا لأن التخطيط Ù…Ùقود.",
+ "srf-error-jqplot-bubble-data-length": "لا يمكن عرض المخطط أو الرسم البياني بسبب عدم توÙر البيانات.",
+ "srf-error-jqplot-stackseries-data-length": "لا يمكن عرض المخطط أو الرسم البياني لأنه ليس كل شريط أو سطر له Ù†Ùس المقدار من العناصر.",
+ "srf-warn-empy-chart": "المخطط أو الرسم البياني Ùارغ بسبب Ùقدان البيانات",
+ "srf-paramdesc-color": "اللون لوضع علامة على إدخالات التقويم",
+ "srfc_previousmonth": "الشهر السابق",
+ "srfc_nextmonth": "الشهر التالي",
+ "srfc_today": "اليوم",
+ "srfc_gotomonth": "اذهب إلى شهر",
+ "srf_printername_calendar": "نتيجة شهرية",
+ "srf_paramdesc_calendarlang": "رمز اللغة الذي لعرض التقويم",
+ "srf_paramdesc_calendarcolors": "اللون المعروض لكل خاصية تاريخ (مثال: \"Start date=>أخضر، تاريخ الانتهاء=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "الشهر: تتم تهيئة عرض التقويم مع (الإعدادات الاÙتراضية للشهر الحالي)",
+ "srf-paramdesc-calendar-startyear": "السنة: تتم تهيئة عرض التقويم مع (الإعدادات الاÙتراضية للسنة الحالية)",
+ "srf_vcard_link": "ÙÙŠ كارد",
+ "srf_printername_vcard": "تصدير vCard",
+ "srf_icalendar_link": "آي كالندر",
+ "srf_printername_icalendar": "تصدير iCalendar",
+ "srf_paramdesc_icalendartitle": "عنوان مل٠النتيجة",
+ "srf_paramdesc_icalendardescription": "وص٠مل٠النتيجة",
+ "srf_bibtex_link": "بب تكس",
+ "srf_printername_bibtex": "تصدير BibTeX",
+ "srf_outline_novalue": "لا قيم",
+ "srf_printername_outline": "إطار",
+ "srf_paramdesc_outlineproperties": "قائمة الخصائص ليتم عرضها كعناوين عامة، Ù…Ùصولة بواسطة Ùاصلات",
+ "srf_printername_sum": "مجموع الأرقام",
+ "srf_printername_average": "متوسط الأرقام",
+ "srf_printername_max": "الرقم الأقصى",
+ "srf_printername_min": "الرقم الأدنى",
+ "srf_paramdesc_limit": "أقصى عدد من الصÙحات للاستعلام",
+ "srf_printername_product": "منتج الأرقام",
+ "srf_printername_median": "متوسط ​​الأرقام",
+ "srf-paramdesc-default": "القيمة الاÙتراضية التي سيتم عرضها عند عدم وجود نتائج رقمية",
+ "srf_printername_earliest": "أقرب وقت",
+ "srf_printername_latest": "آخر مرة",
+ "srf_printername_timeline": "خط زمني",
+ "srf_printername_eventline": "خط الأحداث",
+ "srf_paramdesc_timelinebands": "يعر٠أي الÙرق يتم عرضها ÙÙŠ هذه النتيجة.",
+ "srf_paramdesc_timelineposition": "يعر٠أين يركز الخط الزمني ابتداء.",
+ "srf_paramdesc_timelinestart": "اسم خاصية تستخدم لتعري٠نقطة أول مرة",
+ "srf_paramdesc_timelineend": "اسم خاصية تستخدم لتعري٠نقطة ثاني مرة",
+ "srf_paramdesc_timelinesize": "ارتÙاع الخط الزمني",
+ "srf-timeline-allresults": "مزيد من النتائج لهذا الاستعلام.",
+ "srf-timeline-nojs": "تحتاج إلى تمكين جاÙا سكريبت لعرض الجدول الزمني التÙاعلي.",
+ "srf_paramdesc_views": "عمليات الرؤية للعرض",
+ "srf_paramdesc_facets": "مجموعة الخصائص للعرض لكل صÙحة",
+ "srf_paramdesc_lens": "اسم القالب لعرض خصائص الصÙحة به",
+ "srf_printername_googlebar": "رسم جوجل بالأعمدة",
+ "srf_printername_googlepie": "رسم جوجل بالÙطيرة",
+ "srf-printername-jqplotchart": "مخطط جبلوت",
+ "srf-printername-jqplotseries": "سلسلة جبلوت",
+ "srf_paramdesc_chartheight": "حدد الارتÙاع (بالبكسل) لمخطط أو رسم بياني",
+ "srf_paramdesc_chartwidth": "حدد عرض مخطط أو رسم بياني (بالبكسل أو النسبة المئوية)",
+ "srf_paramdesc_charttitle": "عنوان الرسم البياني",
+ "srf_paramdesc_barcolor": "حدد ألوان المخطط",
+ "srf_paramdesc_bardirection": "حدد اتجاه المخطط",
+ "srf-paramdesc-direction": "حدد اتجاه المخطط أو الرسم البياني",
+ "srf_paramdesc_barnumbersaxislabel": "التسمية لمحور الأرقام",
+ "srf-paramdesc-labelaxislabel": "التسمية لمحور التسمية",
+ "srf-paramdesc-ticklabels": "تمكين عرض تسميات العلامات",
+ "srf-paramdesc-minvalue": "القيمة الدنيا التي تظهر على المحور الصادي",
+ "srf-paramdesc-pointlabels": "عرض نقاط البيانات داخل المخطط",
+ "srf-paramdesc-chartlegend": "موضع عالنوان التÙسيري للرسم البياني",
+ "srf-paramdesc-datalabels": "تسميات بيانات الرسم البياني/المخطط",
+ "srf-paramdesc-charttext": "نص مخطط وصÙÙŠ",
+ "srf-paramdesc-chartclass": "Ùئة CSS إضاÙية",
+ "srf-paramdesc-renderer": "حدد عارض رسم بياني/مخطط",
+ "srf-paramdesc-filling": "خيار التعبئة الÙردية",
+ "srf-paramdesc-theme": "حدد موضوع شبكة",
+ "srf-paramdesc-chartcolor": "تعيين ألوان الرسم البياني الÙردية",
+ "srf-paramdesc-colorscheme": "حدد مخطط ألوان",
+ "srf-paramdesc-valueformat": "حدد قاعدة التنسيق للقيم",
+ "srf-paramdesc-highlighter": "عرض تمييز نقطة البيانات",
+ "srf-paramdesc-smoothlines": "تطبيق خوارزمية التمهيد على المخططات الخطية",
+ "srf-paramdesc-stackseries": "عرض المخطط كما سلسلة مكدسة",
+ "srf-paramdesc-seriesgroup": "حدد تجميع المجموعات",
+ "srf-paramdesc-serieslabel": "حدد تسمية السلسلة",
+ "srf-paramdesc-grouplabel": "حدد تسمية المجموعة",
+ "srf-paramdesc-chartcursor": "خيار عرض مؤشر الرسم البياني",
+ "srf-paramdesc-trendline": "تمكين عرض ÙÙŠ وقت واحد للرسم البياني وخط اتجاهه",
+ "srf-paramdesc-gridview": "عرض الرسم البياني ومجموعات البيانات ÙÙŠ وقت واحد، القيم المسموح بها: \"لا شيء\" Ùˆ\"علامات التبويب\"ØŒ الاÙتراضي: \"لا شيء\"",
+ "srf-paramdesc-paneview": "حدد موضع الجزء الذي يحتوي على مخطط سطر صغي،. القيم المسموح بها: \"أسÙÙ„\" Ùˆ\"أعلى\" Ùˆ\"لا شيء\"ØŒ الاÙتراضي: \"أسÙÙ„\"",
+ "srf-paramdesc-infotext": "عرض معلومات إضاÙية على علامة التبويب معلومات المقابلة",
+ "srf-paramdesc-clicktarget": "حدد صÙحة أو سلسلة استعلام كهد٠عند النقر على تاريخ التقويم.",
+ "srf-ui-gridview-label-item": "عنصر البيانات",
+ "srf-ui-gridview-label-value": "قيمة البيانات",
+ "srf-ui-gridview-label-series": "سلسلة البيانات",
+ "srf-ui-gridview-label-chart-tab": "رسم بياني",
+ "srf-ui-gridview-label-data-tab": "بيانات",
+ "srf-ui-gridview-label-info-tab": "معلومات",
+ "srf_printername_gallery": "معرض",
+ "srf_paramdesc_perrow": "كمية الصور لكل صÙ",
+ "srf_paramdesc_widths": "عرض الصور",
+ "srf_paramdesc_heights": "ارتÙاع الصور",
+ "srf_paramdesc_autocaptions": "استخدم اسم المل٠كتسمية توضيحية عند عدم توÙر أي شيء",
+ "srf_paramdesc_fileextensions": "عند استخدام اسم المل٠كتسمية توضيحية، اعرض أيضا امتداد الملÙ",
+ "srf_paramdesc_captionproperty": "اسم الخاصية الدلالية الموجودة ÙÙŠ الصÙحات التي تم الاستعلام عنها لاستخدامها كتسمية توضيحية",
+ "srf_paramdesc_imageproperty": "اسم الخاصية الدلالية ÙÙŠ الصÙحات التي تم الاستعلام عنها والتي تشير إلى الصور المراد استخدامها، عند الضبط، لن يتم عرض Ù†Ùس الصÙحات التي تم الاستعلام عنها كصور",
+ "srf-paramdesc-redirects": "اسم الخاصية الدلالية الموجودة ÙÙŠ الصÙحات التي تم الاستعلام عنها والتي تحتوي على هد٠تحويلة",
+ "srf-paramdesc-navigation": "تصميم مراقبة الملاحة",
+ "srf-paramdesc-overlay": "تمكين تراكب الصور",
+ "srf-gallery-navigation-previous": "السابق",
+ "srf-gallery-navigation-next": "التالي",
+ "srf-gallery-overlay-count": "الصورة $1 من $2",
+ "srf-gallery-image-url-error": "لم يتم العثور على الصورة.",
+ "srf_printername_tagcloud": "وسم سحابة",
+ "srf_paramdesc_includesubject": "ينبغي إدراج أسماء الموضوعات Ù†Ùسها",
+ "srf_paramdesc_increase": "كيÙية زيادة حجم العلامات",
+ "srf_paramdesc_tagorder": "ترتيب العلامات",
+ "srf_paramdesc_mincount": "الحد الأدنى للمرات التي تحتاج Ùيها القيمة إلى أن يتم إدراجها",
+ "srf_paramdesc_minsize": "حجم أصغر العلامات ÙÙŠ المئة",
+ "srf_paramdesc_maxsize": "حجم أكبر العلامات ÙÙŠ المئة",
+ "srf_paramdesc_maxtags": "الحد الأقصى لعدد العلامات ÙÙŠ السحابة",
+ "srf-paramdesc-excludetags": "استبعاد العلامات (المحدد: \";\")",
+ "srf_printername_valuerank": "قيمة الترتيب",
+ "srf_printername_array": "نسق",
+ "srf_paramdesc_pagetitle": "ما إذا كان سيتم عرض عناوين الصÙحات كإدخالات نتيجة أم تركها",
+ "srf_paramdesc_hidegaps": "سواء كانت الطباعة المطلوبة، ولكن قيم سجل وخواص غير متوÙرة Ù…Ùصولة بÙواصل أو تركها",
+ "srf_paramdesc_arrayname": "إذا تم إعطاء Ùˆ تمديد مجموعة مصÙÙˆÙØ© سيؤدي هذا إلى إنشاء مصÙÙˆÙØ© بالاسم المحدد (لا يوجد أي إخراج مرئي بعدئذ)",
+ "srf_paramdesc_propsep": "Ùاصل بين الخصائص المطلوبة",
+ "srf_paramdesc_manysep": "Ùاصل بين العديد من قيم الخاصية القيمة الملكية",
+ "srf_paramdesc_recordsep": "Ùاصل بين قيم خصائص السجل",
+ "srf_paramdesc_headersep": "Ùاصل بين اسم الخاصية والقيمة إذا تم تعيين \"الرؤوس\" إلى \"إظهار\" أو \"عادي\"",
+ "srf_printername_hash": "تجزئة",
+ "srf_paramdesc_hashname": "إذا تم توÙيرها وإمكانية تمديد جداول التجزئة Ùسيؤدي هذا إلى إنشاء مزيج بالاسم المحدد (لا يوجد إخراج مرئي بعدئذ)",
+ "srf-printername-graph": "رسم بياني",
+ "srf-paramdesc-graph-relation": "يحدد ما إذا كانت الموضوعات أو خصائص الاسم آباء أم أطÙال",
+ "srf-paramdesc-graph-nameprop": "لتعيين الخاصية التي سيتم استخدامها كموضوع بدلا من الموضوع الÙعلي: أي اسم الصÙحة",
+ "srf-paramdesc-graph-nodeshape": "تعيين شكل كل عقدة على الرسم البياني",
+ "srf-paramdesc-graphname": "تعيين عنوان الرسم البياني",
+ "srf-paramdesc-graphsize": "تعيين حجم الرسم البياني بالبكسل",
+ "srf-paramdesc-graphlegend": "تحديد ما إذا كان يجب عرض العنوان التÙسيري للرسم البياني",
+ "srf-paramdesc-graphlabel": "تعيين تسمية الرسم البياني",
+ "srf-paramdesc-rankdir": "تعيين اتجاه الأسهم",
+ "srf-paramdesc-graphlink": "تحديد ما إذا كان يجب ربط العقد بصÙحات الويكي الخاصة بها",
+ "srf-paramdesc-graphcolor": "تعيين لون الرسم البياني",
+ "srf-paramdesc-graph-wwl": "تعيين حد التÙا٠الكلمات (بعدد الأحرÙ)",
+ "srf-paramdesc-clustercolor": "تعيين الألوان المربعات العنقودية",
+ "srf-paramdesc-highlight": "تعيين العقدة ليتم تمييزها",
+ "srf-paramdesc-highlightcolor": "تعيين لون الخط للعقدة المميزة",
+ "srf-paramdesc-redlinkcolor": "تعيين لون الخط للروابط الحمراء",
+ "srf-paramdesc-processcategory": "تعيين تصني٠الويكي الذي يجمع خطوات العملية",
+ "srf-paramdesc-showroles": "عرض الأدوار المناظرة ÙÙŠ الرسم البياني",
+ "srf-paramdesc-showstatus": "تحديد ما إذا كان يجب عرض حالة خطوة العملية",
+ "srf-paramdesc-showresources": "عرض الموارد المقابلة ÙÙŠ الرسم البياني",
+ "srf-paramdesc-showdiscussion": "تحديد ما إذا كان ينبغي عرض مناقشة",
+ "srf-paramdesc-showredlinks": "تحديد ما إذا كان يجب تحديد الروابط الحمراء وتسليط الضوء عليها",
+ "srf-paramdesc-showcompound": "يحدد إذا كان يجب تسليط الضوء العقد المركبة: أي العمليات الÙرعية",
+ "srf-paramdesc-debug": "تحديد ما إذا كان يجب عرض رمز الرسم البياني للعملية قبل وضع العلامات",
+ "srf-paramdesc-graphvalidation": "يعرض خطوات العملية باللون الأحمر والتي ليس لها دور معين",
+ "srf-printername-datatables": "جداول البيانات",
+ "srf-ui-datatables-label-conditions": "الشروط",
+ "srf-ui-datatables-label-parameters": "وسائط",
+ "srf-ui-datatables-label-filters": "مرشحات وبحث العمود",
+ "srf-ui-datatables-label-information": "معلومات",
+ "srf-ui-datatables-panel-disclaimer": "يمكن تغيير الوسائط والشروط، ولكن أي تغيير مؤقت ويتم التخلي عنه بعد تحديث الصÙحة.",
+ "srf-ui-datatables-label-update-success": "تم تحديث الجدول بنجاح",
+ "srf-ui-datatables-label-update-error": "Ùشل تحديث الجدول.",
+ "srf-ui-datatables-label-placeholder-column-search": "بحث...",
+ "srf-ui-datatables-label-content-cache": "تم اشتقاق المحتوى من ذاكرة التخزين المؤقت المحلية.",
+ "srf-ui-datatables-label-content-server": "تم اشتقاق المحتوى من الخادم.",
+ "srf-ui-datatables-label-multiselect-column-header": "الأعمدة المتاحة",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "إعدادات المرشح",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "الأعمدة مرئية",
+ "srf-ui-datatables-label-sEmptyTable": "لا تتوÙر بيانات ÙÙŠ الجدول",
+ "srf-ui-datatables-label-sInfo": "إظهار _START_ ل_END_ من _TOTAL_ إدخالات",
+ "srf-ui-datatables-label-sInfoEmpty": "عرض 0 إلى 0 من 0 إدخالات",
+ "srf-ui-datatables-label-sInfoFiltered": "(تمت تصÙيتها من _MAX_ إجمالي الإدخالات)",
+ "srf-ui-datatables-label-sInfoThousands": "،",
+ "srf-ui-datatables-label-sLengthMenu": "إظهار إدخالات_MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "جار٠التحميل...",
+ "srf-ui-datatables-label-sProcessing": "تجري المعالجة...",
+ "srf-ui-datatables-label-sSearch": "بحث:",
+ "srf-ui-datatables-label-sZeroRecords": "لم يتم العثور على سجلات مطابقة",
+ "srf-ui-datatables-label-oPaginate-sFirst": "الأولى",
+ "srf-ui-datatables-label-oPaginate-sLast": "الأخيرة",
+ "srf-ui-datatables-label-oPaginate-sNext": "التالي",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "السابق",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": تÙعيل Ù„Ùرز العمود تصاعديا",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": تÙعيل Ù„Ùرز العمود تنازليا",
+ "srf-printername-tree": "زود بعمود",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "لم يتم إعطاء أية خاصية رئيسية، لا يمكن بناء الشجرة بدون خاصية رئيسية محددة.",
+ "srf-tree-rootinvalid": "$1 ليس عنوان صÙحة صالحا.",
+ "srf-tree-circledetected": "تم اكتشا٠الدائرة عند محاولة إدراج $1 ÙÙŠ الشجرة.",
+ "srf-paramdesc-tree-parent": "الخاصية التي تحتوي على الصÙحة الأم",
+ "srf-paramdesc-tree-root": "صÙحة جذر الشجرة",
+ "srf-paramdesc-tree-startlevel": "مستوى بداية الشجرة، على سبيل المثال لدمجها ÙÙŠ شجرة أخرى",
+ "srf-printername-slideshow": "عرض الشرائح",
+ "srf-paramdesc-delay": "التأخير بين الشرائح بالثواني",
+ "srf-paramdesc-navigation-controls": "إظهار عناصر تحكم التنقل أم لا",
+ "srf-paramdesc-effect": "التأثير لاستخدامه ÙÙŠ التبديل من شريحة لشريحة",
+ "srf-printername-filtered": "مصÙÙ‰",
+ "srf-paramdesc-filtered-views": "الآراء التي يجب أن تكون متاحة ÙÙŠ عرض النتيجة.",
+ "srf-paramdesc-filtered-filter-position": "موق٠المرشحات Ùيما يتعلق بالآراء، القيم المسموح بها: \"أعلى\"ØŒ \"أسÙÙ„\"ØŒ الاÙتراضي: \"أعلى\".",
+ "srf-paramdesc-filtered-list-type": "نوع القائمة، القيم المسموح بها: \"ul\"ØŒ \"ol\"ØŒ \"قائمة\"ØŒ الاÙتراضي: \"قائمة\".",
+ "srf-paramdesc-filtered-list-template": "القالب الذي سيتم استخدامه لتنسيق إدخالات القائمة.",
+ "srf-paramdesc-filtered-list-named-args": "حدد عمدة العدد المركب التي تم تمريرها إلى القالب.",
+ "srf-paramdesc-filtered-list-introtemplate": "اسم القالب للعرض قبل نتائج الاستعلام، إذا كان هناك أي منها.",
+ "srf-paramdesc-filtered-list-outrotemplate": "اسم القالب للعرض بعد نتائج الاستعلام، إذا كان هناك أي منها.",
+ "srf-paramdesc-filtered-calendar-start": "النسخة المطبوعة التي تحتوي على تاريخ بدء الحدث",
+ "srf-paramdesc-filtered-calendar-end": "النسخة المطبوعة التي تحتوي على تاريخ انتهاء الحدث",
+ "srf-paramdesc-filtered-calendar-title": "النسخة المطبوعة التي تحتوي على عنوان الحدث، لا يمكن استخدامها مع قالب العنوان.",
+ "srf-paramdesc-filtered-calendar-title-template": "قالب ÙŠÙستخدَم لتنسيق عنوان الحدث ÙÙŠ التقويم",
+ "srf-paramdesc-filtered-map-position": "النسخة المطبوعة التي تحتوي على الموقع الجغراÙÙŠ.",
+ "srf-paramdesc-filtered-map-icon": "النسخة المطبوعة التي تقرر رمز الخريطة لاستخدامه.",
+ "srf-paramdesc-filtered-map-icons": "خريطة القيم للأيقونات التي سيتم استخدامها لهذه القيم على الخريطة.",
+ "srf-paramdesc-filtered-map-height": "ارتÙاع الخريطة.",
+ "srf-paramdesc-filtered-map-zoom": "مستوى التكبير عند تحميل الخريطة، قد يتم تغيير هذا من قبل المستخدم، <br>راجع: <i>عرض الخريطة بأقل تكبير</i> و<i>عرض الخريطة بأقصى تكبير</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "الحد الأدنى لمستوى تكبير الخريطة",
+ "srf-paramdesc-filtered-map-max-zoom": "الحد الأدنى لمستوى تكبير الخريطة القابل للاختيار",
+ "srf-paramdesc-filtered-map-marker-cluster": "تشغيل تصني٠علامة أو إيقا٠تشغيله.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "الحد الأقصى لمستوى التكبير الذي لا تزال علامات الخريطة Ùيه متÙاوتة، العلامات Ùوق هذا المستوى دائما غير عنقودية.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "الحد الأقصى لنص٠القطر الذي سيغطيه العنقود من العلامة المركزية (بالبكسل)ØŒ الاÙتراضي 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "عند تمكين نقر العنقود سو٠يتم التكبير إلى حدوده.",
+ "srf-filtered-selectorlabel-list": "قائمة",
+ "srf-filtered-selectorlabel-table": "جدول",
+ "srf-filtered-selectorlabel-calendar": "التقويم",
+ "srf-filtered-selectorlabel-map": "خريطة",
+ "srf-filtered-noscript-error": "لا يمكن عرض النتائج نظرا لعدم تمكين جاÙا سكريبت; انتقل إلى $1.",
+ "srf-filtered-noscript-link-caption": "النتائج ÙÙŠ شكل جدول",
+ "srf-filtered-map-provider-missing-error": "لم يتم تحديد موÙر الخريطة للعرض \"الخريطة\".",
+ "srf-filtered-value-filter-and": "Ùˆ",
+ "srf-filtered-value-filter-or": "أو",
+ "srf-filtered-value-filter-placeholder": "حدد قيمة مرشح",
+ "srf-printername-d3chart": "رسم بياني D3",
+ "srf-printername-timeseries": "مخطط الأحداث",
+ "srf-paramdesc-group": "سلسلة مجمعة حسب",
+ "srf-paramdesc-zoom": "تمكين التكبير",
+ "srf-paramdesc-datatable": "تمكين جدول بيانات",
+ "srf-timeseries-zoom-out-of-range": "لم ينتج نطاق التكبير أية بيانات كاÙية",
+ "srf-printername-sparkline": "مخطط خط المؤشر",
+ "srf-printername-listwidget": "أدة القائمة",
+ "srf-paramdesc-listtype": "حدد نوع القائمة",
+ "srf-paramdesc-widget": "الأداة المتاحة",
+ "srf-paramdesc-pageitems": "عناصر لكل صÙحة",
+ "srf-printername-eventcalendar": "تقويم الحدث",
+ "srf-paramdesc-calendarfirstday": "اليوم الذي يبدأ به كل أسبوع",
+ "srf-paramdesc-calendardefaultview": "العرض الأولي عند تحميل التقويم",
+ "srf-paramdesc-calendarstart": "بدء التقويم الأولي (قيم التاريخ أو التاريخ والوقت)",
+ "srf-paramdesc-calendarlegend": "تحديد موضع الأسطر وخيارات التصÙية المعينة",
+ "srf-paramdesc-dayview": "تمكين عرض اليوم بالنقر على رقم اليوم",
+ "srf-ui-eventcalendar-label-today": "اليوم",
+ "srf-ui-eventcalendar-label-month": "شهر",
+ "srf-ui-eventcalendar-label-week": "أسبوع",
+ "srf-ui-eventcalendar-label-day": "يوم",
+ "srf-ui-eventcalendar-label-listmonth": "الشهر (قائمة)",
+ "srf-ui-eventcalendar-label-listweek": "الأسبوع (قائمة)",
+ "srf-ui-eventcalendar-label-listday": "يوم (قائمة)",
+ "srf-ui-eventcalendar-label-allday": "طوال اليوم",
+ "srf-ui-eventcalendar-label-update-success": "نجح تحديث تقويم الحدث.",
+ "srf-ui-eventcalendar-label-update-error": "Ùشل تحديث تقويم الحدث.",
+ "srf-ui-eventcalendar-click-popup": "هل تريد إنشاء حدث؟",
+ "srf-printername-dygraphs": "الرسم البياني ديغراÙس",
+ "srf-paramdesc-datasource": "المصدر من حيث يمكن الوصول إلى البيانات، القيم المسموح بها: \"ملÙ\" Ùˆ\"صÙ\" Ùˆ\"مسار\"ØŒ الاÙتراضي: \"ملÙ\"",
+ "srf-paramdesc-errorbar": "شريط الخطأ المطلوب استخدامه، القيم المسموح بها: \"الكسر\" (Ùترات الثقة للقيم) Ùˆ\"سيغما\" (الانحرا٠المعياري للقيم) Ùˆ\"النطاق\" (نطاقات القيم المخصصة)",
+ "srf-paramdesc-movingaverage": "عرض المتوسط ​​خلال عدد من الأيام (صÙر لن يشير إلى متوسط ​​متحرك)",
+ "srf-paramdesc-yaxislabel": "الوص٠الذي يظهر على المحور الصادي",
+ "srf-paramdesc-xaxislabel": "الوص٠الذي يظهر على المحور السيني",
+ "srf-paramdesc-unit": "وحدة",
+ "srf-printername-pagewidget": "أداة الصÙحة",
+ "srf-printername-incoming": "الخصائص الواردة",
+ "srf-paramdesc-count": "يحدد ما إذا كان يجب احتساب عدد الخصائص الواردة",
+ "srf-paramdesc-min": "الحد الأدنى أو قيمة العتبة",
+ "srf-paramdesc-excludeproperty": "استبعاد الخاصية من مجموعة النتائج",
+ "srf-printername-media": "مشغل الوسائط",
+ "srf-paramdesc-mediainspector": "يعرض معلومات تÙصيلية حول عنصر وسائط محدد",
+ "srf-ui-mediaplayer-label-previous": "السابق",
+ "srf-ui-mediaplayer-label-play": "تشغيل",
+ "srf-ui-mediaplayer-label-pause": "إيقا٠مؤقت",
+ "srf-ui-mediaplayer-label-next": "التالي",
+ "srf-ui-mediaplayer-label-stop": "إيقاÙ",
+ "srf-ui-mediaplayer-label-mute": "كتم الصوت",
+ "srf-ui-mediaplayer-label-unmute": "تنشيط الصوت",
+ "srf-ui-mediaplayer-label-volume-max": "الصوت الأقصى",
+ "srf-ui-mediaplayer-label-shuffle": "خلط",
+ "srf-ui-mediaplayer-label-shuffle-off": "تهرب",
+ "srf-ui-mediaplayer-label-repeat": "تكرار",
+ "srf-ui-mediaplayer-label-repeat-off": "كرر",
+ "srf-ui-mediaplayer-label-full-screen": "ملء الشاشة",
+ "srf-ui-mediaplayer-label-restore-screen": "استعادة الشاشة",
+ "srf-spreadsheet-link": "جدول ممتد",
+ "srf-paramdesc-spreadsheet-filename": "اسم مل٠لتنزيل مل٠جدول البيانات المنشأ",
+ "srf-paramdesc-spreadsheet-fileformat": "التنسيق الذي سيتم إنتاجه لمل٠جدول البيانات، القيم المسموح بها: xlsx Ùˆxls Ùˆods ÙˆcsvØŒ الاÙتراضي: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "اسم مل٠جدول ممتد من نطاق ''ملÙ'' المستخدمة لتنسيق المل٠المنشأ",
+ "srf-paramdesc-icalendar-timezone": "قائمة Ù…Ùصولة بÙواصل بالمناطق الزمنية",
+ "srf-paramdesc-gantt-diagramtitle": "اسم المخطط",
+ "srf-paramdesc-gantt-diagramtheme": "موضوع الرسم البياني",
+ "srf-paramdesc-gantt-axisformat": "المحور السيني: صيغة التاريخ",
+ "srf-paramdesc-gantt-sortkey": "Ù…Ùتاح Ù„Ùرز الأقسام والمهام",
+ "srf-paramdesc-gantt-titletopmargin": "الهامش العلوي من عنوان المخطط",
+ "srf-paramdesc-gantt-barheight": "ارتÙاع أشرطة المهام",
+ "srf-paramdesc-gantt-leftpadding": "عرض عنوان القسم",
+ "srf-paramdesc-gantt-bargap": "المساÙØ© العمودية لشريط المهام من الهامش",
+ "srf-error-gantt-mapping-assignment": "تعيين خاطئ للقيم المعينة ÙÙŠ '''$1'''",
+ "srf-error-gantt-mapping-keywords": "المÙتاح المستخدم ÙÙŠ وسيط التعيين غير معتمد",
+ "srf-error-gantt-theme": "'''السمة''' التي اخترتها غير مدعومة",
+ "srf-error-gantt-sortkey": "'''Ù…Ùتاح الÙرز''' الذي اخترته غير مدعوم",
+ "srf-error-gantt-mermaid-not-installed": "امتداد Mermaid يحتاج إلى تثبيت.",
+ "srf-printername-gantt": "جانت",
+ "srf-paramdesc-nodelabel": "استخدام تسمية عقدة الرسم البياني، القيم المسموح بها: عنوان العرض."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/arc.json b/www/wiki/extensions/SemanticResultFormats/i18n/arc.json
new file mode 100644
index 00000000..dec5d71d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/arc.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Basharh"
+ ]
+ },
+ "srf-navigation-previous": "Ü•Ü©Ü•Ü¡",
+ "srf-ui-navigation-next": "ܕܒܬܪ",
+ "srfc_previousmonth": "ÜÜªÜšÜ Ü•Ü©Ü•Ü¡",
+ "srfc_nextmonth": "ÜÜªÜšÜ Ü•Ü’Ü¬Üª",
+ "srfc_today": "ÜܘܡܢÜ",
+ "srfc_gotomonth": "ܙܠ Ü ÜܪܚÜ",
+ "srf_printername_calendar": "Ü¦Ü Ü›Ü ÜܪܚÜÜ",
+ "srf_printername_max": "Ü¡Ü¬ÜšÜ Ü¥Ü ÜÜ Ü•Ü¡Ü¢ÜÜ¢Ü",
+ "srf_printername_min": "Ü¡Ü¬ÜšÜ Ü¬ÜšÜ¬ÜÜ Ü•Ü¡Ü¢ÜÜ¢Ü",
+ "srf_printername_gallery": "Ü’Üܬ Ü“Ü ÜšÜ",
+ "srf-gallery-navigation-previous": "Ü•Ü©Ü•Ü¡",
+ "srf-gallery-navigation-next": "ܕܒܬܪ",
+ "srf-gallery-overlay-count": "Ü¨Ü˜ÜªÜ¬Ü $1 Ü¡Ü¢ $2"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/arz.json b/www/wiki/extensions/SemanticResultFormats/i18n/arz.json
new file mode 100644
index 00000000..c3eb9640
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/arz.json
@@ -0,0 +1,43 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meno25"
+ ]
+ },
+ "srf-desc": "صيغ إضاÙيه لاستعلامات ميدياويكى الداخلية",
+ "srf-name": "صيغ النتائج الدلالية",
+ "srfc_previousmonth": "الشهر السابق",
+ "srfc_nextmonth": "الشهر التالي",
+ "srfc_today": "اليوم",
+ "srfc_gotomonth": "اذهب إلى شهر",
+ "srf_printername_calendar": "نتيجه شهرية",
+ "srf_vcard_link": "ÙÙ‰ كارد",
+ "srf_printername_vcard": "تصدير vCard",
+ "srf_icalendar_link": "آى كالندر",
+ "srf_printername_icalendar": "تصدير iCalendar",
+ "srf_paramdesc_icalendartitle": "عنوان مل٠النتيجة",
+ "srf_paramdesc_icalendardescription": "وص٠مل٠النتيجة",
+ "srf_printername_bibtex": "تصدير BibTeX",
+ "srf_outline_novalue": "لا قيم",
+ "srf_printername_outline": "إطار",
+ "srf_paramdesc_outlineproperties": "قائمه الخصائص ليتم عرضها كعناوين عامه، Ù…Ùصوله بواسطه Ùاصلات",
+ "srf_printername_sum": "مجموع الأرقام",
+ "srf_printername_average": "متوسط الأرقام",
+ "srf_printername_max": "الرقم الأقصى",
+ "srf_printername_min": "الرقم الأدنى",
+ "srf_paramdesc_limit": "أقصى عدد من الصÙحات للاستعلام",
+ "srf_printername_timeline": "خط زمني",
+ "srf_printername_eventline": "خط الأحداث",
+ "srf_paramdesc_timelinebands": "يعر٠أى الÙرق يتم عرضها ÙÙ‰ هذه النتيجه.",
+ "srf_paramdesc_timelineposition": "يعر٠أين يركز الخط الزمنى ابتداء.",
+ "srf_paramdesc_timelinestart": "اسم خاصيه تستخدم لتعري٠نقطه أول مرة",
+ "srf_paramdesc_timelineend": "اسم خاصيه تستخدم لتعري٠نقطه ثانى مرة",
+ "srf_paramdesc_timelinesize": "ارتÙاع الخط الزمنى",
+ "srf_paramdesc_views": "عمليات الرؤيه للعرض",
+ "srf_paramdesc_facets": "مجموعه الخصائص للعرض لكل صÙحة",
+ "srf_paramdesc_lens": "اسم القالب لعرض خصائص الصÙحه به",
+ "srf_printername_googlebar": "رسم جوجل بالأعمدة",
+ "srf_printername_googlepie": "رسم جوجل بالÙطيرة",
+ "srf_paramdesc_chartheight": "ارتÙاع الرسم بالبكسل",
+ "srf_paramdesc_chartwidth": "عرض الرسم بالبكسل"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ast.json b/www/wiki/extensions/SemanticResultFormats/i18n/ast.json
new file mode 100644
index 00000000..31a71611
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ast.json
@@ -0,0 +1,323 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "srf-desc": "Formatos de resultancies adicionales pa consultes de Semantic MediaWiki",
+ "prefs-srf": "Estensión:Formatos de resultancies semántiques",
+ "srf-prefs-intro-text": "Tienes instalada la estensión Formatos de resultancia semántica. Pa llograr ayuda adicional, visita la páxina d'ayuda sobre los [https://@www.semantic-mediawiki.org/wiki/Help:Result_formats formatos de les resultancies].",
+ "prefs-srf-eventcalendar-options": "Opciones de calendariu d'actividaes",
+ "srf-prefs-eventcalendar-options-update-default": "Activar les [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates actualizaciones automátiques] de les actividaes del calendariu durante l'actualización de la páxina",
+ "srf-prefs-eventcalendar-options-paneview-default": "Activar la vista de tableru de mou predetermináu",
+ "prefs-srf-datatables-options": "Opciones de DataTables",
+ "srf-prefs-datatables-options-update-default": "Activar les [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates actualizaciones automátiques] del conteníu de la tabla durante l'actualización de la páxina",
+ "srf-prefs-datatables-options-cache-default": "Activar l'[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage almacenamientu llocal] p'ameyorar el tiempu de respuesta",
+ "srf-module-loading": "Cargando...",
+ "srf-paramdesc-layout": "Diseñu disponible",
+ "srf-paramdesc-height": "Altor",
+ "srf-paramdesc-width": "Anchor",
+ "srf-paramdesc-class": "Especificar una clase adicional de fueya d'estilos en cascada (CSS)",
+ "srf-module-nomatch": "Nun s'atoparon coincidencies.",
+ "srf-paramdesc-charttype": "Tipu de gráfica disponible",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "cab",
+ "srf-ui-navigation-next": "Siguiente",
+ "srf-ui-common-label-source": "Fonte",
+ "srf-ui-common-label-datasource": "Fonte de datos",
+ "srf-ui-common-label-ajax-error": "El sirvidor informó d'una comunicación fallida del elementu $1. Intenta anovar la páxina o consulta con $2.",
+ "srf-ui-common-label-request-object": "oxetu de la solicitú",
+ "srf-ui-common-label-help-section": "sección d'ayuda",
+ "srf-ui-tooltip-title-options": "Opciones",
+ "srf-ui-tooltip-title-scope": "Ãmbitu",
+ "srf-ui-tooltip-title-legend": "Lleenda",
+ "srf-ui-tooltip-title-filter": "Filtru",
+ "srf-ui-common-label-refresh": "Refrescar",
+ "srf-ui-common-label-parameters": "Parámetros",
+ "srf-ui-common-label-query": "Consulta",
+ "srf-ui-common-label-paneview": "Vista de tableru",
+ "srf-ui-common-label-daterange": "Intervalu de feches",
+ "srf-ui-widgets-label-parameter-limit": "Parámetru de llende",
+ "srf-error-option-mix": "La opción ($1) nun ta disponible",
+ "srf-error-option-link-all": "La opción ($1) precisa que'l parámetru «link» tea definíu como «all»",
+ "srf-error-missing-layout": "Nun puede amosase la gráfica porque falta'l diseñu.",
+ "srf-error-jqplot-bubble-data-length": "Nun puede amosase'l diagrama o la gráfica porque falten los datos.",
+ "srf-error-jqplot-stackseries-data-length": "Nun puede amosase la gráfica porque non toles barres o llinies tienen la mesma cantidá d'elementos.",
+ "srf-warn-empy-chart": "La gráfica ta vacida porque falten datos",
+ "srf-paramdesc-color": "El color pa marcar entraes de calendariu",
+ "srfc_previousmonth": "Mes anterior",
+ "srfc_nextmonth": "Próximu mes",
+ "srfc_today": "Güei",
+ "srfc_gotomonth": "Dir al mes",
+ "srf_printername_calendar": "Calendariu mensual",
+ "srf_paramdesc_calendarlang": "El códigu de la llingua na que s'amuesa'l calendariu",
+ "srf_paramdesc_calendarcolors": "El color a amosar pa cada propiedá de fecha (exemplu: \"Fecha d'entamu=>green, Fecha de fin=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "El mes col que principia la vista de calendariu (si s'omíte, el mes actual)",
+ "srf-paramdesc-calendar-startyear": "L'añu col que principia la vista de calendariu (si s'omíte, l'añu actual)",
+ "srf_printername_vcard": "Esportar vCard",
+ "srf_printername_icalendar": "Esportar iCalendar",
+ "srf_paramdesc_icalendartitle": "El títulu del ficheru de calendariu",
+ "srf_paramdesc_icalendardescription": "La descripción del ficheru de calendariu",
+ "srf_printername_bibtex": "Esportar a BibTeX",
+ "srf_outline_novalue": "Ensin valor",
+ "srf_printername_outline": "Esquema",
+ "srf_paramdesc_outlineproperties": "La llista de les propiedaes que van amosase como encabezaos d'esquema, dixebraes por comes",
+ "srf_printername_sum": "Suma de númberos",
+ "srf_printername_average": "Promediu de númberos",
+ "srf_printername_max": "Númberu máximu",
+ "srf_printername_min": "Númberu mínimu",
+ "srf_paramdesc_limit": "El númberu máximu de páxines a consultar",
+ "srf_printername_product": "Productu de númberos",
+ "srf_printername_median": "Mediana de númberos",
+ "srf-paramdesc-default": "Valor predetermináu que se va amosar cuando nun hai resultaos numbéricos",
+ "srf_printername_earliest": "Primera hora",
+ "srf_printername_latest": "Última hora",
+ "srf_printername_timeline": "Cronograma",
+ "srf_printername_eventline": "Llinia de socesos",
+ "srf_paramdesc_timelinebands": "Define qué bandes s'amuesen na resultancia.",
+ "srf_paramdesc_timelineposition": "Define onde se centra primeramente la llinia temporal.",
+ "srf_paramdesc_timelinestart": "Un nome de propiedá utilizáu pa definir un primer puntu temporal",
+ "srf_paramdesc_timelineend": "Un nome de propiedá utilizáu pa definir un segundu puntu temporal",
+ "srf_paramdesc_timelinesize": "L'altor de la llinia temporal",
+ "srf-timeline-allresults": "Más resultancies d'esta consulta.",
+ "srf-timeline-nojs": "Necesites tener JavaScript activáu pa ver la llinia temporal interactiva.",
+ "srf_paramdesc_views": "Les vistes a amosar",
+ "srf_paramdesc_facets": "El grupu de propiedaes a amosar pa cada páxina",
+ "srf_paramdesc_lens": "El nome d'una plantía cola que s'amuesen les propiedaes de la páxina",
+ "srf_printername_googlebar": "Gráfica de barres de Google",
+ "srf_printername_googlepie": "Gráfica de tarta de Google",
+ "srf-printername-jqplotchart": "Gráfica jqPlot",
+ "srf-printername-jqplotseries": "Serie jqPlot",
+ "srf_paramdesc_chartheight": "Especifica l'altor (en píxeles) d'una tabla o una gráfica",
+ "srf_paramdesc_chartwidth": "Especifica l'anchor (en píxeles o porcentaxe) de la tabla o gráfica",
+ "srf_paramdesc_charttitle": "El títulu de la gráfica",
+ "srf_paramdesc_barcolor": "Especificar los colores de la gráfica",
+ "srf_paramdesc_bardirection": "Especifica la dirección d'una gráfica",
+ "srf-paramdesc-direction": "Especifica la dirección d'una tabla o una gráfica",
+ "srf_paramdesc_barnumbersaxislabel": "La etiqueta de la exa de los númberos",
+ "srf-paramdesc-labelaxislabel": "La etiqueta pa la exa d'etiquetes",
+ "srf-paramdesc-ticklabels": "Activar la vista d'etiquetes nes marques",
+ "srf-paramdesc-minvalue": "El valor mínimu qu'amosar na exa Y",
+ "srf-paramdesc-pointlabels": "Ver los puntos de datos na gráfica",
+ "srf-paramdesc-chartlegend": "Posición de la lleenda de la gráfica",
+ "srf-paramdesc-datalabels": "Rótulos de datos de la tabla o gráfica",
+ "srf-paramdesc-charttext": "Testu descriptivu de la gráfica",
+ "srf-paramdesc-chartclass": "Clase CSS adicional",
+ "srf-paramdesc-renderer": "Escueye un renderizador de tables/gráfiques",
+ "srf-paramdesc-filling": "Opción de rellenáu individual",
+ "srf-paramdesc-theme": "Escueye una tema de cuadrícula",
+ "srf-paramdesc-chartcolor": "Asignar colores individuales a la gráfica",
+ "srf-paramdesc-colorscheme": "Escueye una combinación de colores",
+ "srf-paramdesc-valueformat": "Especifica una regla de formatu pa los valores",
+ "srf-paramdesc-highlighter": "Amosar un resaltador de puntu de datos",
+ "srf-paramdesc-smoothlines": "Aplicar un algoritmu d'adondáu nos gráficos de llinies",
+ "srf-paramdesc-stackseries": "Amosar gráficu como serie apilada",
+ "srf-paramdesc-seriesgroup": "Escoyer l'agrupamientu de series",
+ "srf-paramdesc-serieslabel": "Determinar la etiqueta de serie",
+ "srf-paramdesc-grouplabel": "Determinar la etiqueta de grupu",
+ "srf-paramdesc-chartcursor": "Opción de visualización del cursor de tabla",
+ "srf-paramdesc-trendline": "Activar la vista simultanea d'una gráfica y la so llinia d'enclín",
+ "srf-paramdesc-gridview": "Amosar simultaneamente gráfica y conxuntu de datos. Valores permitíos: \"none\" y \"tabs\". Predetermináu: \"none\"",
+ "srf-paramdesc-paneview": "Especifica la posición del panel que contien una pequeña gráfica de llinies. Los valores permitíos son: \"abaxo\", \"arriba\" y \"nengún\". Predeterminao: \"abaxo\"",
+ "srf-paramdesc-infotext": "Amosar información adicional nuna llingüeta d'información correspondiente",
+ "srf-paramdesc-clicktarget": "Define una páxina o cadena de consulta como destín al facer click n'una data del calendariu.",
+ "srf-ui-gridview-label-item": "Elementu de datos",
+ "srf-ui-gridview-label-value": "Valor de los datos",
+ "srf-ui-gridview-label-series": "Serie de datos",
+ "srf-ui-gridview-label-chart-tab": "Gráfica",
+ "srf-ui-gridview-label-data-tab": "Datos",
+ "srf-ui-gridview-label-info-tab": "Información",
+ "srf_printername_gallery": "Galería",
+ "srf_paramdesc_perrow": "La cantidá d'imáxenes per filera",
+ "srf_paramdesc_widths": "L'anchor de les imáxenes",
+ "srf_paramdesc_heights": "L'altor de les imáxenes",
+ "srf_paramdesc_autocaptions": "Usar el nome de ficheru como pie d'imaxe cuando nun se da nengunu",
+ "srf_paramdesc_fileextensions": "Al usar el nome del ficheru como pie d'imaxe, amosar tamién la estensión del ficheru",
+ "srf_paramdesc_captionproperty": "El nome d'una propiedá semántica presente nes páxines consultaes a usar como pie d'imaxe",
+ "srf_paramdesc_imageproperty": "Nome d'una propiedá semántica nes páxines consultaes qu'apunta a les imáxenes a usar. Cuando tea definíu, les mesmes páxines consultaes nun se van amosar como imáxenes",
+ "srf-paramdesc-redirects": "El nome d'una propiedá semántica presente nes páxines consultaes que contienen el destín de la redireición",
+ "srf-paramdesc-navigation": "Control de navegación del diseñu",
+ "srf-paramdesc-overlay": "Activar la superposición d'imáxenes",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Siguiente",
+ "srf-gallery-overlay-count": "Imaxe $1 de $2",
+ "srf-gallery-image-url-error": "Nun s'alcontró la imaxe",
+ "srf_printername_tagcloud": "Nube d'etiquetes",
+ "srf_paramdesc_includesubject": "Los mesmos nomes de les temes tendríen d'incluyise",
+ "srf_paramdesc_increase": "Como aumentar el tamañu de les etiquetes",
+ "srf_paramdesc_tagorder": "L'orde de les etiquetes",
+ "srf_paramdesc_mincount": "La cantidá mínima de vegaes qu'un valor tien de presentase pa tar na llista",
+ "srf_paramdesc_minsize": "El tamañu de les etiquetes más pequeñes, en porcentaxe",
+ "srf_paramdesc_maxsize": "El tamañu de les etiquetes más grandes en porcentaxe",
+ "srf_paramdesc_maxtags": "La cantidá máxima d'etiquetes de la nube",
+ "srf-paramdesc-excludetags": "Escluyir etiquetes (allindiador: \";\")",
+ "srf_printername_valuerank": "Rangu de valores",
+ "srf_printername_array": "Tabla",
+ "srf_paramdesc_pagetitle": "Amosar los títulos de les páxines como entraes de resultancies, o bien omitilos",
+ "srf_paramdesc_hidegaps": "Imprimir los valores de les propiedaes y de los rexistros solicitaos y non disponibles, dixebraos por separadores,o bien omitilos",
+ "srf_paramdesc_arrayname": "Si se da y ArrayExtension ta disponible, esto va crear una tabla col nome indicáu (ensin salida visible, nesi casu)",
+ "srf_paramdesc_propsep": "Separador ente les propiedaes solicitaes",
+ "srf_paramdesc_manysep": "Separador ente los valores de les propiedaes con munchos valores",
+ "srf_paramdesc_recordsep": "Separador ente los valores de les propiedaes de rexistru",
+ "srf_paramdesc_headersep": "Separador ente'l nome y el valor de la propiedá si \"headers\" ta definíu como \"show\" o \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Si se da y la estensión HashTables ta disponible, esto va crear un \"hash\" col nome indicáu (ensin salida visible, nesi casu)",
+ "srf-printername-graph": "Gráfica",
+ "srf-paramdesc-graph-relation": "Establez si los suxetos o les propiedaes del nome son padres o fíos",
+ "srf-paramdesc-graph-nameprop": "Establez la propiedá que se va usar como asuntu en llugar del asuntu real, esto ye, el nome de la páxina",
+ "srf-paramdesc-graph-nodeshape": "Establez la forma de cada nodiu nel gráficu",
+ "srf-paramdesc-graphname": "Establez el títulu de la gráfica",
+ "srf-paramdesc-graphsize": "Establez el tamañu de la gráfica en pixels",
+ "srf-paramdesc-graphlegend": "Establez si tien d'amosase una lleenda de gráfica",
+ "srf-paramdesc-graphlabel": "Establez la etiqueta de la gráfica",
+ "srf-paramdesc-rankdir": "Establez la dirección de les fleches",
+ "srf-paramdesc-graphlink": "Establez si los nodios tienen d'enllazar a les sos páxines wiki",
+ "srf-paramdesc-graphcolor": "Establez el color de la gráfica",
+ "srf-paramdesc-graph-wwl": "Establez la llende del axuste de testu (en númberu de caráuteres)",
+ "srf-paramdesc-clustercolor": "Establez los colores de los cuadros d'agrupamientu",
+ "srf-paramdesc-highlight": "Define'l nodiu que tien de destacase",
+ "srf-paramdesc-highlightcolor": "Configura'l color de lletra pal nudu resaltáu",
+ "srf-paramdesc-redlinkcolor": "Configura'l color de lletra pa los enllaces bermeyos",
+ "srf-paramdesc-processcategory": "Configura la categoría de la wiki que recueye los pasos del procesu",
+ "srf-paramdesc-showroles": "Amosar los roles correspondientes na gráfica",
+ "srf-paramdesc-showstatus": "Indica si tien de representase l'estáu d'un pasu del procesu",
+ "srf-paramdesc-showresources": "Amuesa los recursos correspondientes na gráfica",
+ "srf-paramdesc-showdiscussion": "Indica si tendría de representase una páxina d'alderique",
+ "srf-paramdesc-showredlinks": "Indica si los enllaces bermeyos tendríen de revisase y resaltase",
+ "srf-paramdesc-showcompound": "Indica si tienen de resaltase los nudos compuestos, p. ex. los subprocesos",
+ "srf-paramdesc-debug": "Indica si'l códigu de la gráfica del procesu tendría d'amosase ente etiquetes «pre»",
+ "srf-paramdesc-graphvalidation": "Amuesa los pasos del procesu en bermeyu cuando nun tienen definíu un rol",
+ "srf-printername-datatables": "Tables de datos",
+ "srf-ui-datatables-label-conditions": "Condiciones",
+ "srf-ui-datatables-label-parameters": "Parámetros",
+ "srf-ui-datatables-label-filters": "Filtros de columnes y gueta",
+ "srf-ui-datatables-label-information": "Información",
+ "srf-ui-datatables-panel-disclaimer": "Los parámetros y condiciones pueden alteriase, pero cualquier cambéu ye temporal y va abandonase n'actualizando la páxina.",
+ "srf-ui-datatables-label-update-success": "Actualizóse la tabla correutamente",
+ "srf-ui-datatables-label-update-error": "Falló l'actualización de la tabla.",
+ "srf-ui-datatables-label-placeholder-column-search": "Guetar...",
+ "srf-ui-datatables-label-content-cache": "El conteníu derivóse de la caché llocal.",
+ "srf-ui-datatables-label-content-server": "El conteníu derivóse del sirvidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Columnes disponibles",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Configuración de filtros",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Les columnes son visibles",
+ "srf-ui-datatables-label-sEmptyTable": "Nun hai datos disponibles na tabla",
+ "srf-ui-datatables-label-sInfo": "Amosando de la _START_ a la _END_ de _TOTAL_ entraes",
+ "srf-ui-datatables-label-sInfoEmpty": "Amosando de 0 a 0 de 0 entraes",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtriaes d'un total de _MAX_ entraes)",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLengthMenu": "Amosar _MENU_ entraes",
+ "srf-ui-datatables-label-sLoadingRecords": "Cargando...",
+ "srf-ui-datatables-label-sProcessing": "Procesando...",
+ "srf-ui-datatables-label-sSearch": "Buscar:",
+ "srf-ui-datatables-label-sZeroRecords": "Nun s'atoparon rexistros que concasen",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primeru",
+ "srf-ui-datatables-label-oPaginate-sLast": "Postreru",
+ "srf-ui-datatables-label-oPaginate-sNext": "Siguiente",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activar pa ordenar la columna de mou ascendiente",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": activar pa ordenar la columna de mou descendiente",
+ "srf-printername-tree": "Ãrbol",
+ "srf-printername-ultree": "Ãrbol UL",
+ "srf-printername-oltree": "Ãrbol OL",
+ "srf-tree-noparentprop": "Nun s'especificó nenguna propiedá padre. Non puede construise l'árbol ensin especificar una propiedá padre.",
+ "srf-tree-rootinvalid": "$1 nun ye un títulu de páxina válidu.",
+ "srf-tree-circledetected": "Detectóse una referencia circular al tentar inxertar $1 nel árbol.",
+ "srf-paramdesc-tree-parent": "La propiedá que contien la páxina padre",
+ "srf-paramdesc-tree-root": "la páxina raíz del árbol",
+ "srf-paramdesc-tree-startlevel": "El nivel d'entamu del árbol, por casu, pa integralo n'otru árbol",
+ "srf-printername-slideshow": "Presentación de diapositives",
+ "srf-paramdesc-delay": "Posa ente diapositives, en segundos",
+ "srf-paramdesc-navigation-controls": "Amosar o non los controles de navegación",
+ "srf-paramdesc-effect": "L'efectu a utilizar pa cambiar d'una diapositiva a otra",
+ "srf-printername-filtered": "Filtriáu",
+ "srf-paramdesc-filtered-views": "Les vistes que tarán disponibles na pantalla de resultancies.",
+ "srf-paramdesc-filtered-filter-position": "La posición de los filtros en rellación coles vistes. Valores permitíos: \"top\", \"bottom\". Predetermináu: \"top\".",
+ "srf-paramdesc-filtered-list-type": "El tipu de llista. Valores permitíos: \"list\", \"ul\", \"ol\". Predetermináu: \"list\".",
+ "srf-paramdesc-filtered-list-template": "La plantía que tien d'utilizase pa dar formatu a les entraes de la llista.",
+ "srf-paramdesc-filtered-list-named-args": "Nome de los argumentos que se-y pasen a la plantía.",
+ "srf-paramdesc-filtered-list-introtemplate": "El nome d'una plantía que s'amuesa antes de los resultaos de la consulta, si los hai.",
+ "srf-paramdesc-filtered-list-outrotemplate": "El nome d'una plantía que s'amuesa dempués de los resultaos de la consulta, si los hai.",
+ "srf-paramdesc-filtered-calendar-start": "La impresión que contien la fecha d'entamu d'un socesu",
+ "srf-paramdesc-filtered-calendar-end": "La impresión que contien la fecha final d'un socesu",
+ "srf-paramdesc-filtered-calendar-title": "La impresión que contien el títulu d'un socesu. Nun puede utilizase xunto con una plantía de títulu.",
+ "srf-paramdesc-filtered-calendar-title-template": "Una plantía que s'utiliza pa dar formatu al títulu d'un socesu nel calendariu",
+ "srf-paramdesc-filtered-map-position": "La impresión que contien la posición xeográfica.",
+ "srf-paramdesc-filtered-map-icon": "La llista que decide qué iconu del mapa utilizar.",
+ "srf-paramdesc-filtered-map-icons": "Un mapa de valores de los iconos a utilizar pa estos valores nel mapa",
+ "srf-paramdesc-filtered-map-height": "L'altor del mapa.",
+ "srf-paramdesc-filtered-map-zoom": "El nivel d'ampliación al cargar el mapa. Puede cambiase pol usuariu. <br>ConsultaË <i>ampliación mínima de la vista de mapa</i> y <i>ampliación máxima de la vista de mapa</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "El mínimu nivel d'ampliación seleicionable nel mapa",
+ "srf-paramdesc-filtered-map-max-zoom": "El máximu nivel d'ampliación seleicionable nel mapa",
+ "srf-paramdesc-filtered-map-marker-cluster": "Activar o desactivar l'ensame de marcadores.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Nivel máximu d'ampliación nel que los marcadores inda s'ensamen. Perriba d'esti nivel los marcadores siempre tarán separaos.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "El radiu máximu que cubrirá un ensame a partir del marcador central (en pixels). Predeterminao, 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Si s'activa, al facer click nun ensame, ampliaráse hasta les sos llendes.",
+ "srf-filtered-selectorlabel-list": "Llista",
+ "srf-filtered-selectorlabel-table": "Tabla",
+ "srf-filtered-selectorlabel-calendar": "Calendariu",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "Nun pueden amosase los resultaos porque nun ta activáu Javascript. Visita $1.",
+ "srf-filtered-noscript-link-caption": "resultaos en forma de tabla",
+ "srf-filtered-map-provider-missing-error": "Nun s'indicó un orixe de mapa pa la vista «mapa».",
+ "srf-filtered-value-filter-and": "Y",
+ "srf-filtered-value-filter-or": "O",
+ "srf-filtered-value-filter-placeholder": "Seleccionar un valor de filtru",
+ "srf-printername-d3chart": "Gráfica D3",
+ "srf-printername-timeseries": "Gráfica de serie temporal",
+ "srf-paramdesc-group": "Serie agrupada por",
+ "srf-paramdesc-zoom": "Activar el zoom",
+ "srf-paramdesc-datatable": "Activar una tabla de datos",
+ "srf-timeseries-zoom-out-of-range": "El rangu d'ampliación nun produció datos abondo",
+ "srf-printername-sparkline": "Gráfica sparkline",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Especificar el tipu de llista",
+ "srf-paramdesc-widget": "Widget disponibles",
+ "srf-paramdesc-pageitems": "Elementos por páxina",
+ "srf-printername-eventcalendar": "Calendariu de socesos",
+ "srf-paramdesc-calendarfirstday": "El día en qu'empieza cada selmana",
+ "srf-paramdesc-calendardefaultview": "Vista inicial cuando se carga'l calendariu",
+ "srf-paramdesc-calendarstart": "L'empiezu del calendariu inicial (valores date o datetime)",
+ "srf-paramdesc-calendarlegend": "Especifica la posición de la lleenda y les opciones de filtru aplicaes",
+ "srf-paramdesc-dayview": "Activar la vista de día faciendo clic nel númberu del día",
+ "srf-ui-eventcalendar-label-today": "Güei",
+ "srf-ui-eventcalendar-label-month": "Mes",
+ "srf-ui-eventcalendar-label-week": "Selmana",
+ "srf-ui-eventcalendar-label-day": "Día",
+ "srf-ui-eventcalendar-label-listmonth": "Mes (llista)",
+ "srf-ui-eventcalendar-label-listweek": "Selmana (llista)",
+ "srf-ui-eventcalendar-label-listday": "Día (llista)",
+ "srf-ui-eventcalendar-label-allday": "Tol día",
+ "srf-ui-eventcalendar-label-update-success": "El calendariu de socesos actualizóse correutamente.",
+ "srf-ui-eventcalendar-label-update-error": "Falló l'actualización del calendariu de socesos.",
+ "srf-ui-eventcalendar-click-popup": "¿Quies crear un socesu?",
+ "srf-printername-dygraphs": "Gráfica Dygraphs",
+ "srf-paramdesc-datasource": "La fonte na que tán disponibles los datos. Valores permitíos: \"file\", \"raw\" y \"url\". Predetermináu: \"file\"",
+ "srf-paramdesc-errorbar": "La barra d'error a utilizar. Valores permitíos: \"fraction\" (intervalos de confianza pa valores), \"sigma\" (esviación estándar de los valores) y \"range\" (rangos de valor personalizaos)",
+ "srf-paramdesc-movingaverage": "Amosar el valor mediu nun númberu de díes (cero va indicar que nun hai media móvil)",
+ "srf-paramdesc-yaxislabel": "Descripción qu'apaez na exa y",
+ "srf-paramdesc-xaxislabel": "Descripción qu'apaez na exa x",
+ "srf-paramdesc-unit": "Unidá",
+ "srf-printername-pagewidget": "Pagewidget",
+ "srf-printername-incoming": "Propiedaes entrantes",
+ "srf-paramdesc-count": "Indica si tien de contase'l númberu de propiedaes entrantes",
+ "srf-paramdesc-min": "Valor mínimu o estragal",
+ "srf-paramdesc-excludeproperty": "Quitar la propiedá del conxuntu de resultancies",
+ "srf-printername-media": "Reproductor multimedia",
+ "srf-paramdesc-mediainspector": "Amuesa información detallada sobre un elementu multimedia específicu",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reproducir",
+ "srf-ui-mediaplayer-label-pause": "Pausa",
+ "srf-ui-mediaplayer-label-next": "Siguiente",
+ "srf-ui-mediaplayer-label-stop": "Parar",
+ "srf-ui-mediaplayer-label-mute": "Silenciar",
+ "srf-ui-mediaplayer-label-unmute": "Activar soníu",
+ "srf-ui-mediaplayer-label-volume-max": "Volume máx.",
+ "srf-ui-mediaplayer-label-shuffle": "Al debalu",
+ "srf-ui-mediaplayer-label-shuffle-off": "Desactivar mou al debalu",
+ "srf-ui-mediaplayer-label-repeat": "Repetir",
+ "srf-ui-mediaplayer-label-repeat-off": "Desactivar repetición",
+ "srf-ui-mediaplayer-label-full-screen": "Pantalla completa",
+ "srf-ui-mediaplayer-label-restore-screen": "Restaurar la pantalla",
+ "srf-paramdesc-icalendar-timezone": "Llista d'estayes horaries separaes con comes"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/az.json b/www/wiki/extensions/SemanticResultFormats/i18n/az.json
new file mode 100644
index 00000000..9f20d473
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/az.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cekli829"
+ ]
+ },
+ "srfc_today": "Bu gün",
+ "srf_printername_gallery": "Qalereya"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/be-tarask.json b/www/wiki/extensions/SemanticResultFormats/i18n/be-tarask.json
new file mode 100644
index 00000000..29f1128d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/be-tarask.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Red Winged Duck"
+ ]
+ },
+ "srf-desc": "Ð”Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ñ„Ð°Ñ€Ð¼Ð°Ñ‚Ñ‹ вынікаў Ð´Ð»Ñ Ð·Ð°Ð¿Ñ‹Ñ‚Ð°Ñž Semantic MediaWiki",
+ "srf-name": "Фарматы ÑÑмантычных вынікаў",
+ "srfc_previousmonth": "ПапÑÑ€Ñдні меÑÑц",
+ "srfc_nextmonth": "ÐаÑтупны меÑÑц",
+ "srfc_today": "СёньнÑ",
+ "srfc_gotomonth": "ПерайÑьці да меÑÑца",
+ "srf_printername_calendar": "КалÑндар на меÑÑц",
+ "srf_paramdesc_calendarlang": "Код мовы, на Ñкой паказваць калÑндар",
+ "srf_printername_vcard": "ÑкÑпарт у фармаце vCard",
+ "srf_printername_icalendar": "ÑкÑпарт у фармаце iCalendar",
+ "srf_paramdesc_icalendartitle": "Ðазва файла календара",
+ "srf_paramdesc_icalendardescription": "ÐпіÑаньне файла календара",
+ "srf_printername_bibtex": "ÑкÑпарт у фармаце BibTeX",
+ "srf_outline_novalue": "ÐÑма значÑньнÑ",
+ "srf_printername_outline": "Табліца",
+ "srf_paramdesc_outlineproperties": "Ð¡ÑŒÐ¿Ñ–Ñ ÑƒÐ»Ð°ÑьціваÑьцÑÑž Ð´Ð»Ñ Ð¿Ð°ÐºÐ°Ð·Ñƒ Ñž ÑкаÑьці загалоўкаў, падзеленых коÑкамі",
+ "srf_printername_sum": "Сума лікаў",
+ "srf_printername_average": "СÑÑ€ÑднÑе значÑньне лікаў",
+ "srf_printername_max": "МакÑымальны лік",
+ "srf_printername_min": "Мінімальны лік",
+ "srf_paramdesc_limit": "МакÑÑ‹Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð»ÑŒÐºÐ°Ñьць Ñтаронак Ð´Ð»Ñ Ð·Ð°Ð¿Ñ‹Ñ‚Ñƒ",
+ "srf_printername_product": "Вынік лічбаў",
+ "srf_printername_timeline": "ХраналёгіÑ",
+ "srf_printername_eventline": "Ð¥Ñ€Ð°Ð½Ð°Ð»Ñ‘Ð³Ñ–Ñ Ð¿Ð°Ð´Ð·ÐµÑÑž",
+ "srf_paramdesc_timelinebands": "Вызначае, ÑÐºÑ–Ñ Ð´Ñ‹Ñпазоны будуць Ð¿Ð°ÐºÐ°Ð·Ð°Ð½Ñ‹Ñ Ñž выніку.",
+ "srf_paramdesc_timelineposition": "Вызначае, Ñкое меÑца шкалы чаÑу будзе паказвацца Ñпачатку.",
+ "srf_paramdesc_timelinestart": "Ðазва ўлаÑьціваÑьці, ÑÐºÐ°Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваецца Ñк першы пункт чаÑу",
+ "srf_paramdesc_timelineend": "Ðазва ўлаÑьціваÑьці, ÑÐºÐ°Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваецца Ð´Ð»Ñ Ð²Ñ‹Ð·Ð½Ð°Ñ‡ÑÐ½ÑŒÐ½Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð³Ð° пункту чаÑу",
+ "srf_paramdesc_timelinesize": "Ð’Ñ‹ÑˆÑ‹Ð½Ñ ÑˆÐºÐ°Ð»Ñ‹ чаÑу",
+ "srf-timeline-allresults": "Ð”Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ð²Ñ‹Ð½Ñ–ÐºÑ– па гÑтым запыце.",
+ "srf-timeline-nojs": "Вам неабходна дазволіць JavaScript, каб праглÑдаць інтÑрактыўную лінію чаÑу.",
+ "srf_paramdesc_views": "ПраглÑды Ð´Ð»Ñ Ð¿Ð°ÐºÐ°Ð·Ñƒ",
+ "srf_paramdesc_facets": "Ðабор ўлаÑьціваÑьцÑÑž Ð´Ð»Ñ Ð¿Ð°ÐºÐ°Ð·Ñƒ на кожнай Ñтаронцы",
+ "srf_paramdesc_lens": "Ðазва шаблёну Ð´Ð»Ñ Ð¿Ð°ÐºÐ°Ð·Ñƒ ўлаÑьціваÑьцÑÑž Ñтаронкі",
+ "srf_printername_googlebar": "Ð¡Ð»ÑƒÐ¿ÐºÐ¾Ð²Ð°Ñ Ð´Ñ‹Ñграма Google",
+ "srf_printername_googlepie": "ÐšÑ€ÑƒÐ³Ð°Ð²Ð°Ñ Ð´Ñ‹Ñграма Google",
+ "srf_paramdesc_chartheight": "Пазначце вышыню (у пікÑÑлÑÑ…) дыÑграмы ці графіку",
+ "srf_paramdesc_chartwidth": "Вызначце шырыню (у пікÑÑлÑÑ… ці адÑотках) дыÑграмы або графіку",
+ "srf_paramdesc_charttitle": "Ðазва дыÑграмы",
+ "srf_paramdesc_barcolor": "Колер Ñлупкоў",
+ "srf_paramdesc_bardirection": "Вызначце кірунак дыÑграмы",
+ "srf_paramdesc_barnumbersaxislabel": "ÐадпіÑÑ‹ Ð´Ð»Ñ Ð»Ñ–Ñ‡Ð±Ð°Ð²Ñ‹Ñ… воÑÑÑž",
+ "srf_printername_gallery": "ГалерÑÑ",
+ "srf_paramdesc_perrow": "КолькаÑьць выÑваў у радку",
+ "srf_paramdesc_widths": "Ð¨Ñ‹Ñ€Ñ‹Ð½Ñ Ð²Ñ‹Ñваў",
+ "srf_paramdesc_heights": "Ð’Ñ‹ÑˆÑ‹Ð½Ñ Ð²Ñ‹Ñваў",
+ "srf_paramdesc_autocaptions": "ВыкарыÑтоўваць назву файла Ñž ÑкаÑьці загалоўку, калі ён не пададзены",
+ "srf_paramdesc_fileextensions": "ÐŸÐ°Ð´Ñ‡Ð°Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹ÑÑ‚Ð°Ð½ÑŒÐ½Ñ Ð½Ð°Ð·Ð²Ñ‹ файла Ñž ÑкаÑьці загалоўку, такÑама паказваць пашырÑньне файла",
+ "srf_printername_tagcloud": "Воблака Ñ‚Ñгаў",
+ "srf_paramdesc_increase": "Як павÑлічыць памер Ñ‚Ñгаў",
+ "srf_paramdesc_tagorder": "Парадак Ñ‚Ñгаў",
+ "srf_paramdesc_minsize": "Памер Ñамых малых Ñ‚Ñгаў у адÑотках",
+ "srf_paramdesc_maxsize": "Памер Ñамых вÑлікіх Ñ‚Ñгаў у адÑотках",
+ "srf_paramdesc_maxtags": "МакÑÑ‹Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð»ÑŒÐºÐ°Ñьць Ñ‚Ñгаў у воблаку",
+ "srf_printername_array": "МаÑÑ–Ñž",
+ "srf_paramdesc_pagetitle": "Ці паказваць назвы Ñтаронак Ñк ÑлемÑнты вынікаў або прапуÑкаць Ñ–Ñ…",
+ "srf_paramdesc_hidegaps": "Ці друкаваць запытаныÑ, але недаÑÑ‚ÑƒÐ¿Ð½Ñ‹Ñ ÑžÐ»Ð°ÑьціваÑьці Ñ– значÑньні запіÑаў, Ð¿Ð°Ð´Ð·ÐµÐ»ÐµÐ½Ñ‹Ñ Ñ€Ð°Ð·ÑŒÐ´Ð·ÑлÑльнікамі ці прапуÑкаць Ñ–Ñ…",
+ "srf_paramdesc_propsep": "РазьдзÑлÑльнік паміж запытанымі ўлаÑьціваÑьцÑмі",
+ "srf_paramdesc_manysep": "РазьдзÑлÑльнік паміж некалькімі значÑньнÑмі ўлаÑьціваÑьцÑÑž",
+ "srf_paramdesc_recordsep": "РазьдзÑлÑльнік паміж значÑньнÑмі запіÑаных улаÑьціваÑьцÑÑž",
+ "srf_printername_hash": "Рашотка",
+ "srf-printername-graph": "Графік",
+ "srf_paramdesc_graphname": "Ðазва",
+ "srf_paramdesc_graphsize": "Памер дыÑграмы (у пікÑÑлÑÑ…)"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/bg.json b/www/wiki/extensions/SemanticResultFormats/i18n/bg.json
new file mode 100644
index 00000000..6910c684
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/bg.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "DCLXVI",
+ "පසිඳු කà·à·€à·’න්ද"
+ ]
+ },
+ "srf-navigation-previous": "Предишна",
+ "srf-ui-navigation-next": "Следваща",
+ "srf-ui-common-label-source": "Източник",
+ "srfc_previousmonth": "Предходен меÑец",
+ "srfc_nextmonth": "Следващ меÑец",
+ "srfc_today": "ДнеÑ",
+ "srf-ui-gridview-label-data-tab": "Данни",
+ "srf-gallery-navigation-next": "Следваща",
+ "srf_paramdesc_graphname": "Заглавие",
+ "srf-filtered-selectorlabel-list": "СпиÑък",
+ "srf-filtered-selectorlabel-calendar": "Календар",
+ "srf-ui-eventcalendar-label-today": "ДнеÑ",
+ "srf-ui-eventcalendar-label-month": "МеÑец",
+ "srf-ui-eventcalendar-label-week": "Седмица",
+ "srf-ui-eventcalendar-label-day": "Ден",
+ "srf-paramdesc-unit": "Единица"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/bho.json b/www/wiki/extensions/SemanticResultFormats/i18n/bho.json
new file mode 100644
index 00000000..26df4e08
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/bho.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nepaboy"
+ ]
+ },
+ "srf-module-loading": "लोड हो रहल बा...",
+ "srf-ui-datatables-label-placeholder-column-search": "खोज...",
+ "srf-ui-datatables-label-sLoadingRecords": "लोड हो रहल बा...",
+ "srf-ui-datatables-label-sProcessing": "पà¥à¤°à¤—ति में बा..."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/bn.json b/www/wiki/extensions/SemanticResultFormats/i18n/bn.json
new file mode 100644
index 00000000..5145a7ec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/bn.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bellayet",
+ "Wikitanvir"
+ ]
+ },
+ "srfc_previousmonth": "পূরà§à¦¬à¦¬à¦°à§à¦¤à§€ মাস",
+ "srfc_nextmonth": "পরবরà§à¦¤à§€ মাস",
+ "srfc_today": "আজ",
+ "srfc_gotomonth": "যে মাসে যাবেন",
+ "srf_printername_calendar": "মাসিক কà§à¦¯à¦¾à¦²à§‡à¦¨à§à¦¡à¦¾à¦°",
+ "srf_outline_novalue": "কোনো মান নাই",
+ "srf_printername_sum": "সমষà§à¦Ÿà¦¿",
+ "srf_printername_average": "গড়",
+ "srf_printername_max": "সরà§à¦¬à§‹à¦šà§à¦š",
+ "srf_printername_min": "সরà§à¦¬à§‹à¦¨à¦¿à¦®à§à¦¨",
+ "srf_printername_googlebar": "গà§à¦—ল বার চারà§à¦Ÿ",
+ "srf_printername_gallery": "গà§à¦¯à¦¾à¦²à¦¾à¦°à¦¿",
+ "srf_paramdesc_perrow": "পà§à¦°à¦¤à¦¿ সারিতে ছবির সংখà§à¦¯à¦¾",
+ "srf_paramdesc_widths": "ছবির পà§à¦°à¦¸à§à¦¥",
+ "srf_paramdesc_heights": "ছবির উচà§à¦šà¦¤à¦¾",
+ "srf_printername_array": "অà§à¦¯à¦¾à¦°à§‡",
+ "srf_paramdesc_graphname": "শিরোনাম"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/br.json b/www/wiki/extensions/SemanticResultFormats/i18n/br.json
new file mode 100644
index 00000000..301f753c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/br.json
@@ -0,0 +1,138 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fohanno",
+ "Fulup",
+ "Gwendal",
+ "Gwenn-Ael",
+ "Y-M D",
+ "Nemo bis",
+ "Dishual"
+ ]
+ },
+ "srf-desc": "Furmadoù ouzhpenn evit ar rekedoù Semantic MediaWiki",
+ "srf-module-loading": "O kargañ...",
+ "srf-paramdesc-height": "Uhelder",
+ "srf-paramdesc-width": "Ledander",
+ "srf-module-nomatch": "N'eus bet kavet netra.",
+ "srf-navigation-previous": "Kent",
+ "srf-ui-navigation-prev": "Kent",
+ "srf-ui-navigation-next": "War-lerc'h",
+ "srf-ui-common-label-source": "Mammenn",
+ "srf-ui-common-label-datasource": "Mammenn ar roadennoù",
+ "srf-ui-common-label-help-section": "rann skoazell",
+ "srf-ui-tooltip-title-options": "Dibarzhioù",
+ "srf-ui-tooltip-title-legend": "Alc'hwez",
+ "srf-ui-tooltip-title-filter": "Sil",
+ "srf-ui-common-label-refresh": "Freskaat",
+ "srf-ui-common-label-parameters": "Arventennoù",
+ "srf-ui-common-label-query": "Reked",
+ "srfc_previousmonth": "Miz a-raok",
+ "srfc_nextmonth": "Miz a zeu",
+ "srfc_today": "Hiziv",
+ "srfc_gotomonth": "Mont d'ar miz",
+ "srf_printername_calendar": "Deiziataer miziek",
+ "srf_paramdesc_calendarlang": "Kod ar yezh a dalvez da ziskwel an deiziadur",
+ "srf_printername_vcard": "Ezporzh e vCard",
+ "srf_printername_icalendar": "Enporzh e iCalendar",
+ "srf_paramdesc_icalendartitle": "Titl ar restr deiziataer",
+ "srf_paramdesc_icalendardescription": "Deskrivadur restr an deiziataer",
+ "srf_printername_bibtex": "Enporzh e BibTeX",
+ "srf_outline_novalue": "Talvoud ebet",
+ "srf_printername_outline": "Trolinenn",
+ "srf_paramdesc_outlineproperties": "Roll ar perzhioù da ziskwel evel talbennoù, dispartiet gant skejoù.",
+ "srf_printername_sum": "Sammad niveroù",
+ "srf_printername_average": "Keitad an niveroù",
+ "srf_printername_max": "Niver uhelañ",
+ "srf_printername_min": "Niver izelañ",
+ "srf_paramdesc_limit": "Niver brasañ a bajennoù da gerc'hat",
+ "srf_printername_timeline": "Kronologiezh",
+ "srf_printername_eventline": "Kronologiezh an darvoudoù",
+ "srf_paramdesc_timelinebands": "a zielfenn peseurt strolladoù zo diskwelet en disoc'hoù.",
+ "srf_paramdesc_timelineposition": "a zielfenn takad ar frizenn a oa kreizennet da gentañ.",
+ "srf_paramdesc_timelinestart": "Un anv perzh implijet da dermeniñ ur poent loc'hañ en amzer",
+ "srf_paramdesc_timelineend": "Un anv perzh implijet da dermeniñ un eil poent en amzer",
+ "srf_paramdesc_timelinesize": "Uhelder ar frizenn",
+ "srf-timeline-allresults": "Disoc'hoù ouzhpenn evit ar reked-mañ.",
+ "srf_paramdesc_views": "Ar gweladennoù da ziskouez",
+ "srf_paramdesc_facets": "An hollad perzhioù da ziskwel evit pep pajenn",
+ "srf_paramdesc_lens": "Anv ar patrom implijet evit diskouez perzhioù ar bajenn",
+ "srf_printername_googlebar": "Grafik barrennek Google",
+ "srf_printername_googlepie": "Grafik dre lodennoù Google",
+ "srf_paramdesc_chartheight": "Uhelder an diagramm, e piksel",
+ "srf_paramdesc_chartwidth": "Ledander an diagramm, e piksel",
+ "srf_paramdesc_charttitle": "Titl ar grafik",
+ "srf_paramdesc_barcolor": "Liv ar barrennoù",
+ "srf_paramdesc_bardirection": "Spisaat durc'hadur ur grafik",
+ "srf_paramdesc_barnumbersaxislabel": "Tikedenn ahel an niveroù",
+ "srf-ui-gridview-label-item": "Elfenn roadenn",
+ "srf-ui-gridview-label-data-tab": "Roadennoù",
+ "srf-ui-gridview-label-info-tab": "Titouroù",
+ "srf_printername_gallery": "Skeudennaoueg",
+ "srf_paramdesc_perrow": "An niver a skeudennoù dre linenn",
+ "srf_paramdesc_widths": "Ledander ar skeudennoù",
+ "srf_paramdesc_heights": "Uhelder ar skeudennoù",
+ "srf_paramdesc_autocaptions": "Ober gant anv ar restr da alc'hwez ma n'eus ket bet resisaet hini",
+ "srf-gallery-navigation-previous": "Kent",
+ "srf-gallery-navigation-next": "War-lerc'h",
+ "srf-gallery-overlay-count": "Skeudenn $1 diwar $2",
+ "srf-gallery-image-url-error": "N'eo ket bet kavet ar skeudenn.",
+ "srf_printername_tagcloud": "Nivlennad tikedennoù",
+ "srf_paramdesc_includesubject": "Ma tlefer lakaat e-barzh anv an danvezioù o-unan",
+ "srf_paramdesc_increase": "Penaos kreskiñ ment an tikedennoù",
+ "srf_paramdesc_tagorder": "Urzh an tikedennoù",
+ "srf_paramdesc_mincount": "An niver bihanañ a wechoù ma rank un dalvoudenn bezañ implijet a-benn bezañ rollet",
+ "srf_paramdesc_minsize": "Ment an dikedenn vihanañ e dregantad",
+ "srf_paramdesc_maxsize": "Ment an dikedenn vrasañ e dregantad",
+ "srf_paramdesc_maxtags": "Niver brasañ a dikedennoù en nivlennad",
+ "srf_printername_array": "Taolenn",
+ "srf_printername_hash": "Hacherezh",
+ "srf-printername-graph": "Grafik",
+ "srf-paramdesc-graphname": "Titl",
+ "srf-paramdesc-graphsize": "Ment ar grafik (e px)",
+ "srf-paramdesc-graphlegend": "Diskouez alc'hwez ar grafik pe get",
+ "srf-paramdesc-graphlabel": "Tikedenn ar grafik",
+ "srf-paramdesc-rankdir": "Durc'hadur ar bir",
+ "srf-paramdesc-graphlink": "Liamm war-zu ar grafik",
+ "srf-paramdesc-graphcolor": "Liv ar grafik",
+ "srf-ui-datatables-label-parameters": "Arventennoù",
+ "srf-ui-datatables-label-information": "Titouroù",
+ "srf-ui-datatables-label-placeholder-column-search": "Klask...",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Arventennoù ar siloù",
+ "srf-ui-datatables-label-sLoadingRecords": "O kargañ...",
+ "srf-ui-datatables-label-sProcessing": "O tretañ...",
+ "srf-ui-datatables-label-sSearch": "Klask :",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Kentañ",
+ "srf-ui-datatables-label-oPaginate-sLast": "Diwezhañ",
+ "srf-ui-datatables-label-oPaginate-sNext": "War-lerc'h",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Kent",
+ "srf-printername-tree": "Gwezenn",
+ "srf-printername-ultree": "Gwezenn Ul",
+ "srf-tree-rootinvalid": "N'eo ket $1 un titl reizh evit ar bajenn.",
+ "srf-printername-slideshow": "Kinnig luc'hvannoù",
+ "srf-printername-filtered": "Silet",
+ "srf-filtered-selectorlabel-list": "Roll",
+ "srf-filtered-selectorlabel-table": "Taolenn",
+ "srf-filtered-selectorlabel-calendar": "Deiziadur",
+ "srf-filtered-selectorlabel-map": "Kartenn",
+ "srf-filtered-value-filter-and": "HA",
+ "srf-filtered-value-filter-or": "PE",
+ "srf-printername-d3chart": "Grafik 3M",
+ "srf-paramdesc-zoom": "Gweredekaat ar zoum",
+ "srf-ui-eventcalendar-label-today": "Hiziv",
+ "srf-ui-eventcalendar-label-month": "Miz",
+ "srf-ui-eventcalendar-label-week": "Sizhun",
+ "srf-ui-eventcalendar-label-day": "Deiz",
+ "srf-ui-eventcalendar-label-allday": "A-hed an deiz",
+ "srf-paramdesc-unit": "Unvez",
+ "srf-ui-mediaplayer-label-previous": "Kent",
+ "srf-ui-mediaplayer-label-play": "Lenn",
+ "srf-ui-mediaplayer-label-pause": "Ehanañ",
+ "srf-ui-mediaplayer-label-next": "War-lerc'h",
+ "srf-ui-mediaplayer-label-stop": "Paouez",
+ "srf-ui-mediaplayer-label-mute": "Hep son",
+ "srf-ui-mediaplayer-label-unmute": "Gant son",
+ "srf-ui-mediaplayer-label-repeat": "Adober",
+ "srf-ui-mediaplayer-label-full-screen": "Skramm leun",
+ "srf-ui-mediaplayer-label-restore-screen": "Assevel ar skramm"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/bs.json b/www/wiki/extensions/SemanticResultFormats/i18n/bs.json
new file mode 100644
index 00000000..38fa85cc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/bs.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator",
+ "KWiki"
+ ]
+ },
+ "srf-desc": "Dodatni formati za linijske upite na Semantic MediaWiki",
+ "srf-name": "Formati semantiÄkih rezultata",
+ "srfc_previousmonth": "Prethodni mjesec",
+ "srfc_nextmonth": "Sljedeći mjesec",
+ "srfc_today": "Danas",
+ "srfc_gotomonth": "Idi na mjesec",
+ "srf_printername_calendar": "MjeseÄni kalendar",
+ "srf_printername_vcard": "Izvoz u vCard",
+ "srf_printername_icalendar": "Izvoz u iCalendar",
+ "srf_paramdesc_icalendartitle": "Naslov datoteke kalendara",
+ "srf_printername_bibtex": "Izvoz u BibTeX",
+ "srf_outline_novalue": "Nema vrijednosti",
+ "srf_printername_outline": "Kontura",
+ "srf_printername_sum": "Zbir brojeva",
+ "srf_printername_average": "Prosjek brojeva",
+ "srf_printername_max": "Najveći broj",
+ "srf_printername_min": "Najmanji broj",
+ "srf_paramdesc_limit": "Najveći broj stranica za upit",
+ "srf_printername_timeline": "Vremenska linija",
+ "srf_printername_eventline": "Linija događaja",
+ "srf_paramdesc_timelinesize": "Visina vremenske linije"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ca.json b/www/wiki/extensions/SemanticResultFormats/i18n/ca.json
new file mode 100644
index 00000000..b20e83ef
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ca.json
@@ -0,0 +1,133 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dvdgmz",
+ "Paucabot",
+ "Toniher",
+ "Ssola",
+ "Macofe",
+ "Fitoschido"
+ ]
+ },
+ "srf-desc": "Formats addicionals per a les consultes en línia del Semantic MediaWiki.",
+ "prefs-srf": "Formats de resultats semàntics",
+ "srf-module-loading": "S'està carregant...",
+ "srf-paramdesc-height": "Alçada",
+ "srf-paramdesc-width": "Amplada",
+ "srf-paramdesc-class": "Especifiqueu una classe CSS addicional",
+ "srf-module-nomatch": "No s'han trobat coincidències",
+ "srf-paramdesc-charttype": "Tipus de gràfic disponible",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "Ant",
+ "srf-ui-navigation-next": "Següent",
+ "srf-ui-common-label-source": "Origen",
+ "srf-ui-common-label-datasource": "Origen de dades",
+ "srf-ui-common-label-parameters": "Paràmetres",
+ "srf-ui-common-label-daterange": "Interval de dates",
+ "srfc_previousmonth": "Mes anterior",
+ "srfc_nextmonth": "Mes posterior",
+ "srfc_today": "Avui",
+ "srfc_gotomonth": "Vés al mes",
+ "srf_printername_calendar": "Calendari mensual",
+ "srf_paramdesc_calendarlang": "El codi de la llengua en què es mostrarà el calendari",
+ "srf_printername_vcard": "Exportació vCard",
+ "srf_printername_icalendar": "Exportació iCalendar",
+ "srf_paramdesc_icalendartitle": "El títol del fitxer del calendari",
+ "srf_paramdesc_icalendardescription": "La descripció del fitxer del calendari",
+ "srf_printername_bibtex": "Exportació BibTeX",
+ "srf_outline_novalue": "Sense valor",
+ "srf_printername_sum": "Suma dels nombres",
+ "srf_printername_average": "Mitjana dels nombres",
+ "srf_printername_max": "Nombre màxim",
+ "srf_printername_min": "Nombre mínim",
+ "srf_paramdesc_limit": "El nombre màxim de pàgines per consultar",
+ "srf_printername_product": "Producte de nombres",
+ "srf_printername_median": "Mediana de nombres",
+ "srf_printername_timeline": "Línia temporal",
+ "srf_printername_eventline": "Línia d'esdeveniments",
+ "srf_paramdesc_timelinebands": "Defineix quines bandes es mostren en el resultat.",
+ "srf_paramdesc_timelineposition": "Defineix on s'enfoca inicialment la línia temporal.",
+ "srf_paramdesc_timelinesize": "La llargada de la línia de temps",
+ "srf-timeline-allresults": "Més resultats d'aquesta consulta.",
+ "srf_paramdesc_lens": "El nom d'una plantilla amb què mostrar les propietats de la pàgina",
+ "srf_paramdesc_barnumbersaxislabel": "L'etiqueta de l'eix de nombres",
+ "srf-ui-gridview-label-series": "Sèrie de dades",
+ "srf-ui-gridview-label-data-tab": "Dades",
+ "srf-ui-gridview-label-info-tab": "Informació",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_perrow": "El nombre d'imatges per fila",
+ "srf_paramdesc_widths": "L'amplada de les imatges",
+ "srf_paramdesc_heights": "L'alçada de les imatges",
+ "srf_paramdesc_autocaptions": "Utilitza el nom de fitxer com a llegenda quan no se'n proporcioni cap",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Següent",
+ "srf-gallery-overlay-count": "Imatge $1/$2",
+ "srf-gallery-image-url-error": "No s’ha trobat la imatge.",
+ "srf_printername_tagcloud": "Núvol d'etiquetes",
+ "srf_paramdesc_increase": "Com augmentar la mida de les etiquetes",
+ "srf_paramdesc_tagorder": "L'ordre de les etiquetes",
+ "srf_paramdesc_maxtags": "El nombre màxim d'etiquetes en el núvol",
+ "srf_paramdesc_propsep": "Separador entre les propietats sol·licitades",
+ "srf_paramdesc_manysep": "Separador entre moltes propietats amb valor",
+ "srf_paramdesc_recordsep": "Separador entre els valors de les propietats de registre",
+ "srf-printername-graph": "Gràfic",
+ "srf-paramdesc-graph-nodeshape": "La forma de cada node en el gràfic",
+ "srf-paramdesc-graphname": "Defineix el títol del gràfic",
+ "srf-paramdesc-graphsize": "Mida del gràfic (en px)",
+ "srf-paramdesc-graphlabel": "Etiqueta del gràfic",
+ "srf-paramdesc-rankdir": "Direcció de la fletxa",
+ "srf-paramdesc-graphlink": "Enllaç del gràfic",
+ "srf-paramdesc-graphcolor": "Defineix el color del gràfic",
+ "srf-ui-datatables-label-conditions": "Condicions",
+ "srf-ui-datatables-label-parameters": "Paràmetres",
+ "srf-ui-datatables-label-information": "Informació",
+ "srf-ui-datatables-label-placeholder-column-search": "Cerca…",
+ "srf-ui-datatables-label-content-cache": "El contingut s’ha derivat de la memòria cau.",
+ "srf-ui-datatables-label-content-server": "El contingut s’ha derivat del servidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Columnes disponibles",
+ "srf-ui-datatables-label-sLoadingRecords": "S’està carregant…",
+ "srf-ui-datatables-label-sProcessing": "S’està processant…",
+ "srf-ui-datatables-label-sSearch": "Cerca:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primer",
+ "srf-ui-datatables-label-oPaginate-sLast": "Darrer",
+ "srf-ui-datatables-label-oPaginate-sNext": "Següent",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-printername-tree": "Arbre",
+ "srf-printername-ultree": "Arbre UL",
+ "srf-printername-oltree": "Arbre OL",
+ "srf-tree-rootinvalid": "$1 no és un títol de pàgina vàlid.",
+ "srf-paramdesc-filtered-filter-position": "La posició dels filtres en relació amb les visualitzacions. Valors permesos: «top», «bottom». Per defecte: «top».",
+ "srf-paramdesc-filtered-list-type": "El tipus de la llista. Valors permesos: «list», «ul», «ol». Per defecte: «list».",
+ "srf-paramdesc-filtered-map-height": "L’alçada del mapa.",
+ "srf-filtered-selectorlabel-list": "Llista",
+ "srf-filtered-selectorlabel-table": "Taula",
+ "srf-filtered-selectorlabel-calendar": "Calendari",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-paramdesc-datatable": "Habilita una base de dades",
+ "srf-paramdesc-pageitems": "Elements per pàgina",
+ "srf-printername-eventcalendar": "Calendari d’esdeveniments",
+ "srf-ui-eventcalendar-label-today": "Avui",
+ "srf-ui-eventcalendar-label-month": "Mes",
+ "srf-ui-eventcalendar-label-week": "Setmana",
+ "srf-ui-eventcalendar-label-day": "Dia",
+ "srf-ui-eventcalendar-label-listmonth": "Mes (llista)",
+ "srf-ui-eventcalendar-label-listweek": "Setmana (llista)",
+ "srf-ui-eventcalendar-label-listday": "Dia (llista)",
+ "srf-ui-eventcalendar-label-allday": "Tot el dia",
+ "srf-paramdesc-unit": "Unitat",
+ "srf-printername-media": "Reproductor multimèdia",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reprodueix",
+ "srf-ui-mediaplayer-label-pause": "Posa en pausa",
+ "srf-ui-mediaplayer-label-next": "Següent",
+ "srf-ui-mediaplayer-label-stop": "Atura",
+ "srf-ui-mediaplayer-label-mute": "Emmudeix",
+ "srf-ui-mediaplayer-label-unmute": "Habilita el so",
+ "srf-ui-mediaplayer-label-volume-max": "Volum màxim",
+ "srf-ui-mediaplayer-label-shuffle": "Mescla",
+ "srf-ui-mediaplayer-label-shuffle-off": "Mescla apagada",
+ "srf-ui-mediaplayer-label-repeat": "Repeteix",
+ "srf-ui-mediaplayer-label-repeat-off": "Repetició apagada",
+ "srf-ui-mediaplayer-label-full-screen": "Pantalla sencera",
+ "srf-ui-mediaplayer-label-restore-screen": "Restaura la pantalla"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ce.json b/www/wiki/extensions/SemanticResultFormats/i18n/ce.json
new file mode 100644
index 00000000..de324dff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ce.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "Умар"
+ ]
+ },
+ "prefs-srf-datatables-options": "DataTables ниÑÑÑ€",
+ "srf-module-loading": "Чуйолуш...",
+ "srf-paramdesc-height": "Локхалла",
+ "srf-paramdesc-width": "Шоралла",
+ "srf-ui-common-label-source": "ХьоÑÑ‚",
+ "srf-ui-tooltip-title-options": "Параметраш",
+ "srf-ui-tooltip-title-legend": "Легенда",
+ "srf-ui-tooltip-title-filter": "Луьттург",
+ "srf-ui-common-label-refresh": "КарлаÑккха",
+ "srf-ui-common-label-parameters": "Параметраш",
+ "srf-ui-common-label-query": "Дехар",
+ "srf-ui-common-label-paneview": "ÐгӀонашка хьаьжина",
+ "srf_paramdesc_charttitle": "Диаграммин цӀе",
+ "srf-ui-gridview-label-info-tab": "Хаам",
+ "srf_paramdesc_heights": "Суьртан локхалла",
+ "srf-gallery-navigation-previous": "Хьалха йоьдург",
+ "srf-gallery-navigation-next": "ТӀаьхьа йогӀург",
+ "srf_paramdesc_graphname": "Корта",
+ "srf-ui-datatables-label-conditions": "Хьал",
+ "srf-ui-datatables-label-parameters": "Параметраш",
+ "srf-ui-datatables-label-information": "Хаам",
+ "srf-ui-datatables-label-placeholder-column-search": "Лоьху...",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Литтаран ниÑÑрш",
+ "srf-ui-datatables-label-sLoadingRecords": "Чуйолуш...",
+ "srf-ui-datatables-label-sProcessing": "Кечдар...",
+ "srf-ui-datatables-label-sSearch": "Лахар:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "ЦхьалгӀаниг",
+ "srf-ui-datatables-label-oPaginate-sLast": "ТӀехьарниг",
+ "srf-ui-datatables-label-oPaginate-sNext": "ТӀаьхьа йогӀург",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Хьалха йоьдург",
+ "srf-filtered-selectorlabel-table": "Таблица",
+ "srf-ui-mediaplayer-label-play": "ЙолаÑлита",
+ "srf-ui-mediaplayer-label-next": "Кхин дӀа",
+ "srf-excel-link": "Excel"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/co.json b/www/wiki/extensions/SemanticResultFormats/i18n/co.json
new file mode 100644
index 00000000..2cbb9797
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/co.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Paulu"
+ ]
+ },
+ "srf-ui-gridview-label-item": "Elementu dati"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/cs.json b/www/wiki/extensions/SemanticResultFormats/i18n/cs.json
new file mode 100644
index 00000000..42824070
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/cs.json
@@ -0,0 +1,330 @@
+{
+ "@metadata": {
+ "authors": [
+ "Vks",
+ "XenoPheX",
+ "Dvorapa",
+ "Jaroslav Cerny",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Další formáty inline požadavků rozšíření Semantic MediaWiki",
+ "prefs-srf": "Rozšíření:Formáty sémantických výsledků",
+ "srf-prefs-intro-text": "Nainstalovali jste si rozšíření Formáty sémantických výsledků. Podporu k tomuto rozšíření najdete na stránce nápovědy [https://www.semantic-mediawiki.org/wiki/Help:Result_formats k formátům výsledků].",
+ "prefs-srf-eventcalendar-options": "Volby kalendáře událostí",
+ "srf-prefs-eventcalendar-options-update-default": "Povolit [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatické aktualizace] událostí kalendáře během aktualizace stránky",
+ "srf-prefs-eventcalendar-options-paneview-default": "Povolit implicitně zobrazení podokna",
+ "prefs-srf-datatables-options": "Volby datových tabulek",
+ "srf-prefs-datatables-options-update-default": "Povolit [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatické aktualizace] obsahu tabulky během aktualizace stránky",
+ "srf-prefs-datatables-options-cache-default": "Povolit [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage místní úložiÅ¡tÄ›] pro zkrácení Äasu odezvy",
+ "srf-module-loading": "NaÄítání...",
+ "srf-paramdesc-layout": "Dostupné rozložení",
+ "srf-paramdesc-height": "Výška",
+ "srf-paramdesc-width": "Šířka",
+ "srf-paramdesc-class": "Zadejte další třídu stylu CSS",
+ "srf-module-nomatch": "Nenalezena žádná shoda",
+ "srf-paramdesc-charttype": "Dostupný typ grafu",
+ "srf-navigation-previous": "Předchozí",
+ "srf-ui-navigation-prev": "Předch.",
+ "srf-ui-navigation-next": "Další",
+ "srf-ui-common-label-source": "Zdroj",
+ "srf-ui-common-label-datasource": "Zdroj dat",
+ "srf-ui-common-label-ajax-error": "Server ohlásil nezdařenou komunikaci pro toto $1. Zkuste obnovit stránku nebo se obraťte na $2.",
+ "srf-ui-common-label-request-object": "objekt požadavku",
+ "srf-ui-common-label-help-section": "Äást nápovÄ›dy",
+ "srf-ui-tooltip-title-options": "Nastavení",
+ "srf-ui-tooltip-title-scope": "Rozsah",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtr",
+ "srf-ui-common-label-refresh": "Obnovit",
+ "srf-ui-common-label-parameters": "Parametry",
+ "srf-ui-common-label-query": "Dotaz",
+ "srf-ui-common-label-paneview": "Zobrazení podokna",
+ "srf-ui-common-label-daterange": "Časové období",
+ "srf-ui-widgets-label-parameter-limit": "Parametr limitu",
+ "srf-error-option-mix": "Volba ($1) není dostupná",
+ "srf-error-option-link-all": "Volba ($1) vyžaduje, aby parametr \"link\" měl hodnotu \"all\"",
+ "srf-error-missing-layout": "Diagram nebo graf nelze zobrazit, protože chybí rozložení.",
+ "srf-error-jqplot-bubble-data-length": "Diagram nebo graf nelze zobrazit, protože chybí data.",
+ "srf-error-jqplot-stackseries-data-length": "Diagram nebo graf nelze zobrazit, protože pruhy nebo Äáry nemají shodný poÄet prvků.",
+ "srf-warn-empy-chart": "Diagram nebo graf je prázdný, protože chybí data.",
+ "srf-paramdesc-color": "Barva položek kalendáře",
+ "srfc_previousmonth": "Předchozí měsíc",
+ "srfc_nextmonth": "Další měsíc",
+ "srfc_today": "Dnes",
+ "srfc_gotomonth": "Přejdi na měsíc",
+ "srf_printername_calendar": "MÄ›síÄní kalendář",
+ "srf_paramdesc_calendarlang": "Kód jazyka, ve kteréem bude zobrazován kalendář",
+ "srf_paramdesc_calendarcolors": "Barva jednotlivých datových vlastností (příklad: \"Datum zaÄátku=>green,Datum konce=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "PoÄáteÄní zobrazený mÄ›síc kalendáře (výchozí = aktuální mÄ›síc)",
+ "srf-paramdesc-calendar-startyear": "PoÄáteÄní zobrazený rok kalendáře (výchozí = aktuální rok)",
+ "srf_printername_vcard": "export vCard",
+ "srf_printername_icalendar": "export iCalendar",
+ "srf_paramdesc_icalendartitle": "titulek souboru s kalendářem",
+ "srf_paramdesc_icalendardescription": "Popisek souboru s kalendářem",
+ "srf_printername_bibtex": "export BibTeX",
+ "srf_outline_novalue": "Žádná hodnota",
+ "srf_printername_outline": "NáÄrtek",
+ "srf_paramdesc_outlineproperties": "Seznam vlastností, které budou zobrazeny jako záhlaví osnovy, oddÄ›lené Äárkami",
+ "srf_printername_sum": "SouÄet Äísel",
+ "srf_printername_average": "PrůmÄ›r Äísel",
+ "srf_printername_max": "Maximum mezi Äísly",
+ "srf_printername_min": "Minimum mezi Äísly",
+ "srf_paramdesc_limit": "Maximální poÄet stránek zahrnutých do dotazu",
+ "srf_printername_product": "SouÄin Äísel",
+ "srf_printername_median": "Medián Äísel",
+ "srf-paramdesc-default": "Výchozí hodnota, která se zobrazí, když neexistují žádné Äíselné výsledky",
+ "srf_printername_earliest": "NejdřívÄ›jší Äas",
+ "srf_printername_latest": "NejpozdÄ›jší Äas",
+ "srf_printername_timeline": "Časová osa",
+ "srf_printername_eventline": "Časová osa událostí",
+ "srf_paramdesc_timelinebands": "UrÄuje, které pruhy jsou zobrazeny ve výsledku.",
+ "srf_paramdesc_timelineposition": "UrÄuje událost, na kterou se Äasová osa na zaÄátku vystÅ™edí.",
+ "srf_paramdesc_timelinestart": "Název vlastnosti použité k definování prvního Äasového bodu",
+ "srf_paramdesc_timelineend": "Název vlastnosti použité k definování druhého Äasového bodu",
+ "srf_paramdesc_timelinesize": "Výška Äasové osy",
+ "srf-timeline-allresults": "Další výsledky pro tento dotaz.",
+ "srf-timeline-nojs": "K zobrazení interaktivní Äasové osy musíte mít povolen JavaScript.",
+ "srf_paramdesc_views": "Zobrazené pohledy",
+ "srf_paramdesc_facets": "Sada vlastností zobrazených na každé stránce",
+ "srf_paramdesc_lens": "Název šablony, přes kterou se zobrazí vlastnosti stránky",
+ "srf_printername_googlebar": "Pruhový graf Google",
+ "srf_printername_googlepie": "VýseÄový graf Google",
+ "srf-printername-jqplotchart": "Graf jqPlot",
+ "srf-printername-jqplotseries": "Řada jqPlot",
+ "srf_paramdesc_chartheight": "UrÄuje výšku diagramu nebo grafu (v pixelech)",
+ "srf_paramdesc_chartwidth": "UrÄuje šířku diagramu nebo grafu (v pixelech nebo procentech)",
+ "srf_paramdesc_charttitle": "Název grafu",
+ "srf_paramdesc_barcolor": "UrÄuje barvy grafu",
+ "srf_paramdesc_bardirection": "UrÄuje smÄ›r grafu",
+ "srf-paramdesc-direction": "UrÄuje smÄ›r diagramu nebo grafu",
+ "srf_paramdesc_barnumbersaxislabel": "Popisek osy Äísel",
+ "srf-paramdesc-labelaxislabel": "Popisek osy popisků",
+ "srf-paramdesc-ticklabels": "Povolit zobrazení popisků znaÄek",
+ "srf-paramdesc-minvalue": "Minimální hodnota zobrazená na ose Y",
+ "srf-paramdesc-pointlabels": "Zobrazit datové body definované v grafu",
+ "srf-paramdesc-chartlegend": "Umístění legendy grafu",
+ "srf-paramdesc-datalabels": "Popisky dat diagramu/grafu",
+ "srf-paramdesc-charttext": "Popisný text grafu",
+ "srf-paramdesc-chartclass": "Další třída CSS",
+ "srf-paramdesc-renderer": "Vyberte vykreslovaÄ diagramu/grafu",
+ "srf-paramdesc-filling": "Individuální volba výplně",
+ "srf-paramdesc-theme": "Vyberte motiv mřížky",
+ "srf-paramdesc-chartcolor": "Přiřadit individuální barvy grafu",
+ "srf-paramdesc-colorscheme": "Vyberte barevné schéma",
+ "srf-paramdesc-valueformat": "UrÄuje pravidlo formátování hodnot",
+ "srf-paramdesc-highlighter": "Zobrazit zvýrazňovaÄ datového bodu",
+ "srf-paramdesc-smoothlines": "Použít algoritmus vyhlazování ve spojnicových grafech",
+ "srf-paramdesc-stackseries": "Zobrazit graf jako skládané řady",
+ "srf-paramdesc-seriesgroup": "Vybrat seskupení řad",
+ "srf-paramdesc-serieslabel": "UrÄuje popisek Å™ady",
+ "srf-paramdesc-grouplabel": "UrÄuje popisek skupiny",
+ "srf-paramdesc-chartcursor": "Volba zobrazení ukazatele v grafu",
+ "srf-paramdesc-trendline": "Povolit souÄasné zobrazení grafu a jeho spojnice trendu",
+ "srf-paramdesc-gridview": "Zobrazit souÄasnÄ› graf i sady dat. Povolené hodnoty: \"none\" a \"tabs\". Výchozí hodnota: \"none\"",
+ "srf-paramdesc-paneview": "UrÄuje umístÄ›ní podokna s malým spojnicovým grafem. Povolené hodnoty: \"bottom\", \"top\" a \"none\". Výchozí hodnota: \"bottom\"",
+ "srf-paramdesc-infotext": "Zobrazit další informace na odpovídající informaÄní záložce",
+ "srf-paramdesc-clicktarget": "Definuje stránku nebo řetězec dotazu jako cíl kliknutí na datum v kalendáři.",
+ "srf-ui-gridview-label-item": "Datová položka",
+ "srf-ui-gridview-label-value": "Datová hodnota",
+ "srf-ui-gridview-label-series": "Datová řada",
+ "srf-ui-gridview-label-chart-tab": "Graf",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Informace",
+ "srf_printername_gallery": "Galerie",
+ "srf_paramdesc_perrow": "PoÄet obrázků na 1 řádek",
+ "srf_paramdesc_widths": "Šířka obrázků",
+ "srf_paramdesc_heights": "Výška obrázků",
+ "srf_paramdesc_autocaptions": "Použít název souboru jako titulek, není-li žádný zadán",
+ "srf_paramdesc_fileextensions": "Při použití názvu souboru jako titulku zobrazit také příponu souboru",
+ "srf_paramdesc_captionproperty": "Název sémantické vlastnosti přítomné v dotazovaných stránkách, které budou použity jako titulek",
+ "srf_paramdesc_imageproperty": "Název sémantické vlastnosti přítomné v dotazovaných stránkách, která odkazuje na používané obrázky. Je-li vlastnost nastavena, nebudou dotazované stránky zobrazeny jako obrázky",
+ "srf-paramdesc-redirects": "Název sémantické vlastnosti přítomné v dotazovaných stránkách, která obsahuje cíl přesměrování",
+ "srf-paramdesc-navigation": "Ovládací prvek rozložení výstupu",
+ "srf-paramdesc-overlay": "Povolit překrytí obrázků",
+ "srf-gallery-navigation-previous": "Předchozí",
+ "srf-gallery-navigation-next": "Následujicí",
+ "srf-gallery-overlay-count": "Obrázek $1 z $2",
+ "srf-gallery-image-url-error": "Obrázek nebyl nalezen.",
+ "srf_printername_tagcloud": "Oblak nálepek",
+ "srf_paramdesc_includesubject": "Zahrnout také názvy předmětů",
+ "srf_paramdesc_increase": "Jak zvÄ›tÅ¡it velikost znaÄek",
+ "srf_paramdesc_tagorder": "PoÅ™adí znaÄek",
+ "srf_paramdesc_mincount": "Minimální poÄet výskytů hodnoty k zaÅ™azení do seznamu",
+ "srf_paramdesc_minsize": "Velikost nejmenších znaÄek v procentech",
+ "srf_paramdesc_maxsize": "Velikost nejvÄ›tších znaÄek v procentech",
+ "srf_paramdesc_maxtags": "Maximální poÄet znaÄek v cloudu",
+ "srf-paramdesc-excludetags": "VylouÄit znaÄky (oddÄ›lovaÄ: \";\")",
+ "srf_printername_valuerank": "Postavení znaÄky",
+ "srf_printername_array": "Pole",
+ "srf_paramdesc_pagetitle": "Mají být zobrazeny nadpisy stránek jako položky ve výstupu, nebo vynechány?",
+ "srf_paramdesc_hidegaps": "Mají být tiÅ¡tÄ›ny a oddÄ›leny pomocí oddÄ›lovaÄů vyžadované, ale nedostupné hodnoty vlastností a záznamů, nebo vynechány?",
+ "srf_paramdesc_arrayname": "Je-li zadáno a je-li dostupné rozšíření ArrayExtension, vytvoří se pole se zadaným názvem (bez viditelného výstupu)",
+ "srf_paramdesc_propsep": "OddÄ›lovaÄ mezi požadovanými vlastnostmi",
+ "srf_paramdesc_manysep": "OddÄ›lovaÄ mezi hodnotami vícehodnotových vlastností",
+ "srf_paramdesc_recordsep": "OddÄ›lovaÄ mezi hodnotami vlastností záznamu",
+ "srf_paramdesc_headersep": "OddÄ›lovaÄ mezi názvem vlastnosti a hodnotou, když je \"headers\" nastaveno na \"show\" nebo \"plain\"",
+ "srf_printername_hash": "Asociativní pole (Haš)",
+ "srf_paramdesc_hashname": "Je-li zadáno a je-li dostupné rozšíření HashTables, vytvoří se hash se zadaným názvem (bez viditelného výstupu)",
+ "srf-printername-graph": "Graf",
+ "srf-paramdesc-graph-relation": "UrÄuje, zda pÅ™edmÄ›ty nebo vlastnosti názvů jsou nadřízené Äi podřízené prvky",
+ "srf-paramdesc-graph-nameprop": "Nastaví vlastnost, která bude použita jako pÅ™edmÄ›t namísto skuteÄného pÅ™edmÄ›tu, napÅ™. název stránky",
+ "srf-paramdesc-graph-nodeshape": "Nastaví tvar všech uzlů ve grafu",
+ "srf-paramdesc-graphname": "Nastaví název grafu",
+ "srf-paramdesc-graphsize": "Nastaví velikost grafu v pixelech",
+ "srf-paramdesc-graphlegend": "UrÄuje, zda bude zobrazena legenda grafu",
+ "srf-paramdesc-graphlabel": "Nastaví popisek grafu",
+ "srf-paramdesc-rankdir": "Nastaví směr šipek",
+ "srf-paramdesc-graphlink": "UrÄuje, zda mají uzly odkazovat na přísluÅ¡né wiki stránky",
+ "srf-paramdesc-graphcolor": "Nastaví barvu grafu",
+ "srf-paramdesc-graph-wwl": "Nastaví limit zalomení slova (jako poÄet znaků)",
+ "srf-paramdesc-clustercolor": "Nastaví barvy rámeÄků shluku",
+ "srf-paramdesc-highlight": "UrÄí uzel, který bude zvýraznÄ›n",
+ "srf-paramdesc-highlightcolor": "Nastaví barvu písma zvýrazněného uzlu",
+ "srf-paramdesc-redlinkcolor": "Nastaví barvu písma odkazů na neexistující stránky",
+ "srf-paramdesc-processcategory": "Nastaví kategorii wiki, která bude shromažÄovat procesní kroky",
+ "srf-paramdesc-showroles": "Zobrazí odpovídající role v grafu",
+ "srf-paramdesc-showstatus": "UrÄuje, zda má být vykreslen stav procesního kroku",
+ "srf-paramdesc-showresources": "Zobrazí v grafu odpovídající zdroje",
+ "srf-paramdesc-showdiscussion": "UrÄuje, zda má být vykreslena diskuze",
+ "srf-paramdesc-showredlinks": "UrÄuje, zda budou odkazy na neexistující stránky zaÅ¡krtnuty a zvýraznÄ›ny",
+ "srf-paramdesc-showcompound": "UrÄuje, zda mají být zvýraznÄ›ny složené uzly, napÅ™. dílÄí procesy",
+ "srf-paramdesc-debug": "UrÄuje, zda má být kód grafu procesů zobrazen uvnitÅ™ znaÄek PRE",
+ "srf-paramdesc-graphvalidation": "Zobrazí ÄervenÄ› ty procesní kroky, které nemají pÅ™iÅ™azenou roli",
+ "srf-printername-datatables": "Datové tabulky",
+ "srf-ui-datatables-label-conditions": "Podmínky",
+ "srf-ui-datatables-label-parameters": "Parametry",
+ "srf-ui-datatables-label-filters": "Filtry sloupce a hledání",
+ "srf-ui-datatables-label-information": "Informace",
+ "srf-ui-datatables-panel-disclaimer": "Parametry a podmínky lze zmÄ›nit, ale vÅ¡echny zmÄ›ny jsou doÄasné a po aktualizaci stránky se ztratí",
+ "srf-ui-datatables-label-update-success": "Aktualizace tabulky byla úspěšná",
+ "srf-ui-datatables-label-update-error": "Aktualizace tabulky selhala.",
+ "srf-ui-datatables-label-placeholder-column-search": "Hledat...",
+ "srf-ui-datatables-label-content-cache": "Obsah byl odvozen z místní cache.",
+ "srf-ui-datatables-label-content-server": "Obsah byl odvozen ze serveru.",
+ "srf-ui-datatables-label-multiselect-column-header": "Dostupné sloupce",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Nastavení filtru",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Sloupce jsou vidět",
+ "srf-ui-datatables-label-sEmptyTable": "V tabulce nejsou dostupná žádná data",
+ "srf-ui-datatables-label-sInfo": "Zobrazují se položky _START_ až _END_ z _TOTAL_ celkem",
+ "srf-ui-datatables-label-sInfoEmpty": "Zobrazují se položky 0 až 0 z 0 celkem",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtrováno z _MAX_ položek celkem)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Zobrazují se položky _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "NaÄítání...",
+ "srf-ui-datatables-label-sProcessing": "Zpracovává se...",
+ "srf-ui-datatables-label-sSearch": "Hledat:",
+ "srf-ui-datatables-label-sZeroRecords": "Nenalezeny žádné odpovídající záznamy",
+ "srf-ui-datatables-label-oPaginate-sFirst": "První",
+ "srf-ui-datatables-label-oPaginate-sLast": "Poslední",
+ "srf-ui-datatables-label-oPaginate-sNext": "Další",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Předchozí",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": po aktivaci bude sloupec seřazen vzestupně",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": po aktivaci bude sloupec seřazen sestupně",
+ "srf-printername-tree": "Strom",
+ "srf-printername-ultree": "Funkce UItree",
+ "srf-printername-oltree": "Funkce OItree",
+ "srf-tree-noparentprop": "není zadána nadřízená vlastnost. Strom nelze vytvoÅ™it bez urÄené nadřízené vlastnosti.",
+ "srf-tree-rootinvalid": "$1 není platný nadpis stránky.",
+ "srf-tree-circledetected": "Při pokusu o vložení $1 do stromu byl rozpoznán kruhový odkaz.",
+ "srf-paramdesc-tree-parent": "Vlastnost obsahující nadřízenou stránku",
+ "srf-paramdesc-tree-root": "Kořenová stránka stromu",
+ "srf-paramdesc-tree-startlevel": "PoÄáteÄní úroveň stromu, napÅ™. pro integraci do jiného stromu",
+ "srf-printername-slideshow": "Prezentace",
+ "srf-paramdesc-delay": "Prodleva mezi snímky v sekundách",
+ "srf-paramdesc-navigation-controls": "Zobrazit navigaÄní prvky nebo ne",
+ "srf-paramdesc-effect": "Efekt použitý při přechodu ze snímku na další snímek",
+ "srf-printername-filtered": "Filtrováno",
+ "srf-paramdesc-filtered-views": "Pohledy, které mají být dostupné v zobrazení výsledků.",
+ "srf-paramdesc-filtered-filter-position": "Pozice filtrů ve vztahu k zobrazením. Povolené hodnoty: \"top\", \"bottom\". Default: \"top\".",
+ "srf-paramdesc-filtered-list-type": "Typ seznamu. Povolené hodnoty: \"list\", \"ul\", \"ol\". Výchozí: \"list\".",
+ "srf-paramdesc-filtered-list-template": "Šablona, která bude použita pro formátování položek seznamu.",
+ "srf-paramdesc-filtered-list-named-args": "Název argumentu předaného do šablony.",
+ "srf-paramdesc-filtered-list-introtemplate": "Název šablony, která se zobrazí před výsledky dotazu, pokud nějaké jsou.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Název šablony, která se zobrazí za výsledky dotazu, pokud nějaké jsou.",
+ "srf-paramdesc-filtered-calendar-start": "Výpis obsahující poÄáteÄní datum události.",
+ "srf-paramdesc-filtered-calendar-end": "Výpis obsahující koncové datum události.",
+ "srf-paramdesc-filtered-calendar-title": "Výpis obsahující nadpis události. Nelze použít spolu se šablonou nadpisu.",
+ "srf-paramdesc-filtered-calendar-title-template": "Šablona použitá k formátování nadpisu událostí v kalendáři.",
+ "srf-paramdesc-filtered-map-position": "Výpis obsahující geografické umístění.",
+ "srf-paramdesc-filtered-map-icon": "Výpis urÄující použitou ikonu mapy.",
+ "srf-paramdesc-filtered-map-icons": "Mapování hodnot na ikony, které bude použito pro tyto hodnoty v mapě.",
+ "srf-paramdesc-filtered-map-height": "Výška mapy.",
+ "srf-paramdesc-filtered-map-zoom": "Úroveň pÅ™iblížení pÅ™i naÄtení mapy. Uživatel může tento údaj zmÄ›nit.<br>Viz: <i>minimální pÅ™iblížení zobrazení mapy</i> a <i>maximální pÅ™iblížení zobrazení mapy</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "Minimální volitelná úroveň přiblížení mapy",
+ "srf-paramdesc-filtered-map-max-zoom": "Maximální volitelná úroveň přiblížení mapy",
+ "srf-paramdesc-filtered-map-marker-cluster": "Vypne nebo zapne shlukování znaÄek.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Maximální úroveň pÅ™iblížení, ve které jsou znaÄky mapÄ› stále ve shlucích. Nad touto úrovní budou znaÄky vždy samostatnÄ›.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "Maximální polomÄ›r oblasti zabrané shlukem od centrální znaÄky (v obrazových bodech). Výchozí hodnota je 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Je-li zapnuto, shluk se po kliknutí zvětší tak, že pokryje celou zobrazenou plochu.",
+ "srf-filtered-selectorlabel-list": "Seznam",
+ "srf-filtered-selectorlabel-table": "Tabulka",
+ "srf-filtered-selectorlabel-calendar": "Kalendář",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "Výsledky nelze zobrazit, protože není zapnutý Javascript. Přejděte na $1.",
+ "srf-filtered-noscript-link-caption": "výsledky v tabulkovém formátu",
+ "srf-filtered-map-provider-missing-error": "Pro zobrazení mapy není zadán žádný poskytovatel.",
+ "srf-filtered-value-filter-and": "A",
+ "srf-filtered-value-filter-or": "NEBO",
+ "srf-filtered-value-filter-placeholder": "Vyberte hodnotu filtru",
+ "srf-printername-d3chart": "Graf D3",
+ "srf-printername-timeseries": "Graf Äasových Å™ad",
+ "srf-paramdesc-group": "Řady seskupeny podle",
+ "srf-paramdesc-zoom": "Povolit přiblížení",
+ "srf-paramdesc-datatable": "Povolit tabulku dat",
+ "srf-timeseries-zoom-out-of-range": "V rozsahu pÅ™iblížení nejsou žádná dostateÄná data",
+ "srf-printername-sparkline": "Minigraf",
+ "srf-printername-listwidget": "Widget seznamu",
+ "srf-paramdesc-listtype": "UrÄuje typ seznamu",
+ "srf-paramdesc-widget": "Dostupný widget",
+ "srf-paramdesc-pageitems": "Položek na stránku",
+ "srf-printername-eventcalendar": "Kalendář událostí",
+ "srf-paramdesc-calendarfirstday": "Den, kterým zaÄíná týden",
+ "srf-paramdesc-calendardefaultview": "Výchozí zobrazení po naÄtení kalendáře",
+ "srf-paramdesc-calendarstart": "ZaÄátek kalendáře (hodnoty typu datum nebo datum/Äas)",
+ "srf-paramdesc-calendarlegend": "UrÄuje umístÄ›ní legendy a volby pÅ™iÅ™azeného filtru",
+ "srf-paramdesc-dayview": "Aktivovat zobrazení dne kliknutím na Äíslo dne",
+ "srf-ui-eventcalendar-label-today": "Dnes",
+ "srf-ui-eventcalendar-label-month": "Měsíc",
+ "srf-ui-eventcalendar-label-week": "Týden",
+ "srf-ui-eventcalendar-label-day": "Den",
+ "srf-ui-eventcalendar-label-listmonth": "Měsíc (seznam)",
+ "srf-ui-eventcalendar-label-listweek": "Týden (seznam)",
+ "srf-ui-eventcalendar-label-listday": "Den (seznam)",
+ "srf-ui-eventcalendar-label-allday": "Celý den",
+ "srf-ui-eventcalendar-label-update-success": "Aktualizace kalendáře událostí byla úspěšná.",
+ "srf-ui-eventcalendar-label-update-error": "Aktualizace kalendáře událostí selhala.",
+ "srf-ui-eventcalendar-click-popup": "Chcete vytvořit událost?",
+ "srf-printername-dygraphs": "Graf knihovny Dygraphs",
+ "srf-paramdesc-datasource": "Zdroj, ze kterého jsou data dostupná. Povolené hodnoty: \"file\", \"raw\" a \"url\". Výchozí hodnota: \"file\"",
+ "srf-paramdesc-errorbar": "Použitá chybová úseÄka. Povolené hodnoty: \"fraction\" (intervaly důvÄ›ry pro hodnoty), \"sigma\" (standardní odchylka hodnot) a \"range\" (vlastní rozsah hodnot)",
+ "srf-paramdesc-movingaverage": "Zobrazí průmÄ›r za poÄet dnů (0 = žádný klouzavý průmÄ›r)",
+ "srf-paramdesc-yaxislabel": "Popisek, který se objeví na ose y",
+ "srf-paramdesc-xaxislabel": "Popisek, který se objeví na ose x",
+ "srf-paramdesc-unit": "Jednotka",
+ "srf-printername-pagewidget": "Widget stránky",
+ "srf-printername-incoming": "Příchozí vlastnosti",
+ "srf-paramdesc-count": "UrÄuje, zda má být evidován poÄet příchozích vlastností",
+ "srf-paramdesc-min": "Minimální nebo prahová hodnota",
+ "srf-paramdesc-excludeproperty": "VylouÄit vlastnost ze sady výsledků",
+ "srf-printername-media": "PÅ™ehrávaÄ médií",
+ "srf-paramdesc-mediainspector": "Zobrazuje detailní informace o zadaném mediálním prvku",
+ "srf-ui-mediaplayer-label-previous": "Předchozí",
+ "srf-ui-mediaplayer-label-play": "Přehrát",
+ "srf-ui-mediaplayer-label-pause": "Pozastavit",
+ "srf-ui-mediaplayer-label-next": "Následujicí",
+ "srf-ui-mediaplayer-label-stop": "Zastavit",
+ "srf-ui-mediaplayer-label-mute": "Ztlumit",
+ "srf-ui-mediaplayer-label-unmute": "Zapnout zvuk",
+ "srf-ui-mediaplayer-label-volume-max": "Maximální hlasitost",
+ "srf-ui-mediaplayer-label-shuffle": "Náhodné přehrávání",
+ "srf-ui-mediaplayer-label-shuffle-off": "Vypnout náhodné přehrávání",
+ "srf-ui-mediaplayer-label-repeat": "Opakovat",
+ "srf-ui-mediaplayer-label-repeat-off": "Vypnout opakování",
+ "srf-ui-mediaplayer-label-full-screen": "Celá obrazovka",
+ "srf-ui-mediaplayer-label-restore-screen": "Obnovit obrazovku",
+ "srf-spreadsheet-link": "Tabulka",
+ "srf-paramdesc-spreadsheet-filename": "Formát vytvořeného souboru. Povolené hodnoty: xlsx, xls, ods, csv. Výchozí hodnota: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "Název tabulkového souboru z prostoru názvů ''Soubor'', který je použit k formátování vytvořeného souboru",
+ "srf-paramdesc-icalendar-timezone": "Seznam Äasových pásem oddÄ›lených Äárkami"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/da.json b/www/wiki/extensions/SemanticResultFormats/i18n/da.json
new file mode 100644
index 00000000..339b43b4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/da.json
@@ -0,0 +1,99 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saederup92",
+ "Kranix"
+ ]
+ },
+ "srf-module-loading": "Indlæser...",
+ "srf-paramdesc-height": "Højde",
+ "srf-paramdesc-width": "Bredde",
+ "srf-navigation-previous": "Forrige",
+ "srf-ui-navigation-prev": "Forrige",
+ "srf-ui-navigation-next": "Næste",
+ "srf-ui-common-label-source": "Kilde",
+ "srf-ui-common-label-datasource": "Datakilde",
+ "srf-ui-tooltip-title-scope": "Afgrænsning",
+ "srf-ui-tooltip-title-filter": "Filtrer",
+ "srf-ui-common-label-parameters": "Parametre",
+ "srf-ui-common-label-query": "Forespørgsel",
+ "srfc_previousmonth": "Forrige måned",
+ "srfc_nextmonth": "Næste måned",
+ "srfc_today": "I dag",
+ "srfc_gotomonth": "Gå til måned",
+ "srf_printername_calendar": "MÃ¥nedlig kalender",
+ "srf_outline_novalue": "Ingen værdi",
+ "srf_printername_sum": "Sum af tal",
+ "srf_printername_average": "Gennemsnit af tal",
+ "srf_printername_max": "Højeste tal",
+ "srf_printername_min": "Mindste tal",
+ "srf_printername_earliest": "Tidligste tidspunkt",
+ "srf_printername_latest": "Seneste tidspunkt",
+ "srf_printername_timeline": "Tidslinje",
+ "srf_paramdesc_timelinesize": "Højden på tidslinjen",
+ "srf_paramdesc_charttitle": "Titlen på diagrammet",
+ "srf-ui-gridview-label-item": "Dataelement",
+ "srf-ui-gridview-label-value": "Dataværdi",
+ "srf-ui-gridview-label-series": "Datarække",
+ "srf-ui-gridview-label-chart-tab": "Diagram",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galleri",
+ "srf_paramdesc_widths": "Bredden på billederne",
+ "srf_paramdesc_heights": "Højden på billederne",
+ "srf-gallery-navigation-previous": "Forrige",
+ "srf-gallery-navigation-next": "Næste",
+ "srf-gallery-overlay-count": "Billede $1 af $2",
+ "srf-gallery-image-url-error": "Billedet blev ikke fundet.",
+ "srf_printername_array": "Array",
+ "srf-printername-graph": "Graf",
+ "srf-ui-datatables-label-parameters": "Parametre",
+ "srf-ui-datatables-label-information": "Information",
+ "srf-ui-datatables-label-placeholder-column-search": "Søg...",
+ "srf-ui-datatables-label-multiselect-column-header": "Tilgængelige kolonner",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Kolonner er synlige",
+ "srf-ui-datatables-label-sLoadingRecords": "Indlæser...",
+ "srf-ui-datatables-label-sProcessing": "Bearbejder...",
+ "srf-ui-datatables-label-sSearch": "Søg:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Første",
+ "srf-ui-datatables-label-oPaginate-sLast": "Sidste",
+ "srf-ui-datatables-label-oPaginate-sNext": "Næste",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Forrige",
+ "srf-printername-tree": "Træ",
+ "srf-printername-filtered": "Filtreret",
+ "srf-paramdesc-filtered-map-height": "Korthøjden",
+ "srf-filtered-selectorlabel-list": "Liste",
+ "srf-filtered-selectorlabel-table": "Tabel",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-filtered-selectorlabel-map": "Kort",
+ "srf-filtered-value-filter-and": "OG",
+ "srf-filtered-value-filter-or": "ELLER",
+ "srf-paramdesc-zoom": "Aktiver zoom",
+ "srf-paramdesc-datatable": "Aktiver en datatabel",
+ "srf-paramdesc-widget": "Tilgængelig widget",
+ "srf-printername-eventcalendar": "Begivenhedskalender",
+ "srf-paramdesc-calendarfirstday": "Første dag i ugen",
+ "srf-ui-eventcalendar-label-today": "I dag",
+ "srf-ui-eventcalendar-label-month": "MÃ¥ned",
+ "srf-ui-eventcalendar-label-week": "Uge",
+ "srf-ui-eventcalendar-label-day": "Dag",
+ "srf-ui-eventcalendar-label-listmonth": "MÃ¥ned (liste)",
+ "srf-ui-eventcalendar-label-listweek": "Uge (liste)",
+ "srf-ui-eventcalendar-label-listday": "Dag (liste)",
+ "srf-ui-eventcalendar-label-allday": "Hele dagen",
+ "srf-ui-eventcalendar-click-popup": "Ønsker du at oprette en begivenhed?",
+ "srf-paramdesc-unit": "Enhed",
+ "srf-printername-media": "Medieafspiller",
+ "srf-ui-mediaplayer-label-previous": "Forrige",
+ "srf-ui-mediaplayer-label-play": "Afspil",
+ "srf-ui-mediaplayer-label-pause": "Sæt på pause",
+ "srf-ui-mediaplayer-label-next": "Næste",
+ "srf-ui-mediaplayer-label-stop": "Stop",
+ "srf-ui-mediaplayer-label-mute": "Slå lyd fra",
+ "srf-ui-mediaplayer-label-unmute": "Slå lyd til",
+ "srf-ui-mediaplayer-label-repeat": "Gentag",
+ "srf-ui-mediaplayer-label-full-screen": "Fuldskærm",
+ "srf-spreadsheet-link": "Regneark",
+ "srf-paramdesc-gantt-diagramtitle": "Diagramnavn",
+ "srf-paramdesc-gantt-diagramtheme": "Diagramtema"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/de-formal.json b/www/wiki/extensions/SemanticResultFormats/i18n/de-formal.json
new file mode 100644
index 00000000..2e30633f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/de-formal.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ },
+ "srf-prefs-intro-text": "Die Erweiterung „Semantic Result Formats“ ist installiert. Besuchen Sie bitte die [https://www.semantic-mediawiki.org/wiki/Help:Ergebnisformate Hilfeseite zu Ergebnisformaten] für weitere Informationen.",
+ "srf-ui-common-label-ajax-error": "Der Server meldete eine fehlgeschlagene Kommunikation für diesen $1. Bitte versuchen Sie, die Seite neu zu laden oder wenden Sie sich an $2."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/de.json b/www/wiki/extensions/SemanticResultFormats/i18n/de.json
new file mode 100644
index 00000000..a1e7d363
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/de.json
@@ -0,0 +1,355 @@
+{
+ "@metadata": {
+ "authors": [
+ "DaSch",
+ "Imre",
+ "Kghbln",
+ "Krabina",
+ "Metalhead64",
+ "Nipsky",
+ "Purodha",
+ "The Evil IP address",
+ "Umherirrender",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Stellt zusätzliche Ergebnisformate bereit",
+ "prefs-srf": "Erweiterung „Semantic Result Formats“",
+ "srf-prefs-intro-text": "Die Erweiterung „Semantic Result Formats“ ist installiert. Besuch bitte die [https://www.semantic-mediawiki.org/wiki/Help:Ergebnisformate Hilfeseite zu Ergebnisformaten] für weitere Informationen.",
+ "prefs-srf-eventcalendar-options": "Optionen zum Veranstaltungskalender",
+ "srf-prefs-eventcalendar-options-update-default": "[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates Automatische Aktualisierung] des Kalenders beim Neuladen der Seite aktivieren",
+ "srf-prefs-eventcalendar-options-paneview-default": "Ãœbersichtsansicht als Standardansicht aktivieren",
+ "prefs-srf-datatables-options": "Optionen zu Datentabellen",
+ "srf-prefs-datatables-options-update-default": "[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates Automatische Aktualisierung] des Datentabelleninhalts beim Neuladen der Seite aktivieren",
+ "srf-prefs-datatables-options-cache-default": "[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage Lokale Datenspeicherung] zum Verbessern der Leistung aktivieren",
+ "srf-module-loading": "Lade …",
+ "srf-paramdesc-layout": "Das verfügbare Layout",
+ "srf-paramdesc-height": "Die Höhe (in Pixel)",
+ "srf-paramdesc-width": "Die Breite",
+ "srf-paramdesc-class": "Die CSS-Klasse angeben, die zusätzlich verwendet werden soll",
+ "srf-module-nomatch": "Es wurden keine Ãœbereinstimmungen gefunden.",
+ "srf-paramdesc-charttype": "Den Diagrammtyp angeben",
+ "srf-navigation-previous": "Vorherige",
+ "srf-ui-navigation-prev": "Zurück",
+ "srf-ui-navigation-next": "Vor",
+ "srf-ui-common-label-source": "Quelle",
+ "srf-ui-common-label-datasource": "Datenquelle",
+ "srf-ui-common-label-ajax-error": "Der Server meldete eine fehlgeschlagene Kommunikation für diesen $1. Bitte versuche, die Seite neu zu laden oder wende dich an $2.",
+ "srf-ui-common-label-request-object": "Objekt abfragen",
+ "srf-ui-common-label-help-section": "Hilfeabschnitt",
+ "srf-ui-tooltip-title-options": "Optionen",
+ "srf-ui-tooltip-title-scope": "Datenbereich",
+ "srf-ui-tooltip-title-legend": "Legende",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Neu laden",
+ "srf-ui-common-label-parameters": "Parameter",
+ "srf-ui-common-label-query": "Abfrage",
+ "srf-ui-common-label-paneview": "Ãœbersichtsansicht",
+ "srf-ui-common-label-daterange": "Datumsbereich",
+ "srf-ui-widgets-label-parameter-limit": "Begrenzungsparameter",
+ "srf-error-option-mix": "Option ($1) ist nicht verfügbar",
+ "srf-error-option-link-all": "Zur Option ($1) muss beim Paramenter „link“ der Wert „all“ gesetzt werden.",
+ "srf-error-missing-layout": "Das Diagramm oder die Grafik kann nicht angezeigt werden, da das Layout fehlt.",
+ "srf-error-jqplot-bubble-data-length": "Die Tabelle oder Grafik kann nicht angezeigt werden, da erforderliche Daten fehlen.",
+ "srf-error-jqplot-stackseries-data-length": "Das Diagramm oder die Grafik kann nicht angezeigt werden, da nicht jeder Balken oder nicht jede Linie die gleiche Anzahl zu erzeugender Elemente aufweist.",
+ "srf-warn-empy-chart": "Es konnte kein Diagramm / keine Grafik erstellt werden, da keine ausreichenden Daten zum Erstellen vorhanden waren.",
+ "srf-paramdesc-color": "Legt die Farbe zur Markierung von Kalendereinträgen fest",
+ "srfc_previousmonth": "Voriger Monat",
+ "srfc_nextmonth": "Nächster Monat",
+ "srfc_today": "Heute",
+ "srfc_gotomonth": "Gehe zu Monat",
+ "srf_printername_calendar": "Zeit (Kalender)",
+ "srf_paramdesc_calendarlang": "Der Sprachcode der Sprache, in der der Kalender angezeigt werden soll",
+ "srf_paramdesc_calendarcolors": "Die für das jeweilige Datumsattribut zur Darstellung zu verwendende Farbe (Beispiel: „Startdatum=>green,Enddatum=>#09C“)",
+ "srf-paramdesc-calendar-startmonth": "Der Monat, der im Kalender zunächst angezeigt wird (Standard ist der aktuelle Monat)",
+ "srf-paramdesc-calendar-startyear": "Das Jahr, das im Kalender zunächst angezeigt wird (Standard ist das aktuelle Jahr)",
+ "srf_printername_vcard": "Export (vCard)",
+ "srf_printername_icalendar": "Export (iCalendar)",
+ "srf_paramdesc_icalendartitle": "Legt fest, welcher Name der Datei bei der Ausgabe der Abfrageergebnisse gegeben werden soll",
+ "srf_paramdesc_icalendardescription": "Die Beschreibung der Kalenderdatei",
+ "srf_printername_bibtex": "Export (BibTeX)",
+ "srf_outline_novalue": "Kein Wert",
+ "srf_printername_outline": "Gliederung",
+ "srf_paramdesc_outlineproperties": "Die Liste der mit Kommata voneinander getrennten Attribute, die in der Kopfzeile der Gliederung angezeigt werden sollen",
+ "srf_printername_sum": "Zahlen (Summe)",
+ "srf_printername_average": "Zahlen (Durchschnitt)",
+ "srf_printername_max": "Zahlen (höchste Zahl)",
+ "srf_printername_min": "Zahlen (niedrigste Zahl)",
+ "srf_paramdesc_limit": "Die maximale Anzahl der abzufragenden Seiten",
+ "srf_printername_product": "Zahlen (Produkt)",
+ "srf_printername_median": "Zahlen (Median)",
+ "srf-paramdesc-default": "Der Standardwert, der angezeigt wird, sofern keine numerischen Ergebnisse vorhanden sind.",
+ "srf_printername_earliest": "Zeit (Zeitpunkt – frühester)",
+ "srf_printername_latest": "Zeit (Zeitpunkt – spätester)",
+ "srf_printername_timeline": "Zeit (Zeitlinie)",
+ "srf_printername_eventline": "Zeit (Ereignislinie)",
+ "srf_paramdesc_timelinebands": "Die Zeitleisten, die angezeigt werden sollen",
+ "srf_paramdesc_timelineposition": "Die Stelle, an der sich die Zeitleiste ausrichten soll",
+ "srf_paramdesc_timelinestart": "Der Name des Attributs, mit dem der erste anzuzeigende Zeitpunkt festgelegt wird",
+ "srf_paramdesc_timelineend": "Der Name des Attributs, mit dem der zweite anzuzeigende Zeitpunkt festgelegt wird",
+ "srf_paramdesc_timelinesize": "Die Höhe der Zeitleiste(n)",
+ "srf-timeline-allresults": "Weitere Ergebnisse dieser Abfrage.",
+ "srf-timeline-nojs": "JavaScript muss aktiviert sein, damit man die interaktive Zeitleiste ansehen kann.",
+ "srf_paramdesc_views": "Die anzuzeigenden Ansichten",
+ "srf_paramdesc_facets": "Die Gruppe der Attribute, die für jede Seite angezeigt werden sollen",
+ "srf_paramdesc_lens": "Der Name einer Vorlage zum Anzeigen der Seiteneigenschaften",
+ "srf_printername_googlebar": "Diagramm (Säulendiagramm - Google)",
+ "srf_printername_googlepie": "Diagramm (Tortendiagramm - Google)",
+ "srf-printername-jqplotchart": "Diagramm (jqPlot)",
+ "srf-printername-jqplotseries": "Diagramm (Datenreihe - jqPlot)",
+ "srf_paramdesc_chartheight": "Die Höhe des Diagramms / der Grafik (in Pixeln) angeben",
+ "srf_paramdesc_chartwidth": "Die Breite des Diagramms / der Grafik (in Pixeln) angeben",
+ "srf_paramdesc_charttitle": "Der Titel des Diagramms",
+ "srf_paramdesc_barcolor": "Die Farbe der Balken",
+ "srf_paramdesc_bardirection": "Die Darstellung eines Diagramms bestimmen (entweder Balken oder Säulen)",
+ "srf-paramdesc-direction": "Die Ausrichtung des Diagramms / der Grafik angeben",
+ "srf_paramdesc_barnumbersaxislabel": "Die Beschriftung der y-Achse",
+ "srf-paramdesc-labelaxislabel": "Die Beschriftung der y-Achse",
+ "srf-paramdesc-ticklabels": "Die Anzeige von Teilstrichbeschriftungen aktivieren",
+ "srf-paramdesc-minvalue": "Der niedrigste Wert, der auf der y-Achse angezeigt werden soll",
+ "srf-paramdesc-pointlabels": "Die Anzeige der Diagrammdatenpunkte",
+ "srf-paramdesc-chartlegend": "Die Position der Diagrammlegenden",
+ "srf-paramdesc-datalabels": "Die Diagramm- und Grafikbeschriftungen",
+ "srf-paramdesc-charttext": "Der beschreibende Diagrammtext",
+ "srf-paramdesc-chartclass": "Die zusätzliche CSS-Klasse",
+ "srf-paramdesc-renderer": "Das Programm zum Rendern des Diagramms / der Grafik auswählen",
+ "srf-paramdesc-filling": "Die individuelle Fülloption",
+ "srf-paramdesc-theme": "Die Anmutung für das Raster auswählen",
+ "srf-paramdesc-chartcolor": "Die individuellen Diagrammfarben zuteilen",
+ "srf-paramdesc-colorscheme": "Wähle ein Farbschema",
+ "srf-paramdesc-valueformat": "Die Formatierungsregel für Werte bestimmen",
+ "srf-paramdesc-highlighter": "Eine Hervorhebung zu Datenpunkten anzeigen",
+ "srf-paramdesc-smoothlines": "Einen Algorithmus zum Glätten der Anzeige von Liniendiagrammen einsetzen",
+ "srf-paramdesc-stackseries": "Diagramm als gestapelte Reihen anzeigen",
+ "srf-paramdesc-seriesgroup": "Die Gruppierung von Datenreihen auswählen",
+ "srf-paramdesc-serieslabel": "Die Reihenbeschriftung bestimmen",
+ "srf-paramdesc-grouplabel": "Die Gruppenbeschriftung bestimmen",
+ "srf-paramdesc-chartcursor": "Die Option zur Anzeige des Cursors in der Grafik",
+ "srf-paramdesc-trendline": "Das gleichzeitige Anzeigen des Diagramms und der Trendlinie aktivieren",
+ "srf-paramdesc-gridview": "Das Diagramm und die Datensätze simultan anzeigen. Mögliche Parameterwerte: „none“ und „tabs“. Standardwert: „none“",
+ "srf-paramdesc-paneview": "Die Position des Fensters, das ein kleines Liniendiagramm enthält. Mögliche Werte: „bottom“, „top“ und „none“. Standardwert: „bottom“",
+ "srf-paramdesc-infotext": "Die zusätzlichen Informationen auf dem entsprechenden Inforeiter anzeigen",
+ "srf-paramdesc-clicktarget": "Legt die Zielseite oder Abfragezeichenfolge als Ziel bei einem Klick auf ein Kalenderdatum fest",
+ "srf-ui-gridview-label-item": "Datenelement",
+ "srf-ui-gridview-label-value": "Datenwert",
+ "srf-ui-gridview-label-series": "Datenreihen",
+ "srf-ui-gridview-label-chart-tab": "Diagramm",
+ "srf-ui-gridview-label-data-tab": "Daten",
+ "srf-ui-gridview-label-info-tab": "Informationen",
+ "srf_printername_gallery": "Bild (Galerie)",
+ "srf_paramdesc_perrow": "Die Anzahl der Bilder pro Zeile",
+ "srf_paramdesc_widths": "Die Breite der Bilder",
+ "srf_paramdesc_heights": "Die Höhe der Bilder",
+ "srf_paramdesc_autocaptions": "Den Dateinamen als Beschreibung verwenden, sofern keine angegeben wurde",
+ "srf_paramdesc_fileextensions": "Sofern der Dateiname als Beschreibung verwendet wird, ebenso die Dateierweiterung anzeigen",
+ "srf_paramdesc_captionproperty": "Der Name des Attributs auf abgefragten Seiten, der als Beschreibung verwendet werden soll",
+ "srf_paramdesc_imageproperty": "Der Name des Attributs auf abgefragten Seiten, das auf das zu verwendende Bild hinweist. Sofern festgelegt, werden die abgefragten Seiten selbst, nicht als Bild angezeigt.",
+ "srf-paramdesc-redirects": "Der Name des semantischen Attributs, welches das Ziel der Weiterleitung enthält",
+ "srf-paramdesc-navigation": "Die Navigationssteuerung zum Layout",
+ "srf-paramdesc-overlay": "Die Bildüberblendungen aktivieren",
+ "srf-gallery-navigation-previous": "Zurück",
+ "srf-gallery-navigation-next": "Weiter",
+ "srf-gallery-overlay-count": "Bild $1 von $2",
+ "srf-gallery-image-url-error": "Das Bild wurde nicht gefunden.",
+ "srf_printername_tagcloud": "Stichwortwolke",
+ "srf_paramdesc_includesubject": "Ob die Themenbezeichnungen selbst mit einbezogen werden sollen",
+ "srf_paramdesc_increase": "Wie soll die Darstellungsgröße der Stichwörter verändert werden?",
+ "srf_paramdesc_tagorder": "Die Reihenfolge der Stichwörter",
+ "srf_paramdesc_mincount": "Das Mindestvorkommen eines Stichwortes, um aufgelistet zu werden",
+ "srf_paramdesc_minsize": "Die Darstellungsgröße des kleinsten Stichwortes in Prozent",
+ "srf_paramdesc_maxsize": "Die Darstellungsgröße des größten Stichwortes in Prozent",
+ "srf_paramdesc_maxtags": "Die maximale Anzahl der Stichwörter in der Stichwortwolke",
+ "srf-paramdesc-excludetags": "Die auszuschließenden Stichworte (Trennzeichen: „;“)",
+ "srf_printername_valuerank": "Liste (Rangfolge)",
+ "srf_printername_array": "Datenfeld (Array)",
+ "srf_paramdesc_pagetitle": "Legt fest ob Seitentitel in der Ergebnisliste angezeigt oder weggelassen werden sollen",
+ "srf_paramdesc_hidegaps": "Legt fest, ob abgefragte, aber nicht vorhandene Attribut- und Datensatzwerte, durch Trennzeichen getrennt, angezeigt oder weggelassen werden sollen",
+ "srf_paramdesc_arrayname": "Sofern die Erweiterung Arrays installiert ist, wird anstelle einer sichtbaren Ergebnisausgabe ein Datenfeld (Array) dieses Namens angelegt",
+ "srf_paramdesc_propsep": "Das Trennzeichen zwischen gewünschten Attributen",
+ "srf_paramdesc_manysep": "Das Trennzeichen zwischen mehreren Attributwerten eines Attributs",
+ "srf_paramdesc_recordsep": "Das Trennzeichen zwischen den einzelnen Werten eines Attributs von Datentyp Verbund",
+ "srf_paramdesc_headersep": "Das Trennzeichen zwischen Attributnamen und -wert, sofern für den Parameter „headers“ entweder „show“ oder „plain“ festgelegt wurde",
+ "srf_printername_hash": "Assoziatives Datenfeld (Hash)",
+ "srf_paramdesc_hashname": "Sofern die Erweiterung HashTables vorhanden ist, wird anstelle einer sichtbaren Ergebnisausgabe ein assoziatives Datenfeld (Hash) dieses Namens angelegt",
+ "srf-printername-graph": "Grafik",
+ "srf-paramdesc-graph-relation": "Legt fest, ob die Bezeichnungen oder Namensattribute über- oder untergeordnete Objekte sind",
+ "srf-paramdesc-graph-nameprop": "Legt das Attribut fest, dessen Wert als Bezeichnung anstelle der eigentlichen Bezeichnung für den Verweis auf eine Seite genutzt werden soll",
+ "srf-paramdesc-graph-nodeshape": "Legt die Form der Verzweigungspunkte in der Grafik fest",
+ "srf-paramdesc-graphname": "Legt den Titel der Grafik fest",
+ "srf-paramdesc-graphsize": "Legt die Größe der Grafik in Pixeln fest",
+ "srf-paramdesc-graphlegend": "Legt fest, ob eine Legende zur Grafik angezeigt werden soll",
+ "srf-paramdesc-graphlabel": "Legt die Beschriftung der Grafik fest",
+ "srf-paramdesc-rankdir": "Legt die Richtung der Pfeile fest",
+ "srf-paramdesc-graphlink": "Legt fest, ob die Verzweigungspunkte auf ihre Wikiseiten verlinken sollen",
+ "srf-paramdesc-graphcolor": "Legt die Farbe der Grafik fest",
+ "srf-paramdesc-graph-wwl": "Legt die Wortumbruchgrenze fest (in Anzahl der Zeichen)",
+ "srf-paramdesc-clustercolor": "Legt die Farben der Clusterkästen fest",
+ "srf-paramdesc-highlight": "Legt den hervorzuhebenden Verzweigungspunkt fest",
+ "srf-paramdesc-highlightcolor": "Legt die Schriftfarbe für den hervorgehobenen Verzweigungspunkt fest",
+ "srf-paramdesc-redlinkcolor": "Legt die Schriftfarbe für die „roten“ Links fest",
+ "srf-paramdesc-processcategory": "Legt die Wikikategorie fest, in der die Prozessschritte eingeordnet sind",
+ "srf-paramdesc-showroles": "Legt fest, ob die zugehörigen Rollen in der Grafik angezeigt werden sollen",
+ "srf-paramdesc-showstatus": "Legt fest, ob der Status eines Prozessschrittes gerendert werden soll",
+ "srf-paramdesc-showresources": "Legt fest, ob die zugehörigen Quellen in der Grafik angezeigt werden sollen",
+ "srf-paramdesc-showdiscussion": "Legt fest, ob eine Diskussion gerendert werden soll",
+ "srf-paramdesc-showredlinks": "Legt fest, ob rote Links überprüft und hervorgehoben werden sollen",
+ "srf-paramdesc-showcompound": "Legt fest, ob zusammengeführte Verzweigungspunkte, das heißt untergeordnete Prozesse, hervorgehoben werden sollen",
+ "srf-paramdesc-debug": "Legt fest, ob der Code der Prozessgrafik mit „Pre“-Tags versehen angezeigt werden soll",
+ "srf-paramdesc-graphvalidation": "Legt fest, ob die Prozessschritte in rot angezeigt werden sollen, denen keine Rolle zugewiesen ist",
+ "srf-printername-datatables": "Datentabellen",
+ "srf-ui-datatables-label-conditions": "Bedingungen",
+ "srf-ui-datatables-label-parameters": "Parameter",
+ "srf-ui-datatables-label-filters": "Spaltenfilter und Suche",
+ "srf-ui-datatables-label-information": "Informationen",
+ "srf-ui-datatables-panel-disclaimer": "Parameter und Bedingungen können verändert werden. Indes ist dabei jegliche Anpassung temporär und wird nach dem Neuladen der Seite verworfen.",
+ "srf-ui-datatables-label-update-success": "Die Datentabelle wurde erfolgreich aktualisiert.",
+ "srf-ui-datatables-label-update-error": "Die Aktualisierung der Datentabelle ist gescheitert.",
+ "srf-ui-datatables-label-placeholder-column-search": "Suche …",
+ "srf-ui-datatables-label-content-cache": "Der Inhalt stammt aus dem lokalen Zwischenspeicher.",
+ "srf-ui-datatables-label-content-server": "Der Inhalt stammt vom Datenbankserver.",
+ "srf-ui-datatables-label-multiselect-column-header": "Verfügbare Spalten",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filtereinstellungen",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Spalten werden angezeigt",
+ "srf-ui-datatables-label-sEmptyTable": "In der Datentabelle werden keine Daten angezeigt",
+ "srf-ui-datatables-label-sInfo": "Es werden die Einträge _START_ bis _END_ von insgesamt _TOTAL_ Einträgen angezeigt.",
+ "srf-ui-datatables-label-sInfoEmpty": "Es werden 0 bis 0 von insgesamt 0 Einträgen angezeigt.",
+ "srf-ui-datatables-label-sInfoFiltered": "(aus insgesamt _MAX_ Einträgen herausgefiltert)",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLengthMenu": "Zeige _MENU_ Einträge",
+ "srf-ui-datatables-label-sLoadingRecords": "Lade …",
+ "srf-ui-datatables-label-sProcessing": "Verarbeite …",
+ "srf-ui-datatables-label-sSearch": "Suche:",
+ "srf-ui-datatables-label-sZeroRecords": "Es wurden keine passenden Datensätze gefunden.",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Erster",
+ "srf-ui-datatables-label-oPaginate-sLast": "Letzter",
+ "srf-ui-datatables-label-oPaginate-sNext": "Nächster",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Voriger",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": zum aufsteigenden Sortieren der Spalte aktivieren",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": zum absteigenden Sortieren der Spalte aktivieren",
+ "srf-printername-tree": "Baumansicht (aufgezählt)",
+ "srf-printername-ultree": "Baumansicht (aufgezählt)",
+ "srf-printername-oltree": "Baumansicht (nummeriert)",
+ "srf-tree-noparentprop": "Es wurde kein übergeordnetes Attribut angegeben. Die Baumansicht kann nicht ohne Angabe eines übergeordneten Attributs erstellt werden.",
+ "srf-tree-rootinvalid": "„$1“ ist kein gültiger Seitentitel.",
+ "srf-tree-circledetected": "Beim Versuch, „$1“ in die Baumansicht einzufügen, wurde ein Zirkelbezug entdeckt.",
+ "srf-paramdesc-tree-parent": "Legt das Attribut fest, das die übergeordnete Seite enthält",
+ "srf-paramdesc-tree-root": "Legt die Ausgangsseite der Baumansicht fest",
+ "srf-paramdesc-tree-startlevel": "Legt die Ausgangsebene der Baumsicht fest, bspw. um sie in eine andere Baumansicht einbeziehen zu können",
+ "srf-printername-slideshow": "Bild (Vorführung)",
+ "srf-paramdesc-delay": "Die Verzögerung beim Wechseln zwischen den einzelnen Bildern in Sekunden",
+ "srf-paramdesc-navigation-controls": "Die Navigationsschaltflächen anzeigen oder nicht",
+ "srf-paramdesc-effect": "Der Effekt, der beim Wechseln zwischen den einzelnen Bildern angewendet werden soll",
+ "srf-printername-filtered": "Filterung",
+ "srf-paramdesc-filtered-views": "Die Ansichten, die für die Ergebnisanzeige verfügbar sein sollen",
+ "srf-paramdesc-filtered-filter-position": "Die Position der Filter in Bezug auf die Ansichten. Mögliche Parameterwerte: „top“, „bottom“. Standardwert: „top“",
+ "srf-paramdesc-filtered-list-type": "Der Typ der Liste. Mögliche Parameterwerte: „list“, „ul“ und „ol“. Standardwert: „list“",
+ "srf-paramdesc-filtered-list-template": "Die Vorlage, die zur Formatierung der Listeneinträge verwendet werden soll",
+ "srf-paramdesc-filtered-list-named-args": "Legt fest, ob Bezeichnungen für die Parameter an die Vorlage bei der Ausgabe der Abfrageergebnisse weitergegeben werden sollen",
+ "srf-paramdesc-filtered-list-introtemplate": "Der Name der Vorlage, die vor den Abfrageergebnissen angezeigt werden soll, sofern welche vorhanden sind",
+ "srf-paramdesc-filtered-list-outrotemplate": "Der Name der Vorlage, die nach den Abfrageergebnissen angezeigt werden soll, sofern welche vorhanden sind",
+ "srf-paramdesc-filtered-calendar-start": "Die Ausgabe, die das Anfangsdatum einer Veranstaltung enthält",
+ "srf-paramdesc-filtered-calendar-end": "Die Ausgabe, die das Enddatum einer Veranstaltung enthält",
+ "srf-paramdesc-filtered-calendar-title": "Die Ausgabe, die den Titel einer Veranstaltung enthält. Kann nicht zusammen mit einer Vorlage zur Ausgabe des Titels verwendet werden",
+ "srf-paramdesc-filtered-calendar-title-template": "Die Vorlage, die den Titel einer Veranstaltung enthält",
+ "srf-paramdesc-filtered-map-position": "Legt die Ansicht fest, die die geografische Position enthält",
+ "srf-paramdesc-filtered-map-icon": "Legt die Ausgabeanweisung fest, mit der das zu verwendende Kartensymbol bestimmt wird",
+ "srf-paramdesc-filtered-map-icons": "Legt die Zuordnungen von Datenwerten zu Symbolen fest, die auf der Karte für betreffende Datenwerte verwendet werden sollen",
+ "srf-paramdesc-filtered-map-height": "Die Höhe der Karte.",
+ "srf-paramdesc-filtered-map-zoom": "Legt die Vergrößerungsstufe beim Laden der Karte fest. Diese kann durch den Benutzer geändert werden.<br>Siehe: <code>map view min zoom</code> und <code>map view max zoom</code>",
+ "srf-paramdesc-filtered-map-min-zoom": "Legt die kleinste auswählbare Vergrößerungsstufe der Karte fest",
+ "srf-paramdesc-filtered-map-max-zoom": "Legt die größte auswählbare Vergrößerungsstufe der Karte fest",
+ "srf-paramdesc-filtered-map-marker-cluster": "Legt fest, ob die Markierungen geclustert werden sollen",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Legt die maximale Vergrößerungsstufe fest, bei der die Kartenmarkierungen geclustert bleiben. Oberhalb dieser Stufe werden Markierungen immer nicht geclustert",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "Legt den maximalen Radius fest, den ein Cluster von der zentralen Markierung aus (in Pixeln) abdecken wird. Beträgt 80, sofern nicht angegeben",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Legt fest, ob das Anklicken des Clusters zur Vergrößerung auf seine Abgrenzungen führt",
+ "srf-filtered-selectorlabel-list": "Liste",
+ "srf-filtered-selectorlabel-table": "Tabelle",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-filtered-selectorlabel-map": "Karte",
+ "srf-filtered-noscript-error": "Die Ergebnisse können nicht angezeigt werden, da JavaScript nicht aktiviert ist. Zu „$1“ gehen.",
+ "srf-filtered-noscript-link-caption": "Ergebnisse in Form einer Tabelle",
+ "srf-filtered-map-provider-missing-error": "Für die Kartenansicht wurde kein Kartenanbieter angegeben.",
+ "srf-filtered-value-filter-and": "UND",
+ "srf-filtered-value-filter-or": "ODER",
+ "srf-filtered-value-filter-placeholder": "Einen Wert zum Filtern auswählen",
+ "srf-printername-d3chart": "Diagramm (D3)",
+ "srf-printername-timeseries": "Diagramm (Zeitreihe)",
+ "srf-paramdesc-group": "Die Datenreihen sortiert nach",
+ "srf-paramdesc-zoom": "Den Zoom aktivieren oder nicht",
+ "srf-paramdesc-datatable": "Eine Datentabelle anzeigen oder nicht",
+ "srf-timeseries-zoom-out-of-range": "Der Zoombereich enthält nicht genug Daten.",
+ "srf-printername-sparkline": "Diagramm (Wortgrafik)",
+ "srf-printername-listwidget": "Widget (Listenwidget)",
+ "srf-paramdesc-listtype": "Den Listentyp angeben",
+ "srf-paramdesc-widget": "Das verfügbare Widget",
+ "srf-paramdesc-pageitems": "Datenelemente pro Seite",
+ "srf-printername-eventcalendar": "Zeit (Veranstaltungskalender)",
+ "srf-paramdesc-calendarfirstday": "Der Tag, an dem jede Woche beginnt",
+ "srf-paramdesc-calendardefaultview": "Die Ausgangsansicht beim Laden des Kalenders",
+ "srf-paramdesc-calendarstart": "Das Anfangsdatum des Kalenders (Datums- oder Datum-und-Zeit-Werte)",
+ "srf-paramdesc-calendarlegend": "Die Position der Legende sowie angewendeten Filteroptionen",
+ "srf-paramdesc-dayview": "Die Tagesansicht beim Anklicken der Tagesnummer aktivieren oder nicht",
+ "srf-ui-eventcalendar-label-today": "Heute",
+ "srf-ui-eventcalendar-label-month": "Monat",
+ "srf-ui-eventcalendar-label-week": "Woche",
+ "srf-ui-eventcalendar-label-day": "Tag",
+ "srf-ui-eventcalendar-label-listmonth": "Monat (Liste)",
+ "srf-ui-eventcalendar-label-listweek": "Woche (Liste)",
+ "srf-ui-eventcalendar-label-listday": "Tag (Liste)",
+ "srf-ui-eventcalendar-label-allday": "Gesamter Tag",
+ "srf-ui-eventcalendar-format-title-week": "dddd, D. MMM YYYY",
+ "srf-ui-eventcalendar-format-title-day": "D. MMMM YYYY",
+ "srf-ui-eventcalendar-format-column-week": "ddd., DD.MM.",
+ "srf-ui-eventcalendar-format-column-day": "ddd., DD.MM.",
+ "srf-ui-eventcalendar-label-update-success": "Der Kalender wurde erfolgreich aktualisiert.",
+ "srf-ui-eventcalendar-label-update-error": "Die Aktualisierung der Kalenders ist gescheitert.",
+ "srf-ui-eventcalendar-click-popup": "Soll ein Termin erstellt werden?",
+ "srf-printername-dygraphs": "Diagramm (Digraph)",
+ "srf-paramdesc-datasource": "Die Quelle, die die abzurufenden Daten enthält. Mögliche Parameterwerte: „file“, „raw“ und „url“. Standardwert: „file“",
+ "srf-paramdesc-errorbar": "Der zu verwendende Fehlerbalken. Mögliche Parameterwerte: „fraction“ (Konfidenzintervall der Werte), „sigma“ (Standardabweichung der Werte) und „range“ (Wertebereich)",
+ "srf-paramdesc-movingaverage": "Die Anzeige des Durchschnitts zu einem Zeitraum bestimmter Tage (bei Angabe von <code>zero</code> (Null) wird kein gleitender Durchschnitt angezeigt)",
+ "srf-paramdesc-yaxislabel": "Die Beschreibung, die auf der Y-Achse angezeigt wird",
+ "srf-paramdesc-xaxislabel": "Die Beschreibung, die auf der X-Achse angezeigt wird",
+ "srf-paramdesc-unit": "Die Einheit",
+ "srf-printername-pagewidget": "Widget (Seitenwidget)",
+ "srf-printername-incoming": "Eingehende Attribute",
+ "srf-paramdesc-count": "Legt fest, ob die Anzahl der eingehenden Attribute gezählt werden soll",
+ "srf-paramdesc-min": "Der maximale Wert oder Schwellenwert",
+ "srf-paramdesc-excludeproperty": "Das Attribut vom Ergebnis ausschließen",
+ "srf-printername-media": "Medienwiedergabe",
+ "srf-paramdesc-mediainspector": "Zeigt detaillierte Informationen zu einem angegebenen Medienelement an",
+ "srf-ui-mediaplayer-label-previous": "Vorherige",
+ "srf-ui-mediaplayer-label-play": "Wiedergabe",
+ "srf-ui-mediaplayer-label-pause": "Pause",
+ "srf-ui-mediaplayer-label-next": "Nächste",
+ "srf-ui-mediaplayer-label-stop": "Stop",
+ "srf-ui-mediaplayer-label-mute": "Stumm",
+ "srf-ui-mediaplayer-label-unmute": "Ton an",
+ "srf-ui-mediaplayer-label-volume-max": "Maximale Lautstärke",
+ "srf-ui-mediaplayer-label-shuffle": "Zufallswiedergabe",
+ "srf-ui-mediaplayer-label-shuffle-off": "Zufallswiedergabe beenden",
+ "srf-ui-mediaplayer-label-repeat": "Wiederholen",
+ "srf-ui-mediaplayer-label-repeat-off": "Wiederholen beenden",
+ "srf-ui-mediaplayer-label-full-screen": "Vollbild",
+ "srf-ui-mediaplayer-label-restore-screen": "Bildschirm wiederherstellen",
+ "srf-spreadsheet-link": "Datei (Tabellenkalkulation)",
+ "srf-paramdesc-spreadsheet-filename": "Legt fest, welchen Namen die zu erstellende Datei haben soll",
+ "srf-paramdesc-spreadsheet-fileformat": "Legt fest, welches Dateiformat die zu erstellende Datei haben soll. Mögliche Werte: xlsx, xls, ods, csv",
+ "srf-paramdesc-spreadsheet-templatefile": "Legt fest, wie die Tabellenkalkulationsdatei im Namensraum ''Datei'' heißt, die zur Formatierung der zu erstellende Datei verwendet werden soll.",
+ "srf-paramdesc-icalendar-timezone": "Legt eine durch Kommata getrennte Liste mit Zeitzonen fest",
+ "srf-paramdesc-gantt-diagramtitle": "Name des Diagramms",
+ "srf-paramdesc-gantt-diagramtheme": "Farbmotiv des Diagrams",
+ "srf-paramdesc-gantt-axisformat": "Formatierung der X-Achse",
+ "srf-paramdesc-gantt-sortkey": "Sortierschlüssel",
+ "srf-paramdesc-gantt-titletopmargin": "Obere Abstand des Diagrammtitels",
+ "srf-paramdesc-gantt-barheight": "Höhe der Tasks",
+ "srf-paramdesc-gantt-leftpadding": "Breite des Titels der Sections",
+ "srf-paramdesc-gantt-bargap": "Vertikaler Abstand der Tasks",
+ "srf-error-gantt-mapping-assignment": "Falsche Zuweisung der Werte in '''$1'''",
+ "srf-error-gantt-mapping-keywords": "Der verwendete Schlüssel in deinem Mapping wird nicht unterstüzt",
+ "srf-error-gantt-theme": "Diese '''theme''' wird nicht unterstützt",
+ "srf-error-gantt-sortkey": "Dieser '''sortkey''' wird nicht unterstützt",
+ "srf-error-gantt-mermaid-not-installed": "Die Mermaid Extension muss installiert sein.",
+ "srf-printername-gantt": "Diagramm (Gantt)",
+ "srf-paramdesc-nodelabel": "Legt fest, ob die Knoten der Grafik ein Beschriftung erhalten sollen. Möglicher Wert: displaytitle"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/diq.json b/www/wiki/extensions/SemanticResultFormats/i18n/diq.json
new file mode 100644
index 00000000..e0e4ebc9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/diq.json
@@ -0,0 +1,43 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan",
+ "Mirzali"
+ ]
+ },
+ "srf-module-loading": "Bar beno...",
+ "srf-paramdesc-height": "Berziye",
+ "srf-paramdesc-width": "Herayiye",
+ "srf-navigation-previous": "Verên",
+ "srf-ui-navigation-prev": "Ver",
+ "srf-ui-navigation-next": "Bahdoyên",
+ "srf-ui-common-label-source": "Çıme",
+ "srf-ui-tooltip-title-options": "Weçinıteki",
+ "srf-ui-tooltip-title-scope": "Şımul",
+ "srfc_previousmonth": "Aşma verên",
+ "srfc_nextmonth": "Aşma bahdoyên",
+ "srfc_today": "Ewro",
+ "srfc_gotomonth": "Şo aşmêr",
+ "srf_printername_calendar": "Teqwimê Aşmekan",
+ "srf_outline_novalue": "Erc çıno",
+ "srf_printername_timeline": "Wareyê saete",
+ "srf-ui-gridview-label-data-tab": "Melumat",
+ "srf_printername_gallery": "Galeriye",
+ "srf-paramdesc-navigation": "Kontrolê cerbiney da pusula",
+ "srf-gallery-navigation-previous": "Verên",
+ "srf-gallery-navigation-next": "Bahdoyên",
+ "srf_printername_tagcloud": "Etiket çıno",
+ "srf_printername_array": "Nızam",
+ "srf_printername_hash": "XeÅŸxaÅŸ",
+ "srf-printername-graph": "Grafik",
+ "srf_paramdesc_graphname": "Sername",
+ "srf-printername-tree": "Dar",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-printername-slideshow": "SlaydÅŸow",
+ "srf-ui-eventcalendar-label-today": "Ewro",
+ "srf-ui-eventcalendar-label-month": "AÅŸme",
+ "srf-ui-eventcalendar-label-week": "Hefte",
+ "srf-ui-eventcalendar-label-day": "Roce",
+ "srf-paramdesc-unit": "Unita"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/dsb.json b/www/wiki/extensions/SemanticResultFormats/i18n/dsb.json
new file mode 100644
index 00000000..86c407d1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/dsb.json
@@ -0,0 +1,129 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Pśidatne formaty za rědowe wótpšašanja Semantic MediaWiki",
+ "srf-module-loading": "Zacytujo se...",
+ "srf-paramdesc-layout": "K dispoziciji stojecy layout",
+ "srf-paramdesc-height": "Wusokosć (w pikselach)",
+ "srf-paramdesc-width": "Šyrokosć",
+ "srf-paramdesc-class": "Pódaj pśidatnu CSS-klasu",
+ "srf-module-nomatch": "Žedne wótpowědniki namakane",
+ "srf-paramdesc-charttype": "K dispoziciji stojecy diagramowy typ",
+ "srf-error-option-mix": "Opcija ($1) njestoj k dispoziciji",
+ "srf-error-option-link-all": "Opcija ($1) se pomina,, až parameter staji se \"link\" na \"all\"",
+ "srf-error-missing-layout": "Layout felujo",
+ "srf-warn-empy-chart": "Diagram/grafika njedajo se napóraś, dokulaž daty feluju",
+ "srfc_previousmonth": "Slědny mjasec",
+ "srfc_nextmonth": "Pśiducy mjasec",
+ "srfc_today": "Źinsa",
+ "srfc_gotomonth": "Źi k mjasecoju",
+ "srf_printername_calendar": "Mjasecny kalendaŕ",
+ "srf_paramdesc_calendarlang": "Kode za toś tu rěc, w kótarejž kalendaŕ ma se zwobrazniś",
+ "srf_printername_vcard": "vCard eksportěrowaś",
+ "srf_printername_icalendar": "iCalendar eksportěrowaś",
+ "srf_paramdesc_icalendartitle": "Titel kalendroweje dataje",
+ "srf_paramdesc_icalendardescription": "Wopisanje kalendroweje dataje",
+ "srf_printername_bibtex": "BibTeX eksportěrowaś",
+ "srf_outline_novalue": "Žedna gódnota",
+ "srf_printername_outline": "Kontura",
+ "srf_paramdesc_outlineproperties": "Lisćina atributow, kótarež maju se ako rozrědowańske nadpisma zwobrazniś, pśez komy źělone",
+ "srf_printername_sum": "Suma licbow",
+ "srf_printername_average": "Pśerězk licbow",
+ "srf_printername_max": "Maksimalna licba",
+ "srf_printername_min": "Minimalna licba",
+ "srf_paramdesc_limit": "Maksimalna licba bokow za napšašowanje",
+ "srf_printername_product": "Produkt licbow",
+ "srf_printername_median": "Pśerězk licbow",
+ "srf-paramdesc-default": "Standardna gódnota, kótaraž se zwobraznja, jolic numeriske wuslědki njejsu",
+ "srf_printername_earliest": "Nejrańšy cas",
+ "srf_printername_latest": "Njepóznjejšy cas",
+ "srf_printername_timeline": "Casowy wótběg",
+ "srf_printername_eventline": "Wótběg tšojenjow",
+ "srf_paramdesc_timelinebands": "Definěruje, kótare smugi zwobraznjuju se we wuslědku.",
+ "srf_paramdesc_timelineposition": "Definěruje, źož casowa linija ma fokus na zachopjeńku.",
+ "srf_paramdesc_timelinestart": "Mě atributa, kótarež ma se wužywaś, aby definěrowało prědny casowy dypk",
+ "srf_paramdesc_timelineend": "Mě atributa, kótarež ma se wužywaś, aby definěrowało drugi casowy dypk",
+ "srf_paramdesc_timelinesize": "Wusokosć casoweje linije",
+ "srf-timeline-allresults": "Dalšne wuslědki za toś to napšašowanje.",
+ "srf_paramdesc_views": "Naglědy, kótarež maju se zwobrazniś",
+ "srf_paramdesc_facets": "Sajźba atributow, kótarež maju se zwobrazniś za kuždy bok",
+ "srf_paramdesc_lens": "Mě pśedłogi, z kótarejuž maju se bokowe atributy zwobrazniś",
+ "srf_printername_googlebar": "Google słupowy diagram",
+ "srf_printername_googlepie": "Google tortowy diagram",
+ "srf_paramdesc_chartheight": "Pódaj wusokosć diagrama/grafiki (w pikselach)",
+ "srf_paramdesc_chartwidth": "Pódaj šyrokosć diagrama/grafiki (w pikselach abo procentach)",
+ "srf_paramdesc_charttitle": "Titel diagrama",
+ "srf_paramdesc_barcolor": "Barwa słupow",
+ "srf_paramdesc_bardirection": "Směr słupowego diagrama pódaś",
+ "srf_paramdesc_barnumbersaxislabel": "Pópisanje za y-wósku",
+ "srf-paramdesc-minvalue": "Minimalna gódnota, kótaraž ma se na Y-wósce pokazaś",
+ "srf-paramdesc-chartlegend": "Pozicija diagramoweje legendy",
+ "srf-paramdesc-charttext": "Wugroniwy diagramowy tekst",
+ "srf-paramdesc-chartclass": "Pśidatna CSS-klasa",
+ "srf-paramdesc-theme": "Drastwu za raster wubraÅ›",
+ "srf-paramdesc-chartcolor": "Jadnotliwe diagramowe barwy pśipokazaś",
+ "srf-paramdesc-colorscheme": "Barwowu Å¡emu wubraÅ›",
+ "srf-paramdesc-valueformat": "Formatěrowańske pšawidło za gódnoty pódaś",
+ "srf-paramdesc-infotext": "Pśidatne informacije na wótpowědujucem rejtarku Info zwobrazniś",
+ "srf-ui-gridview-label-item": "Datowy element",
+ "srf-ui-gridview-label-value": "Datowa gódnota",
+ "srf-ui-gridview-label-series": "Datowe rědy",
+ "srf-ui-gridview-label-chart-tab": "Diagram",
+ "srf-ui-gridview-label-data-tab": "Daty",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galerija",
+ "srf_paramdesc_perrow": "Licba wobrazow na smužku",
+ "srf_paramdesc_widths": "Šyrokosć wobrazow",
+ "srf_paramdesc_heights": "Wusokosć wobrazow",
+ "srf_paramdesc_autocaptions": "Datajowe mě ako wopisanje wužywaś, jolic žadno njeje pódane",
+ "srf-gallery-navigation-previous": "Slědk",
+ "srf-gallery-navigation-next": "Dalej",
+ "srf-gallery-overlay-count": "Wobraz $1 z $2",
+ "srf-gallery-image-url-error": "Wobraz njejo se namakał.",
+ "srf_printername_tagcloud": "TafliÄkowa mróÄel",
+ "srf_paramdesc_includesubject": "Lěc mjenja temow same maju se zapśimjeś",
+ "srf_paramdesc_increase": "Kak ma se wjelikosć wobznamjenjow pówušyś",
+ "srf_paramdesc_tagorder": "Pórěd wobznamjenjow",
+ "srf_paramdesc_maxtags": "maksimalna licba wobznamjenjow w mrokawje",
+ "srf_printername_valuerank": "Gódnota",
+ "srf_printername_array": "Å ypka",
+ "srf_printername_hash": "Asociatiwne datowe pólo (hash)",
+ "srf-printername-graph": "Grafika",
+ "srf-paramdesc-graph-nodeshape": "Forma kuždego suka na grafice",
+ "srf-paramdesc-graphname": "Titel",
+ "srf-paramdesc-graphsize": "Wjelikosć grafiki (w pikselach)",
+ "srf-paramdesc-graphlegend": "Legendu grafiki pokazaÅ› abo nic",
+ "srf-paramdesc-graphlabel": "Pópisanje grafiki",
+ "srf-paramdesc-rankdir": "Směr šypki",
+ "srf-paramdesc-graphlink": "Wotkaz grafiki",
+ "srf-paramdesc-graphcolor": "Barwa grafiki",
+ "srf-printername-datatables": "DataTables",
+ "srf-printername-tree": "Bom",
+ "srf-printername-ultree": "Bomowy naglěd (nalicenje)",
+ "srf-printername-oltree": "Bomowy naglěd (numerěrowany)",
+ "srf-paramdesc-tree-parent": "Kakosć, kótaraž wopśimujo nadrědowany bok",
+ "srf-printername-slideshow": "Wobrazowe pśedstajenje",
+ "srf-paramdesc-delay": "Wokomuźenje mjazy wobrazami w sekudnach",
+ "srf-printername-filtered": "Filtrowany",
+ "srf-printername-d3chart": "D3-diagram",
+ "srf-printername-timeseries": "Diagram casowych rědow",
+ "srf-paramdesc-group": "Rědy zrědowane pó",
+ "srf-paramdesc-zoom": "Skalěrowanje zmóžniś",
+ "srf-paramdesc-datatable": "Datowu tabelu zmóžniś",
+ "srf-printername-sparkline": "Diagram słownych grafikow",
+ "srf-printername-listwidget": "Lisćinowy asistent",
+ "srf-paramdesc-listtype": "Pódaj lisćinowy typ",
+ "srf-paramdesc-widget": "K dispoziciji stojecy asistent",
+ "srf-paramdesc-pageitems": "Elementy na bok",
+ "srf-printername-eventcalendar": "Kalendaŕ zarědowanjow",
+ "srf-paramdesc-calendarfirstday": "Źeń, gaž kuždy tyźeń se zachopina",
+ "srf-paramdesc-calendardefaultview": "Zachopna gódnota, gaž kalendaŕ se zacytujo",
+ "srf-paramdesc-datasource": "Pódaj žrědło, z kótaregož maju pśistup na daty (dataja, URL atd.)",
+ "srf-paramdesc-yaxislabel": "Wopisanje, kótarež pokazujo se na y-wósce",
+ "srf-paramdesc-xaxislabel": "Wopisanje, kótarež pokazujo se na x-wósce",
+ "srf-paramdesc-unit": "Jadnotka"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/el.json b/www/wiki/extensions/SemanticResultFormats/i18n/el.json
new file mode 100644
index 00000000..c64272fd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/el.json
@@ -0,0 +1,269 @@
+{
+ "@metadata": {
+ "authors": [
+ "Consta",
+ "Omnipaedista",
+ "Protnet",
+ "ZaDiak",
+ "Glavkos",
+ "Thodoris",
+ "Nemo bis",
+ "KATRINE1992",
+ "Nikosgranturismogt"
+ ]
+ },
+ "srf-desc": "ΠÏόσθετες μοÏφές αποτελεσμάτων για εÏωτήματα του Î£Î·Î¼Î±ÏƒÎ¹Î¿Î»Î¿Î³Î¹ÎºÎ¿Ï MediaWiki",
+ "prefs-srf": "Επέκταση:ΜοÏφές σημασιολογικών αποτελεσμάτων",
+ "srf-prefs-intro-text": "Έχετε εγκαταστήσει την επέκταση ΜοÏφές σημασιολογικών αποτελεσμάτων. Για Ï€Ïόσθετη βοήθεια, παÏακαλοÏμε επισκεφθείτε τη σελίδα βοήθειας σχετικά με τις [https://www.semantic-mediawiki.org/wiki/Help:Result_formats μοÏφές αποτελεσμάτων].",
+ "prefs-srf-eventcalendar-options": "Επιλογές ημεÏολογίου εκδηλώσεων",
+ "srf-prefs-eventcalendar-options-update-default": "ΕνεÏγοποίηση [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates αυτόματων ενημεÏώσεων] ημεÏολογίου εκδηλώσεων κατά την ανανέωση της σελίδας",
+ "srf-prefs-eventcalendar-options-paneview-default": "ΕνεÏγοποίηση της Ï€Ïοβολής παÏαθÏÏου από Ï€Ïοεπιλογή",
+ "srf-module-loading": "ΦόÏτωση...",
+ "srf-paramdesc-layout": "Διαθέσιμη διάταξη",
+ "srf-paramdesc-height": "Ύψος",
+ "srf-paramdesc-width": "Πλάτος",
+ "srf-paramdesc-class": "ΚαθοÏισμός Ï€Ïόσθετης κλάσης CSS",
+ "srf-module-nomatch": "Δεν βÏέθηκαν αντιστοιχίες",
+ "srf-paramdesc-charttype": "Διαθέσιμος Ï„Ïπος γÏαφήματος",
+ "srf-navigation-previous": "ΠÏοηγοÏμενο",
+ "srf-ui-navigation-prev": "ΠÏοηγ",
+ "srf-ui-navigation-next": "Επόμενο",
+ "srf-ui-common-label-source": "Πηγή",
+ "srf-ui-common-label-datasource": "Πηγή δεδομένων",
+ "srf-ui-common-label-ajax-error": "Ο διακομιστής ανέφεÏε αποτυχημένη επικοινωνία για αυτό το $1. ΠαÏακαλοÏμε Ï€Ïοσπαθήστε να ανανεώσετε τη σελίδα ή συμβουλευτείτε το $2.",
+ "srf-ui-common-label-request-object": "αντικείμενο αίτησης",
+ "srf-ui-common-label-help-section": "ενότητα βοήθειας",
+ "srf-ui-tooltip-title-options": "Επιλογές",
+ "srf-ui-tooltip-title-scope": "Πεδίο εφαÏμογής",
+ "srf-ui-tooltip-title-legend": "Υπόμνημα",
+ "srf-ui-tooltip-title-filter": "ΦίλτÏο",
+ "srf-ui-common-label-refresh": "Ανανέωση",
+ "srf-ui-common-label-parameters": "ΠαÏάμετÏοι",
+ "srf-ui-common-label-query": "ΕÏώτημα",
+ "srf-ui-common-label-daterange": "ΕÏÏος ημεÏομηνίας",
+ "srf-ui-widgets-label-parameter-limit": "ÎŒÏιο παÏαμέτÏου",
+ "srf-error-option-mix": "Η επιλογή ($1) δεν είναι διαθέσιμη",
+ "srf-error-jqplot-bubble-data-length": "Ο χάÏτης ή η γÏαφική παÏάσταση δεν μποÏοÏν να Ï€ÏοβληθοÏν διότι λείπουν στοιχεία.",
+ "srf-warn-empy-chart": "Το διάγÏαμμα ή γÏάφημα είναι κενό λόγω ελλειπών δεδομένων",
+ "srfc_previousmonth": "ΠÏοηγοÏμενος μήνας",
+ "srfc_nextmonth": "Επόμενος μήνας",
+ "srfc_today": "ΣήμεÏα",
+ "srfc_gotomonth": "Μετάβαση στον μήνα",
+ "srf_printername_calendar": "Μηνιαίο ημεÏολόγιο",
+ "srf_paramdesc_calendarlang": "Κωδικός γλώσσας στην οποία να παÏουσιάζεται το ημεÏολόγιο",
+ "srf_paramdesc_calendarcolors": "Το χÏώμα που να εμφανίζεται για κάθε ιδιότητα ημεÏομηνίας (παÏάδειγμα: «Start date=>green,End date=>#09c»)",
+ "srf_printername_vcard": "Εξαγωγή σε vCard",
+ "srf_printername_icalendar": "Εξαγωγή σε iCalendar",
+ "srf_paramdesc_icalendartitle": "Τίτλος αÏχείου ημεÏολογίου",
+ "srf_paramdesc_icalendardescription": "ΠεÏιγÏαφή αÏχείου ημεÏολογίου",
+ "srf_printername_bibtex": "Εξαγωγή σε BibTeX",
+ "srf_outline_novalue": "Καμία τιμή",
+ "srf_printername_outline": "ΠεÏίγÏαμμα",
+ "srf_printername_sum": "ΣÏνοψη αÏιθμών",
+ "srf_printername_average": "Μέσος ÏŒÏος αÏιθμών",
+ "srf_printername_max": "Μέγιστος αÏιθμός",
+ "srf_printername_min": "Ελάχιστος αÏιθμός",
+ "srf_paramdesc_limit": "Μέγιστος αÏιθμός σελίδων σε εÏώτημα",
+ "srf_printername_product": "Γινόμενο αÏιθμών",
+ "srf_printername_median": "Διάμεσος αÏιθμών",
+ "srf-paramdesc-default": "ΠÏοεπιλεγμένη τιμή που θα εμφανίζεται όταν δεν υπάÏχουν αÏιθμητικά αποτελέσματα",
+ "srf_printername_earliest": "Η παλαιότεÏη χÏονική στιγμή",
+ "srf_printername_latest": "Η πιο Ï€Ïόσφατη χÏονική στιγμή",
+ "srf_printername_timeline": "ΧÏονολόγιο",
+ "srf_printername_eventline": "ΧÏονολόγιο γεγονότων",
+ "srf_paramdesc_timelineposition": "ΟÏίζει Ï€Î¿Ï ÎµÏƒÏ„Î¹Î¬Î¶ÎµÎ¹ αÏχικά το χÏονοδιάγÏαμμα.",
+ "srf_paramdesc_timelinestart": "Όνομα ιδιότητας που χÏησιμοποιείται για να καθοÏίσει Ï€Ïώτο χÏονικό σημείο",
+ "srf_paramdesc_timelineend": "Όνομα ιδιότητας που χÏησιμοποιείται για να καθοÏίσει δεÏτεÏο χÏονικό σημείο",
+ "srf_paramdesc_timelinesize": "Ύψος χÏονολογίου",
+ "srf-timeline-allresults": "ΠεÏαιτέÏω αποτελέσματα για αυτό το εÏώτημα.",
+ "srf-timeline-nojs": "ΠÏέπει να έχετε ενεÏγοποιημένο το JavaScript για να Ï€Ïοβάλετε το διαδÏαστικό χÏονολόγιο.",
+ "srf_paramdesc_views": "Οι Ï€Ïοβολές που θα παÏουσιάζονται",
+ "srf_paramdesc_facets": "Το σÏνολο των ιδιοτήτων που θα παÏουσιάζονται για κάθε σελίδα",
+ "srf_paramdesc_lens": "Το όνομα του Ï€ÏοτÏπου με το οποίο θα παÏουσιάζονται ιδιότητες σελίδας",
+ "srf_printername_googlebar": "ΡαβδόγÏαμμα Google",
+ "srf_printername_googlepie": "ΓÏάφημα πίτας Google",
+ "srf-printername-jqplotchart": "ΓÏάφημα jqPlot",
+ "srf-printername-jqplotseries": "ΣειÏά jqPlot",
+ "srf_paramdesc_chartheight": "ΚαθοÏισμός Ïψους διαγÏάμματος ή γÏαφήματος (σε εικονοστοιχεία)",
+ "srf_paramdesc_chartwidth": "ΚαθοÏισμός πλάτους διαγÏάμματος ή γÏαφήματος (σε εικονοστοιχεία ή ποσοστό επί τοις εκατό)",
+ "srf_paramdesc_charttitle": "Τίτλος διαγÏάμματος",
+ "srf_paramdesc_barcolor": "ΚαθοÏισμός χÏωμάτων διαγÏάμματος",
+ "srf_paramdesc_bardirection": "ΚαθοÏισμός διεÏθυνσης διαγÏάμματος",
+ "srf-paramdesc-direction": "ΚαθοÏισμός διεÏθυνσης διαγÏάμματος ή γÏαφήματος",
+ "srf_paramdesc_barnumbersaxislabel": "Ετικέτα άξονα αÏιθμών",
+ "srf-paramdesc-labelaxislabel": "Ετικέτα άξονα ετικετών",
+ "srf-paramdesc-minvalue": "Ελάχιστη τιμή που να εμφανίζεται στον άξονα Y",
+ "srf-paramdesc-chartlegend": "Θέση υπομνήματος διαγÏάμματος",
+ "srf-paramdesc-datalabels": "Ετικέτες δεδομένων διαγÏάμματος/γÏαφήματος",
+ "srf-paramdesc-charttext": "ΠεÏιγÏαφικό κείμενο διαγÏάμματος",
+ "srf-paramdesc-chartclass": "ΠÏόσθετη κλάση CSS",
+ "srf-paramdesc-theme": "Επιλογή θέματος πλέγματος",
+ "srf-paramdesc-chartcolor": "Αντιστοίχιση μεμονωμένων χÏωμάτων διαγÏάμματος",
+ "srf-paramdesc-colorscheme": "Επιλογή ÏƒÏ…Î½Î´Ï…Î±ÏƒÎ¼Î¿Ï Ï‡Ïωμάτων",
+ "srf-paramdesc-valueformat": "ΚαθοÏισμός κανόνα μοÏφοποίησης για τις τιμές",
+ "srf-paramdesc-seriesgroup": "Επιλογή ομαδοποίησης σειÏών",
+ "srf-paramdesc-serieslabel": "ΠÏοσδιοÏισμός ετικέτας σειÏών",
+ "srf-paramdesc-grouplabel": "ΠÏοσδιοÏισμός ετικέτας ομάδας",
+ "srf-paramdesc-chartcursor": "Επιλογή παÏουσίασης δÏομέα διαγÏάμματος",
+ "srf-ui-gridview-label-item": "Στοιχείο δεδομένων",
+ "srf-ui-gridview-label-value": "Τιμή δεδομένων",
+ "srf-ui-gridview-label-series": "ΣειÏές δεδομένων",
+ "srf-ui-gridview-label-chart-tab": "ΓÏάφημα",
+ "srf-ui-gridview-label-data-tab": "Δεδομένα",
+ "srf-ui-gridview-label-info-tab": "ΠληÏοφοÏίες",
+ "srf_printername_gallery": "ΓκαλεÏί",
+ "srf_paramdesc_perrow": "ΑÏιθμός εικόνων ανά γÏαμμή",
+ "srf_paramdesc_widths": "Πλάτος εικόνων",
+ "srf_paramdesc_heights": "Ύψος εικόνων",
+ "srf_paramdesc_autocaptions": "ΧÏήση του ονόματος αÏχείου ως λεζάντας όταν δεν παÏέχεται καμία",
+ "srf_paramdesc_fileextensions": "Όταν χÏησιμοποιείται το όνομα του αÏχείου ως λεζάντα, να εμφανίζεται επίσης η επέκταση του αÏχείου",
+ "srf_paramdesc_captionproperty": "Όνομα σημασιολογικής ιδιότητας που υπάÏχει σε σελίδες που είναι αποτέλεσμα εÏωτήματος για να χÏησιμοποιηθεί ως λεζάντα",
+ "srf_paramdesc_imageproperty": "Όνομα σημασιολογικής ιδιότητας σε σελίδες που είναι αποτελέσματα εÏωτήματος, που οδηγεί σε εικόνες για χÏήση. Όταν οÏιστεί, οι ίδιες οι σελίδες που είναι αποτελέσματα εÏωτήματος δεν θα εμφανίζονται ως εικόνες.",
+ "srf-paramdesc-overlay": "ΕνεÏγοποίηση υπέÏθεσης εικόνας",
+ "srf-gallery-navigation-previous": "ΠÏοηγοÏμενο",
+ "srf-gallery-navigation-next": "Επόμενο",
+ "srf-gallery-overlay-count": "Εικόνα $1 από $2",
+ "srf-gallery-image-url-error": "Η εικόνα δεν βÏέθηκε.",
+ "srf_printername_tagcloud": "Îέφος ετικεττών",
+ "srf_paramdesc_increase": "Πώς να αυξήσετε το μέγεθος των ετικετών",
+ "srf_paramdesc_tagorder": "ΣειÏά των ετικετών",
+ "srf_paramdesc_minsize": "Το μέγεθος των μικÏότεÏων ετικετών σε ποσοστό επί τοις εκατό",
+ "srf_paramdesc_maxsize": "Το μέγεθος των μεγαλÏτεÏων ετικετών σε ποσοστό επί τοις εκατό",
+ "srf_paramdesc_maxtags": "Το μέγιστο ποσό ετικετών στο νέφος",
+ "srf-paramdesc-excludetags": "Αποκλεισμός ετικετών (διαχωÏιστικό: «;»)",
+ "srf_printername_array": "ΣειÏά",
+ "srf_paramdesc_propsep": "ΔιαχωÏιστικό Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½ αιτηθέντων ιδιοτήτων",
+ "srf_paramdesc_manysep": "ΔιαχωÏιστικό Î¼ÎµÏ„Î±Î¾Ï Ï€Î¿Î»Î»ÏŽÎ½ τιμών αποτιμώμενων ιδιοτήτων",
+ "srf_paramdesc_recordsep": "ΔιαχωÏιστικό Î¼ÎµÏ„Î±Î¾Ï Ï„Î¹Î¼ÏŽÎ½ ιδιοτήτων εγγÏαφής",
+ "srf_paramdesc_headersep": "ΔιαχωÏιστικό Î¼ÎµÏ„Î±Î¾Ï Î¿Î½ÏŒÎ¼Î±Ï„Î¿Ï‚ ιδιότητας και τιμής αν το «headers» έχει οÏιστεί σε «show» ή «plain»",
+ "srf-printername-graph": "ΓÏάφημα",
+ "srf-paramdesc-graph-relation": "ΚαθοÏίζει εάν τα θέματα ή οι ιδιότητες των όνομάτων είναι γονείς ή παιδια",
+ "srf-paramdesc-graph-nameprop": "ΟÏίζει την ιδιότητα που θα χÏησιμοποιηθεί ως αντικείμενο, αντί του Ï€ÏÎ±Î³Î¼Î±Ï„Î¹ÎºÎ¿Ï Î¸Î­Î¼Î±Ï„Î¿Ï‚, δηλαδή το όνομα της σελίδας",
+ "srf-paramdesc-graph-nodeshape": "ΟÏίζει το σχήμα του κάθε κόμβου στο γÏάφημα",
+ "srf-paramdesc-graphname": "Sets the title of the graph",
+ "srf-paramdesc-graphsize": "Ρυθμίζει το μέγεθος του γÏαφήματος σε pixels",
+ "srf-paramdesc-graphlegend": "ΟÏίζει εάν θα Ï€Ïέπει να εμφανίζεται ένα γÏάφημα μÏθος",
+ "srf-paramdesc-graphlabel": "ΟÏίζει την ετικέτα του γÏαφήματος",
+ "srf-paramdesc-rankdir": "ΟÏίζει την κατεÏθυνση των βελών",
+ "srf-paramdesc-graphlink": "Ρυθμίζει εάν οι κόμβοι Ï€Ïέπει να συνδέονται με τις σελίδες wiki τους",
+ "srf-paramdesc-graphcolor": "ΟÏίζει το χÏώμα του γÏαφήματος",
+ "srf-paramdesc-graph-wwl": "ΟÏίζει το ÏŒÏιο αναδίπλωσης κειμένου (σε αÏιθμό χαÏακτήÏων)",
+ "srf-paramdesc-clustercolor": "Ρυθμίζει τα χÏώματα στα κουτιά συμπλέγματος",
+ "srf-paramdesc-highlight": "ΟÏίζει τον κόμβο να είναι επισημασμένος",
+ "srf-paramdesc-highlightcolor": "ΟÏίζει το χÏώμα της γÏαμματοσειÏάς για το τονισμένο κόμβο",
+ "srf-paramdesc-redlinkcolor": "ΟÏίζει το χÏώμα της γÏαμματοσειÏάς για τις κόκκινες συνδέσεις",
+ "srf-paramdesc-processcategory": "ΟÏίζει την κατηγοÏία wiki συλλέγοντας τα στάδια της διαδικασίας",
+ "srf-paramdesc-showroles": "Δείχνει του αντίστοιχους Ïόλους στο γÏάφημα",
+ "srf-paramdesc-showstatus": "ΟÏίζει αν μια κατάσταση στο στάδιο της διαδικασίας θα Ï€Ïέπει να καταστεί",
+ "srf-paramdesc-showresources": "Δείχνει τα αντίστοιχων πόÏων μέσα στο γÏάφημα",
+ "srf-paramdesc-showdiscussion": "ΟÏίζει αν θα Ï€Ïέπει να καταστεί μια συζήτηση",
+ "srf-paramdesc-showredlinks": "ΚαθοÏίζει εάν οι κόκκινες συνδέσεις θα Ï€Ïέπει να ελέγχονται και να επισημαίνονται",
+ "srf-paramdesc-showcompound": "ΟÏίζει εάν θα αναδείξει τους ενωμένους κόμβους, δηλ. subprocesses",
+ "srf-paramdesc-debug": "ΟÏίζει αν η διαδικασία γÏαφής ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î¸Î± Ï€Ïέπει να δειχθεί τυλιγμένη Ï€Ïιν τις ετικέτες",
+ "srf-paramdesc-graphvalidation": "Εμφανίζει τα βήματα της διαδικασίας με κόκκινο χÏώμα στα οποία δεν έχουν εκχωÏηθεί Ïόλο",
+ "srf-ui-datatables-label-conditions": "Συνθήκες",
+ "srf-ui-datatables-label-parameters": "ΠαÏάμετÏοι",
+ "srf-ui-datatables-label-filters": "ΦίλτÏα στηλών και αναζήτηση",
+ "srf-ui-datatables-label-information": "ΠληÏοφοÏίες",
+ "srf-ui-datatables-label-update-success": "Η ενημέÏωση του πίνακα ήταν επιτυχής",
+ "srf-ui-datatables-label-update-error": "Η ενημέÏωση του πίνακα απέτυχε.",
+ "srf-ui-datatables-label-placeholder-column-search": "Αναζήτηση...",
+ "srf-ui-datatables-label-content-cache": "Το πεÏιεχόμενο Ï€ÏοέÏχεται από την τοπική Ï€ÏοσωÏινή μνήμη.",
+ "srf-ui-datatables-label-content-server": "Το πεÏιεχόμενο Ï€ÏοέÏχεται από το διακομιστή.",
+ "srf-ui-datatables-label-multiselect-column-header": "Διαθέσιμες στήλες",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Ρυθμίσεις φίλτÏου",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Οι στήλες είναι οÏατές",
+ "srf-ui-datatables-label-sEmptyTable": "∆εν υπάÏχουν δεδομένα διαθέσιμα στον πίνακα",
+ "srf-ui-datatables-label-sInfo": "Εμφάνιση _START_ έως _END_ από _TOTAL_ καταχωÏίσεις",
+ "srf-ui-datatables-label-sInfoEmpty": "Εμφάνιση 0 έως 0 από 0 καταχωÏίσεις",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLoadingRecords": "Γίνεται φόÏτωση...",
+ "srf-ui-datatables-label-sProcessing": "Γίνεται επεξεÏγασία...",
+ "srf-ui-datatables-label-sSearch": "Αναζήτηση:",
+ "srf-ui-datatables-label-sZeroRecords": "Δεν βÏέθηκαν εγγÏαφές που να ταιÏιάζουν",
+ "srf-ui-datatables-label-oPaginate-sFirst": "ΠÏώτο",
+ "srf-ui-datatables-label-oPaginate-sLast": "Τελευταίο",
+ "srf-ui-datatables-label-oPaginate-sNext": "Επόμενο",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "ΠÏοηγοÏμενο",
+ "srf-printername-tree": "ΔέντÏο",
+ "srf-printername-ultree": "ΔέντÏο Ï„Ïπου μη αÏιθμημένης λίστας",
+ "srf-printername-oltree": "ΔέντÏο Ï„Ïπου αÏιθμημένης λίστας",
+ "srf-tree-noparentprop": "Δεν δόθηκε γονική ιδιότητα. Το δέντÏο δεν μποÏεί να δημιουÏγηθεί χωÏίς να έχει καθοÏιστεί γονική ιδιότητα.",
+ "srf-tree-rootinvalid": "Το «$1» δεν είναι έγκυÏος τίτλος σελίδας.",
+ "srf-paramdesc-tree-parent": "Ιδιότητα που πεÏιέχει την γονική σελίδα",
+ "srf-paramdesc-tree-root": "Ριζική σελίδα του δέντÏου",
+ "srf-paramdesc-tree-startlevel": "ΕναÏκτήÏιο επίπεδο του δέντÏου, Ï€.χ. για την ενσωμάτωσή του σε άλλο δέντÏο",
+ "srf-printername-slideshow": "ΠαÏουσίαση διαφανειών",
+ "srf-paramdesc-delay": "ΚαθυστέÏηση Î¼ÎµÏ„Î±Î¾Ï Î´Î¹Î±Ï†Î±Î½ÎµÎ¹ÏŽÎ½ σε δευτεÏόλεπτα",
+ "srf-paramdesc-navigation-controls": "Εμφάνιση ή μη στοιχείων ελέγχου πλοήγησης",
+ "srf-paramdesc-effect": "Εφέ που θα χÏησιμοποιηθεί για την εναλλαγή από διαφάνεια σε διαφάνεια",
+ "srf-paramdesc-filtered-filter-position": "Η θέση των φίλτÏων σε σχέση με τις Ï€Ïοβολές. ΕπιτÏεπτές τιμές: «top», «bottom». ΠÏοεπιλογή: «top».",
+ "srf-paramdesc-filtered-list-type": "ΤÏπος λίστας. ΕπιτÏεπτές τιμές: «list», «ul», «ol». ΠÏοεπιλογή: «list».",
+ "srf-paramdesc-filtered-list-template": "Το Ï€Ïότυπο που χÏησιμοποιείται για τη μοÏφοποίηση των καταχωÏήσεων της λίστας.",
+ "srf-paramdesc-filtered-list-named-args": "Ονοματοδοσία των οÏισμάτων που πασάÏονται στο Ï€Ïότυπο.",
+ "srf-paramdesc-filtered-list-introtemplate": "Όνομα Ï€ÏοτÏπου που θα εμφανίζεται Ï€Ïιν από τα αποτελέσματα του εÏωτήματος, αν υπάÏχουν.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Όνομα Ï€ÏοτÏπου που θα εμφανίζεται μετά από τα αποτελέσματα του εÏωτήματος, αν υπάÏχουν.",
+ "srf-paramdesc-filtered-calendar-start": "Η εκτÏπωση που πεÏιέχει την ημεÏομηνία έναÏξης του συμβάντος",
+ "srf-paramdesc-filtered-calendar-end": "Η εκτÏπωση που πεÏιέχει την ημεÏομηνία λήξης του συμβάντος",
+ "srf-paramdesc-filtered-calendar-title": "Η εκτÏπωση που πεÏιέχει τον τίτλο του συμβάντος. Δεν μποÏεί να χÏησιμοποιηθεί μαζί με τίτλο Ï€ÏοτÏπου.",
+ "srf-paramdesc-filtered-calendar-title-template": "ΠÏότυπο που χÏησιμοποιείται για την μοÏφοποίηση του τίτλου του συμβάντος στο ημεÏολόγιο",
+ "srf-paramdesc-filtered-map-icon": "Η εκτÏπωση που καθοÏίζει την χÏήση της εικόνας χάÏτη",
+ "srf-paramdesc-filtered-map-icons": "Ένας χάÏτης τιμών για εικόνες για να χÏησιμοποιηθεί για αυτές τις τιμές στον χάÏτη.",
+ "srf-filtered-selectorlabel-list": "Κατάλογος",
+ "srf-filtered-selectorlabel-calendar": "ΗμεÏολόγιο",
+ "srf-filtered-selectorlabel-map": "ΧάÏτης",
+ "srf-printername-d3chart": "ΓÏάφημα D3",
+ "srf-printername-timeseries": "ΓÏάφημα χÏονοσειÏάς",
+ "srf-paramdesc-group": "Ομαδοποίηση σειÏών κατά",
+ "srf-paramdesc-zoom": "ΕνεÏγοποίηση ζουμ",
+ "srf-paramdesc-datatable": "ΕνεÏγοποίηση βάσης δεδομένων",
+ "srf-timeseries-zoom-out-of-range": "Το εÏÏος ζουμ δεν παÏήγαγε επαÏκή δεδομένα",
+ "srf-printername-sparkline": "Μίνι διάγÏαμμα εντός γÏαμμής κειμένου",
+ "srf-paramdesc-listtype": "ΚαθοÏισμός Ï„Ïπου λίστας",
+ "srf-paramdesc-widget": "Διαθέσιμα widget",
+ "srf-paramdesc-pageitems": "Στοιχεία ανά σελίδα",
+ "srf-printername-eventcalendar": "ΗμεÏολόγιο εκδηλώσεων",
+ "srf-paramdesc-calendarfirstday": "ΗμέÏα με την οποία ξεκινάει η εβδομάδα",
+ "srf-paramdesc-calendardefaultview": "ΑÏχική Ï€Ïοβολή όταν φοÏτώνει το ημεÏολόγιο",
+ "srf-paramdesc-calendarstart": "ΑÏχική τιμή έναÏξης ημεÏολογίου (ημεÏομηνία ή ÏŽÏα)",
+ "srf-paramdesc-calendarlegend": "ΚαθοÏίζει τη θέση του υπομνήματος και των εκχωÏισμένων επιλογών φιλτÏαÏίσμος",
+ "srf-paramdesc-dayview": "ΕνεÏγοποίηση της Ï€Ïοβολής ημέÏας κάνοντας κλικ στον αÏιθμό ημέÏας",
+ "srf-ui-eventcalendar-label-today": "ΣήμεÏα",
+ "srf-ui-eventcalendar-label-month": "Μήνας",
+ "srf-ui-eventcalendar-label-week": "Εβδομάδα",
+ "srf-ui-eventcalendar-label-day": "ΗμέÏα",
+ "srf-ui-eventcalendar-label-listmonth": "Μήνας (κατάλογος)",
+ "srf-ui-eventcalendar-label-listweek": "Εβδομάδα (κατάλογος)",
+ "srf-ui-eventcalendar-label-listday": "ΗμέÏα (κατάλογος)",
+ "srf-ui-eventcalendar-label-allday": "Όλη μέÏα",
+ "srf-ui-eventcalendar-label-update-success": "Η ενημέÏωση του ημεÏολογίου εκδηλώσεων ήταν επιτυχής.",
+ "srf-ui-eventcalendar-label-update-error": "Η ενημέÏωση του ημεÏολογίου εκδηλώσεων απέτυχε.",
+ "srf-ui-eventcalendar-click-popup": "Θέλετε να δημιουÏγήσετε γεγονός;",
+ "srf-printername-dygraphs": "ΓÏάφημα Dygraphs",
+ "srf-paramdesc-datasource": "Η πηγή από όπου τα δεδομένα είναι Ï€Ïοσβάσιμα. ΕπιτÏεπτές τιμές: «file», «raw» και «url». ΠÏοεπιλογή: «file»",
+ "srf-paramdesc-errorbar": "Η γÏαμμή σφάλματος που θα χÏησιμοποιηθεί. ΕπιτÏεπτές τιμές: «fraction» (διαστήματα εμπιστοσÏνης για τις τιμές), «sigma» (τυπική απόκλιση των τιμών) και «range» (Ï€ÏοσαÏμοσμένες πεÏιοχές τιμών)",
+ "srf-paramdesc-movingaverage": "Εμφανίζει το μέσο ÏŒÏο στη διάÏκεια ενός αÏÎ¹Î¸Î¼Î¿Ï Î·Î¼ÎµÏών (το μηδέν υποδεικνÏει ότι δεν υπάÏχει κυλιόμενος μέσος ÏŒÏος)",
+ "srf-paramdesc-yaxislabel": "ΠεÏιγÏαφή που εμφανίζεται στον άξονα Y",
+ "srf-paramdesc-xaxislabel": "ΠεÏιγÏαφή που εμφανίζεται στον άξονα X",
+ "srf-paramdesc-unit": "Μονάδα",
+ "srf-printername-incoming": "ΕισεÏχόμενες ιδιότητες",
+ "srf-paramdesc-min": "Κατώτατη τιμή ή τιμή κατωφλίου",
+ "srf-paramdesc-excludeproperty": "ΕξαίÏεση ιδιότητας από σÏνολο αποτελεσμάτων",
+ "srf-printername-media": "ΑναπαÏαγωγός πολυμέσων",
+ "srf-paramdesc-mediainspector": "Εμφανίζει λεπτομεÏείς πληÏοφοÏίες σχετικά με οÏισμένο στοιχείο μέσου",
+ "srf-ui-mediaplayer-label-previous": "ΠÏοηγοÏμενο",
+ "srf-ui-mediaplayer-label-play": "ΑναπαÏαγωγή",
+ "srf-ui-mediaplayer-label-pause": "ΠαÏση",
+ "srf-ui-mediaplayer-label-next": "Επόμενο",
+ "srf-ui-mediaplayer-label-stop": "Στοπ",
+ "srf-ui-mediaplayer-label-mute": "Σίγαση",
+ "srf-ui-mediaplayer-label-unmute": "ΚατάÏγηση σίγασης",
+ "srf-ui-mediaplayer-label-volume-max": "Μέγιστη ένταση",
+ "srf-ui-mediaplayer-label-shuffle": "Τυχαία αναπαÏαγωγή",
+ "srf-ui-mediaplayer-label-shuffle-off": "ΑπενεÏγοποίηση τυχαίας αναπαÏαγωγής",
+ "srf-ui-mediaplayer-label-repeat": "Επανάληψη",
+ "srf-ui-mediaplayer-label-repeat-off": "ΑπενεÏγοποίηση επανάληψης",
+ "srf-ui-mediaplayer-label-full-screen": "ΠλήÏης οθόνη",
+ "srf-ui-mediaplayer-label-restore-screen": "ΕπαναφοÏά οθόνης",
+ "srf-paramdesc-icalendar-timezone": "Μια λίστα τοπικών ωÏών χωÏισμένη με κόμμα?"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/en.json b/www/wiki/extensions/SemanticResultFormats/i18n/en.json
new file mode 100644
index 00000000..57c68e5b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/en.json
@@ -0,0 +1,355 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "srf-desc": "Additional result formats for Semantic MediaWiki queries",
+ "srf-name": "Semantic Result Formats",
+ "prefs-srf": "Semantic Result Formats",
+ "srf-prefs-intro-text": "You have installed the Semantic Result Formats extension. Please visit the [https://www.semantic-mediawiki.org/wiki/Help:Result_formats result formats] help page for additional assistance in regards to the user preferences.",
+ "prefs-srf-eventcalendar-options": "Event calendar options",
+ "srf-prefs-eventcalendar-options-update-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatic updates] of calendar events during page refresh",
+ "srf-prefs-eventcalendar-options-paneview-default": "Enable the pane view by default",
+ "prefs-srf-datatables-options": "DataTables options",
+ "srf-prefs-datatables-options-update-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatic updates] of table content during page refresh",
+ "srf-prefs-datatables-options-cache-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage local storage] to improve response time",
+ "srf-module-loading": "Loading...",
+ "srf-paramdesc-layout": "Available layout",
+ "srf-paramdesc-height": "Height",
+ "srf-paramdesc-width": "Width",
+ "srf-paramdesc-class": "Specify an additional cascading style sheet class",
+ "srf-module-nomatch": "No matches found",
+ "srf-paramdesc-charttype": "Available chart type",
+ "srf-navigation-previous": "Previous",
+ "srf-ui-navigation-prev": "Prev",
+ "srf-ui-navigation-next": "Next",
+ "srf-ui-common-label-source": "Source",
+ "srf-ui-common-label-datasource": "Data source",
+ "srf-ui-common-label-ajax-error": "The server reported a failed communication for this $1. Please try to refresh the page or consult with this $2.",
+ "srf-ui-common-label-request-object": "request object",
+ "srf-ui-common-label-help-section": "help section",
+ "srf-ui-tooltip-title-options": "Options",
+ "srf-ui-tooltip-title-scope": "Scope",
+ "srf-ui-tooltip-title-legend": "Legend",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Refresh",
+ "srf-ui-common-label-parameters": "Parameters",
+ "srf-ui-common-label-query": "Query",
+ "srf-ui-common-label-paneview": "Pane view",
+ "srf-ui-common-label-daterange": "Date range",
+ "srf-ui-widgets-label-parameter-limit": "Limit parameter",
+ "srf-error-option-mix": "Option ($1) is not available",
+ "srf-error-option-link-all": "Option ($1) requires parameter \"link\" to be set \"all\"",
+ "srf-error-missing-layout": "The chart or graph cannot be shown because the layout is missing.",
+ "srf-error-jqplot-bubble-data-length": "The chart or graph cannot be shown because data are missing.",
+ "srf-error-jqplot-stackseries-data-length": "The chart or graph cannot be shown because not every bar or line has the same amount of elements.",
+ "srf-warn-empy-chart": "The chart or graph is empty due to missing data",
+ "srf-paramdesc-color": "The color to mark calendar entries",
+ "srfc_previousmonth": "Previous month",
+ "srfc_nextmonth": "Next month",
+ "srfc_today": "Today",
+ "srfc_gotomonth": "Go to month",
+ "srf_printername_calendar": "Monthly calendar",
+ "srf_paramdesc_calendarlang": "The code for the language in which to display the calendar",
+ "srf_paramdesc_calendarcolors": "The color to display for each date property (example: \"Start date=>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "The month, the calendar display is initialized with (defaults to current month)",
+ "srf-paramdesc-calendar-startyear": "The year, the calendar display is initialized with (defaults to current year)",
+ "srf_vcard_link": "vCard",
+ "srf_printername_vcard": "vCard export",
+ "srf_icalendar_link": "iCalendar",
+ "srf_printername_icalendar": "iCalendar export",
+ "srf_paramdesc_icalendartitle": "The title of the calendar file",
+ "srf_paramdesc_icalendardescription": "The description of the calendar file",
+ "srf_bibtex_link": "BibTeX",
+ "srf_printername_bibtex": "BibTeX export",
+ "srf_outline_novalue": "No value",
+ "srf_printername_outline": "Outline",
+ "srf_paramdesc_outlineproperties": "The list of properties to be displayed as outline headers, separated by commas",
+ "srf_printername_sum": "Sum of numbers",
+ "srf_printername_average": "Average of numbers",
+ "srf_printername_max": "Maximum number",
+ "srf_printername_min": "Minimum number",
+ "srf_paramdesc_limit": "The maximum number of pages to query",
+ "srf_printername_product": "Product of numbers",
+ "srf_printername_median": "Median of numbers",
+ "srf-paramdesc-default": "Default value that will be displayed when there are no numerical results",
+ "srf_printername_earliest": "Earliest time",
+ "srf_printername_latest": "Latest time",
+ "srf_printername_timeline": "Timeline",
+ "srf_printername_eventline": "Eventline",
+ "srf_paramdesc_timelinebands": "Defines which bands are displayed in the result.",
+ "srf_paramdesc_timelineposition": "Defines where the timeline initially focuses at.",
+ "srf_paramdesc_timelinestart": "A property name used to define a first time point",
+ "srf_paramdesc_timelineend": "A property name used to define a second time point",
+ "srf_paramdesc_timelinesize": "The height of the timeline",
+ "srf-timeline-allresults": "Further results for this query.",
+ "srf-timeline-nojs": "You need to have JavaScript enabled to view the interactive timeline.",
+ "srf_paramdesc_views": "The views to be displayed",
+ "srf_paramdesc_facets": "The set of properties to be displayed for each page",
+ "srf_paramdesc_lens": "The name of a template with which to display page properties",
+ "srf_printername_googlebar": "Google bar chart",
+ "srf_printername_googlepie": "Google pie chart",
+ "srf-printername-jqplotchart": "jqPlot chart",
+ "srf-printername-jqplotseries": "jqPlot series",
+ "srf_paramdesc_chartheight": "Specify the height (in pixels) of a chart or graph",
+ "srf_paramdesc_chartwidth": "Specify the width (in pixels or percent) of a chart or graph",
+ "srf_paramdesc_charttitle": "The title of the chart",
+ "srf_paramdesc_barcolor": "Specify chart colors",
+ "srf_paramdesc_bardirection": "Specify the direction of a chart",
+ "srf-paramdesc-direction": "Specify the direction of a chart or graph",
+ "srf_paramdesc_barnumbersaxislabel": "The label for the numbers axis",
+ "srf-paramdesc-labelaxislabel": "The label for the label axis",
+ "srf-paramdesc-ticklabels": "Enable display of tick labels",
+ "srf-paramdesc-minvalue": "The minimum value to show on the Y-axis",
+ "srf-paramdesc-pointlabels": "Display in-chart data points",
+ "srf-paramdesc-chartlegend": "Chart legend position",
+ "srf-paramdesc-datalabels": "Chart/graph data labels",
+ "srf-paramdesc-charttext": "Descriptive chart text",
+ "srf-paramdesc-chartclass": "Additional CSS class",
+ "srf-paramdesc-renderer": "Select a graph/chart renderer",
+ "srf-paramdesc-filling": "Individual filling option",
+ "srf-paramdesc-theme": "Select a grid theme",
+ "srf-paramdesc-chartcolor": "Assign individual chart colors",
+ "srf-paramdesc-colorscheme": "Select a color scheme",
+ "srf-paramdesc-valueformat": "Specify formatting rule for values",
+ "srf-paramdesc-highlighter": "Display a data point highlighter",
+ "srf-paramdesc-smoothlines": "Apply a smoothing algorithm on line charts",
+ "srf-paramdesc-stackseries": "Display chart as stacked series",
+ "srf-paramdesc-seriesgroup": "Select series grouping",
+ "srf-paramdesc-serieslabel": "Determine the series label",
+ "srf-paramdesc-grouplabel": "Determine the group label",
+ "srf-paramdesc-chartcursor": "Chart cursor display option",
+ "srf-paramdesc-trendline": "Enable simultaneous display of a chart and its trendline",
+ "srf-paramdesc-gridview": "Display chart and data sets simultaneously. Allowed values: \"none\" and \"tabs\". Default: \"none\"",
+ "srf-paramdesc-paneview": "Specify the position of the pane containing a small line chart. Allowed values: \"bottom\", \"top\" and \"none\". Default: \"bottom\"",
+ "srf-paramdesc-infotext": "Display additional information on a corresponding info tab",
+ "srf-paramdesc-clicktarget": "Define a page or query string as target when clicking on a calendar date.",
+ "srf-ui-gridview-label-item": "Data item",
+ "srf-ui-gridview-label-value": "Data value",
+ "srf-ui-gridview-label-series": "Data series",
+ "srf-ui-gridview-label-chart-tab": "Chart",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Gallery",
+ "srf_paramdesc_perrow": "The amount of images per row",
+ "srf_paramdesc_widths": "The width of the images",
+ "srf_paramdesc_heights": "The height of the images",
+ "srf_paramdesc_autocaptions": "Use filename as caption when none is provided",
+ "srf_paramdesc_fileextensions": "When using the filename as caption, also display the file extension",
+ "srf_paramdesc_captionproperty": "The name of a semantic property present on the queried pages to be used as caption",
+ "srf_paramdesc_imageproperty": "Name of a semantic property on the queried pages that points to images to use. When set, the queried pages themselves will not be displayed as images",
+ "srf-paramdesc-redirects": "The name of a semantic property present on the queried pages which contain the redirect target",
+ "srf-paramdesc-navigation": "Layout navigation control",
+ "srf-paramdesc-overlay": "Enable image overlay",
+ "srf-gallery-navigation-previous": "Previous",
+ "srf-gallery-navigation-next": "Next",
+ "srf-gallery-overlay-count": "Image $1 of $2",
+ "srf-gallery-image-url-error": "The image was not found.",
+ "srf_printername_tagcloud": "Tag cloud",
+ "srf_paramdesc_includesubject": "Subject names themselves should be included",
+ "srf_paramdesc_increase": "How to increase the size of tags",
+ "srf_paramdesc_tagorder": "The order of the tags",
+ "srf_paramdesc_mincount": "The minimum amount of times a value needs to occur to be listed",
+ "srf_paramdesc_minsize": "The size of the smallest tags in percent",
+ "srf_paramdesc_maxsize": "The size of the biggest tags in percent",
+ "srf_paramdesc_maxtags": "The maximum amount of tags in the cloud",
+ "srf-paramdesc-excludetags": "Exclude tags (delimiter: \";\")",
+ "srf_printername_valuerank": "Value rank",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Whether to show page titles as result entries or to leave them out",
+ "srf_paramdesc_hidegaps": "Whether to print requested, but unavailable property and record values separated by separators or leaving them out",
+ "srf_paramdesc_arrayname": "If given and ArrayExtension is available this will create an array with the specified name (no visible output then)",
+ "srf_paramdesc_propsep": "Separator between the requested properties",
+ "srf_paramdesc_manysep": "Separator between many valued property values",
+ "srf_paramdesc_recordsep": "Separator between values of record properties",
+ "srf_paramdesc_headersep": "Separator between property name and value if \"headers\" is set to \"show\" or \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "If given and the HashTables extension is available this will create a hash with the specified name (no visible output then)",
+ "srf-printername-graph": "Graph",
+ "srf-paramdesc-graph-relation": "Sets whether the subjects or nameproperties are parents or childs",
+ "srf-paramdesc-graph-nameprop": "Sets the property that will be used as subject instead of the actual subject, i.e. page name",
+ "srf-paramdesc-graph-nodeshape": "Sets the shape of each node on the graph",
+ "srf-paramdesc-graphname": "Sets the title of the graph",
+ "srf-paramdesc-graphsize": "Sets the size of the graph in pixels",
+ "srf-paramdesc-graphlegend": "Sets whether a graph legend should be shown",
+ "srf-paramdesc-graphlabel": "Sets the label of the graph",
+ "srf-paramdesc-rankdir": "Sets the direction of the arrows",
+ "srf-paramdesc-graphlink": "Sets whether nodes should link to their wiki pages",
+ "srf-paramdesc-graphcolor": "Sets the color of the graph",
+ "srf-paramdesc-graph-wwl": "Sets the word wrap limit (in number of characters)",
+ "srf-paramdesc-clustercolor": "Sets the colors the cluster boxes",
+ "srf-paramdesc-highlight": "Sets the node to be highlighted",
+ "srf-paramdesc-highlightcolor": "Sets the font color for the highlighted node",
+ "srf-paramdesc-redlinkcolor": "Sets the font color for the red links",
+ "srf-paramdesc-processcategory": "Sets the wiki category collecting the process steps",
+ "srf-paramdesc-showroles": "Shows the corresponding roles in the graph",
+ "srf-paramdesc-showstatus": "Sets whether a process step status should be rendered",
+ "srf-paramdesc-showresources": "Shows the corresponding resources in the graph",
+ "srf-paramdesc-showdiscussion": "Sets whether a discussion should be rendered",
+ "srf-paramdesc-showredlinks": "Sets whether red links should be checked and highlighted",
+ "srf-paramdesc-showcompound": "Sets whether to highlight compound nodes, i.e. subprocesses",
+ "srf-paramdesc-debug": "Sets whether the process graph code should be shown wrapped pre tags",
+ "srf-paramdesc-graphvalidation": "Displays the process steps in red which do not have a assigned role",
+ "srf-printername-datatables": "DataTables",
+ "srf-ui-datatables-label-conditions": "Conditions",
+ "srf-ui-datatables-label-parameters": "Parameters",
+ "srf-ui-datatables-label-filters": "Column filters and search",
+ "srf-ui-datatables-label-information": "Information",
+ "srf-ui-datatables-panel-disclaimer": "Parameters and conditions can be altered, but any change is temporary and abandoned after a page refresh.",
+ "srf-ui-datatables-label-update-success": "The table update was successful",
+ "srf-ui-datatables-label-update-error": "The table update failed.",
+ "srf-ui-datatables-label-placeholder-column-search": "Search...",
+ "srf-ui-datatables-label-content-cache": "The content was derived from local cache.",
+ "srf-ui-datatables-label-content-server": "The content was derived from the server.",
+ "srf-ui-datatables-label-multiselect-column-header": "Available columns",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filter settings",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Columns are visible",
+ "srf-ui-datatables-label-sEmptyTable": "No data available in table",
+ "srf-ui-datatables-label-sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+ "srf-ui-datatables-label-sInfoEmpty": "Showing 0 to 0 of 0 entries",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtered from _MAX_ total entries)",
+ "srf-ui-datatables-label-sInfoPostFix": "",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Show _MENU_ entries",
+ "srf-ui-datatables-label-sLoadingRecords": "Loading...",
+ "srf-ui-datatables-label-sProcessing": "Processing...",
+ "srf-ui-datatables-label-sSearch": "Search:",
+ "srf-ui-datatables-label-sZeroRecords": "No matching records found",
+ "srf-ui-datatables-label-oPaginate-sFirst": "First",
+ "srf-ui-datatables-label-oPaginate-sLast": "Last",
+ "srf-ui-datatables-label-oPaginate-sNext": "Next",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Previous",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activate to sort column ascending",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": activate to sort column descending",
+ "srf-printername-tree": "Tree",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "No parent property given. The tree can not be built without a specified parent property.",
+ "srf-tree-rootinvalid": "$1 is not a valid page title.",
+ "srf-tree-circledetected": "Circle detected when trying to insert $1 into the tree.",
+ "srf-paramdesc-tree-parent": "The property containing the parent page",
+ "srf-paramdesc-tree-root": "The root page of the tree",
+ "srf-paramdesc-tree-startlevel": "The start level of the tree, e.g. for integrating it into another tree",
+ "srf-printername-slideshow": "SlideShow",
+ "srf-paramdesc-delay": "The delay between slides in seconds",
+ "srf-paramdesc-navigation-controls": "Show navigation controls or not",
+ "srf-paramdesc-effect": "The effect to be used to switch from slide to slide",
+ "srf-printername-filtered": "Filtered",
+ "srf-paramdesc-filtered-views": "The views that shall be available in the result display.",
+ "srf-paramdesc-filtered-filter-position": "The position of the filters in relation to the views. Allowed values: \"top\", \"bottom\". Default: \"top\".",
+ "srf-paramdesc-filtered-list-type": "The type of the list. Allowed values: \"list\", \"ul\", \"ol\". Default: \"list\".",
+ "srf-paramdesc-filtered-list-template": "The template that is to be used to format the list entries.",
+ "srf-paramdesc-filtered-list-named-args": "Name the arguments passed to the template.",
+ "srf-paramdesc-filtered-list-introtemplate": "The name of a template to display before the query results, if there are any.",
+ "srf-paramdesc-filtered-list-outrotemplate": "The name of a template to display after the query results, if there are any.",
+ "srf-paramdesc-filtered-calendar-start": "The printout containing the start date of an event",
+ "srf-paramdesc-filtered-calendar-end": "The printout containing the end date of an event",
+ "srf-paramdesc-filtered-calendar-title": "The printout containing the title of an event. Can not be used together with a title template.",
+ "srf-paramdesc-filtered-calendar-title-template": "A template used to format the event's title in the calendar",
+ "srf-paramdesc-filtered-map-position": "The printout containing the geographical position.",
+ "srf-paramdesc-filtered-map-icon": "The printout which decides the map icon to be used.",
+ "srf-paramdesc-filtered-map-icons": "A map of values to icons to be used for these values on the map.",
+ "srf-paramdesc-filtered-map-height": "The height of the map.",
+ "srf-paramdesc-filtered-map-zoom": "The zoom level when the map is loaded. This may be changed by the user.<br>See: <i>map view min zoom</i> and <i>map view max zoom</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "The minimum selectable zoom level of the map",
+ "srf-paramdesc-filtered-map-max-zoom": "The maximum selectable zoom level of the map",
+ "srf-paramdesc-filtered-map-marker-cluster": "Turn marker clustering on or off.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Maximum zoom level at which map markers are still clustered. Above this level markers will always be unclustered.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "The maximum radius that a cluster will cover from the central marker (in pixels). Default 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "When enabled clicking cluster will zoom to its bounds.",
+ "srf-filtered-selectorlabel-list": "List",
+ "srf-filtered-selectorlabel-table": "Table",
+ "srf-filtered-selectorlabel-calendar": "Calendar",
+ "srf-filtered-selectorlabel-map": "Map",
+ "srf-filtered-firstdayofweek": "1",
+ "srf-filtered-noscript-error": "Results can not be displayed because Javascript is not enabled. Go to $1.",
+ "srf-filtered-noscript-link-caption": "results in tabular form",
+ "srf-filtered-map-provider-missing-error": "No map provider specified for \"map\" view.",
+ "srf-filtered-value-filter-and": "AND",
+ "srf-filtered-value-filter-or": "OR",
+ "srf-filtered-value-filter-placeholder": "Select a filter value",
+ "srf-printername-d3chart": "D3 chart",
+ "srf-printername-timeseries": "Timeseries chart",
+ "srf-paramdesc-group": "Series grouped by",
+ "srf-paramdesc-zoom": "Enable zoom",
+ "srf-paramdesc-datatable": "Enable a datatable",
+ "srf-timeseries-zoom-out-of-range": "The zoom range did not produce any sufficient data",
+ "srf-printername-sparkline": "Sparkline chart",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Specify the list type",
+ "srf-paramdesc-widget": "Available widget",
+ "srf-paramdesc-pageitems": "Items per page",
+ "srf-printername-eventcalendar": "Event calendar",
+ "srf-paramdesc-calendarfirstday": "The day that each week begins",
+ "srf-paramdesc-calendardefaultview": "The initial view when the calendar loads",
+ "srf-paramdesc-calendarstart": "The initial calendar start (date or datetime values)",
+ "srf-paramdesc-calendarlegend": "Specifies the position of the legend and assigned filter options",
+ "srf-paramdesc-dayview": "Enable the day view by clicking the day number",
+ "srf-ui-eventcalendar-label-today": "Today",
+ "srf-ui-eventcalendar-label-month": "Month",
+ "srf-ui-eventcalendar-label-week": "Week",
+ "srf-ui-eventcalendar-label-day": "Day",
+ "srf-ui-eventcalendar-label-listmonth": "Month (list)",
+ "srf-ui-eventcalendar-label-listweek": "Week (list)",
+ "srf-ui-eventcalendar-label-listday": "Day (list)",
+ "srf-ui-eventcalendar-label-allday": "All day",
+ "srf-ui-eventcalendar-format-time": "h(:mm)t",
+ "srf-ui-eventcalendar-format-time-agenda": "H:mm( - H:mm)",
+ "srf-ui-eventcalendar-format-axis": "H:mm",
+ "srf-ui-eventcalendar-format-title-month": "MMMM YYYY",
+ "srf-ui-eventcalendar-format-title-week": "MMM D, YYYY",
+ "srf-ui-eventcalendar-format-title-day": "MMMM D, YYYY",
+ "srf-ui-eventcalendar-format-column-month": "ddd",
+ "srf-ui-eventcalendar-format-column-week": "ddd M/D",
+ "srf-ui-eventcalendar-format-column-day": "dddd M/D",
+ "srf-ui-eventcalendar-label-update-success": "The event calendar update was successful.",
+ "srf-ui-eventcalendar-label-update-error": "The event calendar update failed.",
+ "srf-ui-eventcalendar-click-popup": "Do you want to create an event?",
+ "srf-printername-dygraphs": "Dygraphs chart",
+ "srf-paramdesc-datasource": "The source from where the data is accessible. Allowed values: \"file\", \"raw\" and \"url\". Default: \"file\"",
+ "srf-paramdesc-errorbar": "The error bar to be used. Allowed values: \"fraction\" (confidence intervals for values), \"sigma\" (standard deviation of values) and \"range\" (custom value ranges)",
+ "srf-paramdesc-movingaverage": "Display the average over a number of days (zero will indicate no moving average)",
+ "srf-paramdesc-yaxislabel": "Description that appears on the y-axis",
+ "srf-paramdesc-xaxislabel": "Description that appears on the x-axis",
+ "srf-paramdesc-unit": "Unit",
+ "srf-printername-pagewidget": "Pagewidget",
+ "srf-printername-incoming": "Incoming properties",
+ "srf-paramdesc-count": "Sets whether the number of incoming properties should be counted",
+ "srf-paramdesc-min": "Minimum or threshold value",
+ "srf-paramdesc-excludeproperty": "Exclude property from result set",
+ "srf-printername-media": "Media player",
+ "srf-paramdesc-mediainspector": "Displays detailed information about a specified media element",
+ "srf-ui-mediaplayer-label-previous": "Previous",
+ "srf-ui-mediaplayer-label-play": "Play",
+ "srf-ui-mediaplayer-label-pause": "Pause",
+ "srf-ui-mediaplayer-label-next": "Next",
+ "srf-ui-mediaplayer-label-stop": "Stop",
+ "srf-ui-mediaplayer-label-mute": "Mute",
+ "srf-ui-mediaplayer-label-unmute": "Unmute",
+ "srf-ui-mediaplayer-label-volume-max": "Max volume",
+ "srf-ui-mediaplayer-label-shuffle": "Shuffle",
+ "srf-ui-mediaplayer-label-shuffle-off": "Shuffle off",
+ "srf-ui-mediaplayer-label-repeat": "Repeat",
+ "srf-ui-mediaplayer-label-repeat-off": "Repeat off",
+ "srf-ui-mediaplayer-label-full-screen": "Full screen",
+ "srf-ui-mediaplayer-label-restore-screen": "Restore screen",
+ "srf-spreadsheet-link": "Spreadsheet",
+ "srf-paramdesc-spreadsheet-filename": "The filename for the download of the generated spreadsheet file",
+ "srf-paramdesc-spreadsheet-fileformat": "The format to be produced for the spreadsheet file. Allowed values: xlsx, xls, ods, csv. Default: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "The name of a spreadsheet file from the ''File'' namespace used for formatting the generated file",
+ "srf-paramdesc-icalendar-timezone": "A comma separated list of timezones",
+ "srf-paramdesc-gantt-diagramtitle": "Diagram name",
+ "srf-paramdesc-gantt-diagramtheme": "Diagram theme",
+ "srf-paramdesc-gantt-axisformat": "X-axis: Date format",
+ "srf-paramdesc-gantt-sortkey": "Key to sort sections and tasks",
+ "srf-paramdesc-gantt-titletopmargin": "Top margin of the diagram title",
+ "srf-paramdesc-gantt-barheight": "Height of task bars",
+ "srf-paramdesc-gantt-leftpadding": "Width of section title",
+ "srf-paramdesc-gantt-bargap": "Vertical distance of tasks bars from the margin",
+ "srf-error-gantt-mapping-assignment": "Wrong assignment of mapped values in '''$1'''",
+ "srf-error-gantt-mapping-keywords": "The key used in your mapping parameter is not supported",
+ "srf-error-gantt-theme" : "The '''theme''' you have choosen is not supported",
+ "srf-error-gantt-sortkey" : "The '''sortkey''' you have choosen is not supported",
+ "srf-error-gantt-mermaid-not-installed": "Mermaid Extension needs to be installed.",
+ "srf-printername-gantt": "Gantt",
+ "srf-paramdesc-nodelabel": "Use a graph node label. Allowed values: displaytitle."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/eo.json b/www/wiki/extensions/SemanticResultFormats/i18n/eo.json
new file mode 100644
index 00000000..bf4d08d4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/eo.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yekrats"
+ ]
+ },
+ "srfc_previousmonth": "AntaÅ­a monato",
+ "srfc_nextmonth": "Posta monato",
+ "srfc_today": "HodiaÅ­",
+ "srfc_gotomonth": "Iru al monato",
+ "srf_printername_calendar": "Monata kalendaro",
+ "srf_icalendar_link": "iKalendaro",
+ "srf_outline_novalue": "Sen valoro",
+ "srf_printername_sum": "Sumo de nombroj",
+ "srf_printername_average": "AveraÄo de nombroj",
+ "srf_printername_max": "Maksimuma nombro",
+ "srf_printername_min": "Minimuma nombro",
+ "srf_printername_timeline": "Templinio",
+ "srf_printername_eventline": "Eventlinio",
+ "srf_printername_gallery": "Galerio"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/es.json b/www/wiki/extensions/SemanticResultFormats/i18n/es.json
new file mode 100644
index 00000000..c0d46d9c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/es.json
@@ -0,0 +1,339 @@
+{
+ "@metadata": {
+ "authors": [
+ "Antur",
+ "Armando-Martin",
+ "Badon",
+ "Crazymadlover",
+ "Imre",
+ "Jewbask",
+ "Maor X",
+ "McDutchie",
+ "Ralgis",
+ "Sanbec",
+ "Translationista",
+ "VegaDark",
+ "Fitoschido",
+ "Macofe",
+ "Indiralena",
+ "Lemondoge",
+ "Dgstranz",
+ "Julián L",
+ "Luzcaru",
+ "Peter Bowman",
+ "Nemo bis",
+ "KATRINE1992",
+ "Amaia",
+ "AVIADOR71",
+ "Yllelder",
+ "Ciencia Al Poder"
+ ]
+ },
+ "srf-desc": "Formatos de resultados adicionales para consultas de Semantic MediaWiki",
+ "prefs-srf": "Formatos de resultados semánticos",
+ "srf-prefs-intro-text": "Tienes instalada la extensión para dar formato a los resultados semánticos. Para obtener ayuda adicional, visita la página de ayuda sobre los [https://www.semantic-mediawiki.org/wiki/Help:Result_formats formatos de los resultados].",
+ "prefs-srf-eventcalendar-options": "Opciones de eventos de calendario",
+ "srf-prefs-eventcalendar-options-update-default": "Desactivar [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatic updates] de eventos de calendario durante la recarga de las páginas",
+ "srf-prefs-eventcalendar-options-paneview-default": "Activar el panel de vista de manera predeterminada",
+ "prefs-srf-datatables-options": "Opciones de DataTables",
+ "srf-prefs-datatables-options-update-default": "Activar [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates actualizaciones automáticas] del contenido de la tabla durante la actualización de la página",
+ "srf-prefs-datatables-options-cache-default": "Desactivar [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage local storage] para mejorar el tiempo de respuesta",
+ "srf-module-loading": "Cargando...",
+ "srf-paramdesc-layout": "Diseño disponible",
+ "srf-paramdesc-height": "Altura",
+ "srf-paramdesc-width": "Anchura",
+ "srf-paramdesc-class": "Especificar una clase adicional de hoja de estilos en cascada (CSS)",
+ "srf-module-nomatch": "No se encontraron coincidencias",
+ "srf-paramdesc-charttype": "Tipo de gráfico disponible",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "Anterior",
+ "srf-ui-navigation-next": "Siguiente",
+ "srf-ui-common-label-source": "Fuente",
+ "srf-ui-common-label-datasource": "Fuente de datos",
+ "srf-ui-common-label-ajax-error": "El servidor informó sobre una comunicación fallida del elemento $1. Intenta actualizar la página o consultar con $2.",
+ "srf-ui-common-label-request-object": "objeto de la solicitud",
+ "srf-ui-common-label-help-section": "sección de ayuda",
+ "srf-ui-tooltip-title-options": "Opciones",
+ "srf-ui-tooltip-title-scope": "Ãmbito de aplicación",
+ "srf-ui-tooltip-title-legend": "Leyenda",
+ "srf-ui-tooltip-title-filter": "Filtro",
+ "srf-ui-common-label-refresh": "Actualizar",
+ "srf-ui-common-label-parameters": "Parámetros",
+ "srf-ui-common-label-query": "Consulta",
+ "srf-ui-common-label-paneview": "Vista del panel de",
+ "srf-ui-common-label-daterange": "Intervalo de fechas",
+ "srf-ui-widgets-label-parameter-limit": "Limitar parámetro",
+ "srf-error-option-mix": "La opción ($1) no está disponible",
+ "srf-error-option-link-all": "La opción ($1) necesita que el parámetro \"link\" esté definido como \"all\"",
+ "srf-error-missing-layout": "No se puede mostrar el gráfico porque falta el diseño.",
+ "srf-error-jqplot-bubble-data-length": "No es posible mostrar el diagrama o el gráfico por falta de datos.",
+ "srf-error-jqplot-stackseries-data-length": "No se puede mostrar el gráfico porque no todas las barras o líneas tienen la misma cantidad de elementos.",
+ "srf-warn-empy-chart": "La tabla/gráfica está vacía porque faltan datos",
+ "srf-paramdesc-color": "El color para marcar las entradas de calendario",
+ "srfc_previousmonth": "Mes anterior",
+ "srfc_nextmonth": "Próximo mes",
+ "srfc_today": "Hoy",
+ "srfc_gotomonth": "Ir al mes",
+ "srf_printername_calendar": "Calendario mensual",
+ "srf_paramdesc_calendarlang": "El código del idioma en el que se muestra el calendario",
+ "srf_paramdesc_calendarcolors": "El color a mostrar para cada propiedad de datos (ejemplo: \"Fecha de inicio=>green, Fecha de fin=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "El mes con el cual se inicializa la pantalla de calendario (si se omite es el mes actual)",
+ "srf-paramdesc-calendar-startyear": "El año con el cual se inicializa la pantalla de calendario (si se omite es el año actual)",
+ "srf_printername_vcard": "Exportar vCard",
+ "srf_printername_icalendar": "Exportar iCalendar",
+ "srf_paramdesc_icalendartitle": "El título del archivo de calendario",
+ "srf_paramdesc_icalendardescription": "La descripción del archivo de calendario",
+ "srf_printername_bibtex": "Exportar BibTeX",
+ "srf_outline_novalue": "Sin valor",
+ "srf_printername_outline": "Esquema",
+ "srf_paramdesc_outlineproperties": "La lista de propiedades que se mostrará como encabezados de esquema, separadas por comas",
+ "srf_printername_sum": "Suma de números",
+ "srf_printername_average": "Promedio de números",
+ "srf_printername_max": "Número máximo",
+ "srf_printername_min": "Número mínimo",
+ "srf_paramdesc_limit": "La cantidad máxima de páginas que consultar",
+ "srf_printername_product": "Producto de números",
+ "srf_printername_median": "Mediana de los números",
+ "srf-paramdesc-default": "Valor predeterminado que se mostrará cuando no haya resultados numéricos",
+ "srf_printername_earliest": "Primera hora",
+ "srf_printername_latest": "Última hora",
+ "srf_printername_timeline": "Línea de tiempo",
+ "srf_printername_eventline": "Línea de eventos",
+ "srf_paramdesc_timelinebands": "Define cuáles bandas se muestran en el resultado.",
+ "srf_paramdesc_timelineposition": "Define donde se enfocará inicialmente la línea de tiempo.",
+ "srf_paramdesc_timelinestart": "Un nombre de propiedad utilizado para definir un primer punto temporal",
+ "srf_paramdesc_timelineend": "Un nombre de propiedad utilizado para definir un segundo punto temporal",
+ "srf_paramdesc_timelinesize": "La altura de la línea de tiempo",
+ "srf-timeline-allresults": "Resultados adicionales para esta consulta.",
+ "srf-timeline-nojs": "Debe tener habilitado JavaScript para ver la línea de tiempo interactiva.",
+ "srf_paramdesc_views": "Las vistas que se mostrarán",
+ "srf_paramdesc_facets": "El grupo de propiedades a mostrar para cada página",
+ "srf_paramdesc_lens": "El nombre de una plantilla con la que se muestra la propiedades de la página",
+ "srf_printername_googlebar": "Gráfico de barras de Google",
+ "srf_printername_googlepie": "Gráfica circular de Google",
+ "srf-printername-jqplotchart": "Gráfica jqPlot",
+ "srf-printername-jqplotseries": "Serie jqPlot",
+ "srf_paramdesc_chartheight": "Especifica la altura (en píxeles) de una tabla o una gráfica",
+ "srf_paramdesc_chartwidth": "Especificar la anchura (en píxeles o porcentaje) de la tabla o gráfica",
+ "srf_paramdesc_charttitle": "El título del gráfico",
+ "srf_paramdesc_barcolor": "Especificar los colores del gráfico",
+ "srf_paramdesc_bardirection": "Especifique la dirección de un gráfico",
+ "srf-paramdesc-direction": "Especificar la dirección de una tabla o una gráfica",
+ "srf_paramdesc_barnumbersaxislabel": "La etiqueta del eje de los números",
+ "srf-paramdesc-labelaxislabel": "La etiqueta para el eje de la etiqueta",
+ "srf-paramdesc-ticklabels": "Activar la visualización de etiquetas de marca",
+ "srf-paramdesc-minvalue": "El valor mínimo que mostrar en el eje de ordenadas",
+ "srf-paramdesc-pointlabels": "Visualización de datos puntuales en la gráfica",
+ "srf-paramdesc-chartlegend": "Posición de la leyenda de la gráfica",
+ "srf-paramdesc-datalabels": "Rótulos de datos de la tabla/gráfica",
+ "srf-paramdesc-charttext": "Texto descriptivo del gráfico",
+ "srf-paramdesc-chartclass": "Clase CSS adicional",
+ "srf-paramdesc-renderer": "Seleccione un representador tablas/gráficas",
+ "srf-paramdesc-filling": "Opción de rellenado individual",
+ "srf-paramdesc-theme": "Selecciona un tema de cuadrícula",
+ "srf-paramdesc-chartcolor": "Asignar colores individuales al gráfico",
+ "srf-paramdesc-colorscheme": "Seleccione una combinación de colores",
+ "srf-paramdesc-valueformat": "Especifica una regla de formato para valores",
+ "srf-paramdesc-highlighter": "Mostrar un marcador de punto de datos",
+ "srf-paramdesc-smoothlines": "Aplicar un algoritmo de suavizado en los gráficos de líneas",
+ "srf-paramdesc-stackseries": "Mostrar gráfico en forma de serie apilada",
+ "srf-paramdesc-seriesgroup": "Seleccionar agrupamientos de series",
+ "srf-paramdesc-serieslabel": "Determinar la etiqueta de serie",
+ "srf-paramdesc-grouplabel": "Determinar la etiqueta de grupo",
+ "srf-paramdesc-chartcursor": "Opción de visualización del cursor de tabla",
+ "srf-paramdesc-trendline": "Activar la visualización simultánea de un gráfico y su línea de tendencia",
+ "srf-paramdesc-gridview": "Mostrar simultáneamente gráfico y conjunto de datos. Valores permitidos: \"none\" y \"tabs\". Predeterminado: \"none\"",
+ "srf-paramdesc-paneview": "Indica la posición del panel que contiene un pequeño gráfico de líneas. Valores permitidos: \"abajo\", \"arriba\" y \"ninguno\". Predeterminado: \"abajo\"",
+ "srf-paramdesc-infotext": "Mostrar información adicional en una ficha de información correspondiente",
+ "srf-paramdesc-clicktarget": "Define una página o cadena de consulta como destino al hacer clic en una fecha del calendario.",
+ "srf-ui-gridview-label-item": "Elemento de datos",
+ "srf-ui-gridview-label-value": "Valor de los datos",
+ "srf-ui-gridview-label-series": "Serie de datos",
+ "srf-ui-gridview-label-chart-tab": "Gráfico",
+ "srf-ui-gridview-label-data-tab": "Datos",
+ "srf-ui-gridview-label-info-tab": "Información",
+ "srf_printername_gallery": "Galería",
+ "srf_paramdesc_perrow": "La cantidad de imágenes por fila",
+ "srf_paramdesc_widths": "La anchura de las imágenes",
+ "srf_paramdesc_heights": "La altura de las imágenes",
+ "srf_paramdesc_autocaptions": "Usar el nombre del archivo como pie de imagen cuando no se indique ninguna otra",
+ "srf_paramdesc_fileextensions": "Cuando se use el nombre del archivo como pie de imagen, mostrar también la extensión del archivo",
+ "srf_paramdesc_captionproperty": "El nombre de una propiedad semántica presente en las páginas consultadas a usar como pie de imagen",
+ "srf_paramdesc_imageproperty": "Nombre de una propiedad semántica en las páginas consultadas que apunta a las imágenes a usar. Cuando esté definido, las propias páginas consultadas no se mostrarán como imágenes",
+ "srf-paramdesc-redirects": "El nombre de una propiedad semántica presente en las páginas consultadas que contienen el destino de la redirección",
+ "srf-paramdesc-navigation": "Diseñar control de navegación",
+ "srf-paramdesc-overlay": "Activar la superposición de imágenes",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Siguiente",
+ "srf-gallery-overlay-count": "Imagen $1 de $2",
+ "srf-gallery-image-url-error": "No se encontró la imagen.",
+ "srf_printername_tagcloud": "Nube de etiquetas",
+ "srf_paramdesc_includesubject": "Si los propios nombres de los temas deben incluirse",
+ "srf_paramdesc_increase": "Como aumentar el tamaño de las etiquetas",
+ "srf_paramdesc_tagorder": "El orden de las etiquetas",
+ "srf_paramdesc_mincount": "La cantidad mínima de veces que un valor tiene que presentarse para estar en la lista",
+ "srf_paramdesc_minsize": "El tamaño de las etiquetas más pequeñas, en porcentaje",
+ "srf_paramdesc_maxsize": "El tamaño de las etiquetas más grandes en porcentaje",
+ "srf_paramdesc_maxtags": "La cantidad máxima de etiquetas en la nube",
+ "srf-paramdesc-excludetags": "Excluir etiquetas (delimitador: «;»)",
+ "srf_printername_valuerank": "Valor del rango",
+ "srf_printername_array": "Tabla",
+ "srf_paramdesc_pagetitle": "Mostrar los títulos de las páginas como entradas de resultados, o bien omitirlos",
+ "srf_paramdesc_hidegaps": "Imprimir los valores de las propiedades y de los registros solicitados y no disponibles, separados por separadores,obien omitirlos",
+ "srf_paramdesc_arrayname": "Si se da un ArrayExtension y está disponible, esto creará una tabla con el nombre indicado (sin salida visible, en ese caso)",
+ "srf_paramdesc_propsep": "Separador entre las propiedades solicitadas",
+ "srf_paramdesc_manysep": "Separador entre los valores de las propiedades con muchos valores",
+ "srf_paramdesc_recordsep": "Separador entre los valores de las propiedades de registro",
+ "srf_paramdesc_headersep": "Separador entre el nombre y el valor de la propiedad si \"headers\" está definido como \"show\" o \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Si se da una extensión HashTables y está disponible, esto creará un \"hash\" con el nombre indicado (sin salida visible, en ese caso)",
+ "srf-printername-graph": "Gráfico",
+ "srf-paramdesc-graph-relation": "Establece si los sujetos o las propiedades del nombre son padres o hijos",
+ "srf-paramdesc-graph-nameprop": "Establece la propiedad que se usará como asunto en vez del asunto real. O sea, el nombre de la página",
+ "srf-paramdesc-graph-nodeshape": "Establece la forma de cada nodo en el gráfico",
+ "srf-paramdesc-graphname": "Establece el título del gráfico",
+ "srf-paramdesc-graphsize": "Establece el tamaño del gráfico en píxeles",
+ "srf-paramdesc-graphlegend": "Establece si se debe mostrar una leyenda de gráfico",
+ "srf-paramdesc-graphlabel": "Establece la etiqueta del gráfico",
+ "srf-paramdesc-rankdir": "Establece la dirección de las flechas",
+ "srf-paramdesc-graphlink": "Establece si los nodos deben enlazar a sus páginas wiki",
+ "srf-paramdesc-graphcolor": "Establece el color del gráfico",
+ "srf-paramdesc-graph-wwl": "Establece el límite del ajuste de texto (en número de caracteres)",
+ "srf-paramdesc-clustercolor": "Establece los colores de los cuadros de agrupamiento",
+ "srf-paramdesc-highlight": "Establece el nodo que se resaltará",
+ "srf-paramdesc-highlightcolor": "Establece el color de letra del nodo resaltado",
+ "srf-paramdesc-redlinkcolor": "Establece el color de letra de los enlaces rojos",
+ "srf-paramdesc-processcategory": "Establece la categoría del wiki que recogerá los pasos del proceso",
+ "srf-paramdesc-showroles": "Muestra los roles correspondientes en el gráfico",
+ "srf-paramdesc-showstatus": "Determina si se debe mostrar un estado de etapa del proceso",
+ "srf-paramdesc-showresources": "Muestra los recursos correspondientes en el gráfico",
+ "srf-paramdesc-showdiscussion": "Determina si se debe mostrar una discusión",
+ "srf-printername-datatables": "Tablas de datos",
+ "srf-ui-datatables-label-conditions": "Condiciones",
+ "srf-ui-datatables-label-parameters": "Parámetros",
+ "srf-ui-datatables-label-filters": "Filtros de columnas y búsqueda",
+ "srf-ui-datatables-label-information": "Información",
+ "srf-ui-datatables-panel-disclaimer": "Los parámetros y condiciones se pueden alterar, pero cualquier cambio es temporal y se abandonará tras actualizar la página.",
+ "srf-ui-datatables-label-update-success": "La actualización de la tabla se realizó correctamente",
+ "srf-ui-datatables-label-update-error": "Falló la actualización de la tabla.",
+ "srf-ui-datatables-label-placeholder-column-search": "Buscar…",
+ "srf-ui-datatables-label-content-cache": "El contenido se deriva de la caché local.",
+ "srf-ui-datatables-label-content-server": "El contenido se deriva de la del servidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Columnas disponibles",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Configuración de filtros",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Las columnas son visibles",
+ "srf-ui-datatables-label-sEmptyTable": "No hay datos disponibles en la tabla",
+ "srf-ui-datatables-label-sInfo": "Se muestran _START_ a _END_ de _TOTAL_ entradas",
+ "srf-ui-datatables-label-sInfoEmpty": "Muestra: 0 a 0 de 0 entradas",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtradas de _MAX_ entradas en total)",
+ "srf-ui-datatables-label-sInfoThousands": "&nbsp;",
+ "srf-ui-datatables-label-sLengthMenu": "Mostrar _MENU_ entradas",
+ "srf-ui-datatables-label-sLoadingRecords": "Cargando…",
+ "srf-ui-datatables-label-sProcessing": "Procesando…",
+ "srf-ui-datatables-label-sSearch": "Buscar:",
+ "srf-ui-datatables-label-sZeroRecords": "No se encontró ningún registro que coincidiese",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primero",
+ "srf-ui-datatables-label-oPaginate-sLast": "Último",
+ "srf-ui-datatables-label-oPaginate-sNext": "Siguiente",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activar para ordenar columna ascendentemente",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": activar para ordenar columna descendentemente",
+ "srf-printername-tree": "Ãrbol",
+ "srf-printername-ultree": "Ãrbol UL",
+ "srf-printername-oltree": "Ãrbol OL",
+ "srf-tree-noparentprop": "No se ha especificado ninguna propiedad padre. No se puede construir el árbol sin especificar una propiedad padre.",
+ "srf-tree-rootinvalid": "El título de la página «$1» no es válido.",
+ "srf-tree-circledetected": "Se detectó una referencia circular al tratar de insertar $1 en el árbol.",
+ "srf-paramdesc-tree-parent": "La propiedad que contiene la página padre",
+ "srf-paramdesc-tree-root": "Página raíz del árbol",
+ "srf-paramdesc-tree-startlevel": "El nivel de inicio del árbol, por ejemplo, para integrarlo en otro árbol",
+ "srf-printername-slideshow": "Presentación de diapositivas",
+ "srf-paramdesc-delay": "Tiempo entre diapositivas, en segundos",
+ "srf-paramdesc-navigation-controls": "Mostrar controles de navegación o no mostrarlos",
+ "srf-paramdesc-effect": "El efecto que se utilizará para cambiar de una diapositiva a la siguiente",
+ "srf-printername-filtered": "Filtrado",
+ "srf-paramdesc-filtered-views": "Las vistas que estarán disponibles en la pantalla de resultados.",
+ "srf-paramdesc-filtered-filter-position": "La posición de los filtros en relación con las vistas. Valores permitidos: \"top\", \"bottom\". Predeterminado: \"top\".",
+ "srf-paramdesc-filtered-list-type": "El tipo de la lista. Valores permitidos: \"list\", \"ul\", \"ol\". Predeterminado: \"list\".",
+ "srf-paramdesc-filtered-list-template": "La plantilla que se utilizará para dar formato a las entradas de la lista.",
+ "srf-paramdesc-filtered-list-named-args": "Nombra los argumentos que se le pasan a la plantilla.",
+ "srf-paramdesc-filtered-list-introtemplate": "El nombre de una plantilla que se mostrará antes de los resultados de la consulta, si hay alguna.",
+ "srf-paramdesc-filtered-list-outrotemplate": "El nombre de una plantilla que se mostrará después de los resultados de la consulta, si hay alguna.",
+ "srf-paramdesc-filtered-calendar-start": "La impresión que contiene la fecha de inicio de un evento",
+ "srf-paramdesc-filtered-calendar-end": "La impresión que contiene la fecha final de un evento",
+ "srf-paramdesc-filtered-calendar-title": "La impresión que contiene el título de un evento. No puede utilizarse junto con una plantilla de título.",
+ "srf-paramdesc-filtered-calendar-title-template": "Una plantilla que se utiliza para dar formato al título de un evento en el calendario",
+ "srf-paramdesc-filtered-map-icon": "El printout que decide el icono del mapa para ser utilizado",
+ "srf-paramdesc-filtered-map-icons": "Un mapa de valores a iconos para ser utilizado para estas valores en el mapa",
+ "srf-paramdesc-filtered-map-height": "La altura del mapa.",
+ "srf-paramdesc-filtered-map-min-zoom": "La escala mínima seleccionable del mapa",
+ "srf-paramdesc-filtered-map-max-zoom": "La escala máxima seleccionable del mapa",
+ "srf-paramdesc-filtered-map-marker-cluster": "Activa o desactiva el agrupamiento de marcadores.",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tabla",
+ "srf-filtered-selectorlabel-calendar": "Calendario",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "No se pueden mostrar los resultados porque JavaScript está desactivado. Visita $1.",
+ "srf-filtered-noscript-link-caption": "resultados en formato tabular",
+ "srf-filtered-map-provider-missing-error": "No se especificó ningún proveedor de mapas para la vista «map».",
+ "srf-filtered-value-filter-and": "Y",
+ "srf-filtered-value-filter-or": "O",
+ "srf-filtered-value-filter-placeholder": "Seleccionar un valor de filtro",
+ "srf-printername-d3chart": "Gráfico D3",
+ "srf-printername-timeseries": "Gráfico de series temporales",
+ "srf-paramdesc-group": "Serie agrupada por",
+ "srf-paramdesc-zoom": "Activar el zoom",
+ "srf-paramdesc-datatable": "Activar una tabla de datos",
+ "srf-timeseries-zoom-out-of-range": "El alcance del zoom no produjo datos suficientes",
+ "srf-printername-sparkline": "Gráfico Sparkline",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Especificar el tipo de lista",
+ "srf-paramdesc-widget": "Widget disponible",
+ "srf-paramdesc-pageitems": "Elementos por página",
+ "srf-printername-eventcalendar": "Calendario de eventos",
+ "srf-paramdesc-calendarfirstday": "El día en que comienza cada semana",
+ "srf-paramdesc-calendardefaultview": "Vista inicial cuando se carga el calendario",
+ "srf-paramdesc-calendarstart": "El comienzo del calendario inicial (valores date y datetime)",
+ "srf-paramdesc-calendarlegend": "Especifica la posición de la leyenda y asignados a las opciones de filtro",
+ "srf-paramdesc-dayview": "Habilitar la vista de día haciendo clic en el número del día",
+ "srf-ui-eventcalendar-label-today": "Hoy",
+ "srf-ui-eventcalendar-label-month": "Mes",
+ "srf-ui-eventcalendar-label-week": "Semana",
+ "srf-ui-eventcalendar-label-day": "Día",
+ "srf-ui-eventcalendar-label-listmonth": "Mes (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Semana (lista)",
+ "srf-ui-eventcalendar-label-listday": "Día (lista)",
+ "srf-ui-eventcalendar-label-allday": "Todo el día",
+ "srf-ui-eventcalendar-label-update-success": "El calendario de eventos se actualizó correctamente.",
+ "srf-ui-eventcalendar-label-update-error": "El calendario de eventos de error de actualización.",
+ "srf-ui-eventcalendar-click-popup": "¿Deseas crear un evento?",
+ "srf-printername-dygraphs": "Gráfico Dygraphs",
+ "srf-paramdesc-datasource": "La fuente en la que están accesibles los datos. Valores permitidos: \"file\", \"raw\" y \"url\". Predeterminado: \"file\"",
+ "srf-paramdesc-errorbar": "La barra de error que se utilizará. Valores permitidos: \"fraction\" (intervalos de confianza para valores), \"sigma\" (desviación estándar de los valores) y \"range\" (rangos de valor personalizados)",
+ "srf-paramdesc-movingaverage": "Mostrar el valor promedio en un número de días (cero indicará que no hay media móvil)",
+ "srf-paramdesc-yaxislabel": "Descripción que aparece en el eje y",
+ "srf-paramdesc-xaxislabel": "Descripción que aparece en el eje x",
+ "srf-paramdesc-unit": "Unidad",
+ "srf-printername-pagewidget": "Pagewidget",
+ "srf-printername-incoming": "Propiedades entrantes",
+ "srf-paramdesc-min": "Valor mínimo o umbral",
+ "srf-paramdesc-excludeproperty": "Excluir la propiedad del conjunto de resultados",
+ "srf-printername-media": "Reproductor multimedia",
+ "srf-paramdesc-mediainspector": "Muestra información detallada sobre un elemento multimedia específico",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reproducir",
+ "srf-ui-mediaplayer-label-pause": "Pausar",
+ "srf-ui-mediaplayer-label-next": "Siguiente",
+ "srf-ui-mediaplayer-label-stop": "Detener",
+ "srf-ui-mediaplayer-label-mute": "Silenciar",
+ "srf-ui-mediaplayer-label-unmute": "Activar sonido",
+ "srf-ui-mediaplayer-label-volume-max": "Volumen máximo",
+ "srf-ui-mediaplayer-label-shuffle": "Aleatorizar",
+ "srf-ui-mediaplayer-label-shuffle-off": "Desactivar modo aleatorio",
+ "srf-ui-mediaplayer-label-repeat": "Repetir",
+ "srf-ui-mediaplayer-label-repeat-off": "Desactivar repetición",
+ "srf-ui-mediaplayer-label-full-screen": "Pantalla completa",
+ "srf-ui-mediaplayer-label-restore-screen": "Restaurar la pantalla",
+ "srf-paramdesc-spreadsheet-filename": "El nombre de descarga del archivo de hoja de cálculo generado",
+ "srf-paramdesc-icalendar-timezone": "Una lista de husos horarios separados por comas"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/et.json b/www/wiki/extensions/SemanticResultFormats/i18n/et.json
new file mode 100644
index 00000000..6815cb3f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/et.json
@@ -0,0 +1,49 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne"
+ ]
+ },
+ "srf-module-loading": "Laadimine...",
+ "srf-paramdesc-height": "Kõrgus",
+ "srf-paramdesc-width": "Laius",
+ "srf-navigation-previous": "Eelmine",
+ "srf-ui-navigation-prev": "Eelm",
+ "srf-ui-navigation-next": "Järgmine",
+ "srf-ui-common-label-source": "Allikas",
+ "srf-ui-common-label-datasource": "Andmete allikas",
+ "srfc_previousmonth": "Eelmine kuu",
+ "srfc_nextmonth": "Järgmine kuu",
+ "srfc_today": "Täna",
+ "srfc_gotomonth": "Mine kalendrikuuni",
+ "srf_printername_calendar": "Kalender kuu kaupa",
+ "srf_printername_sum": "Arvude summa",
+ "srf_printername_average": "Arvude keskmine",
+ "srf_printername_max": "Maksimaalne arv",
+ "srf_printername_min": "Minimaalne arv",
+ "srf_printername_earliest": "Varaseim aeg",
+ "srf_printername_latest": "Hiliseim aeg",
+ "srf-ui-gridview-label-data-tab": "Andmed",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galerii",
+ "srf-gallery-navigation-previous": "Eelmine",
+ "srf-gallery-navigation-next": "Järgmine",
+ "srf_paramdesc_graphname": "Pealkiri",
+ "srf-printername-tree": "Puu",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-printername-eventcalendar": "Sündmuste kalender",
+ "srf-ui-eventcalendar-label-today": "Täna",
+ "srf-ui-eventcalendar-label-month": "Kuu",
+ "srf-ui-eventcalendar-label-week": "Nädal",
+ "srf-ui-eventcalendar-label-day": "Päev",
+ "srf-ui-eventcalendar-label-allday": "Terve päev",
+ "srf-ui-mediaplayer-label-previous": "Eelmine",
+ "srf-ui-mediaplayer-label-play": "Mängi",
+ "srf-ui-mediaplayer-label-pause": "Paus",
+ "srf-ui-mediaplayer-label-next": "Järgmine",
+ "srf-ui-mediaplayer-label-stop": "Peata",
+ "srf-ui-mediaplayer-label-repeat": "Kordus",
+ "srf-ui-mediaplayer-label-repeat-off": "Kordus maha",
+ "srf-ui-mediaplayer-label-full-screen": "Täisekraan"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/eu.json b/www/wiki/extensions/SemanticResultFormats/i18n/eu.json
new file mode 100644
index 00000000..4c7fd49c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/eu.json
@@ -0,0 +1,144 @@
+{
+ "@metadata": {
+ "authors": [
+ "An13sa",
+ "Subi",
+ "Mikel Ibaiba",
+ "Sator",
+ "Amaia",
+ "Xabier Armendaritz"
+ ]
+ },
+ "prefs-srf": "Emaitza semantikoen formatuak",
+ "prefs-srf-eventcalendar-options": "Gertaera-egutegi aukerak",
+ "srf-module-loading": "Kargatzen...",
+ "srf-paramdesc-height": "Altuera",
+ "srf-paramdesc-width": "Zabalera",
+ "srf-module-nomatch": "Ez da bat datorren emaitzarik aurkitu",
+ "srf-navigation-previous": "Aurrekoa",
+ "srf-ui-navigation-prev": "Aurr",
+ "srf-ui-navigation-next": "Hurrengoa",
+ "srf-ui-common-label-source": "Iturria",
+ "srf-ui-common-label-datasource": "Datuen iturria",
+ "srf-ui-common-label-help-section": "Laguntza atala",
+ "srf-ui-tooltip-title-options": "Aukerak",
+ "srf-ui-tooltip-title-scope": "Esparrua",
+ "srf-ui-tooltip-title-filter": "Iragazkia",
+ "srf-ui-common-label-refresh": "Freskatu",
+ "srf-ui-common-label-parameters": "Parametroak",
+ "srf-ui-common-label-query": "Kontsulta",
+ "srf-ui-widgets-label-parameter-limit": "Muga-parametroa",
+ "srf-error-option-mix": "($1) aukera ez dago erabilgarri",
+ "srfc_previousmonth": "Aurreko hilabetea",
+ "srfc_nextmonth": "Hurrengo hilabetea",
+ "srfc_today": "Gaur",
+ "srfc_gotomonth": "Hilabetera joan",
+ "srf_printername_calendar": "Hileroko egutegia",
+ "srf_paramdesc_icalendartitle": "Egutegi fitxategiko izenburua",
+ "srf_paramdesc_icalendardescription": "Egutegi fitxategiaren deskripzioa",
+ "srf_outline_novalue": "Baliorik ez",
+ "srf_printername_outline": "Izenburua",
+ "srf_printername_sum": "Zenbakien batura",
+ "srf_printername_average": "Zenbakien batez bestekoa",
+ "srf_printername_max": "Zenbaki handiena",
+ "srf_printername_min": "Zenbaki txikiena",
+ "srf_printername_product": "Zenbakien biderkadura",
+ "srf_printername_median": "Zenbakien mediana",
+ "srf_printername_timeline": "Denbora-lerroa",
+ "srf_printername_eventline": "Gertakari-lerroa",
+ "srf-printername-jqplotchart": "jqPlot taula",
+ "srf_paramdesc_charttitle": "Taularen izenburua",
+ "srf_paramdesc_barcolor": "Zehaztu taula koloreak",
+ "srf_paramdesc_bardirection": "Zehaztu taula baten norabidea",
+ "srf-paramdesc-direction": "Taula edo grafiko baten norabidea zehaztu",
+ "srf-paramdesc-chartclass": "CSS klase gehigarria",
+ "srf-paramdesc-colorscheme": "Eskema kolore bat hautatu",
+ "srf-paramdesc-valueformat": "Zehaztu balioen formatu-araua",
+ "srf-paramdesc-serieslabel": "Serietako etiketa zehaztu",
+ "srf-paramdesc-grouplabel": "Talde etiketa zehaztu",
+ "srf-ui-gridview-label-value": "Datu balioa",
+ "srf-ui-gridview-label-series": "Datu serieak",
+ "srf-ui-gridview-label-chart-tab": "Taula",
+ "srf-ui-gridview-label-data-tab": "Datuak",
+ "srf-ui-gridview-label-info-tab": "Informazioa",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_widths": "Irudien zabalera",
+ "srf_paramdesc_heights": "Irudien altuera",
+ "srf-gallery-navigation-previous": "Aurrekoa",
+ "srf-gallery-navigation-next": "Hurrengoa",
+ "srf-gallery-image-url-error": "Irudia ez da aurkitu.",
+ "srf_printername_tagcloud": "Hodei etiketa",
+ "srf_paramdesc_increase": "Nola handiagotu etiketen tamaina",
+ "srf_paramdesc_tagorder": "Etiketen ordena",
+ "srf_paramdesc_minsize": "Etiketa txikienen tamaina, ehunekotan",
+ "srf_paramdesc_maxsize": "Etiketa handienen tamaina, ehunekotan",
+ "srf_paramdesc_maxtags": "Etiketa gehienezkoaren kantitatea hodeian",
+ "srf_printername_valuerank": "Balio ranking-a",
+ "srf-printername-graph": "Grafikoa",
+ "srf-paramdesc-graphname": "Grafikoaren izenburua zehazten du",
+ "srf-paramdesc-graphsize": "Grafikoak pixeletan duen tamaina ezartzen du",
+ "srf-paramdesc-graphlabel": "Grafikoaren etiketa zehazten du",
+ "srf-paramdesc-rankdir": "Gezien norabidea zehazten du",
+ "srf-paramdesc-graphcolor": "Grafikoaren kolorea zehazten du",
+ "srf-ui-datatables-label-conditions": "Baldintzak",
+ "srf-ui-datatables-label-parameters": "Parametroak",
+ "srf-ui-datatables-label-filters": "Zutabe iragazkiak eta bilaketa",
+ "srf-ui-datatables-label-information": "Informazioa",
+ "srf-ui-datatables-label-placeholder-column-search": "Bilatu...",
+ "srf-ui-datatables-label-multiselect-column-header": "Eskuragarri dauden zutabeak",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Iragazki ezarpenak",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Zutabeak ikusgai daude",
+ "srf-ui-datatables-label-sEmptyTable": "Ez dago daturik eskuragarri taulan",
+ "srf-ui-datatables-label-sInfo": "_START_ to _END_ of _TOTAL_ sarrerak erakusten",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "_MENU_ sarrerak erakutsi",
+ "srf-ui-datatables-label-sLoadingRecords": "Kargatzen...",
+ "srf-ui-datatables-label-sProcessing": "Prozesatzen...",
+ "srf-ui-datatables-label-sSearch": "Bilatu:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Lehena",
+ "srf-ui-datatables-label-oPaginate-sLast": "Azkena",
+ "srf-ui-datatables-label-oPaginate-sNext": "Hurrengoa",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Aurrekoa",
+ "srf-printername-tree": "Zuhaitza",
+ "srf-tree-rootinvalid": "\"$1\" ez da balio duen orri izenburu bat.",
+ "srf-paramdesc-navigation-controls": "Nabigazio kontrolak erakutsi edo ez",
+ "srf-printername-filtered": "Iragazia",
+ "srf-paramdesc-filtered-map-height": "Maparen garaiera.",
+ "srf-paramdesc-filtered-map-zoom": "Zoomaren maila mapa kargatu denean. Erabiltzaileak aldatu dezake. <br>Ikusi: <i>map view min zoom</i> and <i>map view max zoom</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "Mapan hautatu daiteken zoom maila minimoa",
+ "srf-paramdesc-filtered-map-max-zoom": "Mapan hautatu daiteken gehienezko zoom maila",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "Cluster batek beteko duen erratiorik handiena erditik (pixeletan). 80 jatorriz.",
+ "srf-filtered-selectorlabel-list": "Zerrenda",
+ "srf-filtered-selectorlabel-table": "Taula",
+ "srf-filtered-selectorlabel-calendar": "Egutegia",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-map-provider-missing-error": "Ez dago mapa hornitzaile espezifikorik \"mapa\" bistarako.",
+ "srf-filtered-value-filter-and": "ETA",
+ "srf-filtered-value-filter-or": "EDO",
+ "srf-filtered-value-filter-placeholder": "Aukeratu iragazki balio bat",
+ "srf-printername-d3chart": "D3 taula",
+ "srf-paramdesc-zoom": "Zoom-a gaitu",
+ "srf-paramdesc-pageitems": "Elementuak orri bakoitzeko",
+ "srf-printername-eventcalendar": "Gertaera egutegia",
+ "srf-paramdesc-calendarfirstday": "Aste bakoitza hasten den eguna",
+ "srf-paramdesc-calendardefaultview": "Egutegia kargatzerakoan duen hasierako ikuspegia",
+ "srf-ui-eventcalendar-label-today": "Gaur",
+ "srf-ui-eventcalendar-label-month": "Hilabetea",
+ "srf-ui-eventcalendar-label-week": "Astea",
+ "srf-ui-eventcalendar-label-day": "Eguna",
+ "srf-ui-eventcalendar-label-listmonth": "Hilabetea (zerrenda)",
+ "srf-ui-eventcalendar-label-listweek": "Astea (zerrenda)",
+ "srf-ui-eventcalendar-label-listday": "Eguna (zerrenda)",
+ "srf-ui-eventcalendar-label-allday": "Egun osoa",
+ "srf-paramdesc-unit": "Unitatea",
+ "srf-ui-mediaplayer-label-previous": "Aurrekoa",
+ "srf-ui-mediaplayer-label-play": "Erreproduzitu",
+ "srf-ui-mediaplayer-label-pause": "Gelditu",
+ "srf-ui-mediaplayer-label-next": "Hurrengoa",
+ "srf-ui-mediaplayer-label-stop": "Eten",
+ "srf-ui-mediaplayer-label-mute": "Mututu",
+ "srf-ui-mediaplayer-label-volume-max": "Bolumen maximoa",
+ "srf-ui-mediaplayer-label-repeat": "Errepikatu",
+ "srf-ui-mediaplayer-label-repeat-off": "Errepikapenik ez",
+ "srf-ui-mediaplayer-label-full-screen": "Pantaila osoa"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/fa.json b/www/wiki/extensions/SemanticResultFormats/i18n/fa.json
new file mode 100644
index 00000000..049f590f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/fa.json
@@ -0,0 +1,154 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mjbmr",
+ "Tofighi",
+ "Reza1615",
+ "Ebraminio",
+ "Alifakoor",
+ "Alirezaaa",
+ "Huji",
+ "Mahdy Saffar",
+ "Nemo bis",
+ "Ommmmid"
+ ]
+ },
+ "prefs-srf-eventcalendar-options": "گزینه‌های تقویم وقایع",
+ "srf-prefs-eventcalendar-options-update-default": "Ùعال سازی [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates به‌روزرسانی‌های خودکار] تقویم وقایع در حین تازه‌کردن صÙحه",
+ "srf-prefs-eventcalendar-options-paneview-default": "Ùعال‌سازی نمایش تکه‌ای به‌صورت پیش‌Ùرض",
+ "srf-module-loading": "در حال بارگیری...",
+ "srf-paramdesc-layout": "چیدمان دردسترس",
+ "srf-paramdesc-height": "ارتÙاع",
+ "srf-paramdesc-width": "عرض",
+ "srf-paramdesc-charttype": "نوع چارت در دسترس",
+ "srf-navigation-previous": "قبلی",
+ "srf-ui-navigation-prev": "قبلی",
+ "srf-ui-navigation-next": "بعدی",
+ "srf-ui-common-label-source": "منبع",
+ "srf-ui-common-label-datasource": "منبع داده",
+ "srf-ui-common-label-request-object": "شیء درخواست",
+ "srf-ui-common-label-help-section": "بخش راهنما",
+ "srf-ui-tooltip-title-options": "گزینه‌ها",
+ "srf-ui-tooltip-title-scope": "حوزه",
+ "srf-ui-tooltip-title-legend": "شرح علائم",
+ "srf-ui-tooltip-title-filter": "پالایه",
+ "srf-ui-common-label-refresh": "تازه کردن",
+ "srf-ui-common-label-parameters": "پارامترها",
+ "srf-ui-common-label-query": "پرسمان",
+ "srf-ui-common-label-paneview": "نمای تکه‌ای",
+ "srf-ui-common-label-daterange": "بازه زمانی",
+ "srf-ui-widgets-label-parameter-limit": "پارامتر محدودیت",
+ "srf-error-option-mix": "گزینه ($1) در دسترس نیست",
+ "srf-warn-empy-chart": "چارت با گرا٠به علت کمبود داده خالی است",
+ "srf-paramdesc-color": "رنگی جهت علامت زدن مدخل‌های تقویم",
+ "srfc_previousmonth": "ماه گذشته",
+ "srfc_nextmonth": "ماه آینده",
+ "srfc_today": "امروز",
+ "srfc_gotomonth": "برو به ماه",
+ "srf_printername_calendar": "تقویم ماهانه",
+ "srf_paramdesc_calendarlang": "کد زبان برای نمایش تقویم",
+ "srf_printername_vcard": "خروجی vCard",
+ "srf_printername_icalendar": "خروجی iCalendar",
+ "srf_paramdesc_icalendartitle": "نام پرونده تقویم",
+ "srf_paramdesc_icalendardescription": "توضیح پرونده تقویم",
+ "srf_printername_bibtex": "خروجی BibTeX",
+ "srf_outline_novalue": "بدون مقدار",
+ "srf_printername_sum": "مجموع اعداد",
+ "srf_printername_average": "میانگین اعداد",
+ "srf_printername_max": "بیشترین عدد",
+ "srf_printername_min": "کمترین عدد",
+ "srf_paramdesc_limit": "حداکثر صÙحاتی Ú©Ù‡ پرسمان شوند",
+ "srf_printername_product": "حاصل‌ضرب اعداد",
+ "srf_printername_median": "میانهٔ اعداد",
+ "srf-paramdesc-default": "دادهٔ پیش‌Ùرضی Ú©Ù‡ در هنگام عدم وجود نتایج عددی نمایش داده می‌شود",
+ "srf_printername_earliest": "اولین زمان",
+ "srf_printername_latest": "آخرین زمان",
+ "srf_printername_timeline": "خط زمان",
+ "srf_printername_eventline": "خط رویداد",
+ "srf_paramdesc_timelinebands": "یاندهایی که در نتایج نمایش داده می‌شوند را مشخص می‌کند",
+ "srf_paramdesc_timelineposition": "نقطه تمرکز اولیه نوار زمان را تعیین می‌کند",
+ "srf_paramdesc_timelinestart": "نام مشخصه‌ای برای تعیین اولین نقطه زمان",
+ "srf_paramdesc_timelineend": "نام مشخصه‌ای برای تعیین دومین نقطه زمان",
+ "srf_paramdesc_timelinesize": "ارتÙاع نوار زمان",
+ "srf-timeline-allresults": "یاÙتههای بیشتر برای این پرسمان",
+ "srf-timeline-nojs": "برای نمایش نوار زمان تعاملی باید جاوا اسکریپت شما Ùعال باشد",
+ "srf_paramdesc_views": "نما‌هایی که نمایش داده شوند",
+ "srf_paramdesc_facets": "مجموعه خصوصیاتی Ú©Ù‡ باید برای هر صÙحه نمایش یابد",
+ "srf_paramdesc_lens": "نام الگویی Ú©Ù‡ با آن مشخصه‌های صÙحه نشان داده شوند",
+ "srf_printername_googlebar": "نمودار میله‌ای گوگل",
+ "srf_printername_googlepie": "نمودار دایره‌ای گوگل",
+ "srf-printername-jqplotchart": "نمودار jqPlot",
+ "srf-printername-jqplotseries": "سلسله jqPlot",
+ "srf_paramdesc_chartheight": "ارتÙاع (به پیکسل) نمودار یا گرا٠را تعیین کنید",
+ "srf_paramdesc_chartwidth": "پهنا (به پیکسل یا درصد) نمودار یا گرا٠را تعیین کنید",
+ "srf_paramdesc_charttitle": "عنوان نمودار",
+ "srf_paramdesc_barcolor": "رنگ‌های نمودار را تعیین کنید",
+ "srf_paramdesc_bardirection": "جهت نمودار را تعیین کنید",
+ "srf-paramdesc-direction": "جهت نمودار یا گرا٠را تعیین کنید",
+ "srf_paramdesc_barnumbersaxislabel": "عنوان محور اعداد",
+ "srf-paramdesc-labelaxislabel": "عنوان محور برچسب‌ها",
+ "srf-paramdesc-ticklabels": "Ùعال‌سازی نمایش برچسب‌های ضخیم",
+ "srf-paramdesc-minvalue": "حداقل مقداری که روی محور Y نشان داده شود",
+ "srf-ui-gridview-label-chart-tab": "نمودار",
+ "srf-ui-gridview-label-data-tab": "داده‌ها",
+ "srf-ui-gridview-label-info-tab": "اطلاعات",
+ "srf_printername_gallery": "نگارخانه",
+ "srf_paramdesc_perrow": "تعداد تصاویر در هر سطر",
+ "srf_paramdesc_widths": "پهنای تصاویر",
+ "srf_paramdesc_heights": "ارتÙاع تصاویر",
+ "srf_paramdesc_autocaptions": "اگر توضیح ارائه نشد از نام پرونده استÙاده Ú©Ù†",
+ "srf_paramdesc_fileextensions": "هنگم استÙاده از نام پرونده به‌عنوان توضیح، پسوند پرونده را نیز نمایش بده",
+ "srf-gallery-navigation-previous": "قبلی",
+ "srf-gallery-navigation-next": "بعدی",
+ "srf-gallery-overlay-count": "تصویر $1 از $2",
+ "srf_printername_array": "آرایه",
+ "srf_printername_hash": "هش",
+ "srf-printername-graph": "گراÙ",
+ "srf-paramdesc-graphname": "عنوان",
+ "srf-paramdesc-graphlabel": "برچسب گراÙ",
+ "srf-paramdesc-graphlink": "پیوند گراÙ",
+ "srf-paramdesc-graphcolor": "رنگ گراÙ",
+ "srf-ui-datatables-label-conditions": "شرایط:",
+ "srf-ui-datatables-label-parameters": "پارامترها",
+ "srf-ui-datatables-label-filters": "پالایش‌ها و جستجوی ستون",
+ "srf-ui-datatables-label-information": "اطلاعات",
+ "srf-ui-datatables-label-placeholder-column-search": "جستجو...",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "تنظیمات پالایش",
+ "srf-ui-datatables-label-sInfoThousands": "،",
+ "srf-ui-datatables-label-sLoadingRecords": "در حال بارگیری...",
+ "srf-ui-datatables-label-sProcessing": "درحال پردازش...",
+ "srf-ui-datatables-label-sSearch": "جستجو:",
+ "srf-ui-datatables-label-sZeroRecords": "هیچ پیشینه مشابهی یاÙت نشد",
+ "srf-ui-datatables-label-oPaginate-sFirst": "نخستین",
+ "srf-ui-datatables-label-oPaginate-sLast": "واپسین",
+ "srf-ui-datatables-label-oPaginate-sNext": "بعدی",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "قبلی",
+ "srf-printername-tree": "درخت",
+ "srf-paramdesc-filtered-list-named-args": "نام بحث‌های عبور داده‌ شده به الگو.",
+ "srf-paramdesc-filtered-list-introtemplate": "نام الگو برای نمایش قبل از نتایج پرس‌و‌جو، اگر وجود داشته باشد.",
+ "srf-paramdesc-filtered-list-outrotemplate": "نام الگو برای نمایش پس از نتایج پرس‌و‌جو، اگر وجود داشته باشد.",
+ "srf-filtered-selectorlabel-list": "Ùهرست",
+ "srf-filtered-selectorlabel-table": "جدول",
+ "srf-filtered-selectorlabel-calendar": "تقویم",
+ "srf-filtered-selectorlabel-map": "نقشه",
+ "srf-filtered-firstdayofweek": "Û±",
+ "srf-ui-eventcalendar-label-today": "امروز",
+ "srf-ui-eventcalendar-label-month": "ماه",
+ "srf-ui-eventcalendar-label-week": "Ù‡Ùته",
+ "srf-ui-eventcalendar-label-day": "روز",
+ "srf-ui-eventcalendar-label-allday": "همه روز",
+ "srf-paramdesc-unit": "واحد",
+ "srf-ui-mediaplayer-label-previous": "قبلی",
+ "srf-ui-mediaplayer-label-play": "پخش",
+ "srf-ui-mediaplayer-label-pause": "Ù…Ú©Ø«",
+ "srf-ui-mediaplayer-label-next": "بعدی",
+ "srf-ui-mediaplayer-label-stop": "توقÙ",
+ "srf-ui-mediaplayer-label-mute": "بی‌صدا",
+ "srf-ui-mediaplayer-label-unmute": "صدا دار",
+ "srf-ui-mediaplayer-label-volume-max": "حداکثر صدا",
+ "srf-ui-mediaplayer-label-shuffle": "تصادÙÛŒ",
+ "srf-ui-mediaplayer-label-shuffle-off": "غیرÙعال کردن تصادÙÛŒ",
+ "srf-ui-mediaplayer-label-repeat": "تکرار",
+ "srf-ui-mediaplayer-label-repeat-off": "خاموش کردن تکرار",
+ "srf-ui-mediaplayer-label-full-screen": "تمام صÙحه"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/fi.json b/www/wiki/extensions/SemanticResultFormats/i18n/fi.json
new file mode 100644
index 00000000..beb5b648
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/fi.json
@@ -0,0 +1,177 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nedergard",
+ "Nike",
+ "Silvonen",
+ "Str4nd",
+ "Pyscowicz",
+ "Nemo bis",
+ "Pahkiqaz",
+ "01miki10",
+ "Valtlait"
+ ]
+ },
+ "srf-desc": "Muita tulosten muotoja Semantic MediaWikin kyselyille",
+ "prefs-srf": "Extension:Semanttisten tulosten muodot",
+ "prefs-srf-eventcalendar-options": "Tapahtumakalenterin asetukset",
+ "srf-module-loading": "Ladataan...",
+ "srf-paramdesc-layout": "Asetteluvaihtoehdot",
+ "srf-paramdesc-height": "Korkeus",
+ "srf-paramdesc-width": "Leveys",
+ "srf-module-nomatch": "Ei hakutuloksia",
+ "srf-paramdesc-charttype": "Mahdolliset kaaviotyypit",
+ "srf-navigation-previous": "Edellinen",
+ "srf-ui-navigation-prev": "Edellinen",
+ "srf-ui-navigation-next": "Seuraava",
+ "srf-ui-common-label-source": "Lähde",
+ "srf-ui-common-label-datasource": "Tietolähde",
+ "srf-ui-common-label-help-section": "ohje-osio",
+ "srf-ui-tooltip-title-options": "Asetukset",
+ "srf-ui-tooltip-title-legend": "Selite",
+ "srf-ui-tooltip-title-filter": "Suodatin",
+ "srf-ui-common-label-refresh": "Päivitä",
+ "srf-ui-common-label-parameters": "Parametrit",
+ "srf-ui-common-label-query": "Kysely",
+ "srf-error-option-mix": "Valinta ($1) ei ole käytettävissä",
+ "srf-error-missing-layout": "Asettelu puuttuu",
+ "srf-warn-empy-chart": "Kaavio tai graafi on tyhjä, koska tietoja ei ole",
+ "srfc_previousmonth": "Edellinen kuukausi",
+ "srfc_nextmonth": "Seuraava kuukausi",
+ "srfc_today": "Tänään",
+ "srfc_gotomonth": "Siirry kuukauteen",
+ "srf_printername_calendar": "Kuukausittainen kalenteri",
+ "srf_paramdesc_calendarlang": "Kalenterin kielen tunnus",
+ "srf_printername_vcard": "vCard-vienti",
+ "srf_printername_icalendar": "iCalendar-vienti",
+ "srf_paramdesc_icalendartitle": "Kalenteritiedoston otsikko",
+ "srf_paramdesc_icalendardescription": "Kalenteritiedoston kuvaus",
+ "srf_printername_bibtex": "BibTeX-vienti",
+ "srf_outline_novalue": "Ei arvoa",
+ "srf_printername_outline": "Jäsennys",
+ "srf_printername_sum": "Lukujen summa",
+ "srf_printername_average": "Lukujen keskiarvo",
+ "srf_printername_max": "Korkein luku",
+ "srf_printername_min": "Pienin luku",
+ "srf_paramdesc_limit": "Kyselyn sivujen enimmäismäärä",
+ "srf_printername_median": "Lukujen mediaani",
+ "srf-paramdesc-default": "Oletusarvo, joka näytetään, kun numeerista tulosta ei saada",
+ "srf_printername_earliest": "Varhaisin aika",
+ "srf_printername_latest": "Viimeisin aika",
+ "srf_printername_timeline": "Aikajana",
+ "srf_printername_eventline": "Tapahtumajana",
+ "srf_paramdesc_timelineposition": "Määrittää, mikä on aikajanan ensimmäinen näytettävä kohta.",
+ "srf_paramdesc_timelinestart": "Ominaisuuden nimi, joka määrittää ensimmäisen ajankohdan",
+ "srf_paramdesc_timelineend": "Ominaisuuden nimi, joka määrittää toisen ajankohdan",
+ "srf_paramdesc_timelinesize": "Aikajanan korkeus",
+ "srf-timeline-allresults": "Lisää tuloksia tälle kyselylle.",
+ "srf-timeline-nojs": "Interaktiivinen aikajana edellyttää JavaScriptin käyttöä.",
+ "srf_paramdesc_views": "Näytettävät näkymät",
+ "srf_paramdesc_facets": "Ominaisuusjoukko, joka näytetään jokaisella sivulla",
+ "srf_printername_googlebar": "Googlen pylväskuvaaja",
+ "srf_printername_googlepie": "Googlen piirakkakuvaaja",
+ "srf-printername-jqplotchart": "jqPlot-kaavio",
+ "srf-printername-jqplotseries": "jqPlot-sarja",
+ "srf_paramdesc_chartheight": "Määritä kaavion tai graafin korkeus (pikseleinä)",
+ "srf_paramdesc_chartwidth": "Määritä kaavion tai graafin leveys (pikseleinä)",
+ "srf_paramdesc_charttitle": "Kaavion otsikko",
+ "srf_paramdesc_barcolor": "Määritä kaavion värit",
+ "srf_paramdesc_bardirection": "Määritä kaavion suunta",
+ "srf-paramdesc-direction": "Määritä kaavion tai graafin suunta",
+ "srf-paramdesc-valueformat": "Määritä arvojen muotoilusäännöt",
+ "srf-paramdesc-stackseries": "Näytä kaavio pinottuna sarjana",
+ "srf-paramdesc-seriesgroup": "Valitse sarjan ryhmittely",
+ "srf-paramdesc-gridview": "Näytän kaavio ja datajoukot samanaikaisesti. Sallitut arvot: \"none\" ja \"tabs\". Oletusarvo: \"none\".",
+ "srf-ui-gridview-label-item": "Kohteen tiedot",
+ "srf-ui-gridview-label-value": "Data-arvo",
+ "srf-ui-gridview-label-series": "Datasarja",
+ "srf-ui-gridview-label-chart-tab": "Kaavio",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Tiedot",
+ "srf_printername_gallery": "Galleria",
+ "srf_paramdesc_perrow": "Kuvien määrä rivillä",
+ "srf_paramdesc_widths": "Kuvien leveys",
+ "srf_paramdesc_heights": "Kuvien korkeus",
+ "srf_paramdesc_autocaptions": "Käytä tiedoston nimeä otsikkoa, jos otsikkoa ei ole määritetty",
+ "srf_paramdesc_fileextensions": "Jos tiedostonimi on otsikkona, näytä myös tiedostopääte",
+ "srf-gallery-navigation-previous": "Edellinen",
+ "srf-gallery-navigation-next": "Seuraava",
+ "srf-gallery-overlay-count": "Kuva $1 / $2",
+ "srf-gallery-image-url-error": "Kuvaa ei löytynyt.",
+ "srf_printername_tagcloud": "Tunnistepilvi",
+ "srf_paramdesc_increase": "Kuinka tunnisteiden kokoa suurennetaan",
+ "srf_paramdesc_tagorder": "Tunnisteiden järjestys",
+ "srf_paramdesc_minsize": "Pienimmän tunnisteen koko prosentteina",
+ "srf_paramdesc_maxsize": "Suurimman tunnisteen koko prosentteina",
+ "srf_paramdesc_maxtags": "Tunnisteiden enimmäismäärä pilvessä",
+ "srf_paramdesc_propsep": "Erotin pyydettyjen ominaisuuksien välissä",
+ "srf_paramdesc_manysep": "Erotin moniarvoisen ominaisuuden arvojen välillä",
+ "srf_paramdesc_headersep": "Erotin ominaisuuden nimen ja arvon välissä, jos â€headers†on â€show†tai â€plainâ€",
+ "srf-printername-graph": "Graafi",
+ "srf-paramdesc-graph-relation": "Ovatko kohteet tai nimiominaisuudet ylätasolla vai alatasolla?",
+ "srf-paramdesc-graphname": "Asettaa taulukon otsikon",
+ "srf-paramdesc-graphsize": "Asettaa graafin koon (pikseleinä)",
+ "srf-paramdesc-rankdir": "Asettaa nuolien suunnan",
+ "srf-paramdesc-graphlink": "Graafin linkki",
+ "srf-paramdesc-graphcolor": "Asettaa graafin värin",
+ "srf-printername-datatables": "Datataulukot",
+ "srf-ui-datatables-label-parameters": "Parametrit",
+ "srf-ui-datatables-label-update-success": "Taulukon päivitys onnistui",
+ "srf-ui-datatables-label-placeholder-column-search": "Hae...",
+ "srf-ui-datatables-label-sInfo": "Näytetään _START_ - _END_ _TOTAL_ merkinnästä",
+ "srf-ui-datatables-label-sInfoEmpty": "Näytetään 0-0 0 merkinnästä",
+ "srf-ui-datatables-label-sLoadingRecords": "Ladataan...",
+ "srf-ui-datatables-label-sProcessing": "Käsitellään...",
+ "srf-ui-datatables-label-sSearch": "Haku:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Ensimmäinen",
+ "srf-ui-datatables-label-oPaginate-sLast": "Viimeinen",
+ "srf-ui-datatables-label-oPaginate-sNext": "Seuraava",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Edellinen",
+ "srf-printername-tree": "Puu",
+ "srf-printername-ultree": "Puu (luettelo)",
+ "srf-printername-oltree": "Puu (numeroitu)",
+ "srf-tree-noparentprop": "Ylätason ominaisuus puuttuu. Puuta ei voi rakentaa, jos ylätason ominaisuutta ei ole määritetty.",
+ "srf-tree-rootinvalid": "$1 ei ole kelvollinen sivun nimi.",
+ "srf-printername-slideshow": "Diaesitys",
+ "srf-paramdesc-navigation-controls": "Näytä navigointiohjaimet tai ei",
+ "srf-printername-filtered": "Suodatettu",
+ "srf-paramdesc-filtered-list-type": "Luettelotyypit. Sallitut arvot: \"list\", \"ul\", \"ol\". Oletusarvo: \"list\".",
+ "srf-paramdesc-filtered-list-template": "Malline, jolla luettelokohdat muotoillaan.",
+ "srf-paramdesc-filtered-list-introtemplate": "Ennen kyselytuloksia näytettävä mallineen nimi, jos sellaista on.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Kyselytulosten jälkeen näytettävä mallineen nimi, jos sellaista on.",
+ "srf-filtered-selectorlabel-list": "Luettelo",
+ "srf-filtered-selectorlabel-calendar": "Kalenteri",
+ "srf-filtered-selectorlabel-map": "Kartta",
+ "srf-filtered-value-filter-and": "JA",
+ "srf-filtered-value-filter-or": "TAI",
+ "srf-printername-d3chart": "D3-kaavio",
+ "srf-paramdesc-group": "Sarjan ryhmittelyavain",
+ "srf-paramdesc-listtype": "Määritä luttelotyyppi",
+ "srf-paramdesc-pageitems": "Kohteiden määrä sivulla",
+ "srf-printername-eventcalendar": "Tapahtumakalenteri",
+ "srf-paramdesc-calendarfirstday": "Viikon ensimmäinen päivä",
+ "srf-paramdesc-calendardefaultview": "Aloitusnäkymä, kun kalenteria ladataan",
+ "srf-paramdesc-calendarstart": "Kalenterin alkupäivämäärä",
+ "srf-ui-eventcalendar-label-today": "Tänään",
+ "srf-ui-eventcalendar-label-month": "Kuukausi",
+ "srf-ui-eventcalendar-label-week": "Viikko",
+ "srf-ui-eventcalendar-label-day": "Päivä",
+ "srf-ui-eventcalendar-label-allday": "Koko päivä",
+ "srf-ui-eventcalendar-click-popup": "Haluatko luoda tapahtuman?",
+ "srf-printername-dygraphs": "Dygraphs-kaavio",
+ "srf-paramdesc-datasource": "Määritä datan tietolähteen sijainti. Sallitut arvot: â€fileâ€, â€raw†ja â€urlâ€. Oletusarvo: â€fileâ€",
+ "srf-paramdesc-yaxislabel": "Y-akselin selite",
+ "srf-paramdesc-xaxislabel": "X-akselin selite",
+ "srf-paramdesc-unit": "Yksikkö",
+ "srf-printername-incoming": "Saapuvat ominaisuudet",
+ "srf-paramdesc-min": "Vähimmäis- tai kynnysarvo",
+ "srf-paramdesc-excludeproperty": "Poista ominaisuus tulosten joukosta",
+ "srf-ui-mediaplayer-label-previous": "Edellinen",
+ "srf-ui-mediaplayer-label-next": "Seuraava",
+ "srf-ui-mediaplayer-label-shuffle": "Sekoitus",
+ "srf-ui-mediaplayer-label-shuffle-off": "Sekoitus pois käytöstä",
+ "srf-ui-mediaplayer-label-repeat": "Toisto",
+ "srf-ui-mediaplayer-label-repeat-off": "Toisto pois käytöstä",
+ "srf-ui-mediaplayer-label-full-screen": "Koko näyttö",
+ "srf-ui-mediaplayer-label-restore-screen": "Palauta näyttö"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/fr.json b/www/wiki/extensions/SemanticResultFormats/i18n/fr.json
new file mode 100644
index 00000000..583a71b4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/fr.json
@@ -0,0 +1,366 @@
+{
+ "@metadata": {
+ "authors": [
+ "Brunoperel",
+ "Crochet.david",
+ "DavidL",
+ "Erkethan",
+ "Gomoko",
+ "Grondin",
+ "Hashar",
+ "IAlex",
+ "Iluvalar",
+ "McDutchie",
+ "Nicolas NALLET",
+ "Peter17",
+ "PieRRoMaN",
+ "Tititou36",
+ "Urhixidur",
+ "Verdy p",
+ "SnowedEarth",
+ "Wladek92",
+ "Macofe",
+ "Yasten",
+ "Dgstranz",
+ "Nemo bis",
+ "DePlusJean"
+ ]
+ },
+ "srf-desc": "Formats additionnels d'affichage de résultat pour les requêtes de Semantic MediaWiki",
+ "prefs-srf": "Formats de résultat sémantique",
+ "srf-prefs-intro-text": "Vous avez installé l’extension Formats de résultats sémantiques. Veuillez consulter la page [https://www.semantic-mediawiki.org/wiki/Help:Result_formats formats de résultat] pour une aide supplémentaire en fonction des préférences utilisateur.",
+ "prefs-srf-eventcalendar-options": "Options du calendrier d’événements",
+ "srf-prefs-eventcalendar-options-update-default": "Activer les [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates mises à jour automatiques] des événements du calendrier lors d’un rafraîchissement de page",
+ "srf-prefs-eventcalendar-options-paneview-default": "Activer l’affichage du volet par défaut",
+ "prefs-srf-datatables-options": "Options des plages de données",
+ "srf-prefs-datatables-options-update-default": "Activer les [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates mises à jour automatiques] du contenu des tables lors du rafraîchissement des pages",
+ "srf-prefs-datatables-options-cache-default": "Activer le [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage stockage local] pour améliorer les temps de réponse",
+ "srf-module-loading": "Chargement...",
+ "srf-paramdesc-layout": "Mise en page disponible",
+ "srf-paramdesc-height": "Hauteur (en pixels)",
+ "srf-paramdesc-width": "Largeur",
+ "srf-paramdesc-class": "Spécifiez une classe CSS supplémentaire",
+ "srf-module-nomatch": "Aucun résultat trouvé",
+ "srf-paramdesc-charttype": "Type de graphique disponible",
+ "srf-navigation-previous": "Précédent",
+ "srf-ui-navigation-prev": "Précédent",
+ "srf-ui-navigation-next": "Suivant",
+ "srf-ui-common-label-source": "Source",
+ "srf-ui-common-label-datasource": "Source de données",
+ "srf-ui-common-label-ajax-error": "Le serveur a signalé un échec de communication pour ce $1. Veuillez rafraîchir la page ou la consulter avec ce $2.",
+ "srf-ui-common-label-request-object": "objet requête",
+ "srf-ui-common-label-help-section": "section d'aide",
+ "srf-ui-tooltip-title-options": "Options",
+ "srf-ui-tooltip-title-scope": "Portée",
+ "srf-ui-tooltip-title-legend": "Légende",
+ "srf-ui-tooltip-title-filter": "Filtrer",
+ "srf-ui-common-label-refresh": "Rafraîchir",
+ "srf-ui-common-label-parameters": "Paramètres",
+ "srf-ui-common-label-query": "Requête",
+ "srf-ui-common-label-paneview": "Affichage du volet",
+ "srf-ui-common-label-daterange": "Plage de dates",
+ "srf-ui-widgets-label-parameter-limit": "Limiter le paramètre",
+ "srf-error-option-mix": "L'option ($1) n'est pas disponible",
+ "srf-error-option-link-all": "L'option ($1) nécessite le paramètre « link » pour être mise à « all »",
+ "srf-error-missing-layout": "Le diagramme ou le graphique ne peuvent être affichés car la mise en page est absente.",
+ "srf-error-jqplot-bubble-data-length": "Le diagramme ou le graphique ne peuvent pas être affichés car il manque des données.",
+ "srf-error-jqplot-stackseries-data-length": "Le diagramme ou le graphique ne peuvent être affichés car chaque barre ou ligne n’a pas le même nombre d’éléments.",
+ "srf-warn-empy-chart": "L’histogramme ou le graphe sont vides car il n’y a pas de données",
+ "srf-paramdesc-color": "La couleur pour marquer les entrées de calendrier",
+ "srfc_previousmonth": "Mois précédent",
+ "srfc_nextmonth": "Mois suivant",
+ "srfc_today": "Aujourd’hui",
+ "srfc_gotomonth": "Aller au mois",
+ "srf_printername_calendar": "Calendrier mensuel",
+ "srf_paramdesc_calendarlang": "Le code de la langue dans laquelle afficher le calendrier",
+ "srf_paramdesc_calendarcolors": "La couleur à afficher pour chaque propriété date (exemple: \"Date de démarrage => green,Date de fin => #09c\")",
+ "srf-paramdesc-calendar-startmonth": "Le mois, avec lequel l'affichage du calendrier est initialisé (par défaut, le mois courant)",
+ "srf-paramdesc-calendar-startyear": "L'année avec laquelle l'affichage de calendrier est initialisé (par défaut, l'année en cours)",
+ "srf_vcard_link": "vCarte",
+ "srf_printername_vcard": "export en vCard",
+ "srf_icalendar_link": "iCalendrier",
+ "srf_printername_icalendar": "export en iCalendar",
+ "srf_paramdesc_icalendartitle": "Le titre du fichier calendrier",
+ "srf_paramdesc_icalendardescription": "La description du fichier calendrier",
+ "srf_printername_bibtex": "export en BibTeX",
+ "srf_outline_novalue": "Aucune valeur",
+ "srf_printername_outline": "esquisse",
+ "srf_paramdesc_outlineproperties": "La liste des propriétés à afficher comme en-têtes, séparées par des virgules",
+ "srf_printername_sum": "Somme de nombres",
+ "srf_printername_average": "Moyenne des nombres",
+ "srf_printername_max": "Nombre maximal",
+ "srf_printername_min": "Nombre minimal",
+ "srf_paramdesc_limit": "Le nombre maximum de pages à rechercher",
+ "srf_printername_product": "Produit de nombres",
+ "srf_printername_median": "Moyenne des nombres",
+ "srf-paramdesc-default": "Valeur par défaut qui s'affichera lorsqu'il n'y a pas de résultats numériques",
+ "srf_printername_earliest": "Première heure",
+ "srf_printername_latest": "Dernière heure",
+ "srf_printername_timeline": "Chronologie",
+ "srf_printername_eventline": "Chronologie des événements",
+ "srf_paramdesc_timelinebands": "Définit quels groupes sont affichés dans les résultats.",
+ "srf_paramdesc_timelineposition": "Définit la zone de la frise pointe initialement.",
+ "srf_paramdesc_timelinestart": "Un nom de propriété utilisé pour définir un point de démarrage",
+ "srf_paramdesc_timelineend": "Un nom de propriété utilisé pour définir un point de seconde date",
+ "srf_paramdesc_timelinesize": "La hauteur de la frise",
+ "srf-timeline-allresults": "Autres résultats pour cette requête.",
+ "srf-timeline-nojs": "JavaScript doit être activé pour voir la chronologie interactive.",
+ "srf_paramdesc_views": "Les vues à afficher",
+ "srf_paramdesc_facets": "L’ensemble des propriétés à afficher pour chaque page",
+ "srf_paramdesc_lens": "Le nom du modèle utilisé pour afficher les propriétés de la page",
+ "srf_printername_googlebar": "Diagramme à barres de Google",
+ "srf_printername_googlepie": "Diagramme en camembert de Google",
+ "srf-printername-jqplotchart": "graphique jqPlot",
+ "srf-printername-jqplotseries": "série jqPlot",
+ "srf_paramdesc_chartheight": "Spécifiez la hauteur (en pixels) d'un diagramme ou d'un graphe",
+ "srf_paramdesc_chartwidth": "Indiquez la largeur (en pixels ou en pourcentage) d'un diagramme ou d'un graphique",
+ "srf_paramdesc_charttitle": "Le titre du graphique",
+ "srf_paramdesc_barcolor": "Spécifier les couleurs du diagramme",
+ "srf_paramdesc_bardirection": "Spécifier la direction d'un diagramme",
+ "srf-paramdesc-direction": "Indiquez l'orientation d'un diagramme ou d'un graphique",
+ "srf_paramdesc_barnumbersaxislabel": "Étiquette pour l’axe numérique",
+ "srf-paramdesc-labelaxislabel": "La légende de l'axe des libellés",
+ "srf-paramdesc-ticklabels": "Activer l'affichage des libellés de graduation",
+ "srf-paramdesc-minvalue": "La valeur minimale à afficher sur l'axe des ordonnées",
+ "srf-paramdesc-pointlabels": "Affichage des points de données dans le graphique",
+ "srf-paramdesc-chartlegend": "Position de la légende du graphique",
+ "srf-paramdesc-datalabels": "Etiquettes du diagramme/graphique",
+ "srf-paramdesc-charttext": "Texte descriptif du graphique",
+ "srf-paramdesc-chartclass": "Classe CSS additionnelle",
+ "srf-paramdesc-renderer": "Sélectionnez un moteur de rendu graphique/graphe",
+ "srf-paramdesc-filling": "Option de remplissage individuel",
+ "srf-paramdesc-theme": "Sélectionnez un thème pour la grille",
+ "srf-paramdesc-chartcolor": "Attribuer des couleurs individuelles au graphique",
+ "srf-paramdesc-colorscheme": "Sélectionnez un jeu de couleurs",
+ "srf-paramdesc-valueformat": "Spécifiez la règle de mise en forme des valeurs",
+ "srf-paramdesc-highlighter": "Afficher un surligneur de point de données",
+ "srf-paramdesc-smoothlines": "Appliquer un algorithme de lissage sur les graphiques en lignes",
+ "srf-paramdesc-stackseries": "Afficher le graphique sous forme de barres empilées",
+ "srf-paramdesc-seriesgroup": "Sélectionner le regroupement par séries",
+ "srf-paramdesc-serieslabel": "Déterminer le libellé des séries",
+ "srf-paramdesc-grouplabel": "Déterminer le libellé de groupe",
+ "srf-paramdesc-chartcursor": "Option d'affichage du curseur de diagramme",
+ "srf-paramdesc-trendline": "Active l'affichage simultané d'un diagramme et de sa tendance",
+ "srf-paramdesc-gridview": "Afficher le diagramme et les ensembles de données en même temps. Valeurs autorisées: « none » et « tabs ». Par défaut: « none »",
+ "srf-paramdesc-paneview": "Spécifier la position du panneau contenant un petit graphique en lignes. Valeurs permises : « bottom » (bas), « top » (haut) et « none » (aucun). Par défaut : « bottom »",
+ "srf-paramdesc-infotext": "Afficher les informations supplémentaires dans un onglet d'information correspondant",
+ "srf-paramdesc-clicktarget": "Définir une page ou une chaîne de requête comme cible lors d’un clic sur une date du calendrier.",
+ "srf-ui-gridview-label-item": "Élément de donnée",
+ "srf-ui-gridview-label-value": "Valeur de donnée",
+ "srf-ui-gridview-label-series": "Série de données",
+ "srf-ui-gridview-label-chart-tab": "Graphique",
+ "srf-ui-gridview-label-data-tab": "Données",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galerie",
+ "srf_paramdesc_perrow": "Le nombre d'images par ligne",
+ "srf_paramdesc_widths": "La largeur des images",
+ "srf_paramdesc_heights": "La hauteur des images",
+ "srf_paramdesc_autocaptions": "Utiliser le nom de fichier comme légende lorsqu'aucune n'est fournie",
+ "srf_paramdesc_fileextensions": "Quand le nom de fichier est utilisé comme titre, afficher aussi l'extension du fichier",
+ "srf_paramdesc_captionproperty": "Le nom de la propriété sémantique présent sur les pages demandées doit être utilisé comme titre",
+ "srf_paramdesc_imageproperty": "Le nom de la propriété sémantique sur les pages demandées qui pointent vers des images à utiliser. Quand il est positionné, les pages demandées elles-mêmes ne seront pas affichées comme des images",
+ "srf-paramdesc-redirects": "Le nom d'une propriété sémantique présente sur les pages demandées qui contient la cible de la redirection",
+ "srf-paramdesc-navigation": "Contrôle de navigation de la mise en page",
+ "srf-paramdesc-overlay": "Activer la superposition d'image",
+ "srf-gallery-navigation-previous": "Précédent",
+ "srf-gallery-navigation-next": "Suivant",
+ "srf-gallery-overlay-count": "Image $1 sur $2",
+ "srf-gallery-image-url-error": "L'image n'a pas été trouvée",
+ "srf_printername_tagcloud": "Nuage de tags",
+ "srf_paramdesc_includesubject": "Les noms des sujets eux-mêmes devraient être inclus",
+ "srf_paramdesc_increase": "Comment augmenter la taille des tags",
+ "srf_paramdesc_tagorder": "L'ordre des tags",
+ "srf_paramdesc_mincount": "Le nombre minimal de fois qu'une valeur doit être utilisée pour être listée",
+ "srf_paramdesc_minsize": "La taille du plus petit tag en pourcent",
+ "srf_paramdesc_maxsize": "La taille des plus grosses balises en pourcentage",
+ "srf_paramdesc_maxtags": "Le nombre maximal de tags dans le nuage",
+ "srf-paramdesc-excludetags": "Exclure les noms de balise (délimiteur : ';')",
+ "srf_printername_valuerank": "Valeur du rang",
+ "srf_printername_array": "Tableau",
+ "srf_paramdesc_pagetitle": "S'il faut afficher les titres de page comme entrées de résultat ou les omettre",
+ "srf_paramdesc_hidegaps": "S'il faut afficher les valeurs de propriété ou d'enregistrement non disponibles séparées par des séparateurs ou les omettre",
+ "srf_paramdesc_arrayname": "Si fourni et qu'un ArrayExtension est disponible, cela créera un tableau avec le nom spécifié (pas de sortie visible, dans ce cas)",
+ "srf_paramdesc_propsep": "Séparateur entre les propriétés demandées",
+ "srf_paramdesc_manysep": "Séparateur de valeur pour les propriétés à valeurs multiples",
+ "srf_paramdesc_recordsep": "Séparateur de valeur pour les propriétés d'enregistrement",
+ "srf_paramdesc_headersep": "Séparateur entre le nom de la propriété et la valeur si \"<code>headers</code>\" est positionné à \"<code>show</code>\" ou \"<code>plain</code>\"",
+ "srf_printername_hash": "Hachage",
+ "srf_paramdesc_hashname": "S'il est fourni et que l'extension HashTables est disponible, ceci créera un hachage avec le nom spécifié (pas de sortie visible dans ce cas)",
+ "srf-printername-graph": "Graphe",
+ "srf-paramdesc-graph-relation": "Indique si les sujets ou les propriétés de nom sont des parents ou des enfants",
+ "srf-paramdesc-graph-nameprop": "Définit la propriété qui sera utilisée comme sujet au lieu de l’objet réel, c'est à dire le nom de la page",
+ "srf-paramdesc-graph-nodeshape": "Fixe la forme de chaque nœud sur le graphique",
+ "srf-paramdesc-graphname": "Définit le titre du graphique",
+ "srf-paramdesc-graphsize": "Fixe la taille du graphique en pixels",
+ "srf-paramdesc-graphlegend": "Indique si la légende d’un graphique devrait être affichée",
+ "srf-paramdesc-graphlabel": "Définit le titre du graphique",
+ "srf-paramdesc-rankdir": "Définit la direction des flèches",
+ "srf-paramdesc-graphlink": "Indique si les nœuds doivent être liés à leur page wiki",
+ "srf-paramdesc-graphcolor": "Définit la couleur du graphe",
+ "srf-paramdesc-graph-wwl": "Définit la limite du retour automatique (en nombre de caractères)",
+ "srf-paramdesc-clustercolor": "Définit les couleurs des boîtes de groupe",
+ "srf-paramdesc-highlight": "Définit le noeud à mettre en surbrillance",
+ "srf-paramdesc-highlightcolor": "Définit la couleur de police pour le nœud en surbrillance",
+ "srf-paramdesc-redlinkcolor": "Définit la couleur de police pour les liens rouges",
+ "srf-paramdesc-processcategory": "Définit la catégorie du wiki contenant les étapes du processus",
+ "srf-paramdesc-showroles": "Affiche les rôles correspondants dans le graphique",
+ "srf-paramdesc-showstatus": "Indique si l’état d’une étape du processus devrait être affichée",
+ "srf-paramdesc-showresources": "Affiche les ressources correspondantes dans le graphique",
+ "srf-paramdesc-showdiscussion": "Indique si une discussion doit être affichée",
+ "srf-paramdesc-showredlinks": "Indique si les liens rouges doivent être vérifiés et surlignés",
+ "srf-paramdesc-showcompound": "Indique s’il faut surligner les nœuds composés, c.-à-d. les sous-processus",
+ "srf-paramdesc-debug": "Indique si le code du graphique du processus doit être entre des balises pre",
+ "srf-paramdesc-graphvalidation": "Affiche les étapes du processus en rouge quand elles n’ont pas de rôle affecté",
+ "srf-printername-datatables": "Tables de données",
+ "srf-ui-datatables-label-conditions": "Conditions",
+ "srf-ui-datatables-label-parameters": "Paramètres",
+ "srf-ui-datatables-label-filters": "Filtres de colonne et de recherche",
+ "srf-ui-datatables-label-information": "Information",
+ "srf-ui-datatables-panel-disclaimer": "Les paramètres et les conditions peuvent être modifiés, mais toute modification est temporaire et sera abandonné après un rafraîchissement de la page.",
+ "srf-ui-datatables-label-update-success": "La mise à jour du tableau a réussi",
+ "srf-ui-datatables-label-update-error": "La mise à jour du tableau a échoué.",
+ "srf-ui-datatables-label-placeholder-column-search": "Recherche en cours…",
+ "srf-ui-datatables-label-content-cache": "Le contenu a été récupéré du cache local.",
+ "srf-ui-datatables-label-content-server": "Le contenu a été récupéré du serveur.",
+ "srf-ui-datatables-label-multiselect-column-header": "Colonnes disponibles",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Paramètres de filtre",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Les colonnes sont visibles",
+ "srf-ui-datatables-label-sEmptyTable": "Aucune donnée disponible dans la table",
+ "srf-ui-datatables-label-sInfo": "Affichage de _START_ à _END_ sur _TOTAL_ entrées",
+ "srf-ui-datatables-label-sInfoEmpty": "Affichage de 0 à 0 sur 0 entrées",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtré par _MAX_ entrées au total)",
+ "srf-ui-datatables-label-sInfoThousands": "&nbsp;",
+ "srf-ui-datatables-label-sLengthMenu": "Afficher les entrées _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "Chargement en cours…",
+ "srf-ui-datatables-label-sProcessing": "Traitement en cours…",
+ "srf-ui-datatables-label-sSearch": "Rechercher :",
+ "srf-ui-datatables-label-sZeroRecords": "Aucun enregistrement correspondant trouvé",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Premier",
+ "srf-ui-datatables-label-oPaginate-sLast": "Dernier",
+ "srf-ui-datatables-label-oPaginate-sNext": "Suivant",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Précédent",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activer pour trier la colonne en ordre croissant",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": activer pour trier la colonne en ordre décroissant",
+ "srf-printername-tree": "Arbre",
+ "srf-printername-ultree": "Arbre Ul",
+ "srf-printername-oltree": "Arbre Ol",
+ "srf-tree-noparentprop": "Aucune propriété parente fournie. L'arbre ne peut pas être construit sans une propriété parente spécifiée.",
+ "srf-tree-rootinvalid": "$1 n’est pas un titre de page valide.",
+ "srf-tree-circledetected": "Relations circulaires détectées en essayant d'insérer $1 dans l'arbre.",
+ "srf-paramdesc-tree-parent": "La propriété contenant la page parent",
+ "srf-paramdesc-tree-root": "La page racine de l’arbre",
+ "srf-paramdesc-tree-startlevel": "Le niveau de démarrage de l’arbre, par ex. pour l’intégrer dans un autre arbre",
+ "srf-printername-slideshow": "Diaporama",
+ "srf-paramdesc-delay": "Le délai entre les diapositives en secondes",
+ "srf-paramdesc-navigation-controls": "Afficher les contrôles de navigation ou non",
+ "srf-paramdesc-effect": "L'effet à utiliser pour passer d'une diapositive à l'autre",
+ "srf-printername-filtered": "Filtré",
+ "srf-paramdesc-filtered-views": "Les vues qui devraient être disponibles dans l'affichage des résultats.",
+ "srf-paramdesc-filtered-filter-position": "La position des filtres en lien avec ces vues. Valeurs permises: « top », « bottom ». Par défaut: « top ».",
+ "srf-paramdesc-filtered-list-type": "Le type de la liste. Valeurs permises: « list », « ul », « ol ». Par défaut: « list ».",
+ "srf-paramdesc-filtered-list-template": "Le modèle qui doit être utilisé pour mettre en forme les entrées de la liste.",
+ "srf-paramdesc-filtered-list-named-args": "Nommer les arguments passés au modèle.",
+ "srf-paramdesc-filtered-list-introtemplate": "Le nom du modèle à afficher avant les résultats de la requête, s'il y en a.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Le nom d'un modèle à afficher après les résultats de la requête, s'il y en a.",
+ "srf-paramdesc-filtered-calendar-start": "L'imprimé contenant la date de début d'un événement",
+ "srf-paramdesc-filtered-calendar-end": "L'imprimé contenant la date de fin d'un événement",
+ "srf-paramdesc-filtered-calendar-title": "L'imprimé contenant le titre d'un événement. Ne peux pas être utilisé en même temps qu'un modèle de titre.",
+ "srf-paramdesc-filtered-calendar-title-template": "Un modèle utilisé pour mettre en forme le titre de l'événement dans le calendrier",
+ "srf-paramdesc-filtered-map-position": "L'affichage contenant la position géographique.",
+ "srf-paramdesc-filtered-map-icon": "L’impression qui décide de l’icône de carte à utiliser.",
+ "srf-paramdesc-filtered-map-icons": "Une correspondance valeurs-icônes à utiliser pour ces valeurs sur la carte.",
+ "srf-paramdesc-filtered-map-height": "La hauteur de la carte.",
+ "srf-paramdesc-filtered-map-zoom": "Le niveau de zoom avec lequel la carte sera chargée. Il peut être modifié l’utilisateur.<br>Voir : <i>zoom minimal d’affichage de la carte</i> et <i>zoom maximal d’affichage de la carte</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "Le niveau de zoom minimal sélectionnable de la carte",
+ "srf-paramdesc-filtered-map-max-zoom": "Le niveau de zoom maximal sélectionnable de la carte",
+ "srf-paramdesc-filtered-map-marker-cluster": "Passe le marqueur d’agrégation à oui ou non.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Niveau de zoom maximal auquel les marqueurs de la carte sont encore agrégés. Au-dessus de ce niveau, les marqueurs seront toujours distincts.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "Le rayon maximal qu’une agrégation couvrira depuis le marqueur central (en pixels). 80 par défaut.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Quand il est activé, cliquer sur l’agrégat zoomera jusqu’à ses limites.",
+ "srf-filtered-selectorlabel-list": "Liste",
+ "srf-filtered-selectorlabel-table": "Tableau",
+ "srf-filtered-selectorlabel-calendar": "Calendrier",
+ "srf-filtered-selectorlabel-map": "Carte",
+ "srf-filtered-noscript-error": "Les résultats ne peuvent pas être affichés parce que Javascript n’est pas activé. Allez à $1.",
+ "srf-filtered-noscript-link-caption": "résultats sous forme tabulée",
+ "srf-filtered-map-provider-missing-error": "Aucun fournisseur de carte spécifié pour la vue « carte ».",
+ "srf-filtered-value-filter-and": "ET",
+ "srf-filtered-value-filter-or": "OU",
+ "srf-filtered-value-filter-placeholder": "Selectionner une valeur de filtre",
+ "srf-printername-d3chart": "Graphique D3",
+ "srf-printername-timeseries": "Graphique de séries chronologiques",
+ "srf-paramdesc-group": "Séries groupées par",
+ "srf-paramdesc-zoom": "Activer le zoom",
+ "srf-paramdesc-datatable": "Activer une table de données",
+ "srf-timeseries-zoom-out-of-range": "La plage de zoom n'a pas produit de données suffisantes",
+ "srf-printername-sparkline": "Graphique de lignes de tendance",
+ "srf-printername-listwidget": "Widget liste",
+ "srf-paramdesc-listtype": "Indiquez le type de liste",
+ "srf-paramdesc-widget": "Widget disponible",
+ "srf-paramdesc-pageitems": "Éléments par page",
+ "srf-printername-eventcalendar": "Calendrier des événements",
+ "srf-paramdesc-calendarfirstday": "Le jour du début de la semaine",
+ "srf-paramdesc-calendardefaultview": "La vue initiale quand le calendrier est chargé",
+ "srf-paramdesc-calendarstart": "Le démarrage du calendrier initial (valeurs de date ou d'horodatage)",
+ "srf-paramdesc-calendarlegend": "Spécifie la position de la légende et les options du filtre assigné",
+ "srf-paramdesc-dayview": "Activer la vue journalière en cliquant sur le numéro du jour",
+ "srf-ui-eventcalendar-label-today": "Aujourd’hui",
+ "srf-ui-eventcalendar-label-month": "Mois",
+ "srf-ui-eventcalendar-label-week": "Semaine",
+ "srf-ui-eventcalendar-label-day": "Jour",
+ "srf-ui-eventcalendar-label-listmonth": "Mois (liste)",
+ "srf-ui-eventcalendar-label-listweek": "Semaine (liste)",
+ "srf-ui-eventcalendar-label-listday": "Jour (liste)",
+ "srf-ui-eventcalendar-label-allday": "Toute la journée",
+ "srf-ui-eventcalendar-label-update-success": "La mise à jour du calendrier des événements a réussi.",
+ "srf-ui-eventcalendar-label-update-error": "La mise a jour du calendrier des événements a échoué.",
+ "srf-ui-eventcalendar-click-popup": "Voulez-vous créer un événement?",
+ "srf-printername-dygraphs": "Diagramme Dygraph",
+ "srf-paramdesc-datasource": "La source depuis laquelle les données sont accessibles. Valeurs autorisées: « file », « raw » et « url ». Par défaut: « file »",
+ "srf-paramdesc-errorbar": "La barre d'erreur à utiliser. Valeurs autorisées: « fraction » (intervalles de confiance pour les valeurs), « sigma » (écart-type des valeurs) et « range » (intervalles de valeurs personnalisés)",
+ "srf-paramdesc-movingaverage": "Affiche la moyenne sur un nombre donné de jours (zéro indiquera aucune moyenne mobile)",
+ "srf-paramdesc-yaxislabel": "Légende apparaissant sur l'axe y",
+ "srf-paramdesc-xaxislabel": "Légende apparaissant sur l'axe x",
+ "srf-paramdesc-unit": "Unité",
+ "srf-printername-pagewidget": "Widget de page",
+ "srf-printername-incoming": "Propriétés entrantes",
+ "srf-paramdesc-count": "Indique si le nombre de propriétés entrantes doit être compté",
+ "srf-paramdesc-min": "Valeur minimale ou seuil",
+ "srf-paramdesc-excludeproperty": "Exclure la propriété de l'ensemble des résultats",
+ "srf-printername-media": "Lecteur de média",
+ "srf-paramdesc-mediainspector": "Affiche des informations détaillées sur un élément de média particulier",
+ "srf-ui-mediaplayer-label-previous": "Précédent",
+ "srf-ui-mediaplayer-label-play": "Lecture",
+ "srf-ui-mediaplayer-label-pause": "Pause",
+ "srf-ui-mediaplayer-label-next": "Suivant",
+ "srf-ui-mediaplayer-label-stop": "Arrêt",
+ "srf-ui-mediaplayer-label-mute": "Muet",
+ "srf-ui-mediaplayer-label-unmute": "Non muet",
+ "srf-ui-mediaplayer-label-volume-max": "Volume max",
+ "srf-ui-mediaplayer-label-shuffle": "Lecture aléatoire",
+ "srf-ui-mediaplayer-label-shuffle-off": "Lecture aléatoire désactivée",
+ "srf-ui-mediaplayer-label-repeat": "Répétition",
+ "srf-ui-mediaplayer-label-repeat-off": "Répétition désactivée",
+ "srf-ui-mediaplayer-label-full-screen": "Plein écran",
+ "srf-ui-mediaplayer-label-restore-screen": "Rétablir l'écran",
+ "srf-spreadsheet-link": "Feuille de calcul",
+ "srf-paramdesc-spreadsheet-filename": "Le nom du fichier pour le téléchargement du fichier classeur généré",
+ "srf-paramdesc-spreadsheet-fileformat": "Le format à produire pour le fichier classeur. Valeurs autorisées : xlsx, xls, ods, csv. Par défaut : xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "Le nom d’un fichier feuille de calcul de l’espace de noms « Fichier » utilisé pour mettre en forme le fichier généré",
+ "srf-paramdesc-icalendar-timezone": "Une liste de fuseaux horaires séparés par des virgules",
+ "srf-paramdesc-gantt-diagramtitle": "Nom du diagramme",
+ "srf-paramdesc-gantt-diagramtheme": "Thème du diagramme",
+ "srf-paramdesc-gantt-axisformat": "Axe X : Format de la date",
+ "srf-paramdesc-gantt-sortkey": "Clé pour trier les sections et les tâches",
+ "srf-paramdesc-gantt-titletopmargin": "Marge en haut du titre du diagramme",
+ "srf-paramdesc-gantt-barheight": "Hauteur des barres de tâche",
+ "srf-paramdesc-gantt-leftpadding": "Largeur du titre de la section",
+ "srf-paramdesc-gantt-bargap": "Distance verticale des barres de tâche depuis la marge",
+ "srf-error-gantt-mapping-assignment": "Mauvaise affectation des valeurs associées dans '''$1'''",
+ "srf-error-gantt-mapping-keywords": "La clé utilisée dans votre paramètre de correspondance n’est pas supportée",
+ "srf-error-gantt-theme": "Le '''thème''' que vous avez choisi n’est pas supporté",
+ "srf-error-gantt-sortkey": "La '''clé de tri''' que vous avez choisie n’est pas supportée",
+ "srf-error-gantt-mermaid-not-installed": "L’extension Mermaid doit être installée.",
+ "srf-printername-gantt": "Gantt",
+ "srf-paramdesc-nodelabel": "Utiliser un libellé de nœud de graphe. Valeurs autorisées : displaytitle."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/frp.json b/www/wiki/extensions/SemanticResultFormats/i18n/frp.json
new file mode 100644
index 00000000..d2ca79cf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/frp.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "srf-name": "Formatâjo des rèsultats sèmanticos",
+ "srf-module-loading": "Chargement...",
+ "srf-paramdesc-height": "Hôtior (en pixèls)",
+ "srf-paramdesc-width": "Largior",
+ "srf-paramdesc-class": "Cllâsse CSS de ples",
+ "srfc_previousmonth": "Mês devant",
+ "srfc_nextmonth": "Mês aprés",
+ "srfc_today": "Houé",
+ "srfc_gotomonth": "Alar vers lo mês",
+ "srf_printername_calendar": "Calendriér du mês",
+ "srf_printername_vcard": "èxportacion en vCard",
+ "srf_printername_icalendar": "èxportacion en iCalendar",
+ "srf_paramdesc_icalendartitle": "Lo titro du fichiér calendriér",
+ "srf_paramdesc_icalendardescription": "La dèscripcion du fichiér calendriér",
+ "srf_printername_bibtex": "èxportacion en BibTeX",
+ "srf_outline_novalue": "Gins de valor",
+ "srf_printername_outline": "Començon",
+ "srf_printername_sum": "Soma de nombros",
+ "srf_printername_average": "Moyena des nombros",
+ "srf_printername_max": "Nombro lo ples grant",
+ "srf_printername_min": "Nombro lo ples petiôt",
+ "srf_printername_product": "Fruit de nombros",
+ "srf_printername_median": "Moyena des nombros",
+ "srf_printername_earliest": "Premiére hora",
+ "srf_printername_latest": "Dèrriére hora",
+ "srf_printername_timeline": "Diagramo cronologico",
+ "srf_printername_eventline": "Diagramo cronologico des èvènements",
+ "srf_printername_googlebar": "Diagramo en bârres de Google",
+ "srf_printername_googlepie": "Diagramo en torta de Google",
+ "srf_paramdesc_chartheight": "La hôtior du diagramo, en pixèls",
+ "srf_paramdesc_chartwidth": "La largior du diagramo, en pixèls",
+ "srf_paramdesc_charttitle": "Lo titro du diagramo",
+ "srf_paramdesc_barcolor": "La color de les bârres",
+ "srf_paramdesc_bardirection": "La dirèccion du diagramo en bârres",
+ "srf_paramdesc_barnumbersaxislabel": "Lo lambél por l’axo numerico",
+ "srf_printername_gallery": "Galerie",
+ "srf_paramdesc_perrow": "Lo nombro d’émâges per legne",
+ "srf_paramdesc_widths": "La largior de les émâges",
+ "srf_paramdesc_heights": "La hôtior de les émâges",
+ "srf-gallery-navigation-previous": "Devant",
+ "srf-gallery-navigation-next": "Aprés",
+ "srf-gallery-overlay-count": "Émâge $1 sur $2",
+ "srf_printername_tagcloud": "Niola de tags",
+ "srf_paramdesc_tagorder": "L’ôrdre des tags",
+ "srf_printername_valuerank": "Valor du rang",
+ "srf_printername_array": "Tablô",
+ "srf_printername_hash": "Chaplâjo",
+ "srf-printername-graph": "Diagramo",
+ "srf_paramdesc_graphname": "Titro",
+ "srf_paramdesc_graphsize": "Talye du diagramo (en px)",
+ "srf_paramdesc_graphlegend": "Fâre vêre la lègenda du diagramo ou ben pas",
+ "srf_paramdesc_graphlabel": "Lambél du diagramo",
+ "srf_paramdesc_rankdir": "Dirèccion de la flèche",
+ "srf_paramdesc_graphlink": "Lim de vers lo diagramo",
+ "srf_paramdesc_graphcolor": "Color du diagramo",
+ "srf-paramdesc-graph-wwl": "Limita de retôrn ôtomatico (en nombro de caractèros)",
+ "srf-printername-datatables": "Grelyes de donâs",
+ "srf-printername-tree": "Âbro",
+ "srf-printername-ultree": "Âbro Ul",
+ "srf-printername-oltree": "Âbro Ol",
+ "srf-printername-filtered": "Filtrâ",
+ "srf-printername-d3chart": "Diagramo D3",
+ "srf-paramdesc-zoom": "Activar lo zoome",
+ "srf-paramdesc-datatable": "Activar na grelye de donâs",
+ "srf-paramdesc-listtype": "Tipo de lista",
+ "srf-paramdesc-pageitems": "Èlèments per pâge"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/fy.json b/www/wiki/extensions/SemanticResultFormats/i18n/fy.json
new file mode 100644
index 00000000..95ac9638
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/fy.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet",
+ "Robin van der Vliet"
+ ]
+ },
+ "srf-ui-navigation-prev": "Foarige",
+ "srf-ui-navigation-next": "Folgjende",
+ "srf-ui-tooltip-title-options": "Opsjes",
+ "srf-ui-tooltip-title-legend": "Leginda",
+ "srfc_today": "Hjoed",
+ "srf-ui-datatables-label-placeholder-column-search": "Sykje...",
+ "srf-ui-datatables-label-sSearch": "Sykje:",
+ "srf-ui-datatables-label-oPaginate-sNext": "Folgjende",
+ "srf-ui-eventcalendar-label-today": "Hjoed",
+ "srf-ui-mediaplayer-label-previous": "Foarige",
+ "srf-ui-mediaplayer-label-next": "Folgjende",
+ "srf-ui-mediaplayer-label-full-screen": "Folsleinskerm"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ga.json b/www/wiki/extensions/SemanticResultFormats/i18n/ga.json
new file mode 100644
index 00000000..203275a6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ga.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කà·à·€à·’න්ද"
+ ]
+ },
+ "srf-module-loading": "Ag Lódáil...",
+ "srf_paramdesc_graphname": "Teideal"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/gd.json b/www/wiki/extensions/SemanticResultFormats/i18n/gd.json
new file mode 100644
index 00000000..255ac081
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/gd.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Akerbeltz"
+ ]
+ },
+ "srf-ui-gridview-label-item": "Ball dàta"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/gl.json b/www/wiki/extensions/SemanticResultFormats/i18n/gl.json
new file mode 100644
index 00000000..34160f92
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/gl.json
@@ -0,0 +1,329 @@
+{
+ "@metadata": {
+ "authors": [
+ "Alma",
+ "Toliño",
+ "Elisardojm",
+ "Banjo",
+ "Nemo bis",
+ "McDutchie",
+ "Navhy"
+ ]
+ },
+ "srf-desc": "Formatos de resultados adicionais para as pescudas de Semantic MediaWiki",
+ "prefs-srf": "ExtensiónË Formatos dos resultados semánticos",
+ "srf-prefs-intro-text": "Ten instalada a extensión para dar formato aos resultados semánticos, pero nestes intres non ten opcións de personalización. Para obter axuda aducuibak, visite a páxina de axuda sobre os [https://www.semantic-mediawiki.org/wiki/Help:Result_formats formatos dos rexultados].",
+ "prefs-srf-eventcalendar-options": "Opcións de calendario de eventos",
+ "srf-prefs-eventcalendar-options-update-default": "Activa as [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates actualizacións automáticas] dos eventos do calendario durante a actualización da páxina",
+ "srf-prefs-eventcalendar-options-paneview-default": "Activar a vista de folla por defecto",
+ "prefs-srf-datatables-options": "Opcións de DataTables",
+ "srf-prefs-datatables-options-update-default": "Activa as [ttps://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates actualizacións automáticas] do contido da táboa durante a actualización da páxina",
+ "srf-prefs-datatables-options-cache-default": "Activar o [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage almacenamento local] para mellorar os tempos de resposta",
+ "srf-module-loading": "Cargando...",
+ "srf-paramdesc-layout": "Esquema dispoñible",
+ "srf-paramdesc-height": "Altura (en píxeles)",
+ "srf-paramdesc-width": "Largo",
+ "srf-paramdesc-class": "Especificar unha clase CSS adicional",
+ "srf-module-nomatch": "Non se atoparon coincidencias",
+ "srf-paramdesc-charttype": "Tipo de gráficas dispoñible",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "Anterior",
+ "srf-ui-navigation-next": "Seguinte",
+ "srf-ui-common-label-source": "Fonte",
+ "srf-ui-common-label-datasource": "Fonte de datos",
+ "srf-ui-common-label-ajax-error": "O servidor informou dun fallo na comunicación con este $1. Intente recargar a páxina ou consulte a $2.",
+ "srf-ui-common-label-request-object": "obxecto da solicitude",
+ "srf-ui-common-label-help-section": "sección de axuda",
+ "srf-ui-tooltip-title-options": "Opcións",
+ "srf-ui-tooltip-title-scope": "Alcance",
+ "srf-ui-tooltip-title-legend": "Lenda",
+ "srf-ui-tooltip-title-filter": "Filtro",
+ "srf-ui-common-label-refresh": "Refrescar",
+ "srf-ui-common-label-parameters": "Parámetros",
+ "srf-ui-common-label-query": "Consulta",
+ "srf-ui-common-label-paneview": "Vista de folla",
+ "srf-ui-common-label-daterange": "Intervalo de datas",
+ "srf-ui-widgets-label-parameter-limit": "Parámetro límite",
+ "srf-error-option-mix": "A opción ($1) non está dispoñible",
+ "srf-error-option-link-all": "A opción ($1) necesita que o parámetro \"link\" estea definido como \"all\"",
+ "srf-error-missing-layout": "Non se pode amosar o gráfico porque falta o deseño.",
+ "srf-error-jqplot-bubble-data-length": "Non é posible amosar o diagrama ou o gráfico por falta de datos.",
+ "srf-error-jqplot-stackseries-data-length": "Non se pode amosar diagrama ou o gráfico porque non todas as barras ou liñas teñen a mesma cantidade de elementos.",
+ "srf-warn-empy-chart": "A gráfica está baleira porque non hai datos suficientes",
+ "srf-paramdesc-color": "A cor para marcar as entradas de calendario",
+ "srfc_previousmonth": "Mes anterior",
+ "srfc_nextmonth": "Mes seguinte",
+ "srfc_today": "Hoxe",
+ "srfc_gotomonth": "Ir ao mes",
+ "srf_printername_calendar": "Calendario mensual",
+ "srf_paramdesc_calendarlang": "O código da lingua na que amosar o calendario",
+ "srf_paramdesc_calendarcolors": "A cor na que amosar cada propiedade de data (exemplo: \"Data de inicio=>green,Data de fin=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "O mes co cal se inicializa a pantalla de calendario (se se omite é o mes actual)",
+ "srf-paramdesc-calendar-startyear": "O ano co cal se inicializa a pantalla de calendario (se se omite é o ano actual)",
+ "srf_vcard_link": "vTarxeta",
+ "srf_printername_vcard": "Exportación en vCard",
+ "srf_icalendar_link": "iCalendario",
+ "srf_printername_icalendar": "Exportación en iCalendar",
+ "srf_paramdesc_icalendartitle": "O título do ficheiro de calendario",
+ "srf_paramdesc_icalendardescription": "A descrición do ficheiro de calendario",
+ "srf_printername_bibtex": "Exportación en BibTeX",
+ "srf_outline_novalue": "Sen valor",
+ "srf_printername_outline": "Esquema",
+ "srf_paramdesc_outlineproperties": "A lista de propiedades a amosar como cabeceiras de contorno, separadas por comas",
+ "srf_printername_sum": "Suma dos números",
+ "srf_printername_average": "Media dos números",
+ "srf_printername_max": "Número máximo",
+ "srf_printername_min": "Número mínimo",
+ "srf_paramdesc_limit": "O número máximo de páxinas a pescudar",
+ "srf_printername_product": "Produto dos números",
+ "srf_printername_median": "Media dos números",
+ "srf-paramdesc-default": "O valor por defecto que se amosará cando non haxa resultados numéricos",
+ "srf_printername_earliest": "Primeira hora",
+ "srf_printername_latest": "Última hora",
+ "srf_printername_timeline": "Liña do tempo",
+ "srf_printername_eventline": "Liña do evento",
+ "srf_paramdesc_timelinebands": "Define as bandas que se amosarán no resultado.",
+ "srf_paramdesc_timelineposition": "Define onde se fixará inicialmente a liña do tempo.",
+ "srf_paramdesc_timelinestart": "Un nome de propiedade usado para definir un primeiro punto de tempo",
+ "srf_paramdesc_timelineend": "Un nome de propiedade usado para definir un segundo punto de tempo",
+ "srf_paramdesc_timelinesize": "A altura da liña do tempo",
+ "srf-timeline-allresults": "Máis resultados para esta pescuda.",
+ "srf-timeline-nojs": "Debe ter o JavaScript activado para ollar a liña do tempo interactiva.",
+ "srf_paramdesc_views": "As vistas a amosar",
+ "srf_paramdesc_facets": "O conxunto de propiedades a amosar en cada páxina",
+ "srf_paramdesc_lens": "O nome dun modelo co que amosar as propiedades da páxina",
+ "srf_printername_googlebar": "Gráfica de barras do Google",
+ "srf_printername_googlepie": "Gráfica circular do Google",
+ "srf-printername-jqplotchart": "Gráfica jqPlot",
+ "srf-printername-jqplotseries": "Serie jqPlot",
+ "srf_paramdesc_chartheight": "Especificar a altura da gráfica (en píxeles ou porcentaxe)",
+ "srf_paramdesc_chartwidth": "Especificar o largo da gráfica (en píxeles ou porcentaxe)",
+ "srf_paramdesc_charttitle": "O título da gráfica",
+ "srf_paramdesc_barcolor": "A cor das barras",
+ "srf_paramdesc_bardirection": "Especificar a dirección da gráfica",
+ "srf-paramdesc-direction": "Especificar a dirección da gráfica",
+ "srf_paramdesc_barnumbersaxislabel": "A etiqueta para o eixe numérico",
+ "srf-paramdesc-labelaxislabel": "A etiqueta para o eixe da etiqueta",
+ "srf-paramdesc-ticklabels": "Activar a visualización de etiquetas de marca",
+ "srf-paramdesc-minvalue": "O valor mínimo que amosar no eixe de ordenadas",
+ "srf-paramdesc-pointlabels": "Amosa os puntos de datos na gráfica",
+ "srf-paramdesc-chartlegend": "Posición da lenda da gráfica",
+ "srf-paramdesc-datalabels": "Etiquetas de datos da gráfica",
+ "srf-paramdesc-charttext": "Texto descritivo da gráfica",
+ "srf-paramdesc-chartclass": "Clase CSS adicional",
+ "srf-paramdesc-renderer": "Seleccione un procesador de gráficas",
+ "srf-paramdesc-filling": "Opción de recheo individual",
+ "srf-paramdesc-theme": "Seleccione un tema visual para a grella",
+ "srf-paramdesc-chartcolor": "Asignar cores individuais á gráfica",
+ "srf-paramdesc-colorscheme": "Seleccione un esquema de cores",
+ "srf-paramdesc-valueformat": "Especifique a regra de formato para os valores",
+ "srf-paramdesc-highlighter": "Amosar un marcador de punto de datos",
+ "srf-paramdesc-smoothlines": "Aplicar un algoritmo de suavizado nas liñas da gráfica",
+ "srf-paramdesc-stackseries": "Amosar a gráfica en forma de serie apilada",
+ "srf-paramdesc-seriesgroup": "Seleccionar o agrupamento por series",
+ "srf-paramdesc-serieslabel": "Determinar a etiqueta da serie",
+ "srf-paramdesc-grouplabel": "Determinar a etiqueta do grupo",
+ "srf-paramdesc-chartcursor": "Opción de visualización do cursor da gráfica",
+ "srf-paramdesc-trendline": "Activar a visualización simultánea dunha gráfica e a súa liña de tencendia",
+ "srf-paramdesc-gridview": "Amosar a gráfica e os conxuntos de datos simultaneamente. Valores permitidos: none e tabs. Predeterminado: \"none\"",
+ "srf-paramdesc-paneview": "Especifique a posición do panel que contén un pequeno gráfico de liñas. Os valores permitidos son: \"abaixo\", \"arriba\" e \"ningún\". Por defecto úsase \"abaixo\"",
+ "srf-paramdesc-infotext": "Amosar información adicional na lapela de información correspondente",
+ "srf-paramdesc-clicktarget": "Definir unha páxina ou un texto de consulta como destino ó premer nunha data do calendario.",
+ "srf-ui-gridview-label-item": "Elemento de datos",
+ "srf-ui-gridview-label-value": "Valor dos datos",
+ "srf-ui-gridview-label-series": "Serie de datos",
+ "srf-ui-gridview-label-chart-tab": "Gráfica",
+ "srf-ui-gridview-label-data-tab": "Datos",
+ "srf-ui-gridview-label-info-tab": "Información",
+ "srf_printername_gallery": "Galería",
+ "srf_paramdesc_perrow": "A cantidade de imaxes por liña",
+ "srf_paramdesc_widths": "O largo das imaxes",
+ "srf_paramdesc_heights": "A altura das imaxes",
+ "srf_paramdesc_autocaptions": "Usar o nome do ficheiro como pé de imaxe cando non se indica ningún",
+ "srf_paramdesc_fileextensions": "Ao usar o nome do ficheiro como pé de imaxe, amosar tamén a extensión do ficheiro",
+ "srf_paramdesc_captionproperty": "O nome dunha propiedade semántica presente nas páxinas consultadas a usar como pé de imaxe",
+ "srf_paramdesc_imageproperty": "Nome dunha propiedade semántica nas páxinas consultadas que apunta cara a imaxes a usar. Cando estea definido, as páxinas consultadas en si non se amosarán como imaxes",
+ "srf-paramdesc-redirects": "O nome dunha propiedade semántica presente nas páxinas consultadas que conteñen o destino da redirección",
+ "srf-paramdesc-navigation": "Control de navegación do esquema",
+ "srf-paramdesc-overlay": "Activar a sobreposición de imaxes",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Seguinte",
+ "srf-gallery-overlay-count": "Imaxe $1 de $2",
+ "srf-gallery-image-url-error": "Non se atopou a imaxe.",
+ "srf_printername_tagcloud": "Nube de etiquetas",
+ "srf_paramdesc_includesubject": "Se os nomes dos temas deben incluírse",
+ "srf_paramdesc_increase": "Como aumentar o tamaño das etiquetas",
+ "srf_paramdesc_tagorder": "A orde das etiquetas",
+ "srf_paramdesc_mincount": "A cantidade mínima de veces que un valor ten que producirse para estar na lista",
+ "srf_paramdesc_minsize": "O tamaño das etiquetas máis pequenas en porcentaxe",
+ "srf_paramdesc_maxsize": "O tamaño das etiquetas máis grandes en porcentaxe",
+ "srf_paramdesc_maxtags": "A cantidade máxima de etiquetas na nube",
+ "srf-paramdesc-excludetags": "Excluír as etiquetas (delimitador: \";\")",
+ "srf_printername_valuerank": "Valor do rango",
+ "srf_printername_array": "Táboa",
+ "srf_paramdesc_pagetitle": "Amosar ou omitir os títulos das páxinas como entradas dos resultados",
+ "srf_paramdesc_hidegaps": "Imprimir ou non os valores non dispoñibles das propiedades e dos rexistros baleiros solicitados, separados por separadores",
+ "srf_paramdesc_arrayname": "En caso de que fose especificado e que a ArrayExtension estea dispoñible, isto creará unha táboa co nome indicado (sen saída visible)",
+ "srf_paramdesc_propsep": "Separador entre as propiedades solicitadas",
+ "srf_paramdesc_manysep": "Separador entre os valores das propiedades con moitos valores",
+ "srf_paramdesc_recordsep": "Separador entre os valores das propiedades de rexistro",
+ "srf_paramdesc_headersep": "Separador entre o nome e o valor da propiedade se \"headers\" está definido como \"show\" ou \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "En caso de que fose aclarado e que a extensión HashTables estea dispoñible, isto creará un hash co nome especificado (sen saída visible)",
+ "srf-printername-graph": "Gráfica",
+ "srf-paramdesc-graph-relation": "Indique se os asuntos ou as propiedades dos nomes son pais ou fillos",
+ "srf-paramdesc-graph-nameprop": "Define a propiedade que se usará como asunto no canto do asunto real, é dicir, o nome da páxina",
+ "srf-paramdesc-graph-nodeshape": "Fixa a forma de cada nodo na gráfica",
+ "srf-paramdesc-graphname": "Define o título do gráfico",
+ "srf-paramdesc-graphsize": "Fixa o tamaño da gráfica en píxeles",
+ "srf-paramdesc-graphlegend": "Indica se a lenda da gráfica debe ser amosada",
+ "srf-paramdesc-graphlabel": "Define o título da gráfica",
+ "srf-paramdesc-rankdir": "Define a dirección das frechas",
+ "srf-paramdesc-graphlink": "Indica se os nodos deben ligar ás súas páxinas wiki",
+ "srf-paramdesc-graphcolor": "Define a cor da gráfica",
+ "srf-paramdesc-graph-wwl": "Define o límite do axuste automático de liña (en número de caracteres)",
+ "srf-paramdesc-clustercolor": "Establece as cores das caixas de agrupamento",
+ "srf-paramdesc-highlight": "Define o nodo que debe ser destacado",
+ "srf-paramdesc-highlightcolor": "Establece a cor de letra do nodo resaltado",
+ "srf-paramdesc-redlinkcolor": "Define a cor de letra para as ligazóns vermellas",
+ "srf-paramdesc-processcategory": "Define a categoría da wiki que contén os pasos de procesos",
+ "srf-paramdesc-showroles": "Amosa os roles correspondentes no gráfico",
+ "srf-paramdesc-showstatus": "Indica se o estado dunha etapa de proceso debería ser visualizada",
+ "srf-paramdesc-showresources": "Amosa os recursos correspondentes no gráfico",
+ "srf-paramdesc-showdiscussion": "Indica se unha páxina de conversa debería ser visualizada",
+ "srf-paramdesc-showredlinks": "Indica se as ligazóns vermellas deberían ser revisadas e resaltadas",
+ "srf-paramdesc-showcompound": "Indica se resaltar os nodos compostos, p. exe. os subprocesos",
+ "srf-paramdesc-debug": "Indica se o código do gráfico de procesos debería ser amosado entre etiquetas ''pre''",
+ "srf-paramdesc-graphvalidation": "Amosa as etapas do proceso en vermello cando non teñen un rol asignado",
+ "srf-printername-datatables": "Táboas de datos",
+ "srf-ui-datatables-label-conditions": "Condicións",
+ "srf-ui-datatables-label-parameters": "Parámetros",
+ "srf-ui-datatables-label-filters": "Filtros de columnas e procura",
+ "srf-ui-datatables-label-information": "Información",
+ "srf-ui-datatables-panel-disclaimer": "Os parámetros e as condicións poden modificarse, pero calquera modificación é temporal e será descartada despois de refrescar a páxina.",
+ "srf-ui-datatables-label-update-success": "A actualización da táboa foi correcta",
+ "srf-ui-datatables-label-update-error": "Fallou a actualización da táboa.",
+ "srf-ui-datatables-label-placeholder-column-search": "Procurar...",
+ "srf-ui-datatables-label-content-cache": "O contido foi recuperado da caché local.",
+ "srf-ui-datatables-label-content-server": "O contido foi recuperado do servidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Columnas dispoñibles",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Configuración de filtros",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "As columnas son visibles",
+ "srf-ui-datatables-label-sEmptyTable": "Non hai datos dispoñibles na táboa",
+ "srf-ui-datatables-label-sInfo": "Amosando _START_ to _END_ of _TOTAL_ entradas",
+ "srf-ui-datatables-label-sInfoEmpty": "Amosa de 0 a 0 de 0 entradas",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtrado de _MAX_ entradas do total)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Amosar as entradas _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "Cargando...",
+ "srf-ui-datatables-label-sProcessing": "Procesando...",
+ "srf-ui-datatables-label-sSearch": "Procurar:",
+ "srf-ui-datatables-label-sZeroRecords": "Non se atoparon rexistros que coincidisen",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primeiro",
+ "srf-ui-datatables-label-oPaginate-sLast": "Último",
+ "srf-ui-datatables-label-oPaginate-sNext": "Seguinte",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activar para ordenar a columna ascendentemente",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": activar para ordenar a columna descendentemente",
+ "srf-printername-tree": "Ãrbore",
+ "srf-printername-ultree": "Ãrbore UL",
+ "srf-printername-oltree": "Ãrbore OL",
+ "srf-tree-noparentprop": "Non se especificou propiedade pai ningunha. Non se pode construír a árbore sen achegar unha propiedade pai.",
+ "srf-tree-rootinvalid": "\"$1\" non é un título de páxina válido.",
+ "srf-tree-circledetected": "Detectadas relacións circulares ó intentar inserir $1 na árbore.",
+ "srf-paramdesc-tree-parent": "A propiedade que contén a páxina pai",
+ "srf-paramdesc-tree-root": "Páxina raíz da árbore",
+ "srf-paramdesc-tree-startlevel": "Nivel inicial da árbore, p. ex. para integrala noutra árbore",
+ "srf-printername-slideshow": "Presentación de diapositivas",
+ "srf-paramdesc-delay": "O tempo entre diapositivas, en segundos",
+ "srf-paramdesc-navigation-controls": "Amosar ou non os controis de navegación",
+ "srf-paramdesc-effect": "O efecto que se usará ao cambiar dunha diapositiva a outra",
+ "srf-printername-filtered": "Filtrado",
+ "srf-paramdesc-filtered-views": "As vistas que deberan estar dispoñibles na presentación do resultado.",
+ "srf-paramdesc-filtered-filter-position": "A posición dos filtros en relación coas visitas. Valores permitidos: ''top'', ''bottom''. Predeterminado: ''top''.",
+ "srf-paramdesc-filtered-list-type": "O tipo de lista. Valores permitidos: ''list'', ''ul'', ''ol''. Predeterminado: ''list''.",
+ "srf-paramdesc-filtered-list-template": "O modelo empregado para dar formato ás entradas da lista.",
+ "srf-paramdesc-filtered-list-named-args": "Dea nome aos argumentos que se lle pasan ao modelo.",
+ "srf-paramdesc-filtered-list-introtemplate": "O nome dun modelo a amosar antes dos resultados da pescuda, se houbese algún.",
+ "srf-paramdesc-filtered-list-outrotemplate": "O nome dun modelo a amosar despois dos resultados da pescuda, se houbese algún.",
+ "srf-paramdesc-filtered-calendar-start": "A impresión que contén a data de inicio dun acontecemento",
+ "srf-paramdesc-filtered-calendar-end": "A impresión que contén a data de fin dun acontecemento",
+ "srf-paramdesc-filtered-calendar-title": "A impresión que contén o título dun acontecemento. Non se pode empregar á vez que un modelo de título.",
+ "srf-paramdesc-filtered-calendar-title-template": "Un modelo utilizado para dar formato ao título dun acontecemento no calendario",
+ "srf-paramdesc-filtered-map-position": "A impresión que contén a posición xeográfica.",
+ "srf-paramdesc-filtered-map-icon": "A impresión que decide a icona de mapa a ser usado.",
+ "srf-paramdesc-filtered-map-icons": "Un mapa de valores a iconas para ser utilizado para estes valores no mapa.",
+ "srf-paramdesc-filtered-map-height": "A altura do mapa.",
+ "srf-paramdesc-filtered-map-zoom": "O nivel do zoom cando se carga o mapa. Pode ser modificado polo usuario. <br>ConsulteË <i>zoom mínimo da vista do mapa</i> e <i>zoom máximo da vista do mapa</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "O mínimo nivel de zoom seleccionable no mapa",
+ "srf-paramdesc-filtered-map-max-zoom": "O máximo nivel de zoom seleccionable no mapa",
+ "srf-paramdesc-filtered-map-marker-cluster": "Activa ou desactiva o marcador de agrupación.",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Táboa",
+ "srf-filtered-selectorlabel-calendar": "Calendario",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "Os resultados non poden visualizarse porque o Javascript non está activado. Vaia a $1.",
+ "srf-filtered-noscript-link-caption": "resultados en forma de táboa",
+ "srf-filtered-map-provider-missing-error": "Non se indicou o provedor de mapa para a vista \"mapa\".",
+ "srf-filtered-value-filter-and": "E",
+ "srf-filtered-value-filter-or": "OU",
+ "srf-filtered-value-filter-placeholder": "Seleccionar un valor de filtro",
+ "srf-printername-d3chart": "Gráfica D3",
+ "srf-printername-timeseries": "Gráfica de serie temporal",
+ "srf-paramdesc-group": "Serie agrupada por",
+ "srf-paramdesc-zoom": "Activar o zoom",
+ "srf-paramdesc-datatable": "Activar unha táboa de datos",
+ "srf-timeseries-zoom-out-of-range": "O rango do zoom non produciu datos suficientes",
+ "srf-printername-sparkline": "Gráfica sparkline",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Especificar o tipo de lista",
+ "srf-paramdesc-widget": "Widget dispoñible",
+ "srf-paramdesc-pageitems": "Elementos por páxina",
+ "srf-printername-eventcalendar": "Calendario de eventos",
+ "srf-paramdesc-calendarfirstday": "O día que comeza a semana",
+ "srf-paramdesc-calendardefaultview": "A vista inicial cando carga o calendario",
+ "srf-paramdesc-calendarstart": "O comezo do calendario inicial (valores de data ou date e hora)",
+ "srf-paramdesc-calendarlegend": "Especifica a posición da lenda e as opcións do filtro asignado",
+ "srf-paramdesc-dayview": "Activar a vista de día ao premer no número do día",
+ "srf-ui-eventcalendar-label-today": "Hoxe",
+ "srf-ui-eventcalendar-label-month": "Mes",
+ "srf-ui-eventcalendar-label-week": "Semana",
+ "srf-ui-eventcalendar-label-day": "Día",
+ "srf-ui-eventcalendar-label-listmonth": "Mes (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Semana (lista)",
+ "srf-ui-eventcalendar-label-listday": "Día (lista)",
+ "srf-ui-eventcalendar-label-allday": "Todo o día",
+ "srf-ui-eventcalendar-label-update-success": "A actualización do calendario de eventos foi correcta.",
+ "srf-ui-eventcalendar-label-update-error": "Fallou a actualización do calendario de eventos.",
+ "srf-ui-eventcalendar-click-popup": "Queres crear un evento?",
+ "srf-printername-dygraphs": "Gráfica dupla",
+ "srf-paramdesc-datasource": "A fonte na que están accesibles os datos. Valores permitidos: ''file'', ''raw'' e ''url''. Predeterminado: ''file''",
+ "srf-paramdesc-errorbar": "A barra de erro a utilizar. Valores permitidos: ''fraction'' (intervalos de confianza dos valores), ''sigma'' (desviación típica dos valores) e ''range'' (rangos personalizados de valores)",
+ "srf-paramdesc-movingaverage": "Amosar a media despois dun número de días (\"zero\" ha indicar que a media non se move)",
+ "srf-paramdesc-yaxislabel": "Descrición do eixe Y",
+ "srf-paramdesc-xaxislabel": "Descrición do eixe X",
+ "srf-paramdesc-unit": "Unidade",
+ "srf-printername-pagewidget": "Pagewidget",
+ "srf-printername-incoming": "Propiedades entrantes",
+ "srf-paramdesc-count": "Indica se o número de propiedades entrantes debería ser contado",
+ "srf-paramdesc-min": "Valor mínimo ou límite",
+ "srf-paramdesc-excludeproperty": "Excluír a propiedade do conxunto de resultados",
+ "srf-printername-media": "Reprodutor multimedia",
+ "srf-paramdesc-mediainspector": "Amosa a información detallada sobre un elemento multimedia específico",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reproducir",
+ "srf-ui-mediaplayer-label-pause": "Pausar",
+ "srf-ui-mediaplayer-label-next": "Seguinte",
+ "srf-ui-mediaplayer-label-stop": "Deter",
+ "srf-ui-mediaplayer-label-mute": "Silenciar",
+ "srf-ui-mediaplayer-label-unmute": "Restablecer o son",
+ "srf-ui-mediaplayer-label-volume-max": "Volume máximo",
+ "srf-ui-mediaplayer-label-shuffle": "Reprodución aleatoria",
+ "srf-ui-mediaplayer-label-shuffle-off": "Reprodución aleatoria desactivada",
+ "srf-ui-mediaplayer-label-repeat": "Repetición",
+ "srf-ui-mediaplayer-label-repeat-off": "Repetición desactivada",
+ "srf-ui-mediaplayer-label-full-screen": "Pantalla completa",
+ "srf-ui-mediaplayer-label-restore-screen": "Restablecer a pantalla",
+ "srf-spreadsheet-link": "Folla de cálculo",
+ "srf-paramdesc-icalendar-timezone": "Unha lista de fusos horarios separados por comas"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/grc.json b/www/wiki/extensions/SemanticResultFormats/i18n/grc.json
new file mode 100644
index 00000000..a5602496
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/grc.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Omnipaedista"
+ ]
+ },
+ "srfc_today": "ΣήμεÏον",
+ "srf_printername_outline": "ΠεÏίγÏαμμα"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/gsw.json b/www/wiki/extensions/SemanticResultFormats/i18n/gsw.json
new file mode 100644
index 00000000..9dbf3293
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/gsw.json
@@ -0,0 +1,48 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Holder"
+ ]
+ },
+ "srf-desc": "Zuesätzligi Format fir Semantic MediaWiki inline-Abfroge",
+ "srf-name": "Semantisch Ergebnis-Format",
+ "srfc_previousmonth": "Vorige Monet",
+ "srfc_nextmonth": "Negschte Monet",
+ "srfc_today": "Hit",
+ "srfc_gotomonth": "Gang zum Monet",
+ "srf_printername_calendar": "Monetlige Kaländer",
+ "srf_paramdesc_calendarlang": "Dr Sprochcode fir d Sproch, wu dr Kaländer soll din aazeigt wäre",
+ "srf_printername_vcard": "vCard-Export",
+ "srf_printername_icalendar": "iCalendar-Export",
+ "srf_paramdesc_icalendartitle": "Dr Titel vu dr Kaländerdatei",
+ "srf_paramdesc_icalendardescription": "D Bschryybig vu dr Kaländerdatei",
+ "srf_printername_bibtex": "BibTeX-Export",
+ "srf_outline_novalue": "Kei Wärt",
+ "srf_printername_outline": "Entwurf",
+ "srf_paramdesc_outlineproperties": "D Lischt vu dr Eigeschafte, wu as Ibersichts-Chopftext aazeigt wird, dur Komma trännt",
+ "srf_printername_sum": "Zahl vu Nummere",
+ "srf_printername_average": "Durschnitt vu Nummere",
+ "srf_printername_max": "Hegschti Nummere",
+ "srf_printername_min": "Niderschti Nummere",
+ "srf_paramdesc_limit": "Di maximal Sytezahl, wu abgfrogt wird",
+ "srf_printername_timeline": "Zytlyschte",
+ "srf_printername_eventline": "Ereignislyschte",
+ "srf_paramdesc_timelinebands": "Definiert d Skalierig, wu d Ergebnis aazeigt wäre.",
+ "srf_paramdesc_timelineposition": "Definiert dr Schwärpunkt vu dr Zytachse.",
+ "srf_paramdesc_timelinestart": "Dr Name vu dr Eigeschaft, wu dr erscht Zytpunkt definiert",
+ "srf_paramdesc_timelineend": "Dr Name vu dr Eigenschaft, wu dr zwet Zytpunkt definiert",
+ "srf_paramdesc_timelinesize": "D Hechi vu dr Zytachse",
+ "srf_paramdesc_views": "D Ibersichte, wu aazeigt wäre",
+ "srf_paramdesc_facets": "D Eigeschafte, wu uf jedere Syte solle aazeigt wäre",
+ "srf_paramdesc_lens": "Dr Name vu dr Vorlag, wu Syteneigeschafte dermit aazeigt wäre",
+ "srf_printername_googlebar": "Google-Syylediagramm",
+ "srf_printername_googlepie": "Google-Kreisdiagramm",
+ "srf_paramdesc_chartheight": "D Hechi vum Diagramm, in Pixel",
+ "srf_paramdesc_chartwidth": "D Breiti vum Diagramm, in Pixel",
+ "srf_paramdesc_charttitle": "Dr Titel vum Diagramm",
+ "srf_paramdesc_barcolor": "D Farb vu dr Balke",
+ "srf_paramdesc_bardirection": "E Syyle- (sänkrächti Uusrichtig) oder Balkediagramm (woogrächti Uusrichtig)",
+ "srf_paramdesc_barnumbersaxislabel": "D Bschryftig vu dr Zahle-Achs",
+ "srf_printername_gallery": "Galeri",
+ "srf_printername_tagcloud": "Schlagwortwulche"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/gv.json b/www/wiki/extensions/SemanticResultFormats/i18n/gv.json
new file mode 100644
index 00000000..b5ad99dd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/gv.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "MacTire02"
+ ]
+ },
+ "srfc_previousmonth": "Yn vee roish shen",
+ "srfc_nextmonth": "Yn chied vee elley",
+ "srfc_today": "Jiu"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/he.json b/www/wiki/extensions/SemanticResultFormats/i18n/he.json
new file mode 100644
index 00000000..7555c301
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/he.json
@@ -0,0 +1,292 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "StuB",
+ "YaronSh",
+ "×—×™×™×",
+ "Inkbug",
+ "Guycn2",
+ "Nemo bis",
+ "המקיסט",
+ "Steeve815"
+ ]
+ },
+ "srf-desc": "תבניות תוצ××” נוספות לש×ילתות של מדיה־ויקי סמנטית",
+ "prefs-srf": "הרחבה:תבניות תוצ××” סמנטיות",
+ "srf-prefs-intro-text": "התקנת ×ת ההרחבה תבניות תוצ××” סמנטיות (Semantic Result Formats). לעזרה נוספת × × ×œ×‘×§×¨ בדף העזרה [https://www.semantic-mediawiki.org/wiki/Help:Result_formats result formats].",
+ "prefs-srf-eventcalendar-options": "×פשרויות יומן ×ירועי×",
+ "srf-prefs-eventcalendar-options-update-default": "הפעלת [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates ×¢×“×›×•× ×™× ×וטומטיי×] של ××™×¨×•×¢×™× ×‘×™×•×ž×Ÿ בזמן רענון דף",
+ "srf-prefs-eventcalendar-options-paneview-default": "הפעלה של תצוגת החלוניות תחילה",
+ "prefs-srf-datatables-options": "×פשרויות טבל×ות נתוני×",
+ "srf-prefs-datatables-options-update-default": "הפעלת [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates ×¢×“×›×•× ×™× ×וטומטיי×] של תוכן הטבלה בזמן רענון הדף",
+ "srf-prefs-datatables-options-cache-default": "הפעלת [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage ×חסון מקומי] לשיפור זמן התגובה",
+ "srf-module-loading": "טעינה...",
+ "srf-paramdesc-layout": "עיצוב זמין",
+ "srf-paramdesc-height": "גובה",
+ "srf-paramdesc-width": "רוחב",
+ "srf-paramdesc-class": "× × ×œ×¦×™×™×Ÿ מחלקה חדשה של גיליונות סגנון ×ž×“×•×¨×’×™× (CSS)",
+ "srf-module-nomatch": "×œ× × ×ž×¦×ו הת×מות",
+ "srf-paramdesc-charttype": "סוג ×ª×¨×©×™× ×–×ž×™×Ÿ",
+ "srf-navigation-previous": "הקוד×",
+ "srf-ui-navigation-prev": "הקוד×",
+ "srf-ui-navigation-next": "הב×",
+ "srf-ui-common-label-source": "מקור",
+ "srf-ui-common-label-datasource": "מקור נתוני×",
+ "srf-ui-common-label-ajax-error": "השרת דיווח כשל בתקשרות עבור $1 ×”×–×”. × × ×œ× ×¡×•×ª לרענן ×ת הדף ×ו ×œ×§×¨×•× ×ת $2 ×”×–×ת.",
+ "srf-ui-common-label-request-object": "×¢×¦× ×”×‘×§×©×”",
+ "srf-ui-common-label-help-section": "פסקת העזרה",
+ "srf-ui-tooltip-title-options": "×פשרויות",
+ "srf-ui-tooltip-title-scope": "טווח",
+ "srf-ui-tooltip-title-legend": "מקר×",
+ "srf-ui-tooltip-title-filter": "מסנן",
+ "srf-ui-common-label-refresh": "רענון",
+ "srf-ui-common-label-parameters": "פרמטרי×",
+ "srf-ui-common-label-query": "ש×ילתה",
+ "srf-ui-common-label-paneview": "תצוגת חלוניות",
+ "srf-ui-common-label-daterange": "טווח ת×ריכי×",
+ "srf-ui-widgets-label-parameter-limit": "פרמטר הגבלה",
+ "srf-error-option-mix": "×”×פשרות ($1) ××™× ×” קיימת",
+ "srf-error-option-link-all": "×”×פשרות ($1) דורשת שהפרמטר \"link\" יוגדר בתור \"all\"",
+ "srf-error-missing-layout": "×œ× × ×™×ª×Ÿ להציג ×ת ×”×ª×¨×©×™× ×ו ×ת הגרף ×”×–×”, ×›×™ העיצוב חסר.",
+ "srf-error-jqplot-stackseries-data-length": "×œ× × ×™×ª×Ÿ להציג ×ת ×”×ª×¨×©×™× ×ו ×ת הגרף ×›×™ ×œ× ×œ×›×œ עמודה ×ו קו יש ×ותו מספר מרכיבי×.",
+ "srf-warn-empy-chart": "×”×ª×¨×©×™× ×ו הגרף ריק בשל × ×ª×•× ×™× ×—×¡×¨×™×",
+ "srfc_previousmonth": "החודש שעבר",
+ "srfc_nextmonth": "החודש הב×",
+ "srfc_today": "היו×",
+ "srfc_gotomonth": "מעבר ×ל חודש",
+ "srf_printername_calendar": "לוח חודשי",
+ "srf_paramdesc_calendarlang": "קוד השפה שלוח השנה יוצג בה",
+ "srf_paramdesc_calendarcolors": "צבע להצגת כל מ×פיין של ת×ריך (דוגמה: \"ת×ריך התחלה=>green,ת×ריך סיו×=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "החוד שתצוגת לוח השנה מ×ותחלת ×תו (בררת המחדל ×”×™× ×”×—×•×“×© הנוכחי)",
+ "srf-paramdesc-calendar-startyear": "השנה שתצוגת לוח השנה מ×ותחלת ×תה (בררת המחדל ×”×™× ×”×©× ×” הנוכחית)",
+ "srf_printername_vcard": "×™×™×¦×•× vCard",
+ "srf_printername_icalendar": "×™×™×¦×•× iCalendar",
+ "srf_paramdesc_icalendartitle": "כותרת קובץ לוח השנה",
+ "srf_paramdesc_icalendardescription": "תי×ור קובץ לוח השנה",
+ "srf_printername_bibtex": "×™×™×¦×•× BibTeX",
+ "srf_outline_novalue": "×ין ערך",
+ "srf_printername_outline": "מִת×ר",
+ "srf_paramdesc_outlineproperties": "רשימת מ××¤×™×™× ×™× ×œ×”×¦×’×” ככותרות במִת×ר, מופרדת בפסיקי×",
+ "srf_printername_sum": "×¡×›×•× ×©×œ מספרי×",
+ "srf_printername_average": "ממוצע של מספרי×",
+ "srf_printername_max": "המספר המרבי",
+ "srf_printername_min": "המספר המזערי",
+ "srf_paramdesc_limit": "מספר ×”×“×¤×™× ×”×ž×¨×‘×™ לתש×ול",
+ "srf_printername_product": "מכפלה של מספרי×",
+ "srf_printername_median": "חציון של מספרי×",
+ "srf-paramdesc-default": "ערך בררת מחדל שיוצג ×× ×ין תוצ×ות מספריות",
+ "srf_printername_earliest": "הזמן ×”×ž×•×§×“× ×‘×™×•×ª×¨",
+ "srf_printername_latest": "הזמן המ×וחר ביותר",
+ "srf_printername_timeline": "ציר זמן",
+ "srf_printername_eventline": "ציר ×ירועי×",
+ "srf_paramdesc_timelinebands": "מגדיר ×ילו ×¤×¡×™× ×ž×•×¦×’×™× ×‘×ª×•×¦×ות.",
+ "srf_paramdesc_timelineposition": "מגדיר ×יפה קו הזמן מתמקד בתחילה.",
+ "srf_paramdesc_timelinestart": "×©× ×”×ž×פיין להגדרה בתור נקודת הזמן הר×שונה",
+ "srf_paramdesc_timelineend": "×©× ×”×ž×פיין להגדרת נקודת זמן שנייה",
+ "srf_paramdesc_timelinesize": "גובה ציר הזמן",
+ "srf-timeline-allresults": "תוצ×ות נוספות עבור ש×ילתה זו.",
+ "srf-timeline-nojs": "יש ל×פשר ×ת JavaScript כדי לצפות בציר זמן ×ינטר×קטיבי.",
+ "srf_paramdesc_views": "התצוגות להצגה",
+ "srf_paramdesc_facets": "קבוצת מ××¤×™×™× ×™× ×œ×”×¦×’×” בר×ש כל דף",
+ "srf_paramdesc_lens": "×©× ×”×ª×‘× ×™×ª שמ×פייני הדף יוצגו ב×מצעותה",
+ "srf_printername_googlebar": "×ª×¨×©×™× ×¢×ž×•×“×•×ª של Google",
+ "srf_printername_googlepie": "×ª×¨×©×™× ×¢×•×’×” של גוגל",
+ "srf-printername-jqplotchart": "×ª×¨×©×™× jqPlot",
+ "srf-printername-jqplotseries": "סדרת jqPlot",
+ "srf_paramdesc_chartheight": "× × ×¦×™×™×Ÿ ×ת הגובה (בפיקסלי×) של ×ª×¨×©×™× ×ו גרף",
+ "srf_paramdesc_chartwidth": "× × ×œ×¦×™×™×Ÿ ×ת הרוחב (×¤×™×§×¡×œ×™× ×ו ×חוזי×) של ×ª×¨×©×™× ×ו גרף",
+ "srf_paramdesc_charttitle": "כותרת התרשי×",
+ "srf_paramdesc_barcolor": "× × ×œ×¦×™×™×Ÿ ×ת צבע הפסי×",
+ "srf_paramdesc_bardirection": "כיוון התרשי×",
+ "srf-paramdesc-direction": "× × ×œ×¦×™×™×Ÿ ×ת הכיוון של ×ª×¨×©×™× ×ו גרף",
+ "srf_paramdesc_barnumbersaxislabel": "התווית לציר המספרי×",
+ "srf-paramdesc-labelaxislabel": "התווית עבור הציר",
+ "srf-paramdesc-ticklabels": "ל×פשר תצוגה של תוויות שנתות",
+ "srf-paramdesc-minvalue": "הערך המזערי להצגה בציר ה־y",
+ "srf-paramdesc-pointlabels": "הצגת נקודות × ×ª×•× ×™× ×‘×ª×¨×©×™×",
+ "srf-paramdesc-chartlegend": "×ž×™×§×•× ×”×ž×§×¨× ×©×œ התרשי×",
+ "srf-paramdesc-datalabels": "תוויות ×”× ×ª×•× ×™× ×©×œ התרשי×/גרף",
+ "srf-paramdesc-charttext": "תי×ור ×”×ª×¨×©×™× ×‘×˜×§×¡×˜",
+ "srf-paramdesc-chartclass": "מחלקת CSS נוספת",
+ "srf-paramdesc-renderer": "× × ×œ×‘×—×•×¨ של גרף/תרשי×",
+ "srf-paramdesc-filling": "×פשרות מילוי בודדה",
+ "srf-paramdesc-theme": "× × ×œ×‘×—×•×¨ ערכת × ×•×©× ×©×œ רשת",
+ "srf-paramdesc-chartcolor": "הקצ×ת צבעי ×ª×¨×©×™× ×‘×•×“×“×™×",
+ "srf-paramdesc-colorscheme": "× × ×œ×‘×—×•×¨ ערכת צבעי×",
+ "srf-paramdesc-valueformat": "× × ×œ×¦×™×™×Ÿ חוק עיצוב לערכי×",
+ "srf-paramdesc-highlighter": "הצגת סימון של נקודת נתוני×",
+ "srf-paramdesc-smoothlines": "החלת ××œ×’×•×¨×™×ª× ×”×—×œ×§×” על תרשימי קו",
+ "srf-paramdesc-stackseries": "הצגת ×ª×¨×©×™× ×›×¡×“×¨×” מעורמת",
+ "srf-paramdesc-seriesgroup": "× × ×œ×‘×—×•×¨ הקבצה של סדרה",
+ "srf-paramdesc-serieslabel": "קביעת התווית של הסדרה",
+ "srf-paramdesc-grouplabel": "קביעת התווית של הקבוצה",
+ "srf-paramdesc-chartcursor": "×פשרות תצוגה של סמן התרשי×",
+ "srf-paramdesc-trendline": "×פשר תצוגה בו־זמנית של ×ª×¨×©×™× ×•×©×œ קו המגמה שלו",
+ "srf-paramdesc-gridview": "הצגת ×ª×¨×©×™× ×•×¢×¨×›×•×ª × ×ª×•× ×™× ×‘×•Ö¾×–×ž× ×™×ª. ×”×¢×¨×›×™× ×”×ž×•×ª×¨×™×: \"none\" ו־\"tabs\". ברירת מחדל: \"none\"",
+ "srf-paramdesc-paneview": "× × ×œ×¦×™×™×Ÿ ×ת ×”×ž×™×§×•× ×©×œ החלונית שמכילה ×ת ×ª×¨×©×™× ×”×§×•×•×™× ×”×§×˜×Ÿ. ×¢×¨×›×™× ×ž×•×¨×©×™×: \"\"bottom\"â€, \"top\" ו־\"none\"",
+ "srf-paramdesc-infotext": "הצגת מידע נוסף בלשונית מידע מת×ימה",
+ "srf-ui-gridview-label-item": "פריט נתוני×",
+ "srf-ui-gridview-label-value": "ערך הנתוני×",
+ "srf-ui-gridview-label-series": "סדרת נתוני×",
+ "srf-ui-gridview-label-chart-tab": "תרשי×",
+ "srf-ui-gridview-label-data-tab": "נתוני×",
+ "srf-ui-gridview-label-info-tab": "מידע",
+ "srf_printername_gallery": "גלריה",
+ "srf_paramdesc_perrow": "מספר התמונות לשורה",
+ "srf_paramdesc_widths": "רוחב התמונות",
+ "srf_paramdesc_heights": "גובה התמונות",
+ "srf_paramdesc_autocaptions": "להשתמש בקובץ בתור כותרת ×× ×œ× ×¡×•×¤×§×” כותרת",
+ "srf_paramdesc_fileextensions": "בעת שימוש ×‘×©× ×”×§×•×‘×¥ ככיתוב, להציג ×’× ×ת סיומת הקובץ",
+ "srf_paramdesc_captionproperty": "×”×©× ×©×œ מ×פיין סמנטי ×§×™×™× ×‘×“×¤×™ הש×ילתה כדי לשמש ככיתוב",
+ "srf_paramdesc_imageproperty": "×©× ×©×œ מ×פיין סמנטי בדפי הש×ילתה המצביע על תמונות לשימוש. ×›×שר ×פשרות זו מוגדרת, דפי הש×ילתה ×¢×¦×ž× ×œ× ×™×•×¦×’×• כתמונות",
+ "srf-paramdesc-redirects": "×”×©× ×©×œ מ×פיין סמנטי ×§×™×™× ×‘×“×¤×™ הש×ילתה ×©×ž×›×™×œ×™× ×ת היעד של ההפניה",
+ "srf-paramdesc-navigation": "פריסת הבקרה של הניווט",
+ "srf-paramdesc-overlay": "להפעיל כיסוי תמונה",
+ "srf-gallery-navigation-previous": "הקוד×",
+ "srf-gallery-navigation-next": "הב×",
+ "srf-gallery-overlay-count": "תמונה $1 מתוך $2",
+ "srf-gallery-image-url-error": "התמונה ×œ× × ×ž×¦××”.",
+ "srf_printername_tagcloud": "ענן תגי×",
+ "srf_paramdesc_includesubject": "×”×× ×œ×›×œ×•×œ השמות של הנוש××™× ×¢×¦×ž×",
+ "srf_paramdesc_increase": "×יך להגדיל ×ת גודל התגי×",
+ "srf_paramdesc_tagorder": "סדר התגי×",
+ "srf_paramdesc_mincount": "המספר המזערי של ×”×¤×¢×ž×™× ×©×”×¢×¨×š צריך להופיע כדי להיכנס לרשימה",
+ "srf_paramdesc_minsize": "גודל התג הקטן ביותר ב×חוזי×",
+ "srf_paramdesc_maxsize": "גודל ×”×ª×’×™× ×”×’×“×•×œ×™× ×‘×™×•×ª×¨ ב×חוזי×",
+ "srf_paramdesc_maxtags": "המספר המרבי של ×ª×’×™× ×‘×¢× ×Ÿ",
+ "srf-paramdesc-excludetags": "×œ× ×œ×›×œ×•×œ ×ª×’×™× (מפריד: \";\")",
+ "srf_printername_valuerank": "דרגת הערך",
+ "srf_printername_array": "מערך",
+ "srf_paramdesc_pagetitle": "×”×× ×œ×”×¦×™×’ כותרות ×“×¤×™× ×‘×ª×•×¨ עיולי תוצ××” ×ו להסתיר ×ות×",
+ "srf_paramdesc_hidegaps": "×”×× ×œ×”×“×¤×™×¡ תכונה שהתבקשה ×בל ××™× ×” זמינה ×ž×•×¤×¨×“×™× ×‘×ª×• מפריד ×ו להסתיר ×ות×",
+ "srf_paramdesc_arrayname": "×× × ×™×ª×Ÿ וההרחבה ArrayExtension זמינה, ×–×” ייצור מערך ×¢× ×”×©× ×”×ž×•×’×“×¨ (ו××– ×œ× ×™×”×™×” פלט נר××” לעין)",
+ "srf_paramdesc_propsep": "מפריד בין רשומות מבוקשות",
+ "srf_paramdesc_manysep": "מפריד בין ערכי מ××¤×™×™× ×™× ×ž×¨×•×‘×™Ö¾×¢×¨×›×™×",
+ "srf_paramdesc_recordsep": "מפריד בין ×¢×¨×›×™× ×©×œ מ×פייני רשומות",
+ "srf_paramdesc_headersep": "מפריד בין ×©× ×”×ž×פיין לערך ×× \"headers\" מוגדר ×›Ö¾\"show\" ×ו \"plain\"",
+ "srf_printername_hash": "גיבוב",
+ "srf_paramdesc_hashname": "×× ×–×” ניתן ו×× ×”×”×¨×—×‘×” HashTables זמינה, ×–×” ייצור גיבוב ×¢× ×¢× ×”×©× ×”×ž×•×’×“×¨ (ו××– ×œ× ×™×”×™×” פלט נר××” לעין)",
+ "srf-printername-graph": "תרשי×",
+ "srf-paramdesc-graph-relation": "×”×× ×”× ×•×©××™× ×ו מ×פייני ×©× (nameproperties) ×”×•×¨×™× ×ו ילדי×?",
+ "srf-paramdesc-graph-nameprop": "מ×פשר הגדרת מ×פיין שישמש × ×•×©× ×‘×ž×§×•× ×”× ×•×©× ×”× ×•×›×—×™",
+ "srf-paramdesc-graph-nodeshape": "הצורה של כל צומת בגרף",
+ "srf-paramdesc-graphname": "כותרת",
+ "srf-paramdesc-graphsize": "גודל הגרף (בפיקסלי×)",
+ "srf-paramdesc-graphlegend": "להציג ×ת ×ž×§×¨× ×”×’×¨×£ ×ו ל×",
+ "srf-paramdesc-graphlabel": "תווית גרף",
+ "srf-paramdesc-rankdir": "כיוון החץ",
+ "srf-paramdesc-graphlink": "קישור גרף",
+ "srf-paramdesc-graphcolor": "צבע הגרף",
+ "srf-paramdesc-graph-wwl": "מגבלת גלישת ×ž×™×œ×™× (מספר תווי×)",
+ "srf-printername-datatables": "טבל×ות נתוני×",
+ "srf-ui-datatables-label-conditions": "תנ××™×",
+ "srf-ui-datatables-label-parameters": "פרמטרי×",
+ "srf-ui-datatables-label-filters": "מסנני עמודה וחיפוש",
+ "srf-ui-datatables-label-information": "מידע",
+ "srf-ui-datatables-panel-disclaimer": "ניתן לשנות ×¤×¨×ž×˜×¨×™× ×•×ª× ××™×, ×ך כל שינוי ×”×•× ×–×ž× ×™ ומבוטל ל×חר רענון של הדף.",
+ "srf-ui-datatables-label-update-success": "עדכון הטבלה הצליח",
+ "srf-ui-datatables-label-update-error": "עדכון הטבלה נכשל.",
+ "srf-ui-datatables-label-placeholder-column-search": "חיפוש...",
+ "srf-ui-datatables-label-content-cache": "התוכן נגזר מתוך מטמון מקומי.",
+ "srf-ui-datatables-label-content-server": "התוכן נגזר מתוך השרת.",
+ "srf-ui-datatables-label-multiselect-column-header": "עמודות זמינות",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "הגדרות המסנן",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "עמודות גלויות",
+ "srf-ui-datatables-label-sEmptyTable": "×ין × ×ª×•× ×™× ×–×ž×™× ×™× ×‘×˜×‘×œ×”",
+ "srf-ui-datatables-label-sInfo": "×ž×•×¦×’×™× ×¢×™×•×œ×™× ×žÖ¾_START_ עד _END_ מתוך _TOTAL_",
+ "srf-ui-datatables-label-sInfoEmpty": "הצגת 0 עד 0 מתוך 0 ערכי×",
+ "srf-ui-datatables-label-sInfoFiltered": "(מסונן מתוך _MAX_ ×¢×™×•×œ×™× ×¡×”\"×›)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "להציג עיולי _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "טעינה...",
+ "srf-ui-datatables-label-sProcessing": "עיבוד...",
+ "srf-ui-datatables-label-sSearch": "חיפוש:",
+ "srf-ui-datatables-label-sZeroRecords": "×œ× × ×ž×¦×ו רשומות תו×מות",
+ "srf-ui-datatables-label-oPaginate-sFirst": "הר×שון",
+ "srf-ui-datatables-label-oPaginate-sLast": "×”×חרון",
+ "srf-ui-datatables-label-oPaginate-sNext": "הב×",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "הקוד×",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": להפעיל כדי למיין ×ת העמודה בסדר עולה",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": להפעיל כדי למיין ×ת העמודה בסדר יורד",
+ "srf-printername-tree": "×¢×¥",
+ "srf-printername-ultree": "×¢×¥ רשימה ×œ× ×ž×ž×•×¡×¤×¨×ª",
+ "srf-printername-oltree": "עץ רשימה ממוספרת",
+ "srf-tree-noparentprop": "×ין מ×פיין הורה שניתן. ×”×¢×¥ ×œ× ×™×›×•×œ להיבנות ×œ×œ× ×ž×פיין הורה שצוין.",
+ "srf-tree-rootinvalid": "$1 ××™× ×” כותרת דף תקינה.",
+ "srf-paramdesc-tree-parent": "המ×פיין שמכיל ×ת דף ההורה",
+ "srf-paramdesc-tree-root": "דף השורש של העץ",
+ "srf-paramdesc-tree-startlevel": "רמת ההתחלה של ×”×¢×¥, למשל לצורך שילוב לתוך ×¢×¥ ×חר",
+ "srf-printername-slideshow": "מצגת שקופיות",
+ "srf-paramdesc-delay": "זמן המעבר בין שקופיות בשניות",
+ "srf-paramdesc-navigation-controls": "הצג פקדי ניווט ×ו ל×",
+ "srf-paramdesc-effect": "×”×פקט למעבר בין שקופית לשקופית",
+ "srf-printername-filtered": "מסונן",
+ "srf-paramdesc-filtered-views": "התצוגות שיהיו זמינות במסך התוצ××”.",
+ "srf-paramdesc-filtered-filter-position": "×”×ž×™×§×•× ×©×œ ×”×ž×¡× × ×™× ×™×—×¡×™×ª לתצוגות. ×¢×¨×›×™× ×ž×•×ª×¨×™×: \"top\"â€, \"bottom\". בררת מחדל: \"top\".",
+ "srf-paramdesc-filtered-list-type": "סוג הרשימה. ×¢×¨×›×™× ×ž×•×ª×¨×™×: \"list\"â€, \"ul\"â€, \"ol\". בררת מחדל: \"list\".",
+ "srf-paramdesc-filtered-list-template": "התבנית שתשמש לעיצוב עיולי רשימה.",
+ "srf-paramdesc-filtered-list-named-args": "שמות ×”××¨×’×•×ž× ×˜×™× ×©×ž×•×¢×‘×¨×™× ×œ×ª×‘× ×™×ª.",
+ "srf-paramdesc-filtered-list-introtemplate": "×©× ×”×ª×‘× ×™×ª שתוצג לפני תוצ×ות בש×ילתה, ×× ×™×© ×›×לה.",
+ "srf-paramdesc-filtered-list-outrotemplate": "×©× ×”×ª×‘× ×™×ª שתוצג ×חרי תוצ×ות בש×ילתה, ×× ×™×© ×›×לה.",
+ "srf-paramdesc-filtered-calendar-start": "ההדפסה שכוללת ×ת ת×ריך תחילת ×”×ירוע",
+ "srf-paramdesc-filtered-calendar-end": "ההדפסה שכוללת ×ת ת×ריך ×¡×™×•× ×”×ירוע",
+ "srf-paramdesc-filtered-calendar-title": "ההדפסה שכוללת ×ת ×©× ×”×ירוע. ×œ× ×™×›×•×œ לשמש יחד ×¢× ×ª×‘× ×™×ª הכותרת.",
+ "srf-paramdesc-filtered-calendar-title-template": "התבנית שתשמש לעיצוב כותרת ×”×ירוע בלוח השנה",
+ "srf-paramdesc-filtered-map-height": "גובה המפה.",
+ "srf-filtered-selectorlabel-list": "רשימה",
+ "srf-filtered-selectorlabel-table": "טבלה",
+ "srf-filtered-selectorlabel-calendar": "לוח שנה",
+ "srf-filtered-selectorlabel-map": "מפה",
+ "srf-printername-d3chart": "×ª×¨×©×™× D3",
+ "srf-printername-timeseries": "×ª×¨×©×™× ×¡×“×¨×ª זמן",
+ "srf-paramdesc-group": "סדרות מקובצות לפי",
+ "srf-paramdesc-zoom": "הפעלת תקריב",
+ "srf-paramdesc-datatable": "הפעלת טבלת נתוני×",
+ "srf-timeseries-zoom-out-of-range": "טווח התקריב ×œ× ×™×™×¦×¨ × ×ª×•× ×™× ×ž×¡×¤×™×§×™×",
+ "srf-printername-sparkline": "קו ×¡×™×›×•× ×ž×’×ž×”",
+ "srf-printername-listwidget": "כלי רשימה",
+ "srf-paramdesc-listtype": "× × ×œ×”×’×“×™×¨ ×ת סוג הרשימה",
+ "srf-paramdesc-widget": "רימות זמינות",
+ "srf-paramdesc-pageitems": "×¤×¨×™×˜×™× ×‘×›×œ דף",
+ "srf-printername-eventcalendar": "יומן ×ירועי×",
+ "srf-paramdesc-calendarfirstday": "×”×™×•× ×©×‘×• מתחיל כל שבוע",
+ "srf-paramdesc-calendardefaultview": "התצוגה הר×שונה כשלוח השנה נטען",
+ "srf-paramdesc-calendarstart": "תחילת לוח השנה (×¢×¨×›×™× ×œ×ª×ריך ×ו לת×ריך ושעה)",
+ "srf-paramdesc-calendarlegend": "מגדיר ×ת ×”×ž×™×§×•× ×©×œ ×”×ž×§×¨× ×•×©×œ ×פשרויות המסנן המשויכות",
+ "srf-paramdesc-dayview": "הגדרת תצוגת ×”×™×•× × ×¢×©×™×ª ב×מצעות לחיצה על מספר היו×",
+ "srf-ui-eventcalendar-label-today": "היו×",
+ "srf-ui-eventcalendar-label-month": "חודש",
+ "srf-ui-eventcalendar-label-week": "שבוע",
+ "srf-ui-eventcalendar-label-day": "יו×",
+ "srf-ui-eventcalendar-label-allday": "כל היו×",
+ "srf-ui-eventcalendar-label-update-success": "עדכון יומן ×”××™×¨×•×¢×™× ×”×¦×œ×™×—.",
+ "srf-ui-eventcalendar-label-update-error": "עדכון ×ירוע היומן נכשל.",
+ "srf-printername-dygraphs": "×ª×¨×©×™× Dygraphs",
+ "srf-paramdesc-datasource": "המקור ×©×”× ×ª×•× ×™× × ×’×™×©×™× ×ž×ž× ×• ×¢×¨×›×™× ×ž×•×ª×¨×™×: \"file\"â€, \"raw\" ו־\"url\". בררת מחדל: \"file\"",
+ "srf-paramdesc-errorbar": "ב××™×–×” סרגל שגי××” להשתמש. ×¢×¨×›×™× ×ž×•×ª×¨×™×: \"fraction\" (טווחי ×מון לערכי×), \"sigma\" (סטיית תקן של ערכי×), ו־\"range\" (טווח ×¢×¨×›×™× ×ž×•×ª××)",
+ "srf-paramdesc-movingaverage": "הצגת הממוצע במספר ×™×ž×™× (×פס יציין ש×ין טווח × ×¢)",
+ "srf-paramdesc-yaxislabel": "תי×ור שמופיע בציר y",
+ "srf-paramdesc-xaxislabel": "תי×ור שמופיע בציר x",
+ "srf-paramdesc-unit": "יחידה",
+ "srf-printername-pagewidget": "כלי דף",
+ "srf-printername-incoming": "מ××¤×™×™× ×™× × ×›× ×¡×™×",
+ "srf-paramdesc-min": "ערך רף ×ו מינימלי",
+ "srf-paramdesc-excludeproperty": "×œ×”×•×¦×™× ×ת המ×פיין מערכת התוצ×ות",
+ "srf-printername-media": "נכנן מדיה",
+ "srf-paramdesc-mediainspector": "הצגת מידע מפורט על מרכיב מדיה מוגדר",
+ "srf-ui-mediaplayer-label-previous": "קוד×",
+ "srf-ui-mediaplayer-label-play": "לנגן",
+ "srf-ui-mediaplayer-label-pause": "להפסיק",
+ "srf-ui-mediaplayer-label-next": "הב×",
+ "srf-ui-mediaplayer-label-stop": "לעצור",
+ "srf-ui-mediaplayer-label-mute": "השתקה",
+ "srf-ui-mediaplayer-label-unmute": "ביטול השתקה",
+ "srf-ui-mediaplayer-label-volume-max": "עצמה מרבית",
+ "srf-ui-mediaplayer-label-shuffle": "סדר ×קר××™",
+ "srf-ui-mediaplayer-label-shuffle-off": "ביטול סדר ×קר××™",
+ "srf-ui-mediaplayer-label-repeat": "חזרה",
+ "srf-ui-mediaplayer-label-repeat-off": "ביטול חזרה",
+ "srf-ui-mediaplayer-label-full-screen": "מסך מל×",
+ "srf-ui-mediaplayer-label-restore-screen": "שחזור מסך"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/hi.json b/www/wiki/extensions/SemanticResultFormats/i18n/hi.json
new file mode 100644
index 00000000..fa41f556
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/hi.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kaustubh",
+ "Phoenix303"
+ ]
+ },
+ "srfc_previousmonth": "पिछला महिना",
+ "srfc_nextmonth": "अगला महिना",
+ "srfc_today": "आज़",
+ "srfc_gotomonth": "महिनेपर चलें",
+ "srf_icalendar_link": "आइकैलेंडर",
+ "srf-ui-datatables-label-information": "जानकारी"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/hsb.json b/www/wiki/extensions/SemanticResultFormats/i18n/hsb.json
new file mode 100644
index 00000000..2929c46e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/hsb.json
@@ -0,0 +1,200 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Přidatne formaty za wotprašowanja Semantic MediaWiki",
+ "prefs-srf": "Formaty semantiskich wuslědkow",
+ "srf-module-loading": "ZaÄituje so...",
+ "srf-paramdesc-layout": "K dispoziciji stejacy layout",
+ "srf-paramdesc-height": "Wysokosć (w pikselach)",
+ "srf-paramdesc-width": "Šěrokosć",
+ "srf-paramdesc-class": "Podaj přidatnu CSS-klasu",
+ "srf-module-nomatch": "Žane wotpowědniki namakane.",
+ "srf-paramdesc-charttype": "K dispoziciji diagramowy typ",
+ "srf-navigation-previous": "Předchadny",
+ "srf-ui-navigation-prev": "Wróćo",
+ "srf-ui-navigation-next": "Přichodny",
+ "srf-ui-common-label-source": "Žórło",
+ "srf-ui-common-label-datasource": "Datowe žórło",
+ "srf-ui-common-label-request-object": "Objekt wotprašować",
+ "srf-ui-common-label-help-section": "wotrězk pomocy",
+ "srf-ui-tooltip-title-options": "Nastajenja",
+ "srf-ui-tooltip-title-scope": "Wobłuk",
+ "srf-ui-common-label-parameters": "Parametry",
+ "srf-ui-common-label-query": "Naprašowanje",
+ "srf-error-option-mix": "Opcija ($1) k dispoziciji njesteji",
+ "srf-error-option-link-all": "Opcija ($1) sej wužaduje, zo so parameter \"link\" na \"all\" staji",
+ "srf-error-missing-layout": "Layout faluje",
+ "srf-warn-empy-chart": "Diagram/grafika njeda so wutworić, dokelž daty faluja",
+ "srfc_previousmonth": "Předchadny měsac",
+ "srfc_nextmonth": "Přichodny měsac",
+ "srfc_today": "Dźensa",
+ "srfc_gotomonth": "Dźi k měsacej",
+ "srf_printername_calendar": "MÄ›saÄna protyka",
+ "srf_paramdesc_calendarlang": "Kod za rÄ›Ä, w kotrejž protyka ma so zwobraznić",
+ "srf_paramdesc_calendarcolors": "Barba, kotraž dyrbi so za kóždu datumowu kajkosć zwobraznić (na pÅ™ikÅ‚ad: \"Startowy datum=>green,KónÄny datum=>#09c\")",
+ "srf_printername_vcard": "vCard eksportować",
+ "srf_printername_icalendar": "iCalendar eksportować",
+ "srf_paramdesc_icalendartitle": "Titul protykoweje dataje",
+ "srf_paramdesc_icalendardescription": "Wopisanje protykoweje dataje",
+ "srf_printername_bibtex": "BibTeX eksportować",
+ "srf_outline_novalue": "Žana hódnota",
+ "srf_printername_outline": "Kontura",
+ "srf_paramdesc_outlineproperties": "Lisćina kajkosćow, kotryž maja so jako rozrjadowanske nadpisma, přez komy dźělene",
+ "srf_printername_sum": "Suma liÄbow",
+ "srf_printername_average": "PÅ™erÄ›zk liÄbow",
+ "srf_printername_max": "Maksimalna liÄba",
+ "srf_printername_min": "Minimalna liÄba",
+ "srf_paramdesc_limit": "Maksimalna liÄba stronow za napraÅ¡owanje",
+ "srf_printername_product": "Produkt liÄbow",
+ "srf_printername_median": "Mediana hódnota liÄbow",
+ "srf-paramdesc-default": "Standardna hódnota, kotraž so zwobraznja, jeli numeriske wuslědki njejsu",
+ "srf_printername_earliest": "NajzažniÅ¡i Äasowy dypk",
+ "srf_printername_latest": "NajpozdźiÅ¡i Äasowy dypk",
+ "srf_printername_timeline": "Časowa wotběh",
+ "srf_printername_eventline": "Wotběh podawkow",
+ "srf_paramdesc_timelinebands": "Definuje, kotre smuhi so we wuslědku zwobraznjeja.",
+ "srf_paramdesc_timelineposition": "Definuje, hdźež Äasowa linija na spoÄatku ma swój fokus.",
+ "srf_paramdesc_timelinestart": "Mjeno atributa, kotrež so wužiwa, zo by prÄ›ni Äasowy dypk definowaÅ‚o",
+ "srf_paramdesc_timelineend": "Mjeno atributa, kotrež so wužiwa, zo by druhi Äasowy dypk definowaÅ‚o",
+ "srf_paramdesc_timelinesize": "Wysokosć Äasoweje linije",
+ "srf-timeline-allresults": "Dalše wuslědki za tute naprašowanje.",
+ "srf-timeline-nojs": "DyrbiÅ¡ JavaScript aktiwizować, zo by sej interaktiwnu Äasowu wósku wobhladaÅ‚.",
+ "srf_paramdesc_views": "Napohlady, kotrež maja so zwobraznić",
+ "srf_paramdesc_facets": "Sadźba atributow, kotrež maja so za kóždu stronu zwobraznić",
+ "srf_paramdesc_lens": "Mjeno předłohi, z kotrejž atributy strony maja so zwobraznić",
+ "srf_printername_googlebar": "Google hrjadowy diagram",
+ "srf_printername_googlepie": "Google tortowy diagram",
+ "srf-printername-jqplotchart": "jqPlot-diagram",
+ "srf-printername-jqplotseries": "jqPlot-rjady",
+ "srf_paramdesc_chartheight": "Podaj wysokosć diagrama abo grafiki (w pikselach)",
+ "srf_paramdesc_chartwidth": "Podaj šěrokosć diagrama abo grafiki (w pikselach abo procentach)",
+ "srf_paramdesc_charttitle": "Titul diagrama",
+ "srf_paramdesc_barcolor": "Barba hrjadow/stołpow",
+ "srf_paramdesc_bardirection": "Směr diagrama podać",
+ "srf-paramdesc-direction": "Podaj směr diagrama abo grafiki",
+ "srf_paramdesc_barnumbersaxislabel": "Popisanje y-wóski",
+ "srf-paramdesc-labelaxislabel": "Popisanje y-wóski",
+ "srf-paramdesc-minvalue": "Minimalna hódnota, kotraž ma so na Y-wósce pokazać",
+ "srf-paramdesc-pointlabels": "Dypki diagramowych datow zwobraznić",
+ "srf-paramdesc-chartlegend": "Pozicija diagramoweje legendy",
+ "srf-paramdesc-datalabels": "Popisy za diagramy a grafiki",
+ "srf-paramdesc-charttext": "Wopisowacy diagramowy tekst",
+ "srf-paramdesc-chartclass": "Přidatna CSS-klasa",
+ "srf-paramdesc-renderer": "Program za rysowanje grafiki/diagrama wubrać",
+ "srf-paramdesc-filling": "Indiwiduelna pjelnjenska opcija",
+ "srf-paramdesc-theme": "LÄ›syÄnu drastu wubrać",
+ "srf-paramdesc-chartcolor": "Jednotliwe diagramowe barby připokazać",
+ "srf-paramdesc-colorscheme": "Barbowu šemu wubrać",
+ "srf-paramdesc-valueformat": "Formatowanske prawidło za hódnoty podać",
+ "srf-paramdesc-highlighter": "Wuzběhnjenje datowych dypkow zwobraznić",
+ "srf-paramdesc-smoothlines": "Algoritmus za wupłonjenje na linijowych diagramach nałožić",
+ "srf-paramdesc-stackseries": "Diagram jako worštowane rjady zwobraznić",
+ "srf-paramdesc-seriesgroup": "Grupěrowanje rjadow wubrać",
+ "srf-paramdesc-serieslabel": "Popis rjadow zwěsćić",
+ "srf-paramdesc-chartcursor": "Opcija za zwobraznjenje kursora w diagramje",
+ "srf-paramdesc-gridview": "Diagram a datowe sadźby simultanje zwobraznić. Dowolene hódnoty: ''none'' a ''tabs''. Standard: ''none''",
+ "srf-paramdesc-infotext": "Přidatne informacije na wotpowědowacym rajtarku Info zwobraznić",
+ "srf-ui-gridview-label-item": "Datowy element",
+ "srf-ui-gridview-label-value": "Datowa hódnota",
+ "srf-ui-gridview-label-series": "Datowe rjady",
+ "srf-ui-gridview-label-chart-tab": "Diagram",
+ "srf-ui-gridview-label-data-tab": "Daty",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galerija",
+ "srf_paramdesc_perrow": "LiÄba wobrazow na rjadku",
+ "srf_paramdesc_widths": "Šěrokosć wobrazow",
+ "srf_paramdesc_heights": "Wysokosć wobrazow",
+ "srf_paramdesc_autocaptions": "Datajowe mjeno jako wobrazowe wopisanje wužiwać, jeli tajke njeje podate.",
+ "srf_paramdesc_fileextensions": "Jeli so datajowe mjeno jako wopisanje wužiwa, tež datajowu kóncowku pokazać",
+ "srf_paramdesc_captionproperty": "Mjeno semantiskeje kajkosće na naprašowanych stronach, kotrež ma so jako wopisanje wužiwać",
+ "srf-paramdesc-navigation": "Nawigaciske wodźenje za layout",
+ "srf-gallery-navigation-previous": "Předchadny",
+ "srf-gallery-navigation-next": "Přichodny",
+ "srf-gallery-overlay-count": "Wobraz $1 z $2",
+ "srf-gallery-image-url-error": "Wobraz njeje so namakał.",
+ "srf_printername_tagcloud": "TafliÄkowa mróÄel",
+ "srf_paramdesc_includesubject": "HaÄ mjena temow same maja so zapÅ™ijeć",
+ "srf_paramdesc_increase": "Kak woznamjenjace słowa powjetšić",
+ "srf_paramdesc_tagorder": "Porjad woznamjenjacych słowow",
+ "srf_paramdesc_mincount": "Maksimalna liÄba razow, katraž hódnota dyrbi so jewić, zo by so nalistowaÅ‚a",
+ "srf_paramdesc_minsize": "Wulkosć najmjeńšich woznamjenjacych słowow w procenće",
+ "srf_paramdesc_maxsize": "Wulkosć najwjetšich woznamjenjacych słowow w procenće",
+ "srf_paramdesc_maxtags": "Maksimalna liÄba woznamjenjacych sÅ‚owow w mróÄeli",
+ "srf_printername_valuerank": "Hódnota",
+ "srf_printername_array": "Datowe polo",
+ "srf_paramdesc_pagetitle": "Postaja, haÄ titule stronow maja so jako wuslÄ›dkowe zapiski pokazać abo so wuwostajić",
+ "srf_paramdesc_propsep": "Dźělatko mjez požadanymi kajkosćemi",
+ "srf_paramdesc_manysep": "Dźělatko mjez wjacorymi kajkostnymi hódnotami kajkosće",
+ "srf_paramdesc_recordsep": "Dźělatko mjez hódnotami kajkosćow datoweje sadźby",
+ "srf_paramdesc_headersep": "Dźělatko mjez kajkostnym mjenom a kajkostnej hódnotu, jeli parameter \"header\" je so na \"show\" abo \"plain\" stajił",
+ "srf_printername_hash": "Asociatiwne datowe polo (hash)",
+ "srf-printername-graph": "Grafika",
+ "srf-paramdesc-graph-relation": "Su temy abo mjenowe kajkosće nadrjadowane abo podrjadowane elementy?",
+ "srf-paramdesc-graph-nameprop": "Zmóžnja kajkosć stajić, kotraž so jako tema wužiwa, město poprawneje temy",
+ "srf-paramdesc-graph-nodeshape": "Forma kóždeho suka na grafice",
+ "srf-paramdesc-graphname": "Titul",
+ "srf-paramdesc-graphsize": "Wulkosć grafiki (w pikselach)",
+ "srf-paramdesc-graphlegend": "Legendu grafiki pokazać abo nic",
+ "srf-paramdesc-graphlabel": "Popis grafiki",
+ "srf-paramdesc-rankdir": "Šipowy směr",
+ "srf-paramdesc-graphlink": "Wotkaz ke grafice",
+ "srf-paramdesc-graphcolor": "Barba grafiki",
+ "srf-paramdesc-graph-wwl": "Limit za tekstowe Å‚amanje (liÄba znamjeÅ¡kow)",
+ "srf-printername-datatables": "Datowe tabele",
+ "srf-ui-datatables-label-conditions": "Wuměnjenja",
+ "srf-ui-datatables-label-parameters": "Parametry",
+ "srf-ui-datatables-label-information": "Informacije",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filtrowe nastajenja",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-printername-tree": "Å tom",
+ "srf-printername-ultree": "Å tomowy napohlad (naliÄeny)",
+ "srf-printername-oltree": "Å tomowy napohlad (ÄisÅ‚owany)",
+ "srf-tree-noparentprop": "Nadrjadowana kajkosć njeje podała. Štom njeda so bjez podateje nadrjadowaneje kajkosće twarić.",
+ "srf-tree-rootinvalid": "$1 płaćiwy titul strony njeje.",
+ "srf-paramdesc-tree-parent": "Kajkosć, kotraž nadrjadowanu stronu wobsahuje",
+ "srf-printername-slideshow": "Wobrazowe předstajenje",
+ "srf-paramdesc-delay": "Komdźenje mjez wobrazami w sekundach",
+ "srf-paramdesc-navigation-controls": "Nawigaciske elementy pokazać abo nic",
+ "srf-paramdesc-effect": "Efekt, kotryž ma so wužiwać, zo by wot wobraza do wobraza přešło",
+ "srf-printername-filtered": "Filtrowany",
+ "srf-paramdesc-filtered-list-type": "Typ lisćiny. Dowolene hódnoty: ''list'', ''ul'', ''ol''. Standard: ''list''.",
+ "srf-filtered-selectorlabel-list": "Lisćina",
+ "srf-filtered-selectorlabel-calendar": "Protyka",
+ "srf-printername-d3chart": "D3-diagram",
+ "srf-printername-timeseries": "Diagram Äasowych rjadow",
+ "srf-paramdesc-group": "Rjady zeskupjene po",
+ "srf-paramdesc-zoom": "Skalowanje zmóžnić",
+ "srf-paramdesc-datatable": "Datowu tabelu zmóžnić",
+ "srf-timeseries-zoom-out-of-range": "Skalowanski wobłuk dosć datow njepłodźi",
+ "srf-printername-sparkline": "Diagram słownych grafikow",
+ "srf-printername-listwidget": "Lisćinowy asistent",
+ "srf-paramdesc-listtype": "Podaj lisćinowy typ",
+ "srf-paramdesc-widget": "K dispoziciji stejacy asistent",
+ "srf-paramdesc-pageitems": "Elementy na stronu",
+ "srf-printername-eventcalendar": "Zarjadowanska protyka",
+ "srf-paramdesc-calendarfirstday": "DźeÅ„, hdyž kóždy tydźeÅ„ so zapoÄina",
+ "srf-paramdesc-calendardefaultview": "Wuchadny napohlad, hdyž so protyka startuje",
+ "srf-paramdesc-calendarstart": "SpoÄatny datum protyki (datumowe a Äasowe hódnoty)",
+ "srf-paramdesc-dayview": "Dnjowy napohlad pÅ™ez kliknjenje na dnjowe ÄisÅ‚o zmóžnić",
+ "srf-ui-eventcalendar-label-today": "Dźensa",
+ "srf-ui-eventcalendar-label-month": "Měsac",
+ "srf-ui-eventcalendar-label-week": "Tydźeń",
+ "srf-ui-eventcalendar-label-day": "Dźeń",
+ "srf-ui-eventcalendar-label-allday": "Cyły dźeń",
+ "srf-printername-dygraphs": "Digrafowy diagram",
+ "srf-paramdesc-datasource": "Žórło, z kotrehož maja přistup na daty. Dowolene hódnoty: ''file'', ''raw'' a ''url''. Standard: ''file''",
+ "srf-paramdesc-yaxislabel": "Wopisanje, kotrež so na y-wósce jewi",
+ "srf-paramdesc-xaxislabel": "Wopisanje, kotrež so na x-wósce jewi",
+ "srf-paramdesc-unit": "Jednotka",
+ "srf-printername-pagewidget": "Asistent strony",
+ "srf-printername-incoming": "Dochadźace kajkosće",
+ "srf-paramdesc-min": "Minimum abo ekstremna hódnota",
+ "srf-paramdesc-excludeproperty": "Kajkosć z wuslědka wuzamknyć",
+ "srf-ui-mediaplayer-label-play": "Wothrać",
+ "srf-ui-mediaplayer-label-repeat": "Wospjetować",
+ "srf-ui-mediaplayer-label-full-screen": "Połna wobrazowka"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ht.json b/www/wiki/extensions/SemanticResultFormats/i18n/ht.json
new file mode 100644
index 00000000..76d331ff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ht.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jvm",
+ "Masterches"
+ ]
+ },
+ "srf_icalendar_link": "iKalandrye"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/hu.json b/www/wiki/extensions/SemanticResultFormats/i18n/hu.json
new file mode 100644
index 00000000..d86c56d8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/hu.json
@@ -0,0 +1,121 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dani",
+ "Dj",
+ "Glanthor Reviol",
+ "TK-999",
+ "Csega",
+ "Misibacsi",
+ "Tacsipacsi"
+ ]
+ },
+ "srf-desc": "További formátumok a Szemantikus MediaWiki beépített lekérdezéseihez",
+ "srf-module-loading": "Betöltés…",
+ "srf-paramdesc-height": "Magasság",
+ "srf-paramdesc-width": "Szélesség",
+ "srf-paramdesc-class": "Extra CSS osztály megadása",
+ "srfc_previousmonth": "Előző hónap",
+ "srfc_nextmonth": "Következő hónap",
+ "srfc_today": "Ma",
+ "srfc_gotomonth": "Ugrás hónapra",
+ "srf_printername_calendar": "Havi naptár",
+ "srf_paramdesc_calendarlang": "A naptár megjelenítési nyelvének kódja",
+ "srf_paramdesc_calendarcolors": "Az egyes dátumtulajdonságok megjelenítendő színe (például \"Kezdő dátum=>green,Végpont=>#09c\")",
+ "srf_printername_vcard": "vCard exportálás",
+ "srf_printername_icalendar": "iCalendar exportálás",
+ "srf_paramdesc_icalendartitle": "A naptárfájl címe",
+ "srf_paramdesc_icalendardescription": "A naptárfájl leírása",
+ "srf_printername_bibtex": "BibTeX exportálás",
+ "srf_outline_novalue": "Nincs érték",
+ "srf_printername_outline": "Tagolt",
+ "srf_printername_sum": "A számok összege",
+ "srf_printername_average": "A számok átlaga",
+ "srf_printername_max": "Legnagyobb szám",
+ "srf_printername_min": "Legkisebb szám",
+ "srf_paramdesc_limit": "A lekérdezendő oldalak maximális száma",
+ "srf_printername_median": "Számhalmaz mediánja",
+ "srf-paramdesc-default": "A numerikus eredmények hiánya esetén megjelenítendő alapérték",
+ "srf_printername_earliest": "Legkorábbi időpont",
+ "srf_printername_latest": "Legkésőbbi időpont",
+ "srf_printername_timeline": "Idővonal",
+ "srf_printername_eventline": "Eseményvonal",
+ "srf_paramdesc_timelinesize": "Az idővonal magassága",
+ "srf-timeline-allresults": "A lekérdezés további eredményei.",
+ "srf-timeline-nojs": "Engedélyezned kell a Javascript használatát az interaktív idővonal megtekintéséhez.",
+ "srf_paramdesc_views": "Megjelenített nézetek",
+ "srf_paramdesc_facets": "Az oldalanként megjelenítendő tulajdonságok halmaza",
+ "srf_paramdesc_lens": "Az oldal tulajdonságait megjelenítő sablon neve",
+ "srf_printername_googlebar": "Google oszlopdiagram",
+ "srf_printername_googlepie": "Google tortadiagram",
+ "srf_paramdesc_chartheight": "Add meg a diagram vagy a grafikon magasságát pixelben",
+ "srf_paramdesc_chartwidth": "Add meg a diagram vagy a grafikon szélességét pixelben",
+ "srf_paramdesc_charttitle": "A diagram címe",
+ "srf_paramdesc_barcolor": "Az oszlopok színe",
+ "srf_paramdesc_bardirection": "Add meg a diagram irányát",
+ "srf-paramdesc-direction": "Add meg a diagram vagy a grafikon irányát",
+ "srf_paramdesc_barnumbersaxislabel": "A számtengely felirata",
+ "srf-paramdesc-labelaxislabel": "A vízszintes tengely felirata",
+ "srf-paramdesc-minvalue": "Az y tengelyen megjelenítendő legkisebb érték",
+ "srf-paramdesc-pointlabels": "Adatpontok megjelenítése a diagramban",
+ "srf-paramdesc-chartlegend": "Diagram jelmagyarázatának helyzete",
+ "srf-paramdesc-datalabels": "Diagram/grafikon feliratok",
+ "srf-paramdesc-charttext": "A diagramot leíró szöveg",
+ "srf-paramdesc-chartclass": "Extra CSS osztály",
+ "srf-paramdesc-renderer": "Válasszd ki a gradikon/diagram leképezőjét",
+ "srf-paramdesc-filling": "Egyéni töltési beállítás",
+ "srf-paramdesc-theme": "Válassz egy rácsstílust",
+ "srf-paramdesc-chartcolor": "Egyéni grafikonszínek hozzárendelése",
+ "srf-paramdesc-colorscheme": "Válassz egy színsémát",
+ "srf-paramdesc-valueformat": "Add meg az értékek formázási szabályát",
+ "srf-paramdesc-highlighter": "Adatpont-kiemelő megjelenítése",
+ "srf-paramdesc-smoothlines": "Simító algoritmus alkalmazása a vonaldiagramokon",
+ "srf-paramdesc-stackseries": "Diagram megjelenítése halmozott adatsorként",
+ "srf-paramdesc-seriesgroup": "Válaszd ki az adatsor csoportosítását",
+ "srf-paramdesc-serieslabel": "Határozd meg az adatsor feliratát",
+ "srf-paramdesc-grouplabel": "Határozd meg a csoport cimkét",
+ "srf_printername_gallery": "Galéria",
+ "srf_paramdesc_perrow": "A képek száma soronként",
+ "srf_paramdesc_widths": "A képek szélessége",
+ "srf_paramdesc_heights": "A képek magassága",
+ "srf_paramdesc_autocaptions": "Fájlnév használata képaláírásként, ha az nincs megadva",
+ "srf_paramdesc_fileextensions": "A kiterjesztés megjelenítése a fájlnév képaláírásként történő használatakor",
+ "srf_paramdesc_captionproperty": "A képaláírásként használandó, a lekérdezett oldalakon megtalálható szemantikai tulajdonság neve",
+ "srf_paramdesc_imageproperty": "A használandó képekre mutató, a lekérdezett oldalakon megtalálható szemantikai tulajdonság neve. Ha be van állítva, maguk a lekérdezett oldalak nem képekként fognak megjelenni",
+ "srf-paramdesc-navigation": "Navigáció",
+ "srf-gallery-navigation-previous": "Előző",
+ "srf-gallery-navigation-next": "Következő",
+ "srf_printername_tagcloud": "Címkefelhő",
+ "srf_paramdesc_increase": "A címkék méretének növeléséhez használandó mód",
+ "srf_paramdesc_tagorder": "A címkék sorrendje",
+ "srf_paramdesc_mincount": "Az érték megjelenítéshez szükséges előfordulások minimuma",
+ "srf_paramdesc_minsize": "A legkisebb címkék mérete százalékban",
+ "srf_paramdesc_maxsize": "A legnagyobb címkék mérete százalékban",
+ "srf_paramdesc_maxtags": "A felhőben lévő címkék maximális mennyisége",
+ "srf-paramdesc-excludetags": "Címkenevek kizárása (elválasztójel: \";\")",
+ "srf_printername_array": "Tömb",
+ "srf_paramdesc_pagetitle": "Megjelenítse-e az oldalcímeket eredményekként, vagy hagyja ki őket?",
+ "srf_paramdesc_propsep": "A kért tulajdonságok közötti elválasztó",
+ "srf_paramdesc_headersep": "A tulajdonság neve és értéke közti elválasztó, ha a \"headers\" paraméter \"show\" vagy \"plain\" értékű",
+ "srf_printername_hash": "Hash",
+ "srf-printername-graph": "Grafikon",
+ "srf-paramdesc-graphname": "Cím",
+ "srf-paramdesc-graphsize": "Grafikon mérete (pixelben)",
+ "srf-paramdesc-graphlegend": "Jelmagyarázat megjelenítése vagy sem",
+ "srf-paramdesc-graphlabel": "Grafikon címkéje",
+ "srf-paramdesc-rankdir": "Nyíl iránya",
+ "srf-paramdesc-graphlink": "Grafikon linkje",
+ "srf-paramdesc-graphcolor": "Grafikon színe",
+ "srf-paramdesc-graph-wwl": "Sortörési határ (karakterszám)",
+ "srf-ui-datatables-label-placeholder-column-search": "Keresés...",
+ "srf-ui-datatables-label-sLoadingRecords": "Betöltés...",
+ "srf-ui-datatables-label-sProcessing": "Feldolgozás...",
+ "srf-ui-eventcalendar-label-today": "Ma",
+ "srf-ui-eventcalendar-label-month": "Hónap",
+ "srf-ui-eventcalendar-label-week": "Hét",
+ "srf-ui-eventcalendar-label-day": "Nap",
+ "srf-ui-eventcalendar-label-allday": "Egész nap",
+ "srf-ui-eventcalendar-click-popup": "Szeretnél létrehozni egy eseményt?",
+ "srf-printername-dygraphs": "Diagram ábra",
+ "srf-printername-incoming": "Bejövő tulajdonságok"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ia.json b/www/wiki/extensions/SemanticResultFormats/i18n/ia.json
new file mode 100644
index 00000000..3e83dc8b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ia.json
@@ -0,0 +1,131 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Additional formatos de resultato pro consultas de Semantic MediaWiki",
+ "srf-paramdesc-height": "Altitude",
+ "srf-paramdesc-width": "Latitude",
+ "srf-paramdesc-class": "Specifica un classe de stilos in cascada (CSS) additional",
+ "srf-error-option-mix": "Le option ($1) non es disponibile",
+ "srf-error-option-link-all": "Le option ($1) require que le parametro \"link\" es definite como \"all\"",
+ "srf-warn-empy-chart": "Le diagramma o graphico es vacue a causa de datos mancante",
+ "srfc_previousmonth": "Mense precedente",
+ "srfc_nextmonth": "Mense sequente",
+ "srfc_today": "Hodie",
+ "srfc_gotomonth": "Ir al mense",
+ "srf_printername_calendar": "Calendario mensual",
+ "srf_paramdesc_calendarlang": "Le codice del lingua in le qual monstrar le calendario",
+ "srf_paramdesc_calendarcolors": "Le color pro cata proprietate de data (exemplo: \"Data de initio=>green,Data de fin=>#09c\")",
+ "srf_printername_vcard": "Exportation in vCard",
+ "srf_printername_icalendar": "Exportation in iCalendar",
+ "srf_paramdesc_icalendartitle": "Le titulo del file del calendario",
+ "srf_paramdesc_icalendardescription": "Le description del file del calendario",
+ "srf_printername_bibtex": "Exportation in BibTeX",
+ "srf_outline_novalue": "Nulle valor",
+ "srf_printername_outline": "Schizzo",
+ "srf_paramdesc_outlineproperties": "Le lista de proprietates a presentar como capites de structura, separate per commas",
+ "srf_printername_sum": "Total del numeros",
+ "srf_printername_average": "Media del numeros",
+ "srf_printername_max": "Numero maxime",
+ "srf_printername_min": "Numero minime",
+ "srf_paramdesc_limit": "Le numero maxime de paginas a consultar",
+ "srf_printername_product": "Producto de numeros",
+ "srf_printername_median": "Mediana de numeros",
+ "srf-paramdesc-default": "Valor predefinite que es monstrate si il non ha resultatos numeric",
+ "srf_printername_earliest": "Prime hora",
+ "srf_printername_latest": "Ultime hora",
+ "srf_printername_timeline": "Chronologia",
+ "srf_printername_eventline": "Chronologia de eventos",
+ "srf_paramdesc_timelinebands": "Defini qual bandas es monstrate in le resultato.",
+ "srf_paramdesc_timelineposition": "Defini ubi le chronologia se concentra initialmente.",
+ "srf_paramdesc_timelinestart": "Un nomine de proprietate usate pro definir un prime puncto de tempore",
+ "srf_paramdesc_timelineend": "Un nomine de proprietate usate pro definir un secunde puncto de tempore",
+ "srf_paramdesc_timelinesize": "Le altitude del chronologia",
+ "srf-timeline-allresults": "Ulterior resultatos de iste consulta.",
+ "srf-timeline-nojs": "Es necessari activar JavaScript pro vider le chronologia interactive.",
+ "srf_paramdesc_views": "Le vistas a monstrar",
+ "srf_paramdesc_facets": "Le insimul de proprietates a monstrar pro cata pagina",
+ "srf_paramdesc_lens": "Le nomine de un patrono con le qual monstrar le proprietates de pagina",
+ "srf_printername_googlebar": "Diagramma a barras de Google",
+ "srf_printername_googlepie": "Diagramma circular de Google",
+ "srf_paramdesc_chartheight": "Le altitude (in pixels) de un diagramma o graphico",
+ "srf_paramdesc_chartwidth": "Le latitude (in pixels o percentage) de un diagramma o graphico",
+ "srf_paramdesc_charttitle": "Le titulo del diagramma",
+ "srf_paramdesc_barcolor": "Le color del barras",
+ "srf_paramdesc_bardirection": "Specifica le direction de un graphico",
+ "srf_paramdesc_barnumbersaxislabel": "Le etiquetta pro le axe de numeros",
+ "srf-paramdesc-minvalue": "Le valor minime a monstrar sur le axe Y",
+ "srf-paramdesc-pointlabels": "Presentar punctos de datos in graphico",
+ "srf-paramdesc-chartlegend": "Position del legenda del gaphico",
+ "srf-paramdesc-datalabels": "Etiquettas de datos in graphico",
+ "srf-paramdesc-charttext": "Texto descriptive del graphico",
+ "srf-paramdesc-chartclass": "Classe CSS additional",
+ "srf-paramdesc-renderer": "Selige un motor de rendition de graphicos",
+ "srf-paramdesc-filling": "Option de plenamento individual",
+ "srf-paramdesc-theme": "Selige un apparentia pro le grillia",
+ "srf-paramdesc-chartcolor": "Assignar individual colores al graphico",
+ "srf-paramdesc-colorscheme": "Selige un schema de colores",
+ "srf-paramdesc-valueformat": "Specifica le regula de formatation pro le valores",
+ "srf-paramdesc-highlighter": "Presentar un colorator de punctos de datos",
+ "srf-paramdesc-smoothlines": "Applicar un algorithmo de lisiamento sur graphicos a lineas",
+ "srf-paramdesc-stackseries": "Presentar graphico como serie accumulate",
+ "srf-paramdesc-seriesgroup": "Selige aggruppamento de serie",
+ "srf-paramdesc-serieslabel": "Determinar le etiquetta de serie",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_perrow": "Le numero de imagines per linea",
+ "srf_paramdesc_widths": "Le latitude del imagines",
+ "srf_paramdesc_heights": "Le altitude del imagines",
+ "srf_paramdesc_autocaptions": "Usar le nomine de file qua legenda si nulle es fornite",
+ "srf_paramdesc_fileextensions": "Si le nomine de file es usate como legenda, monstrar tamben le extension",
+ "srf_paramdesc_captionproperty": "Le nomine de un proprietate semantic presente in le paginas consultate, pro esser usate como legenda",
+ "srf_paramdesc_imageproperty": "Le nomine de un proprietate semantic presente in le paginas consultate, que indica imagines a usar. Si definite, le paginas consultate illos mesme non essera monstrate como imagines.",
+ "srf-paramdesc-navigation": "Controlo pro navigation de disposition",
+ "srf-gallery-navigation-previous": "Precedente",
+ "srf-gallery-navigation-next": "Sequente",
+ "srf_printername_tagcloud": "Etiquettario",
+ "srf_paramdesc_includesubject": "Si le nomines del subjectos mesme debe esser includite",
+ "srf_paramdesc_increase": "Como augmentar le dimension de etiquettas",
+ "srf_paramdesc_tagorder": "Le ordine del etiquettas",
+ "srf_paramdesc_mincount": "Le numero minime de vices que un valor debe occurrer pro esser listate",
+ "srf_paramdesc_minsize": "Le dimension del etiquettas le plus parve, como percentage",
+ "srf_paramdesc_maxsize": "Le dimension del etiquettas le plus grande como percentage",
+ "srf_paramdesc_maxtags": "Le numero maxime de etiquettas in le nube",
+ "srf-paramdesc-excludetags": "Excluder etiquettas (delimitator: \";\")",
+ "srf_printername_valuerank": "Valor del rango",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Si monstrar titulos de pagina como lineas de resultato o omitter los",
+ "srf_paramdesc_hidegaps": "Si monstrar, con separatores, le valores de proprietate e de registro requestate ma indisponibile, o omitter los",
+ "srf_paramdesc_arrayname": "Si isto es specificate e ArrayExtension es disponibile, isto creara un array con le nomine specificate (sin producer un resultato visibile)",
+ "srf_paramdesc_propsep": "Separator inter le proprietates requestate",
+ "srf_paramdesc_manysep": "Separator inter valores de proprietate plurivalor",
+ "srf_paramdesc_recordsep": "Separator inter valores de proprietates de registro",
+ "srf_paramdesc_headersep": "Separator inter nomine e valor de proprietate si \"headers\" es mittite a \"show\" o \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Si isto es specificate e le extension HashTables es disponibile, isto creara un hash con le nomine specificate (sin producer un resultato visibile)",
+ "srf-printername-graph": "Graphico",
+ "srf-paramdesc-graph-relation": "Indica si le subjectos o proprietates de nomines es genitores o infantes",
+ "srf-paramdesc-graph-nameprop": "Defini le proprietate que essera usate como subjecto in loco del ver subjecto, i.e. le nomine del pagina",
+ "srf-paramdesc-graph-nodeshape": "Defini le forma de cata nodo in le graphico",
+ "srf-paramdesc-graphname": "Defini le titulo del graphico",
+ "srf-paramdesc-graphsize": "Defini le dimension del graphico in pixels",
+ "srf-paramdesc-graphlegend": "Indica si le legenda del graphico debe esser monstrate",
+ "srf-paramdesc-graphlabel": "Defini le etiquetta del graphico",
+ "srf-paramdesc-rankdir": "Defini le direction del sagittas",
+ "srf-paramdesc-graphlink": "Indica si le nodos debe ligar a lor paginas wiki",
+ "srf-paramdesc-graphcolor": "Defini le color del graphico",
+ "srf-paramdesc-graph-wwl": "Defini le limite pro torno de parolas (in numero de characteres)",
+ "srf-printername-datatables": "Tabellas de datos",
+ "srf-printername-tree": "Arbore",
+ "srf-printername-ultree": "Arbore UL",
+ "srf-printername-oltree": "Arbore OL",
+ "srf-tree-noparentprop": "Nulle proprietate genitor specificate. Le arbore non pote esser construite sin specification de un proprietate genitor.",
+ "srf-paramdesc-tree-parent": "Le proprietate que contine le pagina genitor",
+ "srf-printername-slideshow": "Presentation de diapositivas",
+ "srf-paramdesc-delay": "Tempore inter diapositivas in secundas",
+ "srf-paramdesc-navigation-controls": "Monstrar controlos de navigation o non",
+ "srf-paramdesc-effect": "Le effecto a usar pro cambiar inter diapositivas",
+ "srf-printername-filtered": "Filtrate"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/id.json b/www/wiki/extensions/SemanticResultFormats/i18n/id.json
new file mode 100644
index 00000000..fcc8b000
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/id.json
@@ -0,0 +1,93 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bennylin",
+ "Farras",
+ "IvanLanin",
+ "Kenrick95",
+ "පසිඳු කà·à·€à·’න්ද"
+ ]
+ },
+ "srf-desc": "Format tambahan untuk kueri Semantik MediaWiki",
+ "srf-name": "Format Hasil Semantik",
+ "srf-navigation-previous": "Sebelumnya",
+ "srf-ui-common-label-source": "Sumber",
+ "srfc_previousmonth": "Bulan lalu",
+ "srfc_nextmonth": "Bulan depan",
+ "srfc_today": "Hari ini",
+ "srfc_gotomonth": "Pergi ke bulan",
+ "srf_printername_calendar": "Kalender bulanan",
+ "srf_paramdesc_calendarlang": "Kode untuk bahasa yang digunakan untuk menampilkan kalender",
+ "srf_printername_vcard": "Ekspor vCard",
+ "srf_printername_icalendar": "Ekspor iCalendar",
+ "srf_paramdesc_icalendartitle": "Judul berkas kalender",
+ "srf_paramdesc_icalendardescription": "Deskripsi berkas kalender",
+ "srf_printername_bibtex": "Ekspor BibTeX",
+ "srf_outline_novalue": "Tanpa nilai",
+ "srf_printername_outline": "Ikhtisar",
+ "srf_paramdesc_outlineproperties": "Daftar properti yang akan ditampilkan sebagai kepala luar, dipisah oleh koma",
+ "srf_printername_sum": "Jumlah angka",
+ "srf_printername_average": "Angka rata-rata",
+ "srf_printername_max": "Angka maksimum",
+ "srf_printername_min": "Angka minimum",
+ "srf_paramdesc_limit": "Jumlah maksimal halaman yang dicari",
+ "srf_printername_timeline": "Garis waktu",
+ "srf_printername_eventline": "Garis kejadian",
+ "srf_paramdesc_timelinebands": "Menetapkan tanda yang mana yang ditampilkan di hasil.",
+ "srf_paramdesc_timelineposition": "Menetapkan tempat fokus awal garis waktu.",
+ "srf_paramdesc_timelinestart": "Nama properti untuk menetapkan titik waktu pertama",
+ "srf_paramdesc_timelineend": "Nama properti untuk menetapkan titik waktu kedua",
+ "srf_paramdesc_timelinesize": "Tinggi garis waktu",
+ "srf_paramdesc_views": "Pandangan yang akan ditampilkan",
+ "srf_paramdesc_facets": "Rangkaian properti untuk ditampilkan di setiap halaman",
+ "srf_paramdesc_lens": "Nama templat untuk menampilkan properti halaman",
+ "srf_printername_googlebar": "Grafik batang Google",
+ "srf_printername_googlepie": "Grafik pai Google",
+ "srf_paramdesc_chartheight": "Tinggi grafik, dalam piksel",
+ "srf_paramdesc_chartwidth": "Lebar grafik, dalam piksel",
+ "srf_paramdesc_charttitle": "Judul grafik",
+ "srf_paramdesc_barcolor": "Warna batang",
+ "srf_paramdesc_bardirection": "Arah grafik batang",
+ "srf_paramdesc_barnumbersaxislabel": "Label untuk poros nomor",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf_printername_gallery": "Galeri",
+ "srf_paramdesc_perrow": "Jumlah gambar per baris",
+ "srf_paramdesc_widths": "Lebar gambar",
+ "srf_paramdesc_heights": "Tinggi gambar",
+ "srf_paramdesc_autocaptions": "Gunakan nama berkas sebagai judul jika judul tidak diberikan",
+ "srf-gallery-navigation-previous": "Sebelumnya",
+ "srf_printername_tagcloud": "Awan tag",
+ "srf_paramdesc_includesubject": "Jika nama subjek sendiri harus dimasukkan",
+ "srf_paramdesc_increase": "Bagaimana meningkatkan ukuran tag",
+ "srf_paramdesc_tagorder": "Urutan tag",
+ "srf_paramdesc_mincount": "Jumlah minimum kemunculan suatu nilai untuk dapat didaftarkan",
+ "srf_paramdesc_minsize": "Ukuran tag terkecil dalam persen",
+ "srf_paramdesc_maxsize": "Ukuran tag terbesar dalam persen",
+ "srf_paramdesc_maxtags": "Jumlah maksimum tag di awan",
+ "srf_printername_array": "Larik",
+ "srf_paramdesc_pagetitle": "Tampilkan atau sembunyikan judul halaman sebagai entri hasil",
+ "srf_paramdesc_hidegaps": "Tampilkan atau sembunyikan nilai properti dan rekaman yang kosong, dipisahkan dengan pemisah",
+ "srf_paramdesc_arrayname": "Jika diberikan dan ArrayExtension tersedia, parameter ini akan membuat larik dengan nama yang diberikan",
+ "srf_paramdesc_propsep": "Pemisah antara properti yang diminta",
+ "srf_paramdesc_manysep": "Pemisah antara banyak properti bernilai",
+ "srf_paramdesc_recordsep": "Pemisah antara nilai properti rekaman",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Jika diberikan dan ekstensi HashTables tersedia, parameter ini akan membuat hash dengan nama yang diberikan",
+ "srf-printername-graph": "Grafik",
+ "srf-paramdesc-graph-relation": "Apakah subjek atau properti nama merupakan induk atau turunan?",
+ "srf-paramdesc-graph-nameprop": "Memungkinkan pengaturan properti yang akan digunakan sebagai subjek, alih-alih subjek yang sebenarnya",
+ "srf-paramdesc-graph-nodeshape": "Bentuk masing-masing nodus (node) pada grafik",
+ "srf_paramdesc_graphname": "Judul",
+ "srf_paramdesc_graphsize": "Besar grafik (dalam px)",
+ "srf_paramdesc_graphlegend": "Tampilkan legenda grafik",
+ "srf_paramdesc_graphlabel": "Label grafik",
+ "srf_paramdesc_rankdir": "Arah panah",
+ "srf_paramdesc_graphlink": "Tautan grafik",
+ "srf_paramdesc_graphcolor": "Warna grafik",
+ "srf-paramdesc-graph-wwl": "Batas pemenggalan kata (dalam jumlah karakter)",
+ "srf-filtered-selectorlabel-list": "Daftar",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-ui-eventcalendar-label-today": "Hari ini",
+ "srf-ui-eventcalendar-label-month": "Bulan",
+ "srf-ui-eventcalendar-label-day": "Hari"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ig.json b/www/wiki/extensions/SemanticResultFormats/i18n/ig.json
new file mode 100644
index 00000000..39870b6f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ig.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ukabia"
+ ]
+ },
+ "srfc_gotomonth": "Ga na önwa",
+ "srf_printername_timeline": "Ahiriogẹ",
+ "srf_printername_eventline": "Ahiriomémé",
+ "srf_printername_googlebar": "Ngwa nkuzie Google",
+ "srf_printername_googlepie": "Orịrị nkuzie Google",
+ "srf_paramdesc_chartheight": "Ógólógó ihü nkuzie, na ogụgụ pixel",
+ "srf_paramdesc_chartwidth": "Ãbụ ihü nkuzie, na ogụgụ pixel"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/it.json b/www/wiki/extensions/SemanticResultFormats/i18n/it.json
new file mode 100644
index 00000000..5813566d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/it.json
@@ -0,0 +1,149 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Civvì",
+ "Darth Kule",
+ "F. Cosoleto",
+ "පසිඳු කà·à·€à·’න්ද",
+ "Ankabel",
+ "Macofe",
+ "McDutchie",
+ "Kaspo",
+ "S4b1nuz E.656"
+ ]
+ },
+ "srf-desc": "Formati addizionali per i risultati delle query di Semantic Mediawiki",
+ "prefs-srf-eventcalendar-options": "Opzioni calendario eventi",
+ "prefs-srf-datatables-options": "Opzioni tabelle dati",
+ "srf-module-loading": "Caricamento in corso...",
+ "srf-paramdesc-layout": "Layout disponibili",
+ "srf-paramdesc-height": "Altezza",
+ "srf-paramdesc-width": "Larghezza",
+ "srf-paramdesc-class": "Specificare un'ulteriore classe di foglio di stile CSS",
+ "srf-module-nomatch": "Nessun risultato trovato",
+ "srf-navigation-previous": "Precedente",
+ "srf-ui-navigation-prev": "Prec",
+ "srf-ui-navigation-next": "Successivo",
+ "srf-ui-common-label-source": "Fonte",
+ "srf-ui-tooltip-title-options": "Opzioni",
+ "srf-ui-tooltip-title-scope": "Scopo",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtro",
+ "srf-ui-common-label-refresh": "Aggiorna",
+ "srf-ui-common-label-parameters": "Parametri",
+ "srf-error-option-mix": "Opzione ($1) non disponibile",
+ "srf-error-option-link-all": "L'opzione ($1) richiede che il parametro \"link\" sia impostato a \"all\"",
+ "srf-error-missing-layout": "Il diagramma o grafico non può essere visualizzato perché il layout è mancante.",
+ "srfc_previousmonth": "Mese precedente",
+ "srfc_nextmonth": "Mese successivo",
+ "srfc_today": "Oggi",
+ "srfc_gotomonth": "Vai al mese",
+ "srf_printername_calendar": "Calendario mensile",
+ "srf_paramdesc_calendarlang": "Il codice per la lingua in cui visualizzare il calendario",
+ "srf_printername_vcard": "esportazione vCard",
+ "srf_printername_icalendar": "esportazione iCalendar",
+ "srf_paramdesc_icalendartitle": "Il titolo del file di calendario",
+ "srf_paramdesc_icalendardescription": "La descrizione del file di calendario",
+ "srf_printername_bibtex": "esportazione BibTeX",
+ "srf_outline_novalue": "Nessun valore",
+ "srf_printername_outline": "Contorno",
+ "srf_paramdesc_outlineproperties": "L'elenco delle proprietà, separate da virgola, da visualizzare come intestazioni di contorno",
+ "srf_printername_sum": "Somma di numeri",
+ "srf_printername_average": "Media dei numeri",
+ "srf_printername_max": "Numero massimo",
+ "srf_printername_min": "Numero minimo",
+ "srf_paramdesc_limit": "Il numero massimo di pagine per eseguire una query",
+ "srf_printername_product": "Prodotto di numeri",
+ "srf_printername_median": "Mediana di numeri",
+ "srf_printername_timeline": "Linea del tempo (timeline)",
+ "srf_printername_eventline": "Linea degli eventi",
+ "srf_paramdesc_timelinebands": "Definisce quali bande temporali vengono visualizzati nel risultato",
+ "srf_paramdesc_timelineposition": "Definisce in quale punto inizia la linea del tempo",
+ "srf_paramdesc_timelinestart": "Il nome della proprietà usata per definire il primo punto temporale",
+ "srf_paramdesc_timelineend": "Il nome della proprietà usata per definire il secondo punto temporale",
+ "srf_paramdesc_timelinesize": "L'altezza della linea temporale",
+ "srf_paramdesc_views": "Le visualizzazioni da mostrare",
+ "srf_paramdesc_facets": "L'insieme di proprietà da visualizzare per ogni pagina",
+ "srf_paramdesc_lens": "Il nome di un template con cui mostrare le proprietà della pagina",
+ "srf_printername_googlebar": "Google bar chart",
+ "srf_printername_googlepie": "Google grafico a torta",
+ "srf_paramdesc_chartheight": "Specificare l'altezza (in pixel) della tabella o del grafico",
+ "srf_paramdesc_chartwidth": "Specificare la larghezza (in pixel o percentuale) della tabella o del grafico",
+ "srf_paramdesc_charttitle": "Il titolo del grafico",
+ "srf_paramdesc_barcolor": "Specificare i colori del grafico",
+ "srf_paramdesc_bardirection": "Specificare la direzione del grafico",
+ "srf-paramdesc-direction": "Specificare la direzione della tabella o del grafico",
+ "srf_paramdesc_barnumbersaxislabel": "L'etichetta per l'asse dei numeri",
+ "srf-paramdesc-labelaxislabel": "L'etichetta per l'asse delle etichetta",
+ "srf-paramdesc-minvalue": "Il valore minimo da mostrare sull'asse y",
+ "srf-paramdesc-chartclass": "Classe CSS aggiuntiva",
+ "srf-paramdesc-infotext": "Mostra informazioni aggiuntive sulla corrispondente scheda di informazioni",
+ "srf-ui-gridview-label-item": "Elemento dati",
+ "srf-ui-gridview-label-value": "Valore dati",
+ "srf-ui-gridview-label-series": "Serie di dati",
+ "srf-ui-gridview-label-chart-tab": "Grafico",
+ "srf-ui-gridview-label-data-tab": "Dati",
+ "srf-ui-gridview-label-info-tab": "Informazioni",
+ "srf_printername_gallery": "Galleria",
+ "srf_paramdesc_perrow": "Il numero di immagini per riga",
+ "srf_paramdesc_widths": "La larghezza delle immagini",
+ "srf_paramdesc_heights": "L'altezza delle immagini",
+ "srf-gallery-navigation-previous": "Precedente",
+ "srf-gallery-navigation-next": "Successivo",
+ "srf-gallery-overlay-count": "Immagine $1 di $2",
+ "srf-gallery-image-url-error": "L'immagine non è stato trovata.",
+ "srf_paramdesc_minsize": "La dimensione dei tag più piccoli in percentuale",
+ "srf_printername_hash": "Hash",
+ "srf-printername-graph": "Grafico",
+ "srf-paramdesc-graphname": "Imposta il titolo del grafico",
+ "srf-paramdesc-graphsize": "Imposta la dimensione del grafico in pixel",
+ "srf-paramdesc-graphlegend": "Imposta se la legenda del grafico va mostrata",
+ "srf-paramdesc-graphlabel": "Imposta l'etichetta del grafico",
+ "srf-paramdesc-graphcolor": "Imposta il colore del grafico",
+ "srf-printername-datatables": "Tabelle dati",
+ "srf-ui-datatables-label-conditions": "Condizioni",
+ "srf-ui-datatables-label-parameters": "Parametri",
+ "srf-ui-datatables-label-information": "Informazioni",
+ "srf-ui-datatables-label-placeholder-column-search": "Ricerca in corso...",
+ "srf-ui-datatables-label-multiselect-column-header": "Colonne disponibili",
+ "srf-ui-datatables-label-sLoadingRecords": "Caricamento...",
+ "srf-ui-datatables-label-sProcessing": "Elaborazione...",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primo",
+ "srf-ui-datatables-label-oPaginate-sLast": "Ultimo",
+ "srf-ui-datatables-label-oPaginate-sNext": "Successivo",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Precedente",
+ "srf-paramdesc-delay": "Il ritardo tra le slide in secondi",
+ "srf-paramdesc-filtered-map-height": "L'altezza della mappa.",
+ "srf-filtered-selectorlabel-list": "Elenco",
+ "srf-filtered-selectorlabel-table": "Tabella",
+ "srf-filtered-selectorlabel-calendar": "Calendario",
+ "srf-filtered-value-filter-and": "E",
+ "srf-filtered-value-filter-or": "O",
+ "srf-filtered-value-filter-placeholder": "Seleziona un valore del filtro",
+ "srf-paramdesc-group": "Serie raggruppata per",
+ "srf-paramdesc-zoom": "Abilita zoom",
+ "srf-paramdesc-listtype": "Specificare il tipo di elenco",
+ "srf-paramdesc-widget": "Widget disponibile",
+ "srf-paramdesc-pageitems": "Elementi per pagina",
+ "srf-printername-eventcalendar": "Calendario degli eventi",
+ "srf-paramdesc-calendarfirstday": "Il giorno in cui inizia ogni settimana",
+ "srf-ui-eventcalendar-label-today": "Oggi",
+ "srf-ui-eventcalendar-label-month": "Mese",
+ "srf-ui-eventcalendar-label-week": "Settimana",
+ "srf-ui-eventcalendar-label-day": "Giorno",
+ "srf-ui-eventcalendar-label-allday": "Tutto il giorno",
+ "srf-ui-eventcalendar-click-popup": "Vuoi creare un evento?",
+ "srf-paramdesc-datasource": "La fonte da dove il dato è accessibile. Valori consentiti: \"file\", \"raw\" e \"url\". Predefinito: \"file\".",
+ "srf-paramdesc-yaxislabel": "Descrizione visualizzata sull'asse y",
+ "srf-paramdesc-xaxislabel": "Descrizione visualizzata sull'asse x",
+ "srf-ui-mediaplayer-label-shuffle": "Mescola",
+ "srf-spreadsheet-link": "Foglio di calcolo",
+ "srf-paramdesc-spreadsheet-filename": "Il nome del file per il download del foglio di calcolo generato",
+ "srf-paramdesc-spreadsheet-fileformat": "Il formato file del foglio di calcolo da produrre. Valori ammessi: xlsx, xls, ods, csv. Predefinito: xlsx",
+ "srf-paramdesc-icalendar-timezone": "Un elenco di fusi orari separati da virgole",
+ "srf-paramdesc-gantt-diagramtitle": "Nome del diagramma",
+ "srf-paramdesc-gantt-diagramtheme": "Tema del diagramma",
+ "srf-paramdesc-gantt-axisformat": "Asse-X: Formato data",
+ "srf-printername-gantt": "Gantt"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ja.json b/www/wiki/extensions/SemanticResultFormats/i18n/ja.json
new file mode 100644
index 00000000..4a977a05
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ja.json
@@ -0,0 +1,230 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fryed-peach",
+ "Hosiryuhosi",
+ "JtFuruhata",
+ "Naohiro19",
+ "Schu",
+ "Shirayuki",
+ "Whym",
+ "é’å­å®ˆæ­Œ",
+ "Rxy",
+ "SkyDaisy9",
+ "Sujiniku",
+ "Otokoume",
+ "Ochaochaocha3",
+ "Omotecho",
+ "Nemo bis",
+ "Suyama"
+ ]
+ },
+ "srf-desc": "Semantic MediaWiki ã®ã‚¯ã‚¨ãƒªã®ãŸã‚ã®è¿½åŠ çš„ãªçµæžœã®å½¢å¼",
+ "prefs-srf": "æ„味的çµæžœã®å½¢å¼",
+ "prefs-srf-eventcalendar-options": "イベントカレンダーオプション",
+ "srf-prefs-eventcalendar-options-update-default": "ページ更新中ã®ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆã®[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自動更新]を有効ã«ã™ã‚‹",
+ "prefs-srf-datatables-options": "データテーブルオプション",
+ "srf-prefs-datatables-options-update-default": "ページ更新中ã®ãƒ†ãƒ¼ãƒ–ル内容ã®[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自動更新]を有効ã«ã™ã‚‹",
+ "srf-prefs-datatables-options-cache-default": "応答時間ã®æ”¹å–„ã®ãŸã‚[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage ローカルストレージ]を有効ã«ã™ã‚‹",
+ "srf-module-loading": "読ã¿è¾¼ã¿ä¸­...",
+ "srf-paramdesc-layout": "利用ã§ãるレイアウト",
+ "srf-paramdesc-height": "高ã•",
+ "srf-paramdesc-width": "å¹…",
+ "srf-paramdesc-class": "追加的㪠CSS クラスを指定",
+ "srf-module-nomatch": "該当ã™ã‚‹ã‚‚ã®ã¯ã‚ã‚Šã¾ã›ã‚“",
+ "srf-paramdesc-charttype": "利用ã§ãるグラフã®ç¨®é¡ž",
+ "srf-navigation-previous": "å‰ã¸",
+ "srf-ui-navigation-prev": "å‰ã¸",
+ "srf-ui-navigation-next": "次ã¸",
+ "srf-ui-common-label-source": "ソース",
+ "srf-ui-common-label-datasource": "データ ソース",
+ "srf-ui-tooltip-title-options": "オプション",
+ "srf-ui-tooltip-title-scope": "スコープ",
+ "srf-ui-tooltip-title-legend": "凡例",
+ "srf-ui-common-label-query": "å•ã„åˆã‚ã›",
+ "srf-error-option-mix": "オプション ($1) ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“",
+ "srf-error-option-link-all": "オプション ($1) を使用ã™ã‚‹ã«ã¯ã€ãƒ‘ラメーター「linkã€ã‚’「allã€ã«è¨­å®šã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™",
+ "srf-error-missing-layout": "レイアウトãŒãªã„ãŸã‚ã€ãƒãƒ£ãƒ¼ãƒˆã‚„グラフを表示ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。",
+ "srf-warn-empy-chart": "データãŒè¶³ã‚Šãªã„ãŸã‚ã€ã‚°ãƒ©ãƒ•ã¯ç©ºã§ã™",
+ "srfc_previousmonth": "å‰ã®æœˆ",
+ "srfc_nextmonth": "次ã®æœˆ",
+ "srfc_today": "今日",
+ "srfc_gotomonth": "ã“ã®æœˆã‚’表示",
+ "srf_printername_calendar": "月毎ã®ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼",
+ "srf_paramdesc_calendarlang": "カレンダーを表示ã™ã‚‹ãŸã‚ã®è¨€èªžã‚³ãƒ¼ãƒ‰",
+ "srf_paramdesc_calendarcolors": "å„日付プロパティを表示ã™ã‚‹è‰² (例: \"開始日=>green,終了日=>#09c\")",
+ "srf_printername_vcard": "vCard å½¢å¼ã§æ›¸ã出ã—",
+ "srf_printername_icalendar": "iCalender å½¢å¼ã§æ›¸ã出ã—",
+ "srf_paramdesc_icalendartitle": "カレンダーファイルã®ã‚¿ã‚¤ãƒˆãƒ«",
+ "srf_paramdesc_icalendardescription": "カレンダーファイルã®èª¬æ˜Ž",
+ "srf_printername_bibtex": "BibTeX å½¢å¼ã§æ›¸ã出ã—",
+ "srf_outline_novalue": "値ãªã—",
+ "srf_printername_outline": "アウトライン",
+ "srf_paramdesc_outlineproperties": "アウトラインã®è¦‹å‡ºã—ã¨ã—ã¦è¡¨ç¤ºã•ã‚Œã‚‹ãƒ—ロパティã®ãƒªã‚¹ãƒˆï¼ˆã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šï¼‰",
+ "srf_printername_sum": "æ•°ã®åˆè¨ˆ",
+ "srf_printername_average": "æ•°ã®å¹³å‡",
+ "srf_printername_max": "最大数",
+ "srf_printername_min": "最å°æ•°",
+ "srf_paramdesc_limit": "å•ã„åˆã‚ã›ã™ã‚‹ãƒšãƒ¼ã‚¸ã®æœ€å¤§æ•°",
+ "srf_printername_product": "数値ã®ç©",
+ "srf_printername_median": "数値ã®å¹³å‡",
+ "srf-paramdesc-default": "数値的データãŒãªã„å ´åˆã«è¡¨ç¤ºã™ã‚‹æ—¢å®šå€¤",
+ "srf_printername_earliest": "最もå¤ã„時刻",
+ "srf_printername_latest": "最も新ã—ã„時刻",
+ "srf_printername_timeline": "時系列",
+ "srf_printername_eventline": "事象系列",
+ "srf_paramdesc_timelinebands": "出力çµæžœã«ã©ã®æ™‚é–“å˜ä½ã‚’表示ã™ã‚‹ã‹å®šç¾©ã™ã‚‹ã€‚",
+ "srf_paramdesc_timelineposition": "åˆæœŸçŠ¶æ…‹ã§ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ãŒã©ã“ã«ãƒ•ã‚©ãƒ¼ã‚«ã‚¹ã—ã¦ã„ã‚‹ã‹å®šç¾©ã™ã‚‹ã€‚",
+ "srf_paramdesc_timelinestart": "最åˆã®æ™‚点を定義ã™ã‚‹ãƒ—ロパティã®åå‰",
+ "srf_paramdesc_timelineend": "2番目ã®æ™‚点を定義ã™ã‚‹ãƒ—ロパティã®åå‰",
+ "srf_paramdesc_timelinesize": "タイムラインã®é«˜ã•",
+ "srf-timeline-nojs": "対話的ãªã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã‚’表示ã™ã‚‹ãŸã‚ã« JavaScript を有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚",
+ "srf_paramdesc_views": "表示ã•ã‚Œã‚‹ãƒ“ュー",
+ "srf_paramdesc_facets": "å„ページã§è¡¨ç¤ºã™ã‚‹ãƒ—ロパティã®é›†åˆ",
+ "srf_paramdesc_lens": "ページã®ãƒ—ロパティã¨å…±ã«è¡¨ç¤ºã™ã‚‹ãƒ†ãƒ³ãƒ—レートã®åå‰",
+ "srf_printername_googlebar": "Google 棒グラフ",
+ "srf_printername_googlepie": "Google 円グラフ",
+ "srf-printername-jqplotchart": "jqPlot ãƒãƒ£ãƒ¼ãƒˆ",
+ "srf-printername-jqplotseries": "jqPlot 系列",
+ "srf_paramdesc_chartheight": "グラフã®é«˜ã•ã‚’指定 (ピクセル)",
+ "srf_paramdesc_chartwidth": "グラフã®å¹…を指定 (ピクセルã¾ãŸã¯ %)",
+ "srf_paramdesc_charttitle": "図ã®ã‚¿ã‚¤ãƒˆãƒ«",
+ "srf_paramdesc_barcolor": "グラフã®è‰²ã‚’指定",
+ "srf_paramdesc_bardirection": "グラフã®æ–¹å‘を指定",
+ "srf-paramdesc-direction": "グラフã®æ–¹å‘を指定",
+ "srf_paramdesc_barnumbersaxislabel": "数値軸ã®ãƒ©ãƒ™ãƒ«",
+ "srf-paramdesc-labelaxislabel": "ラベル軸ã®ãƒ©ãƒ™ãƒ«",
+ "srf-paramdesc-ticklabels": "目盛ラベルã®è¡¨ç¤ºã‚’有効化",
+ "srf-paramdesc-minvalue": "Y 軸ã«è¡¨ç¤ºã™ã‚‹æœ€å¤§å€¤",
+ "srf-paramdesc-chartlegend": "グラフã®å‡¡ä¾‹ã®ä½ç½®",
+ "srf-paramdesc-datalabels": "グラフã®ãƒ‡ãƒ¼ã‚¿ ラベル",
+ "srf-paramdesc-chartclass": "追加的㪠CSS クラス",
+ "srf-paramdesc-theme": "グリッドã®ãƒ†ãƒ¼ãƒžã‚’é¸æŠž",
+ "srf-paramdesc-colorscheme": "色スキームをé¸æŠž",
+ "srf-paramdesc-valueformat": "値ã®æ•´å½¢è¦å‰‡ã‚’指定",
+ "srf-paramdesc-smoothlines": "折れ線グラフã«å¹³æ»‘化アルゴリズムをé©ç”¨",
+ "srf-paramdesc-stackseries": "グラフをç©ã¿é‡ã­ç³»åˆ—ã¨ã—ã¦è¡¨ç¤º",
+ "srf-paramdesc-seriesgroup": "系列ã®ã‚°ãƒ«ãƒ¼ãƒ—化をé¸æŠž",
+ "srf-paramdesc-serieslabel": "系列ラベルを指定",
+ "srf-paramdesc-grouplabel": "グループ ラベルを指定",
+ "srf-paramdesc-chartcursor": "グラフ カーソルã®è¡¨ç¤ºã‚ªãƒ—ション",
+ "srf-paramdesc-trendline": "グラフã¨ãã®è¿‘似曲線ã®åŒæ™‚表示を有効化",
+ "srf-paramdesc-paneview": "å°ã•ãªæŠ˜ã‚Œç·šã‚°ãƒ©ãƒ•ã®å…¥ã‚‹æž ã®ä½ç½®ã‚’指定ã—ã¾ã™ã€‚使用ã§ãる値: 「bottomã€ã€ã€Œtopã€ã€ã€Œnoneã€ã€‚既定値: 「bottomã€",
+ "srf-paramdesc-infotext": "対応ã™ã‚‹æƒ…報タブã§è¿½åŠ çš„ãªæƒ…報を表示",
+ "srf-ui-gridview-label-item": "データ項目",
+ "srf-ui-gridview-label-value": "データã®å€¤",
+ "srf-ui-gridview-label-series": "データ系列",
+ "srf-ui-gridview-label-chart-tab": "グラフ",
+ "srf-ui-gridview-label-data-tab": "データ",
+ "srf-ui-gridview-label-info-tab": "情報",
+ "srf_printername_gallery": "ギャラリー",
+ "srf_paramdesc_perrow": "è¡Œã‚ãŸã‚Šã®ç”»åƒã®é‡",
+ "srf_paramdesc_widths": "ç”»åƒã®å¹…",
+ "srf_paramdesc_heights": "ç”»åƒã®é«˜ã•",
+ "srf_paramdesc_autocaptions": "キャプションã¨ã—ã¦ä½•ã‚‚指定ã—ãªã‹ã£ãŸå ´åˆã¯ãƒ•ã‚¡ã‚¤ãƒ«åを使用",
+ "srf_paramdesc_fileextensions": "キャプションã«ãƒ•ã‚¡ã‚¤ãƒ«åを使用ã™ã‚‹éš›ã«ãã®ãƒ•ã‚¡ã‚¤ãƒ«ã®æ‹¡å¼µå­ã‚‚表示",
+ "srf-paramdesc-redirects": "リダイレクト先をå«ã‚€ã‚¯ã‚¨ãƒªãƒšãƒ¼ã‚¸ã«è¡¨ç¤ºã™ã‚‹æ„味的プロパティã®åå‰",
+ "srf-paramdesc-overlay": "ç”»åƒã‚ªãƒ¼ãƒãƒ¼ãƒ¬ã‚¤ã‚’有効化",
+ "srf-gallery-navigation-previous": "å‰ã¸",
+ "srf-gallery-navigation-next": "次ã¸",
+ "srf-gallery-overlay-count": "ç”»åƒ $1 / $2",
+ "srf-gallery-image-url-error": "ç”»åƒãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。",
+ "srf_printername_tagcloud": "タグ クラウド",
+ "srf_paramdesc_increase": "ã‚¿ã‚°ã®ã‚µã‚¤ã‚ºã®å¢—ã‚„ã—æ–¹",
+ "srf_paramdesc_tagorder": "ã‚¿ã‚°ã®ä¸¦ã³é †",
+ "srf_paramdesc_minsize": "最å°ã®ã‚¿ã‚°ã®ã‚µã‚¤ã‚º (%)",
+ "srf_paramdesc_maxsize": "最大ã®ã‚¿ã‚°ã®ã‚µã‚¤ã‚º (%)",
+ "srf_paramdesc_maxtags": "クラウド内ã®ã‚¿ã‚°ã®æœ€å¤§æ•°",
+ "srf-paramdesc-excludetags": "除外ã™ã‚‹ã‚¿ã‚° (「;ã€ã§åŒºåˆ‡ã‚‹)",
+ "srf_printername_array": "é…列",
+ "srf_printername_hash": "ãƒãƒƒã‚·ãƒ¥",
+ "srf-printername-graph": "グラフ",
+ "srf-paramdesc-graph-nodeshape": "グラフã®å„ノードã®å½¢çŠ¶ã‚’設定",
+ "srf-paramdesc-graphname": "グラフã®ãƒ©ãƒ™ãƒ«ã‚’設定",
+ "srf-paramdesc-graphsize": "グラフã®ã‚µã‚¤ã‚ºã‚’ピクセルå˜ä½ã§è¨­å®š",
+ "srf-paramdesc-graphlegend": "グラフã®å‡¡ä¾‹ã®è¡¨ç¤º/éžè¡¨ç¤ºã‚’設定",
+ "srf-paramdesc-graphlabel": "グラフã®ãƒ©ãƒ™ãƒ«ã‚’設定",
+ "srf-paramdesc-rankdir": "矢å°ã®æ–¹å‘を設定",
+ "srf-paramdesc-graphlink": "ノードをãã‚Œãžã‚Œã®ã‚¦ã‚£ã‚­ãƒšãƒ¼ã‚¸ã«ãƒªãƒ³ã‚¯ã™ã‚‹ã‹ã©ã†ã‹è¨­å®š",
+ "srf-paramdesc-graphcolor": "グラフã®è‰²ã‚’設定",
+ "srf-printername-datatables": "データテーブル",
+ "srf-ui-datatables-label-placeholder-column-search": "検索...",
+ "srf-ui-datatables-label-sInfo": "_TOTAL_ 件中 _START_ ã‹ã‚‰ _END_ 件を表示中",
+ "srf-ui-datatables-label-sInfoEmpty": "0 件中 0 ã‹ã‚‰ 0 件を表示中",
+ "srf-ui-datatables-label-sLengthMenu": "_MENU_ 件を表示",
+ "srf-ui-datatables-label-sLoadingRecords": "読ã¿è¾¼ã¿ä¸­...",
+ "srf-ui-datatables-label-sProcessing": "処ç†ä¸­...",
+ "srf-ui-datatables-label-sSearch": "検索:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "先頭",
+ "srf-ui-datatables-label-oPaginate-sLast": "最後",
+ "srf-ui-datatables-label-oPaginate-sNext": "次ã¸",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "å‰ã¸",
+ "srf-paramdesc-tree-parent": "親ページをå«ã‚€ãƒ—ロパティ",
+ "srf-printername-slideshow": "スライドショー",
+ "srf-paramdesc-delay": "スライド間ã®é…延 (秒)",
+ "srf-paramdesc-navigation-controls": "ナビゲーション コントロールを表示ã™ã‚‹ã‹ã©ã†ã‹",
+ "srf-paramdesc-filtered-list-type": "一覧ã®ç¨®é¡žã€‚指定ã§ãる値: \"list\"ã€\"ul\"ã€\"ol\"。既定値: \"list\"。",
+ "srf-paramdesc-filtered-list-template": "一覧ã®é …ç›®ã®æ•´å½¢ã«ä½¿ç”¨ã™ã‚‹ãƒ†ãƒ³ãƒ—レート。",
+ "srf-paramdesc-filtered-list-named-args": "テンプレートã«æ¸¡ã—ãŸå¼•æ•°ã«åå‰ã‚’付ã‘る。",
+ "srf-paramdesc-filtered-list-introtemplate": "å•ã„åˆã‚ã›çµæžœãŒã‚ã‚‹å ´åˆã€ãã®å‰ã«è¡¨ç¤ºã™ã‚‹ãƒ†ãƒ³ãƒ—レートã®åå‰ã€‚",
+ "srf-paramdesc-filtered-list-outrotemplate": "å•ã„åˆã‚ã›çµæžœãŒã‚ã‚‹å ´åˆã€ãã®å¾Œã«è¡¨ç¤ºã™ã‚‹ãƒ†ãƒ³ãƒ—レートã®åå‰ã€‚",
+ "srf-paramdesc-filtered-calendar-title-template": "カレンダーã§ã‚¤ãƒ™ãƒ³ãƒˆã®ã‚¿ã‚¤ãƒˆãƒ«ã®æ•´å½¢ã«ä½¿ç”¨ã™ã‚‹ãƒ†ãƒ³ãƒ—レート",
+ "srf-filtered-selectorlabel-list": "一覧",
+ "srf-filtered-selectorlabel-table": "テーブル",
+ "srf-filtered-selectorlabel-calendar": "カレンダー",
+ "srf-filtered-firstdayofweek": "0",
+ "srf-printername-d3chart": "D3 ãƒãƒ£ãƒ¼ãƒˆ",
+ "srf-printername-timeseries": "時系列グラフ",
+ "srf-paramdesc-group": "系列ã®ã‚°ãƒ«ãƒ¼ãƒ—化",
+ "srf-paramdesc-zoom": "拡大/縮å°ã‚’有効ã«ã™ã‚‹",
+ "srf-paramdesc-datatable": "データテーブルを有効ã«ã™ã‚‹",
+ "srf-printername-sparkline": "折れ線グラフ",
+ "srf-printername-listwidget": "一覧ウィジェット",
+ "srf-paramdesc-listtype": "一覧ã®ç¨®é¡žã‚’指定",
+ "srf-paramdesc-widget": "利用ã§ãるウィジェット",
+ "srf-paramdesc-pageitems": "ページã‚ãŸã‚Šã®é …目数",
+ "srf-printername-eventcalendar": "イベント カレンダー",
+ "srf-paramdesc-calendarfirstday": "週ã®é–‹å§‹æ—¥ã®æ›œæ—¥",
+ "srf-paramdesc-calendardefaultview": "カレンダー読ã¿è¾¼ã¿æ™‚ã®åˆæœŸã®è¡¨ç¤º",
+ "srf-paramdesc-dayview": "日付をクリックã™ã‚‹ã¨æ—¥è¡¨ç¤ºã«ãªã‚‹ã‚ˆã†ã«ã™ã‚‹",
+ "srf-ui-eventcalendar-label-today": "今日",
+ "srf-ui-eventcalendar-label-month": "月",
+ "srf-ui-eventcalendar-label-week": "週",
+ "srf-ui-eventcalendar-label-day": "æ—¥",
+ "srf-ui-eventcalendar-label-allday": "全日",
+ "srf-ui-eventcalendar-format-time": "H(:mm)",
+ "srf-ui-eventcalendar-format-time-agenda": "H:mm( - H:mm)",
+ "srf-ui-eventcalendar-format-axis": "H:mm",
+ "srf-ui-eventcalendar-format-title-month": "yyyy年M月",
+ "srf-ui-eventcalendar-format-title-week": "yyyy年M月d日{ '&#8212;' [yyyy年][M月]d日}",
+ "srf-ui-eventcalendar-format-title-day": "yyyy年M月d日(ddd)",
+ "srf-ui-eventcalendar-format-column-month": "ddd",
+ "srf-ui-eventcalendar-format-column-week": "M月d日(ddd)",
+ "srf-ui-eventcalendar-format-column-day": "M月d日(ddd)",
+ "srf-ui-eventcalendar-label-update-success": "イベントカレンダーã®æ›´æ–°ã«æˆåŠŸã—ã¾ã—ãŸã€‚",
+ "srf-printername-dygraphs": "Digraph ãƒãƒ£ãƒ¼ãƒˆ",
+ "srf-paramdesc-errorbar": "使用ã™ã‚‹ã‚¨ãƒ©ãƒ¼ãƒãƒ¼ã€‚指定ã§ãる値: \"fraction\" (値ã®ä¿¡é ¼åŒºé–“)ã€\"sigma\" (値ã®æ¨™æº–åå·®)ã€\"range\" (指定ã—ãŸç¯„囲)",
+ "srf-paramdesc-yaxislabel": "Y 軸ã«è¡¨ç¤ºã™ã‚‹èª¬æ˜Ž",
+ "srf-paramdesc-xaxislabel": "X 軸ã«è¡¨ç¤ºã™ã‚‹èª¬æ˜Ž",
+ "srf-paramdesc-unit": "ユニット",
+ "srf-printername-pagewidget": "ページウィジェット",
+ "srf-paramdesc-min": "ã—ãã„値ã®æœ€å°å€¤",
+ "srf-paramdesc-excludeproperty": "çµæžœã®é›†åˆã‹ã‚‰ãƒ—ロパティを除外",
+ "srf-printername-media": "メディア プレーヤー",
+ "srf-paramdesc-mediainspector": "指定ã—ãŸãƒ¡ãƒ‡ã‚£ã‚¢è¦ç´ ã«ã¤ã„ã¦è©³ç´°æƒ…報を表示ã™ã‚‹",
+ "srf-ui-mediaplayer-label-previous": "å‰ã¸",
+ "srf-ui-mediaplayer-label-play": "å†ç”Ÿ",
+ "srf-ui-mediaplayer-label-pause": "一時åœæ­¢",
+ "srf-ui-mediaplayer-label-next": "次ã¸",
+ "srf-ui-mediaplayer-label-stop": "åœæ­¢",
+ "srf-ui-mediaplayer-label-mute": "ミュート",
+ "srf-ui-mediaplayer-label-unmute": "ミュート解除",
+ "srf-ui-mediaplayer-label-volume-max": "最大音é‡",
+ "srf-ui-mediaplayer-label-shuffle": "ランダムå†ç”Ÿ",
+ "srf-ui-mediaplayer-label-shuffle-off": "ランダムå†ç”Ÿè§£é™¤",
+ "srf-ui-mediaplayer-label-repeat": "連続å†ç”Ÿ",
+ "srf-ui-mediaplayer-label-repeat-off": "連続å†ç”Ÿè§£é™¤",
+ "srf-ui-mediaplayer-label-full-screen": "全画é¢è¡¨ç¤º",
+ "srf-ui-mediaplayer-label-restore-screen": "全画é¢è¡¨ç¤ºè§£é™¤",
+ "srf-paramdesc-icalendar-timezone": "タイムゾーンã®ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šãƒªã‚¹ãƒˆ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/jv.json b/www/wiki/extensions/SemanticResultFormats/i18n/jv.json
new file mode 100644
index 00000000..0f5534f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/jv.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meursault2004"
+ ]
+ },
+ "srfc_previousmonth": "Sasi sadurungé",
+ "srfc_nextmonth": "Sasi sabanjuré",
+ "srfc_today": "Dina iki",
+ "srfc_gotomonth": "Tumuju menyang sasi",
+ "srf_icalendar_link": "iKalèndher"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ka.json b/www/wiki/extensions/SemanticResultFormats/i18n/ka.json
new file mode 100644
index 00000000..e7f51469
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ka.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "srf-module-loading": "იტვირთებáƒâ€¦",
+ "srf-paramdesc-height": "სიმáƒáƒ¦áƒšáƒ”",
+ "srf-paramdesc-width": "სიგáƒáƒœáƒ”",
+ "srfc_previousmonth": "წინრთვე",
+ "srfc_nextmonth": "შემდეგი თვე",
+ "srfc_today": "დღეს",
+ "srfc_gotomonth": "თვეზე გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒ",
+ "srf_printername_calendar": "ყáƒáƒ•áƒ”ლთვიური კáƒáƒšáƒ”ნდáƒáƒ áƒ˜",
+ "srf_printername_max": "მáƒáƒ¥áƒ¡áƒ˜áƒ›áƒáƒšáƒ£áƒ áƒ˜ რáƒáƒáƒ“ენáƒáƒ‘áƒ",
+ "srf_printername_min": "მინიმáƒáƒšáƒ£áƒ áƒ˜ რáƒáƒáƒ“ენáƒáƒ‘áƒ",
+ "srf-ui-gridview-label-data-tab": "მáƒáƒœáƒáƒªáƒ”მები",
+ "srf-ui-gridview-label-info-tab": "ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ",
+ "srf_printername_gallery": "გáƒáƒšáƒ”რეáƒ",
+ "srf-gallery-navigation-previous": "წინáƒ",
+ "srf-gallery-navigation-next": "შემდეგი",
+ "srf-printername-graph": "გრáƒáƒ¤áƒ˜áƒ™áƒ˜",
+ "srf_paramdesc_graphname": "სáƒáƒ—áƒáƒ£áƒ áƒ˜",
+ "srf_paramdesc_graphsize": "გრáƒáƒ¤áƒ˜áƒ™áƒ˜áƒ¡ ზáƒáƒ›áƒ (პიქსელებში)",
+ "srf_paramdesc_graphlink": "გრáƒáƒ¤áƒ˜áƒ™áƒ˜áƒ¡ ბმული",
+ "srf_paramdesc_graphcolor": "გრáƒáƒ¤áƒ˜áƒ™áƒ˜áƒ¡ ფერი",
+ "srf-printername-tree": "ხე",
+ "srf-printername-slideshow": "სლáƒáƒ˜áƒ“შáƒáƒ£"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/km.json b/www/wiki/extensions/SemanticResultFormats/i18n/km.json
new file mode 100644
index 00000000..1bae1961
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/km.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lovekhmer",
+ "គីមស៊្រុន"
+ ]
+ },
+ "srfc_previousmonth": "ážáŸ‚មុន",
+ "srfc_nextmonth": "ážáŸ‚បន្ទាប់",
+ "srfc_today": "ážáŸ’ងៃនáŸáŸ‡",
+ "srfc_gotomonth": "ទៅកាន់ážáŸ‚"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ko.json b/www/wiki/extensions/SemanticResultFormats/i18n/ko.json
new file mode 100644
index 00000000..f4ade189
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ko.json
@@ -0,0 +1,251 @@
+{
+ "@metadata": {
+ "authors": [
+ "Keysuck",
+ "ì•„ë¼",
+ "Hwangjy9",
+ "Ykhwong",
+ "Jerrykim306",
+ "Nemo bis",
+ "Garam"
+ ]
+ },
+ "srf-desc": "시맨틱 미디어위키 쿼리용 추가 ê²°ê³¼ í¬ë§·",
+ "prefs-srf": "시맨틱 ê²°ê³¼ í¬ë§·",
+ "srf-prefs-intro-text": "시맨틱 ê²°ê³¼ í¬ë§· 확장 ê¸°ëŠ¥ì„ ì„¤ì¹˜í•˜ì˜€ìŠµë‹ˆë‹¤. 추가ì ì¸ ë„ì›€ì„ ë°›ìœ¼ë ¤ë©´ [https://www.semantic-mediawiki.org/wiki/Help:Result_formats ê²°ê³¼ í¬ë§·] ë„ì›€ë§ íŽ˜ì´ì§€ë¥¼ 방문해 주십시오.",
+ "prefs-srf-eventcalendar-options": "ì´ë²¤íŠ¸ ìº˜ë¦°ë” ì˜µì…˜",
+ "prefs-srf-datatables-options": "ë°ì´í„°í…Œì´ë¸” 옵션",
+ "srf-module-loading": "불러오는 중…",
+ "srf-paramdesc-layout": "사용할 수 있는 ë ˆì´ì•„웃",
+ "srf-paramdesc-height": "높ì´",
+ "srf-paramdesc-width": "너비",
+ "srf-paramdesc-class": "추가ì ì¸ CSS í´ëž˜ìŠ¤ë¥¼ 지정하십시오",
+ "srf-module-nomatch": "ì¼ì¹˜í•˜ëŠ” í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤",
+ "srf-paramdesc-charttype": "사용할 수 있는 차트 종류",
+ "srf-navigation-previous": "ì´ì „",
+ "srf-ui-navigation-prev": "ì´ì „",
+ "srf-ui-navigation-next": "다ìŒ",
+ "srf-ui-common-label-source": "ì›ë³¸",
+ "srf-ui-common-label-datasource": "ë°ì´í„° ì›ë³¸",
+ "srf-ui-common-label-ajax-error": "서버가 ì´ $1ì— ëŒ€í•œ í†µì‹ ì„ ì‹¤íŒ¨í–ˆë‹¤ê³  보고했습니다. 문서를 새로 고치거나 ì´ $2ì„ í†µí•´ ìƒì˜í•´ 보십시오.",
+ "srf-ui-common-label-request-object": "요청 ê°ì²´",
+ "srf-ui-common-label-help-section": "ë„ì›€ë§ ë¬¸ë‹¨",
+ "srf-ui-tooltip-title-options": "옵션",
+ "srf-ui-tooltip-title-scope": "범위",
+ "srf-ui-tooltip-title-legend": "범례",
+ "srf-ui-tooltip-title-filter": "í•„í„°",
+ "srf-ui-common-label-refresh": "새로 고침",
+ "srf-ui-common-label-parameters": "변수",
+ "srf-ui-common-label-query": "쿼리",
+ "srf-ui-common-label-daterange": "날짜 범위",
+ "srf-ui-widgets-label-parameter-limit": "제한 변수",
+ "srf-error-option-mix": "옵션 ($1)ì€ ì‚¬ìš©í•  수 없습니다",
+ "srf-error-option-link-all": "옵션($1)ì˜ ê²½ìš° \"link\" 변수를 ëª¨ë‘ \"all\"ë¡œ 설정할 필요가 있습니다",
+ "srf-error-missing-layout": "ë ˆì´ì•„ì›ƒì´ ì—†ê¸° ë•Œë¬¸ì— ì°¨íŠ¸ë‚˜ 그래프를 표시할 수 없습니다.",
+ "srf-error-jqplot-bubble-data-length": "ë°ì´í„°ê°€ 없기 ë•Œë¬¸ì— ì°¨íŠ¸ë‚˜ 그래프를 표시할 수 없습니다.",
+ "srf-error-jqplot-stackseries-data-length": "모든 막대나 ì„ ì´ ë™ì¼í•œ ì–‘ì˜ ìš”ì†Œë¥¼ 보유한 ê²ƒì´ ì•„ë‹ˆë¯€ë¡œ 차트나 그래프를 표시할 수 없습니다.",
+ "srf-warn-empy-chart": "ë°ì´í„°ê°€ 없기 ë•Œë¬¸ì— ì°¨íŠ¸ë‚˜ 그래프가 비어있습니다",
+ "srfc_previousmonth": "ì´ì „ 달",
+ "srfc_nextmonth": "ë‹¤ìŒ ë‹¬",
+ "srfc_today": "오늘",
+ "srfc_gotomonth": "ì´ ë‹¬ë¡œ 가기",
+ "srf_printername_calendar": "월별 달력",
+ "srf_printername_vcard": "vCard 내보내기",
+ "srf_printername_icalendar": "iCalendar 내보내기",
+ "srf_paramdesc_icalendartitle": "달력 파ì¼ì˜ 제목",
+ "srf_paramdesc_icalendardescription": "달력 파ì¼ì˜ 설명",
+ "srf_printername_bibtex": "BibTeX 내보내기",
+ "srf_outline_novalue": "ê°’ ì—†ìŒ",
+ "srf_printername_outline": "개요",
+ "srf_printername_sum": "숫ìžì˜ í•©",
+ "srf_printername_average": "숫ìžì˜ í‰ê· ",
+ "srf_printername_max": "최대 수",
+ "srf_printername_min": "최소 수",
+ "srf_paramdesc_limit": "쿼리할 페ì´ì§€ì˜ 최대 수",
+ "srf_printername_median": "숫ìžì˜ 중간 ê°’",
+ "srf_printername_earliest": "가장 ì´ë¥¸ 시간",
+ "srf_printername_latest": "가장 ëŠ¦ì€ ì‹œê°„",
+ "srf_printername_timeline": "타임ë¼ì¸",
+ "srf_printername_eventline": "ì´ë²¤íŠ¸ë¼ì¸",
+ "srf_paramdesc_timelinesize": "타임ë¼ì¸ì˜ 높ì´",
+ "srf-timeline-allresults": "ì´ ì¿¼ë¦¬ì˜ ì¶”ê°€ 결과입니다.",
+ "srf-timeline-nojs": "ìƒí˜¸ìž‘ìš© 타임ë¼ì¸ì„ 보려면 ìžë°”스í¬ë¦½íŠ¸ë¥¼ 활성화해야 합니다.",
+ "srf_printername_googlebar": "구글 바 차트",
+ "srf_printername_googlepie": "구글 íŒŒì´ ì°¨íŠ¸",
+ "srf-printername-jqplotchart": "jqPlot 차트",
+ "srf-printername-jqplotseries": "jqPlot 시리즈",
+ "srf_paramdesc_charttitle": "차트 제목",
+ "srf_paramdesc_barcolor": "차트 색 지정",
+ "srf_paramdesc_bardirection": "차트 방향 지정",
+ "srf-paramdesc-direction": "차트나 ê·¸ëž˜í”„ì˜ ë°©í–¥ 지정",
+ "srf_paramdesc_barnumbersaxislabel": "ìˆ«ìž ì¶•ì˜ ë ˆì´ë¸”",
+ "srf-paramdesc-labelaxislabel": "ë ˆì´ë¸” ì¶•ì˜ ë ˆì´ë¸”",
+ "srf-paramdesc-minvalue": "Yì¶•ì— í‘œì‹œí•  최소값",
+ "srf-paramdesc-chartlegend": "차트 범례 위치",
+ "srf-paramdesc-datalabels": "차트/그래프 ë°ì´í„° ë ˆì´ë¸”",
+ "srf-paramdesc-chartclass": "추가ì ì¸ CSS í´ëž˜ìŠ¤",
+ "srf-paramdesc-renderer": "그래프/차트 ë Œë”러 ì„ íƒ",
+ "srf-paramdesc-filling": "개별 채우기 옵션",
+ "srf-paramdesc-theme": "격ìžë¬´ëŠ¬ 테마 ì„ íƒ",
+ "srf-paramdesc-chartcolor": "개별 차트 색 할당",
+ "srf-paramdesc-colorscheme": "컬러 스킴 ì„ íƒ",
+ "srf-paramdesc-smoothlines": "ë¼ì¸ ì°¨íŠ¸ì— ìŠ¤ë¬´ë”© ì•Œê³ ë¦¬ì¦˜ì„ ì ìš©í•©ë‹ˆë‹¤",
+ "srf-paramdesc-chartcursor": "차트 커서 ë””ìŠ¤í”Œë ˆì´ ì˜µì…˜",
+ "srf-ui-gridview-label-item": "ë°ì´í„° 항목",
+ "srf-ui-gridview-label-value": "ë°ì´í„° ê°’",
+ "srf-ui-gridview-label-series": "ë°ì´í„° 시리즈",
+ "srf-ui-gridview-label-chart-tab": "차트",
+ "srf-ui-gridview-label-data-tab": "ë°ì´í„°",
+ "srf-ui-gridview-label-info-tab": "ì •ë³´",
+ "srf_printername_gallery": "갤러리",
+ "srf_paramdesc_perrow": "행별 ê·¸ë¦¼ì˜ ì–‘",
+ "srf_paramdesc_widths": "ê·¸ë¦¼ì˜ ë„ˆë¹„",
+ "srf_paramdesc_heights": "ê·¸ë¦¼ì˜ ë†’ì´",
+ "srf_paramdesc_autocaptions": "아무 ê²ƒë„ ì§€ì •í•˜ì§€ 않으면 íŒŒì¼ ì´ë¦„ì„ ì œëª©ìœ¼ë¡œ 사용합니다",
+ "srf_paramdesc_fileextensions": "íŒŒì¼ ì´ë¦„ì„ ì œëª©ìœ¼ë¡œ 사용하면 íŒŒì¼ í™•ìž¥ìžë„ 표시합니다",
+ "srf-paramdesc-navigation": "ë ˆì´ì•„웃 내비게ì´ì…˜ 컨트롤",
+ "srf-paramdesc-overlay": "ì´ë¯¸ì§€ ì˜¤ë²„ë ˆì´ ì‚¬ìš©",
+ "srf-gallery-navigation-previous": "ì´ì „",
+ "srf-gallery-navigation-next": "다ìŒ",
+ "srf-gallery-overlay-count": "그림 $2 중 $1",
+ "srf-gallery-image-url-error": "ê·¸ë¦¼ì„ ì°¾ì„ ìˆ˜ 없습니다.",
+ "srf_printername_tagcloud": "태그 í´ë¼ìš°ë“œ",
+ "srf_paramdesc_increase": "태그 í¬ê¸°ë¥¼ 늘리는 방법",
+ "srf_paramdesc_tagorder": "íƒœê·¸ì˜ ìˆœì„œ",
+ "srf_paramdesc_maxtags": "í´ë¼ìš°ë“œ ë‚´ íƒœê·¸ì˜ ìµœëŒ€ 수",
+ "srf-paramdesc-excludetags": "태그 제외 (구분ìž: \";\")",
+ "srf_printername_array": "ë°°ì—´",
+ "srf_paramdesc_propsep": "ìš”ì²­ëœ ì†ì„± ê°„ 구분ìž",
+ "srf_paramdesc_manysep": "ê°’ì´ ìžˆëŠ” ìˆ˜ë§Žì€ ì†ì„±ê°’ ê°„ 구분ìž",
+ "srf_paramdesc_recordsep": "레코드 ì†ì„±ê°’ ê°„ 구분ìž",
+ "srf_paramdesc_headersep": "\"headers\"ê°€ \"show\"나 \"plain\"으로 ì„¤ì •ëœ ê²½ìš° ì†ì„± ì´ë¦„ê³¼ ê°’ ê°„ 구분ìž",
+ "srf_printername_hash": "해시",
+ "srf-printername-graph": "그래프",
+ "srf-paramdesc-graph-nodeshape": "ê·¸ëž˜í”„ì˜ ê° ë…¸ë“œì˜ ëª¨ì–‘ 설정",
+ "srf-paramdesc-graphname": "ê·¸ëž˜í”„ì˜ ì œëª© 설정",
+ "srf-paramdesc-graphsize": "그래프 í¬ê¸°ë¥¼ 픽셀 단위로 설정합니다",
+ "srf-paramdesc-graphlegend": "그래프 범례를 ë³´ì´ê±°ë‚˜ ë³´ì´ì§€ 않게 설정",
+ "srf-paramdesc-graphlabel": "ê·¸ëž˜í”„ì˜ ë ˆì´ë¸” 설정",
+ "srf-paramdesc-rankdir": "í™”ì‚´í‘œì˜ ë°©í–¥ 설정",
+ "srf-paramdesc-graphlink": "노드가 ìžì‹ ì˜ 위키 페ì´ì§€ë¡œ ë§í¬í• ì§€ 설정합니다",
+ "srf-paramdesc-graphcolor": "ê·¸ëž˜í”„ì˜ ìƒ‰ 설정",
+ "srf-paramdesc-graph-wwl": "ìžë™ 줄 바꿈 제한 설정 (ë¬¸ìž ìˆ˜)",
+ "srf-paramdesc-highlight": "노드를 강조하ë„ë¡ ì„¤ì •",
+ "srf-paramdesc-highlightcolor": "노드 강조를 위한 글꼴 색 설정",
+ "srf-paramdesc-redlinkcolor": "빨간 ë§í¬ì˜ 글꼴 색 설정",
+ "srf-paramdesc-showroles": "그래프ì—ì„œ ì¼ì¹˜í•˜ëŠ” ì—­í•  표시",
+ "srf-paramdesc-showresources": "그래프ì—ì„œ ì¼ì¹˜í•˜ëŠ” 리소스 표시",
+ "srf-printername-datatables": "ë°ì´í„°í…Œì´ë¸”",
+ "srf-ui-datatables-label-conditions": "ì¡°ê±´",
+ "srf-ui-datatables-label-parameters": "변수",
+ "srf-ui-datatables-label-filters": "컬럼 í•„í„° ë° ê²€ìƒ‰",
+ "srf-ui-datatables-label-information": "ì •ë³´",
+ "srf-ui-datatables-label-update-success": "í…Œì´ë¸” ì—…ë°ì´íŠ¸ë¥¼ 성공했습니다",
+ "srf-ui-datatables-label-update-error": "í…Œì´ë¸” ì—…ë°ì´íŠ¸ë¥¼ 실패했습니다.",
+ "srf-ui-datatables-label-placeholder-column-search": "검색...",
+ "srf-ui-datatables-label-content-cache": "ë‚´ìš©ì€ ë¡œì»¬ ìºì‹œë¡œë¶€í„° 가져왔습니다.",
+ "srf-ui-datatables-label-content-server": "ë‚´ìš©ì€ ì„œë²„ë¡œë¶€í„° 가져왔습니다.",
+ "srf-ui-datatables-label-multiselect-column-header": "사용 가능한 열",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "필터 설정",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "ì»¬ëŸ¼ì„ ë³¼ 수 있습니다",
+ "srf-ui-datatables-label-sEmptyTable": "í…Œì´ë¸”ì— ì‚¬ìš©í•  수 있는 ë°ì´í„°ê°€ 없습니다",
+ "srf-ui-datatables-label-sInfo": "_TOTAL_ê°œì˜ í•­ëª© 중 _START_부터 _END_까지 표시 중",
+ "srf-ui-datatables-label-sInfoEmpty": "0ê°œì˜ í•­ëª© 중 0부터 0까지 표시 중",
+ "srf-ui-datatables-label-sInfoFiltered": "(_MAX_ê°œì˜ ì „ì²´ 항목ì—ì„œ í•„í„°ë¨)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "_MENU_ 엔트리 보기",
+ "srf-ui-datatables-label-sLoadingRecords": "불러오는 중...",
+ "srf-ui-datatables-label-sProcessing": "처리 중...",
+ "srf-ui-datatables-label-sSearch": "검색:",
+ "srf-ui-datatables-label-sZeroRecords": "ì¼ì¹˜í•˜ëŠ” 레코드가 없습니다",
+ "srf-ui-datatables-label-oPaginate-sFirst": "처ìŒ",
+ "srf-ui-datatables-label-oPaginate-sLast": "마지막",
+ "srf-ui-datatables-label-oPaginate-sNext": "다ìŒ",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "ì´ì „",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": 오름차순 정렬 활성화",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": 내림차순 정렬 활성화",
+ "srf-printername-tree": "트리",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "부모 ì†ì„±ì´ 지정ë˜ì§€ 않았습니다. 부모 ì†ì„±ì´ 지정ë˜ì§€ 않으면 트리를 만들 수 없습니다.",
+ "srf-tree-rootinvalid": "$1ì€ ì˜¬ë°”ë¥¸ 문서 ì œëª©ì´ ì•„ë‹™ë‹ˆë‹¤.",
+ "srf-paramdesc-tree-parent": "부모 문서를 í¬í•¨í•˜ëŠ” ì†ì„±",
+ "srf-paramdesc-tree-root": "íŠ¸ë¦¬ì˜ ë£¨íŠ¸ 페ì´ì§€",
+ "srf-printername-slideshow": "슬ë¼ì´ë“œì‡¼",
+ "srf-paramdesc-delay": "슬ë¼ì´ë“œ ê°„ 지연 (ì´ˆ 단위)",
+ "srf-paramdesc-navigation-controls": "íƒìƒ‰ ì»¨íŠ¸ë¡¤ì„ ë³´ì´ê±°ë‚˜ ë³´ì´ì§€ ì•ŠìŒ",
+ "srf-paramdesc-effect": "슬ë¼ì´ë“œ ì „í™˜ì— ì‚¬ìš©í•  효과",
+ "srf-printername-filtered": "í•„í„°ë¨",
+ "srf-paramdesc-filtered-list-type": "목ë¡ì˜ 유형입니다. 허용ë˜ëŠ” ê°’: \"list\", \"ul\", \"ol\". 기본값: \"list\".",
+ "srf-paramdesc-filtered-map-height": "지ë„ì˜ ë†’ì´ìž…니다.",
+ "srf-paramdesc-filtered-map-min-zoom": "최소로 ì„ íƒ ê°€ëŠ¥í•œ 지ë„ì˜ í™•ëŒ€/축소 수준",
+ "srf-paramdesc-filtered-map-max-zoom": "지ë„ì˜ ì„ íƒ ê°€ëŠ¥í•œ 최대 확대/축소 수준",
+ "srf-filtered-selectorlabel-list": "목ë¡",
+ "srf-filtered-selectorlabel-table": "표",
+ "srf-filtered-selectorlabel-calendar": "달력",
+ "srf-filtered-selectorlabel-map": "지ë„",
+ "srf-filtered-noscript-error": "ìžë°”스í¬ë¦½íŠ¸ë¥¼ 사용하지 ì•Šê³  있기 ë•Œë¬¸ì— ê²°ê³¼ë¥¼ 표시할 수 없습니다. $1 문서로 ì´ë™í•©ë‹ˆë‹¤.",
+ "srf-filtered-noscript-link-caption": "í‘œ 형ì‹ì˜ ê²°ê³¼",
+ "srf-filtered-map-provider-missing-error": "\"map\" ë·°ì— ì§€ë„ ì œê³µìžë¥¼ 지정하지 않았습니다.",
+ "srf-filtered-value-filter-and": "그리고",
+ "srf-filtered-value-filter-or": "ë˜ëŠ”",
+ "srf-filtered-value-filter-placeholder": "í•„í„° ê°’ì„ ì„ íƒí•˜ì„¸ìš”",
+ "srf-printername-d3chart": "D3 차트",
+ "srf-printername-timeseries": "시계열 차트",
+ "srf-paramdesc-zoom": "í¬ê¸° ì¡°ì ˆ 사용",
+ "srf-paramdesc-datatable": "ë°ì´í„°ë² ì´ìŠ¤ 사용",
+ "srf-printername-sparkline": "스파í¬ë¼ì¸ 차트",
+ "srf-printername-listwidget": "ëª©ë¡ ìœ„ì ¯",
+ "srf-paramdesc-listtype": "ëª©ë¡ ìœ í˜•ì„ ì§€ì •í•˜ì‹­ì‹œì˜¤",
+ "srf-paramdesc-widget": "사용할 수 있는 위젯",
+ "srf-paramdesc-pageitems": "문서당 항목",
+ "srf-printername-eventcalendar": "ì´ë²¤íŠ¸ 캘린ë”",
+ "srf-paramdesc-calendarfirstday": "ê° ì£¼ê°€ 시작ë˜ëŠ” ìš”ì¼",
+ "srf-ui-eventcalendar-label-today": "오늘",
+ "srf-ui-eventcalendar-label-month": "ì›”",
+ "srf-ui-eventcalendar-label-week": "주",
+ "srf-ui-eventcalendar-label-day": "ì¼",
+ "srf-ui-eventcalendar-label-listmonth": "ì›” (목ë¡)",
+ "srf-ui-eventcalendar-label-listweek": "주 (목ë¡)",
+ "srf-ui-eventcalendar-label-listday": "ì¼ (목ë¡)",
+ "srf-ui-eventcalendar-label-allday": "모든 날",
+ "srf-ui-eventcalendar-format-title-month": "yyyyë…„ MMMM",
+ "srf-ui-eventcalendar-format-title-week": "[ yyyyë…„][MMM] dì¼{ '&#8212;' yyyyë…„ MMM dì¼}",
+ "srf-ui-eventcalendar-format-title-day": "yyyyë…„ MMM dì¼ dddd",
+ "srf-ui-eventcalendar-format-column-week": "M/d ddd",
+ "srf-ui-eventcalendar-format-column-day": "M/d dddd",
+ "srf-ui-eventcalendar-click-popup": "ì´ë²¤íŠ¸ë¥¼ 만드시겠습니까?",
+ "srf-paramdesc-datasource": "ë°ì´í„° ì ‘ê·¼ì´ ê°€ëŠ¥í•œ 출처입니다. í—ˆìš©ëœ ê°’: \"file\", \"raw\", \"url\". 기본값: \"file\"",
+ "srf-paramdesc-yaxislabel": "yì¶•ì— í‘œì‹œë˜ëŠ” 설명",
+ "srf-paramdesc-xaxislabel": "xì¶•ì— í‘œì‹œë˜ëŠ” 설명",
+ "srf-paramdesc-unit": "단위",
+ "srf-printername-pagewidget": "페ì´ì§€ 위젯",
+ "srf-printername-incoming": "들어오는 ì†ì„±",
+ "srf-paramdesc-min": "최소 ë˜ëŠ” 임계값",
+ "srf-paramdesc-excludeproperty": "ê²°ê³¼ 집합ì—ì„œ ì†ì„± 제외",
+ "srf-printername-media": "미디어 플레ì´ì–´",
+ "srf-paramdesc-mediainspector": "ì§€ì •ëœ ë¯¸ë””ì–´ ìš”ì†Œì— ëŒ€í•œ ìžì„¸í•œ 정보를 ë³´ì—¬ì¤ë‹ˆë‹¤",
+ "srf-ui-mediaplayer-label-previous": "ì´ì „",
+ "srf-ui-mediaplayer-label-play": "재ìƒ",
+ "srf-ui-mediaplayer-label-pause": "ì¼ì‹œ 정지",
+ "srf-ui-mediaplayer-label-next": "다ìŒ",
+ "srf-ui-mediaplayer-label-stop": "정지",
+ "srf-ui-mediaplayer-label-mute": "ìŒì†Œê±°",
+ "srf-ui-mediaplayer-label-unmute": "ìŒì†Œê±° í•´ì œ",
+ "srf-ui-mediaplayer-label-volume-max": "최대 ìŒëŸ‰",
+ "srf-ui-mediaplayer-label-shuffle": "셔플",
+ "srf-ui-mediaplayer-label-shuffle-off": "셔플 해제",
+ "srf-ui-mediaplayer-label-repeat": "반복",
+ "srf-ui-mediaplayer-label-repeat-off": "반복 해제",
+ "srf-ui-mediaplayer-label-full-screen": "전체 화면",
+ "srf-ui-mediaplayer-label-restore-screen": "화면 복구",
+ "srf-spreadsheet-link": "스프레드시트",
+ "srf-paramdesc-spreadsheet-filename": "다운로드를 위해 ìƒì„±ëœ 스프레드시트 파ì¼ì˜ íŒŒì¼ ì´ë¦„",
+ "srf-paramdesc-spreadsheet-templatefile": "ìƒì„±ëœ 파ì¼ì˜ ì„œì‹ì„ 제공하기 위한 \"파ì¼\" ì´ë¦„ê³µê°„ì˜ ìŠ¤í”„ë ˆë“œì‹œíŠ¸ 파ì¼ì˜ ì´ë¦„입니다",
+ "srf-paramdesc-icalendar-timezone": "쉼표 구분 시간대 목ë¡",
+ "srf-paramdesc-gantt-diagramtitle": "다ì´ì–´ê·¸ëž¨ ì´ë¦„",
+ "srf-paramdesc-gantt-diagramtheme": "다ì´ì–´ê·¸ëž¨ 테마",
+ "srf-paramdesc-gantt-axisformat": "X축: 날짜 형ì‹",
+ "srf-error-gantt-mermaid-not-installed": "Mermaid 확장 ê¸°ëŠ¥ì˜ ì„¤ì¹˜ê°€ 필요합니다.",
+ "srf-printername-gantt": "간트"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/krc.json b/www/wiki/extensions/SemanticResultFormats/i18n/krc.json
new file mode 100644
index 00000000..b194a27d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/krc.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iltever",
+ "Ernác"
+ ]
+ },
+ "srf-ui-tooltip-title-filter": "Фильтр",
+ "srf-ui-common-label-query": "Сапариш",
+ "srf-ui-gridview-label-item": "Билги Ñлемент",
+ "srf-ui-datatables-label-sLoadingRecords": "Джюклениу...",
+ "srf-ui-datatables-label-sSearch": "Изле:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Биринчи",
+ "srf-ui-datatables-label-oPaginate-sLast": "Ðхыргъы",
+ "srf-ui-datatables-label-oPaginate-sNext": "Эндиги"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ksh.json b/www/wiki/extensions/SemanticResultFormats/i18n/ksh.json
new file mode 100644
index 00000000..724211f1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ksh.json
@@ -0,0 +1,49 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "srf-desc": "Zohsäzlejje Fommaate för dem „Semantesch MediaWiki“ sing Froore em Täx vun Sigge.",
+ "srf-name": "Fomaate för wat bei Semantesch Froore eruß kohm",
+ "srfc_previousmonth": "Jangk nohm Mohnd dovör",
+ "srfc_nextmonth": "Jangk nohm nähkßte Mohnd",
+ "srfc_today": "Hück",
+ "srfc_gotomonth": "Jangk noh däm Mohnd",
+ "srf_printername_calendar": "Dä Kaländer fum Mohnd",
+ "srf-paramdesc-calendar-startmonth": "Der Mohnd. Der Kaländer es am Aanfang op dä Mohnd enjeschtallt. Schtandadd es dä Mohnd, dä mer jrahd han.",
+ "srf-paramdesc-calendar-startyear": "Et Johr. Der Kaländer es am Aanfang op dat Johr jeschtallt. Schtandadd es dat Johr, woh mer jrahd dren sin.",
+ "srf_vcard_link": "<i lang=\"en\">vCard</i>",
+ "srf_printername_vcard": "Expoot em <i lang=\"en\">vCard</i>-Fommaat",
+ "srf_icalendar_link": "<i lang=\"en\">iCalendar</i>",
+ "srf_printername_icalendar": "Expoot em Fommaat vun <i lang=\"en\">iCalendar</i>",
+ "srf_paramdesc_icalendartitle": "De Övverschreff vun dä Datteij met däm Kalländer",
+ "srf_paramdesc_icalendardescription": "Wi de Datteij met däm Kalländer beschrevve es",
+ "srf_printername_bibtex": "Expoot em <i lang=\"en\">BibTeX</i>-Fommaat",
+ "srf_outline_novalue": "Keine Wäät",
+ "srf_printername_outline": "Övverblecks_Leß",
+ "srf_paramdesc_outlineproperties": "De Leß met Eijeschaffte, di als Övverschreffte för en Jlidderung aanjezeijsch wääde sulle, met Kommas dozwesche",
+ "srf_printername_sum": "De Zahle zosammejetrocke",
+ "srf_printername_average": "Der Schnett vun dä Zahle",
+ "srf_printername_max": "De kleinßte Nommer",
+ "srf_printername_min": "De jüüßte Nommer",
+ "srf_paramdesc_limit": "De jrüüßte Zahl Sigge för dren ze söhke",
+ "srf_printername_timeline": "De Reih noh de Zigk",
+ "srf_printername_eventline": "De Reih noh dämm, wat vörjekumme es",
+ "srf_paramdesc_timelinebands": "Jitt aan, wat för en Zickraster aanjezeijsch wääde sulle.",
+ "srf_paramdesc_timelineposition": "Läät faß, woh de Zicklinnesch et eetz drop ußjereschdt es.",
+ "srf_paramdesc_timelinestart": "Ene Eijeschaff iere Name, di jebruch weed, öm ene eezte Zickpungk faßzelääje",
+ "srf_paramdesc_timelineend": "Ene Eijeschaff iere Name, di jebruch weed, öm ene zweijte Zickpungk faßzelääje",
+ "srf_paramdesc_timelinesize": "De Hühde vun dä Zick-Linnesch",
+ "srf_paramdesc_views": "De Aansėschte för aanzezeije",
+ "srf_paramdesc_facets": "De Eijeschaffte, di för jeede Sigg annjezeijsch wääde sulle",
+ "srf_paramdesc_lens": "Ene Schabloon iere Name, woh mer de Eijeschaffte vun ene Sigg aanzeije lohße kann",
+ "srf_printername_googlebar": "E Balleke-Dijajramm vun <i lang=\"en\">Google</i>",
+ "srf_printername_googlepie": "E Kreijß-Dijajramm vun <i lang=\"en\">Google</i>",
+ "srf_paramdesc_chartheight": "Dämm Dijajramm sing Hühde en Pixelle",
+ "srf_paramdesc_chartwidth": "Dämm Dijajramm sing Breedt en Pixelle",
+ "srf_paramdesc_headersep": "Et Trännzeijschen zwesche dä nahme för Eijschaffte un däm Wäät för en Eijeschaff, wann dä Parramehter <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">headers</code> obb ene Wäät „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">show</code>“ udder „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">plain</code>“ jesaz weed.",
+ "srf-printername-graph": "Dijajramm",
+ "srf-printername-ultree": "ene Boum met Leßte met Pongkte",
+ "srf-printername-oltree": "ene Boum met Leßte met Nommere"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ku-latn.json b/www/wiki/extensions/SemanticResultFormats/i18n/ku-latn.json
new file mode 100644
index 00000000..a4776f81
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ku-latn.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "George Animal"
+ ]
+ },
+ "srf-module-loading": "Tê barkirin...",
+ "srf-ui-common-label-refresh": "Nû bike",
+ "srfc_today": "ÃŽro",
+ "srf_paramdesc_graphname": "Sernav",
+ "srf-ui-eventcalendar-label-today": "ÃŽro",
+ "srf-ui-eventcalendar-label-month": "Meh",
+ "srf-ui-eventcalendar-label-week": "Hefte",
+ "srf-ui-eventcalendar-label-day": "Roj",
+ "srf-ui-eventcalendar-label-allday": "Bi tevahiya rojê",
+ "srf-ui-mediaplayer-label-play": "Bilêze"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ky.json b/www/wiki/extensions/SemanticResultFormats/i18n/ky.json
new file mode 100644
index 00000000..7ab2e62d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ky.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Growingup"
+ ]
+ },
+ "srf-module-loading": "Жүктөө...",
+ "srf-ui-common-label-source": "Булак",
+ "srf_printername_gallery": "ГалереÑ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/lb.json b/www/wiki/extensions/SemanticResultFormats/i18n/lb.json
new file mode 100644
index 00000000..11f0a5b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/lb.json
@@ -0,0 +1,136 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "Nemo bis"
+ ]
+ },
+ "prefs-srf-eventcalendar-options": "Optioune vum Kalenner vun den Eventementer",
+ "prefs-srf-datatables-options": "Optioune vun den Tabelle vun Donnéeën",
+ "srf-module-loading": "Lueden...",
+ "srf-paramdesc-height": "Héicht",
+ "srf-paramdesc-width": "Breet",
+ "srf-navigation-previous": "Vireg",
+ "srf-ui-navigation-prev": "Vireg",
+ "srf-ui-navigation-next": "Nächst",
+ "srf-ui-common-label-source": "Quell",
+ "srf-ui-tooltip-title-options": "Optiounen",
+ "srf-ui-tooltip-title-legend": "Erklärung",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Aktualiséieren",
+ "srf-ui-common-label-parameters": "Parameteren",
+ "srf-ui-common-label-query": "Ufro",
+ "srf-error-option-mix": "Optioun ($1) ass net disponibel",
+ "srf-error-missing-layout": "Den Diagramm oder d'Graphik kann net gewise gi well de Layout feelt.",
+ "srfc_previousmonth": "Virege Mount",
+ "srfc_nextmonth": "Nächste Mount",
+ "srfc_today": "Haut",
+ "srfc_gotomonth": "Géi op de Mount",
+ "srf_printername_calendar": "Monatleche Kalenner",
+ "srf_paramdesc_calendarlang": "De Code vun der Sprooch an där de Kalenner gewise gëtt",
+ "srf-paramdesc-calendar-startmonth": "De Mound deen am Kalenner am Ufank gewise gëtt (Standard ass den aktuelle Mound)",
+ "srf_printername_vcard": "Export als vCard",
+ "srf_icalendar_link": "iKalenner",
+ "srf_printername_icalendar": "Export als iCalendar",
+ "srf_paramdesc_icalendartitle": "Den Titel vum Kalenner-Fichier",
+ "srf_paramdesc_icalendardescription": "D'Beschreiwung vum Kalenner-Fichier",
+ "srf_printername_bibtex": "Export als BibTeX",
+ "srf_outline_novalue": "Kee Wäert",
+ "srf_printername_sum": "Total vun den Zuelen",
+ "srf_printername_average": "Duerchschnëtt vun den Zuelen",
+ "srf_printername_max": "Maximal Zuel",
+ "srf_printername_min": "Minimal Zuel",
+ "srf_paramdesc_limit": "D'Maximal Zuel vu Säite fir ofzefroen",
+ "srf_printername_earliest": "Éischte Kéier",
+ "srf_printername_latest": "Leschte Kéier",
+ "srf_printername_timeline": "Chronologie",
+ "srf_printername_eventline": "Chronologie vun den Evenementer",
+ "srf_paramdesc_timelinesize": "D'Héicht vun der Zäitläischt",
+ "srf-timeline-allresults": "Méi Resultater fir dës Ufro.",
+ "srf-timeline-nojs": "JavaScript muss aktivéiert si fir déi interaktiv Zäitläischt benotzen ze kënnen.",
+ "srf_paramdesc_views": "Déi Usiichten déi gewise solle ginn",
+ "srf_paramdesc_lens": "Den Numm vun enger Schabloun mat där Säiteneegeschafte gewise ginn",
+ "srf_printername_googlebar": "Google-Sailen-Diagramm",
+ "srf_printername_googlepie": "Google-Taarten-Diagramm",
+ "srf_paramdesc_chartheight": "Gitt d'Héicht (a Pixel) vun der Grafik un",
+ "srf_paramdesc_chartwidth": "Gitt d'Breet (a Pixel) vun der Grafik un",
+ "srf_paramdesc_charttitle": "Den Titel vum Diagramm",
+ "srf_paramdesc_barcolor": "D'Faarf vun de Balken",
+ "srf_paramdesc_bardirection": "Spezifizéiert d'Ausriichtung vum Balken-Diagramm",
+ "srf_paramdesc_barnumbersaxislabel": "D'Etiquette fir d'Achs vun den Zuelen",
+ "srf-paramdesc-minvalue": "De klengste Wäert,deen op der Y-Achs gewise soll ginn",
+ "srf-paramdesc-charttext": "Textbeschreiwung vum Diagramm",
+ "srf-ui-gridview-label-chart-tab": "Diagramm",
+ "srf-ui-gridview-label-data-tab": "Donnéeën",
+ "srf-ui-gridview-label-info-tab": "Informatioun",
+ "srf_printername_gallery": "Galerie",
+ "srf_paramdesc_perrow": "D'Zuel vu Biller pro Rei",
+ "srf_paramdesc_widths": "D'Breet vun de Biller",
+ "srf_paramdesc_heights": "D'Héicht vun de Biller",
+ "srf_paramdesc_autocaptions": "Den NUmm vum Fichier als Beschreiwung benotzen, wa keng ugi gouf",
+ "srf-gallery-navigation-previous": "Vireg",
+ "srf-gallery-navigation-next": "Nächst",
+ "srf-gallery-overlay-count": "Bild $1 vu(n) $2",
+ "srf-gallery-image-url-error": "D'Bild gouf net fonnt.",
+ "srf_printername_array": "Tabell",
+ "srf-printername-graph": "Grafik",
+ "srf-paramdesc-graphname": "Leet den Titel vun der Grafik fest",
+ "srf-paramdesc-graphsize": "Leet d'Gréisst vun der Grafik (a Pixel) fest",
+ "srf-paramdesc-graphlegend": "Leet fest ob d'Erklärung (Legend) vum Grafik gewise gi soll oder net",
+ "srf-paramdesc-graphlabel": "Lett d'Etiquette vun der Grafik fest",
+ "srf-paramdesc-rankdir": "Leet d'Richtung vun de Feiler fest",
+ "srf-paramdesc-graphlink": "Leet fest ob d'Kniet op hier Wikisäite verlinke sollen",
+ "srf-paramdesc-graphcolor": "Leet d'Faarf vun der Grafik fest",
+ "srf-paramdesc-redlinkcolor": "Leet d'Schrëftfaarf fir rout Linke fest",
+ "srf-paramdesc-showdiscussion": "Leet fest ob eng Diskussioun gerendert gi soll",
+ "srf-paramdesc-showredlinks": "Leet fest ob rout Linke sollen nogekuckt an ervirgehuewe ginn",
+ "srf-ui-datatables-label-conditions": "Bedingungen",
+ "srf-ui-datatables-label-parameters": "Parameteren",
+ "srf-ui-datatables-label-information": "Informatioun",
+ "srf-ui-datatables-label-update-success": "D'Aktualisatioun vun der Datentabell ass ofgeschloss",
+ "srf-ui-datatables-label-update-error": "D'Aktualiséierung vun der Tabell huet net funktionéiert.",
+ "srf-ui-datatables-label-placeholder-column-search": "Sichen...",
+ "srf-ui-datatables-label-multiselect-column-header": "Disponibel Kolonnen",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Astellunge vum Filter",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLoadingRecords": "Lueden...",
+ "srf-ui-datatables-label-sProcessing": "Verschaffen...",
+ "srf-ui-datatables-label-sSearch": "Sichen:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Éischt",
+ "srf-ui-datatables-label-oPaginate-sLast": "Lescht",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Vireg",
+ "srf-printername-tree": "Bam",
+ "srf-tree-rootinvalid": "$1 ass kee valabelen Titel fir eng Säit",
+ "srf-printername-slideshow": "SlideShow",
+ "srf-paramdesc-delay": "Den zäitlechen Ofstand tëschent de Sliden a Sekonnen",
+ "srf-paramdesc-effect": "Den Iwwergang dee vun engem Slide op den nächste Slide benotzt gëtt",
+ "srf-printername-filtered": "Gefiltert",
+ "srf-paramdesc-filtered-map-height": "D'Héicht vun der Kaart.",
+ "srf-filtered-selectorlabel-list": "Lëscht",
+ "srf-filtered-selectorlabel-table": "Tabell",
+ "srf-filtered-selectorlabel-calendar": "Kalenner",
+ "srf-filtered-selectorlabel-map": "Kaart",
+ "srf-filtered-value-filter-and": "AN",
+ "srf-filtered-value-filter-or": "ODER",
+ "srf-filtered-value-filter-placeholder": "Sicht e Wäert fir de Filter eraus",
+ "srf-printername-d3chart": "D3 Grafik",
+ "srf-paramdesc-zoom": "Zoom aschalten",
+ "srf-paramdesc-pageitems": "Objete pro Säit:",
+ "srf-printername-eventcalendar": "Manifestatiounskalenner",
+ "srf-paramdesc-calendarfirstday": "Den Dag mat deem all Woch ufänkt",
+ "srf-ui-eventcalendar-label-today": "Haut",
+ "srf-ui-eventcalendar-label-month": "Mount",
+ "srf-ui-eventcalendar-label-week": "Woch",
+ "srf-ui-eventcalendar-label-day": "Dag",
+ "srf-ui-eventcalendar-label-listmonth": "Mount (Lëscht)",
+ "srf-ui-eventcalendar-label-listweek": "Woch (Lëscht)",
+ "srf-ui-eventcalendar-label-listday": "Dag (Lëscht)",
+ "srf-ui-eventcalendar-label-allday": "Ganzen Dag",
+ "srf-ui-eventcalendar-click-popup": "Wëllt dir en Evenement uleeën?",
+ "srf-paramdesc-unit": "Eenheet",
+ "srf-ui-mediaplayer-label-previous": "Vireg",
+ "srf-ui-mediaplayer-label-pause": "Paus",
+ "srf-ui-mediaplayer-label-stop": "Stopp",
+ "srf-paramdesc-gantt-diagramtitle": "Numm vum Diagramm",
+ "srf-printername-gantt": "Gantt"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/lki.json b/www/wiki/extensions/SemanticResultFormats/i18n/lki.json
new file mode 100644
index 00000000..e92020b9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/lki.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hosseinblue"
+ ]
+ },
+ "srf-ui-common-label-source": "بÙÙ†Ú†Û€Ú©/مۀنبۀع",
+ "srf-ui-eventcalendar-label-month": "مانگ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/lt.json b/www/wiki/extensions/SemanticResultFormats/i18n/lt.json
new file mode 100644
index 00000000..601ea992
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/lt.json
@@ -0,0 +1,175 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg",
+ "Zygimantus",
+ "Eitvys200",
+ "Nemo bis"
+ ]
+ },
+ "srf-module-loading": "Kraunama...",
+ "srf-paramdesc-layout": "Galimas išdėstymas",
+ "srf-paramdesc-height": "Aukštis",
+ "srf-paramdesc-width": "Plotis",
+ "srf-module-nomatch": "Atitikmenų nerasta.",
+ "srf-paramdesc-charttype": "Galimas diagramos tipas",
+ "srf-navigation-previous": "Ankstesnis",
+ "srf-ui-navigation-prev": "Ankstesnis",
+ "srf-ui-navigation-next": "Kitas",
+ "srf-ui-common-label-source": "Å altinis",
+ "srf-ui-common-label-datasource": "Duomenų šaltinis",
+ "srf-ui-common-label-help-section": "pagalbos skyrius",
+ "srf-ui-tooltip-title-options": "Nustatymai",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtras",
+ "srf-ui-common-label-refresh": "Atnaujinti",
+ "srf-ui-common-label-parameters": "Parametrai",
+ "srfc_previousmonth": "Praeitas mÄ—nuo",
+ "srfc_nextmonth": "Ateinantis mÄ—nuo",
+ "srfc_today": "Å iandien",
+ "srfc_gotomonth": "Eiti į mėnesį",
+ "srf_printername_calendar": "MÄ—nesio kalendorius",
+ "srf_paramdesc_calendarlang": "Kalbos, kuria rodyti kalendorių, kodas",
+ "srf_printername_vcard": "vCard eksportavimas",
+ "srf_printername_icalendar": "iCalendar eksportavimas",
+ "srf_paramdesc_icalendartitle": "Kalendoriaus failo pavadinimas",
+ "srf_paramdesc_icalendardescription": "Kalendoriaus failo aprašymas",
+ "srf_printername_bibtex": "BibTeX eksportavimas",
+ "srf_outline_novalue": "Nėra reikšmės",
+ "srf_printername_sum": "SkaiÄių suma",
+ "srf_printername_average": "SkaiÄių vidurkis",
+ "srf_printername_max": "Maksimalus skaiÄius",
+ "srf_printername_min": "Minimalus skaiÄius",
+ "srf_printername_median": "SkaiÄių mediana",
+ "srf_printername_earliest": "AnksÄiausias laikas",
+ "srf_printername_latest": "VÄ—liausias laikas",
+ "srf_printername_timeline": "Laiko juosta",
+ "srf_printername_eventline": "Įvykių juosta",
+ "srf_paramdesc_timelinesize": "Laiko juostos aukštis",
+ "srf-timeline-allresults": "Kiti šios užklausos rezultatai.",
+ "srf-timeline-nojs": "Jums reikia įgalinti JavaScript, kad peržiūrėtumėte interaktyvią laiko juostą.",
+ "srf_printername_googlebar": "Google stulpelinÄ— diagrama",
+ "srf_printername_googlepie": "Google skritulinÄ— diagrama",
+ "srf-printername-jqplotchart": "jqPlot diagrama",
+ "srf-printername-jqplotseries": "jqPlot serija",
+ "srf_paramdesc_chartheight": "Nurodykite diagramos ar grafiko aukštį (pikseliais)",
+ "srf_paramdesc_chartwidth": "Nurodykite diagramos ar grafiko plotį (pikseliais)",
+ "srf_paramdesc_charttitle": "Diagramos pavadinimas",
+ "srf_paramdesc_barcolor": "Nurodykite diagramos spalvas",
+ "srf_paramdesc_bardirection": "Nurodykite diagramos kryptį",
+ "srf-paramdesc-direction": "Nurodykite diagramos ar grafiko kryptį",
+ "srf_paramdesc_barnumbersaxislabel": "SkaiÄių aÅ¡ies pavadinimas",
+ "srf-paramdesc-minvalue": "Minimali reikšmė, rodoma ant Y ašies",
+ "srf-paramdesc-chartlegend": "Diagramos legendos pozicija",
+ "srf-paramdesc-datalabels": "Diagramos/grafiko duomenų etiketės",
+ "srf-paramdesc-charttext": "Aprašomas diagramos tekstas",
+ "srf-paramdesc-chartclass": "Papildoma CSS klasÄ—",
+ "srf-paramdesc-theme": "Pasirinkite tinklo temÄ…",
+ "srf-paramdesc-chartcolor": "Priskirti individualias diagramos spalvas",
+ "srf-paramdesc-colorscheme": "Pasirinkti spalvų schemą",
+ "srf-paramdesc-valueformat": "Nurodykite reikšmių formatavimo taisyklę",
+ "srf-ui-gridview-label-item": "Duomenų objektas",
+ "srf-ui-gridview-label-value": "Duomenų reikšmė",
+ "srf-ui-gridview-label-series": "Duomenų serija",
+ "srf-ui-gridview-label-chart-tab": "Diagrama",
+ "srf-ui-gridview-label-data-tab": "Duomenys",
+ "srf-ui-gridview-label-info-tab": "Informacija",
+ "srf_printername_gallery": "Galerija",
+ "srf_paramdesc_perrow": "Paveikslėlių eilutėje kiekis",
+ "srf_paramdesc_widths": "Paveikslėlių plotis",
+ "srf_paramdesc_heights": "Paveikslėlių aukštis",
+ "srf_paramdesc_autocaptions": "Naudoti failo pavadinimą kaip antrašte, kai jokia nėra pateikta",
+ "srf_paramdesc_fileextensions": "Kai failo pavadinimas naudojamas kaip antraštė kartu pateikti ir failo plėtinį",
+ "srf-paramdesc-navigation": "IÅ¡planavimo navigacijos valdymas",
+ "srf-gallery-navigation-previous": "Ankstesnis",
+ "srf-gallery-navigation-next": "Kitas",
+ "srf-gallery-overlay-count": "Paveikslėlis $1 iš $2",
+ "srf-gallery-image-url-error": "PaveikslÄ—lis nebuvo rastas.",
+ "srf_printername_tagcloud": "Žymių debesis",
+ "srf_paramdesc_increase": "Kaip padidinti žymių dydį",
+ "srf_paramdesc_tagorder": "Žymių tvarka",
+ "srf-printername-graph": "Grafikas",
+ "srf-paramdesc-graphname": "Pavadinimas",
+ "srf-paramdesc-graphsize": "Grafiko dydis (pikseliais)",
+ "srf-paramdesc-graphlegend": "Ar rodyti grafiko legendÄ…",
+ "srf-paramdesc-graphlabel": "Grafiko etiketÄ—",
+ "srf-paramdesc-rankdir": "RodyklÄ—s kryptis",
+ "srf-paramdesc-graphlink": "Grafiko nuoroda",
+ "srf-paramdesc-graphcolor": "Grafiko spalva",
+ "srf-ui-datatables-label-conditions": "SÄ…lygos",
+ "srf-ui-datatables-label-parameters": "Parametrai",
+ "srf-ui-datatables-label-filters": "Stulpelio filtrai ir paieška",
+ "srf-ui-datatables-label-information": "Informacija",
+ "srf-ui-datatables-panel-disclaimer": "Parametrai ir sÄ…lygos gali bÅ«ti pakeistos, taÄiau bet koks pakeitimas yra laikinas ir nebus iÅ¡saugotas po puslapio atnaujinimo.",
+ "srf-ui-datatables-label-update-success": "LentelÄ—s atnaujinimas buvo sÄ—kmingas",
+ "srf-ui-datatables-label-update-error": "LentelÄ—s atnaujinimas nepavyko.",
+ "srf-ui-datatables-label-placeholder-column-search": "Ieškoti...",
+ "srf-ui-datatables-label-multiselect-column-header": "Galimi stulpeliai",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filtro nustatymai",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Stulpeliai yra matomi",
+ "srf-ui-datatables-label-sEmptyTable": "Lentelėje nėra prienamių duomenų",
+ "srf-ui-datatables-label-sInfo": "Rodoma _START_ iki _END_ iš _TOTAL_ įrašų",
+ "srf-ui-datatables-label-sInfoEmpty": "Rodoma 0 iki 0 iš 0 įrašų",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtruota iš _MAX_ visų įrašų)",
+ "srf-ui-datatables-label-sLengthMenu": "Rodyti _MENU_ įrašus",
+ "srf-ui-datatables-label-sLoadingRecords": "Įkeliama…",
+ "srf-ui-datatables-label-sProcessing": "Apdorojama...",
+ "srf-ui-datatables-label-sSearch": "Paieška:",
+ "srf-ui-datatables-label-sZeroRecords": "Nerasta atitinkanÄių įrašų",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Pirmas",
+ "srf-ui-datatables-label-oPaginate-sLast": "Paskutinis",
+ "srf-ui-datatables-label-oPaginate-sNext": "Kitas",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Ankstesnis",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": aktyvuokite, kad rūšiuotumėte stulpelius didėjimo tvarka",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": aktyvuokite, kad rūšiuotumėte stulpelius mažėjimo tvarka",
+ "srf-printername-tree": "Medis",
+ "srf-tree-rootinvalid": "$1 nÄ—ra galimas puslapio pavadinimas.",
+ "srf-printername-slideshow": "Skaidrių peržiūra",
+ "srf-paramdesc-delay": "Pauzė tarp skaidrių sekundėmis",
+ "srf-paramdesc-navigation-controls": "Ar rodyti navigacijos valdiklius",
+ "srf-paramdesc-effect": "Efektas naudojamas skaidrių perjungimui",
+ "srf-printername-filtered": "Filtruota",
+ "srf-paramdesc-filtered-list-template": "Šablonas, kuri naudoti formatuojant sąrašo įrašus.",
+ "srf-filtered-selectorlabel-list": "Sąrašas",
+ "srf-filtered-selectorlabel-table": "LentelÄ—",
+ "srf-filtered-selectorlabel-calendar": "Kalendorius",
+ "srf-printername-d3chart": "D3 diagrama",
+ "srf-paramdesc-group": "Serija sugrupuota pagal",
+ "srf-paramdesc-zoom": "Įgalinti priartinimą",
+ "srf-paramdesc-datatable": "Įgalinti duomenų bazę",
+ "srf-paramdesc-listtype": "Nurodykite sąrašo tipą",
+ "srf-paramdesc-widget": "Galimas valdiklis",
+ "srf-paramdesc-pageitems": "Elementai viename puslapyje",
+ "srf-printername-eventcalendar": "Įvykių kalendorius",
+ "srf-paramdesc-calendarfirstday": "Diena, kuria prasideda kiekviena savaitÄ—",
+ "srf-paramdesc-calendardefaultview": "Pradinis vaizdas, kai kalendorius įkeliamas",
+ "srf-paramdesc-calendarlegend": "Nurodo legendos pozicijÄ… ir priskiria filtro nustatymus",
+ "srf-ui-eventcalendar-label-today": "Å iandien",
+ "srf-ui-eventcalendar-label-month": "MÄ—nesis",
+ "srf-ui-eventcalendar-label-week": "SavaitÄ—",
+ "srf-ui-eventcalendar-label-day": "Diena",
+ "srf-ui-eventcalendar-label-allday": "Visa diena",
+ "srf-ui-eventcalendar-label-update-success": "Įvykių kalendoriaus atnaujinimas buvo sėkmingas.",
+ "srf-ui-eventcalendar-label-update-error": "Įvykių kalendoriaus atnaujinimas nepavyko.",
+ "srf-ui-eventcalendar-click-popup": "Ar norite sukurti įvykį?",
+ "srf-paramdesc-yaxislabel": "Aprašymas, rodomas ant y ašies",
+ "srf-paramdesc-xaxislabel": "Aprašymas, rodomas ant x ašies",
+ "srf-paramdesc-unit": "Vienetas",
+ "srf-printername-media": "Medijos grotuvas",
+ "srf-paramdesc-mediainspector": "Rodo išsamią informaciją apie nurodytą medijos elementą",
+ "srf-ui-mediaplayer-label-previous": "Ankstesnis",
+ "srf-ui-mediaplayer-label-play": "Groti",
+ "srf-ui-mediaplayer-label-pause": "PauzÄ—",
+ "srf-ui-mediaplayer-label-next": "Kitas",
+ "srf-ui-mediaplayer-label-stop": "Sustabdyti",
+ "srf-ui-mediaplayer-label-mute": "Nutildyti",
+ "srf-ui-mediaplayer-label-unmute": "įjungti garsą",
+ "srf-ui-mediaplayer-label-volume-max": "Maksimalus garsas",
+ "srf-ui-mediaplayer-label-shuffle": "Maišyti",
+ "srf-ui-mediaplayer-label-shuffle-off": "Nemaišyti",
+ "srf-ui-mediaplayer-label-repeat": "Kartoti",
+ "srf-ui-mediaplayer-label-repeat-off": "Nekartoti",
+ "srf-ui-mediaplayer-label-full-screen": "Visas ekranas",
+ "srf-ui-mediaplayer-label-restore-screen": "Atkurti ekranÄ…",
+ "srf-spreadsheet-link": "SkaiÄiuoklÄ—"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/lv.json b/www/wiki/extensions/SemanticResultFormats/i18n/lv.json
new file mode 100644
index 00000000..54cfd71a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/lv.json
@@ -0,0 +1,34 @@
+{
+ "@metadata": {
+ "authors": [
+ "GreenZeb",
+ "Papuass"
+ ]
+ },
+ "srf-module-loading": "IelÄdē…",
+ "srf-paramdesc-height": "Augstums",
+ "srf-paramdesc-width": "Platums",
+ "srf-ui-common-label-source": "Avots",
+ "srf-ui-common-label-datasource": "Datu avots",
+ "srf-ui-common-label-help-section": "palīdzības sadaļa",
+ "srfc_previousmonth": "Iepriekšējais mēnesis",
+ "srfc_nextmonth": "NÄkamais mÄ“nesis",
+ "srfc_today": "Å odiena",
+ "srfc_gotomonth": "Doties uz mēnesi",
+ "srf_printername_vcard": "vCard eksports",
+ "srf_printername_icalendar": "iCalendar eksports",
+ "srf_printername_bibtex": "BibTeX eksports",
+ "srf_printername_gallery": "Galerija",
+ "srf-filtered-selectorlabel-list": "Saraksts",
+ "srf-filtered-selectorlabel-calendar": "KalendÄrs",
+ "srf-printername-d3chart": "D3 diagramma",
+ "srf-ui-eventcalendar-label-today": "Å odiena",
+ "srf-ui-eventcalendar-label-month": "MÄ“nesis",
+ "srf-ui-eventcalendar-label-week": "Nedēļa",
+ "srf-ui-eventcalendar-label-day": "Diena",
+ "srf-ui-eventcalendar-label-allday": "Visu dienu",
+ "srf-printername-dygraphs": "Dygraphs diagramma",
+ "srf-paramdesc-datasource": "Avots, no kurienes dati ir pieejami. AtļautÄs vÄ“rtÄ«bas: fails, izejas dati un URL. NoklusÄ“tais: fails",
+ "srf-paramdesc-unit": "Vienība",
+ "srf-ui-mediaplayer-label-repeat": "AtkÄrtot"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/mk.json b/www/wiki/extensions/SemanticResultFormats/i18n/mk.json
new file mode 100644
index 00000000..28a6dfe8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/mk.json
@@ -0,0 +1,303 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06",
+ "Nemo bis",
+ "Vlad5250"
+ ]
+ },
+ "srf-desc": "Дополнителни формати на иÑходот за барања од Семантички МедијаВики",
+ "prefs-srf": "Додаток:Формати на Ñемантички иÑход",
+ "srf-prefs-intro-text": "Го воÑпоÑтавивте додатокот „Формати на Ñемантички иÑход“. Дополнителна помош ќе добиете на Ñтраницата за [https://www.semantic-mediawiki.org/wiki/Help:Result_formats формати на иÑходот].",
+ "prefs-srf-eventcalendar-options": "ПоÑтавки на Календарот на наÑтани",
+ "srf-prefs-eventcalendar-options-update-default": "Овозможи [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматÑка поднова] на наÑтаните во календарот при превчитување на Ñтраницата",
+ "srf-prefs-eventcalendar-options-paneview-default": "Овозможи надгледен поглед по оÑновно",
+ "prefs-srf-datatables-options": "Ðагодувања за Податочните таблици",
+ "srf-prefs-datatables-options-update-default": "Овозможи [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматÑки поднови] на Ñодржината во табелите при превчитување на Ñтраницата",
+ "srf-prefs-datatables-options-cache-default": "Овозможи [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage меÑно Ñкладирање] за да Ñе подобри времето на одговор",
+ "srf-module-loading": "Вчитувам...",
+ "srf-paramdesc-layout": "РаÑпоред на раÑполагање",
+ "srf-paramdesc-height": "ВиÑина",
+ "srf-paramdesc-width": "Ширина",
+ "srf-paramdesc-class": "Укажување на дополнителна клаÑа на каÑкадни ÑтилÑки Ñтраници",
+ "srf-module-nomatch": "Ðема Ñовпаѓања",
+ "srf-paramdesc-charttype": "РаÑположив тип на дијаграм",
+ "srf-navigation-previous": "Претходно",
+ "srf-ui-navigation-prev": "Прет",
+ "srf-ui-navigation-next": "След",
+ "srf-ui-common-label-source": "Извор",
+ "srf-ui-common-label-datasource": "Извор на податоци",
+ "srf-ui-common-label-ajax-error": "ОпÑлужувачот не уÑпеа да Ñе поврзе Ñо овој $1. Превчитајте ја Ñтраницата или конÑултирајте Ñе Ñо овој $2.",
+ "srf-ui-common-label-request-object": "објект за проверка",
+ "srf-ui-common-label-help-section": "дел за помош",
+ "srf-ui-tooltip-title-options": "ПоÑтавки",
+ "srf-ui-tooltip-title-scope": "Делокруг",
+ "srf-ui-tooltip-title-legend": "Легенда",
+ "srf-ui-tooltip-title-filter": "Филтер",
+ "srf-ui-common-label-refresh": "Превчитај",
+ "srf-ui-common-label-parameters": "Параметри",
+ "srf-ui-common-label-query": "Барање",
+ "srf-ui-common-label-paneview": "Ðадгледен поглед",
+ "srf-ui-common-label-daterange": "ДатумÑки опÑег",
+ "srf-ui-widgets-label-parameter-limit": "Граничен параметар",
+ "srf-error-option-mix": "МожноÑта ($1) не е доÑтапна",
+ "srf-error-option-link-all": "МожноÑта ($1) бара параметарот „link“ да биде Ñтавен на „all“",
+ "srf-error-missing-layout": "Табелата/графиконот не може да Ñе прикаже бидејќи недоÑтаÑува раÑпоредот.",
+ "srf-error-jqplot-bubble-data-length": "Табелата/графиконот не може да Ñе прикаже бидејќи недоÑтаÑуваат податоци.",
+ "srf-error-jqplot-stackseries-data-length": "Табелата/графиконот не може да Ñе прикаже бидејќи не Ñекој Ñтолб/ред има иÑÑ‚ број на Ñтавки.",
+ "srf-warn-empy-chart": "Дијаграмот/графиконот е празен или недоÑтаÑуваат податоци",
+ "srf-paramdesc-color": "Со која боја да Ñе означат календарÑките Ñтавки",
+ "srfc_previousmonth": "Претходен меÑец",
+ "srfc_nextmonth": "Следен меÑец",
+ "srfc_today": "ДенеÑ",
+ "srfc_gotomonth": "Оди на меÑецот",
+ "srf_printername_calendar": "МеÑечен календар",
+ "srf_paramdesc_calendarlang": "Кодот на јазикот на кој ќе Ñе прикажува календарот",
+ "srf_paramdesc_calendarcolors": "Бојата за приказ на Ñекое датумÑко ÑвојÑтво (пример: \"Почетен датум=>green,Краен датум=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "Од кој меÑец да почнува приказот на календарот (по оÑновно: тековниот меÑец)",
+ "srf-paramdesc-calendar-startyear": "Од која година да почнува приказот на календарот (по оÑновно: тековната година)",
+ "srf_printername_vcard": "Извоз на vCard",
+ "srf_icalendar_link": "iКалендар",
+ "srf_printername_icalendar": "Извоз на iCalendar",
+ "srf_paramdesc_icalendartitle": "ÐаÑловот на податотеката на календарот",
+ "srf_paramdesc_icalendardescription": "ОпиÑот на податотеката на календарот",
+ "srf_printername_bibtex": "Извоз на BibTeX",
+ "srf_outline_novalue": "Ðема вредноÑÑ‚",
+ "srf_printername_outline": "Преглед",
+ "srf_paramdesc_outlineproperties": "СпиÑок на ÑвојÑтвата за прикажување како заглавија, одделени Ñо запирки",
+ "srf_printername_sum": "Збир од броевите",
+ "srf_printername_average": "ПроÑек од броевите",
+ "srf_printername_max": "Ðајг. допуштен број",
+ "srf_printername_min": "Ðајмал број",
+ "srf_paramdesc_limit": "Ðајвеќе Ñтраници за пребарување",
+ "srf_printername_product": "Производ на броеви",
+ "srf_printername_median": "Средна бројна вредноÑÑ‚",
+ "srf-paramdesc-default": "ОÑновна вредноÑÑ‚ што ќе Ñе прикажува кога нема бројчени Ñтавки",
+ "srf_printername_earliest": "Прва временÑка точка",
+ "srf_printername_latest": "ПоÑледна временÑка точка",
+ "srf_printername_timeline": "ВремеÑлед",
+ "srf_printername_eventline": "Преглед на наÑтани",
+ "srf_paramdesc_timelinebands": "Определува кои ленти ќе Ñе прикажуваат во иÑходот.",
+ "srf_paramdesc_timelineposition": "Определува каде временÑката Ñкала најпрвин ќе Ñе фокуÑира.",
+ "srf_paramdesc_timelinestart": "Име на ÑвојÑтвото кое Ñе кориÑти за определување на првата временÑка точка",
+ "srf_paramdesc_timelineend": "Име на ÑвојÑтвото кое Ñе кориÑти за определување на втората временÑка точка",
+ "srf_paramdesc_timelinesize": "ВиÑината на временÑката Ñкала",
+ "srf-timeline-allresults": "Понатамошнен иÑход од ова барање.",
+ "srf-timeline-nojs": "За да можете да ја гледате интерактивната времеÑлед, ќе треба да имате овозможено JavaScript.",
+ "srf_paramdesc_views": "Погледите за прикажување",
+ "srf_paramdesc_facets": "Збирот ÑвојÑтва кои ќе Ñе прикажуваат на Ñекоја Ñтраница",
+ "srf_paramdesc_lens": "Името на шаблонот Ñо кој ќе Ñе прикажат ÑвојÑтвата на Ñтраницата",
+ "srf_printername_googlebar": "Столбен дијаграм од Google",
+ "srf_printername_googlepie": "Кружен дијаграм од Google",
+ "srf-printername-jqplotchart": "jqPlot-графикон",
+ "srf-printername-jqplotseries": "jqPlot-низа",
+ "srf_paramdesc_chartheight": "Укажување на виÑината на дијаграмот/графикот (во пикÑели)",
+ "srf_paramdesc_chartwidth": "Укажување на ширината на дијаграмот/графикот (во пикÑели)",
+ "srf_paramdesc_charttitle": "ÐаÑловот на графиконот",
+ "srf_paramdesc_barcolor": "Бојата на Ñтолбовите",
+ "srf_paramdesc_bardirection": "Укажете наÑока на Ñтолбниот графикон",
+ "srf-paramdesc-direction": "Укажување на правецот на дијаграмот/графиконот",
+ "srf_paramdesc_barnumbersaxislabel": "ÐÐ°Ñ‚Ð¿Ð¸Ñ Ð·Ð° бројната оÑка",
+ "srf-paramdesc-labelaxislabel": "ÐÐ°Ñ‚Ð¿Ð¸Ñ Ð·Ð° натпиÑната оÑка",
+ "srf-paramdesc-ticklabels": "Овозможување на натпиÑи Ñо штикли",
+ "srf-paramdesc-minvalue": "Ðајмала вредноÑÑ‚ за приказ на Y-оÑката",
+ "srf-paramdesc-pointlabels": "Прикажи податочни точки на графиконот",
+ "srf-paramdesc-chartlegend": "Положба на легендата на графиконот",
+ "srf-paramdesc-datalabels": "Прикажувај натпиÑи за податоци на дијаграмот/графиконот",
+ "srf-paramdesc-charttext": "ОпиÑен текÑÑ‚ за графиконот",
+ "srf-paramdesc-chartclass": "Дополнителна CSS клаÑа",
+ "srf-paramdesc-renderer": "Одберете иÑпиÑник за графиконот",
+ "srf-paramdesc-filling": "Избор на поединечно пополнување",
+ "srf-paramdesc-theme": "Одберете Ñтил на решетката",
+ "srf-paramdesc-chartcolor": "Укажете поединечни бои на графиконот",
+ "srf-paramdesc-colorscheme": "Одберете боен Ñтил",
+ "srf-paramdesc-valueformat": "Укажете правило за форматирање на вредноÑтите",
+ "srf-paramdesc-highlighter": "ИÑтакнувај ги податочните точки",
+ "srf-paramdesc-smoothlines": "Примени алгоритам за измазнување во графиконите Ñо линии",
+ "srf-paramdesc-stackseries": "Прикажи го графиконот како наплаÑтена низа",
+ "srf-paramdesc-seriesgroup": "Одберете групирање на низата",
+ "srf-paramdesc-serieslabel": "Определување на Ð½Ð°Ñ‚Ð¿Ð¸Ñ Ð·Ð° низата",
+ "srf-paramdesc-grouplabel": "Определување на натпиÑот на групата",
+ "srf-paramdesc-chartcursor": "МожноÑÑ‚ за приказ на курÑор во графиконот",
+ "srf-paramdesc-trendline": "Овозможи едновремен приказ на графикон и неговата трендова линија",
+ "srf-paramdesc-gridview": "ИÑтовремено прикажувај графикон и податочни збирови Допуштени вредноÑти: „none“ и „tabs“. По оÑновно: „none“",
+ "srf-paramdesc-paneview": "Укажете каде да Ñе наоѓа квадратот Ñо мал линиÑки графикон. Допуштени вредноÑти: „bottom“, „top“ и „none“. По оÑновно: „bottom“",
+ "srf-paramdesc-infotext": "Прикажување на дополнителни информации во Ñоодветното инфојазиче",
+ "srf-paramdesc-clicktarget": "Зададете целна низа за целна Ñтраница / барање приложена кон URL-то што Ñе повикува кога ќе ÑтиÑнете на календарÑки датум. Ðа пример: clicktarget=Special:FormEdit/ÐаÑтан?ÐаÑтан[Почетен датум]=%clickyear%-%clickmonth%-%clickday%%clicktime%&returnto={{FULLPAGENAME}}.",
+ "srf-ui-gridview-label-item": "Податочна Ñтавка",
+ "srf-ui-gridview-label-value": "Податочна вредноÑÑ‚",
+ "srf-ui-gridview-label-series": "Податочна низа",
+ "srf-ui-gridview-label-chart-tab": "Графикон",
+ "srf-ui-gridview-label-data-tab": "Податоци",
+ "srf-ui-gridview-label-info-tab": "Инфо",
+ "srf_printername_gallery": "Галерија",
+ "srf_paramdesc_perrow": "Број на Ñлики по ред",
+ "srf_paramdesc_widths": "Ширина на Ñликите",
+ "srf_paramdesc_heights": "ВиÑина на Ñликите",
+ "srf_paramdesc_autocaptions": "КориÑти го името на податотеката за Ð¾Ð¿Ð¸Ñ Ð°ÐºÐ¾ не е внеÑен друг",
+ "srf_paramdesc_fileextensions": "При кориÑтење на податотечното име како опиÑ, прикажувај ја и наÑтавката",
+ "srf_paramdesc_captionproperty": "Име на Ñемантичкото ÑвојÑтво приÑутно на побараните Ñтраници што ќе Ñе кориÑти како опиÑ",
+ "srf_paramdesc_imageproperty": "Име на Ñемантичкото ÑвојÑтво приÑутно на побараните Ñтраници што ќе поÑочува кои Ñлики да Ñе кориÑтат. Кога е зададено, Ñамите побарани Ñтраници нема да Ñе прикажуваат како Ñлики",
+ "srf-paramdesc-redirects": "Ðазивот на Ñемантичкото ÑвојÑтво на бараните Ñтраници што Ñодржат цел за пренаÑочување",
+ "srf-paramdesc-navigation": "Управување Ñо раÑпоредот на прегледникот",
+ "srf-paramdesc-overlay": "Овозможи препокривање на Ñликите",
+ "srf-gallery-navigation-previous": "Претходно",
+ "srf-gallery-navigation-next": "Следно",
+ "srf-gallery-overlay-count": "Слика $1 од $2",
+ "srf-gallery-image-url-error": "Сликата не е најдена.",
+ "srf_printername_tagcloud": "Облак Ñо ознаки",
+ "srf_paramdesc_includesubject": "Дали да Ñе вклучат имињата на Ñамите теми",
+ "srf_paramdesc_increase": "Како да ги зголемите ознаките",
+ "srf_paramdesc_tagorder": "РедоÑледот на ознаките",
+ "srf_paramdesc_mincount": "Барем колку пати треба да Ñе јави една вредноÑÑ‚ за да биде наведена",
+ "srf_paramdesc_minsize": "Големина на најмалата ознака во проценти",
+ "srf_paramdesc_maxsize": "Големина на најголемите ознаки во проценти",
+ "srf_paramdesc_maxtags": "Ðајголемиот допуштен број на ознаки во облакот",
+ "srf-paramdesc-excludetags": "Изземи ознаки (одделувач: „;“)",
+ "srf_printername_valuerank": "Ранг",
+ "srf_printername_array": "Податочен Ñтрој",
+ "srf_paramdesc_pagetitle": "Дали во иÑходот да Ñе прикажуваат наÑлови на Ñтраници или да Ñе изоÑтавуваат",
+ "srf_paramdesc_hidegaps": "Дали Ñе иÑпишуваат побараните, но недоÑтапни вредноÑти на ÑвојÑтва и запиÑи одделени Ñо одделувачи, или пак да Ñе изоÑтавуваат",
+ "srf_paramdesc_arrayname": "Ðко е зададено, и има додадок за податотечни Ñтроеви (ArrayExtension ), ова ќе Ñоздаде нов Ñтрој Ñо наведеното име (тогаш нема да има видлив извод)",
+ "srf_paramdesc_propsep": "Одделувач помеѓу бараните ÑвојÑтва",
+ "srf_paramdesc_manysep": "Одделувач на вредноÑтите кај повеќевредноÑни ÑвојÑтва",
+ "srf_paramdesc_recordsep": "Одделувач помеѓу вредноÑтите на запиÑните ÑвојÑтва",
+ "srf_paramdesc_headersep": "Одделувач помеѓу името на ÑвојÑтвото и вредноÑта ако \"headers\" е намеÑтено на „show“ или „plain“",
+ "srf_printername_hash": "Тараба",
+ "srf_paramdesc_hashname": "Ðко е зададено, а на раÑполагање е додатокот зе тарабни табели (HashTables), ова ќе Ñоздаде тараба Ñо наведеното име (тогаш нема да има видлив извод)",
+ "srf-printername-graph": "Графикон",
+ "srf-paramdesc-graph-relation": "Одредете дали предметите или именÑките ÑвојÑтва Ñе матични или завиÑни",
+ "srf-paramdesc-graph-nameprop": "Го задава ÑвојÑтвото што ќе Ñе кориÑти како предмет намеÑто фактичкиот предмет, Ñ‚.е. име на Ñтраницата",
+ "srf-paramdesc-graph-nodeshape": "Го задава обликот на Ñекој јазол во графиконот",
+ "srf-paramdesc-graphname": "Го задава наÑловот на графиконот",
+ "srf-paramdesc-graphsize": "Ја задава големината на графиконот во пикÑели",
+ "srf-paramdesc-graphlegend": "Одредете дали да Ñе прикажува легенда за графиконот",
+ "srf-paramdesc-graphlabel": "Го задава натпиÑот на графиконот",
+ "srf-paramdesc-rankdir": "Правец на Ñтрелката",
+ "srf-paramdesc-graphlink": "Ð’Ñ€Ñка за графиконот",
+ "srf-paramdesc-graphcolor": "Боја на графиконот",
+ "srf-paramdesc-graph-wwl": "Граница за прелом (во бр. на знаци)",
+ "srf-printername-datatables": "ПодаточниТабели",
+ "srf-ui-datatables-label-conditions": "УÑлови",
+ "srf-ui-datatables-label-parameters": "Параметри",
+ "srf-ui-datatables-label-filters": "КолонÑки филтер и пребарување",
+ "srf-ui-datatables-label-information": "Информации",
+ "srf-ui-datatables-panel-disclaimer": "Параметрите и уÑловите може да Ñе менуваат, но промените Ñе привремени и Ñе поништуваат Ñо превчитување на Ñтраницата.",
+ "srf-ui-datatables-label-update-success": "Табелата е уÑпешно подновена",
+ "srf-ui-datatables-label-update-error": "Подновата на табелата не уÑпеа.",
+ "srf-ui-datatables-label-placeholder-column-search": "Пребарај...",
+ "srf-ui-datatables-label-content-cache": "Содржината е изведена од меÑниот меѓуÑклад.",
+ "srf-ui-datatables-label-content-server": "Содржината е изведена од опÑлужувачот.",
+ "srf-ui-datatables-label-multiselect-column-header": "РаÑположиви Ñтолбови",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Ðагодувања на филтерот",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Столбовите Ñе видливи",
+ "srf-ui-datatables-label-sEmptyTable": "Ðема раÑположиви податоци во табелата",
+ "srf-ui-datatables-label-sInfo": "Се прикажуваат _START_ до _END_ од вкупно _TOTAL_ запиÑи",
+ "srf-ui-datatables-label-sInfoEmpty": "Се прикажуваат 0 до 0 од вкупно 0 запиÑи",
+ "srf-ui-datatables-label-sInfoFiltered": "(иÑфилтрирано од вкупно _MAX_ запиÑи)",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLengthMenu": "Прикажи Ñтавки на _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "Вчитувам…",
+ "srf-ui-datatables-label-sProcessing": "Обработувам...",
+ "srf-ui-datatables-label-sSearch": "Пребарај:",
+ "srf-ui-datatables-label-sZeroRecords": "Ðе пронајдов Ñоодветни запиÑи",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Прва",
+ "srf-ui-datatables-label-oPaginate-sLast": "ПоÑледна",
+ "srf-ui-datatables-label-oPaginate-sNext": "Следна",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Претходна",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": вклучете за да ги подредите Ñтолбовите нагорно",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": вклучете за да ги подредите Ñтолбовите надолно",
+ "srf-printername-tree": "Дрво",
+ "srf-printername-ultree": "Ðеподредено дрво",
+ "srf-printername-oltree": "Подредено дрво",
+ "srf-tree-noparentprop": "Ðема зададено матично ÑвојÑтво. Дрвото не може да Ñе оформи без наведено матично ÑвојÑтво.",
+ "srf-tree-rootinvalid": "„$1“ не претÑтавува важечки наÑлов на Ñтраница",
+ "srf-paramdesc-tree-parent": "СвојÑтвото што ја Ñодржи матичната Ñтраница",
+ "srf-paramdesc-tree-root": "ОÑновната Ñтраница на дрвото",
+ "srf-paramdesc-tree-startlevel": "Почетниот Ñтепен на дрвото, на пр. за негово вградување во друго дрво",
+ "srf-printername-slideshow": "Сликоред",
+ "srf-paramdesc-delay": "ВременÑкото раÑтојание помеѓу Ñликите во Ñекунди",
+ "srf-paramdesc-navigation-controls": "Дали да Ñе прикаже прегледничкиот управител",
+ "srf-paramdesc-effect": "Ефектот што ќе Ñе кориÑти при префрлањето од Ñлика на Ñлика",
+ "srf-printername-filtered": "Филтрирано",
+ "srf-paramdesc-filtered-views": "Погледите на на раÑполагање во приказот на иÑходот.",
+ "srf-paramdesc-filtered-filter-position": "Положбата на филтрите во Ð¾Ð´Ð½Ð¾Ñ Ð½Ð° погледите. Допуштени вредноÑти: „top“, „bottom“. По оÑновно: „top“.",
+ "srf-paramdesc-filtered-list-type": "Тип на ÑпиÑокот. Допуштени вредноÑти: „list“, „ul“, „ol“. По оÑновно: „list“.",
+ "srf-paramdesc-filtered-list-template": "Шаблонот што Ñе кориÑти за форматирање на Ñтавките во ÑпиÑокот.",
+ "srf-paramdesc-filtered-list-named-args": "Именувајте ги аргументите што му Ñе предаваат на шаблонот.",
+ "srf-paramdesc-filtered-list-introtemplate": "Име на шаблонот за приказ пред иÑходот од пребарувањето, ако го има",
+ "srf-paramdesc-filtered-list-outrotemplate": "Име на шаблонот за приказ по иÑходот од пребарувањето, ако го има",
+ "srf-paramdesc-filtered-calendar-start": "ИÑпиÑот што го Ñодржи датумот на почеток на наÑтанот",
+ "srf-paramdesc-filtered-calendar-end": "ИÑпиÑот што го Ñодржи датумот на завршување на наÑтанот",
+ "srf-paramdesc-filtered-calendar-title": "ИÑпиÑот што го Ñодржи наÑловот на наÑтанот. Ðе може да Ñе кориÑти заедно Ñо наÑловен шаблон.",
+ "srf-paramdesc-filtered-calendar-title-template": "Шаблон Ñо кој Ñе форматира наÑловот на наÑтанот во календарот",
+ "srf-filtered-selectorlabel-list": "СпиÑок",
+ "srf-filtered-selectorlabel-table": "Табела",
+ "srf-filtered-selectorlabel-calendar": "Календар",
+ "srf-filtered-selectorlabel-map": "Карта",
+ "srf-filtered-value-filter-and": "И",
+ "srf-filtered-value-filter-or": "ИЛИ",
+ "srf-filtered-value-filter-placeholder": "Изберете филтерÑка вредноÑÑ‚",
+ "srf-printername-d3chart": "D3-графикон",
+ "srf-printername-timeseries": "Графикон на временÑка низа",
+ "srf-paramdesc-group": "Групирање на низата Ñпоред",
+ "srf-paramdesc-zoom": "Овозможи приближување",
+ "srf-paramdesc-datatable": "Овозможи податочна табела",
+ "srf-timeseries-zoom-out-of-range": "ОпÑегот на приближување не даде доÑтатни податоци",
+ "srf-printername-sparkline": "Графикон во текÑÑ‚",
+ "srf-printername-listwidget": "Елемент за ÑпиÑоци",
+ "srf-paramdesc-listtype": "Укажување на тип на ÑпиÑокот",
+ "srf-paramdesc-widget": "Елемент на раÑполагање",
+ "srf-paramdesc-pageitems": "Ставки по Ñтраница",
+ "srf-printername-eventcalendar": "Календар на наÑтани",
+ "srf-paramdesc-calendarfirstday": "Почетниот ден на Ñедмиците",
+ "srf-paramdesc-calendardefaultview": "Првичниот изглед Ñо вчитувањето на календарот",
+ "srf-paramdesc-calendarstart": "Почетен датум на календарот (вредноÑта „date“ или „datetime“)",
+ "srf-paramdesc-calendarlegend": "Укажива на кое меÑтото ќе Ñтои легендатата и доделените филтерÑки можноÑти",
+ "srf-paramdesc-dayview": "Овозможува преглед на поедичени денови Ñо ÑтиÑкање на бројот на денот",
+ "srf-ui-eventcalendar-label-today": "ДенеÑ",
+ "srf-ui-eventcalendar-label-month": "МеÑец",
+ "srf-ui-eventcalendar-label-week": "Ðедела",
+ "srf-ui-eventcalendar-label-day": "Ден",
+ "srf-ui-eventcalendar-label-listmonth": "МеÑец (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listweek": "Ðедела (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listday": "Ден (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-allday": "Цел ден",
+ "srf-ui-eventcalendar-format-title-month": "MMMM yyyy г.",
+ "srf-ui-eventcalendar-format-title-week": "d [MMM][ yyyy]{ '&#8212;' d MMM yyyy} г.",
+ "srf-ui-eventcalendar-format-title-day": "dddd d MMM yyyy",
+ "srf-ui-eventcalendar-label-update-success": "Подновата на календарот Ñо наÑтани е уÑпешна.",
+ "srf-ui-eventcalendar-label-update-error": "Ðе уÑпеа подновата на календарот.",
+ "srf-ui-eventcalendar-click-popup": "Дали Ñакате да Ñоздадете наÑтан?",
+ "srf-printername-dygraphs": "Двографен дијаграм",
+ "srf-paramdesc-datasource": "Извор на податоците. Допуштени вредноÑти: „file“, „raw“ и „url“. По оÑновно: „file“",
+ "srf-paramdesc-errorbar": "Укажете ја пругата за грешки што ќе Ñе кориÑти. Допуштени вредноÑти: „fraction“ (интервали на доверба за вредноÑтите), „sigma“ (Ñтандардно отÑтапување на вредноÑтите) и „range“ (прилагодени вредноÑни опÑези)",
+ "srf-paramdesc-movingaverage": "Прикажи го проÑекот за извеÑен број денови (ако укажете <code>zero</code> (нула), тогаш ова ќе значи дека нема подвижен проÑек)",
+ "srf-paramdesc-yaxislabel": "ÐžÐ¿Ð¸Ñ ÑˆÑ‚Ð¾ Ñе прикажува на y-оÑката",
+ "srf-paramdesc-xaxislabel": "ÐžÐ¿Ð¸Ñ ÑˆÑ‚Ð¾ Ñе прикажува на x-оÑката",
+ "srf-paramdesc-unit": "Единица",
+ "srf-printername-pagewidget": "Елемент на Ñтраница",
+ "srf-printername-incoming": "Дојдовни ÑвојÑтва",
+ "srf-paramdesc-min": "Ðајмала или гранична вредноÑÑ‚",
+ "srf-paramdesc-excludeproperty": "ИÑклучување на ÑвојÑтвото од иÑходниот збир",
+ "srf-printername-media": "Мултимедијален изведувач",
+ "srf-paramdesc-mediainspector": "Прикажува подробни информации за даден медиумÑки елемент",
+ "srf-ui-mediaplayer-label-previous": "Претходно",
+ "srf-ui-mediaplayer-label-play": "Пушти",
+ "srf-ui-mediaplayer-label-pause": "Паузирај",
+ "srf-ui-mediaplayer-label-next": "Следно",
+ "srf-ui-mediaplayer-label-stop": "Запри",
+ "srf-ui-mediaplayer-label-mute": "ИÑкл. звук",
+ "srf-ui-mediaplayer-label-unmute": "Вкл. звук",
+ "srf-ui-mediaplayer-label-volume-max": "Ðајг. глаÑноÑÑ‚",
+ "srf-ui-mediaplayer-label-shuffle": "Измешај",
+ "srf-ui-mediaplayer-label-shuffle-off": "ИÑкл. мешање",
+ "srf-ui-mediaplayer-label-repeat": "Повторувај",
+ "srf-ui-mediaplayer-label-repeat-off": "ИÑкл. повторување",
+ "srf-ui-mediaplayer-label-full-screen": "Ðа цел екран",
+ "srf-ui-mediaplayer-label-restore-screen": "Поврати екран",
+ "srf-spreadsheet-link": "Табела",
+ "srf-paramdesc-icalendar-timezone": "СпиÑок на чаÑовни појаÑи одделени Ñо запирки",
+ "srf-paramdesc-gantt-diagramtitle": "Име на дијаграмот",
+ "srf-paramdesc-gantt-diagramtheme": "Тема на дијаграмот"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ml.json b/www/wiki/extensions/SemanticResultFormats/i18n/ml.json
new file mode 100644
index 00000000..51531ae8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ml.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shijualex"
+ ]
+ },
+ "srfc_previousmonth": "à´•à´´à´¿à´žàµà´ž മാസം",
+ "srfc_nextmonth": "à´…à´Ÿàµà´¤àµà´¤ മാസം",
+ "srfc_today": "ഇനàµà´¨àµ",
+ "srfc_gotomonth": "മാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ പോവàµà´•",
+ "srf_icalendar_link": "iകലണàµà´Ÿàµ¼"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/mr.json b/www/wiki/extensions/SemanticResultFormats/i18n/mr.json
new file mode 100644
index 00000000..5620fe89
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/mr.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mahitgar",
+ "V.narsikar"
+ ]
+ },
+ "srfc_previousmonth": "मागचा महीना",
+ "srfc_nextmonth": "पà¥à¤¢à¤šà¤¾ महीना",
+ "srfc_today": "आज",
+ "srfc_gotomonth": "महीनà¥à¤¯à¤¾à¤•à¤¡à¥‡ चला",
+ "srf_icalendar_link": "इ-कैलेंडर",
+ "srf-filtered-selectorlabel-table": "तकà¥à¤¤à¤¾"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ms.json b/www/wiki/extensions/SemanticResultFormats/i18n/ms.json
new file mode 100644
index 00000000..74f3c476
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ms.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "srf_paramdesc_graphname": "Tajuk"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/my.json b/www/wiki/extensions/SemanticResultFormats/i18n/my.json
new file mode 100644
index 00000000..0efd38c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/my.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ninjastrikers"
+ ]
+ },
+ "srfc_today": "ယနေ့"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/myv.json b/www/wiki/extensions/SemanticResultFormats/i18n/myv.json
new file mode 100644
index 00000000..50abd06e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/myv.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Botuzhaleny-sodamo"
+ ]
+ },
+ "srfc_previousmonth": "Йутазь ковÑто",
+ "srfc_nextmonth": "Сы ковÑто",
+ "srfc_today": "Течи"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/nah.json b/www/wiki/extensions/SemanticResultFormats/i18n/nah.json
new file mode 100644
index 00000000..51616f35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/nah.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fluence",
+ "Taresi"
+ ]
+ },
+ "srfc_previousmonth": "Achto mētztli",
+ "srfc_nextmonth": "Niman mētztli",
+ "srfc_today": "Ä€xcÄn",
+ "srfc_gotomonth": "YÄuh mÄ“tzhuÄ«c",
+ "srf-filtered-selectorlabel-table": "Tlapechtli"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/nb.json b/www/wiki/extensions/SemanticResultFormats/i18n/nb.json
new file mode 100644
index 00000000..1684ef06
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/nb.json
@@ -0,0 +1,304 @@
+{
+ "@metadata": {
+ "authors": [
+ "Event",
+ "Nghtwlkr",
+ "Emilbk",
+ "Jon Harald Søby",
+ "Nemo bis",
+ "Jeblad",
+ "Imre Eilertsen"
+ ]
+ },
+ "srf-desc": "Tilleggsformater for Semantic MediaWiki-spørringer",
+ "prefs-srf": "Extenison:Semantic Result Formats",
+ "srf-prefs-intro-text": "Du har installert utvidelsen Semantic Result Formats. For ytterligere assistanse kan du se på [https://www.semantic-mediawiki.org/wiki/Help:Result_formats result formats] hjelpsiden.",
+ "prefs-srf-eventcalendar-options": "Valgmuligheter i hendelseskalenderen.",
+ "srf-prefs-eventcalendar-options-update-default": "Aktiviser [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatiske oppdateringer] av kalenderhendelser ved sideoppdatering",
+ "srf-prefs-eventcalendar-options-paneview-default": "Aktiviser panelvisning som standard",
+ "prefs-srf-datatables-options": "DataTables-valgmuligheter",
+ "srf-prefs-datatables-options-update-default": "Aktiviser [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates automatiske oppdateringer] av tabellinnhold ved sideoppdatering",
+ "srf-prefs-datatables-options-cache-default": "Aktiviser [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage lokal lagring] for å forbedre responstiden",
+ "srf-module-loading": "Laster...",
+ "srf-paramdesc-layout": "Tilgjengelige visninger",
+ "srf-paramdesc-height": "Høyde",
+ "srf-paramdesc-width": "Bredde",
+ "srf-paramdesc-class": "Angi en CSS-klasse til",
+ "srf-module-nomatch": "Ingen treff",
+ "srf-paramdesc-charttype": "Tilgjengelige diagramtyper",
+ "srf-navigation-previous": "Forrige",
+ "srf-ui-navigation-prev": "Forrige",
+ "srf-ui-navigation-next": "Neste",
+ "srf-ui-common-label-source": "Kilde",
+ "srf-ui-common-label-datasource": "Datakilde",
+ "srf-ui-common-label-ajax-error": "Serveren rapporte feil i kommunikasjonen for denne $1. Vær vennlig å oppdatere siden eller sjekk med denne $2.",
+ "srf-ui-common-label-request-object": "etterspurt objekt",
+ "srf-ui-common-label-help-section": "hjelpeavsnitt",
+ "srf-ui-tooltip-title-options": "Valgmuligheter",
+ "srf-ui-tooltip-title-scope": "Avgrensning",
+ "srf-ui-tooltip-title-legend": "Tegnforklaring",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Oppdater",
+ "srf-ui-common-label-parameters": "Parametre",
+ "srf-ui-common-label-query": "Spørring",
+ "srf-ui-common-label-paneview": "Panelvisning",
+ "srf-ui-common-label-daterange": "Datoområde",
+ "srf-ui-widgets-label-parameter-limit": "Grenseparameter",
+ "srf-error-option-mix": "Valgmulighet ($1) er ikke tilgjengelig",
+ "srf-error-option-link-all": "Valgmulighet ($1) krever at parameter \"link\" settes til \"all\"",
+ "srf-error-missing-layout": "Diagrammet/grafen kan ikke vises fordi visningsutformingen mangler",
+ "srf-error-jqplot-stackseries-data-length": "Diagrammet/grafen kan ikke vises fordi stolpene eller linjene har ulikt antall elementer.",
+ "srf-warn-empy-chart": "Diagrammet er tomt fordi det ikke finnes data som kan presenteres.",
+ "srfc_previousmonth": "Forrige måned",
+ "srfc_nextmonth": "Neste måned",
+ "srfc_today": "I dag",
+ "srfc_gotomonth": "Gå til måned",
+ "srf_printername_calendar": "MÃ¥nedlig kalender",
+ "srf_paramdesc_calendarlang": "Språkkoden for språket som kalenderen skal vises i",
+ "srf_paramdesc_calendarcolors": "Fargen som vil brukes for hver datoegenskap (eksempel: \"Start date=>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "Måneden kalendervisningen blir initialisert med (standard er inneværende måned)",
+ "srf-paramdesc-calendar-startyear": "Året kalenderenvisningen blir initialisert med (standard er inneværende år)",
+ "srf_printername_vcard": "vCard-eksport",
+ "srf_icalendar_link": "iKalender",
+ "srf_printername_icalendar": "iCalendar-eksport",
+ "srf_paramdesc_icalendartitle": "Tittelen på kalenderfilen",
+ "srf_paramdesc_icalendardescription": "Beskrivelsen av kalenderfilen",
+ "srf_printername_bibtex": "BibTeX-eksport",
+ "srf_outline_novalue": "Ingen verdi",
+ "srf_printername_outline": "Disposisjon",
+ "srf_paramdesc_outlineproperties": "Listen over egenskaper som skal vises som disposisjonsoverskrifter, adskilt med komma",
+ "srf_printername_sum": "Tallsum",
+ "srf_printername_average": "Gjennomsnitt av tall",
+ "srf_printername_max": "Største tall",
+ "srf_printername_min": "Minste tall",
+ "srf_paramdesc_limit": "Maks antall sider å etterspørre",
+ "srf_printername_product": "Produktet av tallene",
+ "srf_printername_median": "Median av tall",
+ "srf-paramdesc-default": "Standardverdi som vises når det ikke er numeriske resultater",
+ "srf_printername_earliest": "Tidligst tidspunkt",
+ "srf_printername_latest": "Senest tidspunkt",
+ "srf_printername_timeline": "Tidslinje",
+ "srf_printername_eventline": "Hendelseslinje",
+ "srf_paramdesc_timelinebands": "Definerer hvilke bånd som vises i resultatet.",
+ "srf_paramdesc_timelineposition": "Definerer hvor tidslinjen først fokuseres rundt.",
+ "srf_paramdesc_timelinestart": "Et egenskapsnavn brukt for å definere et første tidspunkt",
+ "srf_paramdesc_timelineend": "Et egenskapsnavn brukt for å definere et andre tidspunkt",
+ "srf_paramdesc_timelinesize": "Høyden på tidslinjen",
+ "srf-timeline-allresults": "Flere resultater for denne spørringen",
+ "srf-timeline-nojs": "Du må tillate JavaScript for å kunne se den interaktive tidslinjen.",
+ "srf_paramdesc_views": "Visninger som skal sees",
+ "srf_paramdesc_facets": "Egenskapssettet som skal vises for hver side",
+ "srf_paramdesc_lens": "Navnet på malen som skal vise frem sideegenskapene",
+ "srf_printername_googlebar": "Google stolpediagram",
+ "srf_printername_googlepie": "Google kakediagram",
+ "srf-printername-jqplotchart": "jqPlot-diagram",
+ "srf-printername-jqplotseries": "jqPlot-rekke",
+ "srf_paramdesc_chartheight": "Angi diagrammets høyde, i piksler",
+ "srf_paramdesc_chartwidth": "Angi diagrammes bredde, i piksler",
+ "srf_paramdesc_charttitle": "Tittelen på diagrammet",
+ "srf_paramdesc_barcolor": "Fargen på stolpene",
+ "srf_paramdesc_bardirection": "Angi diagramretning",
+ "srf-paramdesc-direction": "Angi diagrammets retning",
+ "srf_paramdesc_barnumbersaxislabel": "Etiketten for tallaksen",
+ "srf-paramdesc-labelaxislabel": "Etiketten for tallaksen",
+ "srf-paramdesc-ticklabels": "Vis akseverdier",
+ "srf-paramdesc-minvalue": "Minimumsverdi på Y-aksen",
+ "srf-paramdesc-pointlabels": "Visning diagramspesifikke datapunkter",
+ "srf-paramdesc-chartlegend": "Diagramforklaringsposisjon",
+ "srf-paramdesc-datalabels": "Vis dataetiketter",
+ "srf-paramdesc-charttext": "Beskrivende diagramtekst",
+ "srf-paramdesc-chartclass": "Ekstra CSS-klasse",
+ "srf-paramdesc-renderer": "Velg en diagram-fremviser",
+ "srf-paramdesc-filling": "Valg av enkeltutfylling",
+ "srf-paramdesc-theme": "Velg et rutenett-tema",
+ "srf-paramdesc-chartcolor": "Bruk individuelle diagramfarger",
+ "srf-paramdesc-colorscheme": "Velg en fargepalett",
+ "srf-paramdesc-valueformat": "Velg en formateringsregel for verdier",
+ "srf-paramdesc-highlighter": "Vis en datapunktuthever",
+ "srf-paramdesc-smoothlines": "Bruk glatting i linjediagrammer",
+ "srf-paramdesc-stackseries": "Vis diagrammet som en stablet rekke",
+ "srf-paramdesc-seriesgroup": "Velg rekkegruppering",
+ "srf-paramdesc-serieslabel": "Angi rekke-etiketter",
+ "srf-paramdesc-grouplabel": "Angi gruppe-etikett",
+ "srf-paramdesc-chartcursor": "Visningsvalg for diagrampekere",
+ "srf-paramdesc-trendline": "Aktiviser samtidig visning av diagram og tendenslinje",
+ "srf-paramdesc-gridview": "Vis diagram og datasett samtidig. Tillatte verdier: \"none\" og \"tabs\". Standardverdi: \"none\".",
+ "srf-paramdesc-paneview": "Angi posisjonen for panelet som inneholder en liten graf. Tillate verdier er \"bottom\", \"top\" og \"none\". Standardverdi: \"bottom\"",
+ "srf-paramdesc-infotext": "Vis tilleggsinformasjon på en tilhørende info-fane",
+ "srf-paramdesc-clicktarget": "Angi en side eller en spørrestreng som mål når det klikkes på en kalenderdato.",
+ "srf-ui-gridview-label-item": "Dataelement",
+ "srf-ui-gridview-label-value": "Dataverdi",
+ "srf-ui-gridview-label-series": "Datarekke",
+ "srf-ui-gridview-label-chart-tab": "Diagram",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galleri",
+ "srf_paramdesc_perrow": "Antall bilder per rad",
+ "srf_paramdesc_widths": "Bredde på bildene",
+ "srf_paramdesc_heights": "Høyde på bildene",
+ "srf_paramdesc_autocaptions": "Bruk filnavn som bildetekst når denne mangler",
+ "srf_paramdesc_fileextensions": "Hvis filnavn brukes som figurtekst, vis også filtypen",
+ "srf_paramdesc_captionproperty": "Som figurtekst brukes navnet på den semantiske egenskapen tilgjengelig på sidene med spørringer",
+ "srf_paramdesc_imageproperty": "Navnet på en semantisk egenskap for sidene med spørringer som peker to bilder som skal brukes. Hvis satt, blir sidene med spørringer ikke selv vist frem som bilder.",
+ "srf-paramdesc-redirects": "Navnet på en semantisk egenskap til stede på spørringssidene som inneholder omdirigeringsmålet",
+ "srf-paramdesc-navigation": "Navigering for resultatutforming",
+ "srf-paramdesc-overlay": "Aktiviser lagdeling av bilder",
+ "srf-gallery-navigation-previous": "Forrige",
+ "srf-gallery-navigation-next": "Neste",
+ "srf-gallery-overlay-count": "Bilde $1 av $2",
+ "srf-gallery-image-url-error": "Bildet ble ikke funnet",
+ "srf_printername_tagcloud": "Tagg-sky",
+ "srf_paramdesc_includesubject": "Hvis emnetekstene selv bør være med",
+ "srf_paramdesc_increase": "Hvordan du øker størrelsen på taggene",
+ "srf_paramdesc_tagorder": "Tagrekkefølgen",
+ "srf_paramdesc_mincount": "Minste antall forekomster av en verdi for at den skal bli oppført",
+ "srf_paramdesc_minsize": "Størrelsen på de minste taggene i prosent",
+ "srf_paramdesc_maxsize": "Størrelsen på de største taggene i prosent",
+ "srf_paramdesc_maxtags": "Minste antall tagger i skyen",
+ "srf-paramdesc-excludetags": "Ekskluder (skilletegn: \";\")",
+ "srf_printername_valuerank": "Verdirangering",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Angi om sidetitlene skal vises eller skjules i resultatlisten",
+ "srf_paramdesc_hidegaps": "Angi om utilgjengelige egenskaper eller record-verdier adskilt med skilletegn skal vises eller skjules",
+ "srf_paramdesc_arrayname": "Hvis angitt samt at ArrayExtension er tilgjengelig, vil dette opprette et array med det angitte navnet",
+ "srf_paramdesc_propsep": "Skilletegn mellom valgte egenskaper",
+ "srf_paramdesc_manysep": "Skilletegn mellom flere verdier for samme egenskap",
+ "srf_paramdesc_recordsep": "Skilletegn mellom flerverdi-recordegenskaper",
+ "srf_paramdesc_headersep": "Skilletegn mellom egenskapsnavn og -verdi hvis \"overskrifter\" er satt til \"vis\" eller \"vanlig\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Hvis angitt samt at HashTables-utvidelsen er tilgjengelig, vil dette opprette en hashkode med det angitte navnet",
+ "srf-printername-graph": "Graf",
+ "srf-paramdesc-graph-relation": "Angir om subjektene eller navnegenskapene er foreldre eller barn?",
+ "srf-paramdesc-graph-nameprop": "Angir egenskapen som blir brukt som subjekt istedenfor det egentlige subjektet, dvs. sidenavnet",
+ "srf-paramdesc-graph-nodeshape": "Angir formen på hver node i grafen",
+ "srf-paramdesc-graphname": "Angir graftittelen",
+ "srf-paramdesc-graphsize": "Angir grafstørrelsen (i piksler)",
+ "srf-paramdesc-graphlegend": "Angir om en grafbeskrivelse skal vises",
+ "srf-paramdesc-graphlabel": "Angir grafetiketten",
+ "srf-paramdesc-rankdir": "Angir pilretningen",
+ "srf-paramdesc-graphlink": "Angir om nodene skal ha lenke til sine wikisider",
+ "srf-paramdesc-graphcolor": "Angir graffargen",
+ "srf-paramdesc-graph-wwl": "Angir maksimalt antall tegn for en tekstlinje",
+ "srf-paramdesc-clustercolor": "Angir fargene til clusterboksene",
+ "srf-paramdesc-highlight": "Angir noden som skal utheves",
+ "srf-paramdesc-highlightcolor": "Angir fontfargen for uthevet node",
+ "srf-paramdesc-redlinkcolor": "Angir fontfargen for de røde lenkene",
+ "srf-paramdesc-processcategory": "Angir wikikategorien for prosess-stegene.",
+ "srf-paramdesc-showroles": "Viser samhørende roller i grafen",
+ "srf-paramdesc-showstatus": "Angir om status for prosess-stegene skal vises",
+ "srf-paramdesc-showresources": "Viser samsvarende ressurser i grafen",
+ "srf-paramdesc-showdiscussion": "Angir om diskusjonen skasl vises",
+ "srf-paramdesc-showredlinks": "Angir om rødlenkene skal markeres eller utheves",
+ "srf-paramdesc-showcompound": "Angir om de sammensatte nodene, dvs. underprosessene, skal utheves",
+ "srf-paramdesc-debug": "Angir om koden for prosessgrafen skal vise medfølgende pretagger",
+ "srf-paramdesc-graphvalidation": "Fremstiller prosess-stegene uten tilordnet rolle med rødfarge",
+ "srf-printername-datatables": "Datatabeller",
+ "srf-ui-datatables-label-conditions": "Betingelser",
+ "srf-ui-datatables-label-parameters": "Parametre",
+ "srf-ui-datatables-label-filters": "Kolonnefiltre og søk",
+ "srf-ui-datatables-label-information": "Informasjon",
+ "srf-ui-datatables-panel-disclaimer": "Parametre og betingelser kan endres, men slike endringer er midlertidige og borte etter en sideoppdatering.",
+ "srf-ui-datatables-label-update-success": "Tabelloppdateringen var vellykket",
+ "srf-ui-datatables-label-update-error": "Tabelloppdateringen var mislykket",
+ "srf-ui-datatables-label-placeholder-column-search": "Søk...",
+ "srf-ui-datatables-label-content-cache": "Innholdet ble hentet fra det lokale mellomlagret.",
+ "srf-ui-datatables-label-content-server": "Innholdet ble hentet fra serveren.",
+ "srf-ui-datatables-label-multiselect-column-header": "Tilgjengelige kolonner",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filterinnstillinger",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Kolonner er synlige",
+ "srf-ui-datatables-label-sEmptyTable": "Ingen data tilgjengelige i tabellen",
+ "srf-ui-datatables-label-sInfo": "Viser _START_ to _END_ of _TOTAL_ punkter",
+ "srf-ui-datatables-label-sInfoEmpty": "Viser 0 til 0 av 0 punkter",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtrert fra _MAX_ samlede punkter)",
+ "srf-ui-datatables-label-sInfoThousands": "&nbsp;",
+ "srf-ui-datatables-label-sLengthMenu": "Vis _MENU_ punkter",
+ "srf-ui-datatables-label-sLoadingRecords": "Laster...",
+ "srf-ui-datatables-label-sProcessing": "Behandler...",
+ "srf-ui-datatables-label-sSearch": "Søk:",
+ "srf-ui-datatables-label-sZeroRecords": "Ingen samsvarende poster ble funnet",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Første",
+ "srf-ui-datatables-label-oPaginate-sLast": "Siste",
+ "srf-ui-datatables-label-oPaginate-sNext": "Neste",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Forrige",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": aktiviser for å sortere kolonne stigende",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": aktiviser for å sortere kolonne synkende",
+ "srf-printername-tree": "Tre",
+ "srf-printername-ultree": "Unummerert tre (punktlister)",
+ "srf-printername-oltree": "Nummerert tre",
+ "srf-tree-noparentprop": "Ingen foreldreegenskap er oppgitt. Treet kan ikke bygges uten en slik.",
+ "srf-tree-rootinvalid": "$1 er ikke en gyldig sidetittel.",
+ "srf-tree-circledetected": "Sirkelreferanse oppstår når $1 settes inn i treet",
+ "srf-paramdesc-tree-parent": "Egenskapen som peker til foreldresiden",
+ "srf-paramdesc-tree-root": "Rotsiden av treet",
+ "srf-paramdesc-tree-startlevel": "Startnivået til treet, f.eks. for å kunne integrere det med et annet tre",
+ "srf-printername-slideshow": "Lysbildefremvisning",
+ "srf-paramdesc-delay": "Forsinkelsen mellom bilder i sekunder",
+ "srf-paramdesc-navigation-controls": "Vis navigasjonskontroller eller ikke",
+ "srf-paramdesc-effect": "Effekten som brukes ved bytte mellom bilder",
+ "srf-printername-filtered": "Filtrert",
+ "srf-paramdesc-filtered-views": "Visningene som skal være tilgjengelige i resultatvisningen",
+ "srf-paramdesc-filtered-filter-position": "Posisjonen av filtrene i relasjon til visningene. Tillatte verdier: \"top\", \"bottom\". Standard: \"top\".",
+ "srf-paramdesc-filtered-list-type": "Typen liste. Tillatte verdier: \"list\", \"ul\", \"ol\". Standard: \"list\".",
+ "srf-paramdesc-filtered-list-template": "Malen som skal brukes for å formatere listeoppføringene",
+ "srf-paramdesc-filtered-list-named-args": "Navngi parametrene som skal sendes til malen.",
+ "srf-paramdesc-filtered-list-introtemplate": "Navnet på en mal som skal vises før spørringsresultatene, hvis det er noen.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Navnet på en mal som skal vises etter spørringsresultatene, hvis det er noen.",
+ "srf-paramdesc-filtered-calendar-start": "Utskriften som inneholder startdatoen for en hendelse",
+ "srf-paramdesc-filtered-calendar-end": "Utskriften som inneholder sluttdatoen for en hendelse",
+ "srf-paramdesc-filtered-calendar-title": "Utskriften som inneholder tittelen for en hendelse. Denne kan ikke brukes sammen med en tittel-mal.",
+ "srf-paramdesc-filtered-calendar-title-template": "En mal som brukes til å formatere hendelsens tittel i kalenderen",
+ "srf-paramdesc-filtered-map-position": "Utskriften som inneholder geografisk posisjon",
+ "srf-paramdesc-filtered-map-height": "Karthøyden",
+ "srf-paramdesc-filtered-map-zoom": "Zoom-nivået når kartet lastes. Dette kan endres av brukeren.<br>Se: <i>kartnivå min. zoom</i> og <i>kartnivå maks. zoom</i>",
+ "srf-filtered-selectorlabel-list": "Liste",
+ "srf-filtered-selectorlabel-table": "Tabell",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-printername-d3chart": "D3 diagram",
+ "srf-printername-timeseries": "Tidsseriediagram",
+ "srf-paramdesc-group": "Serier gruppert etter",
+ "srf-paramdesc-zoom": "Aktiver zoom",
+ "srf-paramdesc-datatable": "Aktiver en datatabell",
+ "srf-timeseries-zoom-out-of-range": "Zoomnivået gav ingen (eller ikke tilstrekkelig) med data",
+ "srf-printername-sparkline": "Sparkline diagram",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Spesifiser listetypen",
+ "srf-paramdesc-widget": "Tilgjengelig widget",
+ "srf-paramdesc-pageitems": "Elementer per side",
+ "srf-printername-eventcalendar": "Hendelseskalender",
+ "srf-paramdesc-calendarfirstday": "Første dag i uken",
+ "srf-paramdesc-calendardefaultview": "Første visning når kalenderen lastes",
+ "srf-paramdesc-calendarstart": "Startdato for kalenderen (dato- eller dato/tid-verdi)",
+ "srf-paramdesc-calendarlegend": "Spesifiser posisjonen til legenden og tildelte filtervalg",
+ "srf-paramdesc-dayview": "Aktiver dagvisning ved å klikke på nummeret for dagen",
+ "srf-ui-eventcalendar-label-today": "I dag",
+ "srf-ui-eventcalendar-label-month": "MÃ¥ned",
+ "srf-ui-eventcalendar-label-week": "Uke",
+ "srf-ui-eventcalendar-label-day": "Dag",
+ "srf-ui-eventcalendar-label-listmonth": "MÃ¥ned (liste)",
+ "srf-ui-eventcalendar-label-listweek": "Uke (liste)",
+ "srf-ui-eventcalendar-label-listday": "Dag (liste)",
+ "srf-ui-eventcalendar-label-allday": "Hele dagen",
+ "srf-ui-eventcalendar-label-update-success": "Oppdateringen av hendelseskalenderen var vellykket.",
+ "srf-ui-eventcalendar-label-update-error": "Oppdateringen av hendelseskalenderen mislyktes.",
+ "srf-printername-dygraphs": "Dygraphs-diagram",
+ "srf-paramdesc-datasource": "Kilden der dataene er tilgjengelige. Tillatte verdier: \"file\", \"raw\" og \"url\". Standardverdi: \"file\"",
+ "srf-paramdesc-yaxislabel": "Beskrivelse som vises på y-aksen",
+ "srf-paramdesc-xaxislabel": "Beskrivelse som vises på x-aksen",
+ "srf-paramdesc-unit": "Enhet",
+ "srf-printername-pagewidget": "Sidewidget",
+ "srf-printername-media": "Mediespiller",
+ "srf-paramdesc-mediainspector": "Viser detaljert informasjon om et angitt medieelement",
+ "srf-ui-mediaplayer-label-previous": "Forrige",
+ "srf-ui-mediaplayer-label-play": "Spill av",
+ "srf-ui-mediaplayer-label-pause": "Pause",
+ "srf-ui-mediaplayer-label-next": "Neste",
+ "srf-ui-mediaplayer-label-stop": "Stopp",
+ "srf-ui-mediaplayer-label-mute": "Lyd av",
+ "srf-ui-mediaplayer-label-unmute": "Lyd på",
+ "srf-ui-mediaplayer-label-volume-max": "Maks. volum",
+ "srf-ui-mediaplayer-label-shuffle": "Miks",
+ "srf-ui-mediaplayer-label-shuffle-off": "Miks av",
+ "srf-ui-mediaplayer-label-repeat": "Repeter",
+ "srf-ui-mediaplayer-label-repeat-off": "Repeter av",
+ "srf-ui-mediaplayer-label-full-screen": "Fullskjerm"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/nl.json b/www/wiki/extensions/SemanticResultFormats/i18n/nl.json
new file mode 100644
index 00000000..a96cbc09
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/nl.json
@@ -0,0 +1,276 @@
+{
+ "@metadata": {
+ "authors": [
+ "AvatarTeam",
+ "GerardM",
+ "McDutchie",
+ "Rcdeboer",
+ "SPQRobin",
+ "Siebrand",
+ "Southparkfan",
+ "Sjoerddebruin",
+ "Hex",
+ "Mainframe98",
+ "Hzjethro",
+ "Nemo bis",
+ "Festina90",
+ "Mar(c)",
+ "Patio",
+ "KlaasZ4usV",
+ "Elderson"
+ ]
+ },
+ "srf-desc": "Extra resultaatopmaken voor zoekopdrachten van Semantic MediaWiki",
+ "prefs-srf": "Semantische resultaatopmaken",
+ "srf-prefs-intro-text": "U hebt de uitbreiding Semantic Result Formats geïnstalleerd. Raadpleeg de hulppagina voor [https://www.semantic-mediawiki.org/wiki/Help:Result_formats resultaatopmaken] voor meer informatie.",
+ "srf-module-loading": "Bezig met laden…",
+ "srf-paramdesc-layout": "Beschikbare opmaak",
+ "srf-paramdesc-height": "Hoogte",
+ "srf-paramdesc-width": "Breedte",
+ "srf-paramdesc-class": "Geef een extra CSS-klasse op",
+ "srf-module-nomatch": "Geen overeenkomsten gevonden",
+ "srf-paramdesc-charttype": "Beschikbaar grafiektype",
+ "srf-navigation-previous": "Vorige",
+ "srf-ui-navigation-prev": "Vorige",
+ "srf-ui-navigation-next": "Volgende",
+ "srf-ui-common-label-source": "Bron",
+ "srf-ui-common-label-datasource": "Gegevensbron",
+ "srf-ui-common-label-ajax-error": "De server heeft een communicatiefout gerapporteerd voor dit $1. Probeer de pagina opnieuw te laden of raadpleeg deze $2.",
+ "srf-ui-common-label-request-object": "verzoek",
+ "srf-ui-common-label-help-section": "hulppagina",
+ "srf-ui-tooltip-title-options": "Opties",
+ "srf-ui-tooltip-title-scope": "Scope",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Verversen",
+ "srf-ui-common-label-parameters": "Parameters",
+ "srf-error-option-mix": "Optie ($1) is niet beschikbaar",
+ "srf-error-option-link-all": "Voor optie ($1) moet de parameter \"link\" ingesteld worden op \"all\".",
+ "srf-error-missing-layout": "Het diagram of de grafiek kan niet worden getoond omdat de vormgeving ontbreekt.",
+ "srf-warn-empy-chart": "De grafiek of kaart is leeg omdat er gegevens missen",
+ "srfc_previousmonth": "Vorige maand",
+ "srfc_nextmonth": "Volgende maand",
+ "srfc_today": "Vandaag",
+ "srfc_gotomonth": "Ga naar maand",
+ "srf_printername_calendar": "Maandkalender",
+ "srf_paramdesc_calendarlang": "De taalcode voor de taal waarin de kalender wordt weergegeven",
+ "srf_paramdesc_calendarcolors": "De kleur weer te geven voor elke datumeigenschap (voorbeeld: \"Startdatum=>green,Einddatum=>#09c\")",
+ "srf_printername_vcard": "Naar vCard exporteren",
+ "srf_printername_icalendar": "Naar iCalendar exporteren",
+ "srf_paramdesc_icalendartitle": "De titel van het kalenderbestand",
+ "srf_paramdesc_icalendardescription": "De beschrijving van het kalenderbestand",
+ "srf_printername_bibtex": "Naar BibTeX exporteren",
+ "srf_outline_novalue": "Geen waarde",
+ "srf_printername_outline": "Outline",
+ "srf_paramdesc_outlineproperties": "De koomagescheiden lijst met eigenschappen die weergegeven moet worden als overzichtskoptekst",
+ "srf_printername_sum": "Som van getallen",
+ "srf_printername_average": "Gemiddelde van getallen",
+ "srf_printername_max": "Hoogste getal",
+ "srf_printername_min": "Laagste getal",
+ "srf_paramdesc_limit": "Het maximaal aantal op te vragen pagina's",
+ "srf_printername_product": "Product van getallen",
+ "srf_printername_median": "Mediaan van getallen",
+ "srf-paramdesc-default": "De standaard waarde die wordt weergegeven als er geen numerieke resultaten zijn",
+ "srf_printername_earliest": "Vroegste tijd",
+ "srf_printername_latest": "Meest recente tijd",
+ "srf_printername_timeline": "Tijdlijn",
+ "srf_printername_eventline": "Gebeurtenissenlijn",
+ "srf_paramdesc_timelinebands": "Geeft aan welke banden in het resultaat weergegeven moeten worden.",
+ "srf_paramdesc_timelineposition": "Geeft aan waar de tijdlijn zich aanvankelijk op richt.",
+ "srf_paramdesc_timelinestart": "De naam van een eigenschap die wordt gebruikt om het eerst punt in de tijd te bepalen",
+ "srf_paramdesc_timelineend": "De naam van een eigenschap die wordt gebruikt om het tweede punt in de tijd te bepalen",
+ "srf_paramdesc_timelinesize": "De hoogte van de tijdlijn",
+ "srf-timeline-allresults": "Meer resultaten voor deze zoekopdracht.",
+ "srf-timeline-nojs": "U moet JavaScript ingeschakeld hebben om de interactieve tijdlijn te kunnen weergeven.",
+ "srf_paramdesc_views": "De weer te geven overzichten",
+ "srf_paramdesc_facets": "De voor iedere pagina weer te geven eigenschappen",
+ "srf_paramdesc_lens": "De naam van de sjabloon waarmee de paginaeigenschappen weergegeven moeten worden",
+ "srf_printername_googlebar": "Google staafgrafiek",
+ "srf_printername_googlepie": "Google taartgrafiek",
+ "srf-printername-jqplotchart": "jqPlotgrafiek",
+ "srf-printername-jqplotseries": "jqPlotserie",
+ "srf_paramdesc_chartheight": "Geef de hoogte op (in pixels) van een kaart of grafiek",
+ "srf_paramdesc_chartwidth": "Geef de breedte op (in pixels of procent) van een kaart of grafiek",
+ "srf_paramdesc_charttitle": "Grafiektitel",
+ "srf_paramdesc_barcolor": "De kleur van de balken",
+ "srf_paramdesc_bardirection": "Geeft de richting van een grafiek aan",
+ "srf-paramdesc-direction": "Geef de richting van een tabel of grafiek op",
+ "srf_paramdesc_barnumbersaxislabel": "Het label van de nummeras",
+ "srf-paramdesc-labelaxislabel": "Het label voor de labelas",
+ "srf-paramdesc-ticklabels": "Weergave van ticklabels inschakelen",
+ "srf-paramdesc-minvalue": "De minimumwaarde om weer te geven op de Y-as",
+ "srf-paramdesc-pointlabels": "Individuele waarden in de grafiek weergeven",
+ "srf-paramdesc-chartlegend": "Positie van de grafieklegenda",
+ "srf-paramdesc-datalabels": "Grafiek- of kaartlabels weergeven",
+ "srf-paramdesc-charttext": "Beschrijvende grafiektekst",
+ "srf-paramdesc-chartclass": "Extra CSS-klasse",
+ "srf-paramdesc-renderer": "Selecteer een renderer voor een kaart of grafiek",
+ "srf-paramdesc-filling": "Optie voor individuele vulling",
+ "srf-paramdesc-theme": "Selecteer een vormgeving voor het raster",
+ "srf-paramdesc-chartcolor": "Individuele grafiekkleuren toewijzen",
+ "srf-paramdesc-colorscheme": "Selecteer een kleurschema",
+ "srf-paramdesc-valueformat": "Geef een opmaakregel voor de waarden op",
+ "srf-paramdesc-highlighter": "Een gegevenspuntmarkering opgeven",
+ "srf-paramdesc-smoothlines": "Lijnen in lijngrafieken vloeiend maken",
+ "srf-paramdesc-stackseries": "Grafiek weergeven als gestapelde series",
+ "srf-paramdesc-seriesgroup": "Selecteer groeperen van series",
+ "srf-paramdesc-serieslabel": "Label voor series bepalen",
+ "srf-paramdesc-grouplabel": "Bepaal het groepslabel",
+ "srf-paramdesc-chartcursor": "Optie voor het weergeven van een cursor in de grafiek",
+ "srf-paramdesc-trendline": "Gelijktijdige weergave van een tabel en de trendlijn inschakelen",
+ "srf-paramdesc-gridview": "Tabel en gegevensets gelijktijdig weergeven. Toegestane waarden: \"none\" en \"tabs\". Standaard: \"none\".",
+ "srf-paramdesc-infotext": "Extra informatie in een bijbehorend informatietabblad weergeven",
+ "srf-paramdesc-clicktarget": "Definieer een pagina of tekenreeks als doel bij het aanklikken van een kalender datum.",
+ "srf-ui-gridview-label-item": "Gegevensitem",
+ "srf-ui-gridview-label-value": "Gegevenswaarde",
+ "srf-ui-gridview-label-series": "Gegevensseries",
+ "srf-ui-gridview-label-chart-tab": "Grafiek",
+ "srf-ui-gridview-label-data-tab": "Gegevens",
+ "srf-ui-gridview-label-info-tab": "Informatie",
+ "srf_printername_gallery": "Galerij",
+ "srf_paramdesc_perrow": "Het aantal afbeeldingen per rij",
+ "srf_paramdesc_widths": "De breedte van de afbeeldingen",
+ "srf_paramdesc_heights": "De hoogte van de afbeeldingen",
+ "srf_paramdesc_autocaptions": "Bestandsnaam als beschrijving gebruiken als er geen is opgegeven",
+ "srf_paramdesc_fileextensions": "Ook de extensie weergeven als bestandsnamen als bijschrift worden gebruikt",
+ "srf_paramdesc_captionproperty": "De naam van een semantische eigenschap die aanwezig is op de doorzochte pagina's die gebruikt moet worden als bijschrift",
+ "srf_paramdesc_imageproperty": "De naam van een semantische eigenschap die aanwezig is op de doorzochte pagina's die verwijst naar de te gebruiken afbeeldingen. Als deze instelling wordt gebruikt, worden de doorzochte pagina's zelf niet weergegeven als afbeeldingen",
+ "srf-paramdesc-redirects": "De naam van een semantische eigenschap die aanwezig is op de opgevraagde pagina's die het doorverwijzingsdoel bevatten",
+ "srf-paramdesc-navigation": "Navigatie-instellingen",
+ "srf-paramdesc-overlay": "Beeldoverlay inschakelen",
+ "srf-gallery-navigation-previous": "Vorige",
+ "srf-gallery-navigation-next": "Volgende",
+ "srf-gallery-overlay-count": "Afbeelding $1 van $2",
+ "srf-gallery-image-url-error": "Deze afbeelding is niet gevonden.",
+ "srf_printername_tagcloud": "Woordwolk",
+ "srf_paramdesc_includesubject": "Of de namen van de onderwerpen zelf opgenomen moeten worden",
+ "srf_paramdesc_increase": "Hoe de grootte van de labels moet worden vergroot",
+ "srf_paramdesc_tagorder": "De volgorde van de labels",
+ "srf_paramdesc_mincount": "Het minimale aantal keren dat een waarde moet voorkomen om opgenomen te worden",
+ "srf_paramdesc_minsize": "De grootte van de kleinste labels in percentage",
+ "srf_paramdesc_maxsize": "De grootte van de grootste labels in percentage",
+ "srf_paramdesc_maxtags": "Het maximale aantal labels in de wolk",
+ "srf-paramdesc-excludetags": "Labels uitsluiten (scheidingsteken is \";\")",
+ "srf_printername_valuerank": "Rangwaarde",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Of paginanamen moeten worden weergegeven of weggelaten in resultaatregels",
+ "srf_paramdesc_hidegaps": "Of lege eigenschap- en recordwaardes door komma's gescheiden moeten worden weergegeven of weggelaten",
+ "srf_paramdesc_arrayname": "Als opgegeven en ArrayExtension is beschikbaar, wordt een array met de aangegeven naam gemaakt (er is dan geen zichtbare uitvoer)",
+ "srf_paramdesc_propsep": "Scheidingsteken voor de opgevraagde eigenschappen",
+ "srf_paramdesc_manysep": "Scheidingsteken voor eigenschappen met meerdere waarden",
+ "srf_paramdesc_recordsep": "Scheidingsteken voor waarden van recordeigenschappen",
+ "srf_paramdesc_headersep": "Scheidingsteken tussen de eigenschapnaam en de waarde als \"headers\" is ingesteld op \"show\" of \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Als opgegeven en de uitbreiding HashTables is beschikbaar, dan wordt een hash met de aangegeven naam gemaakt (er is dan geen zichtbare uitvoer)",
+ "srf-printername-graph": "Grafiek",
+ "srf-paramdesc-graph-relation": "Zijn de onderwerpen of naameigenschappen ouders of kinderen?",
+ "srf-paramdesc-graph-nameprop": "Maakt het mogelijk een eigenschap in te stellen die wordt gebruikt als onderwerp in plaats van het eigenlijke onderwerp",
+ "srf-paramdesc-graph-nodeshape": "De vorm van de knooppunten in de grafiek.",
+ "srf-paramdesc-graphname": "Naam",
+ "srf-paramdesc-graphsize": "Grafiekgrootte (in pixels)",
+ "srf-paramdesc-graphlegend": "Legenda weergeven of verbergen",
+ "srf-paramdesc-graphlabel": "Grafieklabel",
+ "srf-paramdesc-rankdir": "Pijlrichting",
+ "srf-paramdesc-graphlink": "Grafiekkoppeling",
+ "srf-paramdesc-graphcolor": "Grafiekkleur",
+ "srf-paramdesc-graph-wwl": "Regellimiet (in aantal tekens)",
+ "srf-printername-datatables": "Gegevenstabellen",
+ "srf-ui-datatables-label-conditions": "Voorwaarden",
+ "srf-ui-datatables-label-parameters": "Parameters",
+ "srf-ui-datatables-label-information": "Informatie",
+ "srf-ui-datatables-label-placeholder-column-search": "Zoeken...",
+ "srf-ui-datatables-label-multiselect-column-header": "Beschikbare kolommen",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filterinstellingen",
+ "srf-ui-datatables-label-sInfo": "Weergave _START_ tot _END_ van _TOTAL_ resultaten",
+ "srf-ui-datatables-label-sInfoEmpty": "Weergave 0 van 0 resultaten",
+ "srf-ui-datatables-label-sInfoFiltered": "(gefilterd uit _MAX_ resultaten)",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLengthMenu": "Toon _MENU_ resultaten per pagina",
+ "srf-ui-datatables-label-sLoadingRecords": "Bezig met laden...",
+ "srf-ui-datatables-label-sProcessing": "Verwerken...",
+ "srf-ui-datatables-label-sSearch": "Zoek:",
+ "srf-ui-datatables-label-sZeroRecords": "Geen overeenkomende resultaten gevonden",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Eerste",
+ "srf-ui-datatables-label-oPaginate-sLast": "Laatste",
+ "srf-ui-datatables-label-oPaginate-sNext": "Volgende",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Vorige",
+ "srf-printername-tree": "Boom",
+ "srf-printername-ultree": "Ongenummerde lijst",
+ "srf-printername-oltree": "Genummerde lijst",
+ "srf-tree-noparentprop": "Er is geen bovenliggende eigenschap opgegeven. De boom kan niet opgebouwd worden zonder een bovenliggende eigenschap.",
+ "srf-tree-rootinvalid": "$1 is geen geldige paginanaam.",
+ "srf-paramdesc-tree-parent": "De eigenschap die de bovenliggende pagina bevat",
+ "srf-printername-slideshow": "Diapresentatie",
+ "srf-paramdesc-delay": "De vertraging tussen dia's in seconden",
+ "srf-paramdesc-navigation-controls": "Of navigatieknoppen wel of niet weergegeven moeten worden",
+ "srf-paramdesc-effect": "Het effect om tussen dia's te wisselen",
+ "srf-printername-filtered": "Gefilterd",
+ "srf-paramdesc-filtered-views": "De views die beschikbaar zijn in de resultaatweergave.",
+ "srf-paramdesc-filtered-filter-position": "De positie van de filters in relatie tot de views. Toegestane waarden: \"top\" en \"bottom\". Standaard: \"top\".",
+ "srf-paramdesc-filtered-list-type": "Het lijsttype. Toegestane waarden: \"list\", \"ul\" en \"ol\". Standaard: \"list\".",
+ "srf-paramdesc-filtered-list-template": "De sjabloon die wordt gebruikt om de lijstonderdelen op te maken.",
+ "srf-paramdesc-filtered-list-named-args": "Naam van de argumenten die worden doorgegeven aan de sjabloon.",
+ "srf-paramdesc-filtered-list-introtemplate": "De naam van een sjabloon om voor de resultaten van de zoekopdracht weer te geven, als er resultaten zijn.",
+ "srf-paramdesc-filtered-list-outrotemplate": "De naam van een sjabloon om na de resultaten van de zoekopdracht weer te geven, als er resultaten zijn.",
+ "srf-paramdesc-filtered-calendar-title-template": "Een sjabloon dat wordt gebruikt om de naam van een gebeurtenis in de kalender weer te geven",
+ "srf-filtered-selectorlabel-list": "Lijst",
+ "srf-filtered-selectorlabel-table": "Tabel",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-filtered-selectorlabel-map": "Kaart",
+ "srf-filtered-noscript-error": "De resulaten kunnen niet worden weergegeven omdat JavaScript niet is ingeschakeld. Ga naar $1.",
+ "srf-filtered-value-filter-and": "EN",
+ "srf-filtered-value-filter-or": "OF",
+ "srf-printername-d3chart": "D3-grafiek",
+ "srf-printername-timeseries": "Tijdseriegrafiek",
+ "srf-paramdesc-group": "Series groepen op",
+ "srf-paramdesc-zoom": "Zoom inschakelen",
+ "srf-paramdesc-datatable": "Gegevenstabel inschakelen",
+ "srf-timeseries-zoom-out-of-range": "Het zoombereik heeft onvoldoende gegevens opgeleverd",
+ "srf-printername-sparkline": "Sparklinegrafief",
+ "srf-printername-listwidget": "Lijstwidget",
+ "srf-paramdesc-listtype": "Geef het lijsttype op",
+ "srf-paramdesc-widget": "Beschikbaar widget",
+ "srf-paramdesc-pageitems": "Items per pagina",
+ "srf-printername-eventcalendar": "Evenementenkalender",
+ "srf-paramdesc-calendarfirstday": "De dag waarop de week begint",
+ "srf-paramdesc-calendardefaultview": "De weergave wanneer de kalender wordt geladen",
+ "srf-paramdesc-calendarstart": "De begindatum van de kalender (datum- of datumtijdwaarden)",
+ "srf-paramdesc-dayview": "Dagweergave inschakelen door te klikken op het dagnummer",
+ "srf-ui-eventcalendar-label-today": "Vandaag",
+ "srf-ui-eventcalendar-label-month": "Maand",
+ "srf-ui-eventcalendar-label-week": "Week",
+ "srf-ui-eventcalendar-label-day": "Dag",
+ "srf-ui-eventcalendar-label-listmonth": "Maand (lijst)",
+ "srf-ui-eventcalendar-label-listweek": "Week (lijst)",
+ "srf-ui-eventcalendar-label-listday": "Dag (lijst)",
+ "srf-ui-eventcalendar-label-allday": "Hele dag",
+ "srf-printername-dygraphs": "Dygraphsgrafiek",
+ "srf-paramdesc-datasource": "De bron op waar de gegevens toegankelijk zijn. Toegestane waarden: \"file\", \"raw\" en \"url\". Standaard: \"file\".",
+ "srf-paramdesc-errorbar": "De te gebruiken foutbalk. Toegestane waarden: \"fractie\" (vertrouwensintervallen voor waarden), \"sigma\" (standaarddeviatie van waarden) en \"range\" (aangepaste waardereeksen).",
+ "srf-paramdesc-movingaverage": "Het gemiddelde over een aantal dagen weergeven (met \"0\" wordt aangegeven dat er geen glijdend gemiddelde weergegeven moet worden)",
+ "srf-paramdesc-yaxislabel": "Op Y-as weer te geven beschrijving",
+ "srf-paramdesc-xaxislabel": "Op X-as weer te geven beschrijving",
+ "srf-paramdesc-unit": "Eenheid",
+ "srf-printername-pagewidget": "Paginawidget",
+ "srf-printername-incoming": "Inkomende eigenschappen",
+ "srf-paramdesc-min": "Minimale waar of drempelwaarde",
+ "srf-paramdesc-excludeproperty": "Eigenschap uitsluiten van resultaatset",
+ "srf-printername-media": "Mediaspeler",
+ "srf-paramdesc-mediainspector": "Geeft gedetailleerde gegevens weer over een aangegeven mediaelement",
+ "srf-ui-mediaplayer-label-previous": "Vorige",
+ "srf-ui-mediaplayer-label-play": "Afspelen",
+ "srf-ui-mediaplayer-label-pause": "Pauzeren",
+ "srf-ui-mediaplayer-label-next": "Volgende",
+ "srf-ui-mediaplayer-label-stop": "Stoppen",
+ "srf-ui-mediaplayer-label-mute": "Geluid uit",
+ "srf-ui-mediaplayer-label-unmute": "Geluid aan",
+ "srf-ui-mediaplayer-label-volume-max": "max volume",
+ "srf-ui-mediaplayer-label-shuffle": "Willekeurig",
+ "srf-ui-mediaplayer-label-shuffle-off": "Willekeurig uit",
+ "srf-ui-mediaplayer-label-repeat": "Herhalen",
+ "srf-ui-mediaplayer-label-repeat-off": "Herhalen uit",
+ "srf-ui-mediaplayer-label-full-screen": "Volledig scherm",
+ "srf-ui-mediaplayer-label-restore-screen": "Scherm herstellen",
+ "srf-paramdesc-spreadsheet-filename": "De bestandsnaam voor het downloaden van de gegenereerde speadsheet",
+ "srf-paramdesc-spreadsheet-fileformat": "De bestandsindeling voor de spreadsheet. Mogelijke waarden: xlsx, xls, ods en csv. Standaard: xlsx."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/nn.json b/www/wiki/extensions/SemanticResultFormats/i18n/nn.json
new file mode 100644
index 00000000..c0314c0f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/nn.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eirik",
+ "Gunnernett"
+ ]
+ },
+ "srf-desc": "Fleire format for Semantic MediaWiki «inline»-spørjingar",
+ "srf-name": "Semantisk resultatformat",
+ "srfc_previousmonth": "Førre månad",
+ "srfc_nextmonth": "Neste månad",
+ "srfc_today": "I dag",
+ "srfc_gotomonth": "Gå til månad",
+ "srf_printername_calendar": "MÃ¥nadleg kalender",
+ "srf_printername_vcard": "vCard eksport",
+ "srf_printername_icalendar": "iCalendar eksport",
+ "srf_printername_bibtex": "BibTeX eksport",
+ "srf_outline_novalue": "Ingen verdi",
+ "srf_printername_sum": "Sum av tal",
+ "srf_printername_average": "Gjennomsnitt av tal",
+ "srf_printername_max": "Største tal",
+ "srf_printername_min": "Minste tal",
+ "srf_printername_timeline": "Tidsline",
+ "srf_printername_eventline": "Tidsline for hendingar"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/oc.json b/www/wiki/extensions/SemanticResultFormats/i18n/oc.json
new file mode 100644
index 00000000..cd599746
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/oc.json
@@ -0,0 +1,135 @@
+{
+ "@metadata": {
+ "authors": [
+ "Boulaur",
+ "Cedric31",
+ "Nemo bis",
+ "Unuaiga"
+ ]
+ },
+ "srf-desc": "Formats adicionals d'afichatge de resultat per las requèstas de Semantic MediaWiki",
+ "prefs-srf-datatables-options": "Opcions de las plajas de donadas",
+ "srf-module-loading": "Cargament…",
+ "srf-paramdesc-layout": "Mesa en pagina disponibla",
+ "srf-paramdesc-height": "Nautor",
+ "srf-paramdesc-width": "Largor",
+ "srf-paramdesc-class": "Especificatz una classa CSS suplementària",
+ "srf-navigation-previous": "Precedent",
+ "srf-ui-navigation-prev": "Precedent",
+ "srf-ui-navigation-next": "Seguent",
+ "srf-ui-common-label-source": "Font",
+ "srf-ui-common-label-datasource": "Font de donadas",
+ "srf-ui-common-label-request-object": "objècte requèsta",
+ "srf-ui-common-label-help-section": "seccion d'ajuda",
+ "srf-ui-tooltip-title-options": "Opcions",
+ "srf-ui-tooltip-title-scope": "Portada",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtre",
+ "srf-ui-common-label-refresh": "Refrescar",
+ "srf-ui-common-label-parameters": "Paramètres",
+ "srf-ui-common-label-query": "Requèsta",
+ "srf-ui-common-label-paneview": "Afichatge del panèl",
+ "srf-ui-common-label-daterange": "Plaja de datas",
+ "srf-ui-widgets-label-parameter-limit": "Limitar lo paramètre",
+ "srfc_previousmonth": "Mes precedent",
+ "srfc_nextmonth": "Mes seguent",
+ "srfc_today": "Uèi",
+ "srfc_gotomonth": "Anar cap al mes",
+ "srf_printername_calendar": "Calendièr mesadièr",
+ "srf_vcard_link": "vCarta",
+ "srf_printername_vcard": "expòrt en vCard",
+ "srf_icalendar_link": "iCalendièr",
+ "srf_printername_icalendar": "expòrt en iCalendar",
+ "srf_printername_bibtex": "expòrt en BibTeX",
+ "srf_outline_novalue": "Pas cap de valor",
+ "srf_printername_outline": "Esbòs",
+ "srf_printername_sum": "Soma de nombres",
+ "srf_printername_average": "Mejana dels nombres",
+ "srf_printername_max": "Nombre maximal",
+ "srf_printername_min": "Nombre minimal",
+ "srf_paramdesc_limit": "Lo nombre maximum de paginas de recercar",
+ "srf_printername_timeline": "Cronologia",
+ "srf_printername_eventline": "Cronologia dels eveniments",
+ "srf-timeline-allresults": "Autres resultats per aquesta requèsta.",
+ "srf_printername_googlebar": "Diagrama de barras de Google",
+ "srf_printername_googlepie": "Diagrama en camembèrt de Google",
+ "srf-printername-jqplotchart": "grafic jqPlot",
+ "srf-printername-jqplotseries": "seria jqPlot",
+ "srf_paramdesc_barnumbersaxislabel": "Etiqueta per l’axe numeric",
+ "srf-ui-gridview-label-item": "Element de donada",
+ "srf-ui-gridview-label-value": "Valor de donada",
+ "srf-ui-gridview-label-series": "Seria de donadas",
+ "srf-ui-gridview-label-chart-tab": "Grafic",
+ "srf-ui-gridview-label-data-tab": "Donadas",
+ "srf-ui-gridview-label-info-tab": "Info",
+ "srf_printername_gallery": "Galariá",
+ "srf_paramdesc_autocaptions": "Utilizar lo nom de fichièr coma legenda n'i a pas cap de provesida",
+ "srf-gallery-navigation-previous": "Precedent",
+ "srf-gallery-navigation-next": "Seguent",
+ "srf-gallery-overlay-count": "Imatge $1 sus $2",
+ "srf-gallery-image-url-error": "L'imatge es pas estat trobat.",
+ "srf_printername_tagcloud": "Nívol d'etiquetas",
+ "srf-paramdesc-excludetags": "Exclure los noms de balisa (delimitador : ';')",
+ "srf_printername_valuerank": "Valor del reng",
+ "srf_printername_array": "Tablèu",
+ "srf-printername-graph": "Graf",
+ "srf-paramdesc-graphname": "Títol",
+ "srf-ui-datatables-label-conditions": "Condicions",
+ "srf-ui-datatables-label-parameters": "Paramètres",
+ "srf-ui-datatables-label-filters": "Filtres de colomna e recèrca",
+ "srf-ui-datatables-label-information": "Informacion",
+ "srf-ui-datatables-label-update-success": "La mesa a jorn del tablèu a capitat",
+ "srf-ui-datatables-label-placeholder-column-search": "Recèrca en cors…",
+ "srf-ui-datatables-label-multiselect-column-header": "Colomnas disponiblas",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Paramètres de filtre",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Las colomnas son visiblas",
+ "srf-ui-datatables-label-sInfo": "Afichatge de _START_ a _END_ sus _TOTAL_ entradas",
+ "srf-ui-datatables-label-sInfoEmpty": "Afichatge de 0 a 0 sus 0 entradas",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtrat per _MAX_ entradas al total)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Afichar las entradas _MENU_",
+ "srf-ui-datatables-label-sLoadingRecords": "Cargament…",
+ "srf-ui-datatables-label-sProcessing": "Tractament en cors...",
+ "srf-ui-datatables-label-sSearch": "Recercar :",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primièr",
+ "srf-ui-datatables-label-oPaginate-sLast": "Darrièr",
+ "srf-ui-datatables-label-oPaginate-sNext": "Seguent",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Precedent",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": activar per triar la colomna en òrdre creissent",
+ "srf-printername-tree": "Arbre",
+ "srf-printername-ultree": "Arbre UL",
+ "srf-printername-oltree": "Arbre Ol",
+ "srf-tree-rootinvalid": "$1 es pas un títol de pagina valid.",
+ "srf-paramdesc-tree-root": "La pagina raiç de l’arbre",
+ "srf-printername-slideshow": "Diaporama",
+ "srf-printername-filtered": "Filtrat",
+ "srf-paramdesc-filtered-list-type": "Lo tipe de la lista. Valors permesas: « list », « ul », « ol ». Per defaut : « list ».",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tablèu",
+ "srf-filtered-selectorlabel-calendar": "Calendièr",
+ "srf-printername-d3chart": "Grafic D3",
+ "srf-paramdesc-zoom": "Activar lo zoom",
+ "srf-paramdesc-datatable": "Activar una taula de donadas",
+ "srf-printername-listwidget": "Widget lista",
+ "srf-ui-eventcalendar-label-today": "Uèi",
+ "srf-ui-eventcalendar-label-month": "Mes",
+ "srf-ui-eventcalendar-label-week": "Setmana",
+ "srf-ui-eventcalendar-label-day": "Jorn",
+ "srf-ui-eventcalendar-label-listmonth": "Mes (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Setmana (lista)",
+ "srf-ui-eventcalendar-label-listday": "Jorn (lista)",
+ "srf-ui-eventcalendar-label-allday": "Tota la jornada",
+ "srf-paramdesc-unit": "Unitat",
+ "srf-printername-pagewidget": "Widget de pagina",
+ "srf-printername-incoming": "Proprietats entrantas",
+ "srf-ui-mediaplayer-label-previous": "Precedent",
+ "srf-ui-mediaplayer-label-play": "Lectura",
+ "srf-ui-mediaplayer-label-pause": "Pausa",
+ "srf-ui-mediaplayer-label-next": "Seguent",
+ "srf-ui-mediaplayer-label-stop": "Arrèst",
+ "srf-ui-mediaplayer-label-mute": "Mut",
+ "srf-ui-mediaplayer-label-unmute": "Pas mut",
+ "srf-ui-mediaplayer-label-volume-max": "Volum maximal",
+ "srf-ui-mediaplayer-label-shuffle": "Lectura aleatòria",
+ "srf-ui-mediaplayer-label-repeat": "Repetir"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/om.json b/www/wiki/extensions/SemanticResultFormats/i18n/om.json
new file mode 100644
index 00000000..ef587162
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/om.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tumsaa"
+ ]
+ },
+ "srf-ui-datatables-label-placeholder-column-search": "Barbaacha..."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/os.json b/www/wiki/extensions/SemanticResultFormats/i18n/os.json
new file mode 100644
index 00000000..ae461128
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/os.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amikeco"
+ ]
+ },
+ "srf-ui-common-label-query": "БафарÑÑ‚"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pdc.json b/www/wiki/extensions/SemanticResultFormats/i18n/pdc.json
new file mode 100644
index 00000000..6049eb09
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pdc.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xqt"
+ ]
+ },
+ "srfc_previousmonth": "Letscht Munet",
+ "srfc_nextmonth": "Neegscht Munet",
+ "srfc_today": "Heit"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pfl.json b/www/wiki/extensions/SemanticResultFormats/i18n/pfl.json
new file mode 100644
index 00000000..518f2c22
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pfl.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ },
+ "srfc_previousmonth": "Vorische Monad",
+ "srfc_nextmonth": "Negschde Monad",
+ "srfc_today": "Haid",
+ "srf_printername_earliest": "De friehschde Zaidpungd",
+ "srf_printername_latest": "De schbedschde Zaidpungd"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pl.json b/www/wiki/extensions/SemanticResultFormats/i18n/pl.json
new file mode 100644
index 00000000..f9adc7a4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pl.json
@@ -0,0 +1,217 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym",
+ "Maire",
+ "Sp5uhe",
+ "ToSter",
+ "Rzuwig",
+ "Alan ffm",
+ "Chrumps",
+ "Nemo bis",
+ "Woytecr",
+ "Wojtas"
+ ]
+ },
+ "srf-desc": "Dodatkowe formaty dla zapytań Semantycznej MediaWiki",
+ "prefs-srf-eventcalendar-options": "Opcje kalendarza wydarzeń",
+ "prefs-srf-datatables-options": "Ustawienia tabel danych",
+ "srf-module-loading": "Åadowanie...",
+ "srf-paramdesc-layout": "Dostępny układ",
+ "srf-paramdesc-height": "Wysokość",
+ "srf-paramdesc-width": "Szerokość",
+ "srf-paramdesc-class": "Określ dodatkową klasę CSS",
+ "srf-module-nomatch": "Brak wyników",
+ "srf-paramdesc-charttype": "Dostępny typ wykresu",
+ "srf-navigation-previous": "Poprzednie",
+ "srf-ui-navigation-next": "Następne",
+ "srf-ui-common-label-source": "Źródło",
+ "srf-ui-common-label-datasource": "Źródło danych",
+ "srf-ui-common-label-ajax-error": "Serwer zgłosił nieudaną komunikację dla $1. Spróbuj odświeżyć stronę lub skonsultuj się z $2.",
+ "srf-ui-common-label-help-section": "sekcja pomocy",
+ "srf-ui-tooltip-title-options": "Opcje",
+ "srf-ui-tooltip-title-scope": "Zakres",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtr",
+ "srf-ui-common-label-refresh": "Odśwież",
+ "srf-ui-common-label-parameters": "Parametry",
+ "srf-ui-common-label-query": "Zapytanie",
+ "srf-ui-common-label-daterange": "Zakres dat",
+ "srf-error-option-mix": "Parametr ($1) nie jest dostępny",
+ "srf-error-option-link-all": "Opcja ($1) wymaga ustawienia parametru „link†na „allâ€",
+ "srf-error-jqplot-bubble-data-length": "Wykresu nie można wyświetlić z powodu braku danych.",
+ "srf-warn-empy-chart": "Wykres jest pusty z powodu brakujÄ…cych danych",
+ "srfc_previousmonth": "Poprzedni miesiÄ…c",
+ "srfc_nextmonth": "Następny miesiąc",
+ "srfc_today": "Dzisiaj",
+ "srfc_gotomonth": "Idź do miesiąca",
+ "srf_printername_calendar": "Kalendarz na miesiÄ…c",
+ "srf_paramdesc_calendarlang": "Kod języka, w którym jest wyświetlany kalendarz",
+ "srf-paramdesc-calendar-startmonth": "Miesiąc, z którym inicjowane jest wyświetlanie kalendarza (domyślnie bieżący miesiąc)",
+ "srf-paramdesc-calendar-startyear": "Rok, z którym inicjowane jest wyświetlanie kalendarza (domyślnie bieżący rok)",
+ "srf_printername_vcard": "eksport vCard",
+ "srf_printername_icalendar": "eksport iCalendar",
+ "srf_paramdesc_icalendartitle": "Nazwa pliku kalendarza",
+ "srf_paramdesc_icalendardescription": "Opis pliku kalendarza",
+ "srf_printername_bibtex": "eksport BibTeX",
+ "srf_outline_novalue": "Brak wartości",
+ "srf_printername_outline": "Szkic",
+ "srf_paramdesc_outlineproperties": "Spis właściwości, które zostaną wyświetlone jako nagłówki konspektu, rozdzielone przecinkami",
+ "srf_printername_sum": "Suma liczb",
+ "srf_printername_average": "Åšrednia liczb",
+ "srf_printername_max": "Maksymalna liczba",
+ "srf_printername_min": "Minimalna liczba",
+ "srf_paramdesc_limit": "Maksymalna liczba stron dla zapytania",
+ "srf_printername_median": "Mediana liczb",
+ "srf-paramdesc-default": "Wartość domyślna, która będzie wyświetlana, gdy nie ma wyników liczbowych",
+ "srf_printername_timeline": "OÅ› czasu",
+ "srf_printername_eventline": "Oś wydarzeń",
+ "srf_paramdesc_timelinebands": "Określa, które okresy są wyświetlane w wynikach.",
+ "srf_paramdesc_timelineposition": "Określa, gdzie początkowo zaczyna się oś czasu.",
+ "srf_paramdesc_timelinestart": "Nazwa własności używana do określenia pierwszego punktu w czasie.",
+ "srf_paramdesc_timelineend": "Nazwa własności używana do określenia drugiego punktu w czasie.",
+ "srf_paramdesc_timelinesize": "Wysokość osi czasu",
+ "srf_paramdesc_views": "Widoki do wyświetlenia",
+ "srf_paramdesc_facets": "Zestaw właściwości do wyświetlenia na każdej stronie",
+ "srf_paramdesc_lens": "Nazwa szablonu, który zostanie użyty do wyświetlenia właściwości strony",
+ "srf_printername_googlebar": "wykres słupkowy Google",
+ "srf_printername_googlepie": "wykres kołowy Google",
+ "srf-printername-jqplotchart": "wykres jqPlot",
+ "srf-printername-jqplotseries": "serie jqPlot",
+ "srf_paramdesc_chartheight": "Wskaż wysokość wykresu (w pikselach)",
+ "srf_paramdesc_chartwidth": "Wskaż szerokość wykresu (w pikselach)",
+ "srf_paramdesc_charttitle": "Tytuł wykresu",
+ "srf_paramdesc_barcolor": "Kolory słupków",
+ "srf_paramdesc_bardirection": "Wskaż kierunek wykresu",
+ "srf_paramdesc_barnumbersaxislabel": "Etykieta wartości osi",
+ "srf-paramdesc-labelaxislabel": "Etykieta osi",
+ "srf-paramdesc-minvalue": "Minimalna wartość pokazywana na osi y",
+ "srf-paramdesc-pointlabels": "Wyświetlanie punktów danych na wykresie",
+ "srf-paramdesc-chartlegend": "Położenie legendy wykresu",
+ "srf-paramdesc-datalabels": "Etykiety danych wykresu",
+ "srf-paramdesc-chartclass": "Dodatkowa klasa CSS",
+ "srf-paramdesc-renderer": "Wybierz renderer wykresu",
+ "srf-paramdesc-theme": "Wybierz motyw siatki",
+ "srf-paramdesc-colorscheme": "Wybierz schemat kolorów",
+ "srf-paramdesc-valueformat": "Wprowadź regułę formatowania wartości",
+ "srf-paramdesc-highlighter": "Wyświetl znacznik punktu danych",
+ "srf-paramdesc-smoothlines": "Zastosuj algorytm wygładzania na wykresach liniowych",
+ "srf-paramdesc-seriesgroup": "Wybierz grupowanie serii",
+ "srf-paramdesc-serieslabel": "Określ etykietę serii",
+ "srf-paramdesc-grouplabel": "Określ etykietę grupy",
+ "srf-ui-gridview-label-item": "Element danych",
+ "srf-ui-gridview-label-value": "Wartość danych",
+ "srf-ui-gridview-label-series": "Serie danych",
+ "srf-ui-gridview-label-chart-tab": "Wykres",
+ "srf-ui-gridview-label-data-tab": "Dane",
+ "srf-ui-gridview-label-info-tab": "Informacje",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_perrow": "Liczba obrazków w wierszu",
+ "srf_paramdesc_widths": "Szerokość obrazków",
+ "srf_paramdesc_heights": "Wysokość obrazków",
+ "srf_paramdesc_autocaptions": "Użyj nazwy pliku jako podpisu, jeśli nie został podany",
+ "srf_paramdesc_captionproperty": "Nazwa właściwości semantycznej występującej na stronach z zapytaniami, używana jako podpis",
+ "srf-paramdesc-redirects": "Nazwa właściwości semantycznej występującej na stronach z zapytaniami, zawierającymi cel przekierowania",
+ "srf-paramdesc-overlay": "Zezwól na nakładanie się obrazków",
+ "srf-gallery-navigation-previous": "Poprzedni",
+ "srf-gallery-navigation-next": "Następny",
+ "srf-gallery-overlay-count": "Obrazek $1 z $2",
+ "srf-gallery-image-url-error": "Obrazek nie został znaleziony.",
+ "srf_paramdesc_increase": "Jak zwiększyć rozmiar znaczników",
+ "srf_paramdesc_tagorder": "Kolejność znaczników",
+ "srf_paramdesc_mincount": "Minimalna liczba pojawienia się wartości, aby została wyświetlona",
+ "srf_paramdesc_minsize": "Rozmiar najmniejszych znaczników w procentach",
+ "srf_paramdesc_maxsize": "Rozmiar największych znaczników w procentach",
+ "srf_paramdesc_maxtags": "Maksymalna liczba znaczników w chmurze",
+ "srf-paramdesc-excludetags": "Wyklucz znaczniki (ogranicznik: „;â€)",
+ "srf_printername_array": "Tablica",
+ "srf-printername-graph": "Wykres",
+ "srf-paramdesc-graphname": "Ustawia tytuł wykresu",
+ "srf-paramdesc-graphsize": "Ustawia rozmiar wykresu w pikselach",
+ "srf-paramdesc-graphlegend": "Określa, czy powinna być wyświetlana legenda wykresu",
+ "srf-paramdesc-graphlabel": "Ustawia etykietÄ™ wykresu",
+ "srf-paramdesc-rankdir": "Ustawia kierunek strzałki",
+ "srf-paramdesc-graphcolor": "Ustawia kolor wykresu",
+ "srf-paramdesc-graph-wwl": "Ustawia limit zawijania słowa (w liczbie znaków)",
+ "srf-paramdesc-redlinkcolor": "Określa kolor czcionki dla czerwonych linków",
+ "srf-printername-datatables": "Tabele danych",
+ "srf-ui-datatables-label-conditions": "Warunki",
+ "srf-ui-datatables-label-parameters": "Parametry",
+ "srf-ui-datatables-label-information": "Informacje",
+ "srf-ui-datatables-label-update-success": "Aktualizacja tabeli zakończona pomyślnie",
+ "srf-ui-datatables-label-update-error": "Aktualizacja tabeli nie powiodła się.",
+ "srf-ui-datatables-label-placeholder-column-search": "Wyszukiwanie...",
+ "srf-ui-datatables-label-content-cache": "Zawartość pochodzi z lokalnej pamięci podręcznej.",
+ "srf-ui-datatables-label-content-server": "Treść została pobrana z serwera.",
+ "srf-ui-datatables-label-multiselect-column-header": "Dostępne kolumny",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Ustawienia filtra",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Kolumny są wyświetlane",
+ "srf-ui-datatables-label-sEmptyTable": "Brak danych w tabeli",
+ "srf-ui-datatables-label-sInfoThousands": "&nbsp;",
+ "srf-ui-datatables-label-sLoadingRecords": "Wczytywanie...",
+ "srf-ui-datatables-label-sProcessing": "Przetwarzanie...",
+ "srf-ui-datatables-label-sSearch": "Szukaj:",
+ "srf-ui-datatables-label-sZeroRecords": "Nie znaleziono pasujÄ…cych pozycji",
+ "srf-ui-datatables-label-oPaginate-sFirst": "PoczÄ…tek",
+ "srf-ui-datatables-label-oPaginate-sLast": "Koniec",
+ "srf-ui-datatables-label-oPaginate-sNext": "Następne",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Poprzednie",
+ "srf-printername-tree": "Drzewo",
+ "srf-tree-noparentprop": "Nie podano żadnej właściwości nadrzędnej. Drzewo nie może zostać zbudowane bez określonej właściwości nadrzędnej.",
+ "srf-tree-rootinvalid": "$1 nie jest poprawnym tytułem strony.",
+ "srf-paramdesc-tree-parent": "Właściwość zawierająca stronę nadrzędną",
+ "srf-paramdesc-tree-root": "Główny strona drzewa",
+ "srf-paramdesc-tree-startlevel": "Poziom poczÄ…tkowy drzewa, np. do zintegrowania go z innym drzewem",
+ "srf-paramdesc-delay": "Opóźnienie między slajdami w sekundach",
+ "srf-paramdesc-effect": "Efekt, który ma być użyty do przełączania się między slajdami",
+ "srf-paramdesc-filtered-list-type": "Typ listy. Dopuszczalne wartoÅ›ci: „listaâ€, „ulâ€, „olâ€. DomyÅ›lnie: „listaâ€.",
+ "srf-paramdesc-filtered-map-height": "Wysokość mapy.",
+ "srf-paramdesc-filtered-map-min-zoom": "Minimalny dostępny poziom powiększenia mapy",
+ "srf-paramdesc-filtered-map-max-zoom": "Maksymalny dostępny poziom powiększenia mapy",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tabela",
+ "srf-filtered-selectorlabel-calendar": "Kalendarz",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-link-caption": "wyniki w formie tabelarycznej",
+ "srf-filtered-value-filter-and": "I",
+ "srf-filtered-value-filter-or": "LUB",
+ "srf-filtered-value-filter-placeholder": "Wybierz wartość filtra",
+ "srf-printername-d3chart": "Wykres D3",
+ "srf-printername-timeseries": "Wykres szeregów czasowych",
+ "srf-paramdesc-group": "Serii pogrupowane według",
+ "srf-paramdesc-zoom": "Włącz powiększanie",
+ "srf-paramdesc-pageitems": "Elementów na stronie",
+ "srf-printername-eventcalendar": "Kalendarz wydarzeń",
+ "srf-paramdesc-calendarfirstday": "Pierwszy dzień tygodnia",
+ "srf-ui-eventcalendar-label-today": "Dzisiaj",
+ "srf-ui-eventcalendar-label-month": "MiesiÄ…c",
+ "srf-ui-eventcalendar-label-week": "Tydzień",
+ "srf-ui-eventcalendar-label-day": "Dzień",
+ "srf-ui-eventcalendar-label-listmonth": "MiesiÄ…c (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Tydzień (lista)",
+ "srf-ui-eventcalendar-label-listday": "Dzień (lista)",
+ "srf-ui-eventcalendar-label-update-success": "Aktualizacja kalendarza wydarzeń zakończyła się pomyślnie.",
+ "srf-ui-eventcalendar-label-update-error": "Aktualizacja kalendarza wydarzeń nie powiodła się.",
+ "srf-ui-eventcalendar-click-popup": "Chcesz utworzyć wydarzenie?",
+ "srf-paramdesc-yaxislabel": "Opis osi y",
+ "srf-paramdesc-xaxislabel": "Opis osi x",
+ "srf-paramdesc-unit": "Jednostka",
+ "srf-paramdesc-min": "Wartość minimalna lub progowa",
+ "srf-paramdesc-excludeproperty": "Wyklucz właściwość ze zbioru wyników",
+ "srf-printername-media": "Odtwarzacz multimedialny",
+ "srf-paramdesc-mediainspector": "Wyświetla szczegółowe informacje o określonym elemencie multimedialnym",
+ "srf-ui-mediaplayer-label-previous": "Poprzedni",
+ "srf-ui-mediaplayer-label-play": "Odtwórz",
+ "srf-ui-mediaplayer-label-pause": "Pauza",
+ "srf-ui-mediaplayer-label-next": "Następny",
+ "srf-ui-mediaplayer-label-stop": "Stop",
+ "srf-ui-mediaplayer-label-mute": "Wycisz",
+ "srf-ui-mediaplayer-label-volume-max": "Maksymalna głośność",
+ "srf-ui-mediaplayer-label-shuffle": "Odtwarzanie losowe",
+ "srf-ui-mediaplayer-label-shuffle-off": "Wyłączenie odtwarzania losowego",
+ "srf-ui-mediaplayer-label-repeat": "Powtórz",
+ "srf-ui-mediaplayer-label-repeat-off": "Powtarzanie wyłączone",
+ "srf-ui-mediaplayer-label-full-screen": "Pełny ekran",
+ "srf-ui-mediaplayer-label-restore-screen": "Przywróć ekran",
+ "srf-paramdesc-icalendar-timezone": "Lista stref czasowych przedzielana przecinkami"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pms.json b/www/wiki/extensions/SemanticResultFormats/i18n/pms.json
new file mode 100644
index 00000000..f5d6168a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pms.json
@@ -0,0 +1,232 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt",
+ "පසිඳු කà·à·€à·’න්ද",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Formà adissionaj për anterogassion an linia ëd Semantic MediaWiki",
+ "prefs-srf": "Formà dj'Arzultà Semàntich",
+ "srf-prefs-intro-text": "A l'ha anstalà l'estension Formà dj'Arzultà Semàntich che al moment a l'ha gnun-e opsion utent përsonalisabij. Për assistensa, për piasì, ch'a vìsita la pagina d'agiut [http://www.semantic-mediawiki.org/wiki/Help:Result_formats formà dj'arzultà]",
+ "srf-module-loading": "A caria ...",
+ "srf-paramdesc-layout": "Visualisassion disponìbij",
+ "srf-paramdesc-height": "Autëssa",
+ "srf-paramdesc-width": "Larghëssa",
+ "srf-paramdesc-class": "Spessifiché na classa adissional ëd feuj dë stil an cascada",
+ "srf-module-nomatch": "A-i é pa gnun-a ròba parèj",
+ "srf-paramdesc-charttype": "Sòrt ëd gràfich disponìbil",
+ "srf-navigation-previous": "Prima",
+ "srf-ui-navigation-prev": "Andaré",
+ "srf-ui-navigation-next": "Apress",
+ "srf-ui-common-label-source": "Sorgiss",
+ "srf-ui-common-label-datasource": "Sorgiss dij dat",
+ "srf-ui-common-label-ajax-error": "Ël servent a l'ha arportà na comunicassion falìa për $1. Për piasì, ch'a preuva a rinfrësché la pàgina o ch'a consulta $2.",
+ "srf-ui-common-label-request-object": "ciamé n'ogèt",
+ "srf-ui-common-label-help-section": "session d'agiut",
+ "srf-ui-tooltip-title-options": "Opsion",
+ "srf-ui-tooltip-title-scope": "But",
+ "srf-error-option-mix": "L'opsion ($1) a l'é pa disponìbil",
+ "srf-error-option-link-all": "L'opsion ($1) a veul che ël paràmetr \"link\" a sia ampostà a \"all\"",
+ "srf-error-missing-layout": "Visualisassion mancanta",
+ "srf-warn-empy-chart": "La tàula o ël gràfich a son veuid a càusa ëd dat mancant",
+ "srfc_previousmonth": "Meis prima",
+ "srfc_nextmonth": "Meis apress",
+ "srfc_today": "Ancheuj",
+ "srfc_gotomonth": "Va al meis",
+ "srf_printername_calendar": "Armanach dël meis",
+ "srf_paramdesc_calendarlang": "Ël còdes për la lenga ant la qual visualisé ël calendari",
+ "srf_paramdesc_calendarcolors": "Ël color da mostré për minca propietà dla data (për esempi: \"Start date=>green,End date=>#09c\")",
+ "srf_printername_vcard": "esportassion ëd vCard",
+ "srf_printername_icalendar": "esportassion d'iCalendar",
+ "srf_paramdesc_icalendartitle": "Ël tìtol ëd l'archivi dël calendari",
+ "srf_paramdesc_icalendardescription": "La descrission ëd l'achivi dël calendari",
+ "srf_printername_bibtex": "esportassion BibTeX",
+ "srf_outline_novalue": "Pa gnun valor",
+ "srf_printername_outline": "Fòra linia",
+ "srf_paramdesc_outlineproperties": "La lista ëd proprietà da visualisé com antestassion, separà da vìrgole",
+ "srf_printername_sum": "Total dij nùmer",
+ "srf_printername_average": "Media dij nùmer",
+ "srf_printername_max": "Nùmer pì gròss",
+ "srf_printername_min": "Nùmer pì cit",
+ "srf_paramdesc_limit": "Ël nùmer màssim ëd pàgine da ciamé",
+ "srf_printername_product": "Prodòt dij nùmer",
+ "srf_printername_median": "Media dij nùmer",
+ "srf-paramdesc-default": "Valor predefinì che a sarà smonù quand a-i é gnun arzultà numérich",
+ "srf_printername_earliest": "Prima ora",
+ "srf_printername_latest": "Ùltima ora",
+ "srf_printername_timeline": "Cronologìa",
+ "srf_printername_eventline": "Cronologìa dj'event",
+ "srf_paramdesc_timelinebands": "A definiss che partìe a son visualisà ant l'arzultà.",
+ "srf_paramdesc_timelineposition": "A definiss andoa la cronologìa a part inissialment.",
+ "srf_paramdesc_timelinestart": "Ël nòm ëd na proprietà dovrà për definì un prim pont ëd temp",
+ "srf_paramdesc_timelineend": "Ël nòm ëd na proprietà dovrà për definì un secont pont ëd temp",
+ "srf_paramdesc_timelinesize": "L'autëssa dla cronologìa",
+ "srf-timeline-allresults": "Àutri arzultà për cost'arserca.",
+ "srf-timeline-nojs": "A dev avèj JavaScript abilità për vëdde la bara dij temp anterativa.",
+ "srf_paramdesc_views": "Le viste da visualisé",
+ "srf_paramdesc_facets": "L'ansema ëd proprietà da visualisé për minca pàgina",
+ "srf_paramdesc_lens": "Ël nòm ëd në stamp con ël qual visualisé le proprietà dle pàgine",
+ "srf_printername_googlebar": "Ël diagrama a bare ëd Google",
+ "srf_printername_googlepie": "Ël diagrama a torta ëd Google",
+ "srf-printername-jqplotchart": "gràfich jqPlot",
+ "srf-printername-jqplotseries": "serie jqPlot",
+ "srf_paramdesc_chartheight": "Spessifiché l'autëssa (an pontin) dël gràfich o dël diagrama",
+ "srf_paramdesc_chartwidth": "Spessifiché la larghëssa (an pontin o përsentual) del gràfich o dël diagrama",
+ "srf_paramdesc_charttitle": "Ël tìtol dël gràfich",
+ "srf_paramdesc_barcolor": "Ël color ëd le bare",
+ "srf_paramdesc_bardirection": "Specìfica la diression d'un gràfich",
+ "srf-paramdesc-direction": "Specìfica la diression d'un gràfich o d'un diagrama",
+ "srf_paramdesc_barnumbersaxislabel": "La tichëtta për l'ass dij nùmer",
+ "srf-paramdesc-labelaxislabel": "La tichëtta për l'ass dle tichëtte",
+ "srf-paramdesc-ticklabels": "Abilité la visualisassion dle tichëtte da sponté",
+ "srf-paramdesc-minvalue": "Ël valor mìnim da smon-e dzora l'ass Y",
+ "srf-paramdesc-pointlabels": "Smon-e ij pont dij dat an gràfich",
+ "srf-paramdesc-chartlegend": "Posission dla legenda dël gràfich",
+ "srf-paramdesc-datalabels": "Tichëtte dat dël gràfich/diagrama",
+ "srf-paramdesc-charttext": "Test descritiv dël gràfich",
+ "srf-paramdesc-chartclass": "Classa adissional ëd CSS",
+ "srf-paramdesc-renderer": "Selession-a un visualisador ëd diagrama/gràfich",
+ "srf-paramdesc-filling": "Opsion andividual d'ampiniment",
+ "srf-paramdesc-theme": "Selession-a un tema ëd grija",
+ "srf-paramdesc-chartcolor": "Assigné dij color andividuaj ëd gràfich",
+ "srf-paramdesc-colorscheme": "Selession-a në schema ëd color",
+ "srf-paramdesc-valueformat": "Specìfica la régola ëd formatassion për valor",
+ "srf-paramdesc-highlighter": "Smon-e n'evidensiator ëd pont ëd dat",
+ "srf-paramdesc-smoothlines": "Apliché n'algoritm ëd livelament dzor ël grafich a linie",
+ "srf-paramdesc-stackseries": "Smon-e ël gràfich tanme serie ëd pilie",
+ "srf-paramdesc-seriesgroup": "Selessioné j'argropament ëd le serie",
+ "srf-paramdesc-serieslabel": "Detérmina la tichëtta dle serie",
+ "srf-paramdesc-grouplabel": "Detérmina la tichëtta dla partìa",
+ "srf-paramdesc-chartcursor": "Opsion ëd visualisassion dël cursor dël gràfich",
+ "srf-paramdesc-trendline": "Abilité le visualisassion simultanie dël gràfich e ëd soa linia ëd tendensa",
+ "srf-paramdesc-gridview": "Smon-e ij gràfich e le serie ëd dat simultaneament. Valor përmëttù: gnun e tabulassion. Predefinì: gnun.",
+ "srf-paramdesc-infotext": "Smon-e j'anformassion adissionaj dzora na tabulassion d'anformassion corëspondente",
+ "srf-ui-gridview-label-item": "element ëd dat",
+ "srf-ui-gridview-label-value": "Valor ëd dat",
+ "srf-ui-gridview-label-series": "Serie ëd dat",
+ "srf-ui-gridview-label-chart-tab": "Gràfich",
+ "srf-ui-gridview-label-data-tab": "Dàit",
+ "srf-ui-gridview-label-info-tab": "Anformassion",
+ "srf_printername_gallery": "Galarìa",
+ "srf_paramdesc_perrow": "Ël total ëd figure për riga",
+ "srf_paramdesc_widths": "La larghëssa dla figure",
+ "srf_paramdesc_heights": "L'autëssa dle figure",
+ "srf_paramdesc_autocaptions": "Dovré ël nòm d'archivi com descrission quand che gnun-a a l'é dàita",
+ "srf_paramdesc_fileextensions": "Quand as deuvra ël nòm ëd l'archivi com didascalìa, smon-e ëdcò l'estension dl'archivi",
+ "srf_paramdesc_captionproperty": "Ël nòm ëd na propietà semàntica presenta an sle pàgine ciamà da dovré com didascalìa",
+ "srf_paramdesc_imageproperty": "Ël nòm ëd na propietà semantica an sle pàgine ciamà ch'a ponta a dle figure da dovré. Quand ampostà, le pàgine ciamà mideme a saran pa smonùe com figure",
+ "srf-paramdesc-redirects": "Ël nòm ëd na propietà semantica presenta an sle pàgine ciamà ch'a conten la destinassion ëd la ridiression",
+ "srf-paramdesc-navigation": "Contròl ëd navigassion ëd la visualisassion",
+ "srf-paramdesc-overlay": "Abilité la covertura dla figura",
+ "srf-gallery-navigation-previous": "Prima",
+ "srf-gallery-navigation-next": "Apress",
+ "srf-gallery-overlay-count": "Figura $1 ëd $2",
+ "srf-gallery-image-url-error": "La figura a l'é pa stàita trovà",
+ "srf_printername_tagcloud": "Ansema ëd tichëtte",
+ "srf_paramdesc_includesubject": "Se ij nòm dël soget midem a dovrìo esse ancludù",
+ "srf_paramdesc_increase": "Com aumenté la dimension dle tichëtte",
+ "srf_paramdesc_tagorder": "L'órdin dle tichëtte",
+ "srf_paramdesc_mincount": "Ël nùmer mìnim ëd vire che un valor a dev ancapité për esse listà",
+ "srf_paramdesc_minsize": "La dimension dle tichëtte pi cite an persentual",
+ "srf_paramdesc_maxsize": "La dimension dle tichëtte pi gròsse an përsentual",
+ "srf_paramdesc_maxtags": "La quantità màssima ëd tichëtte ant l'ansema",
+ "srf-paramdesc-excludetags": "Gavé le tichëtte (delimitador: ;)",
+ "srf_printername_valuerank": "Classìfica dij valor",
+ "srf_printername_array": "Tàula",
+ "srf_paramdesc_pagetitle": "S'a venta smon-e ij tìtoj ëd pàgina com vos ëd l'arzultà o lasseje fòra",
+ "srf_paramdesc_hidegaps": "S'a venta smon-e na propietà da stampé ma nen disponìbil e argistré ij valor separà da 'd separator o lassela fòra",
+ "srf_paramdesc_arrayname": "Se dàit e si ArrayEstension a l'é disponìbil sòn a creerà na tàula con ij nòm ëspessìfich (gnun-a stampa visìbil antlora)",
+ "srf_paramdesc_propsep": "Separator tra le proprietà ciamà",
+ "srf_paramdesc_manysep": "Separator tra tanti valor ëd propietà valorisà",
+ "srf_paramdesc_recordsep": "Separator tra ij valor ëd le propietà d'argistrassion",
+ "srf_paramdesc_headersep": "Separador tra nòm ëd propietà e valor se «headers» a l'é ampostà a «show» o «plain»",
+ "srf_printername_hash": "Taj",
+ "srf_paramdesc_hashname": "Se dàit e l'estension HashTables a l'é disponìbil sòn a creerà un taj con ël nòm ëspessìfich (gnun-a stampa visìbil antlora)",
+ "srf-printername-graph": "Gràfich",
+ "srf-paramdesc-graph-relation": "Ij soget o le propietà ëd nòm son-ne dij pare o dij fieuj?",
+ "srf-paramdesc-graph-nameprop": "A përmët d'amposté na propietà che a sarà dovrà com soget al pòst dël soget atual",
+ "srf-paramdesc-graph-nodeshape": "La forma ëd minca vértes ant ël gràf",
+ "srf-paramdesc-graphname": "Tìtol",
+ "srf-paramdesc-graphsize": "Dimension dël graf (an pontin)",
+ "srf-paramdesc-graphlegend": "Mostré la legenda dël graf o nò",
+ "srf-paramdesc-graphlabel": "Tichëtta dël gràfich",
+ "srf-paramdesc-rankdir": "Diression dla flecia",
+ "srf-paramdesc-graphlink": "Liura al graf",
+ "srf-paramdesc-graphcolor": "Color dël gràfich",
+ "srf-paramdesc-graph-wwl": "Lìmit dl'a cap automàtich dla paròla (an nùmer ëd caràter)",
+ "srf-printername-datatables": "Tàule ëd dàit",
+ "srf-printername-tree": "Erbo",
+ "srf-printername-ultree": "Erbo UI",
+ "srf-printername-oltree": "Erbo Ol",
+ "srf-tree-noparentprop": "Gnun-a propietà a mont dàita. L'erbo a peul pa esse fàit sensa na propietà a mont specificà.",
+ "srf-paramdesc-tree-parent": "La propietà a conten la pàgina a mont",
+ "srf-printername-slideshow": "Sequensa ëd diapositive",
+ "srf-paramdesc-delay": "Ël ritard tra le diapositive an second",
+ "srf-paramdesc-navigation-controls": "Smon-e ij contròj ëd navigassion o pa",
+ "srf-paramdesc-effect": "L'efet da dovré për passé da na diapositiva a n'àutra",
+ "srf-printername-filtered": "Filtrà",
+ "srf-paramdesc-filtered-views": "Le visualisassion ch'a dovrìo esse disponìbij ant la visualisassion arzultà.",
+ "srf-paramdesc-filtered-filter-position": "La posission dij filtr an relassion a le visualisassion, Valor përmëttù: testa, pé. Predefinì: testa.",
+ "srf-paramdesc-filtered-list-type": "La sòrt ëd la lista. Valor përmëttù: list, ul, ol. Predefinì: list.",
+ "srf-paramdesc-filtered-list-template": "Lë stamp da dovré për formaté le vos dla lista.",
+ "srf-paramdesc-filtered-list-named-args": "Deje un nòm a j'argoment passà a lë stamp.",
+ "srf-paramdesc-filtered-list-introtemplate": "Ël nòm ëd në stamp da mostré prima dj'arzultà dl'arserca, s'a-i në j'é.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Ël nòm ëd në stamp da mostré apress j'arzultà dl'arserca, s'a-i në j'é.",
+ "srf-paramdesc-filtered-calendar-start": "La stampa contenent la data inissial ëd n'event",
+ "srf-paramdesc-filtered-calendar-end": "La stampa contenta la data final ëd n'event",
+ "srf-paramdesc-filtered-calendar-title": "la stampa contenenta ël tìtol ëd n'event. As peul pa dovresse ansema a në stamp ëd tìtol.",
+ "srf-paramdesc-filtered-calendar-title-template": "Në stamp dovrà për formaté ël tìtol ëd n'event ant ël calendari",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-calendar": "Calendari",
+ "srf-printername-d3chart": "Gràfich D3",
+ "srf-printername-timeseries": "Gràfich ëd serie temporaj",
+ "srf-paramdesc-group": "Serie argropà për",
+ "srf-paramdesc-zoom": "Abilité l'angrandiment",
+ "srf-paramdesc-datatable": "Abilité na tàula ëd dat",
+ "srf-timeseries-zoom-out-of-range": "L'antërval d'angrandiment a dà pa a basta 'd dat",
+ "srf-printername-sparkline": "Gràfich dë sparkline",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Specìfica la sòrt ëd lista",
+ "srf-paramdesc-widget": "Acessòri disponìbij",
+ "srf-paramdesc-pageitems": "Element për pàgina",
+ "srf-printername-eventcalendar": "Calendari dj'event",
+ "srf-paramdesc-calendarfirstday": "Ël di che minca sman-a a ancamin-a",
+ "srf-paramdesc-calendardefaultview": "La visualisassion inissial cand as caria ël calendari",
+ "srf-paramdesc-calendarstart": "Ël prinsipi dël calendari (data o valor ëd data e ora)",
+ "srf-paramdesc-calendarlegend": "A specìfica la posission ëd la legenda e dj'opsion dij filtr assignà",
+ "srf-paramdesc-dayview": "Abìlita la visualisassion dij di sgnacand ël nùmer dël di",
+ "srf-ui-eventcalendar-label-today": "Ancheuj",
+ "srf-ui-eventcalendar-label-month": "Mèis",
+ "srf-ui-eventcalendar-label-week": "Sman-a",
+ "srf-ui-eventcalendar-label-day": "Di",
+ "srf-ui-eventcalendar-label-allday": "Tùit ij di",
+ "srf-printername-dygraphs": "Gràfich ëd dygraphs",
+ "srf-paramdesc-datasource": "La sorgiss d'andoa la data a l'é acessìbil. Valor përmëttù: file, raw e url. Predefinì: file.",
+ "srf-paramdesc-errorbar": "La bara d'eror da dovré. Valor përmëttù: fraction (antërval ëd confidensa per ij valor), sigma (deviassion stàndard dij valor) e range (antërval ëd valor përsonalisà)",
+ "srf-paramdesc-movingaverage": "Smon-e la media dzora un nùmer ëd di (zero a andicherà gnun cangiament ëd media)",
+ "srf-paramdesc-yaxislabel": "Descrission ch'as vëdd an sl'ass y",
+ "srf-paramdesc-xaxislabel": "Descrission ch'as vëdd an sl'ass x",
+ "srf-paramdesc-unit": "Unità",
+ "srf-printername-pagewidget": "Pagewidget",
+ "srf-printername-incoming": "Propietà an intrada",
+ "srf-paramdesc-min": "Mìnim o valor ëd seuja",
+ "srf-paramdesc-excludeproperty": "Esclude na propietà da l'ansem dj'arzultà",
+ "srf-printername-media": "Letor multimojen",
+ "srf-paramdesc-mediainspector": "A smon dj'anformassion detajà a propòsit ëd n'element multimojen specificà",
+ "srf-ui-mediaplayer-label-previous": "Prima",
+ "srf-ui-mediaplayer-label-play": "Fé parte",
+ "srf-ui-mediaplayer-label-pause": "Pàusa",
+ "srf-ui-mediaplayer-label-next": "Apress",
+ "srf-ui-mediaplayer-label-stop": "Fërma",
+ "srf-ui-mediaplayer-label-mute": "Mut",
+ "srf-ui-mediaplayer-label-unmute": "Unmute",
+ "srf-ui-mediaplayer-label-volume-max": "Volum màssim",
+ "srf-ui-mediaplayer-label-shuffle": "A asar",
+ "srf-ui-mediaplayer-label-shuffle-off": "Dëstissé l'ordinament për asar",
+ "srf-ui-mediaplayer-label-repeat": "Arpet",
+ "srf-ui-mediaplayer-label-repeat-off": "Dëstissé l'arpetission",
+ "srf-ui-mediaplayer-label-full-screen": "Scren antregh",
+ "srf-ui-mediaplayer-label-restore-screen": "Ripristiné lë scren"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ps.json b/www/wiki/extensions/SemanticResultFormats/i18n/ps.json
new file mode 100644
index 00000000..b93aabc6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ps.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "srf-module-loading": "رابرسÛرÛÚ–ÙŠ...",
+ "srf-ui-tooltip-title-options": "خوښنÛ",
+ "srfc_previousmonth": "Ù¾Ø®ÙˆØ§Ù†Û Ù…ÙŠØ§Ø´Øª",
+ "srfc_nextmonth": "Ø±Ø§ØªÙ„ÙˆÙ†Ú©Û Ù…ÙŠØ§Ø´Øª",
+ "srfc_today": "نن",
+ "srfc_gotomonth": "مياشت ته ورÚÙ‡",
+ "srf-ui-gridview-label-info-tab": "مالومات",
+ "srf_printername_gallery": "انÚورتون",
+ "srf-gallery-navigation-previous": "پخوانی",
+ "srf-gallery-navigation-next": "راتلونکی",
+ "srf-ui-datatables-label-placeholder-column-search": "پلټل...",
+ "srf-ui-datatables-label-sSearch": "پلټل:",
+ "srf-filtered-selectorlabel-list": "لړليک",
+ "srf-ui-eventcalendar-label-today": "نن",
+ "srf-ui-eventcalendar-label-month": "مياشت",
+ "srf-ui-eventcalendar-label-week": "اونÛ",
+ "srf-ui-eventcalendar-label-day": "ورÚ",
+ "srf-ui-eventcalendar-label-allday": "ټوله ورÚ",
+ "srf-ui-mediaplayer-label-play": "غږول",
+ "srf-ui-mediaplayer-label-stop": "درول",
+ "srf-ui-mediaplayer-label-mute": "ټپول",
+ "srf-ui-mediaplayer-label-unmute": "ناټپول"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pt-br.json b/www/wiki/extensions/SemanticResultFormats/i18n/pt-br.json
new file mode 100644
index 00000000..b51e0522
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pt-br.json
@@ -0,0 +1,356 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eduardo.mps",
+ "GKnedo",
+ "Giro720",
+ "Jaideraf",
+ "Luckas Blade",
+ "Luckas",
+ "!Silent",
+ "Nemo bis",
+ "Eduardo Addad de Oliveira",
+ "Trigonometria87",
+ "Andrecpe"
+ ]
+ },
+ "srf-desc": "Formatos adicionais de resultado para consultas do Semantic MediaWiki",
+ "prefs-srf": "Semantic Result Formats",
+ "srf-prefs-intro-text": "Você instalou a extensão Semantic Result Formats. Para mais informações, por favor visite as [https://www.semantic-mediawiki.org/wiki/Help:Result_formats páginas de ajuda dos formatos de resultado].",
+ "prefs-srf-eventcalendar-options": "Opções do calendário de eventos",
+ "srf-prefs-eventcalendar-options-update-default": "Habilitar as [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates atualizações automáticas] dos eventos de calendário durante a atualização da página",
+ "srf-prefs-eventcalendar-options-paneview-default": "Habilite a exibição do painel por padrão",
+ "prefs-srf-datatables-options": "Opções do DataTables",
+ "srf-prefs-datatables-options-update-default": "Habilitar as [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates atualizações automáticas] do conteúdo da tabela durante a atualização da página",
+ "srf-prefs-datatables-options-cache-default": "Habilitar o [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage armazenamento local] para melhorar o tempo de resposta",
+ "srf-module-loading": "Carregando...",
+ "srf-paramdesc-layout": "Layout disponível",
+ "srf-paramdesc-height": "Altura",
+ "srf-paramdesc-width": "Largura",
+ "srf-paramdesc-class": "Especifique uma classe CSS adicional",
+ "srf-module-nomatch": "Nenhuma correspondência encontrada",
+ "srf-paramdesc-charttype": "Tipo de gráfico disponível",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "Anterior",
+ "srf-ui-navigation-next": "Proximo",
+ "srf-ui-common-label-source": "Fonte",
+ "srf-ui-common-label-datasource": "Fontes de dados",
+ "srf-ui-common-label-ajax-error": "O servidor relatou uma falha na comunicação para este $1. Por favor, tente atualizar a página ou consultar com esse $2.",
+ "srf-ui-common-label-request-object": "objeto solicitado",
+ "srf-ui-common-label-help-section": "seção de ajuda",
+ "srf-ui-tooltip-title-options": "Opções",
+ "srf-ui-tooltip-title-scope": "Contexto",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtro",
+ "srf-ui-common-label-refresh": "Atualizar",
+ "srf-ui-common-label-parameters": "Parâmetros",
+ "srf-ui-common-label-query": "Consulta",
+ "srf-ui-common-label-paneview": "Painel de visualização",
+ "srf-ui-common-label-daterange": "Intervalo de data",
+ "srf-ui-widgets-label-parameter-limit": "Parâmetro limit",
+ "srf-error-option-mix": "A opção ($1) não está disponível",
+ "srf-error-option-link-all": "A opção ($1) requer o parâmetro \"link\" definido como \"all\"",
+ "srf-error-missing-layout": "O diagrama ou gráfico não pode ser mostrado porque o layout está faltando.",
+ "srf-error-jqplot-bubble-data-length": "Não é possível mostrar o diagrama ou o gráfico por falta de dados.",
+ "srf-error-jqplot-stackseries-data-length": "O diagrama ou gráfico não pode ser mostrado porque nem todas as barras ou linhas têm o mesmo número de elementos.",
+ "srf-warn-empy-chart": "O quadro ou gráfico está vazio devido à dados ausentes",
+ "srf-paramdesc-color": "A cor para marcar as entradas do calendário",
+ "srfc_previousmonth": "Mês anterior",
+ "srfc_nextmonth": "Mês seguinte",
+ "srfc_today": "Hoje",
+ "srfc_gotomonth": "Ir para o mês",
+ "srf_printername_calendar": "Calendário mensal",
+ "srf_paramdesc_calendarlang": "O código de idioma em que será apresentado o calendário",
+ "srf_paramdesc_calendarcolors": "A cor a ser exibida para cada propriedade de data (exemplo: \"Start date=>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "O mês com o qual a exibição do calendário é inicializada (o padrão é o mês atual)",
+ "srf-paramdesc-calendar-startyear": "O ano com o qual a exibição do calendário é inicializada (o padrão é o ano atual)",
+ "srf_vcard_link": "vCard",
+ "srf_printername_vcard": "Exportação em vCard",
+ "srf_icalendar_link": "iCalendário",
+ "srf_printername_icalendar": "Exportação em iCalendar",
+ "srf_paramdesc_icalendartitle": "O título do arquivo do calendário",
+ "srf_paramdesc_icalendardescription": "A descrição do arquivo do calendário",
+ "srf_printername_bibtex": "Exportação em BibTeX",
+ "srf_outline_novalue": "Nenhum valor",
+ "srf_printername_outline": "Lista estruturada",
+ "srf_paramdesc_outlineproperties": "A lista das propriedades a serem apresentadas como cabeçalhos das listas estruturadas, separadas por vírgulas",
+ "srf_printername_sum": "Soma dos números",
+ "srf_printername_average": "Média dos números",
+ "srf_printername_max": "Número máximo",
+ "srf_printername_min": "Número mínimo",
+ "srf_paramdesc_limit": "O número máximo de páginas a serem consultadas",
+ "srf_printername_product": "Produto dos números",
+ "srf_printername_median": "Mediana dos números",
+ "srf-paramdesc-default": "O valor padrão que será exibido quando não houver qualquer resultado numérico",
+ "srf_printername_earliest": "Tempo mais antigo",
+ "srf_printername_latest": "Tempo mais recente",
+ "srf_printername_timeline": "Linha do tempo",
+ "srf_printername_eventline": "Cronograma de eventos",
+ "srf_paramdesc_timelinebands": "Define quais grupos são apresentadas nos resultados.",
+ "srf_paramdesc_timelineposition": "Define onde é que o cronograma inicialmente está focado.",
+ "srf_paramdesc_timelinestart": "Um nome de propriedade usado para definir um primeiro ponto no tempo.",
+ "srf_paramdesc_timelineend": "Um nome de propriedade usado para definir um segundo ponto no tempo",
+ "srf_paramdesc_timelinesize": "A altura do cronograma",
+ "srf-timeline-allresults": "Mais resultados para esta consulta.",
+ "srf-timeline-nojs": "Você precisa ter o JavaScript habilitado para visualizar a linha do tempo interativa.",
+ "srf_paramdesc_views": "As visualizações a serem apresentadas",
+ "srf_paramdesc_facets": "O conjunto de propriedades a ser apresentado para cada página",
+ "srf_paramdesc_lens": "O nome de uma predefinição usada para apresentar as propriedades das páginas",
+ "srf_printername_googlebar": "Gráfico de barras do Google",
+ "srf_printername_googlepie": "Gráfico de pizza do Google",
+ "srf-printername-jqplotchart": " Gráfico jqPlot",
+ "srf-printername-jqplotseries": "Série jqPlot",
+ "srf_paramdesc_chartheight": "Especifique a altura do gráfico ou quadro (em pixels)",
+ "srf_paramdesc_chartwidth": "Especifique a largura do gráfico ou quadro (em pixels ou porcentagem)",
+ "srf_paramdesc_charttitle": "O título do gráfico",
+ "srf_paramdesc_barcolor": "Especifique as cores do quadro",
+ "srf_paramdesc_bardirection": "Especifique a orientação do gráfico",
+ "srf-paramdesc-direction": "Especifica a direção de um quadro ou gráfico",
+ "srf_paramdesc_barnumbersaxislabel": "A legenda para o eixo dos números",
+ "srf-paramdesc-labelaxislabel": "A legenda para o nome do eixo",
+ "srf-paramdesc-ticklabels": "Habilitar exibição dos rótulos de seleção",
+ "srf-paramdesc-minvalue": "O valor mínimo a ser mostrado no eixo y",
+ "srf-paramdesc-pointlabels": "Exibir pontos de dados no gráfico",
+ "srf-paramdesc-chartlegend": "Posição da legenda do gráfico",
+ "srf-paramdesc-datalabels": "Rótulos dos dados do quadro/gráfico",
+ "srf-paramdesc-charttext": "Texto descritivo do gráfico",
+ "srf-paramdesc-chartclass": "Clase CSS adicional",
+ "srf-paramdesc-renderer": "Selecione um renderizador de gráficos/quadros",
+ "srf-paramdesc-filling": "Opção de preenchimento individual",
+ "srf-paramdesc-theme": "Selecione um tema de grade",
+ "srf-paramdesc-chartcolor": "Atribuir cores individuais ao gráfico",
+ "srf-paramdesc-colorscheme": "Selecione um esquema de cores",
+ "srf-paramdesc-valueformat": "Especifica regras de formatação para valores",
+ "srf-paramdesc-highlighter": "Exibe um destaque de ponto de dados",
+ "srf-paramdesc-smoothlines": "Aplica um algorítmo de suavização nos gráficos de linhas",
+ "srf-paramdesc-stackseries": "Exibir o gráfico como uma série empilhada",
+ "srf-paramdesc-seriesgroup": "Selecione grupos de séries",
+ "srf-paramdesc-serieslabel": "Determina o rótulo da série",
+ "srf-paramdesc-grouplabel": "Determina o rótulo do grupo",
+ "srf-paramdesc-chartcursor": "Opção de exibição do cursor gráfico",
+ "srf-paramdesc-trendline": "Habilita a exibição simultânea de um gráfico e suas linhas de tendência",
+ "srf-paramdesc-gridview": "Exibe simultaneamente o gráfico e os conjuntos de dados. Valores permitidos: \"none\" e \"tabs\". Padrão: \"none\".",
+ "srf-paramdesc-paneview": "Especifica a posição do quadro que contém um pequeno gráfico de linha. Os valores permitidos são: \"bottom\", \"top\" e \"none\". Padrão: \"bottom\"",
+ "srf-paramdesc-infotext": "Exibe informações adicionais em uma aba correspondente",
+ "srf-paramdesc-clicktarget": "Definir uma página ou seqüência de consulta como alvo ao clicar em uma data de calendário.",
+ "srf-ui-gridview-label-item": "Item dos dados",
+ "srf-ui-gridview-label-value": "Valor dos dados",
+ "srf-ui-gridview-label-series": "Série de dados",
+ "srf-ui-gridview-label-chart-tab": "Gráfico",
+ "srf-ui-gridview-label-data-tab": "Dados",
+ "srf-ui-gridview-label-info-tab": "Informações",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_perrow": "A quantidade de imagens por linha",
+ "srf_paramdesc_widths": "A largura das imagens",
+ "srf_paramdesc_heights": "A altura das imagens",
+ "srf_paramdesc_autocaptions": "Usar o nome do arquivo como legenda quando nenhum for fornecido",
+ "srf_paramdesc_fileextensions": "Ao usar o nome do arquivo como legenda, mostrar também a extensão do arquivo",
+ "srf_paramdesc_captionproperty": "O nome de uma propriedade semântica presente nas páginas consultadas para ser usado como legenda",
+ "srf_paramdesc_imageproperty": "O nome de uma propriedade semântica nas páginas consultadas que aponta para imagens a usar. Quando definido, as próprias páginas consultadas não serão mostradas como imagens",
+ "srf-paramdesc-redirects": "O nome de uma propriedade semântica nas páginas consultadas que contém o alvo do redirecionamento",
+ "srf-paramdesc-navigation": "Controle do layout de navegação",
+ "srf-paramdesc-overlay": "Habilitar a sobreposição de imagens",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Próximo",
+ "srf-gallery-overlay-count": "Imagem $1 de $2",
+ "srf-gallery-image-url-error": "A imagem não foi encontrada.",
+ "srf_printername_tagcloud": "Nuvem de tags",
+ "srf_paramdesc_includesubject": "Se os nomes dos próprios sujeitos devem ser incluídos",
+ "srf_paramdesc_increase": "Como aumentar o tamanho das tags",
+ "srf_paramdesc_tagorder": "A ordem das tags",
+ "srf_paramdesc_mincount": "O número mínimo de vezes que um valor deve ocorrer, para ser listado",
+ "srf_paramdesc_minsize": "O tamanho das tags menores, em porcentagem",
+ "srf_paramdesc_maxsize": "O tamanho das tags maiores, em porcentagem",
+ "srf_paramdesc_maxtags": "A quantidade máxima de tags na nuvem",
+ "srf-paramdesc-excludetags": "Excluir tags (delimitador: \";\")",
+ "srf_printername_valuerank": "Ranking de valores",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Se deseja apresentar os títulos das páginas como resultados ou omiti-los",
+ "srf_paramdesc_hidegaps": "Se deseja exibir os valores das propriedades e registros vazios separados por separadores ou omiti-los",
+ "srf_paramdesc_arrayname": "Se especificado e a ArrayExtension estiver disponível, isso criará uma array com o nome especificado (nesse caso, sem uma saída visível)",
+ "srf_paramdesc_propsep": "Separador entre as propriedades solicitadas",
+ "srf_paramdesc_manysep": "Separador entre propriedades com mais de um valor",
+ "srf_paramdesc_recordsep": "Separador entre valores de propriedades de registro",
+ "srf_paramdesc_headersep": "Separador entre o nome e o valor da propriedade se \"headers\" estiver definido como \"show\" ou \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Se especificado e a extensão HashTables estiver disponível, isso criará um hash com o nome especificado (nesse caso, sem uma saída visível)",
+ "srf-printername-graph": "Gráfico",
+ "srf-paramdesc-graph-relation": "Configura se os sujeitos ou as propriedades dos nomes são pais ou filhos",
+ "srf-paramdesc-graph-nameprop": "Configura a propriedade que será utilizada como sujeito ao invés do verdadeiro sujeito, ou seja, o nome da página",
+ "srf-paramdesc-graph-nodeshape": "Configura a forma de cada nó no gráfico",
+ "srf-paramdesc-graphname": "Configura o título do gráfico",
+ "srf-paramdesc-graphsize": "Configura o tamanho do gráfico em pixels",
+ "srf-paramdesc-graphlegend": "Configura se uma legenda para o gráfico deve ser exibida",
+ "srf-paramdesc-graphlabel": "Configura o rótulo do gráfico",
+ "srf-paramdesc-rankdir": "Configura a direção das setas",
+ "srf-paramdesc-graphlink": "Configura se os nós devem receber links para suas respectivas páginas wiki.",
+ "srf-paramdesc-graphcolor": "Configura a cor do gráfico",
+ "srf-paramdesc-graph-wwl": "Configura o limite da quebra de linha (em número de caracteres)",
+ "srf-paramdesc-clustercolor": "Configura as cores dos \"cluster boxes\"",
+ "srf-paramdesc-highlight": "Configura o nó a ser destacado",
+ "srf-paramdesc-highlightcolor": "Configura a cor da fonte para o nó destacado",
+ "srf-paramdesc-redlinkcolor": "Configura a cor da fonte para os links em vermelho",
+ "srf-paramdesc-processcategory": "Define a categoria wiki coletando as etapas do processo",
+ "srf-paramdesc-showroles": "Mostra as funções correspondentes no gráfico",
+ "srf-paramdesc-showstatus": "Define se um status de etapa do processo deve ser processado",
+ "srf-paramdesc-showresources": "Mostra os recursos correspondentes no gráfico",
+ "srf-paramdesc-showdiscussion": "Define se uma discussão deve ser processada",
+ "srf-paramdesc-showredlinks": "Define se os links vermelhos devem ser verificados e destacados",
+ "srf-paramdesc-showcompound": "Define se os vértices compostos (isto é, os subprocessos) devem ser destacados",
+ "srf-paramdesc-debug": "Define se o código do gráfico do processo deve ser mostrado etiquetas previas envolvidas",
+ "srf-paramdesc-graphvalidation": "Exibe as etapas do processo em vermelho que não possuem função atribuída",
+ "srf-printername-datatables": "DataTables",
+ "srf-ui-datatables-label-conditions": "Condições",
+ "srf-ui-datatables-label-parameters": "Parâmetros",
+ "srf-ui-datatables-label-filters": "Filtros de coluna e busca",
+ "srf-ui-datatables-label-information": "Informação",
+ "srf-ui-datatables-panel-disclaimer": "Parâmetros e condições podem ser alteradas, mas qualquer mudança é temporária e abandonada após uma atualização da página.",
+ "srf-ui-datatables-label-update-success": "A atualização da tabela foi realizada com sucesso.",
+ "srf-ui-datatables-label-update-error": "A atualização da tabela falhou.",
+ "srf-ui-datatables-label-placeholder-column-search": "Procura…",
+ "srf-ui-datatables-label-content-cache": "O conteúdo foi derivado do cache local.",
+ "srf-ui-datatables-label-content-server": "O conteúdo foi derivado do servidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Colunas disponíveis",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Configurações de filtro",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Colunas são visíveis",
+ "srf-ui-datatables-label-sEmptyTable": "Nenhum dado disponível na tabela",
+ "srf-ui-datatables-label-sInfo": "Exibindo _START_ até _END_ de _TOTAL_ linhas",
+ "srf-ui-datatables-label-sInfoEmpty": "Exibindo 0 até 0 de 0 linhas",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtrado a partir de _MAX_ linhas totais)",
+ "srf-ui-datatables-label-sInfoThousands": ".",
+ "srf-ui-datatables-label-sLengthMenu": "Exibir _MENU_ linhas",
+ "srf-ui-datatables-label-sLoadingRecords": "Carregando…",
+ "srf-ui-datatables-label-sProcessing": "Processando…",
+ "srf-ui-datatables-label-sSearch": "Pesquisar:",
+ "srf-ui-datatables-label-sZeroRecords": "Nenhuma correspondência encontrada",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primeiro",
+ "srf-ui-datatables-label-oPaginate-sLast": "Último",
+ "srf-ui-datatables-label-oPaginate-sNext": "Próximo",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": ativar alfabetação ascendente da tabela",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": ativar alfabetação descendente da tabela",
+ "srf-printername-tree": "Ãrvore",
+ "srf-printername-ultree": "Ãrvore (marcadores)",
+ "srf-printername-oltree": "Ãrvore (números)",
+ "srf-tree-noparentprop": "Nenhuma propriedade pai dada. A árvore não pode ser construída sem uma propriedade pai especificada.",
+ "srf-tree-rootinvalid": "$1 não é um título de página válido.",
+ "srf-tree-circledetected": "Foi detetada uma referência circular ao tentar inserir $1 na árvore.",
+ "srf-paramdesc-tree-parent": "A propriedade que contém a página pai",
+ "srf-paramdesc-tree-root": "A página raiz da hierarquia",
+ "srf-paramdesc-tree-startlevel": "O nível inicial da hierarquia, por exemplo, para integrá-lo em outra hierarquia",
+ "srf-printername-slideshow": "SlideShow",
+ "srf-paramdesc-delay": "O tempo entre os slides, em segundos",
+ "srf-paramdesc-navigation-controls": "Mostrar ou não os controles de navegação",
+ "srf-paramdesc-effect": "O efeito a ser utilizado para a transição de slides",
+ "srf-printername-filtered": "Filtrado",
+ "srf-paramdesc-filtered-views": "As visualizações que deverão estar disponíveis na exibição do resultado.",
+ "srf-paramdesc-filtered-filter-position": "A posição dos filtros em relação às visualizações. Valores permitidos: \"top\", \"bottom\". Padrão: \"top\".",
+ "srf-paramdesc-filtered-list-type": "O tipo de lista. Valores permitidos: \"list\", \"ul\", \"ol\". Padrão: \"list\".",
+ "srf-paramdesc-filtered-list-template": "A predefinição a ser utilizada para formatar as entradas da lista.",
+ "srf-paramdesc-filtered-list-named-args": "Nomeie os argumentos passados para a predefinição",
+ "srf-paramdesc-filtered-list-introtemplate": "Nome da predefinição a ser exibida antes dos resultados da consulta, se existir algum resultado.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Nome da predefinição a ser exibida após os resultados da consulta, se existir algum resultado.",
+ "srf-paramdesc-filtered-calendar-start": "A exibição que contém a data de início de um evento",
+ "srf-paramdesc-filtered-calendar-end": "A exibição que contém a data final de um evento",
+ "srf-paramdesc-filtered-calendar-title": "A exibição que contém o título de um evento. Não pode ser utilizado junto com um título de uma predefinição.",
+ "srf-paramdesc-filtered-calendar-title-template": "Uma predefinição utilizada para formatar o título do evento no calendário",
+ "srf-paramdesc-filtered-map-position": "A impressão que contém a posição geográfica.",
+ "srf-paramdesc-filtered-map-icon": "A impressão que decide o ícone de mapa a ser usado.",
+ "srf-paramdesc-filtered-map-icons": "Um mapa entre valores e ícones a serem usados para estes valores no mapa.",
+ "srf-paramdesc-filtered-map-height": "A altura do mapa.",
+ "srf-paramdesc-filtered-map-zoom": "O nível do zoom quando o mapa é carregado. Pode ser alterado pelo usuário.<br>Consulte: <i>vista mapa zoom mínimo</i> e <i>vista mapa zoom máximo</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "O mínimo de nível de zoom selecionável do mapa",
+ "srf-paramdesc-filtered-map-max-zoom": "O nível máximo de zoom selecionável do mapa",
+ "srf-paramdesc-filtered-map-marker-cluster": "Ativar ou desativar o agrupamento de marcadores.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Nível de zoom máximo no qual os marcadores de mapa ainda estão agrupados. Acima deste nível, os marcadores serão sempre descompactados.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "O raio máximo que um agrupamento cobrirá a partir do marcador central (em pixéis). Padrão: 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Quando ativado, clicar um agrupamento faz um zoom até os limites desse agrupamento.",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tabela",
+ "srf-filtered-selectorlabel-calendar": "Calendário",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "Os resultados não podem ser apresentados porque o Javascript não está ativado. Visite $1.",
+ "srf-filtered-noscript-link-caption": "Resultados em forma de tabela",
+ "srf-filtered-map-provider-missing-error": "Nenhum fornecedor de mapa especificado para exibição de \"mapa\".",
+ "srf-filtered-value-filter-and": "E",
+ "srf-filtered-value-filter-or": "OU",
+ "srf-filtered-value-filter-placeholder": "Selecionar um valor de filtro",
+ "srf-printername-d3chart": "Gráfico D3",
+ "srf-printername-timeseries": "Gráfico de séries temporais",
+ "srf-paramdesc-group": "Séries agrupadas por",
+ "srf-paramdesc-zoom": "Ativar zoom",
+ "srf-paramdesc-datatable": "Ativar uma tabela de dados",
+ "srf-timeseries-zoom-out-of-range": "O alcance do zoom não produziu dados suficientes",
+ "srf-printername-sparkline": "Gráfico Sparkline",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Especificar o tipo de lista",
+ "srf-paramdesc-widget": "Widget disponível",
+ "srf-paramdesc-pageitems": "Itens por página",
+ "srf-printername-eventcalendar": "Calendário de eventos",
+ "srf-paramdesc-calendarfirstday": "O dia em que cada semana começa",
+ "srf-paramdesc-calendardefaultview": "A exibição inicial quando o calendário carrega",
+ "srf-paramdesc-calendarstart": "O começo do calendário inicial (valores de data ou de data e hora)",
+ "srf-paramdesc-calendarlegend": "Especifica a posição da legenda e as opções de filtro atribuídas",
+ "srf-paramdesc-dayview": "Habilitar o modo de exibição do dia clicando no número do dia",
+ "srf-ui-eventcalendar-label-today": "Hoje",
+ "srf-ui-eventcalendar-label-month": "Mês",
+ "srf-ui-eventcalendar-label-week": "Semana",
+ "srf-ui-eventcalendar-label-day": "Dia",
+ "srf-ui-eventcalendar-label-listmonth": "Mês (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Semana (lista)",
+ "srf-ui-eventcalendar-label-listday": "Dia (lista)",
+ "srf-ui-eventcalendar-label-allday": "O dia todo",
+ "srf-ui-eventcalendar-format-title-week": "MMM D, AAAA",
+ "srf-ui-eventcalendar-format-title-day": "MMMM D, AAAA",
+ "srf-ui-eventcalendar-label-update-success": "A atualização do calendário de eventos foi executada com êxito.",
+ "srf-ui-eventcalendar-label-update-error": "A atualização do calendário de eventos falhou.",
+ "srf-ui-eventcalendar-click-popup": "Deseja criar um evento?",
+ "srf-printername-dygraphs": "Gráfico Dygraphs",
+ "srf-paramdesc-datasource": "A fonte onde os dados estão acessíveis. Valores permitidos: \"file\", \"raw\" e \"url\". Padrão: \"file\".",
+ "srf-paramdesc-errorbar": "A barra de erro a ser utilizada. Valores permitidos: \"fraction\" (intervalos de confiança para os valores), \"sigma\" (desvio-padrão dos valores) e \"range\" (intervalos de valores personalizados).",
+ "srf-paramdesc-movingaverage": "Exibir a média ao longo de vários dias (zero indicará nenhuma média móvel)",
+ "srf-paramdesc-yaxislabel": "Descrição que aparece no eixo y",
+ "srf-paramdesc-xaxislabel": "Descrição que aparece no eixo x",
+ "srf-paramdesc-unit": "Unidade",
+ "srf-printername-pagewidget": "Widget de página",
+ "srf-printername-incoming": "Propriedades afluentes",
+ "srf-paramdesc-count": "Define se o número de propriedades recebidas deve ser contado",
+ "srf-paramdesc-min": "Mínimo ou valor limite",
+ "srf-paramdesc-excludeproperty": "Excluir a propriedade do conjunto de resultados",
+ "srf-printername-media": "Player de mídia",
+ "srf-paramdesc-mediainspector": "Exibe informações detalhadas sobre um elemento de mídia especificado",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reproduzir",
+ "srf-ui-mediaplayer-label-pause": "Pausar",
+ "srf-ui-mediaplayer-label-next": "Próximo",
+ "srf-ui-mediaplayer-label-stop": "Parar",
+ "srf-ui-mediaplayer-label-mute": "Mudo",
+ "srf-ui-mediaplayer-label-unmute": "Reativar",
+ "srf-ui-mediaplayer-label-volume-max": "Volume máximo",
+ "srf-ui-mediaplayer-label-shuffle": "Aleatório",
+ "srf-ui-mediaplayer-label-shuffle-off": "Desativar aleatoriedade",
+ "srf-ui-mediaplayer-label-repeat": "Repetir",
+ "srf-ui-mediaplayer-label-repeat-off": "Desativar repetição",
+ "srf-ui-mediaplayer-label-full-screen": "Tela inteira",
+ "srf-ui-mediaplayer-label-restore-screen": "Restaurar tela",
+ "srf-spreadsheet-link": "Planilha",
+ "srf-paramdesc-spreadsheet-filename": "O nome de arquivo para o download da folha de cálculo gerada.",
+ "srf-paramdesc-spreadsheet-fileformat": "O formato a ser produzido para o arquivo da folha de cálculo. Os valores permitidos são: xlsx, xls, ods, csv. Por omissão: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "O nome de um arquivo de planilha do namespace ''Arquivo'' usado para formatar o arquivo gerado",
+ "srf-paramdesc-icalendar-timezone": "Uma lista de fusos horários, separados por vírgulas",
+ "srf-paramdesc-gantt-diagramtitle": "Nome do diagrama",
+ "srf-paramdesc-gantt-diagramtheme": "Tema do diagrama",
+ "srf-paramdesc-gantt-axisformat": "X-axis: Formato de data",
+ "srf-paramdesc-gantt-sortkey": "Chave para ordenar sessões e tarefas",
+ "srf-paramdesc-gantt-titletopmargin": "Margem superior do título do diagrama",
+ "srf-paramdesc-gantt-barheight": "Altura das barras de tarefas",
+ "srf-paramdesc-gantt-leftpadding": "Largura do título da seção",
+ "srf-paramdesc-gantt-bargap": "Distância vertical das barras de tarefas para a margem",
+ "srf-error-gantt-mapping-assignment": "Atribuição errada de valores mapeados em '''$1'''",
+ "srf-error-gantt-mapping-keywords": "A chave usada em seu parâmetro de mapeamento não é suportada",
+ "srf-error-gantt-theme": "O '''tema''' escolhido não é suportado",
+ "srf-error-gantt-sortkey": "A '''sortkey''' que você escolheu não é suportado",
+ "srf-error-gantt-mermaid-not-installed": "A Extensão Mermaid precisa ser instalado.",
+ "srf-printername-gantt": "Gantt",
+ "srf-paramdesc-nodelabel": "Use um rótulo de nó de gráfico. Valores permitidos: displaytitle."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/pt.json b/www/wiki/extensions/SemanticResultFormats/i18n/pt.json
new file mode 100644
index 00000000..5e1832e8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/pt.json
@@ -0,0 +1,352 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hamilton Abreu",
+ "Malafaya",
+ "SandroHc",
+ "Waldir",
+ "Vitorvicentevalente",
+ "Macofe",
+ "Ngl2016",
+ "Nemo bis",
+ "Athena in Wonderland",
+ "Waldyrious"
+ ]
+ },
+ "srf-desc": "Formatos adicionais de resultados para consultas do MediaWiki Semântico",
+ "prefs-srf": "Extension:Formatos dos resultados semânticos",
+ "srf-prefs-intro-text": "Tem instalada a extensão Formatos dos Resultados Semânticos. Para ajuda adicional, visite a página de ajuda [https://www.semantic-mediawiki.org/wiki/Help:Result_formats formatos de resultados], por favor.",
+ "prefs-srf-eventcalendar-options": "Opções do calendário de eventos",
+ "srf-prefs-eventcalendar-options-update-default": "Ativar as [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates atualizações automáticas] dos eventos de calendário durante a atualização da página",
+ "srf-prefs-eventcalendar-options-paneview-default": "Ativar a vista do painel por padrão",
+ "prefs-srf-datatables-options": "Opções de tabelas de dados",
+ "srf-prefs-datatables-options-update-default": "Ativar as [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates atualizações automáticas] do conteúdo de tabelas durante a atualização de páginas",
+ "srf-prefs-datatables-options-cache-default": "Ativar o [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage armazenamento local] para melhorar o tempo de resposta",
+ "srf-module-loading": "A carregar...",
+ "srf-paramdesc-layout": "Formato disponível",
+ "srf-paramdesc-height": "Altura",
+ "srf-paramdesc-width": "Largura",
+ "srf-paramdesc-class": "Especificar uma classe CSS adicional",
+ "srf-module-nomatch": "Não foram encontradas correspondências",
+ "srf-paramdesc-charttype": "Tipo de gráfico disponível",
+ "srf-navigation-previous": "Anterior",
+ "srf-ui-navigation-prev": "Anterior",
+ "srf-ui-navigation-next": "Próximo",
+ "srf-ui-common-label-source": "Fonte",
+ "srf-ui-common-label-datasource": "Fonte de dados",
+ "srf-ui-common-label-ajax-error": "O servidor reportou uma falha de comunicação para este $1. Tente atualizar a página ou consulte esta $2.",
+ "srf-ui-common-label-request-object": "objeto do pedido",
+ "srf-ui-common-label-help-section": "secção da ajuda",
+ "srf-ui-tooltip-title-options": "Opções",
+ "srf-ui-tooltip-title-scope": "Âmbito",
+ "srf-ui-tooltip-title-legend": "Legenda",
+ "srf-ui-tooltip-title-filter": "Filtro",
+ "srf-ui-common-label-refresh": "Atualizar",
+ "srf-ui-common-label-parameters": "Parâmetros",
+ "srf-ui-common-label-query": "Consulta",
+ "srf-ui-common-label-paneview": "Vista do painel",
+ "srf-ui-common-label-daterange": "Intervalo de datas",
+ "srf-ui-widgets-label-parameter-limit": "Parâmetro de limite",
+ "srf-error-option-mix": "A opção ($1) não está disponível",
+ "srf-error-option-link-all": "A opção ($1) precisa que o parâmetro \"link\" esteja definido como \"all\"",
+ "srf-error-missing-layout": "Não é possível mostrar o diagrama ou o gráfico porque falta a formatação.",
+ "srf-error-jqplot-bubble-data-length": "Não é possível mostrar o diagrama ou o gráfico por falta de dados.",
+ "srf-error-jqplot-stackseries-data-length": "Não é possível mostrar o diagrama ou o gráfico porque nem todas as barras ou linhas têm o mesmo número de elementos.",
+ "srf-warn-empy-chart": "O diagrama ou gráfico está vazio devido a falta de dados",
+ "srf-paramdesc-color": "A cor para marcar as entradas do calendário",
+ "srfc_previousmonth": "Mês anterior",
+ "srfc_nextmonth": "Mês seguinte",
+ "srfc_today": "Hoje",
+ "srfc_gotomonth": "Ir para mês",
+ "srf_printername_calendar": "Calendário mensal",
+ "srf_paramdesc_calendarlang": "O código da língua em que será apresentado o calendário",
+ "srf_paramdesc_calendarcolors": "A cor a ser apresentada para cada propriedade de data (exemplo: \"Data de início=>green,Data de fim=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "O mês inicial na apresentação do calendário (por omissão, o mês atual)",
+ "srf-paramdesc-calendar-startyear": "O ano inicial na apresentação do calendário (por omissão, o ano atual)",
+ "srf_printername_vcard": "exportação vCard",
+ "srf_icalendar_link": "iCalendário",
+ "srf_printername_icalendar": "exportação iCalendar",
+ "srf_paramdesc_icalendartitle": "O título do ficheiro do calendário",
+ "srf_paramdesc_icalendardescription": "A descrição do ficheiro do calendário",
+ "srf_printername_bibtex": "exportação BibTeX",
+ "srf_outline_novalue": "Nenhum valor",
+ "srf_printername_outline": "Lista estruturada",
+ "srf_paramdesc_outlineproperties": "A lista das propriedades apresentadas como cabeçalhos das listas estruturadas, separadas por vírgulas",
+ "srf_printername_sum": "Soma dos números",
+ "srf_printername_average": "Média dos números",
+ "srf_printername_max": "Número máximo",
+ "srf_printername_min": "Número mínimo",
+ "srf_paramdesc_limit": "O número máximo de páginas a consultar",
+ "srf_printername_product": "Produto dos números",
+ "srf_printername_median": "Mediana dos números",
+ "srf-paramdesc-default": "O valor padrão que será apresentado quando não houver resultados numéricos",
+ "srf_printername_earliest": "Primeira hora",
+ "srf_printername_latest": "Última hora",
+ "srf_printername_timeline": "Cronograma",
+ "srf_printername_eventline": "Cronograma de eventos",
+ "srf_paramdesc_timelinebands": "Define que bandas são apresentadas no resultado.",
+ "srf_paramdesc_timelineposition": "Define onde é que o cronograma está focado inicialmente.",
+ "srf_paramdesc_timelinestart": "Um nome de propriedade, usado para definir um primeiro ponto no tempo",
+ "srf_paramdesc_timelineend": "Um nome de propriedade, usado para definir um segundo ponto no tempo",
+ "srf_paramdesc_timelinesize": "A altura do cronograma",
+ "srf-timeline-allresults": "Mais resultados desta consulta.",
+ "srf-timeline-nojs": "Para ver o cronograma interactivo tem de ativar o JavaScript.",
+ "srf_paramdesc_views": "As vistas que serão apresentadas",
+ "srf_paramdesc_facets": "O conjunto de propriedades que serão apresentadas para cada página",
+ "srf_paramdesc_lens": "O nome de uma predefinição usada para apresentar as propriedades das páginas",
+ "srf_printername_googlebar": "Gráfico de barras Google",
+ "srf_printername_googlepie": "Gráfico circular Google",
+ "srf-printername-jqplotchart": "Gráfico jqPlot",
+ "srf-printername-jqplotseries": "Série jqPlot",
+ "srf_paramdesc_chartheight": "Especificar a altura do gráfico ou quadro (em pixéis)",
+ "srf_paramdesc_chartwidth": "Especificar a largura do gráfico ou quadro (em pixéis)",
+ "srf_paramdesc_charttitle": "O título do gráfico",
+ "srf_paramdesc_barcolor": "Especificar as cores do gráfico",
+ "srf_paramdesc_bardirection": "Especificar a orientação de um gráfico",
+ "srf-paramdesc-direction": "Especificar a orientação de um diagrama ou gráfico",
+ "srf_paramdesc_barnumbersaxislabel": "A legenda para o eixo dos números",
+ "srf-paramdesc-labelaxislabel": "A legenda para o eixo das etiquetas",
+ "srf-paramdesc-ticklabels": "Ativar a apresentação de rótulos",
+ "srf-paramdesc-minvalue": "O valor mínimo a mostrar no eixo y",
+ "srf-paramdesc-pointlabels": "Apresentar pontos de dados nos gráficos",
+ "srf-paramdesc-chartlegend": "Posição da legenda do gráfico",
+ "srf-paramdesc-datalabels": "Etiquetas de dados no diagrama ou gráfico",
+ "srf-paramdesc-charttext": "Texto descritivo do gráfico",
+ "srf-paramdesc-chartclass": "Classe CSS adicional",
+ "srf-paramdesc-renderer": "Selecione um apresentador de gráficos ou diagramas",
+ "srf-paramdesc-filling": "Opção de preenchimento individual",
+ "srf-paramdesc-theme": "Selecione um tema de grelha",
+ "srf-paramdesc-chartcolor": "Atribuir cores individuais ao gráfico",
+ "srf-paramdesc-colorscheme": "Selecione um esquema de cores",
+ "srf-paramdesc-valueformat": "Especificar a regra de formatação para valores",
+ "srf-paramdesc-highlighter": "Apresentar um realçador de ponto de dados",
+ "srf-paramdesc-smoothlines": "Aplicar um algoritmo de suavização nos gráficos de linhas",
+ "srf-paramdesc-stackseries": "Apresentar o gráfico como uma série de barras empilhadas",
+ "srf-paramdesc-seriesgroup": "Selecionar o agrupamento das séries",
+ "srf-paramdesc-serieslabel": "Determinar o rótulo da série",
+ "srf-paramdesc-grouplabel": "Determinar o rótulo do grupo",
+ "srf-paramdesc-chartcursor": "Opção de apresentação do cursor do gráfico",
+ "srf-paramdesc-trendline": "Ativar a apresentação simultânea de um gráfico e da sua linha de tendência",
+ "srf-paramdesc-gridview": "Apresentar simultaneamente o gráfico e os conjuntos de dados. Valores permitidos: \"none\" e \"tabs\". Por omissão: \"none\"",
+ "srf-paramdesc-paneview": "Especificar a posição do painel, que contém um pequeno gráfico de linha. Valores permitidos: \"bottom\", \"top\" e \"none\". Por omissão: \"bottom\"",
+ "srf-paramdesc-infotext": "Apresentar informação adicional num separador informativo correspondente",
+ "srf-paramdesc-clicktarget": "Definir uma página ou texto de consulta como destino ao clicar uma data de calendário.",
+ "srf-ui-gridview-label-item": "Elemento de dados",
+ "srf-ui-gridview-label-value": "Valor de dados",
+ "srf-ui-gridview-label-series": "Série de dados",
+ "srf-ui-gridview-label-chart-tab": "Gráfico",
+ "srf-ui-gridview-label-data-tab": "Dados",
+ "srf-ui-gridview-label-info-tab": "Informação",
+ "srf_printername_gallery": "Galeria",
+ "srf_paramdesc_perrow": "A quantidade de imagens por linha",
+ "srf_paramdesc_widths": "A largura das imagens",
+ "srf_paramdesc_heights": "A altura das imagens",
+ "srf_paramdesc_autocaptions": "Usar o nome do ficheiro como legenda se esta não for fornecida",
+ "srf_paramdesc_fileextensions": "Ao usar o nome do ficheiro como legenda, mostrar também a extensão",
+ "srf_paramdesc_captionproperty": "O nome de uma propriedade semântica presente nas páginas consultadas para ser usado como legenda",
+ "srf_paramdesc_imageproperty": "O nome de uma propriedade semântica nas páginas consultadas que aponta para imagens a usar. Quando definido, as próprias páginas consultadas não serão mostradas como imagens",
+ "srf-paramdesc-redirects": "O nome de uma propriedade semântica presente nas páginas consultadas que contêm o destino do redirecionamento",
+ "srf-paramdesc-navigation": "Controlo de navegação da formatação",
+ "srf-paramdesc-overlay": "Ativar a sobreposição de imagens",
+ "srf-gallery-navigation-previous": "Anterior",
+ "srf-gallery-navigation-next": "Seguinte",
+ "srf-gallery-overlay-count": "Imagem $1 de $2",
+ "srf-gallery-image-url-error": "A imagem não foi encontrada.",
+ "srf_printername_tagcloud": "Nuvem de tags",
+ "srf_paramdesc_includesubject": "Os nomes dos próprios assuntos devem ser incluídos",
+ "srf_paramdesc_increase": "Como aumentar o tamanho das tags",
+ "srf_paramdesc_tagorder": "A ordem das tags",
+ "srf_paramdesc_mincount": "O número mínimo de vezes que um valor deve ocorrer, para ser listado",
+ "srf_paramdesc_minsize": "O tamanho das tags menores, em percentagem",
+ "srf_paramdesc_maxsize": "O tamanho das tags maiores, em percentagem",
+ "srf_paramdesc_maxtags": "A quantidade máxima de tags na nuvem",
+ "srf-paramdesc-excludetags": "Excluir as tags (delimitador: \";\")",
+ "srf_printername_valuerank": "Ocorrências do valor",
+ "srf_printername_array": "Matriz",
+ "srf_paramdesc_pagetitle": "Apresentar os títulos das páginas como entradas nos resultados, ou omiti-los",
+ "srf_paramdesc_hidegaps": "Imprimir os valores das propriedades e registos pedidos mas indisponíveis, separados por separadores, ou omiti-los",
+ "srf_paramdesc_arrayname": "Se especificado e a ArrayExtension estiver disponível, isto criará uma matriz com o nome especificado (neste caso, sem resultado visível)",
+ "srf_paramdesc_propsep": "Separador entre as propriedades solicitadas",
+ "srf_paramdesc_manysep": "Separador entre os valores de propriedades com mais do que um valor",
+ "srf_paramdesc_recordsep": "Separador entre os valores das propriedades do registo",
+ "srf_paramdesc_headersep": "Separador entre o nome e o valor da propriedade, se \"headers\" for definido como \"show\" ou \"plain\"",
+ "srf_printername_hash": "Resumo criptográfico (\"hash\")",
+ "srf_paramdesc_hashname": "Se especificado e a extensão HashTables estiver disponível, isto cria um resumo criptográfico (\"hash\") com o nome especificado (neste caso, sem resultado visível)",
+ "srf-printername-graph": "Grafo",
+ "srf-paramdesc-graph-relation": "Define se os assuntos ou as propriedades dos nomes (\"nameproperties\") são pais ou filhos",
+ "srf-paramdesc-graph-nameprop": "Define a propriedade que será usada como assunto em vez do verdadeiro assunto, isto é, o nome da página",
+ "srf-paramdesc-graph-nodeshape": "Define a forma de cada vértice no grafo",
+ "srf-paramdesc-graphname": "Define o título do grafo",
+ "srf-paramdesc-graphsize": "Define o tamanho do grafo (em pixéis)",
+ "srf-paramdesc-graphlegend": "Define se deve ser mostrada uma legenda do grafo",
+ "srf-paramdesc-graphlabel": "Define o título do grafo",
+ "srf-paramdesc-rankdir": "Define a direção das setas",
+ "srf-paramdesc-graphlink": "Define se os vértices devem ser hiperligações para as respetivas páginas na wiki",
+ "srf-paramdesc-graphcolor": "Define a cor do grafo",
+ "srf-paramdesc-graph-wwl": "Define o limite para forçar nova linha (em nº de caracteres)",
+ "srf-paramdesc-clustercolor": "Define as cores das caixas de agrupamento",
+ "srf-paramdesc-highlight": "Define o vértice a ser destacado",
+ "srf-paramdesc-highlightcolor": "Define a cor da fonte para o vértice destacado",
+ "srf-paramdesc-redlinkcolor": "Define a cor da fonte para as hiperligações vermelhas",
+ "srf-paramdesc-processcategory": "Define a categoria da wiki que reúne os passos do processo",
+ "srf-paramdesc-showroles": "Mostra as funções correspondentes no grafo",
+ "srf-paramdesc-showstatus": "Define se deve ser apresentado um estado do passo do processo",
+ "srf-paramdesc-showresources": "Mostra os recursos correspondentes no grafo",
+ "srf-paramdesc-showdiscussion": "Define se deve ser apresentada uma discussão",
+ "srf-paramdesc-showredlinks": "Define se as hiperligações vermelhas devem ser verificadas e destacadas",
+ "srf-paramdesc-showcompound": "Define se os vértices compostos (isto é, os subprocessos) devem ser destacados",
+ "srf-paramdesc-debug": "Define se o código do grafo de processos deve ser mostrado entre etiquetas \"pre\"",
+ "srf-paramdesc-graphvalidation": "Apresenta a vermelho os passos do processo que não têm uma função atribuída",
+ "srf-printername-datatables": "Tabelas de dados",
+ "srf-ui-datatables-label-conditions": "Condições",
+ "srf-ui-datatables-label-parameters": "Parâmetros",
+ "srf-ui-datatables-label-filters": "Filtros de coluna e pesquisa",
+ "srf-ui-datatables-label-information": "Informação",
+ "srf-ui-datatables-panel-disclaimer": "Os parâmetros e as condições podem ser alterados, mas qualquer mudança é temporária e será abandonada após uma atualização da página.",
+ "srf-ui-datatables-label-update-success": "A tabela foi atualizada",
+ "srf-ui-datatables-label-update-error": "A atualização da tabela falhou.",
+ "srf-ui-datatables-label-placeholder-column-search": "Pesquisar...",
+ "srf-ui-datatables-label-content-cache": "O conteúdo foi obtido da cache local.",
+ "srf-ui-datatables-label-content-server": "O conteúdo foi obtido do servidor.",
+ "srf-ui-datatables-label-multiselect-column-header": "Colunas disponíveis",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Definições de filtragem",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "As colunas são visíveis",
+ "srf-ui-datatables-label-sEmptyTable": "Não há dados disponíveis na tabela",
+ "srf-ui-datatables-label-sInfo": "A mostrar entradas _START_ a _END_, de _TOTAL_",
+ "srf-ui-datatables-label-sInfoEmpty": "A mostrar entradas 0 a 0, de 0",
+ "srf-ui-datatables-label-sInfoFiltered": "(filtradas de _MAX_ entradas no total)",
+ "srf-ui-datatables-label-sInfoThousands": "&nbsp;",
+ "srf-ui-datatables-label-sLengthMenu": "Mostrar _MENU_ entradas",
+ "srf-ui-datatables-label-sLoadingRecords": "A carregar...",
+ "srf-ui-datatables-label-sProcessing": "A processar...",
+ "srf-ui-datatables-label-sSearch": "Pesquisar:",
+ "srf-ui-datatables-label-sZeroRecords": "Não foram encontrados registos com correspondências",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Primeiro",
+ "srf-ui-datatables-label-oPaginate-sLast": "Último",
+ "srf-ui-datatables-label-oPaginate-sNext": "Seguinte",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Anterior",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": ativar para ordenar a coluna por ordem crescente",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": ativar para ordenar a coluna por ordem decrescente",
+ "srf-printername-tree": "Ãrvore",
+ "srf-printername-ultree": "Ãrvore com marcadores",
+ "srf-printername-oltree": "Ãrvore numerada",
+ "srf-tree-noparentprop": "Não foi especificada nenhuma propriedade mãe. A árvore não pode ser construída se não for especificada uma propriedade mãe.",
+ "srf-tree-rootinvalid": "$1 não é um título de página válido.",
+ "srf-tree-circledetected": "Foi detetada uma referência circular ao tentar inserir $1 na árvore.",
+ "srf-paramdesc-tree-parent": "A propriedade que contém a página mãe",
+ "srf-paramdesc-tree-root": "A página de topo da árvore",
+ "srf-paramdesc-tree-startlevel": "O nível inicial da árvore; por exemplo, para integrá-la noutra árvore",
+ "srf-printername-slideshow": "Apresentação de diapositivos",
+ "srf-paramdesc-delay": "O intervalo entre diapositivos, em segundos",
+ "srf-paramdesc-navigation-controls": "Mostrar controlos de navegação, ou omiti-los",
+ "srf-paramdesc-effect": "O efeito a ser usado na transição entre diapositivos",
+ "srf-printername-filtered": "Filtrado",
+ "srf-paramdesc-filtered-views": "As vistas que estarão disponíveis na apresentação do resultado.",
+ "srf-paramdesc-filtered-filter-position": "A posição dos filtros em relação às vistas. Valores permitidos: \"top\" e \"bottom\". Por omissão: \"top\".",
+ "srf-paramdesc-filtered-list-type": "O tipo da lista. Valores permitidos: \"list\", \"ul\" e \"ol\". Por omissão: \"list\".",
+ "srf-paramdesc-filtered-list-template": "A predefinição que será usada para formatar as entradas da lista.",
+ "srf-paramdesc-filtered-list-named-args": "Nome dos argumentos passados à predefinição.",
+ "srf-paramdesc-filtered-list-introtemplate": "O nome de uma predefinição para apresentar antes dos resultados da consulta, se existirem.",
+ "srf-paramdesc-filtered-list-outrotemplate": "O nome de uma predefinição para apresentar após os resultados da consulta, se existirem.",
+ "srf-paramdesc-filtered-calendar-start": "A impressão que contém a data de início de um evento",
+ "srf-paramdesc-filtered-calendar-end": "A impressão que contém a data de fim de um evento",
+ "srf-paramdesc-filtered-calendar-title": "A impressão que contém o título de um evento. Não pode ser usado em conjunto com uma predefinição de título.",
+ "srf-paramdesc-filtered-calendar-title-template": "Uma predefinição usada para formatar o título do evento no calendário",
+ "srf-paramdesc-filtered-map-position": "A impressão que contém a posição geográfica.",
+ "srf-paramdesc-filtered-map-icon": "A impressão que decide o ícone de mapa a ser usado.",
+ "srf-paramdesc-filtered-map-icons": "Um mapa entre valores e ícones a serem usados para estes valores no mapa.",
+ "srf-paramdesc-filtered-map-height": "A altura do mapa.",
+ "srf-paramdesc-filtered-map-zoom": "O nível do zoom quando o mapa é carregado. Pode ser alterado pelo utilizador.<br>Consulte: <i>vista mapa zoom mínimo</i> e <i>vista mapa zoom máximo</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "O mínimo nível de zoom selecionável no mapa",
+ "srf-paramdesc-filtered-map-max-zoom": "O máximo nível de zoom selecionável no mapa",
+ "srf-paramdesc-filtered-map-marker-cluster": "Ligar e desligar o agrupamento de marcadores.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "Nível máximo de zoom no qual os marcadores do mapa ainda estarão agrupados. Acima deste nível, os marcadores estarão sempre desagrupados.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "O raio máximo que um agrupamento cobrirá a partir do marcador central (em pixéis). Predefinido: 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Quando ativado, clicar um agrupamento faz um zoom até os limites desse agrupamento.",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tabela",
+ "srf-filtered-selectorlabel-calendar": "Calendário",
+ "srf-filtered-selectorlabel-map": "Mapa",
+ "srf-filtered-noscript-error": "Os resultados não podem ser apresentados porque o Javascript não está ativado. Visite $1.",
+ "srf-filtered-noscript-link-caption": "resultados em forma de tabela",
+ "srf-filtered-map-provider-missing-error": "Não foi especificado um fornecedor de mapas para a vista \"mapa\".",
+ "srf-filtered-value-filter-and": "E",
+ "srf-filtered-value-filter-or": "OU",
+ "srf-filtered-value-filter-placeholder": "Selecionar um valor de filtro",
+ "srf-printername-d3chart": "Gráfico D3",
+ "srf-printername-timeseries": "Gráfico de séries temporais",
+ "srf-paramdesc-group": "Séries agrupadas por",
+ "srf-paramdesc-zoom": "Ativar ampliação",
+ "srf-paramdesc-datatable": "Ativar uma tabela de dados",
+ "srf-timeseries-zoom-out-of-range": "O alcance da ampliação não produziu dados suficientes",
+ "srf-printername-sparkline": "Gráfico sparkline",
+ "srf-printername-listwidget": "Widget de listas",
+ "srf-paramdesc-listtype": "Especificar o tipo de lista",
+ "srf-paramdesc-widget": "Widget disponível",
+ "srf-paramdesc-pageitems": "Elementos por página",
+ "srf-printername-eventcalendar": "Calendário de eventos",
+ "srf-paramdesc-calendarfirstday": "O dia em que cada semana começa",
+ "srf-paramdesc-calendardefaultview": "A vista inicial quando o calendário é carregado",
+ "srf-paramdesc-calendarstart": "A data inicial do calendário (valores de data ou de data e hora)",
+ "srf-paramdesc-calendarlegend": "Especifica a posição da legenda e as opções de filtro atribuídas",
+ "srf-paramdesc-dayview": "Ativar a vista diária clicando o número do dia",
+ "srf-ui-eventcalendar-label-today": "Hoje",
+ "srf-ui-eventcalendar-label-month": "Mês",
+ "srf-ui-eventcalendar-label-week": "Semana",
+ "srf-ui-eventcalendar-label-day": "Dia",
+ "srf-ui-eventcalendar-label-listmonth": "Mês (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Semana (lista)",
+ "srf-ui-eventcalendar-label-listday": "Dia (lista)",
+ "srf-ui-eventcalendar-label-allday": "Todo o dia",
+ "srf-ui-eventcalendar-label-update-success": "O calendário de eventos foi atualizado.",
+ "srf-ui-eventcalendar-label-update-error": "A atualização do calendário de eventos falhou.",
+ "srf-ui-eventcalendar-click-popup": "Quer criar um evento?",
+ "srf-printername-dygraphs": "Gráfico Dygraphs",
+ "srf-paramdesc-datasource": "A fonte onde os dados estão acessíveis. Valores permitidos: \"file\", \"raw\" e \"url\". Por omissão: \"file\".",
+ "srf-paramdesc-errorbar": "A barra de erro a ser utilizada. Valores permitidos: \"fraction\" (intervalos de confiança para os valores), \"sigma\" (desvio-padrão dos valores) e \"range\" (intervalos de valores personalizados).",
+ "srf-paramdesc-movingaverage": "Apresentar a média ao longo de um número de dias (zero indicará que não há média móvel)",
+ "srf-paramdesc-yaxislabel": "A descrição que aparece no eixo dos y",
+ "srf-paramdesc-xaxislabel": "A descrição que aparece no eixo dos x",
+ "srf-paramdesc-unit": "Unidade",
+ "srf-printername-pagewidget": "Widget de página",
+ "srf-printername-incoming": "Propriedades de entrada",
+ "srf-paramdesc-count": "Define se o número de propriedades de entrada deve ser contado",
+ "srf-paramdesc-min": "Valor mínimo ou patamar",
+ "srf-paramdesc-excludeproperty": "Excluir a propriedade do conjunto de resultados",
+ "srf-printername-media": "Leitor multimédia",
+ "srf-paramdesc-mediainspector": "Apresenta informação detalhada sobre um elemento multimédia especificado",
+ "srf-ui-mediaplayer-label-previous": "Anterior",
+ "srf-ui-mediaplayer-label-play": "Reproduzir",
+ "srf-ui-mediaplayer-label-pause": "Pausa",
+ "srf-ui-mediaplayer-label-next": "Seguinte",
+ "srf-ui-mediaplayer-label-stop": "Parar",
+ "srf-ui-mediaplayer-label-mute": "Silêncio",
+ "srf-ui-mediaplayer-label-unmute": "Ativar som",
+ "srf-ui-mediaplayer-label-volume-max": "Volume máximo",
+ "srf-ui-mediaplayer-label-shuffle": "Aleatório",
+ "srf-ui-mediaplayer-label-shuffle-off": "Sequencial",
+ "srf-ui-mediaplayer-label-repeat": "Repetir",
+ "srf-ui-mediaplayer-label-repeat-off": "Não repetir",
+ "srf-ui-mediaplayer-label-full-screen": "Ecrã completo",
+ "srf-ui-mediaplayer-label-restore-screen": "Restaurar o ecrã",
+ "srf-spreadsheet-link": "Folha de cálculo",
+ "srf-paramdesc-spreadsheet-filename": "O nome de ficheiro para o descarregamento da folha de cálculo gerada.",
+ "srf-paramdesc-spreadsheet-fileformat": "O formato a ser produzido para o ficheiro da folha de cálculo. Os valores permitidos são: xlsx, xls, ods, csv. Por omissão: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "O nome de ficheiro de uma folha de cálculo no espaço nominal/domínio ''Ficheiro'', usado para formatar o ficheiro gerado",
+ "srf-paramdesc-icalendar-timezone": "Uma lista de fusos horários, separados por vírgulas",
+ "srf-paramdesc-gantt-diagramtitle": "Nome do diagrama",
+ "srf-paramdesc-gantt-diagramtheme": "Tema do diagrama",
+ "srf-paramdesc-gantt-axisformat": "Eixo dos x: Formato de data",
+ "srf-paramdesc-gantt-sortkey": "Chave para ordenar secções e tarefas",
+ "srf-paramdesc-gantt-titletopmargin": "Margem superior do título do diagrama",
+ "srf-paramdesc-gantt-barheight": "Altura das barras de tarefas",
+ "srf-paramdesc-gantt-leftpadding": "Largura do título da secção",
+ "srf-paramdesc-gantt-bargap": "Distância vertical das barras de tarefas para a margem",
+ "srf-error-gantt-mapping-assignment": "Atribuição errada de valores mapeados em '''$1'''",
+ "srf-error-gantt-mapping-keywords": "A chave usada no seu parâmetro de mapeamento não é suportada",
+ "srf-error-gantt-theme": "O '''tema''' que escolheu não é suportado",
+ "srf-error-gantt-sortkey": "A '''chave de ordenação''' que escolheu não é suportada",
+ "srf-error-gantt-mermaid-not-installed": "A extensão Mermaid precisa de ser instalada.",
+ "srf-printername-gantt": "Gantt",
+ "srf-paramdesc-nodelabel": "Usar um rótulo de vértice de grafo. Valores permitidos: displaytitle."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/qqq.json b/www/wiki/extensions/SemanticResultFormats/i18n/qqq.json
new file mode 100644
index 00000000..fd3182d2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/qqq.json
@@ -0,0 +1,372 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "F.trott",
+ "Kghbln",
+ "Purodha",
+ "Raymond",
+ "Shirayuki",
+ "Siebrand",
+ "Toliño",
+ "Umherirrender",
+ "Robby",
+ "Amire80",
+ "Liuxinyu970226",
+ "ì•„ë¼",
+ "Hamilton Abreu",
+ "Nike",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "{{desc|name=Semantic Result Formats|url=https://www.mediawiki.org/wiki/Extension:Semantic_Result_Formats}}",
+ "srf-name": "This is the name of this extension (Used by the [[mw:Extension:Admin_Links|Admin Links]] extension).",
+ "prefs-srf": "This is the text of a section header on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "srf-prefs-intro-text": "This is an user preference intro text on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "prefs-srf-eventcalendar-options": "This is a section header text on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]]. \"Event calendar\" is the same thing as in {{msg-mw|Srf-printername-eventcalendar}}.",
+ "srf-prefs-eventcalendar-options-update-default": "This is the description of an user preference for the \"Event calendar\" format on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "srf-prefs-eventcalendar-options-paneview-default": "This is the description of an user preference for the \"Event calendar\" format on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "prefs-srf-datatables-options": "This is a section header text on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "srf-prefs-datatables-options-update-default": "This is the description of an user preference for the \"Datatables\" format on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "srf-prefs-datatables-options-cache-default": "This is the description of an user preference for the \"Datatables\" format on [[Special:Preferences#mw-prefsection-smw|Special:Preferences]].",
+ "srf-module-loading": "This is an informatory message.\n{{Identical|Loading}}",
+ "srf-paramdesc-layout": "{{doc-paramdesc|layout}}",
+ "srf-paramdesc-height": "{{doc-paramdesc|height}}\n{{Identical|Height}}",
+ "srf-paramdesc-width": "{{doc-paramdesc|width}}\n{{Identical|Width}}",
+ "srf-paramdesc-class": "{{doc-paramdesc|class}}",
+ "srf-module-nomatch": "This is an informatory message.",
+ "srf-paramdesc-charttype": "{{doc-paramdesc|charttype}}",
+ "srf-navigation-previous": "A label describing a navigation control component.",
+ "srf-ui-navigation-prev": "A label describing a navigation control component.\n{{Identical|Prev}}",
+ "srf-ui-navigation-next": "A label describing a navigation control component.\n{{Identical|Next}}",
+ "srf-ui-common-label-source": "{{doc-smw-ui-label|source}}\n{{Identical|Source}}",
+ "srf-ui-common-label-datasource": "{{doc-smw-ui-label|datasource}}",
+ "srf-ui-common-label-ajax-error": "Information message that is displayed during a failed Ajax communication. See [https://www.semantic-mediawiki.org/wiki/Help:Ajax Help:Ajax].\nParameters:\n* $1 is a link with {{msg-mw|srf-ui-common-label-request-object}}\n* $2 is a link with {{msg-mw|srf-ui-common-label-help-section}}",
+ "srf-ui-common-label-request-object": "Link text that appears in the message {{msg-mw|Srf-ui-common-label-ajax-error}}. It must be adapted to that sentence in terms of case, grammar endings, and so on.",
+ "srf-ui-common-label-help-section": "Link text that appears in the message {{msg-mw|Srf-ui-common-label-ajax-error}}. It must be adapted to that sentence in terms of case, grammar endings, and so on.",
+ "srf-ui-tooltip-title-options": "{{doc-smw-ui-tooltip|Options}}\n{{Identical|Options}}",
+ "srf-ui-tooltip-title-scope": "{{doc-smw-ui-tooltip|Scope}}\n{{Identical|Scope}}",
+ "srf-ui-tooltip-title-legend": "{{doc-smw-ui-tooltip|tooltip-title-legend}}\n{{Identical|Legend}}",
+ "srf-ui-tooltip-title-filter": "{{doc-smw-ui-tooltip|Filter}}\n{{Identical|Filter}}",
+ "srf-ui-common-label-refresh": "{{doc-smw-ui-label|refresh}}\n{{Identical|Refresh}}",
+ "srf-ui-common-label-parameters": "{{doc-smw-ui-label|parameters}}\n\n{{Identical|Parameter|Plural}}",
+ "srf-ui-common-label-query": "{{doc-smw-ui-label|query}}\n{{Identical|Query}}",
+ "srf-ui-common-label-paneview": "{{doc-smw-ui-label|paneview}}",
+ "srf-ui-common-label-daterange": "{{doc-smw-ui-label|daterange}}\n{{Identical|Date range}}",
+ "srf-ui-widgets-label-parameter-limit": "{{doc-smw-ui-label|parameter-limit}}",
+ "srf-error-option-mix": "This is an error message. Parameters:\n* $1 is a fixed entity name (name of the option) that cannot and should not be translated.",
+ "srf-error-option-link-all": "{{doc-important|Do not translate the parameter \"link\" and its possible value \"all\".}}\nThis is an error message. Parameters:\n* $1 is a fixed entitity name that cannot and should not be translated.",
+ "srf-error-missing-layout": "This is an error message.",
+ "srf-error-jqplot-bubble-data-length": "This is an error message.",
+ "srf-error-jqplot-stackseries-data-length": "This is an error message.",
+ "srf-warn-empy-chart": "This is an informatory message.",
+ "srf-paramdesc-color": "{{doc-paramdesc|color}}",
+ "srfc_previousmonth": "A label describing a navigation control component.",
+ "srfc_nextmonth": "A label describing a navigation control component.",
+ "srfc_today": "A label describing a navigation control component.\n{{Identical|Today}}",
+ "srfc_gotomonth": "A label describing a navigation control component.",
+ "srf_printername_calendar": "{{doc-smwformat|calendar}}",
+ "srf_paramdesc_calendarlang": "{{doc-paramdesc|lang}}",
+ "srf_paramdesc_calendarcolors": "{{doc-paramdesc|colors}}\n{{doc-important|\"Start date\" and \"End date\" should be translated, but not the other parts of the example code.}}",
+ "srf-paramdesc-calendar-startmonth": "{{doc-paramdesc|startmonth}}",
+ "srf-paramdesc-calendar-startyear": "{{doc-paramdesc|startyear}}",
+ "srf_vcard_link": "{{doc-smw-link}}",
+ "srf_printername_vcard": "{{doc-smwformat|vcard}}",
+ "srf_icalendar_link": "{{doc-smw-link}}",
+ "srf_printername_icalendar": "{{doc-smwformat|icalendar}}",
+ "srf_paramdesc_icalendartitle": "{{doc-paramdesc|title}}",
+ "srf_paramdesc_icalendardescription": "{{doc-paramdesc|description}}",
+ "srf_bibtex_link": "{{doc-smw-link}}",
+ "srf_printername_bibtex": "{{doc-smwformat|Bibtex}}",
+ "srf_outline_novalue": "This is an error message.",
+ "srf_printername_outline": "{{doc-smwformat|outline}}\n\nIt is basically a list, or nested list, of topics, subtopics, subsubtopics, etc., as deeply stacked as defined by page editors in an inline query.\nThere is an [https://www.semantic-mediawiki.org/wiki/Help:Outline_format Outline example]\n{{Identical|Outline}}",
+ "srf_paramdesc_outlineproperties": "{{doc-paramdesc|outlineproperties}}\n\n\"Outline\" means the outline of text or document here.",
+ "srf_printername_sum": "{{doc-smwformat|sum}}",
+ "srf_printername_average": "{{doc-smwformat|average}}",
+ "srf_printername_max": "{{doc-smwformat|max}}",
+ "srf_printername_min": "{{doc-smwformat|min}}",
+ "srf_paramdesc_limit": "{{doc-paramdesc|limit}}",
+ "srf_printername_product": "{{doc-smwformat|product}}",
+ "srf_printername_median": "{{doc-smwformat|median}}",
+ "srf-paramdesc-default": "{{doc-paramdesc|default}}",
+ "srf_printername_earliest": "{{doc-smwformat|earliest}}",
+ "srf_printername_latest": "{{doc-smwformat|latest}}",
+ "srf_printername_timeline": "{{doc-smwformat|timeline}}\n{{Identical|Timeline}}",
+ "srf_printername_eventline": "{{doc-smwformat|eventline}}",
+ "srf_paramdesc_timelinebands": "{{doc-smwformat|timelinebands}}",
+ "srf_paramdesc_timelineposition": "{{doc-paramdesc|timelineposition}}",
+ "srf_paramdesc_timelinestart": "{{doc-paramdesc|timelinestart}}",
+ "srf_paramdesc_timelineend": "{{doc-paramdesc|timelineend}}",
+ "srf_paramdesc_timelinesize": "{{doc-paramdesc|timelinesize}}",
+ "srf-timeline-allresults": "This is the text of a link pointing to further query results.",
+ "srf-timeline-nojs": "This is an informatory and/or error message.",
+ "srf_paramdesc_views": "{{doc-paramdesc|views}}\n\nThe [https://www.semantic-mediawiki.org/wiki/Help:Filtered_format result format \"filtered\"], part of the Semantic Result Formats extension, displays results in switchable '''views''', e.g. as map, as table, as calendar, etc.\n\nThis text is a description of the parameter \"views\" to the function that generates the \"filtered\" result format.\n\nSynonyms for '''views''' might be representation, or maybe appearance, aspect, facet",
+ "srf_paramdesc_facets": "{{doc-paramdesc|facets}}",
+ "srf_paramdesc_lens": "{{doc-paramdesc|lens}}",
+ "srf_printername_googlebar": "{{doc-smwformat|googlebar}}",
+ "srf_printername_googlepie": "{{doc-smwformat|googlepie}}",
+ "srf-printername-jqplotchart": "{{doc-smwformat|Jqplotchart}}",
+ "srf-printername-jqplotseries": "{{doc-smwformat|Jqplotseries}}",
+ "srf_paramdesc_chartheight": "{{doc-paramdesc|chartheight}}",
+ "srf_paramdesc_chartwidth": "{{doc-paramdesc|chartwidth}}",
+ "srf_paramdesc_charttitle": "{{doc-paramdesc|charttitle}}",
+ "srf_paramdesc_barcolor": "{{doc-paramdesc|barcolor}}",
+ "srf_paramdesc_bardirection": "{{doc-paramdesc|bardirection}}",
+ "srf-paramdesc-direction": "{{doc-paramdesc|direction}}",
+ "srf_paramdesc_barnumbersaxislabel": "{{doc-paramdesc|barnumbersaxislabel}}",
+ "srf-paramdesc-labelaxislabel": "{{doc-paramdesc|labelaxislabel}}",
+ "srf-paramdesc-ticklabels": "{{doc-paramdesc|ticklabels}}",
+ "srf-paramdesc-minvalue": "{{doc-paramdesc|minvalue}}",
+ "srf-paramdesc-pointlabels": "{{doc-paramdesc|pointlabels}}",
+ "srf-paramdesc-chartlegend": "{{doc-paramdesc|chartlegend}}",
+ "srf-paramdesc-datalabels": "{{doc-paramdesc|datalabels}}",
+ "srf-paramdesc-charttext": "{{doc-paramdesc|charttext}}",
+ "srf-paramdesc-chartclass": "{{doc-paramdesc|class}}",
+ "srf-paramdesc-renderer": "{{doc-paramdesc|renderer}}",
+ "srf-paramdesc-filling": "{{doc-paramdesc|filling}}",
+ "srf-paramdesc-theme": "{{doc-paramdesc|theme}}\n\n'''Related messages:'''\n*{{msg-mw|Bs-bssmwconnector-srf-printername-bsgrid}}",
+ "srf-paramdesc-chartcolor": "{{doc-paramdesc|chartcolor}}",
+ "srf-paramdesc-colorscheme": "{{doc-paramdesc|colorscheme}}",
+ "srf-paramdesc-valueformat": "{{doc-paramdesc|valueformat}}",
+ "srf-paramdesc-highlighter": "{{doc-paramdesc|highlighter}}",
+ "srf-paramdesc-smoothlines": "{{doc-paramdesc|smoothlines}}",
+ "srf-paramdesc-stackseries": "{{doc-paramdesc|stackseries}}",
+ "srf-paramdesc-seriesgroup": "{{doc-paramdesc|seriesgroup}}",
+ "srf-paramdesc-serieslabel": "{{doc-paramdesc|serieslabel}}",
+ "srf-paramdesc-grouplabel": "{{doc-paramdesc|grouplabel}}",
+ "srf-paramdesc-chartcursor": "{{doc-paramdesc|chartcursor}}",
+ "srf-paramdesc-trendline": "{{doc-paramdesc|trendline}}",
+ "srf-paramdesc-gridview": "{{doc-paramdesc|gridview}}\n{{doc-important|Do not translate the possible parameters \"none\" and \"tabs\".}}",
+ "srf-paramdesc-paneview": "{{doc-paramdesc|paneview}}\n{{doc-important|Do not translate the possible parameters \"bottom\", \"top\" and \"none\" and \"tabs\".}}\n\nSee [https://www.semantic-mediawiki.org/wiki/Help:SMW_-_Number_of_downloads this page] for an example (pane below the actual chart).",
+ "srf-paramdesc-infotext": "{{doc-paramdesc|infotext}}",
+ "srf-paramdesc-clicktarget": "{{doc-paramdesc|clicktarget}}",
+ "srf-ui-gridview-label-item": "{{doc-smw-ui-gridview}}",
+ "srf-ui-gridview-label-value": "{{doc-smw-ui-gridview}}",
+ "srf-ui-gridview-label-series": "{{doc-smw-ui-gridview}}",
+ "srf-ui-gridview-label-chart-tab": "{{doc-smw-ui-gridview}}",
+ "srf-ui-gridview-label-data-tab": "{{doc-smw-ui-gridview}}\n{{Identical|Data}}",
+ "srf-ui-gridview-label-info-tab": "{{doc-smw-ui-gridview}}\n{{Identical|Info}}",
+ "srf_printername_gallery": "{{doc-smwformat|gallery}}\n{{Identical|Gallery}}",
+ "srf_paramdesc_perrow": "{{doc-paramdesc|perrow}}",
+ "srf_paramdesc_widths": "{{doc-paramdesc|width}}",
+ "srf_paramdesc_heights": "{{doc-paramdesc|height}}",
+ "srf_paramdesc_autocaptions": "{{doc-paramdesc|autocaptions}}",
+ "srf_paramdesc_fileextensions": "{{doc-paramdesc|fileextensions}}",
+ "srf_paramdesc_captionproperty": "{{doc-paramdesc|captionproperty}}",
+ "srf_paramdesc_imageproperty": "{{doc-paramdesc|imageproperty}}",
+ "srf-paramdesc-redirects": "{{doc-paramdesc|redirects}}",
+ "srf-paramdesc-navigation": "{{doc-paramdesc|navigation}}",
+ "srf-paramdesc-overlay": "{{doc-paramdesc|overlay}}",
+ "srf-gallery-navigation-previous": "A label describing a navigation control component.",
+ "srf-gallery-navigation-next": "A label describing a navigation control component.",
+ "srf-gallery-overlay-count": "This is an informatory message. Parameters:\n* $1 is a number\n* $2 is a number",
+ "srf-gallery-image-url-error": "This is an error message.",
+ "srf_printername_tagcloud": "{{doc-smwformat|tagcloud}}",
+ "srf_paramdesc_includesubject": "{{doc-paramdesc|includesubject}}",
+ "srf_paramdesc_increase": "{{doc-paramdesc|increase}}",
+ "srf_paramdesc_tagorder": "{{doc-paramdesc|tagorder}}",
+ "srf_paramdesc_mincount": "{{doc-paramdesc|mincount}}",
+ "srf_paramdesc_minsize": "{{doc-paramdesc|minsize}}",
+ "srf_paramdesc_maxsize": "{{doc-paramdesc|maxsize}}",
+ "srf_paramdesc_maxtags": "{{doc-paramdesc|maxtags}}",
+ "srf-paramdesc-excludetags": "{{doc-paramdesc|excludetags}}",
+ "srf_printername_valuerank": "{{doc-smwformat|valuerank}}",
+ "srf_printername_array": "{{doc-smwformat|array}}\n{{Identical|Array}}",
+ "srf_paramdesc_pagetitle": "{{doc-paramdesc|pagetitle}}",
+ "srf_paramdesc_hidegaps": "{{doc-paramdesc|hidegaps}}",
+ "srf_paramdesc_arrayname": "{{doc-paramdesc|name}}",
+ "srf_paramdesc_propsep": "{{doc-paramdesc|propsep}}",
+ "srf_paramdesc_manysep": "{{doc-paramdesc|manysep}}",
+ "srf_paramdesc_recordsep": "{{doc-paramdesc|recordsep}}",
+ "srf_paramdesc_headersep": "{{doc-smwformat|headersep}}\n{{doc-important|Do not translate the parameter name \"headers\" and its possible values \"show\" or \"plain\".}}",
+ "srf_printername_hash": "{{doc-smwformat|hash}}\n{{Identical|Hash}}",
+ "srf_paramdesc_hashname": "{{doc-paramdesc|name}}",
+ "srf-printername-graph": "{{doc-smwformat|graph}}\n{{Identical|Graph}}",
+ "srf-paramdesc-graph-relation": "{{doc-paramdesc|graphrelation}}",
+ "srf-paramdesc-graph-nameprop": "{{doc-paramdesc|nameprop}}",
+ "srf-paramdesc-graph-nodeshape": "{{doc-paramdesc|nodeshape}}",
+ "srf-paramdesc-graphname": "{{doc-smwformat|graphname}}",
+ "srf-paramdesc-graphsize": "{{doc-paramdesc|graphsize}}",
+ "srf-paramdesc-graphlegend": "{{doc-paramdesc|graphlegend}}",
+ "srf-paramdesc-graphlabel": "{{doc-paramdesc|graphlabel}}",
+ "srf-paramdesc-rankdir": "{{doc-paramdesc|rankdir}}",
+ "srf-paramdesc-graphlink": "{{doc-paramdesc|graphlink}}",
+ "srf-paramdesc-graphcolor": "{{doc-paramdesc|graphcolor}}",
+ "srf-paramdesc-graph-wwl": "{{doc-paramdesc|wordwraplimit}}",
+ "srf-paramdesc-clustercolor": "{{doc-paramdesc|clustercolor}}",
+ "srf-paramdesc-highlight": "{{doc-paramdesc|highlight}}",
+ "srf-paramdesc-highlightcolor": "{{doc-paramdesc|highlightcolor}}",
+ "srf-paramdesc-redlinkcolor": "{{doc-paramdesc|redlinkcolor}}",
+ "srf-paramdesc-processcategory": "{{doc-paramdesc|processcategory}}",
+ "srf-paramdesc-showroles": "{{doc-paramdesc|showroles}}",
+ "srf-paramdesc-showstatus": "{{doc-paramdesc|showstatus}}",
+ "srf-paramdesc-showresources": "{{doc-paramdesc|showresources}}",
+ "srf-paramdesc-showdiscussion": "{{doc-paramdesc|showdiscussion}}",
+ "srf-paramdesc-showredlinks": "{{doc-paramdesc|showredlinks}}",
+ "srf-paramdesc-showcompound": "{{doc-paramdesc|showcompound}}",
+ "srf-paramdesc-debug": "{{doc-paramdesc|debug}}",
+ "srf-paramdesc-graphvalidation": "{{doc-paramdesc|graphvalidation}}",
+ "srf-printername-datatables": "{{doc-smwformat|datatables}}\n\nAlso used in {{msg-mw|Prefs-srf-datatables-options}}.",
+ "srf-ui-datatables-label-conditions": "{{doc-smw-ui-label-datatables|conditions}}\n{{Identical|Condition}}",
+ "srf-ui-datatables-label-parameters": "{{doc-smw-ui-label-datatables|parameters}}\n\n{{Identical|Parameter|Plural}}",
+ "srf-ui-datatables-label-filters": "{{doc-smw-ui-label-datatables|filters}}",
+ "srf-ui-datatables-label-information": "{{doc-smw-ui-label-datatables|information}}\n{{Identical|Information}}",
+ "srf-ui-datatables-panel-disclaimer": "Some textual information for the user",
+ "srf-ui-datatables-label-update-success": "{{doc-smw-ui-feedback|update-success}}",
+ "srf-ui-datatables-label-update-error": "{{doc-smw-ui-feedback|update-error}}",
+ "srf-ui-datatables-label-placeholder-column-search": "{{doc-smw-ui-label-datatables|placeholder-column-search}}\n{{Identical|Search}}",
+ "srf-ui-datatables-label-content-cache": "{{doc-smw-ui-label-datatables|content-cache}}",
+ "srf-ui-datatables-label-content-server": "{{doc-smw-ui-label-datatables|content-server}}",
+ "srf-ui-datatables-label-multiselect-column-header": "{{doc-smw-ui-label-datatables|multiselect-column-header}}",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "{{doc-smw-ui-label-datatables|multiselect-column-noneselectedtext}}",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "{{doc-smw-ui-label-datatables|multiselect-column-selectedtext}}",
+ "srf-ui-datatables-label-sEmptyTable": "{{doc-smw-ui-label-datatables|sEmptyTable}}",
+ "srf-ui-datatables-label-sInfo": "{{doc-smw-ui-label-datatables|sInfo}}\n{{doc-important|Do not localise the variables <code>_START_</code>, <code>_END_</code> and <code>_TOTAL_</code>}}",
+ "srf-ui-datatables-label-sInfoEmpty": "{{doc-smw-ui-label-datatables|sInfoEmpty}}",
+ "srf-ui-datatables-label-sInfoFiltered": "{{doc-smw-ui-label-datatables|sInfoFiltered}}\n{{doc-important|Do not localise the variable <code>__MAX__.</code>}}",
+ "srf-ui-datatables-label-sInfoPostFix": "{{doc-smw-ui-label-datatables|sInfoPostFix}}",
+ "srf-ui-datatables-label-sInfoThousands": "{{doc-smw-ui-label-datatables|sInfoThousands}}\n{{optional}}\nThis message is as a separator symbol for thousands in numbers, like \",\" in English 1,234.56.",
+ "srf-ui-datatables-label-sLengthMenu": "{{doc-smw-ui-label-datatables|sLengthMenu}}",
+ "srf-ui-datatables-label-sLoadingRecords": "{{doc-smw-ui-label-datatables|sLoadingRecords}}\n{{Identical|Loading}}",
+ "srf-ui-datatables-label-sProcessing": "{{doc-smw-ui-label-datatables|sProcessing}}\n{{Identical|Processing}}",
+ "srf-ui-datatables-label-sSearch": "{{doc-smw-ui-label-datatables|sSearch}}\n{{Identical|Search}}",
+ "srf-ui-datatables-label-sZeroRecords": "{{doc-smw-ui-label-datatables|sZeroRecords}}",
+ "srf-ui-datatables-label-oPaginate-sFirst": "{{doc-smw-ui-label-datatables|oPaginate-sFirst}}\n{{Identical|First}}",
+ "srf-ui-datatables-label-oPaginate-sLast": "{{doc-smw-ui-label-datatables|oPaginate-sLast}}\n{{Identical|Last}}",
+ "srf-ui-datatables-label-oPaginate-sNext": "{{doc-smw-ui-label-datatables|oPaginate-sNext}}\n{{Identical|Next}}",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "{{doc-smw-ui-label-datatables|oPaginate-sPrevious}}\n{{Identical|Previous}}",
+ "srf-ui-datatables-label-oAria-sSortAscending": "{{doc-smw-ui-label-datatables|oAria-sSortAscending}}",
+ "srf-ui-datatables-label-oAria-sSortDescending": "{{doc-smw-ui-label-datatables|oAria-sSortDescending}}",
+ "srf-printername-tree": "{{doc-smwformat|tree}}\n{{Identical|Tree}}",
+ "srf-printername-ultree": "{{doc-smwformat|ultree}}\nThis is an alias of \"tree\" {{msg-mw|Srf printername tree}}.",
+ "srf-printername-oltree": "{{doc-smwformat|oltree}}",
+ "srf-tree-noparentprop": "This is an error message. See result format [http://www.semantic-mediawiki.org/wiki/Help:Tree_format tree] for further information.",
+ "srf-tree-rootinvalid": "This is an error message.\n\nSee result format [http://www.semantic-mediawiki.org/wiki/Help:Tree_format tree] for further information.\n\nParameters:\n* $1 - the specified page title",
+ "srf-tree-circledetected": "This is an error message.\n\nSee result format [http://www.semantic-mediawiki.org/wiki/Help:Tree_format tree] for further information. Circle refers to a [https://en.wikipedia.org/wiki/Circular_reference circular reference].\n\nParameters:\n* $1 - the title of the page that was attempted to be inserted into the tree",
+ "srf-paramdesc-tree-parent": "{{doc-paramdesc|parent}}",
+ "srf-paramdesc-tree-root": "{{doc-paramdesc|root}}",
+ "srf-paramdesc-tree-startlevel": "{{doc-paramdesc|start level}}",
+ "srf-printername-slideshow": "{{doc-smwformat|slideshow}}",
+ "srf-paramdesc-delay": "{{doc-paramdesc|delay}}",
+ "srf-paramdesc-navigation-controls": "{{doc-paramdesc|nav controls}}",
+ "srf-paramdesc-effect": "{{doc-paramdesc|effect}}",
+ "srf-printername-filtered": "{{doc-smwformat|filtered}}",
+ "srf-paramdesc-filtered-views": "{{doc-paramdesc|views}}\n\nA view is how the queried information is shown to the user, e.g. as a table or a calendar, etc.",
+ "srf-paramdesc-filtered-filter-position": "{{doc-paramdesc|filter position}}\n{{doc-important|Do not translate the parameter values \"top\" and \"bottom\".}}",
+ "srf-paramdesc-filtered-list-type": "{{doc-paramdesc|list view type}}\n{{doc-important|Do not translate the parameter values \"list\", \"ul\" and \"ol\"}}",
+ "srf-paramdesc-filtered-list-template": "{{doc-paramdesc|list view template}}",
+ "srf-paramdesc-filtered-list-named-args": "{{doc-paramdesc|list view named args}}\n\nSee this page for [https://www.semantic-mediawiki.org/wiki/Help:Template_format#Usage_for_named_args detailed information on named argruments].",
+ "srf-paramdesc-filtered-list-introtemplate": "{{doc-paramdesc|list view introtemplate}}\n\nSimilar to {{msg-mw|srf-paramdesc-filtered-list-outrotemplate}}.",
+ "srf-paramdesc-filtered-list-outrotemplate": "{{doc-paramdesc|list view outrotemplate}}\n\nSimilar to {{msg-mw|srf-paramdesc-filtered-list-introtemplate}}.",
+ "srf-paramdesc-filtered-calendar-start": "{{doc-paramdesc|calendar view start}}",
+ "srf-paramdesc-filtered-calendar-end": "{{doc-paramdesc|calendar view end}}",
+ "srf-paramdesc-filtered-calendar-title": "{{doc-paramdesc|calendar view title}}",
+ "srf-paramdesc-filtered-calendar-title-template": "{{doc-paramdesc|calendar view title template}}",
+ "srf-paramdesc-filtered-map-position": "{{doc-paramdesc|map view position}}",
+ "srf-paramdesc-filtered-map-icon": "{{doc-paramdesc|map view marker icon property}}",
+ "srf-paramdesc-filtered-map-icons": "{{doc-paramdesc|map view marker icons}}\n\n{{doc-important|The first occurrence of the word \"map\" refers to a datavalue symbol mapping while the second occurance of the word \"map\" refers to an actual geographic map.}}",
+ "srf-paramdesc-filtered-map-height": "{{doc-paramdesc|map view height}}",
+ "srf-paramdesc-filtered-map-zoom": "{{doc-paramdesc|map view zoom}}",
+ "srf-paramdesc-filtered-map-min-zoom": "{{doc-paramdesc|map view min zoom}}",
+ "srf-paramdesc-filtered-map-max-zoom": "{{doc-paramdesc|map view max zoom}}",
+ "srf-paramdesc-filtered-map-marker-cluster": "{{doc-paramdesc|map view marker cluster}}",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "{{doc-paramdesc|map view marker cluster max zoom}}",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "{{doc-paramdesc|map view marker cluster radius}}",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "{{doc-paramdesc|map view marker cluster zoom on click}}",
+ "srf-filtered-selectorlabel-list": "The label for the tab that selects the \"list\" view\n{{Identical|List}}",
+ "srf-filtered-selectorlabel-table": "{{Identical|Table}}",
+ "srf-filtered-selectorlabel-calendar": "The label for the tab that selects the \"calendar\" view\n{{Identical|Calendar}}",
+ "srf-filtered-selectorlabel-map": "The label for the tab that selects the \"map\" view\n{{Identical|Map}}",
+ "srf-filtered-firstdayofweek": "{{optional}}\n0 - sunday, 1 - monday...",
+ "srf-filtered-noscript-error": "This is an informatory message.\n\nParameter:\n* $1 - holds the name of a page",
+ "srf-filtered-noscript-link-caption": "This is the caption of a link.",
+ "srf-filtered-map-provider-missing-error": "This is an error message for a missing setting.",
+ "srf-filtered-value-filter-and": "Label of the radio button selecting AND behavior of the value filter.",
+ "srf-filtered-value-filter-or": "Label of the radio button selecting OR behavior of the value filter.",
+ "srf-filtered-value-filter-placeholder": "Placeholder text for the value filter input",
+ "srf-printername-d3chart": "{{doc-smwformat|d3chart}}\nD3 is the name of the library used to generate the charts.",
+ "srf-printername-timeseries": "{{doc-smwformat|timeseries}}",
+ "srf-paramdesc-group": "{{doc-paramdesc|group}}",
+ "srf-paramdesc-zoom": "{{doc-paramdesc|zoom}}",
+ "srf-paramdesc-datatable": "{{doc-paramdesc|datatable}}",
+ "srf-timeseries-zoom-out-of-range": "This is an informatory and/or error message.",
+ "srf-printername-sparkline": "{{doc-smwformat|sparkline}}",
+ "srf-printername-listwidget": "{{doc-smwformat|listwidget}}",
+ "srf-paramdesc-listtype": "{{doc-paramdesc|listtype}}",
+ "srf-paramdesc-widget": "{{doc-paramdesc|widget}}",
+ "srf-paramdesc-pageitems": "{{doc-paramdesc|pageitems}}",
+ "srf-printername-eventcalendar": "{{doc-smwformat|eventcalendar}}\n\nAlso used in {{msg-mw|Prefs-srf-eventcalendar-options}}.",
+ "srf-paramdesc-calendarfirstday": "{{doc-paramdesc|calendarfirstday}}",
+ "srf-paramdesc-calendardefaultview": "{{doc-paramdesc|calendardefaultview}}",
+ "srf-paramdesc-calendarstart": "{{doc-paramdesc|calendarstart}}",
+ "srf-paramdesc-calendarlegend": "{{doc-paramdesc|calendarlegend}}",
+ "srf-paramdesc-dayview": "{{doc-paramdesc|dayview}}",
+ "srf-ui-eventcalendar-label-today": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]\n{{Identical|Today}}",
+ "srf-ui-eventcalendar-label-month": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-week": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-day": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-listmonth": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-listweek": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-listday": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-label-allday": "Text that will be displayed on buttons of the calendar header. See [http://www.semantic-mediawiki.org/wiki/Help:Event_calendar_format Event calendar format] and [http://arshaw.com/fullcalendar/docs/text/buttonText/ buttonText]",
+ "srf-ui-eventcalendar-format-time": "Determines the time-text that will be displayed on each event and is language dependent. For more see [http://arshaw.com/fullcalendar/docs/text/timeFormat/ here]",
+ "srf-ui-eventcalendar-format-time-agenda": "Determines the time-text that will be displayed on each event and is language dependent. For more see [http://arshaw.com/fullcalendar/docs/text/timeFormat/ here]",
+ "srf-ui-eventcalendar-format-axis": "Determines the time-text that will be displayed on the vertical axis of the agenda. See [http://arshaw.com/fullcalendar/docs/agenda/axisFormat/ axisFormat]",
+ "srf-ui-eventcalendar-format-title-month": "Determines the text that will be displayed in the header's title. See [http://arshaw.com/fullcalendar/docs/text/titleFormat/ titleFormat]\n{{DataFormatSpecifiers/en}}\n{{Related|Srf-ui-eventcalendar-format-title}}",
+ "srf-ui-eventcalendar-format-title-week": "Determines the text that will be displayed in the header's title. See [http://arshaw.com/fullcalendar/docs/text/titleFormat/ titleFormat]\n{{DataFormatSpecifiers/en}}\n{{Related|Srf-ui-eventcalendar-format-title}}",
+ "srf-ui-eventcalendar-format-title-day": "Determines the text that will be displayed in the header's title. See [http://arshaw.com/fullcalendar/docs/text/titleFormat/ titleFormat]\n{{DataFormatSpecifiers/en}}\n{{Related|Srf-ui-eventcalendar-format-title}}",
+ "srf-ui-eventcalendar-format-column-month": "Determines the text that will be displayed on the calendar's column headings. See [http://arshaw.com/fullcalendar/docs/text/columnFormat/ columnFormat]\n{{DataFormatSpecifiers/en}}",
+ "srf-ui-eventcalendar-format-column-week": "Determines the text that will be displayed on the calendar's column headings. See [http://arshaw.com/fullcalendar/docs/text/columnFormat/ columnFormat]\n{{DataFormatSpecifiers/en}}",
+ "srf-ui-eventcalendar-format-column-day": "Determines the text that will be displayed on the calendar's column headings. See [http://arshaw.com/fullcalendar/docs/text/columnFormat/ columnFormat]\n{{DataFormatSpecifiers/en}}",
+ "srf-ui-eventcalendar-label-update-success": "{{doc-smw-ui-feedback|update-success}}",
+ "srf-ui-eventcalendar-label-update-error": "{{doc-smw-ui-feedback|update-error}}",
+ "srf-ui-eventcalendar-click-popup": "This is a question served via a popup.",
+ "srf-printername-dygraphs": "{{doc-smwformat|dygraphs}}",
+ "srf-paramdesc-datasource": "{{doc-paramdesc|datasource}}\n{{doc-important|Do not translate the possible parameters \"file\", \"raw\" and \"url\".}}",
+ "srf-paramdesc-errorbar": "{{doc-paramdesc|errorbar}}\n{{doc-important|Do not translate the parametre values \"fraction\", \"sigma\" and \"range\".}}\nInformation on terms used: [[wikipedia:Error bar|error bar]], [[wikipedia:Standard deviation|standard deviation]], [[wikipedia:Confidence interval|confidence interval]].",
+ "srf-paramdesc-movingaverage": "{{doc-paramdesc|movingaverage}}\n{{doc-important|Do not translate <code>zero</code>}}",
+ "srf-paramdesc-yaxislabel": "{{doc-paramdesc|yaxislabel}}",
+ "srf-paramdesc-xaxislabel": "{{doc-paramdesc|xaxislabel}}",
+ "srf-paramdesc-unit": "{{doc-paramdesc|unit}}",
+ "srf-printername-pagewidget": "{{doc-smwformat|pagewidget}}",
+ "srf-printername-incoming": "{{doc-smwformat|incoming}}",
+ "srf-paramdesc-count": "{{doc-paramdesc|count}}",
+ "srf-paramdesc-min": "{{doc-paramdesc|min}}",
+ "srf-paramdesc-excludeproperty": "{{doc-paramdesc|excludeproperty}}",
+ "srf-printername-media": "{{doc-smwformat|media}}",
+ "srf-paramdesc-mediainspector": "An option to display extra media information",
+ "srf-ui-mediaplayer-label-previous": "{{Doc-smw-ui-label-media|previous}}\n{{Identical|Previous}}",
+ "srf-ui-mediaplayer-label-play": "{{Doc-smw-ui-label-media|play}}\n{{Identical|Play}}",
+ "srf-ui-mediaplayer-label-pause": "{{Doc-smw-ui-label-media|pause}}\n{{Identical|Pause}}",
+ "srf-ui-mediaplayer-label-next": "{{Doc-smw-ui-label-media|next}}\n{{Identical|Next}}",
+ "srf-ui-mediaplayer-label-stop": "{{Doc-smw-ui-label-media|stop}}\n{{Identical|Stop}}",
+ "srf-ui-mediaplayer-label-mute": "{{Doc-smw-ui-label-media|mute}}\n{{Identical|Mute}}",
+ "srf-ui-mediaplayer-label-unmute": "{{Doc-smw-ui-label-media|unmute}}",
+ "srf-ui-mediaplayer-label-volume-max": "{{Doc-smw-ui-label-media|volume-max}}",
+ "srf-ui-mediaplayer-label-shuffle": "{{Doc-smw-ui-label-media|shuffle}}\n{{Identical|Shuffle}}",
+ "srf-ui-mediaplayer-label-shuffle-off": "{{Doc-smw-ui-label-media|shuffle-off}}",
+ "srf-ui-mediaplayer-label-repeat": "{{Doc-smw-ui-label-media|repeat}}\n{{Identical|Repeat}}",
+ "srf-ui-mediaplayer-label-repeat-off": "{{Doc-smw-ui-label-media|repeat-off}}",
+ "srf-ui-mediaplayer-label-full-screen": "{{Doc-smw-ui-label-media|full-screen}}\n{{Identical|Full screen}}",
+ "srf-ui-mediaplayer-label-restore-screen": "{{Doc-smw-ui-label-media|restore-screen}}",
+ "srf-spreadsheet-link": "{{doc-smw-link}}",
+ "srf-paramdesc-spreadsheet-filename": "{{doc-paramdesc|filename}}",
+ "srf-paramdesc-spreadsheet-fileformat": "{{doc-paramdesc|fileformat}}",
+ "srf-paramdesc-spreadsheet-templatefile": "{{doc-paramdesc|templatefile}}",
+ "srf-paramdesc-icalendar-timezone": "{{doc-paramdesc|timezone}}",
+ "srf-paramdesc-gantt-diagramtitle": "{{doc-paramdesc|diagram}}",
+ "srf-paramdesc-gantt-diagramtheme": "{{doc-paramdesc|theme}}",
+ "srf-paramdesc-gantt-axisformat": "{{doc-paramdesc|axisformat}}",
+ "srf-paramdesc-gantt-sortkey": "{{doc-paramdesc|sortkey}}",
+ "srf-paramdesc-gantt-titletopmargin": "{{doc-paramdesc|titletopmargin}}",
+ "srf-paramdesc-gantt-barheight": "{{doc-paramdesc|barheight}}",
+ "srf-paramdesc-gantt-leftpadding": "{{doc-paramdesc|leftpadding}}",
+ "srf-paramdesc-gantt-bargap": "{{doc-paramdesc|bargap}}",
+ "srf-error-gantt-mapping-assignment": "This is an error message.",
+ "srf-error-gantt-mapping-keywords": "This is an error message.",
+ "srf-error-gantt-theme": "This is an error message.",
+ "srf-error-gantt-sortkey": "This is an error message.",
+ "srf-error-gantt-mermaid-not-installed": "This is an error message.",
+ "srf-printername-gantt": "{{doc-smwformat|gantt}}",
+ "srf-paramdesc-nodelabel": "{{doc-paramdesc|nodelabel}}\n{{doc-important|Do not translate the possible parameters: \"displaytitle\".}}"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/qu.json b/www/wiki/extensions/SemanticResultFormats/i18n/qu.json
new file mode 100644
index 00000000..53cbdcff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/qu.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlimanRuna"
+ ]
+ },
+ "srf-ui-common-label-help-section": "yanapa raki",
+ "srf-ui-eventcalendar-format-title-month": "MMMM killapi yyyy watapi"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/rmf.json b/www/wiki/extensions/SemanticResultFormats/i18n/rmf.json
new file mode 100644
index 00000000..45422f67
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/rmf.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Szonja"
+ ]
+ },
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Naaluno"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ro.json b/www/wiki/extensions/SemanticResultFormats/i18n/ro.json
new file mode 100644
index 00000000..b32ff3af
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ro.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "KlaudiuMihaila",
+ "Minisarm",
+ "Stelistcristi"
+ ]
+ },
+ "srf-paramdesc-height": "Înălțime",
+ "srf-paramdesc-width": "Lățime",
+ "srf-ui-common-label-source": "Sursă",
+ "srf-ui-tooltip-title-options": "Opțiuni",
+ "srfc_previousmonth": "Luna anterioară",
+ "srfc_nextmonth": "Luna următoare",
+ "srfc_today": "Astăzi",
+ "srf_printername_calendar": "Calendar lunar",
+ "srf_printername_bibtex": "Export BibTeX",
+ "srf_outline_novalue": "Nici o valoare",
+ "srf_printername_sum": "Suma numerelor",
+ "srf_printername_average": "Media numerelor",
+ "srf_printername_max": "Numărul maxim",
+ "srf_printername_min": "Numărul minim",
+ "srf-ui-gridview-label-chart-tab": "Diagramă",
+ "srf-ui-gridview-label-info-tab": "Informații",
+ "srf_printername_gallery": "Galerie",
+ "srf_paramdesc_graphname": "Titlu",
+ "srf-printername-filtered": "Filtrat",
+ "srf-filtered-selectorlabel-list": "Listă",
+ "srf-filtered-selectorlabel-calendar": "Calendar",
+ "srf-paramdesc-yaxislabel": "Descriere care apare pe axa y",
+ "srf-paramdesc-unit": "Unitate",
+ "srf-ui-mediaplayer-label-play": "Redare",
+ "srf-ui-mediaplayer-label-pause": "Pauză",
+ "srf-ui-mediaplayer-label-stop": "Stop",
+ "srf-ui-mediaplayer-label-mute": "Fără sunet",
+ "srf-ui-mediaplayer-label-volume-max": "Volum maxim",
+ "srf-ui-mediaplayer-label-shuffle": "Amestecare",
+ "srf-ui-mediaplayer-label-repeat": "Repetare",
+ "srf-ui-mediaplayer-label-full-screen": "Pe tot ecranul",
+ "srf-ui-mediaplayer-label-restore-screen": "Restabilește ecranul"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/roa-tara.json b/www/wiki/extensions/SemanticResultFormats/i18n/roa-tara.json
new file mode 100644
index 00000000..439327dc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/roa-tara.json
@@ -0,0 +1,97 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "prefs-srf": "Formate d'u resultate semandeche",
+ "srf-module-loading": "Stoche a scareche…",
+ "srf-paramdesc-height": "Altezze",
+ "srf-paramdesc-width": "Larghezze",
+ "srf-navigation-previous": "Precedende",
+ "srf-ui-navigation-prev": "Prec",
+ "srf-ui-navigation-next": "Successive",
+ "srf-ui-common-label-source": "Sorgende",
+ "srf-ui-tooltip-title-options": "Opziune",
+ "srf-ui-tooltip-title-scope": "Obbiettive",
+ "srf-ui-tooltip-title-legend": "Leggende",
+ "srf-ui-tooltip-title-filter": "Filtre",
+ "srf-ui-common-label-refresh": "Aggiorne",
+ "srf-ui-common-label-parameters": "Parametre",
+ "srf-ui-common-label-query": "'Nderrogazione",
+ "srfc_previousmonth": "Mese precedende",
+ "srfc_nextmonth": "Mese successive",
+ "srfc_today": "Osce",
+ "srfc_gotomonth": "Va a 'u mese",
+ "srf_printername_vcard": "Esporte vCard",
+ "srf_printername_icalendar": "Esporte iCalendar",
+ "srf_printername_bibtex": "Esporte BibTeX",
+ "srf_outline_novalue": "Nisciune valore",
+ "srf_printername_sum": "Somme de le numere",
+ "srf_printername_average": "Medie de le numere",
+ "srf_printername_max": "Numere massime",
+ "srf_printername_min": "Numere minime",
+ "srf_printername_googlebar": "Grafiche a barre de Google",
+ "srf_printername_googlepie": "Grafiche a torte de Google",
+ "srf-printername-jqplotchart": "Grafiche jqPlot",
+ "srf-printername-jqplotseries": "Serie jqPlot",
+ "srf-paramdesc-theme": "Scacchie 'nu teme d'a grate",
+ "srf-paramdesc-chartcolor": "Da le culure d'u grafeche individuale",
+ "srf-paramdesc-colorscheme": "Scacchie 'u scheme de culore",
+ "srf-ui-gridview-label-chart-tab": "Grafeche",
+ "srf-ui-gridview-label-data-tab": "Date",
+ "srf-ui-gridview-label-info-tab": "'Mbormazione",
+ "srf_printername_gallery": "Gallerie",
+ "srf-gallery-navigation-previous": "Precedende",
+ "srf-gallery-navigation-next": "Prossime",
+ "srf-gallery-overlay-count": "Immaggine $1 de $2",
+ "srf-gallery-image-url-error": "Immaggine none acchiate.",
+ "srf_printername_hash": "Hash",
+ "srf-printername-graph": "Grafeche",
+ "srf-ui-datatables-label-conditions": "Condiziune",
+ "srf-ui-datatables-label-parameters": "Parametre",
+ "srf-ui-datatables-label-information": "'Mbormazione",
+ "srf-ui-datatables-label-placeholder-column-search": "Stoche e cerche...",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLoadingRecords": "Stoche a careche…",
+ "srf-ui-datatables-label-sProcessing": "Stoche a processe...",
+ "srf-ui-datatables-label-sSearch": "Cirche:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Prime",
+ "srf-ui-datatables-label-oPaginate-sLast": "Urteme",
+ "srf-ui-datatables-label-oPaginate-sNext": "Prossime",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Precedende",
+ "srf-printername-tree": "Arvule",
+ "srf-printername-filtered": "Filtrate",
+ "srf-filtered-selectorlabel-list": "Elenghe",
+ "srf-filtered-selectorlabel-table": "Tabbelle",
+ "srf-filtered-selectorlabel-calendar": "Calendarije",
+ "srf-filtered-selectorlabel-map": "Mappe",
+ "srf-printername-d3chart": "grafiche D3",
+ "srf-paramdesc-pageitems": "Vôsce pe pàgene",
+ "srf-ui-eventcalendar-label-today": "Osce",
+ "srf-ui-eventcalendar-label-month": "Mese",
+ "srf-ui-eventcalendar-label-week": "Sumáne",
+ "srf-ui-eventcalendar-label-day": "Sciúrne",
+ "srf-ui-eventcalendar-label-allday": "Tutte le sciurne",
+ "srf-paramdesc-unit": "Aunità",
+ "srf-ui-mediaplayer-label-previous": "Precedende",
+ "srf-ui-mediaplayer-label-play": "Reproduce",
+ "srf-ui-mediaplayer-label-pause": "Pause",
+ "srf-ui-mediaplayer-label-next": "Prossime",
+ "srf-ui-mediaplayer-label-stop": "Stuèppe",
+ "srf-ui-mediaplayer-label-mute": "Citte",
+ "srf-ui-mediaplayer-label-unmute": "Cu 'a vôsce",
+ "srf-ui-mediaplayer-label-volume-max": "Volume massime",
+ "srf-ui-mediaplayer-label-shuffle": "Miscke",
+ "srf-spreadsheet-link": "Fogghie de calcole",
+ "srf-paramdesc-gantt-diagramtitle": "Nome d'u diagramme",
+ "srf-paramdesc-gantt-diagramtheme": "Teme d'u diagramme",
+ "srf-paramdesc-gantt-axisformat": "Asse de le X: Formate de le date",
+ "srf-paramdesc-gantt-sortkey": "Chiave pe ordenà le seziune e le attività",
+ "srf-paramdesc-gantt-titletopmargin": "Margine de sus d'u titole d'u diagramme",
+ "srf-paramdesc-gantt-barheight": "Iertezze de le barre de le attività",
+ "srf-paramdesc-gantt-bargap": "Distanze verticale de le barre de le attività da 'u margine",
+ "srf-error-gantt-mapping-keywords": "'A chiave ausate jndr'à 'u parametre de mappature non g'è supportate",
+ "srf-error-gantt-sortkey": "'A '''chiave de ordinamende''' ca è scacchiate non g'è supportate",
+ "srf-printername-gantt": "Gantt"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ru.json b/www/wiki/extensions/SemanticResultFormats/i18n/ru.json
new file mode 100644
index 00000000..81be5238
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ru.json
@@ -0,0 +1,329 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ferrer",
+ "Haffman",
+ "Innv",
+ "Kaganer",
+ "Pastakhov",
+ "ÐлекÑандр Сигачёв",
+ "Okras",
+ "Meshkov.a",
+ "Alexandr Efremov",
+ "Facenapalm",
+ "Redredsonia",
+ "Nemo bis",
+ "Putnik",
+ "Vlad5250",
+ "Nk88",
+ "Romanko Mikhail",
+ "Diralik",
+ "Movses"
+ ]
+ },
+ "srf-desc": "Дополнительные форматы вывода Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов Semantic MediaWiki",
+ "prefs-srf": "Форматы ÑемантичеÑкого вывода",
+ "srf-prefs-intro-text": "РаÑширение «Форматы ÑемантичеÑкого вывода» уÑтановлено. Ð”Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации вы можете ознакомитьÑÑ Ñо Ñтраницей [https://www.semantic-mediawiki.org/wiki/Help:Result_formats «Форматы вывода»].",
+ "prefs-srf-eventcalendar-options": "Календарь Ñобытий параметры",
+ "srf-prefs-eventcalendar-options-update-default": "Включить [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматичеÑкое обновление] Ñобытий ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ñ€Ð¸ обновлении Ñтраницы",
+ "srf-prefs-eventcalendar-options-paneview-default": "Включить по умолчанию вид клеточками",
+ "prefs-srf-datatables-options": "ÐаÑтройки DataTables",
+ "srf-prefs-datatables-options-update-default": "Включить [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматичеÑкое обновление] ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸ обновлении Ñтраницы",
+ "srf-prefs-datatables-options-cache-default": "Включить [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage локальный том хранениÑ], чтобы улучшить Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ÐºÐ»Ð¸ÐºÐ°",
+ "srf-module-loading": "Загрузка...",
+ "srf-paramdesc-layout": "ДоÑтупен макет",
+ "srf-paramdesc-height": "Ð’Ñ‹Ñота",
+ "srf-paramdesc-width": "Ширина",
+ "srf-paramdesc-class": "Указать дополнительный клаÑÑ CSS",
+ "srf-module-nomatch": "Совпадений не найдено",
+ "srf-paramdesc-charttype": "ДоÑтупные типы диаграмм",
+ "srf-navigation-previous": "Предыдущий",
+ "srf-ui-navigation-prev": "Пред.",
+ "srf-ui-navigation-next": "След.",
+ "srf-ui-common-label-source": "ИÑточник",
+ "srf-ui-common-label-datasource": "ИÑточник данных",
+ "srf-ui-common-label-ajax-error": "Сервер Ñообщил о неудачной ÑвÑзи Ñ $1. ПожалуйÑта, попробуйте обновить Ñтраницу или обратитеÑÑŒ Ñ Ñтим в $2.",
+ "srf-ui-common-label-request-object": "объект запроÑа",
+ "srf-ui-common-label-help-section": "раздел Ñправки",
+ "srf-ui-tooltip-title-options": "Параметры",
+ "srf-ui-tooltip-title-scope": "Сфера",
+ "srf-ui-tooltip-title-legend": "Легенда",
+ "srf-ui-tooltip-title-filter": "Фильтр",
+ "srf-ui-common-label-refresh": "Обновить",
+ "srf-ui-common-label-parameters": "Параметры",
+ "srf-ui-common-label-query": "ЗапроÑ",
+ "srf-ui-common-label-paneview": "Вид панели",
+ "srf-ui-common-label-daterange": "Диапазон дат",
+ "srf-ui-widgets-label-parameter-limit": "Параметр лимита",
+ "srf-error-option-mix": "Параметр ( $1 ) не доÑтупен",
+ "srf-error-option-link-all": "ÐžÐ¿Ñ†Ð¸Ñ ($1) требует, чтобы параметр «link» был задан как «all»",
+ "srf-error-missing-layout": "Диаграмма или график не могут быть показаны, поÑкольку макет отÑутÑтвует.",
+ "srf-error-jqplot-bubble-data-length": "Таблица или график не могут быть показаны, поÑкольку данные отÑутÑтвуют.",
+ "srf-error-jqplot-stackseries-data-length": "Диаграмма или график не могут быть показаны, поÑкольку не каждый Ñтолбик или Ð»Ð¸Ð½Ð¸Ñ Ð¸Ð¼ÐµÐµÑ‚ одинаковое количеÑтво Ñлементов.",
+ "srf-warn-empy-chart": "Диаграммы или графика пуÑÑ‚ из-за недоÑтающих данных",
+ "srf-paramdesc-color": "Цвет Ð´Ð»Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ð½Ñ‹Ñ… Ñобытий",
+ "srfc_previousmonth": "Предыдущий меÑÑц",
+ "srfc_nextmonth": "Следующий меÑÑц",
+ "srfc_today": "СегоднÑ",
+ "srfc_gotomonth": "Перейти к меÑÑцу",
+ "srf_printername_calendar": "ЕжемеÑÑчный календарь",
+ "srf_paramdesc_calendarlang": "Код Ñзыка, на котором отображать календарь",
+ "srf_paramdesc_calendarcolors": "Цвет, которым показывать каждое ÑвойÑтво даты (например: \"Start date =>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "МеÑÑц, которым календарь начинает отображатьÑÑ (по умолчанию текущий меÑÑц)",
+ "srf-paramdesc-calendar-startyear": "Год, которым календарь начинает отображатьÑÑ (по умолчанию текущий год)",
+ "srf_printername_vcard": "ЭкÑпорт vCard",
+ "srf_icalendar_link": "iКалендарь",
+ "srf_printername_icalendar": "ЭкÑпорт iCalendar",
+ "srf_paramdesc_icalendartitle": "Ðазвание файла календарÑ",
+ "srf_paramdesc_icalendardescription": "ОпиÑание файла календарÑ",
+ "srf_printername_bibtex": "ЭкÑпорт BibTeX",
+ "srf_outline_novalue": "Ðет значений",
+ "srf_printername_outline": "ÐаброÑки",
+ "srf_paramdesc_outlineproperties": "СпиÑок ÑвойÑтв, отображающихÑÑ Ð² виде заголовков, разделÑетÑÑ Ð·Ð°Ð¿Ñтыми",
+ "srf_printername_sum": "Сумма чиÑел",
+ "srf_printername_average": "Среднее чиÑло",
+ "srf_printername_max": "МакÑимальное чиÑло",
+ "srf_printername_min": "Минимальное чиÑло",
+ "srf_paramdesc_limit": "МакÑимальное количеÑтво Ñтраниц Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€ÐºÐ¸",
+ "srf_printername_product": "Произведение цифр",
+ "srf_printername_median": "Медиана чиÑел",
+ "srf-paramdesc-default": "Значение по умолчанию, которое будет отображатьÑÑ ÐºÐ¾Ð³Ð´Ð° нет чиÑленных результатов",
+ "srf_printername_earliest": "Раннее времÑ",
+ "srf_printername_latest": "Позднее времÑ",
+ "srf_printername_timeline": "ХронологиÑ",
+ "srf_printername_eventline": "СпиÑок Ñобытий",
+ "srf_paramdesc_timelinebands": "ОпределÑет, какие полоÑÑ‹ будут отображены.",
+ "srf_paramdesc_timelineposition": "ОпределÑет какое меÑто временной шкалы будет отображатьÑÑ Ð¿ÐµÑ€Ð²Ð¾Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð¾",
+ "srf_paramdesc_timelinestart": "Ð˜Ð¼Ñ ÑвойÑтва, иÑпользуемое Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð¹ временной точки",
+ "srf_paramdesc_timelineend": "Ð˜Ð¼Ñ ÑвойÑтва, иÑпользуемое Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²Ñ‚Ð¾Ñ€Ð¾Ð¹ временной точки",
+ "srf_paramdesc_timelinesize": "Ð’Ñ‹Ñота временной шкалы",
+ "srf-timeline-allresults": "Дальнейшие результаты Ð´Ð»Ñ Ñтого запроÑа.",
+ "srf-timeline-nojs": "Вам необходимо включить JavaScript Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра интерактивной временной шкалы.",
+ "srf_paramdesc_views": "Виды Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ",
+ "srf_paramdesc_facets": "Ðабор ÑвойÑтв, отображаемых на каждой Ñтранице",
+ "srf_paramdesc_lens": "Ðазвание шаблона Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑвойÑтв Ñтраницы",
+ "srf_printername_googlebar": "Ð¡Ñ‚Ð¾Ð»Ð±Ñ‡Ð°Ñ‚Ð°Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ð° Google",
+ "srf_printername_googlepie": "ÐšÑ€ÑƒÐ³Ð¾Ð²Ð°Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ð° Google",
+ "srf-printername-jqplotchart": "диаграмма jqPlot",
+ "srf-printername-jqplotseries": "ÑÐµÑ€Ð¸Ñ jqPlot",
+ "srf_paramdesc_chartheight": "Укажите выÑоту (в пикÑелÑÑ…) диаграммы или графика",
+ "srf_paramdesc_chartwidth": "Указать ширину (в пикÑелах или процентах) диаграммы или графика",
+ "srf_paramdesc_charttitle": "Ðазвание диаграммы",
+ "srf_paramdesc_barcolor": "Цвет Ñтолбцов",
+ "srf_paramdesc_bardirection": "Укажите направление диаграммы",
+ "srf-paramdesc-direction": "Укажите направление диаграммы или графика",
+ "srf_paramdesc_barnumbersaxislabel": "ÐадпиÑÑŒ Ð´Ð»Ñ Ñ‡Ð¸Ñловых оÑей",
+ "srf-paramdesc-labelaxislabel": "Метка Ð´Ð»Ñ Ð´ÐµÐ»ÐµÐ½Ð¸Ð¹ оÑи",
+ "srf-paramdesc-ticklabels": "Включить отображение меток делений",
+ "srf-paramdesc-minvalue": "Минимальное значение на оÑи y",
+ "srf-paramdesc-pointlabels": "Отображение точек данных в диаграмме",
+ "srf-paramdesc-chartlegend": "Положение легенды диаграммы",
+ "srf-paramdesc-datalabels": "ПодпиÑи данных диаграммы/графика",
+ "srf-paramdesc-charttext": "ТекÑÑ‚ опиÑÐ°Ð½Ð¸Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ñ‹",
+ "srf-paramdesc-chartclass": "Дополнительный CSS-клаÑÑ",
+ "srf-paramdesc-renderer": "Выберите визуализацию графика/диаграммы",
+ "srf-paramdesc-filling": "Ð˜Ð½Ð´Ð¸Ð²Ð¸Ð´ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ",
+ "srf-paramdesc-theme": "Выберите тему Ñетки",
+ "srf-paramdesc-chartcolor": "Ðазначить отдельные цвета диаграммы",
+ "srf-paramdesc-colorscheme": "Выберите цветовую Ñхему",
+ "srf-paramdesc-valueformat": "Укажите правило Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ð¹",
+ "srf-paramdesc-highlighter": "Отображать маркер точки данных",
+ "srf-paramdesc-smoothlines": "ПрименÑÑ‚ÑŒ алгоритм ÑÐ³Ð»Ð°Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð½Ð° графиках",
+ "srf-paramdesc-stackseries": "Отобразить диаграммы в виде ÑоÑтавленной Ñерии",
+ "srf-paramdesc-seriesgroup": "Выберите группировки Ñерии",
+ "srf-paramdesc-serieslabel": "Определите Ñрлык Ñерии",
+ "srf-paramdesc-grouplabel": "Определите Ñрлык группы",
+ "srf-paramdesc-chartcursor": "Параметры Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ñ‹",
+ "srf-paramdesc-trendline": "Включить одновременное отображение диаграммы и её линии тренда",
+ "srf-paramdesc-gridview": "Отобразить диаграмму и наборы данных одновременно. ДопуÑтимые значениÑ: «none» и «tabs». По умолчанию: «none»",
+ "srf-paramdesc-paneview": "Указать положение панели Ñ Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ¸Ð¼ линейным графиком. ДопуÑтимые значениÑ: \"bottom\", \"top\" и \"none\". По умолчанию: \"bottom\"",
+ "srf-paramdesc-infotext": "Отображать дополнительную информацию на ÑоответÑтвующей вкладке",
+ "srf-ui-gridview-label-item": "Элемент данных",
+ "srf-ui-gridview-label-value": "Значение данных",
+ "srf-ui-gridview-label-series": "РÑд данных",
+ "srf-ui-gridview-label-chart-tab": "Диаграмма",
+ "srf-ui-gridview-label-data-tab": "Данные",
+ "srf-ui-gridview-label-info-tab": "ИнформациÑ",
+ "srf_printername_gallery": "ГалереÑ",
+ "srf_paramdesc_perrow": "КоличеÑтво изображений в Ñтроке",
+ "srf_paramdesc_widths": "Ширина изображений",
+ "srf_paramdesc_heights": "Ð’Ñ‹Ñота изображений",
+ "srf_paramdesc_autocaptions": "ИÑпользовать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° в качеÑтве заголовка, когда другое не предоÑтавлено",
+ "srf_paramdesc_fileextensions": "При иÑпользовании Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° в качеÑтве заголовка, отображать также раÑширение файла",
+ "srf_paramdesc_captionproperty": "Ðазвание ÑемантичеÑкого ÑвойÑтва, приÑутÑтвующих на запрашиваемых Ñтраницах, которые будут иÑпользованы в качеÑтве заголовка",
+ "srf_paramdesc_imageproperty": "Ðазвание ÑемантичеÑкого ÑвойÑтва приÑутÑтвующих на запрашиваемых Ñтраницах, которые нужно иÑпользовать. ЕÑли указана, запрошенные Ñтраницы не отображаютÑÑ ÐºÐ°Ðº изображение",
+ "srf-paramdesc-redirects": "Ðазвание ÑемантичеÑкого ÑвойÑтва, приÑутÑтвующие на запрошенных Ñтраницах, Ñодержащие перенаправлениÑ",
+ "srf-paramdesc-navigation": "Управление навигацией макета",
+ "srf-paramdesc-overlay": "Разрешить наложение изображениÑ",
+ "srf-gallery-navigation-previous": "ПредыдущаÑ",
+ "srf-gallery-navigation-next": "СледующаÑ",
+ "srf-gallery-overlay-count": "Изображение $1 из $2",
+ "srf-gallery-image-url-error": "Изображение не найдено.",
+ "srf_printername_tagcloud": "Облако меток",
+ "srf_paramdesc_includesubject": "Должны быть включены Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñубъектов",
+ "srf_paramdesc_increase": "Как увеличить размер тегов",
+ "srf_paramdesc_tagorder": "ПорÑдок тегов",
+ "srf_paramdesc_mincount": "Минимальное количеÑтво раз поÑвление значениÑ, поÑле которых оно попадает в ÑпиÑок",
+ "srf_paramdesc_minsize": "Размер наименьших тегов в процентах",
+ "srf_paramdesc_maxsize": "Размер наибольших тегов в процентах",
+ "srf_paramdesc_maxtags": "МакÑимальное количеÑтво тегов в облаке",
+ "srf-paramdesc-excludetags": "ИÑключить теги (разделитель: \";\")",
+ "srf_printername_valuerank": "Ранг значениÑ",
+ "srf_printername_array": "МаÑÑив",
+ "srf_paramdesc_pagetitle": "Следует ли отражать заголовки Ñтраниц как результирующие запиÑи или пропуÑкать их",
+ "srf_paramdesc_hidegaps": "Печатать запрошенную, Ñледующие ÑвойÑтва и Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñей, разделенных разделителÑми, или пропуÑкать их",
+ "srf_paramdesc_arrayname": "ЕÑли подано и ArrayExtension доÑтупно, то будет Ñоздавать маÑÑив Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ названием (ни видимого на выходе)",
+ "srf_paramdesc_propsep": "Разделитель между воÑтребованными ÑвойÑтвами",
+ "srf_paramdesc_manysep": "Разделитель между многими оцененными значениÑми ÑвойÑтв",
+ "srf_paramdesc_recordsep": "Разделитель между значениÑми ÑвойÑтв запиÑей",
+ "srf_paramdesc_headersep": "Разделитель между названием ÑвойÑтва и значением, еÑли \"headers\" уÑтановлен в \"show\" или \"plain\"",
+ "srf_printername_hash": "Ð¥Ñш",
+ "srf_paramdesc_hashname": "ЕÑли указано, и доÑтупно раÑширение Hash Tables, Ñто ÑоздаÑÑ‚ Ñ…Ñш поданному названием (ни видимого выхода)",
+ "srf-printername-graph": "График",
+ "srf-paramdesc-graph-relation": "ОпределÑет, ÑвлÑÑŽÑ‚ÑÑ Ð»Ð¸ предметы или ÑвойÑтва названий родительÑкими или дочерними",
+ "srf-paramdesc-graph-nameprop": "ПозволÑет уÑтановить ÑвойÑтво, которое будет иÑпользовано как предмет вмеÑто нынешнего предмета, то еÑÑ‚ÑŒ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñтраницы",
+ "srf-paramdesc-graph-nodeshape": "УÑтанавливает форму каждого узла графа",
+ "srf-paramdesc-graphname": "УÑтанавливает заголовок графа",
+ "srf-paramdesc-graphsize": "УÑтанавливает размер графа (в пикÑелÑÑ…)",
+ "srf-paramdesc-graphlegend": "ОпределÑет, Ñледует ли показывать легенду",
+ "srf-paramdesc-graphlabel": "УÑтанавливает подпиÑÑŒ графа",
+ "srf-paramdesc-rankdir": "УÑтанавливает направление Ñтрелок",
+ "srf-paramdesc-graphlink": "ОпределÑет, должны ли узлы ÑÑылатьÑÑ Ð½Ð° их вики-Ñтраницы",
+ "srf-paramdesc-graphcolor": "УÑтанавливает цвет графа",
+ "srf-paramdesc-graph-wwl": "ОпределÑет предел переноÑа Ñлов (в Ñимволах)",
+ "srf-paramdesc-clustercolor": "УÑтанавливает цвета блоков клаÑтера",
+ "srf-paramdesc-highlightcolor": "УÑтанавливает цвет шрифта Ð´Ð»Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð½Ð¾Ð³Ð¾ узла",
+ "srf-paramdesc-redlinkcolor": "Задать цвет шрифта Ð´Ð»Ñ ÐºÑ€Ð°Ñных ÑÑылок",
+ "srf-printername-datatables": "Таблицы данных",
+ "srf-ui-datatables-label-conditions": "УÑловиÑ",
+ "srf-ui-datatables-label-parameters": "Параметры",
+ "srf-ui-datatables-label-filters": "Фильтры Ñтолбцов и поиÑк",
+ "srf-ui-datatables-label-information": "ИнформациÑ",
+ "srf-ui-datatables-panel-disclaimer": "Параметры и уÑÐ»Ð¾Ð²Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть изменены, но любое изменение временное и ÑбраÑываетÑÑ Ð¿Ð¾Ñле Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñтраницы.",
+ "srf-ui-datatables-label-update-success": "Обновление таблицы прошло уÑпешно",
+ "srf-ui-datatables-label-update-error": "Обновление таблицы не удалоÑÑŒ.",
+ "srf-ui-datatables-label-placeholder-column-search": "ПоиÑк…",
+ "srf-ui-datatables-label-content-cache": "Контент получен из локального кÑша.",
+ "srf-ui-datatables-label-content-server": "Контент был получен Ñ Ñервера.",
+ "srf-ui-datatables-label-multiselect-column-header": "ДоÑтупные Ñтолбцы",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "ÐаÑтройки фильтра",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Отображаемые Ñтолбцы",
+ "srf-ui-datatables-label-sEmptyTable": "Данные отÑутÑтвуют в таблице",
+ "srf-ui-datatables-label-sInfo": "Отображение запиÑей от _START_ до _END_ Ñ _TOTAL_",
+ "srf-ui-datatables-label-sInfoEmpty": "Показаны от 0 до 0 из 0 запиÑей",
+ "srf-ui-datatables-label-sInfoFiltered": "(отфильтровано по _MAX_ вÑего запиÑей)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Показать _MENU_ запиÑей",
+ "srf-ui-datatables-label-sLoadingRecords": "Загрузка…",
+ "srf-ui-datatables-label-sProcessing": "Обработка…",
+ "srf-ui-datatables-label-sSearch": "ПоиÑк:",
+ "srf-ui-datatables-label-sZeroRecords": "СоответÑтвующие запиÑи не найдены",
+ "srf-ui-datatables-label-oPaginate-sFirst": "ПерваÑ",
+ "srf-ui-datatables-label-oPaginate-sLast": "ПоÑледнÑÑ",
+ "srf-ui-datatables-label-oPaginate-sNext": "СледующаÑ",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "ПредыдущаÑ",
+ "srf-ui-datatables-label-oAria-sSortAscending": ":активировать Ð´Ð»Ñ Ñортировки Ñтолбца по возраÑтанию",
+ "srf-ui-datatables-label-oAria-sSortDescending": ":активировать Ð´Ð»Ñ Ñортировки Ñтолбца по убыванию",
+ "srf-printername-tree": "Дерево",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "Ðе указано родительÑкого ÑвойÑтва. Дерево не может быть поÑтроено без ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÑкого ÑвойÑтва.",
+ "srf-tree-rootinvalid": "«$1» — некорректный заголовок Ñтраницы.",
+ "srf-paramdesc-tree-parent": "СвойÑтво, Ñодержащее родительÑкую Ñтраницу",
+ "srf-paramdesc-tree-root": "ÐšÐ¾Ñ€Ð½ÐµÐ²Ð°Ñ Ñтраниа дерева",
+ "srf-paramdesc-tree-startlevel": "Ðачальный уровень дерева, напр. Ð”Ð»Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÐµÐ³Ð¾ в другое дерево",
+ "srf-printername-slideshow": "Слайд-шоу",
+ "srf-paramdesc-delay": "Задержка между Ñлайдами (в Ñекундах)",
+ "srf-paramdesc-navigation-controls": "Показать ли Ñлементы управлениÑ",
+ "srf-paramdesc-effect": "Эффект, иÑпользуемый при переходе между Ñлайдами",
+ "srf-printername-filtered": "Отфильтровано",
+ "srf-paramdesc-filtered-views": "Вид, который будет доÑтупен в результатах.",
+ "srf-paramdesc-filtered-filter-position": "ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð¾Ð² отноÑительно проÑмотров. ДопуÑтимые значениÑ: «вверху», «внизу». По умолчанию: «вверху».",
+ "srf-paramdesc-filtered-list-type": "Тип ÑпиÑка. ДопуÑтимые значениÑ: «list», «ul», «ol». По умолчанию: «list».",
+ "srf-paramdesc-filtered-list-template": "Шаблон Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ которого будет формироватьÑÑ ÑпиÑок Ñлементов.",
+ "srf-paramdesc-filtered-list-named-args": "ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð¾Ð², передаваемых шаблоном.",
+ "srf-paramdesc-filtered-list-introtemplate": "Ðазвание шаблона, который будет показан перед результатами запроÑа, еÑли они еÑÑ‚ÑŒ.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Ðазвание шаблона, который будет показан поÑле результатов запроÑа, еÑли они еÑÑ‚ÑŒ.",
+ "srf-paramdesc-filtered-calendar-start": "РаÑпечатка Ñодержит дату начала ÑобытиÑ",
+ "srf-paramdesc-filtered-calendar-end": "РаÑпечатка Ñодержит дату Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ ÑобытиÑ",
+ "srf-paramdesc-filtered-calendar-title": "РаÑпечатка Ñодержит название ÑобытиÑ. Ðе может быть иÑпользовано вмеÑте Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð¾Ð¼ заголовка.",
+ "srf-paramdesc-filtered-calendar-title-template": "Шаблон, иÑпользуемый Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð² календаре",
+ "srf-paramdesc-filtered-map-position": "\nРаÑпечатка, ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ñ‰Ð°Ñ Ð³ÐµÐ¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкое положение.",
+ "srf-paramdesc-filtered-map-icon": "РаÑпечатка, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñет значок карты, который будет иÑпользоватьÑÑ.",
+ "srf-paramdesc-filtered-map-icons": "Карта значений Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐºÐ¾Ð², которые будут иÑпользоватьÑÑ Ð´Ð»Ñ Ñтих значений на карте.",
+ "srf-paramdesc-filtered-map-height": "Ð’Ñ‹Ñота карты.",
+ "srf-paramdesc-filtered-map-min-zoom": "Минимальный выбираемый уровень маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
+ "srf-paramdesc-filtered-map-max-zoom": "МакÑимальный выбираемый уровень маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
+ "srf-paramdesc-filtered-map-marker-cluster": "\nВключить или отключить клаÑтеризацию маркеров.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "\nМакÑимальный уровень маÑштабированиÑ, при котором маркеры карты вÑÑ‘ ещё группируютÑÑ. Выше Ñтого ÑƒÑ€Ð¾Ð²Ð½Ñ Ð¼Ð°Ñ€ÐºÐµÑ€Ñ‹ вÑегда будут клаÑтеризованы.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "\nМакÑимальный радиуÑ, который клаÑтер будет охватывать от центрального маркера (в пикÑелÑÑ…). По умолчанию 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "ЕÑли включено, при нажатии клаÑтер приблизитÑÑ Ðº Ñвоим границам.",
+ "srf-filtered-selectorlabel-list": "СпиÑок",
+ "srf-filtered-selectorlabel-table": "Таблица",
+ "srf-filtered-selectorlabel-calendar": "Календарь",
+ "srf-filtered-selectorlabel-map": "Карта",
+ "srf-filtered-noscript-error": "Результаты не могут быть отображены, потому что Javascript отключён. Перейти к $1",
+ "srf-filtered-noscript-link-caption": "\nрезультаты в табличной форме",
+ "srf-filtered-map-provider-missing-error": "Ð”Ð»Ñ Ð¿Ñ€ÐµÐ´ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ \"карта\" не указан поÑтавщик карт.",
+ "srf-filtered-value-filter-and": "И",
+ "srf-filtered-value-filter-or": "ИЛИ",
+ "srf-filtered-value-filter-placeholder": "Выберите значение фильтра",
+ "srf-printername-d3chart": "D3-диаграма",
+ "srf-printername-timeseries": "Диаграмма временных Ñ€Ñдов",
+ "srf-paramdesc-group": "Серии Ñгруппированы по",
+ "srf-paramdesc-zoom": "Включить маÑштабирование",
+ "srf-paramdesc-datatable": "Включить базу данных",
+ "srf-timeseries-zoom-out-of-range": "Диапазон ÑƒÐ²ÐµÐ»Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ðµ предоÑтавил доÑтаточно данных",
+ "srf-printername-sparkline": "Мини-диаграмма",
+ "srf-printername-listwidget": "Виджет ÑпиÑка",
+ "srf-paramdesc-listtype": "Укажите тип ÑпиÑка",
+ "srf-paramdesc-widget": "ДоÑтупные виджеты",
+ "srf-paramdesc-pageitems": "Элементов на Ñтраницу",
+ "srf-printername-eventcalendar": "Календарь Ñобытий",
+ "srf-paramdesc-calendarfirstday": "Первый день недели",
+ "srf-paramdesc-calendardefaultview": "Вид при открытии календарÑ",
+ "srf-paramdesc-calendarstart": "Первоначальное начало ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (значение даты или даты и времени)",
+ "srf-paramdesc-calendarlegend": "Указывает положение легенды и параметры назначенного фильтра",
+ "srf-paramdesc-dayview": "Разрешить проÑмотр Ð´Ð½Ñ Ð¿Ñ€Ð¸ нажатии на его номер",
+ "srf-ui-eventcalendar-label-today": "СегоднÑ",
+ "srf-ui-eventcalendar-label-month": "МеÑÑц",
+ "srf-ui-eventcalendar-label-week": "ÐеделÑ",
+ "srf-ui-eventcalendar-label-day": "День",
+ "srf-ui-eventcalendar-label-listmonth": "МеÑÑц (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listweek": "ÐÐµÐ´ÐµÐ»Ñ (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listday": "День (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-allday": "ВеÑÑŒ день",
+ "srf-ui-eventcalendar-label-update-success": "Обновление Ñобытий ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ ÑƒÑпешно выполнено.",
+ "srf-ui-eventcalendar-label-update-error": "Ðе удалоÑÑŒ обновить календарь Ñобытий.",
+ "srf-ui-eventcalendar-click-popup": "Ð’Ñ‹ хотите Ñоздать Ñобытие?",
+ "srf-printername-dygraphs": "Диграфы",
+ "srf-paramdesc-datasource": "ИÑточник, из которого доÑтупны данные. ДопуÑтимые значениÑ: «file», «raw» и «url». По умолчанию: «file».",
+ "srf-paramdesc-errorbar": "Величина ошибок, которые будут иÑпользоватьÑÑ. ДопуÑтимые значениÑ: \"fraction\" (доверительные интервалы Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ð¹), \"sigma\" (Ñтандартное отклонение значений) и \"range\" (диапазоны значений)",
+ "srf-paramdesc-movingaverage": "Отобразить Ñреднее течение целого Ñ€Ñда дней, (ноль будет указывать не ÑкользÑщее Ñреднее)",
+ "srf-paramdesc-yaxislabel": "ОпиÑание Ð´Ð»Ñ Ð¾Ñи y",
+ "srf-paramdesc-xaxislabel": "ОпиÑание Ð´Ð»Ñ Ð¾Ñи x",
+ "srf-paramdesc-unit": "Единица",
+ "srf-printername-pagewidget": "Виджет Ñтраница",
+ "srf-printername-incoming": "ВходÑщие ÑвойÑтва",
+ "srf-paramdesc-count": "УÑтанавливает, нужно ли Ñчитать количеÑтво входÑщих ÑвойÑтв",
+ "srf-paramdesc-min": "Минимальное или пороговое значение",
+ "srf-paramdesc-excludeproperty": "ИÑключить ÑвойÑтво из набора результатов",
+ "srf-printername-media": "Медиапроигрыватель",
+ "srf-paramdesc-mediainspector": "Показывать детальную информацию об указанном Ñлементе медиа",
+ "srf-ui-mediaplayer-label-previous": "Ðазад",
+ "srf-ui-mediaplayer-label-play": "ВоÑпроизвеÑти",
+ "srf-ui-mediaplayer-label-pause": "Пауза",
+ "srf-ui-mediaplayer-label-next": "Далее",
+ "srf-ui-mediaplayer-label-stop": "ОÑтановить",
+ "srf-ui-mediaplayer-label-mute": "Без звука",
+ "srf-ui-mediaplayer-label-unmute": "Включить звук",
+ "srf-ui-mediaplayer-label-volume-max": "МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ñ€Ð¾Ð¼ÐºÐ¾ÑÑ‚ÑŒ",
+ "srf-ui-mediaplayer-label-shuffle": "Перемешивание",
+ "srf-ui-mediaplayer-label-shuffle-off": "Перемешивание выключено",
+ "srf-ui-mediaplayer-label-repeat": "ПовторÑÑ‚ÑŒ",
+ "srf-ui-mediaplayer-label-repeat-off": "Повторение выкл",
+ "srf-ui-mediaplayer-label-full-screen": "Ðа веÑÑŒ Ñкран",
+ "srf-ui-mediaplayer-label-restore-screen": "ВоÑÑтановить Ñкран",
+ "srf-spreadsheet-link": "Таблица",
+ "srf-paramdesc-spreadsheet-templatefile": "Ðазвание файла таблицы из проÑтранÑтва имён «Файл», иÑпользуемого Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñоздаваемого файла"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/rue.json b/www/wiki/extensions/SemanticResultFormats/i18n/rue.json
new file mode 100644
index 00000000..e157bf35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/rue.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazeb"
+ ]
+ },
+ "srfc_previousmonth": "Минулый міÑÑць",
+ "srfc_nextmonth": "Далшый міÑÑць",
+ "srfc_today": "ДнеÑÑŒ",
+ "srf_printername_gallery": "ÒалеріÑ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sco.json b/www/wiki/extensions/SemanticResultFormats/i18n/sco.json
new file mode 100644
index 00000000..ecfe33d3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sco.json
@@ -0,0 +1,67 @@
+{
+ "@metadata": {
+ "authors": [
+ "John Reid"
+ ]
+ },
+ "srf-desc": "Addeetional ootcome formats fer Semantic MediaWiki speirins",
+ "srf-prefs-intro-text": "Ye'v instawed the Semanteec Ootcome Formats extension. Fer mair heelp, please veesit the [https://www.semantic-mediawiki.org/wiki/Help:Result_formats ootcome formats] heelp page.",
+ "prefs-srf-eventcalendar-options": "Event calandair opties",
+ "srf-prefs-eventcalendar-options-update-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates autæmateec updates] o calendair events durin the page refresh",
+ "srf-prefs-eventcalendar-options-paneview-default": "Enable the pane luik bi defaut",
+ "prefs-srf-datatables-options": "DataBuirds opties",
+ "srf-prefs-datatables-options-update-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates autæmateec updates] o buird content durin the page refresh",
+ "srf-prefs-datatables-options-cache-default": "Enable [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage local storage] tae impruiv response time",
+ "srf-module-loading": "Laidin...",
+ "srf-ui-tooltip-title-legend": "The Legend",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Refresh",
+ "srf-ui-common-label-parameters": "Boondins",
+ "srf-ui-common-label-query": "Speirin",
+ "srf-ui-common-label-paneview": "The Pane luik",
+ "srf-ui-common-label-daterange": "Date range",
+ "srf-ui-widgets-label-parameter-limit": "Leemit boondin",
+ "srf-paramdesc-gridview": "Displey the chairt n data sets at the same time. The permitit values ar: \"nane\" n \"tabs\". The defaut is: \"nane\"",
+ "srf-paramdesc-excludetags": "Excluid the tags (delimiter: \";\")",
+ "srf_paramdesc_hidegaps": "Whather tae prent the requestit, bit onavailable propertie n record values separatit bi separaters or leain thaim oot",
+ "srf-ui-datatables-label-conditions": "The Condeetions",
+ "srf-ui-datatables-label-parameters": "Boondins",
+ "srf-ui-datatables-label-filters": "Column filters n rake",
+ "srf-ui-datatables-label-information": "Information",
+ "srf-ui-datatables-panel-disclaimer": "Boondins n condeetions can be altered, bit onie chynge is temprie n flung efter ae page refresh.",
+ "srf-ui-datatables-label-update-success": "The buird update wis successfu",
+ "srf-ui-datatables-label-update-error": "The buird update failed.",
+ "srf-ui-datatables-label-placeholder-column-search": "Rake …",
+ "srf-ui-datatables-label-content-cache": "The content wis derived fae the local cache.",
+ "srf-ui-datatables-label-content-server": "The content wis derived fae the server.",
+ "srf-ui-datatables-label-multiselect-column-header": "Available columns",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "The Filter settins",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Columns ar veesible",
+ "srf-ui-datatables-label-sEmptyTable": "Nae data is available in the buird",
+ "srf-ui-datatables-label-sInfo": "Shawin _STAIRT_ til _END_ o _TOTAL_ entries",
+ "srf-ui-datatables-label-sInfoEmpty": "Shawin 0 til 0 o 0 entries",
+ "srf-ui-datatables-label-sInfoFiltered": "(filterit fae _MAX_ total entries)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Shaw _MENU_ entries",
+ "srf-ui-datatables-label-sLoadingRecords": "Laidin...",
+ "srf-ui-datatables-label-sProcessing": "Processin…",
+ "srf-ui-datatables-label-sSearch": "Rake:",
+ "srf-ui-datatables-label-sZeroRecords": "Nae matchin records were foond",
+ "srf-ui-datatables-label-oPaginate-sFirst": "First",
+ "srf-ui-datatables-label-oPaginate-sLast": "Laist",
+ "srf-ui-datatables-label-oPaginate-sNext": "Nex",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Afore-gaun",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": acteevate to sort column ascendin",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": acteevate tae sort column descendin",
+ "srf-tree-rootinvalid": "$1 is na ae valid page title.",
+ "srf-paramdesc-tree-root": "The ruit page o the tree",
+ "srf-paramdesc-tree-startlevel": "The stairt level o the tree, e.g. fer integratin it intil anither tree",
+ "srf-paramdesc-filtered-filter-position": "The poseetion o the filters in relation til the views. The permitit values ar: \"tap\", n \"bottom\". The default is: \"tap\".",
+ "srf-paramdesc-filtered-list-type": "The type o the leet. The permitit values ar: \"leet\", \"ul\", \"ol\". The defaut is: \"leet\".",
+ "srf-ui-eventcalendar-label-update-success": "The event calendair update wis successfu.",
+ "srf-ui-eventcalendar-label-update-error": "The event calendair update failed.",
+ "srf-paramdesc-datasource": "The soorce fae whaur the data is accessible. The permitit values ar: \"file\", \"raw\" n \"url\". The default is: \"file\"",
+ "srf-paramdesc-errorbar": "The mistak baur tae be uised. The permitit values ar: \"fraction\" (confidance intervals fer values), \"sigma\" (staundairt deviation o values) n \"range\" (custom value ranges)",
+ "srf-excel-link": "Excel",
+ "srf-excel-missing-phpexcel": "Coudna export fer MS-Excel cause the extension [https://www.mediawiki.org/wiki/Extension:PHPExcel PHPExcel] isna instawed."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/si.json b/www/wiki/extensions/SemanticResultFormats/i18n/si.json
new file mode 100644
index 00000000..70719a5e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/si.json
@@ -0,0 +1,165 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කà·à·€à·’න්ද",
+ "Nemo bis"
+ ]
+ },
+ "prefs-srf": "අර්ථ විචà·à¶» ප්â€à¶»à¶­à·’එල ආකෘතීන්",
+ "srf-module-loading": "ප්â€à¶»à·€à·šà·à¶±à¶º වෙමින්...",
+ "srf-paramdesc-layout": "ලබ෠ගත à·„à·à¶šà·’ à·ƒà·à¶½à·à·ƒà·Šà¶¸",
+ "srf-paramdesc-height": "උස",
+ "srf-paramdesc-width": "පළල",
+ "srf-module-nomatch": "කිසිදු ගà·à¶½à¶´à·”මක් හමු නොවුණි",
+ "srf-paramdesc-charttype": "ලබ෠ගත à·„à·à¶šà·’ ප්â€à¶»à·ƒà·Šà¶­à·à¶» වර්ගය",
+ "srf-navigation-previous": "පෙර",
+ "srf-ui-navigation-prev": "පෙර",
+ "srf-ui-navigation-next": "මීළඟ",
+ "srf-ui-common-label-source": "මූලà·à·à·Šâ€à¶»à¶º",
+ "srf-ui-common-label-datasource": "දත්ත මූලà·à·à·Šâ€à¶»à¶º",
+ "srf-ui-common-label-request-object": "වස්තුව අයදින්න",
+ "srf-ui-common-label-help-section": "උපකà·à¶» අංà·à¶º",
+ "srf-ui-tooltip-title-options": "විකල්ප",
+ "srf-ui-tooltip-title-scope": "අභිප්â€à¶»à·à¶º",
+ "srf-error-option-mix": "($1) විකල්පය ලබ෠ගත නොහà·à¶š",
+ "srf-error-missing-layout": "à·ƒà·à¶½à·à·ƒà·Šà¶¸ දක්නට නොමà·à¶­",
+ "srfc_previousmonth": "පෙර මà·à·ƒà¶º",
+ "srfc_nextmonth": "මීළඟ මà·à·ƒà¶º",
+ "srfc_today": "අද",
+ "srfc_gotomonth": "මà·à·ƒà¶ºà¶§ යන්න",
+ "srf_printername_calendar": "මà·à·ƒà·’ක දින දසුන",
+ "srf_printername_vcard": "vCard නිර්යà·à¶­ කිරීම",
+ "srf_printername_icalendar": "iCalendar නිර්යà·à¶­ කිරීම",
+ "srf_paramdesc_icalendartitle": "දිනදසුන් ගොනුවේ à·à·“ර්ෂය",
+ "srf_paramdesc_icalendardescription": "දිනදසුන් ගොනුවේ විස්තරය",
+ "srf_printername_bibtex": "BibTeX නිර්යà·à¶­ කිරීම",
+ "srf_outline_novalue": "අගයක් නොමà·à¶­",
+ "srf_printername_outline": "පිට මà·à¶ºà·’ම",
+ "srf_printername_sum": "අංකවල ඓක්â€à¶ºà¶º",
+ "srf_printername_average": "අංකවල à·ƒà·à¶¸à·à¶±à·Šâ€à¶ºà¶º",
+ "srf_printername_max": "උපරිම අංකය",
+ "srf_printername_min": "අවම අංකය",
+ "srf_paramdesc_limit": "ප්â€à¶»à·à·Šà¶± කල යුතු උපරිම පිටු ගණන.",
+ "srf_printername_product": "අංකවල එලය",
+ "srf_printername_median": "අංකවල මධ්â€à¶ºà·ƒà·Šà¶®à¶º",
+ "srf_printername_earliest": "පෙරතම කà·à¶½à¶º",
+ "srf_printername_latest": "නවතම කà·à¶½à¶º",
+ "srf_printername_timeline": "කà·à¶½à¶´à·™à·…",
+ "srf_printername_eventline": "සිද්ධිපෙළ",
+ "srf_paramdesc_timelinesize": "කà·à¶½à¶´à·™à·…à·š උස",
+ "srf-timeline-allresults": "මෙම විමසුම සඳහ෠ඉදිරි ප්â€à¶»à¶­à·’ඵල.",
+ "srf_paramdesc_views": "සංදර්à·à¶±à¶º කිරීමට ඇති දසුන්",
+ "srf_printername_googlebar": "ගූගල් ස්ථම්භ ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶º",
+ "srf_printername_googlepie": "ගූගල් pie ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶º",
+ "srf-printername-jqplotchart": "jqPlot කටු සටහන",
+ "srf-printername-jqplotseries": "jqPlot මà·à¶½à·à·€",
+ "srf_paramdesc_charttitle": "ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶ºà·š à·à·“ර්ෂය",
+ "srf_paramdesc_barcolor": "ප්â€à¶»à·ƒà·Šà¶®à·à¶» වර්ණයන් විà·à·šà·‚ණය කරන්න",
+ "srf_paramdesc_bardirection": "ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶ºà¶š දිà·à·à·€ විà·à·šà·‚ණය කරන්න",
+ "srf-paramdesc-direction": "ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶ºà¶š හ෠රේඛ෠සටහනක දිà·à·à·€ විà·à·šà·‚ණය කරන්න",
+ "srf_paramdesc_barnumbersaxislabel": "ඉලක්කම් අක්ෂය සඳහ෠ලේබලය",
+ "srf-paramdesc-labelaxislabel": "ලේබල අක්ෂය සඳහ෠ලේබලය",
+ "srf-paramdesc-ticklabels": "tick ලේබලවල සංදර්à·à¶±à¶º සක්â€à¶»à·’ය කරන්න",
+ "srf-paramdesc-minvalue": "Y-අක්ෂයේ පෙන්විය යුතු අවම අගය",
+ "srf-paramdesc-chartlegend": "ප්â€à¶»à·ƒà·Šà¶®à·à¶» ප්â€à¶»à¶¶à¶±à·Šà¶°à¶ºà·š ස්ථà·à¶±à¶º",
+ "srf-paramdesc-datalabels": "ප්â€à¶»à·ƒà·Šà¶®à·à¶»/රේඛà·à¶ à·’ත්â€à¶» දත්ත ලේබල",
+ "srf-paramdesc-charttext": "විස්තරà·à¶­à·Šà¶¸à¶š ප්â€à¶»à·ƒà·Šà¶®à·à¶» පෙළ",
+ "srf-paramdesc-chartclass": "අමතර CSS පෙළ",
+ "srf-paramdesc-filling": "තනිතනි පිරවුම් විකල්පය",
+ "srf-paramdesc-theme": "ජà·à¶½à¶š තේමà·à·€à¶šà·Š තà·à¶»à·à¶œà¶±à·Šà¶±",
+ "srf-paramdesc-colorscheme": "වර්ණ යෙදුමක් තà·à¶»à·à¶œà¶±à·Šà¶±",
+ "srf-paramdesc-seriesgroup": "à·à·Šâ€à¶»à·šà¶«à·’ සමූහනය තà·à¶»à¶±à·Šà¶±",
+ "srf-paramdesc-serieslabel": "à·à·Šâ€à¶»à·šà¶«à·’ ලේබලය නිර්ණය කරන්න",
+ "srf-paramdesc-grouplabel": "සමූහ ලේබලය නිර්ණය කරන්න",
+ "srf-ui-gridview-label-item": "දත්ත අයිතමය",
+ "srf-ui-gridview-label-value": "දත්ත අගය",
+ "srf-ui-gridview-label-series": "දත්ත පෙළ",
+ "srf-ui-gridview-label-chart-tab": "ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-ui-gridview-label-data-tab": "දත්ත",
+ "srf-ui-gridview-label-info-tab": "තොරතුරු",
+ "srf_printername_gallery": "ගà·à¶½à¶»à·’ය",
+ "srf_paramdesc_perrow": "එක් පේළියකට පින්තූර සංඛ්â€à¶ºà·à·€",
+ "srf_paramdesc_widths": "පින්තූරවල පළල",
+ "srf_paramdesc_heights": "පින්තූරවල උස",
+ "srf-paramdesc-navigation": "වින්â€à¶ºà·à·ƒ යà·à¶­à·Šâ€à¶»à¶« පà·à¶½à¶šà¶º",
+ "srf-paramdesc-overlay": "පින්තූරය වසà·à¶½à·“ම සක්â€à¶»à·’ය කරන්න",
+ "srf-gallery-navigation-previous": "පෙර",
+ "srf-gallery-navigation-next": "මීළඟ",
+ "srf-gallery-overlay-count": "පින්තූරය $1 න් $2",
+ "srf-gallery-image-url-error": "පින්තූරය හමු නොවුණි.",
+ "srf_printername_tagcloud": "ටà·à¶œ වලà·à¶šà·”à·…",
+ "srf_paramdesc_increase": "ටà·à¶œà¶ºà¶±à·Šà·€à¶½ ප්â€à¶»à¶¸à·à¶«à¶º විà·à·à¶½ කරන්නේ කෙසේද",
+ "srf_paramdesc_tagorder": "ටà·à¶œà¶ºà¶±à·Šà·€à¶½ අනුපිළිවෙළ",
+ "srf_paramdesc_minsize": "ප්â€à¶»à¶­à·’à·à¶­à¶ºà·™à·„à·’ තිබෙන කුඩà·à¶¸ ටà·à¶œà¶ºà¶±à·Šà·€à¶½ ප්â€à¶»à¶¸à·à¶«à¶º",
+ "srf_paramdesc_maxsize": "ප්â€à¶»à¶­à·’à·à¶­à¶ºà·™à·„à·’ තිබෙන ලොකුම ටà·à¶œà¶ºà¶±à·Šà·€à¶½ ප්â€à¶»à¶¸à·à¶«à¶º",
+ "srf_paramdesc_maxtags": "වළà·à¶šà·”ලේ ඇති උපරිම ටà·à¶œ ගණන",
+ "srf-paramdesc-excludetags": "ටà·à¶œà¶ºà¶±à·Š පà·à·„à·à¶» හරින්න (පරිසීමකය: ;)",
+ "srf_printername_valuerank": "අගයන් à·à·Šâ€à¶»à·šà¶«à·’ගත කිරීම",
+ "srf_printername_array": "ආයිත්තම",
+ "srf_printername_hash": "පූරකය",
+ "srf-printername-graph": "ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-paramdesc-graph-nodeshape": "රේඛà·à¶ à·’ත්â€à¶»à¶ºà·š එක් එක් නà·à¶©à·”වල à·„à·à¶©à¶º",
+ "srf-paramdesc-graphname": "මà·à¶­à·˜à¶šà·à·€",
+ "srf-paramdesc-graphsize": "ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶ºà·š ප්â€à¶»à¶¸à·à¶«à¶º (පික්සල් වලින්)",
+ "srf-paramdesc-graphlegend": "රේඛà·à¶ à·’ත්â€à¶» ප්â€à¶»à¶¶à¶±à·Šà¶°à¶º පෙන්වන්න හ෠එපà·",
+ "srf-paramdesc-graphlabel": "ප්â€à¶»à·ƒà·Šà¶®à·à¶» ලේබලය",
+ "srf-paramdesc-rankdir": "ඊ නිර්දේà·à¶±à¶º",
+ "srf-paramdesc-graphlink": "ප්â€à¶»à·ƒà·Šà¶­à·à¶» සබà·à¶³à·’ය",
+ "srf-paramdesc-graphcolor": "ප්â€à¶»à·ƒà·Šà¶­à·à¶» වර්ණය",
+ "srf-paramdesc-graph-wwl": "වචන පොරà·à¶± සීමà·à·€ (# අක්ෂර වලින්)",
+ "srf-printername-datatables": "දත්තවගු",
+ "srf-printername-tree": "වෘක්ෂය",
+ "srf-printername-ultree": "අල්ට්â€à¶»à·’",
+ "srf-printername-oltree": "ඔල්ට්â€à¶»à·’",
+ "srf-paramdesc-tree-parent": "මà·à¶´à·’ය පිටුව අන්තර්ගත වන වත්කම",
+ "srf-printername-slideshow": "පà·à¶­à·’දර්à·à¶±à¶º",
+ "srf-paramdesc-delay": "පà·à¶­à·’ අතර පමà·à·€ තත්පර වලින්",
+ "srf-paramdesc-navigation-controls": "යà·à¶­à·Šâ€à¶»à¶« පà·à¶½à¶š පෙන්වන්න හ෠එපà·",
+ "srf-printername-filtered": "පෙරහන්ගත කෙරුණු",
+ "srf-filtered-selectorlabel-list": "ලà·à¶ºà·’ස්තුව",
+ "srf-filtered-selectorlabel-calendar": "දිනදසුන",
+ "srf-printername-d3chart": "D3 ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-printername-timeseries": "කà·à¶½ à·à·Šâ€à¶»à·šà¶«à·’ ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-paramdesc-group": "à·à·Šâ€à¶»à·šà¶«à·’ සමූහගත වන්නේ",
+ "srf-paramdesc-zoom": "විà·à·à¶½à¶±à¶º සක්â€à¶»à·’ය කරන්න",
+ "srf-paramdesc-datatable": "දත්තවගුවක් සක්â€à¶»à·’ය කරන්න",
+ "srf-printername-sparkline": "දීප්තිමත් ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-printername-listwidget": "ලà·à¶ºà·’ස්තුවිජේට්ටුව",
+ "srf-paramdesc-listtype": "ලà·à¶ºà·’ස්තු වර්ගයක් විà·à·šà·‚ණය කරන්න",
+ "srf-paramdesc-widget": "ලබ෠ගත à·„à·à¶šà·’ ගà·à¶¢à¶§à·Šà¶§à·”à·€",
+ "srf-paramdesc-pageitems": "එක් පිටුවකට අයිතම",
+ "srf-printername-eventcalendar": "සිදුවීම් දිනදසුන",
+ "srf-paramdesc-calendarfirstday": "එක් එක් සතිය පටන් ගන්න දවස",
+ "srf-paramdesc-calendardefaultview": "දිනදසුන පà·à¶§à·€à·™à¶± විට ආරම්භක දසුන",
+ "srf-paramdesc-calendarstart": "ප්â€à¶»à·à¶»à¶¸à·Šà¶· දිනදසුන් ආරම්භය (දිනය හ෠දිනවේල෠අගයන්)",
+ "srf-paramdesc-dayview": "දින අංකය ක්ලික් කිරීමෙන් දින දසුන සක්â€à¶»à·’ය කරන්න",
+ "srf-ui-eventcalendar-label-today": "අද",
+ "srf-ui-eventcalendar-label-month": "මà·à·ƒà¶º",
+ "srf-ui-eventcalendar-label-week": "සතිය",
+ "srf-ui-eventcalendar-label-day": "දිනය",
+ "srf-ui-eventcalendar-label-allday": "දවසෙම",
+ "srf-printername-dygraphs": "Dygraphs ප්â€à¶»à·ƒà·Šà¶­à·à¶»à¶º",
+ "srf-paramdesc-yaxislabel": "y-අක්ෂය මත දිස්වන විස්තරය",
+ "srf-paramdesc-xaxislabel": "x-අක්ෂය මත දිස්වන විස්තරය",
+ "srf-paramdesc-unit": "ඒකකය",
+ "srf-printername-pagewidget": "පිටුගà·à¶¢à·™à¶§à·Šà¶§à·”à·€",
+ "srf-printername-incoming": "පà·à¶¸à·’ණෙන ගුණà·à¶‚ග",
+ "srf-paramdesc-min": "අවම හ෠පර්යන්ත අගය",
+ "srf-paramdesc-excludeproperty": "ප්â€à¶»à¶­à·’එල කට්ටළයෙන් වත්කම බà·à·„à·à¶» හරින්න",
+ "srf-printername-media": "මà·à¶°à·Šâ€à¶º à·€à·à¶¯à¶šà¶º",
+ "srf-paramdesc-mediainspector": "විà·à·šà·‚à·“ මà·à¶°à·Šâ€à¶º පදà·à¶»à·Šà¶®à¶º පිළිබඳ විස්තරමය තොරතුරු පෙන්වයි",
+ "srf-ui-mediaplayer-label-previous": "පෙර",
+ "srf-ui-mediaplayer-label-play": "වයන්න",
+ "srf-ui-mediaplayer-label-pause": "විරà·à¶¸ කරන්න",
+ "srf-ui-mediaplayer-label-next": "මීළඟ",
+ "srf-ui-mediaplayer-label-stop": "නවතන්න",
+ "srf-ui-mediaplayer-label-mute": "නිà·à·Šà·à¶¶à·Šà¶¯ කරන්න",
+ "srf-ui-mediaplayer-label-unmute": "à·à¶¶à·Šà¶¯ කරන්න",
+ "srf-ui-mediaplayer-label-volume-max": "උපරිම à·à¶¶à·Šà¶¯ ප්â€à¶»à¶¸à·à¶«à¶º",
+ "srf-ui-mediaplayer-label-shuffle": "කලවම් කරන්න",
+ "srf-ui-mediaplayer-label-shuffle-off": "කලවම් කිරීම අක්â€à¶»à·’යයි",
+ "srf-ui-mediaplayer-label-repeat": "නà·à·€à¶­ කරන්න",
+ "srf-ui-mediaplayer-label-repeat-off": "නà·à·€à¶­ කිරීම අක්â€à¶»à·’යයි",
+ "srf-ui-mediaplayer-label-full-screen": "පූර්ණ තිරය",
+ "srf-ui-mediaplayer-label-restore-screen": "තිරය ප්â€à¶»à¶šà·˜à¶­à·’මත් කරන්න"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sk.json b/www/wiki/extensions/SemanticResultFormats/i18n/sk.json
new file mode 100644
index 00000000..c3085bbf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sk.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Helix84"
+ ]
+ },
+ "srf-desc": "Ďalšie formáty inline požiadaviek Semantic MediaWiki",
+ "srf-name": "Formáty sémantických výsledkov",
+ "srfc_previousmonth": "Predošlý mesiac",
+ "srfc_nextmonth": "Ďalší mesiac",
+ "srfc_today": "Dnes",
+ "srfc_gotomonth": "Prejsť na mesiac",
+ "srf_printername_calendar": "MesaÄný kalendár",
+ "srf_printername_vcard": "export vCard",
+ "srf_printername_icalendar": "export iCalendar",
+ "srf_printername_bibtex": "export BibTeX",
+ "srf_outline_novalue": "Žiadna hodnota",
+ "srf_printername_outline": "NáÄrt",
+ "srf_printername_sum": "Suma Äísiel",
+ "srf_printername_average": "Priemer Äísiel",
+ "srf_printername_max": "Maximálne Äíslo",
+ "srf_printername_min": "Minimálne Äíslo",
+ "srf_printername_timeline": "Časová os",
+ "srf_printername_eventline": "Os udalostí"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sr-ec.json b/www/wiki/extensions/SemanticResultFormats/i18n/sr-ec.json
new file mode 100644
index 00000000..044442a5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sr-ec.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher",
+ "Михајло Ðнђелковић",
+ "Milicevic01",
+ "Сербијана"
+ ]
+ },
+ "srf-ui-common-label-refresh": "ОÑвежи",
+ "srfc_previousmonth": "Претходни меÑец",
+ "srfc_nextmonth": "Следећи меÑец",
+ "srfc_today": "ДанаÑ",
+ "srfc_gotomonth": "Пређи на меÑец",
+ "srf_printername_calendar": "МеÑечни календар",
+ "srf_vcard_link": "vCard",
+ "srf_icalendar_link": "iCalendar",
+ "srf_bibtex_link": "BibTeX",
+ "srf_outline_novalue": "Ðема вредноÑти",
+ "srf_printername_sum": "Сума бројева",
+ "srf_printername_average": "Средња вредноÑÑ‚ бројева",
+ "srf_printername_max": "Ðајвећи број",
+ "srf_printername_min": "Ðајмањи број",
+ "srf_printername_gallery": "Галерија",
+ "srf-filtered-selectorlabel-table": "Табела"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sr-el.json b/www/wiki/extensions/SemanticResultFormats/i18n/sr-el.json
new file mode 100644
index 00000000..2738639c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sr-el.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michaello",
+ "Milicevic01"
+ ]
+ },
+ "srf-ui-common-label-refresh": "Osveži",
+ "srfc_previousmonth": "Prethodni mesec",
+ "srfc_nextmonth": "Sledeći mesec",
+ "srfc_today": "Danas",
+ "srfc_gotomonth": "Pređi na mesec",
+ "srf_printername_calendar": "MeseÄni kalendar",
+ "srf_vcard_link": "vCard",
+ "srf_icalendar_link": "iCalendar",
+ "srf_bibtex_link": "BibTeX",
+ "srf_outline_novalue": "Nema vrednosti",
+ "srf_printername_sum": "Suma brojeva",
+ "srf_printername_average": "Srednja vrednost brojeva",
+ "srf_printername_max": "Najveći broj",
+ "srf_printername_min": "Najmanji broj",
+ "srf_printername_gallery": "Galerija"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sv.json b/www/wiki/extensions/SemanticResultFormats/i18n/sv.json
new file mode 100644
index 00000000..196c28cc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sv.json
@@ -0,0 +1,263 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dafer45",
+ "M.M.S.",
+ "Martinwiss",
+ "Per",
+ "Rotsee",
+ "WikiPhoenix",
+ "Lokal Profil",
+ "Freked",
+ "McDutchie",
+ "Skalman",
+ "Nemo bis",
+ "Josve05a",
+ "Umeaboy",
+ "Mjälten"
+ ]
+ },
+ "srf-desc": "Extra resultatformat för Semantic MediaWiki-frågor",
+ "srf-prefs-datatables-options-cache-default": "Aktivera [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage lokal lagring] för att förbättra svarstiden",
+ "srf-module-loading": "Laddar...",
+ "srf-paramdesc-layout": "Tillgänglig utformningar",
+ "srf-paramdesc-height": "Höjd",
+ "srf-paramdesc-width": "Bredd",
+ "srf-paramdesc-class": "Ange ytterligare en CSS-klass som ska gälla för formatet",
+ "srf-module-nomatch": "Inga sökresultat hittades",
+ "srf-paramdesc-charttype": "Vilken diagramtyp som ska användas",
+ "srf-navigation-previous": "Föregående",
+ "srf-ui-navigation-prev": "Föreg.",
+ "srf-ui-navigation-next": "Nästa",
+ "srf-ui-common-label-source": "Källa",
+ "srf-ui-common-label-datasource": "Datakälla",
+ "srf-ui-common-label-request-object": "begär objekt",
+ "srf-ui-common-label-help-section": "hjälpavsnitt",
+ "srf-ui-tooltip-title-options": "Alternativ",
+ "srf-ui-tooltip-title-legend": "Teckenförklaring",
+ "srf-ui-tooltip-title-filter": "Filter",
+ "srf-ui-common-label-refresh": "Uppdatera",
+ "srf-ui-common-label-parameters": "Parametrar",
+ "srf-ui-common-label-daterange": "Datumintervall",
+ "srf-error-option-mix": "Alternativ ( $1 ) är inte tillgängligt",
+ "srf-error-option-link-all": "För alternativ ($1) måste parametern \"link\" ges värdet \"all\"",
+ "srf-error-missing-layout": "Layouten saknas",
+ "srf-warn-empy-chart": "Det finns inget diagram eftersom data saknas",
+ "srfc_previousmonth": "Föregående månad",
+ "srfc_nextmonth": "Nästa månad",
+ "srfc_today": "Idag",
+ "srfc_gotomonth": "Gå till månad",
+ "srf_printername_calendar": "MÃ¥nadskalender",
+ "srf_paramdesc_calendarlang": "Språkkoden för det språk som kalendern skall visas med",
+ "srf_paramdesc_calendarcolors": "Färgen som ska visas för varje datum-egenskap (t.ex: \"Start date=>green,End date=>#09c\")",
+ "srf_printername_vcard": "vCard-export",
+ "srf_icalendar_link": "iKalender",
+ "srf_printername_icalendar": "iCalendar-export",
+ "srf_paramdesc_icalendartitle": "Titeln på kalenderfilen",
+ "srf_paramdesc_icalendardescription": "Beskrivningen av kalenderfilen",
+ "srf_printername_bibtex": "BibTeX-export",
+ "srf_outline_novalue": "Inget värde",
+ "srf_printername_outline": "Outline",
+ "srf_paramdesc_outlineproperties": "En kommaseparerad lista med de egenskaper som ska visas som rubriker",
+ "srf_printername_sum": "Summa av tal",
+ "srf_printername_average": "Genomsnitt av tal",
+ "srf_printername_max": "Största nummer",
+ "srf_printername_min": "Minsta nummer",
+ "srf_paramdesc_limit": "Högsta antal sidor att fråga",
+ "srf_printername_product": "Produkt (multiplikation)",
+ "srf_printername_median": "Medianvärde",
+ "srf-paramdesc-default": "Standardvärde att visa när resultat saknas",
+ "srf_printername_earliest": "Earliest time",
+ "srf_printername_latest": "Latest time",
+ "srf_printername_timeline": "Tidslinje",
+ "srf_printername_eventline": "Händelselinje",
+ "srf_paramdesc_timelinebands": "Anger vilka tidslinjer (t.ex. för vecka, dag, eller månad) som ska visas i resultatet.",
+ "srf_paramdesc_timelineposition": "Anger tidpunkt för tidslinjens mittpunkt.",
+ "srf_paramdesc_timelinestart": "En egenskap för första tidpunkten.",
+ "srf_paramdesc_timelineend": "En egenskap för en andra tidpunkt.",
+ "srf_paramdesc_timelinesize": "Tidslinjens höjd",
+ "srf-timeline-allresults": "Visa ytterligare sökresultat för den här frågan.",
+ "srf-timeline-nojs": "Du måste använda JavaScript för att kunna se den interaktiva tidslinjen.",
+ "srf_paramdesc_views": "Vyer som ska visas",
+ "srf_paramdesc_facets": "De egenskaper som ska visas för varje sida",
+ "srf_paramdesc_lens": "Namnet på den mall som ska visa egenskaper från en sida",
+ "srf_printername_googlebar": "Google stapeldiagram",
+ "srf_printername_googlepie": "Google tårtdiagram",
+ "srf-printername-jqplotchart": "jqPlot diagram",
+ "srf-printername-jqplotseries": "jqPlot serier",
+ "srf_paramdesc_chartheight": "Ange höjden (i pixlar) för diagrammet",
+ "srf_paramdesc_chartwidth": "Ange bredden (i pixlar eller procent) för diagrammet",
+ "srf_paramdesc_charttitle": "Namnet på diagrammet (dess titel)",
+ "srf_paramdesc_barcolor": "Ange diagramfärger",
+ "srf_paramdesc_bardirection": "Ange riktning för diagrammet",
+ "srf-paramdesc-direction": "Ange riktning för diagrammet",
+ "srf_paramdesc_barnumbersaxislabel": "Etiketten för tal-axeln",
+ "srf-paramdesc-labelaxislabel": "Etiketten för sak-axeln",
+ "srf-paramdesc-ticklabels": "Visa stödlinjer",
+ "srf-paramdesc-minvalue": "Minsta värdet för Y-axeln",
+ "srf-paramdesc-pointlabels": "Visa datapunkter",
+ "srf-paramdesc-chartlegend": "Position för teckenförklaring",
+ "srf-paramdesc-datalabels": "Diagrametiketter",
+ "srf-paramdesc-charttext": "Beskrivande diagramtext",
+ "srf-paramdesc-chartclass": "Ytterligare CSS-klass",
+ "srf-paramdesc-renderer": "Välj diagram-ritare",
+ "srf-paramdesc-filling": "Särskild ifyllnad",
+ "srf-paramdesc-theme": "Välj rutnät",
+ "srf-paramdesc-chartcolor": "Använd särskilda diagramfärger",
+ "srf-paramdesc-colorscheme": "Välj färgpalett",
+ "srf-paramdesc-valueformat": "Ange format för värden",
+ "srf-paramdesc-highlighter": "Visa en \"datapunkts-framhävare\"",
+ "srf-paramdesc-smoothlines": "Ange en lijneutjämningsalgoritm för linjediagram",
+ "srf-paramdesc-stackseries": "Visa diagram som serier ovanpå varandra",
+ "srf-paramdesc-seriesgroup": "Visa seriegrupperingar",
+ "srf-paramdesc-serieslabel": "Ta reda på serieetiketten",
+ "srf-paramdesc-grouplabel": "Ta reda på gruppetiketten",
+ "srf-paramdesc-chartcursor": "Visningsalternativ för diagram-pekare",
+ "srf-paramdesc-trendline": "Gör så att man kan visa diagrammet och dess trendlinje samtidigt",
+ "srf-paramdesc-infotext": "Visa ytterligare information på en motsvarande informations-fliken",
+ "srf-ui-gridview-label-item": "Dataobjekt",
+ "srf-ui-gridview-label-value": "Datavärde",
+ "srf-ui-gridview-label-series": "Dataserie",
+ "srf-ui-gridview-label-chart-tab": "Diagram",
+ "srf-ui-gridview-label-data-tab": "Data",
+ "srf-ui-gridview-label-info-tab": "Information",
+ "srf_printername_gallery": "Bildgalleri",
+ "srf_paramdesc_perrow": "Antal bilder per rad",
+ "srf_paramdesc_widths": "Bildbredd",
+ "srf_paramdesc_heights": "Bildhöjd",
+ "srf_paramdesc_autocaptions": "Använd filnamnet som bildtext, om ingen annan bildtext angetts",
+ "srf_paramdesc_fileextensions": "Skriv ut filändelser när bildnamn används som bildtext",
+ "srf_paramdesc_captionproperty": "Namnet på den semantiska egenskap (som är närvarande på de efterfrågade sidorna) som ska användas som figurtext",
+ "srf_paramdesc_imageproperty": "Namnet på en semantisk egenskap på den efterfrågade sidan som pekar på bilder som ska användas. När den här parametern är angiven så kommer de efterfrågade sidorna själv inte att visas som bilder",
+ "srf-paramdesc-redirects": "Namnet på den semantiska egenskap som är närvarande på de efterfrågade sidorna som innehåller förflyttningsmålet",
+ "srf-paramdesc-navigation": "Specificera navigation för utformning",
+ "srf-paramdesc-overlay": "Möjliggör bilder ovanpå",
+ "srf-gallery-navigation-previous": "Föregående",
+ "srf-gallery-navigation-next": "Nästa",
+ "srf-gallery-overlay-count": "Bild $1 av $2",
+ "srf-gallery-image-url-error": "Bilden hittades inte",
+ "srf_printername_tagcloud": "Taggmoln",
+ "srf_paramdesc_includesubject": "Ämnestexterna inkluderas",
+ "srf_paramdesc_increase": "Hur man ökar storleken på orden",
+ "srf_paramdesc_tagorder": "Ordens ordning",
+ "srf_paramdesc_mincount": "Hur många gånger ett ord måste förekomma för att visas",
+ "srf_paramdesc_minsize": "Storleken på det minsta ordet (i procent)",
+ "srf_paramdesc_maxsize": "Storleken på det största ordet (i procent)",
+ "srf_paramdesc_maxtags": "Den största mängden ord i molnet",
+ "srf-paramdesc-excludetags": "Ord som ska uteslutas (avgränsare: \";\")",
+ "srf_printername_valuerank": "Value rank",
+ "srf_printername_array": "Array",
+ "srf_paramdesc_pagetitle": "Om man ska visa sidtitlar i resultatet eller inte",
+ "srf_paramdesc_hidegaps": "Om man ska visa efterfrågade egenskaper och datavärden som saknas eller om de ska utelämnas",
+ "srf_paramdesc_arrayname": "Skapar en array med det specificerade namnet om tillägget ArrayExtension har installerats (inget syns då)",
+ "srf_paramdesc_propsep": "Avgränsare mellan de efterfrågade egenskaperna",
+ "srf_paramdesc_manysep": "Avgränsare mellan egenskaper med många värden",
+ "srf_paramdesc_recordsep": "Avgränsare mellan värden för dataegenskaper",
+ "srf_paramdesc_headersep": "Avgränsare mellan egenskapsnamn och egenskapsvärde om \"headers\" har värdet \"show\" eller \"plain\"",
+ "srf_printername_hash": "Hash",
+ "srf_paramdesc_hashname": "Skapar en \"hash\" med namnet om tillägget HashTables är installerat (inget syns då).",
+ "srf-printername-graph": "Diagram",
+ "srf-paramdesc-graph-relation": "Är objekten eller namnegenskaperna ärvda, eller ärvs de?",
+ "srf-paramdesc-graph-nameprop": "Möjliggör att en egenskap används som objekt istället för den faktiska egenskapen",
+ "srf-paramdesc-graph-nodeshape": "Formen på varje nod i diagrammet",
+ "srf-paramdesc-graphname": "Ändrar diagrammets titel",
+ "srf-paramdesc-graphsize": "Diagramstorlek (i punkter)",
+ "srf-paramdesc-graphlegend": "Visa diagramets teckenförklaring (eller inte)",
+ "srf-paramdesc-graphlabel": "Diagrametikett",
+ "srf-paramdesc-rankdir": "Pilriktning",
+ "srf-paramdesc-graphlink": "Diagramlänk",
+ "srf-paramdesc-graphcolor": "Ställer in grafens färg",
+ "srf-paramdesc-graph-wwl": "Maximal längd för textlinje (i # bokstäver)",
+ "srf-paramdesc-redlinkcolor": "Ändrar teckenfärgen för röda länkar",
+ "srf-printername-datatables": "Datatabeller",
+ "srf-ui-datatables-label-conditions": "Villkor",
+ "srf-ui-datatables-label-parameters": "Parametrar",
+ "srf-ui-datatables-label-information": "Information",
+ "srf-ui-datatables-label-update-success": "Tabellen uppdaterades",
+ "srf-ui-datatables-label-update-error": "Uppdateringen av tabellen misslyckades.",
+ "srf-ui-datatables-label-placeholder-column-search": "Sök ...",
+ "srf-ui-datatables-label-multiselect-column-header": "Tillgängliga kolumner",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "Filterinställningar",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Kolonner är synliga",
+ "srf-ui-datatables-label-sInfo": "Visar _START_ till _END_ av _TOTAL_ poster",
+ "srf-ui-datatables-label-sInfoEmpty": "Visar 0 till 0 av 0 poster",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Visar _MENU_ poster",
+ "srf-ui-datatables-label-sLoadingRecords": "Läser in...",
+ "srf-ui-datatables-label-sProcessing": "Bearbetar...",
+ "srf-ui-datatables-label-sSearch": "Sök:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Första",
+ "srf-ui-datatables-label-oPaginate-sLast": "Sista",
+ "srf-ui-datatables-label-oPaginate-sNext": "Nästa",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Föregående",
+ "srf-printername-tree": "Tree",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "Ingen ärv egenskap given. Trädet kan inte skapas utan att man anger en ärvd egenskap.",
+ "srf-tree-rootinvalid": "$1 är inte en giltig sidtitel.",
+ "srf-paramdesc-tree-parent": "Egenskapen som innehåller den ärvda sidan",
+ "srf-printername-slideshow": "Bildvisning",
+ "srf-paramdesc-delay": "Stunden mellan bilder (i sekunder)",
+ "srf-paramdesc-navigation-controls": "Visa navigeringsknappar eller inte",
+ "srf-paramdesc-effect": "Vilken effekt som ska visas när bilden byts",
+ "srf-printername-filtered": "Filtrerad",
+ "srf-paramdesc-filtered-list-named-args": "Namnge de argument som skickas till mallen.",
+ "srf-paramdesc-filtered-calendar-title-template": "En mall som används för att formatera evenemangets rubrik i kalendern",
+ "srf-paramdesc-filtered-map-height": "Karthöjden",
+ "srf-paramdesc-filtered-map-min-zoom": "Den minimala zoomnivån att välja för kartan",
+ "srf-filtered-selectorlabel-list": "Lista",
+ "srf-filtered-selectorlabel-table": "Tabell",
+ "srf-filtered-selectorlabel-calendar": "Kalender",
+ "srf-filtered-selectorlabel-map": "Karta",
+ "srf-printername-d3chart": "D3 diagram",
+ "srf-printername-timeseries": "Tidsserie diagram",
+ "srf-paramdesc-group": "Serie grupperad efter",
+ "srf-paramdesc-zoom": "Använd zoom",
+ "srf-paramdesc-datatable": "Använd datatabell",
+ "srf-timeseries-zoom-out-of-range": "Zoom inom den angivna upplösningen gav ingen (eller inte tillräckligt med) data",
+ "srf-printername-sparkline": "Sparkline diagram",
+ "srf-printername-listwidget": "Listwidget",
+ "srf-paramdesc-listtype": "Ange listtyp",
+ "srf-paramdesc-widget": "Tillgängliga manicker (widget)",
+ "srf-paramdesc-pageitems": "Antal per sida",
+ "srf-printername-eventcalendar": "Event calendar",
+ "srf-paramdesc-calendarfirstday": "Första dagen i veckan",
+ "srf-paramdesc-calendardefaultview": "Första läget när kalendern visas",
+ "srf-paramdesc-calendarstart": "Startdatum för kalendern (datum- eller datum/tid-värden)",
+ "srf-paramdesc-dayview": "Visa \"dags-vyn\" genom att klicka på numret för den dagen",
+ "srf-ui-eventcalendar-label-today": "Idag",
+ "srf-ui-eventcalendar-label-month": "MÃ¥nad",
+ "srf-ui-eventcalendar-label-week": "Vecka",
+ "srf-ui-eventcalendar-label-day": "Dag",
+ "srf-ui-eventcalendar-label-listmonth": "MÃ¥nad (lista)",
+ "srf-ui-eventcalendar-label-listweek": "Vecka (lista)",
+ "srf-ui-eventcalendar-label-listday": "Dag (lista)",
+ "srf-ui-eventcalendar-label-allday": "Hela dagen",
+ "srf-ui-eventcalendar-click-popup": "Vill du skapa en händelse?",
+ "srf-printername-dygraphs": "Dygraphs diagram",
+ "srf-paramdesc-datasource": "Källan varifrån data är tillgänglig. Tillåtna värden: \"file\", \"raw\" och \"url\". Standard: \"file\"",
+ "srf-paramdesc-errorbar": "De felstaplar som ska användas. Tillåtna värden: \"fraction\" (konfidensintervall för värden), \"sigma\" (standardavvikelsen för värden) och \"range\" (anpassad värdeintervall)",
+ "srf-paramdesc-movingaverage": "Visa medelvärdet för ett visst antal dagar (zero innebär inget medelvärde)",
+ "srf-paramdesc-yaxislabel": "Beskrivning som visas på y-axeln",
+ "srf-paramdesc-xaxislabel": "Beskrivning som visas på x-axeln",
+ "srf-paramdesc-unit": "Enhet",
+ "srf-printername-pagewidget": "Pagewidget (sidomanick)",
+ "srf-printername-incoming": "Ingående egenskaper",
+ "srf-paramdesc-min": "Minsta värde eller tröskelvärdet",
+ "srf-paramdesc-excludeproperty": "Uteslut egenskap från resultatet",
+ "srf-printername-media": "Mediaspelare",
+ "srf-ui-mediaplayer-label-previous": "Föregående",
+ "srf-ui-mediaplayer-label-play": "Spela upp",
+ "srf-ui-mediaplayer-label-pause": "Pausa",
+ "srf-ui-mediaplayer-label-next": "Nästa",
+ "srf-ui-mediaplayer-label-stop": "Stopp",
+ "srf-ui-mediaplayer-label-mute": "Ljud av",
+ "srf-ui-mediaplayer-label-unmute": "Ljud på",
+ "srf-ui-mediaplayer-label-volume-max": "Maxvolym",
+ "srf-ui-mediaplayer-label-shuffle": "Blanda",
+ "srf-ui-mediaplayer-label-repeat": "Upprepa",
+ "srf-ui-mediaplayer-label-full-screen": "Fullskärm",
+ "srf-spreadsheet-link": "Kalkylblad",
+ "srf-paramdesc-spreadsheet-filename": "Filformatet att producera. Tillåtna värden: xlsx, xls, ods, csv. Standard: xlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "Namnet på kalkylbladsfilen från namnrymden \"File\" som används för att formatera den genererade filen"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/sw.json b/www/wiki/extensions/SemanticResultFormats/i18n/sw.json
new file mode 100644
index 00000000..1ef7622f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/sw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kwisha"
+ ]
+ },
+ "srf-ui-tooltip-title-legend": "Simulizi"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ta.json b/www/wiki/extensions/SemanticResultFormats/i18n/ta.json
new file mode 100644
index 00000000..caa668e3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ta.json
@@ -0,0 +1,88 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karthi.dr",
+ "Shanmugamp7",
+ "ElangoRamanujam"
+ ]
+ },
+ "srf-module-loading": "à®à®±à¯à®±à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯...",
+ "srf-paramdesc-layout": "கிடைகà¯à®•à¯à®®à¯ வடிவமைபà¯à®ªà¯",
+ "srf-paramdesc-height": "உயரமà¯",
+ "srf-paramdesc-width": "அகலமà¯",
+ "srf-module-nomatch": "பொரà¯à®¤à¯à®¤à®®à®¾à®©à®µà¯ˆà®•à®³à¯ ஒனà¯à®±à¯à®®à¯ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.",
+ "srf-paramdesc-charttype": "கிடைகà¯à®•à¯à®®à¯ வரைபட வகை",
+ "srf-navigation-previous": "à®®à¯à®¨à¯à®¤à¯ˆà®¯",
+ "srf-ui-navigation-prev": "à®®à¯à®¨à¯à®¤à¯ˆà®¯",
+ "srf-ui-navigation-next": "அடà¯à®¤à¯à®¤à®¤à¯",
+ "srf-ui-common-label-source": "மூலமà¯",
+ "srf-ui-common-label-datasource": "தரவ௠மூலமà¯",
+ "srf-ui-common-label-request-object": "பொரà¯à®³à¯ˆà®•à¯ கோரவà¯à®®à¯",
+ "srf-ui-common-label-help-section": "உதவிப௠பகà¯à®¤à®¿",
+ "srf-ui-tooltip-title-options": "விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯à®•à®³à¯",
+ "srf-ui-tooltip-title-scope": "நோகà¯à®•à®®à¯",
+ "srf-ui-tooltip-title-filter": "வடிகடà¯à®Ÿà®¿",
+ "srf-ui-common-label-paneview": "பகà¯à®• நோகà¯à®•à¯",
+ "srf-error-option-mix": "விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯ ($1) இலà¯à®²à¯ˆ",
+ "srfc_previousmonth": "கடநà¯à®¤ மாதமà¯",
+ "srfc_nextmonth": "அடà¯à®¤à¯à®¤ மாதமà¯",
+ "srfc_today": "இனà¯à®±à¯",
+ "srf_printername_calendar": "மாதாநà¯à®¤à®¿à®° நாடà¯à®•à®¾à®Ÿà¯à®Ÿà®¿",
+ "srf_outline_novalue": "மதிபà¯à®ªà¯ இலà¯à®²à¯ˆ",
+ "srf_printername_outline": "திடà¯à®Ÿà®µà®°à¯ˆ",
+ "srf_printername_sum": "எணà¯à®•à®³à®¿à®©à¯ கூடà¯à®Ÿà®²à¯",
+ "srf_printername_average": "எணà¯à®•à®³à®¿à®©à¯ சராசரி",
+ "srf_printername_max": "அதிகபடà¯à®š எணà¯",
+ "srf_printername_min": "கà¯à®±à¯ˆà®¨à¯à®¤à®ªà®Ÿà¯à®š எணà¯",
+ "srf_printername_product": "எணà¯à®•à®³à®¿à®©à¯ பெரà¯à®•à¯à®•à®²à¯",
+ "srf_printername_median": "எணà¯à®•à®³à®¿à®©à¯ இடைநிலை",
+ "srf_printername_earliest": "மிகமà¯à®¨à¯à®¤à®¿à®¯ நேரமà¯",
+ "srf_printername_latest": "மிகஅணà¯à®®à¯ˆà®¯ நேரமà¯",
+ "srf_printername_timeline": "காலவரிசை",
+ "srf_printername_eventline": "நிகழà¯à®šà¯à®šà®¿à®µà®°à®¿à®šà¯ˆ",
+ "srf_paramdesc_timelinesize": "காலகà¯à®•à¯‹à®Ÿà¯à®Ÿà®¿à®©à¯ உயரமà¯",
+ "srf_printername_googlebar": "கூகிள௠படà¯à®Ÿà¯ˆ வரைபடமà¯",
+ "srf_printername_googlepie": "கூகà¯à®³à¯ வடà¯à®Ÿ விளகà¯à®•à®ªà¯à®ªà®Ÿà®®à¯",
+ "srf-ui-gridview-label-item": "தரவ௠உரà¯à®ªà¯à®ªà®Ÿà®¿",
+ "srf-ui-gridview-label-series": "தரவ௠வரிசைகளà¯",
+ "srf-ui-gridview-label-chart-tab": "விளகà¯à®•à®ªà¯à®ªà®Ÿà®®à¯",
+ "srf-ui-gridview-label-data-tab": "தரவà¯",
+ "srf-ui-gridview-label-info-tab": "தகவலà¯",
+ "srf_printername_gallery": "காடà¯à®šà®¿à®¯à®•à®®à¯",
+ "srf_paramdesc_perrow": "நெடà¯à®µà®°à®¿à®šà¯ˆ ஒனà¯à®±à®¿à®±à¯à®•à¯ படஙà¯à®•à®³à®¿à®©à¯ எணà¯à®£à®¿à®•à¯à®•à¯ˆ",
+ "srf_paramdesc_widths": "படஙà¯à®•à®³à®¿à®©à¯ அகலமà¯",
+ "srf_paramdesc_heights": "படஙà¯à®•à®³à®¿à®©à¯ உயரமà¯",
+ "srf-gallery-navigation-previous": "à®®à¯à®¨à¯à®¤à¯ˆà®¯",
+ "srf-gallery-navigation-next": "அடà¯à®¤à¯à®¤à®¤à¯",
+ "srf_paramdesc_graphname": "தலைபà¯à®ªà¯",
+ "srf-ui-datatables-label-conditions": "கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®•à®³à¯",
+ "srf-ui-datatables-label-information": "தகவலà¯",
+ "srf-ui-datatables-label-placeholder-column-search": "தேடà¯à®•...",
+ "srf-ui-datatables-label-sLoadingRecords": "à®à®±à¯à®±à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯...",
+ "srf-ui-datatables-label-sSearch": "தேடà¯à®•:",
+ "srf-ui-datatables-label-oPaginate-sFirst": "à®®à¯à®¤à®²à¯",
+ "srf-ui-datatables-label-oPaginate-sLast": "இறà¯à®¤à®¿",
+ "srf-ui-datatables-label-oPaginate-sNext": "அடà¯à®¤à¯à®¤à¯",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "à®®à¯à®¨à¯à®¤à¯ˆà®¯",
+ "srf-paramdesc-listtype": "படà¯à®Ÿà®¿à®¯à®²à¯ வகையை கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®µà¯à®®à¯",
+ "srf-ui-eventcalendar-label-today": "இனà¯à®±à¯",
+ "srf-ui-eventcalendar-label-month": "மாதமà¯",
+ "srf-ui-eventcalendar-label-week": "வாரமà¯",
+ "srf-ui-eventcalendar-label-day": "நாளà¯",
+ "srf-ui-eventcalendar-label-allday": "அனைதà¯à®¤à¯ நாடà¯à®•à®³à¯à®®à¯",
+ "srf-paramdesc-unit": "பகà¯à®¤à®¿",
+ "srf-printername-media": "ஊடக இயகà¯à®•à®¿",
+ "srf-ui-mediaplayer-label-previous": "à®®à¯à®¨à¯à®¤à¯ˆà®¯",
+ "srf-ui-mediaplayer-label-play": "இயகà¯à®•à¯",
+ "srf-ui-mediaplayer-label-pause": "இடைநிறà¯à®¤à¯à®¤à¯",
+ "srf-ui-mediaplayer-label-next": "அடà¯à®¤à¯à®¤à®¤à¯",
+ "srf-ui-mediaplayer-label-stop": "நிறà¯à®¤à¯à®¤à¯",
+ "srf-ui-mediaplayer-label-mute": "அமைதியாகà¯à®•à¯",
+ "srf-ui-mediaplayer-label-unmute": "ஒலிகà¯à®•à®šà¯ செயà¯",
+ "srf-ui-mediaplayer-label-volume-max": "அதிகபடà¯à®š ஒலியளவà¯",
+ "srf-ui-mediaplayer-label-shuffle": "கலைதà¯à®¤à®²à¯",
+ "srf-ui-mediaplayer-label-shuffle-off": "கலைதà¯à®¤à®²à¯ அணை",
+ "srf-ui-mediaplayer-label-repeat": "மீளà¯à®šà¯†à®¯à®²à¯",
+ "srf-ui-mediaplayer-label-repeat-off": "மீளà¯à®šà¯†à®¯à®²à¯ அணை",
+ "srf-ui-mediaplayer-label-full-screen": "à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/te.json b/www/wiki/extensions/SemanticResultFormats/i18n/te.json
new file mode 100644
index 00000000..dc1ea17d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/te.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Veeven"
+ ]
+ },
+ "srf-paramdesc-height": "à°Žà°¤à±à°¤à±",
+ "srf-paramdesc-width": "వెడలà±à°ªà±",
+ "srfc_previousmonth": "à°•à±à°°à°¿à°¤à°‚ నెల",
+ "srfc_nextmonth": "తరà±à°µà°¾à°¤à°¿ నెల",
+ "srfc_today": "ఈరోజà±",
+ "srfc_gotomonth": "నెలకి వెళà±à°³à°‚à°¡à°¿",
+ "srf_outline_novalue": "విలà±à°µ లేదà±",
+ "srf_printername_sum": "సంఖà±à°¯à°² మొతà±à°¤à°‚",
+ "srf_printername_average": "సంఖà±à°¯à°² సగటà±",
+ "srf_printername_max": "à°—à°°à°¿à°·à±à°  సంఖà±à°¯",
+ "srf_printername_min": "కనిషà±à°  సంఖà±à°¯",
+ "srf_printername_timeline": "కాలరేఖ",
+ "srf_paramdesc_chartheight": "చారà±à°Ÿà± యొకà±à°• à°Žà°¤à±à°¤à±, పికà±à°¸à±†à°³à±à°³à°²à±‹",
+ "srf_paramdesc_chartwidth": "చారà±à°Ÿà± యొకà±à°• వెడలà±à°ªà±, పికà±à°¸à±†à°³à±à°³à°²à±‹",
+ "srf_paramdesc_graphname": "శీరà±à°·à°¿à°•"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tg-cyrl.json b/www/wiki/extensions/SemanticResultFormats/i18n/tg-cyrl.json
new file mode 100644
index 00000000..d14e0d3a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tg-cyrl.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ibrahim"
+ ]
+ },
+ "srfc_previousmonth": "Моҳи қаблӣ",
+ "srfc_nextmonth": "Моҳи баъдӣ",
+ "srfc_today": "Имрӯз",
+ "srfc_gotomonth": "Рафтан ба моҳ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tg-latn.json b/www/wiki/extensions/SemanticResultFormats/i18n/tg-latn.json
new file mode 100644
index 00000000..45a07ec2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tg-latn.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liangent"
+ ]
+ },
+ "srfc_previousmonth": "Mohi qablī",
+ "srfc_nextmonth": "Mohi ba'dī",
+ "srfc_today": "Imrūz",
+ "srfc_gotomonth": "Raftan ba moh"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tl.json b/www/wiki/extensions/SemanticResultFormats/i18n/tl.json
new file mode 100644
index 00000000..7ff5be80
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tl.json
@@ -0,0 +1,176 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw",
+ "Sky Harbor",
+ "Emem.calist",
+ "Nemo bis"
+ ]
+ },
+ "srf-desc": "Dagdag na mga anyo para sa nasa loob ng guhit na mga pagtatanong na pang-Semantikong MediaWiki",
+ "srf-module-loading": "Ikinakarga...",
+ "srf-paramdesc-layout": "Makukuhang kalatagan",
+ "srf-paramdesc-height": "Taas",
+ "srf-paramdesc-width": "Lapad",
+ "srf-paramdesc-class": "Tumukoy ng isang karagdagang klase ng mga pilas ng lumalagaslas na estilo",
+ "srf-module-nomatch": "Walang natagpuang mga pagtutugma",
+ "srf-paramdesc-charttype": "Makukuhang uri ng talangguhit",
+ "srf-error-option-mix": "Hindi makukuha ang napili ($1)",
+ "srf-error-option-link-all": "Ang mapagpipilian ($1) ay nangangailangan ng parametrong \"link\" na maitakda bilang \"all\"",
+ "srf-error-missing-layout": "Nawawala ang kalatagan",
+ "srf-warn-empy-chart": "Ang talaguhitan/talangguhit ay walang laman dahil sa nawawalang dato",
+ "srfc_previousmonth": "Nakaraang buwan",
+ "srfc_nextmonth": "Susunod na buwan",
+ "srfc_today": "Ngayong araw na ito",
+ "srfc_gotomonth": "Pumunta sa buwan",
+ "srf_printername_calendar": "Buwanang kalendaryo",
+ "srf_paramdesc_calendarlang": "Ang kodigo para sa wika na pagpapakitaan ng kalendaryo",
+ "srf_paramdesc_calendarcolors": "Ang kulay na ipapakita para sa bawat isang pag-aaring petsa (halimbawa: \"Petsa ng simula=>green,Petsa ng wakas=>#09c\")",
+ "srf_vcard_link": "vCard",
+ "srf_printername_vcard": "Luwas ng vCard",
+ "srf_icalendar_link": "iCalendar",
+ "srf_printername_icalendar": "Luwas ng iCalendar",
+ "srf_paramdesc_icalendartitle": "Ang pamagat ng talaksan ng kalendaryo",
+ "srf_paramdesc_icalendardescription": "Ang paglalarawan ng talaksan ng kalendaryo",
+ "srf_bibtex_link": "BibTeX",
+ "srf_printername_bibtex": "Luwas ng BibTeX",
+ "srf_outline_novalue": "Walang halaga",
+ "srf_printername_outline": "Banghay",
+ "srf_paramdesc_outlineproperties": "Ang talaan ng mga pag-aaring ipapakita bilang mga paulong banghay, na pinaghihiwalay ng mga kuwit",
+ "srf_printername_sum": "kabuuan ng mga bilang",
+ "srf_printername_average": "Pinatakang halaga ng mga bilang",
+ "srf_printername_max": "Pinakamataas na bilang",
+ "srf_printername_min": "Pinakamababang bilang",
+ "srf_paramdesc_limit": "Ang pinakamaraming bilang ng mga pahinang ipagtatanong",
+ "srf_printername_product": "Produkto ng mga bilang",
+ "srf_printername_median": "Panggitna ng mga bilang",
+ "srf-paramdesc-default": "Ang likas na nakatakdang halaga na ipapakita kapag walang mga resultang pambilang",
+ "srf_printername_earliest": "Pinaka maagang oras",
+ "srf_printername_latest": "Pinaka huling oras",
+ "srf_printername_timeline": "Guhit ng panahon",
+ "srf_printername_eventline": "Guhit ng kaganapan",
+ "srf_paramdesc_timelinebands": "Tumutukoy kung aling mga sintas ang ipapakita sa loob ng resulta.",
+ "srf_paramdesc_timelineposition": "Tumutukoy kung saan unang tutuon ang guhit ng panahon.",
+ "srf_paramdesc_timelinestart": "Isang pangalan ng pag-aaring ginamit upang tukuyin ang isang unang punto ng oras",
+ "srf_paramdesc_timelineend": "Isang pangalan ng pag-aaring ginamit upang tukuyin ang isang pangalawang punto ng oras",
+ "srf_paramdesc_timelinesize": "Ang taas ng guhit ng panahon",
+ "srf-timeline-allresults": "Karagdagang mga resulta para sa pagsisiyasat na ito.",
+ "srf-timeline-nojs": "Kailangan mong paganahin ang JavaScript upang makita ang masiglang guhit ng panahon.",
+ "srf_paramdesc_views": "Mga tanawing ipapakita",
+ "srf_paramdesc_facets": "Ang pangkat ng mga pag-aaring ipapakita para sa bawat pahina",
+ "srf_paramdesc_lens": "Ang pangalan ng isang suleras na pagpapakitaan ng mga pag-aari ng pahina",
+ "srf_printername_googlebar": "Baretang tsart ng Google",
+ "srf_printername_googlepie": "Kakaning-tsart ng Google",
+ "srf-printername-jqplotchart": "Talangguhit ng jqPlot",
+ "srf-printername-jqplotseries": "Mga serye ng jqPlot",
+ "srf_paramdesc_chartheight": "Tukuyin ang taas ng (na nasa mga piksel) ng isang talangguhit o talaguhitan",
+ "srf_paramdesc_chartwidth": "Tukuyin ang lapad (na nasa mga piksel o bahagdan) ng isang talangguhit o talaguhitan",
+ "srf_paramdesc_charttitle": "Ang pamagat ng talangguhit",
+ "srf_paramdesc_barcolor": "Ang kulay ng mga bareta",
+ "srf_paramdesc_bardirection": "Tukuyin ang kapupuntahan ng isang talangguhit",
+ "srf-paramdesc-direction": "Tukuyin ang kapupuntahan ng isang talangguhit o talaguhitan",
+ "srf_paramdesc_barnumbersaxislabel": "Ang tatak para sa painugan ng mga bilang",
+ "srf-paramdesc-labelaxislabel": "Ang tatak para sa painugan ng mga tatak",
+ "srf-paramdesc-ticklabels": "Paganahin ang pagpapakita ng mga tatak ng tsek",
+ "srf-paramdesc-minvalue": "Ang pinaka mababang halaga na ipapakita sa ibabaw ng aksis na Y",
+ "srf-paramdesc-pointlabels": "Ipakita ang mga tuldok ng dato na nasa loob ng talangguhit",
+ "srf-paramdesc-chartlegend": "Puwesto ng paliwanag para sa talangguhit",
+ "srf-paramdesc-datalabels": "Mga katatakan ng dato ng talangguhit/talaguhitan",
+ "srf-paramdesc-charttext": "Mapaglarawang teksto ng talangguhit",
+ "srf-paramdesc-chartclass": "Karagdagang klase ng Mga Pilas ng Lumalagaslas na Estilo",
+ "srf-paramdesc-renderer": "Pumili ng isang tagapagharap ng talaguhitan/talangguhit",
+ "srf-paramdesc-filling": "Indibiduwal na magpipilian ng pampuno",
+ "srf-paramdesc-theme": "Pumili ng isang tema ng parilya",
+ "srf-paramdesc-chartcolor": "Magtalaga ng mga kulay ng indibiduwal na talangguhit",
+ "srf-paramdesc-colorscheme": "Pumili ng isang panukala ng kulay",
+ "srf-paramdesc-valueformat": "Tukuyin ang patakaran ng pagsasaayos ng mga halaga",
+ "srf-paramdesc-highlighter": "Magpakita ng isang pampaliwanag ng tuldok ng dato",
+ "srf-paramdesc-smoothlines": "Maglapat ng isang algoritmong pampakinis sa ibabaw ng mga talangguhit na paguhit",
+ "srf-paramdesc-stackseries": "Ipakita ang talangguhit bilang mga seryeng nakasalansan",
+ "srf-paramdesc-seriesgroup": "Piliin ang pagkakapangkat ng mga serye",
+ "srf-paramdesc-serieslabel": "Alamin ang katatakan ng serye",
+ "srf-paramdesc-grouplabel": "Alamin ang tatak ng pangkat",
+ "srf-paramdesc-chartcursor": "Mapipili na pangtanghal ng panturo ng talangguhit",
+ "srf-paramdesc-trendline": "Paganahin ang sabay-sabay na pagpapakita ng isang talangguhit at ang guhit ng kalakaran nito",
+ "srf-ui-gridview-label-item": "Bagay na pandatos",
+ "srf-ui-gridview-label-value": "Halaga ng dato",
+ "srf-ui-gridview-label-series": "Mga serye ng dato",
+ "srf-ui-gridview-label-chart-tab": "Talangguhit",
+ "srf-ui-gridview-label-data-tab": "Datos",
+ "srf_printername_gallery": "Galerya",
+ "srf_paramdesc_perrow": "Ang dami ng mga larawan bawat hilera",
+ "srf_paramdesc_widths": "Ang lapad ng mga larawan",
+ "srf_paramdesc_heights": "Ang taas ng mga larawan",
+ "srf_paramdesc_autocaptions": "Gamitin ang pangalan ng talaksan bilang paliwag kapag walang ibinigay",
+ "srf_paramdesc_fileextensions": "Kapag ginagamit ang pangalan ng talaksan bilang paliwanag, ipakita rin ang dugtong ng talaksan",
+ "srf_paramdesc_captionproperty": "Ang pangalan ng isang kaariang semantiko naroroon sa ibabaw ng mga pahinang siniyasat na gagamitin bilang paliwanag",
+ "srf_paramdesc_imageproperty": "Pangalan ng isang kaariang semantiko sa ibabaw ng mga pahina siniyasat na tumuturo sa mga imaheng gagamitin. Kapag nakatakda, ang mga pahina siniyasat mismo ay hindi ipapakita sa mga imahe",
+ "srf-paramdesc-redirects": "Ang pangalan ng isang semantikong kaariang naroon sa inuusisang mga pahina na naglalaman ng pinupukol na pagpunta sa ibang lugar",
+ "srf-paramdesc-navigation": "Pantaban sa kalatagan ng panglibot",
+ "srf-paramdesc-overlay": "Paganahin ang kalupkop ng imahe",
+ "srf-gallery-navigation-previous": "Nakaraan",
+ "srf-gallery-navigation-next": "Susunod",
+ "srf-gallery-overlay-count": "Imaheng $1 ng $2",
+ "srf-gallery-image-url-error": "Hindi natagpuan ang larawan.",
+ "srf_printername_tagcloud": "Ulap ng tatak",
+ "srf_paramdesc_includesubject": "Kung dapat bang isama ang mga pangalan ng mga paksa mismo",
+ "srf_paramdesc_increase": "Paano patataasin ang sukat ng mga tatak",
+ "srf_paramdesc_tagorder": "Ang pagkakasunud-sunod ng mga tatak",
+ "srf_paramdesc_mincount": "Ang pinaka mababang dami ng ulit na kailangang lumitaw ang isang halaga upang mailista",
+ "srf_paramdesc_minsize": "Ang sukat ng pinaka maliit na mga tatak na nasa bahagdan",
+ "srf_paramdesc_maxsize": "Ang sukat ng pinaka malaking mga tatak na nasa bahagdan",
+ "srf_paramdesc_maxtags": "Ang pinaka mataas na dami ng mga tatak na nasa loob ng ulap",
+ "srf-paramdesc-excludetags": "Huwag isali ang mga tatak (panghangga: ;)",
+ "srf_printername_valuerank": "Ranggo ng halaga",
+ "srf_printername_array": "Hanay",
+ "srf_paramdesc_pagetitle": "Kung ipapakita ba ang mga pamagat ng pahina bilang resultang mga lahok o huwag isali ang mga ito",
+ "srf_paramdesc_hidegaps": "Kung ililimbag ba ang hiniling ngunit hindi makukuhang kaarian at mga halaga ng pagtatala na pinaghihiwalay-hiwalay ng mga panghiwalay o hindi pagsasali ng mga ito",
+ "srf_paramdesc_arrayname": "Kapag ibinigay at kung makukuha ang Dugtong ng Hanay, lilikha ito ng isang hanay na mayroong tinukoy na pangalan (wala pang makikitang kinalabasan noon)",
+ "srf_paramdesc_propsep": "Panghiwalay sa pagitan ng hiniling na mga kaarian",
+ "srf_paramdesc_manysep": "Panghiwalay sa pagitan ng maraming pinahahalagahang mga halaga ng ari-arian",
+ "srf_paramdesc_recordsep": "Panghiwalay sa pagitan ng mga halaga ng mga pag-aari ng katalaan",
+ "srf_paramdesc_headersep": "Panghiwalay sa pagitan ng pangalan ng kaarian at halaga kapag ang \"headers\" ay nakatakda sa \"show\" o \"plain\"",
+ "srf_printername_hash": "Muling paghahayag",
+ "srf_paramdesc_hashname": "Kapag ibinigay at kung makukuha ang Talahanayan ng Kahaluan, lilikha ito ng isang kahaluan na mayroong tinukoy na pangalan (wala pang makikitang kinalabasan noon)",
+ "srf-printername-graph": "Talangguhit",
+ "srf-paramdesc-graph-relation": "Mga magulang ba o mga anak ang mga paksa o mga kaarian ng pangalan?",
+ "srf-paramdesc-graph-nameprop": "Nagpapahintulot ng pagtatakda ng isang pag-aari na gagamitin bilang paksa sa halip na ang talagang paksa",
+ "srf-paramdesc-graph-nodeshape": "Ang hugis ng bawat buko sa ibabaw ng talangguhit",
+ "srf-paramdesc-graphname": "Pamagat",
+ "srf-paramdesc-graphsize": "Sukat ng talangguhit (nasa px)",
+ "srf-paramdesc-graphlegend": "Ipakita ang alamat ng talangguhit o hindi",
+ "srf-paramdesc-graphlabel": "Tatak ng talangguhit",
+ "srf-paramdesc-rankdir": "Patutunguhan ng palaso",
+ "srf-paramdesc-graphlink": "Kawing ng talangguhit",
+ "srf-paramdesc-graphcolor": "Kulay ng talangguhit",
+ "srf-paramdesc-graph-wwl": "Hangganan ng balot ng salita (sa loob ng # mga panitik)",
+ "srf-paramdesc-showroles": "Ipinakikita ang mga sumusunod na lathala ( ..in graph )",
+ "srf-paramdesc-showresources": "Ipinakikita ang mga sumusunod na lathala ( ..in graph )",
+ "srf-printername-datatables": "Mga Talahanayan ng Dato",
+ "srf-printername-tree": "Puno",
+ "srf-printername-ultree": "Puno na ang listahan ay walang pagkakasunud-sunod",
+ "srf-printername-oltree": "Puno na ang listahan ay may pagkakasunud-sunod",
+ "srf-tree-noparentprop": "Walang ibinigay na magulang na kaarian. Ang puno ay hindi maaaring buuin na wala ang isang tinukoy na magulang na kaarian.",
+ "srf-paramdesc-tree-parent": "Ang pag-aari na naglalaman ng magulang na pahina",
+ "srf-printername-slideshow": "Palabas na Dumudulas",
+ "srf-paramdesc-delay": "Ang pag-antala sa pagitan ng mga padulas na nasa mga segundo",
+ "srf-paramdesc-navigation-controls": "Ipakita o huwag ipakita ang mga pantaban ng paglilibot",
+ "srf-paramdesc-effect": "Ang epektong gagamitin upang magpalipat-lipat mula sa bawat isang padulas",
+ "srf-printername-filtered": "Nasala na",
+ "srf-printername-d3chart": "Talangguhit ng D3",
+ "srf-printername-timeseries": "Talangguhit ng pagkakasunud-sunod ng panahon",
+ "srf-paramdesc-group": "Pinagpangkat-pangkat ang mga serye ayon sa",
+ "srf-paramdesc-zoom": "Paganahin ang paglapit na nakatutok",
+ "srf-paramdesc-datatable": "Paganahin ang isang talahanayan ng dato",
+ "srf-timeseries-zoom-out-of-range": "Ang saklaw ng paglapit na nakatutok ay hindi nakagawa ng anumang sapat na dato",
+ "srf-printername-sparkline": "Mga guhit ng pagkisap",
+ "srf-printername-listwidget": "Widyet ng lista",
+ "srf-paramdesc-listtype": "Tukuyin ang uri ng tala",
+ "srf-paramdesc-widget": "Makukuhang widyet",
+ "srf-paramdesc-pageitems": "Mga bagay sa bawat pahina",
+ "srf-printername-eventcalendar": "Kalendaryo ng pangyayari",
+ "srf-paramdesc-calendarfirstday": "Ang araw na pinagsisimulan ng bawat isang linggo",
+ "srf-paramdesc-calendardefaultview": "Ang paunang pagpapatanaw kapag kumarga na ang kalendaryo",
+ "srf-paramdesc-dayview": "Paganahin ang pagpapatanaw ng araw sa pamamagitan ng paglagitik sa bilang ng araw",
+ "srf-paramdesc-icalendar-timezone": "Kuwit para maihiwalay ang Listahan ng mga 'timezones'"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tr.json b/www/wiki/extensions/SemanticResultFormats/i18n/tr.json
new file mode 100644
index 00000000..d3e2bbfb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tr.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joseph",
+ "Karduelis",
+ "Vito Genovese",
+ "Sayginer"
+ ]
+ },
+ "srf-name": "Anlamsal Sonuç Bilimleri",
+ "srf-module-loading": "Yükleniyor...",
+ "srfc_previousmonth": "Önceki ay",
+ "srfc_nextmonth": "Sonraki ay",
+ "srfc_today": "Bugün",
+ "srfc_gotomonth": "Aya git",
+ "srf_printername_calendar": "Aylık takvim",
+ "srf_printername_vcard": "vCard dışa aktarımı",
+ "srf_printername_icalendar": "iCalendar dışa aktarımı",
+ "srf_paramdesc_icalendartitle": "Takvim dosyasının başlığı",
+ "srf_paramdesc_icalendardescription": "Takvim dosyasının tanımı",
+ "srf_outline_novalue": "DeÄŸer yok",
+ "srf_printername_sum": "Sayıların toplamı",
+ "srf_printername_average": "Sayılan ortalaması",
+ "srf_printername_max": "Azami sayı",
+ "srf_printername_min": "Asgari sayı",
+ "srf_paramdesc_limit": "Sorgulanacak azami sayfa sayısı",
+ "srf_printername_timeline": "Zaman çizgisi",
+ "srf_paramdesc_views": "Görüntülenecek görünümler",
+ "srf_printername_googlebar": "Google çubuk çizelgesi",
+ "srf_printername_googlepie": "Google dilim çizelgesi",
+ "srf-ui-datatables-label-sLoadingRecords": "Yükleniyor...",
+ "srf-ui-datatables-label-sProcessing": "Ä°ÅŸleniyor..."
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tt-cyrl.json b/www/wiki/extensions/SemanticResultFormats/i18n/tt-cyrl.json
new file mode 100644
index 00000000..99323f9e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tt-cyrl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ilnur efende"
+ ]
+ },
+ "srfc_today": "Бүген"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tyv.json b/www/wiki/extensions/SemanticResultFormats/i18n/tyv.json
new file mode 100644
index 00000000..f9671960
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tyv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Agilight"
+ ]
+ },
+ "srf-ui-gridview-label-item": "Данныйлар Ñлементизи"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/tzm.json b/www/wiki/extensions/SemanticResultFormats/i18n/tzm.json
new file mode 100644
index 00000000..151283f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/tzm.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tifinaghes"
+ ]
+ },
+ "srf-filtered-selectorlabel-list": "ⵓⵎⵓⵖ"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/uk.json b/www/wiki/extensions/SemanticResultFormats/i18n/uk.json
new file mode 100644
index 00000000..81cfd67b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/uk.json
@@ -0,0 +1,338 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base",
+ "Steve.rusyn",
+ "SteveR",
+ "Ðта",
+ "NataChe",
+ "Piramidion",
+ "Bunyk",
+ "Nemo bis",
+ "Vlad5250"
+ ]
+ },
+ "srf-desc": "Додаткові формати результатів Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð² Semantic MediaWiki",
+ "prefs-srf": "Формати Ñемантичних результатів",
+ "srf-prefs-intro-text": "Ви вÑтановили Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Semantic Result Formats. Відвідайте, будь лаÑка, [http://www.semantic-mediawiki.org/wiki/Help:Result_formats довідкову Ñторінку форматів результатів] Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¸ відноÑно налаштувань кориÑтувача.",
+ "prefs-srf-eventcalendar-options": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ð¾Ð´Ñ–Ð¹",
+ "srf-prefs-eventcalendar-options-update-default": "Увімкнути [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматичні оновленнÑ] ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ð¾Ð´Ñ–Ð¹ під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñторінки",
+ "srf-prefs-eventcalendar-options-paneview-default": "Увімкнути за замовчуваннÑм виглÑд клітинками",
+ "prefs-srf-datatables-options": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DataTables",
+ "srf-prefs-datatables-options-update-default": "Увімкнути [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates автоматичні оновленнÑ] вміÑту таблиці під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñторінки",
+ "srf-prefs-datatables-options-cache-default": "Увімкнути [https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage локальне збереженнÑ] Ð´Ð»Ñ Ð¿Ð¾ÐºÑ€Ð°Ñ‰ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу відповіді",
+ "srf-module-loading": "ЗавантаженнÑ…",
+ "srf-paramdesc-layout": "ДоÑтупний макет",
+ "srf-paramdesc-height": "ВиÑота",
+ "srf-paramdesc-width": "Ширина",
+ "srf-paramdesc-class": "Вказати додатковий ÐºÐ»Ð°Ñ CSS",
+ "srf-module-nomatch": "Ðе знайдено збігів",
+ "srf-paramdesc-charttype": "ДоÑтупні типи діаграм",
+ "srf-navigation-previous": "Попередній",
+ "srf-ui-navigation-prev": "Попер.",
+ "srf-ui-navigation-next": "ÐаÑтупний",
+ "srf-ui-common-label-source": "Джерело",
+ "srf-ui-common-label-datasource": "Джерело даних",
+ "srf-ui-common-label-ajax-error": "Сервер повідомив про невдалий зв'Ñзок з $1. Будь лаÑка, Ñпробуйте оновити Ñторінку або звернітьÑÑ Ð· цим до $2.",
+ "srf-ui-common-label-request-object": "об'єкт запиту",
+ "srf-ui-common-label-help-section": "розділ довідки",
+ "srf-ui-tooltip-title-options": "Опції",
+ "srf-ui-tooltip-title-scope": "Сфера",
+ "srf-ui-tooltip-title-legend": "Легенда",
+ "srf-ui-tooltip-title-filter": "Фільтр",
+ "srf-ui-common-label-refresh": "Оновити",
+ "srf-ui-common-label-parameters": "Параметри",
+ "srf-ui-common-label-query": "Запит",
+ "srf-ui-common-label-paneview": "ВиглÑд панелі",
+ "srf-ui-common-label-daterange": "Діапазон дати",
+ "srf-ui-widgets-label-parameter-limit": "Параметр ліміту",
+ "srf-error-option-mix": "ÐžÐ¿Ñ†Ñ–Ñ ($1) не доÑтупна",
+ "srf-error-option-link-all": "ÐžÐ¿Ñ†Ñ–Ñ ($1) вимагає, щоб параметр «link» було вÑтановлено Ñк «all»",
+ "srf-error-missing-layout": "Діаграма або графік не можуть бути показані, оÑкільки відÑутній макет.",
+ "srf-error-jqplot-bubble-data-length": "Діаграма або графік не можуть бути показані, оÑкільки відÑутні дані.",
+ "srf-error-jqplot-stackseries-data-length": "Діаграма або графік не можуть бути показані, оÑкільки не кожен Ñтовпчик або Ð»Ñ–Ð½Ñ–Ñ Ð¼Ð°Ñ” однакову кількіÑÑ‚ÑŒ елементів.",
+ "srf-warn-empy-chart": "Діаграма або графік пуÑÑ‚Ñ– через неÑтачу даних",
+ "srf-paramdesc-color": "Колір Ð´Ð»Ñ Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів у календарі",
+ "srfc_previousmonth": "Попередній міÑÑць",
+ "srfc_nextmonth": "ÐаÑтупний міÑÑць",
+ "srfc_today": "Сьогодні",
+ "srfc_gotomonth": "Перейти до міÑÑцÑ",
+ "srf_printername_calendar": "МіÑÑчний календар",
+ "srf_paramdesc_calendarlang": "Код мови, Ñкою показувати календар",
+ "srf_paramdesc_calendarcolors": "Колір, Ñким показувати кожну влаÑтивіÑÑ‚ÑŒ дати (наприклад: «Start date=>green,End date=>#09c»)",
+ "srf-paramdesc-calendar-startmonth": "МіÑÑць, Ñким календар починає відображатиÑÑŒ (за замовчуваннÑм, поточний міÑÑць)",
+ "srf-paramdesc-calendar-startyear": "Рік, Ñким календар починає відображатиÑÑŒ (за замовчуваннÑм, поточний рік)",
+ "srf_printername_vcard": "ЕкÑпорт vCard",
+ "srf_printername_icalendar": "ЕкÑпорт iCalendar",
+ "srf_paramdesc_icalendartitle": "Ðазва фалу календарÑ",
+ "srf_paramdesc_icalendardescription": "ÐžÐ¿Ð¸Ñ Ñ„Ð°Ð¹Ð»Ñƒ календарÑ",
+ "srf_printername_bibtex": "ЕкÑпорт BibTeX",
+ "srf_outline_novalue": "Ðемає значеннÑ",
+ "srf_printername_outline": "ЕÑкіз",
+ "srf_paramdesc_outlineproperties": "СпиÑок влаÑтивоÑтей, що буде показано Ñк заголовки еÑкізу, розділених комами",
+ "srf_printername_sum": "Сума чиÑел",
+ "srf_printername_average": "Середнє арифметичне чиÑел",
+ "srf_printername_max": "МакÑимальне чиÑло",
+ "srf_printername_min": "Мінімальне чиÑло",
+ "srf_paramdesc_limit": "МакÑимальне чиÑло Ñторінок Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ",
+ "srf_printername_product": "Добуток чиÑел",
+ "srf_printername_median": "Медіана чиÑел",
+ "srf-paramdesc-default": "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° змовчуваннÑм, Ñке буде показано, Ñкщо немає чиÑлових результатів",
+ "srf_printername_earliest": "Ðайранніший чаÑ",
+ "srf_printername_latest": "Ðайпізніший чаÑ",
+ "srf_printername_timeline": "ХронологіÑ",
+ "srf_printername_eventline": "СпиÑок подій",
+ "srf_paramdesc_timelinebands": "Визначає, Ñкі діапазони буде показано у результаті.",
+ "srf_paramdesc_timelineposition": "Визначає, Ñке міÑце чаÑової шкали буде показано початково.",
+ "srf_paramdesc_timelinestart": "Ðазва влаÑтивоÑÑ‚Ñ–, що викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÑˆÐ¾Ñ— чаÑової точки",
+ "srf_paramdesc_timelineend": "Ðазва влаÑтивоÑÑ‚Ñ–, що викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ñ€ÑƒÐ³Ð¾Ñ— чаÑової точки",
+ "srf_paramdesc_timelinesize": "ВиÑота чаÑової шкали",
+ "srf-timeline-allresults": "Подальші результати Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ запиту.",
+ "srf-timeline-nojs": "Вам Ñлід увімкнути JavaScript Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб бачити інтерактивну чаÑову шкалу.",
+ "srf_paramdesc_views": "ВиглÑди Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ",
+ "srf_paramdesc_facets": "Ðабір влаÑтивоÑтей, що показуєтьÑÑ Ð½Ð° кожній Ñторінці",
+ "srf_paramdesc_lens": "Ðазва шаблону Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð»Ð°ÑтивоÑтей Ñторінки",
+ "srf_printername_googlebar": "ГіÑтограма Google",
+ "srf_printername_googlepie": "Секторна діаграма Google",
+ "srf-printername-jqplotchart": "діаграма jqPlot",
+ "srf-printername-jqplotseries": "ÑÐµÑ€Ñ–Ñ jqPlot",
+ "srf_paramdesc_chartheight": "Вкажіть виÑоту (у пікÑелÑÑ…) діаграми або графіка",
+ "srf_paramdesc_chartwidth": "Вкажіть ширину (у пікÑелÑÑ… чи відÑотках) діаграми або графіка",
+ "srf_paramdesc_charttitle": "Ðазва діаграми",
+ "srf_paramdesc_barcolor": "Укажіть колір діаграми",
+ "srf_paramdesc_bardirection": "Укажіть напрÑмок діаграми",
+ "srf-paramdesc-direction": "Укажіть напрÑмок діаграми або графіка",
+ "srf_paramdesc_barnumbersaxislabel": "Позначка Ð´Ð»Ñ Ñ‡Ð¸Ñлової оÑÑ–",
+ "srf-paramdesc-labelaxislabel": "Позначка Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ–Ð»Ð¾Ðº оÑÑ–",
+ "srf-paramdesc-ticklabels": "Увімкнути Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ поділок.",
+ "srf-paramdesc-minvalue": "Мінімальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° оÑÑ– Y",
+ "srf-paramdesc-pointlabels": "Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡Ð¾Ðº даних у діаграмі",
+ "srf-paramdesc-chartlegend": "Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð»ÐµÐ³ÐµÐ½Ð´Ð¸ діаграми",
+ "srf-paramdesc-datalabels": "ПідпиÑи даних діаграми/графіка",
+ "srf-paramdesc-charttext": "ТекÑÑ‚ опиÑу діаграми",
+ "srf-paramdesc-chartclass": "Додатковий CSS-клаÑ",
+ "srf-paramdesc-renderer": "Виберіть візуалізацію графіка/діаграми",
+ "srf-paramdesc-filling": "Індивідуальна Ð¾Ð¿Ñ†Ñ–Ñ Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ",
+ "srf-paramdesc-theme": "Виберіть тему Ñітки",
+ "srf-paramdesc-chartcolor": "Призначити окремі кольори діаграми",
+ "srf-paramdesc-colorscheme": "Виберіть Ñхему кольорів",
+ "srf-paramdesc-valueformat": "Вкажіть правило Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ",
+ "srf-paramdesc-highlighter": "Відобразити Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡Ð¾Ðº даних",
+ "srf-paramdesc-smoothlines": "ЗаÑтоÑувати алгоритм Ð·Ð³Ð»Ð°Ð´Ð¶ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð»Ñ–Ð½Ñ–Ð¹Ð½Ð¸Ñ… діаграм",
+ "srf-paramdesc-stackseries": "Відобразити діаграми у виглÑді Ñкладеної Ñерії",
+ "srf-paramdesc-seriesgroup": "Оберіть Ð³Ñ€ÑƒÐ¿ÑƒÐ²Ð°Ð½Ð½Ñ Ñерії",
+ "srf-paramdesc-serieslabel": "Визначте Ñрлик Ñерії",
+ "srf-paramdesc-grouplabel": "Визначте Ñрлик групи",
+ "srf-paramdesc-chartcursor": "Параметр Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾ÐºÐ°Ð¶Ñ‡Ð¸ÐºÐ° діаграми",
+ "srf-paramdesc-trendline": "Увімкнути одночаÑне Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ñ–Ð°Ð³Ñ€Ð°Ð¼Ð¸ та Ñ—Ñ— лінії тренду",
+ "srf-paramdesc-gridview": "Відобразити діаграму та набори даних одночаÑно. ДопуÑтимі значеннÑ: «none» Ñ– «tabs». За замовчуваннÑм: «none»",
+ "srf-paramdesc-paneview": "Вказати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– з невеликим лінійним графіком. Дозволені значеннÑ: \"bottom\", \"top\" Ñ– \"none\". За замовчуваннÑм: \"bottom\"",
+ "srf-paramdesc-infotext": "Відображати додаткові відомоÑÑ‚Ñ– на відповідній інформаційній вкладці",
+ "srf-paramdesc-clicktarget": "При клацанні на дату в календарі визначає Ñторінку чи Ñ€Ñдок запиту Ñк ціль.",
+ "srf-ui-gridview-label-item": "Елемент даних",
+ "srf-ui-gridview-label-value": "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…",
+ "srf-ui-gridview-label-series": "Ð¡ÐµÑ€Ñ–Ñ Ð´Ð°Ð½Ð¸Ñ…",
+ "srf-ui-gridview-label-chart-tab": "Графік",
+ "srf-ui-gridview-label-data-tab": "Дані",
+ "srf-ui-gridview-label-info-tab": "ІнформаціÑ",
+ "srf_printername_gallery": "ГалереÑ",
+ "srf_paramdesc_perrow": "КількіÑÑ‚ÑŒ зображень у Ñ€Ñдку",
+ "srf_paramdesc_widths": "Ширина зображень",
+ "srf_paramdesc_heights": "ВиÑота зображень",
+ "srf_paramdesc_autocaptions": "ВикориÑтовувати назву файлу в ÑкоÑÑ‚Ñ– заголовку, Ñкщо його не вказано",
+ "srf_paramdesc_fileextensions": "При викориÑтанні імені файлу в ÑкоÑÑ‚Ñ– заголовка, відображати також Ñ– Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ",
+ "srf_paramdesc_captionproperty": "Ðазва Ñемантичної влаÑтивоÑÑ‚Ñ–, наÑвна на запинатих Ñторінках, Ñку буде викориÑтано Ñк опиÑ",
+ "srf_paramdesc_imageproperty": "Ðазва Ñемантичної влаÑтивоÑÑ‚Ñ– на запитаних Ñторінках, Ñка вказує на зображеннÑ, Ñкі треба викориÑтати. Якщо вказана, Ñамі запитані Ñторінки не відображатимутьÑÑ Ñк зображеннÑ",
+ "srf-paramdesc-redirects": "Ðазва Ñемантичної влаÑтивоÑÑ‚Ñ–, наÑвна на запитаних Ñторінках, Ñка міÑтить ціль перенаправленнÑ",
+ "srf-paramdesc-navigation": "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ”ÑŽ макету",
+ "srf-paramdesc-overlay": "Дозволити Ð½Ð°ÐºÐ»Ð°Ð´Ð°Ð½Ð½Ñ Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ",
+ "srf-gallery-navigation-previous": "Попередній",
+ "srf-gallery-navigation-next": "ÐаÑтупний",
+ "srf-gallery-overlay-count": "Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ $1 з $2",
+ "srf-gallery-image-url-error": "Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ðµ знайдено.",
+ "srf_printername_tagcloud": "Хмаринка теґів",
+ "srf_paramdesc_includesubject": "Мають бути включені назви влаÑне Ñуб'єктів",
+ "srf_paramdesc_increase": "Як збільшити розмір теґів",
+ "srf_paramdesc_tagorder": "ПорÑдок тегів",
+ "srf_paramdesc_mincount": "Мінімальна кількіÑÑ‚ÑŒ разів поÑви значеннÑ, піÑÐ»Ñ Ñких воно потраплÑÑ” в ÑпиÑок",
+ "srf_paramdesc_minsize": "Розмір найменших теґів у відÑотках",
+ "srf_paramdesc_maxsize": "Розмір найбільших теґів у відÑотках",
+ "srf_paramdesc_maxtags": "МакÑимальна кількіÑÑ‚ÑŒ теґів у хмарці",
+ "srf-paramdesc-excludetags": "Виключити теги (розділювач: \";\")",
+ "srf_printername_valuerank": "Оцінити ранг",
+ "srf_printername_array": "МаÑив",
+ "srf_paramdesc_pagetitle": "Чи Ñлід відображати заголовки Ñторінок Ñк результуючі запиÑи або пропуÑкати Ñ—Ñ…",
+ "srf_paramdesc_hidegaps": "Чи друкувати запитану, але недоÑтупну влаÑтивіÑÑŒ Ñ– Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів, розділених розділювачами, чи пропуÑкати Ñ—Ñ…",
+ "srf_paramdesc_arrayname": "Якщо подано Ñ– ArrayExtension доÑтупне, то це Ñтворюватиме маÑив з вказаною назвою (жодного видимого виходу)",
+ "srf_paramdesc_propsep": "Розділювач між запитаними влаÑтивоÑÑ‚Ñми",
+ "srf_paramdesc_manysep": "Розділювач між багатьма оціненими значеннÑми влаÑтивоÑтей",
+ "srf_paramdesc_recordsep": "Розділювач між значеннÑми влаÑтивоÑтей запиÑів",
+ "srf_paramdesc_headersep": "Розділювач між назвою влаÑтивоÑÑ‚Ñ– та значеннÑм, Ñкщо \"headers\" вÑтановлено Ñк \"show\" або \"plain\"",
+ "srf_printername_hash": "Хеш",
+ "srf_paramdesc_hashname": "Якщо вкажане, Ñ– доÑтупне Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ HashTables, це Ñтворить хеш з поданою назвою (жодного видимого виходу)",
+ "srf-printername-graph": "Графік",
+ "srf-paramdesc-graph-relation": "Визначає, чи предмети або влаÑтивоÑÑ‚Ñ– назв Ñ” батьківÑькими чи дочірніми.",
+ "srf-paramdesc-graph-nameprop": "Ð’Ñтановлює влаÑтивіÑÑ‚ÑŒ, що буде викориÑтана Ñк предмет заміÑÑ‚ÑŒ наÑвного предмета, тобто назви Ñторінки",
+ "srf-paramdesc-graph-nodeshape": "Ð’Ñтановлює форму кожного вузла графу",
+ "srf-paramdesc-graphname": "Ð’Ñтановлює назву графу",
+ "srf-paramdesc-graphsize": "Ð’Ñтановлює розмір графу в пікÑелÑÑ…",
+ "srf-paramdesc-graphlegend": "Ð’Ñтановлює, чи Ñлід показувати легенду графу, чи ні",
+ "srf-paramdesc-graphlabel": "Ð’Ñтановлює Ð¿Ñ–Ð´Ð¿Ð¸Ñ Ð³Ñ€Ð°Ñ„Ñƒ",
+ "srf-paramdesc-rankdir": "Ð’Ñтановлює напрÑмок Ñтрілок",
+ "srf-paramdesc-graphlink": "Ð’Ñтановлює, чи вузли повинні поÑилатиÑÑ Ð½Ð° їхні Ñторінки у вікі",
+ "srf-paramdesc-graphcolor": "Задає колір графу",
+ "srf-paramdesc-graph-wwl": "Ð’Ñтановлює межу переноÑу Ñлів (у формі чиÑла Ñимволів)",
+ "srf-paramdesc-clustercolor": "Ð’Ñтановлює кольори клаÑтерних блоків",
+ "srf-paramdesc-highlight": "Ð’Ñтановлює Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ð°",
+ "srf-paramdesc-highlightcolor": "Ð’Ñтановлює колір текÑту Ð´Ð»Ñ Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð¾Ð³Ð¾ вузла",
+ "srf-paramdesc-redlinkcolor": "Ð’Ñтановлює колір текÑту Ð´Ð»Ñ Ñ‡ÐµÑ€Ð²Ð¾Ð½Ð¸Ñ… поÑилань",
+ "srf-paramdesc-processcategory": "Ð’Ñтановлює вікікатегорію, в Ñкій зберігаютьÑÑ ÐºÑ€Ð¾ÐºÐ¸ процеÑу",
+ "srf-paramdesc-showroles": "Показує відповідні ролі в графі",
+ "srf-paramdesc-showstatus": "Ð’Ñтановлює, чи Ñлід оброблÑти ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÑ€Ð¾ÐºÑƒ процеÑу",
+ "srf-paramdesc-showresources": "Показує відповідні реÑурÑи у графі",
+ "srf-paramdesc-showdiscussion": "Ð’Ñтановлює, чи Ñлід оброблÑти обговореннÑ",
+ "srf-paramdesc-showredlinks": "Ð’Ñтановлює, чи Ñлід позначити й виділити червоні поÑиланнÑ",
+ "srf-paramdesc-showcompound": "Ð’Ñтановлює, чи Ñлід виділÑти Ñкладні вузли, тобто підпроцеÑи",
+ "srf-paramdesc-debug": "Ð’Ñтановлює, чи код графу процеÑу Ñлід показати, взÑтим у теги «pre»",
+ "srf-paramdesc-graphvalidation": "Показує кроки процеÑу, Ñкі не мають призначеної ролі, виділеними червоним кольором",
+ "srf-printername-datatables": "Таблиці даних",
+ "srf-ui-datatables-label-conditions": "Умови",
+ "srf-ui-datatables-label-parameters": "Параметри",
+ "srf-ui-datatables-label-filters": "Фільтри Ñтовпців Ñ– пошук",
+ "srf-ui-datatables-label-information": "ІнформаціÑ",
+ "srf-ui-datatables-panel-disclaimer": "Параметри та умови можуть бути змінені, але будь-Ñка зміна тимчаÑова Ñ– ÑкидаєтьÑÑ Ð¿Ñ–ÑÐ»Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñторінки.",
+ "srf-ui-datatables-label-update-success": "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– пройшло уÑпішно",
+ "srf-ui-datatables-label-update-error": "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ таблицю.",
+ "srf-ui-datatables-label-placeholder-column-search": "Пошук…",
+ "srf-ui-datatables-label-content-cache": "ЗміÑÑ‚ отримано з локального кеша.",
+ "srf-ui-datatables-label-content-server": "ЗміÑÑ‚ було отримано з Ñервера.",
+ "srf-ui-datatables-label-multiselect-column-header": "ДоÑтупні колонки",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ð°",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "Стовпці відображаютьÑÑ",
+ "srf-ui-datatables-label-sEmptyTable": "Ðемає даних у таблиці",
+ "srf-ui-datatables-label-sInfo": "Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів від _START_ по _END_ з _TOTAL_",
+ "srf-ui-datatables-label-sInfoEmpty": "Показані від 0 до 0 з 0 запиÑів",
+ "srf-ui-datatables-label-sInfoFiltered": "(відфільтровано з уÑього _MAX_ запиÑів)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "Показати _MENU_ запиÑів",
+ "srf-ui-datatables-label-sLoadingRecords": "ЗавантаженнÑ…",
+ "srf-ui-datatables-label-sProcessing": "Обробка…",
+ "srf-ui-datatables-label-sSearch": "Пошук:",
+ "srf-ui-datatables-label-sZeroRecords": "Ðічого не знайдено відповідно до критеріїв пошуку",
+ "srf-ui-datatables-label-oPaginate-sFirst": "Перше",
+ "srf-ui-datatables-label-oPaginate-sLast": "ОÑтаннє",
+ "srf-ui-datatables-label-oPaginate-sNext": "ÐаÑтупне",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "Попереднє",
+ "srf-ui-datatables-label-oAria-sSortAscending": ": активувати ÑÐ¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñтовпців за зроÑтаннÑм",
+ "srf-ui-datatables-label-oAria-sSortDescending": ": активувати ÑÐ¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñтовпців за ÑпаданнÑм",
+ "srf-printername-tree": "Дерево",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "Ðе вказано батьківÑької влаÑтивоÑÑ‚Ñ–. Дерево не може бути побудоване без Ð²ÐºÐ°Ð·Ð°Ð½Ð½Ñ Ð±Ð°Ñ‚ÑŒÐºÑ–Ð²Ñької влаÑтивоÑÑ‚Ñ–.",
+ "srf-tree-rootinvalid": "«$1» не Ñ” коректною назвою Ñторінки.",
+ "srf-tree-circledetected": "ВиÑвлено коло при Ñпробі вÑтавити $1 у дерево.",
+ "srf-paramdesc-tree-parent": "ВлаÑтивіÑÑ‚ÑŒ, Ñка міÑтить батьківÑьку Ñторінку",
+ "srf-paramdesc-tree-root": "Коренева Ñторінка дерева",
+ "srf-paramdesc-tree-startlevel": "Початковий рівень дерева, напр., Ð´Ð»Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¹Ð¾Ð³Ð¾ в інше дерево",
+ "srf-printername-slideshow": "Слайд-шоу",
+ "srf-paramdesc-delay": "Затримка між Ñлайдами у Ñекундах",
+ "srf-paramdesc-navigation-controls": "Показувати елементи ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ”ÑŽ чи ні",
+ "srf-paramdesc-effect": "Ефект викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð²Ñ–Ð´ Ñлайда до Ñлайда",
+ "srf-printername-filtered": "Відфільтровано",
+ "srf-paramdesc-filtered-views": "ВиглÑд, Ñкий буде доÑтупний при виведенні результатів.",
+ "srf-paramdesc-filtered-filter-position": "ÐŸÐ¾Ð·Ð¸Ñ†Ñ–Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ñ–Ð² відноÑно переглÑдів. Дозволені значеннÑ: «угорі», «внизу». За замовчуваннÑм: «угорі».",
+ "srf-paramdesc-filtered-list-type": "Тип ÑпиÑку. ДопуÑтимі значеннÑ: «list», «ul», «ol». За замовчуваннÑм: «list».",
+ "srf-paramdesc-filtered-list-template": "Шаблон, за допомогою Ñкого форматуватимутьÑÑ ÐµÐ»ÐµÐ¼ÐµÐ½Ñ‚Ð¸ ÑпиÑку.",
+ "srf-paramdesc-filtered-list-named-args": "Ðазви аргументів, що передаютьÑÑ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñƒ.",
+ "srf-paramdesc-filtered-list-introtemplate": "Ðазва шаблону, Ñкий показувати перед результатами запиту, Ñкщо вони Ñ”.",
+ "srf-paramdesc-filtered-list-outrotemplate": "Ðазва шаблону, Ñкий показувати піÑÐ»Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ñ–Ð² запиту, Ñкщо вони Ñ”.",
+ "srf-paramdesc-filtered-calendar-start": "Роздруківка міÑтить дату початку події",
+ "srf-paramdesc-filtered-calendar-end": "Роздруківка міÑтить дату Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾Ð´Ñ–Ñ—",
+ "srf-paramdesc-filtered-calendar-title": "Роздруківка міÑтить назву події. Ðе може бути викориÑтано разом із шаблоном заголовка.",
+ "srf-paramdesc-filtered-calendar-title-template": "Шаблон, викориÑтаний Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ події у колендарі",
+ "srf-paramdesc-filtered-map-position": "Виведені дані, що міÑÑ‚ÑÑ‚ÑŒ географічну позицію.",
+ "srf-paramdesc-filtered-map-icon": "Вивід, що вирішує, Ñку іконку карти буде викориÑтано.",
+ "srf-paramdesc-filtered-map-icons": "Мапа значень Ð´Ð»Ñ Ñ–ÐºÐ¾Ð½Ð¾Ðº, що будуть викориÑтані Ð´Ð»Ñ Ñ†Ð¸Ñ… значень на мапі.",
+ "srf-paramdesc-filtered-map-height": "ВиÑота мапи.",
+ "srf-paramdesc-filtered-map-zoom": "Рівень маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸ завантаженні мапи. КориÑтувач може це змінити.<br>Див.: <i>map view min zoom</i> та <i>map view max zoom</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "Мінімальний рівень маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ð¿Ð¸, Ñкий можна вибрати",
+ "srf-paramdesc-filtered-map-max-zoom": "МакÑимальний рівень маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ð¿Ð¸, Ñкий можна вибрати",
+ "srf-paramdesc-filtered-map-marker-cluster": "Увімкнути чи вимкнути Ð³Ñ€ÑƒÐ¿ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ€ÐºÐµÑ€Ñ–Ð².",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "МакÑимальний рівень маÑштабуваннÑ, при Ñкому маркери на мапі вÑе ще групуютьÑÑ. При більшому рівні маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ€ÐºÐµÑ€Ð¸ більше не групуватимутьÑÑ.",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "МакÑимальний радіуÑ, Ñкий клаÑтер покриватиме, від центрального маркера (в пікÑелÑÑ…). Стандартно — 80.",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "Коли увімкнено, ÐºÐ»Ð°Ñ†Ð°Ð½Ð½Ñ Ð½Ð° клаÑтері збільшить мапу до меж цього клаÑтера.",
+ "srf-filtered-selectorlabel-list": "СпиÑок",
+ "srf-filtered-selectorlabel-table": "ТаблицÑ",
+ "srf-filtered-selectorlabel-calendar": "Календар",
+ "srf-filtered-selectorlabel-map": "Мапа",
+ "srf-filtered-noscript-error": "Результати неможливо відтворити, оÑкільки JavaScript не увімкнено. Перейдіть до $1.",
+ "srf-filtered-noscript-link-caption": "результати в табличній формі",
+ "srf-filtered-map-provider-missing-error": "Ðе вказано провайдера мапи Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду у форматі «мапа».",
+ "srf-filtered-value-filter-and": "ТÐ",
+ "srf-filtered-value-filter-or": "ÐБО",
+ "srf-filtered-value-filter-placeholder": "Виберіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ð°",
+ "srf-printername-d3chart": "D3-діаграма",
+ "srf-printername-timeseries": "Діаграма чаÑових Ñ€Ñдів",
+ "srf-paramdesc-group": "РÑди згруповані за",
+ "srf-paramdesc-zoom": "Увімкнути маÑштабуваннÑ",
+ "srf-paramdesc-datatable": "Увімкнути базу даних",
+ "srf-timeseries-zoom-out-of-range": "Діапазон Ð·Ð±Ñ–Ð»ÑŒÑˆÐµÐ½Ð½Ñ Ð½Ðµ видав доÑтатньо даних",
+ "srf-printername-sparkline": "Міні-діаграма",
+ "srf-printername-listwidget": "Віджет ÑпиÑку",
+ "srf-paramdesc-listtype": "Вкажіть тип ÑпиÑку",
+ "srf-paramdesc-widget": "ДоÑтупний віджет",
+ "srf-paramdesc-pageitems": "Елементів на Ñторінці",
+ "srf-printername-eventcalendar": "Календар подій",
+ "srf-paramdesc-calendarfirstday": "День, з Ñкого починаєтьÑÑ ÐºÐ¾Ð¶ÐµÐ½ тиждень",
+ "srf-paramdesc-calendardefaultview": "ВиглÑд при відкриванні календарÑ",
+ "srf-paramdesc-calendarstart": "ПервіÑний початок ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð°Ñ‚Ð¸ або дати Ñ– чаÑу)",
+ "srf-paramdesc-calendarlegend": "Вказує Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ Ð»ÐµÐ³ÐµÐ½Ð´Ð¸ та параметри призначеного фільтра",
+ "srf-paramdesc-dayview": "Увімкнути переглÑд Ð´Ð½Ñ Ð¿Ñ€Ð¸ натиÑканні на його номер",
+ "srf-ui-eventcalendar-label-today": "Сьогодні",
+ "srf-ui-eventcalendar-label-month": "МіÑÑць",
+ "srf-ui-eventcalendar-label-week": "Тиждень",
+ "srf-ui-eventcalendar-label-day": "День",
+ "srf-ui-eventcalendar-label-listmonth": "МіÑÑць (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listweek": "Тиждень (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-listday": "День (ÑпиÑок)",
+ "srf-ui-eventcalendar-label-allday": "ВеÑÑŒ день",
+ "srf-ui-eventcalendar-label-update-success": "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ð¾Ð´Ñ–Ð¹ було уÑпішним.",
+ "srf-ui-eventcalendar-label-update-error": "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ календар подій.",
+ "srf-ui-eventcalendar-click-popup": "Хочете Ñтворити подію?",
+ "srf-printername-dygraphs": "Диграфи",
+ "srf-paramdesc-datasource": "Джерело, з Ñкого доÑтупні дані. Дозволені значеннÑ: «file», «raw» та «url». За замовчуваннÑм: «file».",
+ "srf-paramdesc-errorbar": "Величина помилок, Ñка буде викориÑтовуватиÑÑ. ДопуÑтимі значеннÑ: \"fraction\" (довірчі інтервали Ð´Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ), \"sigma\" (Ñтандартне Ð²Ñ–Ð´Ñ…Ð¸Ð»ÐµÐ½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ) Ñ– \"range\" (діапазони значень)",
+ "srf-paramdesc-movingaverage": "Відобразити Ñереднє Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° певну кількіÑÑ‚ÑŒ днів (нуль означатиме відÑутніÑÑ‚ÑŒ рухомого Ñереднього)",
+ "srf-paramdesc-yaxislabel": "ОпиÑ, Ñкий відображаєтьÑÑ Ð½Ð° оÑÑ– Y",
+ "srf-paramdesc-xaxislabel": "ОпиÑ, Ñкий відображаєтьÑÑ Ð½Ð° оÑÑ– X",
+ "srf-paramdesc-unit": "ОдиницÑ",
+ "srf-printername-pagewidget": "Віджет Ñторінки",
+ "srf-printername-incoming": "Вхідні влаÑтивоÑÑ‚Ñ–",
+ "srf-paramdesc-count": "Ð’Ñтановлює, чи Ñлід порахувати кількіÑÑ‚ÑŒ вхідних влаÑтивоÑтей",
+ "srf-paramdesc-min": "Мінімальне або порогове значеннÑ",
+ "srf-paramdesc-excludeproperty": "Вилучити влаÑтивіÑÑ‚ÑŒ з набору результатів",
+ "srf-printername-media": "Мультимедійний програвач",
+ "srf-paramdesc-mediainspector": "Відображає детальну інформацію про зазначений медіаелемент",
+ "srf-ui-mediaplayer-label-previous": "Ðазад",
+ "srf-ui-mediaplayer-label-play": "Відтворити",
+ "srf-ui-mediaplayer-label-pause": "Пауза",
+ "srf-ui-mediaplayer-label-next": "Далі",
+ "srf-ui-mediaplayer-label-stop": "Зупинити",
+ "srf-ui-mediaplayer-label-mute": "Без звуку",
+ "srf-ui-mediaplayer-label-unmute": "Увімкнути звук",
+ "srf-ui-mediaplayer-label-volume-max": "МакÑимальна гучніÑÑ‚ÑŒ",
+ "srf-ui-mediaplayer-label-shuffle": "ПеремішуваннÑ",
+ "srf-ui-mediaplayer-label-shuffle-off": "ÐŸÐµÑ€ÐµÐ¼Ñ–ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ðµ",
+ "srf-ui-mediaplayer-label-repeat": "Повторити",
+ "srf-ui-mediaplayer-label-repeat-off": "Вимкнути повтореннÑ",
+ "srf-ui-mediaplayer-label-full-screen": "Повноекранний режим",
+ "srf-ui-mediaplayer-label-restore-screen": "Відновити екран",
+ "srf-spreadsheet-link": "Електронна таблицÑ",
+ "srf-paramdesc-spreadsheet-filename": "Ðазва файлу Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð³ÐµÐ½ÐµÑ€Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ файлу-таблиці",
+ "srf-paramdesc-spreadsheet-templatefile": "Ðазва електронної таблиці з проÑтору назв «Файл», Ñка викориÑтовуєтьÑÑ Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð³ÐµÐ½ÐµÑ€Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ файлу",
+ "srf-paramdesc-icalendar-timezone": "СпиÑок чаÑових поÑÑів через кому",
+ "srf-paramdesc-gantt-diagramtitle": "Ðазва діаграми",
+ "srf-paramdesc-gantt-diagramtheme": "Тема діаграми",
+ "srf-paramdesc-gantt-axisformat": "X-віÑÑŒ: Формат дати",
+ "srf-printername-gantt": "Òант"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/ur.json b/www/wiki/extensions/SemanticResultFormats/i18n/ur.json
new file mode 100644
index 00000000..b9d120c4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/ur.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කà·à·€à·’න්ද",
+ "عثمان خان شاÛ"
+ ]
+ },
+ "srf-module-loading": "لوڈ ÛÙˆ رÛا ÛÛ’...",
+ "srfc_previousmonth": "Ù¾Ú†Ú¾Ù„Û’ ماÛ",
+ "srfc_nextmonth": "اگلے ماÛ",
+ "srfc_today": "آج",
+ "srfc_gotomonth": "Ù…Ûینے پر جائیں",
+ "srf_printername_calendar": "ماÛØ§Ù†Û Ú©ÛŒÙ„Ù†ÚˆØ±",
+ "srf_paramdesc_autocaptions": "مل٠نام Ú©Ùˆ بطور کیپشن استعمال کریں جب Ú©Ú†Ú¾ Ù†Ûیں دیا گیا ÛÙˆ",
+ "srf-gallery-navigation-previous": "Ù¾Ú†Ú¾Ù„Û’",
+ "srf-gallery-navigation-next": "اگلے",
+ "srf_paramdesc_graphname": "عنوان"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/uz.json b/www/wiki/extensions/SemanticResultFormats/i18n/uz.json
new file mode 100644
index 00000000..22fe0227
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/uz.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "CoderSI"
+ ]
+ },
+ "srf-ui-gridview-label-info-tab": "Ma'lumot"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/vec.json b/www/wiki/extensions/SemanticResultFormats/i18n/vec.json
new file mode 100644
index 00000000..089489cf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/vec.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Candalua"
+ ]
+ },
+ "srfc_previousmonth": "Mese preçedente",
+ "srfc_nextmonth": "Mese sucessivo",
+ "srfc_today": "Ancuó",
+ "srfc_gotomonth": "Và al mese"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/vep.json b/www/wiki/extensions/SemanticResultFormats/i18n/vep.json
new file mode 100644
index 00000000..2d5b0e59
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/vep.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Игорь БродÑкий"
+ ]
+ },
+ "srfc_previousmonth": "Edeline ku",
+ "srfc_nextmonth": "Jäl'ghine ku",
+ "srfc_today": "Tämbei",
+ "srfc_gotomonth": "Mända kunnoks"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/vi.json b/www/wiki/extensions/SemanticResultFormats/i18n/vi.json
new file mode 100644
index 00000000..0d40733c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/vi.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "Vinhtantran",
+ "පසිඳු කà·à·€à·’න්ද"
+ ]
+ },
+ "srf-desc": "Các định dạng bổ sung cho các câu truy vấn trong dòng lệnh của MediaWiki Ngữ nghĩa",
+ "srf-name": "Äịnh dạng Kết quả Ngữ nghÄ©a",
+ "srf-module-loading": "Äang tải…",
+ "srfc_previousmonth": "Tháng trước",
+ "srfc_nextmonth": "Tháng sau",
+ "srfc_today": "Hôm nay",
+ "srfc_gotomonth": "Äến tháng",
+ "srf_printername_calendar": "Lịch tháng",
+ "srf_printername_vcard": "Xuất vCard",
+ "srf_printername_icalendar": "Xuất iCalendar",
+ "srf_printername_bibtex": "Xuất BibTeX",
+ "srf_outline_novalue": "Vô giá trị",
+ "srf_printername_outline": "Khái quát",
+ "srf_printername_sum": "Tổng số",
+ "srf_printername_average": "Trung bình số",
+ "srf_printername_max": "Số lớn nhất",
+ "srf_printername_min": "Số nhỠnhất",
+ "srf_printername_timeline": "Thá»i gian biểu",
+ "srf_printername_eventline": "Sự kiện biểu",
+ "srf-gallery-navigation-previous": "TrÆ°á»›c",
+ "srf-gallery-navigation-next": "Tiếp theo",
+ "srf_paramdesc_graphname": "Tá»±a Ä‘á»"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/vo.json b/www/wiki/extensions/SemanticResultFormats/i18n/vo.json
new file mode 100644
index 00000000..9ba7adcf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/vo.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya",
+ "Smeira"
+ ]
+ },
+ "srfc_previousmonth": "Mul büik",
+ "srfc_nextmonth": "Mul sököl",
+ "srfc_today": "Adelo",
+ "srfc_gotomonth": "Lü mul"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/wa.json b/www/wiki/extensions/SemanticResultFormats/i18n/wa.json
new file mode 100644
index 00000000..97c66405
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/wa.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Srtxg"
+ ]
+ },
+ "srf-ui-tooltip-title-legend": "Ledjinde",
+ "srf-ui-common-label-refresh": "Rafrister"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/yi.json b/www/wiki/extensions/SemanticResultFormats/i18n/yi.json
new file mode 100644
index 00000000..73a946dc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/yi.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "srfc_previousmonth": "פֿ×ריגער חודש",
+ "srfc_nextmonth": "נעקסטער חודש",
+ "srfc_today": "הײַנט",
+ "srf_paramdesc_graphname": "טיטל"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/zh-hans.json b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hans.json
new file mode 100644
index 00000000..a42c8721
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hans.json
@@ -0,0 +1,340 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gzdavidwong",
+ "Liangent",
+ "Linforest",
+ "Shirayuki",
+ "Liuxinyu970226",
+ "乌拉跨氪",
+ "Hudafu",
+ "Fengchao",
+ "Yfdyh000",
+ "Nemo bis",
+ "科劳",
+ "Looong"
+ ]
+ },
+ "srf-desc": "用于Semantic MediaWiki的附加结果格å¼",
+ "prefs-srf": "语义结果格å¼",
+ "srf-prefs-intro-text": "您已安装带有语义的结果格å¼æ‹“展应用。请访问[https://www.semantic-mediawiki.org/wiki/Help:Result_formats result formats]æ¥èŽ·å–用户喜好相关的é¢å¤–帮助。",
+ "prefs-srf-eventcalendar-options": "事件日历选项",
+ "srf-prefs-eventcalendar-options-update-default": "在页é¢åˆ·æ–°æ—¶å¯ç”¨æ—¥åŽ†æ´»åŠ¨çš„[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自动更新]",
+ "srf-prefs-eventcalendar-options-paneview-default": "默认å¯ç”¨çª—格视图",
+ "prefs-srf-datatables-options": "æ•°æ®è¡¨é€‰é¡¹",
+ "srf-prefs-datatables-options-update-default": "在页é¢åˆ·æ–°æ—¶å¯ç”¨è¡¨æ ¼å†…容的[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自动更新]",
+ "srf-prefs-datatables-options-cache-default": "å¯ç”¨[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage 本地存储]以改进å“应时间",
+ "srf-module-loading": "载入中...",
+ "srf-paramdesc-layout": "å¯ç”¨å¸ƒå±€",
+ "srf-paramdesc-height": "高度",
+ "srf-paramdesc-width": "宽度",
+ "srf-paramdesc-class": "指定附加的层å å¼æ ·å¼è¡¨ç±»",
+ "srf-module-nomatch": "找ä¸åˆ°åŒ¹é…项目",
+ "srf-paramdesc-charttype": "å¯ç”¨å›¾è¡¨ç±»åž‹",
+ "srf-navigation-previous": "上一页",
+ "srf-ui-navigation-prev": "上一页",
+ "srf-ui-navigation-next": "下一页",
+ "srf-ui-common-label-source": "æ¥æº",
+ "srf-ui-common-label-datasource": "æ•°æ®æº",
+ "srf-ui-common-label-ajax-error": "æœåŠ¡å™¨æŠ¥å‘Šå¯¹æ­¤$1的通信失败。请å°è¯•åˆ·æ–°é¡µé¢æˆ–查阅$2获å–帮助。",
+ "srf-ui-common-label-request-object": "请求对象",
+ "srf-ui-common-label-help-section": "帮助部分",
+ "srf-ui-tooltip-title-options": "选项",
+ "srf-ui-tooltip-title-scope": "适用范围",
+ "srf-ui-tooltip-title-legend": "图例",
+ "srf-ui-tooltip-title-filter": "过滤器",
+ "srf-ui-common-label-refresh": "刷新",
+ "srf-ui-common-label-parameters": "å‚æ•°",
+ "srf-ui-common-label-query": "查询",
+ "srf-ui-common-label-paneview": "窗格视图",
+ "srf-ui-common-label-daterange": "日期范围",
+ "srf-ui-widgets-label-parameter-limit": "é™åˆ¶å‚æ•°",
+ "srf-error-option-mix": "选项($1)ä¸å¯ç”¨",
+ "srf-error-option-link-all": "选项($1)需è¦å‚æ•°\"link\"设置为\"all\"",
+ "srf-error-missing-layout": "无法显示图表,因为布局丢失。",
+ "srf-error-jqplot-bubble-data-length": "无法显示图纸或图标,因为数æ®ä¸¢å¤±ã€‚",
+ "srf-error-jqplot-stackseries-data-length": "无法显示图表,因为ä¸æ˜¯æ‰€æœ‰è¡Œéƒ½æœ‰ç›¸åŒçš„元素数é‡ã€‚",
+ "srf-warn-empy-chart": "由于丢失数æ®ï¼Œè¯¥å›¾è¡¨æˆ–曲线图是空的",
+ "srf-paramdesc-color": "标记日历项的颜色",
+ "srfc_previousmonth": "上月",
+ "srfc_nextmonth": "下月",
+ "srfc_today": "今天",
+ "srfc_gotomonth": "跳至月份",
+ "srf_printername_calendar": "月历",
+ "srf_paramdesc_calendarlang": "日历显示语言的代ç ",
+ "srf_paramdesc_calendarcolors": "æ¯ä¸ªæ—¥æœŸå±žæ€§çš„显示颜色(示例:\"Start date=>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "月,日历显示åˆå§‹åŒ–为(默认为当å‰æœˆï¼‰",
+ "srf-paramdesc-calendar-startyear": "年,日历显示åˆå§‹åŒ–为(默认为当å‰å¹´ï¼‰",
+ "srf_printername_vcard": "vCard导出",
+ "srf_printername_icalendar": "iCalendar导出",
+ "srf_paramdesc_icalendartitle": "日历文件的标题",
+ "srf_paramdesc_icalendardescription": "日历文件的说明",
+ "srf_printername_bibtex": "BibTeX导出",
+ "srf_outline_novalue": "没有å–值",
+ "srf_printername_outline": "大纲",
+ "srf_paramdesc_outlineproperties": "è¦æ˜¾ç¤ºä¸ºå¤§çº²æ ‡é¢˜çš„属性列表,以逗å·åˆ†éš”",
+ "srf_printername_sum": "数值之和",
+ "srf_printername_average": "数值的平å‡å€¼",
+ "srf_printername_max": "最大数目",
+ "srf_printername_min": "最å°æ•°ç›®",
+ "srf_paramdesc_limit": "所è¦æŸ¥è¯¢é¡µé¢çš„最大数é‡",
+ "srf_printername_product": "数值的乘积",
+ "srf_printername_median": "数值的中ä½æ•°",
+ "srf-paramdesc-default": "没有数值型结果时将会显示的默认值",
+ "srf_printername_earliest": "最早时间",
+ "srf_printername_latest": "最近时间",
+ "srf_printername_timeline": "时间轴",
+ "srf_printername_eventline": "事件轴",
+ "srf_paramdesc_timelinebands": "定义在结果当中显示哪些æ¡å¸¦ã€‚",
+ "srf_paramdesc_timelineposition": "定义时间轴最åˆçš„焦点ä½äºŽä½•å¤„。",
+ "srf_paramdesc_timelinestart": "用æ¥å®šä¹‰ç¬¬ä¸€ä¸ªæ—¶é—´ç‚¹çš„属性å称",
+ "srf_paramdesc_timelineend": "用æ¥å®šä¹‰ç¬¬äºŒä¸ªæ—¶é—´ç‚¹çš„属性å称",
+ "srf_paramdesc_timelinesize": "时间轴高度",
+ "srf-timeline-allresults": "此查询的进一步结果。",
+ "srf-timeline-nojs": "è¦æŸ¥çœ‹äº¤äº’å¼çš„时间轴,您需è¦å¯ç”¨JavaScript。",
+ "srf_paramdesc_views": "所è¦æ˜¾ç¤ºçš„视图",
+ "srf_paramdesc_facets": "为æ¯ä¸ªé¡µé¢æ‰€è¦æ˜¾ç¤ºçš„那套属性",
+ "srf_paramdesc_lens": "用于显示页é¢å±žæ€§çš„模æ¿å称",
+ "srf_printername_googlebar": "Googleæ¡å½¢å›¾",
+ "srf_printername_googlepie": "Google饼图",
+ "srf-printername-jqplotchart": "jqPlot图表",
+ "srf-printername-jqplotseries": "jqPlot系列",
+ "srf_paramdesc_chartheight": "指定图表或曲线图的高度(åƒç´ ï¼‰",
+ "srf_paramdesc_chartwidth": "指定图表或曲线图的宽度(åƒç´ æˆ–百分比)",
+ "srf_paramdesc_charttitle": "图表标题",
+ "srf_paramdesc_barcolor": "æ¡å½¢çš„颜色",
+ "srf_paramdesc_bardirection": "指定图纸的方å‘",
+ "srf-paramdesc-direction": "指定图纸或图表的方å‘",
+ "srf_paramdesc_barnumbersaxislabel": "数字轴标签",
+ "srf-paramdesc-labelaxislabel": "标签轴的标签",
+ "srf-paramdesc-ticklabels": "å¯ç”¨å‹¾é€‰æ ‡ç­¾çš„显示",
+ "srf-paramdesc-minvalue": "Y-轴上所è¦æ˜¾ç¤ºçš„最å°å€¼",
+ "srf-paramdesc-pointlabels": "显示图纸中的数æ®ç‚¹",
+ "srf-paramdesc-chartlegend": "图表图例ä½ç½®",
+ "srf-paramdesc-datalabels": "图纸/图表数æ®æ ‡ç­¾",
+ "srf-paramdesc-charttext": "æ述性图表文本",
+ "srf-paramdesc-chartclass": "é¢å¤–CSSç±»",
+ "srf-paramdesc-renderer": "选择图形/图表渲染器",
+ "srf-paramdesc-filling": "具体填充选项",
+ "srf-paramdesc-theme": "选择网格主题",
+ "srf-paramdesc-chartcolor": "指定具体图表颜色",
+ "srf-paramdesc-colorscheme": "选择é…色方案",
+ "srf-paramdesc-valueformat": "指定å–值的格å¼ç¼–排规则",
+ "srf-paramdesc-highlighter": "显示数æ®ç‚¹é«˜äº®å‚æ•°",
+ "srf-paramdesc-smoothlines": "在折线图上应用平滑算法",
+ "srf-paramdesc-stackseries": "将图表显示为堆å ç³»åˆ—",
+ "srf-paramdesc-seriesgroup": "选择系列分组",
+ "srf-paramdesc-serieslabel": "确定系列标签",
+ "srf-paramdesc-grouplabel": "确定分组标签",
+ "srf-paramdesc-chartcursor": "图表光标显示选项",
+ "srf-paramdesc-trendline": "å¯ç”¨å›¾è¡¨åŠå…¶è¶‹åŠ¿çº¿çš„åŒæ—¶æ˜¾ç¤º",
+ "srf-paramdesc-gridview": "åŒæ—¶æ˜¾ç¤ºå›¾è¡¨å’Œæ•°æ®é›†ã€‚å…许å–值:\"none\"å’Œ\"tabs\"。默认值:\"none\"",
+ "srf-paramdesc-paneview": "指定é¢æ¿å†…å«çš„å°æŠ˜çº¿å›¾çš„ä½ç½®ã€‚å…许å–值:\"bottom\"ã€\"top\"å’Œ\"none\"。默认值:\"bottom\"",
+ "srf-paramdesc-infotext": "在相应的信æ¯é€‰é¡¹å¡ä¸Šæ˜¾ç¤ºé™„加信æ¯",
+ "srf-paramdesc-clicktarget": "当点击日历上的日期时,定义页é¢æˆ–查询字符作为目标。",
+ "srf-ui-gridview-label-item": "æ•°æ®é¡¹",
+ "srf-ui-gridview-label-value": "æ•°æ®å€¼",
+ "srf-ui-gridview-label-series": "æ•°æ®ç³»åˆ—",
+ "srf-ui-gridview-label-chart-tab": "图表",
+ "srf-ui-gridview-label-data-tab": "æ•°æ®",
+ "srf-ui-gridview-label-info-tab": "ä¿¡æ¯",
+ "srf_printername_gallery": "图库",
+ "srf_paramdesc_perrow": "æ¯è¡Œçš„图åƒä¸ªæ•°",
+ "srf_paramdesc_widths": "图åƒå®½åº¦",
+ "srf_paramdesc_heights": "图åƒé«˜åº¦",
+ "srf_paramdesc_autocaptions": "ä¸æ供任何标题时使用文件å称作为标题",
+ "srf_paramdesc_fileextensions": "当使用文件å作为标题,åŒæ—¶ä¹Ÿæ˜¾ç¤ºæ–‡ä»¶æ‰©å±•å",
+ "srf_paramdesc_captionproperty": "存在于所查询页é¢ä¸Šçš„æŸä¸ªè¯­ä¹‰å±žæ€§çš„å称è¦ç”¨ä½œæ ‡é¢˜",
+ "srf_paramdesc_imageproperty": "所查询页é¢ä¸ŠæŸä¸€æŒ‡å‘所è¦ä½¿ç”¨çš„图åƒçš„语义属性的å称。当设置时,所查询页é¢æœ¬èº«å°†ä¸ä¼šæ˜¾ç¤ºä¸ºå›¾åƒã€‚",
+ "srf-paramdesc-redirects": "出现在查询所获得的å«æœ‰é‡å®šå‘目标的页é¢ä¹‹ä¸Šçš„语义属性的å称",
+ "srf-paramdesc-navigation": "布局导航控制",
+ "srf-paramdesc-overlay": "å¯ç”¨å›¾ç‰‡è¦†ç›–",
+ "srf-gallery-navigation-previous": "上一步",
+ "srf-gallery-navigation-next": "下一步",
+ "srf-gallery-overlay-count": "$2的图åƒ$1",
+ "srf-gallery-image-url-error": "图åƒæœªæ‰¾åˆ°ã€‚",
+ "srf_printername_tagcloud": "标签云",
+ "srf_paramdesc_includesubject": "主题å称本身应被包å«",
+ "srf_paramdesc_increase": "如何增加标签的大å°",
+ "srf_paramdesc_tagorder": "标签的顺åº",
+ "srf_paramdesc_mincount": "è¦åˆ—出æŸä¸€å–值所需出现的最少次数",
+ "srf_paramdesc_minsize": "以百分比计算的最å°æ ‡ç­¾çš„大å°",
+ "srf_paramdesc_maxsize": "以百分比计算的最大标签的大å°",
+ "srf_paramdesc_maxtags": "云中标签的最大数é‡",
+ "srf-paramdesc-excludetags": "排除标签(分隔符:“;â€ï¼‰",
+ "srf_printername_valuerank": "å–值排å",
+ "srf_printername_array": "数组",
+ "srf_paramdesc_pagetitle": "究竟是把页é¢æ ‡é¢˜æ˜¾ç¤ºä¸ºç»“æžœæ¡ç›®ï¼Œè¿˜æ˜¯ç•¥åŽ»å®ƒä»¬",
+ "srf_paramdesc_hidegaps": "究竟是打å°è¾“出所请求的但ä¸å¯ç”¨çš„属性以åŠé‡‡ç”¨åˆ†éš”符分隔的记录å–值,还是略去它们",
+ "srf_paramdesc_arrayname": "如果已ç»ç»™å‡ºï¼Œä¸”ArrayExtensionå¯ç”¨ï¼Œè¿™å°†ä¼šåˆ›å»ºä¸€ä¸ªå¸¦æœ‰æŒ‡å®šå称的数组(没有任何å¯è§çš„输出)",
+ "srf_paramdesc_propsep": "所请求属性之间的分隔符",
+ "srf_paramdesc_manysep": "许多已ç»èµ‹å€¼çš„属性å–值之间的分隔符",
+ "srf_paramdesc_recordsep": "记录属性的å–值之间的分隔符",
+ "srf_paramdesc_headersep": "当把\"headers\"设置为\"show\"或\"plain\"时,属性å称和å–值之间的分隔符",
+ "srf_printername_hash": "哈希",
+ "srf_paramdesc_hashname": "如果已ç»ç»™å‡ºï¼Œä¸”HashTableså¯ç”¨ï¼Œè¿™å°†ä¼šåˆ›å»ºä¸€ä¸ªå¸¦æœ‰æŒ‡å®šå称的哈希表(没有任何å¯è§çš„输出)",
+ "srf-printername-graph": "图表",
+ "srf-paramdesc-graph-relation": "这些主题或å称属性是父节点或å­èŠ‚点å—?",
+ "srf-paramdesc-graph-nameprop": "å…许设置一个属性,并将其作为主题æ¥ä½¿ç”¨ï¼Œè€Œä¸æ˜¯å®žé™…的主题",
+ "srf-paramdesc-graph-nodeshape": "图形上æ¯ä¸ªèŠ‚点的形状",
+ "srf-paramdesc-graphname": "设置图表的标题",
+ "srf-paramdesc-graphsize": "设置grapht的大å°ï¼ˆåƒç´ ï¼‰",
+ "srf-paramdesc-graphlegend": "设置是å¦åº”显示图形图例",
+ "srf-paramdesc-graphlabel": "设置图表的标签",
+ "srf-paramdesc-rankdir": "设置箭头的方å‘",
+ "srf-paramdesc-graphlink": "设置节点是å¦åº”链接到其wiki页é¢",
+ "srf-paramdesc-graphcolor": "设置图表的颜色",
+ "srf-paramdesc-graph-wwl": "Word自动æ¢è¡Œé™åˆ¶ï¼ˆä»¥å­—符计)",
+ "srf-paramdesc-clustercolor": "设置集群框的颜色",
+ "srf-paramdesc-highlight": "设置节点高亮",
+ "srf-paramdesc-highlightcolor": "设置高亮节点的字体颜色",
+ "srf-paramdesc-redlinkcolor": "设置红链的字体颜色",
+ "srf-paramdesc-processcategory": "设置收集过程步骤的wiki分类",
+ "srf-paramdesc-showroles": "在图表中显示对应角色",
+ "srf-paramdesc-showstatus": "设置过程步骤是å¦åº”被渲染",
+ "srf-paramdesc-showresources": "在图表中显示对应资æº",
+ "srf-paramdesc-showdiscussion": "设置讨论是å¦åº”被渲染",
+ "srf-paramdesc-showredlinks": "设置红链是å¦åº”检查并高亮",
+ "srf-paramdesc-showcompound": "设置是å¦é«˜äº®åˆæˆèŠ‚点,也就是å­è¿‡ç¨‹",
+ "srf-paramdesc-debug": "设置过程图表代ç æ˜¯å¦åº”显示包裹的预标签",
+ "srf-paramdesc-graphvalidation": "将没有分é…角色的过程步骤显示为红色",
+ "srf-printername-datatables": "æ•°æ®è¡¨",
+ "srf-ui-datatables-label-conditions": "æ¡ä»¶",
+ "srf-ui-datatables-label-parameters": "å‚æ•°",
+ "srf-ui-datatables-label-filters": "列过滤器与æœç´¢",
+ "srf-ui-datatables-label-information": "ä¿¡æ¯",
+ "srf-ui-datatables-panel-disclaimer": "å‚æ•°å’Œæ¡ä»¶æ˜¯å¯ä»¥æ”¹å˜çš„,但任何改å˜éƒ½æ˜¯æš‚时的,且在页é¢åˆ·æ–°ä¹‹åŽå°†ä¼šè¢«æ”¾å¼ƒã€‚",
+ "srf-ui-datatables-label-update-success": "图标更新æˆåŠŸ",
+ "srf-ui-datatables-label-update-error": "图标更新失败。",
+ "srf-ui-datatables-label-placeholder-column-search": "æœç´¢...",
+ "srf-ui-datatables-label-content-cache": "内容从本地缓存中得到。",
+ "srf-ui-datatables-label-content-server": "内容从æœåŠ¡å™¨å¾—到。",
+ "srf-ui-datatables-label-multiselect-column-header": "å¯ç”¨é˜µåˆ—",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "过滤器设置",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "阵列是å¯è§çš„",
+ "srf-ui-datatables-label-sEmptyTable": "表中无å¯ç”¨æ•°æ®",
+ "srf-ui-datatables-label-sInfo": "显示_TOTAL_的记录,从_START_至_END_",
+ "srf-ui-datatables-label-sInfoEmpty": "显示0的记录,从0至0",
+ "srf-ui-datatables-label-sInfoFiltered": "(从_MAX_总记录中筛选)",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "显示_MENU_记录",
+ "srf-ui-datatables-label-sLoadingRecords": "正在载入……",
+ "srf-ui-datatables-label-sProcessing": "处ç†ä¸­...",
+ "srf-ui-datatables-label-sSearch": "æœç´¢ï¼š",
+ "srf-ui-datatables-label-sZeroRecords": "未找到匹é…记录",
+ "srf-ui-datatables-label-oPaginate-sFirst": "首",
+ "srf-ui-datatables-label-oPaginate-sLast": "上",
+ "srf-ui-datatables-label-oPaginate-sNext": "下",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "上一页",
+ "srf-ui-datatables-label-oAria-sSortAscending": ":å¯ç”¨æŒ‰å‡åºè¿›è¡Œåˆ—排åº",
+ "srf-ui-datatables-label-oAria-sSortDescending": ":å¯ç”¨æŒ‰é™åºè¿›è¡Œåˆ—排åº",
+ "srf-printername-tree": "æ ‘",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "未æ供父属性。在没有指定父属性的情况下无法构建树ç§ç»“构。",
+ "srf-tree-rootinvalid": "$1ä¸æ˜¯æœ‰æ•ˆçš„页é¢æ ‡é¢˜ã€‚",
+ "srf-tree-circledetected": "当å°è¯•æ’å…¥$1到树时检测到循环。",
+ "srf-paramdesc-tree-parent": "包å«çˆ¶é¡µé¢çš„属性",
+ "srf-paramdesc-tree-root": "树的根页é¢",
+ "srf-paramdesc-tree-startlevel": "树状结构的起始级别,例如,将其整åˆåˆ°å¦ä¸€æ ‘状结构之中",
+ "srf-printername-slideshow": "å¹»ç¯ç‰‡",
+ "srf-paramdesc-delay": "å¹»ç¯ç‰‡ä¹‹é—´çš„延迟时间(以秒为å•ä½ï¼‰",
+ "srf-paramdesc-navigation-controls": "是å¦æ˜¾ç¤ºå¯¼èˆªæŽ§åˆ¶",
+ "srf-paramdesc-effect": "所è¦é‡‡ç”¨çš„å¹»ç¯ç‰‡åˆ‡æ¢æ•ˆæžœ",
+ "srf-printername-filtered": "已过滤",
+ "srf-paramdesc-filtered-views": "结果显示之中应当æ供的视图。",
+ "srf-paramdesc-filtered-filter-position": "视图相关过滤器的ä½ç½®ã€‚å…许的值:“topâ€å’Œâ€œbottomâ€ã€‚默认值:“topâ€ã€‚",
+ "srf-paramdesc-filtered-list-type": "列表的类型。å…许的值:“listâ€ã€â€œulâ€ã€â€œolâ€ã€‚默认值:“listâ€ã€‚",
+ "srf-paramdesc-filtered-list-template": "用于列表项格å¼ç¼–排的模æ¿ã€‚",
+ "srf-paramdesc-filtered-list-named-args": "请指定传递给该模æ¿çš„å˜é‡",
+ "srf-paramdesc-filtered-list-introtemplate": "查询结果å‰é¢æ‰€è¦æ˜¾ç¤ºæ¨¡æ¿çš„å称(如果有的è¯ï¼‰ã€‚",
+ "srf-paramdesc-filtered-list-outrotemplate": "查询结果åŽé¢æ‰€è¦æ˜¾ç¤ºæ¨¡æ¿çš„å称(如果有的è¯ï¼‰",
+ "srf-paramdesc-filtered-calendar-start": "包å«äº‹ä»¶å¼€å§‹æ—¥æœŸçš„打å°è¾“出",
+ "srf-paramdesc-filtered-calendar-end": "包å«äº‹ä»¶ç»“æŸæ—¥æœŸçš„打å°è¾“出",
+ "srf-paramdesc-filtered-calendar-title": "包å«äº‹ä»¶æ ‡é¢˜çš„打å°è¾“出。ä¸èƒ½ä¸Žæ ‡é¢˜æ¨¡æ¿ä¸€èµ·ä½¿ç”¨ã€‚",
+ "srf-paramdesc-filtered-calendar-title-template": "用于日历之中事件标题格å¼ç¼–排的模æ¿",
+ "srf-paramdesc-filtered-map-position": "打å°è¾“出包å«åœ°ç†ä½ç½®ã€‚",
+ "srf-paramdesc-filtered-map-icon": "决定使用的地图图标的打å°è¾“出。",
+ "srf-paramdesc-filtered-map-icons": "è¦ä¸ºè¿™äº›åœ°å›¾ä¸Šçš„值使用的图标值映射。",
+ "srf-paramdesc-filtered-map-height": "地图高度。",
+ "srf-paramdesc-filtered-map-zoom": "地图加载时的缩放级别。这å¯ä»¥ç”±ç”¨æˆ·æ›´æ”¹ã€‚<br>å‚è§<i>地图视图最低缩放值</i>与<i>最高缩放值</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "地图的最低å¯é€‰ç¼©æ”¾çº§åˆ«",
+ "srf-paramdesc-filtered-map-max-zoom": "地图的最高å¯é€‰ç¼©æ”¾çº§åˆ«",
+ "srf-paramdesc-filtered-map-marker-cluster": "å¯ç”¨æˆ–关闭标记èšåˆã€‚",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "地图标记ä»ç„¶èšé›†æ—¶çš„最高缩放级别。此级别以上的标记将必定ä¸ä¼šèšé›†ã€‚",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "群集从中心点开始覆盖的最大åŠå¾„(åƒç´ ï¼‰ã€‚默认值80。",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "当å¯ç”¨æ—¶ï¼Œç‚¹å‡»ç¾¤é›†å°†æ”¾å¤§åˆ°å…¶ç•Œé™ã€‚",
+ "srf-filtered-selectorlabel-list": "列表",
+ "srf-filtered-selectorlabel-table": "表格",
+ "srf-filtered-selectorlabel-calendar": "日历",
+ "srf-filtered-selectorlabel-map": "地图",
+ "srf-filtered-noscript-error": "因为Javascript未å¯ç”¨ï¼Œæ‰€ä»¥ä¸èƒ½æ˜¾ç¤ºç»“果。å‰å¾€$1。",
+ "srf-filtered-noscript-link-caption": "表格窗体中的结果",
+ "srf-filtered-map-provider-missing-error": "没有为“地图â€è§†å›¾æŒ‡å®šåœ°å›¾æ供者。",
+ "srf-filtered-value-filter-and": "和",
+ "srf-filtered-value-filter-or": "或",
+ "srf-filtered-value-filter-placeholder": "选择过滤器值",
+ "srf-printername-d3chart": "D3图表",
+ "srf-printername-timeseries": "时间åºåˆ—图表",
+ "srf-paramdesc-group": "按系列分组",
+ "srf-paramdesc-zoom": "å¯ç”¨ç¼©æ”¾",
+ "srf-paramdesc-datatable": "å¯ç”¨æ•°æ®è¡¨",
+ "srf-timeseries-zoom-out-of-range": "该缩放范围并未产生任何足够的数æ®",
+ "srf-printername-sparkline": "Sparkline图表",
+ "srf-printername-listwidget": "列表å°å·¥å…·",
+ "srf-paramdesc-listtype": "指定列表类型",
+ "srf-paramdesc-widget": "å¯ç”¨ç»„件",
+ "srf-paramdesc-pageitems": "项æ¯é¡µ",
+ "srf-printername-eventcalendar": "事件日历",
+ "srf-paramdesc-calendarfirstday": "作为æ¯æ˜ŸæœŸå¼€å§‹çš„第一天",
+ "srf-paramdesc-calendardefaultview": "日历加载时的åˆå§‹è§†å›¾",
+ "srf-paramdesc-calendarstart": "日历åˆå§‹èµ·ç‚¹ (日期型或日期时间型å–值)",
+ "srf-paramdesc-calendarlegend": "指定图例ä½ç½®ä»¥åŠæ‰€èµ‹äºˆçš„过滤器选项",
+ "srf-paramdesc-dayview": "点击天数å¯ç”¨æ—¥æœŸæŸ¥çœ‹",
+ "srf-ui-eventcalendar-label-today": "今天",
+ "srf-ui-eventcalendar-label-month": "月",
+ "srf-ui-eventcalendar-label-week": "周",
+ "srf-ui-eventcalendar-label-day": "æ—¥",
+ "srf-ui-eventcalendar-label-listmonth": "月(列表)",
+ "srf-ui-eventcalendar-label-listweek": "周(列表)",
+ "srf-ui-eventcalendar-label-listday": "日(列表)",
+ "srf-ui-eventcalendar-label-allday": "全天",
+ "srf-ui-eventcalendar-label-update-success": "活动日历æˆåŠŸæ›´æ–°ã€‚",
+ "srf-ui-eventcalendar-label-update-error": "活动日历更新失败。",
+ "srf-ui-eventcalendar-click-popup": "您è¦åˆ›å»ºæ´»åŠ¨ä¹ˆï¼Ÿ",
+ "srf-printername-dygraphs": "Dygraphs图表",
+ "srf-paramdesc-datasource": "å¯ä»¥è®¿é—®çš„æ•°æ®æ¥æºã€‚å…许å–值:\"file\"ã€\"raw\"å’Œ\"url\"。默认值:\"file\"",
+ "srf-paramdesc-errorbar": "è¦ä½¿ç”¨çš„误差线。å…许å–值:\"fraction\"(å–值的置信区间)ã€\"sigma\"(å–值的标准åå·®) å’Œ\"range\"(自定义的å–值范围)",
+ "srf-paramdesc-movingaverage": "显示若干天时间的å‡å€¼ (零表示没有移动å‡å€¼ï¼‰",
+ "srf-paramdesc-yaxislabel": "Y轴上显示的说明",
+ "srf-paramdesc-xaxislabel": "X轴上显示的说明",
+ "srf-paramdesc-unit": "å•ä½",
+ "srf-printername-pagewidget": "页é¢å°éƒ¨ä»¶",
+ "srf-printername-incoming": "连入属性",
+ "srf-paramdesc-count": "设置是å¦åº”计算链入属性的数é‡",
+ "srf-paramdesc-min": "最å°å€¼æˆ–阀值",
+ "srf-paramdesc-excludeproperty": "从结果集中排除属性",
+ "srf-printername-media": "媒体播放器",
+ "srf-paramdesc-mediainspector": "显示关于指定媒体元素的详细信æ¯",
+ "srf-ui-mediaplayer-label-previous": "上一个",
+ "srf-ui-mediaplayer-label-play": "播放",
+ "srf-ui-mediaplayer-label-pause": "æš‚åœ",
+ "srf-ui-mediaplayer-label-next": "下一个",
+ "srf-ui-mediaplayer-label-stop": "åœæ­¢",
+ "srf-ui-mediaplayer-label-mute": "ç¦è¨€",
+ "srf-ui-mediaplayer-label-unmute": "å–消ç¦è¨€",
+ "srf-ui-mediaplayer-label-volume-max": "最大音é‡",
+ "srf-ui-mediaplayer-label-shuffle": "æ— åºæ’­æ”¾",
+ "srf-ui-mediaplayer-label-shuffle-off": "关闭无åºæ’­æ”¾",
+ "srf-ui-mediaplayer-label-repeat": "é‡å¤",
+ "srf-ui-mediaplayer-label-repeat-off": "关闭é‡å¤",
+ "srf-ui-mediaplayer-label-full-screen": "å…¨å±",
+ "srf-ui-mediaplayer-label-restore-screen": "还原å±å¹•",
+ "srf-paramdesc-icalendar-timezone": "时区的逗å·åˆ†éš”列表",
+ "srf-paramdesc-gantt-diagramtitle": "æ•°æ®å›¾å称",
+ "srf-paramdesc-gantt-diagramtheme": "æ•°æ®å›¾ä¸»é¢˜",
+ "srf-paramdesc-gantt-axisformat": "横轴:日期格å¼",
+ "srf-paramdesc-gantt-titletopmargin": "æ•°æ®å›¾æ ‡é¢˜çš„内上边è·",
+ "srf-paramdesc-gantt-barheight": "任务æ é«˜åº¦",
+ "srf-printername-gantt": "甘特图"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/zh-hant.json b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hant.json
new file mode 100644
index 00000000..614036dc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hant.json
@@ -0,0 +1,338 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki",
+ "Wrightbus",
+ "Liuxinyu970226",
+ "LNDDYL",
+ "Cwlin0416",
+ "Nemo bis",
+ "Hello903hello",
+ "Kly"
+ ]
+ },
+ "srf-desc": "用於 Semantic MediaWiki 查詢的附加çµæžœæ ¼å¼",
+ "prefs-srf": "擴充:語æ„çµæžœæ ¼å¼",
+ "srf-prefs-intro-text": "æ‚¨å·²å®‰è£ Semantic Result Formats 擴充功能。é¡å¤–幫助內容請查看[https://www.semantic-mediawiki.org/wiki/Help:Result_formats çµæžœæ ¼å¼]的說明é é¢.",
+ "prefs-srf-eventcalendar-options": "事件行事曆é¸é …",
+ "srf-prefs-eventcalendar-options-update-default": "當é é¢é‡æ–°æ•´ç†æ™‚啟用[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自動更新]行事曆事件",
+ "srf-prefs-eventcalendar-options-paneview-default": "é è¨­å•Ÿç”¨æ–¹æ ¼æª¢è¦–",
+ "prefs-srf-datatables-options": "資料表é¸é …",
+ "srf-prefs-datatables-options-update-default": "當é é¢é‡æ–°æ•´ç†æ™‚啟用[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Automatic_updates 自動更新]表格內容",
+ "srf-prefs-datatables-options-cache-default": "啟用[https://www.semantic-mediawiki.org/wiki/Help:User_preferences#Local_storage 本地端儲存]來改善回應時間",
+ "srf-module-loading": "載入中...",
+ "srf-paramdesc-layout": "å¯ç”¨ä½ˆå±€",
+ "srf-paramdesc-height": "高度",
+ "srf-paramdesc-width": "寬度",
+ "srf-paramdesc-class": "指定é¡å¤–的階層å¼æ¨£å¼è¡¨é¡žåˆ¥",
+ "srf-module-nomatch": "沒有符åˆçš„資訊",
+ "srf-paramdesc-charttype": "å¯ç”¨åœ–表類型",
+ "srf-navigation-previous": "上一個",
+ "srf-ui-navigation-prev": "å‰ä¸€é ",
+ "srf-ui-navigation-next": "下一é ",
+ "srf-ui-common-label-source": "來æº",
+ "srf-ui-common-label-datasource": "資料來æº",
+ "srf-ui-common-label-ajax-error": "伺æœå™¨å ±å‘Šå°æ­¤$1通訊失敗。請嘗試é‡æ–°è¼‰å…¥é é¢æˆ–查閱$2。",
+ "srf-ui-common-label-request-object": "徽求å°è±¡",
+ "srf-ui-common-label-help-section": "說明章節",
+ "srf-ui-tooltip-title-options": "é¸é …",
+ "srf-ui-tooltip-title-scope": "範åœ",
+ "srf-ui-tooltip-title-legend": "說明",
+ "srf-ui-tooltip-title-filter": "篩é¸å™¨",
+ "srf-ui-common-label-refresh": "é‡æ–°æ•´ç†",
+ "srf-ui-common-label-parameters": "åƒæ•¸",
+ "srf-ui-common-label-query": "查詢",
+ "srf-ui-common-label-paneview": "方格檢視",
+ "srf-ui-common-label-daterange": "日期範åœ",
+ "srf-ui-widgets-label-parameter-limit": "é™åˆ¶åƒæ•¸",
+ "srf-error-option-mix": "é¸é …($1)ä¸å¯ç”¨",
+ "srf-error-option-link-all": "é¸é …($1)需è¦å°‡åƒæ•¸ã€Œlinkã€è¨­å®šæˆã€Œallã€",
+ "srf-error-missing-layout": "因為佈局éºå¤±ç·£æ•…,圖表或圖形無法顯示。",
+ "srf-error-jqplot-bubble-data-length": "因為資料éºå¤±ç·£æ•…,圖表或圖形無法顯示。",
+ "srf-error-jqplot-stackseries-data-length": "圖表或圖片無法顯示,因為所有æ¢ç‹€æˆ–線狀並沒有都å«æœ‰ç›¸åŒå…ƒç´ æ•¸é‡ã€‚",
+ "srf-warn-empy-chart": "å› éºå¤±è³‡æ–™ï¼Œå°Žè‡´åœ–表或圖型為空",
+ "srf-paramdesc-color": "標記行事曆項目的色彩",
+ "srfc_previousmonth": "上月",
+ "srfc_nextmonth": "下月",
+ "srfc_today": "今天",
+ "srfc_gotomonth": "跳至月份",
+ "srf_printername_calendar": "月曆",
+ "srf_paramdesc_calendarlang": "顯示行事曆的語言代碼",
+ "srf_paramdesc_calendarcolors": "æ¯å€‹æ—¥æœŸå±¬æ€§çš„顯示é¡è‰²ï¼ˆç¤ºä¾‹ï¼š\"Start date=>green,End date=>#09c\")",
+ "srf-paramdesc-calendar-startmonth": "行事曆åˆå§‹åŒ–的月份(é è¨­ç‚ºç›®å‰æœˆä»½ï¼‰",
+ "srf-paramdesc-calendar-startyear": "行事曆åˆå§‹åŒ–的年份(é è¨­ç‚ºç›®å‰å¹´ä»½ï¼‰",
+ "srf_printername_vcard": "vCard匯出",
+ "srf_printername_icalendar": "iCalendar匯出",
+ "srf_paramdesc_icalendartitle": "行事曆檔案的標題",
+ "srf_paramdesc_icalendardescription": "日曆檔案的說明",
+ "srf_printername_bibtex": "BibTeX匯出",
+ "srf_outline_novalue": "沒有å–值",
+ "srf_printername_outline": "大綱",
+ "srf_paramdesc_outlineproperties": "è¦é¡¯ç¤ºç‚ºå¤§ç¶±æ¨™é¡Œçš„屬性列表,以逗號分隔",
+ "srf_printername_sum": "數值之和",
+ "srf_printername_average": "數值的平å‡å€¼",
+ "srf_printername_max": "最大數目",
+ "srf_printername_min": "最å°æ•¸ç›®",
+ "srf_paramdesc_limit": "所è¦æŸ¥è©¢é é¢çš„最大數é‡",
+ "srf_printername_product": "數值的乘ç©",
+ "srf_printername_median": "數值的中ä½æ•¸",
+ "srf-paramdesc-default": "沒有數值型çµæžœæ™‚將會顯示的默èªå€¼",
+ "srf_printername_earliest": "最早時間",
+ "srf_printername_latest": "最後時間",
+ "srf_printername_timeline": "時間軸",
+ "srf_printername_eventline": "事件軸",
+ "srf_paramdesc_timelinebands": "定義在çµæžœç•¶ä¸­é¡¯ç¤ºå“ªäº›æ¢å¸¶ã€‚",
+ "srf_paramdesc_timelineposition": "定義時間軸最åˆçš„焦點ä½æ–¼ä½•è™•ã€‚",
+ "srf_paramdesc_timelinestart": "用來定義第一個時間點的屬性å稱",
+ "srf_paramdesc_timelineend": "用來定義第二個時間點的屬性å稱",
+ "srf_paramdesc_timelinesize": "時間軸高度",
+ "srf-timeline-allresults": "此查詢的進一步çµæžœã€‚",
+ "srf-timeline-nojs": "è¦æª¢è¦–互動å¼çš„時間軸,您需è¦å•Ÿç”¨JavaScript。",
+ "srf_paramdesc_views": "所è¦é¡¯ç¤ºçš„視圖",
+ "srf_paramdesc_facets": "為æ¯å€‹é é¢æ‰€è¦é¡¯ç¤ºçš„那套屬性",
+ "srf_paramdesc_lens": "用於顯示é é¢å±¬æ€§çš„模æ¿å稱",
+ "srf_printername_googlebar": "Googleæ¢å½¢åœ–",
+ "srf_printername_googlepie": "Google餅圖",
+ "srf-printername-jqplotchart": "jqPlot 圖表",
+ "srf-printername-jqplotseries": "jqPlot åºåˆ—",
+ "srf_paramdesc_chartheight": "指定圖表或圖形的高度(åƒç´ ï¼‰",
+ "srf_paramdesc_chartwidth": "指定圖表或圖形的寬度(åƒç´ æˆ–百分比)",
+ "srf_paramdesc_charttitle": "圖表標題",
+ "srf_paramdesc_barcolor": "æ¢å½¢çš„é¡è‰²",
+ "srf_paramdesc_bardirection": "指定圖表的方å‘",
+ "srf-paramdesc-direction": "指定圖表或圖型的方å‘",
+ "srf_paramdesc_barnumbersaxislabel": "數字軸標籤",
+ "srf-paramdesc-labelaxislabel": "標籤軸的標籤",
+ "srf-paramdesc-ticklabels": "啟用勾é¸æ¨™ç±¤çš„顯示",
+ "srf-paramdesc-minvalue": "Y-軸上所è¦é¡¯ç¤ºçš„最å°å€¼",
+ "srf-paramdesc-pointlabels": "顯示圖表中的資料點",
+ "srf-paramdesc-chartlegend": "圖表圖例ä½ç½®",
+ "srf-paramdesc-datalabels": "圖表/圖型資料標籤",
+ "srf-paramdesc-charttext": "æ述性圖表文字",
+ "srf-paramdesc-chartclass": "é¡å¤– CSS 類別",
+ "srf-paramdesc-renderer": "é¸æ“‡åœ–å½¢/圖表渲染器",
+ "srf-paramdesc-filling": "具體填充é¸é …",
+ "srf-paramdesc-theme": "é¸æ“‡ç¶²æ ¼ä¸»é¡Œ",
+ "srf-paramdesc-chartcolor": "分é…具體圖表色彩",
+ "srf-paramdesc-colorscheme": "é¸æ“‡è‰²å½©æ–¹æ¡ˆ",
+ "srf-paramdesc-valueformat": "指定用於值的格å¼è¦ç¯„",
+ "srf-paramdesc-highlighter": "顯示資料點加強凸顯效果",
+ "srf-paramdesc-smoothlines": "在線狀圖上套用平滑演算法",
+ "srf-paramdesc-stackseries": "顯示圖表為疊堆åºåˆ—",
+ "srf-paramdesc-seriesgroup": "é¸æ“‡ç³»åˆ—分組",
+ "srf-paramdesc-serieslabel": "確èªç³»åˆ—標籤",
+ "srf-paramdesc-grouplabel": "確èªç¾¤çµ„標籤",
+ "srf-paramdesc-chartcursor": "圖表游標顯示é¸é …",
+ "srf-paramdesc-trendline": "啟用åŒæ™‚顯示圖表與該趨勢線",
+ "srf-paramdesc-gridview": "åŒæ™‚顯示圖表與資料集。å…許的值為:「noneã€å’Œã€Œtabsã€ï¼Œé è¨­ç‚ºï¼šã€Œnoneã€",
+ "srf-paramdesc-paneview": "指定包å«å°åž‹ç·šç‹€åœ–的方格ä½ç½®ã€‚å…許的值為:「topã€ã€ã€Œbottomã€ã€ã€Œnoneã€ï¼Œé è¨­ç‚ºï¼šã€Œbottomã€ã€‚",
+ "srf-paramdesc-infotext": "顯示在å°æ‡‰è³‡è¨Šåˆ†é çš„é¡å¤–資訊。",
+ "srf-paramdesc-clicktarget": "定義當點擊行事曆日期時,作為目標的é é¢æˆ–查詢字串。",
+ "srf-ui-gridview-label-item": "資料項目",
+ "srf-ui-gridview-label-value": "資料值",
+ "srf-ui-gridview-label-series": "資料åºåˆ—",
+ "srf-ui-gridview-label-chart-tab": "圖表",
+ "srf-ui-gridview-label-data-tab": "資料",
+ "srf-ui-gridview-label-info-tab": "資訊",
+ "srf_printername_gallery": "圖庫",
+ "srf_paramdesc_perrow": "æ¯è¡Œçš„圖åƒå€‹æ•¸",
+ "srf_paramdesc_widths": "圖åƒå¯¬åº¦",
+ "srf_paramdesc_heights": "圖åƒé«˜åº¦",
+ "srf_paramdesc_autocaptions": "ä¸æ供任何標題時使用檔案å稱作為標題",
+ "srf_paramdesc_fileextensions": "當使用檔案å稱作為標題,åŒæ™‚也顯示檔案副檔å",
+ "srf_paramdesc_captionproperty": "存在於所查詢é é¢ä¸Šçš„æŸå€‹èªžç¾©å±¬æ€§çš„å稱è¦ç”¨ä½œæ¨™é¡Œ",
+ "srf_paramdesc_imageproperty": "所查詢é é¢ä¸ŠæŸä¸€æŒ‡å‘所è¦ä½¿ç”¨çš„圖åƒçš„語義屬性的å稱。當設置時,所查詢é é¢æœ¬èº«å°‡ä¸æœƒé¡¯ç¤ºç‚ºåœ–åƒã€‚",
+ "srf-paramdesc-redirects": "呈ç¾åœ¨å·²æŸ¥è©¢é é¢è³žï¼Œä¸”å«æœ‰é‡æ–°å°Žå‘目標的語æ„屬性å稱",
+ "srf-paramdesc-navigation": "佈局導航控制",
+ "srf-paramdesc-overlay": "啟用圖片覆蓋",
+ "srf-gallery-navigation-previous": "上一個",
+ "srf-gallery-navigation-next": "下一個",
+ "srf-gallery-overlay-count": "$2 裡的第 $1 個圖片",
+ "srf-gallery-image-url-error": "找ä¸åˆ°åœ–片。",
+ "srf_printername_tagcloud": "標籤雲",
+ "srf_paramdesc_includesubject": "如果主題å稱本身應當包括在內",
+ "srf_paramdesc_increase": "如何增加標籤的大å°",
+ "srf_paramdesc_tagorder": "標籤的順åº",
+ "srf_paramdesc_mincount": "è¦åˆ—出æŸä¸€å–值所需出ç¾çš„最少次數",
+ "srf_paramdesc_minsize": "以百分比計算的最å°æ¨™ç±¤çš„大å°",
+ "srf_paramdesc_maxsize": "以百分比計算的最大標籤的大å°",
+ "srf_paramdesc_maxtags": "雲中標籤的最大數é‡",
+ "srf-paramdesc-excludetags": "排除標籤(分隔符號:「;ã€ï¼‰",
+ "srf_printername_valuerank": "å–值排å",
+ "srf_printername_array": "數組",
+ "srf_paramdesc_pagetitle": "究竟是把é é¢æ¨™é¡Œé¡¯ç¤ºç‚ºçµæžœæ¢ç›®ï¼Œé‚„是略去它們",
+ "srf_paramdesc_hidegaps": "究竟是打å°è¼¸å‡ºæ‰€è«‹æ±‚的但ä¸å¯ç”¨çš„屬性以åŠæŽ¡ç”¨åˆ†éš”符分隔的記錄å–值,還是略去它們",
+ "srf_paramdesc_arrayname": "如果已經給出,且 ArrayExtension å¯ç”¨ï¼Œé€™å°‡æœƒå»ºç«‹ä¸€å€‹å¸¶æœ‰æŒ‡å®šå稱的數組(沒有任何å¯è¦‹çš„輸出)",
+ "srf_paramdesc_propsep": "所請求屬性之間的分隔符",
+ "srf_paramdesc_manysep": "許多已經賦值的屬性å–值之間的分隔符",
+ "srf_paramdesc_recordsep": "記錄屬性的å–值之間的分隔符",
+ "srf_paramdesc_headersep": "當把\"headers\"設定為\"show\"或\"plain\"時,屬性å稱和å–值之間的分離符",
+ "srf_printername_hash": "雜湊",
+ "srf_paramdesc_hashname": "如果已經給出,且 HashTables 擴展å¯ç”¨ï¼Œé€™å°‡æœƒå»ºç«‹ä¸€å€‹å¸¶æœ‰æŒ‡å®šå稱的哈希表(沒有任何å¯è¦‹çš„輸出)",
+ "srf-printername-graph": "圖形",
+ "srf-paramdesc-graph-relation": "設定這些主題或å稱屬性是å¦ç‚ºçˆ¶ç´šæˆ–å­ç´š",
+ "srf-paramdesc-graph-nameprop": "設定一個屬性,並將其作為主題來使用,而ä¸æ˜¯å¯¦éš›çš„主題,例如:é é¢å稱",
+ "srf-paramdesc-graph-nodeshape": "設定圖形上å„節點的形狀",
+ "srf-paramdesc-graphname": "設定圖表標題",
+ "srf-paramdesc-graphsize": "設定圖形大å°ï¼ˆä»¥åƒç´ è¨ˆï¼‰",
+ "srf-paramdesc-graphlegend": "設定是å¦é¡¯ç¤ºåœ–形圖例",
+ "srf-paramdesc-graphlabel": "設定圖形標籤",
+ "srf-paramdesc-rankdir": "設定箭頭方å‘",
+ "srf-paramdesc-graphlink": "設定節點是å¦è¦é€£æŽ¥åˆ°å®ƒå€‘çš„ wiki é é¢",
+ "srf-paramdesc-graphcolor": "設定圖表顔色",
+ "srf-paramdesc-graph-wwl": "設定字詞æ›è¡Œé™åˆ¶ï¼ˆæŽ¡å­—元數)",
+ "srf-paramdesc-clustercolor": "設定å¢é›†æ¡†è‰²å½©",
+ "srf-paramdesc-highlight": "設定凸顯出節點",
+ "srf-paramdesc-highlightcolor": "設定所凸顯節點的字型色彩",
+ "srf-paramdesc-redlinkcolor": "設定紅連的字型色彩",
+ "srf-paramdesc-processcategory": "設定收集處ç†æ­¥é©Ÿçš„ wiki 分類",
+ "srf-paramdesc-showroles": "在圖形裡顯示相關任務",
+ "srf-paramdesc-showstatus": "設定處ç†ç¨‹åºç‹€æ…‹æ˜¯å¦æ‡‰è¢«å‘ˆç¾",
+ "srf-paramdesc-showresources": "在圖形裡顯示相關資æº",
+ "srf-paramdesc-showdiscussion": "設定是å¦è®“討論給呈ç¾å‡º",
+ "srf-paramdesc-showredlinks": "設定紅éˆæ˜¯å¦æ‡‰æª¢æŸ¥ä¸¦å‡¸é¡¯å‡º",
+ "srf-paramdesc-showcompound": "設定是å¦å‡¸é¡¯å‡ºåˆæˆç¯€é»žï¼Œä¾‹å¦‚å­è™•ç†æµç¨‹",
+ "srf-paramdesc-debug": "設定éŽç¨‹åœ–代碼是å¦æ‡‰åŒ…在é å…ˆæ¨™ç±¤",
+ "srf-paramdesc-graphvalidation": "將沒有分é…到任務的處ç†æ­¥é©Ÿé¡¯ç¤ºç‚ºç´…色。",
+ "srf-printername-datatables": "資料表",
+ "srf-ui-datatables-label-conditions": "æ¢ä»¶",
+ "srf-ui-datatables-label-parameters": "åƒæ•¸",
+ "srf-ui-datatables-label-filters": "欄ä½ç¯©é¸èˆ‡æœå°‹",
+ "srf-ui-datatables-label-information": "資訊",
+ "srf-ui-datatables-panel-disclaimer": "åƒæ•¸èˆ‡æ¢ä»¶æ˜¯å¯è®Šå‹•çš„,但僅為臨時性更改,並且會在é é¢é‡æ–°æ•´ç†å¾Œæ¨æ£„變動內容。",
+ "srf-ui-datatables-label-update-success": "表格更新æˆåŠŸ",
+ "srf-ui-datatables-label-update-error": "表格更新失敗。",
+ "srf-ui-datatables-label-placeholder-column-search": "æœå°‹ä¸­...",
+ "srf-ui-datatables-label-content-cache": "內容從本地端快å–å–得。",
+ "srf-ui-datatables-label-content-server": "內容從伺æœå™¨å–得。",
+ "srf-ui-datatables-label-multiselect-column-header": "å¯ç”¨æ¬„ä½",
+ "srf-ui-datatables-label-multiselect-column-noneselectedtext": "篩é¸è¨­å®š",
+ "srf-ui-datatables-label-multiselect-column-selectedtext": "欄ä½ç‚ºå¯è¦‹çš„",
+ "srf-ui-datatables-label-sEmptyTable": "表格裡沒有å¯ç”¨è³‡æ–™",
+ "srf-ui-datatables-label-sInfo": "顯示 _TOTAL_ 項目從 _START_ 至 _END_ 的內容",
+ "srf-ui-datatables-label-sInfoEmpty": "顯示 0 項目從 0 到 0 的內容",
+ "srf-ui-datatables-label-sInfoFiltered": "(從 _MAX_ total 項目篩é¸ï¼‰",
+ "srf-ui-datatables-label-sInfoThousands": ",",
+ "srf-ui-datatables-label-sLengthMenu": "顯示 _MENU_ 項目",
+ "srf-ui-datatables-label-sLoadingRecords": "正在載入...",
+ "srf-ui-datatables-label-sProcessing": "處ç†ä¸­...",
+ "srf-ui-datatables-label-sSearch": "æœå°‹ï¼š",
+ "srf-ui-datatables-label-sZeroRecords": "找ä¸åˆ°ç¬¦åˆçš„紀錄",
+ "srf-ui-datatables-label-oPaginate-sFirst": "第一",
+ "srf-ui-datatables-label-oPaginate-sLast": "最末",
+ "srf-ui-datatables-label-oPaginate-sNext": "下一é ",
+ "srf-ui-datatables-label-oPaginate-sPrevious": "上一é ",
+ "srf-ui-datatables-label-oAria-sSortAscending": ":啟用å‡å†ªæŽ’åºæ¬„ä½",
+ "srf-ui-datatables-label-oAria-sSortDescending": ":啟用é™å†ªæŽ’åºæ¬„ä½",
+ "srf-printername-tree": "樹狀çµæ§‹",
+ "srf-printername-ultree": "Ultree",
+ "srf-printername-oltree": "Oltree",
+ "srf-tree-noparentprop": "未æ供父屬性。在沒有指定父屬性的情æ³ä¸‹ç„¡æ³•æ§‹å»ºæ¨¹ç‹€çµæ§‹ã€‚",
+ "srf-tree-rootinvalid": "$1 ä¸æ˜¯æœ‰æ•ˆçš„é é¢æ¨™é¡Œã€‚",
+ "srf-tree-circledetected": "當æ’å…¥$1至樹狀çµæ§‹æ™‚åµæ¸¬åˆ°å¾ªç’°å¼•ç”¨ã€‚",
+ "srf-paramdesc-tree-parent": "包å«çˆ¶é é¢çš„屬性",
+ "srf-paramdesc-tree-root": "樹狀çµæ§‹çš„æ ¹é é¢",
+ "srf-paramdesc-tree-startlevel": "樹狀çµæ§‹çš„起始級別,例如:整åˆè‡³å…¶å®ƒæ¨¹ç‹€çµæ§‹",
+ "srf-printername-slideshow": "幻燈片",
+ "srf-paramdesc-delay": "以秒為單ä½çš„幻燈片延é²æ™‚é–“",
+ "srf-paramdesc-navigation-controls": "是å¦é¡¯ç¤ºå°ŽèˆªæŽ§åˆ¶",
+ "srf-paramdesc-effect": "幻燈片切æ›æ™‚所使用的效果",
+ "srf-printername-filtered": "已篩é¸",
+ "srf-paramdesc-filtered-views": "在çµæžœé¡¯ç¤ºè£¡æ‡‰å¯ç”¨çš„視圖。",
+ "srf-paramdesc-filtered-filter-position": "篩é¸ç›¸å°æ–¼è¦–圖的ä½ç½®ã€‚å…許的值為:「topã€ã€ã€Œbottomã€ï¼Œé è¨­ç‚ºï¼šã€Œtopã€ã€‚",
+ "srf-paramdesc-filtered-list-type": "清單類型。å…許的值為:「listã€ã€ã€Œulã€ã€ã€Œolã€ï¼Œé è¨­ç‚ºï¼šã€Œlistã€ã€‚",
+ "srf-paramdesc-filtered-list-template": "用於格å¼æ¸…單項目的模æ¿ã€‚",
+ "srf-paramdesc-filtered-list-named-args": "傳éžçµ¦è‡³æ¨¡æ¿çš„åƒæ•¸å稱。",
+ "srf-paramdesc-filtered-list-introtemplate": "用於在查詢çµæžœå‰é¡¯ç¤ºå…§å®¹çš„模æ¿çš„å稱。",
+ "srf-paramdesc-filtered-list-outrotemplate": "用於在查詢çµæžœå¾Œé¡¯ç¤ºå…§å®¹çš„模æ¿çš„å稱。",
+ "srf-paramdesc-filtered-calendar-start": "包å«äº‹ä»¶èµ·å§‹æ—¥æœŸçš„列å°è¼¸å‡ºå…§å®¹",
+ "srf-paramdesc-filtered-calendar-end": "包å«äº‹ä»¶çµæŸæ—¥æœŸçš„列å°è¼¸å‡ºå…§å®¹",
+ "srf-paramdesc-filtered-calendar-title": "列å°è¼¸å‡ºå…§å®¹æœ‰åŒ…å«åˆ°äº‹ä»¶çš„標題,ä¸å¯èˆ‡æ¨™é¡Œæ¨¡æ¿ä¸€åŒä½¿ç”¨ã€‚",
+ "srf-paramdesc-filtered-calendar-title-template": "在行事曆裡使用來格å¼åŒ–事件標題的模æ¿",
+ "srf-paramdesc-filtered-map-position": "列å°è¼¸å‡ºå…§å®¹åŒ…å«åœ°ç†ä½ç½®ã€‚",
+ "srf-paramdesc-filtered-map-icon": "所決定使用之地圖標示的列å°è¼¸å‡ºã€‚",
+ "srf-paramdesc-filtered-map-icons": "使用於在地圖裡這些值上的值與圖標å°æ‡‰ã€‚",
+ "srf-paramdesc-filtered-map-height": "地圖高度",
+ "srf-paramdesc-filtered-map-zoom": "地圖載入時的縮放層次。這å¯é€éŽä½¿ç”¨è€…來更改。<br>請查看:<i>地圖視圖最å°ç¸®æ”¾</i>與<i>地圖視圖最大縮放</i>",
+ "srf-paramdesc-filtered-map-min-zoom": "地圖最å°å¯ç¸®æ”¾å±¤æ¬¡",
+ "srf-paramdesc-filtered-map-max-zoom": "地圖最大å¯ç¸®æ”¾å±¤ç´š",
+ "srf-paramdesc-filtered-map-marker-cluster": "啟動或關閉èšé›†æ¨™è¨˜",
+ "srf-paramdesc-filtered-map-marker-cluster-max-zoom": "地圖標記ä»æœ‰èšé›†æ™‚的最大縮放層級。以上層級的標記則ä¸æœƒåšå‡ºèšé›†ã€‚",
+ "srf-paramdesc-filtered-map-marker-cluster-max-radius": "å¢é›†æœƒå¾žä¸­å¿ƒé»žèµ·è¦†è“‹çš„最大åŠå¾‘。é è¨­å€¼ç‚º 80(åƒç´ ï¼‰ã€‚",
+ "srf-paramdesc-filtered-map-marker-cluster-zoom-on-click": "當啟用後,點擊å¢é›†æœƒç¸®æ”¾è‡³ç•Œé™ã€‚",
+ "srf-filtered-selectorlabel-list": "清單",
+ "srf-filtered-selectorlabel-table": "表格",
+ "srf-filtered-selectorlabel-calendar": "行事曆",
+ "srf-filtered-selectorlabel-map": "地圖",
+ "srf-filtered-noscript-error": "å›  Javascript 未啟用而無法顯示çµæžœã€‚å‰è‡³$1。",
+ "srf-filtered-noscript-link-caption": "表格å¼è¡¨å–®çš„çµæžœ",
+ "srf-filtered-map-provider-missing-error": "沒有替「mapã€è¦–圖指定地圖æ供方。",
+ "srf-filtered-value-filter-and": "與",
+ "srf-filtered-value-filter-or": "或",
+ "srf-filtered-value-filter-placeholder": "é¸æ“‡ä¸€å€‹ç¯©é¸å€¼",
+ "srf-printername-d3chart": "D3 圖表",
+ "srf-printername-timeseries": "時間åºåˆ—圖表",
+ "srf-paramdesc-group": "系列分組按",
+ "srf-paramdesc-zoom": "啟用縮放",
+ "srf-paramdesc-datatable": "啟用資料表",
+ "srf-timeseries-zoom-out-of-range": "縮放範åœæœªç”¢ç”Ÿè¶³å¤ çš„資料",
+ "srf-printername-sparkline": "走勢圖表",
+ "srf-printername-listwidget": "清單å°å·¥å…·",
+ "srf-paramdesc-listtype": "指定清單類型",
+ "srf-paramdesc-widget": "å¯ç”¨å°å·¥å…·",
+ "srf-paramdesc-pageitems": "å„é é …ç›®",
+ "srf-printername-eventcalendar": "事件行事曆",
+ "srf-paramdesc-calendarfirstday": "æ¯é€±é–‹å§‹çš„第一天",
+ "srf-paramdesc-calendardefaultview": "當行事曆載入時的åˆå§‹è¦–圖",
+ "srf-paramdesc-calendarstart": "åˆå§‹è¡Œäº‹æ›†èµ·å§‹ï¼ˆæ—¥æœŸæˆ–日期時間的值)",
+ "srf-paramdesc-calendarlegend": "指定圖例ä½ç½®ä»¥åŠæ‰€åˆ†é…的篩é¸é …ç›®",
+ "srf-paramdesc-dayview": "以點擊日期數目來啟用日期檢視",
+ "srf-ui-eventcalendar-label-today": "今天",
+ "srf-ui-eventcalendar-label-month": "月",
+ "srf-ui-eventcalendar-label-week": "週",
+ "srf-ui-eventcalendar-label-day": "æ—¥",
+ "srf-ui-eventcalendar-label-listmonth": "月(清單)",
+ "srf-ui-eventcalendar-label-listweek": "週(清單)",
+ "srf-ui-eventcalendar-label-listday": "日(清單)",
+ "srf-ui-eventcalendar-label-allday": "æ•´æ—¥",
+ "srf-ui-eventcalendar-label-update-success": "事件行事曆更新æˆåŠŸã€‚",
+ "srf-ui-eventcalendar-label-update-error": "事件行事曆更新失敗。",
+ "srf-ui-eventcalendar-click-popup": "您是å¦è¦å»ºç«‹äº‹ä»¶ï¼Ÿ",
+ "srf-printername-dygraphs": "Dygraphs 圖表",
+ "srf-paramdesc-datasource": "å¯å­˜å–資料的來æºã€‚å…許的值為:「fileã€ã€ã€Œrawã€ã€ã€Œurlã€ï¼Œé è¨­ç‚ºï¼šã€Œfileã€",
+ "srf-paramdesc-errorbar": "使用到錯誤的æ¢ç‹€ã€‚å…許的值為:「fractionã€ï¼ˆå€¼çš„ä¿¡è³´å€é–“)ã€ã€Œsigmaã€ï¼ˆå€¼çš„標準差)ã€ã€Œrangeã€ï¼ˆè‡ªå®šç¾©çš„值範åœï¼‰",
+ "srf-paramdesc-movingaverage": "顯示一段日å­è£¡çš„å¹³å‡ï¼ˆé›¶ä»£è¡¨æ²’有移動平å‡ï¼‰",
+ "srf-paramdesc-yaxislabel": "在 Y 軸上顯示的æè¿°",
+ "srf-paramdesc-xaxislabel": "在 X 軸上顯示的æè¿°",
+ "srf-paramdesc-unit": "å–®ä½",
+ "srf-printername-pagewidget": "é é¢å°å·¥å…·",
+ "srf-printername-incoming": "連入屬性",
+ "srf-paramdesc-count": "設定是å¦è¨ˆç®—éˆå…¥å±¬æ€§çš„數目",
+ "srf-paramdesc-min": "最å°æˆ–臨界值",
+ "srf-paramdesc-excludeproperty": "從çµæžœé›†è£¡æŽ’除的屬性",
+ "srf-printername-media": "多媒體播放器",
+ "srf-paramdesc-mediainspector": "顯示有關指定媒體元素的詳細資訊",
+ "srf-ui-mediaplayer-label-previous": "上一個",
+ "srf-ui-mediaplayer-label-play": "播放",
+ "srf-ui-mediaplayer-label-pause": "æš«åœ",
+ "srf-ui-mediaplayer-label-next": "下一個",
+ "srf-ui-mediaplayer-label-stop": "åœæ­¢",
+ "srf-ui-mediaplayer-label-mute": "éœéŸ³",
+ "srf-ui-mediaplayer-label-unmute": "å–消éœéŸ³",
+ "srf-ui-mediaplayer-label-volume-max": "最大音é‡",
+ "srf-ui-mediaplayer-label-shuffle": "隨機播放",
+ "srf-ui-mediaplayer-label-shuffle-off": "關閉隨機播放",
+ "srf-ui-mediaplayer-label-repeat": "é‡è¤‡",
+ "srf-ui-mediaplayer-label-repeat-off": "關閉é‡è¤‡",
+ "srf-ui-mediaplayer-label-full-screen": "全螢幕",
+ "srf-ui-mediaplayer-label-restore-screen": "還原螢幕",
+ "srf-spreadsheet-link": "試算表",
+ "srf-paramdesc-spreadsheet-filename": "生æˆçš„檔案格å¼ã€‚å…許值為:xlsxã€xlsã€odsã€csv。é è¨­å€¼ç‚ºï¼šxlsx",
+ "srf-paramdesc-spreadsheet-templatefile": "來自「Fileã€å‘½å空間的試算表檔案å稱,用於格å¼æ‰€ç”¢ç”Ÿçš„檔案",
+ "srf-paramdesc-icalendar-timezone": "逗號分隔的時å€æ¸…å–®",
+ "srf-paramdesc-gantt-diagramtitle": "圖表å稱",
+ "srf-paramdesc-gantt-diagramtheme": "圖表主題",
+ "srf-paramdesc-gantt-axisformat": "X 軸:日期格å¼",
+ "srf-error-gantt-mermaid-not-installed": "需è¦å®‰è£ Mermaid 擴充。",
+ "srf-printername-gantt": "甘特圖"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/i18n/zh-hk.json b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hk.json
new file mode 100644
index 00000000..58281b28
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/i18n/zh-hk.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liuxinyu970226"
+ ]
+ },
+ "srf_printername_hash": "雜湊"
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/phpunit.xml.dist b/www/wiki/extensions/SemanticResultFormats/phpunit.xml.dist
new file mode 100644
index 00000000..103a0c6e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/phpunit.xml.dist
@@ -0,0 +1,32 @@
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ bootstrap="tests/bootstrap.php"
+ cacheTokens="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ stopOnError="false"
+ stopOnFailure="false"
+ stopOnIncomplete="false"
+ stopOnSkipped="false"
+ verbose="true">
+ <testsuites>
+ <testsuite name="semantic-result-formats-unit">
+ <directory>tests/phpunit/Unit</directory>
+ </testsuite>
+ <testsuite name="semantic-result-formats-integration">
+ <directory>tests/phpunit/Integration</directory>
+ </testsuite>
+ </testsuites>
+ <filter>
+ <whitelist addUncoveredFilesFromWhitelist="true">
+ <directory suffix=".php">formats</directory>
+ <directory suffix=".php">src</directory>
+ <file>SemanticResultFormats.hooks.php</file>
+ <file>SemanticResultFormats.parser.php</file>
+ <file>SemanticResultFormats.php</file>
+ <file>SemanticResultFormats.utils.php</file>
+ </whitelist>
+ </filter>
+</phpunit>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/LICENSE b/www/wiki/extensions/SemanticResultFormats/resources/LICENSE
new file mode 100644
index 00000000..59113971
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/LICENSE
@@ -0,0 +1,3 @@
+See [1] the license for the specific language governing permissions and limitations under which each third party plug-in operates.
+
+[1] http://www.semantic-mediawiki.org/wiki/Help:Plug-ins \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/docs/jsduck.external.js b/www/wiki/extensions/SemanticResultFormats/resources/docs/jsduck.external.js
new file mode 100644
index 00000000..6d87218a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/docs/jsduck.external.js
@@ -0,0 +1,37 @@
+/**
+ * @class jQuery
+ * @source <http://api.jquery.com/>
+ */
+
+/**
+ * @method ajax
+ * @source <http://api.jquery.com/jQuery.ajax/>
+ * @return {jqXHR}
+ */
+
+/**
+ * @class jQuery.Event
+ * @source <http://api.jquery.com/Types/#Event>
+ */
+
+/**
+ * @class jQuery.Promise
+ * @source <http://api.jquery.com/Types/#Promise>
+ */
+
+/**
+ * @class jQuery.Deferred
+ * @mixins jQuery.Promise
+ * @source <http://api.jquery.com/jQuery.Deferred/>
+ */
+
+/**
+ * @class jQuery.jqXHR
+ * @source <http://api.jquery.com/Types/#jqXHR>
+ * @alternateClassName jqXHR
+ */
+
+/**
+ * @class QUnit
+ * @source <http://api.qunitjs.com/>
+ */
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.query.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.query.js
new file mode 100644
index 00000000..17a4fdbb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.query.js
@@ -0,0 +1,274 @@
+/**
+ * SRF JavaScript for the api/query
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Private methods and objects used within the class
+ *
+ * @since 1.9
+ */
+ var results = new srf.api.results();
+
+ /**
+ * Public API namespace declaration
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api = srf.api || {};
+
+ /**
+ * Base constructor for objects representing a api.query instance
+ *
+ * @since 1.9
+ */
+ srf.api.query = function() {};
+
+ /**
+ * Public methods to access information via the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.query.prototype = {
+
+ conditions: {
+
+ /**
+ * Builds a conditional statement
+ *
+ * For example
+ * operators ( ::, ::>, ::< etc.)
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ build: function ( property, value, operator ){
+ return '[[' + property + ( operator || '::' ) + value + ']]';
+ }
+ },
+
+ printouts: {
+
+ /**
+ * Normalize printouts in order to get access via key reference
+ *
+ * e.g. |?Has location=location will be transformed into an
+ * array ["Has location", "location"]
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ toList: function( printouts ){
+ var list = [];
+ var identifier = new RegExp( '[\\?&]' + '(.*?)' + '[=]' );
+
+ $.each( printouts, function( value, text ) {
+ // Split the text and find anything that is between ? and = otherwise
+ // split the string just after ?
+ var match = text.split( identifier );
+ if( match !== null ){
+ if ( match[0] === '' ){
+ // match ["", "Has lcoation", "location"]
+ list.push( [ match[1], match[2]] );
+ }else{
+ list.push( match[0].split( '?' )[1] );
+ }
+ }
+ } );
+ return list;
+ },
+
+ /**
+ * Find printout matches
+ *
+ * @since 1.9
+ * @type Object
+ */
+ search: {
+
+ /**
+ * Find printout that matches a specific identifier
+ *
+ * e.g. |?Has location=location
+ *
+ * search.identifier( [...], 'location' ) will result in "Has location"
+ *
+ * @since 1.9
+ * @type Object
+ * @type Object
+ *
+ * @return array
+ */
+ identifier: function( printouts, identifier ){
+ var property = '';
+ var regexS = '[\\?&]' + '(.*?)' + '=' + identifier;
+ var regex = new RegExp(regexS);
+
+ $.each( printouts , function( key, value ) {
+ if( value.match( regex ) !== null ){
+ property = value.match( regex )[1];
+ }
+ } );
+ return property;
+ },
+
+ /**
+ * Returns properties for a specific type where properties
+ * aren't marked with an identifier ( |?property=indentifier)
+ *
+ * SMWQUERY printouts, SMWAPI printrequests, ["_str","_txt"]
+ *
+ * For example
+ * type( printouts, printrequests, ["_str"] )
+ * result in ["Has location", "..."] that matches the type _str
+ *
+ * Filter all printout properties that are of type [...] and check against
+ * the printout list to indentify which of these printouts do not
+ * carry an additional identifier because those are not eligible
+ * to beused as filter properties
+ *
+ * @since 1.9
+ * @type Object
+ * @type Object
+ * @type Object
+ *
+ * @return array
+ */
+ type: function( printouts, printrequests, dataTypes ){
+ // Cache printouts, printrequests
+ var po = srf.api.query.prototype.printouts.toList( printouts ),
+ pr = srf.api.results.prototype.printrequests();
+ pr.toArray( printrequests );
+
+ // Normalize printouts to an amendable structure
+ function normalize(){
+ var matches = [];
+ // Match printouts against the list of available printrequests
+ $.each( po, function( index, property ) {
+ if ( typeof property === 'object' ) {
+ if ( $.inArray( pr.getTypeId( property[1] ), dataTypes ) > -1 ){
+ matches.push( property[0] );
+ }
+ } else {
+ if ( $.inArray( pr.getTypeId( property ), dataTypes ) > -1 ){
+ matches.push( property );
+ }
+ }
+ } );
+ return matches;
+ }
+
+ // Find those properties that are without an identifier
+ function withoutIdentifier( list ){
+ var matches = [];
+ $.each( list, function( index, property ) {
+ if ( $.inArray( property, po ) > -1 ) {
+ matches.push( property );
+ }
+ } );
+ return matches;
+ }
+
+ var record = withoutIdentifier( normalize() );
+ return record.length > 0 ? srf.api.util.prototype.array.unique( record ) : '';
+ }
+ }
+ },
+
+ /**
+ * Returns a concatenated query string
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return string
+ */
+ toString: function( options ){
+
+ var printouts = '';
+ if ( options.printouts ){
+ $.each( options.printouts , function( key, value ) {
+ printouts = printouts + '|' + value;
+ } );
+ }
+
+ var parameters = '';
+ $.each( options.parameters , function( key, value ) {
+ parameters = parameters + '|' + key + '=' + value;
+ } );
+
+ var conditions = '';
+ if ( typeof options.conditions === 'object' ) {
+ $.each( options.conditions , function( key, value ) {
+ conditions = conditions + value;
+ } );
+ } else {
+ conditions = options.conditions;
+ }
+
+ return conditions + printouts + parameters;
+ },
+
+ /**
+ * Return results from the SMWAPI interface as callback
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ fetch: function( query, callback, log ){
+
+ // Log data is only visible while in debug mode( &debug=true )
+ if ( log ){
+ var startDate = new Date();
+ srf.log( 'Query: ' + query );
+ }
+
+ $.ajax( {
+ url: mw.util.wikiScript( 'api' ),
+ dataType: 'json',
+ data: {
+ 'action': 'ask',
+ 'format': 'json',
+ 'query' : query
+ }
+ } )
+ .done( function ( data ) {
+ if ( log ){
+ srf.log( 'Hash: ' + data.query.meta.hash );
+ srf.log( 'Fetched: ' + ( new Date().getTime() - startDate.getTime() ) + ' ms ' + '( ' + data.query.meta.count + ' object )' );
+ }
+
+ // Return data to the callback
+ if ( typeof callback === 'function' ) {
+ callback.call( this, true, data );
+ }
+ return;
+ } )
+ .fail( function ( error ) {
+ if ( typeof callback === 'function' ) {
+ callback.call( this, false, error );
+ }
+ return;
+ } );
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.results.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.results.js
new file mode 100644
index 00000000..f6c1f04b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.api.results.js
@@ -0,0 +1,267 @@
+/**
+ * SRF JavaScript for the api/results
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* global wgMonthNames:true */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var timeLocales = {
+ monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+ dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
+ dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
+ amDesignator: 'AM',
+ pmDesignator: 'PM'
+ };
+
+ // Map wgMonthNames and create an indexed array
+ var monthNames = [];
+ $.map ( mw.config.get( 'wgMonthNames' ), function( value, key ) {
+ if( value !== '' ){
+ monthNames.push( value );
+ }
+ } );
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ /**
+ * API namespace declaration
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api = srf.api || {};
+
+ /**
+ * Base constructor for objects representing a api.results instance
+ *
+ * @since 1.9
+ */
+ srf.api.results = function() {};
+ srf.api.util = function() {};
+
+ /**
+ * Public to access results information retrieved through the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.util.prototype = {
+
+ /**
+ * Array helper functions
+ *
+ * @since 1.9
+ */
+ array:{
+ /**
+ * Array unique function
+ *
+ * $.unique only allows to be an array of DOM elements therefore
+ * this returns a nromal "array" with no duplicates
+ *
+ * @credits http://paulirish.com/2010/duck-punching-with-jquery/
+ *
+ * @since 1.9
+ */
+ unique: function( arr ){
+ if ( !!arr[0].nodeType ){
+ return $.unique.apply( this, arguments );
+ } else {
+ return $.grep(arr,function(v,k){ return $.inArray(v,arr) === k; } );
+ }
+ }
+ }
+ };
+
+ /**
+ * Public to access results information retrieved through the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.results.prototype = {
+
+ /**
+ * Collection related to printrequests and properties
+ *
+ * @since 1.9
+ */
+ printrequests: function( printrequests ){
+ var list = printrequests;
+
+ return {
+ list: list,
+
+ /**
+ * Returns a key reference array
+ *
+ * Transforms printrequest objects into an accessible flat array
+ * allowing a key reference
+ *
+ * Call as class instance via printrequests( [...] ).toArray()
+ * or as operational method via printrequests().toArray( [...] )
+ *
+ * @since 1.9
+ * @type Object
+ */
+ toArray: function ( printrequests ){
+ var tList = {};
+ printrequests = printrequests || list;
+
+ if ( printrequests !== undefined ){
+ $.map( printrequests, function( key, index ) {
+ tList[key.label] = { typeid: key.typeid, position: index, meta: key.meta };
+ } );
+ }
+ return list = tList;
+ },
+
+ /**
+ * Returns typeid for a property
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getTypeId: function ( property ){
+ return list[property].typeid || null;
+ },
+
+ /**
+ * Returns some meta data for a property
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getMetaData: function ( property ){
+ return list[property].meta || null;
+ },
+
+ /**
+ * Returns the position for a property
+ *
+ * Printouts in the result object are not sorted
+ * therefore this returns its position in accordance with the query
+ *
+ * @since 1.9
+ */
+ getPosition: function ( property ){
+ return list[property].position || null;
+ }
+ };
+ },
+
+ /**
+ * Collection related to data values
+ *
+ * @since 1.9
+ */
+ dataValues: {
+
+ /**
+ * Methods related to time data value
+ *
+ * @since 1.9
+ */
+ time: {
+
+ /**
+ * Returns normalized timestamp as JS date object
+ *
+ * @since 1.9
+ * @type Object
+ */
+ parseDate: function( d ) {
+ if ( typeof d === 'object') {
+ return d;
+ }
+ if ( typeof d === 'number' ) {
+ return new Date( d * 1000 );
+ }
+ if ( typeof d === 'string' ) {
+ if ( d.match(/^\d+(\.\d+)?$/) ) {
+ return new Date( parseFloat( d ) * 1000 );
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Create a new JavasScript date object based on the timestamp and return
+ * an ISO string
+ *
+ * @see SMWTimeValue::getISO8601Date()
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getISO8601Date: function( timestamp ) {
+ var d = this.parseDate( timestamp );
+ return d !== null ? d.toISOString() : null;
+ },
+
+ /**
+ * Returns a formatted time (HH:MM:SS)
+ *
+ * @param string|Date time
+ * @return string
+ */
+ getTime: function( time ) {
+ var d = typeof time === 'object' ? time : this.parseDate( time );
+ return ( d.getHours() < 10 ? '0' + d.getHours() : d.getHours() ) +
+ ':' + ( d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes() ) +
+ ':' + ( d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds() );
+ },
+
+ /**
+ * Returns a formatted date
+ *
+ * @param string|Date
+ * @param string format
+ * @return string
+ */
+ getDate: function( date, format ) {
+ var d = typeof date === 'object' ? date : this.parseDate( date ),
+ formatDate = '';
+
+ switch( format ) {
+ case 'dmY':
+ formatDate = d.getDate() + '.' + ( '' + d.getMonth() + 1 ) + '.' + d.getFullYear();
+ break;
+ case 'Ymd':
+ formatDate = d.getFullYear() + '.' + ( '' + d.getMonth() + 1 ) + '.' + d.getDate();
+ break;
+ default:
+ formatDate = d.getDate() + ' ' + monthNames[d.getMonth()] + ' ' + d.getFullYear();
+ }
+
+ return formatDate;
+ },
+
+ /**
+ * Returns date
+ *
+ * @param string timestamp
+ * @param string format
+ * @return string
+ */
+ getMediaWikiDate: function( timestamp, format ) {
+ var date = this.parseDate( timestamp );
+ return this.getDate( date, format ) + ' ' + this.getTime( date );
+ }
+ }
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.css b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.css
new file mode 100644
index 00000000..18641276
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.css
@@ -0,0 +1,109 @@
+/**
+ * CSS for SRF common objects
+ *
+ * @since 1.8
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+.srf-processing-text{
+ padding-left: 2.1em;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+.srf-loading-dots {
+ background: url('data:image/gif;base64,R0lGODlhIgAUAMQRAOjp6dTW19ze3+Xm54iKjevs7IKEh/f396Olp5ianPz8/Judn9fY2YGDhp+ho4CChdHT1P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxRThFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNkVFNURCOUIyREYxMUUyQTBEQUNFNUIzREVGNjg0MyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNkVFNURCOEIyREYxMUUyQTBEQUNFNUIzREVGNjg0MyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyMDhFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxRThFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAkyABEALAAAAAAiABQAAAVeYCSOZGmeaKqubOu+cCzPdM0iBIGYgCAUPB8Q5XgYHw4SAMKEAJRNJ8pwfBhIgagAq0U1qg1ukyFmkk+L6oI0iD5H7ebbdEgYEweSYhAIDEp7fX82hIWGh4iJiosoIQAh+QQJMgARACwAAAAAIgAUAAAFZGAkjmRpnmiqrmzrvnAsz3TNFoIAmAhBICZArpACQI6Q3cjxaD4cJCNSaRIgIQGSwfkwkAJXAYpxzY4a3Mb3ykBJjwPSgrsgDa5U0yAQGChIBwlNCQckCnt9NoqLjI2Oj5CRKSEAIfkEBTIAEQAsAAAAACIAFAAABWNgJI5kaZ5oqq5s675wLM90zRaCAJi4biIEAiIFgBghu1HxmBQ5HtCHAyU4QgKk6hE7MkQfBhTDyhWNt6TGt4FaGgckNwQ+WnwXqUEgMFCU9Hx+IwcJUAkHNomKi4yNjo+QKCEAOw==') no-repeat left center;
+ padding: 5px 0 5px 35px;
+ vertical-align: middle;
+}
+
+.srf-spinner.text{
+ color: #666;
+ padding-left: 1.6em;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+/* Spinner for left side in-text*/
+.srf-spinner.mw-small-spinner {
+ background-position:left;
+ vertical-align: middle;
+ display:inline-block;
+ padding: 0px !important;
+}
+
+/* Sppiner for image center*/
+.srf-spinner-img.mw-small-spinner {
+ vertical-align: middle;
+ display:inline-block;
+ padding: 0px !important;
+}
+
+.srf-notification-content {
+ font-size: 0.8em;
+ color: #fff;
+ padding: 2px;
+ text-align: left;
+}
+
+/**
+ * User preference
+ */
+fieldset#mw-prefsection-smw-srf {
+ border: 0px solid #2a4b8d;
+ border-top: 1px solid #2a4b8d;
+ margin-top: 25px;
+ clear: both;
+}
+
+fieldset#mw-prefsection-smw-srf-eventcalendar-options {
+ border: 0px solid #2a4b8d;
+ border-top: 1px solid #ddd;
+ margin-top: 0px;
+}
+
+fieldset#mw-prefsection-smw-srf-datatables-options {
+ border: 0px solid #2a4b8d;
+ border-top: 1px solid #ddd;
+ margin-top: 15px;
+}
+
+#mw-prefsection-smw-srf .oo-ui-fieldsetLayout-header .oo-ui-labelElement-label:before {
+ content: "⯈ ";
+}
+
+#mw-prefsection-smw-srf .oo-ui-fieldsetLayout-header .oo-ui-labelElement-label {
+ color: #2a4b8d;
+}
+
+#mw-prefsection-smw-srf .oo-ui-panelLayout-padded {
+ padding-top: 0em;
+ padding-bottom: 0em;
+}
+
+#mw-prefsection-smw-srf-eventcalendar-options .oo-ui-fieldsetLayout-group,
+#mw-prefsection-smw-srf-datatables-options .oo-ui-fieldsetLayout-group {
+ columns: 2;
+}
+
+#mw-prefsection-smw-srf .oo-ui-fieldLayout-field {
+ margin-top: 10px;
+}
+
+/**
+ * Responsive settings
+ */
+@media screen and (max-width: 800px) {
+
+ #mw-prefsection-smw-srf-eventcalendar-options .oo-ui-fieldsetLayout-group,
+ #mw-prefsection-smw-srf-datatables-options .oo-ui-fieldsetLayout-group {
+ columns: 1;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.js
new file mode 100644
index 00000000..1244949a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.js
@@ -0,0 +1,130 @@
+/**
+ * This file is part of the Semantic Result Formats Extension
+ * @see https://semantic-mediawiki.org/wiki/Srf
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
+ * @author mwjames
+ */
+
+/**
+ * Declares global srf instance and namespace
+ *
+ * @class srf
+ */
+var instance = ( function () {
+ 'use strict';
+
+ /*global console:true message:true */
+
+ var instance = {};
+
+ instance.log = function( message ) {
+ if ( typeof mediaWiki === 'undefined' ) {
+ if ( typeof console !== 'undefined' ) {
+ console.log( 'SRF: ', message );
+ }
+ } else {
+ return mediaWiki.log.call( mediaWiki.log, 'SRF: ', message );
+ }
+ };
+
+ instance.msg = function() {
+ if ( typeof mediaWiki === 'undefined' ) {
+ message = window.wgSRFMessages[arguments[0]];
+
+ for ( var i = arguments.length - 1; i > 0; i-- ) {
+ message = message.replace( '$' + i, arguments[i] );
+ }
+ return message;
+ } else {
+ return mediaWiki.msg.apply( mediaWiki.msg, arguments );
+ }
+ };
+
+ /**
+ * Declares utility namespace
+ */
+ instance.util = {};
+
+ /**
+ * Declares formats namespace
+ */
+ instance.formats = {};
+
+ /**
+ * Access settings array
+ *
+ * @since 1.9
+ *
+ * @return {mixed}
+ */
+ instance.settings = {
+
+ /**
+ * Returns list of available settings
+ *
+ * @since 1.9
+ *
+ * @return {Object}
+ */
+ getList: function() {
+ return mediaWiki.config.get( 'srf-config' ).settings;
+ },
+
+ /**
+ * Returns a specific settings value
+ *
+ * @since 1.9
+ *
+ * @param {string} key options to be selected
+ *
+ * @return {mixed}
+ */
+ get: function( key ) {
+ if( typeof key === 'string' ) {
+ return this.getList()[key];
+ }
+ return undefined;
+ }
+ };
+
+ /**
+ * Returns SRF version
+ *
+ * @since 1.9
+ *
+ * @return {string}
+ */
+ instance.version = function() {
+ return mediaWiki.config.get( 'srf-config' ).version;
+ };
+
+ // Alias
+ instance.Util = instance.util;
+
+ return instance;
+} )();
+
+// Assign namespace
+window.srf = window.semanticFormats = instance; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.css b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.css
new file mode 100644
index 00000000..bb6df206
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.css
@@ -0,0 +1,22 @@
+/**
+ * CSS for SRF gridview plugin
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gridview
+ *
+ * @since 1.8
+ * @release 0.2
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* Changes have to comply with UI_BASE */
+.srf-gridview-query-link {
+ font-size:12px;
+ font-weight: normal;
+ margin-top:4px;
+ margin-right:3px;
+ color:#ddd;
+ float:right;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.js
new file mode 100644
index 00000000..b3d48303
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.grid.js
@@ -0,0 +1,242 @@
+/**
+ * JavaScript for SRF GridView plugin
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gridview
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( srf, $ ) {
+
+ "use strict";
+
+ /*global mw:true semanticFormats:true*/
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var h = mw.html;
+ var UI_BASE = 'srf-gridview';
+
+ /**
+ * Add tab li element
+ * @var Object
+ */
+ function _addTabLink( tab ){
+ return '<li><a href="#' + tab.id + '">' + tab.msg +'</a></li>';
+ }
+
+ /**
+ * Add tab element
+ * @var Object
+ */
+ function _addTabElement( options ){
+ return options.context.after( h.element( 'div', {
+ 'id' : options.id,
+ 'class' : options.elemClass
+ }, new h.Raw( options.content )
+ ) );
+ }
+
+ /**
+ * Transform data into a structure like counter, series, data item, data value
+ * @var array
+ */
+ function _transformData( options ){
+ var gridData = [],
+ counter = 0;
+
+ // Data array
+ for ( var j = 0; j < options.data.length; ++j ) {
+ var ttSeries = options.series[j];
+ for ( var i = 0; i < options.data[j].length; ++i ) {
+ var row = { id: ++counter , series: ttSeries.label, item: options.data[j][i][0], value: options.data[j][i][1] };
+ gridData.push( row );
+ }
+ }
+ return gridData;
+ }
+
+ ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+ // Should be initialized but if it isn't create an object
+ srf.util = srf.util || {};
+
+ /**
+ * Constructor
+ * Class reference by using new srf.util.grid( options );
+ *
+ * @var Object
+ */
+ srf.util.grid = function( settings ) {
+
+ // Set general class and id identifier
+ var options = $.extend( {
+ 'tableID' : settings.id + '-grid',
+ 'pagerID' : settings.id + '-grid-pager',
+ 'baseClass' : UI_BASE,
+ 'tableClass': UI_BASE + '-table',
+ 'pageClass' : UI_BASE + '-table-pager',
+ 'queryClass': UI_BASE + '-query-link'
+ }, settings );
+
+ $.extend( this, options );
+
+ // Self-invoked init() for direct access to the class reference
+ this.init();
+ };
+
+ srf.util.grid.prototype = {
+ /**
+ * Initializes grid called by the constructor
+ * @var Object
+ */
+ init: function () {
+ var options = this;
+ return this.context.each( function() {
+
+ var obj = $( this ),
+ //options = this,
+ height = obj.height(),
+ width = options.widthBorder !== undefined ? obj.width() - options.widthBorder : obj.width() - 30,
+ tabs = [];
+
+ // Tabs definition
+ tabs.chart = _addTabLink( { id: options.id, msg: mw.msg( 'srf-ui-gridview-label-chart-tab' ) } );
+ tabs.data = _addTabLink( { id: options.id + '-data', msg: mw.msg( 'srf-ui-gridview-label-data-tab' ) } );
+ tabs.info = _addTabLink( { id: options.id + '-info', msg: mw.msg( 'srf-ui-gridview-label-info-tab' ) } );
+
+ // Add tab navigation
+ obj.prepend( '<ul>' + tabs.chart +
+ ( options.data.data !== undefined && options.data.data.length > 0 ? tabs.data : '' ) +
+ ( options.info !== undefined && options.info !== '' ? tabs.info : '' ) + '</ul>'
+ );
+
+ var containerContext = obj.find( '.container' );
+
+ // Add info tab element
+ if ( options.info !== undefined && options.info !== '' ){
+ _addTabElement( {
+ context: containerContext,
+ content: options.info,
+ id : options.id + '-info',
+ elemClass: options.baseClass + '-info-tab'
+ } );
+ }
+
+ // Add data tab element
+ if ( options.data.data !== undefined && options.data.data.length > 0 ){
+ _addTabElement( {
+ context: containerContext,
+ content: '',
+ id : options.id + '-data',
+ elemClass: options.baseClass + '-data-tab'
+ } );
+ }
+
+ // Init data table
+ var tableContext = obj.find( '#' + options.id + '-data');
+
+ tableContext
+ .prepend( '<table id="' + options.tableID + '" class="' + options.tableClass + '"></table>' )
+ .prepend( '<div id="' + options.pagerID + '" class="' + options.pagerClass + '"></div>' );
+ tableContext
+ .css( { width: width, height: height } );
+
+ // Create tabs ui
+ obj.tabs();
+
+ // Tabs height can vary (due to CSS) therefore after tabs instance was
+ // created get the height
+ var _tabs = obj.find( '.ui-tabs-nav' );
+
+ // Create Special:Ask query link [+]
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Ask' || options.data.sask === undefined ){
+ obj.find( '.' + options.queryClass )
+ .empty();
+ } else {
+ _tabs.prepend( '<span class="' + options.queryClass + '">' + options.data.sask + '</span>' );
+ obj.find( '.' + options.queryClass )
+ .find( 'a' )
+ .attr( 'title', mw.msg( 'ask' ) );
+ }
+
+ var gridContext = obj.find( '.' + options.tableClass ),
+ columnWidth = ( width / 2 ) - 5,
+ tableHeight = height - 100 - _tabs.outerHeight();
+
+ // Adopt data item output
+ var colModelItem = '';
+ if ( options.data.fcolumntypeid === '_dat' ) {
+ // Fetch default date display
+ var dateFormat = mw.user.options.get( 'date' );
+ if ( dateFormat.indexOf( 'ISO' ) >= 0 ){
+ dateFormat = "Y-m-d H:i:s";
+ } else {
+ dateFormat = 'd M Y';
+ }
+
+ colModelItem = {
+ name:'item',
+ index:'item',
+ width: columnWidth,
+ align:'center',
+ sorttype:'date',
+ formatter:'date',
+ formatoptions: { srcformat: 'U', newformat: dateFormat }
+ };
+ } else {
+ colModelItem = { name:'item', index:'item', width: columnWidth };
+ }
+
+ // Create grid instance
+ // @see http://www.trirand.com/jqgridwiki/doku.php
+ gridContext.jqGrid( {
+ datatype: 'local',
+ data: _transformData( { data: options.data.data, series: options.data.series } ),
+ colNames:[
+ 'id',
+ mw.msg( 'srf-ui-gridview-label-series' ),
+ mw.msg( 'srf-ui-gridview-label-item' ),
+ mw.msg( 'srf-ui-gridview-label-value' )
+ ],
+ colModel :[
+ { name:'id', index:'id', sorttype: 'int', hidden:true },
+ { name:'series', index:'series', width: 0 },
+ colModelItem,
+ { name:'value', index:'value', width: columnWidth, align:"right" }
+ ],
+ pager: '#' + options.pagerID ,
+ height: tableHeight,
+ rowList:[10,20,30,40,50],
+ ignoreCase: true,
+ grouping:true,
+ groupingView : {
+ groupField : ['series'],
+ groupColumnShow : [false]
+ },
+ sortname: 'item',
+ sortorder: 'asc',
+ viewrecords: true,
+ hidegrid: false
+ } );
+
+ // Init column search
+ gridContext.jqGrid( 'filterToolbar', {
+ stringResult: true,
+ searchOnEnter: false,
+ defaultSearch: "cn"
+ } );
+ } );
+ },
+
+ resize: function( ){
+ // Do something here
+ }
+ };
+
+} )( semanticFormats, jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.html.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.html.js
new file mode 100644
index 00000000..50519c9b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.html.js
@@ -0,0 +1,64 @@
+/**
+ * SRF JavaScript for srf.util namespace
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/*global semanticFormats:true mediaWiki:true*/
+( function( $, mw, srf ) {
+ 'use strict';
+
+
+ ////////////////////////// PRIVATE OBJECTS //////////////////////////
+
+ var html = mw.html;
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ $.extend( srf.util.prototype, {
+
+ html:{
+
+ /**
+ * Returns a dropdown element
+ *
+ * e.g.
+ * options {
+ * list: ['...', '...'],
+ * id: 'printouts',
+ * selectClass: 'printouts',
+ * browser: 'firefox',
+ * disabled: 'disabled'
+ * }
+ *
+ * @since 1.9
+ */
+ dropdown: function( options ){
+ // @note The dropdown size behaves differently in some browsers
+ // therefore a css class is assigned for adjustments
+ var dropdown = '';
+ if ( typeof options.list === 'object' ) {
+ $.each( options.list, function( index, text ) {
+ if ( typeof text === 'object' ) {
+ text = text[0];
+ }
+ dropdown = dropdown + html.element( 'option', { 'value': index }, text );
+ } );
+ }
+
+ return html.element( 'div',{ 'class': 'select-wrap-' + options.browser || 'all' },
+ new html.Raw ( html.element( 'select', {'id': options.id, 'class': options.selectClass, 'disabled': options.disabled || false },
+ new html.Raw( html.element( 'option', { 'value': '' }, '' ) + dropdown ) )
+ )
+ );
+ }
+ }
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats );
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.js b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.js
new file mode 100644
index 00000000..a9c687ca
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/ext.srf.util.js
@@ -0,0 +1,364 @@
+/*!
+ * This file is part of the Semantic Result Formats Extension
+ * @see https://www.semantic-mediawiki.org/wiki/SRF
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.8
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var html = mw.html;
+
+ var _cacheTime = 1000 * 60 * 60 * 24; // 24 hours
+
+ var _CL_mwspinner = 'mw-small-spinner';
+ var _CL_srfIspinner = 'srf-spinner-img';
+ var _CL_srfspinner = 'srf-spinner';
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ /**
+ * Module for formats utilities namespace
+ * @since 1.8
+ * @type Object
+ */
+ srf.util = srf.util || {};
+
+ /**
+ * Constructor
+ * @var Object
+ */
+ srf.util = function( settings ) {
+ $.extend( this, settings );
+ };
+
+ srf.util.prototype = {
+ /**
+ * Get image url
+ * @since 1.8
+ * @param options
+ * @param callback
+ * @return string
+ */
+ getImageURL: function( options, callback ) {
+ var title = options.title,
+ cacheTime = options.cachetime;
+
+ // Get cache time
+ cacheTime = cacheTime === undefined ? _cacheTime : cacheTime;
+
+ // Get url from cache otherwise do an ajax call
+ var url = $.jStorage.get( title );
+
+ if ( url !== null ) {
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, url ); // brings the scope to the callback
+ }
+ return;
+ }
+
+ // Get url via ajax
+ $.getJSON(
+ mw.config.get( 'wgScriptPath' ) + '/api.php',
+ {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'imageinfo',
+ 'iiprop': 'url',
+ 'titles': title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p].imageinfo;
+ for ( var i in info ) {
+ if ( info.hasOwnProperty( i ) ) {
+ $.jStorage.set( title , info[i].url, { TTL: cacheTime } );
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, info[i].url ); // brings the scope to the callback
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, false ); // brings the scope to the callback
+ }
+ }
+ );
+ },
+
+ /**
+ * Get title url
+ * @since 1.8
+ * @param options
+ * @param callback
+ * @return string
+ */
+ getTitleURL: function( options, callback ) {
+ var title = options.title,
+ cacheTime = options.cachetime;
+
+ // Get cache time
+ cacheTime = cacheTime === undefined ? _cacheTime : cacheTime;
+
+ // Get url from cache otherwise do an ajax call
+ var url = $.jStorage.get( title );
+ if ( url !== null ) {
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, url ); // brings the scope to the callback
+ }
+ return;
+ }
+
+ // Get url via ajax
+ $.getJSON(
+ mw.config.get( 'wgScriptPath' ) + '/api.php',
+ {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'info',
+ 'inprop': 'url',
+ 'titles': title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p];
+ $.jStorage.set( title, info.fullurl, { TTL: cacheTime } );
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, info.fullurl ); // brings the scope to the callback
+ }
+ return;
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, false ); // brings the scope to the callback
+ }
+ }
+ );
+ },
+
+ /**
+ * Get spinner for a local element
+ * @since 1.8
+ * @param options
+ * @return object
+ */
+ spinner: {
+ create: function( options ) {
+
+ // Select the object from its context and determine height and width
+ var obj = options.context.find( options.selector ),
+ h = mw.html,
+ width = obj.width(),
+ height = obj.height();
+
+ // Add spinner to target object
+ obj.after( h.element( 'span', { 'class' : _CL_srfIspinner + ' ' + _CL_mwspinner }, null ) );
+
+ // Adopt height and width to avoid clutter
+ options.context.find( '.' + _CL_srfIspinner + '.' + _CL_mwspinner )
+ .css( { width: width, height: height } )
+ .data ( 'spinner', obj ); // Attach the original object as data element
+ obj.remove(); // Could just hide the element instead of removing it
+
+ },
+ replace: function ( options ){
+ // Replace spinner and restore original instance
+ options.context.find( '.' + _CL_srfIspinner + '.' + _CL_mwspinner )
+ .replaceWith( options.context.find( '.' + _CL_srfIspinner ).data( 'spinner' ) ) ;
+ },
+ hide: function ( options ){
+ var c = options.length === undefined ? options.context : options;
+ c.find( '.' + _CL_srfspinner ).hide();
+ }
+ },
+
+ /**
+ * Convenience method to check if some options are supported
+ *
+ * @since 1.9
+ *
+ * @param {string} option
+ *
+ * @return boolean
+ */
+ assert: function( option ) {
+ switch ( option ){
+ case 'canvas':
+ // Checks if the current browser supports canvas
+ // @see http://goo.gl/9PYP3
+ return !!window.HTMLCanvasElement;
+ case 'svg':
+ // Checks if the current browser supports svg
+ return !!window.SVGSVGElement;
+ default:
+ return false;
+ }
+ },
+
+ /**
+ * Convenience method for growl-like notifications using the blockUI plugin
+ *
+ * @since 1.9
+ * @var options
+ * @return object
+ */
+ notification: {
+ create: function( options ) {
+ return $.blockUI( {
+ message: html.element( 'span', { 'class' : 'srf-notification-content' }, new html.Raw( options.content ) ),
+ fadeIn: 700,
+ fadeOut: 700,
+ timeout: 2000,
+ showOverlay: false,
+ centerY: false,
+ css: {
+ 'width': '235px',
+ 'line-height': '1.35',
+ 'z-index': '10000',
+ 'top': '10px',
+ 'left': '',
+ 'right': '15px',
+ 'padding': '0.25em 1em',
+ 'margin-bottom': '0.5em',
+ 'border': '0px solid #fff',
+ 'background-color': options.color || '#000',
+ 'opacity': '.6',
+ 'cursor': 'pointer',
+ '-webkit-border-radius': '5px',
+ '-moz-border-radius': '5px',
+ 'border-radius': '5px',
+ '-webkit-box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)',
+ '-moz-box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)',
+ 'box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)'
+ }
+ } );
+ }
+ },
+
+ /**
+ * Convenience method for ui-widget like error/info messages
+ *
+ * @since 1.9
+ * @var options
+ * @return object
+ */
+ message:{
+ set: function( options ){
+ var type = options.type === 'error' ? 'ui-state-error' : 'ui-state-highlight';
+ options.context.prepend( html.element( 'div', {
+ 'class': 'ui-widget' }, new html.Raw( html.element( 'div', {
+ 'class': type + ' ui-corner-all','style': 'padding-left: 0.5em' }, new html.Raw( html.element( 'p', { }, new html.Raw( html.element( 'span', { 'class': 'ui-icon ui-icon-alert', 'style': 'float: left; margin-right: 0.7em;' }, '' ) + options.message ) ) ) ) ) ) );
+ },
+
+ exception: function( options ){
+ this.set( $.extend( {}, { type: 'error' }, options ) );
+ throw new Error( options.message );
+ },
+
+ remove:function( context ){
+ context.children().fadeOut( 'slow' ).remove();
+ }
+ },
+
+ /**
+ *
+ *
+ *
+ */
+ image: {
+
+ /**
+ * Returns image information including thumbnail
+ *
+ * @since 1.9
+ *
+ * @param options
+ * @param callback
+ *
+ * @return object
+ */
+ imageInfo: function( options, callback ){
+ var isCached = true;
+
+ // Get cache otherwise do an Ajax call
+ if ( options.cache ) {
+ var imageInfo = $.jStorage.get( options.title + '-' + options.width );
+
+ if ( imageInfo !== null ) {
+ if ( typeof callback === 'function' ) {
+ callback.call( this, isCached, imageInfo );
+ }
+ return;
+ }
+ }
+
+ $.getJSON( mw.config.get( 'wgScriptPath' ) + '/api.php', {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'imageinfo',
+ 'iiprop': 'url',
+ 'iiurlwidth': options.width,
+ 'iiurlheight': options.height,
+ 'titles': options.title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p];
+ if ( options.cache !== undefined ) {
+ $.jStorage.set( options.title + '-' + options.width , info, { TTL: options.cache } );
+ }
+ if ( typeof callback === 'function' ) {
+ callback.call( this, !isCached, info );
+ }
+ return;
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) {
+ callback.call( this, !isCached, false );
+ }
+ }
+ );
+ }
+
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js
new file mode 100644
index 00000000..511bdb77
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js
@@ -0,0 +1,398 @@
+// Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/
+// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
+// @author: mwjames, 2012-08, added href as construtor field
+(function(exports) {
+ function cloud() {
+ var size = [256, 256],
+ text = cloudText,
+ href = cloudhref,
+ font = cloudFont,
+ fontSize = cloudFontSize,
+ rotate = cloudRotate,
+ padding = cloudPadding,
+ spiral = archimedeanSpiral,
+ words = [],
+ timeInterval = Infinity,
+ event = d3.dispatch("word", "end"),
+ timer = null,
+ cloud = {};
+
+ cloud.start = function() {
+ var board = zeroArray((size[0] >> 5) * size[1]),
+ bounds = null,
+ n = words.length,
+ i = -1,
+ tags = [],
+ data = words.map(function(d, i) {
+ return {
+ text: text.call(this, d, i),
+ href: href.call(this, d, i),
+ font: font.call(this, d, i),
+ rotate: rotate.call(this, d, i),
+ size: ~~fontSize.call(this, d, i),
+ padding: cloudPadding.call(this, d, i)
+ };
+ }).sort(function(a, b) { return b.size - a.size; });
+
+ if (timer) clearInterval(timer);
+ timer = setInterval(step, 0);
+ step();
+
+ return cloud;
+
+ function step() {
+ var start = +new Date,
+ d;
+ while (+new Date - start < timeInterval && ++i < n && timer) {
+ d = data[i];
+ d.x = (size[0] * (Math.random() + .5)) >> 1;
+ d.y = (size[1] * (Math.random() + .5)) >> 1;
+ cloudSprite(d, data, i);
+ if (place(board, d, bounds)) {
+ tags.push(d);
+ event.word(d);
+ if (bounds) cloudBounds(bounds, d);
+ else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];
+ // Temporary hack
+ d.x -= size[0] >> 1;
+ d.y -= size[1] >> 1;
+ }
+ }
+ if (i >= n) {
+ cloud.stop();
+ event.end(tags, bounds);
+ }
+ }
+ }
+
+ cloud.stop = function() {
+ if (timer) {
+ clearInterval(timer);
+ timer = null;
+ }
+ return cloud;
+ };
+
+ cloud.timeInterval = function(x) {
+ if (!arguments.length) return timeInterval;
+ timeInterval = x == null ? Infinity : x;
+ return cloud;
+ };
+
+ function place(board, tag, bounds) {
+ var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}],
+ startX = tag.x,
+ startY = tag.y,
+ maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),
+ s = spiral(size),
+ dt = Math.random() < .5 ? 1 : -1,
+ t = -dt,
+ dxdy,
+ dx,
+ dy;
+
+ while (dxdy = s(t += dt)) {
+ dx = ~~dxdy[0];
+ dy = ~~dxdy[1];
+
+ if (Math.min(dx, dy) > maxDelta) break;
+
+ tag.x = startX + dx;
+ tag.y = startY + dy;
+
+ if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||
+ tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;
+ // TODO only check for collisions within current bounds.
+ if (!bounds || !cloudCollide(tag, board, size[0])) {
+ if (!bounds || collideRects(tag, bounds)) {
+ var sprite = tag.sprite,
+ w = tag.width >> 5,
+ sw = size[0] >> 5,
+ lx = tag.x - (w << 4),
+ sx = lx & 0x7f,
+ msx = 32 - sx,
+ h = tag.y1 - tag.y0,
+ x = (tag.y + tag.y0) * sw + (lx >> 5),
+ last;
+ for (var j = 0; j < h; j++) {
+ last = 0;
+ for (var i = 0; i <= w; i++) {
+ board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
+ }
+ x += sw;
+ }
+ delete tag.sprite;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ cloud.words = function(x) {
+ if (!arguments.length) return words;
+ words = x;
+ return cloud;
+ };
+
+ cloud.size = function(x) {
+ if (!arguments.length) return size;
+ size = [+x[0], +x[1]];
+ return cloud;
+ };
+
+ cloud.font = function(x) {
+ if (!arguments.length) return font;
+ font = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.rotate = function(x) {
+ if (!arguments.length) return rotate;
+ rotate = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.text = function(x) {
+ if (!arguments.length) return text;
+ text = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.href = function(x) {
+ if (!arguments.length) return href;
+ text = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.spiral = function(x) {
+ if (!arguments.length) return spiral;
+ spiral = spirals[x + ""] || x;
+ return cloud;
+ };
+
+ cloud.fontSize = function(x) {
+ if (!arguments.length) return fontSize;
+ fontSize = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = d3.functor(x);
+ return cloud;
+ };
+
+ return d3.rebind(cloud, event, "on");
+ }
+
+ function cloudText(d) {
+ return d.text;
+ }
+
+ function cloudhref(d) {
+ return d.href;
+ }
+
+ function cloudFont() {
+ return "serif";
+ }
+
+ function cloudFontSize(d) {
+ return Math.sqrt(d.value);
+ }
+
+ function cloudRotate() {
+ return (~~(Math.random() * 6) - 3) * 30;
+ }
+
+ function cloudPadding() {
+ return 1;
+ }
+
+ // Fetches a monochrome sprite bitmap for the specified text.
+ // Load in batches for speed.
+ function cloudSprite(d, data, di) {
+ if (d.sprite) return;
+ c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);
+ var x = 0,
+ y = 0,
+ maxh = 0,
+ n = data.length;
+ di--;
+ while (++di < n) {
+ d = data[di];
+ c.save();
+ c.font = ~~((d.size + 1) / ratio) + "px " + d.font;
+ var w = c.measureText(d.text + "m").width * ratio,
+ h = d.size << 1;
+ if (d.rotate) {
+ var sr = Math.sin(d.rotate * cloudRadians),
+ cr = Math.cos(d.rotate * cloudRadians),
+ wcr = w * cr,
+ wsr = w * sr,
+ hcr = h * cr,
+ hsr = h * sr;
+ w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;
+ h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
+ } else {
+ w = (w + 0x1f) >> 5 << 5;
+ }
+ if (h > maxh) maxh = h;
+ if (x + w >= (cw << 5)) {
+ x = 0;
+ y += maxh;
+ maxh = 0;
+ }
+ if (y + h >= ch) break;
+ c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);
+ if (d.rotate) c.rotate(d.rotate * cloudRadians);
+ c.fillText(d.text, 0, 0);
+ c.restore();
+ d.width = w;
+ d.height = h;
+ d.xoff = x;
+ d.yoff = y;
+ d.x1 = w >> 1;
+ d.y1 = h >> 1;
+ d.x0 = -d.x1;
+ d.y0 = -d.y1;
+ x += w;
+ }
+ var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,
+ sprite = [];
+ while (--di >= 0) {
+ d = data[di];
+ var w = d.width,
+ w32 = w >> 5,
+ h = d.y1 - d.y0,
+ p = d.padding;
+ // Zero the buffer
+ for (var i = 0; i < h * w32; i++) sprite[i] = 0;
+ x = d.xoff;
+ if (x == null) return;
+ y = d.yoff;
+ var seen = 0,
+ seenRow = -1;
+ for (var j = 0; j < h; j++) {
+ for (var i = 0; i < w; i++) {
+ var k = w32 * j + (i >> 5),
+ m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;
+ if (p) {
+ if (j) sprite[k - w32] |= m;
+ if (j < w - 1) sprite[k + w32] |= m;
+ m |= (m << 1) | (m >> 1);
+ }
+ sprite[k] |= m;
+ seen |= m;
+ }
+ if (seen) seenRow = j;
+ else {
+ d.y0++;
+ h--;
+ j--;
+ y++;
+ }
+ }
+ d.y1 = d.y0 + seenRow;
+ d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);
+ }
+ }
+
+ // Use mask-based collision detection.
+ function cloudCollide(tag, board, sw) {
+ sw >>= 5;
+ var sprite = tag.sprite,
+ w = tag.width >> 5,
+ lx = tag.x - (w << 4),
+ sx = lx & 0x7f,
+ msx = 32 - sx,
+ h = tag.y1 - tag.y0,
+ x = (tag.y + tag.y0) * sw + (lx >> 5),
+ last;
+ for (var j = 0; j < h; j++) {
+ last = 0;
+ for (var i = 0; i <= w; i++) {
+ if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))
+ & board[x + i]) return true;
+ }
+ x += sw;
+ }
+ return false;
+ }
+
+ function cloudBounds(bounds, d) {
+ var b0 = bounds[0],
+ b1 = bounds[1];
+ if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;
+ if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;
+ if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;
+ if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;
+ }
+
+ function collideRects(a, b) {
+ return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;
+ }
+
+ function archimedeanSpiral(size) {
+ var e = size[0] / size[1];
+ return function(t) {
+ return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];
+ };
+ }
+
+ function rectangularSpiral(size) {
+ var dy = 4,
+ dx = dy * size[0] / size[1],
+ x = 0,
+ y = 0;
+ return function(t) {
+ var sign = t < 0 ? -1 : 1;
+ // See triangular numbers: T_n = n * (n + 1) / 2.
+ switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {
+ case 0: x += dx; break;
+ case 1: y += dy; break;
+ case 2: x -= dx; break;
+ default: y -= dy; break;
+ }
+ return [x, y];
+ };
+ }
+
+ // TODO reuse arrays?
+ function zeroArray(n) {
+ var a = [],
+ i = -1;
+ while (++i < n) a[i] = 0;
+ return a;
+ }
+
+ var cloudRadians = Math.PI / 180,
+ cw = 1 << 11 >> 5,
+ ch = 1 << 11,
+ canvas,
+ ratio = 1;
+
+ if (typeof document !== "undefined") {
+ canvas = document.createElement("canvas");
+ canvas.width = 1;
+ canvas.height = 1;
+ ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
+ canvas.width = (cw << 5) / ratio;
+ canvas.height = ch / ratio;
+ } else {
+ // node-canvas support
+ var Canvas = require("canvas");
+ canvas = new Canvas(cw << 5, ch);
+ }
+
+ var c = canvas.getContext("2d"),
+ spirals = {
+ archimedean: archimedeanSpiral,
+ rectangular: rectangularSpiral
+ };
+ c.fillStyle = "red";
+ c.textAlign = "center";
+
+ exports.cloud = cloud;
+})(typeof exports === "undefined" ? d3.layout || (d3.layout = {}) : exports);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.v3.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.v3.js
new file mode 100644
index 00000000..2d9c0ef9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/d3/d3.v3.js
@@ -0,0 +1,7806 @@
+(function() {
+ var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ];
+ if (!Date.now) Date.now = function() {
+ return +new Date();
+ };
+ try {
+ document.createElement("div").style.setProperty("opacity", 0, "");
+ } catch (error) {
+ var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+ }
+ d3 = {
+ version: "3.0.4"
+ };
+ var π = Math.PI, ε = 1e-6, d3_radians = π / 180, d3_degrees = 180 / π;
+ function d3_target(d) {
+ return d.target;
+ }
+ function d3_source(d) {
+ return d.source;
+ }
+ function d3_class(ctor, properties) {
+ try {
+ for (var key in properties) {
+ Object.defineProperty(ctor.prototype, key, {
+ value: properties[key],
+ enumerable: false
+ });
+ }
+ } catch (e) {
+ ctor.prototype = properties;
+ }
+ }
+ var d3_array = d3_arraySlice;
+ function d3_arrayCopy(pseudoarray) {
+ var i = -1, n = pseudoarray.length, array = [];
+ while (++i < n) array.push(pseudoarray[i]);
+ return array;
+ }
+ function d3_arraySlice(pseudoarray) {
+ return Array.prototype.slice.call(pseudoarray);
+ }
+ try {
+ d3_array(document.documentElement.childNodes)[0].nodeType;
+ } catch (e) {
+ d3_array = d3_arrayCopy;
+ }
+ var d3_arraySubclass = [].__proto__ ? function(array, prototype) {
+ array.__proto__ = prototype;
+ } : function(array, prototype) {
+ for (var property in prototype) array[property] = prototype[property];
+ };
+ d3.map = function(object) {
+ var map = new d3_Map();
+ for (var key in object) map.set(key, object[key]);
+ return map;
+ };
+ function d3_Map() {}
+ d3_class(d3_Map, {
+ has: function(key) {
+ return d3_map_prefix + key in this;
+ },
+ get: function(key) {
+ return this[d3_map_prefix + key];
+ },
+ set: function(key, value) {
+ return this[d3_map_prefix + key] = value;
+ },
+ remove: function(key) {
+ key = d3_map_prefix + key;
+ return key in this && delete this[key];
+ },
+ keys: function() {
+ var keys = [];
+ this.forEach(function(key) {
+ keys.push(key);
+ });
+ return keys;
+ },
+ values: function() {
+ var values = [];
+ this.forEach(function(key, value) {
+ values.push(value);
+ });
+ return values;
+ },
+ entries: function() {
+ var entries = [];
+ this.forEach(function(key, value) {
+ entries.push({
+ key: key,
+ value: value
+ });
+ });
+ return entries;
+ },
+ forEach: function(f) {
+ for (var key in this) {
+ if (key.charCodeAt(0) === d3_map_prefixCode) {
+ f.call(this, key.substring(1), this[key]);
+ }
+ }
+ }
+ });
+ var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+ function d3_identity(d) {
+ return d;
+ }
+ function d3_true() {
+ return true;
+ }
+ function d3_functor(v) {
+ return typeof v === "function" ? v : function() {
+ return v;
+ };
+ }
+ d3.functor = d3_functor;
+ d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+ return target;
+ };
+ function d3_rebind(target, source, method) {
+ return function() {
+ var value = method.apply(source, arguments);
+ return arguments.length ? target : value;
+ };
+ }
+ d3.ascending = function(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+ };
+ d3.descending = function(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+ };
+ d3.mean = function(array, f) {
+ var n = array.length, a, m = 0, i = -1, j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+ }
+ return j ? m : undefined;
+ };
+ d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
+ };
+ d3.min = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+ } else {
+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
+ }
+ return a;
+ };
+ d3.max = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+ } else {
+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
+ }
+ return a;
+ };
+ d3.extent = function(array, f) {
+ var i = -1, n = array.length, a, b, c;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [ a, c ];
+ };
+ d3.random = {
+ normal: function(µ, σ) {
+ var n = arguments.length;
+ if (n < 2) σ = 1;
+ if (n < 1) µ = 0;
+ return function() {
+ var x, y, r;
+ do {
+ x = Math.random() * 2 - 1;
+ y = Math.random() * 2 - 1;
+ r = x * x + y * y;
+ } while (!r || r > 1);
+ return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
+ };
+ },
+ logNormal: function(µ, σ) {
+ var n = arguments.length;
+ if (n < 2) σ = 1;
+ if (n < 1) µ = 0;
+ var random = d3.random.normal();
+ return function() {
+ return Math.exp(µ + σ * random());
+ };
+ },
+ irwinHall: function(m) {
+ return function() {
+ for (var s = 0, j = 0; j < m; j++) s += Math.random();
+ return s / m;
+ };
+ }
+ };
+ function d3_number(x) {
+ return x != null && !isNaN(x);
+ }
+ d3.sum = function(array, f) {
+ var s = 0, n = array.length, a, i = -1;
+ if (arguments.length === 1) {
+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
+ } else {
+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+ }
+ return s;
+ };
+ d3.quantile = function(values, p) {
+ var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
+ return e ? v + e * (values[h] - v) : v;
+ };
+ d3.shuffle = function(array) {
+ var m = array.length, t, i;
+ while (m) {
+ i = Math.random() * m-- | 0;
+ t = array[m], array[m] = array[i], array[i] = t;
+ }
+ return array;
+ };
+ d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+ };
+ d3.zip = function() {
+ if (!(n = arguments.length)) return [];
+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+ zip[j] = arguments[j][i];
+ }
+ }
+ return zips;
+ };
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ d3.bisector = function(f) {
+ return {
+ left: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
+ }
+ return lo;
+ },
+ right: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
+ }
+ return lo;
+ }
+ };
+ };
+ var d3_bisector = d3.bisector(function(d) {
+ return d;
+ });
+ d3.bisectLeft = d3_bisector.left;
+ d3.bisect = d3.bisectRight = d3_bisector.right;
+ d3.nest = function() {
+ var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+ function map(array, depth) {
+ if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
+ var i = -1, n = array.length, key = keys[depth++], keyValue, object, valuesByKey = new d3_Map(), values, o = {};
+ while (++i < n) {
+ if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+ values.push(object);
+ } else {
+ valuesByKey.set(keyValue, [ object ]);
+ }
+ }
+ valuesByKey.forEach(function(keyValue, values) {
+ o[keyValue] = map(values, depth);
+ });
+ return o;
+ }
+ function entries(map, depth) {
+ if (depth >= keys.length) return map;
+ var a = [], sortKey = sortKeys[depth++], key;
+ for (key in map) {
+ a.push({
+ key: key,
+ values: entries(map[key], depth)
+ });
+ }
+ if (sortKey) a.sort(function(a, b) {
+ return sortKey(a.key, b.key);
+ });
+ return a;
+ }
+ nest.map = function(array) {
+ return map(array, 0);
+ };
+ nest.entries = function(array) {
+ return entries(map(array, 0), 0);
+ };
+ nest.key = function(d) {
+ keys.push(d);
+ return nest;
+ };
+ nest.sortKeys = function(order) {
+ sortKeys[keys.length - 1] = order;
+ return nest;
+ };
+ nest.sortValues = function(order) {
+ sortValues = order;
+ return nest;
+ };
+ nest.rollup = function(f) {
+ rollup = f;
+ return nest;
+ };
+ return nest;
+ };
+ d3.keys = function(map) {
+ var keys = [];
+ for (var key in map) keys.push(key);
+ return keys;
+ };
+ d3.values = function(map) {
+ var values = [];
+ for (var key in map) values.push(map[key]);
+ return values;
+ };
+ d3.entries = function(map) {
+ var entries = [];
+ for (var key in map) entries.push({
+ key: key,
+ value: map[key]
+ });
+ return entries;
+ };
+ d3.permute = function(array, indexes) {
+ var permutes = [], i = -1, n = indexes.length;
+ while (++i < n) permutes[i] = array[indexes[i]];
+ return permutes;
+ };
+ d3.merge = function(arrays) {
+ return Array.prototype.concat.apply([], arrays);
+ };
+ function d3_collapse(s) {
+ return s.trim().replace(/\s+/g, " ");
+ }
+ d3.range = function(start, stop, step) {
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
+ if ((stop - start) / step === Infinity) throw new Error("infinite range");
+ var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j;
+ start *= k, stop *= k, step *= k;
+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
+ return range;
+ };
+ function d3_range_integerScale(x) {
+ var k = 1;
+ while (x * k % 1) k *= 10;
+ return k;
+ }
+ d3.requote = function(s) {
+ return s.replace(d3_requote_re, "\\$&");
+ };
+ var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+ d3.round = function(x, n) {
+ return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
+ };
+ d3.xhr = function(url, mimeType, callback) {
+ var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, response = d3_identity, request = new (window.XDomainRequest && /^(http(s)?:)?\/\//.test(url) ? XDomainRequest : XMLHttpRequest)();
+ "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
+ request.readyState > 3 && respond();
+ };
+ function respond() {
+ var s = request.status;
+ !s && request.responseText || s >= 200 && s < 300 || s === 304 ? dispatch.load.call(xhr, response.call(xhr, request)) : dispatch.error.call(xhr, request);
+ }
+ request.onprogress = function(event) {
+ var o = d3.event;
+ d3.event = event;
+ try {
+ dispatch.progress.call(xhr, request);
+ } finally {
+ d3.event = o;
+ }
+ };
+ xhr.header = function(name, value) {
+ name = (name + "").toLowerCase();
+ if (arguments.length < 2) return headers[name];
+ if (value == null) delete headers[name]; else headers[name] = value + "";
+ return xhr;
+ };
+ xhr.mimeType = function(value) {
+ if (!arguments.length) return mimeType;
+ mimeType = value == null ? null : value + "";
+ return xhr;
+ };
+ xhr.response = function(value) {
+ response = value;
+ return xhr;
+ };
+ [ "get", "post" ].forEach(function(method) {
+ xhr[method] = function() {
+ return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
+ };
+ });
+ xhr.send = function(method, data, callback) {
+ if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
+ request.open(method, url, true);
+ if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
+ if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
+ if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
+ if (callback != null) xhr.on("error", callback).on("load", function(request) {
+ callback(null, request);
+ });
+ request.send(data == null ? null : data);
+ return xhr;
+ };
+ xhr.abort = function() {
+ request.abort();
+ return xhr;
+ };
+ d3.rebind(xhr, dispatch, "on");
+ if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType,
+ mimeType = null;
+ return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
+ };
+ function d3_xhr_fixCallback(callback) {
+ return callback.length === 1 ? function(error, request) {
+ callback(error == null ? request : null);
+ } : callback;
+ }
+ d3.text = function() {
+ return d3.xhr.apply(d3, arguments).response(d3_text);
+ };
+ function d3_text(request) {
+ return request.responseText;
+ }
+ d3.json = function(url, callback) {
+ return d3.xhr(url, "application/json", callback).response(d3_json);
+ };
+ function d3_json(request) {
+ return JSON.parse(request.responseText);
+ }
+ d3.html = function(url, callback) {
+ return d3.xhr(url, "text/html", callback).response(d3_html);
+ };
+ function d3_html(request) {
+ var range = document.createRange();
+ range.selectNode(document.body);
+ return range.createContextualFragment(request.responseText);
+ }
+ d3.xml = function() {
+ return d3.xhr.apply(d3, arguments).response(d3_xml);
+ };
+ function d3_xml(request) {
+ return request.responseXML;
+ }
+ var d3_nsPrefix = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: "http://www.w3.org/1999/xhtml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+ };
+ d3.ns = {
+ prefix: d3_nsPrefix,
+ qualify: function(name) {
+ var i = name.indexOf(":"), prefix = name;
+ if (i >= 0) {
+ prefix = name.substring(0, i);
+ name = name.substring(i + 1);
+ }
+ return d3_nsPrefix.hasOwnProperty(prefix) ? {
+ space: d3_nsPrefix[prefix],
+ local: name
+ } : name;
+ }
+ };
+ d3.dispatch = function() {
+ var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ return dispatch;
+ };
+ function d3_dispatch() {}
+ d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."), name = "";
+ if (i > 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+ return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
+ };
+ function d3_dispatch_event(dispatch) {
+ var listeners = [], listenerByName = new d3_Map();
+ function event() {
+ var z = listeners, i = -1, n = z.length, l;
+ while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+ return dispatch;
+ }
+ event.on = function(name, listener) {
+ var l = listenerByName.get(name), i;
+ if (arguments.length < 2) return l && l.on;
+ if (l) {
+ l.on = null;
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
+ listenerByName.remove(name);
+ }
+ if (listener) listeners.push(listenerByName.set(name, {
+ on: listener
+ }));
+ return dispatch;
+ };
+ return event;
+ }
+ d3.format = function(specifier) {
+ var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", basePrefix = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
+ if (precision) precision = +precision.substring(1);
+ if (zfill || fill === "0" && align === "=") {
+ zfill = fill = "0";
+ align = "=";
+ if (comma) width -= Math.floor((width - 1) / 4);
+ }
+ switch (type) {
+ case "n":
+ comma = true;
+ type = "g";
+ break;
+
+ case "%":
+ scale = 100;
+ suffix = "%";
+ type = "f";
+ break;
+
+ case "p":
+ scale = 100;
+ suffix = "%";
+ type = "r";
+ break;
+
+ case "b":
+ case "o":
+ case "x":
+ case "X":
+ if (basePrefix) basePrefix = "0" + type.toLowerCase();
+
+ case "c":
+ case "d":
+ integer = true;
+ precision = 0;
+ break;
+
+ case "s":
+ scale = -1;
+ type = "r";
+ break;
+ }
+ if (basePrefix === "#") basePrefix = "";
+ if (type == "r" && !precision) type = "g";
+ type = d3_format_types.get(type) || d3_format_typeDefault;
+ var zcomma = zfill && comma;
+ return function(value) {
+ if (integer && value % 1) return "";
+ var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
+ if (scale < 0) {
+ var prefix = d3.formatPrefix(value, precision);
+ value = prefix.scale(value);
+ suffix = prefix.symbol;
+ } else {
+ value *= scale;
+ }
+ value = type(value, precision);
+ if (!zfill && comma) value = d3_format_group(value);
+ var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
+ if (zcomma) value = d3_format_group(padding + value);
+ if (d3_format_decimalPoint) value.replace(".", d3_format_decimalPoint);
+ negative += basePrefix;
+ return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix;
+ };
+ };
+ var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
+ var d3_format_types = d3.map({
+ b: function(x) {
+ return x.toString(2);
+ },
+ c: function(x) {
+ return String.fromCharCode(x);
+ },
+ o: function(x) {
+ return x.toString(8);
+ },
+ x: function(x) {
+ return x.toString(16);
+ },
+ X: function(x) {
+ return x.toString(16).toUpperCase();
+ },
+ g: function(x, p) {
+ return x.toPrecision(p);
+ },
+ e: function(x, p) {
+ return x.toExponential(p);
+ },
+ f: function(x, p) {
+ return x.toFixed(p);
+ },
+ r: function(x, p) {
+ return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p)));
+ }
+ });
+ function d3_format_precision(x, p) {
+ return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
+ }
+ function d3_format_typeDefault(x) {
+ return x + "";
+ }
+ var d3_format_group = d3_identity;
+ if (d3_format_grouping) {
+ var d3_format_groupingLength = d3_format_grouping.length;
+ d3_format_group = function(value) {
+ var i = value.lastIndexOf("."), f = i >= 0 ? "." + value.substring(i + 1) : (i = value.length,
+ ""), t = [], j = 0, g = d3_format_grouping[0];
+ while (i > 0 && g > 0) {
+ t.push(value.substring(i -= g, i + g));
+ g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];
+ }
+ return t.reverse().join(d3_format_thousandsSeparator || "") + f;
+ };
+ }
+ var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
+ d3.formatPrefix = function(value, precision) {
+ var i = 0;
+ if (value) {
+ if (value < 0) value *= -1;
+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+ i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
+ }
+ return d3_formatPrefixes[8 + i / 3];
+ };
+ function d3_formatPrefix(d, i) {
+ var k = Math.pow(10, Math.abs(8 - i) * 3);
+ return {
+ scale: i > 8 ? function(d) {
+ return d / k;
+ } : function(d) {
+ return d * k;
+ },
+ symbol: d
+ };
+ }
+ var d3_ease_default = function() {
+ return d3_identity;
+ };
+ var d3_ease = d3.map({
+ linear: d3_ease_default,
+ poly: d3_ease_poly,
+ quad: function() {
+ return d3_ease_quad;
+ },
+ cubic: function() {
+ return d3_ease_cubic;
+ },
+ sin: function() {
+ return d3_ease_sin;
+ },
+ exp: function() {
+ return d3_ease_exp;
+ },
+ circle: function() {
+ return d3_ease_circle;
+ },
+ elastic: d3_ease_elastic,
+ back: d3_ease_back,
+ bounce: function() {
+ return d3_ease_bounce;
+ }
+ });
+ var d3_ease_mode = d3.map({
+ "in": d3_identity,
+ out: d3_ease_reverse,
+ "in-out": d3_ease_reflect,
+ "out-in": function(f) {
+ return d3_ease_reflect(d3_ease_reverse(f));
+ }
+ });
+ d3.ease = function(name) {
+ var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in";
+ t = d3_ease.get(t) || d3_ease_default;
+ m = d3_ease_mode.get(m) || d3_identity;
+ return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1))));
+ };
+ function d3_ease_clamp(f) {
+ return function(t) {
+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+ };
+ }
+ function d3_ease_reverse(f) {
+ return function(t) {
+ return 1 - f(1 - t);
+ };
+ }
+ function d3_ease_reflect(f) {
+ return function(t) {
+ return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
+ };
+ }
+ function d3_ease_quad(t) {
+ return t * t;
+ }
+ function d3_ease_cubic(t) {
+ return t * t * t;
+ }
+ function d3_ease_cubicInOut(t) {
+ if (t <= 0) return 0;
+ if (t >= 1) return 1;
+ var t2 = t * t, t3 = t2 * t;
+ return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
+ }
+ function d3_ease_poly(e) {
+ return function(t) {
+ return Math.pow(t, e);
+ };
+ }
+ function d3_ease_sin(t) {
+ return 1 - Math.cos(t * π / 2);
+ }
+ function d3_ease_exp(t) {
+ return Math.pow(2, 10 * (t - 1));
+ }
+ function d3_ease_circle(t) {
+ return 1 - Math.sqrt(1 - t * t);
+ }
+ function d3_ease_elastic(a, p) {
+ var s;
+ if (arguments.length < 2) p = .45;
+ if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4;
+ return function(t) {
+ return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p);
+ };
+ }
+ function d3_ease_back(s) {
+ if (!s) s = 1.70158;
+ return function(t) {
+ return t * t * ((s + 1) * t - s);
+ };
+ }
+ function d3_ease_bounce(t) {
+ return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
+ }
+ d3.event = null;
+ function d3_eventCancel() {
+ d3.event.stopPropagation();
+ d3.event.preventDefault();
+ }
+ function d3_eventSource() {
+ var e = d3.event, s;
+ while (s = e.sourceEvent) e = s;
+ return e;
+ }
+ function d3_eventDispatch(target) {
+ var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ dispatch.of = function(thiz, argumentz) {
+ return function(e1) {
+ try {
+ var e0 = e1.sourceEvent = d3.event;
+ e1.target = target;
+ d3.event = e1;
+ dispatch[e1.type].apply(thiz, argumentz);
+ } finally {
+ d3.event = e0;
+ }
+ };
+ };
+ return dispatch;
+ }
+ d3.transform = function(string) {
+ var g = document.createElementNS(d3.ns.prefix.svg, "g");
+ return (d3.transform = function(string) {
+ g.setAttribute("transform", string);
+ var t = g.transform.baseVal.consolidate();
+ return new d3_transform(t ? t.matrix : d3_transformIdentity);
+ })(string);
+ };
+ function d3_transform(m) {
+ var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
+ if (r0[0] * r1[1] < r1[0] * r0[1]) {
+ r0[0] *= -1;
+ r0[1] *= -1;
+ kx *= -1;
+ kz *= -1;
+ }
+ this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
+ this.translate = [ m.e, m.f ];
+ this.scale = [ kx, ky ];
+ this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
+ }
+ d3_transform.prototype.toString = function() {
+ return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
+ };
+ function d3_transformDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+ function d3_transformNormalize(a) {
+ var k = Math.sqrt(d3_transformDot(a, a));
+ if (k) {
+ a[0] /= k;
+ a[1] /= k;
+ }
+ return k;
+ }
+ function d3_transformCombine(a, b, k) {
+ a[0] += k * b[0];
+ a[1] += k * b[1];
+ return a;
+ }
+ var d3_transformIdentity = {
+ a: 1,
+ b: 0,
+ c: 0,
+ d: 1,
+ e: 0,
+ f: 0
+ };
+ d3.interpolate = function(a, b) {
+ var i = d3.interpolators.length, f;
+ while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
+ return f;
+ };
+ d3.interpolateNumber = function(a, b) {
+ b -= a;
+ return function(t) {
+ return a + b * t;
+ };
+ };
+ d3.interpolateRound = function(a, b) {
+ b -= a;
+ return function(t) {
+ return Math.round(a + b * t);
+ };
+ };
+ d3.interpolateString = function(a, b) {
+ var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
+ d3_interpolate_number.lastIndex = 0;
+ for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
+ if (m.index) s.push(b.substring(s0, s1 = m.index));
+ q.push({
+ i: s.length,
+ x: m[0]
+ });
+ s.push(null);
+ s0 = d3_interpolate_number.lastIndex;
+ }
+ if (s0 < b.length) s.push(b.substring(s0));
+ for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
+ o = q[i];
+ if (o.x == m[0]) {
+ if (o.i) {
+ if (s[o.i + 1] == null) {
+ s[o.i - 1] += o.x;
+ s.splice(o.i, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ } else {
+ s[o.i - 1] += o.x + s[o.i + 1];
+ s.splice(o.i, 2);
+ for (j = i + 1; j < n; ++j) q[j].i -= 2;
+ }
+ } else {
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ }
+ }
+ q.splice(i, 1);
+ n--;
+ i--;
+ } else {
+ o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
+ }
+ }
+ while (i < n) {
+ o = q.pop();
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ }
+ n--;
+ }
+ if (s.length === 1) {
+ return s[0] == null ? q[0].x : function() {
+ return b;
+ };
+ }
+ return function(t) {
+ for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+ d3.interpolateTransform = function(a, b) {
+ var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
+ if (ta[0] != tb[0] || ta[1] != tb[1]) {
+ s.push("translate(", null, ",", null, ")");
+ q.push({
+ i: 1,
+ x: d3.interpolateNumber(ta[0], tb[0])
+ }, {
+ i: 3,
+ x: d3.interpolateNumber(ta[1], tb[1])
+ });
+ } else if (tb[0] || tb[1]) {
+ s.push("translate(" + tb + ")");
+ } else {
+ s.push("");
+ }
+ if (ra != rb) {
+ if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
+ q.push({
+ i: s.push(s.pop() + "rotate(", null, ")") - 2,
+ x: d3.interpolateNumber(ra, rb)
+ });
+ } else if (rb) {
+ s.push(s.pop() + "rotate(" + rb + ")");
+ }
+ if (wa != wb) {
+ q.push({
+ i: s.push(s.pop() + "skewX(", null, ")") - 2,
+ x: d3.interpolateNumber(wa, wb)
+ });
+ } else if (wb) {
+ s.push(s.pop() + "skewX(" + wb + ")");
+ }
+ if (ka[0] != kb[0] || ka[1] != kb[1]) {
+ n = s.push(s.pop() + "scale(", null, ",", null, ")");
+ q.push({
+ i: n - 4,
+ x: d3.interpolateNumber(ka[0], kb[0])
+ }, {
+ i: n - 2,
+ x: d3.interpolateNumber(ka[1], kb[1])
+ });
+ } else if (kb[0] != 1 || kb[1] != 1) {
+ s.push(s.pop() + "scale(" + kb + ")");
+ }
+ n = q.length;
+ return function(t) {
+ var i = -1, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+ d3.interpolateRgb = function(a, b) {
+ a = d3.rgb(a);
+ b = d3.rgb(b);
+ var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
+ return function(t) {
+ return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
+ };
+ };
+ d3.interpolateHsl = function(a, b) {
+ a = d3.hsl(a);
+ b = d3.hsl(b);
+ var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0;
+ if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360;
+ return function(t) {
+ return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + "";
+ };
+ };
+ d3.interpolateLab = function(a, b) {
+ a = d3.lab(a);
+ b = d3.lab(b);
+ var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
+ return function(t) {
+ return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
+ };
+ };
+ d3.interpolateHcl = function(a, b) {
+ a = d3.hcl(a);
+ b = d3.hcl(b);
+ var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
+ if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
+ };
+ };
+ d3.interpolateArray = function(a, b) {
+ var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
+ for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i]));
+ for (;i < na; ++i) c[i] = a[i];
+ for (;i < nb; ++i) c[i] = b[i];
+ return function(t) {
+ for (i = 0; i < n0; ++i) c[i] = x[i](t);
+ return c;
+ };
+ };
+ d3.interpolateObject = function(a, b) {
+ var i = {}, c = {}, k;
+ for (k in a) {
+ if (k in b) {
+ i[k] = d3_interpolateByName(k)(a[k], b[k]);
+ } else {
+ c[k] = a[k];
+ }
+ }
+ for (k in b) {
+ if (!(k in a)) {
+ c[k] = b[k];
+ }
+ }
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+ };
+ var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
+ function d3_interpolateByName(name) {
+ return name == "transform" ? d3.interpolateTransform : d3.interpolate;
+ }
+ d3.interpolators = [ d3.interpolateObject, function(a, b) {
+ return b instanceof Array && d3.interpolateArray(a, b);
+ }, function(a, b) {
+ return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
+ }, function(a, b) {
+ return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b);
+ }, function(a, b) {
+ return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b);
+ } ];
+ function d3_uninterpolateNumber(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return (x - a) * b;
+ };
+ }
+ function d3_uninterpolateClamp(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return Math.max(0, Math.min(1, (x - a) * b));
+ };
+ }
+ function d3_Color() {}
+ d3_Color.prototype.toString = function() {
+ return this.rgb() + "";
+ };
+ d3.rgb = function(r, g, b) {
+ return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
+ };
+ function d3_rgb(r, g, b) {
+ return new d3_Rgb(r, g, b);
+ }
+ function d3_Rgb(r, g, b) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+ var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
+ d3_rgbPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ var r = this.r, g = this.g, b = this.b, i = 30;
+ if (!r && !g && !b) return d3_rgb(i, i, i);
+ if (r && r < i) r = i;
+ if (g && g < i) g = i;
+ if (b && b < i) b = i;
+ return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k)));
+ };
+ d3_rgbPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b));
+ };
+ d3_rgbPrototype.hsl = function() {
+ return d3_rgb_hsl(this.r, this.g, this.b);
+ };
+ d3_rgbPrototype.toString = function() {
+ return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
+ };
+ function d3_rgb_hex(v) {
+ return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
+ }
+ function d3_rgb_parse(format, rgb, hsl) {
+ var r = 0, g = 0, b = 0, m1, m2, name;
+ m1 = /([a-z]+)\((.*)\)/i.exec(format);
+ if (m1) {
+ m2 = m1[2].split(",");
+ switch (m1[1]) {
+ case "hsl":
+ {
+ return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
+ }
+
+ case "rgb":
+ {
+ return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
+ }
+ }
+ }
+ if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
+ if (format != null && format.charAt(0) === "#") {
+ if (format.length === 4) {
+ r = format.charAt(1);
+ r += r;
+ g = format.charAt(2);
+ g += g;
+ b = format.charAt(3);
+ b += b;
+ } else if (format.length === 7) {
+ r = format.substring(1, 3);
+ g = format.substring(3, 5);
+ b = format.substring(5, 7);
+ }
+ r = parseInt(r, 16);
+ g = parseInt(g, 16);
+ b = parseInt(b, 16);
+ }
+ return rgb(r, g, b);
+ }
+ function d3_rgb_hsl(r, g, b) {
+ var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
+ if (d) {
+ s = l < .5 ? d / (max + min) : d / (2 - max - min);
+ if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
+ h *= 60;
+ } else {
+ s = h = 0;
+ }
+ return d3_hsl(h, s, l);
+ }
+ function d3_rgb_lab(r, g, b) {
+ r = d3_rgb_xyz(r);
+ g = d3_rgb_xyz(g);
+ b = d3_rgb_xyz(b);
+ var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
+ return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
+ }
+ function d3_rgb_xyz(r) {
+ return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
+ }
+ function d3_rgb_parseNumber(c) {
+ var f = parseFloat(c);
+ return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
+ }
+ var d3_rgb_names = d3.map({
+ aliceblue: "#f0f8ff",
+ antiquewhite: "#faebd7",
+ aqua: "#00ffff",
+ aquamarine: "#7fffd4",
+ azure: "#f0ffff",
+ beige: "#f5f5dc",
+ bisque: "#ffe4c4",
+ black: "#000000",
+ blanchedalmond: "#ffebcd",
+ blue: "#0000ff",
+ blueviolet: "#8a2be2",
+ brown: "#a52a2a",
+ burlywood: "#deb887",
+ cadetblue: "#5f9ea0",
+ chartreuse: "#7fff00",
+ chocolate: "#d2691e",
+ coral: "#ff7f50",
+ cornflowerblue: "#6495ed",
+ cornsilk: "#fff8dc",
+ crimson: "#dc143c",
+ cyan: "#00ffff",
+ darkblue: "#00008b",
+ darkcyan: "#008b8b",
+ darkgoldenrod: "#b8860b",
+ darkgray: "#a9a9a9",
+ darkgreen: "#006400",
+ darkgrey: "#a9a9a9",
+ darkkhaki: "#bdb76b",
+ darkmagenta: "#8b008b",
+ darkolivegreen: "#556b2f",
+ darkorange: "#ff8c00",
+ darkorchid: "#9932cc",
+ darkred: "#8b0000",
+ darksalmon: "#e9967a",
+ darkseagreen: "#8fbc8f",
+ darkslateblue: "#483d8b",
+ darkslategray: "#2f4f4f",
+ darkslategrey: "#2f4f4f",
+ darkturquoise: "#00ced1",
+ darkviolet: "#9400d3",
+ deeppink: "#ff1493",
+ deepskyblue: "#00bfff",
+ dimgray: "#696969",
+ dimgrey: "#696969",
+ dodgerblue: "#1e90ff",
+ firebrick: "#b22222",
+ floralwhite: "#fffaf0",
+ forestgreen: "#228b22",
+ fuchsia: "#ff00ff",
+ gainsboro: "#dcdcdc",
+ ghostwhite: "#f8f8ff",
+ gold: "#ffd700",
+ goldenrod: "#daa520",
+ gray: "#808080",
+ green: "#008000",
+ greenyellow: "#adff2f",
+ grey: "#808080",
+ honeydew: "#f0fff0",
+ hotpink: "#ff69b4",
+ indianred: "#cd5c5c",
+ indigo: "#4b0082",
+ ivory: "#fffff0",
+ khaki: "#f0e68c",
+ lavender: "#e6e6fa",
+ lavenderblush: "#fff0f5",
+ lawngreen: "#7cfc00",
+ lemonchiffon: "#fffacd",
+ lightblue: "#add8e6",
+ lightcoral: "#f08080",
+ lightcyan: "#e0ffff",
+ lightgoldenrodyellow: "#fafad2",
+ lightgray: "#d3d3d3",
+ lightgreen: "#90ee90",
+ lightgrey: "#d3d3d3",
+ lightpink: "#ffb6c1",
+ lightsalmon: "#ffa07a",
+ lightseagreen: "#20b2aa",
+ lightskyblue: "#87cefa",
+ lightslategray: "#778899",
+ lightslategrey: "#778899",
+ lightsteelblue: "#b0c4de",
+ lightyellow: "#ffffe0",
+ lime: "#00ff00",
+ limegreen: "#32cd32",
+ linen: "#faf0e6",
+ magenta: "#ff00ff",
+ maroon: "#800000",
+ mediumaquamarine: "#66cdaa",
+ mediumblue: "#0000cd",
+ mediumorchid: "#ba55d3",
+ mediumpurple: "#9370db",
+ mediumseagreen: "#3cb371",
+ mediumslateblue: "#7b68ee",
+ mediumspringgreen: "#00fa9a",
+ mediumturquoise: "#48d1cc",
+ mediumvioletred: "#c71585",
+ midnightblue: "#191970",
+ mintcream: "#f5fffa",
+ mistyrose: "#ffe4e1",
+ moccasin: "#ffe4b5",
+ navajowhite: "#ffdead",
+ navy: "#000080",
+ oldlace: "#fdf5e6",
+ olive: "#808000",
+ olivedrab: "#6b8e23",
+ orange: "#ffa500",
+ orangered: "#ff4500",
+ orchid: "#da70d6",
+ palegoldenrod: "#eee8aa",
+ palegreen: "#98fb98",
+ paleturquoise: "#afeeee",
+ palevioletred: "#db7093",
+ papayawhip: "#ffefd5",
+ peachpuff: "#ffdab9",
+ peru: "#cd853f",
+ pink: "#ffc0cb",
+ plum: "#dda0dd",
+ powderblue: "#b0e0e6",
+ purple: "#800080",
+ red: "#ff0000",
+ rosybrown: "#bc8f8f",
+ royalblue: "#4169e1",
+ saddlebrown: "#8b4513",
+ salmon: "#fa8072",
+ sandybrown: "#f4a460",
+ seagreen: "#2e8b57",
+ seashell: "#fff5ee",
+ sienna: "#a0522d",
+ silver: "#c0c0c0",
+ skyblue: "#87ceeb",
+ slateblue: "#6a5acd",
+ slategray: "#708090",
+ slategrey: "#708090",
+ snow: "#fffafa",
+ springgreen: "#00ff7f",
+ steelblue: "#4682b4",
+ tan: "#d2b48c",
+ teal: "#008080",
+ thistle: "#d8bfd8",
+ tomato: "#ff6347",
+ turquoise: "#40e0d0",
+ violet: "#ee82ee",
+ wheat: "#f5deb3",
+ white: "#ffffff",
+ whitesmoke: "#f5f5f5",
+ yellow: "#ffff00",
+ yellowgreen: "#9acd32"
+ });
+ d3_rgb_names.forEach(function(key, value) {
+ d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));
+ });
+ d3.hsl = function(h, s, l) {
+ return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+ };
+ function d3_hsl(h, s, l) {
+ return new d3_Hsl(h, s, l);
+ }
+ function d3_Hsl(h, s, l) {
+ this.h = h;
+ this.s = s;
+ this.l = l;
+ }
+ var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+ d3_hslPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, this.l / k);
+ };
+ d3_hslPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, k * this.l);
+ };
+ d3_hslPrototype.rgb = function() {
+ return d3_hsl_rgb(this.h, this.s, this.l);
+ };
+ function d3_hsl_rgb(h, s, l) {
+ var m1, m2;
+ h = h % 360;
+ if (h < 0) h += 360;
+ s = s < 0 ? 0 : s > 1 ? 1 : s;
+ l = l < 0 ? 0 : l > 1 ? 1 : l;
+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+ m1 = 2 * l - m2;
+ function v(h) {
+ if (h > 360) h -= 360; else if (h < 0) h += 360;
+ if (h < 60) return m1 + (m2 - m1) * h / 60;
+ if (h < 180) return m2;
+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+ return m1;
+ }
+ function vv(h) {
+ return Math.round(v(h) * 255);
+ }
+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
+ }
+ d3.hcl = function(h, c, l) {
+ return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+ };
+ function d3_hcl(h, c, l) {
+ return new d3_Hcl(h, c, l);
+ }
+ function d3_Hcl(h, c, l) {
+ this.h = h;
+ this.c = c;
+ this.l = l;
+ }
+ var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+ d3_hclPrototype.brighter = function(k) {
+ return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.darker = function(k) {
+ return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.rgb = function() {
+ return d3_hcl_lab(this.h, this.c, this.l).rgb();
+ };
+ function d3_hcl_lab(h, c, l) {
+ return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
+ }
+ d3.lab = function(l, a, b) {
+ return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
+ };
+ function d3_lab(l, a, b) {
+ return new d3_Lab(l, a, b);
+ }
+ function d3_Lab(l, a, b) {
+ this.l = l;
+ this.a = a;
+ this.b = b;
+ }
+ var d3_lab_K = 18;
+ var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+ var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+ d3_labPrototype.brighter = function(k) {
+ return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.darker = function(k) {
+ return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.rgb = function() {
+ return d3_lab_rgb(this.l, this.a, this.b);
+ };
+ function d3_lab_rgb(l, a, b) {
+ var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+ x = d3_lab_xyz(x) * d3_lab_X;
+ y = d3_lab_xyz(y) * d3_lab_Y;
+ z = d3_lab_xyz(z) * d3_lab_Z;
+ return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
+ }
+ function d3_lab_hcl(l, a, b) {
+ return d3_hcl(Math.atan2(b, a) / π * 180, Math.sqrt(a * a + b * b), l);
+ }
+ function d3_lab_xyz(x) {
+ return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+ }
+ function d3_xyz_lab(x) {
+ return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+ }
+ function d3_xyz_rgb(r) {
+ return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
+ }
+ function d3_selection(groups) {
+ d3_arraySubclass(groups, d3_selectionPrototype);
+ return groups;
+ }
+ var d3_select = function(s, n) {
+ return n.querySelector(s);
+ }, d3_selectAll = function(s, n) {
+ return n.querySelectorAll(s);
+ }, d3_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) {
+ return d3_selectMatcher.call(n, s);
+ };
+ if (typeof Sizzle === "function") {
+ d3_select = function(s, n) {
+ return Sizzle(s, n)[0] || null;
+ };
+ d3_selectAll = function(s, n) {
+ return Sizzle.uniqueSort(Sizzle(s, n));
+ };
+ d3_selectMatches = Sizzle.matchesSelector;
+ }
+ var d3_selectionPrototype = [];
+ d3.selection = function() {
+ return d3_selectionRoot;
+ };
+ d3.selection.prototype = d3_selectionPrototype;
+ d3_selectionPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, group, node;
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i));
+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selector(selector) {
+ return function() {
+ return d3_select(selector, this);
+ };
+ }
+ d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [], subgroup, node;
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
+ subgroup.parentNode = node;
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selectorAll(selector) {
+ return function() {
+ return d3_selectAll(selector, this);
+ };
+ }
+ d3_selectionPrototype.attr = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node();
+ name = d3.ns.qualify(name);
+ return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
+ }
+ for (value in name) this.each(d3_selection_attr(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_attr(name, value));
+ };
+ function d3_selection_attr(name, value) {
+ name = d3.ns.qualify(name);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrConstant() {
+ this.setAttribute(name, value);
+ }
+ function attrConstantNS() {
+ this.setAttributeNS(name.space, name.local, value);
+ }
+ function attrFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
+ }
+ function attrFunctionNS() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
+ }
+ return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
+ }
+ d3_selectionPrototype.classed = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
+ if (value = node.classList) {
+ while (++i < n) if (!value.contains(name[i])) return false;
+ } else {
+ value = node.className;
+ if (value.baseVal != null) value = value.baseVal;
+ while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+ }
+ return true;
+ }
+ for (value in name) this.each(d3_selection_classed(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_classed(name, value));
+ };
+ function d3_selection_classedRe(name) {
+ return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
+ }
+ function d3_selection_classed(name, value) {
+ name = name.trim().split(/\s+/).map(d3_selection_classedName);
+ var n = name.length;
+ function classedConstant() {
+ var i = -1;
+ while (++i < n) name[i](this, value);
+ }
+ function classedFunction() {
+ var i = -1, x = value.apply(this, arguments);
+ while (++i < n) name[i](this, x);
+ }
+ return typeof value === "function" ? classedFunction : classedConstant;
+ }
+ function d3_selection_classedName(name) {
+ var re = d3_selection_classedRe(name);
+ return function(node, value) {
+ if (c = node.classList) return value ? c.add(name) : c.remove(name);
+ var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
+ if (value) {
+ re.lastIndex = 0;
+ if (!re.test(cv)) {
+ cv = d3_collapse(cv + " " + name);
+ if (cb) c.baseVal = cv; else node.className = cv;
+ }
+ } else if (cv) {
+ cv = d3_collapse(cv.replace(re, " "));
+ if (cb) c.baseVal = cv; else node.className = cv;
+ }
+ };
+ }
+ d3_selectionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
+ return this;
+ }
+ if (n < 2) return getComputedStyle(this.node(), null).getPropertyValue(name);
+ priority = "";
+ }
+ return this.each(d3_selection_style(name, value, priority));
+ };
+ function d3_selection_style(name, value, priority) {
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleConstant() {
+ this.style.setProperty(name, value, priority);
+ }
+ function styleFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
+ }
+ return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
+ }
+ d3_selectionPrototype.property = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") return this.node()[name];
+ for (value in name) this.each(d3_selection_property(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_property(name, value));
+ };
+ function d3_selection_property(name, value) {
+ function propertyNull() {
+ delete this[name];
+ }
+ function propertyConstant() {
+ this[name] = value;
+ }
+ function propertyFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) delete this[name]; else this[name] = x;
+ }
+ return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
+ }
+ d3_selectionPrototype.text = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ } : value == null ? function() {
+ this.textContent = "";
+ } : function() {
+ this.textContent = value;
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ } : value == null ? function() {
+ this.innerHTML = "";
+ } : function() {
+ this.innerHTML = value;
+ }) : this.node().innerHTML;
+ };
+ d3_selectionPrototype.append = function(name) {
+ name = d3.ns.qualify(name);
+ function append() {
+ return this.appendChild(document.createElementNS(this.namespaceURI, name));
+ }
+ function appendNS() {
+ return this.appendChild(document.createElementNS(name.space, name.local));
+ }
+ return this.select(name.local ? appendNS : append);
+ };
+ d3_selectionPrototype.insert = function(name, before) {
+ name = d3.ns.qualify(name);
+ function insert() {
+ return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this));
+ }
+ function insertNS() {
+ return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this));
+ }
+ return this.select(name.local ? insertNS : insert);
+ };
+ d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+ };
+ d3_selectionPrototype.data = function(value, key) {
+ var i = -1, n = this.length, group, node;
+ if (!arguments.length) {
+ value = new Array(n = (group = this[0]).length);
+ while (++i < n) {
+ if (node = group[i]) {
+ value[i] = node.__data__;
+ }
+ }
+ return value;
+ }
+ function bind(group, groupData) {
+ var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+ if (key) {
+ var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
+ for (i = -1; ++i < n; ) {
+ keyValue = key.call(node = group[i], node.__data__, i);
+ if (nodeByKeyValue.has(keyValue)) {
+ exitNodes[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ keyValues.push(keyValue);
+ }
+ for (i = -1; ++i < m; ) {
+ keyValue = key.call(groupData, nodeData = groupData[i], i);
+ if (node = nodeByKeyValue.get(keyValue)) {
+ updateNodes[i] = node;
+ node.__data__ = nodeData;
+ } else if (!dataByKeyValue.has(keyValue)) {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ dataByKeyValue.set(keyValue, nodeData);
+ nodeByKeyValue.remove(keyValue);
+ }
+ for (i = -1; ++i < n; ) {
+ if (nodeByKeyValue.has(keyValues[i])) {
+ exitNodes[i] = group[i];
+ }
+ }
+ } else {
+ for (i = -1; ++i < n0; ) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ }
+ for (;i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ }
+ for (;i < n; ++i) {
+ exitNodes[i] = group[i];
+ }
+ }
+ enterNodes.update = updateNodes;
+ enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
+ var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
+ if (typeof value === "function") {
+ while (++i < n) {
+ bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+ }
+ } else {
+ while (++i < n) {
+ bind(group = this[i], value);
+ }
+ }
+ update.enter = function() {
+ return enter;
+ };
+ update.exit = function() {
+ return exit;
+ };
+ return update;
+ };
+ function d3_selection_dataNode(data) {
+ return {
+ __data__: data
+ };
+ }
+ d3_selectionPrototype.datum = function(value) {
+ return arguments.length ? this.property("__data__", value) : this.property("__data__");
+ };
+ d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
+ };
+ }
+ d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
+ if (node = group[i]) {
+ if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+ };
+ d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+ return this.order();
+ };
+ function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3.ascending;
+ return function(a, b) {
+ return comparator(a && a.__data__, b && b.__data__);
+ };
+ }
+ d3_selectionPrototype.on = function(type, listener, capture) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof type !== "string") {
+ if (n < 2) listener = false;
+ for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
+ return this;
+ }
+ if (n < 2) return (n = this.node()["__on" + type]) && n._;
+ capture = false;
+ }
+ return this.each(d3_selection_on(type, listener, capture));
+ };
+ function d3_selection_on(type, listener, capture) {
+ var name = "__on" + type, i = type.indexOf(".");
+ if (i > 0) type = type.substring(0, i);
+ function onRemove() {
+ var wrapper = this[name];
+ if (wrapper) {
+ this.removeEventListener(type, wrapper, wrapper.$);
+ delete this[name];
+ }
+ }
+ function onAdd() {
+ var node = this, args = d3_array(arguments);
+ onRemove.call(this);
+ this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
+ wrapper._ = listener;
+ function wrapper(e) {
+ var o = d3.event;
+ d3.event = e;
+ args[0] = node.__data__;
+ try {
+ listener.apply(node, args);
+ } finally {
+ d3.event = o;
+ }
+ }
+ }
+ return listener ? onAdd : onRemove;
+ }
+ d3_selectionPrototype.each = function(callback) {
+ return d3_selection_each(this, function(node, i, j) {
+ callback.call(node, node.__data__, i, j);
+ });
+ };
+ function d3_selection_each(groups, callback) {
+ for (var j = 0, m = groups.length; j < m; j++) {
+ for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+ if (node = group[i]) callback(node, i, j);
+ }
+ }
+ return groups;
+ }
+ d3_selectionPrototype.call = function(callback) {
+ var args = d3_array(arguments);
+ callback.apply(args[0] = this, args);
+ return this;
+ };
+ d3_selectionPrototype.empty = function() {
+ return !this.node();
+ };
+ d3_selectionPrototype.node = function() {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+ };
+ d3_selectionPrototype.transition = function() {
+ var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = Object.create(d3_transitionInherit);
+ transition.time = Date.now();
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) d3_transitionNode(node, i, id, transition);
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ var d3_selectionRoot = d3_selection([ [ document ] ]);
+ d3_selectionRoot[0].parentNode = d3_selectRoot;
+ d3.select = function(selector) {
+ return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]);
+ };
+ d3.selectAll = function(selector) {
+ return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]);
+ };
+ function d3_selection_enter(selection) {
+ d3_arraySubclass(selection, d3_selection_enterPrototype);
+ return selection;
+ }
+ var d3_selection_enterPrototype = [];
+ d3.selection.enter = d3_selection_enter;
+ d3.selection.enter.prototype = d3_selection_enterPrototype;
+ d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+ d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
+ d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+ d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+ d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, upgroup, group, node;
+ for (var j = -1, m = this.length; ++j < m; ) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_transition(groups, id) {
+ d3_arraySubclass(groups, d3_transitionPrototype);
+ groups.id = id;
+ return groups;
+ }
+ var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit = {
+ ease: d3_ease_cubicInOut,
+ delay: 0,
+ duration: 250
+ };
+ d3_transitionPrototype.call = d3_selectionPrototype.call;
+ d3_transitionPrototype.empty = d3_selectionPrototype.empty;
+ d3_transitionPrototype.node = d3_selectionPrototype.node;
+ d3.transition = function(selection) {
+ return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();
+ };
+ d3.transition.prototype = d3_transitionPrototype;
+ function d3_transitionNode(node, i, id, inherit) {
+ var lock = node.__transition__ || (node.__transition__ = {
+ active: 0,
+ count: 0
+ }), transition = lock[id];
+ if (!transition) {
+ var time = inherit.time;
+ transition = lock[id] = {
+ tween: new d3_Map(),
+ event: d3.dispatch("start", "end"),
+ time: time,
+ ease: inherit.ease,
+ delay: inherit.delay,
+ duration: inherit.duration
+ };
+ ++lock.count;
+ d3.timer(function(elapsed) {
+ var d = node.__data__, ease = transition.ease, event = transition.event, delay = transition.delay, duration = transition.duration, tweened = [];
+ return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;
+ function start(elapsed) {
+ if (lock.active > id) return stop();
+ lock.active = id;
+ event.start.call(node, d, i);
+ transition.tween.forEach(function(key, value) {
+ if (value = value.call(node, d, i)) {
+ tweened.push(value);
+ }
+ });
+ if (!tick(elapsed)) d3.timer(tick, 0, time);
+ return 1;
+ }
+ function tick(elapsed) {
+ if (lock.active !== id) return stop();
+ var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
+ while (n > 0) {
+ tweened[--n].call(node, e);
+ }
+ if (t >= 1) {
+ stop();
+ event.end.call(node, d, i);
+ return 1;
+ }
+ }
+ function stop() {
+ if (--lock.count) delete lock[id]; else delete node.__transition__;
+ return 1;
+ }
+ }, 0, time);
+ return transition;
+ }
+ }
+ d3_transitionPrototype.select = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnode, node;
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i))) {
+ if ("__data__" in node) subnode.__data__ = node.__data__;
+ d3_transitionNode(subnode, i, id, node.__transition__[id]);
+ subgroup.push(subnode);
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.selectAll = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ transition = node.__transition__[id];
+ subnodes = selector.call(node, node.__data__, i);
+ subgroups.push(subgroup = []);
+ for (var k = -1, o = subnodes.length; ++k < o; ) {
+ d3_transitionNode(subnode = subnodes[k], k, id, transition);
+ subgroup.push(subnode);
+ }
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
+ };
+ d3_transitionPrototype.attr = function(nameNS, value) {
+ if (arguments.length < 2) {
+ for (value in nameNS) this.attr(value, nameNS[value]);
+ return this;
+ }
+ var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ return d3_transition_tween(this, "attr." + nameNS, value, function(b) {
+ function attrString() {
+ var a = this.getAttribute(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttribute(name, i(t));
+ });
+ }
+ function attrStringNS() {
+ var a = this.getAttributeNS(name.space, name.local), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttributeNS(name.space, name.local, i(t));
+ });
+ }
+ return b == null ? name.local ? attrNullNS : attrNull : (b += "", name.local ? attrStringNS : attrString);
+ });
+ };
+ d3_transitionPrototype.attrTween = function(nameNS, tween) {
+ var name = d3.ns.qualify(nameNS);
+ function attrTween(d, i) {
+ var f = tween.call(this, d, i, this.getAttribute(name));
+ return f && function(t) {
+ this.setAttribute(name, f(t));
+ };
+ }
+ function attrTweenNS(d, i) {
+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+ return f && function(t) {
+ this.setAttributeNS(name.space, name.local, f(t));
+ };
+ }
+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.style(priority, name[priority], value);
+ return this;
+ }
+ priority = "";
+ }
+ var interpolate = d3_interpolateByName(name);
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ return d3_transition_tween(this, "style." + name, value, function(b) {
+ function styleString() {
+ var a = getComputedStyle(this, null).getPropertyValue(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.style.setProperty(name, i(t), priority);
+ });
+ }
+ return b == null ? styleNull : (b += "", styleString);
+ });
+ };
+ d3_transitionPrototype.styleTween = function(name, tween, priority) {
+ if (arguments.length < 3) priority = "";
+ return this.tween("style." + name, function(d, i) {
+ var f = tween.call(this, d, i, getComputedStyle(this, null).getPropertyValue(name));
+ return f && function(t) {
+ this.style.setProperty(name, f(t), priority);
+ };
+ });
+ };
+ d3_transitionPrototype.text = function(value) {
+ return d3_transition_tween(this, "text", value, d3_transition_text);
+ };
+ function d3_transition_text(b) {
+ if (b == null) b = "";
+ return function() {
+ this.textContent = b;
+ };
+ }
+ d3_transitionPrototype.remove = function() {
+ return this.each("end.transition", function() {
+ var p;
+ if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
+ });
+ };
+ d3_transitionPrototype.ease = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].ease;
+ if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
+ return d3_selection_each(this, function(node) {
+ node.__transition__[id].ease = value;
+ });
+ };
+ d3_transitionPrototype.delay = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0;
+ } : (value |= 0, function(node) {
+ node.__transition__[id].delay = value;
+ }));
+ };
+ d3_transitionPrototype.duration = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0);
+ } : (value = Math.max(1, value | 0), function(node) {
+ node.__transition__[id].duration = value;
+ }));
+ };
+ d3_transitionPrototype.each = function(type, listener) {
+ var id = this.id;
+ if (arguments.length < 2) {
+ var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
+ d3_transitionInheritId = id;
+ d3_selection_each(this, function(node, i, j) {
+ d3_transitionInherit = node.__transition__[id];
+ type.call(node, node.__data__, i, j);
+ });
+ d3_transitionInherit = inherit;
+ d3_transitionInheritId = inheritId;
+ } else {
+ d3_selection_each(this, function(node) {
+ node.__transition__[id].event.on(type, listener);
+ });
+ }
+ return this;
+ };
+ d3_transitionPrototype.transition = function() {
+ var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition;
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if (node = group[i]) {
+ transition = Object.create(node.__transition__[id0]);
+ transition.delay += transition.duration;
+ d3_transitionNode(node, i, id1, transition);
+ }
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id1);
+ };
+ d3_transitionPrototype.tween = function(name, tween) {
+ var id = this.id;
+ if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
+ return d3_selection_each(this, tween == null ? function(node) {
+ node.__transition__[id].tween.remove(name);
+ } : function(node) {
+ node.__transition__[id].tween.set(name, tween);
+ });
+ };
+ function d3_transition_tween(groups, name, value, tween) {
+ var id = groups.id;
+ return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
+ } : (value = tween(value), function(node) {
+ node.__transition__[id].tween.set(name, value);
+ }));
+ }
+ var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
+ d3.timer = function(callback, delay, then) {
+ if (arguments.length < 3) {
+ if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
+ then = Date.now();
+ }
+ var timer = d3_timer_byId[callback.id];
+ if (timer && timer.callback === callback) {
+ timer.then = then;
+ timer.delay = delay;
+ } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
+ callback: callback,
+ then: then,
+ delay: delay,
+ next: d3_timer_queue
+ };
+ if (!d3_timer_interval) {
+ d3_timer_timeout = clearTimeout(d3_timer_timeout);
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ };
+ function d3_timer_step() {
+ var elapsed, now = Date.now(), t1 = d3_timer_queue;
+ while (t1) {
+ elapsed = now - t1.then;
+ if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
+ t1 = t1.next;
+ }
+ var delay = d3_timer_flush() - now;
+ if (delay > 24) {
+ if (isFinite(delay)) {
+ clearTimeout(d3_timer_timeout);
+ d3_timer_timeout = setTimeout(d3_timer_step, delay);
+ }
+ d3_timer_interval = 0;
+ } else {
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ }
+ d3.timer.flush = function() {
+ var elapsed, now = Date.now(), t1 = d3_timer_queue;
+ while (t1) {
+ elapsed = now - t1.then;
+ if (!t1.delay) t1.flush = t1.callback(elapsed);
+ t1 = t1.next;
+ }
+ d3_timer_flush();
+ };
+ function d3_timer_flush() {
+ var t0 = null, t1 = d3_timer_queue, then = Infinity;
+ while (t1) {
+ if (t1.flush) {
+ delete d3_timer_byId[t1.callback.id];
+ t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
+ } else {
+ then = Math.min(then, t1.then + t1.delay);
+ t1 = (t0 = t1).next;
+ }
+ }
+ return then;
+ }
+ var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
+ setTimeout(callback, 17);
+ };
+ d3.mouse = function(container) {
+ return d3_mousePoint(container, d3_eventSource());
+ };
+ var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;
+ function d3_mousePoint(container, e) {
+ var svg = container.ownerSVGElement || container;
+ if (svg.createSVGPoint) {
+ var point = svg.createSVGPoint();
+ if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) {
+ svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0);
+ var ctm = svg[0][0].getScreenCTM();
+ d3_mouse_bug44083 = !(ctm.f || ctm.e);
+ svg.remove();
+ }
+ if (d3_mouse_bug44083) {
+ point.x = e.pageX;
+ point.y = e.pageY;
+ } else {
+ point.x = e.clientX;
+ point.y = e.clientY;
+ }
+ point = point.matrixTransform(container.getScreenCTM().inverse());
+ return [ point.x, point.y ];
+ }
+ var rect = container.getBoundingClientRect();
+ return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
+ }
+ d3.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3_eventSource().touches;
+ return touches ? d3_array(touches).map(function(touch) {
+ var point = d3_mousePoint(container, touch);
+ point.identifier = touch.identifier;
+ return point;
+ }) : [];
+ };
+ function d3_noop() {}
+ d3.scale = {};
+ function d3_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+ }
+ function d3_scale_nice(domain, nice) {
+ var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
+ if (x1 < x0) {
+ dx = i0, i0 = i1, i1 = dx;
+ dx = x0, x0 = x1, x1 = dx;
+ }
+ if (nice = nice(x1 - x0)) {
+ domain[i0] = nice.floor(x0);
+ domain[i1] = nice.ceil(x1);
+ }
+ return domain;
+ }
+ function d3_scale_niceDefault() {
+ return Math;
+ }
+ d3.scale.linear = function() {
+ return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false);
+ };
+ function d3_scale_linear(domain, range, interpolate, clamp) {
+ var output, input;
+ function rescale() {
+ var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
+ output = linear(domain, range, uninterpolate, interpolate);
+ input = linear(range, domain, uninterpolate, d3.interpolate);
+ return scale;
+ }
+ function scale(x) {
+ return output(x);
+ }
+ scale.invert = function(y) {
+ return input(y);
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(Number);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.rangeRound = function(x) {
+ return scale.range(x).interpolate(d3.interpolateRound);
+ };
+ scale.clamp = function(x) {
+ if (!arguments.length) return clamp;
+ clamp = x;
+ return rescale();
+ };
+ scale.interpolate = function(x) {
+ if (!arguments.length) return interpolate;
+ interpolate = x;
+ return rescale();
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(domain, m);
+ };
+ scale.nice = function() {
+ d3_scale_nice(domain, d3_scale_linearNice);
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_linear(domain, range, interpolate, clamp);
+ };
+ return rescale();
+ }
+ function d3_scale_linearRebind(scale, linear) {
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ }
+ function d3_scale_linearNice(dx) {
+ dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
+ return dx && {
+ floor: function(x) {
+ return Math.floor(x / dx) * dx;
+ },
+ ceil: function(x) {
+ return Math.ceil(x / dx) * dx;
+ }
+ };
+ }
+ function d3_scale_linearTickRange(domain, m) {
+ var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
+ if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
+ extent[0] = Math.ceil(extent[0] / step) * step;
+ extent[1] = Math.floor(extent[1] / step) * step + step * .5;
+ extent[2] = step;
+ return extent;
+ }
+ function d3_scale_linearTicks(domain, m) {
+ return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+ }
+ function d3_scale_linearTickFormat(domain, m) {
+ return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
+ }
+ function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
+ var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
+ return function(x) {
+ return i(u(x));
+ };
+ }
+ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
+ var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
+ if (domain[k] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+ while (++j <= k) {
+ u.push(uninterpolate(domain[j - 1], domain[j]));
+ i.push(interpolate(range[j - 1], range[j]));
+ }
+ return function(x) {
+ var j = d3.bisect(domain, x, 1, k) - 1;
+ return i[j](u[j](x));
+ };
+ }
+ d3.scale.log = function() {
+ return d3_scale_log(d3.scale.linear(), d3_scale_logp);
+ };
+ function d3_scale_log(linear, log) {
+ var pow = log.pow;
+ function scale(x) {
+ return linear(log(x));
+ }
+ scale.invert = function(x) {
+ return pow(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(pow);
+ log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
+ pow = log.pow;
+ linear.domain(x.map(log));
+ return scale;
+ };
+ scale.nice = function() {
+ linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
+ return scale;
+ };
+ scale.ticks = function() {
+ var extent = d3_scaleExtent(linear.domain()), ticks = [];
+ if (extent.every(isFinite)) {
+ var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]);
+ if (log === d3_scale_logn) {
+ ticks.push(pow(i));
+ for (;i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
+ } else {
+ for (;i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
+ ticks.push(pow(i));
+ }
+ for (i = 0; ticks[i] < u; i++) {}
+ for (j = ticks.length; ticks[j - 1] > v; j--) {}
+ ticks = ticks.slice(i, j);
+ }
+ return ticks;
+ };
+ scale.tickFormat = function(n, format) {
+ if (arguments.length < 2) format = d3_scale_logFormat;
+ if (!arguments.length) return format;
+ var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12,
+ Math.floor) : (e = 1e-12, Math.ceil), e;
+ return function(d) {
+ return d / pow(f(log(d) + e)) <= k ? format(d) : "";
+ };
+ };
+ scale.copy = function() {
+ return d3_scale_log(linear.copy(), log);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ var d3_scale_logFormat = d3.format(".0e");
+ function d3_scale_logp(x) {
+ return Math.log(x < 0 ? 0 : x) / Math.LN10;
+ }
+ function d3_scale_logn(x) {
+ return -Math.log(x > 0 ? 0 : -x) / Math.LN10;
+ }
+ d3_scale_logp.pow = function(x) {
+ return Math.pow(10, x);
+ };
+ d3_scale_logn.pow = function(x) {
+ return -Math.pow(10, -x);
+ };
+ d3.scale.pow = function() {
+ return d3_scale_pow(d3.scale.linear(), 1);
+ };
+ function d3_scale_pow(linear, exponent) {
+ var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
+ function scale(x) {
+ return linear(powp(x));
+ }
+ scale.invert = function(x) {
+ return powb(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(powb);
+ linear.domain(x.map(powp));
+ return scale;
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(scale.domain(), m);
+ };
+ scale.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(scale.domain(), m);
+ };
+ scale.nice = function() {
+ return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
+ };
+ scale.exponent = function(x) {
+ if (!arguments.length) return exponent;
+ var domain = scale.domain();
+ powp = d3_scale_powPow(exponent = x);
+ powb = d3_scale_powPow(1 / exponent);
+ return scale.domain(domain);
+ };
+ scale.copy = function() {
+ return d3_scale_pow(linear.copy(), exponent);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_scale_powPow(e) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
+ };
+ }
+ d3.scale.sqrt = function() {
+ return d3.scale.pow().exponent(.5);
+ };
+ d3.scale.ordinal = function() {
+ return d3_scale_ordinal([], {
+ t: "range",
+ a: [ [] ]
+ });
+ };
+ function d3_scale_ordinal(domain, ranger) {
+ var index, range, rangeBand;
+ function scale(x) {
+ return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
+ }
+ function steps(start, step) {
+ return d3.range(domain.length).map(function(i) {
+ return start + step * i;
+ });
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = [];
+ index = new d3_Map();
+ var i = -1, n = x.length, xi;
+ while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
+ return scale[ranger.t].apply(scale, ranger.a);
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ rangeBand = 0;
+ ranger = {
+ t: "range",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangePoints = function(x, padding) {
+ if (arguments.length < 2) padding = 0;
+ var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
+ rangeBand = 0;
+ ranger = {
+ t: "rangePoints",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
+ range = steps(start + step * outerPadding, step);
+ if (reverse) range.reverse();
+ rangeBand = step * (1 - padding);
+ ranger = {
+ t: "rangeBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeRoundBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
+ range = steps(start + Math.round(error / 2), step);
+ if (reverse) range.reverse();
+ rangeBand = Math.round(step * (1 - padding));
+ ranger = {
+ t: "rangeRoundBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBand = function() {
+ return rangeBand;
+ };
+ scale.rangeExtent = function() {
+ return d3_scaleExtent(ranger.a[0]);
+ };
+ scale.copy = function() {
+ return d3_scale_ordinal(domain, ranger);
+ };
+ return scale.domain(domain);
+ }
+ d3.scale.category10 = function() {
+ return d3.scale.ordinal().range(d3_category10);
+ };
+ d3.scale.category20 = function() {
+ return d3.scale.ordinal().range(d3_category20);
+ };
+ d3.scale.category20b = function() {
+ return d3.scale.ordinal().range(d3_category20b);
+ };
+ d3.scale.category20c = function() {
+ return d3.scale.ordinal().range(d3_category20c);
+ };
+ var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ];
+ var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ];
+ var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ];
+ var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ];
+ d3.scale.quantile = function() {
+ return d3_scale_quantile([], []);
+ };
+ function d3_scale_quantile(domain, range) {
+ var thresholds;
+ function rescale() {
+ var k = 0, q = range.length;
+ thresholds = [];
+ while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+ return scale;
+ }
+ function scale(x) {
+ if (isNaN(x = +x)) return NaN;
+ return range[d3.bisect(thresholds, x)];
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.filter(function(d) {
+ return !isNaN(d);
+ }).sort(d3.ascending);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.quantiles = function() {
+ return thresholds;
+ };
+ scale.copy = function() {
+ return d3_scale_quantile(domain, range);
+ };
+ return rescale();
+ }
+ d3.scale.quantize = function() {
+ return d3_scale_quantize(0, 1, [ 0, 1 ]);
+ };
+ function d3_scale_quantize(x0, x1, range) {
+ var kx, i;
+ function scale(x) {
+ return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
+ }
+ function rescale() {
+ kx = range.length / (x1 - x0);
+ i = range.length - 1;
+ return scale;
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return [ x0, x1 ];
+ x0 = +x[0];
+ x1 = +x[x.length - 1];
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_quantize(x0, x1, range);
+ };
+ return rescale();
+ }
+ d3.scale.threshold = function() {
+ return d3_scale_threshold([ .5 ], [ 0, 1 ]);
+ };
+ function d3_scale_threshold(domain, range) {
+ function scale(x) {
+ return range[d3.bisect(domain, x)];
+ }
+ scale.domain = function(_) {
+ if (!arguments.length) return domain;
+ domain = _;
+ return scale;
+ };
+ scale.range = function(_) {
+ if (!arguments.length) return range;
+ range = _;
+ return scale;
+ };
+ scale.copy = function() {
+ return d3_scale_threshold(domain, range);
+ };
+ return scale;
+ }
+ d3.scale.identity = function() {
+ return d3_scale_identity([ 0, 1 ]);
+ };
+ function d3_scale_identity(domain) {
+ function identity(x) {
+ return +x;
+ }
+ identity.invert = identity;
+ identity.domain = identity.range = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(identity);
+ return identity;
+ };
+ identity.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ identity.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(domain, m);
+ };
+ identity.copy = function() {
+ return d3_scale_identity(domain);
+ };
+ return identity;
+ }
+ d3.svg = {};
+ d3.svg.arc = function() {
+ var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function arc() {
+ var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0,
+ a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
+ return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
+ }
+ arc.innerRadius = function(v) {
+ if (!arguments.length) return innerRadius;
+ innerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.outerRadius = function(v) {
+ if (!arguments.length) return outerRadius;
+ outerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return arc;
+ };
+ arc.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return arc;
+ };
+ arc.centroid = function() {
+ var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
+ return [ Math.cos(a) * r, Math.sin(a) * r ];
+ };
+ return arc;
+ };
+ var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6;
+ function d3_svg_arcInnerRadius(d) {
+ return d.innerRadius;
+ }
+ function d3_svg_arcOuterRadius(d) {
+ return d.outerRadius;
+ }
+ function d3_svg_arcStartAngle(d) {
+ return d.startAngle;
+ }
+ function d3_svg_arcEndAngle(d) {
+ return d.endAngle;
+ }
+ function d3_svg_line(projection) {
+ var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
+ function line(data) {
+ var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
+ function segment() {
+ segments.push("M", interpolate(projection(points), tension));
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
+ } else if (points.length) {
+ segment();
+ points = [];
+ }
+ }
+ if (points.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ line.x = function(_) {
+ if (!arguments.length) return x;
+ x = _;
+ return line;
+ };
+ line.y = function(_) {
+ if (!arguments.length) return y;
+ y = _;
+ return line;
+ };
+ line.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return line;
+ };
+ line.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ return line;
+ };
+ line.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return line;
+ };
+ return line;
+ }
+ d3.svg.line = function() {
+ return d3_svg_line(d3_identity);
+ };
+ function d3_svg_lineX(d) {
+ return d[0];
+ }
+ function d3_svg_lineY(d) {
+ return d[1];
+ }
+ var d3_svg_lineInterpolators = d3.map({
+ linear: d3_svg_lineLinear,
+ "linear-closed": d3_svg_lineLinearClosed,
+ "step-before": d3_svg_lineStepBefore,
+ "step-after": d3_svg_lineStepAfter,
+ basis: d3_svg_lineBasis,
+ "basis-open": d3_svg_lineBasisOpen,
+ "basis-closed": d3_svg_lineBasisClosed,
+ bundle: d3_svg_lineBundle,
+ cardinal: d3_svg_lineCardinal,
+ "cardinal-open": d3_svg_lineCardinalOpen,
+ "cardinal-closed": d3_svg_lineCardinalClosed,
+ monotone: d3_svg_lineMonotone
+ });
+ d3_svg_lineInterpolators.forEach(function(key, value) {
+ value.key = key;
+ value.closed = /-closed$/.test(key);
+ });
+ function d3_svg_lineLinear(points) {
+ return points.join("L");
+ }
+ function d3_svg_lineLinearClosed(points) {
+ return d3_svg_lineLinear(points) + "Z";
+ }
+ function d3_svg_lineStepBefore(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepAfter(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
+ return path.join("");
+ }
+ function d3_svg_lineCardinalOpen(points, tension) {
+ return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineCardinalClosed(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]),
+ points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
+ }
+ function d3_svg_lineCardinal(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineHermite(points, tangents) {
+ if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
+ return d3_svg_lineLinear(points);
+ }
+ var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
+ if (quad) {
+ path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
+ p0 = points[1];
+ pi = 2;
+ }
+ if (tangents.length > 1) {
+ t = tangents[1];
+ p = points[pi];
+ pi++;
+ path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ for (var i = 2; i < tangents.length; i++, pi++) {
+ p = points[pi];
+ t = tangents[i];
+ path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ }
+ }
+ if (quad) {
+ var lp = points[pi];
+ path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
+ }
+ return path;
+ }
+ function d3_svg_lineCardinalTangents(points, tension) {
+ var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
+ while (++i < n) {
+ p0 = p1;
+ p1 = p2;
+ p2 = points[i];
+ tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineBasis(points) {
+ if (points.length < 3) return d3_svg_lineLinear(points);
+ var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ];
+ d3_svg_lineBasisBezier(path, px, py);
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ i = -1;
+ while (++i < 2) {
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisOpen(points) {
+ if (points.length < 4) return d3_svg_lineLinear(points);
+ var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
+ while (++i < 3) {
+ pi = points[i];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
+ --i;
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisClosed(points) {
+ var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
+ while (++i < 4) {
+ pi = points[i % n];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ --i;
+ while (++i < m) {
+ pi = points[i % n];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBundle(points, tension) {
+ var n = points.length - 1;
+ if (n) {
+ var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
+ while (++i <= n) {
+ p = points[i];
+ t = i / n;
+ p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
+ p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
+ }
+ }
+ return d3_svg_lineBasis(points);
+ }
+ function d3_svg_lineDot4(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+ }
+ var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
+ function d3_svg_lineBasisBezier(path, x, y) {
+ path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
+ }
+ function d3_svg_lineSlope(p0, p1) {
+ return (p1[1] - p0[1]) / (p1[0] - p0[0]);
+ }
+ function d3_svg_lineFiniteDifferences(points) {
+ var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
+ while (++i < j) {
+ m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
+ }
+ m[i] = d;
+ return m;
+ }
+ function d3_svg_lineMonotoneTangents(points) {
+ var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
+ while (++i < j) {
+ d = d3_svg_lineSlope(points[i], points[i + 1]);
+ if (Math.abs(d) < 1e-6) {
+ m[i] = m[i + 1] = 0;
+ } else {
+ a = m[i] / d;
+ b = m[i + 1] / d;
+ s = a * a + b * b;
+ if (s > 9) {
+ s = d * 3 / Math.sqrt(s);
+ m[i] = s * a;
+ m[i + 1] = s * b;
+ }
+ }
+ }
+ i = -1;
+ while (++i <= j) {
+ s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
+ tangents.push([ s || 0, m[i] * s || 0 ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineMonotone(points) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
+ }
+ d3.svg.line.radial = function() {
+ var line = d3_svg_line(d3_svg_lineRadial);
+ line.radius = line.x, delete line.x;
+ line.angle = line.y, delete line.y;
+ return line;
+ };
+ function d3_svg_lineRadial(points) {
+ var point, i = -1, n = points.length, r, a;
+ while (++i < n) {
+ point = points[i];
+ r = point[0];
+ a = point[1] + d3_svg_arcOffset;
+ point[0] = r * Math.cos(a);
+ point[1] = r * Math.sin(a);
+ }
+ return points;
+ }
+ function d3_svg_area(projection) {
+ var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
+ function area(data) {
+ var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
+ return x;
+ } : d3_functor(x1), fy1 = y0 === y1 ? function() {
+ return y;
+ } : d3_functor(y1), x, y;
+ function segment() {
+ segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
+ points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
+ } else if (points0.length) {
+ segment();
+ points0 = [];
+ points1 = [];
+ }
+ }
+ if (points0.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ area.x = function(_) {
+ if (!arguments.length) return x1;
+ x0 = x1 = _;
+ return area;
+ };
+ area.x0 = function(_) {
+ if (!arguments.length) return x0;
+ x0 = _;
+ return area;
+ };
+ area.x1 = function(_) {
+ if (!arguments.length) return x1;
+ x1 = _;
+ return area;
+ };
+ area.y = function(_) {
+ if (!arguments.length) return y1;
+ y0 = y1 = _;
+ return area;
+ };
+ area.y0 = function(_) {
+ if (!arguments.length) return y0;
+ y0 = _;
+ return area;
+ };
+ area.y1 = function(_) {
+ if (!arguments.length) return y1;
+ y1 = _;
+ return area;
+ };
+ area.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return area;
+ };
+ area.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ interpolateReverse = interpolate.reverse || interpolate;
+ L = interpolate.closed ? "M" : "L";
+ return area;
+ };
+ area.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return area;
+ };
+ return area;
+ }
+ d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+ d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+ d3.svg.area = function() {
+ return d3_svg_area(d3_identity);
+ };
+ d3.svg.area.radial = function() {
+ var area = d3_svg_area(d3_svg_lineRadial);
+ area.radius = area.x, delete area.x;
+ area.innerRadius = area.x0, delete area.x0;
+ area.outerRadius = area.x1, delete area.x1;
+ area.angle = area.y, delete area.y;
+ area.startAngle = area.y0, delete area.y0;
+ area.endAngle = area.y1, delete area.y1;
+ return area;
+ };
+ d3.svg.chord = function() {
+ var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function chord(d, i) {
+ var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
+ return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
+ }
+ function subgroup(self, f, d, i) {
+ var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
+ return {
+ r: r,
+ a0: a0,
+ a1: a1,
+ p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
+ p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
+ };
+ }
+ function equals(a, b) {
+ return a.a0 == b.a0 && a.a1 == b.a1;
+ }
+ function arc(r, p, a) {
+ return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
+ }
+ function curve(r0, p0, r1, p1) {
+ return "Q 0,0 " + p1;
+ }
+ chord.radius = function(v) {
+ if (!arguments.length) return radius;
+ radius = d3_functor(v);
+ return chord;
+ };
+ chord.source = function(v) {
+ if (!arguments.length) return source;
+ source = d3_functor(v);
+ return chord;
+ };
+ chord.target = function(v) {
+ if (!arguments.length) return target;
+ target = d3_functor(v);
+ return chord;
+ };
+ chord.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return chord;
+ };
+ chord.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return chord;
+ };
+ return chord;
+ };
+ function d3_svg_chordRadius(d) {
+ return d.radius;
+ }
+ d3.svg.diagonal = function() {
+ var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
+ function diagonal(d, i) {
+ var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
+ x: p0.x,
+ y: m
+ }, {
+ x: p3.x,
+ y: m
+ }, p3 ];
+ p = p.map(projection);
+ return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
+ }
+ diagonal.source = function(x) {
+ if (!arguments.length) return source;
+ source = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.target = function(x) {
+ if (!arguments.length) return target;
+ target = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.projection = function(x) {
+ if (!arguments.length) return projection;
+ projection = x;
+ return diagonal;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalProjection(d) {
+ return [ d.x, d.y ];
+ }
+ d3.svg.diagonal.radial = function() {
+ var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
+ diagonal.projection = function(x) {
+ return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalRadialProjection(projection) {
+ return function() {
+ var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
+ return [ r * Math.cos(a), r * Math.sin(a) ];
+ };
+ }
+ d3.svg.symbol = function() {
+ var type = d3_svg_symbolType, size = d3_svg_symbolSize;
+ function symbol(d, i) {
+ return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
+ }
+ symbol.type = function(x) {
+ if (!arguments.length) return type;
+ type = d3_functor(x);
+ return symbol;
+ };
+ symbol.size = function(x) {
+ if (!arguments.length) return size;
+ size = d3_functor(x);
+ return symbol;
+ };
+ return symbol;
+ };
+ function d3_svg_symbolSize() {
+ return 64;
+ }
+ function d3_svg_symbolType() {
+ return "circle";
+ }
+ function d3_svg_symbolCircle(size) {
+ var r = Math.sqrt(size / π);
+ return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
+ }
+ var d3_svg_symbols = d3.map({
+ circle: d3_svg_symbolCircle,
+ cross: function(size) {
+ var r = Math.sqrt(size / 5) / 2;
+ return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
+ },
+ diamond: function(size) {
+ var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
+ return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
+ },
+ square: function(size) {
+ var r = Math.sqrt(size) / 2;
+ return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
+ },
+ "triangle-down": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
+ },
+ "triangle-up": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
+ }
+ });
+ d3.svg.symbolTypes = d3_svg_symbols.keys();
+ var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
+ d3.svg.axis = function() {
+ var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0;
+ function axis(g) {
+ g.each(function() {
+ var g = d3.select(this);
+ var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;
+ var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1);
+ var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
+ var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = d3.transition(path);
+ var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
+ this.__chart__ = scale1;
+ path.enter().append("path").attr("class", "domain");
+ tickEnter.append("line").attr("class", "tick");
+ tickEnter.append("text");
+ var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
+ switch (orient) {
+ case "bottom":
+ {
+ tickTransform = d3_svg_axisX;
+ subtickEnter.attr("y2", tickMinorSize);
+ subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
+ lineEnter.attr("y2", tickMajorSize);
+ textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
+ lineUpdate.attr("x2", 0).attr("y2", tickMajorSize);
+ textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding);
+ text.attr("dy", ".71em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
+ break;
+ }
+
+ case "top":
+ {
+ tickTransform = d3_svg_axisX;
+ subtickEnter.attr("y2", -tickMinorSize);
+ subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
+ lineEnter.attr("y2", -tickMajorSize);
+ textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
+ lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize);
+ textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
+ text.attr("dy", "0em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
+ break;
+ }
+
+ case "left":
+ {
+ tickTransform = d3_svg_axisY;
+ subtickEnter.attr("x2", -tickMinorSize);
+ subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
+ lineEnter.attr("x2", -tickMajorSize);
+ textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
+ lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
+ textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "end");
+ pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
+ break;
+ }
+
+ case "right":
+ {
+ tickTransform = d3_svg_axisY;
+ subtickEnter.attr("x2", tickMinorSize);
+ subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
+ lineEnter.attr("x2", tickMajorSize);
+ textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding);
+ lineUpdate.attr("x2", tickMajorSize).attr("y2", 0);
+ textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "start");
+ pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
+ break;
+ }
+ }
+ if (scale.ticks) {
+ tickEnter.call(tickTransform, scale0);
+ tickUpdate.call(tickTransform, scale1);
+ tickExit.call(tickTransform, scale1);
+ subtickEnter.call(tickTransform, scale0);
+ subtickUpdate.call(tickTransform, scale1);
+ subtickExit.call(tickTransform, scale1);
+ } else {
+ var dx = scale1.rangeBand() / 2, x = function(d) {
+ return scale1(d) + dx;
+ };
+ tickEnter.call(tickTransform, x);
+ tickUpdate.call(tickTransform, x);
+ }
+ });
+ }
+ axis.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = x;
+ return axis;
+ };
+ axis.orient = function(x) {
+ if (!arguments.length) return orient;
+ orient = x;
+ return axis;
+ };
+ axis.ticks = function() {
+ if (!arguments.length) return tickArguments_;
+ tickArguments_ = arguments;
+ return axis;
+ };
+ axis.tickValues = function(x) {
+ if (!arguments.length) return tickValues;
+ tickValues = x;
+ return axis;
+ };
+ axis.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat_;
+ tickFormat_ = x;
+ return axis;
+ };
+ axis.tickSize = function(x, y) {
+ if (!arguments.length) return tickMajorSize;
+ var n = arguments.length - 1;
+ tickMajorSize = +x;
+ tickMinorSize = n > 1 ? +y : tickMajorSize;
+ tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
+ return axis;
+ };
+ axis.tickPadding = function(x) {
+ if (!arguments.length) return tickPadding;
+ tickPadding = +x;
+ return axis;
+ };
+ axis.tickSubdivide = function(x) {
+ if (!arguments.length) return tickSubdivide;
+ tickSubdivide = +x;
+ return axis;
+ };
+ return axis;
+ };
+ function d3_svg_axisX(selection, x) {
+ selection.attr("transform", function(d) {
+ return "translate(" + x(d) + ",0)";
+ });
+ }
+ function d3_svg_axisY(selection, y) {
+ selection.attr("transform", function(d) {
+ return "translate(0," + y(d) + ")";
+ });
+ }
+ function d3_svg_axisSubdivide(scale, ticks, m) {
+ subticks = [];
+ if (m && ticks.length > 1) {
+ var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v;
+ while (++i < n) {
+ for (j = m; --j > 0; ) {
+ if ((v = +ticks[i] - j * d) >= extent[0]) {
+ subticks.push(v);
+ }
+ }
+ }
+ for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {
+ subticks.push(v);
+ }
+ }
+ return subticks;
+ }
+ d3.svg.brush = function() {
+ var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain;
+ function brush(g) {
+ g.each(function() {
+ var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e;
+ g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
+ bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
+ fg.enter().append("rect").attr("class", "extent").style("cursor", "move");
+ tz.enter().append("g").attr("class", function(d) {
+ return "resize " + d;
+ }).style("cursor", function(d) {
+ return d3_svg_brushCursor[d];
+ }).append("rect").attr("x", function(d) {
+ return /[ew]$/.test(d) ? -3 : null;
+ }).attr("y", function(d) {
+ return /^[ns]/.test(d) ? -3 : null;
+ }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
+ tz.style("display", brush.empty() ? "none" : null);
+ tz.exit().remove();
+ if (x) {
+ e = d3_scaleRange(x);
+ bg.attr("x", e[0]).attr("width", e[1] - e[0]);
+ redrawX(g);
+ }
+ if (y) {
+ e = d3_scaleRange(y);
+ bg.attr("y", e[0]).attr("height", e[1] - e[0]);
+ redrawY(g);
+ }
+ redraw(g);
+ });
+ }
+ function redraw(g) {
+ g.selectAll(".resize").attr("transform", function(d) {
+ return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")";
+ });
+ }
+ function redrawX(g) {
+ g.select(".extent").attr("x", extent[0][0]);
+ g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]);
+ }
+ function redrawY(g) {
+ g.select(".extent").attr("y", extent[0][1]);
+ g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]);
+ }
+ function brushstart() {
+ var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset;
+ var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup);
+ if (dragging) {
+ origin[0] = extent[0][0] - origin[0];
+ origin[1] = extent[0][1] - origin[1];
+ } else if (resizing) {
+ var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
+ offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];
+ origin[0] = extent[ex][0];
+ origin[1] = extent[ey][1];
+ } else if (d3.event.altKey) center = origin.slice();
+ g.style("pointer-events", "none").selectAll(".resize").style("display", null);
+ d3.select("body").style("cursor", eventTarget.style("cursor"));
+ event_({
+ type: "brushstart"
+ });
+ brushmove();
+ d3_eventCancel();
+ function mouse() {
+ var touches = d3.event.changedTouches;
+ return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
+ }
+ function keydown() {
+ if (d3.event.keyCode == 32) {
+ if (!dragging) {
+ center = null;
+ origin[0] -= extent[1][0];
+ origin[1] -= extent[1][1];
+ dragging = 2;
+ }
+ d3_eventCancel();
+ }
+ }
+ function keyup() {
+ if (d3.event.keyCode == 32 && dragging == 2) {
+ origin[0] += extent[1][0];
+ origin[1] += extent[1][1];
+ dragging = 0;
+ d3_eventCancel();
+ }
+ }
+ function brushmove() {
+ var point = mouse(), moved = false;
+ if (offset) {
+ point[0] += offset[0];
+ point[1] += offset[1];
+ }
+ if (!dragging) {
+ if (d3.event.altKey) {
+ if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ];
+ origin[0] = extent[+(point[0] < center[0])][0];
+ origin[1] = extent[+(point[1] < center[1])][1];
+ } else center = null;
+ }
+ if (resizingX && move1(point, x, 0)) {
+ redrawX(g);
+ moved = true;
+ }
+ if (resizingY && move1(point, y, 1)) {
+ redrawY(g);
+ moved = true;
+ }
+ if (moved) {
+ redraw(g);
+ event_({
+ type: "brush",
+ mode: dragging ? "move" : "resize"
+ });
+ }
+ }
+ function move1(point, scale, i) {
+ var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max;
+ if (dragging) {
+ r0 -= position;
+ r1 -= size + position;
+ }
+ min = Math.max(r0, Math.min(r1, point[i]));
+ if (dragging) {
+ max = (min += position) + size;
+ } else {
+ if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
+ if (position < min) {
+ max = min;
+ min = position;
+ } else {
+ max = position;
+ }
+ }
+ if (extent[0][i] !== min || extent[1][i] !== max) {
+ extentDomain = null;
+ extent[0][i] = min;
+ extent[1][i] = max;
+ return true;
+ }
+ }
+ function brushend() {
+ brushmove();
+ g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
+ d3.select("body").style("cursor", null);
+ w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
+ event_({
+ type: "brushend"
+ });
+ d3_eventCancel();
+ }
+ }
+ brush.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.extent = function(z) {
+ var x0, x1, y0, y1, t;
+ if (!arguments.length) {
+ z = extentDomain || extent;
+ if (x) {
+ x0 = z[0][0], x1 = z[1][0];
+ if (!extentDomain) {
+ x0 = extent[0][0], x1 = extent[1][0];
+ if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ }
+ }
+ if (y) {
+ y0 = z[0][1], y1 = z[1][1];
+ if (!extentDomain) {
+ y0 = extent[0][1], y1 = extent[1][1];
+ if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ }
+ }
+ return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
+ }
+ extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];
+ if (x) {
+ x0 = z[0], x1 = z[1];
+ if (y) x0 = x0[0], x1 = x1[0];
+ extentDomain[0][0] = x0, extentDomain[1][0] = x1;
+ if (x.invert) x0 = x(x0), x1 = x(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;
+ }
+ if (y) {
+ y0 = z[0], y1 = z[1];
+ if (x) y0 = y0[1], y1 = y1[1];
+ extentDomain[0][1] = y0, extentDomain[1][1] = y1;
+ if (y.invert) y0 = y(y0), y1 = y(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;
+ }
+ return brush;
+ };
+ brush.clear = function() {
+ extentDomain = null;
+ extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;
+ return brush;
+ };
+ brush.empty = function() {
+ return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1];
+ };
+ return d3.rebind(brush, event, "on");
+ };
+ var d3_svg_brushCursor = {
+ n: "ns-resize",
+ e: "ew-resize",
+ s: "ns-resize",
+ w: "ew-resize",
+ nw: "nwse-resize",
+ ne: "nesw-resize",
+ se: "nwse-resize",
+ sw: "nesw-resize"
+ };
+ var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
+ d3.behavior = {};
+ d3.behavior.drag = function() {
+ var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null;
+ function drag() {
+ this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown);
+ }
+ function mousedown() {
+ var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, origin_ = point(), moved = 0;
+ var w = d3.select(window).on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
+ if (origin) {
+ offset = origin.apply(target, arguments);
+ offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
+ } else {
+ offset = [ 0, 0 ];
+ }
+ if (touchId == null) d3_eventCancel();
+ event_({
+ type: "dragstart"
+ });
+ function point() {
+ var p = target.parentNode;
+ return touchId != null ? d3.touches(p).filter(function(p) {
+ return p.identifier === touchId;
+ })[0] : d3.mouse(p);
+ }
+ function dragmove() {
+ if (!target.parentNode) return dragend();
+ var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
+ moved |= dx | dy;
+ origin_ = p;
+ d3_eventCancel();
+ event_({
+ type: "drag",
+ x: p[0] + offset[0],
+ y: p[1] + offset[1],
+ dx: dx,
+ dy: dy
+ });
+ }
+ function dragend() {
+ event_({
+ type: "dragend"
+ });
+ if (moved) {
+ d3_eventCancel();
+ if (d3.event.target === eventTarget) w.on("click.drag", click, true);
+ }
+ w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null);
+ }
+ function click() {
+ d3_eventCancel();
+ w.on("click.drag", null);
+ }
+ }
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
+ };
+ return d3.rebind(drag, event, "on");
+ };
+ d3.behavior.zoom = function() {
+ var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime;
+ function zoom() {
+ this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart);
+ }
+ zoom.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = x.map(Number);
+ rescale();
+ return zoom;
+ };
+ zoom.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ rescale();
+ return zoom;
+ };
+ zoom.scaleExtent = function(x) {
+ if (!arguments.length) return scaleExtent;
+ scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);
+ return zoom;
+ };
+ zoom.x = function(z) {
+ if (!arguments.length) return x1;
+ x1 = z;
+ x0 = z.copy();
+ translate = [ 0, 0 ];
+ scale = 1;
+ return zoom;
+ };
+ zoom.y = function(z) {
+ if (!arguments.length) return y1;
+ y1 = z;
+ y0 = z.copy();
+ translate = [ 0, 0 ];
+ scale = 1;
+ return zoom;
+ };
+ function location(p) {
+ return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];
+ }
+ function point(l) {
+ return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];
+ }
+ function scaleTo(s) {
+ scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+ }
+ function translateTo(p, l) {
+ l = point(l);
+ translate[0] += p[0] - l[0];
+ translate[1] += p[1] - l[1];
+ }
+ function rescale() {
+ if (x1) x1.domain(x0.range().map(function(x) {
+ return (x - translate[0]) / scale;
+ }).map(x0.invert));
+ if (y1) y1.domain(y0.range().map(function(y) {
+ return (y - translate[1]) / scale;
+ }).map(y0.invert));
+ }
+ function dispatch(event) {
+ rescale();
+ d3.event.preventDefault();
+ event({
+ type: "zoom",
+ scale: scale,
+ translate: translate
+ });
+ }
+ function mousedown() {
+ var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target));
+ window.focus();
+ d3_eventCancel();
+ function mousemove() {
+ moved = 1;
+ translateTo(d3.mouse(target), l);
+ dispatch(event_);
+ }
+ function mouseup() {
+ if (moved) d3_eventCancel();
+ w.on("mousemove.zoom", null).on("mouseup.zoom", null);
+ if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true);
+ }
+ function click() {
+ d3_eventCancel();
+ w.on("click.zoom", null);
+ }
+ }
+ function mousewheel() {
+ if (!translate0) translate0 = location(d3.mouse(this));
+ scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);
+ translateTo(d3.mouse(this), translate0);
+ dispatch(event.of(this, arguments));
+ }
+ function mousemove() {
+ translate0 = null;
+ }
+ function dblclick() {
+ var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2;
+ scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+ translateTo(p, l);
+ dispatch(event.of(this, arguments));
+ }
+ function touchstart() {
+ var touches = d3.touches(this), now = Date.now();
+ scale0 = scale;
+ translate0 = {};
+ touches.forEach(function(t) {
+ translate0[t.identifier] = location(t);
+ });
+ d3_eventCancel();
+ if (touches.length === 1) {
+ if (now - touchtime < 500) {
+ var p = touches[0], l = location(touches[0]);
+ scaleTo(scale * 2);
+ translateTo(p, l);
+ dispatch(event.of(this, arguments));
+ }
+ touchtime = now;
+ }
+ }
+ function touchmove() {
+ var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];
+ if (p1 = touches[1]) {
+ var p1, l1 = translate0[p1.identifier];
+ p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+ l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+ scaleTo(d3.event.scale * scale0);
+ }
+ translateTo(p0, l0);
+ touchtime = null;
+ dispatch(event.of(this, arguments));
+ }
+ return d3.rebind(zoom, event, "on");
+ };
+ var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ];
+ function d3_behavior_zoomDelta() {
+ if (!d3_behavior_zoomDiv) {
+ d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode;
+ }
+ var e = d3.event, delta;
+ try {
+ d3_behavior_zoomDiv.scrollTop = 1e3;
+ d3_behavior_zoomDiv.dispatchEvent(e);
+ delta = 1e3 - d3_behavior_zoomDiv.scrollTop;
+ } catch (error) {
+ delta = e.wheelDelta || -e.detail * 5;
+ }
+ return delta;
+ }
+ d3.layout = {};
+ d3.layout.bundle = function() {
+ return function(links) {
+ var paths = [], i = -1, n = links.length;
+ while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
+ return paths;
+ };
+ };
+ function d3_layout_bundlePath(link) {
+ var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
+ while (start !== lca) {
+ start = start.parent;
+ points.push(start);
+ }
+ var k = points.length;
+ while (end !== lca) {
+ points.splice(k, 0, end);
+ end = end.parent;
+ }
+ return points;
+ }
+ function d3_layout_bundleAncestors(node) {
+ var ancestors = [], parent = node.parent;
+ while (parent != null) {
+ ancestors.push(node);
+ node = parent;
+ parent = parent.parent;
+ }
+ ancestors.push(node);
+ return ancestors;
+ }
+ function d3_layout_bundleLeastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
+ while (aNode === bNode) {
+ sharedNode = aNode;
+ aNode = aNodes.pop();
+ bNode = bNodes.pop();
+ }
+ return sharedNode;
+ }
+ d3.layout.chord = function() {
+ var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
+ function relayout() {
+ var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
+ chords = [];
+ groups = [];
+ k = 0, i = -1;
+ while (++i < n) {
+ x = 0, j = -1;
+ while (++j < n) {
+ x += matrix[i][j];
+ }
+ groupSums.push(x);
+ subgroupIndex.push(d3.range(n));
+ k += x;
+ }
+ if (sortGroups) {
+ groupIndex.sort(function(a, b) {
+ return sortGroups(groupSums[a], groupSums[b]);
+ });
+ }
+ if (sortSubgroups) {
+ subgroupIndex.forEach(function(d, i) {
+ d.sort(function(a, b) {
+ return sortSubgroups(matrix[i][a], matrix[i][b]);
+ });
+ });
+ }
+ k = (2 * π - padding * n) / k;
+ x = 0, i = -1;
+ while (++i < n) {
+ x0 = x, j = -1;
+ while (++j < n) {
+ var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
+ subgroups[di + "-" + dj] = {
+ index: di,
+ subindex: dj,
+ startAngle: a0,
+ endAngle: a1,
+ value: v
+ };
+ }
+ groups[di] = {
+ index: di,
+ startAngle: x0,
+ endAngle: x,
+ value: (x - x0) / k
+ };
+ x += padding;
+ }
+ i = -1;
+ while (++i < n) {
+ j = i - 1;
+ while (++j < n) {
+ var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
+ if (source.value || target.value) {
+ chords.push(source.value < target.value ? {
+ source: target,
+ target: source
+ } : {
+ source: source,
+ target: target
+ });
+ }
+ }
+ }
+ if (sortChords) resort();
+ }
+ function resort() {
+ chords.sort(function(a, b) {
+ return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
+ });
+ }
+ chord.matrix = function(x) {
+ if (!arguments.length) return matrix;
+ n = (matrix = x) && matrix.length;
+ chords = groups = null;
+ return chord;
+ };
+ chord.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortGroups = function(x) {
+ if (!arguments.length) return sortGroups;
+ sortGroups = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortSubgroups = function(x) {
+ if (!arguments.length) return sortSubgroups;
+ sortSubgroups = x;
+ chords = null;
+ return chord;
+ };
+ chord.sortChords = function(x) {
+ if (!arguments.length) return sortChords;
+ sortChords = x;
+ if (chords) resort();
+ return chord;
+ };
+ chord.chords = function() {
+ if (!chords) relayout();
+ return chords;
+ };
+ chord.groups = function() {
+ if (!groups) relayout();
+ return groups;
+ };
+ return chord;
+ };
+ d3.layout.force = function() {
+ var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges;
+ function repulse(node) {
+ return function(quad, x1, _, x2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy);
+ if ((x2 - x1) * dn < theta) {
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ return true;
+ }
+ if (quad.point && isFinite(dn)) {
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ force.tick = function() {
+ if ((alpha *= .99) < .005) {
+ event.end({
+ type: "end",
+ alpha: alpha = 0
+ });
+ return true;
+ }
+ var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ s = o.source;
+ t = o.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if (l = x * x + y * y) {
+ l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ }
+ if (k = alpha * gravity) {
+ x = size[0] / 2;
+ y = size[1] / 2;
+ i = -1;
+ if (k) while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ if (charge) {
+ d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+ i = -1;
+ while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = nodes[i];
+ if (o.fixed) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * friction;
+ o.y -= (o.py - (o.py = o.y)) * friction;
+ }
+ }
+ event.tick({
+ type: "tick",
+ alpha: alpha
+ });
+ };
+ force.nodes = function(x) {
+ if (!arguments.length) return nodes;
+ nodes = x;
+ return force;
+ };
+ force.links = function(x) {
+ if (!arguments.length) return links;
+ links = x;
+ return force;
+ };
+ force.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return force;
+ };
+ force.linkDistance = function(x) {
+ if (!arguments.length) return linkDistance;
+ linkDistance = d3_functor(x);
+ return force;
+ };
+ force.distance = force.linkDistance;
+ force.linkStrength = function(x) {
+ if (!arguments.length) return linkStrength;
+ linkStrength = d3_functor(x);
+ return force;
+ };
+ force.friction = function(x) {
+ if (!arguments.length) return friction;
+ friction = x;
+ return force;
+ };
+ force.charge = function(x) {
+ if (!arguments.length) return charge;
+ charge = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.gravity = function(x) {
+ if (!arguments.length) return gravity;
+ gravity = x;
+ return force;
+ };
+ force.theta = function(x) {
+ if (!arguments.length) return theta;
+ theta = x;
+ return force;
+ };
+ force.alpha = function(x) {
+ if (!arguments.length) return alpha;
+ if (alpha) {
+ if (x > 0) alpha = x; else alpha = 0;
+ } else if (x > 0) {
+ event.start({
+ type: "start",
+ alpha: alpha = x
+ });
+ d3.timer(force.tick);
+ }
+ return force;
+ };
+ force.start = function() {
+ var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
+ for (i = 0; i < n; ++i) {
+ (o = nodes[i]).index = i;
+ o.weight = 0;
+ }
+ distances = [];
+ strengths = [];
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ if (typeof o.source == "number") o.source = nodes[o.source];
+ if (typeof o.target == "number") o.target = nodes[o.target];
+ distances[i] = linkDistance.call(this, o, i);
+ strengths[i] = linkStrength.call(this, o, i);
+ ++o.source.weight;
+ ++o.target.weight;
+ }
+ for (i = 0; i < n; ++i) {
+ o = nodes[i];
+ if (isNaN(o.x)) o.x = position("x", w);
+ if (isNaN(o.y)) o.y = position("y", h);
+ if (isNaN(o.px)) o.px = o.x;
+ if (isNaN(o.py)) o.py = o.y;
+ }
+ charges = [];
+ if (typeof charge === "function") {
+ for (i = 0; i < n; ++i) {
+ charges[i] = +charge.call(this, nodes[i], i);
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ charges[i] = charge;
+ }
+ }
+ function position(dimension, size) {
+ var neighbors = neighbor(i), j = -1, m = neighbors.length, x;
+ while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
+ return Math.random() * size;
+ }
+ function neighbor() {
+ if (!neighbors) {
+ neighbors = [];
+ for (j = 0; j < n; ++j) {
+ neighbors[j] = [];
+ }
+ for (j = 0; j < m; ++j) {
+ var o = links[j];
+ neighbors[o.source.index].push(o.target);
+ neighbors[o.target.index].push(o.source);
+ }
+ }
+ return neighbors[i];
+ }
+ return force.resume();
+ };
+ force.resume = function() {
+ return force.alpha(.1);
+ };
+ force.stop = function() {
+ return force.alpha(0);
+ };
+ force.drag = function() {
+ if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend);
+ this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
+ };
+ function dragmove(d) {
+ d.px = d3.event.x, d.py = d3.event.y;
+ force.resume();
+ }
+ return d3.rebind(force, event, "on");
+ };
+ function d3_layout_forceDragstart(d) {
+ d.fixed |= 2;
+ }
+ function d3_layout_forceDragend(d) {
+ d.fixed &= 1;
+ }
+ function d3_layout_forceMouseover(d) {
+ d.fixed |= 4;
+ d.px = d.x, d.py = d.y;
+ }
+ function d3_layout_forceMouseout(d) {
+ d.fixed &= 3;
+ }
+ function d3_layout_forceAccumulate(quad, alpha, charges) {
+ var cx = 0, cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes, n = nodes.length, i = -1, c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) continue;
+ d3_layout_forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - .5;
+ quad.point.y += Math.random() - .5;
+ }
+ var k = alpha * charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ }
+ function d3_layout_forceLinkDistance() {
+ return 20;
+ }
+ function d3_layout_forceLinkStrength() {
+ return 1;
+ }
+ d3.layout.partition = function() {
+ var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
+ function position(node, x, dx, dy) {
+ var children = node.children;
+ node.x = x;
+ node.y = node.depth * dy;
+ node.dx = dx;
+ node.dy = dy;
+ if (children && (n = children.length)) {
+ var i = -1, n, c, d;
+ dx = node.value ? dx / node.value : 0;
+ while (++i < n) {
+ position(c = children[i], x, d = c.value * dx, dy);
+ x += d;
+ }
+ }
+ }
+ function depth(node) {
+ var children = node.children, d = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ while (++i < n) d = Math.max(d, depth(children[i]));
+ }
+ return 1 + d;
+ }
+ function partition(d, i) {
+ var nodes = hierarchy.call(this, d, i);
+ position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
+ return nodes;
+ }
+ partition.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return partition;
+ };
+ return d3_layout_hierarchyRebind(partition, hierarchy);
+ };
+ d3.layout.pie = function() {
+ var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π;
+ function pie(data) {
+ var values = data.map(function(d, i) {
+ return +value.call(pie, d, i);
+ });
+ var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
+ var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values);
+ var index = d3.range(data.length);
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
+ return values[j] - values[i];
+ } : function(i, j) {
+ return sort(data[i], data[j]);
+ });
+ var arcs = [];
+ index.forEach(function(i) {
+ var d;
+ arcs[i] = {
+ data: data[i],
+ value: d = values[i],
+ startAngle: a,
+ endAngle: a += d * k
+ };
+ });
+ return arcs;
+ }
+ pie.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return pie;
+ };
+ pie.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return pie;
+ };
+ pie.startAngle = function(x) {
+ if (!arguments.length) return startAngle;
+ startAngle = x;
+ return pie;
+ };
+ pie.endAngle = function(x) {
+ if (!arguments.length) return endAngle;
+ endAngle = x;
+ return pie;
+ };
+ return pie;
+ };
+ var d3_layout_pieSortByValue = {};
+ d3.layout.stack = function() {
+ var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
+ function stack(data, index) {
+ var series = data.map(function(d, i) {
+ return values.call(stack, d, i);
+ });
+ var points = series.map(function(d) {
+ return d.map(function(v, i) {
+ return [ x.call(stack, v, i), y.call(stack, v, i) ];
+ });
+ });
+ var orders = order.call(stack, points, index);
+ series = d3.permute(series, orders);
+ points = d3.permute(points, orders);
+ var offsets = offset.call(stack, points, index);
+ var n = series.length, m = series[0].length, i, j, o;
+ for (j = 0; j < m; ++j) {
+ out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
+ for (i = 1; i < n; ++i) {
+ out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
+ }
+ }
+ return data;
+ }
+ stack.values = function(x) {
+ if (!arguments.length) return values;
+ values = x;
+ return stack;
+ };
+ stack.order = function(x) {
+ if (!arguments.length) return order;
+ order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
+ return stack;
+ };
+ stack.offset = function(x) {
+ if (!arguments.length) return offset;
+ offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
+ return stack;
+ };
+ stack.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ return stack;
+ };
+ stack.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ return stack;
+ };
+ stack.out = function(z) {
+ if (!arguments.length) return out;
+ out = z;
+ return stack;
+ };
+ return stack;
+ };
+ function d3_layout_stackX(d) {
+ return d.x;
+ }
+ function d3_layout_stackY(d) {
+ return d.y;
+ }
+ function d3_layout_stackOut(d, y0, y) {
+ d.y0 = y0;
+ d.y = y;
+ }
+ var d3_layout_stackOrders = d3.map({
+ "inside-out": function(data) {
+ var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
+ return max[a] - max[b];
+ }), top = 0, bottom = 0, tops = [], bottoms = [];
+ for (i = 0; i < n; ++i) {
+ j = index[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+ return bottoms.reverse().concat(tops);
+ },
+ reverse: function(data) {
+ return d3.range(data.length).reverse();
+ },
+ "default": d3_layout_stackOrderDefault
+ });
+ var d3_layout_stackOffsets = d3.map({
+ silhouette: function(data) {
+ var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o > max) max = o;
+ sums.push(o);
+ }
+ for (j = 0; j < m; ++j) {
+ y0[j] = (max - sums[j]) / 2;
+ }
+ return y0;
+ },
+ wiggle: function(data) {
+ var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
+ y0[0] = o = o0 = 0;
+ for (j = 1; j < m; ++j) {
+ for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
+ for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
+ for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
+ s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
+ }
+ s2 += s3 * data[i][j][1];
+ }
+ y0[j] = o -= s1 ? s2 / s1 * dx : 0;
+ if (o < o0) o0 = o;
+ }
+ for (j = 0; j < m; ++j) y0[j] -= o0;
+ return y0;
+ },
+ expand: function(data) {
+ var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
+ }
+ for (j = 0; j < m; ++j) y0[j] = 0;
+ return y0;
+ },
+ zero: d3_layout_stackOffsetZero
+ });
+ function d3_layout_stackOrderDefault(data) {
+ return d3.range(data.length);
+ }
+ function d3_layout_stackOffsetZero(data) {
+ var j = -1, m = data[0].length, y0 = [];
+ while (++j < m) y0[j] = 0;
+ return y0;
+ }
+ function d3_layout_stackMaxIndex(array) {
+ var i = 1, j = 0, v = array[0][1], k, n = array.length;
+ for (;i < n; ++i) {
+ if ((k = array[i][1]) > v) {
+ j = i;
+ v = k;
+ }
+ }
+ return j;
+ }
+ function d3_layout_stackReduceSum(d) {
+ return d.reduce(d3_layout_stackSum, 0);
+ }
+ function d3_layout_stackSum(p, d) {
+ return p + d[1];
+ }
+ d3.layout.histogram = function() {
+ var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
+ function histogram(data, i) {
+ var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
+ while (++i < m) {
+ bin = bins[i] = [];
+ bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
+ bin.y = 0;
+ }
+ if (m > 0) {
+ i = -1;
+ while (++i < n) {
+ x = values[i];
+ if (x >= range[0] && x <= range[1]) {
+ bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
+ bin.y += k;
+ bin.push(data[i]);
+ }
+ }
+ }
+ return bins;
+ }
+ histogram.value = function(x) {
+ if (!arguments.length) return valuer;
+ valuer = x;
+ return histogram;
+ };
+ histogram.range = function(x) {
+ if (!arguments.length) return ranger;
+ ranger = d3_functor(x);
+ return histogram;
+ };
+ histogram.bins = function(x) {
+ if (!arguments.length) return binner;
+ binner = typeof x === "number" ? function(range) {
+ return d3_layout_histogramBinFixed(range, x);
+ } : d3_functor(x);
+ return histogram;
+ };
+ histogram.frequency = function(x) {
+ if (!arguments.length) return frequency;
+ frequency = !!x;
+ return histogram;
+ };
+ return histogram;
+ };
+ function d3_layout_histogramBinSturges(range, values) {
+ return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
+ }
+ function d3_layout_histogramBinFixed(range, n) {
+ var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
+ while (++x <= n) f[x] = m * x + b;
+ return f;
+ }
+ function d3_layout_histogramRange(values) {
+ return [ d3.min(values), d3.max(values) ];
+ }
+ d3.layout.hierarchy = function() {
+ var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
+ function recurse(node, depth, nodes) {
+ var childs = children.call(hierarchy, node, depth);
+ node.depth = depth;
+ nodes.push(node);
+ if (childs && (n = childs.length)) {
+ var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;
+ while (++i < n) {
+ d = recurse(childs[i], j, nodes);
+ d.parent = node;
+ c.push(d);
+ v += d.value;
+ }
+ if (sort) c.sort(sort);
+ if (value) node.value = v;
+ } else if (value) {
+ node.value = +value.call(hierarchy, node, depth) || 0;
+ }
+ return node;
+ }
+ function revalue(node, depth) {
+ var children = node.children, v = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n, j = depth + 1;
+ while (++i < n) v += revalue(children[i], j);
+ } else if (value) {
+ v = +value.call(hierarchy, node, depth) || 0;
+ }
+ if (value) node.value = v;
+ return v;
+ }
+ function hierarchy(d) {
+ var nodes = [];
+ recurse(d, 0, nodes);
+ return nodes;
+ }
+ hierarchy.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return hierarchy;
+ };
+ hierarchy.children = function(x) {
+ if (!arguments.length) return children;
+ children = x;
+ return hierarchy;
+ };
+ hierarchy.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return hierarchy;
+ };
+ hierarchy.revalue = function(root) {
+ revalue(root, 0);
+ return root;
+ };
+ return hierarchy;
+ };
+ function d3_layout_hierarchyRebind(object, hierarchy) {
+ d3.rebind(object, hierarchy, "sort", "children", "value");
+ object.nodes = object;
+ object.links = d3_layout_hierarchyLinks;
+ return object;
+ }
+ function d3_layout_hierarchyChildren(d) {
+ return d.children;
+ }
+ function d3_layout_hierarchyValue(d) {
+ return d.value;
+ }
+ function d3_layout_hierarchySort(a, b) {
+ return b.value - a.value;
+ }
+ function d3_layout_hierarchyLinks(nodes) {
+ return d3.merge(nodes.map(function(parent) {
+ return (parent.children || []).map(function(child) {
+ return {
+ source: parent,
+ target: child
+ };
+ });
+ }));
+ }
+ d3.layout.pack = function() {
+ var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ];
+ function pack(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r = Math.sqrt(d.value);
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h);
+ if (padding > 0) {
+ var dr = padding * k / 2;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r += dr;
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r -= dr;
+ });
+ k = Math.max(2 * root.r / w, 2 * root.r / h);
+ }
+ d3_layout_packTransform(root, w / 2, h / 2, 1 / k);
+ return nodes;
+ }
+ pack.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return pack;
+ };
+ pack.padding = function(_) {
+ if (!arguments.length) return padding;
+ padding = +_;
+ return pack;
+ };
+ return d3_layout_hierarchyRebind(pack, hierarchy);
+ };
+ function d3_layout_packSort(a, b) {
+ return a.value - b.value;
+ }
+ function d3_layout_packInsert(a, b) {
+ var c = a._pack_next;
+ a._pack_next = b;
+ b._pack_prev = a;
+ b._pack_next = c;
+ c._pack_prev = b;
+ }
+ function d3_layout_packSplice(a, b) {
+ a._pack_next = b;
+ b._pack_prev = a;
+ }
+ function d3_layout_packIntersects(a, b) {
+ var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
+ return dr * dr - dx * dx - dy * dy > .001;
+ }
+ function d3_layout_packSiblings(node) {
+ if (!(nodes = node.children) || !(n = nodes.length)) return;
+ var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
+ function bound(node) {
+ xMin = Math.min(node.x - node.r, xMin);
+ xMax = Math.max(node.x + node.r, xMax);
+ yMin = Math.min(node.y - node.r, yMin);
+ yMax = Math.max(node.y + node.r, yMax);
+ }
+ nodes.forEach(d3_layout_packLink);
+ a = nodes[0];
+ a.x = -a.r;
+ a.y = 0;
+ bound(a);
+ if (n > 1) {
+ b = nodes[1];
+ b.x = b.r;
+ b.y = 0;
+ bound(b);
+ if (n > 2) {
+ c = nodes[2];
+ d3_layout_packPlace(a, b, c);
+ bound(c);
+ d3_layout_packInsert(a, c);
+ a._pack_prev = c;
+ d3_layout_packInsert(c, b);
+ b = a._pack_next;
+ for (i = 3; i < n; i++) {
+ d3_layout_packPlace(a, b, c = nodes[i]);
+ var isect = 0, s1 = 1, s2 = 1;
+ for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
+ if (d3_layout_packIntersects(j, c)) {
+ isect = 1;
+ break;
+ }
+ }
+ if (isect == 1) {
+ for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
+ if (d3_layout_packIntersects(k, c)) {
+ break;
+ }
+ }
+ }
+ if (isect) {
+ if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
+ i--;
+ } else {
+ d3_layout_packInsert(a, c);
+ b = c;
+ bound(c);
+ }
+ }
+ }
+ }
+ var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
+ for (i = 0; i < n; i++) {
+ c = nodes[i];
+ c.x -= cx;
+ c.y -= cy;
+ cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
+ }
+ node.r = cr;
+ nodes.forEach(d3_layout_packUnlink);
+ }
+ function d3_layout_packLink(node) {
+ node._pack_next = node._pack_prev = node;
+ }
+ function d3_layout_packUnlink(node) {
+ delete node._pack_next;
+ delete node._pack_prev;
+ }
+ function d3_layout_packTransform(node, x, y, k) {
+ var children = node.children;
+ node.x = x += k * node.x;
+ node.y = y += k * node.y;
+ node.r *= k;
+ if (children) {
+ var i = -1, n = children.length;
+ while (++i < n) d3_layout_packTransform(children[i], x, y, k);
+ }
+ }
+ function d3_layout_packPlace(a, b, c) {
+ var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
+ if (db && (dx || dy)) {
+ var da = b.r + c.r, dc = dx * dx + dy * dy;
+ da *= da;
+ db *= db;
+ var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
+ c.x = a.x + x * dx + y * dy;
+ c.y = a.y + x * dy - y * dx;
+ } else {
+ c.x = a.x + db;
+ c.y = a.y;
+ }
+ }
+ d3.layout.cluster = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
+ function cluster(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
+ d3_layout_treeVisitAfter(root, function(node) {
+ var children = node.children;
+ if (children && children.length) {
+ node.x = d3_layout_clusterX(children);
+ node.y = d3_layout_clusterY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+ var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
+ d3_layout_treeVisitAfter(root, function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
+ });
+ return nodes;
+ }
+ cluster.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return cluster;
+ };
+ cluster.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return cluster;
+ };
+ return d3_layout_hierarchyRebind(cluster, hierarchy);
+ };
+ function d3_layout_clusterY(children) {
+ return 1 + d3.max(children, function(child) {
+ return child.y;
+ });
+ }
+ function d3_layout_clusterX(children) {
+ return children.reduce(function(x, child) {
+ return x + child.x;
+ }, 0) / children.length;
+ }
+ function d3_layout_clusterLeft(node) {
+ var children = node.children;
+ return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
+ }
+ function d3_layout_clusterRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
+ }
+ d3.layout.tree = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
+ function tree(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ function firstWalk(node, previousSibling) {
+ var children = node.children, layout = node._tree;
+ if (children && (n = children.length)) {
+ var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
+ while (++i < n) {
+ child = children[i];
+ firstWalk(child, previousChild);
+ ancestor = apportion(child, previousChild, ancestor);
+ previousChild = child;
+ }
+ d3_layout_treeShift(node);
+ var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ layout.mod = layout.prelim - midpoint;
+ } else {
+ layout.prelim = midpoint;
+ }
+ } else {
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ }
+ }
+ }
+ function secondWalk(node, x) {
+ node.x = node._tree.prelim + x;
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ x += node._tree.mod;
+ while (++i < n) {
+ secondWalk(children[i], x);
+ }
+ }
+ }
+ function apportion(node, previousSibling, ancestor) {
+ if (previousSibling) {
+ var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;
+ while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
+ vom = d3_layout_treeLeft(vom);
+ vop = d3_layout_treeRight(vop);
+ vop._tree.ancestor = node;
+ shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
+ if (shift > 0) {
+ d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim._tree.mod;
+ sip += vip._tree.mod;
+ som += vom._tree.mod;
+ sop += vop._tree.mod;
+ }
+ if (vim && !d3_layout_treeRight(vop)) {
+ vop._tree.thread = vim;
+ vop._tree.mod += sim - sop;
+ }
+ if (vip && !d3_layout_treeLeft(vom)) {
+ vom._tree.thread = vip;
+ vom._tree.mod += sip - som;
+ ancestor = node;
+ }
+ }
+ return ancestor;
+ }
+ d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+ node._tree = {
+ ancestor: node,
+ prelim: 0,
+ mod: 0,
+ change: 0,
+ shift: 0,
+ number: previousSibling ? previousSibling._tree.number + 1 : 0
+ };
+ });
+ firstWalk(root);
+ secondWalk(root, -root._tree.prelim);
+ var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
+ d3_layout_treeVisitAfter(root, function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = node.depth / y1 * size[1];
+ delete node._tree;
+ });
+ return nodes;
+ }
+ tree.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return tree;
+ };
+ tree.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return tree;
+ };
+ return d3_layout_hierarchyRebind(tree, hierarchy);
+ };
+ function d3_layout_treeSeparation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+ }
+ function d3_layout_treeLeft(node) {
+ var children = node.children;
+ return children && children.length ? children[0] : node._tree.thread;
+ }
+ function d3_layout_treeRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? children[n - 1] : node._tree.thread;
+ }
+ function d3_layout_treeSearch(node, compare) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, n, i = -1;
+ while (++i < n) {
+ if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+ node = child;
+ }
+ }
+ }
+ return node;
+ }
+ function d3_layout_treeRightmost(a, b) {
+ return a.x - b.x;
+ }
+ function d3_layout_treeLeftmost(a, b) {
+ return b.x - a.x;
+ }
+ function d3_layout_treeDeepest(a, b) {
+ return a.depth - b.depth;
+ }
+ function d3_layout_treeVisitAfter(node, callback) {
+ function visit(node, previousSibling) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, previousChild = null, i = -1, n;
+ while (++i < n) {
+ child = children[i];
+ visit(child, previousChild);
+ previousChild = child;
+ }
+ }
+ callback(node, previousSibling);
+ }
+ visit(node, null);
+ }
+ function d3_layout_treeShift(node) {
+ var shift = 0, change = 0, children = node.children, i = children.length, child;
+ while (--i >= 0) {
+ child = children[i]._tree;
+ child.prelim += shift;
+ child.mod += shift;
+ shift += child.shift + (change += child.change);
+ }
+ }
+ function d3_layout_treeMove(ancestor, node, shift) {
+ ancestor = ancestor._tree;
+ node = node._tree;
+ var change = shift / (node.number - ancestor.number);
+ ancestor.change += change;
+ node.change -= change;
+ node.shift += shift;
+ node.prelim += shift;
+ node.mod += shift;
+ }
+ function d3_layout_treeAncestor(vim, node, ancestor) {
+ return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
+ }
+ d3.layout.treemap = function() {
+ var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
+ function scale(children, k) {
+ var i = -1, n = children.length, child, area;
+ while (++i < n) {
+ area = (child = children[i]).value * (k < 0 ? 0 : k);
+ child.area = isNaN(area) || area <= 0 ? 0 : area;
+ }
+ }
+ function squarify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while ((n = remaining.length) > 0) {
+ row.push(child = remaining[n - 1]);
+ row.area += child.area;
+ if (mode !== "squarify" || (score = worst(row, u)) <= best) {
+ remaining.pop();
+ best = score;
+ } else {
+ row.area -= row.pop().area;
+ position(row, u, rect, false);
+ u = Math.min(rect.dx, rect.dy);
+ row.length = row.area = 0;
+ best = Infinity;
+ }
+ }
+ if (row.length) {
+ position(row, u, rect, true);
+ row.length = row.area = 0;
+ }
+ children.forEach(squarify);
+ }
+ }
+ function stickify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), remaining = children.slice(), child, row = [];
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while (child = remaining.pop()) {
+ row.push(child);
+ row.area += child.area;
+ if (child.z != null) {
+ position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+ row.length = row.area = 0;
+ }
+ }
+ children.forEach(stickify);
+ }
+ }
+ function worst(row, u) {
+ var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
+ while (++i < n) {
+ if (!(r = row[i].area)) continue;
+ if (r < rmin) rmin = r;
+ if (r > rmax) rmax = r;
+ }
+ s *= s;
+ u *= u;
+ return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
+ }
+ function position(row, u, rect, flush) {
+ var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
+ if (u == rect.dx) {
+ if (flush || v > rect.dy) v = rect.dy;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dy = v;
+ x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
+ }
+ o.z = true;
+ o.dx += rect.x + rect.dx - x;
+ rect.y += v;
+ rect.dy -= v;
+ } else {
+ if (flush || v > rect.dx) v = rect.dx;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dx = v;
+ y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
+ }
+ o.z = false;
+ o.dy += rect.y + rect.dy - y;
+ rect.x += v;
+ rect.dx -= v;
+ }
+ }
+ function treemap(d) {
+ var nodes = stickies || hierarchy(d), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ root.dx = size[0];
+ root.dy = size[1];
+ if (stickies) hierarchy.revalue(root);
+ scale([ root ], root.dx * root.dy / root.value);
+ (stickies ? stickify : squarify)(root);
+ if (sticky) stickies = nodes;
+ return nodes;
+ }
+ treemap.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return treemap;
+ };
+ treemap.padding = function(x) {
+ if (!arguments.length) return padding;
+ function padFunction(node) {
+ var p = x.call(treemap, node, node.depth);
+ return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
+ }
+ function padConstant(node) {
+ return d3_layout_treemapPad(node, x);
+ }
+ var type;
+ pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
+ padConstant) : padConstant;
+ return treemap;
+ };
+ treemap.round = function(x) {
+ if (!arguments.length) return round != Number;
+ round = x ? Math.round : Number;
+ return treemap;
+ };
+ treemap.sticky = function(x) {
+ if (!arguments.length) return sticky;
+ sticky = x;
+ stickies = null;
+ return treemap;
+ };
+ treemap.ratio = function(x) {
+ if (!arguments.length) return ratio;
+ ratio = x;
+ return treemap;
+ };
+ treemap.mode = function(x) {
+ if (!arguments.length) return mode;
+ mode = x + "";
+ return treemap;
+ };
+ return d3_layout_hierarchyRebind(treemap, hierarchy);
+ };
+ function d3_layout_treemapPadNull(node) {
+ return {
+ x: node.x,
+ y: node.y,
+ dx: node.dx,
+ dy: node.dy
+ };
+ }
+ function d3_layout_treemapPad(node, padding) {
+ var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
+ if (dx < 0) {
+ x += dx / 2;
+ dx = 0;
+ }
+ if (dy < 0) {
+ y += dy / 2;
+ dy = 0;
+ }
+ return {
+ x: x,
+ y: y,
+ dx: dx,
+ dy: dy
+ };
+ }
+ function d3_dsv(delimiter, mimeType) {
+ var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
+ function dsv(url, callback) {
+ return d3.xhr(url, mimeType, callback).response(response);
+ }
+ function response(request) {
+ return dsv.parse(request.responseText);
+ }
+ dsv.parse = function(text) {
+ var o;
+ return dsv.parseRows(text, function(row) {
+ if (o) return o(row);
+ o = new Function("d", "return {" + row.map(function(name, i) {
+ return JSON.stringify(name) + ": d[" + i + "]";
+ }).join(",") + "}");
+ });
+ };
+ dsv.parseRows = function(text, f) {
+ var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
+ function token() {
+ if (I >= N) return EOF;
+ if (eol) return eol = false, EOL;
+ var j = I;
+ if (text.charCodeAt(j) === 34) {
+ var i = j;
+ while (i++ < N) {
+ if (text.charCodeAt(i) === 34) {
+ if (text.charCodeAt(i + 1) !== 34) break;
+ ++i;
+ }
+ }
+ I = i + 2;
+ var c = text.charCodeAt(i + 1);
+ if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(i + 2) === 10) ++I;
+ } else if (c === 10) {
+ eol = true;
+ }
+ return text.substring(j + 1, i).replace(/""/g, '"');
+ }
+ while (I < N) {
+ var c = text.charCodeAt(I++), k = 1;
+ if (c === 10) eol = true; else if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(I) === 10) ++I, ++k;
+ } else if (c !== delimiterCode) continue;
+ return text.substring(j, I - k);
+ }
+ return text.substring(j);
+ }
+ while ((t = token()) !== EOF) {
+ var a = [];
+ while (t !== EOL && t !== EOF) {
+ a.push(t);
+ t = token();
+ }
+ if (f && !(a = f(a, n++))) continue;
+ rows.push(a);
+ }
+ return rows;
+ };
+ dsv.format = function(rows) {
+ return rows.map(formatRow).join("\n");
+ };
+ function formatRow(row) {
+ return row.map(formatValue).join(delimiter);
+ }
+ function formatValue(text) {
+ return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
+ }
+ return dsv;
+ }
+ d3.csv = d3_dsv(",", "text/csv");
+ d3.tsv = d3_dsv(" ", "text/tab-separated-values");
+ d3.geo = {};
+ d3.geo.stream = function(object, listener) {
+ if (d3_geo_streamObjectType.hasOwnProperty(object.type)) {
+ d3_geo_streamObjectType[object.type](object, listener);
+ } else {
+ d3_geo_streamGeometry(object, listener);
+ }
+ };
+ function d3_geo_streamGeometry(geometry, listener) {
+ if (d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
+ d3_geo_streamGeometryType[geometry.type](geometry, listener);
+ }
+ }
+ var d3_geo_streamObjectType = {
+ Feature: function(feature, listener) {
+ d3_geo_streamGeometry(feature.geometry, listener);
+ },
+ FeatureCollection: function(object, listener) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
+ }
+ };
+ var d3_geo_streamGeometryType = {
+ Sphere: function(object, listener) {
+ listener.sphere();
+ },
+ Point: function(object, listener) {
+ var coordinate = object.coordinates;
+ listener.point(coordinate[0], coordinate[1]);
+ },
+ MultiPoint: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate;
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);
+ },
+ LineString: function(object, listener) {
+ d3_geo_streamLine(object.coordinates, listener, 0);
+ },
+ MultiLineString: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
+ },
+ Polygon: function(object, listener) {
+ d3_geo_streamPolygon(object.coordinates, listener);
+ },
+ MultiPolygon: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
+ },
+ GeometryCollection: function(object, listener) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
+ }
+ };
+ function d3_geo_streamLine(coordinates, listener, closed) {
+ var i = -1, n = coordinates.length - closed, coordinate;
+ listener.lineStart();
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);
+ listener.lineEnd();
+ }
+ function d3_geo_streamPolygon(coordinates, listener) {
+ var i = -1, n = coordinates.length;
+ listener.polygonStart();
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
+ listener.polygonEnd();
+ }
+ function d3_geo_spherical(cartesian) {
+ return [ Math.atan2(cartesian[1], cartesian[0]), Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) ];
+ }
+ function d3_geo_sphericalEqual(a, b) {
+ return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε;
+ }
+ function d3_geo_cartesian(spherical) {
+ var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
+ return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
+ }
+ function d3_geo_cartesianDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ }
+ function d3_geo_cartesianCross(a, b) {
+ return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
+ }
+ function d3_geo_cartesianAdd(a, b) {
+ a[0] += b[0];
+ a[1] += b[1];
+ a[2] += b[2];
+ }
+ function d3_geo_cartesianScale(vector, k) {
+ return [ vector[0] * k, vector[1] * k, vector[2] * k ];
+ }
+ function d3_geo_cartesianNormalize(d) {
+ var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ d[0] /= l;
+ d[1] /= l;
+ d[2] /= l;
+ }
+ function d3_geo_resample(project) {
+ var δ2 = .5, maxDepth = 16;
+ function resample(stream) {
+ var λ0, x0, y0, a0, b0, c0;
+ var resample = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.polygonStart();
+ resample.lineStart = polygonLineStart;
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ resample.lineStart = lineStart;
+ }
+ };
+ function point(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ }
+ function lineStart() {
+ x0 = NaN;
+ resample.point = linePoint;
+ stream.lineStart();
+ }
+ function linePoint(λ, φ) {
+ var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+ stream.point(x0, y0);
+ }
+ function lineEnd() {
+ resample.point = point;
+ stream.lineEnd();
+ }
+ function polygonLineStart() {
+ var λ00, φ00, x00, y00, a00, b00, c00;
+ lineStart();
+ resample.point = function(λ, φ) {
+ linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
+ resample.point = linePoint;
+ };
+ resample.lineEnd = function() {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
+ resample.lineEnd = lineEnd;
+ lineEnd();
+ };
+ }
+ return resample;
+ }
+ function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
+ var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
+ if (d2 > 4 * δ2 && depth--) {
+ var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
+ if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
+ stream.point(x2, y2);
+ resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
+ }
+ }
+ }
+ resample.precision = function(_) {
+ if (!arguments.length) return Math.sqrt(δ2);
+ maxDepth = (δ2 = _ * _) > 0 && 16;
+ return resample;
+ };
+ return resample;
+ }
+ d3.geo.albersUsa = function() {
+ var lower48 = d3.geo.albers();
+ var alaska = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 60 ]).parallels([ 55, 65 ]);
+ var hawaii = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 20 ]).parallels([ 8, 18 ]);
+ var puertoRico = d3.geo.albers().rotate([ 60, 0 ]).center([ 0, 10 ]).parallels([ 8, 18 ]);
+ function albersUsa(coordinates) {
+ return projection(coordinates)(coordinates);
+ }
+ function projection(point) {
+ var lon = point[0], lat = point[1];
+ return lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48;
+ }
+ albersUsa.scale = function(x) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(x);
+ alaska.scale(x * .6);
+ hawaii.scale(x);
+ puertoRico.scale(x * 1.5);
+ return albersUsa.translate(lower48.translate());
+ };
+ albersUsa.translate = function(x) {
+ if (!arguments.length) return lower48.translate();
+ var dz = lower48.scale(), dx = x[0], dy = x[1];
+ lower48.translate(x);
+ alaska.translate([ dx - .4 * dz, dy + .17 * dz ]);
+ hawaii.translate([ dx - .19 * dz, dy + .2 * dz ]);
+ puertoRico.translate([ dx + .58 * dz, dy + .43 * dz ]);
+ return albersUsa;
+ };
+ return albersUsa.scale(lower48.scale());
+ };
+ function d3_geo_albers(φ0, φ1) {
+ var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), Ï0 = Math.sqrt(C) / n;
+ function albers(λ, φ) {
+ var Ï = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
+ return [ Ï * Math.sin(λ *= n), Ï0 - Ï * Math.cos(λ) ];
+ }
+ albers.invert = function(x, y) {
+ var Ï0_y = Ï0 - y;
+ return [ Math.atan2(x, Ï0_y) / n, Math.asin((C - (x * x + Ï0_y * Ï0_y) * n * n) / (2 * n)) ];
+ };
+ return albers;
+ }
+ (d3.geo.albers = function() {
+ var φ0 = 29.5 * d3_radians, φ1 = 45.5 * d3_radians, m = d3_geo_projectionMutator(d3_geo_albers), p = m(φ0, φ1);
+ p.parallels = function(_) {
+ if (!arguments.length) return [ φ0 * d3_degrees, φ1 * d3_degrees ];
+ return m(φ0 = _[0] * d3_radians, φ1 = _[1] * d3_radians);
+ };
+ return p.rotate([ 98, 0 ]).center([ 0, 38 ]).scale(1e3);
+ }).raw = d3_geo_albers;
+ var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
+ return Math.sqrt(2 / (1 + cosλcosφ));
+ }, function(Ï) {
+ return 2 * Math.asin(Ï / 2);
+ });
+ (d3.geo.azimuthalEqualArea = function() {
+ return d3_geo_projection(d3_geo_azimuthalEqualArea);
+ }).raw = d3_geo_azimuthalEqualArea;
+ var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
+ var c = Math.acos(cosλcosφ);
+ return c && c / Math.sin(c);
+ }, d3_identity);
+ (d3.geo.azimuthalEquidistant = function() {
+ return d3_geo_projection(d3_geo_azimuthalEquidistant);
+ }).raw = d3_geo_azimuthalEquidistant;
+ d3.geo.bounds = d3_geo_bounds(d3_identity);
+ function d3_geo_bounds(projectStream) {
+ var x0, y0, x1, y1;
+ var bound = {
+ point: boundPoint,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ bound.lineEnd = boundPolygonLineEnd;
+ },
+ polygonEnd: function() {
+ bound.point = boundPoint;
+ }
+ };
+ function boundPoint(x, y) {
+ if (x < x0) x0 = x;
+ if (x > x1) x1 = x;
+ if (y < y0) y0 = y;
+ if (y > y1) y1 = y;
+ }
+ function boundPolygonLineEnd() {
+ bound.point = bound.lineEnd = d3_noop;
+ }
+ return function(feature) {
+ y1 = x1 = -(x0 = y0 = Infinity);
+ d3.geo.stream(feature, projectStream(bound));
+ return [ [ x0, y0 ], [ x1, y1 ] ];
+ };
+ }
+ d3.geo.centroid = function(object) {
+ d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ d3.geo.stream(object, d3_geo_centroid);
+ var m;
+ if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {
+ return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ];
+ }
+ };
+ var d3_geo_centroidDimension, d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ;
+ var d3_geo_centroid = {
+ sphere: function() {
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ },
+ point: d3_geo_centroidPoint,
+ lineStart: d3_geo_centroidLineStart,
+ lineEnd: d3_geo_centroidLineEnd,
+ polygonStart: function() {
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
+ }
+ };
+ function d3_geo_centroidPoint(λ, φ) {
+ if (d3_geo_centroidDimension) return;
+ ++d3_geo_centroidW;
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW;
+ d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW;
+ d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW;
+ }
+ function d3_geo_centroidRingStart() {
+ var λ00, φ00;
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidLineStart();
+ d3_geo_centroidDimension = 2;
+ var linePoint = d3_geo_centroid.point;
+ d3_geo_centroid.point = function(λ, φ) {
+ linePoint(λ00 = λ, φ00 = φ);
+ };
+ d3_geo_centroid.lineEnd = function() {
+ d3_geo_centroid.point(λ00, φ00);
+ d3_geo_centroidLineEnd();
+ d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
+ };
+ }
+ function d3_geo_centroidLineStart() {
+ var x0, y0, z0;
+ if (d3_geo_centroidDimension > 1) return;
+ if (d3_geo_centroidDimension < 1) {
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_centroid.point = function(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ x0 = cosφ * Math.cos(λ);
+ y0 = cosφ * Math.sin(λ);
+ z0 = Math.sin(φ);
+ d3_geo_centroid.point = nextPoint;
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+ d3_geo_centroidW += w;
+ d3_geo_centroidX += w * (x0 + (x0 = x));
+ d3_geo_centroidY += w * (y0 + (y0 = y));
+ d3_geo_centroidZ += w * (z0 + (z0 = z));
+ }
+ }
+ function d3_geo_centroidLineEnd() {
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ }
+ d3.geo.circle = function() {
+ var origin = [ 0, 0 ], angle, precision = 6, interpolate;
+ function circle() {
+ var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
+ interpolate(null, null, 1, {
+ point: function(x, y) {
+ ring.push(x = rotate(x, y));
+ x[0] *= d3_degrees, x[1] *= d3_degrees;
+ }
+ });
+ return {
+ type: "Polygon",
+ coordinates: [ ring ]
+ };
+ }
+ circle.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return circle;
+ };
+ circle.angle = function(x) {
+ if (!arguments.length) return angle;
+ interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
+ return circle;
+ };
+ circle.precision = function(_) {
+ if (!arguments.length) return precision;
+ interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
+ return circle;
+ };
+ return circle.angle(90);
+ };
+ function d3_geo_circleInterpolate(radians, precision) {
+ var cr = Math.cos(radians), sr = Math.sin(radians);
+ return function(from, to, direction, listener) {
+ if (from != null) {
+ from = d3_geo_circleAngle(cr, from);
+ to = d3_geo_circleAngle(cr, to);
+ if (direction > 0 ? from < to : from > to) from += direction * 2 * π;
+ } else {
+ from = radians + direction * 2 * π;
+ to = radians;
+ }
+ var point;
+ for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) {
+ listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
+ }
+ };
+ }
+ function d3_geo_circleAngle(cr, point) {
+ var a = d3_geo_cartesian(point);
+ a[0] -= cr;
+ d3_geo_cartesianNormalize(a);
+ var angle = Math.acos(Math.max(-1, Math.min(1, -a[1])));
+ return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
+ }
+ function d3_geo_clip(pointVisible, clipLine, interpolate) {
+ return function(listener) {
+ var line = clipLine(listener);
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ clip.point = pointRing;
+ clip.lineStart = ringStart;
+ clip.lineEnd = ringEnd;
+ invisible = false;
+ invisibleArea = visibleArea = 0;
+ segments = [];
+ listener.polygonStart();
+ },
+ polygonEnd: function() {
+ clip.point = point;
+ clip.lineStart = lineStart;
+ clip.lineEnd = lineEnd;
+ segments = d3.merge(segments);
+ if (segments.length) {
+ d3_geo_clipPolygon(segments, interpolate, listener);
+ } else if (visibleArea < -ε || invisible && invisibleArea < -ε) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ listener.polygonEnd();
+ segments = null;
+ },
+ sphere: function() {
+ listener.polygonStart();
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ listener.polygonEnd();
+ }
+ };
+ function point(λ, φ) {
+ if (pointVisible(λ, φ)) listener.point(λ, φ);
+ }
+ function pointLine(λ, φ) {
+ line.point(λ, φ);
+ }
+ function lineStart() {
+ clip.point = pointLine;
+ line.lineStart();
+ }
+ function lineEnd() {
+ clip.point = point;
+ line.lineEnd();
+ }
+ var segments, visibleArea, invisibleArea, invisible;
+ var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), ring;
+ function pointRing(λ, φ) {
+ ringListener.point(λ, φ);
+ ring.push([ λ, φ ]);
+ }
+ function ringStart() {
+ ringListener.lineStart();
+ ring = [];
+ }
+ function ringEnd() {
+ pointRing(ring[0][0], ring[0][1]);
+ ringListener.lineEnd();
+ var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
+ if (!n) {
+ invisible = true;
+ invisibleArea += d3_geo_clipAreaRing(ring, -1);
+ ring = null;
+ return;
+ }
+ ring = null;
+ if (clean & 1) {
+ segment = ringSegments[0];
+ visibleArea += d3_geo_clipAreaRing(segment, 1);
+ var n = segment.length - 1, i = -1, point;
+ listener.lineStart();
+ while (++i < n) listener.point((point = segment[i])[0], point[1]);
+ listener.lineEnd();
+ return;
+ }
+ if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+ segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+ }
+ return clip;
+ };
+ }
+ function d3_geo_clipPolygon(segments, interpolate, listener) {
+ var subject = [], clip = [];
+ segments.forEach(function(segment) {
+ var n = segment.length;
+ if (n <= 1) return;
+ var p0 = segment[0], p1 = segment[n - 1], a = {
+ point: p0,
+ points: segment,
+ other: null,
+ visited: false,
+ entry: true,
+ subject: true
+ }, b = {
+ point: p0,
+ points: [ p0 ],
+ other: a,
+ visited: false,
+ entry: false,
+ subject: false
+ };
+ a.other = b;
+ subject.push(a);
+ clip.push(b);
+ a = {
+ point: p1,
+ points: [ p1 ],
+ other: null,
+ visited: false,
+ entry: false,
+ subject: true
+ };
+ b = {
+ point: p1,
+ points: [ p1 ],
+ other: a,
+ visited: false,
+ entry: true,
+ subject: false
+ };
+ a.other = b;
+ subject.push(a);
+ clip.push(b);
+ });
+ clip.sort(d3_geo_clipSort);
+ d3_geo_clipLinkCircular(subject);
+ d3_geo_clipLinkCircular(clip);
+ if (!subject.length) return;
+ var start = subject[0], current, points, point;
+ while (1) {
+ current = start;
+ while (current.visited) if ((current = current.next) === start) return;
+ points = current.points;
+ listener.lineStart();
+ do {
+ current.visited = current.other.visited = true;
+ if (current.entry) {
+ if (current.subject) {
+ for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.point, current.next.point, 1, listener);
+ }
+ current = current.next;
+ } else {
+ if (current.subject) {
+ points = current.prev.points;
+ for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.point, current.prev.point, -1, listener);
+ }
+ current = current.prev;
+ }
+ current = current.other;
+ points = current.points;
+ } while (!current.visited);
+ listener.lineEnd();
+ }
+ }
+ function d3_geo_clipLinkCircular(array) {
+ if (!(n = array.length)) return;
+ var n, i = 0, a = array[0], b;
+ while (++i < n) {
+ a.next = b = array[i];
+ b.prev = a;
+ a = b;
+ }
+ a.next = b = array[0];
+ b.prev = a;
+ }
+ function d3_geo_clipSort(a, b) {
+ return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]);
+ }
+ function d3_geo_clipSegmentLength1(segment) {
+ return segment.length > 1;
+ }
+ function d3_geo_clipBufferListener() {
+ var lines = [], line;
+ return {
+ lineStart: function() {
+ lines.push(line = []);
+ },
+ point: function(λ, φ) {
+ line.push([ λ, φ ]);
+ },
+ lineEnd: d3_noop,
+ buffer: function() {
+ var buffer = lines;
+ lines = [];
+ line = null;
+ return buffer;
+ }
+ };
+ }
+ function d3_geo_clipAreaRing(ring, invisible) {
+ if (!(n = ring.length)) return 0;
+ var n, i = 0, area = 0, p = ring[0], λ = p[0], φ = p[1], cosφ = Math.cos(φ), x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), y0 = 1 - invisible * Math.cos(λ) * cosφ, x1 = x0, x, y;
+ while (++i < n) {
+ p = ring[i];
+ cosφ = Math.cos(φ = p[1]);
+ x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ));
+ y = 1 - invisible * Math.cos(λ) * cosφ;
+ if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue;
+ if (Math.abs(y) < ε || Math.abs(y0) < ε) {} else if (Math.abs(Math.abs(x - x0) - π) < ε) {
+ if (y + y0 > 2) area += 4 * (x - x0);
+ } else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y);
+ x1 = x0, x0 = x, y0 = y;
+ }
+ return area;
+ }
+ var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate);
+ function d3_geo_clipAntimeridianLine(listener) {
+ var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
+ return {
+ lineStart: function() {
+ listener.lineStart();
+ clean = 1;
+ },
+ point: function(λ1, φ1) {
+ var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0);
+ if (Math.abs(dλ - π) < ε) {
+ listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ listener.point(λ1, φ0);
+ clean = 0;
+ } else if (sλ0 !== sλ1 && dλ >= π) {
+ if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
+ if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
+ φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ clean = 0;
+ }
+ listener.point(λ0 = λ1, φ0 = φ1);
+ sλ0 = sλ1;
+ },
+ lineEnd: function() {
+ listener.lineEnd();
+ λ0 = φ0 = NaN;
+ },
+ clean: function() {
+ return 2 - clean;
+ }
+ };
+ }
+ function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
+ var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
+ return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
+ }
+ function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
+ var φ;
+ if (from == null) {
+ φ = direction * π / 2;
+ listener.point(-π, φ);
+ listener.point(0, φ);
+ listener.point(π, φ);
+ listener.point(Ï€, 0);
+ listener.point(π, -φ);
+ listener.point(0, -φ);
+ listener.point(-π, -φ);
+ listener.point(-Ï€, 0);
+ listener.point(-π, φ);
+ } else if (Math.abs(from[0] - to[0]) > ε) {
+ var s = (from[0] < to[0] ? 1 : -1) * π;
+ φ = direction * s / 2;
+ listener.point(-s, φ);
+ listener.point(0, φ);
+ listener.point(s, φ);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function d3_geo_clipCircle(degrees) {
+ var radians = degrees * d3_radians, cr = Math.cos(radians), interpolate = d3_geo_circleInterpolate(radians, 6 * d3_radians);
+ return d3_geo_clip(visible, clipLine, interpolate);
+ function visible(λ, φ) {
+ return Math.cos(λ) * Math.cos(φ) > cr;
+ }
+ function clipLine(listener) {
+ var point0, v0, v00, clean;
+ return {
+ lineStart: function() {
+ v00 = v0 = false;
+ clean = 1;
+ },
+ point: function(λ, φ) {
+ var point1 = [ λ, φ ], point2, v = visible(λ, φ);
+ if (!point0 && (v00 = v0 = v)) listener.lineStart();
+ if (v !== v0) {
+ point2 = intersect(point0, point1);
+ if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
+ point1[0] += ε;
+ point1[1] += ε;
+ v = visible(point1[0], point1[1]);
+ }
+ }
+ if (v !== v0) {
+ clean = 0;
+ if (v0 = v) {
+ listener.lineStart();
+ point2 = intersect(point1, point0);
+ listener.point(point2[0], point2[1]);
+ } else {
+ point2 = intersect(point0, point1);
+ listener.point(point2[0], point2[1]);
+ listener.lineEnd();
+ }
+ point0 = point2;
+ }
+ if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) listener.point(point1[0], point1[1]);
+ point0 = point1;
+ },
+ lineEnd: function() {
+ if (v0) listener.lineEnd();
+ point0 = null;
+ },
+ clean: function() {
+ return clean | (v00 && v0) << 1;
+ }
+ };
+ }
+ function intersect(a, b) {
+ var pa = d3_geo_cartesian(a, 0), pb = d3_geo_cartesian(b, 0);
+ var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
+ if (!determinant) return a;
+ var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
+ d3_geo_cartesianAdd(A, B);
+ var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t = Math.sqrt(w * w - uu * (d3_geo_cartesianDot(A, A) - 1)), q = d3_geo_cartesianScale(u, (-w - t) / uu);
+ d3_geo_cartesianAdd(q, A);
+ return d3_geo_spherical(q);
+ }
+ }
+ function d3_geo_compose(a, b) {
+ function compose(x, y) {
+ return x = a(x, y), b(x[0], x[1]);
+ }
+ if (a.invert && b.invert) compose.invert = function(x, y) {
+ return x = b.invert(x, y), x && a.invert(x[0], x[1]);
+ };
+ return compose;
+ }
+ function d3_geo_equirectangular(λ, φ) {
+ return [ λ, φ ];
+ }
+ (d3.geo.equirectangular = function() {
+ return d3_geo_projection(d3_geo_equirectangular).scale(250 / π);
+ }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+ var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / cosλcosφ;
+ }, Math.atan);
+ (d3.geo.gnomonic = function() {
+ return d3_geo_projection(d3_geo_gnomonic);
+ }).raw = d3_geo_gnomonic;
+ d3.geo.graticule = function() {
+ var x1, x0, y1, y0, dx = 22.5, dy = dx, x, y, precision = 2.5;
+ function graticule() {
+ return {
+ type: "MultiLineString",
+ coordinates: lines()
+ };
+ }
+ function lines() {
+ return d3.range(Math.ceil(x0 / dx) * dx, x1, dx).map(x).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).map(y));
+ }
+ graticule.lines = function() {
+ return lines().map(function(coordinates) {
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ });
+ };
+ graticule.outline = function() {
+ return {
+ type: "Polygon",
+ coordinates: [ x(x0).concat(y(y1).slice(1), x(x1).reverse().slice(1), y(y0).reverse().slice(1)) ]
+ };
+ };
+ graticule.extent = function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ x0 = +_[0][0], x1 = +_[1][0];
+ y0 = +_[0][1], y1 = +_[1][1];
+ if (x0 > x1) _ = x0, x0 = x1, x1 = _;
+ if (y0 > y1) _ = y0, y0 = y1, y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.step = function(_) {
+ if (!arguments.length) return [ dx, dy ];
+ dx = +_[0], dy = +_[1];
+ return graticule;
+ };
+ graticule.precision = function(_) {
+ if (!arguments.length) return precision;
+ precision = +_;
+ x = d3_geo_graticuleX(y0, y1, precision);
+ y = d3_geo_graticuleY(x0, x1, precision);
+ return graticule;
+ };
+ return graticule.extent([ [ -180 + ε, -90 + ε ], [ 180 - ε, 90 - ε ] ]);
+ };
+ function d3_geo_graticuleX(y0, y1, dy) {
+ var y = d3.range(y0, y1 - ε, dy).concat(y1);
+ return function(x) {
+ return y.map(function(y) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_geo_graticuleY(x0, x1, dx) {
+ var x = d3.range(x0, x1 - ε, dx).concat(x1);
+ return function(y) {
+ return x.map(function(x) {
+ return [ x, y ];
+ });
+ };
+ }
+ d3.geo.interpolate = function(source, target) {
+ return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
+ };
+ function d3_geo_interpolate(x0, y0, x1, y1) {
+ var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))), k = 1 / Math.sin(d);
+ function interpolate(t) {
+ var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
+ return [ Math.atan2(y, x) / d3_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians ];
+ }
+ interpolate.distance = d;
+ return interpolate;
+ }
+ d3.geo.greatArc = function() {
+ var source = d3_source, source_, target = d3_target, target_, precision = 6 * d3_radians, interpolate;
+ function greatArc() {
+ var p0 = source_ || source.apply(this, arguments), p1 = target_ || target.apply(this, arguments), i = interpolate || d3.geo.interpolate(p0, p1), t = 0, dt = precision / i.distance, coordinates = [ p0 ];
+ while ((t += dt) < 1) coordinates.push(i(t));
+ coordinates.push(p1);
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ }
+ greatArc.distance = function() {
+ return (interpolate || d3.geo.interpolate(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments))).distance;
+ };
+ greatArc.source = function(_) {
+ if (!arguments.length) return source;
+ source = _, source_ = typeof _ === "function" ? null : _;
+ interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
+ return greatArc;
+ };
+ greatArc.target = function(_) {
+ if (!arguments.length) return target;
+ target = _, target_ = typeof _ === "function" ? null : _;
+ interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
+ return greatArc;
+ };
+ greatArc.precision = function(_) {
+ if (!arguments.length) return precision / d3_radians;
+ precision = _ * d3_radians;
+ return greatArc;
+ };
+ return greatArc;
+ };
+ function d3_geo_mercator(λ, φ) {
+ return [ λ / (2 * π), Math.max(-.5, Math.min(+.5, Math.log(Math.tan(π / 4 + φ / 2)) / (2 * π))) ];
+ }
+ d3_geo_mercator.invert = function(x, y) {
+ return [ 2 * π * x, 2 * Math.atan(Math.exp(2 * π * y)) - π / 2 ];
+ };
+ (d3.geo.mercator = function() {
+ return d3_geo_projection(d3_geo_mercator).scale(500);
+ }).raw = d3_geo_mercator;
+ var d3_geo_orthographic = d3_geo_azimuthal(function() {
+ return 1;
+ }, Math.asin);
+ (d3.geo.orthographic = function() {
+ return d3_geo_projection(d3_geo_orthographic);
+ }).raw = d3_geo_orthographic;
+ d3.geo.path = function() {
+ var pointRadius = 4.5, projection, context, projectStream, contextStream;
+ function path(object) {
+ if (object) d3.geo.stream(object, projectStream(contextStream.pointRadius(typeof pointRadius === "function" ? +pointRadius.apply(this, arguments) : pointRadius)));
+ return contextStream.result();
+ }
+ path.area = function(object) {
+ d3_geo_pathAreaSum = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathArea));
+ return d3_geo_pathAreaSum;
+ };
+ path.centroid = function(object) {
+ d3_geo_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
+ return d3_geo_centroidZ ? [ d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ ] : undefined;
+ };
+ path.bounds = function(object) {
+ return d3_geo_bounds(projectStream)(object);
+ };
+ path.projection = function(_) {
+ if (!arguments.length) return projection;
+ projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
+ return path;
+ };
+ path.context = function(_) {
+ if (!arguments.length) return context;
+ contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
+ return path;
+ };
+ path.pointRadius = function(_) {
+ if (!arguments.length) return pointRadius;
+ pointRadius = typeof _ === "function" ? _ : +_;
+ return path;
+ };
+ return path.projection(d3.geo.albersUsa()).context(null);
+ };
+ function d3_geo_pathCircle(radius) {
+ return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z";
+ }
+ function d3_geo_pathProjectStream(project) {
+ var resample = d3_geo_resample(function(λ, φ) {
+ return project([ λ * d3_degrees, φ * d3_degrees ]);
+ });
+ return function(stream) {
+ stream = resample(stream);
+ return {
+ point: function(λ, φ) {
+ stream.point(λ * d3_radians, φ * d3_radians);
+ },
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ };
+ }
+ function d3_geo_pathBuffer() {
+ var pointCircle = d3_geo_pathCircle(4.5), buffer = [];
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointCircle = d3_geo_pathCircle(_);
+ return stream;
+ },
+ result: function() {
+ if (buffer.length) {
+ var result = buffer.join("");
+ buffer = [];
+ return result;
+ }
+ }
+ };
+ function point(x, y) {
+ buffer.push("M", x, ",", y, pointCircle);
+ }
+ function pointLineStart(x, y) {
+ buffer.push("M", x, ",", y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ buffer.push("L", x, ",", y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ buffer.push("Z");
+ }
+ return stream;
+ }
+ function d3_geo_pathContext(context) {
+ var pointRadius = 4.5;
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointRadius = _;
+ return stream;
+ },
+ result: d3_noop
+ };
+ function point(x, y) {
+ context.moveTo(x, y);
+ context.arc(x, y, pointRadius, 0, 2 * π);
+ }
+ function pointLineStart(x, y) {
+ context.moveTo(x, y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ context.lineTo(x, y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ context.closePath();
+ }
+ return stream;
+ }
+ var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_pathAreaPolygon = 0;
+ d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
+ d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2);
+ }
+ };
+ function d3_geo_pathAreaRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathArea.point = function(x, y) {
+ d3_geo_pathArea.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ d3_geo_pathAreaPolygon += y0 * x - x0 * y;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathArea.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ var d3_geo_pathCentroid = {
+ point: d3_geo_pathCentroidPoint,
+ lineStart: d3_geo_pathCentroidLineStart,
+ lineEnd: d3_geo_pathCentroidLineEnd,
+ polygonStart: function() {
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
+ d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
+ }
+ };
+ function d3_geo_pathCentroidPoint(x, y) {
+ if (d3_geo_centroidDimension) return;
+ d3_geo_centroidX += x;
+ d3_geo_centroidY += y;
+ ++d3_geo_centroidZ;
+ }
+ function d3_geo_pathCentroidLineStart() {
+ var x0, y0;
+ if (d3_geo_centroidDimension !== 1) {
+ if (d3_geo_centroidDimension < 1) {
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ } else return;
+ }
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ x0 = x, y0 = y;
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX += z * (x0 + x) / 2;
+ d3_geo_centroidY += z * (y0 + y) / 2;
+ d3_geo_centroidZ += z;
+ x0 = x, y0 = y;
+ }
+ }
+ function d3_geo_pathCentroidLineEnd() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ }
+ function d3_geo_pathCentroidRingStart() {
+ var x00, y00, x0, y0;
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ var z = y0 * x - x0 * y;
+ d3_geo_centroidX += z * (x0 + x);
+ d3_geo_centroidY += z * (y0 + y);
+ d3_geo_centroidZ += z * 3;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathCentroid.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ d3.geo.area = function(object) {
+ d3_geo_areaSum = 0;
+ d3.geo.stream(object, d3_geo_area);
+ return d3_geo_areaSum;
+ };
+ var d3_geo_areaSum, d3_geo_areaRing;
+ var d3_geo_area = {
+ sphere: function() {
+ d3_geo_areaSum += 4 * π;
+ },
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_areaRing = 0;
+ d3_geo_area.lineStart = d3_geo_areaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_areaSum += d3_geo_areaRing < 0 ? 4 * π + d3_geo_areaRing : d3_geo_areaRing;
+ d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
+ }
+ };
+ function d3_geo_areaRingStart() {
+ var λ00, φ00, λ1, λ0, φ0, cosφ0, sinφ0;
+ d3_geo_area.point = function(λ, φ) {
+ d3_geo_area.point = nextPoint;
+ λ1 = λ0 = (λ00 = λ) * d3_radians, φ0 = (φ00 = φ) * d3_radians, cosφ0 = Math.cos(φ0),
+ sinφ0 = Math.sin(φ0);
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians, φ *= d3_radians;
+ if (Math.abs(Math.abs(φ0) - π / 2) < ε && Math.abs(Math.abs(φ) - π / 2) < ε) return;
+ var cosφ = Math.cos(φ), sinφ = Math.sin(φ);
+ if (Math.abs(φ0 - π / 2) < ε) d3_geo_areaRing += (λ - λ1) * 2; else {
+ var dλ = λ - λ0, cosdλ = Math.cos(dλ), d = Math.atan2(Math.sqrt((d = cosφ * Math.sin(dλ)) * d + (d = cosφ0 * sinφ - sinφ0 * cosφ * cosdλ) * d), sinφ0 * sinφ + cosφ0 * cosφ * cosdλ), s = (d + π + φ0 + φ) / 4;
+ d3_geo_areaRing += (dλ < 0 && dλ > -π || dλ > π ? -4 : 4) * Math.atan(Math.sqrt(Math.abs(Math.tan(s) * Math.tan(s - d / 2) * Math.tan(s - π / 4 - φ0 / 2) * Math.tan(s - π / 4 - φ / 2))));
+ }
+ λ1 = λ0, λ0 = λ, φ0 = φ, cosφ0 = cosφ, sinφ0 = sinφ;
+ }
+ d3_geo_area.lineEnd = function() {
+ nextPoint(λ00, φ00);
+ };
+ }
+ d3.geo.projection = d3_geo_projection;
+ d3.geo.projectionMutator = d3_geo_projectionMutator;
+ function d3_geo_projection(project) {
+ return d3_geo_projectionMutator(function() {
+ return project;
+ })();
+ }
+ function d3_geo_projectionMutator(projectAt) {
+ var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
+ x = project(x, y);
+ return [ x[0] * k + δx, δy - x[1] * k ];
+ }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, clip = d3_geo_clipAntimeridian, clipAngle = null;
+ function projection(point) {
+ point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
+ return [ point[0] * k + δx, δy - point[1] * k ];
+ }
+ function invert(point) {
+ point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
+ return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
+ }
+ projection.stream = function(stream) {
+ return d3_geo_projectionRadiansRotate(rotate, clip(projectResample(stream)));
+ };
+ projection.clipAngle = function(_) {
+ if (!arguments.length) return clipAngle;
+ clip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle(clipAngle = +_);
+ return projection;
+ };
+ projection.scale = function(_) {
+ if (!arguments.length) return k;
+ k = +_;
+ return reset();
+ };
+ projection.translate = function(_) {
+ if (!arguments.length) return [ x, y ];
+ x = +_[0];
+ y = +_[1];
+ return reset();
+ };
+ projection.center = function(_) {
+ if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
+ λ = _[0] % 360 * d3_radians;
+ φ = _[1] % 360 * d3_radians;
+ return reset();
+ };
+ projection.rotate = function(_) {
+ if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
+ δλ = _[0] % 360 * d3_radians;
+ δφ = _[1] % 360 * d3_radians;
+ δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
+ return reset();
+ };
+ d3.rebind(projection, projectResample, "precision");
+ function reset() {
+ projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
+ var center = project(λ, φ);
+ δx = x - center[0] * k;
+ δy = y + center[1] * k;
+ return projection;
+ }
+ return function() {
+ project = projectAt.apply(this, arguments);
+ projection.invert = project.invert && invert;
+ return reset();
+ };
+ }
+ function d3_geo_projectionRadiansRotate(rotate, stream) {
+ return {
+ point: function(x, y) {
+ y = rotate(x * d3_radians, y * d3_radians), x = y[0];
+ stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]);
+ },
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ }
+ function d3_geo_rotation(δλ, δφ, δγ) {
+ return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular;
+ }
+ function d3_geo_forwardRotationλ(δλ) {
+ return function(λ, φ) {
+ return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ];
+ };
+ }
+ function d3_geo_rotationλ(δλ) {
+ var rotation = d3_geo_forwardRotationλ(δλ);
+ rotation.invert = d3_geo_forwardRotationλ(-δλ);
+ return rotation;
+ }
+ function d3_geo_rotationφγ(δφ, δγ) {
+ var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
+ function rotation(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
+ return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδγ + y * sinδγ))) ];
+ }
+ rotation.invert = function(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
+ return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) ];
+ };
+ return rotation;
+ }
+ var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / (1 + cosλcosφ);
+ }, function(Ï) {
+ return 2 * Math.atan(Ï);
+ });
+ (d3.geo.stereographic = function() {
+ return d3_geo_projection(d3_geo_stereographic);
+ }).raw = d3_geo_stereographic;
+ function d3_geo_azimuthal(scale, angle) {
+ function azimuthal(λ, φ) {
+ var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
+ return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
+ }
+ azimuthal.invert = function(x, y) {
+ var Ï = Math.sqrt(x * x + y * y), c = angle(Ï), sinc = Math.sin(c), cosc = Math.cos(c);
+ return [ Math.atan2(x * sinc, Ï * cosc), Math.asin(Ï && y * sinc / Ï) ];
+ };
+ return azimuthal;
+ }
+ d3.geom = {};
+ d3.geom.hull = function(vertices) {
+ if (vertices.length < 3) return [];
+ var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
+ for (i = 1; i < len; ++i) {
+ if (vertices[i][1] < vertices[h][1]) {
+ h = i;
+ } else if (vertices[i][1] == vertices[h][1]) {
+ h = vertices[i][0] < vertices[h][0] ? i : h;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+ if (i === h) continue;
+ y1 = vertices[i][1] - vertices[h][1];
+ x1 = vertices[i][0] - vertices[h][0];
+ points.push({
+ angle: Math.atan2(y1, x1),
+ index: i
+ });
+ }
+ points.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ a = points[0].angle;
+ v = points[0].index;
+ u = 0;
+ for (i = 1; i < plen; ++i) {
+ j = points[i].index;
+ if (a == points[i].angle) {
+ x1 = vertices[v][0] - vertices[h][0];
+ y1 = vertices[v][1] - vertices[h][1];
+ x2 = vertices[j][0] - vertices[h][0];
+ y2 = vertices[j][1] - vertices[h][1];
+ if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
+ points[i].index = -1;
+ } else {
+ points[u].index = -1;
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ } else {
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ }
+ stack.push(h);
+ for (i = 0, j = 0; i < 2; ++j) {
+ if (points[j].index !== -1) {
+ stack.push(points[j].index);
+ i++;
+ }
+ }
+ sp = stack.length;
+ for (;j < plen; ++j) {
+ if (points[j].index === -1) continue;
+ while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) {
+ --sp;
+ }
+ stack[sp++] = points[j].index;
+ }
+ var poly = [];
+ for (i = 0; i < sp; ++i) {
+ poly.push(vertices[stack[i]]);
+ }
+ return poly;
+ };
+ function d3_geom_hullCCW(i1, i2, i3, v) {
+ var t, a, b, c, d, e, f;
+ t = v[i1];
+ a = t[0];
+ b = t[1];
+ t = v[i2];
+ c = t[0];
+ d = t[1];
+ t = v[i3];
+ e = t[0];
+ f = t[1];
+ return (f - b) * (c - a) - (d - b) * (e - a) > 0;
+ }
+ d3.geom.polygon = function(coordinates) {
+ coordinates.area = function() {
+ var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1];
+ while (++i < n) {
+ area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1];
+ }
+ return area * .5;
+ };
+ coordinates.centroid = function(k) {
+ var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;
+ if (!arguments.length) k = -1 / (6 * coordinates.area());
+ while (++i < n) {
+ a = b;
+ b = coordinates[i];
+ c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+ return [ x * k, y * k ];
+ };
+ coordinates.clip = function(subject) {
+ var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;
+ while (++i < n) {
+ input = subject.slice();
+ subject.length = 0;
+ b = coordinates[i];
+ c = input[(m = input.length) - 1];
+ j = -1;
+ while (++j < m) {
+ d = input[j];
+ if (d3_geom_polygonInside(d, a, b)) {
+ if (!d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ subject.push(d);
+ } else if (d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ c = d;
+ }
+ a = b;
+ }
+ return subject;
+ };
+ return coordinates;
+ };
+ function d3_geom_polygonInside(p, a, b) {
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+ }
+ function d3_geom_polygonIntersect(c, d, a, b) {
+ var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
+ return [ x1 + ua * x21, y1 + ua * y21 ];
+ }
+ d3.geom.voronoi = function(vertices) {
+ var polygons = vertices.map(function() {
+ return [];
+ }), Z = 1e6;
+ d3_voronoi_tessellate(vertices, function(e) {
+ var s1, s2, x1, x2, y1, y2;
+ if (e.a === 1 && e.b >= 0) {
+ s1 = e.ep.r;
+ s2 = e.ep.l;
+ } else {
+ s1 = e.ep.l;
+ s2 = e.ep.r;
+ }
+ if (e.a === 1) {
+ y1 = s1 ? s1.y : -Z;
+ x1 = e.c - e.b * y1;
+ y2 = s2 ? s2.y : Z;
+ x2 = e.c - e.b * y2;
+ } else {
+ x1 = s1 ? s1.x : -Z;
+ y1 = e.c - e.a * x1;
+ x2 = s2 ? s2.x : Z;
+ y2 = e.c - e.a * x2;
+ }
+ var v1 = [ x1, y1 ], v2 = [ x2, y2 ];
+ polygons[e.region.l.index].push(v1, v2);
+ polygons[e.region.r.index].push(v1, v2);
+ });
+ polygons = polygons.map(function(polygon, i) {
+ var cx = vertices[i][0], cy = vertices[i][1], angle = polygon.map(function(v) {
+ return Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ return d3.range(polygon.length).sort(function(a, b) {
+ return angle[a] - angle[b];
+ }).filter(function(d, i, order) {
+ return !i || angle[d] - angle[order[i - 1]] > ε;
+ }).map(function(d) {
+ return polygon[d];
+ });
+ });
+ polygons.forEach(function(polygon, i) {
+ var n = polygon.length;
+ if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]);
+ if (n > 2) return;
+ var p0 = vertices[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1;
+ if (Math.abs(dy) < ε) {
+ var y = y0 < y1 ? -Z : Z;
+ polygon.push([ -Z, y ], [ Z, y ]);
+ } else if (dx < ε) {
+ var x = x0 < x1 ? -Z : Z;
+ polygon.push([ x, -Z ], [ x, Z ]);
+ } else {
+ var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx;
+ if (Math.abs(z) < ε) {
+ polygon.push([ dy < 0 ? y : -y, y ]);
+ } else {
+ if (z > 0) y *= -1;
+ polygon.push([ -Z, y ], [ Z, y ]);
+ }
+ }
+ });
+ return polygons;
+ };
+ var d3_voronoi_opposite = {
+ l: "r",
+ r: "l"
+ };
+ function d3_voronoi_tessellate(vertices, callback) {
+ var Sites = {
+ list: vertices.map(function(v, i) {
+ return {
+ index: i,
+ x: v[0],
+ y: v[1]
+ };
+ }).sort(function(a, b) {
+ return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0;
+ }),
+ bottomSite: null
+ };
+ var EdgeList = {
+ list: [],
+ leftEnd: null,
+ rightEnd: null,
+ init: function() {
+ EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.leftEnd.r = EdgeList.rightEnd;
+ EdgeList.rightEnd.l = EdgeList.leftEnd;
+ EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
+ },
+ createHalfEdge: function(edge, side) {
+ return {
+ edge: edge,
+ side: side,
+ vertex: null,
+ l: null,
+ r: null
+ };
+ },
+ insert: function(lb, he) {
+ he.l = lb;
+ he.r = lb.r;
+ lb.r.l = he;
+ lb.r = he;
+ },
+ leftBound: function(p) {
+ var he = EdgeList.leftEnd;
+ do {
+ he = he.r;
+ } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
+ he = he.l;
+ return he;
+ },
+ del: function(he) {
+ he.l.r = he.r;
+ he.r.l = he.l;
+ he.edge = null;
+ },
+ right: function(he) {
+ return he.r;
+ },
+ left: function(he) {
+ return he.l;
+ },
+ leftRegion: function(he) {
+ return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];
+ },
+ rightRegion: function(he) {
+ return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]];
+ }
+ };
+ var Geom = {
+ bisect: function(s1, s2) {
+ var newEdge = {
+ region: {
+ l: s1,
+ r: s2
+ },
+ ep: {
+ l: null,
+ r: null
+ }
+ };
+ var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;
+ newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;
+ if (adx > ady) {
+ newEdge.a = 1;
+ newEdge.b = dy / dx;
+ newEdge.c /= dx;
+ } else {
+ newEdge.b = 1;
+ newEdge.a = dx / dy;
+ newEdge.c /= dy;
+ }
+ return newEdge;
+ },
+ intersect: function(el1, el2) {
+ var e1 = el1.edge, e2 = el2.edge;
+ if (!e1 || !e2 || e1.region.r == e2.region.r) {
+ return null;
+ }
+ var d = e1.a * e2.b - e1.b * e2.a;
+ if (Math.abs(d) < 1e-10) {
+ return null;
+ }
+ var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e;
+ if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {
+ el = el1;
+ e = e1;
+ } else {
+ el = el2;
+ e = e2;
+ }
+ var rightOfSite = xint >= e.region.r.x;
+ if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") {
+ return null;
+ }
+ return {
+ x: xint,
+ y: yint
+ };
+ },
+ rightOf: function(he, p) {
+ var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;
+ if (rightOfSite && he.side === "l") {
+ return 1;
+ }
+ if (!rightOfSite && he.side === "r") {
+ return 0;
+ }
+ if (e.a === 1) {
+ var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;
+ if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) {
+ above = fast = dyp >= e.b * dxp;
+ } else {
+ above = p.x + p.y * e.b > e.c;
+ if (e.b < 0) {
+ above = !above;
+ }
+ if (!above) {
+ fast = 1;
+ }
+ }
+ if (!fast) {
+ var dxs = topsite.x - e.region.l.x;
+ above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b);
+ if (e.b < 0) {
+ above = !above;
+ }
+ }
+ } else {
+ var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y;
+ above = t1 * t1 > t2 * t2 + t3 * t3;
+ }
+ return he.side === "l" ? above : !above;
+ },
+ endPoint: function(edge, side, site) {
+ edge.ep[side] = site;
+ if (!edge.ep[d3_voronoi_opposite[side]]) return;
+ callback(edge);
+ },
+ distance: function(s, t) {
+ var dx = s.x - t.x, dy = s.y - t.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ };
+ var EventQueue = {
+ list: [],
+ insert: function(he, site, offset) {
+ he.vertex = site;
+ he.ystar = site.y + offset;
+ for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {
+ var next = list[i];
+ if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ list.splice(i, 0, he);
+ },
+ del: function(he) {
+ for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {}
+ ls.splice(i, 1);
+ },
+ empty: function() {
+ return EventQueue.list.length === 0;
+ },
+ nextEvent: function(he) {
+ for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {
+ if (ls[i] == he) return ls[i + 1];
+ }
+ return null;
+ },
+ min: function() {
+ var elem = EventQueue.list[0];
+ return {
+ x: elem.vertex.x,
+ y: elem.ystar
+ };
+ },
+ extractMin: function() {
+ return EventQueue.list.shift();
+ }
+ };
+ EdgeList.init();
+ Sites.bottomSite = Sites.list.shift();
+ var newSite = Sites.list.shift(), newIntStar;
+ var lbnd, rbnd, llbnd, rrbnd, bisector;
+ var bot, top, temp, p, v;
+ var e, pm;
+ while (true) {
+ if (!EventQueue.empty()) {
+ newIntStar = EventQueue.min();
+ }
+ if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {
+ lbnd = EdgeList.leftBound(newSite);
+ rbnd = EdgeList.right(lbnd);
+ bot = EdgeList.rightRegion(lbnd);
+ e = Geom.bisect(bot, newSite);
+ bisector = EdgeList.createHalfEdge(e, "l");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(lbnd, bisector);
+ if (p) {
+ EventQueue.del(lbnd);
+ EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
+ }
+ lbnd = bisector;
+ bisector = EdgeList.createHalfEdge(e, "r");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(bisector, rbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, newSite));
+ }
+ newSite = Sites.list.shift();
+ } else if (!EventQueue.empty()) {
+ lbnd = EventQueue.extractMin();
+ llbnd = EdgeList.left(lbnd);
+ rbnd = EdgeList.right(lbnd);
+ rrbnd = EdgeList.right(rbnd);
+ bot = EdgeList.leftRegion(lbnd);
+ top = EdgeList.rightRegion(rbnd);
+ v = lbnd.vertex;
+ Geom.endPoint(lbnd.edge, lbnd.side, v);
+ Geom.endPoint(rbnd.edge, rbnd.side, v);
+ EdgeList.del(lbnd);
+ EventQueue.del(rbnd);
+ EdgeList.del(rbnd);
+ pm = "l";
+ if (bot.y > top.y) {
+ temp = bot;
+ bot = top;
+ top = temp;
+ pm = "r";
+ }
+ e = Geom.bisect(bot, top);
+ bisector = EdgeList.createHalfEdge(e, pm);
+ EdgeList.insert(llbnd, bisector);
+ Geom.endPoint(e, d3_voronoi_opposite[pm], v);
+ p = Geom.intersect(llbnd, bisector);
+ if (p) {
+ EventQueue.del(llbnd);
+ EventQueue.insert(llbnd, p, Geom.distance(p, bot));
+ }
+ p = Geom.intersect(bisector, rrbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, bot));
+ }
+ } else {
+ break;
+ }
+ }
+ for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) {
+ callback(lbnd.edge);
+ }
+ }
+ d3.geom.delaunay = function(vertices) {
+ var edges = vertices.map(function() {
+ return [];
+ }), triangles = [];
+ d3_voronoi_tessellate(vertices, function(e) {
+ edges[e.region.l.index].push(vertices[e.region.r.index]);
+ });
+ edges.forEach(function(edge, i) {
+ var v = vertices[i], cx = v[0], cy = v[1];
+ edge.forEach(function(v) {
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ edge.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ for (var j = 0, m = edge.length - 1; j < m; j++) {
+ triangles.push([ v, edge[j], edge[j + 1] ]);
+ }
+ });
+ return triangles;
+ };
+ d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+ var p, i = -1, n = points.length;
+ if (arguments.length < 5) {
+ if (arguments.length === 3) {
+ y2 = y1;
+ x2 = x1;
+ y1 = x1 = 0;
+ } else {
+ x1 = y1 = Infinity;
+ x2 = y2 = -Infinity;
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) x1 = p.x;
+ if (p.y < y1) y1 = p.y;
+ if (p.x > x2) x2 = p.x;
+ if (p.y > y2) y2 = p.y;
+ }
+ }
+ }
+ var dx = x2 - x1, dy = y2 - y1;
+ if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy;
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) return;
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, p, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+ if (right) x1 = sx; else x2 = sx;
+ if (bottom) y1 = sy; else y2 = sy;
+ insert(n, p, x1, y1, x2, y2);
+ }
+ var root = d3_geom_quadtreeNode();
+ root.add = function(p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+ root.visit = function(f) {
+ d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+ points.forEach(root.add);
+ return root;
+ };
+ function d3_geom_quadtreeNode() {
+ return {
+ leaf: true,
+ nodes: [],
+ point: null
+ };
+ }
+ function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ d3.time = {};
+ var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+ function d3_time_utc() {
+ this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
+ }
+ d3_time_utc.prototype = {
+ getDate: function() {
+ return this._.getUTCDate();
+ },
+ getDay: function() {
+ return this._.getUTCDay();
+ },
+ getFullYear: function() {
+ return this._.getUTCFullYear();
+ },
+ getHours: function() {
+ return this._.getUTCHours();
+ },
+ getMilliseconds: function() {
+ return this._.getUTCMilliseconds();
+ },
+ getMinutes: function() {
+ return this._.getUTCMinutes();
+ },
+ getMonth: function() {
+ return this._.getUTCMonth();
+ },
+ getSeconds: function() {
+ return this._.getUTCSeconds();
+ },
+ getTime: function() {
+ return this._.getTime();
+ },
+ getTimezoneOffset: function() {
+ return 0;
+ },
+ valueOf: function() {
+ return this._.valueOf();
+ },
+ setDate: function() {
+ d3_time_prototype.setUTCDate.apply(this._, arguments);
+ },
+ setDay: function() {
+ d3_time_prototype.setUTCDay.apply(this._, arguments);
+ },
+ setFullYear: function() {
+ d3_time_prototype.setUTCFullYear.apply(this._, arguments);
+ },
+ setHours: function() {
+ d3_time_prototype.setUTCHours.apply(this._, arguments);
+ },
+ setMilliseconds: function() {
+ d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
+ },
+ setMinutes: function() {
+ d3_time_prototype.setUTCMinutes.apply(this._, arguments);
+ },
+ setMonth: function() {
+ d3_time_prototype.setUTCMonth.apply(this._, arguments);
+ },
+ setSeconds: function() {
+ d3_time_prototype.setUTCSeconds.apply(this._, arguments);
+ },
+ setTime: function() {
+ d3_time_prototype.setTime.apply(this._, arguments);
+ }
+ };
+ var d3_time_prototype = Date.prototype;
+ var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S";
+ var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+ d3.time.format = function(template) {
+ var n = template.length;
+ function format(date) {
+ var string = [], i = -1, j = 0, c, p, f;
+ while (++i < n) {
+ if (template.charCodeAt(i) === 37) {
+ string.push(template.substring(j, i));
+ if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
+ if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
+ string.push(c);
+ j = i + 1;
+ }
+ }
+ string.push(template.substring(j, i));
+ return string.join("");
+ }
+ format.parse = function(string) {
+ var d = {
+ y: 1900,
+ m: 0,
+ d: 1,
+ H: 0,
+ M: 0,
+ S: 0,
+ L: 0
+ }, i = d3_time_parse(d, template, string, 0);
+ if (i != string.length) return null;
+ if ("p" in d) d.H = d.H % 12 + d.p * 12;
+ var date = new d3_time();
+ date.setFullYear(d.y, d.m, d.d);
+ date.setHours(d.H, d.M, d.S, d.L);
+ return date;
+ };
+ format.toString = function() {
+ return template;
+ };
+ return format;
+ };
+ function d3_time_parse(date, template, string, j) {
+ var c, p, i = 0, n = template.length, m = string.length;
+ while (i < n) {
+ if (j >= m) return -1;
+ c = template.charCodeAt(i++);
+ if (c === 37) {
+ p = d3_time_parsers[template.charAt(i++)];
+ if (!p || (j = p(date, string, j)) < 0) return -1;
+ } else if (c != string.charCodeAt(j++)) {
+ return -1;
+ }
+ }
+ return j;
+ }
+ function d3_time_formatRe(names) {
+ return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
+ }
+ function d3_time_formatLookup(names) {
+ var map = new d3_Map(), i = -1, n = names.length;
+ while (++i < n) map.set(names[i].toLowerCase(), i);
+ return map;
+ }
+ function d3_time_formatPad(value, fill, width) {
+ value += "";
+ var length = value.length;
+ return length < width ? new Array(width - length + 1).join(fill) + value : value;
+ }
+ var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations);
+ var d3_time_formatPads = {
+ "-": "",
+ _: " ",
+ "0": "0"
+ };
+ var d3_time_formats = {
+ a: function(d) {
+ return d3_time_dayAbbreviations[d.getDay()];
+ },
+ A: function(d) {
+ return d3_time_days[d.getDay()];
+ },
+ b: function(d) {
+ return d3_time_monthAbbreviations[d.getMonth()];
+ },
+ B: function(d) {
+ return d3_time_months[d.getMonth()];
+ },
+ c: d3.time.format(d3_time_formatDateTime),
+ d: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ e: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ H: function(d, p) {
+ return d3_time_formatPad(d.getHours(), p, 2);
+ },
+ I: function(d, p) {
+ return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
+ },
+ j: function(d, p) {
+ return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3);
+ },
+ L: function(d, p) {
+ return d3_time_formatPad(d.getMilliseconds(), p, 3);
+ },
+ m: function(d, p) {
+ return d3_time_formatPad(d.getMonth() + 1, p, 2);
+ },
+ M: function(d, p) {
+ return d3_time_formatPad(d.getMinutes(), p, 2);
+ },
+ p: function(d) {
+ return d.getHours() >= 12 ? "PM" : "AM";
+ },
+ S: function(d, p) {
+ return d3_time_formatPad(d.getSeconds(), p, 2);
+ },
+ U: function(d, p) {
+ return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2);
+ },
+ w: function(d) {
+ return d.getDay();
+ },
+ W: function(d, p) {
+ return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2);
+ },
+ x: d3.time.format(d3_time_formatDate),
+ X: d3.time.format(d3_time_formatTime),
+ y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 100, p, 2);
+ },
+ Y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
+ },
+ Z: d3_time_zone,
+ "%": function() {
+ return "%";
+ }
+ };
+ var d3_time_parsers = {
+ a: d3_time_parseWeekdayAbbrev,
+ A: d3_time_parseWeekday,
+ b: d3_time_parseMonthAbbrev,
+ B: d3_time_parseMonth,
+ c: d3_time_parseLocaleFull,
+ d: d3_time_parseDay,
+ e: d3_time_parseDay,
+ H: d3_time_parseHour24,
+ I: d3_time_parseHour24,
+ L: d3_time_parseMilliseconds,
+ m: d3_time_parseMonthNumber,
+ M: d3_time_parseMinutes,
+ p: d3_time_parseAmPm,
+ S: d3_time_parseSeconds,
+ x: d3_time_parseLocaleDate,
+ X: d3_time_parseLocaleTime,
+ y: d3_time_parseYear,
+ Y: d3_time_parseFullYear
+ };
+ function d3_time_parseWeekdayAbbrev(date, string, i) {
+ d3_time_dayAbbrevRe.lastIndex = 0;
+ var n = d3_time_dayAbbrevRe.exec(string.substring(i));
+ return n ? i += n[0].length : -1;
+ }
+ function d3_time_parseWeekday(date, string, i) {
+ d3_time_dayRe.lastIndex = 0;
+ var n = d3_time_dayRe.exec(string.substring(i));
+ return n ? i += n[0].length : -1;
+ }
+ function d3_time_parseMonthAbbrev(date, string, i) {
+ d3_time_monthAbbrevRe.lastIndex = 0;
+ var n = d3_time_monthAbbrevRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
+ }
+ function d3_time_parseMonth(date, string, i) {
+ d3_time_monthRe.lastIndex = 0;
+ var n = d3_time_monthRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
+ }
+ function d3_time_parseLocaleFull(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
+ }
+ function d3_time_parseLocaleDate(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
+ }
+ function d3_time_parseLocaleTime(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
+ }
+ function d3_time_parseFullYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 4));
+ return n ? (date.y = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1;
+ }
+ function d3_time_expandYear(d) {
+ return d + (d > 68 ? 1900 : 2e3);
+ }
+ function d3_time_parseMonthNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.m = n[0] - 1, i += n[0].length) : -1;
+ }
+ function d3_time_parseDay(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.d = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseHour24(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.H = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseMinutes(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.M = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseSeconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.S = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseMilliseconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.L = +n[0], i += n[0].length) : -1;
+ }
+ var d3_time_numberRe = /^\s*\d+/;
+ function d3_time_parseAmPm(date, string, i) {
+ var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
+ return n == null ? -1 : (date.p = n, i);
+ }
+ var d3_time_amPmLookup = d3.map({
+ am: 0,
+ pm: 1
+ });
+ function d3_time_zone(d) {
+ var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;
+ return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
+ }
+ d3.time.format.utc = function(template) {
+ var local = d3.time.format(template);
+ function format(date) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time();
+ utc._ = date;
+ return local(utc);
+ } finally {
+ d3_time = Date;
+ }
+ }
+ format.parse = function(string) {
+ try {
+ d3_time = d3_time_utc;
+ var date = local.parse(string);
+ return date && date._;
+ } finally {
+ d3_time = Date;
+ }
+ };
+ format.toString = local.toString;
+ return format;
+ };
+ var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
+ d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso;
+ function d3_time_formatIsoNative(date) {
+ return date.toISOString();
+ }
+ d3_time_formatIsoNative.parse = function(string) {
+ var date = new Date(string);
+ return isNaN(date) ? null : date;
+ };
+ d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
+ function d3_time_interval(local, step, number) {
+ function round(date) {
+ var d0 = local(date), d1 = offset(d0, 1);
+ return date - d0 < d1 - date ? d0 : d1;
+ }
+ function ceil(date) {
+ step(date = local(new d3_time(date - 1)), 1);
+ return date;
+ }
+ function offset(date, k) {
+ step(date = new d3_time(+date), k);
+ return date;
+ }
+ function range(t0, t1, dt) {
+ var time = ceil(t0), times = [];
+ if (dt > 1) {
+ while (time < t1) {
+ if (!(number(time) % dt)) times.push(new Date(+time));
+ step(time, 1);
+ }
+ } else {
+ while (time < t1) times.push(new Date(+time)), step(time, 1);
+ }
+ return times;
+ }
+ function range_utc(t0, t1, dt) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time_utc();
+ utc._ = t0;
+ return range(utc, t1, dt);
+ } finally {
+ d3_time = Date;
+ }
+ }
+ local.floor = local;
+ local.round = round;
+ local.ceil = ceil;
+ local.offset = offset;
+ local.range = range;
+ var utc = local.utc = d3_time_interval_utc(local);
+ utc.floor = utc;
+ utc.round = d3_time_interval_utc(round);
+ utc.ceil = d3_time_interval_utc(ceil);
+ utc.offset = d3_time_interval_utc(offset);
+ utc.range = range_utc;
+ return local;
+ }
+ function d3_time_interval_utc(method) {
+ return function(date, k) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time_utc();
+ utc._ = date;
+ return method(utc, k)._;
+ } finally {
+ d3_time = Date;
+ }
+ };
+ }
+ d3.time.second = d3_time_interval(function(date) {
+ return new d3_time(Math.floor(date / 1e3) * 1e3);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 1e3);
+ }, function(date) {
+ return date.getSeconds();
+ });
+ d3.time.seconds = d3.time.second.range;
+ d3.time.seconds.utc = d3.time.second.utc.range;
+ d3.time.minute = d3_time_interval(function(date) {
+ return new d3_time(Math.floor(date / 6e4) * 6e4);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 6e4);
+ }, function(date) {
+ return date.getMinutes();
+ });
+ d3.time.minutes = d3.time.minute.range;
+ d3.time.minutes.utc = d3.time.minute.utc.range;
+ d3.time.hour = d3_time_interval(function(date) {
+ var timezone = date.getTimezoneOffset() / 60;
+ return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 36e5);
+ }, function(date) {
+ return date.getHours();
+ });
+ d3.time.hours = d3.time.hour.range;
+ d3.time.hours.utc = d3.time.hour.utc.range;
+ d3.time.day = d3_time_interval(function(date) {
+ var day = new d3_time(1970, 0);
+ day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
+ return day;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + offset);
+ }, function(date) {
+ return date.getDate() - 1;
+ });
+ d3.time.days = d3.time.day.range;
+ d3.time.days.utc = d3.time.day.utc.range;
+ d3.time.dayOfYear = function(date) {
+ var year = d3.time.year(date);
+ return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
+ };
+ d3_time_daySymbols.forEach(function(day, i) {
+ day = day.toLowerCase();
+ i = 7 - i;
+ var interval = d3.time[day] = d3_time_interval(function(date) {
+ (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
+ return date;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + Math.floor(offset) * 7);
+ }, function(date) {
+ var day = d3.time.year(date).getDay();
+ return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
+ });
+ d3.time[day + "s"] = interval.range;
+ d3.time[day + "s"].utc = interval.utc.range;
+ d3.time[day + "OfYear"] = function(date) {
+ var day = d3.time.year(date).getDay();
+ return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7);
+ };
+ });
+ d3.time.week = d3.time.sunday;
+ d3.time.weeks = d3.time.sunday.range;
+ d3.time.weeks.utc = d3.time.sunday.utc.range;
+ d3.time.weekOfYear = d3.time.sundayOfYear;
+ d3.time.month = d3_time_interval(function(date) {
+ date = d3.time.day(date);
+ date.setDate(1);
+ return date;
+ }, function(date, offset) {
+ date.setMonth(date.getMonth() + offset);
+ }, function(date) {
+ return date.getMonth();
+ });
+ d3.time.months = d3.time.month.range;
+ d3.time.months.utc = d3.time.month.utc.range;
+ d3.time.year = d3_time_interval(function(date) {
+ date = d3.time.day(date);
+ date.setMonth(0, 1);
+ return date;
+ }, function(date, offset) {
+ date.setFullYear(date.getFullYear() + offset);
+ }, function(date) {
+ return date.getFullYear();
+ });
+ d3.time.years = d3.time.year.range;
+ d3.time.years.utc = d3.time.year.utc.range;
+ function d3_time_scale(linear, methods, format) {
+ function scale(x) {
+ return linear(x);
+ }
+ scale.invert = function(x) {
+ return d3_time_scaleDate(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
+ linear.domain(x);
+ return scale;
+ };
+ scale.nice = function(m) {
+ return scale.domain(d3_scale_nice(scale.domain(), function() {
+ return m;
+ }));
+ };
+ scale.ticks = function(m, k) {
+ var extent = d3_time_scaleExtent(scale.domain());
+ if (typeof m !== "function") {
+ var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target);
+ if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
+ if (!i) return linear.ticks(m).map(d3_time_scaleDate);
+ if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
+ m = methods[i];
+ k = m[1];
+ m = m[0].range;
+ }
+ return m(extent[0], new Date(+extent[1] + 1), k);
+ };
+ scale.tickFormat = function() {
+ return format;
+ };
+ scale.copy = function() {
+ return d3_time_scale(linear.copy(), methods, format);
+ };
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ }
+ function d3_time_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_time_scaleDate(t) {
+ return new Date(t);
+ }
+ function d3_time_scaleFormat(formats) {
+ return function(date) {
+ var i = formats.length - 1, f = formats[i];
+ while (!f[1](date)) f = formats[--i];
+ return f[0](date);
+ };
+ }
+ function d3_time_scaleSetYear(y) {
+ var d = new Date(y, 0, 1);
+ d.setFullYear(y);
+ return d;
+ }
+ function d3_time_scaleGetYear(d) {
+ var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1);
+ return y + (d - d0) / (d1 - d0);
+ }
+ var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
+ var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ];
+ var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) {
+ return d.getMonth();
+ } ], [ d3.time.format("%b %d"), function(d) {
+ return d.getDate() != 1;
+ } ], [ d3.time.format("%a %d"), function(d) {
+ return d.getDay() && d.getDate() != 1;
+ } ], [ d3.time.format("%I %p"), function(d) {
+ return d.getHours();
+ } ], [ d3.time.format("%I:%M"), function(d) {
+ return d.getMinutes();
+ } ], [ d3.time.format(":%S"), function(d) {
+ return d.getSeconds();
+ } ], [ d3.time.format(".%L"), function(d) {
+ return d.getMilliseconds();
+ } ] ];
+ var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
+ d3_time_scaleLocalMethods.year = function(extent, m) {
+ return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);
+ };
+ d3.time.scale = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
+ };
+ var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
+ return [ m[0].utc, m[1] ];
+ });
+ var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) {
+ return d.getUTCMonth();
+ } ], [ d3.time.format.utc("%b %d"), function(d) {
+ return d.getUTCDate() != 1;
+ } ], [ d3.time.format.utc("%a %d"), function(d) {
+ return d.getUTCDay() && d.getUTCDate() != 1;
+ } ], [ d3.time.format.utc("%I %p"), function(d) {
+ return d.getUTCHours();
+ } ], [ d3.time.format.utc("%I:%M"), function(d) {
+ return d.getUTCMinutes();
+ } ], [ d3.time.format.utc(":%S"), function(d) {
+ return d.getUTCSeconds();
+ } ], [ d3.time.format.utc(".%L"), function(d) {
+ return d.getUTCMilliseconds();
+ } ] ];
+ var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
+ function d3_time_scaleUTCSetYear(y) {
+ var d = new Date(Date.UTC(y, 0, 1));
+ d.setUTCFullYear(y);
+ return d;
+ }
+ function d3_time_scaleUTCGetYear(d) {
+ var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1);
+ return y + (d - d0) / (d1 - d0);
+ }
+ d3_time_scaleUTCMethods.year = function(extent, m) {
+ return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);
+ };
+ d3.time.scale.utc = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
+ };
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd
new file mode 100644
index 00000000..53b2e068
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png
new file mode 100644
index 00000000..881de797
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png
new file mode 100644
index 00000000..c608682b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png
new file mode 100644
index 00000000..d300f106
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico
new file mode 100644
index 00000000..6eeaa2a0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png
new file mode 100644
index 00000000..6a6ded7d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png
new file mode 100644
index 00000000..a4e6b538
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png
new file mode 100644
index 00000000..fc46c5eb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png
new file mode 100644
index 00000000..a88d7975
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png
new file mode 100644
index 00000000..4e144cf0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png
new file mode 100644
index 00000000..18670406
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png
new file mode 100644
index 00000000..def071ed
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png
new file mode 100644
index 00000000..7824973c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css
new file mode 100644
index 00000000..1e55b3e2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css
@@ -0,0 +1,217 @@
+/**
+ * Copied from http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css
+ * and adopted in order to work only with .srf-datatables
+ */
+
+/* Table*/
+
+.srf-datatables .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.srf-datatables .bordered-table th+th,.srf-datatables .bordered-table td+td,.srf-datatables .bordered-table th+td{border-left:1px solid #ddd;}
+.srf-datatables .bordered-table thead tr:first-child th:first-child,.srf-datatables .bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.srf-datatables .bordered-table thead tr:first-child th:last-child,.srf-datatables .bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.srf-datatables .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.srf-datatables .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+
+.srf-datatables table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}
+.srf-datatables table th,.srf-datatables table td{padding:10px 10px 9px;line-height:18px;text-align:left;}
+.srf-datatables table th{padding-top:9px;font-weight:bold;vertical-align:middle;}
+.srf-datatables table td{vertical-align:top;border-top:1px solid #ddd;}
+.srf-datatables table tbody th{border-top:1px solid #ddd;vertical-align:top;}
+.srf-datatables .condensed-table th,.srf-datatables .condensed-table td{padding:5px 5px 4px;}
+.srf-datatables .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;}
+.srf-datatables .bordered-table thead tr:first-child th:first-child,.srf-datatables .bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.srf-datatables .bordered-table thead tr:first-child th:last-child,.srf-datatables .bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.srf-datatables .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.srf-datatables .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+
+.srf-datatables .zebra-striped tbody tr:nth-child(odd) td,.srf-datatables .zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
+.srf-datatables .zebra-striped tbody tr:hover td,.srf-datatables .zebra-striped tbody tr:hover th{background-color:#f5f5f5;}
+.srf-datatables table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;}
+.srf-datatables table .headerSortUp,.srf-datatables table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);}
+.srf-datatables table .header:hover:after{visibility:visible;}
+.srf-datatables table .headerSortDown:after,.srf-datatables table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+.srf-datatables table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+.srf-datatables table .blue{color:#049cdb;border-bottom-color:#049cdb;}
+.srf-datatables table .headerSortUp.blue,.srf-datatables table .headerSortDown.blue{background-color:#ade6fe;}
+.srf-datatables table .green{color:#46a546;border-bottom-color:#46a546;}
+.srf-datatables table .headerSortUp.green,.srf-datatables table .headerSortDown.green{background-color:#cdeacd;}
+.srf-datatables table .red{color:#9d261d;border-bottom-color:#9d261d;}
+.srf-datatables table .headerSortUp.red,.srf-datatables table .headerSortDown.red{background-color:#f4c8c5;}
+.srf-datatables table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;}
+.srf-datatables table .headerSortUp.yellow,.srf-datatables table .headerSortDown.yellow{background-color:#fff6d9;}
+.srf-datatables table .orange{color:#f89406;border-bottom-color:#f89406;}
+.srf-datatables table .headerSortUp.orange,.srf-datatables table .headerSortDown.orange{background-color:#fee9cc;}
+.srf-datatables table .purple{color:#7a43b6;border-bottom-color:#7a43b6;}
+.srf-datatables table .headerSortUp.purple,.srf-datatables table .headerSortDown.purple{background-color:#e2d5f0;}
+
+/* Input */
+
+.srf-datatables button,.srf-datatables input,.srf-datatables select,.srf-datatables textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;}
+.srf-datatables button,.srf-datatables input{line-height:normal;*overflow:visible;}
+.srf-datatables button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
+.srf-datatables button,.srf-datatables input[type="button"],.srf-datatables input[type="reset"],.srf-datatables input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
+.srf-datatables input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
+.srf-datatables input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
+
+.srf-datatables input[type=checkbox],input[type=radio]{cursor:pointer;}
+.srf-datatables input,.srf-datatables textarea,.srf-datatables select,.srf-datatables .uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.srf-datatables select{padding:initial;}
+.srf-datatables input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;}
+.srf-datatables input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.srf-datatables input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;}
+.srf-datatables select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;}
+.srf-datatables select[multiple]{height:inherit;background-color:#ffffff;}
+.srf-datatables textarea{height:auto;}
+.srf-datatables .uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+.srf-datatables :-moz-placeholder{color:#bfbfbf;}
+.srf-datatables ::-webkit-input-placeholder{color:#bfbfbf;}
+.srf-datatables input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);}
+.srf-datatables input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);}
+.srf-datatables input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;}
+
+.srf-datatables .input-mini,.srf-datatables input.mini,textarea.mini,.srf-datatables select.mini{width:60px;}
+.srf-datatables .input-small,.srf-datatables input.small,textarea.small,.srf-datatables select.small{width:90px;}
+.srf-datatables .input-medium,.srf-datatables input.medium,textarea.medium,.srf-datatables select.medium{width:150px;}
+.srf-datatables .input-large,.srf-datatables input.large,textarea.large,.srf-datatables select.large{width:210px;}
+.srf-datatables .input-xlarge,.srf-datatables input.xlarge,textarea.xlarge,.srf-datatables select.xlarge{width:270px;}
+.srf-datatables .input-xxlarge,.srf-datatables input.xxlarge,textarea.xxlarge,.srf-datatables select.xxlarge{width:530px;}
+.srf-datatables textarea.xxlarge{overflow-y:auto;}
+.srf-datatables input.span1,.srf-datatables textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;}
+.srf-datatables input.span2,.srf-datatables textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;}
+
+.srf-datatables input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
+
+.srf-datatables .inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;}
+.srf-datatables .input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.srf-datatables .input-prepend .add-on,.srf-datatables .input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.srf-datatables .input-prepend .active,.srf-datatables .input-append .active{background:#a9dba9;border-color:#46a546;}
+.srf-datatables .input-prepend .add-on{*margin-top:1px;}
+.srf-datatables .input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.srf-datatables .input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;}
+.srf-datatables .inputs-list{margin:0 0 5px;width:100%;}
+.srf-datatables .inputs-list li{display:block;padding:0;width:100%;}
+.srf-datatables .inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}
+.srf-datatables .inputs-list label strong{color:#808080;}
+.srf-datatables .inputs-list label small{font-size:11px;font-weight:normal;}
+.srf-datatables .inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;}
+.srf-datatables .inputs-list:first-child{padding-top:6px;}
+.srf-datatables .inputs-list li+li{padding-top:2px;}
+.srf-datatables .inputs-list input[type=radio],.srf-datatables .inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;}
+
+.srf-datatables .row{zoom:1;margin-left:-20px;}.srf-datatables .row:before,.srf-datatables .row:after{display:table;content:"";zoom:1;}
+.srf-datatables .row:after{clear:both;}
+.srf-datatables .row>[class*="span"]{display:inline;margin-left:20px;}
+
+/* pagination */
+
+.srf-datatables .pagination{height:36px;margin:18px 0;}.srf-datatables .pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.srf-datatables .pagination li{display:inline;}
+.srf-datatables .pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;}
+.srf-datatables .pagination a:hover,.srf-datatables .pagination .active a{background-color:#c7eefe;}
+.srf-datatables .pagination .disabled a,.srf-datatables .pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;}
+.srf-datatables .pagination .next a{border:0;}
+
+/* DataTables */
+.srf-datatables .span-search,.srf-datatables .span-page{ float: right; }
+.srf-datatables .span-select,.srf-datatables .span-list{ float: left; }
+
+.srf-datatables .dataTables_length label {
+ float: left;
+ text-align: left;
+}
+
+.srf-datatables .dataTables_length select {
+ width: 75px;
+}
+
+.srf-datatables .dataTables_filter label {
+ float: right;
+}
+
+.srf-datatables .dataTables_info {
+ padding-top: 8px;
+}
+
+.srf-datatables .dataTables_paginate {
+ float: right;
+ margin: 0;
+}
+
+.srf-datatables table {
+ margin: 1em 0;
+ clear: both;
+}
+
+.srf-datatables table.dataTable th:active {
+ outline: none;
+}
+
+.srf-datatables .ui-button-primary {
+color: white;
+background-image: none;
+background-color: #0064CD;
+background-repeat: repeat-x;
+background-image: -webkit-linear-gradient(top, #049CDB, #0064CD);
+background-image: -moz-linear-gradient(top, #049CDB, #0064CD);
+background-image: -o-linear-gradient(top, #049CDB, #0064CD);
+background-image: linear-gradient(top, #049CDB, #0064CD);
+filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#049CDB', endColorstr='#0064CD', GradientType=0);
+text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+border-color: #0064CD #0064CD #003F81;
+border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+}
+
+.srf-datatables .ui-button{
+ margin: 0 0 0 0;
+ cursor: pointer;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ color: #333;
+ font-size: 13px;
+ line-height: normal;
+ cursor: pointer;
+ display: inline-block;
+
+ background-color: #E6E6E6;
+ background-repeat: no-repeat;
+ background-image: -webkit-linear-gradient(white, white 25%, #E6E6E6) !important;
+ background-image: -moz-linear-gradient(top, white, white 25%, #E6E6E6) !important;
+ background-image: -o-linear-gradient(white, white 25%, #E6E6E6) !important;
+ background-image: linear-gradient(white, white 25%, #E6E6E6) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='white', endColorstr='#E6E6E6', GradientType=0);
+ padding: 5px 14px 6px;
+ margin: 0;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ color: #333;
+ font-size: 13px;
+ line-height: normal;
+ border: 1px solid #CCC !important;
+ border-bottom-color: #BBB;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -webkit-transition: 0.1s linear background-image;
+ -moz-transition: 0.1s linear background-image;
+ -o-transition: 0.1s linear background-image;
+ transition: 0.1s linear background-image;
+ overflow: visible;
+}
+
+.srf-datatables .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
+-webkit-border-bottom-right-radius: 4px;
+-moz-border-radius-bottomright: 4px;
+border-bottom-right-radius: 4px;
+}
+
+.srf-datatables .ui-corner-top, .ui-corner-right, .ui-corner-tr {
+-webkit-border-top-right-radius: 4px;
+-moz-border-radius-topright: 4px;
+border-top-right-radius: 4px;
+}
+
+/* Word wrap a link so it doesn't overflow */
+.srf-datatables table td, .srf-datatables table th {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js
new file mode 100644
index 00000000..3a738f97
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js
@@ -0,0 +1,116 @@
+/**
+ * DataTables extras
+ *
+ * @see http://datatables.net/extras/
+ *
+ * @since 1.9
+ */
+( function( $ ) {
+ 'use strict';
+
+// https://github.com/SemanticMediaWiki/SemanticResultFormats/issues/185
+$.fn.dataTableExt = $.fn.dataTableExt || {};
+$.fn.dataTableExt.oStdClasses = $.fn.dataTableExt.oStdClasses || {};
+$.fn.dataTableExt.oApi = $.fn.dataTableExt.oApi || {
+ 'fnPagingInfo': function() {}
+};
+$.fn.dataTableExt.oPagination = $.fn.dataTableExt.oPagination || {};
+
+$.extend( $.fn.dataTableExt.oStdClasses, {
+ 'sSortAsc': 'header headerSortDown',
+ 'sSortDesc': 'header headerSortUp',
+ 'sWrapper': 'dataTables_wrapper form-inline',
+ 'sSortable': 'header'
+} );
+
+/* API method to get paging information */
+$.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings ){
+return {
+ 'iStart': oSettings._iDisplayStart,
+ 'iEnd': oSettings.fnDisplayEnd(),
+ 'iLength': oSettings._iDisplayLength,
+ 'iTotal': oSettings.fnRecordsTotal(),
+ 'iFilteredTotal': oSettings.fnRecordsDisplay(),
+ 'iPage': Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
+ 'iTotalPages': Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
+ };
+};
+
+/* Bootstrap style pagination control */
+$.extend( $.fn.dataTableExt.oPagination, {
+ 'bootstrap': {
+ fnInit: function( oSettings, nPaging, fnDraw ) {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var fnClickHandler = function ( e ) {
+ e.preventDefault();
+ if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
+ fnDraw( oSettings );
+ }
+ };
+
+ $(nPaging).addClass('pagination').append(
+ '<ul>'+
+ '<li class="prev disabled"><a href="#">&larr; '+oLang.sPrevious+'</a></li>'+
+ '<li class="next disabled"><a href="#">'+oLang.sNext+' &rarr; </a></li>'+
+ '</ul>'
+ );
+ var els = $('a', nPaging);
+ $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
+ $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
+ },
+
+ fnUpdate: function ( oSettings, fnDraw ) {
+ var iListLength = 5;
+ var oPaging = oSettings.oInstance.fnPagingInfo();
+ var an = oSettings.aanFeatures.p;
+ var i, j, iLen, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
+
+ if ( oPaging.iTotalPages < iListLength) {
+ iStart = 1;
+ iEnd = oPaging.iTotalPages;
+ }
+ else if ( oPaging.iPage <= iHalf ) {
+ iStart = 1;
+ iEnd = iListLength;
+ } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
+ iStart = oPaging.iTotalPages - iListLength + 1;
+ iEnd = oPaging.iTotalPages;
+ } else {
+ iStart = oPaging.iPage - iHalf + 1;
+ iEnd = iStart + iListLength - 1;
+ }
+
+ for ( i=0, iLen=an.length ; i<iLen ; i++ ) {
+ // Remove the middle elements
+ $('li:gt(0)', an[i]).filter(':not(:last)').remove();
+
+ // Add the new list items and their event handlers
+ for ( j=iStart ; j<=iEnd ; j++ ) {
+ sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
+ $('<li '+sClass+'><a href="#">'+j+'</a></li>')
+ .insertBefore( $('li:last', an[i])[0] )
+ .bind('click', function (e) {
+ e.preventDefault();
+ oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
+ fnDraw( oSettings );
+ } );
+ }
+
+ // Add / remove disabled classes from the static elements
+ if ( oPaging.iPage === 0 ) {
+ $('li:first', an[i]).addClass('disabled');
+ } else {
+ $('li:first', an[i]).removeClass('disabled');
+ }
+
+ if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
+ $('li:last', an[i]).addClass('disabled');
+ } else {
+ $('li:last', an[i]).removeClass('disabled');
+ }
+ }
+ }
+ }
+} );
+
+} )( jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css
new file mode 100644
index 00000000..7da7faec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css
@@ -0,0 +1,221 @@
+
+/*
+ * Table
+ */
+table.dataTable {
+ margin: 0 auto;
+ clear: both;
+ width: 100%;
+}
+
+table.dataTable thead th {
+ padding: 3px 18px 3px 10px;
+ border-bottom: 1px solid black;
+ font-weight: bold;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+table.dataTable tfoot th {
+ padding: 3px 18px 3px 10px;
+ border-top: 1px solid black;
+ font-weight: bold;
+}
+
+table.dataTable td {
+ padding: 3px 10px;
+}
+
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+
+table.dataTable tr.odd { background-color: #E2E4FF; }
+table.dataTable tr.even { background-color: white; }
+
+table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
+table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
+table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
+table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
+table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
+table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
+
+
+/*
+ * Table wrapper
+ */
+.dataTables_wrapper {
+ position: relative;
+ clear: both;
+ *zoom: 1;
+}
+
+
+/*
+ * Page length menu
+ */
+.dataTables_length {
+ float: left;
+}
+
+
+/*
+ * Filter
+ */
+.dataTables_filter {
+ float: right;
+ text-align: right;
+}
+
+
+/*
+ * Table information
+ */
+.dataTables_info {
+ clear: both;
+ float: left;
+}
+
+
+/*
+ * Pagination
+ */
+.dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+
+/* Two button pagination - previous / next */
+.paginate_disabled_previous,
+.paginate_enabled_previous,
+.paginate_disabled_next,
+.paginate_enabled_next {
+ height: 19px;
+ float: left;
+ cursor: pointer;
+ *cursor: hand;
+ color: #111 !important;
+}
+.paginate_disabled_previous:hover,
+.paginate_enabled_previous:hover,
+.paginate_disabled_next:hover,
+.paginate_enabled_next:hover {
+ text-decoration: none !important;
+}
+.paginate_disabled_previous:active,
+.paginate_enabled_previous:active,
+.paginate_disabled_next:active,
+.paginate_enabled_next:active {
+ outline: none;
+}
+
+.paginate_disabled_previous,
+.paginate_disabled_next {
+ color: #666 !important;
+}
+.paginate_disabled_previous,
+.paginate_enabled_previous {
+ padding-left: 23px;
+}
+.paginate_disabled_next,
+.paginate_enabled_next {
+ padding-right: 23px;
+ margin-left: 10px;
+}
+
+.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
+
+/* Full number pagination */
+.paging_full_numbers {
+ height: 22px;
+ line-height: 22px;
+}
+.paging_full_numbers a:active {
+ outline: none
+}
+.paging_full_numbers a:hover {
+ text-decoration: none;
+}
+
+.paging_full_numbers a.paginate_button,
+.paging_full_numbers a.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+ color: #333 !important;
+}
+
+.paging_full_numbers a.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers a.paginate_button:hover {
+ background-color: #ccc;
+ text-decoration: none !important;
+}
+
+.paging_full_numbers a.paginate_active {
+ background-color: #99B3FF;
+}
+
+
+/*
+ * Processing indicator
+ */
+.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 250px;
+ height: 30px;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px 0;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 14px;
+ background-color: white;
+}
+
+
+/*
+ * Sorting
+ */
+.sorting { background: url('../images/sort_both.png') no-repeat center right; }
+.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; }
+.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; }
+
+.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; }
+.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; }
+
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+ outline: none;
+}
+
+
+/*
+ * Scrolling
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.dataTables_scrollBody {
+ *margin-top: -1px;
+ -webkit-overflow-scrolling: touch;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js
new file mode 100644
index 00000000..1a832d60
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js
@@ -0,0 +1,91 @@
+/**
+ * DataTables extras
+ *
+ * @see http://datatables.net/
+ *
+ * @since 1.9
+ */
+( function( $ ) {
+ 'use strict';
+
+// https://github.com/SemanticMediaWiki/SemanticResultFormats/issues/185
+$.fn.dataTableExt = $.fn.dataTableExt || {};
+$.fn.dataTableExt.oSort = $.fn.dataTableExt.oSort || {};
+$.fn.dataTableExt.aTypes = $.fn.dataTableExt.aTypes || {
+ 'unshift': function() {}
+};
+
+// Sorting Currency Columns
+$.extend( $.fn.dataTableExt.aTypes, {
+ 'unshift': function ( sData ) {
+ var sValidChars = "0123456789.-,";
+ var Char;
+
+ if( typeof sData === "object" ) {
+ /* Check the numeric part */
+ for ( var i=1 ; i < sData.length ; i++ ) {
+ Char = sData.charAt(i);
+ if (sValidChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+ }
+
+ /* Check prefixed by currency */
+ if ( sData.charAt(0) == '$' || sData.charAt(0) == '£' ) {
+ return 'currency';
+ }
+ return null;
+ }
+ }
+} );
+
+$.fn.dataTableExt.oSort['currency-asc'] = function(a,b) {
+ /* Remove any formatting */
+ var x = a == "-" ? 0 : a.replace( /[^\d\-\.]/g, "" );
+ var y = b == "-" ? 0 : b.replace( /[^\d\-\.]/g, "" );
+
+ /* Parse and return */
+ x = parseFloat( x );
+ y = parseFloat( y );
+ return x - y;
+};
+
+$.fn.dataTableExt.oSort['currency-desc'] = function(a,b) {
+ var x = a === '-' ? 0 : a.replace( /[^\d\-\.]/g, '' );
+ var y = b === '-' ? 0 : b.replace( /[^\d\-\.]/g, '' );
+
+ x = parseFloat( x );
+ y = parseFloat( y );
+ return y - x;
+};
+
+// Sorting Formatted Numbers
+$.fn.dataTableExt.aTypes.unshift(
+ function ( sData ) {
+ if( sData !== undefined && $.isNumeric( sData ) ) {
+ // var deformatted = sData.replace(/[^\d\-\.\/a-zA-Z]/g,'');
+ //if ( $.isNumeric( deformatted ) ) {
+ return 'formatted-num';
+ }
+ return null;
+ }
+);
+
+$.fn.dataTableExt.oSort['formatted-num-asc'] = function(a,b) {
+ /* Remove any formatting */
+ var x = a.match(/\d/) ? a.replace( /[^\d\-\.]/g, "" ) : 0;
+ var y = b.match(/\d/) ? b.replace( /[^\d\-\.]/g, "" ) : 0;
+
+ /* Parse and return */
+ return parseFloat(x) - parseFloat(y);
+};
+
+$.fn.dataTableExt.oSort['formatted-num-desc'] = function(a,b) {
+ var x = a.match(/\d/) ? a.replace( /[^\d\-\.]/g, "" ) : 0;
+ var y = b.match(/\d/) ? b.replace( /[^\d\-\.]/g, "" ) : 0;
+
+ return parseFloat(y) - parseFloat(x);
+};
+
+} )( jQuery ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css
new file mode 100644
index 00000000..0a0ec9fa
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css
@@ -0,0 +1,29 @@
+/**
+ * CSS dataTables adopt for the MW ResourceLoader environment
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+.paginate_enabled_previous { /* @embed */ background: url('images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { /* @embed */ background: url('images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { /* @embed */ background: url('images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { /* @embed */ background: url('images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { /* @embed */ background: url('images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { /* @embed */ background: url('images/forward_disabled.png') no-repeat top right; }
+
+/*
+ * Sorting
+ */
+.sorting { /* @embed */ background: url('images/sort_both.png') no-repeat center right; }
+.sorting_asc { /* @embed */ background: url('images/sort_asc.png') no-repeat center right; }
+.sorting_desc { /* @embed */ background: url('images/sort_desc.png') no-repeat center right; }
+
+.sorting_asc_disabled { /* @embed */ background: url('images/sort_asc_disabled.png') no-repeat center right; }
+.sorting_desc_disabled { /* @embed */ background: url('images/sort_desc_disabled.png') no-repeat center right; }
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js
new file mode 100644
index 00000000..1d8a220b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js
@@ -0,0 +1,12099 @@
+/**
+ * @summary DataTables
+ * @description Paginate, search and sort HTML tables
+ * @version 1.9.4
+ * @file jquery.dataTables.js
+ * @author Allan Jardine (www.sprymedia.co.uk)
+ * @contact www.sprymedia.co.uk/contact
+ *
+ * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, available at:
+ * http://datatables.net/license_gpl2
+ * http://datatables.net/license_bsd
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
+
+(/** @lends <global> */function( window, document, undefined ) {
+
+(function( factory ) {
+ "use strict";
+
+ // Define as an AMD module if possible
+ if ( typeof define === 'function' && define.amd )
+ {
+ define( ['jquery'], factory );
+ }
+ /* Define using browser globals otherwise
+ * Prevent multiple instantiations if the script is loaded twice
+ */
+ else if ( jQuery && !jQuery.fn.dataTable )
+ {
+ factory( jQuery );
+ }
+}
+(/** @lends <global> */function( $ ) {
+ "use strict";
+ /**
+ * DataTables is a plug-in for the jQuery Javascript library. It is a
+ * highly flexible tool, based upon the foundations of progressive
+ * enhancement, which will add advanced interaction controls to any
+ * HTML table. For a full list of features please refer to
+ * <a href="http://datatables.net">DataTables.net</a>.
+ *
+ * Note that the <i>DataTable</i> object is not a global variable but is
+ * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which
+ * it may be accessed.
+ *
+ * @class
+ * @param {object} [oInit={}] Configuration object for DataTables. Options
+ * are defined by {@link DataTable.defaults}
+ * @requires jQuery 1.3+
+ *
+ * @example
+ * // Basic initialisation
+ * $(document).ready( function {
+ * $('#example').dataTable();
+ * } );
+ *
+ * @example
+ * // Initialisation with configuration options - in this case, disable
+ * // pagination and sorting.
+ * $(document).ready( function {
+ * $('#example').dataTable( {
+ * "bPaginate": false,
+ * "bSort": false
+ * } );
+ * } );
+ */
+ var DataTable = function( oInit )
+ {
+
+
+ /**
+ * Add a column to the list used for the table with default values
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nTh The th element for this column
+ * @memberof DataTable#oApi
+ */
+ function _fnAddColumn( oSettings, nTh )
+ {
+ var oDefaults = DataTable.defaults.columns;
+ var iCol = oSettings.aoColumns.length;
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
+ "sSortingClass": oSettings.oClasses.sSortable,
+ "sSortingClassJUI": oSettings.oClasses.sSortJUI,
+ "nTh": nTh ? nTh : document.createElement('th'),
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
+ "mData": oDefaults.mData ? oDefaults.oDefaults : iCol
+ } );
+ oSettings.aoColumns.push( oCol );
+
+ /* Add a column specific filter */
+ if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
+ {
+ oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
+ }
+ else
+ {
+ var oPre = oSettings.aoPreSearchCols[ iCol ];
+
+ /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
+ if ( oPre.bRegex === undefined )
+ {
+ oPre.bRegex = true;
+ }
+
+ if ( oPre.bSmart === undefined )
+ {
+ oPre.bSmart = true;
+ }
+
+ if ( oPre.bCaseInsensitive === undefined )
+ {
+ oPre.bCaseInsensitive = true;
+ }
+ }
+
+ /* Use the column options function to initialise classes etc */
+ _fnColumnOptions( oSettings, iCol, null );
+ }
+
+
+ /**
+ * Apply options for a column
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column index to consider
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnOptions( oSettings, iCol, oOptions )
+ {
+ var oCol = oSettings.aoColumns[ iCol ];
+
+ /* User specified column options */
+ if ( oOptions !== undefined && oOptions !== null )
+ {
+ /* Backwards compatibility for mDataProp */
+ if ( oOptions.mDataProp && !oOptions.mData )
+ {
+ oOptions.mData = oOptions.mDataProp;
+ }
+
+ if ( oOptions.sType !== undefined )
+ {
+ oCol.sType = oOptions.sType;
+ oCol._bAutoType = false;
+ }
+
+ $.extend( oCol, oOptions );
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
+ * priority if defined
+ */
+ if ( oOptions.iDataSort !== undefined )
+ {
+ oCol.aDataSort = [ oOptions.iDataSort ];
+ }
+ _fnMap( oCol, oOptions, "aDataSort" );
+ }
+
+ /* Cache the data get and set functions for speed */
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+ var mData = _fnGetObjectDataFn( oCol.mData );
+
+ oCol.fnGetData = function (oData, sSpecific) {
+ var innerData = mData( oData, sSpecific );
+
+ if ( oCol.mRender && (sSpecific && sSpecific !== '') )
+ {
+ return mRender( innerData, sSpecific, oData );
+ }
+ return innerData;
+ };
+ oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
+
+ /* Feature sorting overrides column specific when off */
+ if ( !oSettings.oFeatures.bSort )
+ {
+ oCol.bSortable = false;
+ }
+
+ /* Check that the class assignment is correct for sorting */
+ if ( !oCol.bSortable ||
+ ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableNone;
+ oCol.sSortingClassJUI = "";
+ }
+ else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortable;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
+ }
+ else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
+ }
+ else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
+ }
+ }
+
+
+ /**
+ * Adjust the table column widths for new data. Note: you would probably want to
+ * do a redraw after calling this function!
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAdjustColumnSizing ( oSettings )
+ {
+ /* Not interested in doing column width calculation if auto-width is disabled */
+ if ( oSettings.oFeatures.bAutoWidth === false )
+ {
+ return false;
+ }
+
+ _fnCalculateColumnWidths( oSettings );
+ for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
+ }
+ }
+
+
+ /**
+ * Covert the index of a visible column to the index in the data array (take account
+ * of hidden columns)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iMatch Visible column index to lookup
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+
+ return typeof aiVis[iMatch] === 'number' ?
+ aiVis[iMatch] :
+ null;
+ }
+
+
+ /**
+ * Covert the index of an index in the data array and convert it to the visible
+ * column index (take account of hidden columns)
+ * @param {int} iMatch Column index to lookup
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnIndexToVisible( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+ var iPos = $.inArray( iMatch, aiVis );
+
+ return iPos !== -1 ? iPos : null;
+ }
+
+
+ /**
+ * Get the number of visible columns
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the number of visible columns
+ * @memberof DataTable#oApi
+ */
+ function _fnVisbleColumns( oSettings )
+ {
+ return _fnGetColumns( oSettings, 'bVisible' ).length;
+ }
+
+
+ /**
+ * Get an array of column indexes that match a given property
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sParam Parameter in aoColumns to look for - typically
+ * bVisible or bSearchable
+ * @returns {array} Array of indexes with matched properties
+ * @memberof DataTable#oApi
+ */
+ function _fnGetColumns( oSettings, sParam )
+ {
+ var a = [];
+
+ $.map( oSettings.aoColumns, function(val, i) {
+ if ( val[sParam] ) {
+ a.push( i );
+ }
+ } );
+
+ return a;
+ }
+
+
+ /**
+ * Get the sort type based on an input string
+ * @param {string} sData data we wish to know the type of
+ * @returns {string} type (defaults to 'string' if no type can be detected)
+ * @memberof DataTable#oApi
+ */
+ function _fnDetectType( sData )
+ {
+ var aTypes = DataTable.ext.aTypes;
+ var iLen = aTypes.length;
+
+ for ( var i=0 ; i<iLen ; i++ )
+ {
+ var sType = aTypes[i]( sData );
+ if ( sType !== null )
+ {
+ return sType;
+ }
+ }
+
+ return 'string';
+ }
+
+
+ /**
+ * Figure out how to reorder a display list
+ * @param {object} oSettings dataTables settings object
+ * @returns array {int} aiReturn index list for reordering
+ * @memberof DataTable#oApi
+ */
+ function _fnReOrderIndex ( oSettings, sColumns )
+ {
+ var aColumns = sColumns.split(',');
+ var aiReturn = [];
+
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ for ( var j=0 ; j<iLen ; j++ )
+ {
+ if ( oSettings.aoColumns[i].sName == aColumns[j] )
+ {
+ aiReturn.push( j );
+ break;
+ }
+ }
+ }
+
+ return aiReturn;
+ }
+
+
+ /**
+ * Get the column ordering that DataTables expects
+ * @param {object} oSettings dataTables settings object
+ * @returns {string} comma separated list of names
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnOrdering ( oSettings )
+ {
+ var sNames = '';
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ sNames += oSettings.aoColumns[i].sName+',';
+ }
+ if ( sNames.length == iLen )
+ {
+ return "";
+ }
+ return sNames.slice(0, -1);
+ }
+
+
+ /**
+ * Take the column definitions and static columns arrays and calculate how
+ * they relate to column indexes. The callback function will then apply the
+ * definition found for a column to a suitable configuration object.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
+ * @param {array} aoCols The aoColumns array that defines columns individually
+ * @param {function} fn Callback function - takes two parameters, the calculated
+ * column index and the definition for that column.
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+ {
+ var i, iLen, j, jLen, k, kLen;
+
+ // Column definitions with aTargets
+ if ( aoColDefs )
+ {
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
+ {
+ /* Each definition can target multiple columns, as it is an array */
+ var aTargets = aoColDefs[i].aTargets;
+ if ( !$.isArray( aTargets ) )
+ {
+ _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
+ }
+
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+ {
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+ {
+ /* Add columns that we don't yet know about */
+ while( oSettings.aoColumns.length <= aTargets[j] )
+ {
+ _fnAddColumn( oSettings );
+ }
+
+ /* Integer, basic index */
+ fn( aTargets[j], aoColDefs[i] );
+ }
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+ {
+ /* Negative integer, right to left column counting */
+ fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
+ }
+ else if ( typeof aTargets[j] === 'string' )
+ {
+ /* Class name matching on TH element */
+ for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
+ {
+ if ( aTargets[j] == "_all" ||
+ $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
+ {
+ fn( k, aoColDefs[i] );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Statically defined columns array
+ if ( aoCols )
+ {
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
+ {
+ fn( i, aoCols[i] );
+ }
+ }
+ }
+
+ /**
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
+ * DOM source.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aData data array to be added
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
+ * @memberof DataTable#oApi
+ */
+ function _fnAddData ( oSettings, aDataSupplied )
+ {
+ var oCol;
+
+ /* Take an independent copy of the data source so we can bash it about as we wish */
+ var aDataIn = ($.isArray(aDataSupplied)) ?
+ aDataSupplied.slice() :
+ $.extend( true, {}, aDataSupplied );
+
+ /* Create the object for storing information about this new row */
+ var iRow = oSettings.aoData.length;
+ var oData = $.extend( true, {}, DataTable.models.oRow );
+ oData._aData = aDataIn;
+ oSettings.aoData.push( oData );
+
+ /* Create the cells */
+ var nTd, sThisType;
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oCol = oSettings.aoColumns[i];
+
+ /* Use rendered data for filtering / sorting */
+ if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
+ {
+ _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
+ }
+ else
+ {
+ _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
+ }
+
+ /* See if we should auto-detect the column type */
+ if ( oCol._bAutoType && oCol.sType != 'string' )
+ {
+ /* Attempt to auto detect the type - same as _fnGatherData() */
+ var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
+ if ( sVarType !== null && sVarType !== '' )
+ {
+ sThisType = _fnDetectType( sVarType );
+ if ( oCol.sType === null )
+ {
+ oCol.sType = sThisType;
+ }
+ else if ( oCol.sType != sThisType && oCol.sType != "html" )
+ {
+ /* String is always the 'fallback' option */
+ oCol.sType = 'string';
+ }
+ }
+ }
+ }
+
+ /* Add to the display array */
+ oSettings.aiDisplayMaster.push( iRow );
+
+ /* Create the DOM information */
+ if ( !oSettings.oFeatures.bDeferRender )
+ {
+ _fnCreateTr( oSettings, iRow );
+ }
+
+ return iRow;
+ }
+
+
+ /**
+ * Read in the data from the target table from the DOM
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnGatherData( oSettings )
+ {
+ var iLoop, i, iLen, j, jLen, jInner,
+ nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
+ iRow, iRows, iColumn, iColumns, sNodeName,
+ oCol, oData;
+
+ /*
+ * Process by row first
+ * Add the data object for the whole table - storing the tr node. Note - no point in getting
+ * DOM based data if we are going to go and replace it with Ajax source data.
+ */
+ if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
+ {
+ nTr = oSettings.nTBody.firstChild;
+ while ( nTr )
+ {
+ if ( nTr.nodeName.toUpperCase() == "TR" )
+ {
+ iThisIndex = oSettings.aoData.length;
+ nTr._DT_RowIndex = iThisIndex;
+ oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
+ "nTr": nTr
+ } ) );
+
+ oSettings.aiDisplayMaster.push( iThisIndex );
+ nTd = nTr.firstChild;
+ jInner = 0;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toUpperCase();
+ if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
+ jInner++;
+ }
+ nTd = nTd.nextSibling;
+ }
+ }
+ nTr = nTr.nextSibling;
+ }
+ }
+
+ /* Gather in the TD elements of the Table - note that this is basically the same as
+ * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
+ * setup!
+ */
+ nTrs = _fnGetTrNodes( oSettings );
+ nTds = [];
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ nTd = nTrs[i].firstChild;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toUpperCase();
+ if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ nTds.push( nTd );
+ }
+ nTd = nTd.nextSibling;
+ }
+ }
+
+ /* Now process by column */
+ for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+ {
+ oCol = oSettings.aoColumns[iColumn];
+
+ /* Get the title of the column - unless there is a user set one */
+ if ( oCol.sTitle === null )
+ {
+ oCol.sTitle = oCol.nTh.innerHTML;
+ }
+
+ var
+ bAutoType = oCol._bAutoType,
+ bRender = typeof oCol.fnRender === 'function',
+ bClass = oCol.sClass !== null,
+ bVisible = oCol.bVisible,
+ nCell, sThisType, sRendered, sValType;
+
+ /* A single loop to rule them all (and be more efficient) */
+ if ( bAutoType || bRender || bClass || !bVisible )
+ {
+ for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
+ {
+ oData = oSettings.aoData[iRow];
+ nCell = nTds[ (iRow*iColumns) + iColumn ];
+
+ /* Type detection */
+ if ( bAutoType && oCol.sType != 'string' )
+ {
+ sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
+ if ( sValType !== '' )
+ {
+ sThisType = _fnDetectType( sValType );
+ if ( oCol.sType === null )
+ {
+ oCol.sType = sThisType;
+ }
+ else if ( oCol.sType != sThisType &&
+ oCol.sType != "html" )
+ {
+ /* String is always the 'fallback' option */
+ oCol.sType = 'string';
+ }
+ }
+ }
+
+ if ( oCol.mRender )
+ {
+ // mRender has been defined, so we need to get the value and set it
+ nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+ }
+ else if ( oCol.mData !== iColumn )
+ {
+ // If mData is not the same as the column number, then we need to
+ // get the dev set value. If it is the column, no point in wasting
+ // time setting the value that is already there!
+ nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+ }
+
+ /* Rendering */
+ if ( bRender )
+ {
+ sRendered = _fnRender( oSettings, iRow, iColumn );
+ nCell.innerHTML = sRendered;
+ if ( oCol.bUseRendered )
+ {
+ /* Use the rendered data for filtering / sorting */
+ _fnSetCellData( oSettings, iRow, iColumn, sRendered );
+ }
+ }
+
+ /* Classes */
+ if ( bClass )
+ {
+ nCell.className += ' '+oCol.sClass;
+ }
+
+ /* Column visibility */
+ if ( !bVisible )
+ {
+ oData._anHidden[iColumn] = nCell;
+ nCell.parentNode.removeChild( nCell );
+ }
+ else
+ {
+ oData._anHidden[iColumn] = null;
+ }
+
+ if ( oCol.fnCreatedCell )
+ {
+ oCol.fnCreatedCell.call( oSettings.oInstance,
+ nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
+ );
+ }
+ }
+ }
+ }
+
+ /* Row created callbacks */
+ if ( oSettings.aoRowCreatedCallback.length !== 0 )
+ {
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ oData = oSettings.aoData[i];
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
+ }
+ }
+ }
+
+
+ /**
+ * Take a TR element and convert it to an index in aoData
+ * @param {object} oSettings dataTables settings object
+ * @param {node} n the TR element to find
+ * @returns {int} index if the node is found, null if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToDataIndex( oSettings, n )
+ {
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
+ }
+
+
+ /**
+ * Take a TD element and convert it into a column data index (not the visible index)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow The row number the TD/TH can be found in
+ * @param {node} n The TD/TH element to find
+ * @returns {int} index if the node is found, -1 if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
+ {
+ var anCells = _fnGetTdNodes( oSettings, iRow );
+
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( anCells[i] === n )
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ /**
+ * Get an array of data for a given row from the internal data cache
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {string} sSpecific data get type ('type' 'filter' 'sort')
+ * @param {array} aiColumns Array of column indexes to get data from
+ * @returns {array} Data array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
+ {
+ var out = [];
+ for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
+ {
+ out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
+ }
+ return out;
+ }
+
+
+ /**
+ * Get the data for a given cell from the internal cache, taking into account data mapping
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {int} iCol Column index
+ * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
+ * @returns {*} Cell data
+ * @memberof DataTable#oApi
+ */
+ function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
+ {
+ var sData;
+ var oCol = oSettings.aoColumns[iCol];
+ var oData = oSettings.aoData[iRow]._aData;
+
+ if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
+ {
+ if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
+ {
+ _fnLog( oSettings, 0, "Requested unknown parameter "+
+ (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
+ " from the data source for row "+iRow );
+ oSettings.iDrawError = oSettings.iDraw;
+ }
+ return oCol.sDefaultContent;
+ }
+
+ /* When the data source is null, we can use default column data */
+ if ( sData === null && oCol.sDefaultContent !== null )
+ {
+ sData = oCol.sDefaultContent;
+ }
+ else if ( typeof sData === 'function' )
+ {
+ /* If the data source is a function, then we run it and use the return */
+ return sData();
+ }
+
+ if ( sSpecific == 'display' && sData === null )
+ {
+ return '';
+ }
+ return sData;
+ }
+
+
+ /**
+ * Set the value for a specific cell, into the internal data cache
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {int} iCol Column index
+ * @param {*} val Value to set
+ * @memberof DataTable#oApi
+ */
+ function _fnSetCellData( oSettings, iRow, iCol, val )
+ {
+ var oCol = oSettings.aoColumns[iCol];
+ var oData = oSettings.aoData[iRow]._aData;
+
+ oCol.fnSetData( oData, val );
+ }
+
+
+ // Private variable that is used to match array syntax in the data property object
+ var __reArray = /\[.*?\]$/;
+
+ /**
+ * Return a function that can be used to get data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data get function
+ * @memberof DataTable#oApi
+ */
+ function _fnGetObjectDataFn( mSource )
+ {
+ if ( mSource === null )
+ {
+ /* Give an empty string for rendering / sorting etc */
+ return function (data, type) {
+ return null;
+ };
+ }
+ else if ( typeof mSource === 'function' )
+ {
+ return function (data, type, extra) {
+ return mSource( data, type, extra );
+ };
+ }
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+ {
+ /* If there is a . in the source string then the data source is in a
+ * nested object so we loop over the data for each level to get the next
+ * level down. On each loop we test for undefined, and if found immediately
+ * return. This allows entire objects to be missing and sDefaultContent to
+ * be used if defined, rather than throwing an error
+ */
+ var fetchData = function (data, type, src) {
+ var a = src.split('.');
+ var arrayNotation, out, innerSrc;
+
+ if ( src !== "" )
+ {
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+ {
+ // Check if we are dealing with an array notation request
+ arrayNotation = a[i].match(__reArray);
+
+ if ( arrayNotation ) {
+ a[i] = a[i].replace(__reArray, '');
+
+ // Condition allows simply [] to be passed in
+ if ( a[i] !== "" ) {
+ data = data[ a[i] ];
+ }
+ out = [];
+
+ // Get the remainder of the nested object to get
+ a.splice( 0, i+1 );
+ innerSrc = a.join('.');
+
+ // Traverse each entry in the array getting the properties requested
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
+ out.push( fetchData( data[j], type, innerSrc ) );
+ }
+
+ // If a string is given in between the array notation indicators, that
+ // is used to join the strings together, otherwise an array is returned
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
+ data = (join==="") ? out : out.join(join);
+
+ // The inner call to fetchData has already traversed through the remainder
+ // of the source requested, so we exit from the loop
+ break;
+ }
+
+ if ( data === null || data[ a[i] ] === undefined )
+ {
+ return undefined;
+ }
+ data = data[ a[i] ];
+ }
+ }
+
+ return data;
+ };
+
+ return function (data, type) {
+ return fetchData( data, type, mSource );
+ };
+ }
+ else
+ {
+ /* Array or flat object mapping */
+ return function (data, type) {
+ return data[mSource];
+ };
+ }
+ }
+
+
+ /**
+ * Return a function that can be used to set data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data set function
+ * @memberof DataTable#oApi
+ */
+ function _fnSetObjectDataFn( mSource )
+ {
+ if ( mSource === null )
+ {
+ /* Nothing to do when the data source is null */
+ return function (data, val) {};
+ }
+ else if ( typeof mSource === 'function' )
+ {
+ return function (data, val) {
+ mSource( data, 'set', val );
+ };
+ }
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+ {
+ /* Like the get, we need to get data from a nested object */
+ var setData = function (data, val, src) {
+ var a = src.split('.'), b;
+ var arrayNotation, o, innerSrc;
+
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
+ {
+ // Check if we are dealing with an array notation request
+ arrayNotation = a[i].match(__reArray);
+
+ if ( arrayNotation )
+ {
+ a[i] = a[i].replace(__reArray, '');
+ data[ a[i] ] = [];
+
+ // Get the remainder of the nested object to set so we can recurse
+ b = a.slice();
+ b.splice( 0, i+1 );
+ innerSrc = b.join('.');
+
+ // Traverse each entry in the array setting the properties requested
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
+ {
+ o = {};
+ setData( o, val[j], innerSrc );
+ data[ a[i] ].push( o );
+ }
+
+ // The inner call to setData has already traversed through the remainder
+ // of the source and has set the data, thus we can exit here
+ return;
+ }
+
+ // If the nested object doesn't currently exist - since we are
+ // trying to set the value - create it
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
+ {
+ data[ a[i] ] = {};
+ }
+ data = data[ a[i] ];
+ }
+
+ // If array notation is used, we just want to strip it and use the property name
+ // and assign the value. If it isn't used, then we get the result we want anyway
+ data[ a[a.length-1].replace(__reArray, '') ] = val;
+ };
+
+ return function (data, val) {
+ return setData( data, val, mSource );
+ };
+ }
+ else
+ {
+ /* Array or flat object mapping */
+ return function (data, val) {
+ data[mSource] = val;
+ };
+ }
+ }
+
+
+ /**
+ * Return an array with the full table data
+ * @param {object} oSettings dataTables settings object
+ * @returns array {array} aData Master data array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetDataMaster ( oSettings )
+ {
+ var aData = [];
+ var iLen = oSettings.aoData.length;
+ for ( var i=0 ; i<iLen; i++ )
+ {
+ aData.push( oSettings.aoData[i]._aData );
+ }
+ return aData;
+ }
+
+
+ /**
+ * Nuke the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnClearTable( oSettings )
+ {
+ oSettings.aoData.splice( 0, oSettings.aoData.length );
+ oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
+ _fnCalculateEnd( oSettings );
+ }
+
+
+ /**
+ * Take an array of integers (index array) and remove a target integer (value - not
+ * the key!)
+ * @param {array} a Index array to target
+ * @param {int} iTarget value to find
+ * @memberof DataTable#oApi
+ */
+ function _fnDeleteIndex( a, iTarget )
+ {
+ var iTargetIndex = -1;
+
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+ {
+ if ( a[i] == iTarget )
+ {
+ iTargetIndex = i;
+ }
+ else if ( a[i] > iTarget )
+ {
+ a[i]--;
+ }
+ }
+
+ if ( iTargetIndex != -1 )
+ {
+ a.splice( iTargetIndex, 1 );
+ }
+ }
+
+
+ /**
+ * Call the developer defined fnRender function for a given cell (row/column) with
+ * the required parameters and return the result.
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData index for the row
+ * @param {int} iCol aoColumns index for the column
+ * @returns {*} Return of the developer's fnRender function
+ * @memberof DataTable#oApi
+ */
+ function _fnRender( oSettings, iRow, iCol )
+ {
+ var oCol = oSettings.aoColumns[iCol];
+
+ return oCol.fnRender( {
+ "iDataRow": iRow,
+ "iDataColumn": iCol,
+ "oSettings": oSettings,
+ "aData": oSettings.aoData[iRow]._aData,
+ "mDataProp": oCol.mData
+ }, _fnGetCellData(oSettings, iRow, iCol, 'display') );
+ }
+ /**
+ * Create a new TR element (and it's TD children) for a row
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow Row to consider
+ * @memberof DataTable#oApi
+ */
+ function _fnCreateTr ( oSettings, iRow )
+ {
+ var oData = oSettings.aoData[iRow];
+ var nTd;
+
+ if ( oData.nTr === null )
+ {
+ oData.nTr = document.createElement('tr');
+
+ /* Use a private property on the node to allow reserve mapping from the node
+ * to the aoData array for fast look up
+ */
+ oData.nTr._DT_RowIndex = iRow;
+
+ /* Special parameters can be given by the data source to be used on the row */
+ if ( oData._aData.DT_RowId )
+ {
+ oData.nTr.id = oData._aData.DT_RowId;
+ }
+
+ if ( oData._aData.DT_RowClass )
+ {
+ oData.nTr.className = oData._aData.DT_RowClass;
+ }
+
+ /* Process each column */
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ var oCol = oSettings.aoColumns[i];
+ nTd = document.createElement( oCol.sCellType );
+
+ /* Render if needed - if bUseRendered is true then we already have the rendered
+ * value in the data source - so can just use that
+ */
+ nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
+ _fnRender( oSettings, iRow, i ) :
+ _fnGetCellData( oSettings, iRow, i, 'display' );
+
+ /* Add user defined class */
+ if ( oCol.sClass !== null )
+ {
+ nTd.className = oCol.sClass;
+ }
+
+ if ( oCol.bVisible )
+ {
+ oData.nTr.appendChild( nTd );
+ oData._anHidden[i] = null;
+ }
+ else
+ {
+ oData._anHidden[i] = nTd;
+ }
+
+ if ( oCol.fnCreatedCell )
+ {
+ oCol.fnCreatedCell.call( oSettings.oInstance,
+ nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
+ );
+ }
+ }
+
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
+ }
+ }
+
+
+ /**
+ * Create the HTML header for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildHead( oSettings )
+ {
+ var i, nTh, iLen, j, jLen;
+ var iThs = $('th, td', oSettings.nTHead).length;
+ var iCorrector = 0;
+ var jqChildren;
+
+ /* If there is a header in place - then use it - otherwise it's going to get nuked... */
+ if ( iThs !== 0 )
+ {
+ /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+ nTh.setAttribute('role', 'columnheader');
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ nTh.setAttribute('tabindex', oSettings.iTabIndex);
+ nTh.setAttribute('aria-controls', oSettings.sTableId);
+ }
+
+ if ( oSettings.aoColumns[i].sClass !== null )
+ {
+ $(nTh).addClass( oSettings.aoColumns[i].sClass );
+ }
+
+ /* Set the title of the column if it is user defined (not what was auto detected) */
+ if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
+ {
+ nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+ }
+ }
+ }
+ else
+ {
+ /* We don't have a header in the DOM - so we are going to have to create one */
+ var nTr = document.createElement( "tr" );
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+ nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+ nTh.setAttribute('tabindex', '0');
+
+ if ( oSettings.aoColumns[i].sClass !== null )
+ {
+ $(nTh).addClass( oSettings.aoColumns[i].sClass );
+ }
+
+ nTr.appendChild( nTh );
+ }
+ $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
+ _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
+ }
+
+ /* ARIA role for the rows */
+ $(oSettings.nTHead).children('tr').attr('role', 'row');
+
+ /* Add the extra markup needed by jQuery UI's themes */
+ if ( oSettings.bJUI )
+ {
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+
+ var nDiv = document.createElement('div');
+ nDiv.className = oSettings.oClasses.sSortJUIWrapper;
+ $(nTh).contents().appendTo(nDiv);
+
+ var nSpan = document.createElement('span');
+ nSpan.className = oSettings.oClasses.sSortIcon;
+ nDiv.appendChild( nSpan );
+ nTh.appendChild( nDiv );
+ }
+ }
+
+ if ( oSettings.oFeatures.bSort )
+ {
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable !== false )
+ {
+ _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
+ }
+ else
+ {
+ $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
+ }
+ }
+ }
+
+ /* Deal with the footer - add classes if required */
+ if ( oSettings.oClasses.sFooterTH !== "" )
+ {
+ $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
+ }
+
+ /* Cache the footer elements */
+ if ( oSettings.nTFoot !== null )
+ {
+ var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( anCells[i] )
+ {
+ oSettings.aoColumns[i].nTf = anCells[i];
+ if ( oSettings.aoColumns[i].sClass )
+ {
+ $(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Draw the header (or footer) element based on the column visibility states. The
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
+ * the instantaneous column visibility, to construct the new layout. The grid is
+ * traversed over cell at a time in a rows x columns grid fashion, although each
+ * cell insert can cover multiple elements in the grid - which is tracks using the
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
+ * already a cell in that position.
+ * @param {object} oSettings dataTables settings object
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
+ * @memberof DataTable#oApi
+ */
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+ {
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
+ var aoLocal = [];
+ var aApplied = [];
+ var iColumns = oSettings.aoColumns.length;
+ var iRowspan, iColspan;
+
+ if ( bIncludeHidden === undefined )
+ {
+ bIncludeHidden = false;
+ }
+
+ /* Make a copy of the master layout array, but without the visible columns in it */
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
+ {
+ aoLocal[i] = aoSource[i].slice();
+ aoLocal[i].nTr = aoSource[i].nTr;
+
+ /* Remove any columns which are currently hidden */
+ for ( j=iColumns-1 ; j>=0 ; j-- )
+ {
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+ {
+ aoLocal[i].splice( j, 1 );
+ }
+ }
+
+ /* Prep the applied array - it needs an element for each row */
+ aApplied.push( [] );
+ }
+
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
+ {
+ nLocalTr = aoLocal[i].nTr;
+
+ /* All cells are going to be replaced, so empty out the row */
+ if ( nLocalTr )
+ {
+ while( (n = nLocalTr.firstChild) )
+ {
+ nLocalTr.removeChild( n );
+ }
+ }
+
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
+ {
+ iRowspan = 1;
+ iColspan = 1;
+
+ /* Check to see if there is already a cell (row/colspan) covering our target
+ * insert point. If there is, then there is nothing to do.
+ */
+ if ( aApplied[i][j] === undefined )
+ {
+ nLocalTr.appendChild( aoLocal[i][j].cell );
+ aApplied[i][j] = 1;
+
+ /* Expand the cell to cover as many rows as needed */
+ while ( aoLocal[i+iRowspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
+ {
+ aApplied[i+iRowspan][j] = 1;
+ iRowspan++;
+ }
+
+ /* Expand the cell to cover as many columns as needed */
+ while ( aoLocal[i][j+iColspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
+ {
+ /* Must update the applied array over the rows for the columns */
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aApplied[i+k][j+iColspan] = 1;
+ }
+ iColspan++;
+ }
+
+ /* Do the actual expansion in the DOM */
+ aoLocal[i][j].cell.rowSpan = iRowspan;
+ aoLocal[i][j].cell.colSpan = iColspan;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Insert the required TR nodes into the table for display
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnDraw( oSettings )
+ {
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
+ if ( $.inArray( false, aPreDraw ) !== -1 )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ return;
+ }
+
+ var i, iLen, n;
+ var anRows = [];
+ var iRowCount = 0;
+ var iStripes = oSettings.asStripeClasses.length;
+ var iOpenRows = oSettings.aoOpenRows.length;
+
+ oSettings.bDrawing = true;
+
+ /* Check and see if we have an initial draw position from state saving */
+ if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
+ {
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ oSettings._iDisplayStart = oSettings.iInitDisplayStart;
+ }
+ else
+ {
+ oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
+ 0 : oSettings.iInitDisplayStart;
+ }
+ oSettings.iInitDisplayStart = -1;
+ _fnCalculateEnd( oSettings );
+ }
+
+ /* Server-side processing draw intercept */
+ if ( oSettings.bDeferLoading )
+ {
+ oSettings.bDeferLoading = false;
+ oSettings.iDraw++;
+ }
+ else if ( !oSettings.oFeatures.bServerSide )
+ {
+ oSettings.iDraw++;
+ }
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
+ {
+ return;
+ }
+
+ if ( oSettings.aiDisplay.length !== 0 )
+ {
+ var iStart = oSettings._iDisplayStart;
+ var iEnd = oSettings._iDisplayEnd;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ iStart = 0;
+ iEnd = oSettings.aoData.length;
+ }
+
+ for ( var j=iStart ; j<iEnd ; j++ )
+ {
+ var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
+ if ( aoData.nTr === null )
+ {
+ _fnCreateTr( oSettings, oSettings.aiDisplay[j] );
+ }
+
+ var nRow = aoData.nTr;
+
+ /* Remove the old striping classes and then add the new one */
+ if ( iStripes !== 0 )
+ {
+ var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
+ if ( aoData._sRowStripe != sStripe )
+ {
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
+ aoData._sRowStripe = sStripe;
+ }
+ }
+
+ /* Row callback functions - might want to manipulate the row */
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
+ [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
+
+ anRows.push( nRow );
+ iRowCount++;
+
+ /* If there is an open row - and it is attached to this parent - attach it on redraw */
+ if ( iOpenRows !== 0 )
+ {
+ for ( var k=0 ; k<iOpenRows ; k++ )
+ {
+ if ( nRow == oSettings.aoOpenRows[k].nParent )
+ {
+ anRows.push( oSettings.aoOpenRows[k].nTr );
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Table is empty - create a row with an empty message in it */
+ anRows[ 0 ] = document.createElement( 'tr' );
+
+ if ( oSettings.asStripeClasses[0] )
+ {
+ anRows[ 0 ].className = oSettings.asStripeClasses[0];
+ }
+
+ var oLang = oSettings.oLanguage;
+ var sZero = oLang.sZeroRecords;
+ if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+ {
+ sZero = oLang.sLoadingRecords;
+ }
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
+ {
+ sZero = oLang.sEmptyTable;
+ }
+
+ var nTd = document.createElement( 'td' );
+ nTd.setAttribute( 'valign', "top" );
+ nTd.colSpan = _fnVisbleColumns( oSettings );
+ nTd.className = oSettings.oClasses.sRowEmpty;
+ nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
+
+ anRows[ iRowCount ].appendChild( nTd );
+ }
+
+ /* Header and footer callbacks */
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+
+ /*
+ * Need to remove any old row from the display - note we can't just empty the tbody using
+ * $().html('') since this will unbind the jQuery event handlers (even although the node
+ * still exists!) - equally we can't use innerHTML, since IE throws an exception.
+ */
+ var
+ nAddFrag = document.createDocumentFragment(),
+ nRemoveFrag = document.createDocumentFragment(),
+ nBodyPar, nTrs;
+
+ if ( oSettings.nTBody )
+ {
+ nBodyPar = oSettings.nTBody.parentNode;
+ nRemoveFrag.appendChild( oSettings.nTBody );
+
+ /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
+ * up. When not infinite scroll, always do it.
+ */
+ if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
+ oSettings.bSorted || oSettings.bFiltered )
+ {
+ while( (n = oSettings.nTBody.firstChild) )
+ {
+ oSettings.nTBody.removeChild( n );
+ }
+ }
+
+ /* Put the draw table into the dom */
+ for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
+ {
+ nAddFrag.appendChild( anRows[i] );
+ }
+
+ oSettings.nTBody.appendChild( nAddFrag );
+ if ( nBodyPar !== null )
+ {
+ nBodyPar.appendChild( oSettings.nTBody );
+ }
+ }
+
+ /* Call all required callback functions for the end of a draw */
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+
+ /* Draw is complete, sorting and filtering must be as well */
+ oSettings.bSorted = false;
+ oSettings.bFiltered = false;
+ oSettings.bDrawing = false;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ if ( !oSettings._bInitComplete )
+ {
+ _fnInitComplete( oSettings );
+ }
+ }
+ }
+
+
+ /**
+ * Redraw the table - taking account of the various features which are enabled
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnReDraw( oSettings )
+ {
+ if ( oSettings.oFeatures.bSort )
+ {
+ /* Sorting will refilter and draw for us */
+ _fnSort( oSettings, oSettings.oPreviousSearch );
+ }
+ else if ( oSettings.oFeatures.bFilter )
+ {
+ /* Filtering will redraw for us */
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+ }
+ else
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+
+
+ /**
+ * Add the options to the page HTML for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAddOptionsHtml ( oSettings )
+ {
+ /*
+ * Create a temporary, empty, div which we can later on replace with what we have generated
+ * we do it this way to rendering the 'options' html offline - speed :-)
+ */
+ var nHolding = $('<div></div>')[0];
+ oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
+
+ /*
+ * All DataTables are wrapped in a div
+ */
+ oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+
+ /* Track where we want to insert the option */
+ var nInsertNode = oSettings.nTableWrapper;
+
+ /* Loop over the user set positioning and place the elements as needed */
+ var aDom = oSettings.sDom.split('');
+ var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
+ for ( var i=0 ; i<aDom.length ; i++ )
+ {
+ iPushFeature = 0;
+ cOption = aDom[i];
+
+ if ( cOption == '<' )
+ {
+ /* New container div */
+ nNewNode = $('<div></div>')[0];
+
+ /* Check to see if we should append an id and/or a class name to the container */
+ cNext = aDom[i+1];
+ if ( cNext == "'" || cNext == '"' )
+ {
+ sAttr = "";
+ j = 2;
+ while ( aDom[i+j] != cNext )
+ {
+ sAttr += aDom[i+j];
+ j++;
+ }
+
+ /* Replace jQuery UI constants */
+ if ( sAttr == "H" )
+ {
+ sAttr = oSettings.oClasses.sJUIHeader;
+ }
+ else if ( sAttr == "F" )
+ {
+ sAttr = oSettings.oClasses.sJUIFooter;
+ }
+
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+ * breaks the string into parts and applies them as needed
+ */
+ if ( sAttr.indexOf('.') != -1 )
+ {
+ var aSplit = sAttr.split('.');
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+ nNewNode.className = aSplit[1];
+ }
+ else if ( sAttr.charAt(0) == "#" )
+ {
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
+ }
+ else
+ {
+ nNewNode.className = sAttr;
+ }
+
+ i += j; /* Move along the position array */
+ }
+
+ nInsertNode.appendChild( nNewNode );
+ nInsertNode = nNewNode;
+ }
+ else if ( cOption == '>' )
+ {
+ /* End container div */
+ nInsertNode = nInsertNode.parentNode;
+ }
+ else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+ {
+ /* Length */
+ nTmp = _fnFeatureHtmlLength( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+ {
+ /* Filter */
+ nTmp = _fnFeatureHtmlFilter( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+ {
+ /* pRocessing */
+ nTmp = _fnFeatureHtmlProcessing( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ nTmp = _fnFeatureHtmlTable( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
+ {
+ /* Info */
+ nTmp = _fnFeatureHtmlInfo( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+ {
+ /* Pagination */
+ nTmp = _fnFeatureHtmlPaginate( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( DataTable.ext.aoFeatures.length !== 0 )
+ {
+ /* Plug-in features */
+ var aoFeatures = DataTable.ext.aoFeatures;
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+ {
+ if ( cOption == aoFeatures[k].cFeature )
+ {
+ nTmp = aoFeatures[k].fnInit( oSettings );
+ if ( nTmp )
+ {
+ iPushFeature = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add to the 2D features array */
+ if ( iPushFeature == 1 && nTmp !== null )
+ {
+ if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
+ {
+ oSettings.aanFeatures[cOption] = [];
+ }
+ oSettings.aanFeatures[cOption].push( nTmp );
+ nInsertNode.appendChild( nTmp );
+ }
+ }
+
+ /* Built our DOM structure - replace the holding div with what we want */
+ nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
+ }
+
+
+ /**
+ * Use the DOM source to create up an array of header cells. The idea here is to
+ * create a layout grid (array) of rows x columns, which contains a reference
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
+ * any column / row could be removed and the new grid constructed
+ * @param array {object} aLayout Array to store the calculated layout in
+ * @param {node} nThead The header/footer element for the table
+ * @memberof DataTable#oApi
+ */
+ function _fnDetectHeader ( aLayout, nThead )
+ {
+ var nTrs = $(nThead).children('tr');
+ var nTr, nCell;
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
+ var bUnique;
+ var fnShiftCol = function ( a, i, j ) {
+ var k = a[i];
+ while ( k[j] ) {
+ j++;
+ }
+ return j;
+ };
+
+ aLayout.splice( 0, aLayout.length );
+
+ /* We know how many rows there are in the layout - so prep it */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ aLayout.push( [] );
+ }
+
+ /* Calculate a layout array */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ nTr = nTrs[i];
+ iColumn = 0;
+
+ /* For every cell in the row... */
+ nCell = nTr.firstChild;
+ while ( nCell ) {
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
+ nCell.nodeName.toUpperCase() == "TH" )
+ {
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
+ iColspan = nCell.getAttribute('colspan') * 1;
+ iRowspan = nCell.getAttribute('rowspan') * 1;
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
+
+ /* There might be colspan cells already in this row, so shift our target
+ * accordingly
+ */
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
+
+ /* Cache calculation for unique columns */
+ bUnique = iColspan === 1 ? true : false;
+
+ /* If there is col / rowspan, copy the information into the layout grid */
+ for ( l=0 ; l<iColspan ; l++ )
+ {
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aLayout[i+k][iColShifted+l] = {
+ "cell": nCell,
+ "unique": bUnique
+ };
+ aLayout[i+k].nTr = nTr;
+ }
+ }
+ }
+ nCell = nCell.nextSibling;
+ }
+ }
+ }
+
+
+ /**
+ * Get an array of unique th elements, one for each column
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nHeader automatically detect the layout from this node - optional
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
+ * @returns array {node} aReturn list of unique th's
+ * @memberof DataTable#oApi
+ */
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
+ {
+ var aReturn = [];
+ if ( !aLayout )
+ {
+ aLayout = oSettings.aoHeader;
+ if ( nHeader )
+ {
+ aLayout = [];
+ _fnDetectHeader( aLayout, nHeader );
+ }
+ }
+
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
+ {
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+ {
+ if ( aLayout[i][j].unique &&
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
+ {
+ aReturn[j] = aLayout[i][j].cell;
+ }
+ }
+ }
+
+ return aReturn;
+ }
+
+
+
+ /**
+ * Update the table using an Ajax call
+ * @param {object} oSettings dataTables settings object
+ * @returns {boolean} Block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdate( oSettings )
+ {
+ if ( oSettings.bAjaxDataGet )
+ {
+ oSettings.iDraw++;
+ _fnProcessingDisplay( oSettings, true );
+ var iColumns = oSettings.aoColumns.length;
+ var aoData = _fnAjaxParameters( oSettings );
+ _fnServerParams( oSettings, aoData );
+
+ oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
+ function(json) {
+ _fnAjaxUpdateDraw( oSettings, json );
+ }, oSettings );
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+ /**
+ * Build up the parameters in an object needed for a server-side processing request
+ * @param {object} oSettings dataTables settings object
+ * @returns {bool} block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxParameters( oSettings )
+ {
+ var iColumns = oSettings.aoColumns.length;
+ var aoData = [], mDataProp, aaSort, aDataSort;
+ var i, j;
+
+ aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
+ aoData.push( { "name": "iColumns", "value": iColumns } );
+ aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
+ aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
+ aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
+ oSettings._iDisplayLength : -1 } );
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ mDataProp = oSettings.aoColumns[i].mData;
+ aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
+ }
+
+ /* Filtering */
+ if ( oSettings.oFeatures.bFilter !== false )
+ {
+ aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
+ aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } );
+ aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } );
+ aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
+ }
+ }
+
+ /* Sorting */
+ if ( oSettings.oFeatures.bSort !== false )
+ {
+ var iCounter = 0;
+
+ aaSort = ( oSettings.aaSortingFixed !== null ) ?
+ oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+ oSettings.aaSorting.slice();
+
+ for ( i=0 ; i<aaSort.length ; i++ )
+ {
+ aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
+
+ for ( j=0 ; j<aDataSort.length ; j++ )
+ {
+ aoData.push( { "name": "iSortCol_"+iCounter, "value": aDataSort[j] } );
+ aoData.push( { "name": "sSortDir_"+iCounter, "value": aaSort[i][1] } );
+ iCounter++;
+ }
+ }
+ aoData.push( { "name": "iSortingCols", "value": iCounter } );
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } );
+ }
+ }
+
+ return aoData;
+ }
+
+
+ /**
+ * Add Ajax parameters from plug-ins
+ * @param {object} oSettings dataTables settings object
+ * @param array {objects} aoData name/value pairs to send to the server
+ * @memberof DataTable#oApi
+ */
+ function _fnServerParams( oSettings, aoData )
+ {
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
+ }
+
+
+ /**
+ * Data the data from the server (nuking the old) and redraw the table
+ * @param {object} oSettings dataTables settings object
+ * @param {object} json json data return from the server.
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
+ * @param {array} json.aaData The data to display on this page
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdateDraw ( oSettings, json )
+ {
+ if ( json.sEcho !== undefined )
+ {
+ /* Protect against old returns over-writing a new one. Possible when you get
+ * very fast interaction, and later queries are completed much faster
+ */
+ if ( json.sEcho*1 < oSettings.iDraw )
+ {
+ return;
+ }
+ else
+ {
+ oSettings.iDraw = json.sEcho * 1;
+ }
+ }
+
+ if ( !oSettings.oScroll.bInfinite ||
+ (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
+ {
+ _fnClearTable( oSettings );
+ }
+ oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
+ oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
+
+ /* Determine if reordering is required */
+ var sOrdering = _fnColumnOrdering(oSettings);
+ var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
+ var aiIndex;
+ if ( bReOrder )
+ {
+ aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
+ }
+
+ var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
+ for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
+ {
+ if ( bReOrder )
+ {
+ /* If we need to re-order, then create a new array with the correct order and add it */
+ var aDataSorted = [];
+ for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
+ {
+ aDataSorted.push( aData[i][ aiIndex[j] ] );
+ }
+ _fnAddData( oSettings, aDataSorted );
+ }
+ else
+ {
+ /* No re-order required, sever got it "right" - just straight add */
+ _fnAddData( oSettings, aData[i] );
+ }
+ }
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ oSettings.bAjaxDataGet = false;
+ _fnDraw( oSettings );
+ oSettings.bAjaxDataGet = true;
+ _fnProcessingDisplay( oSettings, false );
+ }
+
+
+
+ /**
+ * Generate the node required for filtering text
+ * @returns {node} Filter control element
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlFilter ( oSettings )
+ {
+ var oPreviousSearch = oSettings.oPreviousSearch;
+
+ var sSearchStr = oSettings.oLanguage.sSearch;
+ sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
+ sSearchStr.replace('_INPUT_', '<input type="text" />') :
+ sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
+
+ var nFilter = document.createElement( 'div' );
+ nFilter.className = oSettings.oClasses.sFilter;
+ nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
+ if ( !oSettings.aanFeatures.f )
+ {
+ nFilter.id = oSettings.sTableId+'_filter';
+ }
+
+ var jqFilter = $('input[type="text"]', nFilter);
+
+ // Store a reference to the input element, so other input elements could be
+ // added to the filter wrapper if needed (submit button for example)
+ nFilter._DT_Input = jqFilter[0];
+
+ jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
+ jqFilter.bind( 'keyup.DT', function(e) {
+ /* Update all other filter input elements for the new display */
+ var n = oSettings.aanFeatures.f;
+ var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
+
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
+ {
+ $(n[i]._DT_Input).val( val );
+ }
+ }
+
+ /* Now do the filter */
+ if ( val != oPreviousSearch.sSearch )
+ {
+ _fnFilterComplete( oSettings, {
+ "sSearch": val,
+ "bRegex": oPreviousSearch.bRegex,
+ "bSmart": oPreviousSearch.bSmart ,
+ "bCaseInsensitive": oPreviousSearch.bCaseInsensitive
+ } );
+ }
+ } );
+
+ jqFilter
+ .attr('aria-controls', oSettings.sTableId)
+ .bind( 'keypress.DT', function(e) {
+ /* Prevent form submission */
+ if ( e.keyCode == 13 )
+ {
+ return false;
+ }
+ }
+ );
+
+ return nFilter;
+ }
+
+
+ /**
+ * Filter the table using both the global filter and column based filtering
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oSearch search information
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterComplete ( oSettings, oInput, iForce )
+ {
+ var oPrevSearch = oSettings.oPreviousSearch;
+ var aoPrevSearch = oSettings.aoPreSearchCols;
+ var fnSaveFilter = function ( oFilter ) {
+ /* Save the filtering values */
+ oPrevSearch.sSearch = oFilter.sSearch;
+ oPrevSearch.bRegex = oFilter.bRegex;
+ oPrevSearch.bSmart = oFilter.bSmart;
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+ };
+
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ /* Global filter */
+ _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
+ fnSaveFilter( oInput );
+
+ /* Now do the individual column filter */
+ for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
+ {
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex,
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+ }
+
+ /* Custom filtering */
+ _fnFilterCustom( oSettings );
+ }
+ else
+ {
+ fnSaveFilter( oInput );
+ }
+
+ /* Tell the draw function we have been filtering */
+ oSettings.bFiltered = true;
+ $(oSettings.oInstance).trigger('filter', oSettings);
+
+ /* Redraw the table */
+ oSettings._iDisplayStart = 0;
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+
+ /* Rebuild search array 'offline' */
+ _fnBuildSearchArray( oSettings, 0 );
+ }
+
+
+ /**
+ * Apply custom filtering functions
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCustom( oSettings )
+ {
+ var afnFilters = DataTable.ext.afnFiltering;
+ var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+
+ for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
+ {
+ var iCorrector = 0;
+ for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
+ {
+ var iDisIndex = oSettings.aiDisplay[j-iCorrector];
+ var bTest = afnFilters[i](
+ oSettings,
+ _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
+ iDisIndex
+ );
+
+ /* Check if we should use this row based on the filtering function */
+ if ( !bTest )
+ {
+ oSettings.aiDisplay.splice( j-iCorrector, 1 );
+ iCorrector++;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Filter the table on a per-column basis
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sInput string to filter on
+ * @param {int} iColumn column to filter
+ * @param {bool} bRegex treat search string as a regular expression or not
+ * @param {bool} bSmart use smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
+ {
+ if ( sInput === "" )
+ {
+ return;
+ }
+
+ var iIndexCorrector = 0;
+ var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+
+ for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
+ {
+ var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
+ oSettings.aoColumns[iColumn].sType );
+ if ( ! rpSearch.test( sData ) )
+ {
+ oSettings.aiDisplay.splice( i, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+
+
+ /**
+ * Filter the data table based on user input and draw the table
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sInput string to filter on
+ * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
+ * @param {bool} bRegex treat as a regular expression or not
+ * @param {bool} bSmart perform smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
+ {
+ var i;
+ var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+ var oPrevSearch = oSettings.oPreviousSearch;
+
+ /* Check if we are forcing or not - optional parameter */
+ if ( !iForce )
+ {
+ iForce = 0;
+ }
+
+ /* Need to take account of custom filtering functions - always filter */
+ if ( DataTable.ext.afnFiltering.length !== 0 )
+ {
+ iForce = 1;
+ }
+
+ /*
+ * If the input is blank - we want the full data set
+ */
+ if ( sInput.length <= 0 )
+ {
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ }
+ else
+ {
+ /*
+ * We are starting a new search or the new search string is smaller
+ * then the old one (i.e. delete). Search from the master array
+ */
+ if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+ oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
+ sInput.indexOf(oPrevSearch.sSearch) !== 0 )
+ {
+ /* Nuke the old display array - we are going to rebuild it */
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+
+ /* Force a rebuild of the search array */
+ _fnBuildSearchArray( oSettings, 1 );
+
+ /* Search through all records to populate the search array
+ * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
+ * mapping
+ */
+ for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
+ {
+ if ( rpSearch.test(oSettings.asDataSearch[i]) )
+ {
+ oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
+ }
+ }
+ }
+ else
+ {
+ /* Using old search array - refine it - do it this way for speed
+ * Don't have to search the whole master array again
+ */
+ var iIndexCorrector = 0;
+
+ /* Search the current results */
+ for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
+ {
+ if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
+ {
+ oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Create an array which can be quickly search through
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iMaster use the master data array - optional
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildSearchArray ( oSettings, iMaster )
+ {
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ /* Clear out the old data */
+ oSettings.asDataSearch = [];
+
+ var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+ var aiIndex = (iMaster===1) ?
+ oSettings.aiDisplayMaster :
+ oSettings.aiDisplay;
+
+ for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
+ {
+ oSettings.asDataSearch[i] = _fnBuildSearchRow(
+ oSettings,
+ _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
+ );
+ }
+ }
+ }
+
+
+ /**
+ * Create a searchable string from a single data row
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aData Row data array to use for the data to search
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildSearchRow( oSettings, aData )
+ {
+ var sSearch = aData.join(' ');
+
+ /* If it looks like there is an HTML entity in the string, attempt to decode it */
+ if ( sSearch.indexOf('&') !== -1 )
+ {
+ sSearch = $('<div>').html(sSearch).text();
+ }
+
+ // Strip newline characters
+ return sSearch.replace( /[\n\r]/g, " " );
+ }
+
+ /**
+ * Build a regular expression object suitable for searching a table
+ * @param {string} sSearch string to search for
+ * @param {bool} bRegex treat as a regular expression or not
+ * @param {bool} bSmart perform smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
+ * @returns {RegExp} constructed object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
+ {
+ var asSearch, sRegExpString;
+
+ if ( bSmart )
+ {
+ /* Generate the regular expression to use. Something along the lines of:
+ * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+ */
+ asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
+ sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+ return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
+ }
+ else
+ {
+ sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
+ return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
+ }
+ }
+
+
+ /**
+ * Convert raw data into something that the user can search on
+ * @param {string} sData data to be modified
+ * @param {string} sType data type
+ * @returns {string} search string
+ * @memberof DataTable#oApi
+ */
+ function _fnDataToSearch ( sData, sType )
+ {
+ if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
+ {
+ return DataTable.ext.ofnSearch[sType]( sData );
+ }
+ else if ( sData === null )
+ {
+ return '';
+ }
+ else if ( sType == "html" )
+ {
+ return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
+ }
+ else if ( typeof sData === "string" )
+ {
+ return sData.replace(/[\r\n]/g," ");
+ }
+ return sData;
+ }
+
+
+ /**
+ * scape a string such that it can be used in a regular expression
+ * @param {string} sVal string to escape
+ * @returns {string} escaped string
+ * @memberof DataTable#oApi
+ */
+ function _fnEscapeRegex ( sVal )
+ {
+ var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
+ var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
+ return sVal.replace(reReplace, '\\$1');
+ }
+
+
+ /**
+ * Generate the node required for the info display
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Information element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlInfo ( oSettings )
+ {
+ var nInfo = document.createElement( 'div' );
+ nInfo.className = oSettings.oClasses.sInfo;
+
+ /* Actions that are to be taken once only for this feature */
+ if ( !oSettings.aanFeatures.i )
+ {
+ /* Add draw callback */
+ oSettings.aoDrawCallback.push( {
+ "fn": _fnUpdateInfo,
+ "sName": "information"
+ } );
+
+ /* Add id */
+ nInfo.id = oSettings.sTableId+'_info';
+ }
+ oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
+
+ return nInfo;
+ }
+
+
+ /**
+ * Update the information elements in the display
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnUpdateInfo ( oSettings )
+ {
+ /* Show information about the table */
+ if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
+ {
+ return;
+ }
+
+ var
+ oLang = oSettings.oLanguage,
+ iStart = oSettings._iDisplayStart+1,
+ iEnd = oSettings.fnDisplayEnd(),
+ iMax = oSettings.fnRecordsTotal(),
+ iTotal = oSettings.fnRecordsDisplay(),
+ sOut;
+
+ if ( iTotal === 0 )
+ {
+ /* Empty record set */
+ sOut = oLang.sInfoEmpty;
+ }
+ else {
+ /* Normal record set */
+ sOut = oLang.sInfo;
+ }
+
+ if ( iTotal != iMax )
+ {
+ /* Record set after filtering */
+ sOut += ' ' + oLang.sInfoFiltered;
+ }
+
+ // Convert the macros
+ sOut += oLang.sInfoPostFix;
+ sOut = _fnInfoMacros( oSettings, sOut );
+
+ if ( oLang.fnInfoCallback !== null )
+ {
+ sOut = oLang.fnInfoCallback.call( oSettings.oInstance,
+ oSettings, iStart, iEnd, iMax, iTotal, sOut );
+ }
+
+ var n = oSettings.aanFeatures.i;
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ $(n[i]).html( sOut );
+ }
+ }
+
+
+ function _fnInfoMacros ( oSettings, str )
+ {
+ var
+ iStart = oSettings._iDisplayStart+1,
+ sStart = oSettings.fnFormatNumber( iStart ),
+ iEnd = oSettings.fnDisplayEnd(),
+ sEnd = oSettings.fnFormatNumber( iEnd ),
+ iTotal = oSettings.fnRecordsDisplay(),
+ sTotal = oSettings.fnFormatNumber( iTotal ),
+ iMax = oSettings.fnRecordsTotal(),
+ sMax = oSettings.fnFormatNumber( iMax );
+
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ // internally
+ if ( oSettings.oScroll.bInfinite )
+ {
+ sStart = oSettings.fnFormatNumber( 1 );
+ }
+
+ return str.
+ replace(/_START_/g, sStart).
+ replace(/_END_/g, sEnd).
+ replace(/_TOTAL_/g, sTotal).
+ replace(/_MAX_/g, sMax);
+ }
+
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnInitialise ( oSettings )
+ {
+ var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
+
+ /* Ensure that the table data is fully initialised */
+ if ( oSettings.bInitialised === false )
+ {
+ setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
+ return;
+ }
+
+ /* Show the display HTML options */
+ _fnAddOptionsHtml( oSettings );
+
+ /* Build and draw the header / footer for the table */
+ _fnBuildHead( oSettings );
+ _fnDrawHead( oSettings, oSettings.aoHeader );
+ if ( oSettings.nTFoot )
+ {
+ _fnDrawHead( oSettings, oSettings.aoFooter );
+ }
+
+ /* Okay to show that something is going on now */
+ _fnProcessingDisplay( oSettings, true );
+
+ /* Calculate sizes for columns */
+ if ( oSettings.oFeatures.bAutoWidth )
+ {
+ _fnCalculateColumnWidths( oSettings );
+ }
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
+ }
+ }
+
+ /* If there is default sorting required - let's do it. The sort function will do the
+ * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
+ * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
+ */
+ if ( oSettings.oFeatures.bSort )
+ {
+ _fnSort( oSettings );
+ }
+ else if ( oSettings.oFeatures.bFilter )
+ {
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ /* if there is an ajax source load the data */
+ if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+ {
+ var aoData = [];
+ _fnServerParams( oSettings, aoData );
+ oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
+ var aData = (oSettings.sAjaxDataProp !== "") ?
+ _fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
+
+ /* Got the data - add it to the table */
+ for ( i=0 ; i<aData.length ; i++ )
+ {
+ _fnAddData( oSettings, aData[i] );
+ }
+
+ /* Reset the init display for cookie saving. We've already done a filter, and
+ * therefore cleared it before. So we need to make it appear 'fresh'
+ */
+ oSettings.iInitDisplayStart = iAjaxStart;
+
+ if ( oSettings.oFeatures.bSort )
+ {
+ _fnSort( oSettings );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ _fnProcessingDisplay( oSettings, false );
+ _fnInitComplete( oSettings, json );
+ }, oSettings );
+ return;
+ }
+
+ /* Server-side processing initialisation complete is done at the end of _fnDraw */
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ _fnInitComplete( oSettings );
+ }
+ }
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} oSettings dataTables settings object
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
+ * with client-side processing (optional)
+ * @memberof DataTable#oApi
+ */
+ function _fnInitComplete ( oSettings, json )
+ {
+ oSettings._bInitComplete = true;
+ _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
+ }
+
+
+ /**
+ * Language compatibility - when certain options are given, and others aren't, we
+ * need to duplicate the values over, in order to provide backwards compatibility
+ * with older language files.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnLanguageCompat( oLanguage )
+ {
+ var oDefaults = DataTable.defaults.oLanguage;
+
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
+ * sZeroRecords - assuming that is given.
+ */
+ if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
+ oDefaults.sEmptyTable === "No data available in table" )
+ {
+ _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
+ }
+
+ /* Likewise with loading records */
+ if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
+ oDefaults.sLoadingRecords === "Loading..." )
+ {
+ _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
+ }
+ }
+
+
+
+ /**
+ * Generate the node required for user display length changing
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Display length feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlLength ( oSettings )
+ {
+ if ( oSettings.oScroll.bInfinite )
+ {
+ return null;
+ }
+
+ /* This can be overruled by not using the _MENU_ var/macro in the language variable */
+ var sName = 'name="'+oSettings.sTableId+'_length"';
+ var sStdMenu = '<select size="1" '+sName+'>';
+ var i, iLen;
+ var aLengthMenu = oSettings.aLengthMenu;
+
+ if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' &&
+ typeof aLengthMenu[1] === 'object' )
+ {
+ for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
+ {
+ sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
+ }
+ }
+ else
+ {
+ for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
+ {
+ sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
+ }
+ }
+ sStdMenu += '</select>';
+
+ var nLength = document.createElement( 'div' );
+ if ( !oSettings.aanFeatures.l )
+ {
+ nLength.id = oSettings.sTableId+'_length';
+ }
+ nLength.className = oSettings.oClasses.sLength;
+ nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
+
+ /*
+ * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+ * and Stefan Skopnik for fixing the fix!
+ */
+ $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
+
+ $('select', nLength).bind( 'change.DT', function(e) {
+ var iVal = $(this).val();
+
+ /* Update all other length options for the new display */
+ var n = oSettings.aanFeatures.l;
+ for ( i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ if ( n[i] != this.parentNode )
+ {
+ $('select', n[i]).val( iVal );
+ }
+ }
+
+ /* Redraw the table */
+ oSettings._iDisplayLength = parseInt(iVal, 10);
+ _fnCalculateEnd( oSettings );
+
+ /* If we have space to show extra rows (backing up from the end point - then do so */
+ if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+
+ _fnDraw( oSettings );
+ } );
+
+
+ $('select', nLength).attr('aria-controls', oSettings.sTableId);
+
+ return nLength;
+ }
+
+
+ /**
+ * Recalculate the end point based on the start point
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnCalculateEnd( oSettings )
+ {
+ if ( oSettings.oFeatures.bPaginate === false )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ /* Set the end point of the display - based on how many elements there are
+ * still to display
+ */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
+ oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+ }
+ }
+ }
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Note that most of the paging logic is done in
+ * DataTable.ext.oPagination
+ */
+
+ /**
+ * Generate the node required for default pagination
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Pagination feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlPaginate ( oSettings )
+ {
+ if ( oSettings.oScroll.bInfinite )
+ {
+ return null;
+ }
+
+ var nPaginate = document.createElement( 'div' );
+ nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
+
+ DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate,
+ function( oSettings ) {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ );
+
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
+ if ( !oSettings.aanFeatures.p )
+ {
+ oSettings.aoDrawCallback.push( {
+ "fn": function( oSettings ) {
+ DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ } );
+ },
+ "sName": "pagination"
+ } );
+ }
+ return nPaginate;
+ }
+
+
+ /**
+ * Alter the display settings to change the page
+ * @param {object} oSettings dataTables settings object
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+ * or page number to jump to (integer)
+ * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
+ * @memberof DataTable#oApi
+ */
+ function _fnPageChange ( oSettings, mAction )
+ {
+ var iOldStart = oSettings._iDisplayStart;
+
+ if ( typeof mAction === "number" )
+ {
+ oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "first" )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ else if ( mAction == "previous" )
+ {
+ oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
+ oSettings._iDisplayStart - oSettings._iDisplayLength :
+ 0;
+
+ /* Correct for under-run */
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "next" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ /* Make sure we are not over running the display array */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart += oSettings._iDisplayLength;
+ }
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "last" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+ oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 0, "Unknown paging action: "+mAction );
+ }
+ $(oSettings.oInstance).trigger('page', oSettings);
+
+ return iOldStart != oSettings._iDisplayStart;
+ }
+
+
+
+ /**
+ * Generate the node required for the processing node
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Processing element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlProcessing ( oSettings )
+ {
+ var nProcessing = document.createElement( 'div' );
+
+ if ( !oSettings.aanFeatures.r )
+ {
+ nProcessing.id = oSettings.sTableId+'_processing';
+ }
+ nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
+ nProcessing.className = oSettings.oClasses.sProcessing;
+ oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
+
+ return nProcessing;
+ }
+
+
+ /**
+ * Display or hide the processing indicator
+ * @param {object} oSettings dataTables settings object
+ * @param {bool} bShow Show the processing indicator (true) or not (false)
+ * @memberof DataTable#oApi
+ */
+ function _fnProcessingDisplay ( oSettings, bShow )
+ {
+ if ( oSettings.oFeatures.bProcessing )
+ {
+ var an = oSettings.aanFeatures.r;
+ for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ an[i].style.visibility = bShow ? "visible" : "hidden";
+ }
+ }
+
+ $(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
+ }
+
+ /**
+ * Add any control elements for the table - specifically scrolling
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Node to add to the DOM
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlTable ( oSettings )
+ {
+ /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
+ if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+ {
+ return oSettings.nTable;
+ }
+
+ /*
+ * The HTML structure that we want to generate in this function is:
+ * div - nScroller
+ * div - nScrollHead
+ * div - nScrollHeadInner
+ * table - nScrollHeadTable
+ * thead - nThead
+ * div - nScrollBody
+ * table - oSettings.nTable
+ * thead - nTheadSize
+ * tbody - nTbody
+ * div - nScrollFoot
+ * div - nScrollFootInner
+ * table - nScrollFootTable
+ * tfoot - nTfoot
+ */
+ var
+ nScroller = document.createElement('div'),
+ nScrollHead = document.createElement('div'),
+ nScrollHeadInner = document.createElement('div'),
+ nScrollBody = document.createElement('div'),
+ nScrollFoot = document.createElement('div'),
+ nScrollFootInner = document.createElement('div'),
+ nScrollHeadTable = oSettings.nTable.cloneNode(false),
+ nScrollFootTable = oSettings.nTable.cloneNode(false),
+ nThead = oSettings.nTable.getElementsByTagName('thead')[0],
+ nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
+ oSettings.nTable.getElementsByTagName('tfoot')[0],
+ oClasses = oSettings.oClasses;
+
+ nScrollHead.appendChild( nScrollHeadInner );
+ nScrollFoot.appendChild( nScrollFootInner );
+ nScrollBody.appendChild( oSettings.nTable );
+ nScroller.appendChild( nScrollHead );
+ nScroller.appendChild( nScrollBody );
+ nScrollHeadInner.appendChild( nScrollHeadTable );
+ nScrollHeadTable.appendChild( nThead );
+ if ( nTfoot !== null )
+ {
+ nScroller.appendChild( nScrollFoot );
+ nScrollFootInner.appendChild( nScrollFootTable );
+ nScrollFootTable.appendChild( nTfoot );
+ }
+
+ nScroller.className = oClasses.sScrollWrapper;
+ nScrollHead.className = oClasses.sScrollHead;
+ nScrollHeadInner.className = oClasses.sScrollHeadInner;
+ nScrollBody.className = oClasses.sScrollBody;
+ nScrollFoot.className = oClasses.sScrollFoot;
+ nScrollFootInner.className = oClasses.sScrollFootInner;
+
+ if ( oSettings.oScroll.bAutoCss )
+ {
+ nScrollHead.style.overflow = "hidden";
+ nScrollHead.style.position = "relative";
+ nScrollFoot.style.overflow = "hidden";
+ nScrollBody.style.overflow = "auto";
+ }
+
+ nScrollHead.style.border = "0";
+ nScrollHead.style.width = "100%";
+ nScrollFoot.style.border = "0";
+ nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
+ oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
+
+ /* Modify attributes to respect the clones */
+ nScrollHeadTable.removeAttribute('id');
+ nScrollHeadTable.style.marginLeft = "0";
+ oSettings.nTable.style.marginLeft = "0";
+ if ( nTfoot !== null )
+ {
+ nScrollFootTable.removeAttribute('id');
+ nScrollFootTable.style.marginLeft = "0";
+ }
+
+ /* Move caption elements from the body to the header, footer or leave where it is
+ * depending on the configuration. Note that the DTD says there can be only one caption */
+ var nCaption = $(oSettings.nTable).children('caption');
+ if ( nCaption.length > 0 )
+ {
+ nCaption = nCaption[0];
+ if ( nCaption._captionSide === "top" )
+ {
+ nScrollHeadTable.appendChild( nCaption );
+ }
+ else if ( nCaption._captionSide === "bottom" && nTfoot )
+ {
+ nScrollFootTable.appendChild( nCaption );
+ }
+ }
+
+ /*
+ * Sizing
+ */
+ /* When x-scrolling add the width and a scroller to move the header with the body */
+ if ( oSettings.oScroll.sX !== "" )
+ {
+ nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
+ nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
+
+ if ( nTfoot !== null )
+ {
+ nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );
+ }
+
+ /* When the body is scrolled, then we also want to scroll the headers */
+ $(nScrollBody).scroll( function (e) {
+ nScrollHead.scrollLeft = this.scrollLeft;
+
+ if ( nTfoot !== null )
+ {
+ nScrollFoot.scrollLeft = this.scrollLeft;
+ }
+ } );
+ }
+
+ /* When yscrolling, add the height */
+ if ( oSettings.oScroll.sY !== "" )
+ {
+ nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
+ }
+
+ /* Redraw - align columns across the tables */
+ oSettings.aoDrawCallback.push( {
+ "fn": _fnScrollDraw,
+ "sName": "scrolling"
+ } );
+
+ /* Infinite scrolling event handlers */
+ if ( oSettings.oScroll.bInfinite )
+ {
+ $(nScrollBody).scroll( function() {
+ /* Use a blocker to stop scrolling from loading more data while other data is still loading */
+ if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
+ {
+ /* Check if we should load the next data set */
+ if ( $(this).scrollTop() + $(this).height() >
+ $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
+ {
+ /* Only do the redraw if we have to - we might be at the end of the data */
+ if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
+ {
+ _fnPageChange( oSettings, 'next' );
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+ }
+ } );
+ }
+
+ oSettings.nScrollHead = nScrollHead;
+ oSettings.nScrollFoot = nScrollFoot;
+
+ return nScroller;
+ }
+
+
+ /**
+ * Update the various tables for resizing. It's a bit of a pig this function, but
+ * basically the idea to:
+ * 1. Re-create the table inside the scrolling div
+ * 2. Take live measurements from the DOM
+ * 3. Apply the measurements
+ * 4. Clean up
+ * @param {object} o dataTables settings object
+ * @returns {node} Node to add to the DOM
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollDraw ( o )
+ {
+ var
+ nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
+ nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
+ nScrollBody = o.nTable.parentNode,
+ i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+ nTheadSize, nTfootSize,
+ iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
+ nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
+ nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
+ ie67 = o.oBrowser.bScrollOversize,
+ zeroOut = function(nSizer) {
+ oStyle = nSizer.style;
+ oStyle.paddingTop = "0";
+ oStyle.paddingBottom = "0";
+ oStyle.borderTopWidth = "0";
+ oStyle.borderBottomWidth = "0";
+ oStyle.height = 0;
+ };
+
+ /*
+ * 1. Re-create the table inside the scrolling div
+ */
+
+ /* Remove the old minimised thead and tfoot elements in the inner table */
+ $(o.nTable).children('thead, tfoot').remove();
+
+ /* Clone the current header and footer elements and then place it into the inner table */
+ nTheadSize = $(o.nTHead).clone()[0];
+ o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
+ anHeadToSize = o.nTHead.getElementsByTagName('tr');
+ anHeadSizers = nTheadSize.getElementsByTagName('tr');
+
+ if ( o.nTFoot !== null )
+ {
+ nTfootSize = $(o.nTFoot).clone()[0];
+ o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
+ anFootToSize = o.nTFoot.getElementsByTagName('tr');
+ anFootSizers = nTfootSize.getElementsByTagName('tr');
+ }
+
+ /*
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
+ */
+
+ /* Remove old sizing and apply the calculated column widths
+ * Get the unique column headers in the newly created (cloned) header. We want to apply the
+ * calculated sizes to this header
+ */
+ if ( o.oScroll.sX === "" )
+ {
+ nScrollBody.style.width = '100%';
+ nScrollHeadInner.parentNode.style.width = '100%';
+ }
+
+ var nThs = _fnGetUniqueThs( o, nTheadSize );
+ for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
+ {
+ iVis = _fnVisibleToColumnIndex( o, i );
+ nThs[i].style.width = o.aoColumns[iVis].sWidth;
+ }
+
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( function(n) {
+ n.style.width = "";
+ }, anFootSizers );
+ }
+
+ // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
+ // will end up forcing the scrollbar to appear, making our measurements wrong for when we
+ // then hide it (end of this function), so add the header height to the body scroller.
+ if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
+ {
+ nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
+ }
+
+ /* Size the table as a whole */
+ iSanityWidth = $(o.nTable).outerWidth();
+ if ( o.oScroll.sX === "" )
+ {
+ /* No x scrolling */
+ o.nTable.style.width = "100%";
+
+ /* I know this is rubbish - but IE7 will make the width of the table when 100% include
+ * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
+ * into account.
+ */
+ if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight ||
+ $(nScrollBody).css('overflow-y') == "scroll") )
+ {
+ o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
+ }
+ }
+ else
+ {
+ if ( o.oScroll.sXInner !== "" )
+ {
+ /* x scroll inner has been given - use it */
+ o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
+ }
+ else if ( iSanityWidth == $(nScrollBody).width() &&
+ $(nScrollBody).height() < $(o.nTable).height() )
+ {
+ /* There is y-scrolling - try to take account of the y scroll bar */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
+ if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
+ {
+ /* Not possible to take account of it */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+ else
+ {
+ /* All else fails */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+
+ /* Recalculate the sanity width - now that we've applied the required width, before it was
+ * a temporary variable. This is required because the column width calculation is done
+ * before this table DOM is created.
+ */
+ iSanityWidth = $(o.nTable).outerWidth();
+
+ /* We want the hidden header to have zero height, so remove padding and borders. Then
+ * set the width based on the real headers
+ */
+
+ // Apply all styles in one pass. Invalidates layout only once because we don't read any
+ // DOM properties.
+ _fnApplyToChildren( zeroOut, anHeadSizers );
+
+ // Read all widths in next pass. Forces layout only once because we do not change
+ // any DOM properties.
+ _fnApplyToChildren( function(nSizer) {
+ aApplied.push( _fnStringToCss( $(nSizer).width() ) );
+ }, anHeadSizers );
+
+ // Apply all widths in final pass. Invalidates layout only once because we do not
+ // read any DOM properties.
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = aApplied[i];
+ }, anHeadToSize );
+
+ $(anHeadSizers).height(0);
+
+ /* Same again with the footer if we have one */
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( zeroOut, anFootSizers );
+
+ _fnApplyToChildren( function(nSizer) {
+ aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
+ }, anFootSizers );
+
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = aAppliedFooter[i];
+ }, anFootToSize );
+
+ $(anFootSizers).height(0);
+ }
+
+ /*
+ * 3. Apply the measurements
+ */
+
+ /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
+ * to what they currently are
+ */
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = aApplied[i];
+ }, anHeadSizers );
+
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = aAppliedFooter[i];
+ }, anFootSizers );
+ }
+
+ /* Sanity check that the table is of a sensible width. If not then we are going to get
+ * misalignment - try to prevent this by not allowing the table to shrink below its min width
+ */
+ if ( $(o.nTable).outerWidth() < iSanityWidth )
+ {
+ /* The min width depends upon if we have a vertical scrollbar visible or not */
+ var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight ||
+ $(nScrollBody).css('overflow-y') == "scroll")) ?
+ iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
+
+ /* IE6/7 are a law unto themselves... */
+ if ( ie67 && (nScrollBody.scrollHeight >
+ nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") )
+ {
+ o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
+ }
+
+ /* Apply the calculated minimum width to the table wrappers */
+ nScrollBody.style.width = _fnStringToCss( iCorrection );
+ o.nScrollHead.style.width = _fnStringToCss( iCorrection );
+
+ if ( o.nTFoot !== null )
+ {
+ o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
+ }
+
+ /* And give the user a warning that we've stopped the table getting too small */
+ if ( o.oScroll.sX === "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. The table has been drawn at its minimum possible width." );
+ }
+ else if ( o.oScroll.sXInner !== "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
+ " calculation" );
+ }
+ }
+ else
+ {
+ nScrollBody.style.width = _fnStringToCss( '100%' );
+ o.nScrollHead.style.width = _fnStringToCss( '100%' );
+
+ if ( o.nTFoot !== null )
+ {
+ o.nScrollFoot.style.width = _fnStringToCss( '100%' );
+ }
+ }
+
+
+ /*
+ * 4. Clean up
+ */
+ if ( o.oScroll.sY === "" )
+ {
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+ * the scrollbar height from the visible display, rather than adding it on. We need to
+ * set the height in order to sort this. Don't want to do it in any other browsers.
+ */
+ if ( ie67 )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
+ }
+ }
+
+ if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
+
+ var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
+ o.oScroll.iBarWidth : 0;
+ if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
+ }
+ }
+
+ /* Finally set the width's of the header and footer tables */
+ var iOuterWidth = $(o.nTable).outerWidth();
+ nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
+
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+ var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
+ nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+
+ if ( o.nTFoot !== null )
+ {
+ nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+ }
+
+ /* Adjust the position of the header in case we loose the y-scrollbar */
+ $(nScrollBody).scroll();
+
+ /* If sorting or filtering has occurred, jump the scrolling back to the top */
+ if ( o.bSorted || o.bFiltered )
+ {
+ nScrollBody.scrollTop = 0;
+ }
+ }
+
+
+ /**
+ * Apply a given function to the display child nodes of an element array (typically
+ * TD children of TR rows
+ * @param {function} fn Method to apply to the objects
+ * @param array {nodes} an1 List of elements to look through for display children
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyToChildren( fn, an1, an2 )
+ {
+ var index=0, i=0, iLen=an1.length;
+ var nNode1, nNode2;
+
+ while ( i < iLen )
+ {
+ nNode1 = an1[i].firstChild;
+ nNode2 = an2 ? an2[i].firstChild : null;
+ while ( nNode1 )
+ {
+ if ( nNode1.nodeType === 1 )
+ {
+ if ( an2 )
+ {
+ fn( nNode1, nNode2, index );
+ }
+ else
+ {
+ fn( nNode1, index );
+ }
+ index++;
+ }
+ nNode1 = nNode1.nextSibling;
+ nNode2 = an2 ? nNode2.nextSibling : null;
+ }
+ i++;
+ }
+ }
+
+ /**
+ * Convert a CSS unit width to pixels (e.g. 2em)
+ * @param {string} sWidth width to be converted
+ * @param {node} nParent parent to get the with for (required for relative widths) - optional
+ * @returns {int} iWidth width in pixels
+ * @memberof DataTable#oApi
+ */
+ function _fnConvertToWidth ( sWidth, nParent )
+ {
+ if ( !sWidth || sWidth === null || sWidth === '' )
+ {
+ return 0;
+ }
+
+ if ( !nParent )
+ {
+ nParent = document.body;
+ }
+
+ var iWidth;
+ var nTmp = document.createElement( "div" );
+ nTmp.style.width = _fnStringToCss( sWidth );
+
+ nParent.appendChild( nTmp );
+ iWidth = nTmp.offsetWidth;
+ nParent.removeChild( nTmp );
+
+ return ( iWidth );
+ }
+
+
+ /**
+ * Calculate the width of columns for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnCalculateColumnWidths ( oSettings )
+ {
+ var iTableWidth = oSettings.nTable.offsetWidth;
+ var iUserInputs = 0;
+ var iTmpWidth;
+ var iVisibleColumns = 0;
+ var iColums = oSettings.aoColumns.length;
+ var i, iIndex, iCorrector, iWidth;
+ var oHeaders = $('th', oSettings.nTHead);
+ var widthAttr = oSettings.nTable.getAttribute('width');
+ var nWrapper = oSettings.nTable.parentNode;
+
+ /* Convert any user input sizes into pixel sizes */
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ iVisibleColumns++;
+
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
+ nWrapper );
+ if ( iTmpWidth !== null )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+ }
+
+ iUserInputs++;
+ }
+ }
+ }
+
+ /* If the number of columns in the DOM equals the number that we have to process in
+ * DataTables, then we can use the offsets that are created by the web-browser. No custom
+ * sizes can be set in order for this to happen, nor scrolling used
+ */
+ if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
+ oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+ {
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ iTmpWidth = $(oHeaders[i]).width();
+ if ( iTmpWidth !== null )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+ }
+ }
+ }
+ else
+ {
+ /* Otherwise we are going to have to do some calculations to get the width of each column.
+ * Construct a 1 row table with the widest node in the data, and any user defined widths,
+ * then insert it into the DOM and allow the browser to do all the hard work of
+ * calculating table widths.
+ */
+ var
+ nCalcTmp = oSettings.nTable.cloneNode( false ),
+ nTheadClone = oSettings.nTHead.cloneNode(true),
+ nBody = document.createElement( 'tbody' ),
+ nTr = document.createElement( 'tr' ),
+ nDivSizing;
+
+ nCalcTmp.removeAttribute( "id" );
+ nCalcTmp.appendChild( nTheadClone );
+ if ( oSettings.nTFoot !== null )
+ {
+ nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
+ _fnApplyToChildren( function(n) {
+ n.style.width = "";
+ }, nCalcTmp.getElementsByTagName('tr') );
+ }
+
+ nCalcTmp.appendChild( nBody );
+ nBody.appendChild( nTr );
+
+ /* Remove any sizing that was previously applied by the styles */
+ var jqColSizing = $('thead th', nCalcTmp);
+ if ( jqColSizing.length === 0 )
+ {
+ jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
+ }
+
+ /* Apply custom sizing to the cloned header */
+ var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
+ iCorrector = 0;
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ var oColumn = oSettings.aoColumns[i];
+ if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
+ {
+ nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
+ }
+ else if ( oColumn.bVisible )
+ {
+ nThs[i-iCorrector].style.width = "";
+ }
+ else
+ {
+ iCorrector++;
+ }
+ }
+
+ /* Find the biggest td for each column and put it into the table */
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ var nTd = _fnGetWidestNode( oSettings, i );
+ if ( nTd !== null )
+ {
+ nTd = nTd.cloneNode(true);
+ if ( oSettings.aoColumns[i].sContentPadding !== "" )
+ {
+ nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
+ }
+ nTr.appendChild( nTd );
+ }
+ }
+ }
+
+ /* Build the table and 'display' it */
+ nWrapper.appendChild( nCalcTmp );
+
+ /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
+ * when not scrolling leave the table width as it is. This results in slightly different,
+ * but I think correct behaviour
+ */
+ if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
+ {
+ nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
+ }
+ else if ( oSettings.oScroll.sX !== "" )
+ {
+ nCalcTmp.style.width = "";
+ if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
+ {
+ nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+ }
+ }
+ else if ( oSettings.oScroll.sY !== "" )
+ {
+ nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+ }
+ else if ( widthAttr )
+ {
+ nCalcTmp.style.width = _fnStringToCss( widthAttr );
+ }
+ nCalcTmp.style.visibility = "hidden";
+
+ /* Scrolling considerations */
+ _fnScrollingWidthAdjust( oSettings, nCalcTmp );
+
+ /* Read the width's calculated by the browser and store them for use by the caller. We
+ * first of all try to use the elements in the body, but it is possible that there are
+ * no elements there, under which circumstances we use the header elements
+ */
+ var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
+ if ( oNodes.length === 0 )
+ {
+ oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
+ }
+
+ /* Browsers need a bit of a hand when a width is assigned to any columns when
+ * x-scrolling as they tend to collapse the table to the min-width, even if
+ * we sent the column widths. So we need to keep track of what the table width
+ * should be by summing the user given values, and the automatic values
+ */
+ if ( oSettings.oScroll.sX !== "" )
+ {
+ var iTotal = 0;
+ iCorrector = 0;
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ if ( oSettings.aoColumns[i].sWidthOrig === null )
+ {
+ iTotal += $(oNodes[iCorrector]).outerWidth();
+ }
+ else
+ {
+ iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
+ ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
+ }
+ iCorrector++;
+ }
+ }
+
+ nCalcTmp.style.width = _fnStringToCss( iTotal );
+ oSettings.nTable.style.width = _fnStringToCss( iTotal );
+ }
+
+ iCorrector = 0;
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ iWidth = $(oNodes[iCorrector]).width();
+ if ( iWidth !== null && iWidth > 0 )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
+ }
+ iCorrector++;
+ }
+ }
+
+ var cssWidth = $(nCalcTmp).css('width');
+ oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
+ cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
+ nCalcTmp.parentNode.removeChild( nCalcTmp );
+ }
+
+ if ( widthAttr )
+ {
+ oSettings.nTable.style.width = _fnStringToCss( widthAttr );
+ }
+ }
+
+
+ /**
+ * Adjust a table's width to take account of scrolling
+ * @param {object} oSettings dataTables settings object
+ * @param {node} n table node
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollingWidthAdjust ( oSettings, n )
+ {
+ if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
+ {
+ /* When y-scrolling only, we want to remove the width of the scroll bar so the table
+ * + scroll bar will fit into the area avaialble.
+ */
+ var iOrigWidth = $(n).width();
+ n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
+ }
+ else if ( oSettings.oScroll.sX !== "" )
+ {
+ /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
+ n.style.width = _fnStringToCss( $(n).outerWidth() );
+ }
+ }
+
+
+ /**
+ * Get the widest node
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column of interest
+ * @returns {node} widest table node
+ * @memberof DataTable#oApi
+ */
+ function _fnGetWidestNode( oSettings, iCol )
+ {
+ var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
+ if ( iMaxIndex < 0 )
+ {
+ return null;
+ }
+
+ if ( oSettings.aoData[iMaxIndex].nTr === null )
+ {
+ var n = document.createElement('td');
+ n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
+ return n;
+ }
+ return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
+ }
+
+
+ /**
+ * Get the maximum strlen for each data column
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column of interest
+ * @returns {string} max string length for each column
+ * @memberof DataTable#oApi
+ */
+ function _fnGetMaxLenString( oSettings, iCol )
+ {
+ var iMax = -1;
+ var iMaxIndex = -1;
+
+ for ( var i=0 ; i<oSettings.aoData.length ; i++ )
+ {
+ var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
+ s = s.replace( /<.*?>/g, "" );
+ if ( s.length > iMax )
+ {
+ iMax = s.length;
+ iMaxIndex = i;
+ }
+ }
+
+ return iMaxIndex;
+ }
+
+
+ /**
+ * Append a CSS unit (only if required) to a string
+ * @param {array} aArray1 first array
+ * @param {array} aArray2 second array
+ * @returns {int} 0 if match, 1 if length is different, 2 if no match
+ * @memberof DataTable#oApi
+ */
+ function _fnStringToCss( s )
+ {
+ if ( s === null )
+ {
+ return "0px";
+ }
+
+ if ( typeof s == 'number' )
+ {
+ if ( s < 0 )
+ {
+ return "0px";
+ }
+ return s+"px";
+ }
+
+ /* Check if the last character is not 0-9 */
+ var c = s.charCodeAt( s.length-1 );
+ if (c < 0x30 || c > 0x39)
+ {
+ return s;
+ }
+ return s+"px";
+ }
+
+
+ /**
+ * Get the width of a scroll bar in this browser being used
+ * @returns {int} width in pixels
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollBarWidth ()
+ {
+ var inner = document.createElement('p');
+ var style = inner.style;
+ style.width = "100%";
+ style.height = "200px";
+ style.padding = "0px";
+
+ var outer = document.createElement('div');
+ style = outer.style;
+ style.position = "absolute";
+ style.top = "0px";
+ style.left = "0px";
+ style.visibility = "hidden";
+ style.width = "200px";
+ style.height = "150px";
+ style.padding = "0px";
+ style.overflow = "hidden";
+ outer.appendChild(inner);
+
+ document.body.appendChild(outer);
+ var w1 = inner.offsetWidth;
+ outer.style.overflow = 'scroll';
+ var w2 = inner.offsetWidth;
+ if ( w1 == w2 )
+ {
+ w2 = outer.clientWidth;
+ }
+
+ document.body.removeChild(outer);
+ return (w1 - w2);
+ }
+
+ /**
+ * Change the order of the table
+ * @param {object} oSettings dataTables settings object
+ * @param {bool} bApplyClasses optional - should we apply classes or not
+ * @memberof DataTable#oApi
+ */
+ function _fnSort ( oSettings, bApplyClasses )
+ {
+ var
+ i, iLen, j, jLen, k, kLen,
+ sDataType, nTh,
+ aaSort = [],
+ aiOrig = [],
+ oSort = DataTable.ext.oSort,
+ aoData = oSettings.aoData,
+ aoColumns = oSettings.aoColumns,
+ oAria = oSettings.oLanguage.oAria;
+
+ /* No sorting required if server-side or no sorting array */
+ if ( !oSettings.oFeatures.bServerSide &&
+ (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
+ {
+ aaSort = ( oSettings.aaSortingFixed !== null ) ?
+ oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+ oSettings.aaSorting.slice();
+
+ /* If there is a sorting data type, and a function belonging to it, then we need to
+ * get the data from the developer's function and apply it for this column
+ */
+ for ( i=0 ; i<aaSort.length ; i++ )
+ {
+ var iColumn = aaSort[i][0];
+ var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+ sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
+ if ( DataTable.ext.afnSortData[sDataType] )
+ {
+ var aData = DataTable.ext.afnSortData[sDataType].call(
+ oSettings.oInstance, oSettings, iColumn, iVisColumn
+ );
+ if ( aData.length === aoData.length )
+ {
+ for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
+ {
+ _fnSetCellData( oSettings, j, iColumn, aData[j] );
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
+ }
+ }
+ }
+
+ /* Create a value - key array of the current row positions such that we can use their
+ * current position during the sort, if values match, in order to perform stable sorting
+ */
+ for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
+ {
+ aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
+ }
+
+ /* Build an internal data array which is specific to the sort, so we can get and prep
+ * the data to be sorted only once, rather than needing to do it every time the sorting
+ * function runs. This make the sorting function a very simple comparison
+ */
+ var iSortLen = aaSort.length;
+ var fnSortFormat, aDataSort;
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ for ( j=0 ; j<iSortLen ; j++ )
+ {
+ aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
+
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+ {
+ sDataType = aoColumns[ aDataSort[k] ].sType;
+ fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
+
+ aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
+ fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
+ _fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
+ }
+ }
+ }
+
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
+ * follow on it's own, but this is what we want (example two column sorting):
+ * fnLocalSorting = function(a,b){
+ * var iTest;
+ * iTest = oSort['string-asc']('data11', 'data12');
+ * if (iTest !== 0)
+ * return iTest;
+ * iTest = oSort['numeric-desc']('data21', 'data22');
+ * if (iTest !== 0)
+ * return iTest;
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+ * }
+ * Basically we have a test for each sorting column, if the data in that column is equal,
+ * test the next column. If all columns match, then we use a numeric sort on the row
+ * positions in the original data array to provide a stable sort.
+ */
+ oSettings.aiDisplayMaster.sort( function ( a, b ) {
+ var k, l, lLen, iTest, aDataSort, sDataType;
+ for ( k=0 ; k<iSortLen ; k++ )
+ {
+ aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
+
+ for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
+ {
+ sDataType = aoColumns[ aDataSort[l] ].sType;
+
+ iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
+ aoData[a]._aSortData[ aDataSort[l] ],
+ aoData[b]._aSortData[ aDataSort[l] ]
+ );
+
+ if ( iTest !== 0 )
+ {
+ return iTest;
+ }
+ }
+ }
+
+ return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+ } );
+ }
+
+ /* Alter the sorting classes to take account of the changes */
+ if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
+ {
+ _fnSortingClasses( oSettings );
+ }
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
+ nTh = aoColumns[i].nTh;
+ nTh.removeAttribute('aria-sort');
+ nTh.removeAttribute('aria-label');
+
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
+ if ( aoColumns[i].bSortable )
+ {
+ if ( aaSort.length > 0 && aaSort[0][0] == i )
+ {
+ nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
+
+ var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ?
+ aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
+ nTh.setAttribute('aria-label', sTitle+
+ (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+ }
+ else
+ {
+ nTh.setAttribute('aria-label', sTitle+
+ (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+ }
+ }
+ else
+ {
+ nTh.setAttribute('aria-label', sTitle);
+ }
+ }
+
+ /* Tell the draw function that we have sorted the data */
+ oSettings.bSorted = true;
+ $(oSettings.oInstance).trigger('sort', oSettings);
+
+ /* Copy the master data into the draw array and re-draw */
+ if ( oSettings.oFeatures.bFilter )
+ {
+ /* _fnFilter() will redraw the table for us */
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ oSettings._iDisplayStart = 0; /* reset display back to page 0 */
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+
+
+ /**
+ * Attach a sort handler (click) to a node
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nNode node to attach the handler to
+ * @param {int} iDataIndex column sorting index
+ * @param {function} [fnCallback] callback function
+ * @memberof DataTable#oApi
+ */
+ function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
+ {
+ _fnBindAction( nNode, {}, function (e) {
+ /* If the column is not sortable - don't to anything */
+ if ( oSettings.aoColumns[iDataIndex].bSortable === false )
+ {
+ return;
+ }
+
+ /*
+ * This is a little bit odd I admit... I declare a temporary function inside the scope of
+ * _fnBuildHead and the click handler in order that the code presented here can be used
+ * twice - once for when bProcessing is enabled, and another time for when it is
+ * disabled, as we need to perform slightly different actions.
+ * Basically the issue here is that the Javascript engine in modern browsers don't
+ * appear to allow the rendering engine to update the display while it is still executing
+ * it's thread (well - it does but only after long intervals). This means that the
+ * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
+ * I force an execution break by using setTimeout - but this breaks the expected
+ * thread continuation for the end-developer's point of view (their code would execute
+ * too early), so we only do it when we absolutely have to.
+ */
+ var fnInnerSorting = function () {
+ var iColumn, iNextSort;
+
+ /* If the shift key is pressed then we are multiple column sorting */
+ if ( e.shiftKey )
+ {
+ /* Are we already doing some kind of sort on this column? */
+ var bFound = false;
+ for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
+ {
+ if ( oSettings.aaSorting[i][0] == iDataIndex )
+ {
+ bFound = true;
+ iColumn = oSettings.aaSorting[i][0];
+ iNextSort = oSettings.aaSorting[i][2]+1;
+
+ if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+ {
+ /* Reached the end of the sorting options, remove from multi-col sort */
+ oSettings.aaSorting.splice( i, 1 );
+ }
+ else
+ {
+ /* Move onto next sorting direction */
+ oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+ oSettings.aaSorting[i][2] = iNextSort;
+ }
+ break;
+ }
+ }
+
+ /* No sort yet - add it in */
+ if ( bFound === false )
+ {
+ oSettings.aaSorting.push( [ iDataIndex,
+ oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+ }
+ }
+ else
+ {
+ /* If no shift key then single column sort */
+ if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
+ {
+ iColumn = oSettings.aaSorting[0][0];
+ iNextSort = oSettings.aaSorting[0][2]+1;
+ if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+ {
+ iNextSort = 0;
+ }
+ oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+ oSettings.aaSorting[0][2] = iNextSort;
+ }
+ else
+ {
+ oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
+ oSettings.aaSorting.push( [ iDataIndex,
+ oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+ }
+ }
+
+ /* Run the sort */
+ _fnSort( oSettings );
+ }; /* /fnInnerSorting */
+
+ if ( !oSettings.oFeatures.bProcessing )
+ {
+ fnInnerSorting();
+ }
+ else
+ {
+ _fnProcessingDisplay( oSettings, true );
+ setTimeout( function() {
+ fnInnerSorting();
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ }
+ }, 0 );
+ }
+
+ /* Call the user specified callback function - used for async user interaction */
+ if ( typeof fnCallback == 'function' )
+ {
+ fnCallback( oSettings );
+ }
+ } );
+ }
+
+
+ /**
+ * Set the sorting classes on the header, Note: it is safe to call this function
+ * when bSort and bSortClasses are false
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSortingClasses( oSettings )
+ {
+ var i, iLen, j, jLen, iFound;
+ var aaSort, sClass;
+ var iColumns = oSettings.aoColumns.length;
+ var oClasses = oSettings.oClasses;
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
+ " "+ oSettings.aoColumns[i].sSortingClass );
+ }
+ }
+
+ if ( oSettings.aaSortingFixed !== null )
+ {
+ aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+ }
+ else
+ {
+ aaSort = oSettings.aaSorting.slice();
+ }
+
+ /* Apply the required classes to the header */
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ sClass = oSettings.aoColumns[i].sSortingClass;
+ iFound = -1;
+ for ( j=0 ; j<aaSort.length ; j++ )
+ {
+ if ( aaSort[j][0] == i )
+ {
+ sClass = ( aaSort[j][1] == "asc" ) ?
+ oClasses.sSortAsc : oClasses.sSortDesc;
+ iFound = j;
+ break;
+ }
+ }
+ $(oSettings.aoColumns[i].nTh).addClass( sClass );
+
+ if ( oSettings.bJUI )
+ {
+ /* jQuery UI uses extra markup */
+ var jqSpan = $("span."+oClasses.sSortIcon, oSettings.aoColumns[i].nTh);
+ jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+
+ oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
+
+ var sSpanClass;
+ if ( iFound == -1 )
+ {
+ sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
+ }
+ else if ( aaSort[iFound][1] == "asc" )
+ {
+ sSpanClass = oClasses.sSortJUIAsc;
+ }
+ else
+ {
+ sSpanClass = oClasses.sSortJUIDesc;
+ }
+
+ jqSpan.addClass( sSpanClass );
+ }
+ }
+ else
+ {
+ /* No sorting on this column, so add the base class. This will have been assigned by
+ * _fnAddColumn
+ */
+ $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
+ }
+ }
+
+ /*
+ * Apply the required classes to the table body
+ * Note that this is given as a feature switch since it can significantly slow down a sort
+ * on large data sets (adding and removing of classes is always slow at the best of times..)
+ * Further to this, note that this code is admittedly fairly ugly. It could be made a lot
+ * simpler using jQuery selectors and add/removeClass, but that is significantly slower
+ * (on the order of 5 times slower) - hence the direct DOM manipulation here.
+ * Note that for deferred drawing we do use jQuery - the reason being that taking the first
+ * row found to see if the whole column needs processed can miss classes since the first
+ * column might be new.
+ */
+ sClass = oClasses.sSortColumn;
+
+ if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
+ {
+ var nTds = _fnGetTdNodes( oSettings );
+
+ /* Determine what the sorting class for each column should be */
+ var iClass, iTargetCol;
+ var asClasses = [];
+ for (i = 0; i < iColumns; i++)
+ {
+ asClasses.push("");
+ }
+ for (i = 0, iClass = 1; i < aaSort.length; i++)
+ {
+ iTargetCol = parseInt( aaSort[i][0], 10 );
+ asClasses[iTargetCol] = sClass + iClass;
+
+ if ( iClass < 3 )
+ {
+ iClass++;
+ }
+ }
+
+ /* Make changes to the classes for each cell as needed */
+ var reClass = new RegExp(sClass + "[123]");
+ var sTmpClass, sCurrentClass, sNewClass;
+ for ( i=0, iLen=nTds.length; i<iLen; i++ )
+ {
+ /* Determine which column we're looking at */
+ iTargetCol = i % iColumns;
+
+ /* What is the full list of classes now */
+ sCurrentClass = nTds[i].className;
+ /* What sorting class should be applied? */
+ sNewClass = asClasses[iTargetCol];
+ /* What would the new full list be if we did a replacement? */
+ sTmpClass = sCurrentClass.replace(reClass, sNewClass);
+
+ if ( sTmpClass != sCurrentClass )
+ {
+ /* We changed something */
+ nTds[i].className = $.trim( sTmpClass );
+ }
+ else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
+ {
+ /* We need to add a class */
+ nTds[i].className = sCurrentClass + " " + sNewClass;
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Save the state of a table in a cookie such that the page can be reloaded
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSaveState ( oSettings )
+ {
+ if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
+ {
+ return;
+ }
+
+ /* Store the interesting variables */
+ var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
+ var oState = {
+ "iCreate": new Date().getTime(),
+ "iStart": (bInfinite ? 0 : oSettings._iDisplayStart),
+ "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
+ "iLength": oSettings._iDisplayLength,
+ "aaSorting": $.extend( true, [], oSettings.aaSorting ),
+ "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ),
+ "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
+ "abVisCols": []
+ };
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
+ }
+
+ _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
+
+ oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
+ }
+
+
+ /**
+ * Attempt to load a saved table state from a cookie
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oInit DataTables init object so we can override settings
+ * @memberof DataTable#oApi
+ */
+ function _fnLoadState ( oSettings, oInit )
+ {
+ if ( !oSettings.oFeatures.bStateSave )
+ {
+ return;
+ }
+
+ var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
+ if ( !oData )
+ {
+ return;
+ }
+
+ /* Allow custom and plug-in manipulation functions to alter the saved data set and
+ * cancelling of loading by returning false
+ */
+ var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
+ if ( $.inArray( false, abStateLoad ) !== -1 )
+ {
+ return;
+ }
+
+ /* Store the saved state so it might be accessed at any time */
+ oSettings.oLoadedState = $.extend( true, {}, oData );
+
+ /* Restore key features */
+ oSettings._iDisplayStart = oData.iStart;
+ oSettings.iInitDisplayStart = oData.iStart;
+ oSettings._iDisplayEnd = oData.iEnd;
+ oSettings._iDisplayLength = oData.iLength;
+ oSettings.aaSorting = oData.aaSorting.slice();
+ oSettings.saved_aaSorting = oData.aaSorting.slice();
+
+ /* Search filtering */
+ $.extend( oSettings.oPreviousSearch, oData.oSearch );
+ $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
+
+ /* Column visibility state
+ * Pass back visibility settings to the init handler, but to do not here override
+ * the init object that the user might have passed in
+ */
+ oInit.saved_aoColumns = [];
+ for ( var i=0 ; i<oData.abVisCols.length ; i++ )
+ {
+ oInit.saved_aoColumns[i] = {};
+ oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
+ }
+
+ _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
+ }
+
+
+ /**
+ * Create a new cookie with a value to store the state of a table
+ * @param {string} sName name of the cookie to create
+ * @param {string} sValue the value the cookie should take
+ * @param {int} iSecs duration of the cookie
+ * @param {string} sBaseName sName is made up of the base + file name - this is the base
+ * @param {function} fnCallback User definable function to modify the cookie
+ * @memberof DataTable#oApi
+ */
+ function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
+ {
+ var date = new Date();
+ date.setTime( date.getTime()+(iSecs*1000) );
+
+ /*
+ * Shocking but true - it would appear IE has major issues with having the path not having
+ * a trailing slash on it. We need the cookie to be available based on the path, so we
+ * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
+ * patch to use at least some of the path
+ */
+ var aParts = window.location.pathname.split('/');
+ var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+ var sFullCookie, oData;
+
+ if ( fnCallback !== null )
+ {
+ oData = (typeof $.parseJSON === 'function') ?
+ $.parseJSON( sValue ) : eval( '('+sValue+')' );
+ sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
+ aParts.join('/')+"/" );
+ }
+ else
+ {
+ sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
+ "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
+ }
+
+ /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
+ * belonging to DataTables.
+ */
+ var
+ aCookies =document.cookie.split(';'),
+ iNewCookieLen = sFullCookie.split(';')[0].length,
+ aOldCookies = [];
+
+ if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
+ {
+ for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
+ {
+ if ( aCookies[i].indexOf( sBaseName ) != -1 )
+ {
+ /* It's a DataTables cookie, so eval it and check the time stamp */
+ var aSplitCookie = aCookies[i].split('=');
+ try {
+ oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
+
+ if ( oData && oData.iCreate )
+ {
+ aOldCookies.push( {
+ "name": aSplitCookie[0],
+ "time": oData.iCreate
+ } );
+ }
+ }
+ catch( e ) {}
+ }
+ }
+
+ // Make sure we delete the oldest ones first
+ aOldCookies.sort( function (a, b) {
+ return b.time - a.time;
+ } );
+
+ // Eliminate as many old DataTables cookies as we need to
+ while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
+ if ( aOldCookies.length === 0 ) {
+ // Deleted all DT cookies and still not enough space. Can't state save
+ return;
+ }
+
+ var old = aOldCookies.pop();
+ document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+ aParts.join('/') + "/";
+ }
+ }
+
+ document.cookie = sFullCookie;
+ }
+
+
+ /**
+ * Read an old cookie to get a cookie with an old table state
+ * @param {string} sName name of the cookie to read
+ * @returns {string} contents of the cookie - or null if no cookie with that name found
+ * @memberof DataTable#oApi
+ */
+ function _fnReadCookie ( sName )
+ {
+ var
+ aParts = window.location.pathname.split('/'),
+ sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
+ sCookieContents = document.cookie.split(';');
+
+ for( var i=0 ; i<sCookieContents.length ; i++ )
+ {
+ var c = sCookieContents[i];
+
+ while (c.charAt(0)==' ')
+ {
+ c = c.substring(1,c.length);
+ }
+
+ if (c.indexOf(sNameEQ) === 0)
+ {
+ return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Return the settings object for a particular table
+ * @param {node} nTable table we are using as a dataTable
+ * @returns {object} Settings object - or null if not found
+ * @memberof DataTable#oApi
+ */
+ function _fnSettingsFromNode ( nTable )
+ {
+ for ( var i=0 ; i<DataTable.settings.length ; i++ )
+ {
+ if ( DataTable.settings[i].nTable === nTable )
+ {
+ return DataTable.settings[i];
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Return an array with the TR nodes for the table
+ * @param {object} oSettings dataTables settings object
+ * @returns {array} TR array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetTrNodes ( oSettings )
+ {
+ var aNodes = [];
+ var aoData = oSettings.aoData;
+ for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ aNodes.push( aoData[i].nTr );
+ }
+ }
+ return aNodes;
+ }
+
+
+ /**
+ * Return an flat array with all TD nodes for the table, or row
+ * @param {object} oSettings dataTables settings object
+ * @param {int} [iIndividualRow] aoData index to get the nodes for - optional
+ * if not given then the return array will contain all nodes for the table
+ * @returns {array} TD array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetTdNodes ( oSettings, iIndividualRow )
+ {
+ var anReturn = [];
+ var iCorrector;
+ var anTds, nTd;
+ var iRow, iRows=oSettings.aoData.length,
+ iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
+
+ /* Allow the collection to be limited to just one row */
+ if ( iIndividualRow !== undefined )
+ {
+ iStart = iIndividualRow;
+ iEnd = iIndividualRow+1;
+ }
+
+ for ( iRow=iStart ; iRow<iEnd ; iRow++ )
+ {
+ oData = oSettings.aoData[iRow];
+ if ( oData.nTr !== null )
+ {
+ /* get the TD child nodes - taking into account text etc nodes */
+ anTds = [];
+ nTd = oData.nTr.firstChild;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toLowerCase();
+ if ( sNodeName == 'td' || sNodeName == 'th' )
+ {
+ anTds.push( nTd );
+ }
+ nTd = nTd.nextSibling;
+ }
+
+ iCorrector = 0;
+ for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+ {
+ if ( oSettings.aoColumns[iColumn].bVisible )
+ {
+ anReturn.push( anTds[iColumn-iCorrector] );
+ }
+ else
+ {
+ anReturn.push( oData._anHidden[iColumn] );
+ iCorrector++;
+ }
+ }
+ }
+ }
+
+ return anReturn;
+ }
+
+
+ /**
+ * Log an error message
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iLevel log error messages, or display them to the user
+ * @param {string} sMesg error message
+ * @memberof DataTable#oApi
+ */
+ function _fnLog( oSettings, iLevel, sMesg )
+ {
+ var sAlert = (oSettings===null) ?
+ "DataTables warning: "+sMesg :
+ "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
+
+ if ( iLevel === 0 )
+ {
+ if ( DataTable.ext.sErrMode == 'alert' )
+ {
+ alert( sAlert );
+ }
+ else
+ {
+ throw new Error(sAlert);
+ }
+ return;
+ }
+ else if ( window.console && console.log )
+ {
+ console.log( sAlert );
+ }
+ }
+
+
+ /**
+ * See if a property is defined on one object, if so assign it to the other object
+ * @param {object} oRet target object
+ * @param {object} oSrc source object
+ * @param {string} sName property
+ * @param {string} [sMappedName] name to map too - optional, sName used if not given
+ * @memberof DataTable#oApi
+ */
+ function _fnMap( oRet, oSrc, sName, sMappedName )
+ {
+ if ( sMappedName === undefined )
+ {
+ sMappedName = sName;
+ }
+ if ( oSrc[sName] !== undefined )
+ {
+ oRet[sMappedName] = oSrc[sName];
+ }
+ }
+
+
+ /**
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
+ * copy arrays. The reason we need to do this, is that we don't want to deep copy array
+ * init values (such as aaSorting) since the dev wouldn't be able to override them, but
+ * we do want to deep copy arrays.
+ * @param {object} oOut Object to extend
+ * @param {object} oExtender Object from which the properties will be applied to oOut
+ * @returns {object} oOut Reference, just for convenience - oOut === the return.
+ * @memberof DataTable#oApi
+ * @todo This doesn't take account of arrays inside the deep copied objects.
+ */
+ function _fnExtend( oOut, oExtender )
+ {
+ var val;
+
+ for ( var prop in oExtender )
+ {
+ if ( oExtender.hasOwnProperty(prop) )
+ {
+ val = oExtender[prop];
+
+ if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
+ {
+ $.extend( true, oOut[prop], val );
+ }
+ else
+ {
+ oOut[prop] = val;
+ }
+ }
+ }
+
+ return oOut;
+ }
+
+
+ /**
+ * Bind an event handers to allow a click or return key to activate the callback.
+ * This is good for accessibility since a return on the keyboard will have the
+ * same effect as a click, if the element has focus.
+ * @param {element} n Element to bind the action to
+ * @param {object} oData Data object to pass to the triggered function
+ * @param {function} fn Callback function for when the event is triggered
+ * @memberof DataTable#oApi
+ */
+ function _fnBindAction( n, oData, fn )
+ {
+ $(n)
+ .bind( 'click.DT', oData, function (e) {
+ n.blur(); // Remove focus outline for mouse users
+ fn(e);
+ } )
+ .bind( 'keypress.DT', oData, function (e){
+ if ( e.which === 13 ) {
+ fn(e);
+ } } )
+ .bind( 'selectstart.DT', function () {
+ /* Take the brutal approach to cancelling text selection */
+ return false;
+ } );
+ }
+
+
+ /**
+ * Register a callback function. Easily allows a callback function to be added to
+ * an array store of callback functions that can then all be called together.
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {function} fn Function to be called back
+ * @param {string} sName Identifying name for the callback (i.e. a label)
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
+ {
+ if ( fn )
+ {
+ oSettings[sStore].push( {
+ "fn": fn,
+ "sName": sName
+ } );
+ }
+ }
+
+
+ /**
+ * Fire callback functions and trigger events. Note that the loop over the callback
+ * array store is done backwards! Further note that you do not want to fire off triggers
+ * in time sensitive applications (for example cell creation) as its slow.
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
+ * is fired
+ * @param {array} aArgs Array of arguments to pass to the callback function / trigger
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
+ {
+ var aoStore = oSettings[sStore];
+ var aRet =[];
+
+ for ( var i=aoStore.length-1 ; i>=0 ; i-- )
+ {
+ aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
+ }
+
+ if ( sTrigger !== null )
+ {
+ $(oSettings.oInstance).trigger(sTrigger, aArgs);
+ }
+
+ return aRet;
+ }
+
+
+ /**
+ * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
+ * library, then we use that as it is fast, safe and accurate. If the function isn't
+ * available then we need to built it ourselves - the inspiration for this function comes
+ * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
+ * not perfect and absolutely should not be used as a replacement to json2.js - but it does
+ * do what we need, without requiring a dependency for DataTables.
+ * @param {object} o JSON object to be converted
+ * @returns {string} JSON string
+ * @memberof DataTable#oApi
+ */
+ var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
+ {
+ /* Not an object or array */
+ var sType = typeof o;
+ if (sType !== "object" || o === null)
+ {
+ // simple data type
+ if (sType === "string")
+ {
+ o = '"'+o+'"';
+ }
+ return o+"";
+ }
+
+ /* If object or array, need to recurse over it */
+ var
+ sProp, mValue,
+ json = [],
+ bArr = $.isArray(o);
+
+ for (sProp in o)
+ {
+ mValue = o[sProp];
+ sType = typeof mValue;
+
+ if (sType === "string")
+ {
+ mValue = '"'+mValue+'"';
+ }
+ else if (sType === "object" && mValue !== null)
+ {
+ mValue = _fnJsonString(mValue);
+ }
+
+ json.push((bArr ? "" : '"'+sProp+'":') + mValue);
+ }
+
+ return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
+ };
+
+
+ /**
+ * From some browsers (specifically IE6/7) we need special handling to work around browser
+ * bugs - this function is used to detect when these workarounds are needed.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBrowserDetect( oSettings )
+ {
+ /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
+ * width of the scrollbar, while other browsers ensure the inner element is contained
+ * without forcing scrolling
+ */
+ var n = $(
+ '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
+ '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
+ '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
+ '</div>'+
+ '</div>')[0];
+
+ document.body.appendChild( n );
+ oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
+ document.body.removeChild( n );
+ }
+
+
+ /**
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
+ * return the resulting jQuery object.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
+ * criterion ("applied") or all TR elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {object} jQuery object, filtered by the given selector.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Highlight every second row
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
+ * oTable.fnFilter('Webkit');
+ * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
+ * oTable.fnFilter('');
+ * } );
+ */
+ this.$ = function ( sSelector, oOpts )
+ {
+ var i, iLen, a = [], tr;
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var aoData = oSettings.aoData;
+ var aiDisplay = oSettings.aiDisplay;
+ var aiDisplayMaster = oSettings.aiDisplayMaster;
+
+ if ( !oOpts )
+ {
+ oOpts = {};
+ }
+
+ oOpts = $.extend( {}, {
+ "filter": "none", // applied
+ "order": "current", // "original"
+ "page": "all" // current
+ }, oOpts );
+
+ // Current page implies that order=current and fitler=applied, since it is fairly
+ // senseless otherwise
+ if ( oOpts.page == 'current' )
+ {
+ for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplay[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "current" && oOpts.filter == "none" )
+ {
+ for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplayMaster[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "current" && oOpts.filter == "applied" )
+ {
+ for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplay[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "original" && oOpts.filter == "none" )
+ {
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ i ].nTr ;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "original" && oOpts.filter == "applied" )
+ {
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ i ].nTr;
+ if ( $.inArray( i, aiDisplay ) !== -1 && tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 1, "Unknown selection options" );
+ }
+
+ /* We need to filter on the TR elements and also 'find' in their descendants
+ * to make the selector act like it would in a full table - so we need
+ * to build both results and then combine them together
+ */
+ var jqA = $(a);
+ var jqTRs = jqA.filter( sSelector );
+ var jqDescendants = jqA.find( sSelector );
+
+ return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
+ };
+
+
+ /**
+ * Almost identical to $ in operation, but in this case returns the data for the matched
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
+ * rows are found, the data returned is the original data array/object that was used to
+ * create the row (or a generated array if from a DOM source).
+ *
+ * This method is often useful in-combination with $ where both functions are given the
+ * same parameters and the array indexes will match identically.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
+ * criterion ("applied") or all elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
+ * entry in the array.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the data from the first row in the table
+ * var data = oTable._('tr:first');
+ *
+ * // Do something useful with the data
+ * alert( "First cell is: "+data[0] );
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to 'Webkit' and get all data for
+ * oTable.fnFilter('Webkit');
+ * var data = oTable._('tr', {"filter": "applied"});
+ *
+ * // Do something with the data
+ * alert( data.length+" rows matched the filter" );
+ * } );
+ */
+ this._ = function ( sSelector, oOpts )
+ {
+ var aOut = [];
+ var i, iLen, iIndex;
+ var aTrs = this.$( sSelector, oOpts );
+
+ for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
+ {
+ aOut.push( this.fnGetData(aTrs[i]) );
+ }
+
+ return aOut;
+ };
+
+
+ /**
+ * Add a single new row or multiple rows of data to the table. Please note
+ * that this is suitable for client-side processing only - if you are using
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
+ * @param {array|object} mData The data to be added to the table. This can be:
+ * <ul>
+ * <li>1D array of data - add a single row with the data provided</li>
+ * <li>2D array of arrays - add multiple rows in a single call</li>
+ * <li>object - data object when using <i>mData</i></li>
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
+ * </ul>
+ * @param {bool} [bRedraw=true] redraw the table or not
+ * @returns {array} An array of integers, representing the list of indexes in
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
+ * the table.
+ * @dtopt API
+ *
+ * @example
+ * // Global var for counter
+ * var giCount = 2;
+ *
+ * $(document).ready(function() {
+ * $('#example').dataTable();
+ * } );
+ *
+ * function fnClickAddRow() {
+ * $('#example').dataTable().fnAddData( [
+ * giCount+".1",
+ * giCount+".2",
+ * giCount+".3",
+ * giCount+".4" ]
+ * );
+ *
+ * giCount++;
+ * }
+ */
+ this.fnAddData = function( mData, bRedraw )
+ {
+ if ( mData.length === 0 )
+ {
+ return [];
+ }
+
+ var aiReturn = [];
+ var iTest;
+
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ /* Check if we want to add multiple rows or not */
+ if ( typeof mData[0] === "object" && mData[0] !== null )
+ {
+ for ( var i=0 ; i<mData.length ; i++ )
+ {
+ iTest = _fnAddData( oSettings, mData[i] );
+ if ( iTest == -1 )
+ {
+ return aiReturn;
+ }
+ aiReturn.push( iTest );
+ }
+ }
+ else
+ {
+ iTest = _fnAddData( oSettings, mData );
+ if ( iTest == -1 )
+ {
+ return aiReturn;
+ }
+ aiReturn.push( iTest );
+ }
+
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnReDraw( oSettings );
+ }
+ return aiReturn;
+ };
+
+
+ /**
+ * This function will make DataTables recalculate the column sizes, based on the data
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
+ * through the sWidth parameter). This can be useful when the width of the table's
+ * parent element changes (for example a window resize).
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ *
+ * $(window).bind('resize', function () {
+ * oTable.fnAdjustColumnSizing();
+ * } );
+ * } );
+ */
+ this.fnAdjustColumnSizing = function ( bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
+ _fnAdjustColumnSizing( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ this.fnDraw( false );
+ }
+ else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+ {
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
+ this.oApi._fnScrollDraw(oSettings);
+ }
+ };
+
+
+ /**
+ * Quickly and simply clear a table
+ * @param {bool} [bRedraw=true] redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
+ * oTable.fnClearTable();
+ * } );
+ */
+ this.fnClearTable = function( bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ _fnClearTable( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * The exact opposite of 'opening' a row, this function will close any rows which
+ * are currently 'open'.
+ * @param {node} nTr the table row to 'close'
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnClose = function( nTr )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+ {
+ if ( oSettings.aoOpenRows[i].nParent == nTr )
+ {
+ var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
+ if ( nTrParent )
+ {
+ /* Remove it if it is currently on display */
+ nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
+ }
+ oSettings.aoOpenRows.splice( i, 1 );
+ return 0;
+ }
+ }
+ return 1;
+ };
+
+
+ /**
+ * Remove a row for the table
+ * @param {mixed} mTarget The index of the row from aoData to be deleted, or
+ * the TR element you want to delete
+ * @param {function|null} [fnCallBack] Callback function
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @returns {array} The row that was deleted
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately remove the first row
+ * oTable.fnDeleteRow( 0 );
+ * } );
+ */
+ this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen, iAODataIndex;
+
+ iAODataIndex = (typeof mTarget === 'object') ?
+ _fnNodeToDataIndex(oSettings, mTarget) : mTarget;
+
+ /* Return the data array from this row */
+ var oData = oSettings.aoData.splice( iAODataIndex, 1 );
+
+ /* Update the _DT_RowIndex parameter */
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoData[i].nTr !== null )
+ {
+ oSettings.aoData[i].nTr._DT_RowIndex = i;
+ }
+ }
+
+ /* Remove the target row from the search array */
+ var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
+ oSettings.asDataSearch.splice( iDisplayIndex, 1 );
+
+ /* Delete from the display arrays */
+ _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
+ _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
+
+ /* If there is a user callback function - call it */
+ if ( typeof fnCallBack === "function" )
+ {
+ fnCallBack.call( this, oSettings, oData );
+ }
+
+ /* Check for an 'overflow' they case for displaying the table */
+ if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ return oData;
+ };
+
+
+ /**
+ * Restore the table to it's original state in the DOM by removing all of DataTables
+ * enhancements, alterations to the DOM structure of the table and event listeners.
+ * @param {boolean} [bRemove=false] Completely remove the table from the DOM
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
+ * var oTable = $('#example').dataTable();
+ * oTable.fnDestroy();
+ * } );
+ */
+ this.fnDestroy = function ( bRemove )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var nOrig = oSettings.nTableWrapper.parentNode;
+ var nBody = oSettings.nTBody;
+ var i, iLen;
+
+ bRemove = (bRemove===undefined) ? false : bRemove;
+
+ /* Flag to note that the table is currently being destroyed - no action should be taken */
+ oSettings.bDestroying = true;
+
+ /* Fire off the destroy callbacks for plug-ins etc */
+ _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
+
+ /* If the table is not being removed, restore the hidden columns */
+ if ( !bRemove )
+ {
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible === false )
+ {
+ this.fnSetColumnVis( i, true );
+ }
+ }
+ }
+
+ /* Blitz all DT events */
+ $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
+
+ /* If there is an 'empty' indicator row, remove it */
+ $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
+
+ /* When scrolling we had to break the table up - restore it */
+ if ( oSettings.nTable != oSettings.nTHead.parentNode )
+ {
+ $(oSettings.nTable).children('thead').remove();
+ oSettings.nTable.appendChild( oSettings.nTHead );
+ }
+
+ if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
+ {
+ $(oSettings.nTable).children('tfoot').remove();
+ oSettings.nTable.appendChild( oSettings.nTFoot );
+ }
+
+ /* Remove the DataTables generated nodes, events and classes */
+ oSettings.nTable.parentNode.removeChild( oSettings.nTable );
+ $(oSettings.nTableWrapper).remove();
+
+ oSettings.aaSorting = [];
+ oSettings.aaSortingFixed = [];
+ _fnSortingClasses( oSettings );
+
+ $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
+
+ $('th, td', oSettings.nTHead).removeClass( [
+ oSettings.oClasses.sSortable,
+ oSettings.oClasses.sSortableAsc,
+ oSettings.oClasses.sSortableDesc,
+ oSettings.oClasses.sSortableNone ].join(' ')
+ );
+ if ( oSettings.bJUI )
+ {
+ $('th span.'+oSettings.oClasses.sSortIcon
+ + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
+
+ $('th, td', oSettings.nTHead).each( function () {
+ var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
+ var kids = jqWrapper.contents();
+ $(this).append( kids );
+ jqWrapper.remove();
+ } );
+ }
+
+ /* Add the TR elements back into the table in their original order */
+ if ( !bRemove && oSettings.nTableReinsertBefore )
+ {
+ nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
+ }
+ else if ( !bRemove )
+ {
+ nOrig.appendChild( oSettings.nTable );
+ }
+
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoData[i].nTr !== null )
+ {
+ nBody.appendChild( oSettings.aoData[i].nTr );
+ }
+ }
+
+ /* Restore the width of the original table */
+ if ( oSettings.oFeatures.bAutoWidth === true )
+ {
+ oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
+ }
+
+ /* If the were originally stripe classes - then we add them back here. Note
+ * this is not fool proof (for example if not all rows had stripe classes - but
+ * it's a good effort without getting carried away
+ */
+ iLen = oSettings.asDestroyStripes.length;
+ if (iLen)
+ {
+ var anRows = $(nBody).children('tr');
+ for ( i=0 ; i<iLen ; i++ )
+ {
+ anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
+ }
+ }
+
+ /* Remove the settings object from the settings array */
+ for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+ {
+ if ( DataTable.settings[i] == oSettings )
+ {
+ DataTable.settings.splice( i, 1 );
+ }
+ }
+
+ /* End it all */
+ oSettings = null;
+ oInit = null;
+ };
+
+
+ /**
+ * Redraw the table
+ * @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
+ * oTable.fnDraw();
+ * } );
+ */
+ this.fnDraw = function( bComplete )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ if ( bComplete === false )
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ else
+ {
+ _fnReDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * Filter the input based on data
+ * @param {string} sInput String to filter the table on
+ * @param {int|null} [iColumn] Column to limit filtering to
+ * @param {bool} [bRegex=false] Treat as regular expression or not
+ * @param {bool} [bSmart=true] Perform smart filtering or not
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sometime later - filter...
+ * oTable.fnFilter( 'test string' );
+ * } );
+ */
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( !oSettings.oFeatures.bFilter )
+ {
+ return;
+ }
+
+ if ( bRegex === undefined || bRegex === null )
+ {
+ bRegex = false;
+ }
+
+ if ( bSmart === undefined || bSmart === null )
+ {
+ bSmart = true;
+ }
+
+ if ( bShowGlobal === undefined || bShowGlobal === null )
+ {
+ bShowGlobal = true;
+ }
+
+ if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
+ {
+ bCaseInsensitive = true;
+ }
+
+ if ( iColumn === undefined || iColumn === null )
+ {
+ /* Global filter */
+ _fnFilterComplete( oSettings, {
+ "sSearch":sInput+"",
+ "bRegex": bRegex,
+ "bSmart": bSmart,
+ "bCaseInsensitive": bCaseInsensitive
+ }, 1 );
+
+ if ( bShowGlobal && oSettings.aanFeatures.f )
+ {
+ var n = oSettings.aanFeatures.f;
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame...
+ try {
+ if ( n[i]._DT_Input != document.activeElement )
+ {
+ $(n[i]._DT_Input).val( sInput );
+ }
+ }
+ catch ( e ) {
+ $(n[i]._DT_Input).val( sInput );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Single column filter */
+ $.extend( oSettings.aoPreSearchCols[ iColumn ], {
+ "sSearch": sInput+"",
+ "bRegex": bRegex,
+ "bSmart": bSmart,
+ "bCaseInsensitive": bCaseInsensitive
+ } );
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+ }
+ };
+
+
+ /**
+ * Get the data for the whole table, an individual row or an individual cell based on the
+ * provided parameters.
+ * @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
+ * a TR node then the data source for the whole row will be returned. If given as a
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
+ * cell returned. If given as an integer, then this is treated as the aoData internal
+ * data index for the row (see fnGetPosition) and the data for that row used.
+ * @param {int} [iCol] Optional column index that you want the data of.
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
+ * returned. If mRow is defined, just data for that row, and is iCol is
+ * defined, only data for the designated cell is returned.
+ * @dtopt API
+ *
+ * @example
+ * // Row data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('tr').click( function () {
+ * var data = oTable.fnGetData( this );
+ * // ... do something with the array / object of data for the row
+ * } );
+ * } );
+ *
+ * @example
+ * // Individual cell data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('td').click( function () {
+ * var sData = oTable.fnGetData( this );
+ * alert( 'The cell clicked on had the value of '+sData );
+ * } );
+ * } );
+ */
+ this.fnGetData = function( mRow, iCol )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( mRow !== undefined )
+ {
+ var iRow = mRow;
+ if ( typeof mRow === 'object' )
+ {
+ var sNode = mRow.nodeName.toLowerCase();
+ if (sNode === "tr" )
+ {
+ iRow = _fnNodeToDataIndex(oSettings, mRow);
+ }
+ else if ( sNode === "td" )
+ {
+ iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
+ iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
+ }
+ }
+
+ if ( iCol !== undefined )
+ {
+ return _fnGetCellData( oSettings, iRow, iCol, '' );
+ }
+ return (oSettings.aoData[iRow]!==undefined) ?
+ oSettings.aoData[iRow]._aData : null;
+ }
+ return _fnGetDataMaster( oSettings );
+ };
+
+
+ /**
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
+ * typically want to use the '$' API method in preference to this as it is more
+ * flexible.
+ * @param {int} [iRow] Optional row index for the TR element you want
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
+ * in the table's body, or iRow is defined, just the TR element requested.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the nodes from the table
+ * var nNodes = oTable.fnGetNodes( );
+ * } );
+ */
+ this.fnGetNodes = function( iRow )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( iRow !== undefined ) {
+ return (oSettings.aoData[iRow]!==undefined) ?
+ oSettings.aoData[iRow].nTr : null;
+ }
+ return _fnGetTrNodes( oSettings );
+ };
+
+
+ /**
+ * Get the array indexes of a particular cell from it's DOM element
+ * and column index including hidden columns
+ * @param {node} nNode this can either be a TR, TD or TH in the table's body
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
+ * if given as a cell, an array of [row index, column index (visible),
+ * column index (all)] is given.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * $('#example tbody td').click( function () {
+ * // Get the position of the current data from the node
+ * var aPos = oTable.fnGetPosition( this );
+ *
+ * // Get the data array for this row
+ * var aData = oTable.fnGetData( aPos[0] );
+ *
+ * // Update the data array and return the value
+ * aData[ aPos[1] ] = 'clicked';
+ * this.innerHTML = 'clicked';
+ * } );
+ *
+ * // Init DataTables
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnGetPosition = function( nNode )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var sNodeName = nNode.nodeName.toUpperCase();
+
+ if ( sNodeName == "TR" )
+ {
+ return _fnNodeToDataIndex(oSettings, nNode);
+ }
+ else if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
+ var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
+ return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
+ }
+ return null;
+ };
+
+
+ /**
+ * Check to see if a row is 'open' or not.
+ * @param {node} nTr the table row to check
+ * @returns {boolean} true if the row is currently open, false otherwise
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnIsOpen = function( nTr )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var aoOpenRows = oSettings.aoOpenRows;
+
+ for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+ {
+ if ( oSettings.aoOpenRows[i].nParent == nTr )
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+
+ /**
+ * This function will place a new row directly after a row which is currently
+ * on display on the page, with the HTML contents that is passed into the
+ * function. This can be used, for example, to ask for confirmation that a
+ * particular record should be deleted.
+ * @param {node} nTr The table row to 'open'
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
+ * @param {string} sClass Class to give the new TD cell
+ * @returns {node} The row opened. Note that if the table row passed in as the
+ * first parameter, is not found in the table, this method will silently
+ * return.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnOpen = function( nTr, mHtml, sClass )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ /* Check that the row given is in the table */
+ var nTableRows = _fnGetTrNodes( oSettings );
+ if ( $.inArray(nTr, nTableRows) === -1 )
+ {
+ return;
+ }
+
+ /* the old open one if there is one */
+ this.fnClose( nTr );
+
+ var nNewRow = document.createElement("tr");
+ var nNewCell = document.createElement("td");
+ nNewRow.appendChild( nNewCell );
+ nNewCell.className = sClass;
+ nNewCell.colSpan = _fnVisbleColumns( oSettings );
+
+ if (typeof mHtml === "string")
+ {
+ nNewCell.innerHTML = mHtml;
+ }
+ else
+ {
+ $(nNewCell).html( mHtml );
+ }
+
+ /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
+ var nTrs = $('tr', oSettings.nTBody);
+ if ( $.inArray(nTr, nTrs) != -1 )
+ {
+ $(nNewRow).insertAfter(nTr);
+ }
+
+ oSettings.aoOpenRows.push( {
+ "nTr": nNewRow,
+ "nParent": nTr
+ } );
+
+ return nNewRow;
+ };
+
+
+ /**
+ * Change the pagination - provides the internal logic for pagination in a simple API
+ * function. With this function you can have a DataTables table go to the next,
+ * previous, first or last pages.
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+ * or page number to jump to (integer), note that page 0 is the first page.
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnPageChange( 'next' );
+ * } );
+ */
+ this.fnPageChange = function ( mAction, bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ _fnPageChange( oSettings, mAction );
+ _fnCalculateEnd( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * Show a particular column
+ * @param {int} iCol The column whose display should be changed
+ * @param {bool} bShow Show (true) or hide (false) the column
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Hide the second column after initialisation
+ * oTable.fnSetColumnVis( 1, false );
+ * } );
+ */
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen;
+ var aoColumns = oSettings.aoColumns;
+ var aoData = oSettings.aoData;
+ var nTd, bAppend, iBefore;
+
+ /* No point in doing anything if we are requesting what is already true */
+ if ( aoColumns[iCol].bVisible == bShow )
+ {
+ return;
+ }
+
+ /* Show the column */
+ if ( bShow )
+ {
+ var iInsert = 0;
+ for ( i=0 ; i<iCol ; i++ )
+ {
+ if ( aoColumns[i].bVisible )
+ {
+ iInsert++;
+ }
+ }
+
+ /* Need to decide if we should use appendChild or insertBefore */
+ bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
+
+ /* Which coloumn should we be inserting before? */
+ if ( !bAppend )
+ {
+ for ( i=iCol ; i<aoColumns.length ; i++ )
+ {
+ if ( aoColumns[i].bVisible )
+ {
+ iBefore = i;
+ break;
+ }
+ }
+ }
+
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ if ( bAppend )
+ {
+ aoData[i].nTr.appendChild(
+ aoData[i]._anHidden[iCol]
+ );
+ }
+ else
+ {
+ aoData[i].nTr.insertBefore(
+ aoData[i]._anHidden[iCol],
+ _fnGetTdNodes( oSettings, i )[iBefore] );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Remove a column from display */
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ nTd = _fnGetTdNodes( oSettings, i )[iCol];
+ aoData[i]._anHidden[iCol] = nTd;
+ nTd.parentNode.removeChild( nTd );
+ }
+ }
+ }
+
+ /* Clear to set the visible flag */
+ aoColumns[iCol].bVisible = bShow;
+
+ /* Redraw the header and footer based on the new column visibility */
+ _fnDrawHead( oSettings, oSettings.aoHeader );
+ if ( oSettings.nTFoot )
+ {
+ _fnDrawHead( oSettings, oSettings.aoFooter );
+ }
+
+ /* If there are any 'open' rows, then we need to alter the colspan for this col change */
+ for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
+ {
+ oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
+ }
+
+ /* Do a redraw incase anything depending on the table columns needs it
+ * (built-in: scrolling)
+ */
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnAdjustColumnSizing( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ _fnSaveState( oSettings );
+ };
+
+
+ /**
+ * Get the settings for a particular table for external manipulation
+ * @returns {object} DataTables settings object. See
+ * {@link DataTable.models.oSettings}
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * var oSettings = oTable.fnSettings();
+ *
+ * // Show an example parameter from the settings
+ * alert( oSettings._iDisplayStart );
+ * } );
+ */
+ this.fnSettings = function()
+ {
+ return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ };
+
+
+ /**
+ * Sort the table by a particular column
+ * @param {int} iCol the data index to sort on. Note that this will not match the
+ * 'display index' if you have hidden data entries
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort immediately with columns 0 and 1
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
+ * } );
+ */
+ this.fnSort = function( aaSort )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ oSettings.aaSorting = aaSort;
+ _fnSort( oSettings );
+ };
+
+
+ /**
+ * Attach a sort listener to an element for a given column
+ * @param {node} nNode the element to attach the sort listener to
+ * @param {int} iColumn the column that a click on this node will sort on
+ * @param {function} [fnCallback] callback function when sort is run
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort on column 1, when 'sorter' is clicked on
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
+ * } );
+ */
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
+ {
+ _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
+ fnCallback );
+ };
+
+
+ /**
+ * Update a table cell or row - this method will accept either a single value to
+ * update the cell with, an array of values with one element for each column or
+ * an object in the same format as the original data source. The function is
+ * self-referencing in order to make the multi column updates easier.
+ * @param {object|array|string} mData Data to update the cell/row with
+ * @param {node|int} mRow TR element you want to update or the aoData index
+ * @param {int} [iColumn] The column to update (not used of mData is an array or object)
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
+ * @returns {int} 0 on success, 1 on error
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
+ * } );
+ */
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen, sDisplay;
+ var iRow = (typeof mRow === 'object') ?
+ _fnNodeToDataIndex(oSettings, mRow) : mRow;
+
+ if ( $.isArray(mData) && iColumn === undefined )
+ {
+ /* Array update - update the whole row */
+ oSettings.aoData[iRow]._aData = mData.slice();
+
+ /* Flag to the function that we are recursing */
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+ }
+ }
+ else if ( $.isPlainObject(mData) && iColumn === undefined )
+ {
+ /* Object update - update the whole row - assume the developer gets the object right */
+ oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
+
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+ }
+ }
+ else
+ {
+ /* Individual cell update */
+ _fnSetCellData( oSettings, iRow, iColumn, mData );
+ sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+
+ var oCol = oSettings.aoColumns[iColumn];
+ if ( oCol.fnRender !== null )
+ {
+ sDisplay = _fnRender( oSettings, iRow, iColumn );
+ if ( oCol.bUseRendered )
+ {
+ _fnSetCellData( oSettings, iRow, iColumn, sDisplay );
+ }
+ }
+
+ if ( oSettings.aoData[iRow].nTr !== null )
+ {
+ /* Do the actual HTML update */
+ _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
+ }
+ }
+
+ /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
+ * will rebuild the search array - however, the redraw might be disabled by the user)
+ */
+ var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
+ oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
+ oSettings,
+ _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
+ );
+
+ /* Perform pre-draw actions */
+ if ( bAction === undefined || bAction )
+ {
+ _fnAdjustColumnSizing( oSettings );
+ }
+
+ /* Redraw the table */
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnReDraw( oSettings );
+ }
+ return 0;
+ };
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @method
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
+ * } );
+ */
+ this.fnVersionCheck = DataTable.ext.fnVersionCheck;
+
+
+ /*
+ * This is really a good bit rubbish this method of exposing the internal methods
+ * publicly... - To be fixed in 2.0 using methods on the prototype
+ */
+
+
+ /**
+ * Create a wrapper function for exporting an internal functions to an external API.
+ * @param {string} sFunc API function name
+ * @returns {function} wrapped function
+ * @memberof DataTable#oApi
+ */
+ function _fnExternApiFunc (sFunc)
+ {
+ return function() {
+ var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat(
+ Array.prototype.slice.call(arguments) );
+ return DataTable.ext.oApi[sFunc].apply( this, aArgs );
+ };
+ }
+
+
+ /**
+ * Reference to internal functions for use by plug-in developers. Note that these
+ * methods are references to internal functions and are considered to be private.
+ * If you use these methods, be aware that they are liable to change between versions
+ * (check the upgrade notes).
+ * @namespace
+ */
+ this.oApi = {
+ "_fnExternApiFunc": _fnExternApiFunc,
+ "_fnInitialise": _fnInitialise,
+ "_fnInitComplete": _fnInitComplete,
+ "_fnLanguageCompat": _fnLanguageCompat,
+ "_fnAddColumn": _fnAddColumn,
+ "_fnColumnOptions": _fnColumnOptions,
+ "_fnAddData": _fnAddData,
+ "_fnCreateTr": _fnCreateTr,
+ "_fnGatherData": _fnGatherData,
+ "_fnBuildHead": _fnBuildHead,
+ "_fnDrawHead": _fnDrawHead,
+ "_fnDraw": _fnDraw,
+ "_fnReDraw": _fnReDraw,
+ "_fnAjaxUpdate": _fnAjaxUpdate,
+ "_fnAjaxParameters": _fnAjaxParameters,
+ "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
+ "_fnServerParams": _fnServerParams,
+ "_fnAddOptionsHtml": _fnAddOptionsHtml,
+ "_fnFeatureHtmlTable": _fnFeatureHtmlTable,
+ "_fnScrollDraw": _fnScrollDraw,
+ "_fnAdjustColumnSizing": _fnAdjustColumnSizing,
+ "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
+ "_fnFilterComplete": _fnFilterComplete,
+ "_fnFilterCustom": _fnFilterCustom,
+ "_fnFilterColumn": _fnFilterColumn,
+ "_fnFilter": _fnFilter,
+ "_fnBuildSearchArray": _fnBuildSearchArray,
+ "_fnBuildSearchRow": _fnBuildSearchRow,
+ "_fnFilterCreateSearch": _fnFilterCreateSearch,
+ "_fnDataToSearch": _fnDataToSearch,
+ "_fnSort": _fnSort,
+ "_fnSortAttachListener": _fnSortAttachListener,
+ "_fnSortingClasses": _fnSortingClasses,
+ "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
+ "_fnPageChange": _fnPageChange,
+ "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
+ "_fnUpdateInfo": _fnUpdateInfo,
+ "_fnFeatureHtmlLength": _fnFeatureHtmlLength,
+ "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
+ "_fnProcessingDisplay": _fnProcessingDisplay,
+ "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
+ "_fnColumnIndexToVisible": _fnColumnIndexToVisible,
+ "_fnNodeToDataIndex": _fnNodeToDataIndex,
+ "_fnVisbleColumns": _fnVisbleColumns,
+ "_fnCalculateEnd": _fnCalculateEnd,
+ "_fnConvertToWidth": _fnConvertToWidth,
+ "_fnCalculateColumnWidths": _fnCalculateColumnWidths,
+ "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
+ "_fnGetWidestNode": _fnGetWidestNode,
+ "_fnGetMaxLenString": _fnGetMaxLenString,
+ "_fnStringToCss": _fnStringToCss,
+ "_fnDetectType": _fnDetectType,
+ "_fnSettingsFromNode": _fnSettingsFromNode,
+ "_fnGetDataMaster": _fnGetDataMaster,
+ "_fnGetTrNodes": _fnGetTrNodes,
+ "_fnGetTdNodes": _fnGetTdNodes,
+ "_fnEscapeRegex": _fnEscapeRegex,
+ "_fnDeleteIndex": _fnDeleteIndex,
+ "_fnReOrderIndex": _fnReOrderIndex,
+ "_fnColumnOrdering": _fnColumnOrdering,
+ "_fnLog": _fnLog,
+ "_fnClearTable": _fnClearTable,
+ "_fnSaveState": _fnSaveState,
+ "_fnLoadState": _fnLoadState,
+ "_fnCreateCookie": _fnCreateCookie,
+ "_fnReadCookie": _fnReadCookie,
+ "_fnDetectHeader": _fnDetectHeader,
+ "_fnGetUniqueThs": _fnGetUniqueThs,
+ "_fnScrollBarWidth": _fnScrollBarWidth,
+ "_fnApplyToChildren": _fnApplyToChildren,
+ "_fnMap": _fnMap,
+ "_fnGetRowData": _fnGetRowData,
+ "_fnGetCellData": _fnGetCellData,
+ "_fnSetCellData": _fnSetCellData,
+ "_fnGetObjectDataFn": _fnGetObjectDataFn,
+ "_fnSetObjectDataFn": _fnSetObjectDataFn,
+ "_fnApplyColumnDefs": _fnApplyColumnDefs,
+ "_fnBindAction": _fnBindAction,
+ "_fnExtend": _fnExtend,
+ "_fnCallbackReg": _fnCallbackReg,
+ "_fnCallbackFire": _fnCallbackFire,
+ "_fnJsonString": _fnJsonString,
+ "_fnRender": _fnRender,
+ "_fnNodeToColumnIndex": _fnNodeToColumnIndex,
+ "_fnInfoMacros": _fnInfoMacros,
+ "_fnBrowserDetect": _fnBrowserDetect,
+ "_fnGetColumns": _fnGetColumns
+ };
+
+ $.extend( DataTable.ext.oApi, this.oApi );
+
+ for ( var sFunc in DataTable.ext.oApi )
+ {
+ if ( sFunc )
+ {
+ this[sFunc] = _fnExternApiFunc(sFunc);
+ }
+ }
+
+
+ var _that = this;
+ this.each(function() {
+ var i=0, iLen, j, jLen, k, kLen;
+ var sId = this.getAttribute( 'id' );
+ var bInitHandedOff = false;
+ var bUsePassedData = false;
+
+
+ /* Sanity check */
+ if ( this.nodeName.toLowerCase() != 'table' )
+ {
+ _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
+ "table: "+this.nodeName );
+ return;
+ }
+
+ /* Check to see if we are re-initialising a table */
+ for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+ {
+ /* Base check on table node */
+ if ( DataTable.settings[i].nTable == this )
+ {
+ if ( oInit === undefined || oInit.bRetrieve )
+ {
+ return DataTable.settings[i].oInstance;
+ }
+ else if ( oInit.bDestroy )
+ {
+ DataTable.settings[i].oInstance.fnDestroy();
+ break;
+ }
+ else
+ {
+ _fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
+ "To retrieve the DataTables object for this table, pass no arguments or see "+
+ "the docs for bRetrieve and bDestroy" );
+ return;
+ }
+ }
+
+ /* If the element we are initialising has the same ID as a table which was previously
+ * initialised, but the table nodes don't match (from before) then we destroy the old
+ * instance by simply deleting it. This is under the assumption that the table has been
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+ */
+ if ( DataTable.settings[i].sTableId == this.id )
+ {
+ DataTable.settings.splice( i, 1 );
+ break;
+ }
+ }
+
+ /* Ensure the table has an ID - required for accessibility */
+ if ( sId === null || sId === "" )
+ {
+ sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
+ this.id = sId;
+ }
+
+ /* Create the settings object for this table and set some of the default parameters */
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
+ "nTable": this,
+ "oApi": _that.oApi,
+ "oInit": oInit,
+ "sDestroyWidth": $(this).width(),
+ "sInstance": sId,
+ "sTableId": sId
+ } );
+ DataTable.settings.push( oSettings );
+
+ // Need to add the instance after the instance after the settings object has been added
+ // to the settings array, so we can self reference the table instance if more than one
+ oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
+
+ /* Setting up the initialisation object */
+ if ( !oInit )
+ {
+ oInit = {};
+ }
+
+ // Backwards compatibility, before we apply all the defaults
+ if ( oInit.oLanguage )
+ {
+ _fnLanguageCompat( oInit.oLanguage );
+ }
+
+ oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
+
+ // Map the initialisation options onto the settings object
+ _fnMap( oSettings.oFeatures, oInit, "bPaginate" );
+ _fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
+ _fnMap( oSettings.oFeatures, oInit, "bFilter" );
+ _fnMap( oSettings.oFeatures, oInit, "bSort" );
+ _fnMap( oSettings.oFeatures, oInit, "bInfo" );
+ _fnMap( oSettings.oFeatures, oInit, "bProcessing" );
+ _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
+ _fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
+ _fnMap( oSettings.oFeatures, oInit, "bServerSide" );
+ _fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
+ _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
+ _fnMap( oSettings, oInit, "asStripeClasses" );
+ _fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
+ _fnMap( oSettings, oInit, "fnServerData" );
+ _fnMap( oSettings, oInit, "fnFormatNumber" );
+ _fnMap( oSettings, oInit, "sServerMethod" );
+ _fnMap( oSettings, oInit, "aaSorting" );
+ _fnMap( oSettings, oInit, "aaSortingFixed" );
+ _fnMap( oSettings, oInit, "aLengthMenu" );
+ _fnMap( oSettings, oInit, "sPaginationType" );
+ _fnMap( oSettings, oInit, "sAjaxSource" );
+ _fnMap( oSettings, oInit, "sAjaxDataProp" );
+ _fnMap( oSettings, oInit, "iCookieDuration" );
+ _fnMap( oSettings, oInit, "sCookiePrefix" );
+ _fnMap( oSettings, oInit, "sDom" );
+ _fnMap( oSettings, oInit, "bSortCellsTop" );
+ _fnMap( oSettings, oInit, "iTabIndex" );
+ _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
+ _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
+ _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
+ _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
+ _fnMap( oSettings, oInit, "fnCookieCallback" );
+ _fnMap( oSettings, oInit, "fnStateLoad" );
+ _fnMap( oSettings, oInit, "fnStateSave" );
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+
+ /* Callback functions which are array driven */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
+
+ if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
+ oSettings.oFeatures.bSortClasses )
+ {
+ /* Enable sort classes for server-side processing. Safe to do it here, since server-side
+ * processing must be enabled by the developer
+ */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
+ }
+ else if ( oSettings.oFeatures.bDeferRender )
+ {
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
+ }
+
+ if ( oInit.bJQueryUI )
+ {
+ /* Use the JUI classes object for display. You could clone the oStdClasses object if
+ * you want to have multiple tables with multiple independent classes
+ */
+ $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
+
+ if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
+ {
+ /* Set the DOM to use a layout suitable for jQuery UI's theming */
+ oSettings.sDom = '<"H"lfr>t<"F"ip>';
+ }
+ }
+ else
+ {
+ $.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
+ }
+ $(this).addClass( oSettings.oClasses.sTable );
+
+ /* Calculate the scroll bar width and cache it for use later on */
+ if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+ {
+ oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
+ }
+
+ if ( oSettings.iInitDisplayStart === undefined )
+ {
+ /* Display start point, taking into account the save saving */
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
+ oSettings._iDisplayStart = oInit.iDisplayStart;
+ }
+
+ /* Must be done after everything which can be overridden by a cookie! */
+ if ( oInit.bStateSave )
+ {
+ oSettings.oFeatures.bStateSave = true;
+ _fnLoadState( oSettings, oInit );
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+ }
+
+ if ( oInit.iDeferLoading !== null )
+ {
+ oSettings.bDeferLoading = true;
+ var tmp = $.isArray( oInit.iDeferLoading );
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
+ }
+
+ if ( oInit.aaData !== null )
+ {
+ bUsePassedData = true;
+ }
+
+ /* Language definitions */
+ if ( oInit.oLanguage.sUrl !== "" )
+ {
+ /* Get the language definitions from a file - because this Ajax call makes the language
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
+ */
+ oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
+ $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
+ _fnLanguageCompat( json );
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
+ _fnInitialise( oSettings );
+ } );
+ bInitHandedOff = true;
+ }
+ else
+ {
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage );
+ }
+
+
+ /*
+ * Stripes
+ */
+ if ( oInit.asStripeClasses === null )
+ {
+ oSettings.asStripeClasses =[
+ oSettings.oClasses.sStripeOdd,
+ oSettings.oClasses.sStripeEven
+ ];
+ }
+
+ /* Remove row stripe classes if they are already on the table row */
+ iLen=oSettings.asStripeClasses.length;
+ oSettings.asDestroyStripes = [];
+ if (iLen)
+ {
+ var bStripeRemove = false;
+ var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
+ for ( i=0 ; i<iLen ; i++ )
+ {
+ if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
+ {
+ bStripeRemove = true;
+
+ /* Store the classes which we are about to remove so they can be re-added on destroy */
+ oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
+ }
+ }
+
+ if ( bStripeRemove )
+ {
+ anRows.removeClass( oSettings.asStripeClasses.join(' ') );
+ }
+ }
+
+ /*
+ * Columns
+ * See if we should load columns automatically or use defined ones
+ */
+ var anThs = [];
+ var aoColumnsInit;
+ var nThead = this.getElementsByTagName('thead');
+ if ( nThead.length !== 0 )
+ {
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
+ anThs = _fnGetUniqueThs( oSettings );
+ }
+
+ /* If not given a column array, generate one with nulls */
+ if ( oInit.aoColumns === null )
+ {
+ aoColumnsInit = [];
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+ {
+ aoColumnsInit.push( null );
+ }
+ }
+ else
+ {
+ aoColumnsInit = oInit.aoColumns;
+ }
+
+ /* Add the columns */
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+ {
+ /* Short cut - use the loop to check if we have column visibility state to restore */
+ if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
+ {
+ if ( aoColumnsInit[i] === null )
+ {
+ aoColumnsInit[i] = {};
+ }
+ aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
+ }
+
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
+ }
+
+ /* Apply the column definitions */
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+ _fnColumnOptions( oSettings, iCol, oDef );
+ } );
+
+
+ /*
+ * Sorting
+ * Check the aaSorting array
+ */
+ for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
+ {
+ oSettings.aaSorting[i][0] = 0;
+ }
+ var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
+
+ /* Add a default sorting index */
+ if ( oSettings.aaSorting[i][2] === undefined )
+ {
+ oSettings.aaSorting[i][2] = 0;
+ }
+
+ /* If aaSorting is not defined, then we use the first indicator in asSorting */
+ if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
+ {
+ oSettings.aaSorting[i][1] = oColumn.asSorting[0];
+ }
+
+ /* Set the current sorting index based on aoColumns.asSorting */
+ for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
+ {
+ if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
+ {
+ oSettings.aaSorting[i][2] = j;
+ break;
+ }
+ }
+ }
+
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
+ * account, and also will apply sorting disabled classes if disabled
+ */
+ _fnSortingClasses( oSettings );
+
+
+ /*
+ * Final init
+ * Cache the header, body and footer as required, creating them if needed
+ */
+
+ /* Browser support detection */
+ _fnBrowserDetect( oSettings );
+
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
+ var captions = $(this).children('caption').each( function () {
+ this._captionSide = $(this).css('caption-side');
+ } );
+
+ var thead = $(this).children('thead');
+ if ( thead.length === 0 )
+ {
+ thead = [ document.createElement( 'thead' ) ];
+ this.appendChild( thead[0] );
+ }
+ oSettings.nTHead = thead[0];
+
+ var tbody = $(this).children('tbody');
+ if ( tbody.length === 0 )
+ {
+ tbody = [ document.createElement( 'tbody' ) ];
+ this.appendChild( tbody[0] );
+ }
+ oSettings.nTBody = tbody[0];
+ oSettings.nTBody.setAttribute( "role", "alert" );
+ oSettings.nTBody.setAttribute( "aria-live", "polite" );
+ oSettings.nTBody.setAttribute( "aria-relevant", "all" );
+
+ var tfoot = $(this).children('tfoot');
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
+ {
+ // If we are a scrolling table, and no footer has been given, then we need to create
+ // a tfoot element for the caption element to be appended to
+ tfoot = [ document.createElement( 'tfoot' ) ];
+ this.appendChild( tfoot[0] );
+ }
+
+ if ( tfoot.length > 0 )
+ {
+ oSettings.nTFoot = tfoot[0];
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
+ }
+
+ /* Check if there is data passing into the constructor */
+ if ( bUsePassedData )
+ {
+ for ( i=0 ; i<oInit.aaData.length ; i++ )
+ {
+ _fnAddData( oSettings, oInit.aaData[ i ] );
+ }
+ }
+ else
+ {
+ /* Grab the data from the page */
+ _fnGatherData( oSettings );
+ }
+
+ /* Copy the data index array */
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ /* Initialisation complete - table can be drawn */
+ oSettings.bInitialised = true;
+
+ /* Check if we need to initialise the table (it might not have been handed off to the
+ * language processor)
+ */
+ if ( bInitHandedOff === false )
+ {
+ _fnInitialise( oSettings );
+ }
+ } );
+ _that = null;
+ return this;
+ };
+
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
+ */
+ DataTable.fnVersionCheck = function( sVersion )
+ {
+ /* This is cheap, but effective */
+ var fnZPad = function (Zpad, count)
+ {
+ while(Zpad.length < count) {
+ Zpad += '0';
+ }
+ return Zpad;
+ };
+ var aThis = DataTable.ext.sVersion.split('.');
+ var aThat = sVersion.split('.');
+ var sThis = '', sThat = '';
+
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
+ {
+ sThis += fnZPad( aThis[i], 3 );
+ sThat += fnZPad( aThat[i], 3 );
+ }
+
+ return parseInt(sThis, 10) >= parseInt(sThat, 10);
+ };
+
+
+ /**
+ * Check if a TABLE node is a DataTable table already or not.
+ * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
+ * node types can be passed in, but will always return false).
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * var ex = document.getElementById('example');
+ * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
+ * $(ex).dataTable();
+ * }
+ */
+ DataTable.fnIsDataTable = function ( nTable )
+ {
+ var o = DataTable.settings;
+
+ for ( var i=0 ; i<o.length ; i++ )
+ {
+ if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+
+ /**
+ * Get all DataTable tables that have been initialised - optionally you can select to
+ * get only currently visible tables.
+ * @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or
+ * visible tables only.
+ * @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * var table = $.fn.dataTable.fnTables(true);
+ * if ( table.length > 0 ) {
+ * $(table).dataTable().fnAdjustColumnSizing();
+ * }
+ */
+ DataTable.fnTables = function ( bVisible )
+ {
+ var out = [];
+
+ jQuery.each( DataTable.settings, function (i, o) {
+ if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
+ {
+ out.push( o.nTable );
+ }
+ } );
+
+ return out;
+ };
+
+
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+ * e are optional
+ * @member
+ * @type string
+ * @default Version number
+ */
+ DataTable.version = "1.9.4";
+
+ /**
+ * Private data store, containing all of the settings objects that are created for the
+ * tables on a given page.
+ *
+ * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i>
+ * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
+ * @member
+ * @type array
+ * @default []
+ * @private
+ */
+ DataTable.settings = [];
+
+ /**
+ * Object models container, for the various models that DataTables has available
+ * to it. These models define the objects that are used to hold the active state
+ * and configuration of the table.
+ * @namespace
+ */
+ DataTable.models = {};
+
+
+ /**
+ * DataTables extension options and plug-ins. This namespace acts as a collection "area"
+ * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
+ * of the build in methods use this method to provide their own capabilities (sorting methods
+ * for example).
+ *
+ * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
+ * and modified by plug-ins.
+ * @namespace
+ */
+ DataTable.models.ext = {
+ /**
+ * Plug-in filtering functions - this method of filtering is complimentary to the default
+ * type based filtering, and a lot more comprehensive as it allows you complete control
+ * over the filtering logic. Each element in this array is a function (parameters
+ * described below) that is called for every row in the table, and your logic decides if
+ * it should be included in the filtered data set or not.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{array|object} Data for the row to be processed (same as the original format
+ * that was passed in as the data source, or an array from a DOM data source</li>
+ * <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
+ * be useful to retrieve the TR element if you need DOM interaction.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // The following example shows custom filtering being applied to the fourth column (i.e.
+ * // the aData[3] index) based on two input values from the end-user, matching the data in
+ * // a certain range.
+ * $.fn.dataTableExt.afnFiltering.push(
+ * function( oSettings, aData, iDataIndex ) {
+ * var iMin = document.getElementById('min').value * 1;
+ * var iMax = document.getElementById('max').value * 1;
+ * var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
+ * if ( iMin == "" && iMax == "" ) {
+ * return true;
+ * }
+ * else if ( iMin == "" && iVersion < iMax ) {
+ * return true;
+ * }
+ * else if ( iMin < iVersion && "" == iMax ) {
+ * return true;
+ * }
+ * else if ( iMin < iVersion && iVersion < iMax ) {
+ * return true;
+ * }
+ * return false;
+ * }
+ * );
+ */
+ "afnFiltering": [],
+
+
+ /**
+ * Plug-in sorting functions - this method of sorting is complimentary to the default type
+ * based sorting that DataTables does automatically, allowing much greater control over the
+ * the data that is being used to sort a column. This is useful if you want to do sorting
+ * based on live data (for example the contents of an 'input' element) rather than just the
+ * static string that DataTables knows of. The way these plug-ins work is that you create
+ * an array of the values you wish to be sorted for the column in question and then return
+ * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
+ * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort
+ * data.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{int} Target column index</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{array} Data for the column to be sorted upon</li>
+ * </ul>
+ * </il>
+ * </ul>
+ *
+ * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+ * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+ * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
+ * prepare the data as required for the different types. As such, this method is deprecated.
+ * @type array
+ * @default []
+ * @deprecated
+ *
+ * @example
+ * // Updating the cached sorting information with user entered values in HTML input elements
+ * jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
+ * {
+ * var aData = [];
+ * $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
+ * aData.push( this.value );
+ * } );
+ * return aData;
+ * }
+ */
+ "afnSortData": [],
+
+
+ /**
+ * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
+ * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
+ * option. As such, each feature plug-in must describe a function that is used to initialise
+ * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
+ * of the feature (sFeature). Thus the objects attached to this method must provide:
+ * <ul>
+ * <li>{function} fnInit Initialisation of the plug-in
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{node|null} The element which contains your feature. Note that the return
+ * may also be void if your plug-in does not require to inject any DOM elements
+ * into DataTables control (sDom) - for example this might be useful when
+ * developing a plug-in which allows table control via keyboard entry.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </li>
+ * <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
+ * <li>{string} sFeature Feature name</li>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // How TableTools initialises itself.
+ * $.fn.dataTableExt.aoFeatures.push( {
+ * "fnInit": function( oSettings ) {
+ * return new TableTools( { "oDTSettings": oSettings } );
+ * },
+ * "cFeature": "T",
+ * "sFeature": "TableTools"
+ * } );
+ */
+ "aoFeatures": [],
+
+
+ /**
+ * Type detection plug-in functions - DataTables utilises types to define how sorting and
+ * filtering behave, and types can be either be defined by the developer (sType for the
+ * column) or they can be automatically detected by the methods in this array. The functions
+ * defined in the array are quite simple, taking a single parameter (the data to analyse)
+ * and returning the type if it is a known type, or null otherwise.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data from the column cell to be analysed</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{string|null} Data type detected, or null if unknown (and thus pass it
+ * on to the other type detection functions.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // Currency type detection plug-in:
+ * jQuery.fn.dataTableExt.aTypes.push(
+ * function ( sData ) {
+ * var sValidChars = "0123456789.-";
+ * var Char;
+ *
+ * // Check the numeric part
+ * for ( i=1 ; i<sData.length ; i++ ) {
+ * Char = sData.charAt(i);
+ * if (sValidChars.indexOf(Char) == -1) {
+ * return null;
+ * }
+ * }
+ *
+ * // Check prefixed by currency
+ * if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
+ * return 'currency';
+ * }
+ * return null;
+ * }
+ * );
+ */
+ "aTypes": [],
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used,
+ * in order to ensure compatibility.
+ * @type function
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note
+ * that the formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the
+ * required version, or false if this version of DataTales is not suitable
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
+ * } );
+ */
+ "fnVersionCheck": DataTable.fnVersionCheck,
+
+
+ /**
+ * Index for what 'this' index API functions should use
+ * @type int
+ * @default 0
+ */
+ "iApiIndex": 0,
+
+
+ /**
+ * Pre-processing of filtering data plug-ins - When you assign the sType for a column
+ * (or have it automatically detected for you by DataTables or a type detection plug-in),
+ * you will typically be using this for custom sorting, but it can also be used to provide
+ * custom filtering by allowing you to pre-processing the data and returning the data in
+ * the format that should be filtered upon. This is done by adding functions this object
+ * with a parameter name which matches the sType for that target column. This is the
+ * corollary of <i>afnSortData</i> for filtering data.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data from the column cell to be prepared for filtering</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{string|null} Formatted string that will be used for the filtering.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ *
+ * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+ * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+ * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
+ * prepare the data as required for the different types. As such, this method is deprecated.
+ * @type object
+ * @default {}
+ * @deprecated
+ *
+ * @example
+ * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
+ * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
+ * }
+ */
+ "ofnSearch": {},
+
+
+ /**
+ * Container for all private functions in DataTables so they can be exposed externally
+ * @type object
+ * @default {}
+ */
+ "oApi": {},
+
+
+ /**
+ * Storage for the various classes that DataTables uses
+ * @type object
+ * @default {}
+ */
+ "oStdClasses": {},
+
+
+ /**
+ * Storage for the various classes that DataTables uses - jQuery UI suitable
+ * @type object
+ * @default {}
+ */
+ "oJUIClasses": {},
+
+
+ /**
+ * Pagination plug-in methods - The style and controls of the pagination can significantly
+ * impact on how the end user interacts with the data in your table, and DataTables allows
+ * the addition of pagination controls by extending this object, which can then be enabled
+ * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
+ * is added is an object (the property name of which is what <i>sPaginationType</i> refers
+ * to) that has two properties, both methods that are used by DataTables to update the
+ * control's state.
+ * <ul>
+ * <li>
+ * fnInit - Initialisation of the paging controls. Called only during initialisation
+ * of the table. It is expected that this function will add the required DOM elements
+ * to the page for the paging controls to work. The element pointer
+ * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging
+ * controls (note that this is a 2D array to allow for multiple instances of each
+ * DataTables DOM element). It is suggested that you add the controls to this element
+ * as children
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{node} Container into which the pagination controls must be inserted</li>
+ * <li>{function} Draw callback function - whenever the controls cause a page
+ * change, this method must be called to redraw the table.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>No return required</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </il>
+ * <li>
+ * fnInit - This function is called whenever the paging status of the table changes and is
+ * typically used to update classes and/or text of the paging controls to reflex the new
+ * status.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{function} Draw callback function - in case you need to redraw the table again
+ * or attach new event listeners</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>No return required</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type object
+ * @default {}
+ *
+ * @example
+ * $.fn.dataTableExt.oPagination.four_button = {
+ * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
+ * nFirst = document.createElement( 'span' );
+ * nPrevious = document.createElement( 'span' );
+ * nNext = document.createElement( 'span' );
+ * nLast = document.createElement( 'span' );
+ *
+ * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
+ * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
+ * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
+ * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
+ *
+ * nFirst.className = "paginate_button first";
+ * nPrevious.className = "paginate_button previous";
+ * nNext.className="paginate_button next";
+ * nLast.className = "paginate_button last";
+ *
+ * nPaging.appendChild( nFirst );
+ * nPaging.appendChild( nPrevious );
+ * nPaging.appendChild( nNext );
+ * nPaging.appendChild( nLast );
+ *
+ * $(nFirst).click( function () {
+ * oSettings.oApi._fnPageChange( oSettings, "first" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nPrevious).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "previous" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nNext).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "next" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nLast).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "last" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nFirst).bind( 'selectstart', function () { return false; } );
+ * $(nPrevious).bind( 'selectstart', function () { return false; } );
+ * $(nNext).bind( 'selectstart', function () { return false; } );
+ * $(nLast).bind( 'selectstart', function () { return false; } );
+ * },
+ *
+ * "fnUpdate": function ( oSettings, fnCallbackDraw ) {
+ * if ( !oSettings.aanFeatures.p ) {
+ * return;
+ * }
+ *
+ * // Loop over each instance of the pager
+ * var an = oSettings.aanFeatures.p;
+ * for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
+ * var buttons = an[i].getElementsByTagName('span');
+ * if ( oSettings._iDisplayStart === 0 ) {
+ * buttons[0].className = "paginate_disabled_previous";
+ * buttons[1].className = "paginate_disabled_previous";
+ * }
+ * else {
+ * buttons[0].className = "paginate_enabled_previous";
+ * buttons[1].className = "paginate_enabled_previous";
+ * }
+ *
+ * if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
+ * buttons[2].className = "paginate_disabled_next";
+ * buttons[3].className = "paginate_disabled_next";
+ * }
+ * else {
+ * buttons[2].className = "paginate_enabled_next";
+ * buttons[3].className = "paginate_enabled_next";
+ * }
+ * }
+ * }
+ * };
+ */
+ "oPagination": {},
+
+
+ /**
+ * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
+ * data column (you can add your own type detection functions, or override automatic
+ * detection using sType). With this specific type given to the column, DataTables will
+ * apply the required sort from the functions in the object. Each sort type must provide
+ * two mandatory methods, one each for ascending and descending sorting, and can optionally
+ * provide a pre-formatting method that will help speed up sorting by allowing DataTables
+ * to pre-format the sort data only once (rather than every time the actual sort functions
+ * are run). The two sorting functions are typical Javascript sort methods:
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data to compare to the second parameter</li>
+ * <li>{*} Data to compare to the first parameter</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{int} Sorting match: <0 if first parameter should be sorted lower than
+ * the second parameter, ===0 if the two parameters are equal and >0 if
+ * the first parameter should be sorted height than the second parameter.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Case-sensitive string sorting, with no pre-formatting method
+ * $.extend( $.fn.dataTableExt.oSort, {
+ * "string-case-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-case-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ *
+ * @example
+ * // Case-insensitive string sorting, with pre-formatting
+ * $.extend( $.fn.dataTableExt.oSort, {
+ * "string-pre": function(x) {
+ * return x.toLowerCase();
+ * },
+ * "string-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ */
+ "oSort": {},
+
+
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+ * e are optional
+ * @type string
+ * @default Version number
+ */
+ "sVersion": DataTable.version,
+
+
+ /**
+ * How should DataTables report an error. Can take the value 'alert' or 'throw'
+ * @type string
+ * @default alert
+ */
+ "sErrMode": "alert",
+
+
+ /**
+ * Store information for DataTables to access globally about other instances
+ * @namespace
+ * @private
+ */
+ "_oExternConfig": {
+ /* int:iNextUnique - next unique number for an instance */
+ "iNextUnique": 0
+ }
+ };
+
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * search information for the global filter and individual column filters.
+ * @namespace
+ */
+ DataTable.models.oSearch = {
+ /**
+ * Flag to indicate if the filtering should be case insensitive or not
+ * @type boolean
+ * @default true
+ */
+ "bCaseInsensitive": true,
+
+ /**
+ * Applied search term
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sSearch": "",
+
+ /**
+ * Flag to indicate if the search term should be interpreted as a
+ * regular expression (true) or not (false) and therefore and special
+ * regex characters escaped.
+ * @type boolean
+ * @default false
+ */
+ "bRegex": false,
+
+ /**
+ * Flag to indicate if DataTables is to use its smart filtering or not.
+ * @type boolean
+ * @default true
+ */
+ "bSmart": true
+ };
+
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * each individual row. This is the object format used for the settings
+ * aoData array.
+ * @namespace
+ */
+ DataTable.models.oRow = {
+ /**
+ * TR element for the row
+ * @type node
+ * @default null
+ */
+ "nTr": null,
+
+ /**
+ * Data object from the original data source for the row. This is either
+ * an array if using the traditional form of DataTables, or an object if
+ * using mData options. The exact type will depend on the passed in
+ * data from the data source, or will be an array if using DOM a data
+ * source.
+ * @type array|object
+ * @default []
+ */
+ "_aData": [],
+
+ /**
+ * Sorting data cache - this array is ostensibly the same length as the
+ * number of columns (although each index is generated only as it is
+ * needed), and holds the data that is used for sorting each column in the
+ * row. We do this cache generation at the start of the sort in order that
+ * the formatting of the sort data need be done only once for each cell
+ * per sort. This array should not be read from or written to by anything
+ * other than the master sorting methods.
+ * @type array
+ * @default []
+ * @private
+ */
+ "_aSortData": [],
+
+ /**
+ * Array of TD elements that are cached for hidden rows, so they can be
+ * reinserted into the table if a column is made visible again (or to act
+ * as a store if a column is made hidden). Only hidden columns have a
+ * reference in the array. For non-hidden columns the value is either
+ * undefined or null.
+ * @type array nodes
+ * @default []
+ * @private
+ */
+ "_anHidden": [],
+
+ /**
+ * Cache of the class name that DataTables has applied to the row, so we
+ * can quickly look at this variable rather than needing to do a DOM check
+ * on className for the nTr property.
+ * @type string
+ * @default <i>Empty string</i>
+ * @private
+ */
+ "_sRowStripe": ""
+ };
+
+
+
+ /**
+ * Template object for the column information object in DataTables. This object
+ * is held in the settings aoColumns array and contains all the information that
+ * DataTables needs about each individual column.
+ *
+ * Note that this object is related to {@link DataTable.defaults.columns}
+ * but this one is the internal data store for DataTables's cache of columns.
+ * It should NOT be manipulated outside of DataTables. Any configuration should
+ * be done through the initialisation options.
+ * @namespace
+ */
+ DataTable.models.oColumn = {
+ /**
+ * A list of the columns that sorting should occur on when this column
+ * is sorted. That this property is an array allows multi-column sorting
+ * to be defined for a column (for example first name / last name columns
+ * would benefit from this). The values are integers pointing to the
+ * columns to be sorted on (typically it will be a single integer pointing
+ * at itself, but that doesn't need to be the case).
+ * @type array
+ */
+ "aDataSort": null,
+
+ /**
+ * Define the sorting directions that are applied to the column, in sequence
+ * as the column is repeatedly sorted upon - i.e. the first value is used
+ * as the sorting direction when the column if first sorted (clicked on).
+ * Sort it again (click again) and it will move on to the next index.
+ * Repeat until loop.
+ * @type array
+ */
+ "asSorting": null,
+
+ /**
+ * Flag to indicate if the column is searchable, and thus should be included
+ * in the filtering or not.
+ * @type boolean
+ */
+ "bSearchable": null,
+
+ /**
+ * Flag to indicate if the column is sortable or not.
+ * @type boolean
+ */
+ "bSortable": null,
+
+ /**
+ * <code>Deprecated</code> When using fnRender, you have two options for what
+ * to do with the data, and this property serves as the switch. Firstly, you
+ * can have the sorting and filtering use the rendered value (true - default),
+ * or you can have the sorting and filtering us the original value (false).
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type boolean
+ * @deprecated
+ */
+ "bUseRendered": null,
+
+ /**
+ * Flag to indicate if the column is currently visible in the table or not
+ * @type boolean
+ */
+ "bVisible": null,
+
+ /**
+ * Flag to indicate to the type detection method if the automatic type
+ * detection should be used, or if a column type (sType) has been specified
+ * @type boolean
+ * @default true
+ * @private
+ */
+ "_bAutoType": true,
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} nTd The TD node that has been created
+ * @param {*} sData The Data for the cell
+ * @param {array|object} oData The data for the whole row
+ * @param {int} iRow The row index for the aoData data store
+ * @default null
+ */
+ "fnCreatedCell": null,
+
+ /**
+ * Function to get data from a cell in a column. You should <b>never</b>
+ * access data directly through _aData internally in DataTables - always use
+ * the method attached to this property. It allows mData to function as
+ * required. This function is automatically assigned by the column
+ * initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {string} sSpecific The specific data type you want to get -
+ * 'display', 'type' 'filter' 'sort'
+ * @returns {*} The data for the cell from the given row's data
+ * @default null
+ */
+ "fnGetData": null,
+
+ /**
+ * <code>Deprecated</code> Custom display function that will be called for the
+ * display of each cell in this column.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type function
+ * @param {object} o Object with the following parameters:
+ * @param {int} o.iDataRow The row in aoData
+ * @param {int} o.iDataColumn The column in question
+ * @param {array} o.aData The data for the row in question
+ * @param {object} o.oSettings The settings object for this DataTables instance
+ * @returns {string} The string you which to use in the display
+ * @default null
+ * @deprecated
+ */
+ "fnRender": null,
+
+ /**
+ * Function to set data for a cell in the column. You should <b>never</b>
+ * set the data directly to _aData internally in DataTables - always use
+ * this method. It allows mData to function as required. This function
+ * is automatically assigned by the column initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {*} sValue Value to set
+ * @default null
+ */
+ "fnSetData": null,
+
+ /**
+ * Property to read the value for the cells in the column from the data
+ * source array / object. If null, then the default content is used, if a
+ * function is given then the return from the function is used.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mData": null,
+
+ /**
+ * Partner property to mData which is used (only when defined) to get
+ * the data - i.e. it is basically the same as mData, but without the
+ * 'set' option, and also the data fed to it is the result from mData.
+ * This is the rendering method to match the data method of mData.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mRender": null,
+
+ /**
+ * Unique header TH/TD element for this column - this is what the sorting
+ * listener is attached to (if sorting is enabled.)
+ * @type node
+ * @default null
+ */
+ "nTh": null,
+
+ /**
+ * Unique footer TH/TD element for this column (if there is one). Not used
+ * in DataTables as such, but can be used for plug-ins to reference the
+ * footer for each column.
+ * @type node
+ * @default null
+ */
+ "nTf": null,
+
+ /**
+ * The class to apply to all TD elements in the table's TBODY for the column
+ * @type string
+ * @default null
+ */
+ "sClass": null,
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * @type string
+ */
+ "sContentPadding": null,
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because mData
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ */
+ "sDefaultContent": null,
+
+ /**
+ * Name for the column, allowing reference to the column by name as well as
+ * by index (needs a lookup to work by name).
+ * @type string
+ */
+ "sName": null,
+
+ /**
+ * Custom sorting data type - defines which of the available plug-ins in
+ * afnSortData the custom sorting will use - if any is defined.
+ * @type string
+ * @default std
+ */
+ "sSortDataType": 'std',
+
+ /**
+ * Class to be applied to the header element when sorting on this column
+ * @type string
+ * @default null
+ */
+ "sSortingClass": null,
+
+ /**
+ * Class to be applied to the header element when sorting on this column -
+ * when jQuery UI theming is used.
+ * @type string
+ * @default null
+ */
+ "sSortingClassJUI": null,
+
+ /**
+ * Title of the column - what is seen in the TH element (nTh).
+ * @type string
+ */
+ "sTitle": null,
+
+ /**
+ * Column sorting and filtering type
+ * @type string
+ * @default null
+ */
+ "sType": null,
+
+ /**
+ * Width of the column
+ * @type string
+ * @default null
+ */
+ "sWidth": null,
+
+ /**
+ * Width of the column when it was first "encountered"
+ * @type string
+ * @default null
+ */
+ "sWidthOrig": null
+ };
+
+
+
+ /**
+ * Initialisation options that can be given to DataTables at initialisation
+ * time.
+ * @namespace
+ */
+ DataTable.defaults = {
+ /**
+ * An array of data to use for the table, passed in at initialisation which
+ * will be used in preference to any data which is already in the DOM. This is
+ * particularly useful for constructing tables purely in Javascript, for
+ * example with a custom Ajax call.
+ * @type array
+ * @default null
+ * @dtopt Option
+ *
+ * @example
+ * // Using a 2D array data source
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "aaData": [
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
+ * ],
+ * "aoColumns": [
+ * { "sTitle": "Engine" },
+ * { "sTitle": "Browser" },
+ * { "sTitle": "Platform" },
+ * { "sTitle": "Version" },
+ * { "sTitle": "Grade" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using an array of objects as a data source (mData)
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "aaData": [
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 4.0",
+ * "platform": "Win 95+",
+ * "version": 4,
+ * "grade": "X"
+ * },
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 5.0",
+ * "platform": "Win 95+",
+ * "version": 5,
+ * "grade": "C"
+ * }
+ * ],
+ * "aoColumns": [
+ * { "sTitle": "Engine", "mData": "engine" },
+ * { "sTitle": "Browser", "mData": "browser" },
+ * { "sTitle": "Platform", "mData": "platform" },
+ * { "sTitle": "Version", "mData": "version" },
+ * { "sTitle": "Grade", "mData": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "aaData": null,
+
+
+ /**
+ * If sorting is enabled, then DataTables will perform a first pass sort on
+ * initialisation. You can define which column(s) the sort is performed upon,
+ * and the sorting direction, with this variable. The aaSorting array should
+ * contain an array for each column to be sorted initially containing the
+ * column's index and a direction string ('asc' or 'desc').
+ * @type array
+ * @default [[0,'asc']]
+ * @dtopt Option
+ *
+ * @example
+ * // Sort by 3rd column first, and then 4th column
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSorting": [[2,'asc'], [3,'desc']]
+ * } );
+ * } );
+ *
+ * // No initial sorting
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSorting": []
+ * } );
+ * } );
+ */
+ "aaSorting": [[0,'asc']],
+
+
+ /**
+ * This parameter is basically identical to the aaSorting parameter, but
+ * cannot be overridden by user interaction with the table. What this means
+ * is that you could have a column (visible or hidden) which the sorting will
+ * always be forced on first - any sorting after that (from the user) will
+ * then be performed as required. This can be useful for grouping rows
+ * together.
+ * @type array
+ * @default null
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSortingFixed": [[0,'asc']]
+ * } );
+ * } )
+ */
+ "aaSortingFixed": null,
+
+
+ /**
+ * This parameter allows you to readily specify the entries in the length drop
+ * down menu that DataTables shows when pagination is enabled. It can be
+ * either a 1D array of options which will be used for both the displayed
+ * option and the value, or a 2D array which will use the array in the first
+ * position as the value, and the array in the second position as the
+ * displayed options (useful for language strings such as 'All').
+ * @type array
+ * @default [ 10, 25, 50, 100 ]
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
+ * } );
+ * } );
+ *
+ * @example
+ * // Setting the default display length as well as length menu
+ * // This is likely to be wanted if you remove the '10' option which
+ * // is the iDisplayLength default.
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayLength": 25,
+ * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
+ * } );
+ * } );
+ */
+ "aLengthMenu": [ 10, 25, 50, 100 ],
+
+
+ /**
+ * The aoColumns option in the initialisation parameter allows you to define
+ * details about the way individual columns behave. For a full list of
+ * column options that can be set, please see
+ * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
+ * define your columns, you must have an entry in the array for every single
+ * column that you have in your table (these can be null if you don't which
+ * to specify any options).
+ * @member
+ */
+ "aoColumns": null,
+
+ /**
+ * Very similar to aoColumns, aoColumnDefs allows you to target a specific
+ * column, multiple columns, or all columns, using the aTargets property of
+ * each object in the array. This allows great flexibility when creating
+ * tables, as the aoColumnDefs arrays can be of any length, targeting the
+ * columns you specifically want. aoColumnDefs may use any of the column
+ * options available: {@link DataTable.defaults.columns}, but it _must_
+ * have aTargets defined in each object in the array. Values in the aTargets
+ * array may be:
+ * <ul>
+ * <li>a string - class name will be matched on the TH for the column</li>
+ * <li>0 or a positive integer - column index counting from the left</li>
+ * <li>a negative integer - column index counting from the right</li>
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
+ * </ul>
+ * @member
+ */
+ "aoColumnDefs": null,
+
+
+ /**
+ * Basically the same as oSearch, this parameter defines the individual column
+ * filtering state at initialisation time. The array must be of the same size
+ * as the number of columns, and each element be an object with the parameters
+ * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
+ * accepted and the default will be used.
+ * @type array
+ * @default []
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoSearchCols": [
+ * null,
+ * { "sSearch": "My filter" },
+ * null,
+ * { "sSearch": "^[0-9]", "bEscapeRegex": false }
+ * ]
+ * } );
+ * } )
+ */
+ "aoSearchCols": [],
+
+
+ /**
+ * An array of CSS classes that should be applied to displayed rows. This
+ * array may be of any length, and DataTables will apply each class
+ * sequentially, looping when required.
+ * @type array
+ * @default null <i>Will take the values determined by the oClasses.sStripe*
+ * options</i>
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
+ * } );
+ * } )
+ */
+ "asStripeClasses": null,
+
+
+ /**
+ * Enable or disable automatic column width calculation. This can be disabled
+ * as an optimisation (it takes some time to calculate the widths) if the
+ * tables widths are passed in using aoColumns.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bAutoWidth": false
+ * } );
+ * } );
+ */
+ "bAutoWidth": true,
+
+
+ /**
+ * Deferred rendering can provide DataTables with a huge speed boost when you
+ * are using an Ajax or JS data source for the table. This option, when set to
+ * true, will cause DataTables to defer the creation of the table elements for
+ * each row until they are needed for a draw - saving a significant amount of
+ * time.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/arrays.txt",
+ * "bDeferRender": true
+ * } );
+ * } );
+ */
+ "bDeferRender": false,
+
+
+ /**
+ * Replace a DataTable which matches the given selector and replace it with
+ * one which has the properties of the new initialisation object passed. If no
+ * table matches the selector, then the new DataTable will be constructed as
+ * per normal.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ *
+ * // Some time later....
+ * $('#example').dataTable( {
+ * "bFilter": false,
+ * "bDestroy": true
+ * } );
+ * } );
+ */
+ "bDestroy": false,
+
+
+ /**
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
+ * that it allows the end user to input multiple words (space separated) and
+ * will match a row containing those words, even if not in the order that was
+ * specified (this allow matching across multiple columns). Note that if you
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
+ * default filtering input box and retain filtering abilities, please use
+ * {@link DataTable.defaults.sDom}.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bFilter": false
+ * } );
+ * } );
+ */
+ "bFilter": true,
+
+
+ /**
+ * Enable or disable the table information display. This shows information
+ * about the data that is currently visible on the page, including information
+ * about filtered data if that action is being performed.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bInfo": false
+ * } );
+ * } );
+ */
+ "bInfo": true,
+
+
+ /**
+ * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
+ * slightly different and additional mark-up from what DataTables has
+ * traditionally used).
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bJQueryUI": true
+ * } );
+ * } );
+ */
+ "bJQueryUI": false,
+
+
+ /**
+ * Allows the end user to select the size of a formatted page from a select
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bLengthChange": false
+ * } );
+ * } );
+ */
+ "bLengthChange": true,
+
+
+ /**
+ * Enable or disable pagination.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bPaginate": false
+ * } );
+ * } );
+ */
+ "bPaginate": true,
+
+
+ /**
+ * Enable or disable the display of a 'processing' indicator when the table is
+ * being processed (e.g. a sort). This is particularly useful for tables with
+ * large amounts of data where it can take a noticeable amount of time to sort
+ * the entries.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bProcessing": true
+ * } );
+ * } );
+ */
+ "bProcessing": false,
+
+
+ /**
+ * Retrieve the DataTables object for the given selector. Note that if the
+ * table has already been initialised, this parameter will cause DataTables
+ * to simply return the object that has already been set up - it will not take
+ * account of any changes you might have made to the initialisation object
+ * passed to DataTables (setting this parameter to true is an acknowledgement
+ * that you understand this). bDestroy can be used to reinitialise a table if
+ * you need.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * initTable();
+ * tableActions();
+ * } );
+ *
+ * function initTable ()
+ * {
+ * return $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false,
+ * "bRetrieve": true
+ * } );
+ * }
+ *
+ * function tableActions ()
+ * {
+ * var oTable = initTable();
+ * // perform API operations with oTable
+ * }
+ */
+ "bRetrieve": false,
+
+
+ /**
+ * Indicate if DataTables should be allowed to set the padding / margin
+ * etc for the scrolling header elements or not. Typically you will want
+ * this.
+ * @type boolean
+ * @default true
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollAutoCss": false,
+ * "sScrollY": "200px"
+ * } );
+ * } );
+ */
+ "bScrollAutoCss": true,
+
+
+ /**
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
+ * the table's viewport to the given height at all times (useful for layout).
+ * However, this can look odd when filtering data down to a small data set,
+ * and the footer is left "floating" further down. This parameter (when
+ * enabled) will cause DataTables to collapse the table's viewport down when
+ * the result set will fit within the given Y height.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200",
+ * "bScrollCollapse": true
+ * } );
+ * } );
+ */
+ "bScrollCollapse": false,
+
+
+ /**
+ * Enable infinite scrolling for DataTables (to be used in combination with
+ * sScrollY). Infinite scrolling means that DataTables will continually load
+ * data as a user scrolls through a table, which is very useful for large
+ * dataset. This cannot be used with pagination, which is automatically
+ * disabled. Note - the Scroller extra for DataTables is recommended in
+ * in preference to this option.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollInfinite": true,
+ * "bScrollCollapse": true,
+ * "sScrollY": "200px"
+ * } );
+ * } );
+ */
+ "bScrollInfinite": false,
+
+
+ /**
+ * Configure DataTables to use server-side processing. Note that the
+ * sAjaxSource parameter must also be given in order to give DataTables a
+ * source to obtain the required data for each draw.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "xhr.php"
+ * } );
+ * } );
+ */
+ "bServerSide": false,
+
+
+ /**
+ * Enable or disable sorting of columns. Sorting of individual columns can be
+ * disabled by the "bSortable" option for each column.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bSort": false
+ * } );
+ * } );
+ */
+ "bSort": true,
+
+
+ /**
+ * Allows control over whether DataTables should use the top (true) unique
+ * cell that is found for a single column, or the bottom (false - default).
+ * This is useful when using complex headers.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bSortCellsTop": true
+ * } );
+ * } );
+ */
+ "bSortCellsTop": false,
+
+
+ /**
+ * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
+ * 'sorting_3' to the columns which are currently being sorted on. This is
+ * presented as a feature switch as it can increase processing time (while
+ * classes are removed and added) so for large data sets you might want to
+ * turn this off.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bSortClasses": false
+ * } );
+ * } );
+ */
+ "bSortClasses": true,
+
+
+ /**
+ * Enable or disable state saving. When enabled a cookie will be used to save
+ * table display information such as pagination information, display length,
+ * filtering and sorting. As such when the end user reloads the page the
+ * display display will match what thy had previously set up.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bStateSave": true
+ * } );
+ * } );
+ */
+ "bStateSave": false,
+
+
+ /**
+ * Customise the cookie and / or the parameters being stored when using
+ * DataTables with state saving enabled. This function is called whenever
+ * the cookie is modified, and it expects a fully formed cookie string to be
+ * returned. Note that the data object passed in is a Javascript object which
+ * must be converted to a string (JSON.stringify for example).
+ * @type function
+ * @param {string} sName Name of the cookie defined by DataTables
+ * @param {object} oData Data to be stored in the cookie
+ * @param {string} sExpires Cookie expires string
+ * @param {string} sPath Path of the cookie to set
+ * @returns {string} Cookie formatted string (which should be encoded by
+ * using encodeURIComponent())
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "fnCookieCallback": function (sName, oData, sExpires, sPath) {
+ * // Customise oData or sName or whatever else here
+ * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
+ * }
+ * } );
+ * } );
+ */
+ "fnCookieCallback": null,
+
+
+ /**
+ * This function is called when a TR element is created (and all TD child
+ * elements have been inserted), or registered if using a DOM source, allowing
+ * manipulation of the TR element (adding classes etc).
+ * @type function
+ * @param {node} nRow "TR" element for the current row
+ * @param {array} aData Raw data array for this row
+ * @param {int} iDataIndex The index of this row in aoData
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnCreatedRow": function( nRow, aData, iDataIndex ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( aData[4] == "A" )
+ * {
+ * $('td:eq(4)', nRow).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnCreatedRow": null,
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify any aspect you want about the created DOM.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnDrawCallback": function( oSettings ) {
+ * alert( 'DataTables has redrawn the table' );
+ * }
+ * } );
+ * } );
+ */
+ "fnDrawCallback": null,
+
+
+ /**
+ * Identical to fnHeaderCallback() but for the table footer this function
+ * allows you to modify the table footer on every 'draw' even.
+ * @type function
+ * @param {node} nFoot "TR" element for the footer
+ * @param {array} aData Full table data (as derived from the original HTML)
+ * @param {int} iStart Index for the current display starting point in the
+ * display array
+ * @param {int} iEnd Index for the current display ending point in the
+ * display array
+ * @param {array int} aiDisplay Index array to translate the visual position
+ * to the full data array
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
+ * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
+ * }
+ * } );
+ * } )
+ */
+ "fnFooterCallback": null,
+
+
+ /**
+ * When rendering large numbers in the information element for the table
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
+ * rendered as "1,000,000") to help readability for the end user. This
+ * function will override the default method DataTables uses.
+ * @type function
+ * @member
+ * @param {int} iIn number to be formatted
+ * @returns {string} formatted string for DataTables to show the number
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnFormatNumber": function ( iIn ) {
+ * if ( iIn &lt; 1000 ) {
+ * return iIn;
+ * } else {
+ * var
+ * s=(iIn+""),
+ * a=s.split(""), out="",
+ * iLen=s.length;
+ *
+ * for ( var i=0 ; i&lt;iLen ; i++ ) {
+ * if ( i%3 === 0 &amp;&amp; i !== 0 ) {
+ * out = "'"+out;
+ * }
+ * out = a[iLen-i-1]+out;
+ * }
+ * }
+ * return out;
+ * };
+ * } );
+ * } );
+ */
+ "fnFormatNumber": function ( iIn ) {
+ if ( iIn < 1000 )
+ {
+ // A small optimisation for what is likely to be the majority of use cases
+ return iIn;
+ }
+
+ var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
+
+ for ( var i=0 ; i<iLen ; i++ )
+ {
+ if ( i%3 === 0 && i !== 0 )
+ {
+ out = this.oLanguage.sInfoThousands+out;
+ }
+ out = a[iLen-i-1]+out;
+ }
+ return out;
+ },
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify the header row. This can be used to calculate and
+ * display useful information about the table.
+ * @type function
+ * @param {node} nHead "TR" element for the header
+ * @param {array} aData Full table data (as derived from the original HTML)
+ * @param {int} iStart Index for the current display starting point in the
+ * display array
+ * @param {int} iEnd Index for the current display ending point in the
+ * display array
+ * @param {array int} aiDisplay Index array to translate the visual position
+ * to the full data array
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
+ * nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+ * }
+ * } );
+ * } )
+ */
+ "fnHeaderCallback": null,
+
+
+ /**
+ * The information element can be used to convey information about the current
+ * state of the table. Although the internationalisation options presented by
+ * DataTables are quite capable of dealing with most customisations, there may
+ * be times where you wish to customise the string further. This callback
+ * allows you to do exactly that.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {int} iStart Starting position in data for the draw
+ * @param {int} iEnd End position in data for the draw
+ * @param {int} iMax Total number of rows in the table (regardless of
+ * filtering)
+ * @param {int} iTotal Total number of rows in the data set, after filtering
+ * @param {string} sPre The string that DataTables has formatted using it's
+ * own rules
+ * @returns {string} The string to be displayed in the information element.
+ * @dtopt Callbacks
+ *
+ * @example
+ * $('#example').dataTable( {
+ * "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
+ * return iStart +" to "+ iEnd;
+ * }
+ * } );
+ */
+ "fnInfoCallback": null,
+
+
+ /**
+ * Called when the table has been initialised. Normally DataTables will
+ * initialise sequentially and there will be no need for this function,
+ * however, this does not hold true when using external language information
+ * since that is obtained using an async XHR call.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The JSON object request from the server - only
+ * present if client-side Ajax sourced data is used
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnInitComplete": function(oSettings, json) {
+ * alert( 'DataTables has finished its initialisation.' );
+ * }
+ * } );
+ * } )
+ */
+ "fnInitComplete": null,
+
+
+ /**
+ * Called at the very start of each table draw and can be used to cancel the
+ * draw by returning false, any other return (including undefined) results in
+ * the full draw occurring).
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @returns {boolean} False will cancel the draw, anything else (including no
+ * return) will allow it to complete.
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnPreDrawCallback": function( oSettings ) {
+ * if ( $('#test').val() == 1 ) {
+ * return false;
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnPreDrawCallback": null,
+
+
+ /**
+ * This function allows you to 'post process' each row after it have been
+ * generated for each table draw, but before it is rendered on screen. This
+ * function might be used for setting the row class name etc.
+ * @type function
+ * @param {node} nRow "TR" element for the current row
+ * @param {array} aData Raw data array for this row
+ * @param {int} iDisplayIndex The display index for the current table draw
+ * @param {int} iDisplayIndexFull The index of the data in the full list of
+ * rows (after filtering)
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( aData[4] == "A" )
+ * {
+ * $('td:eq(4)', nRow).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnRowCallback": null,
+
+
+ /**
+ * This parameter allows you to override the default function which obtains
+ * the data from the server ($.getJSON) so something more suitable for your
+ * application. For example you could use POST data, or pull information from
+ * a Gears or AIR database.
+ * @type function
+ * @member
+ * @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
+ * @param {array} aoData A key/value pair object containing the data to send
+ * to the server
+ * @param {function} fnCallback to be called on completion of the data get
+ * process that will draw the data on the page.
+ * @param {object} oSettings DataTables settings object
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ *
+ * @example
+ * // POST data to server
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bProcessing": true,
+ * "bServerSide": true,
+ * "sAjaxSource": "xhr.php",
+ * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
+ * oSettings.jqXHR = $.ajax( {
+ * "dataType": 'json',
+ * "type": "POST",
+ * "url": sSource,
+ * "data": aoData,
+ * "success": fnCallback
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
+ oSettings.jqXHR = $.ajax( {
+ "url": sUrl,
+ "data": aoData,
+ "success": function (json) {
+ if ( json.sError ) {
+ oSettings.oApi._fnLog( oSettings, 0, json.sError );
+ }
+
+ $(oSettings.oInstance).trigger('xhr', [oSettings, json]);
+ fnCallback( json );
+ },
+ "dataType": "json",
+ "cache": false,
+ "type": oSettings.sServerMethod,
+ "error": function (xhr, error, thrown) {
+ if ( error == "parsererror" ) {
+ oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
+ "server could not be parsed. This is caused by a JSON formatting error." );
+ }
+ }
+ } );
+ },
+
+
+ /**
+ * It is often useful to send extra data to the server when making an Ajax
+ * request - for example custom filtering information, and this callback
+ * function makes it trivial to send extra information to the server. The
+ * passed in parameter is the data set that has been constructed by
+ * DataTables, and you can add to this or modify it as you require.
+ * @type function
+ * @param {array} aoData Data array (array of objects which are name/value
+ * pairs) that has been constructed by DataTables and will be sent to the
+ * server. In the case of Ajax sourced data with server-side processing
+ * this will be an empty array, for server-side processing there will be a
+ * significant number of parameters!
+ * @returns {undefined} Ensure that you modify the aoData array passed in,
+ * as this is passed by reference.
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bProcessing": true,
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "fnServerParams": function ( aoData ) {
+ * aoData.push( { "name": "more_data", "value": "my_value" } );
+ * }
+ * } );
+ * } );
+ */
+ "fnServerParams": null,
+
+
+ /**
+ * Load the table state. With this function you can define from where, and how, the
+ * state of a table is loaded. By default DataTables will load from its state saving
+ * cookie, but you might wish to use local storage (HTML5) or a server-side database.
+ * @type function
+ * @member
+ * @param {object} oSettings DataTables settings object
+ * @return {object} The DataTables state object to be loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoad": function (oSettings) {
+ * var o;
+ *
+ * // Send an Ajax request to the server to get the data. Note that
+ * // this is a synchronous request.
+ * $.ajax( {
+ * "url": "/state_load",
+ * "async": false,
+ * "dataType": "json",
+ * "success": function (json) {
+ * o = json;
+ * }
+ * } );
+ *
+ * return o;
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoad": function ( oSettings ) {
+ var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
+ var oData;
+
+ try {
+ oData = (typeof $.parseJSON === 'function') ?
+ $.parseJSON(sData) : eval( '('+sData+')' );
+ } catch (e) {
+ oData = null;
+ }
+
+ return oData;
+ },
+
+
+ /**
+ * Callback which allows modification of the saved state prior to loading that state.
+ * This callback is called when the table is loading state from the stored data, but
+ * prior to the settings object being modified by the saved state. Note that for
+ * plug-in authors, you should use the 'stateLoadParams' event to load parameters for
+ * a plug-in.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object that is to be loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never loaded
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoadParams": function (oSettings, oData) {
+ * oData.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Disallow state loading by returning false
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoadParams": function (oSettings, oData) {
+ * return false;
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoadParams": null,
+
+
+ /**
+ * Callback that is called when the state has been loaded from the state saving method
+ * and the DataTables settings object has been modified as a result of the loaded state.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object that was loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Show an alert with the filtering value that was saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoaded": function (oSettings, oData) {
+ * alert( 'Saved filter was: '+oData.oSearch.sSearch );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoaded": null,
+
+
+ /**
+ * Save the table state. This function allows you to define where and how the state
+ * information for the table is stored - by default it will use a cookie, but you
+ * might want to use local storage (HTML5) or a server-side database.
+ * @type function
+ * @member
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object to be saved
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateSave": function (oSettings, oData) {
+ * // Send an Ajax request to the server with the state object
+ * $.ajax( {
+ * "url": "/state_save",
+ * "data": oData,
+ * "dataType": "json",
+ * "method": "POST"
+ * "success": function () {}
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSave": function ( oSettings, oData ) {
+ this.oApi._fnCreateCookie(
+ oSettings.sCookiePrefix+oSettings.sInstance,
+ this.oApi._fnJsonString(oData),
+ oSettings.iCookieDuration,
+ oSettings.sCookiePrefix,
+ oSettings.fnCookieCallback
+ );
+ },
+
+
+ /**
+ * Callback which allows modification of the state to be saved. Called when the table
+ * has changed state a new state save is required. This method allows modification of
+ * the state saving object prior to actually doing the save, including addition or
+ * other state properties or modification. Note that for plug-in authors, you should
+ * use the 'stateSaveParams' event to save parameters for a plug-in.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object to be saved
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateSaveParams": function (oSettings, oData) {
+ * oData.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSaveParams": null,
+
+
+ /**
+ * Duration of the cookie which is used for storing session information. This
+ * value is given in seconds.
+ * @type int
+ * @default 7200 <i>(2 hours)</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iCookieDuration": 60*60*24; // 1 day
+ * } );
+ * } )
+ */
+ "iCookieDuration": 7200,
+
+
+ /**
+ * When enabled DataTables will not make a request to the server for the first
+ * page draw - rather it will use the data already on the page (no sorting etc
+ * will be applied to it), thus saving on an XHR at load time. iDeferLoading
+ * is used to indicate that deferred loading is required, but it is also used
+ * to tell DataTables how many records there are in the full table (allowing
+ * the information element and pagination to be displayed correctly). In the case
+ * where a filtering is applied to the table on initial load, this can be
+ * indicated by giving the parameter as an array, where the first element is
+ * the number of records available after filtering and the second element is the
+ * number of records without filtering (allowing the table information element
+ * to be shown correctly).
+ * @type int | array
+ * @default null
+ * @dtopt Options
+ *
+ * @example
+ * // 57 records available in the table, no filtering applied
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "iDeferLoading": 57
+ * } );
+ * } );
+ *
+ * @example
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "iDeferLoading": [ 57, 100 ],
+ * "oSearch": {
+ * "sSearch": "my_filter"
+ * }
+ * } );
+ * } );
+ */
+ "iDeferLoading": null,
+
+
+ /**
+ * Number of rows to display on a single page when using pagination. If
+ * feature enabled (bLengthChange) then the end user will be able to override
+ * this to a custom setting using a pop-up menu.
+ * @type int
+ * @default 10
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayLength": 50
+ * } );
+ * } )
+ */
+ "iDisplayLength": 10,
+
+
+ /**
+ * Define the starting point for data display when using DataTables with
+ * pagination. Note that this parameter is the number of records, rather than
+ * the page number, so if you have 10 records per page and want to start on
+ * the third page, it should be "20".
+ * @type int
+ * @default 0
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayStart": 20
+ * } );
+ * } )
+ */
+ "iDisplayStart": 0,
+
+
+ /**
+ * The scroll gap is the amount of scrolling that is left to go before
+ * DataTables will load the next 'page' of data automatically. You typically
+ * want a gap which is big enough that the scrolling will be smooth for the
+ * user, while not so large that it will load more data than need.
+ * @type int
+ * @default 100
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollInfinite": true,
+ * "bScrollCollapse": true,
+ * "sScrollY": "200px",
+ * "iScrollLoadGap": 50
+ * } );
+ * } );
+ */
+ "iScrollLoadGap": 100,
+
+
+ /**
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
+ * and filtering) by adding a tabindex attribute to the required elements. This
+ * allows you to tab through the controls and press the enter key to activate them.
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
+ * disable built-in keyboard navigation.
+ * @type int
+ * @default 0
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iTabIndex": 1
+ * } );
+ * } );
+ */
+ "iTabIndex": 0,
+
+
+ /**
+ * All strings that DataTables uses in the user interface that it creates
+ * are defined in this object, allowing you to modified them individually or
+ * completely replace them all as required.
+ * @namespace
+ */
+ "oLanguage": {
+ /**
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
+ * actually visible on the page, but will be read by screenreaders, and thus
+ * must be internationalised as well).
+ * @namespace
+ */
+ "oAria": {
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted ascending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oAria": {
+ * "sSortAscending": " - click/return to sort ascending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortAscending": ": activate to sort column ascending",
+
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted descending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oAria": {
+ * "sSortDescending": " - click/return to sort descending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortDescending": ": activate to sort column descending"
+ },
+
+ /**
+ * Pagination string used by DataTables for the two built-in pagination
+ * control types ("two_button" and "full_numbers")
+ * @namespace
+ */
+ "oPaginate": {
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the first page.
+ * @type string
+ * @default First
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sFirst": "First page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sFirst": "First",
+
+
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the last page.
+ * @type string
+ * @default Last
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sLast": "Last page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sLast": "Last",
+
+
+ /**
+ * Text to use for the 'next' pagination button (to take the user to the
+ * next page).
+ * @type string
+ * @default Next
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sNext": "Next page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sNext": "Next",
+
+
+ /**
+ * Text to use for the 'previous' pagination button (to take the user to
+ * the previous page).
+ * @type string
+ * @default Previous
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sPrevious": "Previous page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sPrevious": "Previous"
+ },
+
+ /**
+ * This string is shown in preference to sZeroRecords when the table is
+ * empty of data (regardless of filtering). Note that this is an optional
+ * parameter - if it is not given, the value of sZeroRecords will be used
+ * instead (either the default or given value).
+ * @type string
+ * @default No data available in table
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sEmptyTable": "No data available in table"
+ * }
+ * } );
+ * } );
+ */
+ "sEmptyTable": "No data available in table",
+
+
+ /**
+ * This string gives information to the end user about the information that
+ * is current on display on the page. The _START_, _END_ and _TOTAL_
+ * variables are all dynamically replaced as the table display updates, and
+ * can be freely moved or removed as the language requirements change.
+ * @type string
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
+ * }
+ * } );
+ * } );
+ */
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+
+
+ /**
+ * Display information string for when the table is empty. Typically the
+ * format of this string should match sInfo.
+ * @type string
+ * @default Showing 0 to 0 of 0 entries
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoEmpty": "No entries to show"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+
+
+ /**
+ * When a user filters the information in a table, this string is appended
+ * to the information (sInfo) to give an idea of how strong the filtering
+ * is. The variable _MAX_ is dynamically updated.
+ * @type string
+ * @default (filtered from _MAX_ total entries)
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoFiltered": " - filtering from _MAX_ records"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
+
+
+ /**
+ * If can be useful to append extra information to the info string at times,
+ * and this variable does exactly that. This information will be appended to
+ * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
+ * being used) at all times.
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoPostFix": "All records shown are derived from real information."
+ * }
+ * } );
+ * } );
+ */
+ "sInfoPostFix": "",
+
+
+ /**
+ * DataTables has a build in number formatter (fnFormatNumber) which is used
+ * to format large numbers that are used in the table information. By
+ * default a comma is used, but this can be trivially changed to any
+ * character you wish with this parameter.
+ * @type string
+ * @default ,
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoThousands": "'"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoThousands": ",",
+
+
+ /**
+ * Detail the action that will be taken when the drop down menu for the
+ * pagination length option is changed. The '_MENU_' variable is replaced
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
+ * with a custom select box if required.
+ * @type string
+ * @default Show _MENU_ entries
+ * @dtopt Language
+ *
+ * @example
+ * // Language change only
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLengthMenu": "Display _MENU_ records"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Language and options change
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLengthMenu": 'Display <select>'+
+ * '<option value="10">10</option>'+
+ * '<option value="20">20</option>'+
+ * '<option value="30">30</option>'+
+ * '<option value="40">40</option>'+
+ * '<option value="50">50</option>'+
+ * '<option value="-1">All</option>'+
+ * '</select> records'
+ * }
+ * } );
+ * } );
+ */
+ "sLengthMenu": "Show _MENU_ entries",
+
+
+ /**
+ * When using Ajax sourced data and during the first draw when DataTables is
+ * gathering the data, this message is shown in an empty row in the table to
+ * indicate to the end user the the data is being loaded. Note that this
+ * parameter is not used when loading data by server-side processing, just
+ * Ajax sourced data with client-side processing.
+ * @type string
+ * @default Loading...
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLoadingRecords": "Please wait - loading..."
+ * }
+ * } );
+ * } );
+ */
+ "sLoadingRecords": "Loading...",
+
+
+ /**
+ * Text which is displayed when the table is processing a user action
+ * (usually a sort command or similar).
+ * @type string
+ * @default Processing...
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sProcessing": "DataTables is currently busy"
+ * }
+ * } );
+ * } );
+ */
+ "sProcessing": "Processing...",
+
+
+ /**
+ * Details the actions that will be taken when the user types into the
+ * filtering input text box. The variable "_INPUT_", if used in the string,
+ * is replaced with the HTML text box for the filtering input allowing
+ * control over where it appears in the string. If "_INPUT_" is not given
+ * then the input box is appended to the string automatically.
+ * @type string
+ * @default Search:
+ * @dtopt Language
+ *
+ * @example
+ * // Input text box will be appended at the end automatically
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sSearch": "Filter records:"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Specify where the filter should appear
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sSearch": "Apply filter _INPUT_ to table"
+ * }
+ * } );
+ * } );
+ */
+ "sSearch": "Search:",
+
+
+ /**
+ * All of the language information can be stored in a file on the
+ * server-side, which DataTables will look up if this parameter is passed.
+ * It must store the URL of the language file, which is in a JSON format,
+ * and the object has the same properties as the oLanguage object in the
+ * initialiser object (i.e. the above parameters). Please refer to one of
+ * the example language files to see how this works in action.
+ * @type string
+ * @default <i>Empty string - i.e. disabled</i>
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
+ * }
+ * } );
+ * } );
+ */
+ "sUrl": "",
+
+
+ /**
+ * Text shown inside the table records when the is no information to be
+ * displayed after filtering. sEmptyTable is shown when there is simply no
+ * information in the table at all (regardless of filtering).
+ * @type string
+ * @default No matching records found
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sZeroRecords": "No records to display"
+ * }
+ * } );
+ * } );
+ */
+ "sZeroRecords": "No matching records found"
+ },
+
+
+ /**
+ * This parameter allows you to have define the global filtering state at
+ * initialisation time. As an object the "sSearch" parameter must be
+ * defined, but all other parameters are optional. When "bRegex" is true,
+ * the search string will be treated as a regular expression, when false
+ * (default) it will be treated as a straight string. When "bSmart"
+ * DataTables will use it's smart filtering methods (to word match at
+ * any point in the data), when false this will not be done.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oSearch": {"sSearch": "Initial search"}
+ * } );
+ * } )
+ */
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
+
+
+ /**
+ * By default DataTables will look for the property 'aaData' when obtaining
+ * data from an Ajax source or for server-side processing - this parameter
+ * allows that property to be changed. You can use Javascript dotted object
+ * notation to get a data source for multiple levels of nesting.
+ * @type string
+ * @default aaData
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * // Get data from { "data": [...] }
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/data.txt",
+ * "sAjaxDataProp": "data"
+ * } );
+ * } );
+ *
+ * @example
+ * // Get data from { "data": { "inner": [...] } }
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/data.txt",
+ * "sAjaxDataProp": "data.inner"
+ * } );
+ * } );
+ */
+ "sAjaxDataProp": "aaData",
+
+
+ /**
+ * You can instruct DataTables to load data from an external source using this
+ * parameter (use aData if you want to pass data in you already have). Simply
+ * provide a url a JSON object can be obtained from. This object must include
+ * the parameter 'aaData' which is the data source for the table.
+ * @type string
+ * @default null
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
+ * } );
+ * } )
+ */
+ "sAjaxSource": null,
+
+
+ /**
+ * This parameter can be used to override the default prefix that DataTables
+ * assigns to a cookie when state saving is enabled.
+ * @type string
+ * @default SpryMedia_DataTables_
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sCookiePrefix": "my_datatable_",
+ * } );
+ * } );
+ */
+ "sCookiePrefix": "SpryMedia_DataTables_",
+
+
+ /**
+ * This initialisation variable allows you to specify exactly where in the
+ * DOM you want DataTables to inject the various controls it adds to the page
+ * (for example you might want the pagination controls at the top of the
+ * table). DIV elements (with or without a custom class) can also be added to
+ * aid styling. The follow syntax is used:
+ * <ul>
+ * <li>The following options are allowed:
+ * <ul>
+ * <li>'l' - Length changing</li
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * </li>
+ * <li>The following constants are allowed:
+ * <ul>
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
+ * </ul>
+ * </li>
+ * <li>The following syntax is expected:
+ * <ul>
+ * <li>'&lt;' and '&gt;' - div elements</li>
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
+ * </ul>
+ * </li>
+ * <li>Examples:
+ * <ul>
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * @type string
+ * @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b>
+ * <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
+ * } );
+ * } );
+ */
+ "sDom": "lfrtip",
+
+
+ /**
+ * DataTables features two different built-in pagination interaction methods
+ * ('two_button' or 'full_numbers') which present different page controls to
+ * the end user. Further methods can be added using the API (see below).
+ * @type string
+ * @default two_button
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sPaginationType": "full_numbers"
+ * } );
+ * } )
+ */
+ "sPaginationType": "two_button",
+
+
+ /**
+ * Enable horizontal scrolling. When a table is too wide to fit into a certain
+ * layout, or you have a large number of columns in the table, you can enable
+ * x-scrolling to show the table in a viewport, which can be scrolled. This
+ * property can be any CSS unit, or a number (in which case it will be treated
+ * as a pixel measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollX": "100%",
+ * "bScrollCollapse": true
+ * } );
+ * } );
+ */
+ "sScrollX": "",
+
+
+ /**
+ * This property can be used to force a DataTable to use more width than it
+ * might otherwise do when x-scrolling is enabled. For example if you have a
+ * table which requires to be well spaced, this parameter is useful for
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
+ * any CSS unit, or a number (in which case it will be treated as a pixel
+ * measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollX": "100%",
+ * "sScrollXInner": "110%"
+ * } );
+ * } );
+ */
+ "sScrollXInner": "",
+
+
+ /**
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
+ * to the given height, and enable scrolling for any data which overflows the
+ * current viewport. This can be used as an alternative to paging to display
+ * a lot of data in a small area (although paging and scrolling can both be
+ * enabled at the same time). This property can be any CSS unit, or a number
+ * (in which case it will be treated as a pixel measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ * } );
+ */
+ "sScrollY": "",
+
+
+ /**
+ * Set the HTTP method that is used to make the Ajax call for server-side
+ * processing or Ajax sourced data.
+ * @type string
+ * @default GET
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/post.php",
+ * "sServerMethod": "POST"
+ * } );
+ * } );
+ */
+ "sServerMethod": "GET"
+ };
+
+
+
+ /**
+ * Column options that can be given to DataTables at initialisation time.
+ * @namespace
+ */
+ DataTable.defaults.columns = {
+ /**
+ * Allows a column's sorting to take multiple columns into account when
+ * doing a sort. For example first name / last name columns make sense to
+ * do a multi-column sort over the two columns.
+ * @type array
+ * @default null <i>Takes the value of the column index automatically</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
+ * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
+ * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "aDataSort": [ 0, 1 ] },
+ * { "aDataSort": [ 1, 0 ] },
+ * { "aDataSort": [ 2, 3, 4 ] },
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "aDataSort": null,
+
+
+ /**
+ * You can control the default sorting direction, and even alter the behaviour
+ * of the sort handler (i.e. only allow ascending sorting etc) using this
+ * parameter.
+ * @type array
+ * @default [ 'asc', 'desc' ]
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
+ * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
+ * { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * { "asSorting": [ "asc" ] },
+ * { "asSorting": [ "desc", "asc", "asc" ] },
+ * { "asSorting": [ "desc" ] },
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "asSorting": [ 'asc', 'desc' ],
+
+
+ /**
+ * Enable or disable filtering on the data in this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bSearchable": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bSearchable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSearchable": true,
+
+
+ /**
+ * Enable or disable sorting on this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bSortable": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bSortable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSortable": true,
+
+
+ /**
+ * <code>Deprecated</code> When using fnRender() for a column, you may wish
+ * to use the original data (before rendering) for sorting and filtering
+ * (the default is to used the rendered data that the user can see). This
+ * may be useful for dates etc.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ * @deprecated
+ */
+ "bUseRendered": true,
+
+
+ /**
+ * Enable or disable the display of this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bVisible": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bVisible": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bVisible": true,
+
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} nTd The TD node that has been created
+ * @param {*} sData The Data for the cell
+ * @param {array|object} oData The data for the whole row
+ * @param {int} iRow The row index for the aoData data store
+ * @param {int} iCol The column index for aoColumns
+ * @dtopt Columns
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [3],
+ * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
+ * if ( sData == "1.7" ) {
+ * $(nTd).css('color', 'blue')
+ * }
+ * }
+ * } ]
+ * });
+ * } );
+ */
+ "fnCreatedCell": null,
+
+
+ /**
+ * <code>Deprecated</code> Custom display function that will be called for the
+ * display of each cell in this column.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type function
+ * @param {object} o Object with the following parameters:
+ * @param {int} o.iDataRow The row in aoData
+ * @param {int} o.iDataColumn The column in question
+ * @param {array} o.aData The data for the row in question
+ * @param {object} o.oSettings The settings object for this DataTables instance
+ * @param {object} o.mDataProp The data property used for this column
+ * @param {*} val The current cell value
+ * @returns {string} The string you which to use in the display
+ * @dtopt Columns
+ * @deprecated
+ */
+ "fnRender": null,
+
+
+ /**
+ * The column index (starting from 0!) that you wish a sort to be performed
+ * upon when this column is selected for sorting. This can be used for sorting
+ * on hidden columns for example.
+ * @type int
+ * @default -1 <i>Use automatically calculated column index</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "iDataSort": 1, "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "iDataSort": 1 },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "iDataSort": -1,
+
+
+ /**
+ * This parameter has been replaced by mData in DataTables to ensure naming
+ * consistency. mDataProp can still be used, as there is backwards compatibility
+ * in DataTables for this option, but it is strongly recommended that you use
+ * mData in preference to mDataProp.
+ * @name DataTable.defaults.columns.mDataProp
+ */
+
+
+ /**
+ * This property can be used to read data from any JSON data source property,
+ * including deeply nested objects / properties. mData can be given in a
+ * number of different ways which effect its behaviour:
+ * <ul>
+ * <li>integer - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).</li>
+ * <li>string - read an object property from the data source. Note that you can
+ * use Javascript dotted notation to read deep properties / arrays from the
+ * data source.</li>
+ * <li>null - the sDefaultContent option will be used for the cell (null
+ * by default, so you will need to specify the default content you want -
+ * typically an empty string). This can be useful on generated columns such
+ * as edit / delete action columns.</li>
+ * <li>function - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * <ul>
+ * <li>{array|object} The data source for the row</li>
+ * <li>{string} The type call data requested - this will be 'set' when
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined when
+ * gathering data. Note that when <i>undefined</i> is given for the type
+ * DataTables expects to get the raw data for the object back</li>
+ * <li>{*} Data to set when the second parameter is 'set'.</li>
+ * </ul>
+ * The return value from the function is not required when 'set' is the type
+ * of call, but otherwise the return is what will be used for the data
+ * requested.</li>
+ * </ul>
+ *
+ * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
+ * reflects the flexibility of this property and is consistent with the naming of
+ * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
+ * it automatically maps the old name to the new if required.
+ * @type string|int|function|null
+ * @default null <i>Use automatically calculated column index</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Read table data from objects
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/deep.txt",
+ * "aoColumns": [
+ * { "mData": "engine" },
+ * { "mData": "browser" },
+ * { "mData": "platform.inner" },
+ * { "mData": "platform.details.0" },
+ * { "mData": "platform.details.1" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using mData as a function to provide different information for
+ * // sorting, filtering and display. In this case, currency (price)
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [ 0 ],
+ * "mData": function ( source, type, val ) {
+ * if (type === 'set') {
+ * source.price = val;
+ * // Store the computed dislay and filter values for efficiency
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
+ * return;
+ * }
+ * else if (type === 'display') {
+ * return source.price_display;
+ * }
+ * else if (type === 'filter') {
+ * return source.price_filter;
+ * }
+ * // 'sort', 'type' and undefined all just use the integer
+ * return source.price;
+ * }
+ * } ]
+ * } );
+ * } );
+ */
+ "mData": null,
+
+
+ /**
+ * This property is the rendering partner to mData and it is suggested that
+ * when you want to manipulate data for display (including filtering, sorting etc)
+ * but not altering the underlying data for the table, use this property. mData
+ * can actually do everything this property can and more, but this parameter is
+ * easier to use since there is no 'set' option. Like mData is can be given
+ * in a number of different ways to effect its behaviour, with the addition of
+ * supporting array syntax for easy outputting of arrays (including arrays of
+ * objects):
+ * <ul>
+ * <li>integer - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).</li>
+ * <li>string - read an object property from the data source. Note that you can
+ * use Javascript dotted notation to read deep properties / arrays from the
+ * data source and also array brackets to indicate that the data reader should
+ * loop over the data source array. When characters are given between the array
+ * brackets, these characters are used to join the data source array together.
+ * For example: "accounts[, ].name" would result in a comma separated list with
+ * the 'name' value from the 'accounts' array of objects.</li>
+ * <li>function - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * <ul>
+ * <li>{array|object} The data source for the row (based on mData)</li>
+ * <li>{string} The type call data requested - this will be 'filter', 'display',
+ * 'type' or 'sort'.</li>
+ * <li>{array|object} The full data source for the row (not based on mData)</li>
+ * </ul>
+ * The return value from the function is what will be used for the data
+ * requested.</li>
+ * </ul>
+ * @type string|int|function|null
+ * @default null <i>Use mData</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Create a comma separated list from an array of objects
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/deep.txt",
+ * "aoColumns": [
+ * { "mData": "engine" },
+ * { "mData": "browser" },
+ * {
+ * "mData": "platform",
+ * "mRender": "[, ].name"
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Use as a function to create a link from the data source
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * {
+ * "aTargets": [ 0 ],
+ * "mData": "download_link",
+ * "mRender": function ( data, type, full ) {
+ * return '<a href="'+data+'">Download</a>';
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "mRender": null,
+
+
+ /**
+ * Change the cell type created for the column - either TD cells or TH cells. This
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
+ * @type string
+ * @default td
+ * @dtopt Columns
+ *
+ * @example
+ * // Make the first column use TH cells
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [ 0 ],
+ * "sCellType": "th"
+ * } ]
+ * } );
+ * } );
+ */
+ "sCellType": "td",
+
+
+ /**
+ * Class to give to each cell in this column.
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sClass": "my_class", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sClass": "my_class" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sClass": "",
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * Generally you shouldn't need this, and it is not documented on the
+ * general DataTables.net documentation
+ * @type string
+ * @default <i>Empty string<i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "sContentPadding": "mmm"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sContentPadding": "",
+
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because mData
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * {
+ * "mData": null,
+ * "sDefaultContent": "Edit",
+ * "aTargets": [ -1 ]
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "mData": null,
+ * "sDefaultContent": "Edit"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sDefaultContent": null,
+
+
+ /**
+ * This parameter is only used in DataTables' server-side processing. It can
+ * be exceptionally useful to know what columns are being displayed on the
+ * client side, and to map these to database fields. When defined, the names
+ * also allow DataTables to reorder information from the server if it comes
+ * back in an unexpected order (i.e. if you switch your columns around on the
+ * client-side, your server-side code does not also need updating).
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sName": "engine", "aTargets": [ 0 ] },
+ * { "sName": "browser", "aTargets": [ 1 ] },
+ * { "sName": "platform", "aTargets": [ 2 ] },
+ * { "sName": "version", "aTargets": [ 3 ] },
+ * { "sName": "grade", "aTargets": [ 4 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sName": "engine" },
+ * { "sName": "browser" },
+ * { "sName": "platform" },
+ * { "sName": "version" },
+ * { "sName": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "sName": "",
+
+
+ /**
+ * Defines a data source type for the sorting which can be used to read
+ * real-time information from the table (updating the internally cached
+ * version) prior to sorting. This allows sorting to occur on user editable
+ * elements such as form inputs.
+ * @type string
+ * @default std
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
+ * { "sType": "numeric", "aTargets": [ 3 ] },
+ * { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
+ * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * { "sSortDataType": "dom-text" },
+ * { "sSortDataType": "dom-text", "sType": "numeric" },
+ * { "sSortDataType": "dom-select" },
+ * { "sSortDataType": "dom-checkbox" }
+ * ]
+ * } );
+ * } );
+ */
+ "sSortDataType": "std",
+
+
+ /**
+ * The title of this column.
+ * @type string
+ * @default null <i>Derived from the 'TH' value for this column in the
+ * original HTML table.</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sTitle": "My column title", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sTitle": "My column title" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sTitle": null,
+
+
+ /**
+ * The type allows you to specify how the data for this column will be sorted.
+ * Four types (string, numeric, date and html (which will strip HTML tags
+ * before sorting)) are currently available. Note that only date formats
+ * understood by Javascript's Date() object will be accepted as type date. For
+ * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
+ * 'date' or 'html' (by default). Further types can be adding through
+ * plug-ins.
+ * @type string
+ * @default null <i>Auto-detected from raw data</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sType": "html", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sType": "html" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sType": null,
+
+
+ /**
+ * Defining the width of the column, this parameter may take any CSS value
+ * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
+ * been given a specific width through this interface ensuring that the table
+ * remains readable.
+ * @type string
+ * @default null <i>Automatic</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sWidth": "20%", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sWidth": "20%" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sWidth": null
+ };
+
+
+
+ /**
+ * DataTables settings object - this holds all the information needed for a
+ * given table, including configuration, data and current application of the
+ * table options. DataTables does not have a single instance for each DataTable
+ * with the settings attached to that instance, but rather instances of the
+ * DataTable "class" are created on-the-fly as needed (typically by a
+ * $().dataTable() call) and the settings object is then applied to that
+ * instance.
+ *
+ * Note that this object is related to {@link DataTable.defaults} but this
+ * one is the internal data store for DataTables's cache of columns. It should
+ * NOT be manipulated outside of DataTables. Any configuration should be done
+ * through the initialisation options.
+ * @namespace
+ * @todo Really should attach the settings object to individual instances so we
+ * don't need to create new instances on each $().dataTable() call (if the
+ * table already exists). It would also save passing oSettings around and
+ * into every single function. However, this is a very significant
+ * architecture change for DataTables and will almost certainly break
+ * backwards compatibility with older installations. This is something that
+ * will be done in 2.0.
+ */
+ DataTable.models.oSettings = {
+ /**
+ * Primary features of DataTables and their enablement state.
+ * @namespace
+ */
+ "oFeatures": {
+
+ /**
+ * Flag to say if DataTables should automatically try to calculate the
+ * optimum table and columns widths (true) or not (false).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bAutoWidth": null,
+
+ /**
+ * Delay the creation of TR and TD elements until they are actually
+ * needed by a driven page draw. This can give a significant speed
+ * increase for Ajax source and Javascript source data, but makes no
+ * difference at all fro DOM and server-side processing tables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bDeferRender": null,
+
+ /**
+ * Enable filtering on the table or not. Note that if this is disabled
+ * then there is no filtering at all on the table, including fnFilter.
+ * To just remove the filtering input use sDom and remove the 'f' option.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bFilter": null,
+
+ /**
+ * Table information element (the 'Showing x of y records' div) enable
+ * flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bInfo": null,
+
+ /**
+ * Present a user control allowing the end user to change the page size
+ * when pagination is enabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bLengthChange": null,
+
+ /**
+ * Pagination enabled or not. Note that if this is disabled then length
+ * changing must also be disabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bPaginate": null,
+
+ /**
+ * Processing indicator enable flag whenever DataTables is enacting a
+ * user request - typically an Ajax request for server-side processing.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bProcessing": null,
+
+ /**
+ * Server-side processing enabled flag - when enabled DataTables will
+ * get all data from the server for every draw - there is no filtering,
+ * sorting or paging done on the client-side.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bServerSide": null,
+
+ /**
+ * Sorting enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSort": null,
+
+ /**
+ * Apply a class to the columns which are being sorted to provide a
+ * visual highlight or not. This can slow things down when enabled since
+ * there is a lot of DOM interaction.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortClasses": null,
+
+ /**
+ * State saving enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bStateSave": null
+ },
+
+
+ /**
+ * Scrolling settings for a table.
+ * @namespace
+ */
+ "oScroll": {
+ /**
+ * Indicate if DataTables should be allowed to set the padding / margin
+ * etc for the scrolling header elements or not. Typically you will want
+ * this.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bAutoCss": null,
+
+ /**
+ * When the table is shorter in height than sScrollY, collapse the
+ * table container down to the height of the table (when true).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bCollapse": null,
+
+ /**
+ * Infinite scrolling enablement flag. Now deprecated in favour of
+ * using the Scroller plug-in.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bInfinite": null,
+
+ /**
+ * Width of the scrollbar for the web-browser's platform. Calculated
+ * during table initialisation.
+ * @type int
+ * @default 0
+ */
+ "iBarWidth": 0,
+
+ /**
+ * Space (in pixels) between the bottom of the scrolling container and
+ * the bottom of the scrolling viewport before the next page is loaded
+ * when using infinite scrolling.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type int
+ */
+ "iLoadGap": null,
+
+ /**
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
+ * disabled if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sX": null,
+
+ /**
+ * Width to expand the table to when using x-scrolling. Typically you
+ * should not need to use this.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @deprecated
+ */
+ "sXInner": null,
+
+ /**
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
+ * if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sY": null
+ },
+
+ /**
+ * Language information for the table.
+ * @namespace
+ * @extends DataTable.defaults.oLanguage
+ */
+ "oLanguage": {
+ /**
+ * Information callback function. See
+ * {@link DataTable.defaults.fnInfoCallback}
+ * @type function
+ * @default null
+ */
+ "fnInfoCallback": null
+ },
+
+ /**
+ * Browser support parameters
+ * @namespace
+ */
+ "oBrowser": {
+ /**
+ * Indicate if the browser incorrectly calculates width:100% inside a
+ * scrolling element (IE6/7)
+ * @type boolean
+ * @default false
+ */
+ "bScrollOversize": false
+ },
+
+ /**
+ * Array referencing the nodes which are used for the features. The
+ * parameters of this object match what is allowed by sDom - i.e.
+ * <ul>
+ * <li>'l' - Length changing</li>
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aanFeatures": [],
+
+ /**
+ * Store data information - see {@link DataTable.models.oRow} for detailed
+ * information.
+ * @type array
+ * @default []
+ */
+ "aoData": [],
+
+ /**
+ * Array of indexes which are in the current display (after filtering etc)
+ * @type array
+ * @default []
+ */
+ "aiDisplay": [],
+
+ /**
+ * Array of indexes for display - no filtering
+ * @type array
+ * @default []
+ */
+ "aiDisplayMaster": [],
+
+ /**
+ * Store information about each column that is in use
+ * @type array
+ * @default []
+ */
+ "aoColumns": [],
+
+ /**
+ * Store information about the table's header
+ * @type array
+ * @default []
+ */
+ "aoHeader": [],
+
+ /**
+ * Store information about the table's footer
+ * @type array
+ * @default []
+ */
+ "aoFooter": [],
+
+ /**
+ * Search data array for regular expression searching
+ * @type array
+ * @default []
+ */
+ "asDataSearch": [],
+
+ /**
+ * Store the applied global search information in case we want to force a
+ * research or compare the old search to a new one.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ */
+ "oPreviousSearch": {},
+
+ /**
+ * Store the applied search for each column - see
+ * {@link DataTable.models.oSearch} for the format that is used for the
+ * filtering information for each column.
+ * @type array
+ * @default []
+ */
+ "aoPreSearchCols": [],
+
+ /**
+ * Sorting that is applied to the table. Note that the inner arrays are
+ * used in the following manner:
+ * <ul>
+ * <li>Index 0 - column number</li>
+ * <li>Index 1 - current sorting direction</li>
+ * <li>Index 2 - index of asSorting for this column</li>
+ * </ul>
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @todo These inner arrays should really be objects
+ */
+ "aaSorting": null,
+
+ /**
+ * Sorting that is always applied to the table (i.e. prefixed in front of
+ * aaSorting).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array|null
+ * @default null
+ */
+ "aaSortingFixed": null,
+
+ /**
+ * Classes to use for the striping of a table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "asStripeClasses": null,
+
+ /**
+ * If restoring a table - we should restore its striping classes as well
+ * @type array
+ * @default []
+ */
+ "asDestroyStripes": [],
+
+ /**
+ * If restoring a table - we should restore its width
+ * @type int
+ * @default 0
+ */
+ "sDestroyWidth": 0,
+
+ /**
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
+ * @type array
+ * @default []
+ */
+ "aoRowCallback": [],
+
+ /**
+ * Callback functions for the header on each draw.
+ * @type array
+ * @default []
+ */
+ "aoHeaderCallback": [],
+
+ /**
+ * Callback function for the footer on each draw.
+ * @type array
+ * @default []
+ */
+ "aoFooterCallback": [],
+
+ /**
+ * Array of callback functions for draw callback functions
+ * @type array
+ * @default []
+ */
+ "aoDrawCallback": [],
+
+ /**
+ * Array of callback functions for row created function
+ * @type array
+ * @default []
+ */
+ "aoRowCreatedCallback": [],
+
+ /**
+ * Callback functions for just before the table is redrawn. A return of
+ * false will be used to cancel the draw.
+ * @type array
+ * @default []
+ */
+ "aoPreDrawCallback": [],
+
+ /**
+ * Callback functions for when the table has been initialised.
+ * @type array
+ * @default []
+ */
+ "aoInitComplete": [],
+
+
+ /**
+ * Callbacks for modifying the settings to be stored for state saving, prior to
+ * saving state.
+ * @type array
+ * @default []
+ */
+ "aoStateSaveParams": [],
+
+ /**
+ * Callbacks for modifying the settings that have been stored for state saving
+ * prior to using the stored values to restore the state.
+ * @type array
+ * @default []
+ */
+ "aoStateLoadParams": [],
+
+ /**
+ * Callbacks for operating on the settings object once the saved state has been
+ * loaded
+ * @type array
+ * @default []
+ */
+ "aoStateLoaded": [],
+
+ /**
+ * Cache the table ID for quick access
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sTableId": "",
+
+ /**
+ * The TABLE node for the main table
+ * @type node
+ * @default null
+ */
+ "nTable": null,
+
+ /**
+ * Permanent ref to the thead element
+ * @type node
+ * @default null
+ */
+ "nTHead": null,
+
+ /**
+ * Permanent ref to the tfoot element - if it exists
+ * @type node
+ * @default null
+ */
+ "nTFoot": null,
+
+ /**
+ * Permanent ref to the tbody element
+ * @type node
+ * @default null
+ */
+ "nTBody": null,
+
+ /**
+ * Cache the wrapper node (contains all DataTables controlled elements)
+ * @type node
+ * @default null
+ */
+ "nTableWrapper": null,
+
+ /**
+ * Indicate if when using server-side processing the loading of data
+ * should be deferred until the second draw.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ * @default false
+ */
+ "bDeferLoading": false,
+
+ /**
+ * Indicate if all required information has been read in
+ * @type boolean
+ * @default false
+ */
+ "bInitialised": false,
+
+ /**
+ * Information about open rows. Each object in the array has the parameters
+ * 'nTr' and 'nParent'
+ * @type array
+ * @default []
+ */
+ "aoOpenRows": [],
+
+ /**
+ * Dictate the positioning of DataTables' control elements - see
+ * {@link DataTable.model.oInit.sDom}.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sDom": null,
+
+ /**
+ * Which type of pagination should be used.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default two_button
+ */
+ "sPaginationType": "two_button",
+
+ /**
+ * The cookie duration (for bStateSave) in seconds.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type int
+ * @default 0
+ */
+ "iCookieDuration": 0,
+
+ /**
+ * The cookie name prefix.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sCookiePrefix": "",
+
+ /**
+ * Callback function for cookie creation.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ * @default null
+ */
+ "fnCookieCallback": null,
+
+ /**
+ * Array of callback functions for state saving. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the JSON string to save that has been thus far created. Returns
+ * a JSON string to be inserted into a json object
+ * (i.e. '"param": [ 0, 1, 2]')</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateSave": [],
+
+ /**
+ * Array of callback functions for state loading. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the object stored. May return false to cancel state loading</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateLoad": [],
+
+ /**
+ * State that was loaded from the cookie. Useful for back reference
+ * @type object
+ * @default null
+ */
+ "oLoadedState": null,
+
+ /**
+ * Source url for AJAX data for the table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sAjaxSource": null,
+
+ /**
+ * Property from a given object from which to read the table data from. This
+ * can be an empty string (when not server-side processing), in which case
+ * it is assumed an an array is given directly.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sAjaxDataProp": null,
+
+ /**
+ * Note if draw should be blocked while getting data
+ * @type boolean
+ * @default true
+ */
+ "bAjaxDataGet": true,
+
+ /**
+ * The last jQuery XHR object that was used for server-side data gathering.
+ * This can be used for working with the XHR information in one of the
+ * callbacks
+ * @type object
+ * @default null
+ */
+ "jqXHR": null,
+
+ /**
+ * Function to get the server-side data.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnServerData": null,
+
+ /**
+ * Functions which are called prior to sending an Ajax request so extra
+ * parameters can easily be sent to the server
+ * @type array
+ * @default []
+ */
+ "aoServerParams": [],
+
+ /**
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
+ * required).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sServerMethod": null,
+
+ /**
+ * Format numbers for display.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnFormatNumber": null,
+
+ /**
+ * List of options that can be used for the user selectable length menu.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "aLengthMenu": null,
+
+ /**
+ * Counter for the draws that the table does. Also used as a tracker for
+ * server-side processing
+ * @type int
+ * @default 0
+ */
+ "iDraw": 0,
+
+ /**
+ * Indicate if a redraw is being done - useful for Ajax
+ * @type boolean
+ * @default false
+ */
+ "bDrawing": false,
+
+ /**
+ * Draw index (iDraw) of the last error when parsing the returned data
+ * @type int
+ * @default -1
+ */
+ "iDrawError": -1,
+
+ /**
+ * Paging display length
+ * @type int
+ * @default 10
+ */
+ "_iDisplayLength": 10,
+
+ /**
+ * Paging start point - aiDisplay index
+ * @type int
+ * @default 0
+ */
+ "_iDisplayStart": 0,
+
+ /**
+ * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
+ * this property to get the end point
+ * @type int
+ * @default 10
+ * @private
+ */
+ "_iDisplayEnd": 10,
+
+ /**
+ * Server-side processing - number of records in the result set
+ * (i.e. before filtering), Use fnRecordsTotal rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type int
+ * @default 0
+ * @private
+ */
+ "_iRecordsTotal": 0,
+
+ /**
+ * Server-side processing - number of records in the current display set
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type boolean
+ * @default 0
+ * @private
+ */
+ "_iRecordsDisplay": 0,
+
+ /**
+ * Flag to indicate if jQuery UI marking and classes should be used.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bJUI": null,
+
+ /**
+ * The classes to use for the table
+ * @type object
+ * @default {}
+ */
+ "oClasses": {},
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if filtering has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bFiltered": false,
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if sorting has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bSorted": false,
+
+ /**
+ * Indicate that if multiple rows are in the header and there is more than
+ * one unique cell per column, if the top one (true) or bottom one (false)
+ * should be used for sorting / title by DataTables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortCellsTop": null,
+
+ /**
+ * Initialisation object that is used for the table
+ * @type object
+ * @default null
+ */
+ "oInit": null,
+
+ /**
+ * Destroy callback functions - for plug-ins to attach themselves to the
+ * destroy so they can clean up markup and events.
+ * @type array
+ * @default []
+ */
+ "aoDestroyCallback": [],
+
+
+ /**
+ * Get the number of records in the current record set, before filtering
+ * @type function
+ */
+ "fnRecordsTotal": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsTotal, 10);
+ } else {
+ return this.aiDisplayMaster.length;
+ }
+ },
+
+ /**
+ * Get the number of records in the current record set, after filtering
+ * @type function
+ */
+ "fnRecordsDisplay": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsDisplay, 10);
+ } else {
+ return this.aiDisplay.length;
+ }
+ },
+
+ /**
+ * Set the display end point - aiDisplay index
+ * @type function
+ * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
+ */
+ "fnDisplayEnd": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
+ return this._iDisplayStart+this.aiDisplay.length;
+ } else {
+ return Math.min( this._iDisplayStart+this._iDisplayLength,
+ this._iRecordsDisplay );
+ }
+ } else {
+ return this._iDisplayEnd;
+ }
+ },
+
+ /**
+ * The DataTables object for this table
+ * @type object
+ * @default null
+ */
+ "oInstance": null,
+
+ /**
+ * Unique identifier for each instance of the DataTables object. If there
+ * is an ID on the table node, then it takes that value, otherwise an
+ * incrementing internal counter is used.
+ * @type string
+ * @default null
+ */
+ "sInstance": null,
+
+ /**
+ * tabindex attribute value that is added to DataTables control elements, allowing
+ * keyboard navigation of the table and its controls.
+ */
+ "iTabIndex": 0,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollHead": null,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollFoot": null
+ };
+
+ /**
+ * Extension object for DataTables that is used to provide all extension options.
+ *
+ * Note that the <i>DataTable.ext</i> object is available through
+ * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
+ * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
+ * @namespace
+ * @extends DataTable.models.ext
+ */
+ DataTable.ext = $.extend( true, {}, DataTable.models.ext );
+
+ $.extend( DataTable.ext.oStdClasses, {
+ "sTable": "dataTable",
+
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "paginate_enabled_previous",
+ "sPagePrevDisabled": "paginate_disabled_previous",
+ "sPageNextEnabled": "paginate_enabled_next",
+ "sPageNextDisabled": "paginate_disabled_next",
+ "sPageJUINext": "",
+ "sPageJUIPrev": "",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "paginate_button",
+ "sPageButtonActive": "paginate_active",
+ "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
+ "sPageFirst": "first",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last",
+
+ /* Striping classes */
+ "sStripeOdd": "odd",
+ "sStripeEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "sorting_asc",
+ "sSortDesc": "sorting_desc",
+ "sSortable": "sorting", /* Sortable in both directions */
+ "sSortableAsc": "sorting_asc_disabled",
+ "sSortableDesc": "sorting_desc_disabled",
+ "sSortableNone": "sorting_disabled",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "",
+ "sSortJUIDesc": "",
+ "sSortJUI": "",
+ "sSortJUIAscAllowed": "",
+ "sSortJUIDescAllowed": "",
+ "sSortJUIWrapper": "",
+ "sSortIcon": "",
+
+ /* Scrolling */
+ "sScrollWrapper": "dataTables_scroll",
+ "sScrollHead": "dataTables_scrollHead",
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
+ "sScrollBody": "dataTables_scrollBody",
+ "sScrollFoot": "dataTables_scrollFoot",
+ "sScrollFootInner": "dataTables_scrollFootInner",
+
+ /* Misc */
+ "sFooterTH": "",
+ "sJUIHeader": "",
+ "sJUIFooter": ""
+ } );
+
+
+ $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
+ "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+ "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
+ "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
+ "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+ "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "fg-button ui-button ui-state-default",
+ "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageFirst": "first ui-corner-tl ui-corner-bl",
+ "sPageLast": "last ui-corner-tr ui-corner-br",
+
+ /* Features */
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
+
+ /* Sorting */
+ "sSortAsc": "ui-state-default",
+ "sSortDesc": "ui-state-default",
+ "sSortable": "ui-state-default",
+ "sSortableAsc": "ui-state-default",
+ "sSortableDesc": "ui-state-default",
+ "sSortableNone": "ui-state-default",
+ "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+ "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+ "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
+ "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
+ "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
+ "sSortJUIWrapper": "DataTables_sort_wrapper",
+ "sSortIcon": "DataTables_sort_icon",
+
+ /* Scrolling */
+ "sScrollHead": "dataTables_scrollHead ui-state-default",
+ "sScrollFoot": "dataTables_scrollFoot ui-state-default",
+
+ /* Misc */
+ "sFooterTH": "ui-state-default",
+ "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
+ "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
+ } );
+
+ /*
+ * Variable: oPagination
+ * Purpose:
+ * Scope: jQuery.fn.dataTableExt
+ */
+ $.extend( DataTable.ext.oPagination, {
+ /*
+ * Variable: two_button
+ * Purpose: Standard two button (forward/back) pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "two_button": {
+ /*
+ * Function: oPagination.two_button.fnInit
+ * Purpose: Initialise dom elements required for pagination with forward/back buttons only
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:nPaging - the DIV which contains this pagination control
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+ {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var oClasses = oSettings.oClasses;
+ var fnClickHandler = function ( e ) {
+ if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+ {
+ fnCallbackDraw( oSettings );
+ }
+ };
+
+ var sAppend = (!oSettings.bJUI) ?
+ '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
+ '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
+ :
+ '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
+ '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
+ $(nPaging).append( sAppend );
+
+ var els = $('a', nPaging);
+ var nPrevious = els[0],
+ nNext = els[1];
+
+ oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
+
+ /* ID the first elements only */
+ if ( !oSettings.aanFeatures.p )
+ {
+ nPaging.id = oSettings.sTableId+'_paginate';
+ nPrevious.id = oSettings.sTableId+'_previous';
+ nNext.id = oSettings.sTableId+'_next';
+
+ nPrevious.setAttribute('aria-controls', oSettings.sTableId);
+ nNext.setAttribute('aria-controls', oSettings.sTableId);
+ }
+ },
+
+ /*
+ * Function: oPagination.two_button.fnUpdate
+ * Purpose: Update the two button pagination at the end of the draw
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function to call on page change
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.aanFeatures.p )
+ {
+ return;
+ }
+
+ var oClasses = oSettings.oClasses;
+ var an = oSettings.aanFeatures.p;
+ var nNode;
+
+ /* Loop over each instance of the pager */
+ for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ nNode = an[i].firstChild;
+ if ( nNode )
+ {
+ /* Previous page */
+ nNode.className = ( oSettings._iDisplayStart === 0 ) ?
+ oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
+
+ /* Next page */
+ nNode = nNode.nextSibling;
+ nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
+ oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
+ }
+ }
+ }
+ },
+
+
+ /*
+ * Variable: iFullNumbersShowPages
+ * Purpose: Change the number of pages which can be seen
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "iFullNumbersShowPages": 5,
+
+ /*
+ * Variable: full_numbers
+ * Purpose: Full numbers pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "full_numbers": {
+ /*
+ * Function: oPagination.full_numbers.fnInit
+ * Purpose: Initialise dom elements required for pagination with a list of the pages
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:nPaging - the DIV which contains this pagination control
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+ {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var oClasses = oSettings.oClasses;
+ var fnClickHandler = function ( e ) {
+ if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+ {
+ fnCallbackDraw( oSettings );
+ }
+ };
+
+ $(nPaging).append(
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
+ '<span></span>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
+ );
+ var els = $('a', nPaging);
+ var nFirst = els[0],
+ nPrev = els[1],
+ nNext = els[2],
+ nLast = els[3];
+
+ oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler );
+
+ /* ID the first elements only */
+ if ( !oSettings.aanFeatures.p )
+ {
+ nPaging.id = oSettings.sTableId+'_paginate';
+ nFirst.id =oSettings.sTableId+'_first';
+ nPrev.id =oSettings.sTableId+'_previous';
+ nNext.id =oSettings.sTableId+'_next';
+ nLast.id =oSettings.sTableId+'_last';
+ }
+ },
+
+ /*
+ * Function: oPagination.full_numbers.fnUpdate
+ * Purpose: Update the list of page buttons shows
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function to call on page change
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.aanFeatures.p )
+ {
+ return;
+ }
+
+ var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
+ var iPageCountHalf = Math.floor(iPageCount / 2);
+ var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+ var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
+ var sList = "";
+ var iStartButton, iEndButton, i, iLen;
+ var oClasses = oSettings.oClasses;
+ var anButtons, anStatic, nPaginateList, nNode;
+ var an = oSettings.aanFeatures.p;
+ var fnBind = function (j) {
+ oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
+ /* Use the information in the element to jump to the required page */
+ oSettings.oApi._fnPageChange( oSettings, e.data.page );
+ fnCallbackDraw( oSettings );
+ e.preventDefault();
+ } );
+ };
+
+ /* Pages calculation */
+ if ( oSettings._iDisplayLength === -1 )
+ {
+ iStartButton = 1;
+ iEndButton = 1;
+ iCurrentPage = 1;
+ }
+ else if (iPages < iPageCount)
+ {
+ iStartButton = 1;
+ iEndButton = iPages;
+ }
+ else if (iCurrentPage <= iPageCountHalf)
+ {
+ iStartButton = 1;
+ iEndButton = iPageCount;
+ }
+ else if (iCurrentPage >= (iPages - iPageCountHalf))
+ {
+ iStartButton = iPages - iPageCount + 1;
+ iEndButton = iPages;
+ }
+ else
+ {
+ iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+ iEndButton = iStartButton + iPageCount - 1;
+ }
+
+
+ /* Build the dynamic list */
+ for ( i=iStartButton ; i<=iEndButton ; i++ )
+ {
+ sList += (iCurrentPage !== i) ?
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
+ }
+
+ /* Loop over each instance of the pager */
+ for ( i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ nNode = an[i];
+ if ( !nNode.hasChildNodes() )
+ {
+ continue;
+ }
+
+ /* Build up the dynamic list first - html and listeners */
+ $('span:eq(0)', nNode)
+ .html( sList )
+ .children('a').each( fnBind );
+
+ /* Update the permanent button's classes */
+ anButtons = nNode.getElementsByTagName('a');
+ anStatic = [
+ anButtons[0], anButtons[1],
+ anButtons[anButtons.length-2], anButtons[anButtons.length-1]
+ ];
+
+ $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
+ $([anStatic[0], anStatic[1]]).addClass(
+ (iCurrentPage==1) ?
+ oClasses.sPageButtonStaticDisabled :
+ oClasses.sPageButton
+ );
+ $([anStatic[2], anStatic[3]]).addClass(
+ (iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
+ oClasses.sPageButtonStaticDisabled :
+ oClasses.sPageButton
+ );
+ }
+ }
+ }
+ } );
+
+ $.extend( DataTable.ext.oSort, {
+ /*
+ * text sorting
+ */
+ "string-pre": function ( a )
+ {
+ if ( typeof a != 'string' ) {
+ a = (a !== null && a.toString) ? a.toString() : '';
+ }
+ return a.toLowerCase();
+ },
+
+ "string-asc": function ( x, y )
+ {
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "string-desc": function ( x, y )
+ {
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * html sorting (ignore html tags)
+ */
+ "html-pre": function ( a )
+ {
+ return a.replace( /<.*?>/g, "" ).toLowerCase();
+ },
+
+ "html-asc": function ( x, y )
+ {
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "html-desc": function ( x, y )
+ {
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * date sorting
+ */
+ "date-pre": function ( a )
+ {
+ var x = Date.parse( a );
+
+ if ( isNaN(x) || x==="" )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ return x;
+ },
+
+ "date-asc": function ( x, y )
+ {
+ return x - y;
+ },
+
+ "date-desc": function ( x, y )
+ {
+ return y - x;
+ },
+
+
+ /*
+ * numerical sorting
+ */
+ "numeric-pre": function ( a )
+ {
+ return (a=="-" || a==="") ? 0 : a*1;
+ },
+
+ "numeric-asc": function ( x, y )
+ {
+ return x - y;
+ },
+
+ "numeric-desc": function ( x, y )
+ {
+ return y - x;
+ }
+ } );
+
+
+ $.extend( DataTable.ext.aTypes, [
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is numeric
+ * Returns: string:'numeric' or null
+ * Inputs: mixed:sText - string to check
+ */
+ function ( sData )
+ {
+ /* Allow zero length strings as a number */
+ if ( typeof sData === 'number' )
+ {
+ return 'numeric';
+ }
+ else if ( typeof sData !== 'string' )
+ {
+ return null;
+ }
+
+ var sValidFirstChars = "0123456789-";
+ var sValidChars = "0123456789.";
+ var Char;
+ var bDecimal = false;
+
+ /* Check for a valid first char (no period and allow negatives) */
+ Char = sData.charAt(0);
+ if (sValidFirstChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Check all the other characters are valid */
+ for ( var i=1 ; i<sData.length ; i++ )
+ {
+ Char = sData.charAt(i);
+ if (sValidChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Only allowed one decimal place... */
+ if ( Char == "." )
+ {
+ if ( bDecimal )
+ {
+ return null;
+ }
+ bDecimal = true;
+ }
+ }
+
+ return 'numeric';
+ },
+
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is actually a formatted date
+ * Returns: string:'date' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ var iParse = Date.parse(sData);
+ if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
+ {
+ return 'date';
+ }
+ return null;
+ },
+
+ /*
+ * Function: -
+ * Purpose: Check to see if a string should be treated as an HTML string
+ * Returns: string:'html' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
+ {
+ return 'html';
+ }
+ return null;
+ }
+ ] );
+
+
+ // jQuery aliases
+ $.fn.DataTable = DataTable;
+ $.fn.dataTable = DataTable;
+ $.fn.dataTableSettings = DataTable.settings;
+ $.fn.dataTableExt = DataTable.ext;
+
+
+ // Information about events fired by DataTables - for documentation.
+ /**
+ * Draw event, fired whenever the table is redrawn on the page, at the same point as
+ * fnDrawCallback. This may be useful for binding events or performing calculations when
+ * the table is altered at all.
+ * @name DataTable#draw
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Filter event, fired when the filtering applied to the table (using the build in global
+ * global filter, or column filters) is altered.
+ * @name DataTable#filter
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Page change event, fired when the paging of the table is altered.
+ * @name DataTable#page
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Sort event, fired when the sorting applied to the table is altered.
+ * @name DataTable#sort
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * DataTables initialisation complete event, fired when the table is fully drawn,
+ * including Ajax data loaded, if Ajax data is required.
+ * @name DataTable#init
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The JSON object request from the server - only
+ * present if client-side Ajax sourced data is used</li></ol>
+ */
+
+ /**
+ * State save event, fired when the table has changed state a new state save is required.
+ * This method allows modification of the state saving object prior to actually doing the
+ * save, including addition or other state properties (for plug-ins) or modification
+ * of a DataTables core property.
+ * @name DataTable#stateSaveParams
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The state information to be saved
+ */
+
+ /**
+ * State load event, fired when the table is loading state from the stored data, but
+ * prior to the settings object being modified by the saved state - allowing modification
+ * of the saved state is required or loading of state for a plug-in.
+ * @name DataTable#stateLoadParams
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The saved state information
+ */
+
+ /**
+ * State loaded event, fired when state has been loaded from stored data and the settings
+ * object has been modified by the loaded data.
+ * @name DataTable#stateLoaded
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The saved state information
+ */
+
+ /**
+ * Processing event, fired when DataTables is doing some kind of processing (be it,
+ * sort, filter or anything else). Can be used to indicate to the end user that
+ * there is something happening, or that something has finished.
+ * @name DataTable#processing
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
+ */
+
+ /**
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to
+ * made to the server for new data (note that this trigger is called in fnServerData,
+ * if you override fnServerData and which to use this event, you need to trigger it in
+ * you success function).
+ * @name DataTable#xhr
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ * @param {object} json JSON returned from the server
+ */
+
+ /**
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
+ * the bDestroy:true parameter in the initialisation object. This can be used to remove
+ * bound events, added DOM nodes, etc.
+ * @name DataTable#destroy
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+}));
+
+}(window, document));
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css
new file mode 100644
index 00000000..cf1d4ed7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css
@@ -0,0 +1,244 @@
+
+
+/*
+ * Table
+ */
+table.dataTable {
+ margin: 0 auto;
+ clear: both;
+ width: 100%;
+ border-collapse: collapse;
+}
+
+table.dataTable thead th {
+ padding: 3px 0px 3px 10px;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+table.dataTable tfoot th {
+ padding: 3px 10px;
+}
+
+table.dataTable td {
+ padding: 3px 10px;
+}
+
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+
+table.dataTable tr.odd { background-color: #E2E4FF; }
+table.dataTable tr.even { background-color: white; }
+
+table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
+table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
+table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
+table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
+table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
+table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
+
+
+/*
+ * Table wrapper
+ */
+.dataTables_wrapper {
+ position: relative;
+ clear: both;
+ *zoom: 1;
+}
+.dataTables_wrapper .ui-widget-header {
+ font-weight: normal;
+}
+.dataTables_wrapper .ui-toolbar {
+ padding: 5px;
+}
+
+
+/*
+ * Page length menu
+ */
+.dataTables_length {
+ float: left;
+}
+
+
+/*
+ * Filter
+ */
+.dataTables_filter {
+ float: right;
+ text-align: right;
+}
+
+
+/*
+ * Table information
+ */
+.dataTables_info {
+ padding-top: 3px;
+ clear: both;
+ float: left;
+}
+
+
+/*
+ * Pagination
+ */
+.dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+
+.dataTables_paginate .ui-button {
+ margin-right: -0.1em !important;
+}
+
+.paging_two_button .ui-button {
+ float: left;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+.paging_full_numbers .ui-button {
+ padding: 2px 6px;
+ margin: 0;
+ cursor: pointer;
+ * cursor: hand;
+ color: #333 !important;
+}
+
+/* Two button pagination - previous / next */
+.paginate_disabled_previous,
+.paginate_enabled_previous,
+.paginate_disabled_next,
+.paginate_enabled_next {
+ height: 19px;
+ float: left;
+ cursor: pointer;
+ *cursor: hand;
+ color: #111 !important;
+}
+.paginate_disabled_previous:hover,
+.paginate_enabled_previous:hover,
+.paginate_disabled_next:hover,
+.paginate_enabled_next:hover {
+ text-decoration: none !important;
+}
+.paginate_disabled_previous:active,
+.paginate_enabled_previous:active,
+.paginate_disabled_next:active,
+.paginate_enabled_next:active {
+ outline: none;
+}
+
+.paginate_disabled_previous,
+.paginate_disabled_next {
+ color: #666 !important;
+}
+.paginate_disabled_previous,
+.paginate_enabled_previous {
+ padding-left: 23px;
+}
+.paginate_disabled_next,
+.paginate_enabled_next {
+ padding-right: 23px;
+ margin-left: 10px;
+}
+
+.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
+
+/* Full number pagination */
+.paging_full_numbers a:active {
+ outline: none
+}
+.paging_full_numbers a:hover {
+ text-decoration: none;
+}
+
+.paging_full_numbers a.paginate_button,
+.paging_full_numbers a.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+ color: #333 !important;
+}
+
+.paging_full_numbers a.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers a.paginate_button:hover {
+ background-color: #ccc;
+ text-decoration: none !important;
+}
+
+.paging_full_numbers a.paginate_active {
+ background-color: #99B3FF;
+}
+
+
+/*
+ * Processing indicator
+ */
+.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 250px;
+ height: 30px;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px 0;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 14px;
+ background-color: white;
+}
+
+
+/*
+ * Sorting
+ */
+table.dataTable thead th div.DataTables_sort_wrapper {
+ position: relative;
+ padding-right: 20px;
+}
+
+table.dataTable thead th div.DataTables_sort_wrapper span {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+ right: 0;
+}
+
+table.dataTable th:active {
+ outline: none;
+}
+
+
+/*
+ * Scrolling
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.dataTables_scrollBody {
+ *margin-top: -1px;
+ -webkit-overflow-scrolling: touch;
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js
new file mode 100644
index 00000000..bb2f96a6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js
@@ -0,0 +1,2 @@
+/*! @license Copyright 2011 Dan Vanderkam (danvdk@gmail.com) MIT-licensed (http://opensource.org/licenses/MIT) */
+Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(a,c,b){if(typeof(b)=="undefined"){b=10}for(;parseInt(a,10)<b&&b>1;b/=10){a=c.toString()+a}return a.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(a){return Date.ext.locales[a.locale].a[a.getDay()]},A:function(a){return Date.ext.locales[a.locale].A[a.getDay()]},b:function(a){return Date.ext.locales[a.locale].b[a.getMonth()]},B:function(a){return Date.ext.locales[a.locale].B[a.getMonth()]},c:"toLocaleString",C:function(a){return Date.ext.util.xPad(parseInt(a.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(a){return Date.ext.util.xPad(parseInt(Date.ext.util.G(a)/100,10),0)},G:function(c){var e=c.getFullYear();var b=parseInt(Date.ext.formats.V(c),10);var a=parseInt(Date.ext.formats.W(c),10);if(a>b){e++}else{if(a===0&&b>=52){e--}}return e},H:["getHours","0"],I:function(b){var a=b.getHours()%12;return Date.ext.util.xPad(a===0?12:a,0)},j:function(c){var a=c-new Date(""+c.getFullYear()+"/1/1 GMT");a+=c.getTimezoneOffset()*60000;var b=parseInt(a/60000/60/24,10)+1;return Date.ext.util.xPad(b,0,100)},m:function(a){return Date.ext.util.xPad(a.getMonth()+1,0)},M:["getMinutes","0"],p:function(a){return Date.ext.locales[a.locale].p[a.getHours()>=12?1:0]},P:function(a){return Date.ext.locales[a.locale].P[a.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(a){var b=a.getDay();return b===0?7:b},U:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=6-e.getDay();var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0)},V:function(e){var c=parseInt(Date.ext.formats.W(e),10);var a=(new Date(""+e.getFullYear()+"/1/1")).getDay();var b=c+(a>4||a<=1?0:1);if(b==53&&(new Date(""+e.getFullYear()+"/12/31")).getDay()<4){b=1}else{if(b===0){b=Date.ext.formats.V(new Date(""+(e.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(b,0)},w:"getDay",W:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=7-Date.ext.formats.u(e);var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0,10)},y:function(a){return Date.ext.util.xPad(a.getFullYear()%100,0)},Y:"getFullYear",z:function(c){var b=c.getTimezoneOffset();var a=Date.ext.util.xPad(parseInt(Math.abs(b/60),10),0);var e=Date.ext.util.xPad(b%60,0);return(b>0?"-":"+")+a+e},Z:function(a){return a.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(a){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(a){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var c=this;while(a.match(/%[cDhnrRtTxXzZ]/)){a=a.replace(/%([cDhnrRtTxXzZ])/g,function(e,d){var g=Date.ext.aggregates[d];return(g=="locale"?Date.ext.locales[c.locale][d]:g)})}var b=a.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(e,d){var g=Date.ext.formats[d];if(typeof(g)=="string"){return c[g]()}else{if(typeof(g)=="function"){return g.call(c,c)}else{if(typeof(g)=="object"&&typeof(g[0])=="string"){return Date.ext.util.xPad(c[g[0]](),g[1])}else{return d}}}});c=null;return b};"use strict";function RGBColorParser(f){this.ok=false;if(f.charAt(0)=="#"){f=f.substr(1,6)}f=f.replace(/ /g,"");f=f.toLowerCase();var b={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};for(var g in b){if(f==g){f=b[g]}}var e=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(i){return[parseInt(i[1]),parseInt(i[2]),parseInt(i[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(i){return[parseInt(i[1],16),parseInt(i[2],16),parseInt(i[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(i){return[parseInt(i[1]+i[1],16),parseInt(i[2]+i[2],16),parseInt(i[3]+i[3],16)]}}];for(var c=0;c<e.length;c++){var j=e[c].re;var a=e[c].process;var h=j.exec(f);if(h){var d=a(h);this.r=d[0];this.g=d[1];this.b=d[2];this.ok=true}}this.r=(this.r<0||isNaN(this.r))?0:((this.r>255)?255:this.r);this.g=(this.g<0||isNaN(this.g))?0:((this.g>255)?255:this.g);this.b=(this.b<0||isNaN(this.b))?0:((this.b>255)?255:this.b);this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"};this.toHex=function(){var l=this.r.toString(16);var k=this.g.toString(16);var i=this.b.toString(16);if(l.length==1){l="0"+l}if(k.length==1){k="0"+k}if(i.length==1){i="0"+i}return"#"+l+k+i}}function printStackTrace(b){b=b||{guess:true};var c=b.e||null,e=!!b.guess;var d=new printStackTrace.implementation(),a=d.run(c);return(e)?d.guessAnonymousFunctions(a):a}printStackTrace.implementation=function(){};printStackTrace.implementation.prototype={run:function(a,b){a=a||this.createException();b=b||this.mode(a);if(b==="other"){return this.other(arguments.callee)}else{return this[b](a)}},createException:function(){try{this.undef()}catch(a){return a}},mode:function(a){if(a["arguments"]&&a.stack){return"chrome"}else{if(typeof a.message==="string"&&typeof window!=="undefined"&&window.opera){if(!a.stacktrace){return"opera9"}if(a.message.indexOf("\n")>-1&&a.message.split("\n").length>a.stacktrace.split("\n").length){return"opera9"}if(!a.stack){return"opera10a"}if(a.stacktrace.indexOf("called from line")<0){return"opera10b"}return"opera11"}else{if(a.stack){return"firefox"}}}return"other"},instrumentFunction:function(b,d,e){b=b||window;var a=b[d];b[d]=function c(){e.call(this,printStackTrace().slice(4));return b[d]._instrumented.apply(this,arguments)};b[d]._instrumented=a},deinstrumentFunction:function(a,b){if(a[b].constructor===Function&&a[b]._instrumented&&a[b]._instrumented.constructor===Function){a[b]=a[b]._instrumented}},chrome:function(b){var a=(b.stack+"\n").replace(/^\S[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^([^\(]+?)([\n$])/gm,"{anonymous}()@$1$2").replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm,"{anonymous}()@$1").split("\n");a.pop();return a},firefox:function(a){return a.stack.replace(/(?:\n@:0)?\s+$/m,"").replace(/^\(/gm,"{anonymous}(").split("\n")},opera11:function(g){var a="{anonymous}",h=/^.*line (\d+), column (\d+)(?: in (.+))? in (\S+):$/;var k=g.stacktrace.split("\n"),l=[];for(var c=0,f=k.length;c<f;c+=2){var d=h.exec(k[c]);if(d){var j=d[4]+":"+d[1]+":"+d[2];var b=d[3]||"global code";b=b.replace(/<anonymous function: (\S+)>/,"$1").replace(/<anonymous function>/,a);l.push(b+"@"+j+" -- "+k[c+1].replace(/^\s+/,""))}}return l},opera10b:function(g){var a="{anonymous}",h=/^(.*)@(.+):(\d+)$/;var j=g.stacktrace.split("\n"),k=[];for(var c=0,f=j.length;c<f;c++){var d=h.exec(j[c]);if(d){var b=d[1]?(d[1]+"()"):"global code";k.push(b+"@"+d[2]+":"+d[3])}}return k},opera10a:function(g){var a="{anonymous}",h=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;var j=g.stacktrace.split("\n"),k=[];for(var c=0,f=j.length;c<f;c+=2){var d=h.exec(j[c]);if(d){var b=d[3]||a;k.push(b+"()@"+d[2]+":"+d[1]+" -- "+j[c+1].replace(/^\s+/,""))}}return k},opera9:function(j){var d="{anonymous}",h=/Line (\d+).*script (?:in )?(\S+)/i;var c=j.message.split("\n"),b=[];for(var g=2,a=c.length;g<a;g+=2){var f=h.exec(c[g]);if(f){b.push(d+"()@"+f[2]+":"+f[1]+" -- "+c[g+1].replace(/^\s+/,""))}}return b},other:function(g){var b="{anonymous}",f=/function\s*([\w\-$]+)?\s*\(/i,a=[],d,c,e=10;while(g&&a.length<e){d=f.test(g.toString())?RegExp.$1||b:b;c=Array.prototype.slice.call(g["arguments"]||[]);a[a.length]=d+"("+this.stringifyArguments(c)+")";g=g.caller}return a},stringifyArguments:function(c){var b=[];var e=Array.prototype.slice;for(var d=0;d<c.length;++d){var a=c[d];if(a===undefined){b[d]="undefined"}else{if(a===null){b[d]="null"}else{if(a.constructor){if(a.constructor===Array){if(a.length<3){b[d]="["+this.stringifyArguments(a)+"]"}else{b[d]="["+this.stringifyArguments(e.call(a,0,1))+"..."+this.stringifyArguments(e.call(a,-1))+"]"}}else{if(a.constructor===Object){b[d]="#object"}else{if(a.constructor===Function){b[d]="#function"}else{if(a.constructor===String){b[d]='"'+a+'"'}else{if(a.constructor===Number){b[d]=a}}}}}}}}}return b.join(",")},sourceCache:{},ajax:function(a){var b=this.createXMLHTTPObject();if(b){try{b.open("GET",a,false);b.send(null);return b.responseText}catch(c){}}return""},createXMLHTTPObject:function(){var c,a=[function(){return new XMLHttpRequest()},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml3.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")}];for(var b=0;b<a.length;b++){try{c=a[b]();this.createXMLHTTPObject=a[b];return c}catch(d){}}},isSameDomain:function(a){return a.indexOf(location.hostname)!==-1},getSource:function(a){if(!(a in this.sourceCache)){this.sourceCache[a]=this.ajax(a).split("\n")}return this.sourceCache[a]},guessAnonymousFunctions:function(k){for(var g=0;g<k.length;++g){var f=/\{anonymous\}\(.*\)@(.*)/,l=/^(.*?)(?::(\d+))(?::(\d+))?(?: -- .+)?$/,b=k[g],c=f.exec(b);if(c){var e=l.exec(c[1]),d=e[1],a=e[2],j=e[3]||0;if(d&&this.isSameDomain(d)&&a){var h=this.guessAnonymousFunction(d,a,j);k[g]=b.replace("{anonymous}",h)}}}return k},guessAnonymousFunction:function(c,f,a){var b;try{b=this.findFunctionName(this.getSource(c),f)}catch(d){b="getSource failed with url: "+c+", exception: "+d.toString()}return b},findFunctionName:function(a,e){var g=/function\s+([^(]*?)\s*\(([^)]*)\)/;var k=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function\b/;var h=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)\b/;var b="",l,j=Math.min(e,20),d,c;for(var f=0;f<j;++f){l=a[e-f-1];c=l.indexOf("//");if(c>=0){l=l.substr(0,c)}if(l){b=l+b;d=k.exec(b);if(d&&d[1]){return d[1]}d=g.exec(b);if(d&&d[1]){return d[1]}d=h.exec(b);if(d&&d[1]){return d[1]}}}return"(?)"}};CanvasRenderingContext2D.prototype.installPattern=function(e){if(typeof(this.isPatternInstalled)!=="undefined"){throw"Must un-install old line pattern before installing a new one."}this.isPatternInstalled=true;var g=[0,0];var b=[];var f=this.beginPath;var d=this.lineTo;var c=this.moveTo;var a=this.stroke;this.uninstallPattern=function(){this.beginPath=f;this.lineTo=d;this.moveTo=c;this.stroke=a;this.uninstallPattern=undefined;this.isPatternInstalled=undefined};this.beginPath=function(){b=[];f.call(this)};this.moveTo=function(h,i){b.push([[h,i]]);c.call(this,h,i)};this.lineTo=function(h,j){var i=b[b.length-1];i.push([h,j])};this.stroke=function(){if(b.length===0){a.call(this);return}for(var p=0;p<b.length;p++){var o=b[p];var l=o[0][0],u=o[0][1];for(var n=1;n<o.length;n++){var h=o[n][0],s=o[n][1];this.save();var w=(h-l);var v=(s-u);var r=Math.sqrt(w*w+v*v);var k=Math.atan2(v,w);this.translate(l,u);c.call(this,0,0);this.rotate(k);var m=g[0];var t=0;while(r>t){var q=e[m];if(g[1]){t+=g[1]}else{t+=q}if(t>r){g=[m,t-r];t=r}else{g=[(m+1)%e.length,0]}if(m%2===0){d.call(this,t,0)}else{c.call(this,t,0)}m=(m+1)%e.length}this.restore();l=h,u=s}}a.call(this);b=[]}};CanvasRenderingContext2D.prototype.uninstallPattern=function(){throw"Must install a line pattern before uninstalling it."};"use strict";var DygraphOptions=function(a){this.dygraph_=a;this.yAxes_=[];this.xAxis_={};this.series_={};this.global_=this.dygraph_.attrs_;this.user_=this.dygraph_.user_attrs_||{};this.highlightSeries_=this.get("highlightSeriesOpts")||{};var b=this.get("labels");if(!b){return}this.reparseSeries()};DygraphOptions.AXIS_STRING_MAPPINGS_={y:0,Y:0,y1:0,Y1:0,y2:1,Y2:1};DygraphOptions.axisToIndex_=function(a){if(typeof(a)=="string"){if(DygraphOptions.AXIS_STRING_MAPPINGS_.hasOwnProperty(a)){return DygraphOptions.AXIS_STRING_MAPPINGS_[a]}throw"Unknown axis : "+a}if(typeof(a)=="number"){if(a===0||a===1){return a}throw"Dygraphs only supports two y-axes, indexed from 0-1."}if(typeof(a)=="object"){throw"Using objects for axis specification is not supported inside the 'series' option."}if(a){throw"Unknown axis : "+a}return 0};DygraphOptions.prototype.reparseSeries=function(){this.labels=this.get("labels").slice(1);this.yAxes_=[{series:[],options:{}}];this.xAxis_={options:{}};this.series_={};var d=!this.user_.series;if(d){var f=0;for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.user_[a]||{};var c=0;var e=g.axis;if(typeof(e)=="object"){c=++f;this.yAxes_[c]={series:[a],options:e}}if(!e){this.yAxes_[0].series.push(a)}this.series_[a]={idx:b,yAxis:c,options:g}}for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.series_[a]["options"];var e=g.axis;if(typeof(e)=="string"){if(!this.series_.hasOwnProperty(e)){this.dygraph_.error("Series "+a+" wants to share a y-axis with series "+e+", which does not define its own axis.");return null}var c=this.series_[e].yAxis;this.series_[a].yAxis=c;this.yAxes_[c].series.push(a)}}}else{for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.user_.series[a]||{};var c=DygraphOptions.axisToIndex_(g.axis);this.series_[a]={idx:b,yAxis:c,options:g};if(!this.yAxes_[c]){this.yAxes_[c]={series:[a],options:{}}}else{this.yAxes_[c].series.push(a)}}}var h=this.user_.axes||{};Dygraph.update(this.yAxes_[0].options,h.y||{});if(this.yAxes_.length>1){Dygraph.update(this.yAxes_[1].options,h.y2||{})}Dygraph.update(this.xAxis_.options,h.x||{})};DygraphOptions.prototype.get=function(b){var a=this.getGlobalUser_(b);if(a!=null){return a}return this.getGlobalDefault_(b)};DygraphOptions.prototype.getGlobalUser_=function(a){if(this.user_.hasOwnProperty(a)){return this.user_[a]}return null};DygraphOptions.prototype.getGlobalDefault_=function(a){if(this.global_.hasOwnProperty(a)){return this.global_[a]}if(Dygraph.DEFAULT_ATTRS.hasOwnProperty(a)){return Dygraph.DEFAULT_ATTRS[a]}return null};DygraphOptions.prototype.getForAxis=function(c,d){var e;var h;if(typeof(d)=="number"){e=d;h=e==0?"y":"y2"}else{if(d=="y1"){d="y"}if(d=="y"){e=0}else{if(d=="y2"){e=1}else{if(d=="x"){e=-1}else{throw"Unknown axis "+d}}}h=d}var f=(e==-1)?this.xAxis_:this.yAxes_[e];if(f){var g=f.options;if(g.hasOwnProperty(c)){return g[c]}}var b=this.getGlobalUser_(c);if(b!=null){return b}var a=Dygraph.DEFAULT_ATTRS.axes[h];if(a.hasOwnProperty(c)){return a[c]}return this.getGlobalDefault_(c)};DygraphOptions.prototype.getForSeries=function(b,d){if(d===this.dygraph_.highlightSet_){if(this.highlightSeries_.hasOwnProperty(b)){return this.highlightSeries_[b]}}if(!this.series_.hasOwnProperty(d)){throw"Unknown series: "+d}var c=this.series_[d];var a=c.options;if(a.hasOwnProperty(b)){return a[b]}return this.getForAxis(b,c.yAxis)};DygraphOptions.prototype.numAxes=function(){return this.yAxes_.length};DygraphOptions.prototype.axisForSeries=function(a){return this.series_[a].yAxis};DygraphOptions.prototype.axisOptions=function(a){return this.yAxes_[a].options};DygraphOptions.prototype.seriesForAxis=function(a){return this.yAxes_[a].series};DygraphOptions.prototype.seriesNames=function(){return this.labels_};DygraphOptions.prototype.indexOfSeries=function(a){return this.series_[a].idx};"use strict";var DygraphLayout=function(a){this.dygraph_=a;this.datasets=[];this.setNames=[];this.annotations=[];this.yAxes_=null;this.points=null;this.xTicks_=null;this.yTicks_=null};DygraphLayout.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphLayout.prototype.addDataset=function(a,b){this.datasets.push(b);this.setNames.push(a)};DygraphLayout.prototype.getPlotArea=function(){return this.computePlotArea_()};DygraphLayout.prototype.computePlotArea_=function(){var a={x:0,y:0};a.w=this.dygraph_.width_-a.x-this.attr_("rightGap");a.h=this.dygraph_.height_;var b={chart_div:this.dygraph_.graphDiv,reserveSpaceLeft:function(c){var d={x:a.x,y:a.y,w:c,h:a.h};a.x+=c;a.w-=c;return d},reserveSpaceRight:function(c){var d={x:a.x+a.w-c,y:a.y,w:c,h:a.h};a.w-=c;return d},reserveSpaceTop:function(c){var d={x:a.x,y:a.y,w:a.w,h:c};a.y+=c;a.h-=c;return d},reserveSpaceBottom:function(c){var d={x:a.x,y:a.y+a.h-c,w:a.w,h:c};a.h-=c;return d},chartRect:function(){return{x:a.x,y:a.y,w:a.w,h:a.h}}};this.dygraph_.cascadeEvents_("layout",b);if(this.attr_("showRangeSelector")){a.h-=this.attr_("rangeSelectorHeight")+4}return a};DygraphLayout.prototype.setAnnotations=function(d){this.annotations=[];var e=this.attr_("xValueParser")||function(a){return a};for(var c=0;c<d.length;c++){var b={};if(!d[c].xval&&!d[c].x){this.dygraph_.error("Annotations must have an 'x' property");return}if(d[c].icon&&!(d[c].hasOwnProperty("width")&&d[c].hasOwnProperty("height"))){this.dygraph_.error("Must set width and height when setting annotation.icon property");return}Dygraph.update(b,d[c]);if(!b.xval){b.xval=e(b.x)}this.annotations.push(b)}};DygraphLayout.prototype.setXTicks=function(a){this.xTicks_=a};DygraphLayout.prototype.setYAxes=function(a){this.yAxes_=a};DygraphLayout.prototype.setDateWindow=function(a){this.dateWindow_=a};DygraphLayout.prototype.evaluate=function(){this._evaluateLimits();this._evaluateLineCharts();this._evaluateLineTicks();this._evaluateAnnotations()};DygraphLayout.prototype._evaluateLimits=function(){this.minxval=this.maxxval=null;if(this.dateWindow_){this.minxval=this.dateWindow_[0];this.maxxval=this.dateWindow_[1]}else{for(var f=0;f<this.datasets.length;++f){var d=this.datasets[f];if(d.length>1){var b=d[0][0];if(!this.minxval||b<this.minxval){this.minxval=b}var a=d[d.length-1][0];if(!this.maxxval||a>this.maxxval){this.maxxval=a}}}}this.xrange=this.maxxval-this.minxval;this.xscale=(this.xrange!==0?1/this.xrange:1);for(var c=0;c<this.yAxes_.length;c++){var e=this.yAxes_[c];e.minyval=e.computedValueRange[0];e.maxyval=e.computedValueRange[1];e.yrange=e.maxyval-e.minyval;e.yscale=(e.yrange!==0?1/e.yrange:1);if(e.g.attr_("logscale")){e.ylogrange=Dygraph.log10(e.maxyval)-Dygraph.log10(e.minyval);e.ylogscale=(e.ylogrange!==0?1/e.ylogrange:1);if(!isFinite(e.ylogrange)||isNaN(e.ylogrange)){e.g.error("axis "+c+" of graph at "+e.g+" can't be displayed in log scale for range ["+e.minyval+" - "+e.maxyval+"]")}}}};DygraphLayout._calcYNormal=function(b,c,a){if(a){return 1-((Dygraph.log10(c)-Dygraph.log10(b.minyval))*b.ylogscale)}else{return 1-((c-b.minyval)*b.yscale)}};DygraphLayout.prototype._evaluateLineCharts=function(){var c=this.attr_("connectSeparatedPoints");this.points=new Array(this.datasets.length);for(var a=0;a<this.datasets.length;a++){var e=this.datasets[a];var h=this.setNames[a];var b=this.dygraph_.axisPropertiesForSeries(h);var i=this.dygraph_.attributes_.getForSeries("logscale",h);var n=new Array(e.length);for(var f=0;f<e.length;f++){var m=e[f];var d=DygraphLayout.parseFloat_(m[0]);var k=DygraphLayout.parseFloat_(m[1]);var l=(d-this.minxval)*this.xscale;var g=DygraphLayout._calcYNormal(b,k,i);if(c&&m[1]===null){k=null}n[f]={x:l,y:g,xval:d,yval:k,name:h}}this.points[a]=n}};DygraphLayout.parseFloat_=function(a){if(a===null){return NaN}return a};DygraphLayout.prototype._evaluateLineTicks=function(){var d,c,b,f;this.xticks=[];for(d=0;d<this.xTicks_.length;d++){c=this.xTicks_[d];b=c.label;f=this.xscale*(c.v-this.minxval);if((f>=0)&&(f<=1)){this.xticks.push([f,b])}}this.yticks=[];for(d=0;d<this.yAxes_.length;d++){var e=this.yAxes_[d];for(var a=0;a<e.ticks.length;a++){c=e.ticks[a];b=c.label;f=this.dygraph_.toPercentYCoord(c.v,d);if((f>=0)&&(f<=1)){this.yticks.push([d,f,b])}}}};DygraphLayout.prototype.evaluateWithError=function(){this.evaluate();if(!(this.attr_("errorBars")||this.attr_("customBars"))){return}var h=0;for(var a=0;a<this.datasets.length;++a){var p=this.points[a];var g=0;var f=this.datasets[a];var l=this.setNames[a];var e=this.dygraph_.axisPropertiesForSeries(l);var m=this.dygraph_.attributes_.getForSeries("logscale",l);for(g=0;g<f.length;g++,h++){var q=f[g];var c=DygraphLayout.parseFloat_(q[0]);var n=DygraphLayout.parseFloat_(q[1]);if(c==p[g].xval&&n==p[g].yval){var k=DygraphLayout.parseFloat_(q[2]);var d=DygraphLayout.parseFloat_(q[3]);var o=n-k;var b=n+d;p[g].y_top=DygraphLayout._calcYNormal(e,o,m);p[g].y_bottom=DygraphLayout._calcYNormal(e,b,m)}}}};DygraphLayout.prototype._evaluateAnnotations=function(){var d;var g={};for(d=0;d<this.annotations.length;d++){var b=this.annotations[d];g[b.xval+","+b.series]=b}this.annotated_points=[];if(!this.annotations||!this.annotations.length){return}for(var h=0;h<this.points.length;h++){var e=this.points[h];for(d=0;d<e.length;d++){var f=e[d];var c=f.xval+","+f.name;if(c in g){f.annotation=g[c];this.annotated_points.push(f)}}}};DygraphLayout.prototype.removeAllDatasets=function(){delete this.datasets;delete this.setNames;delete this.setPointsLengths;delete this.setPointsOffsets;this.datasets=[];this.setNames=[];this.setPointsLengths=[];this.setPointsOffsets=[]};DygraphLayout.prototype.unstackPointAtIndex=function(f,e){var a=this.points[f][e];if(!a.yval){return a}var c={};for(var d in a){c[d]=a[d]}if(!this.attr_("stackedGraph")){return c}if(f==this.points.length-1){return c}var b=this.points[f+1];if(b[e].xval==a.xval&&b[e].yval){c.yval-=b[e].yval}return c};"use strict";var DygraphCanvasRenderer=function(d,c,b,e){this.dygraph_=d;this.layout=e;this.element=c;this.elementContext=b;this.container=this.element.parentNode;this.height=this.element.height;this.width=this.element.width;if(!this.isIE&&!(DygraphCanvasRenderer.isSupported(this.element))){throw"Canvas is not supported."}this.area=e.getPlotArea();this.container.style.position="relative";this.container.style.width=this.width+"px";if(this.dygraph_.isUsingExcanvas_){this._createIEClipArea()}else{if(!Dygraph.isAndroid()){var a=this.dygraph_.canvas_ctx_;a.beginPath();a.rect(this.area.x,this.area.y,this.area.w,this.area.h);a.clip();a=this.dygraph_.hidden_ctx_;a.beginPath();a.rect(this.area.x,this.area.y,this.area.w,this.area.h);a.clip()}}};DygraphCanvasRenderer.prototype.attr_=function(a,b){return this.dygraph_.attr_(a,b)};DygraphCanvasRenderer.prototype.clear=function(){var a;if(this.isIE){try{if(this.clearDelay){this.clearDelay.cancel();this.clearDelay=null}a=this.elementContext}catch(b){return}}a=this.elementContext;a.clearRect(0,0,this.width,this.height)};DygraphCanvasRenderer.isSupported=function(f){var b=null;try{if(typeof(f)=="undefined"||f===null){b=document.createElement("canvas")}else{b=f}b.getContext("2d")}catch(c){var d=navigator.appVersion.match(/MSIE (\d\.\d)/);var a=(navigator.userAgent.toLowerCase().indexOf("opera")!=-1);if((!d)||(d[1]<6)||(a)){return false}return true}return true};DygraphCanvasRenderer.prototype.render=function(){this._updatePoints();this._renderLineChart()};DygraphCanvasRenderer.prototype._createIEClipArea=function(){var g="dygraph-clip-div";var f=this.dygraph_.graphDiv;for(var e=f.childNodes.length-1;e>=0;e--){if(f.childNodes[e].className==g){f.removeChild(f.childNodes[e])}}var c=document.bgColor;var d=this.dygraph_.graphDiv;while(d!=document){var a=d.currentStyle.backgroundColor;if(a&&a!="transparent"){c=a;break}d=d.parentNode}function b(j){if(j.w===0||j.h===0){return}var i=document.createElement("div");i.className=g;i.style.backgroundColor=c;i.style.position="absolute";i.style.left=j.x+"px";i.style.top=j.y+"px";i.style.width=j.w+"px";i.style.height=j.h+"px";f.appendChild(i)}var h=this.area;b({x:0,y:0,w:h.x,h:this.height});b({x:h.x,y:0,w:this.width-h.x,h:h.y});b({x:h.x+h.w,y:0,w:this.width-h.x-h.w,h:this.height});b({x:h.x,y:h.y+h.h,w:this.width-h.x,h:this.height-h.h-h.y})};DygraphCanvasRenderer._getIteratorPredicate=function(a){return a?DygraphCanvasRenderer._predicateThatSkipsEmptyPoints:null};DygraphCanvasRenderer._predicateThatSkipsEmptyPoints=function(b,a){return b[a].yval!==null};DygraphCanvasRenderer._drawStyledLine=function(i,a,m,q,f,n,d){var h=i.dygraph;var c=h.getOption("stepPlot");if(!Dygraph.isArrayLike(q)){q=null}var l=h.getOption("drawGapEdgePoints",i.setName);var o=i.points;var k=Dygraph.createIterator(o,0,o.length,DygraphCanvasRenderer._getIteratorPredicate(h.getOption("connectSeparatedPoints")));var j=q&&(q.length>=2);var p=i.drawingContext;p.save();if(j){p.installPattern(q)}var b=DygraphCanvasRenderer._drawSeries(i,k,m,d,f,l,c,a);DygraphCanvasRenderer._drawPointsOnLine(i,b,n,a,d);if(j){p.uninstallPattern()}p.restore()};DygraphCanvasRenderer._drawSeries=function(w,u,m,h,q,t,g,r){var b=null;var x=null;var k=null;var j;var p;var l=[];var f=true;var o=w.drawingContext;o.beginPath();o.strokeStyle=r;o.lineWidth=m;var c=u.array_;var v=u.end_;var a=u.predicate_;for(var s=u.start_;s<v;s++){p=c[s];if(a){while(s<v&&!a(c,s)){s++}if(s==v){break}p=c[s]}if(p.canvasy===null||p.canvasy!=p.canvasy){if(g&&b!==null){o.moveTo(b,x);o.lineTo(p.canvasx,x)}b=x=null}else{j=false;if(t||!b){u.nextIdx_=s;var n=u.next();k=u.hasNext?u.peek.canvasy:null;var d=k===null||k!=k;j=(!b&&d);if(t){if((!f&&!b)||(u.hasNext&&d)){j=true}}}if(b!==null){if(m){if(g){o.moveTo(b,x);o.lineTo(p.canvasx,x)}o.lineTo(p.canvasx,p.canvasy)}}else{o.moveTo(p.canvasx,p.canvasy)}if(q||j){l.push([p.canvasx,p.canvasy])}b=p.canvasx;x=p.canvasy}f=false}o.stroke();return l};DygraphCanvasRenderer._drawPointsOnLine=function(h,i,f,d,g){var c=h.drawingContext;for(var b=0;b<i.length;b++){var a=i[b];c.save();f(h.dygraph,h.setName,c,a[0],a[1],d,g);c.restore()}};DygraphCanvasRenderer.prototype._updatePoints=function(){var e=this.layout.points;for(var c=e.length;c--;){var d=e[c];for(var b=d.length;b--;){var a=d[b];a.canvasx=this.area.w*a.x+this.area.x;a.canvasy=this.area.h*a.y+this.area.y}}};DygraphCanvasRenderer.prototype._renderLineChart=function(h,x){var k=x||this.elementContext;var u=this.attr_("errorBars")||this.attr_("customBars");var f=this.attr_("fillGraph");var q;var a=this.layout.points;var v=this.layout.setNames;var n=v.length;var b;this.colors=this.dygraph_.colorsMap_;var r=this.attr_("plotter");var g=r;if(!Dygraph.isArrayLike(g)){g=[g]}var c={};for(q=0;q<v.length;q++){b=v[q];var w=this.attr_("plotter",b);if(w==r){continue}c[b]=w}for(q=0;q<g.length;q++){var t=g[q];var s=(q==g.length-1);for(var m=0;m<a.length;m++){b=v[m];if(h&&b!=h){continue}var o=a[m];var e=t;if(b in c){if(s){e=c[b]}else{continue}}var l=this.colors[b];var d=this.dygraph_.getOption("strokeWidth",b);k.save();k.strokeStyle=l;k.lineWidth=d;e({points:o,setName:b,drawingContext:k,color:l,strokeWidth:d,dygraph:this.dygraph_,axis:this.dygraph_.axisPropertiesForSeries(b),plotArea:this.area,seriesIndex:m,seriesCount:a.length,allSeriesPoints:a});k.restore()}}};DygraphCanvasRenderer._Plotters={linePlotter:function(a){DygraphCanvasRenderer._linePlotter(a)},fillPlotter:function(a){DygraphCanvasRenderer._fillPlotter(a)},errorPlotter:function(a){DygraphCanvasRenderer._errorPlotter(a)}};DygraphCanvasRenderer._linePlotter=function(f){var d=f.dygraph;var h=f.setName;var i=f.strokeWidth;var a=d.getOption("strokeBorderWidth",h);var j=d.getOption("drawPointCallback",h)||Dygraph.Circles.DEFAULT;var k=d.getOption("strokePattern",h);var c=d.getOption("drawPoints",h);var b=d.getOption("pointSize",h);if(a&&i){DygraphCanvasRenderer._drawStyledLine(f,d.getOption("strokeBorderColor",h),i+2*a,k,c,j,b)}DygraphCanvasRenderer._drawStyledLine(f,f.color,i,k,c,j,b)};DygraphCanvasRenderer._errorPlotter=function(t){var s=t.dygraph;var h=t.setName;var v=s.getOption("errorBars")||s.getOption("customBars");if(!v){return}var l=s.getOption("fillGraph",h);if(l){s.warn("Can't use fillGraph option with error bars")}var n=t.drawingContext;var o=t.color;var p=s.getOption("fillAlpha",h);var j=s.getOption("stepPlot");var b=t.axis;var q=t.points;var r=Dygraph.createIterator(q,0,q.length,DygraphCanvasRenderer._getIteratorPredicate(s.getOption("connectSeparatedPoints")));var k;var i=NaN;var d=NaN;var f=[-1,-1];var u=b.yscale;var a=new RGBColorParser(o);var w="rgba("+a.r+","+a.g+","+a.b+","+p+")";n.fillStyle=w;n.beginPath();var c=function(e){return(e===null||e===undefined||isNaN(e))};while(r.hasNext){var m=r.next();if((!j&&c(m.y))||(j&&!isNaN(d)&&c(d))){i=NaN;continue}if(j){k=[m.y_bottom,m.y_top];d=m.y}else{k=[m.y_bottom,m.y_top]}k[0]=t.plotArea.h*k[0]+t.plotArea.y;k[1]=t.plotArea.h*k[1]+t.plotArea.y;if(!isNaN(i)){if(j){n.moveTo(i,f[0]);n.lineTo(m.canvasx,f[0]);n.lineTo(m.canvasx,f[1])}else{n.moveTo(i,f[0]);n.lineTo(m.canvasx,k[0]);n.lineTo(m.canvasx,k[1])}n.lineTo(i,f[1]);n.closePath()}f=k;i=m.canvasx}n.fill()};DygraphCanvasRenderer._fillPlotter=function(D){if(D.seriesIndex!==0){return}var B=D.dygraph;var G=B.getLabels().slice(1);for(var A=G.length;A>=0;A--){if(!B.visibility()[A]){G.splice(A,1)}}var h=(function(){for(var e=0;e<G.length;e++){if(B.getOption("fillGraph",G[e])){return true}}return false})();if(!h){return}var u=D.drawingContext;var C=D.plotArea;var c=D.allSeriesPoints;var x=c.length;var w=B.getOption("fillAlpha");var o=B.getOption("stepPlot");var j=B.getOption("stackedGraph");var p=B.getColors();var q={};var a;for(var s=x-1;s>=0;s--){var m=G[s];if(!B.getOption("fillGraph",m)){continue}var v=p[s];var f=B.axisPropertiesForSeries(m);var d=1+f.minyval*f.yscale;if(d<0){d=0}else{if(d>1){d=1}}d=C.h*d+C.y;var z=c[s];var y=Dygraph.createIterator(z,0,z.length,DygraphCanvasRenderer._getIteratorPredicate(B.getOption("connectSeparatedPoints")));var l=NaN;var k=[-1,-1];var r;var E=f.yscale;var b=new RGBColorParser(v);var F="rgba("+b.r+","+b.g+","+b.b+","+w+")";u.fillStyle=F;u.beginPath();while(y.hasNext){var t=y.next();if(!Dygraph.isOK(t.y)){l=NaN;continue}if(j){a=q[t.canvasx];var n;if(a===undefined){n=d}else{if(o){n=a[0]}else{n=a}}r=[t.canvasy,n];if(o){if(k[0]===-1){q[t.canvasx]=[t.canvasy,d]}else{q[t.canvasx]=[t.canvasy,k[0]]}}else{q[t.canvasx]=t.canvasy}}else{r=[t.canvasy,d]}if(!isNaN(l)){u.moveTo(l,k[0]);if(o){u.lineTo(t.canvasx,k[0]);if(a){u.lineTo(t.canvasx,a[1])}else{u.lineTo(t.canvasx,r[1])}}else{u.lineTo(t.canvasx,r[0]);u.lineTo(t.canvasx,r[1])}u.lineTo(l,k[1]);u.closePath()}k=r;l=t.canvasx}u.fill()}};"use strict";var Dygraph=function(d,c,b,a){if(a!==undefined){this.warn("Using deprecated four-argument dygraph constructor");this.__old_init__(d,c,b,a)}else{this.__init__(d,c,b)}};Dygraph.NAME="Dygraph";Dygraph.VERSION="1.2";Dygraph.__repr__=function(){return"["+this.NAME+" "+this.VERSION+"]"};Dygraph.toString=function(){return this.__repr__()};Dygraph.DEFAULT_ROLL_PERIOD=1;Dygraph.DEFAULT_WIDTH=480;Dygraph.DEFAULT_HEIGHT=320;Dygraph.ANIMATION_STEPS=12;Dygraph.ANIMATION_DURATION=200;Dygraph.numberValueFormatter=function(a,e,h,d){var b=e("sigFigs");if(b!==null){return Dygraph.floatFormat(a,b)}var f=e("digitsAfterDecimal");var c=e("maxNumberWidth");if(a!==0&&(Math.abs(a)>=Math.pow(10,c)||Math.abs(a)<Math.pow(10,-f))){return a.toExponential(f)}else{return""+Dygraph.round_(a,f)}};Dygraph.numberAxisLabelFormatter=function(a,d,c,b){return Dygraph.numberValueFormatter(a,c,b)};Dygraph.dateString_=function(e){var i=Dygraph.zeropad;var h=new Date(e);var f=""+h.getFullYear();var g=i(h.getMonth()+1);var a=i(h.getDate());var c="";var b=h.getHours()*3600+h.getMinutes()*60+h.getSeconds();if(b){c=" "+Dygraph.hmsString_(e)}return f+"/"+g+"/"+a+c};Dygraph.dateAxisFormatter=function(b,c){if(c>=Dygraph.DECADAL){return b.strftime("%Y")}else{if(c>=Dygraph.MONTHLY){return b.strftime("%b %y")}else{var a=b.getHours()*3600+b.getMinutes()*60+b.getSeconds()+b.getMilliseconds();if(a===0||c>=Dygraph.DAILY){return new Date(b.getTime()+3600*1000).strftime("%d%b")}else{return Dygraph.hmsString_(b.getTime())}}}};Dygraph.Plotters=DygraphCanvasRenderer._Plotters;Dygraph.DEFAULT_ATTRS={highlightCircleSize:3,highlightSeriesOpts:null,highlightSeriesBackgroundAlpha:0.5,labelsDivWidth:250,labelsDivStyles:{},labelsSeparateLines:false,labelsShowZeroValues:true,labelsKMB:false,labelsKMG2:false,showLabelsOnHighlight:true,digitsAfterDecimal:2,maxNumberWidth:6,sigFigs:null,strokeWidth:1,strokeBorderWidth:0,strokeBorderColor:"white",axisTickSize:3,axisLabelFontSize:14,xAxisLabelWidth:50,yAxisLabelWidth:50,rightGap:5,showRoller:false,xValueParser:Dygraph.dateParser,delimiter:",",sigma:2,errorBars:false,fractions:false,wilsonInterval:true,customBars:false,fillGraph:false,fillAlpha:0.15,connectSeparatedPoints:false,stackedGraph:false,hideOverlayOnMouseOut:true,legend:"onmouseover",stepPlot:false,avoidMinZero:false,drawAxesAtZero:false,titleHeight:28,xLabelHeight:18,yLabelWidth:18,drawXAxis:true,drawYAxis:true,axisLineColor:"black",axisLineWidth:0.3,gridLineWidth:0.3,axisLabelColor:"black",axisLabelFont:"Arial",axisLabelWidth:50,drawYGrid:true,drawXGrid:true,gridLineColor:"rgb(128,128,128)",interactionModel:null,animatedZooms:false,showRangeSelector:false,rangeSelectorHeight:40,rangeSelectorPlotStrokeColor:"#808FAB",rangeSelectorPlotFillColor:"#A7B1C4",plotter:[Dygraph.Plotters.fillPlotter,Dygraph.Plotters.errorPlotter,Dygraph.Plotters.linePlotter],plugins:[],axes:{x:{pixelsPerLabel:60,axisLabelFormatter:Dygraph.dateAxisFormatter,valueFormatter:Dygraph.dateString_,ticker:null},y:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null},y2:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null}}};Dygraph.HORIZONTAL=1;Dygraph.VERTICAL=2;Dygraph.PLUGINS=[];Dygraph.addedAnnotationCSS=false;Dygraph.prototype.__old_init__=function(f,d,e,b){if(e!==null){var a=["Date"];for(var c=0;c<e.length;c++){a.push(e[c])}Dygraph.update(b,{labels:a})}this.__init__(f,d,b)};Dygraph.prototype.__init__=function(a,c,l){if(/MSIE/.test(navigator.userAgent)&&!window.opera&&typeof(G_vmlCanvasManager)!="undefined"&&document.readyState!="complete"){var o=this;setTimeout(function(){o.__init__(a,c,l)},100);return}if(l===null||l===undefined){l={}}l=Dygraph.mapLegacyOptions_(l);if(typeof(a)=="string"){a=document.getElementById(a)}if(!a){Dygraph.error("Constructing dygraph with a non-existent div!");return}this.isUsingExcanvas_=typeof(G_vmlCanvasManager)!="undefined";this.maindiv_=a;this.file_=c;this.rollPeriod_=l.rollPeriod||Dygraph.DEFAULT_ROLL_PERIOD;this.previousVerticalX_=-1;this.fractions_=l.fractions||false;this.dateWindow_=l.dateWindow||null;this.is_initial_draw_=true;this.annotations_=[];this.zoomed_x_=false;this.zoomed_y_=false;a.innerHTML="";if(a.style.width===""&&l.width){a.style.width=l.width+"px"}if(a.style.height===""&&l.height){a.style.height=l.height+"px"}if(a.style.height===""&&a.clientHeight===0){a.style.height=Dygraph.DEFAULT_HEIGHT+"px";if(a.style.width===""){a.style.width=Dygraph.DEFAULT_WIDTH+"px"}}this.width_=a.clientWidth;this.height_=a.clientHeight;if(l.stackedGraph){l.fillGraph=true}if(l.showRangeSelector&&l.animatedZooms){this.warn("You should not set animatedZooms=true when using the range selector.");l.animatedZooms=false}this.user_attrs_={};Dygraph.update(this.user_attrs_,l);this.attrs_={};Dygraph.updateDeep(this.attrs_,Dygraph.DEFAULT_ATTRS);this.boundaryIds_=[];this.setIndexByName_={};this.datasetIndex_=[];this.registeredEvents_=[];this.eventListeners_={};this.attributes_=new DygraphOptions(this);this.createInterface_();this.plugins_=[];var d=Dygraph.PLUGINS.concat(this.getOption("plugins"));for(var g=0;g<d.length;g++){var k=d[g];var f=new k();var j={plugin:f,events:{},options:{},pluginOptions:{}};var b=f.activate(this);for(var h in b){j.events[h]=b[h]}this.plugins_.push(j)}for(var g=0;g<this.plugins_.length;g++){var n=this.plugins_[g];for(var h in n.events){if(!n.events.hasOwnProperty(h)){continue}var m=n.events[h];var e=[n.plugin,m];if(!(h in this.eventListeners_)){this.eventListeners_[h]=[e]}else{this.eventListeners_[h].push(e)}}}this.start_()};Dygraph.prototype.cascadeEvents_=function(c,b){if(!(c in this.eventListeners_)){return true}var g={dygraph:this,cancelable:false,defaultPrevented:false,preventDefault:function(){if(!g.cancelable){throw"Cannot call preventDefault on non-cancelable event."}g.defaultPrevented=true},propagationStopped:false,stopPropagation:function(){g.propagationStopped=true}};Dygraph.update(g,b);var a=this.eventListeners_[c];if(a){for(var d=a.length-1;d>=0;d--){var f=a[d][0];var h=a[d][1];h.call(f,g);if(g.propagationStopped){break}}}return g.defaultPrevented};Dygraph.prototype.isZoomed=function(a){if(a===null||a===undefined){return this.zoomed_x_||this.zoomed_y_}if(a==="x"){return this.zoomed_x_}if(a==="y"){return this.zoomed_y_}throw"axis parameter is ["+a+"] must be null, 'x' or 'y'."};Dygraph.prototype.toString=function(){var a=this.maindiv_;var b=(a&&a.id)?a.id:a;return"[Dygraph "+b+"]"};Dygraph.prototype.attr_=function(b,a){return a?this.attributes_.getForSeries(b,a):this.attributes_.get(b)};Dygraph.prototype.getOption=function(a,b){return this.attr_(a,b)};Dygraph.prototype.getOptionForAxis=function(a,b){return this.attributes_.getForAxis(a,b)};Dygraph.prototype.optionsViewForAxis_=function(b){var a=this;return function(c){var d=a.user_attrs_.axes;if(d&&d[b]&&d[b][c]){return d[b][c]}if(typeof(a.user_attrs_[c])!="undefined"){return a.user_attrs_[c]}d=a.attrs_.axes;if(d&&d[b]&&d[b][c]){return d[b][c]}if(b=="y"&&a.axes_[0].hasOwnProperty(c)){return a.axes_[0][c]}else{if(b=="y2"&&a.axes_[1].hasOwnProperty(c)){return a.axes_[1][c]}}return a.attr_(c)}};Dygraph.prototype.rollPeriod=function(){return this.rollPeriod_};Dygraph.prototype.xAxisRange=function(){return this.dateWindow_?this.dateWindow_:this.xAxisExtremes()};Dygraph.prototype.xAxisExtremes=function(){var b=this.rawData_[0][0];var a=this.rawData_[this.rawData_.length-1][0];return[b,a]};Dygraph.prototype.yAxisRange=function(a){if(typeof(a)=="undefined"){a=0}if(a<0||a>=this.axes_.length){return null}var b=this.axes_[a];return[b.computedValueRange[0],b.computedValueRange[1]]};Dygraph.prototype.yAxisRanges=function(){var a=[];for(var b=0;b<this.axes_.length;b++){a.push(this.yAxisRange(b))}return a};Dygraph.prototype.toDomCoords=function(a,c,b){return[this.toDomXCoord(a),this.toDomYCoord(c,b)]};Dygraph.prototype.toDomXCoord=function(b){if(b===null){return null}var c=this.plotter_.area;var a=this.xAxisRange();return c.x+(b-a[0])/(a[1]-a[0])*c.w};Dygraph.prototype.toDomYCoord=function(d,a){var c=this.toPercentYCoord(d,a);if(c===null){return null}var b=this.plotter_.area;return b.y+c*b.h};Dygraph.prototype.toDataCoords=function(a,c,b){return[this.toDataXCoord(a),this.toDataYCoord(c,b)]};Dygraph.prototype.toDataXCoord=function(b){if(b===null){return null}var c=this.plotter_.area;var a=this.xAxisRange();return a[0]+(b-c.x)/c.w*(a[1]-a[0])};Dygraph.prototype.toDataYCoord=function(h,b){if(h===null){return null}var c=this.plotter_.area;var g=this.yAxisRange(b);if(typeof(b)=="undefined"){b=0}if(!this.axes_[b].logscale){return g[0]+(c.y+c.h-h)/c.h*(g[1]-g[0])}else{var f=(h-c.y)/c.h;var a=Dygraph.log10(g[1]);var e=a-(f*(a-Dygraph.log10(g[0])));var d=Math.pow(Dygraph.LOG_SCALE,e);return d}};Dygraph.prototype.toPercentYCoord=function(f,c){if(f===null){return null}if(typeof(c)=="undefined"){c=0}var e=this.yAxisRange(c);var d;var b=this.attributes_.getForAxis("logscale",c);if(!b){d=(e[1]-f)/(e[1]-e[0])}else{var a=Dygraph.log10(e[1]);d=(a-Dygraph.log10(f))/(a-Dygraph.log10(e[0]))}return d};Dygraph.prototype.toPercentXCoord=function(b){if(b===null){return null}var a=this.xAxisRange();return(b-a[0])/(a[1]-a[0])};Dygraph.prototype.numColumns=function(){return this.rawData_[0]?this.rawData_[0].length:this.attr_("labels").length};Dygraph.prototype.numRows=function(){return this.rawData_.length};Dygraph.prototype.fullXRange_=function(){if(this.numRows()>0){return[this.rawData_[0][0],this.rawData_[this.numRows()-1][0]]}else{return[0,1]}};Dygraph.prototype.getValue=function(b,a){if(b<0||b>this.rawData_.length){return null}if(a<0||a>this.rawData_[b].length){return null}return this.rawData_[b][a]};Dygraph.prototype.createInterface_=function(){var a=this.maindiv_;this.graphDiv=document.createElement("div");this.graphDiv.style.width=this.width_+"px";this.graphDiv.style.height=this.height_+"px";a.appendChild(this.graphDiv);this.canvas_=Dygraph.createCanvas();this.canvas_.style.position="absolute";this.canvas_.width=this.width_;this.canvas_.height=this.height_;this.canvas_.style.width=this.width_+"px";this.canvas_.style.height=this.height_+"px";this.canvas_ctx_=Dygraph.getContext(this.canvas_);this.hidden_=this.createPlotKitCanvas_(this.canvas_);this.hidden_ctx_=Dygraph.getContext(this.hidden_);if(this.attr_("showRangeSelector")){this.rangeSelector_=new DygraphRangeSelector(this)}this.graphDiv.appendChild(this.hidden_);this.graphDiv.appendChild(this.canvas_);this.mouseEventElement_=this.createMouseEventElement_();this.layout_=new DygraphLayout(this);if(this.rangeSelector_){this.rangeSelector_.addToGraph(this.graphDiv,this.layout_)}var b=this;this.mouseMoveHandler=function(c){b.mouseMove_(c)};this.addEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);this.mouseOutHandler=function(c){b.mouseOut_(c)};this.addEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);this.createDragInterface_();this.resizeHandler=function(c){b.resize()};this.addEvent(window,"resize",this.resizeHandler)};Dygraph.prototype.destroy=function(){var b=function(e){while(e.hasChildNodes()){b(e.firstChild);e.removeChild(e.firstChild)}};for(var a=0;a<this.registeredEvents_.length;a++){var d=this.registeredEvents_[a];Dygraph.removeEvent(d.elem,d.type,d.fn)}this.registeredEvents_=[];Dygraph.removeEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseUpHandler_);b(this.maindiv_);var c=function(e){for(var f in e){if(typeof(e[f])==="object"){e[f]=null}}};Dygraph.removeEvent(window,"resize",this.resizeHandler);this.resizeHandler=null;c(this.layout_);c(this.plotter_);c(this)};Dygraph.prototype.createPlotKitCanvas_=function(a){var b=Dygraph.createCanvas();b.style.position="absolute";b.style.top=a.style.top;b.style.left=a.style.left;b.width=this.width_;b.height=this.height_;b.style.width=this.width_+"px";b.style.height=this.height_+"px";return b};Dygraph.prototype.createMouseEventElement_=function(){if(this.isUsingExcanvas_){var a=document.createElement("div");a.style.position="absolute";a.style.backgroundColor="white";a.style.filter="alpha(opacity=0)";a.style.width=this.width_+"px";a.style.height=this.height_+"px";this.graphDiv.appendChild(a);return a}else{return this.canvas_}};Dygraph.prototype.setColors_=function(){var g=this.getLabels();var e=g.length-1;this.colors_=[];this.colorsMap_={};var a=this.attr_("colors");var d;if(!a){var c=this.attr_("colorSaturation")||1;var b=this.attr_("colorValue")||0.5;var k=Math.ceil(e/2);for(d=1;d<=e;d++){if(!this.visibility()[d-1]){continue}var h=d%2?Math.ceil(d/2):(k+d/2);var f=(1*h/(1+e));var j=Dygraph.hsvToRGB(f,c,b);this.colors_.push(j);this.colorsMap_[g[d]]=j}}else{for(d=0;d<e;d++){if(!this.visibility()[d]){continue}var j=a[d%a.length];this.colors_.push(j);this.colorsMap_[g[1+d]]=j}}};Dygraph.prototype.getColors=function(){return this.colors_};Dygraph.prototype.getPropertiesForSeries=function(c){var a=-1;var d=this.getLabels();for(var b=1;b<d.length;b++){if(d[b]==c){a=b;break}}if(a==-1){return null}return{name:c,column:a,visible:this.visibility()[a-1],color:this.colorsMap_[c],axis:1+this.attributes_.axisForSeries(c)}};Dygraph.prototype.createRollInterface_=function(){if(!this.roller_){this.roller_=document.createElement("input");this.roller_.type="text";this.roller_.style.display="none";this.graphDiv.appendChild(this.roller_)}var e=this.attr_("showRoller")?"block":"none";var d=this.plotter_.area;var b={position:"absolute",zIndex:10,top:(d.y+d.h-25)+"px",left:(d.x+1)+"px",display:e};this.roller_.size="2";this.roller_.value=this.rollPeriod_;for(var a in b){if(b.hasOwnProperty(a)){this.roller_.style[a]=b[a]}}var c=this;this.roller_.onchange=function(){c.adjustRoll(c.roller_.value)}};Dygraph.prototype.dragGetX_=function(b,a){return Dygraph.pageX(b)-a.px};Dygraph.prototype.dragGetY_=function(b,a){return Dygraph.pageY(b)-a.py};Dygraph.prototype.createDragInterface_=function(){var c={isZooming:false,isPanning:false,is2DPan:false,dragStartX:null,dragStartY:null,dragEndX:null,dragEndY:null,dragDirection:null,prevEndX:null,prevEndY:null,prevDragDirection:null,cancelNextDblclick:false,initialLeftmostDate:null,xUnitsPerPixel:null,dateRange:null,px:0,py:0,boundedDates:null,boundedValues:null,tarp:new Dygraph.IFrameTarp(),initializeMouseDown:function(i,h,f){if(i.preventDefault){i.preventDefault()}else{i.returnValue=false;i.cancelBubble=true}f.px=Dygraph.findPosX(h.canvas_);f.py=Dygraph.findPosY(h.canvas_);f.dragStartX=h.dragGetX_(i,f);f.dragStartY=h.dragGetY_(i,f);f.cancelNextDblclick=false;f.tarp.cover()}};var e=this.attr_("interactionModel");var b=this;var d=function(f){return function(g){f(g,b,c)}};for(var a in e){if(!e.hasOwnProperty(a)){continue}this.addEvent(this.mouseEventElement_,a,d(e[a]))}this.mouseUpHandler_=function(g){if(c.isZooming||c.isPanning){c.isZooming=false;c.dragStartX=null;c.dragStartY=null}if(c.isPanning){c.isPanning=false;c.draggingDate=null;c.dateRange=null;for(var f=0;f<b.axes_.length;f++){delete b.axes_[f].draggingValue;delete b.axes_[f].dragValueRange}}c.tarp.uncover()};this.addEvent(document,"mouseup",this.mouseUpHandler_)};Dygraph.prototype.drawZoomRect_=function(e,c,i,b,g,a,f,d){var h=this.canvas_ctx_;if(a==Dygraph.HORIZONTAL){h.clearRect(Math.min(c,f),this.layout_.getPlotArea().y,Math.abs(c-f),this.layout_.getPlotArea().h)}else{if(a==Dygraph.VERTICAL){h.clearRect(this.layout_.getPlotArea().x,Math.min(b,d),this.layout_.getPlotArea().w,Math.abs(b-d))}}if(e==Dygraph.HORIZONTAL){if(i&&c){h.fillStyle="rgba(128,128,128,0.33)";h.fillRect(Math.min(c,i),this.layout_.getPlotArea().y,Math.abs(i-c),this.layout_.getPlotArea().h)}}else{if(e==Dygraph.VERTICAL){if(g&&b){h.fillStyle="rgba(128,128,128,0.33)";h.fillRect(this.layout_.getPlotArea().x,Math.min(b,g),this.layout_.getPlotArea().w,Math.abs(g-b))}}}if(this.isUsingExcanvas_){this.currentZoomRectArgs_=[e,c,i,b,g,0,0,0]}};Dygraph.prototype.clearZoomRect_=function(){this.currentZoomRectArgs_=null;this.canvas_ctx_.clearRect(0,0,this.canvas_.width,this.canvas_.height)};Dygraph.prototype.doZoomX_=function(c,a){this.currentZoomRectArgs_=null;var b=this.toDataXCoord(c);var d=this.toDataXCoord(a);this.doZoomXDates_(b,d)};Dygraph.zoomAnimationFunction=function(c,b){var a=1.5;return(1-Math.pow(a,-c))/(1-Math.pow(a,-b))};Dygraph.prototype.doZoomXDates_=function(c,e){var a=this.xAxisRange();var d=[c,e];this.zoomed_x_=true;var b=this;this.doAnimatedZoom(a,d,null,null,function(){if(b.attr_("zoomCallback")){b.attr_("zoomCallback")(c,e,b.yAxisRanges())}})};Dygraph.prototype.doZoomY_=function(h,f){this.currentZoomRectArgs_=null;var c=this.yAxisRanges();var b=[];for(var e=0;e<this.axes_.length;e++){var d=this.toDataYCoord(h,e);var a=this.toDataYCoord(f,e);b.push([a,d])}this.zoomed_y_=true;var g=this;this.doAnimatedZoom(null,null,c,b,function(){if(g.attr_("zoomCallback")){var i=g.xAxisRange();g.attr_("zoomCallback")(i[0],i[1],g.yAxisRanges())}})};Dygraph.prototype.resetZoom=function(){var c=false,d=false,a=false;if(this.dateWindow_!==null){c=true;d=true}for(var g=0;g<this.axes_.length;g++){if(typeof(this.axes_[g].valueWindow)!=="undefined"&&this.axes_[g].valueWindow!==null){c=true;a=true}}this.clearSelection();if(c){this.zoomed_x_=false;this.zoomed_y_=false;var f=this.rawData_[0][0];var b=this.rawData_[this.rawData_.length-1][0];if(!this.attr_("animatedZooms")){this.dateWindow_=null;for(g=0;g<this.axes_.length;g++){if(this.axes_[g].valueWindow!==null){delete this.axes_[g].valueWindow}}this.drawGraph_();if(this.attr_("zoomCallback")){this.attr_("zoomCallback")(f,b,this.yAxisRanges())}return}var l=null,m=null,k=null,h=null;if(d){l=this.xAxisRange();m=[f,b]}if(a){k=this.yAxisRanges();var n=this.gatherDatasets_(this.rolledSeries_,null);var o=n[1];this.computeYAxisRanges_(o);h=[];for(g=0;g<this.axes_.length;g++){var e=this.axes_[g];h.push((e.valueRange!==null&&e.valueRange!==undefined)?e.valueRange:e.extremeRange)}}var j=this;this.doAnimatedZoom(l,m,k,h,function(){j.dateWindow_=null;for(var p=0;p<j.axes_.length;p++){if(j.axes_[p].valueWindow!==null){delete j.axes_[p].valueWindow}}if(j.attr_("zoomCallback")){j.attr_("zoomCallback")(f,b,j.yAxisRanges())}})}};Dygraph.prototype.doAnimatedZoom=function(a,e,b,c,m){var i=this.attr_("animatedZooms")?Dygraph.ANIMATION_STEPS:1;var l=[];var k=[];var f,d;if(a!==null&&e!==null){for(f=1;f<=i;f++){d=Dygraph.zoomAnimationFunction(f,i);l[f-1]=[a[0]*(1-d)+d*e[0],a[1]*(1-d)+d*e[1]]}}if(b!==null&&c!==null){for(f=1;f<=i;f++){d=Dygraph.zoomAnimationFunction(f,i);var n=[];for(var g=0;g<this.axes_.length;g++){n.push([b[g][0]*(1-d)+d*c[g][0],b[g][1]*(1-d)+d*c[g][1]])}k[f-1]=n}}var h=this;Dygraph.repeatAndCleanup(function(p){if(k.length){for(var o=0;o<h.axes_.length;o++){var j=k[p][o];h.axes_[o].valueWindow=[j[0],j[1]]}}if(l.length){h.dateWindow_=l[p]}h.drawGraph_()},i,Dygraph.ANIMATION_DURATION/i,m)};Dygraph.prototype.getArea=function(){return this.plotter_.area};Dygraph.prototype.eventToDomCoords=function(c){var b=Dygraph.pageX(c)-Dygraph.findPosX(this.mouseEventElement_);var a=Dygraph.pageY(c)-Dygraph.findPosY(this.mouseEventElement_);return[b,a]};Dygraph.prototype.findClosestRow=function(b){var k=Infinity;var d=-1,a=-1;var g=this.layout_.points;for(var e=0;e<g.length;e++){var m=g[e];var f=m.length;for(var c=0;c<f;c++){var l=m[c];if(!Dygraph.isValidPoint(l,true)){continue}var h=Math.abs(l.canvasx-b);if(h<k){k=h;a=e;d=c}}}return this.idxToRow_(a,d)};Dygraph.prototype.findClosestPoint=function(f,e){var j=Infinity;var k=-1;var h,o,n,l,d,c;for(var b=this.layout_.datasets.length-1;b>=0;--b){var m=this.layout_.points[b];for(var g=0;g<m.length;++g){var l=m[g];if(!Dygraph.isValidPoint(l)){continue}o=l.canvasx-f;n=l.canvasy-e;h=o*o+n*n;if(h<j){j=h;d=l;c=b;k=g}}}var a=this.layout_.setNames[c];return{row:k+this.getLeftBoundary_(),seriesName:a,point:d}};Dygraph.prototype.findStackedPoint=function(i,h){var q=this.findClosestRow(i);var g=this.getLeftBoundary_();var e=q-g;var j=this.layout_.points;var f,d;for(var c=0;c<this.layout_.datasets.length;++c){var m=this.layout_.points[c];if(e>=m.length){continue}var n=m[e];if(!Dygraph.isValidPoint(n)){continue}var k=n.canvasy;if(i>n.canvasx&&e+1<m.length){var l=m[e+1];if(Dygraph.isValidPoint(l)){var p=l.canvasx-n.canvasx;if(p>0){var a=(i-n.canvasx)/p;k+=a*(l.canvasy-n.canvasy)}}}else{if(i<n.canvasx&&e>0){var o=m[e-1];if(Dygraph.isValidPoint(o)){var p=n.canvasx-o.canvasx;if(p>0){var a=(n.canvasx-i)/p;k+=a*(o.canvasy-n.canvasy)}}}}if(c===0||k<h){f=n;d=c}}var b=this.layout_.setNames[d];return{row:q,seriesName:b,point:f}};Dygraph.prototype.mouseMove_=function(b){var h=this.layout_.points;if(h===undefined||h===null){return}var e=this.eventToDomCoords(b);var a=e[0];var j=e[1];var f=this.attr_("highlightSeriesOpts");var d=false;if(f&&!this.isSeriesLocked()){var c;if(this.attr_("stackedGraph")){c=this.findStackedPoint(a,j)}else{c=this.findClosestPoint(a,j)}d=this.setSelection(c.row,c.seriesName)}else{var g=this.findClosestRow(a);d=this.setSelection(g)}var i=this.attr_("highlightCallback");if(i&&d){i(b,this.lastx_,this.selPoints_,this.lastRow_,this.highlightSet_)}};Dygraph.prototype.getLeftBoundary_=function(){for(var a=0;a<this.boundaryIds_.length;a++){if(this.boundaryIds_[a]!==undefined){return this.boundaryIds_[a][0]}}return 0};Dygraph.prototype.idxToRow_=function(b,a){if(a<0){return -1}var c=this.getLeftBoundary_();return c+a};Dygraph.prototype.animateSelection_=function(f){var e=10;var c=30;if(this.fadeLevel===undefined){this.fadeLevel=0}if(this.animateId===undefined){this.animateId=0}var g=this.fadeLevel;var b=f<0?g:e-g;if(b<=0){if(this.fadeLevel){this.updateSelection_(1)}return}var a=++this.animateId;var d=this;Dygraph.repeatAndCleanup(function(h){if(d.animateId!=a){return}d.fadeLevel+=f;if(d.fadeLevel===0){d.clearSelection()}else{d.updateSelection_(d.fadeLevel/e)}},b,c,function(){})};Dygraph.prototype.updateSelection_=function(d){var l=this.cascadeEvents_("select",{selectedX:this.lastx_,selectedPoints:this.selPoints_});var h;var o=this.canvas_ctx_;if(this.attr_("highlightSeriesOpts")){o.clearRect(0,0,this.width_,this.height_);var f=1-this.attr_("highlightSeriesBackgroundAlpha");if(f){var g=true;if(g){if(d===undefined){this.animateSelection_(1);return}f*=d}o.fillStyle="rgba(255,255,255,"+f+")";o.fillRect(0,0,this.width_,this.height_)}this.plotter_._renderLineChart(this.highlightSet_,o)}else{if(this.previousVerticalX_>=0){var j=0;var k=this.attr_("labels");for(h=1;h<k.length;h++){var c=this.attr_("highlightCircleSize",k[h]);if(c>j){j=c}}var m=this.previousVerticalX_;o.clearRect(m-j-1,0,2*j+2,this.height_)}}if(this.isUsingExcanvas_&&this.currentZoomRectArgs_){Dygraph.prototype.drawZoomRect_.apply(this,this.currentZoomRectArgs_)}if(this.selPoints_.length>0){var b=this.selPoints_[0].canvasx;o.save();for(h=0;h<this.selPoints_.length;h++){var p=this.selPoints_[h];if(!Dygraph.isOK(p.canvasy)){continue}var a=this.attr_("highlightCircleSize",p.name);var n=this.attr_("drawHighlightPointCallback",p.name);var e=this.plotter_.colors[p.name];if(!n){n=Dygraph.Circles.DEFAULT}o.lineWidth=this.attr_("strokeWidth",p.name);o.strokeStyle=e;o.fillStyle=e;n(this.g,p.name,o,b,p.canvasy,e,a)}o.restore();this.previousVerticalX_=b}};Dygraph.prototype.setSelection=function(d,g,f){this.selPoints_=[];if(d!==false){d-=this.getLeftBoundary_()}var c=false;if(d!==false&&d>=0){if(d!=this.lastRow_){c=true}this.lastRow_=d;for(var b=0;b<this.layout_.datasets.length;++b){var e=this.layout_.datasets[b];if(d<e.length){var a=this.layout_.points[b][d];if(this.attr_("stackedGraph")){a=this.layout_.unstackPointAtIndex(b,d)}if(a.yval!==null){this.selPoints_.push(a)}}}}else{if(this.lastRow_>=0){c=true}this.lastRow_=-1}if(this.selPoints_.length){this.lastx_=this.selPoints_[0].xval}else{this.lastx_=-1}if(g!==undefined){if(this.highlightSet_!==g){c=true}this.highlightSet_=g}if(f!==undefined){this.lockedSet_=f}if(c){this.updateSelection_(undefined)}return c};Dygraph.prototype.mouseOut_=function(a){if(this.attr_("unhighlightCallback")){this.attr_("unhighlightCallback")(a)}if(this.attr_("hideOverlayOnMouseOut")&&!this.lockedSet_){this.clearSelection()}};Dygraph.prototype.clearSelection=function(){this.cascadeEvents_("deselect",{});this.lockedSet_=false;if(this.fadeLevel){this.animateSelection_(-1);return}this.canvas_ctx_.clearRect(0,0,this.width_,this.height_);this.fadeLevel=0;this.selPoints_=[];this.lastx_=-1;this.lastRow_=-1;this.highlightSet_=null};Dygraph.prototype.getSelection=function(){if(!this.selPoints_||this.selPoints_.length<1){return -1}for(var c=0;c<this.layout_.points.length;c++){var a=this.layout_.points[c];for(var b=0;b<a.length;b++){if(a[b].x==this.selPoints_[0].x){return b+this.getLeftBoundary_()}}}return -1};Dygraph.prototype.getHighlightSeries=function(){return this.highlightSet_};Dygraph.prototype.isSeriesLocked=function(){return this.lockedSet_};Dygraph.prototype.loadedEvent_=function(a){this.rawData_=this.parseCSV_(a);this.predraw_()};Dygraph.prototype.addXTicks_=function(){var a;if(this.dateWindow_){a=[this.dateWindow_[0],this.dateWindow_[1]]}else{a=this.fullXRange_()}var c=this.optionsViewForAxis_("x");var b=c("ticker")(a[0],a[1],this.width_,c,this);this.layout_.setXTicks(b)};Dygraph.prototype.extremeValues_=function(d){var h=null,f=null,c,g;var b=this.attr_("errorBars")||this.attr_("customBars");if(b){for(c=0;c<d.length;c++){g=d[c][1][0];if(g===null||isNaN(g)){continue}var a=g-d[c][1][1];var e=g+d[c][1][2];if(a>g){a=g}if(e<g){e=g}if(f===null||e>f){f=e}if(h===null||a<h){h=a}}}else{for(c=0;c<d.length;c++){g=d[c][1];if(g===null||isNaN(g)){continue}if(f===null||g>f){f=g}if(h===null||g<h){h=g}}}return[h,f]};Dygraph.prototype.predraw_=function(){var e=new Date();this.computeYAxes_();if(this.plotter_){this.cascadeEvents_("clearChart");this.plotter_.clear()}this.plotter_=new DygraphCanvasRenderer(this,this.hidden_,this.hidden_ctx_,this.layout_);this.createRollInterface_();this.cascadeEvents_("predraw");if(this.rangeSelector_){this.rangeSelector_.renderStaticLayer()}this.rolledSeries_=[null];for(var c=1;c<this.numColumns();c++){var d=this.attr_("logscale");var b=this.extractSeries_(this.rawData_,c,d);b=this.rollingAverage(b,this.rollPeriod_);this.rolledSeries_.push(b)}this.drawGraph_();var a=new Date();this.drawingTimeMs_=(a-e)};Dygraph.prototype.gatherDatasets_=function(w,c){var s=[];var b=[];var e=[];var a={};var u,t,r;var m=w.length-1;for(u=m;u>=1;u--){if(!this.visibility()[u-1]){continue}var h=[];for(t=0;t<w[u].length;t++){h.push(w[u][t])}var o=this.attr_("errorBars")||this.attr_("customBars");if(c){var A=c[0];var f=c[1];var p=[];var d=null,z=null;for(r=0;r<h.length;r++){if(h[r][0]>=A&&d===null){d=r}if(h[r][0]<=f){z=r}}if(d===null){d=0}if(d>0){d--}if(z===null){z=h.length-1}if(z<h.length-1){z++}s[u-1]=[d,z];for(r=d;r<=z;r++){p.push(h[r])}h=p}else{s[u-1]=[0,h.length-1]}var n=this.extremeValues_(h);if(o){for(t=0;t<h.length;t++){h[t]=[h[t][0],h[t][1][0],h[t][1][1],h[t][1][2]]}}else{if(this.attr_("stackedGraph")){var q=h.length;var y;for(t=0;t<q;t++){var g=h[t][0];if(b[g]===undefined){b[g]=0}y=h[t][1];if(y===null){h[t]=[g,null];continue}b[g]+=y;h[t]=[g,b[g]];if(b[g]>n[1]){n[1]=b[g]}if(b[g]<n[0]){n[0]=b[g]}}}}var v=this.attr_("labels")[u];a[v]=n;e[u]=h}if(this.attr_("stackedGraph")){for(r=e.length-1;r>=0;--r){if(!e[r]){continue}for(t=0;t<e[r].length;t++){var g=e[r][t][0];if(isNaN(b[g])){for(u=e.length-1;u>=0;u--){if(!e[u]){continue}e[u][t][1]=NaN}}}break}}return[e,a,s]};Dygraph.prototype.drawGraph_=function(){var a=new Date();var e=this.is_initial_draw_;this.is_initial_draw_=false;this.layout_.removeAllDatasets();this.setColors_();this.attrs_.pointSize=0.5*this.attr_("highlightCircleSize");var j=this.gatherDatasets_(this.rolledSeries_,this.dateWindow_);var d=j[0];var k=j[1];this.boundaryIds_=j[2];this.setIndexByName_={};var h=this.attr_("labels");if(h.length>0){this.setIndexByName_[h[0]]=0}var f=0;for(var g=1;g<d.length;g++){this.setIndexByName_[h[g]]=g;if(!this.visibility()[g-1]){continue}this.layout_.addDataset(h[g],d[g]);this.datasetIndex_[g]=f++}this.computeYAxisRanges_(k);this.layout_.setYAxes(this.axes_);this.addXTicks_();var b=this.zoomed_x_;this.layout_.setDateWindow(this.dateWindow_);this.zoomed_x_=b;this.layout_.evaluateWithError();this.renderGraph_(e);if(this.attr_("timingName")){var c=new Date();if(console){console.log(this.attr_("timingName")+" - drawGraph: "+(c-a)+"ms")}}};Dygraph.prototype.renderGraph_=function(a){this.cascadeEvents_("clearChart");this.plotter_.clear();if(this.attr_("underlayCallback")){this.attr_("underlayCallback")(this.hidden_ctx_,this.layout_.getPlotArea(),this,this)}var b={canvas:this.hidden_,drawingContext:this.hidden_ctx_};this.cascadeEvents_("willDrawChart",b);this.plotter_.render();this.cascadeEvents_("didDrawChart",b);this.canvas_.getContext("2d").clearRect(0,0,this.canvas_.width,this.canvas_.height);if(this.rangeSelector_){this.rangeSelector_.renderInteractiveLayer()}if(this.attr_("drawCallback")!==null){this.attr_("drawCallback")(this,a)}};Dygraph.prototype.computeYAxes_=function(){var e,c,a,f,d,g,b;if(this.axes_!==undefined&&this.user_attrs_.hasOwnProperty("valueRange")===false){c=[];for(d=0;d<this.axes_.length;d++){c.push(this.axes_[d].valueWindow)}}this.axes_=[];for(f=0;f<this.attributes_.numAxes();f++){g={g:this};Dygraph.update(g,this.attributes_.axisOptions(f));this.axes_[f]=g}b=this.attr_("valueRange");if(b){this.axes_[0].valueRange=b}if(c!==undefined){for(d=0;d<c.length;d++){this.axes_[d].valueWindow=c[d]}}for(f=0;f<this.axes_.length;f++){if(f===0){g=this.optionsViewForAxis_("y"+(f?"2":""));b=g("valueRange");if(b){this.axes_[f].valueRange=b}}else{var h=this.user_attrs_.axes;if(h&&h.y2){b=h.y2.valueRange;if(b){this.axes_[f].valueRange=b}}}}};Dygraph.prototype.numAxes=function(){return this.attributes_.numAxes()};Dygraph.prototype.axisPropertiesForSeries=function(a){return this.axes_[this.attributes_.axisForSeries(a)]};Dygraph.prototype.computeYAxisRanges_=function(a){var g;var l=this.attributes_.numAxes();for(var t=0;t<l;t++){var b=this.axes_[t];var w=this.attributes_.getForAxis("logscale",t);var z=this.attributes_.getForAxis("includeZero",t);g=this.attributes_.seriesForAxis(t);if(g.length==0){b.extremeRange=[0,1]}else{var x=Infinity;var v=-Infinity;var o,m;for(var r=0;r<g.length;r++){if(!a.hasOwnProperty(g[r])){continue}o=a[g[r]][0];if(o!==null){x=Math.min(o,x)}m=a[g[r]][1];if(m!==null){v=Math.max(m,v)}}if(z&&x>0){x=0}if(x==Infinity){x=0}if(v==-Infinity){v=1}var s=v-x;if(s===0){s=v}var d,A;if(w){d=v+0.1*s;A=x}else{d=v+0.1*s;A=x-0.1*s;if(!this.attr_("avoidMinZero")){if(A<0&&x>=0){A=0}if(d>0&&v<=0){d=0}}if(this.attr_("includeZero")){if(v<0){d=0}if(x>0){A=0}}}b.extremeRange=[A,d]}if(b.valueWindow){b.computedValueRange=[b.valueWindow[0],b.valueWindow[1]]}else{if(b.valueRange){b.computedValueRange=[b.valueRange[0],b.valueRange[1]]}else{b.computedValueRange=b.extremeRange}}var n=this.optionsViewForAxis_("y"+(t?"2":""));var y=n("ticker");if(t===0||b.independentTicks){b.ticks=y(b.computedValueRange[0],b.computedValueRange[1],this.height_,n,this)}else{var h=this.axes_[0];var e=h.ticks;var f=h.computedValueRange[1]-h.computedValueRange[0];var B=b.computedValueRange[1]-b.computedValueRange[0];var c=[];for(var q=0;q<e.length;q++){var p=(e[q].v-h.computedValueRange[0])/f;var u=b.computedValueRange[0]+p*B;c.push(u)}b.ticks=y(b.computedValueRange[0],b.computedValueRange[1],this.height_,n,this,c)}}};Dygraph.prototype.extractSeries_=function(g,e,f){var d=[];for(var c=0;c<g.length;c++){var b=g[c][0];var a=g[c][e];if(f){if(a<=0){a=null}}d.push([b,a])}return d};Dygraph.prototype.rollingAverage=function(l,d){if(l.length<2){return l}d=Math.min(d,l.length);var b=[];var s=this.attr_("sigma");var E,o,w,v,m,c,D,x;if(this.fractions_){var k=0;var h=0;var e=100;for(w=0;w<l.length;w++){k+=l[w][1][0];h+=l[w][1][1];if(w-d>=0){k-=l[w-d][1][0];h-=l[w-d][1][1]}var A=l[w][0];var u=h?k/h:0;if(this.attr_("errorBars")){if(this.attr_("wilsonInterval")){if(h){var r=u<0?0:u,t=h;var z=s*Math.sqrt(r*(1-r)/t+s*s/(4*t*t));var a=1+s*s/h;E=(r+s*s/(2*h)-z)/a;o=(r+s*s/(2*h)+z)/a;b[w]=[A,[r*e,(r-E)*e,(o-r)*e]]}else{b[w]=[A,[0,0,0]]}}else{x=h?s*Math.sqrt(u*(1-u)/h):1;b[w]=[A,[e*u,e*x,e*x]]}}else{b[w]=[A,e*u]}}}else{if(this.attr_("customBars")){E=0;var B=0;o=0;var g=0;for(w=0;w<l.length;w++){var C=l[w][1];m=C[1];b[w]=[l[w][0],[m,m-C[0],C[2]-m]];if(m!==null&&!isNaN(m)){E+=C[0];B+=m;o+=C[2];g+=1}if(w-d>=0){var q=l[w-d];if(q[1][1]!==null&&!isNaN(q[1][1])){E-=q[1][0];B-=q[1][1];o-=q[1][2];g-=1}}if(g){b[w]=[l[w][0],[1*B/g,1*(B-E)/g,1*(o-B)/g]]}else{b[w]=[l[w][0],[null,null,null]]}}}else{if(!this.attr_("errorBars")){if(d==1){return l}for(w=0;w<l.length;w++){c=0;D=0;for(v=Math.max(0,w-d+1);v<w+1;v++){m=l[v][1];if(m===null||isNaN(m)){continue}D++;c+=l[v][1]}if(D){b[w]=[l[w][0],c/D]}else{b[w]=[l[w][0],null]}}}else{for(w=0;w<l.length;w++){c=0;var f=0;D=0;for(v=Math.max(0,w-d+1);v<w+1;v++){m=l[v][1][0];if(m===null||isNaN(m)){continue}D++;c+=l[v][1][0];f+=Math.pow(l[v][1][1],2)}if(D){x=Math.sqrt(f)/D;b[w]=[l[w][0],[c/D,s*x,s*x]]}else{b[w]=[l[w][0],[null,null,null]]}}}}}return b};Dygraph.prototype.detectTypeFromString_=function(b){var a=false;var c=b.indexOf("-");if((c>0&&(b[c-1]!="e"&&b[c-1]!="E"))||b.indexOf("/")>=0||isNaN(parseFloat(b))){a=true}else{if(b.length==8&&b>"19700101"&&b<"20371231"){a=true}}this.setXAxisOptions_(a)};Dygraph.prototype.setXAxisOptions_=function(a){if(a){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{this.attrs_.xValueParser=function(b){return parseFloat(b)};this.attrs_.axes.x.valueFormatter=function(b){return b};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}};Dygraph.prototype.parseFloat_=function(a,c,b){var e=parseFloat(a);if(!isNaN(e)){return e}if(/^ *$/.test(a)){return null}if(/^ *nan *$/i.test(a)){return NaN}var d="Unable to parse '"+a+"' as a number";if(b!==null&&c!==null){d+=" on line "+(1+c)+" ('"+b+"') of CSV."}this.error(d);return null};Dygraph.prototype.parseCSV_=function(t){var r=[];var s=Dygraph.detectLineDelimiter(t);var a=t.split(s||"\n");var g,k;var p=this.attr_("delimiter");if(a[0].indexOf(p)==-1&&a[0].indexOf("\t")>=0){p="\t"}var b=0;if(!("labels" in this.user_attrs_)){b=1;this.attrs_.labels=a[0].split(p);this.attributes_.reparseSeries()}var o=0;var m;var q=false;var c=this.attr_("labels").length;var f=false;for(var l=b;l<a.length;l++){var e=a[l];o=l;if(e.length===0){continue}if(e[0]=="#"){continue}var d=e.split(p);if(d.length<2){continue}var h=[];if(!q){this.detectTypeFromString_(d[0]);m=this.attr_("xValueParser");q=true}h[0]=m(d[0],this);if(this.fractions_){for(k=1;k<d.length;k++){g=d[k].split("/");if(g.length!=2){this.error('Expected fractional "num/den" values in CSV data but found a value \''+d[k]+"' on line "+(1+l)+" ('"+e+"') which is not of this form.");h[k]=[0,0]}else{h[k]=[this.parseFloat_(g[0],l,e),this.parseFloat_(g[1],l,e)]}}}else{if(this.attr_("errorBars")){if(d.length%2!=1){this.error("Expected alternating (value, stdev.) pairs in CSV data but line "+(1+l)+" has an odd number of values ("+(d.length-1)+"): '"+e+"'")}for(k=1;k<d.length;k+=2){h[(k+1)/2]=[this.parseFloat_(d[k],l,e),this.parseFloat_(d[k+1],l,e)]}}else{if(this.attr_("customBars")){for(k=1;k<d.length;k++){var u=d[k];if(/^ *$/.test(u)){h[k]=[null,null,null]}else{g=u.split(";");if(g.length==3){h[k]=[this.parseFloat_(g[0],l,e),this.parseFloat_(g[1],l,e),this.parseFloat_(g[2],l,e)]}else{this.warn('When using customBars, values must be either blank or "low;center;high" tuples (got "'+u+'" on line '+(1+l))}}}}else{for(k=1;k<d.length;k++){h[k]=this.parseFloat_(d[k],l,e)}}}}if(r.length>0&&h[0]<r[r.length-1][0]){f=true}if(h.length!=c){this.error("Number of columns in line "+l+" ("+h.length+") does not agree with number of labels ("+c+") "+e)}if(l===0&&this.attr_("labels")){var n=true;for(k=0;n&&k<h.length;k++){if(h[k]){n=false}}if(n){this.warn("The dygraphs 'labels' option is set, but the first row of CSV data ('"+e+"') appears to also contain labels. Will drop the CSV labels and use the option labels.");continue}}r.push(h)}if(f){this.warn("CSV is out of order; order it correctly to speed loading.");r.sort(function(j,i){return j[0]-i[0]})}return r};Dygraph.prototype.parseArray_=function(c){if(c.length===0){this.error("Can't plot empty data set");return null}if(c[0].length===0){this.error("Data set cannot contain an empty row");return null}var a;if(this.attr_("labels")===null){this.warn("Using default labels. Set labels explicitly via 'labels' in the options parameter");this.attrs_.labels=["X"];for(a=1;a<c[0].length;a++){this.attrs_.labels.push("Y"+a)}this.attributes_.reparseSeries()}else{var b=this.attr_("labels");if(b.length!=c[0].length){this.error("Mismatch between number of labels ("+b+") and number of columns in array ("+c[0].length+")");return null}}if(Dygraph.isDateLike(c[0][0])){this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter;var d=Dygraph.clone(c);for(a=0;a<c.length;a++){if(d[a].length===0){this.error("Row "+(1+a)+" of data is empty");return null}if(d[a][0]===null||typeof(d[a][0].getTime)!="function"||isNaN(d[a][0].getTime())){this.error("x value in row "+(1+a)+" is not a Date");return null}d[a][0]=d[a][0].getTime()}return d}else{this.attrs_.axes.x.valueFormatter=function(e){return e};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=Dygraph.numberAxisLabelFormatter;return c}};Dygraph.prototype.parseDataTable_=function(w){var d=function(i){var j=String.fromCharCode(65+i%26);i=Math.floor(i/26);while(i>0){j=String.fromCharCode(65+(i-1)%26)+j.toLowerCase();i=Math.floor((i-1)/26)}return j};var h=w.getNumberOfColumns();var g=w.getNumberOfRows();var f=w.getColumnType(0);if(f=="date"||f=="datetime"){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{if(f=="number"){this.attrs_.xValueParser=function(i){return parseFloat(i)};this.attrs_.axes.x.valueFormatter=function(i){return i};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}else{this.error("only 'date', 'datetime' and 'number' types are supported for column 1 of DataTable input (Got '"+f+"')");return null}}var m=[];var t={};var s=false;var q,o;for(q=1;q<h;q++){var b=w.getColumnType(q);if(b=="number"){m.push(q)}else{if(b=="string"&&this.attr_("displayAnnotations")){var r=m[m.length-1];if(!t.hasOwnProperty(r)){t[r]=[q]}else{t[r].push(q)}s=true}else{this.error("Only 'number' is supported as a dependent type with Gviz. 'string' is only supported if displayAnnotations is true")}}}var u=[w.getColumnLabel(0)];for(q=0;q<m.length;q++){u.push(w.getColumnLabel(m[q]));if(this.attr_("errorBars")){q+=1}}this.attrs_.labels=u;h=u.length;var v=[];var l=false;var a=[];for(q=0;q<g;q++){var e=[];if(typeof(w.getValue(q,0))==="undefined"||w.getValue(q,0)===null){this.warn("Ignoring row "+q+" of DataTable because of undefined or null first column.");continue}if(f=="date"||f=="datetime"){e.push(w.getValue(q,0).getTime())}else{e.push(w.getValue(q,0))}if(!this.attr_("errorBars")){for(o=0;o<m.length;o++){var c=m[o];e.push(w.getValue(q,c));if(s&&t.hasOwnProperty(c)&&w.getValue(q,t[c][0])!==null){var p={};p.series=w.getColumnLabel(c);p.xval=e[0];p.shortText=d(a.length);p.text="";for(var n=0;n<t[c].length;n++){if(n){p.text+="\n"}p.text+=w.getValue(q,t[c][n])}a.push(p)}}for(o=0;o<e.length;o++){if(!isFinite(e[o])){e[o]=null}}}else{for(o=0;o<h-1;o++){e.push([w.getValue(q,1+2*o),w.getValue(q,2+2*o)])}}if(v.length>0&&e[0]<v[v.length-1][0]){l=true}v.push(e)}if(l){this.warn("DataTable is out of order; order it correctly to speed loading.");v.sort(function(j,i){return j[0]-i[0]})}this.rawData_=v;if(a.length>0){this.setAnnotations(a,true)}this.attributes_.reparseSeries()};Dygraph.prototype.start_=function(){var d=this.file_;if(typeof d=="function"){d=d()}if(Dygraph.isArrayLike(d)){this.rawData_=this.parseArray_(d);this.predraw_()}else{if(typeof d=="object"&&typeof d.getColumnRange=="function"){this.parseDataTable_(d);this.predraw_()}else{if(typeof d=="string"){var c=Dygraph.detectLineDelimiter(d);if(c){this.loadedEvent_(d)}else{var b=new XMLHttpRequest();var a=this;b.onreadystatechange=function(){if(b.readyState==4){if(b.status===200||b.status===0){a.loadedEvent_(b.responseText)}}};b.open("GET",d,true);b.send(null)}}else{this.error("Unknown data format: "+(typeof d))}}}};Dygraph.prototype.updateOptions=function(e,b){if(typeof(b)=="undefined"){b=false}var d=e.file;var c=Dygraph.mapLegacyOptions_(e);if("rollPeriod" in c){this.rollPeriod_=c.rollPeriod}if("dateWindow" in c){this.dateWindow_=c.dateWindow;if(!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_x_=(c.dateWindow!==null)}}if("valueRange" in c&&!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_y_=(c.valueRange!==null)}var a=Dygraph.isPixelChangingOptionList(this.attr_("labels"),c);Dygraph.updateDeep(this.user_attrs_,c);this.attributes_.reparseSeries();if(d){this.file_=d;if(!b){this.start_()}}else{if(!b){if(a){this.predraw_()}else{this.renderGraph_(false)}}}};Dygraph.mapLegacyOptions_=function(c){var a={};for(var b in c){if(b=="file"){continue}if(c.hasOwnProperty(b)){a[b]=c[b]}}var e=function(g,f,h){if(!a.axes){a.axes={}}if(!a.axes[g]){a.axes[g]={}}a.axes[g][f]=h};var d=function(f,g,h){if(typeof(c[f])!="undefined"){Dygraph.warn("Option "+f+" is deprecated. Use the "+h+" option for the "+g+" axis instead. (e.g. { axes : { "+g+" : { "+h+" : ... } } } (see http://dygraphs.com/per-axis.html for more information.");e(g,h,c[f]);delete a[f]}};d("xValueFormatter","x","valueFormatter");d("pixelsPerXLabel","x","pixelsPerLabel");d("xAxisLabelFormatter","x","axisLabelFormatter");d("xTicker","x","ticker");d("yValueFormatter","y","valueFormatter");d("pixelsPerYLabel","y","pixelsPerLabel");d("yAxisLabelFormatter","y","axisLabelFormatter");d("yTicker","y","ticker");return a};Dygraph.prototype.resize=function(d,b){if(this.resize_lock){return}this.resize_lock=true;if((d===null)!=(b===null)){this.warn("Dygraph.resize() should be called with zero parameters or two non-NULL parameters. Pretending it was zero.");d=b=null}var a=this.width_;var c=this.height_;if(d){this.maindiv_.style.width=d+"px";this.maindiv_.style.height=b+"px";this.width_=d;this.height_=b}else{this.width_=this.maindiv_.clientWidth;this.height_=this.maindiv_.clientHeight}if(a!=this.width_||c!=this.height_){this.maindiv_.innerHTML="";this.roller_=null;this.attrs_.labelsDiv=null;this.createInterface_();if(this.annotations_.length){this.layout_.setAnnotations(this.annotations_)}this.predraw_()}this.resize_lock=false};Dygraph.prototype.adjustRoll=function(a){this.rollPeriod_=a;this.predraw_()};Dygraph.prototype.visibility=function(){if(!this.attr_("visibility")){this.attrs_.visibility=[]}while(this.attr_("visibility").length<this.numColumns()-1){this.attrs_.visibility.push(true)}return this.attr_("visibility")};Dygraph.prototype.setVisibility=function(b,c){var a=this.visibility();if(b<0||b>=a.length){this.warn("invalid series number in setVisibility: "+b)}else{a[b]=c;this.predraw_()}};Dygraph.prototype.size=function(){return{width:this.width_,height:this.height_}};Dygraph.prototype.setAnnotations=function(b,a){Dygraph.addAnnotationRule();this.annotations_=b;this.layout_.setAnnotations(this.annotations_);if(!a){this.predraw_()}};Dygraph.prototype.annotations=function(){return this.annotations_};Dygraph.prototype.getLabels=function(){return this.attr_("labels").slice()};Dygraph.prototype.indexFromSetName=function(a){return this.setIndexByName_[a]};Dygraph.prototype.datasetIndexFromSetName_=function(a){return this.datasetIndex_[this.indexFromSetName(a)]};Dygraph.addAnnotationRule=function(){if(Dygraph.addedAnnotationCSS){return}var f="border: 1px solid black; background-color: white; text-align: center;";var e=document.createElement("style");e.type="text/css";document.getElementsByTagName("head")[0].appendChild(e);for(var b=0;b<document.styleSheets.length;b++){if(document.styleSheets[b].disabled){continue}var d=document.styleSheets[b];try{if(d.insertRule){var a=d.cssRules?d.cssRules.length:0;d.insertRule(".dygraphDefaultAnnotation { "+f+" }",a)}else{if(d.addRule){d.addRule(".dygraphDefaultAnnotation",f)}}Dygraph.addedAnnotationCSS=true;return}catch(c){}}this.warn("Unable to add default annotation CSS rule; display may be off.")};var DateGraph=Dygraph;"use strict";Dygraph.LOG_SCALE=10;Dygraph.LN_TEN=Math.log(Dygraph.LOG_SCALE);Dygraph.log10=function(a){return Math.log(a)/Dygraph.LN_TEN};Dygraph.DEBUG=1;Dygraph.INFO=2;Dygraph.WARNING=3;Dygraph.ERROR=3;Dygraph.LOG_STACK_TRACES=false;Dygraph.DOTTED_LINE=[2,2];Dygraph.DASHED_LINE=[7,3];Dygraph.DOT_DASH_LINE=[7,2,2,2];Dygraph.log=function(b,d){var a;if(typeof(printStackTrace)!="undefined"){try{a=printStackTrace({guess:false});while(a[0].indexOf("stacktrace")!=-1){a.splice(0,1)}a.splice(0,2);for(var c=0;c<a.length;c++){a[c]=a[c].replace(/\([^)]*\/(.*)\)/,"@$1").replace(/\@.*\/([^\/]*)/,"@$1").replace("[object Object].","")}var g=a.splice(0,1)[0];d+=" ("+g.replace(/^.*@ ?/,"")+")"}catch(f){}}if(typeof(window.console)!="undefined"){switch(b){case Dygraph.DEBUG:window.console.debug("dygraphs: "+d);break;case Dygraph.INFO:window.console.info("dygraphs: "+d);break;case Dygraph.WARNING:window.console.warn("dygraphs: "+d);break;case Dygraph.ERROR:window.console.error("dygraphs: "+d);break}}if(Dygraph.LOG_STACK_TRACES){window.console.log(a.join("\n"))}};Dygraph.info=function(a){Dygraph.log(Dygraph.INFO,a)};Dygraph.prototype.info=Dygraph.info;Dygraph.warn=function(a){Dygraph.log(Dygraph.WARNING,a)};Dygraph.prototype.warn=Dygraph.warn;Dygraph.error=function(a){Dygraph.log(Dygraph.ERROR,a)};Dygraph.prototype.error=Dygraph.error;Dygraph.getContext=function(a){return(a.getContext("2d"))};Dygraph.addEvent=function addEvent(c,b,a){if(c.addEventListener){c.addEventListener(b,a,false)}else{c[b+a]=function(){a(window.event)};c.attachEvent("on"+b,c[b+a])}};Dygraph.prototype.addEvent=function addEvent(c,b,a){Dygraph.addEvent(c,b,a);this.registeredEvents_.push({elem:c,type:b,fn:a})};Dygraph.removeEvent=function addEvent(c,b,a){if(c.removeEventListener){c.removeEventListener(b,a,false)}else{try{c.detachEvent("on"+b,c[b+a])}catch(d){}c[b+a]=null}};Dygraph.cancelEvent=function(a){a=a?a:window.event;if(a.stopPropagation){a.stopPropagation()}if(a.preventDefault){a.preventDefault()}a.cancelBubble=true;a.cancel=true;a.returnValue=false;return false};Dygraph.hsvToRGB=function(h,g,k){var c;var d;var l;if(g===0){c=k;d=k;l=k}else{var e=Math.floor(h*6);var j=(h*6)-e;var b=k*(1-g);var a=k*(1-(g*j));var m=k*(1-(g*(1-j)));switch(e){case 1:c=a;d=k;l=b;break;case 2:c=b;d=k;l=m;break;case 3:c=b;d=a;l=k;break;case 4:c=m;d=b;l=k;break;case 5:c=k;d=b;l=a;break;case 6:case 0:c=k;d=m;l=b;break}}c=Math.floor(255*c+0.5);d=Math.floor(255*d+0.5);l=Math.floor(255*l+0.5);return"rgb("+c+","+d+","+l+")"};Dygraph.findPosX=function(b){var c=0;if(b.offsetParent){var a=b;while(1){c+=a.offsetLeft;if(!a.offsetParent){break}a=a.offsetParent}}else{if(b.x){c+=b.x}}while(b&&b!=document.body){c-=b.scrollLeft;b=b.parentNode}return c};Dygraph.findPosY=function(c){var b=0;if(c.offsetParent){var a=c;while(1){b+=a.offsetTop;if(!a.offsetParent){break}a=a.offsetParent}}else{if(c.y){b+=c.y}}while(c&&c!=document.body){b-=c.scrollTop;c=c.parentNode}return b};Dygraph.pageX=function(c){if(c.pageX){return(!c.pageX||c.pageX<0)?0:c.pageX}else{var d=document.documentElement;var a=document.body;return c.clientX+(d.scrollLeft||a.scrollLeft)-(d.clientLeft||0)}};Dygraph.pageY=function(c){if(c.pageY){return(!c.pageY||c.pageY<0)?0:c.pageY}else{var d=document.documentElement;var a=document.body;return c.clientY+(d.scrollTop||a.scrollTop)-(d.clientTop||0)}};Dygraph.isOK=function(a){return !!a&&!isNaN(a)};Dygraph.isValidPoint=function(b,a){if(!b){return false}if(b.yval===null){return false}if(b.x===null||b.x===undefined){return false}if(b.y===null||b.y===undefined){return false}if(isNaN(b.x)||(!a&&isNaN(b.y))){return false}return true};Dygraph.floatFormat=function(a,b){var c=Math.min(Math.max(1,b||2),21);return(Math.abs(a)<0.001&&a!==0)?a.toExponential(c-1):a.toPrecision(c)};Dygraph.zeropad=function(a){if(a<10){return"0"+a}else{return""+a}};Dygraph.hmsString_=function(a){var c=Dygraph.zeropad;var b=new Date(a);if(b.getSeconds()){return c(b.getHours())+":"+c(b.getMinutes())+":"+c(b.getSeconds())}else{return c(b.getHours())+":"+c(b.getMinutes())}};Dygraph.round_=function(c,b){var a=Math.pow(10,b);return Math.round(c*a)/a};Dygraph.binarySearch=function(a,d,i,e,b){if(e===null||e===undefined||b===null||b===undefined){e=0;b=d.length-1}if(e>b){return -1}if(i===null||i===undefined){i=0}var h=function(j){return j>=0&&j<d.length};var g=parseInt((e+b)/2,10);var c=d[g];var f;if(c==a){return g}else{if(c>a){if(i>0){f=g-1;if(h(f)&&d[f]<a){return g}}return Dygraph.binarySearch(a,d,i,e,g-1)}else{if(c<a){if(i<0){f=g+1;if(h(f)&&d[f]>a){return g}}return Dygraph.binarySearch(a,d,i,g+1,b)}}}return -1};Dygraph.dateParser=function(a){var b;var c;if(a.search("-")==-1||a.search("T")!=-1||a.search("Z")!=-1){c=Dygraph.dateStrToMillis(a);if(c&&!isNaN(c)){return c}}if(a.search("-")!=-1){b=a.replace("-","/","g");while(b.search("-")!=-1){b=b.replace("-","/")}c=Dygraph.dateStrToMillis(b)}else{if(a.length==8){b=a.substr(0,4)+"/"+a.substr(4,2)+"/"+a.substr(6,2);c=Dygraph.dateStrToMillis(b)}else{c=Dygraph.dateStrToMillis(a)}}if(!c||isNaN(c)){Dygraph.error("Couldn't parse "+a+" as a date")}return c};Dygraph.dateStrToMillis=function(a){return new Date(a).getTime()};Dygraph.update=function(b,c){if(typeof(c)!="undefined"&&c!==null){for(var a in c){if(c.hasOwnProperty(a)){b[a]=c[a]}}}return b};Dygraph.updateDeep=function(b,d){function c(e){return(typeof Node==="object"?e instanceof Node:typeof e==="object"&&typeof e.nodeType==="number"&&typeof e.nodeName==="string")}if(typeof(d)!="undefined"&&d!==null){for(var a in d){if(d.hasOwnProperty(a)){if(d[a]===null){b[a]=null}else{if(Dygraph.isArrayLike(d[a])){b[a]=d[a].slice()}else{if(c(d[a])){b[a]=d[a]}else{if(typeof(d[a])=="object"){if(typeof(b[a])!="object"||b[a]===null){b[a]={}}Dygraph.updateDeep(b[a],d[a])}else{b[a]=d[a]}}}}}}}return b};Dygraph.isArrayLike=function(b){var a=typeof(b);if((a!="object"&&!(a=="function"&&typeof(b.item)=="function"))||b===null||typeof(b.length)!="number"||b.nodeType===3){return false}return true};Dygraph.isDateLike=function(a){if(typeof(a)!="object"||a===null||typeof(a.getTime)!="function"){return false}return true};Dygraph.clone=function(c){var b=[];for(var a=0;a<c.length;a++){if(Dygraph.isArrayLike(c[a])){b.push(Dygraph.clone(c[a]))}else{b.push(c[a])}}return b};Dygraph.createCanvas=function(){var a=document.createElement("canvas");var b=(/MSIE/.test(navigator.userAgent)&&!window.opera);if(b&&(typeof(G_vmlCanvasManager)!="undefined")){a=G_vmlCanvasManager.initElement((a))}return a};Dygraph.isAndroid=function(){return(/Android/).test(navigator.userAgent)};Dygraph.Iterator=function(d,c,b,a){c=c||0;b=b||d.length;this.hasNext=true;this.peek=null;this.start_=c;this.array_=d;this.predicate_=a;this.end_=Math.min(d.length,c+b);this.nextIdx_=c-1;this.next()};Dygraph.Iterator.prototype.next=function(){if(!this.hasNext){return null}var c=this.peek;var b=this.nextIdx_+1;var a=false;while(b<this.end_){if(!this.predicate_||this.predicate_(this.array_,b)){this.peek=this.array_[b];a=true;break}b++}this.nextIdx_=b;if(!a){this.hasNext=false;this.peek=null}return c};Dygraph.createIterator=function(d,c,b,a){return new Dygraph.Iterator(d,c,b,a)};Dygraph.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1000/60)}})();Dygraph.repeatAndCleanup=function(h,g,f,a){var i=0;var d;var b=new Date().getTime();h(i);if(g==1){a();return}var e=g-1;(function c(){if(i>=g){return}Dygraph.requestAnimFrame.call(window,function(){var l=new Date().getTime();var j=l-b;d=i;i=Math.floor(j/f);var k=i-d;var m=(i+k)>e;if(m||(i>=e)){h(e);a()}else{if(k!=0){h(i)}c()}})})()};Dygraph.isPixelChangingOptionList=function(h,e){var d={annotationClickHandler:true,annotationDblClickHandler:true,annotationMouseOutHandler:true,annotationMouseOverHandler:true,axisLabelColor:true,axisLineColor:true,axisLineWidth:true,clickCallback:true,digitsAfterDecimal:true,drawCallback:true,drawHighlightPointCallback:true,drawPoints:true,drawPointCallback:true,drawXGrid:true,drawYGrid:true,fillAlpha:true,gridLineColor:true,gridLineWidth:true,hideOverlayOnMouseOut:true,highlightCallback:true,highlightCircleSize:true,interactionModel:true,isZoomedIgnoreProgrammaticZoom:true,labelsDiv:true,labelsDivStyles:true,labelsDivWidth:true,labelsKMB:true,labelsKMG2:true,labelsSeparateLines:true,labelsShowZeroValues:true,legend:true,maxNumberWidth:true,panEdgeFraction:true,pixelsPerYLabel:true,pointClickCallback:true,pointSize:true,rangeSelectorPlotFillColor:true,rangeSelectorPlotStrokeColor:true,showLabelsOnHighlight:true,showRoller:true,sigFigs:true,strokeWidth:true,underlayCallback:true,unhighlightCallback:true,xAxisLabelFormatter:true,xTicker:true,xValueFormatter:true,yAxisLabelFormatter:true,yValueFormatter:true,zoomCallback:true};var a=false;var b={};if(h){for(var f=1;f<h.length;f++){b[h[f]]=true}}for(var g in e){if(a){break}if(e.hasOwnProperty(g)){if(b[g]){for(var c in e[g]){if(a){break}if(e[g].hasOwnProperty(c)&&!d[c]){a=true}}}else{if(!d[g]){a=true}}}}return a};Dygraph.compareArrays=function(c,b){if(!Dygraph.isArrayLike(c)||!Dygraph.isArrayLike(b)){return false}if(c.length!==b.length){return false}for(var a=0;a<c.length;a++){if(c[a]!==b[a]){return false}}return true};Dygraph.regularShape_=function(p,c,j,f,e,a,o){a=a||0;o=o||Math.PI*2/c;p.beginPath();var h=true;var g=a;var d=g;var i=function(){var q=f+(Math.sin(d)*j);var r=e+(-Math.cos(d)*j);return[q,r]};var b=i();var m=b[0];var k=b[1];p.moveTo(m,k);for(var n=0;n<c;n++){d=(n==c-1)?g:(d+o);var l=i();p.lineTo(l[0],l[1])}p.fill();p.stroke()};Dygraph.shapeFunction_=function(b,a,c){return function(j,i,f,e,k,h,d){f.strokeStyle=h;f.fillStyle="white";Dygraph.regularShape_(f,b,d,e,k,a,c)}};Dygraph.Circles={DEFAULT:function(h,f,b,e,d,c,a){b.beginPath();b.fillStyle=c;b.arc(e,d,a,0,2*Math.PI,false);b.fill()},TRIANGLE:Dygraph.shapeFunction_(3),SQUARE:Dygraph.shapeFunction_(4,Math.PI/4),DIAMOND:Dygraph.shapeFunction_(4),PENTAGON:Dygraph.shapeFunction_(5),HEXAGON:Dygraph.shapeFunction_(6),CIRCLE:function(f,e,c,b,h,d,a){c.beginPath();c.strokeStyle=d;c.fillStyle="white";c.arc(b,h,a,0,2*Math.PI,false);c.fill();c.stroke()},STAR:Dygraph.shapeFunction_(5,0,4*Math.PI/5),PLUS:function(f,e,c,b,h,d,a){c.strokeStyle=d;c.beginPath();c.moveTo(b+a,h);c.lineTo(b-a,h);c.closePath();c.stroke();c.beginPath();c.moveTo(b,h+a);c.lineTo(b,h-a);c.closePath();c.stroke()},EX:function(f,e,c,b,h,d,a){c.strokeStyle=d;c.beginPath();c.moveTo(b+a,h+a);c.lineTo(b-a,h-a);c.closePath();c.stroke();c.beginPath();c.moveTo(b+a,h-a);c.lineTo(b-a,h+a);c.closePath();c.stroke()}};Dygraph.IFrameTarp=function(){this.tarps=[]};Dygraph.IFrameTarp.prototype.cover=function(){var f=document.getElementsByTagName("iframe");for(var c=0;c<f.length;c++){var e=f[c];var b=Dygraph.findPosX(e),h=Dygraph.findPosY(e),d=e.offsetWidth,a=e.offsetHeight;var g=document.createElement("div");g.style.position="absolute";g.style.left=b+"px";g.style.top=h+"px";g.style.width=d+"px";g.style.height=a+"px";g.style.zIndex=999;document.body.appendChild(g);this.tarps.push(g)}};Dygraph.IFrameTarp.prototype.uncover=function(){for(var a=0;a<this.tarps.length;a++){this.tarps[a].parentNode.removeChild(this.tarps[a])}this.tarps=[]};Dygraph.detectLineDelimiter=function(c){for(var a=0;a<c.length;a++){var b=c.charAt(a);if(b==="\r"){if(((a+1)<c.length)&&(c.charAt(a+1)==="\n")){return"\r\n"}return b}if(b==="\n"){if(((a+1)<c.length)&&(c.charAt(a+1)==="\r")){return"\n\r"}return b}}return null};"use strict";Dygraph.GVizChart=function(a){this.container=a};Dygraph.GVizChart.prototype.draw=function(b,a){this.container.innerHTML="";if(typeof(this.date_graph)!="undefined"){this.date_graph.destroy()}this.date_graph=new Dygraph(this.container,b,a)};Dygraph.GVizChart.prototype.setSelection=function(b){var a=false;if(b.length){a=b[0].row}this.date_graph.setSelection(a)};Dygraph.GVizChart.prototype.getSelection=function(){var b=[];var d=this.date_graph.getSelection();if(d<0){return b}var a=this.date_graph.layout_.datasets;for(var c=0;c<a.length;++c){b.push({row:d,column:c+1})}return b};"use strict";Dygraph.Interaction={};Dygraph.Interaction.startPan=function(o,t,c){var r,b;c.isPanning=true;var k=t.xAxisRange();c.dateRange=k[1]-k[0];c.initialLeftmostDate=k[0];c.xUnitsPerPixel=c.dateRange/(t.plotter_.area.w-1);if(t.attr_("panEdgeFraction")){var x=t.width_*t.attr_("panEdgeFraction");var d=t.xAxisExtremes();var j=t.toDomXCoord(d[0])-x;var l=t.toDomXCoord(d[1])+x;var u=t.toDataXCoord(j);var w=t.toDataXCoord(l);c.boundedDates=[u,w];var f=[];var a=t.height_*t.attr_("panEdgeFraction");for(r=0;r<t.axes_.length;r++){b=t.axes_[r];var p=b.extremeRange;var q=t.toDomYCoord(p[0],r)+a;var s=t.toDomYCoord(p[1],r)-a;var n=t.toDataYCoord(q);var e=t.toDataYCoord(s);f[r]=[n,e]}c.boundedValues=f}c.is2DPan=false;c.axes=[];for(r=0;r<t.axes_.length;r++){b=t.axes_[r];var h={};var m=t.yAxisRange(r);var v=t.attributes_.getForAxis("logscale",r);if(v){h.initialTopValue=Dygraph.log10(m[1]);h.dragValueRange=Dygraph.log10(m[1])-Dygraph.log10(m[0])}else{h.initialTopValue=m[1];h.dragValueRange=m[1]-m[0]}h.unitsPerPixel=h.dragValueRange/(t.plotter_.area.h-1);c.axes.push(h);if(b.valueWindow||b.valueRange){c.is2DPan=true}}};Dygraph.Interaction.movePan=function(b,k,c){c.dragEndX=k.dragGetX_(b,c);c.dragEndY=k.dragGetY_(b,c);var h=c.initialLeftmostDate-(c.dragEndX-c.dragStartX)*c.xUnitsPerPixel;if(c.boundedDates){h=Math.max(h,c.boundedDates[0])}var a=h+c.dateRange;if(c.boundedDates){if(a>c.boundedDates[1]){h=h-(a-c.boundedDates[1]);a=h+c.dateRange}}k.dateWindow_=[h,a];if(c.is2DPan){for(var j=0;j<k.axes_.length;j++){var e=k.axes_[j];var o=c.axes[j];var d=c.dragEndY-c.dragStartY;var p=d*o.unitsPerPixel;var f=c.boundedValues?c.boundedValues[j]:null;var l=o.initialTopValue+p;if(f){l=Math.min(l,f[1])}var n=l-o.dragValueRange;if(f){if(n<f[0]){l=l-(n-f[0]);n=l-o.dragValueRange}}var m=k.attributes_.getForAxis("logscale",j);if(m){e.valueWindow=[Math.pow(Dygraph.LOG_SCALE,n),Math.pow(Dygraph.LOG_SCALE,l)]}else{e.valueWindow=[n,l]}}}k.drawGraph_(false)};Dygraph.Interaction.endPan=function(c,b,a){a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}a.isPanning=false;a.is2DPan=false;a.initialLeftmostDate=null;a.dateRange=null;a.valueRange=null;a.boundedDates=null;a.boundedValues=null;a.axes=null};Dygraph.Interaction.startZoom=function(c,b,a){a.isZooming=true;a.zoomMoved=false};Dygraph.Interaction.moveZoom=function(c,b,a){a.zoomMoved=true;a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragStartX-a.dragEndX);var d=Math.abs(a.dragStartY-a.dragEndY);a.dragDirection=(e<d/2)?Dygraph.VERTICAL:Dygraph.HORIZONTAL;b.drawZoomRect_(a.dragDirection,a.dragStartX,a.dragEndX,a.dragStartY,a.dragEndY,a.prevDragDirection,a.prevEndX,a.prevEndY);a.prevEndX=a.dragEndX;a.prevEndY=a.dragEndY;a.prevDragDirection=a.dragDirection};Dygraph.Interaction.treatMouseOpAsClick=function(f,b,d){var k=f.attr_("clickCallback");var n=f.attr_("pointClickCallback");var j=null;if(n){var l=-1;var m=Number.MAX_VALUE;for(var e=0;e<f.selPoints_.length;e++){var c=f.selPoints_[e];var a=Math.pow(c.canvasx-d.dragEndX,2)+Math.pow(c.canvasy-d.dragEndY,2);if(!isNaN(a)&&(l==-1||a<m)){m=a;l=e}}var h=f.attr_("highlightCircleSize")+2;if(m<=h*h){j=f.selPoints_[l]}}if(j){n(b,j)}if(k){k(b,f.lastx_,f.selPoints_)}};Dygraph.Interaction.endZoom=function(c,b,a){a.isZooming=false;a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}if(e>=10&&a.dragDirection==Dygraph.HORIZONTAL){b.doZoomX_(Math.min(a.dragStartX,a.dragEndX),Math.max(a.dragStartX,a.dragEndX));a.cancelNextDblclick=true}else{if(d>=10&&a.dragDirection==Dygraph.VERTICAL){b.doZoomY_(Math.min(a.dragStartY,a.dragEndY),Math.max(a.dragStartY,a.dragEndY));a.cancelNextDblclick=true}else{if(a.zoomMoved){b.clearZoomRect_()}}}a.dragStartX=null;a.dragStartY=null};Dygraph.Interaction.startTouch=function(f,e,d){f.preventDefault();var h=[];for(var c=0;c<f.touches.length;c++){var b=f.touches[c];h.push({pageX:b.pageX,pageY:b.pageY,dataX:e.toDataXCoord(b.pageX),dataY:e.toDataYCoord(b.pageY)})}d.initialTouches=h;if(h.length==1){d.initialPinchCenter=h[0];d.touchDirections={x:true,y:true}}else{if(h.length==2){d.initialPinchCenter={pageX:0.5*(h[0].pageX+h[1].pageX),pageY:0.5*(h[0].pageY+h[1].pageY),dataX:0.5*(h[0].dataX+h[1].dataX),dataY:0.5*(h[0].dataY+h[1].dataY)};var a=180/Math.PI*Math.atan2(d.initialPinchCenter.pageY-h[0].pageY,h[0].pageX-d.initialPinchCenter.pageX);a=Math.abs(a);if(a>90){a=90-a}d.touchDirections={x:(a<(90-45/2)),y:(a>45/2)}}}d.initialRange={x:e.xAxisRange(),y:e.yAxisRange()}};Dygraph.Interaction.moveTouch=function(n,q,d){var p,l=[];for(p=0;p<n.touches.length;p++){var k=n.touches[p];l.push({pageX:k.pageX,pageY:k.pageY})}var a=d.initialTouches;var h;var j=d.initialPinchCenter;if(l.length==1){h=l[0]}else{h={pageX:0.5*(l[0].pageX+l[1].pageX),pageY:0.5*(l[0].pageY+l[1].pageY)}}var m={pageX:h.pageX-j.pageX,pageY:h.pageY-j.pageY};var f=d.initialRange.x[1]-d.initialRange.x[0];var o=d.initialRange.y[0]-d.initialRange.y[1];m.dataX=(m.pageX/q.plotter_.area.w)*f;m.dataY=(m.pageY/q.plotter_.area.h)*o;var u,c;if(l.length==1){u=1;c=1}else{if(l.length==2){var e=(a[1].pageX-j.pageX);u=(l[1].pageX-h.pageX)/e;var s=(a[1].pageY-j.pageY);c=(l[1].pageY-h.pageY)/s}}u=Math.min(8,Math.max(0.125,u));c=Math.min(8,Math.max(0.125,c));if(d.touchDirections.x){q.dateWindow_=[j.dataX-m.dataX+(d.initialRange.x[0]-j.dataX)/u,j.dataX-m.dataX+(d.initialRange.x[1]-j.dataX)/u]}if(d.touchDirections.y){for(p=0;p<1;p++){var b=q.axes_[p];var r=q.attributes_.getForAxis("logscale",p);if(r){}else{b.valueWindow=[j.dataY-m.dataY+(d.initialRange.y[0]-j.dataY)/c,j.dataY-m.dataY+(d.initialRange.y[1]-j.dataY)/c]}}}q.drawGraph_(false)};Dygraph.Interaction.endTouch=function(c,b,a){if(c.touches.length!==0){Dygraph.Interaction.startTouch(c,b,a)}};Dygraph.Interaction.defaultModel={mousedown:function(c,b,a){if(c.button&&c.button==2){return}a.initializeMouseDown(c,b,a);if(c.altKey||c.shiftKey){Dygraph.startPan(c,b,a)}else{Dygraph.startZoom(c,b,a)}},mousemove:function(c,b,a){if(a.isZooming){Dygraph.moveZoom(c,b,a)}else{if(a.isPanning){Dygraph.movePan(c,b,a)}}},mouseup:function(c,b,a){if(a.isZooming){Dygraph.endZoom(c,b,a)}else{if(a.isPanning){Dygraph.endPan(c,b,a)}}},touchstart:function(c,b,a){Dygraph.Interaction.startTouch(c,b,a)},touchmove:function(c,b,a){Dygraph.Interaction.moveTouch(c,b,a)},touchend:function(c,b,a){Dygraph.Interaction.endTouch(c,b,a)},mouseout:function(c,b,a){if(a.isZooming){a.dragEndX=null;a.dragEndY=null}},dblclick:function(c,b,a){if(a.cancelNextDblclick){a.cancelNextDblclick=false;return}if(c.altKey||c.shiftKey){return}b.resetZoom()}};Dygraph.DEFAULT_ATTRS.interactionModel=Dygraph.Interaction.defaultModel;Dygraph.defaultInteractionModel=Dygraph.Interaction.defaultModel;Dygraph.endZoom=Dygraph.Interaction.endZoom;Dygraph.moveZoom=Dygraph.Interaction.moveZoom;Dygraph.startZoom=Dygraph.Interaction.startZoom;Dygraph.endPan=Dygraph.Interaction.endPan;Dygraph.movePan=Dygraph.Interaction.movePan;Dygraph.startPan=Dygraph.Interaction.startPan;Dygraph.Interaction.nonInteractiveModel_={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a)},mouseup:function(c,b,a){a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}}};Dygraph.Interaction.dragIsPanInteractionModel={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a);Dygraph.startPan(c,b,a)},mousemove:function(c,b,a){if(a.isPanning){Dygraph.movePan(c,b,a)}},mouseup:function(c,b,a){if(a.isPanning){Dygraph.endPan(c,b,a)}}};"use strict";var DygraphRangeSelector=function(a){this.isIE_=/MSIE/.test(navigator.userAgent)&&!window.opera;this.isUsingExcanvas_=a.isUsingExcanvas_;this.dygraph_=a;this.hasTouchInterface_=typeof(TouchEvent)!="undefined";this.isMobileDevice_=/mobile|android/gi.test(navigator.appVersion);this.createCanvases_();if(this.isUsingExcanvas_){this.createIEPanOverlay_()}this.createZoomHandles_();this.initInteraction_()};DygraphRangeSelector.prototype.addToGraph=function(a,b){this.layout_=b;this.resize_();a.appendChild(this.bgcanvas_);a.appendChild(this.fgcanvas_);a.appendChild(this.leftZoomHandle_);a.appendChild(this.rightZoomHandle_)};DygraphRangeSelector.prototype.renderStaticLayer=function(){this.resize_();this.drawStaticLayer_()};DygraphRangeSelector.prototype.renderInteractiveLayer=function(){if(this.isChangingRange_){return}this.placeZoomHandles_();this.drawInteractiveLayer_()};DygraphRangeSelector.prototype.resize_=function(){function c(d,e){d.style.top=e.y+"px";d.style.left=e.x+"px";d.width=e.w;d.height=e.h;d.style.width=d.width+"px";d.style.height=d.height+"px"}var b=this.layout_.getPlotArea();var a=this.attr_("xAxisHeight")||(this.attr_("axisLabelFontSize")+2*this.attr_("axisTickSize"));this.canvasRect_={x:b.x,y:b.y+b.h+a+4,w:b.w,h:this.attr_("rangeSelectorHeight")};c(this.bgcanvas_,this.canvasRect_);c(this.fgcanvas_,this.canvasRect_)};DygraphRangeSelector.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphRangeSelector.prototype.createCanvases_=function(){this.bgcanvas_=Dygraph.createCanvas();this.bgcanvas_.className="dygraph-rangesel-bgcanvas";this.bgcanvas_.style.position="absolute";this.bgcanvas_.style.zIndex=9;this.bgcanvas_ctx_=Dygraph.getContext(this.bgcanvas_);this.fgcanvas_=Dygraph.createCanvas();this.fgcanvas_.className="dygraph-rangesel-fgcanvas";this.fgcanvas_.style.position="absolute";this.fgcanvas_.style.zIndex=9;this.fgcanvas_.style.cursor="default";this.fgcanvas_ctx_=Dygraph.getContext(this.fgcanvas_)};DygraphRangeSelector.prototype.createIEPanOverlay_=function(){this.iePanOverlay_=document.createElement("div");this.iePanOverlay_.style.position="absolute";this.iePanOverlay_.style.backgroundColor="white";this.iePanOverlay_.style.filter="alpha(opacity=0)";this.iePanOverlay_.style.display="none";this.iePanOverlay_.style.cursor="move";this.fgcanvas_.appendChild(this.iePanOverlay_)};DygraphRangeSelector.prototype.createZoomHandles_=function(){var a=new Image();a.className="dygraph-rangesel-zoomhandle";a.style.position="absolute";a.style.zIndex=10;a.style.visibility="hidden";a.style.cursor="col-resize";if(/MSIE 7/.test(navigator.userAgent)){a.width=7;a.height=14;a.style.backgroundColor="white";a.style.border="1px solid #333333"}else{a.width=9;a.height=16;a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAAXNSR0IArs4c6QAAAAZiS0dEANAAzwDP4Z7KegAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sHGw0cMqdt1UwAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAaElEQVQoz+3SsRFAQBCF4Z9WJM8KCDVwownl6YXsTmCUsyKGkZzcl7zkz3YLkypgAnreFmDEpHkIwVOMfpdi9CEEN2nGpFdwD03yEqDtOgCaun7sqSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII="}if(this.isMobileDevice_){a.width*=2;a.height*=2}this.leftZoomHandle_=a;this.rightZoomHandle_=a.cloneNode(false)};DygraphRangeSelector.prototype.initInteraction_=function(){var o=this;var h=this.isIE_?document:window;var q=0;var v=null;var t=false;var c=false;var f=!this.isMobileDevice_&&!this.isUsingExcanvas_;var k=new Dygraph.IFrameTarp();var p,e,s,i,w,g,x,u,r,b,n,j;var d,m,l;p=function(C){var B=o.dygraph_.xAxisExtremes();var z=(B[1]-B[0])/o.canvasRect_.w;var A=B[0]+(C.leftHandlePos-o.canvasRect_.x)*z;var y=B[0]+(C.rightHandlePos-o.canvasRect_.x)*z;return[A,y]};j=function(z){var y=window.outerWidth/document.documentElement.clientWidth;if(!isNaN(y)){return z/y}else{return z}};e=function(y){Dygraph.cancelEvent(y);t=true;q=y.screenX;v=y.target?y.target:y.srcElement;o.dygraph_.addEvent(h,"mousemove",s);o.dygraph_.addEvent(h,"mouseup",i);o.fgcanvas_.style.cursor="col-resize";k.cover();return true};s=function(C){if(!t){return false}Dygraph.cancelEvent(C);var z=C.screenX-q;if(Math.abs(z)<4||C.screenX===0){return true}q=C.screenX;z=j(z);var B=o.getZoomHandleStatus_();var y;if(v==o.leftZoomHandle_){y=B.leftHandlePos+z;y=Math.min(y,B.rightHandlePos-v.width-3);y=Math.max(y,o.canvasRect_.x)}else{y=B.rightHandlePos+z;y=Math.min(y,o.canvasRect_.x+o.canvasRect_.w);y=Math.max(y,B.leftHandlePos+v.width+3)}var A=v.width/2;v.style.left=(y-A)+"px";o.drawInteractiveLayer_();if(f){w()}return true};i=function(y){if(!t){return false}t=false;k.uncover();Dygraph.removeEvent(h,"mousemove",s);Dygraph.removeEvent(h,"mouseup",i);o.fgcanvas_.style.cursor="default";if(!f){w()}return true};w=function(){try{var z=o.getZoomHandleStatus_();o.isChangingRange_=true;if(!z.isZoomed){o.dygraph_.resetZoom()}else{var y=p(z);o.dygraph_.doZoomXDates_(y[0],y[1])}}finally{o.isChangingRange_=false}};g=function(A){if(o.isUsingExcanvas_){return A.srcElement==o.iePanOverlay_}else{var z=o.leftZoomHandle_.getBoundingClientRect();var y=z.left+z.width/2;z=o.rightZoomHandle_.getBoundingClientRect();var B=z.left+z.width/2;return(A.clientX>y&&A.clientX<B)}};x=function(y){if(!c&&g(y)&&o.getZoomHandleStatus_().isZoomed){Dygraph.cancelEvent(y);c=true;q=y.screenX;o.dygraph_.addEvent(h,"mousemove",u);o.dygraph_.addEvent(h,"mouseup",r);return true}return false};u=function(C){if(!c){return false}Dygraph.cancelEvent(C);var z=C.screenX-q;if(Math.abs(z)<4){return true}q=C.screenX;z=j(z);var B=o.getZoomHandleStatus_();var E=B.leftHandlePos;var y=B.rightHandlePos;var D=y-E;if(E+z<=o.canvasRect_.x){E=o.canvasRect_.x;y=E+D}else{if(y+z>=o.canvasRect_.x+o.canvasRect_.w){y=o.canvasRect_.x+o.canvasRect_.w;E=y-D}else{E+=z;y+=z}}var A=o.leftZoomHandle_.width/2;o.leftZoomHandle_.style.left=(E-A)+"px";o.rightZoomHandle_.style.left=(y-A)+"px";o.drawInteractiveLayer_();if(f){b()}return true};r=function(y){if(!c){return false}c=false;Dygraph.removeEvent(h,"mousemove",u);Dygraph.removeEvent(h,"mouseup",r);if(!f){b()}return true};b=function(){try{o.isChangingRange_=true;o.dygraph_.dateWindow_=p(o.getZoomHandleStatus_());o.dygraph_.drawGraph_(false)}finally{o.isChangingRange_=false}};n=function(y){if(t||c){return}var z=g(y)?"move":"default";if(z!=o.fgcanvas_.style.cursor){o.fgcanvas_.style.cursor=z}};d=function(y){if(y.type=="touchstart"&&y.targetTouches.length==1){if(e(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{if(y.type=="touchmove"&&y.targetTouches.length==1){if(s(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{i(y)}}};m=function(y){if(y.type=="touchstart"&&y.targetTouches.length==1){if(x(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{if(y.type=="touchmove"&&y.targetTouches.length==1){if(u(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{r(y)}}};l=function(B,A){var z=["touchstart","touchend","touchmove","touchcancel"];for(var y=0;y<z.length;y++){o.dygraph_.addEvent(B,z[y],A)}};this.dygraph_.attrs_.interactionModel=Dygraph.Interaction.dragIsPanInteractionModel;this.dygraph_.attrs_.panEdgeFraction=0.0001;var a=window.opera?"mousedown":"dragstart";this.dygraph_.addEvent(this.leftZoomHandle_,a,e);this.dygraph_.addEvent(this.rightZoomHandle_,a,e);if(this.isUsingExcanvas_){this.dygraph_.addEvent(this.iePanOverlay_,"mousedown",x)}else{this.dygraph_.addEvent(this.fgcanvas_,"mousedown",x);this.dygraph_.addEvent(this.fgcanvas_,"mousemove",n)}if(this.hasTouchInterface_){l(this.leftZoomHandle_,d);l(this.rightZoomHandle_,d);l(this.fgcanvas_,m)}};DygraphRangeSelector.prototype.drawStaticLayer_=function(){var a=this.bgcanvas_ctx_;a.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);try{this.drawMiniPlot_()}catch(b){Dygraph.warn(b)}var c=0.5;this.bgcanvas_ctx_.lineWidth=1;a.strokeStyle="gray";a.beginPath();a.moveTo(c,c);a.lineTo(c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,c);a.stroke()};DygraphRangeSelector.prototype.drawMiniPlot_=function(){var e=this.attr_("rangeSelectorPlotFillColor");var q=this.attr_("rangeSelectorPlotStrokeColor");if(!e&&!q){return}var h=this.attr_("stepPlot");var u=this.computeCombinedSeriesAndLimits_();var p=u.yMax-u.yMin;var o=this.bgcanvas_ctx_;var m=0.5;var d=this.dygraph_.xAxisExtremes();var n=Math.max(d[1]-d[0],1e-30);var f=(this.canvasRect_.w-m)/n;var t=(this.canvasRect_.h-m)/p;var s=this.canvasRect_.w-m;var a=this.canvasRect_.h-m;var c=null,b=null;o.beginPath();o.moveTo(m,a);for(var r=0;r<u.data.length;r++){var g=u.data[r];var k=((g[0]!==null)?((g[0]-d[0])*f):NaN);var j=((g[1]!==null)?(a-(g[1]-u.yMin)*t):NaN);if(isFinite(k)&&isFinite(j)){if(c===null){o.lineTo(k,a)}else{if(h){o.lineTo(k,b)}}o.lineTo(k,j);c=k;b=j}else{if(c!==null){if(h){o.lineTo(k,b);o.lineTo(k,a)}else{o.lineTo(c,a)}}c=b=null}}o.lineTo(s,a);o.closePath();if(e){var l=this.bgcanvas_ctx_.createLinearGradient(0,0,0,a);l.addColorStop(0,"white");l.addColorStop(1,e);this.bgcanvas_ctx_.fillStyle=l;o.fill()}if(q){this.bgcanvas_ctx_.strokeStyle=q;this.bgcanvas_ctx_.lineWidth=1.5;o.stroke()}};DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_=function(){var u=this.dygraph_.rawData_;var t=this.attr_("logscale");var p=[];var c;var g;var l;var s,r,q;var d,f;for(s=0;s<u.length;s++){if(u[s].length>1&&u[s][1]!==null){l=typeof u[s][1]!="number";if(l){c=[];g=[];for(q=0;q<u[s][1].length;q++){c.push(0);g.push(0)}}break}}for(s=0;s<u.length;s++){var h=u[s];d=h[0];if(l){for(q=0;q<c.length;q++){c[q]=g[q]=0}}else{c=g=0}for(r=1;r<h.length;r++){if(this.dygraph_.visibility()[r-1]){var m;if(l){for(q=0;q<c.length;q++){m=h[r][q];if(m===null||isNaN(m)){continue}c[q]+=m;g[q]++}}else{m=h[r];if(m===null||isNaN(m)){continue}c+=m;g++}}}if(l){for(q=0;q<c.length;q++){c[q]/=g[q]}f=c.slice(0)}else{f=c/g}p.push([d,f])}p=this.dygraph_.rollingAverage(p,this.dygraph_.rollPeriod_);if(typeof p[0][1]!="number"){for(s=0;s<p.length;s++){f=p[s][1];p[s][1]=f[0]}}var a=Number.MAX_VALUE;var b=-Number.MAX_VALUE;for(s=0;s<p.length;s++){f=p[s][1];if(f!==null&&isFinite(f)&&(!t||f>0)){a=Math.min(a,f);b=Math.max(b,f)}}var n=0.25;if(t){b=Dygraph.log10(b);b+=b*n;a=Dygraph.log10(a);for(s=0;s<p.length;s++){p[s][1]=Dygraph.log10(p[s][1])}}else{var e;var o=b-a;if(o<=Number.MIN_VALUE){e=b*n}else{e=o*n}b+=e;a-=e}return{data:p,yMin:a,yMax:b}};DygraphRangeSelector.prototype.placeZoomHandles_=function(){var g=this.dygraph_.xAxisExtremes();var a=this.dygraph_.xAxisRange();var b=g[1]-g[0];var i=Math.max(0,(a[0]-g[0])/b);var e=Math.max(0,(g[1]-a[1])/b);var h=this.canvasRect_.x+this.canvasRect_.w*i;var d=this.canvasRect_.x+this.canvasRect_.w*(1-e);var c=Math.max(this.canvasRect_.y,this.canvasRect_.y+(this.canvasRect_.h-this.leftZoomHandle_.height)/2);var f=this.leftZoomHandle_.width/2;this.leftZoomHandle_.style.left=(h-f)+"px";this.leftZoomHandle_.style.top=c+"px";this.rightZoomHandle_.style.left=(d-f)+"px";this.rightZoomHandle_.style.top=this.leftZoomHandle_.style.top;this.leftZoomHandle_.style.visibility="visible";this.rightZoomHandle_.style.visibility="visible"};DygraphRangeSelector.prototype.drawInteractiveLayer_=function(){var b=this.fgcanvas_ctx_;b.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);var e=1;var d=this.canvasRect_.w-e;var a=this.canvasRect_.h-e;var g=this.getZoomHandleStatus_();b.strokeStyle="black";if(!g.isZoomed){b.beginPath();b.moveTo(e,e);b.lineTo(e,a);b.lineTo(d,a);b.lineTo(d,e);b.stroke();if(this.iePanOverlay_){this.iePanOverlay_.style.display="none"}}else{var f=Math.max(e,g.leftHandlePos-this.canvasRect_.x);var c=Math.min(d,g.rightHandlePos-this.canvasRect_.x);b.fillStyle="rgba(240, 240, 240, 0.6)";b.fillRect(0,0,f,this.canvasRect_.h);b.fillRect(c,0,this.canvasRect_.w-c,this.canvasRect_.h);b.beginPath();b.moveTo(e,e);b.lineTo(f,e);b.lineTo(f,a);b.lineTo(c,a);b.lineTo(c,e);b.lineTo(d,e);b.stroke();if(this.isUsingExcanvas_){this.iePanOverlay_.style.width=(c-f)+"px";this.iePanOverlay_.style.left=f+"px";this.iePanOverlay_.style.height=a+"px";this.iePanOverlay_.style.display="inline"}}};DygraphRangeSelector.prototype.getZoomHandleStatus_=function(){var b=this.leftZoomHandle_.width/2;var c=parseInt(this.leftZoomHandle_.style.left,10)+b;var a=parseInt(this.rightZoomHandle_.style.left,10)+b;return{leftHandlePos:c,rightHandlePos:a,isZoomed:(c-1>this.canvasRect_.x||a+1<this.canvasRect_.x+this.canvasRect_.w)}};"use strict";Dygraph.TickList;Dygraph.Ticker;Dygraph.numericLinearTicks=function(d,c,i,g,f,h){var e=function(a){if(a==="logscale"){return false}return g(a)};return Dygraph.numericTicks(d,c,i,e,f,h)};Dygraph.numericTicks=function(S,R,p,w,u,F){var y=function(a,b){if(b<0){return 1/Math.pow(a,-b)}return Math.pow(a,b)};var d=(w("pixelsPerLabel"));var G=[];var N,L,h,q;if(F){for(N=0;N<F.length;N++){G.push({v:F[N]})}}else{if(w("logscale")){q=Math.floor(p/d);var r=Dygraph.binarySearch(S,Dygraph.PREFERRED_LOG_TICK_VALUES,1);var A=Dygraph.binarySearch(R,Dygraph.PREFERRED_LOG_TICK_VALUES,-1);if(r==-1){r=0}if(A==-1){A=Dygraph.PREFERRED_LOG_TICK_VALUES.length-1}var H=null;if(A-r>=q/4){for(var Q=A;Q>=r;Q--){var D=Dygraph.PREFERRED_LOG_TICK_VALUES[Q];var s=Math.log(D/S)/Math.log(R/S)*p;var e={v:D};if(H===null){H={tickValue:D,pixel_coord:s}}else{if(Math.abs(s-H.pixel_coord)>=d){H={tickValue:D,pixel_coord:s}}else{e.label=""}}G.push(e)}G.reverse()}}if(G.length===0){var o=w("labelsKMG2");var C,t;if(o){C=[1,2,4,8,16,32,64,128,256];t=16}else{C=[1,2,5,10,20,50,100];t=10}var l=Math.ceil(p/d);var O=Math.abs(R-S)/l;var P=Math.floor(Math.log(O)/Math.log(t));var z=Math.pow(t,P);var B,x,E,q,g;for(L=0;L<C.length;L++){B=z*C[L];x=Math.floor(S/B)*B;E=Math.ceil(R/B)*B;q=Math.abs(E-x)/B;g=p/q;if(g>d){break}}if(x>E){B*=-1}for(N=0;N<q;N++){h=x+N*B;G.push({v:h})}}}var K;var M=[];var f=[];if(w("labelsKMB")){K=1000;M=["K","M","B","T","Q"]}if(w("labelsKMG2")){if(K){Dygraph.warn("Setting both labelsKMB and labelsKMG2. Pick one!")}K=1024;M=["k","M","G","T","P","E","Z","Y"];f=["m","u","n","p","f","a","z","y"]}K=K||1;var m=(w("axisLabelFormatter"));var v=(w("digitsAfterDecimal"));for(N=0;N<G.length;N++){if(G[N].label!==undefined){continue}h=G[N].v;var c=Math.abs(h);var I=m(h,0,w,u);if(M.length>0){var J=y(K,M.length);for(L=M.length-1;L>=0;L--,J/=K){if(c>=J){I=Dygraph.round_(h/J,v)+M[L];break}}}if(w("labelsKMG2")){h=String(h.toExponential());if(h.split("e-").length===2&&h.split("e-")[1]>=3&&h.split("e-")[1]<=24){if(h.split("e-")[1]%3>0){I=Dygraph.round_(h.split("e-")[0]/y(10,(h.split("e-")[1]%3)),v)}else{I=Number(h.split("e-")[0]).toFixed(2)}I+=f[Math.floor(h.split("e-")[1]/3)-1]}}G[N].label=I}return G};Dygraph.dateTicker=function(e,c,i,g,f,h){var d=Dygraph.pickDateTickGranularity(e,c,i,g);if(d>=0){return Dygraph.getDateAxis(e,c,d,g,f)}else{return[]}};Dygraph.SECONDLY=0;Dygraph.TWO_SECONDLY=1;Dygraph.FIVE_SECONDLY=2;Dygraph.TEN_SECONDLY=3;Dygraph.THIRTY_SECONDLY=4;Dygraph.MINUTELY=5;Dygraph.TWO_MINUTELY=6;Dygraph.FIVE_MINUTELY=7;Dygraph.TEN_MINUTELY=8;Dygraph.THIRTY_MINUTELY=9;Dygraph.HOURLY=10;Dygraph.TWO_HOURLY=11;Dygraph.SIX_HOURLY=12;Dygraph.DAILY=13;Dygraph.WEEKLY=14;Dygraph.MONTHLY=15;Dygraph.QUARTERLY=16;Dygraph.BIANNUAL=17;Dygraph.ANNUAL=18;Dygraph.DECADAL=19;Dygraph.CENTENNIAL=20;Dygraph.NUM_GRANULARITIES=21;Dygraph.SHORT_SPACINGS=[];Dygraph.SHORT_SPACINGS[Dygraph.SECONDLY]=1000*1;Dygraph.SHORT_SPACINGS[Dygraph.TWO_SECONDLY]=1000*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_SECONDLY]=1000*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_SECONDLY]=1000*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_SECONDLY]=1000*30;Dygraph.SHORT_SPACINGS[Dygraph.MINUTELY]=1000*60;Dygraph.SHORT_SPACINGS[Dygraph.TWO_MINUTELY]=1000*60*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_MINUTELY]=1000*60*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY]=1000*60*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY]=1000*60*30;Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=1000*3600;Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]=1000*3600*2;Dygraph.SHORT_SPACINGS[Dygraph.SIX_HOURLY]=1000*3600*6;Dygraph.SHORT_SPACINGS[Dygraph.DAILY]=1000*86400;Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY]=1000*604800;Dygraph.PREFERRED_LOG_TICK_VALUES=function(){var c=[];for(var b=-39;b<=39;b++){var a=Math.pow(10,b);for(var d=1;d<=9;d++){var e=a*d;c.push(e)}}return c}();Dygraph.pickDateTickGranularity=function(d,c,j,h){var g=(h("pixelsPerLabel"));for(var f=0;f<Dygraph.NUM_GRANULARITIES;f++){var e=Dygraph.numDateTicks(d,c,f);if(j/e>=g){return f}}return -1};Dygraph.numDateTicks=function(e,b,g){if(g<Dygraph.MONTHLY){var h=Dygraph.SHORT_SPACINGS[g];return Math.floor(0.5+1*(b-e)/h)}else{var f=1;var d=12;if(g==Dygraph.QUARTERLY){d=3}if(g==Dygraph.BIANNUAL){d=2}if(g==Dygraph.ANNUAL){d=1}if(g==Dygraph.DECADAL){d=1;f=10}if(g==Dygraph.CENTENNIAL){d=1;f=100}var c=365.2524*24*3600*1000;var a=1*(b-e)/c;return Math.floor(0.5+1*a*d/f)}};Dygraph.getDateAxis=function(n,h,a,l,w){var u=(l("axisLabelFormatter"));var z=[];var k;if(a<Dygraph.MONTHLY){var c=Dygraph.SHORT_SPACINGS[a];var v=c/1000;var y=new Date(n);y.setMilliseconds(0);var f;if(v<=60){f=y.getSeconds();y.setSeconds(f-f%v)}else{y.setSeconds(0);v/=60;if(v<=60){f=y.getMinutes();y.setMinutes(f-f%v)}else{y.setMinutes(0);v/=60;if(v<=24){f=y.getHours();y.setHours(f-f%v)}else{y.setHours(0);v/=24;if(v==7){y.setDate(y.getDate()-y.getDay())}}}}n=y.getTime();for(k=n;k<=h;k+=c){z.push({v:k,label:u(new Date(k),a,l,w)})}}else{var e;var o=1;if(a==Dygraph.MONTHLY){e=[0,1,2,3,4,5,6,7,8,9,10,11]}else{if(a==Dygraph.QUARTERLY){e=[0,3,6,9]}else{if(a==Dygraph.BIANNUAL){e=[0,6]}else{if(a==Dygraph.ANNUAL){e=[0]}else{if(a==Dygraph.DECADAL){e=[0];o=10}else{if(a==Dygraph.CENTENNIAL){e=[0];o=100}else{Dygraph.warn("Span of dates is too long")}}}}}}var s=new Date(n).getFullYear();var p=new Date(h).getFullYear();var b=Dygraph.zeropad;for(var r=s;r<=p;r++){if(r%o!==0){continue}for(var q=0;q<e.length;q++){var m=r+"/"+b(1+e[q])+"/01";k=Dygraph.dateStrToMillis(m);if(k<n||k>h){continue}z.push({v:k,label:u(new Date(k),a,l,w)})}}}return z};Dygraph.DEFAULT_ATTRS.axes["x"]["ticker"]=Dygraph.dateTicker;Dygraph.DEFAULT_ATTRS.axes["y"]["ticker"]=Dygraph.numericTicks;Dygraph.DEFAULT_ATTRS.axes["y2"]["ticker"]=Dygraph.numericTicks;Dygraph.Plugins={};Dygraph.Plugins.Annotations=(function(){var a=function(){this.annotations_=[]};a.prototype.toString=function(){return"Annotations Plugin"};a.prototype.activate=function(b){return{clearChart:this.clearChart,didDrawChart:this.didDrawChart}};a.prototype.detachLabels=function(){for(var c=0;c<this.annotations_.length;c++){var b=this.annotations_[c];if(b.parentNode){b.parentNode.removeChild(b)}this.annotations_[c]=null}this.annotations_=[]};a.prototype.clearChart=function(b){this.detachLabels()};a.prototype.didDrawChart=function(o){var m=o.dygraph;var t=m.layout_.annotated_points;if(!t||t.length===0){return}var q=o.canvas.parentNode;var l={position:"absolute",fontSize:m.getOption("axisLabelFontSize")+"px",zIndex:10,overflow:"hidden"};var n=function(e,g,i){return function(w){var p=i.annotation;if(p.hasOwnProperty(e)){p[e](p,i,m,w)}else{if(m.getOption(g)){m.getOption(g)(p,i,m,w)}}}};var h=o.dygraph.plotter_.area;for(var k=0;k<t.length;k++){var f=t[k];if(f.canvasx<h.x||f.canvasx>h.x+h.w||f.canvasy<h.y||f.canvasy>h.y+h.h){continue}var r=f.annotation;var s=6;if(r.hasOwnProperty("tickHeight")){s=r.tickHeight}var c=document.createElement("div");for(var b in l){if(l.hasOwnProperty(b)){c.style[b]=l[b]}}if(!r.hasOwnProperty("icon")){c.className="dygraphDefaultAnnotation"}if(r.hasOwnProperty("cssClass")){c.className+=" "+r.cssClass}var d=r.hasOwnProperty("width")?r.width:16;var u=r.hasOwnProperty("height")?r.height:16;if(r.hasOwnProperty("icon")){var j=document.createElement("img");j.src=r.icon;j.width=d;j.height=u;c.appendChild(j)}else{if(f.annotation.hasOwnProperty("shortText")){c.appendChild(document.createTextNode(f.annotation.shortText))}}c.style.left=(f.canvasx-d/2)+"px";if(r.attachAtBottom){c.style.top=(h.h-u-s)+"px"}else{c.style.top=(f.canvasy-u-s)+"px"}c.style.width=d+"px";c.style.height=u+"px";c.title=f.annotation.text;c.style.color=m.colorsMap_[f.name];c.style.borderColor=m.colorsMap_[f.name];r.div=c;m.addEvent(c,"click",n("clickHandler","annotationClickHandler",f,this));m.addEvent(c,"mouseover",n("mouseOverHandler","annotationMouseOverHandler",f,this));m.addEvent(c,"mouseout",n("mouseOutHandler","annotationMouseOutHandler",f,this));m.addEvent(c,"dblclick",n("dblClickHandler","annotationDblClickHandler",f,this));q.appendChild(c);this.annotations_.push(c);var v=o.drawingContext;v.save();v.strokeStyle=m.colorsMap_[f.name];v.beginPath();if(!r.attachAtBottom){v.moveTo(f.canvasx,f.canvasy);v.lineTo(f.canvasx,f.canvasy-2-s)}else{v.moveTo(f.canvasx,h.h);v.lineTo(f.canvasx,h.h-2-s)}v.closePath();v.stroke();v.restore()}};a.prototype.destroy=function(){this.detachLabels()};return a})();Dygraph.Plugins.Axes=(function(){var a=function(){this.xlabels_=[];this.ylabels_=[]};a.prototype.toString=function(){return"Axes Plugin"};a.prototype.activate=function(b){return{layout:this.layout,clearChart:this.clearChart,willDrawChart:this.willDrawChart}};a.prototype.layout=function(k){var j=k.dygraph;if(j.getOption("drawYAxis")){var b=j.getOption("yAxisLabelWidth")+2*j.getOption("axisTickSize");var i=k.reserveSpaceLeft(b)}if(j.getOption("drawXAxis")){var f;if(j.getOption("xAxisHeight")){f=j.getOption("xAxisHeight")}else{f=j.getOptionForAxis("axisLabelFontSize","x")+2*j.getOption("axisTickSize")}var c=k.reserveSpaceBottom(f)}if(j.numAxes()==2){var b=j.getOption("yAxisLabelWidth")+2*j.getOption("axisTickSize");var d=k.reserveSpaceRight(b)}else{if(j.numAxes()>2){j.error("Only two y-axes are supported at this time. (Trying to use "+j.numAxes()+")")}}};a.prototype.detachLabels=function(){function b(d){for(var c=0;c<d.length;c++){var e=d[c];if(e.parentNode){e.parentNode.removeChild(e)}}}b(this.xlabels_);b(this.ylabels_);this.xlabels_=[];this.ylabels_=[]};a.prototype.clearChart=function(c){var b=c.dygraph;this.detachLabels()};a.prototype.willDrawChart=function(H){var F=H.dygraph;if(!F.getOption("drawXAxis")&&!F.getOption("drawYAxis")){return}function B(e){return Math.round(e)+0.5}function A(e){return Math.round(e)-0.5}var j=H.drawingContext;var v=H.canvas.parentNode;var J=H.canvas.width;var d=H.canvas.height;var s,u,t,E,D;var C=function(e){return{position:"absolute",fontSize:F.getOptionForAxis("axisLabelFontSize",e)+"px",zIndex:10,color:F.getOptionForAxis("axisLabelColor",e),width:F.getOption("axisLabelWidth")+"px",lineHeight:"normal",overflow:"hidden"}};var p={x:C("x"),y:C("y"),y2:C("y2"),};var m=function(g,x,y){var K=document.createElement("div");var e=p[y=="y2"?"y2":x];for(var r in e){if(e.hasOwnProperty(r)){K.style[r]=e[r]}}var i=document.createElement("div");i.className="dygraph-axis-label dygraph-axis-label-"+x+(y?" dygraph-axis-label-"+y:"");i.innerHTML=g;K.appendChild(i);return K};j.save();var I=F.layout_;var G=H.dygraph.plotter_.area;if(F.getOption("drawYAxis")){if(I.yticks&&I.yticks.length>0){var h=F.numAxes();for(D=0;D<I.yticks.length;D++){E=I.yticks[D];if(typeof(E)=="function"){return}u=G.x;var o=1;var f="y1";if(E[0]==1){u=G.x+G.w;o=-1;f="y2"}var k=F.getOptionForAxis("axisLabelFontSize",f);t=G.y+E[1]*G.h;s=m(E[2],"y",h==2?f:null);var z=(t-k/2);if(z<0){z=0}if(z+k+3>d){s.style.bottom="0px"}else{s.style.top=z+"px"}if(E[0]===0){s.style.left=(G.x-F.getOption("yAxisLabelWidth")-F.getOption("axisTickSize"))+"px";s.style.textAlign="right"}else{if(E[0]==1){s.style.left=(G.x+G.w+F.getOption("axisTickSize"))+"px";s.style.textAlign="left"}}s.style.width=F.getOption("yAxisLabelWidth")+"px";v.appendChild(s);this.ylabels_.push(s)}var n=this.ylabels_[0];var k=F.getOptionForAxis("axisLabelFontSize","y");var q=parseInt(n.style.top,10)+k;if(q>d-k){n.style.top=(parseInt(n.style.top,10)-k/2)+"px"}}var c;if(F.getOption("drawAxesAtZero")){var w=F.toPercentXCoord(0);if(w>1||w<0){w=0}c=B(G.x+w*G.w)}else{c=B(G.x)}j.strokeStyle=F.getOptionForAxis("axisLineColor","y");j.lineWidth=F.getOptionForAxis("axisLineWidth","y");j.beginPath();j.moveTo(c,A(G.y));j.lineTo(c,A(G.y+G.h));j.closePath();j.stroke();if(F.numAxes()==2){j.strokeStyle=F.getOptionForAxis("axisLineColor","y2");j.lineWidth=F.getOptionForAxis("axisLineWidth","y2");j.beginPath();j.moveTo(A(G.x+G.w),A(G.y));j.lineTo(A(G.x+G.w),A(G.y+G.h));j.closePath();j.stroke()}}if(F.getOption("drawXAxis")){if(I.xticks){for(D=0;D<I.xticks.length;D++){E=I.xticks[D];u=G.x+E[0]*G.w;t=G.y+G.h;s=m(E[1],"x");s.style.textAlign="center";s.style.top=(t+F.getOption("axisTickSize"))+"px";var l=(u-F.getOption("axisLabelWidth")/2);if(l+F.getOption("axisLabelWidth")>J){l=J-F.getOption("xAxisLabelWidth");s.style.textAlign="right"}if(l<0){l=0;s.style.textAlign="left"}s.style.left=l+"px";s.style.width=F.getOption("xAxisLabelWidth")+"px";v.appendChild(s);this.xlabels_.push(s)}}j.strokeStyle=F.getOptionForAxis("axisLineColor","x");j.lineWidth=F.getOptionForAxis("axisLineWidth","x");j.beginPath();var b;if(F.getOption("drawAxesAtZero")){var w=F.toPercentYCoord(0,0);if(w>1||w<0){w=1}b=A(G.y+w*G.h)}else{b=A(G.y+G.h)}j.moveTo(B(G.x),b);j.lineTo(B(G.x+G.w),b);j.closePath();j.stroke()}j.restore()};return a})();Dygraph.Plugins.ChartLabels=(function(){var c=function(){this.title_div_=null;this.xlabel_div_=null;this.ylabel_div_=null;this.y2label_div_=null};c.prototype.toString=function(){return"ChartLabels Plugin"};c.prototype.activate=function(d){return{layout:this.layout,didDrawChart:this.didDrawChart}};var b=function(d){var e=document.createElement("div");e.style.position="absolute";e.style.left=d.x+"px";e.style.top=d.y+"px";e.style.width=d.w+"px";e.style.height=d.h+"px";return e};c.prototype.detachLabels_=function(){var e=[this.title_div_,this.xlabel_div_,this.ylabel_div_,this.y2label_div_];for(var d=0;d<e.length;d++){var f=e[d];if(!f){continue}if(f.parentNode){f.parentNode.removeChild(f)}}this.title_div_=null;this.xlabel_div_=null;this.ylabel_div_=null;this.y2label_div_=null};var a=function(l,i,f,h,j){var d=document.createElement("div");d.style.position="absolute";if(f==1){d.style.left="0px"}else{d.style.left=i.x+"px"}d.style.top=i.y+"px";d.style.width=i.w+"px";d.style.height=i.h+"px";d.style.fontSize=(l.getOption("yLabelWidth")-2)+"px";var m=document.createElement("div");m.style.position="absolute";m.style.width=i.h+"px";m.style.height=i.w+"px";m.style.top=(i.h/2-i.w/2)+"px";m.style.left=(i.w/2-i.h/2)+"px";m.style.textAlign="center";var e="rotate("+(f==1?"-":"")+"90deg)";m.style.transform=e;m.style.WebkitTransform=e;m.style.MozTransform=e;m.style.OTransform=e;m.style.msTransform=e;if(typeof(document.documentMode)!=="undefined"&&document.documentMode<9){m.style.filter="progid:DXImageTransform.Microsoft.BasicImage(rotation="+(f==1?"3":"1")+")";m.style.left="0px";m.style.top="0px"}var k=document.createElement("div");k.className=h;k.innerHTML=j;m.appendChild(k);d.appendChild(m);return d};c.prototype.layout=function(k){this.detachLabels_();var i=k.dygraph;var m=k.chart_div;if(i.getOption("title")){var d=k.reserveSpaceTop(i.getOption("titleHeight"));this.title_div_=b(d);this.title_div_.style.textAlign="center";this.title_div_.style.fontSize=(i.getOption("titleHeight")-8)+"px";this.title_div_.style.fontWeight="bold";this.title_div_.style.zIndex=10;var f=document.createElement("div");f.className="dygraph-label dygraph-title";f.innerHTML=i.getOption("title");this.title_div_.appendChild(f);m.appendChild(this.title_div_)}if(i.getOption("xlabel")){var j=k.reserveSpaceBottom(i.getOption("xLabelHeight"));this.xlabel_div_=b(j);this.xlabel_div_.style.textAlign="center";this.xlabel_div_.style.fontSize=(i.getOption("xLabelHeight")-2)+"px";var f=document.createElement("div");f.className="dygraph-label dygraph-xlabel";f.innerHTML=i.getOption("xlabel");this.xlabel_div_.appendChild(f);m.appendChild(this.xlabel_div_)}if(i.getOption("ylabel")){var h=k.reserveSpaceLeft(0);this.ylabel_div_=a(i,h,1,"dygraph-label dygraph-ylabel",i.getOption("ylabel"));m.appendChild(this.ylabel_div_)}if(i.getOption("y2label")&&i.numAxes()==2){var l=k.reserveSpaceRight(0);this.y2label_div_=a(i,l,2,"dygraph-label dygraph-y2label",i.getOption("y2label"));m.appendChild(this.y2label_div_)}};c.prototype.didDrawChart=function(f){var d=f.dygraph;if(this.title_div_){this.title_div_.children[0].innerHTML=d.getOption("title")}if(this.xlabel_div_){this.xlabel_div_.children[0].innerHTML=d.getOption("xlabel")}if(this.ylabel_div_){this.ylabel_div_.children[0].children[0].innerHTML=d.getOption("ylabel")}if(this.y2label_div_){this.y2label_div_.children[0].children[0].innerHTML=d.getOption("y2label")}};c.prototype.clearChart=function(){};c.prototype.destroy=function(){this.detachLabels_()};return c})();Dygraph.Plugins.Grid=(function(){var a=function(){};a.prototype.toString=function(){return"Gridline Plugin"};a.prototype.activate=function(b){return{willDrawChart:this.willDrawChart}};a.prototype.willDrawChart=function(k){var h=k.dygraph;var o=k.drawingContext;var j=h.layout_;var c=k.dygraph.plotter_.area;function b(e){return Math.round(e)+0.5}function d(e){return Math.round(e)-0.5}var m,l,f,n;if(h.getOption("drawYGrid")){n=j.yticks;o.save();o.strokeStyle=h.getOption("gridLineColor");o.lineWidth=h.getOption("gridLineWidth");for(f=0;f<n.length;f++){if(n[f][0]!==0){continue}m=b(c.x);l=d(c.y+n[f][1]*c.h);o.beginPath();o.moveTo(m,l);o.lineTo(m+c.w,l);o.closePath();o.stroke()}o.restore()}if(h.getOption("drawXGrid")){n=j.xticks;o.save();o.strokeStyle=h.getOption("gridLineColor");o.lineWidth=h.getOption("gridLineWidth");for(f=0;f<n.length;f++){m=b(c.x+n[f][0]*c.w);l=d(c.y+c.h);o.beginPath();o.moveTo(m,l);o.lineTo(m,c.y);o.closePath();o.stroke()}o.restore()}};a.prototype.destroy=function(){};return a})();Dygraph.Plugins.Legend=(function(){var c=function(){this.legend_div_=null;this.is_generated_div_=false};c.prototype.toString=function(){return"Legend Plugin"};var a,d;c.prototype.activate=function(j){var m;var f=j.getOption("labelsDivWidth");var l=j.getOption("labelsDiv");if(l&&null!==l){if(typeof(l)=="string"||l instanceof String){m=document.getElementById(l)}else{m=l}}else{var i={position:"absolute",fontSize:"14px",zIndex:10,width:f+"px",top:"0px",left:(j.size().width-f-2)+"px",background:"white",lineHeight:"normal",textAlign:"left",overflow:"hidden"};Dygraph.update(i,j.getOption("labelsDivStyles"));m=document.createElement("div");m.className="dygraph-legend";for(var h in i){if(!i.hasOwnProperty(h)){continue}try{m.style[h]=i[h]}catch(k){this.warn("You are using unsupported css properties for your browser in labelsDivStyles")}}j.graphDiv.appendChild(m);this.is_generated_div_=true}this.legend_div_=m;this.one_em_width_=10;return{select:this.select,deselect:this.deselect,predraw:this.predraw,didDrawChart:this.didDrawChart}};var b=function(g){var f=document.createElement("span");f.setAttribute("style","margin: 0; padding: 0 0 0 1em; border: 0;");g.appendChild(f);var e=f.offsetWidth;g.removeChild(f);return e};c.prototype.select=function(i){var h=i.selectedX;var g=i.selectedPoints;var f=a(i.dygraph,h,g,this.one_em_width_);this.legend_div_.innerHTML=f};c.prototype.deselect=function(h){var f=b(this.legend_div_);this.one_em_width_=f;var g=a(h.dygraph,undefined,undefined,f);this.legend_div_.innerHTML=g};c.prototype.didDrawChart=function(f){this.deselect(f)};c.prototype.predraw=function(h){if(!this.is_generated_div_){return}h.dygraph.graphDiv.appendChild(this.legend_div_);var g=h.dygraph.plotter_.area;var f=h.dygraph.getOption("labelsDivWidth");this.legend_div_.style.left=g.x+g.w-f-1+"px";this.legend_div_.style.top=g.y+"px";this.legend_div_.style.width=f+"px"};c.prototype.destroy=function(){this.legend_div_=null};a=function(w,p,l,f){if(w.getOption("showLabelsOnHighlight")!==true){return""}var r,D,u,A,s,m;var z=w.getLabels();if(typeof(p)==="undefined"){if(w.getOption("legend")!="always"){return""}D=w.getOption("labelsSeparateLines");r="";for(u=1;u<z.length;u++){var q=w.getPropertiesForSeries(z[u]);if(!q.visible){continue}if(r!==""){r+=(D?"<br/>":" ")}m=w.getOption("strokePattern",z[u]);s=d(m,q.color,f);r+="<span style='font-weight: bold; color: "+q.color+";'>"+s+" "+z[u]+"</span>"}return r}var B=w.optionsViewForAxis_("x");var o=B("valueFormatter");r=o(p,B,z[0],w);if(r!==""){r+=":"}var v=[];var j=w.numAxes();for(u=0;u<j;u++){v[u]=w.optionsViewForAxis_("y"+(u?1+u:""))}var k=w.getOption("labelsShowZeroValues");D=w.getOption("labelsSeparateLines");var C=w.getHighlightSeries();for(u=0;u<l.length;u++){var t=l[u];if(t.yval===0&&!k){continue}if(!Dygraph.isOK(t.canvasy)){continue}if(D){r+="<br/>"}var q=w.getPropertiesForSeries(t.name);var n=v[q.axis-1];var y=n("valueFormatter");var e=y(t.yval,n,t.name,w);var h=(t.name==C)?" class='highlight'":"";r+="<span"+h+"> <b><span style='color: "+q.color+";'>"+t.name+"</span></b>:"+e+"</span>"}return r};d=function(s,h,r){var e=(/MSIE/.test(navigator.userAgent)&&!window.opera);if(e){return"&mdash;"}if(!s||s.length<=1){return'<div style="display: inline-block; position: relative; bottom: .5ex; padding-left: 1em; height: 1px; border-bottom: 2px solid '+h+';"></div>'}var l,k,f,o;var g=0,q=0;var p=[];var n;for(l=0;l<=s.length;l++){g+=s[l%s.length]}n=Math.floor(r/(g-s[0]));if(n>1){for(l=0;l<s.length;l++){p[l]=s[l]/r}q=p.length}else{n=1;for(l=0;l<s.length;l++){p[l]=s[l]/g}q=p.length+1}var m="";for(k=0;k<n;k++){for(l=0;l<q;l+=2){f=p[l%p.length];if(l<s.length){o=p[(l+1)%p.length]}else{o=0}m+='<div style="display: inline-block; position: relative; bottom: .5ex; margin-right: '+o+"em; padding-left: "+f+"em; height: 1px; border-bottom: 2px solid "+h+';"></div>'}}return m};return c})();Dygraph.PLUGINS.push(Dygraph.Plugins.Legend,Dygraph.Plugins.Axes,Dygraph.Plugins.ChartLabels,Dygraph.Plugins.Annotations,Dygraph.Plugins.Grid); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/ext.jquery.migration.browser.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/ext.jquery.migration.browser.js
new file mode 100644
index 00000000..cc68ccaa
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/ext.jquery.migration.browser.js
@@ -0,0 +1,40 @@
+/**
+ * MW 1.24+ uses jQuery 1.9+
+ *
+ * @see http://stackoverflow.com/questions/9645803/whats-the-replacement-for-browser
+ */
+jQuery.uaMatch = function( ua ) {
+ 'use strict';
+
+ ua = ua.toLowerCase();
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || [];
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+if ( !jQuery.browser ) {
+ var
+ matched = jQuery.uaMatch( navigator.userAgent ),
+ browser = {};
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ } else {
+ browser.msie = true;
+ }
+
+ jQuery.browser = browser;
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/blank.gif b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/blank.gif
new file mode 100644
index 00000000..35d42e80
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/blank.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif
new file mode 100644
index 00000000..87b4f8bd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png
new file mode 100644
index 00000000..07035307
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png
new file mode 100644
index 00000000..25030179
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png
new file mode 100644
index 00000000..ebaa6a4f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png
new file mode 100644
index 00000000..873294e9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png
new file mode 100644
index 00000000..2eda0893
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png
new file mode 100644
index 00000000..69aa10e2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png
new file mode 100644
index 00000000..79f6980a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png
new file mode 100644
index 00000000..7182cd93
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png
new file mode 100644
index 00000000..d8858bfb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png
new file mode 100644
index 00000000..541e3ffd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png
new file mode 100644
index 00000000..b451689f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png
new file mode 100644
index 00000000..8a4e4a88
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png
new file mode 100644
index 00000000..6049223d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png
new file mode 100644
index 00000000..8044271f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png
new file mode 100644
index 00000000..d9f458f4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png
new file mode 100644
index 00000000..e36d9db2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png
new file mode 100644
index 00000000..c2130f86
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png
new file mode 100644
index 00000000..7ef399b9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox.png
new file mode 100644
index 00000000..65e14f68
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/fancybox.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css
new file mode 100644
index 00000000..8fe0fbd5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js
new file mode 100644
index 00000000..1373ed08
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.js
new file mode 100644
index 00000000..ccf380dd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.js
@@ -0,0 +1,2605 @@
+/*! Javascript plotting library for jQuery, v. 0.7.
+ *
+ * Released under the MIT license by IOLA, December 2007.
+ *
+ */
+
+// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+
+/* Plugin for jQuery for working with colors.
+ *
+ * Version 1.1.
+ *
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ * var c = $.color.extract($("#mydiv"), 'background-color');
+ * console.log(c.r, c.g, c.b, c.a);
+ * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */
+(function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return"rgb("+[G.r,G.g,G.b].join(",")+")"}else{return"rgba("+[G.r,G.g,G.b,G.a].join(",")+")"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=""&&E!="transparent"){break}D=D.parent()}while(!B.nodeName(D.get(0),"body"));if(E=="rgba(0, 0, 0, 0)"){E="transparent"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D=="transparent"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
+
+// the actual Flot code
+(function($) {
+ function Plot(placeholder, data_, options_, plugins) {
+ // data is on the form:
+ // [ series1, series2 ... ]
+ // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
+ // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
+
+ var series = [],
+ options = {
+ // the color theme used for graphs
+ colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
+ legend: {
+ show: true,
+ noColumns: 1, // number of colums in legend table
+ labelFormatter: null, // fn: string -> string
+ labelBoxBorderColor: "#ccc", // border color for the little label boxes
+ container: null, // container (as jQuery object) to put legend in, null means default on top of graph
+ position: "ne", // position of default legend container within plot
+ margin: 5, // distance from grid edge to default legend container within plot
+ backgroundColor: null, // null means auto-detect
+ backgroundOpacity: 0.85 // set to 0 to avoid background
+ },
+ xaxis: {
+ show: null, // null = auto-detect, true = always, false = never
+ position: "bottom", // or "top"
+ mode: null, // null or "time"
+ color: null, // base color, labels, ticks
+ tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
+ transform: null, // null or f: number -> number to transform axis
+ inverseTransform: null, // if transform is set, this should be the inverse function
+ min: null, // min. value to show, null means set automatically
+ max: null, // max. value to show, null means set automatically
+ autoscaleMargin: null, // margin in % to add if auto-setting min/max
+ ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
+ tickFormatter: null, // fn: number -> string
+ labelWidth: null, // size of tick labels in pixels
+ labelHeight: null,
+ reserveSpace: null, // whether to reserve space even if axis isn't shown
+ tickLength: null, // size in pixels of ticks, or "full" for whole line
+ alignTicksWithAxis: null, // axis number or null for no sync
+
+ // mode specific options
+ tickDecimals: null, // no. of decimals, null means auto
+ tickSize: null, // number or [number, "unit"]
+ minTickSize: null, // number or [number, "unit"]
+ monthNames: null, // list of names of months
+ timeformat: null, // format string to use
+ twelveHourClock: false // 12 or 24 time in time mode
+ },
+ yaxis: {
+ autoscaleMargin: 0.02,
+ position: "left" // or "right"
+ },
+ xaxes: [],
+ yaxes: [],
+ series: {
+ points: {
+ show: false,
+ radius: 3,
+ lineWidth: 2, // in pixels
+ fill: true,
+ fillColor: "#ffffff",
+ symbol: "circle" // or callback
+ },
+ lines: {
+ // we don't put in show: false so we can see
+ // whether lines were actively disabled
+ lineWidth: 2, // in pixels
+ fill: false,
+ fillColor: null,
+ steps: false
+ },
+ bars: {
+ show: false,
+ lineWidth: 2, // in pixels
+ barWidth: 1, // in units of the x axis
+ fill: true,
+ fillColor: null,
+ align: "left", // or "center"
+ horizontal: false
+ },
+ shadowSize: 3
+ },
+ grid: {
+ show: true,
+ aboveData: false,
+ color: "#545454", // primary color used for outline and labels
+ backgroundColor: null, // null for transparent, else color
+ borderColor: null, // set if different from the grid color
+ tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
+ labelMargin: 5, // in pixels
+ axisMargin: 8, // in pixels
+ borderWidth: 2, // in pixels
+ minBorderMargin: null, // in pixels, null means taken from points radius
+ markings: null, // array of ranges or fn: axes -> array of ranges
+ markingsColor: "#f4f4f4",
+ markingsLineWidth: 2,
+ // interactive stuff
+ clickable: false,
+ hoverable: false,
+ autoHighlight: true, // highlight in case mouse is near
+ mouseActiveRadius: 10 // how far the mouse can be away to activate an item
+ },
+ hooks: {}
+ },
+ canvas = null, // the canvas for the plot itself
+ overlay = null, // canvas for interactive stuff on top of plot
+ eventHolder = null, // jQuery object that events should be bound to
+ ctx = null, octx = null,
+ xaxes = [], yaxes = [],
+ plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
+ canvasWidth = 0, canvasHeight = 0,
+ plotWidth = 0, plotHeight = 0,
+ hooks = {
+ processOptions: [],
+ processRawData: [],
+ processDatapoints: [],
+ drawSeries: [],
+ draw: [],
+ bindEvents: [],
+ drawOverlay: [],
+ shutdown: []
+ },
+ plot = this;
+
+ // public functions
+ plot.setData = setData;
+ plot.setupGrid = setupGrid;
+ plot.draw = draw;
+ plot.getPlaceholder = function() { return placeholder; };
+ plot.getCanvas = function() { return canvas; };
+ plot.getPlotOffset = function() { return plotOffset; };
+ plot.width = function () { return plotWidth; };
+ plot.height = function () { return plotHeight; };
+ plot.offset = function () {
+ var o = eventHolder.offset();
+ o.left += plotOffset.left;
+ o.top += plotOffset.top;
+ return o;
+ };
+ plot.getData = function () { return series; };
+ plot.getAxes = function () {
+ var res = {}, i;
+ $.each(xaxes.concat(yaxes), function (_, axis) {
+ if (axis)
+ res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
+ });
+ return res;
+ };
+ plot.getXAxes = function () { return xaxes; };
+ plot.getYAxes = function () { return yaxes; };
+ plot.c2p = canvasToAxisCoords;
+ plot.p2c = axisToCanvasCoords;
+ plot.getOptions = function () { return options; };
+ plot.highlight = highlight;
+ plot.unhighlight = unhighlight;
+ plot.triggerRedrawOverlay = triggerRedrawOverlay;
+ plot.pointOffset = function(point) {
+ return {
+ left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left),
+ top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top)
+ };
+ };
+ plot.shutdown = shutdown;
+ plot.resize = function () {
+ getCanvasDimensions();
+ resizeCanvas(canvas);
+ resizeCanvas(overlay);
+ };
+
+ // public attributes
+ plot.hooks = hooks;
+
+ // initialize
+ initPlugins(plot);
+ parseOptions(options_);
+ setupCanvases();
+ setData(data_);
+ setupGrid();
+ draw();
+ bindEvents();
+
+
+ function executeHooks(hook, args) {
+ args = [plot].concat(args);
+ for (var i = 0; i < hook.length; ++i)
+ hook[i].apply(this, args);
+ }
+
+ function initPlugins() {
+ for (var i = 0; i < plugins.length; ++i) {
+ var p = plugins[i];
+ p.init(plot);
+ if (p.options)
+ $.extend(true, options, p.options);
+ }
+ }
+
+ function parseOptions(opts) {
+ var i;
+
+ $.extend(true, options, opts);
+
+ if (options.xaxis.color == null)
+ options.xaxis.color = options.grid.color;
+ if (options.yaxis.color == null)
+ options.yaxis.color = options.grid.color;
+
+ if (options.xaxis.tickColor == null) // backwards-compatibility
+ options.xaxis.tickColor = options.grid.tickColor;
+ if (options.yaxis.tickColor == null) // backwards-compatibility
+ options.yaxis.tickColor = options.grid.tickColor;
+
+ if (options.grid.borderColor == null)
+ options.grid.borderColor = options.grid.color;
+ if (options.grid.tickColor == null)
+ options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+ // fill in defaults in axes, copy at least always the
+ // first as the rest of the code assumes it'll be there
+ for (i = 0; i < Math.max(1, options.xaxes.length); ++i)
+ options.xaxes[i] = $.extend(true, {}, options.xaxis, options.xaxes[i]);
+ for (i = 0; i < Math.max(1, options.yaxes.length); ++i)
+ options.yaxes[i] = $.extend(true, {}, options.yaxis, options.yaxes[i]);
+
+ // backwards compatibility, to be removed in future
+ if (options.xaxis.noTicks && options.xaxis.ticks == null)
+ options.xaxis.ticks = options.xaxis.noTicks;
+ if (options.yaxis.noTicks && options.yaxis.ticks == null)
+ options.yaxis.ticks = options.yaxis.noTicks;
+ if (options.x2axis) {
+ options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
+ options.xaxes[1].position = "top";
+ }
+ if (options.y2axis) {
+ options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
+ options.yaxes[1].position = "right";
+ }
+ if (options.grid.coloredAreas)
+ options.grid.markings = options.grid.coloredAreas;
+ if (options.grid.coloredAreasColor)
+ options.grid.markingsColor = options.grid.coloredAreasColor;
+ if (options.lines)
+ $.extend(true, options.series.lines, options.lines);
+ if (options.points)
+ $.extend(true, options.series.points, options.points);
+ if (options.bars)
+ $.extend(true, options.series.bars, options.bars);
+ if (options.shadowSize != null)
+ options.series.shadowSize = options.shadowSize;
+
+ // save options on axes for future reference
+ for (i = 0; i < options.xaxes.length; ++i)
+ getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
+ for (i = 0; i < options.yaxes.length; ++i)
+ getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
+
+ // add hooks from options
+ for (var n in hooks)
+ if (options.hooks[n] && options.hooks[n].length)
+ hooks[n] = hooks[n].concat(options.hooks[n]);
+
+ executeHooks(hooks.processOptions, [options]);
+ }
+
+ function setData(d) {
+ series = parseData(d);
+ fillInSeriesOptions();
+ processData();
+ }
+
+ function parseData(d) {
+ var res = [];
+ for (var i = 0; i < d.length; ++i) {
+ var s = $.extend(true, {}, options.series);
+
+ if (d[i].data != null) {
+ s.data = d[i].data; // move the data instead of deep-copy
+ delete d[i].data;
+
+ $.extend(true, s, d[i]);
+
+ d[i].data = s.data;
+ }
+ else
+ s.data = d[i];
+ res.push(s);
+ }
+
+ return res;
+ }
+
+ function axisNumber(obj, coord) {
+ var a = obj[coord + "axis"];
+ if (typeof a == "object") // if we got a real axis, extract number
+ a = a.n;
+ if (typeof a != "number")
+ a = 1; // default to first axis
+ return a;
+ }
+
+ function allAxes() {
+ // return flat array without annoying null entries
+ return $.grep(xaxes.concat(yaxes), function (a) { return a; });
+ }
+
+ function canvasToAxisCoords(pos) {
+ // return an object with x/y corresponding to all used axes
+ var res = {}, i, axis;
+ for (i = 0; i < xaxes.length; ++i) {
+ axis = xaxes[i];
+ if (axis && axis.used)
+ res["x" + axis.n] = axis.c2p(pos.left);
+ }
+
+ for (i = 0; i < yaxes.length; ++i) {
+ axis = yaxes[i];
+ if (axis && axis.used)
+ res["y" + axis.n] = axis.c2p(pos.top);
+ }
+
+ if (res.x1 !== undefined)
+ res.x = res.x1;
+ if (res.y1 !== undefined)
+ res.y = res.y1;
+
+ return res;
+ }
+
+ function axisToCanvasCoords(pos) {
+ // get canvas coords from the first pair of x/y found in pos
+ var res = {}, i, axis, key;
+
+ for (i = 0; i < xaxes.length; ++i) {
+ axis = xaxes[i];
+ if (axis && axis.used) {
+ key = "x" + axis.n;
+ if (pos[key] == null && axis.n == 1)
+ key = "x";
+
+ if (pos[key] != null) {
+ res.left = axis.p2c(pos[key]);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < yaxes.length; ++i) {
+ axis = yaxes[i];
+ if (axis && axis.used) {
+ key = "y" + axis.n;
+ if (pos[key] == null && axis.n == 1)
+ key = "y";
+
+ if (pos[key] != null) {
+ res.top = axis.p2c(pos[key]);
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ function getOrCreateAxis(axes, number) {
+ if (!axes[number - 1])
+ axes[number - 1] = {
+ n: number, // save the number for future reference
+ direction: axes == xaxes ? "x" : "y",
+ options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
+ };
+
+ return axes[number - 1];
+ }
+
+ function fillInSeriesOptions() {
+ var i;
+
+ // collect what we already got of colors
+ var neededColors = series.length,
+ usedColors = [],
+ assignedColors = [];
+ for (i = 0; i < series.length; ++i) {
+ var sc = series[i].color;
+ if (sc != null) {
+ --neededColors;
+ if (typeof sc == "number")
+ assignedColors.push(sc);
+ else
+ usedColors.push($.color.parse(series[i].color));
+ }
+ }
+
+ // we might need to generate more colors if higher indices
+ // are assigned
+ for (i = 0; i < assignedColors.length; ++i) {
+ neededColors = Math.max(neededColors, assignedColors[i] + 1);
+ }
+
+ // produce colors as needed
+ var colors = [], variation = 0;
+ i = 0;
+ while (colors.length < neededColors) {
+ var c;
+ if (options.colors.length == i) // check degenerate case
+ c = $.color.make(100, 100, 100);
+ else
+ c = $.color.parse(options.colors[i]);
+
+ // vary color if needed
+ var sign = variation % 2 == 1 ? -1 : 1;
+ c.scale('rgb', 1 + sign * Math.ceil(variation / 2) * 0.2)
+
+ // FIXME: if we're getting to close to something else,
+ // we should probably skip this one
+ colors.push(c);
+
+ ++i;
+ if (i >= options.colors.length) {
+ i = 0;
+ ++variation;
+ }
+ }
+
+ // fill in the options
+ var colori = 0, s;
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ // assign colors
+ if (s.color == null) {
+ s.color = colors[colori].toString();
+ ++colori;
+ }
+ else if (typeof s.color == "number")
+ s.color = colors[s.color].toString();
+
+ // turn on lines automatically in case nothing is set
+ if (s.lines.show == null) {
+ var v, show = true;
+ for (v in s)
+ if (s[v] && s[v].show) {
+ show = false;
+ break;
+ }
+ if (show)
+ s.lines.show = true;
+ }
+
+ // setup axes
+ s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
+ s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
+ }
+ }
+
+ function processData() {
+ var topSentry = Number.POSITIVE_INFINITY,
+ bottomSentry = Number.NEGATIVE_INFINITY,
+ fakeInfinity = Number.MAX_VALUE,
+ i, j, k, m, length,
+ s, points, ps, x, y, axis, val, f, p;
+
+ function updateAxis(axis, min, max) {
+ if (min < axis.datamin && min != -fakeInfinity)
+ axis.datamin = min;
+ if (max > axis.datamax && max != fakeInfinity)
+ axis.datamax = max;
+ }
+
+ $.each(allAxes(), function (_, axis) {
+ // init axis
+ axis.datamin = topSentry;
+ axis.datamax = bottomSentry;
+ axis.used = false;
+ });
+
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+ s.datapoints = { points: [] };
+
+ executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
+ }
+
+ // first pass: clean and copy data
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ var data = s.data, format = s.datapoints.format;
+
+ if (!format) {
+ format = [];
+ // find out how to copy
+ format.push({ x: true, number: true, required: true });
+ format.push({ y: true, number: true, required: true });
+
+ if (s.bars.show || (s.lines.show && s.lines.fill)) {
+ format.push({ y: true, number: true, required: false, defaultValue: 0 });
+ if (s.bars.horizontal) {
+ delete format[format.length - 1].y;
+ format[format.length - 1].x = true;
+ }
+ }
+
+ s.datapoints.format = format;
+ }
+
+ if (s.datapoints.pointsize != null)
+ continue; // already filled in
+
+ s.datapoints.pointsize = format.length;
+
+ ps = s.datapoints.pointsize;
+ points = s.datapoints.points;
+
+ insertSteps = s.lines.show && s.lines.steps;
+ s.xaxis.used = s.yaxis.used = true;
+
+ for (j = k = 0; j < data.length; ++j, k += ps) {
+ p = data[j];
+
+ var nullify = p == null;
+ if (!nullify) {
+ for (m = 0; m < ps; ++m) {
+ val = p[m];
+ f = format[m];
+
+ if (f) {
+ if (f.number && val != null) {
+ val = +val; // convert to number
+ if (isNaN(val))
+ val = null;
+ else if (val == Infinity)
+ val = fakeInfinity;
+ else if (val == -Infinity)
+ val = -fakeInfinity;
+ }
+
+ if (val == null) {
+ if (f.required)
+ nullify = true;
+
+ if (f.defaultValue != null)
+ val = f.defaultValue;
+ }
+ }
+
+ points[k + m] = val;
+ }
+ }
+
+ if (nullify) {
+ for (m = 0; m < ps; ++m) {
+ val = points[k + m];
+ if (val != null) {
+ f = format[m];
+ // extract min/max info
+ if (f.x)
+ updateAxis(s.xaxis, val, val);
+ if (f.y)
+ updateAxis(s.yaxis, val, val);
+ }
+ points[k + m] = null;
+ }
+ }
+ else {
+ // a little bit of line specific stuff that
+ // perhaps shouldn't be here, but lacking
+ // better means...
+ if (insertSteps && k > 0
+ && points[k - ps] != null
+ && points[k - ps] != points[k]
+ && points[k - ps + 1] != points[k + 1]) {
+ // copy the point to make room for a middle point
+ for (m = 0; m < ps; ++m)
+ points[k + ps + m] = points[k + m];
+
+ // middle point has same y
+ points[k + 1] = points[k - ps + 1];
+
+ // we've added a point, better reflect that
+ k += ps;
+ }
+ }
+ }
+ }
+
+ // give the hooks a chance to run
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
+ }
+
+ // second pass: find datamax/datamin for auto-scaling
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+ points = s.datapoints.points,
+ ps = s.datapoints.pointsize;
+
+ var xmin = topSentry, ymin = topSentry,
+ xmax = bottomSentry, ymax = bottomSentry;
+
+ for (j = 0; j < points.length; j += ps) {
+ if (points[j] == null)
+ continue;
+
+ for (m = 0; m < ps; ++m) {
+ val = points[j + m];
+ f = format[m];
+ if (!f || val == fakeInfinity || val == -fakeInfinity)
+ continue;
+
+ if (f.x) {
+ if (val < xmin)
+ xmin = val;
+ if (val > xmax)
+ xmax = val;
+ }
+ if (f.y) {
+ if (val < ymin)
+ ymin = val;
+ if (val > ymax)
+ ymax = val;
+ }
+ }
+ }
+
+ if (s.bars.show) {
+ // make sure we got room for the bar on the dancing floor
+ var delta = s.bars.align == "left" ? 0 : -s.bars.barWidth/2;
+ if (s.bars.horizontal) {
+ ymin += delta;
+ ymax += delta + s.bars.barWidth;
+ }
+ else {
+ xmin += delta;
+ xmax += delta + s.bars.barWidth;
+ }
+ }
+
+ updateAxis(s.xaxis, xmin, xmax);
+ updateAxis(s.yaxis, ymin, ymax);
+ }
+
+ $.each(allAxes(), function (_, axis) {
+ if (axis.datamin == topSentry)
+ axis.datamin = null;
+ if (axis.datamax == bottomSentry)
+ axis.datamax = null;
+ });
+ }
+
+ function makeCanvas(skipPositioning, cls) {
+ var c = document.createElement('canvas');
+ c.className = cls;
+ c.width = canvasWidth;
+ c.height = canvasHeight;
+
+ if (!skipPositioning)
+ $(c).css({ position: 'absolute', left: 0, top: 0 });
+
+ $(c).appendTo(placeholder);
+
+ if (!c.getContext) // excanvas hack
+ c = window.G_vmlCanvasManager.initElement(c);
+
+ // used for resetting in case we get replotted
+ c.getContext("2d").save();
+
+ return c;
+ }
+
+ function getCanvasDimensions() {
+ canvasWidth = placeholder.width();
+ canvasHeight = placeholder.height();
+
+ if (canvasWidth <= 0 || canvasHeight <= 0)
+ throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
+ }
+
+ function resizeCanvas(c) {
+ // resizing should reset the state (excanvas seems to be
+ // buggy though)
+ if (c.width != canvasWidth)
+ c.width = canvasWidth;
+
+ if (c.height != canvasHeight)
+ c.height = canvasHeight;
+
+ // so try to get back to the initial state (even if it's
+ // gone now, this should be safe according to the spec)
+ var cctx = c.getContext("2d");
+ cctx.restore();
+
+ // and save again
+ cctx.save();
+ }
+
+ function setupCanvases() {
+ var reused,
+ existingCanvas = placeholder.children("canvas.base"),
+ existingOverlay = placeholder.children("canvas.overlay");
+
+ if (existingCanvas.length == 0 || existingOverlay == 0) {
+ // init everything
+
+ placeholder.html(""); // make sure placeholder is clear
+
+ placeholder.css({ padding: 0 }); // padding messes up the positioning
+
+ if (placeholder.css("position") == 'static')
+ placeholder.css("position", "relative"); // for positioning labels and overlay
+
+ getCanvasDimensions();
+
+ canvas = makeCanvas(true, "base");
+ overlay = makeCanvas(false, "overlay"); // overlay canvas for interactive features
+
+ reused = false;
+ }
+ else {
+ // reuse existing elements
+
+ canvas = existingCanvas.get(0);
+ overlay = existingOverlay.get(0);
+
+ reused = true;
+ }
+
+ ctx = canvas.getContext("2d");
+ octx = overlay.getContext("2d");
+
+ // we include the canvas in the event holder too, because IE 7
+ // sometimes has trouble with the stacking order
+ eventHolder = $([overlay, canvas]);
+
+ if (reused) {
+ // run shutdown in the old plot object
+ placeholder.data("plot").shutdown();
+
+ // reset reused canvases
+ plot.resize();
+
+ // make sure overlay pixels are cleared (canvas is cleared when we redraw)
+ octx.clearRect(0, 0, canvasWidth, canvasHeight);
+
+ // then whack any remaining obvious garbage left
+ eventHolder.unbind();
+ placeholder.children().not([canvas, overlay]).remove();
+ }
+
+ // save in case we get replotted
+ placeholder.data("plot", plot);
+ }
+
+ function bindEvents() {
+ // bind events
+ if (options.grid.hoverable) {
+ eventHolder.mousemove(onMouseMove);
+ eventHolder.mouseleave(onMouseLeave);
+ }
+
+ if (options.grid.clickable)
+ eventHolder.click(onClick);
+
+ executeHooks(hooks.bindEvents, [eventHolder]);
+ }
+
+ function shutdown() {
+ if (redrawTimeout)
+ clearTimeout(redrawTimeout);
+
+ eventHolder.unbind("mousemove", onMouseMove);
+ eventHolder.unbind("mouseleave", onMouseLeave);
+ eventHolder.unbind("click", onClick);
+
+ executeHooks(hooks.shutdown, [eventHolder]);
+ }
+
+ function setTransformationHelpers(axis) {
+ // set helper functions on the axis, assumes plot area
+ // has been computed already
+
+ function identity(x) { return x; }
+
+ var s, m, t = axis.options.transform || identity,
+ it = axis.options.inverseTransform;
+
+ // precompute how much the axis is scaling a point
+ // in canvas space
+ if (axis.direction == "x") {
+ s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
+ m = Math.min(t(axis.max), t(axis.min));
+ }
+ else {
+ s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
+ s = -s;
+ m = Math.max(t(axis.max), t(axis.min));
+ }
+
+ // data point to canvas coordinate
+ if (t == identity) // slight optimization
+ axis.p2c = function (p) { return (p - m) * s; };
+ else
+ axis.p2c = function (p) { return (t(p) - m) * s; };
+ // canvas coordinate to data point
+ if (!it)
+ axis.c2p = function (c) { return m + c / s; };
+ else
+ axis.c2p = function (c) { return it(m + c / s); };
+ }
+
+ function measureTickLabels(axis) {
+ var opts = axis.options, i, ticks = axis.ticks || [], labels = [],
+ l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;
+
+ function makeDummyDiv(labels, width) {
+ return $('<div style="position:absolute;top:-10000px;' + width + 'font-size:smaller">' +
+ '<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis">'
+ + labels.join("") + '</div></div>')
+ .appendTo(placeholder);
+ }
+
+ if (axis.direction == "x") {
+ // to avoid measuring the widths of the labels (it's slow), we
+ // construct fixed-size boxes and put the labels inside
+ // them, we don't need the exact figures and the
+ // fixed-size box content is easy to center
+ if (w == null)
+ w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));
+
+ // measure x label heights
+ if (h == null) {
+ labels = [];
+ for (i = 0; i < ticks.length; ++i) {
+ l = ticks[i].label;
+ if (l)
+ labels.push('<div class="tickLabel" style="float:left;width:' + w + 'px">' + l + '</div>');
+ }
+
+ if (labels.length > 0) {
+ // stick them all in the same div and measure
+ // collective height
+ labels.push('<div style="clear:left"></div>');
+ dummyDiv = makeDummyDiv(labels, "width:10000px;");
+ h = dummyDiv.height();
+ dummyDiv.remove();
+ }
+ }
+ }
+ else if (w == null || h == null) {
+ // calculate y label dimensions
+ for (i = 0; i < ticks.length; ++i) {
+ l = ticks[i].label;
+ if (l)
+ labels.push('<div class="tickLabel">' + l + '</div>');
+ }
+
+ if (labels.length > 0) {
+ dummyDiv = makeDummyDiv(labels, "");
+ if (w == null)
+ w = dummyDiv.children().width();
+ if (h == null)
+ h = dummyDiv.find("div.tickLabel").height();
+ dummyDiv.remove();
+ }
+ }
+
+ if (w == null)
+ w = 0;
+ if (h == null)
+ h = 0;
+
+ axis.labelWidth = w;
+ axis.labelHeight = h;
+ }
+
+ function allocateAxisBoxFirstPhase(axis) {
+ // find the bounding box of the axis by looking at label
+ // widths/heights and ticks, make room by diminishing the
+ // plotOffset
+
+ var lw = axis.labelWidth,
+ lh = axis.labelHeight,
+ pos = axis.options.position,
+ tickLength = axis.options.tickLength,
+ axismargin = options.grid.axisMargin,
+ padding = options.grid.labelMargin,
+ all = axis.direction == "x" ? xaxes : yaxes,
+ index;
+
+ // determine axis margin
+ var samePosition = $.grep(all, function (a) {
+ return a && a.options.position == pos && a.reserveSpace;
+ });
+ if ($.inArray(axis, samePosition) == samePosition.length - 1)
+ axismargin = 0; // outermost
+
+ // determine tick length - if we're innermost, we can use "full"
+ if (tickLength == null)
+ tickLength = "full";
+
+ var sameDirection = $.grep(all, function (a) {
+ return a && a.reserveSpace;
+ });
+
+ var innermost = $.inArray(axis, sameDirection) == 0;
+ if (!innermost && tickLength == "full")
+ tickLength = 5;
+
+ if (!isNaN(+tickLength))
+ padding += +tickLength;
+
+ // compute box
+ if (axis.direction == "x") {
+ lh += padding;
+
+ if (pos == "bottom") {
+ plotOffset.bottom += lh + axismargin;
+ axis.box = { top: canvasHeight - plotOffset.bottom, height: lh };
+ }
+ else {
+ axis.box = { top: plotOffset.top + axismargin, height: lh };
+ plotOffset.top += lh + axismargin;
+ }
+ }
+ else {
+ lw += padding;
+
+ if (pos == "left") {
+ axis.box = { left: plotOffset.left + axismargin, width: lw };
+ plotOffset.left += lw + axismargin;
+ }
+ else {
+ plotOffset.right += lw + axismargin;
+ axis.box = { left: canvasWidth - plotOffset.right, width: lw };
+ }
+ }
+
+ // save for future reference
+ axis.position = pos;
+ axis.tickLength = tickLength;
+ axis.box.padding = padding;
+ axis.innermost = innermost;
+ }
+
+ function allocateAxisBoxSecondPhase(axis) {
+ // set remaining bounding box coordinates
+ if (axis.direction == "x") {
+ axis.box.left = plotOffset.left;
+ axis.box.width = plotWidth;
+ }
+ else {
+ axis.box.top = plotOffset.top;
+ axis.box.height = plotHeight;
+ }
+ }
+
+ function setupGrid() {
+ var i, axes = allAxes();
+
+ // first calculate the plot and axis box dimensions
+
+ $.each(axes, function (_, axis) {
+ axis.show = axis.options.show;
+ if (axis.show == null)
+ axis.show = axis.used; // by default an axis is visible if it's got data
+
+ axis.reserveSpace = axis.show || axis.options.reserveSpace;
+
+ setRange(axis);
+ });
+
+ allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
+
+ plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;
+ if (options.grid.show) {
+ $.each(allocatedAxes, function (_, axis) {
+ // make the ticks
+ setupTickGeneration(axis);
+ setTicks(axis);
+ snapRangeToTicks(axis, axis.ticks);
+
+ // find labelWidth/Height for axis
+ measureTickLabels(axis);
+ });
+
+ // with all dimensions in house, we can compute the
+ // axis boxes, start from the outside (reverse order)
+ for (i = allocatedAxes.length - 1; i >= 0; --i)
+ allocateAxisBoxFirstPhase(allocatedAxes[i]);
+
+ // make sure we've got enough space for things that
+ // might stick out
+ var minMargin = options.grid.minBorderMargin;
+ if (minMargin == null) {
+ minMargin = 0;
+ for (i = 0; i < series.length; ++i)
+ minMargin = Math.max(minMargin, series[i].points.radius + series[i].points.lineWidth/2);
+ }
+
+ for (var a in plotOffset) {
+ plotOffset[a] += options.grid.borderWidth;
+ plotOffset[a] = Math.max(minMargin, plotOffset[a]);
+ }
+ }
+
+ plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
+ plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
+
+ // now we got the proper plotWidth/Height, we can compute the scaling
+ $.each(axes, function (_, axis) {
+ setTransformationHelpers(axis);
+ });
+
+ if (options.grid.show) {
+ $.each(allocatedAxes, function (_, axis) {
+ allocateAxisBoxSecondPhase(axis);
+ });
+
+ insertAxisLabels();
+ }
+
+ insertLegend();
+ }
+
+ function setRange(axis) {
+ var opts = axis.options,
+ min = +(opts.min != null ? opts.min : axis.datamin),
+ max = +(opts.max != null ? opts.max : axis.datamax),
+ delta = max - min;
+
+ if (delta == 0.0) {
+ // degenerate case
+ var widen = max == 0 ? 1 : 0.01;
+
+ if (opts.min == null)
+ min -= widen;
+ // always widen max if we couldn't widen min to ensure we
+ // don't fall into min == max which doesn't work
+ if (opts.max == null || opts.min != null)
+ max += widen;
+ }
+ else {
+ // consider autoscaling
+ var margin = opts.autoscaleMargin;
+ if (margin != null) {
+ if (opts.min == null) {
+ min -= delta * margin;
+ // make sure we don't go below zero if all values
+ // are positive
+ if (min < 0 && axis.datamin != null && axis.datamin >= 0)
+ min = 0;
+ }
+ if (opts.max == null) {
+ max += delta * margin;
+ if (max > 0 && axis.datamax != null && axis.datamax <= 0)
+ max = 0;
+ }
+ }
+ }
+ axis.min = min;
+ axis.max = max;
+ }
+
+ function setupTickGeneration(axis) {
+ var opts = axis.options;
+
+ // estimate number of ticks
+ var noTicks;
+ if (typeof opts.ticks == "number" && opts.ticks > 0)
+ noTicks = opts.ticks;
+ else
+ // heuristic based on the model a*sqrt(x) fitted to
+ // some data points that seemed reasonable
+ noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? canvasWidth : canvasHeight);
+
+ var delta = (axis.max - axis.min) / noTicks,
+ size, generator, unit, formatter, i, magn, norm;
+
+ if (opts.mode == "time") {
+ // pretty handling of time
+
+ // map of app. size of time units in milliseconds
+ var timeUnitSize = {
+ "second": 1000,
+ "minute": 60 * 1000,
+ "hour": 60 * 60 * 1000,
+ "day": 24 * 60 * 60 * 1000,
+ "month": 30 * 24 * 60 * 60 * 1000,
+ "year": 365.2425 * 24 * 60 * 60 * 1000
+ };
+
+
+ // the allowed tick sizes, after 1 year we use
+ // an integer algorithm
+ var spec = [
+ [1, "second"], [2, "second"], [5, "second"], [10, "second"],
+ [30, "second"],
+ [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
+ [30, "minute"],
+ [1, "hour"], [2, "hour"], [4, "hour"],
+ [8, "hour"], [12, "hour"],
+ [1, "day"], [2, "day"], [3, "day"],
+ [0.25, "month"], [0.5, "month"], [1, "month"],
+ [2, "month"], [3, "month"], [6, "month"],
+ [1, "year"]
+ ];
+
+ var minSize = 0;
+ if (opts.minTickSize != null) {
+ if (typeof opts.tickSize == "number")
+ minSize = opts.tickSize;
+ else
+ minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
+ }
+
+ for (var i = 0; i < spec.length - 1; ++i)
+ if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]
+ + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
+ && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)
+ break;
+ size = spec[i][0];
+ unit = spec[i][1];
+
+ // special-case the possibility of several years
+ if (unit == "year") {
+ magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));
+ norm = (delta / timeUnitSize.year) / magn;
+ if (norm < 1.5)
+ size = 1;
+ else if (norm < 3)
+ size = 2;
+ else if (norm < 7.5)
+ size = 5;
+ else
+ size = 10;
+
+ size *= magn;
+ }
+
+ axis.tickSize = opts.tickSize || [size, unit];
+
+ generator = function(axis) {
+ var ticks = [],
+ tickSize = axis.tickSize[0], unit = axis.tickSize[1],
+ d = new Date(axis.min);
+
+ var step = tickSize * timeUnitSize[unit];
+
+ if (unit == "second")
+ d.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));
+ if (unit == "minute")
+ d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));
+ if (unit == "hour")
+ d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));
+ if (unit == "month")
+ d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));
+ if (unit == "year")
+ d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));
+
+ // reset smaller components
+ d.setUTCMilliseconds(0);
+ if (step >= timeUnitSize.minute)
+ d.setUTCSeconds(0);
+ if (step >= timeUnitSize.hour)
+ d.setUTCMinutes(0);
+ if (step >= timeUnitSize.day)
+ d.setUTCHours(0);
+ if (step >= timeUnitSize.day * 4)
+ d.setUTCDate(1);
+ if (step >= timeUnitSize.year)
+ d.setUTCMonth(0);
+
+
+ var carry = 0, v = Number.NaN, prev;
+ do {
+ prev = v;
+ v = d.getTime();
+ ticks.push(v);
+ if (unit == "month") {
+ if (tickSize < 1) {
+ // a bit complicated - we'll divide the month
+ // up but we need to take care of fractions
+ // so we don't end up in the middle of a day
+ d.setUTCDate(1);
+ var start = d.getTime();
+ d.setUTCMonth(d.getUTCMonth() + 1);
+ var end = d.getTime();
+ d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
+ carry = d.getUTCHours();
+ d.setUTCHours(0);
+ }
+ else
+ d.setUTCMonth(d.getUTCMonth() + tickSize);
+ }
+ else if (unit == "year") {
+ d.setUTCFullYear(d.getUTCFullYear() + tickSize);
+ }
+ else
+ d.setTime(v + step);
+ } while (v < axis.max && v != prev);
+
+ return ticks;
+ };
+
+ formatter = function (v, axis) {
+ var d = new Date(v);
+
+ // first check global format
+ if (opts.timeformat != null)
+ return $.plot.formatDate(d, opts.timeformat, opts.monthNames);
+
+ var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
+ var span = axis.max - axis.min;
+ var suffix = (opts.twelveHourClock) ? " %p" : "";
+
+ if (t < timeUnitSize.minute)
+ fmt = "%h:%M:%S" + suffix;
+ else if (t < timeUnitSize.day) {
+ if (span < 2 * timeUnitSize.day)
+ fmt = "%h:%M" + suffix;
+ else
+ fmt = "%b %d %h:%M" + suffix;
+ }
+ else if (t < timeUnitSize.month)
+ fmt = "%b %d";
+ else if (t < timeUnitSize.year) {
+ if (span < timeUnitSize.year)
+ fmt = "%b";
+ else
+ fmt = "%b %y";
+ }
+ else
+ fmt = "%y";
+
+ return $.plot.formatDate(d, fmt, opts.monthNames);
+ };
+ }
+ else {
+ // pretty rounding of base-10 numbers
+ var maxDec = opts.tickDecimals;
+ var dec = -Math.floor(Math.log(delta) / Math.LN10);
+ if (maxDec != null && dec > maxDec)
+ dec = maxDec;
+
+ magn = Math.pow(10, -dec);
+ norm = delta / magn; // norm is between 1.0 and 10.0
+
+ if (norm < 1.5)
+ size = 1;
+ else if (norm < 3) {
+ size = 2;
+ // special case for 2.5, requires an extra decimal
+ if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
+ size = 2.5;
+ ++dec;
+ }
+ }
+ else if (norm < 7.5)
+ size = 5;
+ else
+ size = 10;
+
+ size *= magn;
+
+ if (opts.minTickSize != null && size < opts.minTickSize)
+ size = opts.minTickSize;
+
+ //add a checker to determine if we really have a decimeal or integer. if axis.delta = int, dec =0
+ var integerChecker = axis.delta - Math.floor(axis.delta);
+ if (integerChecker < 0.00000001 || integerChecker > 0.999999999) dec = 0;
+
+ //axis.delta is within floating point error of an integer
+
+ axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
+ axis.tickSize = opts.tickSize || size;
+
+ generator = function (axis) {
+ var ticks = [];
+
+ // spew out all possible ticks
+ var start = floorInBase(axis.min, axis.tickSize),
+ i = 0, v = Number.NaN, prev;
+ do {
+ prev = v;
+ v = start + i * axis.tickSize;
+ ticks.push(v);
+ ++i;
+ } while (v < axis.max && v != prev);
+ return ticks;
+ };
+
+ formatter = function (v, axis) {
+ return v.toFixed(axis.tickDecimals);
+ };
+ }
+
+ if (opts.alignTicksWithAxis != null) {
+ var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
+ if (otherAxis && otherAxis.used && otherAxis != axis) {
+ // consider snapping min/max to outermost nice ticks
+ var niceTicks = generator(axis);
+ if (niceTicks.length > 0) {
+ if (opts.min == null)
+ axis.min = Math.min(axis.min, niceTicks[0]);
+ if (opts.max == null && niceTicks.length > 1)
+ axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
+ }
+
+ generator = function (axis) {
+ // copy ticks, scaled to this axis
+ var ticks = [], v, i;
+ for (i = 0; i < otherAxis.ticks.length; ++i) {
+ v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
+ v = axis.min + v * (axis.max - axis.min);
+ ticks.push(v);
+ }
+ return ticks;
+ };
+
+ // we might need an extra decimal since forced
+ // ticks don't necessarily fit naturally
+ if (axis.mode != "time" && opts.tickDecimals == null) {
+ var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),
+ ts = generator(axis);
+
+ // only proceed if the tick interval rounded
+ // with an extra decimal doesn't give us a
+ // zero at end
+ if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
+ axis.tickDecimals = extraDec;
+ }
+ }
+ }
+
+ axis.tickGenerator = generator;
+ if ($.isFunction(opts.tickFormatter))
+ axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
+ else
+ axis.tickFormatter = formatter;
+ }
+
+ function setTicks(axis) {
+ var oticks = axis.options.ticks, ticks = [];
+ if (oticks == null || (typeof oticks == "number" && oticks > 0))
+ ticks = axis.tickGenerator(axis);
+ else if (oticks) {
+ if ($.isFunction(oticks))
+ // generate the ticks
+ ticks = oticks({ min: axis.min, max: axis.max });
+ else
+ ticks = oticks;
+ }
+
+ // clean up/labelify the supplied ticks, copy them over
+ var i, v;
+ axis.ticks = [];
+ for (i = 0; i < ticks.length; ++i) {
+ var label = null;
+ var t = ticks[i];
+ if (typeof t == "object") {
+ v = +t[0];
+ if (t.length > 1)
+ label = t[1];
+ }
+ else
+ v = +t;
+ if (label == null)
+ label = axis.tickFormatter(v, axis);
+ if (!isNaN(v))
+ axis.ticks.push({ v: v, label: label });
+ }
+ }
+
+ function snapRangeToTicks(axis, ticks) {
+ if (axis.options.autoscaleMargin && ticks.length > 0) {
+ // snap to ticks
+ if (axis.options.min == null)
+ axis.min = Math.min(axis.min, ticks[0].v);
+ if (axis.options.max == null && ticks.length > 1)
+ axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
+ }
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+
+ var grid = options.grid;
+
+ // draw background, if any
+ if (grid.show && grid.backgroundColor)
+ drawBackground();
+
+ if (grid.show && !grid.aboveData)
+ drawGrid();
+
+ for (var i = 0; i < series.length; ++i) {
+ executeHooks(hooks.drawSeries, [ctx, series[i]]);
+ drawSeries(series[i]);
+ }
+
+ executeHooks(hooks.draw, [ctx]);
+
+ if (grid.show && grid.aboveData)
+ drawGrid();
+ }
+
+ function extractRange(ranges, coord) {
+ var axis, from, to, key, axes = allAxes();
+
+ for (i = 0; i < axes.length; ++i) {
+ axis = axes[i];
+ if (axis.direction == coord) {
+ key = coord + axis.n + "axis";
+ if (!ranges[key] && axis.n == 1)
+ key = coord + "axis"; // support x1axis as xaxis
+ if (ranges[key]) {
+ from = ranges[key].from;
+ to = ranges[key].to;
+ break;
+ }
+ }
+ }
+
+ // backwards-compat stuff - to be removed in future
+ if (!ranges[key]) {
+ axis = coord == "x" ? xaxes[0] : yaxes[0];
+ from = ranges[coord + "1"];
+ to = ranges[coord + "2"];
+ }
+
+ // auto-reverse as an added bonus
+ if (from != null && to != null && from > to) {
+ var tmp = from;
+ from = to;
+ to = tmp;
+ }
+
+ return { from: from, to: to, axis: axis };
+ }
+
+ function drawBackground() {
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
+ ctx.fillRect(0, 0, plotWidth, plotHeight);
+ ctx.restore();
+ }
+
+ function drawGrid() {
+ var i;
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ // draw markings
+ var markings = options.grid.markings;
+ if (markings) {
+ if ($.isFunction(markings)) {
+ var axes = plot.getAxes();
+ // xmin etc. is backwards compatibility, to be
+ // removed in the future
+ axes.xmin = axes.xaxis.min;
+ axes.xmax = axes.xaxis.max;
+ axes.ymin = axes.yaxis.min;
+ axes.ymax = axes.yaxis.max;
+
+ markings = markings(axes);
+ }
+
+ for (i = 0; i < markings.length; ++i) {
+ var m = markings[i],
+ xrange = extractRange(m, "x"),
+ yrange = extractRange(m, "y");
+
+ // fill in missing
+ if (xrange.from == null)
+ xrange.from = xrange.axis.min;
+ if (xrange.to == null)
+ xrange.to = xrange.axis.max;
+ if (yrange.from == null)
+ yrange.from = yrange.axis.min;
+ if (yrange.to == null)
+ yrange.to = yrange.axis.max;
+
+ // clip
+ if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
+ yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
+ continue;
+
+ xrange.from = Math.max(xrange.from, xrange.axis.min);
+ xrange.to = Math.min(xrange.to, xrange.axis.max);
+ yrange.from = Math.max(yrange.from, yrange.axis.min);
+ yrange.to = Math.min(yrange.to, yrange.axis.max);
+
+ if (xrange.from == xrange.to && yrange.from == yrange.to)
+ continue;
+
+ // then draw
+ xrange.from = xrange.axis.p2c(xrange.from);
+ xrange.to = xrange.axis.p2c(xrange.to);
+ yrange.from = yrange.axis.p2c(yrange.from);
+ yrange.to = yrange.axis.p2c(yrange.to);
+
+ if (xrange.from == xrange.to || yrange.from == yrange.to) {
+ // draw line
+ ctx.beginPath();
+ ctx.strokeStyle = m.color || options.grid.markingsColor;
+ ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
+ ctx.moveTo(xrange.from, yrange.from);
+ ctx.lineTo(xrange.to, yrange.to);
+ ctx.stroke();
+ }
+ else {
+ // fill area
+ ctx.fillStyle = m.color || options.grid.markingsColor;
+ ctx.fillRect(xrange.from, yrange.to,
+ xrange.to - xrange.from,
+ yrange.from - yrange.to);
+ }
+ }
+ }
+
+ // draw the ticks
+ var axes = allAxes(), bw = options.grid.borderWidth;
+
+ for (var j = 0; j < axes.length; ++j) {
+ var axis = axes[j], box = axis.box,
+ t = axis.tickLength, x, y, xoff, yoff;
+ if (!axis.show || axis.ticks.length == 0)
+ continue
+
+ ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();
+ ctx.lineWidth = 1;
+
+ // find the edges
+ if (axis.direction == "x") {
+ x = 0;
+ if (t == "full")
+ y = (axis.position == "top" ? 0 : plotHeight);
+ else
+ y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
+ }
+ else {
+ y = 0;
+ if (t == "full")
+ x = (axis.position == "left" ? 0 : plotWidth);
+ else
+ x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
+ }
+
+ // draw tick bar
+ if (!axis.innermost) {
+ ctx.beginPath();
+ xoff = yoff = 0;
+ if (axis.direction == "x")
+ xoff = plotWidth;
+ else
+ yoff = plotHeight;
+
+ if (ctx.lineWidth == 1) {
+ x = Math.floor(x) + 0.5;
+ y = Math.floor(y) + 0.5;
+ }
+
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + xoff, y + yoff);
+ ctx.stroke();
+ }
+
+ // draw ticks
+ ctx.beginPath();
+ for (i = 0; i < axis.ticks.length; ++i) {
+ var v = axis.ticks[i].v;
+
+ xoff = yoff = 0;
+
+ if (v < axis.min || v > axis.max
+ // skip those lying on the axes if we got a border
+ || (t == "full" && bw > 0
+ && (v == axis.min || v == axis.max)))
+ continue;
+
+ if (axis.direction == "x") {
+ x = axis.p2c(v);
+ yoff = t == "full" ? -plotHeight : t;
+
+ if (axis.position == "top")
+ yoff = -yoff;
+ }
+ else {
+ y = axis.p2c(v);
+ xoff = t == "full" ? -plotWidth : t;
+
+ if (axis.position == "left")
+ xoff = -xoff;
+ }
+
+ if (ctx.lineWidth == 1) {
+ if (axis.direction == "x")
+ x = Math.floor(x) + 0.5;
+ else
+ y = Math.floor(y) + 0.5;
+ }
+
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + xoff, y + yoff);
+ }
+
+ ctx.stroke();
+ }
+
+
+ // draw border
+ if (bw) {
+ ctx.lineWidth = bw;
+ ctx.strokeStyle = options.grid.borderColor;
+ ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
+ }
+
+ ctx.restore();
+ }
+
+ function insertAxisLabels() {
+ placeholder.find(".tickLabels").remove();
+
+ var html = ['<div class="tickLabels" style="font-size:smaller">'];
+
+ var axes = allAxes();
+ for (var j = 0; j < axes.length; ++j) {
+ var axis = axes[j], box = axis.box;
+ if (!axis.show)
+ continue;
+ //debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
+ html.push('<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis" style="color:' + axis.options.color + '">');
+ for (var i = 0; i < axis.ticks.length; ++i) {
+ var tick = axis.ticks[i];
+ if (!tick.label || tick.v < axis.min || tick.v > axis.max)
+ continue;
+
+ var pos = {}, align;
+
+ if (axis.direction == "x") {
+ align = "center";
+ pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);
+ if (axis.position == "bottom")
+ pos.top = box.top + box.padding;
+ else
+ pos.bottom = canvasHeight - (box.top + box.height - box.padding);
+ }
+ else {
+ pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);
+ if (axis.position == "left") {
+ pos.right = canvasWidth - (box.left + box.width - box.padding)
+ align = "right";
+ }
+ else {
+ pos.left = box.left + box.padding;
+ align = "left";
+ }
+ }
+
+ pos.width = axis.labelWidth;
+
+ var style = ["position:absolute", "text-align:" + align ];
+ for (var a in pos)
+ style.push(a + ":" + pos[a] + "px")
+
+ html.push('<div class="tickLabel" style="' + style.join(';') + '">' + tick.label + '</div>');
+ }
+ html.push('</div>');
+ }
+
+ html.push('</div>');
+
+ placeholder.append(html.join(""));
+ }
+
+ function drawSeries(series) {
+ if (series.lines.show)
+ drawSeriesLines(series);
+ if (series.bars.show)
+ drawSeriesBars(series);
+ if (series.points.show)
+ drawSeriesPoints(series);
+ }
+
+ function drawSeriesLines(series) {
+ function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
+ var points = datapoints.points,
+ ps = datapoints.pointsize,
+ prevx = null, prevy = null;
+
+ ctx.beginPath();
+ for (var i = ps; i < points.length; i += ps) {
+ var x1 = points[i - ps], y1 = points[i - ps + 1],
+ x2 = points[i], y2 = points[i + 1];
+
+ if (x1 == null || x2 == null)
+ continue;
+
+ // clip with ymin
+ if (y1 <= y2 && y1 < axisy.min) {
+ if (y2 < axisy.min)
+ continue; // line segment is outside
+ // compute new intersection point
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.min;
+ }
+ else if (y2 <= y1 && y2 < axisy.min) {
+ if (y1 < axisy.min)
+ continue;
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.min;
+ }
+
+ // clip with ymax
+ if (y1 >= y2 && y1 > axisy.max) {
+ if (y2 > axisy.max)
+ continue;
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.max;
+ }
+ else if (y2 >= y1 && y2 > axisy.max) {
+ if (y1 > axisy.max)
+ continue;
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.max;
+ }
+
+ // clip with xmin
+ if (x1 <= x2 && x1 < axisx.min) {
+ if (x2 < axisx.min)
+ continue;
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.min;
+ }
+ else if (x2 <= x1 && x2 < axisx.min) {
+ if (x1 < axisx.min)
+ continue;
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.min;
+ }
+
+ // clip with xmax
+ if (x1 >= x2 && x1 > axisx.max) {
+ if (x2 > axisx.max)
+ continue;
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.max;
+ }
+ else if (x2 >= x1 && x2 > axisx.max) {
+ if (x1 > axisx.max)
+ continue;
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.max;
+ }
+
+ if (x1 != prevx || y1 != prevy)
+ ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
+
+ prevx = x2;
+ prevy = y2;
+ ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
+ }
+ ctx.stroke();
+ }
+
+ function plotLineArea(datapoints, axisx, axisy) {
+ var points = datapoints.points,
+ ps = datapoints.pointsize,
+ bottom = Math.min(Math.max(0, axisy.min), axisy.max),
+ i = 0, top, areaOpen = false,
+ ypos = 1, segmentStart = 0, segmentEnd = 0;
+
+ // we process each segment in two turns, first forward
+ // direction to sketch out top, then once we hit the
+ // end we go backwards to sketch the bottom
+ while (true) {
+ if (ps > 0 && i > points.length + ps)
+ break;
+
+ i += ps; // ps is negative if going backwards
+
+ var x1 = points[i - ps],
+ y1 = points[i - ps + ypos],
+ x2 = points[i], y2 = points[i + ypos];
+
+ if (areaOpen) {
+ if (ps > 0 && x1 != null && x2 == null) {
+ // at turning point
+ segmentEnd = i;
+ ps = -ps;
+ ypos = 2;
+ continue;
+ }
+
+ if (ps < 0 && i == segmentStart + ps) {
+ // done with the reverse sweep
+ ctx.fill();
+ areaOpen = false;
+ ps = -ps;
+ ypos = 1;
+ i = segmentStart = segmentEnd + ps;
+ continue;
+ }
+ }
+
+ if (x1 == null || x2 == null)
+ continue;
+
+ // clip x values
+
+ // clip with xmin
+ if (x1 <= x2 && x1 < axisx.min) {
+ if (x2 < axisx.min)
+ continue;
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.min;
+ }
+ else if (x2 <= x1 && x2 < axisx.min) {
+ if (x1 < axisx.min)
+ continue;
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.min;
+ }
+
+ // clip with xmax
+ if (x1 >= x2 && x1 > axisx.max) {
+ if (x2 > axisx.max)
+ continue;
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.max;
+ }
+ else if (x2 >= x1 && x2 > axisx.max) {
+ if (x1 > axisx.max)
+ continue;
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.max;
+ }
+
+ if (!areaOpen) {
+ // open area
+ ctx.beginPath();
+ ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
+ areaOpen = true;
+ }
+
+ // now first check the case where both is outside
+ if (y1 >= axisy.max && y2 >= axisy.max) {
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
+ continue;
+ }
+ else if (y1 <= axisy.min && y2 <= axisy.min) {
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
+ continue;
+ }
+
+ // else it's a bit more complicated, there might
+ // be a flat maxed out rectangle first, then a
+ // triangular cutout or reverse; to find these
+ // keep track of the current x values
+ var x1old = x1, x2old = x2;
+
+ // clip the y values, without shortcutting, we
+ // go through all cases in turn
+
+ // clip with ymin
+ if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.min;
+ }
+ else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.min;
+ }
+
+ // clip with ymax
+ if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.max;
+ }
+ else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.max;
+ }
+
+ // if the x value was changed we got a rectangle
+ // to fill
+ if (x1 != x1old) {
+ ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
+ // it goes to (x1, y1), but we fill that below
+ }
+
+ // fill triangular section, this sometimes result
+ // in redundant points if (x1, y1) hasn't changed
+ // from previous line to, but we just ignore that
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+
+ // fill the other rectangle if it's there
+ if (x2 != x2old) {
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+ ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
+ }
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+ ctx.lineJoin = "round";
+
+ var lw = series.lines.lineWidth,
+ sw = series.shadowSize;
+ // FIXME: consider another form of shadow when filling is turned on
+ if (lw > 0 && sw > 0) {
+ // draw shadow as a thick and thin line with transparency
+ ctx.lineWidth = sw;
+ ctx.strokeStyle = "rgba(0,0,0,0.1)";
+ // position shadow at angle from the mid of line
+ var angle = Math.PI/18;
+ plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);
+ ctx.lineWidth = sw/2;
+ plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);
+ }
+
+ ctx.lineWidth = lw;
+ ctx.strokeStyle = series.color;
+ var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
+ if (fillStyle) {
+ ctx.fillStyle = fillStyle;
+ plotLineArea(series.datapoints, series.xaxis, series.yaxis);
+ }
+
+ if (lw > 0)
+ plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
+ ctx.restore();
+ }
+
+ function drawSeriesPoints(series) {
+ function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
+ var points = datapoints.points, ps = datapoints.pointsize;
+
+ for (var i = 0; i < points.length; i += ps) {
+ var x = points[i], y = points[i + 1];
+ if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+ continue;
+
+ ctx.beginPath();
+ x = axisx.p2c(x);
+ y = axisy.p2c(y) + offset;
+ if (symbol == "circle")
+ ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
+ else
+ symbol(ctx, x, y, radius, shadow);
+ ctx.closePath();
+
+ if (fillStyle) {
+ ctx.fillStyle = fillStyle;
+ ctx.fill();
+ }
+ ctx.stroke();
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ var lw = series.points.lineWidth,
+ sw = series.shadowSize,
+ radius = series.points.radius,
+ symbol = series.points.symbol;
+ if (lw > 0 && sw > 0) {
+ // draw shadow in two steps
+ var w = sw / 2;
+ ctx.lineWidth = w;
+ ctx.strokeStyle = "rgba(0,0,0,0.1)";
+ plotPoints(series.datapoints, radius, null, w + w/2, true,
+ series.xaxis, series.yaxis, symbol);
+
+ ctx.strokeStyle = "rgba(0,0,0,0.2)";
+ plotPoints(series.datapoints, radius, null, w/2, true,
+ series.xaxis, series.yaxis, symbol);
+ }
+
+ ctx.lineWidth = lw;
+ ctx.strokeStyle = series.color;
+ plotPoints(series.datapoints, radius,
+ getFillStyle(series.points, series.color), 0, false,
+ series.xaxis, series.yaxis, symbol);
+ ctx.restore();
+ }
+
+ function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
+ var left, right, bottom, top,
+ drawLeft, drawRight, drawTop, drawBottom,
+ tmp;
+
+ // in horizontal mode, we start the bar from the left
+ // instead of from the bottom so it appears to be
+ // horizontal rather than vertical
+ if (horizontal) {
+ drawBottom = drawRight = drawTop = true;
+ drawLeft = false;
+ left = b;
+ right = x;
+ top = y + barLeft;
+ bottom = y + barRight;
+
+ // account for negative bars
+ if (right < left) {
+ tmp = right;
+ right = left;
+ left = tmp;
+ drawLeft = true;
+ drawRight = false;
+ }
+ }
+ else {
+ drawLeft = drawRight = drawTop = true;
+ drawBottom = false;
+ left = x + barLeft;
+ right = x + barRight;
+ bottom = b;
+ top = y;
+
+ // account for negative bars
+ if (top < bottom) {
+ tmp = top;
+ top = bottom;
+ bottom = tmp;
+ drawBottom = true;
+ drawTop = false;
+ }
+ }
+
+ // clip
+ if (right < axisx.min || left > axisx.max ||
+ top < axisy.min || bottom > axisy.max)
+ return;
+
+ if (left < axisx.min) {
+ left = axisx.min;
+ drawLeft = false;
+ }
+
+ if (right > axisx.max) {
+ right = axisx.max;
+ drawRight = false;
+ }
+
+ if (bottom < axisy.min) {
+ bottom = axisy.min;
+ drawBottom = false;
+ }
+
+ if (top > axisy.max) {
+ top = axisy.max;
+ drawTop = false;
+ }
+
+ left = axisx.p2c(left);
+ bottom = axisy.p2c(bottom);
+ right = axisx.p2c(right);
+ top = axisy.p2c(top);
+
+ // fill the bar
+ if (fillStyleCallback) {
+ c.beginPath();
+ c.moveTo(left, bottom);
+ c.lineTo(left, top);
+ c.lineTo(right, top);
+ c.lineTo(right, bottom);
+ c.fillStyle = fillStyleCallback(bottom, top);
+ c.fill();
+ }
+
+ // draw outline
+ if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
+ c.beginPath();
+
+ // FIXME: inline moveTo is buggy with excanvas
+ c.moveTo(left, bottom + offset);
+ if (drawLeft)
+ c.lineTo(left, top + offset);
+ else
+ c.moveTo(left, top + offset);
+ if (drawTop)
+ c.lineTo(right, top + offset);
+ else
+ c.moveTo(right, top + offset);
+ if (drawRight)
+ c.lineTo(right, bottom + offset);
+ else
+ c.moveTo(right, bottom + offset);
+ if (drawBottom)
+ c.lineTo(left, bottom + offset);
+ else
+ c.moveTo(left, bottom + offset);
+ c.stroke();
+ }
+ }
+
+ function drawSeriesBars(series) {
+ function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {
+ var points = datapoints.points, ps = datapoints.pointsize;
+
+ for (var i = 0; i < points.length; i += ps) {
+ if (points[i] == null)
+ continue;
+ drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ // FIXME: figure out a way to add shadows (for instance along the right edge)
+ ctx.lineWidth = series.bars.lineWidth;
+ ctx.strokeStyle = series.color;
+ var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
+ var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
+ plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
+ ctx.restore();
+ }
+
+ function getFillStyle(filloptions, seriesColor, bottom, top) {
+ var fill = filloptions.fill;
+ if (!fill)
+ return null;
+
+ if (filloptions.fillColor)
+ return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
+
+ var c = $.color.parse(seriesColor);
+ c.a = typeof fill == "number" ? fill : 0.4;
+ c.normalize();
+ return c.toString();
+ }
+
+ function insertLegend() {
+ placeholder.find(".legend").remove();
+
+ if (!options.legend.show)
+ return;
+
+ var fragments = [], rowStarted = false,
+ lf = options.legend.labelFormatter, s, label;
+ for (var i = 0; i < series.length; ++i) {
+ s = series[i];
+ label = s.label;
+ if (!label)
+ continue;
+
+ if (i % options.legend.noColumns == 0) {
+ if (rowStarted)
+ fragments.push('</tr>');
+ fragments.push('<tr>');
+ rowStarted = true;
+ }
+
+ if (lf)
+ label = lf(label, s);
+
+ fragments.push(
+ '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + s.color + ';overflow:hidden"></div></div></td>' +
+ '<td class="legendLabel">' + label + '</td>');
+ }
+ if (rowStarted)
+ fragments.push('</tr>');
+
+ if (fragments.length == 0)
+ return;
+
+ var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
+ if (options.legend.container != null)
+ $(options.legend.container).html(table);
+ else {
+ var pos = "",
+ p = options.legend.position,
+ m = options.legend.margin;
+ if (m[0] == null)
+ m = [m, m];
+ if (p.charAt(0) == "n")
+ pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
+ else if (p.charAt(0) == "s")
+ pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
+ if (p.charAt(1) == "e")
+ pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
+ else if (p.charAt(1) == "w")
+ pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
+ var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);
+ if (options.legend.backgroundOpacity != 0.0) {
+ // put in the transparent background
+ // separately to avoid blended labels and
+ // label boxes
+ var c = options.legend.backgroundColor;
+ if (c == null) {
+ c = options.grid.backgroundColor;
+ if (c && typeof c == "string")
+ c = $.color.parse(c);
+ else
+ c = $.color.extract(legend, 'background-color');
+ c.a = 1;
+ c = c.toString();
+ }
+ var div = legend.children();
+ $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
+ }
+ }
+ }
+
+
+ // interactive features
+
+ var highlights = [],
+ redrawTimeout = null;
+
+ // returns the data item the mouse is over, or null if none is found
+ function findNearbyItem(mouseX, mouseY, seriesFilter) {
+ var maxDistance = options.grid.mouseActiveRadius,
+ smallestDistance = maxDistance * maxDistance + 1,
+ item = null, foundPoint = false, i, j;
+
+ for (i = series.length - 1; i >= 0; --i) {
+ if (!seriesFilter(series[i]))
+ continue;
+
+ var s = series[i],
+ axisx = s.xaxis,
+ axisy = s.yaxis,
+ points = s.datapoints.points,
+ ps = s.datapoints.pointsize,
+ mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
+ my = axisy.c2p(mouseY),
+ maxx = maxDistance / axisx.scale,
+ maxy = maxDistance / axisy.scale;
+
+ // with inverse transforms, we can't use the maxx/maxy
+ // optimization, sadly
+ if (axisx.options.inverseTransform)
+ maxx = Number.MAX_VALUE;
+ if (axisy.options.inverseTransform)
+ maxy = Number.MAX_VALUE;
+
+ if (s.lines.show || s.points.show) {
+ for (j = 0; j < points.length; j += ps) {
+ var x = points[j], y = points[j + 1];
+ if (x == null)
+ continue;
+
+ // For points and lines, the cursor must be within a
+ // certain distance to the data point
+ if (x - mx > maxx || x - mx < -maxx ||
+ y - my > maxy || y - my < -maxy)
+ continue;
+
+ // We have to calculate distances in pixels, not in
+ // data units, because the scales of the axes may be different
+ var dx = Math.abs(axisx.p2c(x) - mouseX),
+ dy = Math.abs(axisy.p2c(y) - mouseY),
+ dist = dx * dx + dy * dy; // we save the sqrt
+
+ // use <= to ensure last point takes precedence
+ // (last generally means on top of)
+ if (dist < smallestDistance) {
+ smallestDistance = dist;
+ item = [i, j / ps];
+ }
+ }
+ }
+
+ if (s.bars.show && !item) { // no other point can be nearby
+ var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
+ barRight = barLeft + s.bars.barWidth;
+
+ for (j = 0; j < points.length; j += ps) {
+ var x = points[j], y = points[j + 1], b = points[j + 2];
+ if (x == null)
+ continue;
+
+ // for a bar graph, the cursor must be inside the bar
+ if (series[i].bars.horizontal ?
+ (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
+ my >= y + barLeft && my <= y + barRight) :
+ (mx >= x + barLeft && mx <= x + barRight &&
+ my >= Math.min(b, y) && my <= Math.max(b, y)))
+ item = [i, j / ps];
+ }
+ }
+ }
+
+ if (item) {
+ i = item[0];
+ j = item[1];
+ ps = series[i].datapoints.pointsize;
+
+ return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
+ dataIndex: j,
+ series: series[i],
+ seriesIndex: i };
+ }
+
+ return null;
+ }
+
+ function onMouseMove(e) {
+ if (options.grid.hoverable)
+ triggerClickHoverEvent("plothover", e,
+ function (s) { return s["hoverable"] != false; });
+ }
+
+ function onMouseLeave(e) {
+ if (options.grid.hoverable)
+ triggerClickHoverEvent("plothover", e,
+ function (s) { return false; });
+ }
+
+ function onClick(e) {
+ triggerClickHoverEvent("plotclick", e,
+ function (s) { return s["clickable"] != false; });
+ }
+
+ // trigger click or hover event (they send the same parameters
+ // so we share their code)
+ function triggerClickHoverEvent(eventname, event, seriesFilter) {
+ var offset = eventHolder.offset(),
+ canvasX = event.pageX - offset.left - plotOffset.left,
+ canvasY = event.pageY - offset.top - plotOffset.top,
+ pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
+
+ pos.pageX = event.pageX;
+ pos.pageY = event.pageY;
+
+ var item = findNearbyItem(canvasX, canvasY, seriesFilter);
+
+ if (item) {
+ // fill in mouse pos for any listeners out there
+ item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);
+ item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);
+ }
+
+ if (options.grid.autoHighlight) {
+ // clear auto-highlights
+ for (var i = 0; i < highlights.length; ++i) {
+ var h = highlights[i];
+ if (h.auto == eventname &&
+ !(item && h.series == item.series &&
+ h.point[0] == item.datapoint[0] &&
+ h.point[1] == item.datapoint[1]))
+ unhighlight(h.series, h.point);
+ }
+
+ if (item)
+ highlight(item.series, item.datapoint, eventname);
+ }
+
+ placeholder.trigger(eventname, [ pos, item ]);
+ }
+
+ function triggerRedrawOverlay() {
+ if (!redrawTimeout)
+ redrawTimeout = setTimeout(drawOverlay, 30);
+ }
+
+ function drawOverlay() {
+ redrawTimeout = null;
+
+ // draw highlights
+ octx.save();
+ octx.clearRect(0, 0, canvasWidth, canvasHeight);
+ octx.translate(plotOffset.left, plotOffset.top);
+
+ var i, hi;
+ for (i = 0; i < highlights.length; ++i) {
+ hi = highlights[i];
+
+ if (hi.series.bars.show)
+ drawBarHighlight(hi.series, hi.point);
+ else
+ drawPointHighlight(hi.series, hi.point);
+ }
+ octx.restore();
+
+ executeHooks(hooks.drawOverlay, [octx]);
+ }
+
+ function highlight(s, point, auto) {
+ if (typeof s == "number")
+ s = series[s];
+
+ if (typeof point == "number") {
+ var ps = s.datapoints.pointsize;
+ point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+ }
+
+ var i = indexOfHighlight(s, point);
+ if (i == -1) {
+ highlights.push({ series: s, point: point, auto: auto });
+
+ triggerRedrawOverlay();
+ }
+ else if (!auto)
+ highlights[i].auto = false;
+ }
+
+ function unhighlight(s, point) {
+ if (s == null && point == null) {
+ highlights = [];
+ triggerRedrawOverlay();
+ }
+
+ if (typeof s == "number")
+ s = series[s];
+
+ if (typeof point == "number")
+ point = s.data[point];
+
+ var i = indexOfHighlight(s, point);
+ if (i != -1) {
+ highlights.splice(i, 1);
+
+ triggerRedrawOverlay();
+ }
+ }
+
+ function indexOfHighlight(s, p) {
+ for (var i = 0; i < highlights.length; ++i) {
+ var h = highlights[i];
+ if (h.series == s && h.point[0] == p[0]
+ && h.point[1] == p[1])
+ return i;
+ }
+ return -1;
+ }
+
+ function drawPointHighlight(series, point) {
+ var x = point[0], y = point[1],
+ axisx = series.xaxis, axisy = series.yaxis;
+
+ if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+ return;
+
+ var pointRadius = series.points.radius + series.points.lineWidth / 2;
+ octx.lineWidth = pointRadius;
+ octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var radius = 1.5 * pointRadius,
+ x = axisx.p2c(x),
+ y = axisy.p2c(y);
+
+ octx.beginPath();
+ if (series.points.symbol == "circle")
+ octx.arc(x, y, radius, 0, 2 * Math.PI, false);
+ else
+ series.points.symbol(octx, x, y, radius, false);
+ octx.closePath();
+ octx.stroke();
+ }
+
+ function drawBarHighlight(series, point) {
+ octx.lineWidth = series.bars.lineWidth;
+ octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var fillStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
+ drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
+ 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
+ }
+
+ function getColorOrGradient(spec, bottom, top, defaultColor) {
+ if (typeof spec == "string")
+ return spec;
+ else {
+ // assume this is a gradient spec; IE currently only
+ // supports a simple vertical gradient properly, so that's
+ // what we support too
+ var gradient = ctx.createLinearGradient(0, top, 0, bottom);
+
+ for (var i = 0, l = spec.colors.length; i < l; ++i) {
+ var c = spec.colors[i];
+ if (typeof c != "string") {
+ var co = $.color.parse(defaultColor);
+ if (c.brightness != null)
+ co = co.scale('rgb', c.brightness)
+ if (c.opacity != null)
+ co.a *= c.opacity;
+ c = co.toString();
+ }
+ gradient.addColorStop(i / (l - 1), c);
+ }
+
+ return gradient;
+ }
+ }
+ }
+
+ $.plot = function(placeholder, data, options) {
+ //var t0 = new Date();
+ var plot = new Plot($(placeholder), data, options, $.plot.plugins);
+ //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
+ return plot;
+ };
+
+ $.plot.version = "0.7";
+
+ $.plot.plugins = [];
+
+ // returns a string with the date d formatted according to fmt
+ $.plot.formatDate = function(d, fmt, monthNames) {
+ var leftPad = function(n) {
+ n = "" + n;
+ return n.length == 1 ? "0" + n : n;
+ };
+
+ var r = [];
+ var escape = false, padNext = false;
+ var hours = d.getUTCHours();
+ var isAM = hours < 12;
+ if (monthNames == null)
+ monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+
+ if (fmt.search(/%p|%P/) != -1) {
+ if (hours > 12) {
+ hours = hours - 12;
+ } else if (hours == 0) {
+ hours = 12;
+ }
+ }
+ for (var i = 0; i < fmt.length; ++i) {
+ var c = fmt.charAt(i);
+
+ if (escape) {
+ switch (c) {
+ case 'h': c = "" + hours; break;
+ case 'H': c = leftPad(hours); break;
+ case 'M': c = leftPad(d.getUTCMinutes()); break;
+ case 'S': c = leftPad(d.getUTCSeconds()); break;
+ case 'd': c = "" + d.getUTCDate(); break;
+ case 'm': c = "" + (d.getUTCMonth() + 1); break;
+ case 'y': c = "" + d.getUTCFullYear(); break;
+ case 'b': c = "" + monthNames[d.getUTCMonth()]; break;
+ case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
+ case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
+ case '0': c = ""; padNext = true; break;
+ }
+ if (c && padNext) {
+ c = leftPad(c);
+ padNext = false;
+ }
+ r.push(c);
+ if (!padNext)
+ escape = false;
+ }
+ else {
+ if (c == "%")
+ escape = true;
+ else
+ r.push(c);
+ }
+ }
+ return r.join("");
+ };
+
+ // round to nearby lower multiple of base
+ function floorInBase(n, base) {
+ return base * Math.floor(n / base);
+ }
+
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js
new file mode 100644
index 00000000..b46c03c2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js
@@ -0,0 +1,750 @@
+/*
+Flot plugin for rendering pie charts. The plugin assumes the data is
+coming is as a single data value for each series, and each of those
+values is a positive value or zero (negative numbers don't make
+any sense and will cause strange effects). The data values do
+NOT need to be passed in as percentage values because it
+internally calculates the total and percentages.
+
+* Created by Brian Medendorp, June 2009
+* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
+
+* Changes:
+ 2009-10-22: lineJoin set to round
+ 2009-10-23: IE full circle fix, donut
+ 2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
+ 2009-11-17: Added IE hover capability submitted by Anthony Aragues
+ 2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
+
+
+Available options are:
+series: {
+ pie: {
+ show: true/false
+ radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
+ innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
+ startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
+ tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
+ offset: {
+ top: integer value to move the pie up or down
+ left: integer value to move the pie left or right, or 'auto'
+ },
+ stroke: {
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
+ width: integer pixel width of the stroke
+ },
+ label: {
+ show: true/false, or 'auto'
+ formatter: a user-defined function that modifies the text/style of the label text
+ radius: 0-1 for percentage of fullsize, or a specified pixel length
+ background: {
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
+ opacity: 0-1
+ },
+ threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
+ },
+ combine: {
+ threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
+ label: any text value of what the combined slice should be labeled
+ }
+ highlight: {
+ opacity: 0-1
+ }
+ }
+}
+
+More detail and specific examples can be found in the included HTML file.
+
+*/
+
+(function ($)
+{
+ function init(plot) // this is the "body" of the plugin
+ {
+ var canvas = null;
+ var target = null;
+ var maxRadius = null;
+ var centerLeft = null;
+ var centerTop = null;
+ var total = 0;
+ var redraw = true;
+ var redrawAttempts = 10;
+ var shrink = 0.95;
+ var legendWidth = 0;
+ var processed = false;
+ var raw = false;
+
+ // interactive variables
+ var highlights = [];
+
+ // add hook to determine if pie plugin in enabled, and then perform necessary operations
+ plot.hooks.processOptions.push(checkPieEnabled);
+ plot.hooks.bindEvents.push(bindEvents);
+
+ // check to see if the pie plugin is enabled
+ function checkPieEnabled(plot, options)
+ {
+ if (options.series.pie.show)
+ {
+ //disable grid
+ options.grid.show = false;
+
+ // set labels.show
+ if (options.series.pie.label.show=='auto')
+ if (options.legend.show)
+ options.series.pie.label.show = false;
+ else
+ options.series.pie.label.show = true;
+
+ // set radius
+ if (options.series.pie.radius=='auto')
+ if (options.series.pie.label.show)
+ options.series.pie.radius = 3/4;
+ else
+ options.series.pie.radius = 1;
+
+ // ensure sane tilt
+ if (options.series.pie.tilt>1)
+ options.series.pie.tilt=1;
+ if (options.series.pie.tilt<0)
+ options.series.pie.tilt=0;
+
+ // add processData hook to do transformations on the data
+ plot.hooks.processDatapoints.push(processDatapoints);
+ plot.hooks.drawOverlay.push(drawOverlay);
+
+ // add draw hook
+ plot.hooks.draw.push(draw);
+ }
+ }
+
+ // bind hoverable events
+ function bindEvents(plot, eventHolder)
+ {
+ var options = plot.getOptions();
+
+ if (options.series.pie.show && options.grid.hoverable)
+ eventHolder.unbind('mousemove').mousemove(onMouseMove);
+
+ if (options.series.pie.show && options.grid.clickable)
+ eventHolder.unbind('click').click(onClick);
+ }
+
+
+ // debugging function that prints out an object
+ function alertObject(obj)
+ {
+ var msg = '';
+ function traverse(obj, depth)
+ {
+ if (!depth)
+ depth = 0;
+ for (var i = 0; i < obj.length; ++i)
+ {
+ for (var j=0; j<depth; j++)
+ msg += '\t';
+
+ if( typeof obj[i] == "object")
+ { // its an object
+ msg += ''+i+':\n';
+ traverse(obj[i], depth+1);
+ }
+ else
+ { // its a value
+ msg += ''+i+': '+obj[i]+'\n';
+ }
+ }
+ }
+ traverse(obj);
+ alert(msg);
+ }
+
+ function calcTotal(data)
+ {
+ for (var i = 0; i < data.length; ++i)
+ {
+ var item = parseFloat(data[i].data[0][1]);
+ if (item)
+ total += item;
+ }
+ }
+
+ function processDatapoints(plot, series, data, datapoints)
+ {
+ if (!processed)
+ {
+ processed = true;
+
+ canvas = plot.getCanvas();
+ target = $(canvas).parent();
+ options = plot.getOptions();
+
+ plot.setData(combine(plot.getData()));
+ }
+ }
+
+ function setupPie()
+ {
+ legendWidth = target.children().filter('.legend').children().width();
+
+ // calculate maximum radius and center point
+ maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
+ centerTop = (canvas.height/2)+options.series.pie.offset.top;
+ centerLeft = (canvas.width/2);
+
+ if (options.series.pie.offset.left=='auto')
+ if (options.legend.position.match('w'))
+ centerLeft += legendWidth/2;
+ else
+ centerLeft -= legendWidth/2;
+ else
+ centerLeft += options.series.pie.offset.left;
+
+ if (centerLeft<maxRadius)
+ centerLeft = maxRadius;
+ else if (centerLeft>canvas.width-maxRadius)
+ centerLeft = canvas.width-maxRadius;
+ }
+
+ function fixData(data)
+ {
+ for (var i = 0; i < data.length; ++i)
+ {
+ if (typeof(data[i].data)=='number')
+ data[i].data = [[1,data[i].data]];
+ else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
+ {
+ if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
+ data[i].label = data[i].data.label; // fix weirdness coming from flot
+ data[i].data = [[1,0]];
+
+ }
+ }
+ return data;
+ }
+
+ function combine(data)
+ {
+ data = fixData(data);
+ calcTotal(data);
+ var combined = 0;
+ var numCombined = 0;
+ var color = options.series.pie.combine.color;
+
+ var newdata = [];
+ for (var i = 0; i < data.length; ++i)
+ {
+ // make sure its a number
+ data[i].data[0][1] = parseFloat(data[i].data[0][1]);
+ if (!data[i].data[0][1])
+ data[i].data[0][1] = 0;
+
+ if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
+ {
+ combined += data[i].data[0][1];
+ numCombined++;
+ if (!color)
+ color = data[i].color;
+ }
+ else
+ {
+ newdata.push({
+ data: [[1,data[i].data[0][1]]],
+ color: data[i].color,
+ label: data[i].label,
+ angle: (data[i].data[0][1]*(Math.PI*2))/total,
+ percent: (data[i].data[0][1]/total*100)
+ });
+ }
+ }
+ if (numCombined>0)
+ newdata.push({
+ data: [[1,combined]],
+ color: color,
+ label: options.series.pie.combine.label,
+ angle: (combined*(Math.PI*2))/total,
+ percent: (combined/total*100)
+ });
+ return newdata;
+ }
+
+ function draw(plot, newCtx)
+ {
+ if (!target) return; // if no series were passed
+ ctx = newCtx;
+
+ setupPie();
+ var slices = plot.getData();
+
+ var attempts = 0;
+ while (redraw && attempts<redrawAttempts)
+ {
+ redraw = false;
+ if (attempts>0)
+ maxRadius *= shrink;
+ attempts += 1;
+ clear();
+ if (options.series.pie.tilt<=0.8)
+ drawShadow();
+ drawPie();
+ }
+ if (attempts >= redrawAttempts) {
+ clear();
+ target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
+ }
+
+ if ( plot.setSeries && plot.insertLegend )
+ {
+ plot.setSeries(slices);
+ plot.insertLegend();
+ }
+
+ // we're actually done at this point, just defining internal functions at this point
+
+ function clear()
+ {
+ ctx.clearRect(0,0,canvas.width,canvas.height);
+ target.children().filter('.pieLabel, .pieLabelBackground').remove();
+ }
+
+ function drawShadow()
+ {
+ var shadowLeft = 5;
+ var shadowTop = 15;
+ var edge = 10;
+ var alpha = 0.02;
+
+ // set radius
+ if (options.series.pie.radius>1)
+ var radius = options.series.pie.radius;
+ else
+ var radius = maxRadius * options.series.pie.radius;
+
+ if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
+ return; // shadow would be outside canvas, so don't draw it
+
+ ctx.save();
+ ctx.translate(shadowLeft,shadowTop);
+ ctx.globalAlpha = alpha;
+ ctx.fillStyle = '#000';
+
+ // center and rotate to starting position
+ ctx.translate(centerLeft,centerTop);
+ ctx.scale(1, options.series.pie.tilt);
+
+ //radius -= edge;
+ for (var i=1; i<=edge; i++)
+ {
+ ctx.beginPath();
+ ctx.arc(0,0,radius,0,Math.PI*2,false);
+ ctx.fill();
+ radius -= i;
+ }
+
+ ctx.restore();
+ }
+
+ function drawPie()
+ {
+ startAngle = Math.PI*options.series.pie.startAngle;
+
+ // set radius
+ if (options.series.pie.radius>1)
+ var radius = options.series.pie.radius;
+ else
+ var radius = maxRadius * options.series.pie.radius;
+
+ // center and rotate to starting position
+ ctx.save();
+ ctx.translate(centerLeft,centerTop);
+ ctx.scale(1, options.series.pie.tilt);
+ //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
+
+ // draw slices
+ ctx.save();
+ var currentAngle = startAngle;
+ for (var i = 0; i < slices.length; ++i)
+ {
+ slices[i].startAngle = currentAngle;
+ drawSlice(slices[i].angle, slices[i].color, true);
+ }
+ ctx.restore();
+
+ // draw slice outlines
+ ctx.save();
+ ctx.lineWidth = options.series.pie.stroke.width;
+ currentAngle = startAngle;
+ for (var i = 0; i < slices.length; ++i)
+ drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
+ ctx.restore();
+
+ // draw donut hole
+ drawDonutHole(ctx);
+
+ // draw labels
+ if (options.series.pie.label.show)
+ drawLabels();
+
+ // restore to original state
+ ctx.restore();
+
+ function drawSlice(angle, color, fill)
+ {
+ if (angle<=0)
+ return;
+
+ if (fill)
+ ctx.fillStyle = color;
+ else
+ {
+ ctx.strokeStyle = color;
+ ctx.lineJoin = 'round';
+ }
+
+ ctx.beginPath();
+ if (Math.abs(angle - Math.PI*2) > 0.000000001)
+ ctx.moveTo(0,0); // Center of the pie
+ else if ($.browser.msie)
+ angle -= 0.0001;
+ //ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
+ ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
+ ctx.closePath();
+ //ctx.rotate(angle); // This doesn't work properly in Opera
+ currentAngle += angle;
+
+ if (fill)
+ ctx.fill();
+ else
+ ctx.stroke();
+ }
+
+ function drawLabels()
+ {
+ var currentAngle = startAngle;
+
+ // set radius
+ if (options.series.pie.label.radius>1)
+ var radius = options.series.pie.label.radius;
+ else
+ var radius = maxRadius * options.series.pie.label.radius;
+
+ for (var i = 0; i < slices.length; ++i)
+ {
+ if (slices[i].percent >= options.series.pie.label.threshold*100)
+ drawLabel(slices[i], currentAngle, i);
+ currentAngle += slices[i].angle;
+ }
+
+ function drawLabel(slice, startAngle, index)
+ {
+ if (slice.data[0][1]==0)
+ return;
+
+ // format label text
+ var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
+ if (lf)
+ text = lf(slice.label, slice);
+ else
+ text = slice.label;
+ if (plf)
+ text = plf(text, slice);
+
+ var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
+ var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
+ var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
+
+ var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
+ target.append(html);
+ var label = target.children('#pieLabel'+index);
+ var labelTop = (y - label.height()/2);
+ var labelLeft = (x - label.width()/2);
+ label.css('top', labelTop);
+ label.css('left', labelLeft);
+
+ // check to make sure that the label is not outside the canvas
+ if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
+ redraw = true;
+
+ if (options.series.pie.label.background.opacity != 0) {
+ // put in the transparent background separately to avoid blended labels and label boxes
+ var c = options.series.pie.label.background.color;
+ if (c == null) {
+ c = slice.color;
+ }
+ var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
+ $('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
+ }
+ } // end individual label function
+ } // end drawLabels function
+ } // end drawPie function
+ } // end draw function
+
+ // Placed here because it needs to be accessed from multiple locations
+ function drawDonutHole(layer)
+ {
+ // draw donut hole
+ if(options.series.pie.innerRadius > 0)
+ {
+ // subtract the center
+ layer.save();
+ innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
+ layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
+ layer.beginPath();
+ layer.fillStyle = options.series.pie.stroke.color;
+ layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+ layer.fill();
+ layer.closePath();
+ layer.restore();
+
+ // add inner stroke
+ layer.save();
+ layer.beginPath();
+ layer.strokeStyle = options.series.pie.stroke.color;
+ layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+ layer.stroke();
+ layer.closePath();
+ layer.restore();
+ // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
+ }
+ }
+
+ //-- Additional Interactive related functions --
+
+ function isPointInPoly(poly, pt)
+ {
+ for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
+ ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
+ && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
+ && (c = !c);
+ return c;
+ }
+
+ function findNearbySlice(mouseX, mouseY)
+ {
+ var slices = plot.getData(),
+ options = plot.getOptions(),
+ radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+
+ for (var i = 0; i < slices.length; ++i)
+ {
+ var s = slices[i];
+
+ if(s.pie.show)
+ {
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(0,0); // Center of the pie
+ //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
+ ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
+ ctx.closePath();
+ x = mouseX-centerLeft;
+ y = mouseY-centerTop;
+ if(ctx.isPointInPath)
+ {
+ if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
+ {
+ //alert('found slice!');
+ ctx.restore();
+ return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+ }
+ }
+ else
+ {
+ // excanvas for IE doesn;t support isPointInPath, this is a workaround.
+ p1X = (radius * Math.cos(s.startAngle));
+ p1Y = (radius * Math.sin(s.startAngle));
+ p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
+ p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
+ p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
+ p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
+ p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
+ p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
+ p5X = (radius * Math.cos(s.startAngle+s.angle));
+ p5Y = (radius * Math.sin(s.startAngle+s.angle));
+ arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
+ arrPoint = [x,y];
+ // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
+ if(isPointInPoly(arrPoly, arrPoint))
+ {
+ ctx.restore();
+ return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+ }
+ }
+ ctx.restore();
+ }
+ }
+
+ return null;
+ }
+
+ function onMouseMove(e)
+ {
+ triggerClickHoverEvent('plothover', e);
+ }
+
+ function onClick(e)
+ {
+ triggerClickHoverEvent('plotclick', e);
+ }
+
+ // trigger click or hover event (they send the same parameters so we share their code)
+ function triggerClickHoverEvent(eventname, e)
+ {
+ var offset = plot.offset(),
+ canvasX = parseInt(e.pageX - offset.left),
+ canvasY = parseInt(e.pageY - offset.top),
+ item = findNearbySlice(canvasX, canvasY);
+
+ if (options.grid.autoHighlight)
+ {
+ // clear auto-highlights
+ for (var i = 0; i < highlights.length; ++i)
+ {
+ var h = highlights[i];
+ if (h.auto == eventname && !(item && h.series == item.series))
+ unhighlight(h.series);
+ }
+ }
+
+ // highlight the slice
+ if (item)
+ highlight(item.series, eventname);
+
+ // trigger any hover bind events
+ var pos = { pageX: e.pageX, pageY: e.pageY };
+ target.trigger(eventname, [ pos, item ]);
+ }
+
+ function highlight(s, auto)
+ {
+ if (typeof s == "number")
+ s = series[s];
+
+ var i = indexOfHighlight(s);
+ if (i == -1)
+ {
+ highlights.push({ series: s, auto: auto });
+ plot.triggerRedrawOverlay();
+ }
+ else if (!auto)
+ highlights[i].auto = false;
+ }
+
+ function unhighlight(s)
+ {
+ if (s == null)
+ {
+ highlights = [];
+ plot.triggerRedrawOverlay();
+ }
+
+ if (typeof s == "number")
+ s = series[s];
+
+ var i = indexOfHighlight(s);
+ if (i != -1)
+ {
+ highlights.splice(i, 1);
+ plot.triggerRedrawOverlay();
+ }
+ }
+
+ function indexOfHighlight(s)
+ {
+ for (var i = 0; i < highlights.length; ++i)
+ {
+ var h = highlights[i];
+ if (h.series == s)
+ return i;
+ }
+ return -1;
+ }
+
+ function drawOverlay(plot, octx)
+ {
+ //alert(options.series.pie.radius);
+ var options = plot.getOptions();
+ //alert(options.series.pie.radius);
+
+ var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+
+ octx.save();
+ octx.translate(centerLeft, centerTop);
+ octx.scale(1, options.series.pie.tilt);
+
+ for (i = 0; i < highlights.length; ++i)
+ drawHighlight(highlights[i].series);
+
+ drawDonutHole(octx);
+
+ octx.restore();
+
+ function drawHighlight(series)
+ {
+ if (series.angle < 0) return;
+
+ //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
+ octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
+
+ octx.beginPath();
+ if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
+ octx.moveTo(0,0); // Center of the pie
+ octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
+ octx.closePath();
+ octx.fill();
+ }
+
+ }
+
+ } // end init (plugin body)
+
+ // define pie specific options and their default values
+ var options = {
+ series: {
+ pie: {
+ show: false,
+ radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
+ innerRadius:0, /* for donut */
+ startAngle: 3/2,
+ tilt: 1,
+ offset: {
+ top: 0,
+ left: 'auto'
+ },
+ stroke: {
+ color: '#FFF',
+ width: 1
+ },
+ label: {
+ show: 'auto',
+ formatter: function(label, slice){
+ return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
+ }, // formatter function
+ radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
+ background: {
+ color: null,
+ opacity: 0
+ },
+ threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
+ },
+ combine: {
+ threshold: -1, // percentage at which to combine little slices into one larger slice
+ color: null, // color to give the new slice (auto-generated if null)
+ label: 'Other' // label to give the new slice
+ },
+ highlight: {
+ //color: '#FFF', // will add this functionality once parseColor is available
+ opacity: 0.5
+ }
+ }
+ }
+ };
+
+ $.plot.plugins.push({
+ init: init,
+ options: options,
+ name: "pie",
+ version: "1.0"
+ });
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js
new file mode 100644
index 00000000..7f7b3269
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js
@@ -0,0 +1,344 @@
+/*
+Flot plugin for selecting regions.
+
+The plugin defines the following options:
+
+ selection: {
+ mode: null or "x" or "y" or "xy",
+ color: color
+ }
+
+Selection support is enabled by setting the mode to one of "x", "y" or
+"xy". In "x" mode, the user will only be able to specify the x range,
+similarly for "y" mode. For "xy", the selection becomes a rectangle
+where both ranges can be specified. "color" is color of the selection
+(if you need to change the color later on, you can get to it with
+plot.getOptions().selection.color).
+
+When selection support is enabled, a "plotselected" event will be
+emitted on the DOM element you passed into the plot function. The
+event handler gets a parameter with the ranges selected on the axes,
+like this:
+
+ placeholder.bind("plotselected", function(event, ranges) {
+ alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+ // similar for yaxis - with multiple axes, the extra ones are in
+ // x2axis, x3axis, ...
+ });
+
+The "plotselected" event is only fired when the user has finished
+making the selection. A "plotselecting" event is fired during the
+process with the same parameters as the "plotselected" event, in case
+you want to know what's happening while it's happening,
+
+A "plotunselected" event with no arguments is emitted when the user
+clicks the mouse to remove the selection.
+
+The plugin allso adds the following methods to the plot object:
+
+- setSelection(ranges, preventEvent)
+
+ Set the selection rectangle. The passed in ranges is on the same
+ form as returned in the "plotselected" event. If the selection mode
+ is "x", you should put in either an xaxis range, if the mode is "y"
+ you need to put in an yaxis range and both xaxis and yaxis if the
+ selection mode is "xy", like this:
+
+ setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+
+ setSelection will trigger the "plotselected" event when called. If
+ you don't want that to happen, e.g. if you're inside a
+ "plotselected" handler, pass true as the second parameter. If you
+ are using multiple axes, you can specify the ranges on any of those,
+ e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
+ first one it sees.
+
+- clearSelection(preventEvent)
+
+ Clear the selection rectangle. Pass in true to avoid getting a
+ "plotunselected" event.
+
+- getSelection()
+
+ Returns the current selection in the same format as the
+ "plotselected" event. If there's currently no selection, the
+ function returns null.
+
+*/
+
+(function ($) {
+ function init(plot) {
+ var selection = {
+ first: { x: -1, y: -1}, second: { x: -1, y: -1},
+ show: false,
+ active: false
+ };
+
+ // FIXME: The drag handling implemented here should be
+ // abstracted out, there's some similar code from a library in
+ // the navigation plugin, this should be massaged a bit to fit
+ // the Flot cases here better and reused. Doing this would
+ // make this plugin much slimmer.
+ var savedhandlers = {};
+
+ var mouseUpHandler = null;
+
+ function onMouseMove(e) {
+ if (selection.active) {
+ updateSelection(e);
+
+ plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
+ }
+ }
+
+ function onMouseDown(e) {
+ if (e.which != 1) // only accept left-click
+ return;
+
+ // cancel out any text selections
+ document.body.focus();
+
+ // prevent text selection and drag in old-school browsers
+ if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
+ savedhandlers.onselectstart = document.onselectstart;
+ document.onselectstart = function () { return false; };
+ }
+ if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
+ savedhandlers.ondrag = document.ondrag;
+ document.ondrag = function () { return false; };
+ }
+
+ setSelectionPos(selection.first, e);
+
+ selection.active = true;
+
+ // this is a bit silly, but we have to use a closure to be
+ // able to whack the same handler again
+ mouseUpHandler = function (e) { onMouseUp(e); };
+
+ $(document).one("mouseup", mouseUpHandler);
+ }
+
+ function onMouseUp(e) {
+ mouseUpHandler = null;
+
+ // revert drag stuff for old-school browsers
+ if (document.onselectstart !== undefined)
+ document.onselectstart = savedhandlers.onselectstart;
+ if (document.ondrag !== undefined)
+ document.ondrag = savedhandlers.ondrag;
+
+ // no more dragging
+ selection.active = false;
+ updateSelection(e);
+
+ if (selectionIsSane())
+ triggerSelectedEvent();
+ else {
+ // this counts as a clear
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
+ plot.getPlaceholder().trigger("plotselecting", [ null ]);
+ }
+
+ return false;
+ }
+
+ function getSelection() {
+ if (!selectionIsSane())
+ return null;
+
+ var r = {}, c1 = selection.first, c2 = selection.second;
+ $.each(plot.getAxes(), function (name, axis) {
+ if (axis.used) {
+ var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
+ r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
+ }
+ });
+ return r;
+ }
+
+ function triggerSelectedEvent() {
+ var r = getSelection();
+
+ plot.getPlaceholder().trigger("plotselected", [ r ]);
+
+ // backwards-compat stuff, to be removed in future
+ if (r.xaxis && r.yaxis)
+ plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
+ }
+
+ function clamp(min, value, max) {
+ return value < min ? min: (value > max ? max: value);
+ }
+
+ function setSelectionPos(pos, e) {
+ var o = plot.getOptions();
+ var offset = plot.getPlaceholder().offset();
+ var plotOffset = plot.getPlotOffset();
+ pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
+ pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
+
+ if (o.selection.mode == "y")
+ pos.x = pos == selection.first ? 0 : plot.width();
+
+ if (o.selection.mode == "x")
+ pos.y = pos == selection.first ? 0 : plot.height();
+ }
+
+ function updateSelection(pos) {
+ if (pos.pageX == null)
+ return;
+
+ setSelectionPos(selection.second, pos);
+ if (selectionIsSane()) {
+ selection.show = true;
+ plot.triggerRedrawOverlay();
+ }
+ else
+ clearSelection(true);
+ }
+
+ function clearSelection(preventEvent) {
+ if (selection.show) {
+ selection.show = false;
+ plot.triggerRedrawOverlay();
+ if (!preventEvent)
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
+ }
+ }
+
+ // function taken from markings support in Flot
+ function extractRange(ranges, coord) {
+ var axis, from, to, key, axes = plot.getAxes();
+
+ for (var k in axes) {
+ axis = axes[k];
+ if (axis.direction == coord) {
+ key = coord + axis.n + "axis";
+ if (!ranges[key] && axis.n == 1)
+ key = coord + "axis"; // support x1axis as xaxis
+ if (ranges[key]) {
+ from = ranges[key].from;
+ to = ranges[key].to;
+ break;
+ }
+ }
+ }
+
+ // backwards-compat stuff - to be removed in future
+ if (!ranges[key]) {
+ axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
+ from = ranges[coord + "1"];
+ to = ranges[coord + "2"];
+ }
+
+ // auto-reverse as an added bonus
+ if (from != null && to != null && from > to) {
+ var tmp = from;
+ from = to;
+ to = tmp;
+ }
+
+ return { from: from, to: to, axis: axis };
+ }
+
+ function setSelection(ranges, preventEvent) {
+ var axis, range, o = plot.getOptions();
+
+ if (o.selection.mode == "y") {
+ selection.first.x = 0;
+ selection.second.x = plot.width();
+ }
+ else {
+ range = extractRange(ranges, "x");
+
+ selection.first.x = range.axis.p2c(range.from);
+ selection.second.x = range.axis.p2c(range.to);
+ }
+
+ if (o.selection.mode == "x") {
+ selection.first.y = 0;
+ selection.second.y = plot.height();
+ }
+ else {
+ range = extractRange(ranges, "y");
+
+ selection.first.y = range.axis.p2c(range.from);
+ selection.second.y = range.axis.p2c(range.to);
+ }
+
+ selection.show = true;
+ plot.triggerRedrawOverlay();
+ if (!preventEvent && selectionIsSane())
+ triggerSelectedEvent();
+ }
+
+ function selectionIsSane() {
+ var minSize = 5;
+ return Math.abs(selection.second.x - selection.first.x) >= minSize &&
+ Math.abs(selection.second.y - selection.first.y) >= minSize;
+ }
+
+ plot.clearSelection = clearSelection;
+ plot.setSelection = setSelection;
+ plot.getSelection = getSelection;
+
+ plot.hooks.bindEvents.push(function(plot, eventHolder) {
+ var o = plot.getOptions();
+ if (o.selection.mode != null) {
+ eventHolder.mousemove(onMouseMove);
+ eventHolder.mousedown(onMouseDown);
+ }
+ });
+
+
+ plot.hooks.drawOverlay.push(function (plot, ctx) {
+ // draw selection
+ if (selection.show && selectionIsSane()) {
+ var plotOffset = plot.getPlotOffset();
+ var o = plot.getOptions();
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ var c = $.color.parse(o.selection.color);
+
+ ctx.strokeStyle = c.scale('a', 0.8).toString();
+ ctx.lineWidth = 1;
+ ctx.lineJoin = "round";
+ ctx.fillStyle = c.scale('a', 0.4).toString();
+
+ var x = Math.min(selection.first.x, selection.second.x),
+ y = Math.min(selection.first.y, selection.second.y),
+ w = Math.abs(selection.second.x - selection.first.x),
+ h = Math.abs(selection.second.y - selection.first.y);
+
+ ctx.fillRect(x, y, w, h);
+ ctx.strokeRect(x, y, w, h);
+
+ ctx.restore();
+ }
+ });
+
+ plot.hooks.shutdown.push(function (plot, eventHolder) {
+ eventHolder.unbind("mousemove", onMouseMove);
+ eventHolder.unbind("mousedown", onMouseDown);
+
+ if (mouseUpHandler)
+ $(document).unbind("mouseup", mouseUpHandler);
+ });
+
+ }
+
+ $.plot.plugins.push({
+ init: init,
+ options: {
+ selection: {
+ mode: null, // one of null, "x", "y" or "xy"
+ color: "#e8cfac"
+ }
+ },
+ name: 'selection',
+ version: '1.1'
+ });
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt
new file mode 100644
index 00000000..11dddd00
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt
new file mode 100644
index 00000000..46d47544
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Adam Shaw
+
+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/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt
new file mode 100644
index 00000000..67068f7c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt
@@ -0,0 +1,322 @@
+
+version 1.5.4 (9/5/12)
+ - made compatible with jQuery 1.8.* (thx archaeron)
+ - bundled with jQuery 1.8.1 and jQuery UI 1.8.23
+
+version 1.5.3 (2/6/12)
+ - fixed dragging issue with jQuery UI 1.8.16 (issue 1168)
+ - bundled with jQuery 1.7.1 and jQuery UI 1.8.17
+
+version 1.5.2 (8/21/11)
+ - correctly process UTC "Z" ISO8601 date strings (issue 750)
+
+version 1.5.1 (4/9/11)
+ - more flexible ISO8601 date parsing (issue 814)
+ - more flexible parsing of UNIX timestamps (issue 826)
+ - FullCalendar now buildable from source on a Mac (issue 795)
+ - FullCalendar QA'd in FF4 (issue 883)
+ - upgraded to jQuery 1.5.2 (which supports IE9) and jQuery UI 1.8.11
+
+version 1.5 (3/19/11)
+ - slicker default styling for buttons
+ - reworked a lot of the calendar's HTML and accompanying CSS
+ (solves issues 327 and 395)
+ - more printer-friendly (fullcalendar-print.css)
+ - fullcalendar now inherits styles from jquery-ui themes differently.
+ styles for buttons are distinct from styles for calendar cells.
+ (solves issue 299)
+ - can now color events through FullCalendar options and Event-Object properties (issue 117)
+ THIS IS NOW THE PREFERRED METHOD OF COLORING EVENTS (as opposed to using className and CSS)
+ - FullCalendar options:
+ - eventColor (changes both background and border)
+ - eventBackgroundColor
+ - eventBorderColor
+ - eventTextColor
+ - Event-Object options:
+ - color (changes both background and border)
+ - backgroundColor
+ - borderColor
+ - textColor
+ - can now specify an event source as an *object* with a `url` property (json feed) or
+ an `events` property (function or array) with additional properties that will
+ be applied to the entire event source:
+ - color (changes both background and border)
+ - backgroudColor
+ - borderColor
+ - textColor
+ - className
+ - editable
+ - allDayDefault
+ - ignoreTimezone
+ - startParam (for a feed)
+ - endParam (for a feed)
+ - ANY OF THE JQUERY $.ajax OPTIONS
+ allows for easily changing from GET to POST and sending additional parameters (issue 386)
+ allows for easily attaching ajax handlers such as `error` (issue 754)
+ allows for turning caching on (issue 355)
+ - Google Calendar feeds are now specified differently:
+ - specify a simple string of your feed's URL
+ - specify an *object* with a `url` property of your feed's URL.
+ you can include any of the new Event-Source options in this object.
+ - the old `$.fullCalendar.gcalFeed` method still works
+ - no more IE7 SSL popup (issue 504)
+ - remove `cacheParam` - use json event source `cache` option instead
+ - latest jquery/jquery-ui
+
+version 1.4.11 (2/22/11)
+ - fixed rerenderEvents bug (issue 790)
+ - fixed bug with faulty dragging of events from all-day slot in agenda views
+ - bundled with jquery 1.5 and jquery-ui 1.8.9
+
+version 1.4.10 (1/2/11)
+ - fixed bug with resizing event to different week in 5-day month view (issue 740)
+ - fixed bug with events not sticking after a removeEvents call (issue 757)
+ - fixed bug with underlying parseTime method, and other uses of parseInt (issue 688)
+
+version 1.4.9 (11/16/10)
+ - new algorithm for vertically stacking events (issue 111)
+ - resizing an event to a different week (issue 306)
+ - bug: some events not rendered with consecutive calls to addEventSource (issue 679)
+
+version 1.4.8 (10/16/10)
+ - ignoreTimezone option (set to `false` to process UTC offsets in ISO8601 dates)
+ - bugfixes
+ - event refetching not being called under certain conditions (issues 417, 554)
+ - event refetching being called multiple times under certain conditions (issues 586, 616)
+ - selection cannot be triggered by right mouse button (issue 558)
+ - agenda view left axis sized incorrectly (issue 465)
+ - IE js error when calendar is too narrow (issue 517)
+ - agenda view looks strange when no scrollbars (issue 235)
+ - improved parsing of ISO8601 dates with UTC offsets
+ - $.fullCalendar.version
+ - an internal refactor of the code, for easier future development and modularity
+
+version 1.4.7 (7/5/10)
+ - "dropping" external objects onto the calendar
+ - droppable (boolean, to turn on/off)
+ - dropAccept (to filter which events the calendar will accept)
+ - drop (trigger)
+ - selectable options can now be specified with a View Option Hash
+ - bugfixes
+ - dragged & reverted events having wrong time text (issue 406)
+ - bug rendering events that have an endtime with seconds, but no hours/minutes (issue 477)
+ - gotoDate date overflow bug (issue 429)
+ - wrong date reported when clicking on edge of last column in agenda views (412)
+ - support newlines in event titles
+ - select/unselect callbacks now passes native js event
+
+version 1.4.6 (5/31/10)
+ - "selecting" days or timeslots
+ - options: selectable, selectHelper, unselectAuto, unselectCancel
+ - callbacks: select, unselect
+ - methods: select, unselect
+ - when dragging an event, the highlighting reflects the duration of the event
+ - code compressing by Google Closure Compiler
+ - bundled with jQuery 1.4.2 and jQuery UI 1.8.1
+
+version 1.4.5 (2/21/10)
+ - lazyFetching option, which can force the calendar to fetch events on every view/date change
+ - scroll state of agenda views are preserved when switching back to view
+ - bugfixes
+ - calling methods on an uninitialized fullcalendar throws error
+ - IE6/7 bug where an entire view becomes invisible (issue 320)
+ - error when rendering a hidden calendar (in jquery ui tabs for example) in IE (issue 340)
+ - interconnected bugs related to calendar resizing and scrollbars
+ - when switching views or clicking prev/next, calendar would "blink" (issue 333)
+ - liquid-width calendar's events shifted (depending on initial height of browser) (issue 341)
+ - more robust underlying algorithm for calendar resizing
+
+version 1.4.4 (2/3/10)
+ - optimized event rendering in all views (events render in 1/10 the time)
+ - gotoDate() does not force the calendar to unnecessarily rerender
+ - render() method now correctly readjusts height
+
+version 1.4.3 (12/22/09)
+ - added destroy method
+ - Google Calendar event pages respect currentTimezone
+ - caching now handled by jQuery's ajax
+ - protection from setting aspectRatio to zero
+ - bugfixes
+ - parseISO8601 and DST caused certain events to display day before
+ - button positioning problem in IE6
+ - ajax event source removed after recently being added, events still displayed
+ - event not displayed when end is an empty string
+ - dynamically setting calendar height when no events have been fetched, throws error
+
+version 1.4.2 (12/02/09)
+ - eventAfterRender trigger
+ - getDate & getView methods
+ - height & contentHeight options (explicitly sets the pixel height)
+ - minTime & maxTime options (restricts shown hours in agenda view)
+ - getters [for all options] and setters [for height, contentHeight, and aspectRatio ONLY! stay tuned..]
+ - render method now readjusts calendar's size
+ - bugfixes
+ - lightbox scripts that use iframes (like fancybox)
+ - day-of-week classNames were off when firstDay=1
+ - guaranteed space on right side of agenda events (even when stacked)
+ - accepts ISO8601 dates with a space (instead of 'T')
+
+version 1.4.1 (10/31/09)
+ - can exclude weekends with new 'weekends' option
+ - gcal feed 'currentTimezone' option
+ - bugfixes
+ - year/month/date option sometimes wouldn't set correctly (depending on current date)
+ - daylight savings issue caused agenda views to start at 1am (for BST users)
+ - cleanup of gcal.js code
+
+version 1.4 (10/19/09)
+ - agendaWeek and agendaDay views
+ - added some options for agenda views:
+ - allDaySlot
+ - allDayText
+ - firstHour
+ - slotMinutes
+ - defaultEventMinutes
+ - axisFormat
+ - modified some existing options/triggers to work with agenda views:
+ - dragOpacity and timeFormat can now accept a "View Hash" (a new concept)
+ - dayClick now has an allDay parameter
+ - eventDrop now has an an allDay parameter
+ (this will affect those who use revertFunc, adjust parameter list)
+ - added 'prevYear' and 'nextYear' for buttons in header
+ - minor change for theme users, ui-state-hover not applied to active/inactive buttons
+ - added event-color-changing example in docs
+ - better defaults for right-to-left themed button icons
+
+version 1.3.2 (10/13/09)
+ - Bugfixes (please upgrade from 1.3.1!)
+ - squashed potential infinite loop when addMonths and addDays
+ is called with an invalid date
+ - $.fullCalendar.parseDate() now correctly parses IETF format
+ - when switching views, the 'today' button sticks inactive, fixed
+ - gotoDate now can accept a single Date argument
+ - documentation for changes in 1.3.1 and 1.3.2 now on website
+
+version 1.3.1 (9/30/09)
+ - Important Bugfixes (please upgrade from 1.3!)
+ - When current date was late in the month, for long months, and prev/next buttons
+ were clicked in month-view, some months would be skipped/repeated
+ - In certain time zones, daylight savings time would cause certain days
+ to be misnumbered in month-view
+ - Subtle change in way week interval is chosen when switching from month to basicWeek/basicDay view
+ - Added 'allDayDefault' option
+ - Added 'changeView' and 'render' methods
+
+version 1.3 (9/21/09)
+ - different 'views': month/basicWeek/basicDay
+ - more flexible 'header' system for buttons
+ - themable by jQuery UI themes
+ - resizable events (require jQuery UI resizable plugin)
+ - rescoped & rewritten CSS, enhanced default look
+ - cleaner css & rendering techniques for right-to-left
+ - reworked options & API to support multiple views / be consistent with jQuery UI
+ - refactoring of entire codebase
+ - broken into different JS & CSS files, assembled w/ build scripts
+ - new test suite for new features, uses firebug-lite
+ - refactored docs
+ - Options
+ + date
+ + defaultView
+ + aspectRatio
+ + disableResizing
+ + monthNames (use instead of $.fullCalendar.monthNames)
+ + monthNamesShort (use instead of $.fullCalendar.monthAbbrevs)
+ + dayNames (use instead of $.fullCalendar.dayNames)
+ + dayNamesShort (use instead of $.fullCalendar.dayAbbrevs)
+ + theme
+ + buttonText
+ + buttonIcons
+ x draggable -> editable/disableDragging
+ x fixedWeeks -> weekMode
+ x abbrevDayHeadings -> columnFormat
+ x buttons/title -> header
+ x eventDragOpacity -> dragOpacity
+ x eventRevertDuration -> dragRevertDuration
+ x weekStart -> firstDay
+ x rightToLeft -> isRTL
+ x showTime (use 'allDay' CalEvent property instead)
+ - Triggered Actions
+ + eventResizeStart
+ + eventResizeStop
+ + eventResize
+ x monthDisplay -> viewDisplay
+ x resize -> windowResize
+ 'eventDrop' params changed, can revert if ajax cuts out
+ - CalEvent Properties
+ x showTime -> allDay
+ x draggable -> editable
+ 'end' is now INCLUSIVE when allDay=true
+ 'url' now produces a real <a> tag, more native clicking/tab behavior
+ - Methods:
+ + renderEvent
+ x prevMonth -> prev
+ x nextMonth -> next
+ x prevYear/nextYear -> moveDate
+ x refresh -> rerenderEvents/refetchEvents
+ x removeEvent -> removeEvents
+ x getEventsByID -> clientEvents
+ - Utilities:
+ 'formatDate' format string completely changed (inspired by jQuery UI datepicker + datejs)
+ 'formatDates' added to support date-ranges
+ - Google Calendar Options:
+ x draggable -> editable
+ - Bugfixes
+ - gcal extension fetched 25 results max, now fetches all
+
+version 1.2.1 (6/29/09)
+ - bugfixes
+ - allows and corrects invalid end dates for events
+ - doesn't throw an error in IE while rendering when display:none
+ - fixed 'loading' callback when used w/ multiple addEventSource calls
+ - gcal className can now be an array
+
+version 1.2 (5/31/09)
+ - expanded API
+ - 'className' CalEvent attribute
+ - 'source' CalEvent attribute
+ - dynamically get/add/remove/update events of current month
+ - locale improvements: change month/day name text
+ - better date formatting ($.fullCalendar.formatDate)
+ - multiple 'event sources' allowed
+ - dynamically add/remove event sources
+ - options for prevYear and nextYear buttons
+ - docs have been reworked (include addition of Google Calendar docs)
+ - changed behavior of parseDate for number strings
+ (now interpets as unix timestamp, not MS times)
+ - bugfixes
+ - rightToLeft month start bug
+ - off-by-one errors with month formatting commands
+ - events from previous months sticking when clicking prev/next quickly
+ - Google Calendar API changed to work w/ multiple event sources
+ - can also provide 'className' and 'draggable' options
+ - date utilties moved from $ to $.fullCalendar
+ - more documentation in source code
+ - minified version of fullcalendar.js
+ - test suit (available from svn)
+ - top buttons now use <button> w/ an inner <span> for better css cusomization
+ - thus CSS has changed. IF UPGRADING FROM PREVIOUS VERSIONS,
+ UPGRADE YOUR FULLCALENDAR.CSS FILE!!!
+
+version 1.1 (5/10/09)
+ - Added the following options:
+ - weekStart
+ - rightToLeft
+ - titleFormat
+ - timeFormat
+ - cacheParam
+ - resize
+ - Fixed rendering bugs
+ - Opera 9.25 (events placement & window resizing)
+ - IE6 (window resizing)
+ - Optimized window resizing for ALL browsers
+ - Events on same day now sorted by start time (but first by timespan)
+ - Correct z-index when dragging
+ - Dragging contained in overflow DIV for IE6
+ - Modified fullcalendar.css
+ - for right-to-left support
+ - for variable start-of-week
+ - for IE6 resizing bug
+ - for THEAD and TBODY (in 1.0, just used TBODY, restructured in 1.1)
+ - IF UPGRADING FROM FULLCALENDAR 1.0, YOU MUST UPGRADE FULLCALENDAR.CSS
+ !!!!!!!!!!!
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css
new file mode 100644
index 00000000..dcbc9997
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css
@@ -0,0 +1,1293 @@
+/*!
+ * FullCalendar v3.9.0
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+.fc {
+ direction: ltr;
+ text-align: left; }
+
+.fc-rtl {
+ text-align: right; }
+
+body .fc {
+ /* extra precedence to overcome jqui */
+ font-size: 1em; }
+
+/* Colors
+--------------------------------------------------------------------------------------------------*/
+.fc-highlight {
+ /* when user is selecting cells */
+ background: #bce8f1;
+ opacity: .3; }
+
+.fc-bgevent {
+ /* default look for background events */
+ background: #8fdf82;
+ opacity: .3; }
+
+.fc-nonbusiness {
+ /* default look for non-business-hours areas */
+ /* will inherit .fc-bgevent's styles */
+ background: #d7d7d7; }
+
+/* Buttons (styled <button> tags, normalized to work cross-browser)
+--------------------------------------------------------------------------------------------------*/
+.fc button {
+ /* force height to include the border and padding */
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ /* dimensions */
+ margin: 0;
+ height: 2.1em;
+ padding: 0 .6em;
+ /* text & cursor */
+ font-size: 1em;
+ /* normalize */
+ white-space: nowrap;
+ cursor: pointer; }
+
+/* Firefox has an annoying inner border */
+.fc button::-moz-focus-inner {
+ margin: 0;
+ padding: 0; }
+
+.fc-state-default {
+ /* non-theme */
+ border: 1px solid; }
+
+.fc-state-default.fc-corner-left {
+ /* non-theme */
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px; }
+
+.fc-state-default.fc-corner-right {
+ /* non-theme */
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px; }
+
+/* icons in buttons */
+.fc button .fc-icon {
+ /* non-theme */
+ position: relative;
+ top: -0.05em;
+ /* seems to be a good adjustment across browsers */
+ margin: 0 .2em;
+ vertical-align: middle; }
+
+/*
+ button states
+ borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)
+*/
+.fc-state-default {
+ background-color: #f5f5f5;
+ background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+ background-repeat: repeat-x;
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ color: #333;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); }
+
+.fc-state-hover,
+.fc-state-down,
+.fc-state-active,
+.fc-state-disabled {
+ color: #333333;
+ background-color: #e6e6e6; }
+
+.fc-state-hover {
+ color: #333333;
+ text-decoration: none;
+ background-position: 0 -15px;
+ -webkit-transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear; }
+
+.fc-state-down,
+.fc-state-active {
+ background-color: #cccccc;
+ background-image: none;
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); }
+
+.fc-state-disabled {
+ cursor: default;
+ background-image: none;
+ opacity: 0.65;
+ box-shadow: none; }
+
+/* Buttons Groups
+--------------------------------------------------------------------------------------------------*/
+.fc-button-group {
+ display: inline-block; }
+
+/*
+every button that is not first in a button group should scootch over one pixel and cover the
+previous button's border...
+*/
+.fc .fc-button-group > * {
+ /* extra precedence b/c buttons have margin set to zero */
+ float: left;
+ margin: 0 0 0 -1px; }
+
+.fc .fc-button-group > :first-child {
+ /* same */
+ margin-left: 0; }
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+.fc-popover {
+ position: absolute;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); }
+
+.fc-popover .fc-header {
+ /* TODO: be more consistent with fc-head/fc-body */
+ padding: 2px 4px; }
+
+.fc-popover .fc-header .fc-title {
+ margin: 0 2px; }
+
+.fc-popover .fc-header .fc-close {
+ cursor: pointer; }
+
+.fc-ltr .fc-popover .fc-header .fc-title,
+.fc-rtl .fc-popover .fc-header .fc-close {
+ float: left; }
+
+.fc-rtl .fc-popover .fc-header .fc-title,
+.fc-ltr .fc-popover .fc-header .fc-close {
+ float: right; }
+
+/* Misc Reusable Components
+--------------------------------------------------------------------------------------------------*/
+.fc-divider {
+ border-style: solid;
+ border-width: 1px; }
+
+hr.fc-divider {
+ height: 0;
+ margin: 0;
+ padding: 0 0 2px;
+ /* height is unreliable across browsers, so use padding */
+ border-width: 1px 0; }
+
+.fc-clear {
+ clear: both; }
+
+.fc-bg,
+.fc-bgevent-skeleton,
+.fc-highlight-skeleton,
+.fc-helper-skeleton {
+ /* these element should always cling to top-left/right corners */
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0; }
+
+.fc-bg {
+ bottom: 0;
+ /* strech bg to bottom edge */ }
+
+.fc-bg table {
+ height: 100%;
+ /* strech bg to bottom edge */ }
+
+/* Tables
+--------------------------------------------------------------------------------------------------*/
+.fc table {
+ width: 100%;
+ box-sizing: border-box;
+ /* fix scrollbar issue in firefox */
+ table-layout: fixed;
+ border-collapse: collapse;
+ border-spacing: 0;
+ font-size: 1em;
+ /* normalize cross-browser */ }
+
+.fc th {
+ text-align: center; }
+
+.fc th,
+.fc td {
+ border-style: solid;
+ border-width: 1px;
+ padding: 0;
+ vertical-align: top; }
+
+.fc td.fc-today {
+ border-style: double;
+ /* overcome neighboring borders */ }
+
+/* Internal Nav Links
+--------------------------------------------------------------------------------------------------*/
+a[data-goto] {
+ cursor: pointer; }
+
+a[data-goto]:hover {
+ text-decoration: underline; }
+
+/* Fake Table Rows
+--------------------------------------------------------------------------------------------------*/
+.fc .fc-row {
+ /* extra precedence to overcome themes w/ .ui-widget-content forcing a 1px border */
+ /* no visible border by default. but make available if need be (scrollbar width compensation) */
+ border-style: solid;
+ border-width: 0; }
+
+.fc-row table {
+ /* don't put left/right border on anything within a fake row.
+ the outer tbody will worry about this */
+ border-left: 0 hidden transparent;
+ border-right: 0 hidden transparent;
+ /* no bottom borders on rows */
+ border-bottom: 0 hidden transparent; }
+
+.fc-row:first-child table {
+ border-top: 0 hidden transparent;
+ /* no top border on first row */ }
+
+/* Day Row (used within the header and the DayGrid)
+--------------------------------------------------------------------------------------------------*/
+.fc-row {
+ position: relative; }
+
+.fc-row .fc-bg {
+ z-index: 1; }
+
+/* highlighting cells & background event skeleton */
+.fc-row .fc-bgevent-skeleton,
+.fc-row .fc-highlight-skeleton {
+ bottom: 0;
+ /* stretch skeleton to bottom of row */ }
+
+.fc-row .fc-bgevent-skeleton table,
+.fc-row .fc-highlight-skeleton table {
+ height: 100%;
+ /* stretch skeleton to bottom of row */ }
+
+.fc-row .fc-highlight-skeleton td,
+.fc-row .fc-bgevent-skeleton td {
+ border-color: transparent; }
+
+.fc-row .fc-bgevent-skeleton {
+ z-index: 2; }
+
+.fc-row .fc-highlight-skeleton {
+ z-index: 3; }
+
+/*
+row content (which contains day/week numbers and events) as well as "helper" (which contains
+temporary rendered events).
+*/
+.fc-row .fc-content-skeleton {
+ position: relative;
+ z-index: 4;
+ padding-bottom: 2px;
+ /* matches the space above the events */ }
+
+.fc-row .fc-helper-skeleton {
+ z-index: 5; }
+
+.fc .fc-row .fc-content-skeleton table,
+.fc .fc-row .fc-content-skeleton td,
+.fc .fc-row .fc-helper-skeleton td {
+ /* see-through to the background below */
+ /* extra precedence to prevent theme-provided backgrounds */
+ background: none;
+ /* in case <td>s are globally styled */
+ border-color: transparent; }
+
+.fc-row .fc-content-skeleton td,
+.fc-row .fc-helper-skeleton td {
+ /* don't put a border between events and/or the day number */
+ border-bottom: 0; }
+
+.fc-row .fc-content-skeleton tbody td,
+.fc-row .fc-helper-skeleton tbody td {
+ /* don't put a border between event cells */
+ border-top: 0; }
+
+/* Scrolling Container
+--------------------------------------------------------------------------------------------------*/
+.fc-scroller {
+ -webkit-overflow-scrolling: touch; }
+
+/* TODO: move to agenda/basic */
+.fc-scroller > .fc-day-grid,
+.fc-scroller > .fc-time-grid {
+ position: relative;
+ /* re-scope all positions */
+ width: 100%;
+ /* hack to force re-sizing this inner element when scrollbars appear/disappear */ }
+
+/* Global Event Styles
+--------------------------------------------------------------------------------------------------*/
+.fc-event {
+ position: relative;
+ /* for resize handle and other inner positioning */
+ display: block;
+ /* make the <a> tag block */
+ font-size: .85em;
+ line-height: 1.3;
+ border-radius: 3px;
+ border: 1px solid #3a87ad;
+ /* default BORDER color */ }
+
+.fc-event,
+.fc-event-dot {
+ background-color: #3a87ad;
+ /* default BACKGROUND color */ }
+
+.fc-event,
+.fc-event:hover {
+ color: #fff;
+ /* default TEXT color */
+ text-decoration: none;
+ /* if <a> has an href */ }
+
+.fc-event[href],
+.fc-event.fc-draggable {
+ cursor: pointer;
+ /* give events with links and draggable events a hand mouse pointer */ }
+
+.fc-not-allowed,
+.fc-not-allowed .fc-event {
+ /* to override an event's custom cursor */
+ cursor: not-allowed; }
+
+.fc-event .fc-bg {
+ /* the generic .fc-bg already does position */
+ z-index: 1;
+ background: #fff;
+ opacity: .25; }
+
+.fc-event .fc-content {
+ position: relative;
+ z-index: 2; }
+
+/* resizer (cursor AND touch devices) */
+.fc-event .fc-resizer {
+ position: absolute;
+ z-index: 4; }
+
+/* resizer (touch devices) */
+.fc-event .fc-resizer {
+ display: none; }
+
+.fc-event.fc-allow-mouse-resize .fc-resizer,
+.fc-event.fc-selected .fc-resizer {
+ /* only show when hovering or selected (with touch) */
+ display: block; }
+
+/* hit area */
+.fc-event.fc-selected .fc-resizer:before {
+ /* 40x40 touch area */
+ content: "";
+ position: absolute;
+ z-index: 9999;
+ /* user of this util can scope within a lower z-index */
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-left: -20px;
+ margin-top: -20px; }
+
+/* Event Selection (only for touch devices)
+--------------------------------------------------------------------------------------------------*/
+.fc-event.fc-selected {
+ z-index: 9999 !important;
+ /* overcomes inline z-index */
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); }
+
+.fc-event.fc-selected.fc-dragging {
+ box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3); }
+
+/* Horizontal Events
+--------------------------------------------------------------------------------------------------*/
+/* bigger touch area when selected */
+.fc-h-event.fc-selected:before {
+ content: "";
+ position: absolute;
+ z-index: 3;
+ /* below resizers */
+ top: -10px;
+ bottom: -10px;
+ left: 0;
+ right: 0; }
+
+/* events that are continuing to/from another week. kill rounded corners and butt up against edge */
+.fc-ltr .fc-h-event.fc-not-start,
+.fc-rtl .fc-h-event.fc-not-end {
+ margin-left: 0;
+ border-left-width: 0;
+ padding-left: 1px;
+ /* replace the border with padding */
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0; }
+
+.fc-ltr .fc-h-event.fc-not-end,
+.fc-rtl .fc-h-event.fc-not-start {
+ margin-right: 0;
+ border-right-width: 0;
+ padding-right: 1px;
+ /* replace the border with padding */
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0; }
+
+/* resizer (cursor AND touch devices) */
+/* left resizer */
+.fc-ltr .fc-h-event .fc-start-resizer,
+.fc-rtl .fc-h-event .fc-end-resizer {
+ cursor: w-resize;
+ left: -1px;
+ /* overcome border */ }
+
+/* right resizer */
+.fc-ltr .fc-h-event .fc-end-resizer,
+.fc-rtl .fc-h-event .fc-start-resizer {
+ cursor: e-resize;
+ right: -1px;
+ /* overcome border */ }
+
+/* resizer (mouse devices) */
+.fc-h-event.fc-allow-mouse-resize .fc-resizer {
+ width: 7px;
+ top: -1px;
+ /* overcome top border */
+ bottom: -1px;
+ /* overcome bottom border */ }
+
+/* resizer (touch devices) */
+.fc-h-event.fc-selected .fc-resizer {
+ /* 8x8 little dot */
+ border-radius: 4px;
+ border-width: 1px;
+ width: 6px;
+ height: 6px;
+ border-style: solid;
+ border-color: inherit;
+ background: #fff;
+ /* vertically center */
+ top: 50%;
+ margin-top: -4px; }
+
+/* left resizer */
+.fc-ltr .fc-h-event.fc-selected .fc-start-resizer,
+.fc-rtl .fc-h-event.fc-selected .fc-end-resizer {
+ margin-left: -4px;
+ /* centers the 8x8 dot on the left edge */ }
+
+/* right resizer */
+.fc-ltr .fc-h-event.fc-selected .fc-end-resizer,
+.fc-rtl .fc-h-event.fc-selected .fc-start-resizer {
+ margin-right: -4px;
+ /* centers the 8x8 dot on the right edge */ }
+
+/* DayGrid events
+----------------------------------------------------------------------------------------------------
+We use the full "fc-day-grid-event" class instead of using descendants because the event won't
+be a descendant of the grid when it is being dragged.
+*/
+.fc-day-grid-event {
+ margin: 1px 2px 0;
+ /* spacing between events and edges */
+ padding: 0 1px; }
+
+tr:first-child > td > .fc-day-grid-event {
+ margin-top: 2px;
+ /* a little bit more space before the first event */ }
+
+.fc-day-grid-event.fc-selected:after {
+ content: "";
+ position: absolute;
+ z-index: 1;
+ /* same z-index as fc-bg, behind text */
+ /* overcome the borders */
+ top: -1px;
+ right: -1px;
+ bottom: -1px;
+ left: -1px;
+ /* darkening effect */
+ background: #000;
+ opacity: .25; }
+
+.fc-day-grid-event .fc-content {
+ /* force events to be one-line tall */
+ white-space: nowrap;
+ overflow: hidden; }
+
+.fc-day-grid-event .fc-time {
+ font-weight: bold; }
+
+/* resizer (cursor devices) */
+/* left resizer */
+.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer,
+.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer {
+ margin-left: -2px;
+ /* to the day cell's edge */ }
+
+/* right resizer */
+.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer,
+.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer {
+ margin-right: -2px;
+ /* to the day cell's edge */ }
+
+/* Event Limiting
+--------------------------------------------------------------------------------------------------*/
+/* "more" link that represents hidden events */
+a.fc-more {
+ margin: 1px 3px;
+ font-size: .85em;
+ cursor: pointer;
+ text-decoration: none; }
+
+a.fc-more:hover {
+ text-decoration: underline; }
+
+.fc-limited {
+ /* rows and cells that are hidden because of a "more" link */
+ display: none; }
+
+/* popover that appears when "more" link is clicked */
+.fc-day-grid .fc-row {
+ z-index: 1;
+ /* make the "more" popover one higher than this */ }
+
+.fc-more-popover {
+ z-index: 2;
+ width: 220px; }
+
+.fc-more-popover .fc-event-container {
+ padding: 10px; }
+
+/* Now Indicator
+--------------------------------------------------------------------------------------------------*/
+.fc-now-indicator {
+ position: absolute;
+ border: 0 solid red; }
+
+/* Utilities
+--------------------------------------------------------------------------------------------------*/
+.fc-unselectable {
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: transparent; }
+
+/*
+TODO: more distinction between this file and common.css
+*/
+/* Colors
+--------------------------------------------------------------------------------------------------*/
+.fc-unthemed th,
+.fc-unthemed td,
+.fc-unthemed thead,
+.fc-unthemed tbody,
+.fc-unthemed .fc-divider,
+.fc-unthemed .fc-row,
+.fc-unthemed .fc-content,
+.fc-unthemed .fc-popover,
+.fc-unthemed .fc-list-view,
+.fc-unthemed .fc-list-heading td {
+ border-color: #ddd; }
+
+.fc-unthemed .fc-popover {
+ background-color: #fff; }
+
+.fc-unthemed .fc-divider,
+.fc-unthemed .fc-popover .fc-header,
+.fc-unthemed .fc-list-heading td {
+ background: #eee; }
+
+.fc-unthemed .fc-popover .fc-header .fc-close {
+ color: #666; }
+
+.fc-unthemed td.fc-today {
+ background: #fcf8e3; }
+
+.fc-unthemed .fc-disabled-day {
+ background: #d7d7d7;
+ opacity: .3; }
+
+/* Icons (inline elements with styled text that mock arrow icons)
+--------------------------------------------------------------------------------------------------*/
+.fc-icon {
+ display: inline-block;
+ height: 1em;
+ line-height: 1em;
+ font-size: 1em;
+ text-align: center;
+ overflow: hidden;
+ font-family: "Courier New", Courier, monospace;
+ /* don't allow browser text-selection */
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none; }
+
+/*
+Acceptable font-family overrides for individual icons:
+ "Arial", sans-serif
+ "Times New Roman", serif
+
+NOTE: use percentage font sizes or else old IE chokes
+*/
+.fc-icon:after {
+ position: relative; }
+
+.fc-icon-left-single-arrow:after {
+ content: "\2039";
+ font-weight: bold;
+ font-size: 200%;
+ top: -7%; }
+
+.fc-icon-right-single-arrow:after {
+ content: "\203A";
+ font-weight: bold;
+ font-size: 200%;
+ top: -7%; }
+
+.fc-icon-left-double-arrow:after {
+ content: "\AB";
+ font-size: 160%;
+ top: -7%; }
+
+.fc-icon-right-double-arrow:after {
+ content: "\BB";
+ font-size: 160%;
+ top: -7%; }
+
+.fc-icon-left-triangle:after {
+ content: "\25C4";
+ font-size: 125%;
+ top: 3%; }
+
+.fc-icon-right-triangle:after {
+ content: "\25BA";
+ font-size: 125%;
+ top: 3%; }
+
+.fc-icon-down-triangle:after {
+ content: "\25BC";
+ font-size: 125%;
+ top: 2%; }
+
+.fc-icon-x:after {
+ content: "\D7";
+ font-size: 200%;
+ top: 6%; }
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+.fc-unthemed .fc-popover {
+ border-width: 1px;
+ border-style: solid; }
+
+.fc-unthemed .fc-popover .fc-header .fc-close {
+ font-size: .9em;
+ margin-top: 2px; }
+
+/* List View
+--------------------------------------------------------------------------------------------------*/
+.fc-unthemed .fc-list-item:hover td {
+ background-color: #f5f5f5; }
+
+/* Colors
+--------------------------------------------------------------------------------------------------*/
+.ui-widget .fc-disabled-day {
+ background-image: none; }
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+.fc-popover > .ui-widget-header + .ui-widget-content {
+ border-top: 0;
+ /* where they meet, let the header have the border */ }
+
+/* Global Event Styles
+--------------------------------------------------------------------------------------------------*/
+.ui-widget .fc-event {
+ /* overpower jqui's styles on <a> tags. TODO: more DRY */
+ color: #fff;
+ /* default TEXT color */
+ text-decoration: none;
+ /* if <a> has an href */
+ /* undo ui-widget-header bold */
+ font-weight: normal; }
+
+/* TimeGrid axis running down the side (for both the all-day area and the slot area)
+--------------------------------------------------------------------------------------------------*/
+.ui-widget td.fc-axis {
+ font-weight: normal;
+ /* overcome bold */ }
+
+/* TimeGrid Slats (lines that run horizontally)
+--------------------------------------------------------------------------------------------------*/
+.fc-time-grid .fc-slats .ui-widget-content {
+ background: none;
+ /* see through to fc-bg */ }
+
+.fc.fc-bootstrap3 a {
+ text-decoration: none; }
+
+.fc.fc-bootstrap3 a[data-goto]:hover {
+ text-decoration: underline; }
+
+.fc-bootstrap3 hr.fc-divider {
+ border-color: inherit; }
+
+.fc-bootstrap3 .fc-today.alert {
+ border-radius: 0; }
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+.fc-bootstrap3 .fc-popover .panel-body {
+ padding: 0; }
+
+/* TimeGrid Slats (lines that run horizontally)
+--------------------------------------------------------------------------------------------------*/
+.fc-bootstrap3 .fc-time-grid .fc-slats table {
+ /* some themes have background color. see through to slats */
+ background: none; }
+
+.fc.fc-bootstrap4 a {
+ text-decoration: none; }
+
+.fc.fc-bootstrap4 a[data-goto]:hover {
+ text-decoration: underline; }
+
+.fc-bootstrap4 hr.fc-divider {
+ border-color: inherit; }
+
+.fc-bootstrap4 .fc-today.alert {
+ border-radius: 0; }
+
+.fc-bootstrap4 a.fc-event:not([href]):not([tabindex]) {
+ color: #fff; }
+
+.fc-bootstrap4 .fc-popover.card {
+ position: absolute; }
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+.fc-bootstrap4 .fc-popover .card-body {
+ padding: 0; }
+
+/* TimeGrid Slats (lines that run horizontally)
+--------------------------------------------------------------------------------------------------*/
+.fc-bootstrap4 .fc-time-grid .fc-slats table {
+ /* some themes have background color. see through to slats */
+ background: none; }
+
+/* Toolbar
+--------------------------------------------------------------------------------------------------*/
+.fc-toolbar {
+ text-align: center; }
+
+.fc-toolbar.fc-header-toolbar {
+ margin-bottom: 1em; }
+
+.fc-toolbar.fc-footer-toolbar {
+ margin-top: 1em; }
+
+.fc-toolbar .fc-left {
+ float: left; }
+
+.fc-toolbar .fc-right {
+ float: right; }
+
+.fc-toolbar .fc-center {
+ display: inline-block; }
+
+/* the things within each left/right/center section */
+.fc .fc-toolbar > * > * {
+ /* extra precedence to override button border margins */
+ float: left;
+ margin-left: .75em; }
+
+/* the first thing within each left/center/right section */
+.fc .fc-toolbar > * > :first-child {
+ /* extra precedence to override button border margins */
+ margin-left: 0; }
+
+/* title text */
+.fc-toolbar h2 {
+ margin: 0; }
+
+/* button layering (for border precedence) */
+.fc-toolbar button {
+ position: relative; }
+
+.fc-toolbar .fc-state-hover,
+.fc-toolbar .ui-state-hover {
+ z-index: 2; }
+
+.fc-toolbar .fc-state-down {
+ z-index: 3; }
+
+.fc-toolbar .fc-state-active,
+.fc-toolbar .ui-state-active {
+ z-index: 4; }
+
+.fc-toolbar button:focus {
+ z-index: 5; }
+
+/* View Structure
+--------------------------------------------------------------------------------------------------*/
+/* undo twitter bootstrap's box-sizing rules. normalizes positioning techniques */
+/* don't do this for the toolbar because we'll want bootstrap to style those buttons as some pt */
+.fc-view-container *,
+.fc-view-container *:before,
+.fc-view-container *:after {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box; }
+
+.fc-view,
+.fc-view > table {
+ /* so dragged elements can be above the view's main element */
+ position: relative;
+ z-index: 1; }
+
+/* BasicView
+--------------------------------------------------------------------------------------------------*/
+/* day row structure */
+.fc-basicWeek-view .fc-content-skeleton,
+.fc-basicDay-view .fc-content-skeleton {
+ /* there may be week numbers in these views, so no padding-top */
+ padding-bottom: 1em;
+ /* ensure a space at bottom of cell for user selecting/clicking */ }
+
+.fc-basic-view .fc-body .fc-row {
+ min-height: 4em;
+ /* ensure that all rows are at least this tall */ }
+
+/* a "rigid" row will take up a constant amount of height because content-skeleton is absolute */
+.fc-row.fc-rigid {
+ overflow: hidden; }
+
+.fc-row.fc-rigid .fc-content-skeleton {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0; }
+
+/* week and day number styling */
+.fc-day-top.fc-other-month {
+ opacity: 0.3; }
+
+.fc-basic-view .fc-week-number,
+.fc-basic-view .fc-day-number {
+ padding: 2px; }
+
+.fc-basic-view th.fc-week-number,
+.fc-basic-view th.fc-day-number {
+ padding: 0 2px;
+ /* column headers can't have as much v space */ }
+
+.fc-ltr .fc-basic-view .fc-day-top .fc-day-number {
+ float: right; }
+
+.fc-rtl .fc-basic-view .fc-day-top .fc-day-number {
+ float: left; }
+
+.fc-ltr .fc-basic-view .fc-day-top .fc-week-number {
+ float: left;
+ border-radius: 0 0 3px 0; }
+
+.fc-rtl .fc-basic-view .fc-day-top .fc-week-number {
+ float: right;
+ border-radius: 0 0 0 3px; }
+
+.fc-basic-view .fc-day-top .fc-week-number {
+ min-width: 1.5em;
+ text-align: center;
+ background-color: #f2f2f2;
+ color: #808080; }
+
+/* when week/day number have own column */
+.fc-basic-view td.fc-week-number {
+ text-align: center; }
+
+.fc-basic-view td.fc-week-number > * {
+ /* work around the way we do column resizing and ensure a minimum width */
+ display: inline-block;
+ min-width: 1.25em; }
+
+/* AgendaView all-day area
+--------------------------------------------------------------------------------------------------*/
+.fc-agenda-view .fc-day-grid {
+ position: relative;
+ z-index: 2;
+ /* so the "more.." popover will be over the time grid */ }
+
+.fc-agenda-view .fc-day-grid .fc-row {
+ min-height: 3em;
+ /* all-day section will never get shorter than this */ }
+
+.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton {
+ padding-bottom: 1em;
+ /* give space underneath events for clicking/selecting days */ }
+
+/* TimeGrid axis running down the side (for both the all-day area and the slot area)
+--------------------------------------------------------------------------------------------------*/
+.fc .fc-axis {
+ /* .fc to overcome default cell styles */
+ vertical-align: middle;
+ padding: 0 4px;
+ white-space: nowrap; }
+
+.fc-ltr .fc-axis {
+ text-align: right; }
+
+.fc-rtl .fc-axis {
+ text-align: left; }
+
+/* TimeGrid Structure
+--------------------------------------------------------------------------------------------------*/
+.fc-time-grid-container,
+.fc-time-grid {
+ /* so slats/bg/content/etc positions get scoped within here */
+ position: relative;
+ z-index: 1; }
+
+.fc-time-grid {
+ min-height: 100%;
+ /* so if height setting is 'auto', .fc-bg stretches to fill height */ }
+
+.fc-time-grid table {
+ /* don't put outer borders on slats/bg/content/etc */
+ border: 0 hidden transparent; }
+
+.fc-time-grid > .fc-bg {
+ z-index: 1; }
+
+.fc-time-grid .fc-slats,
+.fc-time-grid > hr {
+ /* the <hr> AgendaView injects when grid is shorter than scroller */
+ position: relative;
+ z-index: 2; }
+
+.fc-time-grid .fc-content-col {
+ position: relative;
+ /* because now-indicator lives directly inside */ }
+
+.fc-time-grid .fc-content-skeleton {
+ position: absolute;
+ z-index: 3;
+ top: 0;
+ left: 0;
+ right: 0; }
+
+/* divs within a cell within the fc-content-skeleton */
+.fc-time-grid .fc-business-container {
+ position: relative;
+ z-index: 1; }
+
+.fc-time-grid .fc-bgevent-container {
+ position: relative;
+ z-index: 2; }
+
+.fc-time-grid .fc-highlight-container {
+ position: relative;
+ z-index: 3; }
+
+.fc-time-grid .fc-event-container {
+ position: relative;
+ z-index: 4; }
+
+.fc-time-grid .fc-now-indicator-line {
+ z-index: 5; }
+
+.fc-time-grid .fc-helper-container {
+ /* also is fc-event-container */
+ position: relative;
+ z-index: 6; }
+
+/* TimeGrid Slats (lines that run horizontally)
+--------------------------------------------------------------------------------------------------*/
+.fc-time-grid .fc-slats td {
+ height: 1.5em;
+ border-bottom: 0;
+ /* each cell is responsible for its top border */ }
+
+.fc-time-grid .fc-slats .fc-minor td {
+ border-top-style: dotted; }
+
+/* TimeGrid Highlighting Slots
+--------------------------------------------------------------------------------------------------*/
+.fc-time-grid .fc-highlight-container {
+ /* a div within a cell within the fc-highlight-skeleton */
+ position: relative;
+ /* scopes the left/right of the fc-highlight to be in the column */ }
+
+.fc-time-grid .fc-highlight {
+ position: absolute;
+ left: 0;
+ right: 0;
+ /* top and bottom will be in by JS */ }
+
+/* TimeGrid Event Containment
+--------------------------------------------------------------------------------------------------*/
+.fc-ltr .fc-time-grid .fc-event-container {
+ /* space on the sides of events for LTR (default) */
+ margin: 0 2.5% 0 2px; }
+
+.fc-rtl .fc-time-grid .fc-event-container {
+ /* space on the sides of events for RTL */
+ margin: 0 2px 0 2.5%; }
+
+.fc-time-grid .fc-event,
+.fc-time-grid .fc-bgevent {
+ position: absolute;
+ z-index: 1;
+ /* scope inner z-index's */ }
+
+.fc-time-grid .fc-bgevent {
+ /* background events always span full width */
+ left: 0;
+ right: 0; }
+
+/* Generic Vertical Event
+--------------------------------------------------------------------------------------------------*/
+.fc-v-event.fc-not-start {
+ /* events that are continuing from another day */
+ /* replace space made by the top border with padding */
+ border-top-width: 0;
+ padding-top: 1px;
+ /* remove top rounded corners */
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.fc-v-event.fc-not-end {
+ /* replace space made by the top border with padding */
+ border-bottom-width: 0;
+ padding-bottom: 1px;
+ /* remove bottom rounded corners */
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+/* TimeGrid Event Styling
+----------------------------------------------------------------------------------------------------
+We use the full "fc-time-grid-event" class instead of using descendants because the event won't
+be a descendant of the grid when it is being dragged.
+*/
+.fc-time-grid-event {
+ overflow: hidden;
+ /* don't let the bg flow over rounded corners */ }
+
+.fc-time-grid-event.fc-selected {
+ /* need to allow touch resizers to extend outside event's bounding box */
+ /* common fc-selected styles hide the fc-bg, so don't need this anyway */
+ overflow: visible; }
+
+.fc-time-grid-event.fc-selected .fc-bg {
+ display: none;
+ /* hide semi-white background, to appear darker */ }
+
+.fc-time-grid-event .fc-content {
+ overflow: hidden;
+ /* for when .fc-selected */ }
+
+.fc-time-grid-event .fc-time,
+.fc-time-grid-event .fc-title {
+ padding: 0 1px; }
+
+.fc-time-grid-event .fc-time {
+ font-size: .85em;
+ white-space: nowrap; }
+
+/* short mode, where time and title are on the same line */
+.fc-time-grid-event.fc-short .fc-content {
+ /* don't wrap to second line (now that contents will be inline) */
+ white-space: nowrap; }
+
+.fc-time-grid-event.fc-short .fc-time,
+.fc-time-grid-event.fc-short .fc-title {
+ /* put the time and title on the same line */
+ display: inline-block;
+ vertical-align: top; }
+
+.fc-time-grid-event.fc-short .fc-time span {
+ display: none;
+ /* don't display the full time text... */ }
+
+.fc-time-grid-event.fc-short .fc-time:before {
+ content: attr(data-start);
+ /* ...instead, display only the start time */ }
+
+.fc-time-grid-event.fc-short .fc-time:after {
+ content: "\A0-\A0";
+ /* seperate with a dash, wrapped in nbsp's */ }
+
+.fc-time-grid-event.fc-short .fc-title {
+ font-size: .85em;
+ /* make the title text the same size as the time */
+ padding: 0;
+ /* undo padding from above */ }
+
+/* resizer (cursor device) */
+.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer {
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: 8px;
+ overflow: hidden;
+ line-height: 8px;
+ font-size: 11px;
+ font-family: monospace;
+ text-align: center;
+ cursor: s-resize; }
+
+.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after {
+ content: "="; }
+
+/* resizer (touch device) */
+.fc-time-grid-event.fc-selected .fc-resizer {
+ /* 10x10 dot */
+ border-radius: 5px;
+ border-width: 1px;
+ width: 8px;
+ height: 8px;
+ border-style: solid;
+ border-color: inherit;
+ background: #fff;
+ /* horizontally center */
+ left: 50%;
+ margin-left: -5px;
+ /* center on the bottom edge */
+ bottom: -5px; }
+
+/* Now Indicator
+--------------------------------------------------------------------------------------------------*/
+.fc-time-grid .fc-now-indicator-line {
+ border-top-width: 1px;
+ left: 0;
+ right: 0; }
+
+/* arrow on axis */
+.fc-time-grid .fc-now-indicator-arrow {
+ margin-top: -5px;
+ /* vertically center on top coordinate */ }
+
+.fc-ltr .fc-time-grid .fc-now-indicator-arrow {
+ left: 0;
+ /* triangle pointing right... */
+ border-width: 5px 0 5px 6px;
+ border-top-color: transparent;
+ border-bottom-color: transparent; }
+
+.fc-rtl .fc-time-grid .fc-now-indicator-arrow {
+ right: 0;
+ /* triangle pointing left... */
+ border-width: 5px 6px 5px 0;
+ border-top-color: transparent;
+ border-bottom-color: transparent; }
+
+/* List View
+--------------------------------------------------------------------------------------------------*/
+/* possibly reusable */
+.fc-event-dot {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ border-radius: 5px; }
+
+/* view wrapper */
+.fc-rtl .fc-list-view {
+ direction: rtl;
+ /* unlike core views, leverage browser RTL */ }
+
+.fc-list-view {
+ border-width: 1px;
+ border-style: solid; }
+
+/* table resets */
+.fc .fc-list-table {
+ table-layout: auto;
+ /* for shrinkwrapping cell content */ }
+
+.fc-list-table td {
+ border-width: 1px 0 0;
+ padding: 8px 14px; }
+
+.fc-list-table tr:first-child td {
+ border-top-width: 0; }
+
+/* day headings with the list */
+.fc-list-heading {
+ border-bottom-width: 1px; }
+
+.fc-list-heading td {
+ font-weight: bold; }
+
+.fc-ltr .fc-list-heading-main {
+ float: left; }
+
+.fc-ltr .fc-list-heading-alt {
+ float: right; }
+
+.fc-rtl .fc-list-heading-main {
+ float: right; }
+
+.fc-rtl .fc-list-heading-alt {
+ float: left; }
+
+/* event list items */
+.fc-list-item.fc-has-url {
+ cursor: pointer;
+ /* whole row will be clickable */ }
+
+.fc-list-item-marker,
+.fc-list-item-time {
+ white-space: nowrap;
+ width: 1px; }
+
+/* make the dot closer to the event title */
+.fc-ltr .fc-list-item-marker {
+ padding-right: 0; }
+
+.fc-rtl .fc-list-item-marker {
+ padding-left: 0; }
+
+.fc-list-item-title a {
+ /* every event title cell has an <a> tag */
+ text-decoration: none;
+ color: inherit; }
+
+.fc-list-item-title a[href]:hover {
+ /* hover effect only on titles with hrefs */
+ text-decoration: underline; }
+
+/* message when no events */
+.fc-list-empty-wrap2 {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0; }
+
+.fc-list-empty-wrap1 {
+ width: 100%;
+ height: 100%;
+ display: table; }
+
+.fc-list-empty {
+ display: table-cell;
+ vertical-align: middle;
+ text-align: center; }
+
+.fc-unthemed .fc-list-empty {
+ /* theme will provide own background */
+ background-color: #eee; }
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js
new file mode 100644
index 00000000..5f9bda72
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js
@@ -0,0 +1,15012 @@
+/*!
+ * FullCalendar v3.9.0
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory(require("moment"), require("jquery"));
+ else if(typeof define === 'function' && define.amd)
+ define(["moment", "jquery"], factory);
+ else if(typeof exports === 'object')
+ exports["FullCalendar"] = factory(require("moment"), require("jquery"));
+ else
+ root["FullCalendar"] = factory(root["moment"], root["jQuery"]);
+})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_3__) {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId]) {
+/******/ return installedModules[moduleId].exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ i: moduleId,
+/******/ l: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.l = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // define getter function for harmony exports
+/******/ __webpack_require__.d = function(exports, name, getter) {
+/******/ if(!__webpack_require__.o(exports, name)) {
+/******/ Object.defineProperty(exports, name, {
+/******/ configurable: false,
+/******/ enumerable: true,
+/******/ get: getter
+/******/ });
+/******/ }
+/******/ };
+/******/
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = function(module) {
+/******/ var getter = module && module.__esModule ?
+/******/ function getDefault() { return module['default']; } :
+/******/ function getModuleExports() { return module; };
+/******/ __webpack_require__.d(getter, 'a', getter);
+/******/ return getter;
+/******/ };
+/******/
+/******/ // Object.prototype.hasOwnProperty.call
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(__webpack_require__.s = 236);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
+
+/***/ }),
+/* 1 */,
+/* 2 */
+/***/ (function(module, exports) {
+
+/*
+derived from:
+https://github.com/Microsoft/tslib/blob/v1.6.0/tslib.js
+
+only include the helpers we need, to keep down filesize
+*/
+var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b)
+ if (b.hasOwnProperty(p))
+ d[p] = b[p]; };
+exports.__extends = function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_3__;
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var $ = __webpack_require__(3);
+/* FullCalendar-specific DOM Utilities
+----------------------------------------------------------------------------------------------------------------------*/
+// Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left
+// and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that.
+function compensateScroll(rowEls, scrollbarWidths) {
+ if (scrollbarWidths.left) {
+ rowEls.css({
+ 'border-left-width': 1,
+ 'margin-left': scrollbarWidths.left - 1
+ });
+ }
+ if (scrollbarWidths.right) {
+ rowEls.css({
+ 'border-right-width': 1,
+ 'margin-right': scrollbarWidths.right - 1
+ });
+ }
+}
+exports.compensateScroll = compensateScroll;
+// Undoes compensateScroll and restores all borders/margins
+function uncompensateScroll(rowEls) {
+ rowEls.css({
+ 'margin-left': '',
+ 'margin-right': '',
+ 'border-left-width': '',
+ 'border-right-width': ''
+ });
+}
+exports.uncompensateScroll = uncompensateScroll;
+// Make the mouse cursor express that an event is not allowed in the current area
+function disableCursor() {
+ $('body').addClass('fc-not-allowed');
+}
+exports.disableCursor = disableCursor;
+// Returns the mouse cursor to its original look
+function enableCursor() {
+ $('body').removeClass('fc-not-allowed');
+}
+exports.enableCursor = enableCursor;
+// Given a total available height to fill, have `els` (essentially child rows) expand to accomodate.
+// By default, all elements that are shorter than the recommended height are expanded uniformly, not considering
+// any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and
+// reduces the available height.
+function distributeHeight(els, availableHeight, shouldRedistribute) {
+ // *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions,
+ // and it is better to be shorter than taller, to avoid creating unnecessary scrollbars.
+ var minOffset1 = Math.floor(availableHeight / els.length); // for non-last element
+ var minOffset2 = Math.floor(availableHeight - minOffset1 * (els.length - 1)); // for last element *FLOORING NOTE*
+ var flexEls = []; // elements that are allowed to expand. array of DOM nodes
+ var flexOffsets = []; // amount of vertical space it takes up
+ var flexHeights = []; // actual css height
+ var usedHeight = 0;
+ undistributeHeight(els); // give all elements their natural height
+ // find elements that are below the recommended height (expandable).
+ // important to query for heights in a single first pass (to avoid reflow oscillation).
+ els.each(function (i, el) {
+ var minOffset = i === els.length - 1 ? minOffset2 : minOffset1;
+ var naturalOffset = $(el).outerHeight(true);
+ if (naturalOffset < minOffset) {
+ flexEls.push(el);
+ flexOffsets.push(naturalOffset);
+ flexHeights.push($(el).height());
+ }
+ else {
+ // this element stretches past recommended height (non-expandable). mark the space as occupied.
+ usedHeight += naturalOffset;
+ }
+ });
+ // readjust the recommended height to only consider the height available to non-maxed-out rows.
+ if (shouldRedistribute) {
+ availableHeight -= usedHeight;
+ minOffset1 = Math.floor(availableHeight / flexEls.length);
+ minOffset2 = Math.floor(availableHeight - minOffset1 * (flexEls.length - 1)); // *FLOORING NOTE*
+ }
+ // assign heights to all expandable elements
+ $(flexEls).each(function (i, el) {
+ var minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1;
+ var naturalOffset = flexOffsets[i];
+ var naturalHeight = flexHeights[i];
+ var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding
+ if (naturalOffset < minOffset) {
+ $(el).height(newHeight);
+ }
+ });
+}
+exports.distributeHeight = distributeHeight;
+// Undoes distrubuteHeight, restoring all els to their natural height
+function undistributeHeight(els) {
+ els.height('');
+}
+exports.undistributeHeight = undistributeHeight;
+// Given `els`, a jQuery set of <td> cells, find the cell with the largest natural width and set the widths of all the
+// cells to be that width.
+// PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline
+function matchCellWidths(els) {
+ var maxInnerWidth = 0;
+ els.find('> *').each(function (i, innerEl) {
+ var innerWidth = $(innerEl).outerWidth();
+ if (innerWidth > maxInnerWidth) {
+ maxInnerWidth = innerWidth;
+ }
+ });
+ maxInnerWidth++; // sometimes not accurate of width the text needs to stay on one line. insurance
+ els.width(maxInnerWidth);
+ return maxInnerWidth;
+}
+exports.matchCellWidths = matchCellWidths;
+// Given one element that resides inside another,
+// Subtracts the height of the inner element from the outer element.
+function subtractInnerElHeight(outerEl, innerEl) {
+ var both = outerEl.add(innerEl);
+ var diff;
+ // effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked
+ both.css({
+ position: 'relative',
+ left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll
+ });
+ diff = outerEl.outerHeight() - innerEl.outerHeight(); // grab the dimensions
+ both.css({ position: '', left: '' }); // undo hack
+ return diff;
+}
+exports.subtractInnerElHeight = subtractInnerElHeight;
+/* Element Geom Utilities
+----------------------------------------------------------------------------------------------------------------------*/
+// borrowed from https://github.com/jquery/jquery-ui/blob/1.11.0/ui/core.js#L51
+function getScrollParent(el) {
+ var position = el.css('position');
+ var scrollParent = el.parents().filter(function () {
+ var parent = $(this);
+ return (/(auto|scroll)/).test(parent.css('overflow') + parent.css('overflow-y') + parent.css('overflow-x'));
+ }).eq(0);
+ return position === 'fixed' || !scrollParent.length ? $(el[0].ownerDocument || document) : scrollParent;
+}
+exports.getScrollParent = getScrollParent;
+// Queries the outer bounding area of a jQuery element.
+// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
+// Origin is optional.
+function getOuterRect(el, origin) {
+ var offset = el.offset();
+ var left = offset.left - (origin ? origin.left : 0);
+ var top = offset.top - (origin ? origin.top : 0);
+ return {
+ left: left,
+ right: left + el.outerWidth(),
+ top: top,
+ bottom: top + el.outerHeight()
+ };
+}
+exports.getOuterRect = getOuterRect;
+// Queries the area within the margin/border/scrollbars of a jQuery element. Does not go within the padding.
+// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
+// Origin is optional.
+// WARNING: given element can't have borders
+// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
+function getClientRect(el, origin) {
+ var offset = el.offset();
+ var scrollbarWidths = getScrollbarWidths(el);
+ var left = offset.left + getCssFloat(el, 'border-left-width') + scrollbarWidths.left - (origin ? origin.left : 0);
+ var top = offset.top + getCssFloat(el, 'border-top-width') + scrollbarWidths.top - (origin ? origin.top : 0);
+ return {
+ left: left,
+ right: left + el[0].clientWidth,
+ top: top,
+ bottom: top + el[0].clientHeight // clientHeight includes padding but NOT scrollbars
+ };
+}
+exports.getClientRect = getClientRect;
+// Queries the area within the margin/border/padding of a jQuery element. Assumed not to have scrollbars.
+// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
+// Origin is optional.
+function getContentRect(el, origin) {
+ var offset = el.offset(); // just outside of border, margin not included
+ var left = offset.left + getCssFloat(el, 'border-left-width') + getCssFloat(el, 'padding-left') -
+ (origin ? origin.left : 0);
+ var top = offset.top + getCssFloat(el, 'border-top-width') + getCssFloat(el, 'padding-top') -
+ (origin ? origin.top : 0);
+ return {
+ left: left,
+ right: left + el.width(),
+ top: top,
+ bottom: top + el.height()
+ };
+}
+exports.getContentRect = getContentRect;
+// Returns the computed left/right/top/bottom scrollbar widths for the given jQuery element.
+// WARNING: given element can't have borders (which will cause offsetWidth/offsetHeight to be larger).
+// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
+function getScrollbarWidths(el) {
+ var leftRightWidth = el[0].offsetWidth - el[0].clientWidth;
+ var bottomWidth = el[0].offsetHeight - el[0].clientHeight;
+ var widths;
+ leftRightWidth = sanitizeScrollbarWidth(leftRightWidth);
+ bottomWidth = sanitizeScrollbarWidth(bottomWidth);
+ widths = { left: 0, right: 0, top: 0, bottom: bottomWidth };
+ if (getIsLeftRtlScrollbars() && el.css('direction') === 'rtl') {
+ widths.left = leftRightWidth;
+ }
+ else {
+ widths.right = leftRightWidth;
+ }
+ return widths;
+}
+exports.getScrollbarWidths = getScrollbarWidths;
+// The scrollbar width computations in getScrollbarWidths are sometimes flawed when it comes to
+// retina displays, rounding, and IE11. Massage them into a usable value.
+function sanitizeScrollbarWidth(width) {
+ width = Math.max(0, width); // no negatives
+ width = Math.round(width);
+ return width;
+}
+// Logic for determining if, when the element is right-to-left, the scrollbar appears on the left side
+var _isLeftRtlScrollbars = null;
+function getIsLeftRtlScrollbars() {
+ if (_isLeftRtlScrollbars === null) {
+ _isLeftRtlScrollbars = computeIsLeftRtlScrollbars();
+ }
+ return _isLeftRtlScrollbars;
+}
+function computeIsLeftRtlScrollbars() {
+ var el = $('<div><div/></div>')
+ .css({
+ position: 'absolute',
+ top: -1000,
+ left: 0,
+ border: 0,
+ padding: 0,
+ overflow: 'scroll',
+ direction: 'rtl'
+ })
+ .appendTo('body');
+ var innerEl = el.children();
+ var res = innerEl.offset().left > el.offset().left; // is the inner div shifted to accommodate a left scrollbar?
+ el.remove();
+ return res;
+}
+// Retrieves a jQuery element's computed CSS value as a floating-point number.
+// If the queried value is non-numeric (ex: IE can return "medium" for border width), will just return zero.
+function getCssFloat(el, prop) {
+ return parseFloat(el.css(prop)) || 0;
+}
+/* Mouse / Touch Utilities
+----------------------------------------------------------------------------------------------------------------------*/
+// Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
+function isPrimaryMouseButton(ev) {
+ return ev.which === 1 && !ev.ctrlKey;
+}
+exports.isPrimaryMouseButton = isPrimaryMouseButton;
+function getEvX(ev) {
+ var touches = ev.originalEvent.touches;
+ // on mobile FF, pageX for touch events is present, but incorrect,
+ // so, look at touch coordinates first.
+ if (touches && touches.length) {
+ return touches[0].pageX;
+ }
+ return ev.pageX;
+}
+exports.getEvX = getEvX;
+function getEvY(ev) {
+ var touches = ev.originalEvent.touches;
+ // on mobile FF, pageX for touch events is present, but incorrect,
+ // so, look at touch coordinates first.
+ if (touches && touches.length) {
+ return touches[0].pageY;
+ }
+ return ev.pageY;
+}
+exports.getEvY = getEvY;
+function getEvIsTouch(ev) {
+ return /^touch/.test(ev.type);
+}
+exports.getEvIsTouch = getEvIsTouch;
+function preventSelection(el) {
+ el.addClass('fc-unselectable')
+ .on('selectstart', preventDefault);
+}
+exports.preventSelection = preventSelection;
+function allowSelection(el) {
+ el.removeClass('fc-unselectable')
+ .off('selectstart', preventDefault);
+}
+exports.allowSelection = allowSelection;
+// Stops a mouse/touch event from doing it's native browser action
+function preventDefault(ev) {
+ ev.preventDefault();
+}
+exports.preventDefault = preventDefault;
+/* General Geometry Utils
+----------------------------------------------------------------------------------------------------------------------*/
+// Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
+function intersectRects(rect1, rect2) {
+ var res = {
+ left: Math.max(rect1.left, rect2.left),
+ right: Math.min(rect1.right, rect2.right),
+ top: Math.max(rect1.top, rect2.top),
+ bottom: Math.min(rect1.bottom, rect2.bottom)
+ };
+ if (res.left < res.right && res.top < res.bottom) {
+ return res;
+ }
+ return false;
+}
+exports.intersectRects = intersectRects;
+// Returns a new point that will have been moved to reside within the given rectangle
+function constrainPoint(point, rect) {
+ return {
+ left: Math.min(Math.max(point.left, rect.left), rect.right),
+ top: Math.min(Math.max(point.top, rect.top), rect.bottom)
+ };
+}
+exports.constrainPoint = constrainPoint;
+// Returns a point that is the center of the given rectangle
+function getRectCenter(rect) {
+ return {
+ left: (rect.left + rect.right) / 2,
+ top: (rect.top + rect.bottom) / 2
+ };
+}
+exports.getRectCenter = getRectCenter;
+// Subtracts point2's coordinates from point1's coordinates, returning a delta
+function diffPoints(point1, point2) {
+ return {
+ left: point1.left - point2.left,
+ top: point1.top - point2.top
+ };
+}
+exports.diffPoints = diffPoints;
+/* Object Ordering by Field
+----------------------------------------------------------------------------------------------------------------------*/
+function parseFieldSpecs(input) {
+ var specs = [];
+ var tokens = [];
+ var i;
+ var token;
+ if (typeof input === 'string') {
+ tokens = input.split(/\s*,\s*/);
+ }
+ else if (typeof input === 'function') {
+ tokens = [input];
+ }
+ else if ($.isArray(input)) {
+ tokens = input;
+ }
+ for (i = 0; i < tokens.length; i++) {
+ token = tokens[i];
+ if (typeof token === 'string') {
+ specs.push(token.charAt(0) === '-' ?
+ { field: token.substring(1), order: -1 } :
+ { field: token, order: 1 });
+ }
+ else if (typeof token === 'function') {
+ specs.push({ func: token });
+ }
+ }
+ return specs;
+}
+exports.parseFieldSpecs = parseFieldSpecs;
+function compareByFieldSpecs(obj1, obj2, fieldSpecs, obj1fallback, obj2fallback) {
+ var i;
+ var cmp;
+ for (i = 0; i < fieldSpecs.length; i++) {
+ cmp = compareByFieldSpec(obj1, obj2, fieldSpecs[i], obj1fallback, obj2fallback);
+ if (cmp) {
+ return cmp;
+ }
+ }
+ return 0;
+}
+exports.compareByFieldSpecs = compareByFieldSpecs;
+function compareByFieldSpec(obj1, obj2, fieldSpec, obj1fallback, obj2fallback) {
+ if (fieldSpec.func) {
+ return fieldSpec.func(obj1, obj2);
+ }
+ var val1 = obj1[fieldSpec.field];
+ var val2 = obj2[fieldSpec.field];
+ if (val1 == null && obj1fallback) {
+ val1 = obj1fallback[fieldSpec.field];
+ }
+ if (val2 == null && obj2fallback) {
+ val2 = obj2fallback[fieldSpec.field];
+ }
+ return flexibleCompare(val1, val2) * (fieldSpec.order || 1);
+}
+exports.compareByFieldSpec = compareByFieldSpec;
+function flexibleCompare(a, b) {
+ if (!a && !b) {
+ return 0;
+ }
+ if (b == null) {
+ return -1;
+ }
+ if (a == null) {
+ return 1;
+ }
+ if ($.type(a) === 'string' || $.type(b) === 'string') {
+ return String(a).localeCompare(String(b));
+ }
+ return a - b;
+}
+exports.flexibleCompare = flexibleCompare;
+/* Date Utilities
+----------------------------------------------------------------------------------------------------------------------*/
+exports.dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
+exports.unitsDesc = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond']; // descending
+// Diffs the two moments into a Duration where full-days are recorded first, then the remaining time.
+// Moments will have their timezones normalized.
+function diffDayTime(a, b) {
+ return moment.duration({
+ days: a.clone().stripTime().diff(b.clone().stripTime(), 'days'),
+ ms: a.time() - b.time() // time-of-day from day start. disregards timezone
+ });
+}
+exports.diffDayTime = diffDayTime;
+// Diffs the two moments via their start-of-day (regardless of timezone). Produces whole-day durations.
+function diffDay(a, b) {
+ return moment.duration({
+ days: a.clone().stripTime().diff(b.clone().stripTime(), 'days')
+ });
+}
+exports.diffDay = diffDay;
+// Diffs two moments, producing a duration, made of a whole-unit-increment of the given unit. Uses rounding.
+function diffByUnit(a, b, unit) {
+ return moment.duration(Math.round(a.diff(b, unit, true)), // returnFloat=true
+ unit);
+}
+exports.diffByUnit = diffByUnit;
+// Computes the unit name of the largest whole-unit period of time.
+// For example, 48 hours will be "days" whereas 49 hours will be "hours".
+// Accepts start/end, a range object, or an original duration object.
+function computeGreatestUnit(start, end) {
+ var i;
+ var unit;
+ var val;
+ for (i = 0; i < exports.unitsDesc.length; i++) {
+ unit = exports.unitsDesc[i];
+ val = computeRangeAs(unit, start, end);
+ if (val >= 1 && isInt(val)) {
+ break;
+ }
+ }
+ return unit; // will be "milliseconds" if nothing else matches
+}
+exports.computeGreatestUnit = computeGreatestUnit;
+// like computeGreatestUnit, but has special abilities to interpret the source input for clues
+function computeDurationGreatestUnit(duration, durationInput) {
+ var unit = computeGreatestUnit(duration);
+ // prevent days:7 from being interpreted as a week
+ if (unit === 'week' && typeof durationInput === 'object' && durationInput.days) {
+ unit = 'day';
+ }
+ return unit;
+}
+exports.computeDurationGreatestUnit = computeDurationGreatestUnit;
+// Computes the number of units (like "hours") in the given range.
+// Range can be a {start,end} object, separate start/end args, or a Duration.
+// Results are based on Moment's .as() and .diff() methods, so results can depend on internal handling
+// of month-diffing logic (which tends to vary from version to version).
+function computeRangeAs(unit, start, end) {
+ if (end != null) {
+ return end.diff(start, unit, true);
+ }
+ else if (moment.isDuration(start)) {
+ return start.as(unit);
+ }
+ else {
+ return start.end.diff(start.start, unit, true);
+ }
+}
+// Intelligently divides a range (specified by a start/end params) by a duration
+function divideRangeByDuration(start, end, dur) {
+ var months;
+ if (durationHasTime(dur)) {
+ return (end - start) / dur;
+ }
+ months = dur.asMonths();
+ if (Math.abs(months) >= 1 && isInt(months)) {
+ return end.diff(start, 'months', true) / months;
+ }
+ return end.diff(start, 'days', true) / dur.asDays();
+}
+exports.divideRangeByDuration = divideRangeByDuration;
+// Intelligently divides one duration by another
+function divideDurationByDuration(dur1, dur2) {
+ var months1;
+ var months2;
+ if (durationHasTime(dur1) || durationHasTime(dur2)) {
+ return dur1 / dur2;
+ }
+ months1 = dur1.asMonths();
+ months2 = dur2.asMonths();
+ if (Math.abs(months1) >= 1 && isInt(months1) &&
+ Math.abs(months2) >= 1 && isInt(months2)) {
+ return months1 / months2;
+ }
+ return dur1.asDays() / dur2.asDays();
+}
+exports.divideDurationByDuration = divideDurationByDuration;
+// Intelligently multiplies a duration by a number
+function multiplyDuration(dur, n) {
+ var months;
+ if (durationHasTime(dur)) {
+ return moment.duration(dur * n);
+ }
+ months = dur.asMonths();
+ if (Math.abs(months) >= 1 && isInt(months)) {
+ return moment.duration({ months: months * n });
+ }
+ return moment.duration({ days: dur.asDays() * n });
+}
+exports.multiplyDuration = multiplyDuration;
+// Returns a boolean about whether the given duration has any time parts (hours/minutes/seconds/ms)
+function durationHasTime(dur) {
+ return Boolean(dur.hours() || dur.minutes() || dur.seconds() || dur.milliseconds());
+}
+exports.durationHasTime = durationHasTime;
+function isNativeDate(input) {
+ return Object.prototype.toString.call(input) === '[object Date]' || input instanceof Date;
+}
+exports.isNativeDate = isNativeDate;
+// Returns a boolean about whether the given input is a time string, like "06:40:00" or "06:00"
+function isTimeString(str) {
+ return typeof str === 'string' &&
+ /^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(str);
+}
+exports.isTimeString = isTimeString;
+/* Logging and Debug
+----------------------------------------------------------------------------------------------------------------------*/
+function log() {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ var console = window.console;
+ if (console && console.log) {
+ return console.log.apply(console, args);
+ }
+}
+exports.log = log;
+function warn() {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ var console = window.console;
+ if (console && console.warn) {
+ return console.warn.apply(console, args);
+ }
+ else {
+ return log.apply(null, args);
+ }
+}
+exports.warn = warn;
+/* General Utilities
+----------------------------------------------------------------------------------------------------------------------*/
+var hasOwnPropMethod = {}.hasOwnProperty;
+// Merges an array of objects into a single object.
+// The second argument allows for an array of property names who's object values will be merged together.
+function mergeProps(propObjs, complexProps) {
+ var dest = {};
+ var i;
+ var name;
+ var complexObjs;
+ var j;
+ var val;
+ var props;
+ if (complexProps) {
+ for (i = 0; i < complexProps.length; i++) {
+ name = complexProps[i];
+ complexObjs = [];
+ // collect the trailing object values, stopping when a non-object is discovered
+ for (j = propObjs.length - 1; j >= 0; j--) {
+ val = propObjs[j][name];
+ if (typeof val === 'object') {
+ complexObjs.unshift(val);
+ }
+ else if (val !== undefined) {
+ dest[name] = val; // if there were no objects, this value will be used
+ break;
+ }
+ }
+ // if the trailing values were objects, use the merged value
+ if (complexObjs.length) {
+ dest[name] = mergeProps(complexObjs);
+ }
+ }
+ }
+ // copy values into the destination, going from last to first
+ for (i = propObjs.length - 1; i >= 0; i--) {
+ props = propObjs[i];
+ for (name in props) {
+ if (!(name in dest)) {
+ dest[name] = props[name];
+ }
+ }
+ }
+ return dest;
+}
+exports.mergeProps = mergeProps;
+function copyOwnProps(src, dest) {
+ for (var name_1 in src) {
+ if (hasOwnProp(src, name_1)) {
+ dest[name_1] = src[name_1];
+ }
+ }
+}
+exports.copyOwnProps = copyOwnProps;
+function hasOwnProp(obj, name) {
+ return hasOwnPropMethod.call(obj, name);
+}
+exports.hasOwnProp = hasOwnProp;
+function applyAll(functions, thisObj, args) {
+ if ($.isFunction(functions)) {
+ functions = [functions];
+ }
+ if (functions) {
+ var i = void 0;
+ var ret = void 0;
+ for (i = 0; i < functions.length; i++) {
+ ret = functions[i].apply(thisObj, args) || ret;
+ }
+ return ret;
+ }
+}
+exports.applyAll = applyAll;
+function removeMatching(array, testFunc) {
+ var removeCnt = 0;
+ var i = 0;
+ while (i < array.length) {
+ if (testFunc(array[i])) {
+ array.splice(i, 1);
+ removeCnt++;
+ }
+ else {
+ i++;
+ }
+ }
+ return removeCnt;
+}
+exports.removeMatching = removeMatching;
+function removeExact(array, exactVal) {
+ var removeCnt = 0;
+ var i = 0;
+ while (i < array.length) {
+ if (array[i] === exactVal) {
+ array.splice(i, 1);
+ removeCnt++;
+ }
+ else {
+ i++;
+ }
+ }
+ return removeCnt;
+}
+exports.removeExact = removeExact;
+function isArraysEqual(a0, a1) {
+ var len = a0.length;
+ var i;
+ if (len == null || len !== a1.length) {
+ return false;
+ }
+ for (i = 0; i < len; i++) {
+ if (a0[i] !== a1[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+exports.isArraysEqual = isArraysEqual;
+function firstDefined() {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ for (var i = 0; i < args.length; i++) {
+ if (args[i] !== undefined) {
+ return args[i];
+ }
+ }
+}
+exports.firstDefined = firstDefined;
+function htmlEscape(s) {
+ return (s + '').replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/'/g, '&#039;')
+ .replace(/"/g, '&quot;')
+ .replace(/\n/g, '<br />');
+}
+exports.htmlEscape = htmlEscape;
+function stripHtmlEntities(text) {
+ return text.replace(/&.*?;/g, '');
+}
+exports.stripHtmlEntities = stripHtmlEntities;
+// Given a hash of CSS properties, returns a string of CSS.
+// Uses property names as-is (no camel-case conversion). Will not make statements for null/undefined values.
+function cssToStr(cssProps) {
+ var statements = [];
+ $.each(cssProps, function (name, val) {
+ if (val != null) {
+ statements.push(name + ':' + val);
+ }
+ });
+ return statements.join(';');
+}
+exports.cssToStr = cssToStr;
+// Given an object hash of HTML attribute names to values,
+// generates a string that can be injected between < > in HTML
+function attrsToStr(attrs) {
+ var parts = [];
+ $.each(attrs, function (name, val) {
+ if (val != null) {
+ parts.push(name + '="' + htmlEscape(val) + '"');
+ }
+ });
+ return parts.join(' ');
+}
+exports.attrsToStr = attrsToStr;
+function capitaliseFirstLetter(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+exports.capitaliseFirstLetter = capitaliseFirstLetter;
+function compareNumbers(a, b) {
+ return a - b;
+}
+exports.compareNumbers = compareNumbers;
+function isInt(n) {
+ return n % 1 === 0;
+}
+exports.isInt = isInt;
+// Returns a method bound to the given object context.
+// Just like one of the jQuery.proxy signatures, but without the undesired behavior of treating the same method with
+// different contexts as identical when binding/unbinding events.
+function proxy(obj, methodName) {
+ var method = obj[methodName];
+ return function () {
+ return method.apply(obj, arguments);
+ };
+}
+exports.proxy = proxy;
+// Returns a function, that, as long as it continues to be invoked, will not
+// be triggered. The function will be called after it stops being called for
+// N milliseconds. If `immediate` is passed, trigger the function on the
+// leading edge, instead of the trailing.
+// https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714
+function debounce(func, wait, immediate) {
+ if (immediate === void 0) { immediate = false; }
+ var timeout;
+ var args;
+ var context;
+ var timestamp;
+ var result;
+ var later = function () {
+ var last = +new Date() - timestamp;
+ if (last < wait) {
+ timeout = setTimeout(later, wait - last);
+ }
+ else {
+ timeout = null;
+ if (!immediate) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+ }
+ };
+ return function () {
+ context = this;
+ args = arguments;
+ timestamp = +new Date();
+ var callNow = immediate && !timeout;
+ if (!timeout) {
+ timeout = setTimeout(later, wait);
+ }
+ if (callNow) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+ return result;
+ };
+}
+exports.debounce = debounce;
+
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var moment_ext_1 = __webpack_require__(10);
+var UnzonedRange = /** @class */ (function () {
+ function UnzonedRange(startInput, endInput) {
+ // TODO: move these into footprint.
+ // Especially, doesn't make sense for null startMs/endMs.
+ this.isStart = true;
+ this.isEnd = true;
+ if (moment.isMoment(startInput)) {
+ startInput = startInput.clone().stripZone();
+ }
+ if (moment.isMoment(endInput)) {
+ endInput = endInput.clone().stripZone();
+ }
+ if (startInput) {
+ this.startMs = startInput.valueOf();
+ }
+ if (endInput) {
+ this.endMs = endInput.valueOf();
+ }
+ }
+ /*
+ SIDEEFFECT: will mutate eventRanges.
+ Will return a new array result.
+ Only works for non-open-ended ranges.
+ */
+ UnzonedRange.invertRanges = function (ranges, constraintRange) {
+ var invertedRanges = [];
+ var startMs = constraintRange.startMs; // the end of the previous range. the start of the new range
+ var i;
+ var dateRange;
+ // ranges need to be in order. required for our date-walking algorithm
+ ranges.sort(compareUnzonedRanges);
+ for (i = 0; i < ranges.length; i++) {
+ dateRange = ranges[i];
+ // add the span of time before the event (if there is any)
+ if (dateRange.startMs > startMs) {
+ invertedRanges.push(new UnzonedRange(startMs, dateRange.startMs));
+ }
+ if (dateRange.endMs > startMs) {
+ startMs = dateRange.endMs;
+ }
+ }
+ // add the span of time after the last event (if there is any)
+ if (startMs < constraintRange.endMs) {
+ invertedRanges.push(new UnzonedRange(startMs, constraintRange.endMs));
+ }
+ return invertedRanges;
+ };
+ UnzonedRange.prototype.intersect = function (otherRange) {
+ var startMs = this.startMs;
+ var endMs = this.endMs;
+ var newRange = null;
+ if (otherRange.startMs != null) {
+ if (startMs == null) {
+ startMs = otherRange.startMs;
+ }
+ else {
+ startMs = Math.max(startMs, otherRange.startMs);
+ }
+ }
+ if (otherRange.endMs != null) {
+ if (endMs == null) {
+ endMs = otherRange.endMs;
+ }
+ else {
+ endMs = Math.min(endMs, otherRange.endMs);
+ }
+ }
+ if (startMs == null || endMs == null || startMs < endMs) {
+ newRange = new UnzonedRange(startMs, endMs);
+ newRange.isStart = this.isStart && startMs === this.startMs;
+ newRange.isEnd = this.isEnd && endMs === this.endMs;
+ }
+ return newRange;
+ };
+ UnzonedRange.prototype.intersectsWith = function (otherRange) {
+ return (this.endMs == null || otherRange.startMs == null || this.endMs > otherRange.startMs) &&
+ (this.startMs == null || otherRange.endMs == null || this.startMs < otherRange.endMs);
+ };
+ UnzonedRange.prototype.containsRange = function (innerRange) {
+ return (this.startMs == null || (innerRange.startMs != null && innerRange.startMs >= this.startMs)) &&
+ (this.endMs == null || (innerRange.endMs != null && innerRange.endMs <= this.endMs));
+ };
+ // `date` can be a moment, a Date, or a millisecond time.
+ UnzonedRange.prototype.containsDate = function (date) {
+ var ms = date.valueOf();
+ return (this.startMs == null || ms >= this.startMs) &&
+ (this.endMs == null || ms < this.endMs);
+ };
+ // If the given date is not within the given range, move it inside.
+ // (If it's past the end, make it one millisecond before the end).
+ // `date` can be a moment, a Date, or a millisecond time.
+ // Returns a MS-time.
+ UnzonedRange.prototype.constrainDate = function (date) {
+ var ms = date.valueOf();
+ if (this.startMs != null && ms < this.startMs) {
+ ms = this.startMs;
+ }
+ if (this.endMs != null && ms >= this.endMs) {
+ ms = this.endMs - 1;
+ }
+ return ms;
+ };
+ UnzonedRange.prototype.equals = function (otherRange) {
+ return this.startMs === otherRange.startMs && this.endMs === otherRange.endMs;
+ };
+ UnzonedRange.prototype.clone = function () {
+ var range = new UnzonedRange(this.startMs, this.endMs);
+ range.isStart = this.isStart;
+ range.isEnd = this.isEnd;
+ return range;
+ };
+ // Returns an ambig-zoned moment from startMs.
+ // BEWARE: returned moment is not localized.
+ // Formatting and start-of-week will be default.
+ UnzonedRange.prototype.getStart = function () {
+ if (this.startMs != null) {
+ return moment_ext_1.default.utc(this.startMs).stripZone();
+ }
+ return null;
+ };
+ // Returns an ambig-zoned moment from startMs.
+ // BEWARE: returned moment is not localized.
+ // Formatting and start-of-week will be default.
+ UnzonedRange.prototype.getEnd = function () {
+ if (this.endMs != null) {
+ return moment_ext_1.default.utc(this.endMs).stripZone();
+ }
+ return null;
+ };
+ UnzonedRange.prototype.as = function (unit) {
+ return moment.utc(this.endMs).diff(moment.utc(this.startMs), unit, true);
+ };
+ return UnzonedRange;
+}());
+exports.default = UnzonedRange;
+/*
+Only works for non-open-ended ranges.
+*/
+function compareUnzonedRanges(range1, range2) {
+ return range1.startMs - range2.startMs; // earlier ranges go first
+}
+
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var ParsableModelMixin_1 = __webpack_require__(208);
+var Class_1 = __webpack_require__(33);
+var EventDefParser_1 = __webpack_require__(49);
+var EventSource = /** @class */ (function (_super) {
+ tslib_1.__extends(EventSource, _super);
+ // can we do away with calendar? at least for the abstract?
+ // useful for buildEventDef
+ function EventSource(calendar) {
+ var _this = _super.call(this) || this;
+ _this.calendar = calendar;
+ _this.className = [];
+ _this.uid = String(EventSource.uuid++);
+ return _this;
+ }
+ /*
+ rawInput can be any data type!
+ */
+ EventSource.parse = function (rawInput, calendar) {
+ var source = new this(calendar);
+ if (typeof rawInput === 'object') {
+ if (source.applyProps(rawInput)) {
+ return source;
+ }
+ }
+ return false;
+ };
+ EventSource.normalizeId = function (id) {
+ if (id) {
+ return String(id);
+ }
+ return null;
+ };
+ EventSource.prototype.fetch = function (start, end, timezone) {
+ // subclasses must implement. must return a promise.
+ };
+ EventSource.prototype.removeEventDefsById = function (eventDefId) {
+ // optional for subclasses to implement
+ };
+ EventSource.prototype.removeAllEventDefs = function () {
+ // optional for subclasses to implement
+ };
+ /*
+ For compairing/matching
+ */
+ EventSource.prototype.getPrimitive = function (otherSource) {
+ // subclasses must implement
+ };
+ EventSource.prototype.parseEventDefs = function (rawEventDefs) {
+ var i;
+ var eventDef;
+ var eventDefs = [];
+ for (i = 0; i < rawEventDefs.length; i++) {
+ eventDef = this.parseEventDef(rawEventDefs[i]);
+ if (eventDef) {
+ eventDefs.push(eventDef);
+ }
+ }
+ return eventDefs;
+ };
+ EventSource.prototype.parseEventDef = function (rawInput) {
+ var calendarTransform = this.calendar.opt('eventDataTransform');
+ var sourceTransform = this.eventDataTransform;
+ if (calendarTransform) {
+ rawInput = calendarTransform(rawInput, this.calendar);
+ }
+ if (sourceTransform) {
+ rawInput = sourceTransform(rawInput, this.calendar);
+ }
+ return EventDefParser_1.default.parse(rawInput, this);
+ };
+ EventSource.prototype.applyManualStandardProps = function (rawProps) {
+ if (rawProps.id != null) {
+ this.id = EventSource.normalizeId(rawProps.id);
+ }
+ // TODO: converge with EventDef
+ if ($.isArray(rawProps.className)) {
+ this.className = rawProps.className;
+ }
+ else if (typeof rawProps.className === 'string') {
+ this.className = rawProps.className.split(/\s+/);
+ }
+ return true;
+ };
+ EventSource.uuid = 0;
+ EventSource.defineStandardProps = ParsableModelMixin_1.default.defineStandardProps;
+ EventSource.copyVerbatimStandardProps = ParsableModelMixin_1.default.copyVerbatimStandardProps;
+ return EventSource;
+}(Class_1.default));
+exports.default = EventSource;
+ParsableModelMixin_1.default.mixInto(EventSource);
+// Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+EventSource.defineStandardProps({
+ // manually process...
+ id: false,
+ className: false,
+ // automatically transfer...
+ color: true,
+ backgroundColor: true,
+ borderColor: true,
+ textColor: true,
+ editable: true,
+ startEditable: true,
+ durationEditable: true,
+ rendering: true,
+ overlap: true,
+ constraint: true,
+ allDayDefault: true,
+ eventDataTransform: true
+});
+
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/*
+Utility methods for easily listening to events on another object,
+and more importantly, easily unlistening from them.
+
+USAGE:
+ import { default as ListenerMixin, ListenerInterface } from './ListenerMixin'
+in class:
+ listenTo: ListenerInterface['listenTo']
+ stopListeningTo: ListenerInterface['stopListeningTo']
+after class:
+ ListenerMixin.mixInto(TheClass)
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var Mixin_1 = __webpack_require__(14);
+var guid = 0;
+var ListenerMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(ListenerMixin, _super);
+ function ListenerMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ /*
+ Given an `other` object that has on/off methods, bind the given `callback` to an event by the given name.
+ The `callback` will be called with the `this` context of the object that .listenTo is being called on.
+ Can be called:
+ .listenTo(other, eventName, callback)
+ OR
+ .listenTo(other, {
+ eventName1: callback1,
+ eventName2: callback2
+ })
+ */
+ ListenerMixin.prototype.listenTo = function (other, arg, callback) {
+ if (typeof arg === 'object') {
+ for (var eventName in arg) {
+ if (arg.hasOwnProperty(eventName)) {
+ this.listenTo(other, eventName, arg[eventName]);
+ }
+ }
+ }
+ else if (typeof arg === 'string') {
+ other.on(arg + '.' + this.getListenerNamespace(), // use event namespacing to identify this object
+ $.proxy(callback, this) // always use `this` context
+ // the usually-undesired jQuery guid behavior doesn't matter,
+ // because we always unbind via namespace
+ );
+ }
+ };
+ /*
+ Causes the current object to stop listening to events on the `other` object.
+ `eventName` is optional. If omitted, will stop listening to ALL events on `other`.
+ */
+ ListenerMixin.prototype.stopListeningTo = function (other, eventName) {
+ other.off((eventName || '') + '.' + this.getListenerNamespace());
+ };
+ /*
+ Returns a string, unique to this object, to be used for event namespacing
+ */
+ ListenerMixin.prototype.getListenerNamespace = function () {
+ if (this.listenerId == null) {
+ this.listenerId = guid++;
+ }
+ return '_listener' + this.listenerId;
+ };
+ return ListenerMixin;
+}(Mixin_1.default));
+exports.default = ListenerMixin;
+
+
+/***/ }),
+/* 8 */,
+/* 9 */,
+/* 10 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ambigDateOfMonthRegex = /^\s*\d{4}-\d\d$/;
+var ambigTimeOrZoneRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/;
+var newMomentProto = moment.fn; // where we will attach our new methods
+exports.newMomentProto = newMomentProto;
+var oldMomentProto = $.extend({}, newMomentProto); // copy of original moment methods
+exports.oldMomentProto = oldMomentProto;
+// tell momentjs to transfer these properties upon clone
+var momentProperties = moment.momentProperties;
+momentProperties.push('_fullCalendar');
+momentProperties.push('_ambigTime');
+momentProperties.push('_ambigZone');
+/*
+Call this if you want Moment's original format method to be used
+*/
+function oldMomentFormat(mom, formatStr) {
+ return oldMomentProto.format.call(mom, formatStr); // oldMomentProto defined in moment-ext.js
+}
+exports.oldMomentFormat = oldMomentFormat;
+// Creating
+// -------------------------------------------------------------------------------------------------
+// Creates a new moment, similar to the vanilla moment(...) constructor, but with
+// extra features (ambiguous time, enhanced formatting). When given an existing moment,
+// it will function as a clone (and retain the zone of the moment). Anything else will
+// result in a moment in the local zone.
+var momentExt = function () {
+ return makeMoment(arguments);
+};
+exports.default = momentExt;
+// Sames as momentExt, but forces the resulting moment to be in the UTC timezone.
+momentExt.utc = function () {
+ var mom = makeMoment(arguments, true);
+ // Force it into UTC because makeMoment doesn't guarantee it
+ // (if given a pre-existing moment for example)
+ if (mom.hasTime()) {
+ mom.utc();
+ }
+ return mom;
+};
+// Same as momentExt, but when given an ISO8601 string, the timezone offset is preserved.
+// ISO8601 strings with no timezone offset will become ambiguously zoned.
+momentExt.parseZone = function () {
+ return makeMoment(arguments, true, true);
+};
+// Builds an enhanced moment from args. When given an existing moment, it clones. When given a
+// native Date, or called with no arguments (the current time), the resulting moment will be local.
+// Anything else needs to be "parsed" (a string or an array), and will be affected by:
+// parseAsUTC - if there is no zone information, should we parse the input in UTC?
+// parseZone - if there is zone information, should we force the zone of the moment?
+function makeMoment(args, parseAsUTC, parseZone) {
+ if (parseAsUTC === void 0) { parseAsUTC = false; }
+ if (parseZone === void 0) { parseZone = false; }
+ var input = args[0];
+ var isSingleString = args.length === 1 && typeof input === 'string';
+ var isAmbigTime;
+ var isAmbigZone;
+ var ambigMatch;
+ var mom;
+ if (moment.isMoment(input) || util_1.isNativeDate(input) || input === undefined) {
+ mom = moment.apply(null, args);
+ }
+ else {
+ isAmbigTime = false;
+ isAmbigZone = false;
+ if (isSingleString) {
+ if (ambigDateOfMonthRegex.test(input)) {
+ // accept strings like '2014-05', but convert to the first of the month
+ input += '-01';
+ args = [input]; // for when we pass it on to moment's constructor
+ isAmbigTime = true;
+ isAmbigZone = true;
+ }
+ else if ((ambigMatch = ambigTimeOrZoneRegex.exec(input))) {
+ isAmbigTime = !ambigMatch[5]; // no time part?
+ isAmbigZone = true;
+ }
+ }
+ else if ($.isArray(input)) {
+ // arrays have no timezone information, so assume ambiguous zone
+ isAmbigZone = true;
+ }
+ // otherwise, probably a string with a format
+ if (parseAsUTC || isAmbigTime) {
+ mom = moment.utc.apply(moment, args);
+ }
+ else {
+ mom = moment.apply(null, args);
+ }
+ if (isAmbigTime) {
+ mom._ambigTime = true;
+ mom._ambigZone = true; // ambiguous time always means ambiguous zone
+ }
+ else if (parseZone) {
+ if (isAmbigZone) {
+ mom._ambigZone = true;
+ }
+ else if (isSingleString) {
+ mom.utcOffset(input); // if not a valid zone, will assign UTC
+ }
+ }
+ }
+ mom._fullCalendar = true; // flag for extended functionality
+ return mom;
+}
+// Week Number
+// -------------------------------------------------------------------------------------------------
+// Returns the week number, considering the locale's custom week number calcuation
+// `weeks` is an alias for `week`
+newMomentProto.week = newMomentProto.weeks = function (input) {
+ var weekCalc = this._locale._fullCalendar_weekCalc;
+ if (input == null && typeof weekCalc === 'function') {
+ return weekCalc(this);
+ }
+ else if (weekCalc === 'ISO') {
+ return oldMomentProto.isoWeek.apply(this, arguments); // ISO getter/setter
+ }
+ return oldMomentProto.week.apply(this, arguments); // local getter/setter
+};
+// Time-of-day
+// -------------------------------------------------------------------------------------------------
+// GETTER
+// Returns a Duration with the hours/minutes/seconds/ms values of the moment.
+// If the moment has an ambiguous time, a duration of 00:00 will be returned.
+//
+// SETTER
+// You can supply a Duration, a Moment, or a Duration-like argument.
+// When setting the time, and the moment has an ambiguous time, it then becomes unambiguous.
+newMomentProto.time = function (time) {
+ // Fallback to the original method (if there is one) if this moment wasn't created via FullCalendar.
+ // `time` is a generic enough method name where this precaution is necessary to avoid collisions w/ other plugins.
+ if (!this._fullCalendar) {
+ return oldMomentProto.time.apply(this, arguments);
+ }
+ if (time == null) {
+ return moment.duration({
+ hours: this.hours(),
+ minutes: this.minutes(),
+ seconds: this.seconds(),
+ milliseconds: this.milliseconds()
+ });
+ }
+ else {
+ this._ambigTime = false; // mark that the moment now has a time
+ if (!moment.isDuration(time) && !moment.isMoment(time)) {
+ time = moment.duration(time);
+ }
+ // The day value should cause overflow (so 24 hours becomes 00:00:00 of next day).
+ // Only for Duration times, not Moment times.
+ var dayHours = 0;
+ if (moment.isDuration(time)) {
+ dayHours = Math.floor(time.asDays()) * 24;
+ }
+ // We need to set the individual fields.
+ // Can't use startOf('day') then add duration. In case of DST at start of day.
+ return this.hours(dayHours + time.hours())
+ .minutes(time.minutes())
+ .seconds(time.seconds())
+ .milliseconds(time.milliseconds());
+ }
+};
+// Converts the moment to UTC, stripping out its time-of-day and timezone offset,
+// but preserving its YMD. A moment with a stripped time will display no time
+// nor timezone offset when .format() is called.
+newMomentProto.stripTime = function () {
+ if (!this._ambigTime) {
+ this.utc(true); // keepLocalTime=true (for keeping *date* value)
+ // set time to zero
+ this.set({
+ hours: 0,
+ minutes: 0,
+ seconds: 0,
+ ms: 0
+ });
+ // Mark the time as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
+ // which clears all ambig flags.
+ this._ambigTime = true;
+ this._ambigZone = true; // if ambiguous time, also ambiguous timezone offset
+ }
+ return this; // for chaining
+};
+// Returns if the moment has a non-ambiguous time (boolean)
+newMomentProto.hasTime = function () {
+ return !this._ambigTime;
+};
+// Timezone
+// -------------------------------------------------------------------------------------------------
+// Converts the moment to UTC, stripping out its timezone offset, but preserving its
+// YMD and time-of-day. A moment with a stripped timezone offset will display no
+// timezone offset when .format() is called.
+newMomentProto.stripZone = function () {
+ var wasAmbigTime;
+ if (!this._ambigZone) {
+ wasAmbigTime = this._ambigTime;
+ this.utc(true); // keepLocalTime=true (for keeping date and time values)
+ // the above call to .utc()/.utcOffset() unfortunately might clear the ambig flags, so restore
+ this._ambigTime = wasAmbigTime || false;
+ // Mark the zone as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
+ // which clears the ambig flags.
+ this._ambigZone = true;
+ }
+ return this; // for chaining
+};
+// Returns of the moment has a non-ambiguous timezone offset (boolean)
+newMomentProto.hasZone = function () {
+ return !this._ambigZone;
+};
+// implicitly marks a zone
+newMomentProto.local = function (keepLocalTime) {
+ // for when converting from ambiguously-zoned to local,
+ // keep the time values when converting from UTC -> local
+ oldMomentProto.local.call(this, this._ambigZone || keepLocalTime);
+ // ensure non-ambiguous
+ // this probably already happened via local() -> utcOffset(), but don't rely on Moment's internals
+ this._ambigTime = false;
+ this._ambigZone = false;
+ return this; // for chaining
+};
+// implicitly marks a zone
+newMomentProto.utc = function (keepLocalTime) {
+ oldMomentProto.utc.call(this, keepLocalTime);
+ // ensure non-ambiguous
+ // this probably already happened via utc() -> utcOffset(), but don't rely on Moment's internals
+ this._ambigTime = false;
+ this._ambigZone = false;
+ return this;
+};
+// implicitly marks a zone (will probably get called upon .utc() and .local())
+newMomentProto.utcOffset = function (tzo) {
+ if (tzo != null) {
+ // these assignments needs to happen before the original zone method is called.
+ // I forget why, something to do with a browser crash.
+ this._ambigTime = false;
+ this._ambigZone = false;
+ }
+ return oldMomentProto.utcOffset.apply(this, arguments);
+};
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/*
+USAGE:
+ import { default as EmitterMixin, EmitterInterface } from './EmitterMixin'
+in class:
+ on: EmitterInterface['on']
+ one: EmitterInterface['one']
+ off: EmitterInterface['off']
+ trigger: EmitterInterface['trigger']
+ triggerWith: EmitterInterface['triggerWith']
+ hasHandlers: EmitterInterface['hasHandlers']
+after class:
+ EmitterMixin.mixInto(TheClass)
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var Mixin_1 = __webpack_require__(14);
+var EmitterMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(EmitterMixin, _super);
+ function EmitterMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // jQuery-ification via $(this) allows a non-DOM object to have
+ // the same event handling capabilities (including namespaces).
+ EmitterMixin.prototype.on = function (types, handler) {
+ $(this).on(types, this._prepareIntercept(handler));
+ return this; // for chaining
+ };
+ EmitterMixin.prototype.one = function (types, handler) {
+ $(this).one(types, this._prepareIntercept(handler));
+ return this; // for chaining
+ };
+ EmitterMixin.prototype._prepareIntercept = function (handler) {
+ // handlers are always called with an "event" object as their first param.
+ // sneak the `this` context and arguments into the extra parameter object
+ // and forward them on to the original handler.
+ var intercept = function (ev, extra) {
+ return handler.apply(extra.context || this, extra.args || []);
+ };
+ // mimick jQuery's internal "proxy" system (risky, I know)
+ // causing all functions with the same .guid to appear to be the same.
+ // https://github.com/jquery/jquery/blob/2.2.4/src/core.js#L448
+ // this is needed for calling .off with the original non-intercept handler.
+ if (!handler.guid) {
+ handler.guid = $.guid++;
+ }
+ intercept.guid = handler.guid;
+ return intercept;
+ };
+ EmitterMixin.prototype.off = function (types, handler) {
+ $(this).off(types, handler);
+ return this; // for chaining
+ };
+ EmitterMixin.prototype.trigger = function (types) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ // pass in "extra" info to the intercept
+ $(this).triggerHandler(types, { args: args });
+ return this; // for chaining
+ };
+ EmitterMixin.prototype.triggerWith = function (types, context, args) {
+ // `triggerHandler` is less reliant on the DOM compared to `trigger`.
+ // pass in "extra" info to the intercept.
+ $(this).triggerHandler(types, { context: context, args: args });
+ return this; // for chaining
+ };
+ EmitterMixin.prototype.hasHandlers = function (type) {
+ var hash = $._data(this, 'events'); // http://blog.jquery.com/2012/08/09/jquery-1-8-released/
+ return hash && hash[type] && hash[type].length > 0;
+ };
+ return EmitterMixin;
+}(Mixin_1.default));
+exports.default = EmitterMixin;
+
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+/*
+Meant to be immutable
+*/
+var ComponentFootprint = /** @class */ (function () {
+ function ComponentFootprint(unzonedRange, isAllDay) {
+ this.isAllDay = false; // component can choose to ignore this
+ this.unzonedRange = unzonedRange;
+ this.isAllDay = isAllDay;
+ }
+ /*
+ Only works for non-open-ended ranges.
+ */
+ ComponentFootprint.prototype.toLegacy = function (calendar) {
+ return {
+ start: calendar.msToMoment(this.unzonedRange.startMs, this.isAllDay),
+ end: calendar.msToMoment(this.unzonedRange.endMs, this.isAllDay)
+ };
+ };
+ return ComponentFootprint;
+}());
+exports.default = ComponentFootprint;
+
+
+/***/ }),
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var EventDef_1 = __webpack_require__(34);
+var EventInstance_1 = __webpack_require__(209);
+var EventDateProfile_1 = __webpack_require__(17);
+var SingleEventDef = /** @class */ (function (_super) {
+ tslib_1.__extends(SingleEventDef, _super);
+ function SingleEventDef() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ /*
+ Will receive start/end params, but will be ignored.
+ */
+ SingleEventDef.prototype.buildInstances = function () {
+ return [this.buildInstance()];
+ };
+ SingleEventDef.prototype.buildInstance = function () {
+ return new EventInstance_1.default(this, // definition
+ this.dateProfile);
+ };
+ SingleEventDef.prototype.isAllDay = function () {
+ return this.dateProfile.isAllDay();
+ };
+ SingleEventDef.prototype.clone = function () {
+ var def = _super.prototype.clone.call(this);
+ def.dateProfile = this.dateProfile;
+ return def;
+ };
+ SingleEventDef.prototype.rezone = function () {
+ var calendar = this.source.calendar;
+ var dateProfile = this.dateProfile;
+ this.dateProfile = new EventDateProfile_1.default(calendar.moment(dateProfile.start), dateProfile.end ? calendar.moment(dateProfile.end) : null, calendar);
+ };
+ /*
+ NOTE: if super-method fails, should still attempt to apply
+ */
+ SingleEventDef.prototype.applyManualStandardProps = function (rawProps) {
+ var superSuccess = _super.prototype.applyManualStandardProps.call(this, rawProps);
+ var dateProfile = EventDateProfile_1.default.parse(rawProps, this.source); // returns null on failure
+ if (dateProfile) {
+ this.dateProfile = dateProfile;
+ // make sure `date` shows up in the legacy event objects as-is
+ if (rawProps.date != null) {
+ this.miscProps.date = rawProps.date;
+ }
+ return superSuccess;
+ }
+ else {
+ return false;
+ }
+ };
+ return SingleEventDef;
+}(EventDef_1.default));
+exports.default = SingleEventDef;
+// Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+SingleEventDef.defineStandardProps({
+ start: false,
+ date: false,
+ end: false,
+ allDay: false
+});
+
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var Mixin = /** @class */ (function () {
+ function Mixin() {
+ }
+ Mixin.mixInto = function (destClass) {
+ var _this = this;
+ Object.getOwnPropertyNames(this.prototype).forEach(function (name) {
+ if (!destClass.prototype[name]) {
+ destClass.prototype[name] = _this.prototype[name];
+ }
+ });
+ };
+ /*
+ will override existing methods
+ TODO: remove! not used anymore
+ */
+ Mixin.mixOver = function (destClass) {
+ var _this = this;
+ Object.getOwnPropertyNames(this.prototype).forEach(function (name) {
+ destClass.prototype[name] = _this.prototype[name];
+ });
+ };
+ return Mixin;
+}());
+exports.default = Mixin;
+
+
+/***/ }),
+/* 15 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var Interaction = /** @class */ (function () {
+ function Interaction(component) {
+ this.view = component._getView();
+ this.component = component;
+ }
+ Interaction.prototype.opt = function (name) {
+ return this.view.opt(name);
+ };
+ Interaction.prototype.end = function () {
+ // subclasses can implement
+ };
+ return Interaction;
+}());
+exports.default = Interaction;
+
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.version = '3.9.0';
+// When introducing internal API incompatibilities (where fullcalendar plugins would break),
+// the minor version of the calendar should be upped (ex: 2.7.2 -> 2.8.0)
+// and the below integer should be incremented.
+exports.internalApiVersion = 12;
+var util_1 = __webpack_require__(4);
+exports.applyAll = util_1.applyAll;
+exports.debounce = util_1.debounce;
+exports.isInt = util_1.isInt;
+exports.htmlEscape = util_1.htmlEscape;
+exports.cssToStr = util_1.cssToStr;
+exports.proxy = util_1.proxy;
+exports.capitaliseFirstLetter = util_1.capitaliseFirstLetter;
+exports.getOuterRect = util_1.getOuterRect;
+exports.getClientRect = util_1.getClientRect;
+exports.getContentRect = util_1.getContentRect;
+exports.getScrollbarWidths = util_1.getScrollbarWidths;
+exports.preventDefault = util_1.preventDefault;
+exports.parseFieldSpecs = util_1.parseFieldSpecs;
+exports.compareByFieldSpecs = util_1.compareByFieldSpecs;
+exports.compareByFieldSpec = util_1.compareByFieldSpec;
+exports.flexibleCompare = util_1.flexibleCompare;
+exports.computeGreatestUnit = util_1.computeGreatestUnit;
+exports.divideRangeByDuration = util_1.divideRangeByDuration;
+exports.divideDurationByDuration = util_1.divideDurationByDuration;
+exports.multiplyDuration = util_1.multiplyDuration;
+exports.durationHasTime = util_1.durationHasTime;
+exports.log = util_1.log;
+exports.warn = util_1.warn;
+exports.removeExact = util_1.removeExact;
+exports.intersectRects = util_1.intersectRects;
+var date_formatting_1 = __webpack_require__(47);
+exports.formatDate = date_formatting_1.formatDate;
+exports.formatRange = date_formatting_1.formatRange;
+exports.queryMostGranularFormatUnit = date_formatting_1.queryMostGranularFormatUnit;
+var locale_1 = __webpack_require__(31);
+exports.datepickerLocale = locale_1.datepickerLocale;
+exports.locale = locale_1.locale;
+var moment_ext_1 = __webpack_require__(10);
+exports.moment = moment_ext_1.default;
+var EmitterMixin_1 = __webpack_require__(11);
+exports.EmitterMixin = EmitterMixin_1.default;
+var ListenerMixin_1 = __webpack_require__(7);
+exports.ListenerMixin = ListenerMixin_1.default;
+var Model_1 = __webpack_require__(48);
+exports.Model = Model_1.default;
+var Constraints_1 = __webpack_require__(207);
+exports.Constraints = Constraints_1.default;
+var UnzonedRange_1 = __webpack_require__(5);
+exports.UnzonedRange = UnzonedRange_1.default;
+var ComponentFootprint_1 = __webpack_require__(12);
+exports.ComponentFootprint = ComponentFootprint_1.default;
+var BusinessHourGenerator_1 = __webpack_require__(212);
+exports.BusinessHourGenerator = BusinessHourGenerator_1.default;
+var EventDef_1 = __webpack_require__(34);
+exports.EventDef = EventDef_1.default;
+var EventDefMutation_1 = __webpack_require__(37);
+exports.EventDefMutation = EventDefMutation_1.default;
+var EventSourceParser_1 = __webpack_require__(38);
+exports.EventSourceParser = EventSourceParser_1.default;
+var EventSource_1 = __webpack_require__(6);
+exports.EventSource = EventSource_1.default;
+var ThemeRegistry_1 = __webpack_require__(51);
+exports.defineThemeSystem = ThemeRegistry_1.defineThemeSystem;
+var EventInstanceGroup_1 = __webpack_require__(18);
+exports.EventInstanceGroup = EventInstanceGroup_1.default;
+var ArrayEventSource_1 = __webpack_require__(52);
+exports.ArrayEventSource = ArrayEventSource_1.default;
+var FuncEventSource_1 = __webpack_require__(215);
+exports.FuncEventSource = FuncEventSource_1.default;
+var JsonFeedEventSource_1 = __webpack_require__(216);
+exports.JsonFeedEventSource = JsonFeedEventSource_1.default;
+var EventFootprint_1 = __webpack_require__(36);
+exports.EventFootprint = EventFootprint_1.default;
+var Class_1 = __webpack_require__(33);
+exports.Class = Class_1.default;
+var Mixin_1 = __webpack_require__(14);
+exports.Mixin = Mixin_1.default;
+var CoordCache_1 = __webpack_require__(53);
+exports.CoordCache = CoordCache_1.default;
+var DragListener_1 = __webpack_require__(54);
+exports.DragListener = DragListener_1.default;
+var Promise_1 = __webpack_require__(20);
+exports.Promise = Promise_1.default;
+var TaskQueue_1 = __webpack_require__(217);
+exports.TaskQueue = TaskQueue_1.default;
+var RenderQueue_1 = __webpack_require__(218);
+exports.RenderQueue = RenderQueue_1.default;
+var Scroller_1 = __webpack_require__(39);
+exports.Scroller = Scroller_1.default;
+var Theme_1 = __webpack_require__(19);
+exports.Theme = Theme_1.default;
+var DateComponent_1 = __webpack_require__(219);
+exports.DateComponent = DateComponent_1.default;
+var InteractiveDateComponent_1 = __webpack_require__(40);
+exports.InteractiveDateComponent = InteractiveDateComponent_1.default;
+var Calendar_1 = __webpack_require__(220);
+exports.Calendar = Calendar_1.default;
+var View_1 = __webpack_require__(41);
+exports.View = View_1.default;
+var ViewRegistry_1 = __webpack_require__(22);
+exports.defineView = ViewRegistry_1.defineView;
+exports.getViewConfig = ViewRegistry_1.getViewConfig;
+var DayTableMixin_1 = __webpack_require__(55);
+exports.DayTableMixin = DayTableMixin_1.default;
+var BusinessHourRenderer_1 = __webpack_require__(56);
+exports.BusinessHourRenderer = BusinessHourRenderer_1.default;
+var EventRenderer_1 = __webpack_require__(42);
+exports.EventRenderer = EventRenderer_1.default;
+var FillRenderer_1 = __webpack_require__(57);
+exports.FillRenderer = FillRenderer_1.default;
+var HelperRenderer_1 = __webpack_require__(58);
+exports.HelperRenderer = HelperRenderer_1.default;
+var ExternalDropping_1 = __webpack_require__(222);
+exports.ExternalDropping = ExternalDropping_1.default;
+var EventResizing_1 = __webpack_require__(223);
+exports.EventResizing = EventResizing_1.default;
+var EventPointing_1 = __webpack_require__(59);
+exports.EventPointing = EventPointing_1.default;
+var EventDragging_1 = __webpack_require__(224);
+exports.EventDragging = EventDragging_1.default;
+var DateSelecting_1 = __webpack_require__(225);
+exports.DateSelecting = DateSelecting_1.default;
+var StandardInteractionsMixin_1 = __webpack_require__(60);
+exports.StandardInteractionsMixin = StandardInteractionsMixin_1.default;
+var AgendaView_1 = __webpack_require__(226);
+exports.AgendaView = AgendaView_1.default;
+var TimeGrid_1 = __webpack_require__(227);
+exports.TimeGrid = TimeGrid_1.default;
+var DayGrid_1 = __webpack_require__(61);
+exports.DayGrid = DayGrid_1.default;
+var BasicView_1 = __webpack_require__(62);
+exports.BasicView = BasicView_1.default;
+var MonthView_1 = __webpack_require__(229);
+exports.MonthView = MonthView_1.default;
+var ListView_1 = __webpack_require__(230);
+exports.ListView = ListView_1.default;
+
+
+/***/ }),
+/* 17 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var UnzonedRange_1 = __webpack_require__(5);
+/*
+Meant to be immutable
+*/
+var EventDateProfile = /** @class */ (function () {
+ function EventDateProfile(start, end, calendar) {
+ this.start = start;
+ this.end = end || null;
+ this.unzonedRange = this.buildUnzonedRange(calendar);
+ }
+ /*
+ Needs an EventSource object
+ */
+ EventDateProfile.parse = function (rawProps, source) {
+ var startInput = rawProps.start || rawProps.date;
+ var endInput = rawProps.end;
+ if (!startInput) {
+ return false;
+ }
+ var calendar = source.calendar;
+ var start = calendar.moment(startInput);
+ var end = endInput ? calendar.moment(endInput) : null;
+ var forcedAllDay = rawProps.allDay;
+ var forceEventDuration = calendar.opt('forceEventDuration');
+ if (!start.isValid()) {
+ return false;
+ }
+ if (end && (!end.isValid() || !end.isAfter(start))) {
+ end = null;
+ }
+ if (forcedAllDay == null) {
+ forcedAllDay = source.allDayDefault;
+ if (forcedAllDay == null) {
+ forcedAllDay = calendar.opt('allDayDefault');
+ }
+ }
+ if (forcedAllDay === true) {
+ start.stripTime();
+ if (end) {
+ end.stripTime();
+ }
+ }
+ else if (forcedAllDay === false) {
+ if (!start.hasTime()) {
+ start.time(0);
+ }
+ if (end && !end.hasTime()) {
+ end.time(0);
+ }
+ }
+ if (!end && forceEventDuration) {
+ end = calendar.getDefaultEventEnd(!start.hasTime(), start);
+ }
+ return new EventDateProfile(start, end, calendar);
+ };
+ EventDateProfile.isStandardProp = function (propName) {
+ return propName === 'start' || propName === 'date' || propName === 'end' || propName === 'allDay';
+ };
+ EventDateProfile.prototype.isAllDay = function () {
+ return !(this.start.hasTime() || (this.end && this.end.hasTime()));
+ };
+ /*
+ Needs a Calendar object
+ */
+ EventDateProfile.prototype.buildUnzonedRange = function (calendar) {
+ var startMs = this.start.clone().stripZone().valueOf();
+ var endMs = this.getEnd(calendar).stripZone().valueOf();
+ return new UnzonedRange_1.default(startMs, endMs);
+ };
+ /*
+ Needs a Calendar object
+ */
+ EventDateProfile.prototype.getEnd = function (calendar) {
+ return this.end ?
+ this.end.clone() :
+ // derive the end from the start and allDay. compute allDay if necessary
+ calendar.getDefaultEventEnd(this.isAllDay(), this.start);
+ };
+ return EventDateProfile;
+}());
+exports.default = EventDateProfile;
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var UnzonedRange_1 = __webpack_require__(5);
+var util_1 = __webpack_require__(35);
+var EventRange_1 = __webpack_require__(211);
+/*
+It's expected that there will be at least one EventInstance,
+OR that an explicitEventDef is assigned.
+*/
+var EventInstanceGroup = /** @class */ (function () {
+ function EventInstanceGroup(eventInstances) {
+ this.eventInstances = eventInstances || [];
+ }
+ EventInstanceGroup.prototype.getAllEventRanges = function (constraintRange) {
+ if (constraintRange) {
+ return this.sliceNormalRenderRanges(constraintRange);
+ }
+ else {
+ return this.eventInstances.map(util_1.eventInstanceToEventRange);
+ }
+ };
+ EventInstanceGroup.prototype.sliceRenderRanges = function (constraintRange) {
+ if (this.isInverse()) {
+ return this.sliceInverseRenderRanges(constraintRange);
+ }
+ else {
+ return this.sliceNormalRenderRanges(constraintRange);
+ }
+ };
+ EventInstanceGroup.prototype.sliceNormalRenderRanges = function (constraintRange) {
+ var eventInstances = this.eventInstances;
+ var i;
+ var eventInstance;
+ var slicedRange;
+ var slicedEventRanges = [];
+ for (i = 0; i < eventInstances.length; i++) {
+ eventInstance = eventInstances[i];
+ slicedRange = eventInstance.dateProfile.unzonedRange.intersect(constraintRange);
+ if (slicedRange) {
+ slicedEventRanges.push(new EventRange_1.default(slicedRange, eventInstance.def, eventInstance));
+ }
+ }
+ return slicedEventRanges;
+ };
+ EventInstanceGroup.prototype.sliceInverseRenderRanges = function (constraintRange) {
+ var unzonedRanges = this.eventInstances.map(util_1.eventInstanceToUnzonedRange);
+ var ownerDef = this.getEventDef();
+ unzonedRanges = UnzonedRange_1.default.invertRanges(unzonedRanges, constraintRange);
+ return unzonedRanges.map(function (unzonedRange) {
+ return new EventRange_1.default(unzonedRange, ownerDef); // don't give an EventInstance
+ });
+ };
+ EventInstanceGroup.prototype.isInverse = function () {
+ return this.getEventDef().hasInverseRendering();
+ };
+ EventInstanceGroup.prototype.getEventDef = function () {
+ return this.explicitEventDef || this.eventInstances[0].def;
+ };
+ return EventInstanceGroup;
+}());
+exports.default = EventInstanceGroup;
+
+
+/***/ }),
+/* 19 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var Theme = /** @class */ (function () {
+ function Theme(optionsManager) {
+ this.optionsManager = optionsManager;
+ this.processIconOverride();
+ }
+ Theme.prototype.processIconOverride = function () {
+ if (this.iconOverrideOption) {
+ this.setIconOverride(this.optionsManager.get(this.iconOverrideOption));
+ }
+ };
+ Theme.prototype.setIconOverride = function (iconOverrideHash) {
+ var iconClassesCopy;
+ var buttonName;
+ if ($.isPlainObject(iconOverrideHash)) {
+ iconClassesCopy = $.extend({}, this.iconClasses);
+ for (buttonName in iconOverrideHash) {
+ iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]);
+ }
+ this.iconClasses = iconClassesCopy;
+ }
+ else if (iconOverrideHash === false) {
+ this.iconClasses = {};
+ }
+ };
+ Theme.prototype.applyIconOverridePrefix = function (className) {
+ var prefix = this.iconOverridePrefix;
+ if (prefix && className.indexOf(prefix) !== 0) {
+ className = prefix + className;
+ }
+ return className;
+ };
+ Theme.prototype.getClass = function (key) {
+ return this.classes[key] || '';
+ };
+ Theme.prototype.getIconClass = function (buttonName) {
+ var className = this.iconClasses[buttonName];
+ if (className) {
+ return this.baseIconClass + ' ' + className;
+ }
+ return '';
+ };
+ Theme.prototype.getCustomButtonIconClass = function (customButtonProps) {
+ var className;
+ if (this.iconOverrideCustomButtonOption) {
+ className = customButtonProps[this.iconOverrideCustomButtonOption];
+ if (className) {
+ return this.baseIconClass + ' ' + this.applyIconOverridePrefix(className);
+ }
+ }
+ return '';
+ };
+ return Theme;
+}());
+exports.default = Theme;
+Theme.prototype.classes = {};
+Theme.prototype.iconClasses = {};
+Theme.prototype.baseIconClass = '';
+Theme.prototype.iconOverridePrefix = '';
+
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var PromiseStub = {
+ construct: function (executor) {
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ if (typeof executor === 'function') {
+ executor(function (val) {
+ deferred.resolve(val);
+ attachImmediatelyResolvingThen(promise, val);
+ }, function () {
+ deferred.reject();
+ attachImmediatelyRejectingThen(promise);
+ });
+ }
+ return promise;
+ },
+ resolve: function (val) {
+ var deferred = $.Deferred().resolve(val);
+ var promise = deferred.promise();
+ attachImmediatelyResolvingThen(promise, val);
+ return promise;
+ },
+ reject: function () {
+ var deferred = $.Deferred().reject();
+ var promise = deferred.promise();
+ attachImmediatelyRejectingThen(promise);
+ return promise;
+ }
+};
+exports.default = PromiseStub;
+function attachImmediatelyResolvingThen(promise, val) {
+ promise.then = function (onResolve) {
+ if (typeof onResolve === 'function') {
+ return PromiseStub.resolve(onResolve(val));
+ }
+ return promise;
+ };
+}
+function attachImmediatelyRejectingThen(promise) {
+ promise.then = function (onResolve, onReject) {
+ if (typeof onReject === 'function') {
+ onReject();
+ }
+ return promise;
+ };
+}
+
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var exportHooks = __webpack_require__(16);
+var EmitterMixin_1 = __webpack_require__(11);
+var ListenerMixin_1 = __webpack_require__(7);
+exportHooks.touchMouseIgnoreWait = 500;
+var globalEmitter = null;
+var neededCount = 0;
+/*
+Listens to document and window-level user-interaction events, like touch events and mouse events,
+and fires these events as-is to whoever is observing a GlobalEmitter.
+Best when used as a singleton via GlobalEmitter.get()
+
+Normalizes mouse/touch events. For examples:
+- ignores the the simulated mouse events that happen after a quick tap: mousemove+mousedown+mouseup+click
+- compensates for various buggy scenarios where a touchend does not fire
+*/
+var GlobalEmitter = /** @class */ (function () {
+ function GlobalEmitter() {
+ this.isTouching = false;
+ this.mouseIgnoreDepth = 0;
+ }
+ // gets the singleton
+ GlobalEmitter.get = function () {
+ if (!globalEmitter) {
+ globalEmitter = new GlobalEmitter();
+ globalEmitter.bind();
+ }
+ return globalEmitter;
+ };
+ // called when an object knows it will need a GlobalEmitter in the near future.
+ GlobalEmitter.needed = function () {
+ GlobalEmitter.get(); // ensures globalEmitter
+ neededCount++;
+ };
+ // called when the object that originally called needed() doesn't need a GlobalEmitter anymore.
+ GlobalEmitter.unneeded = function () {
+ neededCount--;
+ if (!neededCount) {
+ globalEmitter.unbind();
+ globalEmitter = null;
+ }
+ };
+ GlobalEmitter.prototype.bind = function () {
+ var _this = this;
+ this.listenTo($(document), {
+ touchstart: this.handleTouchStart,
+ touchcancel: this.handleTouchCancel,
+ touchend: this.handleTouchEnd,
+ mousedown: this.handleMouseDown,
+ mousemove: this.handleMouseMove,
+ mouseup: this.handleMouseUp,
+ click: this.handleClick,
+ selectstart: this.handleSelectStart,
+ contextmenu: this.handleContextMenu
+ });
+ // because we need to call preventDefault
+ // because https://www.chromestatus.com/features/5093566007214080
+ // TODO: investigate performance because this is a global handler
+ window.addEventListener('touchmove', this.handleTouchMoveProxy = function (ev) {
+ _this.handleTouchMove($.Event(ev));
+ }, { passive: false } // allows preventDefault()
+ );
+ // attach a handler to get called when ANY scroll action happens on the page.
+ // this was impossible to do with normal on/off because 'scroll' doesn't bubble.
+ // http://stackoverflow.com/a/32954565/96342
+ window.addEventListener('scroll', this.handleScrollProxy = function (ev) {
+ _this.handleScroll($.Event(ev));
+ }, true // useCapture
+ );
+ };
+ GlobalEmitter.prototype.unbind = function () {
+ this.stopListeningTo($(document));
+ window.removeEventListener('touchmove', this.handleTouchMoveProxy);
+ window.removeEventListener('scroll', this.handleScrollProxy, true // useCapture
+ );
+ };
+ // Touch Handlers
+ // -----------------------------------------------------------------------------------------------------------------
+ GlobalEmitter.prototype.handleTouchStart = function (ev) {
+ // if a previous touch interaction never ended with a touchend, then implicitly end it,
+ // but since a new touch interaction is about to begin, don't start the mouse ignore period.
+ this.stopTouch(ev, true); // skipMouseIgnore=true
+ this.isTouching = true;
+ this.trigger('touchstart', ev);
+ };
+ GlobalEmitter.prototype.handleTouchMove = function (ev) {
+ if (this.isTouching) {
+ this.trigger('touchmove', ev);
+ }
+ };
+ GlobalEmitter.prototype.handleTouchCancel = function (ev) {
+ if (this.isTouching) {
+ this.trigger('touchcancel', ev);
+ // Have touchcancel fire an artificial touchend. That way, handlers won't need to listen to both.
+ // If touchend fires later, it won't have any effect b/c isTouching will be false.
+ this.stopTouch(ev);
+ }
+ };
+ GlobalEmitter.prototype.handleTouchEnd = function (ev) {
+ this.stopTouch(ev);
+ };
+ // Mouse Handlers
+ // -----------------------------------------------------------------------------------------------------------------
+ GlobalEmitter.prototype.handleMouseDown = function (ev) {
+ if (!this.shouldIgnoreMouse()) {
+ this.trigger('mousedown', ev);
+ }
+ };
+ GlobalEmitter.prototype.handleMouseMove = function (ev) {
+ if (!this.shouldIgnoreMouse()) {
+ this.trigger('mousemove', ev);
+ }
+ };
+ GlobalEmitter.prototype.handleMouseUp = function (ev) {
+ if (!this.shouldIgnoreMouse()) {
+ this.trigger('mouseup', ev);
+ }
+ };
+ GlobalEmitter.prototype.handleClick = function (ev) {
+ if (!this.shouldIgnoreMouse()) {
+ this.trigger('click', ev);
+ }
+ };
+ // Misc Handlers
+ // -----------------------------------------------------------------------------------------------------------------
+ GlobalEmitter.prototype.handleSelectStart = function (ev) {
+ this.trigger('selectstart', ev);
+ };
+ GlobalEmitter.prototype.handleContextMenu = function (ev) {
+ this.trigger('contextmenu', ev);
+ };
+ GlobalEmitter.prototype.handleScroll = function (ev) {
+ this.trigger('scroll', ev);
+ };
+ // Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ GlobalEmitter.prototype.stopTouch = function (ev, skipMouseIgnore) {
+ if (skipMouseIgnore === void 0) { skipMouseIgnore = false; }
+ if (this.isTouching) {
+ this.isTouching = false;
+ this.trigger('touchend', ev);
+ if (!skipMouseIgnore) {
+ this.startTouchMouseIgnore();
+ }
+ }
+ };
+ GlobalEmitter.prototype.startTouchMouseIgnore = function () {
+ var _this = this;
+ var wait = exportHooks.touchMouseIgnoreWait;
+ if (wait) {
+ this.mouseIgnoreDepth++;
+ setTimeout(function () {
+ _this.mouseIgnoreDepth--;
+ }, wait);
+ }
+ };
+ GlobalEmitter.prototype.shouldIgnoreMouse = function () {
+ return this.isTouching || Boolean(this.mouseIgnoreDepth);
+ };
+ return GlobalEmitter;
+}());
+exports.default = GlobalEmitter;
+ListenerMixin_1.default.mixInto(GlobalEmitter);
+EmitterMixin_1.default.mixInto(GlobalEmitter);
+
+
+/***/ }),
+/* 22 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var exportHooks = __webpack_require__(16);
+exports.viewHash = {};
+exportHooks.views = exports.viewHash;
+function defineView(viewName, viewConfig) {
+ exports.viewHash[viewName] = viewConfig;
+}
+exports.defineView = defineView;
+function getViewConfig(viewName) {
+ return exports.viewHash[viewName];
+}
+exports.getViewConfig = getViewConfig;
+
+
+/***/ }),
+/* 23 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var DragListener_1 = __webpack_require__(54);
+/* Tracks mouse movements over a component and raises events about which hit the mouse is over.
+------------------------------------------------------------------------------------------------------------------------
+options:
+- subjectEl
+- subjectCenter
+*/
+var HitDragListener = /** @class */ (function (_super) {
+ tslib_1.__extends(HitDragListener, _super);
+ function HitDragListener(component, options) {
+ var _this = _super.call(this, options) || this;
+ _this.component = component;
+ return _this;
+ }
+ // Called when drag listening starts (but a real drag has not necessarily began).
+ // ev might be undefined if dragging was started manually.
+ HitDragListener.prototype.handleInteractionStart = function (ev) {
+ var subjectEl = this.subjectEl;
+ var subjectRect;
+ var origPoint;
+ var point;
+ this.component.hitsNeeded();
+ this.computeScrollBounds(); // for autoscroll
+ if (ev) {
+ origPoint = { left: util_1.getEvX(ev), top: util_1.getEvY(ev) };
+ point = origPoint;
+ // constrain the point to bounds of the element being dragged
+ if (subjectEl) {
+ subjectRect = util_1.getOuterRect(subjectEl); // used for centering as well
+ point = util_1.constrainPoint(point, subjectRect);
+ }
+ this.origHit = this.queryHit(point.left, point.top);
+ // treat the center of the subject as the collision point?
+ if (subjectEl && this.options.subjectCenter) {
+ // only consider the area the subject overlaps the hit. best for large subjects.
+ // TODO: skip this if hit didn't supply left/right/top/bottom
+ if (this.origHit) {
+ subjectRect = util_1.intersectRects(this.origHit, subjectRect) ||
+ subjectRect; // in case there is no intersection
+ }
+ point = util_1.getRectCenter(subjectRect);
+ }
+ this.coordAdjust = util_1.diffPoints(point, origPoint); // point - origPoint
+ }
+ else {
+ this.origHit = null;
+ this.coordAdjust = null;
+ }
+ // call the super-method. do it after origHit has been computed
+ _super.prototype.handleInteractionStart.call(this, ev);
+ };
+ // Called when the actual drag has started
+ HitDragListener.prototype.handleDragStart = function (ev) {
+ var hit;
+ _super.prototype.handleDragStart.call(this, ev);
+ // might be different from this.origHit if the min-distance is large
+ hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
+ // report the initial hit the mouse is over
+ // especially important if no min-distance and drag starts immediately
+ if (hit) {
+ this.handleHitOver(hit);
+ }
+ };
+ // Called when the drag moves
+ HitDragListener.prototype.handleDrag = function (dx, dy, ev) {
+ var hit;
+ _super.prototype.handleDrag.call(this, dx, dy, ev);
+ hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
+ if (!isHitsEqual(hit, this.hit)) {
+ if (this.hit) {
+ this.handleHitOut();
+ }
+ if (hit) {
+ this.handleHitOver(hit);
+ }
+ }
+ };
+ // Called when dragging has been stopped
+ HitDragListener.prototype.handleDragEnd = function (ev) {
+ this.handleHitDone();
+ _super.prototype.handleDragEnd.call(this, ev);
+ };
+ // Called when a the mouse has just moved over a new hit
+ HitDragListener.prototype.handleHitOver = function (hit) {
+ var isOrig = isHitsEqual(hit, this.origHit);
+ this.hit = hit;
+ this.trigger('hitOver', this.hit, isOrig, this.origHit);
+ };
+ // Called when the mouse has just moved out of a hit
+ HitDragListener.prototype.handleHitOut = function () {
+ if (this.hit) {
+ this.trigger('hitOut', this.hit);
+ this.handleHitDone();
+ this.hit = null;
+ }
+ };
+ // Called after a hitOut. Also called before a dragStop
+ HitDragListener.prototype.handleHitDone = function () {
+ if (this.hit) {
+ this.trigger('hitDone', this.hit);
+ }
+ };
+ // Called when the interaction ends, whether there was a real drag or not
+ HitDragListener.prototype.handleInteractionEnd = function (ev, isCancelled) {
+ _super.prototype.handleInteractionEnd.call(this, ev, isCancelled);
+ this.origHit = null;
+ this.hit = null;
+ this.component.hitsNotNeeded();
+ };
+ // Called when scrolling has stopped, whether through auto scroll, or the user scrolling
+ HitDragListener.prototype.handleScrollEnd = function () {
+ _super.prototype.handleScrollEnd.call(this);
+ // hits' absolute positions will be in new places after a user's scroll.
+ // HACK for recomputing.
+ if (this.isDragging) {
+ this.component.releaseHits();
+ this.component.prepareHits();
+ }
+ };
+ // Gets the hit underneath the coordinates for the given mouse event
+ HitDragListener.prototype.queryHit = function (left, top) {
+ if (this.coordAdjust) {
+ left += this.coordAdjust.left;
+ top += this.coordAdjust.top;
+ }
+ return this.component.queryHit(left, top);
+ };
+ return HitDragListener;
+}(DragListener_1.default));
+exports.default = HitDragListener;
+// Returns `true` if the hits are identically equal. `false` otherwise. Must be from the same component.
+// Two null values will be considered equal, as two "out of the component" states are the same.
+function isHitsEqual(hit0, hit1) {
+ if (!hit0 && !hit1) {
+ return true;
+ }
+ if (hit0 && hit1) {
+ return hit0.component === hit1.component &&
+ isHitPropsWithin(hit0, hit1) &&
+ isHitPropsWithin(hit1, hit0); // ensures all props are identical
+ }
+ return false;
+}
+// Returns true if all of subHit's non-standard properties are within superHit
+function isHitPropsWithin(subHit, superHit) {
+ for (var propName in subHit) {
+ if (!/^(component|left|right|top|bottom)$/.test(propName)) {
+ if (subHit[propName] !== superHit[propName]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+/***/ }),
+/* 24 */,
+/* 25 */,
+/* 26 */,
+/* 27 */,
+/* 28 */,
+/* 29 */,
+/* 30 */,
+/* 31 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var exportHooks = __webpack_require__(16);
+var options_1 = __webpack_require__(32);
+var util_1 = __webpack_require__(4);
+exports.localeOptionHash = {};
+exportHooks.locales = exports.localeOptionHash;
+// NOTE: can't guarantee any of these computations will run because not every locale has datepicker
+// configs, so make sure there are English fallbacks for these in the defaults file.
+var dpComputableOptions = {
+ buttonText: function (dpOptions) {
+ return {
+ // the translations sometimes wrongly contain HTML entities
+ prev: util_1.stripHtmlEntities(dpOptions.prevText),
+ next: util_1.stripHtmlEntities(dpOptions.nextText),
+ today: util_1.stripHtmlEntities(dpOptions.currentText)
+ };
+ },
+ // Produces format strings like "MMMM YYYY" -> "September 2014"
+ monthYearFormat: function (dpOptions) {
+ return dpOptions.showMonthAfterYear ?
+ 'YYYY[' + dpOptions.yearSuffix + '] MMMM' :
+ 'MMMM YYYY[' + dpOptions.yearSuffix + ']';
+ }
+};
+var momComputableOptions = {
+ // Produces format strings like "ddd M/D" -> "Fri 9/15"
+ dayOfMonthFormat: function (momOptions, fcOptions) {
+ var format = momOptions.longDateFormat('l'); // for the format like "M/D/YYYY"
+ // strip the year off the edge, as well as other misc non-whitespace chars
+ format = format.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g, '');
+ if (fcOptions.isRTL) {
+ format += ' ddd'; // for RTL, add day-of-week to end
+ }
+ else {
+ format = 'ddd ' + format; // for LTR, add day-of-week to beginning
+ }
+ return format;
+ },
+ // Produces format strings like "h:mma" -> "6:00pm"
+ mediumTimeFormat: function (momOptions) {
+ return momOptions.longDateFormat('LT')
+ .replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
+ },
+ // Produces format strings like "h(:mm)a" -> "6pm" / "6:30pm"
+ smallTimeFormat: function (momOptions) {
+ return momOptions.longDateFormat('LT')
+ .replace(':mm', '(:mm)')
+ .replace(/(\Wmm)$/, '($1)') // like above, but for foreign locales
+ .replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
+ },
+ // Produces format strings like "h(:mm)t" -> "6p" / "6:30p"
+ extraSmallTimeFormat: function (momOptions) {
+ return momOptions.longDateFormat('LT')
+ .replace(':mm', '(:mm)')
+ .replace(/(\Wmm)$/, '($1)') // like above, but for foreign locales
+ .replace(/\s*a$/i, 't'); // convert to AM/PM/am/pm to lowercase one-letter. remove any spaces beforehand
+ },
+ // Produces format strings like "ha" / "H" -> "6pm" / "18"
+ hourFormat: function (momOptions) {
+ return momOptions.longDateFormat('LT')
+ .replace(':mm', '')
+ .replace(/(\Wmm)$/, '') // like above, but for foreign locales
+ .replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
+ },
+ // Produces format strings like "h:mm" -> "6:30" (with no AM/PM)
+ noMeridiemTimeFormat: function (momOptions) {
+ return momOptions.longDateFormat('LT')
+ .replace(/\s*a$/i, ''); // remove trailing AM/PM
+ }
+};
+// options that should be computed off live calendar options (considers override options)
+// TODO: best place for this? related to locale?
+// TODO: flipping text based on isRTL is a bad idea because the CSS `direction` might want to handle it
+var instanceComputableOptions = {
+ // Produces format strings for results like "Mo 16"
+ smallDayDateFormat: function (options) {
+ return options.isRTL ?
+ 'D dd' :
+ 'dd D';
+ },
+ // Produces format strings for results like "Wk 5"
+ weekFormat: function (options) {
+ return options.isRTL ?
+ 'w[ ' + options.weekNumberTitle + ']' :
+ '[' + options.weekNumberTitle + ' ]w';
+ },
+ // Produces format strings for results like "Wk5"
+ smallWeekFormat: function (options) {
+ return options.isRTL ?
+ 'w[' + options.weekNumberTitle + ']' :
+ '[' + options.weekNumberTitle + ']w';
+ }
+};
+// TODO: make these computable properties in optionsManager
+function populateInstanceComputableOptions(options) {
+ $.each(instanceComputableOptions, function (name, func) {
+ if (options[name] == null) {
+ options[name] = func(options);
+ }
+ });
+}
+exports.populateInstanceComputableOptions = populateInstanceComputableOptions;
+// Initialize jQuery UI datepicker translations while using some of the translations
+// Will set this as the default locales for datepicker.
+function datepickerLocale(localeCode, dpLocaleCode, dpOptions) {
+ // get the FullCalendar internal option hash for this locale. create if necessary
+ var fcOptions = exports.localeOptionHash[localeCode] || (exports.localeOptionHash[localeCode] = {});
+ // transfer some simple options from datepicker to fc
+ fcOptions.isRTL = dpOptions.isRTL;
+ fcOptions.weekNumberTitle = dpOptions.weekHeader;
+ // compute some more complex options from datepicker
+ $.each(dpComputableOptions, function (name, func) {
+ fcOptions[name] = func(dpOptions);
+ });
+ var jqDatePicker = $.datepicker;
+ // is jQuery UI Datepicker is on the page?
+ if (jqDatePicker) {
+ // Register the locale data.
+ // FullCalendar and MomentJS use locale codes like "pt-br" but Datepicker
+ // does it like "pt-BR" or if it doesn't have the locale, maybe just "pt".
+ // Make an alias so the locale can be referenced either way.
+ jqDatePicker.regional[dpLocaleCode] =
+ jqDatePicker.regional[localeCode] = // alias
+ dpOptions;
+ // Alias 'en' to the default locale data. Do this every time.
+ jqDatePicker.regional.en = jqDatePicker.regional[''];
+ // Set as Datepicker's global defaults.
+ jqDatePicker.setDefaults(dpOptions);
+ }
+}
+exports.datepickerLocale = datepickerLocale;
+// Sets FullCalendar-specific translations. Will set the locales as the global default.
+function locale(localeCode, newFcOptions) {
+ var fcOptions;
+ var momOptions;
+ // get the FullCalendar internal option hash for this locale. create if necessary
+ fcOptions = exports.localeOptionHash[localeCode] || (exports.localeOptionHash[localeCode] = {});
+ // provided new options for this locales? merge them in
+ if (newFcOptions) {
+ fcOptions = exports.localeOptionHash[localeCode] = options_1.mergeOptions([fcOptions, newFcOptions]);
+ }
+ // compute locale options that weren't defined.
+ // always do this. newFcOptions can be undefined when initializing from i18n file,
+ // so no way to tell if this is an initialization or a default-setting.
+ momOptions = getMomentLocaleData(localeCode); // will fall back to en
+ $.each(momComputableOptions, function (name, func) {
+ if (fcOptions[name] == null) {
+ fcOptions[name] = (func)(momOptions, fcOptions);
+ }
+ });
+ // set it as the default locale for FullCalendar
+ options_1.globalDefaults.locale = localeCode;
+}
+exports.locale = locale;
+// Returns moment's internal locale data. If doesn't exist, returns English.
+function getMomentLocaleData(localeCode) {
+ return moment.localeData(localeCode) || moment.localeData('en');
+}
+exports.getMomentLocaleData = getMomentLocaleData;
+// Initialize English by forcing computation of moment-derived options.
+// Also, sets it as the default.
+locale('en', options_1.englishDefaults);
+
+
+/***/ }),
+/* 32 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var util_1 = __webpack_require__(4);
+exports.globalDefaults = {
+ titleRangeSeparator: ' \u2013 ',
+ monthYearFormat: 'MMMM YYYY',
+ defaultTimedEventDuration: '02:00:00',
+ defaultAllDayEventDuration: { days: 1 },
+ forceEventDuration: false,
+ nextDayThreshold: '09:00:00',
+ // display
+ columnHeader: true,
+ defaultView: 'month',
+ aspectRatio: 1.35,
+ header: {
+ left: 'title',
+ center: '',
+ right: 'today prev,next'
+ },
+ weekends: true,
+ weekNumbers: false,
+ weekNumberTitle: 'W',
+ weekNumberCalculation: 'local',
+ // editable: false,
+ // nowIndicator: false,
+ scrollTime: '06:00:00',
+ minTime: '00:00:00',
+ maxTime: '24:00:00',
+ showNonCurrentDates: true,
+ // event ajax
+ lazyFetching: true,
+ startParam: 'start',
+ endParam: 'end',
+ timezoneParam: 'timezone',
+ timezone: false,
+ // allDayDefault: undefined,
+ // locale
+ locale: null,
+ isRTL: false,
+ buttonText: {
+ prev: 'prev',
+ next: 'next',
+ prevYear: 'prev year',
+ nextYear: 'next year',
+ year: 'year',
+ today: 'today',
+ month: 'month',
+ week: 'week',
+ day: 'day'
+ },
+ // buttonIcons: null,
+ allDayText: 'all-day',
+ // allows setting a min-height to the event segment to prevent short events overlapping each other
+ agendaEventMinHeight: 0,
+ // jquery-ui theming
+ theme: false,
+ // themeButtonIcons: null,
+ // eventResizableFromStart: false,
+ dragOpacity: .75,
+ dragRevertDuration: 500,
+ dragScroll: true,
+ // selectable: false,
+ unselectAuto: true,
+ // selectMinDistance: 0,
+ dropAccept: '*',
+ eventOrder: 'title',
+ // eventRenderWait: null,
+ eventLimit: false,
+ eventLimitText: 'more',
+ eventLimitClick: 'popover',
+ dayPopoverFormat: 'LL',
+ handleWindowResize: true,
+ windowResizeDelay: 100,
+ longPressDelay: 1000
+};
+exports.englishDefaults = {
+ dayPopoverFormat: 'dddd, MMMM D'
+};
+exports.rtlDefaults = {
+ header: {
+ left: 'next,prev today',
+ center: '',
+ right: 'title'
+ },
+ buttonIcons: {
+ prev: 'right-single-arrow',
+ next: 'left-single-arrow',
+ prevYear: 'right-double-arrow',
+ nextYear: 'left-double-arrow'
+ },
+ themeButtonIcons: {
+ prev: 'circle-triangle-e',
+ next: 'circle-triangle-w',
+ nextYear: 'seek-prev',
+ prevYear: 'seek-next'
+ }
+};
+var complexOptions = [
+ 'header',
+ 'footer',
+ 'buttonText',
+ 'buttonIcons',
+ 'themeButtonIcons'
+];
+// Merges an array of option objects into a single object
+function mergeOptions(optionObjs) {
+ return util_1.mergeProps(optionObjs, complexOptions);
+}
+exports.mergeOptions = mergeOptions;
+
+
+/***/ }),
+/* 33 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+// Class that all other classes will inherit from
+var Class = /** @class */ (function () {
+ function Class() {
+ }
+ // Called on a class to create a subclass.
+ // LIMITATION: cannot provide a constructor!
+ Class.extend = function (members) {
+ var SubClass = /** @class */ (function (_super) {
+ tslib_1.__extends(SubClass, _super);
+ function SubClass() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return SubClass;
+ }(this));
+ util_1.copyOwnProps(members, SubClass.prototype);
+ return SubClass;
+ };
+ // Adds new member variables/methods to the class's prototype.
+ // Can be called with another class, or a plain object hash containing new members.
+ Class.mixin = function (members) {
+ util_1.copyOwnProps(members, this.prototype);
+ };
+ return Class;
+}());
+exports.default = Class;
+
+
+/***/ }),
+/* 34 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var ParsableModelMixin_1 = __webpack_require__(208);
+var EventDef = /** @class */ (function () {
+ function EventDef(source) {
+ this.source = source;
+ this.className = [];
+ this.miscProps = {};
+ }
+ EventDef.parse = function (rawInput, source) {
+ var def = new this(source);
+ if (def.applyProps(rawInput)) {
+ return def;
+ }
+ return false;
+ };
+ EventDef.normalizeId = function (id) {
+ return String(id);
+ };
+ EventDef.generateId = function () {
+ return '_fc' + (EventDef.uuid++);
+ };
+ EventDef.prototype.clone = function () {
+ var copy = new this.constructor(this.source);
+ copy.id = this.id;
+ copy.rawId = this.rawId;
+ copy.uid = this.uid; // not really unique anymore :(
+ EventDef.copyVerbatimStandardProps(this, copy);
+ copy.className = this.className.slice(); // copy
+ copy.miscProps = $.extend({}, this.miscProps);
+ return copy;
+ };
+ EventDef.prototype.hasInverseRendering = function () {
+ return this.getRendering() === 'inverse-background';
+ };
+ EventDef.prototype.hasBgRendering = function () {
+ var rendering = this.getRendering();
+ return rendering === 'inverse-background' || rendering === 'background';
+ };
+ EventDef.prototype.getRendering = function () {
+ if (this.rendering != null) {
+ return this.rendering;
+ }
+ return this.source.rendering;
+ };
+ EventDef.prototype.getConstraint = function () {
+ if (this.constraint != null) {
+ return this.constraint;
+ }
+ if (this.source.constraint != null) {
+ return this.source.constraint;
+ }
+ return this.source.calendar.opt('eventConstraint'); // what about View option?
+ };
+ EventDef.prototype.getOverlap = function () {
+ if (this.overlap != null) {
+ return this.overlap;
+ }
+ if (this.source.overlap != null) {
+ return this.source.overlap;
+ }
+ return this.source.calendar.opt('eventOverlap'); // what about View option?
+ };
+ EventDef.prototype.isStartExplicitlyEditable = function () {
+ if (this.startEditable != null) {
+ return this.startEditable;
+ }
+ return this.source.startEditable;
+ };
+ EventDef.prototype.isDurationExplicitlyEditable = function () {
+ if (this.durationEditable != null) {
+ return this.durationEditable;
+ }
+ return this.source.durationEditable;
+ };
+ EventDef.prototype.isExplicitlyEditable = function () {
+ if (this.editable != null) {
+ return this.editable;
+ }
+ return this.source.editable;
+ };
+ EventDef.prototype.toLegacy = function () {
+ var obj = $.extend({}, this.miscProps);
+ obj._id = this.uid;
+ obj.source = this.source;
+ obj.className = this.className.slice(); // copy
+ obj.allDay = this.isAllDay();
+ if (this.rawId != null) {
+ obj.id = this.rawId;
+ }
+ EventDef.copyVerbatimStandardProps(this, obj);
+ return obj;
+ };
+ EventDef.prototype.applyManualStandardProps = function (rawProps) {
+ if (rawProps.id != null) {
+ this.id = EventDef.normalizeId((this.rawId = rawProps.id));
+ }
+ else {
+ this.id = EventDef.generateId();
+ }
+ if (rawProps._id != null) {
+ this.uid = String(rawProps._id);
+ }
+ else {
+ this.uid = EventDef.generateId();
+ }
+ // TODO: converge with EventSource
+ if ($.isArray(rawProps.className)) {
+ this.className = rawProps.className;
+ }
+ if (typeof rawProps.className === 'string') {
+ this.className = rawProps.className.split(/\s+/);
+ }
+ return true;
+ };
+ EventDef.prototype.applyMiscProps = function (rawProps) {
+ $.extend(this.miscProps, rawProps);
+ };
+ EventDef.uuid = 0;
+ EventDef.defineStandardProps = ParsableModelMixin_1.default.defineStandardProps;
+ EventDef.copyVerbatimStandardProps = ParsableModelMixin_1.default.copyVerbatimStandardProps;
+ return EventDef;
+}());
+exports.default = EventDef;
+ParsableModelMixin_1.default.mixInto(EventDef);
+EventDef.defineStandardProps({
+ // not automatically assigned (`false`)
+ _id: false,
+ id: false,
+ className: false,
+ source: false,
+ // automatically assigned (`true`)
+ title: true,
+ url: true,
+ rendering: true,
+ constraint: true,
+ overlap: true,
+ editable: true,
+ startEditable: true,
+ durationEditable: true,
+ color: true,
+ backgroundColor: true,
+ borderColor: true,
+ textColor: true
+});
+
+
+/***/ }),
+/* 35 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventRange_1 = __webpack_require__(211);
+var EventFootprint_1 = __webpack_require__(36);
+var ComponentFootprint_1 = __webpack_require__(12);
+function eventDefsToEventInstances(eventDefs, unzonedRange) {
+ var eventInstances = [];
+ var i;
+ for (i = 0; i < eventDefs.length; i++) {
+ eventInstances.push.apply(eventInstances, // append
+ eventDefs[i].buildInstances(unzonedRange));
+ }
+ return eventInstances;
+}
+exports.eventDefsToEventInstances = eventDefsToEventInstances;
+function eventInstanceToEventRange(eventInstance) {
+ return new EventRange_1.default(eventInstance.dateProfile.unzonedRange, eventInstance.def, eventInstance);
+}
+exports.eventInstanceToEventRange = eventInstanceToEventRange;
+function eventRangeToEventFootprint(eventRange) {
+ return new EventFootprint_1.default(new ComponentFootprint_1.default(eventRange.unzonedRange, eventRange.eventDef.isAllDay()), eventRange.eventDef, eventRange.eventInstance // might not exist
+ );
+}
+exports.eventRangeToEventFootprint = eventRangeToEventFootprint;
+function eventInstanceToUnzonedRange(eventInstance) {
+ return eventInstance.dateProfile.unzonedRange;
+}
+exports.eventInstanceToUnzonedRange = eventInstanceToUnzonedRange;
+function eventFootprintToComponentFootprint(eventFootprint) {
+ return eventFootprint.componentFootprint;
+}
+exports.eventFootprintToComponentFootprint = eventFootprintToComponentFootprint;
+
+
+/***/ }),
+/* 36 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventFootprint = /** @class */ (function () {
+ function EventFootprint(componentFootprint, eventDef, eventInstance) {
+ this.componentFootprint = componentFootprint;
+ this.eventDef = eventDef;
+ if (eventInstance) {
+ this.eventInstance = eventInstance;
+ }
+ }
+ EventFootprint.prototype.getEventLegacy = function () {
+ return (this.eventInstance || this.eventDef).toLegacy();
+ };
+ return EventFootprint;
+}());
+exports.default = EventFootprint;
+
+
+/***/ }),
+/* 37 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var util_1 = __webpack_require__(4);
+var EventDateProfile_1 = __webpack_require__(17);
+var EventDef_1 = __webpack_require__(34);
+var EventDefDateMutation_1 = __webpack_require__(50);
+var SingleEventDef_1 = __webpack_require__(13);
+var EventDefMutation = /** @class */ (function () {
+ function EventDefMutation() {
+ }
+ EventDefMutation.createFromRawProps = function (eventInstance, rawProps, largeUnit) {
+ var eventDef = eventInstance.def;
+ var dateProps = {};
+ var standardProps = {};
+ var miscProps = {};
+ var verbatimStandardProps = {};
+ var eventDefId = null;
+ var className = null;
+ var propName;
+ var dateProfile;
+ var dateMutation;
+ var defMutation;
+ for (propName in rawProps) {
+ if (EventDateProfile_1.default.isStandardProp(propName)) {
+ dateProps[propName] = rawProps[propName];
+ }
+ else if (eventDef.isStandardProp(propName)) {
+ standardProps[propName] = rawProps[propName];
+ }
+ else if (eventDef.miscProps[propName] !== rawProps[propName]) {
+ miscProps[propName] = rawProps[propName];
+ }
+ }
+ dateProfile = EventDateProfile_1.default.parse(dateProps, eventDef.source);
+ if (dateProfile) {
+ dateMutation = EventDefDateMutation_1.default.createFromDiff(eventInstance.dateProfile, dateProfile, largeUnit);
+ }
+ if (standardProps.id !== eventDef.id) {
+ eventDefId = standardProps.id; // only apply if there's a change
+ }
+ if (!util_1.isArraysEqual(standardProps.className, eventDef.className)) {
+ className = standardProps.className; // only apply if there's a change
+ }
+ EventDef_1.default.copyVerbatimStandardProps(standardProps, // src
+ verbatimStandardProps // dest
+ );
+ defMutation = new EventDefMutation();
+ defMutation.eventDefId = eventDefId;
+ defMutation.className = className;
+ defMutation.verbatimStandardProps = verbatimStandardProps;
+ defMutation.miscProps = miscProps;
+ if (dateMutation) {
+ defMutation.dateMutation = dateMutation;
+ }
+ return defMutation;
+ };
+ /*
+ eventDef assumed to be a SingleEventDef.
+ returns an undo function.
+ */
+ EventDefMutation.prototype.mutateSingle = function (eventDef) {
+ var origDateProfile;
+ if (this.dateMutation) {
+ origDateProfile = eventDef.dateProfile;
+ eventDef.dateProfile = this.dateMutation.buildNewDateProfile(origDateProfile, eventDef.source.calendar);
+ }
+ // can't undo
+ // TODO: more DRY with EventDef::applyManualStandardProps
+ if (this.eventDefId != null) {
+ eventDef.id = EventDef_1.default.normalizeId((eventDef.rawId = this.eventDefId));
+ }
+ // can't undo
+ // TODO: more DRY with EventDef::applyManualStandardProps
+ if (this.className) {
+ eventDef.className = this.className;
+ }
+ // can't undo
+ if (this.verbatimStandardProps) {
+ SingleEventDef_1.default.copyVerbatimStandardProps(this.verbatimStandardProps, // src
+ eventDef // dest
+ );
+ }
+ // can't undo
+ if (this.miscProps) {
+ eventDef.applyMiscProps(this.miscProps);
+ }
+ if (origDateProfile) {
+ return function () {
+ eventDef.dateProfile = origDateProfile;
+ };
+ }
+ else {
+ return function () { };
+ }
+ };
+ EventDefMutation.prototype.setDateMutation = function (dateMutation) {
+ if (dateMutation && !dateMutation.isEmpty()) {
+ this.dateMutation = dateMutation;
+ }
+ else {
+ this.dateMutation = null;
+ }
+ };
+ EventDefMutation.prototype.isEmpty = function () {
+ return !this.dateMutation;
+ };
+ return EventDefMutation;
+}());
+exports.default = EventDefMutation;
+
+
+/***/ }),
+/* 38 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.default = {
+ sourceClasses: [],
+ registerClass: function (EventSourceClass) {
+ this.sourceClasses.unshift(EventSourceClass); // give highest priority
+ },
+ parse: function (rawInput, calendar) {
+ var sourceClasses = this.sourceClasses;
+ var i;
+ var eventSource;
+ for (i = 0; i < sourceClasses.length; i++) {
+ eventSource = sourceClasses[i].parse(rawInput, calendar);
+ if (eventSource) {
+ return eventSource;
+ }
+ }
+ }
+};
+
+
+/***/ }),
+/* 39 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Class_1 = __webpack_require__(33);
+/*
+Embodies a div that has potential scrollbars
+*/
+var Scroller = /** @class */ (function (_super) {
+ tslib_1.__extends(Scroller, _super);
+ function Scroller(options) {
+ var _this = _super.call(this) || this;
+ options = options || {};
+ _this.overflowX = options.overflowX || options.overflow || 'auto';
+ _this.overflowY = options.overflowY || options.overflow || 'auto';
+ return _this;
+ }
+ Scroller.prototype.render = function () {
+ this.el = this.renderEl();
+ this.applyOverflow();
+ };
+ Scroller.prototype.renderEl = function () {
+ return (this.scrollEl = $('<div class="fc-scroller"></div>'));
+ };
+ // sets to natural height, unlocks overflow
+ Scroller.prototype.clear = function () {
+ this.setHeight('auto');
+ this.applyOverflow();
+ };
+ Scroller.prototype.destroy = function () {
+ this.el.remove();
+ };
+ // Overflow
+ // -----------------------------------------------------------------------------------------------------------------
+ Scroller.prototype.applyOverflow = function () {
+ this.scrollEl.css({
+ 'overflow-x': this.overflowX,
+ 'overflow-y': this.overflowY
+ });
+ };
+ // Causes any 'auto' overflow values to resolves to 'scroll' or 'hidden'.
+ // Useful for preserving scrollbar widths regardless of future resizes.
+ // Can pass in scrollbarWidths for optimization.
+ Scroller.prototype.lockOverflow = function (scrollbarWidths) {
+ var overflowX = this.overflowX;
+ var overflowY = this.overflowY;
+ scrollbarWidths = scrollbarWidths || this.getScrollbarWidths();
+ if (overflowX === 'auto') {
+ overflowX = (scrollbarWidths.top || scrollbarWidths.bottom || // horizontal scrollbars?
+ // OR scrolling pane with massless scrollbars?
+ this.scrollEl[0].scrollWidth - 1 > this.scrollEl[0].clientWidth) ? 'scroll' : 'hidden';
+ }
+ if (overflowY === 'auto') {
+ overflowY = (scrollbarWidths.left || scrollbarWidths.right || // vertical scrollbars?
+ // OR scrolling pane with massless scrollbars?
+ this.scrollEl[0].scrollHeight - 1 > this.scrollEl[0].clientHeight) ? 'scroll' : 'hidden';
+ }
+ this.scrollEl.css({ 'overflow-x': overflowX, 'overflow-y': overflowY });
+ };
+ // Getters / Setters
+ // -----------------------------------------------------------------------------------------------------------------
+ Scroller.prototype.setHeight = function (height) {
+ this.scrollEl.height(height);
+ };
+ Scroller.prototype.getScrollTop = function () {
+ return this.scrollEl.scrollTop();
+ };
+ Scroller.prototype.setScrollTop = function (top) {
+ this.scrollEl.scrollTop(top);
+ };
+ Scroller.prototype.getClientWidth = function () {
+ return this.scrollEl[0].clientWidth;
+ };
+ Scroller.prototype.getClientHeight = function () {
+ return this.scrollEl[0].clientHeight;
+ };
+ Scroller.prototype.getScrollbarWidths = function () {
+ return util_1.getScrollbarWidths(this.scrollEl);
+ };
+ return Scroller;
+}(Class_1.default));
+exports.default = Scroller;
+
+
+/***/ }),
+/* 40 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var DateComponent_1 = __webpack_require__(219);
+var GlobalEmitter_1 = __webpack_require__(21);
+var InteractiveDateComponent = /** @class */ (function (_super) {
+ tslib_1.__extends(InteractiveDateComponent, _super);
+ function InteractiveDateComponent(_view, _options) {
+ var _this = _super.call(this, _view, _options) || this;
+ // self-config, overridable by subclasses
+ _this.segSelector = '.fc-event-container > *'; // what constitutes an event element?
+ if (_this.dateSelectingClass) {
+ _this.dateClicking = new _this.dateClickingClass(_this);
+ }
+ if (_this.dateSelectingClass) {
+ _this.dateSelecting = new _this.dateSelectingClass(_this);
+ }
+ if (_this.eventPointingClass) {
+ _this.eventPointing = new _this.eventPointingClass(_this);
+ }
+ if (_this.eventDraggingClass && _this.eventPointing) {
+ _this.eventDragging = new _this.eventDraggingClass(_this, _this.eventPointing);
+ }
+ if (_this.eventResizingClass && _this.eventPointing) {
+ _this.eventResizing = new _this.eventResizingClass(_this, _this.eventPointing);
+ }
+ if (_this.externalDroppingClass) {
+ _this.externalDropping = new _this.externalDroppingClass(_this);
+ }
+ return _this;
+ }
+ // Sets the container element that the view should render inside of, does global DOM-related initializations,
+ // and renders all the non-date-related content inside.
+ InteractiveDateComponent.prototype.setElement = function (el) {
+ _super.prototype.setElement.call(this, el);
+ if (this.dateClicking) {
+ this.dateClicking.bindToEl(el);
+ }
+ if (this.dateSelecting) {
+ this.dateSelecting.bindToEl(el);
+ }
+ this.bindAllSegHandlersToEl(el);
+ };
+ InteractiveDateComponent.prototype.removeElement = function () {
+ this.endInteractions();
+ _super.prototype.removeElement.call(this);
+ };
+ InteractiveDateComponent.prototype.executeEventUnrender = function () {
+ this.endInteractions();
+ _super.prototype.executeEventUnrender.call(this);
+ };
+ InteractiveDateComponent.prototype.bindGlobalHandlers = function () {
+ _super.prototype.bindGlobalHandlers.call(this);
+ if (this.externalDropping) {
+ this.externalDropping.bindToDocument();
+ }
+ };
+ InteractiveDateComponent.prototype.unbindGlobalHandlers = function () {
+ _super.prototype.unbindGlobalHandlers.call(this);
+ if (this.externalDropping) {
+ this.externalDropping.unbindFromDocument();
+ }
+ };
+ InteractiveDateComponent.prototype.bindDateHandlerToEl = function (el, name, handler) {
+ var _this = this;
+ // attach a handler to the grid's root element.
+ // jQuery will take care of unregistering them when removeElement gets called.
+ this.el.on(name, function (ev) {
+ if (!$(ev.target).is(_this.segSelector + ':not(.fc-helper),' + // directly on an event element
+ _this.segSelector + ':not(.fc-helper) *,' + // within an event element
+ '.fc-more,' + // a "more.." link
+ 'a[data-goto]' // a clickable nav link
+ )) {
+ return handler.call(_this, ev);
+ }
+ });
+ };
+ InteractiveDateComponent.prototype.bindAllSegHandlersToEl = function (el) {
+ [
+ this.eventPointing,
+ this.eventDragging,
+ this.eventResizing
+ ].forEach(function (eventInteraction) {
+ if (eventInteraction) {
+ eventInteraction.bindToEl(el);
+ }
+ });
+ };
+ InteractiveDateComponent.prototype.bindSegHandlerToEl = function (el, name, handler) {
+ var _this = this;
+ el.on(name, this.segSelector, function (ev) {
+ var segEl = $(ev.currentTarget);
+ if (!segEl.is('.fc-helper')) {
+ var seg = segEl.data('fc-seg'); // grab segment data. put there by View::renderEventsPayload
+ if (seg && !_this.shouldIgnoreEventPointing()) {
+ return handler.call(_this, seg, ev); // context will be the Grid
+ }
+ }
+ });
+ };
+ InteractiveDateComponent.prototype.shouldIgnoreMouse = function () {
+ // HACK
+ // This will still work even though bindDateHandlerToEl doesn't use GlobalEmitter.
+ return GlobalEmitter_1.default.get().shouldIgnoreMouse();
+ };
+ InteractiveDateComponent.prototype.shouldIgnoreTouch = function () {
+ var view = this._getView();
+ // On iOS (and Android?) when a new selection is initiated overtop another selection,
+ // the touchend never fires because the elements gets removed mid-touch-interaction (my theory).
+ // HACK: simply don't allow this to happen.
+ // ALSO: prevent selection when an *event* is already raised.
+ return view.isSelected || view.selectedEvent;
+ };
+ InteractiveDateComponent.prototype.shouldIgnoreEventPointing = function () {
+ // only call the handlers if there is not a drag/resize in progress
+ return (this.eventDragging && this.eventDragging.isDragging) ||
+ (this.eventResizing && this.eventResizing.isResizing);
+ };
+ InteractiveDateComponent.prototype.canStartSelection = function (seg, ev) {
+ return util_1.getEvIsTouch(ev) &&
+ !this.canStartResize(seg, ev) &&
+ (this.isEventDefDraggable(seg.footprint.eventDef) ||
+ this.isEventDefResizable(seg.footprint.eventDef));
+ };
+ InteractiveDateComponent.prototype.canStartDrag = function (seg, ev) {
+ return !this.canStartResize(seg, ev) &&
+ this.isEventDefDraggable(seg.footprint.eventDef);
+ };
+ InteractiveDateComponent.prototype.canStartResize = function (seg, ev) {
+ var view = this._getView();
+ var eventDef = seg.footprint.eventDef;
+ return (!util_1.getEvIsTouch(ev) || view.isEventDefSelected(eventDef)) &&
+ this.isEventDefResizable(eventDef) &&
+ $(ev.target).is('.fc-resizer');
+ };
+ // Kills all in-progress dragging.
+ // Useful for when public API methods that result in re-rendering are invoked during a drag.
+ // Also useful for when touch devices misbehave and don't fire their touchend.
+ InteractiveDateComponent.prototype.endInteractions = function () {
+ [
+ this.dateClicking,
+ this.dateSelecting,
+ this.eventPointing,
+ this.eventDragging,
+ this.eventResizing
+ ].forEach(function (interaction) {
+ if (interaction) {
+ interaction.end();
+ }
+ });
+ };
+ // Event Drag-n-Drop
+ // ---------------------------------------------------------------------------------------------------------------
+ // Computes if the given event is allowed to be dragged by the user
+ InteractiveDateComponent.prototype.isEventDefDraggable = function (eventDef) {
+ return this.isEventDefStartEditable(eventDef);
+ };
+ InteractiveDateComponent.prototype.isEventDefStartEditable = function (eventDef) {
+ var isEditable = eventDef.isStartExplicitlyEditable();
+ if (isEditable == null) {
+ isEditable = this.opt('eventStartEditable');
+ if (isEditable == null) {
+ isEditable = this.isEventDefGenerallyEditable(eventDef);
+ }
+ }
+ return isEditable;
+ };
+ InteractiveDateComponent.prototype.isEventDefGenerallyEditable = function (eventDef) {
+ var isEditable = eventDef.isExplicitlyEditable();
+ if (isEditable == null) {
+ isEditable = this.opt('editable');
+ }
+ return isEditable;
+ };
+ // Event Resizing
+ // ---------------------------------------------------------------------------------------------------------------
+ // Computes if the given event is allowed to be resized from its starting edge
+ InteractiveDateComponent.prototype.isEventDefResizableFromStart = function (eventDef) {
+ return this.opt('eventResizableFromStart') && this.isEventDefResizable(eventDef);
+ };
+ // Computes if the given event is allowed to be resized from its ending edge
+ InteractiveDateComponent.prototype.isEventDefResizableFromEnd = function (eventDef) {
+ return this.isEventDefResizable(eventDef);
+ };
+ // Computes if the given event is allowed to be resized by the user at all
+ InteractiveDateComponent.prototype.isEventDefResizable = function (eventDef) {
+ var isResizable = eventDef.isDurationExplicitlyEditable();
+ if (isResizable == null) {
+ isResizable = this.opt('eventDurationEditable');
+ if (isResizable == null) {
+ isResizable = this.isEventDefGenerallyEditable(eventDef);
+ }
+ }
+ return isResizable;
+ };
+ // Event Mutation / Constraints
+ // ---------------------------------------------------------------------------------------------------------------
+ // Diffs the two dates, returning a duration, based on granularity of the grid
+ // TODO: port isTimeScale into this system?
+ InteractiveDateComponent.prototype.diffDates = function (a, b) {
+ if (this.largeUnit) {
+ return util_1.diffByUnit(a, b, this.largeUnit);
+ }
+ else {
+ return util_1.diffDayTime(a, b);
+ }
+ };
+ // is it allowed, in relation to the view's validRange?
+ // NOTE: very similar to isExternalInstanceGroupAllowed
+ InteractiveDateComponent.prototype.isEventInstanceGroupAllowed = function (eventInstanceGroup) {
+ var view = this._getView();
+ var dateProfile = this.dateProfile;
+ var eventFootprints = this.eventRangesToEventFootprints(eventInstanceGroup.getAllEventRanges());
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ // TODO: just use getAllEventRanges directly
+ if (!dateProfile.validUnzonedRange.containsRange(eventFootprints[i].componentFootprint.unzonedRange)) {
+ return false;
+ }
+ }
+ return view.calendar.constraints.isEventInstanceGroupAllowed(eventInstanceGroup);
+ };
+ // NOTE: very similar to isEventInstanceGroupAllowed
+ // when it's a completely anonymous external drag, no event.
+ InteractiveDateComponent.prototype.isExternalInstanceGroupAllowed = function (eventInstanceGroup) {
+ var view = this._getView();
+ var dateProfile = this.dateProfile;
+ var eventFootprints = this.eventRangesToEventFootprints(eventInstanceGroup.getAllEventRanges());
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ if (!dateProfile.validUnzonedRange.containsRange(eventFootprints[i].componentFootprint.unzonedRange)) {
+ return false;
+ }
+ }
+ for (i = 0; i < eventFootprints.length; i++) {
+ // treat it as a selection
+ // TODO: pass in eventInstanceGroup instead
+ // because we don't want calendar's constraint system to depend on a component's
+ // determination of footprints.
+ if (!view.calendar.constraints.isSelectionFootprintAllowed(eventFootprints[i].componentFootprint)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ return InteractiveDateComponent;
+}(DateComponent_1.default));
+exports.default = InteractiveDateComponent;
+
+
+/***/ }),
+/* 41 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var RenderQueue_1 = __webpack_require__(218);
+var DateProfileGenerator_1 = __webpack_require__(221);
+var InteractiveDateComponent_1 = __webpack_require__(40);
+var GlobalEmitter_1 = __webpack_require__(21);
+var UnzonedRange_1 = __webpack_require__(5);
+/* An abstract class from which other views inherit from
+----------------------------------------------------------------------------------------------------------------------*/
+var View = /** @class */ (function (_super) {
+ tslib_1.__extends(View, _super);
+ function View(calendar, viewSpec) {
+ var _this = _super.call(this, null, viewSpec.options) || this;
+ _this.batchRenderDepth = 0;
+ _this.isSelected = false; // boolean whether a range of time is user-selected or not
+ _this.calendar = calendar;
+ _this.viewSpec = viewSpec;
+ // shortcuts
+ _this.type = viewSpec.type;
+ // .name is deprecated
+ _this.name = _this.type;
+ _this.initRenderQueue();
+ _this.initHiddenDays();
+ _this.dateProfileGenerator = new _this.dateProfileGeneratorClass(_this);
+ _this.bindBaseRenderHandlers();
+ _this.eventOrderSpecs = util_1.parseFieldSpecs(_this.opt('eventOrder'));
+ // legacy
+ if (_this['initialize']) {
+ _this['initialize']();
+ }
+ return _this;
+ }
+ View.prototype._getView = function () {
+ return this;
+ };
+ // Retrieves an option with the given name
+ View.prototype.opt = function (name) {
+ return this.options[name];
+ };
+ /* Render Queue
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.initRenderQueue = function () {
+ this.renderQueue = new RenderQueue_1.default({
+ event: this.opt('eventRenderWait')
+ });
+ this.renderQueue.on('start', this.onRenderQueueStart.bind(this));
+ this.renderQueue.on('stop', this.onRenderQueueStop.bind(this));
+ this.on('before:change', this.startBatchRender);
+ this.on('change', this.stopBatchRender);
+ };
+ View.prototype.onRenderQueueStart = function () {
+ this.calendar.freezeContentHeight();
+ this.addScroll(this.queryScroll());
+ };
+ View.prototype.onRenderQueueStop = function () {
+ if (this.calendar.updateViewSize()) {
+ this.popScroll();
+ }
+ this.calendar.thawContentHeight();
+ };
+ View.prototype.startBatchRender = function () {
+ if (!(this.batchRenderDepth++)) {
+ this.renderQueue.pause();
+ }
+ };
+ View.prototype.stopBatchRender = function () {
+ if (!(--this.batchRenderDepth)) {
+ this.renderQueue.resume();
+ }
+ };
+ View.prototype.requestRender = function (func, namespace, actionType) {
+ this.renderQueue.queue(func, namespace, actionType);
+ };
+ // given func will auto-bind to `this`
+ View.prototype.whenSizeUpdated = function (func) {
+ if (this.renderQueue.isRunning) {
+ this.renderQueue.one('stop', func.bind(this));
+ }
+ else {
+ func.call(this);
+ }
+ };
+ /* Title and Date Formatting
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Computes what the title at the top of the calendar should be for this view
+ View.prototype.computeTitle = function (dateProfile) {
+ var unzonedRange;
+ // for views that span a large unit of time, show the proper interval, ignoring stray days before and after
+ if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {
+ unzonedRange = dateProfile.currentUnzonedRange;
+ }
+ else {
+ unzonedRange = dateProfile.activeUnzonedRange;
+ }
+ return this.formatRange({
+ start: this.calendar.msToMoment(unzonedRange.startMs, dateProfile.isRangeAllDay),
+ end: this.calendar.msToMoment(unzonedRange.endMs, dateProfile.isRangeAllDay)
+ }, dateProfile.isRangeAllDay, this.opt('titleFormat') || this.computeTitleFormat(dateProfile), this.opt('titleRangeSeparator'));
+ };
+ // Generates the format string that should be used to generate the title for the current date range.
+ // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
+ View.prototype.computeTitleFormat = function (dateProfile) {
+ var currentRangeUnit = dateProfile.currentRangeUnit;
+ if (currentRangeUnit === 'year') {
+ return 'YYYY';
+ }
+ else if (currentRangeUnit === 'month') {
+ return this.opt('monthYearFormat'); // like "September 2014"
+ }
+ else if (dateProfile.currentUnzonedRange.as('days') > 1) {
+ return 'll'; // multi-day range. shorter, like "Sep 9 - 10 2014"
+ }
+ else {
+ return 'LL'; // one day. longer, like "September 9 2014"
+ }
+ };
+ // Date Setting/Unsetting
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.setDate = function (date) {
+ var currentDateProfile = this.get('dateProfile');
+ var newDateProfile = this.dateProfileGenerator.build(date, undefined, true); // forceToValid=true
+ if (!currentDateProfile ||
+ !currentDateProfile.activeUnzonedRange.equals(newDateProfile.activeUnzonedRange)) {
+ this.set('dateProfile', newDateProfile);
+ }
+ };
+ View.prototype.unsetDate = function () {
+ this.unset('dateProfile');
+ };
+ // Event Data
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.fetchInitialEvents = function (dateProfile) {
+ var calendar = this.calendar;
+ var forceAllDay = dateProfile.isRangeAllDay && !this.usesMinMaxTime;
+ return calendar.requestEvents(calendar.msToMoment(dateProfile.activeUnzonedRange.startMs, forceAllDay), calendar.msToMoment(dateProfile.activeUnzonedRange.endMs, forceAllDay));
+ };
+ View.prototype.bindEventChanges = function () {
+ this.listenTo(this.calendar, 'eventsReset', this.resetEvents); // TODO: make this a real event
+ };
+ View.prototype.unbindEventChanges = function () {
+ this.stopListeningTo(this.calendar, 'eventsReset');
+ };
+ View.prototype.setEvents = function (eventsPayload) {
+ this.set('currentEvents', eventsPayload);
+ this.set('hasEvents', true);
+ };
+ View.prototype.unsetEvents = function () {
+ this.unset('currentEvents');
+ this.unset('hasEvents');
+ };
+ View.prototype.resetEvents = function (eventsPayload) {
+ this.startBatchRender();
+ this.unsetEvents();
+ this.setEvents(eventsPayload);
+ this.stopBatchRender();
+ };
+ // Date High-level Rendering
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.requestDateRender = function (dateProfile) {
+ var _this = this;
+ this.requestRender(function () {
+ _this.executeDateRender(dateProfile);
+ }, 'date', 'init');
+ };
+ View.prototype.requestDateUnrender = function () {
+ var _this = this;
+ this.requestRender(function () {
+ _this.executeDateUnrender();
+ }, 'date', 'destroy');
+ };
+ // if dateProfile not specified, uses current
+ View.prototype.executeDateRender = function (dateProfile) {
+ _super.prototype.executeDateRender.call(this, dateProfile);
+ if (this['render']) {
+ this['render'](); // TODO: deprecate
+ }
+ this.trigger('datesRendered');
+ this.addScroll({ isDateInit: true });
+ this.startNowIndicator(); // shouldn't render yet because updateSize will be called soon
+ };
+ View.prototype.executeDateUnrender = function () {
+ this.unselect();
+ this.stopNowIndicator();
+ this.trigger('before:datesUnrendered');
+ if (this['destroy']) {
+ this['destroy'](); // TODO: deprecate
+ }
+ _super.prototype.executeDateUnrender.call(this);
+ };
+ // "Base" rendering
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.bindBaseRenderHandlers = function () {
+ var _this = this;
+ this.on('datesRendered', function () {
+ _this.whenSizeUpdated(_this.triggerViewRender);
+ });
+ this.on('before:datesUnrendered', function () {
+ _this.triggerViewDestroy();
+ });
+ };
+ View.prototype.triggerViewRender = function () {
+ this.publiclyTrigger('viewRender', {
+ context: this,
+ args: [this, this.el]
+ });
+ };
+ View.prototype.triggerViewDestroy = function () {
+ this.publiclyTrigger('viewDestroy', {
+ context: this,
+ args: [this, this.el]
+ });
+ };
+ // Event High-level Rendering
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.requestEventsRender = function (eventsPayload) {
+ var _this = this;
+ this.requestRender(function () {
+ _this.executeEventRender(eventsPayload);
+ _this.whenSizeUpdated(_this.triggerAfterEventsRendered);
+ }, 'event', 'init');
+ };
+ View.prototype.requestEventsUnrender = function () {
+ var _this = this;
+ this.requestRender(function () {
+ _this.triggerBeforeEventsDestroyed();
+ _this.executeEventUnrender();
+ }, 'event', 'destroy');
+ };
+ // Business Hour High-level Rendering
+ // -----------------------------------------------------------------------------------------------------------------
+ View.prototype.requestBusinessHoursRender = function (businessHourGenerator) {
+ var _this = this;
+ this.requestRender(function () {
+ _this.renderBusinessHours(businessHourGenerator);
+ }, 'businessHours', 'init');
+ };
+ View.prototype.requestBusinessHoursUnrender = function () {
+ var _this = this;
+ this.requestRender(function () {
+ _this.unrenderBusinessHours();
+ }, 'businessHours', 'destroy');
+ };
+ // Misc view rendering utils
+ // -----------------------------------------------------------------------------------------------------------------
+ // Binds DOM handlers to elements that reside outside the view container, such as the document
+ View.prototype.bindGlobalHandlers = function () {
+ _super.prototype.bindGlobalHandlers.call(this);
+ this.listenTo(GlobalEmitter_1.default.get(), {
+ touchstart: this.processUnselect,
+ mousedown: this.handleDocumentMousedown
+ });
+ };
+ // Unbinds DOM handlers from elements that reside outside the view container
+ View.prototype.unbindGlobalHandlers = function () {
+ _super.prototype.unbindGlobalHandlers.call(this);
+ this.stopListeningTo(GlobalEmitter_1.default.get());
+ };
+ /* Now Indicator
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Immediately render the current time indicator and begins re-rendering it at an interval,
+ // which is defined by this.getNowIndicatorUnit().
+ // TODO: somehow do this for the current whole day's background too
+ View.prototype.startNowIndicator = function () {
+ var _this = this;
+ var unit;
+ var update;
+ var delay; // ms wait value
+ if (this.opt('nowIndicator')) {
+ unit = this.getNowIndicatorUnit();
+ if (unit) {
+ update = util_1.proxy(this, 'updateNowIndicator'); // bind to `this`
+ this.initialNowDate = this.calendar.getNow();
+ this.initialNowQueriedMs = new Date().valueOf();
+ // wait until the beginning of the next interval
+ delay = this.initialNowDate.clone().startOf(unit).add(1, unit).valueOf() - this.initialNowDate.valueOf();
+ this.nowIndicatorTimeoutID = setTimeout(function () {
+ _this.nowIndicatorTimeoutID = null;
+ update();
+ delay = +moment.duration(1, unit);
+ delay = Math.max(100, delay); // prevent too frequent
+ _this.nowIndicatorIntervalID = setInterval(update, delay); // update every interval
+ }, delay);
+ }
+ // rendering will be initiated in updateSize
+ }
+ };
+ // rerenders the now indicator, computing the new current time from the amount of time that has passed
+ // since the initial getNow call.
+ View.prototype.updateNowIndicator = function () {
+ if (this.isDatesRendered &&
+ this.initialNowDate // activated before?
+ ) {
+ this.unrenderNowIndicator(); // won't unrender if unnecessary
+ this.renderNowIndicator(this.initialNowDate.clone().add(new Date().valueOf() - this.initialNowQueriedMs) // add ms
+ );
+ this.isNowIndicatorRendered = true;
+ }
+ };
+ // Immediately unrenders the view's current time indicator and stops any re-rendering timers.
+ // Won't cause side effects if indicator isn't rendered.
+ View.prototype.stopNowIndicator = function () {
+ if (this.isNowIndicatorRendered) {
+ if (this.nowIndicatorTimeoutID) {
+ clearTimeout(this.nowIndicatorTimeoutID);
+ this.nowIndicatorTimeoutID = null;
+ }
+ if (this.nowIndicatorIntervalID) {
+ clearInterval(this.nowIndicatorIntervalID);
+ this.nowIndicatorIntervalID = null;
+ }
+ this.unrenderNowIndicator();
+ this.isNowIndicatorRendered = false;
+ }
+ };
+ /* Dimensions
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ if (this['setHeight']) {
+ this['setHeight'](totalHeight, isAuto);
+ }
+ else {
+ _super.prototype.updateSize.call(this, totalHeight, isAuto, isResize);
+ }
+ this.updateNowIndicator();
+ };
+ /* Scroller
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.addScroll = function (scroll) {
+ var queuedScroll = this.queuedScroll || (this.queuedScroll = {});
+ $.extend(queuedScroll, scroll);
+ };
+ View.prototype.popScroll = function () {
+ this.applyQueuedScroll();
+ this.queuedScroll = null;
+ };
+ View.prototype.applyQueuedScroll = function () {
+ if (this.queuedScroll) {
+ this.applyScroll(this.queuedScroll);
+ }
+ };
+ View.prototype.queryScroll = function () {
+ var scroll = {};
+ if (this.isDatesRendered) {
+ $.extend(scroll, this.queryDateScroll());
+ }
+ return scroll;
+ };
+ View.prototype.applyScroll = function (scroll) {
+ if (scroll.isDateInit && this.isDatesRendered) {
+ $.extend(scroll, this.computeInitialDateScroll());
+ }
+ if (this.isDatesRendered) {
+ this.applyDateScroll(scroll);
+ }
+ };
+ View.prototype.computeInitialDateScroll = function () {
+ return {}; // subclasses must implement
+ };
+ View.prototype.queryDateScroll = function () {
+ return {}; // subclasses must implement
+ };
+ View.prototype.applyDateScroll = function (scroll) {
+ // subclasses must implement
+ };
+ /* Event Drag-n-Drop
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.reportEventDrop = function (eventInstance, eventMutation, el, ev) {
+ var eventManager = this.calendar.eventManager;
+ var undoFunc = eventManager.mutateEventsWithId(eventInstance.def.id, eventMutation);
+ var dateMutation = eventMutation.dateMutation;
+ // update the EventInstance, for handlers
+ if (dateMutation) {
+ eventInstance.dateProfile = dateMutation.buildNewDateProfile(eventInstance.dateProfile, this.calendar);
+ }
+ this.triggerEventDrop(eventInstance,
+ // a drop doesn't necessarily mean a date mutation (ex: resource change)
+ (dateMutation && dateMutation.dateDelta) || moment.duration(), undoFunc, el, ev);
+ };
+ // Triggers event-drop handlers that have subscribed via the API
+ View.prototype.triggerEventDrop = function (eventInstance, dateDelta, undoFunc, el, ev) {
+ this.publiclyTrigger('eventDrop', {
+ context: el[0],
+ args: [
+ eventInstance.toLegacy(),
+ dateDelta,
+ undoFunc,
+ ev,
+ {},
+ this
+ ]
+ });
+ };
+ /* External Element Drag-n-Drop
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Must be called when an external element, via jQuery UI, has been dropped onto the calendar.
+ // `meta` is the parsed data that has been embedded into the dragging event.
+ // `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
+ View.prototype.reportExternalDrop = function (singleEventDef, isEvent, isSticky, el, ev, ui) {
+ if (isEvent) {
+ this.calendar.eventManager.addEventDef(singleEventDef, isSticky);
+ }
+ this.triggerExternalDrop(singleEventDef, isEvent, el, ev, ui);
+ };
+ // Triggers external-drop handlers that have subscribed via the API
+ View.prototype.triggerExternalDrop = function (singleEventDef, isEvent, el, ev, ui) {
+ // trigger 'drop' regardless of whether element represents an event
+ this.publiclyTrigger('drop', {
+ context: el[0],
+ args: [
+ singleEventDef.dateProfile.start.clone(),
+ ev,
+ ui,
+ this
+ ]
+ });
+ if (isEvent) {
+ // signal an external event landed
+ this.publiclyTrigger('eventReceive', {
+ context: this,
+ args: [
+ singleEventDef.buildInstance().toLegacy(),
+ this
+ ]
+ });
+ }
+ };
+ /* Event Resizing
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Must be called when an event in the view has been resized to a new length
+ View.prototype.reportEventResize = function (eventInstance, eventMutation, el, ev) {
+ var eventManager = this.calendar.eventManager;
+ var undoFunc = eventManager.mutateEventsWithId(eventInstance.def.id, eventMutation);
+ // update the EventInstance, for handlers
+ eventInstance.dateProfile = eventMutation.dateMutation.buildNewDateProfile(eventInstance.dateProfile, this.calendar);
+ this.triggerEventResize(eventInstance, eventMutation.dateMutation.endDelta, undoFunc, el, ev);
+ };
+ // Triggers event-resize handlers that have subscribed via the API
+ View.prototype.triggerEventResize = function (eventInstance, durationDelta, undoFunc, el, ev) {
+ this.publiclyTrigger('eventResize', {
+ context: el[0],
+ args: [
+ eventInstance.toLegacy(),
+ durationDelta,
+ undoFunc,
+ ev,
+ {},
+ this
+ ]
+ });
+ };
+ /* Selection (time range)
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Selects a date span on the view. `start` and `end` are both Moments.
+ // `ev` is the native mouse event that begin the interaction.
+ View.prototype.select = function (footprint, ev) {
+ this.unselect(ev);
+ this.renderSelectionFootprint(footprint);
+ this.reportSelection(footprint, ev);
+ };
+ View.prototype.renderSelectionFootprint = function (footprint) {
+ if (this['renderSelection']) {
+ this['renderSelection'](footprint.toLegacy(this.calendar));
+ }
+ else {
+ _super.prototype.renderSelectionFootprint.call(this, footprint);
+ }
+ };
+ // Called when a new selection is made. Updates internal state and triggers handlers.
+ View.prototype.reportSelection = function (footprint, ev) {
+ this.isSelected = true;
+ this.triggerSelect(footprint, ev);
+ };
+ // Triggers handlers to 'select'
+ View.prototype.triggerSelect = function (footprint, ev) {
+ var dateProfile = this.calendar.footprintToDateProfile(footprint); // abuse of "Event"DateProfile?
+ this.publiclyTrigger('select', {
+ context: this,
+ args: [
+ dateProfile.start,
+ dateProfile.end,
+ ev,
+ this
+ ]
+ });
+ };
+ // Undoes a selection. updates in the internal state and triggers handlers.
+ // `ev` is the native mouse event that began the interaction.
+ View.prototype.unselect = function (ev) {
+ if (this.isSelected) {
+ this.isSelected = false;
+ if (this['destroySelection']) {
+ this['destroySelection'](); // TODO: deprecate
+ }
+ this.unrenderSelection();
+ this.publiclyTrigger('unselect', {
+ context: this,
+ args: [ev, this]
+ });
+ }
+ };
+ /* Event Selection
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.selectEventInstance = function (eventInstance) {
+ if (!this.selectedEventInstance ||
+ this.selectedEventInstance !== eventInstance) {
+ this.unselectEventInstance();
+ this.getEventSegs().forEach(function (seg) {
+ if (seg.footprint.eventInstance === eventInstance &&
+ seg.el // necessary?
+ ) {
+ seg.el.addClass('fc-selected');
+ }
+ });
+ this.selectedEventInstance = eventInstance;
+ }
+ };
+ View.prototype.unselectEventInstance = function () {
+ if (this.selectedEventInstance) {
+ this.getEventSegs().forEach(function (seg) {
+ if (seg.el) {
+ seg.el.removeClass('fc-selected');
+ }
+ });
+ this.selectedEventInstance = null;
+ }
+ };
+ View.prototype.isEventDefSelected = function (eventDef) {
+ // event references might change on refetchEvents(), while selectedEventInstance doesn't,
+ // so compare IDs
+ return this.selectedEventInstance && this.selectedEventInstance.def.id === eventDef.id;
+ };
+ /* Mouse / Touch Unselecting (time range & event unselection)
+ ------------------------------------------------------------------------------------------------------------------*/
+ // TODO: move consistently to down/start or up/end?
+ // TODO: don't kill previous selection if touch scrolling
+ View.prototype.handleDocumentMousedown = function (ev) {
+ if (util_1.isPrimaryMouseButton(ev)) {
+ this.processUnselect(ev);
+ }
+ };
+ View.prototype.processUnselect = function (ev) {
+ this.processRangeUnselect(ev);
+ this.processEventUnselect(ev);
+ };
+ View.prototype.processRangeUnselect = function (ev) {
+ var ignore;
+ // is there a time-range selection?
+ if (this.isSelected && this.opt('unselectAuto')) {
+ // only unselect if the clicked element is not identical to or inside of an 'unselectCancel' element
+ ignore = this.opt('unselectCancel');
+ if (!ignore || !$(ev.target).closest(ignore).length) {
+ this.unselect(ev);
+ }
+ }
+ };
+ View.prototype.processEventUnselect = function (ev) {
+ if (this.selectedEventInstance) {
+ if (!$(ev.target).closest('.fc-selected').length) {
+ this.unselectEventInstance();
+ }
+ }
+ };
+ /* Triggers
+ ------------------------------------------------------------------------------------------------------------------*/
+ View.prototype.triggerBaseRendered = function () {
+ this.publiclyTrigger('viewRender', {
+ context: this,
+ args: [this, this.el]
+ });
+ };
+ View.prototype.triggerBaseUnrendered = function () {
+ this.publiclyTrigger('viewDestroy', {
+ context: this,
+ args: [this, this.el]
+ });
+ };
+ // Triggers handlers to 'dayClick'
+ // Span has start/end of the clicked area. Only the start is useful.
+ View.prototype.triggerDayClick = function (footprint, dayEl, ev) {
+ var dateProfile = this.calendar.footprintToDateProfile(footprint); // abuse of "Event"DateProfile?
+ this.publiclyTrigger('dayClick', {
+ context: dayEl,
+ args: [dateProfile.start, ev, this]
+ });
+ };
+ /* Date Utils
+ ------------------------------------------------------------------------------------------------------------------*/
+ // For DateComponent::getDayClasses
+ View.prototype.isDateInOtherMonth = function (date, dateProfile) {
+ return false;
+ };
+ // Arguments after name will be forwarded to a hypothetical function value
+ // WARNING: passed-in arguments will be given to generator functions as-is and can cause side-effects.
+ // Always clone your objects if you fear mutation.
+ View.prototype.getUnzonedRangeOption = function (name) {
+ var val = this.opt(name);
+ if (typeof val === 'function') {
+ val = val.apply(null, Array.prototype.slice.call(arguments, 1));
+ }
+ if (val) {
+ return this.calendar.parseUnzonedRange(val);
+ }
+ };
+ /* Hidden Days
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Initializes internal variables related to calculating hidden days-of-week
+ View.prototype.initHiddenDays = function () {
+ var hiddenDays = this.opt('hiddenDays') || []; // array of day-of-week indices that are hidden
+ var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)
+ var dayCnt = 0;
+ var i;
+ if (this.opt('weekends') === false) {
+ hiddenDays.push(0, 6); // 0=sunday, 6=saturday
+ }
+ for (i = 0; i < 7; i++) {
+ if (!(isHiddenDayHash[i] = $.inArray(i, hiddenDays) !== -1)) {
+ dayCnt++;
+ }
+ }
+ if (!dayCnt) {
+ throw new Error('invalid hiddenDays'); // all days were hidden? bad.
+ }
+ this.isHiddenDayHash = isHiddenDayHash;
+ };
+ // Remove days from the beginning and end of the range that are computed as hidden.
+ // If the whole range is trimmed off, returns null
+ View.prototype.trimHiddenDays = function (inputUnzonedRange) {
+ var start = inputUnzonedRange.getStart();
+ var end = inputUnzonedRange.getEnd();
+ if (start) {
+ start = this.skipHiddenDays(start);
+ }
+ if (end) {
+ end = this.skipHiddenDays(end, -1, true);
+ }
+ if (start === null || end === null || start < end) {
+ return new UnzonedRange_1.default(start, end);
+ }
+ return null;
+ };
+ // Is the current day hidden?
+ // `day` is a day-of-week index (0-6), or a Moment
+ View.prototype.isHiddenDay = function (day) {
+ if (moment.isMoment(day)) {
+ day = day.day();
+ }
+ return this.isHiddenDayHash[day];
+ };
+ // Incrementing the current day until it is no longer a hidden day, returning a copy.
+ // DOES NOT CONSIDER validUnzonedRange!
+ // If the initial value of `date` is not a hidden day, don't do anything.
+ // Pass `isExclusive` as `true` if you are dealing with an end date.
+ // `inc` defaults to `1` (increment one day forward each time)
+ View.prototype.skipHiddenDays = function (date, inc, isExclusive) {
+ if (inc === void 0) { inc = 1; }
+ if (isExclusive === void 0) { isExclusive = false; }
+ var out = date.clone();
+ while (this.isHiddenDayHash[(out.day() + (isExclusive ? inc : 0) + 7) % 7]) {
+ out.add(inc, 'days');
+ }
+ return out;
+ };
+ return View;
+}(InteractiveDateComponent_1.default));
+exports.default = View;
+View.prototype.usesMinMaxTime = false;
+View.prototype.dateProfileGeneratorClass = DateProfileGenerator_1.default;
+View.watch('displayingDates', ['isInDom', 'dateProfile'], function (deps) {
+ this.requestDateRender(deps.dateProfile);
+}, function () {
+ this.requestDateUnrender();
+});
+View.watch('displayingBusinessHours', ['displayingDates', 'businessHourGenerator'], function (deps) {
+ this.requestBusinessHoursRender(deps.businessHourGenerator);
+}, function () {
+ this.requestBusinessHoursUnrender();
+});
+View.watch('initialEvents', ['dateProfile'], function (deps) {
+ return this.fetchInitialEvents(deps.dateProfile);
+});
+View.watch('bindingEvents', ['initialEvents'], function (deps) {
+ this.setEvents(deps.initialEvents);
+ this.bindEventChanges();
+}, function () {
+ this.unbindEventChanges();
+ this.unsetEvents();
+});
+View.watch('displayingEvents', ['displayingDates', 'hasEvents'], function () {
+ this.requestEventsRender(this.get('currentEvents'));
+}, function () {
+ this.requestEventsUnrender();
+});
+View.watch('title', ['dateProfile'], function (deps) {
+ return (this.title = this.computeTitle(deps.dateProfile)); // assign to View for legacy reasons
+});
+View.watch('legacyDateProps', ['dateProfile'], function (deps) {
+ var calendar = this.calendar;
+ var dateProfile = deps.dateProfile;
+ // DEPRECATED, but we need to keep it updated...
+ this.start = calendar.msToMoment(dateProfile.activeUnzonedRange.startMs, dateProfile.isRangeAllDay);
+ this.end = calendar.msToMoment(dateProfile.activeUnzonedRange.endMs, dateProfile.isRangeAllDay);
+ this.intervalStart = calendar.msToMoment(dateProfile.currentUnzonedRange.startMs, dateProfile.isRangeAllDay);
+ this.intervalEnd = calendar.msToMoment(dateProfile.currentUnzonedRange.endMs, dateProfile.isRangeAllDay);
+});
+
+
+/***/ }),
+/* 42 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var EventRenderer = /** @class */ (function () {
+ function EventRenderer(component, fillRenderer) {
+ this.view = component._getView();
+ this.component = component;
+ this.fillRenderer = fillRenderer;
+ }
+ EventRenderer.prototype.opt = function (name) {
+ return this.view.opt(name);
+ };
+ // Updates values that rely on options and also relate to range
+ EventRenderer.prototype.rangeUpdated = function () {
+ var displayEventTime;
+ var displayEventEnd;
+ this.eventTimeFormat =
+ this.opt('eventTimeFormat') ||
+ this.opt('timeFormat') || // deprecated
+ this.computeEventTimeFormat();
+ displayEventTime = this.opt('displayEventTime');
+ if (displayEventTime == null) {
+ displayEventTime = this.computeDisplayEventTime(); // might be based off of range
+ }
+ displayEventEnd = this.opt('displayEventEnd');
+ if (displayEventEnd == null) {
+ displayEventEnd = this.computeDisplayEventEnd(); // might be based off of range
+ }
+ this.displayEventTime = displayEventTime;
+ this.displayEventEnd = displayEventEnd;
+ };
+ EventRenderer.prototype.render = function (eventsPayload) {
+ var dateProfile = this.component._getDateProfile();
+ var eventDefId;
+ var instanceGroup;
+ var eventRanges;
+ var bgRanges = [];
+ var fgRanges = [];
+ for (eventDefId in eventsPayload) {
+ instanceGroup = eventsPayload[eventDefId];
+ eventRanges = instanceGroup.sliceRenderRanges(dateProfile.activeUnzonedRange);
+ if (instanceGroup.getEventDef().hasBgRendering()) {
+ bgRanges.push.apply(bgRanges, eventRanges);
+ }
+ else {
+ fgRanges.push.apply(fgRanges, eventRanges);
+ }
+ }
+ this.renderBgRanges(bgRanges);
+ this.renderFgRanges(fgRanges);
+ };
+ EventRenderer.prototype.unrender = function () {
+ this.unrenderBgRanges();
+ this.unrenderFgRanges();
+ };
+ EventRenderer.prototype.renderFgRanges = function (eventRanges) {
+ var eventFootprints = this.component.eventRangesToEventFootprints(eventRanges);
+ var segs = this.component.eventFootprintsToSegs(eventFootprints);
+ // render an `.el` on each seg
+ // returns a subset of the segs. segs that were actually rendered
+ segs = this.renderFgSegEls(segs);
+ if (this.renderFgSegs(segs) !== false) {
+ this.fgSegs = segs;
+ }
+ };
+ EventRenderer.prototype.unrenderFgRanges = function () {
+ this.unrenderFgSegs(this.fgSegs || []);
+ this.fgSegs = null;
+ };
+ EventRenderer.prototype.renderBgRanges = function (eventRanges) {
+ var eventFootprints = this.component.eventRangesToEventFootprints(eventRanges);
+ var segs = this.component.eventFootprintsToSegs(eventFootprints);
+ if (this.renderBgSegs(segs) !== false) {
+ this.bgSegs = segs;
+ }
+ };
+ EventRenderer.prototype.unrenderBgRanges = function () {
+ this.unrenderBgSegs();
+ this.bgSegs = null;
+ };
+ EventRenderer.prototype.getSegs = function () {
+ return (this.bgSegs || []).concat(this.fgSegs || []);
+ };
+ // Renders foreground event segments onto the grid
+ EventRenderer.prototype.renderFgSegs = function (segs) {
+ // subclasses must implement
+ // segs already has rendered els, and has been filtered.
+ return false; // signal failure if not implemented
+ };
+ // Unrenders all currently rendered foreground segments
+ EventRenderer.prototype.unrenderFgSegs = function (segs) {
+ // subclasses must implement
+ };
+ EventRenderer.prototype.renderBgSegs = function (segs) {
+ var _this = this;
+ if (this.fillRenderer) {
+ this.fillRenderer.renderSegs('bgEvent', segs, {
+ getClasses: function (seg) {
+ return _this.getBgClasses(seg.footprint.eventDef);
+ },
+ getCss: function (seg) {
+ return {
+ 'background-color': _this.getBgColor(seg.footprint.eventDef)
+ };
+ },
+ filterEl: function (seg, el) {
+ return _this.filterEventRenderEl(seg.footprint, el);
+ }
+ });
+ }
+ else {
+ return false; // signal failure if no fillRenderer
+ }
+ };
+ EventRenderer.prototype.unrenderBgSegs = function () {
+ if (this.fillRenderer) {
+ this.fillRenderer.unrender('bgEvent');
+ }
+ };
+ // Renders and assigns an `el` property for each foreground event segment.
+ // Only returns segments that successfully rendered.
+ EventRenderer.prototype.renderFgSegEls = function (segs, disableResizing) {
+ var _this = this;
+ if (disableResizing === void 0) { disableResizing = false; }
+ var hasEventRenderHandlers = this.view.hasPublicHandlers('eventRender');
+ var html = '';
+ var renderedSegs = [];
+ var i;
+ if (segs.length) {
+ // build a large concatenation of event segment HTML
+ for (i = 0; i < segs.length; i++) {
+ this.beforeFgSegHtml(segs[i]);
+ html += this.fgSegHtml(segs[i], disableResizing);
+ }
+ // Grab individual elements from the combined HTML string. Use each as the default rendering.
+ // Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false.
+ $(html).each(function (i, node) {
+ var seg = segs[i];
+ var el = $(node);
+ if (hasEventRenderHandlers) {
+ el = _this.filterEventRenderEl(seg.footprint, el);
+ }
+ if (el) {
+ el.data('fc-seg', seg); // used by handlers
+ seg.el = el;
+ renderedSegs.push(seg);
+ }
+ });
+ }
+ return renderedSegs;
+ };
+ EventRenderer.prototype.beforeFgSegHtml = function (seg) {
+ };
+ // Generates the HTML for the default rendering of a foreground event segment. Used by renderFgSegEls()
+ EventRenderer.prototype.fgSegHtml = function (seg, disableResizing) {
+ // subclasses should implement
+ };
+ // Generic utility for generating the HTML classNames for an event segment's element
+ EventRenderer.prototype.getSegClasses = function (seg, isDraggable, isResizable) {
+ var classes = [
+ 'fc-event',
+ seg.isStart ? 'fc-start' : 'fc-not-start',
+ seg.isEnd ? 'fc-end' : 'fc-not-end'
+ ].concat(this.getClasses(seg.footprint.eventDef));
+ if (isDraggable) {
+ classes.push('fc-draggable');
+ }
+ if (isResizable) {
+ classes.push('fc-resizable');
+ }
+ // event is currently selected? attach a className.
+ if (this.view.isEventDefSelected(seg.footprint.eventDef)) {
+ classes.push('fc-selected');
+ }
+ return classes;
+ };
+ // Given an event and the default element used for rendering, returns the element that should actually be used.
+ // Basically runs events and elements through the eventRender hook.
+ EventRenderer.prototype.filterEventRenderEl = function (eventFootprint, el) {
+ var legacy = eventFootprint.getEventLegacy();
+ var custom = this.view.publiclyTrigger('eventRender', {
+ context: legacy,
+ args: [legacy, el, this.view]
+ });
+ if (custom === false) {
+ el = null;
+ }
+ else if (custom && custom !== true) {
+ el = $(custom);
+ }
+ return el;
+ };
+ // Compute the text that should be displayed on an event's element.
+ // `range` can be the Event object itself, or something range-like, with at least a `start`.
+ // If event times are disabled, or the event has no time, will return a blank string.
+ // If not specified, formatStr will default to the eventTimeFormat setting,
+ // and displayEnd will default to the displayEventEnd setting.
+ EventRenderer.prototype.getTimeText = function (eventFootprint, formatStr, displayEnd) {
+ return this._getTimeText(eventFootprint.eventInstance.dateProfile.start, eventFootprint.eventInstance.dateProfile.end, eventFootprint.componentFootprint.isAllDay, formatStr, displayEnd);
+ };
+ EventRenderer.prototype._getTimeText = function (start, end, isAllDay, formatStr, displayEnd) {
+ if (formatStr == null) {
+ formatStr = this.eventTimeFormat;
+ }
+ if (displayEnd == null) {
+ displayEnd = this.displayEventEnd;
+ }
+ if (this.displayEventTime && !isAllDay) {
+ if (displayEnd && end) {
+ return this.view.formatRange({ start: start, end: end }, false, // allDay
+ formatStr);
+ }
+ else {
+ return start.format(formatStr);
+ }
+ }
+ return '';
+ };
+ EventRenderer.prototype.computeEventTimeFormat = function () {
+ return this.opt('smallTimeFormat');
+ };
+ EventRenderer.prototype.computeDisplayEventTime = function () {
+ return true;
+ };
+ EventRenderer.prototype.computeDisplayEventEnd = function () {
+ return true;
+ };
+ EventRenderer.prototype.getBgClasses = function (eventDef) {
+ var classNames = this.getClasses(eventDef);
+ classNames.push('fc-bgevent');
+ return classNames;
+ };
+ EventRenderer.prototype.getClasses = function (eventDef) {
+ var objs = this.getStylingObjs(eventDef);
+ var i;
+ var classNames = [];
+ for (i = 0; i < objs.length; i++) {
+ classNames.push.apply(// append
+ classNames, objs[i].eventClassName || objs[i].className || []);
+ }
+ return classNames;
+ };
+ // Utility for generating event skin-related CSS properties
+ EventRenderer.prototype.getSkinCss = function (eventDef) {
+ return {
+ 'background-color': this.getBgColor(eventDef),
+ 'border-color': this.getBorderColor(eventDef),
+ color: this.getTextColor(eventDef)
+ };
+ };
+ // Queries for caller-specified color, then falls back to default
+ EventRenderer.prototype.getBgColor = function (eventDef) {
+ var objs = this.getStylingObjs(eventDef);
+ var i;
+ var val;
+ for (i = 0; i < objs.length && !val; i++) {
+ val = objs[i].eventBackgroundColor || objs[i].eventColor ||
+ objs[i].backgroundColor || objs[i].color;
+ }
+ if (!val) {
+ val = this.opt('eventBackgroundColor') || this.opt('eventColor');
+ }
+ return val;
+ };
+ // Queries for caller-specified color, then falls back to default
+ EventRenderer.prototype.getBorderColor = function (eventDef) {
+ var objs = this.getStylingObjs(eventDef);
+ var i;
+ var val;
+ for (i = 0; i < objs.length && !val; i++) {
+ val = objs[i].eventBorderColor || objs[i].eventColor ||
+ objs[i].borderColor || objs[i].color;
+ }
+ if (!val) {
+ val = this.opt('eventBorderColor') || this.opt('eventColor');
+ }
+ return val;
+ };
+ // Queries for caller-specified color, then falls back to default
+ EventRenderer.prototype.getTextColor = function (eventDef) {
+ var objs = this.getStylingObjs(eventDef);
+ var i;
+ var val;
+ for (i = 0; i < objs.length && !val; i++) {
+ val = objs[i].eventTextColor ||
+ objs[i].textColor;
+ }
+ if (!val) {
+ val = this.opt('eventTextColor');
+ }
+ return val;
+ };
+ EventRenderer.prototype.getStylingObjs = function (eventDef) {
+ var objs = this.getFallbackStylingObjs(eventDef);
+ objs.unshift(eventDef);
+ return objs;
+ };
+ EventRenderer.prototype.getFallbackStylingObjs = function (eventDef) {
+ return [eventDef.source];
+ };
+ EventRenderer.prototype.sortEventSegs = function (segs) {
+ segs.sort(util_1.proxy(this, 'compareEventSegs'));
+ };
+ // A cmp function for determining which segments should take visual priority
+ EventRenderer.prototype.compareEventSegs = function (seg1, seg2) {
+ var f1 = seg1.footprint;
+ var f2 = seg2.footprint;
+ var cf1 = f1.componentFootprint;
+ var cf2 = f2.componentFootprint;
+ var r1 = cf1.unzonedRange;
+ var r2 = cf2.unzonedRange;
+ return r1.startMs - r2.startMs || // earlier events go first
+ (r2.endMs - r2.startMs) - (r1.endMs - r1.startMs) || // tie? longer events go first
+ cf2.isAllDay - cf1.isAllDay || // tie? put all-day events first (booleans cast to 0/1)
+ util_1.compareByFieldSpecs(f1.eventDef, f2.eventDef, this.view.eventOrderSpecs, f1.eventDef.miscProps, f2.eventDef.miscProps);
+ };
+ return EventRenderer;
+}());
+exports.default = EventRenderer;
+
+
+/***/ }),
+/* 43 */,
+/* 44 */,
+/* 45 */,
+/* 46 */,
+/* 47 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment_ext_1 = __webpack_require__(10);
+// Plugin
+// -------------------------------------------------------------------------------------------------
+moment_ext_1.newMomentProto.format = function () {
+ if (this._fullCalendar && arguments[0]) {
+ return formatDate(this, arguments[0]); // our extended formatting
+ }
+ if (this._ambigTime) {
+ return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD');
+ }
+ if (this._ambigZone) {
+ return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
+ }
+ if (this._fullCalendar) {
+ // moment.format() doesn't ensure english, but we want to.
+ return moment_ext_1.oldMomentFormat(englishMoment(this));
+ }
+ return moment_ext_1.oldMomentProto.format.apply(this, arguments);
+};
+moment_ext_1.newMomentProto.toISOString = function () {
+ if (this._ambigTime) {
+ return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD');
+ }
+ if (this._ambigZone) {
+ return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
+ }
+ if (this._fullCalendar) {
+ // depending on browser, moment might not output english. ensure english.
+ // https://github.com/moment/moment/blob/2.18.1/src/lib/moment/format.js#L22
+ return moment_ext_1.oldMomentProto.toISOString.apply(englishMoment(this), arguments);
+ }
+ return moment_ext_1.oldMomentProto.toISOString.apply(this, arguments);
+};
+function englishMoment(mom) {
+ if (mom.locale() !== 'en') {
+ return mom.clone().locale('en');
+ }
+ return mom;
+}
+// Config
+// ---------------------------------------------------------------------------------------------------------------------
+/*
+Inserted between chunks in the fake ("intermediate") formatting string.
+Important that it passes as whitespace (\s) because moment often identifies non-standalone months
+via a regexp with an \s.
+*/
+var PART_SEPARATOR = '\u000b'; // vertical tab
+/*
+Inserted as the first character of a literal-text chunk to indicate that the literal text is not actually literal text,
+but rather, a "special" token that has custom rendering (see specialTokens map).
+*/
+var SPECIAL_TOKEN_MARKER = '\u001f'; // information separator 1
+/*
+Inserted at the beginning and end of a span of text that must have non-zero numeric characters.
+Handling of these markers is done in a post-processing step at the very end of text rendering.
+*/
+var MAYBE_MARKER = '\u001e'; // information separator 2
+var MAYBE_REGEXP = new RegExp(MAYBE_MARKER + '([^' + MAYBE_MARKER + ']*)' + MAYBE_MARKER, 'g'); // must be global
+/*
+Addition formatting tokens we want recognized
+*/
+var specialTokens = {
+ t: function (date) {
+ return moment_ext_1.oldMomentFormat(date, 'a').charAt(0);
+ },
+ T: function (date) {
+ return moment_ext_1.oldMomentFormat(date, 'A').charAt(0);
+ }
+};
+/*
+The first characters of formatting tokens for units that are 1 day or larger.
+`value` is for ranking relative size (lower means bigger).
+`unit` is a normalized unit, used for comparing moments.
+*/
+var largeTokenMap = {
+ Y: { value: 1, unit: 'year' },
+ M: { value: 2, unit: 'month' },
+ W: { value: 3, unit: 'week' },
+ w: { value: 3, unit: 'week' },
+ D: { value: 4, unit: 'day' },
+ d: { value: 4, unit: 'day' } // day of week
+};
+// Single Date Formatting
+// ---------------------------------------------------------------------------------------------------------------------
+/*
+Formats `date` with a Moment formatting string, but allow our non-zero areas and special token
+*/
+function formatDate(date, formatStr) {
+ return renderFakeFormatString(getParsedFormatString(formatStr).fakeFormatString, date);
+}
+exports.formatDate = formatDate;
+// Date Range Formatting
+// -------------------------------------------------------------------------------------------------
+// TODO: make it work with timezone offset
+/*
+Using a formatting string meant for a single date, generate a range string, like
+"Sep 2 - 9 2013", that intelligently inserts a separator where the dates differ.
+If the dates are the same as far as the format string is concerned, just return a single
+rendering of one date, without any separator.
+*/
+function formatRange(date1, date2, formatStr, separator, isRTL) {
+ var localeData;
+ date1 = moment_ext_1.default.parseZone(date1);
+ date2 = moment_ext_1.default.parseZone(date2);
+ localeData = date1.localeData();
+ // Expand localized format strings, like "LL" -> "MMMM D YYYY".
+ // BTW, this is not important for `formatDate` because it is impossible to put custom tokens
+ // or non-zero areas in Moment's localized format strings.
+ formatStr = localeData.longDateFormat(formatStr) || formatStr;
+ return renderParsedFormat(getParsedFormatString(formatStr), date1, date2, separator || ' - ', isRTL);
+}
+exports.formatRange = formatRange;
+/*
+Renders a range with an already-parsed format string.
+*/
+function renderParsedFormat(parsedFormat, date1, date2, separator, isRTL) {
+ var sameUnits = parsedFormat.sameUnits;
+ var unzonedDate1 = date1.clone().stripZone(); // for same-unit comparisons
+ var unzonedDate2 = date2.clone().stripZone(); // "
+ var renderedParts1 = renderFakeFormatStringParts(parsedFormat.fakeFormatString, date1);
+ var renderedParts2 = renderFakeFormatStringParts(parsedFormat.fakeFormatString, date2);
+ var leftI;
+ var leftStr = '';
+ var rightI;
+ var rightStr = '';
+ var middleI;
+ var middleStr1 = '';
+ var middleStr2 = '';
+ var middleStr = '';
+ // Start at the leftmost side of the formatting string and continue until you hit a token
+ // that is not the same between dates.
+ for (leftI = 0; leftI < sameUnits.length && (!sameUnits[leftI] || unzonedDate1.isSame(unzonedDate2, sameUnits[leftI])); leftI++) {
+ leftStr += renderedParts1[leftI];
+ }
+ // Similarly, start at the rightmost side of the formatting string and move left
+ for (rightI = sameUnits.length - 1; rightI > leftI && (!sameUnits[rightI] || unzonedDate1.isSame(unzonedDate2, sameUnits[rightI])); rightI--) {
+ // If current chunk is on the boundary of unique date-content, and is a special-case
+ // date-formatting postfix character, then don't consume it. Consider it unique date-content.
+ // TODO: make configurable
+ if (rightI - 1 === leftI && renderedParts1[rightI] === '.') {
+ break;
+ }
+ rightStr = renderedParts1[rightI] + rightStr;
+ }
+ // The area in the middle is different for both of the dates.
+ // Collect them distinctly so we can jam them together later.
+ for (middleI = leftI; middleI <= rightI; middleI++) {
+ middleStr1 += renderedParts1[middleI];
+ middleStr2 += renderedParts2[middleI];
+ }
+ if (middleStr1 || middleStr2) {
+ if (isRTL) {
+ middleStr = middleStr2 + separator + middleStr1;
+ }
+ else {
+ middleStr = middleStr1 + separator + middleStr2;
+ }
+ }
+ return processMaybeMarkers(leftStr + middleStr + rightStr);
+}
+// Format String Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+var parsedFormatStrCache = {};
+/*
+Returns a parsed format string, leveraging a cache.
+*/
+function getParsedFormatString(formatStr) {
+ return parsedFormatStrCache[formatStr] ||
+ (parsedFormatStrCache[formatStr] = parseFormatString(formatStr));
+}
+/*
+Parses a format string into the following:
+- fakeFormatString: a momentJS formatting string, littered with special control characters that get post-processed.
+- sameUnits: for every part in fakeFormatString, if the part is a token, the value will be a unit string (like "day"),
+ that indicates how similar a range's start & end must be in order to share the same formatted text.
+ If not a token, then the value is null.
+ Always a flat array (not nested liked "chunks").
+*/
+function parseFormatString(formatStr) {
+ var chunks = chunkFormatString(formatStr);
+ return {
+ fakeFormatString: buildFakeFormatString(chunks),
+ sameUnits: buildSameUnits(chunks)
+ };
+}
+/*
+Break the formatting string into an array of chunks.
+A 'maybe' chunk will have nested chunks.
+*/
+function chunkFormatString(formatStr) {
+ var chunks = [];
+ var match;
+ // TODO: more descrimination
+ // \4 is a backreference to the first character of a multi-character set.
+ var chunker = /\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;
+ while ((match = chunker.exec(formatStr))) {
+ if (match[1]) {
+ chunks.push.apply(chunks, // append
+ splitStringLiteral(match[1]));
+ }
+ else if (match[2]) {
+ chunks.push({ maybe: chunkFormatString(match[2]) });
+ }
+ else if (match[3]) {
+ chunks.push({ token: match[3] });
+ }
+ else if (match[5]) {
+ chunks.push.apply(chunks, // append
+ splitStringLiteral(match[5]));
+ }
+ }
+ return chunks;
+}
+/*
+Potentially splits a literal-text string into multiple parts. For special cases.
+*/
+function splitStringLiteral(s) {
+ if (s === '. ') {
+ return ['.', ' ']; // for locales with periods bound to the end of each year/month/date
+ }
+ else {
+ return [s];
+ }
+}
+/*
+Given chunks parsed from a real format string, generate a fake (aka "intermediate") format string with special control
+characters that will eventually be given to moment for formatting, and then post-processed.
+*/
+function buildFakeFormatString(chunks) {
+ var parts = [];
+ var i;
+ var chunk;
+ for (i = 0; i < chunks.length; i++) {
+ chunk = chunks[i];
+ if (typeof chunk === 'string') {
+ parts.push('[' + chunk + ']');
+ }
+ else if (chunk.token) {
+ if (chunk.token in specialTokens) {
+ parts.push(SPECIAL_TOKEN_MARKER + // useful during post-processing
+ '[' + chunk.token + ']' // preserve as literal text
+ );
+ }
+ else {
+ parts.push(chunk.token); // unprotected text implies a format string
+ }
+ }
+ else if (chunk.maybe) {
+ parts.push(MAYBE_MARKER + // useful during post-processing
+ buildFakeFormatString(chunk.maybe) +
+ MAYBE_MARKER);
+ }
+ }
+ return parts.join(PART_SEPARATOR);
+}
+/*
+Given parsed chunks from a real formatting string, generates an array of unit strings (like "day") that indicate
+in which regard two dates must be similar in order to share range formatting text.
+The `chunks` can be nested (because of "maybe" chunks), however, the returned array will be flat.
+*/
+function buildSameUnits(chunks) {
+ var units = [];
+ var i;
+ var chunk;
+ var tokenInfo;
+ for (i = 0; i < chunks.length; i++) {
+ chunk = chunks[i];
+ if (chunk.token) {
+ tokenInfo = largeTokenMap[chunk.token.charAt(0)];
+ units.push(tokenInfo ? tokenInfo.unit : 'second'); // default to a very strict same-second
+ }
+ else if (chunk.maybe) {
+ units.push.apply(units, // append
+ buildSameUnits(chunk.maybe));
+ }
+ else {
+ units.push(null);
+ }
+ }
+ return units;
+}
+// Rendering to text
+// ---------------------------------------------------------------------------------------------------------------------
+/*
+Formats a date with a fake format string, post-processes the control characters, then returns.
+*/
+function renderFakeFormatString(fakeFormatString, date) {
+ return processMaybeMarkers(renderFakeFormatStringParts(fakeFormatString, date).join(''));
+}
+/*
+Formats a date into parts that will have been post-processed, EXCEPT for the "maybe" markers.
+*/
+function renderFakeFormatStringParts(fakeFormatString, date) {
+ var parts = [];
+ var fakeRender = moment_ext_1.oldMomentFormat(date, fakeFormatString);
+ var fakeParts = fakeRender.split(PART_SEPARATOR);
+ var i;
+ var fakePart;
+ for (i = 0; i < fakeParts.length; i++) {
+ fakePart = fakeParts[i];
+ if (fakePart.charAt(0) === SPECIAL_TOKEN_MARKER) {
+ parts.push(
+ // the literal string IS the token's name.
+ // call special token's registered function.
+ specialTokens[fakePart.substring(1)](date));
+ }
+ else {
+ parts.push(fakePart);
+ }
+ }
+ return parts;
+}
+/*
+Accepts an almost-finally-formatted string and processes the "maybe" control characters, returning a new string.
+*/
+function processMaybeMarkers(s) {
+ return s.replace(MAYBE_REGEXP, function (m0, m1) {
+ if (m1.match(/[1-9]/)) {
+ return m1;
+ }
+ else {
+ return '';
+ }
+ });
+}
+// Misc Utils
+// -------------------------------------------------------------------------------------------------
+/*
+Returns a unit string, either 'year', 'month', 'day', or null for the most granular formatting token in the string.
+*/
+function queryMostGranularFormatUnit(formatStr) {
+ var chunks = chunkFormatString(formatStr);
+ var i;
+ var chunk;
+ var candidate;
+ var best;
+ for (i = 0; i < chunks.length; i++) {
+ chunk = chunks[i];
+ if (chunk.token) {
+ candidate = largeTokenMap[chunk.token.charAt(0)];
+ if (candidate) {
+ if (!best || candidate.value > best.value) {
+ best = candidate;
+ }
+ }
+ }
+ }
+ if (best) {
+ return best.unit;
+ }
+ return null;
+}
+exports.queryMostGranularFormatUnit = queryMostGranularFormatUnit;
+
+
+/***/ }),
+/* 48 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Class_1 = __webpack_require__(33);
+var EmitterMixin_1 = __webpack_require__(11);
+var ListenerMixin_1 = __webpack_require__(7);
+var Model = /** @class */ (function (_super) {
+ tslib_1.__extends(Model, _super);
+ function Model() {
+ var _this = _super.call(this) || this;
+ _this._watchers = {};
+ _this._props = {};
+ _this.applyGlobalWatchers();
+ _this.constructed();
+ return _this;
+ }
+ Model.watch = function (name) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ // subclasses should make a masked-copy of the superclass's map
+ // TODO: write test
+ if (!this.prototype.hasOwnProperty('_globalWatchArgs')) {
+ this.prototype._globalWatchArgs = Object.create(this.prototype._globalWatchArgs);
+ }
+ this.prototype._globalWatchArgs[name] = args;
+ };
+ Model.prototype.constructed = function () {
+ // useful for monkeypatching. TODO: BaseClass?
+ };
+ Model.prototype.applyGlobalWatchers = function () {
+ var map = this._globalWatchArgs;
+ var name;
+ for (name in map) {
+ this.watch.apply(this, [name].concat(map[name]));
+ }
+ };
+ Model.prototype.has = function (name) {
+ return name in this._props;
+ };
+ Model.prototype.get = function (name) {
+ if (name === undefined) {
+ return this._props;
+ }
+ return this._props[name];
+ };
+ Model.prototype.set = function (name, val) {
+ var newProps;
+ if (typeof name === 'string') {
+ newProps = {};
+ newProps[name] = val === undefined ? null : val;
+ }
+ else {
+ newProps = name;
+ }
+ this.setProps(newProps);
+ };
+ Model.prototype.reset = function (newProps) {
+ var oldProps = this._props;
+ var changeset = {}; // will have undefined's to signal unsets
+ var name;
+ for (name in oldProps) {
+ changeset[name] = undefined;
+ }
+ for (name in newProps) {
+ changeset[name] = newProps[name];
+ }
+ this.setProps(changeset);
+ };
+ Model.prototype.unset = function (name) {
+ var newProps = {};
+ var names;
+ var i;
+ if (typeof name === 'string') {
+ names = [name];
+ }
+ else {
+ names = name;
+ }
+ for (i = 0; i < names.length; i++) {
+ newProps[names[i]] = undefined;
+ }
+ this.setProps(newProps);
+ };
+ Model.prototype.setProps = function (newProps) {
+ var changedProps = {};
+ var changedCnt = 0;
+ var name;
+ var val;
+ for (name in newProps) {
+ val = newProps[name];
+ // a change in value?
+ // if an object, don't check equality, because might have been mutated internally.
+ // TODO: eventually enforce immutability.
+ if (typeof val === 'object' ||
+ val !== this._props[name]) {
+ changedProps[name] = val;
+ changedCnt++;
+ }
+ }
+ if (changedCnt) {
+ this.trigger('before:batchChange', changedProps);
+ for (name in changedProps) {
+ val = changedProps[name];
+ this.trigger('before:change', name, val);
+ this.trigger('before:change:' + name, val);
+ }
+ for (name in changedProps) {
+ val = changedProps[name];
+ if (val === undefined) {
+ delete this._props[name];
+ }
+ else {
+ this._props[name] = val;
+ }
+ this.trigger('change:' + name, val);
+ this.trigger('change', name, val);
+ }
+ this.trigger('batchChange', changedProps);
+ }
+ };
+ Model.prototype.watch = function (name, depList, startFunc, stopFunc) {
+ var _this = this;
+ this.unwatch(name);
+ this._watchers[name] = this._watchDeps(depList, function (deps) {
+ var res = startFunc.call(_this, deps);
+ if (res && res.then) {
+ _this.unset(name); // put in an unset state while resolving
+ res.then(function (val) {
+ _this.set(name, val);
+ });
+ }
+ else {
+ _this.set(name, res);
+ }
+ }, function (deps) {
+ _this.unset(name);
+ if (stopFunc) {
+ stopFunc.call(_this, deps);
+ }
+ });
+ };
+ Model.prototype.unwatch = function (name) {
+ var watcher = this._watchers[name];
+ if (watcher) {
+ delete this._watchers[name];
+ watcher.teardown();
+ }
+ };
+ Model.prototype._watchDeps = function (depList, startFunc, stopFunc) {
+ var _this = this;
+ var queuedChangeCnt = 0;
+ var depCnt = depList.length;
+ var satisfyCnt = 0;
+ var values = {}; // what's passed as the `deps` arguments
+ var bindTuples = []; // array of [ eventName, handlerFunc ] arrays
+ var isCallingStop = false;
+ var onBeforeDepChange = function (depName, val, isOptional) {
+ queuedChangeCnt++;
+ if (queuedChangeCnt === 1) {
+ if (satisfyCnt === depCnt) {
+ isCallingStop = true;
+ stopFunc(values);
+ isCallingStop = false;
+ }
+ }
+ };
+ var onDepChange = function (depName, val, isOptional) {
+ if (val === undefined) {
+ // required dependency that was previously set?
+ if (!isOptional && values[depName] !== undefined) {
+ satisfyCnt--;
+ }
+ delete values[depName];
+ }
+ else {
+ // required dependency that was previously unset?
+ if (!isOptional && values[depName] === undefined) {
+ satisfyCnt++;
+ }
+ values[depName] = val;
+ }
+ queuedChangeCnt--;
+ if (!queuedChangeCnt) {
+ // now finally satisfied or satisfied all along?
+ if (satisfyCnt === depCnt) {
+ // if the stopFunc initiated another value change, ignore it.
+ // it will be processed by another change event anyway.
+ if (!isCallingStop) {
+ startFunc(values);
+ }
+ }
+ }
+ };
+ // intercept for .on() that remembers handlers
+ var bind = function (eventName, handler) {
+ _this.on(eventName, handler);
+ bindTuples.push([eventName, handler]);
+ };
+ // listen to dependency changes
+ depList.forEach(function (depName) {
+ var isOptional = false;
+ if (depName.charAt(0) === '?') {
+ depName = depName.substring(1);
+ isOptional = true;
+ }
+ bind('before:change:' + depName, function (val) {
+ onBeforeDepChange(depName, val, isOptional);
+ });
+ bind('change:' + depName, function (val) {
+ onDepChange(depName, val, isOptional);
+ });
+ });
+ // process current dependency values
+ depList.forEach(function (depName) {
+ var isOptional = false;
+ if (depName.charAt(0) === '?') {
+ depName = depName.substring(1);
+ isOptional = true;
+ }
+ if (_this.has(depName)) {
+ values[depName] = _this.get(depName);
+ satisfyCnt++;
+ }
+ else if (isOptional) {
+ satisfyCnt++;
+ }
+ });
+ // initially satisfied
+ if (satisfyCnt === depCnt) {
+ startFunc(values);
+ }
+ return {
+ teardown: function () {
+ // remove all handlers
+ for (var i = 0; i < bindTuples.length; i++) {
+ _this.off(bindTuples[i][0], bindTuples[i][1]);
+ }
+ bindTuples = null;
+ // was satisfied, so call stopFunc
+ if (satisfyCnt === depCnt) {
+ stopFunc();
+ }
+ },
+ flash: function () {
+ if (satisfyCnt === depCnt) {
+ stopFunc();
+ startFunc(values);
+ }
+ }
+ };
+ };
+ Model.prototype.flash = function (name) {
+ var watcher = this._watchers[name];
+ if (watcher) {
+ watcher.flash();
+ }
+ };
+ return Model;
+}(Class_1.default));
+exports.default = Model;
+Model.prototype._globalWatchArgs = {}; // mutation protection in Model.watch
+EmitterMixin_1.default.mixInto(Model);
+ListenerMixin_1.default.mixInto(Model);
+
+
+/***/ }),
+/* 49 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var SingleEventDef_1 = __webpack_require__(13);
+var RecurringEventDef_1 = __webpack_require__(210);
+exports.default = {
+ parse: function (eventInput, source) {
+ if (util_1.isTimeString(eventInput.start) || moment.isDuration(eventInput.start) ||
+ util_1.isTimeString(eventInput.end) || moment.isDuration(eventInput.end)) {
+ return RecurringEventDef_1.default.parse(eventInput, source);
+ }
+ else {
+ return SingleEventDef_1.default.parse(eventInput, source);
+ }
+ }
+};
+
+
+/***/ }),
+/* 50 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var util_1 = __webpack_require__(4);
+var EventDateProfile_1 = __webpack_require__(17);
+var EventDefDateMutation = /** @class */ (function () {
+ function EventDefDateMutation() {
+ this.clearEnd = false;
+ this.forceTimed = false;
+ this.forceAllDay = false;
+ }
+ EventDefDateMutation.createFromDiff = function (dateProfile0, dateProfile1, largeUnit) {
+ var clearEnd = dateProfile0.end && !dateProfile1.end;
+ var forceTimed = dateProfile0.isAllDay() && !dateProfile1.isAllDay();
+ var forceAllDay = !dateProfile0.isAllDay() && dateProfile1.isAllDay();
+ var dateDelta;
+ var endDiff;
+ var endDelta;
+ var mutation;
+ // subtracts the dates in the appropriate way, returning a duration
+ function subtractDates(date1, date0) {
+ if (largeUnit) {
+ return util_1.diffByUnit(date1, date0, largeUnit); // poorly named
+ }
+ else if (dateProfile1.isAllDay()) {
+ return util_1.diffDay(date1, date0); // poorly named
+ }
+ else {
+ return util_1.diffDayTime(date1, date0); // poorly named
+ }
+ }
+ dateDelta = subtractDates(dateProfile1.start, dateProfile0.start);
+ if (dateProfile1.end) {
+ // use unzonedRanges because dateProfile0.end might be null
+ endDiff = subtractDates(dateProfile1.unzonedRange.getEnd(), dateProfile0.unzonedRange.getEnd());
+ endDelta = endDiff.subtract(dateDelta);
+ }
+ mutation = new EventDefDateMutation();
+ mutation.clearEnd = clearEnd;
+ mutation.forceTimed = forceTimed;
+ mutation.forceAllDay = forceAllDay;
+ mutation.setDateDelta(dateDelta);
+ mutation.setEndDelta(endDelta);
+ return mutation;
+ };
+ /*
+ returns an undo function.
+ */
+ EventDefDateMutation.prototype.buildNewDateProfile = function (eventDateProfile, calendar) {
+ var start = eventDateProfile.start.clone();
+ var end = null;
+ var shouldRezone = false;
+ if (eventDateProfile.end && !this.clearEnd) {
+ end = eventDateProfile.end.clone();
+ }
+ else if (this.endDelta && !end) {
+ end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ }
+ if (this.forceTimed) {
+ shouldRezone = true;
+ if (!start.hasTime()) {
+ start.time(0);
+ }
+ if (end && !end.hasTime()) {
+ end.time(0);
+ }
+ }
+ else if (this.forceAllDay) {
+ if (start.hasTime()) {
+ start.stripTime();
+ }
+ if (end && end.hasTime()) {
+ end.stripTime();
+ }
+ }
+ if (this.dateDelta) {
+ shouldRezone = true;
+ start.add(this.dateDelta);
+ if (end) {
+ end.add(this.dateDelta);
+ }
+ }
+ // do this before adding startDelta to start, so we can work off of start
+ if (this.endDelta) {
+ shouldRezone = true;
+ end.add(this.endDelta);
+ }
+ if (this.startDelta) {
+ shouldRezone = true;
+ start.add(this.startDelta);
+ }
+ if (shouldRezone) {
+ start = calendar.applyTimezone(start);
+ if (end) {
+ end = calendar.applyTimezone(end);
+ }
+ }
+ // TODO: okay to access calendar option?
+ if (!end && calendar.opt('forceEventDuration')) {
+ end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ }
+ return new EventDateProfile_1.default(start, end, calendar);
+ };
+ EventDefDateMutation.prototype.setDateDelta = function (dateDelta) {
+ if (dateDelta && dateDelta.valueOf()) {
+ this.dateDelta = dateDelta;
+ }
+ else {
+ this.dateDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.setStartDelta = function (startDelta) {
+ if (startDelta && startDelta.valueOf()) {
+ this.startDelta = startDelta;
+ }
+ else {
+ this.startDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.setEndDelta = function (endDelta) {
+ if (endDelta && endDelta.valueOf()) {
+ this.endDelta = endDelta;
+ }
+ else {
+ this.endDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.isEmpty = function () {
+ return !this.clearEnd && !this.forceTimed && !this.forceAllDay &&
+ !this.dateDelta && !this.startDelta && !this.endDelta;
+ };
+ return EventDefDateMutation;
+}());
+exports.default = EventDefDateMutation;
+
+
+/***/ }),
+/* 51 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var StandardTheme_1 = __webpack_require__(213);
+var JqueryUiTheme_1 = __webpack_require__(214);
+var themeClassHash = {};
+function defineThemeSystem(themeName, themeClass) {
+ themeClassHash[themeName] = themeClass;
+}
+exports.defineThemeSystem = defineThemeSystem;
+function getThemeSystemClass(themeSetting) {
+ if (!themeSetting) {
+ return StandardTheme_1.default;
+ }
+ else if (themeSetting === true) {
+ return JqueryUiTheme_1.default;
+ }
+ else {
+ return themeClassHash[themeSetting];
+ }
+}
+exports.getThemeSystemClass = getThemeSystemClass;
+
+
+/***/ }),
+/* 52 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Promise_1 = __webpack_require__(20);
+var EventSource_1 = __webpack_require__(6);
+var SingleEventDef_1 = __webpack_require__(13);
+var ArrayEventSource = /** @class */ (function (_super) {
+ tslib_1.__extends(ArrayEventSource, _super);
+ function ArrayEventSource(calendar) {
+ var _this = _super.call(this, calendar) || this;
+ _this.eventDefs = []; // for if setRawEventDefs is never called
+ return _this;
+ }
+ ArrayEventSource.parse = function (rawInput, calendar) {
+ var rawProps;
+ // normalize raw input
+ if ($.isArray(rawInput.events)) {
+ rawProps = rawInput;
+ }
+ else if ($.isArray(rawInput)) {
+ rawProps = { events: rawInput };
+ }
+ if (rawProps) {
+ return EventSource_1.default.parse.call(this, rawProps, calendar);
+ }
+ return false;
+ };
+ ArrayEventSource.prototype.setRawEventDefs = function (rawEventDefs) {
+ this.rawEventDefs = rawEventDefs;
+ this.eventDefs = this.parseEventDefs(rawEventDefs);
+ };
+ ArrayEventSource.prototype.fetch = function (start, end, timezone) {
+ var eventDefs = this.eventDefs;
+ var i;
+ if (this.currentTimezone != null &&
+ this.currentTimezone !== timezone) {
+ for (i = 0; i < eventDefs.length; i++) {
+ if (eventDefs[i] instanceof SingleEventDef_1.default) {
+ eventDefs[i].rezone();
+ }
+ }
+ }
+ this.currentTimezone = timezone;
+ return Promise_1.default.resolve(eventDefs);
+ };
+ ArrayEventSource.prototype.addEventDef = function (eventDef) {
+ this.eventDefs.push(eventDef);
+ };
+ /*
+ eventDefId already normalized to a string
+ */
+ ArrayEventSource.prototype.removeEventDefsById = function (eventDefId) {
+ return util_1.removeMatching(this.eventDefs, function (eventDef) {
+ return eventDef.id === eventDefId;
+ });
+ };
+ ArrayEventSource.prototype.removeAllEventDefs = function () {
+ this.eventDefs = [];
+ };
+ ArrayEventSource.prototype.getPrimitive = function () {
+ return this.rawEventDefs;
+ };
+ ArrayEventSource.prototype.applyManualStandardProps = function (rawProps) {
+ var superSuccess = _super.prototype.applyManualStandardProps.call(this, rawProps);
+ this.setRawEventDefs(rawProps.events);
+ return superSuccess;
+ };
+ return ArrayEventSource;
+}(EventSource_1.default));
+exports.default = ArrayEventSource;
+ArrayEventSource.defineStandardProps({
+ events: false // don't automatically transfer
+});
+
+
+/***/ }),
+/* 53 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+/*
+A cache for the left/right/top/bottom/width/height values for one or more elements.
+Works with both offset (from topleft document) and position (from offsetParent).
+
+options:
+- els
+- isHorizontal
+- isVertical
+*/
+var CoordCache = /** @class */ (function () {
+ function CoordCache(options) {
+ this.isHorizontal = false; // whether to query for left/right/width
+ this.isVertical = false; // whether to query for top/bottom/height
+ this.els = $(options.els);
+ this.isHorizontal = options.isHorizontal;
+ this.isVertical = options.isVertical;
+ this.forcedOffsetParentEl = options.offsetParent ? $(options.offsetParent) : null;
+ }
+ // Queries the els for coordinates and stores them.
+ // Call this method before using and of the get* methods below.
+ CoordCache.prototype.build = function () {
+ var offsetParentEl = this.forcedOffsetParentEl;
+ if (!offsetParentEl && this.els.length > 0) {
+ offsetParentEl = this.els.eq(0).offsetParent();
+ }
+ this.origin = offsetParentEl ?
+ offsetParentEl.offset() :
+ null;
+ this.boundingRect = this.queryBoundingRect();
+ if (this.isHorizontal) {
+ this.buildElHorizontals();
+ }
+ if (this.isVertical) {
+ this.buildElVerticals();
+ }
+ };
+ // Destroys all internal data about coordinates, freeing memory
+ CoordCache.prototype.clear = function () {
+ this.origin = null;
+ this.boundingRect = null;
+ this.lefts = null;
+ this.rights = null;
+ this.tops = null;
+ this.bottoms = null;
+ };
+ // When called, if coord caches aren't built, builds them
+ CoordCache.prototype.ensureBuilt = function () {
+ if (!this.origin) {
+ this.build();
+ }
+ };
+ // Populates the left/right internal coordinate arrays
+ CoordCache.prototype.buildElHorizontals = function () {
+ var lefts = [];
+ var rights = [];
+ this.els.each(function (i, node) {
+ var el = $(node);
+ var left = el.offset().left;
+ var width = el.outerWidth();
+ lefts.push(left);
+ rights.push(left + width);
+ });
+ this.lefts = lefts;
+ this.rights = rights;
+ };
+ // Populates the top/bottom internal coordinate arrays
+ CoordCache.prototype.buildElVerticals = function () {
+ var tops = [];
+ var bottoms = [];
+ this.els.each(function (i, node) {
+ var el = $(node);
+ var top = el.offset().top;
+ var height = el.outerHeight();
+ tops.push(top);
+ bottoms.push(top + height);
+ });
+ this.tops = tops;
+ this.bottoms = bottoms;
+ };
+ // Given a left offset (from document left), returns the index of the el that it horizontally intersects.
+ // If no intersection is made, returns undefined.
+ CoordCache.prototype.getHorizontalIndex = function (leftOffset) {
+ this.ensureBuilt();
+ var lefts = this.lefts;
+ var rights = this.rights;
+ var len = lefts.length;
+ var i;
+ for (i = 0; i < len; i++) {
+ if (leftOffset >= lefts[i] && leftOffset < rights[i]) {
+ return i;
+ }
+ }
+ };
+ // Given a top offset (from document top), returns the index of the el that it vertically intersects.
+ // If no intersection is made, returns undefined.
+ CoordCache.prototype.getVerticalIndex = function (topOffset) {
+ this.ensureBuilt();
+ var tops = this.tops;
+ var bottoms = this.bottoms;
+ var len = tops.length;
+ var i;
+ for (i = 0; i < len; i++) {
+ if (topOffset >= tops[i] && topOffset < bottoms[i]) {
+ return i;
+ }
+ }
+ };
+ // Gets the left offset (from document left) of the element at the given index
+ CoordCache.prototype.getLeftOffset = function (leftIndex) {
+ this.ensureBuilt();
+ return this.lefts[leftIndex];
+ };
+ // Gets the left position (from offsetParent left) of the element at the given index
+ CoordCache.prototype.getLeftPosition = function (leftIndex) {
+ this.ensureBuilt();
+ return this.lefts[leftIndex] - this.origin.left;
+ };
+ // Gets the right offset (from document left) of the element at the given index.
+ // This value is NOT relative to the document's right edge, like the CSS concept of "right" would be.
+ CoordCache.prototype.getRightOffset = function (leftIndex) {
+ this.ensureBuilt();
+ return this.rights[leftIndex];
+ };
+ // Gets the right position (from offsetParent left) of the element at the given index.
+ // This value is NOT relative to the offsetParent's right edge, like the CSS concept of "right" would be.
+ CoordCache.prototype.getRightPosition = function (leftIndex) {
+ this.ensureBuilt();
+ return this.rights[leftIndex] - this.origin.left;
+ };
+ // Gets the width of the element at the given index
+ CoordCache.prototype.getWidth = function (leftIndex) {
+ this.ensureBuilt();
+ return this.rights[leftIndex] - this.lefts[leftIndex];
+ };
+ // Gets the top offset (from document top) of the element at the given index
+ CoordCache.prototype.getTopOffset = function (topIndex) {
+ this.ensureBuilt();
+ return this.tops[topIndex];
+ };
+ // Gets the top position (from offsetParent top) of the element at the given position
+ CoordCache.prototype.getTopPosition = function (topIndex) {
+ this.ensureBuilt();
+ return this.tops[topIndex] - this.origin.top;
+ };
+ // Gets the bottom offset (from the document top) of the element at the given index.
+ // This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+ CoordCache.prototype.getBottomOffset = function (topIndex) {
+ this.ensureBuilt();
+ return this.bottoms[topIndex];
+ };
+ // Gets the bottom position (from the offsetParent top) of the element at the given index.
+ // This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+ CoordCache.prototype.getBottomPosition = function (topIndex) {
+ this.ensureBuilt();
+ return this.bottoms[topIndex] - this.origin.top;
+ };
+ // Gets the height of the element at the given index
+ CoordCache.prototype.getHeight = function (topIndex) {
+ this.ensureBuilt();
+ return this.bottoms[topIndex] - this.tops[topIndex];
+ };
+ // Bounding Rect
+ // TODO: decouple this from CoordCache
+ // Compute and return what the elements' bounding rectangle is, from the user's perspective.
+ // Right now, only returns a rectangle if constrained by an overflow:scroll element.
+ // Returns null if there are no elements
+ CoordCache.prototype.queryBoundingRect = function () {
+ var scrollParentEl;
+ if (this.els.length > 0) {
+ scrollParentEl = util_1.getScrollParent(this.els.eq(0));
+ if (!scrollParentEl.is(document)) {
+ return util_1.getClientRect(scrollParentEl);
+ }
+ }
+ return null;
+ };
+ CoordCache.prototype.isPointInBounds = function (leftOffset, topOffset) {
+ return this.isLeftInBounds(leftOffset) && this.isTopInBounds(topOffset);
+ };
+ CoordCache.prototype.isLeftInBounds = function (leftOffset) {
+ return !this.boundingRect || (leftOffset >= this.boundingRect.left && leftOffset < this.boundingRect.right);
+ };
+ CoordCache.prototype.isTopInBounds = function (topOffset) {
+ return !this.boundingRect || (topOffset >= this.boundingRect.top && topOffset < this.boundingRect.bottom);
+ };
+ return CoordCache;
+}());
+exports.default = CoordCache;
+
+
+/***/ }),
+/* 54 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ListenerMixin_1 = __webpack_require__(7);
+var GlobalEmitter_1 = __webpack_require__(21);
+/* Tracks a drag's mouse movement, firing various handlers
+----------------------------------------------------------------------------------------------------------------------*/
+// TODO: use Emitter
+var DragListener = /** @class */ (function () {
+ function DragListener(options) {
+ this.isInteracting = false;
+ this.isDistanceSurpassed = false;
+ this.isDelayEnded = false;
+ this.isDragging = false;
+ this.isTouch = false;
+ this.isGeneric = false; // initiated by 'dragstart' (jqui)
+ this.shouldCancelTouchScroll = true;
+ this.scrollAlwaysKills = false;
+ this.isAutoScroll = false;
+ // defaults
+ this.scrollSensitivity = 30; // pixels from edge for scrolling to start
+ this.scrollSpeed = 200; // pixels per second, at maximum speed
+ this.scrollIntervalMs = 50; // millisecond wait between scroll increment
+ this.options = options || {};
+ }
+ // Interaction (high-level)
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.startInteraction = function (ev, extraOptions) {
+ if (extraOptions === void 0) { extraOptions = {}; }
+ if (ev.type === 'mousedown') {
+ if (GlobalEmitter_1.default.get().shouldIgnoreMouse()) {
+ return;
+ }
+ else if (!util_1.isPrimaryMouseButton(ev)) {
+ return;
+ }
+ else {
+ ev.preventDefault(); // prevents native selection in most browsers
+ }
+ }
+ if (!this.isInteracting) {
+ // process options
+ this.delay = util_1.firstDefined(extraOptions.delay, this.options.delay, 0);
+ this.minDistance = util_1.firstDefined(extraOptions.distance, this.options.distance, 0);
+ this.subjectEl = this.options.subjectEl;
+ util_1.preventSelection($('body'));
+ this.isInteracting = true;
+ this.isTouch = util_1.getEvIsTouch(ev);
+ this.isGeneric = ev.type === 'dragstart';
+ this.isDelayEnded = false;
+ this.isDistanceSurpassed = false;
+ this.originX = util_1.getEvX(ev);
+ this.originY = util_1.getEvY(ev);
+ this.scrollEl = util_1.getScrollParent($(ev.target));
+ this.bindHandlers();
+ this.initAutoScroll();
+ this.handleInteractionStart(ev);
+ this.startDelay(ev);
+ if (!this.minDistance) {
+ this.handleDistanceSurpassed(ev);
+ }
+ }
+ };
+ DragListener.prototype.handleInteractionStart = function (ev) {
+ this.trigger('interactionStart', ev);
+ };
+ DragListener.prototype.endInteraction = function (ev, isCancelled) {
+ if (this.isInteracting) {
+ this.endDrag(ev);
+ if (this.delayTimeoutId) {
+ clearTimeout(this.delayTimeoutId);
+ this.delayTimeoutId = null;
+ }
+ this.destroyAutoScroll();
+ this.unbindHandlers();
+ this.isInteracting = false;
+ this.handleInteractionEnd(ev, isCancelled);
+ util_1.allowSelection($('body'));
+ }
+ };
+ DragListener.prototype.handleInteractionEnd = function (ev, isCancelled) {
+ this.trigger('interactionEnd', ev, isCancelled || false);
+ };
+ // Binding To DOM
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.bindHandlers = function () {
+ // some browsers (Safari in iOS 10) don't allow preventDefault on touch events that are bound after touchstart,
+ // so listen to the GlobalEmitter singleton, which is always bound, instead of the document directly.
+ var globalEmitter = GlobalEmitter_1.default.get();
+ if (this.isGeneric) {
+ this.listenTo($(document), {
+ drag: this.handleMove,
+ dragstop: this.endInteraction
+ });
+ }
+ else if (this.isTouch) {
+ this.listenTo(globalEmitter, {
+ touchmove: this.handleTouchMove,
+ touchend: this.endInteraction,
+ scroll: this.handleTouchScroll
+ });
+ }
+ else {
+ this.listenTo(globalEmitter, {
+ mousemove: this.handleMouseMove,
+ mouseup: this.endInteraction
+ });
+ }
+ this.listenTo(globalEmitter, {
+ selectstart: util_1.preventDefault,
+ contextmenu: util_1.preventDefault // long taps would open menu on Chrome dev tools
+ });
+ };
+ DragListener.prototype.unbindHandlers = function () {
+ this.stopListeningTo(GlobalEmitter_1.default.get());
+ this.stopListeningTo($(document)); // for isGeneric
+ };
+ // Drag (high-level)
+ // -----------------------------------------------------------------------------------------------------------------
+ // extraOptions ignored if drag already started
+ DragListener.prototype.startDrag = function (ev, extraOptions) {
+ this.startInteraction(ev, extraOptions); // ensure interaction began
+ if (!this.isDragging) {
+ this.isDragging = true;
+ this.handleDragStart(ev);
+ }
+ };
+ DragListener.prototype.handleDragStart = function (ev) {
+ this.trigger('dragStart', ev);
+ };
+ DragListener.prototype.handleMove = function (ev) {
+ var dx = util_1.getEvX(ev) - this.originX;
+ var dy = util_1.getEvY(ev) - this.originY;
+ var minDistance = this.minDistance;
+ var distanceSq; // current distance from the origin, squared
+ if (!this.isDistanceSurpassed) {
+ distanceSq = dx * dx + dy * dy;
+ if (distanceSq >= minDistance * minDistance) {
+ this.handleDistanceSurpassed(ev);
+ }
+ }
+ if (this.isDragging) {
+ this.handleDrag(dx, dy, ev);
+ }
+ };
+ // Called while the mouse is being moved and when we know a legitimate drag is taking place
+ DragListener.prototype.handleDrag = function (dx, dy, ev) {
+ this.trigger('drag', dx, dy, ev);
+ this.updateAutoScroll(ev); // will possibly cause scrolling
+ };
+ DragListener.prototype.endDrag = function (ev) {
+ if (this.isDragging) {
+ this.isDragging = false;
+ this.handleDragEnd(ev);
+ }
+ };
+ DragListener.prototype.handleDragEnd = function (ev) {
+ this.trigger('dragEnd', ev);
+ };
+ // Delay
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.startDelay = function (initialEv) {
+ var _this = this;
+ if (this.delay) {
+ this.delayTimeoutId = setTimeout(function () {
+ _this.handleDelayEnd(initialEv);
+ }, this.delay);
+ }
+ else {
+ this.handleDelayEnd(initialEv);
+ }
+ };
+ DragListener.prototype.handleDelayEnd = function (initialEv) {
+ this.isDelayEnded = true;
+ if (this.isDistanceSurpassed) {
+ this.startDrag(initialEv);
+ }
+ };
+ // Distance
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.handleDistanceSurpassed = function (ev) {
+ this.isDistanceSurpassed = true;
+ if (this.isDelayEnded) {
+ this.startDrag(ev);
+ }
+ };
+ // Mouse / Touch
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.handleTouchMove = function (ev) {
+ // prevent inertia and touchmove-scrolling while dragging
+ if (this.isDragging && this.shouldCancelTouchScroll) {
+ ev.preventDefault();
+ }
+ this.handleMove(ev);
+ };
+ DragListener.prototype.handleMouseMove = function (ev) {
+ this.handleMove(ev);
+ };
+ // Scrolling (unrelated to auto-scroll)
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.handleTouchScroll = function (ev) {
+ // if the drag is being initiated by touch, but a scroll happens before
+ // the drag-initiating delay is over, cancel the drag
+ if (!this.isDragging || this.scrollAlwaysKills) {
+ this.endInteraction(ev, true); // isCancelled=true
+ }
+ };
+ // Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ // Triggers a callback. Calls a function in the option hash of the same name.
+ // Arguments beyond the first `name` are forwarded on.
+ DragListener.prototype.trigger = function (name) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ if (this.options[name]) {
+ this.options[name].apply(this, args);
+ }
+ // makes _methods callable by event name. TODO: kill this
+ if (this['_' + name]) {
+ this['_' + name].apply(this, args);
+ }
+ };
+ // Auto-scroll
+ // -----------------------------------------------------------------------------------------------------------------
+ DragListener.prototype.initAutoScroll = function () {
+ var scrollEl = this.scrollEl;
+ this.isAutoScroll =
+ this.options.scroll &&
+ scrollEl &&
+ !scrollEl.is(window) &&
+ !scrollEl.is(document);
+ if (this.isAutoScroll) {
+ // debounce makes sure rapid calls don't happen
+ this.listenTo(scrollEl, 'scroll', util_1.debounce(this.handleDebouncedScroll, 100));
+ }
+ };
+ DragListener.prototype.destroyAutoScroll = function () {
+ this.endAutoScroll(); // kill any animation loop
+ // remove the scroll handler if there is a scrollEl
+ if (this.isAutoScroll) {
+ this.stopListeningTo(this.scrollEl, 'scroll'); // will probably get removed by unbindHandlers too :(
+ }
+ };
+ // Computes and stores the bounding rectangle of scrollEl
+ DragListener.prototype.computeScrollBounds = function () {
+ if (this.isAutoScroll) {
+ this.scrollBounds = util_1.getOuterRect(this.scrollEl);
+ // TODO: use getClientRect in future. but prevents auto scrolling when on top of scrollbars
+ }
+ };
+ // Called when the dragging is in progress and scrolling should be updated
+ DragListener.prototype.updateAutoScroll = function (ev) {
+ var sensitivity = this.scrollSensitivity;
+ var bounds = this.scrollBounds;
+ var topCloseness;
+ var bottomCloseness;
+ var leftCloseness;
+ var rightCloseness;
+ var topVel = 0;
+ var leftVel = 0;
+ if (bounds) {
+ // compute closeness to edges. valid range is from 0.0 - 1.0
+ topCloseness = (sensitivity - (util_1.getEvY(ev) - bounds.top)) / sensitivity;
+ bottomCloseness = (sensitivity - (bounds.bottom - util_1.getEvY(ev))) / sensitivity;
+ leftCloseness = (sensitivity - (util_1.getEvX(ev) - bounds.left)) / sensitivity;
+ rightCloseness = (sensitivity - (bounds.right - util_1.getEvX(ev))) / sensitivity;
+ // translate vertical closeness into velocity.
+ // mouse must be completely in bounds for velocity to happen.
+ if (topCloseness >= 0 && topCloseness <= 1) {
+ topVel = topCloseness * this.scrollSpeed * -1; // negative. for scrolling up
+ }
+ else if (bottomCloseness >= 0 && bottomCloseness <= 1) {
+ topVel = bottomCloseness * this.scrollSpeed;
+ }
+ // translate horizontal closeness into velocity
+ if (leftCloseness >= 0 && leftCloseness <= 1) {
+ leftVel = leftCloseness * this.scrollSpeed * -1; // negative. for scrolling left
+ }
+ else if (rightCloseness >= 0 && rightCloseness <= 1) {
+ leftVel = rightCloseness * this.scrollSpeed;
+ }
+ }
+ this.setScrollVel(topVel, leftVel);
+ };
+ // Sets the speed-of-scrolling for the scrollEl
+ DragListener.prototype.setScrollVel = function (topVel, leftVel) {
+ this.scrollTopVel = topVel;
+ this.scrollLeftVel = leftVel;
+ this.constrainScrollVel(); // massages into realistic values
+ // if there is non-zero velocity, and an animation loop hasn't already started, then START
+ if ((this.scrollTopVel || this.scrollLeftVel) && !this.scrollIntervalId) {
+ this.scrollIntervalId = setInterval(util_1.proxy(this, 'scrollIntervalFunc'), // scope to `this`
+ this.scrollIntervalMs);
+ }
+ };
+ // Forces scrollTopVel and scrollLeftVel to be zero if scrolling has already gone all the way
+ DragListener.prototype.constrainScrollVel = function () {
+ var el = this.scrollEl;
+ if (this.scrollTopVel < 0) {
+ if (el.scrollTop() <= 0) {
+ this.scrollTopVel = 0;
+ }
+ }
+ else if (this.scrollTopVel > 0) {
+ if (el.scrollTop() + el[0].clientHeight >= el[0].scrollHeight) {
+ this.scrollTopVel = 0;
+ }
+ }
+ if (this.scrollLeftVel < 0) {
+ if (el.scrollLeft() <= 0) {
+ this.scrollLeftVel = 0;
+ }
+ }
+ else if (this.scrollLeftVel > 0) {
+ if (el.scrollLeft() + el[0].clientWidth >= el[0].scrollWidth) {
+ this.scrollLeftVel = 0;
+ }
+ }
+ };
+ // This function gets called during every iteration of the scrolling animation loop
+ DragListener.prototype.scrollIntervalFunc = function () {
+ var el = this.scrollEl;
+ var frac = this.scrollIntervalMs / 1000; // considering animation frequency, what the vel should be mult'd by
+ // change the value of scrollEl's scroll
+ if (this.scrollTopVel) {
+ el.scrollTop(el.scrollTop() + this.scrollTopVel * frac);
+ }
+ if (this.scrollLeftVel) {
+ el.scrollLeft(el.scrollLeft() + this.scrollLeftVel * frac);
+ }
+ this.constrainScrollVel(); // since the scroll values changed, recompute the velocities
+ // if scrolled all the way, which causes the vels to be zero, stop the animation loop
+ if (!this.scrollTopVel && !this.scrollLeftVel) {
+ this.endAutoScroll();
+ }
+ };
+ // Kills any existing scrolling animation loop
+ DragListener.prototype.endAutoScroll = function () {
+ if (this.scrollIntervalId) {
+ clearInterval(this.scrollIntervalId);
+ this.scrollIntervalId = null;
+ this.handleScrollEnd();
+ }
+ };
+ // Get called when the scrollEl is scrolled (NOTE: this is delayed via debounce)
+ DragListener.prototype.handleDebouncedScroll = function () {
+ // recompute all coordinates, but *only* if this is *not* part of our scrolling animation
+ if (!this.scrollIntervalId) {
+ this.handleScrollEnd();
+ }
+ };
+ DragListener.prototype.handleScrollEnd = function () {
+ // Called when scrolling has stopped, whether through auto scroll, or the user scrolling
+ };
+ return DragListener;
+}());
+exports.default = DragListener;
+ListenerMixin_1.default.mixInto(DragListener);
+
+
+/***/ }),
+/* 55 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var Mixin_1 = __webpack_require__(14);
+/*
+A set of rendering and date-related methods for a visual component comprised of one or more rows of day columns.
+Prerequisite: the object being mixed into needs to be a *Grid*
+*/
+var DayTableMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(DayTableMixin, _super);
+ function DayTableMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Populates internal variables used for date calculation and rendering
+ DayTableMixin.prototype.updateDayTable = function () {
+ var t = this;
+ var view = t.view;
+ var calendar = view.calendar;
+ var date = calendar.msToUtcMoment(t.dateProfile.renderUnzonedRange.startMs, true);
+ var end = calendar.msToUtcMoment(t.dateProfile.renderUnzonedRange.endMs, true);
+ var dayIndex = -1;
+ var dayIndices = [];
+ var dayDates = [];
+ var daysPerRow;
+ var firstDay;
+ var rowCnt;
+ while (date.isBefore(end)) {
+ if (view.isHiddenDay(date)) {
+ dayIndices.push(dayIndex + 0.5); // mark that it's between indices
+ }
+ else {
+ dayIndex++;
+ dayIndices.push(dayIndex);
+ dayDates.push(date.clone());
+ }
+ date.add(1, 'days');
+ }
+ if (this.breakOnWeeks) {
+ // count columns until the day-of-week repeats
+ firstDay = dayDates[0].day();
+ for (daysPerRow = 1; daysPerRow < dayDates.length; daysPerRow++) {
+ if (dayDates[daysPerRow].day() === firstDay) {
+ break;
+ }
+ }
+ rowCnt = Math.ceil(dayDates.length / daysPerRow);
+ }
+ else {
+ rowCnt = 1;
+ daysPerRow = dayDates.length;
+ }
+ this.dayDates = dayDates;
+ this.dayIndices = dayIndices;
+ this.daysPerRow = daysPerRow;
+ this.rowCnt = rowCnt;
+ this.updateDayTableCols();
+ };
+ // Computes and assigned the colCnt property and updates any options that may be computed from it
+ DayTableMixin.prototype.updateDayTableCols = function () {
+ this.colCnt = this.computeColCnt();
+ this.colHeadFormat =
+ this.opt('columnHeaderFormat') ||
+ this.opt('columnFormat') || // deprecated
+ this.computeColHeadFormat();
+ };
+ // Determines how many columns there should be in the table
+ DayTableMixin.prototype.computeColCnt = function () {
+ return this.daysPerRow;
+ };
+ // Computes the ambiguously-timed moment for the given cell
+ DayTableMixin.prototype.getCellDate = function (row, col) {
+ return this.dayDates[this.getCellDayIndex(row, col)].clone();
+ };
+ // Computes the ambiguously-timed date range for the given cell
+ DayTableMixin.prototype.getCellRange = function (row, col) {
+ var start = this.getCellDate(row, col);
+ var end = start.clone().add(1, 'days');
+ return { start: start, end: end };
+ };
+ // Returns the number of day cells, chronologically, from the first of the grid (0-based)
+ DayTableMixin.prototype.getCellDayIndex = function (row, col) {
+ return row * this.daysPerRow + this.getColDayIndex(col);
+ };
+ // Returns the numner of day cells, chronologically, from the first cell in *any given row*
+ DayTableMixin.prototype.getColDayIndex = function (col) {
+ if (this.isRTL) {
+ return this.colCnt - 1 - col;
+ }
+ else {
+ return col;
+ }
+ };
+ // Given a date, returns its chronolocial cell-index from the first cell of the grid.
+ // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets.
+ // If before the first offset, returns a negative number.
+ // If after the last offset, returns an offset past the last cell offset.
+ // Only works for *start* dates of cells. Will not work for exclusive end dates for cells.
+ DayTableMixin.prototype.getDateDayIndex = function (date) {
+ var dayIndices = this.dayIndices;
+ var dayOffset = date.diff(this.dayDates[0], 'days');
+ if (dayOffset < 0) {
+ return dayIndices[0] - 1;
+ }
+ else if (dayOffset >= dayIndices.length) {
+ return dayIndices[dayIndices.length - 1] + 1;
+ }
+ else {
+ return dayIndices[dayOffset];
+ }
+ };
+ /* Options
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Computes a default column header formatting string if `colFormat` is not explicitly defined
+ DayTableMixin.prototype.computeColHeadFormat = function () {
+ // if more than one week row, or if there are a lot of columns with not much space,
+ // put just the day numbers will be in each cell
+ if (this.rowCnt > 1 || this.colCnt > 10) {
+ return 'ddd'; // "Sat"
+ }
+ else if (this.colCnt > 1) {
+ return this.opt('dayOfMonthFormat'); // "Sat 12/10"
+ }
+ else {
+ return 'dddd'; // "Saturday"
+ }
+ };
+ /* Slicing
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Slices up a date range into a segment for every week-row it intersects with
+ DayTableMixin.prototype.sliceRangeByRow = function (unzonedRange) {
+ var daysPerRow = this.daysPerRow;
+ var normalRange = this.view.computeDayRange(unzonedRange); // make whole-day range, considering nextDayThreshold
+ var rangeFirst = this.getDateDayIndex(normalRange.start); // inclusive first index
+ var rangeLast = this.getDateDayIndex(normalRange.end.clone().subtract(1, 'days')); // inclusive last index
+ var segs = [];
+ var row;
+ var rowFirst;
+ var rowLast; // inclusive day-index range for current row
+ var segFirst;
+ var segLast; // inclusive day-index range for segment
+ for (row = 0; row < this.rowCnt; row++) {
+ rowFirst = row * daysPerRow;
+ rowLast = rowFirst + daysPerRow - 1;
+ // intersect segment's offset range with the row's
+ segFirst = Math.max(rangeFirst, rowFirst);
+ segLast = Math.min(rangeLast, rowLast);
+ // deal with in-between indices
+ segFirst = Math.ceil(segFirst); // in-between starts round to next cell
+ segLast = Math.floor(segLast); // in-between ends round to prev cell
+ if (segFirst <= segLast) {
+ segs.push({
+ row: row,
+ // normalize to start of row
+ firstRowDayIndex: segFirst - rowFirst,
+ lastRowDayIndex: segLast - rowFirst,
+ // must be matching integers to be the segment's start/end
+ isStart: segFirst === rangeFirst,
+ isEnd: segLast === rangeLast
+ });
+ }
+ }
+ return segs;
+ };
+ // Slices up a date range into a segment for every day-cell it intersects with.
+ // TODO: make more DRY with sliceRangeByRow somehow.
+ DayTableMixin.prototype.sliceRangeByDay = function (unzonedRange) {
+ var daysPerRow = this.daysPerRow;
+ var normalRange = this.view.computeDayRange(unzonedRange); // make whole-day range, considering nextDayThreshold
+ var rangeFirst = this.getDateDayIndex(normalRange.start); // inclusive first index
+ var rangeLast = this.getDateDayIndex(normalRange.end.clone().subtract(1, 'days')); // inclusive last index
+ var segs = [];
+ var row;
+ var rowFirst;
+ var rowLast; // inclusive day-index range for current row
+ var i;
+ var segFirst;
+ var segLast; // inclusive day-index range for segment
+ for (row = 0; row < this.rowCnt; row++) {
+ rowFirst = row * daysPerRow;
+ rowLast = rowFirst + daysPerRow - 1;
+ for (i = rowFirst; i <= rowLast; i++) {
+ // intersect segment's offset range with the row's
+ segFirst = Math.max(rangeFirst, i);
+ segLast = Math.min(rangeLast, i);
+ // deal with in-between indices
+ segFirst = Math.ceil(segFirst); // in-between starts round to next cell
+ segLast = Math.floor(segLast); // in-between ends round to prev cell
+ if (segFirst <= segLast) {
+ segs.push({
+ row: row,
+ // normalize to start of row
+ firstRowDayIndex: segFirst - rowFirst,
+ lastRowDayIndex: segLast - rowFirst,
+ // must be matching integers to be the segment's start/end
+ isStart: segFirst === rangeFirst,
+ isEnd: segLast === rangeLast
+ });
+ }
+ }
+ }
+ return segs;
+ };
+ /* Header Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayTableMixin.prototype.renderHeadHtml = function () {
+ var theme = this.view.calendar.theme;
+ return '' +
+ '<div class="fc-row ' + theme.getClass('headerRow') + '">' +
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ '<thead>' +
+ this.renderHeadTrHtml() +
+ '</thead>' +
+ '</table>' +
+ '</div>';
+ };
+ DayTableMixin.prototype.renderHeadIntroHtml = function () {
+ return this.renderIntroHtml(); // fall back to generic
+ };
+ DayTableMixin.prototype.renderHeadTrHtml = function () {
+ return '' +
+ '<tr>' +
+ (this.isRTL ? '' : this.renderHeadIntroHtml()) +
+ this.renderHeadDateCellsHtml() +
+ (this.isRTL ? this.renderHeadIntroHtml() : '') +
+ '</tr>';
+ };
+ DayTableMixin.prototype.renderHeadDateCellsHtml = function () {
+ var htmls = [];
+ var col;
+ var date;
+ for (col = 0; col < this.colCnt; col++) {
+ date = this.getCellDate(0, col);
+ htmls.push(this.renderHeadDateCellHtml(date));
+ }
+ return htmls.join('');
+ };
+ // TODO: when internalApiVersion, accept an object for HTML attributes
+ // (colspan should be no different)
+ DayTableMixin.prototype.renderHeadDateCellHtml = function (date, colspan, otherAttrs) {
+ var t = this;
+ var view = t.view;
+ var isDateValid = t.dateProfile.activeUnzonedRange.containsDate(date); // TODO: called too frequently. cache somehow.
+ var classNames = [
+ 'fc-day-header',
+ view.calendar.theme.getClass('widgetHeader')
+ ];
+ var innerHtml;
+ if (typeof t.opt('columnHeaderHtml') === 'function') {
+ innerHtml = t.opt('columnHeaderHtml')(date);
+ }
+ else if (typeof t.opt('columnHeaderText') === 'function') {
+ innerHtml = util_1.htmlEscape(t.opt('columnHeaderText')(date));
+ }
+ else {
+ innerHtml = util_1.htmlEscape(date.format(t.colHeadFormat));
+ }
+ // if only one row of days, the classNames on the header can represent the specific days beneath
+ if (t.rowCnt === 1) {
+ classNames = classNames.concat(
+ // includes the day-of-week class
+ // noThemeHighlight=true (don't highlight the header)
+ t.getDayClasses(date, true));
+ }
+ else {
+ classNames.push('fc-' + util_1.dayIDs[date.day()]); // only add the day-of-week class
+ }
+ return '' +
+ '<th class="' + classNames.join(' ') + '"' +
+ ((isDateValid && t.rowCnt) === 1 ?
+ ' data-date="' + date.format('YYYY-MM-DD') + '"' :
+ '') +
+ (colspan > 1 ?
+ ' colspan="' + colspan + '"' :
+ '') +
+ (otherAttrs ?
+ ' ' + otherAttrs :
+ '') +
+ '>' +
+ (isDateValid ?
+ // don't make a link if the heading could represent multiple days, or if there's only one day (forceOff)
+ view.buildGotoAnchorHtml({ date: date, forceOff: t.rowCnt > 1 || t.colCnt === 1 }, innerHtml) :
+ // if not valid, display text, but no link
+ innerHtml) +
+ '</th>';
+ };
+ /* Background Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayTableMixin.prototype.renderBgTrHtml = function (row) {
+ return '' +
+ '<tr>' +
+ (this.isRTL ? '' : this.renderBgIntroHtml(row)) +
+ this.renderBgCellsHtml(row) +
+ (this.isRTL ? this.renderBgIntroHtml(row) : '') +
+ '</tr>';
+ };
+ DayTableMixin.prototype.renderBgIntroHtml = function (row) {
+ return this.renderIntroHtml(); // fall back to generic
+ };
+ DayTableMixin.prototype.renderBgCellsHtml = function (row) {
+ var htmls = [];
+ var col;
+ var date;
+ for (col = 0; col < this.colCnt; col++) {
+ date = this.getCellDate(row, col);
+ htmls.push(this.renderBgCellHtml(date));
+ }
+ return htmls.join('');
+ };
+ DayTableMixin.prototype.renderBgCellHtml = function (date, otherAttrs) {
+ var t = this;
+ var view = t.view;
+ var isDateValid = t.dateProfile.activeUnzonedRange.containsDate(date); // TODO: called too frequently. cache somehow.
+ var classes = t.getDayClasses(date);
+ classes.unshift('fc-day', view.calendar.theme.getClass('widgetContent'));
+ return '<td class="' + classes.join(' ') + '"' +
+ (isDateValid ?
+ ' data-date="' + date.format('YYYY-MM-DD') + '"' : // if date has a time, won't format it
+ '') +
+ (otherAttrs ?
+ ' ' + otherAttrs :
+ '') +
+ '></td>';
+ };
+ /* Generic
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayTableMixin.prototype.renderIntroHtml = function () {
+ // Generates the default HTML intro for any row. User classes should override
+ };
+ // TODO: a generic method for dealing with <tr>, RTL, intro
+ // when increment internalApiVersion
+ // wrapTr (scheduler)
+ /* Utils
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Applies the generic "intro" and "outro" HTML to the given cells.
+ // Intro means the leftmost cell when the calendar is LTR and the rightmost cell when RTL. Vice-versa for outro.
+ DayTableMixin.prototype.bookendCells = function (trEl) {
+ var introHtml = this.renderIntroHtml();
+ if (introHtml) {
+ if (this.isRTL) {
+ trEl.append(introHtml);
+ }
+ else {
+ trEl.prepend(introHtml);
+ }
+ }
+ };
+ return DayTableMixin;
+}(Mixin_1.default));
+exports.default = DayTableMixin;
+
+
+/***/ }),
+/* 56 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var BusinessHourRenderer = /** @class */ (function () {
+ /*
+ component implements:
+ - eventRangesToEventFootprints
+ - eventFootprintsToSegs
+ */
+ function BusinessHourRenderer(component, fillRenderer) {
+ this.component = component;
+ this.fillRenderer = fillRenderer;
+ }
+ BusinessHourRenderer.prototype.render = function (businessHourGenerator) {
+ var component = this.component;
+ var unzonedRange = component._getDateProfile().activeUnzonedRange;
+ var eventInstanceGroup = businessHourGenerator.buildEventInstanceGroup(component.hasAllDayBusinessHours, unzonedRange);
+ var eventFootprints = eventInstanceGroup ?
+ component.eventRangesToEventFootprints(eventInstanceGroup.sliceRenderRanges(unzonedRange)) :
+ [];
+ this.renderEventFootprints(eventFootprints);
+ };
+ BusinessHourRenderer.prototype.renderEventFootprints = function (eventFootprints) {
+ var segs = this.component.eventFootprintsToSegs(eventFootprints);
+ this.renderSegs(segs);
+ this.segs = segs;
+ };
+ BusinessHourRenderer.prototype.renderSegs = function (segs) {
+ if (this.fillRenderer) {
+ this.fillRenderer.renderSegs('businessHours', segs, {
+ getClasses: function (seg) {
+ return ['fc-nonbusiness', 'fc-bgevent'];
+ }
+ });
+ }
+ };
+ BusinessHourRenderer.prototype.unrender = function () {
+ if (this.fillRenderer) {
+ this.fillRenderer.unrender('businessHours');
+ }
+ this.segs = null;
+ };
+ BusinessHourRenderer.prototype.getSegs = function () {
+ return this.segs || [];
+ };
+ return BusinessHourRenderer;
+}());
+exports.default = BusinessHourRenderer;
+
+
+/***/ }),
+/* 57 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var FillRenderer = /** @class */ (function () {
+ function FillRenderer(component) {
+ this.fillSegTag = 'div';
+ this.component = component;
+ this.elsByFill = {};
+ }
+ FillRenderer.prototype.renderFootprint = function (type, componentFootprint, props) {
+ this.renderSegs(type, this.component.componentFootprintToSegs(componentFootprint), props);
+ };
+ FillRenderer.prototype.renderSegs = function (type, segs, props) {
+ var els;
+ segs = this.buildSegEls(type, segs, props); // assignes `.el` to each seg. returns successfully rendered segs
+ els = this.attachSegEls(type, segs);
+ if (els) {
+ this.reportEls(type, els);
+ }
+ return segs;
+ };
+ // Unrenders a specific type of fill that is currently rendered on the grid
+ FillRenderer.prototype.unrender = function (type) {
+ var el = this.elsByFill[type];
+ if (el) {
+ el.remove();
+ delete this.elsByFill[type];
+ }
+ };
+ // Renders and assigns an `el` property for each fill segment. Generic enough to work with different types.
+ // Only returns segments that successfully rendered.
+ FillRenderer.prototype.buildSegEls = function (type, segs, props) {
+ var _this = this;
+ var html = '';
+ var renderedSegs = [];
+ var i;
+ if (segs.length) {
+ // build a large concatenation of segment HTML
+ for (i = 0; i < segs.length; i++) {
+ html += this.buildSegHtml(type, segs[i], props);
+ }
+ // Grab individual elements from the combined HTML string. Use each as the default rendering.
+ // Then, compute the 'el' for each segment.
+ $(html).each(function (i, node) {
+ var seg = segs[i];
+ var el = $(node);
+ // allow custom filter methods per-type
+ if (props.filterEl) {
+ el = props.filterEl(seg, el);
+ }
+ if (el) {
+ el = $(el); // allow custom filter to return raw DOM node
+ // correct element type? (would be bad if a non-TD were inserted into a table for example)
+ if (el.is(_this.fillSegTag)) {
+ seg.el = el;
+ renderedSegs.push(seg);
+ }
+ }
+ });
+ }
+ return renderedSegs;
+ };
+ // Builds the HTML needed for one fill segment. Generic enough to work with different types.
+ FillRenderer.prototype.buildSegHtml = function (type, seg, props) {
+ // custom hooks per-type
+ var classes = props.getClasses ? props.getClasses(seg) : [];
+ var css = util_1.cssToStr(props.getCss ? props.getCss(seg) : {});
+ return '<' + this.fillSegTag +
+ (classes.length ? ' class="' + classes.join(' ') + '"' : '') +
+ (css ? ' style="' + css + '"' : '') +
+ ' />';
+ };
+ // Should return wrapping DOM structure
+ FillRenderer.prototype.attachSegEls = function (type, segs) {
+ // subclasses must implement
+ };
+ FillRenderer.prototype.reportEls = function (type, nodes) {
+ if (this.elsByFill[type]) {
+ this.elsByFill[type] = this.elsByFill[type].add(nodes);
+ }
+ else {
+ this.elsByFill[type] = $(nodes);
+ }
+ };
+ return FillRenderer;
+}());
+exports.default = FillRenderer;
+
+
+/***/ }),
+/* 58 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var SingleEventDef_1 = __webpack_require__(13);
+var EventFootprint_1 = __webpack_require__(36);
+var EventSource_1 = __webpack_require__(6);
+var HelperRenderer = /** @class */ (function () {
+ function HelperRenderer(component, eventRenderer) {
+ this.view = component._getView();
+ this.component = component;
+ this.eventRenderer = eventRenderer;
+ }
+ HelperRenderer.prototype.renderComponentFootprint = function (componentFootprint) {
+ this.renderEventFootprints([
+ this.fabricateEventFootprint(componentFootprint)
+ ]);
+ };
+ HelperRenderer.prototype.renderEventDraggingFootprints = function (eventFootprints, sourceSeg, isTouch) {
+ this.renderEventFootprints(eventFootprints, sourceSeg, 'fc-dragging', isTouch ? null : this.view.opt('dragOpacity'));
+ };
+ HelperRenderer.prototype.renderEventResizingFootprints = function (eventFootprints, sourceSeg, isTouch) {
+ this.renderEventFootprints(eventFootprints, sourceSeg, 'fc-resizing');
+ };
+ HelperRenderer.prototype.renderEventFootprints = function (eventFootprints, sourceSeg, extraClassNames, opacity) {
+ var segs = this.component.eventFootprintsToSegs(eventFootprints);
+ var classNames = 'fc-helper ' + (extraClassNames || '');
+ var i;
+ // assigns each seg's el and returns a subset of segs that were rendered
+ segs = this.eventRenderer.renderFgSegEls(segs);
+ for (i = 0; i < segs.length; i++) {
+ segs[i].el.addClass(classNames);
+ }
+ if (opacity != null) {
+ for (i = 0; i < segs.length; i++) {
+ segs[i].el.css('opacity', opacity);
+ }
+ }
+ this.helperEls = this.renderSegs(segs, sourceSeg);
+ };
+ /*
+ Must return all mock event elements
+ */
+ HelperRenderer.prototype.renderSegs = function (segs, sourceSeg) {
+ // Subclasses must implement
+ };
+ HelperRenderer.prototype.unrender = function () {
+ if (this.helperEls) {
+ this.helperEls.remove();
+ this.helperEls = null;
+ }
+ };
+ HelperRenderer.prototype.fabricateEventFootprint = function (componentFootprint) {
+ var calendar = this.view.calendar;
+ var eventDateProfile = calendar.footprintToDateProfile(componentFootprint);
+ var dummyEvent = new SingleEventDef_1.default(new EventSource_1.default(calendar));
+ var dummyInstance;
+ dummyEvent.dateProfile = eventDateProfile;
+ dummyInstance = dummyEvent.buildInstance();
+ return new EventFootprint_1.default(componentFootprint, dummyEvent, dummyInstance);
+ };
+ return HelperRenderer;
+}());
+exports.default = HelperRenderer;
+
+
+/***/ }),
+/* 59 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var GlobalEmitter_1 = __webpack_require__(21);
+var Interaction_1 = __webpack_require__(15);
+var EventPointing = /** @class */ (function (_super) {
+ tslib_1.__extends(EventPointing, _super);
+ function EventPointing() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ /*
+ component must implement:
+ - publiclyTrigger
+ */
+ EventPointing.prototype.bindToEl = function (el) {
+ var component = this.component;
+ component.bindSegHandlerToEl(el, 'click', this.handleClick.bind(this));
+ component.bindSegHandlerToEl(el, 'mouseenter', this.handleMouseover.bind(this));
+ component.bindSegHandlerToEl(el, 'mouseleave', this.handleMouseout.bind(this));
+ };
+ EventPointing.prototype.handleClick = function (seg, ev) {
+ var res = this.component.publiclyTrigger('eventClick', {
+ context: seg.el[0],
+ args: [seg.footprint.getEventLegacy(), ev, this.view]
+ });
+ if (res === false) {
+ ev.preventDefault();
+ }
+ };
+ // Updates internal state and triggers handlers for when an event element is moused over
+ EventPointing.prototype.handleMouseover = function (seg, ev) {
+ if (!GlobalEmitter_1.default.get().shouldIgnoreMouse() &&
+ !this.mousedOverSeg) {
+ this.mousedOverSeg = seg;
+ // TODO: move to EventSelecting's responsibility
+ if (this.view.isEventDefResizable(seg.footprint.eventDef)) {
+ seg.el.addClass('fc-allow-mouse-resize');
+ }
+ this.component.publiclyTrigger('eventMouseover', {
+ context: seg.el[0],
+ args: [seg.footprint.getEventLegacy(), ev, this.view]
+ });
+ }
+ };
+ // Updates internal state and triggers handlers for when an event element is moused out.
+ // Can be given no arguments, in which case it will mouseout the segment that was previously moused over.
+ EventPointing.prototype.handleMouseout = function (seg, ev) {
+ if (this.mousedOverSeg) {
+ this.mousedOverSeg = null;
+ // TODO: move to EventSelecting's responsibility
+ if (this.view.isEventDefResizable(seg.footprint.eventDef)) {
+ seg.el.removeClass('fc-allow-mouse-resize');
+ }
+ this.component.publiclyTrigger('eventMouseout', {
+ context: seg.el[0],
+ args: [
+ seg.footprint.getEventLegacy(),
+ ev || {},
+ this.view
+ ]
+ });
+ }
+ };
+ EventPointing.prototype.end = function () {
+ if (this.mousedOverSeg) {
+ this.handleMouseout(this.mousedOverSeg);
+ }
+ };
+ return EventPointing;
+}(Interaction_1.default));
+exports.default = EventPointing;
+
+
+/***/ }),
+/* 60 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Mixin_1 = __webpack_require__(14);
+var DateClicking_1 = __webpack_require__(245);
+var DateSelecting_1 = __webpack_require__(225);
+var EventPointing_1 = __webpack_require__(59);
+var EventDragging_1 = __webpack_require__(224);
+var EventResizing_1 = __webpack_require__(223);
+var ExternalDropping_1 = __webpack_require__(222);
+var StandardInteractionsMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(StandardInteractionsMixin, _super);
+ function StandardInteractionsMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return StandardInteractionsMixin;
+}(Mixin_1.default));
+exports.default = StandardInteractionsMixin;
+StandardInteractionsMixin.prototype.dateClickingClass = DateClicking_1.default;
+StandardInteractionsMixin.prototype.dateSelectingClass = DateSelecting_1.default;
+StandardInteractionsMixin.prototype.eventPointingClass = EventPointing_1.default;
+StandardInteractionsMixin.prototype.eventDraggingClass = EventDragging_1.default;
+StandardInteractionsMixin.prototype.eventResizingClass = EventResizing_1.default;
+StandardInteractionsMixin.prototype.externalDroppingClass = ExternalDropping_1.default;
+
+
+/***/ }),
+/* 61 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var CoordCache_1 = __webpack_require__(53);
+var Popover_1 = __webpack_require__(249);
+var UnzonedRange_1 = __webpack_require__(5);
+var ComponentFootprint_1 = __webpack_require__(12);
+var EventFootprint_1 = __webpack_require__(36);
+var BusinessHourRenderer_1 = __webpack_require__(56);
+var StandardInteractionsMixin_1 = __webpack_require__(60);
+var InteractiveDateComponent_1 = __webpack_require__(40);
+var DayTableMixin_1 = __webpack_require__(55);
+var DayGridEventRenderer_1 = __webpack_require__(250);
+var DayGridHelperRenderer_1 = __webpack_require__(251);
+var DayGridFillRenderer_1 = __webpack_require__(252);
+/* A component that renders a grid of whole-days that runs horizontally. There can be multiple rows, one per week.
+----------------------------------------------------------------------------------------------------------------------*/
+var DayGrid = /** @class */ (function (_super) {
+ tslib_1.__extends(DayGrid, _super);
+ function DayGrid(view) {
+ var _this = _super.call(this, view) || this;
+ _this.cellWeekNumbersVisible = false; // display week numbers in day cell?
+ _this.bottomCoordPadding = 0; // hack for extending the hit area for the last row of the coordinate grid
+ // isRigid determines whether the individual rows should ignore the contents and be a constant height.
+ // Relies on the view's colCnt and rowCnt. In the future, this component should probably be self-sufficient.
+ _this.isRigid = false;
+ _this.hasAllDayBusinessHours = true;
+ return _this;
+ }
+ // Slices up the given span (unzoned start/end with other misc data) into an array of segments
+ DayGrid.prototype.componentFootprintToSegs = function (componentFootprint) {
+ var segs = this.sliceRangeByRow(componentFootprint.unzonedRange);
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ if (this.isRTL) {
+ seg.leftCol = this.daysPerRow - 1 - seg.lastRowDayIndex;
+ seg.rightCol = this.daysPerRow - 1 - seg.firstRowDayIndex;
+ }
+ else {
+ seg.leftCol = seg.firstRowDayIndex;
+ seg.rightCol = seg.lastRowDayIndex;
+ }
+ }
+ return segs;
+ };
+ /* Date Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayGrid.prototype.renderDates = function (dateProfile) {
+ this.dateProfile = dateProfile;
+ this.updateDayTable();
+ this.renderGrid();
+ };
+ DayGrid.prototype.unrenderDates = function () {
+ this.removeSegPopover();
+ };
+ // Renders the rows and columns into the component's `this.el`, which should already be assigned.
+ DayGrid.prototype.renderGrid = function () {
+ var view = this.view;
+ var rowCnt = this.rowCnt;
+ var colCnt = this.colCnt;
+ var html = '';
+ var row;
+ var col;
+ if (this.headContainerEl) {
+ this.headContainerEl.html(this.renderHeadHtml());
+ }
+ for (row = 0; row < rowCnt; row++) {
+ html += this.renderDayRowHtml(row, this.isRigid);
+ }
+ this.el.html(html);
+ this.rowEls = this.el.find('.fc-row');
+ this.cellEls = this.el.find('.fc-day, .fc-disabled-day');
+ this.rowCoordCache = new CoordCache_1.default({
+ els: this.rowEls,
+ isVertical: true
+ });
+ this.colCoordCache = new CoordCache_1.default({
+ els: this.cellEls.slice(0, this.colCnt),
+ isHorizontal: true
+ });
+ // trigger dayRender with each cell's element
+ for (row = 0; row < rowCnt; row++) {
+ for (col = 0; col < colCnt; col++) {
+ this.publiclyTrigger('dayRender', {
+ context: view,
+ args: [
+ this.getCellDate(row, col),
+ this.getCellEl(row, col),
+ view
+ ]
+ });
+ }
+ }
+ };
+ // Generates the HTML for a single row, which is a div that wraps a table.
+ // `row` is the row number.
+ DayGrid.prototype.renderDayRowHtml = function (row, isRigid) {
+ var theme = this.view.calendar.theme;
+ var classes = ['fc-row', 'fc-week', theme.getClass('dayRow')];
+ if (isRigid) {
+ classes.push('fc-rigid');
+ }
+ return '' +
+ '<div class="' + classes.join(' ') + '">' +
+ '<div class="fc-bg">' +
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ this.renderBgTrHtml(row) +
+ '</table>' +
+ '</div>' +
+ '<div class="fc-content-skeleton">' +
+ '<table>' +
+ (this.getIsNumbersVisible() ?
+ '<thead>' +
+ this.renderNumberTrHtml(row) +
+ '</thead>' :
+ '') +
+ '</table>' +
+ '</div>' +
+ '</div>';
+ };
+ DayGrid.prototype.getIsNumbersVisible = function () {
+ return this.getIsDayNumbersVisible() || this.cellWeekNumbersVisible;
+ };
+ DayGrid.prototype.getIsDayNumbersVisible = function () {
+ return this.rowCnt > 1;
+ };
+ /* Grid Number Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayGrid.prototype.renderNumberTrHtml = function (row) {
+ return '' +
+ '<tr>' +
+ (this.isRTL ? '' : this.renderNumberIntroHtml(row)) +
+ this.renderNumberCellsHtml(row) +
+ (this.isRTL ? this.renderNumberIntroHtml(row) : '') +
+ '</tr>';
+ };
+ DayGrid.prototype.renderNumberIntroHtml = function (row) {
+ return this.renderIntroHtml();
+ };
+ DayGrid.prototype.renderNumberCellsHtml = function (row) {
+ var htmls = [];
+ var col;
+ var date;
+ for (col = 0; col < this.colCnt; col++) {
+ date = this.getCellDate(row, col);
+ htmls.push(this.renderNumberCellHtml(date));
+ }
+ return htmls.join('');
+ };
+ // Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton.
+ // The number row will only exist if either day numbers or week numbers are turned on.
+ DayGrid.prototype.renderNumberCellHtml = function (date) {
+ var view = this.view;
+ var html = '';
+ var isDateValid = this.dateProfile.activeUnzonedRange.containsDate(date); // TODO: called too frequently. cache somehow.
+ var isDayNumberVisible = this.getIsDayNumbersVisible() && isDateValid;
+ var classes;
+ var weekCalcFirstDoW;
+ if (!isDayNumberVisible && !this.cellWeekNumbersVisible) {
+ // no numbers in day cell (week number must be along the side)
+ return '<td/>'; // will create an empty space above events :(
+ }
+ classes = this.getDayClasses(date);
+ classes.unshift('fc-day-top');
+ if (this.cellWeekNumbersVisible) {
+ // To determine the day of week number change under ISO, we cannot
+ // rely on moment.js methods such as firstDayOfWeek() or weekday(),
+ // because they rely on the locale's dow (possibly overridden by
+ // our firstDay option), which may not be Monday. We cannot change
+ // dow, because that would affect the calendar start day as well.
+ if (date._locale._fullCalendar_weekCalc === 'ISO') {
+ weekCalcFirstDoW = 1; // Monday by ISO 8601 definition
+ }
+ else {
+ weekCalcFirstDoW = date._locale.firstDayOfWeek();
+ }
+ }
+ html += '<td class="' + classes.join(' ') + '"' +
+ (isDateValid ?
+ ' data-date="' + date.format() + '"' :
+ '') +
+ '>';
+ if (this.cellWeekNumbersVisible && (date.day() === weekCalcFirstDoW)) {
+ html += view.buildGotoAnchorHtml({ date: date, type: 'week' }, { 'class': 'fc-week-number' }, date.format('w') // inner HTML
+ );
+ }
+ if (isDayNumberVisible) {
+ html += view.buildGotoAnchorHtml(date, { 'class': 'fc-day-number' }, date.format('D') // inner HTML
+ );
+ }
+ html += '</td>';
+ return html;
+ };
+ /* Hit System
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayGrid.prototype.prepareHits = function () {
+ this.colCoordCache.build();
+ this.rowCoordCache.build();
+ this.rowCoordCache.bottoms[this.rowCnt - 1] += this.bottomCoordPadding; // hack
+ };
+ DayGrid.prototype.releaseHits = function () {
+ this.colCoordCache.clear();
+ this.rowCoordCache.clear();
+ };
+ DayGrid.prototype.queryHit = function (leftOffset, topOffset) {
+ if (this.colCoordCache.isLeftInBounds(leftOffset) && this.rowCoordCache.isTopInBounds(topOffset)) {
+ var col = this.colCoordCache.getHorizontalIndex(leftOffset);
+ var row = this.rowCoordCache.getVerticalIndex(topOffset);
+ if (row != null && col != null) {
+ return this.getCellHit(row, col);
+ }
+ }
+ };
+ DayGrid.prototype.getHitFootprint = function (hit) {
+ var range = this.getCellRange(hit.row, hit.col);
+ return new ComponentFootprint_1.default(new UnzonedRange_1.default(range.start, range.end), true // all-day?
+ );
+ };
+ DayGrid.prototype.getHitEl = function (hit) {
+ return this.getCellEl(hit.row, hit.col);
+ };
+ /* Cell System
+ ------------------------------------------------------------------------------------------------------------------*/
+ // FYI: the first column is the leftmost column, regardless of date
+ DayGrid.prototype.getCellHit = function (row, col) {
+ return {
+ row: row,
+ col: col,
+ component: this,
+ left: this.colCoordCache.getLeftOffset(col),
+ right: this.colCoordCache.getRightOffset(col),
+ top: this.rowCoordCache.getTopOffset(row),
+ bottom: this.rowCoordCache.getBottomOffset(row)
+ };
+ };
+ DayGrid.prototype.getCellEl = function (row, col) {
+ return this.cellEls.eq(row * this.colCnt + col);
+ };
+ /* Event Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Unrenders all events currently rendered on the grid
+ DayGrid.prototype.executeEventUnrender = function () {
+ this.removeSegPopover(); // removes the "more.." events popover
+ _super.prototype.executeEventUnrender.call(this);
+ };
+ // Retrieves all rendered segment objects currently rendered on the grid
+ DayGrid.prototype.getOwnEventSegs = function () {
+ // append the segments from the "more..." popover
+ return _super.prototype.getOwnEventSegs.call(this).concat(this.popoverSegs || []);
+ };
+ /* Event Drag Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of an event or external element being dragged.
+ // `eventLocation` has zoned start and end (optional)
+ DayGrid.prototype.renderDrag = function (eventFootprints, seg, isTouch) {
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ this.renderHighlight(eventFootprints[i].componentFootprint);
+ }
+ // render drags from OTHER components as helpers
+ if (eventFootprints.length && seg && seg.component !== this) {
+ this.helperRenderer.renderEventDraggingFootprints(eventFootprints, seg, isTouch);
+ return true; // signal helpers rendered
+ }
+ };
+ // Unrenders any visual indication of a hovering event
+ DayGrid.prototype.unrenderDrag = function () {
+ this.unrenderHighlight();
+ this.helperRenderer.unrender();
+ };
+ /* Event Resize Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of an event being resized
+ DayGrid.prototype.renderEventResize = function (eventFootprints, seg, isTouch) {
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ this.renderHighlight(eventFootprints[i].componentFootprint);
+ }
+ this.helperRenderer.renderEventResizingFootprints(eventFootprints, seg, isTouch);
+ };
+ // Unrenders a visual indication of an event being resized
+ DayGrid.prototype.unrenderEventResize = function () {
+ this.unrenderHighlight();
+ this.helperRenderer.unrender();
+ };
+ /* More+ Link Popover
+ ------------------------------------------------------------------------------------------------------------------*/
+ DayGrid.prototype.removeSegPopover = function () {
+ if (this.segPopover) {
+ this.segPopover.hide(); // in handler, will call segPopover's removeElement
+ }
+ };
+ // Limits the number of "levels" (vertically stacking layers of events) for each row of the grid.
+ // `levelLimit` can be false (don't limit), a number, or true (should be computed).
+ DayGrid.prototype.limitRows = function (levelLimit) {
+ var rowStructs = this.eventRenderer.rowStructs || [];
+ var row; // row #
+ var rowLevelLimit;
+ for (row = 0; row < rowStructs.length; row++) {
+ this.unlimitRow(row);
+ if (!levelLimit) {
+ rowLevelLimit = false;
+ }
+ else if (typeof levelLimit === 'number') {
+ rowLevelLimit = levelLimit;
+ }
+ else {
+ rowLevelLimit = this.computeRowLevelLimit(row);
+ }
+ if (rowLevelLimit !== false) {
+ this.limitRow(row, rowLevelLimit);
+ }
+ }
+ };
+ // Computes the number of levels a row will accomodate without going outside its bounds.
+ // Assumes the row is "rigid" (maintains a constant height regardless of what is inside).
+ // `row` is the row number.
+ DayGrid.prototype.computeRowLevelLimit = function (row) {
+ var rowEl = this.rowEls.eq(row); // the containing "fake" row div
+ var rowHeight = rowEl.height(); // TODO: cache somehow?
+ var trEls = this.eventRenderer.rowStructs[row].tbodyEl.children();
+ var i;
+ var trEl;
+ var trHeight;
+ function iterInnerHeights(i, childNode) {
+ trHeight = Math.max(trHeight, $(childNode).outerHeight());
+ }
+ // Reveal one level <tr> at a time and stop when we find one out of bounds
+ for (i = 0; i < trEls.length; i++) {
+ trEl = trEls.eq(i).removeClass('fc-limited'); // reset to original state (reveal)
+ // with rowspans>1 and IE8, trEl.outerHeight() would return the height of the largest cell,
+ // so instead, find the tallest inner content element.
+ trHeight = 0;
+ trEl.find('> td > :first-child').each(iterInnerHeights);
+ if (trEl.position().top + trHeight > rowHeight) {
+ return i;
+ }
+ }
+ return false; // should not limit at all
+ };
+ // Limits the given grid row to the maximum number of levels and injects "more" links if necessary.
+ // `row` is the row number.
+ // `levelLimit` is a number for the maximum (inclusive) number of levels allowed.
+ DayGrid.prototype.limitRow = function (row, levelLimit) {
+ var _this = this;
+ var rowStruct = this.eventRenderer.rowStructs[row];
+ var moreNodes = []; // array of "more" <a> links and <td> DOM nodes
+ var col = 0; // col #, left-to-right (not chronologically)
+ var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right
+ var cellMatrix; // a matrix (by level, then column) of all <td> jQuery elements in the row
+ var limitedNodes; // array of temporarily hidden level <tr> and segment <td> DOM nodes
+ var i;
+ var seg;
+ var segsBelow; // array of segment objects below `seg` in the current `col`
+ var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies
+ var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column)
+ var td;
+ var rowspan;
+ var segMoreNodes; // array of "more" <td> cells that will stand-in for the current seg's cell
+ var j;
+ var moreTd;
+ var moreWrap;
+ var moreLink;
+ // Iterates through empty level cells and places "more" links inside if need be
+ var emptyCellsUntil = function (endCol) {
+ while (col < endCol) {
+ segsBelow = _this.getCellSegs(row, col, levelLimit);
+ if (segsBelow.length) {
+ td = cellMatrix[levelLimit - 1][col];
+ moreLink = _this.renderMoreLink(row, col, segsBelow);
+ moreWrap = $('<div/>').append(moreLink);
+ td.append(moreWrap);
+ moreNodes.push(moreWrap[0]);
+ }
+ col++;
+ }
+ };
+ if (levelLimit && levelLimit < rowStruct.segLevels.length) {
+ levelSegs = rowStruct.segLevels[levelLimit - 1];
+ cellMatrix = rowStruct.cellMatrix;
+ limitedNodes = rowStruct.tbodyEl.children().slice(levelLimit) // get level <tr> elements past the limit
+ .addClass('fc-limited').get(); // hide elements and get a simple DOM-nodes array
+ // iterate though segments in the last allowable level
+ for (i = 0; i < levelSegs.length; i++) {
+ seg = levelSegs[i];
+ emptyCellsUntil(seg.leftCol); // process empty cells before the segment
+ // determine *all* segments below `seg` that occupy the same columns
+ colSegsBelow = [];
+ totalSegsBelow = 0;
+ while (col <= seg.rightCol) {
+ segsBelow = this.getCellSegs(row, col, levelLimit);
+ colSegsBelow.push(segsBelow);
+ totalSegsBelow += segsBelow.length;
+ col++;
+ }
+ if (totalSegsBelow) {
+ td = cellMatrix[levelLimit - 1][seg.leftCol]; // the segment's parent cell
+ rowspan = td.attr('rowspan') || 1;
+ segMoreNodes = [];
+ // make a replacement <td> for each column the segment occupies. will be one for each colspan
+ for (j = 0; j < colSegsBelow.length; j++) {
+ moreTd = $('<td class="fc-more-cell"/>').attr('rowspan', rowspan);
+ segsBelow = colSegsBelow[j];
+ moreLink = this.renderMoreLink(row, seg.leftCol + j, [seg].concat(segsBelow) // count seg as hidden too
+ );
+ moreWrap = $('<div/>').append(moreLink);
+ moreTd.append(moreWrap);
+ segMoreNodes.push(moreTd[0]);
+ moreNodes.push(moreTd[0]);
+ }
+ td.addClass('fc-limited').after($(segMoreNodes)); // hide original <td> and inject replacements
+ limitedNodes.push(td[0]);
+ }
+ }
+ emptyCellsUntil(this.colCnt); // finish off the level
+ rowStruct.moreEls = $(moreNodes); // for easy undoing later
+ rowStruct.limitedEls = $(limitedNodes); // for easy undoing later
+ }
+ };
+ // Reveals all levels and removes all "more"-related elements for a grid's row.
+ // `row` is a row number.
+ DayGrid.prototype.unlimitRow = function (row) {
+ var rowStruct = this.eventRenderer.rowStructs[row];
+ if (rowStruct.moreEls) {
+ rowStruct.moreEls.remove();
+ rowStruct.moreEls = null;
+ }
+ if (rowStruct.limitedEls) {
+ rowStruct.limitedEls.removeClass('fc-limited');
+ rowStruct.limitedEls = null;
+ }
+ };
+ // Renders an <a> element that represents hidden event element for a cell.
+ // Responsible for attaching click handler as well.
+ DayGrid.prototype.renderMoreLink = function (row, col, hiddenSegs) {
+ var _this = this;
+ var view = this.view;
+ return $('<a class="fc-more"/>')
+ .text(this.getMoreLinkText(hiddenSegs.length))
+ .on('click', function (ev) {
+ var clickOption = _this.opt('eventLimitClick');
+ var date = _this.getCellDate(row, col);
+ var moreEl = $(ev.currentTarget);
+ var dayEl = _this.getCellEl(row, col);
+ var allSegs = _this.getCellSegs(row, col);
+ // rescope the segments to be within the cell's date
+ var reslicedAllSegs = _this.resliceDaySegs(allSegs, date);
+ var reslicedHiddenSegs = _this.resliceDaySegs(hiddenSegs, date);
+ if (typeof clickOption === 'function') {
+ // the returned value can be an atomic option
+ clickOption = _this.publiclyTrigger('eventLimitClick', {
+ context: view,
+ args: [
+ {
+ date: date.clone(),
+ dayEl: dayEl,
+ moreEl: moreEl,
+ segs: reslicedAllSegs,
+ hiddenSegs: reslicedHiddenSegs
+ },
+ ev,
+ view
+ ]
+ });
+ }
+ if (clickOption === 'popover') {
+ _this.showSegPopover(row, col, moreEl, reslicedAllSegs);
+ }
+ else if (typeof clickOption === 'string') {
+ view.calendar.zoomTo(date, clickOption);
+ }
+ });
+ };
+ // Reveals the popover that displays all events within a cell
+ DayGrid.prototype.showSegPopover = function (row, col, moreLink, segs) {
+ var _this = this;
+ var view = this.view;
+ var moreWrap = moreLink.parent(); // the <div> wrapper around the <a>
+ var topEl; // the element we want to match the top coordinate of
+ var options;
+ if (this.rowCnt === 1) {
+ topEl = view.el; // will cause the popover to cover any sort of header
+ }
+ else {
+ topEl = this.rowEls.eq(row); // will align with top of row
+ }
+ options = {
+ className: 'fc-more-popover ' + view.calendar.theme.getClass('popover'),
+ content: this.renderSegPopoverContent(row, col, segs),
+ parentEl: view.el,
+ top: topEl.offset().top,
+ autoHide: true,
+ viewportConstrain: this.opt('popoverViewportConstrain'),
+ hide: function () {
+ // kill everything when the popover is hidden
+ // notify events to be removed
+ if (_this.popoverSegs) {
+ _this.triggerBeforeEventSegsDestroyed(_this.popoverSegs);
+ }
+ _this.segPopover.removeElement();
+ _this.segPopover = null;
+ _this.popoverSegs = null;
+ }
+ };
+ // Determine horizontal coordinate.
+ // We use the moreWrap instead of the <td> to avoid border confusion.
+ if (this.isRTL) {
+ options.right = moreWrap.offset().left + moreWrap.outerWidth() + 1; // +1 to be over cell border
+ }
+ else {
+ options.left = moreWrap.offset().left - 1; // -1 to be over cell border
+ }
+ this.segPopover = new Popover_1.default(options);
+ this.segPopover.show();
+ // the popover doesn't live within the grid's container element, and thus won't get the event
+ // delegated-handlers for free. attach event-related handlers to the popover.
+ this.bindAllSegHandlersToEl(this.segPopover.el);
+ this.triggerAfterEventSegsRendered(segs);
+ };
+ // Builds the inner DOM contents of the segment popover
+ DayGrid.prototype.renderSegPopoverContent = function (row, col, segs) {
+ var view = this.view;
+ var theme = view.calendar.theme;
+ var title = this.getCellDate(row, col).format(this.opt('dayPopoverFormat'));
+ var content = $('<div class="fc-header ' + theme.getClass('popoverHeader') + '">' +
+ '<span class="fc-close ' + theme.getIconClass('close') + '"></span>' +
+ '<span class="fc-title">' +
+ util_1.htmlEscape(title) +
+ '</span>' +
+ '<div class="fc-clear"/>' +
+ '</div>' +
+ '<div class="fc-body ' + theme.getClass('popoverContent') + '">' +
+ '<div class="fc-event-container"></div>' +
+ '</div>');
+ var segContainer = content.find('.fc-event-container');
+ var i;
+ // render each seg's `el` and only return the visible segs
+ segs = this.eventRenderer.renderFgSegEls(segs, true); // disableResizing=true
+ this.popoverSegs = segs;
+ for (i = 0; i < segs.length; i++) {
+ // because segments in the popover are not part of a grid coordinate system, provide a hint to any
+ // grids that want to do drag-n-drop about which cell it came from
+ this.hitsNeeded();
+ segs[i].hit = this.getCellHit(row, col);
+ this.hitsNotNeeded();
+ segContainer.append(segs[i].el);
+ }
+ return content;
+ };
+ // Given the events within an array of segment objects, reslice them to be in a single day
+ DayGrid.prototype.resliceDaySegs = function (segs, dayDate) {
+ var dayStart = dayDate.clone();
+ var dayEnd = dayStart.clone().add(1, 'days');
+ var dayRange = new UnzonedRange_1.default(dayStart, dayEnd);
+ var newSegs = [];
+ var i;
+ var seg;
+ var slicedRange;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ slicedRange = seg.footprint.componentFootprint.unzonedRange.intersect(dayRange);
+ if (slicedRange) {
+ newSegs.push($.extend({}, seg, {
+ footprint: new EventFootprint_1.default(new ComponentFootprint_1.default(slicedRange, seg.footprint.componentFootprint.isAllDay), seg.footprint.eventDef, seg.footprint.eventInstance),
+ isStart: seg.isStart && slicedRange.isStart,
+ isEnd: seg.isEnd && slicedRange.isEnd
+ }));
+ }
+ }
+ // force an order because eventsToSegs doesn't guarantee one
+ // TODO: research if still needed
+ this.eventRenderer.sortEventSegs(newSegs);
+ return newSegs;
+ };
+ // Generates the text that should be inside a "more" link, given the number of events it represents
+ DayGrid.prototype.getMoreLinkText = function (num) {
+ var opt = this.opt('eventLimitText');
+ if (typeof opt === 'function') {
+ return opt(num);
+ }
+ else {
+ return '+' + num + ' ' + opt;
+ }
+ };
+ // Returns segments within a given cell.
+ // If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs.
+ DayGrid.prototype.getCellSegs = function (row, col, startLevel) {
+ var segMatrix = this.eventRenderer.rowStructs[row].segMatrix;
+ var level = startLevel || 0;
+ var segs = [];
+ var seg;
+ while (level < segMatrix.length) {
+ seg = segMatrix[level][col];
+ if (seg) {
+ segs.push(seg);
+ }
+ level++;
+ }
+ return segs;
+ };
+ return DayGrid;
+}(InteractiveDateComponent_1.default));
+exports.default = DayGrid;
+DayGrid.prototype.eventRendererClass = DayGridEventRenderer_1.default;
+DayGrid.prototype.businessHourRendererClass = BusinessHourRenderer_1.default;
+DayGrid.prototype.helperRendererClass = DayGridHelperRenderer_1.default;
+DayGrid.prototype.fillRendererClass = DayGridFillRenderer_1.default;
+StandardInteractionsMixin_1.default.mixInto(DayGrid);
+DayTableMixin_1.default.mixInto(DayGrid);
+
+
+/***/ }),
+/* 62 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Scroller_1 = __webpack_require__(39);
+var View_1 = __webpack_require__(41);
+var BasicViewDateProfileGenerator_1 = __webpack_require__(228);
+var DayGrid_1 = __webpack_require__(61);
+/* An abstract class for the "basic" views, as well as month view. Renders one or more rows of day cells.
+----------------------------------------------------------------------------------------------------------------------*/
+// It is a manager for a DayGrid subcomponent, which does most of the heavy lifting.
+// It is responsible for managing width/height.
+var BasicView = /** @class */ (function (_super) {
+ tslib_1.__extends(BasicView, _super);
+ function BasicView(calendar, viewSpec) {
+ var _this = _super.call(this, calendar, viewSpec) || this;
+ _this.dayGrid = _this.instantiateDayGrid();
+ _this.dayGrid.isRigid = _this.hasRigidRows();
+ if (_this.opt('weekNumbers')) {
+ if (_this.opt('weekNumbersWithinDays')) {
+ _this.dayGrid.cellWeekNumbersVisible = true;
+ _this.dayGrid.colWeekNumbersVisible = false;
+ }
+ else {
+ _this.dayGrid.cellWeekNumbersVisible = false;
+ _this.dayGrid.colWeekNumbersVisible = true;
+ }
+ }
+ _this.addChild(_this.dayGrid);
+ _this.scroller = new Scroller_1.default({
+ overflowX: 'hidden',
+ overflowY: 'auto'
+ });
+ return _this;
+ }
+ // Generates the DayGrid object this view needs. Draws from this.dayGridClass
+ BasicView.prototype.instantiateDayGrid = function () {
+ // generate a subclass on the fly with BasicView-specific behavior
+ // TODO: cache this subclass
+ var subclass = makeDayGridSubclass(this.dayGridClass);
+ return new subclass(this);
+ };
+ BasicView.prototype.executeDateRender = function (dateProfile) {
+ this.dayGrid.breakOnWeeks = /year|month|week/.test(dateProfile.currentRangeUnit);
+ _super.prototype.executeDateRender.call(this, dateProfile);
+ };
+ BasicView.prototype.renderSkeleton = function () {
+ var dayGridContainerEl;
+ var dayGridEl;
+ this.el.addClass('fc-basic-view').html(this.renderSkeletonHtml());
+ this.scroller.render();
+ dayGridContainerEl = this.scroller.el.addClass('fc-day-grid-container');
+ dayGridEl = $('<div class="fc-day-grid" />').appendTo(dayGridContainerEl);
+ this.el.find('.fc-body > tr > td').append(dayGridContainerEl);
+ this.dayGrid.headContainerEl = this.el.find('.fc-head-container');
+ this.dayGrid.setElement(dayGridEl);
+ };
+ BasicView.prototype.unrenderSkeleton = function () {
+ this.dayGrid.removeElement();
+ this.scroller.destroy();
+ };
+ // Builds the HTML skeleton for the view.
+ // The day-grid component will render inside of a container defined by this HTML.
+ BasicView.prototype.renderSkeletonHtml = function () {
+ var theme = this.calendar.theme;
+ return '' +
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ (this.opt('columnHeader') ?
+ '<thead class="fc-head">' +
+ '<tr>' +
+ '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '">&nbsp;</td>' +
+ '</tr>' +
+ '</thead>' :
+ '') +
+ '<tbody class="fc-body">' +
+ '<tr>' +
+ '<td class="' + theme.getClass('widgetContent') + '"></td>' +
+ '</tr>' +
+ '</tbody>' +
+ '</table>';
+ };
+ // Generates an HTML attribute string for setting the width of the week number column, if it is known
+ BasicView.prototype.weekNumberStyleAttr = function () {
+ if (this.weekNumberWidth != null) {
+ return 'style="width:' + this.weekNumberWidth + 'px"';
+ }
+ return '';
+ };
+ // Determines whether each row should have a constant height
+ BasicView.prototype.hasRigidRows = function () {
+ var eventLimit = this.opt('eventLimit');
+ return eventLimit && typeof eventLimit !== 'number';
+ };
+ /* Dimensions
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Refreshes the horizontal dimensions of the view
+ BasicView.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ var eventLimit = this.opt('eventLimit');
+ var headRowEl = this.dayGrid.headContainerEl.find('.fc-row');
+ var scrollerHeight;
+ var scrollbarWidths;
+ // hack to give the view some height prior to dayGrid's columns being rendered
+ // TODO: separate setting height from scroller VS dayGrid.
+ if (!this.dayGrid.rowEls) {
+ if (!isAuto) {
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ return;
+ }
+ _super.prototype.updateSize.call(this, totalHeight, isAuto, isResize);
+ if (this.dayGrid.colWeekNumbersVisible) {
+ // Make sure all week number cells running down the side have the same width.
+ // Record the width for cells created later.
+ this.weekNumberWidth = util_1.matchCellWidths(this.el.find('.fc-week-number'));
+ }
+ // reset all heights to be natural
+ this.scroller.clear();
+ util_1.uncompensateScroll(headRowEl);
+ this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
+ // is the event limit a constant level number?
+ if (eventLimit && typeof eventLimit === 'number') {
+ this.dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after
+ }
+ // distribute the height to the rows
+ // (totalHeight is a "recommended" value if isAuto)
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.setGridHeight(scrollerHeight, isAuto);
+ // is the event limit dynamically calculated?
+ if (eventLimit && typeof eventLimit !== 'number') {
+ this.dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set
+ }
+ if (!isAuto) {
+ this.scroller.setHeight(scrollerHeight);
+ scrollbarWidths = this.scroller.getScrollbarWidths();
+ if (scrollbarWidths.left || scrollbarWidths.right) {
+ util_1.compensateScroll(headRowEl, scrollbarWidths);
+ // doing the scrollbar compensation might have created text overflow which created more height. redo
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ // guarantees the same scrollbar widths
+ this.scroller.lockOverflow(scrollbarWidths);
+ }
+ };
+ // given a desired total height of the view, returns what the height of the scroller should be
+ BasicView.prototype.computeScrollerHeight = function (totalHeight) {
+ return totalHeight -
+ util_1.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
+ };
+ // Sets the height of just the DayGrid component in this view
+ BasicView.prototype.setGridHeight = function (height, isAuto) {
+ if (isAuto) {
+ util_1.undistributeHeight(this.dayGrid.rowEls); // let the rows be their natural height with no expanding
+ }
+ else {
+ util_1.distributeHeight(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows
+ }
+ };
+ /* Scroll
+ ------------------------------------------------------------------------------------------------------------------*/
+ BasicView.prototype.computeInitialDateScroll = function () {
+ return { top: 0 };
+ };
+ BasicView.prototype.queryDateScroll = function () {
+ return { top: this.scroller.getScrollTop() };
+ };
+ BasicView.prototype.applyDateScroll = function (scroll) {
+ if (scroll.top !== undefined) {
+ this.scroller.setScrollTop(scroll.top);
+ }
+ };
+ return BasicView;
+}(View_1.default));
+exports.default = BasicView;
+BasicView.prototype.dateProfileGeneratorClass = BasicViewDateProfileGenerator_1.default;
+BasicView.prototype.dayGridClass = DayGrid_1.default;
+// customize the rendering behavior of BasicView's dayGrid
+function makeDayGridSubclass(SuperClass) {
+ return /** @class */ (function (_super) {
+ tslib_1.__extends(SubClass, _super);
+ function SubClass() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.colWeekNumbersVisible = false; // display week numbers along the side?
+ return _this;
+ }
+ // Generates the HTML that will go before the day-of week header cells
+ SubClass.prototype.renderHeadIntroHtml = function () {
+ var view = this.view;
+ if (this.colWeekNumbersVisible) {
+ return '' +
+ '<th class="fc-week-number ' + view.calendar.theme.getClass('widgetHeader') + '" ' + view.weekNumberStyleAttr() + '>' +
+ '<span>' + // needed for matchCellWidths
+ util_1.htmlEscape(this.opt('weekNumberTitle')) +
+ '</span>' +
+ '</th>';
+ }
+ return '';
+ };
+ // Generates the HTML that will go before content-skeleton cells that display the day/week numbers
+ SubClass.prototype.renderNumberIntroHtml = function (row) {
+ var view = this.view;
+ var weekStart = this.getCellDate(row, 0);
+ if (this.colWeekNumbersVisible) {
+ return '' +
+ '<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '>' +
+ view.buildGotoAnchorHtml(// aside from link, important for matchCellWidths
+ { date: weekStart, type: 'week', forceOff: this.colCnt === 1 }, weekStart.format('w') // inner HTML
+ ) +
+ '</td>';
+ }
+ return '';
+ };
+ // Generates the HTML that goes before the day bg cells for each day-row
+ SubClass.prototype.renderBgIntroHtml = function () {
+ var view = this.view;
+ if (this.colWeekNumbersVisible) {
+ return '<td class="fc-week-number ' + view.calendar.theme.getClass('widgetContent') + '" ' +
+ view.weekNumberStyleAttr() + '></td>';
+ }
+ return '';
+ };
+ // Generates the HTML that goes before every other type of row generated by DayGrid.
+ // Affects helper-skeleton and highlight-skeleton rows.
+ SubClass.prototype.renderIntroHtml = function () {
+ var view = this.view;
+ if (this.colWeekNumbersVisible) {
+ return '<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '></td>';
+ }
+ return '';
+ };
+ SubClass.prototype.getIsNumbersVisible = function () {
+ return DayGrid_1.default.prototype.getIsNumbersVisible.apply(this, arguments) || this.colWeekNumbersVisible;
+ };
+ return SubClass;
+ }(SuperClass));
+}
+
+
+/***/ }),
+/* 63 */,
+/* 64 */,
+/* 65 */,
+/* 66 */,
+/* 67 */,
+/* 68 */,
+/* 69 */,
+/* 70 */,
+/* 71 */,
+/* 72 */,
+/* 73 */,
+/* 74 */,
+/* 75 */,
+/* 76 */,
+/* 77 */,
+/* 78 */,
+/* 79 */,
+/* 80 */,
+/* 81 */,
+/* 82 */,
+/* 83 */,
+/* 84 */,
+/* 85 */,
+/* 86 */,
+/* 87 */,
+/* 88 */,
+/* 89 */,
+/* 90 */,
+/* 91 */,
+/* 92 */,
+/* 93 */,
+/* 94 */,
+/* 95 */,
+/* 96 */,
+/* 97 */,
+/* 98 */,
+/* 99 */,
+/* 100 */,
+/* 101 */,
+/* 102 */,
+/* 103 */,
+/* 104 */,
+/* 105 */,
+/* 106 */,
+/* 107 */,
+/* 108 */,
+/* 109 */,
+/* 110 */,
+/* 111 */,
+/* 112 */,
+/* 113 */,
+/* 114 */,
+/* 115 */,
+/* 116 */,
+/* 117 */,
+/* 118 */,
+/* 119 */,
+/* 120 */,
+/* 121 */,
+/* 122 */,
+/* 123 */,
+/* 124 */,
+/* 125 */,
+/* 126 */,
+/* 127 */,
+/* 128 */,
+/* 129 */,
+/* 130 */,
+/* 131 */,
+/* 132 */,
+/* 133 */,
+/* 134 */,
+/* 135 */,
+/* 136 */,
+/* 137 */,
+/* 138 */,
+/* 139 */,
+/* 140 */,
+/* 141 */,
+/* 142 */,
+/* 143 */,
+/* 144 */,
+/* 145 */,
+/* 146 */,
+/* 147 */,
+/* 148 */,
+/* 149 */,
+/* 150 */,
+/* 151 */,
+/* 152 */,
+/* 153 */,
+/* 154 */,
+/* 155 */,
+/* 156 */,
+/* 157 */,
+/* 158 */,
+/* 159 */,
+/* 160 */,
+/* 161 */,
+/* 162 */,
+/* 163 */,
+/* 164 */,
+/* 165 */,
+/* 166 */,
+/* 167 */,
+/* 168 */,
+/* 169 */,
+/* 170 */,
+/* 171 */,
+/* 172 */,
+/* 173 */,
+/* 174 */,
+/* 175 */,
+/* 176 */,
+/* 177 */,
+/* 178 */,
+/* 179 */,
+/* 180 */,
+/* 181 */,
+/* 182 */,
+/* 183 */,
+/* 184 */,
+/* 185 */,
+/* 186 */,
+/* 187 */,
+/* 188 */,
+/* 189 */,
+/* 190 */,
+/* 191 */,
+/* 192 */,
+/* 193 */,
+/* 194 */,
+/* 195 */,
+/* 196 */,
+/* 197 */,
+/* 198 */,
+/* 199 */,
+/* 200 */,
+/* 201 */,
+/* 202 */,
+/* 203 */,
+/* 204 */,
+/* 205 */,
+/* 206 */,
+/* 207 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var UnzonedRange_1 = __webpack_require__(5);
+var ComponentFootprint_1 = __webpack_require__(12);
+var EventDefParser_1 = __webpack_require__(49);
+var EventSource_1 = __webpack_require__(6);
+var util_1 = __webpack_require__(35);
+var Constraints = /** @class */ (function () {
+ function Constraints(eventManager, _calendar) {
+ this.eventManager = eventManager;
+ this._calendar = _calendar;
+ }
+ Constraints.prototype.opt = function (name) {
+ return this._calendar.opt(name);
+ };
+ /*
+ determines if eventInstanceGroup is allowed,
+ in relation to other EVENTS and business hours.
+ */
+ Constraints.prototype.isEventInstanceGroupAllowed = function (eventInstanceGroup) {
+ var eventDef = eventInstanceGroup.getEventDef();
+ var eventFootprints = this.eventRangesToEventFootprints(eventInstanceGroup.getAllEventRanges());
+ var i;
+ var peerEventInstances = this.getPeerEventInstances(eventDef);
+ var peerEventRanges = peerEventInstances.map(util_1.eventInstanceToEventRange);
+ var peerEventFootprints = this.eventRangesToEventFootprints(peerEventRanges);
+ var constraintVal = eventDef.getConstraint();
+ var overlapVal = eventDef.getOverlap();
+ var eventAllowFunc = this.opt('eventAllow');
+ for (i = 0; i < eventFootprints.length; i++) {
+ if (!this.isFootprintAllowed(eventFootprints[i].componentFootprint, peerEventFootprints, constraintVal, overlapVal, eventFootprints[i].eventInstance)) {
+ return false;
+ }
+ }
+ if (eventAllowFunc) {
+ for (i = 0; i < eventFootprints.length; i++) {
+ if (eventAllowFunc(eventFootprints[i].componentFootprint.toLegacy(this._calendar), eventFootprints[i].getEventLegacy()) === false) {
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+ Constraints.prototype.getPeerEventInstances = function (eventDef) {
+ return this.eventManager.getEventInstancesWithoutId(eventDef.id);
+ };
+ Constraints.prototype.isSelectionFootprintAllowed = function (componentFootprint) {
+ var peerEventInstances = this.eventManager.getEventInstances();
+ var peerEventRanges = peerEventInstances.map(util_1.eventInstanceToEventRange);
+ var peerEventFootprints = this.eventRangesToEventFootprints(peerEventRanges);
+ var selectAllowFunc;
+ if (this.isFootprintAllowed(componentFootprint, peerEventFootprints, this.opt('selectConstraint'), this.opt('selectOverlap'))) {
+ selectAllowFunc = this.opt('selectAllow');
+ if (selectAllowFunc) {
+ return selectAllowFunc(componentFootprint.toLegacy(this._calendar)) !== false;
+ }
+ else {
+ return true;
+ }
+ }
+ return false;
+ };
+ Constraints.prototype.isFootprintAllowed = function (componentFootprint, peerEventFootprints, constraintVal, overlapVal, subjectEventInstance // optional
+ ) {
+ var constraintFootprints; // ComponentFootprint[]
+ var overlapEventFootprints; // EventFootprint[]
+ if (constraintVal != null) {
+ constraintFootprints = this.constraintValToFootprints(constraintVal, componentFootprint.isAllDay);
+ if (!this.isFootprintWithinConstraints(componentFootprint, constraintFootprints)) {
+ return false;
+ }
+ }
+ overlapEventFootprints = this.collectOverlapEventFootprints(peerEventFootprints, componentFootprint);
+ if (overlapVal === false) {
+ if (overlapEventFootprints.length) {
+ return false;
+ }
+ }
+ else if (typeof overlapVal === 'function') {
+ if (!isOverlapsAllowedByFunc(overlapEventFootprints, overlapVal, subjectEventInstance)) {
+ return false;
+ }
+ }
+ if (subjectEventInstance) {
+ if (!isOverlapEventInstancesAllowed(overlapEventFootprints, subjectEventInstance)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ // Constraint
+ // ------------------------------------------------------------------------------------------------
+ Constraints.prototype.isFootprintWithinConstraints = function (componentFootprint, constraintFootprints) {
+ var i;
+ for (i = 0; i < constraintFootprints.length; i++) {
+ if (this.footprintContainsFootprint(constraintFootprints[i], componentFootprint)) {
+ return true;
+ }
+ }
+ return false;
+ };
+ Constraints.prototype.constraintValToFootprints = function (constraintVal, isAllDay) {
+ var eventInstances;
+ if (constraintVal === 'businessHours') {
+ return this.buildCurrentBusinessFootprints(isAllDay);
+ }
+ else if (typeof constraintVal === 'object') {
+ eventInstances = this.parseEventDefToInstances(constraintVal); // handles recurring events
+ if (!eventInstances) {
+ return this.parseFootprints(constraintVal);
+ }
+ else {
+ return this.eventInstancesToFootprints(eventInstances);
+ }
+ }
+ else if (constraintVal != null) {
+ eventInstances = this.eventManager.getEventInstancesWithId(constraintVal);
+ return this.eventInstancesToFootprints(eventInstances);
+ }
+ };
+ // returns ComponentFootprint[]
+ // uses current view's range
+ Constraints.prototype.buildCurrentBusinessFootprints = function (isAllDay) {
+ var view = this._calendar.view;
+ var businessHourGenerator = view.get('businessHourGenerator');
+ var unzonedRange = view.dateProfile.activeUnzonedRange;
+ var eventInstanceGroup = businessHourGenerator.buildEventInstanceGroup(isAllDay, unzonedRange);
+ if (eventInstanceGroup) {
+ return this.eventInstancesToFootprints(eventInstanceGroup.eventInstances);
+ }
+ else {
+ return [];
+ }
+ };
+ // conversion util
+ Constraints.prototype.eventInstancesToFootprints = function (eventInstances) {
+ var eventRanges = eventInstances.map(util_1.eventInstanceToEventRange);
+ var eventFootprints = this.eventRangesToEventFootprints(eventRanges);
+ return eventFootprints.map(util_1.eventFootprintToComponentFootprint);
+ };
+ // Overlap
+ // ------------------------------------------------------------------------------------------------
+ Constraints.prototype.collectOverlapEventFootprints = function (peerEventFootprints, targetFootprint) {
+ var overlapEventFootprints = [];
+ var i;
+ for (i = 0; i < peerEventFootprints.length; i++) {
+ if (this.footprintsIntersect(targetFootprint, peerEventFootprints[i].componentFootprint)) {
+ overlapEventFootprints.push(peerEventFootprints[i]);
+ }
+ }
+ return overlapEventFootprints;
+ };
+ // Conversion: eventDefs -> eventInstances -> eventRanges -> eventFootprints -> componentFootprints
+ // ------------------------------------------------------------------------------------------------
+ // NOTE: this might seem like repetitive code with the Grid class, however, this code is related to
+ // constraints whereas the Grid code is related to rendering. Each approach might want to convert
+ // eventRanges -> eventFootprints in a different way. Regardless, there are opportunities to make
+ // this more DRY.
+ /*
+ Returns false on invalid input.
+ */
+ Constraints.prototype.parseEventDefToInstances = function (eventInput) {
+ var eventManager = this.eventManager;
+ var eventDef = EventDefParser_1.default.parse(eventInput, new EventSource_1.default(this._calendar));
+ if (!eventDef) {
+ return false;
+ }
+ return eventDef.buildInstances(eventManager.currentPeriod.unzonedRange);
+ };
+ Constraints.prototype.eventRangesToEventFootprints = function (eventRanges) {
+ var i;
+ var eventFootprints = [];
+ for (i = 0; i < eventRanges.length; i++) {
+ eventFootprints.push.apply(// footprints
+ eventFootprints, this.eventRangeToEventFootprints(eventRanges[i]));
+ }
+ return eventFootprints;
+ };
+ Constraints.prototype.eventRangeToEventFootprints = function (eventRange) {
+ return [util_1.eventRangeToEventFootprint(eventRange)];
+ };
+ /*
+ Parses footprints directly.
+ Very similar to EventDateProfile::parse :(
+ */
+ Constraints.prototype.parseFootprints = function (rawInput) {
+ var start;
+ var end;
+ if (rawInput.start) {
+ start = this._calendar.moment(rawInput.start);
+ if (!start.isValid()) {
+ start = null;
+ }
+ }
+ if (rawInput.end) {
+ end = this._calendar.moment(rawInput.end);
+ if (!end.isValid()) {
+ end = null;
+ }
+ }
+ return [
+ new ComponentFootprint_1.default(new UnzonedRange_1.default(start, end), (start && !start.hasTime()) || (end && !end.hasTime()) // isAllDay
+ )
+ ];
+ };
+ // Footprint Utils
+ // ----------------------------------------------------------------------------------------
+ Constraints.prototype.footprintContainsFootprint = function (outerFootprint, innerFootprint) {
+ return outerFootprint.unzonedRange.containsRange(innerFootprint.unzonedRange);
+ };
+ Constraints.prototype.footprintsIntersect = function (footprint0, footprint1) {
+ return footprint0.unzonedRange.intersectsWith(footprint1.unzonedRange);
+ };
+ return Constraints;
+}());
+exports.default = Constraints;
+// optional subjectEventInstance
+function isOverlapsAllowedByFunc(overlapEventFootprints, overlapFunc, subjectEventInstance) {
+ var i;
+ for (i = 0; i < overlapEventFootprints.length; i++) {
+ if (!overlapFunc(overlapEventFootprints[i].eventInstance.toLegacy(), subjectEventInstance ? subjectEventInstance.toLegacy() : null)) {
+ return false;
+ }
+ }
+ return true;
+}
+function isOverlapEventInstancesAllowed(overlapEventFootprints, subjectEventInstance) {
+ var subjectLegacyInstance = subjectEventInstance.toLegacy();
+ var i;
+ var overlapEventInstance;
+ var overlapEventDef;
+ var overlapVal;
+ for (i = 0; i < overlapEventFootprints.length; i++) {
+ overlapEventInstance = overlapEventFootprints[i].eventInstance;
+ overlapEventDef = overlapEventInstance.def;
+ // don't need to pass in calendar, because don't want to consider global eventOverlap property,
+ // because we already considered that earlier in the process.
+ overlapVal = overlapEventDef.getOverlap();
+ if (overlapVal === false) {
+ return false;
+ }
+ else if (typeof overlapVal === 'function') {
+ if (!overlapVal(overlapEventInstance.toLegacy(), subjectLegacyInstance)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+/***/ }),
+/* 208 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/*
+USAGE:
+ import { default as ParsableModelMixin, ParsableModelInterface } from './ParsableModelMixin'
+in class:
+ applyProps: ParsableModelInterface['applyProps']
+ applyManualStandardProps: ParsableModelInterface['applyManualStandardProps']
+ applyMiscProps: ParsableModelInterface['applyMiscProps']
+ isStandardProp: ParsableModelInterface['isStandardProp']
+ static defineStandardProps = ParsableModelMixin.defineStandardProps
+ static copyVerbatimStandardProps = ParsableModelMixin.copyVerbatimStandardProps
+after class:
+ ParsableModelMixin.mixInto(TheClass)
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var Mixin_1 = __webpack_require__(14);
+var ParsableModelMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(ParsableModelMixin, _super);
+ function ParsableModelMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ ParsableModelMixin.defineStandardProps = function (propDefs) {
+ var proto = this.prototype;
+ if (!proto.hasOwnProperty('standardPropMap')) {
+ proto.standardPropMap = Object.create(proto.standardPropMap);
+ }
+ util_1.copyOwnProps(propDefs, proto.standardPropMap);
+ };
+ ParsableModelMixin.copyVerbatimStandardProps = function (src, dest) {
+ var map = this.prototype.standardPropMap;
+ var propName;
+ for (propName in map) {
+ if (src[propName] != null && // in the src object?
+ map[propName] === true // false means "copy verbatim"
+ ) {
+ dest[propName] = src[propName];
+ }
+ }
+ };
+ /*
+ Returns true/false for success.
+ Meant to be only called ONCE, at object creation.
+ */
+ ParsableModelMixin.prototype.applyProps = function (rawProps) {
+ var standardPropMap = this.standardPropMap;
+ var manualProps = {};
+ var miscProps = {};
+ var propName;
+ for (propName in rawProps) {
+ if (standardPropMap[propName] === true) {
+ this[propName] = rawProps[propName];
+ }
+ else if (standardPropMap[propName] === false) {
+ manualProps[propName] = rawProps[propName];
+ }
+ else {
+ miscProps[propName] = rawProps[propName];
+ }
+ }
+ this.applyMiscProps(miscProps);
+ return this.applyManualStandardProps(manualProps);
+ };
+ /*
+ If subclasses override, they must call this supermethod and return the boolean response.
+ Meant to be only called ONCE, at object creation.
+ */
+ ParsableModelMixin.prototype.applyManualStandardProps = function (rawProps) {
+ return true;
+ };
+ /*
+ Can be called even after initial object creation.
+ */
+ ParsableModelMixin.prototype.applyMiscProps = function (rawProps) {
+ // subclasses can implement
+ };
+ /*
+ TODO: why is this a method when defineStandardProps is static
+ */
+ ParsableModelMixin.prototype.isStandardProp = function (propName) {
+ return propName in this.standardPropMap;
+ };
+ return ParsableModelMixin;
+}(Mixin_1.default));
+exports.default = ParsableModelMixin;
+ParsableModelMixin.prototype.standardPropMap = {}; // will be cloned by defineStandardProps
+
+
+/***/ }),
+/* 209 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventInstance = /** @class */ (function () {
+ function EventInstance(def, dateProfile) {
+ this.def = def;
+ this.dateProfile = dateProfile;
+ }
+ EventInstance.prototype.toLegacy = function () {
+ var dateProfile = this.dateProfile;
+ var obj = this.def.toLegacy();
+ obj.start = dateProfile.start.clone();
+ obj.end = dateProfile.end ? dateProfile.end.clone() : null;
+ return obj;
+ };
+ return EventInstance;
+}());
+exports.default = EventInstance;
+
+
+/***/ }),
+/* 210 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var EventDef_1 = __webpack_require__(34);
+var EventInstance_1 = __webpack_require__(209);
+var EventDateProfile_1 = __webpack_require__(17);
+var RecurringEventDef = /** @class */ (function (_super) {
+ tslib_1.__extends(RecurringEventDef, _super);
+ function RecurringEventDef() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ RecurringEventDef.prototype.isAllDay = function () {
+ return !this.startTime && !this.endTime;
+ };
+ RecurringEventDef.prototype.buildInstances = function (unzonedRange) {
+ var calendar = this.source.calendar;
+ var unzonedDate = unzonedRange.getStart();
+ var unzonedEnd = unzonedRange.getEnd();
+ var zonedDayStart;
+ var instanceStart;
+ var instanceEnd;
+ var instances = [];
+ while (unzonedDate.isBefore(unzonedEnd)) {
+ // if everyday, or this particular day-of-week
+ if (!this.dowHash || this.dowHash[unzonedDate.day()]) {
+ zonedDayStart = calendar.applyTimezone(unzonedDate);
+ instanceStart = zonedDayStart.clone();
+ instanceEnd = null;
+ if (this.startTime) {
+ instanceStart.time(this.startTime);
+ }
+ else {
+ instanceStart.stripTime();
+ }
+ if (this.endTime) {
+ instanceEnd = zonedDayStart.clone().time(this.endTime);
+ }
+ instances.push(new EventInstance_1.default(this, // definition
+ new EventDateProfile_1.default(instanceStart, instanceEnd, calendar)));
+ }
+ unzonedDate.add(1, 'days');
+ }
+ return instances;
+ };
+ RecurringEventDef.prototype.setDow = function (dowNumbers) {
+ if (!this.dowHash) {
+ this.dowHash = {};
+ }
+ for (var i = 0; i < dowNumbers.length; i++) {
+ this.dowHash[dowNumbers[i]] = true;
+ }
+ };
+ RecurringEventDef.prototype.clone = function () {
+ var def = _super.prototype.clone.call(this);
+ if (def.startTime) {
+ def.startTime = moment.duration(this.startTime);
+ }
+ if (def.endTime) {
+ def.endTime = moment.duration(this.endTime);
+ }
+ if (this.dowHash) {
+ def.dowHash = $.extend({}, this.dowHash);
+ }
+ return def;
+ };
+ return RecurringEventDef;
+}(EventDef_1.default));
+exports.default = RecurringEventDef;
+/*
+HACK to work with TypeScript mixins
+NOTE: if super-method fails, should still attempt to apply
+*/
+RecurringEventDef.prototype.applyProps = function (rawProps) {
+ var superSuccess = EventDef_1.default.prototype.applyProps.call(this, rawProps);
+ if (rawProps.start) {
+ this.startTime = moment.duration(rawProps.start);
+ }
+ if (rawProps.end) {
+ this.endTime = moment.duration(rawProps.end);
+ }
+ if (rawProps.dow) {
+ this.setDow(rawProps.dow);
+ }
+ return superSuccess;
+};
+// Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+RecurringEventDef.defineStandardProps({
+ start: false,
+ end: false,
+ dow: false
+});
+
+
+/***/ }),
+/* 211 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventRange = /** @class */ (function () {
+ function EventRange(unzonedRange, eventDef, eventInstance) {
+ this.unzonedRange = unzonedRange;
+ this.eventDef = eventDef;
+ if (eventInstance) {
+ this.eventInstance = eventInstance;
+ }
+ }
+ return EventRange;
+}());
+exports.default = EventRange;
+
+
+/***/ }),
+/* 212 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(35);
+var EventInstanceGroup_1 = __webpack_require__(18);
+var RecurringEventDef_1 = __webpack_require__(210);
+var EventSource_1 = __webpack_require__(6);
+var BUSINESS_HOUR_EVENT_DEFAULTS = {
+ start: '09:00',
+ end: '17:00',
+ dow: [1, 2, 3, 4, 5],
+ rendering: 'inverse-background'
+ // classNames are defined in businessHoursSegClasses
+};
+var BusinessHourGenerator = /** @class */ (function () {
+ function BusinessHourGenerator(rawComplexDef, calendar) {
+ this.rawComplexDef = rawComplexDef;
+ this.calendar = calendar;
+ }
+ BusinessHourGenerator.prototype.buildEventInstanceGroup = function (isAllDay, unzonedRange) {
+ var eventDefs = this.buildEventDefs(isAllDay);
+ var eventInstanceGroup;
+ if (eventDefs.length) {
+ eventInstanceGroup = new EventInstanceGroup_1.default(util_1.eventDefsToEventInstances(eventDefs, unzonedRange));
+ // so that inverse-background rendering can happen even when no eventRanges in view
+ eventInstanceGroup.explicitEventDef = eventDefs[0];
+ return eventInstanceGroup;
+ }
+ };
+ BusinessHourGenerator.prototype.buildEventDefs = function (isAllDay) {
+ var rawComplexDef = this.rawComplexDef;
+ var rawDefs = [];
+ var requireDow = false;
+ var i;
+ var defs = [];
+ if (rawComplexDef === true) {
+ rawDefs = [{}]; // will get BUSINESS_HOUR_EVENT_DEFAULTS verbatim
+ }
+ else if ($.isPlainObject(rawComplexDef)) {
+ rawDefs = [rawComplexDef];
+ }
+ else if ($.isArray(rawComplexDef)) {
+ rawDefs = rawComplexDef;
+ requireDow = true; // every sub-definition NEEDS a day-of-week
+ }
+ for (i = 0; i < rawDefs.length; i++) {
+ if (!requireDow || rawDefs[i].dow) {
+ defs.push(this.buildEventDef(isAllDay, rawDefs[i]));
+ }
+ }
+ return defs;
+ };
+ BusinessHourGenerator.prototype.buildEventDef = function (isAllDay, rawDef) {
+ var fullRawDef = $.extend({}, BUSINESS_HOUR_EVENT_DEFAULTS, rawDef);
+ if (isAllDay) {
+ fullRawDef.start = null;
+ fullRawDef.end = null;
+ }
+ return RecurringEventDef_1.default.parse(fullRawDef, new EventSource_1.default(this.calendar) // dummy source
+ );
+ };
+ return BusinessHourGenerator;
+}());
+exports.default = BusinessHourGenerator;
+
+
+/***/ }),
+/* 213 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Theme_1 = __webpack_require__(19);
+var StandardTheme = /** @class */ (function (_super) {
+ tslib_1.__extends(StandardTheme, _super);
+ function StandardTheme() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return StandardTheme;
+}(Theme_1.default));
+exports.default = StandardTheme;
+StandardTheme.prototype.classes = {
+ widget: 'fc-unthemed',
+ widgetHeader: 'fc-widget-header',
+ widgetContent: 'fc-widget-content',
+ buttonGroup: 'fc-button-group',
+ button: 'fc-button',
+ cornerLeft: 'fc-corner-left',
+ cornerRight: 'fc-corner-right',
+ stateDefault: 'fc-state-default',
+ stateActive: 'fc-state-active',
+ stateDisabled: 'fc-state-disabled',
+ stateHover: 'fc-state-hover',
+ stateDown: 'fc-state-down',
+ popoverHeader: 'fc-widget-header',
+ popoverContent: 'fc-widget-content',
+ // day grid
+ headerRow: 'fc-widget-header',
+ dayRow: 'fc-widget-content',
+ // list view
+ listView: 'fc-widget-content'
+};
+StandardTheme.prototype.baseIconClass = 'fc-icon';
+StandardTheme.prototype.iconClasses = {
+ close: 'fc-icon-x',
+ prev: 'fc-icon-left-single-arrow',
+ next: 'fc-icon-right-single-arrow',
+ prevYear: 'fc-icon-left-double-arrow',
+ nextYear: 'fc-icon-right-double-arrow'
+};
+StandardTheme.prototype.iconOverrideOption = 'buttonIcons';
+StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon';
+StandardTheme.prototype.iconOverridePrefix = 'fc-icon-';
+
+
+/***/ }),
+/* 214 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Theme_1 = __webpack_require__(19);
+var JqueryUiTheme = /** @class */ (function (_super) {
+ tslib_1.__extends(JqueryUiTheme, _super);
+ function JqueryUiTheme() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return JqueryUiTheme;
+}(Theme_1.default));
+exports.default = JqueryUiTheme;
+JqueryUiTheme.prototype.classes = {
+ widget: 'ui-widget',
+ widgetHeader: 'ui-widget-header',
+ widgetContent: 'ui-widget-content',
+ buttonGroup: 'fc-button-group',
+ button: 'ui-button',
+ cornerLeft: 'ui-corner-left',
+ cornerRight: 'ui-corner-right',
+ stateDefault: 'ui-state-default',
+ stateActive: 'ui-state-active',
+ stateDisabled: 'ui-state-disabled',
+ stateHover: 'ui-state-hover',
+ stateDown: 'ui-state-down',
+ today: 'ui-state-highlight',
+ popoverHeader: 'ui-widget-header',
+ popoverContent: 'ui-widget-content',
+ // day grid
+ headerRow: 'ui-widget-header',
+ dayRow: 'ui-widget-content',
+ // list view
+ listView: 'ui-widget-content'
+};
+JqueryUiTheme.prototype.baseIconClass = 'ui-icon';
+JqueryUiTheme.prototype.iconClasses = {
+ close: 'ui-icon-closethick',
+ prev: 'ui-icon-circle-triangle-w',
+ next: 'ui-icon-circle-triangle-e',
+ prevYear: 'ui-icon-seek-prev',
+ nextYear: 'ui-icon-seek-next'
+};
+JqueryUiTheme.prototype.iconOverrideOption = 'themeButtonIcons';
+JqueryUiTheme.prototype.iconOverrideCustomButtonOption = 'themeIcon';
+JqueryUiTheme.prototype.iconOverridePrefix = 'ui-icon-';
+
+
+/***/ }),
+/* 215 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var Promise_1 = __webpack_require__(20);
+var EventSource_1 = __webpack_require__(6);
+var FuncEventSource = /** @class */ (function (_super) {
+ tslib_1.__extends(FuncEventSource, _super);
+ function FuncEventSource() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ FuncEventSource.parse = function (rawInput, calendar) {
+ var rawProps;
+ // normalize raw input
+//console.log(rawInput);
+ if ($.isFunction(rawInput.events)) {
+ rawProps = rawInput;
+ }
+ else if ($.isFunction(rawInput)) {
+ rawProps = { events: rawInput };
+ }
+ if (rawProps) {
+ return EventSource_1.default.parse.call(this, rawProps, calendar);
+ }
+ return false;
+ };
+ FuncEventSource.prototype.fetch = function (start, end, timezone) {
+ var _this = this;
+ this.calendar.pushLoading();
+ return Promise_1.default.construct(function (onResolve) {
+ _this.func.call(_this.calendar, start.clone(), end.clone(), timezone, function (rawEventDefs) {
+ _this.calendar.popLoading();
+ onResolve(_this.parseEventDefs(rawEventDefs));
+ });
+ });
+ };
+ FuncEventSource.prototype.getPrimitive = function () {
+ return this.func;
+ };
+ FuncEventSource.prototype.applyManualStandardProps = function (rawProps) {
+ var superSuccess = _super.prototype.applyManualStandardProps.call(this, rawProps);
+ this.func = rawProps.events;
+ return superSuccess;
+ };
+ return FuncEventSource;
+}(EventSource_1.default));
+exports.default = FuncEventSource;
+FuncEventSource.defineStandardProps({
+ events: false // don't automatically transfer
+});
+
+
+/***/ }),
+/* 216 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Promise_1 = __webpack_require__(20);
+var EventSource_1 = __webpack_require__(6);
+var JsonFeedEventSource = /** @class */ (function (_super) {
+ tslib_1.__extends(JsonFeedEventSource, _super);
+ function JsonFeedEventSource() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ JsonFeedEventSource.parse = function (rawInput, calendar) {
+ var rawProps;
+ // normalize raw input
+// return false;
+ if (typeof rawInput.url === 'string') {
+ rawProps = rawInput;
+ }
+ else if (typeof rawInput === 'string') {
+ rawProps = { url: rawInput };
+ }
+ if (rawProps) {
+ return EventSource_1.default.parse.call(this, rawProps, calendar);
+ }
+ return false;
+ };
+ JsonFeedEventSource.prototype.fetch = function (start, end, timezone) {
+ var _this = this;
+ var ajaxSettings = this.ajaxSettings;
+ var onSuccess = ajaxSettings.success;
+ var onError = ajaxSettings.error;
+ var requestParams = this.buildRequestParams(start, end, timezone);
+ // todo: eventually handle the promise's then,
+ // don't intercept success/error
+ // tho will be a breaking API change
+ this.calendar.pushLoading();
+ return Promise_1.default.construct(function (onResolve, onReject) {
+ $.ajax($.extend({}, // destination
+ JsonFeedEventSource.AJAX_DEFAULTS, ajaxSettings, {
+ url: _this.url,
+ data: requestParams,
+ success: function (rawEventDefs, status, xhr) {
+ var callbackRes;
+ _this.calendar.popLoading();
+ if (rawEventDefs) {
+ callbackRes = util_1.applyAll(onSuccess, _this, [rawEventDefs, status, xhr]); // redirect `this`
+ if ($.isArray(callbackRes)) {
+ rawEventDefs = callbackRes;
+ }
+ onResolve(_this.parseEventDefs(rawEventDefs));
+ }
+ else {
+ onReject();
+ }
+ },
+ error: function (xhr, statusText, errorThrown) {
+ _this.calendar.popLoading();
+ util_1.applyAll(onError, _this, [xhr, statusText, errorThrown]); // redirect `this`
+ onReject();
+ }
+ }));
+ });
+ };
+ JsonFeedEventSource.prototype.buildRequestParams = function (start, end, timezone) {
+ var calendar = this.calendar;
+ var ajaxSettings = this.ajaxSettings;
+ var startParam;
+ var endParam;
+ var timezoneParam;
+ var customRequestParams;
+ var params = {};
+ startParam = this.startParam;
+ if (startParam == null) {
+ startParam = calendar.opt('startParam');
+ }
+ endParam = this.endParam;
+ if (endParam == null) {
+ endParam = calendar.opt('endParam');
+ }
+ timezoneParam = this.timezoneParam;
+ if (timezoneParam == null) {
+ timezoneParam = calendar.opt('timezoneParam');
+ }
+ // retrieve any outbound GET/POST $.ajax data from the options
+ if ($.isFunction(ajaxSettings.data)) {
+ // supplied as a function that returns a key/value object
+ customRequestParams = ajaxSettings.data();
+ }
+ else {
+ // probably supplied as a straight key/value object
+ customRequestParams = ajaxSettings.data || {};
+ }
+ $.extend(params, customRequestParams);
+ params[startParam] = start.format();
+ params[endParam] = end.format();
+ if (timezone && timezone !== 'local') {
+ params[timezoneParam] = timezone;
+ }
+ return params;
+ };
+ JsonFeedEventSource.prototype.getPrimitive = function () {
+ return this.url;
+ };
+ JsonFeedEventSource.prototype.applyMiscProps = function (rawProps) {
+ this.ajaxSettings = rawProps;
+ };
+ JsonFeedEventSource.AJAX_DEFAULTS = {
+ dataType: 'json',
+ cache: false
+ };
+ return JsonFeedEventSource;
+}(EventSource_1.default));
+exports.default = JsonFeedEventSource;
+JsonFeedEventSource.defineStandardProps({
+ // automatically transfer (true)...
+ url: true,
+ startParam: true,
+ endParam: true,
+ timezoneParam: true
+});
+
+
+/***/ }),
+/* 217 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EmitterMixin_1 = __webpack_require__(11);
+var TaskQueue = /** @class */ (function () {
+ function TaskQueue() {
+ this.q = [];
+ this.isPaused = false;
+ this.isRunning = false;
+ }
+ TaskQueue.prototype.queue = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ this.q.push.apply(this.q, args); // append
+ this.tryStart();
+ };
+ TaskQueue.prototype.pause = function () {
+ this.isPaused = true;
+ };
+ TaskQueue.prototype.resume = function () {
+ this.isPaused = false;
+ this.tryStart();
+ };
+ TaskQueue.prototype.getIsIdle = function () {
+ return !this.isRunning && !this.isPaused;
+ };
+ TaskQueue.prototype.tryStart = function () {
+ if (!this.isRunning && this.canRunNext()) {
+ this.isRunning = true;
+ this.trigger('start');
+ this.runRemaining();
+ }
+ };
+ TaskQueue.prototype.canRunNext = function () {
+ return !this.isPaused && this.q.length;
+ };
+ TaskQueue.prototype.runRemaining = function () {
+ var _this = this;
+ var task;
+ var res;
+ do {
+ task = this.q.shift(); // always freshly reference q. might have been reassigned.
+ res = this.runTask(task);
+ if (res && res.then) {
+ res.then(function () {
+ if (_this.canRunNext()) {
+ _this.runRemaining();
+ }
+ });
+ return; // prevent marking as stopped
+ }
+ } while (this.canRunNext());
+ this.trigger('stop'); // not really a 'stop' ... more of a 'drained'
+ this.isRunning = false;
+ // if 'stop' handler added more tasks.... TODO: write test for this
+ this.tryStart();
+ };
+ TaskQueue.prototype.runTask = function (task) {
+ return task(); // task *is* the function, but subclasses can change the format of a task
+ };
+ return TaskQueue;
+}());
+exports.default = TaskQueue;
+EmitterMixin_1.default.mixInto(TaskQueue);
+
+
+/***/ }),
+/* 218 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var TaskQueue_1 = __webpack_require__(217);
+var RenderQueue = /** @class */ (function (_super) {
+ tslib_1.__extends(RenderQueue, _super);
+ function RenderQueue(waitsByNamespace) {
+ var _this = _super.call(this) || this;
+ _this.waitsByNamespace = waitsByNamespace || {};
+ return _this;
+ }
+ RenderQueue.prototype.queue = function (taskFunc, namespace, type) {
+ var task = {
+ func: taskFunc,
+ namespace: namespace,
+ type: type
+ };
+ var waitMs;
+ if (namespace) {
+ waitMs = this.waitsByNamespace[namespace];
+ }
+ if (this.waitNamespace) {
+ if (namespace === this.waitNamespace && waitMs != null) {
+ this.delayWait(waitMs);
+ }
+ else {
+ this.clearWait();
+ this.tryStart();
+ }
+ }
+ if (this.compoundTask(task)) {
+ if (!this.waitNamespace && waitMs != null) {
+ this.startWait(namespace, waitMs);
+ }
+ else {
+ this.tryStart();
+ }
+ }
+ };
+ RenderQueue.prototype.startWait = function (namespace, waitMs) {
+ this.waitNamespace = namespace;
+ this.spawnWait(waitMs);
+ };
+ RenderQueue.prototype.delayWait = function (waitMs) {
+ clearTimeout(this.waitId);
+ this.spawnWait(waitMs);
+ };
+ RenderQueue.prototype.spawnWait = function (waitMs) {
+ var _this = this;
+ this.waitId = setTimeout(function () {
+ _this.waitNamespace = null;
+ _this.tryStart();
+ }, waitMs);
+ };
+ RenderQueue.prototype.clearWait = function () {
+ if (this.waitNamespace) {
+ clearTimeout(this.waitId);
+ this.waitId = null;
+ this.waitNamespace = null;
+ }
+ };
+ RenderQueue.prototype.canRunNext = function () {
+ if (!_super.prototype.canRunNext.call(this)) {
+ return false;
+ }
+ // waiting for a certain namespace to stop receiving tasks?
+ if (this.waitNamespace) {
+ var q = this.q;
+ // if there was a different namespace task in the meantime,
+ // that forces all previously-waiting tasks to suddenly execute.
+ // TODO: find a way to do this in constant time.
+ for (var i = 0; i < q.length; i++) {
+ if (q[i].namespace !== this.waitNamespace) {
+ return true; // allow execution
+ }
+ }
+ return false;
+ }
+ return true;
+ };
+ RenderQueue.prototype.runTask = function (task) {
+ task.func();
+ };
+ RenderQueue.prototype.compoundTask = function (newTask) {
+ var q = this.q;
+ var shouldAppend = true;
+ var i;
+ var task;
+ if (newTask.namespace && newTask.type === 'destroy') {
+ // remove all init/add/remove ops with same namespace, regardless of order
+ for (i = q.length - 1; i >= 0; i--) {
+ task = q[i];
+ switch (task.type) {
+ case 'init':
+ shouldAppend = false;
+ // the latest destroy is cancelled out by not doing the init
+ /* falls through */
+ case 'add':
+ /* falls through */
+ case 'remove':
+ q.splice(i, 1); // remove task
+ }
+ }
+ }
+ if (shouldAppend) {
+ q.push(newTask);
+ }
+ return shouldAppend;
+ };
+ return RenderQueue;
+}(TaskQueue_1.default));
+exports.default = RenderQueue;
+
+
+/***/ }),
+/* 219 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var moment_ext_1 = __webpack_require__(10);
+var date_formatting_1 = __webpack_require__(47);
+var Component_1 = __webpack_require__(237);
+var util_2 = __webpack_require__(35);
+var DateComponent = /** @class */ (function (_super) {
+ tslib_1.__extends(DateComponent, _super);
+ function DateComponent(_view, _options) {
+ var _this = _super.call(this) || this;
+ _this.isRTL = false; // frequently accessed options
+ _this.hitsNeededDepth = 0; // necessary because multiple callers might need the same hits
+ _this.hasAllDayBusinessHours = false; // TODO: unify with largeUnit and isTimeScale?
+ _this.isDatesRendered = false;
+ // hack to set options prior to the this.opt calls
+ if (_view) {
+ _this['view'] = _view;
+ }
+ if (_options) {
+ _this['options'] = _options;
+ }
+ _this.uid = String(DateComponent.guid++);
+ _this.childrenByUid = {};
+ _this.nextDayThreshold = moment.duration(_this.opt('nextDayThreshold'));
+ _this.isRTL = _this.opt('isRTL');
+ if (_this.fillRendererClass) {
+ _this.fillRenderer = new _this.fillRendererClass(_this);
+ }
+ if (_this.eventRendererClass) {
+ _this.eventRenderer = new _this.eventRendererClass(_this, _this.fillRenderer);
+ }
+ if (_this.helperRendererClass && _this.eventRenderer) {
+ _this.helperRenderer = new _this.helperRendererClass(_this, _this.eventRenderer);
+ }
+ if (_this.businessHourRendererClass && _this.fillRenderer) {
+ _this.businessHourRenderer = new _this.businessHourRendererClass(_this, _this.fillRenderer);
+ }
+ return _this;
+ }
+ DateComponent.prototype.addChild = function (child) {
+ if (!this.childrenByUid[child.uid]) {
+ this.childrenByUid[child.uid] = child;
+ return true;
+ }
+ return false;
+ };
+ DateComponent.prototype.removeChild = function (child) {
+ if (this.childrenByUid[child.uid]) {
+ delete this.childrenByUid[child.uid];
+ return true;
+ }
+ return false;
+ };
+ // TODO: only do if isInDom?
+ // TODO: make part of Component, along with children/batch-render system?
+ DateComponent.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ this.callChildren('updateSize', arguments);
+ };
+ // Options
+ // -----------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.opt = function (name) {
+ return this._getView().opt(name); // default implementation
+ };
+ DateComponent.prototype.publiclyTrigger = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ var calendar = this._getCalendar();
+ return calendar.publiclyTrigger.apply(calendar, args);
+ };
+ DateComponent.prototype.hasPublicHandlers = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ var calendar = this._getCalendar();
+ return calendar.hasPublicHandlers.apply(calendar, args);
+ };
+ // Date
+ // -----------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.executeDateRender = function (dateProfile) {
+ this.dateProfile = dateProfile; // for rendering
+ this.renderDates(dateProfile);
+ this.isDatesRendered = true;
+ this.callChildren('executeDateRender', arguments);
+ };
+ DateComponent.prototype.executeDateUnrender = function () {
+ this.callChildren('executeDateUnrender', arguments);
+ this.dateProfile = null;
+ this.unrenderDates();
+ this.isDatesRendered = false;
+ };
+ // date-cell content only
+ DateComponent.prototype.renderDates = function (dateProfile) {
+ // subclasses should implement
+ };
+ // date-cell content only
+ DateComponent.prototype.unrenderDates = function () {
+ // subclasses should override
+ };
+ // Now-Indicator
+ // -----------------------------------------------------------------------------------------------------------------
+ // Returns a string unit, like 'second' or 'minute' that defined how often the current time indicator
+ // should be refreshed. If something falsy is returned, no time indicator is rendered at all.
+ DateComponent.prototype.getNowIndicatorUnit = function () {
+ // subclasses should implement
+ };
+ // Renders a current time indicator at the given datetime
+ DateComponent.prototype.renderNowIndicator = function (date) {
+ this.callChildren('renderNowIndicator', arguments);
+ };
+ // Undoes the rendering actions from renderNowIndicator
+ DateComponent.prototype.unrenderNowIndicator = function () {
+ this.callChildren('unrenderNowIndicator', arguments);
+ };
+ // Business Hours
+ // ---------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.renderBusinessHours = function (businessHourGenerator) {
+ if (this.businessHourRenderer) {
+ this.businessHourRenderer.render(businessHourGenerator);
+ }
+ this.callChildren('renderBusinessHours', arguments);
+ };
+ // Unrenders previously-rendered business-hours
+ DateComponent.prototype.unrenderBusinessHours = function () {
+ this.callChildren('unrenderBusinessHours', arguments);
+ if (this.businessHourRenderer) {
+ this.businessHourRenderer.unrender();
+ }
+ };
+ // Event Displaying
+ // -----------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.executeEventRender = function (eventsPayload) {
+ if (this.eventRenderer) {
+ this.eventRenderer.rangeUpdated(); // poorly named now
+ this.eventRenderer.render(eventsPayload);
+ }
+ else if (this['renderEvents']) {
+ this['renderEvents'](convertEventsPayloadToLegacyArray(eventsPayload));
+ }
+ this.callChildren('executeEventRender', arguments);
+ };
+ DateComponent.prototype.executeEventUnrender = function () {
+ this.callChildren('executeEventUnrender', arguments);
+ if (this.eventRenderer) {
+ this.eventRenderer.unrender();
+ }
+ else if (this['destroyEvents']) {
+ this['destroyEvents']();
+ }
+ };
+ DateComponent.prototype.getBusinessHourSegs = function () {
+ var segs = this.getOwnBusinessHourSegs();
+ this.iterChildren(function (child) {
+ segs.push.apply(segs, child.getBusinessHourSegs());
+ });
+ return segs;
+ };
+ DateComponent.prototype.getOwnBusinessHourSegs = function () {
+ if (this.businessHourRenderer) {
+ return this.businessHourRenderer.getSegs();
+ }
+ return [];
+ };
+ DateComponent.prototype.getEventSegs = function () {
+ var segs = this.getOwnEventSegs();
+ this.iterChildren(function (child) {
+ segs.push.apply(segs, child.getEventSegs());
+ });
+ return segs;
+ };
+ DateComponent.prototype.getOwnEventSegs = function () {
+ if (this.eventRenderer) {
+ return this.eventRenderer.getSegs();
+ }
+ return [];
+ };
+ // Event Rendering Triggering
+ // -----------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.triggerAfterEventsRendered = function () {
+ this.triggerAfterEventSegsRendered(this.getEventSegs());
+ this.publiclyTrigger('eventAfterAllRender', {
+ context: this,
+ args: [this]
+ });
+ };
+ DateComponent.prototype.triggerAfterEventSegsRendered = function (segs) {
+ var _this = this;
+ // an optimization, because getEventLegacy is expensive
+ if (this.hasPublicHandlers('eventAfterRender')) {
+ segs.forEach(function (seg) {
+ var legacy;
+ if (seg.el) {
+ legacy = seg.footprint.getEventLegacy();
+ _this.publiclyTrigger('eventAfterRender', {
+ context: legacy,
+ args: [legacy, seg.el, _this]
+ });
+ }
+ });
+ }
+ };
+ DateComponent.prototype.triggerBeforeEventsDestroyed = function () {
+ this.triggerBeforeEventSegsDestroyed(this.getEventSegs());
+ };
+ DateComponent.prototype.triggerBeforeEventSegsDestroyed = function (segs) {
+ var _this = this;
+ if (this.hasPublicHandlers('eventDestroy')) {
+ segs.forEach(function (seg) {
+ var legacy;
+ if (seg.el) {
+ legacy = seg.footprint.getEventLegacy();
+ _this.publiclyTrigger('eventDestroy', {
+ context: legacy,
+ args: [legacy, seg.el, _this]
+ });
+ }
+ });
+ }
+ };
+ // Event Rendering Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ // Hides all rendered event segments linked to the given event
+ // RECURSIVE with subcomponents
+ DateComponent.prototype.showEventsWithId = function (eventDefId) {
+ this.getEventSegs().forEach(function (seg) {
+ if (seg.footprint.eventDef.id === eventDefId &&
+ seg.el // necessary?
+ ) {
+ seg.el.css('visibility', '');
+ }
+ });
+ this.callChildren('showEventsWithId', arguments);
+ };
+ // Shows all rendered event segments linked to the given event
+ // RECURSIVE with subcomponents
+ DateComponent.prototype.hideEventsWithId = function (eventDefId) {
+ this.getEventSegs().forEach(function (seg) {
+ if (seg.footprint.eventDef.id === eventDefId &&
+ seg.el // necessary?
+ ) {
+ seg.el.css('visibility', 'hidden');
+ }
+ });
+ this.callChildren('hideEventsWithId', arguments);
+ };
+ // Drag-n-Drop Rendering (for both events and external elements)
+ // ---------------------------------------------------------------------------------------------------------------
+ // Renders a visual indication of a event or external-element drag over the given drop zone.
+ // If an external-element, seg will be `null`.
+ // Must return elements used for any mock events.
+ DateComponent.prototype.renderDrag = function (eventFootprints, seg, isTouch) {
+ var renderedHelper = false;
+ this.iterChildren(function (child) {
+ if (child.renderDrag(eventFootprints, seg, isTouch)) {
+ renderedHelper = true;
+ }
+ });
+ return renderedHelper;
+ };
+ // Unrenders a visual indication of an event or external-element being dragged.
+ DateComponent.prototype.unrenderDrag = function () {
+ this.callChildren('unrenderDrag', arguments);
+ };
+ // Event Resizing
+ // ---------------------------------------------------------------------------------------------------------------
+ // Renders a visual indication of an event being resized.
+ DateComponent.prototype.renderEventResize = function (eventFootprints, seg, isTouch) {
+ this.callChildren('renderEventResize', arguments);
+ };
+ // Unrenders a visual indication of an event being resized.
+ DateComponent.prototype.unrenderEventResize = function () {
+ this.callChildren('unrenderEventResize', arguments);
+ };
+ // Selection
+ // ---------------------------------------------------------------------------------------------------------------
+ // Renders a visual indication of the selection
+ // TODO: rename to `renderSelection` after legacy is gone
+ DateComponent.prototype.renderSelectionFootprint = function (componentFootprint) {
+ this.renderHighlight(componentFootprint);
+ this.callChildren('renderSelectionFootprint', arguments);
+ };
+ // Unrenders a visual indication of selection
+ DateComponent.prototype.unrenderSelection = function () {
+ this.unrenderHighlight();
+ this.callChildren('unrenderSelection', arguments);
+ };
+ // Highlight
+ // ---------------------------------------------------------------------------------------------------------------
+ // Renders an emphasis on the given date range. Given a span (unzoned start/end and other misc data)
+ DateComponent.prototype.renderHighlight = function (componentFootprint) {
+ if (this.fillRenderer) {
+ this.fillRenderer.renderFootprint('highlight', componentFootprint, {
+ getClasses: function () {
+ return ['fc-highlight'];
+ }
+ });
+ }
+ this.callChildren('renderHighlight', arguments);
+ };
+ // Unrenders the emphasis on a date range
+ DateComponent.prototype.unrenderHighlight = function () {
+ if (this.fillRenderer) {
+ this.fillRenderer.unrender('highlight');
+ }
+ this.callChildren('unrenderHighlight', arguments);
+ };
+ // Hit Areas
+ // ---------------------------------------------------------------------------------------------------------------
+ // just because all DateComponents support this interface
+ // doesn't mean they need to have their own internal coord system. they can defer to sub-components.
+ DateComponent.prototype.hitsNeeded = function () {
+ if (!(this.hitsNeededDepth++)) {
+ this.prepareHits();
+ }
+ this.callChildren('hitsNeeded', arguments);
+ };
+ DateComponent.prototype.hitsNotNeeded = function () {
+ if (this.hitsNeededDepth && !(--this.hitsNeededDepth)) {
+ this.releaseHits();
+ }
+ this.callChildren('hitsNotNeeded', arguments);
+ };
+ DateComponent.prototype.prepareHits = function () {
+ // subclasses can implement
+ };
+ DateComponent.prototype.releaseHits = function () {
+ // subclasses can implement
+ };
+ // Given coordinates from the topleft of the document, return data about the date-related area underneath.
+ // Can return an object with arbitrary properties (although top/right/left/bottom are encouraged).
+ // Must have a `grid` property, a reference to this current grid. TODO: avoid this
+ // The returned object will be processed by getHitFootprint and getHitEl.
+ DateComponent.prototype.queryHit = function (leftOffset, topOffset) {
+ var childrenByUid = this.childrenByUid;
+ var uid;
+ var hit;
+ for (uid in childrenByUid) {
+ hit = childrenByUid[uid].queryHit(leftOffset, topOffset);
+ if (hit) {
+ break;
+ }
+ }
+ return hit;
+ };
+ DateComponent.prototype.getSafeHitFootprint = function (hit) {
+ var footprint = this.getHitFootprint(hit);
+ if (!this.dateProfile.activeUnzonedRange.containsRange(footprint.unzonedRange)) {
+ return null;
+ }
+ return footprint;
+ };
+ DateComponent.prototype.getHitFootprint = function (hit) {
+ // what about being abstract!?
+ };
+ // Given position-level information about a date-related area within the grid,
+ // should return a jQuery element that best represents it. passed to dayClick callback.
+ DateComponent.prototype.getHitEl = function (hit) {
+ // what about being abstract!?
+ };
+ /* Converting eventRange -> eventFootprint
+ ------------------------------------------------------------------------------------------------------------------*/
+ DateComponent.prototype.eventRangesToEventFootprints = function (eventRanges) {
+ var eventFootprints = [];
+ var i;
+ for (i = 0; i < eventRanges.length; i++) {
+ eventFootprints.push.apply(// append
+ eventFootprints, this.eventRangeToEventFootprints(eventRanges[i]));
+ }
+ return eventFootprints;
+ };
+ DateComponent.prototype.eventRangeToEventFootprints = function (eventRange) {
+ return [util_2.eventRangeToEventFootprint(eventRange)];
+ };
+ /* Converting componentFootprint/eventFootprint -> segs
+ ------------------------------------------------------------------------------------------------------------------*/
+ DateComponent.prototype.eventFootprintsToSegs = function (eventFootprints) {
+ var segs = [];
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ segs.push.apply(segs, this.eventFootprintToSegs(eventFootprints[i]));
+ }
+ return segs;
+ };
+ // Given an event's span (unzoned start/end and other misc data), and the event itself,
+ // slices into segments and attaches event-derived properties to them.
+ // eventSpan - { start, end, isStart, isEnd, otherthings... }
+ DateComponent.prototype.eventFootprintToSegs = function (eventFootprint) {
+ var unzonedRange = eventFootprint.componentFootprint.unzonedRange;
+ var segs;
+ var i;
+ var seg;
+ segs = this.componentFootprintToSegs(eventFootprint.componentFootprint);
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ if (!unzonedRange.isStart) {
+ seg.isStart = false;
+ }
+ if (!unzonedRange.isEnd) {
+ seg.isEnd = false;
+ }
+ seg.footprint = eventFootprint;
+ // TODO: rename to seg.eventFootprint
+ }
+ return segs;
+ };
+ DateComponent.prototype.componentFootprintToSegs = function (componentFootprint) {
+ return [];
+ };
+ // Utils
+ // ---------------------------------------------------------------------------------------------------------------
+ DateComponent.prototype.callChildren = function (methodName, args) {
+ this.iterChildren(function (child) {
+ child[methodName].apply(child, args);
+ });
+ };
+ DateComponent.prototype.iterChildren = function (func) {
+ var childrenByUid = this.childrenByUid;
+ var uid;
+ for (uid in childrenByUid) {
+ func(childrenByUid[uid]);
+ }
+ };
+ DateComponent.prototype._getCalendar = function () {
+ var t = this;
+ return t.calendar || t.view.calendar;
+ };
+ DateComponent.prototype._getView = function () {
+ return this.view;
+ };
+ DateComponent.prototype._getDateProfile = function () {
+ return this._getView().get('dateProfile');
+ };
+ // Generates HTML for an anchor to another view into the calendar.
+ // Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings.
+ // `gotoOptions` can either be a moment input, or an object with the form:
+ // { date, type, forceOff }
+ // `type` is a view-type like "day" or "week". default value is "day".
+ // `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
+ DateComponent.prototype.buildGotoAnchorHtml = function (gotoOptions, attrs, innerHtml) {
+ var date;
+ var type;
+ var forceOff;
+ var finalOptions;
+ if ($.isPlainObject(gotoOptions)) {
+ date = gotoOptions.date;
+ type = gotoOptions.type;
+ forceOff = gotoOptions.forceOff;
+ }
+ else {
+ date = gotoOptions; // a single moment input
+ }
+ date = moment_ext_1.default(date); // if a string, parse it
+ finalOptions = {
+ date: date.format('YYYY-MM-DD'),
+ type: type || 'day'
+ };
+ if (typeof attrs === 'string') {
+ innerHtml = attrs;
+ attrs = null;
+ }
+ attrs = attrs ? ' ' + util_1.attrsToStr(attrs) : ''; // will have a leading space
+ innerHtml = innerHtml || '';
+ if (!forceOff && this.opt('navLinks')) {
+ return '<a' + attrs +
+ ' data-goto="' + util_1.htmlEscape(JSON.stringify(finalOptions)) + '">' +
+ innerHtml +
+ '</a>';
+ }
+ else {
+ return '<span' + attrs + '>' +
+ innerHtml +
+ '</span>';
+ }
+ };
+ DateComponent.prototype.getAllDayHtml = function () {
+ return this.opt('allDayHtml') || util_1.htmlEscape(this.opt('allDayText'));
+ };
+ // Computes HTML classNames for a single-day element
+ DateComponent.prototype.getDayClasses = function (date, noThemeHighlight) {
+ var view = this._getView();
+ var classes = [];
+ var today;
+ if (!this.dateProfile.activeUnzonedRange.containsDate(date)) {
+ classes.push('fc-disabled-day'); // TODO: jQuery UI theme?
+ }
+ else {
+ classes.push('fc-' + util_1.dayIDs[date.day()]);
+ if (view.isDateInOtherMonth(date, this.dateProfile)) {
+ classes.push('fc-other-month');
+ }
+ today = view.calendar.getNow();
+ if (date.isSame(today, 'day')) {
+ classes.push('fc-today');
+ if (noThemeHighlight !== true) {
+ classes.push(view.calendar.theme.getClass('today'));
+ }
+ }
+ else if (date < today) {
+ classes.push('fc-past');
+ }
+ else {
+ classes.push('fc-future');
+ }
+ }
+ return classes;
+ };
+ // Utility for formatting a range. Accepts a range object, formatting string, and optional separator.
+ // Displays all-day ranges naturally, with an inclusive end. Takes the current isRTL into account.
+ // The timezones of the dates within `range` will be respected.
+ DateComponent.prototype.formatRange = function (range, isAllDay, formatStr, separator) {
+ var end = range.end;
+ if (isAllDay) {
+ end = end.clone().subtract(1); // convert to inclusive. last ms of previous day
+ }
+ return date_formatting_1.formatRange(range.start, end, formatStr, separator, this.isRTL);
+ };
+ // Compute the number of the give units in the "current" range.
+ // Will return a floating-point number. Won't round.
+ DateComponent.prototype.currentRangeAs = function (unit) {
+ return this._getDateProfile().currentUnzonedRange.as(unit);
+ };
+ // Returns the date range of the full days the given range visually appears to occupy.
+ // Returns a plain object with start/end, NOT an UnzonedRange!
+ DateComponent.prototype.computeDayRange = function (unzonedRange) {
+ var calendar = this._getCalendar();
+ var startDay = calendar.msToUtcMoment(unzonedRange.startMs, true); // the beginning of the day the range starts
+ var end = calendar.msToUtcMoment(unzonedRange.endMs);
+ var endTimeMS = +end.time(); // # of milliseconds into `endDay`
+ var endDay = end.clone().stripTime(); // the beginning of the day the range exclusively ends
+ // If the end time is actually inclusively part of the next day and is equal to or
+ // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
+ // Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
+ if (endTimeMS && endTimeMS >= this.nextDayThreshold) {
+ endDay.add(1, 'days');
+ }
+ // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day.
+ if (endDay <= startDay) {
+ endDay = startDay.clone().add(1, 'days');
+ }
+ return { start: startDay, end: endDay };
+ };
+ // Does the given range visually appear to occupy more than one day?
+ DateComponent.prototype.isMultiDayRange = function (unzonedRange) {
+ var dayRange = this.computeDayRange(unzonedRange);
+ return dayRange.end.diff(dayRange.start, 'days') > 1;
+ };
+ DateComponent.guid = 0; // TODO: better system for this?
+ return DateComponent;
+}(Component_1.default));
+exports.default = DateComponent;
+// legacy
+function convertEventsPayloadToLegacyArray(eventsPayload) {
+ var eventDefId;
+ var eventInstances;
+ var legacyEvents = [];
+ var i;
+ for (eventDefId in eventsPayload) {
+ eventInstances = eventsPayload[eventDefId].eventInstances;
+ for (i = 0; i < eventInstances.length; i++) {
+ legacyEvents.push(eventInstances[i].toLegacy());
+ }
+ }
+ return legacyEvents;
+}
+
+
+/***/ }),
+/* 220 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var options_1 = __webpack_require__(32);
+var Iterator_1 = __webpack_require__(238);
+var GlobalEmitter_1 = __webpack_require__(21);
+var EmitterMixin_1 = __webpack_require__(11);
+var ListenerMixin_1 = __webpack_require__(7);
+var Toolbar_1 = __webpack_require__(239);
+var OptionsManager_1 = __webpack_require__(240);
+var ViewSpecManager_1 = __webpack_require__(241);
+var Constraints_1 = __webpack_require__(207);
+var locale_1 = __webpack_require__(31);
+var moment_ext_1 = __webpack_require__(10);
+var UnzonedRange_1 = __webpack_require__(5);
+var ComponentFootprint_1 = __webpack_require__(12);
+var EventDateProfile_1 = __webpack_require__(17);
+var EventManager_1 = __webpack_require__(242);
+var BusinessHourGenerator_1 = __webpack_require__(212);
+var EventSourceParser_1 = __webpack_require__(38);
+var EventDefParser_1 = __webpack_require__(49);
+var SingleEventDef_1 = __webpack_require__(13);
+var EventDefMutation_1 = __webpack_require__(37);
+var EventSource_1 = __webpack_require__(6);
+var ThemeRegistry_1 = __webpack_require__(51);
+var Calendar = /** @class */ (function () {
+ function Calendar(el, overrides) {
+ this.loadingLevel = 0; // number of simultaneous loading tasks
+ this.ignoreUpdateViewSize = 0;
+ this.freezeContentHeightDepth = 0;
+ // declare the current calendar instance relies on GlobalEmitter. needed for garbage collection.
+ // unneeded() is called in destroy.
+ GlobalEmitter_1.default.needed();
+ this.el = el;
+ this.viewsByType = {};
+ this.optionsManager = new OptionsManager_1.default(this, overrides);
+ this.viewSpecManager = new ViewSpecManager_1.default(this.optionsManager, this);
+ this.initMomentInternals(); // needs to happen after options hash initialized
+ this.initCurrentDate();
+ this.initEventManager();
+ this.constraints = new Constraints_1.default(this.eventManager, this);
+ this.constructed();
+ }
+ Calendar.prototype.constructed = function () {
+ // useful for monkeypatching. used?
+ };
+ Calendar.prototype.getView = function () {
+ return this.view;
+ };
+ Calendar.prototype.publiclyTrigger = function (name, triggerInfo) {
+ var optHandler = this.opt(name);
+ var context;
+ var args;
+ if ($.isPlainObject(triggerInfo)) {
+ context = triggerInfo.context;
+ args = triggerInfo.args;
+ }
+ else if ($.isArray(triggerInfo)) {
+ args = triggerInfo;
+ }
+ if (context == null) {
+ context = this.el[0]; // fallback context
+ }
+ if (!args) {
+ args = [];
+ }
+ this.triggerWith(name, context, args); // Emitter's method
+ if (optHandler) {
+ return optHandler.apply(context, args);
+ }
+ };
+ Calendar.prototype.hasPublicHandlers = function (name) {
+ return this.hasHandlers(name) ||
+ this.opt(name); // handler specified in options
+ };
+ // Options Public API
+ // -----------------------------------------------------------------------------------------------------------------
+ // public getter/setter
+ Calendar.prototype.option = function (name, value) {
+ var newOptionHash;
+ if (typeof name === 'string') {
+ if (value === undefined) {
+ return this.optionsManager.get(name);
+ }
+ else {
+ newOptionHash = {};
+ newOptionHash[name] = value;
+ this.optionsManager.add(newOptionHash);
+ }
+ }
+ else if (typeof name === 'object') {
+ this.optionsManager.add(name);
+ }
+ };
+ // private getter
+ Calendar.prototype.opt = function (name) {
+ return this.optionsManager.get(name);
+ };
+ // View
+ // -----------------------------------------------------------------------------------------------------------------
+ // Given a view name for a custom view or a standard view, creates a ready-to-go View object
+ Calendar.prototype.instantiateView = function (viewType) {
+ var spec = this.viewSpecManager.getViewSpec(viewType);
+ if (!spec) {
+ throw new Error("View type \"" + viewType + "\" is not valid");
+ }
+ return new spec['class'](this, spec);
+ };
+ // Returns a boolean about whether the view is okay to instantiate at some point
+ Calendar.prototype.isValidViewType = function (viewType) {
+ return Boolean(this.viewSpecManager.getViewSpec(viewType));
+ };
+ Calendar.prototype.changeView = function (viewName, dateOrRange) {
+ if (dateOrRange) {
+ if (dateOrRange.start && dateOrRange.end) {
+ this.optionsManager.recordOverrides({
+ visibleRange: dateOrRange
+ });
+ }
+ else {
+ this.currentDate = this.moment(dateOrRange).stripZone(); // just like gotoDate
+ }
+ }
+ this.renderView(viewName);
+ };
+ // Forces navigation to a view for the given date.
+ // `viewType` can be a specific view name or a generic one like "week" or "day".
+ Calendar.prototype.zoomTo = function (newDate, viewType) {
+ var spec;
+ viewType = viewType || 'day'; // day is default zoom
+ spec = this.viewSpecManager.getViewSpec(viewType) ||
+ this.viewSpecManager.getUnitViewSpec(viewType);
+ this.currentDate = newDate.clone();
+ this.renderView(spec ? spec.type : null);
+ };
+ // Current Date
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.initCurrentDate = function () {
+ var defaultDateInput = this.opt('defaultDate');
+ // compute the initial ambig-timezone date
+ if (defaultDateInput != null) {
+ this.currentDate = this.moment(defaultDateInput).stripZone();
+ }
+ else {
+ this.currentDate = this.getNow(); // getNow already returns unzoned
+ }
+ };
+ Calendar.prototype.prev = function () {
+ var view = this.view;
+ var prevInfo = view.dateProfileGenerator.buildPrev(view.get('dateProfile'));
+ if (prevInfo.isValid) {
+ this.currentDate = prevInfo.date;
+ this.renderView();
+ }
+ };
+ Calendar.prototype.next = function () {
+ var view = this.view;
+ var nextInfo = view.dateProfileGenerator.buildNext(view.get('dateProfile'));
+ if (nextInfo.isValid) {
+ this.currentDate = nextInfo.date;
+ this.renderView();
+ }
+ };
+ Calendar.prototype.prevYear = function () {
+ this.currentDate.add(-1, 'years');
+ this.renderView();
+ };
+ Calendar.prototype.nextYear = function () {
+ this.currentDate.add(1, 'years');
+ this.renderView();
+ };
+ Calendar.prototype.today = function () {
+ this.currentDate = this.getNow(); // should deny like prev/next?
+ this.renderView();
+ };
+ Calendar.prototype.gotoDate = function (zonedDateInput) {
+ this.currentDate = this.moment(zonedDateInput).stripZone();
+ this.renderView();
+ };
+ Calendar.prototype.incrementDate = function (delta) {
+ this.currentDate.add(moment.duration(delta));
+ this.renderView();
+ };
+ // for external API
+ Calendar.prototype.getDate = function () {
+ return this.applyTimezone(this.currentDate); // infuse the calendar's timezone
+ };
+ // Loading Triggering
+ // -----------------------------------------------------------------------------------------------------------------
+ // Should be called when any type of async data fetching begins
+ Calendar.prototype.pushLoading = function () {
+ if (!(this.loadingLevel++)) {
+ this.publiclyTrigger('loading', [true, this.view]);
+ }
+ };
+ // Should be called when any type of async data fetching completes
+ Calendar.prototype.popLoading = function () {
+ if (!(--this.loadingLevel)) {
+ this.publiclyTrigger('loading', [false, this.view]);
+ }
+ };
+ // High-level Rendering
+ // -----------------------------------------------------------------------------------
+ Calendar.prototype.render = function () {
+ if (!this.contentEl) {
+ this.initialRender();
+ }
+ else if (this.elementVisible()) {
+ // mainly for the public API
+ this.calcSize();
+ this.updateViewSize();
+ }
+ };
+ Calendar.prototype.initialRender = function () {
+ var _this = this;
+ var el = this.el;
+ el.addClass('fc');
+ // event delegation for nav links
+ el.on('click.fc', 'a[data-goto]', function (ev) {
+ var anchorEl = $(ev.currentTarget);
+ var gotoOptions = anchorEl.data('goto'); // will automatically parse JSON
+ var date = _this.moment(gotoOptions.date);
+ var viewType = gotoOptions.type;
+ // property like "navLinkDayClick". might be a string or a function
+ var customAction = _this.view.opt('navLink' + util_1.capitaliseFirstLetter(viewType) + 'Click');
+ if (typeof customAction === 'function') {
+ customAction(date, ev);
+ }
+ else {
+ if (typeof customAction === 'string') {
+ viewType = customAction;
+ }
+ _this.zoomTo(date, viewType);
+ }
+ });
+ // called immediately, and upon option change
+ this.optionsManager.watch('settingTheme', ['?theme', '?themeSystem'], function (opts) {
+ var themeClass = ThemeRegistry_1.getThemeSystemClass(opts.themeSystem || opts.theme);
+ var theme = new themeClass(_this.optionsManager);
+ var widgetClass = theme.getClass('widget');
+ _this.theme = theme;
+ if (widgetClass) {
+ el.addClass(widgetClass);
+ }
+ }, function () {
+ var widgetClass = _this.theme.getClass('widget');
+ _this.theme = null;
+ if (widgetClass) {
+ el.removeClass(widgetClass);
+ }
+ });
+ this.optionsManager.watch('settingBusinessHourGenerator', ['?businessHours'], function (deps) {
+ _this.businessHourGenerator = new BusinessHourGenerator_1.default(deps.businessHours, _this);
+ if (_this.view) {
+ _this.view.set('businessHourGenerator', _this.businessHourGenerator);
+ }
+ }, function () {
+ _this.businessHourGenerator = null;
+ });
+ // called immediately, and upon option change.
+ // HACK: locale often affects isRTL, so we explicitly listen to that too.
+ this.optionsManager.watch('applyingDirClasses', ['?isRTL', '?locale'], function (opts) {
+ el.toggleClass('fc-ltr', !opts.isRTL);
+ el.toggleClass('fc-rtl', opts.isRTL);
+ });
+ this.contentEl = $("<div class='fc-view-container'/>").prependTo(el);
+ this.initToolbars();
+ this.renderHeader();
+ this.renderFooter();
+ this.renderView(this.opt('defaultView'));
+ if (this.opt('handleWindowResize')) {
+ $(window).resize(this.windowResizeProxy = util_1.debounce(// prevents rapid calls
+ this.windowResize.bind(this), this.opt('windowResizeDelay')));
+ }
+ };
+ Calendar.prototype.destroy = function () {
+ if (this.view) {
+ this.clearView();
+ }
+ this.toolbarsManager.proxyCall('removeElement');
+ this.contentEl.remove();
+ this.el.removeClass('fc fc-ltr fc-rtl');
+ // removes theme-related root className
+ this.optionsManager.unwatch('settingTheme');
+ this.optionsManager.unwatch('settingBusinessHourGenerator');
+ this.el.off('.fc'); // unbind nav link handlers
+ if (this.windowResizeProxy) {
+ $(window).unbind('resize', this.windowResizeProxy);
+ this.windowResizeProxy = null;
+ }
+ GlobalEmitter_1.default.unneeded();
+ };
+ Calendar.prototype.elementVisible = function () {
+ return this.el.is(':visible');
+ };
+ // Render Queue
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.bindViewHandlers = function (view) {
+ var _this = this;
+ view.watch('titleForCalendar', ['title'], function (deps) {
+ if (view === _this.view) {
+ _this.setToolbarsTitle(deps.title);
+ }
+ });
+ view.watch('dateProfileForCalendar', ['dateProfile'], function (deps) {
+ if (view === _this.view) {
+ _this.currentDate = deps.dateProfile.date; // might have been constrained by view dates
+ _this.updateToolbarButtons(deps.dateProfile);
+ }
+ });
+ };
+ Calendar.prototype.unbindViewHandlers = function (view) {
+ view.unwatch('titleForCalendar');
+ view.unwatch('dateProfileForCalendar');
+ };
+ // View Rendering
+ // -----------------------------------------------------------------------------------
+ // Renders a view because of a date change, view-type change, or for the first time.
+ // If not given a viewType, keep the current view but render different dates.
+ // Accepts an optional scroll state to restore to.
+ Calendar.prototype.renderView = function (viewType) {
+ var oldView = this.view;
+ var newView;
+ this.freezeContentHeight();
+ if (oldView && viewType && oldView.type !== viewType) {
+ this.clearView();
+ }
+ // if viewType changed, or the view was never created, create a fresh view
+ if (!this.view && viewType) {
+ newView = this.view =
+ this.viewsByType[viewType] ||
+ (this.viewsByType[viewType] = this.instantiateView(viewType));
+ this.bindViewHandlers(newView);
+ newView.startBatchRender(); // so that setElement+setDate rendering are joined
+ newView.setElement($("<div class='fc-view fc-" + viewType + "-view' />").appendTo(this.contentEl));
+ this.toolbarsManager.proxyCall('activateButton', viewType);
+ }
+ if (this.view) {
+ // prevent unnecessary change firing
+ if (this.view.get('businessHourGenerator') !== this.businessHourGenerator) {
+ this.view.set('businessHourGenerator', this.businessHourGenerator);
+ }
+ this.view.setDate(this.currentDate);
+ if (newView) {
+ newView.stopBatchRender();
+ }
+ }
+ this.thawContentHeight();
+ };
+ // Unrenders the current view and reflects this change in the Header.
+ // Unregsiters the `view`, but does not remove from viewByType hash.
+ Calendar.prototype.clearView = function () {
+ var currentView = this.view;
+ this.toolbarsManager.proxyCall('deactivateButton', currentView.type);
+ this.unbindViewHandlers(currentView);
+ currentView.removeElement();
+ currentView.unsetDate(); // so bindViewHandlers doesn't fire with old values next time
+ this.view = null;
+ };
+ // Destroys the view, including the view object. Then, re-instantiates it and renders it.
+ // Maintains the same scroll state.
+ // TODO: maintain any other user-manipulated state.
+ Calendar.prototype.reinitView = function () {
+ var oldView = this.view;
+ var scroll = oldView.queryScroll(); // wouldn't be so complicated if Calendar owned the scroll
+ this.freezeContentHeight();
+ this.clearView();
+ this.calcSize();
+ this.renderView(oldView.type); // needs the type to freshly render
+ this.view.applyScroll(scroll);
+ this.thawContentHeight();
+ };
+ // Resizing
+ // -----------------------------------------------------------------------------------
+ Calendar.prototype.getSuggestedViewHeight = function () {
+ if (this.suggestedViewHeight == null) {
+ this.calcSize();
+ }
+ return this.suggestedViewHeight;
+ };
+ Calendar.prototype.isHeightAuto = function () {
+ return this.opt('contentHeight') === 'auto' || this.opt('height') === 'auto';
+ };
+ Calendar.prototype.updateViewSize = function (isResize) {
+ if (isResize === void 0) { isResize = false; }
+ var view = this.view;
+ var scroll;
+ if (!this.ignoreUpdateViewSize && view) {
+ if (isResize) {
+ this.calcSize();
+ scroll = view.queryScroll();
+ }
+ this.ignoreUpdateViewSize++;
+ view.updateSize(this.getSuggestedViewHeight(), this.isHeightAuto(), isResize);
+ this.ignoreUpdateViewSize--;
+ if (isResize) {
+ view.applyScroll(scroll);
+ }
+ return true; // signal success
+ }
+ };
+ Calendar.prototype.calcSize = function () {
+ if (this.elementVisible()) {
+ this._calcSize();
+ }
+ };
+ Calendar.prototype._calcSize = function () {
+ var contentHeightInput = this.opt('contentHeight');
+ var heightInput = this.opt('height');
+ if (typeof contentHeightInput === 'number') {
+ this.suggestedViewHeight = contentHeightInput;
+ }
+ else if (typeof contentHeightInput === 'function') {
+ this.suggestedViewHeight = contentHeightInput();
+ }
+ else if (typeof heightInput === 'number') {
+ this.suggestedViewHeight = heightInput - this.queryToolbarsHeight();
+ }
+ else if (typeof heightInput === 'function') {
+ this.suggestedViewHeight = heightInput() - this.queryToolbarsHeight();
+ }
+ else if (heightInput === 'parent') {
+ this.suggestedViewHeight = this.el.parent().height() - this.queryToolbarsHeight();
+ }
+ else {
+ this.suggestedViewHeight = Math.round(this.contentEl.width() /
+ Math.max(this.opt('aspectRatio'), .5));
+ }
+ };
+ Calendar.prototype.windowResize = function (ev) {
+ if (
+ // the purpose: so we don't process jqui "resize" events that have bubbled up
+ // cast to any because .target, which is Element, can't be compared to window for some reason.
+ ev.target === window &&
+ this.view &&
+ this.view.isDatesRendered) {
+ if (this.updateViewSize(true)) {
+ this.publiclyTrigger('windowResize', [this.view]);
+ }
+ }
+ };
+ /* Height "Freezing"
+ -----------------------------------------------------------------------------*/
+ Calendar.prototype.freezeContentHeight = function () {
+ if (!(this.freezeContentHeightDepth++)) {
+ this.forceFreezeContentHeight();
+ }
+ };
+ Calendar.prototype.forceFreezeContentHeight = function () {
+ this.contentEl.css({
+ width: '100%',
+ height: this.contentEl.height(),
+ overflow: 'hidden'
+ });
+ };
+ Calendar.prototype.thawContentHeight = function () {
+ this.freezeContentHeightDepth--;
+ // always bring back to natural height
+ this.contentEl.css({
+ width: '',
+ height: '',
+ overflow: ''
+ });
+ // but if there are future thaws, re-freeze
+ if (this.freezeContentHeightDepth) {
+ this.forceFreezeContentHeight();
+ }
+ };
+ // Toolbar
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.initToolbars = function () {
+ this.header = new Toolbar_1.default(this, this.computeHeaderOptions());
+ this.footer = new Toolbar_1.default(this, this.computeFooterOptions());
+ this.toolbarsManager = new Iterator_1.default([this.header, this.footer]);
+ };
+ Calendar.prototype.computeHeaderOptions = function () {
+ return {
+ extraClasses: 'fc-header-toolbar',
+ layout: this.opt('header')
+ };
+ };
+ Calendar.prototype.computeFooterOptions = function () {
+ return {
+ extraClasses: 'fc-footer-toolbar',
+ layout: this.opt('footer')
+ };
+ };
+ // can be called repeatedly and Header will rerender
+ Calendar.prototype.renderHeader = function () {
+ var header = this.header;
+ header.setToolbarOptions(this.computeHeaderOptions());
+ header.render();
+ if (header.el) {
+ this.el.prepend(header.el);
+ }
+ };
+ // can be called repeatedly and Footer will rerender
+ Calendar.prototype.renderFooter = function () {
+ var footer = this.footer;
+ footer.setToolbarOptions(this.computeFooterOptions());
+ footer.render();
+ if (footer.el) {
+ this.el.append(footer.el);
+ }
+ };
+ Calendar.prototype.setToolbarsTitle = function (title) {
+ this.toolbarsManager.proxyCall('updateTitle', title);
+ };
+ Calendar.prototype.updateToolbarButtons = function (dateProfile) {
+ var now = this.getNow();
+ var view = this.view;
+ var todayInfo = view.dateProfileGenerator.build(now);
+ var prevInfo = view.dateProfileGenerator.buildPrev(view.get('dateProfile'));
+ var nextInfo = view.dateProfileGenerator.buildNext(view.get('dateProfile'));
+ this.toolbarsManager.proxyCall((todayInfo.isValid && !dateProfile.currentUnzonedRange.containsDate(now)) ?
+ 'enableButton' :
+ 'disableButton', 'today');
+ this.toolbarsManager.proxyCall(prevInfo.isValid ?
+ 'enableButton' :
+ 'disableButton', 'prev');
+ this.toolbarsManager.proxyCall(nextInfo.isValid ?
+ 'enableButton' :
+ 'disableButton', 'next');
+ };
+ Calendar.prototype.queryToolbarsHeight = function () {
+ return this.toolbarsManager.items.reduce(function (accumulator, toolbar) {
+ var toolbarHeight = toolbar.el ? toolbar.el.outerHeight(true) : 0; // includes margin
+ return accumulator + toolbarHeight;
+ }, 0);
+ };
+ // Selection
+ // -----------------------------------------------------------------------------------------------------------------
+ // this public method receives start/end dates in any format, with any timezone
+ Calendar.prototype.select = function (zonedStartInput, zonedEndInput) {
+ this.view.select(this.buildSelectFootprint.apply(this, arguments));
+ };
+ Calendar.prototype.unselect = function () {
+ if (this.view) {
+ this.view.unselect();
+ }
+ };
+ // Given arguments to the select method in the API, returns a span (unzoned start/end and other info)
+ Calendar.prototype.buildSelectFootprint = function (zonedStartInput, zonedEndInput) {
+ var start = this.moment(zonedStartInput).stripZone();
+ var end;
+ if (zonedEndInput) {
+ end = this.moment(zonedEndInput).stripZone();
+ }
+ else if (start.hasTime()) {
+ end = start.clone().add(this.defaultTimedEventDuration);
+ }
+ else {
+ end = start.clone().add(this.defaultAllDayEventDuration);
+ }
+ return new ComponentFootprint_1.default(new UnzonedRange_1.default(start, end), !start.hasTime());
+ };
+ // Date Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.initMomentInternals = function () {
+ var _this = this;
+ this.defaultAllDayEventDuration = moment.duration(this.opt('defaultAllDayEventDuration'));
+ this.defaultTimedEventDuration = moment.duration(this.opt('defaultTimedEventDuration'));
+ // Called immediately, and when any of the options change.
+ // Happens before any internal objects rebuild or rerender, because this is very core.
+ this.optionsManager.watch('buildingMomentLocale', [
+ '?locale', '?monthNames', '?monthNamesShort', '?dayNames', '?dayNamesShort',
+ '?firstDay', '?weekNumberCalculation'
+ ], function (opts) {
+ var weekNumberCalculation = opts.weekNumberCalculation;
+ var firstDay = opts.firstDay;
+ var _week;
+ // normalize
+ if (weekNumberCalculation === 'iso') {
+ weekNumberCalculation = 'ISO'; // normalize
+ }
+ var localeData = Object.create(// make a cheap copy
+ locale_1.getMomentLocaleData(opts.locale) // will fall back to en
+ );
+ if (opts.monthNames) {
+ localeData._months = opts.monthNames;
+ }
+ if (opts.monthNamesShort) {
+ localeData._monthsShort = opts.monthNamesShort;
+ }
+ if (opts.dayNames) {
+ localeData._weekdays = opts.dayNames;
+ }
+ if (opts.dayNamesShort) {
+ localeData._weekdaysShort = opts.dayNamesShort;
+ }
+ if (firstDay == null && weekNumberCalculation === 'ISO') {
+ firstDay = 1;
+ }
+ if (firstDay != null) {
+ _week = Object.create(localeData._week); // _week: { dow: # }
+ _week.dow = firstDay;
+ localeData._week = _week;
+ }
+ if (weekNumberCalculation === 'ISO' ||
+ weekNumberCalculation === 'local' ||
+ typeof weekNumberCalculation === 'function') {
+ localeData._fullCalendar_weekCalc = weekNumberCalculation; // moment-ext will know what to do with it
+ }
+ _this.localeData = localeData;
+ // If the internal current date object already exists, move to new locale.
+ // We do NOT need to do this technique for event dates, because this happens when converting to "segments".
+ if (_this.currentDate) {
+ _this.localizeMoment(_this.currentDate); // sets to localeData
+ }
+ });
+ };
+ // Builds a moment using the settings of the current calendar: timezone and locale.
+ // Accepts anything the vanilla moment() constructor accepts.
+ Calendar.prototype.moment = function () {
+ var args = [];
+ for (var _i = 0; _i < arguments.length; _i++) {
+ args[_i] = arguments[_i];
+ }
+ var mom;
+ if (this.opt('timezone') === 'local') {
+ mom = moment_ext_1.default.apply(null, args);
+ // Force the moment to be local, because momentExt doesn't guarantee it.
+ if (mom.hasTime()) {
+ mom.local();
+ }
+ }
+ else if (this.opt('timezone') === 'UTC') {
+ mom = moment_ext_1.default.utc.apply(null, args); // process as UTC
+ }
+ else {
+ mom = moment_ext_1.default.parseZone.apply(null, args); // let the input decide the zone
+ }
+ this.localizeMoment(mom); // TODO
+ return mom;
+ };
+ Calendar.prototype.msToMoment = function (ms, forceAllDay) {
+ var mom = moment_ext_1.default.utc(ms); // TODO: optimize by using Date.UTC
+ if (forceAllDay) {
+ mom.stripTime();
+ }
+ else {
+ mom = this.applyTimezone(mom); // may or may not apply locale
+ }
+ this.localizeMoment(mom);
+ return mom;
+ };
+ Calendar.prototype.msToUtcMoment = function (ms, forceAllDay) {
+ var mom = moment_ext_1.default.utc(ms); // TODO: optimize by using Date.UTC
+ if (forceAllDay) {
+ mom.stripTime();
+ }
+ this.localizeMoment(mom);
+ return mom;
+ };
+ // Updates the given moment's locale settings to the current calendar locale settings.
+ Calendar.prototype.localizeMoment = function (mom) {
+ mom._locale = this.localeData;
+ };
+ // Returns a boolean about whether or not the calendar knows how to calculate
+ // the timezone offset of arbitrary dates in the current timezone.
+ Calendar.prototype.getIsAmbigTimezone = function () {
+ return this.opt('timezone') !== 'local' && this.opt('timezone') !== 'UTC';
+ };
+ // Returns a copy of the given date in the current timezone. Has no effect on dates without times.
+ Calendar.prototype.applyTimezone = function (date) {
+ if (!date.hasTime()) {
+ return date.clone();
+ }
+ var zonedDate = this.moment(date.toArray());
+ var timeAdjust = date.time().asMilliseconds() - zonedDate.time().asMilliseconds();
+ var adjustedZonedDate;
+ // Safari sometimes has problems with this coersion when near DST. Adjust if necessary. (bug #2396)
+ if (timeAdjust) {
+ adjustedZonedDate = zonedDate.clone().add(timeAdjust); // add milliseconds
+ if (date.time().asMilliseconds() - adjustedZonedDate.time().asMilliseconds() === 0) {
+ zonedDate = adjustedZonedDate;
+ }
+ }
+ return zonedDate;
+ };
+ /*
+ Assumes the footprint is non-open-ended.
+ */
+ Calendar.prototype.footprintToDateProfile = function (componentFootprint, ignoreEnd) {
+ if (ignoreEnd === void 0) { ignoreEnd = false; }
+ var start = moment_ext_1.default.utc(componentFootprint.unzonedRange.startMs);
+ var end;
+ if (!ignoreEnd) {
+ end = moment_ext_1.default.utc(componentFootprint.unzonedRange.endMs);
+ }
+ if (componentFootprint.isAllDay) {
+ start.stripTime();
+ if (end) {
+ end.stripTime();
+ }
+ }
+ else {
+ start = this.applyTimezone(start);
+ if (end) {
+ end = this.applyTimezone(end);
+ }
+ }
+ return new EventDateProfile_1.default(start, end, this);
+ };
+ // Returns a moment for the current date, as defined by the client's computer or from the `now` option.
+ // Will return an moment with an ambiguous timezone.
+ Calendar.prototype.getNow = function () {
+ var now = this.opt('now');
+ if (typeof now === 'function') {
+ now = now();
+ }
+ return this.moment(now).stripZone();
+ };
+ // Produces a human-readable string for the given duration.
+ // Side-effect: changes the locale of the given duration.
+ Calendar.prototype.humanizeDuration = function (duration) {
+ return duration.locale(this.opt('locale')).humanize();
+ };
+ // will return `null` if invalid range
+ Calendar.prototype.parseUnzonedRange = function (rangeInput) {
+ var start = null;
+ var end = null;
+ if (rangeInput.start) {
+ start = this.moment(rangeInput.start).stripZone();
+ }
+ if (rangeInput.end) {
+ end = this.moment(rangeInput.end).stripZone();
+ }
+ if (!start && !end) {
+ return null;
+ }
+ if (start && end && end.isBefore(start)) {
+ return null;
+ }
+ return new UnzonedRange_1.default(start, end);
+ };
+ // Event-Date Utilities
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.initEventManager = function () {
+ var _this = this;
+ var eventManager = new EventManager_1.default(this);
+ var rawSources = this.opt('eventSources') || [];
+ var singleRawSource = this.opt('events');
+ this.eventManager = eventManager;
+ if (singleRawSource) {
+ rawSources.unshift(singleRawSource);
+ }
+ eventManager.on('release', function (eventsPayload) {
+ _this.trigger('eventsReset', eventsPayload);
+ });
+ eventManager.freeze();
+ rawSources.forEach(function (rawSource) {
+ var source = EventSourceParser_1.default.parse(rawSource, _this);
+ if (source) {
+ eventManager.addSource(source);
+ }
+ });
+ eventManager.thaw();
+ };
+ Calendar.prototype.requestEvents = function (start, end) {
+ return this.eventManager.requestEvents(start, end, this.opt('timezone'), !this.opt('lazyFetching'));
+ };
+ // Get an event's normalized end date. If not present, calculate it from the defaults.
+ Calendar.prototype.getEventEnd = function (event) {
+ if (event.end) {
+ return event.end.clone();
+ }
+ else {
+ return this.getDefaultEventEnd(event.allDay, event.start);
+ }
+ };
+ // Given an event's allDay status and start date, return what its fallback end date should be.
+ // TODO: rename to computeDefaultEventEnd
+ Calendar.prototype.getDefaultEventEnd = function (allDay, zonedStart) {
+ var end = zonedStart.clone();
+ if (allDay) {
+ end.stripTime().add(this.defaultAllDayEventDuration);
+ }
+ else {
+ end.add(this.defaultTimedEventDuration);
+ }
+ if (this.getIsAmbigTimezone()) {
+ end.stripZone(); // we don't know what the tzo should be
+ }
+ return end;
+ };
+ // Public Events API
+ // -----------------------------------------------------------------------------------------------------------------
+ Calendar.prototype.rerenderEvents = function () {
+ this.view.flash('displayingEvents');
+ };
+ Calendar.prototype.refetchEvents = function () {
+ this.eventManager.refetchAllSources();
+ };
+ Calendar.prototype.renderEvents = function (eventInputs, isSticky) {
+ this.eventManager.freeze();
+ for (var i = 0; i < eventInputs.length; i++) {
+ this.renderEvent(eventInputs[i], isSticky);
+ }
+ this.eventManager.thaw();
+ };
+ Calendar.prototype.renderEvent = function (eventInput, isSticky) {
+ if (isSticky === void 0) { isSticky = false; }
+ var eventManager = this.eventManager;
+ var eventDef = EventDefParser_1.default.parse(eventInput, eventInput.source || eventManager.stickySource);
+ if (eventDef) {
+ eventManager.addEventDef(eventDef, isSticky);
+ }
+ };
+ // legacyQuery operates on legacy event instance objects
+ Calendar.prototype.removeEvents = function (legacyQuery) {
+ var eventManager = this.eventManager;
+ var legacyInstances = [];
+ var idMap = {};
+ var eventDef;
+ var i;
+ if (legacyQuery == null) {
+ eventManager.removeAllEventDefs(); // persist=true
+ }
+ else {
+ eventManager.getEventInstances().forEach(function (eventInstance) {
+ legacyInstances.push(eventInstance.toLegacy());
+ });
+ legacyInstances = filterLegacyEventInstances(legacyInstances, legacyQuery);
+ // compute unique IDs
+ for (i = 0; i < legacyInstances.length; i++) {
+ eventDef = this.eventManager.getEventDefByUid(legacyInstances[i]._id);
+ idMap[eventDef.id] = true;
+ }
+ eventManager.freeze();
+ for (i in idMap) {
+ eventManager.removeEventDefsById(i); // persist=true
+ }
+ eventManager.thaw();
+ }
+ };
+ // legacyQuery operates on legacy event instance objects
+ Calendar.prototype.clientEvents = function (legacyQuery) {
+ var legacyEventInstances = [];
+ this.eventManager.getEventInstances().forEach(function (eventInstance) {
+ legacyEventInstances.push(eventInstance.toLegacy());
+ });
+ return filterLegacyEventInstances(legacyEventInstances, legacyQuery);
+ };
+ Calendar.prototype.updateEvents = function (eventPropsArray) {
+ this.eventManager.freeze();
+ for (var i = 0; i < eventPropsArray.length; i++) {
+ this.updateEvent(eventPropsArray[i]);
+ }
+ this.eventManager.thaw();
+ };
+ Calendar.prototype.updateEvent = function (eventProps) {
+ var eventDef = this.eventManager.getEventDefByUid(eventProps._id);
+ var eventInstance;
+ var eventDefMutation;
+ if (eventDef instanceof SingleEventDef_1.default) {
+ eventInstance = eventDef.buildInstance();
+ eventDefMutation = EventDefMutation_1.default.createFromRawProps(eventInstance, eventProps, // raw props
+ null // largeUnit -- who uses it?
+ );
+ this.eventManager.mutateEventsWithId(eventDef.id, eventDefMutation); // will release
+ }
+ };
+ // Public Event Sources API
+ // ------------------------------------------------------------------------------------
+ Calendar.prototype.getEventSources = function () {
+ return this.eventManager.otherSources.slice(); // clone
+ };
+ Calendar.prototype.getEventSourceById = function (id) {
+ return this.eventManager.getSourceById(EventSource_1.default.normalizeId(id));
+ };
+ Calendar.prototype.addEventSource = function (sourceInput) {
+ var source = EventSourceParser_1.default.parse(sourceInput, this);
+ if (source) {
+ this.eventManager.addSource(source);
+ }
+ };
+ Calendar.prototype.removeEventSources = function (sourceMultiQuery) {
+ var eventManager = this.eventManager;
+ var sources;
+ var i;
+ if (sourceMultiQuery == null) {
+ this.eventManager.removeAllSources();
+ }
+ else {
+ sources = eventManager.multiQuerySources(sourceMultiQuery);
+ eventManager.freeze();
+ for (i = 0; i < sources.length; i++) {
+ eventManager.removeSource(sources[i]);
+ }
+ eventManager.thaw();
+ }
+ };
+ Calendar.prototype.removeEventSource = function (sourceQuery) {
+ var eventManager = this.eventManager;
+ var sources = eventManager.querySources(sourceQuery);
+ var i;
+ eventManager.freeze();
+ for (i = 0; i < sources.length; i++) {
+ eventManager.removeSource(sources[i]);
+ }
+ eventManager.thaw();
+ };
+ Calendar.prototype.refetchEventSources = function (sourceMultiQuery) {
+ var eventManager = this.eventManager;
+ var sources = eventManager.multiQuerySources(sourceMultiQuery);
+ var i;
+ eventManager.freeze();
+ for (i = 0; i < sources.length; i++) {
+ eventManager.refetchSource(sources[i]);
+ }
+ eventManager.thaw();
+ };
+ // not for internal use. use options module directly instead.
+ Calendar.defaults = options_1.globalDefaults;
+ Calendar.englishDefaults = options_1.englishDefaults;
+ Calendar.rtlDefaults = options_1.rtlDefaults;
+ return Calendar;
+}());
+exports.default = Calendar;
+EmitterMixin_1.default.mixInto(Calendar);
+ListenerMixin_1.default.mixInto(Calendar);
+function filterLegacyEventInstances(legacyEventInstances, legacyQuery) {
+ if (legacyQuery == null) {
+ return legacyEventInstances;
+ }
+ else if ($.isFunction(legacyQuery)) {
+ return legacyEventInstances.filter(legacyQuery);
+ }
+ else {
+ legacyQuery += ''; // normalize to string
+ return legacyEventInstances.filter(function (legacyEventInstance) {
+ // soft comparison because id not be normalized to string
+ // tslint:disable-next-line
+ return legacyEventInstance.id == legacyQuery ||
+ legacyEventInstance._id === legacyQuery; // can specify internal id, but must exactly match
+ });
+ }
+}
+
+
+/***/ }),
+/* 221 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var UnzonedRange_1 = __webpack_require__(5);
+var DateProfileGenerator = /** @class */ (function () {
+ function DateProfileGenerator(_view) {
+ this._view = _view;
+ }
+ DateProfileGenerator.prototype.opt = function (name) {
+ return this._view.opt(name);
+ };
+ DateProfileGenerator.prototype.trimHiddenDays = function (unzonedRange) {
+ return this._view.trimHiddenDays(unzonedRange);
+ };
+ DateProfileGenerator.prototype.msToUtcMoment = function (ms, forceAllDay) {
+ return this._view.calendar.msToUtcMoment(ms, forceAllDay);
+ };
+ /* Date Range Computation
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Builds a structure with info about what the dates/ranges will be for the "prev" view.
+ DateProfileGenerator.prototype.buildPrev = function (currentDateProfile) {
+ var prevDate = currentDateProfile.date.clone()
+ .startOf(currentDateProfile.currentRangeUnit)
+ .subtract(currentDateProfile.dateIncrement);
+ return this.build(prevDate, -1);
+ };
+ // Builds a structure with info about what the dates/ranges will be for the "next" view.
+ DateProfileGenerator.prototype.buildNext = function (currentDateProfile) {
+ var nextDate = currentDateProfile.date.clone()
+ .startOf(currentDateProfile.currentRangeUnit)
+ .add(currentDateProfile.dateIncrement);
+ return this.build(nextDate, 1);
+ };
+ // Builds a structure holding dates/ranges for rendering around the given date.
+ // Optional direction param indicates whether the date is being incremented/decremented
+ // from its previous value. decremented = -1, incremented = 1 (default).
+ DateProfileGenerator.prototype.build = function (date, direction, forceToValid) {
+ if (forceToValid === void 0) { forceToValid = false; }
+ var isDateAllDay = !date.hasTime();
+ var validUnzonedRange;
+ var minTime = null;
+ var maxTime = null;
+ var currentInfo;
+ var isRangeAllDay;
+ var renderUnzonedRange;
+ var activeUnzonedRange;
+ var isValid;
+ validUnzonedRange = this.buildValidRange();
+ validUnzonedRange = this.trimHiddenDays(validUnzonedRange);
+ if (forceToValid) {
+ date = this.msToUtcMoment(validUnzonedRange.constrainDate(date), // returns MS
+ isDateAllDay);
+ }
+ currentInfo = this.buildCurrentRangeInfo(date, direction);
+ isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit);
+ renderUnzonedRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.unzonedRange), currentInfo.unit, isRangeAllDay);
+ renderUnzonedRange = this.trimHiddenDays(renderUnzonedRange);
+ activeUnzonedRange = renderUnzonedRange.clone();
+ if (!this.opt('showNonCurrentDates')) {
+ activeUnzonedRange = activeUnzonedRange.intersect(currentInfo.unzonedRange);
+ }
+ minTime = moment.duration(this.opt('minTime'));
+ maxTime = moment.duration(this.opt('maxTime'));
+ activeUnzonedRange = this.adjustActiveRange(activeUnzonedRange, minTime, maxTime);
+ activeUnzonedRange = activeUnzonedRange.intersect(validUnzonedRange); // might return null
+ if (activeUnzonedRange) {
+ date = this.msToUtcMoment(activeUnzonedRange.constrainDate(date), // returns MS
+ isDateAllDay);
+ }
+ // it's invalid if the originally requested date is not contained,
+ // or if the range is completely outside of the valid range.
+ isValid = currentInfo.unzonedRange.intersectsWith(validUnzonedRange);
+ return {
+ // constraint for where prev/next operations can go and where events can be dragged/resized to.
+ // an object with optional start and end properties.
+ validUnzonedRange: validUnzonedRange,
+ // range the view is formally responsible for.
+ // for example, a month view might have 1st-31st, excluding padded dates
+ currentUnzonedRange: currentInfo.unzonedRange,
+ // name of largest unit being displayed, like "month" or "week"
+ currentRangeUnit: currentInfo.unit,
+ isRangeAllDay: isRangeAllDay,
+ // dates that display events and accept drag-n-drop
+ // will be `null` if no dates accept events
+ activeUnzonedRange: activeUnzonedRange,
+ // date range with a rendered skeleton
+ // includes not-active days that need some sort of DOM
+ renderUnzonedRange: renderUnzonedRange,
+ // Duration object that denotes the first visible time of any given day
+ minTime: minTime,
+ // Duration object that denotes the exclusive visible end time of any given day
+ maxTime: maxTime,
+ isValid: isValid,
+ date: date,
+ // how far the current date will move for a prev/next operation
+ dateIncrement: this.buildDateIncrement(currentInfo.duration)
+ // pass a fallback (might be null) ^
+ };
+ };
+ // Builds an object with optional start/end properties.
+ // Indicates the minimum/maximum dates to display.
+ // not responsible for trimming hidden days.
+ DateProfileGenerator.prototype.buildValidRange = function () {
+ return this._view.getUnzonedRangeOption('validRange', this._view.calendar.getNow()) ||
+ new UnzonedRange_1.default(); // completely open-ended
+ };
+ // Builds a structure with info about the "current" range, the range that is
+ // highlighted as being the current month for example.
+ // See build() for a description of `direction`.
+ // Guaranteed to have `range` and `unit` properties. `duration` is optional.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) {
+ var viewSpec = this._view.viewSpec;
+ var duration = null;
+ var unit = null;
+ var unzonedRange = null;
+ var dayCount;
+ if (viewSpec.duration) {
+ duration = viewSpec.duration;
+ unit = viewSpec.durationUnit;
+ unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
+ }
+ else if ((dayCount = this.opt('dayCount'))) {
+ unit = 'day';
+ unzonedRange = this.buildRangeFromDayCount(date, direction, dayCount);
+ }
+ else if ((unzonedRange = this.buildCustomVisibleRange(date))) {
+ unit = util_1.computeGreatestUnit(unzonedRange.getStart(), unzonedRange.getEnd());
+ }
+ else {
+ duration = this.getFallbackDuration();
+ unit = util_1.computeGreatestUnit(duration);
+ unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
+ }
+ return { duration: duration, unit: unit, unzonedRange: unzonedRange };
+ };
+ DateProfileGenerator.prototype.getFallbackDuration = function () {
+ return moment.duration({ days: 1 });
+ };
+ // Returns a new activeUnzonedRange to have time values (un-ambiguate)
+ // minTime or maxTime causes the range to expand.
+ DateProfileGenerator.prototype.adjustActiveRange = function (unzonedRange, minTime, maxTime) {
+ var start = unzonedRange.getStart();
+ var end = unzonedRange.getEnd();
+ if (this._view.usesMinMaxTime) {
+ if (minTime < 0) {
+ start.time(0).add(minTime);
+ }
+ if (maxTime > 24 * 60 * 60 * 1000) {
+ end.time(maxTime - (24 * 60 * 60 * 1000));
+ }
+ }
+ return new UnzonedRange_1.default(start, end);
+ };
+ // Builds the "current" range when it is specified as an explicit duration.
+ // `unit` is the already-computed computeGreatestUnit value of duration.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) {
+ var alignment = this.opt('dateAlignment');
+ var dateIncrementInput;
+ var dateIncrementDuration;
+ var start;
+ var end;
+ var res;
+ // compute what the alignment should be
+ if (!alignment) {
+ dateIncrementInput = this.opt('dateIncrement');
+ if (dateIncrementInput) {
+ dateIncrementDuration = moment.duration(dateIncrementInput);
+ // use the smaller of the two units
+ if (dateIncrementDuration < duration) {
+ alignment = util_1.computeDurationGreatestUnit(dateIncrementDuration, dateIncrementInput);
+ }
+ else {
+ alignment = unit;
+ }
+ }
+ else {
+ alignment = unit;
+ }
+ }
+ // if the view displays a single day or smaller
+ if (duration.as('days') <= 1) {
+ if (this._view.isHiddenDay(start)) {
+ start = this._view.skipHiddenDays(start, direction);
+ start.startOf('day');
+ }
+ }
+ function computeRes() {
+ start = date.clone().startOf(alignment);
+ end = start.clone().add(duration);
+ res = new UnzonedRange_1.default(start, end);
+ }
+ computeRes();
+ // if range is completely enveloped by hidden days, go past the hidden days
+ if (!this.trimHiddenDays(res)) {
+ date = this._view.skipHiddenDays(date, direction);
+ computeRes();
+ }
+ return res;
+ };
+ // Builds the "current" range when a dayCount is specified.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) {
+ var customAlignment = this.opt('dateAlignment');
+ var runningCount = 0;
+ var start = date.clone();
+ var end;
+ if (customAlignment) {
+ start.startOf(customAlignment);
+ }
+ start.startOf('day');
+ start = this._view.skipHiddenDays(start, direction);
+ end = start.clone();
+ do {
+ end.add(1, 'day');
+ if (!this._view.isHiddenDay(end)) {
+ runningCount++;
+ }
+ } while (runningCount < dayCount);
+ return new UnzonedRange_1.default(start, end);
+ };
+ // Builds a normalized range object for the "visible" range,
+ // which is a way to define the currentUnzonedRange and activeUnzonedRange at the same time.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) {
+ var visibleUnzonedRange = this._view.getUnzonedRangeOption('visibleRange', this._view.calendar.applyTimezone(date) // correct zone. also generates new obj that avoids mutations
+ );
+ if (visibleUnzonedRange && (visibleUnzonedRange.startMs == null || visibleUnzonedRange.endMs == null)) {
+ return null;
+ }
+ return visibleUnzonedRange;
+ };
+ // Computes the range that will represent the element/cells for *rendering*,
+ // but which may have voided days/times.
+ // not responsible for trimming hidden days.
+ DateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
+ return currentUnzonedRange.clone();
+ };
+ // Compute the duration value that should be added/substracted to the current date
+ // when a prev/next operation happens.
+ DateProfileGenerator.prototype.buildDateIncrement = function (fallback) {
+ var dateIncrementInput = this.opt('dateIncrement');
+ var customAlignment;
+ if (dateIncrementInput) {
+ return moment.duration(dateIncrementInput);
+ }
+ else if ((customAlignment = this.opt('dateAlignment'))) {
+ return moment.duration(1, customAlignment);
+ }
+ else if (fallback) {
+ return fallback;
+ }
+ else {
+ return moment.duration({ days: 1 });
+ }
+ };
+ return DateProfileGenerator;
+}());
+exports.default = DateProfileGenerator;
+
+
+/***/ }),
+/* 222 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var exportHooks = __webpack_require__(16);
+var util_1 = __webpack_require__(4);
+var moment_ext_1 = __webpack_require__(10);
+var ListenerMixin_1 = __webpack_require__(7);
+var HitDragListener_1 = __webpack_require__(23);
+var SingleEventDef_1 = __webpack_require__(13);
+var EventInstanceGroup_1 = __webpack_require__(18);
+var EventSource_1 = __webpack_require__(6);
+var Interaction_1 = __webpack_require__(15);
+var ExternalDropping = /** @class */ (function (_super) {
+ tslib_1.__extends(ExternalDropping, _super);
+ function ExternalDropping() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.isDragging = false; // jqui-dragging an external element? boolean
+ return _this;
+ }
+ /*
+ component impements:
+ - eventRangesToEventFootprints
+ - isEventInstanceGroupAllowed
+ - isExternalInstanceGroupAllowed
+ - renderDrag
+ - unrenderDrag
+ */
+ ExternalDropping.prototype.end = function () {
+ if (this.dragListener) {
+ this.dragListener.endInteraction();
+ }
+ };
+ ExternalDropping.prototype.bindToDocument = function () {
+ this.listenTo($(document), {
+ dragstart: this.handleDragStart,
+ sortstart: this.handleDragStart // jqui
+ });
+ };
+ ExternalDropping.prototype.unbindFromDocument = function () {
+ this.stopListeningTo($(document));
+ };
+ // Called when a jQuery UI drag is initiated anywhere in the DOM
+ ExternalDropping.prototype.handleDragStart = function (ev, ui) {
+ var el;
+ var accept;
+ if (this.opt('droppable')) {
+ el = $((ui ? ui.item : null) || ev.target);
+ // Test that the dragged element passes the dropAccept selector or filter function.
+ // FYI, the default is "*" (matches all)
+ accept = this.opt('dropAccept');
+ if ($.isFunction(accept) ? accept.call(el[0], el) : el.is(accept)) {
+ if (!this.isDragging) {
+ this.listenToExternalDrag(el, ev, ui);
+ }
+ }
+ }
+ };
+ // Called when a jQuery UI drag starts and it needs to be monitored for dropping
+ ExternalDropping.prototype.listenToExternalDrag = function (el, ev, ui) {
+ var _this = this;
+ var component = this.component;
+ var view = this.view;
+ var meta = getDraggedElMeta(el); // extra data about event drop, including possible event to create
+ var singleEventDef; // a null value signals an unsuccessful drag
+ // listener that tracks mouse movement over date-associated pixel regions
+ var dragListener = this.dragListener = new HitDragListener_1.default(component, {
+ interactionStart: function () {
+ _this.isDragging = true;
+ },
+ hitOver: function (hit) {
+ var isAllowed = true;
+ var hitFootprint = hit.component.getSafeHitFootprint(hit); // hit might not belong to this grid
+ var mutatedEventInstanceGroup;
+ if (hitFootprint) {
+ singleEventDef = _this.computeExternalDrop(hitFootprint, meta);
+ if (singleEventDef) {
+ mutatedEventInstanceGroup = new EventInstanceGroup_1.default(singleEventDef.buildInstances());
+ isAllowed = meta.eventProps ? // isEvent?
+ component.isEventInstanceGroupAllowed(mutatedEventInstanceGroup) :
+ component.isExternalInstanceGroupAllowed(mutatedEventInstanceGroup);
+ }
+ else {
+ isAllowed = false;
+ }
+ }
+ else {
+ isAllowed = false;
+ }
+ if (!isAllowed) {
+ singleEventDef = null;
+ util_1.disableCursor();
+ }
+ if (singleEventDef) {
+ component.renderDrag(// called without a seg parameter
+ component.eventRangesToEventFootprints(mutatedEventInstanceGroup.sliceRenderRanges(component.dateProfile.renderUnzonedRange, view.calendar)));
+ }
+ },
+ hitOut: function () {
+ singleEventDef = null; // signal unsuccessful
+ },
+ hitDone: function () {
+ util_1.enableCursor();
+ component.unrenderDrag();
+ },
+ interactionEnd: function (ev) {
+ if (singleEventDef) {
+ view.reportExternalDrop(singleEventDef, Boolean(meta.eventProps), // isEvent
+ Boolean(meta.stick), // isSticky
+ el, ev, ui);
+ }
+ _this.isDragging = false;
+ _this.dragListener = null;
+ }
+ });
+ dragListener.startDrag(ev); // start listening immediately
+ };
+ // Given a hit to be dropped upon, and misc data associated with the jqui drag (guaranteed to be a plain object),
+ // returns the zoned start/end dates for the event that would result from the hypothetical drop. end might be null.
+ // Returning a null value signals an invalid drop hit.
+ // DOES NOT consider overlap/constraint.
+ // Assumes both footprints are non-open-ended.
+ ExternalDropping.prototype.computeExternalDrop = function (componentFootprint, meta) {
+ var calendar = this.view.calendar;
+ var start = moment_ext_1.default.utc(componentFootprint.unzonedRange.startMs).stripZone();
+ var end;
+ var eventDef;
+ if (componentFootprint.isAllDay) {
+ // if dropped on an all-day span, and element's metadata specified a time, set it
+ if (meta.startTime) {
+ start.time(meta.startTime);
+ }
+ else {
+ start.stripTime();
+ }
+ }
+ if (meta.duration) {
+ end = start.clone().add(meta.duration);
+ }
+ start = calendar.applyTimezone(start);
+ if (end) {
+ end = calendar.applyTimezone(end);
+ }
+ eventDef = SingleEventDef_1.default.parse($.extend({}, meta.eventProps, {
+ start: start,
+ end: end
+ }), new EventSource_1.default(calendar));
+ return eventDef;
+ };
+ return ExternalDropping;
+}(Interaction_1.default));
+exports.default = ExternalDropping;
+ListenerMixin_1.default.mixInto(ExternalDropping);
+/* External-Dragging-Element Data
+----------------------------------------------------------------------------------------------------------------------*/
+// Require all HTML5 data-* attributes used by FullCalendar to have this prefix.
+// A value of '' will query attributes like data-event. A value of 'fc' will query attributes like data-fc-event.
+exportHooks.dataAttrPrefix = '';
+// Given a jQuery element that might represent a dragged FullCalendar event, returns an intermediate data structure
+// to be used for Event Object creation.
+// A defined `.eventProps`, even when empty, indicates that an event should be created.
+function getDraggedElMeta(el) {
+ var prefix = exportHooks.dataAttrPrefix;
+ var eventProps; // properties for creating the event, not related to date/time
+ var startTime; // a Duration
+ var duration;
+ var stick;
+ if (prefix) {
+ prefix += '-';
+ }
+ eventProps = el.data(prefix + 'event') || null;
+ if (eventProps) {
+ if (typeof eventProps === 'object') {
+ eventProps = $.extend({}, eventProps); // make a copy
+ }
+ else {
+ eventProps = {};
+ }
+ // pluck special-cased date/time properties
+ startTime = eventProps.start;
+ if (startTime == null) {
+ startTime = eventProps.time;
+ } // accept 'time' as well
+ duration = eventProps.duration;
+ stick = eventProps.stick;
+ delete eventProps.start;
+ delete eventProps.time;
+ delete eventProps.duration;
+ delete eventProps.stick;
+ }
+ // fallback to standalone attribute values for each of the date/time properties
+ if (startTime == null) {
+ startTime = el.data(prefix + 'start');
+ }
+ if (startTime == null) {
+ startTime = el.data(prefix + 'time');
+ } // accept 'time' as well
+ if (duration == null) {
+ duration = el.data(prefix + 'duration');
+ }
+ if (stick == null) {
+ stick = el.data(prefix + 'stick');
+ }
+ // massage into correct data types
+ startTime = startTime != null ? moment.duration(startTime) : null;
+ duration = duration != null ? moment.duration(duration) : null;
+ stick = Boolean(stick);
+ return { eventProps: eventProps, startTime: startTime, duration: duration, stick: stick };
+}
+
+
+/***/ }),
+/* 223 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var EventDefMutation_1 = __webpack_require__(37);
+var EventDefDateMutation_1 = __webpack_require__(50);
+var HitDragListener_1 = __webpack_require__(23);
+var Interaction_1 = __webpack_require__(15);
+var EventResizing = /** @class */ (function (_super) {
+ tslib_1.__extends(EventResizing, _super);
+ /*
+ component impements:
+ - bindSegHandlerToEl
+ - publiclyTrigger
+ - diffDates
+ - eventRangesToEventFootprints
+ - isEventInstanceGroupAllowed
+ - getSafeHitFootprint
+ */
+ function EventResizing(component, eventPointing) {
+ var _this = _super.call(this, component) || this;
+ _this.isResizing = false;
+ _this.eventPointing = eventPointing;
+ return _this;
+ }
+ EventResizing.prototype.end = function () {
+ if (this.dragListener) {
+ this.dragListener.endInteraction();
+ }
+ };
+ EventResizing.prototype.bindToEl = function (el) {
+ var component = this.component;
+ component.bindSegHandlerToEl(el, 'mousedown', this.handleMouseDown.bind(this));
+ component.bindSegHandlerToEl(el, 'touchstart', this.handleTouchStart.bind(this));
+ };
+ EventResizing.prototype.handleMouseDown = function (seg, ev) {
+ if (this.component.canStartResize(seg, ev)) {
+ this.buildDragListener(seg, $(ev.target).is('.fc-start-resizer'))
+ .startInteraction(ev, { distance: 5 });
+ }
+ };
+ EventResizing.prototype.handleTouchStart = function (seg, ev) {
+ if (this.component.canStartResize(seg, ev)) {
+ this.buildDragListener(seg, $(ev.target).is('.fc-start-resizer'))
+ .startInteraction(ev);
+ }
+ };
+ // Creates a listener that tracks the user as they resize an event segment.
+ // Generic enough to work with any type of Grid.
+ EventResizing.prototype.buildDragListener = function (seg, isStart) {
+ var _this = this;
+ var component = this.component;
+ var view = this.view;
+ var calendar = view.calendar;
+ var eventManager = calendar.eventManager;
+ var el = seg.el;
+ var eventDef = seg.footprint.eventDef;
+ var eventInstance = seg.footprint.eventInstance;
+ var isDragging;
+ var resizeMutation; // zoned event date properties. falsy if invalid resize
+ // Tracks mouse movement over the *grid's* coordinate map
+ var dragListener = this.dragListener = new HitDragListener_1.default(component, {
+ scroll: this.opt('dragScroll'),
+ subjectEl: el,
+ interactionStart: function () {
+ isDragging = false;
+ },
+ dragStart: function (ev) {
+ isDragging = true;
+ // ensure a mouseout on the manipulated event has been reported
+ _this.eventPointing.handleMouseout(seg, ev);
+ _this.segResizeStart(seg, ev);
+ },
+ hitOver: function (hit, isOrig, origHit) {
+ var isAllowed = true;
+ var origHitFootprint = component.getSafeHitFootprint(origHit);
+ var hitFootprint = component.getSafeHitFootprint(hit);
+ var mutatedEventInstanceGroup;
+ if (origHitFootprint && hitFootprint) {
+ resizeMutation = isStart ?
+ _this.computeEventStartResizeMutation(origHitFootprint, hitFootprint, seg.footprint) :
+ _this.computeEventEndResizeMutation(origHitFootprint, hitFootprint, seg.footprint);
+ if (resizeMutation) {
+ mutatedEventInstanceGroup = eventManager.buildMutatedEventInstanceGroup(eventDef.id, resizeMutation);
+ isAllowed = component.isEventInstanceGroupAllowed(mutatedEventInstanceGroup);
+ }
+ else {
+ isAllowed = false;
+ }
+ }
+ else {
+ isAllowed = false;
+ }
+ if (!isAllowed) {
+ resizeMutation = null;
+ util_1.disableCursor();
+ }
+ else if (resizeMutation.isEmpty()) {
+ // no change. (FYI, event dates might have zones)
+ resizeMutation = null;
+ }
+ if (resizeMutation) {
+ view.hideEventsWithId(seg.footprint.eventDef.id);
+ view.renderEventResize(component.eventRangesToEventFootprints(mutatedEventInstanceGroup.sliceRenderRanges(component.dateProfile.renderUnzonedRange, calendar)), seg);
+ }
+ },
+ hitOut: function () {
+ resizeMutation = null;
+ },
+ hitDone: function () {
+ view.unrenderEventResize(seg);
+ view.showEventsWithId(seg.footprint.eventDef.id);
+ util_1.enableCursor();
+ },
+ interactionEnd: function (ev) {
+ if (isDragging) {
+ _this.segResizeStop(seg, ev);
+ }
+ if (resizeMutation) {
+ // no need to re-show original, will rerender all anyways. esp important if eventRenderWait
+ view.reportEventResize(eventInstance, resizeMutation, el, ev);
+ }
+ _this.dragListener = null;
+ }
+ });
+ return dragListener;
+ };
+ // Called before event segment resizing starts
+ EventResizing.prototype.segResizeStart = function (seg, ev) {
+ this.isResizing = true;
+ this.component.publiclyTrigger('eventResizeStart', {
+ context: seg.el[0],
+ args: [
+ seg.footprint.getEventLegacy(),
+ ev,
+ {},
+ this.view
+ ]
+ });
+ };
+ // Called after event segment resizing stops
+ EventResizing.prototype.segResizeStop = function (seg, ev) {
+ this.isResizing = false;
+ this.component.publiclyTrigger('eventResizeStop', {
+ context: seg.el[0],
+ args: [
+ seg.footprint.getEventLegacy(),
+ ev,
+ {},
+ this.view
+ ]
+ });
+ };
+ // Returns new date-information for an event segment being resized from its start
+ EventResizing.prototype.computeEventStartResizeMutation = function (startFootprint, endFootprint, origEventFootprint) {
+ var origRange = origEventFootprint.componentFootprint.unzonedRange;
+ var startDelta = this.component.diffDates(endFootprint.unzonedRange.getStart(), startFootprint.unzonedRange.getStart());
+ var dateMutation;
+ var eventDefMutation;
+ if (origRange.getStart().add(startDelta) < origRange.getEnd()) {
+ dateMutation = new EventDefDateMutation_1.default();
+ dateMutation.setStartDelta(startDelta);
+ eventDefMutation = new EventDefMutation_1.default();
+ eventDefMutation.setDateMutation(dateMutation);
+ return eventDefMutation;
+ }
+ return false;
+ };
+ // Returns new date-information for an event segment being resized from its end
+ EventResizing.prototype.computeEventEndResizeMutation = function (startFootprint, endFootprint, origEventFootprint) {
+ var origRange = origEventFootprint.componentFootprint.unzonedRange;
+ var endDelta = this.component.diffDates(endFootprint.unzonedRange.getEnd(), startFootprint.unzonedRange.getEnd());
+ var dateMutation;
+ var eventDefMutation;
+ if (origRange.getEnd().add(endDelta) > origRange.getStart()) {
+ dateMutation = new EventDefDateMutation_1.default();
+ dateMutation.setEndDelta(endDelta);
+ eventDefMutation = new EventDefMutation_1.default();
+ eventDefMutation.setDateMutation(dateMutation);
+ return eventDefMutation;
+ }
+ return false;
+ };
+ return EventResizing;
+}(Interaction_1.default));
+exports.default = EventResizing;
+
+
+/***/ }),
+/* 224 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var EventDefMutation_1 = __webpack_require__(37);
+var EventDefDateMutation_1 = __webpack_require__(50);
+var DragListener_1 = __webpack_require__(54);
+var HitDragListener_1 = __webpack_require__(23);
+var MouseFollower_1 = __webpack_require__(244);
+var Interaction_1 = __webpack_require__(15);
+var EventDragging = /** @class */ (function (_super) {
+ tslib_1.__extends(EventDragging, _super);
+ /*
+ component implements:
+ - bindSegHandlerToEl
+ - publiclyTrigger
+ - diffDates
+ - eventRangesToEventFootprints
+ - isEventInstanceGroupAllowed
+ */
+ function EventDragging(component, eventPointing) {
+ var _this = _super.call(this, component) || this;
+ _this.isDragging = false;
+ _this.eventPointing = eventPointing;
+ return _this;
+ }
+ EventDragging.prototype.end = function () {
+ if (this.dragListener) {
+ this.dragListener.endInteraction();
+ }
+ };
+ EventDragging.prototype.getSelectionDelay = function () {
+ var delay = this.opt('eventLongPressDelay');
+ if (delay == null) {
+ delay = this.opt('longPressDelay'); // fallback
+ }
+ return delay;
+ };
+ EventDragging.prototype.bindToEl = function (el) {
+ var component = this.component;
+ component.bindSegHandlerToEl(el, 'mousedown', this.handleMousedown.bind(this));
+ component.bindSegHandlerToEl(el, 'touchstart', this.handleTouchStart.bind(this));
+ };
+ EventDragging.prototype.handleMousedown = function (seg, ev) {
+ if (!this.component.shouldIgnoreMouse() &&
+ this.component.canStartDrag(seg, ev)) {
+ this.buildDragListener(seg).startInteraction(ev, { distance: 5 });
+ }
+ };
+ EventDragging.prototype.handleTouchStart = function (seg, ev) {
+ var component = this.component;
+ var settings = {
+ delay: this.view.isEventDefSelected(seg.footprint.eventDef) ? // already selected?
+ 0 : this.getSelectionDelay()
+ };
+ if (component.canStartDrag(seg, ev)) {
+ this.buildDragListener(seg).startInteraction(ev, settings);
+ }
+ else if (component.canStartSelection(seg, ev)) {
+ this.buildSelectListener(seg).startInteraction(ev, settings);
+ }
+ };
+ // seg isn't draggable, but let's use a generic DragListener
+ // simply for the delay, so it can be selected.
+ // Has side effect of setting/unsetting `dragListener`
+ EventDragging.prototype.buildSelectListener = function (seg) {
+ var _this = this;
+ var view = this.view;
+ var eventDef = seg.footprint.eventDef;
+ var eventInstance = seg.footprint.eventInstance; // null for inverse-background events
+ if (this.dragListener) {
+ return this.dragListener;
+ }
+ var dragListener = this.dragListener = new DragListener_1.default({
+ dragStart: function (ev) {
+ if (dragListener.isTouch &&
+ !view.isEventDefSelected(eventDef) &&
+ eventInstance) {
+ // if not previously selected, will fire after a delay. then, select the event
+ view.selectEventInstance(eventInstance);
+ }
+ },
+ interactionEnd: function (ev) {
+ _this.dragListener = null;
+ }
+ });
+ return dragListener;
+ };
+ // Builds a listener that will track user-dragging on an event segment.
+ // Generic enough to work with any type of Grid.
+ // Has side effect of setting/unsetting `dragListener`
+ EventDragging.prototype.buildDragListener = function (seg) {
+ var _this = this;
+ var component = this.component;
+ var view = this.view;
+ var calendar = view.calendar;
+ var eventManager = calendar.eventManager;
+ var el = seg.el;
+ var eventDef = seg.footprint.eventDef;
+ var eventInstance = seg.footprint.eventInstance; // null for inverse-background events
+ var isDragging;
+ var mouseFollower; // A clone of the original element that will move with the mouse
+ var eventDefMutation;
+ if (this.dragListener) {
+ return this.dragListener;
+ }
+ // Tracks mouse movement over the *view's* coordinate map. Allows dragging and dropping between subcomponents
+ // of the view.
+ var dragListener = this.dragListener = new HitDragListener_1.default(view, {
+ scroll: this.opt('dragScroll'),
+ subjectEl: el,
+ subjectCenter: true,
+ interactionStart: function (ev) {
+ seg.component = component; // for renderDrag
+ isDragging = false;
+ mouseFollower = new MouseFollower_1.default(seg.el, {
+ additionalClass: 'fc-dragging',
+ parentEl: view.el,
+ opacity: dragListener.isTouch ? null : _this.opt('dragOpacity'),
+ revertDuration: _this.opt('dragRevertDuration'),
+ zIndex: 2 // one above the .fc-view
+ });
+ mouseFollower.hide(); // don't show until we know this is a real drag
+ mouseFollower.start(ev);
+ },
+ dragStart: function (ev) {
+ if (dragListener.isTouch &&
+ !view.isEventDefSelected(eventDef) &&
+ eventInstance) {
+ // if not previously selected, will fire after a delay. then, select the event
+ view.selectEventInstance(eventInstance);
+ }
+ isDragging = true;
+ // ensure a mouseout on the manipulated event has been reported
+ _this.eventPointing.handleMouseout(seg, ev);
+ _this.segDragStart(seg, ev);
+ view.hideEventsWithId(seg.footprint.eventDef.id);
+ },
+ hitOver: function (hit, isOrig, origHit) {
+ var isAllowed = true;
+ var origFootprint;
+ var footprint;
+ var mutatedEventInstanceGroup;
+ // starting hit could be forced (DayGrid.limit)
+ if (seg.hit) {
+ origHit = seg.hit;
+ }
+ // hit might not belong to this grid, so query origin grid
+ origFootprint = origHit.component.getSafeHitFootprint(origHit);
+ footprint = hit.component.getSafeHitFootprint(hit);
+ if (origFootprint && footprint) {
+ eventDefMutation = _this.computeEventDropMutation(origFootprint, footprint, eventDef);
+ if (eventDefMutation) {
+ mutatedEventInstanceGroup = eventManager.buildMutatedEventInstanceGroup(eventDef.id, eventDefMutation);
+ isAllowed = component.isEventInstanceGroupAllowed(mutatedEventInstanceGroup);
+ }
+ else {
+ isAllowed = false;
+ }
+ }
+ else {
+ isAllowed = false;
+ }
+ if (!isAllowed) {
+ eventDefMutation = null;
+ util_1.disableCursor();
+ }
+ // if a valid drop location, have the subclass render a visual indication
+ if (eventDefMutation &&
+ view.renderDrag(// truthy if rendered something
+ component.eventRangesToEventFootprints(mutatedEventInstanceGroup.sliceRenderRanges(component.dateProfile.renderUnzonedRange, calendar)), seg, dragListener.isTouch)) {
+ mouseFollower.hide(); // if the subclass is already using a mock event "helper", hide our own
+ }
+ else {
+ mouseFollower.show(); // otherwise, have the helper follow the mouse (no snapping)
+ }
+ if (isOrig) {
+ // needs to have moved hits to be a valid drop
+ eventDefMutation = null;
+ }
+ },
+ hitOut: function () {
+ view.unrenderDrag(seg); // unrender whatever was done in renderDrag
+ mouseFollower.show(); // show in case we are moving out of all hits
+ eventDefMutation = null;
+ },
+ hitDone: function () {
+ util_1.enableCursor();
+ },
+ interactionEnd: function (ev) {
+ delete seg.component; // prevent side effects
+ // do revert animation if hasn't changed. calls a callback when finished (whether animation or not)
+ mouseFollower.stop(!eventDefMutation, function () {
+ if (isDragging) {
+ view.unrenderDrag(seg);
+ _this.segDragStop(seg, ev);
+ }
+ view.showEventsWithId(seg.footprint.eventDef.id);
+ if (eventDefMutation) {
+ // no need to re-show original, will rerender all anyways. esp important if eventRenderWait
+ view.reportEventDrop(eventInstance, eventDefMutation, el, ev);
+ }
+ });
+ _this.dragListener = null;
+ }
+ });
+ return dragListener;
+ };
+ // Called before event segment dragging starts
+ EventDragging.prototype.segDragStart = function (seg, ev) {
+ this.isDragging = true;
+ this.component.publiclyTrigger('eventDragStart', {
+ context: seg.el[0],
+ args: [
+ seg.footprint.getEventLegacy(),
+ ev,
+ {},
+ this.view
+ ]
+ });
+ };
+ // Called after event segment dragging stops
+ EventDragging.prototype.segDragStop = function (seg, ev) {
+ this.isDragging = false;
+ this.component.publiclyTrigger('eventDragStop', {
+ context: seg.el[0],
+ args: [
+ seg.footprint.getEventLegacy(),
+ ev,
+ {},
+ this.view
+ ]
+ });
+ };
+ // DOES NOT consider overlap/constraint
+ EventDragging.prototype.computeEventDropMutation = function (startFootprint, endFootprint, eventDef) {
+ var eventDefMutation = new EventDefMutation_1.default();
+ eventDefMutation.setDateMutation(this.computeEventDateMutation(startFootprint, endFootprint));
+ return eventDefMutation;
+ };
+ EventDragging.prototype.computeEventDateMutation = function (startFootprint, endFootprint) {
+ var date0 = startFootprint.unzonedRange.getStart();
+ var date1 = endFootprint.unzonedRange.getStart();
+ var clearEnd = false;
+ var forceTimed = false;
+ var forceAllDay = false;
+ var dateDelta;
+ var dateMutation;
+ if (startFootprint.isAllDay !== endFootprint.isAllDay) {
+ clearEnd = true;
+ if (endFootprint.isAllDay) {
+ forceAllDay = true;
+ date0.stripTime();
+ }
+ else {
+ forceTimed = true;
+ }
+ }
+ dateDelta = this.component.diffDates(date1, date0);
+ dateMutation = new EventDefDateMutation_1.default();
+ dateMutation.clearEnd = clearEnd;
+ dateMutation.forceTimed = forceTimed;
+ dateMutation.forceAllDay = forceAllDay;
+ dateMutation.setDateDelta(dateDelta);
+ return dateMutation;
+ };
+ return EventDragging;
+}(Interaction_1.default));
+exports.default = EventDragging;
+
+
+/***/ }),
+/* 225 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var HitDragListener_1 = __webpack_require__(23);
+var ComponentFootprint_1 = __webpack_require__(12);
+var UnzonedRange_1 = __webpack_require__(5);
+var Interaction_1 = __webpack_require__(15);
+var DateSelecting = /** @class */ (function (_super) {
+ tslib_1.__extends(DateSelecting, _super);
+ /*
+ component must implement:
+ - bindDateHandlerToEl
+ - getSafeHitFootprint
+ - renderHighlight
+ - unrenderHighlight
+ */
+ function DateSelecting(component) {
+ var _this = _super.call(this, component) || this;
+ _this.dragListener = _this.buildDragListener();
+ return _this;
+ }
+ DateSelecting.prototype.end = function () {
+ this.dragListener.endInteraction();
+ };
+ DateSelecting.prototype.getDelay = function () {
+ var delay = this.opt('selectLongPressDelay');
+ if (delay == null) {
+ delay = this.opt('longPressDelay'); // fallback
+ }
+ return delay;
+ };
+ DateSelecting.prototype.bindToEl = function (el) {
+ var _this = this;
+ var component = this.component;
+ var dragListener = this.dragListener;
+ component.bindDateHandlerToEl(el, 'mousedown', function (ev) {
+ if (_this.opt('selectable') && !component.shouldIgnoreMouse()) {
+ dragListener.startInteraction(ev, {
+ distance: _this.opt('selectMinDistance')
+ });
+ }
+ });
+ component.bindDateHandlerToEl(el, 'touchstart', function (ev) {
+ if (_this.opt('selectable') && !component.shouldIgnoreTouch()) {
+ dragListener.startInteraction(ev, {
+ delay: _this.getDelay()
+ });
+ }
+ });
+ util_1.preventSelection(el);
+ };
+ // Creates a listener that tracks the user's drag across day elements, for day selecting.
+ DateSelecting.prototype.buildDragListener = function () {
+ var _this = this;
+ var component = this.component;
+ var selectionFootprint; // null if invalid selection
+ var dragListener = new HitDragListener_1.default(component, {
+ scroll: this.opt('dragScroll'),
+ interactionStart: function () {
+ selectionFootprint = null;
+ },
+ dragStart: function (ev) {
+ _this.view.unselect(ev); // since we could be rendering a new selection, we want to clear any old one
+ },
+ hitOver: function (hit, isOrig, origHit) {
+ var origHitFootprint;
+ var hitFootprint;
+ if (origHit) {
+ origHitFootprint = component.getSafeHitFootprint(origHit);
+ hitFootprint = component.getSafeHitFootprint(hit);
+ if (origHitFootprint && hitFootprint) {
+ selectionFootprint = _this.computeSelection(origHitFootprint, hitFootprint);
+ }
+ else {
+ selectionFootprint = null;
+ }
+ if (selectionFootprint) {
+ component.renderSelectionFootprint(selectionFootprint);
+ }
+ else if (selectionFootprint === false) {
+ util_1.disableCursor();
+ }
+ }
+ },
+ hitOut: function () {
+ selectionFootprint = null;
+ component.unrenderSelection();
+ },
+ hitDone: function () {
+ util_1.enableCursor();
+ },
+ interactionEnd: function (ev, isCancelled) {
+ if (!isCancelled && selectionFootprint) {
+ // the selection will already have been rendered. just report it
+ _this.view.reportSelection(selectionFootprint, ev);
+ }
+ }
+ });
+ return dragListener;
+ };
+ // Given the first and last date-spans of a selection, returns another date-span object.
+ // Subclasses can override and provide additional data in the span object. Will be passed to renderSelectionFootprint().
+ // Will return false if the selection is invalid and this should be indicated to the user.
+ // Will return null/undefined if a selection invalid but no error should be reported.
+ DateSelecting.prototype.computeSelection = function (footprint0, footprint1) {
+ var wholeFootprint = this.computeSelectionFootprint(footprint0, footprint1);
+ if (wholeFootprint && !this.isSelectionFootprintAllowed(wholeFootprint)) {
+ return false;
+ }
+ return wholeFootprint;
+ };
+ // Given two spans, must return the combination of the two.
+ // TODO: do this separation of concerns (combining VS validation) for event dnd/resize too.
+ // Assumes both footprints are non-open-ended.
+ DateSelecting.prototype.computeSelectionFootprint = function (footprint0, footprint1) {
+ var ms = [
+ footprint0.unzonedRange.startMs,
+ footprint0.unzonedRange.endMs,
+ footprint1.unzonedRange.startMs,
+ footprint1.unzonedRange.endMs
+ ];
+ ms.sort(util_1.compareNumbers);
+ return new ComponentFootprint_1.default(new UnzonedRange_1.default(ms[0], ms[3]), footprint0.isAllDay);
+ };
+ DateSelecting.prototype.isSelectionFootprintAllowed = function (componentFootprint) {
+ return this.component.dateProfile.validUnzonedRange.containsRange(componentFootprint.unzonedRange) &&
+ this.view.calendar.constraints.isSelectionFootprintAllowed(componentFootprint);
+ };
+ return DateSelecting;
+}(Interaction_1.default));
+exports.default = DateSelecting;
+
+
+/***/ }),
+/* 226 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var moment = __webpack_require__(0);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Scroller_1 = __webpack_require__(39);
+var View_1 = __webpack_require__(41);
+var TimeGrid_1 = __webpack_require__(227);
+var DayGrid_1 = __webpack_require__(61);
+var AGENDA_ALL_DAY_EVENT_LIMIT = 5;
+var agendaTimeGridMethods;
+var agendaDayGridMethods;
+/* An abstract class for all agenda-related views. Displays one more columns with time slots running vertically.
+----------------------------------------------------------------------------------------------------------------------*/
+// Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
+// Responsible for managing width/height.
+var AgendaView = /** @class */ (function (_super) {
+ tslib_1.__extends(AgendaView, _super);
+ function AgendaView(calendar, viewSpec) {
+ var _this = _super.call(this, calendar, viewSpec) || this;
+ _this.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering
+ _this.timeGrid = _this.instantiateTimeGrid();
+ _this.addChild(_this.timeGrid);
+ if (_this.opt('allDaySlot')) {
+ _this.dayGrid = _this.instantiateDayGrid(); // the all-day subcomponent of this view
+ _this.addChild(_this.dayGrid);
+ }
+ _this.scroller = new Scroller_1.default({
+ overflowX: 'hidden',
+ overflowY: 'auto'
+ });
+ return _this;
+ }
+ // Instantiates the TimeGrid object this view needs. Draws from this.timeGridClass
+ AgendaView.prototype.instantiateTimeGrid = function () {
+ var timeGrid = new this.timeGridClass(this);
+ util_1.copyOwnProps(agendaTimeGridMethods, timeGrid);
+ return timeGrid;
+ };
+ // Instantiates the DayGrid object this view might need. Draws from this.dayGridClass
+ AgendaView.prototype.instantiateDayGrid = function () {
+ var dayGrid = new this.dayGridClass(this);
+ util_1.copyOwnProps(agendaDayGridMethods, dayGrid);
+ return dayGrid;
+ };
+ /* Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ AgendaView.prototype.renderSkeleton = function () {
+ var timeGridWrapEl;
+ var timeGridEl;
+ this.el.addClass('fc-agenda-view').html(this.renderSkeletonHtml());
+ this.scroller.render();
+ timeGridWrapEl = this.scroller.el.addClass('fc-time-grid-container');
+ timeGridEl = $('<div class="fc-time-grid" />').appendTo(timeGridWrapEl);
+ this.el.find('.fc-body > tr > td').append(timeGridWrapEl);
+ this.timeGrid.headContainerEl = this.el.find('.fc-head-container');
+ this.timeGrid.setElement(timeGridEl);
+ if (this.dayGrid) {
+ this.dayGrid.setElement(this.el.find('.fc-day-grid'));
+ // have the day-grid extend it's coordinate area over the <hr> dividing the two grids
+ this.dayGrid.bottomCoordPadding = this.dayGrid.el.next('hr').outerHeight();
+ }
+ };
+ AgendaView.prototype.unrenderSkeleton = function () {
+ this.timeGrid.removeElement();
+ if (this.dayGrid) {
+ this.dayGrid.removeElement();
+ }
+ this.scroller.destroy();
+ };
+ // Builds the HTML skeleton for the view.
+ // The day-grid and time-grid components will render inside containers defined by this HTML.
+ AgendaView.prototype.renderSkeletonHtml = function () {
+ var theme = this.calendar.theme;
+ return '' +
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ (this.opt('columnHeader') ?
+ '<thead class="fc-head">' +
+ '<tr>' +
+ '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '">&nbsp;</td>' +
+ '</tr>' +
+ '</thead>' :
+ '') +
+ '<tbody class="fc-body">' +
+ '<tr>' +
+ '<td class="' + theme.getClass('widgetContent') + '">' +
+ (this.dayGrid ?
+ '<div class="fc-day-grid"/>' +
+ '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '"/>' :
+ '') +
+ '</td>' +
+ '</tr>' +
+ '</tbody>' +
+ '</table>';
+ };
+ // Generates an HTML attribute string for setting the width of the axis, if it is known
+ AgendaView.prototype.axisStyleAttr = function () {
+ if (this.axisWidth != null) {
+ return 'style="width:' + this.axisWidth + 'px"';
+ }
+ return '';
+ };
+ /* Now Indicator
+ ------------------------------------------------------------------------------------------------------------------*/
+ AgendaView.prototype.getNowIndicatorUnit = function () {
+ return this.timeGrid.getNowIndicatorUnit();
+ };
+ /* Dimensions
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Adjusts the vertical dimensions of the view to the specified values
+ AgendaView.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ var eventLimit;
+ var scrollerHeight;
+ var scrollbarWidths;
+ _super.prototype.updateSize.call(this, totalHeight, isAuto, isResize);
+ // make all axis cells line up, and record the width so newly created axis cells will have it
+ this.axisWidth = util_1.matchCellWidths(this.el.find('.fc-axis'));
+ // hack to give the view some height prior to timeGrid's columns being rendered
+ // TODO: separate setting height from scroller VS timeGrid.
+ if (!this.timeGrid.colEls) {
+ if (!isAuto) {
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ return;
+ }
+ // set of fake row elements that must compensate when scroller has scrollbars
+ var noScrollRowEls = this.el.find('.fc-row:not(.fc-scroller *)');
+ // reset all dimensions back to the original state
+ this.timeGrid.bottomRuleEl.hide(); // .show() will be called later if this <hr> is necessary
+ this.scroller.clear(); // sets height to 'auto' and clears overflow
+ util_1.uncompensateScroll(noScrollRowEls);
+ // limit number of events in the all-day area
+ if (this.dayGrid) {
+ this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
+ eventLimit = this.opt('eventLimit');
+ if (eventLimit && typeof eventLimit !== 'number') {
+ eventLimit = AGENDA_ALL_DAY_EVENT_LIMIT; // make sure "auto" goes to a real number
+ }
+ if (eventLimit) {
+ this.dayGrid.limitRows(eventLimit);
+ }
+ }
+ if (!isAuto) {
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.scroller.setHeight(scrollerHeight);
+ scrollbarWidths = this.scroller.getScrollbarWidths();
+ if (scrollbarWidths.left || scrollbarWidths.right) {
+ // make the all-day and header rows lines up
+ util_1.compensateScroll(noScrollRowEls, scrollbarWidths);
+ // the scrollbar compensation might have changed text flow, which might affect height, so recalculate
+ // and reapply the desired height to the scroller.
+ scrollerHeight = this.computeScrollerHeight(totalHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ // guarantees the same scrollbar widths
+ this.scroller.lockOverflow(scrollbarWidths);
+ // if there's any space below the slats, show the horizontal rule.
+ // this won't cause any new overflow, because lockOverflow already called.
+ if (this.timeGrid.getTotalSlatHeight() < scrollerHeight) {
+ this.timeGrid.bottomRuleEl.show();
+ }
+ }
+ };
+ // given a desired total height of the view, returns what the height of the scroller should be
+ AgendaView.prototype.computeScrollerHeight = function (totalHeight) {
+ return totalHeight -
+ util_1.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
+ };
+ /* Scroll
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Computes the initial pre-configured scroll state prior to allowing the user to change it
+ AgendaView.prototype.computeInitialDateScroll = function () {
+ var scrollTime = moment.duration(this.opt('scrollTime'));
+ var top = this.timeGrid.computeTimeTop(scrollTime);
+ // zoom can give weird floating-point values. rather scroll a little bit further
+ top = Math.ceil(top);
+ if (top) {
+ top++; // to overcome top border that slots beyond the first have. looks better
+ }
+ return { top: top };
+ };
+ AgendaView.prototype.queryDateScroll = function () {
+ return { top: this.scroller.getScrollTop() };
+ };
+ AgendaView.prototype.applyDateScroll = function (scroll) {
+ if (scroll.top !== undefined) {
+ this.scroller.setScrollTop(scroll.top);
+ }
+ };
+ /* Hit Areas
+ ------------------------------------------------------------------------------------------------------------------*/
+ // forward all hit-related method calls to the grids (dayGrid might not be defined)
+ AgendaView.prototype.getHitFootprint = function (hit) {
+ // TODO: hit.component is set as a hack to identify where the hit came from
+ return hit.component.getHitFootprint(hit);
+ };
+ AgendaView.prototype.getHitEl = function (hit) {
+ // TODO: hit.component is set as a hack to identify where the hit came from
+ return hit.component.getHitEl(hit);
+ };
+ /* Event Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ AgendaView.prototype.executeEventRender = function (eventsPayload) {
+ var dayEventsPayload = {};
+ var timedEventsPayload = {};
+ var id;
+ var eventInstanceGroup;
+ // separate the events into all-day and timed
+ for (id in eventsPayload) {
+ eventInstanceGroup = eventsPayload[id];
+ if (eventInstanceGroup.getEventDef().isAllDay()) {
+ dayEventsPayload[id] = eventInstanceGroup;
+ }
+ else {
+ timedEventsPayload[id] = eventInstanceGroup;
+ }
+ }
+ this.timeGrid.executeEventRender(timedEventsPayload);
+ if (this.dayGrid) {
+ this.dayGrid.executeEventRender(dayEventsPayload);
+ }
+ };
+ /* Dragging/Resizing Routing
+ ------------------------------------------------------------------------------------------------------------------*/
+ // A returned value of `true` signals that a mock "helper" event has been rendered.
+ AgendaView.prototype.renderDrag = function (eventFootprints, seg, isTouch) {
+ var groups = groupEventFootprintsByAllDay(eventFootprints);
+ var renderedHelper = false;
+ renderedHelper = this.timeGrid.renderDrag(groups.timed, seg, isTouch);
+ if (this.dayGrid) {
+ renderedHelper = this.dayGrid.renderDrag(groups.allDay, seg, isTouch) || renderedHelper;
+ }
+ return renderedHelper;
+ };
+ AgendaView.prototype.renderEventResize = function (eventFootprints, seg, isTouch) {
+ var groups = groupEventFootprintsByAllDay(eventFootprints);
+ this.timeGrid.renderEventResize(groups.timed, seg, isTouch);
+ if (this.dayGrid) {
+ this.dayGrid.renderEventResize(groups.allDay, seg, isTouch);
+ }
+ };
+ /* Selection
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of a selection
+ AgendaView.prototype.renderSelectionFootprint = function (componentFootprint) {
+ if (!componentFootprint.isAllDay) {
+ this.timeGrid.renderSelectionFootprint(componentFootprint);
+ }
+ else if (this.dayGrid) {
+ this.dayGrid.renderSelectionFootprint(componentFootprint);
+ }
+ };
+ return AgendaView;
+}(View_1.default));
+exports.default = AgendaView;
+AgendaView.prototype.timeGridClass = TimeGrid_1.default;
+AgendaView.prototype.dayGridClass = DayGrid_1.default;
+// Will customize the rendering behavior of the AgendaView's timeGrid
+agendaTimeGridMethods = {
+ // Generates the HTML that will go before the day-of week header cells
+ renderHeadIntroHtml: function () {
+ var view = this.view;
+ var calendar = view.calendar;
+ var weekStart = calendar.msToUtcMoment(this.dateProfile.renderUnzonedRange.startMs, true);
+ var weekText;
+ if (this.opt('weekNumbers')) {
+ weekText = weekStart.format(this.opt('smallWeekFormat'));
+ return '' +
+ '<th class="fc-axis fc-week-number ' + calendar.theme.getClass('widgetHeader') + '" ' + view.axisStyleAttr() + '>' +
+ view.buildGotoAnchorHtml(// aside from link, important for matchCellWidths
+ { date: weekStart, type: 'week', forceOff: this.colCnt > 1 }, util_1.htmlEscape(weekText) // inner HTML
+ ) +
+ '</th>';
+ }
+ else {
+ return '<th class="fc-axis ' + calendar.theme.getClass('widgetHeader') + '" ' + view.axisStyleAttr() + '></th>';
+ }
+ },
+ // Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column.
+ renderBgIntroHtml: function () {
+ var view = this.view;
+ return '<td class="fc-axis ' + view.calendar.theme.getClass('widgetContent') + '" ' + view.axisStyleAttr() + '></td>';
+ },
+ // Generates the HTML that goes before all other types of cells.
+ // Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
+ renderIntroHtml: function () {
+ var view = this.view;
+ return '<td class="fc-axis" ' + view.axisStyleAttr() + '></td>';
+ }
+};
+// Will customize the rendering behavior of the AgendaView's dayGrid
+agendaDayGridMethods = {
+ // Generates the HTML that goes before the all-day cells
+ renderBgIntroHtml: function () {
+ var view = this.view;
+ return '' +
+ '<td class="fc-axis ' + view.calendar.theme.getClass('widgetContent') + '" ' + view.axisStyleAttr() + '>' +
+ '<span>' + // needed for matchCellWidths
+ view.getAllDayHtml() +
+ '</span>' +
+ '</td>';
+ },
+ // Generates the HTML that goes before all other types of cells.
+ // Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
+ renderIntroHtml: function () {
+ var view = this.view;
+ return '<td class="fc-axis" ' + view.axisStyleAttr() + '></td>';
+ }
+};
+function groupEventFootprintsByAllDay(eventFootprints) {
+ var allDay = [];
+ var timed = [];
+ var i;
+ for (i = 0; i < eventFootprints.length; i++) {
+ if (eventFootprints[i].componentFootprint.isAllDay) {
+ allDay.push(eventFootprints[i]);
+ }
+ else {
+ timed.push(eventFootprints[i]);
+ }
+ }
+ return { allDay: allDay, timed: timed };
+}
+
+
+/***/ }),
+/* 227 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var InteractiveDateComponent_1 = __webpack_require__(40);
+var BusinessHourRenderer_1 = __webpack_require__(56);
+var StandardInteractionsMixin_1 = __webpack_require__(60);
+var DayTableMixin_1 = __webpack_require__(55);
+var CoordCache_1 = __webpack_require__(53);
+var UnzonedRange_1 = __webpack_require__(5);
+var ComponentFootprint_1 = __webpack_require__(12);
+var TimeGridEventRenderer_1 = __webpack_require__(246);
+var TimeGridHelperRenderer_1 = __webpack_require__(247);
+var TimeGridFillRenderer_1 = __webpack_require__(248);
+/* A component that renders one or more columns of vertical time slots
+----------------------------------------------------------------------------------------------------------------------*/
+// We mixin DayTable, even though there is only a single row of days
+// potential nice values for the slot-duration and interval-duration
+// from largest to smallest
+var AGENDA_STOCK_SUB_DURATIONS = [
+ { hours: 1 },
+ { minutes: 30 },
+ { minutes: 15 },
+ { seconds: 30 },
+ { seconds: 15 }
+];
+var TimeGrid = /** @class */ (function (_super) {
+ tslib_1.__extends(TimeGrid, _super);
+ function TimeGrid(view) {
+ var _this = _super.call(this, view) || this;
+ _this.processOptions();
+ return _this;
+ }
+ // Slices up the given span (unzoned start/end with other misc data) into an array of segments
+ TimeGrid.prototype.componentFootprintToSegs = function (componentFootprint) {
+ var segs = this.sliceRangeByTimes(componentFootprint.unzonedRange);
+ var i;
+ for (i = 0; i < segs.length; i++) {
+ if (this.isRTL) {
+ segs[i].col = this.daysPerRow - 1 - segs[i].dayIndex;
+ }
+ else {
+ segs[i].col = segs[i].dayIndex;
+ }
+ }
+ return segs;
+ };
+ /* Date Handling
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.sliceRangeByTimes = function (unzonedRange) {
+ var segs = [];
+ var segRange;
+ var dayIndex;
+ for (dayIndex = 0; dayIndex < this.daysPerRow; dayIndex++) {
+ segRange = unzonedRange.intersect(this.dayRanges[dayIndex]);
+ if (segRange) {
+ segs.push({
+ startMs: segRange.startMs,
+ endMs: segRange.endMs,
+ isStart: segRange.isStart,
+ isEnd: segRange.isEnd,
+ dayIndex: dayIndex
+ });
+ }
+ }
+ return segs;
+ };
+ /* Options
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Parses various options into properties of this object
+ TimeGrid.prototype.processOptions = function () {
+ var slotDuration = this.opt('slotDuration');
+ var snapDuration = this.opt('snapDuration');
+ var input;
+ slotDuration = moment.duration(slotDuration);
+ snapDuration = snapDuration ? moment.duration(snapDuration) : slotDuration;
+ this.slotDuration = slotDuration;
+ this.snapDuration = snapDuration;
+ this.snapsPerSlot = slotDuration / snapDuration; // TODO: ensure an integer multiple?
+ // might be an array value (for TimelineView).
+ // if so, getting the most granular entry (the last one probably).
+ input = this.opt('slotLabelFormat');
+ if ($.isArray(input)) {
+ input = input[input.length - 1];
+ }
+ this.labelFormat = input ||
+ this.opt('smallTimeFormat'); // the computed default
+ input = this.opt('slotLabelInterval');
+ this.labelInterval = input ?
+ moment.duration(input) :
+ this.computeLabelInterval(slotDuration);
+ };
+ // Computes an automatic value for slotLabelInterval
+ TimeGrid.prototype.computeLabelInterval = function (slotDuration) {
+ var i;
+ var labelInterval;
+ var slotsPerLabel;
+ // find the smallest stock label interval that results in more than one slots-per-label
+ for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
+ labelInterval = moment.duration(AGENDA_STOCK_SUB_DURATIONS[i]);
+ slotsPerLabel = util_1.divideDurationByDuration(labelInterval, slotDuration);
+ if (util_1.isInt(slotsPerLabel) && slotsPerLabel > 1) {
+ return labelInterval;
+ }
+ }
+ return moment.duration(slotDuration); // fall back. clone
+ };
+ /* Date Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.renderDates = function (dateProfile) {
+ this.dateProfile = dateProfile;
+ this.updateDayTable();
+ this.renderSlats();
+ this.renderColumns();
+ };
+ TimeGrid.prototype.unrenderDates = function () {
+ // this.unrenderSlats(); // don't need this because repeated .html() calls clear
+ this.unrenderColumns();
+ };
+ TimeGrid.prototype.renderSkeleton = function () {
+ var theme = this.view.calendar.theme;
+ this.el.html('<div class="fc-bg"></div>' +
+ '<div class="fc-slats"></div>' +
+ '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" style="display:none" />');
+ this.bottomRuleEl = this.el.find('hr');
+ };
+ TimeGrid.prototype.renderSlats = function () {
+ var theme = this.view.calendar.theme;
+ this.slatContainerEl = this.el.find('> .fc-slats')
+ .html(// avoids needing ::unrenderSlats()
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ this.renderSlatRowHtml() +
+ '</table>');
+ this.slatEls = this.slatContainerEl.find('tr');
+ this.slatCoordCache = new CoordCache_1.default({
+ els: this.slatEls,
+ isVertical: true
+ });
+ };
+ // Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
+ TimeGrid.prototype.renderSlatRowHtml = function () {
+ var view = this.view;
+ var calendar = view.calendar;
+ var theme = calendar.theme;
+ var isRTL = this.isRTL;
+ var dateProfile = this.dateProfile;
+ var html = '';
+ var slotTime = moment.duration(+dateProfile.minTime); // wish there was .clone() for durations
+ var slotIterator = moment.duration(0);
+ var slotDate; // will be on the view's first day, but we only care about its time
+ var isLabeled;
+ var axisHtml;
+ // Calculate the time for each slot
+ while (slotTime < dateProfile.maxTime) {
+ slotDate = calendar.msToUtcMoment(dateProfile.renderUnzonedRange.startMs).time(slotTime);
+ isLabeled = util_1.isInt(util_1.divideDurationByDuration(slotIterator, this.labelInterval));
+ axisHtml =
+ '<td class="fc-axis fc-time ' + theme.getClass('widgetContent') + '" ' + view.axisStyleAttr() + '>' +
+ (isLabeled ?
+ '<span>' + // for matchCellWidths
+ util_1.htmlEscape(slotDate.format(this.labelFormat)) +
+ '</span>' :
+ '') +
+ '</td>';
+ html +=
+ '<tr data-time="' + slotDate.format('HH:mm:ss') + '"' +
+ (isLabeled ? '' : ' class="fc-minor"') +
+ '>' +
+ (!isRTL ? axisHtml : '') +
+ '<td class="' + theme.getClass('widgetContent') + '"/>' +
+ (isRTL ? axisHtml : '') +
+ '</tr>';
+ slotTime.add(this.slotDuration);
+ slotIterator.add(this.slotDuration);
+ }
+ return html;
+ };
+ TimeGrid.prototype.renderColumns = function () {
+ var dateProfile = this.dateProfile;
+ var theme = this.view.calendar.theme;
+ this.dayRanges = this.dayDates.map(function (dayDate) {
+ return new UnzonedRange_1.default(dayDate.clone().add(dateProfile.minTime), dayDate.clone().add(dateProfile.maxTime));
+ });
+ if (this.headContainerEl) {
+ this.headContainerEl.html(this.renderHeadHtml());
+ }
+ this.el.find('> .fc-bg').html('<table class="' + theme.getClass('tableGrid') + '">' +
+ this.renderBgTrHtml(0) + // row=0
+ '</table>');
+ this.colEls = this.el.find('.fc-day, .fc-disabled-day');
+ this.colCoordCache = new CoordCache_1.default({
+ els: this.colEls,
+ isHorizontal: true
+ });
+ this.renderContentSkeleton();
+ };
+ TimeGrid.prototype.unrenderColumns = function () {
+ this.unrenderContentSkeleton();
+ };
+ /* Content Skeleton
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders the DOM that the view's content will live in
+ TimeGrid.prototype.renderContentSkeleton = function () {
+ var cellHtml = '';
+ var i;
+ var skeletonEl;
+ for (i = 0; i < this.colCnt; i++) {
+ cellHtml +=
+ '<td>' +
+ '<div class="fc-content-col">' +
+ '<div class="fc-event-container fc-helper-container"></div>' +
+ '<div class="fc-event-container"></div>' +
+ '<div class="fc-highlight-container"></div>' +
+ '<div class="fc-bgevent-container"></div>' +
+ '<div class="fc-business-container"></div>' +
+ '</div>' +
+ '</td>';
+ }
+ skeletonEl = this.contentSkeletonEl = $('<div class="fc-content-skeleton">' +
+ '<table>' +
+ '<tr>' + cellHtml + '</tr>' +
+ '</table>' +
+ '</div>');
+ this.colContainerEls = skeletonEl.find('.fc-content-col');
+ this.helperContainerEls = skeletonEl.find('.fc-helper-container');
+ this.fgContainerEls = skeletonEl.find('.fc-event-container:not(.fc-helper-container)');
+ this.bgContainerEls = skeletonEl.find('.fc-bgevent-container');
+ this.highlightContainerEls = skeletonEl.find('.fc-highlight-container');
+ this.businessContainerEls = skeletonEl.find('.fc-business-container');
+ this.bookendCells(skeletonEl.find('tr')); // TODO: do this on string level
+ this.el.append(skeletonEl);
+ };
+ TimeGrid.prototype.unrenderContentSkeleton = function () {
+ if (this.contentSkeletonEl) {
+ this.contentSkeletonEl.remove();
+ this.contentSkeletonEl = null;
+ this.colContainerEls = null;
+ this.helperContainerEls = null;
+ this.fgContainerEls = null;
+ this.bgContainerEls = null;
+ this.highlightContainerEls = null;
+ this.businessContainerEls = null;
+ }
+ };
+ // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col
+ TimeGrid.prototype.groupSegsByCol = function (segs) {
+ var segsByCol = [];
+ var i;
+ for (i = 0; i < this.colCnt; i++) {
+ segsByCol.push([]);
+ }
+ for (i = 0; i < segs.length; i++) {
+ segsByCol[segs[i].col].push(segs[i]);
+ }
+ return segsByCol;
+ };
+ // Given segments grouped by column, insert the segments' elements into a parallel array of container
+ // elements, each living within a column.
+ TimeGrid.prototype.attachSegsByCol = function (segsByCol, containerEls) {
+ var col;
+ var segs;
+ var i;
+ for (col = 0; col < this.colCnt; col++) {
+ segs = segsByCol[col];
+ for (i = 0; i < segs.length; i++) {
+ containerEls.eq(col).append(segs[i].el);
+ }
+ }
+ };
+ /* Now Indicator
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.getNowIndicatorUnit = function () {
+ return 'minute'; // will refresh on the minute
+ };
+ TimeGrid.prototype.renderNowIndicator = function (date) {
+ // HACK: if date columns not ready for some reason (scheduler)
+ if (!this.colContainerEls) {
+ return;
+ }
+ // seg system might be overkill, but it handles scenario where line needs to be rendered
+ // more than once because of columns with the same date (resources columns for example)
+ var segs = this.componentFootprintToSegs(new ComponentFootprint_1.default(new UnzonedRange_1.default(date, date.valueOf() + 1), // protect against null range
+ false // all-day
+ ));
+ var top = this.computeDateTop(date, date);
+ var nodes = [];
+ var i;
+ // render lines within the columns
+ for (i = 0; i < segs.length; i++) {
+ nodes.push($('<div class="fc-now-indicator fc-now-indicator-line"></div>')
+ .css('top', top)
+ .appendTo(this.colContainerEls.eq(segs[i].col))[0]);
+ }
+ // render an arrow over the axis
+ if (segs.length > 0) {
+ nodes.push($('<div class="fc-now-indicator fc-now-indicator-arrow"></div>')
+ .css('top', top)
+ .appendTo(this.el.find('.fc-content-skeleton'))[0]);
+ }
+ this.nowIndicatorEls = $(nodes);
+ };
+ TimeGrid.prototype.unrenderNowIndicator = function () {
+ if (this.nowIndicatorEls) {
+ this.nowIndicatorEls.remove();
+ this.nowIndicatorEls = null;
+ }
+ };
+ /* Coordinates
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ _super.prototype.updateSize.call(this, totalHeight, isAuto, isResize);
+ this.slatCoordCache.build();
+ if (isResize) {
+ this.updateSegVerticals([].concat(this.eventRenderer.getSegs(), this.businessSegs || []));
+ }
+ };
+ TimeGrid.prototype.getTotalSlatHeight = function () {
+ return this.slatContainerEl.outerHeight();
+ };
+ // Computes the top coordinate, relative to the bounds of the grid, of the given date.
+ // `ms` can be a millisecond UTC time OR a UTC moment.
+ // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
+ TimeGrid.prototype.computeDateTop = function (ms, startOfDayDate) {
+ return this.computeTimeTop(moment.duration(ms - startOfDayDate.clone().stripTime()));
+ };
+ // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
+ TimeGrid.prototype.computeTimeTop = function (time) {
+ var len = this.slatEls.length;
+ var dateProfile = this.dateProfile;
+ var slatCoverage = (time - dateProfile.minTime) / this.slotDuration; // floating-point value of # of slots covered
+ var slatIndex;
+ var slatRemainder;
+ // compute a floating-point number for how many slats should be progressed through.
+ // from 0 to number of slats (inclusive)
+ // constrained because minTime/maxTime might be customized.
+ slatCoverage = Math.max(0, slatCoverage);
+ slatCoverage = Math.min(len, slatCoverage);
+ // an integer index of the furthest whole slat
+ // from 0 to number slats (*exclusive*, so len-1)
+ slatIndex = Math.floor(slatCoverage);
+ slatIndex = Math.min(slatIndex, len - 1);
+ // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
+ // could be 1.0 if slatCoverage is covering *all* the slots
+ slatRemainder = slatCoverage - slatIndex;
+ return this.slatCoordCache.getTopPosition(slatIndex) +
+ this.slatCoordCache.getHeight(slatIndex) * slatRemainder;
+ };
+ // Refreshes the CSS top/bottom coordinates for each segment element.
+ // Works when called after initial render, after a window resize/zoom for example.
+ TimeGrid.prototype.updateSegVerticals = function (segs) {
+ this.computeSegVerticals(segs);
+ this.assignSegVerticals(segs);
+ };
+ // For each segment in an array, computes and assigns its top and bottom properties
+ TimeGrid.prototype.computeSegVerticals = function (segs) {
+ var eventMinHeight = this.opt('agendaEventMinHeight');
+ var i;
+ var seg;
+ var dayDate;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ dayDate = this.dayDates[seg.dayIndex];
+ seg.top = this.computeDateTop(seg.startMs, dayDate);
+ seg.bottom = Math.max(seg.top + eventMinHeight, this.computeDateTop(seg.endMs, dayDate));
+ }
+ };
+ // Given segments that already have their top/bottom properties computed, applies those values to
+ // the segments' elements.
+ TimeGrid.prototype.assignSegVerticals = function (segs) {
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ seg.el.css(this.generateSegVerticalCss(seg));
+ }
+ };
+ // Generates an object with CSS properties for the top/bottom coordinates of a segment element
+ TimeGrid.prototype.generateSegVerticalCss = function (seg) {
+ return {
+ top: seg.top,
+ bottom: -seg.bottom // flipped because needs to be space beyond bottom edge of event container
+ };
+ };
+ /* Hit System
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.prepareHits = function () {
+ this.colCoordCache.build();
+ this.slatCoordCache.build();
+ };
+ TimeGrid.prototype.releaseHits = function () {
+ this.colCoordCache.clear();
+ // NOTE: don't clear slatCoordCache because we rely on it for computeTimeTop
+ };
+ TimeGrid.prototype.queryHit = function (leftOffset, topOffset) {
+ var snapsPerSlot = this.snapsPerSlot;
+ var colCoordCache = this.colCoordCache;
+ var slatCoordCache = this.slatCoordCache;
+ if (colCoordCache.isLeftInBounds(leftOffset) && slatCoordCache.isTopInBounds(topOffset)) {
+ var colIndex = colCoordCache.getHorizontalIndex(leftOffset);
+ var slatIndex = slatCoordCache.getVerticalIndex(topOffset);
+ if (colIndex != null && slatIndex != null) {
+ var slatTop = slatCoordCache.getTopOffset(slatIndex);
+ var slatHeight = slatCoordCache.getHeight(slatIndex);
+ var partial = (topOffset - slatTop) / slatHeight; // floating point number between 0 and 1
+ var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat
+ var snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
+ var snapTop = slatTop + (localSnapIndex / snapsPerSlot) * slatHeight;
+ var snapBottom = slatTop + ((localSnapIndex + 1) / snapsPerSlot) * slatHeight;
+ return {
+ col: colIndex,
+ snap: snapIndex,
+ component: this,
+ left: colCoordCache.getLeftOffset(colIndex),
+ right: colCoordCache.getRightOffset(colIndex),
+ top: snapTop,
+ bottom: snapBottom
+ };
+ }
+ }
+ };
+ TimeGrid.prototype.getHitFootprint = function (hit) {
+ var start = this.getCellDate(0, hit.col); // row=0
+ var time = this.computeSnapTime(hit.snap); // pass in the snap-index
+ var end;
+ start.time(time);
+ end = start.clone().add(this.snapDuration);
+ return new ComponentFootprint_1.default(new UnzonedRange_1.default(start, end), false // all-day?
+ );
+ };
+ // Given a row number of the grid, representing a "snap", returns a time (Duration) from its start-of-day
+ TimeGrid.prototype.computeSnapTime = function (snapIndex) {
+ return moment.duration(this.dateProfile.minTime + this.snapDuration * snapIndex);
+ };
+ TimeGrid.prototype.getHitEl = function (hit) {
+ return this.colEls.eq(hit.col);
+ };
+ /* Event Drag Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of an event being dragged over the specified date(s).
+ // A returned value of `true` signals that a mock "helper" event has been rendered.
+ TimeGrid.prototype.renderDrag = function (eventFootprints, seg, isTouch) {
+ var i;
+ if (seg) {
+ if (eventFootprints.length) {
+ this.helperRenderer.renderEventDraggingFootprints(eventFootprints, seg, isTouch);
+ // signal that a helper has been rendered
+ return true;
+ }
+ }
+ else {
+ for (i = 0; i < eventFootprints.length; i++) {
+ this.renderHighlight(eventFootprints[i].componentFootprint);
+ }
+ }
+ };
+ // Unrenders any visual indication of an event being dragged
+ TimeGrid.prototype.unrenderDrag = function () {
+ this.unrenderHighlight();
+ this.helperRenderer.unrender();
+ };
+ /* Event Resize Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of an event being resized
+ TimeGrid.prototype.renderEventResize = function (eventFootprints, seg, isTouch) {
+ this.helperRenderer.renderEventResizingFootprints(eventFootprints, seg, isTouch);
+ };
+ // Unrenders any visual indication of an event being resized
+ TimeGrid.prototype.unrenderEventResize = function () {
+ this.helperRenderer.unrender();
+ };
+ /* Selection
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight.
+ TimeGrid.prototype.renderSelectionFootprint = function (componentFootprint) {
+ if (this.opt('selectHelper')) {
+ this.helperRenderer.renderComponentFootprint(componentFootprint);
+ }
+ else {
+ this.renderHighlight(componentFootprint);
+ }
+ };
+ // Unrenders any visual indication of a selection
+ TimeGrid.prototype.unrenderSelection = function () {
+ this.helperRenderer.unrender();
+ this.unrenderHighlight();
+ };
+ return TimeGrid;
+}(InteractiveDateComponent_1.default));
+exports.default = TimeGrid;
+TimeGrid.prototype.eventRendererClass = TimeGridEventRenderer_1.default;
+TimeGrid.prototype.businessHourRendererClass = BusinessHourRenderer_1.default;
+TimeGrid.prototype.helperRendererClass = TimeGridHelperRenderer_1.default;
+TimeGrid.prototype.fillRendererClass = TimeGridFillRenderer_1.default;
+StandardInteractionsMixin_1.default.mixInto(TimeGrid);
+DayTableMixin_1.default.mixInto(TimeGrid);
+
+
+/***/ }),
+/* 228 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var UnzonedRange_1 = __webpack_require__(5);
+var DateProfileGenerator_1 = __webpack_require__(221);
+var BasicViewDateProfileGenerator = /** @class */ (function (_super) {
+ tslib_1.__extends(BasicViewDateProfileGenerator, _super);
+ function BasicViewDateProfileGenerator() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Computes the date range that will be rendered.
+ BasicViewDateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
+ var renderUnzonedRange = _super.prototype.buildRenderRange.call(this, currentUnzonedRange, currentRangeUnit, isRangeAllDay); // an UnzonedRange
+ var start = this.msToUtcMoment(renderUnzonedRange.startMs, isRangeAllDay);
+ var end = this.msToUtcMoment(renderUnzonedRange.endMs, isRangeAllDay);
+ // year and month views should be aligned with weeks. this is already done for week
+ if (/^(year|month)$/.test(currentRangeUnit)) {
+ start.startOf('week');
+ // make end-of-week if not already
+ if (end.weekday()) {
+ end.add(1, 'week').startOf('week'); // exclusively move backwards
+ }
+ }
+ return new UnzonedRange_1.default(start, end);
+ };
+ return BasicViewDateProfileGenerator;
+}(DateProfileGenerator_1.default));
+exports.default = BasicViewDateProfileGenerator;
+
+
+/***/ }),
+/* 229 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var BasicView_1 = __webpack_require__(62);
+var MonthViewDateProfileGenerator_1 = __webpack_require__(253);
+/* A month view with day cells running in rows (one-per-week) and columns
+----------------------------------------------------------------------------------------------------------------------*/
+var MonthView = /** @class */ (function (_super) {
+ tslib_1.__extends(MonthView, _super);
+ function MonthView() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Overrides the default BasicView behavior to have special multi-week auto-height logic
+ MonthView.prototype.setGridHeight = function (height, isAuto) {
+ // if auto, make the height of each row the height that it would be if there were 6 weeks
+ if (isAuto) {
+ height *= this.dayGrid.rowCnt / 6;
+ }
+ util_1.distributeHeight(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows
+ };
+ MonthView.prototype.isDateInOtherMonth = function (date, dateProfile) {
+ return date.month() !== moment.utc(dateProfile.currentUnzonedRange.startMs).month(); // TODO: optimize
+ };
+ return MonthView;
+}(BasicView_1.default));
+exports.default = MonthView;
+MonthView.prototype.dateProfileGeneratorClass = MonthViewDateProfileGenerator_1.default;
+
+
+/***/ }),
+/* 230 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var UnzonedRange_1 = __webpack_require__(5);
+var View_1 = __webpack_require__(41);
+var Scroller_1 = __webpack_require__(39);
+var ListEventRenderer_1 = __webpack_require__(254);
+var ListEventPointing_1 = __webpack_require__(255);
+/*
+Responsible for the scroller, and forwarding event-related actions into the "grid".
+*/
+var ListView = /** @class */ (function (_super) {
+ tslib_1.__extends(ListView, _super);
+ function ListView(calendar, viewSpec) {
+ var _this = _super.call(this, calendar, viewSpec) || this;
+ _this.segSelector = '.fc-list-item'; // which elements accept event actions
+ _this.scroller = new Scroller_1.default({
+ overflowX: 'hidden',
+ overflowY: 'auto'
+ });
+ return _this;
+ }
+ ListView.prototype.renderSkeleton = function () {
+ this.el.addClass('fc-list-view ' +
+ this.calendar.theme.getClass('listView'));
+ this.scroller.render();
+ this.scroller.el.appendTo(this.el);
+ this.contentEl = this.scroller.scrollEl; // shortcut
+ };
+ ListView.prototype.unrenderSkeleton = function () {
+ this.scroller.destroy(); // will remove the Grid too
+ };
+ ListView.prototype.updateSize = function (totalHeight, isAuto, isResize) {
+ _super.prototype.updateSize.call(this, totalHeight, isAuto, isResize);
+ this.scroller.clear(); // sets height to 'auto' and clears overflow
+ if (!isAuto) {
+ this.scroller.setHeight(this.computeScrollerHeight(totalHeight));
+ }
+ };
+ ListView.prototype.computeScrollerHeight = function (totalHeight) {
+ return totalHeight -
+ util_1.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
+ };
+ ListView.prototype.renderDates = function (dateProfile) {
+ var calendar = this.calendar;
+ var dayStart = calendar.msToUtcMoment(dateProfile.renderUnzonedRange.startMs, true);
+ var viewEnd = calendar.msToUtcMoment(dateProfile.renderUnzonedRange.endMs, true);
+ var dayDates = [];
+ var dayRanges = [];
+ while (dayStart < viewEnd) {
+ dayDates.push(dayStart.clone());
+ dayRanges.push(new UnzonedRange_1.default(dayStart, dayStart.clone().add(1, 'day')));
+ dayStart.add(1, 'day');
+ }
+ this.dayDates = dayDates;
+ this.dayRanges = dayRanges;
+ // all real rendering happens in EventRenderer
+ };
+ // slices by day
+ ListView.prototype.componentFootprintToSegs = function (footprint) {
+ var dayRanges = this.dayRanges;
+ var dayIndex;
+ var segRange;
+ var seg;
+ var segs = [];
+ for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex++) {
+ segRange = footprint.unzonedRange.intersect(dayRanges[dayIndex]);
+ if (segRange) {
+ seg = {
+ startMs: segRange.startMs,
+ endMs: segRange.endMs,
+ isStart: segRange.isStart,
+ isEnd: segRange.isEnd,
+ dayIndex: dayIndex
+ };
+ segs.push(seg);
+ // detect when footprint won't go fully into the next day,
+ // and mutate the latest seg to the be the end.
+ if (!seg.isEnd && !footprint.isAllDay &&
+ dayIndex + 1 < dayRanges.length &&
+ footprint.unzonedRange.endMs < dayRanges[dayIndex + 1].startMs + this.nextDayThreshold) {
+ seg.endMs = footprint.unzonedRange.endMs;
+ seg.isEnd = true;
+ break;
+ }
+ }
+ }
+ return segs;
+ };
+ ListView.prototype.renderEmptyMessage = function () {
+ this.contentEl.html('<div class="fc-list-empty-wrap2">' + // TODO: try less wraps
+ '<div class="fc-list-empty-wrap1">' +
+ '<div class="fc-list-empty">' +
+ util_1.htmlEscape(this.opt('noEventsMessage')) +
+ '</div>' +
+ '</div>' +
+ '</div>');
+ };
+ // render the event segments in the view
+ ListView.prototype.renderSegList = function (allSegs) {
+ var segsByDay = this.groupSegsByDay(allSegs); // sparse array
+ var dayIndex;
+ var daySegs;
+ var i;
+ var tableEl = $('<table class="fc-list-table ' + this.calendar.theme.getClass('tableList') + '"><tbody/></table>');
+ var tbodyEl = tableEl.find('tbody');
+ for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) {
+ daySegs = segsByDay[dayIndex];
+ if (daySegs) {
+ // append a day header
+ tbodyEl.append(this.dayHeaderHtml(this.dayDates[dayIndex]));
+ this.eventRenderer.sortEventSegs(daySegs);
+ for (i = 0; i < daySegs.length; i++) {
+ tbodyEl.append(daySegs[i].el); // append event row
+ }
+ }
+ }
+ this.contentEl.empty().append(tableEl);
+ };
+ // Returns a sparse array of arrays, segs grouped by their dayIndex
+ ListView.prototype.groupSegsByDay = function (segs) {
+ var segsByDay = []; // sparse array
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
+ .push(seg);
+ }
+ return segsByDay;
+ };
+ // generates the HTML for the day headers that live amongst the event rows
+ ListView.prototype.dayHeaderHtml = function (dayDate) {
+ var mainFormat = this.opt('listDayFormat');
+ var altFormat = this.opt('listDayAltFormat');
+ return '<tr class="fc-list-heading" data-date="' + dayDate.format('YYYY-MM-DD') + '">' +
+ '<td class="' + (this.calendar.theme.getClass('tableListHeading') ||
+ this.calendar.theme.getClass('widgetHeader')) + '" colspan="3">' +
+ (mainFormat ?
+ this.buildGotoAnchorHtml(dayDate, { 'class': 'fc-list-heading-main' }, util_1.htmlEscape(dayDate.format(mainFormat)) // inner HTML
+ ) :
+ '') +
+ (altFormat ?
+ this.buildGotoAnchorHtml(dayDate, { 'class': 'fc-list-heading-alt' }, util_1.htmlEscape(dayDate.format(altFormat)) // inner HTML
+ ) :
+ '') +
+ '</td>' +
+ '</tr>';
+ };
+ return ListView;
+}(View_1.default));
+exports.default = ListView;
+ListView.prototype.eventRendererClass = ListEventRenderer_1.default;
+ListView.prototype.eventPointingClass = ListEventPointing_1.default;
+
+
+/***/ }),
+/* 231 */,
+/* 232 */,
+/* 233 */,
+/* 234 */,
+/* 235 */,
+/* 236 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var $ = __webpack_require__(3);
+var exportHooks = __webpack_require__(16);
+var util_1 = __webpack_require__(4);
+var Calendar_1 = __webpack_require__(220);
+// for intentional side-effects
+__webpack_require__(10);
+__webpack_require__(47);
+__webpack_require__(256);
+__webpack_require__(257);
+__webpack_require__(260);
+__webpack_require__(261);
+__webpack_require__(262);
+__webpack_require__(263);
+$.fullCalendar = exportHooks;
+$.fn.fullCalendar = function (options) {
+ var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
+ var res = this; // what this function will return (this jQuery object by default)
+ this.each(function (i, _element) {
+ var element = $(_element);
+ var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
+ var singleRes; // the returned value of this single method call
+ // a method call
+ if (typeof options === 'string') {
+ if (options === 'getCalendar') {
+ if (!i) {
+ res = calendar;
+ }
+ }
+ else if (options === 'destroy') {
+ if (calendar) {
+ calendar.destroy();
+ element.removeData('fullCalendar');
+ }
+ }
+ else if (!calendar) {
+ util_1.warn('Attempting to call a FullCalendar method on an element with no calendar.');
+ }
+ else if ($.isFunction(calendar[options])) {
+ singleRes = calendar[options].apply(calendar, args);
+ if (!i) {
+ res = singleRes; // record the first method call result
+ }
+ if (options === 'destroy') {
+ element.removeData('fullCalendar');
+ }
+ }
+ else {
+ util_1.warn("'" + options + "' is an unknown FullCalendar method.");
+ }
+ }
+ else if (!calendar) {
+ calendar = new Calendar_1.default(element, options);
+ element.data('fullCalendar', calendar);
+ calendar.render();
+ }
+ });
+ return res;
+};
+module.exports = exportHooks;
+
+
+/***/ }),
+/* 237 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Model_1 = __webpack_require__(48);
+var Component = /** @class */ (function (_super) {
+ tslib_1.__extends(Component, _super);
+ function Component() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ Component.prototype.setElement = function (el) {
+ this.el = el;
+ this.bindGlobalHandlers();
+ this.renderSkeleton();
+ this.set('isInDom', true);
+ };
+ Component.prototype.removeElement = function () {
+ this.unset('isInDom');
+ this.unrenderSkeleton();
+ this.unbindGlobalHandlers();
+ this.el.remove();
+ // NOTE: don't null-out this.el in case the View was destroyed within an API callback.
+ // We don't null-out the View's other jQuery element references upon destroy,
+ // so we shouldn't kill this.el either.
+ };
+ Component.prototype.bindGlobalHandlers = function () {
+ // subclasses can override
+ };
+ Component.prototype.unbindGlobalHandlers = function () {
+ // subclasses can override
+ };
+ /*
+ NOTE: Can't have a `render` method. Read the deprecation notice in View::executeDateRender
+ */
+ // Renders the basic structure of the view before any content is rendered
+ Component.prototype.renderSkeleton = function () {
+ // subclasses should implement
+ };
+ // Unrenders the basic structure of the view
+ Component.prototype.unrenderSkeleton = function () {
+ // subclasses should implement
+ };
+ return Component;
+}(Model_1.default));
+exports.default = Component;
+
+
+/***/ }),
+/* 238 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var Iterator = /** @class */ (function () {
+ function Iterator(items) {
+ this.items = items || [];
+ }
+ /* Calls a method on every item passing the arguments through */
+ Iterator.prototype.proxyCall = function (methodName) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ var results = [];
+ this.items.forEach(function (item) {
+ results.push(item[methodName].apply(item, args));
+ });
+ return results;
+ };
+ return Iterator;
+}());
+exports.default = Iterator;
+
+
+/***/ }),
+/* 239 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+/* Toolbar with buttons and title
+----------------------------------------------------------------------------------------------------------------------*/
+var Toolbar = /** @class */ (function () {
+ function Toolbar(calendar, toolbarOptions) {
+ this.el = null; // mirrors local `el`
+ this.viewsWithButtons = [];
+ this.calendar = calendar;
+ this.toolbarOptions = toolbarOptions;
+ }
+ // method to update toolbar-specific options, not calendar-wide options
+ Toolbar.prototype.setToolbarOptions = function (newToolbarOptions) {
+ this.toolbarOptions = newToolbarOptions;
+ };
+ // can be called repeatedly and will rerender
+ Toolbar.prototype.render = function () {
+ var sections = this.toolbarOptions.layout;
+ var el = this.el;
+ if (sections) {
+ if (!el) {
+ el = this.el = $("<div class='fc-toolbar " + this.toolbarOptions.extraClasses + "'/>");
+ }
+ else {
+ el.empty();
+ }
+ el.append(this.renderSection('left'))
+ .append(this.renderSection('right'))
+ .append(this.renderSection('center'))
+ .append('<div class="fc-clear"/>');
+ }
+ else {
+ this.removeElement();
+ }
+ };
+ Toolbar.prototype.removeElement = function () {
+ if (this.el) {
+ this.el.remove();
+ this.el = null;
+ }
+ };
+ Toolbar.prototype.renderSection = function (position) {
+ var _this = this;
+ var calendar = this.calendar;
+ var theme = calendar.theme;
+ var optionsManager = calendar.optionsManager;
+ var viewSpecManager = calendar.viewSpecManager;
+ var sectionEl = $('<div class="fc-' + position + '"/>');
+ var buttonStr = this.toolbarOptions.layout[position];
+ var calendarCustomButtons = optionsManager.get('customButtons') || {};
+ var calendarButtonTextOverrides = optionsManager.overrides.buttonText || {};
+ var calendarButtonText = optionsManager.get('buttonText') || {};
+ if (buttonStr) {
+ $.each(buttonStr.split(' '), function (i, buttonGroupStr) {
+ var groupChildren = $();
+ var isOnlyButtons = true;
+ var groupEl;
+ $.each(buttonGroupStr.split(','), function (j, buttonName) {
+ var customButtonProps;
+ var viewSpec;
+ var buttonClick;
+ var buttonIcon; // only one of these will be set
+ var buttonText; // "
+ var buttonInnerHtml;
+ var buttonClasses;
+ var buttonEl;
+ var buttonAriaAttr;
+ if (buttonName === 'title') {
+ groupChildren = groupChildren.add($('<h2>&nbsp;</h2>')); // we always want it to take up height
+ isOnlyButtons = false;
+ }
+ else {
+ if ((customButtonProps = calendarCustomButtons[buttonName])) {
+ buttonClick = function (ev) {
+ if (customButtonProps.click) {
+ customButtonProps.click.call(buttonEl[0], ev);
+ }
+ };
+ (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
+ (buttonIcon = theme.getIconClass(buttonName)) ||
+ (buttonText = customButtonProps.text);
+ }
+ else if ((viewSpec = viewSpecManager.getViewSpec(buttonName))) {
+ _this.viewsWithButtons.push(buttonName);
+ buttonClick = function () {
+ calendar.changeView(buttonName);
+ };
+ (buttonText = viewSpec.buttonTextOverride) ||
+ (buttonIcon = theme.getIconClass(buttonName)) ||
+ (buttonText = viewSpec.buttonTextDefault);
+ }
+ else if (calendar[buttonName]) {
+ buttonClick = function () {
+ calendar[buttonName]();
+ };
+ (buttonText = calendarButtonTextOverrides[buttonName]) ||
+ (buttonIcon = theme.getIconClass(buttonName)) ||
+ (buttonText = calendarButtonText[buttonName]);
+ // ^ everything else is considered default
+ }
+ if (buttonClick) {
+ buttonClasses = [
+ 'fc-' + buttonName + '-button',
+ theme.getClass('button'),
+ theme.getClass('stateDefault')
+ ];
+ if (buttonText) {
+ buttonInnerHtml = util_1.htmlEscape(buttonText);
+ buttonAriaAttr = '';
+ }
+ else if (buttonIcon) {
+ buttonInnerHtml = "<span class='" + buttonIcon + "'></span>";
+ buttonAriaAttr = ' aria-label="' + buttonName + '"';
+ }
+ buttonEl = $(// type="button" so that it doesn't submit a form
+ '<button type="button" class="' + buttonClasses.join(' ') + '"' +
+ buttonAriaAttr +
+ '>' + buttonInnerHtml + '</button>')
+ .click(function (ev) {
+ // don't process clicks for disabled buttons
+ if (!buttonEl.hasClass(theme.getClass('stateDisabled'))) {
+ buttonClick(ev);
+ // after the click action, if the button becomes the "active" tab, or disabled,
+ // it should never have a hover class, so remove it now.
+ if (buttonEl.hasClass(theme.getClass('stateActive')) ||
+ buttonEl.hasClass(theme.getClass('stateDisabled'))) {
+ buttonEl.removeClass(theme.getClass('stateHover'));
+ }
+ }
+ })
+ .mousedown(function () {
+ // the *down* effect (mouse pressed in).
+ // only on buttons that are not the "active" tab, or disabled
+ buttonEl
+ .not('.' + theme.getClass('stateActive'))
+ .not('.' + theme.getClass('stateDisabled'))
+ .addClass(theme.getClass('stateDown'));
+ })
+ .mouseup(function () {
+ // undo the *down* effect
+ buttonEl.removeClass(theme.getClass('stateDown'));
+ })
+ .hover(function () {
+ // the *hover* effect.
+ // only on buttons that are not the "active" tab, or disabled
+ buttonEl
+ .not('.' + theme.getClass('stateActive'))
+ .not('.' + theme.getClass('stateDisabled'))
+ .addClass(theme.getClass('stateHover'));
+ }, function () {
+ // undo the *hover* effect
+ buttonEl
+ .removeClass(theme.getClass('stateHover'))
+ .removeClass(theme.getClass('stateDown')); // if mouseleave happens before mouseup
+ });
+ groupChildren = groupChildren.add(buttonEl);
+ }
+ }
+ });
+ if (isOnlyButtons) {
+ groupChildren
+ .first().addClass(theme.getClass('cornerLeft')).end()
+ .last().addClass(theme.getClass('cornerRight')).end();
+ }
+ if (groupChildren.length > 1) {
+ groupEl = $('<div/>');
+ if (isOnlyButtons) {
+ groupEl.addClass(theme.getClass('buttonGroup'));
+ }
+ groupEl.append(groupChildren);
+ sectionEl.append(groupEl);
+ }
+ else {
+ sectionEl.append(groupChildren); // 1 or 0 children
+ }
+ });
+ }
+ return sectionEl;
+ };
+ Toolbar.prototype.updateTitle = function (text) {
+ if (this.el) {
+ this.el.find('h2').text(text);
+ }
+ };
+ Toolbar.prototype.activateButton = function (buttonName) {
+ if (this.el) {
+ this.el.find('.fc-' + buttonName + '-button')
+ .addClass(this.calendar.theme.getClass('stateActive'));
+ }
+ };
+ Toolbar.prototype.deactivateButton = function (buttonName) {
+ if (this.el) {
+ this.el.find('.fc-' + buttonName + '-button')
+ .removeClass(this.calendar.theme.getClass('stateActive'));
+ }
+ };
+ Toolbar.prototype.disableButton = function (buttonName) {
+ if (this.el) {
+ this.el.find('.fc-' + buttonName + '-button')
+ .prop('disabled', true)
+ .addClass(this.calendar.theme.getClass('stateDisabled'));
+ }
+ };
+ Toolbar.prototype.enableButton = function (buttonName) {
+ if (this.el) {
+ this.el.find('.fc-' + buttonName + '-button')
+ .prop('disabled', false)
+ .removeClass(this.calendar.theme.getClass('stateDisabled'));
+ }
+ };
+ Toolbar.prototype.getViewsWithButtons = function () {
+ return this.viewsWithButtons;
+ };
+ return Toolbar;
+}());
+exports.default = Toolbar;
+
+
+/***/ }),
+/* 240 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var options_1 = __webpack_require__(32);
+var locale_1 = __webpack_require__(31);
+var Model_1 = __webpack_require__(48);
+var OptionsManager = /** @class */ (function (_super) {
+ tslib_1.__extends(OptionsManager, _super);
+ function OptionsManager(_calendar, overrides) {
+ var _this = _super.call(this) || this;
+ _this._calendar = _calendar;
+ _this.overrides = $.extend({}, overrides); // make a copy
+ _this.dynamicOverrides = {};
+ _this.compute();
+ return _this;
+ }
+ OptionsManager.prototype.add = function (newOptionHash) {
+ var optionCnt = 0;
+ var optionName;
+ this.recordOverrides(newOptionHash); // will trigger this model's watchers
+ for (optionName in newOptionHash) {
+ optionCnt++;
+ }
+ // special-case handling of single option change.
+ // if only one option change, `optionName` will be its name.
+ if (optionCnt === 1) {
+ if (optionName === 'height' || optionName === 'contentHeight' || optionName === 'aspectRatio') {
+ this._calendar.updateViewSize(true); // isResize=true
+ return;
+ }
+ else if (optionName === 'defaultDate') {
+ return; // can't change date this way. use gotoDate instead
+ }
+ else if (optionName === 'businessHours') {
+ return; // this model already reacts to this
+ }
+ else if (/^(event|select)(Overlap|Constraint|Allow)$/.test(optionName)) {
+ return; // doesn't affect rendering. only interactions.
+ }
+ else if (optionName === 'timezone') {
+ this._calendar.view.flash('initialEvents');
+ return;
+ }
+ }
+ // catch-all. rerender the header and footer and rebuild/rerender the current view
+ this._calendar.renderHeader();
+ this._calendar.renderFooter();
+ // even non-current views will be affected by this option change. do before rerender
+ // TODO: detangle
+ this._calendar.viewsByType = {};
+ this._calendar.reinitView();
+ };
+ // Computes the flattened options hash for the calendar and assigns to `this.options`.
+ // Assumes this.overrides and this.dynamicOverrides have already been initialized.
+ OptionsManager.prototype.compute = function () {
+ var locale;
+ var localeDefaults;
+ var isRTL;
+ var dirDefaults;
+ var rawOptions;
+ locale = util_1.firstDefined(// explicit locale option given?
+ this.dynamicOverrides.locale, this.overrides.locale);
+ localeDefaults = locale_1.localeOptionHash[locale];
+ if (!localeDefaults) {
+ locale = options_1.globalDefaults.locale;
+ localeDefaults = locale_1.localeOptionHash[locale] || {};
+ }
+ isRTL = util_1.firstDefined(// based on options computed so far, is direction RTL?
+ this.dynamicOverrides.isRTL, this.overrides.isRTL, localeDefaults.isRTL, options_1.globalDefaults.isRTL);
+ dirDefaults = isRTL ? options_1.rtlDefaults : {};
+ this.dirDefaults = dirDefaults;
+ this.localeDefaults = localeDefaults;
+ rawOptions = options_1.mergeOptions([
+ options_1.globalDefaults,
+ dirDefaults,
+ localeDefaults,
+ this.overrides,
+ this.dynamicOverrides
+ ]);
+ locale_1.populateInstanceComputableOptions(rawOptions); // fill in gaps with computed options
+ this.reset(rawOptions);
+ };
+ // stores the new options internally, but does not rerender anything.
+ OptionsManager.prototype.recordOverrides = function (newOptionHash) {
+ var optionName;
+ for (optionName in newOptionHash) {
+ this.dynamicOverrides[optionName] = newOptionHash[optionName];
+ }
+ this._calendar.viewSpecManager.clearCache(); // the dynamic override invalidates the options in this cache, so just clear it
+ this.compute(); // this.options needs to be recomputed after the dynamic override
+ };
+ return OptionsManager;
+}(Model_1.default));
+exports.default = OptionsManager;
+
+
+/***/ }),
+/* 241 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var $ = __webpack_require__(3);
+var ViewRegistry_1 = __webpack_require__(22);
+var util_1 = __webpack_require__(4);
+var options_1 = __webpack_require__(32);
+var locale_1 = __webpack_require__(31);
+var ViewSpecManager = /** @class */ (function () {
+ function ViewSpecManager(optionsManager, _calendar) {
+ this.optionsManager = optionsManager;
+ this._calendar = _calendar;
+ this.clearCache();
+ }
+ ViewSpecManager.prototype.clearCache = function () {
+ this.viewSpecCache = {};
+ };
+ // Gets information about how to create a view. Will use a cache.
+ ViewSpecManager.prototype.getViewSpec = function (viewType) {
+ var cache = this.viewSpecCache;
+ return cache[viewType] || (cache[viewType] = this.buildViewSpec(viewType));
+ };
+ // Given a duration singular unit, like "week" or "day", finds a matching view spec.
+ // Preference is given to views that have corresponding buttons.
+ ViewSpecManager.prototype.getUnitViewSpec = function (unit) {
+ var viewTypes;
+ var i;
+ var spec;
+ if ($.inArray(unit, util_1.unitsDesc) !== -1) {
+ // put views that have buttons first. there will be duplicates, but oh well
+ viewTypes = this._calendar.header.getViewsWithButtons(); // TODO: include footer as well?
+ $.each(ViewRegistry_1.viewHash, function (viewType) {
+ viewTypes.push(viewType);
+ });
+ for (i = 0; i < viewTypes.length; i++) {
+ spec = this.getViewSpec(viewTypes[i]);
+ if (spec) {
+ if (spec.singleUnit === unit) {
+ return spec;
+ }
+ }
+ }
+ }
+ };
+ // Builds an object with information on how to create a given view
+ ViewSpecManager.prototype.buildViewSpec = function (requestedViewType) {
+ var viewOverrides = this.optionsManager.overrides.views || {};
+ var specChain = []; // for the view. lowest to highest priority
+ var defaultsChain = []; // for the view. lowest to highest priority
+ var overridesChain = []; // for the view. lowest to highest priority
+ var viewType = requestedViewType;
+ var spec; // for the view
+ var overrides; // for the view
+ var durationInput;
+ var duration;
+ var unit;
+ // iterate from the specific view definition to a more general one until we hit an actual View class
+ while (viewType) {
+ spec = ViewRegistry_1.viewHash[viewType];
+ overrides = viewOverrides[viewType];
+ viewType = null; // clear. might repopulate for another iteration
+ if (typeof spec === 'function') {
+ spec = { 'class': spec };
+ }
+ if (spec) {
+ specChain.unshift(spec);
+ defaultsChain.unshift(spec.defaults || {});
+ durationInput = durationInput || spec.duration;
+ viewType = viewType || spec.type;
+ }
+ if (overrides) {
+ overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
+ durationInput = durationInput || overrides.duration;
+ viewType = viewType || overrides.type;
+ }
+ }
+ spec = util_1.mergeProps(specChain);
+ spec.type = requestedViewType;
+ if (!spec['class']) {
+ return false;
+ }
+ // fall back to top-level `duration` option
+ durationInput = durationInput ||
+ this.optionsManager.dynamicOverrides.duration ||
+ this.optionsManager.overrides.duration;
+ if (durationInput) {
+ duration = moment.duration(durationInput);
+ if (duration.valueOf()) {
+ unit = util_1.computeDurationGreatestUnit(duration, durationInput);
+ spec.duration = duration;
+ spec.durationUnit = unit;
+ // view is a single-unit duration, like "week" or "day"
+ // incorporate options for this. lowest priority
+ if (duration.as(unit) === 1) {
+ spec.singleUnit = unit;
+ overridesChain.unshift(viewOverrides[unit] || {});
+ }
+ }
+ }
+ spec.defaults = options_1.mergeOptions(defaultsChain);
+ spec.overrides = options_1.mergeOptions(overridesChain);
+ this.buildViewSpecOptions(spec);
+ this.buildViewSpecButtonText(spec, requestedViewType);
+ return spec;
+ };
+ // Builds and assigns a view spec's options object from its already-assigned defaults and overrides
+ ViewSpecManager.prototype.buildViewSpecOptions = function (spec) {
+ var optionsManager = this.optionsManager;
+ spec.options = options_1.mergeOptions([
+ options_1.globalDefaults,
+ spec.defaults,
+ optionsManager.dirDefaults,
+ optionsManager.localeDefaults,
+ optionsManager.overrides,
+ spec.overrides,
+ optionsManager.dynamicOverrides // dynamically set via setter. highest precedence
+ ]);
+ locale_1.populateInstanceComputableOptions(spec.options);
+ };
+ // Computes and assigns a view spec's buttonText-related options
+ ViewSpecManager.prototype.buildViewSpecButtonText = function (spec, requestedViewType) {
+ var optionsManager = this.optionsManager;
+ // given an options object with a possible `buttonText` hash, lookup the buttonText for the
+ // requested view, falling back to a generic unit entry like "week" or "day"
+ function queryButtonText(options) {
+ var buttonText = options.buttonText || {};
+ return buttonText[requestedViewType] ||
+ // view can decide to look up a certain key
+ (spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
+ // a key like "month"
+ (spec.singleUnit ? buttonText[spec.singleUnit] : null);
+ }
+ // highest to lowest priority
+ spec.buttonTextOverride =
+ queryButtonText(optionsManager.dynamicOverrides) ||
+ queryButtonText(optionsManager.overrides) || // constructor-specified buttonText lookup hash takes precedence
+ spec.overrides.buttonText; // `buttonText` for view-specific options is a string
+ // highest to lowest priority. mirrors buildViewSpecOptions
+ spec.buttonTextDefault =
+ queryButtonText(optionsManager.localeDefaults) ||
+ queryButtonText(optionsManager.dirDefaults) ||
+ spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
+ queryButtonText(options_1.globalDefaults) ||
+ (spec.duration ? this._calendar.humanizeDuration(spec.duration) : null) || // like "3 days"
+ requestedViewType; // fall back to given view name
+ };
+ return ViewSpecManager;
+}());
+exports.default = ViewSpecManager;
+
+
+/***/ }),
+/* 242 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var EventPeriod_1 = __webpack_require__(243);
+var ArrayEventSource_1 = __webpack_require__(52);
+var EventSource_1 = __webpack_require__(6);
+var EventSourceParser_1 = __webpack_require__(38);
+var SingleEventDef_1 = __webpack_require__(13);
+var EventInstanceGroup_1 = __webpack_require__(18);
+var EmitterMixin_1 = __webpack_require__(11);
+var ListenerMixin_1 = __webpack_require__(7);
+var EventManager = /** @class */ (function () {
+ function EventManager(calendar) {
+ this.calendar = calendar;
+ this.stickySource = new ArrayEventSource_1.default(calendar);
+ this.otherSources = [];
+ }
+ EventManager.prototype.requestEvents = function (start, end, timezone, force) {
+ if (force ||
+ !this.currentPeriod ||
+ !this.currentPeriod.isWithinRange(start, end) ||
+ timezone !== this.currentPeriod.timezone) {
+ this.setPeriod(// will change this.currentPeriod
+ new EventPeriod_1.default(start, end, timezone));
+ }
+ return this.currentPeriod.whenReleased();
+ };
+ // Source Adding/Removing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.addSource = function (eventSource) {
+ this.otherSources.push(eventSource);
+ if (this.currentPeriod) {
+ this.currentPeriod.requestSource(eventSource); // might release
+ }
+ };
+ EventManager.prototype.removeSource = function (doomedSource) {
+ util_1.removeExact(this.otherSources, doomedSource);
+ if (this.currentPeriod) {
+ this.currentPeriod.purgeSource(doomedSource); // might release
+ }
+ };
+ EventManager.prototype.removeAllSources = function () {
+ this.otherSources = [];
+ if (this.currentPeriod) {
+ this.currentPeriod.purgeAllSources(); // might release
+ }
+ };
+ // Source Refetching
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.refetchSource = function (eventSource) {
+ var currentPeriod = this.currentPeriod;
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ currentPeriod.purgeSource(eventSource);
+ currentPeriod.requestSource(eventSource);
+ currentPeriod.thaw();
+ }
+ };
+ EventManager.prototype.refetchAllSources = function () {
+ var currentPeriod = this.currentPeriod;
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ currentPeriod.purgeAllSources();
+ currentPeriod.requestSources(this.getSources());
+ currentPeriod.thaw();
+ }
+ };
+ // Source Querying
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.getSources = function () {
+ return [this.stickySource].concat(this.otherSources);
+ };
+ // like querySources, but accepts multple match criteria (like multiple IDs)
+ EventManager.prototype.multiQuerySources = function (matchInputs) {
+ // coerce into an array
+ if (!matchInputs) {
+ matchInputs = [];
+ }
+ else if (!$.isArray(matchInputs)) {
+ matchInputs = [matchInputs];
+ }
+ var matchingSources = [];
+ var i;
+ // resolve raw inputs to real event source objects
+ for (i = 0; i < matchInputs.length; i++) {
+ matchingSources.push.apply(// append
+ matchingSources, this.querySources(matchInputs[i]));
+ }
+ return matchingSources;
+ };
+ // matchInput can either by a real event source object, an ID, or the function/URL for the source.
+ // returns an array of matching source objects.
+ EventManager.prototype.querySources = function (matchInput) {
+ var sources = this.otherSources;
+ var i;
+ var source;
+ // given a proper event source object
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i];
+ if (source === matchInput) {
+ return [source];
+ }
+ }
+ // an ID match
+ source = this.getSourceById(EventSource_1.default.normalizeId(matchInput));
+ if (source) {
+ return [source];
+ }
+ // parse as an event source
+ matchInput = EventSourceParser_1.default.parse(matchInput, this.calendar);
+ if (matchInput) {
+ return $.grep(sources, function (source) {
+ return isSourcesEquivalent(matchInput, source);
+ });
+ }
+ };
+ /*
+ ID assumed to already be normalized
+ */
+ EventManager.prototype.getSourceById = function (id) {
+ return $.grep(this.otherSources, function (source) {
+ return source.id && source.id === id;
+ })[0];
+ };
+ // Event-Period
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.setPeriod = function (eventPeriod) {
+ if (this.currentPeriod) {
+ this.unbindPeriod(this.currentPeriod);
+ this.currentPeriod = null;
+ }
+ this.currentPeriod = eventPeriod;
+ this.bindPeriod(eventPeriod);
+ eventPeriod.requestSources(this.getSources());
+ };
+ EventManager.prototype.bindPeriod = function (eventPeriod) {
+ this.listenTo(eventPeriod, 'release', function (eventsPayload) {
+ this.trigger('release', eventsPayload);
+ });
+ };
+ EventManager.prototype.unbindPeriod = function (eventPeriod) {
+ this.stopListeningTo(eventPeriod);
+ };
+ // Event Getting/Adding/Removing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.getEventDefByUid = function (uid) {
+ if (this.currentPeriod) {
+ return this.currentPeriod.getEventDefByUid(uid);
+ }
+ };
+ EventManager.prototype.addEventDef = function (eventDef, isSticky) {
+ if (isSticky) {
+ this.stickySource.addEventDef(eventDef);
+ }
+ if (this.currentPeriod) {
+ this.currentPeriod.addEventDef(eventDef); // might release
+ }
+ };
+ EventManager.prototype.removeEventDefsById = function (eventId) {
+ this.getSources().forEach(function (eventSource) {
+ eventSource.removeEventDefsById(eventId);
+ });
+ if (this.currentPeriod) {
+ this.currentPeriod.removeEventDefsById(eventId); // might release
+ }
+ };
+ EventManager.prototype.removeAllEventDefs = function () {
+ this.getSources().forEach(function (eventSource) {
+ eventSource.removeAllEventDefs();
+ });
+ if (this.currentPeriod) {
+ this.currentPeriod.removeAllEventDefs();
+ }
+ };
+ // Event Mutating
+ // -----------------------------------------------------------------------------------------------------------------
+ /*
+ Returns an undo function.
+ */
+ EventManager.prototype.mutateEventsWithId = function (eventDefId, eventDefMutation) {
+ var currentPeriod = this.currentPeriod;
+ var eventDefs;
+ var undoFuncs = [];
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ eventDefs = currentPeriod.getEventDefsById(eventDefId);
+ eventDefs.forEach(function (eventDef) {
+ // add/remove esp because id might change
+ currentPeriod.removeEventDef(eventDef);
+ undoFuncs.push(eventDefMutation.mutateSingle(eventDef));
+ currentPeriod.addEventDef(eventDef);
+ });
+ currentPeriod.thaw();
+ return function () {
+ currentPeriod.freeze();
+ for (var i = 0; i < eventDefs.length; i++) {
+ currentPeriod.removeEventDef(eventDefs[i]);
+ undoFuncs[i]();
+ currentPeriod.addEventDef(eventDefs[i]);
+ }
+ currentPeriod.thaw();
+ };
+ }
+ return function () { };
+ };
+ /*
+ copies and then mutates
+ */
+ EventManager.prototype.buildMutatedEventInstanceGroup = function (eventDefId, eventDefMutation) {
+ var eventDefs = this.getEventDefsById(eventDefId);
+ var i;
+ var defCopy;
+ var allInstances = [];
+ for (i = 0; i < eventDefs.length; i++) {
+ defCopy = eventDefs[i].clone();
+ if (defCopy instanceof SingleEventDef_1.default) {
+ eventDefMutation.mutateSingle(defCopy);
+ allInstances.push.apply(allInstances, // append
+ defCopy.buildInstances());
+ }
+ }
+ return new EventInstanceGroup_1.default(allInstances);
+ };
+ // Freezing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.freeze = function () {
+ if (this.currentPeriod) {
+ this.currentPeriod.freeze();
+ }
+ };
+ EventManager.prototype.thaw = function () {
+ if (this.currentPeriod) {
+ this.currentPeriod.thaw();
+ }
+ };
+ // methods that simply forward to EventPeriod
+ EventManager.prototype.getEventDefsById = function (eventDefId) {
+ return this.currentPeriod.getEventDefsById(eventDefId);
+ };
+ EventManager.prototype.getEventInstances = function () {
+ return this.currentPeriod.getEventInstances();
+ };
+ EventManager.prototype.getEventInstancesWithId = function (eventDefId) {
+ return this.currentPeriod.getEventInstancesWithId(eventDefId);
+ };
+ EventManager.prototype.getEventInstancesWithoutId = function (eventDefId) {
+ return this.currentPeriod.getEventInstancesWithoutId(eventDefId);
+ };
+ return EventManager;
+}());
+exports.default = EventManager;
+EmitterMixin_1.default.mixInto(EventManager);
+ListenerMixin_1.default.mixInto(EventManager);
+function isSourcesEquivalent(source0, source1) {
+ return source0.getPrimitive() === source1.getPrimitive();
+}
+
+
+/***/ }),
+/* 243 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Promise_1 = __webpack_require__(20);
+var EmitterMixin_1 = __webpack_require__(11);
+var UnzonedRange_1 = __webpack_require__(5);
+var EventInstanceGroup_1 = __webpack_require__(18);
+var EventPeriod = /** @class */ (function () {
+ function EventPeriod(start, end, timezone) {
+ this.pendingCnt = 0;
+ this.freezeDepth = 0;
+ this.stuntedReleaseCnt = 0;
+ this.releaseCnt = 0;
+ this.start = start;
+ this.end = end;
+ this.timezone = timezone;
+ this.unzonedRange = new UnzonedRange_1.default(start.clone().stripZone(), end.clone().stripZone());
+ this.requestsByUid = {};
+ this.eventDefsByUid = {};
+ this.eventDefsById = {};
+ this.eventInstanceGroupsById = {};
+ }
+ EventPeriod.prototype.isWithinRange = function (start, end) {
+ // TODO: use a range util function?
+ return !start.isBefore(this.start) && !end.isAfter(this.end);
+ };
+ // Requesting and Purging
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.requestSources = function (sources) {
+ this.freeze();
+ for (var i = 0; i < sources.length; i++) {
+ this.requestSource(sources[i]);
+ }
+ this.thaw();
+ };
+ EventPeriod.prototype.requestSource = function (source) {
+ var _this = this;
+ var request = { source: source, status: 'pending', eventDefs: null };
+ this.requestsByUid[source.uid] = request;
+ this.pendingCnt += 1;
+ source.fetch(this.start, this.end, this.timezone).then(function (eventDefs) {
+ if (request.status !== 'cancelled') {
+ request.status = 'completed';
+ request.eventDefs = eventDefs;
+ _this.addEventDefs(eventDefs);
+ _this.pendingCnt--;
+ _this.tryRelease();
+ }
+ }, function () {
+ if (request.status !== 'cancelled') {
+ request.status = 'failed';
+ _this.pendingCnt--;
+ _this.tryRelease();
+ }
+ });
+ };
+ EventPeriod.prototype.purgeSource = function (source) {
+ var request = this.requestsByUid[source.uid];
+ if (request) {
+ delete this.requestsByUid[source.uid];
+ if (request.status === 'pending') {
+ request.status = 'cancelled';
+ this.pendingCnt--;
+ this.tryRelease();
+ }
+ else if (request.status === 'completed') {
+ request.eventDefs.forEach(this.removeEventDef.bind(this));
+ }
+ }
+ };
+ EventPeriod.prototype.purgeAllSources = function () {
+ var requestsByUid = this.requestsByUid;
+ var uid;
+ var request;
+ var completedCnt = 0;
+ for (uid in requestsByUid) {
+ request = requestsByUid[uid];
+ if (request.status === 'pending') {
+ request.status = 'cancelled';
+ }
+ else if (request.status === 'completed') {
+ completedCnt++;
+ }
+ }
+ this.requestsByUid = {};
+ this.pendingCnt = 0;
+ if (completedCnt) {
+ this.removeAllEventDefs(); // might release
+ }
+ };
+ // Event Definitions
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.getEventDefByUid = function (eventDefUid) {
+ return this.eventDefsByUid[eventDefUid];
+ };
+ EventPeriod.prototype.getEventDefsById = function (eventDefId) {
+ var a = this.eventDefsById[eventDefId];
+ if (a) {
+ return a.slice(); // clone
+ }
+ return [];
+ };
+ EventPeriod.prototype.addEventDefs = function (eventDefs) {
+ for (var i = 0; i < eventDefs.length; i++) {
+ this.addEventDef(eventDefs[i]);
+ }
+ };
+ EventPeriod.prototype.addEventDef = function (eventDef) {
+ var eventDefsById = this.eventDefsById;
+ var eventDefId = eventDef.id;
+ var eventDefs = eventDefsById[eventDefId] || (eventDefsById[eventDefId] = []);
+ var eventInstances = eventDef.buildInstances(this.unzonedRange);
+ var i;
+ eventDefs.push(eventDef);
+ this.eventDefsByUid[eventDef.uid] = eventDef;
+ for (i = 0; i < eventInstances.length; i++) {
+ this.addEventInstance(eventInstances[i], eventDefId);
+ }
+ };
+ EventPeriod.prototype.removeEventDefsById = function (eventDefId) {
+ var _this = this;
+ this.getEventDefsById(eventDefId).forEach(function (eventDef) {
+ _this.removeEventDef(eventDef);
+ });
+ };
+ EventPeriod.prototype.removeAllEventDefs = function () {
+ var isEmpty = $.isEmptyObject(this.eventDefsByUid);
+ this.eventDefsByUid = {};
+ this.eventDefsById = {};
+ this.eventInstanceGroupsById = {};
+ if (!isEmpty) {
+ this.tryRelease();
+ }
+ };
+ EventPeriod.prototype.removeEventDef = function (eventDef) {
+ var eventDefsById = this.eventDefsById;
+ var eventDefs = eventDefsById[eventDef.id];
+ delete this.eventDefsByUid[eventDef.uid];
+ if (eventDefs) {
+ util_1.removeExact(eventDefs, eventDef);
+ if (!eventDefs.length) {
+ delete eventDefsById[eventDef.id];
+ }
+ this.removeEventInstancesForDef(eventDef);
+ }
+ };
+ // Event Instances
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.getEventInstances = function () {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstances = [];
+ var id;
+ for (id in eventInstanceGroupsById) {
+ eventInstances.push.apply(eventInstances, // append
+ eventInstanceGroupsById[id].eventInstances);
+ }
+ return eventInstances;
+ };
+ EventPeriod.prototype.getEventInstancesWithId = function (eventDefId) {
+ var eventInstanceGroup = this.eventInstanceGroupsById[eventDefId];
+ if (eventInstanceGroup) {
+ return eventInstanceGroup.eventInstances.slice(); // clone
+ }
+ return [];
+ };
+ EventPeriod.prototype.getEventInstancesWithoutId = function (eventDefId) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var matchingInstances = [];
+ var id;
+ for (id in eventInstanceGroupsById) {
+ if (id !== eventDefId) {
+ matchingInstances.push.apply(matchingInstances, // append
+ eventInstanceGroupsById[id].eventInstances);
+ }
+ }
+ return matchingInstances;
+ };
+ EventPeriod.prototype.addEventInstance = function (eventInstance, eventDefId) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstanceGroup = eventInstanceGroupsById[eventDefId] ||
+ (eventInstanceGroupsById[eventDefId] = new EventInstanceGroup_1.default());
+ eventInstanceGroup.eventInstances.push(eventInstance);
+ this.tryRelease();
+ };
+ EventPeriod.prototype.removeEventInstancesForDef = function (eventDef) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstanceGroup = eventInstanceGroupsById[eventDef.id];
+ var removeCnt;
+ if (eventInstanceGroup) {
+ removeCnt = util_1.removeMatching(eventInstanceGroup.eventInstances, function (currentEventInstance) {
+ return currentEventInstance.def === eventDef;
+ });
+ if (!eventInstanceGroup.eventInstances.length) {
+ delete eventInstanceGroupsById[eventDef.id];
+ }
+ if (removeCnt) {
+ this.tryRelease();
+ }
+ }
+ };
+ // Releasing and Freezing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.tryRelease = function () {
+ if (!this.pendingCnt) {
+ if (!this.freezeDepth) {
+ this.release();
+ }
+ else {
+ this.stuntedReleaseCnt++;
+ }
+ }
+ };
+ EventPeriod.prototype.release = function () {
+ this.releaseCnt++;
+ this.trigger('release', this.eventInstanceGroupsById);
+ };
+ EventPeriod.prototype.whenReleased = function () {
+ var _this = this;
+ if (this.releaseCnt) {
+ return Promise_1.default.resolve(this.eventInstanceGroupsById);
+ }
+ else {
+ return Promise_1.default.construct(function (onResolve) {
+ _this.one('release', onResolve);
+ });
+ }
+ };
+ EventPeriod.prototype.freeze = function () {
+ if (!(this.freezeDepth++)) {
+ this.stuntedReleaseCnt = 0;
+ }
+ };
+ EventPeriod.prototype.thaw = function () {
+ if (!(--this.freezeDepth) && this.stuntedReleaseCnt && !this.pendingCnt) {
+ this.release();
+ }
+ };
+ return EventPeriod;
+}());
+exports.default = EventPeriod;
+EmitterMixin_1.default.mixInto(EventPeriod);
+
+
+/***/ }),
+/* 244 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ListenerMixin_1 = __webpack_require__(7);
+/* Creates a clone of an element and lets it track the mouse as it moves
+----------------------------------------------------------------------------------------------------------------------*/
+var MouseFollower = /** @class */ (function () {
+ function MouseFollower(sourceEl, options) {
+ this.isFollowing = false;
+ this.isHidden = false;
+ this.isAnimating = false; // doing the revert animation?
+ this.options = options = options || {};
+ this.sourceEl = sourceEl;
+ this.parentEl = options.parentEl ? $(options.parentEl) : sourceEl.parent(); // default to sourceEl's parent
+ }
+ // Causes the element to start following the mouse
+ MouseFollower.prototype.start = function (ev) {
+ if (!this.isFollowing) {
+ this.isFollowing = true;
+ this.y0 = util_1.getEvY(ev);
+ this.x0 = util_1.getEvX(ev);
+ this.topDelta = 0;
+ this.leftDelta = 0;
+ if (!this.isHidden) {
+ this.updatePosition();
+ }
+ if (util_1.getEvIsTouch(ev)) {
+ this.listenTo($(document), 'touchmove', this.handleMove);
+ }
+ else {
+ this.listenTo($(document), 'mousemove', this.handleMove);
+ }
+ }
+ };
+ // Causes the element to stop following the mouse. If shouldRevert is true, will animate back to original position.
+ // `callback` gets invoked when the animation is complete. If no animation, it is invoked immediately.
+ MouseFollower.prototype.stop = function (shouldRevert, callback) {
+ var _this = this;
+ var revertDuration = this.options.revertDuration;
+ var complete = function () {
+ _this.isAnimating = false;
+ _this.removeElement();
+ _this.top0 = _this.left0 = null; // reset state for future updatePosition calls
+ if (callback) {
+ callback();
+ }
+ };
+ if (this.isFollowing && !this.isAnimating) {
+ this.isFollowing = false;
+ this.stopListeningTo($(document));
+ if (shouldRevert && revertDuration && !this.isHidden) {
+ this.isAnimating = true;
+ this.el.animate({
+ top: this.top0,
+ left: this.left0
+ }, {
+ duration: revertDuration,
+ complete: complete
+ });
+ }
+ else {
+ complete();
+ }
+ }
+ };
+ // Gets the tracking element. Create it if necessary
+ MouseFollower.prototype.getEl = function () {
+ var el = this.el;
+ if (!el) {
+ el = this.el = this.sourceEl.clone()
+ .addClass(this.options.additionalClass || '')
+ .css({
+ position: 'absolute',
+ visibility: '',
+ display: this.isHidden ? 'none' : '',
+ margin: 0,
+ right: 'auto',
+ bottom: 'auto',
+ width: this.sourceEl.width(),
+ height: this.sourceEl.height(),
+ opacity: this.options.opacity || '',
+ zIndex: this.options.zIndex
+ });
+ // we don't want long taps or any mouse interaction causing selection/menus.
+ // would use preventSelection(), but that prevents selectstart, causing problems.
+ el.addClass('fc-unselectable');
+ el.appendTo(this.parentEl);
+ }
+ return el;
+ };
+ // Removes the tracking element if it has already been created
+ MouseFollower.prototype.removeElement = function () {
+ if (this.el) {
+ this.el.remove();
+ this.el = null;
+ }
+ };
+ // Update the CSS position of the tracking element
+ MouseFollower.prototype.updatePosition = function () {
+ var sourceOffset;
+ var origin;
+ this.getEl(); // ensure this.el
+ // make sure origin info was computed
+ if (this.top0 == null) {
+ sourceOffset = this.sourceEl.offset();
+ origin = this.el.offsetParent().offset();
+ this.top0 = sourceOffset.top - origin.top;
+ this.left0 = sourceOffset.left - origin.left;
+ }
+ this.el.css({
+ top: this.top0 + this.topDelta,
+ left: this.left0 + this.leftDelta
+ });
+ };
+ // Gets called when the user moves the mouse
+ MouseFollower.prototype.handleMove = function (ev) {
+ this.topDelta = util_1.getEvY(ev) - this.y0;
+ this.leftDelta = util_1.getEvX(ev) - this.x0;
+ if (!this.isHidden) {
+ this.updatePosition();
+ }
+ };
+ // Temporarily makes the tracking element invisible. Can be called before following starts
+ MouseFollower.prototype.hide = function () {
+ if (!this.isHidden) {
+ this.isHidden = true;
+ if (this.el) {
+ this.el.hide();
+ }
+ }
+ };
+ // Show the tracking element after it has been temporarily hidden
+ MouseFollower.prototype.show = function () {
+ if (this.isHidden) {
+ this.isHidden = false;
+ this.updatePosition();
+ this.getEl().show();
+ }
+ };
+ return MouseFollower;
+}());
+exports.default = MouseFollower;
+ListenerMixin_1.default.mixInto(MouseFollower);
+
+
+/***/ }),
+/* 245 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var HitDragListener_1 = __webpack_require__(23);
+var Interaction_1 = __webpack_require__(15);
+var DateClicking = /** @class */ (function (_super) {
+ tslib_1.__extends(DateClicking, _super);
+ /*
+ component must implement:
+ - bindDateHandlerToEl
+ - getSafeHitFootprint
+ - getHitEl
+ */
+ function DateClicking(component) {
+ var _this = _super.call(this, component) || this;
+ _this.dragListener = _this.buildDragListener();
+ return _this;
+ }
+ DateClicking.prototype.end = function () {
+ this.dragListener.endInteraction();
+ };
+ DateClicking.prototype.bindToEl = function (el) {
+ var component = this.component;
+ var dragListener = this.dragListener;
+ component.bindDateHandlerToEl(el, 'mousedown', function (ev) {
+ if (!component.shouldIgnoreMouse()) {
+ dragListener.startInteraction(ev);
+ }
+ });
+ component.bindDateHandlerToEl(el, 'touchstart', function (ev) {
+ if (!component.shouldIgnoreTouch()) {
+ dragListener.startInteraction(ev);
+ }
+ });
+ };
+ // Creates a listener that tracks the user's drag across day elements, for day clicking.
+ DateClicking.prototype.buildDragListener = function () {
+ var _this = this;
+ var component = this.component;
+ var dayClickHit; // null if invalid dayClick
+ var dragListener = new HitDragListener_1.default(component, {
+ scroll: this.opt('dragScroll'),
+ interactionStart: function () {
+ dayClickHit = dragListener.origHit;
+ },
+ hitOver: function (hit, isOrig, origHit) {
+ // if user dragged to another cell at any point, it can no longer be a dayClick
+ if (!isOrig) {
+ dayClickHit = null;
+ }
+ },
+ hitOut: function () {
+ dayClickHit = null;
+ },
+ interactionEnd: function (ev, isCancelled) {
+ var componentFootprint;
+ if (!isCancelled && dayClickHit) {
+ componentFootprint = component.getSafeHitFootprint(dayClickHit);
+ if (componentFootprint) {
+ _this.view.triggerDayClick(componentFootprint, component.getHitEl(dayClickHit), ev);
+ }
+ }
+ }
+ });
+ // because dragListener won't be called with any time delay, "dragging" will begin immediately,
+ // which will kill any touchmoving/scrolling. Prevent this.
+ dragListener.shouldCancelTouchScroll = false;
+ dragListener.scrollAlwaysKills = true;
+ return dragListener;
+ };
+ return DateClicking;
+}(Interaction_1.default));
+exports.default = DateClicking;
+
+
+/***/ }),
+/* 246 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var EventRenderer_1 = __webpack_require__(42);
+/*
+Only handles foreground segs.
+Does not own rendering. Use for low-level util methods by TimeGrid.
+*/
+var TimeGridEventRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(TimeGridEventRenderer, _super);
+ function TimeGridEventRenderer(timeGrid, fillRenderer) {
+ var _this = _super.call(this, timeGrid, fillRenderer) || this;
+ _this.timeGrid = timeGrid;
+ return _this;
+ }
+ TimeGridEventRenderer.prototype.renderFgSegs = function (segs) {
+ this.renderFgSegsIntoContainers(segs, this.timeGrid.fgContainerEls);
+ };
+ // Given an array of foreground segments, render a DOM element for each, computes position,
+ // and attaches to the column inner-container elements.
+ TimeGridEventRenderer.prototype.renderFgSegsIntoContainers = function (segs, containerEls) {
+ var segsByCol;
+ var col;
+ segsByCol = this.timeGrid.groupSegsByCol(segs);
+ for (col = 0; col < this.timeGrid.colCnt; col++) {
+ this.updateFgSegCoords(segsByCol[col]);
+ }
+ this.timeGrid.attachSegsByCol(segsByCol, containerEls);
+ };
+ TimeGridEventRenderer.prototype.unrenderFgSegs = function () {
+ if (this.fgSegs) {
+ this.fgSegs.forEach(function (seg) {
+ seg.el.remove();
+ });
+ }
+ };
+ // Computes a default event time formatting string if `timeFormat` is not explicitly defined
+ TimeGridEventRenderer.prototype.computeEventTimeFormat = function () {
+ return this.opt('noMeridiemTimeFormat'); // like "6:30" (no AM/PM)
+ };
+ // Computes a default `displayEventEnd` value if one is not expliclty defined
+ TimeGridEventRenderer.prototype.computeDisplayEventEnd = function () {
+ return true;
+ };
+ // Renders the HTML for a single event segment's default rendering
+ TimeGridEventRenderer.prototype.fgSegHtml = function (seg, disableResizing) {
+ var view = this.view;
+ var calendar = view.calendar;
+ var componentFootprint = seg.footprint.componentFootprint;
+ var isAllDay = componentFootprint.isAllDay;
+ var eventDef = seg.footprint.eventDef;
+ var isDraggable = view.isEventDefDraggable(eventDef);
+ var isResizableFromStart = !disableResizing && seg.isStart && view.isEventDefResizableFromStart(eventDef);
+ var isResizableFromEnd = !disableResizing && seg.isEnd && view.isEventDefResizableFromEnd(eventDef);
+ var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
+ var skinCss = util_1.cssToStr(this.getSkinCss(eventDef));
+ var timeText;
+ var fullTimeText; // more verbose time text. for the print stylesheet
+ var startTimeText; // just the start time text
+ classes.unshift('fc-time-grid-event', 'fc-v-event');
+ // if the event appears to span more than one day...
+ if (view.isMultiDayRange(componentFootprint.unzonedRange)) {
+ // Don't display time text on segments that run entirely through a day.
+ // That would appear as midnight-midnight and would look dumb.
+ // Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am)
+ if (seg.isStart || seg.isEnd) {
+ var zonedStart = calendar.msToMoment(seg.startMs);
+ var zonedEnd = calendar.msToMoment(seg.endMs);
+ timeText = this._getTimeText(zonedStart, zonedEnd, isAllDay);
+ fullTimeText = this._getTimeText(zonedStart, zonedEnd, isAllDay, 'LT');
+ startTimeText = this._getTimeText(zonedStart, zonedEnd, isAllDay, null, false); // displayEnd=false
+ }
+ }
+ else {
+ // Display the normal time text for the *event's* times
+ timeText = this.getTimeText(seg.footprint);
+ fullTimeText = this.getTimeText(seg.footprint, 'LT');
+ startTimeText = this.getTimeText(seg.footprint, null, false); // displayEnd=false
+ }
+ return '<a class="' + classes.join(' ') + '"' +
+ (eventDef.url ?
+ ' href="' + util_1.htmlEscape(eventDef.url) + '"' :
+ '') +
+ (skinCss ?
+ ' style="' + skinCss + '"' :
+ '') +
+ '>' +
+ '<div class="fc-content">' +
+ (timeText ?
+ '<div class="fc-time"' +
+ ' data-start="' + util_1.htmlEscape(startTimeText) + '"' +
+ ' data-full="' + util_1.htmlEscape(fullTimeText) + '"' +
+ '>' +
+ '<span>' + util_1.htmlEscape(timeText) + '</span>' +
+ '</div>' :
+ '') +
+ (eventDef.title ?
+ '<div class="fc-title">' +
+ util_1.htmlEscape(eventDef.title) +
+ '</div>' :
+ '') +
+ '</div>' +
+ '<div class="fc-bg"/>' +
+ /* TODO: write CSS for this
+ (isResizableFromStart ?
+ '<div class="fc-resizer fc-start-resizer" />' :
+ ''
+ ) +
+ */
+ (isResizableFromEnd ?
+ '<div class="fc-resizer fc-end-resizer" />' :
+ '') +
+ '</a>';
+ };
+ // Given segments that are assumed to all live in the *same column*,
+ // compute their verical/horizontal coordinates and assign to their elements.
+ TimeGridEventRenderer.prototype.updateFgSegCoords = function (segs) {
+ this.timeGrid.computeSegVerticals(segs); // horizontals relies on this
+ this.computeFgSegHorizontals(segs); // compute horizontal coordinates, z-index's, and reorder the array
+ this.timeGrid.assignSegVerticals(segs);
+ this.assignFgSegHorizontals(segs);
+ };
+ // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
+ // NOTE: Also reorders the given array by date!
+ TimeGridEventRenderer.prototype.computeFgSegHorizontals = function (segs) {
+ var levels;
+ var level0;
+ var i;
+ this.sortEventSegs(segs); // order by certain criteria
+ levels = buildSlotSegLevels(segs);
+ computeForwardSlotSegs(levels);
+ if ((level0 = levels[0])) {
+ for (i = 0; i < level0.length; i++) {
+ computeSlotSegPressures(level0[i]);
+ }
+ for (i = 0; i < level0.length; i++) {
+ this.computeFgSegForwardBack(level0[i], 0, 0);
+ }
+ }
+ };
+ // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
+ // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
+ // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
+ //
+ // The segment might be part of a "series", which means consecutive segments with the same pressure
+ // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
+ // segments behind this one in the current series, and `seriesBackwardCoord` is the starting
+ // coordinate of the first segment in the series.
+ TimeGridEventRenderer.prototype.computeFgSegForwardBack = function (seg, seriesBackwardPressure, seriesBackwardCoord) {
+ var forwardSegs = seg.forwardSegs;
+ var i;
+ if (seg.forwardCoord === undefined) {
+ if (!forwardSegs.length) {
+ // if there are no forward segments, this segment should butt up against the edge
+ seg.forwardCoord = 1;
+ }
+ else {
+ // sort highest pressure first
+ this.sortForwardSegs(forwardSegs);
+ // this segment's forwardCoord will be calculated from the backwardCoord of the
+ // highest-pressure forward segment.
+ this.computeFgSegForwardBack(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);
+ seg.forwardCoord = forwardSegs[0].backwardCoord;
+ }
+ // calculate the backwardCoord from the forwardCoord. consider the series
+ seg.backwardCoord = seg.forwardCoord -
+ (seg.forwardCoord - seriesBackwardCoord) / // available width for series
+ (seriesBackwardPressure + 1); // # of segments in the series
+ // use this segment's coordinates to computed the coordinates of the less-pressurized
+ // forward segments
+ for (i = 0; i < forwardSegs.length; i++) {
+ this.computeFgSegForwardBack(forwardSegs[i], 0, seg.forwardCoord);
+ }
+ }
+ };
+ TimeGridEventRenderer.prototype.sortForwardSegs = function (forwardSegs) {
+ forwardSegs.sort(util_1.proxy(this, 'compareForwardSegs'));
+ };
+ // A cmp function for determining which forward segment to rely on more when computing coordinates.
+ TimeGridEventRenderer.prototype.compareForwardSegs = function (seg1, seg2) {
+ // put higher-pressure first
+ return seg2.forwardPressure - seg1.forwardPressure ||
+ // put segments that are closer to initial edge first (and favor ones with no coords yet)
+ (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||
+ // do normal sorting...
+ this.compareEventSegs(seg1, seg2);
+ };
+ // Given foreground event segments that have already had their position coordinates computed,
+ // assigns position-related CSS values to their elements.
+ TimeGridEventRenderer.prototype.assignFgSegHorizontals = function (segs) {
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ seg.el.css(this.generateFgSegHorizontalCss(seg));
+ // if the height is short, add a className for alternate styling
+ if (seg.bottom - seg.top < 30) {
+ seg.el.addClass('fc-short');
+ }
+ }
+ };
+ // Generates an object with CSS properties/values that should be applied to an event segment element.
+ // Contains important positioning-related properties that should be applied to any event element, customized or not.
+ TimeGridEventRenderer.prototype.generateFgSegHorizontalCss = function (seg) {
+ var shouldOverlap = this.opt('slotEventOverlap');
+ var backwardCoord = seg.backwardCoord; // the left side if LTR. the right side if RTL. floating-point
+ var forwardCoord = seg.forwardCoord; // the right side if LTR. the left side if RTL. floating-point
+ var props = this.timeGrid.generateSegVerticalCss(seg); // get top/bottom first
+ var isRTL = this.timeGrid.isRTL;
+ var left; // amount of space from left edge, a fraction of the total width
+ var right; // amount of space from right edge, a fraction of the total width
+ if (shouldOverlap) {
+ // double the width, but don't go beyond the maximum forward coordinate (1.0)
+ forwardCoord = Math.min(1, backwardCoord + (forwardCoord - backwardCoord) * 2);
+ }
+ if (isRTL) {
+ left = 1 - forwardCoord;
+ right = backwardCoord;
+ }
+ else {
+ left = backwardCoord;
+ right = 1 - forwardCoord;
+ }
+ props.zIndex = seg.level + 1; // convert from 0-base to 1-based
+ props.left = left * 100 + '%';
+ props.right = right * 100 + '%';
+ if (shouldOverlap && seg.forwardPressure) {
+ // add padding to the edge so that forward stacked events don't cover the resizer's icon
+ props[isRTL ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width
+ }
+ return props;
+ };
+ return TimeGridEventRenderer;
+}(EventRenderer_1.default));
+exports.default = TimeGridEventRenderer;
+// Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is
+// left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date.
+function buildSlotSegLevels(segs) {
+ var levels = [];
+ var i;
+ var seg;
+ var j;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ // go through all the levels and stop on the first level where there are no collisions
+ for (j = 0; j < levels.length; j++) {
+ if (!computeSlotSegCollisions(seg, levels[j]).length) {
+ break;
+ }
+ }
+ seg.level = j;
+ (levels[j] || (levels[j] = [])).push(seg);
+ }
+ return levels;
+}
+// For every segment, figure out the other segments that are in subsequent
+// levels that also occupy the same vertical space. Accumulate in seg.forwardSegs
+function computeForwardSlotSegs(levels) {
+ var i;
+ var level;
+ var j;
+ var seg;
+ var k;
+ for (i = 0; i < levels.length; i++) {
+ level = levels[i];
+ for (j = 0; j < level.length; j++) {
+ seg = level[j];
+ seg.forwardSegs = [];
+ for (k = i + 1; k < levels.length; k++) {
+ computeSlotSegCollisions(seg, levels[k], seg.forwardSegs);
+ }
+ }
+ }
+}
+// Figure out which path forward (via seg.forwardSegs) results in the longest path until
+// the furthest edge is reached. The number of segments in this path will be seg.forwardPressure
+function computeSlotSegPressures(seg) {
+ var forwardSegs = seg.forwardSegs;
+ var forwardPressure = 0;
+ var i;
+ var forwardSeg;
+ if (seg.forwardPressure === undefined) {
+ for (i = 0; i < forwardSegs.length; i++) {
+ forwardSeg = forwardSegs[i];
+ // figure out the child's maximum forward path
+ computeSlotSegPressures(forwardSeg);
+ // either use the existing maximum, or use the child's forward pressure
+ // plus one (for the forwardSeg itself)
+ forwardPressure = Math.max(forwardPressure, 1 + forwardSeg.forwardPressure);
+ }
+ seg.forwardPressure = forwardPressure;
+ }
+}
+// Find all the segments in `otherSegs` that vertically collide with `seg`.
+// Append into an optionally-supplied `results` array and return.
+function computeSlotSegCollisions(seg, otherSegs, results) {
+ if (results === void 0) { results = []; }
+ for (var i = 0; i < otherSegs.length; i++) {
+ if (isSlotSegCollision(seg, otherSegs[i])) {
+ results.push(otherSegs[i]);
+ }
+ }
+ return results;
+}
+// Do these segments occupy the same vertical space?
+function isSlotSegCollision(seg1, seg2) {
+ return seg1.bottom > seg2.top && seg1.top < seg2.bottom;
+}
+
+
+/***/ }),
+/* 247 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var HelperRenderer_1 = __webpack_require__(58);
+var TimeGridHelperRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(TimeGridHelperRenderer, _super);
+ function TimeGridHelperRenderer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ TimeGridHelperRenderer.prototype.renderSegs = function (segs, sourceSeg) {
+ var helperNodes = [];
+ var i;
+ var seg;
+ var sourceEl;
+ // TODO: not good to call eventRenderer this way
+ this.eventRenderer.renderFgSegsIntoContainers(segs, this.component.helperContainerEls);
+ // Try to make the segment that is in the same row as sourceSeg look the same
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ if (sourceSeg && sourceSeg.col === seg.col) {
+ sourceEl = sourceSeg.el;
+ seg.el.css({
+ left: sourceEl.css('left'),
+ right: sourceEl.css('right'),
+ 'margin-left': sourceEl.css('margin-left'),
+ 'margin-right': sourceEl.css('margin-right')
+ });
+ }
+ helperNodes.push(seg.el[0]);
+ }
+ return $(helperNodes); // must return the elements rendered
+ };
+ return TimeGridHelperRenderer;
+}(HelperRenderer_1.default));
+exports.default = TimeGridHelperRenderer;
+
+
+/***/ }),
+/* 248 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var FillRenderer_1 = __webpack_require__(57);
+var TimeGridFillRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(TimeGridFillRenderer, _super);
+ function TimeGridFillRenderer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ TimeGridFillRenderer.prototype.attachSegEls = function (type, segs) {
+ var timeGrid = this.component;
+ var containerEls;
+ // TODO: more efficient lookup
+ if (type === 'bgEvent') {
+ containerEls = timeGrid.bgContainerEls;
+ }
+ else if (type === 'businessHours') {
+ containerEls = timeGrid.businessContainerEls;
+ }
+ else if (type === 'highlight') {
+ containerEls = timeGrid.highlightContainerEls;
+ }
+ timeGrid.updateSegVerticals(segs);
+ timeGrid.attachSegsByCol(timeGrid.groupSegsByCol(segs), containerEls);
+ return segs.map(function (seg) {
+ return seg.el[0];
+ });
+ };
+ return TimeGridFillRenderer;
+}(FillRenderer_1.default));
+exports.default = TimeGridFillRenderer;
+
+
+/***/ }),
+/* 249 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* A rectangular panel that is absolutely positioned over other content
+------------------------------------------------------------------------------------------------------------------------
+Options:
+ - className (string)
+ - content (HTML string or jQuery element set)
+ - parentEl
+ - top
+ - left
+ - right (the x coord of where the right edge should be. not a "CSS" right)
+ - autoHide (boolean)
+ - show (callback)
+ - hide (callback)
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ListenerMixin_1 = __webpack_require__(7);
+var Popover = /** @class */ (function () {
+ function Popover(options) {
+ this.isHidden = true;
+ this.margin = 10; // the space required between the popover and the edges of the scroll container
+ this.options = options || {};
+ }
+ // Shows the popover on the specified position. Renders it if not already
+ Popover.prototype.show = function () {
+ if (this.isHidden) {
+ if (!this.el) {
+ this.render();
+ }
+ this.el.show();
+ this.position();
+ this.isHidden = false;
+ this.trigger('show');
+ }
+ };
+ // Hides the popover, through CSS, but does not remove it from the DOM
+ Popover.prototype.hide = function () {
+ if (!this.isHidden) {
+ this.el.hide();
+ this.isHidden = true;
+ this.trigger('hide');
+ }
+ };
+ // Creates `this.el` and renders content inside of it
+ Popover.prototype.render = function () {
+ var _this = this;
+ var options = this.options;
+ this.el = $('<div class="fc-popover"/>')
+ .addClass(options.className || '')
+ .css({
+ // position initially to the top left to avoid creating scrollbars
+ top: 0,
+ left: 0
+ })
+ .append(options.content)
+ .appendTo(options.parentEl);
+ // when a click happens on anything inside with a 'fc-close' className, hide the popover
+ this.el.on('click', '.fc-close', function () {
+ _this.hide();
+ });
+ if (options.autoHide) {
+ this.listenTo($(document), 'mousedown', this.documentMousedown);
+ }
+ };
+ // Triggered when the user clicks *anywhere* in the document, for the autoHide feature
+ Popover.prototype.documentMousedown = function (ev) {
+ // only hide the popover if the click happened outside the popover
+ if (this.el && !$(ev.target).closest(this.el).length) {
+ this.hide();
+ }
+ };
+ // Hides and unregisters any handlers
+ Popover.prototype.removeElement = function () {
+ this.hide();
+ if (this.el) {
+ this.el.remove();
+ this.el = null;
+ }
+ this.stopListeningTo($(document), 'mousedown');
+ };
+ // Positions the popover optimally, using the top/left/right options
+ Popover.prototype.position = function () {
+ var options = this.options;
+ var origin = this.el.offsetParent().offset();
+ var width = this.el.outerWidth();
+ var height = this.el.outerHeight();
+ var windowEl = $(window);
+ var viewportEl = util_1.getScrollParent(this.el);
+ var viewportTop;
+ var viewportLeft;
+ var viewportOffset;
+ var top; // the "position" (not "offset") values for the popover
+ var left; //
+ // compute top and left
+ top = options.top || 0;
+ if (options.left !== undefined) {
+ left = options.left;
+ }
+ else if (options.right !== undefined) {
+ left = options.right - width; // derive the left value from the right value
+ }
+ else {
+ left = 0;
+ }
+ if (viewportEl.is(window) || viewportEl.is(document)) {
+ viewportEl = windowEl;
+ viewportTop = 0; // the window is always at the top left
+ viewportLeft = 0; // (and .offset() won't work if called here)
+ }
+ else {
+ viewportOffset = viewportEl.offset();
+ viewportTop = viewportOffset.top;
+ viewportLeft = viewportOffset.left;
+ }
+ // if the window is scrolled, it causes the visible area to be further down
+ viewportTop += windowEl.scrollTop();
+ viewportLeft += windowEl.scrollLeft();
+ // constrain to the view port. if constrained by two edges, give precedence to top/left
+ if (options.viewportConstrain !== false) {
+ top = Math.min(top, viewportTop + viewportEl.outerHeight() - height - this.margin);
+ top = Math.max(top, viewportTop + this.margin);
+ left = Math.min(left, viewportLeft + viewportEl.outerWidth() - width - this.margin);
+ left = Math.max(left, viewportLeft + this.margin);
+ }
+ this.el.css({
+ top: top - origin.top,
+ left: left - origin.left
+ });
+ };
+ // Triggers a callback. Calls a function in the option hash of the same name.
+ // Arguments beyond the first `name` are forwarded on.
+ // TODO: better code reuse for this. Repeat code
+ Popover.prototype.trigger = function (name) {
+ if (this.options[name]) {
+ this.options[name].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ };
+ return Popover;
+}());
+exports.default = Popover;
+ListenerMixin_1.default.mixInto(Popover);
+
+
+/***/ }),
+/* 250 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var EventRenderer_1 = __webpack_require__(42);
+/* Event-rendering methods for the DayGrid class
+----------------------------------------------------------------------------------------------------------------------*/
+var DayGridEventRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(DayGridEventRenderer, _super);
+ function DayGridEventRenderer(dayGrid, fillRenderer) {
+ var _this = _super.call(this, dayGrid, fillRenderer) || this;
+ _this.dayGrid = dayGrid;
+ return _this;
+ }
+ DayGridEventRenderer.prototype.renderBgRanges = function (eventRanges) {
+ // don't render timed background events
+ eventRanges = $.grep(eventRanges, function (eventRange) {
+ return eventRange.eventDef.isAllDay();
+ });
+ _super.prototype.renderBgRanges.call(this, eventRanges);
+ };
+ // Renders the given foreground event segments onto the grid
+ DayGridEventRenderer.prototype.renderFgSegs = function (segs) {
+ var rowStructs = this.rowStructs = this.renderSegRows(segs);
+ // append to each row's content skeleton
+ this.dayGrid.rowEls.each(function (i, rowNode) {
+ $(rowNode).find('.fc-content-skeleton > table').append(rowStructs[i].tbodyEl);
+ });
+ };
+ // Unrenders all currently rendered foreground event segments
+ DayGridEventRenderer.prototype.unrenderFgSegs = function () {
+ var rowStructs = this.rowStructs || [];
+ var rowStruct;
+ while ((rowStruct = rowStructs.pop())) {
+ rowStruct.tbodyEl.remove();
+ }
+ this.rowStructs = null;
+ };
+ // Uses the given events array to generate <tbody> elements that should be appended to each row's content skeleton.
+ // Returns an array of rowStruct objects (see the bottom of `renderSegRow`).
+ // PRECONDITION: each segment shoud already have a rendered and assigned `.el`
+ DayGridEventRenderer.prototype.renderSegRows = function (segs) {
+ var rowStructs = [];
+ var segRows;
+ var row;
+ segRows = this.groupSegRows(segs); // group into nested arrays
+ // iterate each row of segment groupings
+ for (row = 0; row < segRows.length; row++) {
+ rowStructs.push(this.renderSegRow(row, segRows[row]));
+ }
+ return rowStructs;
+ };
+ // Given a row # and an array of segments all in the same row, render a <tbody> element, a skeleton that contains
+ // the segments. Returns object with a bunch of internal data about how the render was calculated.
+ // NOTE: modifies rowSegs
+ DayGridEventRenderer.prototype.renderSegRow = function (row, rowSegs) {
+ var colCnt = this.dayGrid.colCnt;
+ var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels
+ var levelCnt = Math.max(1, segLevels.length); // ensure at least one level
+ var tbody = $('<tbody/>');
+ var segMatrix = []; // lookup for which segments are rendered into which level+col cells
+ var cellMatrix = []; // lookup for all <td> elements of the level+col matrix
+ var loneCellMatrix = []; // lookup for <td> elements that only take up a single column
+ var i;
+ var levelSegs;
+ var col;
+ var tr;
+ var j;
+ var seg;
+ var td;
+ // populates empty cells from the current column (`col`) to `endCol`
+ function emptyCellsUntil(endCol) {
+ while (col < endCol) {
+ // try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell
+ td = (loneCellMatrix[i - 1] || [])[col];
+ if (td) {
+ td.attr('rowspan', parseInt(td.attr('rowspan') || 1, 10) + 1);
+ }
+ else {
+ td = $('<td/>');
+ tr.append(td);
+ }
+ cellMatrix[i][col] = td;
+ loneCellMatrix[i][col] = td;
+ col++;
+ }
+ }
+ for (i = 0; i < levelCnt; i++) {
+ levelSegs = segLevels[i];
+ col = 0;
+ tr = $('<tr/>');
+ segMatrix.push([]);
+ cellMatrix.push([]);
+ loneCellMatrix.push([]);
+ // levelCnt might be 1 even though there are no actual levels. protect against this.
+ // this single empty row is useful for styling.
+ if (levelSegs) {
+ for (j = 0; j < levelSegs.length; j++) {
+ seg = levelSegs[j];
+ emptyCellsUntil(seg.leftCol);
+ // create a container that occupies or more columns. append the event element.
+ td = $('<td class="fc-event-container"/>').append(seg.el);
+ if (seg.leftCol !== seg.rightCol) {
+ td.attr('colspan', seg.rightCol - seg.leftCol + 1);
+ }
+ else {
+ loneCellMatrix[i][col] = td;
+ }
+ while (col <= seg.rightCol) {
+ cellMatrix[i][col] = td;
+ segMatrix[i][col] = seg;
+ col++;
+ }
+ tr.append(td);
+ }
+ }
+ emptyCellsUntil(colCnt); // finish off the row
+ this.dayGrid.bookendCells(tr);
+ tbody.append(tr);
+ }
+ return {
+ row: row,
+ tbodyEl: tbody,
+ cellMatrix: cellMatrix,
+ segMatrix: segMatrix,
+ segLevels: segLevels,
+ segs: rowSegs
+ };
+ };
+ // Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels.
+ // NOTE: modifies segs
+ DayGridEventRenderer.prototype.buildSegLevels = function (segs) {
+ var levels = [];
+ var i;
+ var seg;
+ var j;
+ // Give preference to elements with certain criteria, so they have
+ // a chance to be closer to the top.
+ this.sortEventSegs(segs);
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ // loop through levels, starting with the topmost, until the segment doesn't collide with other segments
+ for (j = 0; j < levels.length; j++) {
+ if (!isDaySegCollision(seg, levels[j])) {
+ break;
+ }
+ }
+ // `j` now holds the desired subrow index
+ seg.level = j;
+ // create new level array if needed and append segment
+ (levels[j] || (levels[j] = [])).push(seg);
+ }
+ // order segments left-to-right. very important if calendar is RTL
+ for (j = 0; j < levels.length; j++) {
+ levels[j].sort(compareDaySegCols);
+ }
+ return levels;
+ };
+ // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row
+ DayGridEventRenderer.prototype.groupSegRows = function (segs) {
+ var segRows = [];
+ var i;
+ for (i = 0; i < this.dayGrid.rowCnt; i++) {
+ segRows.push([]);
+ }
+ for (i = 0; i < segs.length; i++) {
+ segRows[segs[i].row].push(segs[i]);
+ }
+ return segRows;
+ };
+ // Computes a default event time formatting string if `timeFormat` is not explicitly defined
+ DayGridEventRenderer.prototype.computeEventTimeFormat = function () {
+ return this.opt('extraSmallTimeFormat'); // like "6p" or "6:30p"
+ };
+ // Computes a default `displayEventEnd` value if one is not expliclty defined
+ DayGridEventRenderer.prototype.computeDisplayEventEnd = function () {
+ return this.dayGrid.colCnt === 1; // we'll likely have space if there's only one day
+ };
+ // Builds the HTML to be used for the default element for an individual segment
+ DayGridEventRenderer.prototype.fgSegHtml = function (seg, disableResizing) {
+ var view = this.view;
+ var eventDef = seg.footprint.eventDef;
+ var isAllDay = seg.footprint.componentFootprint.isAllDay;
+ var isDraggable = view.isEventDefDraggable(eventDef);
+ var isResizableFromStart = !disableResizing && isAllDay &&
+ seg.isStart && view.isEventDefResizableFromStart(eventDef);
+ var isResizableFromEnd = !disableResizing && isAllDay &&
+ seg.isEnd && view.isEventDefResizableFromEnd(eventDef);
+ var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
+ var skinCss = util_1.cssToStr(this.getSkinCss(eventDef));
+ var timeHtml = '';
+ var timeText;
+ var titleHtml;
+ classes.unshift('fc-day-grid-event', 'fc-h-event');
+ // Only display a timed events time if it is the starting segment
+ if (seg.isStart) {
+ timeText = this.getTimeText(seg.footprint);
+ if (timeText) {
+ timeHtml = '<span class="fc-time">' + util_1.htmlEscape(timeText) + '</span>';
+ }
+ }
+ titleHtml =
+ '<span class="fc-title">' +
+ (util_1.htmlEscape(eventDef.title || '') || '&nbsp;') + // we always want one line of height
+ '</span>';
+ return '<a class="' + classes.join(' ') + '"' +
+ (eventDef.url ?
+ ' href="' + util_1.htmlEscape(eventDef.url) + '"' :
+ '') +
+ (skinCss ?
+ ' style="' + skinCss + '"' :
+ '') +
+ '>' +
+ '<div class="fc-content">' +
+ (this.dayGrid.isRTL ?
+ titleHtml + ' ' + timeHtml : // put a natural space in between
+ timeHtml + ' ' + titleHtml //
+ ) +
+ '</div>' +
+ (isResizableFromStart ?
+ '<div class="fc-resizer fc-start-resizer" />' :
+ '') +
+ (isResizableFromEnd ?
+ '<div class="fc-resizer fc-end-resizer" />' :
+ '') +
+ '</a>';
+ };
+ return DayGridEventRenderer;
+}(EventRenderer_1.default));
+exports.default = DayGridEventRenderer;
+// Computes whether two segments' columns collide. They are assumed to be in the same row.
+function isDaySegCollision(seg, otherSegs) {
+ var i;
+ var otherSeg;
+ for (i = 0; i < otherSegs.length; i++) {
+ otherSeg = otherSegs[i];
+ if (otherSeg.leftCol <= seg.rightCol &&
+ otherSeg.rightCol >= seg.leftCol) {
+ return true;
+ }
+ }
+ return false;
+}
+// A cmp function for determining the leftmost event
+function compareDaySegCols(a, b) {
+ return a.leftCol - b.leftCol;
+}
+
+
+/***/ }),
+/* 251 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var HelperRenderer_1 = __webpack_require__(58);
+var DayGridHelperRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(DayGridHelperRenderer, _super);
+ function DayGridHelperRenderer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Renders a mock "helper" event. `sourceSeg` is the associated internal segment object. It can be null.
+ DayGridHelperRenderer.prototype.renderSegs = function (segs, sourceSeg) {
+ var helperNodes = [];
+ var rowStructs;
+ // TODO: not good to call eventRenderer this way
+ rowStructs = this.eventRenderer.renderSegRows(segs);
+ // inject each new event skeleton into each associated row
+ this.component.rowEls.each(function (row, rowNode) {
+ var rowEl = $(rowNode); // the .fc-row
+ var skeletonEl = $('<div class="fc-helper-skeleton"><table/></div>'); // will be absolutely positioned
+ var skeletonTopEl;
+ var skeletonTop;
+ // If there is an original segment, match the top position. Otherwise, put it at the row's top level
+ if (sourceSeg && sourceSeg.row === row) {
+ skeletonTop = sourceSeg.el.position().top;
+ }
+ else {
+ skeletonTopEl = rowEl.find('.fc-content-skeleton tbody');
+ if (!skeletonTopEl.length) {
+ skeletonTopEl = rowEl.find('.fc-content-skeleton table');
+ }
+ skeletonTop = skeletonTopEl.position().top;
+ }
+ skeletonEl.css('top', skeletonTop)
+ .find('table')
+ .append(rowStructs[row].tbodyEl);
+ rowEl.append(skeletonEl);
+ helperNodes.push(skeletonEl[0]);
+ });
+ return $(helperNodes); // must return the elements rendered
+ };
+ return DayGridHelperRenderer;
+}(HelperRenderer_1.default));
+exports.default = DayGridHelperRenderer;
+
+
+/***/ }),
+/* 252 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var FillRenderer_1 = __webpack_require__(57);
+var DayGridFillRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(DayGridFillRenderer, _super);
+ function DayGridFillRenderer() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.fillSegTag = 'td'; // override the default tag name
+ return _this;
+ }
+ DayGridFillRenderer.prototype.attachSegEls = function (type, segs) {
+ var nodes = [];
+ var i;
+ var seg;
+ var skeletonEl;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ skeletonEl = this.renderFillRow(type, seg);
+ this.component.rowEls.eq(seg.row).append(skeletonEl);
+ nodes.push(skeletonEl[0]);
+ }
+ return nodes;
+ };
+ // Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered.
+ DayGridFillRenderer.prototype.renderFillRow = function (type, seg) {
+ var colCnt = this.component.colCnt;
+ var startCol = seg.leftCol;
+ var endCol = seg.rightCol + 1;
+ var className;
+ var skeletonEl;
+ var trEl;
+ if (type === 'businessHours') {
+ className = 'bgevent';
+ }
+ else {
+ className = type.toLowerCase();
+ }
+ skeletonEl = $('<div class="fc-' + className + '-skeleton">' +
+ '<table><tr/></table>' +
+ '</div>');
+ trEl = skeletonEl.find('tr');
+ if (startCol > 0) {
+ trEl.append('<td colspan="' + startCol + '"/>');
+ }
+ trEl.append(seg.el.attr('colspan', endCol - startCol));
+ if (endCol < colCnt) {
+ trEl.append('<td colspan="' + (colCnt - endCol) + '"/>');
+ }
+ this.component.bookendCells(trEl);
+ return skeletonEl;
+ };
+ return DayGridFillRenderer;
+}(FillRenderer_1.default));
+exports.default = DayGridFillRenderer;
+
+
+/***/ }),
+/* 253 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var BasicViewDateProfileGenerator_1 = __webpack_require__(228);
+var UnzonedRange_1 = __webpack_require__(5);
+var MonthViewDateProfileGenerator = /** @class */ (function (_super) {
+ tslib_1.__extends(MonthViewDateProfileGenerator, _super);
+ function MonthViewDateProfileGenerator() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Computes the date range that will be rendered.
+ MonthViewDateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
+ var renderUnzonedRange = _super.prototype.buildRenderRange.call(this, currentUnzonedRange, currentRangeUnit, isRangeAllDay);
+ var start = this.msToUtcMoment(renderUnzonedRange.startMs, isRangeAllDay);
+ var end = this.msToUtcMoment(renderUnzonedRange.endMs, isRangeAllDay);
+ var rowCnt;
+ // ensure 6 weeks
+ if (this.opt('fixedWeekCount')) {
+ rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
+ end.diff(start, 'weeks', true) // dontRound=true
+ );
+ end.add(6 - rowCnt, 'weeks');
+ }
+ return new UnzonedRange_1.default(start, end);
+ };
+ return MonthViewDateProfileGenerator;
+}(BasicViewDateProfileGenerator_1.default));
+exports.default = MonthViewDateProfileGenerator;
+
+
+/***/ }),
+/* 254 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var EventRenderer_1 = __webpack_require__(42);
+var ListEventRenderer = /** @class */ (function (_super) {
+ tslib_1.__extends(ListEventRenderer, _super);
+ function ListEventRenderer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ ListEventRenderer.prototype.renderFgSegs = function (segs) {
+ if (!segs.length) {
+ this.component.renderEmptyMessage();
+ }
+ else {
+ this.component.renderSegList(segs);
+ }
+ };
+ // generates the HTML for a single event row
+ ListEventRenderer.prototype.fgSegHtml = function (seg) {
+ var view = this.view;
+ var calendar = view.calendar;
+ var theme = calendar.theme;
+ var eventFootprint = seg.footprint;
+ var eventDef = eventFootprint.eventDef;
+ var componentFootprint = eventFootprint.componentFootprint;
+ var url = eventDef.url;
+ var classes = ['fc-list-item'].concat(this.getClasses(eventDef));
+ var bgColor = this.getBgColor(eventDef);
+ var timeHtml;
+ if (componentFootprint.isAllDay) {
+ timeHtml = view.getAllDayHtml();
+ }
+ else if (view.isMultiDayRange(componentFootprint.unzonedRange)) {
+ if (seg.isStart || seg.isEnd) {
+ timeHtml = util_1.htmlEscape(this._getTimeText(calendar.msToMoment(seg.startMs), calendar.msToMoment(seg.endMs), componentFootprint.isAllDay));
+ }
+ else {
+ timeHtml = view.getAllDayHtml();
+ }
+ }
+ else {
+ // Display the normal time text for the *event's* times
+ timeHtml = util_1.htmlEscape(this.getTimeText(eventFootprint));
+ }
+ if (url) {
+ classes.push('fc-has-url');
+ }
+ return '<tr class="' + classes.join(' ') + '">' +
+ (this.displayEventTime ?
+ '<td class="fc-list-item-time ' + theme.getClass('widgetContent') + '">' +
+ (timeHtml || '') +
+ '</td>' :
+ '') +
+ '<td class="fc-list-item-marker ' + theme.getClass('widgetContent') + '">' +
+ '<span class="fc-event-dot"' +
+ (bgColor ?
+ ' style="background-color:' + bgColor + '"' :
+ '') +
+ '></span>' +
+ '</td>' +
+ '<td class="fc-list-item-title ' + theme.getClass('widgetContent') + '">' +
+ '<a' + (url ? ' href="' + util_1.htmlEscape(url) + '"' : '') + '>' +
+ util_1.htmlEscape(eventDef.title || '') +
+ '</a>' +
+ '</td>' +
+ '</tr>';
+ };
+ // like "4:00am"
+ ListEventRenderer.prototype.computeEventTimeFormat = function () {
+ return this.opt('mediumTimeFormat');
+ };
+ return ListEventRenderer;
+}(EventRenderer_1.default));
+exports.default = ListEventRenderer;
+
+
+/***/ }),
+/* 255 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var EventPointing_1 = __webpack_require__(59);
+var ListEventPointing = /** @class */ (function (_super) {
+ tslib_1.__extends(ListEventPointing, _super);
+ function ListEventPointing() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // for events with a url, the whole <tr> should be clickable,
+ // but it's impossible to wrap with an <a> tag. simulate this.
+ ListEventPointing.prototype.handleClick = function (seg, ev) {
+ var url;
+ _super.prototype.handleClick.call(this, seg, ev); // might prevent the default action
+ // not clicking on or within an <a> with an href
+ if (!$(ev.target).closest('a[href]').length) {
+ url = seg.footprint.eventDef.url;
+ if (url && !ev.isDefaultPrevented()) {
+ window.location.href = url; // simulate link click
+ }
+ }
+ };
+ return ListEventPointing;
+}(EventPointing_1.default));
+exports.default = ListEventPointing;
+
+
+/***/ }),
+/* 256 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventSourceParser_1 = __webpack_require__(38);
+var ArrayEventSource_1 = __webpack_require__(52);
+var FuncEventSource_1 = __webpack_require__(215);
+var JsonFeedEventSource_1 = __webpack_require__(216);
+EventSourceParser_1.default.registerClass(ArrayEventSource_1.default);
+EventSourceParser_1.default.registerClass(FuncEventSource_1.default);
+EventSourceParser_1.default.registerClass(JsonFeedEventSource_1.default);
+
+
+/***/ }),
+/* 257 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var ThemeRegistry_1 = __webpack_require__(51);
+var StandardTheme_1 = __webpack_require__(213);
+var JqueryUiTheme_1 = __webpack_require__(214);
+var Bootstrap3Theme_1 = __webpack_require__(258);
+var Bootstrap4Theme_1 = __webpack_require__(259);
+ThemeRegistry_1.defineThemeSystem('standard', StandardTheme_1.default);
+ThemeRegistry_1.defineThemeSystem('jquery-ui', JqueryUiTheme_1.default);
+ThemeRegistry_1.defineThemeSystem('bootstrap3', Bootstrap3Theme_1.default);
+ThemeRegistry_1.defineThemeSystem('bootstrap4', Bootstrap4Theme_1.default);
+
+
+/***/ }),
+/* 258 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Theme_1 = __webpack_require__(19);
+var Bootstrap3Theme = /** @class */ (function (_super) {
+ tslib_1.__extends(Bootstrap3Theme, _super);
+ function Bootstrap3Theme() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return Bootstrap3Theme;
+}(Theme_1.default));
+exports.default = Bootstrap3Theme;
+Bootstrap3Theme.prototype.classes = {
+ widget: 'fc-bootstrap3',
+ tableGrid: 'table-bordered',
+ tableList: 'table',
+ tableListHeading: 'active',
+ buttonGroup: 'btn-group',
+ button: 'btn btn-default',
+ stateActive: 'active',
+ stateDisabled: 'disabled',
+ today: 'alert alert-info',
+ popover: 'panel panel-default',
+ popoverHeader: 'panel-heading',
+ popoverContent: 'panel-body',
+ // day grid
+ // for left/right border color when border is inset from edges (all-day in agenda view)
+ // avoid `panel` class b/c don't want margins/radius. only border color.
+ headerRow: 'panel-default',
+ dayRow: 'panel-default',
+ // list view
+ listView: 'panel panel-default'
+};
+Bootstrap3Theme.prototype.baseIconClass = 'glyphicon';
+Bootstrap3Theme.prototype.iconClasses = {
+ close: 'glyphicon-remove',
+ prev: 'glyphicon-chevron-left',
+ next: 'glyphicon-chevron-right',
+ prevYear: 'glyphicon-backward',
+ nextYear: 'glyphicon-forward'
+};
+Bootstrap3Theme.prototype.iconOverrideOption = 'bootstrapGlyphicons';
+Bootstrap3Theme.prototype.iconOverrideCustomButtonOption = 'bootstrapGlyphicon';
+Bootstrap3Theme.prototype.iconOverridePrefix = 'glyphicon-';
+
+
+/***/ }),
+/* 259 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Theme_1 = __webpack_require__(19);
+var Bootstrap4Theme = /** @class */ (function (_super) {
+ tslib_1.__extends(Bootstrap4Theme, _super);
+ function Bootstrap4Theme() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return Bootstrap4Theme;
+}(Theme_1.default));
+exports.default = Bootstrap4Theme;
+Bootstrap4Theme.prototype.classes = {
+ widget: 'fc-bootstrap4',
+ tableGrid: 'table-bordered',
+ tableList: 'table',
+ tableListHeading: 'table-active',
+ buttonGroup: 'btn-group',
+ button: 'btn btn-primary',
+ stateActive: 'active',
+ stateDisabled: 'disabled',
+ today: 'alert alert-info',
+ popover: 'card card-primary',
+ popoverHeader: 'card-header',
+ popoverContent: 'card-body',
+ // day grid
+ // for left/right border color when border is inset from edges (all-day in agenda view)
+ // avoid `table` class b/c don't want margins/padding/structure. only border color.
+ headerRow: 'table-bordered',
+ dayRow: 'table-bordered',
+ // list view
+ listView: 'card card-primary'
+};
+Bootstrap4Theme.prototype.baseIconClass = 'fa';
+Bootstrap4Theme.prototype.iconClasses = {
+ close: 'fa-times',
+ prev: 'fa-chevron-left',
+ next: 'fa-chevron-right',
+ prevYear: 'fa-angle-double-left',
+ nextYear: 'fa-angle-double-right'
+};
+Bootstrap4Theme.prototype.iconOverrideOption = 'bootstrapFontAwesome';
+Bootstrap4Theme.prototype.iconOverrideCustomButtonOption = 'bootstrapFontAwesome';
+Bootstrap4Theme.prototype.iconOverridePrefix = 'fa-';
+
+
+/***/ }),
+/* 260 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var ViewRegistry_1 = __webpack_require__(22);
+var BasicView_1 = __webpack_require__(62);
+var MonthView_1 = __webpack_require__(229);
+ViewRegistry_1.defineView('basic', {
+ 'class': BasicView_1.default
+});
+ViewRegistry_1.defineView('basicDay', {
+ type: 'basic',
+ duration: { days: 1 }
+});
+ViewRegistry_1.defineView('basicWeek', {
+ type: 'basic',
+ duration: { weeks: 1 }
+});
+ViewRegistry_1.defineView('month', {
+ 'class': MonthView_1.default,
+ duration: { months: 1 },
+ defaults: {
+ fixedWeekCount: true
+ }
+});
+
+
+/***/ }),
+/* 261 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var ViewRegistry_1 = __webpack_require__(22);
+var AgendaView_1 = __webpack_require__(226);
+ViewRegistry_1.defineView('agenda', {
+ 'class': AgendaView_1.default,
+ defaults: {
+ allDaySlot: true,
+ slotDuration: '00:30:00',
+ slotEventOverlap: true // a bad name. confused with overlap/constraint system
+ }
+});
+ViewRegistry_1.defineView('agendaDay', {
+ type: 'agenda',
+ duration: { days: 1 }
+});
+ViewRegistry_1.defineView('agendaWeek', {
+ type: 'agenda',
+ duration: { weeks: 1 }
+});
+
+
+/***/ }),
+/* 262 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var ViewRegistry_1 = __webpack_require__(22);
+var ListView_1 = __webpack_require__(230);
+ViewRegistry_1.defineView('list', {
+ 'class': ListView_1.default,
+ buttonTextKey: 'list',
+ defaults: {
+ buttonText: 'list',
+ listDayFormat: 'LL',
+ noEventsMessage: 'No events to display'
+ }
+});
+ViewRegistry_1.defineView('listDay', {
+ type: 'list',
+ duration: { days: 1 },
+ defaults: {
+ listDayFormat: 'dddd' // day-of-week is all we need. full date is probably in header
+ }
+});
+ViewRegistry_1.defineView('listWeek', {
+ type: 'list',
+ duration: { weeks: 1 },
+ defaults: {
+ listDayFormat: 'dddd',
+ listDayAltFormat: 'LL'
+ }
+});
+ViewRegistry_1.defineView('listMonth', {
+ type: 'list',
+ duration: { month: 1 },
+ defaults: {
+ listDayAltFormat: 'dddd' // day-of-week is nice-to-have
+ }
+});
+ViewRegistry_1.defineView('listYear', {
+ type: 'list',
+ duration: { year: 1 },
+ defaults: {
+ listDayAltFormat: 'dddd' // day-of-week is nice-to-have
+ }
+});
+
+
+/***/ }),
+/* 263 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+
+
+/***/ })
+/******/ ]);
+});
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js
new file mode 100644
index 00000000..88045457
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js
@@ -0,0 +1,12 @@
+/*!
+ * FullCalendar v3.9.0
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("moment"),require("jquery")):"function"==typeof define&&define.amd?define(["moment","jquery"],e):"object"==typeof exports?exports.FullCalendar=e(require("moment"),require("jquery")):t.FullCalendar=e(t.moment,t.jQuery)}("undefined"!=typeof self?self:this,function(t,e){return function(t){function e(i){if(n[i])return n[i].exports;var r=n[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=236)}([function(e,n){e.exports=t},,function(t,e){var n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};e.__extends=function(t,e){function i(){this.constructor=t}n(t,e),t.prototype=null===e?Object.create(e):(i.prototype=e.prototype,new i)}},function(t,n){t.exports=e},function(t,e,n){function i(t,e){e.left&&t.css({"border-left-width":1,"margin-left":e.left-1}),e.right&&t.css({"border-right-width":1,"margin-right":e.right-1})}function r(t){t.css({"margin-left":"","margin-right":"","border-left-width":"","border-right-width":""})}function o(){ht("body").addClass("fc-not-allowed")}function s(){ht("body").removeClass("fc-not-allowed")}function a(t,e,n){var i=Math.floor(e/t.length),r=Math.floor(e-i*(t.length-1)),o=[],s=[],a=[],u=0;l(t),t.each(function(e,n){var l=e===t.length-1?r:i,d=ht(n).outerHeight(!0);d<l?(o.push(n),s.push(d),a.push(ht(n).height())):u+=d}),n&&(e-=u,i=Math.floor(e/o.length),r=Math.floor(e-i*(o.length-1))),ht(o).each(function(t,e){var n=t===o.length-1?r:i,l=s[t],u=a[t],d=n-(l-u);l<n&&ht(e).height(d)})}function l(t){t.height("")}function u(t){var e=0;return t.find("> *").each(function(t,n){var i=ht(n).outerWidth();i>e&&(e=i)}),e++,t.width(e),e}function d(t,e){var n,i=t.add(e);return i.css({position:"relative",left:-1}),n=t.outerHeight()-e.outerHeight(),i.css({position:"",left:""}),n}function c(t){var e=t.css("position"),n=t.parents().filter(function(){var t=ht(this);return/(auto|scroll)/.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==e&&n.length?n:ht(t[0].ownerDocument||document)}function p(t,e){var n=t.offset(),i=n.left-(e?e.left:0),r=n.top-(e?e.top:0);return{left:i,right:i+t.outerWidth(),top:r,bottom:r+t.outerHeight()}}function h(t,e){var n=t.offset(),i=g(t),r=n.left+b(t,"border-left-width")+i.left-(e?e.left:0),o=n.top+b(t,"border-top-width")+i.top-(e?e.top:0);return{left:r,right:r+t[0].clientWidth,top:o,bottom:o+t[0].clientHeight}}function f(t,e){var n=t.offset(),i=n.left+b(t,"border-left-width")+b(t,"padding-left")-(e?e.left:0),r=n.top+b(t,"border-top-width")+b(t,"padding-top")-(e?e.top:0);return{left:i,right:i+t.width(),top:r,bottom:r+t.height()}}function g(t){var e,n=t[0].offsetWidth-t[0].clientWidth,i=t[0].offsetHeight-t[0].clientHeight;return n=v(n),i=v(i),e={left:0,right:0,top:0,bottom:i},y()&&"rtl"===t.css("direction")?e.left=n:e.right=n,e}function v(t){return t=Math.max(0,t),t=Math.round(t)}function y(){return null===ft&&(ft=m()),ft}function m(){var t=ht("<div><div/></div>").css({position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}).appendTo("body"),e=t.children(),n=e.offset().left>t.offset().left;return t.remove(),n}function b(t,e){return parseFloat(t.css(e))||0}function w(t){return 1===t.which&&!t.ctrlKey}function D(t){var e=t.originalEvent.touches;return e&&e.length?e[0].pageX:t.pageX}function E(t){var e=t.originalEvent.touches;return e&&e.length?e[0].pageY:t.pageY}function S(t){return/^touch/.test(t.type)}function C(t){t.addClass("fc-unselectable").on("selectstart",T)}function R(t){t.removeClass("fc-unselectable").off("selectstart",T)}function T(t){t.preventDefault()}function M(t,e){var n={left:Math.max(t.left,e.left),right:Math.min(t.right,e.right),top:Math.max(t.top,e.top),bottom:Math.min(t.bottom,e.bottom)};return n.left<n.right&&n.top<n.bottom&&n}function I(t,e){return{left:Math.min(Math.max(t.left,e.left),e.right),top:Math.min(Math.max(t.top,e.top),e.bottom)}}function H(t){return{left:(t.left+t.right)/2,top:(t.top+t.bottom)/2}}function P(t,e){return{left:t.left-e.left,top:t.top-e.top}}function _(t){var e,n,i=[],r=[];for("string"==typeof t?r=t.split(/\s*,\s*/):"function"==typeof t?r=[t]:ht.isArray(t)&&(r=t),e=0;e<r.length;e++)n=r[e],"string"==typeof n?i.push("-"===n.charAt(0)?{field:n.substring(1),order:-1}:{field:n,order:1}):"function"==typeof n&&i.push({func:n});return i}function x(t,e,n,i,r){var o,s;for(o=0;o<n.length;o++)if(s=O(t,e,n[o],i,r))return s;return 0}function O(t,e,n,i,r){if(n.func)return n.func(t,e);var o=t[n.field],s=e[n.field];return null==o&&i&&(o=i[n.field]),null==s&&r&&(s=r[n.field]),F(o,s)*(n.order||1)}function F(t,e){return t||e?null==e?-1:null==t?1:"string"===ht.type(t)||"string"===ht.type(e)?String(t).localeCompare(String(e)):t-e:0}function z(t,e){return pt.duration({days:t.clone().stripTime().diff(e.clone().stripTime(),"days"),ms:t.time()-e.time()})}function B(t,e){return pt.duration({days:t.clone().stripTime().diff(e.clone().stripTime(),"days")})}function A(t,e,n){return pt.duration(Math.round(t.diff(e,n,!0)),n)}function k(t,n){var i,r,o;for(i=0;i<e.unitsDesc.length&&(r=e.unitsDesc[i],!((o=V(r,t,n))>=1&&ut(o)));i++);return r}function L(t,e){var n=k(t);return"week"===n&&"object"==typeof e&&e.days&&(n="day"),n}function V(t,e,n){return null!=n?n.diff(e,t,!0):pt.isDuration(e)?e.as(t):e.end.diff(e.start,t,!0)}function G(t,e,n){var i;return U(n)?(e-t)/n:(i=n.asMonths(),Math.abs(i)>=1&&ut(i)?e.diff(t,"months",!0)/i:e.diff(t,"days",!0)/n.asDays())}function N(t,e){var n,i;return U(t)||U(e)?t/e:(n=t.asMonths(),i=e.asMonths(),Math.abs(n)>=1&&ut(n)&&Math.abs(i)>=1&&ut(i)?n/i:t.asDays()/e.asDays())}function j(t,e){var n;return U(t)?pt.duration(t*e):(n=t.asMonths(),Math.abs(n)>=1&&ut(n)?pt.duration({months:n*e}):pt.duration({days:t.asDays()*e}))}function U(t){return Boolean(t.hours()||t.minutes()||t.seconds()||t.milliseconds())}function W(t){return"[object Date]"===Object.prototype.toString.call(t)||t instanceof Date}function q(t){return"string"==typeof t&&/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(t)}function Y(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=window.console;if(n&&n.log)return n.log.apply(n,t)}function Z(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=window.console;return n&&n.warn?n.warn.apply(n,t):Y.apply(null,t)}function Q(t,e){var n,i,r,o,s,a,l={};if(e)for(n=0;n<e.length;n++){for(i=e[n],r=[],o=t.length-1;o>=0;o--)if("object"==typeof(s=t[o][i]))r.unshift(s);else if(void 0!==s){l[i]=s;break}r.length&&(l[i]=Q(r))}for(n=t.length-1;n>=0;n--){a=t[n];for(i in a)i in l||(l[i]=a[i])}return l}function X(t,e){for(var n in t)$(t,n)&&(e[n]=t[n])}function $(t,e){return gt.call(t,e)}function K(t,e,n){if(ht.isFunction(t)&&(t=[t]),t){var i=void 0,r=void 0;for(i=0;i<t.length;i++)r=t[i].apply(e,n)||r;return r}}function J(t,e){for(var n=0,i=0;i<t.length;)e(t[i])?(t.splice(i,1),n++):i++;return n}function tt(t,e){for(var n=0,i=0;i<t.length;)t[i]===e?(t.splice(i,1),n++):i++;return n}function et(t,e){var n,i=t.length;if(null==i||i!==e.length)return!1;for(n=0;n<i;n++)if(t[n]!==e[n])return!1;return!0}function nt(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];for(var n=0;n<t.length;n++)if(void 0!==t[n])return t[n]}function it(t){return(t+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;").replace(/\n/g,"<br />")}function rt(t){return t.replace(/&.*?;/g,"")}function ot(t){var e=[];return ht.each(t,function(t,n){null!=n&&e.push(t+":"+n)}),e.join(";")}function st(t){var e=[];return ht.each(t,function(t,n){null!=n&&e.push(t+'="'+it(n)+'"')}),e.join(" ")}function at(t){return t.charAt(0).toUpperCase()+t.slice(1)}function lt(t,e){return t-e}function ut(t){return t%1==0}function dt(t,e){var n=t[e];return function(){return n.apply(t,arguments)}}function ct(t,e,n){void 0===n&&(n=!1);var i,r,o,s,a,l=function(){var u=+new Date-s;u<e?i=setTimeout(l,e-u):(i=null,n||(a=t.apply(o,r),o=r=null))};return function(){o=this,r=arguments,s=+new Date;var u=n&&!i;return i||(i=setTimeout(l,e)),u&&(a=t.apply(o,r),o=r=null),a}}Object.defineProperty(e,"__esModule",{value:!0});var pt=n(0),ht=n(3);e.compensateScroll=i,e.uncompensateScroll=r,e.disableCursor=o,e.enableCursor=s,e.distributeHeight=a,e.undistributeHeight=l,e.matchCellWidths=u,e.subtractInnerElHeight=d,e.getScrollParent=c,e.getOuterRect=p,e.getClientRect=h,e.getContentRect=f,e.getScrollbarWidths=g;var ft=null;e.isPrimaryMouseButton=w,e.getEvX=D,e.getEvY=E,e.getEvIsTouch=S,e.preventSelection=C,e.allowSelection=R,e.preventDefault=T,e.intersectRects=M,e.constrainPoint=I,e.getRectCenter=H,e.diffPoints=P,e.parseFieldSpecs=_,e.compareByFieldSpecs=x,e.compareByFieldSpec=O,e.flexibleCompare=F,e.dayIDs=["sun","mon","tue","wed","thu","fri","sat"],e.unitsDesc=["year","month","week","day","hour","minute","second","millisecond"],e.diffDayTime=z,e.diffDay=B,e.diffByUnit=A,e.computeGreatestUnit=k,e.computeDurationGreatestUnit=L,e.divideRangeByDuration=G,e.divideDurationByDuration=N,e.multiplyDuration=j,e.durationHasTime=U,e.isNativeDate=W,e.isTimeString=q,e.log=Y,e.warn=Z;var gt={}.hasOwnProperty;e.mergeProps=Q,e.copyOwnProps=X,e.hasOwnProp=$,e.applyAll=K,e.removeMatching=J,e.removeExact=tt,e.isArraysEqual=et,e.firstDefined=nt,e.htmlEscape=it,e.stripHtmlEntities=rt,e.cssToStr=ot,e.attrsToStr=st,e.capitaliseFirstLetter=at,e.compareNumbers=lt,e.isInt=ut,e.proxy=dt,e.debounce=ct},function(t,e,n){function i(t,e){return t.startMs-e.startMs}Object.defineProperty(e,"__esModule",{value:!0});var r=n(0),o=n(10),s=function(){function t(t,e){this.isStart=!0,this.isEnd=!0,r.isMoment(t)&&(t=t.clone().stripZone()),r.isMoment(e)&&(e=e.clone().stripZone()),t&&(this.startMs=t.valueOf()),e&&(this.endMs=e.valueOf())}return t.invertRanges=function(e,n){var r,o,s=[],a=n.startMs;for(e.sort(i),r=0;r<e.length;r++)o=e[r],o.startMs>a&&s.push(new t(a,o.startMs)),o.endMs>a&&(a=o.endMs);return a<n.endMs&&s.push(new t(a,n.endMs)),s},t.prototype.intersect=function(e){var n=this.startMs,i=this.endMs,r=null;return null!=e.startMs&&(n=null==n?e.startMs:Math.max(n,e.startMs)),null!=e.endMs&&(i=null==i?e.endMs:Math.min(i,e.endMs)),(null==n||null==i||n<i)&&(r=new t(n,i),r.isStart=this.isStart&&n===this.startMs,r.isEnd=this.isEnd&&i===this.endMs),r},t.prototype.intersectsWith=function(t){return(null==this.endMs||null==t.startMs||this.endMs>t.startMs)&&(null==this.startMs||null==t.endMs||this.startMs<t.endMs)},t.prototype.containsRange=function(t){return(null==this.startMs||null!=t.startMs&&t.startMs>=this.startMs)&&(null==this.endMs||null!=t.endMs&&t.endMs<=this.endMs)},t.prototype.containsDate=function(t){var e=t.valueOf();return(null==this.startMs||e>=this.startMs)&&(null==this.endMs||e<this.endMs)},t.prototype.constrainDate=function(t){var e=t.valueOf();return null!=this.startMs&&e<this.startMs&&(e=this.startMs),null!=this.endMs&&e>=this.endMs&&(e=this.endMs-1),e},t.prototype.equals=function(t){return this.startMs===t.startMs&&this.endMs===t.endMs},t.prototype.clone=function(){var e=new t(this.startMs,this.endMs);return e.isStart=this.isStart,e.isEnd=this.isEnd,e},t.prototype.getStart=function(){return null!=this.startMs?o.default.utc(this.startMs).stripZone():null},t.prototype.getEnd=function(){return null!=this.endMs?o.default.utc(this.endMs).stripZone():null},t.prototype.as=function(t){return r.utc(this.endMs).diff(r.utc(this.startMs),t,!0)},t}();e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(208),s=n(33),a=n(49),l=function(t){function e(n){var i=t.call(this)||this;return i.calendar=n,i.className=[],i.uid=String(e.uuid++),i}return i.__extends(e,t),e.parse=function(t,e){var n=new this(e);return!("object"!=typeof t||!n.applyProps(t))&&n},e.normalizeId=function(t){return t?String(t):null},e.prototype.fetch=function(t,e,n){},e.prototype.removeEventDefsById=function(t){},e.prototype.removeAllEventDefs=function(){},e.prototype.getPrimitive=function(t){},e.prototype.parseEventDefs=function(t){var e,n,i=[];for(e=0;e<t.length;e++)(n=this.parseEventDef(t[e]))&&i.push(n);return i},e.prototype.parseEventDef=function(t){var e=this.calendar.opt("eventDataTransform"),n=this.eventDataTransform;return e&&(t=e(t,this.calendar)),n&&(t=n(t,this.calendar)),a.default.parse(t,this)},e.prototype.applyManualStandardProps=function(t){return null!=t.id&&(this.id=e.normalizeId(t.id)),r.isArray(t.className)?this.className=t.className:"string"==typeof t.className&&(this.className=t.className.split(/\s+/)),!0},e.uuid=0,e.defineStandardProps=o.default.defineStandardProps,e.copyVerbatimStandardProps=o.default.copyVerbatimStandardProps,e}(s.default);e.default=l,o.default.mixInto(l),l.defineStandardProps({id:!1,className:!1,color:!0,backgroundColor:!0,borderColor:!0,textColor:!0,editable:!0,startEditable:!0,durationEditable:!0,rendering:!0,overlap:!0,constraint:!0,allDayDefault:!0,eventDataTransform:!0})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(14),s=0,a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.listenTo=function(t,e,n){if("object"==typeof e)for(var i in e)e.hasOwnProperty(i)&&this.listenTo(t,i,e[i]);else"string"==typeof e&&t.on(e+"."+this.getListenerNamespace(),r.proxy(n,this))},e.prototype.stopListeningTo=function(t,e){t.off((e||"")+"."+this.getListenerNamespace())},e.prototype.getListenerNamespace=function(){return null==this.listenerId&&(this.listenerId=s++),"_listener"+this.listenerId},e}(o.default);e.default=a},,,function(t,e,n){function i(t,e){return c.format.call(t,e)}function r(t,e,n){void 0===e&&(e=!1),void 0===n&&(n=!1);var i,r,d,c,p=t[0],h=1===t.length&&"string"==typeof p;return o.isMoment(p)||a.isNativeDate(p)||void 0===p?c=o.apply(null,t):(i=!1,r=!1,h?l.test(p)?(p+="-01",t=[p],i=!0,r=!0):(d=u.exec(p))&&(i=!d[5],r=!0):s.isArray(p)&&(r=!0),c=e||i?o.utc.apply(o,t):o.apply(null,t),i?(c._ambigTime=!0,c._ambigZone=!0):n&&(r?c._ambigZone=!0:h&&c.utcOffset(p))),c._fullCalendar=!0,c}Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),s=n(3),a=n(4),l=/^\s*\d{4}-\d\d$/,u=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/,d=o.fn;e.newMomentProto=d;var c=s.extend({},d);e.oldMomentProto=c;var p=o.momentProperties;p.push("_fullCalendar"),p.push("_ambigTime"),p.push("_ambigZone"),e.oldMomentFormat=i;var h=function(){return r(arguments)};e.default=h,h.utc=function(){var t=r(arguments,!0);return t.hasTime()&&t.utc(),t},h.parseZone=function(){return r(arguments,!0,!0)},d.week=d.weeks=function(t){var e=this._locale._fullCalendar_weekCalc;return null==t&&"function"==typeof e?e(this):"ISO"===e?c.isoWeek.apply(this,arguments):c.week.apply(this,arguments)},d.time=function(t){if(!this._fullCalendar)return c.time.apply(this,arguments);if(null==t)return o.duration({hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()});this._ambigTime=!1,o.isDuration(t)||o.isMoment(t)||(t=o.duration(t));var e=0;return o.isDuration(t)&&(e=24*Math.floor(t.asDays())),this.hours(e+t.hours()).minutes(t.minutes()).seconds(t.seconds()).milliseconds(t.milliseconds())},d.stripTime=function(){return this._ambigTime||(this.utc(!0),this.set({hours:0,minutes:0,seconds:0,ms:0}),this._ambigTime=!0,this._ambigZone=!0),this},d.hasTime=function(){return!this._ambigTime},d.stripZone=function(){var t;return this._ambigZone||(t=this._ambigTime,this.utc(!0),this._ambigTime=t||!1,this._ambigZone=!0),this},d.hasZone=function(){return!this._ambigZone},d.local=function(t){return c.local.call(this,this._ambigZone||t),this._ambigTime=!1,this._ambigZone=!1,this},d.utc=function(t){return c.utc.call(this,t),this._ambigTime=!1,this._ambigZone=!1,this},d.utcOffset=function(t){return null!=t&&(this._ambigTime=!1,this._ambigZone=!1),c.utcOffset.apply(this,arguments)}},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(14),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.on=function(t,e){return r(this).on(t,this._prepareIntercept(e)),this},e.prototype.one=function(t,e){return r(this).one(t,this._prepareIntercept(e)),this},e.prototype._prepareIntercept=function(t){var e=function(e,n){return t.apply(n.context||this,n.args||[])};return t.guid||(t.guid=r.guid++),e.guid=t.guid,e},e.prototype.off=function(t,e){return r(this).off(t,e),this},e.prototype.trigger=function(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];return r(this).triggerHandler(t,{args:e}),this},e.prototype.triggerWith=function(t,e,n){return r(this).triggerHandler(t,{context:e,args:n}),this},e.prototype.hasHandlers=function(t){var e=r._data(this,"events");return e&&e[t]&&e[t].length>0},e}(o.default);e.default=s},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){this.isAllDay=!1,this.unzonedRange=t,this.isAllDay=e}return t.prototype.toLegacy=function(t){return{start:t.msToMoment(this.unzonedRange.startMs,this.isAllDay),end:t.msToMoment(this.unzonedRange.endMs,this.isAllDay)}},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(34),o=n(209),s=n(17),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.buildInstances=function(){return[this.buildInstance()]},e.prototype.buildInstance=function(){return new o.default(this,this.dateProfile)},e.prototype.isAllDay=function(){return this.dateProfile.isAllDay()},e.prototype.clone=function(){var e=t.prototype.clone.call(this);return e.dateProfile=this.dateProfile,e},e.prototype.rezone=function(){var t=this.source.calendar,e=this.dateProfile;this.dateProfile=new s.default(t.moment(e.start),e.end?t.moment(e.end):null,t)},e.prototype.applyManualStandardProps=function(e){var n=t.prototype.applyManualStandardProps.call(this,e),i=s.default.parse(e,this.source);return!!i&&(this.dateProfile=i,null!=e.date&&(this.miscProps.date=e.date),n)},e}(r.default);e.default=a,a.defineStandardProps({start:!1,date:!1,end:!1,allDay:!1})},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(){}return t.mixInto=function(t){var e=this;Object.getOwnPropertyNames(this.prototype).forEach(function(n){t.prototype[n]||(t.prototype[n]=e.prototype[n])})},t.mixOver=function(t){var e=this;Object.getOwnPropertyNames(this.prototype).forEach(function(n){t.prototype[n]=e.prototype[n]})},t}();e.default=n},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t){this.view=t._getView(),this.component=t}return t.prototype.opt=function(t){return this.view.opt(t)},t.prototype.end=function(){},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0}),e.version="3.9.0",e.internalApiVersion=12;var i=n(4);e.applyAll=i.applyAll,e.debounce=i.debounce,e.isInt=i.isInt,e.htmlEscape=i.htmlEscape,e.cssToStr=i.cssToStr,e.proxy=i.proxy,e.capitaliseFirstLetter=i.capitaliseFirstLetter,e.getOuterRect=i.getOuterRect,e.getClientRect=i.getClientRect,e.getContentRect=i.getContentRect,e.getScrollbarWidths=i.getScrollbarWidths,e.preventDefault=i.preventDefault,e.parseFieldSpecs=i.parseFieldSpecs,e.compareByFieldSpecs=i.compareByFieldSpecs,e.compareByFieldSpec=i.compareByFieldSpec,e.flexibleCompare=i.flexibleCompare,e.computeGreatestUnit=i.computeGreatestUnit,e.divideRangeByDuration=i.divideRangeByDuration,e.divideDurationByDuration=i.divideDurationByDuration,e.multiplyDuration=i.multiplyDuration,e.durationHasTime=i.durationHasTime,e.log=i.log,e.warn=i.warn,e.removeExact=i.removeExact,e.intersectRects=i.intersectRects;var r=n(47);e.formatDate=r.formatDate,e.formatRange=r.formatRange,e.queryMostGranularFormatUnit=r.queryMostGranularFormatUnit;var o=n(31);e.datepickerLocale=o.datepickerLocale,e.locale=o.locale;var s=n(10);e.moment=s.default;var a=n(11);e.EmitterMixin=a.default;var l=n(7);e.ListenerMixin=l.default;var u=n(48);e.Model=u.default;var d=n(207);e.Constraints=d.default;var c=n(5);e.UnzonedRange=c.default;var p=n(12);e.ComponentFootprint=p.default;var h=n(212);e.BusinessHourGenerator=h.default;var f=n(34);e.EventDef=f.default;var g=n(37);e.EventDefMutation=g.default;var v=n(38);e.EventSourceParser=v.default;var y=n(6);e.EventSource=y.default;var m=n(51);e.defineThemeSystem=m.defineThemeSystem;var b=n(18);e.EventInstanceGroup=b.default;var w=n(52);e.ArrayEventSource=w.default;var D=n(215);e.FuncEventSource=D.default;var E=n(216);e.JsonFeedEventSource=E.default;var S=n(36);e.EventFootprint=S.default;var C=n(33);e.Class=C.default;var R=n(14);e.Mixin=R.default;var T=n(53);e.CoordCache=T.default;var M=n(54);e.DragListener=M.default;var I=n(20);e.Promise=I.default;var H=n(217);e.TaskQueue=H.default;var P=n(218);e.RenderQueue=P.default;var _=n(39);e.Scroller=_.default;var x=n(19);e.Theme=x.default;var O=n(219);e.DateComponent=O.default;var F=n(40);e.InteractiveDateComponent=F.default;var z=n(220);e.Calendar=z.default;var B=n(41);e.View=B.default;var A=n(22);e.defineView=A.defineView,e.getViewConfig=A.getViewConfig;var k=n(55);e.DayTableMixin=k.default;var L=n(56);e.BusinessHourRenderer=L.default;var V=n(42);e.EventRenderer=V.default;var G=n(57);e.FillRenderer=G.default;var N=n(58);e.HelperRenderer=N.default;var j=n(222);e.ExternalDropping=j.default;var U=n(223);e.EventResizing=U.default;var W=n(59);e.EventPointing=W.default;var q=n(224);e.EventDragging=q.default;var Y=n(225);e.DateSelecting=Y.default;var Z=n(60);e.StandardInteractionsMixin=Z.default;var Q=n(226);e.AgendaView=Q.default;var X=n(227);e.TimeGrid=X.default;var $=n(61);e.DayGrid=$.default;var K=n(62);e.BasicView=K.default;var J=n(229);e.MonthView=J.default;var tt=n(230);e.ListView=tt.default},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),r=function(){function t(t,e,n){this.start=t,this.end=e||null,this.unzonedRange=this.buildUnzonedRange(n)}return t.parse=function(e,n){var i=e.start||e.date,r=e.end;if(!i)return!1;var o=n.calendar,s=o.moment(i),a=r?o.moment(r):null,l=e.allDay,u=o.opt("forceEventDuration");return!!s.isValid()&&(!a||a.isValid()&&a.isAfter(s)||(a=null),null==l&&null==(l=n.allDayDefault)&&(l=o.opt("allDayDefault")),!0===l?(s.stripTime(),a&&a.stripTime()):!1===l&&(s.hasTime()||s.time(0),a&&!a.hasTime()&&a.time(0)),!a&&u&&(a=o.getDefaultEventEnd(!s.hasTime(),s)),new t(s,a,o))},t.isStandardProp=function(t){return"start"===t||"date"===t||"end"===t||"allDay"===t},t.prototype.isAllDay=function(){return!(this.start.hasTime()||this.end&&this.end.hasTime())},t.prototype.buildUnzonedRange=function(t){var e=this.start.clone().stripZone().valueOf(),n=this.getEnd(t).stripZone().valueOf();return new i.default(e,n)},t.prototype.getEnd=function(t){return this.end?this.end.clone():t.getDefaultEventEnd(this.isAllDay(),this.start)},t}();e.default=r},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),r=n(35),o=n(211),s=function(){function t(t){this.eventInstances=t||[]}return t.prototype.getAllEventRanges=function(t){return t?this.sliceNormalRenderRanges(t):this.eventInstances.map(r.eventInstanceToEventRange)},t.prototype.sliceRenderRanges=function(t){return this.isInverse()?this.sliceInverseRenderRanges(t):this.sliceNormalRenderRanges(t)},t.prototype.sliceNormalRenderRanges=function(t){var e,n,i,r=this.eventInstances,s=[];for(e=0;e<r.length;e++)n=r[e],(i=n.dateProfile.unzonedRange.intersect(t))&&s.push(new o.default(i,n.def,n));return s},t.prototype.sliceInverseRenderRanges=function(t){var e=this.eventInstances.map(r.eventInstanceToUnzonedRange),n=this.getEventDef();return e=i.default.invertRanges(e,t),e.map(function(t){return new o.default(t,n)})},t.prototype.isInverse=function(){return this.getEventDef().hasInverseRendering()},t.prototype.getEventDef=function(){return this.explicitEventDef||this.eventInstances[0].def},t}();e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=function(){function t(t){this.optionsManager=t,this.processIconOverride()}return t.prototype.processIconOverride=function(){this.iconOverrideOption&&this.setIconOverride(this.optionsManager.get(this.iconOverrideOption))},t.prototype.setIconOverride=function(t){var e,n;if(i.isPlainObject(t)){e=i.extend({},this.iconClasses);for(n in t)e[n]=this.applyIconOverridePrefix(t[n]);this.iconClasses=e}else!1===t&&(this.iconClasses={})},t.prototype.applyIconOverridePrefix=function(t){var e=this.iconOverridePrefix;return e&&0!==t.indexOf(e)&&(t=e+t),t},t.prototype.getClass=function(t){return this.classes[t]||""},t.prototype.getIconClass=function(t){var e=this.iconClasses[t];return e?this.baseIconClass+" "+e:""},t.prototype.getCustomButtonIconClass=function(t){var e;return this.iconOverrideCustomButtonOption&&(e=t[this.iconOverrideCustomButtonOption])?this.baseIconClass+" "+this.applyIconOverridePrefix(e):""},t}();e.default=r,r.prototype.classes={},r.prototype.iconClasses={},r.prototype.baseIconClass="",r.prototype.iconOverridePrefix=""},function(t,e,n){function i(t,e){t.then=function(n){return"function"==typeof n?s.resolve(n(e)):t}}function r(t){t.then=function(e,n){return"function"==typeof n&&n(),t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(3),s={construct:function(t){var e=o.Deferred(),n=e.promise();return"function"==typeof t&&t(function(t){e.resolve(t),i(n,t)},function(){e.reject(),r(n)}),n},resolve:function(t){var e=o.Deferred().resolve(t),n=e.promise();return i(n,t),n},reject:function(){var t=o.Deferred().reject(),e=t.promise();return r(e),e}};e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(16),o=n(11),s=n(7);r.touchMouseIgnoreWait=500;var a=null,l=0,u=function(){function t(){this.isTouching=!1,this.mouseIgnoreDepth=0}return t.get=function(){return a||(a=new t,a.bind()),a},t.needed=function(){t.get(),l++},t.unneeded=function(){--l||(a.unbind(),a=null)},t.prototype.bind=function(){var t=this;this.listenTo(i(document),{touchstart:this.handleTouchStart,touchcancel:this.handleTouchCancel,touchend:this.handleTouchEnd,mousedown:this.handleMouseDown,mousemove:this.handleMouseMove,mouseup:this.handleMouseUp,click:this.handleClick,selectstart:this.handleSelectStart,contextmenu:this.handleContextMenu}),window.addEventListener("touchmove",this.handleTouchMoveProxy=function(e){t.handleTouchMove(i.Event(e))},{passive:!1}),window.addEventListener("scroll",this.handleScrollProxy=function(e){t.handleScroll(i.Event(e))},!0)},t.prototype.unbind=function(){this.stopListeningTo(i(document)),window.removeEventListener("touchmove",this.handleTouchMoveProxy),window.removeEventListener("scroll",this.handleScrollProxy,!0)},t.prototype.handleTouchStart=function(t){this.stopTouch(t,!0),this.isTouching=!0,this.trigger("touchstart",t)},t.prototype.handleTouchMove=function(t){this.isTouching&&this.trigger("touchmove",t)},t.prototype.handleTouchCancel=function(t){this.isTouching&&(this.trigger("touchcancel",t),this.stopTouch(t))},t.prototype.handleTouchEnd=function(t){this.stopTouch(t)},t.prototype.handleMouseDown=function(t){this.shouldIgnoreMouse()||this.trigger("mousedown",t)},t.prototype.handleMouseMove=function(t){this.shouldIgnoreMouse()||this.trigger("mousemove",t)},t.prototype.handleMouseUp=function(t){this.shouldIgnoreMouse()||this.trigger("mouseup",t)},t.prototype.handleClick=function(t){this.shouldIgnoreMouse()||this.trigger("click",t)},t.prototype.handleSelectStart=function(t){this.trigger("selectstart",t)},t.prototype.handleContextMenu=function(t){this.trigger("contextmenu",t)},t.prototype.handleScroll=function(t){this.trigger("scroll",t)},t.prototype.stopTouch=function(t,e){void 0===e&&(e=!1),this.isTouching&&(this.isTouching=!1,this.trigger("touchend",t),e||this.startTouchMouseIgnore())},t.prototype.startTouchMouseIgnore=function(){var t=this,e=r.touchMouseIgnoreWait;e&&(this.mouseIgnoreDepth++,setTimeout(function(){t.mouseIgnoreDepth--},e))},t.prototype.shouldIgnoreMouse=function(){return this.isTouching||Boolean(this.mouseIgnoreDepth)},t}();e.default=u,s.default.mixInto(u),o.default.mixInto(u)},function(t,e,n){function i(t,n){e.viewHash[t]=n}function r(t){return e.viewHash[t]}Object.defineProperty(e,"__esModule",{value:!0});var o=n(16);e.viewHash={},o.views=e.viewHash,e.defineView=i,e.getViewConfig=r},function(t,e,n){function i(t,e){return!t&&!e||!(!t||!e)&&(t.component===e.component&&r(t,e)&&r(e,t))}function r(t,e){for(var n in t)if(!/^(component|left|right|top|bottom)$/.test(n)&&t[n]!==e[n])return!1;return!0}Object.defineProperty(e,"__esModule",{value:!0});var o=n(2),s=n(4),a=n(54),l=function(t){function e(e,n){var i=t.call(this,n)||this;return i.component=e,i}return o.__extends(e,t),e.prototype.handleInteractionStart=function(e){var n,i,r,o=this.subjectEl;this.component.hitsNeeded(),this.computeScrollBounds(),e?(i={left:s.getEvX(e),top:s.getEvY(e)},r=i,o&&(n=s.getOuterRect(o),r=s.constrainPoint(r,n)),this.origHit=this.queryHit(r.left,r.top),o&&this.options.subjectCenter&&(this.origHit&&(n=s.intersectRects(this.origHit,n)||n),r=s.getRectCenter(n)),this.coordAdjust=s.diffPoints(r,i)):(this.origHit=null,this.coordAdjust=null),t.prototype.handleInteractionStart.call(this,e)},e.prototype.handleDragStart=function(e){var n;t.prototype.handleDragStart.call(this,e),(n=this.queryHit(s.getEvX(e),s.getEvY(e)))&&this.handleHitOver(n)},e.prototype.handleDrag=function(e,n,r){var o;t.prototype.handleDrag.call(this,e,n,r),o=this.queryHit(s.getEvX(r),s.getEvY(r)),i(o,this.hit)||(this.hit&&this.handleHitOut(),o&&this.handleHitOver(o))},e.prototype.handleDragEnd=function(e){this.handleHitDone(),t.prototype.handleDragEnd.call(this,e)},e.prototype.handleHitOver=function(t){var e=i(t,this.origHit);this.hit=t,this.trigger("hitOver",this.hit,e,this.origHit)},e.prototype.handleHitOut=function(){this.hit&&(this.trigger("hitOut",this.hit),this.handleHitDone(),this.hit=null)},e.prototype.handleHitDone=function(){this.hit&&this.trigger("hitDone",this.hit)},e.prototype.handleInteractionEnd=function(e,n){t.prototype.handleInteractionEnd.call(this,e,n),this.origHit=null,this.hit=null,this.component.hitsNotNeeded()},e.prototype.handleScrollEnd=function(){t.prototype.handleScrollEnd.call(this),this.isDragging&&(this.component.releaseHits(),this.component.prepareHits())},e.prototype.queryHit=function(t,e){return this.coordAdjust&&(t+=this.coordAdjust.left,e+=this.coordAdjust.top),this.component.queryHit(t,e)},e}(a.default);e.default=l},,,,,,,,function(t,e,n){function i(t){a.each(f,function(e,n){null==t[e]&&(t[e]=n(t))})}function r(t,n,i){var r=e.localeOptionHash[t]||(e.localeOptionHash[t]={});r.isRTL=i.isRTL,r.weekNumberTitle=i.weekHeader,a.each(p,function(t,e){r[t]=e(i)});var o=a.datepicker;o&&(o.regional[n]=o.regional[t]=i,o.regional.en=o.regional[""],o.setDefaults(i))}function o(t,n){var i,r;i=e.localeOptionHash[t]||(e.localeOptionHash[t]={}),n&&(i=e.localeOptionHash[t]=d.mergeOptions([i,n])),r=s(t),a.each(h,function(t,e){null==i[t]&&(i[t]=e(r,i))}),d.globalDefaults.locale=t}function s(t){return l.localeData(t)||l.localeData("en")}Object.defineProperty(e,"__esModule",{value:!0});var a=n(3),l=n(0),u=n(16),d=n(32),c=n(4);e.localeOptionHash={},u.locales=e.localeOptionHash;var p={buttonText:function(t){return{prev:c.stripHtmlEntities(t.prevText),next:c.stripHtmlEntities(t.nextText),today:c.stripHtmlEntities(t.currentText)}},monthYearFormat:function(t){return t.showMonthAfterYear?"YYYY["+t.yearSuffix+"] MMMM":"MMMM YYYY["+t.yearSuffix+"]"}},h={dayOfMonthFormat:function(t,e){var n=t.longDateFormat("l");return n=n.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g,""),e.isRTL?n+=" ddd":n="ddd "+n,n},
+mediumTimeFormat:function(t){return t.longDateFormat("LT").replace(/\s*a$/i,"a")},smallTimeFormat:function(t){return t.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"a")},extraSmallTimeFormat:function(t){return t.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"t")},hourFormat:function(t){return t.longDateFormat("LT").replace(":mm","").replace(/(\Wmm)$/,"").replace(/\s*a$/i,"a")},noMeridiemTimeFormat:function(t){return t.longDateFormat("LT").replace(/\s*a$/i,"")}},f={smallDayDateFormat:function(t){return t.isRTL?"D dd":"dd D"},weekFormat:function(t){return t.isRTL?"w[ "+t.weekNumberTitle+"]":"["+t.weekNumberTitle+" ]w"},smallWeekFormat:function(t){return t.isRTL?"w["+t.weekNumberTitle+"]":"["+t.weekNumberTitle+"]w"}};e.populateInstanceComputableOptions=i,e.datepickerLocale=r,e.locale=o,e.getMomentLocaleData=s,o("en",d.englishDefaults)},function(t,e,n){function i(t){return r.mergeProps(t,o)}Object.defineProperty(e,"__esModule",{value:!0});var r=n(4);e.globalDefaults={titleRangeSeparator:" – ",monthYearFormat:"MMMM YYYY",defaultTimedEventDuration:"02:00:00",defaultAllDayEventDuration:{days:1},forceEventDuration:!1,nextDayThreshold:"09:00:00",columnHeader:!0,defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberTitle:"W",weekNumberCalculation:"local",scrollTime:"06:00:00",minTime:"00:00:00",maxTime:"24:00:00",showNonCurrentDates:!0,lazyFetching:!0,startParam:"start",endParam:"end",timezoneParam:"timezone",timezone:!1,locale:null,isRTL:!1,buttonText:{prev:"prev",next:"next",prevYear:"prev year",nextYear:"next year",year:"year",today:"today",month:"month",week:"week",day:"day"},allDayText:"all-day",agendaEventMinHeight:0,theme:!1,dragOpacity:.75,dragRevertDuration:500,dragScroll:!0,unselectAuto:!0,dropAccept:"*",eventOrder:"title",eventLimit:!1,eventLimitText:"more",eventLimitClick:"popover",dayPopoverFormat:"LL",handleWindowResize:!0,windowResizeDelay:100,longPressDelay:1e3},e.englishDefaults={dayPopoverFormat:"dddd, MMMM D"},e.rtlDefaults={header:{left:"next,prev today",center:"",right:"title"},buttonIcons:{prev:"right-single-arrow",next:"left-single-arrow",prevYear:"right-double-arrow",nextYear:"left-double-arrow"},themeButtonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w",nextYear:"seek-prev",prevYear:"seek-next"}};var o=["header","footer","buttonText","buttonIcons","themeButtonIcons"];e.mergeOptions=i},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=function(){function t(){}return t.extend=function(t){var e=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(this);return r.copyOwnProps(t,e.prototype),e},t.mixin=function(t){r.copyOwnProps(t,this.prototype)},t}();e.default=o},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(208),o=function(){function t(t){this.source=t,this.className=[],this.miscProps={}}return t.parse=function(t,e){var n=new this(e);return!!n.applyProps(t)&&n},t.normalizeId=function(t){return String(t)},t.generateId=function(){return"_fc"+t.uuid++},t.prototype.clone=function(){var e=new this.constructor(this.source);return e.id=this.id,e.rawId=this.rawId,e.uid=this.uid,t.copyVerbatimStandardProps(this,e),e.className=this.className.slice(),e.miscProps=i.extend({},this.miscProps),e},t.prototype.hasInverseRendering=function(){return"inverse-background"===this.getRendering()},t.prototype.hasBgRendering=function(){var t=this.getRendering();return"inverse-background"===t||"background"===t},t.prototype.getRendering=function(){return null!=this.rendering?this.rendering:this.source.rendering},t.prototype.getConstraint=function(){return null!=this.constraint?this.constraint:null!=this.source.constraint?this.source.constraint:this.source.calendar.opt("eventConstraint")},t.prototype.getOverlap=function(){return null!=this.overlap?this.overlap:null!=this.source.overlap?this.source.overlap:this.source.calendar.opt("eventOverlap")},t.prototype.isStartExplicitlyEditable=function(){return null!=this.startEditable?this.startEditable:this.source.startEditable},t.prototype.isDurationExplicitlyEditable=function(){return null!=this.durationEditable?this.durationEditable:this.source.durationEditable},t.prototype.isExplicitlyEditable=function(){return null!=this.editable?this.editable:this.source.editable},t.prototype.toLegacy=function(){var e=i.extend({},this.miscProps);return e._id=this.uid,e.source=this.source,e.className=this.className.slice(),e.allDay=this.isAllDay(),null!=this.rawId&&(e.id=this.rawId),t.copyVerbatimStandardProps(this,e),e},t.prototype.applyManualStandardProps=function(e){return null!=e.id?this.id=t.normalizeId(this.rawId=e.id):this.id=t.generateId(),null!=e._id?this.uid=String(e._id):this.uid=t.generateId(),i.isArray(e.className)&&(this.className=e.className),"string"==typeof e.className&&(this.className=e.className.split(/\s+/)),!0},t.prototype.applyMiscProps=function(t){i.extend(this.miscProps,t)},t.uuid=0,t.defineStandardProps=r.default.defineStandardProps,t.copyVerbatimStandardProps=r.default.copyVerbatimStandardProps,t}();e.default=o,r.default.mixInto(o),o.defineStandardProps({_id:!1,id:!1,className:!1,source:!1,title:!0,url:!0,rendering:!0,constraint:!0,overlap:!0,editable:!0,startEditable:!0,durationEditable:!0,color:!0,backgroundColor:!0,borderColor:!0,textColor:!0})},function(t,e,n){function i(t,e){var n,i=[];for(n=0;n<t.length;n++)i.push.apply(i,t[n].buildInstances(e));return i}function r(t){return new l.default(t.dateProfile.unzonedRange,t.def,t)}function o(t){return new u.default(new d.default(t.unzonedRange,t.eventDef.isAllDay()),t.eventDef,t.eventInstance)}function s(t){return t.dateProfile.unzonedRange}function a(t){return t.componentFootprint}Object.defineProperty(e,"__esModule",{value:!0});var l=n(211),u=n(36),d=n(12);e.eventDefsToEventInstances=i,e.eventInstanceToEventRange=r,e.eventRangeToEventFootprint=o,e.eventInstanceToUnzonedRange=s,e.eventFootprintToComponentFootprint=a},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e,n){this.componentFootprint=t,this.eventDef=e,n&&(this.eventInstance=n)}return t.prototype.getEventLegacy=function(){return(this.eventInstance||this.eventDef).toLegacy()},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(4),r=n(17),o=n(34),s=n(50),a=n(13),l=function(){function t(){}return t.createFromRawProps=function(e,n,a){var l,u,d,c,p=e.def,h={},f={},g={},v={},y=null,m=null;for(l in n)r.default.isStandardProp(l)?h[l]=n[l]:p.isStandardProp(l)?f[l]=n[l]:p.miscProps[l]!==n[l]&&(g[l]=n[l]);return u=r.default.parse(h,p.source),u&&(d=s.default.createFromDiff(e.dateProfile,u,a)),f.id!==p.id&&(y=f.id),i.isArraysEqual(f.className,p.className)||(m=f.className),o.default.copyVerbatimStandardProps(f,v),c=new t,c.eventDefId=y,c.className=m,c.verbatimStandardProps=v,c.miscProps=g,d&&(c.dateMutation=d),c},t.prototype.mutateSingle=function(t){var e;return this.dateMutation&&(e=t.dateProfile,t.dateProfile=this.dateMutation.buildNewDateProfile(e,t.source.calendar)),null!=this.eventDefId&&(t.id=o.default.normalizeId(t.rawId=this.eventDefId)),this.className&&(t.className=this.className),this.verbatimStandardProps&&a.default.copyVerbatimStandardProps(this.verbatimStandardProps,t),this.miscProps&&t.applyMiscProps(this.miscProps),e?function(){t.dateProfile=e}:function(){}},t.prototype.setDateMutation=function(t){t&&!t.isEmpty()?this.dateMutation=t:this.dateMutation=null},t.prototype.isEmpty=function(){return!this.dateMutation},t}();e.default=l},function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.default={sourceClasses:[],registerClass:function(t){this.sourceClasses.unshift(t)},parse:function(t,e){var n,i,r=this.sourceClasses;for(n=0;n<r.length;n++)if(i=r[n].parse(t,e))return i}}},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(33),a=function(t){function e(e){var n=t.call(this)||this;return e=e||{},n.overflowX=e.overflowX||e.overflow||"auto",n.overflowY=e.overflowY||e.overflow||"auto",n}return i.__extends(e,t),e.prototype.render=function(){this.el=this.renderEl(),this.applyOverflow()},e.prototype.renderEl=function(){return this.scrollEl=r('<div class="fc-scroller"></div>')},e.prototype.clear=function(){this.setHeight("auto"),this.applyOverflow()},e.prototype.destroy=function(){this.el.remove()},e.prototype.applyOverflow=function(){this.scrollEl.css({"overflow-x":this.overflowX,"overflow-y":this.overflowY})},e.prototype.lockOverflow=function(t){var e=this.overflowX,n=this.overflowY;t=t||this.getScrollbarWidths(),"auto"===e&&(e=t.top||t.bottom||this.scrollEl[0].scrollWidth-1>this.scrollEl[0].clientWidth?"scroll":"hidden"),"auto"===n&&(n=t.left||t.right||this.scrollEl[0].scrollHeight-1>this.scrollEl[0].clientHeight?"scroll":"hidden"),this.scrollEl.css({"overflow-x":e,"overflow-y":n})},e.prototype.setHeight=function(t){this.scrollEl.height(t)},e.prototype.getScrollTop=function(){return this.scrollEl.scrollTop()},e.prototype.setScrollTop=function(t){this.scrollEl.scrollTop(t)},e.prototype.getClientWidth=function(){return this.scrollEl[0].clientWidth},e.prototype.getClientHeight=function(){return this.scrollEl[0].clientHeight},e.prototype.getScrollbarWidths=function(){return o.getScrollbarWidths(this.scrollEl)},e}(s.default);e.default=a},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(219),a=n(21),l=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.segSelector=".fc-event-container > *",i.dateSelectingClass&&(i.dateClicking=new i.dateClickingClass(i)),i.dateSelectingClass&&(i.dateSelecting=new i.dateSelectingClass(i)),i.eventPointingClass&&(i.eventPointing=new i.eventPointingClass(i)),i.eventDraggingClass&&i.eventPointing&&(i.eventDragging=new i.eventDraggingClass(i,i.eventPointing)),i.eventResizingClass&&i.eventPointing&&(i.eventResizing=new i.eventResizingClass(i,i.eventPointing)),i.externalDroppingClass&&(i.externalDropping=new i.externalDroppingClass(i)),i}return i.__extends(e,t),e.prototype.setElement=function(e){t.prototype.setElement.call(this,e),this.dateClicking&&this.dateClicking.bindToEl(e),this.dateSelecting&&this.dateSelecting.bindToEl(e),this.bindAllSegHandlersToEl(e)},e.prototype.removeElement=function(){this.endInteractions(),t.prototype.removeElement.call(this)},e.prototype.executeEventUnrender=function(){this.endInteractions(),t.prototype.executeEventUnrender.call(this)},e.prototype.bindGlobalHandlers=function(){t.prototype.bindGlobalHandlers.call(this),this.externalDropping&&this.externalDropping.bindToDocument()},e.prototype.unbindGlobalHandlers=function(){t.prototype.unbindGlobalHandlers.call(this),this.externalDropping&&this.externalDropping.unbindFromDocument()},e.prototype.bindDateHandlerToEl=function(t,e,n){var i=this;this.el.on(e,function(t){if(!r(t.target).is(i.segSelector+":not(.fc-helper),"+i.segSelector+":not(.fc-helper) *,.fc-more,a[data-goto]"))return n.call(i,t)})},e.prototype.bindAllSegHandlersToEl=function(t){[this.eventPointing,this.eventDragging,this.eventResizing].forEach(function(e){e&&e.bindToEl(t)})},e.prototype.bindSegHandlerToEl=function(t,e,n){var i=this;t.on(e,this.segSelector,function(t){var e=r(t.currentTarget);if(!e.is(".fc-helper")){var o=e.data("fc-seg");if(o&&!i.shouldIgnoreEventPointing())return n.call(i,o,t)}})},e.prototype.shouldIgnoreMouse=function(){return a.default.get().shouldIgnoreMouse()},e.prototype.shouldIgnoreTouch=function(){var t=this._getView();return t.isSelected||t.selectedEvent},e.prototype.shouldIgnoreEventPointing=function(){return this.eventDragging&&this.eventDragging.isDragging||this.eventResizing&&this.eventResizing.isResizing},e.prototype.canStartSelection=function(t,e){return o.getEvIsTouch(e)&&!this.canStartResize(t,e)&&(this.isEventDefDraggable(t.footprint.eventDef)||this.isEventDefResizable(t.footprint.eventDef))},e.prototype.canStartDrag=function(t,e){return!this.canStartResize(t,e)&&this.isEventDefDraggable(t.footprint.eventDef)},e.prototype.canStartResize=function(t,e){var n=this._getView(),i=t.footprint.eventDef;return(!o.getEvIsTouch(e)||n.isEventDefSelected(i))&&this.isEventDefResizable(i)&&r(e.target).is(".fc-resizer")},e.prototype.endInteractions=function(){[this.dateClicking,this.dateSelecting,this.eventPointing,this.eventDragging,this.eventResizing].forEach(function(t){t&&t.end()})},e.prototype.isEventDefDraggable=function(t){return this.isEventDefStartEditable(t)},e.prototype.isEventDefStartEditable=function(t){var e=t.isStartExplicitlyEditable();return null==e&&null==(e=this.opt("eventStartEditable"))&&(e=this.isEventDefGenerallyEditable(t)),e},e.prototype.isEventDefGenerallyEditable=function(t){var e=t.isExplicitlyEditable();return null==e&&(e=this.opt("editable")),e},e.prototype.isEventDefResizableFromStart=function(t){return this.opt("eventResizableFromStart")&&this.isEventDefResizable(t)},e.prototype.isEventDefResizableFromEnd=function(t){return this.isEventDefResizable(t)},e.prototype.isEventDefResizable=function(t){var e=t.isDurationExplicitlyEditable();return null==e&&null==(e=this.opt("eventDurationEditable"))&&(e=this.isEventDefGenerallyEditable(t)),e},e.prototype.diffDates=function(t,e){return this.largeUnit?o.diffByUnit(t,e,this.largeUnit):o.diffDayTime(t,e)},e.prototype.isEventInstanceGroupAllowed=function(t){var e,n=this._getView(),i=this.dateProfile,r=this.eventRangesToEventFootprints(t.getAllEventRanges());for(e=0;e<r.length;e++)if(!i.validUnzonedRange.containsRange(r[e].componentFootprint.unzonedRange))return!1;return n.calendar.constraints.isEventInstanceGroupAllowed(t)},e.prototype.isExternalInstanceGroupAllowed=function(t){var e,n=this._getView(),i=this.dateProfile,r=this.eventRangesToEventFootprints(t.getAllEventRanges());for(e=0;e<r.length;e++)if(!i.validUnzonedRange.containsRange(r[e].componentFootprint.unzonedRange))return!1;for(e=0;e<r.length;e++)if(!n.calendar.constraints.isSelectionFootprintAllowed(r[e].componentFootprint))return!1;return!0},e}(s.default);e.default=l},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(0),s=n(4),a=n(218),l=n(221),u=n(40),d=n(21),c=n(5),p=function(t){function e(e,n){var i=t.call(this,null,n.options)||this;return i.batchRenderDepth=0,i.isSelected=!1,i.calendar=e,i.viewSpec=n,i.type=n.type,i.name=i.type,i.initRenderQueue(),i.initHiddenDays(),i.dateProfileGenerator=new i.dateProfileGeneratorClass(i),i.bindBaseRenderHandlers(),i.eventOrderSpecs=s.parseFieldSpecs(i.opt("eventOrder")),i.initialize&&i.initialize(),i}return i.__extends(e,t),e.prototype._getView=function(){return this},e.prototype.opt=function(t){return this.options[t]},e.prototype.initRenderQueue=function(){this.renderQueue=new a.default({event:this.opt("eventRenderWait")}),this.renderQueue.on("start",this.onRenderQueueStart.bind(this)),this.renderQueue.on("stop",this.onRenderQueueStop.bind(this)),this.on("before:change",this.startBatchRender),this.on("change",this.stopBatchRender)},e.prototype.onRenderQueueStart=function(){this.calendar.freezeContentHeight(),this.addScroll(this.queryScroll())},e.prototype.onRenderQueueStop=function(){this.calendar.updateViewSize()&&this.popScroll(),this.calendar.thawContentHeight()},e.prototype.startBatchRender=function(){this.batchRenderDepth++||this.renderQueue.pause()},e.prototype.stopBatchRender=function(){--this.batchRenderDepth||this.renderQueue.resume()},e.prototype.requestRender=function(t,e,n){this.renderQueue.queue(t,e,n)},e.prototype.whenSizeUpdated=function(t){this.renderQueue.isRunning?this.renderQueue.one("stop",t.bind(this)):t.call(this)},e.prototype.computeTitle=function(t){var e;return e=/^(year|month)$/.test(t.currentRangeUnit)?t.currentUnzonedRange:t.activeUnzonedRange,this.formatRange({start:this.calendar.msToMoment(e.startMs,t.isRangeAllDay),end:this.calendar.msToMoment(e.endMs,t.isRangeAllDay)},t.isRangeAllDay,this.opt("titleFormat")||this.computeTitleFormat(t),this.opt("titleRangeSeparator"))},e.prototype.computeTitleFormat=function(t){var e=t.currentRangeUnit;return"year"===e?"YYYY":"month"===e?this.opt("monthYearFormat"):t.currentUnzonedRange.as("days")>1?"ll":"LL"},e.prototype.setDate=function(t){var e=this.get("dateProfile"),n=this.dateProfileGenerator.build(t,void 0,!0);e&&e.activeUnzonedRange.equals(n.activeUnzonedRange)||this.set("dateProfile",n)},e.prototype.unsetDate=function(){this.unset("dateProfile")},e.prototype.fetchInitialEvents=function(t){var e=this.calendar,n=t.isRangeAllDay&&!this.usesMinMaxTime;return e.requestEvents(e.msToMoment(t.activeUnzonedRange.startMs,n),e.msToMoment(t.activeUnzonedRange.endMs,n))},e.prototype.bindEventChanges=function(){this.listenTo(this.calendar,"eventsReset",this.resetEvents)},e.prototype.unbindEventChanges=function(){this.stopListeningTo(this.calendar,"eventsReset")},e.prototype.setEvents=function(t){this.set("currentEvents",t),this.set("hasEvents",!0)},e.prototype.unsetEvents=function(){this.unset("currentEvents"),this.unset("hasEvents")},e.prototype.resetEvents=function(t){this.startBatchRender(),this.unsetEvents(),this.setEvents(t),this.stopBatchRender()},e.prototype.requestDateRender=function(t){var e=this;this.requestRender(function(){e.executeDateRender(t)},"date","init")},e.prototype.requestDateUnrender=function(){var t=this;this.requestRender(function(){t.executeDateUnrender()},"date","destroy")},e.prototype.executeDateRender=function(e){t.prototype.executeDateRender.call(this,e),this.render&&this.render(),this.trigger("datesRendered"),this.addScroll({isDateInit:!0}),this.startNowIndicator()},e.prototype.executeDateUnrender=function(){this.unselect(),this.stopNowIndicator(),this.trigger("before:datesUnrendered"),this.destroy&&this.destroy(),t.prototype.executeDateUnrender.call(this)},e.prototype.bindBaseRenderHandlers=function(){var t=this;this.on("datesRendered",function(){t.whenSizeUpdated(t.triggerViewRender)}),this.on("before:datesUnrendered",function(){t.triggerViewDestroy()})},e.prototype.triggerViewRender=function(){this.publiclyTrigger("viewRender",{context:this,args:[this,this.el]})},e.prototype.triggerViewDestroy=function(){this.publiclyTrigger("viewDestroy",{context:this,args:[this,this.el]})},e.prototype.requestEventsRender=function(t){var e=this;this.requestRender(function(){e.executeEventRender(t),e.whenSizeUpdated(e.triggerAfterEventsRendered)},"event","init")},e.prototype.requestEventsUnrender=function(){var t=this;this.requestRender(function(){t.triggerBeforeEventsDestroyed(),t.executeEventUnrender()},"event","destroy")},e.prototype.requestBusinessHoursRender=function(t){var e=this;this.requestRender(function(){e.renderBusinessHours(t)},"businessHours","init")},e.prototype.requestBusinessHoursUnrender=function(){var t=this;this.requestRender(function(){t.unrenderBusinessHours()},"businessHours","destroy")},e.prototype.bindGlobalHandlers=function(){t.prototype.bindGlobalHandlers.call(this),this.listenTo(d.default.get(),{touchstart:this.processUnselect,mousedown:this.handleDocumentMousedown})},e.prototype.unbindGlobalHandlers=function(){t.prototype.unbindGlobalHandlers.call(this),this.stopListeningTo(d.default.get())},e.prototype.startNowIndicator=function(){var t,e,n,i=this;this.opt("nowIndicator")&&(t=this.getNowIndicatorUnit())&&(e=s.proxy(this,"updateNowIndicator"),this.initialNowDate=this.calendar.getNow(),this.initialNowQueriedMs=(new Date).valueOf(),n=this.initialNowDate.clone().startOf(t).add(1,t).valueOf()-this.initialNowDate.valueOf(),this.nowIndicatorTimeoutID=setTimeout(function(){i.nowIndicatorTimeoutID=null,e(),n=+o.duration(1,t),n=Math.max(100,n),i.nowIndicatorIntervalID=setInterval(e,n)},n))},e.prototype.updateNowIndicator=function(){this.isDatesRendered&&this.initialNowDate&&(this.unrenderNowIndicator(),this.renderNowIndicator(this.initialNowDate.clone().add((new Date).valueOf()-this.initialNowQueriedMs)),this.isNowIndicatorRendered=!0)},e.prototype.stopNowIndicator=function(){this.isNowIndicatorRendered&&(this.nowIndicatorTimeoutID&&(clearTimeout(this.nowIndicatorTimeoutID),this.nowIndicatorTimeoutID=null),this.nowIndicatorIntervalID&&(clearInterval(this.nowIndicatorIntervalID),this.nowIndicatorIntervalID=null),this.unrenderNowIndicator(),this.isNowIndicatorRendered=!1)},e.prototype.updateSize=function(e,n,i){this.setHeight?this.setHeight(e,n):t.prototype.updateSize.call(this,e,n,i),this.updateNowIndicator()},e.prototype.addScroll=function(t){var e=this.queuedScroll||(this.queuedScroll={});r.extend(e,t)},e.prototype.popScroll=function(){this.applyQueuedScroll(),this.queuedScroll=null},e.prototype.applyQueuedScroll=function(){this.queuedScroll&&this.applyScroll(this.queuedScroll)},e.prototype.queryScroll=function(){var t={};return this.isDatesRendered&&r.extend(t,this.queryDateScroll()),t},e.prototype.applyScroll=function(t){t.isDateInit&&this.isDatesRendered&&r.extend(t,this.computeInitialDateScroll()),this.isDatesRendered&&this.applyDateScroll(t)},e.prototype.computeInitialDateScroll=function(){return{}},e.prototype.queryDateScroll=function(){return{}},e.prototype.applyDateScroll=function(t){},e.prototype.reportEventDrop=function(t,e,n,i){var r=this.calendar.eventManager,s=r.mutateEventsWithId(t.def.id,e),a=e.dateMutation;a&&(t.dateProfile=a.buildNewDateProfile(t.dateProfile,this.calendar)),this.triggerEventDrop(t,a&&a.dateDelta||o.duration(),s,n,i)},e.prototype.triggerEventDrop=function(t,e,n,i,r){this.publiclyTrigger("eventDrop",{context:i[0],args:[t.toLegacy(),e,n,r,{},this]})},e.prototype.reportExternalDrop=function(t,e,n,i,r,o){e&&this.calendar.eventManager.addEventDef(t,n),this.triggerExternalDrop(t,e,i,r,o)},e.prototype.triggerExternalDrop=function(t,e,n,i,r){this.publiclyTrigger("drop",{context:n[0],args:[t.dateProfile.start.clone(),i,r,this]}),e&&this.publiclyTrigger("eventReceive",{context:this,args:[t.buildInstance().toLegacy(),this]})},e.prototype.reportEventResize=function(t,e,n,i){var r=this.calendar.eventManager,o=r.mutateEventsWithId(t.def.id,e);t.dateProfile=e.dateMutation.buildNewDateProfile(t.dateProfile,this.calendar),this.triggerEventResize(t,e.dateMutation.endDelta,o,n,i)},e.prototype.triggerEventResize=function(t,e,n,i,r){this.publiclyTrigger("eventResize",{context:i[0],args:[t.toLegacy(),e,n,r,{},this]})},e.prototype.select=function(t,e){this.unselect(e),this.renderSelectionFootprint(t),this.reportSelection(t,e)},e.prototype.renderSelectionFootprint=function(e){this.renderSelection?this.renderSelection(e.toLegacy(this.calendar)):t.prototype.renderSelectionFootprint.call(this,e)},e.prototype.reportSelection=function(t,e){this.isSelected=!0,this.triggerSelect(t,e)},e.prototype.triggerSelect=function(t,e){var n=this.calendar.footprintToDateProfile(t);this.publiclyTrigger("select",{context:this,args:[n.start,n.end,e,this]})},e.prototype.unselect=function(t){this.isSelected&&(this.isSelected=!1,this.destroySelection&&this.destroySelection(),this.unrenderSelection(),this.publiclyTrigger("unselect",{context:this,args:[t,this]}))},e.prototype.selectEventInstance=function(t){this.selectedEventInstance&&this.selectedEventInstance===t||(this.unselectEventInstance(),this.getEventSegs().forEach(function(e){e.footprint.eventInstance===t&&e.el&&e.el.addClass("fc-selected")}),this.selectedEventInstance=t)},e.prototype.unselectEventInstance=function(){this.selectedEventInstance&&(this.getEventSegs().forEach(function(t){t.el&&t.el.removeClass("fc-selected")}),this.selectedEventInstance=null)},e.prototype.isEventDefSelected=function(t){return this.selectedEventInstance&&this.selectedEventInstance.def.id===t.id},e.prototype.handleDocumentMousedown=function(t){s.isPrimaryMouseButton(t)&&this.processUnselect(t)},e.prototype.processUnselect=function(t){this.processRangeUnselect(t),this.processEventUnselect(t)},e.prototype.processRangeUnselect=function(t){var e;this.isSelected&&this.opt("unselectAuto")&&((e=this.opt("unselectCancel"))&&r(t.target).closest(e).length||this.unselect(t))},e.prototype.processEventUnselect=function(t){this.selectedEventInstance&&(r(t.target).closest(".fc-selected").length||this.unselectEventInstance())},e.prototype.triggerBaseRendered=function(){this.publiclyTrigger("viewRender",{context:this,args:[this,this.el]})},e.prototype.triggerBaseUnrendered=function(){this.publiclyTrigger("viewDestroy",{context:this,args:[this,this.el]})},e.prototype.triggerDayClick=function(t,e,n){var i=this.calendar.footprintToDateProfile(t);this.publiclyTrigger("dayClick",{context:e,args:[i.start,n,this]})},e.prototype.isDateInOtherMonth=function(t,e){return!1},e.prototype.getUnzonedRangeOption=function(t){var e=this.opt(t);if("function"==typeof e&&(e=e.apply(null,Array.prototype.slice.call(arguments,1))),e)return this.calendar.parseUnzonedRange(e)},e.prototype.initHiddenDays=function(){var t,e=this.opt("hiddenDays")||[],n=[],i=0;for(!1===this.opt("weekends")&&e.push(0,6),t=0;t<7;t++)(n[t]=-1!==r.inArray(t,e))||i++;if(!i)throw new Error("invalid hiddenDays");this.isHiddenDayHash=n},e.prototype.trimHiddenDays=function(t){var e=t.getStart(),n=t.getEnd();return e&&(e=this.skipHiddenDays(e)),n&&(n=this.skipHiddenDays(n,-1,!0)),null===e||null===n||e<n?new c.default(e,n):null},e.prototype.isHiddenDay=function(t){return o.isMoment(t)&&(t=t.day()),this.isHiddenDayHash[t]},e.prototype.skipHiddenDays=function(t,e,n){void 0===e&&(e=1),void 0===n&&(n=!1);for(var i=t.clone();this.isHiddenDayHash[(i.day()+(n?e:0)+7)%7];)i.add(e,"days");return i},e}(u.default);e.default=p,p.prototype.usesMinMaxTime=!1,p.prototype.dateProfileGeneratorClass=l.default,p.watch("displayingDates",["isInDom","dateProfile"],function(t){this.requestDateRender(t.dateProfile)},function(){this.requestDateUnrender()}),p.watch("displayingBusinessHours",["displayingDates","businessHourGenerator"],function(t){this.requestBusinessHoursRender(t.businessHourGenerator)},function(){this.requestBusinessHoursUnrender()}),p.watch("initialEvents",["dateProfile"],function(t){return this.fetchInitialEvents(t.dateProfile)}),p.watch("bindingEvents",["initialEvents"],function(t){this.setEvents(t.initialEvents),this.bindEventChanges()},function(){this.unbindEventChanges(),this.unsetEvents()}),p.watch("displayingEvents",["displayingDates","hasEvents"],function(){this.requestEventsRender(this.get("currentEvents"))},function(){this.requestEventsUnrender()}),p.watch("title",["dateProfile"],function(t){return this.title=this.computeTitle(t.dateProfile)}),p.watch("legacyDateProps",["dateProfile"],function(t){var e=this.calendar,n=t.dateProfile;this.start=e.msToMoment(n.activeUnzonedRange.startMs,n.isRangeAllDay),this.end=e.msToMoment(n.activeUnzonedRange.endMs,n.isRangeAllDay),this.intervalStart=e.msToMoment(n.currentUnzonedRange.startMs,n.isRangeAllDay),this.intervalEnd=e.msToMoment(n.currentUnzonedRange.endMs,n.isRangeAllDay)})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=function(){function t(t,e){this.view=t._getView(),this.component=t,this.fillRenderer=e}return t.prototype.opt=function(t){return this.view.opt(t)},t.prototype.rangeUpdated=function(){var t,e;this.eventTimeFormat=this.opt("eventTimeFormat")||this.opt("timeFormat")||this.computeEventTimeFormat(),t=this.opt("displayEventTime"),null==t&&(t=this.computeDisplayEventTime()),e=this.opt("displayEventEnd"),null==e&&(e=this.computeDisplayEventEnd()),this.displayEventTime=t,this.displayEventEnd=e},t.prototype.render=function(t){var e,n,i,r=this.component._getDateProfile(),o=[],s=[];for(e in t)n=t[e],i=n.sliceRenderRanges(r.activeUnzonedRange),n.getEventDef().hasBgRendering()?o.push.apply(o,i):s.push.apply(s,i);this.renderBgRanges(o),this.renderFgRanges(s)},t.prototype.unrender=function(){this.unrenderBgRanges(),this.unrenderFgRanges()},t.prototype.renderFgRanges=function(t){var e=this.component.eventRangesToEventFootprints(t),n=this.component.eventFootprintsToSegs(e);n=this.renderFgSegEls(n),!1!==this.renderFgSegs(n)&&(this.fgSegs=n)},t.prototype.unrenderFgRanges=function(){this.unrenderFgSegs(this.fgSegs||[]),this.fgSegs=null},t.prototype.renderBgRanges=function(t){var e=this.component.eventRangesToEventFootprints(t),n=this.component.eventFootprintsToSegs(e);!1!==this.renderBgSegs(n)&&(this.bgSegs=n)},t.prototype.unrenderBgRanges=function(){this.unrenderBgSegs(),this.bgSegs=null},t.prototype.getSegs=function(){return(this.bgSegs||[]).concat(this.fgSegs||[])},t.prototype.renderFgSegs=function(t){return!1},t.prototype.unrenderFgSegs=function(t){},t.prototype.renderBgSegs=function(t){var e=this;if(!this.fillRenderer)return!1;this.fillRenderer.renderSegs("bgEvent",t,{getClasses:function(t){return e.getBgClasses(t.footprint.eventDef)},getCss:function(t){return{"background-color":e.getBgColor(t.footprint.eventDef)}},filterEl:function(t,n){return e.filterEventRenderEl(t.footprint,n)}})},t.prototype.unrenderBgSegs=function(){this.fillRenderer&&this.fillRenderer.unrender("bgEvent")},t.prototype.renderFgSegEls=function(t,e){var n=this;void 0===e&&(e=!1);var r,o=this.view.hasPublicHandlers("eventRender"),s="",a=[];if(t.length){for(r=0;r<t.length;r++)this.beforeFgSegHtml(t[r]),s+=this.fgSegHtml(t[r],e);i(s).each(function(e,r){var s=t[e],l=i(r);o&&(l=n.filterEventRenderEl(s.footprint,l)),l&&(l.data("fc-seg",s),s.el=l,a.push(s))})}return a},t.prototype.beforeFgSegHtml=function(t){},t.prototype.fgSegHtml=function(t,e){},t.prototype.getSegClasses=function(t,e,n){var i=["fc-event",t.isStart?"fc-start":"fc-not-start",t.isEnd?"fc-end":"fc-not-end"].concat(this.getClasses(t.footprint.eventDef));return e&&i.push("fc-draggable"),n&&i.push("fc-resizable"),this.view.isEventDefSelected(t.footprint.eventDef)&&i.push("fc-selected"),i},t.prototype.filterEventRenderEl=function(t,e){var n=t.getEventLegacy(),r=this.view.publiclyTrigger("eventRender",{context:n,args:[n,e,this.view]});return!1===r?e=null:r&&!0!==r&&(e=i(r)),e},t.prototype.getTimeText=function(t,e,n){return this._getTimeText(t.eventInstance.dateProfile.start,t.eventInstance.dateProfile.end,t.componentFootprint.isAllDay,e,n)},t.prototype._getTimeText=function(t,e,n,i,r){return null==i&&(i=this.eventTimeFormat),null==r&&(r=this.displayEventEnd),this.displayEventTime&&!n?r&&e?this.view.formatRange({start:t,end:e},!1,i):t.format(i):""},t.prototype.computeEventTimeFormat=function(){return this.opt("smallTimeFormat")},t.prototype.computeDisplayEventTime=function(){return!0},t.prototype.computeDisplayEventEnd=function(){return!0},t.prototype.getBgClasses=function(t){var e=this.getClasses(t);return e.push("fc-bgevent"),e},t.prototype.getClasses=function(t){var e,n=this.getStylingObjs(t),i=[];for(e=0;e<n.length;e++)i.push.apply(i,n[e].eventClassName||n[e].className||[]);return i},t.prototype.getSkinCss=function(t){return{"background-color":this.getBgColor(t),"border-color":this.getBorderColor(t),color:this.getTextColor(t)}},t.prototype.getBgColor=function(t){var e,n,i=this.getStylingObjs(t);for(e=0;e<i.length&&!n;e++)n=i[e].eventBackgroundColor||i[e].eventColor||i[e].backgroundColor||i[e].color;return n||(n=this.opt("eventBackgroundColor")||this.opt("eventColor")),n},t.prototype.getBorderColor=function(t){var e,n,i=this.getStylingObjs(t);for(e=0;e<i.length&&!n;e++)n=i[e].eventBorderColor||i[e].eventColor||i[e].borderColor||i[e].color;return n||(n=this.opt("eventBorderColor")||this.opt("eventColor")),n},t.prototype.getTextColor=function(t){var e,n,i=this.getStylingObjs(t);for(e=0;e<i.length&&!n;e++)n=i[e].eventTextColor||i[e].textColor;return n||(n=this.opt("eventTextColor")),n},t.prototype.getStylingObjs=function(t){var e=this.getFallbackStylingObjs(t);return e.unshift(t),e},t.prototype.getFallbackStylingObjs=function(t){return[t.source]},t.prototype.sortEventSegs=function(t){t.sort(r.proxy(this,"compareEventSegs"))},t.prototype.compareEventSegs=function(t,e){var n=t.footprint,i=e.footprint,o=n.componentFootprint,s=i.componentFootprint,a=o.unzonedRange,l=s.unzonedRange
+;return a.startMs-l.startMs||l.endMs-l.startMs-(a.endMs-a.startMs)||s.isAllDay-o.isAllDay||r.compareByFieldSpecs(n.eventDef,i.eventDef,this.view.eventOrderSpecs,n.eventDef.miscProps,i.eventDef.miscProps)},t}();e.default=o},,,,,function(t,e,n){function i(t){return"en"!==t.locale()?t.clone().locale("en"):t}function r(t,e){return h(a(e).fakeFormatString,t)}function o(t,e,n,i,r){var o;return t=y.default.parseZone(t),e=y.default.parseZone(e),o=t.localeData(),n=o.longDateFormat(n)||n,s(a(n),t,e,i||" - ",r)}function s(t,e,n,i,r){var o,s,a,l=t.sameUnits,u=e.clone().stripZone(),d=n.clone().stripZone(),c=f(t.fakeFormatString,e),p=f(t.fakeFormatString,n),h="",v="",y="",m="",b="";for(o=0;o<l.length&&(!l[o]||u.isSame(d,l[o]));o++)h+=c[o];for(s=l.length-1;s>o&&(!l[s]||u.isSame(d,l[s]))&&(s-1!==o||"."!==c[s]);s--)v=c[s]+v;for(a=o;a<=s;a++)y+=c[a],m+=p[a];return(y||m)&&(b=r?m+i+y:y+i+m),g(h+b+v)}function a(t){return C[t]||(C[t]=l(t))}function l(t){var e=u(t);return{fakeFormatString:c(e),sameUnits:p(e)}}function u(t){for(var e,n=[],i=/\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;e=i.exec(t);)e[1]?n.push.apply(n,d(e[1])):e[2]?n.push({maybe:u(e[2])}):e[3]?n.push({token:e[3]}):e[5]&&n.push.apply(n,d(e[5]));return n}function d(t){return". "===t?["."," "]:[t]}function c(t){var e,n,i=[];for(e=0;e<t.length;e++)n=t[e],"string"==typeof n?i.push("["+n+"]"):n.token?n.token in E?i.push(b+"["+n.token+"]"):i.push(n.token):n.maybe&&i.push(w+c(n.maybe)+w);return i.join(m)}function p(t){var e,n,i,r=[];for(e=0;e<t.length;e++)n=t[e],n.token?(i=S[n.token.charAt(0)],r.push(i?i.unit:"second")):n.maybe?r.push.apply(r,p(n.maybe)):r.push(null);return r}function h(t,e){return g(f(t,e).join(""))}function f(t,e){var n,i,r=[],o=y.oldMomentFormat(e,t),s=o.split(m);for(n=0;n<s.length;n++)i=s[n],i.charAt(0)===b?r.push(E[i.substring(1)](e)):r.push(i);return r}function g(t){return t.replace(D,function(t,e){return e.match(/[1-9]/)?e:""})}function v(t){var e,n,i,r,o=u(t);for(e=0;e<o.length;e++)n=o[e],n.token&&(i=S[n.token.charAt(0)])&&(!r||i.value>r.value)&&(r=i);return r?r.unit:null}Object.defineProperty(e,"__esModule",{value:!0});var y=n(10);y.newMomentProto.format=function(){return this._fullCalendar&&arguments[0]?r(this,arguments[0]):this._ambigTime?y.oldMomentFormat(i(this),"YYYY-MM-DD"):this._ambigZone?y.oldMomentFormat(i(this),"YYYY-MM-DD[T]HH:mm:ss"):this._fullCalendar?y.oldMomentFormat(i(this)):y.oldMomentProto.format.apply(this,arguments)},y.newMomentProto.toISOString=function(){return this._ambigTime?y.oldMomentFormat(i(this),"YYYY-MM-DD"):this._ambigZone?y.oldMomentFormat(i(this),"YYYY-MM-DD[T]HH:mm:ss"):this._fullCalendar?y.oldMomentProto.toISOString.apply(i(this),arguments):y.oldMomentProto.toISOString.apply(this,arguments)};var m="\v",b="",w="",D=new RegExp(w+"([^"+w+"]*)"+w,"g"),E={t:function(t){return y.oldMomentFormat(t,"a").charAt(0)},T:function(t){return y.oldMomentFormat(t,"A").charAt(0)}},S={Y:{value:1,unit:"year"},M:{value:2,unit:"month"},W:{value:3,unit:"week"},w:{value:3,unit:"week"},D:{value:4,unit:"day"},d:{value:4,unit:"day"}};e.formatDate=r,e.formatRange=o;var C={};e.queryMostGranularFormatUnit=v},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(33),o=n(11),s=n(7),a=function(t){function e(){var e=t.call(this)||this;return e._watchers={},e._props={},e.applyGlobalWatchers(),e.constructed(),e}return i.__extends(e,t),e.watch=function(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];this.prototype.hasOwnProperty("_globalWatchArgs")||(this.prototype._globalWatchArgs=Object.create(this.prototype._globalWatchArgs)),this.prototype._globalWatchArgs[t]=e},e.prototype.constructed=function(){},e.prototype.applyGlobalWatchers=function(){var t,e=this._globalWatchArgs;for(t in e)this.watch.apply(this,[t].concat(e[t]))},e.prototype.has=function(t){return t in this._props},e.prototype.get=function(t){return void 0===t?this._props:this._props[t]},e.prototype.set=function(t,e){var n;"string"==typeof t?(n={},n[t]=void 0===e?null:e):n=t,this.setProps(n)},e.prototype.reset=function(t){var e,n=this._props,i={};for(e in n)i[e]=void 0;for(e in t)i[e]=t[e];this.setProps(i)},e.prototype.unset=function(t){var e,n,i={};for(e="string"==typeof t?[t]:t,n=0;n<e.length;n++)i[e[n]]=void 0;this.setProps(i)},e.prototype.setProps=function(t){var e,n,i={},r=0;for(e in t)"object"!=typeof(n=t[e])&&n===this._props[e]||(i[e]=n,r++);if(r){this.trigger("before:batchChange",i);for(e in i)n=i[e],this.trigger("before:change",e,n),this.trigger("before:change:"+e,n);for(e in i)n=i[e],void 0===n?delete this._props[e]:this._props[e]=n,this.trigger("change:"+e,n),this.trigger("change",e,n);this.trigger("batchChange",i)}},e.prototype.watch=function(t,e,n,i){var r=this;this.unwatch(t),this._watchers[t]=this._watchDeps(e,function(e){var i=n.call(r,e);i&&i.then?(r.unset(t),i.then(function(e){r.set(t,e)})):r.set(t,i)},function(e){r.unset(t),i&&i.call(r,e)})},e.prototype.unwatch=function(t){var e=this._watchers[t];e&&(delete this._watchers[t],e.teardown())},e.prototype._watchDeps=function(t,e,n){var i=this,r=0,o=t.length,s=0,a={},l=[],u=!1,d=function(t,e,i){1===++r&&s===o&&(u=!0,n(a),u=!1)},c=function(t,n,i){void 0===n?(i||void 0===a[t]||s--,delete a[t]):(i||void 0!==a[t]||s++,a[t]=n),--r||s===o&&(u||e(a))},p=function(t,e){i.on(t,e),l.push([t,e])};return t.forEach(function(t){var e=!1;"?"===t.charAt(0)&&(t=t.substring(1),e=!0),p("before:change:"+t,function(t){d()}),p("change:"+t,function(n){c(t,n,e)})}),t.forEach(function(t){var e=!1;"?"===t.charAt(0)&&(t=t.substring(1),e=!0),i.has(t)?(a[t]=i.get(t),s++):e&&s++}),s===o&&e(a),{teardown:function(){for(var t=0;t<l.length;t++)i.off(l[t][0],l[t][1]);l=null,s===o&&n()},flash:function(){s===o&&(n(),e(a))}}},e.prototype.flash=function(t){var e=this._watchers[t];e&&e.flash()},e}(r.default);e.default=a,a.prototype._globalWatchArgs={},o.default.mixInto(a),s.default.mixInto(a)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(0),r=n(4),o=n(13),s=n(210);e.default={parse:function(t,e){return r.isTimeString(t.start)||i.isDuration(t.start)||r.isTimeString(t.end)||i.isDuration(t.end)?s.default.parse(t,e):o.default.parse(t,e)}}},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(4),r=n(17),o=function(){function t(){this.clearEnd=!1,this.forceTimed=!1,this.forceAllDay=!1}return t.createFromDiff=function(e,n,r){function o(t,e){return r?i.diffByUnit(t,e,r):n.isAllDay()?i.diffDay(t,e):i.diffDayTime(t,e)}var s,a,l,u,d=e.end&&!n.end,c=e.isAllDay()&&!n.isAllDay(),p=!e.isAllDay()&&n.isAllDay();return s=o(n.start,e.start),n.end&&(a=o(n.unzonedRange.getEnd(),e.unzonedRange.getEnd()),l=a.subtract(s)),u=new t,u.clearEnd=d,u.forceTimed=c,u.forceAllDay=p,u.setDateDelta(s),u.setEndDelta(l),u},t.prototype.buildNewDateProfile=function(t,e){var n=t.start.clone(),i=null,o=!1;return t.end&&!this.clearEnd?i=t.end.clone():this.endDelta&&!i&&(i=e.getDefaultEventEnd(t.isAllDay(),n)),this.forceTimed?(o=!0,n.hasTime()||n.time(0),i&&!i.hasTime()&&i.time(0)):this.forceAllDay&&(n.hasTime()&&n.stripTime(),i&&i.hasTime()&&i.stripTime()),this.dateDelta&&(o=!0,n.add(this.dateDelta),i&&i.add(this.dateDelta)),this.endDelta&&(o=!0,i.add(this.endDelta)),this.startDelta&&(o=!0,n.add(this.startDelta)),o&&(n=e.applyTimezone(n),i&&(i=e.applyTimezone(i))),!i&&e.opt("forceEventDuration")&&(i=e.getDefaultEventEnd(t.isAllDay(),n)),new r.default(n,i,e)},t.prototype.setDateDelta=function(t){t&&t.valueOf()?this.dateDelta=t:this.dateDelta=null},t.prototype.setStartDelta=function(t){t&&t.valueOf()?this.startDelta=t:this.startDelta=null},t.prototype.setEndDelta=function(t){t&&t.valueOf()?this.endDelta=t:this.endDelta=null},t.prototype.isEmpty=function(){return!(this.clearEnd||this.forceTimed||this.forceAllDay||this.dateDelta||this.startDelta||this.endDelta)},t}();e.default=o},function(t,e,n){function i(t,e){a[t]=e}function r(t){return t?!0===t?s.default:a[t]:o.default}Object.defineProperty(e,"__esModule",{value:!0});var o=n(213),s=n(214),a={};e.defineThemeSystem=i,e.getThemeSystemClass=r},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(20),a=n(6),l=n(13),u=function(t){function e(e){var n=t.call(this,e)||this;return n.eventDefs=[],n}return i.__extends(e,t),e.parse=function(t,e){var n;return r.isArray(t.events)?n=t:r.isArray(t)&&(n={events:t}),!!n&&a.default.parse.call(this,n,e)},e.prototype.setRawEventDefs=function(t){this.rawEventDefs=t,this.eventDefs=this.parseEventDefs(t)},e.prototype.fetch=function(t,e,n){var i,r=this.eventDefs;if(null!=this.currentTimezone&&this.currentTimezone!==n)for(i=0;i<r.length;i++)r[i]instanceof l.default&&r[i].rezone();return this.currentTimezone=n,s.default.resolve(r)},e.prototype.addEventDef=function(t){this.eventDefs.push(t)},e.prototype.removeEventDefsById=function(t){return o.removeMatching(this.eventDefs,function(e){return e.id===t})},e.prototype.removeAllEventDefs=function(){this.eventDefs=[]},e.prototype.getPrimitive=function(){return this.rawEventDefs},e.prototype.applyManualStandardProps=function(e){var n=t.prototype.applyManualStandardProps.call(this,e);return this.setRawEventDefs(e.events),n},e}(a.default);e.default=u,u.defineStandardProps({events:!1})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=function(){function t(t){this.isHorizontal=!1,this.isVertical=!1,this.els=i(t.els),this.isHorizontal=t.isHorizontal,this.isVertical=t.isVertical,this.forcedOffsetParentEl=t.offsetParent?i(t.offsetParent):null}return t.prototype.build=function(){var t=this.forcedOffsetParentEl;!t&&this.els.length>0&&(t=this.els.eq(0).offsetParent()),this.origin=t?t.offset():null,this.boundingRect=this.queryBoundingRect(),this.isHorizontal&&this.buildElHorizontals(),this.isVertical&&this.buildElVerticals()},t.prototype.clear=function(){this.origin=null,this.boundingRect=null,this.lefts=null,this.rights=null,this.tops=null,this.bottoms=null},t.prototype.ensureBuilt=function(){this.origin||this.build()},t.prototype.buildElHorizontals=function(){var t=[],e=[];this.els.each(function(n,r){var o=i(r),s=o.offset().left,a=o.outerWidth();t.push(s),e.push(s+a)}),this.lefts=t,this.rights=e},t.prototype.buildElVerticals=function(){var t=[],e=[];this.els.each(function(n,r){var o=i(r),s=o.offset().top,a=o.outerHeight();t.push(s),e.push(s+a)}),this.tops=t,this.bottoms=e},t.prototype.getHorizontalIndex=function(t){this.ensureBuilt();var e,n=this.lefts,i=this.rights,r=n.length;for(e=0;e<r;e++)if(t>=n[e]&&t<i[e])return e},t.prototype.getVerticalIndex=function(t){this.ensureBuilt();var e,n=this.tops,i=this.bottoms,r=n.length;for(e=0;e<r;e++)if(t>=n[e]&&t<i[e])return e},t.prototype.getLeftOffset=function(t){return this.ensureBuilt(),this.lefts[t]},t.prototype.getLeftPosition=function(t){return this.ensureBuilt(),this.lefts[t]-this.origin.left},t.prototype.getRightOffset=function(t){return this.ensureBuilt(),this.rights[t]},t.prototype.getRightPosition=function(t){return this.ensureBuilt(),this.rights[t]-this.origin.left},t.prototype.getWidth=function(t){return this.ensureBuilt(),this.rights[t]-this.lefts[t]},t.prototype.getTopOffset=function(t){return this.ensureBuilt(),this.tops[t]},t.prototype.getTopPosition=function(t){return this.ensureBuilt(),this.tops[t]-this.origin.top},t.prototype.getBottomOffset=function(t){return this.ensureBuilt(),this.bottoms[t]},t.prototype.getBottomPosition=function(t){return this.ensureBuilt(),this.bottoms[t]-this.origin.top},t.prototype.getHeight=function(t){return this.ensureBuilt(),this.bottoms[t]-this.tops[t]},t.prototype.queryBoundingRect=function(){var t;return this.els.length>0&&(t=r.getScrollParent(this.els.eq(0)),!t.is(document))?r.getClientRect(t):null},t.prototype.isPointInBounds=function(t,e){return this.isLeftInBounds(t)&&this.isTopInBounds(e)},t.prototype.isLeftInBounds=function(t){return!this.boundingRect||t>=this.boundingRect.left&&t<this.boundingRect.right},t.prototype.isTopInBounds=function(t){return!this.boundingRect||t>=this.boundingRect.top&&t<this.boundingRect.bottom},t}();e.default=o},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=n(7),s=n(21),a=function(){function t(t){this.isInteracting=!1,this.isDistanceSurpassed=!1,this.isDelayEnded=!1,this.isDragging=!1,this.isTouch=!1,this.isGeneric=!1,this.shouldCancelTouchScroll=!0,this.scrollAlwaysKills=!1,this.isAutoScroll=!1,this.scrollSensitivity=30,this.scrollSpeed=200,this.scrollIntervalMs=50,this.options=t||{}}return t.prototype.startInteraction=function(t,e){if(void 0===e&&(e={}),"mousedown"===t.type){if(s.default.get().shouldIgnoreMouse())return;if(!r.isPrimaryMouseButton(t))return;t.preventDefault()}this.isInteracting||(this.delay=r.firstDefined(e.delay,this.options.delay,0),this.minDistance=r.firstDefined(e.distance,this.options.distance,0),this.subjectEl=this.options.subjectEl,r.preventSelection(i("body")),this.isInteracting=!0,this.isTouch=r.getEvIsTouch(t),this.isGeneric="dragstart"===t.type,this.isDelayEnded=!1,this.isDistanceSurpassed=!1,this.originX=r.getEvX(t),this.originY=r.getEvY(t),this.scrollEl=r.getScrollParent(i(t.target)),this.bindHandlers(),this.initAutoScroll(),this.handleInteractionStart(t),this.startDelay(t),this.minDistance||this.handleDistanceSurpassed(t))},t.prototype.handleInteractionStart=function(t){this.trigger("interactionStart",t)},t.prototype.endInteraction=function(t,e){this.isInteracting&&(this.endDrag(t),this.delayTimeoutId&&(clearTimeout(this.delayTimeoutId),this.delayTimeoutId=null),this.destroyAutoScroll(),this.unbindHandlers(),this.isInteracting=!1,this.handleInteractionEnd(t,e),r.allowSelection(i("body")))},t.prototype.handleInteractionEnd=function(t,e){this.trigger("interactionEnd",t,e||!1)},t.prototype.bindHandlers=function(){var t=s.default.get();this.isGeneric?this.listenTo(i(document),{drag:this.handleMove,dragstop:this.endInteraction}):this.isTouch?this.listenTo(t,{touchmove:this.handleTouchMove,touchend:this.endInteraction,scroll:this.handleTouchScroll}):this.listenTo(t,{mousemove:this.handleMouseMove,mouseup:this.endInteraction}),this.listenTo(t,{selectstart:r.preventDefault,contextmenu:r.preventDefault})},t.prototype.unbindHandlers=function(){this.stopListeningTo(s.default.get()),this.stopListeningTo(i(document))},t.prototype.startDrag=function(t,e){this.startInteraction(t,e),this.isDragging||(this.isDragging=!0,this.handleDragStart(t))},t.prototype.handleDragStart=function(t){this.trigger("dragStart",t)},t.prototype.handleMove=function(t){var e=r.getEvX(t)-this.originX,n=r.getEvY(t)-this.originY,i=this.minDistance;this.isDistanceSurpassed||e*e+n*n>=i*i&&this.handleDistanceSurpassed(t),this.isDragging&&this.handleDrag(e,n,t)},t.prototype.handleDrag=function(t,e,n){this.trigger("drag",t,e,n),this.updateAutoScroll(n)},t.prototype.endDrag=function(t){this.isDragging&&(this.isDragging=!1,this.handleDragEnd(t))},t.prototype.handleDragEnd=function(t){this.trigger("dragEnd",t)},t.prototype.startDelay=function(t){var e=this;this.delay?this.delayTimeoutId=setTimeout(function(){e.handleDelayEnd(t)},this.delay):this.handleDelayEnd(t)},t.prototype.handleDelayEnd=function(t){this.isDelayEnded=!0,this.isDistanceSurpassed&&this.startDrag(t)},t.prototype.handleDistanceSurpassed=function(t){this.isDistanceSurpassed=!0,this.isDelayEnded&&this.startDrag(t)},t.prototype.handleTouchMove=function(t){this.isDragging&&this.shouldCancelTouchScroll&&t.preventDefault(),this.handleMove(t)},t.prototype.handleMouseMove=function(t){this.handleMove(t)},t.prototype.handleTouchScroll=function(t){this.isDragging&&!this.scrollAlwaysKills||this.endInteraction(t,!0)},t.prototype.trigger=function(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];this.options[t]&&this.options[t].apply(this,e),this["_"+t]&&this["_"+t].apply(this,e)},t.prototype.initAutoScroll=function(){var t=this.scrollEl;this.isAutoScroll=this.options.scroll&&t&&!t.is(window)&&!t.is(document),this.isAutoScroll&&this.listenTo(t,"scroll",r.debounce(this.handleDebouncedScroll,100))},t.prototype.destroyAutoScroll=function(){this.endAutoScroll(),this.isAutoScroll&&this.stopListeningTo(this.scrollEl,"scroll")},t.prototype.computeScrollBounds=function(){this.isAutoScroll&&(this.scrollBounds=r.getOuterRect(this.scrollEl))},t.prototype.updateAutoScroll=function(t){var e,n,i,o,s=this.scrollSensitivity,a=this.scrollBounds,l=0,u=0;a&&(e=(s-(r.getEvY(t)-a.top))/s,n=(s-(a.bottom-r.getEvY(t)))/s,i=(s-(r.getEvX(t)-a.left))/s,o=(s-(a.right-r.getEvX(t)))/s,e>=0&&e<=1?l=e*this.scrollSpeed*-1:n>=0&&n<=1&&(l=n*this.scrollSpeed),i>=0&&i<=1?u=i*this.scrollSpeed*-1:o>=0&&o<=1&&(u=o*this.scrollSpeed)),this.setScrollVel(l,u)},t.prototype.setScrollVel=function(t,e){this.scrollTopVel=t,this.scrollLeftVel=e,this.constrainScrollVel(),!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(r.proxy(this,"scrollIntervalFunc"),this.scrollIntervalMs))},t.prototype.constrainScrollVel=function(){var t=this.scrollEl;this.scrollTopVel<0?t.scrollTop()<=0&&(this.scrollTopVel=0):this.scrollTopVel>0&&t.scrollTop()+t[0].clientHeight>=t[0].scrollHeight&&(this.scrollTopVel=0),this.scrollLeftVel<0?t.scrollLeft()<=0&&(this.scrollLeftVel=0):this.scrollLeftVel>0&&t.scrollLeft()+t[0].clientWidth>=t[0].scrollWidth&&(this.scrollLeftVel=0)},t.prototype.scrollIntervalFunc=function(){var t=this.scrollEl,e=this.scrollIntervalMs/1e3;this.scrollTopVel&&t.scrollTop(t.scrollTop()+this.scrollTopVel*e),this.scrollLeftVel&&t.scrollLeft(t.scrollLeft()+this.scrollLeftVel*e),this.constrainScrollVel(),this.scrollTopVel||this.scrollLeftVel||this.endAutoScroll()},t.prototype.endAutoScroll=function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.handleScrollEnd())},t.prototype.handleDebouncedScroll=function(){this.scrollIntervalId||this.handleScrollEnd()},t.prototype.handleScrollEnd=function(){},t}();e.default=a,o.default.mixInto(a)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=n(14),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.updateDayTable=function(){for(var t,e,n,i=this,r=i.view,o=r.calendar,s=o.msToUtcMoment(i.dateProfile.renderUnzonedRange.startMs,!0),a=o.msToUtcMoment(i.dateProfile.renderUnzonedRange.endMs,!0),l=-1,u=[],d=[];s.isBefore(a);)r.isHiddenDay(s)?u.push(l+.5):(l++,u.push(l),d.push(s.clone())),s.add(1,"days");if(this.breakOnWeeks){for(e=d[0].day(),t=1;t<d.length&&d[t].day()!==e;t++);n=Math.ceil(d.length/t)}else n=1,t=d.length;this.dayDates=d,this.dayIndices=u,this.daysPerRow=t,this.rowCnt=n,this.updateDayTableCols()},e.prototype.updateDayTableCols=function(){this.colCnt=this.computeColCnt(),this.colHeadFormat=this.opt("columnHeaderFormat")||this.opt("columnFormat")||this.computeColHeadFormat()},e.prototype.computeColCnt=function(){return this.daysPerRow},e.prototype.getCellDate=function(t,e){return this.dayDates[this.getCellDayIndex(t,e)].clone()},e.prototype.getCellRange=function(t,e){var n=this.getCellDate(t,e);return{start:n,end:n.clone().add(1,"days")}},e.prototype.getCellDayIndex=function(t,e){return t*this.daysPerRow+this.getColDayIndex(e)},e.prototype.getColDayIndex=function(t){return this.isRTL?this.colCnt-1-t:t},e.prototype.getDateDayIndex=function(t){var e=this.dayIndices,n=t.diff(this.dayDates[0],"days");return n<0?e[0]-1:n>=e.length?e[e.length-1]+1:e[n]},e.prototype.computeColHeadFormat=function(){return this.rowCnt>1||this.colCnt>10?"ddd":this.colCnt>1?this.opt("dayOfMonthFormat"):"dddd"},e.prototype.sliceRangeByRow=function(t){var e,n,i,r,o,s=this.daysPerRow,a=this.view.computeDayRange(t),l=this.getDateDayIndex(a.start),u=this.getDateDayIndex(a.end.clone().subtract(1,"days")),d=[];for(e=0;e<this.rowCnt;e++)n=e*s,i=n+s-1,r=Math.max(l,n),o=Math.min(u,i),r=Math.ceil(r),o=Math.floor(o),r<=o&&d.push({row:e,firstRowDayIndex:r-n,lastRowDayIndex:o-n,isStart:r===l,isEnd:o===u});return d},e.prototype.sliceRangeByDay=function(t){var e,n,i,r,o,s,a=this.daysPerRow,l=this.view.computeDayRange(t),u=this.getDateDayIndex(l.start),d=this.getDateDayIndex(l.end.clone().subtract(1,"days")),c=[];for(e=0;e<this.rowCnt;e++)for(n=e*a,i=n+a-1,r=n;r<=i;r++)o=Math.max(u,r),s=Math.min(d,r),o=Math.ceil(o),s=Math.floor(s),o<=s&&c.push({row:e,firstRowDayIndex:o-n,lastRowDayIndex:s-n,isStart:o===u,isEnd:s===d});return c},e.prototype.renderHeadHtml=function(){var t=this.view.calendar.theme;return'<div class="fc-row '+t.getClass("headerRow")+'"><table class="'+t.getClass("tableGrid")+'"><thead>'+this.renderHeadTrHtml()+"</thead></table></div>"},e.prototype.renderHeadIntroHtml=function(){return this.renderIntroHtml()},e.prototype.renderHeadTrHtml=function(){return"<tr>"+(this.isRTL?"":this.renderHeadIntroHtml())+this.renderHeadDateCellsHtml()+(this.isRTL?this.renderHeadIntroHtml():"")+"</tr>"},e.prototype.renderHeadDateCellsHtml=function(){var t,e,n=[];for(t=0;t<this.colCnt;t++)e=this.getCellDate(0,t),n.push(this.renderHeadDateCellHtml(e));return n.join("")},e.prototype.renderHeadDateCellHtml=function(t,e,n){var i,o=this,s=o.view,a=o.dateProfile.activeUnzonedRange.containsDate(t),l=["fc-day-header",s.calendar.theme.getClass("widgetHeader")];return i="function"==typeof o.opt("columnHeaderHtml")?o.opt("columnHeaderHtml")(t):"function"==typeof o.opt("columnHeaderText")?r.htmlEscape(o.opt("columnHeaderText")(t)):r.htmlEscape(t.format(o.colHeadFormat)),1===o.rowCnt?l=l.concat(o.getDayClasses(t,!0)):l.push("fc-"+r.dayIDs[t.day()]),'<th class="'+l.join(" ")+'"'+(1===(a&&o.rowCnt)?' data-date="'+t.format("YYYY-MM-DD")+'"':"")+(e>1?' colspan="'+e+'"':"")+(n?" "+n:"")+">"+(a?s.buildGotoAnchorHtml({date:t,forceOff:o.rowCnt>1||1===o.colCnt},i):i)+"</th>"},e.prototype.renderBgTrHtml=function(t){return"<tr>"+(this.isRTL?"":this.renderBgIntroHtml(t))+this.renderBgCellsHtml(t)+(this.isRTL?this.renderBgIntroHtml(t):"")+"</tr>"},e.prototype.renderBgIntroHtml=function(t){return this.renderIntroHtml()},e.prototype.renderBgCellsHtml=function(t){var e,n,i=[];for(e=0;e<this.colCnt;e++)n=this.getCellDate(t,e),i.push(this.renderBgCellHtml(n));return i.join("")},e.prototype.renderBgCellHtml=function(t,e){var n=this,i=n.view,r=n.dateProfile.activeUnzonedRange.containsDate(t),o=n.getDayClasses(t);return o.unshift("fc-day",i.calendar.theme.getClass("widgetContent")),'<td class="'+o.join(" ")+'"'+(r?' data-date="'+t.format("YYYY-MM-DD")+'"':"")+(e?" "+e:"")+"></td>"},e.prototype.renderIntroHtml=function(){},e.prototype.bookendCells=function(t){var e=this.renderIntroHtml();e&&(this.isRTL?t.append(e):t.prepend(e))},e}(o.default);e.default=s},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){this.component=t,this.fillRenderer=e}return t.prototype.render=function(t){var e=this.component,n=e._getDateProfile().activeUnzonedRange,i=t.buildEventInstanceGroup(e.hasAllDayBusinessHours,n),r=i?e.eventRangesToEventFootprints(i.sliceRenderRanges(n)):[];this.renderEventFootprints(r)},t.prototype.renderEventFootprints=function(t){var e=this.component.eventFootprintsToSegs(t);this.renderSegs(e),this.segs=e},t.prototype.renderSegs=function(t){this.fillRenderer&&this.fillRenderer.renderSegs("businessHours",t,{getClasses:function(t){return["fc-nonbusiness","fc-bgevent"]}})},t.prototype.unrender=function(){this.fillRenderer&&this.fillRenderer.unrender("businessHours"),this.segs=null},t.prototype.getSegs=function(){return this.segs||[]},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=function(){function t(t){this.fillSegTag="div",this.component=t,this.elsByFill={}}return t.prototype.renderFootprint=function(t,e,n){this.renderSegs(t,this.component.componentFootprintToSegs(e),n)},t.prototype.renderSegs=function(t,e,n){var i;return e=this.buildSegEls(t,e,n),i=this.attachSegEls(t,e),i&&this.reportEls(t,i),e},t.prototype.unrender=function(t){var e=this.elsByFill[t];e&&(e.remove(),delete this.elsByFill[t])},t.prototype.buildSegEls=function(t,e,n){var r,o=this,s="",a=[];if(e.length){for(r=0;r<e.length;r++)s+=this.buildSegHtml(t,e[r],n);i(s).each(function(t,r){var s=e[t],l=i(r);n.filterEl&&(l=n.filterEl(s,l)),l&&(l=i(l),l.is(o.fillSegTag)&&(s.el=l,a.push(s)))})}return a},t.prototype.buildSegHtml=function(t,e,n){var i=n.getClasses?n.getClasses(e):[],o=r.cssToStr(n.getCss?n.getCss(e):{});return"<"+this.fillSegTag+(i.length?' class="'+i.join(" ")+'"':"")+(o?' style="'+o+'"':"")+" />"},t.prototype.attachSegEls=function(t,e){},t.prototype.reportEls=function(t,e){this.elsByFill[t]?this.elsByFill[t]=this.elsByFill[t].add(e):this.elsByFill[t]=i(e)},t}();e.default=o},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(13),r=n(36),o=n(6),s=function(){function t(t,e){this.view=t._getView(),this.component=t,this.eventRenderer=e}return t.prototype.renderComponentFootprint=function(t){this.renderEventFootprints([this.fabricateEventFootprint(t)])},t.prototype.renderEventDraggingFootprints=function(t,e,n){this.renderEventFootprints(t,e,"fc-dragging",n?null:this.view.opt("dragOpacity"))},t.prototype.renderEventResizingFootprints=function(t,e,n){this.renderEventFootprints(t,e,"fc-resizing")},t.prototype.renderEventFootprints=function(t,e,n,i){var r,o=this.component.eventFootprintsToSegs(t),s="fc-helper "+(n||"");for(o=this.eventRenderer.renderFgSegEls(o),r=0;r<o.length;r++)o[r].el.addClass(s);if(null!=i)for(r=0;r<o.length;r++)o[r].el.css("opacity",i);this.helperEls=this.renderSegs(o,e)},t.prototype.renderSegs=function(t,e){},t.prototype.unrender=function(){this.helperEls&&(this.helperEls.remove(),this.helperEls=null)},t.prototype.fabricateEventFootprint=function(t){var e,n=this.view.calendar,s=n.footprintToDateProfile(t),a=new i.default(new o.default(n));return a.dateProfile=s,e=a.buildInstance(),new r.default(t,a,e)},t}();e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(21),o=n(15),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.bindToEl=function(t){var e=this.component;e.bindSegHandlerToEl(t,"click",this.handleClick.bind(this)),e.bindSegHandlerToEl(t,"mouseenter",this.handleMouseover.bind(this)),e.bindSegHandlerToEl(t,"mouseleave",this.handleMouseout.bind(this))},e.prototype.handleClick=function(t,e){!1===this.component.publiclyTrigger("eventClick",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,this.view]})&&e.preventDefault()},e.prototype.handleMouseover=function(t,e){r.default.get().shouldIgnoreMouse()||this.mousedOverSeg||(this.mousedOverSeg=t,this.view.isEventDefResizable(t.footprint.eventDef)&&t.el.addClass("fc-allow-mouse-resize"),this.component.publiclyTrigger("eventMouseover",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,this.view]}))},e.prototype.handleMouseout=function(t,e){this.mousedOverSeg&&(this.mousedOverSeg=null,this.view.isEventDefResizable(t.footprint.eventDef)&&t.el.removeClass("fc-allow-mouse-resize"),this.component.publiclyTrigger("eventMouseout",{context:t.el[0],args:[t.footprint.getEventLegacy(),e||{},this.view]}))},e.prototype.end=function(){this.mousedOverSeg&&this.handleMouseout(this.mousedOverSeg)},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(14),o=n(245),s=n(225),a=n(59),l=n(224),u=n(223),d=n(222),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(r.default);e.default=c,c.prototype.dateClickingClass=o.default,c.prototype.dateSelectingClass=s.default,c.prototype.eventPointingClass=a.default,c.prototype.eventDraggingClass=l.default,c.prototype.eventResizingClass=u.default,c.prototype.externalDroppingClass=d.default},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(53),a=n(249),l=n(5),u=n(12),d=n(36),c=n(56),p=n(60),h=n(40),f=n(55),g=n(250),v=n(251),y=n(252),m=function(t){function e(e){var n=t.call(this,e)||this;return n.cellWeekNumbersVisible=!1,n.bottomCoordPadding=0,n.isRigid=!1,n.hasAllDayBusinessHours=!0,n}return i.__extends(e,t),e.prototype.componentFootprintToSegs=function(t){var e,n,i=this.sliceRangeByRow(t.unzonedRange);for(e=0;e<i.length;e++)n=i[e],this.isRTL?(n.leftCol=this.daysPerRow-1-n.lastRowDayIndex,n.rightCol=this.daysPerRow-1-n.firstRowDayIndex):(n.leftCol=n.firstRowDayIndex,n.rightCol=n.lastRowDayIndex);return i},e.prototype.renderDates=function(t){this.dateProfile=t,this.updateDayTable(),this.renderGrid()},e.prototype.unrenderDates=function(){this.removeSegPopover()},e.prototype.renderGrid=function(){var t,e,n=this.view,i=this.rowCnt,r=this.colCnt,o="";for(this.headContainerEl&&this.headContainerEl.html(this.renderHeadHtml()),t=0;t<i;t++)o+=this.renderDayRowHtml(t,this.isRigid);for(this.el.html(o),this.rowEls=this.el.find(".fc-row"),this.cellEls=this.el.find(".fc-day, .fc-disabled-day"),this.rowCoordCache=new s.default({els:this.rowEls,isVertical:!0}),this.colCoordCache=new s.default({els:this.cellEls.slice(0,this.colCnt),isHorizontal:!0}),t=0;t<i;t++)for(e=0;e<r;e++)this.publiclyTrigger("dayRender",{context:n,args:[this.getCellDate(t,e),this.getCellEl(t,e),n]})},e.prototype.renderDayRowHtml=function(t,e){var n=this.view.calendar.theme,i=["fc-row","fc-week",n.getClass("dayRow")];return e&&i.push("fc-rigid"),'<div class="'+i.join(" ")+'"><div class="fc-bg"><table class="'+n.getClass("tableGrid")+'">'+this.renderBgTrHtml(t)+'</table></div><div class="fc-content-skeleton"><table>'+(this.getIsNumbersVisible()?"<thead>"+this.renderNumberTrHtml(t)+"</thead>":"")+"</table></div></div>"},e.prototype.getIsNumbersVisible=function(){return this.getIsDayNumbersVisible()||this.cellWeekNumbersVisible},e.prototype.getIsDayNumbersVisible=function(){return this.rowCnt>1},e.prototype.renderNumberTrHtml=function(t){return"<tr>"+(this.isRTL?"":this.renderNumberIntroHtml(t))+this.renderNumberCellsHtml(t)+(this.isRTL?this.renderNumberIntroHtml(t):"")+"</tr>"},e.prototype.renderNumberIntroHtml=function(t){return this.renderIntroHtml()},e.prototype.renderNumberCellsHtml=function(t){var e,n,i=[];for(e=0;e<this.colCnt;e++)n=this.getCellDate(t,e),i.push(this.renderNumberCellHtml(n));return i.join("")},e.prototype.renderNumberCellHtml=function(t){var e,n,i=this.view,r="",o=this.dateProfile.activeUnzonedRange.containsDate(t),s=this.getIsDayNumbersVisible()&&o;return s||this.cellWeekNumbersVisible?(e=this.getDayClasses(t),e.unshift("fc-day-top"),this.cellWeekNumbersVisible&&(n="ISO"===t._locale._fullCalendar_weekCalc?1:t._locale.firstDayOfWeek()),r+='<td class="'+e.join(" ")+'"'+(o?' data-date="'+t.format()+'"':"")+">",this.cellWeekNumbersVisible&&t.day()===n&&(r+=i.buildGotoAnchorHtml({date:t,type:"week"},{class:"fc-week-number"},t.format("w"))),s&&(r+=i.buildGotoAnchorHtml(t,{class:"fc-day-number"},t.format("D"))),r+="</td>"):"<td/>"},e.prototype.prepareHits=function(){this.colCoordCache.build(),this.rowCoordCache.build(),this.rowCoordCache.bottoms[this.rowCnt-1]+=this.bottomCoordPadding},e.prototype.releaseHits=function(){this.colCoordCache.clear(),this.rowCoordCache.clear()},e.prototype.queryHit=function(t,e){if(this.colCoordCache.isLeftInBounds(t)&&this.rowCoordCache.isTopInBounds(e)){var n=this.colCoordCache.getHorizontalIndex(t),i=this.rowCoordCache.getVerticalIndex(e);if(null!=i&&null!=n)return this.getCellHit(i,n)}},e.prototype.getHitFootprint=function(t){var e=this.getCellRange(t.row,t.col);return new u.default(new l.default(e.start,e.end),!0)},e.prototype.getHitEl=function(t){return this.getCellEl(t.row,t.col)},e.prototype.getCellHit=function(t,e){return{row:t,col:e,component:this,left:this.colCoordCache.getLeftOffset(e),right:this.colCoordCache.getRightOffset(e),top:this.rowCoordCache.getTopOffset(t),bottom:this.rowCoordCache.getBottomOffset(t)}},e.prototype.getCellEl=function(t,e){return this.cellEls.eq(t*this.colCnt+e)},e.prototype.executeEventUnrender=function(){this.removeSegPopover(),t.prototype.executeEventUnrender.call(this)},e.prototype.getOwnEventSegs=function(){
+return t.prototype.getOwnEventSegs.call(this).concat(this.popoverSegs||[])},e.prototype.renderDrag=function(t,e,n){var i;for(i=0;i<t.length;i++)this.renderHighlight(t[i].componentFootprint);if(t.length&&e&&e.component!==this)return this.helperRenderer.renderEventDraggingFootprints(t,e,n),!0},e.prototype.unrenderDrag=function(){this.unrenderHighlight(),this.helperRenderer.unrender()},e.prototype.renderEventResize=function(t,e,n){var i;for(i=0;i<t.length;i++)this.renderHighlight(t[i].componentFootprint);this.helperRenderer.renderEventResizingFootprints(t,e,n)},e.prototype.unrenderEventResize=function(){this.unrenderHighlight(),this.helperRenderer.unrender()},e.prototype.removeSegPopover=function(){this.segPopover&&this.segPopover.hide()},e.prototype.limitRows=function(t){var e,n,i=this.eventRenderer.rowStructs||[];for(e=0;e<i.length;e++)this.unlimitRow(e),!1!==(n=!!t&&("number"==typeof t?t:this.computeRowLevelLimit(e)))&&this.limitRow(e,n)},e.prototype.computeRowLevelLimit=function(t){function e(t,e){o=Math.max(o,r(e).outerHeight())}var n,i,o,s=this.rowEls.eq(t),a=s.height(),l=this.eventRenderer.rowStructs[t].tbodyEl.children();for(n=0;n<l.length;n++)if(i=l.eq(n).removeClass("fc-limited"),o=0,i.find("> td > :first-child").each(e),i.position().top+o>a)return n;return!1},e.prototype.limitRow=function(t,e){var n,i,o,s,a,l,u,d,c,p,h,f,g,v,y,m=this,b=this.eventRenderer.rowStructs[t],w=[],D=0,E=function(n){for(;D<n;)l=m.getCellSegs(t,D,e),l.length&&(c=i[e-1][D],y=m.renderMoreLink(t,D,l),v=r("<div/>").append(y),c.append(v),w.push(v[0])),D++};if(e&&e<b.segLevels.length){for(n=b.segLevels[e-1],i=b.cellMatrix,o=b.tbodyEl.children().slice(e).addClass("fc-limited").get(),s=0;s<n.length;s++){for(a=n[s],E(a.leftCol),d=[],u=0;D<=a.rightCol;)l=this.getCellSegs(t,D,e),d.push(l),u+=l.length,D++;if(u){for(c=i[e-1][a.leftCol],p=c.attr("rowspan")||1,h=[],f=0;f<d.length;f++)g=r('<td class="fc-more-cell"/>').attr("rowspan",p),l=d[f],y=this.renderMoreLink(t,a.leftCol+f,[a].concat(l)),v=r("<div/>").append(y),g.append(v),h.push(g[0]),w.push(g[0]);c.addClass("fc-limited").after(r(h)),o.push(c[0])}}E(this.colCnt),b.moreEls=r(w),b.limitedEls=r(o)}},e.prototype.unlimitRow=function(t){var e=this.eventRenderer.rowStructs[t];e.moreEls&&(e.moreEls.remove(),e.moreEls=null),e.limitedEls&&(e.limitedEls.removeClass("fc-limited"),e.limitedEls=null)},e.prototype.renderMoreLink=function(t,e,n){var i=this,o=this.view;return r('<a class="fc-more"/>').text(this.getMoreLinkText(n.length)).on("click",function(s){var a=i.opt("eventLimitClick"),l=i.getCellDate(t,e),u=r(s.currentTarget),d=i.getCellEl(t,e),c=i.getCellSegs(t,e),p=i.resliceDaySegs(c,l),h=i.resliceDaySegs(n,l);"function"==typeof a&&(a=i.publiclyTrigger("eventLimitClick",{context:o,args:[{date:l.clone(),dayEl:d,moreEl:u,segs:p,hiddenSegs:h},s,o]})),"popover"===a?i.showSegPopover(t,e,u,p):"string"==typeof a&&o.calendar.zoomTo(l,a)})},e.prototype.showSegPopover=function(t,e,n,i){var r,o,s=this,l=this.view,u=n.parent();r=1===this.rowCnt?l.el:this.rowEls.eq(t),o={className:"fc-more-popover "+l.calendar.theme.getClass("popover"),content:this.renderSegPopoverContent(t,e,i),parentEl:l.el,top:r.offset().top,autoHide:!0,viewportConstrain:this.opt("popoverViewportConstrain"),hide:function(){s.popoverSegs&&s.triggerBeforeEventSegsDestroyed(s.popoverSegs),s.segPopover.removeElement(),s.segPopover=null,s.popoverSegs=null}},this.isRTL?o.right=u.offset().left+u.outerWidth()+1:o.left=u.offset().left-1,this.segPopover=new a.default(o),this.segPopover.show(),this.bindAllSegHandlersToEl(this.segPopover.el),this.triggerAfterEventSegsRendered(i)},e.prototype.renderSegPopoverContent=function(t,e,n){var i,s=this.view,a=s.calendar.theme,l=this.getCellDate(t,e).format(this.opt("dayPopoverFormat")),u=r('<div class="fc-header '+a.getClass("popoverHeader")+'"><span class="fc-close '+a.getIconClass("close")+'"></span><span class="fc-title">'+o.htmlEscape(l)+'</span><div class="fc-clear"/></div><div class="fc-body '+a.getClass("popoverContent")+'"><div class="fc-event-container"></div></div>'),d=u.find(".fc-event-container");for(n=this.eventRenderer.renderFgSegEls(n,!0),this.popoverSegs=n,i=0;i<n.length;i++)this.hitsNeeded(),n[i].hit=this.getCellHit(t,e),this.hitsNotNeeded(),d.append(n[i].el);return u},e.prototype.resliceDaySegs=function(t,e){var n,i,o,s=e.clone(),a=s.clone().add(1,"days"),c=new l.default(s,a),p=[];for(n=0;n<t.length;n++)i=t[n],(o=i.footprint.componentFootprint.unzonedRange.intersect(c))&&p.push(r.extend({},i,{footprint:new d.default(new u.default(o,i.footprint.componentFootprint.isAllDay),i.footprint.eventDef,i.footprint.eventInstance),isStart:i.isStart&&o.isStart,isEnd:i.isEnd&&o.isEnd}));return this.eventRenderer.sortEventSegs(p),p},e.prototype.getMoreLinkText=function(t){var e=this.opt("eventLimitText");return"function"==typeof e?e(t):"+"+t+" "+e},e.prototype.getCellSegs=function(t,e,n){for(var i,r=this.eventRenderer.rowStructs[t].segMatrix,o=n||0,s=[];o<r.length;)i=r[o][e],i&&s.push(i),o++;return s},e}(h.default);e.default=m,m.prototype.eventRendererClass=g.default,m.prototype.businessHourRendererClass=c.default,m.prototype.helperRendererClass=v.default,m.prototype.fillRendererClass=y.default,p.default.mixInto(m),f.default.mixInto(m)},function(t,e,n){function i(t){return function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.colWeekNumbersVisible=!1,e}return r.__extends(e,t),e.prototype.renderHeadIntroHtml=function(){var t=this.view;return this.colWeekNumbersVisible?'<th class="fc-week-number '+t.calendar.theme.getClass("widgetHeader")+'" '+t.weekNumberStyleAttr()+"><span>"+s.htmlEscape(this.opt("weekNumberTitle"))+"</span></th>":""},e.prototype.renderNumberIntroHtml=function(t){var e=this.view,n=this.getCellDate(t,0);return this.colWeekNumbersVisible?'<td class="fc-week-number" '+e.weekNumberStyleAttr()+">"+e.buildGotoAnchorHtml({date:n,type:"week",forceOff:1===this.colCnt},n.format("w"))+"</td>":""},e.prototype.renderBgIntroHtml=function(){var t=this.view;return this.colWeekNumbersVisible?'<td class="fc-week-number '+t.calendar.theme.getClass("widgetContent")+'" '+t.weekNumberStyleAttr()+"></td>":""},e.prototype.renderIntroHtml=function(){var t=this.view;return this.colWeekNumbersVisible?'<td class="fc-week-number" '+t.weekNumberStyleAttr()+"></td>":""},e.prototype.getIsNumbersVisible=function(){return d.default.prototype.getIsNumbersVisible.apply(this,arguments)||this.colWeekNumbersVisible},e}(t)}Object.defineProperty(e,"__esModule",{value:!0});var r=n(2),o=n(3),s=n(4),a=n(39),l=n(41),u=n(228),d=n(61),c=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.dayGrid=i.instantiateDayGrid(),i.dayGrid.isRigid=i.hasRigidRows(),i.opt("weekNumbers")&&(i.opt("weekNumbersWithinDays")?(i.dayGrid.cellWeekNumbersVisible=!0,i.dayGrid.colWeekNumbersVisible=!1):(i.dayGrid.cellWeekNumbersVisible=!1,i.dayGrid.colWeekNumbersVisible=!0)),i.addChild(i.dayGrid),i.scroller=new a.default({overflowX:"hidden",overflowY:"auto"}),i}return r.__extends(e,t),e.prototype.instantiateDayGrid=function(){return new(i(this.dayGridClass))(this)},e.prototype.executeDateRender=function(e){this.dayGrid.breakOnWeeks=/year|month|week/.test(e.currentRangeUnit),t.prototype.executeDateRender.call(this,e)},e.prototype.renderSkeleton=function(){var t,e;this.el.addClass("fc-basic-view").html(this.renderSkeletonHtml()),this.scroller.render(),t=this.scroller.el.addClass("fc-day-grid-container"),e=o('<div class="fc-day-grid" />').appendTo(t),this.el.find(".fc-body > tr > td").append(t),this.dayGrid.headContainerEl=this.el.find(".fc-head-container"),this.dayGrid.setElement(e)},e.prototype.unrenderSkeleton=function(){this.dayGrid.removeElement(),this.scroller.destroy()},e.prototype.renderSkeletonHtml=function(){var t=this.calendar.theme;return'<table class="'+t.getClass("tableGrid")+'">'+(this.opt("columnHeader")?'<thead class="fc-head"><tr><td class="fc-head-container '+t.getClass("widgetHeader")+'">&nbsp;</td></tr></thead>':"")+'<tbody class="fc-body"><tr><td class="'+t.getClass("widgetContent")+'"></td></tr></tbody></table>'},e.prototype.weekNumberStyleAttr=function(){return null!=this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},e.prototype.hasRigidRows=function(){var t=this.opt("eventLimit");return t&&"number"!=typeof t},e.prototype.updateSize=function(e,n,i){var r,o,a=this.opt("eventLimit"),l=this.dayGrid.headContainerEl.find(".fc-row");if(!this.dayGrid.rowEls)return void(n||(r=this.computeScrollerHeight(e),this.scroller.setHeight(r)));t.prototype.updateSize.call(this,e,n,i),this.dayGrid.colWeekNumbersVisible&&(this.weekNumberWidth=s.matchCellWidths(this.el.find(".fc-week-number"))),this.scroller.clear(),s.uncompensateScroll(l),this.dayGrid.removeSegPopover(),a&&"number"==typeof a&&this.dayGrid.limitRows(a),r=this.computeScrollerHeight(e),this.setGridHeight(r,n),a&&"number"!=typeof a&&this.dayGrid.limitRows(a),n||(this.scroller.setHeight(r),o=this.scroller.getScrollbarWidths(),(o.left||o.right)&&(s.compensateScroll(l,o),r=this.computeScrollerHeight(e),this.scroller.setHeight(r)),this.scroller.lockOverflow(o))},e.prototype.computeScrollerHeight=function(t){return t-s.subtractInnerElHeight(this.el,this.scroller.el)},e.prototype.setGridHeight=function(t,e){e?s.undistributeHeight(this.dayGrid.rowEls):s.distributeHeight(this.dayGrid.rowEls,t,!0)},e.prototype.computeInitialDateScroll=function(){return{top:0}},e.prototype.queryDateScroll=function(){return{top:this.scroller.getScrollTop()}},e.prototype.applyDateScroll=function(t){void 0!==t.top&&this.scroller.setScrollTop(t.top)},e}(l.default);e.default=c,c.prototype.dateProfileGeneratorClass=u.default,c.prototype.dayGridClass=d.default},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(t,e,n){function i(t,e,n){var i;for(i=0;i<t.length;i++)if(!e(t[i].eventInstance.toLegacy(),n?n.toLegacy():null))return!1;return!0}function r(t,e){var n,i,r,o,s=e.toLegacy();for(n=0;n<t.length;n++){if(i=t[n].eventInstance,r=i.def,!1===(o=r.getOverlap()))return!1;if("function"==typeof o&&!o(i.toLegacy(),s))return!1}return!0}Object.defineProperty(e,"__esModule",{value:!0});var o=n(5),s=n(12),a=n(49),l=n(6),u=n(35),d=function(){function t(t,e){this.eventManager=t,this._calendar=e}return t.prototype.opt=function(t){return this._calendar.opt(t)},t.prototype.isEventInstanceGroupAllowed=function(t){var e,n=t.getEventDef(),i=this.eventRangesToEventFootprints(t.getAllEventRanges()),r=this.getPeerEventInstances(n),o=r.map(u.eventInstanceToEventRange),s=this.eventRangesToEventFootprints(o),a=n.getConstraint(),l=n.getOverlap(),d=this.opt("eventAllow");for(e=0;e<i.length;e++)if(!this.isFootprintAllowed(i[e].componentFootprint,s,a,l,i[e].eventInstance))return!1;if(d)for(e=0;e<i.length;e++)if(!1===d(i[e].componentFootprint.toLegacy(this._calendar),i[e].getEventLegacy()))return!1;return!0},t.prototype.getPeerEventInstances=function(t){return this.eventManager.getEventInstancesWithoutId(t.id)},t.prototype.isSelectionFootprintAllowed=function(t){var e,n=this.eventManager.getEventInstances(),i=n.map(u.eventInstanceToEventRange),r=this.eventRangesToEventFootprints(i);return!!this.isFootprintAllowed(t,r,this.opt("selectConstraint"),this.opt("selectOverlap"))&&(!(e=this.opt("selectAllow"))||!1!==e(t.toLegacy(this._calendar)))},t.prototype.isFootprintAllowed=function(t,e,n,o,s){var a,l;if(null!=n&&(a=this.constraintValToFootprints(n,t.isAllDay),!this.isFootprintWithinConstraints(t,a)))return!1;if(l=this.collectOverlapEventFootprints(e,t),!1===o){if(l.length)return!1}else if("function"==typeof o&&!i(l,o,s))return!1;return!(s&&!r(l,s))},t.prototype.isFootprintWithinConstraints=function(t,e){var n;for(n=0;n<e.length;n++)if(this.footprintContainsFootprint(e[n],t))return!0;return!1},t.prototype.constraintValToFootprints=function(t,e){var n;return"businessHours"===t?this.buildCurrentBusinessFootprints(e):"object"==typeof t?(n=this.parseEventDefToInstances(t),n?this.eventInstancesToFootprints(n):this.parseFootprints(t)):null!=t?(n=this.eventManager.getEventInstancesWithId(t),this.eventInstancesToFootprints(n)):void 0},t.prototype.buildCurrentBusinessFootprints=function(t){var e=this._calendar.view,n=e.get("businessHourGenerator"),i=e.dateProfile.activeUnzonedRange,r=n.buildEventInstanceGroup(t,i);return r?this.eventInstancesToFootprints(r.eventInstances):[]},t.prototype.eventInstancesToFootprints=function(t){var e=t.map(u.eventInstanceToEventRange);return this.eventRangesToEventFootprints(e).map(u.eventFootprintToComponentFootprint)},t.prototype.collectOverlapEventFootprints=function(t,e){var n,i=[];for(n=0;n<t.length;n++)this.footprintsIntersect(e,t[n].componentFootprint)&&i.push(t[n]);return i},t.prototype.parseEventDefToInstances=function(t){var e=this.eventManager,n=a.default.parse(t,new l.default(this._calendar));return!!n&&n.buildInstances(e.currentPeriod.unzonedRange)},t.prototype.eventRangesToEventFootprints=function(t){var e,n=[];for(e=0;e<t.length;e++)n.push.apply(n,this.eventRangeToEventFootprints(t[e]));return n},t.prototype.eventRangeToEventFootprints=function(t){return[u.eventRangeToEventFootprint(t)]},t.prototype.parseFootprints=function(t){var e,n;return t.start&&(e=this._calendar.moment(t.start),e.isValid()||(e=null)),t.end&&(n=this._calendar.moment(t.end),n.isValid()||(n=null)),[new s.default(new o.default(e,n),e&&!e.hasTime()||n&&!n.hasTime())]},t.prototype.footprintContainsFootprint=function(t,e){return t.unzonedRange.containsRange(e.unzonedRange)},t.prototype.footprintsIntersect=function(t,e){return t.unzonedRange.intersectsWith(e.unzonedRange)},t}();e.default=d},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=n(14),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.defineStandardProps=function(t){var e=this.prototype;e.hasOwnProperty("standardPropMap")||(e.standardPropMap=Object.create(e.standardPropMap)),r.copyOwnProps(t,e.standardPropMap)},e.copyVerbatimStandardProps=function(t,e){var n,i=this.prototype.standardPropMap;for(n in i)null!=t[n]&&!0===i[n]&&(e[n]=t[n])},e.prototype.applyProps=function(t){var e,n=this.standardPropMap,i={},r={};for(e in t)!0===n[e]?this[e]=t[e]:!1===n[e]?i[e]=t[e]:r[e]=t[e];return this.applyMiscProps(r),this.applyManualStandardProps(i)},e.prototype.applyManualStandardProps=function(t){return!0},e.prototype.applyMiscProps=function(t){},e.prototype.isStandardProp=function(t){return t in this.standardPropMap},e}(o.default);e.default=s,s.prototype.standardPropMap={}},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){this.def=t,this.dateProfile=e}return t.prototype.toLegacy=function(){var t=this.dateProfile,e=this.def.toLegacy();return e.start=t.start.clone(),e.end=t.end?t.end.clone():null,e},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(0),s=n(34),a=n(209),l=n(17),u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.isAllDay=function(){return!this.startTime&&!this.endTime},e.prototype.buildInstances=function(t){for(var e,n,i,r=this.source.calendar,o=t.getStart(),s=t.getEnd(),u=[];o.isBefore(s);)this.dowHash&&!this.dowHash[o.day()]||(e=r.applyTimezone(o),n=e.clone(),i=null,this.startTime?n.time(this.startTime):n.stripTime(),this.endTime&&(i=e.clone().time(this.endTime)),u.push(new a.default(this,new l.default(n,i,r)))),o.add(1,"days");return u},e.prototype.setDow=function(t){this.dowHash||(this.dowHash={});for(var e=0;e<t.length;e++)this.dowHash[t[e]]=!0},e.prototype.clone=function(){var e=t.prototype.clone.call(this);return e.startTime&&(e.startTime=o.duration(this.startTime)),e.endTime&&(e.endTime=o.duration(this.endTime)),this.dowHash&&(e.dowHash=r.extend({},this.dowHash)),e},e}(s.default);e.default=u,u.prototype.applyProps=function(t){var e=s.default.prototype.applyProps.call(this,t);return t.start&&(this.startTime=o.duration(t.start)),t.end&&(this.endTime=o.duration(t.end)),t.dow&&this.setDow(t.dow),e},u.defineStandardProps({start:!1,end:!1,dow:!1})},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e,n){this.unzonedRange=t,this.eventDef=e,n&&(this.eventInstance=n)}return t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(35),o=n(18),s=n(210),a=n(6),l={start:"09:00",end:"17:00",dow:[1,2,3,4,5],rendering:"inverse-background"},u=function(){function t(t,e){this.rawComplexDef=t,this.calendar=e}return t.prototype.buildEventInstanceGroup=function(t,e){var n,i=this.buildEventDefs(t);if(i.length)return n=new o.default(r.eventDefsToEventInstances(i,e)),n.explicitEventDef=i[0],n},t.prototype.buildEventDefs=function(t){var e,n=this.rawComplexDef,r=[],o=!1,s=[];for(!0===n?r=[{}]:i.isPlainObject(n)?r=[n]:i.isArray(n)&&(r=n,o=!0),e=0;e<r.length;e++)o&&!r[e].dow||s.push(this.buildEventDef(t,r[e]));return s},t.prototype.buildEventDef=function(t,e){var n=i.extend({},l,e);return t&&(n.start=null,n.end=null),s.default.parse(n,new a.default(this.calendar))},t}();e.default=u},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(19),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(r.default);e.default=o,o.prototype.classes={widget:"fc-unthemed",widgetHeader:"fc-widget-header",widgetContent:"fc-widget-content",buttonGroup:"fc-button-group",button:"fc-button",cornerLeft:"fc-corner-left",cornerRight:"fc-corner-right",stateDefault:"fc-state-default",stateActive:"fc-state-active",stateDisabled:"fc-state-disabled",stateHover:"fc-state-hover",stateDown:"fc-state-down",popoverHeader:"fc-widget-header",popoverContent:"fc-widget-content",headerRow:"fc-widget-header",dayRow:"fc-widget-content",listView:"fc-widget-content"},o.prototype.baseIconClass="fc-icon",o.prototype.iconClasses={close:"fc-icon-x",prev:"fc-icon-left-single-arrow",next:"fc-icon-right-single-arrow",prevYear:"fc-icon-left-double-arrow",nextYear:"fc-icon-right-double-arrow"},o.prototype.iconOverrideOption="buttonIcons",o.prototype.iconOverrideCustomButtonOption="icon",o.prototype.iconOverridePrefix="fc-icon-"},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(19),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(r.default);e.default=o,o.prototype.classes={widget:"ui-widget",widgetHeader:"ui-widget-header",widgetContent:"ui-widget-content",buttonGroup:"fc-button-group",button:"ui-button",cornerLeft:"ui-corner-left",cornerRight:"ui-corner-right",stateDefault:"ui-state-default",stateActive:"ui-state-active",stateDisabled:"ui-state-disabled",stateHover:"ui-state-hover",stateDown:"ui-state-down",today:"ui-state-highlight",popoverHeader:"ui-widget-header",popoverContent:"ui-widget-content",headerRow:"ui-widget-header",dayRow:"ui-widget-content",listView:"ui-widget-content"},o.prototype.baseIconClass="ui-icon",o.prototype.iconClasses={close:"ui-icon-closethick",prev:"ui-icon-circle-triangle-w",next:"ui-icon-circle-triangle-e",prevYear:"ui-icon-seek-prev",nextYear:"ui-icon-seek-next"},o.prototype.iconOverrideOption="themeButtonIcons",o.prototype.iconOverrideCustomButtonOption="themeIcon",o.prototype.iconOverridePrefix="ui-icon-"},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(20),s=n(6),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.parse=function(t,e){var n;return r.isFunction(t.events)?n=t:r.isFunction(t)&&(n={events:t}),!!n&&s.default.parse.call(this,n,e)},e.prototype.fetch=function(t,e,n){var i=this;return this.calendar.pushLoading(),o.default.construct(function(r){i.func.call(i.calendar,t.clone(),e.clone(),n,function(t){i.calendar.popLoading(),r(i.parseEventDefs(t))})})},e.prototype.getPrimitive=function(){return this.func},e.prototype.applyManualStandardProps=function(e){var n=t.prototype.applyManualStandardProps.call(this,e);return this.func=e.events,n},e}(s.default);e.default=a,a.defineStandardProps({events:!1})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(20),a=n(6),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.parse=function(t,e){var n;return"string"==typeof t.url?n=t:"string"==typeof t&&(n={url:t}),!!n&&a.default.parse.call(this,n,e)},e.prototype.fetch=function(t,n,i){var a=this,l=this.ajaxSettings,u=l.success,d=l.error,c=this.buildRequestParams(t,n,i);return this.calendar.pushLoading(),s.default.construct(function(t,n){r.ajax(r.extend({},e.AJAX_DEFAULTS,l,{url:a.url,data:c,success:function(e,i,s){var l;a.calendar.popLoading(),e?(l=o.applyAll(u,a,[e,i,s]),r.isArray(l)&&(e=l),t(a.parseEventDefs(e))):n()},error:function(t,e,i){a.calendar.popLoading(),o.applyAll(d,a,[t,e,i]),n()}}))})},e.prototype.buildRequestParams=function(t,e,n){var i,o,s,a,l=this.calendar,u=this.ajaxSettings,d={};return i=this.startParam,null==i&&(i=l.opt("startParam")),o=this.endParam,null==o&&(o=l.opt("endParam")),s=this.timezoneParam,null==s&&(s=l.opt("timezoneParam")),a=r.isFunction(u.data)?u.data():u.data||{},r.extend(d,a),d[i]=t.format(),d[o]=e.format(),n&&"local"!==n&&(d[s]=n),d},e.prototype.getPrimitive=function(){return this.url},e.prototype.applyMiscProps=function(t){this.ajaxSettings=t},e.AJAX_DEFAULTS={dataType:"json",cache:!1},e}(a.default);e.default=l,l.defineStandardProps({url:!0,startParam:!0,endParam:!0,timezoneParam:!0})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(11),r=function(){function t(){this.q=[],this.isPaused=!1,this.isRunning=!1}return t.prototype.queue=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];this.q.push.apply(this.q,t),this.tryStart()},t.prototype.pause=function(){this.isPaused=!0},t.prototype.resume=function(){this.isPaused=!1,this.tryStart()},t.prototype.getIsIdle=function(){return!this.isRunning&&!this.isPaused},t.prototype.tryStart=function(){!this.isRunning&&this.canRunNext()&&(this.isRunning=!0,this.trigger("start"),this.runRemaining())},t.prototype.canRunNext=function(){return!this.isPaused&&this.q.length},t.prototype.runRemaining=function(){var t,e,n=this;do{if(t=this.q.shift(),(e=this.runTask(t))&&e.then)return void e.then(function(){n.canRunNext()&&n.runRemaining()})}while(this.canRunNext());this.trigger("stop"),this.isRunning=!1,this.tryStart()},t.prototype.runTask=function(t){return t()},t}();e.default=r,i.default.mixInto(r)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(217),o=function(t){function e(e){var n=t.call(this)||this;return n.waitsByNamespace=e||{},n}return i.__extends(e,t),e.prototype.queue=function(t,e,n){var i,r={func:t,namespace:e,type:n};e&&(i=this.waitsByNamespace[e]),this.waitNamespace&&(e===this.waitNamespace&&null!=i?this.delayWait(i):(this.clearWait(),this.tryStart())),this.compoundTask(r)&&(this.waitNamespace||null==i?this.tryStart():this.startWait(e,i))},e.prototype.startWait=function(t,e){this.waitNamespace=t,this.spawnWait(e)},e.prototype.delayWait=function(t){clearTimeout(this.waitId),this.spawnWait(t)},e.prototype.spawnWait=function(t){var e=this;this.waitId=setTimeout(function(){e.waitNamespace=null,e.tryStart()},t)},e.prototype.clearWait=function(){this.waitNamespace&&(clearTimeout(this.waitId),this.waitId=null,this.waitNamespace=null)},e.prototype.canRunNext=function(){if(!t.prototype.canRunNext.call(this))return!1;if(this.waitNamespace){for(var e=this.q,n=0;n<e.length;n++)if(e[n].namespace!==this.waitNamespace)return!0;return!1}return!0},e.prototype.runTask=function(t){t.func()},e.prototype.compoundTask=function(t){var e,n,i=this.q,r=!0;if(t.namespace&&"destroy"===t.type)for(e=i.length-1;e>=0;e--)switch(n=i[e],n.type){case"init":r=!1;case"add":case"remove":i.splice(e,1)}return r&&i.push(t),r},e}(r.default);e.default=o},function(t,e,n){function i(t){var e,n,i,r=[];for(e in t)for(n=t[e].eventInstances,i=0;i<n.length;i++)r.push(n[i].toLegacy());return r}Object.defineProperty(e,"__esModule",{value:!0});var r=n(2),o=n(3),s=n(0),a=n(4),l=n(10),u=n(47),d=n(237),c=n(35),p=function(t){function e(n,i){var r=t.call(this)||this;return r.isRTL=!1,r.hitsNeededDepth=0,r.hasAllDayBusinessHours=!1,r.isDatesRendered=!1,n&&(r.view=n),i&&(r.options=i),r.uid=String(e.guid++),r.childrenByUid={},r.nextDayThreshold=s.duration(r.opt("nextDayThreshold")),r.isRTL=r.opt("isRTL"),r.fillRendererClass&&(r.fillRenderer=new r.fillRendererClass(r)),r.eventRendererClass&&(r.eventRenderer=new r.eventRendererClass(r,r.fillRenderer)),r.helperRendererClass&&r.eventRenderer&&(r.helperRenderer=new r.helperRendererClass(r,r.eventRenderer)),r.businessHourRendererClass&&r.fillRenderer&&(r.businessHourRenderer=new r.businessHourRendererClass(r,r.fillRenderer)),r}return r.__extends(e,t),e.prototype.addChild=function(t){return!this.childrenByUid[t.uid]&&(this.childrenByUid[t.uid]=t,!0)},e.prototype.removeChild=function(t){return!!this.childrenByUid[t.uid]&&(delete this.childrenByUid[t.uid],!0)},e.prototype.updateSize=function(t,e,n){this.callChildren("updateSize",arguments)},e.prototype.opt=function(t){return this._getView().opt(t)},e.prototype.publiclyTrigger=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=this._getCalendar();return n.publiclyTrigger.apply(n,t)},e.prototype.hasPublicHandlers=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n=this._getCalendar();return n.hasPublicHandlers.apply(n,t)},e.prototype.executeDateRender=function(t){this.dateProfile=t,this.renderDates(t),this.isDatesRendered=!0,this.callChildren("executeDateRender",arguments)},e.prototype.executeDateUnrender=function(){this.callChildren("executeDateUnrender",arguments),this.dateProfile=null,this.unrenderDates(),this.isDatesRendered=!1},e.prototype.renderDates=function(t){},e.prototype.unrenderDates=function(){},e.prototype.getNowIndicatorUnit=function(){},e.prototype.renderNowIndicator=function(t){this.callChildren("renderNowIndicator",arguments)},e.prototype.unrenderNowIndicator=function(){this.callChildren("unrenderNowIndicator",arguments)},e.prototype.renderBusinessHours=function(t){this.businessHourRenderer&&this.businessHourRenderer.render(t),this.callChildren("renderBusinessHours",arguments)},e.prototype.unrenderBusinessHours=function(){this.callChildren("unrenderBusinessHours",arguments),this.businessHourRenderer&&this.businessHourRenderer.unrender()},e.prototype.executeEventRender=function(t){this.eventRenderer?(this.eventRenderer.rangeUpdated(),this.eventRenderer.render(t)):this.renderEvents&&this.renderEvents(i(t)),this.callChildren("executeEventRender",arguments)},e.prototype.executeEventUnrender=function(){this.callChildren("executeEventUnrender",arguments),this.eventRenderer?this.eventRenderer.unrender():this.destroyEvents&&this.destroyEvents()},e.prototype.getBusinessHourSegs=function(){var t=this.getOwnBusinessHourSegs();return this.iterChildren(function(e){t.push.apply(t,e.getBusinessHourSegs())}),t},e.prototype.getOwnBusinessHourSegs=function(){return this.businessHourRenderer?this.businessHourRenderer.getSegs():[]},e.prototype.getEventSegs=function(){var t=this.getOwnEventSegs();return this.iterChildren(function(e){t.push.apply(t,e.getEventSegs())}),t},e.prototype.getOwnEventSegs=function(){return this.eventRenderer?this.eventRenderer.getSegs():[]},e.prototype.triggerAfterEventsRendered=function(){this.triggerAfterEventSegsRendered(this.getEventSegs()),this.publiclyTrigger("eventAfterAllRender",{context:this,args:[this]})},e.prototype.triggerAfterEventSegsRendered=function(t){var e=this;this.hasPublicHandlers("eventAfterRender")&&t.forEach(function(t){var n;t.el&&(n=t.footprint.getEventLegacy(),e.publiclyTrigger("eventAfterRender",{context:n,args:[n,t.el,e]}))})},e.prototype.triggerBeforeEventsDestroyed=function(){this.triggerBeforeEventSegsDestroyed(this.getEventSegs())},e.prototype.triggerBeforeEventSegsDestroyed=function(t){var e=this;this.hasPublicHandlers("eventDestroy")&&t.forEach(function(t){var n;t.el&&(n=t.footprint.getEventLegacy(),e.publiclyTrigger("eventDestroy",{context:n,args:[n,t.el,e]}))})},e.prototype.showEventsWithId=function(t){this.getEventSegs().forEach(function(e){e.footprint.eventDef.id===t&&e.el&&e.el.css("visibility","")}),this.callChildren("showEventsWithId",arguments)},e.prototype.hideEventsWithId=function(t){this.getEventSegs().forEach(function(e){e.footprint.eventDef.id===t&&e.el&&e.el.css("visibility","hidden")}),this.callChildren("hideEventsWithId",arguments)},e.prototype.renderDrag=function(t,e,n){var i=!1;return this.iterChildren(function(r){r.renderDrag(t,e,n)&&(i=!0)}),i},e.prototype.unrenderDrag=function(){this.callChildren("unrenderDrag",arguments)},e.prototype.renderEventResize=function(t,e,n){this.callChildren("renderEventResize",arguments)},e.prototype.unrenderEventResize=function(){this.callChildren("unrenderEventResize",arguments)},e.prototype.renderSelectionFootprint=function(t){this.renderHighlight(t),this.callChildren("renderSelectionFootprint",arguments)},e.prototype.unrenderSelection=function(){this.unrenderHighlight(),this.callChildren("unrenderSelection",arguments)},e.prototype.renderHighlight=function(t){this.fillRenderer&&this.fillRenderer.renderFootprint("highlight",t,{getClasses:function(){return["fc-highlight"]}}),this.callChildren("renderHighlight",arguments)},e.prototype.unrenderHighlight=function(){this.fillRenderer&&this.fillRenderer.unrender("highlight"),this.callChildren("unrenderHighlight",arguments)},e.prototype.hitsNeeded=function(){this.hitsNeededDepth++||this.prepareHits(),this.callChildren("hitsNeeded",arguments)},e.prototype.hitsNotNeeded=function(){this.hitsNeededDepth&&!--this.hitsNeededDepth&&this.releaseHits(),this.callChildren("hitsNotNeeded",arguments)},e.prototype.prepareHits=function(){},e.prototype.releaseHits=function(){},e.prototype.queryHit=function(t,e){var n,i,r=this.childrenByUid;for(n in r)if(i=r[n].queryHit(t,e))break;return i},e.prototype.getSafeHitFootprint=function(t){var e=this.getHitFootprint(t);return this.dateProfile.activeUnzonedRange.containsRange(e.unzonedRange)?e:null},e.prototype.getHitFootprint=function(t){},e.prototype.getHitEl=function(t){},e.prototype.eventRangesToEventFootprints=function(t){var e,n=[];for(e=0;e<t.length;e++)n.push.apply(n,this.eventRangeToEventFootprints(t[e]));return n},e.prototype.eventRangeToEventFootprints=function(t){return[c.eventRangeToEventFootprint(t)]},e.prototype.eventFootprintsToSegs=function(t){var e,n=[];for(e=0;e<t.length;e++)n.push.apply(n,this.eventFootprintToSegs(t[e]));return n},e.prototype.eventFootprintToSegs=function(t){var e,n,i,r=t.componentFootprint.unzonedRange;for(e=this.componentFootprintToSegs(t.componentFootprint),n=0;n<e.length;n++)i=e[n],r.isStart||(i.isStart=!1),r.isEnd||(i.isEnd=!1),i.footprint=t;return e},e.prototype.componentFootprintToSegs=function(t){return[]},e.prototype.callChildren=function(t,e){this.iterChildren(function(n){n[t].apply(n,e)})},e.prototype.iterChildren=function(t){var e,n=this.childrenByUid;for(e in n)t(n[e])},e.prototype._getCalendar=function(){var t=this;return t.calendar||t.view.calendar},e.prototype._getView=function(){return this.view},e.prototype._getDateProfile=function(){return this._getView().get("dateProfile")},e.prototype.buildGotoAnchorHtml=function(t,e,n){var i,r,s,u;return o.isPlainObject(t)?(i=t.date,r=t.type,s=t.forceOff):i=t,i=l.default(i),u={date:i.format("YYYY-MM-DD"),type:r||"day"},"string"==typeof e&&(n=e,e=null),e=e?" "+a.attrsToStr(e):"",n=n||"",!s&&this.opt("navLinks")?"<a"+e+' data-goto="'+a.htmlEscape(JSON.stringify(u))+'">'+n+"</a>":"<span"+e+">"+n+"</span>"},e.prototype.getAllDayHtml=function(){return this.opt("allDayHtml")||a.htmlEscape(this.opt("allDayText"))},e.prototype.getDayClasses=function(t,e){var n,i=this._getView(),r=[]
+;return this.dateProfile.activeUnzonedRange.containsDate(t)?(r.push("fc-"+a.dayIDs[t.day()]),i.isDateInOtherMonth(t,this.dateProfile)&&r.push("fc-other-month"),n=i.calendar.getNow(),t.isSame(n,"day")?(r.push("fc-today"),!0!==e&&r.push(i.calendar.theme.getClass("today"))):t<n?r.push("fc-past"):r.push("fc-future")):r.push("fc-disabled-day"),r},e.prototype.formatRange=function(t,e,n,i){var r=t.end;return e&&(r=r.clone().subtract(1)),u.formatRange(t.start,r,n,i,this.isRTL)},e.prototype.currentRangeAs=function(t){return this._getDateProfile().currentUnzonedRange.as(t)},e.prototype.computeDayRange=function(t){var e=this._getCalendar(),n=e.msToUtcMoment(t.startMs,!0),i=e.msToUtcMoment(t.endMs),r=+i.time(),o=i.clone().stripTime();return r&&r>=this.nextDayThreshold&&o.add(1,"days"),o<=n&&(o=n.clone().add(1,"days")),{start:n,end:o}},e.prototype.isMultiDayRange=function(t){var e=this.computeDayRange(t);return e.end.diff(e.start,"days")>1},e.guid=0,e}(d.default);e.default=p},function(t,e,n){function i(t,e){return null==e?t:r.isFunction(e)?t.filter(e):(e+="",t.filter(function(t){return t.id==e||t._id===e}))}Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),o=n(0),s=n(4),a=n(32),l=n(238),u=n(21),d=n(11),c=n(7),p=n(239),h=n(240),f=n(241),g=n(207),v=n(31),y=n(10),m=n(5),b=n(12),w=n(17),D=n(242),E=n(212),S=n(38),C=n(49),R=n(13),T=n(37),M=n(6),I=n(51),H=function(){function t(t,e){this.loadingLevel=0,this.ignoreUpdateViewSize=0,this.freezeContentHeightDepth=0,u.default.needed(),this.el=t,this.viewsByType={},this.optionsManager=new h.default(this,e),this.viewSpecManager=new f.default(this.optionsManager,this),this.initMomentInternals(),this.initCurrentDate(),this.initEventManager(),this.constraints=new g.default(this.eventManager,this),this.constructed()}return t.prototype.constructed=function(){},t.prototype.getView=function(){return this.view},t.prototype.publiclyTrigger=function(t,e){var n,i,o=this.opt(t);if(r.isPlainObject(e)?(n=e.context,i=e.args):r.isArray(e)&&(i=e),null==n&&(n=this.el[0]),i||(i=[]),this.triggerWith(t,n,i),o)return o.apply(n,i)},t.prototype.hasPublicHandlers=function(t){return this.hasHandlers(t)||this.opt(t)},t.prototype.option=function(t,e){var n;if("string"==typeof t){if(void 0===e)return this.optionsManager.get(t);n={},n[t]=e,this.optionsManager.add(n)}else"object"==typeof t&&this.optionsManager.add(t)},t.prototype.opt=function(t){return this.optionsManager.get(t)},t.prototype.instantiateView=function(t){var e=this.viewSpecManager.getViewSpec(t);if(!e)throw new Error('View type "'+t+'" is not valid');return new e.class(this,e)},t.prototype.isValidViewType=function(t){return Boolean(this.viewSpecManager.getViewSpec(t))},t.prototype.changeView=function(t,e){e&&(e.start&&e.end?this.optionsManager.recordOverrides({visibleRange:e}):this.currentDate=this.moment(e).stripZone()),this.renderView(t)},t.prototype.zoomTo=function(t,e){var n;e=e||"day",n=this.viewSpecManager.getViewSpec(e)||this.viewSpecManager.getUnitViewSpec(e),this.currentDate=t.clone(),this.renderView(n?n.type:null)},t.prototype.initCurrentDate=function(){var t=this.opt("defaultDate");this.currentDate=null!=t?this.moment(t).stripZone():this.getNow()},t.prototype.prev=function(){var t=this.view,e=t.dateProfileGenerator.buildPrev(t.get("dateProfile"));e.isValid&&(this.currentDate=e.date,this.renderView())},t.prototype.next=function(){var t=this.view,e=t.dateProfileGenerator.buildNext(t.get("dateProfile"));e.isValid&&(this.currentDate=e.date,this.renderView())},t.prototype.prevYear=function(){this.currentDate.add(-1,"years"),this.renderView()},t.prototype.nextYear=function(){this.currentDate.add(1,"years"),this.renderView()},t.prototype.today=function(){this.currentDate=this.getNow(),this.renderView()},t.prototype.gotoDate=function(t){this.currentDate=this.moment(t).stripZone(),this.renderView()},t.prototype.incrementDate=function(t){this.currentDate.add(o.duration(t)),this.renderView()},t.prototype.getDate=function(){return this.applyTimezone(this.currentDate)},t.prototype.pushLoading=function(){this.loadingLevel++||this.publiclyTrigger("loading",[!0,this.view])},t.prototype.popLoading=function(){--this.loadingLevel||this.publiclyTrigger("loading",[!1,this.view])},t.prototype.render=function(){this.contentEl?this.elementVisible()&&(this.calcSize(),this.updateViewSize()):this.initialRender()},t.prototype.initialRender=function(){var t=this,e=this.el;e.addClass("fc"),e.on("click.fc","a[data-goto]",function(e){var n=r(e.currentTarget),i=n.data("goto"),o=t.moment(i.date),a=i.type,l=t.view.opt("navLink"+s.capitaliseFirstLetter(a)+"Click");"function"==typeof l?l(o,e):("string"==typeof l&&(a=l),t.zoomTo(o,a))}),this.optionsManager.watch("settingTheme",["?theme","?themeSystem"],function(n){var i=I.getThemeSystemClass(n.themeSystem||n.theme),r=new i(t.optionsManager),o=r.getClass("widget");t.theme=r,o&&e.addClass(o)},function(){var n=t.theme.getClass("widget");t.theme=null,n&&e.removeClass(n)}),this.optionsManager.watch("settingBusinessHourGenerator",["?businessHours"],function(e){t.businessHourGenerator=new E.default(e.businessHours,t),t.view&&t.view.set("businessHourGenerator",t.businessHourGenerator)},function(){t.businessHourGenerator=null}),this.optionsManager.watch("applyingDirClasses",["?isRTL","?locale"],function(t){e.toggleClass("fc-ltr",!t.isRTL),e.toggleClass("fc-rtl",t.isRTL)}),this.contentEl=r("<div class='fc-view-container'/>").prependTo(e),this.initToolbars(),this.renderHeader(),this.renderFooter(),this.renderView(this.opt("defaultView")),this.opt("handleWindowResize")&&r(window).resize(this.windowResizeProxy=s.debounce(this.windowResize.bind(this),this.opt("windowResizeDelay")))},t.prototype.destroy=function(){this.view&&this.clearView(),this.toolbarsManager.proxyCall("removeElement"),this.contentEl.remove(),this.el.removeClass("fc fc-ltr fc-rtl"),this.optionsManager.unwatch("settingTheme"),this.optionsManager.unwatch("settingBusinessHourGenerator"),this.el.off(".fc"),this.windowResizeProxy&&(r(window).unbind("resize",this.windowResizeProxy),this.windowResizeProxy=null),u.default.unneeded()},t.prototype.elementVisible=function(){return this.el.is(":visible")},t.prototype.bindViewHandlers=function(t){var e=this;t.watch("titleForCalendar",["title"],function(n){t===e.view&&e.setToolbarsTitle(n.title)}),t.watch("dateProfileForCalendar",["dateProfile"],function(n){t===e.view&&(e.currentDate=n.dateProfile.date,e.updateToolbarButtons(n.dateProfile))})},t.prototype.unbindViewHandlers=function(t){t.unwatch("titleForCalendar"),t.unwatch("dateProfileForCalendar")},t.prototype.renderView=function(t){var e,n=this.view;this.freezeContentHeight(),n&&t&&n.type!==t&&this.clearView(),!this.view&&t&&(e=this.view=this.viewsByType[t]||(this.viewsByType[t]=this.instantiateView(t)),this.bindViewHandlers(e),e.startBatchRender(),e.setElement(r("<div class='fc-view fc-"+t+"-view' />").appendTo(this.contentEl)),this.toolbarsManager.proxyCall("activateButton",t)),this.view&&(this.view.get("businessHourGenerator")!==this.businessHourGenerator&&this.view.set("businessHourGenerator",this.businessHourGenerator),this.view.setDate(this.currentDate),e&&e.stopBatchRender()),this.thawContentHeight()},t.prototype.clearView=function(){var t=this.view;this.toolbarsManager.proxyCall("deactivateButton",t.type),this.unbindViewHandlers(t),t.removeElement(),t.unsetDate(),this.view=null},t.prototype.reinitView=function(){var t=this.view,e=t.queryScroll();this.freezeContentHeight(),this.clearView(),this.calcSize(),this.renderView(t.type),this.view.applyScroll(e),this.thawContentHeight()},t.prototype.getSuggestedViewHeight=function(){return null==this.suggestedViewHeight&&this.calcSize(),this.suggestedViewHeight},t.prototype.isHeightAuto=function(){return"auto"===this.opt("contentHeight")||"auto"===this.opt("height")},t.prototype.updateViewSize=function(t){void 0===t&&(t=!1);var e,n=this.view;if(!this.ignoreUpdateViewSize&&n)return t&&(this.calcSize(),e=n.queryScroll()),this.ignoreUpdateViewSize++,n.updateSize(this.getSuggestedViewHeight(),this.isHeightAuto(),t),this.ignoreUpdateViewSize--,t&&n.applyScroll(e),!0},t.prototype.calcSize=function(){this.elementVisible()&&this._calcSize()},t.prototype._calcSize=function(){var t=this.opt("contentHeight"),e=this.opt("height");this.suggestedViewHeight="number"==typeof t?t:"function"==typeof t?t():"number"==typeof e?e-this.queryToolbarsHeight():"function"==typeof e?e()-this.queryToolbarsHeight():"parent"===e?this.el.parent().height()-this.queryToolbarsHeight():Math.round(this.contentEl.width()/Math.max(this.opt("aspectRatio"),.5))},t.prototype.windowResize=function(t){t.target===window&&this.view&&this.view.isDatesRendered&&this.updateViewSize(!0)&&this.publiclyTrigger("windowResize",[this.view])},t.prototype.freezeContentHeight=function(){this.freezeContentHeightDepth++||this.forceFreezeContentHeight()},t.prototype.forceFreezeContentHeight=function(){this.contentEl.css({width:"100%",height:this.contentEl.height(),overflow:"hidden"})},t.prototype.thawContentHeight=function(){this.freezeContentHeightDepth--,this.contentEl.css({width:"",height:"",overflow:""}),this.freezeContentHeightDepth&&this.forceFreezeContentHeight()},t.prototype.initToolbars=function(){this.header=new p.default(this,this.computeHeaderOptions()),this.footer=new p.default(this,this.computeFooterOptions()),this.toolbarsManager=new l.default([this.header,this.footer])},t.prototype.computeHeaderOptions=function(){return{extraClasses:"fc-header-toolbar",layout:this.opt("header")}},t.prototype.computeFooterOptions=function(){return{extraClasses:"fc-footer-toolbar",layout:this.opt("footer")}},t.prototype.renderHeader=function(){var t=this.header;t.setToolbarOptions(this.computeHeaderOptions()),t.render(),t.el&&this.el.prepend(t.el)},t.prototype.renderFooter=function(){var t=this.footer;t.setToolbarOptions(this.computeFooterOptions()),t.render(),t.el&&this.el.append(t.el)},t.prototype.setToolbarsTitle=function(t){this.toolbarsManager.proxyCall("updateTitle",t)},t.prototype.updateToolbarButtons=function(t){var e=this.getNow(),n=this.view,i=n.dateProfileGenerator.build(e),r=n.dateProfileGenerator.buildPrev(n.get("dateProfile")),o=n.dateProfileGenerator.buildNext(n.get("dateProfile"));this.toolbarsManager.proxyCall(i.isValid&&!t.currentUnzonedRange.containsDate(e)?"enableButton":"disableButton","today"),this.toolbarsManager.proxyCall(r.isValid?"enableButton":"disableButton","prev"),this.toolbarsManager.proxyCall(o.isValid?"enableButton":"disableButton","next")},t.prototype.queryToolbarsHeight=function(){return this.toolbarsManager.items.reduce(function(t,e){return t+(e.el?e.el.outerHeight(!0):0)},0)},t.prototype.select=function(t,e){this.view.select(this.buildSelectFootprint.apply(this,arguments))},t.prototype.unselect=function(){this.view&&this.view.unselect()},t.prototype.buildSelectFootprint=function(t,e){var n,i=this.moment(t).stripZone();return n=e?this.moment(e).stripZone():i.hasTime()?i.clone().add(this.defaultTimedEventDuration):i.clone().add(this.defaultAllDayEventDuration),new b.default(new m.default(i,n),!i.hasTime())},t.prototype.initMomentInternals=function(){var t=this;this.defaultAllDayEventDuration=o.duration(this.opt("defaultAllDayEventDuration")),this.defaultTimedEventDuration=o.duration(this.opt("defaultTimedEventDuration")),this.optionsManager.watch("buildingMomentLocale",["?locale","?monthNames","?monthNamesShort","?dayNames","?dayNamesShort","?firstDay","?weekNumberCalculation"],function(e){var n,i=e.weekNumberCalculation,r=e.firstDay;"iso"===i&&(i="ISO");var o=Object.create(v.getMomentLocaleData(e.locale));e.monthNames&&(o._months=e.monthNames),e.monthNamesShort&&(o._monthsShort=e.monthNamesShort),e.dayNames&&(o._weekdays=e.dayNames),e.dayNamesShort&&(o._weekdaysShort=e.dayNamesShort),null==r&&"ISO"===i&&(r=1),null!=r&&(n=Object.create(o._week),n.dow=r,o._week=n),"ISO"!==i&&"local"!==i&&"function"!=typeof i||(o._fullCalendar_weekCalc=i),t.localeData=o,t.currentDate&&t.localizeMoment(t.currentDate)})},t.prototype.moment=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];var n;return"local"===this.opt("timezone")?(n=y.default.apply(null,t),n.hasTime()&&n.local()):n="UTC"===this.opt("timezone")?y.default.utc.apply(null,t):y.default.parseZone.apply(null,t),this.localizeMoment(n),n},t.prototype.msToMoment=function(t,e){var n=y.default.utc(t);return e?n.stripTime():n=this.applyTimezone(n),this.localizeMoment(n),n},t.prototype.msToUtcMoment=function(t,e){var n=y.default.utc(t);return e&&n.stripTime(),this.localizeMoment(n),n},t.prototype.localizeMoment=function(t){t._locale=this.localeData},t.prototype.getIsAmbigTimezone=function(){return"local"!==this.opt("timezone")&&"UTC"!==this.opt("timezone")},t.prototype.applyTimezone=function(t){if(!t.hasTime())return t.clone();var e,n=this.moment(t.toArray()),i=t.time().asMilliseconds()-n.time().asMilliseconds();return i&&(e=n.clone().add(i),t.time().asMilliseconds()-e.time().asMilliseconds()==0&&(n=e)),n},t.prototype.footprintToDateProfile=function(t,e){void 0===e&&(e=!1);var n,i=y.default.utc(t.unzonedRange.startMs);return e||(n=y.default.utc(t.unzonedRange.endMs)),t.isAllDay?(i.stripTime(),n&&n.stripTime()):(i=this.applyTimezone(i),n&&(n=this.applyTimezone(n))),new w.default(i,n,this)},t.prototype.getNow=function(){var t=this.opt("now");return"function"==typeof t&&(t=t()),this.moment(t).stripZone()},t.prototype.humanizeDuration=function(t){return t.locale(this.opt("locale")).humanize()},t.prototype.parseUnzonedRange=function(t){var e=null,n=null;return t.start&&(e=this.moment(t.start).stripZone()),t.end&&(n=this.moment(t.end).stripZone()),e||n?e&&n&&n.isBefore(e)?null:new m.default(e,n):null},t.prototype.initEventManager=function(){var t=this,e=new D.default(this),n=this.opt("eventSources")||[],i=this.opt("events");this.eventManager=e,i&&n.unshift(i),e.on("release",function(e){t.trigger("eventsReset",e)}),e.freeze(),n.forEach(function(n){var i=S.default.parse(n,t);i&&e.addSource(i)}),e.thaw()},t.prototype.requestEvents=function(t,e){return this.eventManager.requestEvents(t,e,this.opt("timezone"),!this.opt("lazyFetching"))},t.prototype.getEventEnd=function(t){return t.end?t.end.clone():this.getDefaultEventEnd(t.allDay,t.start)},t.prototype.getDefaultEventEnd=function(t,e){var n=e.clone();return t?n.stripTime().add(this.defaultAllDayEventDuration):n.add(this.defaultTimedEventDuration),this.getIsAmbigTimezone()&&n.stripZone(),n},t.prototype.rerenderEvents=function(){this.view.flash("displayingEvents")},t.prototype.refetchEvents=function(){this.eventManager.refetchAllSources()},t.prototype.renderEvents=function(t,e){this.eventManager.freeze();for(var n=0;n<t.length;n++)this.renderEvent(t[n],e);this.eventManager.thaw()},t.prototype.renderEvent=function(t,e){void 0===e&&(e=!1);var n=this.eventManager,i=C.default.parse(t,t.source||n.stickySource);i&&n.addEventDef(i,e)},t.prototype.removeEvents=function(t){var e,n,r=this.eventManager,o=[],s={};if(null==t)r.removeAllEventDefs();else{for(r.getEventInstances().forEach(function(t){o.push(t.toLegacy())}),o=i(o,t),n=0;n<o.length;n++)e=this.eventManager.getEventDefByUid(o[n]._id),s[e.id]=!0;r.freeze();for(n in s)r.removeEventDefsById(n);r.thaw()}},t.prototype.clientEvents=function(t){var e=[];return this.eventManager.getEventInstances().forEach(function(t){e.push(t.toLegacy())}),i(e,t)},t.prototype.updateEvents=function(t){this.eventManager.freeze();for(var e=0;e<t.length;e++)this.updateEvent(t[e]);this.eventManager.thaw()},t.prototype.updateEvent=function(t){var e,n,i=this.eventManager.getEventDefByUid(t._id);i instanceof R.default&&(e=i.buildInstance(),n=T.default.createFromRawProps(e,t,null),this.eventManager.mutateEventsWithId(i.id,n))},t.prototype.getEventSources=function(){return this.eventManager.otherSources.slice()},t.prototype.getEventSourceById=function(t){return this.eventManager.getSourceById(M.default.normalizeId(t))},t.prototype.addEventSource=function(t){var e=S.default.parse(t,this);e&&this.eventManager.addSource(e)},t.prototype.removeEventSources=function(t){var e,n,i=this.eventManager;if(null==t)this.eventManager.removeAllSources();else{for(e=i.multiQuerySources(t),i.freeze(),n=0;n<e.length;n++)i.removeSource(e[n]);i.thaw()}},t.prototype.removeEventSource=function(t){var e,n=this.eventManager,i=n.querySources(t);for(n.freeze(),e=0;e<i.length;e++)n.removeSource(i[e]);n.thaw()},t.prototype.refetchEventSources=function(t){var e,n=this.eventManager,i=n.multiQuerySources(t);for(n.freeze(),e=0;e<i.length;e++)n.refetchSource(i[e]);n.thaw()},t.defaults=a.globalDefaults,t.englishDefaults=a.englishDefaults,t.rtlDefaults=a.rtlDefaults,t}();e.default=H,d.default.mixInto(H),c.default.mixInto(H)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(0),r=n(4),o=n(5),s=function(){function t(t){this._view=t}return t.prototype.opt=function(t){return this._view.opt(t)},t.prototype.trimHiddenDays=function(t){return this._view.trimHiddenDays(t)},t.prototype.msToUtcMoment=function(t,e){return this._view.calendar.msToUtcMoment(t,e)},t.prototype.buildPrev=function(t){var e=t.date.clone().startOf(t.currentRangeUnit).subtract(t.dateIncrement);return this.build(e,-1)},t.prototype.buildNext=function(t){var e=t.date.clone().startOf(t.currentRangeUnit).add(t.dateIncrement);return this.build(e,1)},t.prototype.build=function(t,e,n){void 0===n&&(n=!1);var r,o,s,a,l,u,d=!t.hasTime(),c=null,p=null;return r=this.buildValidRange(),r=this.trimHiddenDays(r),n&&(t=this.msToUtcMoment(r.constrainDate(t),d)),o=this.buildCurrentRangeInfo(t,e),s=/^(year|month|week|day)$/.test(o.unit),a=this.buildRenderRange(this.trimHiddenDays(o.unzonedRange),o.unit,s),a=this.trimHiddenDays(a),l=a.clone(),this.opt("showNonCurrentDates")||(l=l.intersect(o.unzonedRange)),c=i.duration(this.opt("minTime")),p=i.duration(this.opt("maxTime")),l=this.adjustActiveRange(l,c,p),l=l.intersect(r),l&&(t=this.msToUtcMoment(l.constrainDate(t),d)),u=o.unzonedRange.intersectsWith(r),{validUnzonedRange:r,currentUnzonedRange:o.unzonedRange,currentRangeUnit:o.unit,isRangeAllDay:s,activeUnzonedRange:l,renderUnzonedRange:a,minTime:c,maxTime:p,isValid:u,date:t,dateIncrement:this.buildDateIncrement(o.duration)}},t.prototype.buildValidRange=function(){return this._view.getUnzonedRangeOption("validRange",this._view.calendar.getNow())||new o.default},t.prototype.buildCurrentRangeInfo=function(t,e){var n,i=this._view.viewSpec,o=null,s=null,a=null;return i.duration?(o=i.duration,s=i.durationUnit,a=this.buildRangeFromDuration(t,e,o,s)):(n=this.opt("dayCount"))?(s="day",a=this.buildRangeFromDayCount(t,e,n)):(a=this.buildCustomVisibleRange(t))?s=r.computeGreatestUnit(a.getStart(),a.getEnd()):(o=this.getFallbackDuration(),s=r.computeGreatestUnit(o),a=this.buildRangeFromDuration(t,e,o,s)),{duration:o,unit:s,unzonedRange:a}},t.prototype.getFallbackDuration=function(){return i.duration({days:1})},t.prototype.adjustActiveRange=function(t,e,n){var i=t.getStart(),r=t.getEnd();return this._view.usesMinMaxTime&&(e<0&&i.time(0).add(e),n>864e5&&r.time(n-864e5)),new o.default(i,r)},t.prototype.buildRangeFromDuration=function(t,e,n,s){function a(){d=t.clone().startOf(h),c=d.clone().add(n),p=new o.default(d,c)}var l,u,d,c,p,h=this.opt("dateAlignment");return h||(l=this.opt("dateIncrement"),l?(u=i.duration(l),h=u<n?r.computeDurationGreatestUnit(u,l):s):h=s),n.as("days")<=1&&this._view.isHiddenDay(d)&&(d=this._view.skipHiddenDays(d,e),d.startOf("day")),a(),this.trimHiddenDays(p)||(t=this._view.skipHiddenDays(t,e),a()),p},t.prototype.buildRangeFromDayCount=function(t,e,n){var i,r=this.opt("dateAlignment"),s=0,a=t.clone();r&&a.startOf(r),a.startOf("day"),a=this._view.skipHiddenDays(a,e),i=a.clone();do{i.add(1,"day"),this._view.isHiddenDay(i)||s++}while(s<n);return new o.default(a,i)},t.prototype.buildCustomVisibleRange=function(t){var e=this._view.getUnzonedRangeOption("visibleRange",this._view.calendar.applyTimezone(t));return!e||null!=e.startMs&&null!=e.endMs?e:null},t.prototype.buildRenderRange=function(t,e,n){return t.clone()},t.prototype.buildDateIncrement=function(t){var e,n=this.opt("dateIncrement");return n?i.duration(n):(e=this.opt("dateAlignment"))?i.duration(1,e):t||i.duration({days:1})},t}();e.default=s},function(t,e,n){function i(t){var e,n,i,r,l=a.dataAttrPrefix;return l&&(l+="-"),e=t.data(l+"event")||null,e&&(e="object"==typeof e?o.extend({},e):{},n=e.start,null==n&&(n=e.time),i=e.duration,r=e.stick,delete e.start,delete e.time,delete e.duration,delete e.stick),null==n&&(n=t.data(l+"start")),null==n&&(n=t.data(l+"time")),null==i&&(i=t.data(l+"duration")),null==r&&(r=t.data(l+"stick")),n=null!=n?s.duration(n):null,i=null!=i?s.duration(i):null,r=Boolean(r),{eventProps:e,startTime:n,duration:i,stick:r}}Object.defineProperty(e,"__esModule",{value:!0});var r=n(2),o=n(3),s=n(0),a=n(16),l=n(4),u=n(10),d=n(7),c=n(23),p=n(13),h=n(18),f=n(6),g=n(15),v=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.isDragging=!1,e}return r.__extends(e,t),e.prototype.end=function(){this.dragListener&&this.dragListener.endInteraction()},e.prototype.bindToDocument=function(){this.listenTo(o(document),{dragstart:this.handleDragStart,sortstart:this.handleDragStart})},e.prototype.unbindFromDocument=function(){this.stopListeningTo(o(document))},e.prototype.handleDragStart=function(t,e){var n,i;this.opt("droppable")&&(n=o((e?e.item:null)||t.target),i=this.opt("dropAccept"),(o.isFunction(i)?i.call(n[0],n):n.is(i))&&(this.isDragging||this.listenToExternalDrag(n,t,e)))},e.prototype.listenToExternalDrag=function(t,e,n){var r,o=this,s=this.component,a=this.view,u=i(t);(this.dragListener=new c.default(s,{interactionStart:function(){o.isDragging=!0},hitOver:function(t){var e,n=!0,i=t.component.getSafeHitFootprint(t);i?(r=o.computeExternalDrop(i,u),r?(e=new h.default(r.buildInstances()),n=u.eventProps?s.isEventInstanceGroupAllowed(e):s.isExternalInstanceGroupAllowed(e)):n=!1):n=!1,n||(r=null,l.disableCursor()),r&&s.renderDrag(s.eventRangesToEventFootprints(e.sliceRenderRanges(s.dateProfile.renderUnzonedRange,a.calendar)))},hitOut:function(){r=null},hitDone:function(){l.enableCursor(),s.unrenderDrag()},interactionEnd:function(e){r&&a.reportExternalDrop(r,Boolean(u.eventProps),Boolean(u.stick),t,e,n),o.isDragging=!1,o.dragListener=null}})).startDrag(e)},e.prototype.computeExternalDrop=function(t,e){var n,i=this.view.calendar,r=u.default.utc(t.unzonedRange.startMs).stripZone();return t.isAllDay&&(e.startTime?r.time(e.startTime):r.stripTime()),e.duration&&(n=r.clone().add(e.duration)),r=i.applyTimezone(r),n&&(n=i.applyTimezone(n)),p.default.parse(o.extend({},e.eventProps,{start:r,end:n}),new f.default(i))},e}(g.default);e.default=v,d.default.mixInto(v),a.dataAttrPrefix=""},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(37),a=n(50),l=n(23),u=n(15),d=function(t){function e(e,n){var i=t.call(this,e)||this;return i.isResizing=!1,i.eventPointing=n,i}return i.__extends(e,t),e.prototype.end=function(){this.dragListener&&this.dragListener.endInteraction()},e.prototype.bindToEl=function(t){var e=this.component;e.bindSegHandlerToEl(t,"mousedown",this.handleMouseDown.bind(this)),e.bindSegHandlerToEl(t,"touchstart",this.handleTouchStart.bind(this))},e.prototype.handleMouseDown=function(t,e){this.component.canStartResize(t,e)&&this.buildDragListener(t,r(e.target).is(".fc-start-resizer")).startInteraction(e,{distance:5})},e.prototype.handleTouchStart=function(t,e){this.component.canStartResize(t,e)&&this.buildDragListener(t,r(e.target).is(".fc-start-resizer")).startInteraction(e)},e.prototype.buildDragListener=function(t,e){var n,i,r=this,s=this.component,a=this.view,u=a.calendar,d=u.eventManager,c=t.el,p=t.footprint.eventDef,h=t.footprint.eventInstance;return this.dragListener=new l.default(s,{scroll:this.opt("dragScroll"),subjectEl:c,interactionStart:function(){n=!1},dragStart:function(e){n=!0,r.eventPointing.handleMouseout(t,e),r.segResizeStart(t,e)},hitOver:function(n,l,c){var h,f=!0,g=s.getSafeHitFootprint(c),v=s.getSafeHitFootprint(n);g&&v?(i=e?r.computeEventStartResizeMutation(g,v,t.footprint):r.computeEventEndResizeMutation(g,v,t.footprint),i?(h=d.buildMutatedEventInstanceGroup(p.id,i),f=s.isEventInstanceGroupAllowed(h)):f=!1):f=!1,f?i.isEmpty()&&(i=null):(i=null,o.disableCursor()),i&&(a.hideEventsWithId(t.footprint.eventDef.id),a.renderEventResize(s.eventRangesToEventFootprints(h.sliceRenderRanges(s.dateProfile.renderUnzonedRange,u)),t))},hitOut:function(){i=null},hitDone:function(){a.unrenderEventResize(t),a.showEventsWithId(t.footprint.eventDef.id),o.enableCursor()},interactionEnd:function(e){n&&r.segResizeStop(t,e),i&&a.reportEventResize(h,i,c,e),r.dragListener=null}})},e.prototype.segResizeStart=function(t,e){this.isResizing=!0,this.component.publiclyTrigger("eventResizeStart",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,{},this.view]})},e.prototype.segResizeStop=function(t,e){this.isResizing=!1,this.component.publiclyTrigger("eventResizeStop",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,{},this.view]})},e.prototype.computeEventStartResizeMutation=function(t,e,n){var i,r,o=n.componentFootprint.unzonedRange,l=this.component.diffDates(e.unzonedRange.getStart(),t.unzonedRange.getStart());return o.getStart().add(l)<o.getEnd()&&(i=new a.default,i.setStartDelta(l),r=new s.default,r.setDateMutation(i),r)},e.prototype.computeEventEndResizeMutation=function(t,e,n){var i,r,o=n.componentFootprint.unzonedRange,l=this.component.diffDates(e.unzonedRange.getEnd(),t.unzonedRange.getEnd());return o.getEnd().add(l)>o.getStart()&&(i=new a.default,i.setEndDelta(l),r=new s.default,r.setDateMutation(i),r)},e}(u.default);e.default=d},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=n(37),s=n(50),a=n(54),l=n(23),u=n(244),d=n(15),c=function(t){function e(e,n){var i=t.call(this,e)||this;return i.isDragging=!1,i.eventPointing=n,i}return i.__extends(e,t),e.prototype.end=function(){this.dragListener&&this.dragListener.endInteraction()},e.prototype.getSelectionDelay=function(){var t=this.opt("eventLongPressDelay");return null==t&&(t=this.opt("longPressDelay")),t},e.prototype.bindToEl=function(t){var e=this.component;e.bindSegHandlerToEl(t,"mousedown",this.handleMousedown.bind(this)),e.bindSegHandlerToEl(t,"touchstart",this.handleTouchStart.bind(this))},e.prototype.handleMousedown=function(t,e){!this.component.shouldIgnoreMouse()&&this.component.canStartDrag(t,e)&&this.buildDragListener(t).startInteraction(e,{distance:5})},e.prototype.handleTouchStart=function(t,e){var n=this.component,i={delay:this.view.isEventDefSelected(t.footprint.eventDef)?0:this.getSelectionDelay()};n.canStartDrag(t,e)?this.buildDragListener(t).startInteraction(e,i):n.canStartSelection(t,e)&&this.buildSelectListener(t).startInteraction(e,i)},e.prototype.buildSelectListener=function(t){var e=this,n=this.view,i=t.footprint.eventDef,r=t.footprint.eventInstance;if(this.dragListener)return this.dragListener;var o=this.dragListener=new a.default({dragStart:function(t){o.isTouch&&!n.isEventDefSelected(i)&&r&&n.selectEventInstance(r)},interactionEnd:function(t){e.dragListener=null}});return o},e.prototype.buildDragListener=function(t){var e,n,i,o=this,s=this.component,a=this.view,d=a.calendar,c=d.eventManager,p=t.el,h=t.footprint.eventDef,f=t.footprint.eventInstance;if(this.dragListener)return this.dragListener;var g=this.dragListener=new l.default(a,{scroll:this.opt("dragScroll"),subjectEl:p,subjectCenter:!0,interactionStart:function(i){t.component=s,e=!1,n=new u.default(t.el,{additionalClass:"fc-dragging",parentEl:a.el,opacity:g.isTouch?null:o.opt("dragOpacity"),revertDuration:o.opt("dragRevertDuration"),zIndex:2}),n.hide(),n.start(i)},dragStart:function(n){g.isTouch&&!a.isEventDefSelected(h)&&f&&a.selectEventInstance(f),e=!0,o.eventPointing.handleMouseout(t,n),o.segDragStart(t,n),a.hideEventsWithId(t.footprint.eventDef.id)},hitOver:function(e,l,u){var p,f,v,y=!0;t.hit&&(u=t.hit),p=u.component.getSafeHitFootprint(u),f=e.component.getSafeHitFootprint(e),p&&f?(i=o.computeEventDropMutation(p,f,h),i?(v=c.buildMutatedEventInstanceGroup(h.id,i),y=s.isEventInstanceGroupAllowed(v)):y=!1):y=!1,y||(i=null,r.disableCursor()),i&&a.renderDrag(s.eventRangesToEventFootprints(v.sliceRenderRanges(s.dateProfile.renderUnzonedRange,d)),t,g.isTouch)?n.hide():n.show(),l&&(i=null)},hitOut:function(){a.unrenderDrag(t),n.show(),i=null},hitDone:function(){r.enableCursor()},interactionEnd:function(r){delete t.component,n.stop(!i,function(){e&&(a.unrenderDrag(t),o.segDragStop(t,r)),a.showEventsWithId(t.footprint.eventDef.id),i&&a.reportEventDrop(f,i,p,r)}),o.dragListener=null}});return g},e.prototype.segDragStart=function(t,e){this.isDragging=!0,this.component.publiclyTrigger("eventDragStart",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,{},this.view]})},e.prototype.segDragStop=function(t,e){this.isDragging=!1,this.component.publiclyTrigger("eventDragStop",{context:t.el[0],args:[t.footprint.getEventLegacy(),e,{},this.view]})},e.prototype.computeEventDropMutation=function(t,e,n){var i=new o.default;return i.setDateMutation(this.computeEventDateMutation(t,e)),i},e.prototype.computeEventDateMutation=function(t,e){var n,i,r=t.unzonedRange.getStart(),o=e.unzonedRange.getStart(),a=!1,l=!1,u=!1;return t.isAllDay!==e.isAllDay&&(a=!0,e.isAllDay?(u=!0,r.stripTime()):l=!0),n=this.component.diffDates(o,r),i=new s.default,i.clearEnd=a,i.forceTimed=l,i.forceAllDay=u,i.setDateDelta(n),i},e}(d.default);e.default=c},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=n(23),s=n(12),a=n(5),l=n(15),u=function(t){function e(e){var n=t.call(this,e)||this;return n.dragListener=n.buildDragListener(),n}return i.__extends(e,t),e.prototype.end=function(){this.dragListener.endInteraction()},e.prototype.getDelay=function(){var t=this.opt("selectLongPressDelay");return null==t&&(t=this.opt("longPressDelay")),t},e.prototype.bindToEl=function(t){var e=this,n=this.component,i=this.dragListener;n.bindDateHandlerToEl(t,"mousedown",function(t){e.opt("selectable")&&!n.shouldIgnoreMouse()&&i.startInteraction(t,{distance:e.opt("selectMinDistance")})}),n.bindDateHandlerToEl(t,"touchstart",function(t){e.opt("selectable")&&!n.shouldIgnoreTouch()&&i.startInteraction(t,{delay:e.getDelay()})}),r.preventSelection(t)},e.prototype.buildDragListener=function(){var t,e=this,n=this.component;return new o.default(n,{scroll:this.opt("dragScroll"),interactionStart:function(){t=null},dragStart:function(t){e.view.unselect(t)},hitOver:function(i,o,s){var a,l;s&&(a=n.getSafeHitFootprint(s),l=n.getSafeHitFootprint(i),t=a&&l?e.computeSelection(a,l):null,t?n.renderSelectionFootprint(t):!1===t&&r.disableCursor())},hitOut:function(){t=null,n.unrenderSelection()},hitDone:function(){r.enableCursor()},interactionEnd:function(n,i){!i&&t&&e.view.reportSelection(t,n)}})},e.prototype.computeSelection=function(t,e){var n=this.computeSelectionFootprint(t,e);return!(n&&!this.isSelectionFootprintAllowed(n))&&n},e.prototype.computeSelectionFootprint=function(t,e){var n=[t.unzonedRange.startMs,t.unzonedRange.endMs,e.unzonedRange.startMs,e.unzonedRange.endMs];return n.sort(r.compareNumbers),new s.default(new a.default(n[0],n[3]),t.isAllDay)},e.prototype.isSelectionFootprintAllowed=function(t){return this.component.dateProfile.validUnzonedRange.containsRange(t.unzonedRange)&&this.view.calendar.constraints.isSelectionFootprintAllowed(t)},e}(l.default);e.default=u},function(t,e,n){function i(t){var e,n=[],i=[];for(e=0;e<t.length;e++)t[e].componentFootprint.isAllDay?n.push(t[e]):i.push(t[e]);return{allDay:n,timed:i}}Object.defineProperty(e,"__esModule",{value:!0});var r,o,s=n(2),a=n(0),l=n(3),u=n(4),d=n(39),c=n(41),p=n(227),h=n(61),f=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.usesMinMaxTime=!0,i.timeGrid=i.instantiateTimeGrid(),i.addChild(i.timeGrid),i.opt("allDaySlot")&&(i.dayGrid=i.instantiateDayGrid(),i.addChild(i.dayGrid)),i.scroller=new d.default({overflowX:"hidden",overflowY:"auto"}),i}
+return s.__extends(e,t),e.prototype.instantiateTimeGrid=function(){var t=new this.timeGridClass(this);return u.copyOwnProps(r,t),t},e.prototype.instantiateDayGrid=function(){var t=new this.dayGridClass(this);return u.copyOwnProps(o,t),t},e.prototype.renderSkeleton=function(){var t,e;this.el.addClass("fc-agenda-view").html(this.renderSkeletonHtml()),this.scroller.render(),t=this.scroller.el.addClass("fc-time-grid-container"),e=l('<div class="fc-time-grid" />').appendTo(t),this.el.find(".fc-body > tr > td").append(t),this.timeGrid.headContainerEl=this.el.find(".fc-head-container"),this.timeGrid.setElement(e),this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight())},e.prototype.unrenderSkeleton=function(){this.timeGrid.removeElement(),this.dayGrid&&this.dayGrid.removeElement(),this.scroller.destroy()},e.prototype.renderSkeletonHtml=function(){var t=this.calendar.theme;return'<table class="'+t.getClass("tableGrid")+'">'+(this.opt("columnHeader")?'<thead class="fc-head"><tr><td class="fc-head-container '+t.getClass("widgetHeader")+'">&nbsp;</td></tr></thead>':"")+'<tbody class="fc-body"><tr><td class="'+t.getClass("widgetContent")+'">'+(this.dayGrid?'<div class="fc-day-grid"/><hr class="fc-divider '+t.getClass("widgetHeader")+'"/>':"")+"</td></tr></tbody></table>"},e.prototype.axisStyleAttr=function(){return null!=this.axisWidth?'style="width:'+this.axisWidth+'px"':""},e.prototype.getNowIndicatorUnit=function(){return this.timeGrid.getNowIndicatorUnit()},e.prototype.updateSize=function(e,n,i){var r,o,s;if(t.prototype.updateSize.call(this,e,n,i),this.axisWidth=u.matchCellWidths(this.el.find(".fc-axis")),!this.timeGrid.colEls)return void(n||(o=this.computeScrollerHeight(e),this.scroller.setHeight(o)));var a=this.el.find(".fc-row:not(.fc-scroller *)");this.timeGrid.bottomRuleEl.hide(),this.scroller.clear(),u.uncompensateScroll(a),this.dayGrid&&(this.dayGrid.removeSegPopover(),r=this.opt("eventLimit"),r&&"number"!=typeof r&&(r=5),r&&this.dayGrid.limitRows(r)),n||(o=this.computeScrollerHeight(e),this.scroller.setHeight(o),s=this.scroller.getScrollbarWidths(),(s.left||s.right)&&(u.compensateScroll(a,s),o=this.computeScrollerHeight(e),this.scroller.setHeight(o)),this.scroller.lockOverflow(s),this.timeGrid.getTotalSlatHeight()<o&&this.timeGrid.bottomRuleEl.show())},e.prototype.computeScrollerHeight=function(t){return t-u.subtractInnerElHeight(this.el,this.scroller.el)},e.prototype.computeInitialDateScroll=function(){var t=a.duration(this.opt("scrollTime")),e=this.timeGrid.computeTimeTop(t);return e=Math.ceil(e),e&&e++,{top:e}},e.prototype.queryDateScroll=function(){return{top:this.scroller.getScrollTop()}},e.prototype.applyDateScroll=function(t){void 0!==t.top&&this.scroller.setScrollTop(t.top)},e.prototype.getHitFootprint=function(t){return t.component.getHitFootprint(t)},e.prototype.getHitEl=function(t){return t.component.getHitEl(t)},e.prototype.executeEventRender=function(t){var e,n,i={},r={};for(e in t)n=t[e],n.getEventDef().isAllDay()?i[e]=n:r[e]=n;this.timeGrid.executeEventRender(r),this.dayGrid&&this.dayGrid.executeEventRender(i)},e.prototype.renderDrag=function(t,e,n){var r=i(t),o=!1;return o=this.timeGrid.renderDrag(r.timed,e,n),this.dayGrid&&(o=this.dayGrid.renderDrag(r.allDay,e,n)||o),o},e.prototype.renderEventResize=function(t,e,n){var r=i(t);this.timeGrid.renderEventResize(r.timed,e,n),this.dayGrid&&this.dayGrid.renderEventResize(r.allDay,e,n)},e.prototype.renderSelectionFootprint=function(t){t.isAllDay?this.dayGrid&&this.dayGrid.renderSelectionFootprint(t):this.timeGrid.renderSelectionFootprint(t)},e}(c.default);e.default=f,f.prototype.timeGridClass=p.default,f.prototype.dayGridClass=h.default,r={renderHeadIntroHtml:function(){var t,e=this.view,n=e.calendar,i=n.msToUtcMoment(this.dateProfile.renderUnzonedRange.startMs,!0);return this.opt("weekNumbers")?(t=i.format(this.opt("smallWeekFormat")),'<th class="fc-axis fc-week-number '+n.theme.getClass("widgetHeader")+'" '+e.axisStyleAttr()+">"+e.buildGotoAnchorHtml({date:i,type:"week",forceOff:this.colCnt>1},u.htmlEscape(t))+"</th>"):'<th class="fc-axis '+n.theme.getClass("widgetHeader")+'" '+e.axisStyleAttr()+"></th>"},renderBgIntroHtml:function(){var t=this.view;return'<td class="fc-axis '+t.calendar.theme.getClass("widgetContent")+'" '+t.axisStyleAttr()+"></td>"},renderIntroHtml:function(){return'<td class="fc-axis" '+this.view.axisStyleAttr()+"></td>"}},o={renderBgIntroHtml:function(){var t=this.view;return'<td class="fc-axis '+t.calendar.theme.getClass("widgetContent")+'" '+t.axisStyleAttr()+"><span>"+t.getAllDayHtml()+"</span></td>"},renderIntroHtml:function(){return'<td class="fc-axis" '+this.view.axisStyleAttr()+"></td>"}}},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(0),s=n(4),a=n(40),l=n(56),u=n(60),d=n(55),c=n(53),p=n(5),h=n(12),f=n(246),g=n(247),v=n(248),y=[{hours:1},{minutes:30},{minutes:15},{seconds:30},{seconds:15}],m=function(t){function e(e){var n=t.call(this,e)||this;return n.processOptions(),n}return i.__extends(e,t),e.prototype.componentFootprintToSegs=function(t){var e,n=this.sliceRangeByTimes(t.unzonedRange);for(e=0;e<n.length;e++)this.isRTL?n[e].col=this.daysPerRow-1-n[e].dayIndex:n[e].col=n[e].dayIndex;return n},e.prototype.sliceRangeByTimes=function(t){var e,n,i=[];for(n=0;n<this.daysPerRow;n++)(e=t.intersect(this.dayRanges[n]))&&i.push({startMs:e.startMs,endMs:e.endMs,isStart:e.isStart,isEnd:e.isEnd,dayIndex:n});return i},e.prototype.processOptions=function(){var t,e=this.opt("slotDuration"),n=this.opt("snapDuration");e=o.duration(e),n=n?o.duration(n):e,this.slotDuration=e,this.snapDuration=n,this.snapsPerSlot=e/n,t=this.opt("slotLabelFormat"),r.isArray(t)&&(t=t[t.length-1]),this.labelFormat=t||this.opt("smallTimeFormat"),t=this.opt("slotLabelInterval"),this.labelInterval=t?o.duration(t):this.computeLabelInterval(e)},e.prototype.computeLabelInterval=function(t){var e,n,i;for(e=y.length-1;e>=0;e--)if(n=o.duration(y[e]),i=s.divideDurationByDuration(n,t),s.isInt(i)&&i>1)return n;return o.duration(t)},e.prototype.renderDates=function(t){this.dateProfile=t,this.updateDayTable(),this.renderSlats(),this.renderColumns()},e.prototype.unrenderDates=function(){this.unrenderColumns()},e.prototype.renderSkeleton=function(){var t=this.view.calendar.theme;this.el.html('<div class="fc-bg"></div><div class="fc-slats"></div><hr class="fc-divider '+t.getClass("widgetHeader")+'" style="display:none" />'),this.bottomRuleEl=this.el.find("hr")},e.prototype.renderSlats=function(){var t=this.view.calendar.theme;this.slatContainerEl=this.el.find("> .fc-slats").html('<table class="'+t.getClass("tableGrid")+'">'+this.renderSlatRowHtml()+"</table>"),this.slatEls=this.slatContainerEl.find("tr"),this.slatCoordCache=new c.default({els:this.slatEls,isVertical:!0})},e.prototype.renderSlatRowHtml=function(){for(var t,e,n,i=this.view,r=i.calendar,a=r.theme,l=this.isRTL,u=this.dateProfile,d="",c=o.duration(+u.minTime),p=o.duration(0);c<u.maxTime;)t=r.msToUtcMoment(u.renderUnzonedRange.startMs).time(c),e=s.isInt(s.divideDurationByDuration(p,this.labelInterval)),n='<td class="fc-axis fc-time '+a.getClass("widgetContent")+'" '+i.axisStyleAttr()+">"+(e?"<span>"+s.htmlEscape(t.format(this.labelFormat))+"</span>":"")+"</td>",d+='<tr data-time="'+t.format("HH:mm:ss")+'"'+(e?"":' class="fc-minor"')+">"+(l?"":n)+'<td class="'+a.getClass("widgetContent")+'"/>'+(l?n:"")+"</tr>",c.add(this.slotDuration),p.add(this.slotDuration);return d},e.prototype.renderColumns=function(){var t=this.dateProfile,e=this.view.calendar.theme;this.dayRanges=this.dayDates.map(function(e){return new p.default(e.clone().add(t.minTime),e.clone().add(t.maxTime))}),this.headContainerEl&&this.headContainerEl.html(this.renderHeadHtml()),this.el.find("> .fc-bg").html('<table class="'+e.getClass("tableGrid")+'">'+this.renderBgTrHtml(0)+"</table>"),this.colEls=this.el.find(".fc-day, .fc-disabled-day"),this.colCoordCache=new c.default({els:this.colEls,isHorizontal:!0}),this.renderContentSkeleton()},e.prototype.unrenderColumns=function(){this.unrenderContentSkeleton()},e.prototype.renderContentSkeleton=function(){var t,e,n="";for(t=0;t<this.colCnt;t++)n+='<td><div class="fc-content-col"><div class="fc-event-container fc-helper-container"></div><div class="fc-event-container"></div><div class="fc-highlight-container"></div><div class="fc-bgevent-container"></div><div class="fc-business-container"></div></div></td>';e=this.contentSkeletonEl=r('<div class="fc-content-skeleton"><table><tr>'+n+"</tr></table></div>"),this.colContainerEls=e.find(".fc-content-col"),this.helperContainerEls=e.find(".fc-helper-container"),this.fgContainerEls=e.find(".fc-event-container:not(.fc-helper-container)"),this.bgContainerEls=e.find(".fc-bgevent-container"),this.highlightContainerEls=e.find(".fc-highlight-container"),this.businessContainerEls=e.find(".fc-business-container"),this.bookendCells(e.find("tr")),this.el.append(e)},e.prototype.unrenderContentSkeleton=function(){this.contentSkeletonEl&&(this.contentSkeletonEl.remove(),this.contentSkeletonEl=null,this.colContainerEls=null,this.helperContainerEls=null,this.fgContainerEls=null,this.bgContainerEls=null,this.highlightContainerEls=null,this.businessContainerEls=null)},e.prototype.groupSegsByCol=function(t){var e,n=[];for(e=0;e<this.colCnt;e++)n.push([]);for(e=0;e<t.length;e++)n[t[e].col].push(t[e]);return n},e.prototype.attachSegsByCol=function(t,e){var n,i,r;for(n=0;n<this.colCnt;n++)for(i=t[n],r=0;r<i.length;r++)e.eq(n).append(i[r].el)},e.prototype.getNowIndicatorUnit=function(){return"minute"},e.prototype.renderNowIndicator=function(t){if(this.colContainerEls){var e,n=this.componentFootprintToSegs(new h.default(new p.default(t,t.valueOf()+1),!1)),i=this.computeDateTop(t,t),o=[];for(e=0;e<n.length;e++)o.push(r('<div class="fc-now-indicator fc-now-indicator-line"></div>').css("top",i).appendTo(this.colContainerEls.eq(n[e].col))[0]);n.length>0&&o.push(r('<div class="fc-now-indicator fc-now-indicator-arrow"></div>').css("top",i).appendTo(this.el.find(".fc-content-skeleton"))[0]),this.nowIndicatorEls=r(o)}},e.prototype.unrenderNowIndicator=function(){this.nowIndicatorEls&&(this.nowIndicatorEls.remove(),this.nowIndicatorEls=null)},e.prototype.updateSize=function(e,n,i){t.prototype.updateSize.call(this,e,n,i),this.slatCoordCache.build(),i&&this.updateSegVerticals([].concat(this.eventRenderer.getSegs(),this.businessSegs||[]))},e.prototype.getTotalSlatHeight=function(){return this.slatContainerEl.outerHeight()},e.prototype.computeDateTop=function(t,e){return this.computeTimeTop(o.duration(t-e.clone().stripTime()))},e.prototype.computeTimeTop=function(t){var e,n,i=this.slatEls.length,r=this.dateProfile,o=(t-r.minTime)/this.slotDuration;return o=Math.max(0,o),o=Math.min(i,o),e=Math.floor(o),e=Math.min(e,i-1),n=o-e,this.slatCoordCache.getTopPosition(e)+this.slatCoordCache.getHeight(e)*n},e.prototype.updateSegVerticals=function(t){this.computeSegVerticals(t),this.assignSegVerticals(t)},e.prototype.computeSegVerticals=function(t){var e,n,i,r=this.opt("agendaEventMinHeight");for(e=0;e<t.length;e++)n=t[e],i=this.dayDates[n.dayIndex],n.top=this.computeDateTop(n.startMs,i),n.bottom=Math.max(n.top+r,this.computeDateTop(n.endMs,i))},e.prototype.assignSegVerticals=function(t){var e,n;for(e=0;e<t.length;e++)n=t[e],n.el.css(this.generateSegVerticalCss(n))},e.prototype.generateSegVerticalCss=function(t){return{top:t.top,bottom:-t.bottom}},e.prototype.prepareHits=function(){this.colCoordCache.build(),this.slatCoordCache.build()},e.prototype.releaseHits=function(){this.colCoordCache.clear()},e.prototype.queryHit=function(t,e){var n=this.snapsPerSlot,i=this.colCoordCache,r=this.slatCoordCache;if(i.isLeftInBounds(t)&&r.isTopInBounds(e)){var o=i.getHorizontalIndex(t),s=r.getVerticalIndex(e);if(null!=o&&null!=s){var a=r.getTopOffset(s),l=r.getHeight(s),u=(e-a)/l,d=Math.floor(u*n),c=s*n+d,p=a+d/n*l,h=a+(d+1)/n*l;return{col:o,snap:c,component:this,left:i.getLeftOffset(o),right:i.getRightOffset(o),top:p,bottom:h}}}},e.prototype.getHitFootprint=function(t){var e,n=this.getCellDate(0,t.col),i=this.computeSnapTime(t.snap);return n.time(i),e=n.clone().add(this.snapDuration),new h.default(new p.default(n,e),!1)},e.prototype.computeSnapTime=function(t){return o.duration(this.dateProfile.minTime+this.snapDuration*t)},e.prototype.getHitEl=function(t){return this.colEls.eq(t.col)},e.prototype.renderDrag=function(t,e,n){var i;if(e){if(t.length)return this.helperRenderer.renderEventDraggingFootprints(t,e,n),!0}else for(i=0;i<t.length;i++)this.renderHighlight(t[i].componentFootprint)},e.prototype.unrenderDrag=function(){this.unrenderHighlight(),this.helperRenderer.unrender()},e.prototype.renderEventResize=function(t,e,n){this.helperRenderer.renderEventResizingFootprints(t,e,n)},e.prototype.unrenderEventResize=function(){this.helperRenderer.unrender()},e.prototype.renderSelectionFootprint=function(t){this.opt("selectHelper")?this.helperRenderer.renderComponentFootprint(t):this.renderHighlight(t)},e.prototype.unrenderSelection=function(){this.helperRenderer.unrender(),this.unrenderHighlight()},e}(a.default);e.default=m,m.prototype.eventRendererClass=f.default,m.prototype.businessHourRendererClass=l.default,m.prototype.helperRendererClass=g.default,m.prototype.fillRendererClass=v.default,u.default.mixInto(m),d.default.mixInto(m)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(5),o=n(221),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.buildRenderRange=function(e,n,i){var o=t.prototype.buildRenderRange.call(this,e,n,i),s=this.msToUtcMoment(o.startMs,i),a=this.msToUtcMoment(o.endMs,i);return/^(year|month)$/.test(n)&&(s.startOf("week"),a.weekday()&&a.add(1,"week").startOf("week")),new r.default(s,a)},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(0),o=n(4),s=n(62),a=n(253),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.setGridHeight=function(t,e){e&&(t*=this.dayGrid.rowCnt/6),o.distributeHeight(this.dayGrid.rowEls,t,!e)},e.prototype.isDateInOtherMonth=function(t,e){return t.month()!==r.utc(e.currentUnzonedRange.startMs).month()},e}(s.default);e.default=l,l.prototype.dateProfileGeneratorClass=a.default},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(5),a=n(41),l=n(39),u=n(254),d=n(255),c=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.segSelector=".fc-list-item",i.scroller=new l.default({overflowX:"hidden",overflowY:"auto"}),i}return i.__extends(e,t),e.prototype.renderSkeleton=function(){this.el.addClass("fc-list-view "+this.calendar.theme.getClass("listView")),this.scroller.render(),this.scroller.el.appendTo(this.el),this.contentEl=this.scroller.scrollEl},e.prototype.unrenderSkeleton=function(){this.scroller.destroy()},e.prototype.updateSize=function(e,n,i){t.prototype.updateSize.call(this,e,n,i),this.scroller.clear(),n||this.scroller.setHeight(this.computeScrollerHeight(e))},e.prototype.computeScrollerHeight=function(t){return t-o.subtractInnerElHeight(this.el,this.scroller.el)},e.prototype.renderDates=function(t){for(var e=this.calendar,n=e.msToUtcMoment(t.renderUnzonedRange.startMs,!0),i=e.msToUtcMoment(t.renderUnzonedRange.endMs,!0),r=[],o=[];n<i;)r.push(n.clone()),o.push(new s.default(n,n.clone().add(1,"day"))),n.add(1,"day");this.dayDates=r,this.dayRanges=o},e.prototype.componentFootprintToSegs=function(t){var e,n,i,r=this.dayRanges,o=[];for(e=0;e<r.length;e++)if((n=t.unzonedRange.intersect(r[e]))&&(i={startMs:n.startMs,endMs:n.endMs,isStart:n.isStart,isEnd:n.isEnd,dayIndex:e},o.push(i),!i.isEnd&&!t.isAllDay&&e+1<r.length&&t.unzonedRange.endMs<r[e+1].startMs+this.nextDayThreshold)){i.endMs=t.unzonedRange.endMs,i.isEnd=!0;break}return o},e.prototype.renderEmptyMessage=function(){this.contentEl.html('<div class="fc-list-empty-wrap2"><div class="fc-list-empty-wrap1"><div class="fc-list-empty">'+o.htmlEscape(this.opt("noEventsMessage"))+"</div></div></div>")},e.prototype.renderSegList=function(t){var e,n,i,o=this.groupSegsByDay(t),s=r('<table class="fc-list-table '+this.calendar.theme.getClass("tableList")+'"><tbody/></table>'),a=s.find("tbody");for(e=0;e<o.length;e++)if(n=o[e])for(a.append(this.dayHeaderHtml(this.dayDates[e])),this.eventRenderer.sortEventSegs(n),i=0;i<n.length;i++)a.append(n[i].el);this.contentEl.empty().append(s)},e.prototype.groupSegsByDay=function(t){var e,n,i=[];for(e=0;e<t.length;e++)n=t[e],(i[n.dayIndex]||(i[n.dayIndex]=[])).push(n);return i},e.prototype.dayHeaderHtml=function(t){var e=this.opt("listDayFormat"),n=this.opt("listDayAltFormat");return'<tr class="fc-list-heading" data-date="'+t.format("YYYY-MM-DD")+'"><td class="'+(this.calendar.theme.getClass("tableListHeading")||this.calendar.theme.getClass("widgetHeader"))+'" colspan="3">'+(e?this.buildGotoAnchorHtml(t,{class:"fc-list-heading-main"},o.htmlEscape(t.format(e))):"")+(n?this.buildGotoAnchorHtml(t,{class:"fc-list-heading-alt"},o.htmlEscape(t.format(n))):"")+"</td></tr>"},e}(a.default);e.default=c,c.prototype.eventRendererClass=u.default,c.prototype.eventPointingClass=d.default},,,,,,function(t,e,n){var i=n(3),r=n(16),o=n(4),s=n(220);n(10),n(47),n(256),n(257),n(260),n(261),n(262),n(263),i.fullCalendar=r,i.fn.fullCalendar=function(t){var e=Array.prototype.slice.call(arguments,1),n=this;return this.each(function(r,a){var l,u=i(a),d=u.data("fullCalendar");"string"==typeof t?"getCalendar"===t?r||(n=d):"destroy"===t?d&&(d.destroy(),u.removeData("fullCalendar")):d?i.isFunction(d[t])?(l=d[t].apply(d,e),r||(n=l),"destroy"===t&&u.removeData("fullCalendar")):o.warn("'"+t+"' is an unknown FullCalendar method."):o.warn("Attempting to call a FullCalendar method on an element with no calendar."):d||(d=new s.default(u,t),u.data("fullCalendar",d),d.render())}),n},t.exports=r},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(48),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.setElement=function(t){this.el=t,this.bindGlobalHandlers(),this.renderSkeleton(),this.set("isInDom",!0)},e.prototype.removeElement=function(){this.unset("isInDom"),this.unrenderSkeleton(),this.unbindGlobalHandlers(),this.el.remove()},e.prototype.bindGlobalHandlers=function(){},e.prototype.unbindGlobalHandlers=function(){},e.prototype.renderSkeleton=function(){},e.prototype.unrenderSkeleton=function(){},e}(r.default);e.default=o},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t){this.items=t||[]}return t.prototype.proxyCall=function(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];var i=[];return this.items.forEach(function(n){i.push(n[t].apply(n,e))}),i},t}();e.default=n},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=function(){function t(t,e){this.el=null,this.viewsWithButtons=[],this.calendar=t,this.toolbarOptions=e}return t.prototype.setToolbarOptions=function(t){this.toolbarOptions=t},t.prototype.render=function(){var t=this.toolbarOptions.layout,e=this.el;t?(e?e.empty():e=this.el=i("<div class='fc-toolbar "+this.toolbarOptions.extraClasses+"'/>"),e.append(this.renderSection("left")).append(this.renderSection("right")).append(this.renderSection("center")).append('<div class="fc-clear"/>')):this.removeElement()},t.prototype.removeElement=function(){this.el&&(this.el.remove(),this.el=null)},t.prototype.renderSection=function(t){var e=this,n=this.calendar,o=n.theme,s=n.optionsManager,a=n.viewSpecManager,l=i('<div class="fc-'+t+'"/>'),u=this.toolbarOptions.layout[t],d=s.get("customButtons")||{},c=s.overrides.buttonText||{},p=s.get("buttonText")||{};return u&&i.each(u.split(" "),function(t,s){var u,h=i(),f=!0;i.each(s.split(","),function(t,s){var l,u,g,v,y,m,b,w,D;"title"===s?(h=h.add(i("<h2>&nbsp;</h2>")),f=!1):((l=d[s])?(g=function(t){l.click&&l.click.call(w[0],t)},(v=o.getCustomButtonIconClass(l))||(v=o.getIconClass(s))||(y=l.text)):(u=a.getViewSpec(s))?(e.viewsWithButtons.push(s),g=function(){n.changeView(s)},(y=u.buttonTextOverride)||(v=o.getIconClass(s))||(y=u.buttonTextDefault)):n[s]&&(g=function(){n[s]()},(y=c[s])||(v=o.getIconClass(s))||(y=p[s])),g&&(b=["fc-"+s+"-button",o.getClass("button"),o.getClass("stateDefault")],y?(m=r.htmlEscape(y),D=""):v&&(m="<span class='"+v+"'></span>",D=' aria-label="'+s+'"'),w=i('<button type="button" class="'+b.join(" ")+'"'+D+">"+m+"</button>").click(function(t){w.hasClass(o.getClass("stateDisabled"))||(g(t),(w.hasClass(o.getClass("stateActive"))||w.hasClass(o.getClass("stateDisabled")))&&w.removeClass(o.getClass("stateHover")))}).mousedown(function(){w.not("."+o.getClass("stateActive")).not("."+o.getClass("stateDisabled")).addClass(o.getClass("stateDown"))}).mouseup(function(){w.removeClass(o.getClass("stateDown"))}).hover(function(){w.not("."+o.getClass("stateActive")).not("."+o.getClass("stateDisabled")).addClass(o.getClass("stateHover"))},function(){w.removeClass(o.getClass("stateHover")).removeClass(o.getClass("stateDown"))}),h=h.add(w)))}),f&&h.first().addClass(o.getClass("cornerLeft")).end().last().addClass(o.getClass("cornerRight")).end(),h.length>1?(u=i("<div/>"),f&&u.addClass(o.getClass("buttonGroup")),u.append(h),l.append(u)):l.append(h)}),l},t.prototype.updateTitle=function(t){this.el&&this.el.find("h2").text(t)},t.prototype.activateButton=function(t){this.el&&this.el.find(".fc-"+t+"-button").addClass(this.calendar.theme.getClass("stateActive"))},t.prototype.deactivateButton=function(t){this.el&&this.el.find(".fc-"+t+"-button").removeClass(this.calendar.theme.getClass("stateActive"))},t.prototype.disableButton=function(t){this.el&&this.el.find(".fc-"+t+"-button").prop("disabled",!0).addClass(this.calendar.theme.getClass("stateDisabled"))},t.prototype.enableButton=function(t){this.el&&this.el.find(".fc-"+t+"-button").prop("disabled",!1).removeClass(this.calendar.theme.getClass("stateDisabled"))},t.prototype.getViewsWithButtons=function(){return this.viewsWithButtons},t}();e.default=o},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(4),s=n(32),a=n(31),l=n(48),u=function(t){function e(e,n){var i=t.call(this)||this;return i._calendar=e,i.overrides=r.extend({},n),i.dynamicOverrides={},i.compute(),i}return i.__extends(e,t),e.prototype.add=function(t){var e,n=0;this.recordOverrides(t);for(e in t)n++;if(1===n){if("height"===e||"contentHeight"===e||"aspectRatio"===e)return void this._calendar.updateViewSize(!0);if("defaultDate"===e)return;if("businessHours"===e)return;if(/^(event|select)(Overlap|Constraint|Allow)$/.test(e))return;if("timezone"===e)return void this._calendar.view.flash("initialEvents")}this._calendar.renderHeader(),this._calendar.renderFooter(),this._calendar.viewsByType={},this._calendar.reinitView()},e.prototype.compute=function(){var t,e,n,i,r;t=o.firstDefined(this.dynamicOverrides.locale,this.overrides.locale),e=a.localeOptionHash[t],e||(t=s.globalDefaults.locale,e=a.localeOptionHash[t]||{}),n=o.firstDefined(this.dynamicOverrides.isRTL,this.overrides.isRTL,e.isRTL,s.globalDefaults.isRTL),i=n?s.rtlDefaults:{},this.dirDefaults=i,this.localeDefaults=e,r=s.mergeOptions([s.globalDefaults,i,e,this.overrides,this.dynamicOverrides]),a.populateInstanceComputableOptions(r),this.reset(r)},e.prototype.recordOverrides=function(t){var e;for(e in t)this.dynamicOverrides[e]=t[e];this._calendar.viewSpecManager.clearCache(),this.compute()},e}(l.default);e.default=u},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(0),r=n(3),o=n(22),s=n(4),a=n(32),l=n(31),u=function(){function t(t,e){this.optionsManager=t,this._calendar=e,this.clearCache()}return t.prototype.clearCache=function(){this.viewSpecCache={}},t.prototype.getViewSpec=function(t){var e=this.viewSpecCache;return e[t]||(e[t]=this.buildViewSpec(t))},t.prototype.getUnitViewSpec=function(t){var e,n,i;if(-1!==r.inArray(t,s.unitsDesc))for(e=this._calendar.header.getViewsWithButtons(),r.each(o.viewHash,function(t){e.push(t)}),n=0;n<e.length;n++)if((i=this.getViewSpec(e[n]))&&i.singleUnit===t)return i},t.prototype.buildViewSpec=function(t){for(var e,n,r,l,u,d=this.optionsManager.overrides.views||{},c=[],p=[],h=[],f=t;f;)e=o.viewHash[f],n=d[f],f=null,"function"==typeof e&&(e={class:e}),e&&(c.unshift(e),p.unshift(e.defaults||{}),r=r||e.duration,f=f||e.type),n&&(h.unshift(n),r=r||n.duration,f=f||n.type);return e=s.mergeProps(c),e.type=t,!!e.class&&(r=r||this.optionsManager.dynamicOverrides.duration||this.optionsManager.overrides.duration,r&&(l=i.duration(r),l.valueOf()&&(u=s.computeDurationGreatestUnit(l,r),e.duration=l,e.durationUnit=u,1===l.as(u)&&(e.singleUnit=u,h.unshift(d[u]||{})))),e.defaults=a.mergeOptions(p),e.overrides=a.mergeOptions(h),this.buildViewSpecOptions(e),this.buildViewSpecButtonText(e,t),e)},t.prototype.buildViewSpecOptions=function(t){var e=this.optionsManager;t.options=a.mergeOptions([a.globalDefaults,t.defaults,e.dirDefaults,e.localeDefaults,e.overrides,t.overrides,e.dynamicOverrides]),l.populateInstanceComputableOptions(t.options)},t.prototype.buildViewSpecButtonText=function(t,e){function n(n){var i=n.buttonText||{};return i[e]||(t.buttonTextKey?i[t.buttonTextKey]:null)||(t.singleUnit?i[t.singleUnit]:null)}var i=this.optionsManager;t.buttonTextOverride=n(i.dynamicOverrides)||n(i.overrides)||t.overrides.buttonText,t.buttonTextDefault=n(i.localeDefaults)||n(i.dirDefaults)||t.defaults.buttonText||n(a.globalDefaults)||(t.duration?this._calendar.humanizeDuration(t.duration):null)||e},t}();e.default=u},function(t,e,n){function i(t,e){return t.getPrimitive()===e.getPrimitive()}Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),o=n(4),s=n(243),a=n(52),l=n(6),u=n(38),d=n(13),c=n(18),p=n(11),h=n(7),f=function(){function t(t){this.calendar=t,this.stickySource=new a.default(t),this.otherSources=[]}return t.prototype.requestEvents=function(t,e,n,i){return!i&&this.currentPeriod&&this.currentPeriod.isWithinRange(t,e)&&n===this.currentPeriod.timezone||this.setPeriod(new s.default(t,e,n)),this.currentPeriod.whenReleased()},t.prototype.addSource=function(t){this.otherSources.push(t),this.currentPeriod&&this.currentPeriod.requestSource(t)},t.prototype.removeSource=function(t){o.removeExact(this.otherSources,t),this.currentPeriod&&this.currentPeriod.purgeSource(t)},t.prototype.removeAllSources=function(){this.otherSources=[],this.currentPeriod&&this.currentPeriod.purgeAllSources()},t.prototype.refetchSource=function(t){var e=this.currentPeriod;e&&(e.freeze(),e.purgeSource(t),e.requestSource(t),e.thaw())},t.prototype.refetchAllSources=function(){var t=this.currentPeriod;t&&(t.freeze(),t.purgeAllSources(),t.requestSources(this.getSources()),t.thaw())},t.prototype.getSources=function(){return[this.stickySource].concat(this.otherSources)},t.prototype.multiQuerySources=function(t){t?r.isArray(t)||(t=[t]):t=[];var e,n=[];for(e=0;e<t.length;e++)n.push.apply(n,this.querySources(t[e]));return n},t.prototype.querySources=function(t){var e,n,o=this.otherSources;for(e=0;e<o.length;e++)if((n=o[e])===t)return[n];return(n=this.getSourceById(l.default.normalizeId(t)))?[n]:(t=u.default.parse(t,this.calendar),t?r.grep(o,function(e){return i(t,e)}):void 0)},t.prototype.getSourceById=function(t){return r.grep(this.otherSources,function(e){return e.id&&e.id===t})[0]},t.prototype.setPeriod=function(t){this.currentPeriod&&(this.unbindPeriod(this.currentPeriod),this.currentPeriod=null),this.currentPeriod=t,this.bindPeriod(t),t.requestSources(this.getSources())},t.prototype.bindPeriod=function(t){this.listenTo(t,"release",function(t){this.trigger("release",t)})},t.prototype.unbindPeriod=function(t){this.stopListeningTo(t)},t.prototype.getEventDefByUid=function(t){if(this.currentPeriod)return this.currentPeriod.getEventDefByUid(t)},t.prototype.addEventDef=function(t,e){e&&this.stickySource.addEventDef(t),this.currentPeriod&&this.currentPeriod.addEventDef(t)},t.prototype.removeEventDefsById=function(t){this.getSources().forEach(function(e){e.removeEventDefsById(t)}),this.currentPeriod&&this.currentPeriod.removeEventDefsById(t)},t.prototype.removeAllEventDefs=function(){this.getSources().forEach(function(t){t.removeAllEventDefs()}),this.currentPeriod&&this.currentPeriod.removeAllEventDefs()},t.prototype.mutateEventsWithId=function(t,e){var n,i=this.currentPeriod,r=[];return i?(i.freeze(),n=i.getEventDefsById(t),n.forEach(function(t){i.removeEventDef(t),r.push(e.mutateSingle(t)),i.addEventDef(t)}),i.thaw(),function(){i.freeze();for(var t=0;t<n.length;t++)i.removeEventDef(n[t]),r[t](),i.addEventDef(n[t]);i.thaw()}):function(){}},t.prototype.buildMutatedEventInstanceGroup=function(t,e){var n,i,r=this.getEventDefsById(t),o=[];for(n=0;n<r.length;n++)(i=r[n].clone())instanceof d.default&&(e.mutateSingle(i),o.push.apply(o,i.buildInstances()));return new c.default(o)},t.prototype.freeze=function(){this.currentPeriod&&this.currentPeriod.freeze()},t.prototype.thaw=function(){this.currentPeriod&&this.currentPeriod.thaw()},t.prototype.getEventDefsById=function(t){return this.currentPeriod.getEventDefsById(t)},t.prototype.getEventInstances=function(){return this.currentPeriod.getEventInstances()},t.prototype.getEventInstancesWithId=function(t){return this.currentPeriod.getEventInstancesWithId(t)},t.prototype.getEventInstancesWithoutId=function(t){return this.currentPeriod.getEventInstancesWithoutId(t)},t}();e.default=f,p.default.mixInto(f),h.default.mixInto(f)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=n(20),s=n(11),a=n(5),l=n(18),u=function(){function t(t,e,n){this.pendingCnt=0,this.freezeDepth=0,this.stuntedReleaseCnt=0,this.releaseCnt=0,this.start=t,this.end=e,this.timezone=n,this.unzonedRange=new a.default(t.clone().stripZone(),e.clone().stripZone()),this.requestsByUid={},this.eventDefsByUid={},this.eventDefsById={},this.eventInstanceGroupsById={}}return t.prototype.isWithinRange=function(t,e){return!t.isBefore(this.start)&&!e.isAfter(this.end)},t.prototype.requestSources=function(t){this.freeze();for(var e=0;e<t.length;e++)this.requestSource(t[e]);this.thaw()},t.prototype.requestSource=function(t){var e=this,n={source:t,status:"pending",eventDefs:null};this.requestsByUid[t.uid]=n,this.pendingCnt+=1,t.fetch(this.start,this.end,this.timezone).then(function(t){"cancelled"!==n.status&&(n.status="completed",n.eventDefs=t,e.addEventDefs(t),e.pendingCnt--,e.tryRelease())},function(){"cancelled"!==n.status&&(n.status="failed",e.pendingCnt--,e.tryRelease())})},t.prototype.purgeSource=function(t){var e=this.requestsByUid[t.uid];e&&(delete this.requestsByUid[t.uid],"pending"===e.status?(e.status="cancelled",this.pendingCnt--,this.tryRelease()):"completed"===e.status&&e.eventDefs.forEach(this.removeEventDef.bind(this)))},t.prototype.purgeAllSources=function(){var t,e,n=this.requestsByUid,i=0;for(t in n)e=n[t],"pending"===e.status?e.status="cancelled":"completed"===e.status&&i++;this.requestsByUid={},this.pendingCnt=0,i&&this.removeAllEventDefs()},t.prototype.getEventDefByUid=function(t){return this.eventDefsByUid[t]},t.prototype.getEventDefsById=function(t){var e=this.eventDefsById[t];return e?e.slice():[]},t.prototype.addEventDefs=function(t){for(var e=0;e<t.length;e++)this.addEventDef(t[e])},t.prototype.addEventDef=function(t){var e,n=this.eventDefsById,i=t.id,r=n[i]||(n[i]=[]),o=t.buildInstances(this.unzonedRange);for(r.push(t),this.eventDefsByUid[t.uid]=t,e=0;e<o.length;e++)this.addEventInstance(o[e],i)},t.prototype.removeEventDefsById=function(t){var e=this;this.getEventDefsById(t).forEach(function(t){e.removeEventDef(t)})},t.prototype.removeAllEventDefs=function(){var t=i.isEmptyObject(this.eventDefsByUid);this.eventDefsByUid={},this.eventDefsById={},this.eventInstanceGroupsById={},t||this.tryRelease()},t.prototype.removeEventDef=function(t){var e=this.eventDefsById,n=e[t.id]
+;delete this.eventDefsByUid[t.uid],n&&(r.removeExact(n,t),n.length||delete e[t.id],this.removeEventInstancesForDef(t))},t.prototype.getEventInstances=function(){var t,e=this.eventInstanceGroupsById,n=[];for(t in e)n.push.apply(n,e[t].eventInstances);return n},t.prototype.getEventInstancesWithId=function(t){var e=this.eventInstanceGroupsById[t];return e?e.eventInstances.slice():[]},t.prototype.getEventInstancesWithoutId=function(t){var e,n=this.eventInstanceGroupsById,i=[];for(e in n)e!==t&&i.push.apply(i,n[e].eventInstances);return i},t.prototype.addEventInstance=function(t,e){var n=this.eventInstanceGroupsById;(n[e]||(n[e]=new l.default)).eventInstances.push(t),this.tryRelease()},t.prototype.removeEventInstancesForDef=function(t){var e,n=this.eventInstanceGroupsById,i=n[t.id];i&&(e=r.removeMatching(i.eventInstances,function(e){return e.def===t}),i.eventInstances.length||delete n[t.id],e&&this.tryRelease())},t.prototype.tryRelease=function(){this.pendingCnt||(this.freezeDepth?this.stuntedReleaseCnt++:this.release())},t.prototype.release=function(){this.releaseCnt++,this.trigger("release",this.eventInstanceGroupsById)},t.prototype.whenReleased=function(){var t=this;return this.releaseCnt?o.default.resolve(this.eventInstanceGroupsById):o.default.construct(function(e){t.one("release",e)})},t.prototype.freeze=function(){this.freezeDepth++||(this.stuntedReleaseCnt=0)},t.prototype.thaw=function(){--this.freezeDepth||!this.stuntedReleaseCnt||this.pendingCnt||this.release()},t}();e.default=u,s.default.mixInto(u)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=n(7),s=function(){function t(t,e){this.isFollowing=!1,this.isHidden=!1,this.isAnimating=!1,this.options=e=e||{},this.sourceEl=t,this.parentEl=e.parentEl?i(e.parentEl):t.parent()}return t.prototype.start=function(t){this.isFollowing||(this.isFollowing=!0,this.y0=r.getEvY(t),this.x0=r.getEvX(t),this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),r.getEvIsTouch(t)?this.listenTo(i(document),"touchmove",this.handleMove):this.listenTo(i(document),"mousemove",this.handleMove))},t.prototype.stop=function(t,e){var n=this,r=this.options.revertDuration,o=function(){n.isAnimating=!1,n.removeElement(),n.top0=n.left0=null,e&&e()};this.isFollowing&&!this.isAnimating&&(this.isFollowing=!1,this.stopListeningTo(i(document)),t&&r&&!this.isHidden?(this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:r,complete:o})):o())},t.prototype.getEl=function(){var t=this.el;return t||(t=this.el=this.sourceEl.clone().addClass(this.options.additionalClass||"").css({position:"absolute",visibility:"",display:this.isHidden?"none":"",margin:0,right:"auto",bottom:"auto",width:this.sourceEl.width(),height:this.sourceEl.height(),opacity:this.options.opacity||"",zIndex:this.options.zIndex}),t.addClass("fc-unselectable"),t.appendTo(this.parentEl)),t},t.prototype.removeElement=function(){this.el&&(this.el.remove(),this.el=null)},t.prototype.updatePosition=function(){var t,e;this.getEl(),null==this.top0&&(t=this.sourceEl.offset(),e=this.el.offsetParent().offset(),this.top0=t.top-e.top,this.left0=t.left-e.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},t.prototype.handleMove=function(t){this.topDelta=r.getEvY(t)-this.y0,this.leftDelta=r.getEvX(t)-this.x0,this.isHidden||this.updatePosition()},t.prototype.hide=function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},t.prototype.show=function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())},t}();e.default=s,o.default.mixInto(s)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(23),o=n(15),s=function(t){function e(e){var n=t.call(this,e)||this;return n.dragListener=n.buildDragListener(),n}return i.__extends(e,t),e.prototype.end=function(){this.dragListener.endInteraction()},e.prototype.bindToEl=function(t){var e=this.component,n=this.dragListener;e.bindDateHandlerToEl(t,"mousedown",function(t){e.shouldIgnoreMouse()||n.startInteraction(t)}),e.bindDateHandlerToEl(t,"touchstart",function(t){e.shouldIgnoreTouch()||n.startInteraction(t)})},e.prototype.buildDragListener=function(){var t,e=this,n=this.component,i=new r.default(n,{scroll:this.opt("dragScroll"),interactionStart:function(){t=i.origHit},hitOver:function(e,n,i){n||(t=null)},hitOut:function(){t=null},interactionEnd:function(i,r){var o;!r&&t&&(o=n.getSafeHitFootprint(t))&&e.view.triggerDayClick(o,n.getHitEl(t),i)}});return i.shouldCancelTouchScroll=!1,i.scrollAlwaysKills=!0,i},e}(o.default);e.default=s},function(t,e,n){function i(t){var e,n,i,r=[];for(e=0;e<t.length;e++){for(n=t[e],i=0;i<r.length&&s(n,r[i]).length;i++);n.level=i,(r[i]||(r[i]=[])).push(n)}return r}function r(t){var e,n,i,r,o;for(e=0;e<t.length;e++)for(n=t[e],i=0;i<n.length;i++)for(r=n[i],r.forwardSegs=[],o=e+1;o<t.length;o++)s(r,t[o],r.forwardSegs)}function o(t){var e,n,i=t.forwardSegs,r=0;if(void 0===t.forwardPressure){for(e=0;e<i.length;e++)n=i[e],o(n),r=Math.max(r,1+n.forwardPressure);t.forwardPressure=r}}function s(t,e,n){void 0===n&&(n=[]);for(var i=0;i<e.length;i++)a(t,e[i])&&n.push(e[i]);return n}function a(t,e){return t.bottom>e.top&&t.top<e.bottom}Object.defineProperty(e,"__esModule",{value:!0});var l=n(2),u=n(4),d=n(42),c=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.timeGrid=e,i}return l.__extends(e,t),e.prototype.renderFgSegs=function(t){this.renderFgSegsIntoContainers(t,this.timeGrid.fgContainerEls)},e.prototype.renderFgSegsIntoContainers=function(t,e){var n,i;for(n=this.timeGrid.groupSegsByCol(t),i=0;i<this.timeGrid.colCnt;i++)this.updateFgSegCoords(n[i]);this.timeGrid.attachSegsByCol(n,e)},e.prototype.unrenderFgSegs=function(){this.fgSegs&&this.fgSegs.forEach(function(t){t.el.remove()})},e.prototype.computeEventTimeFormat=function(){return this.opt("noMeridiemTimeFormat")},e.prototype.computeDisplayEventEnd=function(){return!0},e.prototype.fgSegHtml=function(t,e){var n,i,r,o=this.view,s=o.calendar,a=t.footprint.componentFootprint,l=a.isAllDay,d=t.footprint.eventDef,c=o.isEventDefDraggable(d),p=!e&&t.isStart&&o.isEventDefResizableFromStart(d),h=!e&&t.isEnd&&o.isEventDefResizableFromEnd(d),f=this.getSegClasses(t,c,p||h),g=u.cssToStr(this.getSkinCss(d));if(f.unshift("fc-time-grid-event","fc-v-event"),o.isMultiDayRange(a.unzonedRange)){if(t.isStart||t.isEnd){var v=s.msToMoment(t.startMs),y=s.msToMoment(t.endMs);n=this._getTimeText(v,y,l),i=this._getTimeText(v,y,l,"LT"),r=this._getTimeText(v,y,l,null,!1)}}else n=this.getTimeText(t.footprint),i=this.getTimeText(t.footprint,"LT"),r=this.getTimeText(t.footprint,null,!1);return'<a class="'+f.join(" ")+'"'+(d.url?' href="'+u.htmlEscape(d.url)+'"':"")+(g?' style="'+g+'"':"")+'><div class="fc-content">'+(n?'<div class="fc-time" data-start="'+u.htmlEscape(r)+'" data-full="'+u.htmlEscape(i)+'"><span>'+u.htmlEscape(n)+"</span></div>":"")+(d.title?'<div class="fc-title">'+u.htmlEscape(d.title)+"</div>":"")+'</div><div class="fc-bg"/>'+(h?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},e.prototype.updateFgSegCoords=function(t){this.timeGrid.computeSegVerticals(t),this.computeFgSegHorizontals(t),this.timeGrid.assignSegVerticals(t),this.assignFgSegHorizontals(t)},e.prototype.computeFgSegHorizontals=function(t){var e,n,s;if(this.sortEventSegs(t),e=i(t),r(e),n=e[0]){for(s=0;s<n.length;s++)o(n[s]);for(s=0;s<n.length;s++)this.computeFgSegForwardBack(n[s],0,0)}},e.prototype.computeFgSegForwardBack=function(t,e,n){var i,r=t.forwardSegs;if(void 0===t.forwardCoord)for(r.length?(this.sortForwardSegs(r),this.computeFgSegForwardBack(r[0],e+1,n),t.forwardCoord=r[0].backwardCoord):t.forwardCoord=1,t.backwardCoord=t.forwardCoord-(t.forwardCoord-n)/(e+1),i=0;i<r.length;i++)this.computeFgSegForwardBack(r[i],0,t.forwardCoord)},e.prototype.sortForwardSegs=function(t){t.sort(u.proxy(this,"compareForwardSegs"))},e.prototype.compareForwardSegs=function(t,e){return e.forwardPressure-t.forwardPressure||(t.backwardCoord||0)-(e.backwardCoord||0)||this.compareEventSegs(t,e)},e.prototype.assignFgSegHorizontals=function(t){var e,n;for(e=0;e<t.length;e++)n=t[e],n.el.css(this.generateFgSegHorizontalCss(n)),n.bottom-n.top<30&&n.el.addClass("fc-short")},e.prototype.generateFgSegHorizontalCss=function(t){var e,n,i=this.opt("slotEventOverlap"),r=t.backwardCoord,o=t.forwardCoord,s=this.timeGrid.generateSegVerticalCss(t),a=this.timeGrid.isRTL;return i&&(o=Math.min(1,r+2*(o-r))),a?(e=1-o,n=r):(e=r,n=1-o),s.zIndex=t.level+1,s.left=100*e+"%",s.right=100*n+"%",i&&t.forwardPressure&&(s[a?"marginLeft":"marginRight"]=20),s},e}(d.default);e.default=c},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(58),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.renderSegs=function(t,e){var n,i,o,s=[];for(this.eventRenderer.renderFgSegsIntoContainers(t,this.component.helperContainerEls),n=0;n<t.length;n++)i=t[n],e&&e.col===i.col&&(o=e.el,i.el.css({left:o.css("left"),right:o.css("right"),"margin-left":o.css("margin-left"),"margin-right":o.css("margin-right")})),s.push(i.el[0]);return r(s)},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(57),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.attachSegEls=function(t,e){var n,i=this.component;return"bgEvent"===t?n=i.bgContainerEls:"businessHours"===t?n=i.businessContainerEls:"highlight"===t&&(n=i.highlightContainerEls),i.updateSegVerticals(e),i.attachSegsByCol(i.groupSegsByCol(e),n),e.map(function(t){return t.el[0]})},e}(r.default);e.default=o},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),r=n(4),o=n(7),s=function(){function t(t){this.isHidden=!0,this.margin=10,this.options=t||{}}return t.prototype.show=function(){this.isHidden&&(this.el||this.render(),this.el.show(),this.position(),this.isHidden=!1,this.trigger("show"))},t.prototype.hide=function(){this.isHidden||(this.el.hide(),this.isHidden=!0,this.trigger("hide"))},t.prototype.render=function(){var t=this,e=this.options;this.el=i('<div class="fc-popover"/>').addClass(e.className||"").css({top:0,left:0}).append(e.content).appendTo(e.parentEl),this.el.on("click",".fc-close",function(){t.hide()}),e.autoHide&&this.listenTo(i(document),"mousedown",this.documentMousedown)},t.prototype.documentMousedown=function(t){this.el&&!i(t.target).closest(this.el).length&&this.hide()},t.prototype.removeElement=function(){this.hide(),this.el&&(this.el.remove(),this.el=null),this.stopListeningTo(i(document),"mousedown")},t.prototype.position=function(){var t,e,n,o,s,a=this.options,l=this.el.offsetParent().offset(),u=this.el.outerWidth(),d=this.el.outerHeight(),c=i(window),p=r.getScrollParent(this.el);o=a.top||0,s=void 0!==a.left?a.left:void 0!==a.right?a.right-u:0,p.is(window)||p.is(document)?(p=c,t=0,e=0):(n=p.offset(),t=n.top,e=n.left),t+=c.scrollTop(),e+=c.scrollLeft(),!1!==a.viewportConstrain&&(o=Math.min(o,t+p.outerHeight()-d-this.margin),o=Math.max(o,t+this.margin),s=Math.min(s,e+p.outerWidth()-u-this.margin),s=Math.max(s,e+this.margin)),this.el.css({top:o-l.top,left:s-l.left})},t.prototype.trigger=function(t){this.options[t]&&this.options[t].apply(this,Array.prototype.slice.call(arguments,1))},t}();e.default=s,o.default.mixInto(s)},function(t,e,n){function i(t,e){var n,i;for(n=0;n<e.length;n++)if(i=e[n],i.leftCol<=t.rightCol&&i.rightCol>=t.leftCol)return!0;return!1}function r(t,e){return t.leftCol-e.leftCol}Object.defineProperty(e,"__esModule",{value:!0});var o=n(2),s=n(3),a=n(4),l=n(42),u=function(t){function e(e,n){var i=t.call(this,e,n)||this;return i.dayGrid=e,i}return o.__extends(e,t),e.prototype.renderBgRanges=function(e){e=s.grep(e,function(t){return t.eventDef.isAllDay()}),t.prototype.renderBgRanges.call(this,e)},e.prototype.renderFgSegs=function(t){var e=this.rowStructs=this.renderSegRows(t);this.dayGrid.rowEls.each(function(t,n){s(n).find(".fc-content-skeleton > table").append(e[t].tbodyEl)})},e.prototype.unrenderFgSegs=function(){for(var t,e=this.rowStructs||[];t=e.pop();)t.tbodyEl.remove();this.rowStructs=null},e.prototype.renderSegRows=function(t){var e,n,i=[];for(e=this.groupSegRows(t),n=0;n<e.length;n++)i.push(this.renderSegRow(n,e[n]));return i},e.prototype.renderSegRow=function(t,e){function n(t){for(;o<t;)d=(y[i-1]||[])[o],d?d.attr("rowspan",parseInt(d.attr("rowspan")||1,10)+1):(d=s("<td/>"),a.append(d)),v[i][o]=d,y[i][o]=d,o++}var i,r,o,a,l,u,d,c=this.dayGrid.colCnt,p=this.buildSegLevels(e),h=Math.max(1,p.length),f=s("<tbody/>"),g=[],v=[],y=[];for(i=0;i<h;i++){if(r=p[i],o=0,a=s("<tr/>"),g.push([]),v.push([]),y.push([]),r)for(l=0;l<r.length;l++){for(u=r[l],n(u.leftCol),d=s('<td class="fc-event-container"/>').append(u.el),u.leftCol!==u.rightCol?d.attr("colspan",u.rightCol-u.leftCol+1):y[i][o]=d;o<=u.rightCol;)v[i][o]=d,g[i][o]=u,o++;a.append(d)}n(c),this.dayGrid.bookendCells(a),f.append(a)}return{row:t,tbodyEl:f,cellMatrix:v,segMatrix:g,segLevels:p,segs:e}},e.prototype.buildSegLevels=function(t){var e,n,o,s=[];for(this.sortEventSegs(t),e=0;e<t.length;e++){for(n=t[e],o=0;o<s.length&&i(n,s[o]);o++);n.level=o,(s[o]||(s[o]=[])).push(n)}for(o=0;o<s.length;o++)s[o].sort(r);return s},e.prototype.groupSegRows=function(t){var e,n=[];for(e=0;e<this.dayGrid.rowCnt;e++)n.push([]);for(e=0;e<t.length;e++)n[t[e].row].push(t[e]);return n},e.prototype.computeEventTimeFormat=function(){return this.opt("extraSmallTimeFormat")},e.prototype.computeDisplayEventEnd=function(){return 1===this.dayGrid.colCnt},e.prototype.fgSegHtml=function(t,e){var n,i,r=this.view,o=t.footprint.eventDef,s=t.footprint.componentFootprint.isAllDay,l=r.isEventDefDraggable(o),u=!e&&s&&t.isStart&&r.isEventDefResizableFromStart(o),d=!e&&s&&t.isEnd&&r.isEventDefResizableFromEnd(o),c=this.getSegClasses(t,l,u||d),p=a.cssToStr(this.getSkinCss(o)),h="";return c.unshift("fc-day-grid-event","fc-h-event"),t.isStart&&(n=this.getTimeText(t.footprint))&&(h='<span class="fc-time">'+a.htmlEscape(n)+"</span>"),i='<span class="fc-title">'+(a.htmlEscape(o.title||"")||"&nbsp;")+"</span>",'<a class="'+c.join(" ")+'"'+(o.url?' href="'+a.htmlEscape(o.url)+'"':"")+(p?' style="'+p+'"':"")+'><div class="fc-content">'+(this.dayGrid.isRTL?i+" "+h:h+" "+i)+"</div>"+(u?'<div class="fc-resizer fc-start-resizer" />':"")+(d?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},e}(l.default);e.default=u},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(58),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.renderSegs=function(t,e){var n,i=[];return n=this.eventRenderer.renderSegRows(t),this.component.rowEls.each(function(t,o){var s,a,l=r(o),u=r('<div class="fc-helper-skeleton"><table/></div>');e&&e.row===t?a=e.el.position().top:(s=l.find(".fc-content-skeleton tbody"),s.length||(s=l.find(".fc-content-skeleton table")),a=s.position().top),u.css("top",a).find("table").append(n[t].tbodyEl),l.append(u),i.push(u[0])}),r(i)},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(57),s=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.fillSegTag="td",e}return i.__extends(e,t),e.prototype.attachSegEls=function(t,e){var n,i,r,o=[];for(n=0;n<e.length;n++)i=e[n],r=this.renderFillRow(t,i),this.component.rowEls.eq(i.row).append(r),o.push(r[0]);return o},e.prototype.renderFillRow=function(t,e){var n,i,o,s=this.component.colCnt,a=e.leftCol,l=e.rightCol+1;return n="businessHours"===t?"bgevent":t.toLowerCase(),i=r('<div class="fc-'+n+'-skeleton"><table><tr/></table></div>'),o=i.find("tr"),a>0&&o.append('<td colspan="'+a+'"/>'),o.append(e.el.attr("colspan",l-a)),l<s&&o.append('<td colspan="'+(s-l)+'"/>'),this.component.bookendCells(o),i},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(228),o=n(5),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.buildRenderRange=function(e,n,i){var r,s=t.prototype.buildRenderRange.call(this,e,n,i),a=this.msToUtcMoment(s.startMs,i),l=this.msToUtcMoment(s.endMs,i);return this.opt("fixedWeekCount")&&(r=Math.ceil(l.diff(a,"weeks",!0)),l.add(6-r,"weeks")),new o.default(a,l)},e}(r.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(4),o=n(42),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.renderFgSegs=function(t){t.length?this.component.renderSegList(t):this.component.renderEmptyMessage()},e.prototype.fgSegHtml=function(t){var e,n=this.view,i=n.calendar,o=i.theme,s=t.footprint,a=s.eventDef,l=s.componentFootprint,u=a.url,d=["fc-list-item"].concat(this.getClasses(a)),c=this.getBgColor(a);return e=l.isAllDay?n.getAllDayHtml():n.isMultiDayRange(l.unzonedRange)?t.isStart||t.isEnd?r.htmlEscape(this._getTimeText(i.msToMoment(t.startMs),i.msToMoment(t.endMs),l.isAllDay)):n.getAllDayHtml():r.htmlEscape(this.getTimeText(s)),u&&d.push("fc-has-url"),'<tr class="'+d.join(" ")+'">'+(this.displayEventTime?'<td class="fc-list-item-time '+o.getClass("widgetContent")+'">'+(e||"")+"</td>":"")+'<td class="fc-list-item-marker '+o.getClass("widgetContent")+'"><span class="fc-event-dot"'+(c?' style="background-color:'+c+'"':"")+'></span></td><td class="fc-list-item-title '+o.getClass("widgetContent")+'"><a'+(u?' href="'+r.htmlEscape(u)+'"':"")+">"+r.htmlEscape(a.title||"")+"</a></td></tr>"},e.prototype.computeEventTimeFormat=function(){return this.opt("mediumTimeFormat")},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(3),o=n(59),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.handleClick=function(e,n){var i;t.prototype.handleClick.call(this,e,n),r(n.target).closest("a[href]").length||(i=e.footprint.eventDef.url)&&!n.isDefaultPrevented()&&(window.location.href=i)},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(38),r=n(52),o=n(215),s=n(216);i.default.registerClass(r.default),i.default.registerClass(o.default),i.default.registerClass(s.default)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(51),r=n(213),o=n(214),s=n(258),a=n(259);i.defineThemeSystem("standard",r.default),i.defineThemeSystem("jquery-ui",o.default),i.defineThemeSystem("bootstrap3",s.default),i.defineThemeSystem("bootstrap4",a.default)},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(19),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(r.default);e.default=o,o.prototype.classes={widget:"fc-bootstrap3",tableGrid:"table-bordered",tableList:"table",tableListHeading:"active",buttonGroup:"btn-group",button:"btn btn-default",stateActive:"active",stateDisabled:"disabled",today:"alert alert-info",popover:"panel panel-default",popoverHeader:"panel-heading",popoverContent:"panel-body",headerRow:"panel-default",dayRow:"panel-default",listView:"panel panel-default"},o.prototype.baseIconClass="glyphicon",o.prototype.iconClasses={close:"glyphicon-remove",prev:"glyphicon-chevron-left",next:"glyphicon-chevron-right",prevYear:"glyphicon-backward",nextYear:"glyphicon-forward"},o.prototype.iconOverrideOption="bootstrapGlyphicons",o.prototype.iconOverrideCustomButtonOption="bootstrapGlyphicon",o.prototype.iconOverridePrefix="glyphicon-"},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(19),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e}(r.default);e.default=o,o.prototype.classes={widget:"fc-bootstrap4",tableGrid:"table-bordered",tableList:"table",tableListHeading:"table-active",buttonGroup:"btn-group",button:"btn btn-primary",stateActive:"active",stateDisabled:"disabled",today:"alert alert-info",popover:"card card-primary",popoverHeader:"card-header",popoverContent:"card-body",headerRow:"table-bordered",dayRow:"table-bordered",listView:"card card-primary"},o.prototype.baseIconClass="fa",o.prototype.iconClasses={close:"fa-times",prev:"fa-chevron-left",next:"fa-chevron-right",prevYear:"fa-angle-double-left",nextYear:"fa-angle-double-right"},o.prototype.iconOverrideOption="bootstrapFontAwesome",o.prototype.iconOverrideCustomButtonOption="bootstrapFontAwesome",o.prototype.iconOverridePrefix="fa-"},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(22),r=n(62),o=n(229);i.defineView("basic",{class:r.default}),i.defineView("basicDay",{type:"basic",duration:{days:1}}),i.defineView("basicWeek",{type:"basic",duration:{weeks:1}}),i.defineView("month",{class:o.default,duration:{months:1},defaults:{fixedWeekCount:!0}})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(22),r=n(226);i.defineView("agenda",{class:r.default,defaults:{allDaySlot:!0,slotDuration:"00:30:00",slotEventOverlap:!0}}),i.defineView("agendaDay",{type:"agenda",duration:{days:1}}),i.defineView("agendaWeek",{type:"agenda",duration:{weeks:1}})},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(22),r=n(230);i.defineView("list",{class:r.default,buttonTextKey:"list",defaults:{buttonText:"list",listDayFormat:"LL",noEventsMessage:"No events to display"}}),i.defineView("listDay",{type:"list",duration:{days:1},defaults:{listDayFormat:"dddd"}}),i.defineView("listWeek",{type:"list",duration:{weeks:1},defaults:{listDayFormat:"dddd",listDayAltFormat:"LL"}}),i.defineView("listMonth",{type:"list",duration:{month:1},defaults:{listDayAltFormat:"dddd"}}),i.defineView("listYear",{type:"list",duration:{year:1},defaults:{listDayAltFormat:"dddd"}})},function(t,e){Object.defineProperty(e,"__esModule",{value:!0})}])}); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css
new file mode 100644
index 00000000..fb858cd7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css
@@ -0,0 +1,176 @@
+/*!
+ * FullCalendar v3.9.0
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+/*!
+ * FullCalendar v3.9.0 Print Stylesheet
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+/*
+ * Include this stylesheet on your page to get a more printer-friendly calendar.
+ * When including this stylesheet, use the media='print' attribute of the <link> tag.
+ * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
+ */
+.fc {
+ max-width: 100% !important; }
+
+/* Global Event Restyling
+--------------------------------------------------------------------------------------------------*/
+.fc-event {
+ background: #fff !important;
+ color: #000 !important;
+ page-break-inside: avoid; }
+
+.fc-event .fc-resizer {
+ display: none; }
+
+/* Table & Day-Row Restyling
+--------------------------------------------------------------------------------------------------*/
+.fc th,
+.fc td,
+.fc hr,
+.fc thead,
+.fc tbody,
+.fc-row {
+ border-color: #ccc !important;
+ background: #fff !important; }
+
+/* kill the overlaid, absolutely-positioned components */
+/* common... */
+.fc-bg,
+.fc-bgevent-skeleton,
+.fc-highlight-skeleton,
+.fc-helper-skeleton,
+.fc-bgevent-container,
+.fc-business-container,
+.fc-highlight-container,
+.fc-helper-container {
+ display: none; }
+
+/* don't force a min-height on rows (for DayGrid) */
+.fc tbody .fc-row {
+ height: auto !important;
+ /* undo height that JS set in distributeHeight */
+ min-height: 0 !important;
+ /* undo the min-height from each view's specific stylesheet */ }
+
+.fc tbody .fc-row .fc-content-skeleton {
+ position: static;
+ /* undo .fc-rigid */
+ padding-bottom: 0 !important;
+ /* use a more border-friendly method for this... */ }
+
+.fc tbody .fc-row .fc-content-skeleton tbody tr:last-child td {
+ /* only works in newer browsers */
+ padding-bottom: 1em;
+ /* ...gives space within the skeleton. also ensures min height in a way */ }
+
+.fc tbody .fc-row .fc-content-skeleton table {
+ /* provides a min-height for the row, but only effective for IE, which exaggerates this value,
+ making it look more like 3em. for other browers, it will already be this tall */
+ height: 1em; }
+
+/* Undo month-view event limiting. Display all events and hide the "more" links
+--------------------------------------------------------------------------------------------------*/
+.fc-more-cell,
+.fc-more {
+ display: none !important; }
+
+.fc tr.fc-limited {
+ display: table-row !important; }
+
+.fc td.fc-limited {
+ display: table-cell !important; }
+
+.fc-popover {
+ display: none;
+ /* never display the "more.." popover in print mode */ }
+
+/* TimeGrid Restyling
+--------------------------------------------------------------------------------------------------*/
+/* undo the min-height 100% trick used to fill the container's height */
+.fc-time-grid {
+ min-height: 0 !important; }
+
+/* don't display the side axis at all ("all-day" and time cells) */
+.fc-agenda-view .fc-axis {
+ display: none; }
+
+/* don't display the horizontal lines */
+.fc-slats,
+.fc-time-grid hr {
+ /* this hr is used when height is underused and needs to be filled */
+ display: none !important;
+ /* important overrides inline declaration */ }
+
+/* let the container that holds the events be naturally positioned and create real height */
+.fc-time-grid .fc-content-skeleton {
+ position: static; }
+
+/* in case there are no events, we still want some height */
+.fc-time-grid .fc-content-skeleton table {
+ height: 4em; }
+
+/* kill the horizontal spacing made by the event container. event margins will be done below */
+.fc-time-grid .fc-event-container {
+ margin: 0 !important; }
+
+/* TimeGrid *Event* Restyling
+--------------------------------------------------------------------------------------------------*/
+/* naturally position events, vertically stacking them */
+.fc-time-grid .fc-event {
+ position: static !important;
+ margin: 3px 2px !important; }
+
+/* for events that continue to a future day, give the bottom border back */
+.fc-time-grid .fc-event.fc-not-end {
+ border-bottom-width: 1px !important; }
+
+/* indicate the event continues via "..." text */
+.fc-time-grid .fc-event.fc-not-end:after {
+ content: "..."; }
+
+/* for events that are continuations from previous days, give the top border back */
+.fc-time-grid .fc-event.fc-not-start {
+ border-top-width: 1px !important; }
+
+/* indicate the event is a continuation via "..." text */
+.fc-time-grid .fc-event.fc-not-start:before {
+ content: "..."; }
+
+/* time */
+/* undo a previous declaration and let the time text span to a second line */
+.fc-time-grid .fc-event .fc-time {
+ white-space: normal !important; }
+
+/* hide the the time that is normally displayed... */
+.fc-time-grid .fc-event .fc-time span {
+ display: none; }
+
+/* ...replace it with a more verbose version (includes AM/PM) stored in an html attribute */
+.fc-time-grid .fc-event .fc-time:after {
+ content: attr(data-full); }
+
+/* Vertical Scroller & Containers
+--------------------------------------------------------------------------------------------------*/
+/* kill the scrollbars and allow natural height */
+.fc-scroller,
+.fc-day-grid-container,
+.fc-time-grid-container {
+ /* */
+ overflow: visible !important;
+ height: auto !important; }
+
+/* kill the horizontal border/padding used to compensate for scrollbars */
+.fc-row {
+ border: 0 !important;
+ margin: 0 !important; }
+
+/* Button Controls
+--------------------------------------------------------------------------------------------------*/
+.fc-button-group,
+.fc button {
+ display: none;
+ /* don't display any button-related controls */ }
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js
new file mode 100644
index 00000000..bddcd1f0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js
@@ -0,0 +1,324 @@
+/*!
+ * FullCalendar v3.9.0
+ * Docs & License: https://fullcalendar.io/
+ * (c) 2018 Adam Shaw
+ */
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory(require("fullcalendar"), require("jquery"));
+ else if(typeof define === 'function' && define.amd)
+ define(["fullcalendar", "jquery"], factory);
+ else if(typeof exports === 'object')
+ factory(require("fullcalendar"), require("jquery"));
+ else
+ factory(root["FullCalendar"], root["jQuery"]);
+})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_3__) {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId]) {
+/******/ return installedModules[moduleId].exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ i: moduleId,
+/******/ l: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.l = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // define getter function for harmony exports
+/******/ __webpack_require__.d = function(exports, name, getter) {
+/******/ if(!__webpack_require__.o(exports, name)) {
+/******/ Object.defineProperty(exports, name, {
+/******/ configurable: false,
+/******/ enumerable: true,
+/******/ get: getter
+/******/ });
+/******/ }
+/******/ };
+/******/
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = function(module) {
+/******/ var getter = module && module.__esModule ?
+/******/ function getDefault() { return module['default']; } :
+/******/ function getModuleExports() { return module; };
+/******/ __webpack_require__.d(getter, 'a', getter);
+/******/ return getter;
+/******/ };
+/******/
+/******/ // Object.prototype.hasOwnProperty.call
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(__webpack_require__.s = 266);
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ 1:
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
+
+/***/ }),
+
+/***/ 2:
+/***/ (function(module, exports) {
+
+/*
+derived from:
+https://github.com/Microsoft/tslib/blob/v1.6.0/tslib.js
+
+only include the helpers we need, to keep down filesize
+*/
+var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b)
+ if (b.hasOwnProperty(p))
+ d[p] = b[p]; };
+exports.__extends = function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+
+
+/***/ }),
+
+/***/ 266:
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var exportHooks = __webpack_require__(1);
+var GcalEventSource_1 = __webpack_require__(267);
+exportHooks.EventSourceParser.registerClass(GcalEventSource_1.default);
+exportHooks.GcalEventSource = GcalEventSource_1.default;
+
+
+/***/ }),
+
+/***/ 267:
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var fullcalendar_1 = __webpack_require__(1);
+var GcalEventSource = /** @class */ (function (_super) {
+ tslib_1.__extends(GcalEventSource, _super);
+ function GcalEventSource() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ GcalEventSource.parse = function (rawInput, calendar) {
+ var rawProps;
+ if (typeof rawInput === 'object') {
+ rawProps = rawInput;
+ }
+ else if (typeof rawInput === 'string') {
+ rawProps = { url: rawInput }; // url will be parsed with parseGoogleCalendarId
+ }
+ if (rawProps) {
+ return fullcalendar_1.EventSource.parse.call(this, rawProps, calendar);
+ }
+ return false;
+ };
+ GcalEventSource.prototype.fetch = function (start, end, timezone) {
+ var _this = this;
+ var url = this.buildUrl();
+ var requestParams = this.buildRequestParams(start, end, timezone);
+ var ajaxSettings = this.ajaxSettings || {};
+ var onSuccess = ajaxSettings.success;
+ if (!requestParams) {
+ return fullcalendar_1.Promise.reject();
+ }
+ this.calendar.pushLoading();
+ return fullcalendar_1.Promise.construct(function (onResolve, onReject) {
+ $.ajax($.extend({}, // destination
+ fullcalendar_1.JsonFeedEventSource.AJAX_DEFAULTS, ajaxSettings, {
+ url: url,
+ data: requestParams,
+ success: function (responseData, status, xhr) {
+ var rawEventDefs;
+ var successRes;
+ _this.calendar.popLoading();
+ if (responseData.error) {
+ _this.reportError('Google Calendar API: ' + responseData.error.message, responseData.error.errors);
+ onReject();
+ }
+ else if (responseData.items) {
+ rawEventDefs = _this.gcalItemsToRawEventDefs(responseData.items, requestParams.timeZone);
+ successRes = fullcalendar_1.applyAll(onSuccess, _this, [responseData, status, xhr]); // passthru
+ if ($.isArray(successRes)) {
+ rawEventDefs = successRes;
+ }
+ onResolve(_this.parseEventDefs(rawEventDefs));
+ }
+ },
+ error: function (xhr, statusText, errorThrown) {
+ _this.reportError('Google Calendar network failure: ' + statusText, [xhr, errorThrown]);
+ _this.calendar.popLoading();
+ onReject();
+ }
+ }));
+ });
+ };
+ GcalEventSource.prototype.gcalItemsToRawEventDefs = function (items, gcalTimezone) {
+ var _this = this;
+ return items.map(function (item) {
+ return _this.gcalItemToRawEventDef(item, gcalTimezone);
+ });
+ };
+ GcalEventSource.prototype.gcalItemToRawEventDef = function (item, gcalTimezone) {
+ var url = item.htmlLink || null;
+ // make the URLs for each event show times in the correct timezone
+ if (url && gcalTimezone) {
+ url = injectQsComponent(url, 'ctz=' + gcalTimezone);
+ }
+ return {
+ id: item.id,
+ title: item.summary,
+ start: item.start.dateTime || item.start.date,
+ end: item.end.dateTime || item.end.date,
+ url: url,
+ location: item.location,
+ description: item.description
+ };
+ };
+ GcalEventSource.prototype.buildUrl = function () {
+ return GcalEventSource.API_BASE + '/' +
+ encodeURIComponent(this.googleCalendarId) +
+ '/events?callback=?'; // jsonp
+ };
+ GcalEventSource.prototype.buildRequestParams = function (start, end, timezone) {
+ var apiKey = this.googleCalendarApiKey || this.calendar.opt('googleCalendarApiKey');
+ var params;
+ if (!apiKey) {
+ this.reportError('Specify a googleCalendarApiKey. See http://fullcalendar.io/docs/google_calendar/');
+ return null;
+ }
+ // The API expects an ISO8601 datetime with a time and timezone part.
+ // Since the calendar's timezone offset isn't always known, request the date in UTC and pad it by a day on each
+ // side, guaranteeing we will receive all events in the desired range, albeit a superset.
+ // .utc() will set a zone and give it a 00:00:00 time.
+ if (!start.hasZone()) {
+ start = start.clone().utc().add(-1, 'day');
+ }
+ if (!end.hasZone()) {
+ end = end.clone().utc().add(1, 'day');
+ }
+ params = $.extend(this.ajaxSettings.data || {}, {
+ key: apiKey,
+ timeMin: start.format(),
+ timeMax: end.format(),
+ singleEvents: true,
+ maxResults: 9999
+ });
+ if (timezone && timezone !== 'local') {
+ // when sending timezone names to Google, only accepts underscores, not spaces
+ params.timeZone = timezone.replace(' ', '_');
+ }
+ return params;
+ };
+ GcalEventSource.prototype.reportError = function (message, apiErrorObjs) {
+ var calendar = this.calendar;
+ var calendarOnError = calendar.opt('googleCalendarError');
+ var errorObjs = apiErrorObjs || [{ message: message }]; // to be passed into error handlers
+ if (this.googleCalendarError) {
+ this.googleCalendarError.apply(calendar, errorObjs);
+ }
+ if (calendarOnError) {
+ calendarOnError.apply(calendar, errorObjs);
+ }
+ // print error to debug console
+ fullcalendar_1.warn.apply(null, [message].concat(apiErrorObjs || []));
+ };
+ GcalEventSource.prototype.getPrimitive = function () {
+ return this.googleCalendarId;
+ };
+ GcalEventSource.prototype.applyManualStandardProps = function (rawProps) {
+ var superSuccess = fullcalendar_1.EventSource.prototype.applyManualStandardProps.apply(this, arguments);
+ var googleCalendarId = rawProps.googleCalendarId;
+ if (googleCalendarId == null && rawProps.url) {
+ googleCalendarId = parseGoogleCalendarId(rawProps.url);
+ }
+ if (googleCalendarId != null) {
+ this.googleCalendarId = googleCalendarId;
+ return superSuccess;
+ }
+ return false;
+ };
+ GcalEventSource.prototype.applyMiscProps = function (rawProps) {
+ if (!this.ajaxSettings) {
+ this.ajaxSettings = {};
+ }
+ $.extend(this.ajaxSettings, rawProps);
+ };
+ GcalEventSource.API_BASE = 'https://www.googleapis.com/calendar/v3/calendars';
+ return GcalEventSource;
+}(fullcalendar_1.EventSource));
+exports.default = GcalEventSource;
+GcalEventSource.defineStandardProps({
+ // manually process...
+ url: false,
+ googleCalendarId: false,
+ // automatically transfer...
+ googleCalendarApiKey: true,
+ googleCalendarError: true
+});
+function parseGoogleCalendarId(url) {
+ var match;
+ // detect if the ID was specified as a single string.
+ // will match calendars like "asdf1234@calendar.google.com" in addition to person email calendars.
+ if (/^[^\/]+@([^\/\.]+\.)*(google|googlemail|gmail)\.com$/.test(url)) {
+ return url;
+ }
+ else if ((match = /^https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/([^\/]*)/.exec(url)) ||
+ (match = /^https?:\/\/www.google.com\/calendar\/feeds\/([^\/]*)/.exec(url))) {
+ return decodeURIComponent(match[1]);
+ }
+}
+// Injects a string like "arg=value" into the querystring of a URL
+function injectQsComponent(url, component) {
+ // inject it after the querystring but before the fragment
+ return url.replace(/(\?.*?)?(#|$)/, function (whole, qs, hash) {
+ return (qs ? qs + '&' : '?') + component + hash;
+ });
+}
+
+
+/***/ }),
+
+/***/ 3:
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_3__;
+
+/***/ })
+
+/******/ });
+}); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/moment.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/moment.js
new file mode 100644
index 00000000..ba40245a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/fullcalendar/moment.js
@@ -0,0 +1,4506 @@
+//! moment.js
+
+;(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ global.moment = factory()
+}(this, (function () { 'use strict';
+
+var hookCallback;
+
+function hooks () {
+ return hookCallback.apply(null, arguments);
+}
+
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function setHookCallback (callback) {
+ hookCallback = callback;
+}
+
+function isArray(input) {
+ return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+}
+
+function isObject(input) {
+ // IE8 will treat undefined and null as object if it wasn't for
+ // input != null
+ return input != null && Object.prototype.toString.call(input) === '[object Object]';
+}
+
+function isObjectEmpty(obj) {
+ if (Object.getOwnPropertyNames) {
+ return (Object.getOwnPropertyNames(obj).length === 0);
+ } else {
+ var k;
+ for (k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+function isUndefined(input) {
+ return input === void 0;
+}
+
+function isNumber(input) {
+ return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+}
+
+function isDate(input) {
+ return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+}
+
+function map(arr, fn) {
+ var res = [], i;
+ for (i = 0; i < arr.length; ++i) {
+ res.push(fn(arr[i], i));
+ }
+ return res;
+}
+
+function hasOwnProp(a, b) {
+ return Object.prototype.hasOwnProperty.call(a, b);
+}
+
+function extend(a, b) {
+ for (var i in b) {
+ if (hasOwnProp(b, i)) {
+ a[i] = b[i];
+ }
+ }
+
+ if (hasOwnProp(b, 'toString')) {
+ a.toString = b.toString;
+ }
+
+ if (hasOwnProp(b, 'valueOf')) {
+ a.valueOf = b.valueOf;
+ }
+
+ return a;
+}
+
+function createUTC (input, format, locale, strict) {
+ return createLocalOrUTC(input, format, locale, strict, true).utc();
+}
+
+function defaultParsingFlags() {
+ // We need to deep clone this object.
+ return {
+ empty : false,
+ unusedTokens : [],
+ unusedInput : [],
+ overflow : -2,
+ charsLeftOver : 0,
+ nullInput : false,
+ invalidMonth : null,
+ invalidFormat : false,
+ userInvalidated : false,
+ iso : false,
+ parsedDateParts : [],
+ meridiem : null,
+ rfc2822 : false,
+ weekdayMismatch : false
+ };
+}
+
+function getParsingFlags(m) {
+ if (m._pf == null) {
+ m._pf = defaultParsingFlags();
+ }
+ return m._pf;
+}
+
+var some;
+if (Array.prototype.some) {
+ some = Array.prototype.some;
+} else {
+ some = function (fun) {
+ var t = Object(this);
+ var len = t.length >>> 0;
+
+ for (var i = 0; i < len; i++) {
+ if (i in t && fun.call(this, t[i], i, t)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+}
+
+function isValid(m) {
+ if (m._isValid == null) {
+ var flags = getParsingFlags(m);
+ var parsedParts = some.call(flags.parsedDateParts, function (i) {
+ return i != null;
+ });
+ var isNowValid = !isNaN(m._d.getTime()) &&
+ flags.overflow < 0 &&
+ !flags.empty &&
+ !flags.invalidMonth &&
+ !flags.invalidWeekday &&
+ !flags.weekdayMismatch &&
+ !flags.nullInput &&
+ !flags.invalidFormat &&
+ !flags.userInvalidated &&
+ (!flags.meridiem || (flags.meridiem && parsedParts));
+
+ if (m._strict) {
+ isNowValid = isNowValid &&
+ flags.charsLeftOver === 0 &&
+ flags.unusedTokens.length === 0 &&
+ flags.bigHour === undefined;
+ }
+
+ if (Object.isFrozen == null || !Object.isFrozen(m)) {
+ m._isValid = isNowValid;
+ }
+ else {
+ return isNowValid;
+ }
+ }
+ return m._isValid;
+}
+
+function createInvalid (flags) {
+ var m = createUTC(NaN);
+ if (flags != null) {
+ extend(getParsingFlags(m), flags);
+ }
+ else {
+ getParsingFlags(m).userInvalidated = true;
+ }
+
+ return m;
+}
+
+// Plugins that add properties should also add the key here (null value),
+// so we can properly clone ourselves.
+var momentProperties = hooks.momentProperties = [];
+
+function copyConfig(to, from) {
+ var i, prop, val;
+
+ if (!isUndefined(from._isAMomentObject)) {
+ to._isAMomentObject = from._isAMomentObject;
+ }
+ if (!isUndefined(from._i)) {
+ to._i = from._i;
+ }
+ if (!isUndefined(from._f)) {
+ to._f = from._f;
+ }
+ if (!isUndefined(from._l)) {
+ to._l = from._l;
+ }
+ if (!isUndefined(from._strict)) {
+ to._strict = from._strict;
+ }
+ if (!isUndefined(from._tzm)) {
+ to._tzm = from._tzm;
+ }
+ if (!isUndefined(from._isUTC)) {
+ to._isUTC = from._isUTC;
+ }
+ if (!isUndefined(from._offset)) {
+ to._offset = from._offset;
+ }
+ if (!isUndefined(from._pf)) {
+ to._pf = getParsingFlags(from);
+ }
+ if (!isUndefined(from._locale)) {
+ to._locale = from._locale;
+ }
+
+ if (momentProperties.length > 0) {
+ for (i = 0; i < momentProperties.length; i++) {
+ prop = momentProperties[i];
+ val = from[prop];
+ if (!isUndefined(val)) {
+ to[prop] = val;
+ }
+ }
+ }
+
+ return to;
+}
+
+var updateInProgress = false;
+
+// Moment prototype object
+function Moment(config) {
+ copyConfig(this, config);
+ this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+ if (!this.isValid()) {
+ this._d = new Date(NaN);
+ }
+ // Prevent infinite loop in case updateOffset creates new moment
+ // objects.
+ if (updateInProgress === false) {
+ updateInProgress = true;
+ hooks.updateOffset(this);
+ updateInProgress = false;
+ }
+}
+
+function isMoment (obj) {
+ return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+}
+
+function absFloor (number) {
+ if (number < 0) {
+ // -0 -> 0
+ return Math.ceil(number) || 0;
+ } else {
+ return Math.floor(number);
+ }
+}
+
+function toInt(argumentForCoercion) {
+ var coercedNumber = +argumentForCoercion,
+ value = 0;
+
+ if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+ value = absFloor(coercedNumber);
+ }
+
+ return value;
+}
+
+// compare two arrays, return the number of differences
+function compareArrays(array1, array2, dontConvert) {
+ var len = Math.min(array1.length, array2.length),
+ lengthDiff = Math.abs(array1.length - array2.length),
+ diffs = 0,
+ i;
+ for (i = 0; i < len; i++) {
+ if ((dontConvert && array1[i] !== array2[i]) ||
+ (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+ diffs++;
+ }
+ }
+ return diffs + lengthDiff;
+}
+
+function warn(msg) {
+ if (hooks.suppressDeprecationWarnings === false &&
+ (typeof console !== 'undefined') && console.warn) {
+ console.warn('Deprecation warning: ' + msg);
+ }
+}
+
+function deprecate(msg, fn) {
+ var firstTime = true;
+
+ return extend(function () {
+ if (hooks.deprecationHandler != null) {
+ hooks.deprecationHandler(null, msg);
+ }
+ if (firstTime) {
+ var args = [];
+ var arg;
+ for (var i = 0; i < arguments.length; i++) {
+ arg = '';
+ if (typeof arguments[i] === 'object') {
+ arg += '\n[' + i + '] ';
+ for (var key in arguments[0]) {
+ arg += key + ': ' + arguments[0][key] + ', ';
+ }
+ arg = arg.slice(0, -2); // Remove trailing comma and space
+ } else {
+ arg = arguments[i];
+ }
+ args.push(arg);
+ }
+ warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+ firstTime = false;
+ }
+ return fn.apply(this, arguments);
+ }, fn);
+}
+
+var deprecations = {};
+
+function deprecateSimple(name, msg) {
+ if (hooks.deprecationHandler != null) {
+ hooks.deprecationHandler(name, msg);
+ }
+ if (!deprecations[name]) {
+ warn(msg);
+ deprecations[name] = true;
+ }
+}
+
+hooks.suppressDeprecationWarnings = false;
+hooks.deprecationHandler = null;
+
+function isFunction(input) {
+ return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+function set (config) {
+ var prop, i;
+ for (i in config) {
+ prop = config[i];
+ if (isFunction(prop)) {
+ this[i] = prop;
+ } else {
+ this['_' + i] = prop;
+ }
+ }
+ this._config = config;
+ // Lenient ordinal parsing accepts just a number in addition to
+ // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
+ // TODO: Remove "ordinalParse" fallback in next major release.
+ this._dayOfMonthOrdinalParseLenient = new RegExp(
+ (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
+ '|' + (/\d{1,2}/).source);
+}
+
+function mergeConfigs(parentConfig, childConfig) {
+ var res = extend({}, parentConfig), prop;
+ for (prop in childConfig) {
+ if (hasOwnProp(childConfig, prop)) {
+ if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+ res[prop] = {};
+ extend(res[prop], parentConfig[prop]);
+ extend(res[prop], childConfig[prop]);
+ } else if (childConfig[prop] != null) {
+ res[prop] = childConfig[prop];
+ } else {
+ delete res[prop];
+ }
+ }
+ }
+ for (prop in parentConfig) {
+ if (hasOwnProp(parentConfig, prop) &&
+ !hasOwnProp(childConfig, prop) &&
+ isObject(parentConfig[prop])) {
+ // make sure changes to properties don't modify parent config
+ res[prop] = extend({}, res[prop]);
+ }
+ }
+ return res;
+}
+
+function Locale(config) {
+ if (config != null) {
+ this.set(config);
+ }
+}
+
+var keys;
+
+if (Object.keys) {
+ keys = Object.keys;
+} else {
+ keys = function (obj) {
+ var i, res = [];
+ for (i in obj) {
+ if (hasOwnProp(obj, i)) {
+ res.push(i);
+ }
+ }
+ return res;
+ };
+}
+
+var defaultCalendar = {
+ sameDay : '[Today at] LT',
+ nextDay : '[Tomorrow at] LT',
+ nextWeek : 'dddd [at] LT',
+ lastDay : '[Yesterday at] LT',
+ lastWeek : '[Last] dddd [at] LT',
+ sameElse : 'L'
+};
+
+function calendar (key, mom, now) {
+ var output = this._calendar[key] || this._calendar['sameElse'];
+ return isFunction(output) ? output.call(mom, now) : output;
+}
+
+var defaultLongDateFormat = {
+ LTS : 'h:mm:ss A',
+ LT : 'h:mm A',
+ L : 'MM/DD/YYYY',
+ LL : 'MMMM D, YYYY',
+ LLL : 'MMMM D, YYYY h:mm A',
+ LLLL : 'dddd, MMMM D, YYYY h:mm A'
+};
+
+function longDateFormat (key) {
+ var format = this._longDateFormat[key],
+ formatUpper = this._longDateFormat[key.toUpperCase()];
+
+ if (format || !formatUpper) {
+ return format;
+ }
+
+ this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+ return val.slice(1);
+ });
+
+ return this._longDateFormat[key];
+}
+
+var defaultInvalidDate = 'Invalid date';
+
+function invalidDate () {
+ return this._invalidDate;
+}
+
+var defaultOrdinal = '%d';
+var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
+
+function ordinal (number) {
+ return this._ordinal.replace('%d', number);
+}
+
+var defaultRelativeTime = {
+ future : 'in %s',
+ past : '%s ago',
+ s : 'a few seconds',
+ ss : '%d seconds',
+ m : 'a minute',
+ mm : '%d minutes',
+ h : 'an hour',
+ hh : '%d hours',
+ d : 'a day',
+ dd : '%d days',
+ M : 'a month',
+ MM : '%d months',
+ y : 'a year',
+ yy : '%d years'
+};
+
+function relativeTime (number, withoutSuffix, string, isFuture) {
+ var output = this._relativeTime[string];
+ return (isFunction(output)) ?
+ output(number, withoutSuffix, string, isFuture) :
+ output.replace(/%d/i, number);
+}
+
+function pastFuture (diff, output) {
+ var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+ return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+}
+
+var aliases = {};
+
+function addUnitAlias (unit, shorthand) {
+ var lowerCase = unit.toLowerCase();
+ aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+}
+
+function normalizeUnits(units) {
+ return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+}
+
+function normalizeObjectUnits(inputObject) {
+ var normalizedInput = {},
+ normalizedProp,
+ prop;
+
+ for (prop in inputObject) {
+ if (hasOwnProp(inputObject, prop)) {
+ normalizedProp = normalizeUnits(prop);
+ if (normalizedProp) {
+ normalizedInput[normalizedProp] = inputObject[prop];
+ }
+ }
+ }
+
+ return normalizedInput;
+}
+
+var priorities = {};
+
+function addUnitPriority(unit, priority) {
+ priorities[unit] = priority;
+}
+
+function getPrioritizedUnits(unitsObj) {
+ var units = [];
+ for (var u in unitsObj) {
+ units.push({unit: u, priority: priorities[u]});
+ }
+ units.sort(function (a, b) {
+ return a.priority - b.priority;
+ });
+ return units;
+}
+
+function zeroFill(number, targetLength, forceSign) {
+ var absNumber = '' + Math.abs(number),
+ zerosToFill = targetLength - absNumber.length,
+ sign = number >= 0;
+ return (sign ? (forceSign ? '+' : '') : '-') +
+ Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+}
+
+var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+var formatFunctions = {};
+
+var formatTokenFunctions = {};
+
+// token: 'M'
+// padded: ['MM', 2]
+// ordinal: 'Mo'
+// callback: function () { this.month() + 1 }
+function addFormatToken (token, padded, ordinal, callback) {
+ var func = callback;
+ if (typeof callback === 'string') {
+ func = function () {
+ return this[callback]();
+ };
+ }
+ if (token) {
+ formatTokenFunctions[token] = func;
+ }
+ if (padded) {
+ formatTokenFunctions[padded[0]] = function () {
+ return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+ };
+ }
+ if (ordinal) {
+ formatTokenFunctions[ordinal] = function () {
+ return this.localeData().ordinal(func.apply(this, arguments), token);
+ };
+ }
+}
+
+function removeFormattingTokens(input) {
+ if (input.match(/\[[\s\S]/)) {
+ return input.replace(/^\[|\]$/g, '');
+ }
+ return input.replace(/\\/g, '');
+}
+
+function makeFormatFunction(format) {
+ var array = format.match(formattingTokens), i, length;
+
+ for (i = 0, length = array.length; i < length; i++) {
+ if (formatTokenFunctions[array[i]]) {
+ array[i] = formatTokenFunctions[array[i]];
+ } else {
+ array[i] = removeFormattingTokens(array[i]);
+ }
+ }
+
+ return function (mom) {
+ var output = '', i;
+ for (i = 0; i < length; i++) {
+ output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
+ }
+ return output;
+ };
+}
+
+// format date using native date object
+function formatMoment(m, format) {
+ if (!m.isValid()) {
+ return m.localeData().invalidDate();
+ }
+
+ format = expandFormat(format, m.localeData());
+ formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+ return formatFunctions[format](m);
+}
+
+function expandFormat(format, locale) {
+ var i = 5;
+
+ function replaceLongDateFormatTokens(input) {
+ return locale.longDateFormat(input) || input;
+ }
+
+ localFormattingTokens.lastIndex = 0;
+ while (i >= 0 && localFormattingTokens.test(format)) {
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+ localFormattingTokens.lastIndex = 0;
+ i -= 1;
+ }
+
+ return format;
+}
+
+var match1 = /\d/; // 0 - 9
+var match2 = /\d\d/; // 00 - 99
+var match3 = /\d{3}/; // 000 - 999
+var match4 = /\d{4}/; // 0000 - 9999
+var match6 = /[+-]?\d{6}/; // -999999 - 999999
+var match1to2 = /\d\d?/; // 0 - 99
+var match3to4 = /\d\d\d\d?/; // 999 - 9999
+var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
+var match1to3 = /\d{1,3}/; // 0 - 999
+var match1to4 = /\d{1,4}/; // 0 - 9999
+var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
+
+var matchUnsigned = /\d+/; // 0 - inf
+var matchSigned = /[+-]?\d+/; // -inf - inf
+
+var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+// any word (or two) characters or numbers including two/three word month in arabic.
+// includes scottish gaelic two word and hyphenated months
+var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
+
+var regexes = {};
+
+function addRegexToken (token, regex, strictRegex) {
+ regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+ return (isStrict && strictRegex) ? strictRegex : regex;
+ };
+}
+
+function getParseRegexForToken (token, config) {
+ if (!hasOwnProp(regexes, token)) {
+ return new RegExp(unescapeFormat(token));
+ }
+
+ return regexes[token](config._strict, config._locale);
+}
+
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function unescapeFormat(s) {
+ return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+ return p1 || p2 || p3 || p4;
+ }));
+}
+
+function regexEscape(s) {
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
+
+var tokens = {};
+
+function addParseToken (token, callback) {
+ var i, func = callback;
+ if (typeof token === 'string') {
+ token = [token];
+ }
+ if (isNumber(callback)) {
+ func = function (input, array) {
+ array[callback] = toInt(input);
+ };
+ }
+ for (i = 0; i < token.length; i++) {
+ tokens[token[i]] = func;
+ }
+}
+
+function addWeekParseToken (token, callback) {
+ addParseToken(token, function (input, array, config, token) {
+ config._w = config._w || {};
+ callback(input, config._w, config, token);
+ });
+}
+
+function addTimeToArrayFromToken(token, input, config) {
+ if (input != null && hasOwnProp(tokens, token)) {
+ tokens[token](input, config._a, config, token);
+ }
+}
+
+var YEAR = 0;
+var MONTH = 1;
+var DATE = 2;
+var HOUR = 3;
+var MINUTE = 4;
+var SECOND = 5;
+var MILLISECOND = 6;
+var WEEK = 7;
+var WEEKDAY = 8;
+
+// FORMATTING
+
+addFormatToken('Y', 0, 0, function () {
+ var y = this.year();
+ return y <= 9999 ? '' + y : '+' + y;
+});
+
+addFormatToken(0, ['YY', 2], 0, function () {
+ return this.year() % 100;
+});
+
+addFormatToken(0, ['YYYY', 4], 0, 'year');
+addFormatToken(0, ['YYYYY', 5], 0, 'year');
+addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+// ALIASES
+
+addUnitAlias('year', 'y');
+
+// PRIORITIES
+
+addUnitPriority('year', 1);
+
+// PARSING
+
+addRegexToken('Y', matchSigned);
+addRegexToken('YY', match1to2, match2);
+addRegexToken('YYYY', match1to4, match4);
+addRegexToken('YYYYY', match1to6, match6);
+addRegexToken('YYYYYY', match1to6, match6);
+
+addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+addParseToken('YYYY', function (input, array) {
+ array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+});
+addParseToken('YY', function (input, array) {
+ array[YEAR] = hooks.parseTwoDigitYear(input);
+});
+addParseToken('Y', function (input, array) {
+ array[YEAR] = parseInt(input, 10);
+});
+
+// HELPERS
+
+function daysInYear(year) {
+ return isLeapYear(year) ? 366 : 365;
+}
+
+function isLeapYear(year) {
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+}
+
+// HOOKS
+
+hooks.parseTwoDigitYear = function (input) {
+ return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+};
+
+// MOMENTS
+
+var getSetYear = makeGetSet('FullYear', true);
+
+function getIsLeapYear () {
+ return isLeapYear(this.year());
+}
+
+function makeGetSet (unit, keepTime) {
+ return function (value) {
+ if (value != null) {
+ set$1(this, unit, value);
+ hooks.updateOffset(this, keepTime);
+ return this;
+ } else {
+ return get(this, unit);
+ }
+ };
+}
+
+function get (mom, unit) {
+ return mom.isValid() ?
+ mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+}
+
+function set$1 (mom, unit, value) {
+ if (mom.isValid() && !isNaN(value)) {
+ if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
+ }
+ else {
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+ }
+ }
+}
+
+// MOMENTS
+
+function stringGet (units) {
+ units = normalizeUnits(units);
+ if (isFunction(this[units])) {
+ return this[units]();
+ }
+ return this;
+}
+
+
+function stringSet (units, value) {
+ if (typeof units === 'object') {
+ units = normalizeObjectUnits(units);
+ var prioritized = getPrioritizedUnits(units);
+ for (var i = 0; i < prioritized.length; i++) {
+ this[prioritized[i].unit](units[prioritized[i].unit]);
+ }
+ } else {
+ units = normalizeUnits(units);
+ if (isFunction(this[units])) {
+ return this[units](value);
+ }
+ }
+ return this;
+}
+
+function mod(n, x) {
+ return ((n % x) + x) % x;
+}
+
+var indexOf;
+
+if (Array.prototype.indexOf) {
+ indexOf = Array.prototype.indexOf;
+} else {
+ indexOf = function (o) {
+ // I know
+ var i;
+ for (i = 0; i < this.length; ++i) {
+ if (this[i] === o) {
+ return i;
+ }
+ }
+ return -1;
+ };
+}
+
+function daysInMonth(year, month) {
+ if (isNaN(year) || isNaN(month)) {
+ return NaN;
+ }
+ var modMonth = mod(month, 12);
+ year += (month - modMonth) / 12;
+ return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
+}
+
+// FORMATTING
+
+addFormatToken('M', ['MM', 2], 'Mo', function () {
+ return this.month() + 1;
+});
+
+addFormatToken('MMM', 0, 0, function (format) {
+ return this.localeData().monthsShort(this, format);
+});
+
+addFormatToken('MMMM', 0, 0, function (format) {
+ return this.localeData().months(this, format);
+});
+
+// ALIASES
+
+addUnitAlias('month', 'M');
+
+// PRIORITY
+
+addUnitPriority('month', 8);
+
+// PARSING
+
+addRegexToken('M', match1to2);
+addRegexToken('MM', match1to2, match2);
+addRegexToken('MMM', function (isStrict, locale) {
+ return locale.monthsShortRegex(isStrict);
+});
+addRegexToken('MMMM', function (isStrict, locale) {
+ return locale.monthsRegex(isStrict);
+});
+
+addParseToken(['M', 'MM'], function (input, array) {
+ array[MONTH] = toInt(input) - 1;
+});
+
+addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+ var month = config._locale.monthsParse(input, token, config._strict);
+ // if we didn't find a month name, mark the date as invalid.
+ if (month != null) {
+ array[MONTH] = month;
+ } else {
+ getParsingFlags(config).invalidMonth = input;
+ }
+});
+
+// LOCALES
+
+var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+function localeMonths (m, format) {
+ if (!m) {
+ return isArray(this._months) ? this._months :
+ this._months['standalone'];
+ }
+ return isArray(this._months) ? this._months[m.month()] :
+ this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+function localeMonthsShort (m, format) {
+ if (!m) {
+ return isArray(this._monthsShort) ? this._monthsShort :
+ this._monthsShort['standalone'];
+ }
+ return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+ this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+function handleStrictParse(monthName, format, strict) {
+ var i, ii, mom, llc = monthName.toLocaleLowerCase();
+ if (!this._monthsParse) {
+ // this is not used
+ this._monthsParse = [];
+ this._longMonthsParse = [];
+ this._shortMonthsParse = [];
+ for (i = 0; i < 12; ++i) {
+ mom = createUTC([2000, i]);
+ this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+ this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+ }
+ }
+
+ if (strict) {
+ if (format === 'MMM') {
+ ii = indexOf.call(this._shortMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf.call(this._longMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ } else {
+ if (format === 'MMM') {
+ ii = indexOf.call(this._shortMonthsParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._longMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf.call(this._longMonthsParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._shortMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ }
+}
+
+function localeMonthsParse (monthName, format, strict) {
+ var i, mom, regex;
+
+ if (this._monthsParseExact) {
+ return handleStrictParse.call(this, monthName, format, strict);
+ }
+
+ if (!this._monthsParse) {
+ this._monthsParse = [];
+ this._longMonthsParse = [];
+ this._shortMonthsParse = [];
+ }
+
+ // TODO: add sorting
+ // Sorting makes sure if one month (or abbr) is a prefix of another
+ // see sorting in computeMonthsParse
+ for (i = 0; i < 12; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, i]);
+ if (strict && !this._longMonthsParse[i]) {
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+ }
+ if (!strict && !this._monthsParse[i]) {
+ regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+ this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+ }
+ // test the regex
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
+ return i;
+ }
+ }
+}
+
+// MOMENTS
+
+function setMonth (mom, value) {
+ var dayOfMonth;
+
+ if (!mom.isValid()) {
+ // No op
+ return mom;
+ }
+
+ if (typeof value === 'string') {
+ if (/^\d+$/.test(value)) {
+ value = toInt(value);
+ } else {
+ value = mom.localeData().monthsParse(value);
+ // TODO: Another silent failure?
+ if (!isNumber(value)) {
+ return mom;
+ }
+ }
+ }
+
+ dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+ return mom;
+}
+
+function getSetMonth (value) {
+ if (value != null) {
+ setMonth(this, value);
+ hooks.updateOffset(this, true);
+ return this;
+ } else {
+ return get(this, 'Month');
+ }
+}
+
+function getDaysInMonth () {
+ return daysInMonth(this.year(), this.month());
+}
+
+var defaultMonthsShortRegex = matchWord;
+function monthsShortRegex (isStrict) {
+ if (this._monthsParseExact) {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ computeMonthsParse.call(this);
+ }
+ if (isStrict) {
+ return this._monthsShortStrictRegex;
+ } else {
+ return this._monthsShortRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_monthsShortRegex')) {
+ this._monthsShortRegex = defaultMonthsShortRegex;
+ }
+ return this._monthsShortStrictRegex && isStrict ?
+ this._monthsShortStrictRegex : this._monthsShortRegex;
+ }
+}
+
+var defaultMonthsRegex = matchWord;
+function monthsRegex (isStrict) {
+ if (this._monthsParseExact) {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ computeMonthsParse.call(this);
+ }
+ if (isStrict) {
+ return this._monthsStrictRegex;
+ } else {
+ return this._monthsRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ this._monthsRegex = defaultMonthsRegex;
+ }
+ return this._monthsStrictRegex && isStrict ?
+ this._monthsStrictRegex : this._monthsRegex;
+ }
+}
+
+function computeMonthsParse () {
+ function cmpLenRev(a, b) {
+ return b.length - a.length;
+ }
+
+ var shortPieces = [], longPieces = [], mixedPieces = [],
+ i, mom;
+ for (i = 0; i < 12; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, i]);
+ shortPieces.push(this.monthsShort(mom, ''));
+ longPieces.push(this.months(mom, ''));
+ mixedPieces.push(this.months(mom, ''));
+ mixedPieces.push(this.monthsShort(mom, ''));
+ }
+ // Sorting makes sure if one month (or abbr) is a prefix of another it
+ // will match the longer piece.
+ shortPieces.sort(cmpLenRev);
+ longPieces.sort(cmpLenRev);
+ mixedPieces.sort(cmpLenRev);
+ for (i = 0; i < 12; i++) {
+ shortPieces[i] = regexEscape(shortPieces[i]);
+ longPieces[i] = regexEscape(longPieces[i]);
+ }
+ for (i = 0; i < 24; i++) {
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
+ }
+
+ this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+ this._monthsShortRegex = this._monthsRegex;
+ this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+ this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+}
+
+function createDate (y, m, d, h, M, s, ms) {
+ // can't just apply() to create a date:
+ // https://stackoverflow.com/q/181348
+ var date = new Date(y, m, d, h, M, s, ms);
+
+ // the date constructor remaps years 0-99 to 1900-1999
+ if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
+ date.setFullYear(y);
+ }
+ return date;
+}
+
+function createUTCDate (y) {
+ var date = new Date(Date.UTC.apply(null, arguments));
+
+ // the Date.UTC function remaps years 0-99 to 1900-1999
+ if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
+ date.setUTCFullYear(y);
+ }
+ return date;
+}
+
+// start-of-first-week - start-of-year
+function firstWeekOffset(year, dow, doy) {
+ var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+ fwd = 7 + dow - doy,
+ // first-week day local weekday -- which local weekday is fwd
+ fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+ return -fwdlw + fwd - 1;
+}
+
+// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+ var localWeekday = (7 + weekday - dow) % 7,
+ weekOffset = firstWeekOffset(year, dow, doy),
+ dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+ resYear, resDayOfYear;
+
+ if (dayOfYear <= 0) {
+ resYear = year - 1;
+ resDayOfYear = daysInYear(resYear) + dayOfYear;
+ } else if (dayOfYear > daysInYear(year)) {
+ resYear = year + 1;
+ resDayOfYear = dayOfYear - daysInYear(year);
+ } else {
+ resYear = year;
+ resDayOfYear = dayOfYear;
+ }
+
+ return {
+ year: resYear,
+ dayOfYear: resDayOfYear
+ };
+}
+
+function weekOfYear(mom, dow, doy) {
+ var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+ week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+ resWeek, resYear;
+
+ if (week < 1) {
+ resYear = mom.year() - 1;
+ resWeek = week + weeksInYear(resYear, dow, doy);
+ } else if (week > weeksInYear(mom.year(), dow, doy)) {
+ resWeek = week - weeksInYear(mom.year(), dow, doy);
+ resYear = mom.year() + 1;
+ } else {
+ resYear = mom.year();
+ resWeek = week;
+ }
+
+ return {
+ week: resWeek,
+ year: resYear
+ };
+}
+
+function weeksInYear(year, dow, doy) {
+ var weekOffset = firstWeekOffset(year, dow, doy),
+ weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+ return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+}
+
+// FORMATTING
+
+addFormatToken('w', ['ww', 2], 'wo', 'week');
+addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+// ALIASES
+
+addUnitAlias('week', 'w');
+addUnitAlias('isoWeek', 'W');
+
+// PRIORITIES
+
+addUnitPriority('week', 5);
+addUnitPriority('isoWeek', 5);
+
+// PARSING
+
+addRegexToken('w', match1to2);
+addRegexToken('ww', match1to2, match2);
+addRegexToken('W', match1to2);
+addRegexToken('WW', match1to2, match2);
+
+addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+ week[token.substr(0, 1)] = toInt(input);
+});
+
+// HELPERS
+
+// LOCALES
+
+function localeWeek (mom) {
+ return weekOfYear(mom, this._week.dow, this._week.doy).week;
+}
+
+var defaultLocaleWeek = {
+ dow : 0, // Sunday is the first day of the week.
+ doy : 6 // The week that contains Jan 1st is the first week of the year.
+};
+
+function localeFirstDayOfWeek () {
+ return this._week.dow;
+}
+
+function localeFirstDayOfYear () {
+ return this._week.doy;
+}
+
+// MOMENTS
+
+function getSetWeek (input) {
+ var week = this.localeData().week(this);
+ return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+function getSetISOWeek (input) {
+ var week = weekOfYear(this, 1, 4).week;
+ return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+// FORMATTING
+
+addFormatToken('d', 0, 'do', 'day');
+
+addFormatToken('dd', 0, 0, function (format) {
+ return this.localeData().weekdaysMin(this, format);
+});
+
+addFormatToken('ddd', 0, 0, function (format) {
+ return this.localeData().weekdaysShort(this, format);
+});
+
+addFormatToken('dddd', 0, 0, function (format) {
+ return this.localeData().weekdays(this, format);
+});
+
+addFormatToken('e', 0, 0, 'weekday');
+addFormatToken('E', 0, 0, 'isoWeekday');
+
+// ALIASES
+
+addUnitAlias('day', 'd');
+addUnitAlias('weekday', 'e');
+addUnitAlias('isoWeekday', 'E');
+
+// PRIORITY
+addUnitPriority('day', 11);
+addUnitPriority('weekday', 11);
+addUnitPriority('isoWeekday', 11);
+
+// PARSING
+
+addRegexToken('d', match1to2);
+addRegexToken('e', match1to2);
+addRegexToken('E', match1to2);
+addRegexToken('dd', function (isStrict, locale) {
+ return locale.weekdaysMinRegex(isStrict);
+});
+addRegexToken('ddd', function (isStrict, locale) {
+ return locale.weekdaysShortRegex(isStrict);
+});
+addRegexToken('dddd', function (isStrict, locale) {
+ return locale.weekdaysRegex(isStrict);
+});
+
+addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+ var weekday = config._locale.weekdaysParse(input, token, config._strict);
+ // if we didn't get a weekday name, mark the date as invalid
+ if (weekday != null) {
+ week.d = weekday;
+ } else {
+ getParsingFlags(config).invalidWeekday = input;
+ }
+});
+
+addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+ week[token] = toInt(input);
+});
+
+// HELPERS
+
+function parseWeekday(input, locale) {
+ if (typeof input !== 'string') {
+ return input;
+ }
+
+ if (!isNaN(input)) {
+ return parseInt(input, 10);
+ }
+
+ input = locale.weekdaysParse(input);
+ if (typeof input === 'number') {
+ return input;
+ }
+
+ return null;
+}
+
+function parseIsoWeekday(input, locale) {
+ if (typeof input === 'string') {
+ return locale.weekdaysParse(input) % 7 || 7;
+ }
+ return isNaN(input) ? null : input;
+}
+
+// LOCALES
+
+var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+function localeWeekdays (m, format) {
+ if (!m) {
+ return isArray(this._weekdays) ? this._weekdays :
+ this._weekdays['standalone'];
+ }
+ return isArray(this._weekdays) ? this._weekdays[m.day()] :
+ this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
+}
+
+var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+function localeWeekdaysShort (m) {
+ return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+}
+
+var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+function localeWeekdaysMin (m) {
+ return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+}
+
+function handleStrictParse$1(weekdayName, format, strict) {
+ var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+ if (!this._weekdaysParse) {
+ this._weekdaysParse = [];
+ this._shortWeekdaysParse = [];
+ this._minWeekdaysParse = [];
+
+ for (i = 0; i < 7; ++i) {
+ mom = createUTC([2000, 1]).day(i);
+ this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+ this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+ this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+ }
+ }
+
+ if (strict) {
+ if (format === 'dddd') {
+ ii = indexOf.call(this._weekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else if (format === 'ddd') {
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ } else {
+ if (format === 'dddd') {
+ ii = indexOf.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else if (format === 'ddd') {
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf.call(this._minWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ }
+}
+
+function localeWeekdaysParse (weekdayName, format, strict) {
+ var i, mom, regex;
+
+ if (this._weekdaysParseExact) {
+ return handleStrictParse$1.call(this, weekdayName, format, strict);
+ }
+
+ if (!this._weekdaysParse) {
+ this._weekdaysParse = [];
+ this._minWeekdaysParse = [];
+ this._shortWeekdaysParse = [];
+ this._fullWeekdaysParse = [];
+ }
+
+ for (i = 0; i < 7; i++) {
+ // make the regex if we don't have it already
+
+ mom = createUTC([2000, 1]).day(i);
+ if (strict && !this._fullWeekdaysParse[i]) {
+ this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
+ this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
+ this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
+ }
+ if (!this._weekdaysParse[i]) {
+ regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+ this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+ }
+ // test the regex
+ if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+ return i;
+ }
+ }
+}
+
+// MOMENTS
+
+function getSetDayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+ if (input != null) {
+ input = parseWeekday(input, this.localeData());
+ return this.add(input - day, 'd');
+ } else {
+ return day;
+ }
+}
+
+function getSetLocaleDayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+ return input == null ? weekday : this.add(input - weekday, 'd');
+}
+
+function getSetISODayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+
+ // behaves the same as moment#day except
+ // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+ // as a setter, sunday should belong to the previous week.
+
+ if (input != null) {
+ var weekday = parseIsoWeekday(input, this.localeData());
+ return this.day(this.day() % 7 ? weekday : weekday - 7);
+ } else {
+ return this.day() || 7;
+ }
+}
+
+var defaultWeekdaysRegex = matchWord;
+function weekdaysRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysStrictRegex;
+ } else {
+ return this._weekdaysRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ this._weekdaysRegex = defaultWeekdaysRegex;
+ }
+ return this._weekdaysStrictRegex && isStrict ?
+ this._weekdaysStrictRegex : this._weekdaysRegex;
+ }
+}
+
+var defaultWeekdaysShortRegex = matchWord;
+function weekdaysShortRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysShortStrictRegex;
+ } else {
+ return this._weekdaysShortRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+ this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+ }
+ return this._weekdaysShortStrictRegex && isStrict ?
+ this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+ }
+}
+
+var defaultWeekdaysMinRegex = matchWord;
+function weekdaysMinRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysMinStrictRegex;
+ } else {
+ return this._weekdaysMinRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+ this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+ }
+ return this._weekdaysMinStrictRegex && isStrict ?
+ this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+ }
+}
+
+
+function computeWeekdaysParse () {
+ function cmpLenRev(a, b) {
+ return b.length - a.length;
+ }
+
+ var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+ i, mom, minp, shortp, longp;
+ for (i = 0; i < 7; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, 1]).day(i);
+ minp = this.weekdaysMin(mom, '');
+ shortp = this.weekdaysShort(mom, '');
+ longp = this.weekdays(mom, '');
+ minPieces.push(minp);
+ shortPieces.push(shortp);
+ longPieces.push(longp);
+ mixedPieces.push(minp);
+ mixedPieces.push(shortp);
+ mixedPieces.push(longp);
+ }
+ // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+ // will match the longer piece.
+ minPieces.sort(cmpLenRev);
+ shortPieces.sort(cmpLenRev);
+ longPieces.sort(cmpLenRev);
+ mixedPieces.sort(cmpLenRev);
+ for (i = 0; i < 7; i++) {
+ shortPieces[i] = regexEscape(shortPieces[i]);
+ longPieces[i] = regexEscape(longPieces[i]);
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
+ }
+
+ this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+ this._weekdaysShortRegex = this._weekdaysRegex;
+ this._weekdaysMinRegex = this._weekdaysRegex;
+
+ this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+ this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+ this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+function hFormat() {
+ return this.hours() % 12 || 12;
+}
+
+function kFormat() {
+ return this.hours() || 24;
+}
+
+addFormatToken('H', ['HH', 2], 0, 'hour');
+addFormatToken('h', ['hh', 2], 0, hFormat);
+addFormatToken('k', ['kk', 2], 0, kFormat);
+
+addFormatToken('hmm', 0, 0, function () {
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('hmmss', 0, 0, function () {
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+ zeroFill(this.seconds(), 2);
+});
+
+addFormatToken('Hmm', 0, 0, function () {
+ return '' + this.hours() + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('Hmmss', 0, 0, function () {
+ return '' + this.hours() + zeroFill(this.minutes(), 2) +
+ zeroFill(this.seconds(), 2);
+});
+
+function meridiem (token, lowercase) {
+ addFormatToken(token, 0, 0, function () {
+ return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+ });
+}
+
+meridiem('a', true);
+meridiem('A', false);
+
+// ALIASES
+
+addUnitAlias('hour', 'h');
+
+// PRIORITY
+addUnitPriority('hour', 13);
+
+// PARSING
+
+function matchMeridiem (isStrict, locale) {
+ return locale._meridiemParse;
+}
+
+addRegexToken('a', matchMeridiem);
+addRegexToken('A', matchMeridiem);
+addRegexToken('H', match1to2);
+addRegexToken('h', match1to2);
+addRegexToken('k', match1to2);
+addRegexToken('HH', match1to2, match2);
+addRegexToken('hh', match1to2, match2);
+addRegexToken('kk', match1to2, match2);
+
+addRegexToken('hmm', match3to4);
+addRegexToken('hmmss', match5to6);
+addRegexToken('Hmm', match3to4);
+addRegexToken('Hmmss', match5to6);
+
+addParseToken(['H', 'HH'], HOUR);
+addParseToken(['k', 'kk'], function (input, array, config) {
+ var kInput = toInt(input);
+ array[HOUR] = kInput === 24 ? 0 : kInput;
+});
+addParseToken(['a', 'A'], function (input, array, config) {
+ config._isPm = config._locale.isPM(input);
+ config._meridiem = input;
+});
+addParseToken(['h', 'hh'], function (input, array, config) {
+ array[HOUR] = toInt(input);
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmm', function (input, array, config) {
+ var pos = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos));
+ array[MINUTE] = toInt(input.substr(pos));
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmmss', function (input, array, config) {
+ var pos1 = input.length - 4;
+ var pos2 = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos1));
+ array[MINUTE] = toInt(input.substr(pos1, 2));
+ array[SECOND] = toInt(input.substr(pos2));
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('Hmm', function (input, array, config) {
+ var pos = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos));
+ array[MINUTE] = toInt(input.substr(pos));
+});
+addParseToken('Hmmss', function (input, array, config) {
+ var pos1 = input.length - 4;
+ var pos2 = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos1));
+ array[MINUTE] = toInt(input.substr(pos1, 2));
+ array[SECOND] = toInt(input.substr(pos2));
+});
+
+// LOCALES
+
+function localeIsPM (input) {
+ // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+ // Using charAt should be more compatible.
+ return ((input + '').toLowerCase().charAt(0) === 'p');
+}
+
+var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+function localeMeridiem (hours, minutes, isLower) {
+ if (hours > 11) {
+ return isLower ? 'pm' : 'PM';
+ } else {
+ return isLower ? 'am' : 'AM';
+ }
+}
+
+
+// MOMENTS
+
+// Setting the hour should keep the time, because the user explicitly
+// specified which hour he wants. So trying to maintain the same hour (in
+// a new timezone) makes sense. Adding/subtracting hours does not follow
+// this rule.
+var getSetHour = makeGetSet('Hours', true);
+
+var baseConfig = {
+ calendar: defaultCalendar,
+ longDateFormat: defaultLongDateFormat,
+ invalidDate: defaultInvalidDate,
+ ordinal: defaultOrdinal,
+ dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
+ relativeTime: defaultRelativeTime,
+
+ months: defaultLocaleMonths,
+ monthsShort: defaultLocaleMonthsShort,
+
+ week: defaultLocaleWeek,
+
+ weekdays: defaultLocaleWeekdays,
+ weekdaysMin: defaultLocaleWeekdaysMin,
+ weekdaysShort: defaultLocaleWeekdaysShort,
+
+ meridiemParse: defaultLocaleMeridiemParse
+};
+
+// internal storage for locale config files
+var locales = {};
+var localeFamilies = {};
+var globalLocale;
+
+function normalizeLocale(key) {
+ return key ? key.toLowerCase().replace('_', '-') : key;
+}
+
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function chooseLocale(names) {
+ var i = 0, j, next, locale, split;
+
+ while (i < names.length) {
+ split = normalizeLocale(names[i]).split('-');
+ j = split.length;
+ next = normalizeLocale(names[i + 1]);
+ next = next ? next.split('-') : null;
+ while (j > 0) {
+ locale = loadLocale(split.slice(0, j).join('-'));
+ if (locale) {
+ return locale;
+ }
+ if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+ //the next array item is better than a shallower substring of this one
+ break;
+ }
+ j--;
+ }
+ i++;
+ }
+ return globalLocale;
+}
+
+function loadLocale(name) {
+ var oldLocale = null;
+ // TODO: Find a better way to register and load all the locales in Node
+ if (!locales[name] && (typeof module !== 'undefined') &&
+ module && module.exports) {
+ try {
+ oldLocale = globalLocale._abbr;
+ var aliasedRequire = require;
+ aliasedRequire('./locale/' + name);
+ getSetGlobalLocale(oldLocale);
+ } catch (e) {}
+ }
+ return locales[name];
+}
+
+// This function will load locale and then set the global locale. If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function getSetGlobalLocale (key, values) {
+ var data;
+ if (key) {
+ if (isUndefined(values)) {
+ data = getLocale(key);
+ }
+ else {
+ data = defineLocale(key, values);
+ }
+
+ if (data) {
+ // moment.duration._locale = moment._locale = data;
+ globalLocale = data;
+ }
+ else {
+ if ((typeof console !== 'undefined') && console.warn) {
+ //warn user if arguments are passed but the locale could not be set
+ console.warn('Locale ' + key + ' not found. Did you forget to load it?');
+ }
+ }
+ }
+
+ return globalLocale._abbr;
+}
+
+function defineLocale (name, config) {
+ if (config !== null) {
+ var locale, parentConfig = baseConfig;
+ config.abbr = name;
+ if (locales[name] != null) {
+ deprecateSimple('defineLocaleOverride',
+ 'use moment.updateLocale(localeName, config) to change ' +
+ 'an existing locale. moment.defineLocale(localeName, ' +
+ 'config) should only be used for creating a new locale ' +
+ 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+ parentConfig = locales[name]._config;
+ } else if (config.parentLocale != null) {
+ if (locales[config.parentLocale] != null) {
+ parentConfig = locales[config.parentLocale]._config;
+ } else {
+ locale = loadLocale(config.parentLocale);
+ if (locale != null) {
+ parentConfig = locale._config;
+ } else {
+ if (!localeFamilies[config.parentLocale]) {
+ localeFamilies[config.parentLocale] = [];
+ }
+ localeFamilies[config.parentLocale].push({
+ name: name,
+ config: config
+ });
+ return null;
+ }
+ }
+ }
+ locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+ if (localeFamilies[name]) {
+ localeFamilies[name].forEach(function (x) {
+ defineLocale(x.name, x.config);
+ });
+ }
+
+ // backwards compat for now: also set the locale
+ // make sure we set the locale AFTER all child locales have been
+ // created, so we won't end up with the child locale set.
+ getSetGlobalLocale(name);
+
+
+ return locales[name];
+ } else {
+ // useful for testing
+ delete locales[name];
+ return null;
+ }
+}
+
+function updateLocale(name, config) {
+ if (config != null) {
+ var locale, tmpLocale, parentConfig = baseConfig;
+ // MERGE
+ tmpLocale = loadLocale(name);
+ if (tmpLocale != null) {
+ parentConfig = tmpLocale._config;
+ }
+ config = mergeConfigs(parentConfig, config);
+ locale = new Locale(config);
+ locale.parentLocale = locales[name];
+ locales[name] = locale;
+
+ // backwards compat for now: also set the locale
+ getSetGlobalLocale(name);
+ } else {
+ // pass null for config to unupdate, useful for tests
+ if (locales[name] != null) {
+ if (locales[name].parentLocale != null) {
+ locales[name] = locales[name].parentLocale;
+ } else if (locales[name] != null) {
+ delete locales[name];
+ }
+ }
+ }
+ return locales[name];
+}
+
+// returns locale data
+function getLocale (key) {
+ var locale;
+
+ if (key && key._locale && key._locale._abbr) {
+ key = key._locale._abbr;
+ }
+
+ if (!key) {
+ return globalLocale;
+ }
+
+ if (!isArray(key)) {
+ //short-circuit everything else
+ locale = loadLocale(key);
+ if (locale) {
+ return locale;
+ }
+ key = [key];
+ }
+
+ return chooseLocale(key);
+}
+
+function listLocales() {
+ return keys(locales);
+}
+
+function checkOverflow (m) {
+ var overflow;
+ var a = m._a;
+
+ if (a && getParsingFlags(m).overflow === -2) {
+ overflow =
+ a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
+ a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+ a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+ a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
+ a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
+ a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+ -1;
+
+ if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+ overflow = DATE;
+ }
+ if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+ overflow = WEEK;
+ }
+ if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+ overflow = WEEKDAY;
+ }
+
+ getParsingFlags(m).overflow = overflow;
+ }
+
+ return m;
+}
+
+// Pick the first defined of two or three arguments.
+function defaults(a, b, c) {
+ if (a != null) {
+ return a;
+ }
+ if (b != null) {
+ return b;
+ }
+ return c;
+}
+
+function currentDateArray(config) {
+ // hooks is actually the exported moment object
+ var nowValue = new Date(hooks.now());
+ if (config._useUTC) {
+ return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+ }
+ return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+}
+
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function configFromArray (config) {
+ var i, date, input = [], currentDate, expectedWeekday, yearToUse;
+
+ if (config._d) {
+ return;
+ }
+
+ currentDate = currentDateArray(config);
+
+ //compute day of the year from weeks and weekdays
+ if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+ dayOfYearFromWeekInfo(config);
+ }
+
+ //if the day of the year is set, figure out what it is
+ if (config._dayOfYear != null) {
+ yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+ if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
+ getParsingFlags(config)._overflowDayOfYear = true;
+ }
+
+ date = createUTCDate(yearToUse, 0, config._dayOfYear);
+ config._a[MONTH] = date.getUTCMonth();
+ config._a[DATE] = date.getUTCDate();
+ }
+
+ // Default to current date.
+ // * if no year, month, day of month are given, default to today
+ // * if day of month is given, default month and year
+ // * if month is given, default only year
+ // * if year is given, don't default anything
+ for (i = 0; i < 3 && config._a[i] == null; ++i) {
+ config._a[i] = input[i] = currentDate[i];
+ }
+
+ // Zero out whatever was not defaulted, including time
+ for (; i < 7; i++) {
+ config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+ }
+
+ // Check for 24:00:00.000
+ if (config._a[HOUR] === 24 &&
+ config._a[MINUTE] === 0 &&
+ config._a[SECOND] === 0 &&
+ config._a[MILLISECOND] === 0) {
+ config._nextDay = true;
+ config._a[HOUR] = 0;
+ }
+
+ config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+ expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
+
+ // Apply timezone offset from input. The actual utcOffset can be changed
+ // with parseZone.
+ if (config._tzm != null) {
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+ }
+
+ if (config._nextDay) {
+ config._a[HOUR] = 24;
+ }
+
+ // check for mismatching day of week
+ if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
+ getParsingFlags(config).weekdayMismatch = true;
+ }
+}
+
+function dayOfYearFromWeekInfo(config) {
+ var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+ w = config._w;
+ if (w.GG != null || w.W != null || w.E != null) {
+ dow = 1;
+ doy = 4;
+
+ // TODO: We need to take the current isoWeekYear, but that depends on
+ // how we interpret now (local, utc, fixed offset). So create
+ // a now version of current config (take local/utc/offset flags, and
+ // create now).
+ weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+ week = defaults(w.W, 1);
+ weekday = defaults(w.E, 1);
+ if (weekday < 1 || weekday > 7) {
+ weekdayOverflow = true;
+ }
+ } else {
+ dow = config._locale._week.dow;
+ doy = config._locale._week.doy;
+
+ var curWeek = weekOfYear(createLocal(), dow, doy);
+
+ weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+ // Default to current week.
+ week = defaults(w.w, curWeek.week);
+
+ if (w.d != null) {
+ // weekday -- low day numbers are considered next week
+ weekday = w.d;
+ if (weekday < 0 || weekday > 6) {
+ weekdayOverflow = true;
+ }
+ } else if (w.e != null) {
+ // local weekday -- counting starts from begining of week
+ weekday = w.e + dow;
+ if (w.e < 0 || w.e > 6) {
+ weekdayOverflow = true;
+ }
+ } else {
+ // default to begining of week
+ weekday = dow;
+ }
+ }
+ if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+ getParsingFlags(config)._overflowWeeks = true;
+ } else if (weekdayOverflow != null) {
+ getParsingFlags(config)._overflowWeekday = true;
+ } else {
+ temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+ config._a[YEAR] = temp.year;
+ config._dayOfYear = temp.dayOfYear;
+ }
+}
+
+// iso 8601 regex
+// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+var isoDates = [
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+ ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+ ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+ ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+ ['YYYY-DDD', /\d{4}-\d{3}/],
+ ['YYYY-MM', /\d{4}-\d\d/, false],
+ ['YYYYYYMMDD', /[+-]\d{10}/],
+ ['YYYYMMDD', /\d{8}/],
+ // YYYYMM is NOT allowed by the standard
+ ['GGGG[W]WWE', /\d{4}W\d{3}/],
+ ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+ ['YYYYDDD', /\d{7}/]
+];
+
+// iso time formats and regexes
+var isoTimes = [
+ ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+ ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+ ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+ ['HH:mm', /\d\d:\d\d/],
+ ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+ ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+ ['HHmmss', /\d\d\d\d\d\d/],
+ ['HHmm', /\d\d\d\d/],
+ ['HH', /\d\d/]
+];
+
+var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+// date from iso format
+function configFromISO(config) {
+ var i, l,
+ string = config._i,
+ match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+ allowTime, dateFormat, timeFormat, tzFormat;
+
+ if (match) {
+ getParsingFlags(config).iso = true;
+
+ for (i = 0, l = isoDates.length; i < l; i++) {
+ if (isoDates[i][1].exec(match[1])) {
+ dateFormat = isoDates[i][0];
+ allowTime = isoDates[i][2] !== false;
+ break;
+ }
+ }
+ if (dateFormat == null) {
+ config._isValid = false;
+ return;
+ }
+ if (match[3]) {
+ for (i = 0, l = isoTimes.length; i < l; i++) {
+ if (isoTimes[i][1].exec(match[3])) {
+ // match[2] should be 'T' or space
+ timeFormat = (match[2] || ' ') + isoTimes[i][0];
+ break;
+ }
+ }
+ if (timeFormat == null) {
+ config._isValid = false;
+ return;
+ }
+ }
+ if (!allowTime && timeFormat != null) {
+ config._isValid = false;
+ return;
+ }
+ if (match[4]) {
+ if (tzRegex.exec(match[4])) {
+ tzFormat = 'Z';
+ } else {
+ config._isValid = false;
+ return;
+ }
+ }
+ config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+ configFromStringAndFormat(config);
+ } else {
+ config._isValid = false;
+ }
+}
+
+// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
+var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
+
+function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
+ var result = [
+ untruncateYear(yearStr),
+ defaultLocaleMonthsShort.indexOf(monthStr),
+ parseInt(dayStr, 10),
+ parseInt(hourStr, 10),
+ parseInt(minuteStr, 10)
+ ];
+
+ if (secondStr) {
+ result.push(parseInt(secondStr, 10));
+ }
+
+ return result;
+}
+
+function untruncateYear(yearStr) {
+ var year = parseInt(yearStr, 10);
+ if (year <= 49) {
+ return 2000 + year;
+ } else if (year <= 999) {
+ return 1900 + year;
+ }
+ return year;
+}
+
+function preprocessRFC2822(s) {
+ // Remove comments and folding whitespace and replace multiple-spaces with a single space
+ return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
+}
+
+function checkWeekday(weekdayStr, parsedInput, config) {
+ if (weekdayStr) {
+ // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
+ var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
+ weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
+ if (weekdayProvided !== weekdayActual) {
+ getParsingFlags(config).weekdayMismatch = true;
+ config._isValid = false;
+ return false;
+ }
+ }
+ return true;
+}
+
+var obsOffsets = {
+ UT: 0,
+ GMT: 0,
+ EDT: -4 * 60,
+ EST: -5 * 60,
+ CDT: -5 * 60,
+ CST: -6 * 60,
+ MDT: -6 * 60,
+ MST: -7 * 60,
+ PDT: -7 * 60,
+ PST: -8 * 60
+};
+
+function calculateOffset(obsOffset, militaryOffset, numOffset) {
+ if (obsOffset) {
+ return obsOffsets[obsOffset];
+ } else if (militaryOffset) {
+ // the only allowed military tz is Z
+ return 0;
+ } else {
+ var hm = parseInt(numOffset, 10);
+ var m = hm % 100, h = (hm - m) / 100;
+ return h * 60 + m;
+ }
+}
+
+// date and time from ref 2822 format
+function configFromRFC2822(config) {
+ var match = rfc2822.exec(preprocessRFC2822(config._i));
+ if (match) {
+ var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
+ if (!checkWeekday(match[1], parsedArray, config)) {
+ return;
+ }
+
+ config._a = parsedArray;
+ config._tzm = calculateOffset(match[8], match[9], match[10]);
+
+ config._d = createUTCDate.apply(null, config._a);
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+
+ getParsingFlags(config).rfc2822 = true;
+ } else {
+ config._isValid = false;
+ }
+}
+
+// date from iso format or fallback
+function configFromString(config) {
+ var matched = aspNetJsonRegex.exec(config._i);
+
+ if (matched !== null) {
+ config._d = new Date(+matched[1]);
+ return;
+ }
+
+ configFromISO(config);
+ if (config._isValid === false) {
+ delete config._isValid;
+ } else {
+ return;
+ }
+
+ configFromRFC2822(config);
+ if (config._isValid === false) {
+ delete config._isValid;
+ } else {
+ return;
+ }
+
+ // Final attempt, use Input Fallback
+ hooks.createFromInputFallback(config);
+}
+
+hooks.createFromInputFallback = deprecate(
+ 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
+ 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
+ 'discouraged and will be removed in an upcoming major release. Please refer to ' +
+ 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+ function (config) {
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+ }
+);
+
+// constant that refers to the ISO standard
+hooks.ISO_8601 = function () {};
+
+// constant that refers to the RFC 2822 form
+hooks.RFC_2822 = function () {};
+
+// date from string and format string
+function configFromStringAndFormat(config) {
+ // TODO: Move this to another part of the creation flow to prevent circular deps
+ if (config._f === hooks.ISO_8601) {
+ configFromISO(config);
+ return;
+ }
+ if (config._f === hooks.RFC_2822) {
+ configFromRFC2822(config);
+ return;
+ }
+ config._a = [];
+ getParsingFlags(config).empty = true;
+
+ // This array is used to make a Date, either with `new Date` or `Date.UTC`
+ var string = '' + config._i,
+ i, parsedInput, tokens, token, skipped,
+ stringLength = string.length,
+ totalParsedInputLength = 0;
+
+ tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+ for (i = 0; i < tokens.length; i++) {
+ token = tokens[i];
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+ // console.log('token', token, 'parsedInput', parsedInput,
+ // 'regex', getParseRegexForToken(token, config));
+ if (parsedInput) {
+ skipped = string.substr(0, string.indexOf(parsedInput));
+ if (skipped.length > 0) {
+ getParsingFlags(config).unusedInput.push(skipped);
+ }
+ string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+ totalParsedInputLength += parsedInput.length;
+ }
+ // don't parse if it's not a known token
+ if (formatTokenFunctions[token]) {
+ if (parsedInput) {
+ getParsingFlags(config).empty = false;
+ }
+ else {
+ getParsingFlags(config).unusedTokens.push(token);
+ }
+ addTimeToArrayFromToken(token, parsedInput, config);
+ }
+ else if (config._strict && !parsedInput) {
+ getParsingFlags(config).unusedTokens.push(token);
+ }
+ }
+
+ // add remaining unparsed input length to the string
+ getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+ if (string.length > 0) {
+ getParsingFlags(config).unusedInput.push(string);
+ }
+
+ // clear _12h flag if hour is <= 12
+ if (config._a[HOUR] <= 12 &&
+ getParsingFlags(config).bigHour === true &&
+ config._a[HOUR] > 0) {
+ getParsingFlags(config).bigHour = undefined;
+ }
+
+ getParsingFlags(config).parsedDateParts = config._a.slice(0);
+ getParsingFlags(config).meridiem = config._meridiem;
+ // handle meridiem
+ config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+ configFromArray(config);
+ checkOverflow(config);
+}
+
+
+function meridiemFixWrap (locale, hour, meridiem) {
+ var isPm;
+
+ if (meridiem == null) {
+ // nothing to do
+ return hour;
+ }
+ if (locale.meridiemHour != null) {
+ return locale.meridiemHour(hour, meridiem);
+ } else if (locale.isPM != null) {
+ // Fallback
+ isPm = locale.isPM(meridiem);
+ if (isPm && hour < 12) {
+ hour += 12;
+ }
+ if (!isPm && hour === 12) {
+ hour = 0;
+ }
+ return hour;
+ } else {
+ // this is not supposed to happen
+ return hour;
+ }
+}
+
+// date from string and array of format strings
+function configFromStringAndArray(config) {
+ var tempConfig,
+ bestMoment,
+
+ scoreToBeat,
+ i,
+ currentScore;
+
+ if (config._f.length === 0) {
+ getParsingFlags(config).invalidFormat = true;
+ config._d = new Date(NaN);
+ return;
+ }
+
+ for (i = 0; i < config._f.length; i++) {
+ currentScore = 0;
+ tempConfig = copyConfig({}, config);
+ if (config._useUTC != null) {
+ tempConfig._useUTC = config._useUTC;
+ }
+ tempConfig._f = config._f[i];
+ configFromStringAndFormat(tempConfig);
+
+ if (!isValid(tempConfig)) {
+ continue;
+ }
+
+ // if there is any input that was not parsed add a penalty for that format
+ currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+ //or tokens
+ currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+ getParsingFlags(tempConfig).score = currentScore;
+
+ if (scoreToBeat == null || currentScore < scoreToBeat) {
+ scoreToBeat = currentScore;
+ bestMoment = tempConfig;
+ }
+ }
+
+ extend(config, bestMoment || tempConfig);
+}
+
+function configFromObject(config) {
+ if (config._d) {
+ return;
+ }
+
+ var i = normalizeObjectUnits(config._i);
+ config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+ return obj && parseInt(obj, 10);
+ });
+
+ configFromArray(config);
+}
+
+function createFromConfig (config) {
+ var res = new Moment(checkOverflow(prepareConfig(config)));
+ if (res._nextDay) {
+ // Adding is smart enough around DST
+ res.add(1, 'd');
+ res._nextDay = undefined;
+ }
+
+ return res;
+}
+
+function prepareConfig (config) {
+ var input = config._i,
+ format = config._f;
+
+ config._locale = config._locale || getLocale(config._l);
+
+ if (input === null || (format === undefined && input === '')) {
+ return createInvalid({nullInput: true});
+ }
+
+ if (typeof input === 'string') {
+ config._i = input = config._locale.preparse(input);
+ }
+
+ if (isMoment(input)) {
+ return new Moment(checkOverflow(input));
+ } else if (isDate(input)) {
+ config._d = input;
+ } else if (isArray(format)) {
+ configFromStringAndArray(config);
+ } else if (format) {
+ configFromStringAndFormat(config);
+ } else {
+ configFromInput(config);
+ }
+
+ if (!isValid(config)) {
+ config._d = null;
+ }
+
+ return config;
+}
+
+function configFromInput(config) {
+ var input = config._i;
+ if (isUndefined(input)) {
+ config._d = new Date(hooks.now());
+ } else if (isDate(input)) {
+ config._d = new Date(input.valueOf());
+ } else if (typeof input === 'string') {
+ configFromString(config);
+ } else if (isArray(input)) {
+ config._a = map(input.slice(0), function (obj) {
+ return parseInt(obj, 10);
+ });
+ configFromArray(config);
+ } else if (isObject(input)) {
+ configFromObject(config);
+ } else if (isNumber(input)) {
+ // from milliseconds
+ config._d = new Date(input);
+ } else {
+ hooks.createFromInputFallback(config);
+ }
+}
+
+function createLocalOrUTC (input, format, locale, strict, isUTC) {
+ var c = {};
+
+ if (locale === true || locale === false) {
+ strict = locale;
+ locale = undefined;
+ }
+
+ if ((isObject(input) && isObjectEmpty(input)) ||
+ (isArray(input) && input.length === 0)) {
+ input = undefined;
+ }
+ // object construction must be done this way.
+ // https://github.com/moment/moment/issues/1423
+ c._isAMomentObject = true;
+ c._useUTC = c._isUTC = isUTC;
+ c._l = locale;
+ c._i = input;
+ c._f = format;
+ c._strict = strict;
+
+ return createFromConfig(c);
+}
+
+function createLocal (input, format, locale, strict) {
+ return createLocalOrUTC(input, format, locale, strict, false);
+}
+
+var prototypeMin = deprecate(
+ 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+ function () {
+ var other = createLocal.apply(null, arguments);
+ if (this.isValid() && other.isValid()) {
+ return other < this ? this : other;
+ } else {
+ return createInvalid();
+ }
+ }
+);
+
+var prototypeMax = deprecate(
+ 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+ function () {
+ var other = createLocal.apply(null, arguments);
+ if (this.isValid() && other.isValid()) {
+ return other > this ? this : other;
+ } else {
+ return createInvalid();
+ }
+ }
+);
+
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function pickBy(fn, moments) {
+ var res, i;
+ if (moments.length === 1 && isArray(moments[0])) {
+ moments = moments[0];
+ }
+ if (!moments.length) {
+ return createLocal();
+ }
+ res = moments[0];
+ for (i = 1; i < moments.length; ++i) {
+ if (!moments[i].isValid() || moments[i][fn](res)) {
+ res = moments[i];
+ }
+ }
+ return res;
+}
+
+// TODO: Use [].sort instead?
+function min () {
+ var args = [].slice.call(arguments, 0);
+
+ return pickBy('isBefore', args);
+}
+
+function max () {
+ var args = [].slice.call(arguments, 0);
+
+ return pickBy('isAfter', args);
+}
+
+var now = function () {
+ return Date.now ? Date.now() : +(new Date());
+};
+
+var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
+
+function isDurationValid(m) {
+ for (var key in m) {
+ if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
+ return false;
+ }
+ }
+
+ var unitHasDecimal = false;
+ for (var i = 0; i < ordering.length; ++i) {
+ if (m[ordering[i]]) {
+ if (unitHasDecimal) {
+ return false; // only allow non-integers for smallest unit
+ }
+ if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
+ unitHasDecimal = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+function isValid$1() {
+ return this._isValid;
+}
+
+function createInvalid$1() {
+ return createDuration(NaN);
+}
+
+function Duration (duration) {
+ var normalizedInput = normalizeObjectUnits(duration),
+ years = normalizedInput.year || 0,
+ quarters = normalizedInput.quarter || 0,
+ months = normalizedInput.month || 0,
+ weeks = normalizedInput.week || 0,
+ days = normalizedInput.day || 0,
+ hours = normalizedInput.hour || 0,
+ minutes = normalizedInput.minute || 0,
+ seconds = normalizedInput.second || 0,
+ milliseconds = normalizedInput.millisecond || 0;
+
+ this._isValid = isDurationValid(normalizedInput);
+
+ // representation for dateAddRemove
+ this._milliseconds = +milliseconds +
+ seconds * 1e3 + // 1000
+ minutes * 6e4 + // 1000 * 60
+ hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+ // Because of dateAddRemove treats 24 hours as different from a
+ // day when working around DST, we need to store them separately
+ this._days = +days +
+ weeks * 7;
+ // It is impossible to translate months into days without knowing
+ // which months you are are talking about, so we have to store
+ // it separately.
+ this._months = +months +
+ quarters * 3 +
+ years * 12;
+
+ this._data = {};
+
+ this._locale = getLocale();
+
+ this._bubble();
+}
+
+function isDuration (obj) {
+ return obj instanceof Duration;
+}
+
+function absRound (number) {
+ if (number < 0) {
+ return Math.round(-1 * number) * -1;
+ } else {
+ return Math.round(number);
+ }
+}
+
+// FORMATTING
+
+function offset (token, separator) {
+ addFormatToken(token, 0, 0, function () {
+ var offset = this.utcOffset();
+ var sign = '+';
+ if (offset < 0) {
+ offset = -offset;
+ sign = '-';
+ }
+ return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+ });
+}
+
+offset('Z', ':');
+offset('ZZ', '');
+
+// PARSING
+
+addRegexToken('Z', matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
+addParseToken(['Z', 'ZZ'], function (input, array, config) {
+ config._useUTC = true;
+ config._tzm = offsetFromString(matchShortOffset, input);
+});
+
+// HELPERS
+
+// timezone chunker
+// '+10:00' > ['10', '00']
+// '-1530' > ['-15', '30']
+var chunkOffset = /([\+\-]|\d\d)/gi;
+
+function offsetFromString(matcher, string) {
+ var matches = (string || '').match(matcher);
+
+ if (matches === null) {
+ return null;
+ }
+
+ var chunk = matches[matches.length - 1] || [];
+ var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+ var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+ return minutes === 0 ?
+ 0 :
+ parts[0] === '+' ? minutes : -minutes;
+}
+
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function cloneWithOffset(input, model) {
+ var res, diff;
+ if (model._isUTC) {
+ res = model.clone();
+ diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+ // Use low-level api, because this fn is low-level api.
+ res._d.setTime(res._d.valueOf() + diff);
+ hooks.updateOffset(res, false);
+ return res;
+ } else {
+ return createLocal(input).local();
+ }
+}
+
+function getDateOffset (m) {
+ // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+ // https://github.com/moment/moment/pull/1871
+ return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+}
+
+// HOOKS
+
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+hooks.updateOffset = function () {};
+
+// MOMENTS
+
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function getSetOffset (input, keepLocalTime, keepMinutes) {
+ var offset = this._offset || 0,
+ localAdjust;
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ if (input != null) {
+ if (typeof input === 'string') {
+ input = offsetFromString(matchShortOffset, input);
+ if (input === null) {
+ return this;
+ }
+ } else if (Math.abs(input) < 16 && !keepMinutes) {
+ input = input * 60;
+ }
+ if (!this._isUTC && keepLocalTime) {
+ localAdjust = getDateOffset(this);
+ }
+ this._offset = input;
+ this._isUTC = true;
+ if (localAdjust != null) {
+ this.add(localAdjust, 'm');
+ }
+ if (offset !== input) {
+ if (!keepLocalTime || this._changeInProgress) {
+ addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+ } else if (!this._changeInProgress) {
+ this._changeInProgress = true;
+ hooks.updateOffset(this, true);
+ this._changeInProgress = null;
+ }
+ }
+ return this;
+ } else {
+ return this._isUTC ? offset : getDateOffset(this);
+ }
+}
+
+function getSetZone (input, keepLocalTime) {
+ if (input != null) {
+ if (typeof input !== 'string') {
+ input = -input;
+ }
+
+ this.utcOffset(input, keepLocalTime);
+
+ return this;
+ } else {
+ return -this.utcOffset();
+ }
+}
+
+function setOffsetToUTC (keepLocalTime) {
+ return this.utcOffset(0, keepLocalTime);
+}
+
+function setOffsetToLocal (keepLocalTime) {
+ if (this._isUTC) {
+ this.utcOffset(0, keepLocalTime);
+ this._isUTC = false;
+
+ if (keepLocalTime) {
+ this.subtract(getDateOffset(this), 'm');
+ }
+ }
+ return this;
+}
+
+function setOffsetToParsedOffset () {
+ if (this._tzm != null) {
+ this.utcOffset(this._tzm, false, true);
+ } else if (typeof this._i === 'string') {
+ var tZone = offsetFromString(matchOffset, this._i);
+ if (tZone != null) {
+ this.utcOffset(tZone);
+ }
+ else {
+ this.utcOffset(0, true);
+ }
+ }
+ return this;
+}
+
+function hasAlignedHourOffset (input) {
+ if (!this.isValid()) {
+ return false;
+ }
+ input = input ? createLocal(input).utcOffset() : 0;
+
+ return (this.utcOffset() - input) % 60 === 0;
+}
+
+function isDaylightSavingTime () {
+ return (
+ this.utcOffset() > this.clone().month(0).utcOffset() ||
+ this.utcOffset() > this.clone().month(5).utcOffset()
+ );
+}
+
+function isDaylightSavingTimeShifted () {
+ if (!isUndefined(this._isDSTShifted)) {
+ return this._isDSTShifted;
+ }
+
+ var c = {};
+
+ copyConfig(c, this);
+ c = prepareConfig(c);
+
+ if (c._a) {
+ var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+ this._isDSTShifted = this.isValid() &&
+ compareArrays(c._a, other.toArray()) > 0;
+ } else {
+ this._isDSTShifted = false;
+ }
+
+ return this._isDSTShifted;
+}
+
+function isLocal () {
+ return this.isValid() ? !this._isUTC : false;
+}
+
+function isUtcOffset () {
+ return this.isValid() ? this._isUTC : false;
+}
+
+function isUtc () {
+ return this.isValid() ? this._isUTC && this._offset === 0 : false;
+}
+
+// ASP.NET json date format regex
+var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+// and further modified to allow for strings containing both week and day
+var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
+
+function createDuration (input, key) {
+ var duration = input,
+ // matching against regexp is expensive, do it on demand
+ match = null,
+ sign,
+ ret,
+ diffRes;
+
+ if (isDuration(input)) {
+ duration = {
+ ms : input._milliseconds,
+ d : input._days,
+ M : input._months
+ };
+ } else if (isNumber(input)) {
+ duration = {};
+ if (key) {
+ duration[key] = input;
+ } else {
+ duration.milliseconds = input;
+ }
+ } else if (!!(match = aspNetRegex.exec(input))) {
+ sign = (match[1] === '-') ? -1 : 1;
+ duration = {
+ y : 0,
+ d : toInt(match[DATE]) * sign,
+ h : toInt(match[HOUR]) * sign,
+ m : toInt(match[MINUTE]) * sign,
+ s : toInt(match[SECOND]) * sign,
+ ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+ };
+ } else if (!!(match = isoRegex.exec(input))) {
+ sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
+ duration = {
+ y : parseIso(match[2], sign),
+ M : parseIso(match[3], sign),
+ w : parseIso(match[4], sign),
+ d : parseIso(match[5], sign),
+ h : parseIso(match[6], sign),
+ m : parseIso(match[7], sign),
+ s : parseIso(match[8], sign)
+ };
+ } else if (duration == null) {// checks for null or undefined
+ duration = {};
+ } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+ diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+ duration = {};
+ duration.ms = diffRes.milliseconds;
+ duration.M = diffRes.months;
+ }
+
+ ret = new Duration(duration);
+
+ if (isDuration(input) && hasOwnProp(input, '_locale')) {
+ ret._locale = input._locale;
+ }
+
+ return ret;
+}
+
+createDuration.fn = Duration.prototype;
+createDuration.invalid = createInvalid$1;
+
+function parseIso (inp, sign) {
+ // We'd normally use ~~inp for this, but unfortunately it also
+ // converts floats to ints.
+ // inp may be undefined, so careful calling replace on it.
+ var res = inp && parseFloat(inp.replace(',', '.'));
+ // apply sign while we're at it
+ return (isNaN(res) ? 0 : res) * sign;
+}
+
+function positiveMomentsDifference(base, other) {
+ var res = {milliseconds: 0, months: 0};
+
+ res.months = other.month() - base.month() +
+ (other.year() - base.year()) * 12;
+ if (base.clone().add(res.months, 'M').isAfter(other)) {
+ --res.months;
+ }
+
+ res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+ return res;
+}
+
+function momentsDifference(base, other) {
+ var res;
+ if (!(base.isValid() && other.isValid())) {
+ return {milliseconds: 0, months: 0};
+ }
+
+ other = cloneWithOffset(other, base);
+ if (base.isBefore(other)) {
+ res = positiveMomentsDifference(base, other);
+ } else {
+ res = positiveMomentsDifference(other, base);
+ res.milliseconds = -res.milliseconds;
+ res.months = -res.months;
+ }
+
+ return res;
+}
+
+// TODO: remove 'name' arg after deprecation is removed
+function createAdder(direction, name) {
+ return function (val, period) {
+ var dur, tmp;
+ //invert the arguments, but complain about it
+ if (period !== null && !isNaN(+period)) {
+ deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+ 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+ tmp = val; val = period; period = tmp;
+ }
+
+ val = typeof val === 'string' ? +val : val;
+ dur = createDuration(val, period);
+ addSubtract(this, dur, direction);
+ return this;
+ };
+}
+
+function addSubtract (mom, duration, isAdding, updateOffset) {
+ var milliseconds = duration._milliseconds,
+ days = absRound(duration._days),
+ months = absRound(duration._months);
+
+ if (!mom.isValid()) {
+ // No op
+ return;
+ }
+
+ updateOffset = updateOffset == null ? true : updateOffset;
+
+ if (months) {
+ setMonth(mom, get(mom, 'Month') + months * isAdding);
+ }
+ if (days) {
+ set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
+ }
+ if (milliseconds) {
+ mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+ }
+ if (updateOffset) {
+ hooks.updateOffset(mom, days || months);
+ }
+}
+
+var add = createAdder(1, 'add');
+var subtract = createAdder(-1, 'subtract');
+
+function getCalendarFormat(myMoment, now) {
+ var diff = myMoment.diff(now, 'days', true);
+ return diff < -6 ? 'sameElse' :
+ diff < -1 ? 'lastWeek' :
+ diff < 0 ? 'lastDay' :
+ diff < 1 ? 'sameDay' :
+ diff < 2 ? 'nextDay' :
+ diff < 7 ? 'nextWeek' : 'sameElse';
+}
+
+function calendar$1 (time, formats) {
+ // We want to compare the start of today, vs this.
+ // Getting start-of-today depends on whether we're local/utc/offset or not.
+ var now = time || createLocal(),
+ sod = cloneWithOffset(now, this).startOf('day'),
+ format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+ var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+ return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+}
+
+function clone () {
+ return new Moment(this);
+}
+
+function isAfter (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input);
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() > localInput.valueOf();
+ } else {
+ return localInput.valueOf() < this.clone().startOf(units).valueOf();
+ }
+}
+
+function isBefore (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input);
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() < localInput.valueOf();
+ } else {
+ return this.clone().endOf(units).valueOf() < localInput.valueOf();
+ }
+}
+
+function isBetween (from, to, units, inclusivity) {
+ inclusivity = inclusivity || '()';
+ return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
+ (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
+}
+
+function isSame (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input),
+ inputMs;
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(units || 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() === localInput.valueOf();
+ } else {
+ inputMs = localInput.valueOf();
+ return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+ }
+}
+
+function isSameOrAfter (input, units) {
+ return this.isSame(input, units) || this.isAfter(input,units);
+}
+
+function isSameOrBefore (input, units) {
+ return this.isSame(input, units) || this.isBefore(input,units);
+}
+
+function diff (input, units, asFloat) {
+ var that,
+ zoneDelta,
+ output;
+
+ if (!this.isValid()) {
+ return NaN;
+ }
+
+ that = cloneWithOffset(input, this);
+
+ if (!that.isValid()) {
+ return NaN;
+ }
+
+ zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+ units = normalizeUnits(units);
+
+ switch (units) {
+ case 'year': output = monthDiff(this, that) / 12; break;
+ case 'month': output = monthDiff(this, that); break;
+ case 'quarter': output = monthDiff(this, that) / 3; break;
+ case 'second': output = (this - that) / 1e3; break; // 1000
+ case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
+ case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
+ case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
+ case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
+ default: output = this - that;
+ }
+
+ return asFloat ? output : absFloor(output);
+}
+
+function monthDiff (a, b) {
+ // difference in months
+ var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+ // b is in (anchor - 1 month, anchor + 1 month)
+ anchor = a.clone().add(wholeMonthDiff, 'months'),
+ anchor2, adjust;
+
+ if (b - anchor < 0) {
+ anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+ // linear across the month
+ adjust = (b - anchor) / (anchor - anchor2);
+ } else {
+ anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+ // linear across the month
+ adjust = (b - anchor) / (anchor2 - anchor);
+ }
+
+ //check for negative zero, return zero if negative zero
+ return -(wholeMonthDiff + adjust) || 0;
+}
+
+hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+function toString () {
+ return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+}
+
+function toISOString(keepOffset) {
+ if (!this.isValid()) {
+ return null;
+ }
+ var utc = keepOffset !== true;
+ var m = utc ? this.clone().utc() : this;
+ if (m.year() < 0 || m.year() > 9999) {
+ return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
+ }
+ if (isFunction(Date.prototype.toISOString)) {
+ // native implementation is ~50x faster, use it when we can
+ if (utc) {
+ return this.toDate().toISOString();
+ } else {
+ return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
+ }
+ }
+ return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
+}
+
+/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function inspect () {
+ if (!this.isValid()) {
+ return 'moment.invalid(/* ' + this._i + ' */)';
+ }
+ var func = 'moment';
+ var zone = '';
+ if (!this.isLocal()) {
+ func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+ zone = 'Z';
+ }
+ var prefix = '[' + func + '("]';
+ var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+ var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+ var suffix = zone + '[")]';
+
+ return this.format(prefix + year + datetime + suffix);
+}
+
+function format (inputString) {
+ if (!inputString) {
+ inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+ }
+ var output = formatMoment(this, inputString);
+ return this.localeData().postformat(output);
+}
+
+function from (time, withoutSuffix) {
+ if (this.isValid() &&
+ ((isMoment(time) && time.isValid()) ||
+ createLocal(time).isValid())) {
+ return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+ } else {
+ return this.localeData().invalidDate();
+ }
+}
+
+function fromNow (withoutSuffix) {
+ return this.from(createLocal(), withoutSuffix);
+}
+
+function to (time, withoutSuffix) {
+ if (this.isValid() &&
+ ((isMoment(time) && time.isValid()) ||
+ createLocal(time).isValid())) {
+ return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+ } else {
+ return this.localeData().invalidDate();
+ }
+}
+
+function toNow (withoutSuffix) {
+ return this.to(createLocal(), withoutSuffix);
+}
+
+// If passed a locale key, it will set the locale for this
+// instance. Otherwise, it will return the locale configuration
+// variables for this instance.
+function locale (key) {
+ var newLocaleData;
+
+ if (key === undefined) {
+ return this._locale._abbr;
+ } else {
+ newLocaleData = getLocale(key);
+ if (newLocaleData != null) {
+ this._locale = newLocaleData;
+ }
+ return this;
+ }
+}
+
+var lang = deprecate(
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+ function (key) {
+ if (key === undefined) {
+ return this.localeData();
+ } else {
+ return this.locale(key);
+ }
+ }
+);
+
+function localeData () {
+ return this._locale;
+}
+
+function startOf (units) {
+ units = normalizeUnits(units);
+ // the following switch intentionally omits break keywords
+ // to utilize falling through the cases.
+ switch (units) {
+ case 'year':
+ this.month(0);
+ /* falls through */
+ case 'quarter':
+ case 'month':
+ this.date(1);
+ /* falls through */
+ case 'week':
+ case 'isoWeek':
+ case 'day':
+ case 'date':
+ this.hours(0);
+ /* falls through */
+ case 'hour':
+ this.minutes(0);
+ /* falls through */
+ case 'minute':
+ this.seconds(0);
+ /* falls through */
+ case 'second':
+ this.milliseconds(0);
+ }
+
+ // weeks are a special case
+ if (units === 'week') {
+ this.weekday(0);
+ }
+ if (units === 'isoWeek') {
+ this.isoWeekday(1);
+ }
+
+ // quarters are also special
+ if (units === 'quarter') {
+ this.month(Math.floor(this.month() / 3) * 3);
+ }
+
+ return this;
+}
+
+function endOf (units) {
+ units = normalizeUnits(units);
+ if (units === undefined || units === 'millisecond') {
+ return this;
+ }
+
+ // 'date' is an alias for 'day', so it should be considered as such.
+ if (units === 'date') {
+ units = 'day';
+ }
+
+ return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
+}
+
+function valueOf () {
+ return this._d.valueOf() - ((this._offset || 0) * 60000);
+}
+
+function unix () {
+ return Math.floor(this.valueOf() / 1000);
+}
+
+function toDate () {
+ return new Date(this.valueOf());
+}
+
+function toArray () {
+ var m = this;
+ return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+}
+
+function toObject () {
+ var m = this;
+ return {
+ years: m.year(),
+ months: m.month(),
+ date: m.date(),
+ hours: m.hours(),
+ minutes: m.minutes(),
+ seconds: m.seconds(),
+ milliseconds: m.milliseconds()
+ };
+}
+
+function toJSON () {
+ // new Date(NaN).toJSON() === null
+ return this.isValid() ? this.toISOString() : null;
+}
+
+function isValid$2 () {
+ return isValid(this);
+}
+
+function parsingFlags () {
+ return extend({}, getParsingFlags(this));
+}
+
+function invalidAt () {
+ return getParsingFlags(this).overflow;
+}
+
+function creationData() {
+ return {
+ input: this._i,
+ format: this._f,
+ locale: this._locale,
+ isUTC: this._isUTC,
+ strict: this._strict
+ };
+}
+
+// FORMATTING
+
+addFormatToken(0, ['gg', 2], 0, function () {
+ return this.weekYear() % 100;
+});
+
+addFormatToken(0, ['GG', 2], 0, function () {
+ return this.isoWeekYear() % 100;
+});
+
+function addWeekYearFormatToken (token, getter) {
+ addFormatToken(0, [token, token.length], 0, getter);
+}
+
+addWeekYearFormatToken('gggg', 'weekYear');
+addWeekYearFormatToken('ggggg', 'weekYear');
+addWeekYearFormatToken('GGGG', 'isoWeekYear');
+addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+// ALIASES
+
+addUnitAlias('weekYear', 'gg');
+addUnitAlias('isoWeekYear', 'GG');
+
+// PRIORITY
+
+addUnitPriority('weekYear', 1);
+addUnitPriority('isoWeekYear', 1);
+
+
+// PARSING
+
+addRegexToken('G', matchSigned);
+addRegexToken('g', matchSigned);
+addRegexToken('GG', match1to2, match2);
+addRegexToken('gg', match1to2, match2);
+addRegexToken('GGGG', match1to4, match4);
+addRegexToken('gggg', match1to4, match4);
+addRegexToken('GGGGG', match1to6, match6);
+addRegexToken('ggggg', match1to6, match6);
+
+addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+ week[token.substr(0, 2)] = toInt(input);
+});
+
+addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+ week[token] = hooks.parseTwoDigitYear(input);
+});
+
+// MOMENTS
+
+function getSetWeekYear (input) {
+ return getSetWeekYearHelper.call(this,
+ input,
+ this.week(),
+ this.weekday(),
+ this.localeData()._week.dow,
+ this.localeData()._week.doy);
+}
+
+function getSetISOWeekYear (input) {
+ return getSetWeekYearHelper.call(this,
+ input, this.isoWeek(), this.isoWeekday(), 1, 4);
+}
+
+function getISOWeeksInYear () {
+ return weeksInYear(this.year(), 1, 4);
+}
+
+function getWeeksInYear () {
+ var weekInfo = this.localeData()._week;
+ return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+}
+
+function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+ var weeksTarget;
+ if (input == null) {
+ return weekOfYear(this, dow, doy).year;
+ } else {
+ weeksTarget = weeksInYear(input, dow, doy);
+ if (week > weeksTarget) {
+ week = weeksTarget;
+ }
+ return setWeekAll.call(this, input, week, weekday, dow, doy);
+ }
+}
+
+function setWeekAll(weekYear, week, weekday, dow, doy) {
+ var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+ date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+ this.year(date.getUTCFullYear());
+ this.month(date.getUTCMonth());
+ this.date(date.getUTCDate());
+ return this;
+}
+
+// FORMATTING
+
+addFormatToken('Q', 0, 'Qo', 'quarter');
+
+// ALIASES
+
+addUnitAlias('quarter', 'Q');
+
+// PRIORITY
+
+addUnitPriority('quarter', 7);
+
+// PARSING
+
+addRegexToken('Q', match1);
+addParseToken('Q', function (input, array) {
+ array[MONTH] = (toInt(input) - 1) * 3;
+});
+
+// MOMENTS
+
+function getSetQuarter (input) {
+ return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+}
+
+// FORMATTING
+
+addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+// ALIASES
+
+addUnitAlias('date', 'D');
+
+// PRIOROITY
+addUnitPriority('date', 9);
+
+// PARSING
+
+addRegexToken('D', match1to2);
+addRegexToken('DD', match1to2, match2);
+addRegexToken('Do', function (isStrict, locale) {
+ // TODO: Remove "ordinalParse" fallback in next major release.
+ return isStrict ?
+ (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
+ locale._dayOfMonthOrdinalParseLenient;
+});
+
+addParseToken(['D', 'DD'], DATE);
+addParseToken('Do', function (input, array) {
+ array[DATE] = toInt(input.match(match1to2)[0]);
+});
+
+// MOMENTS
+
+var getSetDayOfMonth = makeGetSet('Date', true);
+
+// FORMATTING
+
+addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+// ALIASES
+
+addUnitAlias('dayOfYear', 'DDD');
+
+// PRIORITY
+addUnitPriority('dayOfYear', 4);
+
+// PARSING
+
+addRegexToken('DDD', match1to3);
+addRegexToken('DDDD', match3);
+addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+ config._dayOfYear = toInt(input);
+});
+
+// HELPERS
+
+// MOMENTS
+
+function getSetDayOfYear (input) {
+ var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+ return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+}
+
+// FORMATTING
+
+addFormatToken('m', ['mm', 2], 0, 'minute');
+
+// ALIASES
+
+addUnitAlias('minute', 'm');
+
+// PRIORITY
+
+addUnitPriority('minute', 14);
+
+// PARSING
+
+addRegexToken('m', match1to2);
+addRegexToken('mm', match1to2, match2);
+addParseToken(['m', 'mm'], MINUTE);
+
+// MOMENTS
+
+var getSetMinute = makeGetSet('Minutes', false);
+
+// FORMATTING
+
+addFormatToken('s', ['ss', 2], 0, 'second');
+
+// ALIASES
+
+addUnitAlias('second', 's');
+
+// PRIORITY
+
+addUnitPriority('second', 15);
+
+// PARSING
+
+addRegexToken('s', match1to2);
+addRegexToken('ss', match1to2, match2);
+addParseToken(['s', 'ss'], SECOND);
+
+// MOMENTS
+
+var getSetSecond = makeGetSet('Seconds', false);
+
+// FORMATTING
+
+addFormatToken('S', 0, 0, function () {
+ return ~~(this.millisecond() / 100);
+});
+
+addFormatToken(0, ['SS', 2], 0, function () {
+ return ~~(this.millisecond() / 10);
+});
+
+addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+addFormatToken(0, ['SSSS', 4], 0, function () {
+ return this.millisecond() * 10;
+});
+addFormatToken(0, ['SSSSS', 5], 0, function () {
+ return this.millisecond() * 100;
+});
+addFormatToken(0, ['SSSSSS', 6], 0, function () {
+ return this.millisecond() * 1000;
+});
+addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+ return this.millisecond() * 10000;
+});
+addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+ return this.millisecond() * 100000;
+});
+addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+ return this.millisecond() * 1000000;
+});
+
+
+// ALIASES
+
+addUnitAlias('millisecond', 'ms');
+
+// PRIORITY
+
+addUnitPriority('millisecond', 16);
+
+// PARSING
+
+addRegexToken('S', match1to3, match1);
+addRegexToken('SS', match1to3, match2);
+addRegexToken('SSS', match1to3, match3);
+
+var token;
+for (token = 'SSSS'; token.length <= 9; token += 'S') {
+ addRegexToken(token, matchUnsigned);
+}
+
+function parseMs(input, array) {
+ array[MILLISECOND] = toInt(('0.' + input) * 1000);
+}
+
+for (token = 'S'; token.length <= 9; token += 'S') {
+ addParseToken(token, parseMs);
+}
+// MOMENTS
+
+var getSetMillisecond = makeGetSet('Milliseconds', false);
+
+// FORMATTING
+
+addFormatToken('z', 0, 0, 'zoneAbbr');
+addFormatToken('zz', 0, 0, 'zoneName');
+
+// MOMENTS
+
+function getZoneAbbr () {
+ return this._isUTC ? 'UTC' : '';
+}
+
+function getZoneName () {
+ return this._isUTC ? 'Coordinated Universal Time' : '';
+}
+
+var proto = Moment.prototype;
+
+proto.add = add;
+proto.calendar = calendar$1;
+proto.clone = clone;
+proto.diff = diff;
+proto.endOf = endOf;
+proto.format = format;
+proto.from = from;
+proto.fromNow = fromNow;
+proto.to = to;
+proto.toNow = toNow;
+proto.get = stringGet;
+proto.invalidAt = invalidAt;
+proto.isAfter = isAfter;
+proto.isBefore = isBefore;
+proto.isBetween = isBetween;
+proto.isSame = isSame;
+proto.isSameOrAfter = isSameOrAfter;
+proto.isSameOrBefore = isSameOrBefore;
+proto.isValid = isValid$2;
+proto.lang = lang;
+proto.locale = locale;
+proto.localeData = localeData;
+proto.max = prototypeMax;
+proto.min = prototypeMin;
+proto.parsingFlags = parsingFlags;
+proto.set = stringSet;
+proto.startOf = startOf;
+proto.subtract = subtract;
+proto.toArray = toArray;
+proto.toObject = toObject;
+proto.toDate = toDate;
+proto.toISOString = toISOString;
+proto.inspect = inspect;
+proto.toJSON = toJSON;
+proto.toString = toString;
+proto.unix = unix;
+proto.valueOf = valueOf;
+proto.creationData = creationData;
+proto.year = getSetYear;
+proto.isLeapYear = getIsLeapYear;
+proto.weekYear = getSetWeekYear;
+proto.isoWeekYear = getSetISOWeekYear;
+proto.quarter = proto.quarters = getSetQuarter;
+proto.month = getSetMonth;
+proto.daysInMonth = getDaysInMonth;
+proto.week = proto.weeks = getSetWeek;
+proto.isoWeek = proto.isoWeeks = getSetISOWeek;
+proto.weeksInYear = getWeeksInYear;
+proto.isoWeeksInYear = getISOWeeksInYear;
+proto.date = getSetDayOfMonth;
+proto.day = proto.days = getSetDayOfWeek;
+proto.weekday = getSetLocaleDayOfWeek;
+proto.isoWeekday = getSetISODayOfWeek;
+proto.dayOfYear = getSetDayOfYear;
+proto.hour = proto.hours = getSetHour;
+proto.minute = proto.minutes = getSetMinute;
+proto.second = proto.seconds = getSetSecond;
+proto.millisecond = proto.milliseconds = getSetMillisecond;
+proto.utcOffset = getSetOffset;
+proto.utc = setOffsetToUTC;
+proto.local = setOffsetToLocal;
+proto.parseZone = setOffsetToParsedOffset;
+proto.hasAlignedHourOffset = hasAlignedHourOffset;
+proto.isDST = isDaylightSavingTime;
+proto.isLocal = isLocal;
+proto.isUtcOffset = isUtcOffset;
+proto.isUtc = isUtc;
+proto.isUTC = isUtc;
+proto.zoneAbbr = getZoneAbbr;
+proto.zoneName = getZoneName;
+proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+function createUnix (input) {
+ return createLocal(input * 1000);
+}
+
+function createInZone () {
+ return createLocal.apply(null, arguments).parseZone();
+}
+
+function preParsePostFormat (string) {
+ return string;
+}
+
+var proto$1 = Locale.prototype;
+
+proto$1.calendar = calendar;
+proto$1.longDateFormat = longDateFormat;
+proto$1.invalidDate = invalidDate;
+proto$1.ordinal = ordinal;
+proto$1.preparse = preParsePostFormat;
+proto$1.postformat = preParsePostFormat;
+proto$1.relativeTime = relativeTime;
+proto$1.pastFuture = pastFuture;
+proto$1.set = set;
+
+proto$1.months = localeMonths;
+proto$1.monthsShort = localeMonthsShort;
+proto$1.monthsParse = localeMonthsParse;
+proto$1.monthsRegex = monthsRegex;
+proto$1.monthsShortRegex = monthsShortRegex;
+proto$1.week = localeWeek;
+proto$1.firstDayOfYear = localeFirstDayOfYear;
+proto$1.firstDayOfWeek = localeFirstDayOfWeek;
+
+proto$1.weekdays = localeWeekdays;
+proto$1.weekdaysMin = localeWeekdaysMin;
+proto$1.weekdaysShort = localeWeekdaysShort;
+proto$1.weekdaysParse = localeWeekdaysParse;
+
+proto$1.weekdaysRegex = weekdaysRegex;
+proto$1.weekdaysShortRegex = weekdaysShortRegex;
+proto$1.weekdaysMinRegex = weekdaysMinRegex;
+
+proto$1.isPM = localeIsPM;
+proto$1.meridiem = localeMeridiem;
+
+function get$1 (format, index, field, setter) {
+ var locale = getLocale();
+ var utc = createUTC().set(setter, index);
+ return locale[field](utc, format);
+}
+
+function listMonthsImpl (format, index, field) {
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+
+ if (index != null) {
+ return get$1(format, index, field, 'month');
+ }
+
+ var i;
+ var out = [];
+ for (i = 0; i < 12; i++) {
+ out[i] = get$1(format, i, field, 'month');
+ }
+ return out;
+}
+
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function listWeekdaysImpl (localeSorted, format, index, field) {
+ if (typeof localeSorted === 'boolean') {
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+ } else {
+ format = localeSorted;
+ index = format;
+ localeSorted = false;
+
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+ }
+
+ var locale = getLocale(),
+ shift = localeSorted ? locale._week.dow : 0;
+
+ if (index != null) {
+ return get$1(format, (index + shift) % 7, field, 'day');
+ }
+
+ var i;
+ var out = [];
+ for (i = 0; i < 7; i++) {
+ out[i] = get$1(format, (i + shift) % 7, field, 'day');
+ }
+ return out;
+}
+
+function listMonths (format, index) {
+ return listMonthsImpl(format, index, 'months');
+}
+
+function listMonthsShort (format, index) {
+ return listMonthsImpl(format, index, 'monthsShort');
+}
+
+function listWeekdays (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+}
+
+function listWeekdaysShort (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+}
+
+function listWeekdaysMin (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+}
+
+getSetGlobalLocale('en', {
+ dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
+ ordinal : function (number) {
+ var b = number % 10,
+ output = (toInt(number % 100 / 10) === 1) ? 'th' :
+ (b === 1) ? 'st' :
+ (b === 2) ? 'nd' :
+ (b === 3) ? 'rd' : 'th';
+ return number + output;
+ }
+});
+
+// Side effect imports
+
+hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+var mathAbs = Math.abs;
+
+function abs () {
+ var data = this._data;
+
+ this._milliseconds = mathAbs(this._milliseconds);
+ this._days = mathAbs(this._days);
+ this._months = mathAbs(this._months);
+
+ data.milliseconds = mathAbs(data.milliseconds);
+ data.seconds = mathAbs(data.seconds);
+ data.minutes = mathAbs(data.minutes);
+ data.hours = mathAbs(data.hours);
+ data.months = mathAbs(data.months);
+ data.years = mathAbs(data.years);
+
+ return this;
+}
+
+function addSubtract$1 (duration, input, value, direction) {
+ var other = createDuration(input, value);
+
+ duration._milliseconds += direction * other._milliseconds;
+ duration._days += direction * other._days;
+ duration._months += direction * other._months;
+
+ return duration._bubble();
+}
+
+// supports only 2.0-style add(1, 's') or add(duration)
+function add$1 (input, value) {
+ return addSubtract$1(this, input, value, 1);
+}
+
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function subtract$1 (input, value) {
+ return addSubtract$1(this, input, value, -1);
+}
+
+function absCeil (number) {
+ if (number < 0) {
+ return Math.floor(number);
+ } else {
+ return Math.ceil(number);
+ }
+}
+
+function bubble () {
+ var milliseconds = this._milliseconds;
+ var days = this._days;
+ var months = this._months;
+ var data = this._data;
+ var seconds, minutes, hours, years, monthsFromDays;
+
+ // if we have a mix of positive and negative values, bubble down first
+ // check: https://github.com/moment/moment/issues/2166
+ if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+ (milliseconds <= 0 && days <= 0 && months <= 0))) {
+ milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+ days = 0;
+ months = 0;
+ }
+
+ // The following code bubbles up values, see the tests for
+ // examples of what that means.
+ data.milliseconds = milliseconds % 1000;
+
+ seconds = absFloor(milliseconds / 1000);
+ data.seconds = seconds % 60;
+
+ minutes = absFloor(seconds / 60);
+ data.minutes = minutes % 60;
+
+ hours = absFloor(minutes / 60);
+ data.hours = hours % 24;
+
+ days += absFloor(hours / 24);
+
+ // convert days to months
+ monthsFromDays = absFloor(daysToMonths(days));
+ months += monthsFromDays;
+ days -= absCeil(monthsToDays(monthsFromDays));
+
+ // 12 months -> 1 year
+ years = absFloor(months / 12);
+ months %= 12;
+
+ data.days = days;
+ data.months = months;
+ data.years = years;
+
+ return this;
+}
+
+function daysToMonths (days) {
+ // 400 years have 146097 days (taking into account leap year rules)
+ // 400 years have 12 months === 4800
+ return days * 4800 / 146097;
+}
+
+function monthsToDays (months) {
+ // the reverse of daysToMonths
+ return months * 146097 / 4800;
+}
+
+function as (units) {
+ if (!this.isValid()) {
+ return NaN;
+ }
+ var days;
+ var months;
+ var milliseconds = this._milliseconds;
+
+ units = normalizeUnits(units);
+
+ if (units === 'month' || units === 'year') {
+ days = this._days + milliseconds / 864e5;
+ months = this._months + daysToMonths(days);
+ return units === 'month' ? months : months / 12;
+ } else {
+ // handle milliseconds separately because of floating point math errors (issue #1867)
+ days = this._days + Math.round(monthsToDays(this._months));
+ switch (units) {
+ case 'week' : return days / 7 + milliseconds / 6048e5;
+ case 'day' : return days + milliseconds / 864e5;
+ case 'hour' : return days * 24 + milliseconds / 36e5;
+ case 'minute' : return days * 1440 + milliseconds / 6e4;
+ case 'second' : return days * 86400 + milliseconds / 1000;
+ // Math.floor prevents floating point math errors here
+ case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+ default: throw new Error('Unknown unit ' + units);
+ }
+ }
+}
+
+// TODO: Use this.as('ms')?
+function valueOf$1 () {
+ if (!this.isValid()) {
+ return NaN;
+ }
+ return (
+ this._milliseconds +
+ this._days * 864e5 +
+ (this._months % 12) * 2592e6 +
+ toInt(this._months / 12) * 31536e6
+ );
+}
+
+function makeAs (alias) {
+ return function () {
+ return this.as(alias);
+ };
+}
+
+var asMilliseconds = makeAs('ms');
+var asSeconds = makeAs('s');
+var asMinutes = makeAs('m');
+var asHours = makeAs('h');
+var asDays = makeAs('d');
+var asWeeks = makeAs('w');
+var asMonths = makeAs('M');
+var asYears = makeAs('y');
+
+function clone$1 () {
+ return createDuration(this);
+}
+
+function get$2 (units) {
+ units = normalizeUnits(units);
+ return this.isValid() ? this[units + 's']() : NaN;
+}
+
+function makeGetter(name) {
+ return function () {
+ return this.isValid() ? this._data[name] : NaN;
+ };
+}
+
+var milliseconds = makeGetter('milliseconds');
+var seconds = makeGetter('seconds');
+var minutes = makeGetter('minutes');
+var hours = makeGetter('hours');
+var days = makeGetter('days');
+var months = makeGetter('months');
+var years = makeGetter('years');
+
+function weeks () {
+ return absFloor(this.days() / 7);
+}
+
+var round = Math.round;
+var thresholds = {
+ ss: 44, // a few seconds to seconds
+ s : 45, // seconds to minute
+ m : 45, // minutes to hour
+ h : 22, // hours to day
+ d : 26, // days to month
+ M : 11 // months to year
+};
+
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+ return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+}
+
+function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
+ var duration = createDuration(posNegDuration).abs();
+ var seconds = round(duration.as('s'));
+ var minutes = round(duration.as('m'));
+ var hours = round(duration.as('h'));
+ var days = round(duration.as('d'));
+ var months = round(duration.as('M'));
+ var years = round(duration.as('y'));
+
+ var a = seconds <= thresholds.ss && ['s', seconds] ||
+ seconds < thresholds.s && ['ss', seconds] ||
+ minutes <= 1 && ['m'] ||
+ minutes < thresholds.m && ['mm', minutes] ||
+ hours <= 1 && ['h'] ||
+ hours < thresholds.h && ['hh', hours] ||
+ days <= 1 && ['d'] ||
+ days < thresholds.d && ['dd', days] ||
+ months <= 1 && ['M'] ||
+ months < thresholds.M && ['MM', months] ||
+ years <= 1 && ['y'] || ['yy', years];
+
+ a[2] = withoutSuffix;
+ a[3] = +posNegDuration > 0;
+ a[4] = locale;
+ return substituteTimeAgo.apply(null, a);
+}
+
+// This function allows you to set the rounding function for relative time strings
+function getSetRelativeTimeRounding (roundingFunction) {
+ if (roundingFunction === undefined) {
+ return round;
+ }
+ if (typeof(roundingFunction) === 'function') {
+ round = roundingFunction;
+ return true;
+ }
+ return false;
+}
+
+// This function allows you to set a threshold for relative time strings
+function getSetRelativeTimeThreshold (threshold, limit) {
+ if (thresholds[threshold] === undefined) {
+ return false;
+ }
+ if (limit === undefined) {
+ return thresholds[threshold];
+ }
+ thresholds[threshold] = limit;
+ if (threshold === 's') {
+ thresholds.ss = limit - 1;
+ }
+ return true;
+}
+
+function humanize (withSuffix) {
+ if (!this.isValid()) {
+ return this.localeData().invalidDate();
+ }
+
+ var locale = this.localeData();
+ var output = relativeTime$1(this, !withSuffix, locale);
+
+ if (withSuffix) {
+ output = locale.pastFuture(+this, output);
+ }
+
+ return locale.postformat(output);
+}
+
+var abs$1 = Math.abs;
+
+function sign(x) {
+ return ((x > 0) - (x < 0)) || +x;
+}
+
+function toISOString$1() {
+ // for ISO strings we do not use the normal bubbling rules:
+ // * milliseconds bubble up until they become hours
+ // * days do not bubble at all
+ // * months bubble up until they become years
+ // This is because there is no context-free conversion between hours and days
+ // (think of clock changes)
+ // and also not between days and months (28-31 days per month)
+ if (!this.isValid()) {
+ return this.localeData().invalidDate();
+ }
+
+ var seconds = abs$1(this._milliseconds) / 1000;
+ var days = abs$1(this._days);
+ var months = abs$1(this._months);
+ var minutes, hours, years;
+
+ // 3600 seconds -> 60 minutes -> 1 hour
+ minutes = absFloor(seconds / 60);
+ hours = absFloor(minutes / 60);
+ seconds %= 60;
+ minutes %= 60;
+
+ // 12 months -> 1 year
+ years = absFloor(months / 12);
+ months %= 12;
+
+
+ // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+ var Y = years;
+ var M = months;
+ var D = days;
+ var h = hours;
+ var m = minutes;
+ var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
+ var total = this.asSeconds();
+
+ if (!total) {
+ // this is the same as C#'s (Noda) and python (isodate)...
+ // but not other JS (goog.date)
+ return 'P0D';
+ }
+
+ var totalSign = total < 0 ? '-' : '';
+ var ymSign = sign(this._months) !== sign(total) ? '-' : '';
+ var daysSign = sign(this._days) !== sign(total) ? '-' : '';
+ var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
+
+ return totalSign + 'P' +
+ (Y ? ymSign + Y + 'Y' : '') +
+ (M ? ymSign + M + 'M' : '') +
+ (D ? daysSign + D + 'D' : '') +
+ ((h || m || s) ? 'T' : '') +
+ (h ? hmsSign + h + 'H' : '') +
+ (m ? hmsSign + m + 'M' : '') +
+ (s ? hmsSign + s + 'S' : '');
+}
+
+var proto$2 = Duration.prototype;
+
+proto$2.isValid = isValid$1;
+proto$2.abs = abs;
+proto$2.add = add$1;
+proto$2.subtract = subtract$1;
+proto$2.as = as;
+proto$2.asMilliseconds = asMilliseconds;
+proto$2.asSeconds = asSeconds;
+proto$2.asMinutes = asMinutes;
+proto$2.asHours = asHours;
+proto$2.asDays = asDays;
+proto$2.asWeeks = asWeeks;
+proto$2.asMonths = asMonths;
+proto$2.asYears = asYears;
+proto$2.valueOf = valueOf$1;
+proto$2._bubble = bubble;
+proto$2.clone = clone$1;
+proto$2.get = get$2;
+proto$2.milliseconds = milliseconds;
+proto$2.seconds = seconds;
+proto$2.minutes = minutes;
+proto$2.hours = hours;
+proto$2.days = days;
+proto$2.weeks = weeks;
+proto$2.months = months;
+proto$2.years = years;
+proto$2.humanize = humanize;
+proto$2.toISOString = toISOString$1;
+proto$2.toString = toISOString$1;
+proto$2.toJSON = toISOString$1;
+proto$2.locale = locale;
+proto$2.localeData = localeData;
+
+proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
+proto$2.lang = lang;
+
+// Side effect imports
+
+// FORMATTING
+
+addFormatToken('X', 0, 0, 'unix');
+addFormatToken('x', 0, 0, 'valueOf');
+
+// PARSING
+
+addRegexToken('x', matchSigned);
+addRegexToken('X', matchTimestamp);
+addParseToken('X', function (input, array, config) {
+ config._d = new Date(parseFloat(input, 10) * 1000);
+});
+addParseToken('x', function (input, array, config) {
+ config._d = new Date(toInt(input));
+});
+
+// Side effect imports
+
+
+hooks.version = '2.21.0';
+
+setHookCallback(createLocal);
+
+hooks.fn = proto;
+hooks.min = min;
+hooks.max = max;
+hooks.now = now;
+hooks.utc = createUTC;
+hooks.unix = createUnix;
+hooks.months = listMonths;
+hooks.isDate = isDate;
+hooks.locale = getSetGlobalLocale;
+hooks.invalid = createInvalid;
+hooks.duration = createDuration;
+hooks.isMoment = isMoment;
+hooks.weekdays = listWeekdays;
+hooks.parseZone = createInZone;
+hooks.localeData = getLocale;
+hooks.isDuration = isDuration;
+hooks.monthsShort = listMonthsShort;
+hooks.weekdaysMin = listWeekdaysMin;
+hooks.defineLocale = defineLocale;
+hooks.updateLocale = updateLocale;
+hooks.locales = listLocales;
+hooks.weekdaysShort = listWeekdaysShort;
+hooks.normalizeUnits = normalizeUnits;
+hooks.relativeTimeRounding = getSetRelativeTimeRounding;
+hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
+hooks.calendarFormat = getCalendarFormat;
+hooks.prototype = proto;
+
+// currently HTML5 input type only supports 24-hour formats
+hooks.HTML5_FMT = {
+ DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" />
+ DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" />
+ DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" />
+ DATE: 'YYYY-MM-DD', // <input type="date" />
+ TIME: 'HH:mm', // <input type="time" />
+ TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" />
+ TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" />
+ WEEK: 'YYYY-[W]WW', // <input type="week" />
+ MONTH: 'YYYY-MM' // <input type="month" />
+};
+
+return hooks;
+
+})));
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.js
new file mode 100644
index 00000000..725caf06
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.js
@@ -0,0 +1,496 @@
+/*
+ * Playlist Object for the jPlayer Plugin
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2014 Happyworm Ltd
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/MIT
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.4.1
+ * Date: 19th November 2014
+ *
+ * Requires:
+ * - jQuery 1.7.0+
+ * - jPlayer 2.8.2+
+ */
+
+/*global jPlayerPlaylist:true */
+
+(function($, undefined) {
+
+ jPlayerPlaylist = function(cssSelector, playlist, options) {
+ var self = this;
+
+ this.current = 0;
+ this.loop = false; // Flag used with the jPlayer repeat event
+ this.shuffled = false;
+ this.removing = false; // Flag is true during remove animation, disabling the remove() method until complete.
+
+ this.cssSelector = $.extend({}, this._cssSelector, cssSelector); // Object: Containing the css selectors for jPlayer and its cssSelectorAncestor
+ this.options = $.extend(true, {
+ keyBindings: {
+ next: {
+ key: 221, // ]
+ fn: function() {
+ self.next();
+ }
+ },
+ previous: {
+ key: 219, // [
+ fn: function() {
+ self.previous();
+ }
+ },
+ shuffle: {
+ key: 83, // s
+ fn: function() {
+ self.shuffle();
+ }
+ }
+ },
+ stateClass: {
+ shuffled: "jp-state-shuffled"
+ }
+ }, this._options, options); // Object: The jPlayer constructor options for this playlist and the playlist options
+
+ this.playlist = []; // Array of Objects: The current playlist displayed (Un-shuffled or Shuffled)
+ this.original = []; // Array of Objects: The original playlist
+
+ this._initPlaylist(playlist); // Copies playlist to this.original. Then mirrors this.original to this.playlist. Creating two arrays, where the element pointers match. (Enables pointer comparison.)
+
+ // Setup the css selectors for the extra interface items used by the playlist.
+ this.cssSelector.details = this.cssSelector.cssSelectorAncestor + " .jp-details"; // Note that jPlayer controls the text in the title element.
+ this.cssSelector.playlist = this.cssSelector.cssSelectorAncestor + " .jp-playlist";
+ this.cssSelector.next = this.cssSelector.cssSelectorAncestor + " .jp-next";
+ this.cssSelector.previous = this.cssSelector.cssSelectorAncestor + " .jp-previous";
+ this.cssSelector.shuffle = this.cssSelector.cssSelectorAncestor + " .jp-shuffle";
+ this.cssSelector.shuffleOff = this.cssSelector.cssSelectorAncestor + " .jp-shuffle-off";
+
+ // Override the cssSelectorAncestor given in options
+ this.options.cssSelectorAncestor = this.cssSelector.cssSelectorAncestor;
+
+ // Override the default repeat event handler
+ this.options.repeat = function(event) {
+ self.loop = event.jPlayer.options.loop;
+ };
+
+ // Create a ready event handler to initialize the playlist
+ $(this.cssSelector.jPlayer).bind($.jPlayer.event.ready, function() {
+ self._init();
+ });
+
+ // Create an ended event handler to move to the next item
+ $(this.cssSelector.jPlayer).bind($.jPlayer.event.ended, function() {
+ self.next();
+ });
+
+ // Create a play event handler to pause other instances
+ $(this.cssSelector.jPlayer).bind($.jPlayer.event.play, function() {
+ $(this).jPlayer("pauseOthers");
+ });
+
+ // Create a resize event handler to show the title in full screen mode.
+ $(this.cssSelector.jPlayer).bind($.jPlayer.event.resize, function(event) {
+ if(event.jPlayer.options.fullScreen) {
+ $(self.cssSelector.details).show();
+ } else {
+ $(self.cssSelector.details).hide();
+ }
+ });
+
+ // Create click handlers for the extra buttons that do playlist functions.
+ $(this.cssSelector.previous).click(function(e) {
+ e.preventDefault();
+ self.previous();
+ self.blur(this);
+ });
+
+ $(this.cssSelector.next).click(function(e) {
+ e.preventDefault();
+ self.next();
+ self.blur(this);
+ });
+
+ $(this.cssSelector.shuffle).click(function(e) {
+ e.preventDefault();
+ if(self.shuffled && $(self.cssSelector.jPlayer).jPlayer("option", "useStateClassSkin")) {
+ self.shuffle(false);
+ } else {
+ self.shuffle(true);
+ }
+ self.blur(this);
+ });
+ $(this.cssSelector.shuffleOff).click(function(e) {
+ e.preventDefault();
+ self.shuffle(false);
+ self.blur(this);
+ }).hide();
+
+ // Put the title in its initial display state
+ if(!this.options.fullScreen) {
+ $(this.cssSelector.details).hide();
+ }
+
+ // Remove the empty <li> from the page HTML. Allows page to be valid HTML, while not interfereing with display animations
+ $(this.cssSelector.playlist + " ul").empty();
+
+ // Create .on() handlers for the playlist items along with the free media and remove controls.
+ this._createItemHandlers();
+
+ // Instance jPlayer
+ $(this.cssSelector.jPlayer).jPlayer(this.options);
+ };
+
+ jPlayerPlaylist.prototype = {
+ _cssSelector: { // static object, instanced in constructor
+ jPlayer: "#jquery_jplayer_1",
+ cssSelectorAncestor: "#jp_container_1"
+ },
+ _options: { // static object, instanced in constructor
+ playlistOptions: {
+ autoPlay: false,
+ loopOnPrevious: false,
+ shuffleOnLoop: true,
+ enableRemoveControls: false,
+ displayTime: 'slow',
+ addTime: 'fast',
+ removeTime: 'fast',
+ shuffleTime: 'slow',
+ itemClass: "jp-playlist-item",
+ freeGroupClass: "jp-free-media",
+ freeItemClass: "jp-playlist-item-free",
+ removeItemClass: "jp-playlist-item-remove"
+ }
+ },
+ option: function(option, value) { // For changing playlist options only
+ if(value === undefined) {
+ return this.options.playlistOptions[option];
+ }
+
+ this.options.playlistOptions[option] = value;
+
+ switch(option) {
+ case "enableRemoveControls":
+ this._updateControls();
+ break;
+ case "itemClass":
+ case "freeGroupClass":
+ case "freeItemClass":
+ case "removeItemClass":
+ this._refresh(true); // Instant
+ this._createItemHandlers();
+ break;
+ }
+ return this;
+ },
+ _init: function() {
+ var self = this;
+ this._refresh(function() {
+ if(self.options.playlistOptions.autoPlay) {
+ self.play(self.current);
+ } else {
+ self.select(self.current);
+ }
+ });
+ },
+ _initPlaylist: function(playlist) {
+ this.current = 0;
+ this.shuffled = false;
+ this.removing = false;
+ this.original = $.extend(true, [], playlist); // Copy the Array of Objects
+ this._originalPlaylist();
+ },
+ _originalPlaylist: function() {
+ var self = this;
+ this.playlist = [];
+ // Make both arrays point to the same object elements. Gives us 2 different arrays, each pointing to the same actual object. ie., Not copies of the object.
+ $.each(this.original, function(i) {
+ self.playlist[i] = self.original[i];
+ });
+ },
+ _refresh: function(instant) {
+ /* instant: Can be undefined, true or a function.
+ * undefined -> use animation timings
+ * true -> no animation
+ * function -> use animation timings and excute function at half way point.
+ */
+ var self = this;
+
+ if(instant && !$.isFunction(instant)) {
+ $(this.cssSelector.playlist + " ul").empty();
+ $.each(this.playlist, function(i) {
+ $(self.cssSelector.playlist + " ul").append(self._createListItem(self.playlist[i]));
+ });
+ this._updateControls();
+ } else {
+ var displayTime = $(this.cssSelector.playlist + " ul").children().length ? this.options.playlistOptions.displayTime : 0;
+
+ $(this.cssSelector.playlist + " ul").slideUp(displayTime, function() {
+ var $this = $(this);
+ $(this).empty();
+
+ $.each(self.playlist, function(i) {
+ $this.append(self._createListItem(self.playlist[i]));
+ });
+ self._updateControls();
+ if($.isFunction(instant)) {
+ instant();
+ }
+ if(self.playlist.length) {
+ $(this).slideDown(self.options.playlistOptions.displayTime);
+ } else {
+ $(this).show();
+ }
+ });
+ }
+ },
+ _createListItem: function(media) {
+ var self = this;
+
+ // Wrap the <li> contents in a <div>
+ var listItem = "<li><div>";
+
+ // Create remove control
+ listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.removeItemClass + "'>&times;</a>";
+
+ // Create links to free media
+ if(media.free) {
+ var first = true;
+ listItem += "<span class='" + this.options.playlistOptions.freeGroupClass + "'>(";
+ $.each(media, function(property,value) {
+ if($.jPlayer.prototype.format[property]) { // Check property is a media format.
+ if(first) {
+ first = false;
+ } else {
+ listItem += " | ";
+ }
+ listItem += "<a class='" + self.options.playlistOptions.freeItemClass + "' href='" + value + "' tabindex='-1'>" + property + "</a>";
+ }
+ });
+ listItem += ")</span>";
+ }
+
+ // The title is given next in the HTML otherwise the float:right on the free media corrupts in IE6/7
+ listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.itemClass + "' tabindex='0'>" + media.title + (media.artist ? " <span class='jp-artist'>by " + media.artist + "</span>" : "") + "</a>";
+ listItem += "</div></li>";
+
+ return listItem;
+ },
+ _createItemHandlers: function() {
+ var self = this;
+ // Create live handlers for the playlist items
+ $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.itemClass).on("click", "a." + this.options.playlistOptions.itemClass, function(e) {
+ e.preventDefault();
+ var index = $(this).parent().parent().index();
+ if(self.current !== index) {
+ self.play(index);
+ } else {
+ $(self.cssSelector.jPlayer).jPlayer("play");
+ }
+ self.blur(this);
+ });
+
+ // Create live handlers that disable free media links to force access via right click
+ $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.freeItemClass).on("click", "a." + this.options.playlistOptions.freeItemClass, function(e) {
+ e.preventDefault();
+ $(this).parent().parent().find("." + self.options.playlistOptions.itemClass).click();
+ self.blur(this);
+ });
+
+ // Create live handlers for the remove controls
+ $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.removeItemClass).on("click", "a." + this.options.playlistOptions.removeItemClass, function(e) {
+ e.preventDefault();
+ var index = $(this).parent().parent().index();
+ self.remove(index);
+ self.blur(this);
+ });
+ },
+ _updateControls: function() {
+ if(this.options.playlistOptions.enableRemoveControls) {
+ $(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).show();
+ } else {
+ $(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).hide();
+ }
+
+ if(this.shuffled) {
+ $(this.cssSelector.jPlayer).jPlayer("addStateClass", "shuffled");
+ } else {
+ $(this.cssSelector.jPlayer).jPlayer("removeStateClass", "shuffled");
+ }
+ if($(this.cssSelector.shuffle).length && $(this.cssSelector.shuffleOff).length) {
+ if(this.shuffled) {
+ $(this.cssSelector.shuffleOff).show();
+ $(this.cssSelector.shuffle).hide();
+ } else {
+ $(this.cssSelector.shuffleOff).hide();
+ $(this.cssSelector.shuffle).show();
+ }
+ }
+ },
+ _highlight: function(index) {
+ if(this.playlist.length && index !== undefined) {
+ $(this.cssSelector.playlist + " .jp-playlist-current").removeClass("jp-playlist-current");
+ $(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current");
+ // $(this.cssSelector.details + " li").html("<span class='jp-title'>" + this.playlist[index].title + "</span>" + (this.playlist[index].artist ? " <span class='jp-artist'>by " + this.playlist[index].artist + "</span>" : ""));
+ }
+ },
+ setPlaylist: function(playlist) {
+ this._initPlaylist(playlist);
+ this._init();
+ },
+ add: function(media, playNow) {
+ $(this.cssSelector.playlist + " ul").append(this._createListItem(media)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);
+ this._updateControls();
+ this.original.push(media);
+ this.playlist.push(media); // Both array elements share the same object pointer. Comforms with _initPlaylist(p) system.
+
+ if(playNow) {
+ this.play(this.playlist.length - 1);
+ } else {
+ if(this.original.length === 1) {
+ this.select(0);
+ }
+ }
+ },
+ remove: function(index) {
+ var self = this;
+
+ if(index === undefined) {
+ this._initPlaylist([]);
+ this._refresh(function() {
+ $(self.cssSelector.jPlayer).jPlayer("clearMedia");
+ });
+ return true;
+ } else {
+
+ if(this.removing) {
+ return false;
+ } else {
+ index = (index < 0) ? self.original.length + index : index; // Negative index relates to end of array.
+ if(0 <= index && index < this.playlist.length) {
+ this.removing = true;
+
+ $(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").slideUp(this.options.playlistOptions.removeTime, function() {
+ $(this).remove();
+
+ if(self.shuffled) {
+ var item = self.playlist[index];
+ $.each(self.original, function(i) {
+ if(self.original[i] === item) {
+ self.original.splice(i, 1);
+ return false; // Exit $.each
+ }
+ });
+ self.playlist.splice(index, 1);
+ } else {
+ self.original.splice(index, 1);
+ self.playlist.splice(index, 1);
+ }
+
+ if(self.original.length) {
+ if(index === self.current) {
+ self.current = (index < self.original.length) ? self.current : self.original.length - 1; // To cope when last element being selected when it was removed
+ self.select(self.current);
+ } else if(index < self.current) {
+ self.current--;
+ }
+ } else {
+ $(self.cssSelector.jPlayer).jPlayer("clearMedia");
+ self.current = 0;
+ self.shuffled = false;
+ self._updateControls();
+ }
+
+ self.removing = false;
+ });
+ }
+ return true;
+ }
+ }
+ },
+ select: function(index) {
+ index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
+ if(0 <= index && index < this.playlist.length) {
+ this.current = index;
+ this._highlight(index);
+ $(this.cssSelector.jPlayer).jPlayer("setMedia", this.playlist[this.current]);
+ } else {
+ this.current = 0;
+ }
+ },
+ play: function(index) {
+ index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
+ if(0 <= index && index < this.playlist.length) {
+ if(this.playlist.length) {
+ this.select(index);
+ $(this.cssSelector.jPlayer).jPlayer("play");
+ }
+ } else if(index === undefined) {
+ $(this.cssSelector.jPlayer).jPlayer("play");
+ }
+ },
+ pause: function() {
+ $(this.cssSelector.jPlayer).jPlayer("pause");
+ },
+ next: function() {
+ var index = (this.current + 1 < this.playlist.length) ? this.current + 1 : 0;
+
+ if(this.loop) {
+ // See if we need to shuffle before looping to start, and only shuffle if more than 1 item.
+ if(index === 0 && this.shuffled && this.options.playlistOptions.shuffleOnLoop && this.playlist.length > 1) {
+ this.shuffle(true, true); // playNow
+ } else {
+ this.play(index);
+ }
+ } else {
+ // The index will be zero if it just looped round
+ if(index > 0) {
+ this.play(index);
+ }
+ }
+ },
+ previous: function() {
+ var index = (this.current - 1 >= 0) ? this.current - 1 : this.playlist.length - 1;
+
+ if(this.loop && this.options.playlistOptions.loopOnPrevious || index < this.playlist.length - 1) {
+ this.play(index);
+ }
+ },
+ shuffle: function(shuffled, playNow) {
+ var self = this;
+
+ if(shuffled === undefined) {
+ shuffled = !this.shuffled;
+ }
+
+ if(shuffled || shuffled !== this.shuffled) {
+
+ $(this.cssSelector.playlist + " ul").slideUp(this.options.playlistOptions.shuffleTime, function() {
+ self.shuffled = shuffled;
+ if(shuffled) {
+ self.playlist.sort(function() {
+ return 0.5 - Math.random();
+ });
+ } else {
+ self._originalPlaylist();
+ }
+ self._refresh(true); // Instant
+
+ if(playNow || !$(self.cssSelector.jPlayer).data("jPlayer").status.paused) {
+ self.play(0);
+ } else {
+ self.select(0);
+ }
+
+ $(this).slideDown(self.options.playlistOptions.shuffleTime);
+ });
+ }
+ },
+ blur: function(that) {
+ if($(this.cssSelector.jPlayer).jPlayer("option", "autoBlur")) {
+ $(that).blur();
+ }
+ }
+ };
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js
new file mode 100644
index 00000000..6a0e866f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js
@@ -0,0 +1,2 @@
+/*! jPlayerPlaylist for jPlayer 2.9.2 ~ (c) 2009-2014 Happyworm Ltd ~ MIT License */
+!function(a,b){jPlayerPlaylist=function(b,c,d){var e=this;this.current=0,this.loop=!1,this.shuffled=!1,this.removing=!1,this.cssSelector=a.extend({},this._cssSelector,b),this.options=a.extend(!0,{keyBindings:{next:{key:221,fn:function(){e.next()}},previous:{key:219,fn:function(){e.previous()}},shuffle:{key:83,fn:function(){e.shuffle()}}},stateClass:{shuffled:"jp-state-shuffled"}},this._options,d),this.playlist=[],this.original=[],this._initPlaylist(c),this.cssSelector.details=this.cssSelector.cssSelectorAncestor+" .jp-details",this.cssSelector.playlist=this.cssSelector.cssSelectorAncestor+" .jp-playlist",this.cssSelector.next=this.cssSelector.cssSelectorAncestor+" .jp-next",this.cssSelector.previous=this.cssSelector.cssSelectorAncestor+" .jp-previous",this.cssSelector.shuffle=this.cssSelector.cssSelectorAncestor+" .jp-shuffle",this.cssSelector.shuffleOff=this.cssSelector.cssSelectorAncestor+" .jp-shuffle-off",this.options.cssSelectorAncestor=this.cssSelector.cssSelectorAncestor,this.options.repeat=function(a){e.loop=a.jPlayer.options.loop},a(this.cssSelector.jPlayer).bind(a.jPlayer.event.ready,function(){e._init()}),a(this.cssSelector.jPlayer).bind(a.jPlayer.event.ended,function(){e.next()}),a(this.cssSelector.jPlayer).bind(a.jPlayer.event.play,function(){a(this).jPlayer("pauseOthers")}),a(this.cssSelector.jPlayer).bind(a.jPlayer.event.resize,function(b){b.jPlayer.options.fullScreen?a(e.cssSelector.details).show():a(e.cssSelector.details).hide()}),a(this.cssSelector.previous).click(function(a){a.preventDefault(),e.previous(),e.blur(this)}),a(this.cssSelector.next).click(function(a){a.preventDefault(),e.next(),e.blur(this)}),a(this.cssSelector.shuffle).click(function(b){b.preventDefault(),e.shuffle(e.shuffled&&a(e.cssSelector.jPlayer).jPlayer("option","useStateClassSkin")?!1:!0),e.blur(this)}),a(this.cssSelector.shuffleOff).click(function(a){a.preventDefault(),e.shuffle(!1),e.blur(this)}).hide(),this.options.fullScreen||a(this.cssSelector.details).hide(),a(this.cssSelector.playlist+" ul").empty(),this._createItemHandlers(),a(this.cssSelector.jPlayer).jPlayer(this.options)},jPlayerPlaylist.prototype={_cssSelector:{jPlayer:"#jquery_jplayer_1",cssSelectorAncestor:"#jp_container_1"},_options:{playlistOptions:{autoPlay:!1,loopOnPrevious:!1,shuffleOnLoop:!0,enableRemoveControls:!1,displayTime:"slow",addTime:"fast",removeTime:"fast",shuffleTime:"slow",itemClass:"jp-playlist-item",freeGroupClass:"jp-free-media",freeItemClass:"jp-playlist-item-free",removeItemClass:"jp-playlist-item-remove"}},option:function(a,c){if(c===b)return this.options.playlistOptions[a];switch(this.options.playlistOptions[a]=c,a){case"enableRemoveControls":this._updateControls();break;case"itemClass":case"freeGroupClass":case"freeItemClass":case"removeItemClass":this._refresh(!0),this._createItemHandlers()}return this},_init:function(){var a=this;this._refresh(function(){a.options.playlistOptions.autoPlay?a.play(a.current):a.select(a.current)})},_initPlaylist:function(b){this.current=0,this.shuffled=!1,this.removing=!1,this.original=a.extend(!0,[],b),this._originalPlaylist()},_originalPlaylist:function(){var b=this;this.playlist=[],a.each(this.original,function(a){b.playlist[a]=b.original[a]})},_refresh:function(b){var c=this;if(b&&!a.isFunction(b))a(this.cssSelector.playlist+" ul").empty(),a.each(this.playlist,function(b){a(c.cssSelector.playlist+" ul").append(c._createListItem(c.playlist[b]))}),this._updateControls();else{var d=a(this.cssSelector.playlist+" ul").children().length?this.options.playlistOptions.displayTime:0;a(this.cssSelector.playlist+" ul").slideUp(d,function(){var d=a(this);a(this).empty(),a.each(c.playlist,function(a){d.append(c._createListItem(c.playlist[a]))}),c._updateControls(),a.isFunction(b)&&b(),c.playlist.length?a(this).slideDown(c.options.playlistOptions.displayTime):a(this).show()})}},_createListItem:function(b){var c=this,d="<li><div>";if(d+="<a href='javascript:;' class='"+this.options.playlistOptions.removeItemClass+"'>&times;</a>",b.free){var e=!0;d+="<span class='"+this.options.playlistOptions.freeGroupClass+"'>(",a.each(b,function(b,f){a.jPlayer.prototype.format[b]&&(e?e=!1:d+=" | ",d+="<a class='"+c.options.playlistOptions.freeItemClass+"' href='"+f+"' tabindex='-1'>"+b+"</a>")}),d+=")</span>"}return d+="<a href='javascript:;' class='"+this.options.playlistOptions.itemClass+"' tabindex='0'>"+b.title+(b.artist?" <span class='jp-artist'>by "+b.artist+"</span>":"")+"</a>",d+="</div></li>"},_createItemHandlers:function(){var b=this;a(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.itemClass).on("click","a."+this.options.playlistOptions.itemClass,function(c){c.preventDefault();var d=a(this).parent().parent().index();b.current!==d?b.play(d):a(b.cssSelector.jPlayer).jPlayer("play"),b.blur(this)}),a(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.freeItemClass).on("click","a."+this.options.playlistOptions.freeItemClass,function(c){c.preventDefault(),a(this).parent().parent().find("."+b.options.playlistOptions.itemClass).click(),b.blur(this)}),a(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.removeItemClass).on("click","a."+this.options.playlistOptions.removeItemClass,function(c){c.preventDefault();var d=a(this).parent().parent().index();b.remove(d),b.blur(this)})},_updateControls:function(){this.options.playlistOptions.enableRemoveControls?a(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).show():a(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).hide(),this.shuffled?a(this.cssSelector.jPlayer).jPlayer("addStateClass","shuffled"):a(this.cssSelector.jPlayer).jPlayer("removeStateClass","shuffled"),a(this.cssSelector.shuffle).length&&a(this.cssSelector.shuffleOff).length&&(this.shuffled?(a(this.cssSelector.shuffleOff).show(),a(this.cssSelector.shuffle).hide()):(a(this.cssSelector.shuffleOff).hide(),a(this.cssSelector.shuffle).show()))},_highlight:function(c){this.playlist.length&&c!==b&&(a(this.cssSelector.playlist+" .jp-playlist-current").removeClass("jp-playlist-current"),a(this.cssSelector.playlist+" li:nth-child("+(c+1)+")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current"))},setPlaylist:function(a){this._initPlaylist(a),this._init()},add:function(b,c){a(this.cssSelector.playlist+" ul").append(this._createListItem(b)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime),this._updateControls(),this.original.push(b),this.playlist.push(b),c?this.play(this.playlist.length-1):1===this.original.length&&this.select(0)},remove:function(c){var d=this;return c===b?(this._initPlaylist([]),this._refresh(function(){a(d.cssSelector.jPlayer).jPlayer("clearMedia")}),!0):this.removing?!1:(c=0>c?d.original.length+c:c,c>=0&&c<this.playlist.length&&(this.removing=!0,a(this.cssSelector.playlist+" li:nth-child("+(c+1)+")").slideUp(this.options.playlistOptions.removeTime,function(){if(a(this).remove(),d.shuffled){var b=d.playlist[c];a.each(d.original,function(a){return d.original[a]===b?(d.original.splice(a,1),!1):void 0}),d.playlist.splice(c,1)}else d.original.splice(c,1),d.playlist.splice(c,1);d.original.length?c===d.current?(d.current=c<d.original.length?d.current:d.original.length-1,d.select(d.current)):c<d.current&&d.current--:(a(d.cssSelector.jPlayer).jPlayer("clearMedia"),d.current=0,d.shuffled=!1,d._updateControls()),d.removing=!1})),!0)},select:function(b){b=0>b?this.original.length+b:b,b>=0&&b<this.playlist.length?(this.current=b,this._highlight(b),a(this.cssSelector.jPlayer).jPlayer("setMedia",this.playlist[this.current])):this.current=0},play:function(c){c=0>c?this.original.length+c:c,c>=0&&c<this.playlist.length?this.playlist.length&&(this.select(c),a(this.cssSelector.jPlayer).jPlayer("play")):c===b&&a(this.cssSelector.jPlayer).jPlayer("play")},pause:function(){a(this.cssSelector.jPlayer).jPlayer("pause")},next:function(){var a=this.current+1<this.playlist.length?this.current+1:0;this.loop?0===a&&this.shuffled&&this.options.playlistOptions.shuffleOnLoop&&this.playlist.length>1?this.shuffle(!0,!0):this.play(a):a>0&&this.play(a)},previous:function(){var a=this.current-1>=0?this.current-1:this.playlist.length-1;(this.loop&&this.options.playlistOptions.loopOnPrevious||a<this.playlist.length-1)&&this.play(a)},shuffle:function(c,d){var e=this;c===b&&(c=!this.shuffled),(c||c!==this.shuffled)&&a(this.cssSelector.playlist+" ul").slideUp(this.options.playlistOptions.shuffleTime,function(){e.shuffled=c,c?e.playlist.sort(function(){return.5-Math.random()}):e._originalPlaylist(),e._refresh(!0),d||!a(e.cssSelector.jPlayer).data("jPlayer").status.paused?e.play(0):e.select(0),a(this).slideDown(e.options.playlistOptions.shuffleTime)})},blur:function(b){a(this.cssSelector.jPlayer).jPlayer("option","autoBlur")&&a(b).blur()}}}(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js
new file mode 100644
index 00000000..e7a6cf89
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js
@@ -0,0 +1,338 @@
+/*
+ * jPlayerInspector Plugin for jPlayer Plugin for jQuery JavaScript Library
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2014 Happyworm Ltd
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/MIT
+ *
+ * Author: Mark J Panaghiston
+ * Version: 1.0.5
+ * Date: 1st April 2014
+ *
+ * For use with jPlayer Version: 2.6.0+
+ *
+ * Note: Declare inspector instances after jPlayer instances. ie., Otherwise the jPlayer instance is nonsense.
+ */
+
+(function($, undefined) {
+ $.jPlayerInspector = {};
+ $.jPlayerInspector.i = 0;
+ $.jPlayerInspector.defaults = {
+ jPlayer: undefined, // The jQuery selector of the jPlayer instance to inspect.
+ idPrefix: "jplayer_inspector_",
+ visible: false
+ };
+
+ var methods = {
+ init: function(options) {
+ var self = this;
+ var $this = $(this);
+
+ var config = $.extend({}, $.jPlayerInspector.defaults, options);
+ $(this).data("jPlayerInspector", config);
+
+ config.id = $(this).attr("id");
+ config.jPlayerId = config.jPlayer.attr("id");
+
+ config.windowId = config.idPrefix + "window_" + $.jPlayerInspector.i;
+ config.statusId = config.idPrefix + "status_" + $.jPlayerInspector.i;
+ config.configId = config.idPrefix + "config_" + $.jPlayerInspector.i;
+ config.toggleId = config.idPrefix + "toggle_" + $.jPlayerInspector.i;
+ config.eventResetId = config.idPrefix + "event_reset_" + $.jPlayerInspector.i;
+ config.updateId = config.idPrefix + "update_" + $.jPlayerInspector.i;
+ config.eventWindowId = config.idPrefix + "event_window_" + $.jPlayerInspector.i;
+
+ config.eventId = {};
+ config.eventJq = {};
+ config.eventTimeout = {};
+ config.eventOccurrence = {};
+
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventId[eventType] = config.idPrefix + "event_" + eventName + "_" + $.jPlayerInspector.i;
+ config.eventOccurrence[eventType] = 0;
+ });
+
+ var structure =
+ '<p><a href="#" id="' + config.toggleId + '">' + (config.visible ? "Hide" : "Show") + '</a> jPlayer Inspector</p>'
+ + '<div id="' + config.windowId + '">'
+ + '<div id="' + config.statusId + '"></div>'
+ + '<div id="' + config.eventWindowId + '" style="padding:5px 5px 0 5px;background-color:#eee;border:1px dotted #000;">'
+ + '<p style="margin:0 0 10px 0;"><strong>jPlayer events that have occurred over the past 1 second:</strong>'
+ + '<br />(Backgrounds: <span style="padding:0 5px;background-color:#eee;border:1px dotted #000;">Never occurred</span> <span style="padding:0 5px;background-color:#fff;border:1px dotted #000;">Occurred before</span> <span style="padding:0 5px;background-color:#9f9;border:1px dotted #000;">Occurred</span> <span style="padding:0 5px;background-color:#ff9;border:1px dotted #000;">Multiple occurrences</span> <a href="#" id="' + config.eventResetId + '">reset</a>)</p>';
+
+ // MJP: Would use the next 3 lines for ease, but the events are just slapped on the page.
+ // $.each($.jPlayer.event, function(eventName,eventType) {
+ // structure += '<div id="' + config.eventId[eventType] + '" style="float:left;">' + eventName + '</div>';
+ // });
+
+ var eventStyle = "float:left;margin:0 5px 5px 0;padding:0 5px;border:1px dotted #000;";
+ // MJP: Doing it longhand so order and layout easier to control.
+ structure +=
+ '<div id="' + config.eventId[$.jPlayer.event.ready] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.setmedia] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.flashreset] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.resize] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.repeat] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.click] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.warning] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.loadstart] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.progress] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.timeupdate] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.volumechange] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.error] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.play] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.pause] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.waiting] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.playing] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.seeking] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.seeked] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.ended] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.loadeddata] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.loadedmetadata] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.canplay] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.canplaythrough] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.suspend] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.abort] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.emptied] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.stalled] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.ratechange] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.durationchange] + '" style="' + eventStyle + '"></div>'
+
+ + '<div style="clear:both"></div>';
+
+ // MJP: Would like a check here in case we missed an event.
+
+ // MJP: Check fails, since it is not on the page yet.
+/* $.each($.jPlayer.event, function(eventName,eventType) {
+ if($("#" + config.eventId[eventType])[0] === undefined) {
+ structure += '<div id="' + config.eventId[eventType] + '" style="clear:left;' + eventStyle + '">' + eventName + '</div>';
+ }
+ });
+*/
+ structure +=
+ '</div>'
+ + '<p><a href="#" id="' + config.updateId + '">Update</a> jPlayer Inspector</p>'
+ + '<div id="' + config.configId + '"></div>'
+ + '</div>';
+ $(this).html(structure);
+
+ config.windowJq = $("#" + config.windowId);
+ config.statusJq = $("#" + config.statusId);
+ config.configJq = $("#" + config.configId);
+ config.toggleJq = $("#" + config.toggleId);
+ config.eventResetJq = $("#" + config.eventResetId);
+ config.updateJq = $("#" + config.updateId);
+
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventJq[eventType] = $("#" + config.eventId[eventType]);
+ config.eventJq[eventType].text(eventName + " (" + config.eventOccurrence[eventType] + ")"); // Sets the text to the event name and (0);
+
+ config.jPlayer.bind(eventType + ".jPlayerInspector", function(e) {
+ config.eventOccurrence[e.type]++;
+ if(config.eventOccurrence[e.type] > 1) {
+ config.eventJq[e.type].css("background-color","#ff9");
+ } else {
+ config.eventJq[e.type].css("background-color","#9f9");
+ }
+ config.eventJq[e.type].text(eventName + " (" + config.eventOccurrence[e.type] + ")");
+ // The timer to handle the color
+ clearTimeout(config.eventTimeout[e.type]);
+ config.eventTimeout[e.type] = setTimeout(function() {
+ config.eventJq[e.type].css("background-color","#fff");
+ }, 1000);
+ // The timer to handle the occurences.
+ setTimeout(function() {
+ config.eventOccurrence[e.type]--;
+ config.eventJq[e.type].text(eventName + " (" + config.eventOccurrence[e.type] + ")");
+ }, 1000);
+ if(config.visible) { // Update the status, if inspector open.
+ $this.jPlayerInspector("updateStatus");
+ }
+ });
+ });
+
+ config.jPlayer.bind($.jPlayer.event.ready + ".jPlayerInspector", function(e) {
+ $this.jPlayerInspector("updateConfig");
+ });
+
+ config.toggleJq.click(function() {
+ if(config.visible) {
+ $(this).text("Show");
+ config.windowJq.hide();
+ config.statusJq.empty();
+ config.configJq.empty();
+ } else {
+ $(this).text("Hide");
+ config.windowJq.show();
+ config.updateJq.click();
+ }
+ config.visible = !config.visible;
+ $(this).blur();
+ return false;
+ });
+
+ config.eventResetJq.click(function() {
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventJq[eventType].css("background-color","#eee");
+ });
+ $(this).blur();
+ return false;
+ });
+
+ config.updateJq.click(function() {
+ $this.jPlayerInspector("updateStatus");
+ $this.jPlayerInspector("updateConfig");
+ return false;
+ });
+
+ if(!config.visible) {
+ config.windowJq.hide();
+ } else {
+ // config.updateJq.click();
+ }
+
+ $.jPlayerInspector.i++;
+
+ return this;
+ },
+ destroy: function() {
+ $(this).data("jPlayerInspector") && $(this).data("jPlayerInspector").jPlayer.unbind(".jPlayerInspector");
+ $(this).empty();
+ },
+ updateConfig: function() { // This displays information about jPlayer's configuration in inspector
+
+ var jPlayerInfo = "<p>This jPlayer instance is running in your browser where:<br />"
+
+ for(i = 0; i < $(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions.length; i++) {
+ var solution = $(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions[i];
+ jPlayerInfo += "&nbsp;jPlayer's <strong>" + solution + "</strong> solution is";
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].used) {
+ jPlayerInfo += " being <strong>used</strong> and will support:<strong>";
+ for(format in $(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].support) {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].support[format]) {
+ jPlayerInfo += " " + format;
+ }
+ }
+ jPlayerInfo += "</strong><br />";
+ } else {
+ jPlayerInfo += " <strong>not required</strong><br />";
+ }
+ }
+ jPlayerInfo += "</p>";
+
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.active) {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active) {
+ jPlayerInfo += "<strong>Problem with jPlayer since both HTML5 and Flash are active.</strong>";
+ } else {
+ jPlayerInfo += "The <strong>HTML5 is active</strong>.";
+ }
+ } else {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active) {
+ jPlayerInfo += "The <strong>Flash is active</strong>.";
+ } else {
+ jPlayerInfo += "No solution is currently active. jPlayer needs a setMedia().";
+ }
+ }
+ jPlayerInfo += "</p>";
+
+ var formatType = $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.formatType;
+ jPlayerInfo += "<p><code>status.formatType = '" + formatType + "'</code><br />";
+ if(formatType) {
+ jPlayerInfo += "<code>Browser canPlay('" + $.jPlayer.prototype.format[formatType].codec + "')</code>";
+ } else {
+ jPlayerInfo += "</p>";
+ }
+
+ jPlayerInfo += "<p><code>status.src = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.src + "'</code></p>";
+
+ jPlayerInfo += "<p><code>status.media = {<br />";
+ for(prop in $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media) {
+ jPlayerInfo += "&nbsp;" + prop + ": " + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media[prop] + "<br />"; // Some are strings
+ }
+ jPlayerInfo += "};</code></p>"
+
+ jPlayerInfo += "<p>";
+ jPlayerInfo += "<code>status.videoWidth = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoWidth + "'</code>";
+ jPlayerInfo += " | <code>status.videoHeight = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoHeight + "'</code>";
+ jPlayerInfo += "<br /><code>status.width = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.width + "'</code>";
+ jPlayerInfo += " | <code>status.height = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.height + "'</code>";
+ jPlayerInfo += "</p>";
+
+ + "<p>Raw browser test for HTML5 support. Should equal a function if HTML5 is available.<br />";
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.audio.available) {
+ jPlayerInfo += "<code>htmlElement.audio.canPlayType = " + (typeof $(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.audio.canPlayType) +"</code><br />"
+ }
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.video.available) {
+ jPlayerInfo += "<code>htmlElement.video.canPlayType = " + (typeof $(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.video.canPlayType) +"</code>";
+ }
+ jPlayerInfo += "</p>";
+
+ jPlayerInfo += "<p>This instance is using the constructor options:<br />"
+ + "<code>$('#" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").internal.self.id + "').jPlayer({<br />"
+
+ + "&nbsp;swfPath: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "swfPath") + "',<br />"
+
+ + "&nbsp;solution: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "solution") + "',<br />"
+
+ + "&nbsp;supplied: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "supplied") + "',<br />"
+
+ + "&nbsp;preload: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "preload") + "',<br />"
+
+ + "&nbsp;volume: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "volume") + ",<br />"
+
+ + "&nbsp;muted: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "muted") + ",<br />"
+
+ + "&nbsp;backgroundColor: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "backgroundColor") + "',<br />"
+
+ + "&nbsp;cssSelectorAncestor: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelectorAncestor") + "',<br />"
+
+ + "&nbsp;cssSelector: {";
+
+ var cssSelector = $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelector");
+ for(prop in cssSelector) {
+
+ // jPlayerInfo += "<br />&nbsp;&nbsp;" + prop + ": '" + cssSelector[prop] + "'," // This works too of course, but want to use option method for deep keys.
+ jPlayerInfo += "<br />&nbsp;&nbsp;" + prop + ": '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelector." + prop) + "',"
+ }
+
+ jPlayerInfo = jPlayerInfo.slice(0, -1); // Because the sloppy comma was bugging me.
+
+ jPlayerInfo += "<br />&nbsp;},<br />"
+
+ + "&nbsp;errorAlerts: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "errorAlerts") + ",<br />"
+
+ + "&nbsp;warningAlerts: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "warningAlerts") + "<br />"
+
+ + "});</code></p>";
+ $(this).data("jPlayerInspector").configJq.html(jPlayerInfo);
+ return this;
+ },
+ updateStatus: function() { // This displays information about jPlayer's status in the inspector
+ $(this).data("jPlayerInspector").statusJq.html(
+ "<p>jPlayer is " +
+ ($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.paused ? "paused" : "playing") +
+ " at time: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentTime*10)/10 + "s." +
+ " (d: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.duration*10)/10 + "s" +
+ ", sp: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.seekPercent) + "%" +
+ ", cpr: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentRelative) + "%" +
+ ", cpa: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentAbsolute) + "%)</p>"
+ );
+ return this;
+ }
+ };
+ $.fn.jPlayerInspector = function( method ) {
+ // Method calling logic
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.jPlayerInspector' );
+ }
+ };
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.min.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.min.js
new file mode 100644
index 00000000..69925c84
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.min.js
@@ -0,0 +1,2 @@
+/*! jPlayerInspector for jPlayer 2.9.2 ~ (c) 2009-2014 Happyworm Ltd ~ MIT License */
+!function(a,b){a.jPlayerInspector={},a.jPlayerInspector.i=0,a.jPlayerInspector.defaults={jPlayer:b,idPrefix:"jplayer_inspector_",visible:!1};var c={init:function(b){var c=a(this),d=a.extend({},a.jPlayerInspector.defaults,b);a(this).data("jPlayerInspector",d),d.id=a(this).attr("id"),d.jPlayerId=d.jPlayer.attr("id"),d.windowId=d.idPrefix+"window_"+a.jPlayerInspector.i,d.statusId=d.idPrefix+"status_"+a.jPlayerInspector.i,d.configId=d.idPrefix+"config_"+a.jPlayerInspector.i,d.toggleId=d.idPrefix+"toggle_"+a.jPlayerInspector.i,d.eventResetId=d.idPrefix+"event_reset_"+a.jPlayerInspector.i,d.updateId=d.idPrefix+"update_"+a.jPlayerInspector.i,d.eventWindowId=d.idPrefix+"event_window_"+a.jPlayerInspector.i,d.eventId={},d.eventJq={},d.eventTimeout={},d.eventOccurrence={},a.each(a.jPlayer.event,function(b,c){d.eventId[c]=d.idPrefix+"event_"+b+"_"+a.jPlayerInspector.i,d.eventOccurrence[c]=0});var e='<p><a href="#" id="'+d.toggleId+'">'+(d.visible?"Hide":"Show")+'</a> jPlayer Inspector</p><div id="'+d.windowId+'"><div id="'+d.statusId+'"></div><div id="'+d.eventWindowId+'" style="padding:5px 5px 0 5px;background-color:#eee;border:1px dotted #000;"><p style="margin:0 0 10px 0;"><strong>jPlayer events that have occurred over the past 1 second:</strong><br />(Backgrounds: <span style="padding:0 5px;background-color:#eee;border:1px dotted #000;">Never occurred</span> <span style="padding:0 5px;background-color:#fff;border:1px dotted #000;">Occurred before</span> <span style="padding:0 5px;background-color:#9f9;border:1px dotted #000;">Occurred</span> <span style="padding:0 5px;background-color:#ff9;border:1px dotted #000;">Multiple occurrences</span> <a href="#" id="'+d.eventResetId+'">reset</a>)</p>',f="float:left;margin:0 5px 5px 0;padding:0 5px;border:1px dotted #000;";return e+='<div id="'+d.eventId[a.jPlayer.event.ready]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.setmedia]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.flashreset]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.resize]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.repeat]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.click]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.warning]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.loadstart]+'" style="clear:left;'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.progress]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.timeupdate]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.volumechange]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.error]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.play]+'" style="clear:left;'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.pause]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.waiting]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.playing]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.seeking]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.seeked]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.ended]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.loadeddata]+'" style="clear:left;'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.loadedmetadata]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.canplay]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.canplaythrough]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.suspend]+'" style="clear:left;'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.abort]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.emptied]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.stalled]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.ratechange]+'" style="'+f+'"></div><div id="'+d.eventId[a.jPlayer.event.durationchange]+'" style="'+f+'"></div><div style="clear:both"></div>',e+='</div><p><a href="#" id="'+d.updateId+'">Update</a> jPlayer Inspector</p><div id="'+d.configId+'"></div></div>',a(this).html(e),d.windowJq=a("#"+d.windowId),d.statusJq=a("#"+d.statusId),d.configJq=a("#"+d.configId),d.toggleJq=a("#"+d.toggleId),d.eventResetJq=a("#"+d.eventResetId),d.updateJq=a("#"+d.updateId),a.each(a.jPlayer.event,function(b,e){d.eventJq[e]=a("#"+d.eventId[e]),d.eventJq[e].text(b+" ("+d.eventOccurrence[e]+")"),d.jPlayer.bind(e+".jPlayerInspector",function(a){d.eventOccurrence[a.type]++,d.eventOccurrence[a.type]>1?d.eventJq[a.type].css("background-color","#ff9"):d.eventJq[a.type].css("background-color","#9f9"),d.eventJq[a.type].text(b+" ("+d.eventOccurrence[a.type]+")"),clearTimeout(d.eventTimeout[a.type]),d.eventTimeout[a.type]=setTimeout(function(){d.eventJq[a.type].css("background-color","#fff")},1e3),setTimeout(function(){d.eventOccurrence[a.type]--,d.eventJq[a.type].text(b+" ("+d.eventOccurrence[a.type]+")")},1e3),d.visible&&c.jPlayerInspector("updateStatus")})}),d.jPlayer.bind(a.jPlayer.event.ready+".jPlayerInspector",function(){c.jPlayerInspector("updateConfig")}),d.toggleJq.click(function(){return d.visible?(a(this).text("Show"),d.windowJq.hide(),d.statusJq.empty(),d.configJq.empty()):(a(this).text("Hide"),d.windowJq.show(),d.updateJq.click()),d.visible=!d.visible,a(this).blur(),!1}),d.eventResetJq.click(function(){return a.each(a.jPlayer.event,function(a,b){d.eventJq[b].css("background-color","#eee")}),a(this).blur(),!1}),d.updateJq.click(function(){return c.jPlayerInspector("updateStatus"),c.jPlayerInspector("updateConfig"),!1}),d.visible||d.windowJq.hide(),a.jPlayerInspector.i++,this},destroy:function(){a(this).data("jPlayerInspector")&&a(this).data("jPlayerInspector").jPlayer.unbind(".jPlayerInspector"),a(this).empty()},updateConfig:function(){var b="<p>This jPlayer instance is running in your browser where:<br />";for(i=0;i<a(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions.length;i++){var c=a(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions[i];if(b+="&nbsp;jPlayer's <strong>"+c+"</strong> solution is",a(this).data("jPlayerInspector").jPlayer.data("jPlayer")[c].used){b+=" being <strong>used</strong> and will support:<strong>";for(format in a(this).data("jPlayerInspector").jPlayer.data("jPlayer")[c].support)a(this).data("jPlayerInspector").jPlayer.data("jPlayer")[c].support[format]&&(b+=" "+format);b+="</strong><br />"}else b+=" <strong>not required</strong><br />"}b+="</p>",b+=a(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.active?a(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active?"<strong>Problem with jPlayer since both HTML5 and Flash are active.</strong>":"The <strong>HTML5 is active</strong>.":a(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active?"The <strong>Flash is active</strong>.":"No solution is currently active. jPlayer needs a setMedia().",b+="</p>";var d=a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.formatType;b+="<p><code>status.formatType = '"+d+"'</code><br />",b+=d?"<code>Browser canPlay('"+a.jPlayer.prototype.format[d].codec+"')</code>":"</p>",b+="<p><code>status.src = '"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.src+"'</code></p>",b+="<p><code>status.media = {<br />";for(prop in a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media)b+="&nbsp;"+prop+": "+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media[prop]+"<br />";b+="};</code></p>",b+="<p>",b+="<code>status.videoWidth = '"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoWidth+"'</code>",b+=" | <code>status.videoHeight = '"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoHeight+"'</code>",b+="<br /><code>status.width = '"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.width+"'</code>",b+=" | <code>status.height = '"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.height+"'</code>",b+="</p>",a(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.audio.available&&(b+="<code>htmlElement.audio.canPlayType = "+typeof a(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.audio.canPlayType+"</code><br />"),a(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.video.available&&(b+="<code>htmlElement.video.canPlayType = "+typeof a(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.video.canPlayType+"</code>"),b+="</p>",b+="<p>This instance is using the constructor options:<br /><code>$('#"+a(this).data("jPlayerInspector").jPlayer.data("jPlayer").internal.self.id+"').jPlayer({<br />&nbsp;swfPath: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","swfPath")+"',<br />&nbsp;solution: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","solution")+"',<br />&nbsp;supplied: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","supplied")+"',<br />&nbsp;preload: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","preload")+"',<br />&nbsp;volume: "+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","volume")+",<br />&nbsp;muted: "+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","muted")+",<br />&nbsp;backgroundColor: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","backgroundColor")+"',<br />&nbsp;cssSelectorAncestor: '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","cssSelectorAncestor")+"',<br />&nbsp;cssSelector: {";var e=a(this).data("jPlayerInspector").jPlayer.jPlayer("option","cssSelector");for(prop in e)b+="<br />&nbsp;&nbsp;"+prop+": '"+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","cssSelector."+prop)+"',";return b=b.slice(0,-1),b+="<br />&nbsp;},<br />&nbsp;errorAlerts: "+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","errorAlerts")+",<br />&nbsp;warningAlerts: "+a(this).data("jPlayerInspector").jPlayer.jPlayer("option","warningAlerts")+"<br />});</code></p>",a(this).data("jPlayerInspector").configJq.html(b),this},updateStatus:function(){return a(this).data("jPlayerInspector").statusJq.html("<p>jPlayer is "+(a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.paused?"paused":"playing")+" at time: "+Math.floor(10*a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentTime)/10+"s. (d: "+Math.floor(10*a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.duration)/10+"s, sp: "+Math.floor(a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.seekPercent)+"%, cpr: "+Math.floor(a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentRelative)+"%, cpa: "+Math.floor(a(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentAbsolute)+"%)</p>"),this}};a.fn.jPlayerInspector=function(b){return c[b]?c[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.jPlayerInspector"):c.init.apply(this,arguments)}}(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.js
new file mode 100644
index 00000000..842f31b6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.js
@@ -0,0 +1,3506 @@
+/*
+ * jPlayer Plugin for jQuery JavaScript Library
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2014 Happyworm Ltd
+ * Licensed under the MIT license.
+ * http://opensource.org/licenses/MIT
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.9.2
+ * Date: 14th December 2014
+ */
+
+/* Support for Zepto 1.0 compiled with optional data module.
+ * For AMD or NODE/CommonJS support, you will need to manually switch the related 2 lines in the code below.
+ * Search terms: "jQuery Switch" and "Zepto Switch"
+ */
+
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory); // jQuery Switch
+ // define(['zepto'], factory); // Zepto Switch
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS
+ factory(require('jquery')); // jQuery Switch
+ //factory(require('zepto')); // Zepto Switch
+ } else {
+ // Browser globals
+ if(root.jQuery) { // Use jQuery if available
+ factory(root.jQuery);
+ } else { // Otherwise, use Zepto
+ factory(root.Zepto);
+ }
+ }
+}(this, function ($, undefined) {
+
+ // Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge - Tweaked $.data(this,XYZ) to $(this).data(XYZ) for Zepto
+ $.fn.jPlayer = function( options ) {
+ var name = "jPlayer";
+ var isMethodCall = typeof options === "string",
+ args = Array.prototype.slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.extend.apply( null, [ true, options ].concat(args) ) :
+ options;
+
+ // prevent calls to internal methods
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+ return returnValue;
+ }
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var instance = $(this).data( name ),
+ methodValue = instance && $.isFunction( instance[options] ) ?
+ instance[ options ].apply( instance, args ) :
+ instance;
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $(this).data( name );
+ if ( instance ) {
+ // instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface.
+ instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm.
+ } else {
+ $(this).data( name, new $.jPlayer( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+
+ $.jPlayer = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this.element = $(element);
+ this.options = $.extend(true, {},
+ this.options,
+ options
+ );
+ var self = this;
+ this.element.bind( "remove.jPlayer", function() {
+ self.destroy();
+ });
+ this._init();
+ }
+ };
+ // End of: (Adapted from jquery.ui.widget.js (1.8.7))
+
+ // Zepto is missing one of the animation methods.
+ if(typeof $.fn.stop !== 'function') {
+ $.fn.stop = function() {};
+ }
+
+ // Emulated HTML5 methods and properties
+ $.jPlayer.emulateMethods = "load play pause";
+ $.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate";
+ $.jPlayer.emulateOptions = "muted volume";
+
+ // Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec
+ $.jPlayer.reservedEvent = "ready flashreset resize repeat error warning";
+
+ // Events generated by jPlayer
+ $.jPlayer.event = {};
+ $.each(
+ [
+ 'ready',
+ 'setmedia', // Fires when the media is set
+ 'flashreset', // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature.
+ 'resize', // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed.
+ 'repeat', // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface.
+ 'click', // Occurs when the user clicks on one of the following: poster image, html video, flash video.
+ 'error', // Event error code in event.jPlayer.error.type. See $.jPlayer.error
+ 'warning', // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning
+
+ // Other events match HTML5 spec.
+ 'loadstart',
+ 'progress',
+ 'suspend',
+ 'abort',
+ 'emptied',
+ 'stalled',
+ 'play',
+ 'pause',
+ 'loadedmetadata',
+ 'loadeddata',
+ 'waiting',
+ 'playing',
+ 'canplay',
+ 'canplaythrough',
+ 'seeking',
+ 'seeked',
+ 'timeupdate',
+ 'ended',
+ 'ratechange',
+ 'durationchange',
+ 'volumechange'
+ ],
+ function() {
+ $.jPlayer.event[ this ] = 'jPlayer_' + this;
+ }
+ );
+
+ $.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action.
+ "loadstart",
+ // "progress", // jPlayer uses internally before bubbling.
+ // "suspend", // jPlayer uses internally before bubbling.
+ "abort",
+ // "error", // jPlayer uses internally before bubbling.
+ "emptied",
+ "stalled",
+ // "play", // jPlayer uses internally before bubbling.
+ // "pause", // jPlayer uses internally before bubbling.
+ "loadedmetadata",
+ // "loadeddata", // jPlayer uses internally before bubbling.
+ // "waiting", // jPlayer uses internally before bubbling.
+ // "playing", // jPlayer uses internally before bubbling.
+ "canplay",
+ "canplaythrough"
+ // "seeking", // jPlayer uses internally before bubbling.
+ // "seeked", // jPlayer uses internally before bubbling.
+ // "timeupdate", // jPlayer uses internally before bubbling.
+ // "ended", // jPlayer uses internally before bubbling.
+ // "ratechange" // jPlayer uses internally before bubbling.
+ // "durationchange" // jPlayer uses internally before bubbling.
+ // "volumechange" // jPlayer uses internally before bubbling.
+ ];
+
+ $.jPlayer.pause = function() {
+ $.jPlayer.prototype.destroyRemoved();
+ $.each($.jPlayer.prototype.instances, function(i, element) {
+ if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
+ element.jPlayer("pause");
+ }
+ });
+ };
+
+ // Default for jPlayer option.timeFormat
+ $.jPlayer.timeFormat = {
+ showHour: false,
+ showMin: true,
+ showSec: true,
+ padHour: false,
+ padMin: true,
+ padSec: true,
+ sepHour: ":",
+ sepMin: ":",
+ sepSec: ""
+ };
+ var ConvertTime = function() {
+ this.init();
+ };
+ ConvertTime.prototype = {
+ init: function() {
+ this.options = {
+ timeFormat: $.jPlayer.timeFormat
+ };
+ },
+ time: function(s) { // function used on jPlayer.prototype._convertTime to enable per instance options.
+ s = (s && typeof s === 'number') ? s : 0;
+
+ var myTime = new Date(s * 1000),
+ hour = myTime.getUTCHours(),
+ min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60,
+ sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60,
+ strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour,
+ strMin = (this.options.timeFormat.padMin && min < 10) ? "0" + min : min,
+ strSec = (this.options.timeFormat.padSec && sec < 10) ? "0" + sec : sec,
+ strTime = "";
+
+ strTime += this.options.timeFormat.showHour ? strHour + this.options.timeFormat.sepHour : "";
+ strTime += this.options.timeFormat.showMin ? strMin + this.options.timeFormat.sepMin : "";
+ strTime += this.options.timeFormat.showSec ? strSec + this.options.timeFormat.sepSec : "";
+
+ return strTime;
+ }
+ };
+ var myConvertTime = new ConvertTime();
+ $.jPlayer.convertTime = function(s) {
+ return myConvertTime.time(s);
+ };
+
+ // Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit.
+ $.jPlayer.uaBrowser = function( userAgent ) {
+ var ua = userAgent.toLowerCase();
+
+ // Useragent RegExp
+ var rwebkit = /(webkit)[ \/]([\w.]+)/;
+ var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
+ var rmsie = /(msie) ([\w.]+)/;
+ var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
+
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ };
+
+ // Platform sniffer for detecting mobile devices
+ $.jPlayer.uaPlatform = function( userAgent ) {
+ var ua = userAgent.toLowerCase();
+
+ // Useragent RegExp
+ var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/;
+ var rtablet = /(ipad|playbook)/;
+ var randroid = /(android)/;
+ var rmobile = /(mobile)/;
+
+ var platform = rplatform.exec( ua ) || [];
+ var tablet = rtablet.exec( ua ) ||
+ !rmobile.exec( ua ) && randroid.exec( ua ) ||
+ [];
+
+ if(platform[1]) {
+ platform[1] = platform[1].replace(/\s/g, "_"); // Change whitespace to underscore. Enables dot notation.
+ }
+
+ return { platform: platform[1] || "", tablet: tablet[1] || "" };
+ };
+
+ $.jPlayer.browser = {
+ };
+ $.jPlayer.platform = {
+ };
+
+ var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent);
+ if ( browserMatch.browser ) {
+ $.jPlayer.browser[ browserMatch.browser ] = true;
+ $.jPlayer.browser.version = browserMatch.version;
+ }
+ var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent);
+ if ( platformMatch.platform ) {
+ $.jPlayer.platform[ platformMatch.platform ] = true;
+ $.jPlayer.platform.mobile = !platformMatch.tablet;
+ $.jPlayer.platform.tablet = !!platformMatch.tablet;
+ }
+
+ // Internet Explorer (IE) Browser Document Mode Sniffer. Based on code at:
+ // http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx#GetMode
+ $.jPlayer.getDocMode = function() {
+ var docMode;
+ if ($.jPlayer.browser.msie) {
+ if (document.documentMode) { // IE8 or later
+ docMode = document.documentMode;
+ } else { // IE 5-7
+ docMode = 5; // Assume quirks mode unless proven otherwise
+ if (document.compatMode) {
+ if (document.compatMode === "CSS1Compat") {
+ docMode = 7; // standards mode
+ }
+ }
+ }
+ }
+ return docMode;
+ };
+ $.jPlayer.browser.documentMode = $.jPlayer.getDocMode();
+
+ $.jPlayer.nativeFeatures = {
+ init: function() {
+
+ /* Fullscreen function naming influenced by W3C naming.
+ * No support for: Mozilla Proposal: https://wiki.mozilla.org/Gecko:FullScreenAPI
+ */
+
+ var d = document,
+ v = d.createElement('video'),
+ spec = {
+ // http://www.w3.org/TR/fullscreen/
+ w3c: [
+ 'fullscreenEnabled',
+ 'fullscreenElement',
+ 'requestFullscreen',
+ 'exitFullscreen',
+ 'fullscreenchange',
+ 'fullscreenerror'
+ ],
+ // https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
+ moz: [
+ 'mozFullScreenEnabled',
+ 'mozFullScreenElement',
+ 'mozRequestFullScreen',
+ 'mozCancelFullScreen',
+ 'mozfullscreenchange',
+ 'mozfullscreenerror'
+ ],
+ // http://developer.apple.com/library/safari/#documentation/WebKit/Reference/ElementClassRef/Element/Element.html
+ // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
+ webkit: [
+ '',
+ 'webkitCurrentFullScreenElement',
+ 'webkitRequestFullScreen',
+ 'webkitCancelFullScreen',
+ 'webkitfullscreenchange',
+ ''
+ ],
+ // http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
+ // https://developer.apple.com/library/safari/samplecode/HTML5VideoEventFlow/Listings/events_js.html#//apple_ref/doc/uid/DTS40010085-events_js-DontLinkElementID_5
+ // Events: 'webkitbeginfullscreen' and 'webkitendfullscreen'
+ webkitVideo: [
+ 'webkitSupportsFullscreen',
+ 'webkitDisplayingFullscreen',
+ 'webkitEnterFullscreen',
+ 'webkitExitFullscreen',
+ '',
+ ''
+ ],
+ ms: [
+ '',
+ 'msFullscreenElement',
+ 'msRequestFullscreen',
+ 'msExitFullscreen',
+ 'MSFullscreenChange',
+ 'MSFullscreenError'
+ ]
+ },
+ specOrder = [
+ 'w3c',
+ 'moz',
+ 'webkit',
+ 'webkitVideo',
+ 'ms'
+ ],
+ fs, i, il;
+
+ this.fullscreen = fs = {
+ support: {
+ w3c: !!d[spec.w3c[0]],
+ moz: !!d[spec.moz[0]],
+ webkit: typeof d[spec.webkit[3]] === 'function',
+ webkitVideo: typeof v[spec.webkitVideo[2]] === 'function',
+ ms: typeof v[spec.ms[2]] === 'function'
+ },
+ used: {}
+ };
+
+ // Store the name of the spec being used and as a handy boolean.
+ for(i = 0, il = specOrder.length; i < il; i++) {
+ var n = specOrder[i];
+ if(fs.support[n]) {
+ fs.spec = n;
+ fs.used[n] = true;
+ break;
+ }
+ }
+
+ if(fs.spec) {
+ var s = spec[fs.spec];
+ fs.api = {
+ fullscreenEnabled: true,
+ fullscreenElement: function(elem) {
+ elem = elem ? elem : d; // Video element required for webkitVideo
+ return elem[s[1]];
+ },
+ requestFullscreen: function(elem) {
+ return elem[s[2]](); // Chrome and Opera want parameter (Element.ALLOW_KEYBOARD_INPUT) but Safari fails if flag used.
+ },
+ exitFullscreen: function(elem) {
+ elem = elem ? elem : d; // Video element required for webkitVideo
+ return elem[s[3]]();
+ }
+ };
+ fs.event = {
+ fullscreenchange: s[4],
+ fullscreenerror: s[5]
+ };
+ } else {
+ fs.api = {
+ fullscreenEnabled: false,
+ fullscreenElement: function() {
+ return null;
+ },
+ requestFullscreen: function() {},
+ exitFullscreen: function() {}
+ };
+ fs.event = {};
+ }
+ }
+ };
+ $.jPlayer.nativeFeatures.init();
+
+ // The keyboard control system.
+
+ // The current jPlayer instance in focus.
+ $.jPlayer.focus = null;
+
+ // The list of element node names to ignore with key controls.
+ $.jPlayer.keyIgnoreElementNames = "A INPUT TEXTAREA SELECT BUTTON";
+
+ // The function that deals with key presses.
+ var keyBindings = function(event) {
+ var f = $.jPlayer.focus,
+ ignoreKey;
+
+ // A jPlayer instance must be in focus. ie., keyEnabled and the last one played.
+ if(f) {
+ // What generated the key press?
+ $.each( $.jPlayer.keyIgnoreElementNames.split(/\s+/g), function(i, name) {
+ // The strings should already be uppercase.
+ if(event.target.nodeName.toUpperCase() === name.toUpperCase()) {
+ ignoreKey = true;
+ return false; // exit each.
+ }
+ });
+ if(!ignoreKey) {
+ // See if the key pressed matches any of the bindings.
+ $.each(f.options.keyBindings, function(action, binding) {
+ // The binding could be a null when the default has been disabled. ie., 1st clause in if()
+ if(
+ (binding && $.isFunction(binding.fn)) &&
+ ((typeof binding.key === 'number' && event.which === binding.key) ||
+ (typeof binding.key === 'string' && event.key === binding.key))
+ ) {
+ event.preventDefault(); // Key being used by jPlayer, so prevent default operation.
+ binding.fn(f);
+ return false; // exit each.
+ }
+ });
+ }
+ }
+ };
+
+ $.jPlayer.keys = function(en) {
+ var event = "keydown.jPlayer";
+ // Remove any binding, just in case enabled more than once.
+ $(document.documentElement).unbind(event);
+ if(en) {
+ $(document.documentElement).bind(event, keyBindings);
+ }
+ };
+
+ // Enable the global key control handler ready for any jPlayer instance with the keyEnabled option enabled.
+ $.jPlayer.keys(true);
+
+ $.jPlayer.prototype = {
+ count: 0, // Static Variable: Change it via prototype.
+ version: { // Static Object
+ script: "2.9.2",
+ needFlash: "2.9.0",
+ flash: "unknown"
+ },
+ options: { // Instanced in $.jPlayer() constructor
+ swfPath: "js", // Path to jquery.jplayer.swf. Can be relative, absolute or server root relative.
+ solution: "html, flash", // Valid solutions: html, flash, aurora. Order defines priority. 1st is highest,
+ supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest,
+ auroraFormats: "wav", // List the aurora.js codecs being loaded externally. Its core supports "wav". Specify format in jPlayer context. EG., The aac.js codec gives the "m4a" format.
+ preload: 'metadata', // HTML5 Spec values: none, metadata, auto.
+ volume: 0.8, // The volume. Number 0 to 1.
+ muted: false,
+ remainingDuration: false, // When true, the remaining time is shown in the duration GUI element.
+ toggleDuration: false, // When true, clicks on the duration toggle between the duration and remaining display.
+ captureDuration: true, // When true, clicks on the duration are captured and no longer propagate up the DOM.
+ playbackRate: 1,
+ defaultPlaybackRate: 1,
+ minPlaybackRate: 0.5,
+ maxPlaybackRate: 4,
+ wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu.
+ backgroundColor: "#000000", // To define the jPlayer div and Flash background color.
+ cssSelectorAncestor: "#jp_container_1",
+ cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults.
+ videoPlay: ".jp-video-play", // *
+ play: ".jp-play",
+ pause: ".jp-pause",
+ stop: ".jp-stop",
+ seekBar: ".jp-seek-bar",
+ playBar: ".jp-play-bar",
+ mute: ".jp-mute",
+ unmute: ".jp-unmute",
+ volumeBar: ".jp-volume-bar",
+ volumeBarValue: ".jp-volume-bar-value",
+ volumeMax: ".jp-volume-max",
+ playbackRateBar: ".jp-playback-rate-bar",
+ playbackRateBarValue: ".jp-playback-rate-bar-value",
+ currentTime: ".jp-current-time",
+ duration: ".jp-duration",
+ title: ".jp-title",
+ fullScreen: ".jp-full-screen", // *
+ restoreScreen: ".jp-restore-screen", // *
+ repeat: ".jp-repeat",
+ repeatOff: ".jp-repeat-off",
+ gui: ".jp-gui", // The interface used with autohide feature.
+ noSolution: ".jp-no-solution" // For error feedback when jPlayer cannot find a solution.
+ },
+ stateClass: { // Classes added to the cssSelectorAncestor to indicate the state.
+ playing: "jp-state-playing",
+ seeking: "jp-state-seeking",
+ muted: "jp-state-muted",
+ looped: "jp-state-looped",
+ fullScreen: "jp-state-full-screen",
+ noVolume: "jp-state-no-volume"
+ },
+ useStateClassSkin: false, // A state class skin relies on the state classes to change the visual appearance. The single control toggles the effect, for example: play then pause, mute then unmute.
+ autoBlur: true, // GUI control handlers will drop focus after clicks.
+ smoothPlayBar: false, // Smooths the play bar transitions, which affects clicks and short media with big changes per second.
+ fullScreen: false, // Native Full Screen
+ fullWindow: false,
+ autohide: {
+ restored: false, // Controls the interface autohide feature.
+ full: true, // Controls the interface autohide feature.
+ fadeIn: 200, // Milliseconds. The period of the fadeIn anim.
+ fadeOut: 600, // Milliseconds. The period of the fadeOut anim.
+ hold: 1000 // Milliseconds. The period of the pause before autohide beings.
+ },
+ loop: false,
+ repeat: function(event) { // The default jPlayer repeat event handler
+ if(event.jPlayer.options.loop) {
+ $(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
+ $(this).jPlayer("play");
+ });
+ } else {
+ $(this).unbind(".jPlayerRepeat");
+ }
+ },
+ nativeVideoControls: {
+ // Works well on standard browsers.
+ // Phone and tablet browsers can have problems with the controls disappearing.
+ },
+ noFullWindow: {
+ msie: /msie [0-6]\./,
+ ipad: /ipad.*?os [0-4]\./,
+ iphone: /iphone/,
+ ipod: /ipod/,
+ android_pad: /android [0-3]\.(?!.*?mobile)/,
+ android_phone: /(?=.*android)(?!.*chrome)(?=.*mobile)/,
+ blackberry: /blackberry/,
+ windows_ce: /windows ce/,
+ iemobile: /iemobile/,
+ webos: /webos/
+ },
+ noVolume: {
+ ipad: /ipad/,
+ iphone: /iphone/,
+ ipod: /ipod/,
+ android_pad: /android(?!.*?mobile)/,
+ android_phone: /android.*?mobile/,
+ blackberry: /blackberry/,
+ windows_ce: /windows ce/,
+ iemobile: /iemobile/,
+ webos: /webos/,
+ playbook: /playbook/
+ },
+ timeFormat: {
+ // Specific time format for this instance. The supported options are defined in $.jPlayer.timeFormat
+ // For the undefined options we use the default from $.jPlayer.timeFormat
+ },
+ keyEnabled: false, // Enables keyboard controls.
+ audioFullScreen: false, // Enables keyboard controls to enter full screen with audio media.
+ keyBindings: { // The key control object, defining the key codes and the functions to execute.
+ // The parameter, f = $.jPlayer.focus, will be checked truethy before attempting to call any of these functions.
+ // Properties may be added to this object, in key/fn pairs, to enable other key controls. EG, for the playlist add-on.
+ play: {
+ key: 80, // p
+ fn: function(f) {
+ if(f.status.paused) {
+ f.play();
+ } else {
+ f.pause();
+ }
+ }
+ },
+ fullScreen: {
+ key: 70, // f
+ fn: function(f) {
+ if(f.status.video || f.options.audioFullScreen) {
+ f._setOption("fullScreen", !f.options.fullScreen);
+ }
+ }
+ },
+ muted: {
+ key: 77, // m
+ fn: function(f) {
+ f._muted(!f.options.muted);
+ }
+ },
+ volumeUp: {
+ key: 190, // .
+ fn: function(f) {
+ f.volume(f.options.volume + 0.1);
+ }
+ },
+ volumeDown: {
+ key: 188, // ,
+ fn: function(f) {
+ f.volume(f.options.volume - 0.1);
+ }
+ },
+ loop: {
+ key: 76, // l
+ fn: function(f) {
+ f._loop(!f.options.loop);
+ }
+ }
+ },
+ verticalVolume: false, // Calculate volume from the bottom of the volume bar. Default is from the left. Also volume affects either width or height.
+ verticalPlaybackRate: false,
+ globalVolume: false, // Set to make volume and muted changes affect all jPlayer instances with this option enabled
+ idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \
+ noConflict: "jQuery",
+ emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element.
+ consoleAlerts: true, // Alerts are sent to the console.log() instead of alert().
+ errorAlerts: false,
+ warningAlerts: false
+ },
+ optionsAudio: {
+ size: {
+ width: "0px",
+ height: "0px",
+ cssClass: ""
+ },
+ sizeFull: {
+ width: "0px",
+ height: "0px",
+ cssClass: ""
+ }
+ },
+ optionsVideo: {
+ size: {
+ width: "480px",
+ height: "270px",
+ cssClass: "jp-video-270p"
+ },
+ sizeFull: {
+ width: "100%",
+ height: "100%",
+ cssClass: "jp-video-full"
+ }
+ },
+ instances: {}, // Static Object
+ status: { // Instanced in _init()
+ src: "",
+ media: {},
+ paused: true,
+ format: {},
+ formatType: "",
+ waitForPlay: true, // Same as waitForLoad except in case where preloading.
+ waitForLoad: true,
+ srcSet: false,
+ video: false, // True if playing a video
+ seekPercent: 0,
+ currentPercentRelative: 0,
+ currentPercentAbsolute: 0,
+ currentTime: 0,
+ duration: 0,
+ remaining: 0,
+ videoWidth: 0, // Intrinsic width of the video in pixels.
+ videoHeight: 0, // Intrinsic height of the video in pixels.
+ readyState: 0,
+ networkState: 0,
+ playbackRate: 1, // Warning - Now both an option and a status property
+ ended: 0
+
+/* Persistant status properties created dynamically at _init():
+ width
+ height
+ cssClass
+ nativeVideoControls
+ noFullWindow
+ noVolume
+ playbackRateEnabled // Warning - Technically, we can have both Flash and HTML, so this might not be correct if the Flash is active. That is a niche case.
+*/
+ },
+
+ internal: { // Instanced in _init()
+ ready: false
+ // instance: undefined
+ // domNode: undefined
+ // htmlDlyCmdId: undefined
+ // autohideId: undefined
+ // mouse: undefined
+ // cmdsIgnored
+ },
+ solution: { // Static Object: Defines the solutions built in jPlayer.
+ html: true,
+ aurora: true,
+ flash: true
+ },
+ // 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"')
+ format: { // Static Object
+ mp3: {
+ codec: 'audio/mpeg',
+ flashCanPlay: true,
+ media: 'audio'
+ },
+ m4a: { // AAC / MP4
+ codec: 'audio/mp4; codecs="mp4a.40.2"',
+ flashCanPlay: true,
+ media: 'audio'
+ },
+ m3u8a: { // AAC / MP4 / Apple HLS
+ codec: 'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ m3ua: { // M3U
+ codec: 'audio/mpegurl',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ oga: { // OGG
+ codec: 'audio/ogg; codecs="vorbis, opus"',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ flac: { // FLAC
+ codec: 'audio/x-flac',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ wav: { // PCM
+ codec: 'audio/wav; codecs="1"',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ webma: { // WEBM
+ codec: 'audio/webm; codecs="vorbis"',
+ flashCanPlay: false,
+ media: 'audio'
+ },
+ fla: { // FLV / F4A
+ codec: 'audio/x-flv',
+ flashCanPlay: true,
+ media: 'audio'
+ },
+ rtmpa: { // RTMP AUDIO
+ codec: 'audio/rtmp; codecs="rtmp"',
+ flashCanPlay: true,
+ media: 'audio'
+ },
+ m4v: { // H.264 / MP4
+ codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ flashCanPlay: true,
+ media: 'video'
+ },
+ m3u8v: { // H.264 / AAC / MP4 / Apple HLS
+ codec: 'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',
+ flashCanPlay: false,
+ media: 'video'
+ },
+ m3uv: { // M3U
+ codec: 'audio/mpegurl',
+ flashCanPlay: false,
+ media: 'video'
+ },
+ ogv: { // OGG
+ codec: 'video/ogg; codecs="theora, vorbis"',
+ flashCanPlay: false,
+ media: 'video'
+ },
+ webmv: { // WEBM
+ codec: 'video/webm; codecs="vorbis, vp8"',
+ flashCanPlay: false,
+ media: 'video'
+ },
+ flv: { // FLV / F4V
+ codec: 'video/x-flv',
+ flashCanPlay: true,
+ media: 'video'
+ },
+ rtmpv: { // RTMP VIDEO
+ codec: 'video/rtmp; codecs="rtmp"',
+ flashCanPlay: true,
+ media: 'video'
+ }
+ },
+ _init: function() {
+ var self = this;
+
+ this.element.empty();
+
+ this.status = $.extend({}, this.status); // Copy static to unique instance.
+ this.internal = $.extend({}, this.internal); // Copy static to unique instance.
+
+ // Initialize the time format
+ this.options.timeFormat = $.extend({}, $.jPlayer.timeFormat, this.options.timeFormat);
+
+ // On iOS, assume commands will be ignored before user initiates them.
+ this.internal.cmdsIgnored = $.jPlayer.platform.ipad || $.jPlayer.platform.iphone || $.jPlayer.platform.ipod;
+
+ this.internal.domNode = this.element.get(0);
+
+ // Add key bindings focus to 1st jPlayer instanced with key control enabled.
+ if(this.options.keyEnabled && !$.jPlayer.focus) {
+ $.jPlayer.focus = this;
+ }
+
+ // A fix for Android where older (2.3) and even some 4.x devices fail to work when changing the *audio* SRC and then playing immediately.
+ this.androidFix = {
+ setMedia: false, // True when media set
+ play: false, // True when a progress event will instruct the media to play
+ pause: false, // True when a progress event will instruct the media to pause at a time.
+ time: NaN // The play(time) parameter
+ };
+ if($.jPlayer.platform.android) {
+ this.options.preload = this.options.preload !== 'auto' ? 'metadata' : 'auto'; // Default to metadata, but allow auto.
+ }
+
+ this.formats = []; // Array based on supplied string option. Order defines priority.
+ this.solutions = []; // Array based on solution string option. Order defines priority.
+ this.require = {}; // Which media types are required: video, audio.
+
+ this.htmlElement = {}; // DOM elements created by jPlayer
+ this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
+ this.html.audio = {};
+ this.html.video = {};
+ this.aurora = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
+ this.aurora.formats = [];
+ this.aurora.properties = [];
+ this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
+
+ this.css = {};
+ this.css.cs = {}; // Holds the css selector strings
+ this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method)
+
+ this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+
+
+ this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds.
+
+ // Create the formats array, with prority based on the order of the supplied formats string
+ $.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) {
+ var format = value1.replace(/^\s+|\s+$/g, ""); //trim
+ if(self.format[format]) { // Check format is valid.
+ var dupFound = false;
+ $.each(self.formats, function(index2, value2) { // Check for duplicates
+ if(format === value2) {
+ dupFound = true;
+ return false;
+ }
+ });
+ if(!dupFound) {
+ self.formats.push(format);
+ }
+ }
+ });
+
+ // Create the solutions array, with prority based on the order of the solution string
+ $.each(this.options.solution.toLowerCase().split(","), function(index1, value1) {
+ var solution = value1.replace(/^\s+|\s+$/g, ""); //trim
+ if(self.solution[solution]) { // Check solution is valid.
+ var dupFound = false;
+ $.each(self.solutions, function(index2, value2) { // Check for duplicates
+ if(solution === value2) {
+ dupFound = true;
+ return false;
+ }
+ });
+ if(!dupFound) {
+ self.solutions.push(solution);
+ }
+ }
+ });
+
+ // Create Aurora.js formats array
+ $.each(this.options.auroraFormats.toLowerCase().split(","), function(index1, value1) {
+ var format = value1.replace(/^\s+|\s+$/g, ""); //trim
+ if(self.format[format]) { // Check format is valid.
+ var dupFound = false;
+ $.each(self.aurora.formats, function(index2, value2) { // Check for duplicates
+ if(format === value2) {
+ dupFound = true;
+ return false;
+ }
+ });
+ if(!dupFound) {
+ self.aurora.formats.push(format);
+ }
+ }
+ });
+
+ this.internal.instance = "jp_" + this.count;
+ this.instances[this.internal.instance] = this.element;
+
+ // Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms.
+ if(!this.element.attr("id")) {
+ this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count);
+ }
+
+ this.internal.self = $.extend({}, {
+ id: this.element.attr("id"),
+ jq: this.element
+ });
+ this.internal.audio = $.extend({}, {
+ id: this.options.idPrefix + "_audio_" + this.count,
+ jq: undefined
+ });
+ this.internal.video = $.extend({}, {
+ id: this.options.idPrefix + "_video_" + this.count,
+ jq: undefined
+ });
+ this.internal.flash = $.extend({}, {
+ id: this.options.idPrefix + "_flash_" + this.count,
+ jq: undefined,
+ swf: this.options.swfPath + (this.options.swfPath.toLowerCase().slice(-4) !== ".swf" ? (this.options.swfPath && this.options.swfPath.slice(-1) !== "/" ? "/" : "") + "jquery.jplayer.swf" : "")
+ });
+ this.internal.poster = $.extend({}, {
+ id: this.options.idPrefix + "_poster_" + this.count,
+ jq: undefined
+ });
+
+ // Register listeners defined in the constructor
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ if(self.options[eventName] !== undefined) {
+ self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace.
+ self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading.
+ }
+ });
+
+ // Determine if we require solutions for audio, video or both media types.
+ this.require.audio = false;
+ this.require.video = false;
+ $.each(this.formats, function(priority, format) {
+ self.require[self.format[format].media] = true;
+ });
+
+ // Now required types are known, finish the options default settings.
+ if(this.require.video) {
+ this.options = $.extend(true, {},
+ this.optionsVideo,
+ this.options
+ );
+ } else {
+ this.options = $.extend(true, {},
+ this.optionsAudio,
+ this.options
+ );
+ }
+ this._setSize(); // update status and jPlayer element size
+
+ // Determine the status for Blocklisted options.
+ this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
+ this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
+ this.status.noVolume = this._uaBlocklist(this.options.noVolume);
+
+ // Create event handlers if native fullscreen is supported
+ if($.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled) {
+ this._fullscreenAddEventListeners();
+ }
+
+ // The native controls are only for video and are disabled when audio is also used.
+ this._restrictNativeVideoControls();
+
+ // Create the poster image.
+ this.htmlElement.poster = document.createElement('img');
+ this.htmlElement.poster.id = this.internal.poster.id;
+ this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser.
+ if(!self.status.video || self.status.waitForPlay) {
+ self.internal.poster.jq.show();
+ }
+ };
+ this.element.append(this.htmlElement.poster);
+ this.internal.poster.jq = $("#" + this.internal.poster.id);
+ this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
+ this.internal.poster.jq.hide();
+ this.internal.poster.jq.bind("click.jPlayer", function() {
+ self._trigger($.jPlayer.event.click);
+ });
+
+ // Generate the required media elements
+ this.html.audio.available = false;
+ if(this.require.audio) { // If a supplied format is audio
+ this.htmlElement.audio = document.createElement('audio');
+ this.htmlElement.audio.id = this.internal.audio.id;
+ this.html.audio.available = !!this.htmlElement.audio.canPlayType && this._testCanPlayType(this.htmlElement.audio); // Test is for IE9 on Win Server 2008.
+ }
+ this.html.video.available = false;
+ if(this.require.video) { // If a supplied format is video
+ this.htmlElement.video = document.createElement('video');
+ this.htmlElement.video.id = this.internal.video.id;
+ this.html.video.available = !!this.htmlElement.video.canPlayType && this._testCanPlayType(this.htmlElement.video); // Test is for IE9 on Win Server 2008.
+ }
+
+ this.flash.available = this._checkForFlash(10.1);
+
+ this.html.canPlay = {};
+ this.aurora.canPlay = {};
+ this.flash.canPlay = {};
+ $.each(this.formats, function(priority, format) {
+ self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec);
+ self.aurora.canPlay[format] = ($.inArray(format, self.aurora.formats) > -1);
+ self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available;
+ });
+ this.html.desired = false;
+ this.aurora.desired = false;
+ this.flash.desired = false;
+ $.each(this.solutions, function(solutionPriority, solution) {
+ if(solutionPriority === 0) {
+ self[solution].desired = true;
+ } else {
+ var audioCanPlay = false;
+ var videoCanPlay = false;
+ $.each(self.formats, function(formatPriority, format) {
+ if(self[self.solutions[0]].canPlay[format]) { // The other solution can play
+ if(self.format[format].media === 'video') {
+ videoCanPlay = true;
+ } else {
+ audioCanPlay = true;
+ }
+ }
+ });
+ self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay);
+ }
+ });
+ // This is what jPlayer will support, based on solution and supplied.
+ this.html.support = {};
+ this.aurora.support = {};
+ this.flash.support = {};
+ $.each(this.formats, function(priority, format) {
+ self.html.support[format] = self.html.canPlay[format] && self.html.desired;
+ self.aurora.support[format] = self.aurora.canPlay[format] && self.aurora.desired;
+ self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired;
+ });
+ // If jPlayer is supporting any format in a solution, then the solution is used.
+ this.html.used = false;
+ this.aurora.used = false;
+ this.flash.used = false;
+ $.each(this.solutions, function(solutionPriority, solution) {
+ $.each(self.formats, function(formatPriority, format) {
+ if(self[solution].support[format]) {
+ self[solution].used = true;
+ return false;
+ }
+ });
+ });
+
+ // Init solution active state and the event gates to false.
+ this._resetActive();
+ this._resetGate();
+
+ // Set up the css selectors for the control and feedback entities.
+ this._cssSelectorAncestor(this.options.cssSelectorAncestor);
+
+ // If neither html nor aurora nor flash are being used by this browser, then media playback is not possible. Trigger an error event.
+ if(!(this.html.used || this.aurora.used || this.flash.used)) {
+ this._error( {
+ type: $.jPlayer.error.NO_SOLUTION,
+ context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}",
+ message: $.jPlayer.errorMsg.NO_SOLUTION,
+ hint: $.jPlayer.errorHint.NO_SOLUTION
+ });
+ if(this.css.jq.noSolution.length) {
+ this.css.jq.noSolution.show();
+ }
+ } else {
+ if(this.css.jq.noSolution.length) {
+ this.css.jq.noSolution.hide();
+ }
+ }
+
+ // Add the flash solution if it is being used.
+ if(this.flash.used) {
+ var htmlObj,
+ flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted;
+
+ // Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/
+ // Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event.
+
+ if($.jPlayer.browser.msie && (Number($.jPlayer.browser.version) < 9 || $.jPlayer.browser.documentMode < 9)) {
+ var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>';
+
+ var paramStr = [
+ '<param name="movie" value="' + this.internal.flash.swf + '" />',
+ '<param name="FlashVars" value="' + flashVars + '" />',
+ '<param name="allowScriptAccess" value="always" />',
+ '<param name="bgcolor" value="' + this.options.backgroundColor + '" />',
+ '<param name="wmode" value="' + this.options.wmode + '" />'
+ ];
+
+ htmlObj = document.createElement(objStr);
+ for(var i=0; i < paramStr.length; i++) {
+ htmlObj.appendChild(document.createElement(paramStr[i]));
+ }
+ } else {
+ var createParam = function(el, n, v) {
+ var p = document.createElement("param");
+ p.setAttribute("name", n);
+ p.setAttribute("value", v);
+ el.appendChild(p);
+ };
+
+ htmlObj = document.createElement("object");
+ htmlObj.setAttribute("id", this.internal.flash.id);
+ htmlObj.setAttribute("name", this.internal.flash.id);
+ htmlObj.setAttribute("data", this.internal.flash.swf);
+ htmlObj.setAttribute("type", "application/x-shockwave-flash");
+ htmlObj.setAttribute("width", "1"); // Non-zero
+ htmlObj.setAttribute("height", "1"); // Non-zero
+ htmlObj.setAttribute("tabindex", "-1");
+ createParam(htmlObj, "flashvars", flashVars);
+ createParam(htmlObj, "allowscriptaccess", "always");
+ createParam(htmlObj, "bgcolor", this.options.backgroundColor);
+ createParam(htmlObj, "wmode", this.options.wmode);
+ }
+
+ this.element.append(htmlObj);
+ this.internal.flash.jq = $(htmlObj);
+ }
+
+ // Setup playbackRate ability before using _addHtmlEventListeners()
+ if(this.html.used && !this.flash.used) { // If only HTML
+ // Using the audio element capabilities for playbackRate. ie., Assuming video element is the same.
+ this.status.playbackRateEnabled = this._testPlaybackRate('audio');
+ } else {
+ this.status.playbackRateEnabled = false;
+ }
+
+ this._updatePlaybackRate();
+
+ // Add the HTML solution if being used.
+ if(this.html.used) {
+
+ // The HTML Audio handlers
+ if(this.html.audio.available) {
+ this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio);
+ this.element.append(this.htmlElement.audio);
+ this.internal.audio.jq = $("#" + this.internal.audio.id);
+ }
+
+ // The HTML Video handlers
+ if(this.html.video.available) {
+ this._addHtmlEventListeners(this.htmlElement.video, this.html.video);
+ this.element.append(this.htmlElement.video);
+ this.internal.video.jq = $("#" + this.internal.video.id);
+ if(this.status.nativeVideoControls) {
+ this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
+ } else {
+ this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS
+ }
+ this.internal.video.jq.bind("click.jPlayer", function() {
+ self._trigger($.jPlayer.event.click);
+ });
+ }
+ }
+
+ // Add the Aurora.js solution if being used.
+ if(this.aurora.used) {
+ // Aurora.js player need to be created for each media, see setMedia function.
+ }
+
+ // Create the bridge that emulates the HTML Media element on the jPlayer DIV
+ if( this.options.emulateHtml ) {
+ this._emulateHtmlBridge();
+ }
+
+ if((this.html.used || this.aurora.used) && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms.
+ setTimeout( function() {
+ self.internal.ready = true;
+ self.version.flash = "n/a";
+ self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
+ self._trigger($.jPlayer.event.ready);
+ }, 100);
+ }
+
+ // Initialize the interface components with the options.
+ this._updateNativeVideoControls();
+ // The other controls are now setup in _cssSelectorAncestor()
+ if(this.css.jq.videoPlay.length) {
+ this.css.jq.videoPlay.hide();
+ }
+
+ $.jPlayer.prototype.count++; // Change static variable via prototype.
+ },
+ destroy: function() {
+ // MJP: The background change remains. Would need to store the original to restore it correctly.
+ // MJP: The jPlayer element's size change remains.
+
+ // Clear the media to reset the GUI and stop any downloads. Streams on some browsers had persited. (Chrome)
+ this.clearMedia();
+ // Remove the size/sizeFull cssClass from the cssSelectorAncestor
+ this._removeUiClass();
+ // Remove the times from the GUI
+ if(this.css.jq.currentTime.length) {
+ this.css.jq.currentTime.text("");
+ }
+ if(this.css.jq.duration.length) {
+ this.css.jq.duration.text("");
+ }
+ // Remove any bindings from the interface controls.
+ $.each(this.css.jq, function(fn, jq) {
+ // Check selector is valid before trying to execute method.
+ if(jq.length) {
+ jq.unbind(".jPlayer");
+ }
+ });
+ // Remove the click handlers for $.jPlayer.event.click
+ this.internal.poster.jq.unbind(".jPlayer");
+ if(this.internal.video.jq) {
+ this.internal.video.jq.unbind(".jPlayer");
+ }
+ // Remove the fullscreen event handlers
+ this._fullscreenRemoveEventListeners();
+ // Remove key bindings
+ if(this === $.jPlayer.focus) {
+ $.jPlayer.focus = null;
+ }
+ // Destroy the HTML bridge.
+ if(this.options.emulateHtml) {
+ this._destroyHtmlBridge();
+ }
+ this.element.removeData("jPlayer"); // Remove jPlayer data
+ this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor
+ this.element.empty(); // Remove the inserted child elements
+
+ delete this.instances[this.internal.instance]; // Clear the instance on the static instance object
+ },
+ destroyRemoved: function() { // Destroy any instances that have gone away.
+ var self = this;
+ $.each(this.instances, function(i, element) {
+ if(self.element !== element) { // Do not destroy this instance.
+ if(!element.data("jPlayer")) { // Check that element is a real jPlayer.
+ element.jPlayer("destroy");
+ delete self.instances[i];
+ }
+ }
+ });
+ },
+ enable: function() { // Plan to implement
+ // options.disabled = false
+ },
+ disable: function () { // Plan to implement
+ // options.disabled = true
+ },
+ _testCanPlayType: function(elem) {
+ // IE9 on Win Server 2008 did not implement canPlayType(), but it has the property.
+ try {
+ elem.canPlayType(this.format.mp3.codec); // The type is irrelevant.
+ return true;
+ } catch(err) {
+ return false;
+ }
+ },
+ _testPlaybackRate: function(type) {
+ // type: String 'audio' or 'video'
+ var el, rate = 0.5;
+ type = typeof type === 'string' ? type : 'audio';
+ el = document.createElement(type);
+ // Wrapping in a try/catch, just in case older HTML5 browsers throw and error.
+ try {
+ if('playbackRate' in el) {
+ el.playbackRate = rate;
+ return el.playbackRate === rate;
+ } else {
+ return false;
+ }
+ } catch(err) {
+ return false;
+ }
+ },
+ _uaBlocklist: function(list) {
+ // list : object with properties that are all regular expressions. Property names are irrelevant.
+ // Returns true if the user agent is matched in list.
+ var ua = navigator.userAgent.toLowerCase(),
+ block = false;
+
+ $.each(list, function(p, re) {
+ if(re && re.test(ua)) {
+ block = true;
+ return false; // exit $.each.
+ }
+ });
+ return block;
+ },
+ _restrictNativeVideoControls: function() {
+ // Fallback to noFullWindow when nativeVideoControls is true and audio media is being used. Affects when both media types are used.
+ if(this.require.audio) {
+ if(this.status.nativeVideoControls) {
+ this.status.nativeVideoControls = false;
+ this.status.noFullWindow = true;
+ }
+ }
+ },
+ _updateNativeVideoControls: function() {
+ if(this.html.video.available && this.html.used) {
+ // Turn the HTML Video controls on/off
+ this.htmlElement.video.controls = this.status.nativeVideoControls;
+ // Show/hide the jPlayer GUI.
+ this._updateAutohide();
+ // For when option changed. The poster image is not updated, as it is dealt with in setMedia(). Acceptable degradation since seriously doubt these options will change on the fly. Can again review later.
+ if(this.status.nativeVideoControls && this.require.video) {
+ this.internal.poster.jq.hide();
+ this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
+ } else if(this.status.waitForPlay && this.status.video) {
+ this.internal.poster.jq.show();
+ this.internal.video.jq.css({'width': '0px', 'height': '0px'});
+ }
+ }
+ },
+ _addHtmlEventListeners: function(mediaElement, entity) {
+ var self = this;
+ mediaElement.preload = this.options.preload;
+ mediaElement.muted = this.options.muted;
+ mediaElement.volume = this.options.volume;
+
+ if(this.status.playbackRateEnabled) {
+ mediaElement.defaultPlaybackRate = this.options.defaultPlaybackRate;
+ mediaElement.playbackRate = this.options.playbackRate;
+ }
+
+ // Create the event listeners
+ // Only want the active entity to affect jPlayer and bubble events.
+ // Using entity.gate so that object is referenced and gate property always current
+
+ mediaElement.addEventListener("progress", function() {
+ if(entity.gate) {
+ if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
+ self.internal.cmdsIgnored = false;
+ }
+ self._getHtmlStatus(mediaElement);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.progress);
+ }
+ }, false);
+ mediaElement.addEventListener("loadeddata", function() {
+ if(entity.gate) {
+ self.androidFix.setMedia = false; // Disable the fix after the first progress event.
+ if(self.androidFix.play) { // Play Android audio - performing the fix.
+ self.androidFix.play = false;
+ self.play(self.androidFix.time);
+ }
+ if(self.androidFix.pause) { // Pause Android audio at time - performing the fix.
+ self.androidFix.pause = false;
+ self.pause(self.androidFix.time);
+ }
+ self._trigger($.jPlayer.event.loadeddata);
+ }
+ }, false);
+ mediaElement.addEventListener("timeupdate", function() {
+ if(entity.gate) {
+ self._getHtmlStatus(mediaElement);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.timeupdate);
+ }
+ }, false);
+ mediaElement.addEventListener("durationchange", function() {
+ if(entity.gate) {
+ self._getHtmlStatus(mediaElement);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.durationchange);
+ }
+ }, false);
+ mediaElement.addEventListener("play", function() {
+ if(entity.gate) {
+ self._updateButtons(true);
+ self._html_checkWaitForPlay(); // So the native controls update this variable and puts the hidden interface in the correct state. Affects toggling native controls.
+ self._trigger($.jPlayer.event.play);
+ }
+ }, false);
+ mediaElement.addEventListener("playing", function() {
+ if(entity.gate) {
+ self._updateButtons(true);
+ self._seeked();
+ self._trigger($.jPlayer.event.playing);
+ }
+ }, false);
+ mediaElement.addEventListener("pause", function() {
+ if(entity.gate) {
+ self._updateButtons(false);
+ self._trigger($.jPlayer.event.pause);
+ }
+ }, false);
+ mediaElement.addEventListener("waiting", function() {
+ if(entity.gate) {
+ self._seeking();
+ self._trigger($.jPlayer.event.waiting);
+ }
+ }, false);
+ mediaElement.addEventListener("seeking", function() {
+ if(entity.gate) {
+ self._seeking();
+ self._trigger($.jPlayer.event.seeking);
+ }
+ }, false);
+ mediaElement.addEventListener("seeked", function() {
+ if(entity.gate) {
+ self._seeked();
+ self._trigger($.jPlayer.event.seeked);
+ }
+ }, false);
+ mediaElement.addEventListener("volumechange", function() {
+ if(entity.gate) {
+ // Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control.
+ // However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though.
+ self.options.volume = mediaElement.volume;
+ self.options.muted = mediaElement.muted;
+ self._updateMute();
+ self._updateVolume();
+ self._trigger($.jPlayer.event.volumechange);
+ }
+ }, false);
+ mediaElement.addEventListener("ratechange", function() {
+ if(entity.gate) {
+ self.options.defaultPlaybackRate = mediaElement.defaultPlaybackRate;
+ self.options.playbackRate = mediaElement.playbackRate;
+ self._updatePlaybackRate();
+ self._trigger($.jPlayer.event.ratechange);
+ }
+ }, false);
+ mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture.
+ if(entity.gate) {
+ self._seeked();
+ self._trigger($.jPlayer.event.suspend);
+ }
+ }, false);
+ mediaElement.addEventListener("ended", function() {
+ if(entity.gate) {
+ // Order of the next few commands are important. Change the time and then pause.
+ // Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored.
+ if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo.
+ self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.)
+ }
+ self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback.
+ self._updateButtons(false);
+ self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full.
+ self._updateInterface();
+ self._trigger($.jPlayer.event.ended);
+ }
+ }, false);
+ mediaElement.addEventListener("error", function() {
+ if(entity.gate) {
+ self._updateButtons(false);
+ self._seeked();
+ if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
+ clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
+ self.status.waitForLoad = true; // Allows the load operation to try again.
+ self.status.waitForPlay = true; // Reset since a play was captured.
+ if(self.status.video && !self.status.nativeVideoControls) {
+ self.internal.video.jq.css({'width':'0px', 'height':'0px'});
+ }
+ if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
+ self.internal.poster.jq.show();
+ }
+ if(self.css.jq.videoPlay.length) {
+ self.css.jq.videoPlay.show();
+ }
+ self._error( {
+ type: $.jPlayer.error.URL,
+ context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
+ message: $.jPlayer.errorMsg.URL,
+ hint: $.jPlayer.errorHint.URL
+ });
+ }
+ }
+ }, false);
+ // Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer.
+ $.each($.jPlayer.htmlEvent, function(i, eventType) {
+ mediaElement.addEventListener(this, function() {
+ if(entity.gate) {
+ self._trigger($.jPlayer.event[eventType]);
+ }
+ }, false);
+ });
+ },
+ _addAuroraEventListeners : function(player, entity) {
+ var self = this;
+ //player.preload = this.options.preload;
+ //player.muted = this.options.muted;
+ player.volume = this.options.volume * 100;
+
+ // Create the event listeners
+ // Only want the active entity to affect jPlayer and bubble events.
+ // Using entity.gate so that object is referenced and gate property always current
+
+ player.on("progress", function() {
+ if(entity.gate) {
+ if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
+ self.internal.cmdsIgnored = false;
+ }
+ self._getAuroraStatus(player);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.progress);
+ // Progress with song duration, we estimate timeupdate need to be triggered too.
+ if (player.duration > 0) {
+ self._trigger($.jPlayer.event.timeupdate);
+ }
+ }
+ }, false);
+ player.on("ready", function() {
+ if(entity.gate) {
+ self._trigger($.jPlayer.event.loadeddata);
+ }
+ }, false);
+ player.on("duration", function() {
+ if(entity.gate) {
+ self._getAuroraStatus(player);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.durationchange);
+ }
+ }, false);
+ player.on("end", function() {
+ if(entity.gate) {
+ // Order of the next few commands are important. Change the time and then pause.
+ self._updateButtons(false);
+ self._getAuroraStatus(player, true);
+ self._updateInterface();
+ self._trigger($.jPlayer.event.ended);
+ }
+ }, false);
+ player.on("error", function() {
+ if(entity.gate) {
+ self._updateButtons(false);
+ self._seeked();
+ if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
+ self.status.waitForLoad = true; // Allows the load operation to try again.
+ self.status.waitForPlay = true; // Reset since a play was captured.
+ if(self.status.video && !self.status.nativeVideoControls) {
+ self.internal.video.jq.css({'width':'0px', 'height':'0px'});
+ }
+ if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
+ self.internal.poster.jq.show();
+ }
+ if(self.css.jq.videoPlay.length) {
+ self.css.jq.videoPlay.show();
+ }
+ self._error( {
+ type: $.jPlayer.error.URL,
+ context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
+ message: $.jPlayer.errorMsg.URL,
+ hint: $.jPlayer.errorHint.URL
+ });
+ }
+ }
+ }, false);
+ },
+ _getHtmlStatus: function(media, override) {
+ var ct = 0, cpa = 0, sp = 0, cpr = 0;
+
+ // Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct.
+ // Fixes the initial duration bug in BB OS7, where the media.duration is infinity and displays as NaN:NaN due to Date() using inifity.
+ if(isFinite(media.duration)) {
+ this.status.duration = media.duration;
+ }
+
+ ct = media.currentTime;
+ cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
+ if((typeof media.seekable === "object") && (media.seekable.length > 0)) {
+ sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100;
+ cpr = (this.status.duration > 0) ? 100 * media.currentTime / media.seekable.end(media.seekable.length-1) : 0; // Duration conditional for iOS duration bug. ie., seekable.end is a NaN in that case.
+ } else {
+ sp = 100;
+ cpr = cpa;
+ }
+
+ if(override) {
+ ct = 0;
+ cpr = 0;
+ cpa = 0;
+ }
+
+ this.status.seekPercent = sp;
+ this.status.currentPercentRelative = cpr;
+ this.status.currentPercentAbsolute = cpa;
+ this.status.currentTime = ct;
+
+ this.status.remaining = this.status.duration - this.status.currentTime;
+
+ this.status.videoWidth = media.videoWidth;
+ this.status.videoHeight = media.videoHeight;
+
+ this.status.readyState = media.readyState;
+ this.status.networkState = media.networkState;
+ this.status.playbackRate = media.playbackRate;
+ this.status.ended = media.ended;
+ },
+ _getAuroraStatus: function(player, override) {
+ var ct = 0, cpa = 0, sp = 0, cpr = 0;
+
+ this.status.duration = player.duration / 1000;
+
+ ct = player.currentTime / 1000;
+ cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
+ if(player.buffered > 0) {
+ sp = (this.status.duration > 0) ? (player.buffered * this.status.duration) / this.status.duration : 100;
+ cpr = (this.status.duration > 0) ? ct / (player.buffered * this.status.duration) : 0;
+ } else {
+ sp = 100;
+ cpr = cpa;
+ }
+
+ if(override) {
+ ct = 0;
+ cpr = 0;
+ cpa = 0;
+ }
+
+ this.status.seekPercent = sp;
+ this.status.currentPercentRelative = cpr;
+ this.status.currentPercentAbsolute = cpa;
+ this.status.currentTime = ct;
+
+ this.status.remaining = this.status.duration - this.status.currentTime;
+
+ this.status.readyState = 4; // status.readyState;
+ this.status.networkState = 0; // status.networkState;
+ this.status.playbackRate = 1; // status.playbackRate;
+ this.status.ended = false; // status.ended;
+ },
+ _resetStatus: function() {
+ this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset.
+ },
+ _trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType
+ var event = $.Event(eventType);
+ event.jPlayer = {};
+ event.jPlayer.version = $.extend({}, this.version);
+ event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy
+ event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy
+ event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy
+ event.jPlayer.aurora = $.extend(true, {}, this.aurora); // Deep copy
+ event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy
+ if(error) {
+ event.jPlayer.error = $.extend({}, error);
+ }
+ if(warning) {
+ event.jPlayer.warning = $.extend({}, warning);
+ }
+ this.element.trigger(event);
+ },
+ jPlayerFlashEvent: function(eventType, status) { // Called from Flash
+ if(eventType === $.jPlayer.event.ready) {
+ if(!this.internal.ready) {
+ this.internal.ready = true;
+ this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore.
+
+ this.version.flash = status.version;
+ if(this.version.needFlash !== this.version.flash) {
+ this._error( {
+ type: $.jPlayer.error.VERSION,
+ context: this.version.flash,
+ message: $.jPlayer.errorMsg.VERSION + this.version.flash,
+ hint: $.jPlayer.errorHint.VERSION
+ });
+ }
+ this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
+ this._trigger(eventType);
+ } else {
+ // This condition occurs if the Flash is hidden and then shown again.
+ // Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen.
+
+ // Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used.
+ if(this.flash.gate) {
+
+ // Send the current status to the Flash now that it is ready (available) again.
+ if(this.status.srcSet) {
+
+ // Need to read original status before issuing the setMedia command.
+ var currentTime = this.status.currentTime,
+ paused = this.status.paused;
+
+ this.setMedia(this.status.media);
+ this.volumeWorker(this.options.volume);
+ if(currentTime > 0) {
+ if(paused) {
+ this.pause(currentTime);
+ } else {
+ this.play(currentTime);
+ }
+ }
+ }
+ this._trigger($.jPlayer.event.flashreset);
+ }
+ }
+ }
+ if(this.flash.gate) {
+ switch(eventType) {
+ case $.jPlayer.event.progress:
+ this._getFlashStatus(status);
+ this._updateInterface();
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.timeupdate:
+ this._getFlashStatus(status);
+ this._updateInterface();
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.play:
+ this._seeked();
+ this._updateButtons(true);
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.pause:
+ this._updateButtons(false);
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.ended:
+ this._updateButtons(false);
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.click:
+ this._trigger(eventType); // This could be dealt with by the default
+ break;
+ case $.jPlayer.event.error:
+ this.status.waitForLoad = true; // Allows the load operation to try again.
+ this.status.waitForPlay = true; // Reset since a play was captured.
+ if(this.status.video) {
+ this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
+ }
+ if(this._validString(this.status.media.poster)) {
+ this.internal.poster.jq.show();
+ }
+ if(this.css.jq.videoPlay.length && this.status.video) {
+ this.css.jq.videoPlay.show();
+ }
+ if(this.status.video) { // Set up for another try. Execute before error event.
+ this._flash_setVideo(this.status.media);
+ } else {
+ this._flash_setAudio(this.status.media);
+ }
+ this._updateButtons(false);
+ this._error( {
+ type: $.jPlayer.error.URL,
+ context:status.src,
+ message: $.jPlayer.errorMsg.URL,
+ hint: $.jPlayer.errorHint.URL
+ });
+ break;
+ case $.jPlayer.event.seeking:
+ this._seeking();
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.seeked:
+ this._seeked();
+ this._trigger(eventType);
+ break;
+ case $.jPlayer.event.ready:
+ // The ready event is handled outside the switch statement.
+ // Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia.
+ break;
+ default:
+ this._trigger(eventType);
+ }
+ }
+ return false;
+ },
+ _getFlashStatus: function(status) {
+ this.status.seekPercent = status.seekPercent;
+ this.status.currentPercentRelative = status.currentPercentRelative;
+ this.status.currentPercentAbsolute = status.currentPercentAbsolute;
+ this.status.currentTime = status.currentTime;
+ this.status.duration = status.duration;
+ this.status.remaining = status.duration - status.currentTime;
+
+ this.status.videoWidth = status.videoWidth;
+ this.status.videoHeight = status.videoHeight;
+
+ // The Flash does not generate this information in this release
+ this.status.readyState = 4; // status.readyState;
+ this.status.networkState = 0; // status.networkState;
+ this.status.playbackRate = 1; // status.playbackRate;
+ this.status.ended = false; // status.ended;
+ },
+ _updateButtons: function(playing) {
+ if(playing === undefined) {
+ playing = !this.status.paused;
+ } else {
+ this.status.paused = !playing;
+ }
+ // Apply the state classes. (For the useStateClassSkin:true option)
+ if(playing) {
+ this.addStateClass('playing');
+ } else {
+ this.removeStateClass('playing');
+ }
+ if(!this.status.noFullWindow && this.options.fullWindow) {
+ this.addStateClass('fullScreen');
+ } else {
+ this.removeStateClass('fullScreen');
+ }
+ if(this.options.loop) {
+ this.addStateClass('looped');
+ } else {
+ this.removeStateClass('looped');
+ }
+ // Toggle the GUI element pairs. (For the useStateClassSkin:false option)
+ if(this.css.jq.play.length && this.css.jq.pause.length) {
+ if(playing) {
+ this.css.jq.play.hide();
+ this.css.jq.pause.show();
+ } else {
+ this.css.jq.play.show();
+ this.css.jq.pause.hide();
+ }
+ }
+ if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) {
+ if(this.status.noFullWindow) {
+ this.css.jq.fullScreen.hide();
+ this.css.jq.restoreScreen.hide();
+ } else if(this.options.fullWindow) {
+ this.css.jq.fullScreen.hide();
+ this.css.jq.restoreScreen.show();
+ } else {
+ this.css.jq.fullScreen.show();
+ this.css.jq.restoreScreen.hide();
+ }
+ }
+ if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) {
+ if(this.options.loop) {
+ this.css.jq.repeat.hide();
+ this.css.jq.repeatOff.show();
+ } else {
+ this.css.jq.repeat.show();
+ this.css.jq.repeatOff.hide();
+ }
+ }
+ },
+ _updateInterface: function() {
+ if(this.css.jq.seekBar.length) {
+ this.css.jq.seekBar.width(this.status.seekPercent+"%");
+ }
+ if(this.css.jq.playBar.length) {
+ if(this.options.smoothPlayBar) {
+ this.css.jq.playBar.stop().animate({
+ width: this.status.currentPercentAbsolute+"%"
+ }, 250, "linear");
+ } else {
+ this.css.jq.playBar.width(this.status.currentPercentRelative+"%");
+ }
+ }
+ var currentTimeText = '';
+ if(this.css.jq.currentTime.length) {
+ currentTimeText = this._convertTime(this.status.currentTime);
+ if(currentTimeText !== this.css.jq.currentTime.text()) {
+ this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));
+ }
+ }
+ var durationText = '',
+ duration = this.status.duration,
+ remaining = this.status.remaining;
+ if(this.css.jq.duration.length) {
+ if(typeof this.status.media.duration === 'string') {
+ durationText = this.status.media.duration;
+ } else {
+ if(typeof this.status.media.duration === 'number') {
+ duration = this.status.media.duration;
+ remaining = duration - this.status.currentTime;
+ }
+ if(this.options.remainingDuration) {
+ durationText = (remaining > 0 ? '-' : '') + this._convertTime(remaining);
+ } else {
+ durationText = this._convertTime(duration);
+ }
+ }
+ if(durationText !== this.css.jq.duration.text()) {
+ this.css.jq.duration.text(durationText);
+ }
+ }
+ },
+ _convertTime: ConvertTime.prototype.time,
+ _seeking: function() {
+ if(this.css.jq.seekBar.length) {
+ this.css.jq.seekBar.addClass("jp-seeking-bg");
+ }
+ this.addStateClass('seeking');
+ },
+ _seeked: function() {
+ if(this.css.jq.seekBar.length) {
+ this.css.jq.seekBar.removeClass("jp-seeking-bg");
+ }
+ this.removeStateClass('seeking');
+ },
+ _resetGate: function() {
+ this.html.audio.gate = false;
+ this.html.video.gate = false;
+ this.aurora.gate = false;
+ this.flash.gate = false;
+ },
+ _resetActive: function() {
+ this.html.active = false;
+ this.aurora.active = false;
+ this.flash.active = false;
+ },
+ _escapeHtml: function(s) {
+ return s.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('"').join('&quot;');
+ },
+ _qualifyURL: function(url) {
+ var el = document.createElement('div');
+ el.innerHTML= '<a href="' + this._escapeHtml(url) + '">x</a>';
+ return el.firstChild.href;
+ },
+ _absoluteMediaUrls: function(media) {
+ var self = this;
+ $.each(media, function(type, url) {
+ if(url && self.format[type] && url.substr(0, 5) !== "data:") {
+ media[type] = self._qualifyURL(url);
+ }
+ });
+ return media;
+ },
+ addStateClass: function(state) {
+ if(this.ancestorJq.length) {
+ this.ancestorJq.addClass(this.options.stateClass[state]);
+ }
+ },
+ removeStateClass: function(state) {
+ if(this.ancestorJq.length) {
+ this.ancestorJq.removeClass(this.options.stateClass[state]);
+ }
+ },
+ setMedia: function(media) {
+
+ /* media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats.
+ * media.poster = String: Video poster URL.
+ * media.track = Array: Of objects defining the track element: kind, src, srclang, label, def.
+ * media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often.
+ */
+
+ var self = this,
+ supported = false,
+ posterChanged = this.status.media.poster !== media.poster; // Compare before reset. Important for OSX Safari as this.htmlElement.poster.src is absolute, even if original poster URL was relative.
+
+ this._resetMedia();
+ this._resetGate();
+ this._resetActive();
+
+ // Clear the Android Fix.
+ this.androidFix.setMedia = false;
+ this.androidFix.play = false;
+ this.androidFix.pause = false;
+
+ // Convert all media URLs to absolute URLs.
+ media = this._absoluteMediaUrls(media);
+
+ $.each(this.formats, function(formatPriority, format) {
+ var isVideo = self.format[format].media === 'video';
+ $.each(self.solutions, function(solutionPriority, solution) {
+ if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format.
+ var isHtml = solution === 'html';
+ var isAurora = solution === 'aurora';
+
+ if(isVideo) {
+ if(isHtml) {
+ self.html.video.gate = true;
+ self._html_setVideo(media);
+ self.html.active = true;
+ } else {
+ self.flash.gate = true;
+ self._flash_setVideo(media);
+ self.flash.active = true;
+ }
+ if(self.css.jq.videoPlay.length) {
+ self.css.jq.videoPlay.show();
+ }
+ self.status.video = true;
+ } else {
+ if(isHtml) {
+ self.html.audio.gate = true;
+ self._html_setAudio(media);
+ self.html.active = true;
+
+ // Setup the Android Fix - Only for HTML audio.
+ if($.jPlayer.platform.android) {
+ self.androidFix.setMedia = true;
+ }
+ } else if(isAurora) {
+ self.aurora.gate = true;
+ self._aurora_setAudio(media);
+ self.aurora.active = true;
+ } else {
+ self.flash.gate = true;
+ self._flash_setAudio(media);
+ self.flash.active = true;
+ }
+ if(self.css.jq.videoPlay.length) {
+ self.css.jq.videoPlay.hide();
+ }
+ self.status.video = false;
+ }
+
+ supported = true;
+ return false; // Exit $.each
+ }
+ });
+ if(supported) {
+ return false; // Exit $.each
+ }
+ });
+
+ if(supported) {
+ if(!(this.status.nativeVideoControls && this.html.video.gate)) {
+ // Set poster IMG if native video controls are not being used
+ // Note: With IE the IMG onload event occurs immediately when cached.
+ // Note: Poster hidden by default in _resetMedia()
+ if(this._validString(media.poster)) {
+ if(posterChanged) { // Since some browsers do not generate img onload event.
+ this.htmlElement.poster.src = media.poster;
+ } else {
+ this.internal.poster.jq.show();
+ }
+ }
+ }
+ if(typeof media.title === 'string') {
+ if(this.css.jq.title.length) {
+ this.css.jq.title.html(media.title);
+ }
+ if(this.htmlElement.audio) {
+ this.htmlElement.audio.setAttribute('title', media.title);
+ }
+ if(this.htmlElement.video) {
+ this.htmlElement.video.setAttribute('title', media.title);
+ }
+ }
+ this.status.srcSet = true;
+ this.status.media = $.extend({}, media);
+ this._updateButtons(false);
+ this._updateInterface();
+ this._trigger($.jPlayer.event.setmedia);
+ } else { // jPlayer cannot support any formats provided in this browser
+ // Send an error event
+ this._error( {
+ type: $.jPlayer.error.NO_SUPPORT,
+ context: "{supplied:'" + this.options.supplied + "'}",
+ message: $.jPlayer.errorMsg.NO_SUPPORT,
+ hint: $.jPlayer.errorHint.NO_SUPPORT
+ });
+ }
+ },
+ _resetMedia: function() {
+ this._resetStatus();
+ this._updateButtons(false);
+ this._updateInterface();
+ this._seeked();
+ this.internal.poster.jq.hide();
+
+ clearTimeout(this.internal.htmlDlyCmdId);
+
+ if(this.html.active) {
+ this._html_resetMedia();
+ } else if(this.aurora.active) {
+ this._aurora_resetMedia();
+ } else if(this.flash.active) {
+ this._flash_resetMedia();
+ }
+ },
+ clearMedia: function() {
+ this._resetMedia();
+
+ if(this.html.active) {
+ this._html_clearMedia();
+ } else if(this.aurora.active) {
+ this._aurora_clearMedia();
+ } else if(this.flash.active) {
+ this._flash_clearMedia();
+ }
+
+ this._resetGate();
+ this._resetActive();
+ },
+ load: function() {
+ if(this.status.srcSet) {
+ if(this.html.active) {
+ this._html_load();
+ } else if(this.aurora.active) {
+ this._aurora_load();
+ } else if(this.flash.active) {
+ this._flash_load();
+ }
+ } else {
+ this._urlNotSetError("load");
+ }
+ },
+ focus: function() {
+ if(this.options.keyEnabled) {
+ $.jPlayer.focus = this;
+ }
+ },
+ play: function(time) {
+ var guiAction = typeof time === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
+ if(guiAction && this.options.useStateClassSkin && !this.status.paused) {
+ this.pause(time); // The time would be the click event, but passing it over so info is not lost.
+ } else {
+ time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
+ if(this.status.srcSet) {
+ this.focus();
+ if(this.html.active) {
+ this._html_play(time);
+ } else if(this.aurora.active) {
+ this._aurora_play(time);
+ } else if(this.flash.active) {
+ this._flash_play(time);
+ }
+ } else {
+ this._urlNotSetError("play");
+ }
+ }
+ },
+ videoPlay: function() { // Handles clicks on the play button over the video poster
+ this.play();
+ },
+ pause: function(time) {
+ time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
+ if(this.status.srcSet) {
+ if(this.html.active) {
+ this._html_pause(time);
+ } else if(this.aurora.active) {
+ this._aurora_pause(time);
+ } else if(this.flash.active) {
+ this._flash_pause(time);
+ }
+ } else {
+ this._urlNotSetError("pause");
+ }
+ },
+ tellOthers: function(command, conditions) {
+ var self = this,
+ hasConditions = typeof conditions === 'function',
+ args = Array.prototype.slice.call(arguments); // Convert arguments to an Array.
+
+ if(typeof command !== 'string') { // Ignore, since no command.
+ return; // Return undefined to maintain chaining.
+ }
+ if(hasConditions) {
+ args.splice(1, 1); // Remove the conditions from the arguments
+ }
+
+ $.jPlayer.prototype.destroyRemoved();
+ $.each(this.instances, function() {
+ // Remember that "this" is the instance's "element" in the $.each() loop.
+ if(self.element !== this) { // Do not tell my instance.
+ if(!hasConditions || conditions.call(this.data("jPlayer"), self)) {
+ this.jPlayer.apply(this, args);
+ }
+ }
+ });
+ },
+ pauseOthers: function(time) {
+ this.tellOthers("pause", function() {
+ // In the conditions function, the "this" context is the other instance's jPlayer object.
+ return this.status.srcSet;
+ }, time);
+ },
+ stop: function() {
+ if(this.status.srcSet) {
+ if(this.html.active) {
+ this._html_pause(0);
+ } else if(this.aurora.active) {
+ this._aurora_pause(0);
+ } else if(this.flash.active) {
+ this._flash_pause(0);
+ }
+ } else {
+ this._urlNotSetError("stop");
+ }
+ },
+ playHead: function(p) {
+ p = this._limitValue(p, 0, 100);
+ if(this.status.srcSet) {
+ if(this.html.active) {
+ this._html_playHead(p);
+ } else if(this.aurora.active) {
+ this._aurora_playHead(p);
+ } else if(this.flash.active) {
+ this._flash_playHead(p);
+ }
+ } else {
+ this._urlNotSetError("playHead");
+ }
+ },
+ _muted: function(muted) {
+ this.mutedWorker(muted);
+ if(this.options.globalVolume) {
+ this.tellOthers("mutedWorker", function() {
+ // Check the other instance has global volume enabled.
+ return this.options.globalVolume;
+ }, muted);
+ }
+ },
+ mutedWorker: function(muted) {
+ this.options.muted = muted;
+ if(this.html.used) {
+ this._html_setProperty('muted', muted);
+ }
+ if(this.aurora.used) {
+ this._aurora_mute(muted);
+ }
+ if(this.flash.used) {
+ this._flash_mute(muted);
+ }
+
+ // The HTML solution generates this event from the media element itself.
+ if(!this.html.video.gate && !this.html.audio.gate) {
+ this._updateMute(muted);
+ this._updateVolume(this.options.volume);
+ this._trigger($.jPlayer.event.volumechange);
+ }
+ },
+ mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted).
+ var guiAction = typeof mute === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
+ if(guiAction && this.options.useStateClassSkin && this.options.muted) {
+ this._muted(false);
+ } else {
+ mute = mute === undefined ? true : !!mute;
+ this._muted(mute);
+ }
+ },
+ unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted).
+ unmute = unmute === undefined ? true : !!unmute;
+ this._muted(!unmute);
+ },
+ _updateMute: function(mute) {
+ if(mute === undefined) {
+ mute = this.options.muted;
+ }
+ if(mute) {
+ this.addStateClass('muted');
+ } else {
+ this.removeStateClass('muted');
+ }
+ if(this.css.jq.mute.length && this.css.jq.unmute.length) {
+ if(this.status.noVolume) {
+ this.css.jq.mute.hide();
+ this.css.jq.unmute.hide();
+ } else if(mute) {
+ this.css.jq.mute.hide();
+ this.css.jq.unmute.show();
+ } else {
+ this.css.jq.mute.show();
+ this.css.jq.unmute.hide();
+ }
+ }
+ },
+ volume: function(v) {
+ this.volumeWorker(v);
+ if(this.options.globalVolume) {
+ this.tellOthers("volumeWorker", function() {
+ // Check the other instance has global volume enabled.
+ return this.options.globalVolume;
+ }, v);
+ }
+ },
+ volumeWorker: function(v) {
+ v = this._limitValue(v, 0, 1);
+ this.options.volume = v;
+
+ if(this.html.used) {
+ this._html_setProperty('volume', v);
+ }
+ if(this.aurora.used) {
+ this._aurora_volume(v);
+ }
+ if(this.flash.used) {
+ this._flash_volume(v);
+ }
+
+ // The HTML solution generates this event from the media element itself.
+ if(!this.html.video.gate && !this.html.audio.gate) {
+ this._updateVolume(v);
+ this._trigger($.jPlayer.event.volumechange);
+ }
+ },
+ volumeBar: function(e) { // Handles clicks on the volumeBar
+ if(this.css.jq.volumeBar.length) {
+ // Using $(e.currentTarget) to enable multiple volume bars
+ var $bar = $(e.currentTarget),
+ offset = $bar.offset(),
+ x = e.pageX - offset.left,
+ w = $bar.width(),
+ y = $bar.height() - e.pageY + offset.top,
+ h = $bar.height();
+ if(this.options.verticalVolume) {
+ this.volume(y/h);
+ } else {
+ this.volume(x/w);
+ }
+ }
+ if(this.options.muted) {
+ this._muted(false);
+ }
+ },
+ _updateVolume: function(v) {
+ if(v === undefined) {
+ v = this.options.volume;
+ }
+ v = this.options.muted ? 0 : v;
+
+ if(this.status.noVolume) {
+ this.addStateClass('noVolume');
+ if(this.css.jq.volumeBar.length) {
+ this.css.jq.volumeBar.hide();
+ }
+ if(this.css.jq.volumeBarValue.length) {
+ this.css.jq.volumeBarValue.hide();
+ }
+ if(this.css.jq.volumeMax.length) {
+ this.css.jq.volumeMax.hide();
+ }
+ } else {
+ this.removeStateClass('noVolume');
+ if(this.css.jq.volumeBar.length) {
+ this.css.jq.volumeBar.show();
+ }
+ if(this.css.jq.volumeBarValue.length) {
+ this.css.jq.volumeBarValue.show();
+ this.css.jq.volumeBarValue[this.options.verticalVolume ? "height" : "width"]((v*100)+"%");
+ }
+ if(this.css.jq.volumeMax.length) {
+ this.css.jq.volumeMax.show();
+ }
+ }
+ },
+ volumeMax: function() { // Handles clicks on the volume max
+ this.volume(1);
+ if(this.options.muted) {
+ this._muted(false);
+ }
+ },
+ _cssSelectorAncestor: function(ancestor) {
+ var self = this;
+ this.options.cssSelectorAncestor = ancestor;
+ this._removeUiClass();
+ this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+
+ if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning.
+ this._warning( {
+ type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
+ context: ancestor,
+ message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.",
+ hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
+ });
+ }
+ this._addUiClass();
+ $.each(this.options.cssSelector, function(fn, cssSel) {
+ self._cssSelector(fn, cssSel);
+ });
+
+ // Set the GUI to the current state.
+ this._updateInterface();
+ this._updateButtons();
+ this._updateAutohide();
+ this._updateVolume();
+ this._updateMute();
+ },
+ _cssSelector: function(fn, cssSel) {
+ var self = this;
+ if(typeof cssSel === 'string') {
+ if($.jPlayer.prototype.options.cssSelector[fn]) {
+ if(this.css.jq[fn] && this.css.jq[fn].length) {
+ this.css.jq[fn].unbind(".jPlayer");
+ }
+ this.options.cssSelector[fn] = cssSel;
+ this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel;
+
+ if(cssSel) { // Checks for empty string
+ this.css.jq[fn] = $(this.css.cs[fn]);
+ } else {
+ this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set.
+ }
+
+ if(this.css.jq[fn].length && this[fn]) {
+ var handler = function(e) {
+ e.preventDefault();
+ self[fn](e);
+ if(self.options.autoBlur) {
+ $(this).blur();
+ } else {
+ $(this).focus(); // Force focus for ARIA.
+ }
+ };
+ this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace
+ }
+
+ if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one.
+ this._warning( {
+ type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
+ context: this.css.cs[fn],
+ message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.",
+ hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
+ });
+ }
+ } else {
+ this._warning( {
+ type: $.jPlayer.warning.CSS_SELECTOR_METHOD,
+ context: fn,
+ message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD,
+ hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD
+ });
+ }
+ } else {
+ this._warning( {
+ type: $.jPlayer.warning.CSS_SELECTOR_STRING,
+ context: cssSel,
+ message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING,
+ hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING
+ });
+ }
+ },
+ duration: function(e) {
+ if(this.options.toggleDuration) {
+ if(this.options.captureDuration) {
+ e.stopPropagation();
+ }
+ this._setOption("remainingDuration", !this.options.remainingDuration);
+ }
+ },
+ seekBar: function(e) { // Handles clicks on the seekBar
+ if(this.css.jq.seekBar.length) {
+ // Using $(e.currentTarget) to enable multiple seek bars
+ var $bar = $(e.currentTarget),
+ offset = $bar.offset(),
+ x = e.pageX - offset.left,
+ w = $bar.width(),
+ p = 100 * x / w;
+ this.playHead(p);
+ }
+ },
+ playbackRate: function(pbr) {
+ this._setOption("playbackRate", pbr);
+ },
+ playbackRateBar: function(e) { // Handles clicks on the playbackRateBar
+ if(this.css.jq.playbackRateBar.length) {
+ // Using $(e.currentTarget) to enable multiple playbackRate bars
+ var $bar = $(e.currentTarget),
+ offset = $bar.offset(),
+ x = e.pageX - offset.left,
+ w = $bar.width(),
+ y = $bar.height() - e.pageY + offset.top,
+ h = $bar.height(),
+ ratio, pbr;
+ if(this.options.verticalPlaybackRate) {
+ ratio = y/h;
+ } else {
+ ratio = x/w;
+ }
+ pbr = ratio * (this.options.maxPlaybackRate - this.options.minPlaybackRate) + this.options.minPlaybackRate;
+ this.playbackRate(pbr);
+ }
+ },
+ _updatePlaybackRate: function() {
+ var pbr = this.options.playbackRate,
+ ratio = (pbr - this.options.minPlaybackRate) / (this.options.maxPlaybackRate - this.options.minPlaybackRate);
+ if(this.status.playbackRateEnabled) {
+ if(this.css.jq.playbackRateBar.length) {
+ this.css.jq.playbackRateBar.show();
+ }
+ if(this.css.jq.playbackRateBarValue.length) {
+ this.css.jq.playbackRateBarValue.show();
+ this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate ? "height" : "width"]((ratio*100)+"%");
+ }
+ } else {
+ if(this.css.jq.playbackRateBar.length) {
+ this.css.jq.playbackRateBar.hide();
+ }
+ if(this.css.jq.playbackRateBarValue.length) {
+ this.css.jq.playbackRateBarValue.hide();
+ }
+ }
+ },
+ repeat: function(event) { // Handle clicks on the repeat button
+ var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
+ if(guiAction && this.options.useStateClassSkin && this.options.loop) {
+ this._loop(false);
+ } else {
+ this._loop(true);
+ }
+ },
+ repeatOff: function() { // Handle clicks on the repeatOff button
+ this._loop(false);
+ },
+ _loop: function(loop) {
+ if(this.options.loop !== loop) {
+ this.options.loop = loop;
+ this._updateButtons();
+ this._trigger($.jPlayer.event.repeat);
+ }
+ },
+
+ // Options code adapted from ui.widget.js (1.8.7). Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1.
+ option: function(key, value) {
+ var options = key;
+
+ // Enables use: options(). Returns a copy of options object
+ if ( arguments.length === 0 ) {
+ return $.extend( true, {}, this.options );
+ }
+
+ if(typeof key === "string") {
+ var keys = key.split(".");
+
+ // Enables use: options("someOption") Returns a copy of the option. Supports dot notation.
+ if(value === undefined) {
+
+ var opt = $.extend(true, {}, this.options);
+ for(var i = 0; i < keys.length; i++) {
+ if(opt[keys[i]] !== undefined) {
+ opt = opt[keys[i]];
+ } else {
+ this._warning( {
+ type: $.jPlayer.warning.OPTION_KEY,
+ context: key,
+ message: $.jPlayer.warningMsg.OPTION_KEY,
+ hint: $.jPlayer.warningHint.OPTION_KEY
+ });
+ return undefined;
+ }
+ }
+ return opt;
+ }
+
+ // Enables use: options("someOptionObject", someObject}). Creates: {someOptionObject:someObject}
+ // Enables use: options("someOption", someValue). Creates: {someOption:someValue}
+ // Enables use: options("someOptionObject.someOption", someValue). Creates: {someOptionObject:{someOption:someValue}}
+
+ options = {};
+ var opts = options;
+
+ for(var j = 0; j < keys.length; j++) {
+ if(j < keys.length - 1) {
+ opts[keys[j]] = {};
+ opts = opts[keys[j]];
+ } else {
+ opts[keys[j]] = value;
+ }
+ }
+ }
+
+ // Otherwise enables use: options(optionObject). Uses original object (the key)
+
+ this._setOptions(options);
+
+ return this;
+ },
+ _setOptions: function(options) {
+ var self = this;
+ $.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth.
+ self._setOption(key, value);
+ });
+
+ return this;
+ },
+ _setOption: function(key, value) {
+ var self = this;
+
+ // The ability to set options is limited at this time.
+
+ switch(key) {
+ case "volume" :
+ this.volume(value);
+ break;
+ case "muted" :
+ this._muted(value);
+ break;
+ case "globalVolume" :
+ this.options[key] = value;
+ break;
+ case "cssSelectorAncestor" :
+ this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor.
+ break;
+ case "cssSelector" :
+ $.each(value, function(fn, cssSel) {
+ self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks.
+ });
+ break;
+ case "playbackRate" :
+ this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
+ if(this.html.used) {
+ this._html_setProperty('playbackRate', value);
+ }
+ this._updatePlaybackRate();
+ break;
+ case "defaultPlaybackRate" :
+ this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
+ if(this.html.used) {
+ this._html_setProperty('defaultPlaybackRate', value);
+ }
+ this._updatePlaybackRate();
+ break;
+ case "minPlaybackRate" :
+ this.options[key] = value = this._limitValue(value, 0.1, this.options.maxPlaybackRate - 0.1);
+ this._updatePlaybackRate();
+ break;
+ case "maxPlaybackRate" :
+ this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate + 0.1, 16);
+ this._updatePlaybackRate();
+ break;
+ case "fullScreen" :
+ if(this.options[key] !== value) { // if changed
+ var wkv = $.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;
+ if(!wkv || wkv && !this.status.waitForPlay) {
+ if(!wkv) { // No sensible way to unset option on these devices.
+ this.options[key] = value;
+ }
+ if(value) {
+ this._requestFullscreen();
+ } else {
+ this._exitFullscreen();
+ }
+ if(!wkv) {
+ this._setOption("fullWindow", value);
+ }
+ }
+ }
+ break;
+ case "fullWindow" :
+ if(this.options[key] !== value) { // if changed
+ this._removeUiClass();
+ this.options[key] = value;
+ this._refreshSize();
+ }
+ break;
+ case "size" :
+ if(!this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
+ this._removeUiClass();
+ }
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this._refreshSize();
+ break;
+ case "sizeFull" :
+ if(this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
+ this._removeUiClass();
+ }
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this._refreshSize();
+ break;
+ case "autohide" :
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this._updateAutohide();
+ break;
+ case "loop" :
+ this._loop(value);
+ break;
+ case "remainingDuration" :
+ this.options[key] = value;
+ this._updateInterface();
+ break;
+ case "toggleDuration" :
+ this.options[key] = value;
+ break;
+ case "nativeVideoControls" :
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
+ this._restrictNativeVideoControls();
+ this._updateNativeVideoControls();
+ break;
+ case "noFullWindow" :
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); // Need to check again as noFullWindow can depend on this flag and the restrict() can override it.
+ this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
+ this._restrictNativeVideoControls();
+ this._updateButtons();
+ break;
+ case "noVolume" :
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ this.status.noVolume = this._uaBlocklist(this.options.noVolume);
+ this._updateVolume();
+ this._updateMute();
+ break;
+ case "emulateHtml" :
+ if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already.
+ this.options[key] = value;
+ if(value) {
+ this._emulateHtmlBridge();
+ } else {
+ this._destroyHtmlBridge();
+ }
+ }
+ break;
+ case "timeFormat" :
+ this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
+ break;
+ case "keyEnabled" :
+ this.options[key] = value;
+ if(!value && this === $.jPlayer.focus) {
+ $.jPlayer.focus = null;
+ }
+ break;
+ case "keyBindings" :
+ this.options[key] = $.extend(true, {}, this.options[key], value); // store a merged DEEP copy of it, incase not all properties changed.
+ break;
+ case "audioFullScreen" :
+ this.options[key] = value;
+ break;
+ case "autoBlur" :
+ this.options[key] = value;
+ break;
+ }
+
+ return this;
+ },
+ // End of: (Options code adapted from ui.widget.js)
+
+ _refreshSize: function() {
+ this._setSize(); // update status and jPlayer element size
+ this._addUiClass(); // update the ui class
+ this._updateSize(); // update internal sizes
+ this._updateButtons();
+ this._updateAutohide();
+ this._trigger($.jPlayer.event.resize);
+ },
+ _setSize: function() {
+ // Determine the current size from the options
+ if(this.options.fullWindow) {
+ this.status.width = this.options.sizeFull.width;
+ this.status.height = this.options.sizeFull.height;
+ this.status.cssClass = this.options.sizeFull.cssClass;
+ } else {
+ this.status.width = this.options.size.width;
+ this.status.height = this.options.size.height;
+ this.status.cssClass = this.options.size.cssClass;
+ }
+
+ // Set the size of the jPlayer area.
+ this.element.css({'width': this.status.width, 'height': this.status.height});
+ },
+ _addUiClass: function() {
+ if(this.ancestorJq.length) {
+ this.ancestorJq.addClass(this.status.cssClass);
+ }
+ },
+ _removeUiClass: function() {
+ if(this.ancestorJq.length) {
+ this.ancestorJq.removeClass(this.status.cssClass);
+ }
+ },
+ _updateSize: function() {
+ // The poster uses show/hide so can simply resize it.
+ this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
+
+ // Video html or flash resized if necessary at this time, or if native video controls being used.
+ if(!this.status.waitForPlay && this.html.active && this.status.video || this.html.video.available && this.html.used && this.status.nativeVideoControls) {
+ this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
+ }
+ else if(!this.status.waitForPlay && this.flash.active && this.status.video) {
+ this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
+ }
+ },
+ _updateAutohide: function() {
+ var self = this,
+ event = "mousemove.jPlayer",
+ namespace = ".jPlayerAutohide",
+ eventType = event + namespace,
+ handler = function(event) {
+ var moved = false,
+ deltaX, deltaY;
+ if(typeof self.internal.mouse !== "undefined") {
+ //get the change from last position to this position
+ deltaX = self.internal.mouse.x - event.pageX;
+ deltaY = self.internal.mouse.y - event.pageY;
+ moved = (Math.floor(deltaX) > 0) || (Math.floor(deltaY)>0);
+ } else {
+ moved = true;
+ }
+ // store current position for next method execution
+ self.internal.mouse = {
+ x : event.pageX,
+ y : event.pageY
+ };
+ // if mouse has been actually moved, do the gui fadeIn/fadeOut
+ if (moved) {
+ self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() {
+ clearTimeout(self.internal.autohideId);
+ self.internal.autohideId = setTimeout( function() {
+ self.css.jq.gui.fadeOut(self.options.autohide.fadeOut);
+ }, self.options.autohide.hold);
+ });
+ }
+ };
+
+ if(this.css.jq.gui.length) {
+
+ // End animations first so that its callback is executed now.
+ // Otherwise an in progress fadeIn animation still has the callback to fadeOut again.
+ this.css.jq.gui.stop(true, true);
+
+ // Removes the fadeOut operation from the fadeIn callback.
+ clearTimeout(this.internal.autohideId);
+ // undefine mouse
+ delete this.internal.mouse;
+
+ this.element.unbind(namespace);
+ this.css.jq.gui.unbind(namespace);
+
+ if(!this.status.nativeVideoControls) {
+ if(this.options.fullWindow && this.options.autohide.full || !this.options.fullWindow && this.options.autohide.restored) {
+ this.element.bind(eventType, handler);
+ this.css.jq.gui.bind(eventType, handler);
+ this.css.jq.gui.hide();
+ } else {
+ this.css.jq.gui.show();
+ }
+ } else {
+ this.css.jq.gui.hide();
+ }
+ }
+ },
+ fullScreen: function(event) {
+ var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
+ if(guiAction && this.options.useStateClassSkin && this.options.fullScreen) {
+ this._setOption("fullScreen", false);
+ } else {
+ this._setOption("fullScreen", true);
+ }
+ },
+ restoreScreen: function() {
+ this._setOption("fullScreen", false);
+ },
+ _fullscreenAddEventListeners: function() {
+ var self = this,
+ fs = $.jPlayer.nativeFeatures.fullscreen;
+
+ if(fs.api.fullscreenEnabled) {
+ if(fs.event.fullscreenchange) {
+ // Create the event handler function and store it for removal.
+ if(typeof this.internal.fullscreenchangeHandler !== 'function') {
+ this.internal.fullscreenchangeHandler = function() {
+ self._fullscreenchange();
+ };
+ }
+ document.addEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
+ }
+ // No point creating handler for fullscreenerror.
+ // Either logic avoids fullscreen occurring (w3c/moz), or their is no event on the browser (webkit).
+ }
+ },
+ _fullscreenRemoveEventListeners: function() {
+ var fs = $.jPlayer.nativeFeatures.fullscreen;
+ if(this.internal.fullscreenchangeHandler) {
+ document.removeEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
+ }
+ },
+ _fullscreenchange: function() {
+ // If nothing is fullscreen, then we cannot be in fullscreen mode.
+ if(this.options.fullScreen && !$.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()) {
+ this._setOption("fullScreen", false);
+ }
+ },
+ _requestFullscreen: function() {
+ // Either the container or the jPlayer div
+ var e = this.ancestorJq.length ? this.ancestorJq[0] : this.element[0],
+ fs = $.jPlayer.nativeFeatures.fullscreen;
+
+ // This method needs the video element. For iOS and Android.
+ if(fs.used.webkitVideo) {
+ e = this.htmlElement.video;
+ }
+
+ if(fs.api.fullscreenEnabled) {
+ fs.api.requestFullscreen(e);
+ }
+ },
+ _exitFullscreen: function() {
+
+ var fs = $.jPlayer.nativeFeatures.fullscreen,
+ e;
+
+ // This method needs the video element. For iOS and Android.
+ if(fs.used.webkitVideo) {
+ e = this.htmlElement.video;
+ }
+
+ if(fs.api.fullscreenEnabled) {
+ fs.api.exitFullscreen(e);
+ }
+ },
+ _html_initMedia: function(media) {
+ // Remove any existing track elements
+ var $media = $(this.htmlElement.media).empty();
+
+ // Create any track elements given with the media, as an Array of track Objects.
+ $.each(media.track || [], function(i,v) {
+ var track = document.createElement('track');
+ track.setAttribute("kind", v.kind ? v.kind : "");
+ track.setAttribute("src", v.src ? v.src : "");
+ track.setAttribute("srclang", v.srclang ? v.srclang : "");
+ track.setAttribute("label", v.label ? v.label : "");
+ if(v.def) {
+ track.setAttribute("default", v.def);
+ }
+ $media.append(track);
+ });
+
+ this.htmlElement.media.src = this.status.src;
+
+ if(this.options.preload !== 'none') {
+ this._html_load(); // See function for comments
+ }
+ this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution.
+ },
+ _html_setFormat: function(media) {
+ var self = this;
+ // Always finds a format due to checks in setMedia()
+ $.each(this.formats, function(priority, format) {
+ if(self.html.support[format] && media[format]) {
+ self.status.src = media[format];
+ self.status.format[format] = true;
+ self.status.formatType = format;
+ return false;
+ }
+ });
+ },
+ _html_setAudio: function(media) {
+ this._html_setFormat(media);
+ this.htmlElement.media = this.htmlElement.audio;
+ this._html_initMedia(media);
+ },
+ _html_setVideo: function(media) {
+ this._html_setFormat(media);
+ if(this.status.nativeVideoControls) {
+ this.htmlElement.video.poster = this._validString(media.poster) ? media.poster : "";
+ }
+ this.htmlElement.media = this.htmlElement.video;
+ this._html_initMedia(media);
+ },
+ _html_resetMedia: function() {
+ if(this.htmlElement.media) {
+ if(this.htmlElement.media.id === this.internal.video.id && !this.status.nativeVideoControls) {
+ this.internal.video.jq.css({'width':'0px', 'height':'0px'});
+ }
+ this.htmlElement.media.pause();
+ }
+ },
+ _html_clearMedia: function() {
+ if(this.htmlElement.media) {
+ this.htmlElement.media.src = "about:blank";
+ // The following load() is only required for Firefox 3.6 (PowerMacs).
+ // Recent HTMl5 browsers only require the src change. Due to changes in W3C spec and load() effect.
+ this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress.
+ }
+ },
+ _html_load: function() {
+ // This function remains to allow the early HTML5 browsers to work, such as Firefox 3.6
+ // A change in the W3C spec for the media.load() command means that this is no longer necessary.
+ // This command should be removed and actually causes minor undesirable effects on some browsers. Such as loading the whole file and not only the metadata.
+ if(this.status.waitForLoad) {
+ this.status.waitForLoad = false;
+ this.htmlElement.media.load();
+ }
+ clearTimeout(this.internal.htmlDlyCmdId);
+ },
+ _html_play: function(time) {
+ var self = this,
+ media = this.htmlElement.media;
+
+ this.androidFix.pause = false; // Cancel the pause fix.
+
+ this._html_load(); // Loads if required and clears any delayed commands.
+
+ // Setup the Android Fix.
+ if(this.androidFix.setMedia) {
+ this.androidFix.play = true;
+ this.androidFix.time = time;
+
+ } else if(!isNaN(time)) {
+
+ // Attempt to play it, since iOS has been ignoring commands
+ if(this.internal.cmdsIgnored) {
+ media.play();
+ }
+
+ try {
+ // !media.seekable is for old HTML5 browsers, like Firefox 3.6.
+ // Checking seekable.length is important for iOS6 to work with setMedia().play(time)
+ if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
+ media.currentTime = time;
+ media.play();
+ } else {
+ throw 1;
+ }
+ } catch(err) {
+ this.internal.htmlDlyCmdId = setTimeout(function() {
+ self.play(time);
+ }, 250);
+ return; // Cancel execution and wait for the delayed command.
+ }
+ } else {
+ media.play();
+ }
+ this._html_checkWaitForPlay();
+ },
+ _html_pause: function(time) {
+ var self = this,
+ media = this.htmlElement.media;
+
+ this.androidFix.play = false; // Cancel the play fix.
+
+ if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
+ this._html_load(); // Loads if required and clears any delayed commands.
+ } else {
+ clearTimeout(this.internal.htmlDlyCmdId);
+ }
+
+ // Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime.
+ media.pause();
+
+ // Setup the Android Fix.
+ if(this.androidFix.setMedia) {
+ this.androidFix.pause = true;
+ this.androidFix.time = time;
+
+ } else if(!isNaN(time)) {
+ try {
+ if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
+ media.currentTime = time;
+ } else {
+ throw 1;
+ }
+ } catch(err) {
+ this.internal.htmlDlyCmdId = setTimeout(function() {
+ self.pause(time);
+ }, 250);
+ return; // Cancel execution and wait for the delayed command.
+ }
+ }
+ if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
+ this._html_checkWaitForPlay();
+ }
+ },
+ _html_playHead: function(percent) {
+ var self = this,
+ media = this.htmlElement.media;
+
+ this._html_load(); // Loads if required and clears any delayed commands.
+
+ // This playHead() method needs a refactor to apply the android fix.
+
+ try {
+ if(typeof media.seekable === "object" && media.seekable.length > 0) {
+ media.currentTime = percent * media.seekable.end(media.seekable.length-1) / 100;
+ } else if(media.duration > 0 && !isNaN(media.duration)) {
+ media.currentTime = percent * media.duration / 100;
+ } else {
+ throw "e";
+ }
+ } catch(err) {
+ this.internal.htmlDlyCmdId = setTimeout(function() {
+ self.playHead(percent);
+ }, 250);
+ return; // Cancel execution and wait for the delayed command.
+ }
+ if(!this.status.waitForLoad) {
+ this._html_checkWaitForPlay();
+ }
+ },
+ _html_checkWaitForPlay: function() {
+ if(this.status.waitForPlay) {
+ this.status.waitForPlay = false;
+ if(this.css.jq.videoPlay.length) {
+ this.css.jq.videoPlay.hide();
+ }
+ if(this.status.video) {
+ this.internal.poster.jq.hide();
+ this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
+ }
+ }
+ },
+ _html_setProperty: function(property, value) {
+ if(this.html.audio.available) {
+ this.htmlElement.audio[property] = value;
+ }
+ if(this.html.video.available) {
+ this.htmlElement.video[property] = value;
+ }
+ },
+ _aurora_setAudio: function(media) {
+ var self = this;
+
+ // Always finds a format due to checks in setMedia()
+ $.each(this.formats, function(priority, format) {
+ if(self.aurora.support[format] && media[format]) {
+ self.status.src = media[format];
+ self.status.format[format] = true;
+ self.status.formatType = format;
+
+ return false;
+ }
+ });
+
+ this.aurora.player = new AV.Player.fromURL(this.status.src);
+ this._addAuroraEventListeners(this.aurora.player, this.aurora);
+
+ if(this.options.preload === 'auto') {
+ this._aurora_load();
+ this.status.waitForLoad = false;
+ }
+ },
+ _aurora_resetMedia: function() {
+ if (this.aurora.player) {
+ this.aurora.player.stop();
+ }
+ },
+ _aurora_clearMedia: function() {
+ // Nothing to clear.
+ },
+ _aurora_load: function() {
+ if(this.status.waitForLoad) {
+ this.status.waitForLoad = false;
+ this.aurora.player.preload();
+ }
+ },
+ _aurora_play: function(time) {
+ if (!this.status.waitForLoad) {
+ if (!isNaN(time)) {
+ this.aurora.player.seek(time);
+ }
+ }
+ if (!this.aurora.player.playing) {
+ this.aurora.player.play();
+ }
+ this.status.waitForLoad = false;
+ this._aurora_checkWaitForPlay();
+
+ // No event from the player, update UI now.
+ this._updateButtons(true);
+ this._trigger($.jPlayer.event.play);
+ },
+ _aurora_pause: function(time) {
+ if (!isNaN(time)) {
+ this.aurora.player.seek(time * 1000);
+ }
+ this.aurora.player.pause();
+
+ if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
+ this._aurora_checkWaitForPlay();
+ }
+
+ // No event from the player, update UI now.
+ this._updateButtons(false);
+ this._trigger($.jPlayer.event.pause);
+ },
+ _aurora_playHead: function(percent) {
+ if(this.aurora.player.duration > 0) {
+ // The seek() sould be in milliseconds, but the only codec that works with seek (aac.js) uses seconds.
+ this.aurora.player.seek(percent * this.aurora.player.duration / 100); // Using seconds
+ }
+
+ if(!this.status.waitForLoad) {
+ this._aurora_checkWaitForPlay();
+ }
+ },
+ _aurora_checkWaitForPlay: function() {
+ if(this.status.waitForPlay) {
+ this.status.waitForPlay = false;
+ }
+ },
+ _aurora_volume: function(v) {
+ this.aurora.player.volume = v * 100;
+ },
+ _aurora_mute: function(m) {
+ if (m) {
+ this.aurora.properties.lastvolume = this.aurora.player.volume;
+ this.aurora.player.volume = 0;
+ } else {
+ this.aurora.player.volume = this.aurora.properties.lastvolume;
+ }
+ this.aurora.properties.muted = m;
+ },
+ _flash_setAudio: function(media) {
+ var self = this;
+ try {
+ // Always finds a format due to checks in setMedia()
+ $.each(this.formats, function(priority, format) {
+ if(self.flash.support[format] && media[format]) {
+ switch (format) {
+ case "m4a" :
+ case "fla" :
+ self._getMovie().fl_setAudio_m4a(media[format]);
+ break;
+ case "mp3" :
+ self._getMovie().fl_setAudio_mp3(media[format]);
+ break;
+ case "rtmpa":
+ self._getMovie().fl_setAudio_rtmp(media[format]);
+ break;
+ }
+ self.status.src = media[format];
+ self.status.format[format] = true;
+ self.status.formatType = format;
+ return false;
+ }
+ });
+
+ if(this.options.preload === 'auto') {
+ this._flash_load();
+ this.status.waitForLoad = false;
+ }
+ } catch(err) { this._flashError(err); }
+ },
+ _flash_setVideo: function(media) {
+ var self = this;
+ try {
+ // Always finds a format due to checks in setMedia()
+ $.each(this.formats, function(priority, format) {
+ if(self.flash.support[format] && media[format]) {
+ switch (format) {
+ case "m4v" :
+ case "flv" :
+ self._getMovie().fl_setVideo_m4v(media[format]);
+ break;
+ case "rtmpv":
+ self._getMovie().fl_setVideo_rtmp(media[format]);
+ break;
+ }
+ self.status.src = media[format];
+ self.status.format[format] = true;
+ self.status.formatType = format;
+ return false;
+ }
+ });
+
+ if(this.options.preload === 'auto') {
+ this._flash_load();
+ this.status.waitForLoad = false;
+ }
+ } catch(err) { this._flashError(err); }
+ },
+ _flash_resetMedia: function() {
+ this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE.
+ this._flash_pause(NaN);
+ },
+ _flash_clearMedia: function() {
+ try {
+ this._getMovie().fl_clearMedia();
+ } catch(err) { this._flashError(err); }
+ },
+ _flash_load: function() {
+ try {
+ this._getMovie().fl_load();
+ } catch(err) { this._flashError(err); }
+ this.status.waitForLoad = false;
+ },
+ _flash_play: function(time) {
+ try {
+ this._getMovie().fl_play(time);
+ } catch(err) { this._flashError(err); }
+ this.status.waitForLoad = false;
+ this._flash_checkWaitForPlay();
+ },
+ _flash_pause: function(time) {
+ try {
+ this._getMovie().fl_pause(time);
+ } catch(err) { this._flashError(err); }
+ if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
+ this.status.waitForLoad = false;
+ this._flash_checkWaitForPlay();
+ }
+ },
+ _flash_playHead: function(p) {
+ try {
+ this._getMovie().fl_play_head(p);
+ } catch(err) { this._flashError(err); }
+ if(!this.status.waitForLoad) {
+ this._flash_checkWaitForPlay();
+ }
+ },
+ _flash_checkWaitForPlay: function() {
+ if(this.status.waitForPlay) {
+ this.status.waitForPlay = false;
+ if(this.css.jq.videoPlay.length) {
+ this.css.jq.videoPlay.hide();
+ }
+ if(this.status.video) {
+ this.internal.poster.jq.hide();
+ this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
+ }
+ }
+ },
+ _flash_volume: function(v) {
+ try {
+ this._getMovie().fl_volume(v);
+ } catch(err) { this._flashError(err); }
+ },
+ _flash_mute: function(m) {
+ try {
+ this._getMovie().fl_mute(m);
+ } catch(err) { this._flashError(err); }
+ },
+ _getMovie: function() {
+ return document[this.internal.flash.id];
+ },
+ _getFlashPluginVersion: function() {
+
+ // _getFlashPluginVersion() code influenced by:
+ // - FlashReplace 1.01: http://code.google.com/p/flashreplace/
+ // - SWFObject 2.2: http://code.google.com/p/swfobject/
+
+ var version = 0,
+ flash;
+ if(window.ActiveXObject) {
+ try {
+ flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
+ if (flash) { // flash will return null when ActiveX is disabled
+ var v = flash.GetVariable("$version");
+ if(v) {
+ v = v.split(" ")[1].split(",");
+ version = parseInt(v[0], 10) + "." + parseInt(v[1], 10);
+ }
+ }
+ } catch(e) {}
+ }
+ else if(navigator.plugins && navigator.mimeTypes.length > 0) {
+ flash = navigator.plugins["Shockwave Flash"];
+ if(flash) {
+ version = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1");
+ }
+ }
+ return version * 1; // Converts to a number
+ },
+ _checkForFlash: function (version) {
+ var flashOk = false;
+ if(this._getFlashPluginVersion() >= version) {
+ flashOk = true;
+ }
+ return flashOk;
+ },
+ _validString: function(url) {
+ return (url && typeof url === "string"); // Empty strings return false
+ },
+ _limitValue: function(value, min, max) {
+ return (value < min) ? min : ((value > max) ? max : value);
+ },
+ _urlNotSetError: function(context) {
+ this._error( {
+ type: $.jPlayer.error.URL_NOT_SET,
+ context: context,
+ message: $.jPlayer.errorMsg.URL_NOT_SET,
+ hint: $.jPlayer.errorHint.URL_NOT_SET
+ });
+ },
+ _flashError: function(error) {
+ var errorType;
+ if(!this.internal.ready) {
+ errorType = "FLASH";
+ } else {
+ errorType = "FLASH_DISABLED";
+ }
+ this._error( {
+ type: $.jPlayer.error[errorType],
+ context: this.internal.flash.swf,
+ message: $.jPlayer.errorMsg[errorType] + error.message,
+ hint: $.jPlayer.errorHint[errorType]
+ });
+ // Allow the audio player to recover if display:none and then shown again, or with position:fixed on Firefox.
+ // This really only affects audio in a media player, as an audio player could easily move the jPlayer element away from such issues.
+ this.internal.flash.jq.css({'width':'1px', 'height':'1px'});
+ },
+ _error: function(error) {
+ this._trigger($.jPlayer.event.error, error);
+ if(this.options.errorAlerts) {
+ this._alert("Error!" + (error.message ? "\n" + error.message : "") + (error.hint ? "\n" + error.hint : "") + "\nContext: " + error.context);
+ }
+ },
+ _warning: function(warning) {
+ this._trigger($.jPlayer.event.warning, undefined, warning);
+ if(this.options.warningAlerts) {
+ this._alert("Warning!" + (warning.message ? "\n" + warning.message : "") + (warning.hint ? "\n" + warning.hint : "") + "\nContext: " + warning.context);
+ }
+ },
+ _alert: function(message) {
+ var msg = "jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message;
+ if(!this.options.consoleAlerts) {
+ alert(msg);
+ } else if(window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ },
+ _emulateHtmlBridge: function() {
+ var self = this;
+
+ // Emulate methods on jPlayer's DOM element.
+ $.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) {
+ self.internal.domNode[name] = function(arg) {
+ self[name](arg);
+ };
+
+ });
+
+ // Bubble jPlayer events to its DOM element.
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ var nativeEvent = true;
+ $.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) {
+ if(name === eventName) {
+ nativeEvent = false;
+ return false;
+ }
+ });
+ if(nativeEvent) {
+ self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces.
+ self._emulateHtmlUpdate();
+ var domEvent = document.createEvent("Event");
+ domEvent.initEvent(eventName, false, true);
+ self.internal.domNode.dispatchEvent(domEvent);
+ });
+ }
+ // The error event would require a special case
+ });
+
+ // IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState.
+ },
+ _emulateHtmlUpdate: function() {
+ var self = this;
+
+ $.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) {
+ self.internal.domNode[name] = self.status[name];
+ });
+ $.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) {
+ self.internal.domNode[name] = self.options[name];
+ });
+ },
+ _destroyHtmlBridge: function() {
+ var self = this;
+
+ // Bridge event handlers are also removed by destroy() through .jPlayer namespace.
+ this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option.
+
+ // Remove the methods and properties
+ var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions;
+ $.each( emulated.split(/\s+/g), function(i, name) {
+ delete self.internal.domNode[name];
+ });
+ }
+ };
+
+ $.jPlayer.error = {
+ FLASH: "e_flash",
+ FLASH_DISABLED: "e_flash_disabled",
+ NO_SOLUTION: "e_no_solution",
+ NO_SUPPORT: "e_no_support",
+ URL: "e_url",
+ URL_NOT_SET: "e_url_not_set",
+ VERSION: "e_version"
+ };
+
+ $.jPlayer.errorMsg = {
+ FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError()
+ FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError()
+ NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init()
+ NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia()
+ URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners()
+ URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead()
+ VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady()
+ };
+
+ $.jPlayer.errorHint = {
+ FLASH: "Check your swfPath option and that Jplayer.swf is there.",
+ FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.",
+ NO_SOLUTION: "Review the jPlayer options: support and supplied.",
+ NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.",
+ URL: "Check media URL is valid.",
+ URL_NOT_SET: "Use setMedia() to set the media URL.",
+ VERSION: "Update jPlayer files."
+ };
+
+ $.jPlayer.warning = {
+ CSS_SELECTOR_COUNT: "e_css_selector_count",
+ CSS_SELECTOR_METHOD: "e_css_selector_method",
+ CSS_SELECTOR_STRING: "e_css_selector_string",
+ OPTION_KEY: "e_option_key"
+ };
+
+ $.jPlayer.warningMsg = {
+ CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ",
+ CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",
+ CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
+ OPTION_KEY: "The option requested in jPlayer('option') is undefined."
+ };
+
+ $.jPlayer.warningHint = {
+ CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.",
+ CSS_SELECTOR_METHOD: "Check your method name.",
+ CSS_SELECTOR_STRING: "Check your css selector is a string.",
+ OPTION_KEY: "Check your option name."
+ };
+}));
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.swf b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.swf
new file mode 100644
index 00000000..340f7f98
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.swf
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.css
new file mode 100644
index 00000000..c13a812a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.css
@@ -0,0 +1,551 @@
+/*! Blue Monday Skin for jPlayer 2.9.2 ~ (c) 2009-2014 Happyworm Ltd ~ MIT License */
+
+/*
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)
+ * http://www.jplayer.org
+ *
+ * Skin Name: Blue Monday
+ *
+ * Copyright (c) 2010 - 2014 Happyworm Ltd
+ * Licensed under the MIT license.
+ * - http://www.opensource.org/licenses/mit-license.php
+ *
+ * Author: Silvia Benvenuti
+ * Skin Version: 5.1 (jPlayer 2.8.0)
+ * Date: 13th November 2014
+ */
+.jp-audio *:focus,
+.jp-audio-stream *:focus,
+.jp-video *:focus {
+ /* Disable the browser focus highlighting. */
+ outline: none; }
+
+.jp-audio button::-moz-focus-inner,
+.jp-audio-stream button::-moz-focus-inner,
+.jp-video button::-moz-focus-inner {
+ /* Disable the browser CSS3 focus highlighting. */
+ border: 0; }
+
+.jp-audio,
+.jp-audio-stream,
+.jp-video {
+ font-size: 16px;
+ font-family: Verdana, Arial, sans-serif;
+ line-height: 1.6;
+ color: #666;
+ border: 1px solid #009be3;
+ background-color: #eee; }
+
+.jp-audio {
+ width: 420px; }
+
+.jp-audio-stream {
+ width: 182px; }
+
+.jp-video-270p {
+ width: 480px; }
+
+.jp-video-360p {
+ width: 640px; }
+
+.jp-video-full {
+ /* Rules for IE6 (full-screen) */
+ width: 480px;
+ height: 270px;
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
+ position: static !important;
+ position: relative; }
+
+/* The z-index rule is defined in this manner to enable Popcorn plugins that add overlays to video area. EG. Subtitles. */
+.jp-video-full div div {
+ z-index: 1000; }
+
+.jp-video-full .jp-jplayer {
+ top: 0;
+ left: 0;
+ position: fixed !important;
+ position: relative;
+ /* Rules for IE6 (full-screen) */
+ overflow: hidden; }
+
+.jp-video-full .jp-gui {
+ position: fixed !important;
+ position: static;
+ /* Rules for IE6 (full-screen) */
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1001;
+ /* 1 layer above the others. */ }
+
+.jp-video-full .jp-interface {
+ position: absolute !important;
+ position: relative;
+ /* Rules for IE6 (full-screen) */
+ bottom: 0;
+ left: 0; }
+
+.jp-interface {
+ position: relative;
+ background-color: #eee;
+ width: 100%; }
+
+.jp-audio .jp-interface {
+ height: 80px; }
+
+.jp-audio-stream .jp-interface {
+ height: 80px; }
+
+.jp-video .jp-interface {
+ border-top: 1px solid #009be3; }
+
+/* @group CONTROLS */
+.jp-controls-holder {
+ clear: both;
+ width: 440px;
+ margin: 0 auto;
+ position: relative;
+ overflow: hidden;
+ top: -8px;
+ /* This negative value depends on the size of the text in jp-currentTime and jp-duration */ }
+
+.jp-interface .jp-controls {
+ margin: 0;
+ padding: 0;
+ overflow: hidden; }
+
+.jp-audio .jp-controls {
+ width: 380px;
+ padding: 20px 20px 0 20px; }
+
+.jp-audio-stream .jp-controls {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ width: 142px; }
+
+.jp-video .jp-type-single .jp-controls {
+ width: 78px;
+ margin-left: 200px; }
+
+.jp-video .jp-type-playlist .jp-controls {
+ width: 134px;
+ margin-left: 172px; }
+
+.jp-video .jp-controls {
+ float: left; }
+
+.jp-controls button {
+ display: block;
+ float: left;
+ overflow: hidden;
+ text-indent: -9999px;
+ border: none;
+ cursor: pointer; }
+
+.jp-play {
+ width: 40px;
+ height: 40px; }
+
+.jp-play {
+ background: url("../image/jplayer.blue.monday.jpg") 0 0 no-repeat; }
+
+.jp-play:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -41px 0 no-repeat; }
+
+.jp-state-playing .jp-play {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -42px no-repeat; }
+
+.jp-state-playing .jp-play:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -41px -42px no-repeat; }
+
+.jp-stop, .jp-previous, .jp-next {
+ width: 28px;
+ height: 28px;
+ margin-top: 6px; }
+
+.jp-stop {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -83px no-repeat;
+ margin-left: 10px; }
+
+.jp-stop:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -29px -83px no-repeat; }
+
+.jp-previous {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -112px no-repeat; }
+
+.jp-previous:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -29px -112px no-repeat; }
+
+.jp-next {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -141px no-repeat; }
+
+.jp-next:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -29px -141px no-repeat; }
+
+/* @end */
+/* @group progress bar */
+.jp-progress {
+ overflow: hidden;
+ background-color: #ddd; }
+
+.jp-audio .jp-progress {
+ position: absolute;
+ top: 32px;
+ height: 15px; }
+
+.jp-audio .jp-type-single .jp-progress {
+ left: 110px;
+ width: 186px; }
+
+.jp-audio .jp-type-playlist .jp-progress {
+ left: 166px;
+ width: 130px; }
+
+.jp-video .jp-progress {
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 10px; }
+
+.jp-seek-bar {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -202px repeat-x;
+ width: 0px;
+ height: 100%;
+ cursor: pointer; }
+
+.jp-play-bar {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -218px repeat-x;
+ width: 0px;
+ height: 100%; }
+
+/* The seeking class is added/removed inside jPlayer */
+.jp-seeking-bg {
+ background: url("../image/jplayer.blue.monday.seeking.gif"); }
+
+/* @end */
+/* @group volume controls */
+.jp-state-no-volume .jp-volume-controls {
+ display: none; }
+
+.jp-volume-controls {
+ position: absolute;
+ top: 32px;
+ left: 308px;
+ width: 200px; }
+
+.jp-audio-stream .jp-volume-controls {
+ left: 70px; }
+
+.jp-video .jp-volume-controls {
+ top: 12px;
+ left: 50px; }
+
+.jp-volume-controls button {
+ display: block;
+ position: absolute;
+ overflow: hidden;
+ text-indent: -9999px;
+ border: none;
+ cursor: pointer; }
+
+.jp-mute,
+.jp-volume-max {
+ width: 18px;
+ height: 15px; }
+
+.jp-volume-max {
+ left: 74px; }
+
+.jp-mute {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -170px no-repeat; }
+
+.jp-mute:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -19px -170px no-repeat; }
+
+.jp-state-muted .jp-mute {
+ background: url("../image/jplayer.blue.monday.jpg") -60px -170px no-repeat; }
+
+.jp-state-muted .jp-mute:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -79px -170px no-repeat; }
+
+.jp-volume-max {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -186px no-repeat; }
+
+.jp-volume-max:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -19px -186px no-repeat; }
+
+.jp-volume-bar {
+ position: absolute;
+ overflow: hidden;
+ background: url("../image/jplayer.blue.monday.jpg") 0 -250px repeat-x;
+ top: 5px;
+ left: 22px;
+ width: 46px;
+ height: 5px;
+ cursor: pointer; }
+
+.jp-volume-bar-value {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -256px repeat-x;
+ width: 0px;
+ height: 5px; }
+
+/* @end */
+/* @group current time and duration */
+.jp-audio .jp-time-holder {
+ position: absolute;
+ top: 50px; }
+
+.jp-audio .jp-type-single .jp-time-holder {
+ left: 110px;
+ width: 186px; }
+
+.jp-audio .jp-type-playlist .jp-time-holder {
+ left: 166px;
+ width: 130px; }
+
+.jp-current-time,
+.jp-duration {
+ width: 60px;
+ font-size: .64em;
+ font-style: oblique; }
+
+.jp-current-time {
+ float: left;
+ display: inline;
+ cursor: default; }
+
+.jp-duration {
+ float: right;
+ display: inline;
+ text-align: right;
+ cursor: pointer; }
+
+.jp-video .jp-current-time {
+ margin-left: 20px; }
+
+.jp-video .jp-duration {
+ margin-right: 20px; }
+
+/* @end */
+/* @group playlist */
+.jp-details {
+ font-weight: bold;
+ text-align: center;
+ cursor: default; }
+
+.jp-details,
+.jp-playlist {
+ width: 100%;
+ background-color: #ccc;
+ border-top: 1px solid #009be3; }
+
+.jp-type-single .jp-details,
+.jp-type-playlist .jp-details {
+ border-top: none; }
+
+.jp-details .jp-title {
+ margin: 0;
+ padding: 5px 20px;
+ font-size: .72em;
+ font-weight: bold; }
+
+.jp-playlist ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0 20px;
+ font-size: .72em; }
+
+.jp-playlist li {
+ padding: 5px 0 4px 20px;
+ border-bottom: 1px solid #eee; }
+
+.jp-playlist li div {
+ display: inline; }
+
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
+div.jp-type-playlist div.jp-playlist li:last-child {
+ padding: 5px 0 5px 20px;
+ border-bottom: none; }
+
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
+ list-style-type: square;
+ list-style-position: inside;
+ padding-left: 7px; }
+
+div.jp-type-playlist div.jp-playlist a {
+ color: #333;
+ text-decoration: none; }
+
+div.jp-type-playlist div.jp-playlist a:hover {
+ color: #0d88c1; }
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
+ color: #0d88c1; }
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
+ float: right;
+ display: inline;
+ text-align: right;
+ margin-right: 10px;
+ font-weight: bold;
+ color: #666; }
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
+ color: #0d88c1; }
+
+div.jp-type-playlist div.jp-playlist span.jp-free-media {
+ float: right;
+ display: inline;
+ text-align: right;
+ margin-right: 10px; }
+
+div.jp-type-playlist div.jp-playlist span.jp-free-media a {
+ color: #666; }
+
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover {
+ color: #0d88c1; }
+
+span.jp-artist {
+ font-size: .8em;
+ color: #666; }
+
+/* @end */
+.jp-video-play {
+ width: 100%;
+ overflow: hidden;
+ /* Important for nested negative margins to work in modern browsers */
+ cursor: pointer;
+ background-color: transparent;
+ /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */ }
+
+.jp-video-270p .jp-video-play {
+ margin-top: -270px;
+ height: 270px; }
+
+.jp-video-360p .jp-video-play {
+ margin-top: -360px;
+ height: 360px; }
+
+.jp-video-full .jp-video-play {
+ height: 100%; }
+
+.jp-video-play-icon {
+ position: relative;
+ display: block;
+ width: 112px;
+ height: 100px;
+ margin-left: -56px;
+ margin-top: -50px;
+ left: 50%;
+ top: 50%;
+ background: url("../image/jplayer.blue.monday.video.play.png") 0 0 no-repeat;
+ text-indent: -9999px;
+ border: none;
+ cursor: pointer; }
+
+.jp-video-play-icon:focus {
+ background: url("../image/jplayer.blue.monday.video.play.png") 0 -100px no-repeat; }
+
+.jp-jplayer audio,
+.jp-jplayer {
+ width: 0px;
+ height: 0px; }
+
+.jp-jplayer {
+ background-color: #000000; }
+
+/* @group TOGGLES */
+/* The audio toggles are nested inside jp-time-holder */
+.jp-toggles {
+ padding: 0;
+ margin: 0 auto;
+ overflow: hidden; }
+
+.jp-audio .jp-type-single .jp-toggles {
+ width: 25px; }
+
+.jp-audio .jp-type-playlist .jp-toggles {
+ width: 55px;
+ margin: 0;
+ position: absolute;
+ left: 325px;
+ top: 50px; }
+
+.jp-video .jp-toggles {
+ position: absolute;
+ right: 16px;
+ margin: 0;
+ margin-top: 10px;
+ width: 100px; }
+
+.jp-toggles button {
+ display: block;
+ float: left;
+ width: 25px;
+ height: 18px;
+ text-indent: -9999px;
+ line-height: 100%;
+ /* need this for IE6 */
+ border: none;
+ cursor: pointer; }
+
+.jp-full-screen {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -310px no-repeat;
+ margin-left: 20px; }
+
+.jp-full-screen:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -30px -310px no-repeat; }
+
+.jp-state-full-screen .jp-full-screen {
+ background: url("../image/jplayer.blue.monday.jpg") -60px -310px no-repeat; }
+
+.jp-state-full-screen .jp-full-screen:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -90px -310px no-repeat; }
+
+.jp-repeat {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -290px no-repeat; }
+
+.jp-repeat:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -30px -290px no-repeat; }
+
+.jp-state-looped .jp-repeat {
+ background: url("../image/jplayer.blue.monday.jpg") -60px -290px no-repeat; }
+
+.jp-state-looped .jp-repeat:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -90px -290px no-repeat; }
+
+.jp-shuffle {
+ background: url("../image/jplayer.blue.monday.jpg") 0 -270px no-repeat;
+ margin-left: 5px; }
+
+.jp-shuffle:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -30px -270px no-repeat; }
+
+.jp-state-shuffled .jp-shuffle {
+ background: url("../image/jplayer.blue.monday.jpg") -60px -270px no-repeat; }
+
+.jp-state-shuffled .jp-shuffle:focus {
+ background: url("../image/jplayer.blue.monday.jpg") -90px -270px no-repeat; }
+
+/* @end */
+/* @group NO SOLUTION error feedback */
+.jp-no-solution {
+ padding: 5px;
+ font-size: .8em;
+ background-color: #eee;
+ border: 2px solid #009be3;
+ color: #000;
+ display: none; }
+
+.jp-no-solution a {
+ color: #000; }
+
+.jp-no-solution span {
+ font-size: 1em;
+ display: block;
+ text-align: center;
+ font-weight: bold; }
+
+/* @end */
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.min.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.min.css
new file mode 100644
index 00000000..f80584a5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/css/jplayer.blue.monday.min.css
@@ -0,0 +1 @@
+/*! Blue Monday Skin for jPlayer 2.9.2 ~ (c) 2009-2014 Happyworm Ltd ~ MIT License */.jp-audio :focus,.jp-audio-stream :focus,.jp-video :focus{outline:0}.jp-audio button::-moz-focus-inner,.jp-audio-stream button::-moz-focus-inner,.jp-video button::-moz-focus-inner{border:0}.jp-audio,.jp-audio-stream,.jp-video{font-size:16px;font-family:Verdana,Arial,sans-serif;line-height:1.6;color:#666;border:1px solid #009be3;background-color:#eee}.jp-audio{width:420px}.jp-audio-stream{width:182px}.jp-video-270p{width:480px}.jp-video-360p{width:640px}.jp-video-full{width:480px;height:270px;position:static!important;position:relative}.jp-video-full div div{z-index:1000}.jp-video-full .jp-jplayer{top:0;left:0;position:fixed!important;position:relative;overflow:hidden}.jp-video-full .jp-gui{position:fixed!important;position:static;top:0;left:0;width:100%;height:100%;z-index:1001}.jp-video-full .jp-interface{position:absolute!important;position:relative;bottom:0;left:0}.jp-interface{position:relative;background-color:#eee;width:100%}.jp-audio .jp-interface,.jp-audio-stream .jp-interface{height:80px}.jp-video .jp-interface{border-top:1px solid #009be3}.jp-controls-holder{clear:both;width:440px;margin:0 auto;position:relative;overflow:hidden;top:-8px}.jp-interface .jp-controls{margin:0;padding:0;overflow:hidden}.jp-audio .jp-controls{width:380px;padding:20px 20px 0}.jp-audio-stream .jp-controls{position:absolute;top:20px;left:20px;width:142px}.jp-video .jp-type-single .jp-controls{width:78px;margin-left:200px}.jp-video .jp-type-playlist .jp-controls{width:134px;margin-left:172px}.jp-video .jp-controls{float:left}.jp-controls button{display:block;float:left;overflow:hidden;text-indent:-9999px;border:none;cursor:pointer}.jp-play{width:40px;height:40px;background:url(../image/jplayer.blue.monday.jpg) no-repeat}.jp-play:focus{background:url(../image/jplayer.blue.monday.jpg) -41px 0 no-repeat}.jp-state-playing .jp-play{background:url(../image/jplayer.blue.monday.jpg) 0 -42px no-repeat}.jp-state-playing .jp-play:focus{background:url(../image/jplayer.blue.monday.jpg) -41px -42px no-repeat}.jp-next,.jp-previous,.jp-stop{width:28px;height:28px;margin-top:6px}.jp-stop{background:url(../image/jplayer.blue.monday.jpg) 0 -83px no-repeat;margin-left:10px}.jp-stop:focus{background:url(../image/jplayer.blue.monday.jpg) -29px -83px no-repeat}.jp-previous{background:url(../image/jplayer.blue.monday.jpg) 0 -112px no-repeat}.jp-previous:focus{background:url(../image/jplayer.blue.monday.jpg) -29px -112px no-repeat}.jp-next{background:url(../image/jplayer.blue.monday.jpg) 0 -141px no-repeat}.jp-next:focus{background:url(../image/jplayer.blue.monday.jpg) -29px -141px no-repeat}.jp-progress{overflow:hidden;background-color:#ddd}.jp-audio .jp-progress{position:absolute;top:32px;height:15px}.jp-audio .jp-type-single .jp-progress{left:110px;width:186px}.jp-audio .jp-type-playlist .jp-progress{left:166px;width:130px}.jp-video .jp-progress{top:0;left:0;width:100%;height:10px}.jp-seek-bar{background:url(../image/jplayer.blue.monday.jpg) 0 -202px repeat-x;width:0;height:100%;cursor:pointer}.jp-play-bar{background:url(../image/jplayer.blue.monday.jpg) 0 -218px repeat-x;width:0;height:100%}.jp-seeking-bg{background:url(../image/jplayer.blue.monday.seeking.gif)}.jp-state-no-volume .jp-volume-controls{display:none}.jp-volume-controls{position:absolute;top:32px;left:308px;width:200px}.jp-audio-stream .jp-volume-controls{left:70px}.jp-video .jp-volume-controls{top:12px;left:50px}.jp-volume-controls button{display:block;position:absolute;overflow:hidden;text-indent:-9999px;border:none;cursor:pointer}.jp-mute,.jp-volume-max{width:18px;height:15px}.jp-volume-max{left:74px}.jp-mute{background:url(../image/jplayer.blue.monday.jpg) 0 -170px no-repeat}.jp-mute:focus{background:url(../image/jplayer.blue.monday.jpg) -19px -170px no-repeat}.jp-state-muted .jp-mute{background:url(../image/jplayer.blue.monday.jpg) -60px -170px no-repeat}.jp-state-muted .jp-mute:focus{background:url(../image/jplayer.blue.monday.jpg) -79px -170px no-repeat}.jp-volume-max{background:url(../image/jplayer.blue.monday.jpg) 0 -186px no-repeat}.jp-volume-max:focus{background:url(../image/jplayer.blue.monday.jpg) -19px -186px no-repeat}.jp-volume-bar{position:absolute;overflow:hidden;background:url(../image/jplayer.blue.monday.jpg) 0 -250px repeat-x;top:5px;left:22px;width:46px;height:5px;cursor:pointer}.jp-volume-bar-value{background:url(../image/jplayer.blue.monday.jpg) 0 -256px repeat-x;width:0;height:5px}.jp-audio .jp-time-holder{position:absolute;top:50px}.jp-audio .jp-type-single .jp-time-holder{left:110px;width:186px}.jp-audio .jp-type-playlist .jp-time-holder{left:166px;width:130px}.jp-current-time,.jp-duration{width:60px;font-size:.64em;font-style:oblique}.jp-current-time{float:left;display:inline;cursor:default}.jp-duration{float:right;display:inline;text-align:right;cursor:pointer}.jp-video .jp-current-time{margin-left:20px}.jp-video .jp-duration{margin-right:20px}.jp-details{font-weight:700;text-align:center;cursor:default}.jp-details,.jp-playlist{width:100%;background-color:#ccc;border-top:1px solid #009be3}.jp-type-playlist .jp-details,.jp-type-single .jp-details{border-top:none}.jp-details .jp-title{margin:0;padding:5px 20px;font-size:.72em;font-weight:700}.jp-playlist ul{list-style-type:none;margin:0;padding:0 20px;font-size:.72em}.jp-playlist li{padding:5px 0 4px 20px;border-bottom:1px solid #eee}.jp-playlist li div{display:inline}div.jp-type-playlist div.jp-playlist li:last-child{padding:5px 0 5px 20px;border-bottom:none}div.jp-type-playlist div.jp-playlist li.jp-playlist-current{list-style-type:square;list-style-position:inside;padding-left:7px}div.jp-type-playlist div.jp-playlist a{color:#333;text-decoration:none}div.jp-type-playlist div.jp-playlist a.jp-playlist-current,div.jp-type-playlist div.jp-playlist a:hover{color:#0d88c1}div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove{float:right;display:inline;text-align:right;margin-right:10px;font-weight:700;color:#666}div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover{color:#0d88c1}div.jp-type-playlist div.jp-playlist span.jp-free-media{float:right;display:inline;text-align:right;margin-right:10px}div.jp-type-playlist div.jp-playlist span.jp-free-media a{color:#666}div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{color:#0d88c1}span.jp-artist{font-size:.8em;color:#666}.jp-video-play{width:100%;overflow:hidden;cursor:pointer;background-color:transparent}.jp-video-270p .jp-video-play{margin-top:-270px;height:270px}.jp-video-360p .jp-video-play{margin-top:-360px;height:360px}.jp-video-full .jp-video-play{height:100%}.jp-video-play-icon{position:relative;display:block;width:112px;height:100px;margin-left:-56px;margin-top:-50px;left:50%;top:50%;background:url(../image/jplayer.blue.monday.video.play.png) no-repeat;text-indent:-9999px;border:none;cursor:pointer}.jp-video-play-icon:focus{background:url(../image/jplayer.blue.monday.video.play.png) 0 -100px no-repeat}.jp-jplayer,.jp-jplayer audio{width:0;height:0}.jp-jplayer{background-color:#000}.jp-toggles{padding:0;margin:0 auto;overflow:hidden}.jp-audio .jp-type-single .jp-toggles{width:25px}.jp-audio .jp-type-playlist .jp-toggles{width:55px;margin:0;position:absolute;left:325px;top:50px}.jp-video .jp-toggles{position:absolute;right:16px;margin:10px 0 0;width:100px}.jp-toggles button{display:block;float:left;width:25px;height:18px;text-indent:-9999px;line-height:100%;border:none;cursor:pointer}.jp-full-screen{background:url(../image/jplayer.blue.monday.jpg) 0 -310px no-repeat;margin-left:20px}.jp-full-screen:focus{background:url(../image/jplayer.blue.monday.jpg) -30px -310px no-repeat}.jp-state-full-screen .jp-full-screen{background:url(../image/jplayer.blue.monday.jpg) -60px -310px no-repeat}.jp-state-full-screen .jp-full-screen:focus{background:url(../image/jplayer.blue.monday.jpg) -90px -310px no-repeat}.jp-repeat{background:url(../image/jplayer.blue.monday.jpg) 0 -290px no-repeat}.jp-repeat:focus{background:url(../image/jplayer.blue.monday.jpg) -30px -290px no-repeat}.jp-state-looped .jp-repeat{background:url(../image/jplayer.blue.monday.jpg) -60px -290px no-repeat}.jp-state-looped .jp-repeat:focus{background:url(../image/jplayer.blue.monday.jpg) -90px -290px no-repeat}.jp-shuffle{background:url(../image/jplayer.blue.monday.jpg) 0 -270px no-repeat;margin-left:5px}.jp-shuffle:focus{background:url(../image/jplayer.blue.monday.jpg) -30px -270px no-repeat}.jp-state-shuffled .jp-shuffle{background:url(../image/jplayer.blue.monday.jpg) -60px -270px no-repeat}.jp-state-shuffled .jp-shuffle:focus{background:url(../image/jplayer.blue.monday.jpg) -90px -270px no-repeat}.jp-no-solution{padding:5px;font-size:.8em;background-color:#eee;border:2px solid #009be3;color:#000;display:none}.jp-no-solution a{color:#000}.jp-no-solution span{font-size:1em;display:block;text-align:center;font-weight:700} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.jpg b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.jpg
new file mode 100644
index 00000000..adab53ff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.jpg
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.seeking.gif b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.seeking.gif
new file mode 100644
index 00000000..dbd2105a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.seeking.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.video.play.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.video.play.png
new file mode 100644
index 00000000..8e97df01
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/image/jplayer.blue.monday.video.play.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css
new file mode 100644
index 00000000..9b639734
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css
@@ -0,0 +1,640 @@
+/*
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)
+ * http://www.jplayer.org
+ *
+ * Skin Name: Blue Monday
+ *
+ * Copyright (c) 2010-2012 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Silvia Benvenuti
+ * Skin Version: 4.2 (jPlayer 2.2.0)
+ * Date: 22nd October 2012
+ */
+
+div.jp-audio,
+div.jp-audio-stream,
+div.jp-video {
+
+ /* Edit the font-size to counteract inherited font sizing.
+ * Eg. 1.25em = 1 / 0.8em
+ */
+
+ font-size:1.25em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
+
+ font-family:Verdana, Arial, sans-serif;
+ line-height:1.6;
+ color: #666;
+ border:1px solid #009be3;
+ background-color:#eee;
+}
+div.jp-audio {
+ width:420px;
+}
+div.jp-audio-stream {
+ width:182px;
+}
+div.jp-video-270p {
+ width:480px;
+}
+div.jp-video-360p {
+ width:640px;
+}
+div.jp-video-full {
+ /* Rules for IE6 (full-screen) */
+ width:480px;
+ height:270px;
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
+ position:static !important; position:relative
+}
+
+/* The z-index rule is defined in this manner to enable Popcorn plugins that add overlays to video area. EG. Subtitles. */
+div.jp-video-full div div {
+ z-index:1000;
+}
+
+div.jp-video-full div.jp-jplayer {
+ top: 0;
+ left: 0;
+ position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
+ overflow: hidden;
+}
+
+div.jp-video-full div.jp-gui {
+ position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
+ top: 0;
+ left: 0;
+ width:100%;
+ height:100%;
+ z-index:1001; /* 1 layer above the others. */
+}
+
+div.jp-video-full div.jp-interface {
+ position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
+ bottom: 0;
+ left: 0;
+}
+
+div.jp-interface {
+ position: relative;
+ background-color:#eee;
+ width:100%;
+}
+
+div.jp-audio div.jp-type-single div.jp-interface {
+ height:80px;
+}
+div.jp-audio div.jp-type-playlist div.jp-interface {
+ height:80px;
+}
+
+div.jp-audio-stream div.jp-type-single div.jp-interface {
+ height:80px;
+}
+
+div.jp-video div.jp-interface {
+ border-top:1px solid #009be3;
+}
+
+/* @group CONTROLS */
+
+div.jp-controls-holder {
+ clear: both;
+ width:440px;
+ margin:0 auto;
+ position: relative;
+ overflow:hidden;
+ top:-8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
+}
+
+div.jp-interface ul.jp-controls {
+ list-style-type:none;
+ margin:0;
+ padding: 0;
+ overflow:hidden;
+}
+
+div.jp-audio ul.jp-controls {
+ width: 380px;
+ padding:20px 20px 0 20px;
+}
+
+div.jp-audio-stream ul.jp-controls {
+ width: 142px;
+ padding:20px 20px 0 20px;
+}
+
+div.jp-video div.jp-type-single ul.jp-controls {
+ width: 78px;
+ margin-left: 200px;
+}
+
+div.jp-video div.jp-type-playlist ul.jp-controls {
+ width: 134px;
+ margin-left: 172px;
+}
+div.jp-video ul.jp-controls,
+div.jp-interface ul.jp-controls li {
+ display:inline;
+ float: left;
+}
+
+div.jp-interface ul.jp-controls a {
+ display:block;
+ overflow:hidden;
+ text-indent:-9999px;
+}
+a.jp-play,
+a.jp-pause {
+ width:40px;
+ height:40px;
+}
+
+a.jp-play {
+ background: url("jplayer.blue.monday.jpg") 0 0 no-repeat;
+}
+a.jp-play:hover {
+ background: url("jplayer.blue.monday.jpg") -41px 0 no-repeat;
+}
+a.jp-pause {
+ background: url("jplayer.blue.monday.jpg") 0 -42px no-repeat;
+ display: none;
+}
+a.jp-pause:hover {
+ background: url("jplayer.blue.monday.jpg") -41px -42px no-repeat;
+}
+
+a.jp-stop, a.jp-previous, a.jp-next {
+ width:28px;
+ height:28px;
+ margin-top:6px;
+}
+
+a.jp-stop {
+ background: url("jplayer.blue.monday.jpg") 0 -83px no-repeat;
+ margin-left:10px;
+}
+
+a.jp-stop:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -83px no-repeat;
+}
+
+a.jp-previous {
+ background: url("jplayer.blue.monday.jpg") 0 -112px no-repeat;
+}
+a.jp-previous:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -112px no-repeat;
+}
+
+a.jp-next {
+ background: url("jplayer.blue.monday.jpg") 0 -141px no-repeat;
+}
+a.jp-next:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -141px no-repeat;
+}
+
+/* @end */
+
+/* @group progress bar */
+
+div.jp-progress {
+ overflow:hidden;
+ background-color: #ddd;
+}
+div.jp-audio div.jp-progress {
+ position: absolute;
+ top:32px;
+ height:15px;
+}
+div.jp-audio div.jp-type-single div.jp-progress {
+ left:110px;
+ width:186px;
+}
+div.jp-audio div.jp-type-playlist div.jp-progress {
+ left:166px;
+ width:130px;
+}
+div.jp-video div.jp-progress {
+ top:0px;
+ left:0px;
+ width:100%;
+ height:10px;
+}
+div.jp-seek-bar {
+ background: url("jplayer.blue.monday.jpg") 0 -202px repeat-x;
+ width:0px;
+ height:100%;
+ cursor: pointer;
+}
+div.jp-play-bar {
+ background: url("jplayer.blue.monday.jpg") 0 -218px repeat-x ;
+ width:0px;
+ height:100%;
+}
+
+/* The seeking class is added/removed inside jPlayer */
+div.jp-seeking-bg {
+ background: url("jplayer.blue.monday.seeking.gif");
+}
+
+/* @end */
+
+/* @group volume controls */
+
+
+a.jp-mute,
+a.jp-unmute,
+a.jp-volume-max {
+ width:18px;
+ height:15px;
+ margin-top:12px;
+}
+
+div.jp-audio div.jp-type-single a.jp-mute,
+div.jp-audio div.jp-type-single a.jp-unmute {
+ margin-left: 210px;
+}
+div.jp-audio div.jp-type-playlist a.jp-mute,
+div.jp-audio div.jp-type-playlist a.jp-unmute {
+ margin-left: 154px;
+}
+
+div.jp-audio-stream div.jp-type-single a.jp-mute,
+div.jp-audio-stream div.jp-type-single a.jp-unmute {
+ margin-left:10px;
+}
+
+div.jp-audio a.jp-volume-max,
+div.jp-audio-stream a.jp-volume-max {
+ margin-left: 56px;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute,
+div.jp-video a.jp-volume-max {
+ position: absolute;
+ top:12px;
+ margin-top:0;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute {
+ left: 50px;
+}
+
+div.jp-video a.jp-volume-max {
+ left: 134px;
+}
+
+a.jp-mute {
+ background: url("jplayer.blue.monday.jpg") 0 -170px no-repeat;
+}
+a.jp-mute:hover {
+ background: url("jplayer.blue.monday.jpg") -19px -170px no-repeat;
+}
+a.jp-unmute {
+ background: url("jplayer.blue.monday.jpg") -60px -170px no-repeat;
+ display: none;
+}
+a.jp-unmute:hover {
+ background: url("jplayer.blue.monday.jpg") -79px -170px no-repeat;
+}
+a.jp-volume-max {
+ background: url("jplayer.blue.monday.jpg") 0 -186px no-repeat;
+}
+a.jp-volume-max:hover {
+ background: url("jplayer.blue.monday.jpg") -19px -186px no-repeat;
+}
+
+div.jp-volume-bar {
+ position: absolute;
+ overflow:hidden;
+ background: url("jplayer.blue.monday.jpg") 0 -250px repeat-x;
+ width:46px;
+ height:5px;
+ cursor: pointer;
+}
+div.jp-audio div.jp-volume-bar {
+ top:37px;
+ left:330px;
+}
+div.jp-audio-stream div.jp-volume-bar {
+ top:37px;
+ left:92px;
+}
+div.jp-video div.jp-volume-bar {
+ top:17px;
+ left:72px;
+}
+div.jp-volume-bar-value {
+ background: url("jplayer.blue.monday.jpg") 0 -256px repeat-x;
+ width:0px;
+ height:5px;
+}
+
+/* @end */
+
+/* @group current time and duration */
+
+div.jp-audio div.jp-time-holder {
+ position:absolute;
+ top:50px;
+}
+div.jp-audio div.jp-type-single div.jp-time-holder {
+ left:110px;
+ width:186px;
+}
+div.jp-audio div.jp-type-playlist div.jp-time-holder {
+ left:166px;
+ width:130px;
+}
+
+div.jp-current-time,
+div.jp-duration {
+ width:60px;
+ font-size:.64em;
+ font-style:oblique;
+}
+div.jp-current-time {
+ float: left;
+ display:inline;
+}
+div.jp-duration {
+ float: right;
+ display:inline;
+ text-align: right;
+}
+
+div.jp-video div.jp-current-time {
+ margin-left:20px;
+}
+div.jp-video div.jp-duration {
+ margin-right:20px;
+}
+
+/* @end */
+
+/* @group playlist */
+
+div.jp-title {
+ font-weight:bold;
+ text-align:center;
+}
+
+div.jp-title,
+div.jp-playlist {
+ width:100%;
+ background-color:#ccc;
+ border-top:1px solid #009be3;
+}
+div.jp-type-single div.jp-title,
+div.jp-type-playlist div.jp-title,
+div.jp-type-single div.jp-playlist {
+ border-top:none;
+}
+div.jp-title ul,
+div.jp-playlist ul {
+ list-style-type:none;
+ margin:0;
+ padding:0 20px;
+ font-size:.72em;
+}
+
+div.jp-title li {
+ padding:5px 0;
+ font-weight:bold;
+}
+div.jp-playlist li {
+ padding:5px 0 4px 20px;
+ border-bottom:1px solid #eee;
+}
+
+div.jp-playlist li div {
+ display:inline;
+}
+
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
+
+div.jp-type-playlist div.jp-playlist li:last-child {
+ padding:5px 0 5px 20px;
+ border-bottom:none;
+}
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
+ list-style-type:square;
+ list-style-position:inside;
+ padding-left:7px;
+}
+div.jp-type-playlist div.jp-playlist a {
+ color: #333;
+ text-decoration: none;
+}
+div.jp-type-playlist div.jp-playlist a:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
+ color:#0d88c1;
+}
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+ font-weight:bold;
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a{
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
+ color:#0d88c1;
+}
+span.jp-artist {
+ font-size:.8em;
+ color:#666;
+}
+
+/* @end */
+
+div.jp-video-play {
+ width:100%;
+ overflow:hidden; /* Important for nested negative margins to work in modern browsers */
+ cursor:pointer;
+ background-color:rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
+}
+div.jp-video-270p div.jp-video-play {
+ margin-top:-270px;
+ height:270px;
+}
+div.jp-video-360p div.jp-video-play {
+ margin-top:-360px;
+ height:360px;
+}
+div.jp-video-full div.jp-video-play {
+ height:100%;
+}
+a.jp-video-play-icon {
+ position:relative;
+ display:block;
+ width: 112px;
+ height: 100px;
+
+ margin-left:-56px;
+ margin-top:-50px;
+ left:50%;
+ top:50%;
+
+ background: url("jplayer.blue.monday.video.play.png") 0 0 no-repeat;
+ text-indent:-9999px;
+}
+div.jp-video-play:hover a.jp-video-play-icon {
+ background: url("jplayer.blue.monday.video.play.png") 0 -100px no-repeat;
+}
+
+
+
+
+
+div.jp-jplayer audio,
+div.jp-jplayer {
+ width:0px;
+ height:0px;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+}
+
+
+
+
+
+/* @group TOGGLES */
+
+/* The audio toggles are nested inside jp-time-holder */
+
+ul.jp-toggles {
+ list-style-type:none;
+ padding:0;
+ margin:0 auto;
+ overflow:hidden;
+}
+
+div.jp-audio .jp-type-single ul.jp-toggles {
+ width:25px;
+}
+div.jp-audio .jp-type-playlist ul.jp-toggles {
+ width:55px;
+ margin: 0;
+ position: absolute;
+ left: 325px;
+ top: 50px;
+}
+
+div.jp-video ul.jp-toggles {
+ margin-top:10px;
+ width:100px;
+}
+
+ul.jp-toggles li {
+ display:block;
+ float:right;
+}
+
+ul.jp-toggles li a {
+ display:block;
+ width:25px;
+ height:18px;
+ text-indent:-9999px;
+ line-height:100%; /* need this for IE6 */
+}
+
+a.jp-full-screen {
+ background: url("jplayer.blue.monday.jpg") 0 -310px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-full-screen:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -310px no-repeat;
+}
+
+a.jp-restore-screen {
+ background: url("jplayer.blue.monday.jpg") -60px -310px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-restore-screen:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -310px no-repeat;
+}
+
+a.jp-repeat {
+ background: url("jplayer.blue.monday.jpg") 0 -290px no-repeat;
+}
+
+a.jp-repeat:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -290px no-repeat;
+}
+
+a.jp-repeat-off {
+ background: url("jplayer.blue.monday.jpg") -60px -290px no-repeat;
+}
+
+a.jp-repeat-off:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -290px no-repeat;
+}
+
+a.jp-shuffle {
+ background: url("jplayer.blue.monday.jpg") 0 -270px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -270px no-repeat;
+}
+
+a.jp-shuffle-off {
+ background: url("jplayer.blue.monday.jpg") -60px -270px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle-off:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -270px no-repeat;
+}
+
+
+/* @end */
+
+/* @group NO SOLUTION error feedback */
+
+.jp-no-solution {
+ padding:5px;
+ font-size:.8em;
+ background-color:#eee;
+ border:2px solid #009be3;
+ color:#000;
+ display:none;
+}
+
+.jp-no-solution a {
+ color:#000;
+}
+
+.jp-no-solution span {
+ font-size:1em;
+ display:block;
+ text-align:center;
+ font-weight:bold;
+}
+
+/* @end */
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg
new file mode 100644
index 00000000..adab53ff
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif
new file mode 100644
index 00000000..dbd2105a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png
new file mode 100644
index 00000000..8e97df01
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.playlist.html b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.playlist.html
new file mode 100644
index 00000000..2c2d2dd0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.playlist.html
@@ -0,0 +1,42 @@
+<div id="{{JPLAYER}}" class="jp-jplayer"></div>
+<div id="{{WRAPPER}}" class="jp-audio" role="application" aria-label="media player">
+ <div class="jp-type-playlist">
+ <div class="jp-gui jp-interface">
+ <div class="jp-controls">
+ <button class="jp-previous" role="button" tabindex="0">previous</button>
+ <button class="jp-play" role="button" tabindex="0">play</button>
+ <button class="jp-next" role="button" tabindex="0">next</button>
+ <button class="jp-stop" role="button" tabindex="0">stop</button>
+ </div>
+ <div class="jp-progress">
+ <div class="jp-seek-bar">
+ <div class="jp-play-bar"></div>
+ </div>
+ </div>
+ <div class="jp-volume-controls">
+ <button class="jp-mute" role="button" tabindex="0">mute</button>
+ <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ </div>
+ <div class="jp-time-holder">
+ <div class="jp-current-time" role="timer" aria-label="time">&nbsp;</div>
+ <div class="jp-duration" role="timer" aria-label="duration">&nbsp;</div>
+ </div>
+ <div class="jp-toggles">
+ <button class="jp-repeat" role="button" tabindex="0">repeat</button>
+ <button class="jp-shuffle" role="button" tabindex="0">shuffle</button>
+ </div>
+ </div>
+ <div class="jp-playlist">
+ <ul>
+ <li>&nbsp;</li>
+ </ul>
+ </div>
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+</div>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.single.html b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.single.html
new file mode 100644
index 00000000..3b3341fe
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.single.html
@@ -0,0 +1,37 @@
+<div id="{{JPLAYER}}" class="jp-jplayer"></div>
+<div id="{{WRAPPER}}" class="jp-audio" role="application" aria-label="media player">
+ <div class="jp-type-single">
+ <div class="jp-gui jp-interface">
+ <div class="jp-controls">
+ <button class="jp-play" role="button" tabindex="0">play</button>
+ <button class="jp-stop" role="button" tabindex="0">stop</button>
+ </div>
+ <div class="jp-progress">
+ <div class="jp-seek-bar">
+ <div class="jp-play-bar"></div>
+ </div>
+ </div>
+ <div class="jp-volume-controls">
+ <button class="jp-mute" role="button" tabindex="0">mute</button>
+ <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ </div>
+ <div class="jp-time-holder">
+ <div class="jp-current-time" role="timer" aria-label="time">&nbsp;</div>
+ <div class="jp-duration" role="timer" aria-label="duration">&nbsp;</div>
+ <div class="jp-toggles">
+ <button class="jp-repeat" role="button" tabindex="0">repeat</button>
+ </div>
+ </div>
+ </div>
+ <div class="jp-details">
+ <div class="jp-title" aria-label="title">&nbsp;</div>
+ </div>
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+</div>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.stream.html b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.stream.html
new file mode 100644
index 00000000..efeb5048
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.stream.html
@@ -0,0 +1,24 @@
+<div id="{{JPLAYER}}" class="jp-jplayer"></div>
+<div id="{{WRAPPER}}" class="jp-audio-stream" role="application" aria-label="media player">
+ <div class="jp-type-single">
+ <div class="jp-gui jp-interface">
+ <div class="jp-controls">
+ <button class="jp-play" role="button" tabindex="0">play</button>
+ </div>
+ <div class="jp-volume-controls">
+ <button class="jp-mute" role="button" tabindex="0">mute</button>
+ <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ </div>
+ </div>
+ <div class="jp-details">
+ <div class="jp-title" aria-label="title">&nbsp;</div>
+ </div>
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+</div>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.playlist.html b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.playlist.html
new file mode 100644
index 00000000..7ffc474e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.playlist.html
@@ -0,0 +1,52 @@
+<div id="{{WRAPPER}}" class="jp-video " role="application" aria-label="media player">
+ <div class="jp-type-playlist">
+ <div id="{{JPLAYER}}" class="jp-jplayer"></div>
+ <div class="jp-gui">
+ <div class="jp-video-play">
+ <button class="jp-video-play-icon" role="button" tabindex="0">play</button>
+ </div>
+ <div class="jp-interface">
+ <div class="jp-progress">
+ <div class="jp-seek-bar">
+ <div class="jp-play-bar"></div>
+ </div>
+ </div>
+ <div class="jp-current-time" role="timer" aria-label="time">&nbsp;</div>
+ <div class="jp-duration" role="timer" aria-label="duration">&nbsp;</div>
+ <div class="jp-controls-holder">
+ <div class="jp-controls">
+ <button class="jp-previous" role="button" tabindex="0">previous</button>
+ <button class="jp-play" role="button" tabindex="0">play</button>
+ <button class="jp-next" role="button" tabindex="0">next</button>
+ <button class="jp-stop" role="button" tabindex="0">stop</button>
+ </div>
+ <div class="jp-volume-controls">
+ <button class="jp-mute" role="button" tabindex="0">mute</button>
+ <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ </div>
+ <div class="jp-toggles">
+ <button class="jp-repeat" role="button" tabindex="0">repeat</button>
+ <button class="jp-shuffle" role="button" tabindex="0">shuffle</button>
+ <button class="jp-full-screen" role="button" tabindex="0">full screen</button>
+ </div>
+ </div>
+ <div class="jp-details">
+ <div class="jp-title" aria-label="title">&nbsp;</div>
+ </div>
+ </div>
+ </div>
+ <div class="jp-playlist">
+ <ul>
+ <!-- The method Playlist.displayPlaylist() uses this unordered list -->
+ <li>&nbsp;</li>
+ </ul>
+ </div>
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+</div>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.single.html b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.single.html
new file mode 100644
index 00000000..c9a16f83
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/mustache/jplayer.blue.monday.video.single.html
@@ -0,0 +1,43 @@
+<div id="{{WRAPPER}}" class="jp-video " role="application" aria-label="media player">
+ <div class="jp-type-single">
+ <div id="{{JPLAYER}}" class="jp-jplayer"></div>
+ <div class="jp-gui">
+ <div class="jp-video-play">
+ <button class="jp-video-play-icon" role="button" tabindex="0">play</button>
+ </div>
+ <div class="jp-interface">
+ <div class="jp-progress">
+ <div class="jp-seek-bar">
+ <div class="jp-play-bar"></div>
+ </div>
+ </div>
+ <div class="jp-current-time" role="timer" aria-label="time">&nbsp;</div>
+ <div class="jp-duration" role="timer" aria-label="duration">&nbsp;</div>
+ <div class="jp-controls-holder">
+ <div class="jp-controls">
+ <button class="jp-play" role="button" tabindex="0">play</button>
+ <button class="jp-stop" role="button" tabindex="0">stop</button>
+ </div>
+ <div class="jp-volume-controls">
+ <button class="jp-mute" role="button" tabindex="0">mute</button>
+ <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ </div>
+ <div class="jp-toggles">
+ <button class="jp-repeat" role="button" tabindex="0">repeat</button>
+ <button class="jp-full-screen" role="button" tabindex="0">full screen</button>
+ </div>
+ </div>
+ <div class="jp-details">
+ <div class="jp-title" aria-label="title">&nbsp;</div>
+ </div>
+ </div>
+ </div>
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+</div>
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md
new file mode 100644
index 00000000..5587d7f4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md
@@ -0,0 +1,29 @@
+Morning Light
+=========
+Quite a while ago, I found this great jPlayer skin on GitHub. It was nice, simple, and great looking! But what I soon found out was that it was only for jPlayer 2.0.0. That got me thinking, "Hey! Why don't I update it?!". And I did just that!
+
+It actually ended up looking pretty good :D
+
+Compatibility
+=========
+Morning Light will support any jPlayer version from 2.1.0 all the way to the current developmental build. I recommend you keep up to date on your jPlayer installation. Morning Light also uses some CSS3 features such as *border-radius*, *text-shadow*, and *box-shadow* (specifically *box-shdaow: inset*) so it won't show up in IE8 or lower. If you want, you can use [CSS3PIE](http://css3pie.com/) to enable *border-radius* in IE8 and lower but *text-shadow* and *box-shadow: inset* are still a WIP. I'll add support for CSS3PIE as soon as they add more functionality to it.
+
+Licensing
+=========
+This is skin is dual licensed under the MIT and GPL licenses.
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/copyleft/gpl.html
+
+Authors and Contributors
+=========
+This skin was originally created by [persand](https://github.com/persand). He made it for jPlayer 2.0.0 and I simply updated the CSS and added a few more images. I only take 40% credit for this work.
+
+The orginal theme for jPlayer 2.0.0 can be found here - https://github.com/persand/jPlayer-skins
+
+Support or Contact
+=========
+If you are having issues with the skin, please feel free to post in the [Issues](https://github.com/TheInfection/Morning-Light/issues) section on the GitHub repository. I will try my hardest to respond and solve all of your problems.
+
+Also Check Out Midnight Black!
+=========
+If you want a darker jPlayer skin, go check out Midnight Black! - http://theinfection.github.com/Midnight-Black/ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css
new file mode 100644
index 00000000..7ed33c48
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css
@@ -0,0 +1,749 @@
+/*
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)
+ * http://www.happyworm.com/jquery/jplayer
+ *
+ * Skin Name: Morning Light
+ *
+ * Copyright (c) 2012 Per Sandström (https://github.com/persand) and Kasim Ahmic (https://github.com/TheInfection)
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Authors: Per Sandström (Updated to support jPlayer 2.1.0 by Kasim Ahmic)
+ * Skin Version: 2.0 (jPlayer 2.1.0)
+ * Date: April 27th 2012
+ */
+
+*:focus, *:active {
+ outline: none !important;
+}
+
+.noScroll {
+ overflow: hidden !important;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+ margin: auto auto;
+}
+
+div.jp-audio,
+div.jp-audio-stream,
+div.jp-video {
+
+ /* Edit the font-size to counteract inherited font sizing.
+ * Eg. 1.25em = 1 / 0.8em
+ */
+
+ font-size:1em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
+
+ font-family:Verdana, Arial, sans-serif;
+ line-height:1.6;
+ color:#666;
+ border:1px solid #DDD;
+ border-radius:0 0 8px 8px !important;
+ background:transparent;
+ position:relative;
+}
+div.jp-audio {
+ width:480px;
+ border-radius: 8px !important;
+}
+div.jp-audio-stream {
+ width:180px;
+ border-radius: 8px !important;
+}
+div.jp-video-270p {
+ width:480px;
+}
+div.jp-video-360p {
+ width:640px;
+}
+div.jp-video-full {
+ /* Rules for IE6 (full-screen) */
+ width:480px;
+ height:270px;
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
+ position:static !important; position:relative;
+}
+
+div.jp-video-full div.jp-jplayer {
+ top: 0;
+ left: 0;
+ position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
+ overflow: hidden;
+ z-index:1000;
+ margin-left: 0 !important;
+}
+
+div.jp-video-full div.jp-gui {
+ position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
+ top: 0;
+ left: 0;
+ width:100%;
+ height:100%;
+ z-index:1000;
+}
+
+div.jp-video-full div.jp-interface {
+ position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
+ bottom: 0;
+ left: 0;
+ z-index:1000;
+}
+
+div.jp-gui {
+ width: 100%;
+}
+
+div.jp-gui div.jp-interface {
+ border: none !important;
+}
+
+div.jp-interface {
+ width: 100%;
+ position: relative;
+ background: url("jplayer.morning.light.interface.png") repeat-x;
+}
+
+div.jp-audio div.jp-type-single div.jp-interface {
+ height:75px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-audio div.jp-type-playlist div.jp-interface {
+ height:70px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-audio-stream div.jp-type-single div.jp-interface {
+ height:50px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-video div.jp-interface {
+ border:0;
+}
+
+/* @group CONTROLS */
+
+div.jp-controls-holder {
+ clear: both;
+ width:440px;
+ margin:0 auto;
+ position: relative;
+ overflow:hidden;
+ top:-8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
+}
+
+div.jp-interface ul.jp-controls {
+ list-style-type:none;
+ margin:0;
+ padding: 0;
+ overflow:hidden;
+}
+
+div.jp-audio ul.jp-controls {
+ width: auto;
+ padding: 15px 15px 0 10px;
+}
+
+div.jp-audio-stream ul.jp-controls {
+ width: 142px;
+ padding:5px;
+}
+
+div.jp-video div.jp-type-single ul.jp-controls {
+ width: 78px;
+ margin-left: 200px;
+}
+
+div.jp-video div.jp-type-playlist ul.jp-controls {
+ width: 134px;
+ margin-left: 150px;
+}
+div.jp-video ul.jp-controls,
+div.jp-interface ul.jp-controls li {
+ display:inline;
+ float: left;
+}
+
+div.jp-interface ul.jp-controls a {
+ display:block;
+ overflow:hidden;
+ text-indent:-9999px;
+}
+a.jp-play,
+a.jp-pause {
+ width:40px;
+ height:40px;
+}
+
+a.jp-play {
+ background: url("jplayer.morning.light.png") 0 0 no-repeat;
+}
+a.jp-play:hover {
+ background: url("jplayer.morning.light.png") -41px 0 no-repeat;
+}
+a.jp-pause {
+ background: url("jplayer.morning.light.png") 0 -42px no-repeat;
+ display: none;
+}
+a.jp-pause:hover {
+ background: url("jplayer.morning.light.png") -41px -42px no-repeat;
+}
+
+a.jp-stop, a.jp-previous, a.jp-next {
+ width:28px;
+ height:28px;
+ margin-top:6px;
+}
+
+a.jp-stop {
+ background: url("jplayer.morning.light.png") 0 -83px no-repeat;
+ margin-left:10px;
+}
+
+a.jp-stop:hover {
+ background: url("jplayer.morning.light.png") -29px -83px no-repeat;
+}
+
+a.jp-previous {
+ background: url("jplayer.morning.light.png") 0 -112px no-repeat;
+}
+a.jp-previous:hover {
+ background: url("jplayer.morning.light.png") -29px -112px no-repeat;
+}
+
+a.jp-next {
+ background: url("jplayer.morning.light.png") 0 -141px no-repeat;
+}
+a.jp-next:hover {
+ background: url("jplayer.morning.light.png") -29px -141px no-repeat;
+}
+
+/* @end */
+
+/* @group progress bar */
+
+div.jp-progress {
+ overflow:hidden;
+ background: url("jplayer.morning.light.png") 0 -202px repeat-x;
+}
+div.jp-audio div.jp-progress {
+ position: absolute;
+ top:27px;
+ height:15px;
+ border-radius: 5px;
+}
+div.jp-audio div.jp-type-single div.jp-progress {
+ left:100px;
+ right:130px;
+}
+div.jp-audio div.jp-type-playlist div.jp-progress {
+ left:156px;
+ right: 180px;
+}
+div.jp-video div.jp-progress {
+ top:0px;
+ left:0px;
+ width:100%;
+ height:10px;
+}
+div.jp-seek-bar {
+ background: url("jplayer.morning.light.png") 0 -202px repeat-x;
+ width:0px;
+ height:100%;
+ cursor: pointer;
+ border-radius: 5px;
+ box-shadow: inset 0 0 5px #000;
+}
+div.jp-play-bar {
+ background: url("jplayer.morning.light.png") 0 -218px repeat-x ;
+ width:0px;
+ height:100%;
+ border-radius: 4px;
+ box-shadow: inset 0 0 5px #000;
+}
+div.jp-video div.jp-seek-bar {
+ border-radius: 0 !important;
+}
+div.jp-video div.jp-play-bar {
+ border-radius: 0 !important;
+}
+
+
+/* The seeking class is added/removed inside jPlayer */
+div.jp-seeking-bg {
+ background: url("jplayer.morning.light.seeking.gif");
+}
+
+/* @end */
+
+/* @group volume controls */
+
+
+a.jp-mute,
+a.jp-unmute,
+a.jp-volume-max {
+ position: absolute;
+ top: 27px;
+ width:18px;
+ height:15px;
+}
+
+div.jp-audio div.jp-type-single a.jp-mute,
+div.jp-audio div.jp-type-single a.jp-unmute {
+ right: 98px;
+}
+
+div.jp-audio div.jp-type-single a.jp-volume-max {
+ right: 15px;
+}
+
+div.jp-audio div.jp-type-playlist a.jp-mute,
+div.jp-audio div.jp-type-playlist a.jp-unmute {
+ right: 148px;
+}
+
+div.jp-audio div.jp-type-playlist a.jp-volume-max {
+ right: 85px;
+}
+
+div.jp-audio-stream div.jp-type-single a.jp-mute,
+div.jp-audio-stream div.jp-type-single a.jp-unmute {
+ top: 18px;
+ left: 60px;
+}
+
+div.jp-audio-stream a.jp-volume-max {
+ top: 18px;
+ left: 150px;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute,
+div.jp-video a.jp-volume-max {
+ position: absolute;
+ top: 12px;
+ width:18px;
+ height:15px;
+}
+
+div.jp-video div.jp-type-single a.jp-mute,
+div.jp-video div.jp-type-single a.jp-unmute {
+ left: 0px;
+}
+
+div.jp-video div.jp-type-playlist a.jp-mute,
+div.jp-video div.jp-type-playlist a.jp-unmute {
+ left: 0;
+}
+
+div.jp-video div.jp-type-single a.jp-volume-max {
+ left: 160px;
+}
+
+div.jp-video div.jp-type-playlist a.jp-volume-max {
+ left: 128px;
+}
+
+a.jp-mute {
+ background: url("jplayer.morning.light.png") 0 -170px no-repeat;
+}
+a.jp-mute:hover {
+ background: url("jplayer.morning.light.png") -19px -170px no-repeat;
+}
+a.jp-unmute {
+ background: url("jplayer.morning.light.png") -39px -170px no-repeat;
+ display: none;
+}
+a.jp-unmute:hover {
+ background: url("jplayer.morning.light.png") -60px -170px no-repeat;
+}
+
+a.jp-volume-max {
+ background: url("jplayer.morning.light.png") 0 -186px no-repeat;
+}
+a.jp-volume-max:hover {
+ background: url("jplayer.morning.light.png") -19px -186px no-repeat;
+}
+
+div.jp-video div.jp-volume-bar,
+div.jp-audio-stream div.jp-volume-bar,
+div.jp-audio div.jp-volume-bar {
+ position:absolute !important;
+ overflow:hidden;
+ background:url("jplayer.morning.light.png") 0 -250px repeat-x;
+ height:5px;
+ cursor:pointer;
+ border-radius:5px;
+ box-shadow: inset 0 0 3px #000;
+}
+
+div.jp-audio div.jp-type-single div.jp-volume-bar {
+ top:32px;
+ right:45px;
+ width:50px;
+}
+div.jp-audio div.jp-type-playlist div.jp-volume-bar {
+ top:32px;
+ right:110px;
+ width:40px;
+}
+div.jp-audio-stream div.jp-type-single div.jp-volume-bar {
+ width:60px;
+ top:23px;
+ left:80px;
+}
+div.jp-video div.jp-type-single div.jp-volume-bar {
+ top:17px;
+ left:20px;
+ width:130px;
+}
+div.jp-video div.jp-type-playlist div.jp-volume-bar {
+ top:17px;
+ left:20px;
+ width:100px;
+}
+div.jp-volume-bar-value {
+ background:url("jplayer.morning.light.png") 0 -256px repeat-x;
+ width:0px;
+ height:5px;
+ border-radius: 5px;
+ box-shadow: inset 0 0 3px #000;
+}
+
+/* @end */
+
+/* @group current time and duration */
+
+div.jp-audio div.jp-time-holder {
+ position:absolute;
+ top:50px;
+}
+div.jp-audio div.jp-type-single div.jp-time-holder {
+ left:100px;
+ right:130px;
+}
+div.jp-audio div.jp-type-playlist div.jp-time-holder {
+ left:156px;
+ right:180px;
+}
+
+div.jp-current-time,
+div.jp-duration {
+ width:auto;
+ font-size:.64em;
+ font-style:oblique;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+div.jp-current-time {
+ float: left;
+ display:inline;
+ text-align: left;
+}
+div.jp-duration {
+ float: right;
+ display:inline;
+ text-align: right;
+}
+
+div.jp-video div.jp-current-time {
+ margin-left:10px;
+}
+div.jp-video div.jp-duration {
+ margin-right:10px;
+}
+/* @end */
+
+/* @group playlist */
+
+div.jp-title {
+ font-weight:bold;
+ text-align:center;
+ color: #666;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+
+div.jp-video div.jp-title {
+ border: none !important;
+}
+
+div.jp-title,
+div.jp-playlist {
+ background: url("jplayer.morning.light.playlist.png");
+ border-top: none !important;
+ text-align: left !important;
+ width: 100%;
+ border-radius: 0 0 6px 6px !important;
+}
+div.jp-type-single div.jp-title {
+ border-radius: 0 0 6px 6px;
+}
+div.video div.jp-type-single div.jp-playlist div.jp-title {
+ border-radius: 0;
+}
+div.jp-type-single div.jp-title,
+div.jp-type-playlist div.jp-title,
+div.jp-type-single div.jp-playlist {
+ border-top:none;
+}
+div.jp-title ul,
+div.jp-playlist ul {
+ list-style-type:none !important;
+ margin:0;
+ padding:0 0;
+ font-size:.72em;
+}
+
+div.jp-title li {
+ padding:5px 15px 5px 15px;
+ font-weight:bold;
+}
+div.jp-playlist li {
+ padding:5px 15px 5px 15px;
+ border-bottom: 1px solid #DDD;
+ background: url(jplayer.morning.light.playlist.png);
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+
+div.jp-playlist li div {
+ display:inline;
+}
+
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
+
+div.jp-type-playlist div.jp-playlist li:last-child {
+ padding:5px 15px 5px 15px;
+ border-bottom: none !important;
+ border-radius: 0 0 6px 6px !important;
+}
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
+ list-style-type:none;
+ list-style-position:inside;
+ padding-left:15px;
+}
+div.jp-type-playlist div.jp-playlist a {
+ color: #666;
+ text-decoration: none;
+}
+div.jp-type-playlist div.jp-playlist a:hover {
+ color:#0D88C1;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
+ color:#0D88C1;
+ font-weight: bold;
+}
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+ font-weight:bold;
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a{
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
+ color:#0d88c1;
+}
+span.jp-artist {
+ font-size:.8em;
+ color:#666;
+}
+
+/* @end */
+
+div.jp-video-play {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ cursor:pointer;
+ background-color:rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
+}
+div.jp-video-270p div.jp-video-play {
+ height:270px;
+}
+div.jp-video-360p div.jp-video-play {
+ height:360px;
+}
+div.jp-video-full div.jp-video-play {
+ height:100%;
+ z-index:1000;
+}
+a.jp-video-play-icon {
+ position:relative;
+ display:block;
+ width: 112px;
+ height: 100px;
+
+ margin-left:-56px;
+ margin-top:-50px;
+ left:50%;
+ top:50%;
+
+ background: url("jplayer.morning.light.video.play.png") 0 0 no-repeat;
+ text-indent:-9999px;
+}
+div.jp-video-play:hover a.jp-video-play-icon {
+ background: url("jplayer.morning.light.video.play.png") 0 -100px no-repeat;
+}
+
+
+
+
+
+div.jp-jplayer audio,
+div.jp-jplayer {
+ width:0px;
+ height:0px;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+}
+
+
+
+
+
+/* @group TOGGLES */
+
+/* The audio toggles are nested inside jp-time-holder */
+
+ul.jp-toggles {
+ width: 110px;
+ display: block;
+ list-style-type:none;
+ padding:0;
+ margin:0 auto;
+ overflow:hidden;
+}
+
+div.jp-audio .jp-type-single ul.jp-toggles {
+ width:28px;
+ margin: 0 0 0 -14px;
+ position: absolute;
+ left: 50%;
+ top: -5px;
+}
+div.jp-audio .jp-type-playlist ul.jp-toggles {
+ width:65px;
+ margin: 0;
+ position: absolute;
+ right: 8px;
+ top: 22px;
+}
+
+div.jp-video ul.jp-toggles {
+ margin-top:7px;
+ width:110px;
+}
+
+ul.jp-toggles li {
+ display:block;
+ float:right;
+}
+
+ul.jp-toggles li a {
+ display:block;
+ width:28px;
+ height:28px;
+ text-indent:-9999px;
+ line-height:100%; /* need this for IE6 */
+}
+
+a.jp-shuffle {
+ background: url("jplayer.morning.light.png") 0 -262px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle:hover {
+ background: url("jplayer.morning.light.png") -30px -262px no-repeat;
+}
+
+a.jp-shuffle-off {
+ background: url("jplayer.morning.light.png") -60px -262px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle-off:hover {
+ background: url("jplayer.morning.light.png") -90px -262px no-repeat;
+}
+
+a.jp-repeat {
+ background: url("jplayer.morning.light.png") 0 -290px no-repeat;
+}
+
+a.jp-repeat:hover {
+ background: url("jplayer.morning.light.png") -30px -290px no-repeat;
+}
+
+a.jp-repeat-off {
+ background: url("jplayer.morning.light.png") -60px -290px no-repeat;
+}
+
+a.jp-repeat-off:hover {
+ background: url("jplayer.morning.light.png") -90px -290px no-repeat;
+}
+
+a.jp-full-screen {
+ background: url("jplayer.morning.light.png") 0 -318px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-full-screen:hover {
+ background: url("jplayer.morning.light.png") -30px -318px no-repeat;
+}
+
+a.jp-restore-screen {
+ background: url("jplayer.morning.light.png") -60px -318px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-restore-screen:hover {
+ background: url("jplayer.morning.light.png") -90px -318px no-repeat;
+}
+
+
+/* @end */
+
+/* @group NO SOLUTION error feedback */
+
+.jp-no-solution {
+ position:absolute;
+ width:390px;
+ margin-left:-202px;
+ left:50%;
+ top: 10px;
+
+ padding:5px;
+ font-size:.8em;
+ background-color:#eee;
+ border:2px solid #009be3;
+ color:#000;
+ display:none;
+}
+
+.jp-no-solution a {
+ color:#000;
+}
+
+.jp-no-solution span {
+ font-size:1em;
+ display:block;
+ text-align:center;
+ font-weight:bold;
+}
+
+/* @end */
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png
new file mode 100644
index 00000000..901ffc35
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png
new file mode 100644
index 00000000..38c9d755
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png
new file mode 100644
index 00000000..3470f629
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif
new file mode 100644
index 00000000..dbd2105a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png
new file mode 100644
index 00000000..e8d7f896
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js
new file mode 100644
index 00000000..14dd4c64
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js
@@ -0,0 +1,169 @@
+;(function($){
+/**
+ * jqGrid English Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = $.jgrid || {};
+$.extend($.jgrid,{
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "Loading...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Search...",
+ Find: "Find",
+ Reset: "Reset",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Add Record",
+ editCaption: "Edit Record",
+ bSubmit: "Submit",
+ bCancel: "Cancel",
+ bClose: "Close",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Field is required",
+ number:"Please, enter valid number",
+ minValue:"value must be greater than or equal to ",
+ maxValue:"value must be less than or equal to",
+ email: "is not a valid e-mail",
+ integer: "Please, enter valid integer value",
+ date: "Please, enter valid date value",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Delete",
+ msg: "Delete selected record(s)?",
+ bSubmit: "Delete",
+ bCancel: "Cancel"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Edit selected row",
+ addtext:"",
+ addtitle: "Add new row",
+ deltext: "",
+ deltitle: "Delete selected row",
+ searchtext: "",
+ searchtitle: "Find records",
+ refreshtext: "",
+ refreshtitle: "Reload Grid",
+ alertcap: "Warning",
+ alerttext: "Please, select row",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Select columns",
+ bSubmit: "Ok",
+ bCancel: "Cancel"
+ },
+ errors : {
+ errcap : "Error",
+ nourl : "No url is set",
+ norecords: "No records to process",
+ model : "Length of colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ",", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th';},
+ srcformat: 'Y-m-d',
+ newformat: 'n/j/Y',
+ masks : {
+ // see http://php.net/manual/en/function.date.php for PHP format used in jqGrid
+ // and see http://docs.jquery.com/UI/Datepicker/formatDate
+ // and https://github.com/jquery/globalize#dates for alternative formats used frequently
+ // one can find on https://github.com/jquery/globalize/tree/master/lib/cultures many
+ // information about date, time, numbers and currency formats used in different countries
+ // one should just convert the information in PHP format
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ // short date:
+ // n - Numeric representation of a month, without leading zeros
+ // j - Day of the month without leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ // example: 3/1/2012 which means 1 March 2012
+ ShortDate: "n/j/Y", // in jQuery UI Datepicker: "M/d/yyyy"
+ // long date:
+ // l - A full textual representation of the day of the week
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ LongDate: "l, F d, Y", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy"
+ // long date with long time:
+ // l - A full textual representation of the day of the week
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // s - Seconds, with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ FullDateTime: "l, F d, Y g:i:s A", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy h:mm:ss tt"
+ // month day:
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ MonthDay: "F d", // in jQuery UI Datepicker: "MMMM dd"
+ // short time (without seconds)
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ ShortTime: "g:i A", // in jQuery UI Datepicker: "h:mm tt"
+ // long time (with seconds)
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // s - Seconds, with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ LongTime: "g:i:s A", // in jQuery UI Datepicker: "h:mm:ss tt"
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ // month with year
+ // Y - A full numeric representation of a year, 4 digits
+ // F - A full textual representation of a month
+ YearMonth: "F, Y" // in jQuery UI Datepicker: "MMMM, yyyy"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+});
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js
new file mode 100644
index 00000000..e89e54d4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js
@@ -0,0 +1,516 @@
+/*
+* jqGrid 4.4.0 - jQuery Grid
+* Copyright (c) 2008, Tony Tomov, tony@trirand.com
+* Dual licensed under the MIT and GPL licenses
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl-2.0.html
+* Date:2012-06-14
+* Modules: grid.base.js; jquery.fmatter.js; grid.custom.js; grid.common.js; grid.formedit.js; grid.filter.js; grid.inlinedit.js; grid.celledit.js; jqModal.js; jqDnR.js; grid.subgrid.js; grid.grouping.js; grid.treegrid.js; grid.import.js; JsonXml.js; grid.tbltogrid.js; grid.jqueryui.js;
+*/
+(function(b){b.jgrid=b.jgrid||{};b.extend(b.jgrid,{version:"4.4.0",htmlDecode:function(b){return b&&("&nbsp;"==b||"&#160;"==b||1===b.length&&160===b.charCodeAt(0))?"":!b?b:(""+b).replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&quot;/g,'"').replace(/&amp;/g,"&")},htmlEncode:function(b){return!b?b:(""+b).replace(/&/g,"&amp;").replace(/\"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},format:function(f){var e=b.makeArray(arguments).slice(1);void 0===f&&(f="");return f.replace(/\{(\d+)\}/g,
+function(b,d){return e[d]})},getCellIndex:function(f){f=b(f);if(f.is("tr"))return-1;f=(!f.is("td")&&!f.is("th")?f.closest("td,th"):f)[0];return b.browser.msie?b.inArray(f,f.parentNode.cells):f.cellIndex},stripHtml:function(b){var b=b+"",e=/<("[^"]*"|'[^']*'|[^'">])*>/gi;return b?(b=b.replace(e,""))&&"&nbsp;"!==b&&"&#160;"!==b?b.replace(/\"/g,"'"):"":b},stripPref:function(f,e){var c=b.type(f);if("string"==c||"number"==c)f=""+f,e=""!==f?(""+e).replace(""+f,""):e;return e},stringToDoc:function(b){var e;
+if("string"!==typeof b)return b;try{e=(new DOMParser).parseFromString(b,"text/xml")}catch(c){e=new ActiveXObject("Microsoft.XMLDOM"),e.async=!1,e.loadXML(b)}return e&&e.documentElement&&"parsererror"!=e.documentElement.tagName?e:null},parse:function(f){"while(1);"==f.substr(0,9)&&(f=f.substr(9));"/*"==f.substr(0,2)&&(f=f.substr(2,f.length-4));f||(f="{}");return!0===b.jgrid.useJSON&&"object"===typeof JSON&&"function"===typeof JSON.parse?JSON.parse(f):eval("("+f+")")},parseDate:function(f,e){var c=
+{m:1,d:1,y:1970,h:0,i:0,s:0,u:0},d,a,h;d=/[\\\/:_;.,\t\T\s-]/;if(e&&null!==e&&void 0!==e){e=b.trim(e);e=e.split(d);void 0!==b.jgrid.formatter.date.masks[f]&&(f=b.jgrid.formatter.date.masks[f]);var f=f.split(d),g=b.jgrid.formatter.date.monthNames,i=b.jgrid.formatter.date.AmPm,j=function(a,b){0===a?12===b&&(b=0):12!==b&&(b+=12);return b};d=0;for(a=f.length;d<a;d++)"M"==f[d]&&(h=b.inArray(e[d],g),-1!==h&&12>h&&(e[d]=h+1,c.m=e[d])),"F"==f[d]&&(h=b.inArray(e[d],g),-1!==h&&11<h&&(e[d]=h+1-12,c.m=e[d])),
+"a"==f[d]&&(h=b.inArray(e[d],i),-1!==h&&2>h&&e[d]==i[h]&&(e[d]=h,c.h=j(e[d],c.h))),"A"==f[d]&&(h=b.inArray(e[d],i),-1!==h&&1<h&&e[d]==i[h]&&(e[d]=h-2,c.h=j(e[d],c.h))),void 0!==e[d]&&(c[f[d].toLowerCase()]=parseInt(e[d],10));c.m=parseInt(c.m,10)-1;d=c.y;70<=d&&99>=d?c.y=1900+c.y:0<=d&&69>=d&&(c.y=2E3+c.y);void 0!==c.j&&(c.d=c.j);void 0!==c.n&&(c.m=parseInt(c.n,10)-1)}return new Date(c.y,c.m,c.d,c.h,c.i,c.s,c.u)},jqID:function(b){return(""+b).replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},
+guid:1,uidPref:"jqg",randId:function(f){return(f?f:b.jgrid.uidPref)+b.jgrid.guid++},getAccessor:function(b,e){var c,d,a=[],h;if("function"===typeof e)return e(b);c=b[e];if(void 0===c)try{if("string"===typeof e&&(a=e.split(".")),h=a.length)for(c=b;c&&h--;)d=a.shift(),c=c[d]}catch(g){}return c},getXmlData:function(f,e,c){var d="string"===typeof e?e.match(/^(.*)\[(\w+)\]$/):null;if("function"===typeof e)return e(f);if(d&&d[2])return d[1]?b(d[1],f).attr(d[2]):b(f).attr(d[2]);f=b(e,f);return c?f:0<f.length?
+b(f).text():void 0},cellWidth:function(){var f=b("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;'></td></tr></table></div>"),e=f.appendTo("body").find("td").width();f.remove();return 5!==e},ajaxOptions:{},from:function(f){return new function(e,c){"string"==typeof e&&(e=b.data(e));var d=this,a=e,h=!0,f=!1,i=c,j=/[\$,%]/g,l=null,k=null,m=0,o=!1,p="",v=[],u=!0;if("object"==typeof e&&e.push)0<e.length&&(u="object"!=
+typeof e[0]?!1:!0);else throw"data provides is not an array";this._hasData=function(){return null===a?!1:0===a.length?!1:!0};this._getStr=function(a){var b=[];f&&b.push("jQuery.trim(");b.push("String("+a+")");f&&b.push(")");h||b.push(".toLowerCase()");return b.join("")};this._strComp=function(a){return"string"==typeof a?".toString()":""};this._group=function(a,b){return{field:a.toString(),unique:b,items:[]}};this._toStr=function(a){f&&(a=b.trim(a));a=a.toString().replace(/\\/g,"\\\\").replace(/\"/g,
+'\\"');return h?a:a.toLowerCase()};this._funcLoop=function(d){var c=[];b.each(a,function(a,b){c.push(d(b))});return c};this._append=function(a){var b;i=null===i?"":i+(""===p?" && ":p);for(b=0;b<m;b++)i+="(";o&&(i+="!");i+="("+a+")";o=!1;p="";m=0};this._setCommand=function(a,b){l=a;k=b};this._resetNegate=function(){o=!1};this._repeatCommand=function(a,b){return null===l?d:null!==a&&null!==b?l(a,b):null===k||!u?l(a):l(k,a)};this._equals=function(a,b){return 0===d._compare(a,b,1)};this._compare=function(a,
+b,d){var c=Object.prototype.toString;void 0===d&&(d=1);void 0===a&&(a=null);void 0===b&&(b=null);if(null===a&&null===b)return 0;if(null===a&&null!==b)return 1;if(null!==a&&null===b)return-1;if("[object Date]"===c.call(a)&&"[object Date]"===c.call(b))return a<b?-d:a>b?d:0;!h&&"number"!==typeof a&&"number"!==typeof b&&(a=(""+a).toLowerCase(),b=(""+b).toLowerCase());return a<b?-d:a>b?d:0};this._performSort=function(){0!==v.length&&(a=d._doSort(a,0))};this._doSort=function(a,b){var c=v[b].by,f=v[b].dir,
+h=v[b].type,e=v[b].datefmt;if(b==v.length-1)return d._getOrder(a,c,f,h,e);b++;c=d._getGroup(a,c,f,h,e);f=[];for(h=0;h<c.length;h++)for(var e=d._doSort(c[h].items,b),g=0;g<e.length;g++)f.push(e[g]);return f};this._getOrder=function(a,c,h,f,e){var g=[],i=[],l="a"==h?1:-1,k,m;void 0===f&&(f="text");m="float"==f||"number"==f||"currency"==f||"numeric"==f?function(a){a=parseFloat((""+a).replace(j,""));return isNaN(a)?0:a}:"int"==f||"integer"==f?function(a){return a?parseFloat((""+a).replace(j,"")):0}:"date"==
+f||"datetime"==f?function(a){return b.jgrid.parseDate(e,a).getTime()}:b.isFunction(f)?f:function(a){a||(a="");return b.trim((""+a).toUpperCase())};b.each(a,function(a,d){k=""!==c?b.jgrid.getAccessor(d,c):d;void 0===k&&(k="");k=m(k,d);i.push({vSort:k,index:a})});i.sort(function(a,b){a=a.vSort;b=b.vSort;return d._compare(a,b,l)});for(var f=0,o=a.length;f<o;)h=i[f].index,g.push(a[h]),f++;return g};this._getGroup=function(a,c,f,h,e){var g=[],i=null,j=null,k;b.each(d._getOrder(a,c,f,h,e),function(a,f){k=
+b.jgrid.getAccessor(f,c);void 0===k&&(k="");d._equals(j,k)||(j=k,null!==i&&g.push(i),i=d._group(c,k));i.items.push(f)});null!==i&&g.push(i);return g};this.ignoreCase=function(){h=!1;return d};this.useCase=function(){h=!0;return d};this.trim=function(){f=!0;return d};this.noTrim=function(){f=!1;return d};this.execute=function(){var c=i,f=[];if(null===c)return d;b.each(a,function(){eval(c)&&f.push(this)});a=f;return d};this.data=function(){return a};this.select=function(c){d._performSort();if(!d._hasData())return[];
+d.execute();if(b.isFunction(c)){var f=[];b.each(a,function(a,b){f.push(c(b))});return f}return a};this.hasMatch=function(){if(!d._hasData())return!1;d.execute();return 0<a.length};this.andNot=function(a,b,c){o=!o;return d.and(a,b,c)};this.orNot=function(a,b,c){o=!o;return d.or(a,b,c)};this.not=function(a,b,c){return d.andNot(a,b,c)};this.and=function(a,b,c){p=" && ";return void 0===a?d:d._repeatCommand(a,b,c)};this.or=function(a,b,c){p=" || ";return void 0===a?d:d._repeatCommand(a,b,c)};this.orBegin=
+function(){m++;return d};this.orEnd=function(){null!==i&&(i+=")");return d};this.isNot=function(a){o=!o;return d.is(a)};this.is=function(a){d._append("this."+a);d._resetNegate();return d};this._compareValues=function(a,c,f,h,e){var g;g=u?"jQuery.jgrid.getAccessor(this,'"+c+"')":"this";void 0===f&&(f=null);var i=f,k=void 0===e.stype?"text":e.stype;if(null!==f)switch(k){case "int":case "integer":i=isNaN(Number(i))||""===i?"0":i;g="parseInt("+g+",10)";i="parseInt("+i+",10)";break;case "float":case "number":case "numeric":i=
+(""+i).replace(j,"");i=isNaN(Number(i))||""===i?"0":i;g="parseFloat("+g+")";i="parseFloat("+i+")";break;case "date":case "datetime":i=""+b.jgrid.parseDate(e.newfmt||"Y-m-d",i).getTime();g='jQuery.jgrid.parseDate("'+e.srcfmt+'",'+g+").getTime()";break;default:g=d._getStr(g),i=d._getStr('"'+d._toStr(i)+'"')}d._append(g+" "+h+" "+i);d._setCommand(a,c);d._resetNegate();return d};this.equals=function(a,b,c){return d._compareValues(d.equals,a,b,"==",c)};this.notEquals=function(a,b,c){return d._compareValues(d.equals,
+a,b,"!==",c)};this.isNull=function(a,b,c){return d._compareValues(d.equals,a,null,"===",c)};this.greater=function(a,b,c){return d._compareValues(d.greater,a,b,">",c)};this.less=function(a,b,c){return d._compareValues(d.less,a,b,"<",c)};this.greaterOrEquals=function(a,b,c){return d._compareValues(d.greaterOrEquals,a,b,">=",c)};this.lessOrEquals=function(a,b,c){return d._compareValues(d.lessOrEquals,a,b,"<=",c)};this.startsWith=function(a,c){var h=void 0===c||null===c?a:c,h=f?b.trim(h.toString()).length:
+h.toString().length;u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+".substr(0,"+h+") == "+d._getStr('"'+d._toStr(c)+'"')):(h=f?b.trim(c.toString()).length:c.toString().length,d._append(d._getStr("this")+".substr(0,"+h+") == "+d._getStr('"'+d._toStr(a)+'"')));d._setCommand(d.startsWith,a);d._resetNegate();return d};this.endsWith=function(a,c){var h=void 0===c||null===c?a:c,h=f?b.trim(h.toString()).length:h.toString().length;u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+
+"')")+".substr("+d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+".length-"+h+","+h+') == "'+d._toStr(c)+'"'):d._append(d._getStr("this")+".substr("+d._getStr("this")+'.length-"'+d._toStr(a)+'".length,"'+d._toStr(a)+'".length) == "'+d._toStr(a)+'"');d._setCommand(d.endsWith,a);d._resetNegate();return d};this.contains=function(a,b){u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+'.indexOf("'+d._toStr(b)+'",0) > -1'):d._append(d._getStr("this")+'.indexOf("'+d._toStr(a)+'",0) > -1');
+d._setCommand(d.contains,a);d._resetNegate();return d};this.groupBy=function(b,c,f,h){return!d._hasData()?null:d._getGroup(a,b,c,f,h)};this.orderBy=function(a,c,f,h){c=void 0===c||null===c?"a":b.trim(c.toString().toLowerCase());if(null===f||void 0===f)f="text";if(null===h||void 0===h)h="Y-m-d";if("desc"==c||"descending"==c)c="d";if("asc"==c||"ascending"==c)c="a";v.push({by:a,dir:c,type:f,datefmt:h});return d};return d}(f,null)},extend:function(f){b.extend(b.fn.jqGrid,f);this.no_legacy_api||b.fn.extend(f)}});
+b.fn.jqGrid=function(f){if("string"==typeof f){var e=b.jgrid.getAccessor(b.fn.jqGrid,f);if(!e)throw"jqGrid - No such method: "+f;var c=b.makeArray(arguments).slice(1);return e.apply(this,c)}return this.each(function(){if(!this.grid){var d=b.extend(!0,{url:"",height:150,page:1,rowNum:20,rowTotal:null,records:0,pager:"",pgbuttons:!0,pginput:!0,colModel:[],rowList:[],colNames:[],sortorder:"asc",sortname:"",datatype:"xml",mtype:"GET",altRows:!1,selarrrow:[],savedRow:[],shrinkToFit:!0,xmlReader:{},jsonReader:{},
+subGrid:!1,subGridModel:[],reccount:0,lastpage:0,lastsort:0,selrow:null,beforeSelectRow:null,onSelectRow:null,onSortCol:null,ondblClickRow:null,onRightClickRow:null,onPaging:null,onSelectAll:null,loadComplete:null,gridComplete:null,loadError:null,loadBeforeSend:null,afterInsertRow:null,beforeRequest:null,beforeProcessing:null,onHeaderClick:null,viewrecords:!1,loadonce:!1,multiselect:!1,multikey:!1,editurl:null,search:!1,caption:"",hidegrid:!0,hiddengrid:!1,postData:{},userData:{},treeGrid:!1,treeGridModel:"nested",
+treeReader:{},treeANode:-1,ExpandColumn:null,tree_root_level:0,prmNames:{page:"page",rows:"rows",sort:"sidx",order:"sord",search:"_search",nd:"nd",id:"id",oper:"oper",editoper:"edit",addoper:"add",deloper:"del",subgridid:"id",npage:null,totalrows:"totalrows"},forceFit:!1,gridstate:"visible",cellEdit:!1,cellsubmit:"remote",nv:0,loadui:"enable",toolbar:[!1,""],scroll:!1,multiboxonly:!1,deselectAfterSort:!0,scrollrows:!1,autowidth:!1,scrollOffset:18,cellLayout:5,subGridWidth:20,multiselectWidth:20,gridview:!1,
+rownumWidth:25,rownumbers:!1,pagerpos:"center",recordpos:"right",footerrow:!1,userDataOnFooter:!1,hoverrows:!0,altclass:"ui-priority-secondary",viewsortcols:[!1,"vertical",!0],resizeclass:"",autoencode:!1,remapColumns:[],ajaxGridOptions:{},direction:"ltr",toppager:!1,headertitles:!1,scrollTimeout:40,data:[],_index:{},grouping:!1,groupingView:{groupField:[],groupOrder:[],groupText:[],groupColumnShow:[],groupSummary:[],showSummaryOnHide:!1,sortitems:[],sortnames:[],summary:[],summaryval:[],plusicon:"ui-icon-circlesmall-plus",
+minusicon:"ui-icon-circlesmall-minus"},ignoreCase:!1,cmTemplate:{},idPrefix:""},b.jgrid.defaults,f||{}),a=this,c={headers:[],cols:[],footers:[],dragStart:function(c,e,f){this.resizing={idx:c,startX:e.clientX,sOL:f[0]};this.hDiv.style.cursor="col-resize";this.curGbox=b("#rs_m"+b.jgrid.jqID(d.id),"#gbox_"+b.jgrid.jqID(d.id));this.curGbox.css({display:"block",left:f[0],top:f[1],height:f[2]});b(a).triggerHandler("jqGridResizeStart",[e,c]);b.isFunction(d.resizeStart)&&d.resizeStart.call(this,e,c);document.onselectstart=
+function(){return!1}},dragMove:function(a){if(this.resizing){var b=a.clientX-this.resizing.startX,a=this.headers[this.resizing.idx],c="ltr"===d.direction?a.width+b:a.width-b,e;33<c&&(this.curGbox.css({left:this.resizing.sOL+b}),!0===d.forceFit?(e=this.headers[this.resizing.idx+d.nv],b="ltr"===d.direction?e.width-b:e.width+b,33<b&&(a.newWidth=c,e.newWidth=b)):(this.newWidth="ltr"===d.direction?d.tblwidth+b:d.tblwidth-b,a.newWidth=c))}},dragEnd:function(){this.hDiv.style.cursor="default";if(this.resizing){var c=
+this.resizing.idx,e=this.headers[c].newWidth||this.headers[c].width,e=parseInt(e,10);this.resizing=!1;b("#rs_m"+b.jgrid.jqID(d.id)).css("display","none");d.colModel[c].width=e;this.headers[c].width=e;this.headers[c].el.style.width=e+"px";this.cols[c].style.width=e+"px";0<this.footers.length&&(this.footers[c].style.width=e+"px");!0===d.forceFit?(e=this.headers[c+d.nv].newWidth||this.headers[c+d.nv].width,this.headers[c+d.nv].width=e,this.headers[c+d.nv].el.style.width=e+"px",this.cols[c+d.nv].style.width=
+e+"px",0<this.footers.length&&(this.footers[c+d.nv].style.width=e+"px"),d.colModel[c+d.nv].width=e):(d.tblwidth=this.newWidth||d.tblwidth,b("table:first",this.bDiv).css("width",d.tblwidth+"px"),b("table:first",this.hDiv).css("width",d.tblwidth+"px"),this.hDiv.scrollLeft=this.bDiv.scrollLeft,d.footerrow&&(b("table:first",this.sDiv).css("width",d.tblwidth+"px"),this.sDiv.scrollLeft=this.bDiv.scrollLeft));b(a).triggerHandler("jqGridResizeStop",[e,c]);b.isFunction(d.resizeStop)&&d.resizeStop.call(this,
+e,c)}this.curGbox=null;document.onselectstart=function(){return!0}},populateVisible:function(){c.timer&&clearTimeout(c.timer);c.timer=null;var a=b(c.bDiv).height();if(a){var e=b("table:first",c.bDiv),f,G;if(e[0].rows.length)try{G=(f=e[0].rows[1])?b(f).outerHeight()||c.prevRowHeight:c.prevRowHeight}catch(g){G=c.prevRowHeight}if(G){c.prevRowHeight=G;var i=d.rowNum;f=c.scrollTop=c.bDiv.scrollTop;var j=Math.round(e.position().top)-f,k=j+e.height();G*=i;var y,z,B;if(k<a&&0>=j&&(void 0===d.lastpage||parseInt((k+
+f+G-1)/G,10)<=d.lastpage))z=parseInt((a-k+G-1)/G,10),0<=k||2>z||!0===d.scroll?(y=Math.round((k+f)/G)+1,j=-1):j=1;0<j&&(y=parseInt(f/G,10)+1,z=parseInt((f+a)/G,10)+2-y,B=!0);if(z&&!(d.lastpage&&y>d.lastpage||1==d.lastpage||y===d.page&&y===d.lastpage))c.hDiv.loading?c.timer=setTimeout(c.populateVisible,d.scrollTimeout):(d.page=y,B&&(c.selectionPreserver(e[0]),c.emptyRows.call(e[0],!1,!1)),c.populate(z))}}},scrollGrid:function(a){if(d.scroll){var b=c.bDiv.scrollTop;void 0===c.scrollTop&&(c.scrollTop=
+0);b!=c.scrollTop&&(c.scrollTop=b,c.timer&&clearTimeout(c.timer),c.timer=setTimeout(c.populateVisible,d.scrollTimeout))}c.hDiv.scrollLeft=c.bDiv.scrollLeft;d.footerrow&&(c.sDiv.scrollLeft=c.bDiv.scrollLeft);a&&a.stopPropagation()},selectionPreserver:function(a){var c=a.p,d=c.selrow,e=c.selarrrow?b.makeArray(c.selarrrow):null,f=a.grid.bDiv.scrollLeft,g=function(){var h;c.selrow=null;c.selarrrow=[];if(c.multiselect&&e&&0<e.length)for(h=0;h<e.length;h++)e[h]!=d&&b(a).jqGrid("setSelection",e[h],!1,null);
+d&&b(a).jqGrid("setSelection",d,!1,null);a.grid.bDiv.scrollLeft=f;b(a).unbind(".selectionPreserver",g)};b(a).bind("jqGridGridComplete.selectionPreserver",g)}};if("TABLE"!=this.tagName.toUpperCase())alert("Element is not a table");else if(void 0!==document.documentMode&&5>=document.documentMode)alert("Grid can not be used in this ('quirks') mode!");else{b(this).empty().attr("tabindex","1");this.p=d;this.p.useProp=!!b.fn.prop;var e,i;if(0===this.p.colNames.length)for(e=0;e<this.p.colModel.length;e++)this.p.colNames[e]=
+this.p.colModel[e].label||this.p.colModel[e].name;if(this.p.colNames.length!==this.p.colModel.length)alert(b.jgrid.errors.model);else{var j=b("<div class='ui-jqgrid-view'></div>"),l,k=b.browser.msie?!0:!1;a.p.direction=b.trim(a.p.direction.toLowerCase());-1==b.inArray(a.p.direction,["ltr","rtl"])&&(a.p.direction="ltr");i=a.p.direction;b(j).insertBefore(this);b(this).appendTo(j).removeClass("scroll");var m=b("<div class='ui-jqgrid ui-widget ui-widget-content ui-corner-all'></div>");b(m).insertBefore(j).attr({id:"gbox_"+
+this.id,dir:i});b(j).appendTo(m).attr("id","gview_"+this.id);l=k&&6>=b.browser.version?'<iframe style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=\'0\');" src="javascript:false;"></iframe>':"";b("<div class='ui-widget-overlay jqgrid-overlay' id='lui_"+this.id+"'></div>").append(l).insertBefore(j);b("<div class='loading ui-state-default ui-state-active' id='load_"+this.id+"'>"+this.p.loadtext+"</div>").insertBefore(j);b(this).attr({cellspacing:"0",cellpadding:"0",border:"0",role:"grid",
+"aria-multiselectable":!!this.p.multiselect,"aria-labelledby":"gbox_"+this.id});var o=function(a,b){a=parseInt(a,10);return isNaN(a)?b?b:0:a},p=function(d,e,f,g,i,j){var K=a.p.colModel[d],k=K.align,y='style="',z=K.classes,B=K.name,q=[];k&&(y=y+("text-align:"+k+";"));K.hidden===true&&(y=y+"display:none;");if(e===0)y=y+("width: "+c.headers[d].width+"px;");else if(K.cellattr&&b.isFunction(K.cellattr))if((d=K.cellattr.call(a,i,f,g,K,j))&&typeof d==="string"){d=d.replace(/style/i,"style").replace(/title/i,
+"title");if(d.indexOf("title")>-1)K.title=false;d.indexOf("class")>-1&&(z=void 0);q=d.split("style");if(q.length===2){q[1]=b.trim(q[1].replace("=",""));if(q[1].indexOf("'")===0||q[1].indexOf('"')===0)q[1]=q[1].substring(1);y=y+q[1].replace(/'/gi,'"')}else y=y+'"'}if(!q.length){q[0]="";y=y+'"'}y=y+((z!==void 0?' class="'+z+'"':"")+(K.title&&f?' title="'+b.jgrid.stripHtml(f)+'"':""));y=y+(' aria-describedby="'+a.p.id+"_"+B+'"');return y+q[0]},v=function(c){return c===void 0||c===null||c===""?"&#160;":
+a.p.autoencode?b.jgrid.htmlEncode(c):c+""},u=function(c,d,e,f,g){var h=a.p.colModel[e];if(typeof h.formatter!=="undefined"){c={rowId:c,colModel:h,gid:a.p.id,pos:e};d=b.isFunction(h.formatter)?h.formatter.call(a,d,c,f,g):b.fmatter?b.fn.fmatter.call(a,h.formatter,d,c,f,g):v(d)}else d=v(d);return d},M=function(a,b,c,d,e){b=u(a,b,c,e,"add");return'<td role="gridcell" '+p(c,d,b,e,a,true)+">"+b+"</td>"},F=function(b,c,d){var e='<input role="checkbox" type="checkbox" id="jqg_'+a.p.id+"_"+b+'" class="cbox" name="jqg_'+
+a.p.id+"_"+b+'"/>';return'<td role="gridcell" '+p(c,d,"",null,b,true)+">"+e+"</td>"},Z=function(a,b,c,d){c=(parseInt(c,10)-1)*parseInt(d,10)+1+b;return'<td role="gridcell" class="ui-state-default jqgrid-rownum" '+p(a,b,c,null,b,true)+">"+c+"</td>"},U=function(b){var c,d=[],e=0,f;for(f=0;f<a.p.colModel.length;f++){c=a.p.colModel[f];if(c.name!=="cb"&&c.name!=="subgrid"&&c.name!=="rn"){d[e]=b=="local"?c.name:b=="xml"||b==="xmlstring"?c.xmlmap||c.name:c.jsonmap||c.name;e++}}return d},V=function(c){var d=
+a.p.remapColumns;if(!d||!d.length)d=b.map(a.p.colModel,function(a,b){return b});c&&(d=b.map(d,function(a){return a<c?null:a-c}));return d},N=function(a,c){var d;if(this.p.deepempty)b(this.rows).slice(1).remove();else{d=this.rows.length>0?this.rows[0]:null;b(this.firstChild).empty().append(d)}if(a&&this.p.scroll){b(this.grid.bDiv.firstChild).css({height:"auto"});b(this.grid.bDiv.firstChild.firstChild).css({height:0,display:"none"});if(this.grid.bDiv.scrollTop!==0)this.grid.bDiv.scrollTop=0}if(c===
+true&&this.p.treeGrid){this.p.data=[];this.p._index={}}},S=function(){var c=a.p.data.length,d,e,f;d=a.p.rownumbers===true?1:0;e=a.p.multiselect===true?1:0;f=a.p.subGrid===true?1:0;d=a.p.keyIndex===false||a.p.loadonce===true?a.p.localReader.id:a.p.colModel[a.p.keyIndex+e+f+d].name;for(e=0;e<c;e++){f=b.jgrid.getAccessor(a.p.data[e],d);a.p._index[f]=e}},J=function(c,d,e,f,g){var h="-1",i="",j,d=d?"display:none;":"",e="ui-widget-content jqgrow ui-row-"+a.p.direction+e,f=b.isFunction(a.p.rowattr)?a.p.rowattr.call(a,
+f,g):{};if(!b.isEmptyObject(f)){if(f.hasOwnProperty("id")){c=f.id;delete f.id}if(f.hasOwnProperty("tabindex")){h=f.tabindex;delete f.tabindex}if(f.hasOwnProperty("style")){d=d+f.style;delete f.style}if(f.hasOwnProperty("class")){e=e+(" "+f["class"]);delete f["class"]}try{delete f.role}catch(k){}for(j in f)f.hasOwnProperty(j)&&(i=i+(" "+j+"="+f[j]))}return'<tr role="row" id="'+c+'" tabindex="'+h+'" class="'+e+'"'+(d===""?"":' style="'+d+'"')+i+">"},$=function(c,d,e,f,g){var h=new Date,i=a.p.datatype!=
+"local"&&a.p.loadonce||a.p.datatype=="xmlstring",j=a.p.xmlReader,k=a.p.datatype=="local"?"local":"xml";if(i){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(b.isXMLDoc(c)){if(a.p.treeANode===-1&&!a.p.scroll){N.call(a,false,true);e=1}else e=e>1?e:1;var z,B,q=0,l,s=a.p.multiselect===true?1:0,P=a.p.subGrid===true?1:0,m=a.p.rownumbers===true?1:0,o,p=[],u,n={},r,w,C=[],v=a.p.altRows===true?" "+a.p.altclass:"",A;j.repeatitems||(p=U(k));o=a.p.keyIndex===false?b.isFunction(j.id)?j.id.call(a,
+c):j.id:a.p.keyIndex;if(p.length>0&&!isNaN(o)){a.p.remapColumns&&a.p.remapColumns.length&&(o=b.inArray(o,a.p.remapColumns));o=p[o]}k=(o+"").indexOf("[")===-1?p.length?function(a,c){return b(o,a).text()||c}:function(a,c){return b(j.cell,a).eq(o).text()||c}:function(a,b){return a.getAttribute(o.replace(/[\[\]]/g,""))||b};a.p.userData={};a.p.page=b.jgrid.getXmlData(c,j.page)||0;a.p.lastpage=b.jgrid.getXmlData(c,j.total);if(a.p.lastpage===void 0)a.p.lastpage=1;a.p.records=b.jgrid.getXmlData(c,j.records)||
+0;b.isFunction(j.userdata)?a.p.userData=j.userdata.call(a,c)||{}:b.jgrid.getXmlData(c,j.userdata,true).each(function(){a.p.userData[this.getAttribute("name")]=b(this).text()});c=b.jgrid.getXmlData(c,j.root,true);(c=b.jgrid.getXmlData(c,j.row,true))||(c=[]);var t=c.length,H=0,Q=[],x=parseInt(a.p.rowNum,10);if(t>0&&a.p.page<=0)a.p.page=1;if(c&&t){var D=a.p.scroll?b.jgrid.randId():1;g&&(x=x*(g+1));for(var g=b.isFunction(a.p.afterInsertRow),E=a.p.grouping&&a.p.groupingView.groupCollapse===true;H<t;){r=
+c[H];w=k(r,D+H);w=a.p.idPrefix+w;z=e===0?0:e+1;A=(z+H)%2==1?v:"";var I=C.length;C.push("");m&&C.push(Z(0,H,a.p.page,a.p.rowNum));s&&C.push(F(w,m,H));P&&C.push(b(a).jqGrid("addSubGridCell",s+m,H+e));if(j.repeatitems){u||(u=V(s+P+m));var L=b.jgrid.getXmlData(r,j.cell,true);b.each(u,function(b){var c=L[this];if(!c)return false;l=c.textContent||c.text;n[a.p.colModel[b+s+P+m].name]=l;C.push(M(w,l,b+s+P+m,H+e,r))})}else for(z=0;z<p.length;z++){l=b.jgrid.getXmlData(r,p[z]);n[a.p.colModel[z+s+P+m].name]=
+l;C.push(M(w,l,z+s+P+m,H+e,r))}C[I]=J(w,E,A,n,r);C.push("</tr>");if(a.p.grouping){Q=b(a).jqGrid("groupingPrepare",C,Q,n,H);C=[]}if(i||a.p.treeGrid===true){n._id_=w;a.p.data.push(n);a.p._index[w]=a.p.data.length-1}if(a.p.gridview===false){b("tbody:first",d).append(C.join(""));b(a).triggerHandler("jqGridAfterInsertRow",[w,n,r]);g&&a.p.afterInsertRow.call(a,w,n,r);C=[]}n={};q++;H++;if(q==x)break}}if(a.p.gridview===true){B=a.p.treeANode>-1?a.p.treeANode:0;if(a.p.grouping){b(a).jqGrid("groupingRender",
+Q,a.p.colModel.length);Q=null}else a.p.treeGrid===true&&B>0?b(a.rows[B]).after(C.join("")):b("tbody:first",d).append(C.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",s+m)}catch(R){}a.p.totaltime=new Date-h;if(q>0&&a.p.records===0)a.p.records=t;C=null;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",B+1,q+B+1)}catch(S){}if(!a.p.treeGrid&&!a.p.scroll)a.grid.bDiv.scrollTop=0;a.p.reccount=q;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(i){a.p.records=
+t;a.p.lastpage=Math.ceil(t/x)}f||a.updatepager(false,true);if(i)for(;q<t;){r=c[q];w=k(r,q+D);w=a.p.idPrefix+w;if(j.repeatitems){u||(u=V(s+P+m));var O=b.jgrid.getXmlData(r,j.cell,true);b.each(u,function(b){var c=O[this];if(!c)return false;l=c.textContent||c.text;n[a.p.colModel[b+s+P+m].name]=l})}else for(z=0;z<p.length;z++){l=b.jgrid.getXmlData(r,p[z]);n[a.p.colModel[z+s+P+m].name]=l}n._id_=w;a.p.data.push(n);a.p._index[w]=a.p.data.length-1;n={};q++}}},aa=function(c,d,e,f,g){d=new Date;if(c){if(a.p.treeANode===
+-1&&!a.p.scroll){N.call(a,false,true);e=1}else e=e>1?e:1;var h,i,j=a.p.datatype!="local"&&a.p.loadonce||a.p.datatype=="jsonstring";if(j){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(a.p.datatype=="local"){h=a.p.localReader;i="local"}else{h=a.p.jsonReader;i="json"}var k=0,l,B,q=[],m,s=a.p.multiselect?1:0,o=a.p.subGrid?1:0,p=a.p.rownumbers===true?1:0,n,u,t={},v,r,w=[],C=a.p.altRows===true?" "+a.p.altclass:"",A;a.p.page=b.jgrid.getAccessor(c,h.page)||0;n=b.jgrid.getAccessor(c,
+h.total);a.p.lastpage=n===void 0?1:n;a.p.records=b.jgrid.getAccessor(c,h.records)||0;a.p.userData=b.jgrid.getAccessor(c,h.userdata)||{};h.repeatitems||(m=q=U(i));i=a.p.keyIndex===false?b.isFunction(h.id)?h.id.call(a,c):h.id:a.p.keyIndex;if(q.length>0&&!isNaN(i)){a.p.remapColumns&&a.p.remapColumns.length&&(i=b.inArray(i,a.p.remapColumns));i=q[i]}(u=b.jgrid.getAccessor(c,h.root))||(u=[]);n=u.length;c=0;if(n>0&&a.p.page<=0)a.p.page=1;var x=parseInt(a.p.rowNum,10),D=a.p.scroll?b.jgrid.randId():1;g&&(x=
+x*(g+1));for(var H=b.isFunction(a.p.afterInsertRow),Q=[],E=a.p.grouping&&a.p.groupingView.groupCollapse===true;c<n;){g=u[c];r=b.jgrid.getAccessor(g,i);if(r===void 0){r=D+c;if(q.length===0&&h.cell){l=b.jgrid.getAccessor(g,h.cell);r=l!==void 0?l[i]||r:r}}r=a.p.idPrefix+r;l=e===1?0:e;A=(l+c)%2==1?C:"";var I=w.length;w.push("");p&&w.push(Z(0,c,a.p.page,a.p.rowNum));s&&w.push(F(r,p,c));o&&w.push(b(a).jqGrid("addSubGridCell",s+p,c+e));if(h.repeatitems){h.cell&&(g=b.jgrid.getAccessor(g,h.cell));m||(m=V(s+
+o+p))}for(B=0;B<m.length;B++){l=b.jgrid.getAccessor(g,m[B]);w.push(M(r,l,B+s+o+p,c+e,g));t[a.p.colModel[B+s+o+p].name]=l}w[I]=J(r,E,A,t,g);w.push("</tr>");if(a.p.grouping){Q=b(a).jqGrid("groupingPrepare",w,Q,t,c);w=[]}if(j||a.p.treeGrid===true){t._id_=r;a.p.data.push(t);a.p._index[r]=a.p.data.length-1}if(a.p.gridview===false){b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(w.join(""));b(a).triggerHandler("jqGridAfterInsertRow",[r,t,g]);H&&a.p.afterInsertRow.call(a,r,t,g);w=[]}t={};k++;c++;if(k==
+x)break}if(a.p.gridview===true){v=a.p.treeANode>-1?a.p.treeANode:0;a.p.grouping?b(a).jqGrid("groupingRender",Q,a.p.colModel.length):a.p.treeGrid===true&&v>0?b(a.rows[v]).after(w.join("")):b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(w.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",s+p)}catch(L){}a.p.totaltime=new Date-d;if(k>0&&a.p.records===0)a.p.records=n;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",v+1,k+v+1)}catch(O){}if(!a.p.treeGrid&&!a.p.scroll)a.grid.bDiv.scrollTop=
+0;a.p.reccount=k;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(j){a.p.records=n;a.p.lastpage=Math.ceil(n/x)}f||a.updatepager(false,true);if(j)for(;k<n&&u[k];){g=u[k];r=b.jgrid.getAccessor(g,i);if(r===void 0){r=D+k;q.length===0&&h.cell&&(r=b.jgrid.getAccessor(g,h.cell)[i]||r)}if(g){r=a.p.idPrefix+r;if(h.repeatitems){h.cell&&(g=b.jgrid.getAccessor(g,h.cell));m||(m=V(s+o+p))}for(B=0;B<m.length;B++){l=b.jgrid.getAccessor(g,m[B]);t[a.p.colModel[B+s+o+p].name]=
+l}t._id_=r;a.p.data.push(t);a.p._index[r]=a.p.data.length-1;t={}}k++}}},ma=function(){function c(d){var e=0,g,h,i,j,T;if(d.groups!==void 0){(h=d.groups.length&&d.groupOp.toString().toUpperCase()==="OR")&&s.orBegin();for(g=0;g<d.groups.length;g++){e>0&&h&&s.or();try{c(d.groups[g])}catch(k){alert(k)}e++}h&&s.orEnd()}if(d.rules!==void 0){if(e>0){h=s.select();s=b.jgrid.from(h);a.p.ignoreCase&&(s=s.ignoreCase())}try{(i=d.rules.length&&d.groupOp.toString().toUpperCase()==="OR")&&s.orBegin();for(g=0;g<d.rules.length;g++){T=
+d.rules[g];j=d.groupOp.toString().toUpperCase();if(o[T.op]&&T.field){e>0&&j&&j==="OR"&&(s=s.or());s=o[T.op](s,j)(T.field,T.data,f[T.field])}e++}i&&s.orEnd()}catch(na){alert(na)}}}var d,e=false,f={},g=[],h=[],i,j,k;if(b.isArray(a.p.data)){var l=a.p.grouping?a.p.groupingView:false,m,q;b.each(a.p.colModel,function(){j=this.sorttype||"text";if(j=="date"||j=="datetime"){if(this.formatter&&typeof this.formatter==="string"&&this.formatter=="date"){i=this.formatoptions&&this.formatoptions.srcformat?this.formatoptions.srcformat:
+b.jgrid.formatter.date.srcformat;k=this.formatoptions&&this.formatoptions.newformat?this.formatoptions.newformat:b.jgrid.formatter.date.newformat}else i=k=this.datefmt||"Y-m-d";f[this.name]={stype:j,srcfmt:i,newfmt:k}}else f[this.name]={stype:j,srcfmt:"",newfmt:""};if(a.p.grouping){q=0;for(m=l.groupField.length;q<m;q++)if(this.name==l.groupField[q]){var c=this.name;if(typeof this.index!="undefined")c=this.index;g[q]=f[c];h[q]=c}}if(!e&&(this.index==a.p.sortname||this.name==a.p.sortname)){d=this.name;
+e=true}});if(a.p.treeGrid)b(a).jqGrid("SortTree",d,a.p.sortorder,f[d].stype,f[d].srcfmt);else{var o={eq:function(a){return a.equals},ne:function(a){return a.notEquals},lt:function(a){return a.less},le:function(a){return a.lessOrEquals},gt:function(a){return a.greater},ge:function(a){return a.greaterOrEquals},cn:function(a){return a.contains},nc:function(a,b){return b==="OR"?a.orNot().contains:a.andNot().contains},bw:function(a){return a.startsWith},bn:function(a,b){return b==="OR"?a.orNot().startsWith:
+a.andNot().startsWith},en:function(a,b){return b==="OR"?a.orNot().endsWith:a.andNot().endsWith},ew:function(a){return a.endsWith},ni:function(a,b){return b==="OR"?a.orNot().equals:a.andNot().equals},"in":function(a){return a.equals},nu:function(a){return a.isNull},nn:function(a,b){return b==="OR"?a.orNot().isNull:a.andNot().isNull}},s=b.jgrid.from(a.p.data);a.p.ignoreCase&&(s=s.ignoreCase());if(a.p.search===true){var n=a.p.postData.filters;if(n){typeof n=="string"&&(n=b.jgrid.parse(n));c(n)}else try{s=
+o[a.p.postData.searchOper](s)(a.p.postData.searchField,a.p.postData.searchString,f[a.p.postData.searchField])}catch(p){}}if(a.p.grouping)for(q=0;q<m;q++)s.orderBy(h[q],l.groupOrder[q],g[q].stype,g[q].srcfmt);d&&a.p.sortorder&&e&&(a.p.sortorder.toUpperCase()=="DESC"?s.orderBy(a.p.sortname,"d",f[d].stype,f[d].srcfmt):s.orderBy(a.p.sortname,"a",f[d].stype,f[d].srcfmt));var n=s.select(),u=parseInt(a.p.rowNum,10),t=n.length,v=parseInt(a.p.page,10),x=Math.ceil(t/u),r={},n=n.slice((v-1)*u,v*u),f=s=null;
+r[a.p.localReader.total]=x;r[a.p.localReader.page]=v;r[a.p.localReader.records]=t;r[a.p.localReader.root]=n;r[a.p.localReader.userdata]=a.p.userData;n=null;return r}}},ca=function(){a.grid.hDiv.loading=true;if(!a.p.hiddengrid)switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).show();break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).show();b("#load_"+b.jgrid.jqID(a.p.id)).show()}},O=function(){a.grid.hDiv.loading=false;switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).hide();
+break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).hide();b("#load_"+b.jgrid.jqID(a.p.id)).hide()}},I=function(c){if(!a.grid.hDiv.loading){var d=a.p.scroll&&c===false,e={},f,g=a.p.prmNames;if(a.p.page<=0)a.p.page=1;if(g.search!==null)e[g.search]=a.p.search;g.nd!==null&&(e[g.nd]=(new Date).getTime());if(g.rows!==null)e[g.rows]=a.p.rowNum;if(g.page!==null)e[g.page]=a.p.page;if(g.sort!==null)e[g.sort]=a.p.sortname;if(g.order!==null)e[g.order]=a.p.sortorder;if(a.p.rowTotal!==null&&g.totalrows!==null)e[g.totalrows]=
+a.p.rowTotal;var h=b.isFunction(a.p.loadComplete),i=h?a.p.loadComplete:null,j=0,c=c||1;if(c>1)if(g.npage!==null){e[g.npage]=c;j=c-1;c=1}else i=function(b){a.p.page++;a.grid.hDiv.loading=false;h&&a.p.loadComplete.call(a,b);I(c-1)};else g.npage!==null&&delete a.p.postData[g.npage];if(a.p.grouping){b(a).jqGrid("groupingSetup");var k=a.p.groupingView,l,m="";for(l=0;l<k.groupField.length;l++)m=m+(k.groupField[l]+" "+k.groupOrder[l]+", ");e[g.sort]=m+e[g.sort]}b.extend(a.p.postData,e);var q=!a.p.scroll?
+1:a.rows.length-1,e=b(a).triggerHandler("jqGridBeforeRequest");if(!(e===false||e==="stop"))if(b.isFunction(a.p.datatype))a.p.datatype.call(a,a.p.postData,"load_"+a.p.id);else{if(b.isFunction(a.p.beforeRequest)){e=a.p.beforeRequest.call(a);e===void 0&&(e=true);if(e===false)return}f=a.p.datatype.toLowerCase();switch(f){case "json":case "jsonp":case "xml":case "script":b.ajax(b.extend({url:a.p.url,type:a.p.mtype,dataType:f,data:b.isFunction(a.p.serializeGridData)?a.p.serializeGridData.call(a,a.p.postData):
+a.p.postData,success:function(e,g,h){if(b.isFunction(a.p.beforeProcessing)&&a.p.beforeProcessing.call(a,e,g,h)===false)O();else{f==="xml"?$(e,a.grid.bDiv,q,c>1,j):aa(e,a.grid.bDiv,q,c>1,j);b(a).triggerHandler("jqGridLoadComplete",[e]);i&&i.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);d&&a.grid.populateVisible();if(a.p.loadonce||a.p.treeGrid)a.p.datatype="local";c===1&&O()}},error:function(d,e,f){b.isFunction(a.p.loadError)&&a.p.loadError.call(a,d,e,f);c===1&&O()},beforeSend:function(c,
+d){var e=true;b.isFunction(a.p.loadBeforeSend)&&(e=a.p.loadBeforeSend.call(a,c,d));e===void 0&&(e=true);if(e===false)return false;ca()}},b.jgrid.ajaxOptions,a.p.ajaxGridOptions));break;case "xmlstring":ca();e=b.jgrid.stringToDoc(a.p.datastr);$(e,a.grid.bDiv);b(a).triggerHandler("jqGridLoadComplete",[e]);h&&a.p.loadComplete.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);a.p.datatype="local";a.p.datastr=null;O();break;case "jsonstring":ca();e=typeof a.p.datastr=="string"?b.jgrid.parse(a.p.datastr):
+a.p.datastr;aa(e,a.grid.bDiv);b(a).triggerHandler("jqGridLoadComplete",[e]);h&&a.p.loadComplete.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);a.p.datatype="local";a.p.datastr=null;O();break;case "local":case "clientside":ca();a.p.datatype="local";e=ma();aa(e,a.grid.bDiv,q,c>1,j);b(a).triggerHandler("jqGridLoadComplete",[e]);i&&i.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);d&&a.grid.populateVisible();O()}}}},da=function(c){b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv)[a.p.useProp?
+"prop":"attr"]("checked",c);if(a.p.frozenColumns&&a.p.id+"_frozen")b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.fhDiv)[a.p.useProp?"prop":"attr"]("checked",c)};l=function(c,e){var d="",f="<table cellspacing='0' cellpadding='0' border='0' style='table-layout:auto;' class='ui-pg-table'><tbody><tr>",g="",h,j,k,l,m=function(c){var e;b.isFunction(a.p.onPaging)&&(e=a.p.onPaging.call(a,c));a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];da(false)}a.p.savedRow=[];return e=="stop"?false:true},c=c.substr(1),e=
+e+("_"+c);h="pg_"+c;j=c+"_left";k=c+"_center";l=c+"_right";b("#"+b.jgrid.jqID(c)).append("<div id='"+h+"' class='ui-pager-control' role='group'><table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table' style='width:100%;table-layout:fixed;height:100%;' role='row'><tbody><tr><td id='"+j+"' align='left'></td><td id='"+k+"' align='center' style='white-space:pre;'></td><td id='"+l+"' align='right'></td></tr></tbody></table></div>").attr("dir","ltr");if(a.p.rowList.length>0){g="<td dir='"+
+i+"'>";g=g+"<select class='ui-pg-selbox' role='listbox'>";for(j=0;j<a.p.rowList.length;j++)g=g+('<option role="option" value="'+a.p.rowList[j]+'"'+(a.p.rowNum==a.p.rowList[j]?' selected="selected"':"")+">"+a.p.rowList[j]+"</option>");g=g+"</select></td>"}i=="rtl"&&(f=f+g);a.p.pginput===true&&(d="<td dir='"+i+"'>"+b.jgrid.format(a.p.pgtext||"","<input class='ui-pg-input' type='text' size='2' maxlength='7' value='0' role='textbox'/>","<span id='sp_1_"+b.jgrid.jqID(c)+"'></span>")+"</td>");if(a.p.pgbuttons===
+true){j=["first"+e,"prev"+e,"next"+e,"last"+e];i=="rtl"&&j.reverse();f=f+("<td id='"+j[0]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-first'></span></td>");f=f+("<td id='"+j[1]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-prev'></span></td>");f=f+(d!==""?"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>"+d+"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>":
+"")+("<td id='"+j[2]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-next'></span></td>");f=f+("<td id='"+j[3]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-end'></span></td>")}else d!==""&&(f=f+d);i=="ltr"&&(f=f+g);f=f+"</tr></tbody></table>";a.p.viewrecords===true&&b("td#"+c+"_"+a.p.recordpos,"#"+h).append("<div dir='"+i+"' style='text-align:"+a.p.recordpos+"' class='ui-paging-info'></div>");b("td#"+c+"_"+a.p.pagerpos,"#"+h).append(f);g=b(".ui-jqgrid").css("font-size")||
+"11px";b(document.body).append("<div id='testpg' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+g+";visibility:hidden;' ></div>");f=b(f).clone().appendTo("#testpg").width();b("#testpg").remove();if(f>0){d!==""&&(f=f+50);b("td#"+c+"_"+a.p.pagerpos,"#"+h).width(f)}a.p._nvtd=[];a.p._nvtd[0]=f?Math.floor((a.p.width-f)/2):Math.floor(a.p.width/3);a.p._nvtd[1]=0;f=null;b(".ui-pg-selbox","#"+h).bind("change",function(){a.p.page=Math.round(a.p.rowNum*(a.p.page-1)/this.value-0.5)+1;a.p.rowNum=
+this.value;a.p.pager&&b(".ui-pg-selbox",a.p.pager).val(this.value);a.p.toppager&&b(".ui-pg-selbox",a.p.toppager).val(this.value);if(!m("records"))return false;I();return false});if(a.p.pgbuttons===true){b(".ui-pg-button","#"+h).hover(function(){if(b(this).hasClass("ui-state-disabled"))this.style.cursor="default";else{b(this).addClass("ui-state-hover");this.style.cursor="pointer"}},function(){if(!b(this).hasClass("ui-state-disabled")){b(this).removeClass("ui-state-hover");this.style.cursor="default"}});
+b("#first"+b.jgrid.jqID(e)+", #prev"+b.jgrid.jqID(e)+", #next"+b.jgrid.jqID(e)+", #last"+b.jgrid.jqID(e)).click(function(){var b=o(a.p.page,1),c=o(a.p.lastpage,1),d=false,f=true,g=true,h=true,i=true;if(c===0||c===1)i=h=g=f=false;else if(c>1&&b>=1)if(b===1)g=f=false;else{if(b===c)i=h=false}else if(c>1&&b===0){i=h=false;b=c-1}if(this.id==="first"+e&&f){a.p.page=1;d=true}if(this.id==="prev"+e&&g){a.p.page=b-1;d=true}if(this.id==="next"+e&&h){a.p.page=b+1;d=true}if(this.id==="last"+e&&i){a.p.page=c;d=
+true}if(d){if(!m(this.id))return false;I()}return false})}a.p.pginput===true&&b("input.ui-pg-input","#"+h).keypress(function(c){if((c.charCode?c.charCode:c.keyCode?c.keyCode:0)==13){a.p.page=b(this).val()>0?b(this).val():a.p.page;if(!m("user"))return false;I();return false}return this})};var ja=function(c,e,d,f){if(a.p.colModel[e].sortable&&!(a.p.savedRow.length>0)){if(!d){if(a.p.lastsort==e)if(a.p.sortorder=="asc")a.p.sortorder="desc";else{if(a.p.sortorder=="desc")a.p.sortorder="asc"}else a.p.sortorder=
+a.p.colModel[e].firstsortorder||"asc";a.p.page=1}if(f){if(a.p.lastsort==e&&a.p.sortorder==f&&!d)return;a.p.sortorder=f}d=a.grid.headers[a.p.lastsort].el;f=a.grid.headers[e].el;b("span.ui-grid-ico-sort",d).addClass("ui-state-disabled");b(d).attr("aria-selected","false");b("span.ui-icon-"+a.p.sortorder,f).removeClass("ui-state-disabled");b(f).attr("aria-selected","true");if(!a.p.viewsortcols[0]&&a.p.lastsort!=e){b("span.s-ico",d).hide();b("span.s-ico",f).show()}c=c.substring(5+a.p.id.length+1);a.p.sortname=
+a.p.colModel[e].index||c;d=a.p.sortorder;if(b(a).triggerHandler("jqGridSortCol",[c,e,d])==="stop")a.p.lastsort=e;else if(b.isFunction(a.p.onSortCol)&&a.p.onSortCol.call(a,c,e,d)=="stop")a.p.lastsort=e;else{if(a.p.datatype=="local")a.p.deselectAfterSort&&b(a).jqGrid("resetSelection");else{a.p.selrow=null;a.p.multiselect&&da(false);a.p.selarrrow=[];a.p.savedRow=[]}if(a.p.scroll){d=a.grid.bDiv.scrollLeft;N.call(a,true,false);a.grid.hDiv.scrollLeft=d}a.p.subGrid&&a.p.datatype=="local"&&b("td.sgexpanded",
+"#"+b.jgrid.jqID(a.p.id)).each(function(){b(this).trigger("click")});I();a.p.lastsort=e;if(a.p.sortname!=c&&e)a.p.lastsort=e}}},oa=function(c){var e,d={},f=b.jgrid.cellWidth()?0:a.p.cellLayout;for(e=d[0]=d[1]=d[2]=0;e<=c;e++)a.p.colModel[e].hidden===false&&(d[0]=d[0]+(a.p.colModel[e].width+f));a.p.direction=="rtl"&&(d[0]=a.p.width-d[0]);d[0]=d[0]-a.grid.bDiv.scrollLeft;b(a.grid.cDiv).is(":visible")&&(d[1]=d[1]+(b(a.grid.cDiv).height()+parseInt(b(a.grid.cDiv).css("padding-top"),10)+parseInt(b(a.grid.cDiv).css("padding-bottom"),
+10)));if(a.p.toolbar[0]===true&&(a.p.toolbar[1]=="top"||a.p.toolbar[1]=="both"))d[1]=d[1]+(b(a.grid.uDiv).height()+parseInt(b(a.grid.uDiv).css("border-top-width"),10)+parseInt(b(a.grid.uDiv).css("border-bottom-width"),10));a.p.toppager&&(d[1]=d[1]+(b(a.grid.topDiv).height()+parseInt(b(a.grid.topDiv).css("border-bottom-width"),10)));d[2]=d[2]+(b(a.grid.bDiv).height()+b(a.grid.hDiv).height());return d},ka=function(c){var d,e=a.grid.headers,f=b.jgrid.getCellIndex(c);for(d=0;d<e.length;d++)if(c===e[d].el){f=
+d;break}return f};this.p.id=this.id;-1==b.inArray(a.p.multikey,["shiftKey","altKey","ctrlKey"])&&(a.p.multikey=!1);a.p.keyIndex=!1;for(e=0;e<a.p.colModel.length;e++)a.p.colModel[e]=b.extend(!0,{},a.p.cmTemplate,a.p.colModel[e].template||{},a.p.colModel[e]),!1===a.p.keyIndex&&!0===a.p.colModel[e].key&&(a.p.keyIndex=e);a.p.sortorder=a.p.sortorder.toLowerCase();!0===a.p.grouping&&(a.p.scroll=!1,a.p.rownumbers=!1,a.p.treeGrid=!1,a.p.gridview=!0);if(!0===this.p.treeGrid){try{b(this).jqGrid("setTreeGrid")}catch(qa){}"local"!=
+a.p.datatype&&(a.p.localReader={id:"_id_"})}if(this.p.subGrid)try{b(a).jqGrid("setSubGrid")}catch(ra){}this.p.multiselect&&(this.p.colNames.unshift("<input role='checkbox' id='cb_"+this.p.id+"' class='cbox' type='checkbox'/>"),this.p.colModel.unshift({name:"cb",width:b.jgrid.cellWidth()?a.p.multiselectWidth+a.p.cellLayout:a.p.multiselectWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,align:"center",fixed:!0}));this.p.rownumbers&&(this.p.colNames.unshift(""),this.p.colModel.unshift({name:"rn",
+width:a.p.rownumWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,align:"center",fixed:!0}));a.p.xmlReader=b.extend(!0,{root:"rows",row:"row",page:"rows>page",total:"rows>total",records:"rows>records",repeatitems:!0,cell:"cell",id:"[id]",userdata:"userdata",subgrid:{root:"rows",row:"row",repeatitems:!0,cell:"cell"}},a.p.xmlReader);a.p.jsonReader=b.extend(!0,{root:"rows",page:"page",total:"total",records:"records",repeatitems:!0,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:!0,
+cell:"cell"}},a.p.jsonReader);a.p.localReader=b.extend(!0,{root:"rows",page:"page",total:"total",records:"records",repeatitems:!1,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:!0,cell:"cell"}},a.p.localReader);a.p.scroll&&(a.p.pgbuttons=!1,a.p.pginput=!1,a.p.rowList=[]);a.p.data.length&&S();var x="<thead><tr class='ui-jqgrid-labels' role='rowheader'>",la,L,ea,ba,fa,A,n,W;L=W="";if(!0===a.p.shrinkToFit&&!0===a.p.forceFit)for(e=a.p.colModel.length-1;0<=e;e--)if(!a.p.colModel[e].hidden){a.p.colModel[e].resizable=
+!1;break}"horizontal"==a.p.viewsortcols[1]&&(W=" ui-i-asc",L=" ui-i-desc");la=k?"class='ui-th-div-ie'":"";W="<span class='s-ico' style='display:none'><span sort='asc' class='ui-grid-ico-sort ui-icon-asc"+W+" ui-state-disabled ui-icon ui-icon-triangle-1-n ui-sort-"+i+"'></span>"+("<span sort='desc' class='ui-grid-ico-sort ui-icon-desc"+L+" ui-state-disabled ui-icon ui-icon-triangle-1-s ui-sort-"+i+"'></span></span>");for(e=0;e<this.p.colNames.length;e++)L=a.p.headertitles?' title="'+b.jgrid.stripHtml(a.p.colNames[e])+
+'"':"",x+="<th id='"+a.p.id+"_"+a.p.colModel[e].name+"' role='columnheader' class='ui-state-default ui-th-column ui-th-"+i+"'"+L+">",L=a.p.colModel[e].index||a.p.colModel[e].name,x+="<div id='jqgh_"+a.p.id+"_"+a.p.colModel[e].name+"' "+la+">"+a.p.colNames[e],a.p.colModel[e].width=a.p.colModel[e].width?parseInt(a.p.colModel[e].width,10):150,"boolean"!==typeof a.p.colModel[e].title&&(a.p.colModel[e].title=!0),L==a.p.sortname&&(a.p.lastsort=e),x+=W+"</div></th>";W=null;b(this).append(x+"</tr></thead>");
+b("thead tr:first th",this).hover(function(){b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")});if(this.p.multiselect){var ga=[],X;b("#cb_"+b.jgrid.jqID(a.p.id),this).bind("click",function(){a.p.selarrrow=[];var c=a.p.frozenColumns===true?a.p.id+"_frozen":"";if(this.checked){b(a.rows).each(function(d){if(d>0&&!b(this).hasClass("ui-subgrid")&&!b(this).hasClass("jqgroup")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id))[a.p.useProp?
+"prop":"attr"]("checked",true);b(this).addClass("ui-state-highlight").attr("aria-selected","true");a.p.selarrrow.push(this.id);a.p.selrow=this.id;if(c){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id),a.grid.fbDiv)[a.p.useProp?"prop":"attr"]("checked",true);b("#"+b.jgrid.jqID(this.id),a.grid.fbDiv).addClass("ui-state-highlight")}}});X=true;ga=[]}else{b(a.rows).each(function(d){if(d>0&&!b(this).hasClass("ui-subgrid")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+b.jgrid.jqID(this.id))[a.p.useProp?"prop":"attr"]("checked",false);b(this).removeClass("ui-state-highlight").attr("aria-selected","false");ga.push(this.id);if(c){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id),a.grid.fbDiv)[a.p.useProp?"prop":"attr"]("checked",false);b("#"+b.jgrid.jqID(this.id),a.grid.fbDiv).removeClass("ui-state-highlight")}}});a.p.selrow=null;X=false}b(a).triggerHandler("jqGridSelectAll",[X?a.p.selarrrow:ga,X]);b.isFunction(a.p.onSelectAll)&&a.p.onSelectAll.call(a,X?a.p.selarrrow:
+ga,X)})}!0===a.p.autowidth&&(x=b(m).innerWidth(),a.p.width=0<x?x:"nw");(function(){var d=0,e=b.jgrid.cellWidth()?0:o(a.p.cellLayout,0),f=0,g,i=o(a.p.scrollOffset,0),j,k=false,l,m=0,n=0,p;b.each(a.p.colModel,function(){if(typeof this.hidden==="undefined")this.hidden=false;this.widthOrg=j=o(this.width,0);if(this.hidden===false){d=d+(j+e);this.fixed?m=m+(j+e):f++;n++}});if(isNaN(a.p.width))a.p.width=d+(a.p.shrinkToFit===false&&!isNaN(a.p.height)?i:0);c.width=a.p.width;a.p.tblwidth=d;if(a.p.shrinkToFit===
+false&&a.p.forceFit===true)a.p.forceFit=false;if(a.p.shrinkToFit===true&&f>0){l=c.width-e*f-m;if(!isNaN(a.p.height)){l=l-i;k=true}d=0;b.each(a.p.colModel,function(b){if(this.hidden===false&&!this.fixed){this.width=j=Math.round(l*this.width/(a.p.tblwidth-e*f-m));d=d+j;g=b}});p=0;k?c.width-m-(d+e*f)!==i&&(p=c.width-m-(d+e*f)-i):!k&&Math.abs(c.width-m-(d+e*f))!==1&&(p=c.width-m-(d+e*f));a.p.colModel[g].width=a.p.colModel[g].width+p;a.p.tblwidth=d+p+e*f+m;if(a.p.tblwidth>a.p.width){a.p.colModel[g].width=
+a.p.colModel[g].width-(a.p.tblwidth-parseInt(a.p.width,10));a.p.tblwidth=a.p.width}}})();b(m).css("width",c.width+"px").append("<div class='ui-jqgrid-resize-mark' id='rs_m"+a.p.id+"'>&#160;</div>");b(j).css("width",c.width+"px");var x=b("thead:first",a).get(0),R="";a.p.footerrow&&(R+="<table role='grid' style='width:"+a.p.tblwidth+"px' class='ui-jqgrid-ftable' cellspacing='0' cellpadding='0' border='0'><tbody><tr role='row' class='ui-widget-content footrow footrow-"+i+"'>");var j=b("tr:first",x),
+Y="<tr class='jqgfirstrow' role='row' style='height:auto'>";a.p.disableClick=!1;b("th",j).each(function(d){ea=a.p.colModel[d].width;if(typeof a.p.colModel[d].resizable==="undefined")a.p.colModel[d].resizable=true;if(a.p.colModel[d].resizable){ba=document.createElement("span");b(ba).html("&#160;").addClass("ui-jqgrid-resize ui-jqgrid-resize-"+i);b.browser.opera||b(ba).css("cursor","col-resize");b(this).addClass(a.p.resizeclass)}else ba="";b(this).css("width",ea+"px").prepend(ba);var e="";if(a.p.colModel[d].hidden){b(this).css("display",
+"none");e="display:none;"}Y=Y+("<td role='gridcell' style='height:0px;width:"+ea+"px;"+e+"'></td>");c.headers[d]={width:ea,el:this};fa=a.p.colModel[d].sortable;if(typeof fa!=="boolean")fa=a.p.colModel[d].sortable=true;e=a.p.colModel[d].name;e=="cb"||e=="subgrid"||e=="rn"||a.p.viewsortcols[2]&&b(">div",this).addClass("ui-jqgrid-sortable");if(fa)if(a.p.viewsortcols[0]){b("div span.s-ico",this).show();d==a.p.lastsort&&b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}else if(d==
+a.p.lastsort){b("div span.s-ico",this).show();b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}a.p.footerrow&&(R=R+("<td role='gridcell' "+p(d,0,"",null,"",false)+">&#160;</td>"))}).mousedown(function(d){if(b(d.target).closest("th>span.ui-jqgrid-resize").length==1){var e=ka(this);if(a.p.forceFit===true){var f=a.p,g=e,i;for(i=e+1;i<a.p.colModel.length;i++)if(a.p.colModel[i].hidden!==true){g=i;break}f.nv=g-e}c.dragStart(e,d,oa(e));return false}}).click(function(c){if(a.p.disableClick)return a.p.disableClick=
+false;var d="th>div.ui-jqgrid-sortable",e,f;a.p.viewsortcols[2]||(d="th>div>span>span.ui-grid-ico-sort");c=b(c.target).closest(d);if(c.length==1){d=ka(this);if(!a.p.viewsortcols[2]){e=true;f=c.attr("sort")}ja(b("div",this)[0].id,d,e,f);return false}});if(a.p.sortable&&b.fn.sortable)try{b(a).jqGrid("sortableColumns",j)}catch(sa){}a.p.footerrow&&(R+="</tr></tbody></table>");Y+="</tr>";this.appendChild(document.createElement("tbody"));b(this).addClass("ui-jqgrid-btable").append(Y);var Y=null,j=b("<table class='ui-jqgrid-htable' style='width:"+
+a.p.tblwidth+"px' role='grid' aria-labelledby='gbox_"+this.id+"' cellspacing='0' cellpadding='0' border='0'></table>").append(x),D=a.p.caption&&!0===a.p.hiddengrid?!0:!1;e=b("<div class='ui-jqgrid-hbox"+("rtl"==i?"-rtl":"")+"'></div>");x=null;c.hDiv=document.createElement("div");b(c.hDiv).css({width:c.width+"px"}).addClass("ui-state-default ui-jqgrid-hdiv").append(e);b(e).append(j);j=null;D&&b(c.hDiv).hide();a.p.pager&&("string"==typeof a.p.pager?"#"!=a.p.pager.substr(0,1)&&(a.p.pager="#"+a.p.pager):
+a.p.pager="#"+b(a.p.pager).attr("id"),b(a.p.pager).css({width:c.width+"px"}).appendTo(m).addClass("ui-state-default ui-jqgrid-pager ui-corner-bottom"),D&&b(a.p.pager).hide(),l(a.p.pager,""));!1===a.p.cellEdit&&!0===a.p.hoverrows&&b(a).bind("mouseover",function(a){n=b(a.target).closest("tr.jqgrow");b(n).attr("class")!=="ui-subgrid"&&b(n).addClass("ui-state-hover")}).bind("mouseout",function(a){n=b(a.target).closest("tr.jqgrow");b(n).removeClass("ui-state-hover")});var t,E,ha;b(a).before(c.hDiv).click(function(c){A=
+c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length===0||n[0].className.indexOf("ui-state-disabled")>-1||(b(A,a).closest("table.ui-jqgrid-btable").attr("id")||"").replace("_frozen","")!==a.id)return this;var d=b(A).hasClass("cbox"),e=b(a).triggerHandler("jqGridBeforeSelectRow",[n[0].id,c]);(e=e===false||e==="stop"?false:true)&&b.isFunction(a.p.beforeSelectRow)&&(e=a.p.beforeSelectRow.call(a,n[0].id,c));if(!(A.tagName=="A"||(A.tagName=="INPUT"||A.tagName=="TEXTAREA"||A.tagName=="OPTION"||A.tagName==
+"SELECT")&&!d)&&e===true){t=n[0].id;E=b.jgrid.getCellIndex(A);ha=b(A).closest("td,th").html();b(a).triggerHandler("jqGridCellSelect",[t,E,ha,c]);b.isFunction(a.p.onCellSelect)&&a.p.onCellSelect.call(a,t,E,ha,c);if(a.p.cellEdit===true)if(a.p.multiselect&&d)b(a).jqGrid("setSelection",t,true,c);else{t=n[0].rowIndex;try{b(a).jqGrid("editCell",t,E,true)}catch(f){}}else if(a.p.multikey)if(c[a.p.multikey])b(a).jqGrid("setSelection",t,true,c);else{if(a.p.multiselect&&d){d=b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+t).is(":checked");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+t)[a.p.useProp?"prop":"attr"]("checked",d)}}else{if(a.p.multiselect&&a.p.multiboxonly&&!d){var g=a.p.frozenColumns?a.p.id+"_frozen":"";b(a.p.selarrrow).each(function(c,d){var e=a.rows.namedItem(d);b(e).removeClass("ui-state-highlight");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(d))[a.p.useProp?"prop":"attr"]("checked",false);if(g){b("#"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(g)).removeClass("ui-state-highlight");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+b.jgrid.jqID(d),"#"+b.jgrid.jqID(g))[a.p.useProp?"prop":"attr"]("checked",false)}});a.p.selarrrow=[]}b(a).jqGrid("setSelection",t,true,c)}}}).bind("reloadGrid",function(c,d){if(a.p.treeGrid===true)a.p.datatype=a.p.treedatatype;d&&d.current&&a.grid.selectionPreserver(a);if(a.p.datatype=="local"){b(a).jqGrid("resetSelection");a.p.data.length&&S()}else if(!a.p.treeGrid){a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];da(false)}a.p.savedRow=[]}a.p.scroll&&N.call(a,true,false);if(d&&d.page){var e=
+d.page;if(e>a.p.lastpage)e=a.p.lastpage;e<1&&(e=1);a.p.page=e;a.grid.bDiv.scrollTop=a.grid.prevRowHeight?(e-1)*a.grid.prevRowHeight*a.p.rowNum:0}if(a.grid.prevRowHeight&&a.p.scroll){delete a.p.lastpage;a.grid.populateVisible()}else a.grid.populate();a.p._inlinenav===true&&b(a).jqGrid("showAddEditButtons");return false}).dblclick(function(c){A=c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length!==0){t=n[0].rowIndex;E=b.jgrid.getCellIndex(A);b(a).triggerHandler("jqGridDblClickRow",[b(n).attr("id"),
+t,E,c]);b.isFunction(this.p.ondblClickRow)&&a.p.ondblClickRow.call(a,b(n).attr("id"),t,E,c)}}).bind("contextmenu",function(c){A=c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length!==0){a.p.multiselect||b(a).jqGrid("setSelection",n[0].id,true,c);t=n[0].rowIndex;E=b.jgrid.getCellIndex(A);b(a).triggerHandler("jqGridRightClickRow",[b(n).attr("id"),t,E,c]);b.isFunction(this.p.onRightClickRow)&&a.p.onRightClickRow.call(a,b(n).attr("id"),t,E,c)}});c.bDiv=document.createElement("div");k&&"auto"===
+(""+a.p.height).toLowerCase()&&(a.p.height="100%");b(c.bDiv).append(b('<div style="position:relative;'+(k&&8>b.browser.version?"height:0.01%;":"")+'"></div>').append("<div></div>").append(this)).addClass("ui-jqgrid-bdiv").css({height:a.p.height+(isNaN(a.p.height)?"":"px"),width:c.width+"px"}).scroll(c.scrollGrid);b("table:first",c.bDiv).css({width:a.p.tblwidth+"px"});k?(2==b("tbody",this).size()&&b("tbody:gt(0)",this).remove(),a.p.multikey&&b(c.bDiv).bind("selectstart",function(){return false})):
+a.p.multikey&&b(c.bDiv).bind("mousedown",function(){return false});D&&b(c.bDiv).hide();c.cDiv=document.createElement("div");var ia=!0===a.p.hidegrid?b("<a role='link' href='javascript:void(0)'/>").addClass("ui-jqgrid-titlebar-close HeaderButton").hover(function(){ia.addClass("ui-state-hover")},function(){ia.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-circle-triangle-n'></span>").css("rtl"==i?"left":"right","0px"):"";b(c.cDiv).append(ia).append("<span class='ui-jqgrid-title"+
+("rtl"==i?"-rtl":"")+"'>"+a.p.caption+"</span>").addClass("ui-jqgrid-titlebar ui-widget-header ui-corner-top ui-helper-clearfix");b(c.cDiv).insertBefore(c.hDiv);a.p.toolbar[0]&&(c.uDiv=document.createElement("div"),"top"==a.p.toolbar[1]?b(c.uDiv).insertBefore(c.hDiv):"bottom"==a.p.toolbar[1]&&b(c.uDiv).insertAfter(c.hDiv),"both"==a.p.toolbar[1]?(c.ubDiv=document.createElement("div"),b(c.uDiv).insertBefore(c.hDiv).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id),b(c.ubDiv).insertAfter(c.hDiv).addClass("ui-userdata ui-state-default").attr("id",
+"tb_"+this.id),D&&b(c.ubDiv).hide()):b(c.uDiv).width(c.width).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id),D&&b(c.uDiv).hide());a.p.toppager&&(a.p.toppager=b.jgrid.jqID(a.p.id)+"_toppager",c.topDiv=b("<div id='"+a.p.toppager+"'></div>")[0],a.p.toppager="#"+a.p.toppager,b(c.topDiv).insertBefore(c.hDiv).addClass("ui-state-default ui-jqgrid-toppager").width(c.width),l(a.p.toppager,"_t"));a.p.footerrow&&(c.sDiv=b("<div class='ui-jqgrid-sdiv'></div>")[0],e=b("<div class='ui-jqgrid-hbox"+
+("rtl"==i?"-rtl":"")+"'></div>"),b(c.sDiv).append(e).insertAfter(c.hDiv).width(c.width),b(e).append(R),c.footers=b(".ui-jqgrid-ftable",c.sDiv)[0].rows[0].cells,a.p.rownumbers&&(c.footers[0].className="ui-state-default jqgrid-rownum"),D&&b(c.sDiv).hide());e=null;if(a.p.caption){var pa=a.p.datatype;!0===a.p.hidegrid&&(b(".ui-jqgrid-titlebar-close",c.cDiv).click(function(d){var e=b.isFunction(a.p.onHeaderClick),f=".ui-jqgrid-bdiv, .ui-jqgrid-hdiv, .ui-jqgrid-pager, .ui-jqgrid-sdiv",g,i=this;if(a.p.toolbar[0]===
+true){a.p.toolbar[1]=="both"&&(f=f+(", #"+b(c.ubDiv).attr("id")));f=f+(", #"+b(c.uDiv).attr("id"))}g=b(f,"#gview_"+b.jgrid.jqID(a.p.id)).length;a.p.gridstate=="visible"?b(f,"#gbox_"+b.jgrid.jqID(a.p.id)).slideUp("fast",function(){g--;if(g===0){b("span",i).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");a.p.gridstate="hidden";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).hide();b(a).triggerHandler("jqGridHeaderClick",
+[a.p.gridstate,d]);e&&(D||a.p.onHeaderClick.call(a,a.p.gridstate,d))}}):a.p.gridstate=="hidden"&&b(f,"#gbox_"+b.jgrid.jqID(a.p.id)).slideDown("fast",function(){g--;if(g===0){b("span",i).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");if(D){a.p.datatype=pa;I();D=false}a.p.gridstate="visible";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).show();b(a).triggerHandler("jqGridHeaderClick",[a.p.gridstate,d]);
+e&&(D||a.p.onHeaderClick.call(a,a.p.gridstate,d))}});return false}),D&&(a.p.datatype="local",b(".ui-jqgrid-titlebar-close",c.cDiv).trigger("click")))}else b(c.cDiv).hide();b(c.hDiv).after(c.bDiv).mousemove(function(a){if(c.resizing){c.dragMove(a);return false}});b(".ui-jqgrid-labels",c.hDiv).bind("selectstart",function(){return false});b(document).mouseup(function(){if(c.resizing){c.dragEnd();return false}return true});a.formatCol=p;a.sortData=ja;a.updatepager=function(c,d){var e,f,g,h,i,j,k,l="",
+m=a.p.pager?"_"+b.jgrid.jqID(a.p.pager.substr(1)):"",n=a.p.toppager?"_"+a.p.toppager.substr(1):"";g=parseInt(a.p.page,10)-1;g<0&&(g=0);g=g*parseInt(a.p.rowNum,10);i=g+a.p.reccount;if(a.p.scroll){e=b("tbody:first > tr:gt(0)",a.grid.bDiv);g=i-e.length;a.p.reccount=e.length;if(f=e.outerHeight()||a.grid.prevRowHeight){e=g*f;f=parseInt(a.p.records,10)*f;b(">div:first",a.grid.bDiv).css({height:f}).children("div:first").css({height:e,display:e?"":"none"})}a.grid.bDiv.scrollLeft=a.grid.hDiv.scrollLeft}l=
+a.p.pager?a.p.pager:"";if(l=l+(a.p.toppager?l?","+a.p.toppager:a.p.toppager:"")){k=b.jgrid.formatter.integer||{};e=o(a.p.page);f=o(a.p.lastpage);b(".selbox",l)[this.p.useProp?"prop":"attr"]("disabled",false);if(a.p.pginput===true){b(".ui-pg-input",l).val(a.p.page);h=a.p.toppager?"#sp_1"+m+",#sp_1"+n:"#sp_1"+m;b(h).html(b.fmatter?b.fmatter.util.NumberFormat(a.p.lastpage,k):a.p.lastpage)}if(a.p.viewrecords)if(a.p.reccount===0)b(".ui-paging-info",l).html(a.p.emptyrecords);else{h=g+1;j=a.p.records;if(b.fmatter){h=
+b.fmatter.util.NumberFormat(h,k);i=b.fmatter.util.NumberFormat(i,k);j=b.fmatter.util.NumberFormat(j,k)}b(".ui-paging-info",l).html(b.jgrid.format(a.p.recordtext,h,i,j))}if(a.p.pgbuttons===true){e<=0&&(e=f=0);if(e==1||e===0){b("#first"+m+", #prev"+m).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#first_t"+n+", #prev_t"+n).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#first"+m+", #prev"+m).removeClass("ui-state-disabled");a.p.toppager&&b("#first_t"+
+n+", #prev_t"+n).removeClass("ui-state-disabled")}if(e==f||e===0){b("#next"+m+", #last"+m).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#next_t"+n+", #last_t"+n).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#next"+m+", #last"+m).removeClass("ui-state-disabled");a.p.toppager&&b("#next_t"+n+", #last_t"+n).removeClass("ui-state-disabled")}}}c===true&&a.p.rownumbers===true&&b("td.jqgrid-rownum",a.rows).each(function(a){b(this).html(g+1+a)});d&&a.p.jqgdnd&&
+b(a).jqGrid("gridDnD","updateDnD");b(a).triggerHandler("jqGridGridComplete");b.isFunction(a.p.gridComplete)&&a.p.gridComplete.call(a);b(a).triggerHandler("jqGridAfterGridComplete")};a.refreshIndex=S;a.setHeadCheckBox=da;a.constructTr=J;a.formatter=function(a,b,c,d,e){return u(a,b,c,d,e)};b.extend(c,{populate:I,emptyRows:N});this.grid=c;a.addXmlData=function(b){$(b,a.grid.bDiv)};a.addJSONData=function(b){aa(b,a.grid.bDiv)};this.grid.cols=this.rows[0].cells;I();a.p.hiddengrid=!1;b(window).unload(function(){a=
+null})}}}})};b.jgrid.extend({getGridParam:function(b){var e=this[0];return!e||!e.grid?void 0:b?"undefined"!=typeof e.p[b]?e.p[b]:null:e.p},setGridParam:function(f){return this.each(function(){this.grid&&"object"===typeof f&&b.extend(!0,this.p,f)})},getDataIDs:function(){var f=[],e=0,c,d=0;this.each(function(){if((c=this.rows.length)&&0<c)for(;e<c;)b(this.rows[e]).hasClass("jqgrow")&&(f[d]=this.rows[e].id,d++),e++});return f},setSelection:function(f,e,c){return this.each(function(){var d,a,h,g,i,j;
+if(void 0!==f&&(e=!1===e?!1:!0,(a=this.rows.namedItem(f+""))&&a.className&&!(-1<a.className.indexOf("ui-state-disabled"))))(!0===this.p.scrollrows&&(h=this.rows.namedItem(f).rowIndex,0<=h&&(d=b(this.grid.bDiv)[0].clientHeight,g=b(this.grid.bDiv)[0].scrollTop,i=this.rows[h].offsetTop,h=this.rows[h].clientHeight,i+h>=d+g?b(this.grid.bDiv)[0].scrollTop=i-(d+g)+h+g:i<d+g&&i<g&&(b(this.grid.bDiv)[0].scrollTop=i))),!0===this.p.frozenColumns&&(j=this.p.id+"_frozen"),this.p.multiselect)?(this.setHeadCheckBox(!1),
+this.p.selrow=a.id,g=b.inArray(this.p.selrow,this.p.selarrrow),-1===g?("ui-subgrid"!==a.className&&b(a).addClass("ui-state-highlight").attr("aria-selected","true"),d=!0,this.p.selarrrow.push(this.p.selrow)):("ui-subgrid"!==a.className&&b(a).removeClass("ui-state-highlight").attr("aria-selected","false"),d=!1,this.p.selarrrow.splice(g,1),i=this.p.selarrrow[0],this.p.selrow=void 0===i?null:i),b("#jqg_"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(a.id))[this.p.useProp?"prop":"attr"]("checked",d),j&&(-1===
+g?b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).addClass("ui-state-highlight"):b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).removeClass("ui-state-highlight"),b("#jqg_"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j))[this.p.useProp?"prop":"attr"]("checked",d)),b(this).triggerHandler("jqGridSelectRow",[a.id,d,c]),this.p.onSelectRow&&e&&this.p.onSelectRow.call(this,a.id,d,c)):"ui-subgrid"!==a.className&&(this.p.selrow!=a.id?(b(this.rows.namedItem(this.p.selrow)).removeClass("ui-state-highlight").attr({"aria-selected":"false",
+tabindex:"-1"}),b(a).addClass("ui-state-highlight").attr({"aria-selected":"true",tabindex:"0"}),j&&(b("#"+b.jgrid.jqID(this.p.selrow),"#"+b.jgrid.jqID(j)).removeClass("ui-state-highlight"),b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).addClass("ui-state-highlight")),d=!0):d=!1,this.p.selrow=a.id,b(this).triggerHandler("jqGridSelectRow",[a.id,d,c]),this.p.onSelectRow&&e&&this.p.onSelectRow.call(this,a.id,d,c))})},resetSelection:function(f){return this.each(function(){var e=this,c,d,a;!0===e.p.frozenColumns&&
+(a=e.p.id+"_frozen");if("undefined"!==typeof f){d=f===e.p.selrow?e.p.selrow:f;b("#"+b.jgrid.jqID(e.p.id)+" tbody:first tr#"+b.jgrid.jqID(d)).removeClass("ui-state-highlight").attr("aria-selected","false");a&&b("#"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight");if(e.p.multiselect){b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(e.p.id))[e.p.useProp?"prop":"attr"]("checked",!1);if(a)b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(a))[e.p.useProp?
+"prop":"attr"]("checked",!1);e.setHeadCheckBox(!1)}d=null}else e.p.multiselect?(b(e.p.selarrrow).each(function(d,f){c=e.rows.namedItem(f);b(c).removeClass("ui-state-highlight").attr("aria-selected","false");b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(f))[e.p.useProp?"prop":"attr"]("checked",!1);a&&(b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight"),b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(a))[e.p.useProp?"prop":"attr"]("checked",!1))}),e.setHeadCheckBox(!1),
+e.p.selarrrow=[]):e.p.selrow&&(b("#"+b.jgrid.jqID(e.p.id)+" tbody:first tr#"+b.jgrid.jqID(e.p.selrow)).removeClass("ui-state-highlight").attr("aria-selected","false"),a&&b("#"+b.jgrid.jqID(e.p.selrow),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight"),e.p.selrow=null);!0===e.p.cellEdit&&0<=parseInt(e.p.iCol,10)&&0<=parseInt(e.p.iRow,10)&&(b("td:eq("+e.p.iCol+")",e.rows[e.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(e.rows[e.p.iRow]).removeClass("selected-row ui-state-hover"));e.p.savedRow=
+[]})},getRowData:function(f){var e={},c,d=!1,a,h=0;this.each(function(){var g=this,i,j;if("undefined"==typeof f)d=!0,c=[],a=g.rows.length;else{j=g.rows.namedItem(f);if(!j)return e;a=2}for(;h<a;)d&&(j=g.rows[h]),b(j).hasClass("jqgrow")&&(b('td[role="gridcell"]',j).each(function(a){i=g.p.colModel[a].name;if("cb"!==i&&"subgrid"!==i&&"rn"!==i)if(!0===g.p.treeGrid&&i==g.p.ExpandColumn)e[i]=b.jgrid.htmlDecode(b("span:first",this).html());else try{e[i]=b.unformat.call(g,this,{rowId:j.id,colModel:g.p.colModel[a]},
+a)}catch(c){e[i]=b.jgrid.htmlDecode(b(this).html())}}),d&&(c.push(e),e={})),h++});return c?c:e},delRowData:function(f){var e=!1,c,d;this.each(function(){if(c=this.rows.namedItem(f)){if(b(c).remove(),this.p.records--,this.p.reccount--,this.updatepager(!0,!1),e=!0,this.p.multiselect&&(d=b.inArray(f,this.p.selarrrow),-1!=d&&this.p.selarrrow.splice(d,1)),f==this.p.selrow)this.p.selrow=null}else return!1;if("local"==this.p.datatype){var a=this.p._index[b.jgrid.stripPref(this.p.idPrefix,f)];"undefined"!=
+typeof a&&(this.p.data.splice(a,1),this.refreshIndex())}if(!0===this.p.altRows&&e){var h=this.p.altclass;b(this.rows).each(function(a){1==a%2?b(this).addClass(h):b(this).removeClass(h)})}});return e},setRowData:function(f,e,c){var d,a=!0,h;this.each(function(){if(!this.grid)return!1;var g=this,i,j,l=typeof c,k={};j=g.rows.namedItem(f);if(!j)return!1;if(e)try{if(b(this.p.colModel).each(function(a){d=this.name;void 0!==e[d]&&(k[d]=this.formatter&&"string"===typeof this.formatter&&"date"==this.formatter?
+b.unformat.date.call(g,e[d],this):e[d],i=g.formatter(f,e[d],a,e,"edit"),h=this.title?{title:b.jgrid.stripHtml(i)}:{},!0===g.p.treeGrid&&d==g.p.ExpandColumn?b("td:eq("+a+") > span:first",j).html(i).attr(h):b("td:eq("+a+")",j).html(i).attr(h))}),"local"==g.p.datatype){var m=b.jgrid.stripPref(g.p.idPrefix,f),o=g.p._index[m];if(g.p.treeGrid)for(var p in g.p.treeReader)k.hasOwnProperty(g.p.treeReader[p])&&delete k[g.p.treeReader[p]];"undefined"!=typeof o&&(g.p.data[o]=b.extend(!0,g.p.data[o],k));k=null}}catch(v){a=
+!1}a&&("string"===l?b(j).addClass(c):"object"===l&&b(j).css(c),b(g).triggerHandler("jqGridAfterGridComplete"))});return a},addRowData:function(f,e,c,d){c||(c="last");var a=!1,h,g,i,j,l,k,m,o,p="",v,u,M,F,Z,U;e&&(b.isArray(e)?(v=!0,c="last",u=f):(e=[e],v=!1),this.each(function(){var V=e.length;l=this.p.rownumbers===true?1:0;i=this.p.multiselect===true?1:0;j=this.p.subGrid===true?1:0;if(!v)if(typeof f!="undefined")f=f+"";else{f=b.jgrid.randId();if(this.p.keyIndex!==false){u=this.p.colModel[this.p.keyIndex+
+i+j+l].name;typeof e[0][u]!="undefined"&&(f=e[0][u])}}M=this.p.altclass;for(var N=0,S="",J={},$=b.isFunction(this.p.afterInsertRow)?true:false;N<V;){F=e[N];g=[];if(v){try{f=F[u]}catch(aa){f=b.jgrid.randId()}S=this.p.altRows===true?(this.rows.length-1)%2===0?M:"":""}U=f;f=this.p.idPrefix+f;if(l){p=this.formatCol(0,1,"",null,f,true);g[g.length]='<td role="gridcell" class="ui-state-default jqgrid-rownum" '+p+">0</td>"}if(i){o='<input role="checkbox" type="checkbox" id="jqg_'+this.p.id+"_"+f+'" class="cbox"/>';
+p=this.formatCol(l,1,"",null,f,true);g[g.length]='<td role="gridcell" '+p+">"+o+"</td>"}j&&(g[g.length]=b(this).jqGrid("addSubGridCell",i+l,1));for(m=i+j+l;m<this.p.colModel.length;m++){Z=this.p.colModel[m];h=Z.name;J[h]=F[h];o=this.formatter(f,b.jgrid.getAccessor(F,h),m,F);p=this.formatCol(m,1,o,F,f,true);g[g.length]='<td role="gridcell" '+p+">"+o+"</td>"}g.unshift(this.constructTr(f,false,S,J,J));g[g.length]="</tr>";if(this.rows.length===0)b("table:first",this.grid.bDiv).append(g.join(""));else switch(c){case "last":b(this.rows[this.rows.length-
+1]).after(g.join(""));k=this.rows.length-1;break;case "first":b(this.rows[0]).after(g.join(""));k=1;break;case "after":(k=this.rows.namedItem(d))&&(b(this.rows[k.rowIndex+1]).hasClass("ui-subgrid")?b(this.rows[k.rowIndex+1]).after(g):b(k).after(g.join("")));k++;break;case "before":if(k=this.rows.namedItem(d)){b(k).before(g.join(""));k=k.rowIndex}k--}this.p.subGrid===true&&b(this).jqGrid("addSubGrid",i+l,k);this.p.records++;this.p.reccount++;b(this).triggerHandler("jqGridAfterInsertRow",[f,F,F]);$&&
+this.p.afterInsertRow.call(this,f,F,F);N++;if(this.p.datatype=="local"){J[this.p.localReader.id]=U;this.p._index[U]=this.p.data.length;this.p.data.push(J);J={}}}this.p.altRows===true&&!v&&(c=="last"?(this.rows.length-1)%2==1&&b(this.rows[this.rows.length-1]).addClass(M):b(this.rows).each(function(a){a%2==1?b(this).addClass(M):b(this).removeClass(M)}));this.updatepager(true,true);a=true}));return a},footerData:function(f,e,c){function d(a){for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}var a,
+h=!1,g={},i;"undefined"==typeof f&&(f="get");"boolean"!=typeof c&&(c=!0);f=f.toLowerCase();this.each(function(){var j=this,l;if(!j.grid||!j.p.footerrow||"set"==f&&d(e))return!1;h=!0;b(this.p.colModel).each(function(d){a=this.name;"set"==f?void 0!==e[a]&&(l=c?j.formatter("",e[a],d,e,"edit"):e[a],i=this.title?{title:b.jgrid.stripHtml(l)}:{},b("tr.footrow td:eq("+d+")",j.grid.sDiv).html(l).attr(i),h=!0):"get"==f&&(g[a]=b("tr.footrow td:eq("+d+")",j.grid.sDiv).html())})});return"get"==f?g:h},showHideCol:function(f,
+e){return this.each(function(){var c=this,d=!1,a=b.jgrid.cellWidth()?0:c.p.cellLayout,h;if(c.grid){"string"===typeof f&&(f=[f]);e="none"!=e?"":"none";var g=""===e?!0:!1,i=c.p.groupHeader&&("object"===typeof c.p.groupHeader||b.isFunction(c.p.groupHeader));i&&b(c).jqGrid("destroyGroupHeader",!1);b(this.p.colModel).each(function(i){if(-1!==b.inArray(this.name,f)&&this.hidden===g){if(!0===c.p.frozenColumns&&!0===this.frozen)return!0;b("tr",c.grid.hDiv).each(function(){b(this.cells[i]).css("display",e)});
+b(c.rows).each(function(){b(this).hasClass("jqgroup")||b(this.cells[i]).css("display",e)});c.p.footerrow&&b("tr.footrow td:eq("+i+")",c.grid.sDiv).css("display",e);h=parseInt(this.width,10);c.p.tblwidth="none"===e?c.p.tblwidth-(h+a):c.p.tblwidth+(h+a);this.hidden=!g;d=!0;b(c).triggerHandler("jqGridShowHideCol",[g,this.name,i])}});!0===d&&(!0===c.p.shrinkToFit&&!isNaN(c.p.height)&&(c.p.tblwidth+=parseInt(c.p.scrollOffset,10)),b(c).jqGrid("setGridWidth",!0===c.p.shrinkToFit?c.p.tblwidth:c.p.width));
+i&&b(c).jqGrid("setGroupHeaders",c.p.groupHeader)}})},hideCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",f,"none")})},showCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",f,"")})},remapColumns:function(f,e,c){function d(a){var c;c=a.length?b.makeArray(a):b.extend({},a);b.each(f,function(b){a[b]=c[this]})}function a(a,c){b(">tr"+(c||""),a).each(function(){var a=this,c=b.makeArray(a.cells);b.each(f,function(){var b=c[this];b&&a.appendChild(b)})})}var h=
+this.get(0);d(h.p.colModel);d(h.p.colNames);d(h.grid.headers);a(b("thead:first",h.grid.hDiv),c&&":not(.ui-jqgrid-labels)");e&&a(b("#"+b.jgrid.jqID(h.p.id)+" tbody:first"),".jqgfirstrow, tr.jqgrow, tr.jqfoot");h.p.footerrow&&a(b("tbody:first",h.grid.sDiv));h.p.remapColumns&&(h.p.remapColumns.length?d(h.p.remapColumns):h.p.remapColumns=b.makeArray(f));h.p.lastsort=b.inArray(h.p.lastsort,f);h.p.treeGrid&&(h.p.expColInd=b.inArray(h.p.expColInd,f));b(h).triggerHandler("jqGridRemapColumns",[f,e,c])},setGridWidth:function(f,
+e){return this.each(function(){if(this.grid){var c=this,d,a=0,h=b.jgrid.cellWidth()?0:c.p.cellLayout,g,i=0,j=!1,l=c.p.scrollOffset,k,m=0,o=0,p;"boolean"!=typeof e&&(e=c.p.shrinkToFit);if(!isNaN(f)){f=parseInt(f,10);c.grid.width=c.p.width=f;b("#gbox_"+b.jgrid.jqID(c.p.id)).css("width",f+"px");b("#gview_"+b.jgrid.jqID(c.p.id)).css("width",f+"px");b(c.grid.bDiv).css("width",f+"px");b(c.grid.hDiv).css("width",f+"px");c.p.pager&&b(c.p.pager).css("width",f+"px");c.p.toppager&&b(c.p.toppager).css("width",
+f+"px");!0===c.p.toolbar[0]&&(b(c.grid.uDiv).css("width",f+"px"),"both"==c.p.toolbar[1]&&b(c.grid.ubDiv).css("width",f+"px"));c.p.footerrow&&b(c.grid.sDiv).css("width",f+"px");!1===e&&!0===c.p.forceFit&&(c.p.forceFit=!1);if(!0===e){b.each(c.p.colModel,function(){if(this.hidden===false){d=this.widthOrg;a=a+(d+h);this.fixed?m=m+(d+h):i++;o++}});if(0===i)return;c.p.tblwidth=a;k=f-h*i-m;if(!isNaN(c.p.height)&&(b(c.grid.bDiv)[0].clientHeight<b(c.grid.bDiv)[0].scrollHeight||1===c.rows.length))j=!0,k-=l;
+var a=0,v=0<c.grid.cols.length;b.each(c.p.colModel,function(b){if(this.hidden===false&&!this.fixed){d=this.widthOrg;d=Math.round(k*d/(c.p.tblwidth-h*i-m));if(!(d<0)){this.width=d;a=a+d;c.grid.headers[b].width=d;c.grid.headers[b].el.style.width=d+"px";if(c.p.footerrow)c.grid.footers[b].style.width=d+"px";if(v)c.grid.cols[b].style.width=d+"px";g=b}}});if(!g)return;p=0;j?f-m-(a+h*i)!==l&&(p=f-m-(a+h*i)-l):1!==Math.abs(f-m-(a+h*i))&&(p=f-m-(a+h*i));c.p.colModel[g].width+=p;c.p.tblwidth=a+p+h*i+m;c.p.tblwidth>
+f?(j=c.p.tblwidth-parseInt(f,10),c.p.tblwidth=f,d=c.p.colModel[g].width-=j):d=c.p.colModel[g].width;c.grid.headers[g].width=d;c.grid.headers[g].el.style.width=d+"px";v&&(c.grid.cols[g].style.width=d+"px");c.p.footerrow&&(c.grid.footers[g].style.width=d+"px")}c.p.tblwidth&&(b("table:first",c.grid.bDiv).css("width",c.p.tblwidth+"px"),b("table:first",c.grid.hDiv).css("width",c.p.tblwidth+"px"),c.grid.hDiv.scrollLeft=c.grid.bDiv.scrollLeft,c.p.footerrow&&b("table:first",c.grid.sDiv).css("width",c.p.tblwidth+
+"px"))}}})},setGridHeight:function(f){return this.each(function(){if(this.grid){var e=b(this.grid.bDiv);e.css({height:f+(isNaN(f)?"":"px")});!0===this.p.frozenColumns&&b("#"+b.jgrid.jqID(this.p.id)+"_frozen").parent().height(e.height()-16);this.p.height=f;this.p.scroll&&this.grid.populateVisible()}})},setCaption:function(f){return this.each(function(){this.p.caption=f;b("span.ui-jqgrid-title, span.ui-jqgrid-title-rtl",this.grid.cDiv).html(f);b(this.grid.cDiv).show()})},setLabel:function(f,e,c,d){return this.each(function(){var a=
+-1;if(this.grid&&"undefined"!=typeof f&&(b(this.p.colModel).each(function(b){if(this.name==f)return a=b,!1}),0<=a)){var h=b("tr.ui-jqgrid-labels th:eq("+a+")",this.grid.hDiv);if(e){var g=b(".s-ico",h);b("[id^=jqgh_]",h).empty().html(e).append(g);this.p.colNames[a]=e}c&&("string"===typeof c?b(h).addClass(c):b(h).css(c));"object"===typeof d&&b(h).attr(d)}})},setCell:function(f,e,c,d,a,h){return this.each(function(){var g=-1,i,j;if(this.grid&&(isNaN(e)?b(this.p.colModel).each(function(a){if(this.name==
+e)return g=a,!1}):g=parseInt(e,10),0<=g&&(i=this.rows.namedItem(f)))){var l=b("td:eq("+g+")",i);if(""!==c||!0===h)i=this.formatter(f,c,g,i,"edit"),j=this.p.colModel[g].title?{title:b.jgrid.stripHtml(i)}:{},this.p.treeGrid&&0<b(".tree-wrap",b(l)).length?b("span",b(l)).html(i).attr(j):b(l).html(i).attr(j),"local"==this.p.datatype&&(i=this.p.colModel[g],c=i.formatter&&"string"===typeof i.formatter&&"date"==i.formatter?b.unformat.date.call(this,c,i):c,j=this.p._index[f],"undefined"!=typeof j&&(this.p.data[j][i.name]=
+c));"string"===typeof d?b(l).addClass(d):d&&b(l).css(d);"object"===typeof a&&b(l).attr(a)}})},getCell:function(f,e){var c=!1;this.each(function(){var d=-1;if(this.grid&&(isNaN(e)?b(this.p.colModel).each(function(a){if(this.name===e)return d=a,!1}):d=parseInt(e,10),0<=d)){var a=this.rows.namedItem(f);if(a)try{c=b.unformat.call(this,b("td:eq("+d+")",a),{rowId:a.id,colModel:this.p.colModel[d]},d)}catch(h){c=b.jgrid.htmlDecode(b("td:eq("+d+")",a).html())}}});return c},getCol:function(f,e,c){var d=[],
+a,h=0,g,i,j,e="boolean"!=typeof e?!1:e;"undefined"==typeof c&&(c=!1);this.each(function(){var l=-1;if(this.grid&&(isNaN(f)?b(this.p.colModel).each(function(a){if(this.name===f)return l=a,!1}):l=parseInt(f,10),0<=l)){var k=this.rows.length,m=0;if(k&&0<k){for(;m<k;){if(b(this.rows[m]).hasClass("jqgrow")){try{a=b.unformat.call(this,b(this.rows[m].cells[l]),{rowId:this.rows[m].id,colModel:this.p.colModel[l]},l)}catch(o){a=b.jgrid.htmlDecode(this.rows[m].cells[l].innerHTML)}c?(j=parseFloat(a),h+=j,0===
+m?i=g=j:(g=Math.min(g,j),i=Math.max(i,j))):e?d.push({id:this.rows[m].id,value:a}):d.push(a)}m++}if(c)switch(c.toLowerCase()){case "sum":d=h;break;case "avg":d=h/k;break;case "count":d=k;break;case "min":d=g;break;case "max":d=i}}}});return d},clearGridData:function(f){return this.each(function(){if(this.grid){"boolean"!=typeof f&&(f=!1);if(this.p.deepempty)b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:gt(0)").remove();else{var e=b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:first")[0];b("#"+b.jgrid.jqID(this.p.id)+
+" tbody:first").empty().append(e)}this.p.footerrow&&f&&b(".ui-jqgrid-ftable td",this.grid.sDiv).html("&#160;");this.p.selrow=null;this.p.selarrrow=[];this.p.savedRow=[];this.p.records=0;this.p.page=1;this.p.lastpage=0;this.p.reccount=0;this.p.data=[];this.p._index={};this.updatepager(!0,!1)}})},getInd:function(b,e){var c=!1,d;this.each(function(){(d=this.rows.namedItem(b))&&(c=!0===e?d:d.rowIndex)});return c},bindKeys:function(f){var e=b.extend({onEnter:null,onSpace:null,onLeftKey:null,onRightKey:null,
+scrollingRows:!0},f||{});return this.each(function(){var c=this;b("body").is("[role]")||b("body").attr("role","application");c.p.scrollrows=e.scrollingRows;b(c).keydown(function(d){var a=b(c).find("tr[tabindex=0]")[0],f,g,i,j=c.p.treeReader.expanded_field;if(a)if(i=c.p._index[a.id],37===d.keyCode||38===d.keyCode||39===d.keyCode||40===d.keyCode){if(38===d.keyCode){g=a.previousSibling;f="";if(g)if(b(g).is(":hidden"))for(;g;){if(g=g.previousSibling,!b(g).is(":hidden")&&b(g).hasClass("jqgrow")){f=g.id;
+break}}else f=g.id;b(c).jqGrid("setSelection",f,!0,d)}if(40===d.keyCode){g=a.nextSibling;f="";if(g)if(b(g).is(":hidden"))for(;g;){if(g=g.nextSibling,!b(g).is(":hidden")&&b(g).hasClass("jqgrow")){f=g.id;break}}else f=g.id;b(c).jqGrid("setSelection",f,!0,d)}37===d.keyCode&&(c.p.treeGrid&&c.p.data[i][j]&&b(a).find("div.treeclick").trigger("click"),b(c).triggerHandler("jqGridKeyLeft",[c.p.selrow]),b.isFunction(e.onLeftKey)&&e.onLeftKey.call(c,c.p.selrow));39===d.keyCode&&(c.p.treeGrid&&!c.p.data[i][j]&&
+b(a).find("div.treeclick").trigger("click"),b(c).triggerHandler("jqGridKeyRight",[c.p.selrow]),b.isFunction(e.onRightKey)&&e.onRightKey.call(c,c.p.selrow))}else 13===d.keyCode?(b(c).triggerHandler("jqGridKeyEnter",[c.p.selrow]),b.isFunction(e.onEnter)&&e.onEnter.call(c,c.p.selrow)):32===d.keyCode&&(b(c).triggerHandler("jqGridKeySpace",[c.p.selrow]),b.isFunction(e.onSpace)&&e.onSpace.call(c,c.p.selrow))})})},unbindKeys:function(){return this.each(function(){b(this).unbind("keydown")})},getLocalRow:function(b){var e=
+!1,c;this.each(function(){"undefined"!==typeof b&&(c=this.p._index[b],0<=c&&(e=this.p.data[c]))});return e}})})(jQuery);
+(function(c){c.fmatter={};c.extend(c.fmatter,{isBoolean:function(a){return"boolean"===typeof a},isObject:function(a){return a&&("object"===typeof a||c.isFunction(a))||!1},isString:function(a){return"string"===typeof a},isNumber:function(a){return"number"===typeof a&&isFinite(a)},isNull:function(a){return null===a},isUndefined:function(a){return"undefined"===typeof a},isValue:function(a){return this.isObject(a)||this.isString(a)||this.isNumber(a)||this.isBoolean(a)},isEmpty:function(a){if(!this.isString(a)&&
+this.isValue(a))return!1;if(!this.isValue(a))return!0;a=c.trim(a).replace(/\&nbsp\;/ig,"").replace(/\&#160\;/ig,"");return""===a}});c.fn.fmatter=function(a,b,f,d,e){var g=b,f=c.extend({},c.jgrid.formatter,f);try{g=c.fn.fmatter[a].call(this,b,f,d,e)}catch(h){}return g};c.fmatter.util={NumberFormat:function(a,b){c.fmatter.isNumber(a)||(a*=1);if(c.fmatter.isNumber(a)){var f=0>a,d=a+"",e=b.decimalSeparator?b.decimalSeparator:".",g;if(c.fmatter.isNumber(b.decimalPlaces)){var h=b.decimalPlaces,d=Math.pow(10,
+h),d=Math.round(a*d)/d+"";g=d.lastIndexOf(".");if(0<h){0>g?(d+=e,g=d.length-1):"."!==e&&(d=d.replace(".",e));for(;d.length-1-g<h;)d+="0"}}if(b.thousandsSeparator){h=b.thousandsSeparator;g=d.lastIndexOf(e);g=-1<g?g:d.length;for(var e=d.substring(g),i=-1,j=g;0<j;j--){i++;if(0===i%3&&j!==g&&(!f||1<j))e=h+e;e=d.charAt(j-1)+e}d=e}d=b.prefix?b.prefix+d:d;return d=b.suffix?d+b.suffix:d}return a},DateFormat:function(a,b,f,d){var e=/^\/Date\((([-+])?[0-9]+)(([-+])([0-9]{2})([0-9]{2}))?\)\/$/,g="string"===
+typeof b?b.match(e):null,e=function(a,b){a=""+a;for(b=parseInt(b,10)||2;a.length<b;)a="0"+a;return a},h={m:1,d:1,y:1970,h:0,i:0,s:0,u:0},i=0,j,k=["i18n"];k.i18n={dayNames:d.dayNames,monthNames:d.monthNames};a in d.masks&&(a=d.masks[a]);if(!isNaN(b-0)&&"u"==(""+a).toLowerCase())i=new Date(1E3*parseFloat(b));else if(b.constructor===Date)i=b;else if(null!==g)i=new Date(parseInt(g[1],10)),g[3]&&(a=60*Number(g[5])+Number(g[6]),a*="-"==g[4]?1:-1,a-=i.getTimezoneOffset(),i.setTime(Number(Number(i)+6E4*a)));
+else{b=(""+b).split(/[\\\/:_;.,\t\T\s-]/);a=a.split(/[\\\/:_;.,\t\T\s-]/);g=0;for(j=a.length;g<j;g++)"M"==a[g]&&(i=c.inArray(b[g],k.i18n.monthNames),-1!==i&&12>i&&(b[g]=i+1)),"F"==a[g]&&(i=c.inArray(b[g],k.i18n.monthNames),-1!==i&&11<i&&(b[g]=i+1-12)),b[g]&&(h[a[g].toLowerCase()]=parseInt(b[g],10));h.f&&(h.m=h.f);if(0===h.m&&0===h.y&&0===h.d)return"&#160;";h.m=parseInt(h.m,10)-1;i=h.y;70<=i&&99>=i?h.y=1900+h.y:0<=i&&69>=i&&(h.y=2E3+h.y);i=new Date(h.y,h.m,h.d,h.h,h.i,h.s,h.u)}f in d.masks?f=d.masks[f]:
+f||(f="Y-m-d");a=i.getHours();b=i.getMinutes();h=i.getDate();g=i.getMonth()+1;j=i.getTimezoneOffset();var l=i.getSeconds(),r=i.getMilliseconds(),n=i.getDay(),m=i.getFullYear(),o=(n+6)%7+1,p=(new Date(m,g-1,h)-new Date(m,0,1))/864E5,q={d:e(h),D:k.i18n.dayNames[n],j:h,l:k.i18n.dayNames[n+7],N:o,S:d.S(h),w:n,z:p,W:5>o?Math.floor((p+o-1)/7)+1:Math.floor((p+o-1)/7)||(4>((new Date(m-1,0,1)).getDay()+6)%7?53:52),F:k.i18n.monthNames[g-1+12],m:e(g),M:k.i18n.monthNames[g-1],n:g,t:"?",L:"?",o:"?",Y:m,y:(""+
+m).substring(2),a:12>a?d.AmPm[0]:d.AmPm[1],A:12>a?d.AmPm[2]:d.AmPm[3],B:"?",g:a%12||12,G:a,h:e(a%12||12),H:e(a),i:e(b),s:e(l),u:r,e:"?",I:"?",O:(0<j?"-":"+")+e(100*Math.floor(Math.abs(j)/60)+Math.abs(j)%60,4),P:"?",T:((""+i).match(/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g)||[""]).pop().replace(/[^-+\dA-Z]/g,""),Z:"?",c:"?",r:"?",U:Math.floor(i/1E3)};return f.replace(/\\.|[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g,
+function(a){return a in q?q[a]:a.substring(1)})}};c.fn.fmatter.defaultFormat=function(a,b){return c.fmatter.isValue(a)&&""!==a?a:b.defaultValue?b.defaultValue:"&#160;"};c.fn.fmatter.email=function(a,b){return c.fmatter.isEmpty(a)?c.fn.fmatter.defaultFormat(a,b):'<a href="mailto:'+a+'">'+a+"</a>"};c.fn.fmatter.checkbox=function(a,b){var f=c.extend({},b.checkbox),d;void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));d=!0===f.disabled?'disabled="disabled"':
+"";if(c.fmatter.isEmpty(a)||c.fmatter.isUndefined(a))a=c.fn.fmatter.defaultFormat(a,f);a=(a+"").toLowerCase();return'<input type="checkbox" '+(0>a.search(/(false|0|no|off)/i)?" checked='checked' ":"")+' value="'+a+'" offval="no" '+d+"/>"};c.fn.fmatter.link=function(a,b){var f={target:b.target},d="";void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));f.target&&(d="target="+f.target);return!c.fmatter.isEmpty(a)?"<a "+d+' href="'+a+'">'+
+a+"</a>":c.fn.fmatter.defaultFormat(a,b)};c.fn.fmatter.showlink=function(a,b){var f={baseLinkUrl:b.baseLinkUrl,showAction:b.showAction,addParam:b.addParam||"",target:b.target,idName:b.idName},d="";void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));f.target&&(d="target="+f.target);f=f.baseLinkUrl+f.showAction+"?"+f.idName+"="+b.rowId+f.addParam;return c.fmatter.isString(a)||c.fmatter.isNumber(a)?"<a "+d+' href="'+f+'">'+a+"</a>":c.fn.fmatter.defaultFormat(a,
+b)};c.fn.fmatter.integer=function(a,b){var f=c.extend({},b.integer);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,f)};c.fn.fmatter.number=function(a,b){var f=c.extend({},b.number);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,
+f)};c.fn.fmatter.currency=function(a,b){var f=c.extend({},b.currency);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,f)};c.fn.fmatter.date=function(a,b,f,d){f=c.extend({},b.date);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return!f.reformatAfterEdit&&"edit"==d||c.fmatter.isEmpty(a)?c.fn.fmatter.defaultFormat(a,
+b):c.fmatter.util.DateFormat(f.srcformat,a,f.newformat,f)};c.fn.fmatter.select=function(a,b){var a=a+"",f=!1,d=[],e,g;c.fmatter.isUndefined(b.colModel.formatoptions)?c.fmatter.isUndefined(b.colModel.editoptions)||(f=b.colModel.editoptions.value,e=void 0===b.colModel.editoptions.separator?":":b.colModel.editoptions.separator,g=void 0===b.colModel.editoptions.delimiter?";":b.colModel.editoptions.delimiter):(f=b.colModel.formatoptions.value,e=void 0===b.colModel.formatoptions.separator?":":b.colModel.formatoptions.separator,
+g=void 0===b.colModel.formatoptions.delimiter?";":b.colModel.formatoptions.delimiter);if(f){var h=!0===b.colModel.editoptions.multiple?!0:!1,i=[];h&&(i=a.split(","),i=c.map(i,function(a){return c.trim(a)}));if(c.fmatter.isString(f))for(var j=f.split(g),k=0,l=0;l<j.length;l++)if(g=j[l].split(e),2<g.length&&(g[1]=c.map(g,function(a,b){if(b>0)return a}).join(e)),h)-1<c.inArray(g[0],i)&&(d[k]=g[1],k++);else{if(c.trim(g[0])==c.trim(a)){d[0]=g[1];break}}else c.fmatter.isObject(f)&&(h?d=c.map(i,function(a){return f[a]}):
+d[0]=f[a]||"")}a=d.join(", ");return""===a?c.fn.fmatter.defaultFormat(a,b):a};c.fn.fmatter.rowactions=function(a,b,f,d){var e={keys:!1,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null,restoreAfterError:!0,mtype:"POST",delOptions:{},editOptions:{}},a=c.jgrid.jqID(a),b=c.jgrid.jqID(b),d=c("#"+b)[0].p.colModel[d];c.fmatter.isUndefined(d.formatoptions)||(e=c.extend(e,d.formatoptions));c.fmatter.isUndefined(c("#"+b)[0].p.editOptions)||(e.editOptions=c("#"+
+b)[0].p.editOptions);c.fmatter.isUndefined(c("#"+b)[0].p.delOptions)||(e.delOptions=c("#"+b)[0].p.delOptions);var g=c("#"+b)[0],d=function(d){c.isFunction(e.afterRestore)&&e.afterRestore.call(g,d);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide()};if(c("#"+a,"#"+b).hasClass("jqgrid-new-row")){var h=g.p.prmNames;e.extraparam[h.oper]=h.addoper}h={keys:e.keys,
+oneditfunc:e.onEdit,successfunc:e.onSuccess,url:e.url,extraparam:e.extraparam,aftersavefunc:function(d,f){c.isFunction(e.afterSave)&&e.afterSave.call(g,d,f);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide()},errorfunc:e.onError,afterrestorefunc:d,restoreAfterError:e.restoreAfterError,mtype:e.mtype};switch(f){case "edit":c("#"+b).jqGrid("editRow",
+a,h);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").hide();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").show();c(g).triggerHandler("jqGridAfterGridComplete");break;case "save":c("#"+b).jqGrid("saveRow",a,h)&&(c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show(),c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide(),
+c(g).triggerHandler("jqGridAfterGridComplete"));break;case "cancel":c("#"+b).jqGrid("restoreRow",a,d);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide();c(g).triggerHandler("jqGridAfterGridComplete");break;case "del":c("#"+b).jqGrid("delGridRow",a,e.delOptions);break;case "formedit":c("#"+b).jqGrid("setSelection",a),c("#"+b).jqGrid("editGridRow",a,
+e.editOptions)}};c.fn.fmatter.actions=function(a,b){var f={keys:!1,editbutton:!0,delbutton:!0,editformbutton:!1};c.fmatter.isUndefined(b.colModel.formatoptions)||(f=c.extend(f,b.colModel.formatoptions));var d=b.rowId,e="",g;if("undefined"==typeof d||c.fmatter.isEmpty(d))return"";f.editformbutton?(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','formedit',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ",e=e+"<div title='"+
+c.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>"):f.editbutton&&(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','edit',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover') ",e=e+"<div title='"+c.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>");
+f.delbutton&&(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','del',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ",e=e+"<div title='"+c.jgrid.nav.deltitle+"' style='float:left;margin-left:5px;' class='ui-pg-div ui-inline-del' "+g+"><span class='ui-icon ui-icon-trash'></span></div>");g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','save',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";
+e=e+"<div title='"+c.jgrid.edit.bSubmit+"' style='float:left;display:none' class='ui-pg-div ui-inline-save' "+g+"><span class='ui-icon ui-icon-disk'></span></div>";g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','cancel',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";e=e+"<div title='"+c.jgrid.edit.bCancel+"' style='float:left;display:none;margin-left:5px;' class='ui-pg-div ui-inline-cancel' "+g+"><span class='ui-icon ui-icon-cancel'></span></div>";
+return"<div style='margin-left:8px;'>"+e+"</div>"};c.unformat=function(a,b,f,d){var e,g=b.colModel.formatter,h=b.colModel.formatoptions||{},i=/([\.\*\_\'\(\)\{\}\+\?\\])/g,j=b.colModel.unformat||c.fn.fmatter[g]&&c.fn.fmatter[g].unformat;if("undefined"!==typeof j&&c.isFunction(j))e=j.call(this,c(a).text(),b,a);else if(!c.fmatter.isUndefined(g)&&c.fmatter.isString(g))switch(e=c.jgrid.formatter||{},g){case "integer":h=c.extend({},e.integer,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");
+e=c(a).text().replace(b,"");break;case "number":h=c.extend({},e.number,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");e=c(a).text().replace(b,"").replace(h.decimalSeparator,".");break;case "currency":h=c.extend({},e.currency,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");e=c(a).text();h.prefix&&h.prefix.length&&(e=e.substr(h.prefix.length));h.suffix&&h.suffix.length&&(e=e.substr(0,e.length-h.suffix.length));e=e.replace(b,"").replace(h.decimalSeparator,".");break;case "checkbox":h=
+b.colModel.editoptions?b.colModel.editoptions.value.split(":"):["Yes","No"];e=c("input",a).is(":checked")?h[0]:h[1];break;case "select":e=c.unformat.select(a,b,f,d);break;case "actions":return"";default:e=c(a).text()}return void 0!==e?e:!0===d?c(a).text():c.jgrid.htmlDecode(c(a).html())};c.unformat.select=function(a,b,f,d){f=[];a=c(a).text();if(!0===d)return a;var d=c.extend({},!c.fmatter.isUndefined(b.colModel.formatoptions)?b.colModel.formatoptions:b.colModel.editoptions),b=void 0===d.separator?
+":":d.separator,e=void 0===d.delimiter?";":d.delimiter;if(d.value){var g=d.value,d=!0===d.multiple?!0:!1,h=[];d&&(h=a.split(","),h=c.map(h,function(a){return c.trim(a)}));if(c.fmatter.isString(g))for(var i=g.split(e),j=0,k=0;k<i.length;k++)if(e=i[k].split(b),2<e.length&&(e[1]=c.map(e,function(a,b){if(b>0)return a}).join(b)),d)-1<c.inArray(e[1],h)&&(f[j]=e[0],j++);else{if(c.trim(e[1])==c.trim(a)){f[0]=e[0];break}}else if(c.fmatter.isObject(g)||c.isArray(g))d||(h[0]=a),f=c.map(h,function(a){var b;c.each(g,
+function(c,d){if(d==a){b=c;return false}});if(typeof b!="undefined")return b});return f.join(", ")}return a||""};c.unformat.date=function(a,b){var f=c.jgrid.formatter.date||{};c.fmatter.isUndefined(b.formatoptions)||(f=c.extend({},f,b.formatoptions));return!c.fmatter.isEmpty(a)?c.fmatter.util.DateFormat(f.newformat,a,f.srcformat,f):c.fn.fmatter.defaultFormat(a,b)}})(jQuery);
+(function(a){a.jgrid.extend({getColProp:function(a){var d={},c=this[0];if(!c.grid)return!1;for(var c=c.p.colModel,e=0;e<c.length;e++)if(c[e].name==a){d=c[e];break}return d},setColProp:function(b,d){return this.each(function(){if(this.grid&&d)for(var c=this.p.colModel,e=0;e<c.length;e++)if(c[e].name==b){a.extend(this.p.colModel[e],d);break}})},sortGrid:function(a,d,c){return this.each(function(){var e=-1;if(this.grid){a||(a=this.p.sortname);for(var h=0;h<this.p.colModel.length;h++)if(this.p.colModel[h].index==
+a||this.p.colModel[h].name==a){e=h;break}-1!=e&&(h=this.p.colModel[e].sortable,"boolean"!==typeof h&&(h=!0),"boolean"!==typeof d&&(d=!1),h&&this.sortData("jqgh_"+this.p.id+"_"+a,e,d,c))}})},GridDestroy:function(){return this.each(function(){if(this.grid){this.p.pager&&a(this.p.pager).remove();try{a("#gbox_"+a.jgrid.jqID(this.id)).remove()}catch(b){}}})},GridUnload:function(){return this.each(function(){if(this.grid){var b=a(this).attr("id"),d=a(this).attr("class");this.p.pager&&a(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom");
+var c=document.createElement("table");a(c).attr({id:b});c.className=d;b=a.jgrid.jqID(this.id);a(c).removeClass("ui-jqgrid-btable");1===a(this.p.pager).parents("#gbox_"+b).length?(a(c).insertBefore("#gbox_"+b).show(),a(this.p.pager).insertBefore("#gbox_"+b)):a(c).insertBefore("#gbox_"+b).show();a("#gbox_"+b).remove()}})},setGridState:function(b){return this.each(function(){this.grid&&("hidden"==b?(a(".ui-jqgrid-bdiv, .ui-jqgrid-hdiv","#gview_"+a.jgrid.jqID(this.p.id)).slideUp("fast"),this.p.pager&&
+a(this.p.pager).slideUp("fast"),this.p.toppager&&a(this.p.toppager).slideUp("fast"),!0===this.p.toolbar[0]&&("both"==this.p.toolbar[1]&&a(this.grid.ubDiv).slideUp("fast"),a(this.grid.uDiv).slideUp("fast")),this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+a.jgrid.jqID(this.p.id)).slideUp("fast"),a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s"),this.p.gridstate="hidden"):"visible"==b&&(a(".ui-jqgrid-hdiv, .ui-jqgrid-bdiv",
+"#gview_"+a.jgrid.jqID(this.p.id)).slideDown("fast"),this.p.pager&&a(this.p.pager).slideDown("fast"),this.p.toppager&&a(this.p.toppager).slideDown("fast"),!0===this.p.toolbar[0]&&("both"==this.p.toolbar[1]&&a(this.grid.ubDiv).slideDown("fast"),a(this.grid.uDiv).slideDown("fast")),this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+a.jgrid.jqID(this.p.id)).slideDown("fast"),a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n"),
+this.p.gridstate="visible"))})},filterToolbar:function(b){b=a.extend({autosearch:!0,searchOnEnter:!0,beforeSearch:null,afterSearch:null,beforeClear:null,afterClear:null,searchurl:"",stringResult:!1,groupOp:"AND",defaultSearch:"bw"},b||{});return this.each(function(){function d(b,c){var d=a(b);d[0]&&jQuery.each(c,function(){void 0!==this.data?d.bind(this.type,this.data,this.fn):d.bind(this.type,this.fn)})}var c=this;if(!this.ftoolbar){var e=function(){var d={},j=0,g,f,h={},m;a.each(c.p.colModel,function(){f=
+this.index||this.name;m=this.searchoptions&&this.searchoptions.sopt?this.searchoptions.sopt[0]:"select"==this.stype?"eq":b.defaultSearch;if(g=a("#gs_"+a.jgrid.jqID(this.name),!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).val())d[f]=g,h[f]=m,j++;else try{delete c.p.postData[f]}catch(e){}});var e=0<j?!0:!1;if(!0===b.stringResult||"local"==c.p.datatype){var k='{"groupOp":"'+b.groupOp+'","rules":[',l=0;a.each(d,function(a,b){0<l&&(k+=",");k+='{"field":"'+a+'",';k+='"op":"'+h[a]+'",';
+k+='"data":"'+(b+"").replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';l++});k+="]}";a.extend(c.p.postData,{filters:k});a.each(["searchField","searchString","searchOper"],function(a,b){c.p.postData.hasOwnProperty(b)&&delete c.p.postData[b]})}else a.extend(c.p.postData,d);var p;c.p.searchurl&&(p=c.p.url,a(c).jqGrid("setGridParam",{url:c.p.searchurl}));var r="stop"===a(c).triggerHandler("jqGridToolbarBeforeSearch")?!0:!1;!r&&a.isFunction(b.beforeSearch)&&(r=b.beforeSearch.call(c));r||a(c).jqGrid("setGridParam",
+{search:e}).trigger("reloadGrid",[{page:1}]);p&&a(c).jqGrid("setGridParam",{url:p});a(c).triggerHandler("jqGridToolbarAfterSearch");a.isFunction(b.afterSearch)&&b.afterSearch.call(c)},h=a("<tr class='ui-search-toolbar' role='rowheader'></tr>"),g;a.each(c.p.colModel,function(){var i=this,j,q,f,n;q=a("<th role='columnheader' class='ui-state-default ui-th-column ui-th-"+c.p.direction+"'></th>");j=a("<div style='width:100%;position:relative;height:100%;padding-right:0.3em;'></div>");!0===this.hidden&&
+a(q).css("display","none");this.search=!1===this.search?!1:!0;"undefined"==typeof this.stype&&(this.stype="text");f=a.extend({},this.searchoptions||{});if(this.search)switch(this.stype){case "select":if(n=this.surl||f.dataUrl)a.ajax(a.extend({url:n,dataType:"html",success:function(c){if(f.buildSelect!==void 0)(c=f.buildSelect(c))&&a(j).append(c);else a(j).append(c);f.defaultValue!==void 0&&a("select",j).val(f.defaultValue);a("select",j).attr({name:i.index||i.name,id:"gs_"+i.name});f.attr&&a("select",
+j).attr(f.attr);a("select",j).css({width:"100%"});f.dataInit!==void 0&&f.dataInit(a("select",j)[0]);f.dataEvents!==void 0&&d(a("select",j)[0],f.dataEvents);b.autosearch===true&&a("select",j).change(function(){e();return false});c=null}},a.jgrid.ajaxOptions,c.p.ajaxSelectOptions||{}));else{var m,o,k;i.searchoptions?(m=void 0===i.searchoptions.value?"":i.searchoptions.value,o=void 0===i.searchoptions.separator?":":i.searchoptions.separator,k=void 0===i.searchoptions.delimiter?";":i.searchoptions.delimiter):
+i.editoptions&&(m=void 0===i.editoptions.value?"":i.editoptions.value,o=void 0===i.editoptions.separator?":":i.editoptions.separator,k=void 0===i.editoptions.delimiter?";":i.editoptions.delimiter);if(m){n=document.createElement("select");n.style.width="100%";a(n).attr({name:i.index||i.name,id:"gs_"+i.name});var l;if("string"===typeof m){m=m.split(k);for(var p=0;p<m.length;p++)l=m[p].split(o),k=document.createElement("option"),k.value=l[0],k.innerHTML=l[1],n.appendChild(k)}else if("object"===typeof m)for(l in m)m.hasOwnProperty(l)&&
+(k=document.createElement("option"),k.value=l,k.innerHTML=m[l],n.appendChild(k));void 0!==f.defaultValue&&a(n).val(f.defaultValue);f.attr&&a(n).attr(f.attr);void 0!==f.dataInit&&f.dataInit(n);void 0!==f.dataEvents&&d(n,f.dataEvents);a(j).append(n);!0===b.autosearch&&a(n).change(function(){e();return false})}}break;case "text":o=void 0!==f.defaultValue?f.defaultValue:"",a(j).append("<input type='text' style='width:95%;padding:0px;' name='"+(i.index||i.name)+"' id='gs_"+i.name+"' value='"+o+"'/>"),
+f.attr&&a("input",j).attr(f.attr),void 0!==f.dataInit&&f.dataInit(a("input",j)[0]),void 0!==f.dataEvents&&d(a("input",j)[0],f.dataEvents),!0===b.autosearch&&(b.searchOnEnter?a("input",j).keypress(function(a){if((a.charCode?a.charCode:a.keyCode?a.keyCode:0)==13){e();return false}return this}):a("input",j).keydown(function(a){switch(a.which){case 13:return false;case 9:case 16:case 37:case 38:case 39:case 40:case 27:break;default:g&&clearTimeout(g);g=setTimeout(function(){e()},500)}}))}a(q).append(j);
+a(h).append(q)});a("table thead",c.grid.hDiv).append(h);this.ftoolbar=!0;this.triggerToolbar=e;this.clearToolbar=function(d){var j={},g=0,f,d="boolean"!=typeof d?!0:d;a.each(c.p.colModel,function(){var b;this.searchoptions&&void 0!==this.searchoptions.defaultValue&&(b=this.searchoptions.defaultValue);f=this.index||this.name;switch(this.stype){case "select":a("#gs_"+a.jgrid.jqID(this.name)+" option",!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).each(function(c){if(c===0)this.selected=
+true;if(a(this).val()==b){this.selected=true;return false}});if(void 0!==b)j[f]=b,g++;else try{delete c.p.postData[f]}catch(d){}break;case "text":if(a("#gs_"+a.jgrid.jqID(this.name),!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).val(b),void 0!==b)j[f]=b,g++;else try{delete c.p.postData[f]}catch(e){}}});var h=0<g?!0:!1;if(!0===b.stringResult||"local"==c.p.datatype){var e='{"groupOp":"'+b.groupOp+'","rules":[',o=0;a.each(j,function(a,b){0<o&&(e+=",");e+='{"field":"'+a+'",';e+='"op":"eq",';
+e+='"data":"'+(b+"").replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';o++});e+="]}";a.extend(c.p.postData,{filters:e});a.each(["searchField","searchString","searchOper"],function(a,b){c.p.postData.hasOwnProperty(b)&&delete c.p.postData[b]})}else a.extend(c.p.postData,j);var k;c.p.searchurl&&(k=c.p.url,a(c).jqGrid("setGridParam",{url:c.p.searchurl}));var l="stop"===a(c).triggerHandler("jqGridToolbarBeforeClear")?!0:!1;!l&&a.isFunction(b.beforeClear)&&(l=b.beforeClear.call(c));l||d&&a(c).jqGrid("setGridParam",
+{search:h}).trigger("reloadGrid",[{page:1}]);k&&a(c).jqGrid("setGridParam",{url:k});a(c).triggerHandler("jqGridToolbarAfterClear");a.isFunction(b.afterClear)&&b.afterClear()};this.toggleToolbar=function(){var b=a("tr.ui-search-toolbar",c.grid.hDiv),d=!0===c.p.frozenColumns?a("tr.ui-search-toolbar",c.grid.fhDiv):!1;"none"==b.css("display")?(b.show(),d&&d.show()):(b.hide(),d&&d.hide())}}})},destroyGroupHeader:function(b){"undefined"==typeof b&&(b=!0);return this.each(function(){var d,c,e,h,g,i;c=this.grid;
+var j=a("table.ui-jqgrid-htable thead",c.hDiv),q=this.p.colModel;if(c){a(this).unbind(".setGroupHeaders");d=a("<tr>",{role:"rowheader"}).addClass("ui-jqgrid-labels");h=c.headers;c=0;for(e=h.length;c<e;c++){g=q[c].hidden?"none":"";g=a(h[c].el).width(h[c].width).css("display",g);try{g.removeAttr("rowSpan")}catch(f){g.attr("rowSpan",1)}d.append(g);i=g.children("span.ui-jqgrid-resize");0<i.length&&(i[0].style.height="");g.children("div")[0].style.top=""}a(j).children("tr.ui-jqgrid-labels").remove();a(j).prepend(d);
+!0===b&&a(this).jqGrid("setGridParam",{groupHeader:null})}})},setGroupHeaders:function(b){b=a.extend({useColSpanStyle:!1,groupHeaders:[]},b||{});return this.each(function(){this.p.groupHeader=b;var d,c,e=0,h,g,i,j,q,f=this.p.colModel,n=f.length,m=this.grid.headers,o=a("table.ui-jqgrid-htable",this.grid.hDiv),k=o.children("thead").children("tr.ui-jqgrid-labels:last").addClass("jqg-second-row-header");h=o.children("thead");var l=o.find(".jqg-first-row-header");null===l.html()?l=a("<tr>",{role:"row",
+"aria-hidden":"true"}).addClass("jqg-first-row-header").css("height","auto"):l.empty();var p,r=function(a,b){for(var c=0,d=b.length;c<d;c++)if(b[c].startColumnName===a)return c;return-1};a(this).prepend(h);h=a("<tr>",{role:"rowheader"}).addClass("ui-jqgrid-labels jqg-third-row-header");for(d=0;d<n;d++)if(i=m[d].el,j=a(i),c=f[d],g={height:"0px",width:m[d].width+"px",display:c.hidden?"none":""},a("<th>",{role:"gridcell"}).css(g).addClass("ui-first-th-"+this.p.direction).appendTo(l),i.style.width="",
+g=r(c.name,b.groupHeaders),0<=g){g=b.groupHeaders[g];e=g.numberOfColumns;q=g.titleText;for(g=c=0;g<e&&d+g<n;g++)f[d+g].hidden||c++;g=a("<th>").attr({role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+this.p.direction).css({height:"22px","border-top":"0px none"}).html(q);0<c&&g.attr("colspan",""+c);this.p.headertitles&&g.attr("title",g.text());0===c&&g.hide();j.before(g);h.append(i);e-=1}else 0===e?b.useColSpanStyle?j.attr("rowspan","2"):(a("<th>",{role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+
+this.p.direction).css({display:c.hidden?"none":"","border-top":"0px none"}).insertBefore(j),h.append(i)):(h.append(i),e--);f=a(this).children("thead");f.prepend(l);h.insertAfter(k);o.append(f);b.useColSpanStyle&&(o.find("span.ui-jqgrid-resize").each(function(){var b=a(this).parent();b.is(":visible")&&(this.style.cssText="height: "+b.height()+"px !important; cursor: col-resize;")}),o.find("div.ui-jqgrid-sortable").each(function(){var b=a(this),c=b.parent();c.is(":visible")&&c.is(":has(span.ui-jqgrid-resize)")&&
+b.css("top",(c.height()-b.outerHeight())/2+"px")}));p=f.find("tr.jqg-first-row-header");a(this).bind("jqGridResizeStop.setGroupHeaders",function(a,b,c){p.find("th").eq(c).width(b)})})},setFrozenColumns:function(){return this.each(function(){if(this.grid){var b=this,d=b.p.colModel,c=0,e=d.length,h=-1,g=!1;if(!(!0===b.p.subGrid||!0===b.p.treeGrid||!0===b.p.cellEdit||b.p.sortable||b.p.scroll||b.p.grouping)){b.p.rownumbers&&c++;for(b.p.multiselect&&c++;c<e;){if(!0===d[c].frozen)g=!0,h=c;else break;c++}if(0<=
+h&&g){d=b.p.caption?a(b.grid.cDiv).outerHeight():0;c=a(".ui-jqgrid-htable","#gview_"+a.jgrid.jqID(b.p.id)).height();b.p.toppager&&(d+=a(b.grid.topDiv).outerHeight());!0===b.p.toolbar[0]&&"bottom"!=b.p.toolbar[1]&&(d+=a(b.grid.uDiv).outerHeight());b.grid.fhDiv=a('<div style="position:absolute;left:0px;top:'+d+"px;height:"+c+'px;" class="frozen-div ui-state-default ui-jqgrid-hdiv"></div>');b.grid.fbDiv=a('<div style="position:absolute;left:0px;top:'+(parseInt(d,10)+parseInt(c,10)+1)+'px;overflow-y:hidden" class="frozen-bdiv ui-jqgrid-bdiv"></div>');
+a("#gview_"+a.jgrid.jqID(b.p.id)).append(b.grid.fhDiv);d=a(".ui-jqgrid-htable","#gview_"+a.jgrid.jqID(b.p.id)).clone(!0);if(b.p.groupHeader){a("tr.jqg-first-row-header, tr.jqg-third-row-header",d).each(function(){a("th:gt("+h+")",this).remove()});var i=-1,j=-1;a("tr.jqg-second-row-header th",d).each(function(){var b=parseInt(a(this).attr("colspan"),10);b&&(i+=b,j++);if(i===h)return!1});i!==h&&(j=h);a("tr.jqg-second-row-header",d).each(function(){a("th:gt("+j+")",this).remove()})}else a("tr",d).each(function(){a("th:gt("+
+h+")",this).remove()});a(d).width(1);a(b.grid.fhDiv).append(d).mousemove(function(a){if(b.grid.resizing)return b.grid.dragMove(a),!1});a(b).bind("jqGridResizeStop.setFrozenColumns",function(c,d,e){c=a(".ui-jqgrid-htable",b.grid.fhDiv);a("th:eq("+e+")",c).width(d);c=a(".ui-jqgrid-btable",b.grid.fbDiv);a("tr:first td:eq("+e+")",c).width(d)});a(b).bind("jqGridOnSortCol.setFrozenColumns",function(c,d){var e=a("tr.ui-jqgrid-labels:last th:eq("+b.p.lastsort+")",b.grid.fhDiv),g=a("tr.ui-jqgrid-labels:last th:eq("+
+d+")",b.grid.fhDiv);a("span.ui-grid-ico-sort",e).addClass("ui-state-disabled");a(e).attr("aria-selected","false");a("span.ui-icon-"+b.p.sortorder,g).removeClass("ui-state-disabled");a(g).attr("aria-selected","true");!b.p.viewsortcols[0]&&b.p.lastsort!=d&&(a("span.s-ico",e).hide(),a("span.s-ico",g).show())});a("#gview_"+a.jgrid.jqID(b.p.id)).append(b.grid.fbDiv);jQuery(b.grid.bDiv).scroll(function(){jQuery(b.grid.fbDiv).scrollTop(jQuery(this).scrollTop())});!0===b.p.hoverrows&&a("#"+a.jgrid.jqID(b.p.id)).unbind("mouseover").unbind("mouseout");
+a(b).bind("jqGridAfterGridComplete.setFrozenColumns",function(){a("#"+a.jgrid.jqID(b.p.id)+"_frozen").remove();jQuery(b.grid.fbDiv).height(jQuery(b.grid.bDiv).height()-16);var c=a("#"+a.jgrid.jqID(b.p.id)).clone(!0);a("tr",c).each(function(){a("td:gt("+h+")",this).remove()});a(c).width(1).attr("id",b.p.id+"_frozen");a(b.grid.fbDiv).append(c);!0===b.p.hoverrows&&(a("tr.jqgrow",c).hover(function(){a(this).addClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)).addClass("ui-state-hover")},
+function(){a(this).removeClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)).removeClass("ui-state-hover")}),a("tr.jqgrow","#"+a.jgrid.jqID(b.p.id)).hover(function(){a(this).addClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)+"_frozen").addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)+"_frozen").removeClass("ui-state-hover")}));c=null});b.p.frozenColumns=!0}}}})},
+destroyFrozenColumns:function(){return this.each(function(){if(this.grid&&!0===this.p.frozenColumns){a(this.grid.fhDiv).remove();a(this.grid.fbDiv).remove();this.grid.fhDiv=null;this.grid.fbDiv=null;a(this).unbind(".setFrozenColumns");if(!0===this.p.hoverrows){var b;a("#"+a.jgrid.jqID(this.p.id)).bind("mouseover",function(d){b=a(d.target).closest("tr.jqgrow");"ui-subgrid"!==a(b).attr("class")&&a(b).addClass("ui-state-hover")}).bind("mouseout",function(d){b=a(d.target).closest("tr.jqgrow");a(b).removeClass("ui-state-hover")})}this.p.frozenColumns=
+!1}})}})})(jQuery);
+(function(a){a.extend(a.jgrid,{showModal:function(a){a.w.show()},closeModal:function(a){a.w.hide().attr("aria-hidden","true");a.o&&a.o.remove()},hideModal:function(d,b){b=a.extend({jqm:!0,gb:""},b||{});if(b.onClose){var c=b.onClose(d);if("boolean"==typeof c&&!c)return}if(a.fn.jqm&&!0===b.jqm)a(d).attr("aria-hidden","true").jqmHide();else{if(""!==b.gb)try{a(".jqgrid-overlay:first",b.gb).hide()}catch(f){}a(d).hide().attr("aria-hidden","true")}},findPos:function(a){var b=0,c=0;if(a.offsetParent){do b+=
+a.offsetLeft,c+=a.offsetTop;while(a=a.offsetParent)}return[b,c]},createModal:function(d,b,c,f,g,h,i){var e=document.createElement("div"),l,j=this,i=a.extend({},i||{});l="rtl"==a(c.gbox).attr("dir")?!0:!1;e.className="ui-widget ui-widget-content ui-corner-all ui-jqdialog";e.id=d.themodal;var k=document.createElement("div");k.className="ui-jqdialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix";k.id=d.modalhead;a(k).append("<span class='ui-jqdialog-title'>"+c.caption+"</span>");var n=a("<a href='javascript:void(0)' class='ui-jqdialog-titlebar-close ui-corner-all'></a>").hover(function(){n.addClass("ui-state-hover")},
+function(){n.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-closethick'></span>");a(k).append(n);l?(e.dir="rtl",a(".ui-jqdialog-title",k).css("float","right"),a(".ui-jqdialog-titlebar-close",k).css("left","0.3em")):(e.dir="ltr",a(".ui-jqdialog-title",k).css("float","left"),a(".ui-jqdialog-titlebar-close",k).css("right","0.3em"));var m=document.createElement("div");a(m).addClass("ui-jqdialog-content ui-widget-content").attr("id",d.modalcontent);a(m).append(b);e.appendChild(m);
+a(e).prepend(k);!0===h?a("body").append(e):"string"==typeof h?a(h).append(e):a(e).insertBefore(f);a(e).css(i);"undefined"===typeof c.jqModal&&(c.jqModal=!0);b={};if(a.fn.jqm&&!0===c.jqModal)0===c.left&&(0===c.top&&c.overlay)&&(i=[],i=a.jgrid.findPos(g),c.left=i[0]+4,c.top=i[1]+4),b.top=c.top+"px",b.left=c.left;else if(0!==c.left||0!==c.top)b.left=c.left,b.top=c.top+"px";a("a.ui-jqdialog-titlebar-close",k).click(function(){var b=a("#"+a.jgrid.jqID(d.themodal)).data("onClose")||c.onClose,e=a("#"+a.jgrid.jqID(d.themodal)).data("gbox")||
+c.gbox;j.hideModal("#"+a.jgrid.jqID(d.themodal),{gb:e,jqm:c.jqModal,onClose:b});return false});if(0===c.width||!c.width)c.width=300;if(0===c.height||!c.height)c.height=200;c.zIndex||(f=a(f).parents("*[role=dialog]").filter(":first").css("z-index"),c.zIndex=f?parseInt(f,10)+2:950);f=0;l&&(b.left&&!h)&&(f=a(c.gbox).width()-(!isNaN(c.width)?parseInt(c.width,10):0)-8,b.left=parseInt(b.left,10)+parseInt(f,10));b.left&&(b.left+="px");a(e).css(a.extend({width:isNaN(c.width)?"auto":c.width+"px",height:isNaN(c.height)?
+"auto":c.height+"px",zIndex:c.zIndex,overflow:"hidden"},b)).attr({tabIndex:"-1",role:"dialog","aria-labelledby":d.modalhead,"aria-hidden":"true"});"undefined"==typeof c.drag&&(c.drag=!0);"undefined"==typeof c.resize&&(c.resize=!0);if(c.drag)if(a(k).css("cursor","move"),a.fn.jqDrag)a(e).jqDrag(k);else try{a(e).draggable({handle:a("#"+a.jgrid.jqID(k.id))})}catch(o){}if(c.resize)if(a.fn.jqResize)a(e).append("<div class='jqResize ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se ui-icon-grip-diagonal-se'></div>"),
+a("#"+a.jgrid.jqID(d.themodal)).jqResize(".jqResize",d.scrollelm?"#"+a.jgrid.jqID(d.scrollelm):!1);else try{a(e).resizable({handles:"se, sw",alsoResize:d.scrollelm?"#"+a.jgrid.jqID(d.scrollelm):!1})}catch(p){}!0===c.closeOnEscape&&a(e).keydown(function(b){if(b.which==27){b=a("#"+a.jgrid.jqID(d.themodal)).data("onClose")||c.onClose;j.hideModal(this,{gb:c.gbox,jqm:c.jqModal,onClose:b})}})},viewModal:function(d,b){b=a.extend({toTop:!0,overlay:10,modal:!1,overlayClass:"ui-widget-overlay",onShow:a.jgrid.showModal,
+onHide:a.jgrid.closeModal,gbox:"",jqm:!0,jqM:!0},b||{});if(a.fn.jqm&&!0===b.jqm)b.jqM?a(d).attr("aria-hidden","false").jqm(b).jqmShow():a(d).attr("aria-hidden","false").jqmShow();else{""!==b.gbox&&(a(".jqgrid-overlay:first",b.gbox).show(),a(d).data("gbox",b.gbox));a(d).show().attr("aria-hidden","false");try{a(":input:visible",d)[0].focus()}catch(c){}}},info_dialog:function(d,b,c,f){var g={width:290,height:"auto",dataheight:"auto",drag:!0,resize:!1,caption:"<b>"+d+"</b>",left:250,top:170,zIndex:1E3,
+jqModal:!0,modal:!1,closeOnEscape:!0,align:"center",buttonalign:"center",buttons:[]};a.extend(g,f||{});var h=g.jqModal,i=this;a.fn.jqm&&!h&&(h=!1);d="";if(0<g.buttons.length)for(f=0;f<g.buttons.length;f++)"undefined"==typeof g.buttons[f].id&&(g.buttons[f].id="info_button_"+f),d+="<a href='javascript:void(0)' id='"+g.buttons[f].id+"' class='fm-button ui-state-default ui-corner-all'>"+g.buttons[f].text+"</a>";f=isNaN(g.dataheight)?g.dataheight:g.dataheight+"px";b="<div id='info_id'>"+("<div id='infocnt' style='margin:0px;padding-bottom:1em;width:100%;overflow:auto;position:relative;height:"+
+f+";"+("text-align:"+g.align+";")+"'>"+b+"</div>");b+=c?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'><a href='javascript:void(0)' id='closedialog' class='fm-button ui-state-default ui-corner-all'>"+c+"</a>"+d+"</div>":""!==d?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'>"+
+d+"</div>":"";b+="</div>";try{"false"==a("#info_dialog").attr("aria-hidden")&&a.jgrid.hideModal("#info_dialog",{jqm:h}),a("#info_dialog").remove()}catch(e){}a.jgrid.createModal({themodal:"info_dialog",modalhead:"info_head",modalcontent:"info_content",scrollelm:"infocnt"},b,g,"","",!0);d&&a.each(g.buttons,function(b){a("#"+a.jgrid.jqID(this.id),"#info_id").bind("click",function(){g.buttons[b].onClick.call(a("#info_dialog"));return!1})});a("#closedialog","#info_id").click(function(){i.hideModal("#info_dialog",
+{jqm:h});return!1});a(".fm-button","#info_dialog").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});a.isFunction(g.beforeOpen)&&g.beforeOpen();a.jgrid.viewModal("#info_dialog",{onHide:function(a){a.w.hide().remove();a.o&&a.o.remove()},modal:g.modal,jqm:h});a.isFunction(g.afterOpen)&&g.afterOpen();try{a("#info_dialog").focus()}catch(l){}},createEl:function(d,b,c,f,g){function h(b,d){a.isFunction(d.dataInit)&&d.dataInit.call(l,b);d.dataEvents&&
+a.each(d.dataEvents,function(){void 0!==this.data?a(b).bind(this.type,this.data,this.fn):a(b).bind(this.type,this.fn)});return d}function i(b,d,c){var e="dataInit dataEvents dataUrl buildSelect sopt searchhidden defaultValue attr".split(" ");"undefined"!=typeof c&&a.isArray(c)&&a.merge(e,c);a.each(d,function(d,c){-1===a.inArray(d,e)&&a(b).attr(d,c)});d.hasOwnProperty("id")||a(b).attr("id",a.jgrid.randId())}var e="",l=this;switch(d){case "textarea":e=document.createElement("textarea");f?b.cols||a(e).css({width:"98%"}):
+b.cols||(b.cols=20);b.rows||(b.rows=2);if("&nbsp;"==c||"&#160;"==c||1==c.length&&160==c.charCodeAt(0))c="";e.value=c;i(e,b);b=h(e,b);a(e).attr({role:"textbox",multiline:"true"});break;case "checkbox":e=document.createElement("input");e.type="checkbox";b.value?(d=b.value.split(":"),c===d[0]&&(e.checked=!0,e.defaultChecked=!0),e.value=d[0],a(e).attr("offval",d[1])):(d=c.toLowerCase(),0>d.search(/(false|0|no|off|undefined)/i)&&""!==d?(e.checked=!0,e.defaultChecked=!0,e.value=c):e.value="on",a(e).attr("offval",
+"off"));i(e,b,["value"]);b=h(e,b);a(e).attr("role","checkbox");break;case "select":e=document.createElement("select");e.setAttribute("role","select");f=[];!0===b.multiple?(d=!0,e.multiple="multiple",a(e).attr("aria-multiselectable","true")):d=!1;if("undefined"!=typeof b.dataUrl)a.ajax(a.extend({url:b.dataUrl,type:"GET",dataType:"html",context:{elem:e,options:b,vl:c},success:function(d){var b=[],c=this.elem,e=this.vl,f=a.extend({},this.options),g=f.multiple===true;a.isFunction(f.buildSelect)&&(d=f.buildSelect.call(l,
+d));if(d=a(d).html()){a(c).append(d);i(c,f);f=h(c,f);if(typeof f.size==="undefined")f.size=g?3:1;if(g){b=e.split(",");b=a.map(b,function(b){return a.trim(b)})}else b[0]=a.trim(e);setTimeout(function(){a("option",c).each(function(d){if(d===0&&c.multiple)this.selected=false;a(this).attr("role","option");if(a.inArray(a.trim(a(this).text()),b)>-1||a.inArray(a.trim(a(this).val()),b)>-1)this.selected="selected"})},0)}}},g||{}));else if(b.value){var j;"undefined"===typeof b.size&&(b.size=d?3:1);d&&(f=c.split(","),
+f=a.map(f,function(b){return a.trim(b)}));"function"===typeof b.value&&(b.value=b.value());var k,n,m=void 0===b.separator?":":b.separator,g=void 0===b.delimiter?";":b.delimiter;if("string"===typeof b.value){k=b.value.split(g);for(j=0;j<k.length;j++){n=k[j].split(m);2<n.length&&(n[1]=a.map(n,function(a,b){if(b>0)return a}).join(m));g=document.createElement("option");g.setAttribute("role","option");g.value=n[0];g.innerHTML=n[1];e.appendChild(g);if(!d&&(a.trim(n[0])==a.trim(c)||a.trim(n[1])==a.trim(c)))g.selected=
+"selected";if(d&&(-1<a.inArray(a.trim(n[1]),f)||-1<a.inArray(a.trim(n[0]),f)))g.selected="selected"}}else if("object"===typeof b.value)for(j in m=b.value,m)if(m.hasOwnProperty(j)){g=document.createElement("option");g.setAttribute("role","option");g.value=j;g.innerHTML=m[j];e.appendChild(g);if(!d&&(a.trim(j)==a.trim(c)||a.trim(m[j])==a.trim(c)))g.selected="selected";if(d&&(-1<a.inArray(a.trim(m[j]),f)||-1<a.inArray(a.trim(j),f)))g.selected="selected"}i(e,b,["value"]);b=h(e,b)}break;case "text":case "password":case "button":j=
+"button"==d?"button":"textbox";e=document.createElement("input");e.type=d;e.value=c;i(e,b);b=h(e,b);"button"!=d&&(f?b.size||a(e).css({width:"98%"}):b.size||(b.size=20));a(e).attr("role",j);break;case "image":case "file":e=document.createElement("input");e.type=d;i(e,b);b=h(e,b);break;case "custom":e=document.createElement("span");try{if(a.isFunction(b.custom_element))if(m=b.custom_element.call(l,c,b))m=a(m).addClass("customelement").attr({id:b.id,name:b.name}),a(e).empty().append(m);else throw"e2";
+else throw"e1";}catch(o){"e1"==o&&a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.nodefined,a.jgrid.edit.bClose),"e2"==o?a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.novalue,a.jgrid.edit.bClose):a.jgrid.info_dialog(a.jgrid.errors.errcap,"string"===typeof o?o:o.message,a.jgrid.edit.bClose)}}return e},checkDate:function(a,b){var c={},f,a=a.toLowerCase();f=-1!=a.indexOf("/")?"/":-1!=a.indexOf("-")?"-":-1!=a.indexOf(".")?
+".":"/";a=a.split(f);b=b.split(f);if(3!=b.length)return!1;f=-1;for(var g,h=-1,i=-1,e=0;e<a.length;e++)g=isNaN(b[e])?0:parseInt(b[e],10),c[a[e]]=g,g=a[e],-1!=g.indexOf("y")&&(f=e),-1!=g.indexOf("m")&&(i=e),-1!=g.indexOf("d")&&(h=e);g="y"==a[f]||"yyyy"==a[f]?4:"yy"==a[f]?2:-1;var e=function(a){for(var b=1;b<=a;b++){this[b]=31;if(4==b||6==b||9==b||11==b)this[b]=30;2==b&&(this[b]=29)}return this}(12),l;if(-1===f)return!1;l=c[a[f]].toString();2==g&&1==l.length&&(g=1);if(l.length!=g||0===c[a[f]]&&"00"!=
+b[f]||-1===i)return!1;l=c[a[i]].toString();if(1>l.length||(1>c[a[i]]||12<c[a[i]])||-1===h)return!1;l=c[a[h]].toString();return 1>l.length||1>c[a[h]]||31<c[a[h]]||2==c[a[i]]&&c[a[h]]>(0===c[a[f]]%4&&(0!==c[a[f]]%100||0===c[a[f]]%400)?29:28)||c[a[h]]>e[c[a[i]]]?!1:!0},isEmpty:function(a){return a.match(/^\s+$/)||""===a?!0:!1},checkTime:function(d){var b=/^(\d{1,2}):(\d{2})([ap]m)?$/;if(!a.jgrid.isEmpty(d))if(d=d.match(b)){if(d[3]){if(1>d[1]||12<d[1])return!1}else if(23<d[1])return!1;if(59<d[2])return!1}else return!1;
+return!0},checkValues:function(d,b,c,f,g){var h,i;if("undefined"===typeof f)if("string"==typeof b){f=0;for(g=c.p.colModel.length;f<g;f++)if(c.p.colModel[f].name==b){h=c.p.colModel[f].editrules;b=f;try{i=c.p.colModel[f].formoptions.label}catch(e){}break}}else 0<=b&&(h=c.p.colModel[b].editrules);else h=f,i=void 0===g?"_":g;if(h){i||(i=c.p.colNames[b]);if(!0===h.required&&a.jgrid.isEmpty(d))return[!1,i+": "+a.jgrid.edit.msg.required,""];f=!1===h.required?!1:!0;if(!0===h.number&&!(!1===f&&a.jgrid.isEmpty(d))&&
+isNaN(d))return[!1,i+": "+a.jgrid.edit.msg.number,""];if("undefined"!=typeof h.minValue&&!isNaN(h.minValue)&&parseFloat(d)<parseFloat(h.minValue))return[!1,i+": "+a.jgrid.edit.msg.minValue+" "+h.minValue,""];if("undefined"!=typeof h.maxValue&&!isNaN(h.maxValue)&&parseFloat(d)>parseFloat(h.maxValue))return[!1,i+": "+a.jgrid.edit.msg.maxValue+" "+h.maxValue,""];if(!0===h.email&&!(!1===f&&a.jgrid.isEmpty(d))&&(g=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i,
+!g.test(d)))return[!1,i+": "+a.jgrid.edit.msg.email,""];if(!0===h.integer&&!(!1===f&&a.jgrid.isEmpty(d))&&(isNaN(d)||0!==d%1||-1!=d.indexOf(".")))return[!1,i+": "+a.jgrid.edit.msg.integer,""];if(!0===h.date&&!(!1===f&&a.jgrid.isEmpty(d))&&(b=c.p.colModel[b].formatoptions&&c.p.colModel[b].formatoptions.newformat?c.p.colModel[b].formatoptions.newformat:c.p.colModel[b].datefmt||"Y-m-d",!a.jgrid.checkDate(b,d)))return[!1,i+": "+a.jgrid.edit.msg.date+" - "+b,""];if(!0===h.time&&!(!1===f&&a.jgrid.isEmpty(d))&&
+!a.jgrid.checkTime(d))return[!1,i+": "+a.jgrid.edit.msg.date+" - hh:mm (am/pm)",""];if(!0===h.url&&!(!1===f&&a.jgrid.isEmpty(d))&&(g=/^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i,!g.test(d)))return[!1,i+": "+a.jgrid.edit.msg.url,""];if(!0===h.custom&&!(!1===f&&a.jgrid.isEmpty(d)))return a.isFunction(h.custom_func)?(d=h.custom_func.call(c,d,i),a.isArray(d)?d:[!1,a.jgrid.edit.msg.customarray,""]):[!1,a.jgrid.edit.msg.customfcheck,
+""]}return[!0,"",""]}})})(jQuery);
+(function(a){var c={};a.jgrid.extend({searchGrid:function(c){c=a.extend({recreateFilter:!1,drag:!0,sField:"searchField",sValue:"searchString",sOper:"searchOper",sFilter:"filters",loadDefaults:!0,beforeShowSearch:null,afterShowSearch:null,onInitializeSearch:null,afterRedraw:null,afterChange:null,closeAfterSearch:!1,closeAfterReset:!1,closeOnEscape:!1,searchOnEnter:!1,multipleSearch:!1,multipleGroup:!1,top:0,left:0,jqModal:!0,modal:!1,resize:!0,width:450,height:"auto",dataheight:"auto",showQuery:!1,
+errorcheck:!0,sopt:null,stringResult:void 0,onClose:null,onSearch:null,onReset:null,toTop:!0,overlay:30,columns:[],tmplNames:null,tmplFilters:null,tmplLabel:" Template: ",showOnLoad:!1,layer:null},a.jgrid.search,c||{});return this.each(function(){function d(b){r=a(e).triggerHandler("jqGridFilterBeforeShow",[b]);"undefined"===typeof r&&(r=!0);r&&a.isFunction(c.beforeShowSearch)&&(r=c.beforeShowSearch.call(e,b));r&&(a.jgrid.viewModal("#"+a.jgrid.jqID(t.themodal),{gbox:"#gbox_"+a.jgrid.jqID(l),jqm:c.jqModal,
+modal:c.modal,overlay:c.overlay,toTop:c.toTop}),a(e).triggerHandler("jqGridFilterAfterShow",[b]),a.isFunction(c.afterShowSearch)&&c.afterShowSearch.call(e,b))}var e=this;if(e.grid){var l="fbox_"+e.p.id,r=!0,t={themodal:"searchmod"+l,modalhead:"searchhd"+l,modalcontent:"searchcnt"+l,scrollelm:l},s=e.p.postData[c.sFilter];"string"===typeof s&&(s=a.jgrid.parse(s));!0===c.recreateFilter&&a("#"+a.jgrid.jqID(t.themodal)).remove();if(null!==a("#"+a.jgrid.jqID(t.themodal)).html())d(a("#fbox_"+a.jgrid.jqID(+e.p.id)));
+else{var p=a("<div><div id='"+l+"' class='searchFilter' style='overflow:auto'></div></div>").insertBefore("#gview_"+a.jgrid.jqID(e.p.id)),g="left",f="";"rtl"==e.p.direction&&(g="right",f=" style='text-align:left'",p.attr("dir","rtl"));var n=a.extend([],e.p.colModel),w="<a href='javascript:void(0)' id='"+l+"_search' class='fm-button ui-state-default ui-corner-all fm-button-icon-right ui-reset'><span class='ui-icon ui-icon-search'></span>"+c.Find+"</a>",b="<a href='javascript:void(0)' id='"+l+"_reset' class='fm-button ui-state-default ui-corner-all fm-button-icon-left ui-search'><span class='ui-icon ui-icon-arrowreturnthick-1-w'></span>"+
+c.Reset+"</a>",m="",h="",k,j=!1,o=-1;c.showQuery&&(m="<a href='javascript:void(0)' id='"+l+"_query' class='fm-button ui-state-default ui-corner-all fm-button-icon-left'><span class='ui-icon ui-icon-comment'></span>Query</a>");c.columns.length?n=c.columns:a.each(n,function(a,b){if(!b.label)b.label=e.p.colNames[a];if(!j){var c=typeof b.search==="undefined"?true:b.search,d=b.hidden===true;if(b.searchoptions&&b.searchoptions.searchhidden===true&&c||c&&!d){j=true;k=b.index||b.name;o=a}}});if(!s&&k||!1===
+c.multipleSearch){var y="eq";0<=o&&n[o].searchoptions&&n[o].searchoptions.sopt?y=n[o].searchoptions.sopt[0]:c.sopt&&c.sopt.length&&(y=c.sopt[0]);s={groupOp:"AND",rules:[{field:k,op:y,data:""}]}}j=!1;c.tmplNames&&c.tmplNames.length&&(j=!0,h=c.tmplLabel,h+="<select class='ui-template'>",h+="<option value='default'>Default</option>",a.each(c.tmplNames,function(a,b){h=h+("<option value='"+a+"'>"+b+"</option>")}),h+="</select>");g="<table class='EditTable' style='border:0px none;margin-top:5px' id='"+
+l+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='EditButton' style='text-align:"+g+"'>"+b+h+"</td><td class='EditButton' "+f+">"+m+w+"</td></tr></tbody></table>";l=a.jgrid.jqID(l);a("#"+l).jqFilter({columns:n,filter:c.loadDefaults?s:null,showQuery:c.showQuery,errorcheck:c.errorcheck,sopt:c.sopt,groupButton:c.multipleGroup,ruleButtons:c.multipleSearch,afterRedraw:c.afterRedraw,_gridsopt:a.jgrid.search.odata,ajaxSelectOptions:e.p.ajaxSelectOptions,
+groupOps:c.groupOps,onChange:function(){this.p.showQuery&&a(".query",this).html(this.toUserFriendlyString());a.isFunction(c.afterChange)&&c.afterChange.call(e,a("#"+l),c)},direction:e.p.direction});p.append(g);j&&(c.tmplFilters&&c.tmplFilters.length)&&a(".ui-template",p).bind("change",function(){var b=a(this).val();b=="default"?a("#"+l).jqFilter("addFilter",s):a("#"+l).jqFilter("addFilter",c.tmplFilters[parseInt(b,10)]);return false});!0===c.multipleGroup&&(c.multipleSearch=!0);a(e).triggerHandler("jqGridFilterInitialize",
+[a("#"+l)]);a.isFunction(c.onInitializeSearch)&&c.onInitializeSearch.call(e,a("#"+l));c.gbox="#gbox_"+l;c.layer?a.jgrid.createModal(t,p,c,"#gview_"+a.jgrid.jqID(e.p.id),a("#gbox_"+a.jgrid.jqID(e.p.id))[0],"#"+a.jgrid.jqID(c.layer),{position:"relative"}):a.jgrid.createModal(t,p,c,"#gview_"+a.jgrid.jqID(e.p.id),a("#gbox_"+a.jgrid.jqID(e.p.id))[0]);(c.searchOnEnter||c.closeOnEscape)&&a("#"+a.jgrid.jqID(t.themodal)).keydown(function(b){var d=a(b.target);if(c.searchOnEnter&&b.which===13&&!d.hasClass("add-group")&&
+!d.hasClass("add-rule")&&!d.hasClass("delete-group")&&!d.hasClass("delete-rule")&&(!d.hasClass("fm-button")||!d.is("[id$=_query]"))){a("#"+l+"_search").focus().click();return false}if(c.closeOnEscape&&b.which===27){a("#"+a.jgrid.jqID(t.modalhead)).find(".ui-jqdialog-titlebar-close").focus().click();return false}});m&&a("#"+l+"_query").bind("click",function(){a(".queryresult",p).toggle();return false});void 0===c.stringResult&&(c.stringResult=c.multipleSearch);a("#"+l+"_search").bind("click",function(){var b=
+a("#"+l),d={},h,q=b.jqFilter("filterData");if(c.errorcheck){b[0].hideError();c.showQuery||b.jqFilter("toSQLString");if(b[0].p.error){b[0].showError();return false}}if(c.stringResult){try{h=xmlJsonClass.toJson(q,"","",false)}catch(f){try{h=JSON.stringify(q)}catch(g){}}if(typeof h==="string"){d[c.sFilter]=h;a.each([c.sField,c.sValue,c.sOper],function(){d[this]=""})}}else if(c.multipleSearch){d[c.sFilter]=q;a.each([c.sField,c.sValue,c.sOper],function(){d[this]=""})}else{d[c.sField]=q.rules[0].field;
+d[c.sValue]=q.rules[0].data;d[c.sOper]=q.rules[0].op;d[c.sFilter]=""}e.p.search=true;a.extend(e.p.postData,d);a(e).triggerHandler("jqGridFilterSearch");a.isFunction(c.onSearch)&&c.onSearch.call(e);a(e).trigger("reloadGrid",[{page:1}]);c.closeAfterSearch&&a.jgrid.hideModal("#"+a.jgrid.jqID(t.themodal),{gb:"#gbox_"+a.jgrid.jqID(e.p.id),jqm:c.jqModal,onClose:c.onClose});return false});a("#"+l+"_reset").bind("click",function(){var b={},d=a("#"+l);e.p.search=false;c.multipleSearch===false?b[c.sField]=
+b[c.sValue]=b[c.sOper]="":b[c.sFilter]="";d[0].resetFilter();j&&a(".ui-template",p).val("default");a.extend(e.p.postData,b);a(e).triggerHandler("jqGridFilterReset");a.isFunction(c.onReset)&&c.onReset.call(e);a(e).trigger("reloadGrid",[{page:1}]);return false});d(a("#"+l));a(".fm-button:not(.ui-state-disabled)",p).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")})}}})},editGridRow:function(u,d){d=a.extend({top:0,left:0,width:300,height:"auto",dataheight:"auto",
+modal:!1,overlay:30,drag:!0,resize:!0,url:null,mtype:"POST",clearAfterAdd:!0,closeAfterEdit:!1,reloadAfterSubmit:!0,onInitializeForm:null,beforeInitData:null,beforeShowForm:null,afterShowForm:null,beforeSubmit:null,afterSubmit:null,onclickSubmit:null,afterComplete:null,onclickPgButtons:null,afterclickPgButtons:null,editData:{},recreateForm:!1,jqModal:!0,closeOnEscape:!1,addedrow:"first",topinfo:"",bottominfo:"",saveicon:[],closeicon:[],savekey:[!1,13],navkeys:[!1,38,40],checkOnSubmit:!1,checkOnUpdate:!1,
+_savedData:{},processing:!1,onClose:null,ajaxEditOptions:{},serializeEditData:null,viewPagerButtons:!0},a.jgrid.edit,d||{});c[a(this)[0].p.id]=d;return this.each(function(){function e(){a(j+" > tbody > tr > td > .FormElement").each(function(){var d=a(".customelement",this);if(d.length){var c=a(d[0]).attr("name");a.each(b.p.colModel,function(){if(this.name===c&&this.editoptions&&a.isFunction(this.editoptions.custom_value)){try{if(i[c]=this.editoptions.custom_value.call(b,a("#"+a.jgrid.jqID(c),j),"get"),
+void 0===i[c])throw"e1";}catch(d){"e1"===d?a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.novalue,jQuery.jgrid.edit.bClose):a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,d.message,jQuery.jgrid.edit.bClose)}return!0}})}else{switch(a(this).get(0).type){case "checkbox":a(this).is(":checked")?i[this.name]=a(this).val():(d=a(this).attr("offval"),i[this.name]=d);break;case "select-one":i[this.name]=a("option:selected",this).val();B[this.name]=a("option:selected",
+this).text();break;case "select-multiple":i[this.name]=a(this).val();i[this.name]=i[this.name]?i[this.name].join(","):"";var e=[];a("option:selected",this).each(function(b,d){e[b]=a(d).text()});B[this.name]=e.join(",");break;case "password":case "text":case "textarea":case "button":i[this.name]=a(this).val()}b.p.autoencode&&(i[this.name]=a.jgrid.htmlEncode(i[this.name]))}});return!0}function l(d,e,h,q){var i,f,g,k=0,j,o,l,p=[],n=!1,u="",m;for(m=1;m<=q;m++)u+="<td class='CaptionTD'>&#160;</td><td class='DataTD'>&#160;</td>";
+"_empty"!=d&&(n=a(e).jqGrid("getInd",d));a(e.p.colModel).each(function(m){i=this.name;o=(f=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1)?"style='display:none'":"";if("cb"!==i&&"subgrid"!==i&&!0===this.editable&&"rn"!==i){if(!1===n)j="";else if(i==e.p.ExpandColumn&&!0===e.p.treeGrid)j=a("td:eq("+m+")",e.rows[n]).text();else{try{j=a.unformat.call(e,a("td:eq("+m+")",e.rows[n]),{rowId:d,colModel:this},m)}catch(r){j=this.edittype&&"textarea"==this.edittype?a("td:eq("+m+")",
+e.rows[n]).text():a("td:eq("+m+")",e.rows[n]).html()}if(!j||"&nbsp;"==j||"&#160;"==j||1==j.length&&160==j.charCodeAt(0))j=""}var v=a.extend({},this.editoptions||{},{id:i,name:i}),s=a.extend({},{elmprefix:"",elmsuffix:"",rowabove:!1,rowcontent:""},this.formoptions||{}),t=parseInt(s.rowpos,10)||k+1,y=parseInt(2*(parseInt(s.colpos,10)||1),10);"_empty"==d&&v.defaultValue&&(j=a.isFunction(v.defaultValue)?v.defaultValue.call(b):v.defaultValue);this.edittype||(this.edittype="text");b.p.autoencode&&(j=a.jgrid.htmlDecode(j));
+l=a.jgrid.createEl.call(b,this.edittype,v,j,!1,a.extend({},a.jgrid.ajaxOptions,e.p.ajaxSelectOptions||{}));""===j&&"checkbox"==this.edittype&&(j=a(l).attr("offval"));""===j&&"select"==this.edittype&&(j=a("option:eq(0)",l).text());if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=j;a(l).addClass("FormElement");("text"==this.edittype||"textarea"==this.edittype)&&a(l).addClass("ui-widget-content ui-corner-all");g=a(h).find("tr[rowpos="+t+"]");s.rowabove&&(v=a("<tr><td class='contentinfo' colspan='"+
+2*q+"'>"+s.rowcontent+"</td></tr>"),a(h).append(v),v[0].rp=t);0===g.length&&(g=a("<tr "+o+" rowpos='"+t+"'></tr>").addClass("FormData").attr("id","tr_"+i),a(g).append(u),a(h).append(g),g[0].rp=t);a("td:eq("+(y-2)+")",g[0]).html("undefined"===typeof s.label?e.p.colNames[m]:s.label);a("td:eq("+(y-1)+")",g[0]).append(s.elmprefix).append(l).append(s.elmsuffix);p[k]=m;k++}});if(0<k&&(m=a("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+(2*q-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='"+
+e.p.id+"_id' value='"+d+"'/></td></tr>"),m[0].rp=k+999,a(h).append(m),c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate))c[b.p.id]._savedData[e.p.id+"_id"]=d;return p}function r(d,e,h){var i,q=0,g,f,k,o,l;if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData={},c[b.p.id]._savedData[e.p.id+"_id"]=d;var m=e.p.colModel;if("_empty"==d)a(m).each(function(){i=this.name;k=a.extend({},this.editoptions||{});if((f=a("#"+a.jgrid.jqID(i),"#"+h))&&f.length&&null!==f[0])if(o="",k.defaultValue?
+(o=a.isFunction(k.defaultValue)?k.defaultValue.call(b):k.defaultValue,"checkbox"==f[0].type?(l=o.toLowerCase(),0>l.search(/(false|0|no|off|undefined)/i)&&""!==l?(f[0].checked=!0,f[0].defaultChecked=!0,f[0].value=o):(f[0].checked=!1,f[0].defaultChecked=!1)):f.val(o)):"checkbox"==f[0].type?(f[0].checked=!1,f[0].defaultChecked=!1,o=a(f).attr("offval")):f[0].type&&"select"==f[0].type.substr(0,6)?f[0].selectedIndex=0:f.val(o),!0===c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=
+o}),a("#id_g","#"+h).val(d);else{var n=a(e).jqGrid("getInd",d,!0);n&&(a('td[role="gridcell"]',n).each(function(f){i=m[f].name;if("cb"!==i&&"subgrid"!==i&&"rn"!==i&&!0===m[f].editable){if(i==e.p.ExpandColumn&&!0===e.p.treeGrid)g=a(this).text();else try{g=a.unformat.call(e,a(this),{rowId:d,colModel:m[f]},f)}catch(j){g="textarea"==m[f].edittype?a(this).text():a(this).html()}b.p.autoencode&&(g=a.jgrid.htmlDecode(g));if(!0===c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=g;i=
+a.jgrid.jqID(i);switch(m[f].edittype){case "password":case "text":case "button":case "image":case "textarea":if("&nbsp;"==g||"&#160;"==g||1==g.length&&160==g.charCodeAt(0))g="";a("#"+i,"#"+h).val(g);break;case "select":var k=g.split(","),k=a.map(k,function(b){return a.trim(b)});a("#"+i+" option","#"+h).each(function(){this.selected=!m[f].editoptions.multiple&&(a.trim(g)==a.trim(a(this).text())||k[0]==a.trim(a(this).text())||k[0]==a.trim(a(this).val()))?!0:m[f].editoptions.multiple?-1<a.inArray(a.trim(a(this).text()),
+k)||-1<a.inArray(a.trim(a(this).val()),k)?!0:!1:!1});break;case "checkbox":g+="";m[f].editoptions&&m[f].editoptions.value?m[f].editoptions.value.split(":")[0]==g?(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!0),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!0)):(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!1),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!1)):(g=g.toLowerCase(),0>g.search(/(false|0|no|off|undefined)/i)&&""!==g?(a("#"+i,"#"+h)[b.p.useProp?
+"prop":"attr"]("checked",!0),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!0)):(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!1),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!1)));break;case "custom":try{if(m[f].editoptions&&a.isFunction(m[f].editoptions.custom_value))m[f].editoptions.custom_value.call(b,a("#"+i,"#"+h),"set",g);else throw"e1";}catch(o){"e1"==o?a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.nodefined,jQuery.jgrid.edit.bClose):
+a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,o.message,jQuery.jgrid.edit.bClose)}}q++}}),0<q&&a("#id_g",j).val(d))}}function t(){a.each(b.p.colModel,function(a,b){b.editoptions&&!0===b.editoptions.NullIfEmpty&&i.hasOwnProperty(b.name)&&""===i[b.name]&&(i[b.name]="null")})}function s(){var e,f=[!0,"",""],g={},q=b.p.prmNames,k,l,n,p,v,u=a(b).triggerHandler("jqGridAddEditBeforeCheckValues",[a("#"+h),z]);u&&"object"===typeof u&&(i=u);a.isFunction(c[b.p.id].beforeCheckValues)&&(u=c[b.p.id].beforeCheckValues.call(b,
+i,a("#"+h),"_empty"==i[b.p.id+"_id"]?q.addoper:q.editoper))&&"object"===typeof u&&(i=u);for(n in i)if(i.hasOwnProperty(n)&&(f=a.jgrid.checkValues.call(b,i[n],n,b),!1===f[0]))break;t();f[0]&&(g=a(b).triggerHandler("jqGridAddEditClickSubmit",[c[b.p.id],i,z]),void 0===g&&a.isFunction(c[b.p.id].onclickSubmit)&&(g=c[b.p.id].onclickSubmit.call(b,c[b.p.id],i)||{}),f=a(b).triggerHandler("jqGridAddEditBeforeSubmit",[i,a("#"+h),z]),void 0===f&&(f=[!0,"",""]),f[0]&&a.isFunction(c[b.p.id].beforeSubmit)&&(f=c[b.p.id].beforeSubmit.call(b,
+i,a("#"+h))));if(f[0]&&!c[b.p.id].processing){c[b.p.id].processing=!0;a("#sData",j+"_2").addClass("ui-state-active");l=q.oper;k=q.id;i[l]="_empty"==a.trim(i[b.p.id+"_id"])?q.addoper:q.editoper;i[l]!=q.addoper?i[k]=i[b.p.id+"_id"]:void 0===i[k]&&(i[k]=i[b.p.id+"_id"]);delete i[b.p.id+"_id"];i=a.extend(i,c[b.p.id].editData,g);if(!0===b.p.treeGrid)for(v in i[l]==q.addoper&&(p=a(b).jqGrid("getGridParam","selrow"),i["adjacency"==b.p.treeGridModel?b.p.treeReader.parent_id_field:"parent_id"]=p),b.p.treeReader)b.p.treeReader.hasOwnProperty(v)&&
+(g=b.p.treeReader[v],i.hasOwnProperty(g)&&!(i[l]==q.addoper&&"parent_id_field"===v)&&delete i[g]);i[k]=a.jgrid.stripPref(b.p.idPrefix,i[k]);v=a.extend({url:c[b.p.id].url?c[b.p.id].url:a(b).jqGrid("getGridParam","editurl"),type:c[b.p.id].mtype,data:a.isFunction(c[b.p.id].serializeEditData)?c[b.p.id].serializeEditData.call(b,i):i,complete:function(g,n){i[k]=b.p.idPrefix+i[k];if(n!="success"){f[0]=false;f[1]=a(b).triggerHandler("jqGridAddEditErrorTextFormat",[g,z]);f[1]=a.isFunction(c[b.p.id].errorTextFormat)?
+c[b.p.id].errorTextFormat.call(b,g):n+" Status: '"+g.statusText+"'. Error code: "+g.status}else{f=a(b).triggerHandler("jqGridAddEditAfterSubmit",[g,i,z]);f===void 0&&(f=[true,"",""]);f[0]&&a.isFunction(c[b.p.id].afterSubmit)&&(f=c[b.p.id].afterSubmit.call(b,g,i))}if(f[0]===false){a("#FormError>td",j).html(f[1]);a("#FormError",j).show()}else{a.each(b.p.colModel,function(){if(B[this.name]&&this.formatter&&this.formatter=="select")try{delete B[this.name]}catch(a){}});i=a.extend(i,B);b.p.autoencode&&
+a.each(i,function(b,d){i[b]=a.jgrid.htmlDecode(d)});if(i[l]==q.addoper){f[2]||(f[2]=a.jgrid.randId());i[k]=f[2];if(c[b.p.id].closeAfterAdd){if(c[b.p.id].reloadAfterSubmit)a(b).trigger("reloadGrid");else if(b.p.treeGrid===true)a(b).jqGrid("addChildNode",f[2],p,i);else{a(b).jqGrid("addRowData",f[2],i,d.addedrow);a(b).jqGrid("setSelection",f[2])}a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose})}else if(c[b.p.id].clearAfterAdd){c[b.p.id].reloadAfterSubmit?
+a(b).trigger("reloadGrid"):b.p.treeGrid===true?a(b).jqGrid("addChildNode",f[2],p,i):a(b).jqGrid("addRowData",f[2],i,d.addedrow);r("_empty",b,h)}else c[b.p.id].reloadAfterSubmit?a(b).trigger("reloadGrid"):b.p.treeGrid===true?a(b).jqGrid("addChildNode",f[2],p,i):a(b).jqGrid("addRowData",f[2],i,d.addedrow)}else{if(c[b.p.id].reloadAfterSubmit){a(b).trigger("reloadGrid");c[b.p.id].closeAfterEdit||setTimeout(function(){a(b).jqGrid("setSelection",i[k])},1E3)}else b.p.treeGrid===true?a(b).jqGrid("setTreeRow",
+i[k],i):a(b).jqGrid("setRowData",i[k],i);c[b.p.id].closeAfterEdit&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose})}if(a.isFunction(c[b.p.id].afterComplete)){e=g;setTimeout(function(){a(b).triggerHandler("jqGridAddEditAfterComplete",[e,i,a("#"+h),z]);c[b.p.id].afterComplete.call(b,e,i,a("#"+h));e=null},500)}if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate){a("#"+h).data("disabled",false);if(c[b.p.id]._savedData[b.p.id+"_id"]!=
+"_empty")for(var v in c[b.p.id]._savedData)i[v]&&(c[b.p.id]._savedData[v]=i[v])}}c[b.p.id].processing=false;a("#sData",j+"_2").removeClass("ui-state-active");try{a(":input:visible","#"+h)[0].focus()}catch(u){}}},a.jgrid.ajaxOptions,c[b.p.id].ajaxEditOptions);!v.url&&!c[b.p.id].useDataProxy&&(a.isFunction(b.p.dataProxy)?c[b.p.id].useDataProxy=!0:(f[0]=!1,f[1]+=" "+a.jgrid.errors.nourl));f[0]&&(c[b.p.id].useDataProxy?(g=b.p.dataProxy.call(b,v,"set_"+b.p.id),"undefined"==typeof g&&(g=[!0,""]),!1===g[0]?
+(f[0]=!1,f[1]=g[1]||"Error deleting the selected row!"):(v.data.oper==q.addoper&&c[b.p.id].closeAfterAdd&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose}),v.data.oper==q.editoper&&c[b.p.id].closeAfterEdit&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose}))):a.ajax(v))}!1===f[0]&&(a("#FormError>td",j).html(f[1]),a("#FormError",j).show())}function p(a,b){var d=!1,
+c;for(c in a)if(a[c]!=b[c]){d=!0;break}return d}function g(){var d=!0;a("#FormError",j).hide();if(c[b.p.id].checkOnUpdate&&(i={},B={},e(),F=a.extend({},i,B),M=p(F,c[b.p.id]._savedData)))a("#"+h).data("disabled",!0),a(".confirm","#"+o.themodal).show(),d=!1;return d}function f(){if("_empty"!==u&&"undefined"!==typeof b.p.savedRow&&0<b.p.savedRow.length&&a.isFunction(a.fn.jqGrid.restoreRow))for(var d=0;d<b.p.savedRow.length;d++)if(b.p.savedRow[d].id==u){a(b).jqGrid("restoreRow",u);break}}function n(b,
+d){0===b?a("#pData",j+"_2").addClass("ui-state-disabled"):a("#pData",j+"_2").removeClass("ui-state-disabled");b==d?a("#nData",j+"_2").addClass("ui-state-disabled"):a("#nData",j+"_2").removeClass("ui-state-disabled")}function w(){var d=a(b).jqGrid("getDataIDs"),c=a("#id_g",j).val();return[a.inArray(c,d),d]}var b=this;if(b.grid&&u){var m=b.p.id,h="FrmGrid_"+m,k="TblGrid_"+m,j="#"+a.jgrid.jqID(k),o={themodal:"editmod"+m,modalhead:"edithd"+m,modalcontent:"editcnt"+m,scrollelm:h},y=a.isFunction(c[b.p.id].beforeShowForm)?
+c[b.p.id].beforeShowForm:!1,A=a.isFunction(c[b.p.id].afterShowForm)?c[b.p.id].afterShowForm:!1,x=a.isFunction(c[b.p.id].beforeInitData)?c[b.p.id].beforeInitData:!1,E=a.isFunction(c[b.p.id].onInitializeForm)?c[b.p.id].onInitializeForm:!1,q=!0,v=1,H=0,i,B,F,M,z,h=a.jgrid.jqID(h);"new"===u?(u="_empty",z="add",d.caption=c[b.p.id].addCaption):(d.caption=c[b.p.id].editCaption,z="edit");!0===d.recreateForm&&null!==a("#"+a.jgrid.jqID(o.themodal)).html()&&a("#"+a.jgrid.jqID(o.themodal)).remove();var I=!0;
+d.checkOnUpdate&&(d.jqModal&&!d.modal)&&(I=!1);if(null!==a("#"+a.jgrid.jqID(o.themodal)).html()){q=a(b).triggerHandler("jqGridAddEditBeforeInitData",[a("#"+a.jgrid.jqID(h))]);"undefined"==typeof q&&(q=!0);q&&x&&(q=x.call(b,a("#"+h)));if(!1===q)return;f();a(".ui-jqdialog-title","#"+a.jgrid.jqID(o.modalhead)).html(d.caption);a("#FormError",j).hide();c[b.p.id].topinfo?(a(".topinfo",j).html(c[b.p.id].topinfo),a(".tinfo",j).show()):a(".tinfo",j).hide();c[b.p.id].bottominfo?(a(".bottominfo",j+"_2").html(c[b.p.id].bottominfo),
+a(".binfo",j+"_2").show()):a(".binfo",j+"_2").hide();r(u,b,h);"_empty"==u||!c[b.p.id].viewPagerButtons?a("#pData, #nData",j+"_2").hide():a("#pData, #nData",j+"_2").show();!0===c[b.p.id].processing&&(c[b.p.id].processing=!1,a("#sData",j+"_2").removeClass("ui-state-active"));!0===a("#"+h).data("disabled")&&(a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide(),a("#"+h).data("disabled",!1));a(b).triggerHandler("jqGridAddEditBeforeShowForm",[a("#"+h),z]);y&&y.call(b,a("#"+h));a("#"+a.jgrid.jqID(o.themodal)).data("onClose",
+c[b.p.id].onClose);a.jgrid.viewModal("#"+a.jgrid.jqID(o.themodal),{gbox:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,jqM:!1,overlay:d.overlay,modal:d.modal});I||a(".jqmOverlay").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditAfterShowForm",[a("#"+h),z]);A&&A.call(b,a("#"+h))}else{var G=isNaN(d.dataheight)?d.dataheight:d.dataheight+"px",G=a("<form name='FormPost' id='"+
+h+"' class='FormGrid' onSubmit='return false;' style='width:100%;overflow:auto;position:relative;height:"+G+";'></form>").data("disabled",!1),C=a("<table id='"+k+"' class='EditTable' cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),q=a(b).triggerHandler("jqGridAddEditBeforeInitData",[a("#"+h),z]);"undefined"==typeof q&&(q=!0);q&&x&&(q=x.call(b,a("#"+h)));if(!1===q)return;f();a(b.p.colModel).each(function(){var a=this.formoptions;v=Math.max(v,a?a.colpos||0:0);H=Math.max(H,a?a.rowpos||
+0:0)});a(G).append(C);x=a("<tr id='FormError' style='display:none'><td class='ui-state-error' colspan='"+2*v+"'></td></tr>");x[0].rp=0;a(C).append(x);x=a("<tr style='display:none' class='tinfo'><td class='topinfo' colspan='"+2*v+"'>"+c[b.p.id].topinfo+"</td></tr>");x[0].rp=0;a(C).append(x);var q=(x="rtl"==b.p.direction?!0:!1)?"nData":"pData",D=x?"pData":"nData";l(u,b,C,v);var q="<a href='javascript:void(0)' id='"+q+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>",
+D="<a href='javascript:void(0)' id='"+D+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>",J="<a href='javascript:void(0)' id='sData' class='fm-button ui-state-default ui-corner-all'>"+d.bSubmit+"</a>",K="<a href='javascript:void(0)' id='cData' class='fm-button ui-state-default ui-corner-all'>"+d.bCancel+"</a>",k="<table border='0' cellspacing='0' cellpadding='0' class='EditTable' id='"+k+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr id='Act_Buttons'><td class='navButton'>"+
+(x?D+q:q+D)+"</td><td class='EditButton'>"+J+K+"</td></tr>"+("<tr style='display:none' class='binfo'><td class='bottominfo' colspan='2'>"+c[b.p.id].bottominfo+"</td></tr>"),k=k+"</tbody></table>";if(0<H){var L=[];a.each(a(C)[0].rows,function(a,b){L[a]=b});L.sort(function(a,b){return a.rp>b.rp?1:a.rp<b.rp?-1:0});a.each(L,function(b,d){a("tbody",C).append(d)})}d.gbox="#gbox_"+a.jgrid.jqID(m);var N=!1;!0===d.closeOnEscape&&(d.closeOnEscape=!1,N=!0);k=a("<span></span>").append(G).append(k);a.jgrid.createModal(o,
+k,d,"#gview_"+a.jgrid.jqID(b.p.id),a("#gbox_"+a.jgrid.jqID(b.p.id))[0]);x&&(a("#pData, #nData",j+"_2").css("float","right"),a(".EditButton",j+"_2").css("text-align","left"));c[b.p.id].topinfo&&a(".tinfo",j).show();c[b.p.id].bottominfo&&a(".binfo",j+"_2").show();k=k=null;a("#"+a.jgrid.jqID(o.themodal)).keydown(function(e){var f=e.target;if(a("#"+h).data("disabled")===true)return false;if(c[b.p.id].savekey[0]===true&&e.which==c[b.p.id].savekey[1]&&f.tagName!="TEXTAREA"){a("#sData",j+"_2").trigger("click");
+return false}if(e.which===27){if(!g())return false;N&&a.jgrid.hideModal(this,{gb:d.gbox,jqm:d.jqModal,onClose:c[b.p.id].onClose});return false}if(c[b.p.id].navkeys[0]===true){if(a("#id_g",j).val()=="_empty")return true;if(e.which==c[b.p.id].navkeys[1]){a("#pData",j+"_2").trigger("click");return false}if(e.which==c[b.p.id].navkeys[2]){a("#nData",j+"_2").trigger("click");return false}}});d.checkOnUpdate&&(a("a.ui-jqdialog-titlebar-close span","#"+a.jgrid.jqID(o.themodal)).removeClass("jqmClose"),a("a.ui-jqdialog-titlebar-close",
+"#"+a.jgrid.jqID(o.themodal)).unbind("click").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false}));d.saveicon=a.extend([!0,"left","ui-icon-disk"],d.saveicon);d.closeicon=a.extend([!0,"left","ui-icon-close"],d.closeicon);!0===d.saveicon[0]&&a("#sData",j+"_2").addClass("right"==d.saveicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.saveicon[2]+
+"'></span>");!0===d.closeicon[0]&&a("#cData",j+"_2").addClass("right"==d.closeicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.closeicon[2]+"'></span>");if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)J="<a href='javascript:void(0)' id='sNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+d.bYes+"</a>",D="<a href='javascript:void(0)' id='nNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+d.bNo+"</a>",K="<a href='javascript:void(0)' id='cNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+
+d.bExit+"</a>",k=d.zIndex||999,k++,a("<div class='ui-widget-overlay jqgrid-overlay confirm' style='z-index:"+k+";display:none;'>&#160;"+(a.browser.msie&&6==a.browser.version?'<iframe style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=\'0\');" src="javascript:false;"></iframe>':"")+"</div><div class='confirm ui-widget-content ui-jqconfirm' style='z-index:"+(k+1)+"'>"+d.saveData+"<br/><br/>"+J+D+K+"</div>").insertAfter("#"+h),a("#sNew","#"+a.jgrid.jqID(o.themodal)).click(function(){s();
+a("#"+h).data("disabled",false);a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();return false}),a("#nNew","#"+a.jgrid.jqID(o.themodal)).click(function(){a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();a("#"+h).data("disabled",false);setTimeout(function(){a(":input","#"+h)[0].focus()},0);return false}),a("#cNew","#"+a.jgrid.jqID(o.themodal)).click(function(){a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();a("#"+h).data("disabled",false);a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+
+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditInitializeForm",[a("#"+h),z]);E&&E.call(b,a("#"+h));"_empty"==u||!c[b.p.id].viewPagerButtons?a("#pData,#nData",j+"_2").hide():a("#pData,#nData",j+"_2").show();a(b).triggerHandler("jqGridAddEditBeforeShowForm",[a("#"+h),z]);y&&y.call(b,a("#"+h));a("#"+a.jgrid.jqID(o.themodal)).data("onClose",c[b.p.id].onClose);a.jgrid.viewModal("#"+a.jgrid.jqID(o.themodal),{gbox:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,
+overlay:d.overlay,modal:d.modal});I||a(".jqmOverlay").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditAfterShowForm",[a("#"+h),z]);A&&A.call(b,a("#"+h));a(".fm-button","#"+a.jgrid.jqID(o.themodal)).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});a("#sData",j+"_2").click(function(){i={};B=
+{};a("#FormError",j).hide();e();if(i[b.p.id+"_id"]=="_empty")s();else if(d.checkOnSubmit===true){F=a.extend({},i,B);if(M=p(F,c[b.p.id]._savedData)){a("#"+h).data("disabled",true);a(".confirm","#"+a.jgrid.jqID(o.themodal)).show()}else s()}else s();return false});a("#cData",j+"_2").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a("#nData",j+"_2").click(function(){if(!g())return false;
+a("#FormError",j).hide();var c=w();c[0]=parseInt(c[0],10);if(c[0]!=-1&&c[1][c[0]+1]){a(b).triggerHandler("jqGridAddEditClickPgButtons",["next",a("#"+h),c[1][c[0]]]);a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(b,"next",a("#"+h),c[1][c[0]]);r(c[1][c[0]+1],b,h);a(b).jqGrid("setSelection",c[1][c[0]+1]);a(b).triggerHandler("jqGridAddEditAfterClickPgButtons",["next",a("#"+h),c[1][c[0]]]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(b,"next",a("#"+h),c[1][c[0]+1]);n(c[0]+
+1,c[1].length-1)}return false});a("#pData",j+"_2").click(function(){if(!g())return false;a("#FormError",j).hide();var c=w();if(c[0]!=-1&&c[1][c[0]-1]){a(b).triggerHandler("jqGridAddEditClickPgButtons",["prev",a("#"+h),c[1][c[0]]]);a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(b,"prev",a("#"+h),c[1][c[0]]);r(c[1][c[0]-1],b,h);a(b).jqGrid("setSelection",c[1][c[0]-1]);a(b).triggerHandler("jqGridAddEditAfterClickPgButtons",["prev",a("#"+h),c[1][c[0]]]);a.isFunction(d.afterclickPgButtons)&&
+d.afterclickPgButtons.call(b,"prev",a("#"+h),c[1][c[0]-1]);n(c[0]-1,c[1].length-1)}return false})}y=w();n(y[0],y[1].length-1)}})},viewGridRow:function(c,d){d=a.extend({top:0,left:0,width:0,height:"auto",dataheight:"auto",modal:!1,overlay:30,drag:!0,resize:!0,jqModal:!0,closeOnEscape:!1,labelswidth:"30%",closeicon:[],navkeys:[!1,38,40],onClose:null,beforeShowForm:null,beforeInitData:null,viewPagerButtons:!0},a.jgrid.view,d||{});return this.each(function(){function e(){(!0===d.closeOnEscape||!0===d.navkeys[0])&&
+setTimeout(function(){a(".ui-jqdialog-titlebar-close","#"+a.jgrid.jqID(m.modalhead)).focus()},0)}function l(b,c,e,f){for(var g,h,k,j=0,o,m,l=[],n=!1,p="<td class='CaptionTD form-view-label ui-widget-content' width='"+d.labelswidth+"'>&#160;</td><td class='DataTD form-view-data ui-helper-reset ui-widget-content'>&#160;</td>",u="",s=["integer","number","currency"],r=0,t=0,y,x,w,A=1;A<=f;A++)u+=1==A?p:"<td class='CaptionTD form-view-label ui-widget-content'>&#160;</td><td class='DataTD form-view-data ui-widget-content'>&#160;</td>";
+a(c.p.colModel).each(function(){h=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1;!h&&"right"===this.align&&(this.formatter&&-1!==a.inArray(this.formatter,s)?r=Math.max(r,parseInt(this.width,10)):t=Math.max(t,parseInt(this.width,10)))});y=0!==r?r:0!==t?t:0;n=a(c).jqGrid("getInd",b);a(c.p.colModel).each(function(b){g=this.name;x=!1;m=(h=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1)?"style='display:none'":"";w="boolean"!=typeof this.viewable?!0:this.viewable;
+if("cb"!==g&&"subgrid"!==g&&"rn"!==g&&w){o=!1===n?"":g==c.p.ExpandColumn&&!0===c.p.treeGrid?a("td:eq("+b+")",c.rows[n]).text():a("td:eq("+b+")",c.rows[n]).html();x="right"===this.align&&0!==y?!0:!1;a.extend({},this.editoptions||{},{id:g,name:g});var d=a.extend({},{rowabove:!1,rowcontent:""},this.formoptions||{}),q=parseInt(d.rowpos,10)||j+1,p=parseInt(2*(parseInt(d.colpos,10)||1),10);if(d.rowabove){var r=a("<tr><td class='contentinfo' colspan='"+2*f+"'>"+d.rowcontent+"</td></tr>");a(e).append(r);
+r[0].rp=q}k=a(e).find("tr[rowpos="+q+"]");0===k.length&&(k=a("<tr "+m+" rowpos='"+q+"'></tr>").addClass("FormData").attr("id","trv_"+g),a(k).append(u),a(e).append(k),k[0].rp=q);a("td:eq("+(p-2)+")",k[0]).html("<b>"+("undefined"===typeof d.label?c.p.colNames[b]:d.label)+"</b>");a("td:eq("+(p-1)+")",k[0]).append("<span>"+o+"</span>").attr("id","v_"+g);x&&a("td:eq("+(p-1)+") span",k[0]).css({"text-align":"right",width:y+"px"});l[j]=b;j++}});0<j&&(b=a("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+
+(2*f-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='id' value='"+b+"'/></td></tr>"),b[0].rp=j+99,a(e).append(b));return l}function r(b,c){var d,e,f=0,g,h;if(h=a(c).jqGrid("getInd",b,!0))a("td",h).each(function(b){d=c.p.colModel[b].name;e=c.p.colModel[b].editrules&&!0===c.p.colModel[b].editrules.edithidden?!1:!0===c.p.colModel[b].hidden?!0:!1;"cb"!==d&&("subgrid"!==d&&"rn"!==d)&&(g=d==c.p.ExpandColumn&&!0===c.p.treeGrid?a(this).text():a(this).html(),a.extend({},c.p.colModel[b].editoptions||
+{}),d=a.jgrid.jqID("v_"+d),a("#"+d+" span","#"+n).html(g),e&&a("#"+d,"#"+n).parents("tr:first").hide(),f++)}),0<f&&a("#id_g","#"+n).val(b)}function t(b,c){0===b?a("#pData","#"+n+"_2").addClass("ui-state-disabled"):a("#pData","#"+n+"_2").removeClass("ui-state-disabled");b==c?a("#nData","#"+n+"_2").addClass("ui-state-disabled"):a("#nData","#"+n+"_2").removeClass("ui-state-disabled")}function s(){var b=a(p).jqGrid("getDataIDs"),c=a("#id_g","#"+n).val();return[a.inArray(c,b),b]}var p=this;if(p.grid&&
+c){var g=p.p.id,f="ViewGrid_"+a.jgrid.jqID(g),n="ViewTbl_"+a.jgrid.jqID(g),w="ViewGrid_"+g,b="ViewTbl_"+g,m={themodal:"viewmod"+g,modalhead:"viewhd"+g,modalcontent:"viewcnt"+g,scrollelm:f},h=a.isFunction(d.beforeInitData)?d.beforeInitData:!1,k=!0,j=1,o=0;if(null!==a("#"+a.jgrid.jqID(m.themodal)).html()){h&&(k=h.call(p,a("#"+f)),"undefined"==typeof k&&(k=!0));if(!1===k)return;a(".ui-jqdialog-title","#"+a.jgrid.jqID(m.modalhead)).html(d.caption);a("#FormError","#"+n).hide();r(c,p);a.isFunction(d.beforeShowForm)&&
+d.beforeShowForm.call(p,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(m.themodal),{gbox:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,jqM:!1,overlay:d.overlay,modal:d.modal});e()}else{var y=isNaN(d.dataheight)?d.dataheight:d.dataheight+"px",w=a("<form name='FormPost' id='"+w+"' class='FormGrid' style='width:100%;overflow:auto;position:relative;height:"+y+";'></form>"),A=a("<table id='"+b+"' class='EditTable' cellspacing='1' cellpadding='2' border='0' style='table-layout:fixed'><tbody></tbody></table>");h&&
+(k=h.call(p,a("#"+f)),"undefined"==typeof k&&(k=!0));if(!1===k)return;a(p.p.colModel).each(function(){var a=this.formoptions;j=Math.max(j,a?a.colpos||0:0);o=Math.max(o,a?a.rowpos||0:0)});a(w).append(A);l(c,p,A,j);b="rtl"==p.p.direction?!0:!1;h="<a href='javascript:void(0)' id='"+(b?"nData":"pData")+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>";k="<a href='javascript:void(0)' id='"+(b?"pData":"nData")+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>";
+y="<a href='javascript:void(0)' id='cData' class='fm-button ui-state-default ui-corner-all'>"+d.bClose+"</a>";if(0<o){var x=[];a.each(a(A)[0].rows,function(a,b){x[a]=b});x.sort(function(a,b){return a.rp>b.rp?1:a.rp<b.rp?-1:0});a.each(x,function(b,c){a("tbody",A).append(c)})}d.gbox="#gbox_"+a.jgrid.jqID(g);var E=!1;!0===d.closeOnEscape&&(d.closeOnEscape=!1,E=!0);w=a("<span></span>").append(w).append("<table border='0' class='EditTable' id='"+n+"_2'><tbody><tr id='Act_Buttons'><td class='navButton' width='"+
+d.labelswidth+"'>"+(b?k+h:h+k)+"</td><td class='EditButton'>"+y+"</td></tr></tbody></table>");a.jgrid.createModal(m,w,d,"#gview_"+a.jgrid.jqID(p.p.id),a("#gview_"+a.jgrid.jqID(p.p.id))[0]);b&&(a("#pData, #nData","#"+n+"_2").css("float","right"),a(".EditButton","#"+n+"_2").css("text-align","left"));d.viewPagerButtons||a("#pData, #nData","#"+n+"_2").hide();w=null;a("#"+m.themodal).keydown(function(b){if(b.which===27){E&&a.jgrid.hideModal(this,{gb:d.gbox,jqm:d.jqModal,onClose:d.onClose});return false}if(d.navkeys[0]===
+true){if(b.which===d.navkeys[1]){a("#pData","#"+n+"_2").trigger("click");return false}if(b.which===d.navkeys[2]){a("#nData","#"+n+"_2").trigger("click");return false}}});d.closeicon=a.extend([!0,"left","ui-icon-close"],d.closeicon);!0===d.closeicon[0]&&a("#cData","#"+n+"_2").addClass("right"==d.closeicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.closeicon[2]+"'></span>");a.isFunction(d.beforeShowForm)&&d.beforeShowForm.call(p,a("#"+f));a.jgrid.viewModal("#"+
+a.jgrid.jqID(m.themodal),{gbox:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,modal:d.modal});a(".fm-button:not(.ui-state-disabled)","#"+n+"_2").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});e();a("#cData","#"+n+"_2").click(function(){a.jgrid.hideModal("#"+a.jgrid.jqID(m.themodal),{gb:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,onClose:d.onClose});return false});a("#nData","#"+n+"_2").click(function(){a("#FormError","#"+n).hide();var b=s();b[0]=parseInt(b[0],
+10);if(b[0]!=-1&&b[1][b[0]+1]){a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(p,"next",a("#"+f),b[1][b[0]]);r(b[1][b[0]+1],p);a(p).jqGrid("setSelection",b[1][b[0]+1]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(p,"next",a("#"+f),b[1][b[0]+1]);t(b[0]+1,b[1].length-1)}e();return false});a("#pData","#"+n+"_2").click(function(){a("#FormError","#"+n).hide();var b=s();if(b[0]!=-1&&b[1][b[0]-1]){a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(p,"prev",a("#"+f),b[1][b[0]]);
+r(b[1][b[0]-1],p);a(p).jqGrid("setSelection",b[1][b[0]-1]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(p,"prev",a("#"+f),b[1][b[0]-1]);t(b[0]-1,b[1].length-1)}e();return false})}w=s();t(w[0],w[1].length-1)}})},delGridRow:function(u,d){d=a.extend({top:0,left:0,width:240,height:"auto",dataheight:"auto",modal:!1,overlay:30,drag:!0,resize:!0,url:"",mtype:"POST",reloadAfterSubmit:!0,beforeShowForm:null,beforeInitData:null,afterShowForm:null,beforeSubmit:null,onclickSubmit:null,afterSubmit:null,
+jqModal:!0,closeOnEscape:!1,delData:{},delicon:[],cancelicon:[],onClose:null,ajaxDelOptions:{},processing:!1,serializeDelData:null,useDataProxy:!1},a.jgrid.del,d||{});c[a(this)[0].p.id]=d;return this.each(function(){var e=this;if(e.grid&&u){var l=a.isFunction(c[e.p.id].beforeShowForm),r=a.isFunction(c[e.p.id].afterShowForm),t=a.isFunction(c[e.p.id].beforeInitData)?c[e.p.id].beforeInitData:!1,s=e.p.id,p={},g=!0,f="DelTbl_"+a.jgrid.jqID(s),n,w,b,m,h="DelTbl_"+s,k={themodal:"delmod"+s,modalhead:"delhd"+
+s,modalcontent:"delcnt"+s,scrollelm:f};jQuery.isArray(u)&&(u=u.join());if(null!==a("#"+a.jgrid.jqID(k.themodal)).html()){t&&(g=t.call(e,a("#"+f)),"undefined"==typeof g&&(g=!0));if(!1===g)return;a("#DelData>td","#"+f).text(u);a("#DelError","#"+f).hide();!0===c[e.p.id].processing&&(c[e.p.id].processing=!1,a("#dData","#"+f).removeClass("ui-state-active"));l&&c[e.p.id].beforeShowForm.call(e,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(k.themodal),{gbox:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,jqM:!1,
+overlay:c[e.p.id].overlay,modal:c[e.p.id].modal})}else{var j=isNaN(c[e.p.id].dataheight)?c[e.p.id].dataheight:c[e.p.id].dataheight+"px",h="<div id='"+h+"' class='formdata' style='width:100%;overflow:auto;position:relative;height:"+j+";'><table class='DelTable'><tbody><tr id='DelError' style='display:none'><td class='ui-state-error'></td></tr>"+("<tr id='DelData' style='display:none'><td >"+u+"</td></tr>"),h=h+('<tr><td class="delmsg" style="white-space:pre;">'+c[e.p.id].msg+"</td></tr><tr><td >&#160;</td></tr>"),
+h=h+"</tbody></table></div>"+("<table cellspacing='0' cellpadding='0' border='0' class='EditTable' id='"+f+"_2'><tbody><tr><td><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='DelButton EditButton'>"+("<a href='javascript:void(0)' id='dData' class='fm-button ui-state-default ui-corner-all'>"+d.bSubmit+"</a>")+"&#160;"+("<a href='javascript:void(0)' id='eData' class='fm-button ui-state-default ui-corner-all'>"+d.bCancel+"</a>")+"</td></tr></tbody></table>");d.gbox="#gbox_"+
+a.jgrid.jqID(s);a.jgrid.createModal(k,h,d,"#gview_"+a.jgrid.jqID(e.p.id),a("#gview_"+a.jgrid.jqID(e.p.id))[0]);t&&(g=t.call(e,a("#"+f)),"undefined"==typeof g&&(g=!0));if(!1===g)return;a(".fm-button","#"+f+"_2").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});d.delicon=a.extend([!0,"left","ui-icon-scissors"],c[e.p.id].delicon);d.cancelicon=a.extend([!0,"left","ui-icon-cancel"],c[e.p.id].cancelicon);!0===d.delicon[0]&&a("#dData","#"+f+"_2").addClass("right"==
+d.delicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.delicon[2]+"'></span>");!0===d.cancelicon[0]&&a("#eData","#"+f+"_2").addClass("right"==d.cancelicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.cancelicon[2]+"'></span>");a("#dData","#"+f+"_2").click(function(){var g=[true,""];p={};var h=a("#DelData>td","#"+f).text();a.isFunction(c[e.p.id].onclickSubmit)&&(p=c[e.p.id].onclickSubmit.call(e,c[e.p.id],h)||{});a.isFunction(c[e.p.id].beforeSubmit)&&
+(g=c[e.p.id].beforeSubmit.call(e,h));if(g[0]&&!c[e.p.id].processing){c[e.p.id].processing=true;b=e.p.prmNames;n=a.extend({},c[e.p.id].delData,p);m=b.oper;n[m]=b.deloper;w=b.id;h=(""+h).split(",");if(!h.length)return false;for(var j in h)h.hasOwnProperty(j)&&(h[j]=a.jgrid.stripPref(e.p.idPrefix,h[j]));n[w]=h.join();a(this).addClass("ui-state-active");j=a.extend({url:c[e.p.id].url?c[e.p.id].url:a(e).jqGrid("getGridParam","editurl"),type:c[e.p.id].mtype,data:a.isFunction(c[e.p.id].serializeDelData)?
+c[e.p.id].serializeDelData.call(e,n):n,complete:function(b,j){if(j!="success"){g[0]=false;g[1]=a.isFunction(c[e.p.id].errorTextFormat)?c[e.p.id].errorTextFormat.call(e,b):j+" Status: '"+b.statusText+"'. Error code: "+b.status}else a.isFunction(c[e.p.id].afterSubmit)&&(g=c[e.p.id].afterSubmit.call(e,b,n));if(g[0]===false){a("#DelError>td","#"+f).html(g[1]);a("#DelError","#"+f).show()}else{if(c[e.p.id].reloadAfterSubmit&&e.p.datatype!="local")a(e).trigger("reloadGrid");else{if(e.p.treeGrid===true)try{a(e).jqGrid("delTreeNode",
+e.p.idPrefix+h[0])}catch(m){}else for(var l=0;l<h.length;l++)a(e).jqGrid("delRowData",e.p.idPrefix+h[l]);e.p.selrow=null;e.p.selarrrow=[]}a.isFunction(c[e.p.id].afterComplete)&&setTimeout(function(){c[e.p.id].afterComplete.call(e,b,h)},500)}c[e.p.id].processing=false;a("#dData","#"+f+"_2").removeClass("ui-state-active");g[0]&&a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:d.jqModal,onClose:c[e.p.id].onClose})}},a.jgrid.ajaxOptions,c[e.p.id].ajaxDelOptions);if(!j.url&&
+!c[e.p.id].useDataProxy)if(a.isFunction(e.p.dataProxy))c[e.p.id].useDataProxy=true;else{g[0]=false;g[1]=g[1]+(" "+a.jgrid.errors.nourl)}if(g[0])if(c[e.p.id].useDataProxy){j=e.p.dataProxy.call(e,j,"del_"+e.p.id);typeof j=="undefined"&&(j=[true,""]);if(j[0]===false){g[0]=false;g[1]=j[1]||"Error deleting the selected row!"}else a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:d.jqModal,onClose:c[e.p.id].onClose})}else a.ajax(j)}if(g[0]===false){a("#DelError>td","#"+f).html(g[1]);
+a("#DelError","#"+f).show()}return false});a("#eData","#"+f+"_2").click(function(){a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,onClose:c[e.p.id].onClose});return false});l&&c[e.p.id].beforeShowForm.call(e,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(k.themodal),{gbox:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,overlay:c[e.p.id].overlay,modal:c[e.p.id].modal})}r&&c[e.p.id].afterShowForm.call(e,a("#"+f));!0===c[e.p.id].closeOnEscape&&setTimeout(function(){a(".ui-jqdialog-titlebar-close",
+"#"+a.jgrid.jqID(k.modalhead)).focus()},0)}})},navGrid:function(c,d,e,l,r,t,s){d=a.extend({edit:!0,editicon:"ui-icon-pencil",add:!0,addicon:"ui-icon-plus",del:!0,delicon:"ui-icon-trash",search:!0,searchicon:"ui-icon-search",refresh:!0,refreshicon:"ui-icon-refresh",refreshstate:"firstpage",view:!1,viewicon:"ui-icon-document",position:"left",closeOnEscape:!0,beforeRefresh:null,afterRefresh:null,cloneToTop:!1,alertwidth:200,alertheight:"auto",alerttop:null,alertleft:null,alertzIndex:null},a.jgrid.nav,
+d||{});return this.each(function(){if(!this.nav){var p={themodal:"alertmod",modalhead:"alerthd",modalcontent:"alertcnt"},g=this,f;if(g.grid&&"string"==typeof c){null===a("#"+p.themodal).html()&&(!d.alerttop&&!d.alertleft&&("undefined"!=typeof window.innerWidth?(d.alertleft=window.innerWidth,d.alerttop=window.innerHeight):"undefined"!=typeof document.documentElement&&"undefined"!=typeof document.documentElement.clientWidth&&0!==document.documentElement.clientWidth?(d.alertleft=document.documentElement.clientWidth,
+d.alerttop=document.documentElement.clientHeight):(d.alertleft=1024,d.alerttop=768),d.alertleft=d.alertleft/2-parseInt(d.alertwidth,10)/2,d.alerttop=d.alerttop/2-25),a.jgrid.createModal(p,"<div>"+d.alerttext+"</div><span tabindex='0'><span tabindex='-1' id='jqg_alrt'></span></span>",{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqModal:!0,drag:!0,resize:!0,caption:d.alertcap,top:d.alerttop,left:d.alertleft,width:d.alertwidth,height:d.alertheight,closeOnEscape:d.closeOnEscape,zIndex:d.alertzIndex},"","",!0));
+var n=1;d.cloneToTop&&g.p.toppager&&(n=2);for(var w=0;w<n;w++){var b=a("<table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table navtable' style='float:left;table-layout:auto;'><tbody><tr></tr></tbody></table>"),m,h;0===w?(m=c,h=g.p.id,m==g.p.toppager&&(h+="_top",n=1)):(m=g.p.toppager,h=g.p.id+"_top");"rtl"==g.p.direction&&a(b).attr("dir","rtl").css("float","right");d.add&&(l=l||{},f=a("<td class='ui-pg-button ui-corner-all'></td>"),a(f).append("<div class='ui-pg-div'><span class='ui-icon "+
+d.addicon+"'></span>"+d.addtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.addtitle||"",id:l.id||"add_"+h}).click(function(){a(this).hasClass("ui-state-disabled")||(a.isFunction(d.addfunc)?d.addfunc.call(g):a(g).jqGrid("editGridRow","new",l));return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);d.edit&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),e=e||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+
+d.editicon+"'></span>"+d.edittext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.edittitle||"",id:e.id||"edit_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b=g.p.selrow;if(b)a.isFunction(d.editfunc)?d.editfunc.call(g,b):a(g).jqGrid("editGridRow",b,e);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),
+f=null);d.view&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),s=s||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.viewicon+"'></span>"+d.viewtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.viewtitle||"",id:s.id||"view_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b=g.p.selrow;if(b)a.isFunction(d.viewfunc)?d.viewfunc.call(g,b):a(g).jqGrid("viewGridRow",b,s);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||
+a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);d.del&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),r=r||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.delicon+"'></span>"+d.deltext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.deltitle||"",id:r.id||"del_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b;if(g.p.multiselect){b=g.p.selarrrow;b.length===0&&(b=null)}else b=g.p.selrow;if(b)a.isFunction(d.delfunc)?
+d.delfunc.call(g,b):a(g).jqGrid("delGridRow",b,r);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);(d.add||d.edit||d.del||d.view)&&a("tr",b).append("<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>");d.search&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),
+t=t||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.searchicon+"'></span>"+d.searchtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.searchtitle||"",id:t.id||"search_"+h}).click(function(){a(this).hasClass("ui-state-disabled")||(a.isFunction(d.searchfunc)?d.searchfunc.call(g,t):a(g).jqGrid("searchGrid",t));return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),t.showOnLoad&&
+!0===t.showOnLoad&&a(f,b).click(),f=null);d.refresh&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.refreshicon+"'></span>"+d.refreshtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.refreshtitle||"",id:"refresh_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){a.isFunction(d.beforeRefresh)&&d.beforeRefresh.call(g);g.p.search=false;try{var b=g.p.id;g.p.postData.filters="";a("#fbox_"+a.jgrid.jqID(b)).jqFilter("resetFilter");
+a.isFunction(g.clearToolbar)&&g.clearToolbar.call(g,false)}catch(c){}switch(d.refreshstate){case "firstpage":a(g).trigger("reloadGrid",[{page:1}]);break;case "current":a(g).trigger("reloadGrid",[{current:true}])}a.isFunction(d.afterRefresh)&&d.afterRefresh.call(g)}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);f=a(".ui-jqgrid").css("font-size")||"11px";a("body").append("<div id='testpg2' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+
+f+";visibility:hidden;' ></div>");f=a(b).clone().appendTo("#testpg2").width();a("#testpg2").remove();a(m+"_"+d.position,m).append(b);g.p._nvtd&&(f>g.p._nvtd[0]&&(a(m+"_"+d.position,m).width(f),g.p._nvtd[0]=f),g.p._nvtd[1]=f);b=f=f=null;this.nav=!0}}}})},navButtonAdd:function(c,d){d=a.extend({caption:"newButton",title:"",buttonicon:"ui-icon-newwin",onClickButton:null,position:"last",cursor:"pointer"},d||{});return this.each(function(){if(this.grid){"string"===typeof c&&0!==c.indexOf("#")&&(c="#"+a.jgrid.jqID(c));
+var e=a(".navtable",c)[0],l=this;if(e&&!(d.id&&null!==a("#"+a.jgrid.jqID(d.id),e).html())){var r=a("<td></td>");"NONE"==d.buttonicon.toString().toUpperCase()?a(r).addClass("ui-pg-button ui-corner-all").append("<div class='ui-pg-div'>"+d.caption+"</div>"):a(r).addClass("ui-pg-button ui-corner-all").append("<div class='ui-pg-div'><span class='ui-icon "+d.buttonicon+"'></span>"+d.caption+"</div>");d.id&&a(r).attr("id",d.id);"first"==d.position?0===e.rows[0].cells.length?a("tr",e).append(r):a("tr td:eq(0)",
+e).before(r):a("tr",e).append(r);a(r,e).attr("title",d.title||"").click(function(c){a(this).hasClass("ui-state-disabled")||a.isFunction(d.onClickButton)&&d.onClickButton.call(l,c);return!1}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")})}}})},navSeparatorAdd:function(c,d){d=a.extend({sepclass:"ui-separator",sepcontent:""},d||{});return this.each(function(){if(this.grid){"string"===typeof c&&0!==c.indexOf("#")&&
+(c="#"+a.jgrid.jqID(c));var e=a(".navtable",c)[0];if(e){var l="<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='"+d.sepclass+"'></span>"+d.sepcontent+"</td>";a("tr",e).append(l)}}})},GridToForm:function(c,d){return this.each(function(){var e=this;if(e.grid){var l=a(e).jqGrid("getRowData",c);if(l)for(var r in l)a("[name="+a.jgrid.jqID(r)+"]",d).is("input:radio")||a("[name="+a.jgrid.jqID(r)+"]",d).is("input:checkbox")?a("[name="+a.jgrid.jqID(r)+"]",d).each(function(){if(a(this).val()==
+l[r])a(this)[e.p.useProp?"prop":"attr"]("checked",!0);else a(this)[e.p.useProp?"prop":"attr"]("checked",!1)}):a("[name="+a.jgrid.jqID(r)+"]",d).val(l[r])}})},FormToGrid:function(c,d,e,l){return this.each(function(){if(this.grid){e||(e="set");l||(l="first");var r=a(d).serializeArray(),t={};a.each(r,function(a,c){t[c.name]=c.value});"add"==e?a(this).jqGrid("addRowData",c,t,l):"set"==e&&a(this).jqGrid("setRowData",c,t)}})}})})(jQuery);
+(function(a){a.fn.jqFilter=function(d){if("string"===typeof d){var n=a.fn.jqFilter[d];if(!n)throw"jqFilter - No such method: "+d;var u=a.makeArray(arguments).slice(1);return n.apply(this,u)}var o=a.extend(!0,{filter:null,columns:[],onChange:null,afterRedraw:null,checkValues:null,error:!1,errmsg:"",errorcheck:!0,showQuery:!0,sopt:null,ops:[{name:"eq",description:"equal",operator:"="},{name:"ne",description:"not equal",operator:"<>"},{name:"lt",description:"less",operator:"<"},{name:"le",description:"less or equal",
+operator:"<="},{name:"gt",description:"greater",operator:">"},{name:"ge",description:"greater or equal",operator:">="},{name:"bw",description:"begins with",operator:"LIKE"},{name:"bn",description:"does not begin with",operator:"NOT LIKE"},{name:"in",description:"in",operator:"IN"},{name:"ni",description:"not in",operator:"NOT IN"},{name:"ew",description:"ends with",operator:"LIKE"},{name:"en",description:"does not end with",operator:"NOT LIKE"},{name:"cn",description:"contains",operator:"LIKE"},{name:"nc",
+description:"does not contain",operator:"NOT LIKE"},{name:"nu",description:"is null",operator:"IS NULL"},{name:"nn",description:"is not null",operator:"IS NOT NULL"}],numopts:"eq ne lt le gt ge nu nn in ni".split(" "),stropts:"eq ne bw bn ew en cn nc nu nn in ni".split(" "),_gridsopt:[],groupOps:[{op:"AND",text:"AND"},{op:"OR",text:"OR"}],groupButton:!0,ruleButtons:!0,direction:"ltr"},a.jgrid.filter,d||{});return this.each(function(){if(!this.filter){this.p=o;if(null===this.p.filter||void 0===this.p.filter)this.p.filter=
+{groupOp:this.p.groupOps[0].op,rules:[],groups:[]};var d,n=this.p.columns.length,f,t=/msie/i.test(navigator.userAgent)&&!window.opera;if(this.p._gridsopt.length)for(d=0;d<this.p._gridsopt.length;d++)this.p.ops[d].description=this.p._gridsopt[d];this.p.initFilter=a.extend(!0,{},this.p.filter);if(n){for(d=0;d<n;d++)if(f=this.p.columns[d],f.stype?f.inputtype=f.stype:f.inputtype||(f.inputtype="text"),f.sorttype?f.searchtype=f.sorttype:f.searchtype||(f.searchtype="string"),void 0===f.hidden&&(f.hidden=
+!1),f.label||(f.label=f.name),f.index&&(f.name=f.index),f.hasOwnProperty("searchoptions")||(f.searchoptions={}),!f.hasOwnProperty("searchrules"))f.searchrules={};this.p.showQuery&&a(this).append("<table class='queryresult ui-widget ui-widget-content' style='display:block;max-width:440px;border:0px none;' dir='"+this.p.direction+"'><tbody><tr><td class='query'></td></tr></tbody></table>");var r=function(g,k){var b=[!0,""];if(a.isFunction(k.searchrules))b=k.searchrules(g,k);else if(a.jgrid&&a.jgrid.checkValues)try{b=
+a.jgrid.checkValues(g,-1,null,k.searchrules,k.label)}catch(c){}b&&(b.length&&!1===b[0])&&(o.error=!b[0],o.errmsg=b[1])};this.onchange=function(){this.p.error=!1;this.p.errmsg="";return a.isFunction(this.p.onChange)?this.p.onChange.call(this,this.p):!1};this.reDraw=function(){a("table.group:first",this).remove();var g=this.createTableForGroup(o.filter,null);a(this).append(g);a.isFunction(this.p.afterRedraw)&&this.p.afterRedraw.call(this,this.p)};this.createTableForGroup=function(g,k){var b=this,c,
+e=a("<table class='group ui-widget ui-widget-content' style='border:0px none;'><tbody></tbody></table>"),d="left";"rtl"==this.p.direction&&(d="right",e.attr("dir","rtl"));null===k&&e.append("<tr class='error' style='display:none;'><th colspan='5' class='ui-state-error' align='"+d+"'></th></tr>");var h=a("<tr></tr>");e.append(h);d=a("<th colspan='5' align='"+d+"'></th>");h.append(d);if(!0===this.p.ruleButtons){var i=a("<select class='opsel'></select>");d.append(i);var h="",f;for(c=0;c<o.groupOps.length;c++)f=
+g.groupOp===b.p.groupOps[c].op?" selected='selected'":"",h+="<option value='"+b.p.groupOps[c].op+"'"+f+">"+b.p.groupOps[c].text+"</option>";i.append(h).bind("change",function(){g.groupOp=a(i).val();b.onchange()})}h="<span></span>";this.p.groupButton&&(h=a("<input type='button' value='+ {}' title='Add subgroup' class='add-group'/>"),h.bind("click",function(){if(g.groups===void 0)g.groups=[];g.groups.push({groupOp:o.groupOps[0].op,rules:[],groups:[]});b.reDraw();b.onchange();return false}));d.append(h);
+if(!0===this.p.ruleButtons){var h=a("<input type='button' value='+' title='Add rule' class='add-rule ui-add'/>"),l;h.bind("click",function(){if(g.rules===void 0)g.rules=[];for(c=0;c<b.p.columns.length;c++){var a=typeof b.p.columns[c].search==="undefined"?true:b.p.columns[c].search,e=b.p.columns[c].hidden===true;if(b.p.columns[c].searchoptions.searchhidden===true&&a||a&&!e){l=b.p.columns[c];break}}g.rules.push({field:l.name,op:(l.searchoptions.sopt?l.searchoptions.sopt:b.p.sopt?b.p.sopt:l.searchtype===
+"string"?b.p.stropts:b.p.numopts)[0],data:""});b.reDraw();return false});d.append(h)}null!==k&&(h=a("<input type='button' value='-' title='Delete group' class='delete-group'/>"),d.append(h),h.bind("click",function(){for(c=0;c<k.groups.length;c++)if(k.groups[c]===g){k.groups.splice(c,1);break}b.reDraw();b.onchange();return false}));if(void 0!==g.groups)for(c=0;c<g.groups.length;c++)d=a("<tr></tr>"),e.append(d),h=a("<td class='first'></td>"),d.append(h),h=a("<td colspan='4'></td>"),h.append(this.createTableForGroup(g.groups[c],
+g)),d.append(h);void 0===g.groupOp&&(g.groupOp=b.p.groupOps[0].op);if(void 0!==g.rules)for(c=0;c<g.rules.length;c++)e.append(this.createTableRowForRule(g.rules[c],g));return e};this.createTableRowForRule=function(g,d){var b=this,c=a("<tr></tr>"),e,f,h,i,j="",l;c.append("<td class='first'></td>");var m=a("<td class='columns'></td>");c.append(m);var n=a("<select></select>"),p,q=[];m.append(n);n.bind("change",function(){g.field=a(n).val();h=a(this).parents("tr:first");for(e=0;e<b.p.columns.length;e++)if(b.p.columns[e].name===
+g.field){i=b.p.columns[e];break}if(i){i.searchoptions.id=a.jgrid.randId();t&&"text"===i.inputtype&&!i.searchoptions.size&&(i.searchoptions.size=10);var c=a.jgrid.createEl(i.inputtype,i.searchoptions,"",!0,b.p.ajaxSelectOptions,!0);a(c).addClass("input-elm");f=i.searchoptions.sopt?i.searchoptions.sopt:b.p.sopt?b.p.sopt:"string"===i.searchtype?b.p.stropts:b.p.numopts;var d="",k=0;q=[];a.each(b.p.ops,function(){q.push(this.name)});for(e=0;e<f.length;e++)p=a.inArray(f[e],q),-1!==p&&(0===k&&(g.op=b.p.ops[p].name),
+d+="<option value='"+b.p.ops[p].name+"'>"+b.p.ops[p].description+"</option>",k++);a(".selectopts",h).empty().append(d);a(".selectopts",h)[0].selectedIndex=0;a.browser.msie&&9>a.browser.version&&(d=parseInt(a("select.selectopts",h)[0].offsetWidth)+1,a(".selectopts",h).width(d),a(".selectopts",h).css("width","auto"));a(".data",h).empty().append(c);a(".input-elm",h).bind("change",function(c){var d=a(this).hasClass("ui-autocomplete-input")?200:0;setTimeout(function(){var d=c.target;g.data=d.nodeName.toUpperCase()===
+"SPAN"&&i.searchoptions&&a.isFunction(i.searchoptions.custom_value)?i.searchoptions.custom_value(a(d).children(".customelement:first"),"get"):d.value;b.onchange()},d)});setTimeout(function(){g.data=a(c).val();b.onchange()},0)}});for(e=m=0;e<b.p.columns.length;e++){l="undefined"===typeof b.p.columns[e].search?!0:b.p.columns[e].search;var r=!0===b.p.columns[e].hidden;if(!0===b.p.columns[e].searchoptions.searchhidden&&l||l&&!r)l="",g.field===b.p.columns[e].name&&(l=" selected='selected'",m=e),j+="<option value='"+
+b.p.columns[e].name+"'"+l+">"+b.p.columns[e].label+"</option>"}n.append(j);j=a("<td class='operators'></td>");c.append(j);i=o.columns[m];i.searchoptions.id=a.jgrid.randId();t&&"text"===i.inputtype&&!i.searchoptions.size&&(i.searchoptions.size=10);var m=a.jgrid.createEl(i.inputtype,i.searchoptions,g.data,!0,b.p.ajaxSelectOptions,!0),s=a("<select class='selectopts'></select>");j.append(s);s.bind("change",function(){g.op=a(s).val();h=a(this).parents("tr:first");var c=a(".input-elm",h)[0];if(g.op==="nu"||
+g.op==="nn"){g.data="";c.value="";c.setAttribute("readonly","true");c.setAttribute("disabled","true")}else{c.removeAttribute("readonly");c.removeAttribute("disabled")}b.onchange()});f=i.searchoptions.sopt?i.searchoptions.sopt:b.p.sopt?b.p.sopt:"string"===i.searchtype?o.stropts:b.p.numopts;j="";a.each(b.p.ops,function(){q.push(this.name)});for(e=0;e<f.length;e++)p=a.inArray(f[e],q),-1!==p&&(l=g.op===b.p.ops[p].name?" selected='selected'":"",j+="<option value='"+b.p.ops[p].name+"'"+l+">"+b.p.ops[p].description+
+"</option>");s.append(j);j=a("<td class='data'></td>");c.append(j);j.append(m);a(m).addClass("input-elm").bind("change",function(){g.data=i.inputtype==="custom"?i.searchoptions.custom_value(a(this).children(".customelement:first"),"get"):a(this).val();b.onchange()});j=a("<td></td>");c.append(j);!0===this.p.ruleButtons&&(m=a("<input type='button' value='-' title='Delete rule' class='delete-rule ui-del'/>"),j.append(m),m.bind("click",function(){for(e=0;e<d.rules.length;e++)if(d.rules[e]===g){d.rules.splice(e,
+1);break}b.reDraw();b.onchange();return false}));return c};this.getStringForGroup=function(a){var d="(",b;if(void 0!==a.groups)for(b=0;b<a.groups.length;b++){1<d.length&&(d+=" "+a.groupOp+" ");try{d+=this.getStringForGroup(a.groups[b])}catch(c){alert(c)}}if(void 0!==a.rules)try{for(b=0;b<a.rules.length;b++)1<d.length&&(d+=" "+a.groupOp+" "),d+=this.getStringForRule(a.rules[b])}catch(e){alert(e)}d+=")";return"()"===d?"":d};this.getStringForRule=function(d){var f="",b="",c,e;for(c=0;c<this.p.ops.length;c++)if(this.p.ops[c].name===
+d.op){f=this.p.ops[c].operator;b=this.p.ops[c].name;break}for(c=0;c<this.p.columns.length;c++)if(this.p.columns[c].name===d.field){e=this.p.columns[c];break}c=d.data;if("bw"===b||"bn"===b)c+="%";if("ew"===b||"en"===b)c="%"+c;if("cn"===b||"nc"===b)c="%"+c+"%";if("in"===b||"ni"===b)c=" ("+c+")";o.errorcheck&&r(d.data,e);return-1!==a.inArray(e.searchtype,["int","integer","float","number","currency"])||"nn"===b||"nu"===b?d.field+" "+f+" "+c:d.field+" "+f+' "'+c+'"'};this.resetFilter=function(){this.p.filter=
+a.extend(!0,{},this.p.initFilter);this.reDraw();this.onchange()};this.hideError=function(){a("th.ui-state-error",this).html("");a("tr.error",this).hide()};this.showError=function(){a("th.ui-state-error",this).html(this.p.errmsg);a("tr.error",this).show()};this.toUserFriendlyString=function(){return this.getStringForGroup(o.filter)};this.toString=function(){function a(b){var c="(",e;if(void 0!==b.groups)for(e=0;e<b.groups.length;e++)1<c.length&&(c="OR"===b.groupOp?c+" || ":c+" && "),c+=a(b.groups[e]);
+if(void 0!==b.rules)for(e=0;e<b.rules.length;e++){1<c.length&&(c="OR"===b.groupOp?c+" || ":c+" && ");var f=b.rules[e];if(d.p.errorcheck){for(var h=void 0,i=void 0,h=0;h<d.p.columns.length;h++)if(d.p.columns[h].name===f.field){i=d.p.columns[h];break}i&&r(f.data,i)}c+=f.op+"(item."+f.field+",'"+f.data+"')"}c+=")";return"()"===c?"":c}var d=this;return a(this.p.filter)};this.reDraw();if(this.p.showQuery)this.onchange();this.filter=!0}}})};a.extend(a.fn.jqFilter,{toSQLString:function(){var a="";this.each(function(){a=
+this.toUserFriendlyString()});return a},filterData:function(){var a;this.each(function(){a=this.p.filter});return a},getParameter:function(a){return void 0!==a&&this.p.hasOwnProperty(a)?this.p[a]:this.p},resetFilter:function(){return this.each(function(){this.resetFilter()})},addFilter:function(a){"string"===typeof a&&(a=jQuery.jgrid.parse(a));this.each(function(){this.p.filter=a;this.reDraw();this.onchange()})}})})(jQuery);
+(function(a){a.jgrid.inlineEdit=a.jgrid.inlineEdit||{};a.jgrid.extend({editRow:function(c,b,d,k,g,l,p,h,f){var j={},e=a.makeArray(arguments).slice(1);if("object"===a.type(e[0]))j=e[0];else if("undefined"!==typeof b&&(j.keys=b),a.isFunction(d)&&(j.oneditfunc=d),a.isFunction(k)&&(j.successfunc=k),"undefined"!==typeof g&&(j.url=g),"undefined"!==typeof l&&(j.extraparam=l),a.isFunction(p)&&(j.aftersavefunc=p),a.isFunction(h)&&(j.errorfunc=h),a.isFunction(f))j.afterrestorefunc=f;j=a.extend(!0,{keys:!1,
+oneditfunc:null,successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:!0,mtype:"POST"},a.jgrid.inlineEdit,j);return this.each(function(){var b=this,f,d,e,g=0,h=null,l={},m,n;b.grid&&(m=a(b).jqGrid("getInd",c,!0),!1!==m&&(e=a(m).attr("editable")||"0","0"==e&&!a(m).hasClass("not-editable-row")&&(n=b.p.colModel,a('td[role="gridcell"]',m).each(function(e){f=n[e].name;var j=!0===b.p.treeGrid&&f==b.p.ExpandColumn;if(j)d=a("span:first",this).html();
+else try{d=a.unformat.call(b,this,{rowId:c,colModel:n[e]},e)}catch(m){d=n[e].edittype&&"textarea"==n[e].edittype?a(this).text():a(this).html()}if("cb"!=f&&("subgrid"!=f&&"rn"!=f)&&(b.p.autoencode&&(d=a.jgrid.htmlDecode(d)),l[f]=d,!0===n[e].editable)){null===h&&(h=e);j?a("span:first",this).html(""):a(this).html("");var k=a.extend({},n[e].editoptions||{},{id:c+"_"+f,name:f});n[e].edittype||(n[e].edittype="text");if("&nbsp;"==d||"&#160;"==d||1==d.length&&160==d.charCodeAt(0))d="";k=a.jgrid.createEl.call(b,
+n[e].edittype,k,d,!0,a.extend({},a.jgrid.ajaxOptions,b.p.ajaxSelectOptions||{}));a(k).addClass("editable");j?a("span:first",this).append(k):a(this).append(k);"select"==n[e].edittype&&("undefined"!==typeof n[e].editoptions&&!0===n[e].editoptions.multiple&&"undefined"===typeof n[e].editoptions.dataUrl&&a.browser.msie)&&a(k).width(a(k).width());g++}}),0<g&&(l.id=c,b.p.savedRow.push(l),a(m).attr("editable","1"),a("td:eq("+h+") input",m).focus(),!0===j.keys&&a(m).bind("keydown",function(e){if(27===e.keyCode){a(b).jqGrid("restoreRow",
+c,j.afterrestorefunc);if(b.p._inlinenav)try{a(b).jqGrid("showAddEditButtons")}catch(d){}return!1}if(13===e.keyCode){if("TEXTAREA"==e.target.tagName)return!0;if(a(b).jqGrid("saveRow",c,j)&&b.p._inlinenav)try{a(b).jqGrid("showAddEditButtons")}catch(f){}return!1}}),a(b).triggerHandler("jqGridInlineEditRow",[c,j]),a.isFunction(j.oneditfunc)&&j.oneditfunc.call(b,c)))))})},saveRow:function(c,b,d,k,g,l,p){var h=a.makeArray(arguments).slice(1),f={};if("object"===a.type(h[0]))f=h[0];else if(a.isFunction(b)&&
+(f.successfunc=b),"undefined"!==typeof d&&(f.url=d),"undefined"!==typeof k&&(f.extraparam=k),a.isFunction(g)&&(f.aftersavefunc=g),a.isFunction(l)&&(f.errorfunc=l),a.isFunction(p))f.afterrestorefunc=p;var f=a.extend(!0,{successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:!0,mtype:"POST"},a.jgrid.inlineEdit,f),j=!1,e=this[0],o,i={},u={},r={},t,s,q;if(!e.grid)return j;q=a(e).jqGrid("getInd",c,!0);if(!1===q)return j;h=a(q).attr("editable");
+f.url=f.url?f.url:e.p.editurl;if("1"===h){var m;a('td[role="gridcell"]',q).each(function(b){m=e.p.colModel[b];o=m.name;if("cb"!=o&&"subgrid"!=o&&!0===m.editable&&"rn"!=o&&!a(this).hasClass("not-editable-cell")){switch(m.edittype){case "checkbox":var c=["Yes","No"];m.editoptions&&(c=m.editoptions.value.split(":"));i[o]=a("input",this).is(":checked")?c[0]:c[1];break;case "text":case "password":case "textarea":case "button":i[o]=a("input, textarea",this).val();break;case "select":if(m.editoptions.multiple){var c=
+a("select",this),d=[];i[o]=a(c).val();i[o]=i[o]?i[o].join(","):"";a("select option:selected",this).each(function(b,c){d[b]=a(c).text()});u[o]=d.join(",")}else i[o]=a("select option:selected",this).val(),u[o]=a("select option:selected",this).text();m.formatter&&"select"==m.formatter&&(u={});break;case "custom":try{if(m.editoptions&&a.isFunction(m.editoptions.custom_value)){if(i[o]=m.editoptions.custom_value.call(e,a(".customelement",this),"get"),void 0===i[o])throw"e2";}else throw"e1";}catch(g){"e1"==
+g&&a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.nodefined,a.jgrid.edit.bClose),"e2"==g?a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.novalue,a.jgrid.edit.bClose):a.jgrid.info_dialog(a.jgrid.errors.errcap,g.message,a.jgrid.edit.bClose)}}s=a.jgrid.checkValues(i[o],b,e);if(!1===s[0])return s[1]=i[o]+" "+s[1],!1;e.p.autoencode&&(i[o]=a.jgrid.htmlEncode(i[o]));"clientArray"!==f.url&&m.editoptions&&!0===m.editoptions.NullIfEmpty&&
+""===i[o]&&(r[o]="null")}});if(!1===s[0]){try{var n=a.jgrid.findPos(a("#"+a.jgrid.jqID(c),e.grid.bDiv)[0]);a.jgrid.info_dialog(a.jgrid.errors.errcap,s[1],a.jgrid.edit.bClose,{left:n[0],top:n[1]})}catch(w){alert(s[1])}return j}var v,h=e.p.prmNames;v=h.oper;n=h.id;i&&(i[v]=h.editoper,i[n]=c,"undefined"==typeof e.p.inlineData&&(e.p.inlineData={}),i=a.extend({},i,e.p.inlineData,f.extraparam));if("clientArray"==f.url){i=a.extend({},i,u);e.p.autoencode&&a.each(i,function(b,c){i[b]=a.jgrid.htmlDecode(c)});
+n=a(e).jqGrid("setRowData",c,i);a(q).attr("editable","0");for(h=0;h<e.p.savedRow.length;h++)if(e.p.savedRow[h].id==c){t=h;break}0<=t&&e.p.savedRow.splice(t,1);a(e).triggerHandler("jqGridInlineAfterSaveRow",[c,n,i,f]);a.isFunction(f.aftersavefunc)&&f.aftersavefunc.call(e,c,n);j=!0;a(q).unbind("keydown")}else a("#lui_"+a.jgrid.jqID(e.p.id)).show(),r=a.extend({},i,r),r[n]=a.jgrid.stripPref(e.p.idPrefix,r[n]),a.ajax(a.extend({url:f.url,data:a.isFunction(e.p.serializeRowData)?e.p.serializeRowData.call(e,
+r):r,type:f.mtype,async:!1,complete:function(b,d){a("#lui_"+a.jgrid.jqID(e.p.id)).hide();if(d==="success"){var g=true,h;h=a(e).triggerHandler("jqGridInlineSuccessSaveRow",[b,c,f]);a.isArray(h)||(h=[true,i]);h[0]&&a.isFunction(f.successfunc)&&(h=f.successfunc.call(e,b));if(a.isArray(h)){g=h[0];i=h[1]?h[1]:i}else g=h;if(g===true){e.p.autoencode&&a.each(i,function(b,c){i[b]=a.jgrid.htmlDecode(c)});i=a.extend({},i,u);a(e).jqGrid("setRowData",c,i);a(q).attr("editable","0");for(g=0;g<e.p.savedRow.length;g++)if(e.p.savedRow[g].id==
+c){t=g;break}t>=0&&e.p.savedRow.splice(t,1);a(e).triggerHandler("jqGridInlineAfterSaveRow",[c,b,i,f]);a.isFunction(f.aftersavefunc)&&f.aftersavefunc.call(e,c,b);j=true;a(q).unbind("keydown")}else{a(e).triggerHandler("jqGridInlineErrorSaveRow",[c,b,d,null,f]);a.isFunction(f.errorfunc)&&f.errorfunc.call(e,c,b,d,null);f.restoreAfterError===true&&a(e).jqGrid("restoreRow",c,f.afterrestorefunc)}}},error:function(b,d,g){a("#lui_"+a.jgrid.jqID(e.p.id)).hide();a(e).triggerHandler("jqGridInlineErrorSaveRow",
+[c,b,d,g,f]);if(a.isFunction(f.errorfunc))f.errorfunc.call(e,c,b,d,g);else try{a.jgrid.info_dialog(a.jgrid.errors.errcap,'<div class="ui-state-error">'+b.responseText+"</div>",a.jgrid.edit.bClose,{buttonalign:"right"})}catch(h){alert(b.responseText)}f.restoreAfterError===true&&a(e).jqGrid("restoreRow",c,f.afterrestorefunc)}},a.jgrid.ajaxOptions,e.p.ajaxRowOptions||{}))}return j},restoreRow:function(c,b){var d=a.makeArray(arguments).slice(1),k={};"object"===a.type(d[0])?k=d[0]:a.isFunction(b)&&(k.afterrestorefunc=
+b);k=a.extend(!0,a.jgrid.inlineEdit,k);return this.each(function(){var b=this,d,p,h={};if(b.grid){p=a(b).jqGrid("getInd",c,true);if(p!==false){for(var f=0;f<b.p.savedRow.length;f++)if(b.p.savedRow[f].id==c){d=f;break}if(d>=0){if(a.isFunction(a.fn.datepicker))try{a("input.hasDatepicker","#"+a.jgrid.jqID(p.id)).datepicker("hide")}catch(j){}a.each(b.p.colModel,function(){this.editable===true&&this.name in b.p.savedRow[d]&&(h[this.name]=b.p.savedRow[d][this.name])});a(b).jqGrid("setRowData",c,h);a(p).attr("editable",
+"0").unbind("keydown");b.p.savedRow.splice(d,1);a("#"+a.jgrid.jqID(c),"#"+a.jgrid.jqID(b.p.id)).hasClass("jqgrid-new-row")&&setTimeout(function(){a(b).jqGrid("delRowData",c)},0)}a(b).triggerHandler("jqGridInlineAfterRestoreRow",[c]);a.isFunction(k.afterrestorefunc)&&k.afterrestorefunc.call(b,c)}}})},addRow:function(c){c=a.extend(!0,{rowID:"new_row",initdata:{},position:"first",useDefValues:!0,useFormatter:!1,addRowParams:{extraparam:{}}},c||{});return this.each(function(){if(this.grid){var b=this;
+!0===c.useDefValues&&a(b.p.colModel).each(function(){if(this.editoptions&&this.editoptions.defaultValue){var d=this.editoptions.defaultValue,d=a.isFunction(d)?d.call(b):d;c.initdata[this.name]=d}});a(b).jqGrid("addRowData",c.rowID,c.initdata,c.position);c.rowID=b.p.idPrefix+c.rowID;a("#"+a.jgrid.jqID(c.rowID),"#"+a.jgrid.jqID(b.p.id)).addClass("jqgrid-new-row");if(c.useFormatter)a("#"+a.jgrid.jqID(c.rowID)+" .ui-inline-edit","#"+a.jgrid.jqID(b.p.id)).click();else{var d=b.p.prmNames;c.addRowParams.extraparam[d.oper]=
+d.addoper;a(b).jqGrid("editRow",c.rowID,c.addRowParams);a(b).jqGrid("setSelection",c.rowID)}}})},inlineNav:function(c,b){b=a.extend({edit:!0,editicon:"ui-icon-pencil",add:!0,addicon:"ui-icon-plus",save:!0,saveicon:"ui-icon-disk",cancel:!0,cancelicon:"ui-icon-cancel",addParams:{useFormatter:!1,rowID:"new_row"},editParams:{},restoreAfterSelect:!0},a.jgrid.nav,b||{});return this.each(function(){if(this.grid){var d=this,k,g=a.jgrid.jqID(d.p.id);d.p._inlinenav=!0;if(!0===b.addParams.useFormatter){var l=
+d.p.colModel,p;for(p=0;p<l.length;p++)if(l[p].formatter&&"actions"===l[p].formatter){l[p].formatoptions&&(l=a.extend({keys:!1,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null},l[p].formatoptions),b.addParams.addRowParams={keys:l.keys,oneditfunc:l.onEdit,successfunc:l.onSuccess,url:l.url,extraparam:l.extraparam,aftersavefunc:l.afterSavef,errorfunc:l.onError,afterrestorefunc:l.afterRestore});break}}b.add&&a(d).jqGrid("navButtonAdd",c,{caption:b.addtext,
+title:b.addtitle,buttonicon:b.addicon,id:d.p.id+"_iladd",onClickButton:function(){a(d).jqGrid("addRow",b.addParams);b.addParams.useFormatter||(a("#"+g+"_ilsave").removeClass("ui-state-disabled"),a("#"+g+"_ilcancel").removeClass("ui-state-disabled"),a("#"+g+"_iladd").addClass("ui-state-disabled"),a("#"+g+"_iledit").addClass("ui-state-disabled"))}});b.edit&&a(d).jqGrid("navButtonAdd",c,{caption:b.edittext,title:b.edittitle,buttonicon:b.editicon,id:d.p.id+"_iledit",onClickButton:function(){var c=a(d).jqGrid("getGridParam",
+"selrow");c?(a(d).jqGrid("editRow",c,b.editParams),a("#"+g+"_ilsave").removeClass("ui-state-disabled"),a("#"+g+"_ilcancel").removeClass("ui-state-disabled"),a("#"+g+"_iladd").addClass("ui-state-disabled"),a("#"+g+"_iledit").addClass("ui-state-disabled")):(a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:!0}),a("#jqg_alrt").focus())}});b.save&&(a(d).jqGrid("navButtonAdd",c,{caption:b.savetext||"",title:b.savetitle||"Save row",buttonicon:b.saveicon,id:d.p.id+"_ilsave",onClickButton:function(){var c=
+d.p.savedRow[0].id;if(c){var f=d.p.prmNames,j=f.oper;b.editParams.extraparam||(b.editParams.extraparam={});b.editParams.extraparam[j]=a("#"+a.jgrid.jqID(c),"#"+g).hasClass("jqgrid-new-row")?f.addoper:f.editoper;a(d).jqGrid("saveRow",c,b.editParams)&&a(d).jqGrid("showAddEditButtons")}else a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:!0}),a("#jqg_alrt").focus()}}),a("#"+g+"_ilsave").addClass("ui-state-disabled"));b.cancel&&(a(d).jqGrid("navButtonAdd",c,{caption:b.canceltext||"",title:b.canceltitle||
+"Cancel row editing",buttonicon:b.cancelicon,id:d.p.id+"_ilcancel",onClickButton:function(){var c=d.p.savedRow[0].id;if(c){a(d).jqGrid("restoreRow",c,b.editParams);a(d).jqGrid("showAddEditButtons")}else{a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:true});a("#jqg_alrt").focus()}}}),a("#"+g+"_ilcancel").addClass("ui-state-disabled"));!0===b.restoreAfterSelect&&(k=a.isFunction(d.p.beforeSelectRow)?d.p.beforeSelectRow:!1,d.p.beforeSelectRow=function(c,f){var g=true;if(d.p.savedRow.length>0&&d.p._inlinenav===
+true&&c!==d.p.selrow&&d.p.selrow!==null){d.p.selrow==b.addParams.rowID?a(d).jqGrid("delRowData",d.p.selrow):a(d).jqGrid("restoreRow",d.p.selrow,b.editParams);a(d).jqGrid("showAddEditButtons")}k&&(g=k.call(d,c,f));return g})}})},showAddEditButtons:function(){return this.each(function(){if(this.grid){var c=a.jgrid.jqID(this.p.id);a("#"+c+"_ilsave").addClass("ui-state-disabled");a("#"+c+"_ilcancel").addClass("ui-state-disabled");a("#"+c+"_iladd").removeClass("ui-state-disabled");a("#"+c+"_iledit").removeClass("ui-state-disabled")}})}})})(jQuery);
+(function(b){b.jgrid.extend({editCell:function(d,f,a){return this.each(function(){var c=this,g,e,h,i;if(c.grid&&!0===c.p.cellEdit){f=parseInt(f,10);c.p.selrow=c.rows[d].id;c.p.knv||b(c).jqGrid("GridNav");if(0<c.p.savedRow.length){if(!0===a&&d==c.p.iRow&&f==c.p.iCol)return;b(c).jqGrid("saveCell",c.p.savedRow[0].id,c.p.savedRow[0].ic)}else window.setTimeout(function(){b("#"+b.jgrid.jqID(c.p.knv)).attr("tabindex","-1").focus()},0);i=c.p.colModel[f];g=i.name;if(!("subgrid"==g||"cb"==g||"rn"==g)){h=b("td:eq("+
+f+")",c.rows[d]);if(!0===i.editable&&!0===a&&!h.hasClass("not-editable-cell")){0<=parseInt(c.p.iCol,10)&&0<=parseInt(c.p.iRow,10)&&(b("td:eq("+c.p.iCol+")",c.rows[c.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(c.rows[c.p.iRow]).removeClass("selected-row ui-state-hover"));b(h).addClass("edit-cell ui-state-highlight");b(c.rows[d]).addClass("selected-row ui-state-hover");try{e=b.unformat.call(c,h,{rowId:c.rows[d].id,colModel:i},f)}catch(k){e=i.edittype&&"textarea"==i.edittype?b(h).text():b(h).html()}c.p.autoencode&&
+(e=b.jgrid.htmlDecode(e));i.edittype||(i.edittype="text");c.p.savedRow.push({id:d,ic:f,name:g,v:e});if("&nbsp;"===e||"&#160;"===e||1===e.length&&160===e.charCodeAt(0))e="";if(b.isFunction(c.p.formatCell)){var j=c.p.formatCell.call(c,c.rows[d].id,g,e,d,f);void 0!==j&&(e=j)}var j=b.extend({},i.editoptions||{},{id:d+"_"+g,name:g}),n=b.jgrid.createEl.call(c,i.edittype,j,e,!0,b.extend({},b.jgrid.ajaxOptions,c.p.ajaxSelectOptions||{}));b(c).triggerHandler("jqGridBeforeEditCell",[c.rows[d].id,g,e,d,f]);
+b.isFunction(c.p.beforeEditCell)&&c.p.beforeEditCell.call(c,c.rows[d].id,g,e,d,f);b(h).html("").append(n).attr("tabindex","0");window.setTimeout(function(){b(n).focus()},0);b("input, select, textarea",h).bind("keydown",function(a){a.keyCode===27&&(b("input.hasDatepicker",h).length>0?b(".ui-datepicker").is(":hidden")?b(c).jqGrid("restoreCell",d,f):b("input.hasDatepicker",h).datepicker("hide"):b(c).jqGrid("restoreCell",d,f));if(a.keyCode===13){b(c).jqGrid("saveCell",d,f);return false}if(a.keyCode===
+9){if(c.grid.hDiv.loading)return false;a.shiftKey?b(c).jqGrid("prevCell",d,f):b(c).jqGrid("nextCell",d,f)}a.stopPropagation()});b(c).triggerHandler("jqGridAfterEditCell",[c.rows[d].id,g,e,d,f]);b.isFunction(c.p.afterEditCell)&&c.p.afterEditCell.call(c,c.rows[d].id,g,e,d,f)}else 0<=parseInt(c.p.iCol,10)&&0<=parseInt(c.p.iRow,10)&&(b("td:eq("+c.p.iCol+")",c.rows[c.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(c.rows[c.p.iRow]).removeClass("selected-row ui-state-hover")),h.addClass("edit-cell ui-state-highlight"),
+b(c.rows[d]).addClass("selected-row ui-state-hover"),e=h.html().replace(/\&#160\;/ig,""),b(c).triggerHandler("jqGridSelectCell",[c.rows[d].id,g,e,d,f]),b.isFunction(c.p.onSelectCell)&&c.p.onSelectCell.call(c,c.rows[d].id,g,e,d,f);c.p.iCol=f;c.p.iRow=d}}})},saveCell:function(d,f){return this.each(function(){var a=this,c;if(a.grid&&!0===a.p.cellEdit){c=1<=a.p.savedRow.length?0:null;if(null!==c){var g=b("td:eq("+f+")",a.rows[d]),e,h,i=a.p.colModel[f],k=i.name,j=b.jgrid.jqID(k);switch(i.edittype){case "select":if(i.editoptions.multiple){var j=
+b("#"+d+"_"+j,a.rows[d]),n=[];(e=b(j).val())?e.join(","):e="";b("option:selected",j).each(function(a,c){n[a]=b(c).text()});h=n.join(",")}else e=b("#"+d+"_"+j+" option:selected",a.rows[d]).val(),h=b("#"+d+"_"+j+" option:selected",a.rows[d]).text();i.formatter&&(h=e);break;case "checkbox":var l=["Yes","No"];i.editoptions&&(l=i.editoptions.value.split(":"));h=e=b("#"+d+"_"+j,a.rows[d]).is(":checked")?l[0]:l[1];break;case "password":case "text":case "textarea":case "button":h=e=b("#"+d+"_"+j,a.rows[d]).val();
+break;case "custom":try{if(i.editoptions&&b.isFunction(i.editoptions.custom_value)){e=i.editoptions.custom_value.call(a,b(".customelement",g),"get");if(void 0===e)throw"e2";h=e}else throw"e1";}catch(o){"e1"==o&&b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+b.jgrid.edit.msg.nodefined,jQuery.jgrid.edit.bClose),"e2"==o?b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+b.jgrid.edit.msg.novalue,jQuery.jgrid.edit.bClose):b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,
+o.message,jQuery.jgrid.edit.bClose)}}if(h!==a.p.savedRow[c].v){if(c=b(a).triggerHandler("jqGridBeforeSaveCell",[a.rows[d].id,k,e,d,f]))h=e=c;if(b.isFunction(a.p.beforeSaveCell)&&(c=a.p.beforeSaveCell.call(a,a.rows[d].id,k,e,d,f)))h=e=c;var p=b.jgrid.checkValues(e,f,a);if(!0===p[0]){c=b(a).triggerHandler("jqGridBeforeSubmitCell",[a.rows[d].id,k,e,d,f])||{};b.isFunction(a.p.beforeSubmitCell)&&((c=a.p.beforeSubmitCell.call(a,a.rows[d].id,k,e,d,f))||(c={}));0<b("input.hasDatepicker",g).length&&b("input.hasDatepicker",
+g).datepicker("hide");if("remote"==a.p.cellsubmit)if(a.p.cellurl){var m={};a.p.autoencode&&(e=b.jgrid.htmlEncode(e));m[k]=e;l=a.p.prmNames;i=l.id;j=l.oper;m[i]=b.jgrid.stripPref(a.p.idPrefix,a.rows[d].id);m[j]=l.editoper;m=b.extend(c,m);b("#lui_"+b.jgrid.jqID(a.p.id)).show();a.grid.hDiv.loading=!0;b.ajax(b.extend({url:a.p.cellurl,data:b.isFunction(a.p.serializeCellData)?a.p.serializeCellData.call(a,m):m,type:"POST",complete:function(c,i){b("#lui_"+a.p.id).hide();a.grid.hDiv.loading=false;if(i=="success"){var j=
+b(a).triggerHandler("jqGridAfterSubmitCell",[a,c,m.id,k,e,d,f])||[true,""];j[0]===true&&b.isFunction(a.p.afterSubmitCell)&&(j=a.p.afterSubmitCell.call(a,c,m.id,k,e,d,f));if(j[0]===true){b(g).empty();b(a).jqGrid("setCell",a.rows[d].id,f,h,false,false,true);b(g).addClass("dirty-cell");b(a.rows[d]).addClass("edited");b(a).triggerHandler("jqGridAfterSaveCell",[a.rows[d].id,k,e,d,f]);b.isFunction(a.p.afterSaveCell)&&a.p.afterSaveCell.call(a,a.rows[d].id,k,e,d,f);a.p.savedRow.splice(0,1)}else{b.jgrid.info_dialog(b.jgrid.errors.errcap,
+j[1],b.jgrid.edit.bClose);b(a).jqGrid("restoreCell",d,f)}}},error:function(c,e,h){b("#lui_"+b.jgrid.jqID(a.p.id)).hide();a.grid.hDiv.loading=false;b(a).triggerHandler("jqGridErrorCell",[c,e,h]);b.isFunction(a.p.errorCell)?a.p.errorCell.call(a,c,e,h):b.jgrid.info_dialog(b.jgrid.errors.errcap,c.status+" : "+c.statusText+"<br/>"+e,b.jgrid.edit.bClose);b(a).jqGrid("restoreCell",d,f)}},b.jgrid.ajaxOptions,a.p.ajaxCellOptions||{}))}else try{b.jgrid.info_dialog(b.jgrid.errors.errcap,b.jgrid.errors.nourl,
+b.jgrid.edit.bClose),b(a).jqGrid("restoreCell",d,f)}catch(q){}"clientArray"==a.p.cellsubmit&&(b(g).empty(),b(a).jqGrid("setCell",a.rows[d].id,f,h,!1,!1,!0),b(g).addClass("dirty-cell"),b(a.rows[d]).addClass("edited"),b(a).triggerHandler("jqGridAfterSaveCell",[a.rows[d].id,k,e,d,f]),b.isFunction(a.p.afterSaveCell)&&a.p.afterSaveCell.call(a,a.rows[d].id,k,e,d,f),a.p.savedRow.splice(0,1))}else try{window.setTimeout(function(){b.jgrid.info_dialog(b.jgrid.errors.errcap,e+" "+p[1],b.jgrid.edit.bClose)},
+100),b(a).jqGrid("restoreCell",d,f)}catch(r){}}else b(a).jqGrid("restoreCell",d,f)}b.browser.opera?b("#"+b.jgrid.jqID(a.p.knv)).attr("tabindex","-1").focus():window.setTimeout(function(){b("#"+b.jgrid.jqID(a.p.knv)).attr("tabindex","-1").focus()},0)}})},restoreCell:function(d,f){return this.each(function(){var a=this,c;if(a.grid&&!0===a.p.cellEdit){c=1<=a.p.savedRow.length?0:null;if(null!==c){var g=b("td:eq("+f+")",a.rows[d]);if(b.isFunction(b.fn.datepicker))try{b("input.hasDatepicker",g).datepicker("hide")}catch(e){}b(g).empty().attr("tabindex",
+"-1");b(a).jqGrid("setCell",a.rows[d].id,f,a.p.savedRow[c].v,!1,!1,!0);b(a).triggerHandler("jqGridAfterRestoreCell",[a.rows[d].id,a.p.savedRow[c].v,d,f]);b.isFunction(a.p.afterRestoreCell)&&a.p.afterRestoreCell.call(a,a.rows[d].id,a.p.savedRow[c].v,d,f);a.p.savedRow.splice(0,1)}window.setTimeout(function(){b("#"+a.p.knv).attr("tabindex","-1").focus()},0)}})},nextCell:function(d,f){return this.each(function(){var a=!1;if(this.grid&&!0===this.p.cellEdit){for(var c=f+1;c<this.p.colModel.length;c++)if(!0===
+this.p.colModel[c].editable){a=c;break}!1!==a?b(this).jqGrid("editCell",d,a,!0):0<this.p.savedRow.length&&b(this).jqGrid("saveCell",d,f)}})},prevCell:function(d,f){return this.each(function(){var a=!1;if(this.grid&&!0===this.p.cellEdit){for(var c=f-1;0<=c;c--)if(!0===this.p.colModel[c].editable){a=c;break}!1!==a?b(this).jqGrid("editCell",d,a,!0):0<this.p.savedRow.length&&b(this).jqGrid("saveCell",d,f)}})},GridNav:function(){return this.each(function(){function d(c,d,e){if("v"==e.substr(0,1)){var f=
+b(a.grid.bDiv)[0].clientHeight,g=b(a.grid.bDiv)[0].scrollTop,l=a.rows[c].offsetTop+a.rows[c].clientHeight,o=a.rows[c].offsetTop;"vd"==e&&l>=f&&(b(a.grid.bDiv)[0].scrollTop=b(a.grid.bDiv)[0].scrollTop+a.rows[c].clientHeight);"vu"==e&&o<g&&(b(a.grid.bDiv)[0].scrollTop=b(a.grid.bDiv)[0].scrollTop-a.rows[c].clientHeight)}"h"==e&&(e=b(a.grid.bDiv)[0].clientWidth,f=b(a.grid.bDiv)[0].scrollLeft,g=a.rows[c].cells[d].offsetLeft,a.rows[c].cells[d].offsetLeft+a.rows[c].cells[d].clientWidth>=e+parseInt(f,10)?
+b(a.grid.bDiv)[0].scrollLeft=b(a.grid.bDiv)[0].scrollLeft+a.rows[c].cells[d].clientWidth:g<f&&(b(a.grid.bDiv)[0].scrollLeft=b(a.grid.bDiv)[0].scrollLeft-a.rows[c].cells[d].clientWidth))}function f(b,c){var d,e;if("lft"==c){d=b+1;for(e=b;0<=e;e--)if(!0!==a.p.colModel[e].hidden){d=e;break}}if("rgt"==c){d=b-1;for(e=b;e<a.p.colModel.length;e++)if(!0!==a.p.colModel[e].hidden){d=e;break}}return d}var a=this;if(a.grid&&!0===a.p.cellEdit){a.p.knv=a.p.id+"_kn";var c=b("<span style='width:0px;height:0px;background-color:black;' tabindex='0'><span tabindex='-1' style='width:0px;height:0px;background-color:grey' id='"+
+a.p.knv+"'></span></span>"),g,e;b(c).insertBefore(a.grid.cDiv);b("#"+a.p.knv).focus().keydown(function(c){e=c.keyCode;"rtl"==a.p.direction&&(37===e?e=39:39===e&&(e=37));switch(e){case 38:0<a.p.iRow-1&&(d(a.p.iRow-1,a.p.iCol,"vu"),b(a).jqGrid("editCell",a.p.iRow-1,a.p.iCol,!1));break;case 40:a.p.iRow+1<=a.rows.length-1&&(d(a.p.iRow+1,a.p.iCol,"vd"),b(a).jqGrid("editCell",a.p.iRow+1,a.p.iCol,!1));break;case 37:0<=a.p.iCol-1&&(g=f(a.p.iCol-1,"lft"),d(a.p.iRow,g,"h"),b(a).jqGrid("editCell",a.p.iRow,g,
+!1));break;case 39:a.p.iCol+1<=a.p.colModel.length-1&&(g=f(a.p.iCol+1,"rgt"),d(a.p.iRow,g,"h"),b(a).jqGrid("editCell",a.p.iRow,g,!1));break;case 13:0<=parseInt(a.p.iCol,10)&&0<=parseInt(a.p.iRow,10)&&b(a).jqGrid("editCell",a.p.iRow,a.p.iCol,!0);break;default:return!0}return!1})}})},getChangedCells:function(d){var f=[];d||(d="all");this.each(function(){var a=this,c;a.grid&&!0===a.p.cellEdit&&b(a.rows).each(function(g){var e={};b(this).hasClass("edited")&&(b("td",this).each(function(f){c=a.p.colModel[f].name;
+if("cb"!==c&&"subgrid"!==c)if("dirty"==d){if(b(this).hasClass("dirty-cell"))try{e[c]=b.unformat.call(a,this,{rowId:a.rows[g].id,colModel:a.p.colModel[f]},f)}catch(i){e[c]=b.jgrid.htmlDecode(b(this).html())}}else try{e[c]=b.unformat.call(a,this,{rowId:a.rows[g].id,colModel:a.p.colModel[f]},f)}catch(k){e[c]=b.jgrid.htmlDecode(b(this).html())}}),e.id=this.id,f.push(e))})});return f}})})(jQuery);
+(function(b){b.fn.jqm=function(a){var k={overlay:50,closeoverlay:!0,overlayClass:"jqmOverlay",closeClass:"jqmClose",trigger:".jqModal",ajax:d,ajaxText:"",target:d,modal:d,toTop:d,onShow:d,onHide:d,onLoad:d};return this.each(function(){if(this._jqm)return i[this._jqm].c=b.extend({},i[this._jqm].c,a);g++;this._jqm=g;i[g]={c:b.extend(k,b.jqm.params,a),a:d,w:b(this).addClass("jqmID"+g),s:g};k.trigger&&b(this).jqmAddTrigger(k.trigger)})};b.fn.jqmAddClose=function(a){return n(this,a,"jqmHide")};b.fn.jqmAddTrigger=
+function(a){return n(this,a,"jqmShow")};b.fn.jqmShow=function(a){return this.each(function(){b.jqm.open(this._jqm,a)})};b.fn.jqmHide=function(a){return this.each(function(){b.jqm.close(this._jqm,a)})};b.jqm={hash:{},open:function(a,k){var c=i[a],e=c.c,l="."+e.closeClass,h=parseInt(c.w.css("z-index")),h=0<h?h:3E3,f=b("<div></div>").css({height:"100%",width:"100%",position:"fixed",left:0,top:0,"z-index":h-1,opacity:e.overlay/100});if(c.a)return d;c.t=k;c.a=!0;c.w.css("z-index",h);e.modal?(j[0]||setTimeout(function(){o("bind")},
+1),j.push(a)):0<e.overlay?e.closeoverlay&&c.w.jqmAddClose(f):f=d;c.o=f?f.addClass(e.overlayClass).prependTo("body"):d;if(p&&(b("html,body").css({height:"100%",width:"100%"}),f)){var f=f.css({position:"absolute"})[0],g;for(g in{Top:1,Left:1})f.style.setExpression(g.toLowerCase(),"(_=(document.documentElement.scroll"+g+" || document.body.scroll"+g+"))+'px'")}e.ajax?(h=e.target||c.w,f=e.ajax,h="string"==typeof h?b(h,c.w):b(h),f="@"==f.substr(0,1)?b(k).attr(f.substring(1)):f,h.html(e.ajaxText).load(f,
+function(){e.onLoad&&e.onLoad.call(this,c);l&&c.w.jqmAddClose(b(l,c.w));q(c)})):l&&c.w.jqmAddClose(b(l,c.w));e.toTop&&c.o&&c.w.before('<span id="jqmP'+c.w[0]._jqm+'"></span>').insertAfter(c.o);e.onShow?e.onShow(c):c.w.show();q(c);return d},close:function(a){a=i[a];if(!a.a)return d;a.a=d;j[0]&&(j.pop(),j[0]||o("unbind"));a.c.toTop&&a.o&&b("#jqmP"+a.w[0]._jqm).after(a.w).remove();if(a.c.onHide)a.c.onHide(a);else a.w.hide(),a.o&&a.o.remove();return d},params:{}};var g=0,i=b.jqm.hash,j=[],p=b.browser.msie&&
+"6.0"==b.browser.version,d=!1,q=function(a){var d=b('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0});p&&(a.o?a.o.html('<p style="width:100%;height:100%"/>').prepend(d):b("iframe.jqm",a.w)[0]||a.w.prepend(d));r(a)},r=function(a){try{b(":input:visible",a.w)[0].focus()}catch(d){}},o=function(a){b(document)[a]("keypress",m)[a]("keydown",m)[a]("mousedown",m)},m=function(a){var d=i[j[j.length-1]];(a=!b(a.target).parents(".jqmID"+d.s)[0])&&r(d);return!a},n=function(a,
+g,c){return a.each(function(){var a=this._jqm;b(g).each(function(){this[c]||(this[c]=[],b(this).click(function(){for(var a in{jqmShow:1,jqmHide:1})for(var b in this[a])if(i[this[a][b]])i[this[a][b]].w[a](this);return d}));this[c].push(a)})})}})(jQuery);
+(function(b){b.fn.jqDrag=function(a){return h(this,a,"d")};b.fn.jqResize=function(a,b){return h(this,a,"r",b)};b.jqDnR={dnr:{},e:0,drag:function(a){"d"==d.k?e.css({left:d.X+a.pageX-d.pX,top:d.Y+a.pageY-d.pY}):(e.css({width:Math.max(a.pageX-d.pX+d.W,0),height:Math.max(a.pageY-d.pY+d.H,0)}),f&&g.css({width:Math.max(a.pageX-f.pX+f.W,0),height:Math.max(a.pageY-f.pY+f.H,0)}));return!1},stop:function(){b(document).unbind("mousemove",c.drag).unbind("mouseup",c.stop)}};var c=b.jqDnR,d=c.dnr,e=c.e,g,f,h=function(a,
+c,h,l){return a.each(function(){c=c?b(c,a):a;c.bind("mousedown",{e:a,k:h},function(a){var c=a.data,i={};e=c.e;g=l?b(l):!1;if("relative"!=e.css("position"))try{e.position(i)}catch(h){}d={X:i.left||j("left")||0,Y:i.top||j("top")||0,W:j("width")||e[0].scrollWidth||0,H:j("height")||e[0].scrollHeight||0,pX:a.pageX,pY:a.pageY,k:c.k};f=g&&"d"!=c.k?{X:i.left||k("left")||0,Y:i.top||k("top")||0,W:g[0].offsetWidth||k("width")||0,H:g[0].offsetHeight||k("height")||0,pX:a.pageX,pY:a.pageY,k:c.k}:!1;if(b("input.hasDatepicker",
+e[0])[0])try{b("input.hasDatepicker",e[0]).datepicker("hide")}catch(m){}b(document).mousemove(b.jqDnR.drag).mouseup(b.jqDnR.stop);return!1})})},j=function(a){return parseInt(e.css(a),10)||!1},k=function(a){return parseInt(g.css(a),10)||!1}})(jQuery);
+(function(b){b.jgrid.extend({setSubGrid:function(){return this.each(function(){var e;this.p.subGridOptions=b.extend({plusicon:"ui-icon-plus",minusicon:"ui-icon-minus",openicon:"ui-icon-carat-1-sw",expandOnLoad:!1,delayOnLoad:50,selectOnExpand:!1,reloadOnExpand:!0},this.p.subGridOptions||{});this.p.colNames.unshift("");this.p.colModel.unshift({name:"subgrid",width:b.browser.safari?this.p.subGridWidth+this.p.cellLayout:this.p.subGridWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,fixed:!0});e=this.p.subGridModel;
+if(e[0]){e[0].align=b.extend([],e[0].align||[]);for(var c=0;c<e[0].name.length;c++)e[0].align[c]=e[0].align[c]||"left"}})},addSubGridCell:function(b,c){var a="",m,l;this.each(function(){a=this.formatCol(b,c);l=this.p.id;m=this.p.subGridOptions.plusicon});return'<td role="gridcell" aria-describedby="'+l+'_subgrid" class="ui-sgcollapsed sgcollapsed" '+a+"><a href='javascript:void(0);'><span class='ui-icon "+m+"'></span></a></td>"},addSubGrid:function(e,c){return this.each(function(){var a=this;if(a.grid){var m=
+function(c,e,h){e=b("<td align='"+a.p.subGridModel[0].align[h]+"'></td>").html(e);b(c).append(e)},l=function(c,e){var h,f,n,d=b("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),i=b("<tr></tr>");for(f=0;f<a.p.subGridModel[0].name.length;f++)h=b("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+a.p.direction+"'></th>"),b(h).html(a.p.subGridModel[0].name[f]),b(h).width(a.p.subGridModel[0].width[f]),b(i).append(h);b(d).append(i);c&&(n=a.p.xmlReader.subgrid,b(n.root+
+" "+n.row,c).each(function(){i=b("<tr class='ui-widget-content ui-subtblcell'></tr>");if(!0===n.repeatitems)b(n.cell,this).each(function(a){m(i,b(this).text()||"&#160;",a)});else{var c=a.p.subGridModel[0].mapping||a.p.subGridModel[0].name;if(c)for(f=0;f<c.length;f++)m(i,b(c[f],this).text()||"&#160;",f)}b(d).append(i)}));h=b("table:first",a.grid.bDiv).attr("id")+"_";b("#"+b.jgrid.jqID(h+e)).append(d);a.grid.hDiv.loading=!1;b("#load_"+b.jgrid.jqID(a.p.id)).hide();return!1},p=function(c,e){var h,f,d,
+g,i,k=b("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),j=b("<tr></tr>");for(f=0;f<a.p.subGridModel[0].name.length;f++)h=b("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+a.p.direction+"'></th>"),b(h).html(a.p.subGridModel[0].name[f]),b(h).width(a.p.subGridModel[0].width[f]),b(j).append(h);b(k).append(j);if(c&&(g=a.p.jsonReader.subgrid,h=c[g.root],"undefined"!==typeof h))for(f=0;f<h.length;f++){d=h[f];j=b("<tr class='ui-widget-content ui-subtblcell'></tr>");
+if(!0===g.repeatitems){g.cell&&(d=d[g.cell]);for(i=0;i<d.length;i++)m(j,d[i]||"&#160;",i)}else{var l=a.p.subGridModel[0].mapping||a.p.subGridModel[0].name;if(l.length)for(i=0;i<l.length;i++)m(j,d[l[i]]||"&#160;",i)}b(k).append(j)}f=b("table:first",a.grid.bDiv).attr("id")+"_";b("#"+b.jgrid.jqID(f+e)).append(k);a.grid.hDiv.loading=!1;b("#load_"+b.jgrid.jqID(a.p.id)).hide();return!1},t=function(c){var e,d,f,g;e=b(c).attr("id");d={nd_:(new Date).getTime()};d[a.p.prmNames.subgridid]=e;if(!a.p.subGridModel[0])return!1;
+if(a.p.subGridModel[0].params)for(g=0;g<a.p.subGridModel[0].params.length;g++)for(f=0;f<a.p.colModel.length;f++)a.p.colModel[f].name===a.p.subGridModel[0].params[g]&&(d[a.p.colModel[f].name]=b("td:eq("+f+")",c).text().replace(/\&#160\;/ig,""));if(!a.grid.hDiv.loading)switch(a.grid.hDiv.loading=!0,b("#load_"+b.jgrid.jqID(a.p.id)).show(),a.p.subgridtype||(a.p.subgridtype=a.p.datatype),b.isFunction(a.p.subgridtype)?a.p.subgridtype.call(a,d):a.p.subgridtype=a.p.subgridtype.toLowerCase(),a.p.subgridtype){case "xml":case "json":b.ajax(b.extend({type:a.p.mtype,
+url:a.p.subGridUrl,dataType:a.p.subgridtype,data:b.isFunction(a.p.serializeSubGridData)?a.p.serializeSubGridData.call(a,d):d,complete:function(c){a.p.subgridtype==="xml"?l(c.responseXML,e):p(b.jgrid.parse(c.responseText),e)}},b.jgrid.ajaxOptions,a.p.ajaxSubgridOptions||{}))}return!1},d,k,q,r=0,g,j;b.each(a.p.colModel,function(){(!0===this.hidden||"rn"===this.name||"cb"===this.name)&&r++});var s=a.rows.length,o=1;void 0!==c&&0<c&&(o=c,s=c+1);for(;o<s;)b(a.rows[o]).hasClass("jqgrow")&&b(a.rows[o].cells[e]).bind("click",
+function(){var c=b(this).parent("tr")[0];j=c.nextSibling;if(b(this).hasClass("sgcollapsed")){k=a.p.id;d=c.id;if(a.p.subGridOptions.reloadOnExpand===true||a.p.subGridOptions.reloadOnExpand===false&&!b(j).hasClass("ui-subgrid")){q=e>=1?"<td colspan='"+e+"'>&#160;</td>":"";g=b(a).triggerHandler("jqGridSubGridBeforeExpand",[k+"_"+d,d]);(g=g===false||g==="stop"?false:true)&&b.isFunction(a.p.subGridBeforeExpand)&&(g=a.p.subGridBeforeExpand.call(a,k+"_"+d,d));if(g===false)return false;b(c).after("<tr role='row' class='ui-subgrid'>"+
+q+"<td class='ui-widget-content subgrid-cell'><span class='ui-icon "+a.p.subGridOptions.openicon+"'></span></td><td colspan='"+parseInt(a.p.colNames.length-1-r,10)+"' class='ui-widget-content subgrid-data'><div id="+k+"_"+d+" class='tablediv'></div></td></tr>");b(a).triggerHandler("jqGridSubGridRowExpanded",[k+"_"+d,d]);b.isFunction(a.p.subGridRowExpanded)?a.p.subGridRowExpanded.call(a,k+"_"+d,d):t(c)}else b(j).show();b(this).html("<a href='javascript:void(0);'><span class='ui-icon "+a.p.subGridOptions.minusicon+
+"'></span></a>").removeClass("sgcollapsed").addClass("sgexpanded");a.p.subGridOptions.selectOnExpand&&b(a).jqGrid("setSelection",d)}else if(b(this).hasClass("sgexpanded")){g=b(a).triggerHandler("jqGridSubGridRowColapsed",[k+"_"+d,d]);if((g=g===false||g==="stop"?false:true)&&b.isFunction(a.p.subGridRowColapsed)){d=c.id;g=a.p.subGridRowColapsed.call(a,k+"_"+d,d)}if(g===false)return false;a.p.subGridOptions.reloadOnExpand===true?b(j).remove(".ui-subgrid"):b(j).hasClass("ui-subgrid")&&b(j).hide();b(this).html("<a href='javascript:void(0);'><span class='ui-icon "+
+a.p.subGridOptions.plusicon+"'></span></a>").removeClass("sgexpanded").addClass("sgcollapsed")}return false}),o++;!0===a.p.subGridOptions.expandOnLoad&&b(a.rows).filter(".jqgrow").each(function(a,c){b(c.cells[0]).click()});a.subGridXml=function(a,b){l(a,b)};a.subGridJson=function(a,b){p(a,b)}}})},expandSubGridRow:function(e){return this.each(function(){if((this.grid||e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);c&&(c=b("td.sgcollapsed",c)[0])&&b(c).trigger("click")}})},collapseSubGridRow:function(e){return this.each(function(){if((this.grid||
+e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);c&&(c=b("td.sgexpanded",c)[0])&&b(c).trigger("click")}})},toggleSubGridRow:function(e){return this.each(function(){if((this.grid||e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);if(c){var a=b("td.sgcollapsed",c)[0];a?b(a).trigger("click"):(a=b("td.sgexpanded",c)[0])&&b(a).trigger("click")}}})}})})(jQuery);
+(function(b){b.extend(b.jgrid,{template:function(a){var d=b.makeArray(arguments).slice(1),e=1;void 0===a&&(a="");return a.replace(/\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,function(a,c){if(isNaN(parseInt(c,10))){for(var b=d[e],g=b.length;g--;)if(c===b[g].nm)return b[g].v;e++}else return e++,d[parseInt(c,10)]})}});b.jgrid.extend({groupingSetup:function(){return this.each(function(){var a=this.p.groupingView;if(null!==a&&("object"===typeof a||b.isFunction(a)))if(a.groupField.length){"undefined"===
+typeof a.visibiltyOnNextGrouping&&(a.visibiltyOnNextGrouping=[]);a.lastvalues=[];a.groups=[];a.counters=[];for(var d=0;d<a.groupField.length;d++)a.groupOrder[d]||(a.groupOrder[d]="asc"),a.groupText[d]||(a.groupText[d]="{0}"),"boolean"!==typeof a.groupColumnShow[d]&&(a.groupColumnShow[d]=!0),"boolean"!==typeof a.groupSummary[d]&&(a.groupSummary[d]=!1),!0===a.groupColumnShow[d]?(a.visibiltyOnNextGrouping[d]=!0,b(this).jqGrid("showCol",a.groupField[d])):(a.visibiltyOnNextGrouping[d]=b("#"+b.jgrid.jqID(this.p.id+
+"_"+a.groupField[d])).is(":visible"),b(this).jqGrid("hideCol",a.groupField[d]));a.summary=[];for(var d=this.p.colModel,e=0,f=d.length;e<f;e++)d[e].summaryType&&a.summary.push({nm:d[e].name,st:d[e].summaryType,v:"",sr:d[e].summaryRound,srt:d[e].summaryRoundType||"round"})}else this.p.grouping=!1;else this.p.grouping=!1})},groupingPrepare:function(a,d,e,f){this.each(function(){for(var c=this.p.groupingView,h=this,g=c.groupField.length,k,j,p=0,i=0;i<g;i++)k=c.groupField[i],j=e[k],void 0!==j&&(0===f?
+(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,c.counters[i]={cnt:1,pos:c.groups.length-1,summary:b.extend(!0,[],c.summary)}):"object"!==typeof j&&c.lastvalues[i]!==j?(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,p=1,c.counters[i]={cnt:1,pos:c.groups.length-1,summary:b.extend(!0,[],c.summary)}):1===p?(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,c.counters[i]={cnt:1,pos:c.groups.length-
+1,summary:b.extend(!0,[],c.summary)}):(c.counters[i].cnt+=1,c.groups[c.counters[i].pos].cnt=c.counters[i].cnt),b.each(c.counters[i].summary,function(){this.v=b.isFunction(this.st)?this.st.call(h,this.v,this.nm,e):b(h).jqGrid("groupingCalculations.handler",this.st,this.v,this.nm,this.sr,this.srt,e)}),c.groups[c.counters[i].pos].summary=c.counters[i].summary);d.push(a)});return d},groupingToggle:function(a){this.each(function(){var d=this.p.groupingView,e=a.split("_"),f=parseInt(e[e.length-2],10);e.splice(e.length-
+2,2);var e=e.join("_"),c=d.minusicon,h=d.plusicon,g=b("#"+b.jgrid.jqID(a)),g=g.length?g[0].nextSibling:null,k=b("#"+b.jgrid.jqID(a)+" span.tree-wrap-"+this.p.direction),j=!1;if(k.hasClass(c)){if(d.showSummaryOnHide){if(g)for(;g&&!b(g).hasClass("jqfoot");)b(g).hide(),g=g.nextSibling}else if(g)for(;g&&!b(g).hasClass(e+"_"+(""+f))&&!b(g).hasClass(e+"_"+(""+(f-1)));)b(g).hide(),g=g.nextSibling;k.removeClass(c).addClass(h);j=!0}else{if(g)for(;g&&!b(g).hasClass(e+"_"+(""+f))&&!b(g).hasClass(e+"_"+(""+(f-
+1)));)b(g).show(),g=g.nextSibling;k.removeClass(h).addClass(c)}b(this).triggerHandler("jqGridGroupingClickGroup",[a,j]);b.isFunction(this.p.onClickGroup)&&this.p.onClickGroup.call(this,a,j)});return!1},groupingRender:function(a,d){return this.each(function(){function e(a,c,b){if(0===c)return b[a];var d=b[a].idx;if(0===d)return b[a];for(;0<=a;a--)if(b[a].idx===d-c)return b[a]}var f=this,c=f.p.groupingView,h="",g="",k,j,p=c.groupCollapse?c.plusicon:c.minusicon,i,w=[],x=c.groupField.length,p=p+(" tree-wrap-"+
+f.p.direction);b.each(f.p.colModel,function(a,b){for(var d=0;d<x;d++)if(c.groupField[d]===b.name){w[d]=a;break}});var s=0,y=c.groupSummary;y.reverse();b.each(c.groups,function(r,l){s++;j=f.p.id+"ghead_"+l.idx;k=j+"_"+r;g="<span style='cursor:pointer;' class='ui-icon "+p+"' onclick=\"jQuery('#"+b.jgrid.jqID(f.p.id)+"').jqGrid('groupingToggle','"+k+"');return false;\"></span>";try{i=f.formatter(k,l.value,w[l.idx],l.value)}catch(C){i=l.value}h+='<tr id="'+k+'" role="row" class= "ui-widget-content jqgroup ui-row-'+
+f.p.direction+" "+j+'"><td style="padding-left:'+12*l.idx+'px;" colspan="'+d+'">'+g+b.jgrid.template(c.groupText[l.idx],i,l.cnt,l.summary)+"</td></tr>";if(x-1===l.idx){for(var m=c.groups[r+1],o=void 0!==m?c.groups[r+1].startRow:a.length,t=l.startRow;t<o;t++)h+=a[t].join("");var q;if(void 0!==m){for(q=0;q<c.groupField.length&&m.dataIndex!==c.groupField[q];q++);s=c.groupField.length-q}for(m=0;m<s;m++)if(y[m]){o="";c.groupCollapse&&!c.showSummaryOnHide&&(o=' style="display:none;"');h+="<tr"+o+' role="row" class="ui-widget-content jqfoot ui-row-'+
+f.p.direction+'">';for(var o=e(r,m,c.groups),u=f.p.colModel,v,z=o.cnt,n=0;n<d;n++){var A="<td "+f.formatCol(n,1,"")+">&#160;</td>",B="{0}";b.each(o.summary,function(){if(this.nm===u[n].name){u[n].summaryTpl&&(B=u[n].summaryTpl);"avg"===this.st.toLowerCase()&&(this.v&&0<z)&&(this.v/=z);try{v=f.formatter("",this.v,n,this)}catch(a){v=this.v}A="<td "+f.formatCol(n,1,"")+">"+b.jgrid.format(B,v)+"</td>";return!1}});h+=A}h+="</tr>"}s=q}});b("#"+b.jgrid.jqID(f.p.id)+" tbody:first").append(h);h=null})},groupingGroupBy:function(a,
+d){return this.each(function(){"string"===typeof a&&(a=[a]);var e=this.p.groupingView;this.p.grouping=!0;"undefined"===typeof e.visibiltyOnNextGrouping&&(e.visibiltyOnNextGrouping=[]);var f;for(f=0;f<e.groupField.length;f++)!e.groupColumnShow[f]&&e.visibiltyOnNextGrouping[f]&&b(this).jqGrid("showCol",e.groupField[f]);for(f=0;f<a.length;f++)e.visibiltyOnNextGrouping[f]=b("#"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(a[f])).is(":visible");this.p.groupingView=b.extend(this.p.groupingView,d||{});e.groupField=
+a;b(this).trigger("reloadGrid")})},groupingRemove:function(a){return this.each(function(){"undefined"===typeof a&&(a=!0);this.p.grouping=!1;if(!0===a){for(var d=this.p.groupingView,e=0;e<d.groupField.length;e++)!d.groupColumnShow[e]&&d.visibiltyOnNextGrouping[e]&&b(this).jqGrid("showCol",d.groupField);b("tr.jqgroup, tr.jqfoot","#"+b.jgrid.jqID(this.p.id)+" tbody:first").remove();b("tr.jqgrow:hidden","#"+b.jgrid.jqID(this.p.id)+" tbody:first").show()}else b(this).trigger("reloadGrid")})},groupingCalculations:{handler:function(a,
+b,e,f,c,h){var g={sum:function(){return parseFloat(b||0)+parseFloat(h[e]||0)},min:function(){return""===b?parseFloat(h[e]||0):Math.min(parseFloat(b),parseFloat(h[e]||0))},max:function(){return""===b?parseFloat(h[e]||0):Math.max(parseFloat(b),parseFloat(h[e]||0))},count:function(){""===b&&(b=0);return h.hasOwnProperty(e)?b+1:0},avg:function(){return g.sum()}};if(!g[a])throw"jqGrid Grouping No such method: "+a;a=g[a]();null!=f&&("fixed"==c?a=a.toFixed(f):(f=Math.pow(10,f),a=Math.round(a*f)/f));return a}}})})(jQuery);
+(function(d){d.jgrid.extend({setTreeNode:function(a,c){return this.each(function(){var b=this;if(b.grid&&b.p.treeGrid)for(var e=b.p.expColInd,g=b.p.treeReader.expanded_field,h=b.p.treeReader.leaf_field,f=b.p.treeReader.level_field,l=b.p.treeReader.icon_field,j=b.p.treeReader.loaded,i,p,m,k;a<c;)k=b.p.data[b.p._index[b.rows[a].id]],"nested"==b.p.treeGridModel&&!k[h]&&(i=parseInt(k[b.p.treeReader.left_field],10),p=parseInt(k[b.p.treeReader.right_field],10),k[h]=p===i+1?"true":"false",b.rows[a].cells[b.p._treeleafpos].innerHTML=
+k[h]),i=parseInt(k[f],10),0===b.p.tree_root_level?(m=i+1,p=i):(m=i,p=i-1),m="<div class='tree-wrap tree-wrap-"+b.p.direction+"' style='width:"+18*m+"px;'>",m+="<div style='"+("rtl"==b.p.direction?"right:":"left:")+18*p+"px;' class='ui-icon ",void 0!==k[j]&&(k[j]="true"==k[j]||!0===k[j]?!0:!1),"true"==k[h]||!0===k[h]?(m+=(void 0!==k[l]&&""!==k[l]?k[l]:b.p.treeIcons.leaf)+" tree-leaf treeclick",k[h]=!0,p="leaf"):(k[h]=!1,p=""),k[g]=("true"==k[g]||!0===k[g]?!0:!1)&&k[j],m=!1===k[g]?m+(!0===k[h]?"'":
+b.p.treeIcons.plus+" tree-plus treeclick'"):m+(!0===k[h]?"'":b.p.treeIcons.minus+" tree-minus treeclick'"),m+="></div></div>",d(b.rows[a].cells[e]).wrapInner("<span class='cell-wrapper"+p+"'></span>").prepend(m),i!==parseInt(b.p.tree_root_level,10)&&((k=(k=d(b).jqGrid("getNodeParent",k))&&k.hasOwnProperty(g)?k[g]:!0)||d(b.rows[a]).css("display","none")),d(b.rows[a].cells[e]).find("div.treeclick").bind("click",function(a){a=d(a.target||a.srcElement,b.rows).closest("tr.jqgrow")[0].id;a=b.p._index[a];
+if(!b.p.data[a][h])if(b.p.data[a][g]){d(b).jqGrid("collapseRow",b.p.data[a]);d(b).jqGrid("collapseNode",b.p.data[a])}else{d(b).jqGrid("expandRow",b.p.data[a]);d(b).jqGrid("expandNode",b.p.data[a])}return false}),!0===b.p.ExpandColClick&&d(b.rows[a].cells[e]).find("span.cell-wrapper").css("cursor","pointer").bind("click",function(a){var a=d(a.target||a.srcElement,b.rows).closest("tr.jqgrow")[0].id,c=b.p._index[a];if(!b.p.data[c][h])if(b.p.data[c][g]){d(b).jqGrid("collapseRow",b.p.data[c]);d(b).jqGrid("collapseNode",
+b.p.data[c])}else{d(b).jqGrid("expandRow",b.p.data[c]);d(b).jqGrid("expandNode",b.p.data[c])}d(b).jqGrid("setSelection",a);return false}),a++})},setTreeGrid:function(){return this.each(function(){var a=this,c=0,b,e=!1,g,h=[];if(a.p.treeGrid){a.p.treedatatype||d.extend(a.p,{treedatatype:a.p.datatype});a.p.subGrid=!1;a.p.altRows=!1;a.p.pgbuttons=!1;a.p.pginput=!1;a.p.gridview=!0;null===a.p.rowTotal&&(a.p.rowNum=1E4);a.p.multiselect=!1;a.p.rowList=[];a.p.expColInd=0;b="ui-icon-triangle-1-"+("rtl"==a.p.direction?
+"w":"e");a.p.treeIcons=d.extend({plus:b,minus:"ui-icon-triangle-1-s",leaf:"ui-icon-radio-off"},a.p.treeIcons||{});"nested"==a.p.treeGridModel?a.p.treeReader=d.extend({level_field:"level",left_field:"lft",right_field:"rgt",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},a.p.treeReader):"adjacency"==a.p.treeGridModel&&(a.p.treeReader=d.extend({level_field:"level",parent_id_field:"parent",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},
+a.p.treeReader));for(g in a.p.colModel)if(a.p.colModel.hasOwnProperty(g)){b=a.p.colModel[g].name;b==a.p.ExpandColumn&&!e&&(e=!0,a.p.expColInd=c);c++;for(var f in a.p.treeReader)a.p.treeReader[f]==b&&h.push(b)}d.each(a.p.treeReader,function(b,e){if(e&&d.inArray(e,h)===-1){if(b==="leaf_field")a.p._treeleafpos=c;c++;a.p.colNames.push(e);a.p.colModel.push({name:e,width:1,hidden:true,sortable:false,resizable:false,hidedlg:true,editable:true,search:false})}})}})},expandRow:function(a){this.each(function(){var c=
+this;if(c.grid&&c.p.treeGrid){var b=d(c).jqGrid("getNodeChildren",a),e=c.p.treeReader.expanded_field,g=c.rows;d(b).each(function(){var a=d.jgrid.getAccessor(this,c.p.localReader.id);d(g.namedItem(a)).css("display","");this[e]&&d(c).jqGrid("expandRow",this)})}})},collapseRow:function(a){this.each(function(){var c=this;if(c.grid&&c.p.treeGrid){var b=d(c).jqGrid("getNodeChildren",a),e=c.p.treeReader.expanded_field,g=c.rows;d(b).each(function(){var a=d.jgrid.getAccessor(this,c.p.localReader.id);d(g.namedItem(a)).css("display",
+"none");this[e]&&d(c).jqGrid("collapseRow",this)})}})},getRootNodes:function(){var a=[];this.each(function(){var c=this;if(c.grid&&c.p.treeGrid)switch(c.p.treeGridModel){case "nested":var b=c.p.treeReader.level_field;d(c.p.data).each(function(){parseInt(this[b],10)===parseInt(c.p.tree_root_level,10)&&a.push(this)});break;case "adjacency":var e=c.p.treeReader.parent_id_field;d(c.p.data).each(function(){(null===this[e]||"null"==(""+this[e]).toLowerCase())&&a.push(this)})}});return a},getNodeDepth:function(a){var c=
+null;this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":c=parseInt(a[this.p.treeReader.level_field],10)-parseInt(this.p.tree_root_level,10);break;case "adjacency":c=d(this).jqGrid("getNodeAncestors",a).length}});return c},getNodeParent:function(a){var c=null;this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var b=this.p.treeReader.left_field,e=this.p.treeReader.right_field,g=this.p.treeReader.level_field,h=parseInt(a[b],
+10),f=parseInt(a[e],10),l=parseInt(a[g],10);d(this.p.data).each(function(){if(parseInt(this[g],10)===l-1&&parseInt(this[b],10)<h&&parseInt(this[e],10)>f)return c=this,!1});break;case "adjacency":var j=this.p.treeReader.parent_id_field,i=this.p.localReader.id;d(this.p.data).each(function(){if(this[i]==a[j])return c=this,!1})}});return c},getNodeChildren:function(a){var c=[];this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var b=this.p.treeReader.left_field,
+e=this.p.treeReader.right_field,g=this.p.treeReader.level_field,h=parseInt(a[b],10),f=parseInt(a[e],10),l=parseInt(a[g],10);d(this.p.data).each(function(){parseInt(this[g],10)===l+1&&(parseInt(this[b],10)>h&&parseInt(this[e],10)<f)&&c.push(this)});break;case "adjacency":var j=this.p.treeReader.parent_id_field,i=this.p.localReader.id;d(this.p.data).each(function(){this[j]==a[i]&&c.push(this)})}});return c},getFullTreeNode:function(a){var c=[];this.each(function(){var b;if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var e=
+this.p.treeReader.left_field,g=this.p.treeReader.right_field,h=this.p.treeReader.level_field,f=parseInt(a[e],10),l=parseInt(a[g],10),j=parseInt(a[h],10);d(this.p.data).each(function(){parseInt(this[h],10)>=j&&(parseInt(this[e],10)>=f&&parseInt(this[e],10)<=l)&&c.push(this)});break;case "adjacency":if(a){c.push(a);var i=this.p.treeReader.parent_id_field,p=this.p.localReader.id;d(this.p.data).each(function(a){b=c.length;for(a=0;a<b;a++)if(c[a][p]==this[i]){c.push(this);break}})}}});return c},getNodeAncestors:function(a){var c=
+[];this.each(function(){if(this.grid&&this.p.treeGrid)for(var b=d(this).jqGrid("getNodeParent",a);b;)c.push(b),b=d(this).jqGrid("getNodeParent",b)});return c},isVisibleNode:function(a){var c=!0;this.each(function(){if(this.grid&&this.p.treeGrid){var b=d(this).jqGrid("getNodeAncestors",a),e=this.p.treeReader.expanded_field;d(b).each(function(){c=c&&this[e];if(!c)return!1})}});return c},isNodeLoaded:function(a){var c;this.each(function(){if(this.grid&&this.p.treeGrid){var b=this.p.treeReader.leaf_field;
+c=void 0!==a?void 0!==a.loaded?a.loaded:a[b]||0<d(this).jqGrid("getNodeChildren",a).length?!0:!1:!1}});return c},expandNode:function(a){return this.each(function(){if(this.grid&&this.p.treeGrid){var c=this.p.treeReader.expanded_field,b=this.p.treeReader.parent_id_field,e=this.p.treeReader.loaded,g=this.p.treeReader.level_field,h=this.p.treeReader.left_field,f=this.p.treeReader.right_field;if(!a[c]){var l=d.jgrid.getAccessor(a,this.p.localReader.id),j=d("#"+d.jgrid.jqID(l),this.grid.bDiv)[0],i=this.p._index[l];
+d(this).jqGrid("isNodeLoaded",this.p.data[i])?(a[c]=!0,d("div.treeclick",j).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus")):this.grid.hDiv.loading||(a[c]=!0,d("div.treeclick",j).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus"),this.p.treeANode=j.rowIndex,this.p.datatype=this.p.treedatatype,"nested"==this.p.treeGridModel?d(this).jqGrid("setGridParam",{postData:{nodeid:l,n_left:a[h],n_right:a[f],n_level:a[g]}}):
+d(this).jqGrid("setGridParam",{postData:{nodeid:l,parentid:a[b],n_level:a[g]}}),d(this).trigger("reloadGrid"),a[e]=!0,"nested"==this.p.treeGridModel?d(this).jqGrid("setGridParam",{postData:{nodeid:"",n_left:"",n_right:"",n_level:""}}):d(this).jqGrid("setGridParam",{postData:{nodeid:"",parentid:"",n_level:""}}))}}})},collapseNode:function(a){return this.each(function(){if(this.grid&&this.p.treeGrid){var c=this.p.treeReader.expanded_field;a[c]&&(a[c]=!1,c=d.jgrid.getAccessor(a,this.p.localReader.id),
+c=d("#"+d.jgrid.jqID(c),this.grid.bDiv)[0],d("div.treeclick",c).removeClass(this.p.treeIcons.minus+" tree-minus").addClass(this.p.treeIcons.plus+" tree-plus"))}})},SortTree:function(a,c,b,e){return this.each(function(){if(this.grid&&this.p.treeGrid){var g,h,f,l=[],j=this,i;g=d(this).jqGrid("getRootNodes");g=d.jgrid.from(g);g.orderBy(a,c,b,e);i=g.select();g=0;for(h=i.length;g<h;g++)f=i[g],l.push(f),d(this).jqGrid("collectChildrenSortTree",l,f,a,c,b,e);d.each(l,function(a){var b=d.jgrid.getAccessor(this,
+j.p.localReader.id);d("#"+d.jgrid.jqID(j.p.id)+" tbody tr:eq("+a+")").after(d("tr#"+d.jgrid.jqID(b),j.grid.bDiv))});l=i=g=null}})},collectChildrenSortTree:function(a,c,b,e,g,h){return this.each(function(){if(this.grid&&this.p.treeGrid){var f,l,j,i;f=d(this).jqGrid("getNodeChildren",c);f=d.jgrid.from(f);f.orderBy(b,e,g,h);i=f.select();f=0;for(l=i.length;f<l;f++)j=i[f],a.push(j),d(this).jqGrid("collectChildrenSortTree",a,j,b,e,g,h)}})},setTreeRow:function(a,c){var b=!1;this.each(function(){this.grid&&
+this.p.treeGrid&&(b=d(this).jqGrid("setRowData",a,c))});return b},delTreeNode:function(a){return this.each(function(){var c=this.p.localReader.id,b=this.p.treeReader.left_field,e=this.p.treeReader.right_field,g,h,f;if(this.grid&&this.p.treeGrid){var l=this.p._index[a];if(void 0!==l){g=parseInt(this.p.data[l][e],10);h=g-parseInt(this.p.data[l][b],10)+1;l=d(this).jqGrid("getFullTreeNode",this.p.data[l]);if(0<l.length)for(var j=0;j<l.length;j++)d(this).jqGrid("delRowData",l[j][c]);if("nested"===this.p.treeGridModel){c=
+d.jgrid.from(this.p.data).greater(b,g,{stype:"integer"}).select();if(c.length)for(f in c)c.hasOwnProperty(f)&&(c[f][b]=parseInt(c[f][b],10)-h);c=d.jgrid.from(this.p.data).greater(e,g,{stype:"integer"}).select();if(c.length)for(f in c)c.hasOwnProperty(f)&&(c[f][e]=parseInt(c[f][e],10)-h)}}}})},addChildNode:function(a,c,b){var e=this[0];if(b){var g=e.p.treeReader.expanded_field,h=e.p.treeReader.leaf_field,f=e.p.treeReader.level_field,l=e.p.treeReader.parent_id_field,j=e.p.treeReader.left_field,i=e.p.treeReader.right_field,
+p=e.p.treeReader.loaded,m,k,q,s,o;m=0;var r=c,t;if("undefined"===typeof a||null===a){o=e.p.data.length-1;if(0<=o)for(;0<=o;)m=Math.max(m,parseInt(e.p.data[o][e.p.localReader.id],10)),o--;a=m+1}var u=d(e).jqGrid("getInd",c);t=!1;if(void 0===c||null===c||""===c)r=c=null,m="last",s=e.p.tree_root_level,o=e.p.data.length+1;else if(m="after",k=e.p._index[c],q=e.p.data[k],c=q[e.p.localReader.id],s=parseInt(q[f],10)+1,o=d(e).jqGrid("getFullTreeNode",q),o.length?(r=o=o[o.length-1][e.p.localReader.id],o=d(e).jqGrid("getInd",
+r)+1):o=d(e).jqGrid("getInd",c)+1,q[h])t=!0,q[g]=!0,d(e.rows[u]).find("span.cell-wrapperleaf").removeClass("cell-wrapperleaf").addClass("cell-wrapper").end().find("div.tree-leaf").removeClass(e.p.treeIcons.leaf+" tree-leaf").addClass(e.p.treeIcons.minus+" tree-minus"),e.p.data[k][h]=!1,q[p]=!0;k=o+1;b[g]=!1;b[p]=!0;b[f]=s;b[h]=!0;"adjacency"===e.p.treeGridModel&&(b[l]=c);if("nested"===e.p.treeGridModel){var n;if(null!==c){h=parseInt(q[i],10);f=d.jgrid.from(e.p.data);f=f.greaterOrEquals(i,h,{stype:"integer"});
+f=f.select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][j]=f[n][j]>h?parseInt(f[n][j],10)+2:f[n][j],f[n][i]=f[n][i]>=h?parseInt(f[n][i],10)+2:f[n][i]);b[j]=h;b[i]=h+1}else{h=parseInt(d(e).jqGrid("getCol",i,!1,"max"),10);f=d.jgrid.from(e.p.data).greater(j,h,{stype:"integer"}).select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][j]=parseInt(f[n][j],10)+2);f=d.jgrid.from(e.p.data).greater(i,h,{stype:"integer"}).select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][i]=parseInt(f[n][i],
+10)+2);b[j]=h+1;b[i]=h+2}}if(null===c||d(e).jqGrid("isNodeLoaded",q)||t)d(e).jqGrid("addRowData",a,b,m,r),d(e).jqGrid("setTreeNode",o,k);q&&!q[g]&&d(e.rows[u]).find("div.treeclick").click()}}})})(jQuery);
+(function(c){c.jgrid.extend({jqGridImport:function(a){a=c.extend({imptype:"xml",impstring:"",impurl:"",mtype:"GET",impData:{},xmlGrid:{config:"roots>grid",data:"roots>rows"},jsonGrid:{config:"grid",data:"data"},ajaxOptions:{}},a||{});return this.each(function(){var d=this,b=function(a,b){var e=c(b.xmlGrid.config,a)[0],h=c(b.xmlGrid.data,a)[0],f;if(xmlJsonClass.xml2json&&c.jgrid.parse){var e=xmlJsonClass.xml2json(e," "),e=c.jgrid.parse(e),g;for(g in e)e.hasOwnProperty(g)&&(f=e[g]);h?(h=e.grid.datatype,
+e.grid.datatype="xmlstring",e.grid.datastr=a,c(d).jqGrid(f).jqGrid("setGridParam",{datatype:h})):c(d).jqGrid(f)}else alert("xml2json or parse are not present")},g=function(a,b){if(a&&"string"==typeof a){var e=!1;c.jgrid.useJSON&&(c.jgrid.useJSON=!1,e=!0);var f=c.jgrid.parse(a);e&&(c.jgrid.useJSON=!0);e=f[b.jsonGrid.config];if(f=f[b.jsonGrid.data]){var g=e.datatype;e.datatype="jsonstring";e.datastr=f;c(d).jqGrid(e).jqGrid("setGridParam",{datatype:g})}else c(d).jqGrid(e)}};switch(a.imptype){case "xml":c.ajax(c.extend({url:a.impurl,
+type:a.mtype,data:a.impData,dataType:"xml",complete:function(f,g){"success"==g&&(b(f.responseXML,a),c(d).triggerHandler("jqGridImportComplete",[f,a]),c.isFunction(a.importComplete)&&a.importComplete(f))}},a.ajaxOptions));break;case "xmlstring":if(a.impstring&&"string"==typeof a.impstring){var f=c.jgrid.stringToDoc(a.impstring);f&&(b(f,a),c(d).triggerHandler("jqGridImportComplete",[f,a]),c.isFunction(a.importComplete)&&a.importComplete(f),a.impstring=null);f=null}break;case "json":c.ajax(c.extend({url:a.impurl,
+type:a.mtype,data:a.impData,dataType:"json",complete:function(b){try{g(b.responseText,a),c(d).triggerHandler("jqGridImportComplete",[b,a]),c.isFunction(a.importComplete)&&a.importComplete(b)}catch(f){}}},a.ajaxOptions));break;case "jsonstring":a.impstring&&"string"==typeof a.impstring&&(g(a.impstring,a),c(d).triggerHandler("jqGridImportComplete",[a.impstring,a]),c.isFunction(a.importComplete)&&a.importComplete(a.impstring),a.impstring=null)}})},jqGridExport:function(a){var a=c.extend({exptype:"xmlstring",
+root:"grid",ident:"\t"},a||{}),d=null;this.each(function(){if(this.grid){var b=c.extend(!0,{},c(this).jqGrid("getGridParam"));b.rownumbers&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.multiselect&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.subGrid&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.knv=null;if(b.treeGrid)for(var g in b.treeReader)b.treeReader.hasOwnProperty(g)&&(b.colNames.splice(b.colNames.length-1),b.colModel.splice(b.colModel.length-1));switch(a.exptype){case "xmlstring":d=
+"<"+a.root+">"+xmlJsonClass.json2xml(b,a.ident)+"</"+a.root+">";break;case "jsonstring":d="{"+xmlJsonClass.toJson(b,a.root,a.ident,!1)+"}",void 0!==b.postData.filters&&(d=d.replace(/filters":"/,'filters":'),d=d.replace(/}]}"/,"}]}"))}}});return d},excelExport:function(a){a=c.extend({exptype:"remote",url:null,oper:"oper",tag:"excel",exportOptions:{}},a||{});return this.each(function(){if(this.grid){var d;"remote"==a.exptype&&(d=c.extend({},this.p.postData),d[a.oper]=a.tag,d=jQuery.param(d),d=-1!=a.url.indexOf("?")?
+a.url+"&"+d:a.url+"?"+d,window.location=d)}})}})})(jQuery);
+var xmlJsonClass={xml2json:function(a,b){9===a.nodeType&&(a=a.documentElement);var g=this.toJson(this.toObj(this.removeWhite(a)),a.nodeName,"\t");return"{\n"+b+(b?g.replace(/\t/g,b):g.replace(/\t|\n/g,""))+"\n}"},json2xml:function(a,b){var g=function(a,b,e){var d="",f,i;if(a instanceof Array)if(0===a.length)d+=e+"<"+b+">__EMPTY_ARRAY_</"+b+">\n";else{f=0;for(i=a.length;f<i;f+=1)var l=e+g(a[f],b,e+"\t")+"\n",d=d+l}else if("object"===typeof a){f=!1;d+=e+"<"+b;for(i in a)a.hasOwnProperty(i)&&("@"===
+i.charAt(0)?d+=" "+i.substr(1)+'="'+a[i].toString()+'"':f=!0);d+=f?">":"/>";if(f){for(i in a)a.hasOwnProperty(i)&&("#text"===i?d+=a[i]:"#cdata"===i?d+="<![CDATA["+a[i]+"]]\>":"@"!==i.charAt(0)&&(d+=g(a[i],i,e+"\t")));d+=("\n"===d.charAt(d.length-1)?e:"")+"</"+b+">"}}else"function"===typeof a?d+=e+"<"+b+"><![CDATA["+a+"]]\></"+b+">":(void 0===a&&(a=""),d='""'===a.toString()||0===a.toString().length?d+(e+"<"+b+">__EMPTY_STRING_</"+b+">"):d+(e+"<"+b+">"+a.toString()+"</"+b+">"));return d},f="",e;for(e in a)a.hasOwnProperty(e)&&
+(f+=g(a[e],e,""));return b?f.replace(/\t/g,b):f.replace(/\t|\n/g,"")},toObj:function(a){var b={},g=/function/i;if(1===a.nodeType){if(a.attributes.length){var f;for(f=0;f<a.attributes.length;f+=1)b["@"+a.attributes[f].nodeName]=(a.attributes[f].nodeValue||"").toString()}if(a.firstChild){var e=f=0,h=!1,c;for(c=a.firstChild;c;c=c.nextSibling)1===c.nodeType?h=!0:3===c.nodeType&&c.nodeValue.match(/[^ \f\n\r\t\v]/)?f+=1:4===c.nodeType&&(e+=1);if(h)if(2>f&&2>e){this.removeWhite(a);for(c=a.firstChild;c;c=
+c.nextSibling)3===c.nodeType?b["#text"]=this.escape(c.nodeValue):4===c.nodeType?g.test(c.nodeValue)?b[c.nodeName]=[b[c.nodeName],c.nodeValue]:b["#cdata"]=this.escape(c.nodeValue):b[c.nodeName]?b[c.nodeName]instanceof Array?b[c.nodeName][b[c.nodeName].length]=this.toObj(c):b[c.nodeName]=[b[c.nodeName],this.toObj(c)]:b[c.nodeName]=this.toObj(c)}else a.attributes.length?b["#text"]=this.escape(this.innerXml(a)):b=this.escape(this.innerXml(a));else if(f)a.attributes.length?b["#text"]=this.escape(this.innerXml(a)):
+(b=this.escape(this.innerXml(a)),"__EMPTY_ARRAY_"===b?b="[]":"__EMPTY_STRING_"===b&&(b=""));else if(e)if(1<e)b=this.escape(this.innerXml(a));else for(c=a.firstChild;c;c=c.nextSibling)if(g.test(a.firstChild.nodeValue)){b=a.firstChild.nodeValue;break}else b["#cdata"]=this.escape(c.nodeValue)}!a.attributes.length&&!a.firstChild&&(b=null)}else 9===a.nodeType?b=this.toObj(a.documentElement):alert("unhandled node type: "+a.nodeType);return b},toJson:function(a,b,g,f){void 0===f&&(f=!0);var e=b?'"'+b+'"':
+"",h="\t",c="\n";f||(c=h="");if("[]"===a)e+=b?":[]":"[]";else if(a instanceof Array){var j,d,k=[];d=0;for(j=a.length;d<j;d+=1)k[d]=this.toJson(a[d],"",g+h,f);e+=(b?":[":"[")+(1<k.length?c+g+h+k.join(","+c+g+h)+c+g:k.join(""))+"]"}else if(null===a)e+=(b&&":")+"null";else if("object"===typeof a){j=[];for(d in a)a.hasOwnProperty(d)&&(j[j.length]=this.toJson(a[d],d,g+h,f));e+=(b?":{":"{")+(1<j.length?c+g+h+j.join(","+c+g+h)+c+g:j.join(""))+"}"}else e="string"===typeof a?e+((b&&":")+'"'+a.replace(/\\/g,
+"\\\\").replace(/\"/g,'\\"')+'"'):e+((b&&":")+a.toString());return e},innerXml:function(a){var b="";if("innerHTML"in a)b=a.innerHTML;else for(var g=function(a){var b="",h;if(1===a.nodeType){b+="<"+a.nodeName;for(h=0;h<a.attributes.length;h+=1)b+=" "+a.attributes[h].nodeName+'="'+(a.attributes[h].nodeValue||"").toString()+'"';if(a.firstChild){b+=">";for(h=a.firstChild;h;h=h.nextSibling)b+=g(h);b+="</"+a.nodeName+">"}else b+="/>"}else 3===a.nodeType?b+=a.nodeValue:4===a.nodeType&&(b+="<![CDATA["+a.nodeValue+
+"]]\>");return b},a=a.firstChild;a;a=a.nextSibling)b+=g(a);return b},escape:function(a){return a.replace(/[\\]/g,"\\\\").replace(/[\"]/g,'\\"').replace(/[\n]/g,"\\n").replace(/[\r]/g,"\\r")},removeWhite:function(a){a.normalize();var b;for(b=a.firstChild;b;)if(3===b.nodeType)if(b.nodeValue.match(/[^ \f\n\r\t\v]/))b=b.nextSibling;else{var g=b.nextSibling;a.removeChild(b);b=g}else 1===b.nodeType&&this.removeWhite(b),b=b.nextSibling;return a}};
+function tableToGrid(j,k){jQuery(j).each(function(){if(!this.grid){jQuery(this).width("99%");var b=jQuery(this).width(),c=jQuery("tr td:first-child input[type=checkbox]:first",jQuery(this)),a=jQuery("tr td:first-child input[type=radio]:first",jQuery(this)),c=0<c.length,a=!c&&0<a.length,i=c||a,d=[],e=[];jQuery("th",jQuery(this)).each(function(){0===d.length&&i?(d.push({name:"__selection__",index:"__selection__",width:0,hidden:!0}),e.push("__selection__")):(d.push({name:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(" ").join("_"),
+index:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(" ").join("_"),width:jQuery(this).width()||150}),e.push(jQuery(this).html()))});var f=[],g=[],h=[];jQuery("tbody > tr",jQuery(this)).each(function(){var b={},a=0;jQuery("td",jQuery(this)).each(function(){if(0===a&&i){var c=jQuery("input",jQuery(this)),e=c.attr("value");g.push(e||f.length);c.is(":checked")&&h.push(e);b[d[a].name]=c.attr("value")}else b[d[a].name]=jQuery(this).html();a++});0<a&&f.push(b)});
+jQuery(this).empty();jQuery(this).addClass("scroll");jQuery(this).jqGrid(jQuery.extend({datatype:"local",width:b,colNames:e,colModel:d,multiselect:c},k||{}));for(b=0;b<f.length;b++)a=null,0<g.length&&(a=g[b])&&a.replace&&(a=encodeURIComponent(a).replace(/[.\-%]/g,"_")),null===a&&(a=b+1),jQuery(this).jqGrid("addRowData",a,f[b]);for(b=0;b<h.length;b++)jQuery(this).jqGrid("setSelection",h[b])}})};
+(function(b){b.browser.msie&&8==b.browser.version&&(b.expr[":"].hidden=function(b){return 0===b.offsetWidth||0===b.offsetHeight||"none"==b.style.display});b.jgrid._multiselect=!1;if(b.ui&&b.ui.multiselect){if(b.ui.multiselect.prototype._setSelected){var m=b.ui.multiselect.prototype._setSelected;b.ui.multiselect.prototype._setSelected=function(a,e){var c=m.call(this,a,e);if(e&&this.selectedList){var d=this.element;this.selectedList.find("li").each(function(){b(this).data("optionLink")&&b(this).data("optionLink").remove().appendTo(d)})}return c}}b.ui.multiselect.prototype.destroy&&
+(b.ui.multiselect.prototype.destroy=function(){this.element.show();this.container.remove();b.Widget===void 0?b.widget.prototype.destroy.apply(this,arguments):b.Widget.prototype.destroy.apply(this,arguments)});b.jgrid._multiselect=!0}b.jgrid.extend({sortableColumns:function(a){return this.each(function(){function e(){c.p.disableClick=true}var c=this,d=b.jgrid.jqID(c.p.id),d={tolerance:"pointer",axis:"x",scrollSensitivity:"1",items:">th:not(:has(#jqgh_"+d+"_cb,#jqgh_"+d+"_rn,#jqgh_"+d+"_subgrid),:hidden)",
+placeholder:{element:function(a){return b(document.createElement(a[0].nodeName)).addClass(a[0].className+" ui-sortable-placeholder ui-state-highlight").removeClass("ui-sortable-helper")[0]},update:function(b,a){a.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));a.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}},update:function(a,
+g){var d=b(g.item).parent(),d=b(">th",d),e={},i=c.p.id+"_";b.each(c.p.colModel,function(b){e[this.name]=b});var h=[];d.each(function(){var a=b(">div",this).get(0).id.replace(/^jqgh_/,"").replace(i,"");a in e&&h.push(e[a])});b(c).jqGrid("remapColumns",h,true,true);b.isFunction(c.p.sortable.update)&&c.p.sortable.update(h);setTimeout(function(){c.p.disableClick=false},50)}};if(c.p.sortable.options)b.extend(d,c.p.sortable.options);else if(b.isFunction(c.p.sortable))c.p.sortable={update:c.p.sortable};
+if(d.start){var g=d.start;d.start=function(b,a){e();g.call(this,b,a)}}else d.start=e;if(c.p.sortable.exclude)d.items=d.items+(":not("+c.p.sortable.exclude+")");a.sortable(d).data("sortable").floating=true})},columnChooser:function(a){function e(a,c){a&&(typeof a=="string"?b.fn[a]&&b.fn[a].apply(c,b.makeArray(arguments).slice(2)):b.isFunction(a)&&a.apply(c,b.makeArray(arguments).slice(2)))}var c=this;if(!b("#colchooser_"+b.jgrid.jqID(c[0].p.id)).length){var d=b('<div id="colchooser_'+c[0].p.id+'" style="position:relative;overflow:hidden"><div><select multiple="multiple"></select></div></div>'),
+g=b("select",d),a=b.extend({width:420,height:240,classname:null,done:function(b){b&&c.jqGrid("remapColumns",b,true)},msel:"multiselect",dlog:"dialog",dialog_opts:{minWidth:470},dlog_opts:function(a){var c={};c[a.bSubmit]=function(){a.apply_perm();a.cleanup(false)};c[a.bCancel]=function(){a.cleanup(true)};return b.extend(true,{buttons:c,close:function(){a.cleanup(true)},modal:a.modal?a.modal:false,resizable:a.resizable?a.resizable:true,width:a.width+20},a.dialog_opts||{})},apply_perm:function(){b("option",
+g).each(function(){this.selected?c.jqGrid("showCol",k[this.value].name):c.jqGrid("hideCol",k[this.value].name)});var d=[];b("option:selected",g).each(function(){d.push(parseInt(this.value,10))});b.each(d,function(){delete f[k[parseInt(this,10)].name]});b.each(f,function(){var b=parseInt(this,10);var a=d,c=b;if(c>=0){var g=a.slice(),e=g.splice(c,Math.max(a.length-c,c));if(c>a.length)c=a.length;g[c]=b;d=g.concat(e)}else d=void 0});a.done&&a.done.call(c,d)},cleanup:function(b){e(a.dlog,d,"destroy");
+e(a.msel,g,"destroy");d.remove();b&&a.done&&a.done.call(c)},msel_opts:{}},b.jgrid.col,a||{});if(b.ui&&b.ui.multiselect&&a.msel=="multiselect"){if(!b.jgrid._multiselect){alert("Multiselect plugin loaded after jqGrid. Please load the plugin before the jqGrid!");return}a.msel_opts=b.extend(b.ui.multiselect.defaults,a.msel_opts)}a.caption&&d.attr("title",a.caption);if(a.classname){d.addClass(a.classname);g.addClass(a.classname)}if(a.width){b(">div",d).css({width:a.width,margin:"0 auto"});g.css("width",
+a.width)}if(a.height){b(">div",d).css("height",a.height);g.css("height",a.height-10)}var k=c.jqGrid("getGridParam","colModel"),p=c.jqGrid("getGridParam","colNames"),f={},j=[];g.empty();b.each(k,function(b){f[this.name]=b;this.hidedlg?this.hidden||j.push(b):g.append("<option value='"+b+"' "+(this.hidden?"":"selected='selected'")+">"+jQuery.jgrid.stripHtml(p[b])+"</option>")});var i=b.isFunction(a.dlog_opts)?a.dlog_opts.call(c,a):a.dlog_opts;e(a.dlog,d,i);i=b.isFunction(a.msel_opts)?a.msel_opts.call(c,
+a):a.msel_opts;e(a.msel,g,i)}},sortableRows:function(a){return this.each(function(){var e=this;if(e.grid&&!e.p.treeGrid&&b.fn.sortable){a=b.extend({cursor:"move",axis:"y",items:".jqgrow"},a||{});if(a.start&&b.isFunction(a.start)){a._start_=a.start;delete a.start}else a._start_=false;if(a.update&&b.isFunction(a.update)){a._update_=a.update;delete a.update}else a._update_=false;a.start=function(c,d){b(d.item).css("border-width","0px");b("td",d.item).each(function(b){this.style.width=e.grid.cols[b].style.width});
+if(e.p.subGrid){var g=b(d.item).attr("id");try{b(e).jqGrid("collapseSubGridRow",g)}catch(k){}}a._start_&&a._start_.apply(this,[c,d])};a.update=function(c,d){b(d.item).css("border-width","");e.p.rownumbers===true&&b("td.jqgrid-rownum",e.rows).each(function(a){b(this).html(a+1+(parseInt(e.p.page,10)-1)*parseInt(e.p.rowNum,10))});a._update_&&a._update_.apply(this,[c,d])};b("tbody:first",e).sortable(a);b("tbody:first",e).disableSelection()}})},gridDnD:function(a){return this.each(function(){function e(){var a=
+b.data(c,"dnd");b("tr.jqgrow:not(.ui-draggable)",c).draggable(b.isFunction(a.drag)?a.drag.call(b(c),a):a.drag)}var c=this;if(c.grid&&!c.p.treeGrid&&b.fn.draggable&&b.fn.droppable){b("#jqgrid_dnd").html()===null&&b("body").append("<table id='jqgrid_dnd' class='ui-jqgrid-dnd'></table>");if(typeof a=="string"&&a=="updateDnD"&&c.p.jqgdnd===true)e();else{a=b.extend({drag:function(a){return b.extend({start:function(d,e){if(c.p.subGrid){var f=b(e.helper).attr("id");try{b(c).jqGrid("collapseSubGridRow",f)}catch(j){}}for(f=
+0;f<b.data(c,"dnd").connectWith.length;f++)b(b.data(c,"dnd").connectWith[f]).jqGrid("getGridParam","reccount")=="0"&&b(b.data(c,"dnd").connectWith[f]).jqGrid("addRowData","jqg_empty_row",{});e.helper.addClass("ui-state-highlight");b("td",e.helper).each(function(b){this.style.width=c.grid.headers[b].width+"px"});a.onstart&&b.isFunction(a.onstart)&&a.onstart.call(b(c),d,e)},stop:function(d,e){if(e.helper.dropped&&!a.dragcopy){var f=b(e.helper).attr("id");f===void 0&&(f=b(this).attr("id"));b(c).jqGrid("delRowData",
+f)}for(f=0;f<b.data(c,"dnd").connectWith.length;f++)b(b.data(c,"dnd").connectWith[f]).jqGrid("delRowData","jqg_empty_row");a.onstop&&b.isFunction(a.onstop)&&a.onstop.call(b(c),d,e)}},a.drag_opts||{})},drop:function(a){return b.extend({accept:function(a){if(!b(a).hasClass("jqgrow"))return a;a=b(a).closest("table.ui-jqgrid-btable");if(a.length>0&&b.data(a[0],"dnd")!==void 0){a=b.data(a[0],"dnd").connectWith;return b.inArray("#"+b.jgrid.jqID(this.id),a)!=-1?true:false}return false},drop:function(d,e){if(b(e.draggable).hasClass("jqgrow")){var f=
+b(e.draggable).attr("id"),f=e.draggable.parent().parent().jqGrid("getRowData",f);if(!a.dropbyname){var j=0,i={},h,n=b("#"+b.jgrid.jqID(this.id)).jqGrid("getGridParam","colModel");try{for(var o in f){h=n[j].name;h=="cb"||(h=="rn"||h=="subgrid")||f.hasOwnProperty(o)&&n[j]&&(i[h]=f[o]);j++}f=i}catch(m){}}e.helper.dropped=true;if(a.beforedrop&&b.isFunction(a.beforedrop)){h=a.beforedrop.call(this,d,e,f,b("#"+b.jgrid.jqID(c.p.id)),b(this));typeof h!="undefined"&&(h!==null&&typeof h=="object")&&(f=h)}if(e.helper.dropped){var l;
+if(a.autoid)if(b.isFunction(a.autoid))l=a.autoid.call(this,f);else{l=Math.ceil(Math.random()*1E3);l=a.autoidprefix+l}b("#"+b.jgrid.jqID(this.id)).jqGrid("addRowData",l,f,a.droppos)}a.ondrop&&b.isFunction(a.ondrop)&&a.ondrop.call(this,d,e,f)}}},a.drop_opts||{})},onstart:null,onstop:null,beforedrop:null,ondrop:null,drop_opts:{activeClass:"ui-state-active",hoverClass:"ui-state-hover"},drag_opts:{revert:"invalid",helper:"clone",cursor:"move",appendTo:"#jqgrid_dnd",zIndex:5E3},dragcopy:false,dropbyname:false,
+droppos:"first",autoid:true,autoidprefix:"dnd_"},a||{});if(a.connectWith){a.connectWith=a.connectWith.split(",");a.connectWith=b.map(a.connectWith,function(a){return b.trim(a)});b.data(c,"dnd",a);c.p.reccount!="0"&&!c.p.jqgdnd&&e();c.p.jqgdnd=true;for(var d=0;d<a.connectWith.length;d++)b(a.connectWith[d]).droppable(b.isFunction(a.drop)?a.drop.call(b(c),a):a.drop)}}}})},gridResize:function(a){return this.each(function(){var e=this,c=b.jgrid.jqID(e.p.id);if(e.grid&&b.fn.resizable){a=b.extend({},a||
+{});if(a.alsoResize){a._alsoResize_=a.alsoResize;delete a.alsoResize}else a._alsoResize_=false;if(a.stop&&b.isFunction(a.stop)){a._stop_=a.stop;delete a.stop}else a._stop_=false;a.stop=function(d,g){b(e).jqGrid("setGridParam",{height:b("#gview_"+c+" .ui-jqgrid-bdiv").height()});b(e).jqGrid("setGridWidth",g.size.width,a.shrinkToFit);a._stop_&&a._stop_.call(e,d,g)};a.alsoResize=a._alsoResize_?eval("("+("{'#gview_"+c+" .ui-jqgrid-bdiv':true,'"+a._alsoResize_+"':true}")+")"):b(".ui-jqgrid-bdiv","#gview_"+
+c);delete a._alsoResize_;b("#gbox_"+c).resizable(a)}})}})})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css
new file mode 100644
index 00000000..c0801ae6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css
@@ -0,0 +1,144 @@
+/*Grid*/
+.ui-jqgrid {position: relative;}
+.ui-jqgrid .ui-jqgrid-view {position: relative;left:0px; top: 0px; padding: .0em; font-size:11px;}
+/* caption*/
+.ui-jqgrid .ui-jqgrid-titlebar {padding: .3em .2em .2em .3em; position: relative; border-left: 0px none;border-right: 0px none; border-top: 0px none;}
+.ui-jqgrid .ui-jqgrid-title { float: left; margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-titlebar-close { position: absolute;top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height:18px;}.ui-jqgrid .ui-jqgrid-titlebar-close span { display: block; margin: 1px; }
+.ui-jqgrid .ui-jqgrid-titlebar-close:hover { padding: 0; }
+/* header*/
+.ui-jqgrid .ui-jqgrid-hdiv {position: relative; margin: 0em;padding: 0em; overflow-x: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-hbox {float: left; padding-right: 20px;}
+.ui-jqgrid .ui-jqgrid-htable {table-layout:fixed;margin:0em;}
+.ui-jqgrid .ui-jqgrid-htable th {height:22px;padding: 0 2px 0 2px;}
+.ui-jqgrid .ui-jqgrid-htable th div {overflow: hidden; position:relative; height:17px;}
+.ui-th-column, .ui-jqgrid .ui-jqgrid-htable th.ui-th-column {overflow: hidden;white-space: nowrap;text-align:center;border-top : 0px none;border-bottom : 0px none;}
+.ui-th-ltr, .ui-jqgrid .ui-jqgrid-htable th.ui-th-ltr {border-left : 0px none;}
+.ui-th-rtl, .ui-jqgrid .ui-jqgrid-htable th.ui-th-rtl {border-right : 0px none;}
+.ui-first-th-ltr {border-right: 1px solid; }
+.ui-first-th-rtl {border-left: 1px solid; }
+.ui-jqgrid .ui-th-div-ie {white-space: nowrap; zoom :1; height:17px;}
+.ui-jqgrid .ui-jqgrid-resize {height:20px !important;position: relative; cursor :e-resize;display: inline;overflow: hidden;}
+.ui-jqgrid .ui-grid-ico-sort {overflow:hidden;position:absolute;display:inline; cursor: pointer !important;}
+.ui-jqgrid .ui-icon-asc {margin-top:-3px; height:12px;}
+.ui-jqgrid .ui-icon-desc {margin-top:3px;height:12px;}
+.ui-jqgrid .ui-i-asc {margin-top:0px;height:16px;}
+.ui-jqgrid .ui-i-desc {margin-top:0px;margin-left:13px;height:16px;}
+.ui-jqgrid .ui-jqgrid-sortable {cursor:pointer;}
+.ui-jqgrid tr.ui-search-toolbar th { border-top-width: 1px !important; border-top-color: inherit !important; border-top-style: ridge !important }
+tr.ui-search-toolbar input {margin: 1px 0px 0px 0px}
+tr.ui-search-toolbar select {margin: 1px 0px 0px 0px}
+/* body */
+.ui-jqgrid .ui-jqgrid-bdiv {position: relative; margin: 0em; padding:0; overflow: auto; text-align:left;}
+.ui-jqgrid .ui-jqgrid-btable {table-layout:fixed; margin:0em; outline-style: none; }
+.ui-jqgrid tr.jqgrow { outline-style: none; }
+.ui-jqgrid tr.jqgroup { outline-style: none; }
+.ui-jqgrid tr.jqgrow td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqgfirstrow td {padding: 0 2px 0 2px;border-right-width: 1px; border-right-style: solid;}
+.ui-jqgrid tr.jqgroup td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqfoot td {font-weight: bold; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.ui-row-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.ui-row-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+.ui-jqgrid td.jqgrid-rownum { padding: 0 2px 0 2px; margin: 0px; border: 0px none;}
+.ui-jqgrid .ui-jqgrid-resize-mark { width:2px; left:0; background-color:#777; cursor: e-resize; cursor: col-resize; position:absolute; top:0; height:100px; overflow:hidden; display:none; border:0 none; z-index: 99999;}
+/* footer */
+.ui-jqgrid .ui-jqgrid-sdiv {position: relative; margin: 0em;padding: 0em; overflow: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-ftable {table-layout:fixed; margin-bottom:0em;}
+.ui-jqgrid tr.footrow td {font-weight: bold; overflow: hidden; white-space:nowrap; height: 21px;padding: 0 2px 0 2px;border-top-width: 1px; border-top-color: inherit; border-top-style: solid;}
+.ui-jqgrid tr.footrow-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.footrow-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+/* Pager*/
+.ui-jqgrid .ui-jqgrid-pager { border-left: 0px none !important;border-right: 0px none !important; border-bottom: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px;white-space: nowrap;overflow: hidden;font-size:11px;}
+.ui-jqgrid .ui-pager-control {position: relative;}
+.ui-jqgrid .ui-pg-table {position: relative; padding-bottom:2px; width:auto; margin: 0em;}
+.ui-jqgrid .ui-pg-table td {font-weight:normal; vertical-align:middle; padding:1px;}
+.ui-jqgrid .ui-pg-button { height:19px !important;}
+.ui-jqgrid .ui-pg-button span { display: block; margin: 1px; float:left;}
+.ui-jqgrid .ui-pg-button:hover { padding: 0px; }
+.ui-jqgrid .ui-state-disabled:hover {padding:1px;}
+.ui-jqgrid .ui-pg-input { height:13px;font-size:.8em; margin: 0em;}
+.ui-jqgrid .ui-pg-selbox {font-size:.8em; line-height:18px; display:block; height:18px; margin: 0em;}
+.ui-jqgrid .ui-separator {height: 18px; border-left: 1px solid #ccc ; border-right: 1px solid #ccc ; margin: 1px; float: right;}
+.ui-jqgrid .ui-paging-info {font-weight: normal;height:19px; margin-top:3px;margin-right:4px;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div {padding:1px 0;float:left;position:relative;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-button { cursor:pointer; }
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
+.ui-jqgrid td input, .ui-jqgrid td select .ui-jqgrid td textarea { margin: 0em;}
+.ui-jqgrid td textarea {width:auto;height:auto;}
+.ui-jqgrid .ui-jqgrid-toppager {border-left: 0px none !important;border-right: 0px none !important; border-top: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px !important;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-div {padding:1px 0;float:left;position:relative;}
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-button { cursor:pointer; }
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
+/*subgrid*/
+.ui-jqgrid .ui-jqgrid-btable .ui-sgcollapsed span {display: block;}
+.ui-jqgrid .ui-subgrid {margin:0em;padding:0em; width:100%;}
+.ui-jqgrid .ui-subgrid table {table-layout: fixed;}
+.ui-jqgrid .ui-subgrid tr.ui-subtblcell td {height:18px;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid .ui-subgrid td.subgrid-data {border-top: 0px none !important;}
+.ui-jqgrid .ui-subgrid td.subgrid-cell {border-width: 0px 0px 1px 0px;}
+.ui-jqgrid .ui-th-subgrid {height:20px;}
+/* loading */
+.ui-jqgrid .loading {position: absolute; top: 45%;left: 45%;width: auto;z-index:101;padding: 6px; margin: 5px;text-align: center;font-weight: bold;display: none;border-width: 2px !important; font-size:11px;}
+.ui-jqgrid .jqgrid-overlay {display:none;z-index:100;}
+* html .jqgrid-overlay {width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+* .jqgrid-overlay iframe {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+/* end loading div */
+/* toolbar */
+.ui-jqgrid .ui-userdata {border-left: 0px none; border-right: 0px none; height : 21px;overflow: hidden; }
+/*Modal Window */
+.ui-jqdialog { display: none; width: 300px; position: absolute; padding: .2em; font-size:11px; overflow:visible;}
+.ui-jqdialog .ui-jqdialog-titlebar { padding: .3em .2em; position: relative; }
+.ui-jqdialog .ui-jqdialog-title { margin: .1em 0 .2em; }
+.ui-jqdialog .ui-jqdialog-titlebar-close { position: absolute; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+
+.ui-jqdialog .ui-jqdialog-titlebar-close span { display: block; margin: 1px; }
+.ui-jqdialog .ui-jqdialog-titlebar-close:hover, .ui-jqdialog .ui-jqdialog-titlebar-close:focus { padding: 0; }
+.ui-jqdialog-content, .ui-jqdialog .ui-jqdialog-content { border: 0; padding: .3em .2em; background: none; height:auto;}
+.ui-jqdialog .ui-jqconfirm {padding: .4em 1em; border-width:3px;position:absolute;bottom:10px;right:10px;overflow:visible;display:none;height:80px;width:220px;text-align:center;}
+/* end Modal window*/
+/* Form edit */
+.ui-jqdialog-content .FormGrid {margin: 0px;}
+.ui-jqdialog-content .EditTable { width: 100%; margin-bottom:0em;}
+.ui-jqdialog-content .DelTable { width: 100%; margin-bottom:0em;}
+.EditTable td input, .EditTable td select, .EditTable td textarea {margin: 0em;}
+.EditTable td textarea { width:auto; height:auto;}
+.ui-jqdialog-content td.EditButton {text-align: right;border-top: 0px none;border-left: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content td.navButton {text-align: center; border-left: 0px none;border-top: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content input.FormElement {padding:.3em}
+.ui-jqdialog-content .data-line {padding-top:.1em;border: 0px none;}
+
+.ui-jqdialog-content .CaptionTD {vertical-align: middle;border: 0px none; padding: 2px;white-space: nowrap;}
+.ui-jqdialog-content .DataTD {padding: 2px; border: 0px none; vertical-align: top;}
+.ui-jqdialog-content .form-view-data {white-space:pre}
+.fm-button { display: inline-block; margin:0 4px 0 0; padding: .4em .5em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
+.fm-button-icon-left { padding-left: 1.9em; }
+.fm-button-icon-right { padding-right: 1.9em; }
+.fm-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px; }
+.fm-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px;}
+#nData, #pData { float: left; margin:3px;padding: 0; width: 15px; }
+/* End Eorm edit */
+/*.ui-jqgrid .edit-cell {}*/
+.ui-jqgrid .selected-row, div.ui-jqgrid .selected-row td {font-style : normal;border-left: 0px none;}
+/* inline edit actions button*/
+.ui-inline-del.ui-state-hover span, .ui-inline-edit.ui-state-hover span,
+.ui-inline-save.ui-state-hover span, .ui-inline-cancel.ui-state-hover span {
+ margin: -1px;
+}
+/* Tree Grid */
+.ui-jqgrid .tree-wrap {float: left; position: relative;height: 18px;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .tree-minus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-plus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-leaf {position: absolute; height: 18px; width: 18px;overflow: hidden;}
+.ui-jqgrid .treeclick {cursor: pointer;}
+/* moda dialog */
+* iframe.jqm {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+.ui-jqgrid-dnd tr td {border-right-width: 1px; border-right-color: inherit; border-right-style: solid; height:20px}
+/* RTL Support */
+.ui-jqgrid .ui-jqgrid-title-rtl {float:right;margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-hbox-rtl {float: right; padding-left: 20px;}
+.ui-jqgrid .ui-jqgrid-resize-ltr {float: right;margin: -2px -2px -2px 0px;}
+.ui-jqgrid .ui-jqgrid-resize-rtl {float: left;margin: -2px 0px -1px -3px;}
+.ui-jqgrid .ui-sort-rtl {left:0px;}
+.ui-jqgrid .tree-wrap-ltr {float: left;}
+.ui-jqgrid .tree-wrap-rtl {float: right;}
+.ui-jqgrid .ui-ellipsis {text-overflow:ellipsis;}
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/excanvas.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/excanvas.js
new file mode 100644
index 00000000..4ca9653f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/excanvas.js
@@ -0,0 +1,1438 @@
+// Memory Leaks patch from http://explorercanvas.googlecode.com/svn/trunk/
+// svn : r73
+// ------------------------------------------------------------------
+// Copyright 2006 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// Known Issues:
+//
+// * Patterns only support repeat.
+// * Radial gradient are not implemented. The VML version of these look very
+// different from the canvas one.
+// * Clipping paths are not implemented.
+// * Coordsize. The width and height attribute have higher priority than the
+// width and height style values which isn't correct.
+// * Painting mode isn't implemented.
+// * Canvas width/height should is using content-box by default. IE in
+// Quirks mode will draw the canvas using border-box. Either change your
+// doctype to HTML5
+// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
+// or use Box Sizing Behavior from WebFX
+// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
+// * Non uniform scaling does not correctly scale strokes.
+// * Optimize. There is always room for speed improvements.
+
+// Only add this code if we do not already have a canvas implementation
+if (!document.createElement('canvas').getContext) {
+
+(function() {
+
+ // alias some functions to make (compiled) code shorter
+ var m = Math;
+ var mr = m.round;
+ var ms = m.sin;
+ var mc = m.cos;
+ var abs = m.abs;
+ var sqrt = m.sqrt;
+
+ // this is used for sub pixel precision
+ var Z = 10;
+ var Z2 = Z / 2;
+
+ var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
+
+ /**
+ * This funtion is assigned to the <canvas> elements as element.getContext().
+ * @this {HTMLElement}
+ * @return {CanvasRenderingContext2D_}
+ */
+ function getContext() {
+ return this.context_ ||
+ (this.context_ = new CanvasRenderingContext2D_(this));
+ }
+
+ var slice = Array.prototype.slice;
+
+ /**
+ * Binds a function to an object. The returned function will always use the
+ * passed in {@code obj} as {@code this}.
+ *
+ * Example:
+ *
+ * g = bind(f, obj, a, b)
+ * g(c, d) // will do f.call(obj, a, b, c, d)
+ *
+ * @param {Function} f The function to bind the object to
+ * @param {Object} obj The object that should act as this when the function
+ * is called
+ * @param {*} var_args Rest arguments that will be used as the initial
+ * arguments when the function is called
+ * @return {Function} A new function that has bound this
+ */
+ function bind(f, obj, var_args) {
+ var a = slice.call(arguments, 2);
+ return function() {
+ return f.apply(obj, a.concat(slice.call(arguments)));
+ };
+ }
+
+ function encodeHtmlAttribute(s) {
+ return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+ }
+
+ function addNamespace(doc, prefix, urn) {
+ if (!doc.namespaces[prefix]) {
+ doc.namespaces.add(prefix, urn, '#default#VML');
+ }
+ }
+
+ function addNamespacesAndStylesheet(doc) {
+ addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
+ addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
+
+ // Setup default CSS. Only add one style sheet per document
+ if (!doc.styleSheets['ex_canvas_']) {
+ var ss = doc.createStyleSheet();
+ ss.owningElement.id = 'ex_canvas_';
+ ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
+ // default size is 300x150 in Gecko and Opera
+ 'text-align:left;width:300px;height:150px}';
+ }
+ }
+
+ // Add namespaces and stylesheet at startup.
+ addNamespacesAndStylesheet(document);
+
+ var G_vmlCanvasManager_ = {
+ init: function(opt_doc) {
+ var doc = opt_doc || document;
+ // Create a dummy element so that IE will allow canvas elements to be
+ // recognized.
+ doc.createElement('canvas');
+ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
+ },
+
+ init_: function(doc) {
+ // find all canvas elements
+ var els = doc.getElementsByTagName('canvas');
+ for (var i = 0; i < els.length; i++) {
+ this.initElement(els[i]);
+ }
+ },
+
+ /**
+ * Public initializes a canvas element so that it can be used as canvas
+ * element from now on. This is called automatically before the page is
+ * loaded but if you are creating elements using createElement you need to
+ * make sure this is called on the element.
+ * @param {HTMLElement} el The canvas element to initialize.
+ * @return {HTMLElement} the element that was created.
+ */
+ initElement: function(el) {
+ if (!el.getContext) {
+ el.getContext = getContext;
+
+ // Add namespaces and stylesheet to document of the element.
+ addNamespacesAndStylesheet(el.ownerDocument);
+
+ // Remove fallback content. There is no way to hide text nodes so we
+ // just remove all childNodes. We could hide all elements and remove
+ // text nodes but who really cares about the fallback content.
+ el.innerHTML = '';
+
+ // do not use inline function because that will leak memory
+ el.attachEvent('onpropertychange', onPropertyChange);
+ el.attachEvent('onresize', onResize);
+
+ var attrs = el.attributes;
+ if (attrs.width && attrs.width.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setWidth_(attrs.width.nodeValue);
+ el.style.width = attrs.width.nodeValue + 'px';
+ } else {
+ el.width = el.clientWidth;
+ }
+ if (attrs.height && attrs.height.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setHeight_(attrs.height.nodeValue);
+ el.style.height = attrs.height.nodeValue + 'px';
+ } else {
+ el.height = el.clientHeight;
+ }
+ //el.getContext().setCoordsize_()
+ }
+ return el;
+ },
+
+ // Memory Leaks patch : see http://code.google.com/p/explorercanvas/issues/detail?id=82
+ uninitElement: function(el){
+ if (el.getContext) {
+ var ctx = el.getContext();
+ delete ctx.element_;
+ delete ctx.canvas;
+ el.innerHTML = "";
+ //el.outerHTML = "";
+ el.context_ = null;
+ el.getContext = null;
+ el.detachEvent("onpropertychange", onPropertyChange);
+ el.detachEvent("onresize", onResize);
+ }
+ }
+ };
+
+ function onPropertyChange(e) {
+ var el = e.srcElement;
+
+ switch (e.propertyName) {
+ case 'width':
+ el.getContext().clearRect();
+ el.style.width = el.attributes.width.nodeValue + 'px';
+ // In IE8 this does not trigger onresize.
+ el.firstChild.style.width = el.clientWidth + 'px';
+ break;
+ case 'height':
+ el.getContext().clearRect();
+ el.style.height = el.attributes.height.nodeValue + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ break;
+ }
+ }
+
+ function onResize(e) {
+ var el = e.srcElement;
+ if (el.firstChild) {
+ el.firstChild.style.width = el.clientWidth + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ }
+ }
+
+ G_vmlCanvasManager_.init();
+
+ // precompute "00" to "FF"
+ var decToHex = [];
+ for (var i = 0; i < 16; i++) {
+ for (var j = 0; j < 16; j++) {
+ decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
+ }
+ }
+
+ function createMatrixIdentity() {
+ return [
+ [1, 0, 0],
+ [0, 1, 0],
+ [0, 0, 1]
+ ];
+ }
+
+ function matrixMultiply(m1, m2) {
+ var result = createMatrixIdentity();
+
+ for (var x = 0; x < 3; x++) {
+ for (var y = 0; y < 3; y++) {
+ var sum = 0;
+
+ for (var z = 0; z < 3; z++) {
+ sum += m1[x][z] * m2[z][y];
+ }
+
+ result[x][y] = sum;
+ }
+ }
+ return result;
+ }
+
+ function copyState(o1, o2) {
+ o2.fillStyle = o1.fillStyle;
+ o2.lineCap = o1.lineCap;
+ o2.lineJoin = o1.lineJoin;
+ o2.lineWidth = o1.lineWidth;
+ o2.miterLimit = o1.miterLimit;
+ o2.shadowBlur = o1.shadowBlur;
+ o2.shadowColor = o1.shadowColor;
+ o2.shadowOffsetX = o1.shadowOffsetX;
+ o2.shadowOffsetY = o1.shadowOffsetY;
+ o2.strokeStyle = o1.strokeStyle;
+ o2.globalAlpha = o1.globalAlpha;
+ o2.font = o1.font;
+ o2.textAlign = o1.textAlign;
+ o2.textBaseline = o1.textBaseline;
+ o2.arcScaleX_ = o1.arcScaleX_;
+ o2.arcScaleY_ = o1.arcScaleY_;
+ o2.lineScale_ = o1.lineScale_;
+ }
+
+ var colorData = {
+ aliceblue: '#F0F8FF',
+ antiquewhite: '#FAEBD7',
+ aquamarine: '#7FFFD4',
+ azure: '#F0FFFF',
+ beige: '#F5F5DC',
+ bisque: '#FFE4C4',
+ black: '#000000',
+ blanchedalmond: '#FFEBCD',
+ blueviolet: '#8A2BE2',
+ brown: '#A52A2A',
+ burlywood: '#DEB887',
+ cadetblue: '#5F9EA0',
+ chartreuse: '#7FFF00',
+ chocolate: '#D2691E',
+ coral: '#FF7F50',
+ cornflowerblue: '#6495ED',
+ cornsilk: '#FFF8DC',
+ crimson: '#DC143C',
+ cyan: '#00FFFF',
+ darkblue: '#00008B',
+ darkcyan: '#008B8B',
+ darkgoldenrod: '#B8860B',
+ darkgray: '#A9A9A9',
+ darkgreen: '#006400',
+ darkgrey: '#A9A9A9',
+ darkkhaki: '#BDB76B',
+ darkmagenta: '#8B008B',
+ darkolivegreen: '#556B2F',
+ darkorange: '#FF8C00',
+ darkorchid: '#9932CC',
+ darkred: '#8B0000',
+ darksalmon: '#E9967A',
+ darkseagreen: '#8FBC8F',
+ darkslateblue: '#483D8B',
+ darkslategray: '#2F4F4F',
+ darkslategrey: '#2F4F4F',
+ darkturquoise: '#00CED1',
+ darkviolet: '#9400D3',
+ deeppink: '#FF1493',
+ deepskyblue: '#00BFFF',
+ dimgray: '#696969',
+ dimgrey: '#696969',
+ dodgerblue: '#1E90FF',
+ firebrick: '#B22222',
+ floralwhite: '#FFFAF0',
+ forestgreen: '#228B22',
+ gainsboro: '#DCDCDC',
+ ghostwhite: '#F8F8FF',
+ gold: '#FFD700',
+ goldenrod: '#DAA520',
+ grey: '#808080',
+ greenyellow: '#ADFF2F',
+ honeydew: '#F0FFF0',
+ hotpink: '#FF69B4',
+ indianred: '#CD5C5C',
+ indigo: '#4B0082',
+ ivory: '#FFFFF0',
+ khaki: '#F0E68C',
+ lavender: '#E6E6FA',
+ lavenderblush: '#FFF0F5',
+ lawngreen: '#7CFC00',
+ lemonchiffon: '#FFFACD',
+ lightblue: '#ADD8E6',
+ lightcoral: '#F08080',
+ lightcyan: '#E0FFFF',
+ lightgoldenrodyellow: '#FAFAD2',
+ lightgreen: '#90EE90',
+ lightgrey: '#D3D3D3',
+ lightpink: '#FFB6C1',
+ lightsalmon: '#FFA07A',
+ lightseagreen: '#20B2AA',
+ lightskyblue: '#87CEFA',
+ lightslategray: '#778899',
+ lightslategrey: '#778899',
+ lightsteelblue: '#B0C4DE',
+ lightyellow: '#FFFFE0',
+ limegreen: '#32CD32',
+ linen: '#FAF0E6',
+ magenta: '#FF00FF',
+ mediumaquamarine: '#66CDAA',
+ mediumblue: '#0000CD',
+ mediumorchid: '#BA55D3',
+ mediumpurple: '#9370DB',
+ mediumseagreen: '#3CB371',
+ mediumslateblue: '#7B68EE',
+ mediumspringgreen: '#00FA9A',
+ mediumturquoise: '#48D1CC',
+ mediumvioletred: '#C71585',
+ midnightblue: '#191970',
+ mintcream: '#F5FFFA',
+ mistyrose: '#FFE4E1',
+ moccasin: '#FFE4B5',
+ navajowhite: '#FFDEAD',
+ oldlace: '#FDF5E6',
+ olivedrab: '#6B8E23',
+ orange: '#FFA500',
+ orangered: '#FF4500',
+ orchid: '#DA70D6',
+ palegoldenrod: '#EEE8AA',
+ palegreen: '#98FB98',
+ paleturquoise: '#AFEEEE',
+ palevioletred: '#DB7093',
+ papayawhip: '#FFEFD5',
+ peachpuff: '#FFDAB9',
+ peru: '#CD853F',
+ pink: '#FFC0CB',
+ plum: '#DDA0DD',
+ powderblue: '#B0E0E6',
+ rosybrown: '#BC8F8F',
+ royalblue: '#4169E1',
+ saddlebrown: '#8B4513',
+ salmon: '#FA8072',
+ sandybrown: '#F4A460',
+ seagreen: '#2E8B57',
+ seashell: '#FFF5EE',
+ sienna: '#A0522D',
+ skyblue: '#87CEEB',
+ slateblue: '#6A5ACD',
+ slategray: '#708090',
+ slategrey: '#708090',
+ snow: '#FFFAFA',
+ springgreen: '#00FF7F',
+ steelblue: '#4682B4',
+ tan: '#D2B48C',
+ thistle: '#D8BFD8',
+ tomato: '#FF6347',
+ turquoise: '#40E0D0',
+ violet: '#EE82EE',
+ wheat: '#F5DEB3',
+ whitesmoke: '#F5F5F5',
+ yellowgreen: '#9ACD32'
+ };
+
+
+ function getRgbHslContent(styleString) {
+ var start = styleString.indexOf('(', 3);
+ var end = styleString.indexOf(')', start + 1);
+ var parts = styleString.substring(start + 1, end).split(',');
+ // add alpha if needed
+ if (parts.length != 4 || styleString.charAt(3) != 'a') {
+ parts[3] = 1;
+ }
+ return parts;
+ }
+
+ function percent(s) {
+ return parseFloat(s) / 100;
+ }
+
+ function clamp(v, min, max) {
+ return Math.min(max, Math.max(min, v));
+ }
+
+ function hslToRgb(parts){
+ var r, g, b, h, s, l;
+ h = parseFloat(parts[0]) / 360 % 360;
+ if (h < 0)
+ h++;
+ s = clamp(percent(parts[1]), 0, 1);
+ l = clamp(percent(parts[2]), 0, 1);
+ if (s == 0) {
+ r = g = b = l; // achromatic
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hueToRgb(p, q, h + 1 / 3);
+ g = hueToRgb(p, q, h);
+ b = hueToRgb(p, q, h - 1 / 3);
+ }
+
+ return '#' + decToHex[Math.floor(r * 255)] +
+ decToHex[Math.floor(g * 255)] +
+ decToHex[Math.floor(b * 255)];
+ }
+
+ function hueToRgb(m1, m2, h) {
+ if (h < 0)
+ h++;
+ if (h > 1)
+ h--;
+
+ if (6 * h < 1)
+ return m1 + (m2 - m1) * 6 * h;
+ else if (2 * h < 1)
+ return m2;
+ else if (3 * h < 2)
+ return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+ else
+ return m1;
+ }
+
+ var processStyleCache = {};
+
+ function processStyle(styleString) {
+ if (styleString in processStyleCache) {
+ return processStyleCache[styleString];
+ }
+
+ var str, alpha = 1;
+
+ styleString = String(styleString);
+ if (styleString.charAt(0) == '#') {
+ str = styleString;
+ } else if (/^rgb/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ var str = '#', n;
+ for (var i = 0; i < 3; i++) {
+ if (parts[i].indexOf('%') != -1) {
+ n = Math.floor(percent(parts[i]) * 255);
+ } else {
+ n = +parts[i];
+ }
+ str += decToHex[clamp(n, 0, 255)];
+ }
+ alpha = +parts[3];
+ } else if (/^hsl/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ str = hslToRgb(parts);
+ alpha = parts[3];
+ } else {
+ str = colorData[styleString] || styleString;
+ }
+ return processStyleCache[styleString] = {color: str, alpha: alpha};
+ }
+
+ var DEFAULT_STYLE = {
+ style: 'normal',
+ variant: 'normal',
+ weight: 'normal',
+ size: 10,
+ family: 'sans-serif'
+ };
+
+ // Internal text style cache
+ var fontStyleCache = {};
+
+ function processFontStyle(styleString) {
+ if (fontStyleCache[styleString]) {
+ return fontStyleCache[styleString];
+ }
+
+ var el = document.createElement('div');
+ var style = el.style;
+ try {
+ style.font = styleString;
+ } catch (ex) {
+ // Ignore failures to set to invalid font.
+ }
+
+ return fontStyleCache[styleString] = {
+ style: style.fontStyle || DEFAULT_STYLE.style,
+ variant: style.fontVariant || DEFAULT_STYLE.variant,
+ weight: style.fontWeight || DEFAULT_STYLE.weight,
+ size: style.fontSize || DEFAULT_STYLE.size,
+ family: style.fontFamily || DEFAULT_STYLE.family
+ };
+ }
+
+ function getComputedStyle(style, element) {
+ var computedStyle = {};
+
+ for (var p in style) {
+ computedStyle[p] = style[p];
+ }
+
+ // Compute the size
+ var canvasFontSize = parseFloat(element.currentStyle.fontSize),
+ fontSize = parseFloat(style.size);
+
+ if (typeof style.size == 'number') {
+ computedStyle.size = style.size;
+ } else if (style.size.indexOf('px') != -1) {
+ computedStyle.size = fontSize;
+ } else if (style.size.indexOf('em') != -1) {
+ computedStyle.size = canvasFontSize * fontSize;
+ } else if(style.size.indexOf('%') != -1) {
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
+ } else if (style.size.indexOf('pt') != -1) {
+ computedStyle.size = fontSize / .75;
+ } else {
+ computedStyle.size = canvasFontSize;
+ }
+
+ // Different scaling between normal text and VML text. This was found using
+ // trial and error to get the same size as non VML text.
+ computedStyle.size *= 0.981;
+
+ // Fix for VML handling of bare font family names. Add a '' around font family names.
+ computedStyle.family = "'" + computedStyle.family.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
+
+ return computedStyle;
+ }
+
+ function buildStyle(style) {
+ return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
+ style.size + 'px ' + style.family;
+ }
+
+ var lineCapMap = {
+ 'butt': 'flat',
+ 'round': 'round'
+ };
+
+ function processLineCap(lineCap) {
+ return lineCapMap[lineCap] || 'square';
+ }
+
+ /**
+ * This class implements CanvasRenderingContext2D interface as described by
+ * the WHATWG.
+ * @param {HTMLElement} canvasElement The element that the 2D context should
+ * be associated with
+ */
+ function CanvasRenderingContext2D_(canvasElement) {
+ this.m_ = createMatrixIdentity();
+
+ this.mStack_ = [];
+ this.aStack_ = [];
+ this.currentPath_ = [];
+
+ // Canvas context properties
+ this.strokeStyle = '#000';
+ this.fillStyle = '#000';
+
+ this.lineWidth = 1;
+ this.lineJoin = 'miter';
+ this.lineCap = 'butt';
+ this.miterLimit = Z * 1;
+ this.globalAlpha = 1;
+ this.font = '10px sans-serif';
+ this.textAlign = 'left';
+ this.textBaseline = 'alphabetic';
+ this.canvas = canvasElement;
+
+ var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
+ canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
+ var el = canvasElement.ownerDocument.createElement('div');
+ el.style.cssText = cssText;
+ canvasElement.appendChild(el);
+
+ var overlayEl = el.cloneNode(false);
+ // Use a non transparent background.
+ overlayEl.style.backgroundColor = 'red';
+ overlayEl.style.filter = 'alpha(opacity=0)';
+ canvasElement.appendChild(overlayEl);
+
+ this.element_ = el;
+ this.arcScaleX_ = 1;
+ this.arcScaleY_ = 1;
+ this.lineScale_ = 1;
+ }
+
+ var contextPrototype = CanvasRenderingContext2D_.prototype;
+ contextPrototype.clearRect = function() {
+ if (this.textMeasureEl_) {
+ this.textMeasureEl_.removeNode(true);
+ this.textMeasureEl_ = null;
+ }
+ this.element_.innerHTML = '';
+ };
+
+ contextPrototype.beginPath = function() {
+ // TODO: Branch current matrix so that save/restore has no effect
+ // as per safari docs.
+ this.currentPath_ = [];
+ };
+
+ contextPrototype.moveTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.lineTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
+
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+ aCP2x, aCP2y,
+ aX, aY) {
+ var p = getCoords(this, aX, aY);
+ var cp1 = getCoords(this, aCP1x, aCP1y);
+ var cp2 = getCoords(this, aCP2x, aCP2y);
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ // Helper function that takes the already fixed cordinates.
+ function bezierCurveTo(self, cp1, cp2, p) {
+ self.currentPath_.push({
+ type: 'bezierCurveTo',
+ cp1x: cp1.x,
+ cp1y: cp1.y,
+ cp2x: cp2.x,
+ cp2y: cp2.y,
+ x: p.x,
+ y: p.y
+ });
+ self.currentX_ = p.x;
+ self.currentY_ = p.y;
+ }
+
+ contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
+ // the following is lifted almost directly from
+ // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
+
+ var cp = getCoords(this, aCPx, aCPy);
+ var p = getCoords(this, aX, aY);
+
+ var cp1 = {
+ x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
+ y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
+ };
+ var cp2 = {
+ x: cp1.x + (p.x - this.currentX_) / 3.0,
+ y: cp1.y + (p.y - this.currentY_) / 3.0
+ };
+
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ contextPrototype.arc = function(aX, aY, aRadius,
+ aStartAngle, aEndAngle, aClockwise) {
+ aRadius *= Z;
+ var arcType = aClockwise ? 'at' : 'wa';
+
+ var xStart = aX + mc(aStartAngle) * aRadius - Z2;
+ var yStart = aY + ms(aStartAngle) * aRadius - Z2;
+
+ var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
+ var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
+
+ // IE won't render arches drawn counter clockwise if xStart == xEnd.
+ if (xStart == xEnd && !aClockwise) {
+ xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
+ // that can be represented in binary
+ }
+
+ var p = getCoords(this, aX, aY);
+ var pStart = getCoords(this, xStart, yStart);
+ var pEnd = getCoords(this, xEnd, yEnd);
+
+ this.currentPath_.push({type: arcType,
+ x: p.x,
+ y: p.y,
+ radius: aRadius,
+ xStart: pStart.x,
+ yStart: pStart.y,
+ xEnd: pEnd.x,
+ yEnd: pEnd.y});
+
+ };
+
+ contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ };
+
+ contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.stroke();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.fill();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+ var gradient = new CanvasGradient_('gradient');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ return gradient;
+ };
+
+ contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
+ aX1, aY1, aR1) {
+ var gradient = new CanvasGradient_('gradientradial');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.r0_ = aR0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ gradient.r1_ = aR1;
+ return gradient;
+ };
+
+ contextPrototype.drawImage = function(image, var_args) {
+ var dx, dy, dw, dh, sx, sy, sw, sh;
+
+ // to find the original width we overide the width and height
+ var oldRuntimeWidth = image.runtimeStyle.width;
+ var oldRuntimeHeight = image.runtimeStyle.height;
+ image.runtimeStyle.width = 'auto';
+ image.runtimeStyle.height = 'auto';
+
+ // get the original size
+ var w = image.width;
+ var h = image.height;
+
+ // and remove overides
+ image.runtimeStyle.width = oldRuntimeWidth;
+ image.runtimeStyle.height = oldRuntimeHeight;
+
+ if (arguments.length == 3) {
+ dx = arguments[1];
+ dy = arguments[2];
+ sx = sy = 0;
+ sw = dw = w;
+ sh = dh = h;
+ } else if (arguments.length == 5) {
+ dx = arguments[1];
+ dy = arguments[2];
+ dw = arguments[3];
+ dh = arguments[4];
+ sx = sy = 0;
+ sw = w;
+ sh = h;
+ } else if (arguments.length == 9) {
+ sx = arguments[1];
+ sy = arguments[2];
+ sw = arguments[3];
+ sh = arguments[4];
+ dx = arguments[5];
+ dy = arguments[6];
+ dw = arguments[7];
+ dh = arguments[8];
+ } else {
+ throw Error('Invalid number of arguments');
+ }
+
+ var d = getCoords(this, dx, dy);
+
+ var w2 = sw / 2;
+ var h2 = sh / 2;
+
+ var vmlStr = [];
+
+ var W = 10;
+ var H = 10;
+
+ // For some reason that I've now forgotten, using divs didn't work
+ vmlStr.push(' <g_vml_:group',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' coordorigin="0,0"' ,
+ ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
+
+ // If filters are necessary (rotation exists), create them
+ // filters are bog-slow, so only create them if abbsolutely necessary
+ // The following check doesn't account for skews (which don't exist
+ // in the canvas spec (yet) anyway.
+
+ if (this.m_[0][0] != 1 || this.m_[0][1] ||
+ this.m_[1][1] != 1 || this.m_[1][0]) {
+ var filter = [];
+
+ // Note the 12/21 reversal
+ filter.push('M11=', this.m_[0][0], ',',
+ 'M12=', this.m_[1][0], ',',
+ 'M21=', this.m_[0][1], ',',
+ 'M22=', this.m_[1][1], ',',
+ 'Dx=', mr(d.x / Z), ',',
+ 'Dy=', mr(d.y / Z), '');
+
+ // Bounding box calculation (need to minimize displayed area so that
+ // filters don't waste time on unused pixels.
+ var max = d;
+ var c2 = getCoords(this, dx + dw, dy);
+ var c3 = getCoords(this, dx, dy + dh);
+ var c4 = getCoords(this, dx + dw, dy + dh);
+
+ max.x = m.max(max.x, c2.x, c3.x, c4.x);
+ max.y = m.max(max.y, c2.y, c3.y, c4.y);
+
+ vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
+ 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
+ filter.join(''), ", sizingmethod='clip');");
+
+ } else {
+ vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
+ }
+
+ vmlStr.push(' ">' ,
+ '<g_vml_:image src="', image.src, '"',
+ ' style="width:', Z * dw, 'px;',
+ ' height:', Z * dh, 'px"',
+ ' cropleft="', sx / w, '"',
+ ' croptop="', sy / h, '"',
+ ' cropright="', (w - sx - sw) / w, '"',
+ ' cropbottom="', (h - sy - sh) / h, '"',
+ ' />',
+ '</g_vml_:group>');
+
+ this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
+ };
+
+ contextPrototype.stroke = function(aFill) {
+ var lineStr = [];
+ var lineOpen = false;
+
+ var W = 10;
+ var H = 10;
+
+ lineStr.push('<g_vml_:shape',
+ ' filled="', !!aFill, '"',
+ ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
+ ' coordorigin="0,0"',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' stroked="', !aFill, '"',
+ ' path="');
+
+ var newSeq = false;
+ var min = {x: null, y: null};
+ var max = {x: null, y: null};
+
+ for (var i = 0; i < this.currentPath_.length; i++) {
+ var p = this.currentPath_[i];
+ var c;
+
+ switch (p.type) {
+ case 'moveTo':
+ c = p;
+ lineStr.push(' m ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'lineTo':
+ lineStr.push(' l ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'close':
+ lineStr.push(' x ');
+ p = null;
+ break;
+ case 'bezierCurveTo':
+ lineStr.push(' c ',
+ mr(p.cp1x), ',', mr(p.cp1y), ',',
+ mr(p.cp2x), ',', mr(p.cp2y), ',',
+ mr(p.x), ',', mr(p.y));
+ break;
+ case 'at':
+ case 'wa':
+ lineStr.push(' ', p.type, ' ',
+ mr(p.x - this.arcScaleX_ * p.radius), ',',
+ mr(p.y - this.arcScaleY_ * p.radius), ' ',
+ mr(p.x + this.arcScaleX_ * p.radius), ',',
+ mr(p.y + this.arcScaleY_ * p.radius), ' ',
+ mr(p.xStart), ',', mr(p.yStart), ' ',
+ mr(p.xEnd), ',', mr(p.yEnd));
+ break;
+ }
+
+
+ // TODO: Following is broken for curves due to
+ // move to proper paths.
+
+ // Figure out dimensions so we can do gradient fills
+ // properly
+ if (p) {
+ if (min.x == null || p.x < min.x) {
+ min.x = p.x;
+ }
+ if (max.x == null || p.x > max.x) {
+ max.x = p.x;
+ }
+ if (min.y == null || p.y < min.y) {
+ min.y = p.y;
+ }
+ if (max.y == null || p.y > max.y) {
+ max.y = p.y;
+ }
+ }
+ }
+ lineStr.push(' ">');
+
+ if (!aFill) {
+ appendStroke(this, lineStr);
+ } else {
+ appendFill(this, lineStr, min, max);
+ }
+
+ lineStr.push('</g_vml_:shape>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ function appendStroke(ctx, lineStr) {
+ var a = processStyle(ctx.strokeStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ var lineWidth = ctx.lineScale_ * ctx.lineWidth;
+
+ // VML cannot correctly render a line if the width is less than 1px.
+ // In that case, we dilute the color to make the line look thinner.
+ if (lineWidth < 1) {
+ opacity *= lineWidth;
+ }
+
+ lineStr.push(
+ '<g_vml_:stroke',
+ ' opacity="', opacity, '"',
+ ' joinstyle="', ctx.lineJoin, '"',
+ ' miterlimit="', ctx.miterLimit, '"',
+ ' endcap="', processLineCap(ctx.lineCap), '"',
+ ' weight="', lineWidth, 'px"',
+ ' color="', color, '" />'
+ );
+ }
+
+ function appendFill(ctx, lineStr, min, max) {
+ var fillStyle = ctx.fillStyle;
+ var arcScaleX = ctx.arcScaleX_;
+ var arcScaleY = ctx.arcScaleY_;
+ var width = max.x - min.x;
+ var height = max.y - min.y;
+ if (fillStyle instanceof CanvasGradient_) {
+ // TODO: Gradients transformed with the transformation matrix.
+ var angle = 0;
+ var focus = {x: 0, y: 0};
+
+ // additional offset
+ var shift = 0;
+ // scale factor for offset
+ var expansion = 1;
+
+ if (fillStyle.type_ == 'gradient') {
+ var x0 = fillStyle.x0_ / arcScaleX;
+ var y0 = fillStyle.y0_ / arcScaleY;
+ var x1 = fillStyle.x1_ / arcScaleX;
+ var y1 = fillStyle.y1_ / arcScaleY;
+ var p0 = getCoords(ctx, x0, y0);
+ var p1 = getCoords(ctx, x1, y1);
+ var dx = p1.x - p0.x;
+ var dy = p1.y - p0.y;
+ angle = Math.atan2(dx, dy) * 180 / Math.PI;
+
+ // The angle should be a non-negative number.
+ if (angle < 0) {
+ angle += 360;
+ }
+
+ // Very small angles produce an unexpected result because they are
+ // converted to a scientific notation string.
+ if (angle < 1e-6) {
+ angle = 0;
+ }
+ } else {
+ var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
+ focus = {
+ x: (p0.x - min.x) / width,
+ y: (p0.y - min.y) / height
+ };
+
+ width /= arcScaleX * Z;
+ height /= arcScaleY * Z;
+ var dimension = m.max(width, height);
+ shift = 2 * fillStyle.r0_ / dimension;
+ expansion = 2 * fillStyle.r1_ / dimension - shift;
+ }
+
+ // We need to sort the color stops in ascending order by offset,
+ // otherwise IE won't interpret it correctly.
+ var stops = fillStyle.colors_;
+ stops.sort(function(cs1, cs2) {
+ return cs1.offset - cs2.offset;
+ });
+
+ var length = stops.length;
+ var color1 = stops[0].color;
+ var color2 = stops[length - 1].color;
+ var opacity1 = stops[0].alpha * ctx.globalAlpha;
+ var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
+
+ var colors = [];
+ for (var i = 0; i < length; i++) {
+ var stop = stops[i];
+ colors.push(stop.offset * expansion + shift + ' ' + stop.color);
+ }
+
+ // When colors attribute is used, the meanings of opacity and o:opacity2
+ // are reversed.
+ lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
+ ' method="none" focus="100%"',
+ ' color="', color1, '"',
+ ' color2="', color2, '"',
+ ' colors="', colors.join(','), '"',
+ ' opacity="', opacity2, '"',
+ ' g_o_:opacity2="', opacity1, '"',
+ ' angle="', angle, '"',
+ ' focusposition="', focus.x, ',', focus.y, '" />');
+ } else if (fillStyle instanceof CanvasPattern_) {
+ if (width && height) {
+ var deltaLeft = -min.x;
+ var deltaTop = -min.y;
+ lineStr.push('<g_vml_:fill',
+ ' position="',
+ deltaLeft / width * arcScaleX * arcScaleX, ',',
+ deltaTop / height * arcScaleY * arcScaleY, '"',
+ ' type="tile"',
+ // TODO: Figure out the correct size to fit the scale.
+ //' size="', w, 'px ', h, 'px"',
+ ' src="', fillStyle.src_, '" />');
+ }
+ } else {
+ var a = processStyle(ctx.fillStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
+ '" />');
+ }
+ }
+
+ contextPrototype.fill = function() {
+ this.stroke(true);
+ };
+
+ contextPrototype.closePath = function() {
+ this.currentPath_.push({type: 'close'});
+ };
+
+ function getCoords(ctx, aX, aY) {
+ var m = ctx.m_;
+ return {
+ x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
+ y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
+ };
+ };
+
+ contextPrototype.save = function() {
+ var o = {};
+ copyState(this, o);
+ this.aStack_.push(o);
+ this.mStack_.push(this.m_);
+ this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
+ };
+
+ contextPrototype.restore = function() {
+ if (this.aStack_.length) {
+ copyState(this.aStack_.pop(), this);
+ this.m_ = this.mStack_.pop();
+ }
+ };
+
+ function matrixIsFinite(m) {
+ return isFinite(m[0][0]) && isFinite(m[0][1]) &&
+ isFinite(m[1][0]) && isFinite(m[1][1]) &&
+ isFinite(m[2][0]) && isFinite(m[2][1]);
+ }
+
+ function setM(ctx, m, updateLineScale) {
+ if (!matrixIsFinite(m)) {
+ return;
+ }
+ ctx.m_ = m;
+
+ if (updateLineScale) {
+ // Get the line scale.
+ // Determinant of this.m_ means how much the area is enlarged by the
+ // transformation. So its square root can be used as a scale factor
+ // for width.
+ var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
+ ctx.lineScale_ = sqrt(abs(det));
+ }
+ }
+
+ contextPrototype.translate = function(aX, aY) {
+ var m1 = [
+ [1, 0, 0],
+ [0, 1, 0],
+ [aX, aY, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.rotate = function(aRot) {
+ var c = mc(aRot);
+ var s = ms(aRot);
+
+ var m1 = [
+ [c, s, 0],
+ [-s, c, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.scale = function(aX, aY) {
+ this.arcScaleX_ *= aX;
+ this.arcScaleY_ *= aY;
+ var m1 = [
+ [aX, 0, 0],
+ [0, aY, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
+ var m1 = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
+ var m = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, m, true);
+ };
+
+ /**
+ * The text drawing function.
+ * The maxWidth argument isn't taken in account, since no browser supports
+ * it yet.
+ */
+ contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
+ var m = this.m_,
+ delta = 1000,
+ left = 0,
+ right = delta,
+ offset = {x: 0, y: 0},
+ lineStr = [];
+
+ var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_);
+
+ var fontStyleString = buildStyle(fontStyle);
+
+ var elementStyle = this.element_.currentStyle;
+ var textAlign = this.textAlign.toLowerCase();
+ switch (textAlign) {
+ case 'left':
+ case 'center':
+ case 'right':
+ break;
+ case 'end':
+ textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
+ break;
+ case 'start':
+ textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
+ break;
+ default:
+ textAlign = 'left';
+ }
+
+ // 1.75 is an arbitrary number, as there is no info about the text baseline
+ switch (this.textBaseline) {
+ case 'hanging':
+ case 'top':
+ offset.y = fontStyle.size / 1.75;
+ break;
+ case 'middle':
+ break;
+ default:
+ case null:
+ case 'alphabetic':
+ case 'ideographic':
+ case 'bottom':
+ offset.y = -fontStyle.size / 2.25;
+ break;
+ }
+
+ switch(textAlign) {
+ case 'right':
+ left = delta;
+ right = 0.05;
+ break;
+ case 'center':
+ left = right = delta / 2;
+ break;
+ }
+
+ var d = getCoords(this, x + offset.x, y + offset.y);
+
+ lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
+ ' coordsize="100 100" coordorigin="0 0"',
+ ' filled="', !stroke, '" stroked="', !!stroke,
+ '" style="position:absolute;width:1px;height:1px;">');
+
+ if (stroke) {
+ appendStroke(this, lineStr);
+ } else {
+ // TODO: Fix the min and max params.
+ appendFill(this, lineStr, {x: -left, y: 0},
+ {x: right, y: fontStyle.size});
+ }
+
+ var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
+ m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
+
+ var skewOffset = mr(d.x / Z + 1 - m[0][0]) + ',' + mr(d.y / Z - 2 * m[1][0]);
+
+
+ lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
+ ' offset="', skewOffset, '" origin="', left ,' 0" />',
+ '<g_vml_:path textpathok="true" />',
+ '<g_vml_:textpath on="true" string="',
+ encodeHtmlAttribute(text),
+ '" style="v-text-align:', textAlign,
+ ';font:', encodeHtmlAttribute(fontStyleString),
+ '" /></g_vml_:line>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ contextPrototype.fillText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, false);
+ };
+
+ contextPrototype.strokeText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, true);
+ };
+
+ contextPrototype.measureText = function(text) {
+ if (!this.textMeasureEl_) {
+ var s = '<span style="position:absolute;' +
+ 'top:-20000px;left:0;padding:0;margin:0;border:none;' +
+ 'white-space:pre;"></span>';
+ this.element_.insertAdjacentHTML('beforeEnd', s);
+ this.textMeasureEl_ = this.element_.lastChild;
+ }
+ var doc = this.element_.ownerDocument;
+ this.textMeasureEl_.innerHTML = '';
+ this.textMeasureEl_.style.font = this.font;
+ // Don't use innerHTML or innerText because they allow markup/whitespace.
+ this.textMeasureEl_.appendChild(doc.createTextNode(text));
+ return {width: this.textMeasureEl_.offsetWidth};
+ };
+
+ /******** STUBS ********/
+ contextPrototype.clip = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.arcTo = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.createPattern = function(image, repetition) {
+ return new CanvasPattern_(image, repetition);
+ };
+
+ // Gradient / Pattern Stubs
+ function CanvasGradient_(aType) {
+ this.type_ = aType;
+ this.x0_ = 0;
+ this.y0_ = 0;
+ this.r0_ = 0;
+ this.x1_ = 0;
+ this.y1_ = 0;
+ this.r1_ = 0;
+ this.colors_ = [];
+ }
+
+ CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
+ aColor = processStyle(aColor);
+ this.colors_.push({offset: aOffset,
+ color: aColor.color,
+ alpha: aColor.alpha});
+ };
+
+ function CanvasPattern_(image, repetition) {
+ assertImageIsValid(image);
+ switch (repetition) {
+ case 'repeat':
+ case null:
+ case '':
+ this.repetition_ = 'repeat';
+ break;
+ case 'repeat-x':
+ case 'repeat-y':
+ case 'no-repeat':
+ this.repetition_ = repetition;
+ break;
+ default:
+ throwException('SYNTAX_ERR');
+ }
+
+ this.src_ = image.src;
+ this.width_ = image.width;
+ this.height_ = image.height;
+ }
+
+ function throwException(s) {
+ throw new DOMException_(s);
+ }
+
+ function assertImageIsValid(img) {
+ if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
+ throwException('TYPE_MISMATCH_ERR');
+ }
+ if (img.readyState != 'complete') {
+ throwException('INVALID_STATE_ERR');
+ }
+ }
+
+ function DOMException_(s) {
+ this.code = this[s];
+ this.message = s +': DOM Exception ' + this.code;
+ }
+ var p = DOMException_.prototype = new Error;
+ p.INDEX_SIZE_ERR = 1;
+ p.DOMSTRING_SIZE_ERR = 2;
+ p.HIERARCHY_REQUEST_ERR = 3;
+ p.WRONG_DOCUMENT_ERR = 4;
+ p.INVALID_CHARACTER_ERR = 5;
+ p.NO_DATA_ALLOWED_ERR = 6;
+ p.NO_MODIFICATION_ALLOWED_ERR = 7;
+ p.NOT_FOUND_ERR = 8;
+ p.NOT_SUPPORTED_ERR = 9;
+ p.INUSE_ATTRIBUTE_ERR = 10;
+ p.INVALID_STATE_ERR = 11;
+ p.SYNTAX_ERR = 12;
+ p.INVALID_MODIFICATION_ERR = 13;
+ p.NAMESPACE_ERR = 14;
+ p.INVALID_ACCESS_ERR = 15;
+ p.VALIDATION_ERR = 16;
+ p.TYPE_MISMATCH_ERR = 17;
+
+ // set up externs
+ G_vmlCanvasManager = G_vmlCanvasManager_;
+ CanvasRenderingContext2D = CanvasRenderingContext2D_;
+ CanvasGradient = CanvasGradient_;
+ CanvasPattern = CanvasPattern_;
+ DOMException = DOMException_;
+ G_vmlCanvasManager._version = 888;
+})();
+
+} // if
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright
new file mode 100644
index 00000000..1329729f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright
@@ -0,0 +1,29 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE
new file mode 100644
index 00000000..da4732ec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE
@@ -0,0 +1,21 @@
+Title: MIT License
+
+Copyright (c) 2009-2011 Chris Leonello
+
+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. \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js
new file mode 100644
index 00000000..00b33815
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js
@@ -0,0 +1,313 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // Class: $.jqplot.BezierCurveRenderer.js
+ // Renderer which draws lines as stacked bezier curves.
+ // Data for the line will not be specified as an array of
+ // [x, y] data point values, but as a an array of [start piont, bezier curve]
+ // So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]].
+ $.jqplot.BezierCurveRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer;
+
+
+ // Method: setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ // this._plotData should be same as this.data
+ var data = this.data;
+ this.gridData = [];
+ this._prevGridData = [];
+ // if seriesIndex = 0, fill to x axis.
+ // if seriesIndex > 0, fill to previous series data.
+ var idx = this.index;
+ if (data.length == 2) {
+ if (idx == 0) {
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
+ [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ else {
+ if (idx == 0) {
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
+ [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ };
+
+ // Method: makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var pgd = [];
+ // if seriesIndex = 0, fill to x axis.
+ // if seriesIndex > 0, fill to previous series data.
+ var idx = this.index;
+ if (data.length == 2) {
+ if (idx == 0) {
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
+ [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ else {
+ if (idx == 0) {
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
+ [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) {
+ var i;
+ ctx.save();
+ if (gd.length) {
+ if (this.showLine) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ ctx.fillStyle = opts.fillStyle || this.color;
+ ctx.beginPath();
+ ctx.moveTo(gd[0][0], gd[0][1]);
+ ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]);
+ ctx.lineTo(gd[2][0], gd[2][1]);
+ if (gd[3].length == 2) {
+ ctx.lineTo(gd[3][0], gd[3][1]);
+ }
+ else {
+ ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]);
+ }
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ $.jqplot.BezierAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer;
+
+
+ // Axes on a plot with Bezier Curves
+ $.jqplot.BezierAxisRenderer.prototype.init = function(options){
+ $.extend(true, this, options);
+ var db = this._dataBounds;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s.data;
+ if (d.length == 4) {
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ }
+ else {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[0][0] < db.min || db.min == null) {
+ db.min = d[0][0];
+ }
+ if (d[0][0] > db.max || db.max == null) {
+ db.max = d[0][0];
+ }
+ for (var j=0; j<5; j+=2) {
+ if (d[1][j] < db.min || db.min == null) {
+ db.min = d[1][j];
+ }
+ if (d[1][j] > db.max || db.max == null) {
+ db.max = d[1][j];
+ }
+ }
+ }
+ else {
+ if (d[0][1] < db.min || db.min == null) {
+ db.min = d[0][1];
+ }
+ if (d[0][1] > db.max || db.max == null) {
+ db.max = d[0][1];
+ }
+ for (var j=1; j<6; j+=2) {
+ if (d[1][j] < db.min || db.min == null) {
+ db.min = d[1][j];
+ }
+ if (d[1][j] > db.max || db.max == null) {
+ db.max = d[1][j];
+ }
+ }
+ }
+ }
+ }
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults);
+ options.legend = $.extend(true, {placement:'outside'}, options.legend);
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js
new file mode 100644
index 00000000..c1be235d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js
@@ -0,0 +1,797 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ // Class: $.jqplot.BarRenderer
+ // A plugin renderer for jqPlot to draw a bar plot.
+ // Draws series as a line.
+
+ $.jqplot.BarRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
+
+ // called with scope of series.
+ $.jqplot.BarRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: barPadding
+ // Number of pixels between adjacent bars at the same axis value.
+ this.barPadding = 8;
+ // prop: barMargin
+ // Number of pixels between groups of bars at adjacent axis values.
+ this.barMargin = 10;
+ // prop: barDirection
+ // 'vertical' = up and down bars, 'horizontal' = side to side bars
+ this.barDirection = 'vertical';
+ // prop: barWidth
+ // Width of the bar in pixels (auto by devaul). null = calculated automatically.
+ this.barWidth = null;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.08;
+ // prop: waterfall
+ // true to enable waterfall plot.
+ this.waterfall = false;
+ // prop: groups
+ // group bars into this many groups
+ this.groups = 1;
+ // prop: varyBarColor
+ // true to color each bar of a series separately rather than
+ // have every bar of a given series the same color.
+ // If used for non-stacked multiple series bar plots, user should
+ // specify a separate 'seriesColors' array for each series.
+ // Otherwise, each series will set their bars to the same color array.
+ // This option has no Effect for stacked bar charts and is disabled.
+ this.varyBarColor = false;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a bar.
+ this.highlightColors = [];
+ // prop: transposedData
+ // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and
+ // x and y values are "transposed". Tranposed, or "swapped", data is
+ // required prior to rev. 894 builds of jqPlot with horizontal bars.
+ // Allows backward compatability of bar renderer horizontal bars with
+ // old style data sets.
+ this.transposedData = true;
+ this.renderer.animation = {
+ show: false,
+ direction: 'down',
+ speed: 3000,
+ _supported: true
+ };
+ this._type = 'bar';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ //////
+ // This is probably wrong here.
+ // After going back and forth on wether renderer should be the thing
+ // or extend the thing, it seems that it it best if it is a property
+ // on the thing. This should be something that is commonized
+ // among series renderers in the future.
+ //////
+ $.extend(true, this, options);
+
+ // really should probably do this
+ $.extend(true, this.renderer, options);
+ // fill is still needed to properly draw the legend.
+ // bars have to be filled.
+ this.fill = true;
+
+ // if horizontal bar and animating, reset the default direction
+ if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) {
+ this.renderer.animation.direction = 'left';
+ }
+
+ if (this.waterfall) {
+ this.fillToZero = false;
+ this.disableStack = true;
+ }
+
+ if (this.barDirection == 'vertical' ) {
+ this._primaryAxis = '_xaxis';
+ this._stackAxis = 'y';
+ this.fillAxis = 'y';
+ }
+ else {
+ this._primaryAxis = '_yaxis';
+ this._stackAxis = 'x';
+ this.fillAxis = 'x';
+ }
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // total number of values for all bar series, total number of bar series, and position of this series
+ this._plotSeriesInfo = null;
+ // Array of actual data colors used for each data point.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
+ this.renderer.shapeRenderer.init(opts);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
+ this.renderer.shadowRenderer.init(sopts);
+
+ plot.postInitHooks.addOnce(postInit);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ };
+
+ // called with scope of series
+ function barPreInit(target, data, seriesDefaults, options) {
+ if (this.rendererOptions.barDirection == 'horizontal') {
+ this._stackAxis = 'x';
+ this._primaryAxis = '_yaxis';
+ }
+ if (this.rendererOptions.waterfall == true) {
+ this._data = $.extend(true, [], this.data);
+ var sum = 0;
+ var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0;
+ for(var i=0; i<this.data.length; i++) {
+ sum += this.data[i][pos];
+ if (i>0) {
+ this.data[i][pos] += this.data[i-1][pos];
+ }
+ }
+ this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
+ this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
+ }
+ if (this.rendererOptions.groups > 1) {
+ this.breakOnNull = true;
+ var l = this.data.length;
+ var skip = parseInt(l/this.rendererOptions.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip) {
+ this.data.splice(i+count, 0, [null, null]);
+ this._plotData.splice(i+count, 0, [null, null]);
+ this._stackData.splice(i+count, 0, [null, null]);
+ count++;
+ }
+ for (i=0; i<this.data.length; i++) {
+ if (this._primaryAxis == '_xaxis') {
+ this.data[i][0] = i+1;
+ this._plotData[i][0] = i+1;
+ this._stackData[i][0] = i+1;
+ }
+ else {
+ this.data[i][1] = i+1;
+ this._plotData[i][1] = i+1;
+ this._stackData[i][1] = i+1;
+ }
+ }
+ }
+ }
+
+ $.jqplot.preSeriesInitHooks.push(barPreInit);
+
+ // needs to be called with scope of series, not renderer.
+ $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ // loop through all series on this axis
+ for (var i=0; i < paxis._series.length; i++) {
+ series = paxis._series[i];
+ if (series === this) {
+ pos = i;
+ }
+ // is the series rendered as a bar?
+ if (series.renderer.constructor == $.jqplot.BarRenderer) {
+ // gridData may not be computed yet, use data length insted
+ nvals += series.data.length;
+ nseries += 1;
+ }
+ }
+ // return total number of values for all bar series, total number of bar series, and position of this series
+ return [nvals, nseries, pos];
+ };
+
+ $.jqplot.BarRenderer.prototype.setBarWidth = function() {
+ // need to know how many data values we have on the approprate axis and figure it out.
+ var i;
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ nvals = temp[0];
+ nseries = temp[1];
+ var nticks = paxis.numberTicks;
+ var nbins = (nticks-1)/2;
+ // so, now we have total number of axis values.
+ if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
+ if (this._stack) {
+ this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
+ }
+ else {
+ this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
+ // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
+ }
+ }
+ else {
+ if (this._stack) {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
+ }
+ else {
+ this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
+ // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
+ }
+ }
+ return [nvals, nseries];
+ };
+
+ function computeHighlightColors (colors) {
+ var ret = [];
+ for (var i=0; i<colors.length; i++){
+ var rgba = $.jqplot.getColorComponents(colors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ return ret;
+ }
+
+ function getStart(sidx, didx, comp, plot, axis) {
+ // check if sign change
+ var seriesIndex = sidx,
+ prevSeriesIndex = sidx - 1,
+ start,
+ prevVal,
+ aidx = (axis === 'x') ? 0 : 1;
+
+ // is this not the first series?
+ if (seriesIndex > 0) {
+ prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx];
+
+ // is there a sign change
+ if ((comp * prevVal) < 0) {
+ start = getStart(prevSeriesIndex, didx, comp, plot, axis);
+ }
+
+ // no sign change.
+ else {
+ start = plot.series[prevSeriesIndex].gridData[didx][aidx];
+ }
+
+ }
+
+ // if first series, return value at 0
+ else {
+
+ start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0);
+ }
+
+ return start;
+ }
+
+
+ $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) {
+ var i;
+ // Ughhh, have to make a copy of options b/c it may be modified later.
+ var opts = $.extend({}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xaxis = this.xaxis;
+ var yaxis = this.yaxis;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, pointy;
+ // clear out data colors.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ if (this.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ var nvals = temp[0];
+ var nseries = temp[1];
+ var pos = temp[2];
+ var points = [];
+
+ if (this._stack) {
+ this._barNudge = 0;
+ }
+ else {
+ this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
+ }
+ if (showLine) {
+ var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
+ var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
+ var negativeColor = negativeColors.get(this.index);
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var positiveColor = opts.fillStyle;
+ var base;
+ var xstart;
+ var ystart;
+
+ if (this.barDirection == 'vertical') {
+ for (var i=0; i<gridData.length; i++) {
+ if (!this._stack && this.data[i][1] == null) {
+ continue;
+ }
+ points = [];
+ base = gridData[i][0] + this._barNudge;
+
+ // stacked
+ if (this._stack && this._prevGridData.length) {
+ ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
+ }
+
+ // not stacked
+ else {
+ if (this.fillToZero) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
+ ystart = this.gridData[i-1][1];
+ }
+ else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
+ if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this._yaxis.min > 0) {
+ ystart = ctx.canvas.height;
+ }
+ else {
+ ystart = 0;
+ }
+ }
+ else if (this.waterfall && i == this.gridData.length - 1) {
+ if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this._yaxis.min > 0) {
+ ystart = ctx.canvas.height;
+ }
+ else {
+ ystart = 0;
+ }
+ }
+ else {
+ ystart = ctx.canvas.height;
+ }
+ }
+ if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ else {
+ opts.fillStyle = negativeColor;
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+ if (!this.fillToZero || this._plotData[i][1] >= 0) {
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, ystart]);
+ }
+ // for negative bars make sure points are always ordered clockwise
+ else {
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base+this.barWidth/2, ystart]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ }
+ this._barPoints.push(points);
+ // now draw the shadows if not stacked.
+ // for stacked plots, they are predrawn by drawShadow
+ if (shadow && !this._stack) {
+ var sopts = $.extend(true, {}, opts);
+ // need to get rid of fillStyle on shadow.
+ delete sopts.fillStyle;
+ this.renderer.shadowRenderer.draw(ctx, points, sopts);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+
+ else if (this.barDirection == 'horizontal'){
+ for (var i=0; i<gridData.length; i++) {
+ if (!this._stack && this.data[i][0] == null) {
+ continue;
+ }
+ points = [];
+ base = gridData[i][1] - this._barNudge;
+ xstart;
+
+ if (this._stack && this._prevGridData.length) {
+ xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
+ }
+ // not stacked
+ else {
+ if (this.fillToZero) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
+ xstart = this.gridData[i-1][0];
+ }
+ else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
+ if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this._xaxis.min > 0) {
+ xstart = 0;
+ }
+ else {
+ xstart = 0;
+ }
+ }
+ else if (this.waterfall && i == this.gridData.length - 1) {
+ if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this._xaxis.min > 0) {
+ xstart = 0;
+ }
+ else {
+ xstart = ctx.canvas.width;
+ }
+ }
+ else {
+ xstart = 0;
+ }
+ }
+ if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+
+ if (!this.fillToZero || this._plotData[i][0] >= 0) {
+ points.push([xstart, base + this.barWidth / 2]);
+ points.push([xstart, base - this.barWidth / 2]);
+ points.push([gridData[i][0], base - this.barWidth / 2]);
+ points.push([gridData[i][0], base + this.barWidth / 2]);
+ }
+ else {
+ points.push([gridData[i][0], base + this.barWidth / 2]);
+ points.push([gridData[i][0], base - this.barWidth / 2]);
+ points.push([xstart, base - this.barWidth / 2]);
+ points.push([xstart, base + this.barWidth / 2]);
+ }
+
+ this._barPoints.push(points);
+ // now draw the shadows if not stacked.
+ // for stacked plots, they are predrawn by drawShadow
+ if (shadow && !this._stack) {
+ var sopts = $.extend(true, {}, opts);
+ delete sopts.fillStyle;
+ this.renderer.shadowRenderer.draw(ctx, points, sopts);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+
+ if (this.highlightColors.length == 0) {
+ this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
+ }
+
+ else if (typeof(this.highlightColors) == 'string') {
+ var temp = this.highlightColors;
+ this.highlightColors = [];
+ for (var i=0; i<this._dataColors.length; i++) {
+ this.highlightColors.push(temp);
+ }
+ }
+
+ };
+
+
+ // for stacked plots, shadows will be pre drawn by drawShadow.
+ $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xaxis = this.xaxis;
+ var yaxis = this.yaxis;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, points, pointy, nvals, nseries, pos;
+
+ if (this._stack && this.shadow) {
+ if (this.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ nvals = temp[0];
+ nseries = temp[1];
+ pos = temp[2];
+
+ if (this._stack) {
+ this._barNudge = 0;
+ }
+ else {
+ this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
+ }
+ if (showLine) {
+
+ if (this.barDirection == 'vertical') {
+ for (var i=0; i<gridData.length; i++) {
+ if (this.data[i][1] == null) {
+ continue;
+ }
+ points = [];
+ var base = gridData[i][0] + this._barNudge;
+ var ystart;
+
+ if (this._stack && this._prevGridData.length) {
+ ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
+ }
+ else {
+ if (this.fillToZero) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else {
+ ystart = ctx.canvas.height;
+ }
+ }
+
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, ystart]);
+ this.renderer.shadowRenderer.draw(ctx, points, opts);
+ }
+ }
+
+ else if (this.barDirection == 'horizontal'){
+ for (var i=0; i<gridData.length; i++) {
+ if (this.data[i][0] == null) {
+ continue;
+ }
+ points = [];
+ var base = gridData[i][1] - this._barNudge;
+ var xstart;
+
+ if (this._stack && this._prevGridData.length) {
+ xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
+ }
+ else {
+ if (this.fillToZero) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else {
+ xstart = 0;
+ }
+ }
+
+ points.push([xstart, base+this.barWidth/2]);
+ points.push([gridData[i][0], base+this.barWidth/2]);
+ points.push([gridData[i][0], base-this.barWidth/2]);
+ points.push([xstart, base-this.barWidth/2]);
+ this.renderer.shadowRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+
+ }
+ };
+
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) {
+
+ this.plugins.barRenderer.highlightCanvas.resetCanvas();
+ this.plugins.barRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.barRenderer = {highlightedSeriesIndex:null};
+ this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.barRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.barRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.barRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColors[pidx]};
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.barRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.barRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js
new file mode 100644
index 00000000..5f2bc341
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js
@@ -0,0 +1,235 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.BlockRenderer
+ * Plugin renderer to draw a x-y block chart. A Block chart has data points displayed as
+ * colored squares with a text label inside. Data must be supplied in the form:
+ *
+ * > [[x1, y1, "label 1", {css}], [x2, y2, "label 2", {css}], ...]
+ *
+ * The label and css object are optional. If the label is ommitted, the
+ * box will collapse unless a css height and/or width is specified.
+ *
+ * The css object is an object specifying css properties
+ * such as:
+ *
+ * > {background:'#4f98a5', border:'3px solid gray', padding:'1px'}
+ *
+ * Note that css properties specified with the data point override defaults
+ * specified with the series.
+ *
+ */
+ $.jqplot.BlockRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BlockRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BlockRenderer.prototype.constructor = $.jqplot.BlockRenderer;
+
+ // called with scope of a series
+ $.jqplot.BlockRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: css
+ // default css styles that will be applied to all data blocks.
+ // these values will be overridden by css styles supplied with the
+ // individulal data points.
+ this.css = {padding:'2px', border:'1px solid #999', textAlign:'center'};
+ // prop: escapeHtml
+ // true to escape html in the box label.
+ this.escapeHtml = false;
+ // prop: insertBreaks
+ // true to turn spaces in data block label into html breaks <br />.
+ this.insertBreaks = true;
+ // prop: varyBlockColors
+ // true to vary the color of each block in this series according to
+ // the seriesColors array. False to set each block to the color
+ // specified on this series. This has no effect if a css background color
+ // option is specified in the renderer css options.
+ this.varyBlockColors = false;
+ $.extend(true, this, options);
+ if (this.css.backgroundColor) {
+ this.color = this.css.backgroundColor;
+ }
+ else if (this.css.background) {
+ this.color = this.css.background;
+ }
+ else if (!this.varyBlockColors) {
+ this.css.background = this.color;
+ }
+ this.canvas = new $.jqplot.BlockCanvas();
+ this.shadowCanvas = new $.jqplot.BlockCanvas();
+ this.canvas._plotDimensions = this._plotDimensions;
+ this.shadowCanvas._plotDimensions = this._plotDimensions;
+ this._type = 'block';
+
+ // group: Methods
+ //
+ // Method: moveBlock
+ // Moves an individual block. More efficient than redrawing
+ // the whole series by calling plot.drawSeries().
+ // Properties:
+ // idx - the 0 based index of the block or point in this series.
+ // x - the x coordinate in data units (value on x axis) to move the block to.
+ // y - the y coordinate in data units (value on the y axis) to move the block to.
+ // duration - optional parameter to create an animated movement. Can be a
+ // number (higher is slower animation) or 'fast', 'normal' or 'slow'. If not
+ // provided, the element is moved without any animation.
+ this.moveBlock = function (idx, x, y, duration) {
+ // update plotData, stackData, data and gridData
+ // x and y are in data coordinates.
+ var el = this.canvas._elem.children(':eq('+idx+')');
+ this.data[idx][0] = x;
+ this.data[idx][1] = y;
+ this._plotData[idx][0] = x;
+ this._plotData[idx][1] = y;
+ this._stackData[idx][0] = x;
+ this._stackData[idx][1] = y;
+ this.gridData[idx][0] = this._xaxis.series_u2p(x);
+ this.gridData[idx][1] = this._yaxis.series_u2p(y);
+ var w = el.outerWidth();
+ var h = el.outerHeight();
+ var left = this.gridData[idx][0] - w/2 + 'px';
+ var top = this.gridData[idx][1] - h/2 + 'px';
+ if (duration) {
+ if (parseInt(duration, 10)) {
+ duration = parseInt(duration, 10);
+ }
+ el.animate({left:left, top:top}, duration);
+ }
+ else {
+ el.css({left:left, top:top});
+ }
+ el = null;
+ };
+ };
+
+ // called with scope of series
+ $.jqplot.BlockRenderer.prototype.draw = function (ctx, gd, options) {
+ if (this.plugins.pointLabels) {
+ this.plugins.pointLabels.show = false;
+ }
+ var i, el, d, gd, t, css, w, h, left, top;
+ var opts = (options != undefined) ? options : {};
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ this.canvas._elem.empty();
+ for (i=0; i<this.gridData.length; i++) {
+ d = this.data[i];
+ gd = this.gridData[i];
+ t = '';
+ css = {};
+ if (typeof d[2] == 'string') {
+ t = d[2];
+ }
+ else if (typeof d[2] == 'object') {
+ css = d[2];
+ }
+ if (typeof d[3] == 'object') {
+ css = d[3];
+ }
+ if (this.insertBreaks){
+ t = t.replace(/ /g, '<br />');
+ }
+ css = $.extend(true, {}, this.css, css);
+ // create a div
+ el = $('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>');
+ this.canvas._elem.append(el);
+ // set text
+ this.escapeHtml ? el.text(t) : el.html(t);
+ // style it
+ // remove styles we don't want overridden.
+ delete css.position;
+ delete css.marginRight;
+ delete css.marginLeft;
+ if (!css.background && !css.backgroundColor && !css.backgroundImage){
+ css.background = colorGenerator.next();
+ }
+ el.css(css);
+ w = el.outerWidth();
+ h = el.outerHeight();
+ left = gd[0] - w/2 + 'px';
+ top = gd[1] - h/2 + 'px';
+ el.css({left:left, top:top});
+ el = null;
+ }
+ };
+
+ $.jqplot.BlockCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.BlockCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.BlockCanvas.prototype.constructor = $.jqplot.BlockCanvas;
+
+ $.jqplot.BlockCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
+ this._offsets = offsets;
+ var klass = 'jqplot-blockCanvas';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('div');
+ }
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != undefined) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px';
+ var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px';
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+ return this._elem;
+ };
+
+ $.jqplot.BlockCanvas.prototype.setContext = function() {
+ this._ctx = {
+ canvas:{
+ width:0,
+ height:0
+ },
+ clearRect:function(){return null;}
+ };
+ return this._ctx;
+ };
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js
new file mode 100644
index 00000000..d46f7b77
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js
@@ -0,0 +1,759 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ var arrayMax = function( array ){
+ return Math.max.apply( Math, array );
+ };
+ var arrayMin = function( array ){
+ return Math.min.apply( Math, array );
+ };
+
+ /**
+ * Class: $.jqplot.BubbleRenderer
+ * Plugin renderer to draw a bubble chart. A Bubble chart has data points displayed as
+ * colored circles with an optional text label inside. To use
+ * the bubble renderer, you must include the bubble renderer like:
+ *
+ * > <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.bubbleRenderer.js"></script>
+ *
+ * Data must be supplied in
+ * the form:
+ *
+ * > [[x1, y1, r1, <label or {label:'text', color:color}>], ...]
+ *
+ * where the label or options
+ * object is optional.
+ *
+ * Note that all bubble colors will be the same
+ * unless the "varyBubbleColors" option is set to true. Colors can be specified in the data array
+ * or in the seriesColors array option on the series. If no colors are defined, the default jqPlot
+ * series of 16 colors are used. Colors are automatically cycled around again if there are more
+ * bubbles than colors.
+ *
+ * Bubbles are autoscaled by default to fit within the chart area while maintaining
+ * relative sizes. If the "autoscaleBubbles" option is set to false, the r(adius) values
+ * in the data array a treated as literal pixel values for the radii of the bubbles.
+ *
+ * Properties are passed into the bubble renderer in the rendererOptions object of
+ * the series options like:
+ *
+ * > seriesDefaults: {
+ * > renderer: $.jqplot.BubbleRenderer,
+ * > rendererOptions: {
+ * > bubbleAlpha: 0.7,
+ * > varyBubbleColors: false
+ * > }
+ * > }
+ *
+ */
+ $.jqplot.BubbleRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BubbleRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BubbleRenderer.prototype.constructor = $.jqplot.BubbleRenderer;
+
+ // called with scope of a series
+ $.jqplot.BubbleRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: varyBubbleColors
+ // True to vary the color of each bubble in this series according to
+ // the seriesColors array. False to set each bubble to the color
+ // specified on this series. This has no effect if a css background color
+ // option is specified in the renderer css options.
+ this.varyBubbleColors = true;
+ // prop: autoscaleBubbles
+ // True to scale the bubble radius based on plot size.
+ // False will use the radius value as provided as a raw pixel value for
+ // bubble radius.
+ this.autoscaleBubbles = true;
+ // prop: autoscaleMultiplier
+ // Multiplier the bubble size if autoscaleBubbles is true.
+ this.autoscaleMultiplier = 1.0;
+ // prop: autoscalePointsFactor
+ // Factor which decreases bubble size based on how many bubbles on on the chart.
+ // 0 means no adjustment for number of bubbles. Negative values will decrease
+ // size of bubbles as more bubbles are added. Values between 0 and -0.2
+ // should work well.
+ this.autoscalePointsFactor = -0.07;
+ // prop: escapeHtml
+ // True to escape html in bubble label text.
+ this.escapeHtml = true;
+ // prop: highlightMouseOver
+ // True to highlight bubbles when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a bubble.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // An array of colors to use when highlighting a slice. Calculated automatically
+ // if not supplied.
+ this.highlightColors = [];
+ // prop: bubbleAlpha
+ // Alpha transparency to apply to all bubbles in this series.
+ this.bubbleAlpha = 1.0;
+ // prop: highlightAlpha
+ // Alpha transparency to apply when highlighting bubble.
+ // Set to value of bubbleAlpha by default.
+ this.highlightAlpha = null;
+ // prop: bubbleGradients
+ // True to color the bubbles with gradient fills instead of flat colors.
+ // NOT AVAILABLE IN IE due to lack of excanvas support for radial gradient fills.
+ // will be ignored in IE.
+ this.bubbleGradients = false;
+ // prop: showLabels
+ // True to show labels on bubbles (if any), false to not show.
+ this.showLabels = true;
+ // array of [point index, radius] which will be sorted in descending order to plot
+ // largest points below smaller points.
+ this.radii = [];
+ this.maxRadius = 0;
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // array of jQuery labels.
+ this.labels = [];
+ this.bubbleCanvases = [];
+ this._type = 'bubble';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ if (this.highlightAlpha == null) {
+ this.highlightAlpha = this.bubbleAlpha;
+ if (this.bubbleGradients) {
+ this.highlightAlpha = 0.35;
+ }
+ }
+
+ this.autoscaleMultiplier = this.autoscaleMultiplier * Math.pow(this.data.length, this.autoscalePointsFactor);
+
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // adjust the series colors for options colors passed in with data or for alpha.
+ // note, this can leave undefined holes in the seriesColors array.
+ var comps;
+ for (var i=0; i<this.data.length; i++) {
+ var color = null;
+ var d = this.data[i];
+ this.maxRadius = Math.max(this.maxRadius, d[2]);
+ if (d[3]) {
+ if (typeof(d[3]) == 'object') {
+ color = d[3]['color'];
+ }
+ }
+
+ if (color == null) {
+ if (this.seriesColors[i] != null) {
+ color = this.seriesColors[i];
+ }
+ }
+
+ if (color && this.bubbleAlpha < 1.0) {
+ comps = $.jqplot.getColorComponents(color);
+ color = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', '+this.bubbleAlpha+')';
+ }
+
+ if (color) {
+ this.seriesColors[i] = color;
+ }
+ }
+
+ if (!this.varyBubbleColors) {
+ this.seriesColors = [this.color];
+ }
+
+ this.colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+', '+this.highlightAlpha+')');
+ }
+ }
+
+ this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
+
+ var sopts = {fill:true, isarc:true, angle:this.shadowAngle, alpha:this.shadowAlpha, closePath:true};
+
+ this.renderer.shadowRenderer.init(sopts);
+
+ this.canvas = new $.jqplot.DivCanvas();
+ this.canvas._plotDimensions = this._plotDimensions;
+
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+ };
+
+
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.BubbleRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ this.gridData = [];
+ var radii = [];
+ this.radii = [];
+ var dim = Math.min(plot._height, plot._width);
+ for (var i=0; i<this.data.length; i++) {
+ if (data[i] != null) {
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]);
+ this.radii.push([i, data[i][2]]);
+ radii.push(data[i][2]);
+ }
+ }
+ var r, val, maxr = this.maxRadius = arrayMax(radii);
+ var l = this.gridData.length;
+ if (this.autoscaleBubbles) {
+ for (var i=0; i<l; i++) {
+ val = radii[i]/maxr;
+ r = this.autoscaleMultiplier * dim / 6;
+ this.gridData[i][2] = r * val;
+ }
+ }
+
+ this.radii.sort(function(a, b) { return b[1] - a[1]; });
+ };
+
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.BubbleRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var radii = [];
+ this.radii = [];
+ var dim = Math.min(plot._height, plot._width);
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]);
+ radii.push(data[i][2]);
+ this.radii.push([i, data[i][2]]);
+ }
+ }
+ var r, val, maxr = this.maxRadius = arrayMax(radii);
+ var l = this.gridData.length;
+ if (this.autoscaleBubbles) {
+ for (var i=0; i<l; i++) {
+ val = radii[i]/maxr;
+ r = this.autoscaleMultiplier * dim / 6;
+ gd[i][2] = r * val;
+ }
+ }
+ this.radii.sort(function(a, b) { return b[1] - a[1]; });
+ return gd;
+ };
+
+ // called with scope of series
+ $.jqplot.BubbleRenderer.prototype.draw = function (ctx, gd, options) {
+ if (this.plugins.pointLabels) {
+ this.plugins.pointLabels.show = false;
+ }
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ this.canvas._elem.empty();
+ for (var i=0; i<this.radii.length; i++) {
+ var idx = this.radii[i][0];
+ var t=null;
+ var color = null;
+ var el = null;
+ var tel = null;
+ var d = this.data[idx];
+ var gd = this.gridData[idx];
+ if (d[3]) {
+ if (typeof(d[3]) == 'object') {
+ t = d[3]['label'];
+ }
+ else if (typeof(d[3]) == 'string') {
+ t = d[3];
+ }
+ }
+
+ // color = (this.varyBubbleColors) ? this.colorGenerator.get(idx) : this.color;
+ color = this.colorGenerator.get(idx);
+
+ // If we're drawing a shadow, expand the canvas dimensions to accomodate.
+ var canvasRadius = gd[2];
+ var offset, depth;
+ if (this.shadow) {
+ offset = (0.7 + gd[2]/40).toFixed(1);
+ depth = 1 + Math.ceil(gd[2]/15);
+ canvasRadius += offset*depth;
+ }
+ this.bubbleCanvases[idx] = new $.jqplot.BubbleCanvas();
+ this.canvas._elem.append(this.bubbleCanvases[idx].createElement(gd[0], gd[1], canvasRadius));
+ this.bubbleCanvases[idx].setContext();
+ var ctx = this.bubbleCanvases[idx]._ctx;
+ var x = ctx.canvas.width/2;
+ var y = ctx.canvas.height/2;
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [x, y, gd[2], 0, 2*Math.PI], {offset: offset, depth: depth});
+ }
+ this.bubbleCanvases[idx].draw(gd[2], color, this.bubbleGradients, this.shadowAngle/180*Math.PI);
+
+ // now draw label.
+ if (t && this.showLabels) {
+ tel = $('<div style="position:absolute;" class="jqplot-bubble-label"></div>');
+ if (this.escapeHtml) {
+ tel.text(t);
+ }
+ else {
+ tel.html(t);
+ }
+ this.canvas._elem.append(tel);
+ var h = $(tel).outerHeight();
+ var w = $(tel).outerWidth();
+ var top = gd[1] - 0.5*h;
+ var left = gd[0] - 0.5*w;
+ tel.css({top: top, left: left});
+ this.labels[idx] = $(tel);
+ }
+ }
+ };
+
+
+ $.jqplot.DivCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.DivCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.DivCanvas.prototype.constructor = $.jqplot.DivCanvas;
+
+ $.jqplot.DivCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
+ this._offsets = offsets;
+ var klass = 'jqplot-DivCanvas';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('div');
+ }
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != undefined) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px';
+ var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px';
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+ return this._elem;
+ };
+
+ $.jqplot.DivCanvas.prototype.setContext = function() {
+ this._ctx = {
+ canvas:{
+ width:0,
+ height:0
+ },
+ clearRect:function(){return null;}
+ };
+ return this._ctx;
+ };
+
+ $.jqplot.BubbleCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.BubbleCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.BubbleCanvas.prototype.constructor = $.jqplot.BubbleCanvas;
+
+ // initialize with the x,y pont of bubble center and the bubble radius.
+ $.jqplot.BubbleCanvas.prototype.createElement = function(x, y, r) {
+ var klass = 'jqplot-bubble-point';
+
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('canvas');
+ }
+
+ elem.width = (r != null) ? 2*r : elem.width;
+ elem.height = (r != null) ? 2*r : elem.height;
+ this._elem = $(elem);
+ var l = (x != null && r != null) ? x - r : this._elem.css('left');
+ var t = (y != null && r != null) ? y - r : this._elem.css('top');
+ this._elem.css({ position: 'absolute', left: l, top: t });
+
+ this._elem.addClass(klass);
+ if ($.jqplot.use_excanvas) {
+ window.G_vmlCanvasManager.init_(document);
+ elem = window.G_vmlCanvasManager.initElement(elem);
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.BubbleCanvas.prototype.draw = function(r, color, gradients, angle) {
+ var ctx = this._ctx;
+ // r = Math.floor(r*1.04);
+ // var x = Math.round(ctx.canvas.width/2);
+ // var y = Math.round(ctx.canvas.height/2);
+ var x = ctx.canvas.width/2;
+ var y = ctx.canvas.height/2;
+ ctx.save();
+ if (gradients && !$.jqplot.use_excanvas) {
+ r = r*1.04;
+ var comps = $.jqplot.getColorComponents(color);
+ var colorinner = 'rgba('+Math.round(comps[0]+0.8*(255-comps[0]))+', '+Math.round(comps[1]+0.8*(255-comps[1]))+', '+Math.round(comps[2]+0.8*(255-comps[2]))+', '+comps[3]+')';
+ var colorend = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', 0)';
+ // var rinner = Math.round(0.35 * r);
+ // var xinner = Math.round(x - Math.cos(angle) * 0.33 * r);
+ // var yinner = Math.round(y - Math.sin(angle) * 0.33 * r);
+ var rinner = 0.35 * r;
+ var xinner = x - Math.cos(angle) * 0.33 * r;
+ var yinner = y - Math.sin(angle) * 0.33 * r;
+ var radgrad = ctx.createRadialGradient(xinner, yinner, rinner, x, y, r);
+ radgrad.addColorStop(0, colorinner);
+ radgrad.addColorStop(0.93, color);
+ radgrad.addColorStop(0.96, colorend);
+ radgrad.addColorStop(1, colorend);
+ // radgrad.addColorStop(.98, colorend);
+ ctx.fillStyle = radgrad;
+ ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height);
+ }
+ else {
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ var ang = 2*Math.PI;
+ ctx.arc(x, y, r, 0, ang, 0);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+ };
+
+ $.jqplot.BubbleCanvas.prototype.setContext = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ return this._ctx;
+ };
+
+ $.jqplot.BubbleAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.BubbleAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.BubbleAxisRenderer.prototype.constructor = $.jqplot.BubbleAxisRenderer;
+
+ // called with scope of axis object.
+ $.jqplot.BubbleAxisRenderer.prototype.init = function(options){
+ $.extend(true, this, options);
+ var db = this._dataBounds;
+ var minsidx = 0,
+ minpidx = 0,
+ maxsidx = 0,
+ maxpidx = 0,
+ maxr = 0,
+ minr = 0,
+ minMaxRadius = 0,
+ maxMaxRadius = 0,
+ maxMult = 0,
+ minMult = 0;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s._plotData;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ minsidx=i;
+ minpidx=j;
+ minr = d[j][2];
+ minMaxRadius = s.maxRadius;
+ minMult = s.autoscaleMultiplier;
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ maxsidx=i;
+ maxpidx=j;
+ maxr = d[j][2];
+ maxMaxRadius = s.maxRadius;
+ maxMult = s.autoscaleMultiplier;
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ minsidx=i;
+ minpidx=j;
+ minr = d[j][2];
+ minMaxRadius = s.maxRadius;
+ minMult = s.autoscaleMultiplier;
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ maxsidx=i;
+ maxpidx=j;
+ maxr = d[j][2];
+ maxMaxRadius = s.maxRadius;
+ maxMult = s.autoscaleMultiplier;
+ }
+ }
+ }
+ }
+
+ var minRatio = minr/minMaxRadius;
+ var maxRatio = maxr/maxMaxRadius;
+
+ // need to estimate the effect of the radius on total axis span and adjust axis accordingly.
+ var span = db.max - db.min;
+ // var dim = (this.name == 'xaxis' || this.name == 'x2axis') ? this._plotDimensions.width : this._plotDimensions.height;
+ var dim = Math.min(this._plotDimensions.width, this._plotDimensions.height);
+
+ var minfact = minRatio * minMult/3 * span;
+ var maxfact = maxRatio * maxMult/3 * span;
+ db.max += maxfact;
+ db.min -= minfact;
+ };
+
+ function highlight (plot, sidx, pidx) {
+ plot.plugins.bubbleRenderer.highlightLabelCanvas.empty();
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.bubbleRenderer.highlightCanvas;
+ var ctx = canvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.bubbleRenderer.highlightedSeriesIndex = sidx;
+
+ var color = s.highlightColorGenerator.get(pidx);
+ var x = s.gridData[pidx][0],
+ y = s.gridData[pidx][1],
+ r = s.gridData[pidx][2];
+ ctx.save();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, 2*Math.PI, 0);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ // bring label to front
+ if (s.labels[pidx]) {
+ plot.plugins.bubbleRenderer.highlightLabel = s.labels[pidx].clone();
+ plot.plugins.bubbleRenderer.highlightLabel.appendTo(plot.plugins.bubbleRenderer.highlightLabelCanvas);
+ plot.plugins.bubbleRenderer.highlightLabel.addClass('jqplot-bubble-label-highlight');
+ }
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.bubbleRenderer.highlightCanvas;
+ var sidx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ plot.plugins.bubbleRenderer.highlightLabelCanvas.empty();
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.bubbleRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.bubbleRenderer && this.plugins.bubbleRenderer.highlightCanvas) {
+ this.plugins.bubbleRenderer.highlightCanvas.resetCanvas();
+ this.plugins.bubbleRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.bubbleRenderer = {highlightedSeriesIndex:null};
+ this.plugins.bubbleRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+ this.plugins.bubbleRenderer.highlightLabel = null;
+ this.plugins.bubbleRenderer.highlightLabelCanvas = $('<div style="position:absolute;"></div>');
+ var top = this._gridPadding.top;
+ var left = this._gridPadding.left;
+ var width = this._plotDimensions.width - this._gridPadding.left - this._gridPadding.right;
+ var height = this._plotDimensions.height - this._gridPadding.top - this._gridPadding.bottom;
+ this.plugins.bubbleRenderer.highlightLabelCanvas.css({top:top, left:left, width:width+'px', height:height+'px'});
+
+ this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-bubbleRenderer-highlight-canvas', this._plotDimensions, this));
+ this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightLabelCanvas);
+
+ var hctx = this.plugins.bubbleRenderer.highlightCanvas.setContext();
+ }
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a Bubble series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.BubbleRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.BubbleRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.BubbleAxisRenderer;
+ options.sortData = false;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js
new file mode 100644
index 00000000..18404399
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js
@@ -0,0 +1,203 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.CanvasAxisLabelRenderer
+ * Renderer to draw axis labels with a canvas element to support advanced
+ * featrues such as rotated text. This renderer uses a separate rendering engine
+ * to draw the text on the canvas. Two modes of rendering the text are available.
+ * If the browser has native font support for canvas fonts (currently Mozila 3.5
+ * and Safari 4), you can enable text rendering with the canvas fillText method.
+ * You do so by setting the "enableFontSupport" option to true.
+ *
+ * Browsers lacking native font support will have the text drawn on the canvas
+ * using the Hershey font metrics. Even if the "enableFontSupport" option is true
+ * non-supporting browsers will still render with the Hershey font.
+ *
+ */
+ $.jqplot.CanvasAxisLabelRenderer = function(options) {
+ // Group: Properties
+
+ // prop: angle
+ // angle of text, measured clockwise from x axis.
+ this.angle = 0;
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ // prop: label
+ // label for the axis.
+ this.label = '';
+ // prop: fontFamily
+ // CSS spec for the font-family css attribute.
+ // Applies only to browsers supporting native font rendering in the
+ // canvas tag. Currently Mozilla 3.5 and Safari 4.
+ this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
+ // prop: fontSize
+ // CSS spec for font size.
+ this.fontSize = '11pt';
+ // prop: fontWeight
+ // CSS spec for fontWeight: normal, bold, bolder, lighter or a number 100 - 900
+ this.fontWeight = 'normal';
+ // prop: fontStretch
+ // Multiplier to condense or expand font width.
+ // Applies only to browsers which don't support canvas native font rendering.
+ this.fontStretch = 1.0;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor = '#666666';
+ // prop: enableFontSupport
+ // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
+ // If true, label will be drawn with canvas tag native support for fonts.
+ // If false, label will be drawn with Hershey font metrics.
+ this.enableFontSupport = true;
+ // prop: pt2px
+ // Point to pixel scaling factor, used for computing height of bounding box
+ // around a label. The labels text renderer has a default setting of 1.4, which
+ // should be suitable for most fonts. Leave as null to use default. If tops of
+ // letters appear clipped, increase this. If bounding box seems too big, decrease.
+ // This is an issue only with the native font renderering capabilities of Mozilla
+ // 3.5 and Safari 4 since they do not provide a method to determine the font height.
+ this.pt2px = null;
+
+ this._elem;
+ this._ctx;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+
+ $.extend(true, this, options);
+
+ if (options.angle == null && this.axis != 'xaxis' && this.axis != 'x2axis') {
+ this.angle = -90;
+ }
+
+ var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
+ if (this.pt2px) {
+ ropts.pt2px = this.pt2px;
+ }
+
+ if (this.enableFontSupport) {
+ if ($.jqplot.support_canvas_text()) {
+ this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
+ }
+
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ }
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
+ };
+
+ // return width along the x axis
+ // will check first to see if an element exists.
+ // if not, will return the computed text box width.
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getWidth = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
+ return w;
+ }
+ };
+
+ // return height along the y axis.
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getHeight = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
+ return w;
+ }
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad = function() {
+ var a = this.angle * Math.PI/180;
+ return a;
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ // create a canvas here, but can't draw on it untill it is appended
+ // to dom for IE compatability.
+ var elem = plot.canvasManager.getCanvas();
+
+ this._textRenderer.setText(this.label, ctx);
+ var w = this.getWidth(ctx);
+ var h = this.getHeight(ctx);
+ elem.width = w;
+ elem.height = h;
+ elem.style.width = w;
+ elem.style.height = h;
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute'});
+ this._elem.addClass('jqplot-'+this.axis+'-label');
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.pack = function() {
+ this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js
new file mode 100644
index 00000000..1550c7d0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js
@@ -0,0 +1,243 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.CanvasAxisTickRenderer
+ * Renderer to draw axis ticks with a canvas element to support advanced
+ * featrues such as rotated text. This renderer uses a separate rendering engine
+ * to draw the text on the canvas. Two modes of rendering the text are available.
+ * If the browser has native font support for canvas fonts (currently Mozila 3.5
+ * and Safari 4), you can enable text rendering with the canvas fillText method.
+ * You do so by setting the "enableFontSupport" option to true.
+ *
+ * Browsers lacking native font support will have the text drawn on the canvas
+ * using the Hershey font metrics. Even if the "enableFontSupport" option is true
+ * non-supporting browsers will still render with the Hershey font.
+ */
+ $.jqplot.CanvasAxisTickRenderer = function(options) {
+ // Group: Properties
+
+ // prop: mark
+ // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
+ this.mark = 'outside';
+ // prop: showMark
+ // wether or not to show the mark on the axis.
+ this.showMark = true;
+ // prop: showGridline
+ // wether or not to draw the gridline on the grid at this tick.
+ this.showGridline = true;
+ // prop: isMinorTick
+ // if this is a minor tick.
+ this.isMinorTick = false;
+ // prop: angle
+ // angle of text, measured clockwise from x axis.
+ this.angle = 0;
+ // prop: markSize
+ // Length of the tick marks in pixels. For 'cross' style, length
+ // will be stoked above and below axis, so total length will be twice this.
+ this.markSize = 4;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ // prop: labelPosition
+ // 'auto', 'start', 'middle' or 'end'.
+ // Whether tick label should be positioned so the start, middle, or end
+ // of the tick mark.
+ this.labelPosition = 'auto';
+ this.label = '';
+ this.value = null;
+ this._styles = {};
+ // prop: formatter
+ // A class of a formatter for the tick text.
+ // The default $.jqplot.DefaultTickFormatter uses sprintf.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: prefix
+ // String to prepend to the tick label.
+ // Prefix is prepended to the formatted tick label.
+ this.prefix = '';
+ // prop: fontFamily
+ // css spec for the font-family css attribute.
+ this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
+ // prop: fontSize
+ // CSS spec for font size.
+ this.fontSize = '10pt';
+ // prop: fontWeight
+ // CSS spec for fontWeight
+ this.fontWeight = 'normal';
+ // prop: fontStretch
+ // Multiplier to condense or expand font width.
+ // Applies only to browsers which don't support canvas native font rendering.
+ this.fontStretch = 1.0;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor = '#666666';
+ // prop: enableFontSupport
+ // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
+ // If true, tick label will be drawn with canvas tag native support for fonts.
+ // If false, tick label will be drawn with Hershey font metrics.
+ this.enableFontSupport = true;
+ // prop: pt2px
+ // Point to pixel scaling factor, used for computing height of bounding box
+ // around a label. The labels text renderer has a default setting of 1.4, which
+ // should be suitable for most fonts. Leave as null to use default. If tops of
+ // letters appear clipped, increase this. If bounding box seems too big, decrease.
+ // This is an issue only with the native font renderering capabilities of Mozilla
+ // 3.5 and Safari 4 since they do not provide a method to determine the font height.
+ this.pt2px = null;
+
+ this._elem;
+ this._ctx;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+
+ $.extend(true, this, options);
+
+ var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
+ if (this.pt2px) {
+ ropts.pt2px = this.pt2px;
+ }
+
+ if (this.enableFontSupport) {
+ if ($.jqplot.support_canvas_text()) {
+ this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
+ }
+
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ }
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
+ };
+
+ // return width along the x axis
+ // will check first to see if an element exists.
+ // if not, will return the computed text box width.
+ $.jqplot.CanvasAxisTickRenderer.prototype.getWidth = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
+ return w;
+ }
+ };
+
+ // return height along the y axis.
+ $.jqplot.CanvasAxisTickRenderer.prototype.getHeight = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
+ return w;
+ }
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad = function() {
+ var a = this.angle * Math.PI/180;
+ return a;
+ };
+
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
+ this.value = value;
+ if (isMinor) {
+ this.isMinorTick = true;
+ }
+ return this;
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx, plot) {
+ if (!this.label) {
+ this.label = this.prefix + this.formatter(this.formatString, this.value);
+ }
+
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ // create a canvas here, but can't draw on it untill it is appended
+ // to dom for IE compatability.
+
+ var elem = plot.canvasManager.getCanvas();
+
+ this._textRenderer.setText(this.label, ctx);
+ var w = this.getWidth(ctx);
+ var h = this.getHeight(ctx);
+ // canvases seem to need to have width and heigh attributes directly set.
+ elem.width = w;
+ elem.height = h;
+ elem.style.width = w;
+ elem.style.height = h;
+ elem.style.textAlign = 'left';
+ elem.style.position = 'absolute';
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._elem = $(elem);
+ this._elem.css(this._styles);
+ this._elem.addClass('jqplot-'+this.axis+'-tick');
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.pack = function() {
+ this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js
new file mode 100644
index 00000000..03766206
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js
@@ -0,0 +1,865 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ var objCounter = 0;
+ // class: $.jqplot.CanvasOverlay
+ $.jqplot.CanvasOverlay = function(opts){
+ var options = opts || {};
+ this.options = {
+ show: $.jqplot.config.enablePlugins,
+ deferDraw: false
+ };
+ // prop: objects
+ this.objects = [];
+ this.objectNames = [];
+ this.canvas = null;
+ this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'});
+ this.markerRenderer.init();
+ this.highlightObjectIndex = null;
+ if (options.objects) {
+ var objs = options.objects,
+ obj;
+ for (var i=0; i<objs.length; i++) {
+ obj = objs[i];
+ for (var n in obj) {
+ switch (n) {
+ case 'line':
+ this.addLine(obj[n]);
+ break;
+ case 'horizontalLine':
+ this.addHorizontalLine(obj[n]);
+ break;
+ case 'dashedHorizontalLine':
+ this.addDashedHorizontalLine(obj[n]);
+ break;
+ case 'verticalLine':
+ this.addVerticalLine(obj[n]);
+ break;
+ case 'dashedVerticalLine':
+ this.addDashedVerticalLine(obj[n]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ $.extend(true, this.options, options);
+ };
+
+ // called with scope of a plot object
+ $.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) {
+ var options = opts || {};
+ // add a canvasOverlay attribute to the plot
+ this.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay);
+ };
+
+
+ function LineBase() {
+ this.uid = null;
+ this.type = null;
+ this.gridStart = null;
+ this.gridStop = null;
+ this.tooltipWidthFactor = 0;
+ this.options = {
+ // prop: name
+ // Optional name for the overlay object.
+ // Can be later used to retrieve the object by name.
+ name: null,
+ // prop: show
+ // true to show (draw), false to not draw.
+ show: true,
+ // prop: lineWidth
+ // Width of the line.
+ lineWidth: 2,
+ // prop: lineCap
+ // Type of ending placed on the line ['round', 'butt', 'square']
+ lineCap: 'round',
+ // prop: color
+ // color of the line
+ color: '#666666',
+ // prop: shadow
+ // wether or not to draw a shadow on the line
+ shadow: true,
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ shadowAngle: 45,
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ shadowOffset: 1,
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ shadowDepth: 3,
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ shadowAlpha: '0.07',
+ // prop: xaxis
+ // X axis to use for positioning/scaling the line.
+ xaxis: 'xaxis',
+ // prop: yaxis
+ // Y axis to use for positioning/scaling the line.
+ yaxis: 'yaxis',
+ // prop: showTooltip
+ // Show a tooltip with data point values.
+ showTooltip: false,
+ // prop: showTooltipPrecision
+ // Controls how close to line cursor must be to show tooltip.
+ // Higher number = closer to line, lower number = farther from line.
+ // 1.0 = cursor must be over line.
+ showTooltipPrecision: 0.6,
+ // prop: tooltipLocation
+ // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ tooltipLocation: 'nw',
+ // prop: fadeTooltip
+ // true = fade in/out tooltip, flase = show/hide tooltip
+ fadeTooltip: true,
+ // prop: tooltipFadeSpeed
+ // 'slow', 'def', 'fast', or number of milliseconds.
+ tooltipFadeSpeed: "fast",
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the highlight.
+ tooltipOffset: 4,
+ // prop: tooltipFormatString
+ // Format string passed the x and y values of the cursor on the line.
+ // e.g., 'Dogs: %.2f, Cats: %d'.
+ tooltipFormatString: '%d, %d'
+ };
+ }
+
+ /**
+ * Class: Line
+ * A straight line.
+ */
+ function Line(options) {
+ LineBase.call(this);
+ this.type = 'line';
+ var opts = {
+ // prop: start
+ // [x, y] coordinates for the start of the line.
+ start: [],
+ // prop: stop
+ // [x, y] coordinates for the end of the line.
+ stop: []
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ Line.prototype = new LineBase();
+ Line.prototype.constructor = Line;
+
+
+ /**
+ * Class: HorizontalLine
+ * A straight horizontal line.
+ */
+ function HorizontalLine(options) {
+ LineBase.call(this);
+ this.type = 'horizontalLine';
+ var opts = {
+ // prop: y
+ // y value to position the line
+ y: null,
+ // prop: xmin
+ // x value for the start of the line, null to scale to axis min.
+ xmin: null,
+ // prop: xmax
+ // x value for the end of the line, null to scale to axis max.
+ xmax: null,
+ // prop xOffset
+ // offset ends of the line inside the grid. Number
+ xOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ xminOffset: null,
+ xmaxOffset: null
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ HorizontalLine.prototype = new LineBase();
+ HorizontalLine.prototype.constructor = HorizontalLine;
+
+
+ /**
+ * Class: DashedHorizontalLine
+ * A straight dashed horizontal line.
+ */
+ function DashedHorizontalLine(options) {
+ LineBase.call(this);
+ this.type = 'dashedHorizontalLine';
+ var opts = {
+ y: null,
+ xmin: null,
+ xmax: null,
+ xOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ xminOffset: null,
+ xmaxOffset: null,
+ // prop: dashPattern
+ // Array of line, space settings in pixels.
+ // Default is 8 pixel of line, 8 pixel of space.
+ // Note, limit to a 2 element array b/c of bug with higher order arrays.
+ dashPattern: [8,8]
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ DashedHorizontalLine.prototype = new LineBase();
+ DashedHorizontalLine.prototype.constructor = DashedHorizontalLine;
+
+
+ /**
+ * Class: VerticalLine
+ * A straight vertical line.
+ */
+ function VerticalLine(options) {
+ LineBase.call(this);
+ this.type = 'verticalLine';
+ var opts = {
+ x: null,
+ ymin: null,
+ ymax: null,
+ yOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ yminOffset: null,
+ ymaxOffset: null
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ VerticalLine.prototype = new LineBase();
+ VerticalLine.prototype.constructor = VerticalLine;
+
+
+ /**
+ * Class: DashedVerticalLine
+ * A straight dashed vertical line.
+ */
+ function DashedVerticalLine(options) {
+ LineBase.call(this);
+ this.type = 'dashedVerticalLine';
+ this.start = null;
+ this.stop = null;
+ var opts = {
+ x: null,
+ ymin: null,
+ ymax: null,
+ yOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ yminOffset: null,
+ ymaxOffset: null,
+ // prop: dashPattern
+ // Array of line, space settings in pixels.
+ // Default is 8 pixel of line, 8 pixel of space.
+ // Note, limit to a 2 element array b/c of bug with higher order arrays.
+ dashPattern: [8,8]
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ DashedVerticalLine.prototype = new LineBase();
+ DashedVerticalLine.prototype.constructor = DashedVerticalLine;
+
+ $.jqplot.CanvasOverlay.prototype.addLine = function(opts) {
+ var line = new Line(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) {
+ var line = new HorizontalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) {
+ var line = new DashedHorizontalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) {
+ var line = new VerticalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) {
+ var line = new DashedVerticalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.removeObject = function(idx) {
+ // check if integer, remove by index
+ if ($.type(idx) == 'number') {
+ this.objects.splice(idx, 1);
+ this.objectNames.splice(idx, 1);
+ }
+ // if string, remove by name
+ else {
+ var id = $.inArray(idx, this.objectNames);
+ if (id != -1) {
+ this.objects.splice(id, 1);
+ this.objectNames.splice(id, 1);
+ }
+ }
+ };
+
+ $.jqplot.CanvasOverlay.prototype.getObject = function(idx) {
+ // check if integer, remove by index
+ if ($.type(idx) == 'number') {
+ return this.objects[idx];
+ }
+ // if string, remove by name
+ else {
+ var id = $.inArray(idx, this.objectNames);
+ if (id != -1) {
+ return this.objects[id];
+ }
+ }
+ };
+
+ // Set get as alias for getObject.
+ $.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject;
+
+ $.jqplot.CanvasOverlay.prototype.clear = function(plot) {
+ this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
+ };
+
+ $.jqplot.CanvasOverlay.prototype.draw = function(plot) {
+ var obj,
+ objs = this.objects,
+ mr = this.markerRenderer,
+ start,
+ stop;
+ if (this.options.show) {
+ this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
+ for (var k=0; k<objs.length; k++) {
+ obj = objs[k];
+ var opts = $.extend(true, {}, obj.options);
+ if (obj.options.show) {
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ mr.shadow = obj.options.shadow;
+ obj.tooltipWidthFactor = obj.options.lineWidth / obj.options.showTooltipPrecision;
+ switch (obj.type) {
+ case 'line':
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ mr.style = 'line';
+ opts.closePath = false;
+ start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])];
+ stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])];
+ obj.gridStart = start;
+ obj.gridStop = stop;
+ mr.draw(start, stop, this.canvas._ctx, opts);
+ break;
+ case 'horizontalLine':
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.y != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var xaxis = plot.axes[obj.options.xaxis],
+ xstart,
+ xstop,
+ y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
+ xminoff = obj.options.xminOffset || obj.options.xOffset,
+ xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
+ if (obj.options.xmin != null) {
+ xstart = xaxis.series_u2p(obj.options.xmin);
+ }
+ else if (xminoff != null) {
+ if ($.type(xminoff) == "number") {
+ xstart = xaxis.series_u2p(xaxis.min + xminoff);
+ }
+ else if ($.type(xminoff) == "string") {
+ xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
+ }
+ }
+ if (obj.options.xmax != null) {
+ xstop = xaxis.series_u2p(obj.options.xmax);
+ }
+ else if (xmaxoff != null) {
+ if ($.type(xmaxoff) == "number") {
+ xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
+ }
+ else if ($.type(xmaxoff) == "string") {
+ xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
+ }
+ }
+ if (xstop != null && xstart != null) {
+ obj.gridStart = [xstart, y];
+ obj.gridStop = [xstop, y];
+ mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts);
+ }
+ }
+ break;
+
+ case 'dashedHorizontalLine':
+
+ var dashPat = obj.options.dashPattern;
+ var dashPatLen = 0;
+ for (var i=0; i<dashPat.length; i++) {
+ dashPatLen += dashPat[i];
+ }
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.y != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var xaxis = plot.axes[obj.options.xaxis],
+ xstart,
+ xstop,
+ y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
+ xminoff = obj.options.xminOffset || obj.options.xOffset,
+ xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
+ if (obj.options.xmin != null) {
+ xstart = xaxis.series_u2p(obj.options.xmin);
+ }
+ else if (xminoff != null) {
+ if ($.type(xminoff) == "number") {
+ xstart = xaxis.series_u2p(xaxis.min + xminoff);
+ }
+ else if ($.type(xminoff) == "string") {
+ xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
+ }
+ }
+ if (obj.options.xmax != null) {
+ xstop = xaxis.series_u2p(obj.options.xmax);
+ }
+ else if (xmaxoff != null) {
+ if ($.type(xmaxoff) == "number") {
+ xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
+ }
+ else if ($.type(xmaxoff) == "string") {
+ xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
+ }
+ }
+ if (xstop != null && xstart != null) {
+ obj.gridStart = [xstart, y];
+ obj.gridStop = [xstop, y];
+ var numDash = Math.ceil((xstop - xstart)/dashPatLen);
+ var b=xstart, e;
+ for (var i=0; i<numDash; i++) {
+ for (var j=0; j<dashPat.length; j+=2) {
+ e = b+dashPat[j];
+ mr.draw([b, y], [e, y], this.canvas._ctx, opts);
+ b += dashPat[j];
+ if (j < dashPat.length-1) {
+ b += dashPat[j+1];
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 'verticalLine':
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.x != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var yaxis = plot.axes[obj.options.yaxis],
+ ystart,
+ ystop,
+ x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
+ yminoff = obj.options.yminOffset || obj.options.yOffset,
+ ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
+ if (obj.options.ymin != null) {
+ ystart = yaxis.series_u2p(obj.options.ymin);
+ }
+ else if (yminoff != null) {
+ if ($.type(yminoff) == "number") {
+ ystart = yaxis.series_u2p(yaxis.min - yminoff);
+ }
+ else if ($.type(yminoff) == "string") {
+ ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
+ }
+ }
+ if (obj.options.ymax != null) {
+ ystop = yaxis.series_u2p(obj.options.ymax);
+ }
+ else if (ymaxoff != null) {
+ if ($.type(ymaxoff) == "number") {
+ ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
+ }
+ else if ($.type(ymaxoff) == "string") {
+ ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
+ }
+ }
+ if (ystop != null && ystart != null) {
+ obj.gridStart = [x, ystart];
+ obj.gridStop = [x, ystop];
+ mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts);
+ }
+ }
+ break;
+
+ case 'dashedVerticalLine':
+
+ var dashPat = obj.options.dashPattern;
+ var dashPatLen = 0;
+ for (var i=0; i<dashPat.length; i++) {
+ dashPatLen += dashPat[i];
+ }
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.x != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var yaxis = plot.axes[obj.options.yaxis],
+ ystart,
+ ystop,
+ x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
+ yminoff = obj.options.yminOffset || obj.options.yOffset,
+ ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
+ if (obj.options.ymin != null) {
+ ystart = yaxis.series_u2p(obj.options.ymin);
+ }
+ else if (yminoff != null) {
+ if ($.type(yminoff) == "number") {
+ ystart = yaxis.series_u2p(yaxis.min - yminoff);
+ }
+ else if ($.type(yminoff) == "string") {
+ ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
+ }
+ }
+ if (obj.options.ymax != null) {
+ ystop = yaxis.series_u2p(obj.options.ymax);
+ }
+ else if (ymaxoff != null) {
+ if ($.type(ymaxoff) == "number") {
+ ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
+ }
+ else if ($.type(ymaxoff) == "string") {
+ ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
+ }
+ }
+
+
+ if (ystop != null && ystart != null) {
+ obj.gridStart = [x, ystart];
+ obj.gridStop = [x, ystop];
+ var numDash = Math.ceil((ystart - ystop)/dashPatLen);
+ var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0;
+ var b=ystart, e, bs, es;
+ for (var i=0; i<numDash; i++) {
+ for (var j=0; j<dashPat.length; j+=2) {
+ e = b - dashPat[j];
+ if (e < ystop) {
+ e = ystop;
+ }
+ if (b < ystop) {
+ b = ystop;
+ }
+ // es = e;
+ // if (i == 0) {
+ // es += firstDashAdjust;
+ // }
+ mr.draw([x, b], [x, e], this.canvas._ctx, opts);
+ b -= dashPat[j];
+ if (j < dashPat.length-1) {
+ b -= dashPat[j+1];
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ $.jqplot.CanvasOverlay.postPlotDraw = function() {
+ var co = this.plugins.canvasOverlay;
+ // Memory Leaks patch
+ if (co && co.highlightCanvas) {
+ co.highlightCanvas.resetCanvas();
+ co.highlightCanvas = null;
+ }
+ co.canvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(co.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this));
+ co.canvas.setContext();
+ if (!co.deferDraw) {
+ co.draw(this);
+ }
+
+ var elem = document.createElement('div');
+ co._tooltipElem = $(elem);
+ elem = null;
+ co._tooltipElem.addClass('jqplot-canvasOverlay-tooltip');
+ co._tooltipElem.css({position:'absolute', display:'none'});
+
+ this.eventCanvas._elem.before(co._tooltipElem);
+ this.eventCanvas._elem.bind('mouseleave', { elem: co._tooltipElem }, function (ev) { ev.data.elem.hide(); });
+
+ var co = null;
+ };
+
+
+ function showTooltip(plot, obj, gridpos, datapos) {
+ var co = plot.plugins.canvasOverlay;
+ var elem = co._tooltipElem;
+
+ var opts = obj.options, x, y;
+
+ elem.html($.jqplot.sprintf(opts.tooltipFormatString, datapos[0], datapos[1]));
+
+ switch (opts.tooltipLocation) {
+ case 'nw':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'n':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'ne':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'e':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 's':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 'sw':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 'w':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ }
+
+ elem.css('left', x);
+ elem.css('top', y);
+ if (opts.fadeTooltip) {
+ // Fix for stacked up animations. Thnanks Trevor!
+ elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
+ }
+ else {
+ elem.show();
+ }
+ elem = null;
+ }
+
+
+ function isNearLine(point, lstart, lstop, width) {
+ // r is point to test, p and q are end points.
+ var rx = point[0];
+ var ry = point[1];
+ var px = Math.round(lstop[0]);
+ var py = Math.round(lstop[1]);
+ var qx = Math.round(lstart[0]);
+ var qy = Math.round(lstart[1]);
+
+ var l = Math.sqrt(Math.pow(px-qx, 2) + Math.pow(py-qy, 2));
+
+ // scale error term by length of line.
+ var eps = width*l;
+ var res = Math.abs((qx-px) * (ry-py) - (qy-py) * (rx-px));
+ var ret = (res < eps) ? true : false;
+ return ret;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ var co = plot.plugins.canvasOverlay;
+ var objs = co.objects;
+ var l = objs.length;
+ var obj, haveHighlight=false;
+ var elem;
+ for (var i=0; i<l; i++) {
+ obj = objs[i];
+ if (obj.options.showTooltip) {
+ var n = isNearLine([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor);
+ datapos = [plot.axes[obj.options.xaxis].series_p2u(gridpos.x), plot.axes[obj.options.yaxis].series_p2u(gridpos.y)];
+
+ // cases:
+ // near line, no highlighting
+ // near line, highliting on this line
+ // near line, highlighting another line
+ // not near any line, highlighting
+ // not near any line, no highlighting
+
+ // near line, not currently highlighting
+ if (n && co.highlightObjectIndex == null) {
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+ co.highlightObjectIndex = i;
+ haveHighlight = true;
+ break;
+ }
+
+ // near line, highlighting another line.
+ else if (n && co.highlightObjectIndex !== i) {
+ // turn off tooltip.
+ elem = co._tooltipElem;
+ if (obj.fadeTooltip) {
+ elem.fadeOut(obj.tooltipFadeSpeed);
+ }
+ else {
+ elem.hide();
+ }
+
+ // turn on right tooltip.
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+
+ co.highlightObjectIndex = i;
+ haveHighlight = true;
+ break;
+ }
+
+ // near line, already highlighting this line, update
+ else if (n) {
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+
+ haveHighlight = true;
+ break;
+ }
+ }
+ }
+
+ // check if we are highlighting and not near a line, turn it off.
+ if (!haveHighlight && co.highlightObjectIndex !== null) {
+ elem = co._tooltipElem;
+ obj = co.getObject(co.highlightObjectIndex);
+ if (obj.fadeTooltip) {
+ elem.fadeOut(obj.tooltipFadeSpeed);
+ }
+ else {
+ elem.hide();
+ }
+ co.highlightObjectIndex = null;
+ }
+ }
+
+ $.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit);
+ $.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js
new file mode 100644
index 00000000..53f25305
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js
@@ -0,0 +1,449 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ * included jsDate library by Chris Leonello:
+ *
+ * Copyright (c) 2010-2012 Chris Leonello
+ *
+ * jsDate is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * jsDate borrows many concepts and ideas from the Date Instance
+ * Methods by Ken Snyder along with some parts of Ken's actual code.
+ *
+ * Ken's origianl Date Instance Methods and copyright notice:
+ *
+ * Ken Snyder (ken d snyder at gmail dot com)
+ * 2008-09-10
+ * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
+ * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
+ *
+ * jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
+ * Larry has generously given permission to adapt his code for inclusion
+ * into jqPlot.
+ *
+ * Larry's original code can be found here:
+ *
+ * https://github.com/lsiden/export-jqplot-to-png
+ *
+ *
+ */
+
+(function($) {
+ // This code is a modified version of the canvastext.js code, copyright below:
+ //
+ // This code is released to the public domain by Jim Studt, 2007.
+ // He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
+ //
+ $.jqplot.CanvasTextRenderer = function(options){
+ this.fontStyle = 'normal'; // normal, italic, oblique [not implemented]
+ this.fontVariant = 'normal'; // normal, small caps [not implemented]
+ this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900
+ this.fontSize = '10px';
+ this.fontFamily = 'sans-serif';
+ this.fontStretch = 1.0;
+ this.fillStyle = '#666666';
+ this.angle = 0;
+ this.textAlign = 'start';
+ this.textBaseline = 'alphabetic';
+ this.text;
+ this.width;
+ this.height;
+ this.pt2px = 1.28;
+
+ $.extend(true, this, options);
+ this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
+ this.setHeight();
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
+ this.setHeight();
+ };
+
+ // convert css spec into point size
+ // returns float
+ $.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) {
+ sz = String(sz);
+ var n = parseFloat(sz);
+ if (sz.indexOf('px') > -1) {
+ return n/this.pt2px;
+ }
+ else if (sz.indexOf('pt') > -1) {
+ return n;
+ }
+ else if (sz.indexOf('em') > -1) {
+ return n*12;
+ }
+ else if (sz.indexOf('%') > -1) {
+ return n*12/100;
+ }
+ // default to pixels;
+ else {
+ return n/this.pt2px;
+ }
+ };
+
+
+ $.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) {
+ // w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
+ // return values adjusted for Hershey font.
+ if (Number(w)) {
+ return w/400;
+ }
+ else {
+ switch (w) {
+ case 'normal':
+ return 1;
+ break;
+ case 'bold':
+ return 1.75;
+ break;
+ case 'bolder':
+ return 2.25;
+ break;
+ case 'lighter':
+ return 0.75;
+ break;
+ default:
+ return 1;
+ break;
+ }
+ }
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.getText = function() {
+ return this.text;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) {
+ this.text = t;
+ this.setWidth(ctx);
+ return this;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) {
+ return this.width;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) {
+ if (!w) {
+ this.width = this.measure(ctx, this.text);
+ }
+ else {
+ this.width = w;
+ }
+ return this;
+ };
+
+ // return height in pixels.
+ $.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) {
+ return this.height;
+ };
+
+ // w - height in pt
+ // set heigh in px
+ $.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) {
+ if (!w) {
+ //height = this.fontSize /0.75;
+ this.height = this.normalizedFontSize * this.pt2px;
+ }
+ else {
+ this.height = w;
+ }
+ return this;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.letter = function (ch)
+ {
+ return this.letters[ch];
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.ascent = function()
+ {
+ return this.normalizedFontSize;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.descent = function()
+ {
+ return 7.0*this.normalizedFontSize/25.0;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str)
+ {
+ var total = 0;
+ var len = str.length;
+
+ for (var i = 0; i < len; i++) {
+ var c = this.letter(str.charAt(i));
+ if (c) {
+ total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch;
+ }
+ }
+ return total;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str)
+ {
+ var x = 0;
+ // leave room at bottom for descenders.
+ var y = this.height*0.72;
+ var total = 0;
+ var len = str.length;
+ var mag = this.normalizedFontSize / 25.0;
+
+ ctx.save();
+ var tx, ty;
+
+ // 1st quadrant
+ if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
+ tx = 0;
+ ty = -Math.sin(this.angle) * this.width;
+ }
+ // 4th quadrant
+ else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
+ tx = Math.sin(this.angle) * this.height;
+ ty = 0;
+ }
+ // 2nd quadrant
+ else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
+ tx = -Math.cos(this.angle) * this.width;
+ ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
+ }
+ // 3rd quadrant
+ else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
+ tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
+ ty = -Math.cos(this.angle) * this.height;
+ }
+
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fillStyle = this.fillStyle;
+ ctx.translate(tx, ty);
+ ctx.rotate(this.angle);
+ ctx.lineCap = "round";
+ // multiplier was 2.0
+ var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20;
+ ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight);
+
+ for ( var i = 0; i < len; i++) {
+ var c = this.letter( str.charAt(i));
+ if ( !c) {
+ continue;
+ }
+
+ ctx.beginPath();
+
+ var penUp = 1;
+ var needStroke = 0;
+ for ( var j = 0; j < c.points.length; j++) {
+ var a = c.points[j];
+ if ( a[0] == -1 && a[1] == -1) {
+ penUp = 1;
+ continue;
+ }
+ if ( penUp) {
+ ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
+ penUp = false;
+ } else {
+ ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
+ }
+ }
+ ctx.stroke();
+ x += c.width*mag*this.fontStretch;
+ }
+ ctx.restore();
+ return total;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.letters = {
+ ' ': { width: 16, points: [] },
+ '!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] },
+ '#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] },
+ '$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ '%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
+ '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
+ '\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
+ '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
+ ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
+ '*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] },
+ '+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] },
+ ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '-': { width: 18, points: [[6,9],[12,9]] },
+ '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '/': { width: 22, points: [[20,25],[2,-7]] },
+ '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
+ '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
+ '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
+ '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] },
+ '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
+ '7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] },
+ '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
+ '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
+ ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '<': { width: 24, points: [[20,18],[4,9],[20,0]] },
+ '=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] },
+ '>': { width: 24, points: [[4,18],[20,9],[4,0]] },
+ '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] },
+ '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] },
+ 'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] },
+ 'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
+ 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
+ 'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
+ 'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] },
+ 'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] },
+ 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] },
+ 'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] },
+ 'I': { width: 8, points: [[4,21],[4,0]] },
+ 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
+ 'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] },
+ 'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] },
+ 'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] },
+ 'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] },
+ 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
+ 'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
+ 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] },
+ 'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] },
+ 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ 'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] },
+ 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
+ 'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] },
+ 'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] },
+ 'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] },
+ 'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] },
+ 'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] },
+ '[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] },
+ '\\': { width: 14, points: [[0,21],[14,-3]] },
+ ']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] },
+ '^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] },
+ '_': { width: 16, points: [[0,-2],[16,-2]] },
+ '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
+ 'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] },
+ 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] },
+ 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
+ 'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] },
+ 'l': { width: 8, points: [[4,21],[4,0]] },
+ 'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
+ 'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
+ 'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] },
+ 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
+ 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] },
+ 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] },
+ 'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] },
+ 'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] },
+ 'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] },
+ 'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
+ 'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] },
+ '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
+ '|': { width: 8, points: [[4,25],[4,-7]] },
+ '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
+ '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] }
+ };
+
+ $.jqplot.CanvasFontRenderer = function(options) {
+ options = options || {};
+ if (!options.pt2px) {
+ options.pt2px = 1.5;
+ }
+ $.jqplot.CanvasTextRenderer.call(this, options);
+ };
+
+ $.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({});
+ $.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer;
+
+ $.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str)
+ {
+ // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
+ var fstyle = this.fontSize+' '+this.fontFamily;
+ ctx.save();
+ ctx.font = fstyle;
+ var w = ctx.measureText(str).width;
+ ctx.restore();
+ return w;
+ };
+
+ $.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str)
+ {
+ var x = 0;
+ // leave room at bottom for descenders.
+ var y = this.height*0.72;
+ //var y = 12;
+
+ ctx.save();
+ var tx, ty;
+
+ // 1st quadrant
+ if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
+ tx = 0;
+ ty = -Math.sin(this.angle) * this.width;
+ }
+ // 4th quadrant
+ else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
+ tx = Math.sin(this.angle) * this.height;
+ ty = 0;
+ }
+ // 2nd quadrant
+ else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
+ tx = -Math.cos(this.angle) * this.width;
+ ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
+ }
+ // 3rd quadrant
+ else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
+ tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
+ ty = -Math.cos(this.angle) * this.height;
+ }
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fillStyle = this.fillStyle;
+ // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
+ var fstyle = this.fontSize+' '+this.fontFamily;
+ ctx.font = fstyle;
+ ctx.translate(tx, ty);
+ ctx.rotate(this.angle);
+ ctx.fillText(str, x, y);
+ // ctx.strokeText(str, x, y);
+
+ ctx.restore();
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js
new file mode 100644
index 00000000..4cea2de6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js
@@ -0,0 +1,673 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * class: $.jqplot.CategoryAxisRenderer
+ * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}}
+ **/
+ $.jqplot.CategoryAxisRenderer = function(options) {
+ $.jqplot.LinearAxisRenderer.call(this);
+ // prop: sortMergedLabels
+ // True to sort tick labels when labels are created by merging
+ // x axis values from multiple series. That is, say you have
+ // two series like:
+ // > line1 = [[2006, 4], [2008, 9], [2009, 16]];
+ // > line2 = [[2006, 3], [2007, 7], [2008, 6]];
+ // If no label array is specified, tick labels will be collected
+ // from the x values of the series. With sortMergedLabels
+ // set to true, tick labels will be:
+ // > [2006, 2007, 2008, 2009]
+ // With sortMergedLabels set to false, tick labels will be:
+ // > [2006, 2008, 2009, 2007]
+ //
+ // Note, this property is specified on the renderOptions for the
+ // axes when creating a plot:
+ // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}}
+ this.sortMergedLabels = false;
+ };
+
+ $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
+
+ $.jqplot.CategoryAxisRenderer.prototype.init = function(options){
+ this.groups = 1;
+ this.groupLabels = [];
+ this._groupLabels = [];
+ this._grouped = false;
+ this._barsPerGroup = null;
+ this.reverse = false;
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ // this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ $.extend(true, this, {tickOptions:{formatString:'%d'}}, options);
+ var db = this._dataBounds;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ if (s.groups) {
+ this.groups = s.groups;
+ }
+ var d = s.data;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ }
+
+ if (this.groupLabels.length) {
+ this.groups = this.groupLabels.length;
+ }
+ };
+
+
+ $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim, interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+
+ // if we already have ticks, use them.
+ if (userTicks.length) {
+ // adjust with blanks if we have groups
+ if (this.groups > 1 && !this._grouped) {
+ var l = userTicks.length;
+ var skip = parseInt(l/this.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip) {
+ userTicks.splice(i+count, 0, ' ');
+ count++;
+ }
+ this._grouped = true;
+ }
+ this.min = 0.5;
+ this.max = userTicks.length + 0.5;
+ var range = this.max - this.min;
+ this.numberTicks = 2*userTicks.length + 1;
+ for (i=0; i<userTicks.length; i++){
+ tt = this.min + 2 * i * range / (this.numberTicks-1);
+ // need a marker before and after the tick
+ var t = new this.tickRenderer(this.tickOptions);
+ t.showLabel = false;
+ // t.showMark = true;
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ var t = new this.tickRenderer(this.tickOptions);
+ t.label = userTicks[i];
+ // t.showLabel = true;
+ t.showMark = false;
+ t.showGridline = false;
+ t.setTick(tt+0.5, this.name);
+ this._ticks.push(t);
+ }
+ // now add the last tick at the end
+ var t = new this.tickRenderer(this.tickOptions);
+ t.showLabel = false;
+ // t.showMark = true;
+ t.setTick(tt+1, this.name);
+ this._ticks.push(t);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ // if max, min, and interval specified and interval won't fit, ignore interval.
+ if (this.min != null && this.max != null && this.tickInterval != null) {
+ if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
+ this.tickInterval = null;
+ }
+ }
+
+ // find out how many categories are in the lines and collect labels
+ var labels = [];
+ var numcats = 0;
+ var min = 0.5;
+ var max, val;
+ var isMerged = false;
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ for (var j=0; j<s.data.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ val = s.data[j][0];
+ }
+ else {
+ val = s.data[j][1];
+ }
+ if ($.inArray(val, labels) == -1) {
+ isMerged = true;
+ numcats += 1;
+ labels.push(val);
+ }
+ }
+ }
+
+ if (isMerged && this.sortMergedLabels) {
+ labels.sort(function(a,b) { return a - b; });
+ }
+
+ // keep a reference to these tick labels to use for redrawing plot (see bug #57)
+ this.ticks = labels;
+
+ // now bin the data values to the right lables.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ for (var j=0; j<s.data.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ val = s.data[j][0];
+ }
+ else {
+ val = s.data[j][1];
+ }
+ // for category axis, force the values into category bins.
+ // we should have the value in the label array now.
+ var idx = $.inArray(val, labels)+1;
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ s.data[j][0] = idx;
+ }
+ else {
+ s.data[j][1] = idx;
+ }
+ }
+ }
+
+ // adjust with blanks if we have groups
+ if (this.groups > 1 && !this._grouped) {
+ var l = labels.length;
+ var skip = parseInt(l/this.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip+1) {
+ labels[i] = ' ';
+ }
+ this._grouped = true;
+ }
+
+ max = numcats + 0.5;
+ if (this.numberTicks == null) {
+ this.numberTicks = 2*numcats + 1;
+ }
+
+ var range = max - min;
+ this.min = min;
+ this.max = max;
+ var track = 0;
+
+ // todo: adjust this so more ticks displayed.
+ var maxVisibleTicks = parseInt(3+dim/10, 10);
+ var skip = parseInt(numcats/maxVisibleTicks, 10);
+
+ if (this.tickInterval == null) {
+
+ this.tickInterval = range / (this.numberTicks-1);
+
+ }
+ // if tickInterval is specified, we will ignore any computed maximum.
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ var t = new this.tickRenderer(this.tickOptions);
+ // if even tick, it isn't a category, it's a divider
+ if (i/2 == parseInt(i/2, 10)) {
+ t.showLabel = false;
+ t.showMark = true;
+ }
+ else {
+ if (skip>0 && track<skip) {
+ t.showLabel = false;
+ track += 1;
+ }
+ else {
+ t.showLabel = true;
+ track = 0;
+ }
+ t.label = t.formatter(t.formatString, labels[(i-1)/2]);
+ t.showMark = false;
+ t.showGridline = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // this._elem.empty();
+ // Memory Leaks patch
+ this._elem.emptyForce();
+ }
+
+ this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ }
+
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ var elem = tick.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ }
+ }
+
+ this._groupLabels = [];
+ // now make group labels
+ for (var i=0; i<this.groupLabels.length; i++)
+ {
+ var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>');
+ elem.html(this.groupLabels[i]);
+ this._groupLabels.push(elem);
+ elem.appendTo(this._elem);
+ }
+ }
+ return this._elem;
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ var dim2 = 0;
+ for (var i=0; i<this._groupLabels.length; i++) {
+ var l = this._groupLabels[i];
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = l.outerHeight(true);
+ }
+ else {
+ temp = l.outerWidth(true);
+ }
+ if (temp > dim2) {
+ dim2 = temp;
+ }
+ }
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim += dim2 + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim += dim2 + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim += dim2 + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim += dim2 + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) {
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+ var i;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ if (!this.reverse) {
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ else {
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+
+ this.u2p = function(u){
+ return offmin + (max - u) * pixellength / unitlength;
+ };
+
+ this.p2u = function(p){
+ return min + (p - offmin) * unitlength / pixellength;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (max - u) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (min - u) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ }
+
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+
+ var labeledge=['bottom', 0];
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ labeledge = ['bottom', this._label._elem.outerHeight(true)];
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ labeledge = ['top', this._label._elem.outerHeight(true)];
+ }
+ this._label.pack();
+ }
+
+ // draw the group labels
+ var step = parseInt(this._ticks.length/this.groups, 10);
+ for (i=0; i<this._groupLabels.length; i++) {
+ var mid = 0;
+ var count = 0;
+ for (var j=i*step; j<=(i+1)*step; j++) {
+ if (this._ticks[j]._elem && this._ticks[j].label != " ") {
+ var t = this._ticks[j]._elem;
+ var p = t.position();
+ mid += p.left + t.outerWidth(true)/2;
+ count++;
+ }
+ }
+ mid = mid/count;
+ this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)});
+ this._groupLabels[i].css(labeledge[0], labeledge[1]);
+ }
+ }
+ else {
+ for (i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+
+ var labeledge=['left', 0];
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ labeledge = ['left', this._label._elem.outerWidth(true)];
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ labeledge = ['right', this._label._elem.outerWidth(true)];
+ }
+ this._label.pack();
+ }
+
+ // draw the group labels, position top here, do left after label position.
+ var step = parseInt(this._ticks.length/this.groups, 10);
+ for (i=0; i<this._groupLabels.length; i++) {
+ var mid = 0;
+ var count = 0;
+ for (var j=i*step; j<=(i+1)*step; j++) {
+ if (this._ticks[j]._elem && this._ticks[j].label != " ") {
+ var t = this._ticks[j]._elem;
+ var p = t.position();
+ mid += p.top + t.outerHeight()/2;
+ count++;
+ }
+ }
+ mid = mid/count;
+ this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2});
+ this._groupLabels[i].css(labeledge[0], labeledge[1]);
+
+ }
+ }
+ }
+ };
+
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js
new file mode 100644
index 00000000..22401dc7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js
@@ -0,0 +1,116 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.ciParser
+ * Data Renderer function which converts a custom JSON data object into jqPlot data format.
+ * Set this as a callable on the jqplot dataRenderer plot option:
+ *
+ * > plot = $.jqplot('mychart', [data], { dataRenderer: $.jqplot.ciParser, ... });
+ *
+ * Where data is an object in JSON format or a JSON encoded string conforming to the
+ * City Index API spec.
+ *
+ * Note that calling the renderer function is handled internally by jqPlot. The
+ * user does not have to call the function. The parameters described below will
+ * automatically be passed to the ciParser function.
+ *
+ * Parameters:
+ * data - JSON encoded string or object.
+ * plot - reference to jqPlot Plot object.
+ *
+ * Returns:
+ * data array in jqPlot format.
+ *
+ */
+ $.jqplot.ciParser = function (data, plot) {
+ var ret = [],
+ line,
+ temp,
+ i, j, k, kk;
+
+ if (typeof(data) == "string") {
+ data = $.jqplot.JSON.parse(data, handleStrings);
+ }
+
+ else if (typeof(data) == "object") {
+ for (k in data) {
+ for (i=0; i<data[k].length; i++) {
+ for (kk in data[k][i]) {
+ data[k][i][kk] = handleStrings(kk, data[k][i][kk]);
+ }
+ }
+ }
+ }
+
+ else {
+ return null;
+ }
+
+ // function handleStrings
+ // Checks any JSON encoded strings to see if they are
+ // encoded dates. If so, pull out the timestamp.
+ // Expects dates to be represented by js timestamps.
+
+ function handleStrings(key, value) {
+ var a;
+ if (value != null) {
+ if (value.toString().indexOf('Date') >= 0) {
+ //here we will try to extract the ticks from the Date string in the "value" fields of JSON returned data
+ a = /^\/Date\((-?[0-9]+)\)\/$/.exec(value);
+ if (a) {
+ return parseInt(a[1], 10);
+ }
+ }
+ return value;
+ }
+ }
+
+ for (var prop in data) {
+ line = [];
+ temp = data[prop];
+ switch (prop) {
+ case "PriceTicks":
+ for (i=0; i<temp.length; i++) {
+ line.push([temp[i]['TickDate'], temp[i]['Price']]);
+ }
+ break;
+ case "PriceBars":
+ for (i=0; i<temp.length; i++) {
+ line.push([temp[i]['BarDate'], temp[i]['Open'], temp[i]['High'], temp[i]['Low'], temp[i]['Close']]);
+ }
+ break;
+ }
+ ret.push(line);
+ }
+ return ret;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js
new file mode 100644
index 00000000..0e583682
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js
@@ -0,0 +1,1108 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Cursor
+ * Plugin class representing the cursor as displayed on the plot.
+ */
+ $.jqplot.Cursor = function(options) {
+ // Group: Properties
+ //
+ // prop: style
+ // CSS spec for cursor style
+ this.style = 'crosshair';
+ this.previousCursor = 'auto';
+ // prop: show
+ // wether to show the cursor or not.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: showTooltip
+ // show a cursor position tooltip. Location of the tooltip
+ // will be controlled by followMouse and tooltipLocation.
+ this.showTooltip = true;
+ // prop: followMouse
+ // Tooltip follows the mouse, it is not at a fixed location.
+ // Tooltip will show on the grid at the location given by
+ // tooltipLocation, offset from the grid edge by tooltipOffset.
+ this.followMouse = false;
+ // prop: tooltipLocation
+ // Where to position tooltip. If followMouse is true, this is
+ // relative to the cursor, otherwise, it is relative to the grid.
+ // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'se';
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the grid boudaries or cursor center.
+ this.tooltipOffset = 6;
+ // prop: showTooltipGridPosition
+ // show the grid pixel coordinates of the mouse.
+ this.showTooltipGridPosition = false;
+ // prop: showTooltipUnitPosition
+ // show the unit (data) coordinates of the mouse.
+ this.showTooltipUnitPosition = true;
+ // prop: showTooltipDataPosition
+ // Used with showVerticalLine to show intersecting data points in the tooltip.
+ this.showTooltipDataPosition = false;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference
+ // Note, if showTooltipDataPosition is true, the default tooltipFormatString
+ // will be set to the cursorLegendFormatString, not the default given here.
+ this.tooltipFormatString = '%.4P, %.4P';
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipAxisGroups
+ // Show position for the specified axes.
+ // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']]
+ // Default is to compute automatically for all visible axes.
+ this.tooltipAxisGroups = [];
+ // prop: zoom
+ // Enable plot zooming.
+ this.zoom = false;
+ // zoomProxy and zoomTarget properties are not directly set by user.
+ // They Will be set through call to zoomProxy method.
+ this.zoomProxy = false;
+ this.zoomTarget = false;
+ // prop: looseZoom
+ // Will expand zoom range to provide more rounded tick values.
+ // Works only with linear, log and date axes.
+ this.looseZoom = true;
+ // prop: clickReset
+ // Will reset plot zoom if single click on plot without drag.
+ this.clickReset = false;
+ // prop: dblClickReset
+ // Will reset plot zoom if double click on plot without drag.
+ this.dblClickReset = true;
+ // prop: showVerticalLine
+ // draw a vertical line across the plot which follows the cursor.
+ // When the line is near a data point, a special legend and/or tooltip can
+ // be updated with the data values.
+ this.showVerticalLine = false;
+ // prop: showHorizontalLine
+ // draw a horizontal line across the plot which follows the cursor.
+ this.showHorizontalLine = false;
+ // prop: constrainZoomTo
+ // 'none', 'x' or 'y'
+ this.constrainZoomTo = 'none';
+ // // prop: autoscaleConstraint
+ // // when a constrained axis is specified, true will
+ // // auatoscale the adjacent axis.
+ // this.autoscaleConstraint = true;
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}};
+ this._tooltipElem;
+ this.zoomCanvas;
+ this.cursorCanvas;
+ // prop: intersectionThreshold
+ // pixel distance from data point or marker to consider cursor lines intersecting with point.
+ // If data point markers are not shown, this should be >= 1 or will often miss point intersections.
+ this.intersectionThreshold = 2;
+ // prop: showCursorLegend
+ // Replace the plot legend with an enhanced legend displaying intersection information.
+ this.showCursorLegend = false;
+ // prop: cursorLegendFormatString
+ // Format string used in the cursor legend. If showTooltipDataPosition is true,
+ // this will also be the default format string used by tooltipFormatString.
+ this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ // whether the cursor is over the grid or not.
+ this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null};
+ // prop: constrainOutsideZoom
+ // True to limit actual zoom area to edges of grid, even when zooming
+ // outside of plot area. That is, can't zoom out by mousing outside plot.
+ this.constrainOutsideZoom = true;
+ // prop: showTooltipOutsideZoom
+ // True will keep updating the tooltip when zooming of the grid.
+ this.showTooltipOutsideZoom = false;
+ // true if mouse is over grid, false if not.
+ this.onGrid = false;
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s';
+
+ // called with scope of plot
+ $.jqplot.Cursor.init = function (target, data, opts){
+ // add a cursor attribute to the plot
+ var options = opts || {};
+ this.plugins.cursor = new $.jqplot.Cursor(options.cursor);
+ var c = this.plugins.cursor;
+
+ if (c.show) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]);
+
+ if (c.showCursorLegend) {
+ opts.legend = opts.legend || {};
+ opts.legend.renderer = $.jqplot.CursorLegendRenderer;
+ opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString;
+ opts.legend.show = true;
+ }
+
+ if (c.zoom) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]);
+
+ if (c.clickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]);
+ }
+
+ if (c.dblClickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]);
+ }
+ }
+
+ this.resetZoom = function() {
+ var axes = this.axes;
+ if (!c.zoomProxy) {
+ for (var ax in axes) {
+ axes[ax].reset();
+ axes[ax]._ticks = [];
+ // fake out tick creation algorithm to make sure original auto
+ // computed format string is used if _overrideFormatString is true
+ if (c._zoom.axes[ax] !== undefined) {
+ axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString;
+ }
+ }
+ this.redraw();
+ }
+ else {
+ var ctx = this.plugins.cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ this.plugins.cursor._zoom.isZoomed = false;
+ this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]);
+ };
+
+
+ if (c.showTooltipDataPosition) {
+ c.showTooltipUnitPosition = false;
+ c.showTooltipGridPosition = false;
+ if (options.cursor.tooltipFormatString == undefined) {
+ c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ }
+ }
+ }
+ };
+
+ // called with context of plot
+ $.jqplot.Cursor.postDraw = function() {
+ var c = this.plugins.cursor;
+
+ // Memory Leaks patch
+ if (c.zoomCanvas) {
+ c.zoomCanvas.resetCanvas();
+ c.zoomCanvas = null;
+ }
+
+ if (c.cursorCanvas) {
+ c.cursorCanvas.resetCanvas();
+ c.cursorCanvas = null;
+ }
+
+ if (c._tooltipElem) {
+ c._tooltipElem.emptyForce();
+ c._tooltipElem = null;
+ }
+
+
+ if (c.zoom) {
+ c.zoomCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this));
+ c.zoomCanvas.setContext();
+ }
+
+ var elem = document.createElement('div');
+ c._tooltipElem = $(elem);
+ elem = null;
+ c._tooltipElem.addClass('jqplot-cursor-tooltip');
+ c._tooltipElem.css({position:'absolute', display:'none'});
+
+
+ if (c.zoomCanvas) {
+ c.zoomCanvas._elem.before(c._tooltipElem);
+ }
+
+ else {
+ this.eventCanvas._elem.before(c._tooltipElem);
+ }
+
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ c.cursorCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this));
+ c.cursorCanvas.setContext();
+ }
+
+ // if we are showing the positions in unit coordinates, and no axes groups
+ // were specified, create a default set.
+ if (c.showTooltipUnitPosition){
+ if (c.tooltipAxisGroups.length === 0) {
+ var series = this.series;
+ var s;
+ var temp = [];
+ for (var i=0; i<series.length; i++) {
+ s = series[i];
+ var ax = s.xaxis+','+s.yaxis;
+ if ($.inArray(ax, temp) == -1) {
+ temp.push(ax);
+ }
+ }
+ for (var i=0; i<temp.length; i++) {
+ c.tooltipAxisGroups.push(temp[i].split(','));
+ }
+ }
+ }
+ };
+
+ // Group: methods
+ //
+ // method: $.jqplot.Cursor.zoomProxy
+ // links targetPlot to controllerPlot so that plot zooming of
+ // targetPlot will be controlled by zooming on the controllerPlot.
+ // controllerPlot will not actually zoom, but acts as an
+ // overview plot. Note, the zoom options must be set to true for
+ // zoomProxy to work.
+ $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) {
+ var tc = targetPlot.plugins.cursor;
+ var cc = controllerPlot.plugins.cursor;
+ tc.zoomTarget = true;
+ tc.zoom = true;
+ tc.style = 'auto';
+ tc.dblClickReset = false;
+ cc.zoom = true;
+ cc.zoomProxy = true;
+
+ controllerPlot.target.bind('jqplotZoom', plotZoom);
+ controllerPlot.target.bind('jqplotResetZoom', plotReset);
+
+ function plotZoom(ev, gridpos, datapos, plot, cursor) {
+ tc.doZoom(gridpos, datapos, targetPlot, cursor);
+ }
+
+ function plotReset(ev, plot, cursor) {
+ targetPlot.resetZoom();
+ }
+ };
+
+ $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) {
+ var axes = plot.axes;
+ var cax = cursor._zoom.axes;
+ if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) {
+ for (var ax in axes) {
+ // axes[ax]._ticks = [];
+ // axes[ax].min = cax[ax].min;
+ // axes[ax].max = cax[ax].max;
+ // axes[ax].numberTicks = cax[ax].numberTicks;
+ // axes[ax].tickInterval = cax[ax].tickInterval;
+ // // for date axes
+ // axes[ax].daTickInterval = cax[ax].daTickInterval;
+ axes[ax].reset();
+ axes[ax]._ticks = [];
+ // fake out tick creation algorithm to make sure original auto
+ // computed format string is used if _overrideFormatString is true
+ axes[ax]._autoFormatString = cax[ax].tickFormatString;
+ }
+ plot.redraw();
+ cursor._zoom.isZoomed = false;
+ }
+ else {
+ var ctx = cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ plot.target.trigger('jqplotResetZoom', [plot, cursor]);
+ };
+
+ $.jqplot.Cursor.resetZoom = function(plot) {
+ plot.resetZoom();
+ };
+
+ $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) {
+ var c = cursor;
+ var axes = plot.axes;
+ var zaxes = c._zoom.axes;
+ var start = zaxes.start;
+ var end = zaxes.end;
+ var min, max, dp, span,
+ newmin, newmax, curax, _numberTicks, ret;
+ var ctx = plot.plugins.cursor.zoomCanvas._ctx;
+ // don't zoom if zoom area is too small (in pixels)
+ if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) {
+ if (!plot.plugins.cursor.zoomProxy) {
+ for (var ax in datapos) {
+ // make a copy of the original axes to revert back.
+ if (c._zoom.axes[ax] == undefined) {
+ c._zoom.axes[ax] = {};
+ c._zoom.axes[ax].numberTicks = axes[ax].numberTicks;
+ c._zoom.axes[ax].tickInterval = axes[ax].tickInterval;
+ // for date axes...
+ c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval;
+ c._zoom.axes[ax].min = axes[ax].min;
+ c._zoom.axes[ax].max = axes[ax].max;
+ c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : '';
+ }
+
+
+ if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) {
+ dp = datapos[ax];
+ if (dp != null) {
+ if (dp > start[ax]) {
+ newmin = start[ax];
+ newmax = dp;
+ }
+ else {
+ span = start[ax] - dp;
+ newmin = dp;
+ newmax = start[ax];
+ }
+
+ curax = axes[ax];
+
+ _numberTicks = null;
+
+ // if aligning this axis, use number of ticks from previous axis.
+ // Do I need to reset somehow if alignTicks is changed and then graph is replotted??
+ if (curax.alignTicks) {
+ if (curax.name === 'x2axis' && plot.axes.xaxis.show) {
+ _numberTicks = plot.axes.xaxis.numberTicks;
+ }
+ else if (curax.name.charAt(0) === 'y' && curax.name !== 'yaxis' && curax.name !== 'yMidAxis' && plot.axes.yaxis.show) {
+ _numberTicks = plot.axes.yaxis.numberTicks;
+ }
+ }
+
+ if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer )) { //} || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) {
+
+ ret = $.jqplot.LinearTickGenerator(newmin, newmax, curax._scalefact, _numberTicks);
+
+ // if new minimum is less than "true" minimum of axis display, adjust it
+ if (axes[ax].tickInset && ret[0] < axes[ax].min + axes[ax].tickInset * axes[ax].tickInterval) {
+ ret[0] += ret[4];
+ ret[2] -= 1;
+ }
+
+ // if new maximum is greater than "true" max of axis display, adjust it
+ if (axes[ax].tickInset && ret[1] > axes[ax].max - axes[ax].tickInset * axes[ax].tickInterval) {
+ ret[1] -= ret[4];
+ ret[2] -= 1;
+ }
+
+ // for log axes, don't fall below current minimum, this will look bad and can't have 0 in range anyway.
+ if (axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer && ret[0] < axes[ax].min) {
+ // remove a tick and shift min up
+ ret[0] += ret[4];
+ ret[2] -= 1;
+ }
+
+ axes[ax].min = ret[0];
+ axes[ax].max = ret[1];
+ axes[ax]._autoFormatString = ret[3];
+ axes[ax].numberTicks = ret[2];
+ axes[ax].tickInterval = ret[4];
+ // for date axes...
+ axes[ax].daTickInterval = [ret[4]/1000, 'seconds'];
+ }
+ else {
+ axes[ax].min = newmin;
+ axes[ax].max = newmax;
+ axes[ax].tickInterval = null;
+ axes[ax].numberTicks = null;
+ // for date axes...
+ axes[ax].daTickInterval = null;
+ }
+
+ axes[ax]._ticks = [];
+ }
+ }
+
+ // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) {
+ // dp = datapos[ax];
+ // if (dp != null) {
+ // axes[ax].max == null;
+ // axes[ax].min = null;
+ // }
+ // }
+ }
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ plot.redraw();
+ c._zoom.isZoomed = true;
+ ctx = null;
+ }
+ plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]);
+ }
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Cursor.init);
+ $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw);
+
+ function updateTooltip(gridpos, datapos, plot) {
+ var c = plot.plugins.cursor;
+ var s = '';
+ var addbr = false;
+ if (c.showTooltipGridPosition) {
+ s = gridpos.x+', '+gridpos.y;
+ addbr = true;
+ }
+ if (c.showTooltipUnitPosition) {
+ var g;
+ for (var i=0; i<c.tooltipAxisGroups.length; i++) {
+ g = c.tooltipAxisGroups[i];
+ if (addbr) {
+ s += '<br />';
+ }
+ if (c.useAxesFormatters) {
+ for (var j=0; j<g.length; j++) {
+ if (j) {
+ s += ', ';
+ }
+ var af = plot.axes[g[j]]._ticks[0].formatter;
+ var afstr = plot.axes[g[j]]._ticks[0].formatString;
+ s += af(afstr, datapos[g[j]]);
+ }
+ }
+ else {
+ s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]);
+ }
+ addbr = true;
+ }
+ }
+
+ if (c.showTooltipDataPosition) {
+ var series = plot.series;
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ var addbr = false;
+
+ for (var i = 0; i< series.length; i++) {
+ if (series[i].show) {
+ var idx = series[i].index;
+ var label = series[i].label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series[i]._xaxis._ticks[0].formatter;
+ var yf = series[i]._yaxis._ticks[0].formatter;
+ var xfstr = series[i]._xaxis._ticks[0].formatString;
+ var yfstr = series[i]._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ if (addbr) {
+ s += '<br />';
+ }
+ s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy);
+ addbr = true;
+ }
+ }
+ }
+
+ }
+ c._tooltipElem.html(s);
+ }
+
+ function moveLine(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ if (c.showVerticalLine) {
+ c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
+ }
+ if (c.showHorizontalLine) {
+ c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
+ }
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ }
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ }
+ }
+ ctx = null;
+ }
+
+ function getIntersectingPoints(plot, x, y) {
+ var ret = {indices:[], data:[]};
+ var s, i, d0, d, j, r, p;
+ var threshold;
+ var c = plot.plugins.cursor;
+ for (var i=0; i<plot.series.length; i++) {
+ s = plot.series[i];
+ r = s.renderer;
+ if (s.show) {
+ threshold = c.intersectionThreshold;
+ if (s.showMarker) {
+ threshold += s.markerRenderer.size/2;
+ }
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // check vertical line
+ if (c.showVerticalLine) {
+ if (Math.abs(x-p[0]) <= threshold) {
+ ret.indices.push(i);
+ ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]});
+ }
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ function moveTooltip(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default:
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ }
+
+ elem.css('left', x);
+ elem.css('top', y);
+ elem = null;
+ }
+
+ function positionTooltip(plot) {
+ // fake a grid for positioning
+ var grid = plot._gridPadding;
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'n':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'ne':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = grid.right + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = grid.left + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid.right - c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ }
+ elem = null;
+ }
+
+ function handleClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.clickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleDblClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.dblClickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = false;
+ if (c.show) {
+ $(ev.target).css('cursor', c.previousCursor);
+ if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) {
+ c._tooltipElem.empty();
+ c._tooltipElem.hide();
+ }
+ if (c.zoom) {
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+
+ }
+ }
+ }
+ }
+
+ function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = true;
+ if (c.show) {
+ c.previousCursor = ev.target.style.cursor;
+ ev.target.style.cursor = c.style;
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ else {
+ positionTooltip(plot);
+ }
+ c._tooltipElem.show();
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+
+ }
+
+ function handleMouseMove(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ if (c.show) {
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+ }
+
+ function getEventPosition(ev) {
+ var plot = ev.data.plot;
+ var go = plot.eventCanvas._elem.offset();
+ var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
+ //////
+ // TO DO: handle yMidAxis
+ //////
+ var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null};
+ var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ var ax = plot.axes;
+ var n, axis;
+ for (n=11; n>0; n--) {
+ axis = an[n-1];
+ if (ax[axis].show) {
+ dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
+ }
+ }
+
+ return {offsets:go, gridPos:gridPos, dataPos:dataPos};
+ }
+
+ function handleZoomMove(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ // don't do anything if not on grid.
+ if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) {
+ ev.preventDefault();
+ var ctx = c.zoomCanvas._ctx;
+ var positions = getEventPosition(ev);
+ var gridpos = positions.gridPos;
+ var datapos = positions.dataPos;
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ c._zoom.zooming = true;
+ var xpos = gridpos.x;
+ var ypos = gridpos.y;
+ var height = ctx.canvas.height;
+ var width = ctx.canvas.width;
+ if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.end = [xpos, height];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.end = [width, ypos];
+ }
+ else {
+ c._zoom.end = [xpos, ypos];
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ drawZoomBox.call(c);
+ ctx = null;
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ if(plot.plugins.mobile){
+ $(document).one('vmouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
+ } else {
+ $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
+ }
+ var axes = plot.axes;
+ if (document.onselectstart != undefined) {
+ c._oldHandlers.onselectstart = document.onselectstart;
+ document.onselectstart = function () { return false; };
+ }
+ if (document.ondrag != undefined) {
+ c._oldHandlers.ondrag = document.ondrag;
+ document.ondrag = function () { return false; };
+ }
+ if (document.onmousedown != undefined) {
+ c._oldHandlers.onmousedown = document.onmousedown;
+ document.onmousedown = function () { return false; };
+ }
+ if (c.zoom) {
+ if (!c.zoomProxy) {
+ var ctx = c.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.start = [gridpos.x, 0];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.start = [0, gridpos.y];
+ }
+ else {
+ c._zoom.start = [gridpos.x, gridpos.y];
+ }
+ c._zoom.started = true;
+ for (var ax in datapos) {
+ // get zoom starting position.
+ c._zoom.axes.start[ax] = datapos[ax];
+ }
+ if(plot.plugins.mobile){
+ $(document).bind('vmousemove.jqplotCursor', {plot:plot}, handleZoomMove);
+ } else {
+ $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove);
+ }
+
+ }
+ }
+
+ function handleMouseUp(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ if (c.zoom && c._zoom.zooming && !c.zoomTarget) {
+ var xpos = c._zoom.gridpos.x;
+ var ypos = c._zoom.gridpos.y;
+ var datapos = c._zoom.datapos;
+ var height = c.zoomCanvas._ctx.canvas.height;
+ var width = c.zoomCanvas._ctx.canvas.width;
+ var axes = plot.axes;
+
+ if (c.constrainOutsideZoom && !c.onGrid) {
+ if (xpos < 0) { xpos = 0; }
+ else if (xpos > width) { xpos = width; }
+ if (ypos < 0) { ypos = 0; }
+ else if (ypos > height) { ypos = height; }
+
+ for (var axis in datapos) {
+ if (datapos[axis]) {
+ if (axis.charAt(0) == 'x') {
+ datapos[axis] = axes[axis].series_p2u(xpos);
+ }
+ else {
+ datapos[axis] = axes[axis].series_p2u(ypos);
+ }
+ }
+ }
+ }
+
+ if (c.constrainZoomTo == 'x') {
+ ypos = height;
+ }
+ else if (c.constrainZoomTo == 'y') {
+ xpos = width;
+ }
+ c._zoom.end = [xpos, ypos];
+ c._zoom.gridpos = {x:xpos, y:ypos};
+
+ c.doZoom(c._zoom.gridpos, datapos, plot, c);
+ }
+ c._zoom.started = false;
+ c._zoom.zooming = false;
+
+ $(document).unbind('mousemove.jqplotCursor', handleZoomMove);
+
+ if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){
+ document.onselectstart = c._oldHandlers.onselectstart;
+ c._oldHandlers.onselectstart = null;
+ }
+ if (document.ondrag != undefined && c._oldHandlers.ondrag != null){
+ document.ondrag = c._oldHandlers.ondrag;
+ c._oldHandlers.ondrag = null;
+ }
+ if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){
+ document.onmousedown = c._oldHandlers.onmousedown;
+ c._oldHandlers.onmousedown = null;
+ }
+
+ }
+
+ function drawZoomBox() {
+ var start = this._zoom.start;
+ var end = this._zoom.end;
+ var ctx = this.zoomCanvas._ctx;
+ var l, t, h, w;
+ if (end[0] > start[0]) {
+ l = start[0];
+ w = end[0] - start[0];
+ }
+ else {
+ l = end[0];
+ w = start[0] - end[0];
+ }
+ if (end[1] > start[1]) {
+ t = start[1];
+ h = end[1] - start[1];
+ }
+ else {
+ t = end[1];
+ h = start[1] - end[1];
+ }
+ ctx.fillStyle = 'rgba(0,0,0,0.2)';
+ ctx.strokeStyle = '#999999';
+ ctx.lineWidth = 1.0;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.clearRect(l, t, w, h);
+ // IE won't show transparent fill rect, so stroke a rect also.
+ ctx.strokeRect(l,t,w,h);
+ ctx = null;
+ }
+
+ $.jqplot.CursorLegendRenderer = function(options) {
+ $.jqplot.TableLegendRenderer.call(this, options);
+ this.formatString = '%s';
+ };
+
+ $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer;
+
+ // called in context of a Legend
+ $.jqplot.CursorLegendRenderer.prototype.draw = function() {
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+ if (this.show) {
+ var series = this._series, s;
+ // make a table. one line label per row.
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ elem = null;
+ this._elem.addClass('jqplot-legend jqplot-cursor-legend');
+ this._elem.css('position', 'absolute');
+
+ var pad = false;
+ for (var i = 0; i< series.length; i++) {
+ s = series[i];
+ if (s.show && s.showLabel) {
+ var lt = $.jqplot.sprintf(this.formatString, s.label.toString());
+ if (lt) {
+ var color = s.color;
+ if (s._stack && !s.fill) {
+ color = '';
+ }
+ addrow.call(this, lt, color, pad, i);
+ pad = true;
+ }
+ // let plugins add more rows to legend. Used by trend line plugin.
+ for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
+ var item = $.jqplot.addLegendRowHooks[j].call(this, s);
+ if (item) {
+ addrow.call(this, item.label, item.color, pad);
+ pad = true;
+ }
+ }
+ }
+ }
+ series = s = null;
+ delete series;
+ delete s;
+ }
+
+ function addrow(label, color, pad, idx) {
+ var rs = (pad) ? this.rowSpacing : '0';
+ var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem);
+ tr.data('seriesIndex', idx);
+ $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+
+ '<div style="border:1px solid #cccccc;padding:0.2em;">'+
+ '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+
+ '</div></td>').appendTo(tr);
+ var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>');
+ td.appendTo(tr);
+ td.data('seriesIndex', idx);
+ if (this.escapeHtml) {
+ td.text(label);
+ }
+ else {
+ td.html(label);
+ }
+ tr = null;
+ td = null;
+ }
+ return this._elem;
+ };
+
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js
new file mode 100644
index 00000000..ec4211d4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js
@@ -0,0 +1,737 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.DateAxisRenderer
+ * A plugin for a jqPlot to render an axis as a series of date values.
+ * This renderer has no options beyond those supplied by the <Axis> class.
+ * It supplies it's own tick formatter, so the tickOptions.formatter option
+ * should not be overridden.
+ *
+ * Thanks to Ken Synder for his enhanced Date instance methods which are
+ * included with this code <http://kendsnyder.com/sandbox/date/>.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer}}}
+ *
+ * Dates can be passed into the axis in almost any recognizable value and
+ * will be parsed. They will be rendered on the axis in the format
+ * specified by tickOptions.formatString. e.g. tickOptions.formatString = '%Y-%m-%d'.
+ *
+ * Accecptable format codes
+ * are:
+ *
+ * > Code Result Description
+ * > == Years ==
+ * > %Y 2008 Four-digit year
+ * > %y 08 Two-digit year
+ * > == Months ==
+ * > %m 09 Two-digit month
+ * > %#m 9 One or two-digit month
+ * > %B September Full month name
+ * > %b Sep Abbreviated month name
+ * > == Days ==
+ * > %d 05 Two-digit day of month
+ * > %#d 5 One or two-digit day of month
+ * > %e 5 One or two-digit day of month
+ * > %A Sunday Full name of the day of the week
+ * > %a Sun Abbreviated name of the day of the week
+ * > %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
+ * > %o th The ordinal suffix string following the day of the month
+ * > == Hours ==
+ * > %H 23 Hours in 24-hour format (two digits)
+ * > %#H 3 Hours in 24-hour integer format (one or two digits)
+ * > %I 11 Hours in 12-hour format (two digits)
+ * > %#I 3 Hours in 12-hour integer format (one or two digits)
+ * > %p PM AM or PM
+ * > == Minutes ==
+ * > %M 09 Minutes (two digits)
+ * > %#M 9 Minutes (one or two digits)
+ * > == Seconds ==
+ * > %S 02 Seconds (two digits)
+ * > %#S 2 Seconds (one or two digits)
+ * > %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
+ * > == Milliseconds ==
+ * > %N 008 Milliseconds (three digits)
+ * > %#N 8 Milliseconds (one to three digits)
+ * > == Timezone ==
+ * > %O 360 difference in minutes between local time and GMT
+ * > %Z Mountain Standard Time Name of timezone as reported by browser
+ * > %G -06:00 Hours and minutes between GMT
+ * > == Shortcuts ==
+ * > %F 2008-03-26 %Y-%m-%d
+ * > %T 05:06:30 %H:%M:%S
+ * > %X 05:06:30 %H:%M:%S
+ * > %x 03/26/08 %m/%d/%y
+ * > %D 03/26/08 %m/%d/%y
+ * > %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
+ * > %v 3-Sep-2008 %e-%b-%Y
+ * > %R 15:31 %H:%M
+ * > %r 3:31:00 PM %I:%M:%S %p
+ * > == Characters ==
+ * > %n \n Newline
+ * > %t \t Tab
+ * > %% % Percent Symbol
+ */
+ $.jqplot.DateAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ this.date = new $.jsDate();
+ };
+
+ var second = 1000;
+ var minute = 60 * second;
+ var hour = 60 * minute;
+ var day = 24 * hour;
+ var week = 7 * day;
+
+ // these are less definitive
+ var month = 30.4368499 * day;
+ var year = 365.242199 * day;
+
+ var daysInMonths = [31,28,31,30,31,30,31,30,31,30,31,30];
+ // array of consistent nice intervals. Longer intervals
+ // will depend on days in month, days in year, etc.
+ var niceFormatStrings = ['%M:%S.%#N', '%M:%S.%#N', '%M:%S.%#N', '%M:%S', '%M:%S', '%M:%S', '%M:%S', '%H:%M:%S', '%H:%M:%S', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%a %H:%M', '%a %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%v', '%v', '%v', '%v', '%v', '%v', '%v'];
+ var niceIntervals = [0.1*second, 0.2*second, 0.5*second, second, 2*second, 5*second, 10*second, 15*second, 30*second, minute, 2*minute, 5*minute, 10*minute, 15*minute, 30*minute, hour, 2*hour, 4*hour, 6*hour, 8*hour, 12*hour, day, 2*day, 3*day, 4*day, 5*day, week, 2*week];
+
+ var niceMonthlyIntervals = [];
+
+ function bestDateInterval(min, max, titarget) {
+ // iterate through niceIntervals to find one closest to titarget
+ var badness = Number.MAX_VALUE;
+ var temp, bestTi, bestfmt;
+ for (var i=0, l=niceIntervals.length; i < l; i++) {
+ temp = Math.abs(titarget - niceIntervals[i]);
+ if (temp < badness) {
+ badness = temp;
+ bestTi = niceIntervals[i];
+ bestfmt = niceFormatStrings[i];
+ }
+ }
+
+ return [bestTi, bestfmt];
+ }
+
+ $.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.DateAxisRenderer.prototype.constructor = $.jqplot.DateAxisRenderer;
+
+ $.jqplot.DateTickFormatter = function(format, val) {
+ if (!format) {
+ format = '%Y/%m/%d';
+ }
+ return $.jsDate.strftime(val, format);
+ };
+
+ $.jqplot.DateAxisRenderer.prototype.init = function(options){
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ // this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ this.tickOptions.formatter = $.jqplot.DateTickFormatter;
+ // prop: tickInset
+ // Controls the amount to inset the first and last ticks from
+ // the edges of the grid, in multiples of the tick interval.
+ // 0 is no inset, 0.5 is one half a tick interval, 1 is a full
+ // tick interval, etc.
+ this.tickInset = 0;
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ this.daTickInterval = null;
+ this._daTickInterval = null;
+
+ $.extend(true, this, options);
+
+ var db = this._dataBounds,
+ stats,
+ sum,
+ s,
+ d,
+ pd,
+ sd,
+ intv;
+
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ stats = {intervals:[], frequencies:{}, sortedIntervals:[], min:null, max:null, mean:null};
+ sum = 0;
+ s = this._series[i];
+ d = s.data;
+ pd = s._plotData;
+ sd = s._stackData;
+ intv = 0;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ d[j][0] = new $.jsDate(d[j][0]).getTime();
+ pd[j][0] = new $.jsDate(d[j][0]).getTime();
+ sd[j][0] = new $.jsDate(d[j][0]).getTime();
+ if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
+ db.min = d[j][0];
+ }
+ if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
+ db.max = d[j][0];
+ }
+ if (j>0) {
+ intv = Math.abs(d[j][0] - d[j-1][0]);
+ stats.intervals.push(intv);
+ if (stats.frequencies.hasOwnProperty(intv)) {
+ stats.frequencies[intv] += 1;
+ }
+ else {
+ stats.frequencies[intv] = 1;
+ }
+ }
+ sum += intv;
+
+ }
+ else {
+ d[j][1] = new $.jsDate(d[j][1]).getTime();
+ pd[j][1] = new $.jsDate(d[j][1]).getTime();
+ sd[j][1] = new $.jsDate(d[j][1]).getTime();
+ if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) {
+ db.min = d[j][1];
+ }
+ if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) {
+ db.max = d[j][1];
+ }
+ if (j>0) {
+ intv = Math.abs(d[j][1] - d[j-1][1]);
+ stats.intervals.push(intv);
+ if (stats.frequencies.hasOwnProperty(intv)) {
+ stats.frequencies[intv] += 1;
+ }
+ else {
+ stats.frequencies[intv] = 1;
+ }
+ }
+ }
+ sum += intv;
+ }
+
+ if (s.renderer.bands) {
+ if (s.renderer.bands.hiData.length) {
+ var bd = s.renderer.bands.hiData;
+ for (var j=0, l=bd.length; j < l; j++) {
+ if (this.name === 'xaxis' || this.name === 'x2axis') {
+ bd[j][0] = new $.jsDate(bd[j][0]).getTime();
+ if ((bd[j][0] != null && bd[j][0] > db.max) || db.max == null) {
+ db.max = bd[j][0];
+ }
+ }
+ else {
+ bd[j][1] = new $.jsDate(bd[j][1]).getTime();
+ if ((bd[j][1] != null && bd[j][1] > db.max) || db.max == null) {
+ db.max = bd[j][1];
+ }
+ }
+ }
+ }
+ if (s.renderer.bands.lowData.length) {
+ var bd = s.renderer.bands.lowData;
+ for (var j=0, l=bd.length; j < l; j++) {
+ if (this.name === 'xaxis' || this.name === 'x2axis') {
+ bd[j][0] = new $.jsDate(bd[j][0]).getTime();
+ if ((bd[j][0] != null && bd[j][0] < db.min) || db.min == null) {
+ db.min = bd[j][0];
+ }
+ }
+ else {
+ bd[j][1] = new $.jsDate(bd[j][1]).getTime();
+ if ((bd[j][1] != null && bd[j][1] < db.min) || db.min == null) {
+ db.min = bd[j][1];
+ }
+ }
+ }
+ }
+ }
+
+ var tempf = 0,
+ tempn=0;
+ for (var n in stats.frequencies) {
+ stats.sortedIntervals.push({interval:n, frequency:stats.frequencies[n]});
+ }
+ stats.sortedIntervals.sort(function(a, b){
+ return b.frequency - a.frequency;
+ });
+
+ stats.min = $.jqplot.arrayMin(stats.intervals);
+ stats.max = $.jqplot.arrayMax(stats.intervals);
+ stats.mean = sum/d.length;
+ this._intervalStats.push(stats);
+ stats = sum = s = d = pd = sd = null;
+ }
+ db = null;
+
+ };
+
+ // called with scope of an axis
+ $.jqplot.DateAxisRenderer.prototype.reset = function() {
+ this.min = this._options.min;
+ this.max = this._options.max;
+ this.tickInterval = this._options.tickInterval;
+ this.numberTicks = this._options.numberTicks;
+ this._autoFormatString = '';
+ if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
+ this.tickOptions.formatString = '';
+ }
+ this.daTickInterval = this._daTickInterval;
+ // this._ticks = this.__ticks;
+ };
+
+ $.jqplot.DateAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var iv = this._intervalStats;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+ var threshold = 30;
+ var insetMult = 1;
+
+ var tickInterval = this.tickInterval;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ min = ((this.min != null) ? new $.jsDate(this.min).getTime() : db.min);
+ max = ((this.max != null) ? new $.jsDate(this.max).getTime() : db.max);
+
+ // see if we're zooming. if we are, don't use the min and max we're given,
+ // but compute some nice ones. They will be reset later.
+
+ var cursor = plot.plugins.cursor;
+
+ if (cursor && cursor._zoom && cursor._zoom.zooming) {
+ this.min = null;
+ this.max = null;
+ }
+
+ var range = max - min;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = new $.jsDate(ut[0]).getTime();
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(t.value, this.name);
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = new $.jsDate(ut).getTime();
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(t.value, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.daTickInterval = [(this.max - this.min) / (this.numberTicks - 1)/1000, 'seconds'];
+ }
+
+ ////////
+ // We don't have any ticks yet, let's make some!
+ ////////
+
+ // special case when there is only one point, make three tick marks to center the point
+ else if (this.min == null && this.max == null && db.min == db.max)
+ {
+ var onePointOpts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+ var delta = 300000;
+ this.min = db.min - delta;
+ this.max = db.max + delta;
+ this.numberTicks = 3;
+
+ for(var i=this.min;i<=this.max;i+= delta)
+ {
+ onePointOpts.value = i;
+
+ var t = new this.tickRenderer(onePointOpts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+
+ t.showLabel = false;
+ t.showMark = false;
+
+ this._ticks.push(t);
+ }
+
+ if(this.showTicks) {
+ this._ticks[1].showLabel = true;
+ }
+ if(this.showTickMarks) {
+ this._ticks[1].showTickMarks = true;
+ }
+ }
+ // if user specified min and max are null, we set those to make best ticks.
+ else if (this.min == null && this.max == null) {
+
+ var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+
+ // want to find a nice interval
+ var nttarget,
+ titarget;
+
+ // if no tickInterval or numberTicks options specified, make a good guess.
+ if (!this.tickInterval && !this.numberTicks) {
+ var tdim = Math.max(dim, threshold+1);
+ // how many ticks to put on the axis?
+ // date labels tend to be long. If ticks not rotated,
+ // don't use too many and have a high spacing factor.
+ // If we are rotating ticks, use a lower factor.
+ var spacingFactor = 115;
+ if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) {
+ spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI));
+ }
+
+ nttarget = Math.ceil((tdim-threshold)/spacingFactor + 1);
+ titarget = (max - min) / (nttarget - 1);
+ }
+
+ // If tickInterval is specified, we'll try to honor it.
+ // Not gauranteed to get this interval, but we'll get as close as
+ // we can.
+ // tickInterval will be used before numberTicks, that is if
+ // both are specified, numberTicks will be ignored.
+ else if (this.tickInterval) {
+ titarget = this.tickInterval;
+ }
+
+ // if numberTicks specified, try to honor it.
+ // Not gauranteed, but will try to get close.
+ else if (this.numberTicks) {
+ nttarget = this.numberTicks;
+ titarget = (max - min) / (nttarget - 1);
+ }
+
+ // If we can use an interval of 2 weeks or less, pick best one
+ if (titarget <= 19*day) {
+ var ret = bestDateInterval(min, max, titarget);
+ var tempti = ret[0];
+ this._autoFormatString = ret[1];
+
+ min = Math.floor(min/tempti) * tempti;
+ min = new $.jsDate(min);
+ min = min.getTime() + min.getUtcOffset();
+
+ nttarget = Math.ceil((max - min) / tempti) + 1;
+ this.min = min;
+ this.max = min + (nttarget - 1) * tempti;
+
+ // if max is less than max, add an interval
+ if (this.max < max) {
+ this.max += tempti;
+ nttarget += 1;
+ }
+ this.tickInterval = tempti;
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ opts.value = this.min + i * tempti;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = this.tickInterval;
+ }
+
+ // should we use a monthly interval?
+ else if (titarget <= 9 * month) {
+
+ this._autoFormatString = '%v';
+
+ // how many months in an interval?
+ var intv = Math.round(titarget/month);
+ if (intv < 1) {
+ intv = 1;
+ }
+ else if (intv > 6) {
+ intv = 6;
+ }
+
+ // figure out the starting month and ending month.
+ var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
+
+ // See if max ends exactly on a month
+ var tempmend = new $.jsDate(max);
+ var mend = new $.jsDate(max).setDate(1).setHours(0,0,0,0);
+
+ if (tempmend.getTime() !== mend.getTime()) {
+ mend = mend.add(1, 'month');
+ }
+
+ var nmonths = mend.diff(mstart, 'month');
+
+ nttarget = Math.ceil(nmonths/intv) + 1;
+
+ this.min = mstart.getTime();
+ this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ if (i === 0) {
+ opts.value = mstart.getTime();
+ }
+ else {
+ opts.value = mstart.add(intv, 'month').getTime();
+ }
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = intv * month;
+ }
+
+ // use yearly intervals
+ else {
+
+ this._autoFormatString = '%v';
+
+ // how many years in an interval?
+ var intv = Math.round(titarget/year);
+ if (intv < 1) {
+ intv = 1;
+ }
+
+ // figure out the starting and ending years.
+ var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
+ var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
+
+ var nyears = mend.diff(mstart, 'year');
+
+ nttarget = Math.ceil(nyears/intv) + 1;
+
+ this.min = mstart.getTime();
+ this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ if (i === 0) {
+ opts.value = mstart.getTime();
+ }
+ else {
+ opts.value = mstart.add(intv, 'year').getTime();
+ }
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = intv * year;
+ }
+ }
+
+ ////////
+ // Some option(s) specified, work around that.
+ ////////
+
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ // if user specified a tick interval, convert to usable.
+ if (this.tickInterval != null)
+ {
+ // if interval is a number or can be converted to one, use it.
+ // Assume it is in SECONDS!!!
+ if (Number(this.tickInterval)) {
+ this.daTickInterval = [Number(this.tickInterval), 'seconds'];
+ }
+ // else, parse out something we can build from.
+ else if (typeof this.tickInterval == "string") {
+ var parts = this.tickInterval.split(' ');
+ if (parts.length == 1) {
+ this.daTickInterval = [1, parts[0]];
+ }
+ else if (parts.length == 2) {
+ this.daTickInterval = [parts[0], parts[1]];
+ }
+ }
+ }
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 24*60*60*500; // 1/2 day
+ min -= adj;
+ max += adj;
+ }
+
+ range = max - min;
+
+ var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10);
+
+
+ var rmin, rmax;
+
+ rmin = (this.min != null) ? new $.jsDate(this.min).getTime() : min - range/2*(this.padMin - 1);
+ rmax = (this.max != null) ? new $.jsDate(this.max).getTime() : max + range/2*(this.padMax - 1);
+ this.min = rmin;
+ this.max = rmax;
+ range = this.max - this.min;
+
+ if (this.numberTicks == null){
+ // if tickInterval is specified by user, we will ignore computed maximum.
+ // max will be equal or greater to fit even # of ticks.
+ if (this.daTickInterval != null) {
+ var nc = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true);
+ this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1;
+ // this.max = new $.jsDate(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime();
+ this.max = new $.jsDate(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime();
+ }
+ else if (dim > 200) {
+ this.numberTicks = parseInt(3+(dim-200)/100, 10);
+ }
+ else {
+ this.numberTicks = 2;
+ }
+ }
+
+ insetMult = range / (this.numberTicks-1)/1000;
+
+ if (this.daTickInterval == null) {
+ this.daTickInterval = [insetMult, 'seconds'];
+ }
+
+
+ for (var i=0; i<this.numberTicks; i++){
+ var min = new $.jsDate(this.min);
+ tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime();
+ var t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ if (this.tickInset) {
+ this.min = this.min - this.tickInset * insetMult;
+ this.max = this.max + this.tickInset * insetMult;
+ }
+
+ if (this._daTickInterval == null) {
+ this._daTickInterval = this.daTickInterval;
+ }
+
+ ticks = null;
+ };
+
+})(jQuery);
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js
new file mode 100644
index 00000000..621b92ec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js
@@ -0,0 +1,805 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.DonutRenderer
+ * Plugin renderer to draw a donut chart.
+ * x values, if present, will be used as slice labels.
+ * y values give slice size.
+ *
+ * To use this renderer, you need to include the
+ * donut renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.donutRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.DonutRenderer,
+ * > rendererOptions:{
+ * > sliceMargin: 2,
+ * > innerDiameter: 110,
+ * > startAngle: -90
+ * > }
+ * > }
+ * > });
+ *
+ * A donut plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (slice) index, and the point data for
+ * the appropriate slice.
+ *
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted slice.
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.DonutRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer;
+
+ // called with scope of a series
+ $.jqplot.DonutRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the donut, auto computed by default
+ this.diameter = null;
+ // prop: innerDiameter
+ // Inner diameter of the donut, auto calculated by default.
+ // If specified will override thickness value.
+ this.innerDiameter = null;
+ // prop: thickness
+ // thickness of the donut, auto computed by default
+ // Overridden by if innerDiameter is specified.
+ this.thickness = null;
+ // prop: padding
+ // padding between the donut and plot edges, legend, etc.
+ this.padding = 20;
+ // prop: sliceMargin
+ // angular spacing between donut slices in degrees.
+ this.sliceMargin = 0;
+ // prop: ringMargin
+ // pixel distance between rings, or multiple series in a donut plot.
+ // null will compute ringMargin based on sliceMargin.
+ this.ringMargin = null;
+ // prop: fill
+ // true or false, wether to fil the slices.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ // prop: dataLabelPositionFactor
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
+ this.dataLabelPositionFactor = 0.4;
+ // prop: dataLabelNudge
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
+ this.dataLabelNudge = 0;
+ // prop: startAngle
+ // Angle to start drawing donut in degrees.
+ // According to orientation of canvas coordinate system:
+ // 0 = on the positive x axis
+ // -90 = on the positive y axis.
+ // 90 = on the negaive y axis.
+ // 180 or - 180 = on the negative x axis.
+ this.startAngle = 0;
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
+ // Used as check for conditions where donut shouldn't be drawn.
+ this._drawData = true;
+ this._type = 'donut';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+ if (this.diameter != null) {
+ this.diameter = this.diameter - this.sliceMargin;
+ }
+ this._diameter = null;
+ this._innerDiameter = null;
+ this._radius = null;
+ this._innerRadius = null;
+ this._thickness = null;
+ // references to the previous series in the plot to properly calculate diameters
+ // and thicknesses of nested rings.
+ this._previousSeries = [];
+ this._numberSeries = 1;
+ // array of [start,end] angles arrays, one for each slice. In radians.
+ this._sliceAngles = [];
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+
+ };
+
+ $.jqplot.DonutRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle/180*Math.PI;
+ var tot = 0;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<this.data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += this.data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = this.data[i][1]/tot;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var tot = 0;
+ var sa = this.startAngle/180*Math.PI;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = data[i][1]/tot;
+ }
+ return td;
+ };
+
+ $.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
+ var r = this._diameter / 2;
+ var ri = r - this._thickness;
+ var fill = this.fill;
+ // var lineWidth = this.lineWidth;
+ ctx.save();
+ ctx.translate(this._center[0], this._center[1]);
+ // ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2));
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw();
+ }
+ }
+
+ else {
+ doDraw();
+ }
+
+ function doDraw () {
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
+ if (ang2 > 6.282 + this.startAngle) {
+ ang2 = 6.282 + this.startAngle;
+ if (ang1 > ang2) {
+ ang1 = 6.281 + this.startAngle;
+ }
+ }
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
+ // ugly line on unfilled donuts.
+ if (ang1 >= ang2) {
+ return;
+ }
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ // ctx.lineWidth = lineWidth;
+ ctx.arc(0, 0, r, ang1, ang2, false);
+ ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2));
+ ctx.arc(0,0, ri, ang2, ang1, true);
+ ctx.closePath();
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ // called with scope of series
+ $.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ var mindim = Math.min(w,h);
+ var d = mindim;
+ var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin;
+
+ for (var i=0; i<this._previousSeries.length; i++) {
+ d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin;
+ }
+ this._diameter = this.diameter || d;
+ if (this.innerDiameter != null) {
+ var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter;
+ this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0;
+ }
+ else {
+ this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85;
+ }
+
+ var r = this._radius = this._diameter/2;
+ this._innerRadius = this._radius - this._thickness;
+ var sa = this.startAngle / 180 * Math.PI;
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
+
+ if (this.shadow) {
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ ang1 += this.sliceMargin/180*Math.PI;
+ this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
+ }
+
+ }
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ ang1 += this.sliceMargin/180*Math.PI;
+ var ang2 = gd[i][1] + sa;
+ this._sliceAngles.push([ang1, ang2]);
+ this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false);
+
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
+ var fstr, avgang = (ang1+ang2)/2, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
+ }
+
+ var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
+
+ var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+ }
+
+ };
+
+ $.jqplot.DonutAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer;
+
+
+ // There are no traditional axes on a donut chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.DonutAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+
+ $.jqplot.DonutLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer;
+
+ /**
+ * Class: $.jqplot.DonutLegendRenderer
+ * Legend Renderer specific to donut plots. Set by default
+ * when user creates a donut plot.
+ */
+ $.jqplot.DonutLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.DonutLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Donut charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a donut series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.DonutRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer;
+ options.legend.renderer = $.jqplot.DonutLegendRenderer;
+ options.legend.preDraw = true;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ // called with scope of plot.
+ function postInit(target, data, options) {
+ // if multiple series, add a reference to the previous one so that
+ // donut rings can nest.
+ for (var i=1; i<this.series.length; i++) {
+ if (!this.series[i]._previousSeries.length){
+ for (var j=0; j<i; j++) {
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) {
+ this.series[i]._previousSeries.push(this.series[j]);
+ }
+ }
+ }
+ }
+ for (i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) {
+ this.series[i]._numberSeries = this.series.length;
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ var postParseOptionsRun = false;
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.donutRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.donutRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) {
+ this.plugins.donutRenderer.highlightCanvas.resetCanvas();
+ this.plugins.donutRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.donutRenderer = {highlightedSeriesIndex:null};
+ this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+ // do we have any data labels? if so, put highlight canvas before those
+ // Fix for broken jquery :first selector with canvas (VML) elements.
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ var hctx = this.plugins.donutRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.DonutTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js
new file mode 100644
index 00000000..00419518
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js
@@ -0,0 +1,225 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Dragable
+ * Plugin to make plotted points dragable by the user.
+ */
+ $.jqplot.Dragable = function(options) {
+ // Group: Properties
+ this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this.isDragging = false;
+ this.isOver = false;
+ this._ctx;
+ this._elem;
+ this._point;
+ this._gridData;
+ // prop: color
+ // CSS color spec for the dragged point (and adjacent line segment or bar).
+ this.color;
+ // prop: constrainTo
+ // Constrain dragging motion to an axis or to none.
+ // Allowable values are 'none', 'x', 'y'
+ this.constrainTo = 'none'; // 'x', 'y', or 'none';
+ $.extend(true, this, options);
+ };
+
+ function DragCanvas() {
+ $.jqplot.GenericCanvas.call(this);
+ this.isDragging = false;
+ this.isOver = false;
+ this._neighbor;
+ this._cursors = [];
+ }
+
+ DragCanvas.prototype = new $.jqplot.GenericCanvas();
+ DragCanvas.prototype.constructor = DragCanvas;
+
+
+ // called within scope of series
+ $.jqplot.Dragable.parseOptions = function (defaults, opts) {
+ var options = opts || {};
+ this.plugins.dragable = new $.jqplot.Dragable(options.dragable);
+ // since this function is called before series options are parsed,
+ // we can set this here and it will be overridden if needed.
+ this.isDragable = $.jqplot.config.enablePlugins;
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ // add a new DragCanvas object to the plot plugins to handle drawing on this new canvas.
+ $.jqplot.Dragable.postPlotDraw = function() {
+ // Memory Leaks patch
+ if (this.plugins.dragable && this.plugins.dragable.highlightCanvas) {
+ this.plugins.dragable.highlightCanvas.resetCanvas();
+ this.plugins.dragable.highlightCanvas = null;
+ }
+
+ this.plugins.dragable = {previousCursor:'auto', isOver:false};
+ this.plugins.dragable.dragCanvas = new DragCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding, 'jqplot-dragable-canvas', this._plotDimensions, this));
+ var dctx = this.plugins.dragable.dragCanvas.setContext();
+ };
+
+ //$.jqplot.preInitHooks.push($.jqplot.Dragable.init);
+ $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Dragable.parseOptions);
+ $.jqplot.postDrawHooks.push($.jqplot.Dragable.postPlotDraw);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleDown]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseUp', handleUp]);
+
+
+ function initDragPoint(plot, neighbor) {
+ var s = plot.series[neighbor.seriesIndex];
+ var drag = s.plugins.dragable;
+
+ // first, init the mark renderer for the dragged point
+ var smr = s.markerRenderer;
+ var mr = drag.markerRenderer;
+ mr.style = smr.style;
+ mr.lineWidth = smr.lineWidth + 2.5;
+ mr.size = smr.size + 5;
+ if (!drag.color) {
+ var rgba = $.jqplot.getColorComponents(smr.color);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
+ drag.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
+ }
+ mr.color = drag.color;
+ mr.init();
+
+ var start = (neighbor.pointIndex > 0) ? neighbor.pointIndex - 1 : 0;
+ var end = neighbor.pointIndex+2;
+ drag._gridData = s.gridData.slice(start, end);
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (plot.plugins.dragable.dragCanvas.isDragging) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ var dp = dc._neighbor;
+ var s = plot.series[dp.seriesIndex];
+ var drag = s.plugins.dragable;
+ var gd = s.gridData;
+
+ // compute the new grid position with any constraints.
+ var x = (drag.constrainTo == 'y') ? dp.gridData[0] : gridpos.x;
+ var y = (drag.constrainTo == 'x') ? dp.gridData[1] : gridpos.y;
+
+ // compute data values for any listeners.
+ var xu = s._xaxis.series_p2u(x);
+ var yu = s._yaxis.series_p2u(y);
+
+ // clear the canvas then redraw effect at new position.
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+
+ // adjust our gridData for the new mouse position
+ if (dp.pointIndex > 0) {
+ drag._gridData[1] = [x, y];
+ }
+ else {
+ drag._gridData[0] = [x, y];
+ }
+ plot.series[dp.seriesIndex].draw(dc._ctx, {gridData:drag._gridData, shadow:false, preventJqPlotSeriesDrawTrigger:true, color:drag.color, markerOptions:{color:drag.color, shadow:false}, trendline:{show:false}});
+ plot.target.trigger('jqplotSeriesPointChange', [dp.seriesIndex, dp.pointIndex, [xu,yu], [x,y]]);
+ }
+ else if (neighbor != null) {
+ var series = plot.series[neighbor.seriesIndex];
+ if (series.isDragable) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ if (!dc.isOver) {
+ dc._cursors.push(ev.target.style.cursor);
+ ev.target.style.cursor = "pointer";
+ }
+ dc.isOver = true;
+ }
+ }
+ else if (neighbor == null) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ if (dc.isOver) {
+ ev.target.style.cursor = dc._cursors.pop();
+ dc.isOver = false;
+ }
+ }
+ }
+
+ function handleDown(ev, gridpos, datapos, neighbor, plot) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ dc._cursors.push(ev.target.style.cursor);
+ if (neighbor != null) {
+ var s = plot.series[neighbor.seriesIndex];
+ var drag = s.plugins.dragable;
+ if (s.isDragable && !dc.isDragging) {
+ dc._neighbor = neighbor;
+ dc.isDragging = true;
+ initDragPoint(plot, neighbor);
+ drag.markerRenderer.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], dc._ctx);
+ ev.target.style.cursor = "move";
+ plot.target.trigger('jqplotDragStart', [neighbor.seriesIndex, neighbor.pointIndex, gridpos, datapos]);
+ }
+ }
+ // Just in case of a hickup, we'll clear the drag canvas and reset.
+ else {
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ dc.isDragging = false;
+ }
+ }
+
+ function handleUp(ev, gridpos, datapos, neighbor, plot) {
+ if (plot.plugins.dragable.dragCanvas.isDragging) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ // clear the canvas
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ dc.isDragging = false;
+ // redraw the series canvas at the new point.
+ var dp = dc._neighbor;
+ var s = plot.series[dp.seriesIndex];
+ var drag = s.plugins.dragable;
+ // compute the new grid position with any constraints.
+ var x = (drag.constrainTo == 'y') ? dp.data[0] : datapos[s.xaxis];
+ var y = (drag.constrainTo == 'x') ? dp.data[1] : datapos[s.yaxis];
+ // var x = datapos[s.xaxis];
+ // var y = datapos[s.yaxis];
+ s.data[dp.pointIndex][0] = x;
+ s.data[dp.pointIndex][1] = y;
+ plot.drawSeries({preventJqPlotSeriesDrawTrigger:true}, dp.seriesIndex);
+ dc._neighbor = null;
+ ev.target.style.cursor = dc._cursors.pop();
+ plot.target.trigger('jqplotDragStop', [gridpos, datapos]);
+ }
+ }
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js
new file mode 100644
index 00000000..effa111a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js
@@ -0,0 +1,305 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // class $.jqplot.EnhancedLegendRenderer
+ // Legend renderer which can specify the number of rows and/or columns in the legend.
+ $.jqplot.EnhancedLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.EnhancedLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.EnhancedLegendRenderer.prototype.constructor = $.jqplot.EnhancedLegendRenderer;
+
+ // called with scope of legend.
+ $.jqplot.EnhancedLegendRenderer.prototype.init = function(options) {
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ // prop: seriesToggle
+ // false to not enable series on/off toggling on the legend.
+ // true or a fadein/fadeout speed (number of milliseconds or 'fast', 'normal', 'slow')
+ // to enable show/hide of series on click of legend item.
+ this.seriesToggle = 'normal';
+ // prop: seriesToggleReplot
+ // True to replot the chart after toggling series on/off.
+ // This will set the series show property to false.
+ // This allows for rescaling or other maniplation of chart.
+ // Set to an options object (e.g. {resetAxes: true}) for replot options.
+ this.seriesToggleReplot = false;
+ // prop: disableIEFading
+ // true to toggle series with a show/hide method only and not allow fading in/out.
+ // This is to overcome poor performance of fade in some versions of IE.
+ this.disableIEFading = true;
+ $.extend(true, this, options);
+
+ if (this.seriesToggle) {
+ $.jqplot.postDrawHooks.push(postDraw);
+ }
+ };
+
+ // called with scope of legend
+ $.jqplot.EnhancedLegendRenderer.prototype.draw = function(offsets, plot) {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var s;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ if (this.seriesToggle) {
+ this._elem.css('z-index', '3');
+ }
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(series.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(series.length/this.numberColumns);
+ }
+ else {
+ nr = series.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, div, div0, div1;
+ var idx = 0;
+ // check to see if we need to reverse
+ for (i=series.length-1; i>=0; i--) {
+ if (nc == 1 && series[i]._stack || series[i].renderer.constructor == $.jqplot.BezierCurveRenderer){
+ reverse = true;
+ }
+ }
+
+ for (i=0; i<nr; i++) {
+ tr = $(document.createElement('tr'));
+ tr.addClass('jqplot-table-legend');
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+ else{
+ tr.appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < series.length && (series[idx].show || series[idx].showLabel)){
+ s = series[idx];
+ lt = this.labels[idx] || s.label.toString();
+ if (lt) {
+ var color = s.color;
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $(document.createElement('td'));
+ td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td1.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+
+ td1.append(div0.append(div1));
+
+ td2 = $(document.createElement('td'));
+ td2.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td2.css('paddingTop', rs);
+
+ // td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+
+ // '</div></td>');
+ // td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ if (this.showLabels) {td2.prependTo(tr);}
+ if (this.showSwatches) {td1.prependTo(tr);}
+ }
+ else {
+ if (this.showSwatches) {td1.appendTo(tr);}
+ if (this.showLabels) {td2.appendTo(tr);}
+ }
+
+ if (this.seriesToggle) {
+
+ // add an overlay for clicking series on/off
+ // div0 = $(document.createElement('div'));
+ // div0.addClass('jqplot-table-legend-overlay');
+ // div0.css({position:'relative', left:0, top:0, height:'100%', width:'100%'});
+ // tr.append(div0);
+
+ var speed;
+ if (typeof(this.seriesToggle) === 'string' || typeof(this.seriesToggle) === 'number') {
+ if (!$.jqplot.use_excanvas || !this.disableIEFading) {
+ speed = this.seriesToggle;
+ }
+ }
+ if (this.showSwatches) {
+ td1.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
+ td1.addClass('jqplot-seriesToggle');
+ }
+ if (this.showLabels) {
+ td2.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
+ td2.addClass('jqplot-seriesToggle');
+ }
+
+ // for series that are already hidden, add the hidden class
+ if (!s.show && s.showLabel) {
+ td1.addClass('jqplot-series-hidden');
+ td2.addClass('jqplot-series-hidden');
+ }
+ }
+
+ pad = true;
+ }
+ }
+ idx++;
+ }
+
+ td1 = td2 = div0 = div1 = null;
+ }
+ }
+ return this._elem;
+ };
+
+ var handleToggle = function (ev) {
+ var d = ev.data,
+ s = d.series,
+ replot = d.replot,
+ plot = d.plot,
+ speed = d.speed,
+ sidx = s.index,
+ showing = false;
+
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ showing = true;
+ }
+
+ var doLegendToggle = function() {
+
+ if (replot) {
+ var opts = {};
+
+ if ($.isPlainObject(replot)) {
+ $.extend(true, opts, replot);
+ }
+
+ plot.replot(opts);
+ // if showing, there was no canvas element to fade in, so hide here
+ // and then do a fade in.
+ if (showing && speed) {
+ var s = plot.series[sidx];
+
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.hide().fadeIn(speed);
+ }
+ s.canvas._elem.hide().fadeIn(speed);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide().fadeIn(speed);
+ }
+
+ }
+
+ else {
+ var s = plot.series[sidx];
+
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ // Not sure if there is a better way to check for showSwatches and showLabels === true.
+ // Test for "undefined" since default values for both showSwatches and showLables is true.
+ if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) {
+ plot.legend._elem.find('td').eq(sidx * 2).addClass('jqplot-series-hidden');
+ }
+ if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) {
+ plot.legend._elem.find('td').eq((sidx * 2) + 1).addClass('jqplot-series-hidden');
+ }
+ }
+ else {
+ if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) {
+ plot.legend._elem.find('td').eq(sidx * 2).removeClass('jqplot-series-hidden');
+ }
+ if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) {
+ plot.legend._elem.find('td').eq((sidx * 2) + 1).removeClass('jqplot-series-hidden');
+ }
+ }
+
+ }
+
+ };
+
+ s.toggleDisplay(ev, doLegendToggle);
+ };
+
+ // called with scope of plot.
+ var postDraw = function () {
+ if (this.legend.renderer.constructor == $.jqplot.EnhancedLegendRenderer && this.legend.seriesToggle){
+ var e = this.legend._elem.detach();
+ this.eventCanvas._elem.after(e);
+ }
+ };
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js
new file mode 100644
index 00000000..c72660cc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js
@@ -0,0 +1,943 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.FunnelRenderer
+ * Plugin renderer to draw a funnel chart.
+ * x values, if present, will be used as labels.
+ * y values give area size.
+ *
+ * Funnel charts will draw a single series
+ * only.
+ *
+ * To use this renderer, you need to include the
+ * funnel renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.FunnelRenderer,
+ * > rendererOptions:{
+ * > sectionMargin: 12,
+ * > widthRatio: 0.3
+ * > }
+ * > }
+ * > });
+ *
+ * IMPORTANT
+ *
+ * *The funnel renderer will reorder data in descending order* so the largest value in
+ * the data set is first and displayed on top of the funnel. Data will then
+ * be displayed in descending order down the funnel. The area of each funnel
+ * section will correspond to the value of each data point relative to the sum
+ * of all values. That is section area is proportional to section value divided by
+ * sum of all section values.
+ *
+ * If your data is not in descending order when passed into the plot, *it will be
+ * reordered* when stored in the series.data property. A copy of the unordered
+ * data is kept in the series._unorderedData property.
+ *
+ * A funnel plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (section) index, and the point data for
+ * the appropriate section. *Note* the point index will referr to the ordered
+ * data, not the original unordered data.
+ *
+ * 'jqplotDataMouseOver' - triggered when mousing over a section.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a section,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted section.
+ * 'jqplotDataClick' - triggered when the user clicks on a section.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a section if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.FunnelRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer;
+
+ // called with scope of a series
+ $.jqplot.FunnelRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: padding
+ // padding between the funnel and plot edges, legend, etc.
+ this.padding = {top: 20, right: 20, bottom: 20, left: 20};
+ // prop: sectionMargin
+ // spacing between funnel sections in pixels.
+ this.sectionMargin = 6;
+ // prop: fill
+ // true or false, wether to fill the areas.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the area and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight area when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a area.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a area.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // array of colors to use when highlighting an area.
+ this.highlightColors = [];
+ // prop: widthRatio
+ // The ratio of the width of the top of the funnel to the bottom.
+ // a ratio of 0 will make an upside down pyramid.
+ this.widthRatio = 0.2;
+ // prop: lineWidth
+ // width of line if areas are stroked and not filled.
+ this.lineWidth = 2;
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ this._type = 'funnel';
+
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // lengths of bases, or horizontal sides of areas of trapezoid.
+ this._bases = [];
+ // total area
+ this._atot;
+ // areas of segments.
+ this._areas = [];
+ // vertical lengths of segments.
+ this._lengths = [];
+ // angle of the funnel to vertical.
+ this._angle;
+ this._dataIndices = [];
+
+ // sort data
+ this._unorderedData = $.extend(true, [], this.data);
+ var idxs = $.extend(true, [], this.data);
+ for (var i=0; i<idxs.length; i++) {
+ idxs[i].push(i);
+ }
+ this.data.sort( function (a, b) { return b[1] - a[1]; } );
+ idxs.sort( function (a, b) { return b[1] - a[1]; });
+ for (var i=0; i<idxs.length; i++) {
+ this._dataIndices.push(idxs[i][2]);
+ }
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+ };
+
+ // gridData will be of form [label, percentage of total]
+ $.jqplot.FunnelRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var sum = 0;
+ var td = [];
+ for (var i=0; i<this.data.length; i++){
+ sum += this.data[i][1];
+ td.push([this.data[i][0], this.data[i][1]]);
+ }
+
+ // normalize y values, so areas are proportional.
+ for (var i=0; i<td.length; i++) {
+ td[i][1] = td[i][1]/sum;
+ }
+
+ this._bases = new Array(td.length + 1);
+ this._lengths = new Array(td.length);
+
+ this.gridData = td;
+ };
+
+ $.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var sum = 0;
+ var td = [];
+ for (var i=0; i<this.data.length; i++){
+ sum += this.data[i][1];
+ td.push([this.data[i][0], this.data[i][1]]);
+ }
+
+ // normalize y values, so areas are proportional.
+ for (var i=0; i<td.length; i++) {
+ td[i][1] = td[i][1]/sum;
+ }
+
+ this._bases = new Array(td.length + 1);
+ this._lengths = new Array(td.length);
+
+ return td;
+ };
+
+ $.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) {
+ var fill = this.fill;
+ var lineWidth = this.lineWidth;
+ ctx.save();
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw();
+ }
+ }
+
+ else {
+ doDraw();
+ }
+
+ function doDraw () {
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.moveTo(vertices[0][0], vertices[0][1]);
+ for (var i=1; i<4; i++) {
+ ctx.lineTo(vertices[i][0], vertices[i][1]);
+ }
+ ctx.closePath();
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ // called with scope of series
+ $.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ this._areas = [];
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var loff = (trans==1) ? this.padding.left + offx : this.padding.left;
+ var toff = (trans==1) ? this.padding.top + offy : this.padding.top;
+ var roff = (trans==-1) ? this.padding.right + offx : this.padding.right;
+ var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom;
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ this._bases[0] = cw - loff - roff;
+ var ltot = this._length = ch - toff - boff;
+
+ var hend = this._bases[0]*this.widthRatio;
+ this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio);
+
+ this._angle = Math.atan((this._bases[0] - hend)/2/ltot);
+
+ for (i=0; i<gd.length; i++) {
+ this._areas.push(gd[i][1] * this._atot);
+ }
+
+
+ var guess, err, count, lsum=0;
+ var tolerance = 0.0001;
+
+ for (i=0; i<this._areas.length; i++) {
+ guess = this._areas[i]/this._bases[i];
+ err = 999999;
+ this._lengths[i] = guess;
+ count = 0;
+ while (err > this._lengths[i]*tolerance && count < 100) {
+ this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle));
+ err = Math.abs(this._lengths[i] - guess);
+ this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle));
+ guess = this._lengths[i];
+ count++;
+ }
+ lsum += this._lengths[i];
+ }
+
+ // figure out vertices of each section
+ this._vertices = new Array(gd.length);
+
+ // these are 4 coners of entire trapezoid
+ var p0 = [loff, toff],
+ p1 = [loff+this._bases[0], toff],
+ p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length],
+ p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]];
+
+ // equations of right and left sides, returns x, y values given height of section (y value)
+ function findleft (l) {
+ var m = (p0[1] - p2[1])/(p0[0] - p2[0]);
+ var b = p0[1] - m*p0[0];
+ var y = l + p0[1];
+
+ return [(y - b)/m, y];
+ }
+
+ function findright (l) {
+ var m = (p1[1] - p3[1])/(p1[0] - p3[0]);
+ var b = p1[1] - m*p1[0];
+ var y = l + p1[1];
+
+ return [(y - b)/m, y];
+ }
+
+ var x = offx, y = offy;
+ var h=0, adj=0;
+
+ for (i=0; i<gd.length; i++) {
+ this._vertices[i] = new Array();
+ var v = this._vertices[i];
+ var sm = this.sectionMargin;
+ if (i == 0) {
+ adj = 0;
+ }
+ if (i == 1) {
+ adj = sm/3;
+ }
+ else if (i > 0 && i < gd.length-1) {
+ adj = sm/2;
+ }
+ else if (i == gd.length -1) {
+ adj = 2*sm/3;
+ }
+ v.push(findleft(h+adj));
+ v.push(findright(h+adj));
+ h += this._lengths[i];
+ if (i == 0) {
+ adj = -2*sm/3;
+ }
+ else if (i > 0 && i < gd.length-1) {
+ adj = -sm/2;
+ }
+ else if (i == gd.length - 1) {
+ adj = 0;
+ }
+ v.push(findright(h+adj));
+ v.push(findleft(h+adj));
+
+ }
+
+ if (this.shadow) {
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ for (var i=0; i<gd.length; i++) {
+ this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true);
+ }
+
+ }
+ for (var i=0; i<gd.length; i++) {
+ var v = this._vertices[i];
+ this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]);
+
+ if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) {
+ var fstr, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][1]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]);
+ }
+
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left;
+ var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top;
+
+ var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+
+ }
+
+ };
+
+ $.jqplot.FunnelAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer;
+
+
+ // There are no traditional axes on a funnel chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.FunnelAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+ /**
+ * Class: $.jqplot.FunnelLegendRenderer
+ * Legend Renderer specific to funnel plots. Set by default
+ * when the user creates a funnel plot.
+ */
+ $.jqplot.FunnelLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer;
+
+ $.jqplot.FunnelLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.FunnelLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Funnel charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ // $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) {
+ // if (this.show) {
+ // // fake a grid for positioning
+ // var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
+ // if (this.placement == 'insideGrid') {
+ // switch (this.location) {
+ // case 'nw':
+ // var a = grid._left + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'n':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'ne':
+ // var a = offsets.right + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // case 'e':
+ // var a = offsets.right + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // case 'se':
+ // var a = offsets.right + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // case 's':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 'sw':
+ // var a = grid._left + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 'w':
+ // var a = grid._left + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // default: // same as 'se'
+ // var a = grid._right - this.xoffset;
+ // var b = grid._bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // }
+ //
+ // }
+ // else {
+ // switch (this.location) {
+ // case 'nw':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('right', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'n':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = this._plotDimensions.height - grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('bottom', b);
+ // break;
+ // case 'ne':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'e':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'se':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 's':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'sw':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // case 'w':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // default: // same as 'se'
+ // var a = grid._right - this.xoffset;
+ // var b = grid._bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // }
+ // }
+ // }
+ // };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a funnel series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.FunnelRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer;
+ options.legend.renderer = $.jqplot.FunnelLegendRenderer;
+ options.legend.preDraw = true;
+ options.sortData = false;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ function postInit(target, data, options) {
+ // if multiple series, add a reference to the previous one so that
+ // funnel rings can nest.
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) {
+ this.plugins.funnelRenderer.highlightCanvas.resetCanvas();
+ this.plugins.funnelRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.funnelRenderer = {};
+ this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ // do we have any data labels? if so, put highlight canvas before those
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.FunnelTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js
new file mode 100644
index 00000000..2e8c5da9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js
@@ -0,0 +1,465 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+
+ /**
+ * Class: $.jqplot.Highlighter
+ * Plugin which will highlight data points when they are moused over.
+ *
+ * To use this plugin, include the js
+ * file in your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
+ *
+ * A tooltip providing information about the data point is enabled by default.
+ * To disable the tooltip, set "showTooltip" to false.
+ *
+ * You can control what data is displayed in the tooltip with various
+ * options. The "tooltipAxes" option controls wether the x, y or both
+ * data values are displayed.
+ *
+ * Some chart types (e.g. hi-low-close) have more than one y value per
+ * data point. To display the additional values in the tooltip, set the
+ * "yvalues" option to the desired number of y values present (3 for a hlc chart).
+ *
+ * By default, data values will be formatted with the same formatting
+ * specifiers as used to format the axis ticks. A custom format code
+ * can be supplied with the tooltipFormatString option. This will apply
+ * to all values in the tooltip.
+ *
+ * For more complete control, the "formatString" option can be set. This
+ * Allows conplete control over tooltip formatting. Values are passed to
+ * the format string in an order determined by the "tooltipAxes" and "yvalues"
+ * options. So, if you have a hi-low-close chart and you just want to display
+ * the hi-low-close values in the tooltip, you could set a formatString like:
+ *
+ * > highlighter: {
+ * > tooltipAxes: 'y',
+ * > yvalues: 3,
+ * > formatString:'<table class="jqplot-highlighter">
+ * > <tr><td>hi:</td><td>%s</td></tr>
+ * > <tr><td>low:</td><td>%s</td></tr>
+ * > <tr><td>close:</td><td>%s</td></tr></table>'
+ * > }
+ *
+ */
+ $.jqplot.Highlighter = function(options) {
+ // Group: Properties
+ //
+ //prop: show
+ // true to show the highlight.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: markerRenderer
+ // Renderer used to draw the marker of the highlighted point.
+ // Renderer will assimilate attributes from the data point being highlighted,
+ // so no attributes need set on the renderer directly.
+ // Default is to turn off shadow drawing on the highlighted point.
+ this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
+ // prop: showMarker
+ // true to show the marker
+ this.showMarker = true;
+ // prop: lineWidthAdjust
+ // Pixels to add to the lineWidth of the highlight.
+ this.lineWidthAdjust = 2.5;
+ // prop: sizeAdjust
+ // Pixels to add to the overall size of the highlight.
+ this.sizeAdjust = 5;
+ // prop: showTooltip
+ // Show a tooltip with data point values.
+ this.showTooltip = true;
+ // prop: tooltipLocation
+ // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'nw';
+ // prop: fadeTooltip
+ // true = fade in/out tooltip, flase = show/hide tooltip
+ this.fadeTooltip = true;
+ // prop: tooltipFadeSpeed
+ // 'slow', 'def', 'fast', or number of milliseconds.
+ this.tooltipFadeSpeed = "fast";
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the highlight.
+ this.tooltipOffset = 2;
+ // prop: tooltipAxes
+ // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
+ // 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
+ this.tooltipAxes = 'both';
+ // prop; tooltipSeparator
+ // String to use to separate x and y axes in tooltip.
+ this.tooltipSeparator = ', ';
+ // prop; tooltipContentEditor
+ // Function used to edit/augment/replace the formatted tooltip contents.
+ // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)
+ // where str is the generated tooltip html and seriesIndex and pointIndex identify
+ // the data point being highlighted. Should return the html for the tooltip contents.
+ this.tooltipContentEditor = null;
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference.
+ // Additional "p" and "P" format specifiers added by Chris Leonello.
+ this.tooltipFormatString = '%.5P';
+ // prop: formatString
+ // alternative to tooltipFormatString
+ // will format the whole tooltip text, populating with x, y values as
+ // indicated by tooltipAxes option. So, you could have a tooltip like:
+ // 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
+ // If useAxesFormatters is true, values will be formatted according to
+ // Axes formatters and you can populate your tooltip string with
+ // %s placeholders.
+ this.formatString = null;
+ // prop: yvalues
+ // Number of y values to expect in the data point array.
+ // Typically this is 1. Certain plots, like OHLC, will
+ // have more y values in each data point array.
+ this.yvalues = 1;
+ // prop: bringSeriesToFront
+ // This option requires jQuery 1.4+
+ // True to bring the series of the highlighted point to the front
+ // of other series.
+ this.bringSeriesToFront = false;
+ this._tooltipElem;
+ this.isHighlighting = false;
+ this.currentNeighbor = null;
+
+ $.extend(true, this, options);
+ };
+
+ var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
+ var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
+ var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
+
+ // axis.renderer.tickrenderer.formatter
+
+ // called with scope of plot
+ $.jqplot.Highlighter.init = function (target, data, opts){
+ var options = opts || {};
+ // add a highlighter attribute to the plot
+ this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
+ };
+
+ // called within scope of series
+ $.jqplot.Highlighter.parseOptions = function (defaults, options) {
+ // Add a showHighlight option to the series
+ // and set it to true by default.
+ this.showHighlight = true;
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ $.jqplot.Highlighter.postPlotDraw = function() {
+ // Memory Leaks patch
+ if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) {
+ this.plugins.highlighter.highlightCanvas.resetCanvas();
+ this.plugins.highlighter.highlightCanvas = null;
+ }
+
+ if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) {
+ this.plugins.highlighter._tooltipElem.emptyForce();
+ this.plugins.highlighter._tooltipElem = null;
+ }
+
+ this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this));
+ this.plugins.highlighter.highlightCanvas.setContext();
+
+ var elem = document.createElement('div');
+ this.plugins.highlighter._tooltipElem = $(elem);
+ elem = null;
+ this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip');
+ this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'});
+
+ this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
+ $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
+ $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
+
+ function draw(plot, neighbor) {
+ var hl = plot.plugins.highlighter;
+ var s = plot.series[neighbor.seriesIndex];
+ var smr = s.markerRenderer;
+ var mr = hl.markerRenderer;
+ mr.style = smr.style;
+ mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
+ mr.size = smr.size + hl.sizeAdjust;
+ var rgba = $.jqplot.getColorComponents(smr.color);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
+ mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
+ mr.init();
+ mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);
+ }
+
+ function showTooltip(plot, series, neighbor) {
+ // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
+ // gridData should be x,y pixel coords on the grid.
+ // add the plot._gridPadding to that to get x,y in the target.
+ var hl = plot.plugins.highlighter;
+ var elem = hl._tooltipElem;
+ var serieshl = series.highlighter || {};
+
+ var opts = $.extend(true, {}, hl, serieshl);
+
+ if (opts.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ var str;
+ var xstr = xf(xfstr, neighbor.data[0]);
+ var ystrs = [];
+ for (var i=1; i<opts.yvalues+1; i++) {
+ ystrs.push(yf(yfstr, neighbor.data[i]));
+ }
+ if (typeof opts.formatString === 'string') {
+ switch (opts.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ ystrs.unshift(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'yx':
+ ystrs.push(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'x':
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);
+ break;
+ case 'y':
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ default: // same as xy
+ ystrs.unshift(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ }
+ }
+ else {
+ switch (opts.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += opts.tooltipSeparator + ystrs[i];
+ }
+ break;
+ case 'yx':
+ str = '';
+ for (var i=0; i<ystrs.length; i++) {
+ str += ystrs[i] + opts.tooltipSeparator;
+ }
+ str += xstr;
+ break;
+ case 'x':
+ str = xstr;
+ break;
+ case 'y':
+ str = ystrs.join(opts.tooltipSeparator);
+ break;
+ default: // same as 'xy'
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += opts.tooltipSeparator + ystrs[i];
+ }
+ break;
+
+ }
+ }
+ }
+ else {
+ var str;
+ if (typeof opts.formatString === 'string') {
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));
+ }
+
+ else {
+ if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
+ }
+ else if (opts.tooltipAxes == 'yx') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (opts.tooltipAxes == 'x') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (opts.tooltipAxes == 'y') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
+ }
+ }
+ }
+ if ($.isFunction(opts.tooltipContentEditor)) {
+ // args str, seriesIndex, pointIndex are essential so the hook can look up
+ // extra data for the point.
+ str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
+ }
+ elem.html(str);
+ var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
+ var ms = 0;
+ var fact = 0.707;
+ if (series.markerRenderer.show == true) {
+ ms = (series.markerRenderer.size + opts.sizeAdjust)/2;
+ }
+
+ var loc = locations;
+ if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
+ loc = oppositeLocations;
+ }
+
+ switch (loc[locationIndicies[opts.tooltipLocation]]) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ }
+ elem.css('left', x);
+ elem.css('top', y);
+ if (opts.fadeTooltip) {
+ // Fix for stacked up animations. Thnanks Trevor!
+ elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
+ }
+ else {
+ elem.show();
+ }
+ elem = null;
+
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ var hl = plot.plugins.highlighter;
+ var c = plot.plugins.cursor;
+ if (hl.show) {
+ if (neighbor == null && hl.isHighlighting) {
+ var evt = jQuery.Event('jqplotHighlighterUnhighlight');
+ plot.target.trigger(evt);
+
+ var ctx = hl.highlightCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ if (hl.fadeTooltip) {
+ hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
+ }
+ else {
+ hl._tooltipElem.hide();
+ }
+ if (hl.bringSeriesToFront) {
+ plot.restorePreviousSeriesOrder();
+ }
+ hl.isHighlighting = false;
+ hl.currentNeighbor = null;
+ ctx = null;
+ }
+ else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
+ var evt = jQuery.Event('jqplotHighlighterHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot];
+ plot.target.trigger(evt, ins);
+
+ hl.isHighlighting = true;
+ hl.currentNeighbor = neighbor;
+ if (hl.showMarker) {
+ draw(plot, neighbor);
+ }
+ if (hl.showTooltip && (!c || !c._zoom.started)) {
+ showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
+ }
+ if (hl.bringSeriesToFront) {
+ plot.moveSeriesToFront(neighbor.seriesIndex);
+ }
+ }
+ // check to see if we're highlighting the wrong point.
+ else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {
+ // highlighting the wrong point.
+
+ // if new series allows highlighting, highlight new point.
+ if (plot.series[neighbor.seriesIndex].showHighlight) {
+ var ctx = hl.highlightCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ hl.isHighlighting = true;
+ hl.currentNeighbor = neighbor;
+ if (hl.showMarker) {
+ draw(plot, neighbor);
+ }
+ if (hl.showTooltip && (!c || !c._zoom.started)) {
+ showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
+ }
+ if (hl.bringSeriesToFront) {
+ plot.moveSeriesToFront(neighbor.seriesIndex);
+ }
+ }
+ }
+ }
+ }
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js
new file mode 100644
index 00000000..46fb942b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js
@@ -0,0 +1,475 @@
+/*
+ 2010-11-01 Chris Leonello
+
+ Slightly modified version of the original json2.js to put JSON
+ functions under the $.jqplot namespace.
+
+ licensing and orignal comments follow:
+
+ http://www.JSON.org/json2.js
+ 2010-08-25
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ $.jqplot.JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ $.jqplot.JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = $.jqplot.JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ $.jqplot.JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = $.jqplot.JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = $.jqplot.JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+(function($) {
+
+ $.jqplot.JSON = window.JSON;
+
+ if (!window.JSON) {
+ $.jqplot.JSON = {};
+ }
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof $.jqplot.JSON.stringify !== 'function') {
+ $.jqplot.JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('$.jqplot.JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof $.jqplot.JSON.parse !== 'function') {
+ $.jqplot.JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('$.jqplot.JSON.parse');
+ };
+ }
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js
new file mode 100644
index 00000000..8d358ec7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js
@@ -0,0 +1,529 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * class: $.jqplot.LogAxisRenderer
+ * A plugin for a jqPlot to render a logarithmic axis.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.logAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.LogAxisRenderer}}}
+ **/
+ $.jqplot.LogAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ // prop: axisDefaults
+ // Default properties which will be applied directly to the series.
+ //
+ // Group: Properties
+ //
+ // Properties
+ //
+ // base - the logarithmic base, commonly 2, 10 or Math.E
+ // tickDistribution - Deprecated. "power" distribution of ticks
+ // always used. Option has no effect.
+ this.axisDefaults = {
+ base : 10,
+ tickDistribution :'power'
+ };
+ };
+
+ $.jqplot.LogAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.LogAxisRenderer.prototype.constructor = $.jqplot.LogAxisRenderer;
+
+ $.jqplot.LogAxisRenderer.prototype.init = function(options) {
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: minorTicks
+ // Number of ticks to add between "major" ticks.
+ // Major ticks are ticks supplied by user or auto computed.
+ // Minor ticks cannot be created by user.
+ this.minorTicks = 'auto';
+ this._scalefact = 1.0;
+
+ $.extend(true, this, options);
+
+ this._autoFormatString = '%d';
+ this._overrideFormatString = false;
+
+ for (var d in this.renderer.axisDefaults) {
+ if (this[d] == null) {
+ this[d] = this.renderer.axisDefaults[d];
+ }
+ }
+
+ this.resetDataBounds();
+ };
+
+ $.jqplot.LogAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ var db = this._dataBounds;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+
+ var threshold = 30;
+ // For some reason scalefactor is screwing up ticks.
+ this._scalefact = (Math.max(dim, threshold+1) - threshold)/300;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = ut[0];
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else if (this.min == null && this.max == null) {
+ min = db.min * (2 - this.padMin);
+ max = db.max * this.padMax;
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 0.05;
+ min = min*(1-adj);
+ max = max*(1+adj);
+ }
+
+ // perform some checks
+ if (this.min != null && this.min <= 0) {
+ throw('log axis minimum must be greater than 0');
+ }
+ if (this.max != null && this.max <= 0) {
+ throw('log axis maximum must be greater than 0');
+ }
+
+ function findCeil (val) {
+ var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
+ return Math.ceil(val/order) * order;
+ }
+
+ function findFloor(val) {
+ var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
+ return Math.floor(val/order) * order;
+ }
+
+ // var range = max - min;
+ var rmin, rmax;
+
+ // for power distribution, open up range to get a nice power of axis.renderer.base.
+ // power distribution won't respect the user's min/max settings.
+ rmin = Math.pow(this.base, Math.floor(Math.log(min)/Math.log(this.base)));
+ rmax = Math.pow(this.base, Math.ceil(Math.log(max)/Math.log(this.base)));
+
+ // // if min and max are same, space them out a bit
+ // if (rmin === rmax) {
+ // var adj = 0.05;
+ // rmin = rmin*(1-adj);
+ // rmax = rmax*(1+adj);
+ // }
+
+ var order = Math.round(Math.log(rmin)/Math.LN10);
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ this.min = rmin;
+ this.max = rmax;
+ var range = this.max - this.min;
+
+ var minorTicks = (this.minorTicks === 'auto') ? 0 : this.minorTicks;
+ var numberTicks;
+ if (this.numberTicks == null){
+ if (dim > 140) {
+ numberTicks = Math.round(Math.log(this.max/this.min)/Math.log(this.base) + 1);
+ if (numberTicks < 2) {
+ numberTicks = 2;
+ }
+ if (minorTicks === 0) {
+ var temp = dim/(numberTicks - 1);
+ if (temp < 100) {
+ minorTicks = 0;
+ }
+ else if (temp < 190) {
+ minorTicks = 1;
+ }
+ else if (temp < 250) {
+ minorTicks = 3;
+ }
+ else if (temp < 600) {
+ minorTicks = 4;
+ }
+ else {
+ minorTicks = 9;
+ }
+ }
+ }
+ else {
+ numberTicks = 2;
+ if (minorTicks === 0) {
+ minorTicks = 1;
+ }
+ minorTicks = 0;
+ }
+ }
+ else {
+ numberTicks = this.numberTicks;
+ }
+
+ if (order >= 0 && minorTicks !== 3) {
+ this._autoFormatString = '%d';
+ }
+ // Adjust format string for case with 3 ticks where we'll have like 1, 2.5, 5, 7.5, 10
+ else if (order <= 0 && minorTicks === 3) {
+ var temp = -(order - 1);
+ this._autoFormatString = '%.'+ Math.abs(order-1) + 'f';
+ }
+
+ // Adjust format string for values less than 1.
+ else if (order < 0) {
+ var temp = -order;
+ this._autoFormatString = '%.'+ Math.abs(order) + 'f';
+ }
+
+ else {
+ this._autoFormatString = '%d';
+ }
+
+ var to, t, val, tt1, spread, interval;
+ for (var i=0; i<numberTicks; i++){
+ tt = Math.pow(this.base, i - numberTicks + 1) * this.max;
+
+ t = new this.tickRenderer(this.tickOptions);
+
+ if (this._overrideFormatString) {
+ t.formatString = this._autoFormatString;
+ }
+
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+
+ if (minorTicks && i<numberTicks-1) {
+ tt1 = Math.pow(this.base, i - numberTicks + 2) * this.max;
+ spread = tt1 - tt;
+ interval = tt1 / (minorTicks+1);
+ for (var j=minorTicks-1; j>=0; j--) {
+ val = tt1-interval*(j+1);
+ t = new this.tickRenderer(this.tickOptions);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(val, this.name);
+ this._ticks.push(t);
+ }
+ }
+ }
+ }
+
+ // min and max are set as would be the case with zooming
+ else if (this.min != null && this.max != null) {
+ var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+ var nt, ti;
+ // don't have an interval yet, pick one that gives the most
+ // "round" ticks we can get.
+ if (this.numberTicks == null && this.tickInterval == null) {
+ // var threshold = 30;
+ var tdim = Math.max(dim, threshold+1);
+ var nttarget = Math.ceil((tdim-threshold)/35 + 1);
+
+ var ret = $.jqplot.LinearTickGenerator.bestConstrainedInterval(this.min, this.max, nttarget);
+
+ this._autoFormatString = ret[3];
+ nt = ret[2];
+ ti = ret[4];
+
+ for (var i=0; i<nt; i++) {
+ opts.value = this.min + i * ti;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+ }
+
+ // for loose zoom, number ticks and interval are also set.
+ else if (this.numberTicks != null && this.tickInterval != null) {
+ nt = this.numberTicks;
+ for (var i=0; i<nt; i++) {
+ opts.value = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+ }
+ }
+ };
+
+ $.jqplot.LogAxisRenderer.prototype.pack = function(pos, offsets) {
+ var lb = parseInt(this.base, 10);
+ var ticks = this._ticks;
+ var trans = function (v) { return Math.log(v)/Math.log(lb); };
+ var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); };
+ var max = trans(this.max);
+ var min = trans(this.min);
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ this.p2u = function(p){
+ return invtrans((p - offmin) * unitlength / pixellength + min);
+ };
+
+ this.u2p = function(u){
+ return (trans(u) - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (trans(u) - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return invtrans(p * unitlength / pixellength + min);
+ };
+ }
+ // yaxis is max at top of canvas.
+ else {
+ this.series_u2p = function(u){
+ return (trans(u) - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return invtrans(p * unitlength / pixellength + max);
+ };
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ // var shim = t.getWidth()/2;
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js
new file mode 100644
index 00000000..694de41d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js
@@ -0,0 +1,611 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // class: $.jqplot.MekkoAxisRenderer
+ // An axis renderer for a Mekko chart.
+ // Should be used with a Mekko chart where the mekkoRenderer is used on the series.
+ // Displays the Y axis as a range from 0 to 1 (0 to 100%) and the x axis with a tick
+ // for each series scaled to the sum of all the y values.
+ $.jqplot.MekkoAxisRenderer = function() {
+ };
+
+ // called with scope of axis object.
+ $.jqplot.MekkoAxisRenderer.prototype.init = function(options){
+ // prop: tickMode
+ // How to space the ticks on the axis.
+ // 'bar' will place a tick at the width of each bar.
+ // This is the default for the x axis.
+ // 'even' will place ticks at even intervals. This is
+ // the default for x2 axis and y axis. y axis cannot be changed.
+ this.tickMode;
+ // prop: barLabelRenderer
+ // renderer to use to draw labels under each bar.
+ this.barLabelRenderer = $.jqplot.AxisLabelRenderer;
+ // prop: barLabels
+ // array of labels to put under each bar.
+ this.barLabels = this.barLabels || [];
+ // prop: barLabelOptions
+ // options object to pass to the bar label renderer.
+ this.barLabelOptions = {};
+ this.tickOptions = $.extend(true, {showGridline:false}, this.tickOptions);
+ this._barLabels = [];
+ $.extend(true, this, options);
+ if (this.name == 'yaxis') {
+ this.tickOptions.formatString = this.tickOptions.formatString || "%d\%";
+ }
+ var db = this._dataBounds;
+ db.min = 0;
+ // for y axes, scale always go from 0 to 1 (0 to 100%)
+ if (this.name == 'yaxis' || this.name == 'y2axis') {
+ db.max = 100;
+ this.tickMode = 'even';
+ }
+ // For x axes, scale goes from 0 to sum of all y values.
+ else if (this.name == 'xaxis'){
+ this.tickMode = (this.tickMode == null) ? 'bar' : this.tickMode;
+ for (var i=0; i<this._series.length; i++) {
+ db.max += this._series[i]._sumy;
+ }
+ }
+ else if (this.name == 'x2axis'){
+ this.tickMode = (this.tickMode == null) ? 'even' : this.tickMode;
+ for (var i=0; i<this._series.length; i++) {
+ db.max += this._series[i]._sumy;
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+ elem = null;
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // draw the axis label
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ this._elem.append(this._label.draw(ctx));
+ }
+
+ var t, tick, elem;
+ if (this.showTicks) {
+ t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ this._elem.append(tick.draw(ctx));
+ }
+ }
+ }
+
+ // draw the series labels
+ for (i=0; i<this.barLabels.length; i++) {
+ this.barLabelOptions.axis = this.name;
+ this.barLabelOptions.label = this.barLabels[i];
+ this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions));
+ if (this.tickMode != 'bar') {
+ this._barLabels[i].show = false;
+ }
+ if (this._barLabels[i].show) {
+ var elem = this._barLabels[i].draw(ctx, plot);
+ elem.removeClass('jqplot-'+this.name+'-label');
+ elem.addClass('jqplot-'+this.name+'-tick');
+ elem.addClass('jqplot-mekko-barLabel');
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+ }
+
+ }
+ return this._elem;
+ };
+
+ // called with scope of an axis
+ $.jqplot.MekkoAxisRenderer.prototype.reset = function() {
+ this.min = this._min;
+ this.max = this._max;
+ this.tickInterval = this._tickInterval;
+ this.numberTicks = this._numberTicks;
+ // this._ticks = this.__ticks;
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show && this.showTicks) {
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.createTicks = function() {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim, interval;
+ var min, max;
+ var pos1, pos2;
+ var t, tt, i, j;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = ut[0];
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ min = (this.min != null) ? this.min : db.min;
+ max = (this.max != null) ? this.max : db.max;
+
+ // if min and max are same, space them out a bit.+
+ if (min == max) {
+ var adj = 0.05;
+ if (min > 0) {
+ adj = Math.max(Math.log(min)/Math.LN10, 0.05);
+ }
+ min -= adj;
+ max += adj;
+ }
+
+ var range = max - min;
+ var rmin, rmax;
+ var temp, prev, curr;
+ var ynumticks = [3,5,6,11,21];
+
+ // yaxis divide ticks in nice intervals from 0 to 1.
+ if (this.name == 'yaxis' || this.name == 'y2axis') {
+ this.min = 0;
+ this.max = 100;
+ // user didn't specify number of ticks.
+ if (!this.numberTicks){
+ if (this.tickInterval) {
+ this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
+ }
+ else {
+ temp = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ for (i=0; i<ynumticks.length; i++) {
+ curr = temp/ynumticks[i];
+ if (curr == 1) {
+ this.numberTicks = ynumticks[i];
+ break;
+ }
+ else if (curr > 1) {
+ prev = curr;
+ continue;
+ }
+ else if (curr < 1) {
+ // was prev or is curr closer to one?
+ if (Math.abs(prev - 1) < Math.abs(curr - 1)) {
+ this.numberTicks = ynumticks[i-1];
+ break;
+ }
+ else {
+ this.numberTicks = ynumticks[i];
+ break;
+ }
+ }
+ else if (i == ynumticks.length -1) {
+ this.numberTicks = ynumticks[i];
+ }
+ }
+ this.tickInterval = range / (this.numberTicks - 1);
+ }
+ }
+
+ // user did specify number of ticks.
+ else {
+ this.tickInterval = range / (this.numberTicks - 1);
+ }
+
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ // for x axes, have number ot ticks equal to number of series and ticks placed
+ // at sum of y values for each series.
+ else if (this.tickMode == 'bar') {
+ this.min = 0;
+ this.numberTicks = this._series.length + 1;
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(0, this.name);
+ this._ticks.push(t);
+
+ temp = 0;
+
+ for (i=1; i<this.numberTicks; i++){
+ temp += this._series[i-1]._sumy;
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(temp, this.name);
+ this._ticks.push(t);
+ }
+ this.max = this.max || temp;
+
+ // if user specified a max and it is greater than sum, add a tick
+ if (this.max > temp) {
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(this.max, this.name);
+ this._ticks.push(t);
+
+ }
+ }
+
+ else if (this.tickMode == 'even') {
+ this.min = 0;
+ this.max = this.max || db.max;
+ // get a desired number of ticks
+ var nt = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ range = this.max - this.min;
+ this.numberTicks = nt;
+ this.tickInterval = range / (this.numberTicks - 1);
+
+ for (i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.pack = function(pos, offsets) {
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ var w;
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ // now show the labels under the bars.
+ var b, l, r;
+ for (var i=0; i<this.barLabels.length; i++) {
+ b = this._barLabels[i];
+ if (b.show) {
+ w = b.getWidth();
+ l = this._ticks[i].getLeft() + this._ticks[i].getWidth();
+ r = this._ticks[i+1].getLeft();
+ b._elem.css('left', (r+l-w)/2+'px');
+ b._elem.css('top', this._ticks[i]._elem.css('top'));
+ b.pack();
+ }
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+ };
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js
new file mode 100644
index 00000000..893e2b98
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js
@@ -0,0 +1,437 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.MekkoRenderer
+ * Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph.
+ * the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts. The mekko renderer
+ * overrides the default legend renderer with it's own $.jqplot.MekkoLegendRenderer
+ * which allows more flexibility to specify number of rows and columns in the legend.
+ *
+ * Data is specified per bar in the chart. You can specify data as an array of y values, or as
+ * an array of [label, value] pairs. Note that labels are used only on the first series.
+ * Labels on subsequent series are ignored:
+ *
+ * > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]];
+ * > bar2 = [15,6,9,13,6];
+ * > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]];
+ *
+ * If you want to place labels for each bar under the axis, you use the barLabels option on
+ * the axes. The bar labels can be styled with the ".jqplot-mekko-barLabel" css class.
+ *
+ * > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy'];
+ * > axes:{xaxis:{barLabels:barLabels}}
+ *
+ */
+
+
+ $.jqplot.MekkoRenderer = function(){
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ // prop: borderColor
+ // color of the borders between areas on the chart
+ this.borderColor = null;
+ // prop: showBorders
+ // True to draw borders lines between areas on the chart.
+ // False will draw borders lines with the same color as the area.
+ this.showBorders = true;
+ };
+
+ // called with scope of series.
+ $.jqplot.MekkoRenderer.prototype.init = function(options, plot) {
+ this.fill = false;
+ this.fillRect = true;
+ this.strokeRect = true;
+ this.shadow = false;
+ // width of bar on x axis.
+ this._xwidth = 0;
+ this._xstart = 0;
+ $.extend(true, this.renderer, options);
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect};
+ this.renderer.shapeRenderer.init(opts);
+ plot.axes.x2axis._series.push(this);
+ this._type = 'mekko';
+ };
+
+ // Method: setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array. Will convert user data into appropriate
+ // rectangles.
+ // Called with scope of a series.
+ $.jqplot.MekkoRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ this.gridData = [];
+ // figure out width on x axis.
+ // this._xwidth = this._sumy / plot._sumy * this.canvas.getWidth();
+ this._xwidth = xp(this._sumy) - xp(0);
+ if (this.index>0) {
+ this._xstart = plot.series[this.index-1]._xstart + plot.series[this.index-1]._xwidth;
+ }
+ var totheight = this.canvas.getHeight();
+ var sumy = 0;
+ var cury;
+ var curheight;
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ sumy += data[i][1];
+ cury = totheight - (sumy / this._sumy * totheight);
+ curheight = data[i][1] / this._sumy * totheight;
+ this.gridData.push([this._xstart, cury, this._xwidth, curheight]);
+ }
+ }
+ };
+
+ // Method: makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.MekkoRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ // figure out width on x axis.
+ var xp = this._xaxis.series_u2p;
+ var totheight = this.canvas.getHeight();
+ var sumy = 0;
+ var cury;
+ var curheight;
+ var gd = [];
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ sumy += data[i][1];
+ cury = totheight - (sumy / this._sumy * totheight);
+ curheight = data[i][1] / this._sumy * totheight;
+ gd.push([this._xstart, cury, this._xwidth, curheight]);
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.MekkoRenderer.prototype.draw = function(ctx, gd, options) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ ctx.save();
+ if (gd.length) {
+ if (showLine) {
+ for (i=0; i<gd.length; i++){
+ opts.fillStyle = colorGenerator.next();
+ if (this.renderer.showBorders) {
+ opts.strokeStyle = this.renderer.borderColor;
+ }
+ else {
+ opts.strokeStyle = opts.fillStyle;
+ }
+ this.renderer.shapeRenderer.draw(ctx, gd[i], opts);
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.MekkoRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, no shadows on mekko charts.
+ };
+
+ /**
+ * Class: $.jqplot.MekkoLegendRenderer
+ * Legend renderer used by mekko charts with options for
+ * controlling number or rows and columns as well as placement
+ * outside of plot area.
+ *
+ */
+ $.jqplot.MekkoLegendRenderer = function(){
+ //
+ };
+
+ $.jqplot.MekkoLegendRenderer.prototype.init = function(options) {
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ // this will override the placement option on the Legend object
+ this.placement = "outside";
+ $.extend(true, this, options);
+ };
+
+ // called with scope of legend
+ $.jqplot.MekkoLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Mekko charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = true, // mekko charts are always stacked, so reverse
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length) {
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+
+ tr = null;
+ td1 = null;
+ td2 = null;
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) {
+ if (this.show) {
+ // fake a grid for positioning
+ var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ var a = grid._left + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'ne':
+ var a = offsets.right + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = offsets.right + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = offsets.right + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = grid._left + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = grid._left + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid._right - this.xoffset;
+ var b = grid._bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+
+ }
+ else {
+ switch (this.location) {
+ case 'nw':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css('right', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('bottom', b);
+ break;
+ case 'ne':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'e':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'se':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'sw':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 'w':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid._right - this.xoffset;
+ var b = grid._bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+ }
+ }
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.MekkoRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.MekkoRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.MekkoAxisRenderer;
+ options.legend.renderer = $.jqplot.MekkoLegendRenderer;
+ options.legend.preDraw = true;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js
new file mode 100644
index 00000000..10a40949
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js
@@ -0,0 +1,1030 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.MeterGaugeRenderer
+ * Plugin renderer to draw a meter gauge chart.
+ *
+ * Data consists of a single series with 1 data point to position the gauge needle.
+ *
+ * To use this renderer, you need to include the
+ * meter gauge renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot0 = $.jqplot('chart0',[[18]],{
+ * > title: 'Network Speed',
+ * > seriesDefaults: {
+ * > renderer: $.jqplot.MeterGaugeRenderer,
+ * > rendererOptions: {
+ * > label: 'MB/s'
+ * > }
+ * > }
+ * > });
+ *
+ * A meterGauge plot does not support events.
+ */
+ $.jqplot.MeterGaugeRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer;
+
+ // called with scope of a series
+ $.jqplot.MeterGaugeRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the meterGauge, auto computed by default
+ this.diameter = null;
+ // prop: padding
+ // padding between the meterGauge and plot edges, auto
+ // calculated by default.
+ this.padding = null;
+ // prop: shadowOffset
+ // offset of the shadow from the gauge ring and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 4;
+ // prop: background
+ // background color of the inside of the gauge.
+ this.background = "#efefef";
+ // prop: ringColor
+ // color of the outer ring, hub, and needle of the gauge.
+ this.ringColor = "#BBC6D0";
+ // needle color not implemented yet.
+ this.needleColor = "#C3D3E5";
+ // prop: tickColor
+ // color of the tick marks around the gauge.
+ this.tickColor = "989898";
+ // prop: ringWidth
+ // width of the ring around the gauge. Auto computed by default.
+ this.ringWidth = null;
+ // prop: min
+ // Minimum value on the gauge. Auto computed by default
+ this.min;
+ // prop: max
+ // Maximum value on the gauge. Auto computed by default
+ this.max;
+ // prop: ticks
+ // Array of tick values. Auto computed by default.
+ this.ticks = [];
+ // prop: showTicks
+ // true to show ticks around gauge.
+ this.showTicks = true;
+ // prop: showTickLabels
+ // true to show tick labels next to ticks.
+ this.showTickLabels = true;
+ // prop: label
+ // A gauge label like 'kph' or 'Volts'
+ this.label = null;
+ // prop: labelHeightAdjust
+ // Number of Pixels to offset the label up (-) or down (+) from its default position.
+ this.labelHeightAdjust = 0;
+ // prop: labelPosition
+ // Where to position the label, either 'inside' or 'bottom'.
+ this.labelPosition = 'inside';
+ // prop: intervals
+ // Array of ranges to be drawn around the gauge.
+ // Array of form:
+ // > [value1, value2, ...]
+ // indicating the values for the first, second, ... intervals.
+ this.intervals = [];
+ // prop: intervalColors
+ // Array of colors to use for the intervals.
+ this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"];
+ // prop: intervalInnerRadius
+ // Radius of the inner circle of the interval ring.
+ this.intervalInnerRadius = null;
+ // prop: intervalOuterRadius
+ // Radius of the outer circle of the interval ring.
+ this.intervalOuterRadius = null;
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
+ // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc.
+ this.tickPositions = [1, 2, 2.5, 5, 10];
+ // prop: tickSpacing
+ // Degrees between ticks. This is a target number, if
+ // incompatible span and ticks are supplied, a suitable
+ // spacing close to this value will be computed.
+ this.tickSpacing = 30;
+ this.numberMinorTicks = null;
+ // prop: hubRadius
+ // Radius of the hub at the bottom center of gauge which the needle attaches to.
+ // Auto computed by default
+ this.hubRadius = null;
+ // prop: tickPadding
+ // padding of the tick marks to the outer ring and the tick labels to marks.
+ // Auto computed by default.
+ this.tickPadding = null;
+ // prop: needleThickness
+ // Maximum thickness the needle. Auto computed by default.
+ this.needleThickness = null;
+ // prop: needlePad
+ // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value.
+ this.needlePad = 6;
+ // prop: pegNeedle
+ // True will stop needle just below/above the min/max values if data is below/above min/max,
+ // as if the meter is "pegged".
+ this.pegNeedle = true;
+ this._type = 'meterGauge';
+
+ $.extend(true, this, options);
+ this.type = null;
+ this.numberTicks = null;
+ this.tickInterval = null;
+ // span, the sweep (in degrees) from min to max. This gauge is
+ // a semi-circle.
+ this.span = 180;
+ // get rid of this nonsense
+ // this.innerSpan = this.span;
+ if (this.type == 'circular') {
+ this.semiCircular = false;
+ }
+ else if (this.type != 'circular') {
+ this.semiCircular = true;
+ }
+ else {
+ this.semiCircular = (this.span <= 180) ? true : false;
+ }
+ this._tickPoints = [];
+ // reference to label element.
+ this._labelElem = null;
+
+ // start the gauge at the beginning of the span
+ this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180;
+ this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180;
+
+ this.setmin = !!(this.min == null);
+ this.setmax = !!(this.max == null);
+
+ // if given intervals and is an array of values, create labels and colors.
+ if (this.intervals.length) {
+ if (this.intervals[0].length == null || this.intervals.length == 1) {
+ for (var i=0; i<this.intervals.length; i++) {
+ this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]];
+ }
+ }
+ else if (this.intervals[0].length == 2) {
+ for (i=0; i<this.intervals.length; i++) {
+ this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]];
+ }
+ }
+ }
+
+ // compute min, max and ticks if not supplied:
+ if (this.ticks.length) {
+ if (this.ticks[0].length == null || this.ticks[0].length == 1) {
+ for (var i=0; i<this.ticks.length; i++) {
+ this.ticks[i] = [this.ticks[i], this.ticks[i]];
+ }
+ }
+ this.min = (this.min == null) ? this.ticks[0][0] : this.min;
+ this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max;
+ this.setmin = false;
+ this.setmax = false;
+ this.numberTicks = this.ticks.length;
+ this.tickInterval = this.ticks[1][0] - this.ticks[0][0];
+ this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11)));
+ // use the first interal to calculate minor ticks;
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = 1;
+ }
+ }
+
+ else if (this.intervals.length) {
+ this.min = (this.min == null) ? 0 : this.min;
+ this.setmin = false;
+ if (this.max == null) {
+ if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) {
+ this.max = this.intervals[this.intervals.length-1][0];
+ this.setmax = false;
+ }
+ }
+ else {
+ this.setmax = false;
+ }
+ }
+
+ else {
+ // no ticks and no intervals supplied, put needle in middle
+ this.min = (this.min == null) ? 0 : this.min;
+ this.setmin = false;
+ if (this.max == null) {
+ this.max = this.data[0][1] * 1.25;
+ this.setmax = true;
+ }
+ else {
+ this.setmax = false;
+ }
+ }
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle;
+ for (var i=0; i<this.data.length; i++){
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle;
+ for (var i=0; i<data.length; i++){
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ }
+ return td;
+ };
+
+
+ function getnmt(pos, interval, fact) {
+ var temp;
+ for (var i=pos.length-1; i>=0; i--) {
+ temp = interval/(pos[i] * Math.pow(10, fact));
+ if (temp == 4 || temp == 5) {
+ return temp - 1;
+ }
+ }
+ return null;
+ }
+
+ // called with scope of series
+ $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ if (options.legendInfo && options.legendInfo.placement == 'inside') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+
+ // pre-draw so can get it's dimensions.
+ if (this.label) {
+ this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
+ this.canvas._elem.after(this._labelElem);
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ if (this.padding == null) {
+ this.padding = Math.round(Math.min(cw, ch)/30);
+ }
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ if (this.labelPosition == 'bottom' && this.label) {
+ h -= this._labelElem.outerHeight(true);
+ }
+ var mindim = Math.min(w,h);
+ var d = mindim;
+
+ if (!this.diameter) {
+ if (this.semiCircular) {
+ if ( w >= 2*h) {
+ if (!this.ringWidth) {
+ this.ringWidth = 2*h/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
+ this.diameter = 2 * (h - 2*this.innerPad);
+ }
+ else {
+ if (!this.ringWidth) {
+ this.ringWidth = w/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
+ this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding;
+ }
+ // center taking into account legend and over draw for gauge bottom below hub.
+ // this will be center of hub.
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)];
+ }
+ else {
+ if (!this.ringWidth) {
+ this.ringWidth = d/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = 0;
+ this.diameter = d - this.ringWidth;
+ // center in middle of canvas taking into account legend.
+ // will be center of hub.
+ this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy];
+ }
+ }
+
+
+ if (this._labelElem && this.labelPosition == 'bottom') {
+ this._center[1] -= this._labelElem.outerHeight(true);
+ }
+
+ this._radius = this.diameter/2;
+
+ this.tickSpacing = 6000/this.diameter;
+
+ if (!this.hubRadius) {
+ this.hubRadius = this.diameter/18;
+ }
+
+ this.shadowOffset = 0.5 + this.ringWidth/9;
+ this.shadowWidth = this.ringWidth*1;
+
+ this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7);
+ this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding;
+ this.tickLength = (this.showTicks) ? this._radius/13 : 0;
+
+ if (this.ticks.length == 0) {
+ // no ticks, lets make some.
+ var max = this.max,
+ min = this.min,
+ setmax = this.setmax,
+ setmin = this.setmin,
+ ti = (max - min) * this.tickSpacing / this.span;
+ var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11)));
+ var tp = (ti/Math.pow(10, tf));
+ (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp);
+ var t = this.tickPositions;
+ var tpindex, nt;
+
+ for (i=0; i<t.length; i++) {
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
+ ti = t[i]*Math.pow(10, tf);
+ tpindex = i;
+ }
+ }
+
+ for (i=0; i<t.length; i++) {
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
+ ti = t[i]*Math.pow(10, tf);
+ nt = Math.ceil((max - min) / ti);
+ }
+ }
+
+ // both max and min are free
+ if (setmax && setmin) {
+ var tmin = (min > 0) ? min - min % ti : min - min % ti - ti;
+ if (!this.forceZero) {
+ var diff = Math.min(min - tmin, 0.8*ti);
+ var ntp = Math.floor(diff/t[tpindex]);
+ if (ntp > 1) {
+ tmin = tmin + t[tpindex] * (ntp-1);
+ if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) {
+ tmin = tmin - t[tpindex];
+ }
+ }
+ }
+ if (min == tmin) {
+ min -= ti;
+ }
+ else {
+ // tmin should always be lower than dataMin
+ if (min - tmin > 0.23*ti) {
+ min = tmin;
+ }
+ else {
+ min = tmin -ti;
+ nt += 1;
+ }
+ }
+ nt += 1;
+ var tmax = min + (nt - 1) * ti;
+ if (max >= tmax) {
+ tmax += ti;
+ nt += 1;
+ }
+ // now tmax should always be mroe than dataMax
+ if (tmax - max < 0.23*ti) {
+ tmax += ti;
+ nt += 1;
+ }
+ this.max = max = tmax;
+ this.min = min;
+
+ this.tickInterval = ti;
+ this.numberTicks = nt;
+ var it;
+ for (i=0; i<nt; i++) {
+ it = parseFloat((min+i*ti).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ this.max = this.ticks[nt-1][1];
+
+ this.tickFactor = tf;
+ // determine number of minor ticks
+
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ }
+ // max is free, min is fixed
+ else if (setmax) {
+ var tmax = min + (nt - 1) * ti;
+ if (max >= tmax) {
+ max = tmax + ti;
+ nt += 1;
+ }
+ else {
+ max = tmax;
+ }
+
+ this.tickInterval = this.tickInterval || ti;
+ this.numberTicks = this.numberTicks || nt;
+ var it;
+ for (i=0; i<this.numberTicks; i++) {
+ it = parseFloat((min+i*this.tickInterval).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ this.max = this.ticks[this.numberTicks-1][1];
+
+ this.tickFactor = tf;
+ // determine number of minor ticks
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ }
+
+ // not setting max or min
+ if (!setmax && !setmin) {
+ var range = this.max - this.min;
+ tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1;
+ var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange;
+ // check to see how many zeros are at the end of the range
+ if (range > 1) {
+ var rstr = String(range);
+ if (rstr.search(/\./) == -1) {
+ var pos = rstr.search(/0+$/);
+ nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0;
+ }
+ }
+ sigRange = range/Math.pow(10, nonSigDigits);
+ for (i=0; i<nticks.length; i++) {
+ res = sigRange/(nticks[i]-1);
+ if (res == parseInt(res, 10)) {
+ this.numberTicks = nticks[i];
+ this.tickInterval = range/(this.numberTicks-1);
+ this.tickFactor = tf+1;
+ break;
+ }
+ }
+ var it;
+ for (i=0; i<this.numberTicks; i++) {
+ it = parseFloat((this.min+i*this.tickInterval).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ // determine number of minor ticks
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = 1;
+ var nums = [4, 5, 3, 6, 2];
+ for (i=0; i<5; i++) {
+ var temp = this.tickInterval/nums[i];
+ if (temp == parseInt(temp, 10)) {
+ this.numberMinorTicks = nums[i]-1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ var r = this._radius,
+ sa = this.startAngle,
+ ea = this.endAngle,
+ pi = Math.PI,
+ hpi = Math.PI/2;
+
+ if (this.semiCircular) {
+ var overAngle = Math.atan(this.innerPad/r),
+ outersa = this.outerStartAngle = sa - overAngle,
+ outerea = this.outerEndAngle = ea + overAngle,
+ hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2),
+ hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2);
+
+ ctx.save();
+
+ ctx.translate(this._center[0], this._center[1]);
+ ctx.lineJoin = "round";
+ ctx.lineCap = "round";
+
+ // draw the innerbackground
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.background;
+ ctx.arc(0, 0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+
+ // draw the shadow
+ // the outer ring.
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ ctx.save();
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ ctx.beginPath();
+ ctx.strokeStyle = shadowColor;
+ ctx.lineWidth = this.shadowWidth;
+ ctx.arc(0 ,0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.stroke();
+ }
+ ctx.restore();
+
+ // the inner hub.
+ ctx.save();
+ var tempd = parseInt((this.shadowDepth+1)/2, 10);
+ for (var i=0; i<tempd; i++) {
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ ctx.beginPath();
+ ctx.fillStyle = shadowColor;
+ ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+
+ // draw the outer ring.
+ ctx.save();
+ ctx.beginPath();
+ ctx.strokeStyle = this.ringColor;
+ ctx.lineWidth = this.ringWidth;
+ ctx.arc(0 ,0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore();
+
+ // draw the hub
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.ringColor;
+ ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+
+ // draw the ticks
+ if (this.showTicks) {
+ ctx.save();
+ var orad = this.tickOuterRadius,
+ tl = this.tickLength,
+ mtl = tl/2,
+ nmt = this.numberMinorTicks,
+ ts = this.span * Math.PI / 180 / (this.ticks.length-1),
+ mts = ts/(nmt + 1);
+
+ for (i = 0; i<this.ticks.length; i++) {
+ ctx.beginPath();
+ ctx.lineWidth = 1.5 + this.diameter/360;
+ ctx.strokeStyle = this.ringColor;
+ var wps = ts*i+sa;
+ ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa));
+ ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa));
+ this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]);
+ ctx.stroke();
+ ctx.lineWidth = 1.0 + this.diameter/440;
+ if (i<this.ticks.length-1) {
+ for (var j=1; j<=nmt; j++) {
+ ctx.beginPath();
+ ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa));
+ ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa));
+ ctx.stroke();
+ }
+ }
+ }
+ ctx.restore();
+ }
+
+ // draw the tick labels
+ if (this.showTickLabels) {
+ var elem, l, t, ew, eh, dim, maxdim=0;
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
+ for (i=0; i<this.ticks.length; i++) {
+ elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>');
+ this.canvas._elem.after(elem);
+ ew = elem.outerWidth(true);
+ eh = elem.outerHeight(true);
+ l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]);
+ t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ;
+ // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]);
+ elem.css({left:l, top:t});
+ dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2);
+ maxdim = (dim > maxdim) ? dim : maxdim;
+ }
+ }
+
+ // draw the gauge label
+ if (this.label && this.labelPosition == 'inside') {
+ var l = this._center[0] + this.canvas._offsets.left;
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
+ var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust;
+ // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
+ // this.canvas._elem.after(this._labelElem);
+ l -= this._labelElem.outerWidth(true)/2;
+ t -= this._labelElem.outerHeight(true)/2;
+ this._labelElem.css({left:l, top:t});
+ }
+
+ else if (this.label && this.labelPosition == 'bottom') {
+ var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2;
+ var t = this._center[1] + this.canvas._offsets.top + this.innerPad + + this.ringWidth + this.padding + this.labelHeightAdjust;
+ this._labelElem.css({left:l, top:t});
+
+ }
+
+ // draw the intervals
+
+ ctx.save();
+ var inner = this.intervalInnerRadius || this.hubRadius * 1.5;
+ if (this.intervalOuterRadius == null) {
+ if (this.showTickLabels) {
+ var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8);
+ }
+ else {
+ var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16);
+ }
+ }
+ else {
+ var outer = this.intervalOuterRadius;
+ }
+ var range = this.max - this.min;
+ var intrange = this.intervals[this.intervals.length-1] - this.min;
+ var start, end, span = this.span*Math.PI/180;
+ for (i=0; i<this.intervals.length; i++) {
+ start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range;
+ if (start < 0) {
+ start = 0;
+ }
+ end = sa + (this.intervals[i][0] - this.min)*span/range;
+ if (end < 0) {
+ end = 0;
+ }
+ ctx.beginPath();
+ ctx.fillStyle = this.intervals[i][2];
+ ctx.arc(0, 0, inner, start, end, false);
+ ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end));
+ ctx.arc(0, 0, outer, end, start, true);
+ ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start));
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+
+ // draw the needle
+ var datapoint = this.data[0][1];
+ var dataspan = this.max - this.min;
+ if (this.pegNeedle) {
+ if (this.data[0][1] > this.max + dataspan*3/this.span) {
+ datapoint = this.max + dataspan*3/this.span;
+ }
+ if (this.data[0][1] < this.min - dataspan*3/this.span) {
+ datapoint = this.min - dataspan*3/this.span;
+ }
+ }
+ var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle;
+
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.ringColor;
+ ctx.strokeStyle = this.ringColor;
+ this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85;
+ this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness;
+ var endwidth = this.needleThickness * 0.4;
+
+
+ var dl = this.needleLength/10;
+ var dt = (this.needleThickness - endwidth)/10;
+ var templ;
+ for (var i=0; i<10; i++) {
+ templ = this.needleThickness - i*dt;
+ ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang));
+ ctx.lineWidth = templ;
+ ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang));
+ ctx.stroke();
+ }
+
+ ctx.restore();
+ }
+ else {
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
+ }
+ };
+
+ $.jqplot.MeterGaugeAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer;
+
+
+ // There are no traditional axes on a gauge chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+ $.jqplot.MeterGaugeLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer;
+
+ /**
+ * Class: $.jqplot.MeterGaugeLegendRenderer
+ *Meter gauges don't typically have a legend, this overrides the default legend renderer.
+ */
+ $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) {
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() {
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // MeterGauge charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ // debugger
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = s.color;
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ // debugger
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ options.grid = options.grid || {};
+
+ // only set these if there is a gauge series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer;
+ options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer;
+ options.legend.preDraw = true;
+ options.grid.background = options.grid.background || 'white';
+ options.grid.drawGridlines = false;
+ options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0;
+ options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false;
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ //
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+ $.jqplot.postParseOptionsHooks.push(postParseOptions);
+
+ $.jqplot.MeterGaugeTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js
new file mode 100644
index 00000000..22b77464
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js
@@ -0,0 +1,45 @@
+/**
+ * jqplot.jquerymobile plugin
+ * jQuery Mobile virtual event support.
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2011 Takashi Okamoto
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ */
+(function($) {
+ function postInit(target, data, options){
+ this.bindCustomEvents = function() {
+ this.eventCanvas._elem.bind('vclick', {plot:this}, this.onClick);
+ this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('taphold', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('vmousedown', {plot:this}, this.onMouseDown);
+ this.eventCanvas._elem.bind('vmousemove', {plot:this}, this.onMouseMove);
+ this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
+ if (this.captureRightClick) {
+ this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onRightClick);
+ this.eventCanvas._elem.get(0).oncontextmenu = function() {
+ return false;
+ };
+ }
+ else {
+ this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onMouseUp);
+ }
+ };
+ this.plugins.mobile = true;
+ }
+ $.jqplot.postInitHooks.push(postInit);
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js
new file mode 100644
index 00000000..2f143f1b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js
@@ -0,0 +1,373 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.OHLCRenderer
+ * jqPlot Plugin to draw Open Hi Low Close, Candlestick and Hi Low Close charts.
+ *
+ * To use this plugin, include the renderer js file in
+ * your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.ohlcRenderer.js"></script>
+ *
+ * You will most likely want to use a date axis renderer
+ * for the x axis also, so include the date axis render js file also:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
+ *
+ * Then you set the renderer in the series options on your plot:
+ *
+ * > series: [{renderer:$.jqplot.OHLCRenderer}]
+ *
+ * For OHLC and candlestick charts, data should be specified
+ * like so:
+ *
+ * > dat = [['07/06/2009',138.7,139.68,135.18,135.4], ['06/29/2009',143.46,144.66,139.79,140.02], ...]
+ *
+ * If the data array has only 4 values per point instead of 5,
+ * the renderer will create a Hi Low Close chart instead. In that case,
+ * data should be supplied like:
+ *
+ * > dat = [['07/06/2009',139.68,135.18,135.4], ['06/29/2009',144.66,139.79,140.02], ...]
+ *
+ * To generate a candlestick chart instead of an OHLC chart,
+ * set the "candlestick" option to true:
+ *
+ * > series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}],
+ *
+ */
+ $.jqplot.OHLCRenderer = function(){
+ // subclass line renderer to make use of some of it's methods.
+ $.jqplot.LineRenderer.call(this);
+ // prop: candleStick
+ // true to render chart as candleStick.
+ // Must have an open price, cannot be a hlc chart.
+ this.candleStick = false;
+ // prop: tickLength
+ // length of the line in pixels indicating open and close price.
+ // Default will auto calculate based on plot width and
+ // number of points displayed.
+ this.tickLength = 'auto';
+ // prop: bodyWidth
+ // width of the candlestick body in pixels. Default will auto calculate
+ // based on plot width and number of candlesticks displayed.
+ this.bodyWidth = 'auto';
+ // prop: openColor
+ // color of the open price tick mark. Default is series color.
+ this.openColor = null;
+ // prop: closeColor
+ // color of the close price tick mark. Default is series color.
+ this.closeColor = null;
+ // prop: wickColor
+ // color of the hi-lo line thorugh the candlestick body.
+ // Default is the series color.
+ this.wickColor = null;
+ // prop: fillUpBody
+ // true to render an "up" day (close price greater than open price)
+ // with a filled candlestick body.
+ this.fillUpBody = false;
+ // prop: fillDownBody
+ // true to render a "down" day (close price lower than open price)
+ // with a filled candlestick body.
+ this.fillDownBody = true;
+ // prop: upBodyColor
+ // Color of candlestick body of an "up" day. Default is series color.
+ this.upBodyColor = null;
+ // prop: downBodyColor
+ // Color of candlestick body on a "down" day. Default is series color.
+ this.downBodyColor = null;
+ // prop: hlc
+ // true if is a hi-low-close chart (no open price).
+ // This is determined automatically from the series data.
+ this.hlc = false;
+ // prop: lineWidth
+ // Width of the hi-low line and open/close ticks.
+ // Must be set in the rendererOptions for the series.
+ this.lineWidth = 1.5;
+ this._tickLength;
+ this._bodyWidth;
+ };
+
+ $.jqplot.OHLCRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.OHLCRenderer.prototype.constructor = $.jqplot.OHLCRenderer;
+
+ // called with scope of series.
+ $.jqplot.OHLCRenderer.prototype.init = function(options) {
+ options = options || {};
+ // lineWidth has to be set on the series, changes in renderer
+ // constructor have no effect. set the default here
+ // if no renderer option for lineWidth is specified.
+ this.lineWidth = options.lineWidth || 1.5;
+ $.jqplot.LineRenderer.prototype.init.call(this, options);
+ this._type = 'ohlc';
+ // set the yaxis data bounds here to account for hi and low values
+ var db = this._yaxis._dataBounds;
+ var d = this._plotData;
+ // if data points have less than 5 values, force a hlc chart.
+ if (d[0].length < 5) {
+ this.renderer.hlc = true;
+
+ for (var j=0; j<d.length; j++) {
+ if (d[j][2] < db.min || db.min == null) {
+ db.min = d[j][2];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ else {
+ for (var j=0; j<d.length; j++) {
+ if (d[j][3] < db.min || db.min == null) {
+ db.min = d[j][3];
+ }
+ if (d[j][2] > db.max || db.max == null) {
+ db.max = d[j][2];
+ }
+ }
+ }
+
+ };
+
+ // called within scope of series.
+ $.jqplot.OHLCRenderer.prototype.draw = function(ctx, gd, options) {
+ var d = this.data;
+ var xmin = this._xaxis.min;
+ var xmax = this._xaxis.max;
+ // index of last value below range of plot.
+ var xminidx = 0;
+ // index of first value above range of plot.
+ var xmaxidx = d.length;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var i, prevColor, ops, b, h, w, a, points;
+ var o;
+ var r = this.renderer;
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
+ r.bodyWidth = (opts.bodyWidth != undefined) ? opts.bodyWidth : r.bodyWidth;
+ r.tickLength = (opts.tickLength != undefined) ? opts.tickLength : r.tickLength;
+ ctx.save();
+ if (this.show) {
+ var x, open, hi, low, close;
+ // need to get widths based on number of points shown,
+ // not on total number of points. Use the results
+ // to speed up drawing in next step.
+ for (var i=0; i<d.length; i++) {
+ if (d[i][0] < xmin) {
+ xminidx = i;
+ }
+ else if (d[i][0] < xmax) {
+ xmaxidx = i+1;
+ }
+ }
+
+ var dwidth = this.gridData[xmaxidx-1][0] - this.gridData[xminidx][0];
+ var nvisiblePoints = xmaxidx - xminidx;
+ try {
+ var dinterval = Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval, 10)) - this._xaxis.series_u2p(0));
+ }
+
+ catch (e) {
+ var dinterval = dwidth / nvisiblePoints;
+ }
+
+ if (r.candleStick) {
+ if (typeof(r.bodyWidth) == 'number') {
+ r._bodyWidth = r.bodyWidth;
+ }
+ else {
+ r._bodyWidth = Math.min(20, dinterval/1.65);
+ }
+ }
+ else {
+ if (typeof(r.tickLength) == 'number') {
+ r._tickLength = r.tickLength;
+ }
+ else {
+ r._tickLength = Math.min(10, dinterval/3.5);
+ }
+ }
+
+ for (var i=xminidx; i<xmaxidx; i++) {
+ x = xp(d[i][0]);
+ if (r.hlc) {
+ open = null;
+ hi = yp(d[i][1]);
+ low = yp(d[i][2]);
+ close = yp(d[i][3]);
+ }
+ else {
+ open = yp(d[i][1]);
+ hi = yp(d[i][2]);
+ low = yp(d[i][3]);
+ close = yp(d[i][4]);
+ }
+ o = {};
+ if (r.candleStick && !r.hlc) {
+ w = r._bodyWidth;
+ a = x - w/2;
+ // draw candle
+ // determine if candle up or down
+ // up, remember grid coordinates increase downward
+ if (close < open) {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ else if (r.downBodyColor) {
+ o.color = r.upBodyColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, close]], ops);
+ r.shapeRenderer.draw(ctx, [[x, open], [x, low]], ops);
+ o = {};
+ b = close;
+ h = open - close;
+ // if color specified, use it
+ if (r.fillUpBody) {
+ o.fillRect = true;
+ }
+ else {
+ o.strokeRect = true;
+ w = w - this.lineWidth;
+ a = x - w/2;
+ }
+ if (r.upBodyColor) {
+ o.color = r.upBodyColor;
+ o.fillStyle = r.upBodyColor;
+ }
+ points = [a, b, w, h];
+ }
+ // down
+ else if (close > open) {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ else if (r.downBodyColor) {
+ o.color = r.downBodyColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, open]], ops);
+ r.shapeRenderer.draw(ctx, [[x, close], [x, low]], ops);
+
+ o = {};
+
+ b = open;
+ h = close - open;
+ // if color specified, use it
+ if (r.fillDownBody) {
+ o.fillRect = true;
+ }
+ else {
+ o.strokeRect = true;
+ w = w - this.lineWidth;
+ a = x - w/2;
+ }
+ if (r.downBodyColor) {
+ o.color = r.downBodyColor;
+ o.fillStyle = r.downBodyColor;
+ }
+ points = [a, b, w, h];
+ }
+ // even, open = close
+ else {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], ops);
+ o = {};
+ o.fillRect = false;
+ o.strokeRect = false;
+ a = [x - w/2, open];
+ b = [x + w/2, close];
+ w = null;
+ h = null;
+ points = [a, b];
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, points, ops);
+ }
+ else {
+ prevColor = opts.color;
+ if (r.openColor) {
+ opts.color = r.openColor;
+ }
+ // draw open tick
+ if (!r.hlc) {
+ r.shapeRenderer.draw(ctx, [[x-r._tickLength, open], [x, open]], opts);
+ }
+ opts.color = prevColor;
+ // draw wick
+ if (r.wickColor) {
+ opts.color = r.wickColor;
+ }
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], opts);
+ opts.color = prevColor;
+ // draw close tick
+ if (r.closeColor) {
+ opts.color = r.closeColor;
+ }
+ r.shapeRenderer.draw(ctx, [[x, close], [x+r._tickLength, close]], opts);
+ opts.color = prevColor;
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.OHLCRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ // called with scope of plot.
+ $.jqplot.OHLCRenderer.checkOptions = function(target, data, options) {
+ // provide some sensible highlighter options by default
+ // These aren't good for hlc, only for ohlc or candlestick
+ if (!options.highlighter) {
+ options.highlighter = {
+ showMarker:false,
+ tooltipAxes: 'y',
+ yvalues: 4,
+ formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'
+ };
+ }
+ };
+
+ //$.jqplot.preInitHooks.push($.jqplot.OHLCRenderer.checkOptions);
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js
new file mode 100644
index 00000000..2479885c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js
@@ -0,0 +1,904 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.PieRenderer
+ * Plugin renderer to draw a pie chart.
+ * x values, if present, will be used as slice labels.
+ * y values give slice size.
+ *
+ * To use this renderer, you need to include the
+ * pie renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.PieRenderer,
+ * > rendererOptions:{
+ * > sliceMargin: 2,
+ * > startAngle: -90
+ * > }
+ * > }
+ * > });
+ *
+ * A pie plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (slice) index, and the point data for
+ * the appropriate slice.
+ *
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted slice.
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.PieRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
+
+ // called with scope of a series
+ $.jqplot.PieRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the pie, auto computed by default
+ this.diameter = null;
+ // prop: padding
+ // padding between the pie and plot edges, legend, etc.
+ this.padding = 20;
+ // prop: sliceMargin
+ // angular spacing between pie slices in degrees.
+ this.sliceMargin = 0;
+ // prop: fill
+ // true or false, wether to fil the slices.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0-100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ // prop: dataLabelPositionFactor
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
+ this.dataLabelPositionFactor = 0.52;
+ // prop: dataLabelNudge
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
+ this.dataLabelNudge = 2;
+ // prop: dataLabelCenterOn
+ // True to center the data label at its position.
+ // False to set the inside facing edge of the label at its position.
+ this.dataLabelCenterOn = true;
+ // prop: startAngle
+ // Angle to start drawing pie in degrees.
+ // According to orientation of canvas coordinate system:
+ // 0 = on the positive x axis
+ // -90 = on the positive y axis.
+ // 90 = on the negaive y axis.
+ // 180 or - 180 = on the negative x axis.
+ this.startAngle = 0;
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ // Used as check for conditions where pie shouldn't be drawn.
+ this._drawData = true;
+ this._type = 'pie';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ if (this.sliceMargin < 0) {
+ this.sliceMargin = 0;
+ }
+
+ this._diameter = null;
+ this._radius = null;
+ // array of [start,end] angles arrays, one for each slice. In radians.
+ this._sliceAngles = [];
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ };
+
+ $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle/180*Math.PI;
+ var tot = 0;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<this.data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += this.data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = this.data[i][1]/tot;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var tot = 0;
+ var sa = this.startAngle/180*Math.PI;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = data[i][1]/tot;
+ }
+ return td;
+ };
+
+ function calcRadiusAdjustment(ang) {
+ return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0);
+ }
+
+ function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
+ var rprime = 0;
+ var ang = ang2 - ang1;
+ var absang = Math.abs(ang);
+ var sm = sliceMargin;
+ if (fill == false) {
+ sm += lineWidth;
+ }
+
+ if (sm > 0 && absang > 0.01 && absang < 6.282) {
+ rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang);
+ }
+
+ return rprime;
+ }
+
+ $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
+ if (this._drawData) {
+ var r = this._radius;
+ var fill = this.fill;
+ var lineWidth = this.lineWidth;
+ var sm = this.sliceMargin;
+ if (this.fill == false) {
+ sm += this.lineWidth;
+ }
+ ctx.save();
+ ctx.translate(this._center[0], this._center[1]);
+
+ var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
+
+ var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
+ var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
+
+ if ((ang2 - ang1) <= Math.PI) {
+ r -= rprime;
+ }
+ else {
+ r += rprime;
+ }
+
+ ctx.translate(transx, transy);
+
+ if (isShadow) {
+ for (var i=0, l=this.shadowDepth; i<l; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw(r);
+ }
+ for (var i=0, l=this.shadowDepth; i<l; i++) {
+ ctx.restore();
+ }
+ }
+
+ else {
+ doDraw(r);
+ }
+ ctx.restore();
+ }
+
+ function doDraw (rad) {
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
+ // 2Pi = 6.2831853, Pi = 3.1415927
+ if (ang2 > 6.282 + this.startAngle) {
+ ang2 = 6.282 + this.startAngle;
+ if (ang1 > ang2) {
+ ang1 = 6.281 + this.startAngle;
+ }
+ }
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
+ // ugly line on unfilled pies.
+ if (ang1 >= ang2) {
+ return;
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.arc(0, 0, rad, ang1, ang2, false);
+ ctx.lineTo(0,0);
+ ctx.closePath();
+
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ };
+
+ // called with scope of series
+ $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ var mindim = Math.min(w,h);
+ var d = mindim;
+
+ // Fixes issue #272. Thanks hugwijst!
+ // reset slice angles array.
+ this._sliceAngles = [];
+
+ var sm = this.sliceMargin;
+ if (this.fill == false) {
+ sm += this.lineWidth;
+ }
+
+ var rprime;
+ var maxrprime = 0;
+
+ var ang, ang1, ang2, shadowColor;
+ var sa = this.startAngle / 180 * Math.PI;
+
+ // have to pre-draw shadows, so loop throgh here and calculate some values also.
+ for (var i=0, l=gd.length; i<l; i++) {
+ ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ ang2 = gd[i][1] + sa;
+
+ this._sliceAngles.push([ang1, ang2]);
+
+ rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
+
+ if (Math.abs(ang2-ang1) > Math.PI) {
+ maxrprime = Math.max(rprime, maxrprime);
+ }
+ }
+
+ if (this.diameter != null && this.diameter > 0) {
+ this._diameter = this.diameter - 2*maxrprime;
+ }
+ else {
+ this._diameter = d - 2*maxrprime;
+ }
+
+ // Need to check for undersized pie. This can happen if
+ // plot area too small and legend is too big.
+ if (this._diameter < 6) {
+ $.jqplot.log('Diameter of pie too small, not rendering.');
+ return;
+ }
+
+ var r = this._radius = this._diameter/2;
+
+ this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)];
+
+ if (this.shadow) {
+ for (var i=0, l=gd.length; i<l; i++) {
+ shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true);
+ }
+ }
+
+ for (var i=0; i<gd.length; i++) {
+
+ this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false);
+
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
+ var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
+ }
+
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
+
+ var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
+ if (this.dataLabelCenterOn) {
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ }
+ else {
+ x -= labelelem.width() * Math.sin(avgang/2);
+ y -= labelelem.height()/2;
+ }
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+ }
+ };
+
+ $.jqplot.PieAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
+
+
+ // There are no traditional axes on a pie chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.PieAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+
+ $.jqplot.PieLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
+
+ /**
+ * Class: $.jqplot.PieLegendRenderer
+ * Legend Renderer specific to pie plots. Set by default
+ * when user creates a pie plot.
+ */
+ $.jqplot.PieLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.PieLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+
+
+ this._elem = $(document.createElement('table'));
+ this._elem.addClass('jqplot-table-legend');
+
+ var ss = {position:'absolute'};
+ if (this.background) {
+ ss['background'] = this.background;
+ }
+ if (this.border) {
+ ss['border'] = this.border;
+ }
+ if (this.fontSize) {
+ ss['fontSize'] = this.fontSize;
+ }
+ if (this.fontFamily) {
+ ss['fontFamily'] = this.fontFamily;
+ }
+ if (this.textColor) {
+ ss['textColor'] = this.textColor;
+ }
+ if (this.marginTop != null) {
+ ss['marginTop'] = this.marginTop;
+ }
+ if (this.marginBottom != null) {
+ ss['marginBottom'] = this.marginBottom;
+ }
+ if (this.marginLeft != null) {
+ ss['marginLeft'] = this.marginLeft;
+ }
+ if (this.marginRight != null) {
+ ss['marginRight'] = this.marginRight;
+ }
+
+ this._elem.css(ss);
+
+ // Pie charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr,
+ nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j;
+ var tr, td1, td2;
+ var lt, rs, color;
+ var idx = 0;
+ var div0, div1;
+
+ for (i=0; i<nr; i++) {
+ tr = $(document.createElement('tr'));
+ tr.addClass('jqplot-table-legend');
+
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+
+ else{
+ tr.appendTo(this._elem);
+ }
+
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+
+
+ td1 = $(document.createElement('td'));
+ td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td1.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+ td1.append(div0.append(div1));
+
+ td2 = $(document.createElement('td'));
+ td2.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td2.css('paddingTop', rs);
+
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ plot.target.trigger('jqplotDataMouseOver', ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ plot.target.trigger('jqplotDataHighlight', ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ };
+
+
+ // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
+ options.legend.renderer = $.jqplot.PieLegendRenderer;
+ options.legend.preDraw = true;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.pieRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) {
+ this.plugins.pieRenderer.highlightCanvas.resetCanvas();
+ this.plugins.pieRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.pieRenderer = {highlightedSeriesIndex:null};
+ this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ // do we have any data labels? if so, put highlight canvas before those
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+
+ var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.PieTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js
new file mode 100644
index 00000000..c20a9c44
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js
@@ -0,0 +1,379 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.PointLabels
+ * Plugin for putting labels at the data points.
+ *
+ * To use this plugin, include the js
+ * file in your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.pointLabels.js"></script>
+ *
+ * By default, the last value in the data ponit array in the data series is used
+ * for the label. For most series renderers, extra data can be added to the
+ * data point arrays and the last value will be used as the label.
+ *
+ * For instance,
+ * this series:
+ *
+ * > [[1,4], [3,5], [7,2]]
+ *
+ * Would, by default, use the y values in the labels.
+ * Extra data can be added to the series like so:
+ *
+ * > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']]
+ *
+ * And now the point labels would be 'mid', 'low', and 'hi'.
+ *
+ * Options to the point labels and a custom labels array can be passed into the
+ * "pointLabels" option on the series option like so:
+ *
+ * > series:[{pointLabels:{
+ * > labels:['mid', 'hi', 'low'],
+ * > location:'se',
+ * > ypadding: 12
+ * > }
+ * > }]
+ *
+ * A custom labels array in the options takes precendence over any labels
+ * in the series data. If you have a custom labels array in the options,
+ * but still want to use values from the series array as labels, set the
+ * "labelsFromSeries" option to true.
+ *
+ * By default, html entities (<, >, etc.) are escaped in point labels.
+ * If you want to include actual html markup in the labels,
+ * set the "escapeHTML" option to false.
+ *
+ */
+ $.jqplot.PointLabels = function(options) {
+ // Group: Properties
+ //
+ // prop: show
+ // show the labels or not.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: location
+ // compass location where to position the label around the point.
+ // 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.location = 'n';
+ // prop: labelsFromSeries
+ // true to use labels within data point arrays.
+ this.labelsFromSeries = false;
+ // prop: seriesLabelIndex
+ // array index for location of labels within data point arrays.
+ // if null, will use the last element of the data point array.
+ this.seriesLabelIndex = null;
+ // prop: labels
+ // array of arrays of labels, one array for each series.
+ this.labels = [];
+ // actual labels that will get displayed.
+ // needed to preserve user specified labels in labels array.
+ this._labels = [];
+ // prop: stackedValue
+ // true to display value as stacked in a stacked plot.
+ // no effect if labels is specified.
+ this.stackedValue = false;
+ // prop: ypadding
+ // vertical padding in pixels between point and label
+ this.ypadding = 6;
+ // prop: xpadding
+ // horizontal padding in pixels between point and label
+ this.xpadding = 6;
+ // prop: escapeHTML
+ // true to escape html entities in the labels.
+ // If you want to include markup in the labels, set to false.
+ this.escapeHTML = true;
+ // prop: edgeTolerance
+ // Number of pixels that the label must be away from an axis
+ // boundary in order to be drawn. Negative values will allow overlap
+ // with the grid boundaries.
+ this.edgeTolerance = -5;
+ // prop: formatter
+ // A class of a formatter for the tick text. sprintf by default.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: hideZeros
+ // true to not show a label for a value which is 0.
+ this.hideZeros = false;
+ this._elems = [];
+
+ $.extend(true, this, options);
+ };
+
+ var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
+ var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
+ var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
+
+ // called with scope of a series
+ $.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts, plot){
+ var options = $.extend(true, {}, seriesDefaults, opts);
+ options.pointLabels = options.pointLabels || {};
+ if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal' && !options.pointLabels.location) {
+ options.pointLabels.location = 'e';
+ }
+ // add a pointLabels attribute to the series plugins
+ this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels);
+ this.plugins.pointLabels.setLabels.call(this);
+ };
+
+ // called with scope of series
+ $.jqplot.PointLabels.prototype.setLabels = function() {
+ var p = this.plugins.pointLabels;
+ var labelIdx;
+ if (p.seriesLabelIndex != null) {
+ labelIdx = p.seriesLabelIndex;
+ }
+ else if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal') {
+ labelIdx = 0;
+ }
+ else {
+ labelIdx = (this._plotData.length === 0) ? 0 : this._plotData[0].length -1;
+ }
+ p._labels = [];
+ if (p.labels.length === 0 || p.labelsFromSeries) {
+ if (p.stackedValue) {
+ if (this._plotData.length && this._plotData[0].length){
+ // var idx = p.seriesLabelIndex || this._plotData[0].length -1;
+ for (var i=0; i<this._plotData.length; i++) {
+ p._labels.push(this._plotData[i][labelIdx]);
+ }
+ }
+ }
+ else {
+ // var d = this._plotData;
+ var d = this.data;
+ if (this.renderer.constructor === $.jqplot.BarRenderer && this.waterfall) {
+ d = this._data;
+ }
+ if (d.length && d[0].length) {
+ // var idx = p.seriesLabelIndex || d[0].length -1;
+ for (var i=0; i<d.length; i++) {
+ p._labels.push(d[i][labelIdx]);
+ }
+ }
+ d = null;
+ }
+ }
+ else if (p.labels.length){
+ p._labels = p.labels;
+ }
+ };
+
+ $.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) {
+ location = location || this.location;
+ padding = padding || this.xpadding;
+ var offset;
+
+ switch (location) {
+ case 'nw':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ case 'n':
+ offset = -elem.outerWidth(true)/2;
+ break;
+ case 'ne':
+ offset = this.xpadding;
+ break;
+ case 'e':
+ offset = this.xpadding;
+ break;
+ case 'se':
+ offset = this.xpadding;
+ break;
+ case 's':
+ offset = -elem.outerWidth(true)/2;
+ break;
+ case 'sw':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ case 'w':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ default: // same as 'nw'
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ }
+ return offset;
+ };
+
+ $.jqplot.PointLabels.prototype.yOffset = function(elem, location, padding) {
+ location = location || this.location;
+ padding = padding || this.xpadding;
+ var offset;
+
+ switch (location) {
+ case 'nw':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'n':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'ne':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'e':
+ offset = -elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ offset = this.ypadding;
+ break;
+ case 's':
+ offset = this.ypadding;
+ break;
+ case 'sw':
+ offset = this.ypadding;
+ break;
+ case 'w':
+ offset = -elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ }
+ return offset;
+ };
+
+ // called with scope of series
+ $.jqplot.PointLabels.draw = function (sctx, options, plot) {
+ var p = this.plugins.pointLabels;
+ // set labels again in case they have changed.
+ p.setLabels.call(this);
+ // remove any previous labels
+ for (var i=0; i<p._elems.length; i++) {
+ // Memory Leaks patch
+ // p._elems[i].remove();
+ p._elems[i].emptyForce();
+ }
+ p._elems.splice(0, p._elems.length);
+
+ if (p.show) {
+ var ax = '_'+this._stackAxis+'axis';
+
+ if (!p.formatString) {
+ p.formatString = this[ax]._ticks[0].formatString;
+ p.formatter = this[ax]._ticks[0].formatter;
+ }
+
+ var pd = this._plotData;
+ var ppd = this._prevPlotData;
+ var xax = this._xaxis;
+ var yax = this._yaxis;
+ var elem, helem;
+
+ for (var i=0, l=p._labels.length; i < l; i++) {
+ var label = p._labels[i];
+
+ if (p.hideZeros && parseInt(p._labels[i], 10) == 0) {
+ label = '';
+ }
+
+ if (label != null) {
+ label = p.formatter(p.formatString, label);
+ }
+
+ helem = document.createElement('div');
+ p._elems[i] = $(helem);
+
+ elem = p._elems[i];
+
+
+ elem.addClass('jqplot-point-label jqplot-series-'+this.index+' jqplot-point-'+i);
+ elem.css('position', 'absolute');
+ elem.insertAfter(sctx.canvas);
+
+ if (p.escapeHTML) {
+ elem.text(label);
+ }
+ else {
+ elem.html(label);
+ }
+ var location = p.location;
+ if ((this.fillToZero && pd[i][1] < 0) || (this.fillToZero && this._type === 'bar' && this.barDirection === 'horizontal' && pd[i][0] < 0) || (this.waterfall && parseInt(label, 10)) < 0) {
+ location = oppositeLocations[locationIndicies[location]];
+ }
+
+
+ var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location);
+ var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location);
+
+ // we have stacked chart but are not showing stacked values,
+ // place labels in center.
+ if (this._stack && !p.stackedValue) {
+ if (this.barDirection === "vertical") {
+ elt = (this._barPoints[i][0][1] + this._barPoints[i][1][1]) / 2 + plot._gridPadding.top - 0.5 * elem.outerHeight(true);
+ }
+ else {
+ ell = (this._barPoints[i][2][0] + this._barPoints[i][0][0]) / 2 + plot._gridPadding.left - 0.5 * elem.outerWidth(true);
+ }
+ }
+
+ if (this.renderer.constructor == $.jqplot.BarRenderer) {
+ if (this.barDirection == "vertical") {
+ ell += this._barNudge;
+ }
+ else {
+ elt -= this._barNudge;
+ }
+ }
+ elem.css('left', ell);
+ elem.css('top', elt);
+ var elr = ell + elem.width();
+ var elb = elt + elem.height();
+ var et = p.edgeTolerance;
+ var scl = $(sctx.canvas).position().left;
+ var sct = $(sctx.canvas).position().top;
+ var scr = sctx.canvas.width + scl;
+ var scb = sctx.canvas.height + sct;
+ // if label is outside of allowed area, remove it
+ if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) {
+ elem.remove();
+ }
+
+ elem = null;
+ helem = null;
+ }
+
+ // finally, animate them if the series is animated
+ // if (this.renderer.animation && this.renderer.animation._supported && this.renderer.animation.show && plot._drawCount < 2) {
+ // var sel = '.jqplot-point-label.jqplot-series-'+this.index;
+ // $(sel).hide();
+ // $(sel).fadeIn(1000);
+ // }
+
+ }
+ };
+
+ $.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init);
+ $.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw);
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js
new file mode 100644
index 00000000..4035488a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js
@@ -0,0 +1,728 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ $.jqplot.PyramidAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.PyramidAxisRenderer.prototype.constructor = $.jqplot.PyramidAxisRenderer;
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.init = function(options){
+ // Group: Properties
+ //
+ // prop: position
+ // Position of axis. Values are: top, bottom , left, center, right.
+ // By default, x and x2 axes are bottom, y axis is center.
+ this.position = null;
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ this.tickSpacingFactor = 25;
+ this._type = 'pyramid';
+ this._splitAxis = false;
+ this._splitLength = null;
+ this.category = false;
+ this._autoFormatString = '';
+ this._overrideFormatString = false;
+
+ $.extend(true, this, options);
+ this.renderer.options = options;
+
+ this.resetDataBounds = this.renderer.resetDataBounds;
+ this.resetDataBounds();
+
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype.resetDataBounds = function() {
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ var db = this._dataBounds;
+ db.min = null;
+ db.max = null;
+ var temp;
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s._plotData;
+
+ for (var j=0, l=d.length; j<l; j++) {
+ if (this.name.charAt(0) === 'x') {
+ temp = d[j][1];
+ if ((temp !== null && temp < db.min) || db.min === null) {
+ db.min = temp;
+ }
+ if ((temp !== null && temp > db.max) || db.max === null) {
+ db.max = temp;
+ }
+ }
+ else {
+ temp = d[j][0];
+ if ((temp !== null && temp < db.min) || db.min === null) {
+ db.min = temp;
+ }
+ if ((temp !== null && temp > db.max) || db.max === null) {
+ db.max = temp;
+ }
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this, plot);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // Memory Leaks patch
+ //this._elem.empty();
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.show && tick.showLabel && (!tick.isMinorTick)) {
+ this._elem.append(tick.draw(ctx, plot));
+ }
+ }
+ tick = null;
+ t = null;
+ }
+ return this._elem;
+ };
+
+ // Note, primes can be found on http://primes.utm.edu/
+ var _primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
+
+
+ var _primesHash = {};
+
+ for (var i =0, l = _primes.length; i < l; i++) {
+ _primesHash[_primes[i]] = _primes[i];
+ }
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var userTicks = this.ticks;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim;
+ var interval;
+ var min;
+ var max;
+ var range;
+ var pos1;
+ var pos2;
+ var tt;
+ var i;
+ var l;
+ var s;
+ // get a copy of user's settings for min/max.
+ var userMin = this.min;
+ var userMax = this.max;
+ var ut;
+ var t;
+ var threshold;
+ var tdim;
+ var scalefact;
+ var ret;
+ var tumin;
+ var tumax;
+ var maxVisibleTicks;
+ var val;
+ var skip = null;
+ var temp;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0, l=userTicks.length; i<l; i++){
+ ut = userTicks[i];
+ t = new this.tickRenderer(this.tickOptions);
+ if ($.isArray(ut)) {
+ t.value = ut[0];
+ t.label = ut[1];
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ if (typeof ut === 'string') {
+ val = i + plot.defaultAxisStart;
+ }
+ else {
+ val = ut;
+ }
+ t.value = val;
+ t.label = ut;
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+
+ // use user specified tickInterval if there is one
+ if (this._options.tickInterval) {
+ // hide every tick except for ticks on interval
+ var ti = this._options.tickInterval;
+ for (i=0; i<this.numberTicks; i++) {
+ if (i%ti !== 0) {
+ // this._ticks[i].show = false;
+ this._ticks[i].isMinorTick = true;
+ }
+ }
+ }
+
+ else {
+ // check if we have too many ticks
+ dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor);
+
+ if (this.numberTicks > maxVisibleTicks) {
+ // check for number of ticks we can skip
+ temp = this.numberTicks - 1;
+ for (i=2; i<temp; i++) {
+ if (temp % i === 0 && temp/i < maxVisibleTicks) {
+ skip = i-1;
+ break;
+ }
+ }
+
+ if (skip !== null) {
+ var count = 1;
+ for (i=1, l=this._ticks.length; i<l; i++) {
+ if (count <= skip) {
+ this._ticks[i].show = false;
+ count += 1;
+ }
+ else {
+ count = 1;
+ }
+ }
+ }
+ }
+ }
+
+ // if category style, add minor ticks in between
+ temp = [];
+ if (this.category) {
+ // turn off gridline and mark on first tick
+ this._ticks[0].showGridline = false;
+ this._ticks[0].showMark = false;
+
+ for (i=this._ticks.length-1; i>0; i--) {
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[i-1].value + this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks[i].showGridline = false;
+ this._ticks[i].showMark = false;
+ this._ticks.splice(i, 0, t);
+ // temp.push(t);
+ }
+
+ // merge in the new ticks
+ // for (i=1, l=temp.length; i<l; i++) {
+ // this._ticks.splice(i, 0, temp[i]);
+ // }
+
+ // now add a tick at beginning and end
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[0].value - this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks.unshift(t);
+
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[this._ticks.length-1].value + this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks.push(t);
+
+ this.tickInterval = this.tickInterval / 2.0;
+ this.numberTicks = this._ticks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this._ticks.length-1].value;
+ }
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (this.name.charAt(0) === 'x') {
+ dim = this._plotDimensions.width;
+ // make sure x axis is symetric about 0.
+ var tempmax = Math.max(db.max, Math.abs(db.min));
+ var tempmin = Math.min(db.min, -tempmax);
+ // min = ((this.min != null) ? this.min : tempmin);
+ // max = ((this.max != null) ? this.max : tempmax);
+ min = tempmin;
+ max = tempmax;
+ range = max - min;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ threshold = 30;
+ tdim = Math.max(dim, threshold+1);
+ scalefact = (tdim-threshold)/300.0;
+ ret = $.jqplot.LinearTickGenerator(min, max, scalefact);
+ // calculate a padded max and min, points should be less than these
+ // so that they aren't too close to the edges of the plot.
+ // User can adjust how much padding is allowed with pad, padMin and PadMax options.
+ tumin = min + range*(this.padMin - 1);
+ tumax = max - range*(this.padMax - 1);
+
+ if (min < tumin || max > tumax) {
+ tumin = min - range*(this.padMin - 1);
+ tumax = max + range*(this.padMax - 1);
+ ret = $.jqplot.LinearTickGenerator(tumin, tumax, scalefact);
+ }
+
+ this.min = ret[0];
+ this.max = ret[1];
+ this.numberTicks = ret[2];
+ this._autoFormatString = ret[3];
+ this.tickInterval = ret[4];
+ }
+ else {
+ dim = this._plotDimensions.height;
+
+ // ticks will be on whole integers like 1, 2, 3, ... or 1, 4, 7, ...
+ min = db.min;
+ max = db.max;
+ s = this._series[0];
+ this._ticks = [];
+
+ range = max - min;
+
+ // if range is a prime, will get only 2 ticks, expand range in that case.
+ if (_primesHash[range]) {
+ range += 1;
+ max += 1;
+ }
+
+ this.max = max;
+ this.min = min;
+
+ maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor);
+
+ if (range + 1 <= maxVisibleTicks) {
+ this.numberTicks = range + 1;
+ this.tickInterval = 1.0;
+ }
+
+ else {
+ // figure out a round number of ticks to skip in every interval
+ // range / ti + 1 = nt
+ // ti = range / (nt - 1)
+ for (var i=maxVisibleTicks; i>1; i--) {
+ if (range/(i - 1) === Math.round(range/(i - 1))) {
+ this.numberTicks = i;
+ this.tickInterval = range/(i - 1);
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ this.tickOptions = this.tickOptions || {};
+ this.tickOptions.formatString = this._autoFormatString;
+ }
+
+ var labelval;
+ for (i=0; i<this.numberTicks; i++) {
+ this.tickOptions.axis = this.name;
+ labelval = this.min + this.tickInterval * i;
+ if (this.name.charAt(0) === 'x') {
+ labelval = Math.abs(labelval);
+ }
+ // this.tickOptions.label = String (labelval);
+ this.tickOptions.value = this.min + this.tickInterval * i;
+ t = new this.tickRenderer(this.tickOptions);
+
+ t.label = t.prefix + t.formatter(t.formatString, labelval);
+
+ this._ticks.push(t);
+ // for x axis, if y axis is in middle, add a symetrical 0 tick
+ if (this.name.charAt(0) === 'x' && plot.axes.yMidAxis.show && this.tickOptions.value === 0) {
+ this._splitAxis = true;
+ this._splitLength = plot.axes.yMidAxis.getWidth();
+ // t.value = -this.max/2000.0;
+ t = new this.tickRenderer(this.tickOptions);
+ this._ticks.push(t);
+ t.value = this.max/2000.0;
+ }
+ }
+ t = null;
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var i;
+ var t;
+ var tick;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ t = this._ticks;
+ l = t.length;
+ for (i=0; i<l; i++) {
+ tick = t[i];
+ if (!tick._breakTick && tick.show && tick.showLabel && !tick.isMinorTick) {
+ if (this.name.charAt(0) === 'x') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ if (this.name === 'yMidAxis') {
+ for (i=0; i<l; i++) {
+ tick = t[i];
+ if (tick._elem) {
+ temp = (dim - tick._elem.outerWidth(true))/2.0;
+ tick._elem.css('left', temp);
+ }
+ }
+ }
+ tick = null;
+ t = null;
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name === 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name === 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name === 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else if (this.name === 'yMidAxis') {
+ // don't include width of label at all in width of axis?
+ // dim = (dim > w) ? dim : w;
+ var temp = dim/2.0 - w/2.0;
+ this._elem.css({'width':dim+'px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css({width: w, left: temp, top: 0});
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype.pack = function(pos, offsets) {
+ // Add defaults for repacking from resetTickValues function.
+ pos = pos || {};
+ offsets = offsets || this._offsets;
+
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+ var sl = this._splitLength;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ if (this._splitAxis) {
+ pixellength -= this._splitLength;
+
+ // don't know that this one is correct.
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ if (u <= 0) {
+ return (u - min) * pixellength / unitlength + offmin;
+ }
+ else {
+ return (u - min) * pixellength / unitlength + offmin + sl;
+ }
+ };
+
+ this.series_u2p = function(u){
+ if (u <= 0) {
+ return (u - min) * pixellength / unitlength;
+ }
+ else {
+ return (u - min) * pixellength / unitlength + sl;
+ }
+ };
+
+ // don't know that this one is correct.
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+ else {
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name.charAt(0) === 'x'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ if (this.show) {
+ if (this.name.charAt(0) === 'x') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel && !t.isMinorTick) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ if (this.name !== 'yMidAxis') {
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ }
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else if (this.name !== 'yMidAxis') {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+
+ ticks = null;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js
new file mode 100644
index 00000000..6124cbad
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js
@@ -0,0 +1,429 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // Class: $.jqplot.CanvasGridRenderer
+ // The default jqPlot grid renderer, creating a grid on a canvas element.
+ // The renderer has no additional options beyond the <Grid> class.
+ $.jqplot.PyramidGridRenderer = function(){
+ $.jqplot.CanvasGridRenderer.call(this);
+ };
+
+ $.jqplot.PyramidGridRenderer.prototype = new $.jqplot.CanvasGridRenderer();
+ $.jqplot.PyramidGridRenderer.prototype.constructor = $.jqplot.PyramidGridRenderer;
+
+ // called with context of Grid object
+ $.jqplot.CanvasGridRenderer.prototype.init = function(options) {
+ this._ctx;
+ this.plotBands = {
+ show: false,
+ color: 'rgb(230, 219, 179)',
+ axis: 'y',
+ start: null,
+ interval: 10
+ };
+ $.extend(true, this, options);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor};
+ this.renderer.shadowRenderer.init(sopts);
+ };
+
+ $.jqplot.PyramidGridRenderer.prototype.draw = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ var ctx = this._ctx;
+ var axes = this._axes;
+ var xp = axes.xaxis.u2p;
+ var yp = axes.yMidAxis.u2p;
+ var xnudge = axes.xaxis.max/1000.0;
+ var xp0 = xp(0);
+ var xpn = xp(xnudge);
+ var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis','yMidAxis'];
+ // Add the grid onto the grid canvas. This is the bottom most layer.
+ ctx.save();
+ ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height);
+ ctx.fillStyle = this.backgroundColor || this.background;
+
+ ctx.fillRect(this._left, this._top, this._width, this._height);
+
+ if (this.plotBands.show) {
+ ctx.save();
+ var pb = this.plotBands;
+ ctx.fillStyle = pb.color;
+ var axis;
+ var x, y, w, h;
+ // find axis to work with
+ if (pb.axis.charAt(0) === 'x') {
+ if (axes.xaxis.show) {
+ axis = axes.xaxis;
+ }
+ }
+ else if (pb.axis.charAt(0) === 'y') {
+ if (axes.yaxis.show) {
+ axis = axes.yaxis;
+ }
+ else if (axes.y2axis.show) {
+ axis = axes.y2axis;
+ }
+ else if (axes.yMidAxis.show) {
+ axis = axes.yMidAxis;
+ }
+ }
+
+ if (axis !== undefined) {
+ // draw some rectangles
+ var start = pb.start;
+ if (start === null) {
+ start = axis.min;
+ }
+ for (var i = start; i < axis.max; i += 2 * pb.interval) {
+ if (axis.name.charAt(0) === 'y') {
+ x = this._left;
+ if ((i + pb.interval) < axis.max) {
+ y = axis.series_u2p(i + pb.interval) + this._top;
+ }
+ else {
+ y = axis.series_u2p(axis.max) + this._top;
+ }
+ w = this._right - this._left;
+ h = axis.series_u2p(start) - axis.series_u2p(start + pb.interval);
+ ctx.fillRect(x, y, w, h);
+ }
+ // else {
+ // y = 0;
+ // x = axis.series_u2p(i);
+ // h = this._height;
+ // w = axis.series_u2p(start + pb.interval) - axis.series_u2p(start);
+ // }
+
+ }
+ }
+ ctx.restore();
+ }
+
+ ctx.save();
+ ctx.lineJoin = 'miter';
+ ctx.lineCap = 'butt';
+ ctx.lineWidth = this.gridLineWidth;
+ ctx.strokeStyle = this.gridLineColor;
+ var b, e, s, m;
+ for (var i=5; i>0; i--) {
+ var name = ax[i-1];
+ var axis = axes[name];
+ var ticks = axis._ticks;
+ var numticks = ticks.length;
+ if (axis.show) {
+ if (axis.drawBaseline) {
+ var bopts = {};
+ if (axis.baselineWidth !== null) {
+ bopts.lineWidth = axis.baselineWidth;
+ }
+ if (axis.baselineColor !== null) {
+ bopts.strokeStyle = axis.baselineColor;
+ }
+ switch (name) {
+ case 'xaxis':
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._bottom, xp0, this._bottom, bopts);
+ drawLine (xpn, this._bottom, this._right, this._bottom, bopts);
+ }
+ else {
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ }
+ break;
+ case 'yaxis':
+ drawLine (this._left, this._bottom, this._left, this._top, bopts);
+ break;
+ case 'yMidAxis':
+ drawLine(xp0, this._bottom, xp0, this._top, bopts);
+ drawLine(xpn, this._bottom, xpn, this._top, bopts);
+ break;
+ case 'x2axis':
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._top, xp0, this._top, bopts);
+ drawLine (xpn, this._top, this._right, this._top, bopts);
+ }
+ else {
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ }
+ break;
+ case 'y2axis':
+ drawLine (this._right, this._bottom, this._right, this._top, bopts);
+ break;
+
+ }
+ }
+ for (var j=numticks; j>0; j--) {
+ var t = ticks[j-1];
+ if (t.show) {
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (name) {
+ case 'xaxis':
+ // draw the grid line if we should
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(pos, this._top, pos, this._bottom);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ case 'inside':
+ b = this._bottom-s;
+ e = this._bottom;
+ break;
+ case 'cross':
+ b = this._bottom-s;
+ e = this._bottom+s;
+ break;
+ default:
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'yaxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._right, pos, this._left, pos);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._left-s;
+ e = this._left;
+ break;
+ case 'inside':
+ b = this._left;
+ e = this._left+s;
+ break;
+ case 'cross':
+ b = this._left-s;
+ e = this._left+s;
+ break;
+ default:
+ b = this._left-s;
+ e = this._left;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'yMidAxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._left, pos, xp0, pos);
+ drawLine(xpn, pos, this._right, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+
+ b = xp0;
+ e = xp0 + s;
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+
+ b = xpn - s;
+ e = xpn;
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'x2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(pos, this._bottom, pos, this._top);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._top-s;
+ e = this._top;
+ break;
+ case 'inside':
+ b = this._top;
+ e = this._top+s;
+ break;
+ case 'cross':
+ b = this._top-s;
+ e = this._top+s;
+ break;
+ default:
+ b = this._top-s;
+ e = this._top;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'y2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._left, pos, this._right, pos);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._right;
+ e = this._right+s;
+ break;
+ case 'inside':
+ b = this._right-s;
+ e = this._right;
+ break;
+ case 'cross':
+ b = this._right-s;
+ e = this._right+s;
+ break;
+ default:
+ b = this._right;
+ e = this._right+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ t = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+
+ ctx.restore();
+
+ function drawLine(bx, by, ex, ey, opts) {
+ ctx.save();
+ opts = opts || {};
+ if (opts.lineWidth == null || opts.lineWidth != 0){
+ $.extend(true, ctx, opts);
+ ctx.beginPath();
+ ctx.moveTo(bx, by);
+ ctx.lineTo(ex, ey);
+ ctx.stroke();
+ }
+ ctx.restore();
+ }
+
+ if (this.shadow) {
+ if (axes.yMidAxis.show) {
+ var points = [[this._left, this._bottom], [xp0, this._bottom]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ var points = [[xpn, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ var points = [[xp0, this._bottom], [xp0, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ else {
+ var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ }
+ // Now draw border around grid. Use axis border definitions. start at
+ // upper left and go clockwise.
+ if (this.borderWidth != 0 && this.drawBorder) {
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._top, xp0, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (xpn, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, xpn, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (xp0, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ drawLine (xp0, this._bottom, xp0, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ drawLine (xpn, this._bottom, xpn, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ else {
+ drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ }
+ // ctx.lineWidth = this.borderWidth;
+ // ctx.strokeStyle = this.borderColor;
+ // ctx.strokeRect(this._left, this._top, this._width, this._height);
+
+ ctx.restore();
+ ctx = null;
+ axes = null;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js
new file mode 100644
index 00000000..b5516a90
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js
@@ -0,0 +1,514 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ // Need to ensure pyramid axis and grid renderers are loaded.
+ // You should load these with script tags in the html head, that is more efficient
+ // as the browser will cache the request.
+ // Note, have to block with synchronous request in order to execute bar renderer code.
+ if ($.jqplot.PyramidAxisRenderer === undefined) {
+ $.ajax({
+ url: $.jqplot.pluginLocation + 'jqplot.pyramidAxisRenderer.js',
+ dataType: "script",
+ async: false
+ });
+ }
+
+ if ($.jqplot.PyramidGridRenderer === undefined) {
+ $.ajax({
+ url: $.jqplot.pluginLocation + 'jqplot.pyramidGridRenderer.js',
+ dataType: "script",
+ async: false
+ });
+ }
+
+ $.jqplot.PyramidRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.PyramidRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.PyramidRenderer.prototype.constructor = $.jqplot.PyramidRenderer;
+
+ // called with scope of a series
+ $.jqplot.PyramidRenderer.prototype.init = function(options, plot) {
+ options = options || {};
+ this._type = 'pyramid';
+ // Group: Properties
+ //
+ // prop: barPadding
+ this.barPadding = 10;
+ this.barWidth = null;
+ // prop: fill
+ // True to fill the bars.
+ this.fill = true;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop highlightThreshold
+ // Expand the highlightable region in the x direction.
+ // E.g. a value of 3 will highlight a bar when the mouse is
+ // within 3 pixels of the bar in the x direction.
+ this.highlightThreshold = 2;
+ // prop: synchronizeHighlight
+ // Index of another series to highlight when this series is highlighted.
+ // null or false to not synchronize.
+ this.synchronizeHighlight = false;
+ // prop: offsetBars
+ // False will center bars on their y value.
+ // True will push bars up by 1/2 bar width to fill between their y values.
+ // If true, there needs to be 1 more tick than there are bars.
+ this.offsetBars = false;
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ this.side = 'right';
+
+ $.extend(true, this, options);
+
+ // if (this.fill === false) {
+ // this.shadow = false;
+ // }
+
+ if (this.side === 'left') {
+ this._highlightThreshold = [[-this.highlightThreshold, 0], [-this.highlightThreshold, 0], [0,0], [0,0]];
+ }
+
+ else {
+ this._highlightThreshold = [[0,0], [0,0], [this.highlightThreshold, 0], [this.highlightThreshold, 0]];
+ }
+
+ this.renderer.options = options;
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // Array of actual data colors used for each data point.
+ this._dataColors = [];
+ this._barPoints = [];
+ this.fillAxis = 'y';
+ this._primaryAxis = '_yaxis';
+ this._xnudge = 0;
+
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill, lineWidth: this.lineWidth};
+ this.renderer.shapeRenderer.init(opts);
+ // set the shadow renderer options
+ var shadow_offset = options.shadowOffset;
+ // set the shadow renderer options
+ if (shadow_offset == null) {
+ // scale the shadowOffset to the width of the line.
+ if (this.lineWidth > 2.5) {
+ shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
+ // var shadow_offset = this.shadowOffset;
+ }
+ // for skinny lines, don't make such a big shadow.
+ else {
+ shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163;
+ }
+ }
+ var sopts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill, lineWidth: this.lineWidth};
+ this.renderer.shadowRenderer.init(sopts);
+
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+
+ // if this is the left side of pyramid, set y values to negative.
+ if (this.side === 'left') {
+ for (var i=0, l=this.data.length; i<l; i++) {
+ this.data[i][1] = -Math.abs(this.data[i][1]);
+ }
+ }
+ };
+
+ // setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.PyramidRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ var pdata = this._prevPlotData;
+ this.gridData = [];
+ this._prevGridData = [];
+ var l = data.length;
+ var adjust = false;
+ var i;
+
+ // if any data values are < 0, consider this a negative series
+ for (i = 0; i < l; i++) {
+ if (data[i][1] < 0) {
+ this.side = 'left';
+ }
+ }
+
+ if (this._yaxis.name === 'yMidAxis' && this.side === 'right') {
+ this._xnudge = this._xaxis.max/2000.0;
+ adjust = true;
+ }
+
+ for (i = 0; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ this.gridData.push([xp(data[i][1]), yp(data[i][0])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ this.gridData.push([xp(data[i][1]), null]);
+ }
+ else if (data[i][1] == null) {
+ this.gridData.push(null, [yp(data[i][0])]);
+ }
+ // finally, adjust x grid data if have to
+ if (data[i][1] === 0 && adjust) {
+ this.gridData[i][0] = xp(this._xnudge);
+ }
+ }
+ };
+
+ // makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.PyramidRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var l = data.length;
+ var adjust = false;
+ var i;
+
+ // if any data values are < 0, consider this a negative series
+ for (i = 0; i < l; i++) {
+ if (data[i][1] < 0) {
+ this.side = 'left';
+ }
+ }
+
+ if (this._yaxis.name === 'yMidAxis' && this.side === 'right') {
+ this._xnudge = this._xaxis.max/2000.0;
+ adjust = true;
+ }
+
+ for (i = 0; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ gd.push([xp(data[i][1]), yp(data[i][0])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ gd.push([xp(data[i][1]), null]);
+ }
+ else if (data[i][1] == null) {
+ gd.push([null, yp(data[i][0])]);
+ }
+ // finally, adjust x grid data if have to
+ if (data[i][1] === 0 && adjust) {
+ gd[i][0] = xp(this._xnudge);
+ }
+ }
+
+ return gd;
+ };
+
+ $.jqplot.PyramidRenderer.prototype.setBarWidth = function() {
+ // need to know how many data values we have on the approprate axis and figure it out.
+ var i;
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ nvals = paxis.max - paxis.min;
+ var nticks = paxis.numberTicks;
+ var nbins = (nticks-1)/2;
+ // so, now we have total number of axis values.
+ var temp = (this.barPadding === 0) ? 1.0 : 0;
+ if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
+ this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding + temp;
+ }
+ else {
+ if (this.fill) {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding + temp;
+ }
+ else {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals;
+ }
+ }
+ };
+
+ $.jqplot.PyramidRenderer.prototype.draw = function(ctx, gridData, options) {
+ var i;
+ // Ughhh, have to make a copy of options b/c it may be modified later.
+ var opts = $.extend({}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, pointy;
+ // clear out data colors.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ if (this.renderer.options.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ // var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ // var nvals = temp[0];
+ // var nseries = temp[1];
+ // var pos = temp[2];
+ var points = [],
+ w,
+ h;
+
+ // this._barNudge = 0;
+
+ if (showLine) {
+ var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
+ var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
+ var negativeColor = negativeColors.get(this.index);
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var positiveColor = opts.fillStyle;
+ var base;
+ var xstart = this._xaxis.series_u2p(this._xnudge);
+ var ystart = this._yaxis.series_u2p(this._yaxis.min);
+ var yend = this._yaxis.series_u2p(this._yaxis.max);
+ var bw = this.barWidth;
+ var bw2 = bw/2.0;
+ var points = [];
+ var yadj = this.offsetBars ? bw2 : 0;
+
+ for (var i=0, l=gridData.length; i<l; i++) {
+ if (this.data[i][0] == null) {
+ continue;
+ }
+ base = gridData[i][1];
+ // not stacked and first series in stack
+
+ if (this._plotData[i][1] < 0) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+ if (this.fill) {
+
+ if (this._plotData[i][1] >= 0) {
+ // xstart = this._xaxis.series_u2p(this._xnudge);
+ w = gridData[i][0] - xstart;
+ h = this.barWidth;
+ points = [xstart, base - bw2 - yadj, w, h];
+ }
+ else {
+ // xstart = this._xaxis.series_u2p(0);
+ w = xstart - gridData[i][0];
+ h = this.barWidth;
+ points = [gridData[i][0], base - bw2 - yadj, w, h];
+ }
+
+ this._barPoints.push([[points[0], points[1] + h], [points[0], points[1]], [points[0] + w, points[1]], [points[0] + w, points[1] + h]]);
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+
+ else {
+ if (i === 0) {
+ points =[[xstart, ystart], [gridData[i][0], ystart], [gridData[i][0], gridData[i][1] - bw2 - yadj]];
+ }
+
+ else if (i < l-1) {
+ points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], gridData[i][1] - bw2 - yadj]]);
+ }
+
+ // finally, draw the line
+ else {
+ points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], yend], [xstart, yend]]);
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+ }
+
+ if (this.highlightColors.length == 0) {
+ this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
+ }
+
+ else if (typeof(this.highlightColors) == 'string') {
+ this.highlightColors = [];
+ for (var i=0; i<this._dataColors.length; i++) {
+ this.highlightColors.push(this.highlightColors);
+ }
+ }
+
+ };
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.grid = options.grid || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer === $.jqplot.PyramidRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer === $.jqplot.PyramidRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.PyramidAxisRenderer;
+ options.grid.renderer = $.jqplot.PyramidGridRenderer;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.pyramidRenderer && this.plugins.pyramidRenderer.highlightCanvas) {
+
+ this.plugins.pyramidRenderer.highlightCanvas.resetCanvas();
+ this.plugins.pyramidRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.pyramidRenderer = {highlightedSeriesIndex:null};
+ this.plugins.pyramidRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.pyramidRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pyramidRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.pyramidRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.pyramidRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.pyramidRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColors[pidx], fillRect: false};
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ if (s.synchronizeHighlight !== false && plot.series.length >= s.synchronizeHighlight && s.synchronizeHighlight !== sidx) {
+ s = plot.series[s.synchronizeHighlight];
+ opts = {fillStyle: s.highlightColors[pidx], fillRect: false};
+ s.renderer.shapeRenderer.draw(canvas._ctx, s._barPoints[pidx], opts);
+ }
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.pyramidRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.pyramidRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pyramidRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ // Have to add hook here, because it needs called before series is inited.
+ $.jqplot.preInitHooks.push(preInit);
+
+
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js
new file mode 100644
index 00000000..168fb7a6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js
@@ -0,0 +1,223 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Trendline
+ * Plugin which will automatically compute and draw trendlines for plotted data.
+ */
+ $.jqplot.Trendline = function() {
+ // Group: Properties
+
+ // prop: show
+ // Wether or not to show the trend line.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: color
+ // CSS color spec for the trend line.
+ // By default this wil be the same color as the primary line.
+ this.color = '#666666';
+ // prop: renderer
+ // Renderer to use to draw the trend line.
+ // The data series that is plotted may not be rendered as a line.
+ // Therefore, we use our own line renderer here to draw a trend line.
+ this.renderer = new $.jqplot.LineRenderer();
+ // prop: rendererOptions
+ // Options to pass to the line renderer.
+ // By default, markers are not shown on trend lines.
+ this.rendererOptions = {marker:{show:false}};
+ // prop: label
+ // Label for the trend line to use in the legend.
+ this.label = '';
+ // prop: type
+ // Either 'exponential', 'exp', or 'linear'.
+ this.type = 'linear';
+ // prop: shadow
+ // true or false, wether or not to show the shadow.
+ this.shadow = true;
+ // prop: markerRenderer
+ // Renderer to use to draw markers on the line.
+ // I think this is wrong.
+ this.markerRenderer = {show:false};
+ // prop: lineWidth
+ // Width of the trend line.
+ this.lineWidth = 1.5;
+ // prop: shadowAngle
+ // Angle of the shadow on the trend line.
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // pixel offset for each stroke of the shadow.
+ this.shadowOffset = 1.0;
+ // prop: shadowAlpha
+ // Alpha transparency of the shadow.
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to make of the shadow.
+ this.shadowDepth = 3;
+ this.isTrendline = true;
+
+ };
+
+ $.jqplot.postSeriesInitHooks.push(parseTrendLineOptions);
+ $.jqplot.postDrawSeriesHooks.push(drawTrendline);
+ $.jqplot.addLegendRowHooks.push(addTrendlineLegend);
+
+ // called witin scope of the legend object
+ // current series passed in
+ // must return null or an object {label:label, color:color}
+ function addTrendlineLegend(series) {
+ var ret = null;
+ if (series.trendline && series.trendline.show) {
+ var lt = series.trendline.label.toString();
+ if (lt) {
+ ret = {label:lt, color:series.trendline.color};
+ }
+ }
+ return ret;
+ }
+
+ // called within scope of a series
+ function parseTrendLineOptions (target, data, seriesDefaults, options, plot) {
+ if (this._type && (this._type === 'line' || this._type == 'bar')) {
+ this.trendline = new $.jqplot.Trendline();
+ options = options || {};
+ $.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline);
+ this.trendline.renderer.init.call(this.trendline, null);
+ }
+ }
+
+ // called within scope of series object
+ function drawTrendline(sctx, options) {
+ // if we have options, merge trendline options in with precedence
+ options = $.extend(true, {}, this.trendline, options);
+
+ if (this.trendline && options.show) {
+ var fit;
+ // this.renderer.setGridData.call(this);
+ var data = options.data || this.data;
+ fit = fitData(data, this.trendline.type);
+ var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data);
+ this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow});
+ }
+ }
+
+ function regression(x, y, typ) {
+ var type = (typ == null) ? 'linear' : typ;
+ var N = x.length;
+ var slope;
+ var intercept;
+ var SX = 0;
+ var SY = 0;
+ var SXX = 0;
+ var SXY = 0;
+ var SYY = 0;
+ var Y = [];
+ var X = [];
+
+ if (type == 'linear') {
+ X = x;
+ Y = y;
+ }
+ else if (type == 'exp' || type == 'exponential') {
+ for ( var i=0; i<y.length; i++) {
+ // ignore points <= 0, log undefined.
+ if (y[i] <= 0) {
+ N--;
+ }
+ else {
+ X.push(x[i]);
+ Y.push(Math.log(y[i]));
+ }
+ }
+ }
+
+ for ( var i = 0; i < N; i++) {
+ SX = SX + X[i];
+ SY = SY + Y[i];
+ SXY = SXY + X[i]* Y[i];
+ SXX = SXX + X[i]* X[i];
+ SYY = SYY + Y[i]* Y[i];
+ }
+
+ slope = (N*SXY - SX*SY)/(N*SXX - SX*SX);
+ intercept = (SY - slope*SX)/N;
+
+ return [slope, intercept];
+ }
+
+ function linearRegression(X,Y) {
+ var ret;
+ ret = regression(X,Y,'linear');
+ return [ret[0],ret[1]];
+ }
+
+ function expRegression(X,Y) {
+ var ret;
+ var x = X;
+ var y = Y;
+ ret = regression(x, y,'exp');
+ var base = Math.exp(ret[0]);
+ var coeff = Math.exp(ret[1]);
+ return [base, coeff];
+ }
+
+ function fitData(data, typ) {
+ var type = (typ == null) ? 'linear' : typ;
+ var ret;
+ var res;
+ var x = [];
+ var y = [];
+ var ypred = [];
+
+ for (i=0; i<data.length; i++){
+ if (data[i] != null && data[i][0] != null && data[i][1] != null) {
+ x.push(data[i][0]);
+ y.push(data[i][1]);
+ }
+ }
+
+ if (type == 'linear') {
+ ret = linearRegression(x,y);
+ for ( var i=0; i<x.length; i++){
+ res = ret[0]*x[i] + ret[1];
+ ypred.push([x[i], res]);
+ }
+ }
+ else if (type == 'exp' || type == 'exponential') {
+ ret = expRegression(x,y);
+ for ( var i=0; i<x.length; i++){
+ res = ret[1]*Math.pow(ret[0],x[i]);
+ ypred.push([x[i], res]);
+ }
+ }
+ return {data: ypred, slope: ret[0], intercept: ret[1]};
+ }
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css
new file mode 100644
index 00000000..d30bafb1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css
@@ -0,0 +1,259 @@
+/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/
+.jqplot-target {
+ position: relative;
+ color: #666666;
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
+ font-size: 1em;
+/* height: 300px;
+ width: 400px;*/
+}
+
+/*rules applied to all axes*/
+.jqplot-axis {
+ font-size: 0.75em;
+}
+
+.jqplot-xaxis {
+ margin-top: 10px;
+}
+
+.jqplot-x2axis {
+ margin-bottom: 10px;
+}
+
+.jqplot-yaxis {
+ margin-right: 10px;
+}
+
+.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+/*rules applied to all axis tick divs*/
+.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick {
+ position: absolute;
+ white-space: pre;
+}
+
+
+.jqplot-xaxis-tick {
+ top: 0px;
+ /* initial position untill tick is drawn in proper place */
+ left: 15px;
+/* padding-top: 10px;*/
+ vertical-align: top;
+}
+
+.jqplot-x2axis-tick {
+ bottom: 0px;
+ /* initial position untill tick is drawn in proper place */
+ left: 15px;
+/* padding-bottom: 10px;*/
+ vertical-align: bottom;
+}
+
+.jqplot-yaxis-tick {
+ right: 0px;
+ /* initial position untill tick is drawn in proper place */
+ top: 15px;
+/* padding-right: 10px;*/
+ text-align: right;
+}
+
+.jqplot-yaxis-tick.jqplot-breakTick {
+ right: -20px;
+ margin-right: 0px;
+ padding:1px 5px 1px 5px;
+/* background-color: white;*/
+ z-index: 2;
+ font-size: 1.5em;
+}
+
+.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick {
+ left: 0px;
+ /* initial position untill tick is drawn in proper place */
+ top: 15px;
+/* padding-left: 10px;*/
+/* padding-right: 15px;*/
+ text-align: left;
+}
+
+.jqplot-yMidAxis-tick {
+ text-align: center;
+ white-space: nowrap;
+}
+
+.jqplot-xaxis-label {
+ margin-top: 10px;
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-x2axis-label {
+ margin-bottom: 10px;
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-yaxis-label {
+ margin-right: 10px;
+/* text-align: center;*/
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-yMidAxis-label {
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
+/* text-align: center;*/
+ font-size: 11pt;
+ margin-left: 10px;
+ position: absolute;
+}
+
+.jqplot-meterGauge-tick {
+ font-size: 0.75em;
+ color: #999999;
+}
+
+.jqplot-meterGauge-label {
+ font-size: 1em;
+ color: #999999;
+}
+
+table.jqplot-table-legend {
+ margin-top: 12px;
+ margin-bottom: 12px;
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+table.jqplot-table-legend, table.jqplot-cursor-legend {
+ background-color: rgba(255,255,255,0.6);
+ border: 1px solid #cccccc;
+ position: absolute;
+ font-size: 0.75em;
+}
+
+td.jqplot-table-legend {
+ vertical-align:middle;
+}
+
+/*
+These rules could be used instead of assigning
+element styles and relying on js object properties.
+*/
+
+/*
+td.jqplot-table-legend-swatch {
+ padding-top: 0.5em;
+ text-align: center;
+}
+
+tr.jqplot-table-legend:first td.jqplot-table-legend-swatch {
+ padding-top: 0px;
+}
+*/
+
+td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active {
+ cursor: pointer;
+}
+
+.jqplot-table-legend .jqplot-series-hidden {
+ text-decoration: line-through;
+}
+
+div.jqplot-table-legend-swatch-outline {
+ border: 1px solid #cccccc;
+ padding:1px;
+}
+
+div.jqplot-table-legend-swatch {
+ width:0px;
+ height:0px;
+ border-top-width: 5px;
+ border-bottom-width: 5px;
+ border-left-width: 6px;
+ border-right-width: 6px;
+ border-top-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-right-style: solid;
+}
+
+.jqplot-title {
+ top: 0px;
+ left: 0px;
+ padding-bottom: 0.5em;
+ font-size: 1.2em;
+}
+
+table.jqplot-cursor-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+}
+
+
+.jqplot-cursor-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(208,208,208,0.5);
+ padding: 1px;
+}
+
+.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(208,208,208,0.5);
+ padding: 1px;
+}
+
+.jqplot-point-label {
+ font-size: 0.75em;
+ z-index: 2;
+}
+
+td.jqplot-cursor-legend-swatch {
+ vertical-align: middle;
+ text-align: center;
+}
+
+div.jqplot-cursor-legend-swatch {
+ width: 1.2em;
+ height: 0.7em;
+}
+
+.jqplot-error {
+/* Styles added to the plot target container when there is an error go here.*/
+ text-align: center;
+}
+
+.jqplot-error-message {
+/* Styling of the custom error message div goes here.*/
+ position: relative;
+ top: 46%;
+ display: inline-block;
+}
+
+div.jqplot-bubble-label {
+ font-size: 0.8em;
+/* background: rgba(90%, 90%, 90%, 0.15);*/
+ padding-left: 2px;
+ padding-right: 2px;
+ color: rgb(20%, 20%, 20%);
+}
+
+div.jqplot-bubble-label.jqplot-bubble-label-highlight {
+ background: rgba(90%, 90%, 90%, 0.7);
+}
+
+div.jqplot-noData-container {
+ text-align: center;
+ background-color: rgba(96%, 96%, 96%, 0.3);
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js
new file mode 100644
index 00000000..f8d6eccf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js
@@ -0,0 +1,11381 @@
+/**
+ * Title: jqPlot Charts
+ *
+ * Pure JavaScript plotting plugin for jQuery.
+ *
+ * About: Version
+ *
+ * version: 1.0.4
+ * revision: 1121
+ *
+ * About: Copyright & License
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * See <GPL Version 2> and <MIT License> contained within this distribution for further information.
+ *
+ * The author would appreciate an email letting him know of any substantial
+ * use of jqPlot. You can reach the author at: chris at jqplot dot com
+ * or see http://www.jqplot.com/info.php. This is, of course, not required.
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php.
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ *
+ * About: Introduction
+ *
+ * jqPlot requires jQuery (1.4+ required for certain features). jQuery 1.4.2 is included in the distribution.
+ * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally
+ * the excanvas script for IE support in your web page:
+ *
+ * > <!--[if lt IE 9]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
+ * > <script language="javascript" type="text/javascript" src="jquery-1.4.4.min.js"></script>
+ * > <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script>
+ * > <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" />
+ *
+ * jqPlot can be customized by overriding the defaults of any of the objects which make
+ * up the plot. The general usage of jqplot is:
+ *
+ * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject});
+ *
+ * The options available to jqplot are detailed in <jqPlot Options> in the jqPlotOptions.txt file.
+ *
+ * An actual call to $.jqplot() may look like the
+ * examples below:
+ *
+ * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]);
+ *
+ * or
+ *
+ * > dataArray = [34,12,43,55,77];
+ * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}});
+ *
+ * For more inforrmation, see <jqPlot Usage>.
+ *
+ * About: Usage
+ *
+ * See <jqPlot Usage>
+ *
+ * About: Available Options
+ *
+ * See <jqPlot Options> for a list of options available thorugh the options object (not complete yet!)
+ *
+ * About: Options Usage
+ *
+ * See <Options Tutorial>
+ *
+ * About: Changes
+ *
+ * See <Change Log>
+ *
+ */
+
+(function($) {
+ // make sure undefined is undefined
+ var undefined;
+
+ $.fn.emptyForce = function() {
+ for ( var i = 0, elem; (elem = $(this)[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ $.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ if ($.jqplot.use_excanvas) {
+ elem.outerHTML = "";
+ }
+ else {
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ elem = null;
+ }
+
+ return $(this);
+ };
+
+ $.fn.removeChildForce = function(parent) {
+ while ( parent.firstChild ) {
+ this.removeChildForce( parent.firstChild );
+ parent.removeChild( parent.firstChild );
+ }
+ };
+
+ $.fn.jqplot = function() {
+ var datas = [];
+ var options = [];
+ // see how many data arrays we have
+ for (var i=0, l=arguments.length; i<l; i++) {
+ if ($.isArray(arguments[i])) {
+ datas.push(arguments[i]);
+ }
+ else if ($.isPlainObject(arguments[i])) {
+ options.push(arguments[i]);
+ }
+ }
+
+ return this.each(function(index) {
+ var tid,
+ plot,
+ $this = $(this),
+ dl = datas.length,
+ ol = options.length,
+ data,
+ opts;
+
+ if (index < dl) {
+ data = datas[index];
+ }
+ else {
+ data = dl ? datas[dl-1] : null;
+ }
+
+ if (index < ol) {
+ opts = options[index];
+ }
+ else {
+ opts = ol ? options[ol-1] : null;
+ }
+
+ // does el have an id?
+ // if not assign it one.
+ tid = $this.attr('id');
+ if (tid === undefined) {
+ tid = 'jqplot_target_' + $.jqplot.targetCounter++;
+ $this.attr('id', tid);
+ }
+
+ plot = $.jqplot(tid, data, opts);
+
+ $this.data('jqplot', plot);
+ });
+ };
+
+
+ /**
+ * Namespace: $.jqplot
+ * jQuery function called by the user to create a plot.
+ *
+ * Parameters:
+ * target - ID of target element to render the plot into.
+ * data - an array of data series.
+ * options - user defined options object. See the individual classes for available options.
+ *
+ * Properties:
+ * config - object to hold configuration information for jqPlot plot object.
+ *
+ * attributes:
+ * enablePlugins - False to disable plugins by default. Plugins must then be explicitly
+ * enabled in the individual plot options. Default: false.
+ * This property sets the "show" property of certain plugins to true or false.
+ * Only plugins that can be immediately active upon loading are affected. This includes
+ * non-renderer plugins like cursor, dragable, highlighter, and trendline.
+ * defaultHeight - Default height for plots where no css height specification exists. This
+ * is a jqplot wide default.
+ * defaultWidth - Default height for plots where no css height specification exists. This
+ * is a jqplot wide default.
+ */
+
+ $.jqplot = function(target, data, options) {
+ var _data = null, _options = null;
+
+ if (arguments.length === 3) {
+ _data = data;
+ _options = options;
+ }
+
+ else if (arguments.length === 2) {
+ if ($.isArray(data)) {
+ _data = data;
+ }
+
+ else if ($.isPlainObject(data)) {
+ _options = data;
+ }
+ }
+
+ if (_data === null && _options !== null && _options.data) {
+ _data = _options.data;
+ }
+
+ var plot = new jqPlot();
+ // remove any error class that may be stuck on target.
+ $('#'+target).removeClass('jqplot-error');
+
+ if ($.jqplot.config.catchErrors) {
+ try {
+ plot.init(target, _data, _options);
+ plot.draw();
+ plot.themeEngine.init.call(plot);
+ return plot;
+ }
+ catch(e) {
+ var msg = $.jqplot.config.errorMessage || e.message;
+ $('#'+target).append('<div class="jqplot-error-message">'+msg+'</div>');
+ $('#'+target).addClass('jqplot-error');
+ document.getElementById(target).style.background = $.jqplot.config.errorBackground;
+ document.getElementById(target).style.border = $.jqplot.config.errorBorder;
+ document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily;
+ document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize;
+ document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle;
+ document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight;
+ }
+ }
+ else {
+ plot.init(target, _data, _options);
+ plot.draw();
+ plot.themeEngine.init.call(plot);
+ return plot;
+ }
+ };
+
+ $.jqplot.version = "1.0.4";
+ $.jqplot.revision = "1121";
+
+ $.jqplot.targetCounter = 1;
+
+ // canvas manager to reuse canvases on the plot.
+ // Should help solve problem of canvases not being freed and
+ // problem of waiting forever for firefox to decide to free memory.
+ $.jqplot.CanvasManager = function() {
+ // canvases are managed globally so that they can be reused
+ // across plots after they have been freed
+ if (typeof $.jqplot.CanvasManager.canvases == 'undefined') {
+ $.jqplot.CanvasManager.canvases = [];
+ $.jqplot.CanvasManager.free = [];
+ }
+
+ var myCanvases = [];
+
+ this.getCanvas = function() {
+ var canvas;
+ var makeNew = true;
+
+ if (!$.jqplot.use_excanvas) {
+ for (var i = 0, l = $.jqplot.CanvasManager.canvases.length; i < l; i++) {
+ if ($.jqplot.CanvasManager.free[i] === true) {
+ makeNew = false;
+ canvas = $.jqplot.CanvasManager.canvases[i];
+ // $(canvas).removeClass('jqplot-canvasManager-free').addClass('jqplot-canvasManager-inuse');
+ $.jqplot.CanvasManager.free[i] = false;
+ myCanvases.push(i);
+ break;
+ }
+ }
+ }
+
+ if (makeNew) {
+ canvas = document.createElement('canvas');
+ myCanvases.push($.jqplot.CanvasManager.canvases.length);
+ $.jqplot.CanvasManager.canvases.push(canvas);
+ $.jqplot.CanvasManager.free.push(false);
+ }
+
+ return canvas;
+ };
+
+ // this method has to be used after settings the dimesions
+ // on the element returned by getCanvas()
+ this.initCanvas = function(canvas) {
+ if ($.jqplot.use_excanvas) {
+ return window.G_vmlCanvasManager.initElement(canvas);
+ }
+ return canvas;
+ };
+
+ this.freeAllCanvases = function() {
+ for (var i = 0, l=myCanvases.length; i < l; i++) {
+ this.freeCanvas(myCanvases[i]);
+ }
+ myCanvases = [];
+ };
+
+ this.freeCanvas = function(idx) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ // excanvas can't be reused, but properly unset
+ window.G_vmlCanvasManager.uninitElement($.jqplot.CanvasManager.canvases[idx]);
+ $.jqplot.CanvasManager.canvases[idx] = null;
+ }
+ else {
+ var canvas = $.jqplot.CanvasManager.canvases[idx];
+ canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ $(canvas).unbind().removeAttr('class').removeAttr('style');
+ // Style attributes seemed to be still hanging around weird. Some ticks
+ // still retained a left: 0px attribute after reusing a canvas.
+ $(canvas).css({left: '', top: '', position: ''});
+ // setting size to 0 may save memory of unused canvases?
+ canvas.width = 0;
+ canvas.height = 0;
+ $.jqplot.CanvasManager.free[idx] = true;
+ }
+ };
+
+ };
+
+
+ // Convienence function that won't hang IE or FF without FireBug.
+ $.jqplot.log = function() {
+ if (window.console) {
+ window.console.log.apply(window.console, arguments);
+ }
+ };
+
+ $.jqplot.config = {
+ addDomReference: false,
+ enablePlugins:false,
+ defaultHeight:300,
+ defaultWidth:400,
+ UTCAdjust:false,
+ timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000),
+ errorMessage: '',
+ errorBackground: '',
+ errorBorder: '',
+ errorFontFamily: '',
+ errorFontSize: '',
+ errorFontStyle: '',
+ errorFontWeight: '',
+ catchErrors: false,
+ defaultTickFormatString: "%.1f",
+ defaultColors: [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"],
+ dashLength: 4,
+ gapLength: 4,
+ dotGapLength: 2.5,
+ srcLocation: 'jqplot/src/',
+ pluginLocation: 'jqplot/src/plugins/'
+ };
+
+
+ $.jqplot.arrayMax = function( array ){
+ return Math.max.apply( Math, array );
+ };
+
+ $.jqplot.arrayMin = function( array ){
+ return Math.min.apply( Math, array );
+ };
+
+ $.jqplot.enablePlugins = $.jqplot.config.enablePlugins;
+
+ // canvas related tests taken from modernizer:
+ // Copyright (c) 2009 - 2010 Faruk Ates.
+ // http://www.modernizr.com
+
+ $.jqplot.support_canvas = function() {
+ if (typeof $.jqplot.support_canvas.result == 'undefined') {
+ $.jqplot.support_canvas.result = !!document.createElement('canvas').getContext;
+ }
+ return $.jqplot.support_canvas.result;
+ };
+
+ $.jqplot.support_canvas_text = function() {
+ if (typeof $.jqplot.support_canvas_text.result == 'undefined') {
+ if (window.G_vmlCanvasManager !== undefined && window.G_vmlCanvasManager._version > 887) {
+ $.jqplot.support_canvas_text.result = true;
+ }
+ else {
+ $.jqplot.support_canvas_text.result = !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function');
+ }
+
+ }
+ return $.jqplot.support_canvas_text.result;
+ };
+
+ $.jqplot.use_excanvas = ($.browser.msie && !$.jqplot.support_canvas()) ? true : false;
+
+ /**
+ *
+ * Hooks: jqPlot Pugin Hooks
+ *
+ * $.jqplot.preInitHooks - called before initialization.
+ * $.jqplot.postInitHooks - called after initialization.
+ * $.jqplot.preParseOptionsHooks - called before user options are parsed.
+ * $.jqplot.postParseOptionsHooks - called after user options are parsed.
+ * $.jqplot.preDrawHooks - called before plot draw.
+ * $.jqplot.postDrawHooks - called after plot draw.
+ * $.jqplot.preDrawSeriesHooks - called before each series is drawn.
+ * $.jqplot.postDrawSeriesHooks - called after each series is drawn.
+ * $.jqplot.preDrawLegendHooks - called before the legend is drawn.
+ * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins
+ * can add rows to the legend table.
+ * $.jqplot.preSeriesInitHooks - called before series is initialized.
+ * $.jqplot.postSeriesInitHooks - called after series is initialized.
+ * $.jqplot.preParseSeriesOptionsHooks - called before series related options
+ * are parsed.
+ * $.jqplot.postParseSeriesOptionsHooks - called after series related options
+ * are parsed.
+ * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds
+ * listeners to the event canvas which lays on top of the grid area.
+ * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn.
+ * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn.
+ *
+ */
+
+ $.jqplot.preInitHooks = [];
+ $.jqplot.postInitHooks = [];
+ $.jqplot.preParseOptionsHooks = [];
+ $.jqplot.postParseOptionsHooks = [];
+ $.jqplot.preDrawHooks = [];
+ $.jqplot.postDrawHooks = [];
+ $.jqplot.preDrawSeriesHooks = [];
+ $.jqplot.postDrawSeriesHooks = [];
+ $.jqplot.preDrawLegendHooks = [];
+ $.jqplot.addLegendRowHooks = [];
+ $.jqplot.preSeriesInitHooks = [];
+ $.jqplot.postSeriesInitHooks = [];
+ $.jqplot.preParseSeriesOptionsHooks = [];
+ $.jqplot.postParseSeriesOptionsHooks = [];
+ $.jqplot.eventListenerHooks = [];
+ $.jqplot.preDrawSeriesShadowHooks = [];
+ $.jqplot.postDrawSeriesShadowHooks = [];
+
+ // A superclass holding some common properties and methods.
+ $.jqplot.ElemContainer = function() {
+ this._elem;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+ };
+
+ $.jqplot.ElemContainer.prototype.createElement = function(el, offsets, clss, cssopts, attrib) {
+ this._offsets = offsets;
+ var klass = clss || 'jqplot';
+ var elem = document.createElement(el);
+ this._elem = $(elem);
+ this._elem.addClass(klass);
+ this._elem.css(cssopts);
+ this._elem.attr(attrib);
+ // avoid memory leak;
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.ElemContainer.prototype.getWidth = function() {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ return null;
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getHeight = function() {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ return null;
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getPosition = function() {
+ if (this._elem) {
+ return this._elem.position();
+ }
+ else {
+ return {top:null, left:null, bottom:null, right:null};
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getTop = function() {
+ return this.getPosition().top;
+ };
+
+ $.jqplot.ElemContainer.prototype.getLeft = function() {
+ return this.getPosition().left;
+ };
+
+ $.jqplot.ElemContainer.prototype.getBottom = function() {
+ return this._elem.css('bottom');
+ };
+
+ $.jqplot.ElemContainer.prototype.getRight = function() {
+ return this._elem.css('right');
+ };
+
+
+ /**
+ * Class: Axis
+ * An individual axis object. Cannot be instantiated directly, but created
+ * by the Plot oject. Axis properties can be set or overriden by the
+ * options passed in from the user.
+ *
+ */
+ function Axis(name) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+ //
+ // Axes options are specified within an axes object at the top level of the
+ // plot options like so:
+ // > {
+ // > axes: {
+ // > xaxis: {min: 5},
+ // > yaxis: {min: 2, max: 8, numberTicks:4},
+ // > x2axis: {pad: 1.5},
+ // > y2axis: {ticks:[22, 44, 66, 88]}
+ // > }
+ // > }
+ // There are 2 x axes, 'xaxis' and 'x2axis', and
+ // 9 yaxes, 'yaxis', 'y2axis'. 'y3axis', ... Any or all of which may be specified.
+ this.name = name;
+ this._series = [];
+ // prop: show
+ // Wether to display the axis on the graph.
+ this.show = false;
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // prop: tickOptions
+ // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options.
+ this.tickOptions = {};
+ // prop: labelRenderer
+ // A class of a rendering engine for creating an axis label.
+ this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ // prop: labelOptions
+ // Options passed to the label renderer.
+ this.labelOptions = {};
+ // prop: label
+ // Label for the axis
+ this.label = null;
+ // prop: showLabel
+ // true to show the axis label.
+ this.showLabel = true;
+ // prop: min
+ // minimum value of the axis (in data units, not pixels).
+ this.min = null;
+ // prop: max
+ // maximum value of the axis (in data units, not pixels).
+ this.max = null;
+ // prop: autoscale
+ // DEPRECATED
+ // the default scaling algorithm produces superior results.
+ this.autoscale = false;
+ // prop: pad
+ // Padding to extend the range above and below the data bounds.
+ // The data range is multiplied by this factor to determine minimum and maximum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0.
+ this.pad = 1.2;
+ // prop: padMax
+ // Padding to extend the range above data bounds.
+ // The top of the data range is multiplied by this factor to determine maximum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0.
+ this.padMax = null;
+ // prop: padMin
+ // Padding to extend the range below data bounds.
+ // The bottom of the data range is multiplied by this factor to determine minimum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0.
+ this.padMin = null;
+ // prop: ticks
+ // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis.
+ // If no label is specified, the value is formatted into an appropriate label.
+ this.ticks = [];
+ // prop: numberTicks
+ // Desired number of ticks. Default is to compute automatically.
+ this.numberTicks;
+ // prop: tickInterval
+ // number of units between ticks. Mutually exclusive with numberTicks.
+ this.tickInterval;
+ // prop: renderer
+ // A class of a rendering engine that handles tick generation,
+ // scaling input data to pixel grid units and drawing the axis element.
+ this.renderer = $.jqplot.LinearAxisRenderer;
+ // prop: rendererOptions
+ // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options.
+ this.rendererOptions = {};
+ // prop: showTicks
+ // Wether to show the ticks (both marks and labels) or not.
+ // Will not override showMark and showLabel options if specified on the ticks themselves.
+ this.showTicks = true;
+ // prop: showTickMarks
+ // Wether to show the tick marks (line crossing grid) or not.
+ // Overridden by showTicks and showMark option of tick itself.
+ this.showTickMarks = true;
+ // prop: showMinorTicks
+ // Wether or not to show minor ticks. This is renderer dependent.
+ this.showMinorTicks = true;
+ // prop: drawMajorGridlines
+ // True to draw gridlines for major axis ticks.
+ this.drawMajorGridlines = true;
+ // prop: drawMinorGridlines
+ // True to draw gridlines for minor ticks.
+ this.drawMinorGridlines = false;
+ // prop: drawMajorTickMarks
+ // True to draw tick marks for major axis ticks.
+ this.drawMajorTickMarks = true;
+ // prop: drawMinorTickMarks
+ // True to draw tick marks for minor ticks. This is renderer dependent.
+ this.drawMinorTickMarks = true;
+ // prop: useSeriesColor
+ // Use the color of the first series associated with this axis for the
+ // tick marks and line bordering this axis.
+ this.useSeriesColor = false;
+ // prop: borderWidth
+ // width of line stroked at the border of the axis. Defaults
+ // to the width of the grid boarder.
+ this.borderWidth = null;
+ // prop: borderColor
+ // color of the border adjacent to the axis. Defaults to grid border color.
+ this.borderColor = null;
+ // prop: scaleToHiddenSeries
+ // True to include hidden series when computing axes bounds and scaling.
+ this.scaleToHiddenSeries = false;
+ // minimum and maximum values on the axis.
+ this._dataBounds = {min:null, max:null};
+ // statistics (min, max, mean) as well as actual data intervals for each series attached to axis.
+ // holds collection of {intervals:[], min:, max:, mean: } objects for each series on axis.
+ this._intervalStats = [];
+ // pixel position from the top left of the min value and max value on the axis.
+ this._offsets = {min:null, max:null};
+ this._ticks=[];
+ this._label = null;
+ // prop: syncTicks
+ // true to try and synchronize tick spacing across multiple axes so that ticks and
+ // grid lines line up. This has an impact on autoscaling algorithm, however.
+ // In general, autoscaling an individual axis will work better if it does not
+ // have to sync ticks.
+ this.syncTicks = null;
+ // prop: tickSpacing
+ // Approximate pixel spacing between ticks on graph. Used during autoscaling.
+ // This number will be an upper bound, actual spacing will be less.
+ this.tickSpacing = 75;
+ // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks
+ // so they can be restored if altered by plugins.
+ this._min = null;
+ this._max = null;
+ this._tickInterval = null;
+ this._numberTicks = null;
+ this.__ticks = null;
+ // hold original user options.
+ this._options = {};
+ }
+
+ Axis.prototype = new $.jqplot.ElemContainer();
+ Axis.prototype.constructor = Axis;
+
+ Axis.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ // set the axis name
+ this.tickOptions.axis = this.name;
+ // if showMark or showLabel tick options not specified, use value of axis option.
+ // showTicks overrides showTickMarks.
+ if (this.tickOptions.showMark == null) {
+ this.tickOptions.showMark = this.showTicks;
+ }
+ if (this.tickOptions.showMark == null) {
+ this.tickOptions.showMark = this.showTickMarks;
+ }
+ if (this.tickOptions.showLabel == null) {
+ this.tickOptions.showLabel = this.showTicks;
+ }
+
+ if (this.label == null || this.label == '') {
+ this.showLabel = false;
+ }
+ else {
+ this.labelOptions.label = this.label;
+ }
+ if (this.showLabel == false) {
+ this.labelOptions.show = false;
+ }
+ // set the default padMax, padMin if not specified
+ // special check, if no padding desired, padding
+ // should be set to 1.0
+ if (this.pad == 0) {
+ this.pad = 1.0;
+ }
+ if (this.padMax == 0) {
+ this.padMax = 1.0;
+ }
+ if (this.padMin == 0) {
+ this.padMin = 1.0;
+ }
+ if (this.padMax == null) {
+ this.padMax = (this.pad-1)/2 + 1;
+ }
+ if (this.padMin == null) {
+ this.padMin = (this.pad-1)/2 + 1;
+ }
+ // now that padMin and padMax are correctly set, reset pad in case user has supplied
+ // padMin and/or padMax
+ this.pad = this.padMax + this.padMin - 1;
+ if (this.min != null || this.max != null) {
+ this.autoscale = false;
+ }
+ // if not set, sync ticks for y axes but not x by default.
+ if (this.syncTicks == null && this.name.indexOf('y') > -1) {
+ this.syncTicks = true;
+ }
+ else if (this.syncTicks == null){
+ this.syncTicks = false;
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+
+ };
+
+ Axis.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this.__ticks) {
+ this.__ticks = null;
+ }
+
+ return this.renderer.draw.call(this, ctx, plot);
+
+ };
+
+ Axis.prototype.set = function() {
+ this.renderer.set.call(this);
+ };
+
+ Axis.prototype.pack = function(pos, offsets) {
+ if (this.show) {
+ this.renderer.pack.call(this, pos, offsets);
+ }
+ // these properties should all be available now.
+ if (this._min == null) {
+ this._min = this.min;
+ this._max = this.max;
+ this._tickInterval = this.tickInterval;
+ this._numberTicks = this.numberTicks;
+ this.__ticks = this._ticks;
+ }
+ };
+
+ // reset the axis back to original values if it has been scaled, zoomed, etc.
+ Axis.prototype.reset = function() {
+ this.renderer.reset.call(this);
+ };
+
+ Axis.prototype.resetScale = function(opts) {
+ $.extend(true, this, {min: null, max: null, numberTicks: null, tickInterval: null, _ticks: [], ticks: []}, opts);
+ this.resetDataBounds();
+ };
+
+ Axis.prototype.resetDataBounds = function() {
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ var db = this._dataBounds;
+ db.min = null;
+ db.max = null;
+ var l, s, d;
+ // check for when to force min 0 on bar series plots.
+ var doforce = (this.show) ? true : false;
+ for (var i=0; i<this._series.length; i++) {
+ s = this._series[i];
+ if (s.show || this.scaleToHiddenSeries) {
+ d = s._plotData;
+ if (s._type === 'line' && s.renderer.bands.show && this.name.charAt(0) !== 'x') {
+ d = [[0, s.renderer.bands._min], [1, s.renderer.bands._max]];
+ }
+
+ var minyidx = 1, maxyidx = 1;
+
+ if (s._type != null && s._type == 'ohlc') {
+ minyidx = 3;
+ maxyidx = 2;
+ }
+
+ for (var j=0, l=d.length; j<l; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
+ db.min = d[j][0];
+ }
+ if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if ((d[j][minyidx] != null && d[j][minyidx] < db.min) || db.min == null) {
+ db.min = d[j][minyidx];
+ }
+ if ((d[j][maxyidx] != null && d[j][maxyidx] > db.max) || db.max == null) {
+ db.max = d[j][maxyidx];
+ }
+ }
+ }
+
+ // Hack to not pad out bottom of bar plots unless user has specified a padding.
+ // every series will have a chance to set doforce to false. once it is set to
+ // false, it cannot be reset to true.
+ // If any series attached to axis is not a bar, wont force 0.
+ if (doforce && s.renderer.constructor !== $.jqplot.BarRenderer) {
+ doforce = false;
+ }
+
+ else if (doforce && this._options.hasOwnProperty('forceTickAt0') && this._options.forceTickAt0 == false) {
+ doforce = false;
+ }
+
+ else if (doforce && s.renderer.constructor === $.jqplot.BarRenderer) {
+ if (s.barDirection == 'vertical' && this.name != 'xaxis' && this.name != 'x2axis') {
+ if (this._options.pad != null || this._options.padMin != null) {
+ doforce = false;
+ }
+ }
+
+ else if (s.barDirection == 'horizontal' && (this.name == 'xaxis' || this.name == 'x2axis')) {
+ if (this._options.pad != null || this._options.padMin != null) {
+ doforce = false;
+ }
+ }
+
+ }
+ }
+ }
+
+ if (doforce && this.renderer.constructor === $.jqplot.LinearAxisRenderer && db.min >= 0) {
+ this.padMin = 1.0;
+ this.forceTickAt0 = true;
+ }
+ };
+
+ /**
+ * Class: Legend
+ * Legend object. Cannot be instantiated directly, but created
+ * by the Plot oject. Legend properties can be set or overriden by the
+ * options passed in from the user.
+ */
+ function Legend(options) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: show
+ // Wether to display the legend on the graph.
+ this.show = false;
+ // prop: location
+ // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w
+ this.location = 'ne';
+ // prop: labels
+ // Array of labels to use. By default the renderer will look for labels on the series.
+ // Labels specified in this array will override labels specified on the series.
+ this.labels = [];
+ // prop: showLabels
+ // true to show the label text on the legend.
+ this.showLabels = true;
+ // prop: showSwatch
+ // true to show the color swatches on the legend.
+ this.showSwatches = true;
+ // prop: placement
+ // "insideGrid" places legend inside the grid area of the plot.
+ // "outsideGrid" places the legend outside the grid but inside the plot container,
+ // shrinking the grid to accomodate the legend.
+ // "inside" synonym for "insideGrid",
+ // "outside" places the legend ouside the grid area, but does not shrink the grid which
+ // can cause the legend to overflow the plot container.
+ this.placement = "insideGrid";
+ // prop: xoffset
+ // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
+ // properties or via CSS margin styling of the .jqplot-table-legend class.
+ this.xoffset = 0;
+ // prop: yoffset
+ // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
+ // properties or via CSS margin styling of the .jqplot-table-legend class.
+ this.yoffset = 0;
+ // prop: border
+ // css spec for the border around the legend box.
+ this.border;
+ // prop: background
+ // css spec for the background of the legend box.
+ this.background;
+ // prop: textColor
+ // css color spec for the legend text.
+ this.textColor;
+ // prop: fontFamily
+ // css font-family spec for the legend text.
+ this.fontFamily;
+ // prop: fontSize
+ // css font-size spec for the legend text.
+ this.fontSize ;
+ // prop: rowSpacing
+ // css padding-top spec for the rows in the legend.
+ this.rowSpacing = '0.5em';
+ // renderer
+ // A class that will create a DOM object for the legend,
+ // see <$.jqplot.TableLegendRenderer>.
+ this.renderer = $.jqplot.TableLegendRenderer;
+ // prop: rendererOptions
+ // renderer specific options passed to the renderer.
+ this.rendererOptions = {};
+ // prop: predraw
+ // Wether to draw the legend before the series or not.
+ // Used with series specific legend renderers for pie, donut, mekko charts, etc.
+ this.preDraw = false;
+ // prop: marginTop
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginTop = null;
+ // prop: marginRight
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginRight = null;
+ // prop: marginBottom
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginBottom = null;
+ // prop: marginLeft
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginLeft = null;
+ // prop: escapeHtml
+ // True to escape special characters with their html entity equivalents
+ // in legend text. "<" becomes &lt; and so on, so html tags are not rendered.
+ this.escapeHtml = false;
+ this._series = [];
+
+ $.extend(true, this, options);
+ }
+
+ Legend.prototype = new $.jqplot.ElemContainer();
+ Legend.prototype.constructor = Legend;
+
+ Legend.prototype.setOptions = function(options) {
+ $.extend(true, this, options);
+
+ // Try to emulate deprecated behaviour
+ // if user has specified xoffset or yoffset, copy these to
+ // the margin properties.
+
+ if (this.placement == 'inside') {
+ this.placement = 'insideGrid';
+ }
+
+ if (this.xoffset >0) {
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ case 'w':
+ case 'sw':
+ if (this.marginLeft == null) {
+ this.marginLeft = this.xoffset + 'px';
+ }
+ this.marginRight = '0px';
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ default:
+ if (this.marginRight == null) {
+ this.marginRight = this.xoffset + 'px';
+ }
+ this.marginLeft = '0px';
+ break;
+ }
+ }
+ else if (this.placement == 'outside') {
+ switch (this.location) {
+ case 'nw':
+ case 'w':
+ case 'sw':
+ if (this.marginRight == null) {
+ this.marginRight = this.xoffset + 'px';
+ }
+ this.marginLeft = '0px';
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ default:
+ if (this.marginLeft == null) {
+ this.marginLeft = this.xoffset + 'px';
+ }
+ this.marginRight = '0px';
+ break;
+ }
+ }
+ this.xoffset = 0;
+ }
+
+ if (this.yoffset >0) {
+ if (this.placement == 'outside') {
+ switch (this.location) {
+ case 'sw':
+ case 's':
+ case 'se':
+ if (this.marginTop == null) {
+ this.marginTop = this.yoffset + 'px';
+ }
+ this.marginBottom = '0px';
+ break;
+ case 'ne':
+ case 'n':
+ case 'nw':
+ default:
+ if (this.marginBottom == null) {
+ this.marginBottom = this.yoffset + 'px';
+ }
+ this.marginTop = '0px';
+ break;
+ }
+ }
+ else if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'sw':
+ case 's':
+ case 'se':
+ if (this.marginBottom == null) {
+ this.marginBottom = this.yoffset + 'px';
+ }
+ this.marginTop = '0px';
+ break;
+ case 'ne':
+ case 'n':
+ case 'nw':
+ default:
+ if (this.marginTop == null) {
+ this.marginTop = this.yoffset + 'px';
+ }
+ this.marginBottom = '0px';
+ break;
+ }
+ }
+ this.yoffset = 0;
+ }
+
+ // TO-DO:
+ // Handle case where offsets are < 0.
+ //
+ };
+
+ Legend.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Legend.prototype.draw = function(offsets, plot) {
+ for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){
+ $.jqplot.preDrawLegendHooks[i].call(this, offsets);
+ }
+ return this.renderer.draw.call(this, offsets, plot);
+ };
+
+ Legend.prototype.pack = function(offsets) {
+ this.renderer.pack.call(this, offsets);
+ };
+
+ /**
+ * Class: Title
+ * Plot Title object. Cannot be instantiated directly, but created
+ * by the Plot oject. Title properties can be set or overriden by the
+ * options passed in from the user.
+ *
+ * Parameters:
+ * text - text of the title.
+ */
+ function Title(text) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: text
+ // text of the title;
+ this.text = text;
+ // prop: show
+ // wether or not to show the title
+ this.show = true;
+ // prop: fontFamily
+ // css font-family spec for the text.
+ this.fontFamily;
+ // prop: fontSize
+ // css font-size spec for the text.
+ this.fontSize ;
+ // prop: textAlign
+ // css text-align spec for the text.
+ this.textAlign;
+ // prop: textColor
+ // css color spec for the text.
+ this.textColor;
+ // prop: renderer
+ // A class for creating a DOM element for the title,
+ // see <$.jqplot.DivTitleRenderer>.
+ this.renderer = $.jqplot.DivTitleRenderer;
+ // prop: rendererOptions
+ // renderer specific options passed to the renderer.
+ this.rendererOptions = {};
+ // prop: escapeHtml
+ // True to escape special characters with their html entity equivalents
+ // in title text. "<" becomes &lt; and so on, so html tags are not rendered.
+ this.escapeHtml = false;
+ }
+
+ Title.prototype = new $.jqplot.ElemContainer();
+ Title.prototype.constructor = Title;
+
+ Title.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Title.prototype.draw = function(width) {
+ return this.renderer.draw.call(this, width);
+ };
+
+ Title.prototype.pack = function() {
+ this.renderer.pack.call(this);
+ };
+
+
+ /**
+ * Class: Series
+ * An individual data series object. Cannot be instantiated directly, but created
+ * by the Plot oject. Series properties can be set or overriden by the
+ * options passed in from the user.
+ */
+ function Series(options) {
+ options = options || {};
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+ // Properties will be assigned from a series array at the top level of the
+ // options. If you had two series and wanted to change the color and line
+ // width of the first and set the second to use the secondary y axis with
+ // no shadow and supply custom labels for each:
+ // > {
+ // > series:[
+ // > {color: '#ff4466', lineWidth: 5, label:'good line'},
+ // > {yaxis: 'y2axis', shadow: false, label:'bad line'}
+ // > ]
+ // > }
+
+ // prop: show
+ // wether or not to draw the series.
+ this.show = true;
+ // prop: xaxis
+ // which x axis to use with this series, either 'xaxis' or 'x2axis'.
+ this.xaxis = 'xaxis';
+ this._xaxis;
+ // prop: yaxis
+ // which y axis to use with this series, either 'yaxis' or 'y2axis'.
+ this.yaxis = 'yaxis';
+ this._yaxis;
+ this.gridBorderWidth = 2.0;
+ // prop: renderer
+ // A class of a renderer which will draw the series,
+ // see <$.jqplot.LineRenderer>.
+ this.renderer = $.jqplot.LineRenderer;
+ // prop: rendererOptions
+ // Options to pass on to the renderer.
+ this.rendererOptions = {};
+ this.data = [];
+ this.gridData = [];
+ // prop: label
+ // Line label to use in the legend.
+ this.label = '';
+ // prop: showLabel
+ // true to show label for this series in the legend.
+ this.showLabel = true;
+ // prop: color
+ // css color spec for the series
+ this.color;
+ // prop: negativeColor
+ // css color spec used for filled (area) plots that are filled to zero and
+ // the "useNegativeColors" option is true.
+ this.negativeColor;
+ // prop: lineWidth
+ // width of the line in pixels. May have different meanings depending on renderer.
+ this.lineWidth = 2.5;
+ // prop: lineJoin
+ // Canvas lineJoin style between segments of series.
+ this.lineJoin = 'round';
+ // prop: lineCap
+ // Canvas lineCap style at ends of line.
+ this.lineCap = 'round';
+ // prop: linePattern
+ // line pattern 'dashed', 'dotted', 'solid', some combination
+ // of '-' and '.' characters such as '.-.' or a numerical array like
+ // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line,
+ // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+ this.linePattern = 'solid';
+ this.shadow = true;
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ this.shadowOffset = 1.25;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.1';
+ // prop: breakOnNull
+ // Wether line segments should be be broken at null value.
+ // False will join point on either side of line.
+ this.breakOnNull = false;
+ // prop: markerRenderer
+ // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points,
+ // see <$.jqplot.MarkerRenderer>.
+ this.markerRenderer = $.jqplot.MarkerRenderer;
+ // prop: markerOptions
+ // renderer specific options to pass to the markerRenderer,
+ // see <$.jqplot.MarkerRenderer>.
+ this.markerOptions = {};
+ // prop: showLine
+ // wether to actually draw the line or not. Series will still be renderered, even if no line is drawn.
+ this.showLine = true;
+ // prop: showMarker
+ // wether or not to show the markers at the data points.
+ this.showMarker = true;
+ // prop: index
+ // 0 based index of this series in the plot series array.
+ this.index;
+ // prop: fill
+ // true or false, wether to fill under lines or in bars.
+ // May not be implemented in all renderers.
+ this.fill = false;
+ // prop: fillColor
+ // CSS color spec to use for fill under line. Defaults to line color.
+ this.fillColor;
+ // prop: fillAlpha
+ // Alpha transparency to apply to the fill under the line.
+ // Use this to adjust alpha separate from fill color.
+ this.fillAlpha;
+ // prop: fillAndStroke
+ // If true will stroke the line (with color this.color) as well as fill under it.
+ // Applies only when fill is true.
+ this.fillAndStroke = false;
+ // prop: disableStack
+ // true to not stack this series with other series in the plot.
+ // To render properly, non-stacked series must come after any stacked series
+ // in the plot's data series array. So, the plot's data series array would look like:
+ // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...]
+ // disableStack will put a gap in the stacking order of series, and subsequent
+ // stacked series will not fill down through the non-stacked series and will
+ // most likely not stack properly on top of the non-stacked series.
+ this.disableStack = false;
+ // _stack is set by the Plot if the plot is a stacked chart.
+ // will stack lines or bars on top of one another to build a "mountain" style chart.
+ // May not be implemented in all renderers.
+ this._stack = false;
+ // prop: neighborThreshold
+ // how close or far (in pixels) the cursor must be from a point marker to detect the point.
+ this.neighborThreshold = 4;
+ // prop: fillToZero
+ // true will force bar and filled series to fill toward zero on the fill Axis.
+ this.fillToZero = false;
+ // prop: fillToValue
+ // fill a filled series to this value on the fill axis.
+ // Works in conjunction with fillToZero, so that must be true.
+ this.fillToValue = 0;
+ // prop: fillAxis
+ // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true.
+ // 'y' means fill up/down to 0 on the y axis for this series.
+ this.fillAxis = 'y';
+ // prop: useNegativeColors
+ // true to color negative values differently in filled and bar charts.
+ this.useNegativeColors = true;
+ this._stackData = [];
+ // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If
+ // stacked, _plotData is accumulation of stacking data.
+ this._plotData = [];
+ // _plotValues hold the individual x and y values that will be plotted for this series.
+ this._plotValues = {x:[], y:[]};
+ // statistics about the intervals between data points. Used for auto scaling.
+ this._intervals = {x:{}, y:{}};
+ // data from the previous series, for stacked charts.
+ this._prevPlotData = [];
+ this._prevGridData = [];
+ this._stackAxis = 'y';
+ this._primaryAxis = '_xaxis';
+ // give each series a canvas to draw on. This should allow for redrawing speedups.
+ this.canvas = new $.jqplot.GenericCanvas();
+ this.shadowCanvas = new $.jqplot.GenericCanvas();
+ this.plugins = {};
+ // sum of y values in this series.
+ this._sumy = 0;
+ this._sumx = 0;
+ this._type = '';
+ }
+
+ Series.prototype = new $.jqplot.ElemContainer();
+ Series.prototype.constructor = Series;
+
+ Series.prototype.init = function(index, gridbw, plot) {
+ // weed out any null values in the data.
+ this.index = index;
+ this.gridBorderWidth = gridbw;
+ var d = this.data;
+ var temp = [], i, l;
+ for (i=0, l=d.length; i<l; i++) {
+ if (! this.breakOnNull) {
+ if (d[i] == null || d[i][0] == null || d[i][1] == null) {
+ continue;
+ }
+ else {
+ temp.push(d[i]);
+ }
+ }
+ else {
+ // TODO: figure out what to do with null values
+ // probably involve keeping nulls in data array
+ // and then updating renderers to break line
+ // when it hits null value.
+ // For now, just keep value.
+ temp.push(d[i]);
+ }
+ }
+ this.data = temp;
+
+ // parse the renderer options and apply default colors if not provided
+ // Set color even if not shown, so series don't change colors when other
+ // series on plot shown/hidden.
+ if (!this.color) {
+ this.color = plot.colorGenerator.get(this.index);
+ }
+ if (!this.negativeColor) {
+ this.negativeColor = plot.negativeColorGenerator.get(this.index);
+ }
+
+
+ if (!this.fillColor) {
+ this.fillColor = this.color;
+ }
+ if (this.fillAlpha) {
+ var comp = $.jqplot.normalize2rgb(this.fillColor);
+ var comp = $.jqplot.getColorComponents(comp);
+ this.fillColor = 'rgba('+comp[0]+','+comp[1]+','+comp[2]+','+this.fillAlpha+')';
+ }
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions, plot);
+ this.markerRenderer = new this.markerRenderer();
+ if (!this.markerOptions.color) {
+ this.markerOptions.color = this.color;
+ }
+ if (this.markerOptions.show == null) {
+ this.markerOptions.show = this.showMarker;
+ }
+ this.showMarker = this.markerOptions.show;
+ // the markerRenderer is called within it's own scaope, don't want to overwrite series options!!
+ this.markerRenderer.init(this.markerOptions);
+ };
+
+ // data - optional data point array to draw using this series renderer
+ // gridData - optional grid data point array to draw using this series renderer
+ // stackData - array of cumulative data for stacked plots.
+ Series.prototype.draw = function(sctx, opts, plot) {
+ var options = (opts == undefined) ? {} : opts;
+ sctx = (sctx == undefined) ? this.canvas._ctx : sctx;
+
+ var j, data, gridData;
+
+ // hooks get called even if series not shown
+ // we don't clear canvas here, it would wipe out all other series as well.
+ for (j=0; j<$.jqplot.preDrawSeriesHooks.length; j++) {
+ $.jqplot.preDrawSeriesHooks[j].call(this, sctx, options);
+ }
+ if (this.show) {
+ this.renderer.setGridData.call(this, plot);
+ if (!options.preventJqPlotSeriesDrawTrigger) {
+ $(sctx.canvas).trigger('jqplotSeriesDraw', [this.data, this.gridData]);
+ }
+ data = [];
+ if (options.data) {
+ data = options.data;
+ }
+ else if (!this._stack) {
+ data = this.data;
+ }
+ else {
+ data = this._plotData;
+ }
+ gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
+
+ if (this._type === 'line' && this.renderer.smooth && this.renderer._smoothedData.length) {
+ gridData = this.renderer._smoothedData;
+ }
+
+ this.renderer.draw.call(this, sctx, gridData, options, plot);
+ }
+
+ for (j=0; j<$.jqplot.postDrawSeriesHooks.length; j++) {
+ $.jqplot.postDrawSeriesHooks[j].call(this, sctx, options, plot);
+ }
+
+ sctx = opts = plot = j = data = gridData = null;
+ };
+
+ Series.prototype.drawShadow = function(sctx, opts, plot) {
+ var options = (opts == undefined) ? {} : opts;
+ sctx = (sctx == undefined) ? this.shadowCanvas._ctx : sctx;
+
+ var j, data, gridData;
+
+ // hooks get called even if series not shown
+ // we don't clear canvas here, it would wipe out all other series as well.
+ for (j=0; j<$.jqplot.preDrawSeriesShadowHooks.length; j++) {
+ $.jqplot.preDrawSeriesShadowHooks[j].call(this, sctx, options);
+ }
+ if (this.shadow) {
+ this.renderer.setGridData.call(this, plot);
+
+ data = [];
+ if (options.data) {
+ data = options.data;
+ }
+ else if (!this._stack) {
+ data = this.data;
+ }
+ else {
+ data = this._plotData;
+ }
+ gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
+
+ this.renderer.drawShadow.call(this, sctx, gridData, options, plot);
+ }
+
+ for (j=0; j<$.jqplot.postDrawSeriesShadowHooks.length; j++) {
+ $.jqplot.postDrawSeriesShadowHooks[j].call(this, sctx, options);
+ }
+
+ sctx = opts = plot = j = data = gridData = null;
+
+ };
+
+ // toggles series display on plot, e.g. show/hide series
+ Series.prototype.toggleDisplay = function(ev, callback) {
+ var s, speed;
+ if (ev.data.series) {
+ s = ev.data.series;
+ }
+ else {
+ s = this;
+ }
+
+ if (ev.data.speed) {
+ speed = ev.data.speed;
+ }
+ if (speed) {
+ // this can be tricky because series may not have a canvas element if replotting.
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ s.show = true;
+
+ s.canvas._elem.removeClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.fadeIn(speed);
+ }
+ s.canvas._elem.fadeIn(speed, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeIn(speed);
+ }
+ else {
+ s.show = false;
+
+ s.canvas._elem.addClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.fadeOut(speed);
+ }
+ s.canvas._elem.fadeOut(speed, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeOut(speed);
+ }
+ }
+ else {
+ // this can be tricky because series may not have a canvas element if replotting.
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ s.show = true;
+
+ s.canvas._elem.removeClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.show();
+ }
+ s.canvas._elem.show(0, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).show();
+ }
+ else {
+ s.show = false;
+
+ s.canvas._elem.addClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.hide();
+ }
+ s.canvas._elem.hide(0, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide();
+ }
+ }
+ };
+
+
+
+ /**
+ * Class: Grid
+ *
+ * Object representing the grid on which the plot is drawn. The grid in this
+ * context is the area bounded by the axes, the area which will contain the series.
+ * Note, the series are drawn on their own canvas.
+ * The Grid object cannot be instantiated directly, but is created by the Plot oject.
+ * Grid properties can be set or overriden by the options passed in from the user.
+ */
+ function Grid() {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: drawGridlines
+ // wether to draw the gridlines on the plot.
+ this.drawGridlines = true;
+ // prop: gridLineColor
+ // color of the grid lines.
+ this.gridLineColor = '#cccccc';
+ // prop: gridLineWidth
+ // width of the grid lines.
+ this.gridLineWidth = 1.0;
+ // prop: background
+ // css spec for the background color.
+ this.background = '#fffdf6';
+ // prop: borderColor
+ // css spec for the color of the grid border.
+ this.borderColor = '#999999';
+ // prop: borderWidth
+ // width of the border in pixels.
+ this.borderWidth = 2.0;
+ // prop: drawBorder
+ // True to draw border around grid.
+ this.drawBorder = true;
+ // prop: shadow
+ // wether to show a shadow behind the grid.
+ this.shadow = true;
+ // prop: shadowAngle
+ // shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Offset of each shadow stroke from the border in pixels
+ this.shadowOffset = 1.5;
+ // prop: shadowWidth
+ // width of the stoke for the shadow
+ this.shadowWidth = 3;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowColor
+ // an optional css color spec for the shadow in 'rgba(n, n, n, n)' form
+ this.shadowColor = null;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.07';
+ this._left;
+ this._top;
+ this._right;
+ this._bottom;
+ this._width;
+ this._height;
+ this._axes = [];
+ // prop: renderer
+ // Instance of a renderer which will actually render the grid,
+ // see <$.jqplot.CanvasGridRenderer>.
+ this.renderer = $.jqplot.CanvasGridRenderer;
+ // prop: rendererOptions
+ // Options to pass on to the renderer,
+ // see <$.jqplot.CanvasGridRenderer>.
+ this.rendererOptions = {};
+ this._offsets = {top:null, bottom:null, left:null, right:null};
+ }
+
+ Grid.prototype = new $.jqplot.ElemContainer();
+ Grid.prototype.constructor = Grid;
+
+ Grid.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Grid.prototype.createElement = function(offsets,plot) {
+ this._offsets = offsets;
+ return this.renderer.createElement.call(this, plot);
+ };
+
+ Grid.prototype.draw = function() {
+ this.renderer.draw.call(this);
+ };
+
+ $.jqplot.GenericCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas;
+
+ $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions, plot) {
+ this._offsets = offsets;
+ var klass = 'jqplot';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+
+ elem = plot.canvasManager.getCanvas();
+
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != null) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right;
+ elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom;
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.GenericCanvas.prototype.setContext = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ return this._ctx;
+ };
+
+ // Memory Leaks patch
+ $.jqplot.GenericCanvas.prototype.resetCanvas = function() {
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ //this._elem.remove();
+ this._elem.emptyForce();
+ }
+
+ this._ctx = null;
+ };
+
+ $.jqplot.HooksManager = function () {
+ this.hooks =[];
+ this.args = [];
+ };
+
+ $.jqplot.HooksManager.prototype.addOnce = function(fn, args) {
+ args = args || [];
+ var havehook = false;
+ for (var i=0, l=this.hooks.length; i<l; i++) {
+ if (this.hooks[i] == fn) {
+ havehook = true;
+ }
+ }
+ if (!havehook) {
+ this.hooks.push(fn);
+ this.args.push(args);
+ }
+ };
+
+ $.jqplot.HooksManager.prototype.add = function(fn, args) {
+ args = args || [];
+ this.hooks.push(fn);
+ this.args.push(args);
+ };
+
+ $.jqplot.EventListenerManager = function () {
+ this.hooks =[];
+ };
+
+ $.jqplot.EventListenerManager.prototype.addOnce = function(ev, fn) {
+ var havehook = false, h, i;
+ for (var i=0, l=this.hooks.length; i<l; i++) {
+ h = this.hooks[i];
+ if (h[0] == ev && h[1] == fn) {
+ havehook = true;
+ }
+ }
+ if (!havehook) {
+ this.hooks.push([ev, fn]);
+ }
+ };
+
+ $.jqplot.EventListenerManager.prototype.add = function(ev, fn) {
+ this.hooks.push([ev, fn]);
+ };
+
+
+ var _axisNames = ['yMidAxis', 'xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
+
+ /**
+ * Class: jqPlot
+ * Plot object returned by call to $.jqplot. Handles parsing user options,
+ * creating sub objects (Axes, legend, title, series) and rendering the plot.
+ */
+ function jqPlot() {
+ // Group: Properties
+ // These properties are specified at the top of the options object
+ // like so:
+ // > {
+ // > axesDefaults:{min:0},
+ // > series:[{color:'#6633dd'}],
+ // > title: 'A Plot'
+ // > }
+ //
+
+ // prop: animate
+ // True to animate the series on initial plot draw (renderer dependent).
+ // Actual animation functionality must be supported in the renderer.
+ this.animate = false;
+ // prop: animateReplot
+ // True to animate series after a call to the replot() method.
+ // Use with caution! Replots can happen very frequently under
+ // certain circumstances (e.g. resizing, dragging points) and
+ // animation in these situations can cause problems.
+ this.animateReplot = false;
+ // prop: axes
+ // up to 4 axes are supported, each with it's own options,
+ // See <Axis> for axis specific options.
+ this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis'), yMidAxis: new Axis('yMidAxis')};
+ this.baseCanvas = new $.jqplot.GenericCanvas();
+ // true to intercept right click events and fire a 'jqplotRightClick' event.
+ // this will also block the context menu.
+ this.captureRightClick = false;
+ // prop: data
+ // user's data. Data should *NOT* be specified in the options object,
+ // but be passed in as the second argument to the $.jqplot() function.
+ // The data property is described here soley for reference.
+ // The data should be in the form of an array of 2D or 1D arrays like
+ // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ].
+ this.data = [];
+ // prop: dataRenderer
+ // A callable which can be used to preprocess data passed into the plot.
+ // Will be called with 2 arguments, the plot data and a reference to the plot.
+ this.dataRenderer;
+ // prop: dataRendererOptions
+ // Options that will be passed to the dataRenderer.
+ // Can be of any type.
+ this.dataRendererOptions;
+ this.defaults = {
+ // prop: axesDefaults
+ // default options that will be applied to all axes.
+ // see <Axis> for axes options.
+ axesDefaults: {},
+ axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}, yMidAxis:{}},
+ // prop: seriesDefaults
+ // default options that will be applied to all series.
+ // see <Series> for series options.
+ seriesDefaults: {},
+ series:[]
+ };
+ // prop: defaultAxisStart
+ // 1-D data series are internally converted into 2-D [x,y] data point arrays
+ // by jqPlot. This is the default starting value for the missing x or y value.
+ // The added data will be a monotonically increasing series (e.g. [1, 2, 3, ...])
+ // starting at this value.
+ this.defaultAxisStart = 1;
+ // this.doCustomEventBinding = true;
+ // prop: drawIfHidden
+ // True to execute the draw method even if the plot target is hidden.
+ // Generally, this should be false. Most plot elements will not be sized/
+ // positioned correclty if renderered into a hidden container. To render into
+ // a hidden container, call the replot method when the container is shown.
+ this.drawIfHidden = false;
+ this.eventCanvas = new $.jqplot.GenericCanvas();
+ // prop: fillBetween
+ // Fill between 2 line series in a plot.
+ // Options object:
+ // {
+ // series1: first index (0 based) of series in fill
+ // series2: second index (0 based) of series in fill
+ // color: color of fill [default fillColor of series1]
+ // baseSeries: fill will be drawn below this series (0 based index)
+ // fill: false to turn off fill [default true].
+ // }
+ this.fillBetween = {
+ series1: null,
+ series2: null,
+ color: null,
+ baseSeries: 0,
+ fill: true
+ };
+ // prop; fontFamily
+ // css spec for the font-family attribute. Default for the entire plot.
+ this.fontFamily;
+ // prop: fontSize
+ // css spec for the font-size attribute. Default for the entire plot.
+ this.fontSize;
+ // prop: grid
+ // See <Grid> for grid specific options.
+ this.grid = new Grid();
+ // prop: legend
+ // see <$.jqplot.TableLegendRenderer>
+ this.legend = new Legend();
+ // prop: noDataIndicator
+ // Options to set up a mock plot with a data loading indicator if no data is specified.
+ this.negativeSeriesColors = $.jqplot.config.defaultNegativeColors;
+ this.noDataIndicator = {
+ show: false,
+ indicator: 'Loading Data...',
+ axes: {
+ xaxis: {
+ min: 0,
+ max: 10,
+ tickInterval: 2,
+ show: true
+ },
+ yaxis: {
+ min: 0,
+ max: 12,
+ tickInterval: 3,
+ show: true
+ }
+ }
+ };
+ // container to hold all of the merged options. Convienence for plugins.
+ this.options = {};
+ this.previousSeriesStack = [];
+ // Namespece to hold plugins. Generally non-renderer plugins add themselves to here.
+ this.plugins = {};
+ // prop: series
+ // Array of series object options.
+ // see <Series> for series specific options.
+ this.series = [];
+ // array of series indicies. Keep track of order
+ // which series canvases are displayed, lowest
+ // to highest, back to front.
+ this.seriesStack = [];
+ // prop: seriesColors
+ // Ann array of CSS color specifications that will be applied, in order,
+ // to the series in the plot. Colors will wrap around so, if their
+ // are more series than colors, colors will be reused starting at the
+ // beginning. For pie charts, this specifies the colors of the slices.
+ this.seriesColors = $.jqplot.config.defaultColors;
+ // prop: sortData
+ // false to not sort the data passed in by the user.
+ // Many bar, stakced and other graphs as well as many plugins depend on
+ // having sorted data.
+ this.sortData = true;
+ // prop: stackSeries
+ // true or false, creates a stack or "mountain" plot.
+ // Not all series renderers may implement this option.
+ this.stackSeries = false;
+ // a shortcut for axis syncTicks options. Not implemented yet.
+ this.syncXTicks = true;
+ // a shortcut for axis syncTicks options. Not implemented yet.
+ this.syncYTicks = true;
+ // the jquery object for the dom target.
+ this.target = null;
+ // The id of the dom element to render the plot into
+ this.targetId = null;
+ // prop textColor
+ // css spec for the css color attribute. Default for the entire plot.
+ this.textColor;
+ // prop: title
+ // Title object. See <Title> for specific options. As a shortcut, you
+ // can specify the title option as just a string like: title: 'My Plot'
+ // and this will create a new title object with the specified text.
+ this.title = new Title();
+ // Count how many times the draw method has been called while the plot is visible.
+ // Mostly used to test if plot has never been dran (=0), has been successfully drawn
+ // into a visible container once (=1) or draw more than once into a visible container.
+ // Can use this in tests to see if plot has been visibly drawn at least one time.
+ // After plot has been visibly drawn once, it generally doesn't need redrawn if its
+ // container is hidden and shown.
+ this._drawCount = 0;
+ // sum of y values for all series in plot.
+ // used in mekko chart.
+ this._sumy = 0;
+ this._sumx = 0;
+ // array to hold the cumulative stacked series data.
+ // used to ajust the individual series data, which won't have access to other
+ // series data.
+ this._stackData = [];
+ // array that holds the data to be plotted. This will be the series data
+ // merged with the the appropriate data from _stackData according to the stackAxis.
+ this._plotData = [];
+ this._width = null;
+ this._height = null;
+ this._plotDimensions = {height:null, width:null};
+ this._gridPadding = {top:null, right:null, bottom:null, left:null};
+ this._defaultGridPadding = {top:10, right:10, bottom:23, left:10};
+
+ this._addDomReference = $.jqplot.config.addDomReference;
+
+ this.preInitHooks = new $.jqplot.HooksManager();
+ this.postInitHooks = new $.jqplot.HooksManager();
+ this.preParseOptionsHooks = new $.jqplot.HooksManager();
+ this.postParseOptionsHooks = new $.jqplot.HooksManager();
+ this.preDrawHooks = new $.jqplot.HooksManager();
+ this.postDrawHooks = new $.jqplot.HooksManager();
+ this.preDrawSeriesHooks = new $.jqplot.HooksManager();
+ this.postDrawSeriesHooks = new $.jqplot.HooksManager();
+ this.preDrawLegendHooks = new $.jqplot.HooksManager();
+ this.addLegendRowHooks = new $.jqplot.HooksManager();
+ this.preSeriesInitHooks = new $.jqplot.HooksManager();
+ this.postSeriesInitHooks = new $.jqplot.HooksManager();
+ this.preParseSeriesOptionsHooks = new $.jqplot.HooksManager();
+ this.postParseSeriesOptionsHooks = new $.jqplot.HooksManager();
+ this.eventListenerHooks = new $.jqplot.EventListenerManager();
+ this.preDrawSeriesShadowHooks = new $.jqplot.HooksManager();
+ this.postDrawSeriesShadowHooks = new $.jqplot.HooksManager();
+
+ this.colorGenerator = new $.jqplot.ColorGenerator();
+ this.negativeColorGenerator = new $.jqplot.ColorGenerator();
+
+ this.canvasManager = new $.jqplot.CanvasManager();
+
+ this.themeEngine = new $.jqplot.ThemeEngine();
+
+ var seriesColorsIndex = 0;
+
+ // Group: methods
+ //
+ // method: init
+ // sets the plot target, checks data and applies user
+ // options to plot.
+ this.init = function(target, data, options) {
+ options = options || {};
+ for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
+ $.jqplot.preInitHooks[i].call(this, target, data, options);
+ }
+
+ for (var i=0; i<this.preInitHooks.hooks.length; i++) {
+ this.preInitHooks.hooks[i].call(this, target, data, options);
+ }
+
+ this.targetId = '#'+target;
+ this.target = $('#'+target);
+
+ //////
+ // Add a reference to plot
+ //////
+ if (this._addDomReference) {
+ this.target.data('jqplot', this);
+ }
+ // remove any error class that may be stuck on target.
+ this.target.removeClass('jqplot-error');
+ if (!this.target.get(0)) {
+ throw "No plot target specified";
+ }
+
+ // make sure the target is positioned by some means and set css
+ if (this.target.css('position') == 'static') {
+ this.target.css('position', 'relative');
+ }
+ if (!this.target.hasClass('jqplot-target')) {
+ this.target.addClass('jqplot-target');
+ }
+
+ // if no height or width specified, use a default.
+ if (!this.target.height()) {
+ var h;
+ if (options && options.height) {
+ h = parseInt(options.height, 10);
+ }
+ else if (this.target.attr('data-height')) {
+ h = parseInt(this.target.attr('data-height'), 10);
+ }
+ else {
+ h = parseInt($.jqplot.config.defaultHeight, 10);
+ }
+ this._height = h;
+ this.target.css('height', h+'px');
+ }
+ else {
+ this._height = h = this.target.height();
+ }
+ if (!this.target.width()) {
+ var w;
+ if (options && options.width) {
+ w = parseInt(options.width, 10);
+ }
+ else if (this.target.attr('data-width')) {
+ w = parseInt(this.target.attr('data-width'), 10);
+ }
+ else {
+ w = parseInt($.jqplot.config.defaultWidth, 10);
+ }
+ this._width = w;
+ this.target.css('width', w+'px');
+ }
+ else {
+ this._width = w = this.target.width();
+ }
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ this.axes[_axisNames[i]] = new Axis(_axisNames[i]);
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Canvas dimension not set";
+ }
+
+ if (options.dataRenderer && $.isFunction(options.dataRenderer)) {
+ if (options.dataRendererOptions) {
+ this.dataRendererOptions = options.dataRendererOptions;
+ }
+ this.dataRenderer = options.dataRenderer;
+ data = this.dataRenderer(data, this, this.dataRendererOptions);
+ }
+
+ if (options.noDataIndicator && $.isPlainObject(options.noDataIndicator)) {
+ $.extend(true, this.noDataIndicator, options.noDataIndicator);
+ }
+
+ if (data == null || $.isArray(data) == false || data.length == 0 || $.isArray(data[0]) == false || data[0].length == 0) {
+
+ if (this.noDataIndicator.show == false) {
+ throw "No Data";
+ }
+
+ else {
+ // have to be descructive here in order for plot to not try and render series.
+ // This means that $.jqplot() will have to be called again when there is data.
+ //delete options.series;
+
+ for (var ax in this.noDataIndicator.axes) {
+ for (var prop in this.noDataIndicator.axes[ax]) {
+ this.axes[ax][prop] = this.noDataIndicator.axes[ax][prop];
+ }
+ }
+
+ this.postDrawHooks.add(function() {
+ var eh = this.eventCanvas.getHeight();
+ var ew = this.eventCanvas.getWidth();
+ var temp = $('<div class="jqplot-noData-container" style="position:absolute;"></div>');
+ this.target.append(temp);
+ temp.height(eh);
+ temp.width(ew);
+ temp.css('top', this.eventCanvas._offsets.top);
+ temp.css('left', this.eventCanvas._offsets.left);
+
+ var temp2 = $('<div class="jqplot-noData-contents" style="text-align:center; position:relative; margin-left:auto; margin-right:auto;"></div>');
+ temp.append(temp2);
+ temp2.html(this.noDataIndicator.indicator);
+ var th = temp2.height();
+ var tw = temp2.width();
+ temp2.height(th);
+ temp2.width(tw);
+ temp2.css('top', (eh - th)/2 + 'px');
+ });
+
+ }
+ }
+
+ // make a copy of the data
+ this.data = $.extend(true, [], data);
+
+ this.parseOptions(options);
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this.title.init();
+ this.legend.init();
+ this._sumy = 0;
+ this._sumx = 0;
+ this.computePlotData();
+ for (var i=0; i<this.series.length; i++) {
+ // set default stacking order for series canvases
+ this.seriesStack.push(i);
+ this.previousSeriesStack.push(i);
+ this.series[i].shadowCanvas._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
+ $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) {
+ this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ // this.populatePlotData(this.series[i], i);
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].init(i, this.grid.borderWidth, this);
+ for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
+ $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) {
+ this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ var name,
+ axis;
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+ axis._plotDimensions = this._plotDimensions;
+ axis.init();
+ if (this.axes[name].borderColor == null) {
+ if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) {
+ axis.borderColor = axis._series[0].color;
+ }
+ else {
+ axis.borderColor = this.grid.borderColor;
+ }
+ }
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+ this.grid.init();
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+
+ for (var i=0; i<$.jqplot.postInitHooks.length; i++) {
+ $.jqplot.postInitHooks[i].call(this, target, this.data, options);
+ }
+
+ for (var i=0; i<this.postInitHooks.hooks.length; i++) {
+ this.postInitHooks.hooks[i].call(this, target, this.data, options);
+ }
+ };
+
+ // method: resetAxesScale
+ // Reset the specified axes min, max, numberTicks and tickInterval properties to null
+ // or reset these properties on all axes if no list of axes is provided.
+ //
+ // Parameters:
+ // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset.
+ this.resetAxesScale = function(axes, options) {
+ var opts = options || {};
+ var ax = axes || this.axes;
+ if (ax === true) {
+ ax = this.axes;
+ }
+ if ($.isArray(ax)) {
+ for (var i = 0; i < ax.length; i++) {
+ this.axes[ax[i]].resetScale(opts[ax[i]]);
+ }
+ }
+ else if (typeof(ax) === 'object') {
+ for (var name in ax) {
+ this.axes[name].resetScale(opts[name]);
+ }
+ }
+ };
+ // method: reInitialize
+ // reinitialize plot for replotting.
+ // not called directly.
+ this.reInitialize = function (data, opts) {
+ // Plot should be visible and have a height and width.
+ // If plot doesn't have height and width for some
+ // reason, set it by other means. Plot must not have
+ // a display:none attribute, however.
+
+ var options = $.extend(true, {}, this.options, opts);
+
+ var target = this.targetId.substr(1);
+ var tdata = (data == null) ? this.data : data;
+
+ for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
+ $.jqplot.preInitHooks[i].call(this, target, tdata, options);
+ }
+
+ for (var i=0; i<this.preInitHooks.hooks.length; i++) {
+ this.preInitHooks.hooks[i].call(this, target, tdata, options);
+ }
+
+ this._height = this.target.height();
+ this._width = this.target.width();
+
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Target dimension not set";
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+
+ var name,
+ t,
+ j,
+ axis;
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+
+ // Memory Leaks patch : clear ticks elements
+ t = axis._ticks;
+ for (var j = 0, tlen = t.length; j < tlen; j++) {
+ var el = t[j]._elem;
+ if (el) {
+ // if canvas renderer
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(el.get(0));
+ }
+ el.emptyForce();
+ el = null;
+ t._elem = null;
+ }
+ }
+ t = null;
+
+ delete axis.ticks;
+ delete axis._ticks;
+ this.axes[name] = new Axis(name);
+ this.axes[name]._plotWidth = this._width;
+ this.axes[name]._plotHeight = this._height;
+ }
+
+ if (data) {
+ if (options.dataRenderer && $.isFunction(options.dataRenderer)) {
+ if (options.dataRendererOptions) {
+ this.dataRendererOptions = options.dataRendererOptions;
+ }
+ this.dataRenderer = options.dataRenderer;
+ data = this.dataRenderer(data, this, this.dataRendererOptions);
+ }
+
+ // make a copy of the data
+ this.data = $.extend(true, [], data);
+ }
+
+ if (opts) {
+ this.parseOptions(options);
+ }
+
+ this.title._plotWidth = this._width;
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this.title.init();
+ this.legend.init();
+ this._sumy = 0;
+ this._sumx = 0;
+
+ this.seriesStack = [];
+ this.previousSeriesStack = [];
+
+ this.computePlotData();
+ for (var i=0, l=this.series.length; i<l; i++) {
+ // set default stacking order for series canvases
+ this.seriesStack.push(i);
+ this.previousSeriesStack.push(i);
+ this.series[i].shadowCanvas._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
+ $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) {
+ this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ // this.populatePlotData(this.series[i], i);
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].init(i, this.grid.borderWidth, this);
+ for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
+ $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) {
+ this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+
+ axis._plotDimensions = this._plotDimensions;
+ axis.init();
+ if (axis.borderColor == null) {
+ if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) {
+ axis.borderColor = axis._series[0].color;
+ }
+ else {
+ axis.borderColor = this.grid.borderColor;
+ }
+ }
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+ this.grid.init();
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+
+ for (var i=0, l=$.jqplot.postInitHooks.length; i<l; i++) {
+ $.jqplot.postInitHooks[i].call(this, target, this.data, options);
+ }
+
+ for (var i=0, l=this.postInitHooks.hooks.length; i<l; i++) {
+ this.postInitHooks.hooks[i].call(this, target, this.data, options);
+ }
+ };
+
+
+
+ // method: quickInit
+ //
+ // Quick reinitialization plot for replotting.
+ // Does not parse options ore recreate axes and series.
+ // not called directly.
+ this.quickInit = function () {
+ // Plot should be visible and have a height and width.
+ // If plot doesn't have height and width for some
+ // reason, set it by other means. Plot must not have
+ // a display:none attribute, however.
+
+ this._height = this.target.height();
+ this._width = this.target.width();
+
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Target dimension not set";
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+
+ for (var n in this.axes) {
+ this.axes[n]._plotWidth = this._width;
+ this.axes[n]._plotHeight = this._height;
+ }
+
+ this.title._plotWidth = this._width;
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this._sumy = 0;
+ this._sumx = 0;
+ this.computePlotData();
+ for (var i=0; i<this.series.length; i++) {
+ // this.populatePlotData(this.series[i], i);
+ if (this.series[i]._type === 'line' && this.series[i].renderer.bands.show) {
+ this.series[i].renderer.initBands.call(this.series[i], this.series[i].renderer.options, this);
+ }
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ //this.series[i].init(i, this.grid.borderWidth);
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ var name;
+
+ for (var j=0; j<12; j++) {
+ name = _axisNames[j];
+ // Memory Leaks patch : clear ticks elements
+ var t = this.axes[name]._ticks;
+ for (var i = 0; i < t.length; i++) {
+ var el = t[i]._elem;
+ if (el) {
+ // if canvas renderer
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(el.get(0));
+ }
+ el.emptyForce();
+ el = null;
+ t._elem = null;
+ }
+ }
+ t = null;
+
+ this.axes[name]._plotDimensions = this._plotDimensions;
+ this.axes[name]._ticks = [];
+ // this.axes[name].renderer.init.call(this.axes[name], {});
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+ };
+
+ // sort the series data in increasing order.
+ function sortData(series) {
+ var d, sd, pd, ppd, ret;
+ for (var i=0; i<series.length; i++) {
+ var check;
+ var bat = [series[i].data, series[i]._stackData, series[i]._plotData, series[i]._prevPlotData];
+ for (var n=0; n<4; n++) {
+ check = true;
+ d = bat[n];
+ if (series[i]._stackAxis == 'x') {
+ for (var j = 0; j < d.length; j++) {
+ if (typeof(d[j][1]) != "number") {
+ check = false;
+ break;
+ }
+ }
+ if (check) {
+ d.sort(function(a,b) { return a[1] - b[1]; });
+ }
+ }
+ else {
+ for (var j = 0; j < d.length; j++) {
+ if (typeof(d[j][0]) != "number") {
+ check = false;
+ break;
+ }
+ }
+ if (check) {
+ d.sort(function(a,b) { return a[0] - b[0]; });
+ }
+ }
+ }
+
+ }
+ }
+
+ this.computePlotData = function() {
+ this._plotData = [];
+ this._stackData = [];
+ var series,
+ index,
+ l;
+
+
+ for (index=0, l=this.series.length; index<l; index++) {
+ series = this.series[index];
+ this._plotData.push([]);
+ this._stackData.push([]);
+ var cd = series.data;
+ this._plotData[index] = $.extend(true, [], cd);
+ this._stackData[index] = $.extend(true, [], cd);
+ series._plotData = this._plotData[index];
+ series._stackData = this._stackData[index];
+ var plotValues = {x:[], y:[]};
+
+ if (this.stackSeries && !series.disableStack) {
+ series._stack = true;
+ ///////////////////////////
+ // have to check for nulls
+ ///////////////////////////
+ var sidx = (series._stackAxis === 'x') ? 0 : 1;
+
+ for (var k=0, cdl=cd.length; k<cdl; k++) {
+ var temp = cd[k][sidx];
+ if (temp == null) {
+ temp = 0;
+ }
+ this._plotData[index][k][sidx] = temp;
+ this._stackData[index][k][sidx] = temp;
+
+ if (index > 0) {
+ for (var j=index; j--;) {
+ var prevval = this._plotData[j][k][sidx];
+ // only need to sum up the stack axis column of data
+ // and only sum if it is of same sign.
+ // if previous series isn't same sign, keep looking
+ // at earlier series untill we find one of same sign.
+ if (temp * prevval >= 0) {
+ this._plotData[index][k][sidx] += prevval;
+ this._stackData[index][k][sidx] += prevval;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ else {
+ for (var i=0; i<series.data.length; i++) {
+ plotValues.x.push(series.data[i][0]);
+ plotValues.y.push(series.data[i][1]);
+ }
+ this._stackData.push(series.data);
+ this.series[index]._stackData = series.data;
+ this._plotData.push(series.data);
+ series._plotData = series.data;
+ series._plotValues = plotValues;
+ }
+ if (index>0) {
+ series._prevPlotData = this.series[index-1]._plotData;
+ }
+ series._sumy = 0;
+ series._sumx = 0;
+ for (i=series.data.length-1; i>-1; i--) {
+ series._sumy += series.data[i][1];
+ series._sumx += series.data[i][0];
+ }
+ }
+
+ };
+
+ // populate the _stackData and _plotData arrays for the plot and the series.
+ this.populatePlotData = function(series, index) {
+ // if a stacked chart, compute the stacked data
+ this._plotData = [];
+ this._stackData = [];
+ series._stackData = [];
+ series._plotData = [];
+ var plotValues = {x:[], y:[]};
+ if (this.stackSeries && !series.disableStack) {
+ series._stack = true;
+ var sidx = (series._stackAxis === 'x') ? 0 : 1;
+ // var idx = sidx ? 0 : 1;
+ // push the current data into stackData
+ //this._stackData.push(this.series[i].data);
+ var temp = $.extend(true, [], series.data);
+ // create the data that will be plotted for this series
+ var plotdata = $.extend(true, [], series.data);
+ var tempx, tempy, dval, stackval, comparator;
+ // for first series, nothing to add to stackData.
+ for (var j=0; j<index; j++) {
+ var cd = this.series[j].data;
+ for (var k=0; k<cd.length; k++) {
+ dval = cd[k];
+ tempx = (dval[0] != null) ? dval[0] : 0;
+ tempy = (dval[1] != null) ? dval[1] : 0;
+ temp[k][0] += tempx;
+ temp[k][1] += tempy;
+ stackval = (sidx) ? tempy : tempx;
+ // only need to sum up the stack axis column of data
+ // and only sum if it is of same sign.
+ if (series.data[k][sidx] * stackval >= 0) {
+ plotdata[k][sidx] += stackval;
+ }
+ }
+ }
+ for (var i=0; i<plotdata.length; i++) {
+ plotValues.x.push(plotdata[i][0]);
+ plotValues.y.push(plotdata[i][1]);
+ }
+ this._plotData.push(plotdata);
+ this._stackData.push(temp);
+ series._stackData = temp;
+ series._plotData = plotdata;
+ series._plotValues = plotValues;
+ }
+ else {
+ for (var i=0; i<series.data.length; i++) {
+ plotValues.x.push(series.data[i][0]);
+ plotValues.y.push(series.data[i][1]);
+ }
+ this._stackData.push(series.data);
+ this.series[index]._stackData = series.data;
+ this._plotData.push(series.data);
+ series._plotData = series.data;
+ series._plotValues = plotValues;
+ }
+ if (index>0) {
+ series._prevPlotData = this.series[index-1]._plotData;
+ }
+ series._sumy = 0;
+ series._sumx = 0;
+ for (i=series.data.length-1; i>-1; i--) {
+ series._sumy += series.data[i][1];
+ series._sumx += series.data[i][0];
+ }
+ };
+
+ // function to safely return colors from the color array and wrap around at the end.
+ this.getNextSeriesColor = (function(t) {
+ var idx = 0;
+ var sc = t.seriesColors;
+
+ return function () {
+ if (idx < sc.length) {
+ return sc[idx++];
+ }
+ else {
+ idx = 0;
+ return sc[idx++];
+ }
+ };
+ })(this);
+
+ this.parseOptions = function(options){
+ for (var i=0; i<this.preParseOptionsHooks.hooks.length; i++) {
+ this.preParseOptionsHooks.hooks[i].call(this, options);
+ }
+ for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) {
+ $.jqplot.preParseOptionsHooks[i].call(this, options);
+ }
+ this.options = $.extend(true, {}, this.defaults, options);
+ var opts = this.options;
+ this.animate = opts.animate;
+ this.animateReplot = opts.animateReplot;
+ this.stackSeries = opts.stackSeries;
+ if ($.isPlainObject(opts.fillBetween)) {
+
+ var temp = ['series1', 'series2', 'color', 'baseSeries', 'fill'],
+ tempi;
+
+ for (var i=0, l=temp.length; i<l; i++) {
+ tempi = temp[i];
+ if (opts.fillBetween[tempi] != null) {
+ this.fillBetween[tempi] = opts.fillBetween[tempi];
+ }
+ }
+ }
+
+ if (opts.seriesColors) {
+ this.seriesColors = opts.seriesColors;
+ }
+ if (opts.negativeSeriesColors) {
+ this.negativeSeriesColors = opts.negativeSeriesColors;
+ }
+ if (opts.captureRightClick) {
+ this.captureRightClick = opts.captureRightClick;
+ }
+ this.defaultAxisStart = (options && options.defaultAxisStart != null) ? options.defaultAxisStart : this.defaultAxisStart;
+ this.colorGenerator.setColors(this.seriesColors);
+ this.negativeColorGenerator.setColors(this.negativeSeriesColors);
+ // var cg = new this.colorGenerator(this.seriesColors);
+ // var ncg = new this.colorGenerator(this.negativeSeriesColors);
+ // this._gridPadding = this.options.gridPadding;
+ $.extend(true, this._gridPadding, opts.gridPadding);
+ this.sortData = (opts.sortData != null) ? opts.sortData : this.sortData;
+ for (var i=0; i<12; i++) {
+ var n = _axisNames[i];
+ var axis = this.axes[n];
+ axis._options = $.extend(true, {}, opts.axesDefaults, opts.axes[n]);
+ $.extend(true, axis, opts.axesDefaults, opts.axes[n]);
+ axis._plotWidth = this._width;
+ axis._plotHeight = this._height;
+ }
+ // if (this.data.length == 0) {
+ // this.data = [];
+ // for (var i=0; i<this.options.series.length; i++) {
+ // this.data.push(this.options.series.data);
+ // }
+ // }
+
+ var normalizeData = function(data, dir, start) {
+ // return data as an array of point arrays,
+ // in form [[x1,y1...], [x2,y2...], ...]
+ var temp = [];
+ var i, l;
+ dir = dir || 'vertical';
+ if (!$.isArray(data[0])) {
+ // we have a series of scalars. One line with just y values.
+ // turn the scalar list of data into a data array of form:
+ // [[1, data[0]], [2, data[1]], ...]
+ for (i=0, l=data.length; i<l; i++) {
+ if (dir == 'vertical') {
+ temp.push([start + i, data[i]]);
+ }
+ else {
+ temp.push([data[i], start+i]);
+ }
+ }
+ }
+ else {
+ // we have a properly formatted data series, copy it.
+ $.extend(true, temp, data);
+ }
+ return temp;
+ };
+
+ var colorIndex = 0;
+ this.series = [];
+ for (var i=0; i<this.data.length; i++) {
+ var sopts = $.extend(true, {index: i}, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i], {rendererOptions:{animation:{show: this.animate}}});
+ // pass in options in case something needs set prior to initialization.
+ var temp = new Series(sopts);
+ for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) {
+ $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
+ }
+ for (var j=0; j<this.preParseSeriesOptionsHooks.hooks.length; j++) {
+ this.preParseSeriesOptionsHooks.hooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
+ }
+ // Now go back and apply the options to the series. Really should just do this during initializaiton, but don't want to
+ // mess up preParseSeriesOptionsHooks at this point.
+ $.extend(true, temp, sopts);
+ var dir = 'vertical';
+ if (temp.renderer === $.jqplot.BarRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') {
+ dir = 'horizontal';
+ temp._stackAxis = 'x';
+ temp._primaryAxis = '_yaxis';
+ }
+ temp.data = normalizeData(this.data[i], dir, this.defaultAxisStart);
+ switch (temp.xaxis) {
+ case 'xaxis':
+ temp._xaxis = this.axes.xaxis;
+ break;
+ case 'x2axis':
+ temp._xaxis = this.axes.x2axis;
+ break;
+ default:
+ break;
+ }
+ temp._yaxis = this.axes[temp.yaxis];
+ temp._xaxis._series.push(temp);
+ temp._yaxis._series.push(temp);
+ if (temp.show) {
+ temp._xaxis.show = true;
+ temp._yaxis.show = true;
+ }
+ else {
+ if (temp._xaxis.scaleToHiddenSeries) {
+ temp._xaxis.show = true;
+ }
+ if (temp._yaxis.scaleToHiddenSeries) {
+ temp._yaxis.show = true;
+ }
+ }
+
+ // // parse the renderer options and apply default colors if not provided
+ // if (!temp.color && temp.show != false) {
+ // temp.color = cg.next();
+ // colorIndex = cg.getIndex() - 1;;
+ // }
+ // if (!temp.negativeColor && temp.show != false) {
+ // temp.negativeColor = ncg.get(colorIndex);
+ // ncg.setIndex(colorIndex);
+ // }
+ if (!temp.label) {
+ temp.label = 'Series '+ (i+1).toString();
+ }
+ // temp.rendererOptions.show = temp.show;
+ // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions);
+ this.series.push(temp);
+ for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) {
+ $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
+ }
+ for (var j=0; j<this.postParseSeriesOptionsHooks.hooks.length; j++) {
+ this.postParseSeriesOptionsHooks.hooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
+ }
+ }
+
+ // copy the grid and title options into this object.
+ $.extend(true, this.grid, this.options.grid);
+ // if axis border properties aren't set, set default.
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ var n = _axisNames[i];
+ var axis = this.axes[n];
+ if (axis.borderWidth == null) {
+ axis.borderWidth =this.grid.borderWidth;
+ }
+ }
+
+ if (typeof this.options.title == 'string') {
+ this.title.text = this.options.title;
+ }
+ else if (typeof this.options.title == 'object') {
+ $.extend(true, this.title, this.options.title);
+ }
+ this.title._plotWidth = this._width;
+ this.legend.setOptions(this.options.legend);
+
+ for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) {
+ $.jqplot.postParseOptionsHooks[i].call(this, options);
+ }
+ for (var i=0; i<this.postParseOptionsHooks.hooks.length; i++) {
+ this.postParseOptionsHooks.hooks[i].call(this, options);
+ }
+ };
+
+ // method: destroy
+ // Releases all resources occupied by the plot
+ this.destroy = function() {
+ this.canvasManager.freeAllCanvases();
+ if (this.eventCanvas && this.eventCanvas._elem) {
+ this.eventCanvas._elem.unbind();
+ }
+ // Couple of posts on Stack Overflow indicate that empty() doesn't
+ // always cear up the dom and release memory. Sometimes setting
+ // innerHTML property to null is needed. Particularly on IE, may
+ // have to directly set it to null, bypassing $.
+ this.target.empty();
+
+ this.target[0].innerHTML = '';
+ };
+
+ // method: replot
+ // Does a reinitialization of the plot followed by
+ // a redraw. Method could be used to interactively
+ // change plot characteristics and then replot.
+ //
+ // Parameters:
+ // options - Options used for replotting.
+ //
+ // Properties:
+ // clear - false to not clear (empty) the plot container before replotting (default: true).
+ // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves.
+ // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false).
+ this.replot = function(options) {
+ var opts = options || {};
+ var data = opts.data || null;
+ var clear = (opts.clear === false) ? false : true;
+ var resetAxes = opts.resetAxes || false;
+ delete opts.data;
+ delete opts.clear;
+ delete opts.resetAxes;
+
+ this.target.trigger('jqplotPreReplot');
+
+ if (clear) {
+ this.destroy();
+ }
+ // if have data or other options, full reinit.
+ // otherwise, quickinit.
+ if (data || !$.isEmptyObject(opts)) {
+ this.reInitialize(data, opts);
+ }
+ else {
+ this.quickInit();
+ }
+
+ if (resetAxes) {
+ this.resetAxesScale(resetAxes, opts.axes);
+ }
+ this.draw();
+ this.target.trigger('jqplotPostReplot');
+ };
+
+ // method: redraw
+ // Empties the plot target div and redraws the plot.
+ // This enables plot data and properties to be changed
+ // and then to comletely clear the plot and redraw.
+ // redraw *will not* reinitialize any plot elements.
+ // That is, axes will not be autoscaled and defaults
+ // will not be reapplied to any plot elements. redraw
+ // is used primarily with zooming.
+ //
+ // Parameters:
+ // clear - false to not clear (empty) the plot container before redrawing (default: true).
+ this.redraw = function(clear) {
+ clear = (clear != null) ? clear : true;
+ this.target.trigger('jqplotPreRedraw');
+ if (clear) {
+ this.canvasManager.freeAllCanvases();
+ this.eventCanvas._elem.unbind();
+ // Dont think I bind any events to the target, this shouldn't be necessary.
+ // It will remove user's events.
+ // this.target.unbind();
+ this.target.empty();
+ }
+ for (var ax in this.axes) {
+ this.axes[ax]._ticks = [];
+ }
+ this.computePlotData();
+ // for (var i=0; i<this.series.length; i++) {
+ // this.populatePlotData(this.series[i], i);
+ // }
+ this._sumy = 0;
+ this._sumx = 0;
+ for (var i=0, tsl = this.series.length; i<tsl; i++) {
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+ this.draw();
+ this.target.trigger('jqplotPostRedraw');
+ };
+
+ // method: draw
+ // Draws all elements of the plot into the container.
+ // Does not clear the container before drawing.
+ this.draw = function(){
+ if (this.drawIfHidden || this.target.is(':visible')) {
+ this.target.trigger('jqplotPreDraw');
+ var i,
+ j,
+ l,
+ tempseries;
+ for (i=0, l=$.jqplot.preDrawHooks.length; i<l; i++) {
+ $.jqplot.preDrawHooks[i].call(this);
+ }
+ for (i=0, l=this.preDrawHooks.length; i<l; i++) {
+ this.preDrawHooks.hooks[i].apply(this, this.preDrawSeriesHooks.args[i]);
+ }
+ // create an underlying canvas to be used for special features.
+ this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas', null, this));
+ this.baseCanvas.setContext();
+ this.target.append(this.title.draw());
+ this.title.pack({top:0, left:0});
+
+ // make room for the legend between the grid and the edge.
+ // pass a dummy offsets object and a reference to the plot.
+ var legendElem = this.legend.draw({}, this);
+
+ var gridPadding = {top:0, left:0, bottom:0, right:0};
+
+ if (this.legend.placement == "outsideGrid") {
+ // temporarily append the legend to get dimensions
+ this.target.append(legendElem);
+ switch (this.legend.location) {
+ case 'n':
+ gridPadding.top += this.legend.getHeight();
+ break;
+ case 's':
+ gridPadding.bottom += this.legend.getHeight();
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ gridPadding.right += this.legend.getWidth();
+ break;
+ case 'nw':
+ case 'w':
+ case 'sw':
+ gridPadding.left += this.legend.getWidth();
+ break;
+ default: // same as 'ne'
+ gridPadding.right += this.legend.getWidth();
+ break;
+ }
+ legendElem = legendElem.detach();
+ }
+
+ var ax = this.axes;
+ var name;
+ // draw the yMidAxis first, so xaxis of pyramid chart can adjust itself if needed.
+ for (i=0; i<12; i++) {
+ name = _axisNames[i];
+ this.target.append(ax[name].draw(this.baseCanvas._ctx, this));
+ ax[name].set();
+ }
+ if (ax.yaxis.show) {
+ gridPadding.left += ax.yaxis.getWidth();
+ }
+ var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
+ var rapad = [0, 0, 0, 0, 0, 0, 0, 0];
+ var gpr = 0;
+ var n;
+ for (n=0; n<8; n++) {
+ if (ax[ra[n]].show) {
+ gpr += ax[ra[n]].getWidth();
+ rapad[n] = gpr;
+ }
+ }
+ gridPadding.right += gpr;
+ if (ax.x2axis.show) {
+ gridPadding.top += ax.x2axis.getHeight();
+ }
+ if (this.title.show) {
+ gridPadding.top += this.title.getHeight();
+ }
+ if (ax.xaxis.show) {
+ gridPadding.bottom += ax.xaxis.getHeight();
+ }
+
+ // end of gridPadding adjustments.
+
+ // if user passed in gridDimensions option, check against calculated gridPadding
+ if (this.options.gridDimensions && $.isPlainObject(this.options.gridDimensions)) {
+ var gdw = parseInt(this.options.gridDimensions.width, 10) || 0;
+ var gdh = parseInt(this.options.gridDimensions.height, 10) || 0;
+ var widthAdj = (this._width - gridPadding.left - gridPadding.right - gdw)/2;
+ var heightAdj = (this._height - gridPadding.top - gridPadding.bottom - gdh)/2;
+
+ if (heightAdj >= 0 && widthAdj >= 0) {
+ gridPadding.top += heightAdj;
+ gridPadding.bottom += heightAdj;
+ gridPadding.left += widthAdj;
+ gridPadding.right += widthAdj;
+ }
+ }
+ var arr = ['top', 'bottom', 'left', 'right'];
+ for (var n in arr) {
+ if (this._gridPadding[arr[n]] == null && gridPadding[arr[n]] > 0) {
+ this._gridPadding[arr[n]] = gridPadding[arr[n]];
+ }
+ else if (this._gridPadding[arr[n]] == null) {
+ this._gridPadding[arr[n]] = this._defaultGridPadding[arr[n]];
+ }
+ }
+
+ var legendPadding = this._gridPadding;
+
+ if (this.legend.placement === 'outsideGrid') {
+ legendPadding = {top:this.title.getHeight(), left: 0, right: 0, bottom: 0};
+ if (this.legend.location === 's') {
+ legendPadding.left = this._gridPadding.left;
+ legendPadding.right = this._gridPadding.right;
+ }
+ }
+
+ ax.xaxis.pack({position:'absolute', bottom:this._gridPadding.bottom - ax.xaxis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
+ ax.yaxis.pack({position:'absolute', top:0, left:this._gridPadding.left - ax.yaxis.getWidth(), height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+ ax.x2axis.pack({position:'absolute', top:this._gridPadding.top - ax.x2axis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
+ for (i=8; i>0; i--) {
+ ax[ra[i-1]].pack({position:'absolute', top:0, right:this._gridPadding.right - rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+ }
+ var ltemp = (this._width - this._gridPadding.left - this._gridPadding.right)/2.0 + this._gridPadding.left - ax.yMidAxis.getWidth()/2.0;
+ ax.yMidAxis.pack({position:'absolute', top:0, left:ltemp, zIndex:9, textAlign: 'center'}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+
+ this.target.append(this.grid.createElement(this._gridPadding, this));
+ this.grid.draw();
+
+ var series = this.series;
+ var seriesLength = series.length;
+ // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars.
+ for (i=0, l=seriesLength; i<l; i++) {
+ // draw series in order of stacking. This affects only
+ // order in which canvases are added to dom.
+ j = this.seriesStack[i];
+ this.target.append(series[j].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-shadowCanvas', null, this));
+ series[j].shadowCanvas.setContext();
+ series[j].shadowCanvas._elem.data('seriesIndex', j);
+ }
+
+ for (i=0, l=seriesLength; i<l; i++) {
+ // draw series in order of stacking. This affects only
+ // order in which canvases are added to dom.
+ j = this.seriesStack[i];
+ this.target.append(series[j].canvas.createElement(this._gridPadding, 'jqplot-series-canvas', null, this));
+ series[j].canvas.setContext();
+ series[j].canvas._elem.data('seriesIndex', j);
+ }
+ // Need to use filled canvas to capture events in IE.
+ // Also, canvas seems to block selection of other elements in document on FF.
+ this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas', null, this));
+ this.eventCanvas.setContext();
+ this.eventCanvas._ctx.fillStyle = 'rgba(0,0,0,0)';
+ this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width, this.eventCanvas._ctx.canvas.height);
+
+ // bind custom event handlers to regular events.
+ this.bindCustomEvents();
+
+ // draw legend before series if the series needs to know the legend dimensions.
+ if (this.legend.preDraw) {
+ this.eventCanvas._elem.before(legendElem);
+ this.legend.pack(legendPadding);
+ if (this.legend._elem) {
+ this.drawSeries({legendInfo:{location:this.legend.location, placement:this.legend.placement, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}});
+ }
+ else {
+ this.drawSeries();
+ }
+ }
+ else { // draw series before legend
+ this.drawSeries();
+ if (seriesLength) {
+ $(series[seriesLength-1].canvas._elem).after(legendElem);
+ }
+ this.legend.pack(legendPadding);
+ }
+
+ // register event listeners on the overlay canvas
+ for (var i=0, l=$.jqplot.eventListenerHooks.length; i<l; i++) {
+ // in the handler, this will refer to the eventCanvas dom element.
+ // make sure there are references back into plot objects.
+ this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
+ }
+
+ // register event listeners on the overlay canvas
+ for (var i=0, l=this.eventListenerHooks.hooks.length; i<l; i++) {
+ // in the handler, this will refer to the eventCanvas dom element.
+ // make sure there are references back into plot objects.
+ this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[i][0], {plot:this}, this.eventListenerHooks.hooks[i][1]);
+ }
+
+ var fb = this.fillBetween;
+ if (fb.fill && fb.series1 !== fb.series2 && fb.series1 < seriesLength && fb.series2 < seriesLength && series[fb.series1]._type === 'line' && series[fb.series2]._type === 'line') {
+ this.doFillBetweenLines();
+ }
+
+ for (var i=0, l=$.jqplot.postDrawHooks.length; i<l; i++) {
+ $.jqplot.postDrawHooks[i].call(this);
+ }
+
+ for (var i=0, l=this.postDrawHooks.hooks.length; i<l; i++) {
+ this.postDrawHooks.hooks[i].apply(this, this.postDrawHooks.args[i]);
+ }
+
+ if (this.target.is(':visible')) {
+ this._drawCount += 1;
+ }
+
+ var temps,
+ tempr,
+ sel,
+ _els;
+ // ughh. ideally would hide all series then show them.
+ for (i=0, l=seriesLength; i<l; i++) {
+ temps = series[i];
+ tempr = temps.renderer;
+ sel = '.jqplot-point-label.jqplot-series-'+i;
+ if (tempr.animation && tempr.animation._supported && tempr.animation.show && (this._drawCount < 2 || this.animateReplot)) {
+ _els = this.target.find(sel);
+ _els.stop(true, true).hide();
+ temps.canvas._elem.stop(true, true).hide();
+ temps.shadowCanvas._elem.stop(true, true).hide();
+ temps.canvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed);
+ temps.shadowCanvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed);
+ _els.fadeIn(tempr.animation.speed*0.8);
+ }
+ }
+ _els = null;
+
+ this.target.trigger('jqplotPostDraw', [this]);
+ }
+ };
+
+ jqPlot.prototype.doFillBetweenLines = function () {
+ var fb = this.fillBetween;
+ var sid1 = fb.series1;
+ var sid2 = fb.series2;
+ // first series should always be lowest index
+ var id1 = (sid1 < sid2) ? sid1 : sid2;
+ var id2 = (sid2 > sid1) ? sid2 : sid1;
+
+ var series1 = this.series[id1];
+ var series2 = this.series[id2];
+
+ if (series2.renderer.smooth) {
+ var tempgd = series2.renderer._smoothedData.slice(0).reverse();
+ }
+ else {
+ var tempgd = series2.gridData.slice(0).reverse();
+ }
+
+ if (series1.renderer.smooth) {
+ var gd = series1.renderer._smoothedData.concat(tempgd);
+ }
+ else {
+ var gd = series1.gridData.concat(tempgd);
+ }
+
+ var color = (fb.color !== null) ? fb.color : this.series[sid1].fillColor;
+ var baseSeries = (fb.baseSeries !== null) ? fb.baseSeries : id1;
+
+ // now apply a fill to the shape on the lower series shadow canvas,
+ // so it is behind both series.
+ var sr = this.series[baseSeries].renderer.shapeRenderer;
+ var opts = {fillStyle: color, fill: true, closePath: true};
+ sr.draw(series1.shadowCanvas._ctx, gd, opts);
+ };
+
+ this.bindCustomEvents = function() {
+ this.eventCanvas._elem.bind('click', {plot:this}, this.onClick);
+ this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown);
+ this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove);
+ this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
+ if (this.captureRightClick) {
+ this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onRightClick);
+ this.eventCanvas._elem.get(0).oncontextmenu = function() {
+ return false;
+ };
+ }
+ else {
+ this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp);
+ }
+ };
+
+ function getEventPosition(ev) {
+ var plot = ev.data.plot;
+ var go = plot.eventCanvas._elem.offset();
+ var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
+ var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null};
+ var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ var ax = plot.axes;
+ var n, axis;
+ for (n=11; n>0; n--) {
+ axis = an[n-1];
+ if (ax[axis].show) {
+ dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
+ }
+ }
+
+ return {offsets:go, gridPos:gridPos, dataPos:dataPos};
+ }
+
+
+ // function to check if event location is over a area area
+ function checkIntersection(gridpos, plot) {
+ var series = plot.series;
+ var i, j, k, s, r, x, y, theta, sm, sa, minang, maxang;
+ var d0, d, p, pp, points, bw, hp;
+ var threshold, t;
+ for (k=plot.seriesStack.length-1; k>=0; k--) {
+ i = plot.seriesStack[k];
+ s = series[i];
+ hp = s._highlightThreshold;
+ switch (s.renderer.constructor) {
+ case $.jqplot.BarRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ for (j=0; j<s._barPoints.length; j++) {
+ points = s._barPoints[j];
+ p = s.gridData[j];
+ if (x>points[0][0] && x<points[2][0] && y>points[2][1] && y<points[0][1]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]};
+ }
+ }
+ break;
+ case $.jqplot.PyramidRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ for (j=0; j<s._barPoints.length; j++) {
+ points = s._barPoints[j];
+ p = s.gridData[j];
+ if (x > points[0][0] + hp[0][0] && x < points[2][0] + hp[2][0] && y > points[2][1] && y < points[0][1]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]};
+ }
+ }
+ break;
+
+ case $.jqplot.DonutRenderer:
+ sa = s.startAngle/180*Math.PI;
+ x = gridpos.x - s._center[0];
+ y = gridpos.y - s._center[1];
+ r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
+ if (x > 0 && -y >= 0) {
+ theta = 2*Math.PI - Math.atan(-y/x);
+ }
+ else if (x > 0 && -y < 0) {
+ theta = -Math.atan(-y/x);
+ }
+ else if (x < 0) {
+ theta = Math.PI - Math.atan(-y/x);
+ }
+ else if (x == 0 && -y > 0) {
+ theta = 3*Math.PI/2;
+ }
+ else if (x == 0 && -y < 0) {
+ theta = Math.PI/2;
+ }
+ else if (x == 0 && y == 0) {
+ theta = 0;
+ }
+ if (sa) {
+ theta -= sa;
+ if (theta < 0) {
+ theta += 2*Math.PI;
+ }
+ else if (theta > 2*Math.PI) {
+ theta -= 2*Math.PI;
+ }
+ }
+
+ sm = s.sliceMargin/180*Math.PI;
+ if (r < s._radius && r > s._innerRadius) {
+ for (j=0; j<s.gridData.length; j++) {
+ minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
+ maxang = s.gridData[j][1];
+ if (theta > minang && theta < maxang) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
+ }
+ }
+ }
+ break;
+
+ case $.jqplot.PieRenderer:
+ sa = s.startAngle/180*Math.PI;
+ x = gridpos.x - s._center[0];
+ y = gridpos.y - s._center[1];
+ r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
+ if (x > 0 && -y >= 0) {
+ theta = 2*Math.PI - Math.atan(-y/x);
+ }
+ else if (x > 0 && -y < 0) {
+ theta = -Math.atan(-y/x);
+ }
+ else if (x < 0) {
+ theta = Math.PI - Math.atan(-y/x);
+ }
+ else if (x == 0 && -y > 0) {
+ theta = 3*Math.PI/2;
+ }
+ else if (x == 0 && -y < 0) {
+ theta = Math.PI/2;
+ }
+ else if (x == 0 && y == 0) {
+ theta = 0;
+ }
+ if (sa) {
+ theta -= sa;
+ if (theta < 0) {
+ theta += 2*Math.PI;
+ }
+ else if (theta > 2*Math.PI) {
+ theta -= 2*Math.PI;
+ }
+ }
+
+ sm = s.sliceMargin/180*Math.PI;
+ if (r < s._radius) {
+ for (j=0; j<s.gridData.length; j++) {
+ minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
+ maxang = s.gridData[j][1];
+ if (theta > minang && theta < maxang) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
+ }
+ }
+ }
+ break;
+
+ case $.jqplot.BubbleRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ var ret = null;
+
+ if (s.show) {
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= p[2] && (d <= d0 || d0 == null)) {
+ d0 = d;
+ ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ if (ret != null) {
+ return ret;
+ }
+ }
+ break;
+
+ case $.jqplot.FunnelRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ var v = s._vertices,
+ vfirst = v[0],
+ vlast = v[v.length-1],
+ lex,
+ rex,
+ cv;
+
+ // equations of right and left sides, returns x, y values given height of section (y value and 2 points)
+
+ function findedge (l, p1 , p2) {
+ var m = (p1[1] - p2[1])/(p1[0] - p2[0]);
+ var b = p1[1] - m*p1[0];
+ var y = l + p1[1];
+
+ return [(y - b)/m, y];
+ }
+
+ // check each section
+ lex = findedge(y, vfirst[0], vlast[3]);
+ rex = findedge(y, vfirst[1], vlast[2]);
+ for (j=0; j<v.length; j++) {
+ cv = v[j];
+ if (y >= cv[0][1] && y <= cv[3][1] && x >= lex[0] && x <= rex[0]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:null, data:s.data[j]};
+ }
+ }
+ break;
+
+ case $.jqplot.LineRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ r = s.renderer;
+ if (s.show) {
+ if ((s.fill || (s.renderer.bands.show && s.renderer.bands.fill)) && (!plot.plugins.highlighter || !plot.plugins.highlighter.show)) {
+ // first check if it is in bounding box
+ var inside = false;
+ if (x>s._boundingBox[0][0] && x<s._boundingBox[1][0] && y>s._boundingBox[1][1] && y<s._boundingBox[0][1]) {
+ // now check the crossing number
+
+ var numPoints = s._areaPoints.length;
+ var ii;
+ var j = numPoints-1;
+
+ for(var ii=0; ii < numPoints; ii++) {
+ var vertex1 = [s._areaPoints[ii][0], s._areaPoints[ii][1]];
+ var vertex2 = [s._areaPoints[j][0], s._areaPoints[j][1]];
+
+ if (vertex1[1] < y && vertex2[1] >= y || vertex2[1] < y && vertex1[1] >= y) {
+ if (vertex1[0] + (y - vertex1[1]) / (vertex2[1] - vertex1[1]) * (vertex2[0] - vertex1[0]) < x) {
+ inside = !inside;
+ }
+ }
+
+ j = ii;
+ }
+ }
+ if (inside) {
+ return {seriesIndex:i, pointIndex:null, gridData:s.gridData, data:s.data, points:s._areaPoints};
+ }
+ break;
+
+ }
+
+ else {
+ t = s.markerRenderer.size/2+s.neighborThreshold;
+ threshold = (t > 0) ? t : 0;
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // neighbor looks different to OHLC chart.
+ if (r.constructor == $.jqplot.OHLCRenderer) {
+ if (r.candleStick) {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // if an open hi low close chart
+ else if (!r.hlc){
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // a hi low close chart
+ else {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+
+ }
+ else if (p[0] != null && p[1] != null){
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= threshold && (d <= d0 || d0 == null)) {
+ d0 = d;
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ x = gridpos.x;
+ y = gridpos.y;
+ r = s.renderer;
+ if (s.show) {
+ t = s.markerRenderer.size/2+s.neighborThreshold;
+ threshold = (t > 0) ? t : 0;
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // neighbor looks different to OHLC chart.
+ if (r.constructor == $.jqplot.OHLCRenderer) {
+ if (r.candleStick) {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // if an open hi low close chart
+ else if (!r.hlc){
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // a hi low close chart
+ else {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+
+ }
+ else {
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= threshold && (d <= d0 || d0 == null)) {
+ d0 = d;
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return null;
+ }
+
+
+
+ this.onClick = function(ev) {
+ // Event passed in is normalized and will have data attribute.
+ // Event passed out is unnormalized.
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onDblClick = function(ev) {
+ // Event passed in is normalized and will have data attribute.
+ // Event passed out is unnormalized.
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotDblClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseDown = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotMouseDown');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseUp = function(ev) {
+ var positions = getEventPosition(ev);
+ var evt = $.Event('jqplotMouseUp');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, ev.data.plot]);
+ };
+
+ this.onRightClick = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ if (p.captureRightClick) {
+ if (ev.which == 3) {
+ var evt = $.Event('jqplotRightClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ }
+ else {
+ var evt = $.Event('jqplotMouseUp');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ }
+ }
+ };
+
+ this.onMouseMove = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotMouseMove');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseEnter = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var evt = $.Event('jqplotMouseEnter');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ evt.relatedTarget = ev.relatedTarget;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
+ };
+
+ this.onMouseLeave = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var evt = $.Event('jqplotMouseLeave');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ evt.relatedTarget = ev.relatedTarget;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
+ };
+
+ // method: drawSeries
+ // Redraws all or just one series on the plot. No axis scaling
+ // is performed and no other elements on the plot are redrawn.
+ // options is an options object to pass on to the series renderers.
+ // It can be an empty object {}. idx is the series index
+ // to redraw if only one series is to be redrawn.
+ this.drawSeries = function(options, idx){
+ var i, series, ctx;
+ // if only one argument passed in and it is a number, use it ad idx.
+ idx = (typeof(options) === "number" && idx == null) ? options : idx;
+ options = (typeof(options) === "object") ? options : {};
+ // draw specified series
+ if (idx != undefined) {
+ series = this.series[idx];
+ ctx = series.shadowCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.drawShadow(ctx, options, this);
+ ctx = series.canvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.draw(ctx, options, this);
+ if (series.renderer.constructor == $.jqplot.BezierCurveRenderer) {
+ if (idx < this.series.length - 1) {
+ this.drawSeries(idx+1);
+ }
+ }
+ }
+
+ else {
+ // if call series drawShadow method first, in case all series shadows
+ // should be drawn before any series. This will ensure, like for
+ // stacked bar plots, that shadows don't overlap series.
+ for (i=0; i<this.series.length; i++) {
+ // first clear the canvas
+ series = this.series[i];
+ ctx = series.shadowCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.drawShadow(ctx, options, this);
+ ctx = series.canvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.draw(ctx, options, this);
+ }
+ }
+ options = idx = i = series = ctx = null;
+ };
+
+ // method: moveSeriesToFront
+ // This method requires jQuery 1.4+
+ // Moves the specified series canvas in front of all other series canvases.
+ // This effectively "draws" the specified series on top of all other series,
+ // although it is performed through DOM manipulation, no redrawing is performed.
+ //
+ // Parameters:
+ // idx - 0 based index of the series to move. This will be the index of the series
+ // as it was first passed into the jqplot function.
+ this.moveSeriesToFront = function (idx) {
+ idx = parseInt(idx, 10);
+ var stackIndex = $.inArray(idx, this.seriesStack);
+ // if already in front, return
+ if (stackIndex == -1) {
+ return;
+ }
+ if (stackIndex == this.seriesStack.length -1) {
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ return;
+ }
+ var opidx = this.seriesStack[this.seriesStack.length -1];
+ var serelem = this.series[idx].canvas._elem.detach();
+ var shadelem = this.series[idx].shadowCanvas._elem.detach();
+ this.series[opidx].shadowCanvas._elem.after(shadelem);
+ this.series[opidx].canvas._elem.after(serelem);
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack.splice(stackIndex, 1);
+ this.seriesStack.push(idx);
+ };
+
+ // method: moveSeriesToBack
+ // This method requires jQuery 1.4+
+ // Moves the specified series canvas behind all other series canvases.
+ //
+ // Parameters:
+ // idx - 0 based index of the series to move. This will be the index of the series
+ // as it was first passed into the jqplot function.
+ this.moveSeriesToBack = function (idx) {
+ idx = parseInt(idx, 10);
+ var stackIndex = $.inArray(idx, this.seriesStack);
+ // if already in back, return
+ if (stackIndex == 0 || stackIndex == -1) {
+ return;
+ }
+ var opidx = this.seriesStack[0];
+ var serelem = this.series[idx].canvas._elem.detach();
+ var shadelem = this.series[idx].shadowCanvas._elem.detach();
+ this.series[opidx].shadowCanvas._elem.before(shadelem);
+ this.series[opidx].canvas._elem.before(serelem);
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack.splice(stackIndex, 1);
+ this.seriesStack.unshift(idx);
+ };
+
+ // method: restorePreviousSeriesOrder
+ // This method requires jQuery 1.4+
+ // Restore the series canvas order to its previous state.
+ // Useful to put a series back where it belongs after moving
+ // it to the front.
+ this.restorePreviousSeriesOrder = function () {
+ var i, j, serelem, shadelem, temp, move, keep;
+ // if no change, return.
+ if (this.seriesStack == this.previousSeriesStack) {
+ return;
+ }
+ for (i=1; i<this.previousSeriesStack.length; i++) {
+ move = this.previousSeriesStack[i];
+ keep = this.previousSeriesStack[i-1];
+ serelem = this.series[move].canvas._elem.detach();
+ shadelem = this.series[move].shadowCanvas._elem.detach();
+ this.series[keep].shadowCanvas._elem.after(shadelem);
+ this.series[keep].canvas._elem.after(serelem);
+ }
+ temp = this.seriesStack.slice(0);
+ this.seriesStack = this.previousSeriesStack.slice(0);
+ this.previousSeriesStack = temp;
+ };
+
+ // method: restoreOriginalSeriesOrder
+ // This method requires jQuery 1.4+
+ // Restore the series canvas order to its original order
+ // when the plot was created.
+ this.restoreOriginalSeriesOrder = function () {
+ var i, j, arr=[], serelem, shadelem;
+ for (i=0; i<this.series.length; i++) {
+ arr.push(i);
+ }
+ if (this.seriesStack == arr) {
+ return;
+ }
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack = arr;
+ for (i=1; i<this.seriesStack.length; i++) {
+ serelem = this.series[i].canvas._elem.detach();
+ shadelem = this.series[i].shadowCanvas._elem.detach();
+ this.series[i-1].shadowCanvas._elem.after(shadelem);
+ this.series[i-1].canvas._elem.after(serelem);
+ }
+ };
+
+ this.activateTheme = function (name) {
+ this.themeEngine.activate(this, name);
+ };
+ }
+
+
+ // conpute a highlight color or array of highlight colors from given colors.
+ $.jqplot.computeHighlightColors = function(colors) {
+ var ret;
+ if ($.isArray(colors)) {
+ ret = [];
+ for (var i=0; i<colors.length; i++){
+ var rgba = $.jqplot.getColorComponents(colors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90;
+ newrgb[j] = parseInt(newrgb[j], 10);
+ (newrgb[j] > 255) ? 255 : newrgb[j];
+ }
+ // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5;
+ // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2;
+ newrgb[3] = 0.3 + 0.35 * rgba[3];
+ ret.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')');
+ }
+ }
+ else {
+ var rgba = $.jqplot.getColorComponents(colors);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ // newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ // newrgb[j] = parseInt(newrgb[j], 10);
+ newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90;
+ newrgb[j] = parseInt(newrgb[j], 10);
+ (newrgb[j] > 255) ? 255 : newrgb[j];
+ }
+ // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5;
+ // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2;
+ newrgb[3] = 0.3 + 0.35 * rgba[3];
+ ret = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')';
+ }
+ return ret;
+ };
+
+ $.jqplot.ColorGenerator = function(colors) {
+ colors = colors || $.jqplot.config.defaultColors;
+ var idx = 0;
+
+ this.next = function () {
+ if (idx < colors.length) {
+ return colors[idx++];
+ }
+ else {
+ idx = 0;
+ return colors[idx++];
+ }
+ };
+
+ this.previous = function () {
+ if (idx > 0) {
+ return colors[idx--];
+ }
+ else {
+ idx = colors.length-1;
+ return colors[idx];
+ }
+ };
+
+ // get a color by index without advancing pointer.
+ this.get = function(i) {
+ var idx = i - colors.length * Math.floor(i/colors.length);
+ return colors[idx];
+ };
+
+ this.setColors = function(c) {
+ colors = c;
+ };
+
+ this.reset = function() {
+ idx = 0;
+ };
+
+ this.getIndex = function() {
+ return idx;
+ };
+
+ this.setIndex = function(index) {
+ idx = index;
+ };
+ };
+
+ // convert a hex color string to rgb string.
+ // h - 3 or 6 character hex string, with or without leading #
+ // a - optional alpha
+ $.jqplot.hex2rgb = function(h, a) {
+ h = h.replace('#', '');
+ if (h.length == 3) {
+ h = h.charAt(0)+h.charAt(0)+h.charAt(1)+h.charAt(1)+h.charAt(2)+h.charAt(2);
+ }
+ var rgb;
+ rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16);
+ if (a) {
+ rgb += ', '+a;
+ }
+ rgb += ')';
+ return rgb;
+ };
+
+ // convert an rgb color spec to a hex spec. ignore any alpha specification.
+ $.jqplot.rgb2hex = function(s) {
+ var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;
+ var m = s.match(pat);
+ var h = '#';
+ for (var i=1; i<4; i++) {
+ var temp;
+ if (m[i].search(/%/) != -1) {
+ temp = parseInt(255*m[i]/100, 10).toString(16);
+ if (temp.length == 1) {
+ temp = '0'+temp;
+ }
+ }
+ else {
+ temp = parseInt(m[i], 10).toString(16);
+ if (temp.length == 1) {
+ temp = '0'+temp;
+ }
+ }
+ h += temp;
+ }
+ return h;
+ };
+
+ // given a css color spec, return an rgb css color spec
+ $.jqplot.normalize2rgb = function(s, a) {
+ if (s.search(/^ *rgba?\(/) != -1) {
+ return s;
+ }
+ else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) {
+ return $.jqplot.hex2rgb(s, a);
+ }
+ else {
+ throw 'invalid color spec';
+ }
+ };
+
+ // extract the r, g, b, a color components out of a css color spec.
+ $.jqplot.getColorComponents = function(s) {
+ // check to see if a color keyword.
+ s = $.jqplot.colorKeywordMap[s] || s;
+ var rgb = $.jqplot.normalize2rgb(s);
+ var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;
+ var m = rgb.match(pat);
+ var ret = [];
+ for (var i=1; i<4; i++) {
+ if (m[i].search(/%/) != -1) {
+ ret[i-1] = parseInt(255*m[i]/100, 10);
+ }
+ else {
+ ret[i-1] = parseInt(m[i], 10);
+ }
+ }
+ ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0;
+ return ret;
+ };
+
+ $.jqplot.colorKeywordMap = {
+ aliceblue: 'rgb(240, 248, 255)',
+ antiquewhite: 'rgb(250, 235, 215)',
+ aqua: 'rgb( 0, 255, 255)',
+ aquamarine: 'rgb(127, 255, 212)',
+ azure: 'rgb(240, 255, 255)',
+ beige: 'rgb(245, 245, 220)',
+ bisque: 'rgb(255, 228, 196)',
+ black: 'rgb( 0, 0, 0)',
+ blanchedalmond: 'rgb(255, 235, 205)',
+ blue: 'rgb( 0, 0, 255)',
+ blueviolet: 'rgb(138, 43, 226)',
+ brown: 'rgb(165, 42, 42)',
+ burlywood: 'rgb(222, 184, 135)',
+ cadetblue: 'rgb( 95, 158, 160)',
+ chartreuse: 'rgb(127, 255, 0)',
+ chocolate: 'rgb(210, 105, 30)',
+ coral: 'rgb(255, 127, 80)',
+ cornflowerblue: 'rgb(100, 149, 237)',
+ cornsilk: 'rgb(255, 248, 220)',
+ crimson: 'rgb(220, 20, 60)',
+ cyan: 'rgb( 0, 255, 255)',
+ darkblue: 'rgb( 0, 0, 139)',
+ darkcyan: 'rgb( 0, 139, 139)',
+ darkgoldenrod: 'rgb(184, 134, 11)',
+ darkgray: 'rgb(169, 169, 169)',
+ darkgreen: 'rgb( 0, 100, 0)',
+ darkgrey: 'rgb(169, 169, 169)',
+ darkkhaki: 'rgb(189, 183, 107)',
+ darkmagenta: 'rgb(139, 0, 139)',
+ darkolivegreen: 'rgb( 85, 107, 47)',
+ darkorange: 'rgb(255, 140, 0)',
+ darkorchid: 'rgb(153, 50, 204)',
+ darkred: 'rgb(139, 0, 0)',
+ darksalmon: 'rgb(233, 150, 122)',
+ darkseagreen: 'rgb(143, 188, 143)',
+ darkslateblue: 'rgb( 72, 61, 139)',
+ darkslategray: 'rgb( 47, 79, 79)',
+ darkslategrey: 'rgb( 47, 79, 79)',
+ darkturquoise: 'rgb( 0, 206, 209)',
+ darkviolet: 'rgb(148, 0, 211)',
+ deeppink: 'rgb(255, 20, 147)',
+ deepskyblue: 'rgb( 0, 191, 255)',
+ dimgray: 'rgb(105, 105, 105)',
+ dimgrey: 'rgb(105, 105, 105)',
+ dodgerblue: 'rgb( 30, 144, 255)',
+ firebrick: 'rgb(178, 34, 34)',
+ floralwhite: 'rgb(255, 250, 240)',
+ forestgreen: 'rgb( 34, 139, 34)',
+ fuchsia: 'rgb(255, 0, 255)',
+ gainsboro: 'rgb(220, 220, 220)',
+ ghostwhite: 'rgb(248, 248, 255)',
+ gold: 'rgb(255, 215, 0)',
+ goldenrod: 'rgb(218, 165, 32)',
+ gray: 'rgb(128, 128, 128)',
+ grey: 'rgb(128, 128, 128)',
+ green: 'rgb( 0, 128, 0)',
+ greenyellow: 'rgb(173, 255, 47)',
+ honeydew: 'rgb(240, 255, 240)',
+ hotpink: 'rgb(255, 105, 180)',
+ indianred: 'rgb(205, 92, 92)',
+ indigo: 'rgb( 75, 0, 130)',
+ ivory: 'rgb(255, 255, 240)',
+ khaki: 'rgb(240, 230, 140)',
+ lavender: 'rgb(230, 230, 250)',
+ lavenderblush: 'rgb(255, 240, 245)',
+ lawngreen: 'rgb(124, 252, 0)',
+ lemonchiffon: 'rgb(255, 250, 205)',
+ lightblue: 'rgb(173, 216, 230)',
+ lightcoral: 'rgb(240, 128, 128)',
+ lightcyan: 'rgb(224, 255, 255)',
+ lightgoldenrodyellow: 'rgb(250, 250, 210)',
+ lightgray: 'rgb(211, 211, 211)',
+ lightgreen: 'rgb(144, 238, 144)',
+ lightgrey: 'rgb(211, 211, 211)',
+ lightpink: 'rgb(255, 182, 193)',
+ lightsalmon: 'rgb(255, 160, 122)',
+ lightseagreen: 'rgb( 32, 178, 170)',
+ lightskyblue: 'rgb(135, 206, 250)',
+ lightslategray: 'rgb(119, 136, 153)',
+ lightslategrey: 'rgb(119, 136, 153)',
+ lightsteelblue: 'rgb(176, 196, 222)',
+ lightyellow: 'rgb(255, 255, 224)',
+ lime: 'rgb( 0, 255, 0)',
+ limegreen: 'rgb( 50, 205, 50)',
+ linen: 'rgb(250, 240, 230)',
+ magenta: 'rgb(255, 0, 255)',
+ maroon: 'rgb(128, 0, 0)',
+ mediumaquamarine: 'rgb(102, 205, 170)',
+ mediumblue: 'rgb( 0, 0, 205)',
+ mediumorchid: 'rgb(186, 85, 211)',
+ mediumpurple: 'rgb(147, 112, 219)',
+ mediumseagreen: 'rgb( 60, 179, 113)',
+ mediumslateblue: 'rgb(123, 104, 238)',
+ mediumspringgreen: 'rgb( 0, 250, 154)',
+ mediumturquoise: 'rgb( 72, 209, 204)',
+ mediumvioletred: 'rgb(199, 21, 133)',
+ midnightblue: 'rgb( 25, 25, 112)',
+ mintcream: 'rgb(245, 255, 250)',
+ mistyrose: 'rgb(255, 228, 225)',
+ moccasin: 'rgb(255, 228, 181)',
+ navajowhite: 'rgb(255, 222, 173)',
+ navy: 'rgb( 0, 0, 128)',
+ oldlace: 'rgb(253, 245, 230)',
+ olive: 'rgb(128, 128, 0)',
+ olivedrab: 'rgb(107, 142, 35)',
+ orange: 'rgb(255, 165, 0)',
+ orangered: 'rgb(255, 69, 0)',
+ orchid: 'rgb(218, 112, 214)',
+ palegoldenrod: 'rgb(238, 232, 170)',
+ palegreen: 'rgb(152, 251, 152)',
+ paleturquoise: 'rgb(175, 238, 238)',
+ palevioletred: 'rgb(219, 112, 147)',
+ papayawhip: 'rgb(255, 239, 213)',
+ peachpuff: 'rgb(255, 218, 185)',
+ peru: 'rgb(205, 133, 63)',
+ pink: 'rgb(255, 192, 203)',
+ plum: 'rgb(221, 160, 221)',
+ powderblue: 'rgb(176, 224, 230)',
+ purple: 'rgb(128, 0, 128)',
+ red: 'rgb(255, 0, 0)',
+ rosybrown: 'rgb(188, 143, 143)',
+ royalblue: 'rgb( 65, 105, 225)',
+ saddlebrown: 'rgb(139, 69, 19)',
+ salmon: 'rgb(250, 128, 114)',
+ sandybrown: 'rgb(244, 164, 96)',
+ seagreen: 'rgb( 46, 139, 87)',
+ seashell: 'rgb(255, 245, 238)',
+ sienna: 'rgb(160, 82, 45)',
+ silver: 'rgb(192, 192, 192)',
+ skyblue: 'rgb(135, 206, 235)',
+ slateblue: 'rgb(106, 90, 205)',
+ slategray: 'rgb(112, 128, 144)',
+ slategrey: 'rgb(112, 128, 144)',
+ snow: 'rgb(255, 250, 250)',
+ springgreen: 'rgb( 0, 255, 127)',
+ steelblue: 'rgb( 70, 130, 180)',
+ tan: 'rgb(210, 180, 140)',
+ teal: 'rgb( 0, 128, 128)',
+ thistle: 'rgb(216, 191, 216)',
+ tomato: 'rgb(255, 99, 71)',
+ turquoise: 'rgb( 64, 224, 208)',
+ violet: 'rgb(238, 130, 238)',
+ wheat: 'rgb(245, 222, 179)',
+ white: 'rgb(255, 255, 255)',
+ whitesmoke: 'rgb(245, 245, 245)',
+ yellow: 'rgb(255, 255, 0)',
+ yellowgreen: 'rgb(154, 205, 50)'
+ };
+
+
+
+ // class: $.jqplot.AxisLabelRenderer
+ // Renderer to place labels on the axes.
+ $.jqplot.AxisLabelRenderer = function(options) {
+ // Group: Properties
+ $.jqplot.ElemContainer.call(this);
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: label
+ // The text or html for the label.
+ this.label = '';
+ this.fontFamily = null;
+ this.fontSize = null;
+ this.textColor = null;
+ this._elem;
+ // prop: escapeHTML
+ // true to escape HTML entities in the label.
+ this.escapeHTML = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer;
+
+ $.jqplot.AxisLabelRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>');
+
+ if (Number(this.label)) {
+ this._elem.css('white-space', 'nowrap');
+ }
+
+ if (!this.escapeHTML) {
+ this._elem.html(this.label);
+ }
+ else {
+ this._elem.text(this.label);
+ }
+ if (this.fontFamily) {
+ this._elem.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this._elem.css('font-size', this.fontSize);
+ }
+ if (this.textColor) {
+ this._elem.css('color', this.textColor);
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype.pack = function() {
+ };
+
+ // class: $.jqplot.AxisTickRenderer
+ // A "tick" object showing the value of a tick/gridline on the plot.
+ $.jqplot.AxisTickRenderer = function(options) {
+ // Group: Properties
+ $.jqplot.ElemContainer.call(this);
+ // prop: mark
+ // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
+ this.mark = 'outside';
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: showMark
+ // wether or not to show the mark on the axis.
+ this.showMark = true;
+ // prop: showGridline
+ // wether or not to draw the gridline on the grid at this tick.
+ this.showGridline = true;
+ // prop: isMinorTick
+ // if this is a minor tick.
+ this.isMinorTick = false;
+ // prop: size
+ // Length of the tick beyond the grid in pixels.
+ // DEPRECATED: This has been superceeded by markSize
+ this.size = 4;
+ // prop: markSize
+ // Length of the tick marks in pixels. For 'cross' style, length
+ // will be stoked above and below axis, so total length will be twice this.
+ this.markSize = 6;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ // Setting this to false requires more testing. It is recommended
+ // to set showLabel and showMark to false instead.
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ this.label = null;
+ this.value = null;
+ this._styles = {};
+ // prop: formatter
+ // A class of a formatter for the tick text. sprintf by default.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: prefix
+ // String to prepend to the tick label.
+ // Prefix is prepended to the formatted tick label.
+ this.prefix = '';
+ // prop: suffix
+ // String to append to the tick label.
+ // Suffix is appended to the formatted tick label.
+ this.suffix = '';
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: fontFamily
+ // css spec for the font-family css attribute.
+ this.fontFamily;
+ // prop: fontSize
+ // css spec for the font-size css attribute.
+ this.fontSize;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor;
+ // prop: escapeHTML
+ // true to escape HTML entities in the label.
+ this.escapeHTML = false;
+ this._elem;
+ this._breakTick = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer;
+
+ $.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
+ this.value = value;
+ this.axis = axisName;
+ if (isMinor) {
+ this.isMinorTick = true;
+ }
+ return this;
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.draw = function() {
+ if (this.label === null) {
+ this.label = this.prefix + this.formatter(this.formatString, this.value) + this.suffix;
+ }
+ var style = {position: 'absolute'};
+ if (Number(this.label)) {
+ style['whitSpace'] = 'nowrap';
+ }
+
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass("jqplot-"+this.axis+"-tick");
+
+ if (!this.escapeHTML) {
+ this._elem.html(this.label);
+ }
+ else {
+ this._elem.text(this.label);
+ }
+
+ this._elem.css(style);
+
+ for (var s in this._styles) {
+ this._elem.css(s, this._styles[s]);
+ }
+ if (this.fontFamily) {
+ this._elem.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this._elem.css('font-size', this.fontSize);
+ }
+ if (this.textColor) {
+ this._elem.css('color', this.textColor);
+ }
+ if (this._breakTick) {
+ this._elem.addClass('jqplot-breakTick');
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.DefaultTickFormatter = function (format, val) {
+ if (typeof val == 'number') {
+ if (!format) {
+ format = $.jqplot.config.defaultTickFormatString;
+ }
+ return $.jqplot.sprintf(format, val);
+ }
+ else {
+ return String(val);
+ }
+ };
+
+ $.jqplot.PercentTickFormatter = function (format, val) {
+ if (typeof val == 'number') {
+ val = 100 * val;
+ if (!format) {
+ format = $.jqplot.config.defaultTickFormatString;
+ }
+ return $.jqplot.sprintf(format, val);
+ }
+ else {
+ return String(val);
+ }
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.pack = function() {
+ };
+
+ // Class: $.jqplot.CanvasGridRenderer
+ // The default jqPlot grid renderer, creating a grid on a canvas element.
+ // The renderer has no additional options beyond the <Grid> class.
+ $.jqplot.CanvasGridRenderer = function(){
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ };
+
+ // called with context of Grid object
+ $.jqplot.CanvasGridRenderer.prototype.init = function(options) {
+ this._ctx;
+ $.extend(true, this, options);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor};
+ this.renderer.shadowRenderer.init(sopts);
+ };
+
+ // called with context of Grid.
+ $.jqplot.CanvasGridRenderer.prototype.createElement = function(plot) {
+ var elem;
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ elem = this._elem.get(0);
+ window.G_vmlCanvasManager.uninitElement(elem);
+ elem = null;
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ elem = plot.canvasManager.getCanvas();
+
+ var w = this._plotDimensions.width;
+ var h = this._plotDimensions.height;
+ elem.width = w;
+ elem.height = h;
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-grid-canvas');
+ this._elem.css({ position: 'absolute', left: 0, top: 0 });
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._top = this._offsets.top;
+ this._bottom = h - this._offsets.bottom;
+ this._left = this._offsets.left;
+ this._right = w - this._offsets.right;
+ this._width = this._right - this._left;
+ this._height = this._bottom - this._top;
+ // avoid memory leak
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasGridRenderer.prototype.draw = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ var ctx = this._ctx;
+ var axes = this._axes;
+ // Add the grid onto the grid canvas. This is the bottom most layer.
+ ctx.save();
+ ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height);
+ ctx.fillStyle = this.backgroundColor || this.background;
+ ctx.fillRect(this._left, this._top, this._width, this._height);
+
+ ctx.save();
+ ctx.lineJoin = 'miter';
+ ctx.lineCap = 'butt';
+ ctx.lineWidth = this.gridLineWidth;
+ ctx.strokeStyle = this.gridLineColor;
+ var b, e, s, m;
+ var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis'];
+ for (var i=4; i>0; i--) {
+ var name = ax[i-1];
+ var axis = axes[name];
+ var ticks = axis._ticks;
+ var numticks = ticks.length;
+ if (axis.show) {
+ if (axis.drawBaseline) {
+ var bopts = {};
+ if (axis.baselineWidth !== null) {
+ bopts.lineWidth = axis.baselineWidth;
+ }
+ if (axis.baselineColor !== null) {
+ bopts.strokeStyle = axis.baselineColor;
+ }
+ switch (name) {
+ case 'xaxis':
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ break;
+ case 'yaxis':
+ drawLine (this._left, this._bottom, this._left, this._top, bopts);
+ break;
+ case 'x2axis':
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ break;
+ case 'y2axis':
+ drawLine (this._right, this._bottom, this._right, this._top, bopts);
+ break;
+ }
+ }
+ for (var j=numticks; j>0; j--) {
+ var t = ticks[j-1];
+ if (t.show) {
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (name) {
+ case 'xaxis':
+ // draw the grid line if we should
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(pos, this._top, pos, this._bottom);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ case 'inside':
+ b = this._bottom-s;
+ e = this._bottom;
+ break;
+ case 'cross':
+ b = this._bottom-s;
+ e = this._bottom+s;
+ break;
+ default:
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'yaxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(this._right, pos, this._left, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._left-s;
+ e = this._left;
+ break;
+ case 'inside':
+ b = this._left;
+ e = this._left+s;
+ break;
+ case 'cross':
+ b = this._left-s;
+ e = this._left+s;
+ break;
+ default:
+ b = this._left-s;
+ e = this._left;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'x2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(pos, this._bottom, pos, this._top);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._top-s;
+ e = this._top;
+ break;
+ case 'inside':
+ b = this._top;
+ e = this._top+s;
+ break;
+ case 'cross':
+ b = this._top-s;
+ e = this._top+s;
+ break;
+ default:
+ b = this._top-s;
+ e = this._top;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'y2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(this._left, pos, this._right, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._right;
+ e = this._right+s;
+ break;
+ case 'inside':
+ b = this._right-s;
+ e = this._right;
+ break;
+ case 'cross':
+ b = this._right-s;
+ e = this._right+s;
+ break;
+ default:
+ b = this._right;
+ e = this._right+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ t = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+ // Now draw grid lines for additional y axes
+ //////
+ // TO DO: handle yMidAxis
+ //////
+ ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ for (var i=7; i>0; i--) {
+ var axis = axes[ax[i-1]];
+ var ticks = axis._ticks;
+ if (axis.show) {
+ var tn = ticks[axis.numberTicks-1];
+ var t0 = ticks[0];
+ var left = axis.getLeft();
+ var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]];
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth});
+ // draw the tick marks
+ for (var j=ticks.length; j>0; j--) {
+ var t = ticks[j-1];
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ if (t.showMark && t.mark) {
+ switch (m) {
+ case 'outside':
+ b = left;
+ e = left+s;
+ break;
+ case 'inside':
+ b = left-s;
+ e = left;
+ break;
+ case 'cross':
+ b = left-s;
+ e = left+s;
+ break;
+ default:
+ b = left;
+ e = left+s;
+ break;
+ }
+ points = [[b,pos], [e,pos]];
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ t = null;
+ }
+ t0 = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+
+ ctx.restore();
+
+ function drawLine(bx, by, ex, ey, opts) {
+ ctx.save();
+ opts = opts || {};
+ if (opts.lineWidth == null || opts.lineWidth != 0){
+ $.extend(true, ctx, opts);
+ ctx.beginPath();
+ ctx.moveTo(bx, by);
+ ctx.lineTo(ex, ey);
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+
+ if (this.shadow) {
+ var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ // Now draw border around grid. Use axis border definitions. start at
+ // upper left and go clockwise.
+ if (this.borderWidth != 0 && this.drawBorder) {
+ drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ // ctx.lineWidth = this.borderWidth;
+ // ctx.strokeStyle = this.borderColor;
+ // ctx.strokeRect(this._left, this._top, this._width, this._height);
+
+ ctx.restore();
+ ctx = null;
+ axes = null;
+ };
+
+ // Class: $.jqplot.DivTitleRenderer
+ // The default title renderer for jqPlot. This class has no options beyond the <Title> class.
+ $.jqplot.DivTitleRenderer = function() {
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.draw = function() {
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ var r = this.renderer;
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-title');
+
+ if (!this.text) {
+ this.show = false;
+ this._elem.height(0);
+ this._elem.width(0);
+ }
+ else if (this.text) {
+ var color;
+ if (this.color) {
+ color = this.color;
+ }
+ else if (this.textColor) {
+ color = this.textColor;
+ }
+
+ // don't trust that a stylesheet is present, set the position.
+ var styles = {position:'absolute', top:'0px', left:'0px'};
+
+ if (this._plotWidth) {
+ styles['width'] = this._plotWidth+'px';
+ }
+ if (this.fontSize) {
+ styles['fontSize'] = this.fontSize;
+ }
+ if (typeof this.textAlign === 'string') {
+ styles['textAlign'] = this.textAlign;
+ }
+ else {
+ styles['textAlign'] = 'center';
+ }
+ if (color) {
+ styles['color'] = color;
+ }
+ if (this.paddingBottom) {
+ styles['paddingBottom'] = this.paddingBottom;
+ }
+ if (this.fontFamily) {
+ styles['fontFamily'] = this.fontFamily;
+ }
+
+ this._elem.css(styles);
+ if (this.escapeHtml) {
+ this._elem.text(this.text);
+ }
+ else {
+ this._elem.html(this.text);
+ }
+
+
+ // styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : '';
+ // styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ // styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;';
+ // styletext += (color) ? 'color:'+color+';' : '';
+ // styletext += (this.paddingBottom) ? 'padding-bottom:'+this.paddingBottom+';' : '';
+ // this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>');
+ // if (this.fontFamily) {
+ // this._elem.css('font-family', this.fontFamily);
+ // }
+ }
+
+ elem = null;
+
+ return this._elem;
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.pack = function() {
+ // nothing to do here
+ };
+
+
+ var dotlen = 0.1;
+
+ $.jqplot.LinePattern = function (ctx, pattern) {
+
+ var defaultLinePatterns = {
+ dotted: [ dotlen, $.jqplot.config.dotGapLength ],
+ dashed: [ $.jqplot.config.dashLength, $.jqplot.config.gapLength ],
+ solid: null
+ };
+
+ if (typeof pattern === 'string') {
+ if (pattern[0] === '.' || pattern[0] === '-') {
+ var s = pattern;
+ pattern = [];
+ for (var i=0, imax=s.length; i<imax; i++) {
+ if (s[i] === '.') {
+ pattern.push( dotlen );
+ }
+ else if (s[i] === '-') {
+ pattern.push( $.jqplot.config.dashLength );
+ }
+ else {
+ continue;
+ }
+ pattern.push( $.jqplot.config.gapLength );
+ }
+ }
+ else {
+ pattern = defaultLinePatterns[pattern];
+ }
+ }
+
+ if (!(pattern && pattern.length)) {
+ return ctx;
+ }
+
+ var patternIndex = 0;
+ var patternDistance = pattern[0];
+ var px = 0;
+ var py = 0;
+ var pathx0 = 0;
+ var pathy0 = 0;
+
+ var moveTo = function (x, y) {
+ ctx.moveTo( x, y );
+ px = x;
+ py = y;
+ pathx0 = x;
+ pathy0 = y;
+ };
+
+ var lineTo = function (x, y) {
+ var scale = ctx.lineWidth;
+ var dx = x - px;
+ var dy = y - py;
+ var dist = Math.sqrt(dx*dx+dy*dy);
+ if ((dist > 0) && (scale > 0)) {
+ dx /= dist;
+ dy /= dist;
+ while (true) {
+ var dp = scale * patternDistance;
+ if (dp < dist) {
+ px += dp * dx;
+ py += dp * dy;
+ if ((patternIndex & 1) == 0) {
+ ctx.lineTo( px, py );
+ }
+ else {
+ ctx.moveTo( px, py );
+ }
+ dist -= dp;
+ patternIndex++;
+ if (patternIndex >= pattern.length) {
+ patternIndex = 0;
+ }
+ patternDistance = pattern[patternIndex];
+ }
+ else {
+ px = x;
+ py = y;
+ if ((patternIndex & 1) == 0) {
+ ctx.lineTo( px, py );
+ }
+ else {
+ ctx.moveTo( px, py );
+ }
+ patternDistance -= dist / scale;
+ break;
+ }
+ }
+ }
+ };
+
+ var beginPath = function () {
+ ctx.beginPath();
+ };
+
+ var closePath = function () {
+ lineTo( pathx0, pathy0 );
+ };
+
+ return {
+ moveTo: moveTo,
+ lineTo: lineTo,
+ beginPath: beginPath,
+ closePath: closePath
+ };
+ };
+
+ // Class: $.jqplot.LineRenderer
+ // The default line renderer for jqPlot, this class has no options beyond the <Series> class.
+ // Draws series as a line.
+ $.jqplot.LineRenderer = function(){
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ };
+
+ // called with scope of series.
+ $.jqplot.LineRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ options = options || {};
+ this._type='line';
+ this.renderer.animation = {
+ show: false,
+ direction: 'left',
+ speed: 2500,
+ _supported: true
+ };
+ // prop: smooth
+ // True to draw a smoothed (interpolated) line through the data points
+ // with automatically computed number of smoothing points.
+ // Set to an integer number > 2 to specify number of smoothing points
+ // to use between each data point.
+ this.renderer.smooth = false; // true or a number > 2 for smoothing.
+ this.renderer.tension = null; // null to auto compute or a number typically > 6. Fewer points requires higher tension.
+ // prop: constrainSmoothing
+ // True to use a more accurate smoothing algorithm that will
+ // not overshoot any data points. False to allow overshoot but
+ // produce a smoother looking line.
+ this.renderer.constrainSmoothing = true;
+ // this is smoothed data in grid coordinates, like gridData
+ this.renderer._smoothedData = [];
+ // this is smoothed data in plot units (plot coordinates), like plotData.
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+
+ // prop: bandData
+ // Data used to draw error bands or confidence intervals above/below a line.
+ //
+ // bandData can be input in 3 forms. jqPlot will figure out which is the
+ // low band line and which is the high band line for all forms:
+ //
+ // A 2 dimensional array like [[yl1, yl2, ...], [yu1, yu2, ...]] where
+ // [yl1, yl2, ...] are y values of the lower line and
+ // [yu1, yu2, ...] are y values of the upper line.
+ // In this case there must be the same number of y data points as data points
+ // in the series and the bands will inherit the x values of the series.
+ //
+ // A 2 dimensional array like [[[xl1, yl1], [xl2, yl2], ...], [[xh1, yh1], [xh2, yh2], ...]]
+ // where [xl1, yl1] are x,y data points for the lower line and
+ // [xh1, yh1] are x,y data points for the high line.
+ // x values do not have to correspond to the x values of the series and can
+ // be of any arbitrary length.
+ //
+ // Can be of form [[yl1, yu1], [yl2, yu2], [yl3, yu3], ...] where
+ // there must be 3 or more arrays and there must be the same number of arrays
+ // as there are data points in the series. In this case,
+ // [yl1, yu1] specifies the lower and upper y values for the 1st
+ // data point and so on. The bands will inherit the x
+ // values from the series.
+ this.renderer.bandData = [];
+
+ // Group: bands
+ // Banding around line, e.g error bands or confidence intervals.
+ this.renderer.bands = {
+ // prop: show
+ // true to show the bands. If bandData or interval is
+ // supplied, show will be set to true by default.
+ show: false,
+ hiData: [],
+ lowData: [],
+ // prop: color
+ // color of lines at top and bottom of bands [default: series color].
+ color: this.color,
+ // prop: showLines
+ // True to show lines at top and bottom of bands [default: false].
+ showLines: false,
+ // prop: fill
+ // True to fill area between bands [default: true].
+ fill: true,
+ // prop: fillColor
+ // css color spec for filled area. [default: series color].
+ fillColor: null,
+ _min: null,
+ _max: null,
+ // prop: interval
+ // User specified interval above and below line for bands [default: '3%''].
+ // Can be a value like 3 or a string like '3%'
+ // or an upper/lower array like [1, -2] or ['2%', '-1.5%']
+ interval: '3%'
+ };
+
+
+ var lopts = {highlightMouseOver: options.highlightMouseOver, highlightMouseDown: options.highlightMouseDown, highlightColor: options.highlightColor};
+
+ delete (options.highlightMouseOver);
+ delete (options.highlightMouseDown);
+ delete (options.highlightColor);
+
+ $.extend(true, this.renderer, options);
+
+ this.renderer.options = options;
+
+ // if we are given some band data, and bands aren't explicity set to false in options, turn them on.
+ if (this.renderer.bandData.length > 1 && (!options.bands || options.bands.show == null)) {
+ this.renderer.bands.show = true;
+ }
+
+ // if we are given an interval, and bands aren't explicity set to false in options, turn them on.
+ else if (options.bands && options.bands.show == null && options.bands.interval != null) {
+ this.renderer.bands.show = true;
+ }
+
+ // if plot is filled, turn off bands.
+ if (this.fill) {
+ this.renderer.bands.show = false;
+ }
+
+ if (this.renderer.bands.show) {
+ this.renderer.initBands.call(this, this.renderer.options, plot);
+ }
+
+
+ // smoothing is not compatible with stacked lines, disable
+ if (this._stack) {
+ this.renderer.smooth = false;
+ }
+
+ // set the shape renderer options
+ var opts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
+ this.renderer.shapeRenderer.init(opts);
+
+ var shadow_offset = options.shadowOffset;
+ // set the shadow renderer options
+ if (shadow_offset == null) {
+ // scale the shadowOffset to the width of the line.
+ if (this.lineWidth > 2.5) {
+ shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
+ // var shadow_offset = this.shadowOffset;
+ }
+ // for skinny lines, don't make such a big shadow.
+ else {
+ shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163;
+ }
+ }
+
+ var sopts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
+ this.renderer.shadowRenderer.init(sopts);
+ this._areaPoints = [];
+ this._boundingBox = [[],[]];
+
+ if (!this.isTrendline && this.fill || this.renderer.bands.show) {
+ // Group: Properties
+ //
+ // prop: highlightMouseOver
+ // True to highlight area on a filled plot when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on an area on a filled plot.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over an area on a filled plot.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColor
+ // color to use when highlighting an area on a filled plot.
+ this.highlightColor = null;
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (lopts.highlightMouseDown && lopts.highlightMouseOver == null) {
+ lopts.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, {highlightMouseOver: lopts.highlightMouseOver, highlightMouseDown: lopts.highlightMouseDown, highlightColor: lopts.highlightColor});
+
+ if (!this.highlightColor) {
+ var fc = (this.renderer.bands.show) ? this.renderer.bands.fillColor : this.fillColor;
+ this.highlightColor = $.jqplot.computeHighlightColors(fc);
+ }
+ // turn off (disable) the highlighter plugin
+ if (this.highlighter) {
+ this.highlighter.show = false;
+ }
+ }
+
+ if (!this.isTrendline && plot) {
+ plot.plugins.lineRenderer = {};
+ plot.postInitHooks.addOnce(postInit);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ }
+
+ };
+
+ $.jqplot.LineRenderer.prototype.initBands = function(options, plot) {
+ // use bandData if no data specified in bands option
+ //var bd = this.renderer.bandData;
+ var bd = options.bandData || [];
+ var bands = this.renderer.bands;
+ bands.hiData = [];
+ bands.lowData = [];
+ var data = this.data;
+ bands._max = null;
+ bands._min = null;
+ // If 2 arrays, and each array greater than 2 elements, assume it is hi and low data bands of y values.
+ if (bd.length == 2) {
+ // Do we have an array of x,y values?
+ // like [[[1,1], [2,4], [3,3]], [[1,3], [2,6], [3,5]]]
+ if ($.isArray(bd[0][0])) {
+ // since an arbitrary array of points, spin through all of them to determine max and min lines.
+
+ var p;
+ var bdminidx = 0, bdmaxidx = 0;
+ for (var i = 0, l = bd[0].length; i<l; i++) {
+ p = bd[0][i];
+ if ((p[1] != null && p[1] > bands._max) || bands._max == null) {
+ bands._max = p[1];
+ }
+ if ((p[1] != null && p[1] < bands._min) || bands._min == null) {
+ bands._min = p[1];
+ }
+ }
+ for (var i = 0, l = bd[1].length; i<l; i++) {
+ p = bd[1][i];
+ if ((p[1] != null && p[1] > bands._max) || bands._max == null) {
+ bands._max = p[1];
+ bdmaxidx = 1;
+ }
+ if ((p[1] != null && p[1] < bands._min) || bands._min == null) {
+ bands._min = p[1];
+ bdminidx = 1;
+ }
+ }
+
+ if (bdmaxidx === bdminidx) {
+ bands.show = false;
+ }
+
+ bands.hiData = bd[bdmaxidx];
+ bands.lowData = bd[bdminidx];
+ }
+ // else data is arrays of y values
+ // like [[1,4,3], [3,6,5]]
+ // must have same number of band data points as points in series
+ else if (bd[0].length === data.length && bd[1].length === data.length) {
+ var hi = (bd[0][0] > bd[1][0]) ? 0 : 1;
+ var low = (hi) ? 0 : 1;
+ for (var i=0, l=data.length; i < l; i++) {
+ bands.hiData.push([data[i][0], bd[hi][i]]);
+ bands.lowData.push([data[i][0], bd[low][i]]);
+ }
+ }
+
+ // we don't have proper data array, don't show bands.
+ else {
+ bands.show = false;
+ }
+ }
+
+ // if more than 2 arrays, have arrays of [ylow, yhi] values.
+ // note, can't distinguish case of [[ylow, yhi], [ylow, yhi]] from [[ylow, ylow], [yhi, yhi]]
+ // this is assumed to be of the latter form.
+ else if (bd.length > 2 && !$.isArray(bd[0][0])) {
+ var hi = (bd[0][0] > bd[0][1]) ? 0 : 1;
+ var low = (hi) ? 0 : 1;
+ for (var i=0, l=bd.length; i<l; i++) {
+ bands.hiData.push([data[i][0], bd[i][hi]]);
+ bands.lowData.push([data[i][0], bd[i][low]]);
+ }
+ }
+
+ // don't have proper data, auto calculate
+ else {
+ var intrv = bands.interval;
+ var a = null;
+ var b = null;
+ var afunc = null;
+ var bfunc = null;
+
+ if ($.isArray(intrv)) {
+ a = intrv[0];
+ b = intrv[1];
+ }
+ else {
+ a = intrv;
+ }
+
+ if (isNaN(a)) {
+ // we have a string
+ if (a.charAt(a.length - 1) === '%') {
+ afunc = 'multiply';
+ a = parseFloat(a)/100 + 1;
+ }
+ }
+
+ else {
+ a = parseFloat(a);
+ afunc = 'add';
+ }
+
+ if (b !== null && isNaN(b)) {
+ // we have a string
+ if (b.charAt(b.length - 1) === '%') {
+ bfunc = 'multiply';
+ b = parseFloat(b)/100 + 1;
+ }
+ }
+
+ else if (b !== null) {
+ b = parseFloat(b);
+ bfunc = 'add';
+ }
+
+ if (a !== null) {
+ if (b === null) {
+ b = -a;
+ bfunc = afunc;
+ if (bfunc === 'multiply') {
+ b += 2;
+ }
+ }
+
+ // make sure a always applies to hi band.
+ if (a < b) {
+ var temp = a;
+ a = b;
+ b = temp;
+ temp = afunc;
+ afunc = bfunc;
+ bfunc = temp;
+ }
+
+ for (var i=0, l = data.length; i < l; i++) {
+ switch (afunc) {
+ case 'add':
+ bands.hiData.push([data[i][0], data[i][1] + a]);
+ break;
+ case 'multiply':
+ bands.hiData.push([data[i][0], data[i][1] * a]);
+ break;
+ }
+ switch (bfunc) {
+ case 'add':
+ bands.lowData.push([data[i][0], data[i][1] + b]);
+ break;
+ case 'multiply':
+ bands.lowData.push([data[i][0], data[i][1] * b]);
+ break;
+ }
+ }
+ }
+
+ else {
+ bands.show = false;
+ }
+ }
+
+ var hd = bands.hiData;
+ var ld = bands.lowData;
+ for (var i = 0, l = hd.length; i<l; i++) {
+ if ((hd[i][1] != null && hd[i][1] > bands._max) || bands._max == null) {
+ bands._max = hd[i][1];
+ }
+ }
+ for (var i = 0, l = ld.length; i<l; i++) {
+ if ((ld[i][1] != null && ld[i][1] < bands._min) || bands._min == null) {
+ bands._min = ld[i][1];
+ }
+ }
+
+ // one last check for proper data
+ // these don't apply any more since allowing arbitrary x,y values
+ // if (bands.hiData.length != bands.lowData.length) {
+ // bands.show = false;
+ // }
+
+ // if (bands.hiData.length != this.data.length) {
+ // bands.show = false;
+ // }
+
+ if (bands.fillColor === null) {
+ var c = $.jqplot.getColorComponents(bands.color);
+ // now adjust alpha to differentiate fill
+ c[3] = c[3] * 0.5;
+ bands.fillColor = 'rgba(' + c[0] +', '+ c[1] +', '+ c[2] +', '+ c[3] + ')';
+ }
+ };
+
+ function getSteps (d, f) {
+ return (3.4182054+f) * Math.pow(d, -0.3534992);
+ }
+
+ function computeSteps (d1, d2) {
+ var s = Math.sqrt(Math.pow((d2[0]- d1[0]), 2) + Math.pow ((d2[1] - d1[1]), 2));
+ return 5.7648 * Math.log(s) + 7.4456;
+ }
+
+ function tanh (x) {
+ var a = (Math.exp(2*x) - 1) / (Math.exp(2*x) + 1);
+ return a;
+ }
+
+ //////////
+ // computeConstrainedSmoothedData
+ // An implementation of the constrained cubic spline interpolation
+ // method as presented in:
+ //
+ // Kruger, CJC, Constrained Cubic Spine Interpolation for Chemical Engineering Applications
+ // http://www.korf.co.uk/spline.pdf
+ //
+ // The implementation below borrows heavily from the sample Visual Basic
+ // implementation by CJC Kruger found in http://www.korf.co.uk/spline.xls
+ //
+ /////////
+
+ // called with scope of series
+ function computeConstrainedSmoothedData (gd) {
+ var smooth = this.renderer.smooth;
+ var dim = this.canvas.getWidth();
+ var xp = this._xaxis.series_p2u;
+ var yp = this._yaxis.series_p2u;
+ var steps =null;
+ var _steps = null;
+ var dist = gd.length/dim;
+ var _smoothedData = [];
+ var _smoothedPlotData = [];
+
+ if (!isNaN(parseFloat(smooth))) {
+ steps = parseFloat(smooth);
+ }
+ else {
+ steps = getSteps(dist, 0.5);
+ }
+
+ var yy = [];
+ var xx = [];
+
+ for (var i=0, l = gd.length; i<l; i++) {
+ yy.push(gd[i][1]);
+ xx.push(gd[i][0]);
+ }
+
+ function dxx(x1, x0) {
+ if (x1 - x0 == 0) {
+ return Math.pow(10,10);
+ }
+ else {
+ return x1 - x0;
+ }
+ }
+
+ var A, B, C, D;
+ // loop through each line segment. Have # points - 1 line segments. Nmber segments starting at 1.
+ var nmax = gd.length - 1;
+ for (var num = 1, gdl = gd.length; num<gdl; num++) {
+ var gxx = [];
+ var ggxx = [];
+ // point at each end of segment.
+ for (var j = 0; j < 2; j++) {
+ var i = num - 1 + j; // point number, 0 to # points.
+
+ if (i == 0 || i == nmax) {
+ gxx[j] = Math.pow(10, 10);
+ }
+ else if (yy[i+1] - yy[i] == 0 || yy[i] - yy[i-1] == 0) {
+ gxx[j] = 0;
+ }
+ else if (((xx[i+1] - xx[i]) / (yy[i+1] - yy[i]) + (xx[i] - xx[i-1]) / (yy[i] - yy[i-1])) == 0 ) {
+ gxx[j] = 0;
+ }
+ else if ( (yy[i+1] - yy[i]) * (yy[i] - yy[i-1]) < 0 ) {
+ gxx[j] = 0;
+ }
+
+ else {
+ gxx[j] = 2 / (dxx(xx[i + 1], xx[i]) / (yy[i + 1] - yy[i]) + dxx(xx[i], xx[i - 1]) / (yy[i] - yy[i - 1]));
+ }
+ }
+
+ // Reset first derivative (slope) at first and last point
+ if (num == 1) {
+ // First point has 0 2nd derivative
+ gxx[0] = 3 / 2 * (yy[1] - yy[0]) / dxx(xx[1], xx[0]) - gxx[1] / 2;
+ }
+ else if (num == nmax) {
+ // Last point has 0 2nd derivative
+ gxx[1] = 3 / 2 * (yy[nmax] - yy[nmax - 1]) / dxx(xx[nmax], xx[nmax - 1]) - gxx[0] / 2;
+ }
+
+ // Calc second derivative at points
+ ggxx[0] = -2 * (gxx[1] + 2 * gxx[0]) / dxx(xx[num], xx[num - 1]) + 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2);
+ ggxx[1] = 2 * (2 * gxx[1] + gxx[0]) / dxx(xx[num], xx[num - 1]) - 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2);
+
+ // Calc constants for cubic interpolation
+ D = 1 / 6 * (ggxx[1] - ggxx[0]) / dxx(xx[num], xx[num - 1]);
+ C = 1 / 2 * (xx[num] * ggxx[0] - xx[num - 1] * ggxx[1]) / dxx(xx[num], xx[num - 1]);
+ B = (yy[num] - yy[num - 1] - C * (Math.pow(xx[num], 2) - Math.pow(xx[num - 1], 2)) - D * (Math.pow(xx[num], 3) - Math.pow(xx[num - 1], 3))) / dxx(xx[num], xx[num - 1]);
+ A = yy[num - 1] - B * xx[num - 1] - C * Math.pow(xx[num - 1], 2) - D * Math.pow(xx[num - 1], 3);
+
+ var increment = (xx[num] - xx[num - 1]) / steps;
+ var temp, tempx;
+
+ for (var j = 0, l = steps; j < l; j++) {
+ temp = [];
+ tempx = xx[num - 1] + j * increment;
+ temp.push(tempx);
+ temp.push(A + B * tempx + C * Math.pow(tempx, 2) + D * Math.pow(tempx, 3));
+ _smoothedData.push(temp);
+ _smoothedPlotData.push([xp(temp[0]), yp(temp[1])]);
+ }
+ }
+
+ _smoothedData.push(gd[i]);
+ _smoothedPlotData.push([xp(gd[i][0]), yp(gd[i][1])]);
+
+ return [_smoothedData, _smoothedPlotData];
+ }
+
+ ///////
+ // computeHermiteSmoothedData
+ // A hermite spline smoothing of the plot data.
+ // This implementation is derived from the one posted
+ // by krypin on the jqplot-users mailing list:
+ //
+ // http://groups.google.com/group/jqplot-users/browse_thread/thread/748be6a445723cea?pli=1
+ //
+ // with a blog post:
+ //
+ // http://blog.statscollector.com/a-plugin-renderer-for-jqplot-to-draw-a-hermite-spline/
+ //
+ // and download of the original plugin:
+ //
+ // http://blog.statscollector.com/wp-content/uploads/2010/02/jqplot.hermiteSplineRenderer.js
+ //////////
+
+ // called with scope of series
+ function computeHermiteSmoothedData (gd) {
+ var smooth = this.renderer.smooth;
+ var tension = this.renderer.tension;
+ var dim = this.canvas.getWidth();
+ var xp = this._xaxis.series_p2u;
+ var yp = this._yaxis.series_p2u;
+ var steps =null;
+ var _steps = null;
+ var a = null;
+ var a1 = null;
+ var a2 = null;
+ var slope = null;
+ var slope2 = null;
+ var temp = null;
+ var t, s, h1, h2, h3, h4;
+ var TiX, TiY, Ti1X, Ti1Y;
+ var pX, pY, p;
+ var sd = [];
+ var spd = [];
+ var dist = gd.length/dim;
+ var min, max, stretch, scale, shift;
+ var _smoothedData = [];
+ var _smoothedPlotData = [];
+ if (!isNaN(parseFloat(smooth))) {
+ steps = parseFloat(smooth);
+ }
+ else {
+ steps = getSteps(dist, 0.5);
+ }
+ if (!isNaN(parseFloat(tension))) {
+ tension = parseFloat(tension);
+ }
+
+ for (var i=0, l = gd.length-1; i < l; i++) {
+
+ if (tension === null) {
+ slope = Math.abs((gd[i+1][1] - gd[i][1]) / (gd[i+1][0] - gd[i][0]));
+
+ min = 0.3;
+ max = 0.6;
+ stretch = (max - min)/2.0;
+ scale = 2.5;
+ shift = -1.4;
+
+ temp = slope/scale + shift;
+
+ a1 = stretch * tanh(temp) - stretch * tanh(shift) + min;
+
+ // if have both left and right line segments, will use minimum tension.
+ if (i > 0) {
+ slope2 = Math.abs((gd[i][1] - gd[i-1][1]) / (gd[i][0] - gd[i-1][0]));
+ }
+ temp = slope2/scale + shift;
+
+ a2 = stretch * tanh(temp) - stretch * tanh(shift) + min;
+
+ a = (a1 + a2)/2.0;
+
+ }
+ else {
+ a = tension;
+ }
+ for (t=0; t < steps; t++) {
+ s = t / steps;
+ h1 = (1 + 2*s)*Math.pow((1-s),2);
+ h2 = s*Math.pow((1-s),2);
+ h3 = Math.pow(s,2)*(3-2*s);
+ h4 = Math.pow(s,2)*(s-1);
+
+ if (gd[i-1]) {
+ TiX = a * (gd[i+1][0] - gd[i-1][0]);
+ TiY = a * (gd[i+1][1] - gd[i-1][1]);
+ } else {
+ TiX = a * (gd[i+1][0] - gd[i][0]);
+ TiY = a * (gd[i+1][1] - gd[i][1]);
+ }
+ if (gd[i+2]) {
+ Ti1X = a * (gd[i+2][0] - gd[i][0]);
+ Ti1Y = a * (gd[i+2][1] - gd[i][1]);
+ } else {
+ Ti1X = a * (gd[i+1][0] - gd[i][0]);
+ Ti1Y = a * (gd[i+1][1] - gd[i][1]);
+ }
+
+ pX = h1*gd[i][0] + h3*gd[i+1][0] + h2*TiX + h4*Ti1X;
+ pY = h1*gd[i][1] + h3*gd[i+1][1] + h2*TiY + h4*Ti1Y;
+ p = [pX, pY];
+
+ _smoothedData.push(p);
+ _smoothedPlotData.push([xp(pX), yp(pY)]);
+ }
+ }
+ _smoothedData.push(gd[l]);
+ _smoothedPlotData.push([xp(gd[l][0]), yp(gd[l][1])]);
+
+ return [_smoothedData, _smoothedPlotData];
+ }
+
+ // setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.LineRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ var pdata = this._prevPlotData;
+ this.gridData = [];
+ this._prevGridData = [];
+ this.renderer._smoothedData = [];
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+ var bands = this.renderer.bands;
+ var hasNull = false;
+ for (var i=0, l=data.length; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ hasNull = true;
+ this.gridData.push([null, yp.call(this._yaxis, data[i][1])]);
+ }
+ else if (data[i][1] == null) {
+ hasNull = true;
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), null]);
+ }
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] != null) {
+ this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (pdata[i] != null && pdata[i][0] == null) {
+ this._prevGridData.push([null, yp.call(this._yaxis, pdata[i][1])]);
+ }
+ else if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] == null) {
+ this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), null]);
+ }
+ }
+
+ // don't do smoothing or bands on broken lines.
+ if (hasNull) {
+ this.renderer.smooth = false;
+ if (this._type === 'line') {
+ bands.show = false;
+ }
+ }
+
+ if (this._type === 'line' && bands.show) {
+ for (var i=0, l=bands.hiData.length; i<l; i++) {
+ this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]);
+ }
+ for (var i=0, l=bands.lowData.length; i<l; i++) {
+ this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]);
+ }
+ }
+
+ // calculate smoothed data if enough points and no nulls
+ if (this._type === 'line' && this.renderer.smooth && this.gridData.length > 2) {
+ var ret;
+ if (this.renderer.constrainSmoothing) {
+ ret = computeConstrainedSmoothedData.call(this, this.gridData);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ else {
+ ret = computeHermiteSmoothedData.call(this, this.gridData);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ }
+ };
+
+ // makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.LineRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var pgd = [];
+ this.renderer._smoothedData = [];
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+ var bands = this.renderer.bands;
+ var hasNull = false;
+ for (var i=0; i<data.length; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ hasNull = true;
+ gd.push([null, yp.call(this._yaxis, data[i][1])]);
+ }
+ else if (data[i][1] == null) {
+ hasNull = true;
+ gd.push([xp.call(this._xaxis, data[i][0]), null]);
+ }
+ }
+
+ // don't do smoothing or bands on broken lines.
+ if (hasNull) {
+ this.renderer.smooth = false;
+ if (this._type === 'line') {
+ bands.show = false;
+ }
+ }
+
+ if (this._type === 'line' && bands.show) {
+ for (var i=0, l=bands.hiData.length; i<l; i++) {
+ this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]);
+ }
+ for (var i=0, l=bands.lowData.length; i<l; i++) {
+ this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]);
+ }
+ }
+
+ if (this._type === 'line' && this.renderer.smooth && gd.length > 2) {
+ var ret;
+ if (this.renderer.constrainSmoothing) {
+ ret = computeConstrainedSmoothedData.call(this, gd);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ else {
+ ret = computeHermiteSmoothedData.call(this, gd);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options, plot) {
+ var i;
+ // get a copy of the options, so we don't modify the original object.
+ var opts = $.extend(true, {}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
+ var xmin, ymin, xmax, ymax;
+ ctx.save();
+ if (gd.length) {
+ if (showLine) {
+ // if we fill, we'll have to add points to close the curve.
+ if (fill) {
+ if (this.fillToZero) {
+ // have to break line up into shapes at axis crossings
+ var negativeColor = this.negativeColor;
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var isnegative = false;
+ var posfs = opts.fillStyle;
+
+ // if stoking line as well as filling, get a copy of line data.
+ if (fillAndStroke) {
+ var fasgd = gd.slice(0);
+ }
+ // if not stacked, fill down to axis
+ if (this.index == 0 || !this._stack) {
+
+ var tempgd = [];
+ var pd = (this.renderer.smooth) ? this.renderer._smoothedPlotData : this._plotData;
+ this._areaPoints = [];
+ var pyzero = this._yaxis.series_u2p(this.fillToValue);
+ var pxzero = this._xaxis.series_u2p(this.fillToValue);
+
+ opts.closePath = true;
+
+ if (this.fillAxis == 'y') {
+ tempgd.push([gd[0][0], pyzero]);
+ this._areaPoints.push([gd[0][0], pyzero]);
+
+ for (var i=0; i<gd.length-1; i++) {
+ tempgd.push(gd[i]);
+ this._areaPoints.push(gd[i]);
+ // do we have an axis crossing?
+ if (pd[i][1] * pd[i+1][1] < 0) {
+ if (pd[i][1] < 0) {
+ isnegative = true;
+ opts.fillStyle = negativeColor;
+ }
+ else {
+ isnegative = false;
+ opts.fillStyle = posfs;
+ }
+
+ var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]);
+ tempgd.push([xintercept, pyzero]);
+ this._areaPoints.push([xintercept, pyzero]);
+ // now draw this shape and shadow.
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
+ }
+ this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
+ // now empty temp array and continue
+ tempgd = [[xintercept, pyzero]];
+ // this._areaPoints = [[xintercept, pyzero]];
+ }
+ }
+ if (pd[gd.length-1][1] < 0) {
+ isnegative = true;
+ opts.fillStyle = negativeColor;
+ }
+ else {
+ isnegative = false;
+ opts.fillStyle = posfs;
+ }
+ tempgd.push(gd[gd.length-1]);
+ this._areaPoints.push(gd[gd.length-1]);
+ tempgd.push([gd[gd.length-1][0], pyzero]);
+ this._areaPoints.push([gd[gd.length-1][0], pyzero]);
+ }
+ // now draw the last area.
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
+ }
+ this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
+
+
+ // var gridymin = this._yaxis.series_u2p(0);
+ // // IE doesn't return new length on unshift
+ // gd.unshift([gd[0][0], gridymin]);
+ // len = gd.length;
+ // gd.push([gd[len - 1][0], gridymin]);
+ }
+ // if stacked, fill to line below
+ else {
+ var prev = this._prevGridData;
+ for (var i=prev.length; i>0; i--) {
+ gd.push(prev[i-1]);
+ // this._areaPoints.push(prev[i-1]);
+ }
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+ this._areaPoints = gd;
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ }
+ /////////////////////////
+ // Not filled to zero
+ ////////////////////////
+ else {
+ // if stoking line as well as filling, get a copy of line data.
+ if (fillAndStroke) {
+ var fasgd = gd.slice(0);
+ }
+ // if not stacked, fill down to axis
+ if (this.index == 0 || !this._stack) {
+ // var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2;
+ var gridymin = ctx.canvas.height;
+ // IE doesn't return new length on unshift
+ gd.unshift([gd[0][0], gridymin]);
+ var len = gd.length;
+ gd.push([gd[len - 1][0], gridymin]);
+ }
+ // if stacked, fill to line below
+ else {
+ var prev = this._prevGridData;
+ for (var i=prev.length; i>0; i--) {
+ gd.push(prev[i-1]);
+ }
+ }
+ this._areaPoints = gd;
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ if (fillAndStroke) {
+ var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false});
+ this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts);
+ //////////
+ // TODO: figure out some way to do shadows nicely
+ // if (shadow) {
+ // this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts);
+ // }
+ // now draw the markers
+ if (this.markerRenderer.show) {
+ if (this.renderer.smooth) {
+ fasgd = this.gridData;
+ }
+ for (i=0; i<fasgd.length; i++) {
+ this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions);
+ }
+ }
+ }
+ }
+ else {
+
+ if (this.renderer.bands.show) {
+ var bdat;
+ var bopts = $.extend(true, {}, opts);
+ if (this.renderer.bands.showLines) {
+ bdat = (this.renderer.smooth) ? this.renderer._hiBandSmoothedData : this.renderer._hiBandGridData;
+ this.renderer.shapeRenderer.draw(ctx, bdat, opts);
+ bdat = (this.renderer.smooth) ? this.renderer._lowBandSmoothedData : this.renderer._lowBandGridData;
+ this.renderer.shapeRenderer.draw(ctx, bdat, bopts);
+ }
+
+ if (this.renderer.bands.fill) {
+ if (this.renderer.smooth) {
+ bdat = this.renderer._hiBandSmoothedData.concat(this.renderer._lowBandSmoothedData.reverse());
+ }
+ else {
+ bdat = this.renderer._hiBandGridData.concat(this.renderer._lowBandGridData.reverse());
+ }
+ this._areaPoints = bdat;
+ bopts.closePath = true;
+ bopts.fill = true;
+ bopts.fillStyle = this.renderer.bands.fillColor;
+ this.renderer.shapeRenderer.draw(ctx, bdat, bopts);
+ }
+ }
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ }
+ // calculate the bounding box
+ var xmin = xmax = ymin = ymax = null;
+ for (i=0; i<this._areaPoints.length; i++) {
+ var p = this._areaPoints[i];
+ if (xmin > p[0] || xmin == null) {
+ xmin = p[0];
+ }
+ if (ymax < p[1] || ymax == null) {
+ ymax = p[1];
+ }
+ if (xmax < p[0] || xmax == null) {
+ xmax = p[0];
+ }
+ if (ymin > p[1] || ymin == null) {
+ ymin = p[1];
+ }
+ }
+
+ if (this.type === 'line' && this.renderer.bands.show) {
+ ymax = this._yaxis.series_u2p(this.renderer.bands._min);
+ ymin = this._yaxis.series_u2p(this.renderer.bands._max);
+ }
+
+ this._boundingBox = [[xmin, ymax], [xmax, ymin]];
+
+ // now draw the markers
+ if (this.markerRenderer.show && !fill) {
+ if (this.renderer.smooth) {
+ gd = this.gridData;
+ }
+ for (i=0; i<gd.length; i++) {
+ if (gd[i][0] != null && gd[i][1] != null) {
+ this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions);
+ }
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ // called with scope of plot.
+ // make sure to not leave anything highlighted.
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.LineRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.lineRenderer && this.plugins.lineRenderer.highlightCanvas) {
+ this.plugins.lineRenderer.highlightCanvas.resetCanvas();
+ this.plugins.lineRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.lineRenderer.highlightedSeriesIndex = null;
+ this.plugins.lineRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.lineRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-lineRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.lineRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.lineRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.lineRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColor};
+ if (s.type === 'line' && s.renderer.bands.show) {
+ opts.fill = true;
+ opts.closePath = true;
+ }
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.lineRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.lineRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+
+ // class: $.jqplot.LinearAxisRenderer
+ // The default jqPlot axis renderer, creating a numeric axis.
+ $.jqplot.LinearAxisRenderer = function() {
+ };
+
+ // called with scope of axis object.
+ $.jqplot.LinearAxisRenderer.prototype.init = function(options){
+ // prop: breakPoints
+ // EXPERIMENTAL!! Use at your own risk!
+ // Works only with linear axes and the default tick renderer.
+ // Array of [start, stop] points to create a broken axis.
+ // Broken axes have a "jump" in them, which is an immediate
+ // transition from a smaller value to a larger value.
+ // Currently, axis ticks MUST be manually assigned if using breakPoints
+ // by using the axis ticks array option.
+ this.breakPoints = null;
+ // prop: breakTickLabel
+ // Label to use at the axis break if breakPoints are specified.
+ this.breakTickLabel = "&asymp;";
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ // prop: forceTickAt0
+ // This will ensure that there is always a tick mark at 0.
+ // If data range is strictly positive or negative,
+ // this will force 0 to be inside the axis bounds unless
+ // the appropriate axis pad (pad, padMin or padMax) is set
+ // to 0, then this will force an axis min or max value at 0.
+ // This has know effect when any of the following options
+ // are set: autoscale, min, max, numberTicks or tickInterval.
+ this.forceTickAt0 = false;
+ // prop: forceTickAt100
+ // This will ensure that there is always a tick mark at 100.
+ // If data range is strictly above or below 100,
+ // this will force 100 to be inside the axis bounds unless
+ // the appropriate axis pad (pad, padMin or padMax) is set
+ // to 0, then this will force an axis min or max value at 100.
+ // This has know effect when any of the following options
+ // are set: autoscale, min, max, numberTicks or tickInterval.
+ this.forceTickAt100 = false;
+ // prop: tickInset
+ // Controls the amount to inset the first and last ticks from
+ // the edges of the grid, in multiples of the tick interval.
+ // 0 is no inset, 0.5 is one half a tick interval, 1 is a full
+ // tick interval, etc.
+ this.tickInset = 0;
+ // prop: minorTicks
+ // Number of ticks to add between "major" ticks.
+ // Major ticks are ticks supplied by user or auto computed.
+ // Minor ticks cannot be created by user.
+ this.minorTicks = 0;
+ // prop: alignTicks
+ // true to align tick marks across opposed axes
+ // such as from the y2axis to yaxis.
+ this.alignTicks = false;
+ this._autoFormatString = '';
+ this._overrideFormatString = false;
+ this._scalefact = 1.0;
+ $.extend(true, this, options);
+ if (this.breakPoints) {
+ if (!$.isArray(this.breakPoints)) {
+ this.breakPoints = null;
+ }
+ else if (this.breakPoints.length < 2 || this.breakPoints[1] <= this.breakPoints[0]) {
+ this.breakPoints = null;
+ }
+ }
+ if (this.numberTicks != null && this.numberTicks < 2) {
+ this.numberTicks = 2;
+ }
+ this.resetDataBounds();
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this, plot);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // Memory Leaks patch
+ //this._elem.empty();
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ this._elem.append(tick.draw(ctx, plot));
+ }
+ }
+ tick = null;
+ t = null;
+ }
+ return this._elem;
+ };
+
+ // called with scope of an axis
+ $.jqplot.LinearAxisRenderer.prototype.reset = function() {
+ this.min = this._options.min;
+ this.max = this._options.max;
+ this.tickInterval = this._options.tickInterval;
+ this.numberTicks = this._options.numberTicks;
+ this._autoFormatString = '';
+ if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
+ this.tickOptions.formatString = '';
+ }
+
+ // this._ticks = this.__ticks;
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (!tick._breakTick && tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+ tick = null;
+ t = null;
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+ // get a copy of user's settings for min/max.
+ var userMin = this.min;
+ var userMax = this.max;
+ var userNT = this.numberTicks;
+ var userTI = this.tickInterval;
+
+ var threshold = 30;
+ this._scalefact = (Math.max(dim, threshold+1) - threshold)/300.0;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if ($.isArray(ut)) {
+ t.value = ut[0];
+ if (this.breakPoints) {
+ if (ut[0] == this.breakPoints[0]) {
+ t.label = this.breakTickLabel;
+ t._breakTick = true;
+ t.showGridline = false;
+ t.showMark = false;
+ }
+ else if (ut[0] > this.breakPoints[0] && ut[0] <= this.breakPoints[1]) {
+ t.show = false;
+ t.showGridline = false;
+ t.label = ut[1];
+ }
+ else {
+ t.label = ut[1];
+ }
+ }
+ else {
+ t.label = ut[1];
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (this.breakPoints) {
+ if (ut == this.breakPoints[0]) {
+ t.label = this.breakTickLabel;
+ t._breakTick = true;
+ t.showGridline = false;
+ t.showMark = false;
+ }
+ else if (ut > this.breakPoints[0] && ut <= this.breakPoints[1]) {
+ t.show = false;
+ t.showGridline = false;
+ }
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ var _numberTicks = this.numberTicks;
+
+ // if aligning this axis, use number of ticks from previous axis.
+ // Do I need to reset somehow if alignTicks is changed and then graph is replotted??
+ if (this.alignTicks) {
+ if (this.name === 'x2axis' && plot.axes.xaxis.show) {
+ _numberTicks = plot.axes.xaxis.numberTicks;
+ }
+ else if (this.name.charAt(0) === 'y' && this.name !== 'yaxis' && this.name !== 'yMidAxis' && plot.axes.yaxis.show) {
+ _numberTicks = plot.axes.yaxis.numberTicks;
+ }
+ }
+
+ min = ((this.min != null) ? this.min : db.min);
+ max = ((this.max != null) ? this.max : db.max);
+
+ var range = max - min;
+ var rmin, rmax;
+ var temp;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ // Doing complete autoscaling
+ if (this.min == null || this.max == null && this.tickInterval == null && !this.autoscale) {
+ // Check if user must have tick at 0 or 100 and ensure they are in range.
+ // The autoscaling algorithm will always place ticks at 0 and 100 if they are in range.
+ if (this.forceTickAt0) {
+ if (min > 0) {
+ min = 0;
+ }
+ if (max < 0) {
+ max = 0;
+ }
+ }
+
+ if (this.forceTickAt100) {
+ if (min > 100) {
+ min = 100;
+ }
+ if (max < 100) {
+ max = 100;
+ }
+ }
+
+ var keepMin = false,
+ keepMax = false;
+
+ if (this.min != null) {
+ keepMin = true;
+ }
+
+ else if (this.max != null) {
+ keepMax = true;
+ }
+
+ // var threshold = 30;
+ // var tdim = Math.max(dim, threshold+1);
+ // this._scalefact = (tdim-threshold)/300.0;
+ var ret = $.jqplot.LinearTickGenerator(min, max, this._scalefact, _numberTicks, keepMin, keepMax);
+ // calculate a padded max and min, points should be less than these
+ // so that they aren't too close to the edges of the plot.
+ // User can adjust how much padding is allowed with pad, padMin and PadMax options.
+ // If min or max is set, don't pad that end of axis.
+ var tumin = (this.min != null) ? min : min + range*(this.padMin - 1);
+ var tumax = (this.max != null) ? max : max - range*(this.padMax - 1);
+
+ // if they're equal, we shouldn't have to do anything, right?
+ // if (min <=tumin || max >= tumax) {
+ if (min <tumin || max > tumax) {
+ tumin = (this.min != null) ? min : min - range*(this.padMin - 1);
+ tumax = (this.max != null) ? max : max + range*(this.padMax - 1);
+ ret = $.jqplot.LinearTickGenerator(tumin, tumax, this._scalefact, _numberTicks, keepMin, keepMax);
+ }
+
+ this.min = ret[0];
+ this.max = ret[1];
+ // if numberTicks specified, it should return the same.
+ this.numberTicks = ret[2];
+ this._autoFormatString = ret[3];
+ this.tickInterval = ret[4];
+ }
+
+ // User has specified some axis scale related option, can use auto algorithm
+ else {
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 0.05;
+ if (min > 0) {
+ adj = Math.max(Math.log(min)/Math.LN10, 0.05);
+ }
+ min -= adj;
+ max += adj;
+ }
+
+ // autoscale. Can't autoscale if min or max is supplied.
+ // Will use numberTicks and tickInterval if supplied. Ticks
+ // across multiple axes may not line up depending on how
+ // bars are to be plotted.
+ if (this.autoscale && this.min == null && this.max == null) {
+ var rrange, ti, margin;
+ var forceMinZero = false;
+ var forceZeroLine = false;
+ var intervals = {min:null, max:null, average:null, stddev:null};
+ // if any series are bars, or if any are fill to zero, and if this
+ // is the axis to fill toward, check to see if we can start axis at zero.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name;
+ // check to see if this is the fill axis
+ if (this.name == faname) {
+ var vals = s._plotValues[s.fillAxis];
+ var vmin = vals[0];
+ var vmax = vals[0];
+ for (var j=1; j<vals.length; j++) {
+ if (vals[j] < vmin) {
+ vmin = vals[j];
+ }
+ else if (vals[j] > vmax) {
+ vmax = vals[j];
+ }
+ }
+ var dp = (vmax - vmin) / vmax;
+ // is this sries a bar?
+ if (s.renderer.constructor == $.jqplot.BarRenderer) {
+ // if no negative values and could also check range.
+ if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
+ forceMinZero = true;
+ }
+ else {
+ forceMinZero = false;
+ if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) {
+ forceZeroLine = true;
+ }
+ else {
+ forceZeroLine = false;
+ }
+ }
+ }
+
+ // if not a bar and filling, use appropriate method.
+ else if (s.fill) {
+ if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
+ forceMinZero = true;
+ }
+ else if (vmin < 0 && vmax > 0 && s.fillToZero) {
+ forceMinZero = false;
+ forceZeroLine = true;
+ }
+ else {
+ forceMinZero = false;
+ forceZeroLine = false;
+ }
+ }
+
+ // if not a bar and not filling, only change existing state
+ // if it doesn't make sense
+ else if (vmin < 0) {
+ forceMinZero = false;
+ }
+ }
+ }
+
+ // check if we need make axis min at 0.
+ if (forceMinZero) {
+ // compute number of ticks
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ this.min = 0;
+ userMin = 0;
+ // what order is this range?
+ // what tick interval does that give us?
+ ti = max/(this.numberTicks-1);
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ if (ti/temp == parseInt(ti/temp, 10)) {
+ ti += temp;
+ }
+ this.tickInterval = Math.ceil(ti/temp) * temp;
+ this.max = this.tickInterval * (this.numberTicks - 1);
+ }
+
+ // check if we need to make sure there is a tick at 0.
+ else if (forceZeroLine) {
+ // compute number of ticks
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1));
+ var ntmax = this.numberTicks - 1 - ntmin;
+ ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax));
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ this.tickInterval = Math.ceil(ti/temp) * temp;
+ this.max = this.tickInterval * ntmax;
+ this.min = -this.tickInterval * ntmin;
+ }
+
+ // if nothing else, do autoscaling which will try to line up ticks across axes.
+ else {
+ if (this.numberTicks == null){
+ if (this.tickInterval) {
+ this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
+ }
+ else {
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ }
+ }
+
+ if (this.tickInterval == null) {
+ // get a tick interval
+ ti = range/(this.numberTicks - 1);
+
+ if (ti < 1) {
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ }
+ else {
+ temp = 1;
+ }
+ this.tickInterval = Math.ceil(ti*temp*this.pad)/temp;
+ }
+ else {
+ temp = 1 / this.tickInterval;
+ }
+
+ // try to compute a nicer, more even tick interval
+ // temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10));
+ // this.tickInterval = Math.ceil(ti/temp) * temp;
+ rrange = this.tickInterval * (this.numberTicks - 1);
+ margin = (rrange - range)/2;
+
+ if (this.min == null) {
+ this.min = Math.floor(temp*(min-margin))/temp;
+ }
+ if (this.max == null) {
+ this.max = this.min + rrange;
+ }
+ }
+
+ // Compute a somewhat decent format string if it is needed.
+ // get precision of interval and determine a format string.
+ var sf = $.jqplot.getSignificantFigures(this.tickInterval);
+
+ var fstr;
+
+ // if we have only a whole number, use integer formatting
+ if (sf.digitsLeft >= sf.significantDigits) {
+ fstr = '%d';
+ }
+
+ else {
+ var temp = Math.max(0, 5 - sf.digitsLeft);
+ temp = Math.min(temp, sf.digitsRight);
+ fstr = '%.'+ temp + 'f';
+ }
+
+ this._autoFormatString = fstr;
+ }
+
+ // Use the default algorithm which pads each axis to make the chart
+ // centered nicely on the grid.
+ else {
+
+ rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1);
+ rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1);
+ range = rmax - rmin;
+
+ if (this.numberTicks == null){
+ // if tickInterval is specified by user, we will ignore computed maximum.
+ // max will be equal or greater to fit even # of ticks.
+ if (this.tickInterval != null) {
+ this.numberTicks = Math.ceil((rmax - rmin)/this.tickInterval)+1;
+ }
+ else if (dim > 100) {
+ this.numberTicks = parseInt(3+(dim-100)/75, 10);
+ }
+ else {
+ this.numberTicks = 2;
+ }
+ }
+
+ if (this.tickInterval == null) {
+ this.tickInterval = range / (this.numberTicks-1);
+ }
+
+ if (this.max == null) {
+ rmax = rmin + this.tickInterval*(this.numberTicks - 1);
+ }
+ if (this.min == null) {
+ rmin = rmax - this.tickInterval*(this.numberTicks - 1);
+ }
+
+ // get precision of interval and determine a format string.
+ var sf = $.jqplot.getSignificantFigures(this.tickInterval);
+
+ var fstr;
+
+ // if we have only a whole number, use integer formatting
+ if (sf.digitsLeft >= sf.significantDigits) {
+ fstr = '%d';
+ }
+
+ else {
+ var temp = Math.max(0, 5 - sf.digitsLeft);
+ temp = Math.min(temp, sf.digitsRight);
+ fstr = '%.'+ temp + 'f';
+ }
+
+
+ this._autoFormatString = fstr;
+
+ this.min = rmin;
+ this.max = rmax;
+ }
+
+ if (this.renderer.constructor == $.jqplot.LinearAxisRenderer && this._autoFormatString == '') {
+ // fix for misleading tick display with small range and low precision.
+ range = this.max - this.min;
+ // figure out precision
+ var temptick = new this.tickRenderer(this.tickOptions);
+ // use the tick formatString or, the default.
+ var fs = temptick.formatString || $.jqplot.config.defaultTickFormatString;
+ var fs = fs.match($.jqplot.sprintf.regex)[0];
+ var precision = 0;
+ if (fs) {
+ if (fs.search(/[fFeEgGpP]/) > -1) {
+ var m = fs.match(/\%\.(\d{0,})?[eEfFgGpP]/);
+ if (m) {
+ precision = parseInt(m[1], 10);
+ }
+ else {
+ precision = 6;
+ }
+ }
+ else if (fs.search(/[di]/) > -1) {
+ precision = 0;
+ }
+ // fact will be <= 1;
+ var fact = Math.pow(10, -precision);
+ if (this.tickInterval < fact) {
+ // need to correct underrange
+ if (userNT == null && userTI == null) {
+ this.tickInterval = fact;
+ if (userMax == null && userMin == null) {
+ // this.min = Math.floor((this._dataBounds.min - this.tickInterval)/fact) * fact;
+ this.min = Math.floor(this._dataBounds.min/fact) * fact;
+ if (this.min == this._dataBounds.min) {
+ this.min = this._dataBounds.min - this.tickInterval;
+ }
+ // this.max = Math.ceil((this._dataBounds.max + this.tickInterval)/fact) * fact;
+ this.max = Math.ceil(this._dataBounds.max/fact) * fact;
+ if (this.max == this._dataBounds.max) {
+ this.max = this._dataBounds.max + this.tickInterval;
+ }
+ var n = (this.max - this.min)/this.tickInterval;
+ n = n.toFixed(11);
+ n = Math.ceil(n);
+ this.numberTicks = n + 1;
+ }
+ else if (userMax == null) {
+ // add one tick for top of range.
+ var n = (this._dataBounds.max - this.min) / this.tickInterval;
+ n = n.toFixed(11);
+ this.numberTicks = Math.ceil(n) + 2;
+ this.max = this.min + this.tickInterval * (this.numberTicks-1);
+ }
+ else if (userMin == null) {
+ // add one tick for bottom of range.
+ var n = (this.max - this._dataBounds.min) / this.tickInterval;
+ n = n.toFixed(11);
+ this.numberTicks = Math.ceil(n) + 2;
+ this.min = this.max - this.tickInterval * (this.numberTicks-1);
+ }
+ else {
+ // calculate a number of ticks so max is within axis scale
+ this.numberTicks = Math.ceil((userMax - userMin)/this.tickInterval) + 1;
+ // if user's min and max don't fit evenly in ticks, adjust.
+ // This takes care of cases such as user min set to 0, max set to 3.5 but tick
+ // format string set to %d (integer ticks)
+ this.min = Math.floor(userMin*Math.pow(10, precision))/Math.pow(10, precision);
+ this.max = Math.ceil(userMax*Math.pow(10, precision))/Math.pow(10, precision);
+ // this.max = this.min + this.tickInterval*(this.numberTicks-1);
+ this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval) + 1;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ this.tickOptions = this.tickOptions || {};
+ this.tickOptions.formatString = this._autoFormatString;
+ }
+
+ var t, to;
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+
+ if (i < this.numberTicks - 1) {
+ for (var j=0; j<this.minorTicks; j++) {
+ tt += this.tickInterval/(this.minorTicks+1);
+ to = $.extend(true, {}, this.tickOptions, {name:this.name, value:tt, label:'', isMinorTick:true});
+ t = new this.tickRenderer(to);
+ this._ticks.push(t);
+ }
+ }
+ t = null;
+ }
+ }
+
+ if (this.tickInset) {
+ this.min = this.min - this.tickInset * this.tickInterval;
+ this.max = this.max + this.tickInset * this.tickInterval;
+ }
+
+ ticks = null;
+ };
+
+ // Used to reset just the values of the ticks and then repack, which will
+ // recalculate the positioning functions. It is assuemd that the
+ // number of ticks is the same and the values of the new array are at the
+ // proper interval.
+ // This method needs to be called with the scope of an axis object, like:
+ //
+ // > plot.axes.yaxis.renderer.resetTickValues.call(plot.axes.yaxis, yarr);
+ //
+ $.jqplot.LinearAxisRenderer.prototype.resetTickValues = function(opts) {
+ if ($.isArray(opts) && opts.length == this._ticks.length) {
+ var t;
+ for (var i=0; i<opts.length; i++) {
+ t = this._ticks[i];
+ t.value = opts[i];
+ t.label = t.formatter(t.formatString, opts[i]);
+ t.label = t.prefix + t.label;
+ t._elem.html(t.label);
+ }
+ t = null;
+ this.min = $.jqplot.arrayMin(opts);
+ this.max = $.jqplot.arrayMax(opts);
+ this.pack();
+ }
+ // Not implemented yet.
+ // else if ($.isPlainObject(opts)) {
+ //
+ // }
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) {
+ // Add defaults for repacking from resetTickValues function.
+ pos = pos || {};
+ offsets = offsets || this._offsets;
+
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ if (this.breakPoints) {
+ unitlength = unitlength - this.breakPoints[1] + this.breakPoints[0];
+
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u <= this.breakPoints[0]) {
+ return (u - min) * pixellength / unitlength + offmin;
+ }
+ else {
+ return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength + offmin;
+ }
+ };
+
+ if (this.name.charAt(0) == 'x'){
+ this.series_u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u <= this.breakPoints[0]) {
+ return (u - min) * pixellength / unitlength;
+ }
+ else {
+ return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength;
+ }
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u >= this.breakPoints[1]) {
+ return (u - max) * pixellength / unitlength;
+ }
+ else {
+ return (u + this.breakPoints[1] - this.breakPoints[0] - max) * pixellength / unitlength;
+ }
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+ else {
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+
+ ticks = null;
+ };
+
+
+ /**
+ * The following code was generaously given to me a while back by Scott Prahl.
+ * He did a good job at computing axes min, max and number of ticks for the
+ * case where the user has not set any scale related parameters (tickInterval,
+ * numberTicks, min or max). I had ignored this use case for a long time,
+ * focusing on the more difficult case where user has set some option controlling
+ * tick generation. Anyway, about time I got this into jqPlot.
+ * Thanks Scott!!
+ */
+
+ /**
+ * Copyright (c) 2010 Scott Prahl
+ * The next three routines are currently available for use in all personal
+ * or commercial projects under both the MIT and GPL version 2.0 licenses.
+ * This means that you can choose the license that best suits your project
+ * and use it accordingly.
+ */
+
+ // A good format string depends on the interval. If the interval is greater
+ // than 1 then there is no need to show any decimal digits. If it is < 1.0, then
+ // use the magnitude of the interval to determine the number of digits to show.
+ function bestFormatString (interval)
+ {
+ var fstr;
+ interval = Math.abs(interval);
+ if (interval >= 10) {
+ fstr = '%d';
+ }
+
+ else if (interval > 1) {
+ if (interval === parseInt(interval, 10)) {
+ fstr = '%d';
+ }
+ else {
+ fstr = '%.1f';
+ }
+ }
+
+ else {
+ var expv = -Math.floor(Math.log(interval)/Math.LN10);
+ fstr = '%.' + expv + 'f';
+ }
+
+ return fstr;
+ }
+
+ var _factors = [0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1, 2, 3, 4, 5];
+
+ var _getLowerFactor = function(f) {
+ var i = _factors.indexOf(f);
+ if (i > 0) {
+ return _factors[i-1];
+ }
+ else {
+ return _factors[_factors.length - 1] / 100;
+ }
+ };
+
+ var _getHigherFactor = function(f) {
+ var i = _factors.indexOf(f);
+ if (i < _factors.length-1) {
+ return _factors[i+1];
+ }
+ else {
+ return _factors[0] * 100;
+ }
+ };
+
+ // Given a fixed minimum and maximum and a target number ot ticks
+ // figure out the best interval and
+ // return min, max, number ticks, format string and tick interval
+ function bestConstrainedInterval(min, max, nttarget) {
+ // run through possible number to ticks and see which interval is best
+ var low = Math.floor(nttarget/2);
+ var hi = Math.ceil(nttarget*1.5);
+ var badness = Number.MAX_VALUE;
+ var r = (max - min);
+ var temp;
+ var sd;
+ var bestNT;
+ var gsf = $.jqplot.getSignificantFigures;
+ var fsd;
+ var fs;
+ var currentNT;
+ var bestPrec;
+
+ for (var i=0, l=hi-low+1; i<l; i++) {
+ currentNT = low + i;
+ temp = r/(currentNT-1);
+ sd = gsf(temp);
+
+ temp = Math.abs(nttarget - currentNT) + sd.digitsRight;
+ if (temp < badness) {
+ badness = temp;
+ bestNT = currentNT;
+ bestPrec = sd.digitsRight;
+ }
+ else if (temp === badness) {
+ // let nicer ticks trump number ot ticks
+ if (sd.digitsRight < bestPrec) {
+ bestNT = currentNT;
+ bestPrec = sd.digitsRight;
+ }
+ }
+
+ }
+
+ fsd = Math.max(bestPrec, Math.max(gsf(min).digitsRight, gsf(max).digitsRight));
+ if (fsd === 0) {
+ fs = '%d';
+ }
+ else {
+ fs = '%.' + fsd + 'f';
+ }
+ temp = r / (bestNT - 1);
+ // min, max, number ticks, format string, tick interval
+ return [min, max, bestNT, fs, temp];
+ }
+
+ // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n
+ // it is based soley on the range and number of ticks. So if user specifies
+ // number of ticks, use this.
+ function bestInterval(range, numberTicks) {
+ numberTicks = numberTicks || 7;
+ var minimum = range / (numberTicks - 1);
+ var magnitude = Math.pow(10, Math.floor(Math.log(minimum) / Math.LN10));
+ var residual = minimum / magnitude;
+ var interval;
+ // "nicest" ranges are 1, 2, 5 or powers of these.
+ // for magnitudes below 1, only allow these.
+ if (magnitude < 1) {
+ if (residual > 5) {
+ interval = 10 * magnitude;
+ }
+ else if (residual > 2) {
+ interval = 5 * magnitude;
+ }
+ else if (residual > 1) {
+ interval = 2 * magnitude;
+ }
+ else {
+ interval = magnitude;
+ }
+ }
+ // for large ranges (whole integers), allow intervals like 3, 4 or powers of these.
+ // this helps a lot with poor choices for number of ticks.
+ else {
+ if (residual > 5) {
+ interval = 10 * magnitude;
+ }
+ else if (residual > 4) {
+ interval = 5 * magnitude;
+ }
+ else if (residual > 3) {
+ interval = 4 * magnitude;
+ }
+ else if (residual > 2) {
+ interval = 3 * magnitude;
+ }
+ else if (residual > 1) {
+ interval = 2 * magnitude;
+ }
+ else {
+ interval = magnitude;
+ }
+ }
+
+ return interval;
+ }
+
+ // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n
+ // it is based soley on the range of data, number of ticks must be computed later.
+ function bestLinearInterval(range, scalefact) {
+ scalefact = scalefact || 1;
+ var expv = Math.floor(Math.log(range)/Math.LN10);
+ var magnitude = Math.pow(10, expv);
+ // 0 < f < 10
+ var f = range / magnitude;
+ var fact;
+ // for large plots, scalefact will decrease f and increase number of ticks.
+ // for small plots, scalefact will increase f and decrease number of ticks.
+ f = f/scalefact;
+
+ // for large plots, smaller interval, more ticks.
+ if (f<=0.38) {
+ fact = 0.1;
+ }
+ else if (f<=1.6) {
+ fact = 0.2;
+ }
+ else if (f<=4.0) {
+ fact = 0.5;
+ }
+ else if (f<=8.0) {
+ fact = 1.0;
+ }
+ // for very small plots, larger interval, less ticks in number ticks
+ else if (f<=16.0) {
+ fact = 2;
+ }
+ else {
+ fact = 5;
+ }
+
+ return fact*magnitude;
+ }
+
+ function bestLinearComponents(range, scalefact) {
+ var expv = Math.floor(Math.log(range)/Math.LN10);
+ var magnitude = Math.pow(10, expv);
+ // 0 < f < 10
+ var f = range / magnitude;
+ var interval;
+ var fact;
+ // for large plots, scalefact will decrease f and increase number of ticks.
+ // for small plots, scalefact will increase f and decrease number of ticks.
+ f = f/scalefact;
+
+ // for large plots, smaller interval, more ticks.
+ if (f<=0.38) {
+ fact = 0.1;
+ }
+ else if (f<=1.6) {
+ fact = 0.2;
+ }
+ else if (f<=4.0) {
+ fact = 0.5;
+ }
+ else if (f<=8.0) {
+ fact = 1.0;
+ }
+ // for very small plots, larger interval, less ticks in number ticks
+ else if (f<=16.0) {
+ fact = 2;
+ }
+ // else if (f<=20.0) {
+ // fact = 3;
+ // }
+ // else if (f<=24.0) {
+ // fact = 4;
+ // }
+ else {
+ fact = 5;
+ }
+
+ interval = fact * magnitude;
+
+ return [interval, fact, magnitude];
+ }
+
+ // Given the min and max for a dataset, return suitable endpoints
+ // for the graphing, a good number for the number of ticks, and a
+ // format string so that extraneous digits are not displayed.
+ // returned is an array containing [min, max, nTicks, format]
+ $.jqplot.LinearTickGenerator = function(axis_min, axis_max, scalefact, numberTicks, keepMin, keepMax) {
+ // Set to preserve EITHER min OR max.
+ // If min is preserved, max must be free.
+ keepMin = (keepMin === null) ? false : keepMin;
+ keepMax = (keepMax === null || keepMin) ? false : keepMax;
+ // if endpoints are equal try to include zero otherwise include one
+ if (axis_min === axis_max) {
+ axis_max = (axis_max) ? 0 : 1;
+ }
+
+ scalefact = scalefact || 1.0;
+
+ // make sure range is positive
+ if (axis_max < axis_min) {
+ var a = axis_max;
+ axis_max = axis_min;
+ axis_min = a;
+ }
+
+ var r = [];
+ var ss = bestLinearInterval(axis_max - axis_min, scalefact);
+
+ var gsf = $.jqplot.getSignificantFigures;
+
+ if (numberTicks == null) {
+
+ // Figure out the axis min, max and number of ticks
+ // the min and max will be some multiple of the tick interval,
+ // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the
+ // axis min is negative, 0 will be a tick.
+ if (!keepMin && !keepMax) {
+ r[0] = Math.floor(axis_min / ss) * ss; // min
+ r[1] = Math.ceil(axis_max / ss) * ss; // max
+ r[2] = Math.round((r[1]-r[0])/ss+1.0); // number of ticks
+ r[3] = bestFormatString(ss); // format string
+ r[4] = ss; // tick Interval
+ }
+
+ else if (keepMin) {
+ r[0] = axis_min; // min
+ r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks
+ r[1] = axis_min + (r[2] - 1) * ss; // max
+ var digitsMin = gsf(axis_min).digitsRight;
+ var digitsSS = gsf(ss).digitsRight;
+ if (digitsMin < digitsSS) {
+ r[3] = bestFormatString(ss); // format string
+ }
+ else {
+ r[3] = '%.' + digitsMin + 'f';
+ }
+ r[4] = ss; // tick Interval
+ }
+
+ else if (keepMax) {
+ r[1] = axis_max; // max
+ r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks
+ r[0] = axis_max - (r[2] - 1) * ss; // min
+ var digitsMax = gsf(axis_max).digitsRight;
+ var digitsSS = gsf(ss).digitsRight;
+ if (digitsMax < digitsSS) {
+ r[3] = bestFormatString(ss); // format string
+ }
+ else {
+ r[3] = '%.' + digitsMax + 'f';
+ }
+ r[4] = ss; // tick Interval
+ }
+ }
+
+ else {
+ var tempr = [];
+
+ // Figure out the axis min, max and number of ticks
+ // the min and max will be some multiple of the tick interval,
+ // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the
+ // axis min is negative, 0 will be a tick.
+ tempr[0] = Math.floor(axis_min / ss) * ss; // min
+ tempr[1] = Math.ceil(axis_max / ss) * ss; // max
+ tempr[2] = Math.round((tempr[1]-tempr[0])/ss+1.0); // number of ticks
+ tempr[3] = bestFormatString(ss); // format string
+ tempr[4] = ss; // tick Interval
+
+ // first, see if we happen to get the right number of ticks
+ if (tempr[2] === numberTicks) {
+ r = tempr;
+ }
+
+ else {
+
+ var newti = bestInterval(tempr[1] - tempr[0], numberTicks);
+
+ r[0] = tempr[0]; // min
+ r[2] = numberTicks; // number of ticks
+ r[4] = newti; // tick interval
+ r[3] = bestFormatString(newti); // format string
+ r[1] = r[0] + (r[2] - 1) * r[4]; // max
+ }
+ }
+
+ return r;
+ };
+
+ $.jqplot.LinearTickGenerator.bestLinearInterval = bestLinearInterval;
+ $.jqplot.LinearTickGenerator.bestInterval = bestInterval;
+ $.jqplot.LinearTickGenerator.bestLinearComponents = bestLinearComponents;
+ $.jqplot.LinearTickGenerator.bestConstrainedInterval = bestConstrainedInterval;
+
+
+ // class: $.jqplot.MarkerRenderer
+ // The default jqPlot marker renderer, rendering the points on the line.
+ $.jqplot.MarkerRenderer = function(options){
+ // Group: Properties
+
+ // prop: show
+ // wether or not to show the marker.
+ this.show = true;
+ // prop: style
+ // One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare
+ this.style = 'filledCircle';
+ // prop: lineWidth
+ // size of the line for non-filled markers.
+ this.lineWidth = 2;
+ // prop: size
+ // Size of the marker (diameter or circle, length of edge of square, etc.)
+ this.size = 9.0;
+ // prop: color
+ // color of marker. Will be set to color of series by default on init.
+ this.color = '#666666';
+ // prop: shadow
+ // wether or not to draw a shadow on the line
+ this.shadow = true;
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ this.shadowOffset = 1;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.07';
+ // prop: shadowRenderer
+ // Renderer that will draws the shadows on the marker.
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ // prop: shapeRenderer
+ // Renderer that will draw the marker.
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true};
+ if (this.style.indexOf('filled') != -1) {
+ sdopt.fill = true;
+ }
+ if (this.style.indexOf('ircle') != -1) {
+ sdopt.isarc = true;
+ sdopt.closePath = false;
+ }
+ this.shadowRenderer.init(sdopt);
+
+ var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true};
+ if (this.style.indexOf('filled') != -1) {
+ shopt.fill = true;
+ }
+ if (this.style.indexOf('ircle') != -1) {
+ shopt.isarc = true;
+ shopt.closePath = false;
+ }
+ this.shapeRenderer.init(shopt);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) {
+ var stretch = 1.2;
+ var dx = this.size/2/stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var points1 = [[x, y-dy], [x, y+dy]];
+ var points2 = [[x+dx, y], [x-dx, y]];
+ var opts = $.extend(true, {}, this.options, {closePath:false});
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points1, {closePath:false});
+ this.shadowRenderer.draw(ctx, points2, {closePath:false});
+ }
+ this.shapeRenderer.draw(ctx, points1, opts);
+ this.shapeRenderer.draw(ctx, points2, opts);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var opts = $.extend(true, {}, this.options, {closePath:false});
+ var points1 = [[x-dx, y-dy], [x+dx, y+dy]];
+ var points2 = [[x-dx, y+dy], [x+dx, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points1, {closePath:false});
+ this.shadowRenderer.draw(ctx, points2, {closePath:false});
+ }
+ this.shapeRenderer.draw(ctx, points1, opts);
+ this.shapeRenderer.draw(ctx, points2, opts);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y], [x+dx, y]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawLine = function(p1, p2, ctx, fill, options) {
+ var points = [p1, p2];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2/stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) {
+ var radius = this.size/2;
+ var end = 2*Math.PI;
+ var points = [x, y, radius, 0, end, true];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) {
+ options = options || {};
+ // hack here b/c shape renderer uses canvas based color style options
+ // and marker uses css style names.
+ if (options.show == null || options.show != false) {
+ if (options.color && !options.fillStyle) {
+ options.fillStyle = options.color;
+ }
+ if (options.color && !options.strokeStyle) {
+ options.strokeStyle = options.color;
+ }
+ switch (this.style) {
+ case 'diamond':
+ this.drawDiamond(x,y,ctx, false, options);
+ break;
+ case 'filledDiamond':
+ this.drawDiamond(x,y,ctx, true, options);
+ break;
+ case 'circle':
+ this.drawCircle(x,y,ctx, false, options);
+ break;
+ case 'filledCircle':
+ this.drawCircle(x,y,ctx, true, options);
+ break;
+ case 'square':
+ this.drawSquare(x,y,ctx, false, options);
+ break;
+ case 'filledSquare':
+ this.drawSquare(x,y,ctx, true, options);
+ break;
+ case 'x':
+ this.drawX(x,y,ctx, true, options);
+ break;
+ case 'plus':
+ this.drawPlus(x,y,ctx, true, options);
+ break;
+ case 'dash':
+ this.drawDash(x,y,ctx, true, options);
+ break;
+ case 'line':
+ this.drawLine(x, y, ctx, false, options);
+ break;
+ default:
+ this.drawDiamond(x,y,ctx, false, options);
+ break;
+ }
+ }
+ };
+
+ // class: $.jqplot.shadowRenderer
+ // The default jqPlot shadow renderer, rendering shadows behind shapes.
+ $.jqplot.ShadowRenderer = function(options){
+ // Group: Properties
+
+ // prop: angle
+ // Angle of the shadow in degrees. Measured counter-clockwise from the x axis.
+ this.angle = 45;
+ // prop: offset
+ // Pixel offset at the given shadow angle of each shadow stroke from the last stroke.
+ this.offset = 1;
+ // prop: alpha
+ // alpha transparency of shadow stroke.
+ this.alpha = 0.07;
+ // prop: lineWidth
+ // width of the shadow line stroke.
+ this.lineWidth = 1.5;
+ // prop: lineJoin
+ // How line segments of the shadow are joined.
+ this.lineJoin = 'miter';
+ // prop: lineCap
+ // how ends of the shadow line are rendered.
+ this.lineCap = 'round';
+ // prop; closePath
+ // whether line path segment is closed upon itself.
+ this.closePath = false;
+ // prop: fill
+ // whether to fill the shape.
+ this.fill = false;
+ // prop: depth
+ // how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees.
+ this.depth = 3;
+ this.strokeStyle = 'rgba(0,0,0,0.1)';
+ // prop: isarc
+ // wether the shadow is an arc or not.
+ this.isarc = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.ShadowRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ // function: draw
+ // draws an transparent black (i.e. gray) shadow.
+ //
+ // ctx - canvas drawing context
+ // points - array of points or [x, y, radius, start angle (rad), end angle (rad)]
+ $.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ var fill = (opts.fill != null) ? opts.fill : this.fill;
+ var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
+ var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
+ var offset = (opts.offset != null) ? opts.offset : this.offset;
+ var alpha = (opts.alpha != null) ? opts.alpha : this.alpha;
+ var depth = (opts.depth != null) ? opts.depth : this.depth;
+ var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+ var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
+ ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth;
+ ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin;
+ ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap;
+ ctx.strokeStyle = opts.strokeStyle || this.strokeStyle || 'rgba(0,0,0,'+alpha+')';
+ ctx.fillStyle = opts.fillStyle || this.fillStyle || 'rgba(0,0,0,'+alpha+')';
+ for (var j=0; j<depth; j++) {
+ var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
+ ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset);
+ ctxPattern.beginPath();
+ if (isarc) {
+ ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
+ }
+ else if (fillRect) {
+ if (fillRect) {
+ ctx.fillRect(points[0], points[1], points[2], points[3]);
+ }
+ }
+ else if (points && points.length){
+ var move = true;
+ for (var i=0; i<points.length; i++) {
+ // skip to the first non-null point and move to it.
+ if (points[i][0] != null && points[i][1] != null) {
+ if (move) {
+ ctxPattern.moveTo(points[i][0], points[i][1]);
+ move = false;
+ }
+ else {
+ ctxPattern.lineTo(points[i][0], points[i][1]);
+ }
+ }
+ else {
+ move = true;
+ }
+ }
+
+ }
+ if (closePath) {
+ ctxPattern.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ };
+
+ // class: $.jqplot.shapeRenderer
+ // The default jqPlot shape renderer. Given a set of points will
+ // plot them and either stroke a line (fill = false) or fill them (fill = true).
+ // If a filled shape is desired, closePath = true must also be set to close
+ // the shape.
+ $.jqplot.ShapeRenderer = function(options){
+
+ this.lineWidth = 1.5;
+ // prop: linePattern
+ // line pattern 'dashed', 'dotted', 'solid', some combination
+ // of '-' and '.' characters such as '.-.' or a numerical array like
+ // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line,
+ // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+ this.linePattern = 'solid';
+ // prop: lineJoin
+ // How line segments of the shadow are joined.
+ this.lineJoin = 'miter';
+ // prop: lineCap
+ // how ends of the shadow line are rendered.
+ this.lineCap = 'round';
+ // prop; closePath
+ // whether line path segment is closed upon itself.
+ this.closePath = false;
+ // prop: fill
+ // whether to fill the shape.
+ this.fill = false;
+ // prop: isarc
+ // wether the shadow is an arc or not.
+ this.isarc = false;
+ // prop: fillRect
+ // true to draw shape as a filled rectangle.
+ this.fillRect = false;
+ // prop: strokeRect
+ // true to draw shape as a stroked rectangle.
+ this.strokeRect = false;
+ // prop: clearRect
+ // true to cear a rectangle.
+ this.clearRect = false;
+ // prop: strokeStyle
+ // css color spec for the stoke style
+ this.strokeStyle = '#999999';
+ // prop: fillStyle
+ // css color spec for the fill style.
+ this.fillStyle = '#999999';
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.ShapeRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ // function: draw
+ // draws the shape.
+ //
+ // ctx - canvas drawing context
+ // points - array of points for shapes or
+ // [x, y, width, height] for rectangles or
+ // [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs.
+ $.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ var fill = (opts.fill != null) ? opts.fill : this.fill;
+ var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
+ var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
+ var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect;
+ var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
+ var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+ var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
+ var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
+ ctx.lineWidth = opts.lineWidth || this.lineWidth;
+ ctx.lineJoin = opts.lineJoin || this.lineJoin;
+ ctx.lineCap = opts.lineCap || this.lineCap;
+ ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle;
+ ctx.fillStyle = opts.fillStyle || this.fillStyle;
+ ctx.beginPath();
+ if (isarc) {
+ ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
+ if (closePath) {
+ ctx.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ ctx.restore();
+ return;
+ }
+ else if (clearRect) {
+ ctx.clearRect(points[0], points[1], points[2], points[3]);
+ ctx.restore();
+ return;
+ }
+ else if (fillRect || strokeRect) {
+ if (fillRect) {
+ ctx.fillRect(points[0], points[1], points[2], points[3]);
+ }
+ if (strokeRect) {
+ ctx.strokeRect(points[0], points[1], points[2], points[3]);
+ ctx.restore();
+ return;
+ }
+ }
+ else if (points && points.length){
+ var move = true;
+ for (var i=0; i<points.length; i++) {
+ // skip to the first non-null point and move to it.
+ if (points[i][0] != null && points[i][1] != null) {
+ if (move) {
+ ctxPattern.moveTo(points[i][0], points[i][1]);
+ move = false;
+ }
+ else {
+ ctxPattern.lineTo(points[i][0], points[i][1]);
+ }
+ }
+ else {
+ move = true;
+ }
+ }
+ if (closePath) {
+ ctxPattern.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ };
+
+ // class $.jqplot.TableLegendRenderer
+ // The default legend renderer for jqPlot.
+ $.jqplot.TableLegendRenderer = function(){
+ //
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad, reverse) {
+ var rs = (pad) ? this.rowSpacing+'px' : '0px';
+ var tr;
+ var td;
+ var elem;
+ var div0;
+ var div1;
+ elem = document.createElement('tr');
+ tr = $(elem);
+ tr.addClass('jqplot-table-legend');
+ elem = null;
+
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+
+ else{
+ tr.appendTo(this._elem);
+ }
+
+ if (this.showSwatches) {
+ td = $(document.createElement('td'));
+ td.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+
+ tr.append(td.append(div0.append(div1)));
+
+ // $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+
+ // '</div></td>').appendTo(tr);
+ }
+ if (this.showLabels) {
+ td = $(document.createElement('td'));
+ td.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td.css('paddingTop', rs);
+ tr.append(td);
+
+ // elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ // elem.appendTo(tr);
+ if (this.escapeHtml) {
+ td.text(label);
+ }
+ else {
+ td.html(label);
+ }
+ }
+ td = null;
+ div0 = null;
+ div1 = null;
+ tr = null;
+ elem = null;
+ };
+
+ // called with scope of legend
+ $.jqplot.TableLegendRenderer.prototype.draw = function() {
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ if (this.show) {
+ var series = this._series;
+ // make a table. one line label per row.
+ var elem = document.createElement('table');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-table-legend');
+
+ var ss = {position:'absolute'};
+ if (this.background) {
+ ss['background'] = this.background;
+ }
+ if (this.border) {
+ ss['border'] = this.border;
+ }
+ if (this.fontSize) {
+ ss['fontSize'] = this.fontSize;
+ }
+ if (this.fontFamily) {
+ ss['fontFamily'] = this.fontFamily;
+ }
+ if (this.textColor) {
+ ss['textColor'] = this.textColor;
+ }
+ if (this.marginTop != null) {
+ ss['marginTop'] = this.marginTop;
+ }
+ if (this.marginBottom != null) {
+ ss['marginBottom'] = this.marginBottom;
+ }
+ if (this.marginLeft != null) {
+ ss['marginLeft'] = this.marginLeft;
+ }
+ if (this.marginRight != null) {
+ ss['marginRight'] = this.marginRight;
+ }
+
+
+ var pad = false,
+ reverse = false,
+ s;
+ for (var i = 0; i< series.length; i++) {
+ s = series[i];
+ if (s._stack || s.renderer.constructor == $.jqplot.BezierCurveRenderer){
+ reverse = true;
+ }
+ if (s.show && s.showLabel) {
+ var lt = this.labels[i] || s.label.toString();
+ if (lt) {
+ var color = s.color;
+ if (reverse && i < series.length - 1){
+ pad = true;
+ }
+ else if (reverse && i == series.length - 1){
+ pad = false;
+ }
+ this.renderer.addrow.call(this, lt, color, pad, reverse);
+ pad = true;
+ }
+ // let plugins add more rows to legend. Used by trend line plugin.
+ for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
+ var item = $.jqplot.addLegendRowHooks[j].call(this, s);
+ if (item) {
+ this.renderer.addrow.call(this, item.label, item.color, pad);
+ pad = true;
+ }
+ }
+ lt = null;
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) {
+ if (this.show) {
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ var a = offsets.left;
+ var b = offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'ne':
+ var a = offsets.right;
+ var b = offsets.top;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = offsets.right;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = offsets.left;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = offsets.left;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+
+ }
+ else if (this.placement == 'outside'){
+ switch (this.location) {
+ case 'nw':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = offsets.top;
+ this._elem.css('right', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('bottom', b);
+ break;
+ case 'ne':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = offsets.top;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'e':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'se':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.bottom;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'sw':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 'w':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+ }
+ else {
+ switch (this.location) {
+ case 'nw':
+ this._elem.css({left:0, top:offsets.top});
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ this._elem.css({left: a, top:offsets.top});
+ break;
+ case 'ne':
+ this._elem.css({right:0, top:offsets.top});
+ break;
+ case 'e':
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:offsets.right, top:b});
+ break;
+ case 'se':
+ this._elem.css({right:offsets.right, bottom:offsets.bottom});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ this._elem.css({left: a, bottom:offsets.bottom});
+ break;
+ case 'sw':
+ this._elem.css({left:offsets.left, bottom:offsets.bottom});
+ break;
+ case 'w':
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:offsets.left, top:b});
+ break;
+ default: // same as 'se'
+ this._elem.css({right:offsets.right, bottom:offsets.bottom});
+ break;
+ }
+ }
+ }
+ };
+
+ /**
+ * Class: $.jqplot.ThemeEngine
+ * Theme Engine provides a programatic way to change some of the more
+ * common jqplot styling options such as fonts, colors and grid options.
+ * A theme engine instance is created with each plot. The theme engine
+ * manages a collection of themes which can be modified, added to, or
+ * applied to the plot.
+ *
+ * The themeEngine class is not instantiated directly.
+ * When a plot is initialized, the current plot options are scanned
+ * an a default theme named "Default" is created. This theme is
+ * used as the basis for other themes added to the theme engine and
+ * is always available.
+ *
+ * A theme is a simple javascript object with styling parameters for
+ * various entities of the plot. A theme has the form:
+ *
+ *
+ * > {
+ * > _name:f "Default",
+ * > target: {
+ * > backgroundColor: "transparent"
+ * > },
+ * > legend: {
+ * > textColor: null,
+ * > fontFamily: null,
+ * > fontSize: null,
+ * > border: null,
+ * > background: null
+ * > },
+ * > title: {
+ * > textColor: "rgb(102, 102, 102)",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
+ * > fontSize: "19.2px",
+ * > textAlign: "center"
+ * > },
+ * > seriesStyles: {},
+ * > series: [{
+ * > color: "#4bb2c5",
+ * > lineWidth: 2.5,
+ * > linePattern: "solid",
+ * > shadow: true,
+ * > fillColor: "#4bb2c5",
+ * > showMarker: true,
+ * > markerOptions: {
+ * > color: "#4bb2c5",
+ * > show: true,
+ * > style: 'filledCircle',
+ * > lineWidth: 1.5,
+ * > size: 4,
+ * > shadow: true
+ * > }
+ * > }],
+ * > grid: {
+ * > drawGridlines: true,
+ * > gridLineColor: "#cccccc",
+ * > gridLineWidth: 1,
+ * > backgroundColor: "#fffdf6",
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > shadow: true
+ * > },
+ * > axesStyles: {
+ * > label: {},
+ * > ticks: {}
+ * > },
+ * > axes: {
+ * > xaxis: {
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > ticks: {
+ * > show: true,
+ * > showGridline: true,
+ * > showLabel: true,
+ * > showMark: true,
+ * > size: 4,
+ * > textColor: "",
+ * > whiteSpace: "nowrap",
+ * > fontSize: "12px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
+ * > },
+ * > label: {
+ * > textColor: "rgb(102, 102, 102)",
+ * > whiteSpace: "normal",
+ * > fontSize: "14.6667px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
+ * > fontWeight: "400"
+ * > }
+ * > },
+ * > yaxis: {
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > ticks: {
+ * > show: true,
+ * > showGridline: true,
+ * > showLabel: true,
+ * > showMark: true,
+ * > size: 4,
+ * > textColor: "",
+ * > whiteSpace: "nowrap",
+ * > fontSize: "12px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
+ * > },
+ * > label: {
+ * > textColor: null,
+ * > whiteSpace: null,
+ * > fontSize: null,
+ * > fontFamily: null,
+ * > fontWeight: null
+ * > }
+ * > },
+ * > x2axis: {...
+ * > },
+ * > ...
+ * > y9axis: {...
+ * > }
+ * > }
+ * > }
+ *
+ * "seriesStyles" is a style object that will be applied to all series in the plot.
+ * It will forcibly override any styles applied on the individual series. "axesStyles" is
+ * a style object that will be applied to all axes in the plot. It will also forcibly
+ * override any styles on the individual axes.
+ *
+ * The example shown above has series options for a line series. Options for other
+ * series types are shown below:
+ *
+ * Bar Series:
+ *
+ * > {
+ * > color: "#4bb2c5",
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > lineWidth: 2.5,
+ * > shadow: true,
+ * > barPadding: 2,
+ * > barMargin: 10,
+ * > barWidth: 15.09375,
+ * > highlightColors: ["rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)"]
+ * > }
+ *
+ * Pie Series:
+ *
+ * > {
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > padding: 20,
+ * > sliceMargin: 0,
+ * > fill: true,
+ * > shadow: true,
+ * > startAngle: 0,
+ * > lineWidth: 2.5,
+ * > highlightColors: ["rgb(129,201,214)", "rgb(240,189,104)", "rgb(214,202,165)", "rgb(137,180,158)", "rgb(168,180,137)", "rgb(180,174,89)", "rgb(180,113,161)", "rgb(129,141,236)", "rgb(227,205,120)", "rgb(255,138,76)", "rgb(76,169,219)", "rgb(215,126,190)", "rgb(220,232,135)", "rgb(200,167,96)", "rgb(103,202,235)", "rgb(208,154,215)"]
+ * > }
+ *
+ * Funnel Series:
+ *
+ * > {
+ * > color: "#4bb2c5",
+ * > lineWidth: 2,
+ * > shadow: true,
+ * > padding: {
+ * > top: 20,
+ * > right: 20,
+ * > bottom: 20,
+ * > left: 20
+ * > },
+ * > sectionMargin: 6,
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > highlightColors: ["rgb(147,208,220)", "rgb(242,199,126)", "rgb(220,210,178)", "rgb(154,191,172)", "rgb(180,191,154)", "rgb(191,186,112)", "rgb(191,133,174)", "rgb(147,157,238)", "rgb(231,212,139)", "rgb(255,154,102)", "rgb(102,181,224)", "rgb(221,144,199)", "rgb(225,235,152)", "rgb(200,167,96)", "rgb(124,210,238)", "rgb(215,169,221)"]
+ * > }
+ *
+ */
+ $.jqplot.ThemeEngine = function(){
+ // Group: Properties
+ //
+ // prop: themes
+ // hash of themes managed by the theme engine.
+ // Indexed by theme name.
+ this.themes = {};
+ // prop: activeTheme
+ // Pointer to currently active theme
+ this.activeTheme=null;
+
+ };
+
+ // called with scope of plot
+ $.jqplot.ThemeEngine.prototype.init = function() {
+ // get the Default theme from the current plot settings.
+ var th = new $.jqplot.Theme({_name:'Default'});
+ var n, i, nn;
+
+ for (n in th.target) {
+ if (n == "textColor") {
+ th.target[n] = this.target.css('color');
+ }
+ else {
+ th.target[n] = this.target.css(n);
+ }
+ }
+
+ if (this.title.show && this.title._elem) {
+ for (n in th.title) {
+ if (n == "textColor") {
+ th.title[n] = this.title._elem.css('color');
+ }
+ else {
+ th.title[n] = this.title._elem.css(n);
+ }
+ }
+ }
+
+ for (n in th.grid) {
+ th.grid[n] = this.grid[n];
+ }
+ if (th.grid.backgroundColor == null && this.grid.background != null) {
+ th.grid.backgroundColor = this.grid.background;
+ }
+ if (this.legend.show && this.legend._elem) {
+ for (n in th.legend) {
+ if (n == 'textColor') {
+ th.legend[n] = this.legend._elem.css('color');
+ }
+ else {
+ th.legend[n] = this.legend._elem.css(n);
+ }
+ }
+ }
+ var s;
+
+ for (i=0; i<this.series.length; i++) {
+ s = this.series[i];
+ if (s.renderer.constructor == $.jqplot.LineRenderer) {
+ th.series.push(new LineSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.BarRenderer) {
+ th.series.push(new BarSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.PieRenderer) {
+ th.series.push(new PieSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.DonutRenderer) {
+ th.series.push(new DonutSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.FunnelRenderer) {
+ th.series.push(new FunnelSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.MeterGaugeRenderer) {
+ th.series.push(new MeterSeriesProperties());
+ }
+ else {
+ th.series.push({});
+ }
+ for (n in th.series[i]) {
+ th.series[i][n] = s[n];
+ }
+ }
+ var a, ax;
+ for (n in this.axes) {
+ ax = this.axes[n];
+ a = th.axes[n] = new AxisProperties();
+ a.borderColor = ax.borderColor;
+ a.borderWidth = ax.borderWidth;
+ if (ax._ticks && ax._ticks[0]) {
+ for (nn in a.ticks) {
+ if (ax._ticks[0].hasOwnProperty(nn)) {
+ a.ticks[nn] = ax._ticks[0][nn];
+ }
+ else if (ax._ticks[0]._elem){
+ a.ticks[nn] = ax._ticks[0]._elem.css(nn);
+ }
+ }
+ }
+ if (ax._label && ax._label.show) {
+ for (nn in a.label) {
+ // a.label[nn] = ax._label._elem.css(nn);
+ if (ax._label[nn]) {
+ a.label[nn] = ax._label[nn];
+ }
+ else if (ax._label._elem){
+ if (nn == 'textColor') {
+ a.label[nn] = ax._label._elem.css('color');
+ }
+ else {
+ a.label[nn] = ax._label._elem.css(nn);
+ }
+ }
+ }
+ }
+ }
+ this.themeEngine._add(th);
+ this.themeEngine.activeTheme = this.themeEngine.themes[th._name];
+ };
+ /**
+ * Group: methods
+ *
+ * method: get
+ *
+ * Get and return the named theme or the active theme if no name given.
+ *
+ * parameter:
+ *
+ * name - name of theme to get.
+ *
+ * returns:
+ *
+ * Theme instance of given name.
+ */
+ $.jqplot.ThemeEngine.prototype.get = function(name) {
+ if (!name) {
+ // return the active theme
+ return this.activeTheme;
+ }
+ else {
+ return this.themes[name];
+ }
+ };
+
+ function numericalOrder(a,b) { return a-b; }
+
+ /**
+ * method: getThemeNames
+ *
+ * Return the list of theme names in this manager in alpha-numerical order.
+ *
+ * parameter:
+ *
+ * None
+ *
+ * returns:
+ *
+ * A the list of theme names in this manager in alpha-numerical order.
+ */
+ $.jqplot.ThemeEngine.prototype.getThemeNames = function() {
+ var tn = [];
+ for (var n in this.themes) {
+ tn.push(n);
+ }
+ return tn.sort(numericalOrder);
+ };
+
+ /**
+ * method: getThemes
+ *
+ * Return a list of themes in alpha-numerical order by name.
+ *
+ * parameter:
+ *
+ * None
+ *
+ * returns:
+ *
+ * A list of themes in alpha-numerical order by name.
+ */
+ $.jqplot.ThemeEngine.prototype.getThemes = function() {
+ var tn = [];
+ var themes = [];
+ for (var n in this.themes) {
+ tn.push(n);
+ }
+ tn.sort(numericalOrder);
+ for (var i=0; i<tn.length; i++) {
+ themes.push(this.themes[tn[i]]);
+ }
+ return themes;
+ };
+
+ $.jqplot.ThemeEngine.prototype.activate = function(plot, name) {
+ // sometimes need to redraw whole plot.
+ var redrawPlot = false;
+ if (!name && this.activeTheme && this.activeTheme._name) {
+ name = this.activeTheme._name;
+ }
+ if (!this.themes.hasOwnProperty(name)) {
+ throw new Error("No theme of that name");
+ }
+ else {
+ var th = this.themes[name];
+ this.activeTheme = th;
+ var val, checkBorderColor = false, checkBorderWidth = false;
+ var arr = ['xaxis', 'x2axis', 'yaxis', 'y2axis'];
+
+ for (i=0; i<arr.length; i++) {
+ var ax = arr[i];
+ if (th.axesStyles.borderColor != null) {
+ plot.axes[ax].borderColor = th.axesStyles.borderColor;
+ }
+ if (th.axesStyles.borderWidth != null) {
+ plot.axes[ax].borderWidth = th.axesStyles.borderWidth;
+ }
+ }
+
+ for (var axname in plot.axes) {
+ var axis = plot.axes[axname];
+ if (axis.show) {
+ var thaxis = th.axes[axname] || {};
+ var thaxstyle = th.axesStyles;
+ var thax = $.jqplot.extend(true, {}, thaxis, thaxstyle);
+ val = (th.axesStyles.borderColor != null) ? th.axesStyles.borderColor : thax.borderColor;
+ if (thax.borderColor != null) {
+ axis.borderColor = thax.borderColor;
+ redrawPlot = true;
+ }
+ val = (th.axesStyles.borderWidth != null) ? th.axesStyles.borderWidth : thax.borderWidth;
+ if (thax.borderWidth != null) {
+ axis.borderWidth = thax.borderWidth;
+ redrawPlot = true;
+ }
+ if (axis._ticks && axis._ticks[0]) {
+ for (var nn in thax.ticks) {
+ // val = null;
+ // if (th.axesStyles.ticks && th.axesStyles.ticks[nn] != null) {
+ // val = th.axesStyles.ticks[nn];
+ // }
+ // else if (thax.ticks[nn] != null){
+ // val = thax.ticks[nn]
+ // }
+ val = thax.ticks[nn];
+ if (val != null) {
+ axis.tickOptions[nn] = val;
+ axis._ticks = [];
+ redrawPlot = true;
+ }
+ }
+ }
+ if (axis._label && axis._label.show) {
+ for (var nn in thax.label) {
+ // val = null;
+ // if (th.axesStyles.label && th.axesStyles.label[nn] != null) {
+ // val = th.axesStyles.label[nn];
+ // }
+ // else if (thax.label && thax.label[nn] != null){
+ // val = thax.label[nn]
+ // }
+ val = thax.label[nn];
+ if (val != null) {
+ axis.labelOptions[nn] = val;
+ redrawPlot = true;
+ }
+ }
+ }
+
+ }
+ }
+
+ for (var n in th.grid) {
+ if (th.grid[n] != null) {
+ plot.grid[n] = th.grid[n];
+ }
+ }
+ if (!redrawPlot) {
+ plot.grid.draw();
+ }
+
+ if (plot.legend.show) {
+ for (n in th.legend) {
+ if (th.legend[n] != null) {
+ plot.legend[n] = th.legend[n];
+ }
+ }
+ }
+ if (plot.title.show) {
+ for (n in th.title) {
+ if (th.title[n] != null) {
+ plot.title[n] = th.title[n];
+ }
+ }
+ }
+
+ var i;
+ for (i=0; i<th.series.length; i++) {
+ var opts = {};
+ var redrawSeries = false;
+ for (n in th.series[i]) {
+ val = (th.seriesStyles[n] != null) ? th.seriesStyles[n] : th.series[i][n];
+ if (val != null) {
+ opts[n] = val;
+ if (n == 'color') {
+ plot.series[i].renderer.shapeRenderer.fillStyle = val;
+ plot.series[i].renderer.shapeRenderer.strokeStyle = val;
+ plot.series[i][n] = val;
+ }
+ else if ((n == 'lineWidth') || (n == 'linePattern')) {
+ plot.series[i].renderer.shapeRenderer[n] = val;
+ plot.series[i][n] = val;
+ }
+ else if (n == 'markerOptions') {
+ merge (plot.series[i].markerOptions, val);
+ merge (plot.series[i].markerRenderer, val);
+ }
+ else {
+ plot.series[i][n] = val;
+ }
+ redrawPlot = true;
+ }
+ }
+ }
+
+ if (redrawPlot) {
+ plot.target.empty();
+ plot.draw();
+ }
+
+ for (n in th.target) {
+ if (th.target[n] != null) {
+ plot.target.css(n, th.target[n]);
+ }
+ }
+ }
+
+ };
+
+ $.jqplot.ThemeEngine.prototype._add = function(theme, name) {
+ if (name) {
+ theme._name = name;
+ }
+ if (!theme._name) {
+ theme._name = Date.parse(new Date());
+ }
+ if (!this.themes.hasOwnProperty(theme._name)) {
+ this.themes[theme._name] = theme;
+ }
+ else {
+ throw new Error("jqplot.ThemeEngine Error: Theme already in use");
+ }
+ };
+
+ // method remove
+ // Delete the named theme, return true on success, false on failure.
+
+
+ /**
+ * method: remove
+ *
+ * Remove the given theme from the themeEngine.
+ *
+ * parameters:
+ *
+ * name - name of the theme to remove.
+ *
+ * returns:
+ *
+ * true on success, false on failure.
+ */
+ $.jqplot.ThemeEngine.prototype.remove = function(name) {
+ if (name == 'Default') {
+ return false;
+ }
+ return delete this.themes[name];
+ };
+
+ /**
+ * method: newTheme
+ *
+ * Create a new theme based on the default theme, adding it the themeEngine.
+ *
+ * parameters:
+ *
+ * name - name of the new theme.
+ * obj - optional object of styles to be applied to this new theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.newTheme = function(name, obj) {
+ if (typeof(name) == 'object') {
+ obj = obj || name;
+ name = null;
+ }
+ if (obj && obj._name) {
+ name = obj._name;
+ }
+ else {
+ name = name || Date.parse(new Date());
+ }
+ // var th = new $.jqplot.Theme(name);
+ var th = this.copy(this.themes['Default']._name, name);
+ $.jqplot.extend(th, obj);
+ return th;
+ };
+
+ // function clone(obj) {
+ // return eval(obj.toSource());
+ // }
+
+ function clone(obj){
+ if(obj == null || typeof(obj) != 'object'){
+ return obj;
+ }
+
+ var temp = new obj.constructor();
+ for(var key in obj){
+ temp[key] = clone(obj[key]);
+ }
+ return temp;
+ }
+
+ $.jqplot.clone = clone;
+
+ function merge(obj1, obj2) {
+ if (obj2 == null || typeof(obj2) != 'object') {
+ return;
+ }
+ for (var key in obj2) {
+ if (key == 'highlightColors') {
+ obj1[key] = clone(obj2[key]);
+ }
+ if (obj2[key] != null && typeof(obj2[key]) == 'object') {
+ if (!obj1.hasOwnProperty(key)) {
+ obj1[key] = {};
+ }
+ merge(obj1[key], obj2[key]);
+ }
+ else {
+ obj1[key] = obj2[key];
+ }
+ }
+ }
+
+ $.jqplot.merge = merge;
+
+ // Use the jQuery 1.3.2 extend function since behaviour in jQuery 1.4 seems problematic
+ $.jqplot.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !toString.call(target) === "[object Function]" ) {
+ target = {};
+ }
+
+ for ( ; i < length; i++ ){
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( var name in options ) {
+ var src = target[ name ], copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging object values
+ if ( deep && copy && typeof copy === "object" && !copy.nodeType ) {
+ target[ name ] = $.jqplot.extend( deep,
+ // Never move original objects, clone them
+ src || ( copy.length != null ? [ ] : { } )
+ , copy );
+ }
+ // Don't bring in undefined values
+ else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+ // Return the modified object
+ return target;
+ };
+
+ /**
+ * method: rename
+ *
+ * Rename a theme.
+ *
+ * parameters:
+ *
+ * oldName - current name of the theme.
+ * newName - desired name of the theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.rename = function (oldName, newName) {
+ if (oldName == 'Default' || newName == 'Default') {
+ throw new Error ("jqplot.ThemeEngine Error: Cannot rename from/to Default");
+ }
+ if (this.themes.hasOwnProperty(newName)) {
+ throw new Error ("jqplot.ThemeEngine Error: New name already in use.");
+ }
+ else if (this.themes.hasOwnProperty(oldName)) {
+ var th = this.copy (oldName, newName);
+ this.remove(oldName);
+ return th;
+ }
+ throw new Error("jqplot.ThemeEngine Error: Old name or new name invalid");
+ };
+
+ /**
+ * method: copy
+ *
+ * Create a copy of an existing theme in the themeEngine, adding it the themeEngine.
+ *
+ * parameters:
+ *
+ * sourceName - name of the existing theme.
+ * targetName - name of the copy.
+ * obj - optional object of style parameter to apply to the new theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.copy = function (sourceName, targetName, obj) {
+ if (targetName == 'Default') {
+ throw new Error ("jqplot.ThemeEngine Error: Cannot copy over Default theme");
+ }
+ if (!this.themes.hasOwnProperty(sourceName)) {
+ var s = "jqplot.ThemeEngine Error: Source name invalid";
+ throw new Error(s);
+ }
+ if (this.themes.hasOwnProperty(targetName)) {
+ var s = "jqplot.ThemeEngine Error: Target name invalid";
+ throw new Error(s);
+ }
+ else {
+ var th = clone(this.themes[sourceName]);
+ th._name = targetName;
+ $.jqplot.extend(true, th, obj);
+ this._add(th);
+ return th;
+ }
+ };
+
+
+ $.jqplot.Theme = function(name, obj) {
+ if (typeof(name) == 'object') {
+ obj = obj || name;
+ name = null;
+ }
+ name = name || Date.parse(new Date());
+ this._name = name;
+ this.target = {
+ backgroundColor: null
+ };
+ this.legend = {
+ textColor: null,
+ fontFamily: null,
+ fontSize: null,
+ border: null,
+ background: null
+ };
+ this.title = {
+ textColor: null,
+ fontFamily: null,
+ fontSize: null,
+ textAlign: null
+ };
+ this.seriesStyles = {};
+ this.series = [];
+ this.grid = {
+ drawGridlines: null,
+ gridLineColor: null,
+ gridLineWidth: null,
+ backgroundColor: null,
+ borderColor: null,
+ borderWidth: null,
+ shadow: null
+ };
+ this.axesStyles = {label:{}, ticks:{}};
+ this.axes = {};
+ if (typeof(obj) == 'string') {
+ this._name = obj;
+ }
+ else if(typeof(obj) == 'object') {
+ $.jqplot.extend(true, this, obj);
+ }
+ };
+
+ var AxisProperties = function() {
+ this.borderColor = null;
+ this.borderWidth = null;
+ this.ticks = new AxisTicks();
+ this.label = new AxisLabel();
+ };
+
+ var AxisTicks = function() {
+ this.show = null;
+ this.showGridline = null;
+ this.showLabel = null;
+ this.showMark = null;
+ this.size = null;
+ this.textColor = null;
+ this.whiteSpace = null;
+ this.fontSize = null;
+ this.fontFamily = null;
+ };
+
+ var AxisLabel = function() {
+ this.textColor = null;
+ this.whiteSpace = null;
+ this.fontSize = null;
+ this.fontFamily = null;
+ this.fontWeight = null;
+ };
+
+ var LineSeriesProperties = function() {
+ this.color=null;
+ this.lineWidth=null;
+ this.linePattern=null;
+ this.shadow=null;
+ this.fillColor=null;
+ this.showMarker=null;
+ this.markerOptions = new MarkerOptions();
+ };
+
+ var MarkerOptions = function() {
+ this.show = null;
+ this.style = null;
+ this.lineWidth = null;
+ this.size = null;
+ this.color = null;
+ this.shadow = null;
+ };
+
+ var BarSeriesProperties = function() {
+ this.color=null;
+ this.seriesColors=null;
+ this.lineWidth=null;
+ this.shadow=null;
+ this.barPadding=null;
+ this.barMargin=null;
+ this.barWidth=null;
+ this.highlightColors=null;
+ };
+
+ var PieSeriesProperties = function() {
+ this.seriesColors=null;
+ this.padding=null;
+ this.sliceMargin=null;
+ this.fill=null;
+ this.shadow=null;
+ this.startAngle=null;
+ this.lineWidth=null;
+ this.highlightColors=null;
+ };
+
+ var DonutSeriesProperties = function() {
+ this.seriesColors=null;
+ this.padding=null;
+ this.sliceMargin=null;
+ this.fill=null;
+ this.shadow=null;
+ this.startAngle=null;
+ this.lineWidth=null;
+ this.innerDiameter=null;
+ this.thickness=null;
+ this.ringMargin=null;
+ this.highlightColors=null;
+ };
+
+ var FunnelSeriesProperties = function() {
+ this.color=null;
+ this.lineWidth=null;
+ this.shadow=null;
+ this.padding=null;
+ this.sectionMargin=null;
+ this.seriesColors=null;
+ this.highlightColors=null;
+ };
+
+ var MeterSeriesProperties = function() {
+ this.padding=null;
+ this.backgroundColor=null;
+ this.ringColor=null;
+ this.tickColor=null;
+ this.ringWidth=null;
+ this.intervalColors=null;
+ this.intervalInnerRadius=null;
+ this.intervalOuterRadius=null;
+ this.hubRadius=null;
+ this.needleThickness=null;
+ this.needlePad=null;
+ };
+
+
+
+
+ $.fn.jqplotChildText = function() {
+ return $(this).contents().filter(function() {
+ return this.nodeType == 3; // Node.TEXT_NODE not defined in I7
+ }).text();
+ };
+
+ // Returns font style as abbreviation for "font" property.
+ $.fn.jqplotGetComputedFontStyle = function() {
+ var css = window.getComputedStyle ? window.getComputedStyle(this[0], "") : this[0].currentStyle;
+ var attrs = css['font-style'] ? ['font-style', 'font-weight', 'font-size', 'font-family'] : ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily'];
+ var style = [];
+
+ for (var i=0 ; i < attrs.length; ++i) {
+ var attr = String(css[attrs[i]]);
+
+ if (attr && attr != 'normal') {
+ style.push(attr);
+ }
+ }
+ return style.join(' ');
+ };
+
+ /**
+ * Namespace: $.fn
+ * jQuery namespace to attach functions to jQuery elements.
+ *
+ */
+
+ $.fn.jqplotToImageCanvas = function(options) {
+
+ options = options || {};
+ var x_offset = (options.x_offset == null) ? 0 : options.x_offset;
+ var y_offset = (options.y_offset == null) ? 0 : options.y_offset;
+ var backgroundColor = (options.backgroundColor == null) ? 'rgb(255,255,255)' : options.backgroundColor;
+
+ if ($(this).width() == 0 || $(this).height() == 0) {
+ return null;
+ }
+
+ // excanvas and hence IE < 9 do not support toDataURL and cannot export images.
+ if ($.jqplot.use_excanvas) {
+ return null;
+ }
+
+ var newCanvas = document.createElement("canvas");
+ var h = $(this).outerHeight(true);
+ var w = $(this).outerWidth(true);
+ var offs = $(this).offset();
+ var plotleft = offs.left;
+ var plottop = offs.top;
+ var transx = 0, transy = 0;
+
+ // have to check if any elements are hanging outside of plot area before rendering,
+ // since changing width of canvas will erase canvas.
+
+ var clses = ['jqplot-table-legend', 'jqplot-xaxis-tick', 'jqplot-x2axis-tick', 'jqplot-yaxis-tick', 'jqplot-y2axis-tick', 'jqplot-y3axis-tick',
+ 'jqplot-y4axis-tick', 'jqplot-y5axis-tick', 'jqplot-y6axis-tick', 'jqplot-y7axis-tick', 'jqplot-y8axis-tick', 'jqplot-y9axis-tick',
+ 'jqplot-xaxis-label', 'jqplot-x2axis-label', 'jqplot-yaxis-label', 'jqplot-y2axis-label', 'jqplot-y3axis-label', 'jqplot-y4axis-label',
+ 'jqplot-y5axis-label', 'jqplot-y6axis-label', 'jqplot-y7axis-label', 'jqplot-y8axis-label', 'jqplot-y9axis-label' ];
+
+ var temptop, templeft, tempbottom, tempright;
+
+ for (var i = 0; i < clses.length; i++) {
+ $(this).find('.'+clses[i]).each(function() {
+ temptop = $(this).offset().top - plottop;
+ templeft = $(this).offset().left - plotleft;
+ tempright = templeft + $(this).outerWidth(true) + transx;
+ tempbottom = temptop + $(this).outerHeight(true) + transy;
+ if (templeft < -transx) {
+ w = w - transx - templeft;
+ transx = -templeft;
+ }
+ if (temptop < -transy) {
+ h = h - transy - temptop;
+ transy = - temptop;
+ }
+ if (tempright > w) {
+ w = tempright;
+ }
+ if (tempbottom > h) {
+ h = tempbottom;
+ }
+ });
+ }
+
+ newCanvas.width = w + Number(x_offset);
+ newCanvas.height = h + Number(y_offset);
+
+ var newContext = newCanvas.getContext("2d");
+
+ newContext.save();
+ newContext.fillStyle = backgroundColor;
+ newContext.fillRect(0,0, newCanvas.width, newCanvas.height);
+ newContext.restore();
+
+ newContext.translate(transx, transy);
+ newContext.textAlign = 'left';
+ newContext.textBaseline = 'top';
+
+ function getLineheight(el) {
+ var lineheight = parseInt($(el).css('line-height'), 10);
+
+ if (isNaN(lineheight)) {
+ lineheight = parseInt($(el).css('font-size'), 10) * 1.2;
+ }
+ return lineheight;
+ }
+
+ function writeWrappedText (el, context, text, left, top, canvasWidth) {
+ var lineheight = getLineheight(el);
+ var tagwidth = $(el).innerWidth();
+ var tagheight = $(el).innerHeight();
+ var words = text.split(/\s+/);
+ var wl = words.length;
+ var w = '';
+ var breaks = [];
+ var temptop = top;
+ var templeft = left;
+
+ for (var i=0; i<wl; i++) {
+ w += words[i];
+ if (context.measureText(w).width > tagwidth) {
+ breaks.push(i);
+ w = '';
+ i--;
+ }
+ }
+ if (breaks.length === 0) {
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(text, templeft, top);
+ }
+ else {
+ w = words.slice(0, breaks[0]).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ temptop += lineheight;
+ for (var i=1, l=breaks.length; i<l; i++) {
+ w = words.slice(breaks[i-1], breaks[i]).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ temptop += lineheight;
+ }
+ w = words.slice(breaks[i-1], words.length).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ }
+
+ }
+
+ function _jqpToImage(el, x_offset, y_offset) {
+ var tagname = el.tagName.toLowerCase();
+ var p = $(el).position();
+ var css = window.getComputedStyle ? window.getComputedStyle(el, "") : el.currentStyle; // for IE < 9
+ var left = x_offset + p.left + parseInt(css.marginLeft, 10) + parseInt(css.borderLeftWidth, 10) + parseInt(css.paddingLeft, 10);
+ var top = y_offset + p.top + parseInt(css.marginTop, 10) + parseInt(css.borderTopWidth, 10)+ parseInt(css.paddingTop, 10);
+ var w = newCanvas.width;
+ // var left = x_offset + p.left + $(el).css('marginLeft') + $(el).css('borderLeftWidth')
+
+ // somehow in here, for divs within divs, the width of the inner div should be used instead of the canvas.
+
+ if ((tagname == 'div' || tagname == 'span') && !$(el).hasClass('jqplot-highlighter-tooltip')) {
+ $(el).children().each(function() {
+ _jqpToImage(this, left, top);
+ });
+ var text = $(el).jqplotChildText();
+
+ if (text) {
+ newContext.font = $(el).jqplotGetComputedFontStyle();
+ newContext.fillStyle = $(el).css('color');
+
+ writeWrappedText(el, newContext, text, left, top, w);
+ }
+ }
+
+ // handle the standard table legend
+
+ else if (tagname === 'table' && $(el).hasClass('jqplot-table-legend')) {
+ newContext.strokeStyle = $(el).css('border-top-color');
+ newContext.fillStyle = $(el).css('background-color');
+ newContext.fillRect(left, top, $(el).innerWidth(), $(el).innerHeight());
+ if (parseInt($(el).css('border-top-width'), 10) > 0) {
+ newContext.strokeRect(left, top, $(el).innerWidth(), $(el).innerHeight());
+ }
+
+ // find all the swatches
+ $(el).find('div.jqplot-table-legend-swatch-outline').each(function() {
+ // get the first div and stroke it
+ var elem = $(this);
+ newContext.strokeStyle = elem.css('border-top-color');
+ var l = left + elem.position().left;
+ var t = top + elem.position().top;
+ newContext.strokeRect(l, t, elem.innerWidth(), elem.innerHeight());
+
+ // now fill the swatch
+
+ l += parseInt(elem.css('padding-left'), 10);
+ t += parseInt(elem.css('padding-top'), 10);
+ var h = elem.innerHeight() - 2 * parseInt(elem.css('padding-top'), 10);
+ var w = elem.innerWidth() - 2 * parseInt(elem.css('padding-left'), 10);
+
+ var swatch = elem.children('div.jqplot-table-legend-swatch');
+ newContext.fillStyle = swatch.css('background-color');
+ newContext.fillRect(l, t, w, h);
+ });
+
+ // now add text
+
+ $(el).find('td.jqplot-table-legend-label').each(function(){
+ var elem = $(this);
+ var l = left + elem.position().left;
+ var t = top + elem.position().top + parseInt(elem.css('padding-top'), 10);
+ newContext.font = elem.jqplotGetComputedFontStyle();
+ newContext.fillStyle = elem.css('color');
+ writeWrappedText(elem, newContext, elem.text(), l, t, w);
+ });
+
+ var elem = null;
+ }
+
+ else if (tagname == 'canvas') {
+ newContext.drawImage(el, left, top);
+ }
+ }
+ $(this).children().each(function() {
+ _jqpToImage(this, x_offset, y_offset);
+ });
+ return newCanvas;
+ };
+
+ // return the raw image data string.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageStr = function(options) {
+ var imgCanvas = $(this).jqplotToImageCanvas(options);
+ if (imgCanvas) {
+ return imgCanvas.toDataURL("image/png");
+ }
+ else {
+ return null;
+ }
+ };
+
+ // return a DOM <img> element and return it.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageElem = function(options) {
+ var elem = document.createElement("img");
+ var str = $(this).jqplotToImageStr(options);
+ elem.src = str;
+ return elem;
+ };
+
+ // return a string for an <img> element and return it.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageElemStr = function(options) {
+ var str = '<img src='+$(this).jqplotToImageStr(options)+' />';
+ return str;
+ };
+
+ // Not gauranteed to work, even on canvas supporting browsers due to
+ // limitations with location.href and browser support.
+ $.fn.jqplotSaveImage = function() {
+ var imgData = $(this).jqplotToImageStr({});
+ if (imgData) {
+ window.location.href = imgData.replace("image/png", "image/octet-stream");
+ }
+
+ };
+
+ // Not gauranteed to work, even on canvas supporting browsers due to
+ // limitations with window.open and arbitrary data.
+ $.fn.jqplotViewImage = function() {
+ var imgStr = $(this).jqplotToImageElemStr({});
+ var imgData = $(this).jqplotToImageStr({});
+ if (imgStr) {
+ var w = window.open('');
+ w.document.open("image/png");
+ w.document.write(imgStr);
+ w.document.close();
+ w = null;
+ }
+ };
+
+
+
+
+ /**
+ * @description
+ * <p>Object with extended date parsing and formatting capabilities.
+ * This library borrows many concepts and ideas from the Date Instance
+ * Methods by Ken Snyder along with some parts of Ken's actual code.</p>
+ *
+ * <p>jsDate takes a different approach by not extending the built-in
+ * Date Object, improving date parsing, allowing for multiple formatting
+ * syntaxes and multiple and more easily expandable localization.</p>
+ *
+ * @author Chris Leonello
+ * @date #date#
+ * @version #VERSION#
+ * @copyright (c) 2010 Chris Leonello
+ * jsDate is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * <p>Ken's origianl Date Instance Methods and copyright notice:</p>
+ * <pre>
+ * Ken Snyder (ken d snyder at gmail dot com)
+ * 2008-09-10
+ * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
+ * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
+ * </pre>
+ *
+ * @class
+ * @name jsDate
+ * @param {String | Number | Array | Date&nbsp;Object | Options&nbsp;Object} arguments Optional arguments, either a parsable date/time string,
+ * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
+ * a Date object, or an options object of form {syntax: "perl", date:some Date} where all options are optional.
+ */
+
+ var jsDate = function () {
+
+ this.syntax = jsDate.config.syntax;
+ this._type = "jsDate";
+ this.proxy = new Date();
+ this.options = {};
+ this.locale = jsDate.regional.getLocale();
+ this.formatString = '';
+ this.defaultCentury = jsDate.config.defaultCentury;
+
+ switch ( arguments.length ) {
+ case 0:
+ break;
+ case 1:
+ // other objects either won't have a _type property or,
+ // if they do, it shouldn't be set to "jsDate", so
+ // assume it is an options argument.
+ if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
+ var opts = this.options = arguments[0];
+ this.syntax = opts.syntax || this.syntax;
+ this.defaultCentury = opts.defaultCentury || this.defaultCentury;
+ this.proxy = jsDate.createDate(opts.date);
+ }
+ else {
+ this.proxy = jsDate.createDate(arguments[0]);
+ }
+ break;
+ default:
+ var a = [];
+ for ( var i=0; i<arguments.length; i++ ) {
+ a.push(arguments[i]);
+ }
+ // this should be the current date/time?
+ this.proxy = new Date();
+ this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
+ if ( a.slice(3).length ) {
+ this.proxy.setHours.apply( this.proxy, a.slice(3) );
+ }
+ break;
+ }
+ };
+
+ /**
+ * @namespace Configuration options that will be used as defaults for all instances on the page.
+ * @property {String} defaultLocale The default locale to use [en].
+ * @property {String} syntax The default syntax to use [perl].
+ * @property {Number} defaultCentury The default centry for 2 digit dates.
+ */
+ jsDate.config = {
+ defaultLocale: 'en',
+ syntax: 'perl',
+ defaultCentury: 1900
+ };
+
+ /**
+ * Add an arbitrary amount to the currently stored date
+ *
+ * @param {Number} number
+ * @param {String} unit
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.add = function(number, unit) {
+ var factor = multipliers[unit] || multipliers.day;
+ if (typeof factor == 'number') {
+ this.proxy.setTime(this.proxy.getTime() + (factor * number));
+ } else {
+ factor.add(this, number);
+ }
+ return this;
+ };
+
+ /**
+ * Create a new jqplot.date object with the same date
+ *
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.clone = function() {
+ return new jsDate(this.proxy.getTime());
+ };
+
+ /**
+ * Get the UTC TimeZone Offset of this date in milliseconds.
+ *
+ * @returns {Number}
+ */
+
+ jsDate.prototype.getUtcOffset = function() {
+ return this.proxy.getTimezoneOffset() * 60000;
+ };
+
+ /**
+ * Find the difference between this jsDate and another date.
+ *
+ * @param {String| Number| Array| jsDate&nbsp;Object| Date&nbsp;Object} dateObj
+ * @param {String} unit
+ * @param {Boolean} allowDecimal
+ * @returns {Number} Number of units difference between dates.
+ */
+
+ jsDate.prototype.diff = function(dateObj, unit, allowDecimal) {
+ // ensure we have a Date object
+ dateObj = new jsDate(dateObj);
+ if (dateObj === null) {
+ return null;
+ }
+ // get the multiplying factor integer or factor function
+ var factor = multipliers[unit] || multipliers.day;
+ if (typeof factor == 'number') {
+ // multiply
+ var unitDiff = (this.proxy.getTime() - dateObj.proxy.getTime()) / factor;
+ } else {
+ // run function
+ var unitDiff = factor.diff(this.proxy, dateObj.proxy);
+ }
+ // if decimals are not allowed, round toward zero
+ return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff));
+ };
+
+ /**
+ * Get the abbreviated name of the current week day
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAbbrDayName = function() {
+ return jsDate.regional[this.locale]["dayNamesShort"][this.proxy.getDay()];
+ };
+
+ /**
+ * Get the abbreviated name of the current month
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAbbrMonthName = function() {
+ return jsDate.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()];
+ };
+
+ /**
+ * Get UPPER CASE AM or PM for the current time
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAMPM = function() {
+ return this.proxy.getHours() >= 12 ? 'PM' : 'AM';
+ };
+
+ /**
+ * Get lower case am or pm for the current time
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAmPm = function() {
+ return this.proxy.getHours() >= 12 ? 'pm' : 'am';
+ };
+
+ /**
+ * Get the century (19 for 20th Century)
+ *
+ * @returns {Integer} Century (19 for 20th century).
+ */
+ jsDate.prototype.getCentury = function() {
+ return parseInt(this.proxy.getFullYear()/100, 10);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getDate = function() {
+ return this.proxy.getDate();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getDay = function() {
+ return this.proxy.getDay();
+ };
+
+ /**
+ * Get the Day of week 1 (Monday) thru 7 (Sunday)
+ *
+ * @returns {Integer} Day of week 1 (Monday) thru 7 (Sunday)
+ */
+ jsDate.prototype.getDayOfWeek = function() {
+ var dow = this.proxy.getDay();
+ return dow===0?7:dow;
+ };
+
+ /**
+ * Get the day of the year
+ *
+ * @returns {Integer} 1 - 366, day of the year
+ */
+ jsDate.prototype.getDayOfYear = function() {
+ var d = this.proxy;
+ var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT');
+ ms += d.getTimezoneOffset()*60000;
+ d = null;
+ return parseInt(ms/60000/60/24, 10)+1;
+ };
+
+ /**
+ * Get the name of the current week day
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getDayName = function() {
+ return jsDate.regional[this.locale]["dayNames"][this.proxy.getDay()];
+ };
+
+ /**
+ * Get the week number of the given year, starting with the first Sunday as the first week
+ * @returns {Integer} Week number (13 for the 13th full week of the year).
+ */
+ jsDate.prototype.getFullWeekOfYear = function() {
+ var d = this.proxy;
+ var doy = this.getDayOfYear();
+ var rdow = 6-d.getDay();
+ var woy = parseInt((doy+rdow)/7, 10);
+ return woy;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getFullYear = function() {
+ return this.proxy.getFullYear();
+ };
+
+ /**
+ * Get the GMT offset in hours and minutes (e.g. +06:30)
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getGmtOffset = function() {
+ // divide the minutes offset by 60
+ var hours = this.proxy.getTimezoneOffset() / 60;
+ // decide if we are ahead of or behind GMT
+ var prefix = hours < 0 ? '+' : '-';
+ // remove the negative sign if any
+ hours = Math.abs(hours);
+ // add the +/- to the padded number of hours to : to the padded minutes
+ return prefix + addZeros(Math.floor(hours), 2) + ':' + addZeros((hours % 1) * 60, 2);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getHours = function() {
+ return this.proxy.getHours();
+ };
+
+ /**
+ * Get the current hour on a 12-hour scheme
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getHours12 = function() {
+ var hours = this.proxy.getHours();
+ return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours);
+ };
+
+
+ jsDate.prototype.getIsoWeek = function() {
+ var d = this.proxy;
+ var woy = d.getWeekOfYear();
+ var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay();
+ // First week is 01 and not 00 as in the case of %U and %W,
+ // so we add 1 to the final result except if day 1 of the year
+ // is a Monday (then %W returns 01).
+ // We also need to subtract 1 if the day 1 of the year is
+ // Friday-Sunday, so the resulting equation becomes:
+ var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
+ if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4)
+ {
+ idow = 1;
+ }
+ else if(idow === 0)
+ {
+ d = new jsDate(new Date('' + (d.getFullYear()-1) + '/12/31'));
+ idow = d.getIsoWeek();
+ }
+ d = null;
+ return idow;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMilliseconds = function() {
+ return this.proxy.getMilliseconds();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMinutes = function() {
+ return this.proxy.getMinutes();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMonth = function() {
+ return this.proxy.getMonth();
+ };
+
+ /**
+ * Get the name of the current month
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getMonthName = function() {
+ return jsDate.regional[this.locale]["monthNames"][this.proxy.getMonth()];
+ };
+
+ /**
+ * Get the number of the current month, 1-12
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getMonthNumber = function() {
+ return this.proxy.getMonth() + 1;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getSeconds = function() {
+ return this.proxy.getSeconds();
+ };
+
+ /**
+ * Return a proper two-digit year integer
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getShortYear = function() {
+ return this.proxy.getYear() % 100;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getTime = function() {
+ return this.proxy.getTime();
+ };
+
+ /**
+ * Get the timezone abbreviation
+ *
+ * @returns {String} Abbreviation for the timezone
+ */
+ jsDate.prototype.getTimezoneAbbr = function() {
+ return this.proxy.toString().replace(/^.*\(([^)]+)\)$/, '$1');
+ };
+
+ /**
+ * Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time)
+ *
+ * @returns {String}
+ */
+ jsDate.prototype.getTimezoneName = function() {
+ var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());
+ return match[1] || match[2] || 'GMT' + this.getGmtOffset();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getTimezoneOffset = function() {
+ return this.proxy.getTimezoneOffset();
+ };
+
+
+ /**
+ * Get the week number of the given year, starting with the first Monday as the first week
+ * @returns {Integer} Week number (13 for the 13th week of the year).
+ */
+ jsDate.prototype.getWeekOfYear = function() {
+ var doy = this.getDayOfYear();
+ var rdow = 7 - this.getDayOfWeek();
+ var woy = parseInt((doy+rdow)/7, 10);
+ return woy;
+ };
+
+ /**
+ * Get the current date as a Unix timestamp
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getUnix = function() {
+ return Math.round(this.proxy.getTime() / 1000, 0);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getYear = function() {
+ return this.proxy.getYear();
+ };
+
+ /**
+ * Return a date one day ahead (or any other unit)
+ *
+ * @param {String} unit Optional, year | month | day | week | hour | minute | second | millisecond
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.next = function(unit) {
+ unit = unit || 'day';
+ return this.clone().add(1, unit);
+ };
+
+ /**
+ * Set the jsDate instance to a new date.
+ *
+ * @param {String | Number | Array | Date Object | jsDate Object | Options Object} arguments Optional arguments,
+ * either a parsable date/time string,
+ * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
+ * a Date object, jsDate Object or an options object of form {syntax: "perl", date:some Date} where all options are optional.
+ */
+ jsDate.prototype.set = function() {
+ switch ( arguments.length ) {
+ case 0:
+ this.proxy = new Date();
+ break;
+ case 1:
+ // other objects either won't have a _type property or,
+ // if they do, it shouldn't be set to "jsDate", so
+ // assume it is an options argument.
+ if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
+ var opts = this.options = arguments[0];
+ this.syntax = opts.syntax || this.syntax;
+ this.defaultCentury = opts.defaultCentury || this.defaultCentury;
+ this.proxy = jsDate.createDate(opts.date);
+ }
+ else {
+ this.proxy = jsDate.createDate(arguments[0]);
+ }
+ break;
+ default:
+ var a = [];
+ for ( var i=0; i<arguments.length; i++ ) {
+ a.push(arguments[i]);
+ }
+ // this should be the current date/time
+ this.proxy = new Date();
+ this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
+ if ( a.slice(3).length ) {
+ this.proxy.setHours.apply( this.proxy, a.slice(3) );
+ }
+ break;
+ }
+ return this;
+ };
+
+ /**
+ * Sets the day of the month for a specified date according to local time.
+ * @param {Integer} dayValue An integer from 1 to 31, representing the day of the month.
+ */
+ jsDate.prototype.setDate = function(n) {
+ this.proxy.setDate(n);
+ return this;
+ };
+
+ /**
+ * Sets the full year for a specified date according to local time.
+ * @param {Integer} yearValue The numeric value of the year, for example, 1995.
+ * @param {Integer} monthValue Optional, between 0 and 11 representing the months January through December.
+ * @param {Integer} dayValue Optional, between 1 and 31 representing the day of the month. If you specify the dayValue parameter, you must also specify the monthValue.
+ */
+ jsDate.prototype.setFullYear = function() {
+ this.proxy.setFullYear.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Sets the hours for a specified date according to local time.
+ *
+ * @param {Integer} hoursValue An integer between 0 and 23, representing the hour.
+ * @param {Integer} minutesValue Optional, An integer between 0 and 59, representing the minutes.
+ * @param {Integer} secondsValue Optional, An integer between 0 and 59, representing the seconds.
+ * If you specify the secondsValue parameter, you must also specify the minutesValue.
+ * @param {Integer} msValue Optional, A number between 0 and 999, representing the milliseconds.
+ * If you specify the msValue parameter, you must also specify the minutesValue and secondsValue.
+ */
+ jsDate.prototype.setHours = function() {
+ this.proxy.setHours.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMilliseconds = function(n) {
+ this.proxy.setMilliseconds(n);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMinutes = function() {
+ this.proxy.setMinutes.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMonth = function() {
+ this.proxy.setMonth.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setSeconds = function() {
+ this.proxy.setSeconds.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setTime = function(n) {
+ this.proxy.setTime(n);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setYear = function() {
+ this.proxy.setYear.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Provide a formatted string representation of this date.
+ *
+ * @param {String} formatString A format string.
+ * See: {@link jsDate.formats}.
+ * @returns {String} Date String.
+ */
+
+ jsDate.prototype.strftime = function(formatString) {
+ formatString = formatString || this.formatString || jsDate.regional[this.locale]['formatString'];
+ return jsDate.strftime(this, formatString, this.syntax);
+ };
+
+ /**
+ * Return a String representation of this jsDate object.
+ * @returns {String} Date string.
+ */
+
+ jsDate.prototype.toString = function() {
+ return this.proxy.toString();
+ };
+
+ /**
+ * Convert the current date to an 8-digit integer (%Y%m%d)
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.toYmdInt = function() {
+ return (this.proxy.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.proxy.getDate();
+ };
+
+ /**
+ * @namespace Holds localizations for month/day names.
+ * <p>jsDate attempts to detect locale when loaded and defaults to 'en'.
+ * If a localization is detected which is not available, jsDate defaults to 'en'.
+ * Additional localizations can be added after jsDate loads. After adding a localization,
+ * call the jsDate.regional.getLocale() method. Currently, en, fr and de are defined.</p>
+ *
+ * <p>Localizations must be an object and have the following properties defined: monthNames, monthNamesShort, dayNames, dayNamesShort and Localizations are added like:</p>
+ * <pre class="code">
+ * jsDate.regional['en'] = {
+ * monthNames : 'January February March April May June July August September October November December'.split(' '),
+ * monthNamesShort : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '),
+ * dayNames : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '),
+ * dayNamesShort : 'Sun Mon Tue Wed Thu Fri Sat'.split(' ')
+ * };
+ * </pre>
+ * <p>After adding localizations, call <code>jsDate.regional.getLocale();</code> to update the locale setting with the
+ * new localizations.</p>
+ */
+
+ jsDate.regional = {
+ 'en': {
+ monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'fr': {
+ monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
+ monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun','Jul','Aoû','Sep','Oct','Nov','Déc'],
+ dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
+ dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'de': {
+ monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
+ monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
+ dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
+ dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'es': {
+ monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
+ monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', 'Jul','Ago','Sep','Oct','Nov','Dic'],
+ dayNames: ['Domingo','Lunes','Martes','Mi&eacute;rcoles','Jueves','Viernes','S&aacute;bado'],
+ dayNamesShort: ['Dom','Lun','Mar','Mi&eacute;','Juv','Vie','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'ru': {
+ monthNames: ['Январь','Февраль','Март','Ðпрель','Май','Июнь','Июль','ÐвгуÑÑ‚','СентÑбрь','ОктÑбрь','ÐоÑбрь','Декабрь'],
+ monthNamesShort: ['Янв','Фев','Мар','Ðпр','Май','Июн','Июл','Ðвг','Сен','Окт','ÐоÑ','Дек'],
+ dayNames: ['воÑкреÑенье','понедельник','вторник','Ñреда','четверг','пÑтница','Ñуббота'],
+ dayNamesShort: ['вÑк','пнд','втр','Ñрд','чтв','птн','Ñбт'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'ar': {
+ monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران','تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],
+ monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
+ dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'],
+ dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'pt': {
+ monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
+ monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
+ dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
+ dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'pt-BR': {
+ monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho', 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
+ monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
+ dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
+ dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ }
+
+
+ };
+
+ // Set english variants to 'en'
+ jsDate.regional['en-US'] = jsDate.regional['en-GB'] = jsDate.regional['en'];
+
+ /**
+ * Try to determine the users locale based on the lang attribute of the html page. Defaults to 'en'
+ * if it cannot figure out a locale of if the locale does not have a localization defined.
+ * @returns {String} locale
+ */
+
+ jsDate.regional.getLocale = function () {
+ var l = jsDate.config.defaultLocale;
+
+ if ( document && document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang ) {
+ l = document.getElementsByTagName('html')[0].lang;
+ if (!jsDate.regional.hasOwnProperty(l)) {
+ l = jsDate.config.defaultLocale;
+ }
+ }
+
+ return l;
+ };
+
+ // ms in day
+ var day = 24 * 60 * 60 * 1000;
+
+ // padd a number with zeros
+ var addZeros = function(num, digits) {
+ num = String(num);
+ var i = digits - num.length;
+ var s = String(Math.pow(10, i)).slice(1);
+ return s.concat(num);
+ };
+
+ // representations used for calculating differences between dates.
+ // This borrows heavily from Ken Snyder's work.
+ var multipliers = {
+ millisecond: 1,
+ second: 1000,
+ minute: 60 * 1000,
+ hour: 60 * 60 * 1000,
+ day: day,
+ week: 7 * day,
+ month: {
+ // add a number of months
+ add: function(d, number) {
+ // add any years needed (increments of 12)
+ multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12));
+ // ensure that we properly wrap betwen December and January
+ // 11 % 12 = 11
+ // 12 % 12 = 0
+ var prevMonth = d.getMonth() + (number % 12);
+ if (prevMonth == 12) {
+ prevMonth = 0;
+ d.setYear(d.getFullYear() + 1);
+ } else if (prevMonth == -1) {
+ prevMonth = 11;
+ d.setYear(d.getFullYear() - 1);
+ }
+ d.setMonth(prevMonth);
+ },
+ // get the number of months between two Date objects (decimal to the nearest day)
+ diff: function(d1, d2) {
+ // get the number of years
+ var diffYears = d1.getFullYear() - d2.getFullYear();
+ // get the number of remaining months
+ var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12);
+ // get the number of remaining days
+ var diffDays = d1.getDate() - d2.getDate();
+ // return the month difference with the days difference as a decimal
+ return diffMonths + (diffDays / 30);
+ }
+ },
+ year: {
+ // add a number of years
+ add: function(d, number) {
+ d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number));
+ },
+ // get the number of years between two Date objects (decimal to the nearest day)
+ diff: function(d1, d2) {
+ return multipliers.month.diff(d1, d2) / 12;
+ }
+ }
+ };
+ //
+ // Alias each multiplier with an 's' to allow 'year' and 'years' for example.
+ // This comes from Ken Snyders work.
+ //
+ for (var unit in multipliers) {
+ if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :|
+ multipliers[unit + 's'] = multipliers[unit];
+ }
+ }
+
+ //
+ // take a jsDate instance and a format code and return the formatted value.
+ // This is a somewhat modified version of Ken Snyder's method.
+ //
+ var format = function(d, code, syntax) {
+ // if shorcut codes are used, recursively expand those.
+ if (jsDate.formats[syntax]["shortcuts"][code]) {
+ return jsDate.strftime(d, jsDate.formats[syntax]["shortcuts"][code], syntax);
+ } else {
+ // get the format code function and addZeros() argument
+ var getter = (jsDate.formats[syntax]["codes"][code] || '').split('.');
+ var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : '';
+ if (getter[1]) {
+ nbr = addZeros(nbr, getter[1]);
+ }
+ return nbr;
+ }
+ };
+
+ /**
+ * @static
+ * Static function for convert a date to a string according to a given format. Also acts as namespace for strftime format codes.
+ * <p>strftime formatting can be accomplished without creating a jsDate object by calling jsDate.strftime():</p>
+ * <pre class="code">
+ * var formattedDate = jsDate.strftime('Feb 8, 2006 8:48:32', '%Y-%m-%d %H:%M:%S');
+ * </pre>
+ * @param {String | Number | Array | jsDate&nbsp;Object | Date&nbsp;Object} date A parsable date string, JavaScript time stamp, Array of form [year, month, day, hours, minutes, seconds, milliseconds], jsDate Object or Date object.
+ * @param {String} formatString String with embedded date formatting codes.
+ * See: {@link jsDate.formats}.
+ * @param {String} syntax Optional syntax to use [default perl].
+ * @param {String} locale Optional locale to use.
+ * @returns {String} Formatted representation of the date.
+ */
+ //
+ // Logic as implemented here is very similar to Ken Snyder's Date Instance Methods.
+ //
+ jsDate.strftime = function(d, formatString, syntax, locale) {
+ var syn = 'perl';
+ var loc = jsDate.regional.getLocale();
+
+ // check if syntax and locale are available or reversed
+ if (syntax && jsDate.formats.hasOwnProperty(syntax)) {
+ syn = syntax;
+ }
+ else if (syntax && jsDate.regional.hasOwnProperty(syntax)) {
+ loc = syntax;
+ }
+
+ if (locale && jsDate.formats.hasOwnProperty(locale)) {
+ syn = locale;
+ }
+ else if (locale && jsDate.regional.hasOwnProperty(locale)) {
+ loc = locale;
+ }
+
+ if (get_type(d) != "[object Object]" || d._type != "jsDate") {
+ d = new jsDate(d);
+ d.locale = loc;
+ }
+ if (!formatString) {
+ formatString = d.formatString || jsDate.regional[loc]['formatString'];
+ }
+ // default the format string to year-month-day
+ var source = formatString || '%Y-%m-%d',
+ result = '',
+ match;
+ // replace each format code
+ while (source.length > 0) {
+ if (match = source.match(jsDate.formats[syn].codes.matcher)) {
+ result += source.slice(0, match.index);
+ result += (match[1] || '') + format(d, match[2], syn);
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source;
+ source = '';
+ }
+ }
+ return result;
+ };
+
+ /**
+ * @namespace
+ * Namespace to hold format codes and format shortcuts. "perl" and "php" format codes
+ * and shortcuts are defined by default. Additional codes and shortcuts can be
+ * added like:
+ *
+ * <pre class="code">
+ * jsDate.formats["perl"] = {
+ * "codes": {
+ * matcher: /someregex/,
+ * Y: "fullYear", // name of "get" method without the "get",
+ * ..., // more codes
+ * },
+ * "shortcuts": {
+ * F: '%Y-%m-%d',
+ * ..., // more shortcuts
+ * }
+ * };
+ * </pre>
+ *
+ * <p>Additionally, ISO and SQL shortcuts are defined and can be accesses via:
+ * <code>jsDate.formats.ISO</code> and <code>jsDate.formats.SQL</code>
+ */
+
+ jsDate.formats = {
+ ISO:'%Y-%m-%dT%H:%M:%S.%N%G',
+ SQL:'%Y-%m-%d %H:%M:%S'
+ };
+
+ /**
+ * Perl format codes and shortcuts for strftime.
+ *
+ * A hash (object) of codes where each code must be an array where the first member is
+ * the name of a Date.prototype or jsDate.prototype function to call
+ * and optionally a second member indicating the number to pass to addZeros()
+ *
+ * <p>The following format codes are defined:</p>
+ *
+ * <pre class="code">
+ * Code Result Description
+ * == Years ==
+ * %Y 2008 Four-digit year
+ * %y 08 Two-digit year
+ *
+ * == Months ==
+ * %m 09 Two-digit month
+ * %#m 9 One or two-digit month
+ * %B September Full month name
+ * %b Sep Abbreviated month name
+ *
+ * == Days ==
+ * %d 05 Two-digit day of month
+ * %#d 5 One or two-digit day of month
+ * %e 5 One or two-digit day of month
+ * %A Sunday Full name of the day of the week
+ * %a Sun Abbreviated name of the day of the week
+ * %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
+ *
+ * == Hours ==
+ * %H 23 Hours in 24-hour format (two digits)
+ * %#H 3 Hours in 24-hour integer format (one or two digits)
+ * %I 11 Hours in 12-hour format (two digits)
+ * %#I 3 Hours in 12-hour integer format (one or two digits)
+ * %p PM AM or PM
+ *
+ * == Minutes ==
+ * %M 09 Minutes (two digits)
+ * %#M 9 Minutes (one or two digits)
+ *
+ * == Seconds ==
+ * %S 02 Seconds (two digits)
+ * %#S 2 Seconds (one or two digits)
+ * %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
+ *
+ * == Milliseconds ==
+ * %N 008 Milliseconds (three digits)
+ * %#N 8 Milliseconds (one to three digits)
+ *
+ * == Timezone ==
+ * %O 360 difference in minutes between local time and GMT
+ * %Z Mountain Standard Time Name of timezone as reported by browser
+ * %G 06:00 Hours and minutes between GMT
+ *
+ * == Shortcuts ==
+ * %F 2008-03-26 %Y-%m-%d
+ * %T 05:06:30 %H:%M:%S
+ * %X 05:06:30 %H:%M:%S
+ * %x 03/26/08 %m/%d/%y
+ * %D 03/26/08 %m/%d/%y
+ * %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
+ * %v 3-Sep-2008 %e-%b-%Y
+ * %R 15:31 %H:%M
+ * %r 03:31:00 PM %I:%M:%S %p
+ *
+ * == Characters ==
+ * %n \n Newline
+ * %t \t Tab
+ * %% % Percent Symbol
+ * </pre>
+ *
+ * <p>Formatting shortcuts that will be translated into their longer version.
+ * Be sure that format shortcuts do not refer to themselves: this will cause an infinite loop.</p>
+ *
+ * <p>Format codes and format shortcuts can be redefined after the jsDate
+ * module is imported.</p>
+ *
+ * <p>Note that if you redefine the whole hash (object), you must supply a "matcher"
+ * regex for the parser. The default matcher is:</p>
+ *
+ * <code>/()%(#?(%|[a-z]))/i</code>
+ *
+ * <p>which corresponds to the Perl syntax used by default.</p>
+ *
+ * <p>By customizing the matcher and format codes, nearly any strftime functionality is possible.</p>
+ */
+
+ jsDate.formats.perl = {
+ codes: {
+ //
+ // 2-part regex matcher for format codes
+ //
+ // first match must be the character before the code (to account for escaping)
+ // second match must be the format code character(s)
+ //
+ matcher: /()%(#?(%|[a-z]))/i,
+ // year
+ Y: 'FullYear',
+ y: 'ShortYear.2',
+ // month
+ m: 'MonthNumber.2',
+ '#m': 'MonthNumber',
+ B: 'MonthName',
+ b: 'AbbrMonthName',
+ // day
+ d: 'Date.2',
+ '#d': 'Date',
+ e: 'Date',
+ A: 'DayName',
+ a: 'AbbrDayName',
+ w: 'Day',
+ // hours
+ H: 'Hours.2',
+ '#H': 'Hours',
+ I: 'Hours12.2',
+ '#I': 'Hours12',
+ p: 'AMPM',
+ // minutes
+ M: 'Minutes.2',
+ '#M': 'Minutes',
+ // seconds
+ S: 'Seconds.2',
+ '#S': 'Seconds',
+ s: 'Unix',
+ // milliseconds
+ N: 'Milliseconds.3',
+ '#N': 'Milliseconds',
+ // timezone
+ O: 'TimezoneOffset',
+ Z: 'TimezoneName',
+ G: 'GmtOffset'
+ },
+
+ shortcuts: {
+ // date
+ F: '%Y-%m-%d',
+ // time
+ T: '%H:%M:%S',
+ X: '%H:%M:%S',
+ // local format date
+ x: '%m/%d/%y',
+ D: '%m/%d/%y',
+ // local format extended
+ '#c': '%a %b %e %H:%M:%S %Y',
+ // local format short
+ v: '%e-%b-%Y',
+ R: '%H:%M',
+ r: '%I:%M:%S %p',
+ // tab and newline
+ t: '\t',
+ n: '\n',
+ '%': '%'
+ }
+ };
+
+ /**
+ * PHP format codes and shortcuts for strftime.
+ *
+ * A hash (object) of codes where each code must be an array where the first member is
+ * the name of a Date.prototype or jsDate.prototype function to call
+ * and optionally a second member indicating the number to pass to addZeros()
+ *
+ * <p>The following format codes are defined:</p>
+ *
+ * <pre class="code">
+ * Code Result Description
+ * === Days ===
+ * %a Sun through Sat An abbreviated textual representation of the day
+ * %A Sunday - Saturday A full textual representation of the day
+ * %d 01 to 31 Two-digit day of the month (with leading zeros)
+ * %e 1 to 31 Day of the month, with a space preceding single digits.
+ * %j 001 to 366 Day of the year, 3 digits with leading zeros
+ * %u 1 - 7 (Mon - Sun) ISO-8601 numeric representation of the day of the week
+ * %w 0 - 6 (Sun - Sat) Numeric representation of the day of the week
+ *
+ * === Week ===
+ * %U 13 Full Week number, starting with the first Sunday as the first week
+ * %V 01 through 53 ISO-8601:1988 week number, starting with the first week of the year
+ * with at least 4 weekdays, with Monday being the start of the week
+ * %W 46 A numeric representation of the week of the year,
+ * starting with the first Monday as the first week
+ * === Month ===
+ * %b Jan through Dec Abbreviated month name, based on the locale
+ * %B January - December Full month name, based on the locale
+ * %h Jan through Dec Abbreviated month name, based on the locale (an alias of %b)
+ * %m 01 - 12 (Jan - Dec) Two digit representation of the month
+ *
+ * === Year ===
+ * %C 19 Two digit century (year/100, truncated to an integer)
+ * %y 09 for 2009 Two digit year
+ * %Y 2038 Four digit year
+ *
+ * === Time ===
+ * %H 00 through 23 Two digit representation of the hour in 24-hour format
+ * %I 01 through 12 Two digit representation of the hour in 12-hour format
+ * %l 1 through 12 Hour in 12-hour format, with a space preceeding single digits
+ * %M 00 through 59 Two digit representation of the minute
+ * %p AM/PM UPPER-CASE 'AM' or 'PM' based on the given time
+ * %P am/pm lower-case 'am' or 'pm' based on the given time
+ * %r 09:34:17 PM Same as %I:%M:%S %p
+ * %R 00:35 Same as %H:%M
+ * %S 00 through 59 Two digit representation of the second
+ * %T 21:34:17 Same as %H:%M:%S
+ * %X 03:59:16 Preferred time representation based on locale, without the date
+ * %z -0500 or EST Either the time zone offset from UTC or the abbreviation
+ * %Z -0500 or EST The time zone offset/abbreviation option NOT given by %z
+ *
+ * === Time and Date ===
+ * %D 02/05/09 Same as %m/%d/%y
+ * %F 2009-02-05 Same as %Y-%m-%d (commonly used in database datestamps)
+ * %s 305815200 Unix Epoch Time timestamp (same as the time() function)
+ * %x 02/05/09 Preferred date representation, without the time
+ *
+ * === Miscellaneous ===
+ * %n --- A newline character (\n)
+ * %t --- A Tab character (\t)
+ * %% --- A literal percentage character (%)
+ * </pre>
+ */
+
+ jsDate.formats.php = {
+ codes: {
+ //
+ // 2-part regex matcher for format codes
+ //
+ // first match must be the character before the code (to account for escaping)
+ // second match must be the format code character(s)
+ //
+ matcher: /()%((%|[a-z]))/i,
+ // day
+ a: 'AbbrDayName',
+ A: 'DayName',
+ d: 'Date.2',
+ e: 'Date',
+ j: 'DayOfYear.3',
+ u: 'DayOfWeek',
+ w: 'Day',
+ // week
+ U: 'FullWeekOfYear.2',
+ V: 'IsoWeek.2',
+ W: 'WeekOfYear.2',
+ // month
+ b: 'AbbrMonthName',
+ B: 'MonthName',
+ m: 'MonthNumber.2',
+ h: 'AbbrMonthName',
+ // year
+ C: 'Century.2',
+ y: 'ShortYear.2',
+ Y: 'FullYear',
+ // time
+ H: 'Hours.2',
+ I: 'Hours12.2',
+ l: 'Hours12',
+ p: 'AMPM',
+ P: 'AmPm',
+ M: 'Minutes.2',
+ S: 'Seconds.2',
+ s: 'Unix',
+ O: 'TimezoneOffset',
+ z: 'GmtOffset',
+ Z: 'TimezoneAbbr'
+ },
+
+ shortcuts: {
+ D: '%m/%d/%y',
+ F: '%Y-%m-%d',
+ T: '%H:%M:%S',
+ X: '%H:%M:%S',
+ x: '%m/%d/%y',
+ R: '%H:%M',
+ r: '%I:%M:%S %p',
+ t: '\t',
+ n: '\n',
+ '%': '%'
+ }
+ };
+ //
+ // Conceptually, the logic implemented here is similar to Ken Snyder's Date Instance Methods.
+ // I use his idea of a set of parsers which can be regular expressions or functions,
+ // iterating through those, and then seeing if Date.parse() will create a date.
+ // The parser expressions and functions are a little different and some bugs have been
+ // worked out. Also, a lot of "pre-parsing" is done to fix implementation
+ // variations of Date.parse() between browsers.
+ //
+ jsDate.createDate = function(date) {
+ // if passing in multiple arguments, try Date constructor
+ if (date == null) {
+ return new Date();
+ }
+ // If the passed value is already a date object, return it
+ if (date instanceof Date) {
+ return date;
+ }
+ // if (typeof date == 'number') return new Date(date * 1000);
+ // If the passed value is an integer, interpret it as a javascript timestamp
+ if (typeof date == 'number') {
+ return new Date(date);
+ }
+
+ // Before passing strings into Date.parse(), have to normalize them for certain conditions.
+ // If strings are not formatted staccording to the EcmaScript spec, results from Date parse will be implementation dependent.
+ //
+ // For example:
+ // * FF and Opera assume 2 digit dates are pre y2k, Chome assumes <50 is pre y2k, 50+ is 21st century.
+ // * Chrome will correctly parse '1984-1-25' into localtime, FF and Opera will not parse.
+ // * Both FF, Chrome and Opera will parse '1984/1/25' into localtime.
+
+ // remove leading and trailing spaces
+ var parsable = String(date).replace(/^\s*(.+)\s*$/g, '$1');
+
+ // replace dahses (-) with slashes (/) in dates like n[nnn]/n[n]/n[nnn]
+ parsable = parsable.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/, "$1/$2/$3");
+
+ /////////
+ // Need to check for '15-Dec-09' also.
+ // FF will not parse, but Chrome will.
+ // Chrome will set date to 2009 as well.
+ /////////
+
+ // first check for 'dd-mmm-yyyy' or 'dd/mmm/yyyy' like '15-Dec-2010'
+ parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i, "$1 $2 $3");
+
+ // Now check for 'dd-mmm-yy' or 'dd/mmm/yy' and normalize years to default century.
+ var match = parsable.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);
+ if (match && match.length > 3) {
+ var m3 = parseFloat(match[3]);
+ var ny = jsDate.config.defaultCentury + m3;
+ ny = String(ny);
+
+ // now replace 2 digit year with 4 digit year
+ parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i, match[1] +' '+ match[2] +' '+ ny);
+
+ }
+
+ // Check for '1/19/70 8:14PM'
+ // where starts with mm/dd/yy or yy/mm/dd and have something after
+ // Check if 1st postiion is greater than 31, assume it is year.
+ // Assme all 2 digit years are 1900's.
+ // Finally, change them into US style mm/dd/yyyy representations.
+ match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);
+
+ function h1(parsable, match) {
+ var m1 = parseFloat(match[1]);
+ var m2 = parseFloat(match[2]);
+ var m3 = parseFloat(match[3]);
+ var cent = jsDate.config.defaultCentury;
+ var ny, nd, nm, str;
+
+ if (m1 > 31) { // first number is a year
+ nd = m3;
+ nm = m2;
+ ny = cent + m1;
+ }
+
+ else { // last number is the year
+ nd = m2;
+ nm = m1;
+ ny = cent + m3;
+ }
+
+ str = nm+'/'+nd+'/'+ny;
+
+ // now replace 2 digit year with 4 digit year
+ return parsable.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/, str);
+
+ }
+
+ if (match && match.length > 3) {
+ parsable = h1(parsable, match);
+ }
+
+ // Now check for '1/19/70' with nothing after and do as above
+ var match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);
+
+ if (match && match.length > 3) {
+ parsable = h1(parsable, match);
+ }
+
+
+ var i = 0;
+ var length = jsDate.matchers.length;
+ var pattern,
+ ms,
+ current = parsable,
+ obj;
+ while (i < length) {
+ ms = Date.parse(current);
+ if (!isNaN(ms)) {
+ return new Date(ms);
+ }
+ pattern = jsDate.matchers[i];
+ if (typeof pattern == 'function') {
+ obj = pattern.call(jsDate, current);
+ if (obj instanceof Date) {
+ return obj;
+ }
+ } else {
+ current = parsable.replace(pattern[0], pattern[1]);
+ }
+ i++;
+ }
+ return NaN;
+ };
+
+
+ /**
+ * @static
+ * Handy static utility function to return the number of days in a given month.
+ * @param {Integer} year Year
+ * @param {Integer} month Month (1-12)
+ * @returns {Integer} Number of days in the month.
+ */
+ //
+ // handy utility method Borrowed right from Ken Snyder's Date Instance Methods.
+ //
+ jsDate.daysInMonth = function(year, month) {
+ if (month == 2) {
+ return new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
+ }
+ return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month];
+ };
+
+
+ //
+ // An Array of regular expressions or functions that will attempt to match the date string.
+ // Functions are called with scope of a jsDate instance.
+ //
+ jsDate.matchers = [
+ // convert dd.mmm.yyyy to mm/dd/yyyy (world date to US date).
+ [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'],
+ // convert yyyy-mm-dd to mm/dd/yyyy (ISO date to US date).
+ [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'],
+ // Handle 12 hour or 24 hour time with milliseconds am/pm and optional date part.
+ function(str) {
+ var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i);
+ // opt. date hour opt. minute opt. second opt. msec opt. am or pm
+ if (match) {
+ if (match[1]) {
+ var d = this.createDate(match[1]);
+ if (isNaN(d)) {
+ return;
+ }
+ } else {
+ var d = new Date();
+ d.setMilliseconds(0);
+ }
+ var hour = parseFloat(match[2]);
+ if (match[6]) {
+ hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12);
+ }
+ d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000);
+ return d;
+ }
+ else {
+ return str;
+ }
+ },
+ // Handle ISO timestamp with time zone.
+ function(str) {
+ var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i);
+ if (match) {
+ if (match[1]) {
+ var d = this.createDate(match[1]);
+ if (isNaN(d)) {
+ return;
+ }
+ } else {
+ var d = new Date();
+ d.setMilliseconds(0);
+ }
+ var hour = parseFloat(match[2]);
+ d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000);
+ return d;
+ }
+ else {
+ return str;
+ }
+ },
+ // Try to match ambiguous strings like 12/8/22.
+ // Use FF date assumption that 2 digit years are 20th century (i.e. 1900's).
+ // This may be redundant with pre processing of date already performed.
+ function(str) {
+ var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/);
+ if (match) {
+ var d = new Date();
+ var cent = jsDate.config.defaultCentury;
+ var m1 = parseFloat(match[1]);
+ var m3 = parseFloat(match[3]);
+ var ny, nd, nm;
+ if (m1 > 31) { // first number is a year
+ nd = m3;
+ ny = cent + m1;
+ }
+
+ else { // last number is the year
+ nd = m1;
+ ny = cent + m3;
+ }
+
+ var nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNamesShort"]);
+
+ if (nm == -1) {
+ nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNames"]);
+ }
+
+ d.setFullYear(ny, nm, nd);
+ d.setHours(0,0,0,0);
+ return d;
+ }
+
+ else {
+ return str;
+ }
+ }
+ ];
+
+ //
+ // I think John Reisig published this method on his blog, ejohn.
+ //
+ function inArray( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ //
+ // Thanks to Kangax, Christian Sciberras and Stack Overflow for this method.
+ //
+ function get_type(thing){
+ if(thing===null) return "[object Null]"; // special case
+ return Object.prototype.toString.call(thing);
+ }
+
+ $.jsDate = jsDate;
+
+
+ /**
+ * JavaScript printf/sprintf functions.
+ *
+ * This code has been adapted from the publicly available sprintf methods
+ * by Ash Searle. His original header follows:
+ *
+ * This code is unrestricted: you are free to use it however you like.
+ *
+ * The functions should work as expected, performing left or right alignment,
+ * truncating strings, outputting numbers with a required precision etc.
+ *
+ * For complex cases, these functions follow the Perl implementations of
+ * (s)printf, allowing arguments to be passed out-of-order, and to set the
+ * precision or length of the output based on arguments instead of fixed
+ * numbers.
+ *
+ * See http://perldoc.perl.org/functions/sprintf.html for more information.
+ *
+ * Implemented:
+ * - zero and space-padding
+ * - right and left-alignment,
+ * - base X prefix (binary, octal and hex)
+ * - positive number prefix
+ * - (minimum) width
+ * - precision / truncation / maximum width
+ * - out of order arguments
+ *
+ * Not implemented (yet):
+ * - vector flag
+ * - size (bytes, words, long-words etc.)
+ *
+ * Will not implement:
+ * - %n or %p (no pass-by-reference in JavaScript)
+ *
+ * @version 2007.04.27
+ * @author Ash Searle
+ *
+ * You can see the original work and comments on his blog:
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ */
+
+ /**
+ * @Modifications 2009.05.26
+ * @author Chris Leonello
+ *
+ * Added %p %P specifier
+ * Acts like %g or %G but will not add more significant digits to the output than present in the input.
+ * Example:
+ * Format: '%.3p', Input: 0.012, Output: 0.012
+ * Format: '%.3g', Input: 0.012, Output: 0.0120
+ * Format: '%.4p', Input: 12.0, Output: 12.0
+ * Format: '%.4g', Input: 12.0, Output: 12.00
+ * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5
+ * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5
+ *
+ * Example:
+ * >>> $.jqplot.sprintf('%.2f, %d', 23.3452, 43.23)
+ * "23.35, 43"
+ * >>> $.jqplot.sprintf("no value: %n, decimal with thousands separator: %'d", 23.3452, 433524)
+ * "no value: , decimal with thousands separator: 433,524"
+ */
+ $.jqplot.sprintf = function() {
+ function pad(str, len, chr, leftJustify) {
+ var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
+ return leftJustify ? str + padding : padding + str;
+
+ }
+
+ function thousand_separate(value) {
+ var value_str = new String(value);
+ for (var i=10; i>0; i--) {
+ if (value_str == (value_str = value_str.replace(/^(\d+)(\d{3})/, "$1"+$.jqplot.sprintf.thousandsSeparator+"$2"))) break;
+ }
+ return value_str;
+ }
+
+ function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) {
+ var diff = minWidth - value.length;
+ if (diff > 0) {
+ var spchar = ' ';
+ if (htmlSpace) { spchar = '&nbsp;'; }
+ if (leftJustify || !zeroPad) {
+ value = pad(value, minWidth, spchar, leftJustify);
+ } else {
+ value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
+ }
+ }
+ return value;
+ }
+
+ function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
+ // Note: casts negative numbers to positive ones
+ var number = value >>> 0;
+ prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
+ value = prefix + pad(number.toString(base), precision || 0, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+
+ function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
+ if (precision != null) {
+ value = value.slice(0, precision);
+ }
+ return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+
+ var a = arguments, i = 0, format = a[i++];
+
+ return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) {
+ if (substring == '%%') { return '%'; }
+
+ // parse flags
+ var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false, thousandSeparation = false;
+ for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
+ case ' ': positivePrefix = ' '; break;
+ case '+': positivePrefix = '+'; break;
+ case '-': leftJustify = true; break;
+ case '0': zeroPad = true; break;
+ case '#': prefixBaseX = true; break;
+ case '&': htmlSpace = true; break;
+ case '\'': thousandSeparation = true; break;
+ }
+
+ // parameters may be null, undefined, empty-string or real valued
+ // we want to ignore null, undefined and empty-string values
+
+ if (!minWidth) {
+ minWidth = 0;
+ }
+ else if (minWidth == '*') {
+ minWidth = +a[i++];
+ }
+ else if (minWidth.charAt(0) == '*') {
+ minWidth = +a[minWidth.slice(1, -1)];
+ }
+ else {
+ minWidth = +minWidth;
+ }
+
+ // Note: undocumented perl feature:
+ if (minWidth < 0) {
+ minWidth = -minWidth;
+ leftJustify = true;
+ }
+
+ if (!isFinite(minWidth)) {
+ throw new Error('$.jqplot.sprintf: (minimum-)width must be finite');
+ }
+
+ if (!precision) {
+ precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
+ }
+ else if (precision == '*') {
+ precision = +a[i++];
+ }
+ else if (precision.charAt(0) == '*') {
+ precision = +a[precision.slice(1, -1)];
+ }
+ else {
+ precision = +precision;
+ }
+
+ // grab value using valueIndex if required?
+ var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
+
+ switch (type) {
+ case 's': {
+ if (value == null) {
+ return '';
+ }
+ return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ }
+ case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace);
+ case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase();
+ case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'i': {
+ var number = parseInt(+value, 10);
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number));
+ value = prefix + pad(number_str, precision, '0', false);
+ //value = prefix + pad(String(Math.abs(number)), precision, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+ case 'd': {
+ var number = Math.round(+value);
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number));
+ value = prefix + pad(number_str, precision, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ {
+ var number = +value;
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
+ var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
+ var number_str = Math.abs(number)[method](precision);
+ number_str = thousandSeparation ? thousand_separate(number_str): number_str;
+ value = prefix + number_str;
+ var justified = justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
+
+ if ($.jqplot.sprintf.decimalMark !== '.' && $.jqplot.sprintf.decimalMark !== $.jqplot.sprintf.thousandsSeparator) {
+ return justified.replace(/\./, $.jqplot.sprintf.decimalMark);
+ } else {
+ return justified;
+ }
+ }
+ case 'p':
+ case 'P':
+ {
+ // make sure number is a number
+ var number = +value;
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+
+ var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
+ var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
+ var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
+
+ if (Math.abs(number) < 1) {
+ if (sd + zeros <= precision) {
+ value = prefix + Math.abs(number).toPrecision(sd);
+ }
+ else {
+ if (sd <= precision - 1) {
+ value = prefix + Math.abs(number).toExponential(sd-1);
+ }
+ else {
+ value = prefix + Math.abs(number).toExponential(precision-1);
+ }
+ }
+ }
+ else {
+ var prec = (sd <= precision) ? sd : precision;
+ value = prefix + Math.abs(number).toPrecision(prec);
+ }
+ var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2];
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
+ }
+ case 'n': return '';
+ default: return substring;
+ }
+ });
+ };
+
+ $.jqplot.sprintf.thousandsSeparator = ',';
+ // Specifies the decimal mark for floating point values. By default a period '.'
+ // is used. If you change this value to for example a comma be sure to also
+ // change the thousands separator or else this won't work since a simple String
+ // replace is used (replacing all periods with the mark specified here).
+ $.jqplot.sprintf.decimalMark = '.';
+
+ $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;
+
+ $.jqplot.getSignificantFigures = function(number) {
+ var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
+ // total significant digits
+ var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
+ var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
+ // exponent
+ var expn = parseInt(parts[1], 10);
+ // digits to the left of the decimal place
+ var dleft = (expn + 1 > 0) ? expn + 1 : 0;
+ // digits to the right of the decimal place
+ var dright = (sd <= dleft) ? 0 : sd - expn - 1;
+ return {significantDigits: sd, digitsLeft: dleft, digitsRight: dright, zeros: zeros, exponent: expn} ;
+ };
+
+ $.jqplot.getPrecision = function(number) {
+ return $.jqplot.getSignificantFigures(number).digitsRight;
+ };
+
+})(jQuery);
+
+
+ var backCompat = $.uiBackCompat !== false;
+
+ $.jqplot.effects = {
+ effect: {}
+ };
+
+ // prefix used for storing data on .data()
+ var dataSpace = "jqplot.storage.";
+
+ /******************************************************************************/
+ /*********************************** EFFECTS **********************************/
+ /******************************************************************************/
+
+ $.extend( $.jqplot.effects, {
+ version: "1.9pre",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.css( set[ i ], element.data( dataSpace + set[ i ] ) );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ }
+ });
+
+ // return an effect options object for the given parameters:
+ function _normalizeArguments( effect, options, speed, callback ) {
+
+ // short path for passing an effect options object:
+ if ( $.isPlainObject( effect ) ) {
+ return effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect)
+ if ( options === undefined ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( $.type( options ) === "number" || $.fx.speeds[ options ]) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 : typeof speed === "number"
+ ? speed : speed in $.fx.speeds ? $.fx.speeds[ speed ] : $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+ }
+
+ function standardSpeed( speed ) {
+ // valid standard speeds
+ if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
+ return true;
+ }
+
+ // invalid strings - treat as "normal" speed
+ if ( typeof speed === "string" && !$.jqplot.effects.effect[ speed ] ) {
+ // TODO: remove in 2.0 (#7115)
+ if ( backCompat && $.jqplot.effects[ speed ] ) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ $.fn.extend({
+ jqplotEffect: function( effect, options, speed, callback ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.jqplot.effects.effect[ args.effect ],
+
+ // DEPRECATED: remove in 2.0 (#7115)
+ oldEffectMethod = !effectMethod && backCompat && $.jqplot.effects[ args.effect ];
+
+ if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // if the element is hiddden and mode is hide,
+ // or element is visible and mode is show
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ // TODO: remove this check in 2.0, effectMethod will always be true
+ if ( effectMethod ) {
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ } else {
+ // DEPRECATED: remove in 2.0 (#7115)
+ return oldEffectMethod.call(this, {
+ options: args,
+ duration: args.duration,
+ callback: args.complete,
+ mode: args.mode
+ });
+ }
+ }
+ });
+
+
+
+
+ var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+ $.jqplot.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.jqplot.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, top;
+
+ // // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.jqplot.effects.save( el.parent(), props );
+ } else {
+ $.jqplot.effects.save( el, props );
+ }
+ el.show();
+ top = parseInt(el.css('top'), 10);
+ wrapper = $.jqplot.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = vertical ? wrapper[ ref ]() + top : wrapper[ ref ]();
+
+ animation[ ref ] = show ? String(distance) : '0';
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "" )
+ .css({ position: "absolute" });
+ animation[ ref2 ] = show ? '0' : String(distance);
+ }
+
+ // // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, distance );
+ }
+ }
+
+ // // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.jqplot.effects.restore( el, props );
+ $.jqplot.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+ };
+
+
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.blockUI.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.blockUI.js
new file mode 100644
index 00000000..ccef3f03
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.blockUI.js
@@ -0,0 +1,619 @@
+/*!
+ * jQuery blockUI plugin
+ * Version 2.66.0-2013.10.09
+ * Requires jQuery v1.7 or later
+ *
+ * Examples at: http://malsup.com/jquery/block/
+ * Copyright (c) 2007-2013 M. Alsup
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
+ */
+
+;(function() {
+/*jshint eqeqeq:false curly:false latedef:false */
+"use strict";
+
+ function setup($) {
+ $.fn._fadeIn = $.fn.fadeIn;
+
+ var noOp = $.noop || function() {};
+
+ // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
+ // confusing userAgent strings on Vista)
+ var msie = /MSIE/.test(navigator.userAgent);
+ var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
+ var mode = document.documentMode || 0;
+ var setExpr = $.isFunction( document.createElement('div').style.setExpression );
+
+ // global $ methods for blocking/unblocking the entire page
+ $.blockUI = function(opts) { install(window, opts); };
+ $.unblockUI = function(opts) { remove(window, opts); };
+
+ // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
+ $.growlUI = function(title, message, timeout, onClose) {
+ var $m = $('<div class="growlUI"></div>');
+ if (title) $m.append('<h1>'+title+'</h1>');
+ if (message) $m.append('<h2>'+message+'</h2>');
+ if (timeout === undefined) timeout = 3000;
+
+ // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
+ var callBlock = function(opts) {
+ opts = opts || {};
+
+ $.blockUI({
+ message: $m,
+ fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
+ fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
+ timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
+ centerY: false,
+ showOverlay: false,
+ onUnblock: onClose,
+ css: $.blockUI.defaults.growlCSS
+ });
+ };
+
+ callBlock();
+ var nonmousedOpacity = $m.css('opacity');
+ $m.mouseover(function() {
+ callBlock({
+ fadeIn: 0,
+ timeout: 30000
+ });
+
+ var displayBlock = $('.blockMsg');
+ displayBlock.stop(); // cancel fadeout if it has started
+ displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
+ }).mouseout(function() {
+ $('.blockMsg').fadeOut(1000);
+ });
+ // End konapun additions
+ };
+
+ // plugin method for blocking element content
+ $.fn.block = function(opts) {
+ if ( this[0] === window ) {
+ $.blockUI( opts );
+ return this;
+ }
+ var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
+ this.each(function() {
+ var $el = $(this);
+ if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
+ return;
+ $el.unblock({ fadeOut: 0 });
+ });
+
+ return this.each(function() {
+ if ($.css(this,'position') == 'static') {
+ this.style.position = 'relative';
+ $(this).data('blockUI.static', true);
+ }
+ this.style.zoom = 1; // force 'hasLayout' in ie
+ install(this, opts);
+ });
+ };
+
+ // plugin method for unblocking element content
+ $.fn.unblock = function(opts) {
+ if ( this[0] === window ) {
+ $.unblockUI( opts );
+ return this;
+ }
+ return this.each(function() {
+ remove(this, opts);
+ });
+ };
+
+ $.blockUI.version = 2.66; // 2nd generation blocking at no extra cost!
+
+ // override these in your code to change the default behavior and style
+ $.blockUI.defaults = {
+ // message displayed when blocking (use null for no message)
+ message: '<h1>Please wait...</h1>',
+
+ title: null, // title string; only used when theme == true
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
+
+ theme: false, // set to true to use with jQuery UI themes
+
+ // styles for the message when blocking; if you wish to disable
+ // these and use an external stylesheet then do this in your code:
+ // $.blockUI.defaults.css = {};
+ css: {
+ padding: 0,
+ margin: 0,
+ width: '30%',
+ top: '40%',
+ left: '35%',
+ textAlign: 'center',
+ color: '#000',
+ border: '3px solid #aaa',
+ backgroundColor:'#fff',
+ cursor: 'wait'
+ },
+
+ // minimal style set used when themes are used
+ themedCSS: {
+ width: '30%',
+ top: '40%',
+ left: '35%'
+ },
+
+ // styles for the overlay
+ overlayCSS: {
+ backgroundColor: '#000',
+ opacity: 0.6,
+ cursor: 'wait'
+ },
+
+ // style to replace wait cursor before unblocking to correct issue
+ // of lingering wait cursor
+ cursorReset: 'default',
+
+ // styles applied when using $.growlUI
+ growlCSS: {
+ width: '350px',
+ top: '10px',
+ left: '',
+ right: '10px',
+ border: 'none',
+ padding: '5px',
+ opacity: 0.6,
+ cursor: 'default',
+ color: '#fff',
+ backgroundColor: '#000',
+ '-webkit-border-radius':'10px',
+ '-moz-border-radius': '10px',
+ 'border-radius': '10px'
+ },
+
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+ // (hat tip to Jorge H. N. de Vasconcelos)
+ /*jshint scripturl:true */
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
+ forceIframe: false,
+
+ // z-index for the blocking overlay
+ baseZ: 1000,
+
+ // set these to true to have the message automatically centered
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
+ centerY: true,
+
+ // allow body element to be stetched in ie6; this makes blocking look better
+ // on "short" pages. disable if you wish to prevent changes to the body height
+ allowBodyStretch: true,
+
+ // enable if you want key and mouse events to be disabled for content that is blocked
+ bindEvents: true,
+
+ // be default blockUI will supress tab navigation from leaving blocking content
+ // (if bindEvents is true)
+ constrainTabKey: true,
+
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
+ fadeIn: 200,
+
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+ fadeOut: 400,
+
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+ timeout: 0,
+
+ // disable if you don't want to show the overlay
+ showOverlay: true,
+
+ // if true, focus will be placed in the first available input field when
+ // page blocking
+ focusInput: true,
+
+ // elements that can receive focus
+ focusableElements: ':input:enabled:visible',
+
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+ // no longer needed in 2012
+ // applyPlatformOpacityRules: true,
+
+ // callback method invoked when fadeIn has completed and blocking message is visible
+ onBlock: null,
+
+ // callback method invoked when unblocking has completed; the callback is
+ // passed the element that has been unblocked (which is the window object for page
+ // blocks) and the options that were passed to the unblock call:
+ // onUnblock(element, options)
+ onUnblock: null,
+
+ // callback method invoked when the overlay area is clicked.
+ // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
+ onOverlayClick: null,
+
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+ quirksmodeOffsetHack: 4,
+
+ // class name of the message block
+ blockMsgClass: 'blockMsg',
+
+ // if it is already blocked, then ignore it (don't unblock and reblock)
+ ignoreIfBlocked: false
+ };
+
+ // private data and functions follow...
+
+ var pageBlock = null;
+ var pageBlockEls = [];
+
+ function install(el, opts) {
+ var css, themedCSS;
+ var full = (el == window);
+ var msg = (opts && opts.message !== undefined ? opts.message : undefined);
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+
+ if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
+ return;
+
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+ css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+ if (opts.onOverlayClick)
+ opts.overlayCSS.cursor = 'pointer';
+
+ themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+ msg = msg === undefined ? opts.message : msg;
+
+ // remove the current block (if there is one)
+ if (full && pageBlock)
+ remove(window, {fadeOut:0});
+
+ // if an existing element is being used as the blocking content then we capture
+ // its current place in the DOM (and current display style) so we can restore
+ // it when we unblock
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+ var node = msg.jquery ? msg[0] : msg;
+ var data = {};
+ $(el).data('blockUI.history', data);
+ data.el = node;
+ data.parent = node.parentNode;
+ data.display = node.style.display;
+ data.position = node.style.position;
+ if (data.parent)
+ data.parent.removeChild(node);
+ }
+
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
+ var z = opts.baseZ;
+
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+ // layer1 is the iframe layer which is used to supress bleed through of underlying content
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+ // layer3 is the message content that is displayed while blocking
+ var lyr1, lyr2, lyr3, s;
+ if (msie || opts.forceIframe)
+ lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
+ else
+ lyr1 = $('<div class="blockUI" style="display:none"></div>');
+
+ if (opts.theme)
+ lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
+ else
+ lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
+
+ if (opts.theme && full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
+ if ( opts.title ) {
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
+ }
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
+ s += '</div>';
+ }
+ else if (opts.theme) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
+ if ( opts.title ) {
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
+ }
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
+ s += '</div>';
+ }
+ else if (full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
+ }
+ else {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
+ }
+ lyr3 = $(s);
+
+ // if we have a message, style it
+ if (msg) {
+ if (opts.theme) {
+ lyr3.css(themedCSS);
+ lyr3.addClass('ui-widget-content');
+ }
+ else
+ lyr3.css(css);
+ }
+
+ // style the overlay
+ if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
+ lyr2.css(opts.overlayCSS);
+ lyr2.css('position', full ? 'fixed' : 'absolute');
+
+ // make iframe layer transparent in IE
+ if (msie || opts.forceIframe)
+ lyr1.css('opacity',0.0);
+
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+ $.each(layers, function() {
+ this.appendTo($par);
+ });
+
+ if (opts.theme && opts.draggable && $.fn.draggable) {
+ lyr3.draggable({
+ handle: '.ui-dialog-titlebar',
+ cancel: 'li'
+ });
+ }
+
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+ var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
+ if (ie6 || expr) {
+ // give body 100% height
+ if (full && opts.allowBodyStretch && $.support.boxModel)
+ $('html,body').css('height','100%');
+
+ // fix ie6 issue when blocked element has a border width
+ if ((ie6 || !$.support.boxModel) && !full) {
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+ var fixT = t ? '(0 - '+t+')' : 0;
+ var fixL = l ? '(0 - '+l+')' : 0;
+ }
+
+ // simulate fixed position
+ $.each(layers, function(i,o) {
+ var s = o[0].style;
+ s.position = 'absolute';
+ if (i < 2) {
+ if (full)
+ s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
+ else
+ s.setExpression('height','this.parentNode.offsetHeight + "px"');
+ if (full)
+ s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
+ else
+ s.setExpression('width','this.parentNode.offsetWidth + "px"');
+ if (fixL) s.setExpression('left', fixL);
+ if (fixT) s.setExpression('top', fixT);
+ }
+ else if (opts.centerY) {
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+ s.marginTop = 0;
+ }
+ else if (!opts.centerY && full) {
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+ s.setExpression('top',expression);
+ }
+ });
+ }
+
+ // show the message
+ if (msg) {
+ if (opts.theme)
+ lyr3.find('.ui-widget-content').append(msg);
+ else
+ lyr3.append(msg);
+ if (msg.jquery || msg.nodeType)
+ $(msg).show();
+ }
+
+ if ((msie || opts.forceIframe) && opts.showOverlay)
+ lyr1.show(); // opacity is zero
+ if (opts.fadeIn) {
+ var cb = opts.onBlock ? opts.onBlock : noOp;
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+ var cb2 = msg ? cb : noOp;
+ if (opts.showOverlay)
+ lyr2._fadeIn(opts.fadeIn, cb1);
+ if (msg)
+ lyr3._fadeIn(opts.fadeIn, cb2);
+ }
+ else {
+ if (opts.showOverlay)
+ lyr2.show();
+ if (msg)
+ lyr3.show();
+ if (opts.onBlock)
+ opts.onBlock();
+ }
+
+ // bind key and mouse events
+ bind(1, el, opts);
+
+ if (full) {
+ pageBlock = lyr3[0];
+ pageBlockEls = $(opts.focusableElements,pageBlock);
+ if (opts.focusInput)
+ setTimeout(focus, 20);
+ }
+ else
+ center(lyr3[0], opts.centerX, opts.centerY);
+
+ if (opts.timeout) {
+ // auto-unblock
+ var to = setTimeout(function() {
+ if (full)
+ $.unblockUI(opts);
+ else
+ $(el).unblock(opts);
+ }, opts.timeout);
+ $(el).data('blockUI.timeout', to);
+ }
+ }
+
+ // remove the block
+ function remove(el, opts) {
+ var count;
+ var full = (el == window);
+ var $el = $(el);
+ var data = $el.data('blockUI.history');
+ var to = $el.data('blockUI.timeout');
+ if (to) {
+ clearTimeout(to);
+ $el.removeData('blockUI.timeout');
+ }
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ bind(0, el, opts); // unbind events
+
+ if (opts.onUnblock === null) {
+ opts.onUnblock = $el.data('blockUI.onUnblock');
+ $el.removeData('blockUI.onUnblock');
+ }
+
+ var els;
+ if (full) // crazy selector to handle odd field errors in ie6/7
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
+ else
+ els = $el.find('>.blockUI');
+
+ // fix cursor issue
+ if ( opts.cursorReset ) {
+ if ( els.length > 1 )
+ els[1].style.cursor = opts.cursorReset;
+ if ( els.length > 2 )
+ els[2].style.cursor = opts.cursorReset;
+ }
+
+ if (full)
+ pageBlock = pageBlockEls = null;
+
+ if (opts.fadeOut) {
+ count = els.length;
+ els.stop().fadeOut(opts.fadeOut, function() {
+ if ( --count === 0)
+ reset(els,data,opts,el);
+ });
+ }
+ else
+ reset(els, data, opts, el);
+ }
+
+ // move blocking element back into the DOM where it started
+ function reset(els,data,opts,el) {
+ var $el = $(el);
+ if ( $el.data('blockUI.isBlocked') )
+ return;
+
+ els.each(function(i,o) {
+ // remove via DOM calls so we don't lose event handlers
+ if (this.parentNode)
+ this.parentNode.removeChild(this);
+ });
+
+ if (data && data.el) {
+ data.el.style.display = data.display;
+ data.el.style.position = data.position;
+ if (data.parent)
+ data.parent.appendChild(data.el);
+ $el.removeData('blockUI.history');
+ }
+
+ if ($el.data('blockUI.static')) {
+ $el.css('position', 'static'); // #22
+ }
+
+ if (typeof opts.onUnblock == 'function')
+ opts.onUnblock(el,opts);
+
+ // fix issue in Safari 6 where block artifacts remain until reflow
+ var body = $(document.body), w = body.width(), cssW = body[0].style.width;
+ body.width(w-1).width(w);
+ body[0].style.width = cssW;
+ }
+
+ // bind/unbind the handler
+ function bind(b, el, opts) {
+ var full = el == window, $el = $(el);
+
+ // don't bother unbinding if there is nothing to unbind
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+ return;
+
+ $el.data('blockUI.isBlocked', b);
+
+ // don't bind events when overlay is not in use or if bindEvents is false
+ if (!full || !opts.bindEvents || (b && !opts.showOverlay))
+ return;
+
+ // bind anchors and inputs for mouse and key events
+ var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
+ if (b)
+ $(document).bind(events, opts, handler);
+ else
+ $(document).unbind(events, handler);
+
+ // former impl...
+ // var $e = $('a,:input');
+ // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+ }
+
+ // event handler to suppress keyboard/mouse events when blocking
+ function handler(e) {
+ // allow tab navigation (conditionally)
+ if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
+ if (pageBlock && e.data.constrainTabKey) {
+ var els = pageBlockEls;
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
+ var back = e.shiftKey && e.target === els[0];
+ if (fwd || back) {
+ setTimeout(function(){focus(back);},10);
+ return false;
+ }
+ }
+ }
+ var opts = e.data;
+ var target = $(e.target);
+ if (target.hasClass('blockOverlay') && opts.onOverlayClick)
+ opts.onOverlayClick(e);
+
+ // allow events within the message content
+ if (target.parents('div.' + opts.blockMsgClass).length > 0)
+ return true;
+
+ // allow events for content that is not being blocked
+ return target.parents().children().filter('div.blockUI').length === 0;
+ }
+
+ function focus(back) {
+ if (!pageBlockEls)
+ return;
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+ if (e)
+ e.focus();
+ }
+
+ function center(el, x, y) {
+ var p = el.parentNode, s = el.style;
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+ if (x) s.left = l > 0 ? (l+'px') : '0';
+ if (y) s.top = t > 0 ? (t+'px') : '0';
+ }
+
+ function sz(el, p) {
+ return parseInt($.css(el,p),10)||0;
+ }
+
+ }
+
+
+ /*global define:true */
+ if (typeof define === 'function' && define.amd && define.amd.jQuery) {
+ define(['jquery'], setup);
+ } else {
+ setup(jQuery);
+ }
+
+})(); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js
new file mode 100644
index 00000000..456ec536
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js
@@ -0,0 +1,526 @@
+/*! (c) Mat Marquis (@wilto). MIT License. http://wil.to/3a */
+
+(function( $, undefined ) {
+ var inst = 0;
+
+ $.fn.getPercentage = function() {
+ var oPercent = this.attr('style').match(/margin\-left:(.*[0-9])/i) && parseInt(RegExp.$1);
+
+ return oPercent;
+ };
+
+ $.fn.adjRounding = function(slide) {
+ var $el = $(this),
+ $slides = $el.find( slide ),
+ diff = $el.parent().width() - $($slides[0]).width();
+
+ if (diff !== 0) {
+ $($slides).css( "position", "relative" );
+
+ for (var i = 0; i < $slides.length; i++) {
+ $($slides[i]).css( "left", (diff * i) + "px" );
+ }
+ }
+
+ return this;
+ };
+
+ $.fn.carousel = function(config) {
+
+ // Prevent re-init:
+ if( this.data( "carousel-initialized" ) ) { return; }
+
+ // Carousel is being initialized:
+ this.data( "carousel-initialized", true );
+
+ var defaults = {
+ slider : '.slider',
+ slide : '.slide',
+ prevSlide : null,
+ nextSlide : null,
+ slideHed : null,
+ addPagination : false,
+ addNav : ( config != undefined && ( config.prevSlide || config.nextSlide ) ) ? false : true,
+ namespace : 'carousel',
+ speed : 300
+ },
+ opt = $.extend(defaults, config),
+ $slidewrap = this,
+ dStyle = document.body.style,
+ transitionSupport = dStyle.webkitTransition !== undefined ||
+ dStyle.mozTransition !== undefined ||
+ dStyle.msTransition !== undefined ||
+ dStyle.OTransition !== undefined ||
+ dStyle.transition !== undefined,
+ carousel = {
+ init : function() {
+ inst++;
+
+ $slidewrap.each(function(carInt) {
+ var $wrap = $(this),
+ $slider = $wrap.find(opt.slider),
+ $slide = $wrap.find(opt.slide),
+ slidenum = $slide.length,
+ transition = "margin-left " + ( opt.speed / 1000 ) + "s ease",
+ tmp = 'carousel-' + inst + '-' + carInt;
+
+ if( $slide.length <= 1 ) {
+ return; /* No sense running all this code if the carousel functionality is unnecessary. */
+ }
+
+ $wrap
+ .css({
+ overflow : "hidden",
+ width : "100%"
+ })
+ .attr('role' , 'application');
+
+ $slider
+ .attr( 'id', ( $slider[0].id || 'carousel-' + inst + '-' + carInt ) )
+ .css({
+ "marginLeft" : "0px",
+ "float" : "left",
+ "width" : 100 * slidenum + "%",
+ "-webkit-transition" : transition,
+ "-moz-transition" : transition,
+ "-ms-transition" : transition,
+ "-o-transition" : transition,
+ "transition" : transition
+ })
+ .bind( 'carouselmove' , carousel.move )
+ .bind( 'nextprev' , carousel.nextPrev )
+ .bind( 'navstate' , carousel.navState );
+
+ $slide
+ .css({
+ "float": "left",
+ width: (100 / slidenum) + "%"
+ })
+ .each(function(i) {
+ var $el = $(this);
+
+ $el.attr({
+ role : "tabpanel document",
+ id : tmp + '-slide' + i
+ });
+
+ if( opt.addPagination ) {
+ $el.attr('aria-labelledby', tmp + '-tab' + i);
+ }
+ });
+
+ // Build and insert navigation/pagination, if specified in the options:
+ opt.addPagination && carousel.addPagination();
+ opt.addNav && carousel.addNav();
+
+ $slider.trigger( "navstate", { current: 0 });
+ });
+ },
+ addNav : function() {
+ $slidewrap.each(function(i) {
+ var $oEl = $(this),
+ $slider = $oEl.find(opt.slider),
+ currentSlider = $slider[0].id,
+ navMarkup = [
+ '<ul class="slidecontrols" role="navigation">',
+ ' <li role="presentation"><a href="#' + currentSlider + '" class="' + opt.namespace + '-next">Next</a></li>',
+ ' <li role="presentation"><a href="#' + currentSlider + '" class="' + opt.namespace + '-prev">Prev</a></li>',
+ '</ul>'
+ ].join(''),
+ nextprev = {
+ nextSlide : '.' + opt.namespace + '-next',
+ prevSlide : '.' + opt.namespace + '-prev'
+ };
+
+ opt = $.extend(opt, nextprev);
+
+ $oEl.prepend(navMarkup);
+ });
+ },
+ addPagination : function() {
+ $slidewrap.each(function(i) {
+ var $oEl = $(this),
+ $pagination = $('<ol class="' + opt.namespace + '-tabs" role="tablist navigation" />'),
+ $slider = $oEl.find(opt.slider),
+ $slides = $oEl.find(opt.slide)
+ slideNum = $slides.length,
+ associated = 'carousel-' + inst + '-' + i;
+
+ while( slideNum-- ) {
+ var hed = $( $slides[ slideNum ] ).find( opt.slideHed ).text() || 'Page ' + ( slideNum + 1 ),
+ tabMarkup = [
+ '<li role="presentation">',
+ '<a href="#' + associated + '-slide' + slideNum +'"',
+ ' aria-controls="' + associated + '-slide' + slideNum +'"',
+ ' id="' + associated + '-tab' + slideNum + '" role="tab">' + hed + '</a>',
+ '</li>'
+ ].join('');
+
+ $pagination.prepend(tabMarkup);
+ };
+
+ $pagination
+ .appendTo( $oEl )
+ .find('li').keydown( function(e) {
+ var $el = $(this),
+ $prevTab = $el.prev().find('a'),
+ $nextTab = $el.next().find('a');
+
+ switch( e.which ) {
+ case 37:
+ case 38:
+ $prevTab.length && $prevTab.trigger('click').focus();
+ e.preventDefault();
+ break;
+ case 39:
+ case 40:
+ $nextTab.length && $nextTab.trigger('click').focus();
+ e.preventDefault();
+ break;
+ }
+ })
+ .find('a').click( function(e) {
+ var $el = $(this);
+
+ if( $el.attr('aria-selected') == 'true' ) {
+ var current = $el.parent().index(),
+ move = -( 100 * ( current ) ),
+ $slider = $oEl.find( opt.slider );
+
+ $slider.trigger( 'carouselmove', { moveTo: move });
+ }
+ e.preventDefault();
+ });
+ });
+ },
+ roundDown : function(oVal) {
+ var val = parseInt(oVal, 10);
+
+ return Math.ceil( (val - (val % 100 ) ) / 100) * 100;
+ },
+ navState : function(e, ui) {
+ var $el = $(this),
+ $slides = $el.find(opt.slide),
+ ind = -(ui.current / 100),
+ $activeSlide = $($slides[ind]);
+
+ $el.attr('aria-activedescendant', $activeSlide[0].id);
+
+ // Update state of active tabpanel:
+ $activeSlide
+ .addClass( opt.namespace + "-active-slide" )
+ .attr( 'aria-hidden', false )
+ .siblings()
+ .removeClass( opt.namespace + "-active-slide" )
+ .attr( 'aria-hidden', true );
+
+ // Update state of next/prev navigation:
+ if( ( !!opt.prevSlide || !!opt.nextSlide ) ) {
+ var $target = $('[href*="#' + this.id + '"]');
+
+ $target.removeClass( opt.namespace + '-disabled' );
+
+ if( ind == 0 ) {
+ $target.filter(opt.prevSlide).addClass( opt.namespace + '-disabled' );
+ } else if( ind == $slides.length - 1 ) {
+ $target.filter(opt.nextSlide).addClass( opt.namespace + '-disabled' );
+ }
+ }
+
+ // Update state of pagination tabs:
+ if( !!opt.addPagination ) {
+ var tabId = $activeSlide.attr('aria-labelledby'),
+ $tab = $('#' + tabId );
+
+ $tab
+ .parent()
+ .addClass(opt.namespace + '-active-tab')
+ .siblings()
+ .removeClass(opt.namespace + '-active-tab')
+ .find('a')
+ .attr({
+ 'aria-selected' : false,
+ 'tabindex' : -1
+ });
+
+ $tab.attr({
+ 'aria-selected' : true,
+ 'tabindex' : 0
+ });
+ }
+ },
+ move : function(e, ui) {
+ var $el = $(this);
+
+ $el
+ .trigger(opt.namespace + "-beforemove")
+ .trigger("navstate", { current: ui.moveTo });
+
+ if( transitionSupport ) {
+
+ $el
+ .adjRounding( opt.slide ) /* Accounts for browser rounding errors. Lookin’ at you, iOS Safari. */
+ .css('marginLeft', ui.moveTo + "%")
+ .one("transitionend webkitTransitionEnd OTransitionEnd", function() {
+ $(this).trigger( opt.namespace + "-aftermove" );
+ });
+
+ } else {
+ $el
+ .adjRounding( opt.slide )
+ .animate({ marginLeft: ui.moveTo + "%" }, { duration : opt.speed, queue : false }, function() {
+ $(this).trigger( opt.namespace + "-aftermove" );
+ });
+ }
+ },
+ nextPrev : function(e, ui) {
+ var $el = $(this),
+ left = ( $el ) ? $el.getPercentage() : 0,
+ $slide = $el.find(opt.slide),
+ constrain = ui.dir === 'prev' ? left != 0 : -left < ($slide.length - 1) * 100,
+ $target = $( '[href="#' + this.id + '"]');
+
+ if (!$el.is(":animated") && constrain ) {
+
+ if ( ui.dir === 'prev' ) {
+ left = ( left % 100 != 0 ) ? carousel.roundDown(left) : left + 100;
+ } else {
+ left = ( ( left % 100 ) != 0 ) ? carousel.roundDown(left) - 100 : left - 100;
+ }
+
+ $el.trigger('carouselmove', { moveTo: left });
+
+ $target
+ .removeClass( opt.namespace + '-disabled')
+ .removeAttr('aria-disabled');
+
+ switch( left ) {
+ case ( -($slide.length - 1) * 100 ):
+ $target.filter(opt.nextSlide)
+ .addClass( opt.namespace + '-disabled')
+ .attr('aria-disabled', true);
+ break;
+ case 0:
+ $target.filter(opt.prevSlide)
+ .addClass( opt.namespace + '-disabled')
+ .attr('aria-disabled', true);
+ break;
+ }
+ } else {
+ var reset = carousel.roundDown(left);
+
+ $el.trigger('carouselmove', { moveTo: reset });
+ }
+
+ }
+ };
+
+ carousel.init(this);
+
+ $(opt.nextSlide + ',' + opt.prevSlide)
+ .bind('click', function(e) {
+ var $el = $(this),
+ link = this.hash,
+ dir = ( $el.is(opt.prevSlide) ) ? 'prev' : 'next',
+ $slider = $(link);
+
+ if ( $el.is('.' + opt.namespace + '-disabled') ) {
+ return false;
+ }
+
+ $slider.trigger('nextprev', { dir: dir });
+
+ e.preventDefault();
+ })
+ .bind('keydown', function(e) {
+ var $el = $(this),
+ link = this.hash;
+
+ switch (e.which) {
+ case 37:
+ case 38:
+ $('#' + link).trigger('nextprev', { dir: 'next' });
+ e.preventDefault();
+ break;
+ case 39:
+ case 40:
+ $('#' + link).trigger('nextprev', { dir: 'prev' });
+ e.preventDefault();
+ break;
+ }
+ });
+
+ var setup = {
+ wrap : this,
+ slider : opt.slider
+ };
+ $slidewrap.bind( "dragSnap", setup, function(e, ui){
+ var $slider = $(this).find( opt.slider ),
+ dir = ( ui.direction === "left" ) ? 'next' : 'prev';
+
+ $slider.trigger("nextprev", { dir: dir });
+ });
+
+
+ $slidewrap.filter('[data-autorotate]').each(function() {
+ var auto,
+ $el = $(this),
+ speed = $el.attr('data-autorotate'),
+ slidenum = $el.find(opt.slide).length,
+ autoAdvance = function() {
+ var $slider = $el.find(opt.slider),
+ active = -( $(opt.slider).getPercentage() / 100 ) + 1;
+
+ switch( active ) {
+ case slidenum:
+ clearInterval(auto);
+
+ auto = setInterval(function() {
+ autoAdvance();
+ $slider.trigger("nextprev", { dir: 'prev' });
+ }, speed);
+
+ break;
+ case 1:
+ clearInterval(auto);
+
+ auto = setInterval(function() {
+ autoAdvance();
+ $slider.trigger("nextprev", { dir: 'next' });
+ }, speed);
+
+ break;
+ }
+ };
+
+ auto = setInterval(autoAdvance, speed);
+
+ $el
+ .attr('aria-live', 'polite')
+ .bind('mouseenter click touchstart', function() {
+ clearInterval(auto);
+ });
+ });
+
+ return this;
+ };
+})(jQuery);
+
+
+$.event.special.dragSnap = {
+ setup: function(setup) {
+
+ var $el = $(this),
+ transitionSwap = function($el, tog) {
+ var speed = .3,
+ transition = ( tog ) ? "margin-left " + speed + "s ease" : 'none';
+
+ $el.css({
+ "-webkit-transition" : transition,
+ "-moz-transition" : transition,
+ "-ms-transition" : transition,
+ "-o-transition" : transition,
+ "transition" : transition
+ });
+ },
+ roundDown = function(left) {
+ var left = parseInt(left, 10);
+
+ return Math.ceil( (left - (left % 100 ) ) / 100) * 100;
+ },
+ snapBack = function(e, ui) {
+ var $el = ui.target,
+ currentPos = ( $el.attr('style') != undefined ) ? $el.getPercentage() : 0,
+ left = (ui.left === false) ? roundDown(currentPos) - 100 : roundDown(currentPos),
+ dStyle = document.body.style,
+ transitionSupport = dStyle.webkitTransition !== undefined ||
+ dStyle.mozTransition !== undefined ||
+ dStyle.msTransition !== undefined ||
+ dStyle.oTransition !== undefined ||
+ dStyle.transition !== undefined;
+
+ transitionSwap($el, true);
+
+ if( transitionSupport ) {
+ $el.css('marginLeft', left + "%");
+ } else {
+ $el.animate({ marginLeft: left + "%" }, opt.speed);
+ }
+ };
+
+ $el
+ .bind("snapback", snapBack)
+ .bind("touchstart", function(e) {
+ var data = e.originalEvent.touches ? e.originalEvent.touches[0] : e,
+ start = {
+ time: (new Date).getTime(),
+ coords: [ data.pageX, data.pageY ],
+ origin: $(e.target).closest( setup.wrap )
+ },
+ stop,
+ $tEl = $(e.target).closest( setup.slider ),
+ currentPos = ( $tEl.attr('style') != undefined ) ? $tEl.getPercentage() : 0;
+
+ transitionSwap($tEl, false);
+
+ function moveHandler(e) {
+ var data = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
+ stop = {
+ time: (new Date).getTime(),
+ coords: [ data.pageX, data.pageY ]
+ };
+
+ if(!start || Math.abs(start.coords[0] - stop.coords[0]) < Math.abs(start.coords[1] - stop.coords[1]) ) {
+ return;
+ }
+
+ $tEl.css({"margin-left": currentPos + ( ( (stop.coords[0] - start.coords[0]) / start.origin.width() ) * 100 ) + '%' });
+
+ // prevent scrolling
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 10) {
+ e.preventDefault();
+ }
+
+ };
+
+ $el
+ .bind("gesturestart", function(e) {
+ $el
+ .unbind("touchmove", moveHandler)
+ .unbind("touchend", moveHandler);
+ })
+ .bind("touchmove", moveHandler)
+ .one("touchend", function(e) {
+
+ $el.unbind("touchmove", moveHandler);
+
+ transitionSwap($tEl, true);
+
+ if (start && stop ) {
+
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 10
+ && Math.abs(start.coords[0] - stop.coords[0]) > Math.abs(start.coords[1] - stop.coords[1])) {
+ e.preventDefault();
+ } else {
+ $el.trigger('snapback', { target: $tEl, left: true });
+ return;
+ }
+
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 1 && Math.abs(start.coords[1] - stop.coords[1]) < 75) {
+ var left = start.coords[0] > stop.coords[0];
+
+ if( -( stop.coords[0] - start.coords[0]) > ( start.origin.width() / 4 ) || ( stop.coords[0] - start.coords[0]) > ( start.origin.width() / 4 ) ) {
+
+ start.origin.trigger("dragSnap", {direction: left ? "left" : "right"});
+
+ } else {
+ $el.trigger('snapback', { target: $tEl, left: left });
+ }
+
+ }
+ }
+ start = stop = undefined;
+ });
+ });
+ }
+}; \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.easing.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.easing.js
new file mode 100644
index 00000000..2e679986
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.easing.js
@@ -0,0 +1,205 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+jQuery.easing['jswing'] = jQuery.easing['swing'];
+
+jQuery.extend( jQuery.easing,
+{
+ def: 'easeOutQuad',
+ swing: function (x, t, b, c, d) {
+ //alert(jQuery.easing.default);
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c*(t/=d)*t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t*t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*(t/=d)*t*((s+1)*t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ if ((t/=d) < (1/2.75)) {
+ return c*(7.5625*t*t) + b;
+ } else if (t < (2/2.75)) {
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+ } else if (t < (2.5/2.75)) {
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+ } else {
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
+ }
+});
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */ \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jStorage.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jStorage.js
new file mode 100644
index 00000000..6ca21b5c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jStorage.js
@@ -0,0 +1,1143 @@
+/*
+ * ----------------------------- JSTORAGE -------------------------------------
+ * Simple local storage wrapper to save data on the browser side, supporting
+ * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
+ *
+ * Copyright (c) 2010 - 2012 Andris Reinman, andris.reinman@gmail.com
+ * Project homepage: www.jstorage.info
+ *
+ * Licensed under MIT-style license:
+ *
+ * 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 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.
+ */
+
+ (function(){
+ var
+ /* jStorage version */
+ JSTORAGE_VERSION = "0.3.0",
+
+ /* detect a dollar object or create one if not found */
+ $ = window.jQuery || window.$ || (window.$ = {}),
+
+ /* check for a JSON handling support */
+ JSON = {
+ parse:
+ window.JSON && (window.JSON.parse || window.JSON.decode) ||
+ String.prototype.evalJSON && function(str){return String(str).evalJSON();} ||
+ $.parseJSON ||
+ $.evalJSON,
+ stringify:
+ Object.toJSON ||
+ window.JSON && (window.JSON.stringify || window.JSON.encode) ||
+ $.toJSON
+ };
+
+ // Break if no JSON support was found
+ if(!JSON.parse || !JSON.stringify){
+ throw new Error("No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page");
+ }
+
+ var
+ /* This is the object, that holds the cached values */
+ _storage = {},
+
+ /* Actual browser storage (localStorage or globalStorage['domain']) */
+ _storage_service = {jStorage:"{}"},
+
+ /* DOM element for older IE versions, holds userData behavior */
+ _storage_elm = null,
+
+ /* How much space does the storage take */
+ _storage_size = 0,
+
+ /* which backend is currently used */
+ _backend = false,
+
+ /* onchange observers */
+ _observers = {},
+
+ /* timeout to wait after onchange event */
+ _observer_timeout = false,
+
+ /* last update time */
+ _observer_update = 0,
+
+ /* pubsub observers */
+ _pubsub_observers = {},
+
+ /* skip published items older than current timestamp */
+ _pubsub_last = +new Date(),
+
+ /* Next check for TTL */
+ _ttl_timeout,
+
+ /* crc32 table */
+ _crc32Table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 "+
+ "0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 "+
+ "6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 "+
+ "FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 "+
+ "A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 "+
+ "32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 "+
+ "56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 "+
+ "C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 "+
+ "E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 "+
+ "6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 "+
+ "12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE "+
+ "A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 "+
+ "DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 "+
+ "5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 "+
+ "2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF "+
+ "04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 "+
+ "7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 "+
+ "FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 "+
+ "A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C "+
+ "36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 "+
+ "5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 "+
+ "C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 "+
+ "EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D "+
+ "7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 "+
+ "18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 "+
+ "A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A "+
+ "D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A "+
+ "53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 "+
+ "2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D",
+
+ /**
+ * XML encoding and decoding as XML nodes can't be JSON'ized
+ * XML nodes are encoded and decoded if the node is the value to be saved
+ * but not if it's as a property of another object
+ * Eg. -
+ * $.jStorage.set("key", xmlNode); // IS OK
+ * $.jStorage.set("key", {xml: xmlNode}); // NOT OK
+ */
+ _XMLService = {
+
+ /**
+ * Validates a XML node to be XML
+ * based on jQuery.isXML function
+ */
+ isXML: function(elm){
+ var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+ },
+
+ /**
+ * Encodes a XML node to string
+ * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
+ */
+ encode: function(xmlNode) {
+ if(!this.isXML(xmlNode)){
+ return false;
+ }
+ try{ // Mozilla, Webkit, Opera
+ return new XMLSerializer().serializeToString(xmlNode);
+ }catch(E1) {
+ try { // IE
+ return xmlNode.xml;
+ }catch(E2){}
+ }
+ return false;
+ },
+
+ /**
+ * Decodes a XML node from string
+ * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
+ */
+ decode: function(xmlString){
+ var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) ||
+ (window.ActiveXObject && function(_xmlString) {
+ var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
+ xml_doc.async = 'false';
+ xml_doc.loadXML(_xmlString);
+ return xml_doc;
+ }),
+ resultXML;
+ if(!dom_parser){
+ return false;
+ }
+ resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml');
+ return this.isXML(resultXML)?resultXML:false;
+ }
+ },
+
+ _localStoragePolyfillSetKey = function(){};
+
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ /**
+ * Initialization function. Detects if the browser supports DOM Storage
+ * or userData behavior and behaves accordingly.
+ */
+ function _init(){
+ /* Check if browser supports localStorage */
+ var localStorageReallyWorks = false;
+ if("localStorage" in window){
+ try {
+ window.localStorage.setItem('_tmptest', 'tmpval');
+ localStorageReallyWorks = true;
+ window.localStorage.removeItem('_tmptest');
+ } catch(BogusQuotaExceededErrorOnIos5) {
+ // Thanks be to iOS5 Private Browsing mode which throws
+ // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
+ }
+ }
+
+ if(localStorageReallyWorks){
+ try {
+ if(window.localStorage) {
+ _storage_service = window.localStorage;
+ _backend = "localStorage";
+ _observer_update = _storage_service.jStorage_update;
+ }
+ } catch(E3) {/* Firefox fails when touching localStorage and cookies are disabled */}
+ }
+ /* Check if browser supports globalStorage */
+ else if("globalStorage" in window){
+ try {
+ if(window.globalStorage) {
+ _storage_service = window.globalStorage[window.location.hostname];
+ _backend = "globalStorage";
+ _observer_update = _storage_service.jStorage_update;
+ }
+ } catch(E4) {/* Firefox fails when touching localStorage and cookies are disabled */}
+ }
+ /* Check if browser supports userData behavior */
+ else {
+ _storage_elm = document.createElement('link');
+ if(_storage_elm.addBehavior){
+
+ /* Use a DOM element to act as userData storage */
+ _storage_elm.style.behavior = 'url(#default#userData)';
+
+ /* userData element needs to be inserted into the DOM! */
+ document.getElementsByTagName('head')[0].appendChild(_storage_elm);
+
+ try{
+ _storage_elm.load("jStorage");
+ }catch(E){
+ // try to reset cache
+ _storage_elm.setAttribute("jStorage", "{}");
+ _storage_elm.save("jStorage");
+ _storage_elm.load("jStorage");
+ }
+
+ var data = "{}";
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+
+ try{
+ _observer_update = _storage_elm.getAttribute("jStorage_update");
+ }catch(E6){}
+
+ _storage_service.jStorage = data;
+ _backend = "userDataBehavior";
+ }else{
+ _storage_elm = null;
+ return;
+ }
+ }
+
+ // Load data from storage
+ _load_storage();
+
+ // remove dead keys
+ _handleTTL();
+
+ // create localStorage and sessionStorage polyfills if needed
+ _createPolyfillStorage("local");
+ _createPolyfillStorage("session");
+
+ // start listening for changes
+ _setupObserver();
+
+ // initialize publish-subscribe service
+ _handlePubSub();
+
+ // handle cached navigation
+ if("addEventListener" in window){
+ window.addEventListener("pageshow", function(event){
+ if(event.persisted){
+ _storageObserver();
+ }
+ }, false);
+ }
+ }
+
+ /**
+ * Create a polyfill for localStorage (type="local") or sessionStorage (type="session")
+ *
+ * @param {String} type Either "local" or "session"
+ * @param {Boolean} forceCreate If set to true, recreate the polyfill (needed with flush)
+ */
+ function _createPolyfillStorage(type, forceCreate){
+ var _skipSave = false,
+ _length = 0,
+ i,
+ storage,
+ storage_source = {};
+
+ var rand = Math.random();
+
+ if(!forceCreate && typeof window[type+"Storage"] != "undefined"){
+ return;
+ }
+
+ // Use globalStorage for localStorage if available
+ if(type == "local" && window.globalStorage){
+ localStorage = window.globalStorage[window.location.hostname];
+ return;
+ }
+
+ // only IE6/7 from this point on
+ if(_backend != "userDataBehavior"){
+ return;
+ }
+
+ // Remove existing storage element if available
+ if(forceCreate && window[type+"Storage"] && window[type+"Storage"].parentNode){
+ window[type+"Storage"].parentNode.removeChild(window[type+"Storage"]);
+ }
+
+ storage = document.createElement("button");
+ document.getElementsByTagName('head')[0].appendChild(storage);
+
+ if(type == "local"){
+ storage_source = _storage;
+ }else if(type == "session"){
+ _sessionStoragePolyfillUpdate();
+ }
+
+ for(i in storage_source){
+
+ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i != "length" && typeof storage_source[i] != "undefined"){
+ if(!(i in storage)){
+ _length++;
+ }
+ storage[i] = storage_source[i];
+ }
+ }
+
+ // Polyfill API
+
+ /**
+ * Indicates how many keys are stored in the storage
+ */
+ storage.length = _length;
+
+ /**
+ * Returns the key of the nth stored value
+ *
+ * @param {Number} n Index position
+ * @return {String} Key name of the nth stored value
+ */
+ storage.key = function(n){
+ var count = 0, i;
+ _sessionStoragePolyfillUpdate();
+ for(i in storage_source){
+ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i!="length" && typeof storage_source[i] != "undefined"){
+ if(count == n){
+ return i;
+ }
+ count++;
+ }
+ }
+ }
+
+ /**
+ * Returns the current value associated with the given key
+ *
+ * @param {String} key key name
+ * @return {Mixed} Stored value
+ */
+ storage.getItem = function(key){
+ _sessionStoragePolyfillUpdate();
+ if(type == "session"){
+ return storage_source[key];
+ }
+ return $.jStorage.get(key);
+ }
+
+ /**
+ * Sets or updates value for a give key
+ *
+ * @param {String} key Key name to be updated
+ * @param {String} value String value to be stored
+ */
+ storage.setItem = function(key, value){
+ if(typeof value == "undefined"){
+ return;
+ }
+ storage[key] = (value || "").toString();
+ }
+
+ /**
+ * Removes key from the storage
+ *
+ * @param {String} key Key name to be removed
+ */
+ storage.removeItem = function(key){
+ if(type == "local"){
+ return $.jStorage.deleteKey(key);
+ }
+
+ storage[key] = undefined;
+
+ _skipSave = true;
+ if(key in storage){
+ storage.removeAttribute(key);
+ }
+ _skipSave = false;
+ }
+
+ /**
+ * Clear storage
+ */
+ storage.clear = function(){
+ if(type == "session"){
+ window.name = "";
+ _createPolyfillStorage("session", true);
+ return;
+ }
+ $.jStorage.flush();
+ }
+
+ if(type == "local"){
+
+ _localStoragePolyfillSetKey = function(key, value){
+ if(key == "length"){
+ return;
+ }
+ _skipSave = true;
+ if(typeof value == "undefined"){
+ if(key in storage){
+ _length--;
+ storage.removeAttribute(key);
+ }
+ }else{
+ if(!(key in storage)){
+ _length++;
+ }
+ storage[key] = (value || "").toString();
+ }
+ storage.length = _length;
+ _skipSave = false;
+ }
+ }
+
+ function _sessionStoragePolyfillUpdate(){
+ if(type != "session"){
+ return;
+ }
+ try{
+ storage_source = JSON.parse(window.name || "{}");
+ }catch(E){
+ storage_source = {};
+ }
+ }
+
+ function _sessionStoragePolyfillSave(){
+ if(type != "session"){
+ return;
+ }
+ window.name = JSON.stringify(storage_source);
+ };
+
+ storage.attachEvent("onpropertychange", function(e){
+ if(e.propertyName == "length"){
+ return;
+ }
+
+ if(_skipSave || e.propertyName == "length"){
+ return;
+ }
+
+ if(type == "local"){
+ if(!(e.propertyName in storage_source) && typeof storage[e.propertyName] != "undefined"){
+ _length ++;
+ }
+ }else if(type == "session"){
+ _sessionStoragePolyfillUpdate();
+ if(typeof storage[e.propertyName] != "undefined" && !(e.propertyName in storage_source)){
+ storage_source[e.propertyName] = storage[e.propertyName];
+ _length++;
+ }else if(typeof storage[e.propertyName] == "undefined" && e.propertyName in storage_source){
+ delete storage_source[e.propertyName];
+ _length--;
+ }else{
+ storage_source[e.propertyName] = storage[e.propertyName];
+ }
+
+ _sessionStoragePolyfillSave();
+ storage.length = _length;
+ return;
+ }
+
+ $.jStorage.set(e.propertyName, storage[e.propertyName]);
+ storage.length = _length;
+ });
+
+ window[type+"Storage"] = storage;
+ }
+
+ /**
+ * Reload data from storage when needed
+ */
+ function _reloadData(){
+ var data = "{}";
+
+ if(_backend == "userDataBehavior"){
+ _storage_elm.load("jStorage");
+
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+
+ try{
+ _observer_update = _storage_elm.getAttribute("jStorage_update");
+ }catch(E6){}
+
+ _storage_service.jStorage = data;
+ }
+
+ _load_storage();
+
+ // remove dead keys
+ _handleTTL();
+
+ _handlePubSub();
+ }
+
+ /**
+ * Sets up a storage change observer
+ */
+ function _setupObserver(){
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ if("addEventListener" in window){
+ window.addEventListener("storage", _storageObserver, false);
+ }else{
+ document.attachEvent("onstorage", _storageObserver);
+ }
+ }else if(_backend == "userDataBehavior"){
+ setInterval(_storageObserver, 1000);
+ }
+ }
+
+ /**
+ * Fired on any kind of data change, needs to check if anything has
+ * really been changed
+ */
+ function _storageObserver(){
+ var updateTime;
+ // cumulate change notifications with timeout
+ clearTimeout(_observer_timeout);
+ _observer_timeout = setTimeout(function(){
+
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ updateTime = _storage_service.jStorage_update;
+ }else if(_backend == "userDataBehavior"){
+ _storage_elm.load("jStorage");
+ try{
+ updateTime = _storage_elm.getAttribute("jStorage_update");
+ }catch(E5){}
+ }
+
+ if(updateTime && updateTime != _observer_update){
+ _observer_update = updateTime;
+ _checkUpdatedKeys();
+ }
+
+ }, 25);
+ }
+
+ /**
+ * Reloads the data and checks if any keys are changed
+ */
+ function _checkUpdatedKeys(){
+ var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)),
+ newCrc32List;
+
+ _reloadData();
+ newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32));
+
+ var key,
+ updated = [],
+ removed = [];
+
+ for(key in oldCrc32List){
+ if(oldCrc32List.hasOwnProperty(key)){
+ if(!newCrc32List[key]){
+ removed.push(key);
+ continue;
+ }
+ if(oldCrc32List[key] != newCrc32List[key]){
+ updated.push(key);
+ }
+ }
+ }
+
+ for(key in newCrc32List){
+ if(newCrc32List.hasOwnProperty(key)){
+ if(!oldCrc32List[key]){
+ updated.push(key);
+ }
+ }
+ }
+
+ _fireObservers(updated, "updated");
+ _fireObservers(removed, "deleted");
+ }
+
+ /**
+ * Fires observers for updated keys
+ *
+ * @param {Array|String} keys Array of key names or a key
+ * @param {String} action What happened with the value (updated, deleted, flushed)
+ */
+ function _fireObservers(keys, action){
+ keys = [].concat(keys || []);
+ if(action == "flushed"){
+ keys = [];
+ for(var key in _observers){
+ if(_observers.hasOwnProperty(key)){
+ keys.push(key);
+ }
+ }
+ action = "deleted";
+ }
+ for(var i=0, len = keys.length; i<len; i++){
+ if(_observers[keys[i]]){
+ for(var j=0, jlen = _observers[keys[i]].length; j<jlen; j++){
+ _observers[keys[i]][j](keys[i], action);
+ }
+ }
+ }
+ }
+
+ /**
+ * Publishes key change to listeners
+ */
+ function _publishChange(){
+ var updateTime = (+new Date()).toString();
+
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ _storage_service.jStorage_update = updateTime;
+ }else if(_backend == "userDataBehavior"){
+ _storage_elm.setAttribute("jStorage_update", updateTime);
+ _storage_elm.save("jStorage");
+ }
+
+ _storageObserver();
+ }
+
+ /**
+ * Loads the data from the storage based on the supported mechanism
+ */
+ function _load_storage(){
+ /* if jStorage string is retrieved, then decode it */
+ if(_storage_service.jStorage){
+ try{
+ _storage = JSON.parse(String(_storage_service.jStorage));
+ }catch(E6){_storage_service.jStorage = "{}";}
+ }else{
+ _storage_service.jStorage = "{}";
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+
+ if(!_storage.__jstorage_meta){
+ _storage.__jstorage_meta = {};
+ }
+ if(!_storage.__jstorage_meta.CRC32){
+ _storage.__jstorage_meta.CRC32 = {};
+ }
+ }
+
+ /**
+ * This functions provides the "save" mechanism to store the jStorage object
+ */
+ function _save(){
+ _dropOldEvents(); // remove expired events
+ try{
+ _storage_service.jStorage = JSON.stringify(_storage);
+ // If userData is used as the storage engine, additional
+ if(_storage_elm) {
+ _storage_elm.setAttribute("jStorage",_storage_service.jStorage);
+ _storage_elm.save("jStorage");
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+ }catch(E7){/* probably cache is full, nothing is saved this way*/}
+ }
+
+ /**
+ * Function checks if a key is set and is string or numberic
+ *
+ * @param {String} key Key name
+ */
+ function _checkKey(key){
+ if(!key || (typeof key != "string" && typeof key != "number")){
+ throw new TypeError('Key name must be string or numeric');
+ }
+ if(key == "__jstorage_meta"){
+ throw new TypeError('Reserved key name');
+ }
+ return true;
+ }
+
+ /**
+ * Removes expired keys
+ */
+ function _handleTTL(){
+ var curtime, i, TTL, CRC32, nextExpire = Infinity, changed = false, deleted = [];
+
+ clearTimeout(_ttl_timeout);
+
+ if(!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != "object"){
+ // nothing to do here
+ return;
+ }
+
+ curtime = +new Date();
+ TTL = _storage.__jstorage_meta.TTL;
+
+ CRC32 = _storage.__jstorage_meta.CRC32;
+ for(i in TTL){
+ if(TTL.hasOwnProperty(i)){
+ if(TTL[i] <= curtime){
+ delete TTL[i];
+ delete CRC32[i];
+ delete _storage[i];
+ changed = true;
+ deleted.push(i);
+ }else if(TTL[i] < nextExpire){
+ nextExpire = TTL[i];
+ }
+ }
+ }
+
+ // set next check
+ if(nextExpire != Infinity){
+ _ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime);
+ }
+
+ // save changes
+ if(changed){
+ _save();
+ _publishChange();
+ _fireObservers(deleted, "deleted");
+ }
+ }
+
+ /**
+ * Checks if there's any events on hold to be fired to listeners
+ */
+ function _handlePubSub(){
+ if(!_storage.__jstorage_meta.PubSub){
+ return;
+ }
+ var pubelm,
+ _pubsubCurrent = _pubsub_last;
+
+ for(var i=len=_storage.__jstorage_meta.PubSub.length-1; i>=0; i--){
+ pubelm = _storage.__jstorage_meta.PubSub[i];
+ if(pubelm[0] > _pubsub_last){
+ _pubsubCurrent = pubelm[0];
+ _fireSubscribers(pubelm[1], pubelm[2]);
+ }
+ }
+
+ _pubsub_last = _pubsubCurrent;
+ }
+
+ /**
+ * Fires all subscriber listeners for a pubsub channel
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload data to deliver
+ */
+ function _fireSubscribers(channel, payload){
+ if(_pubsub_observers[channel]){
+ for(var i=0, len = _pubsub_observers[channel].length; i<len; i++){
+ // send immutable data that can't be modified by listeners
+ _pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload)));
+ }
+ }
+ }
+
+ /**
+ * Remove old events from the publish stream (at least 2sec old)
+ */
+ function _dropOldEvents(){
+ if(!_storage.__jstorage_meta.PubSub){
+ return;
+ }
+
+ var retire = +new Date() - 2000;
+
+ for(var i=0, len = _storage.__jstorage_meta.PubSub.length; i<len; i++){
+ if(_storage.__jstorage_meta.PubSub[i][0] <= retire){
+ // deleteCount is needed for IE6
+ _storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i);
+ break;
+ }
+ }
+
+ if(!_storage.__jstorage_meta.PubSub.length){
+ delete _storage.__jstorage_meta.PubSub;
+ }
+
+ }
+
+ /**
+ * Publish payload to a channel
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload to send to the subscribers
+ */
+ function _publish(channel, payload){
+ if(!_storage.__jstorage_meta){
+ _storage.__jstorage_meta = {};
+ }
+ if(!_storage.__jstorage_meta.PubSub){
+ _storage.__jstorage_meta.PubSub = [];
+ }
+
+ _storage.__jstorage_meta.PubSub.unshift([+new Date, channel, payload]);
+
+ _save();
+ _publishChange();
+ }
+
+ /**
+ * CRC32 calculation based on http://noteslog.com/post/crc32-for-javascript/
+ *
+ * @param {String} str String to be hashed
+ * @param {Number} [crc] Last crc value in case of streams
+ */
+ function _crc32(str, crc){
+ crc = crc || 0;
+
+ var n = 0, //a number between 0 and 255
+ x = 0; //an hex number
+
+ crc = crc ^ (-1);
+ for(var i = 0, len = str.length; i < len; i++){
+ n = (crc ^ str.charCodeAt(i)) & 0xFF;
+ x = "0x" + _crc32Table.substr(n * 9, 8);
+ crc = (crc >>> 8)^x;
+ }
+ return crc^(-1);
+ }
+
+ ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+ $.jStorage = {
+ /* Version number */
+ version: JSTORAGE_VERSION,
+
+ /**
+ * Sets a key's value.
+ *
+ * @param {String} key Key to set. If this value is not set or not
+ * a string an exception is raised.
+ * @param {Mixed} value Value to set. This can be any value that is JSON
+ * compatible (Numbers, Strings, Objects etc.).
+ * @param {Object} [options] - possible options to use
+ * @param {Number} [options.TTL] - optional TTL value
+ * @return {Mixed} the used value
+ */
+ set: function(key, value, options){
+ _checkKey(key);
+
+ options = options || {};
+
+ // undefined values are deleted automatically
+ if(typeof value == "undefined"){
+ this.deleteKey(key);
+ return value;
+ }
+
+ if(_XMLService.isXML(value)){
+ value = {_is_xml:true,xml:_XMLService.encode(value)};
+ }else if(typeof value == "function"){
+ return undefined; // functions can't be saved!
+ }else if(value && typeof value == "object"){
+ // clone the object before saving to _storage tree
+ value = JSON.parse(JSON.stringify(value));
+ }
+
+ _storage[key] = value;
+
+ _storage.__jstorage_meta.CRC32[key] = _crc32(JSON.stringify(value));
+
+ this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange
+
+ _localStoragePolyfillSetKey(key, value);
+
+ _fireObservers(key, "updated");
+ return value;
+ },
+
+ /**
+ * Looks up a key in cache
+ *
+ * @param {String} key - Key to look up.
+ * @param {mixed} def - Default value to return, if key didn't exist.
+ * @return {Mixed} the key value, default value or null
+ */
+ get: function(key, def){
+ _checkKey(key);
+ if(key in _storage){
+ if(_storage[key] && typeof _storage[key] == "object" &&
+ _storage[key]._is_xml &&
+ _storage[key]._is_xml){
+ return _XMLService.decode(_storage[key].xml);
+ }else{
+ return _storage[key];
+ }
+ }
+ return typeof(def) == 'undefined' ? null : def;
+ },
+
+ /**
+ * Deletes a key from cache.
+ *
+ * @param {String} key - Key to delete.
+ * @return {Boolean} true if key existed or false if it didn't
+ */
+ deleteKey: function(key){
+ _checkKey(key);
+ if(key in _storage){
+ delete _storage[key];
+ // remove from TTL list
+ if(typeof _storage.__jstorage_meta.TTL == "object" &&
+ key in _storage.__jstorage_meta.TTL){
+ delete _storage.__jstorage_meta.TTL[key];
+ }
+
+ delete _storage.__jstorage_meta.CRC32[key];
+ _localStoragePolyfillSetKey(key, undefined);
+
+ _save();
+ _publishChange();
+ _fireObservers(key, "deleted");
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Sets a TTL for a key, or remove it if ttl value is 0 or below
+ *
+ * @param {String} key - key to set the TTL for
+ * @param {Number} ttl - TTL timeout in milliseconds
+ * @return {Boolean} true if key existed or false if it didn't
+ */
+ setTTL: function(key, ttl){
+ var curtime = +new Date();
+ _checkKey(key);
+ ttl = Number(ttl) || 0;
+ if(key in _storage){
+
+ if(!_storage.__jstorage_meta.TTL){
+ _storage.__jstorage_meta.TTL = {};
+ }
+
+ // Set TTL value for the key
+ if(ttl>0){
+ _storage.__jstorage_meta.TTL[key] = curtime + ttl;
+ }else{
+ delete _storage.__jstorage_meta.TTL[key];
+ }
+
+ _save();
+
+ _handleTTL();
+
+ _publishChange();
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set
+ *
+ * @param {String} key Key to check
+ * @return {Number} Remaining TTL in milliseconds
+ */
+ getTTL: function(key){
+ var curtime = +new Date(), ttl;
+ _checkKey(key);
+ if(key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]){
+ ttl = _storage.__jstorage_meta.TTL[key] - curtime;
+ return ttl || 0;
+ }
+ return 0;
+ },
+
+ /**
+ * Deletes everything in cache.
+ *
+ * @return {Boolean} Always true
+ */
+ flush: function(){
+ _storage = {__jstorage_meta:{CRC32:{}}};
+ _createPolyfillStorage("local", true);
+ _save();
+ _publishChange();
+ _fireObservers(null, "flushed");
+ return true;
+ },
+
+ /**
+ * Returns a read-only copy of _storage
+ *
+ * @return {Object} Read-only copy of _storage
+ */
+ storageObj: function(){
+ function F() {}
+ F.prototype = _storage;
+ return new F();
+ },
+
+ /**
+ * Returns an index of all used keys as an array
+ * ['key1', 'key2',..'keyN']
+ *
+ * @return {Array} Used keys
+ */
+ index: function(){
+ var index = [], i;
+ for(i in _storage){
+ if(_storage.hasOwnProperty(i) && i != "__jstorage_meta"){
+ index.push(i);
+ }
+ }
+ return index;
+ },
+
+ /**
+ * How much space in bytes does the storage take?
+ *
+ * @return {Number} Storage size in chars (not the same as in bytes,
+ * since some chars may take several bytes)
+ */
+ storageSize: function(){
+ return _storage_size;
+ },
+
+ /**
+ * Which backend is currently in use?
+ *
+ * @return {String} Backend name
+ */
+ currentBackend: function(){
+ return _backend;
+ },
+
+ /**
+ * Test if storage is available
+ *
+ * @return {Boolean} True if storage can be used
+ */
+ storageAvailable: function(){
+ return !!_backend;
+ },
+
+ /**
+ * Register change listeners
+ *
+ * @param {String} key Key name
+ * @param {Function} callback Function to run when the key changes
+ */
+ listenKeyChange: function(key, callback){
+ _checkKey(key);
+ if(!_observers[key]){
+ _observers[key] = [];
+ }
+ _observers[key].push(callback);
+ },
+
+ /**
+ * Remove change listeners
+ *
+ * @param {String} key Key name to unregister listeners against
+ * @param {Function} [callback] If set, unregister the callback, if not - unregister all
+ */
+ stopListening: function(key, callback){
+ _checkKey(key);
+
+ if(!_observers[key]){
+ return;
+ }
+
+ if(!callback){
+ delete _observers[key];
+ return;
+ }
+
+ for(var i = _observers[key].length - 1; i>=0; i--){
+ if(_observers[key][i] == callback){
+ _observers[key].splice(i,1);
+ }
+ }
+ },
+
+ /**
+ * Subscribe to a Publish/Subscribe event stream
+ *
+ * @param {String} channel Channel name
+ * @param {Function} callback Function to run when the something is published to the channel
+ */
+ subscribe: function(channel, callback){
+ channel = (channel || "").toString();
+ if(!channel){
+ throw new TypeError('Channel not defined');
+ }
+ if(!_pubsub_observers[channel]){
+ _pubsub_observers[channel] = [];
+ }
+ _pubsub_observers[channel].push(callback);
+ },
+
+ /**
+ * Publish data to an event stream
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload to deliver
+ */
+ publish: function(channel, payload){
+ channel = (channel || "").toString();
+ if(!channel){
+ throw new TypeError('Channel not defined');
+ }
+
+ _publish(channel, payload);
+ },
+
+ /**
+ * Reloads the data from browser storage
+ */
+ reInit: function(){
+ _reloadData();
+ }
+ };
+
+ // Initialize jStorage
+ _init();
+
+})();
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jcarousel.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jcarousel.js
new file mode 100644
index 00000000..dff253f8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.jcarousel.js
@@ -0,0 +1,1057 @@
+/*!
+ * jCarousel - Riding carousels with jQuery
+ * http://sorgalla.com/jcarousel/
+ *
+ * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * Built on top of the jQuery library
+ * http://jquery.com
+ *
+ * Inspired by the "Carousel Component" by Bill Scott
+ * http://billwscott.com/carousel/
+ */
+
+/*global window, jQuery */
+(function($) {
+ // Default configuration properties.
+ var defaults = {
+ vertical: false,
+ rtl: false,
+ start: 1,
+ offset: 1,
+ size: null,
+ scroll: 3,
+ visible: null,
+ animation: 'normal',
+ easing: 'swing',
+ auto: 0,
+ wrap: null,
+ initCallback: null,
+ setupCallback: null,
+ reloadCallback: null,
+ itemLoadCallback: null,
+ itemFirstInCallback: null,
+ itemFirstOutCallback: null,
+ itemLastInCallback: null,
+ itemLastOutCallback: null,
+ itemVisibleInCallback: null,
+ itemVisibleOutCallback: null,
+ animationStepCallback: null,
+ buttonNextHTML: '<div></div>',
+ buttonPrevHTML: '<div></div>',
+ buttonNextEvent: 'click',
+ buttonPrevEvent: 'click',
+ buttonNextCallback: null,
+ buttonPrevCallback: null,
+ itemFallbackDimension: null
+ }, windowLoaded = false;
+
+ $(window).bind('load.jcarousel', function() { windowLoaded = true; });
+
+ /**
+ * The jCarousel object.
+ *
+ * @constructor
+ * @class jcarousel
+ * @param e {HTMLElement} The element to create the carousel for.
+ * @param o {Object} A set of key/value pairs to set as configuration properties.
+ * @cat Plugins/jCarousel
+ */
+ $.jcarousel = function(e, o) {
+ this.options = $.extend({}, defaults, o || {});
+
+ this.locked = false;
+ this.autoStopped = false;
+
+ this.container = null;
+ this.clip = null;
+ this.list = null;
+ this.buttonNext = null;
+ this.buttonPrev = null;
+ this.buttonNextState = null;
+ this.buttonPrevState = null;
+
+ // Only set if not explicitly passed as option
+ if (!o || o.rtl === undefined) {
+ this.options.rtl = ($(e).attr('dir') || $('html').attr('dir') || '').toLowerCase() == 'rtl';
+ }
+
+ this.wh = !this.options.vertical ? 'width' : 'height';
+ this.lt = !this.options.vertical ? (this.options.rtl ? 'right' : 'left') : 'top';
+
+ // Extract skin class
+ var skin = '', split = e.className.split(' ');
+
+ for (var i = 0; i < split.length; i++) {
+ if (split[i].indexOf('jcarousel-skin') != -1) {
+ $(e).removeClass(split[i]);
+ skin = split[i];
+ break;
+ }
+ }
+
+ if (e.nodeName.toUpperCase() == 'UL' || e.nodeName.toUpperCase() == 'OL') {
+ this.list = $(e);
+ this.clip = this.list.parents('.jcarousel-clip');
+ this.container = this.list.parents('.jcarousel-container');
+ } else {
+ this.container = $(e);
+ this.list = this.container.find('ul,ol').eq(0);
+ this.clip = this.container.find('.jcarousel-clip');
+ }
+
+ if (this.clip.size() === 0) {
+ this.clip = this.list.wrap('<div></div>').parent();
+ }
+
+ if (this.container.size() === 0) {
+ this.container = this.clip.wrap('<div></div>').parent();
+ }
+
+ if (skin !== '' && this.container.parent()[0].className.indexOf('jcarousel-skin') == -1) {
+ this.container.wrap('<div class=" '+ skin + '"></div>');
+ }
+
+ this.buttonPrev = $('.jcarousel-prev', this.container);
+
+ if (this.buttonPrev.size() === 0 && this.options.buttonPrevHTML !== null) {
+ this.buttonPrev = $(this.options.buttonPrevHTML).appendTo(this.container);
+ }
+
+ this.buttonPrev.addClass(this.className('jcarousel-prev'));
+
+ this.buttonNext = $('.jcarousel-next', this.container);
+
+ if (this.buttonNext.size() === 0 && this.options.buttonNextHTML !== null) {
+ this.buttonNext = $(this.options.buttonNextHTML).appendTo(this.container);
+ }
+
+ this.buttonNext.addClass(this.className('jcarousel-next'));
+
+ this.clip.addClass(this.className('jcarousel-clip')).css({
+ position: 'relative'
+ });
+
+ this.list.addClass(this.className('jcarousel-list')).css({
+ overflow: 'hidden',
+ position: 'relative',
+ top: 0,
+ margin: 0,
+ padding: 0
+ }).css((this.options.rtl ? 'right' : 'left'), 0);
+
+ this.container.addClass(this.className('jcarousel-container')).css({
+ position: 'relative'
+ });
+
+ if (!this.options.vertical && this.options.rtl) {
+ this.container.addClass('jcarousel-direction-rtl').attr('dir', 'rtl');
+ }
+
+ var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null;
+ var li = this.list.children('li');
+
+ var self = this;
+
+ if (li.size() > 0) {
+ var wh = 0, j = this.options.offset;
+ li.each(function() {
+ self.format(this, j++);
+ wh += self.dimension(this, di);
+ });
+
+ this.list.css(this.wh, (wh + 100) + 'px');
+
+ // Only set if not explicitly passed as option
+ if (!o || o.size === undefined) {
+ this.options.size = li.size();
+ }
+ }
+
+ // For whatever reason, .show() does not work in Safari...
+ this.container.css('display', 'block');
+ this.buttonNext.css('display', 'block');
+ this.buttonPrev.css('display', 'block');
+
+ this.funcNext = function() { self.next(); };
+ this.funcPrev = function() { self.prev(); };
+ this.funcResize = function() {
+ if (self.resizeTimer) {
+ clearTimeout(self.resizeTimer);
+ }
+
+ self.resizeTimer = setTimeout(function() {
+ self.reload();
+ }, 100);
+ };
+
+ if (this.options.initCallback !== null) {
+ this.options.initCallback(this, 'init');
+ }
+
+ if (!windowLoaded && $.browser.safari) {
+ this.buttons(false, false);
+ $(window).bind('load.jcarousel', function() { self.setup(); });
+ } else {
+ this.setup();
+ }
+ };
+
+ // Create shortcut for internal use
+ var $jc = $.jcarousel;
+
+ $jc.fn = $jc.prototype = {
+ jcarousel: '0.2.8'
+ };
+
+ $jc.fn.extend = $jc.extend = $.extend;
+
+ $jc.fn.extend({
+ /**
+ * Setups the carousel.
+ *
+ * @method setup
+ * @return undefined
+ */
+ setup: function() {
+ this.first = null;
+ this.last = null;
+ this.prevFirst = null;
+ this.prevLast = null;
+ this.animating = false;
+ this.timer = null;
+ this.resizeTimer = null;
+ this.tail = null;
+ this.inTail = false;
+
+ if (this.locked) {
+ return;
+ }
+
+ this.list.css(this.lt, this.pos(this.options.offset) + 'px');
+ var p = this.pos(this.options.start, true);
+ this.prevFirst = this.prevLast = null;
+ this.animate(p, false);
+
+ $(window).unbind('resize.jcarousel', this.funcResize).bind('resize.jcarousel', this.funcResize);
+
+ if (this.options.setupCallback !== null) {
+ this.options.setupCallback(this);
+ }
+ },
+
+ /**
+ * Clears the list and resets the carousel.
+ *
+ * @method reset
+ * @return undefined
+ */
+ reset: function() {
+ this.list.empty();
+
+ this.list.css(this.lt, '0px');
+ this.list.css(this.wh, '10px');
+
+ if (this.options.initCallback !== null) {
+ this.options.initCallback(this, 'reset');
+ }
+
+ this.setup();
+ },
+
+ /**
+ * Reloads the carousel and adjusts positions.
+ *
+ * @method reload
+ * @return undefined
+ */
+ reload: function() {
+ if (this.tail !== null && this.inTail) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail);
+ }
+
+ this.tail = null;
+ this.inTail = false;
+
+ if (this.options.reloadCallback !== null) {
+ this.options.reloadCallback(this);
+ }
+
+ if (this.options.visible !== null) {
+ var self = this;
+ var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0;
+ this.list.children('li').each(function(i) {
+ wh += self.dimension(this, di);
+ if (i + 1 < self.first) {
+ lt = wh;
+ }
+ });
+
+ this.list.css(this.wh, wh + 'px');
+ this.list.css(this.lt, -lt + 'px');
+ }
+
+ this.scroll(this.first, false);
+ },
+
+ /**
+ * Locks the carousel.
+ *
+ * @method lock
+ * @return undefined
+ */
+ lock: function() {
+ this.locked = true;
+ this.buttons();
+ },
+
+ /**
+ * Unlocks the carousel.
+ *
+ * @method unlock
+ * @return undefined
+ */
+ unlock: function() {
+ this.locked = false;
+ this.buttons();
+ },
+
+ /**
+ * Sets the size of the carousel.
+ *
+ * @method size
+ * @return undefined
+ * @param s {Number} The size of the carousel.
+ */
+ size: function(s) {
+ if (s !== undefined) {
+ this.options.size = s;
+ if (!this.locked) {
+ this.buttons();
+ }
+ }
+
+ return this.options.size;
+ },
+
+ /**
+ * Checks whether a list element exists for the given index (or index range).
+ *
+ * @method get
+ * @return bool
+ * @param i {Number} The index of the (first) element.
+ * @param i2 {Number} The index of the last element.
+ */
+ has: function(i, i2) {
+ if (i2 === undefined || !i2) {
+ i2 = i;
+ }
+
+ if (this.options.size !== null && i2 > this.options.size) {
+ i2 = this.options.size;
+ }
+
+ for (var j = i; j <= i2; j++) {
+ var e = this.get(j);
+ if (!e.length || e.hasClass('jcarousel-item-placeholder')) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Returns a jQuery object with list element for the given index.
+ *
+ * @method get
+ * @return jQuery
+ * @param i {Number} The index of the element.
+ */
+ get: function(i) {
+ return $('>.jcarousel-item-' + i, this.list);
+ },
+
+ /**
+ * Adds an element for the given index to the list.
+ * If the element already exists, it updates the inner html.
+ * Returns the created element as jQuery object.
+ *
+ * @method add
+ * @return jQuery
+ * @param i {Number} The index of the element.
+ * @param s {String} The innerHTML of the element.
+ */
+ add: function(i, s) {
+ var e = this.get(i), old = 0, n = $(s);
+
+ if (e.length === 0) {
+ var c, j = $jc.intval(i);
+ e = this.create(i);
+ while (true) {
+ c = this.get(--j);
+ if (j <= 0 || c.length) {
+ if (j <= 0) {
+ this.list.prepend(e);
+ } else {
+ c.after(e);
+ }
+ break;
+ }
+ }
+ } else {
+ old = this.dimension(e);
+ }
+
+ if (n.get(0).nodeName.toUpperCase() == 'LI') {
+ e.replaceWith(n);
+ e = n;
+ } else {
+ e.empty().append(s);
+ }
+
+ this.format(e.removeClass(this.className('jcarousel-item-placeholder')), i);
+
+ var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null;
+ var wh = this.dimension(e, di) - old;
+
+ if (i > 0 && i < this.first) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - wh + 'px');
+ }
+
+ this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px');
+
+ return e;
+ },
+
+ /**
+ * Removes an element for the given index from the list.
+ *
+ * @method remove
+ * @return undefined
+ * @param i {Number} The index of the element.
+ */
+ remove: function(i) {
+ var e = this.get(i);
+
+ // Check if item exists and is not currently visible
+ if (!e.length || (i >= this.first && i <= this.last)) {
+ return;
+ }
+
+ var d = this.dimension(e);
+
+ if (i < this.first) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px');
+ }
+
+ e.remove();
+
+ this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px');
+ },
+
+ /**
+ * Moves the carousel forwards.
+ *
+ * @method next
+ * @return undefined
+ */
+ next: function() {
+ if (this.tail !== null && !this.inTail) {
+ this.scrollTail(false);
+ } else {
+ this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size !== null && this.last == this.options.size) ? 1 : this.first + this.options.scroll);
+ }
+ },
+
+ /**
+ * Moves the carousel backwards.
+ *
+ * @method prev
+ * @return undefined
+ */
+ prev: function() {
+ if (this.tail !== null && this.inTail) {
+ this.scrollTail(true);
+ } else {
+ this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size !== null && this.first == 1) ? this.options.size : this.first - this.options.scroll);
+ }
+ },
+
+ /**
+ * Scrolls the tail of the carousel.
+ *
+ * @method scrollTail
+ * @return undefined
+ * @param b {Boolean} Whether scroll the tail back or forward.
+ */
+ scrollTail: function(b) {
+ if (this.locked || this.animating || !this.tail) {
+ return;
+ }
+
+ this.pauseAuto();
+
+ var pos = $jc.intval(this.list.css(this.lt));
+
+ pos = !b ? pos - this.tail : pos + this.tail;
+ this.inTail = !b;
+
+ // Save for callbacks
+ this.prevFirst = this.first;
+ this.prevLast = this.last;
+
+ this.animate(pos);
+ },
+
+ /**
+ * Scrolls the carousel to a certain position.
+ *
+ * @method scroll
+ * @return undefined
+ * @param i {Number} The index of the element to scoll to.
+ * @param a {Boolean} Flag indicating whether to perform animation.
+ */
+ scroll: function(i, a) {
+ if (this.locked || this.animating) {
+ return;
+ }
+
+ this.pauseAuto();
+ this.animate(this.pos(i), a);
+ },
+
+ /**
+ * Prepares the carousel and return the position for a certian index.
+ *
+ * @method pos
+ * @return {Number}
+ * @param i {Number} The index of the element to scoll to.
+ * @param fv {Boolean} Whether to force last item to be visible.
+ */
+ pos: function(i, fv) {
+ var pos = $jc.intval(this.list.css(this.lt));
+
+ if (this.locked || this.animating) {
+ return pos;
+ }
+
+ if (this.options.wrap != 'circular') {
+ i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i);
+ }
+
+ var back = this.first > i;
+
+ // Create placeholders, new list width/height
+ // and new list position
+ var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first;
+ var c = back ? this.get(f) : this.get(this.last);
+ var j = back ? f : f - 1;
+ var e = null, l = 0, p = false, d = 0, g;
+
+ while (back ? --j >= i : ++j < i) {
+ e = this.get(j);
+ p = !e.length;
+ if (e.length === 0) {
+ e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
+ c[back ? 'before' : 'after' ](e);
+
+ if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) {
+ g = this.get(this.index(j));
+ if (g.length) {
+ e = this.add(j, g.clone(true));
+ }
+ }
+ }
+
+ c = e;
+ d = this.dimension(e);
+
+ if (p) {
+ l += d;
+ }
+
+ if (this.first !== null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size === null || j <= this.options.size)))) {
+ pos = back ? pos + d : pos - d;
+ }
+ }
+
+ // Calculate visible items
+ var clipping = this.clipping(), cache = [], visible = 0, v = 0;
+ c = this.get(i - 1);
+ j = i;
+
+ while (++visible) {
+ e = this.get(j);
+ p = !e.length;
+ if (e.length === 0) {
+ e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
+ // This should only happen on a next scroll
+ if (c.length === 0) {
+ this.list.prepend(e);
+ } else {
+ c[back ? 'before' : 'after' ](e);
+ }
+
+ if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) {
+ g = this.get(this.index(j));
+ if (g.length) {
+ e = this.add(j, g.clone(true));
+ }
+ }
+ }
+
+ c = e;
+ d = this.dimension(e);
+ if (d === 0) {
+ throw new Error('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...');
+ }
+
+ if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size) {
+ cache.push(e);
+ } else if (p) {
+ l += d;
+ }
+
+ v += d;
+
+ if (v >= clipping) {
+ break;
+ }
+
+ j++;
+ }
+
+ // Remove out-of-range placeholders
+ for (var x = 0; x < cache.length; x++) {
+ cache[x].remove();
+ }
+
+ // Resize list
+ if (l > 0) {
+ this.list.css(this.wh, this.dimension(this.list) + l + 'px');
+
+ if (back) {
+ pos -= l;
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px');
+ }
+ }
+
+ // Calculate first and last item
+ var last = i + visible - 1;
+ if (this.options.wrap != 'circular' && this.options.size && last > this.options.size) {
+ last = this.options.size;
+ }
+
+ if (j > last) {
+ visible = 0;
+ j = last;
+ v = 0;
+ while (++visible) {
+ e = this.get(j--);
+ if (!e.length) {
+ break;
+ }
+ v += this.dimension(e);
+ if (v >= clipping) {
+ break;
+ }
+ }
+ }
+
+ var first = last - visible + 1;
+ if (this.options.wrap != 'circular' && first < 1) {
+ first = 1;
+ }
+
+ if (this.inTail && back) {
+ pos += this.tail;
+ this.inTail = false;
+ }
+
+ this.tail = null;
+ if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) {
+ var m = $jc.intval(this.get(last).css(!this.options.vertical ? 'marginRight' : 'marginBottom'));
+ if ((v - m) > clipping) {
+ this.tail = v - clipping - m;
+ }
+ }
+
+ if (fv && i === this.options.size && this.tail) {
+ pos -= this.tail;
+ this.inTail = true;
+ }
+
+ // Adjust position
+ while (i-- > first) {
+ pos += this.dimension(this.get(i));
+ }
+
+ // Save visible item range
+ this.prevFirst = this.first;
+ this.prevLast = this.last;
+ this.first = first;
+ this.last = last;
+
+ return pos;
+ },
+
+ /**
+ * Animates the carousel to a certain position.
+ *
+ * @method animate
+ * @return undefined
+ * @param p {Number} Position to scroll to.
+ * @param a {Boolean} Flag indicating whether to perform animation.
+ */
+ animate: function(p, a) {
+ if (this.locked || this.animating) {
+ return;
+ }
+
+ this.animating = true;
+
+ var self = this;
+ var scrolled = function() {
+ self.animating = false;
+
+ if (p === 0) {
+ self.list.css(self.lt, 0);
+ }
+
+ if (!self.autoStopped && (self.options.wrap == 'circular' || self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size === null || self.last < self.options.size || (self.last == self.options.size && self.tail !== null && !self.inTail))) {
+ self.startAuto();
+ }
+
+ self.buttons();
+ self.notify('onAfterAnimation');
+
+ // This function removes items which are appended automatically for circulation.
+ // This prevents the list from growing infinitely.
+ if (self.options.wrap == 'circular' && self.options.size !== null) {
+ for (var i = self.prevFirst; i <= self.prevLast; i++) {
+ if (i !== null && !(i >= self.first && i <= self.last) && (i < 1 || i > self.options.size)) {
+ self.remove(i);
+ }
+ }
+ }
+ };
+
+ this.notify('onBeforeAnimation');
+
+ // Animate
+ if (!this.options.animation || a === false) {
+ this.list.css(this.lt, p + 'px');
+ scrolled();
+ } else {
+ var o = !this.options.vertical ? (this.options.rtl ? {'right': p} : {'left': p}) : {'top': p};
+ // Define animation settings.
+ var settings = {
+ duration: this.options.animation,
+ easing: this.options.easing,
+ complete: scrolled
+ };
+ // If we have a step callback, specify it as well.
+ if ($.isFunction(this.options.animationStepCallback)) {
+ settings.step = this.options.animationStepCallback;
+ }
+ // Start the animation.
+ this.list.animate(o, settings);
+ }
+ },
+
+ /**
+ * Starts autoscrolling.
+ *
+ * @method auto
+ * @return undefined
+ * @param s {Number} Seconds to periodically autoscroll the content.
+ */
+ startAuto: function(s) {
+ if (s !== undefined) {
+ this.options.auto = s;
+ }
+
+ if (this.options.auto === 0) {
+ return this.stopAuto();
+ }
+
+ if (this.timer !== null) {
+ return;
+ }
+
+ this.autoStopped = false;
+
+ var self = this;
+ this.timer = window.setTimeout(function() { self.next(); }, this.options.auto * 1000);
+ },
+
+ /**
+ * Stops autoscrolling.
+ *
+ * @method stopAuto
+ * @return undefined
+ */
+ stopAuto: function() {
+ this.pauseAuto();
+ this.autoStopped = true;
+ },
+
+ /**
+ * Pauses autoscrolling.
+ *
+ * @method pauseAuto
+ * @return undefined
+ */
+ pauseAuto: function() {
+ if (this.timer === null) {
+ return;
+ }
+
+ window.clearTimeout(this.timer);
+ this.timer = null;
+ },
+
+ /**
+ * Sets the states of the prev/next buttons.
+ *
+ * @method buttons
+ * @return undefined
+ */
+ buttons: function(n, p) {
+ if (n == null) {
+ n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size === null || this.last < this.options.size);
+ if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size !== null && this.last >= this.options.size) {
+ n = this.tail !== null && !this.inTail;
+ }
+ }
+
+ if (p == null) {
+ p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1);
+ if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size !== null && this.first == 1) {
+ p = this.tail !== null && this.inTail;
+ }
+ }
+
+ var self = this;
+
+ if (this.buttonNext.size() > 0) {
+ this.buttonNext.unbind(this.options.buttonNextEvent + '.jcarousel', this.funcNext);
+
+ if (n) {
+ this.buttonNext.bind(this.options.buttonNextEvent + '.jcarousel', this.funcNext);
+ }
+
+ this.buttonNext[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
+
+ if (this.options.buttonNextCallback !== null && this.buttonNext.data('jcarouselstate') != n) {
+ this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); }).data('jcarouselstate', n);
+ }
+ } else {
+ if (this.options.buttonNextCallback !== null && this.buttonNextState != n) {
+ this.options.buttonNextCallback(self, null, n);
+ }
+ }
+
+ if (this.buttonPrev.size() > 0) {
+ this.buttonPrev.unbind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev);
+
+ if (p) {
+ this.buttonPrev.bind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev);
+ }
+
+ this.buttonPrev[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);
+
+ if (this.options.buttonPrevCallback !== null && this.buttonPrev.data('jcarouselstate') != p) {
+ this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); }).data('jcarouselstate', p);
+ }
+ } else {
+ if (this.options.buttonPrevCallback !== null && this.buttonPrevState != p) {
+ this.options.buttonPrevCallback(self, null, p);
+ }
+ }
+
+ this.buttonNextState = n;
+ this.buttonPrevState = p;
+ },
+
+ /**
+ * Notify callback of a specified event.
+ *
+ * @method notify
+ * @return undefined
+ * @param evt {String} The event name
+ */
+ notify: function(evt) {
+ var state = this.prevFirst === null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev');
+
+ // Load items
+ this.callback('itemLoadCallback', evt, state);
+
+ if (this.prevFirst !== this.first) {
+ this.callback('itemFirstInCallback', evt, state, this.first);
+ this.callback('itemFirstOutCallback', evt, state, this.prevFirst);
+ }
+
+ if (this.prevLast !== this.last) {
+ this.callback('itemLastInCallback', evt, state, this.last);
+ this.callback('itemLastOutCallback', evt, state, this.prevLast);
+ }
+
+ this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast);
+ this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last);
+ },
+
+ callback: function(cb, evt, state, i1, i2, i3, i4) {
+ if (this.options[cb] == null || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation')) {
+ return;
+ }
+
+ var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb];
+
+ if (!$.isFunction(callback)) {
+ return;
+ }
+
+ var self = this;
+
+ if (i1 === undefined) {
+ callback(self, state, evt);
+ } else if (i2 === undefined) {
+ this.get(i1).each(function() { callback(self, this, i1, state, evt); });
+ } else {
+ var call = function(i) {
+ self.get(i).each(function() { callback(self, this, i, state, evt); });
+ };
+ for (var i = i1; i <= i2; i++) {
+ if (i !== null && !(i >= i3 && i <= i4)) {
+ call(i);
+ }
+ }
+ }
+ },
+
+ create: function(i) {
+ return this.format('<li></li>', i);
+ },
+
+ format: function(e, i) {
+ e = $(e);
+ var split = e.get(0).className.split(' ');
+ for (var j = 0; j < split.length; j++) {
+ if (split[j].indexOf('jcarousel-') != -1) {
+ e.removeClass(split[j]);
+ }
+ }
+ e.addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i)).css({
+ 'float': (this.options.rtl ? 'right' : 'left'),
+ 'list-style': 'none'
+ }).attr('jcarouselindex', i);
+ return e;
+ },
+
+ className: function(c) {
+ return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical');
+ },
+
+ dimension: function(e, d) {
+ var el = $(e);
+
+ if (d == null) {
+ return !this.options.vertical ?
+ (el.outerWidth(true) || $jc.intval(this.options.itemFallbackDimension)) :
+ (el.outerHeight(true) || $jc.intval(this.options.itemFallbackDimension));
+ } else {
+ var w = !this.options.vertical ?
+ d - $jc.intval(el.css('marginLeft')) - $jc.intval(el.css('marginRight')) :
+ d - $jc.intval(el.css('marginTop')) - $jc.intval(el.css('marginBottom'));
+
+ $(el).css(this.wh, w + 'px');
+
+ return this.dimension(el);
+ }
+ },
+
+ clipping: function() {
+ return !this.options.vertical ?
+ this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) :
+ this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth'));
+ },
+
+ index: function(i, s) {
+ if (s == null) {
+ s = this.options.size;
+ }
+
+ return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1;
+ }
+ });
+
+ $jc.extend({
+ /**
+ * Gets/Sets the global default configuration properties.
+ *
+ * @method defaults
+ * @return {Object}
+ * @param d {Object} A set of key/value pairs to set as configuration properties.
+ */
+ defaults: function(d) {
+ return $.extend(defaults, d || {});
+ },
+
+ intval: function(v) {
+ v = parseInt(v, 10);
+ return isNaN(v) ? 0 : v;
+ },
+
+ windowLoaded: function() {
+ windowLoaded = true;
+ }
+ });
+
+ /**
+ * Creates a carousel for all matched elements.
+ *
+ * @example $("#mycarousel").jcarousel();
+ * @before <ul id="mycarousel" class="jcarousel-skin-name"><li>First item</li><li>Second item</li></ul>
+ * @result
+ *
+ * <div class="jcarousel-skin-name">
+ * <div class="jcarousel-container">
+ * <div class="jcarousel-clip">
+ * <ul class="jcarousel-list">
+ * <li class="jcarousel-item-1">First item</li>
+ * <li class="jcarousel-item-2">Second item</li>
+ * </ul>
+ * </div>
+ * <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div>
+ * <div class="jcarousel-next"></div>
+ * </div>
+ * </div>
+ *
+ * @method jcarousel
+ * @return jQuery
+ * @param o {Hash|String} A set of key/value pairs to set as configuration properties or a method name to call on a formerly created instance.
+ */
+ $.fn.jcarousel = function(o) {
+ if (typeof o == 'string') {
+ var instance = $(this).data('jcarousel'), args = Array.prototype.slice.call(arguments, 1);
+ return instance[o].apply(instance, args);
+ } else {
+ return this.each(function() {
+ var instance = $(this).data('jcarousel');
+ if (instance) {
+ if (o) {
+ $.extend(instance.options, o);
+ }
+ instance.reload();
+ } else {
+ $(this).data('jcarousel', new $jc(this, o));
+ }
+ });
+ }
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listmenu.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listmenu.js
new file mode 100644
index 00000000..d9c93ec7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listmenu.js
@@ -0,0 +1,281 @@
+/*
+*
+* jQuery listmenu plugin
+* Copyright (c) 2009 iHwy, Inc.
+* Author: Jack Killpatrick
+*
+* Version 1.1 (08/09/2009)
+* Requires jQuery 1.3.2 or jquery 1.2.6
+*
+* Visit http://www.ihwy.com/labs/jquery-listmenu-plugin.aspx for more information.
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+*/
+
+(function($) {
+ $.fn.listmenu = function(options) {
+ var opts = $.extend({}, $.fn.listmenu.defaults, options);
+ var alph = ['_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-'];
+
+ return this.each(function() {
+ var $wrapper, list, $list, $letters, letters = {}, $letterCount, id, $menu, colOpts = $.extend({}, $.fn.listmenu.defaults.cols, opts.cols), onNav = false, onMenu = false, currentLetter = '';
+ id = this.id;
+ $list = $(this);
+
+ function init() {
+ $list.css('visibility', 'hidden'); // hiding to prevent pre-load flicker. Using visibility:hidden so that list item dimensions remain available
+
+ setTimeout(function() {
+ $list.before(createWrapperHtml());
+
+ $wrapper = $('#' + id + '-menu');
+ $wrapper.append(createLettersHtml());
+
+ $letters = $('.lm-letters', $wrapper).slice(0, 1); // will always be a single item
+ if (opts.showCounts) $letterCount = $('.lm-letter-count', $wrapper).slice(0, 1); // will always be a single item
+
+ $wrapper.append(createMenuHtml());
+ $menu = $('.lm-menu', $wrapper);
+ populateMenu();
+ if (opts.flagDisabled) addDisabledClass(); // run after populateMenu(): needs some data from there
+
+ bindHandlers();
+
+ // decide whether to include num and/or other links
+ //
+ if (!opts.includeNums) $('._', $letters).remove();
+ if (!opts.includeOther) $('.-', $letters).remove();
+ $(':last', $letters).addClass('lm-last');
+
+ $wrapper.show();
+ }, 50);
+ }
+
+ // positions the letter count div above the letter links (so we only have to do it once: after this we just change it's left position via mouseover)
+ //
+ function setLetterCountTop() {
+ $letterCount.css({ top: $('.a', $letters).slice(0, 1).offset({ margin: false, border: true }).top - $letterCount.outerHeight({ margin: true }) });
+ }
+
+ function addDisabledClass() {
+ for (var i = 0; i < alph.length; i++) {
+ if (letters[alph[i]] === undefined) $('.' + alph[i], $letters).addClass('lm-disabled');
+ }
+ }
+
+ function populateMenu() {
+ var gutter = colOpts.gutter,
+ cols = colOpts.count,
+ menuWidth,
+ colWidth;
+
+ if (opts.menuWidth) menuWidth = opts.menuWidth; // use user defined menu width if one provided, else calculate one
+ else menuWidth = $('.lm-letters', $wrapper).width() - ($menu.outerWidth() - $menu.width());
+
+ colWidth = (cols == 1) ? menuWidth : Math.floor((menuWidth - (gutter * (cols - 1))) / cols);
+ $menu.width(menuWidth); // prevents it from resizing based on content
+
+ $list.width(colWidth);
+
+ var letter, outerHeight;
+ $list.children().each(function() {
+ str = $(this).text().replace(/\s+/g, ''); // strip all white space from text (including tabs and linebreaks that might have been in the HTML) // thanks to Liam Byrne, liam@onsight.ie
+ // Deployed with SRF 1.9 to recognize the data-sortkey
+ var sortKey = String( $(this).data( 'sortkey' ) );
+ if ( sortKey !== 'undefined' ){
+ firstChar = sortKey.toLowerCase();
+ } else {
+ if (str !== '') {
+ firstChar = str.slice(0, 1).toLowerCase();
+ if (/\W/.test(firstChar)) firstChar = '-'; // not A-Z, a-z or 0-9, so considered "other"
+ if (!isNaN(firstChar)) firstChar = '_'; // use '_' if the first char is a number
+ }
+ }
+
+ outerHeight = $(this).outerHeight();
+
+ if (letters[firstChar] === undefined) letters[firstChar] = { totHeight: 0, count: 0, colHeight: 0, hasMenu: false };
+ letter = letters[firstChar];
+ letter.totHeight += outerHeight;
+ letter.count++;
+
+ $.data($(this)[0], id, { firstChar: firstChar, height: outerHeight });
+ });
+
+ $.each(letters, function() {
+ this.colHeight = (this.count > 1) ? Math.ceil(this.totHeight / cols) : this.totHeight;
+ });
+
+ var $this, data, iHeight, iLetter, cols = {}, c;
+ var tagName = $list[0].tagName.toLowerCase();
+ $list.children().each(function() {
+ $this = $(this);
+ data = $.data($this.get(0), id); iLetter = data.firstChar; iHeight = data.height;
+ if (!letters[l = iLetter].hasMenu) {
+ $menu.append('<div class="lm-submenu ' + iLetter + '" style="display:none;"></div>');
+ letters[iLetter].hasMenu = true;
+ }
+
+ if (cols[iLetter] === undefined) cols[iLetter] = { height: 0, colNum: 0, itemCount: 0, $colRoot: null };
+ c = cols[iLetter];
+ c.itemCount++;
+ if (c.height === 0) {
+ c.colNum++;
+ $('.lm-submenu.' + iLetter, $menu).append('<div class="lm-col c' + c.colNum + '"><' + tagName + ((tagName == 'ol') ? ' start="' + c.itemCount + '"' : '') + ' id="lm-' + id + '-' + iLetter + '-' + c.colNum + '" class="lm-col-root"></' + tagName + '></div>'); // reset start number for OL lists (deprecacted, but no reliable css solution). Creating an id to make lookups for appending list items faster
+ }
+ $('#lm-' + id + '-' + iLetter + '-' + c.colNum).append($(this));
+
+ c.height += iHeight;
+ if (c.height >= letters[iLetter].colHeight) c.height = 0; // forces another column to get started if this letter comes up again
+ });
+
+ $.each(letters, function(idx) {
+ if (this.hasMenu) {
+ $('.lm-submenu.' + idx + ' .lm-col', $menu).css({ 'width': colWidth, 'float': 'left' });
+ $('.lm-submenu.' + idx + ' .lm-col:not(:last)', $menu).css({ 'marginRight': gutter });
+ }
+ });
+
+ $menu.append('<div class="lm-no-match" style="display:none">' + opts.noMatchText + '</div>');
+ $list.remove();
+ }
+
+ function getLetterCount(el) {
+ var letter = letters[$(el).attr('class').split(' ')[0]];
+ return (letter !== undefined) ? letter.count : 0; // some letters may not be in the hash
+ }
+
+ function hideCurrentSubmenu() {
+ if (currentLetter !== '') $('.lm-submenu.' + currentLetter, $menu).hide();
+ $('.lm-no-match', $menu).hide(); // hiding each time, rather than checking to see if we need to hide it
+ }
+
+ function bindHandlers() {
+
+ // sets the top position of the count div in case something above it on the page has resized
+ //
+ if (opts.showCounts) {
+ $wrapper.mouseover(function() {
+ setLetterCountTop();
+ });
+ }
+
+ // kill letter clicks
+ //
+ $('a', $letters).click(function() {
+ $(this).blur();
+ return false;
+ });
+
+ $letters.hover(
+ function() { onNav = true; },
+ function() {
+ onNav = false;
+
+ setTimeout(function() {
+ if (!onMenu) {
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ $('.lm-menu', $wrapper).hide();
+ hideCurrentSubmenu();
+ currentLetter = '';
+ }
+ }, 10);
+ }
+ );
+
+ $('a', $letters).mouseover(function() {
+ var count = getLetterCount(this);
+ var $this = $(this);
+
+ if (opts.showCounts) {
+ var left = $this.position().left;
+ var width = $this.outerWidth({ margin: true });
+ if (opts.showCounts) $letterCount.css({ left: left, width: width + 'px' }).text(count).show(); // set left position and width of letter count, set count text and show it
+ }
+
+ var newLetter = $this.attr('class').split(' ')[0];
+ if (newLetter != currentLetter) {
+ if (currentLetter !== '') {
+ hideCurrentSubmenu();
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ }
+ $this.addClass('lm-selected');
+
+ if (count > 0) $('.lm-submenu.' + newLetter, $wrapper).show();
+ else $('.lm-no-match', $wrapper).show();
+
+ if (currentLetter === '') $('.lm-menu', $wrapper).show();
+ currentLetter = newLetter;
+ }
+ });
+
+ $('a', $letters).mouseout(function() {
+ if (opts.showCounts) $letterCount.hide();
+ });
+
+ $menu.hover(
+ function() {
+ onMenu = true;
+ },
+ function() {
+ onMenu = false;
+ setTimeout(function() {
+ if (!onNav) {
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ $('.lm-menu', $wrapper).hide();
+ hideCurrentSubmenu();
+ currentLetter = '';
+ }
+ }, 10);
+ }
+ );
+
+ if (opts.onClick !== null) {
+ $menu.click(function(e) {
+ var $target = $(e.target);
+ opts.onClick($target);
+ return false;
+ });
+ }
+ }
+
+ // creates the HTML for the letter links
+ //
+ function createLettersHtml() {
+ var html = [];
+ for (var i = 1; i < alph.length; i++) {
+ if (html.length === 0) html.push('<a class="_" href="#">0-9</a>');
+ html.push('<a class="' + alph[i] + '" href="#">' + ((alph[i] == '-') ? '...' : alph[i].toUpperCase()) + '</a>');
+ }
+ return '<div class="lm-letters">' + html.join('') + '</div>' + ((opts.showCounts) ? '<div class="lm-letter-count" style="display:none; position:absolute; top:0; left:0; width:20px;">0</div>' : ''); // the styling for letterCount is to give us a starting point for the element, which will be repositioned when made visible (ie, should not need to be styled by the user)
+ }
+
+ function createMenuHtml() {
+ return '<div class="lm-menu"></div>';
+ }
+
+ function createWrapperHtml() {
+ return '<div id="' + id + '-menu" class="lm-wrapper"></div>';
+ }
+
+ init();
+ });
+ };
+
+ $.fn.listmenu.defaults = {
+ includeNums: true,
+ includeOther: false,
+ flagDisabled: true,
+ noMatchText: 'No matching entries',
+ showCounts: true,
+ menuWidth: null,
+ cols: {
+ count: 4,
+ gutter: 40
+ },
+ onClick: null
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listnav.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listnav.js
new file mode 100644
index 00000000..2e3f62a4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.listnav.js
@@ -0,0 +1,232 @@
+/*
+*
+* jQuery listnav plugin
+* Copyright (c) 2009 iHwy, Inc.
+* Author: Jack Killpatrick
+*
+* Version 2.1 (08/09/2009)
+* Requires jQuery 1.3.2, jquery 1.2.6 or jquery 1.2.x plus the jquery dimensions plugin
+*
+* Visit http://www.ihwy.com/labs/jquery-listnav-plugin.aspx for more information.
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+*/
+
+(function($) {
+ $.fn.listnav = function(options) {
+ var opts = $.extend({}, $.fn.listnav.defaults, options);
+ var letters = ['_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-'];
+ var firstClick = false;
+ opts.prefixes = $.map(opts.prefixes, function(n) { return n.toLowerCase(); });
+
+ return this.each(function() {
+ var $wrapper, list, $list, $letters, $letterCount, id;
+ id = this.id;
+ $wrapper = $('#' + id + '-nav'); // user must abide by the convention: <ul id="myList"> for list and <div id="myList-nav"> for nav wrapper
+ $list = $(this);
+
+ var counts = {}, allCount = 0, isAll = true, numCount = 0, prevLetter = '';
+
+ function init() {
+ $wrapper.append(createLettersHtml());
+
+ $letters = $('.ln-letters', $wrapper).slice(0, 1); // will always be a single item
+ if (opts.showCounts) $letterCount = $('.ln-letter-count', $wrapper).slice(0, 1); // will always be a single item
+
+ addClasses();
+ addNoMatchLI();
+ if (opts.flagDisabled) addDisabledClass();
+ bindHandlers();
+
+ if (!opts.includeAll) $list.show(); // show the list in case the recommendation for includeAll=false was taken
+
+ // remove nav items we don't need
+ //
+ if (!opts.includeAll) $('.all', $letters).remove();
+ if (!opts.includeNums) $('._', $letters).remove();
+ if (!opts.includeOther) $('.-', $letters).remove();
+
+ $(':last', $letters).addClass('ln-last'); // allows for styling a case where last item needs right border set (because items before that only have top, left and bottom so that border between items isn't doubled)
+
+ if ($.cookie && (opts.cookieName !== null)) {
+ var cookieLetter = $.cookie(opts.cookieName);
+ if (cookieLetter !== null) opts.initLetter = cookieLetter;
+ }
+
+ // decide what to show first
+ //
+ if (opts.initLetter !== '') {
+ firstClick = true;
+ $('.' + opts.initLetter.toLowerCase(), $letters).slice(0, 1).click(); // click the initLetter if there was one
+ }
+ else {
+ if (opts.includeAll) $('.all', $letters).addClass('ln-selected'); // showing all: we don't need to click this: the whole list is already loaded
+ else { // ALL link is hidden, click the first letter that will display LI's
+ for (var i = ((opts.includeNums) ? 0 : 1); i < letters.length; i++) {
+ if (counts[letters[i]] > 0) {
+ firstClick = true;
+ $('.' + letters[i], $letters).slice(0, 1).click();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // positions the letter count div above the letter links (so we only have to do it once: after this we just change it's left position via mouseover)
+ //
+ function setLetterCountTop() {
+ $letterCount.css({ top: $('.a', $letters).slice(0, 1).offset({ margin: false, border: true }).top - $letterCount.outerHeight({ margin: true }) }); // note: don't set top based on '.all': it might not be visible
+ }
+
+ // adds a class to each LI that has text content inside of it (ie, inside an <a>, a <div>, nested DOM nodes, etc)
+ //
+ function addClasses() {
+ var str, firstChar, firstWord, spl, $this, hasPrefixes = (opts.prefixes.length > 0);
+ $($list).children().each(function() {
+ $this = $(this), firstChar = '', str = $.trim($this.text()).toLowerCase();
+ if (str !== '') {
+ if (hasPrefixes) {
+ spl = str.split(' ');
+ if ((spl.length > 1) && ($.inArray(spl[0], opts.prefixes) > -1)) {
+ firstChar = spl[1].charAt(0);
+ addLetterClass(firstChar, $this, true);
+ }
+ }
+ firstChar = str.charAt(0);
+ addLetterClass(firstChar, $this);
+ }
+ });
+ }
+
+ function addLetterClass(firstChar, $el, isPrefix) {
+ // Deployed with SRF 1.9 to recognize the data-sortkey
+ var sortKey = String( $el.data( 'sortkey' ) );
+ if ( sortKey !== 'undefined' ){
+ firstChar = sortKey.toLowerCase();
+ } else {
+ if (/\W/.test(firstChar)) firstChar = '-'; // not A-Z, a-z or 0-9, so considered "other"
+ if (!isNaN(firstChar)) firstChar = '_'; // use '_' if the first char is a number
+ }
+
+ $el.addClass('ln-' + firstChar);
+
+ if (counts[firstChar] === undefined) counts[firstChar] = 0;
+ counts[firstChar]++;
+ if (!isPrefix) allCount++;
+ }
+
+ function addDisabledClass() {
+ for (var i = 0; i < letters.length; i++) {
+ if (counts[letters[i]] === undefined) $('.' + letters[i], $letters).addClass('ln-disabled');
+ }
+ }
+
+ function addNoMatchLI() {
+ $list.append('<li class="ln-no-match" style="display:none">' + opts.noMatchText + '</li>');
+ }
+
+ function getLetterCount(el) {
+ if ($(el).hasClass('all')) return allCount;
+ else {
+ var count = counts[$(el).attr('class').split(' ')[0]];
+ return (count !== undefined) ? count : 0; // some letters may not have a count in the hash
+ }
+ }
+
+ function bindHandlers() {
+
+ // sets the top position of the count div in case something above it on the page has resized
+ //
+ if (opts.showCounts) {
+ $wrapper.mouseover(function() {
+ setLetterCountTop();
+ });
+ }
+
+ // mouseover for each letter: shows the count above the letter
+ //
+ if (opts.showCounts) {
+ $('a', $letters).mouseover(function() {
+ var left = $(this).position().left;
+ var width = ($(this).outerWidth({ margin: true }) - 1) + 'px'; // the -1 is to tweak the width a bit due to a seeming inaccuracy in jquery ui/dimensions outerWidth (same result in FF2 and IE6/7)
+ var count = getLetterCount(this);
+ $letterCount.css({ left: left, width: width }).text(count).show(); // set left position and width of letter count, set count text and show it
+ });
+
+ // mouseout for each letter: hide the count
+ //
+ $('a', $letters).mouseout(function() {
+ $letterCount.hide();
+ });
+ }
+
+ // click handler for letters: shows/hides relevant LI's
+ //
+ $('a', $letters).click(function() {
+ $('a.ln-selected', $letters).removeClass('ln-selected');
+
+ var letter = $(this).attr('class').split(' ')[0];
+
+ if (letter == 'all') {
+ $list.children().show();
+ $list.children('.ln-no-match').hide();
+ isAll = true;
+ } else {
+ if (isAll) {
+ $list.children().hide();
+ isAll = false;
+ } else if (prevLetter !== '') $list.children('.ln-' + prevLetter).hide();
+
+ var count = getLetterCount(this);
+ if (count > 0) {
+ $list.children('.ln-no-match').hide(); // in case it's showing
+ $list.children('.ln-' + letter).show();
+ }
+ else $list.children('.ln-no-match').show();
+
+ prevLetter = letter;
+ }
+
+ if ($.cookie && (opts.cookieName !== null)) $.cookie(opts.cookieName, letter);
+
+
+ $(this).addClass('ln-selected');
+ $(this).blur();
+ if (!firstClick && (opts.onClick !== null)) opts.onClick(letter);
+ else firstClick = false;
+ return false;
+ });
+ }
+
+ // creates the HTML for the letter links
+ //
+ function createLettersHtml() {
+ var html = [];
+ for (var i = 1; i < letters.length; i++) {
+ if (html.length === 0) html.push('<a class="all" href="#">ALL</a><a class="_" href="#">0-9</a>');
+ html.push('<a class="' + letters[i] + '" href="#">' + ((letters[i] == '-') ? '...' : letters[i].toUpperCase()) + '</a>');
+ }
+ return '<div class="ln-letters">' + html.join('') + '</div>' + ((opts.showCounts) ? '<div class="ln-letter-count" style="display:none; position:absolute; top:0; left:0; width:20px;">0</div>' : ''); // the styling for ln-letter-count is to give us a starting point for the element, which will be repositioned when made visible (ie, should not need to be styled by the user)
+ }
+
+ init();
+ });
+ };
+
+ $.fn.listnav.defaults = {
+ initLetter: '',
+ includeAll: true,
+ incudeOther: false,
+ includeNums: true,
+ flagDisabled: true,
+ noMatchText: 'No matching entries',
+ showCounts: true,
+ cookieName: null,
+ onClick: null,
+ prefixes: []
+ };
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.pajinate.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.pajinate.js
new file mode 100644
index 00000000..a6fa442b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.pajinate.js
@@ -0,0 +1,313 @@
+;(function($){
+/*******************************************************************************************/
+// jquery.pajinate.js - version 0.4
+// A jQuery plugin for paginating through any number of DOM elements
+//
+// Copyright (c) 2010, Wes Nolte (http://wesnolte.com)
+// Licensed under the MIT License (MIT-LICENSE.txt)
+// http://www.opensource.org/licenses/mit-license.php
+// Created: 2010-04-16 | Updated: 2010-04-26
+//
+/*******************************************************************************************/
+
+ $.fn.pajinate = function(options){
+ // Set some state information
+ var current_page = 'current_page';
+ var items_per_page = 'items_per_page';
+
+ var meta;
+
+ // Setup default option values
+ var defaults = {
+ item_container_id : '.content',
+ items_per_page : 10,
+ nav_panel_id : '.page_navigation',
+ nav_info_id : '.info_text',
+ num_page_links_to_display : 20,
+ start_page : 0,
+ wrap_around : false,
+ nav_label_first : 'First',
+ nav_label_prev : 'Prev',
+ nav_label_next : 'Next',
+ nav_label_last : 'Last',
+ nav_order : ["first", "prev", "num", "next", "last"],
+ nav_label_info : 'Showing {0}-{1} of {2} results',
+ show_first_last: true,
+ abort_on_small_lists: false,
+ jquery_ui: false,
+ jquery_ui_active: "ui-state-highlight",
+ jquery_ui_default: "ui-state-default",
+ jquery_ui_disabled: "ui-state-disabled"
+ };
+ var options = $.extend(defaults,options);
+ var $item_container;
+ var $page_container;
+ var $items;
+ var $nav_panels;
+ var total_page_no_links;
+ var jquery_ui_default_class = options.jquery_ui ? options.jquery_ui_default : '';
+ var jquery_ui_active_class = options.jquery_ui ? options.jquery_ui_active : '';
+ var jquery_ui_disabled_class = options.jquery_ui ? options.jquery_ui_disabled : '';
+
+ return this.each(function(){
+ $page_container = $(this);
+ $item_container = $(this).find(options.item_container_id);
+ $items = $page_container.find(options.item_container_id).children();
+
+ if (options.abort_on_small_lists && options.items_per_page >= $items.size())
+ return $page_container;
+
+ meta = $page_container;
+
+ // Initialize meta data
+ meta.data(current_page,0);
+ meta.data(items_per_page, options.items_per_page);
+
+ // Get the total number of items
+ var total_items = $item_container.children().size();
+
+ // Calculate the number of pages needed
+ var number_of_pages = Math.ceil(total_items/options.items_per_page);
+
+ // Construct the nav bar
+ var more = '<span class="ellipse more">...</span>';
+ var less = '<span class="ellipse less">...</span>';
+ var first = !options.show_first_last ? '' : '<a class="first_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_first +'</a>';
+ var last = !options.show_first_last ? '' : '<a class="last_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_last +'</a>';
+
+ var navigation_html = "";
+
+ for(var i = 0; i < options.nav_order.length; i++) {
+ switch (options.nav_order[i]) {
+ case "first":
+ navigation_html += first;
+ break;
+ case "last":
+ navigation_html += last;
+ break;
+ case "next":
+ navigation_html += '<a class="next_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_next +'</a>';
+ break;
+ case "prev":
+ navigation_html += '<a class="previous_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_prev +'</a>';
+ break;
+ case "num":
+ navigation_html += less;
+ var current_link = 0;
+ while(number_of_pages > current_link){
+ navigation_html += '<a class="page_link '+ jquery_ui_default_class +'" href="" longdesc="' + current_link +'">'+ (current_link + 1) +'</a>';
+ current_link++;
+ }
+ navigation_html += more;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ // And add it to the appropriate area of the DOM
+ $nav_panels = $page_container.find(options.nav_panel_id);
+ $nav_panels.html(navigation_html).each(function(){
+
+ $(this).find('.page_link:first').addClass('first');
+ $(this).find('.page_link:last').addClass('last');
+
+ });
+
+ // Hide the more/less indicators
+ $nav_panels.children('.ellipse').hide();
+
+ // Set the active page link styling
+ $nav_panels.find('.previous_link').next().next().addClass('active_page '+ jquery_ui_active_class);
+
+ /* Setup Page Display */
+ // And hide all pages
+ $items.hide();
+ // Show the first page
+ $items.slice(0, meta.data(items_per_page)).show();
+
+ /* Setup Nav Menu Display */
+ // Page number slices
+
+ total_page_no_links = $page_container.children(options.nav_panel_id+':first').children('.page_link').size();
+ options.num_page_links_to_display = Math.min(options.num_page_links_to_display,total_page_no_links);
+
+ $nav_panels.children('.page_link').hide(); // Hide all the page links
+
+ // And only show the number we should be seeing
+ $nav_panels.each(function(){
+ $(this).children('.page_link').slice(0, options.num_page_links_to_display).show();
+ });
+
+ /* Bind the actions to their respective links */
+
+ // Event handler for 'First' link
+ $page_container.find('.first_link').click(function(e){
+ e.preventDefault();
+
+ movePageNumbersRight($(this),0);
+ gotopage(0);
+ });
+
+ // Event handler for 'Last' link
+ $page_container.find('.last_link').click(function(e){
+ e.preventDefault();
+ var lastPage = total_page_no_links - 1;
+ movePageNumbersLeft($(this),lastPage);
+ gotopage(lastPage);
+ });
+
+ // Event handler for 'Prev' link
+ $page_container.find('.previous_link').click(function(e){
+ e.preventDefault();
+ showPrevPage($(this));
+ });
+
+
+ // Event handler for 'Next' link
+ $page_container.find('.next_link').click(function(e){
+ e.preventDefault();
+ showNextPage($(this));
+ });
+
+ // Event handler for each 'Page' link
+ $page_container.find('.page_link').click(function(e){
+ e.preventDefault();
+ gotopage($(this).attr('longdesc'));
+ });
+
+ // Goto the required page
+ gotopage(parseInt(options.start_page));
+ toggleMoreLess();
+ if(!options.wrap_around)
+ tagNextPrev();
+ });
+
+ function showPrevPage(e){
+ new_page = parseInt(meta.data(current_page)) - 1;
+
+ // Check that we aren't on a boundary link
+ if($(e).siblings('.active_page').prev('.page_link').length==true){
+ movePageNumbersRight(e,new_page);
+ gotopage(new_page);
+ }else if(options.wrap_around){
+ gotopage(total_page_no_links-1);
+ }
+
+ }
+
+ function showNextPage(e){
+ new_page = parseInt(meta.data(current_page)) + 1;
+
+ // Check that we aren't on a boundary link
+ if($(e).siblings('.active_page').next('.page_link').length==true){
+ movePageNumbersLeft(e,new_page);
+ gotopage(new_page);
+ } else if (options.wrap_around) {
+ gotopage(0);
+ }
+
+ }
+
+ function gotopage(page_num){
+
+ var ipp = parseInt(meta.data(items_per_page));
+
+ var isLastPage = false;
+
+ // Find the start of the next slice
+ start_from = page_num * ipp;
+
+ // Find the end of the next slice
+ end_on = start_from + ipp;
+ // Hide the current page
+ var items = $items.hide().slice(start_from, end_on);
+
+ items.show();
+
+ // Reassign the active class
+ $page_container.find(options.nav_panel_id).children('.page_link[longdesc=' + page_num +']').addClass('active_page '+ jquery_ui_active_class)
+ .siblings('.active_page')
+ .removeClass('active_page ' + jquery_ui_active_class);
+
+ // Set the current page meta data
+ meta.data(current_page,page_num);
+
+ $page_container.find(options.nav_info_id).html(options.nav_label_info.replace("{0}",start_from+1).
+ replace("{1}",start_from + items.length).replace("{2}",$items.length));
+
+ // Hide the more and/or less indicators
+ toggleMoreLess();
+
+ // Add a class to the next or prev links if there are no more pages next or previous to the active page
+ tagNextPrev();
+ }
+ // Methods to shift the diplayed index of page numbers to the left or right
+ function movePageNumbersLeft(e, new_p){
+ var new_page = new_p;
+
+ var $current_active_link = $(e).siblings('.active_page');
+
+ if($current_active_link.siblings('.page_link[longdesc=' + new_page +']').css('display') == 'none'){
+
+ $nav_panels.each(function(){
+ $(this).children('.page_link')
+ .hide() // Hide all the page links
+ .slice(parseInt(new_page - options.num_page_links_to_display + 1) , new_page + 1)
+ .show();
+ });
+ }
+
+ }
+
+ function movePageNumbersRight(e, new_p){
+ var new_page = new_p;
+
+ var $current_active_link = $(e).siblings('.active_page');
+
+ if($current_active_link.siblings('.page_link[longdesc=' + new_page +']').css('display') == 'none'){
+
+ $nav_panels.each(function(){
+ $(this).children('.page_link')
+ .hide() // Hide all the page links
+ .slice( new_page , new_page + parseInt(options.num_page_links_to_display))
+ .show();
+ });
+ }
+ }
+
+ // Show or remove the ellipses that indicate that more page numbers exist in the page index than are currently shown
+ function toggleMoreLess(){
+
+ if(!$nav_panels.children('.page_link:visible').hasClass('last')){
+ $nav_panels.children('.more').show();
+ }else {
+ $nav_panels.children('.more').hide();
+ }
+
+ if(!$nav_panels.children('.page_link:visible').hasClass('first')){
+ $nav_panels.children('.less').show();
+ }else {
+ $nav_panels.children('.less').hide();
+ }
+ }
+
+ /* Add the style class ".no_more" to the first/prev and last/next links to allow custom styling */
+ function tagNextPrev() {
+ if($nav_panels.children('.last').hasClass('active_page')){
+ $nav_panels.children('.next_link').add('.last_link').addClass('no_more ' + jquery_ui_disabled_class);
+ } else {
+ $nav_panels.children('.next_link').add('.last_link').removeClass('no_more ' + jquery_ui_disabled_class);
+ }
+
+ if($nav_panels.children('.first').hasClass('active_page')){
+ $nav_panels.children('.previous_link').add('.first_link').addClass('no_more ' + jquery_ui_disabled_class);
+ } else {
+ $nav_panels.children('.previous_link').add('.first_link').removeClass('no_more ' + jquery_ui_disabled_class);
+ }
+ }
+
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js
new file mode 100644
index 00000000..2924396d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js
@@ -0,0 +1,391 @@
+/*! ResponsiveSlides.js v1.53
+ * http://responsiveslides.com
+ * http://viljamis.com
+ *
+ * Copyright (c) 2011-2012 @viljamis
+ * Available under the MIT license
+ */
+
+/*jslint browser: true, sloppy: true, vars: true, plusplus: true, indent: 2 */
+
+(function ($, window, i) {
+ $.fn.responsiveSlides = function (options) {
+
+ // Default settings
+ var settings = $.extend({
+ "auto": true, // Boolean: Animate automatically, true or false
+ "speed": 500, // Integer: Speed of the transition, in milliseconds
+ "timeout": 4000, // Integer: Time between slide transitions, in milliseconds
+ "pager": false, // Boolean: Show pager, true or false
+ "nav": false, // Boolean: Show navigation, true or false
+ "random": false, // Boolean: Randomize the order of the slides, true or false
+ "pause": false, // Boolean: Pause on hover, true or false
+ "pauseControls": true, // Boolean: Pause when hovering controls, true or false
+ "prevText": "Previous", // String: Text for the "previous" button
+ "nextText": "Next", // String: Text for the "next" button
+ "maxwidth": "", // Integer: Max-width of the slideshow, in pixels
+ "navContainer": "", // Selector: Where auto generated controls should be appended to, default is after the <ul>
+ "manualControls": "", // Selector: Declare custom pager navigation
+ "namespace": "rslides", // String: change the default namespace used
+ before: function () {}, // Function: Before callback
+ after: function () {} // Function: After callback
+ }, options);
+
+ return this.each(function () {
+
+ // Index for namespacing
+ i++;
+
+ var $this = $(this),
+
+ // Local variables
+ vendor,
+ selectTab,
+ startCycle,
+ restartCycle,
+ rotate,
+ $tabs,
+
+ // Helpers
+ index = 0,
+ $slide = $this.children(),
+ length = $slide.size(),
+ fadeTime = parseFloat(settings.speed),
+ waitTime = parseFloat(settings.timeout),
+ maxw = parseFloat(settings.maxwidth),
+
+ // Namespacing
+ namespace = settings.namespace,
+ namespaceIdx = namespace + i,
+
+ // Classes
+ navClass = namespace + "_nav " + namespaceIdx + "_nav",
+ activeClass = namespace + "_here",
+ visibleClass = namespaceIdx + "_on",
+ slideClassPrefix = namespaceIdx + "_s",
+
+ // Pager
+ $pager = $("<ul class='" + namespace + "_tabs " + namespaceIdx + "_tabs' />"),
+
+ // Styles for visible and hidden slides
+ visible = {"float": "left", "position": "relative", "opacity": 1, "zIndex": 2},
+ hidden = {"float": "none", "position": "absolute", "opacity": 0, "zIndex": 1},
+
+ // Detect transition support
+ supportsTransitions = (function () {
+ var docBody = document.body || document.documentElement;
+ var styles = docBody.style;
+ var prop = "transition";
+ if (typeof styles[prop] === "string") {
+ return true;
+ }
+ // Tests for vendor specific prop
+ vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
+ prop = prop.charAt(0).toUpperCase() + prop.substr(1);
+ var i;
+ for (i = 0; i < vendor.length; i++) {
+ if (typeof styles[vendor[i] + prop] === "string") {
+ return true;
+ }
+ }
+ return false;
+ })(),
+
+ // Fading animation
+ slideTo = function (idx) {
+ settings.before();
+ // If CSS3 transitions are supported
+ if (supportsTransitions) {
+ $slide
+ .removeClass(visibleClass)
+ .css(hidden)
+ .eq(idx)
+ .addClass(visibleClass)
+ .css(visible);
+ index = idx;
+ setTimeout(function () {
+ settings.after();
+ }, fadeTime);
+ // If not, use jQuery fallback
+ } else {
+ $slide
+ .stop()
+ .fadeOut(fadeTime, function () {
+ $(this)
+ .removeClass(visibleClass)
+ .css(hidden)
+ .css("opacity", 1);
+ })
+ .eq(idx)
+ .fadeIn(fadeTime, function () {
+ $(this)
+ .addClass(visibleClass)
+ .css(visible);
+ settings.after();
+ index = idx;
+ });
+ }
+ };
+
+ // Random order
+ if (settings.random) {
+ $slide.sort(function () {
+ return (Math.round(Math.random()) - 0.5);
+ });
+ $this
+ .empty()
+ .append($slide);
+ }
+
+ // Add ID's to each slide
+ $slide.each(function (i) {
+ this.id = slideClassPrefix + i;
+ });
+
+ // Add max-width and classes
+ $this.addClass(namespace + " " + namespaceIdx);
+ if (options && options.maxwidth) {
+ $this.css("max-width", maxw);
+ }
+
+ // Hide all slides, then show first one
+ $slide
+ .hide()
+ .css(hidden)
+ .eq(0)
+ .addClass(visibleClass)
+ .css(visible)
+ .show();
+
+ // CSS transitions
+ if (supportsTransitions) {
+ $slide
+ .show()
+ .css({
+ // -ms prefix isn't needed as IE10 uses prefix free version
+ "-webkit-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "-moz-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "-o-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "transition": "opacity " + fadeTime + "ms ease-in-out"
+ });
+ }
+
+ // Only run if there's more than one slide
+ if ($slide.size() > 1) {
+
+ // Make sure the timeout is at least 100ms longer than the fade
+ if (waitTime < fadeTime + 100) {
+ return;
+ }
+
+ // Pager
+ if (settings.pager && !settings.manualControls) {
+ var tabMarkup = [];
+ $slide.each(function (i) {
+ var n = i + 1;
+ tabMarkup +=
+ "<li>" +
+ "<a href='#' class='" + slideClassPrefix + n + "'>" + n + "</a>" +
+ "</li>";
+ });
+ $pager.append(tabMarkup);
+
+ // Inject pager
+ if (options.navContainer) {
+ $(settings.navContainer).append($pager);
+ } else {
+ $this.after($pager);
+ }
+ }
+
+ // Manual pager controls
+ if (settings.manualControls) {
+ $pager = $(settings.manualControls);
+ $pager.addClass(namespace + "_tabs " + namespaceIdx + "_tabs");
+ }
+
+ // Add pager slide class prefixes
+ if (settings.pager || settings.manualControls) {
+ $pager.find('li').each(function (i) {
+ $(this).addClass(slideClassPrefix + (i + 1));
+ });
+ }
+
+ // If we have a pager, we need to set up the selectTab function
+ if (settings.pager || settings.manualControls) {
+ $tabs = $pager.find('a');
+
+ // Select pager item
+ selectTab = function (idx) {
+ $tabs
+ .closest("li")
+ .removeClass(activeClass)
+ .eq(idx)
+ .addClass(activeClass);
+ };
+ }
+
+ // Auto cycle
+ if (settings.auto) {
+
+ startCycle = function () {
+ rotate = setInterval(function () {
+
+ // Clear the event queue
+ $slide.stop(true, true);
+
+ var idx = index + 1 < length ? index + 1 : 0;
+
+ // Remove active state and set new if pager is set
+ if (settings.pager || settings.manualControls) {
+ selectTab(idx);
+ }
+
+ slideTo(idx);
+ }, waitTime);
+ };
+
+ // Init cycle
+ startCycle();
+ }
+
+ // Restarting cycle
+ restartCycle = function () {
+ if (settings.auto) {
+ // Stop
+ clearInterval(rotate);
+ // Restart
+ startCycle();
+ }
+ };
+
+ // Pause on hover
+ if (settings.pause) {
+ $this.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+
+ // Pager click event handler
+ if (settings.pager || settings.manualControls) {
+ $tabs.bind("click", function (e) {
+ e.preventDefault();
+
+ if (!settings.pauseControls) {
+ restartCycle();
+ }
+
+ // Get index of clicked tab
+ var idx = $tabs.index(this);
+
+ // Break if element is already active or currently animated
+ if (index === idx || $("." + visibleClass).queue('fx').length) {
+ return;
+ }
+
+ // Remove active state from old tab and set new one
+ selectTab(idx);
+
+ // Do the animation
+ slideTo(idx);
+ })
+ .eq(0)
+ .closest("li")
+ .addClass(activeClass);
+
+ // Pause when hovering pager
+ if (settings.pauseControls) {
+ $tabs.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+ }
+
+ // Navigation
+ if (settings.nav) {
+ var navMarkup =
+ "<a href='#' class='" + navClass + " prev'>" + settings.prevText + "</a>" +
+ "<a href='#' class='" + navClass + " next'>" + settings.nextText + "</a>";
+
+ // Inject navigation
+ if (options.navContainer) {
+ $(settings.navContainer).append(navMarkup);
+ } else {
+ $this.after(navMarkup);
+ }
+
+ var $trigger = $("." + namespaceIdx + "_nav"),
+ $prev = $trigger.filter(".prev");
+
+ // Click event handler
+ $trigger.bind("click", function (e) {
+ e.preventDefault();
+
+ var $visibleClass = $("." + visibleClass);
+
+ // Prevent clicking if currently animated
+ if ($visibleClass.queue('fx').length) {
+ return;
+ }
+
+ // Adds active class during slide animation
+ // $(this)
+ // .addClass(namespace + "_active")
+ // .delay(fadeTime)
+ // .queue(function (next) {
+ // $(this).removeClass(namespace + "_active");
+ // next();
+ // });
+
+ // Determine where to slide
+ var idx = $slide.index($visibleClass),
+ prevIdx = idx - 1,
+ nextIdx = idx + 1 < length ? index + 1 : 0;
+
+ // Go to slide
+ slideTo($(this)[0] === $prev[0] ? prevIdx : nextIdx);
+ if (settings.pager || settings.manualControls) {
+ selectTab($(this)[0] === $prev[0] ? prevIdx : nextIdx);
+ }
+
+ if (!settings.pauseControls) {
+ restartCycle();
+ }
+ });
+
+ // Pause when hovering navigation
+ if (settings.pauseControls) {
+ $trigger.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+ }
+
+ }
+
+ // Max-width fallback
+ if (typeof document.body.style.maxWidth === "undefined" && options.maxwidth) {
+ var widthSupport = function () {
+ $this.css("width", "100%");
+ if ($this.width() > maxw) {
+ $this.css("width", maxw);
+ }
+ };
+
+ // Init fallback
+ widthSupport();
+ $(window).bind("resize", function () {
+ widthSupport();
+ });
+ }
+
+ });
+
+ };
+})(jQuery, this, 0); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.sparkline.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.sparkline.js
new file mode 100644
index 00000000..43b24c08
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.sparkline.js
@@ -0,0 +1,3054 @@
+/**
+*
+* jquery.sparkline.js
+*
+* v2.1.2
+* (c) Splunk, Inc
+* Contact: Gareth Watts (gareth@splunk.com)
+* http://omnipotent.net/jquery.sparkline/
+*
+* Generates inline sparkline charts from data supplied either to the method
+* or inline in HTML
+*
+* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag
+* (Firefox 2.0+, Safari, Opera, etc)
+*
+* License: New BSD License
+*
+* Copyright (c) 2012, Splunk Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+* * Neither the name of Splunk Inc nor the names of its contributors may
+* be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*
+* Usage:
+* $(selector).sparkline(values, options)
+*
+* If values is undefined or set to 'html' then the data values are read from the specified tag:
+* <p>Sparkline: <span class="sparkline">1,4,6,6,8,5,3,5</span></p>
+* $('.sparkline').sparkline();
+* There must be no spaces in the enclosed data set
+*
+* Otherwise values must be an array of numbers or null values
+* <p>Sparkline: <span id="sparkline1">This text replaced if the browser is compatible</span></p>
+* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])
+* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])
+*
+* Values can also be specified in an HTML comment, or as a values attribute:
+* <p>Sparkline: <span class="sparkline"><!--1,4,6,6,8,5,3,5 --></span></p>
+* <p>Sparkline: <span class="sparkline" values="1,4,6,6,8,5,3,5"></span></p>
+* $('.sparkline').sparkline();
+*
+* For line charts, x values can also be specified:
+* <p>Sparkline: <span class="sparkline">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>
+* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
+*
+* By default, options should be passed in as teh second argument to the sparkline function:
+* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
+*
+* Options can also be set by passing them on the tag itself. This feature is disabled by default though
+* as there's a slight performance overhead:
+* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})
+* <p>Sparkline: <span class="sparkline" sparkType="bar" sparkBarColor="red">loading</span></p>
+* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionPrefix)
+*
+* Supported options:
+* lineColor - Color of the line used for the chart
+* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart
+* width - Width of the chart - Defaults to 3 times the number of values in pixels
+* height - Height of the chart - Defaults to the height of the containing element
+* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied
+* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied
+* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax
+* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied
+* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied
+* composite - If true then don't erase any existing chart attached to the tag, but draw
+* another chart over the top - Note that width and height are ignored if an
+* existing chart is detected.
+* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'
+* enableTagOptions - Whether to check tags for sparkline options
+* tagOptionPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'
+* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a
+* hidden dom element, avoding a browser reflow
+* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,
+* making the plugin perform much like it did in 1.x
+* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)
+* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled
+* defaults to false (highlights enabled)
+* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase
+* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body
+* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied
+* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis
+* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis
+* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip
+* callback is given arguments of (sparkline, options, fields)
+* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title
+* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)
+* to control the format of the tooltip
+* tooltipPrefix - A string to prepend to each field displayed in a tooltip
+* tooltipSuffix - A string to append to each field displayed in a tooltip
+* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)
+* tooltipValueLookups - An object or range map to map field values to tooltip strings
+* (eg. to map -1 to "Lost", 0 to "Draw", and 1 to "Win")
+* numberFormatter - Optional callback for formatting numbers in tooltips
+* numberDigitGroupSep - Character to use for group separator in numbers "1,234" - Defaults to ","
+* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
+* numberDigitGroupCount - Number of digits between group separator - Defaults to 3
+*
+* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
+* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
+* line - Line chart. Options:
+* spotColor - Set to '' to not end each line in a circular spot
+* minSpotColor - If set, color of spot at minimum value
+* maxSpotColor - If set, color of spot at maximum value
+* spotRadius - Radius in pixels
+* lineWidth - Width of line in pixels
+* normalRangeMin
+* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
+* or expected range of values
+* normalRangeColor - Color to use for the above bar
+* drawNormalOnTop - Draw the normal range above the chart fill color if true
+* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
+* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
+* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
+* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map
+*
+* bar - Bar chart. Options:
+* barColor - Color of bars for postive values
+* negBarColor - Color of bars for negative values
+* zeroColor - Color of bars with zero values
+* nullColor - Color of bars with null values - Defaults to omitting the bar entirely
+* barWidth - Width of bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+* barSpacing - Gap between bars in pixels
+* zeroAxis - Centers the y-axis around zero if true
+*
+* tristate - Charts values of win (>0), lose (<0) or draw (=0)
+* posBarColor - Color of win values
+* negBarColor - Color of lose values
+* zeroBarColor - Color of draw values
+* barWidth - Width of bars in pixels
+* barSpacing - Gap between bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+*
+* discrete - Options:
+* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
+* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
+* thresholdColor
+*
+* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
+* options:
+* targetColor - The color of the vertical target marker
+* targetWidth - The width of the target marker in pixels
+* performanceColor - The color of the performance measure horizontal bar
+* rangeColors - Colors to use for each qualitative range background color
+*
+* pie - Pie chart. Options:
+* sliceColors - An array of colors to use for pie slices
+* offset - Angle in degrees to offset the first slice - Try -90 or +90
+* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
+* borderColor - Color to use for the pie chart border - Defaults to #000
+*
+* box - Box plot. Options:
+* raw - Set to true to supply pre-computed plot points as values
+* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
+* When set to false you can supply any number of values and the box plot will
+* be computed for you. Default is false.
+* showOutliers - Set to true (default) to display outliers as circles
+* outlierIQR - Interquartile range used to determine outliers. Default 1.5
+* boxLineColor - Outline color of the box
+* boxFillColor - Fill color for the box
+* whiskerColor - Line color used for whiskers
+* outlierLineColor - Outline color of outlier circles
+* outlierFillColor - Fill color of the outlier circles
+* spotRadius - Radius of outlier circles
+* medianColor - Line color of the median line
+* target - Draw a target cross hair at the supplied value (default undefined)
+*
+*
+*
+* Examples:
+* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
+* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
+* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
+* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
+* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
+* $('#pie').sparkline([1,1,2], { type:'pie' });
+*/
+
+/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
+
+(function(document, Math, undefined) { // performance/minified-size optimization
+(function(factory) {
+ if(typeof define === 'function' && define.amd) {
+ define(['jquery'], factory);
+ } else if (jQuery && !jQuery.fn.sparkline) {
+ factory(jQuery);
+ }
+}
+(function($) {
+ 'use strict';
+
+ var UNSET_OPTION = {},
+ getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
+ remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
+ MouseHandler, Tooltip, barHighlightMixin,
+ line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
+ VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
+
+ /**
+ * Default configuration settings
+ */
+ getDefaults = function () {
+ return {
+ // Settings common to most/all chart types
+ common: {
+ type: 'line',
+ lineColor: '#00f',
+ fillColor: '#cdf',
+ defaultPixelsPerValue: 3,
+ width: 'auto',
+ height: 'auto',
+ composite: false,
+ tagValuesAttribute: 'values',
+ tagOptionsPrefix: 'spark',
+ enableTagOptions: false,
+ enableHighlight: true,
+ highlightLighten: 1.4,
+ tooltipSkipNull: true,
+ tooltipPrefix: '',
+ tooltipSuffix: '',
+ disableHiddenCheck: false,
+ numberFormatter: false,
+ numberDigitGroupCount: 3,
+ numberDigitGroupSep: ',',
+ numberDecimalMark: '.',
+ disableTooltips: false,
+ disableInteraction: false
+ },
+ // Defaults for line charts
+ line: {
+ spotColor: '#f80',
+ highlightSpotColor: '#5f5',
+ highlightLineColor: '#f22',
+ spotRadius: 1.5,
+ minSpotColor: '#f80',
+ maxSpotColor: '#f80',
+ lineWidth: 1,
+ normalRangeMin: undefined,
+ normalRangeMax: undefined,
+ normalRangeColor: '#ccc',
+ drawNormalOnTop: false,
+ chartRangeMin: undefined,
+ chartRangeMax: undefined,
+ chartRangeMinX: undefined,
+ chartRangeMaxX: undefined,
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{y}}{{suffix}}')
+ },
+ // Defaults for bar charts
+ bar: {
+ barColor: '#3366cc',
+ negBarColor: '#f44',
+ stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ zeroColor: undefined,
+ nullColor: undefined,
+ zeroAxis: true,
+ barWidth: 4,
+ barSpacing: 1,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ colorMap: undefined,
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for tristate charts
+ tristate: {
+ barWidth: 4,
+ barSpacing: 1,
+ posBarColor: '#6f6',
+ negBarColor: '#f44',
+ zeroBarColor: '#999',
+ colorMap: {},
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value:map}}'),
+ tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
+ },
+ // Defaults for discrete charts
+ discrete: {
+ lineHeight: 'auto',
+ thresholdColor: undefined,
+ thresholdValue: 0,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for bullet charts
+ bullet: {
+ targetColor: '#f33',
+ targetWidth: 3, // width of the target bar in pixels
+ performanceColor: '#33f',
+ rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
+ base: undefined, // set this to a number to change the base start number
+ tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
+ tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
+ },
+ // Defaults for pie charts
+ pie: {
+ offset: 0,
+ sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ borderWidth: 0,
+ borderColor: '#000',
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value}} ({{percent.1}}%)')
+ },
+ // Defaults for box plots
+ box: {
+ raw: false,
+ boxLineColor: '#000',
+ boxFillColor: '#cdf',
+ whiskerColor: '#000',
+ outlierLineColor: '#333',
+ outlierFillColor: '#fff',
+ medianColor: '#f00',
+ showOutliers: true,
+ outlierIQR: 1.5,
+ spotRadius: 1.5,
+ target: undefined,
+ targetColor: '#4a2',
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
+ tooltipFormatFieldlistKey: 'field',
+ tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
+ uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
+ lw: 'Left Whisker', rw: 'Right Whisker'} }
+ }
+ };
+ };
+
+ // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname
+ defaultStyles = '.jqstooltip { ' +
+ 'position: absolute;' +
+ 'left: 0px;' +
+ 'top: 0px;' +
+ 'visibility: hidden;' +
+ 'background: rgb(0, 0, 0) transparent;' +
+ 'background-color: rgba(0,0,0,0.6);' +
+ 'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +
+ '-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ 'white-space: nowrap;' +
+ 'padding: 5px;' +
+ 'border: 1px solid white;' +
+ 'z-index: 10000;' +
+ '}' +
+ '.jqsfield { ' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ '}';
+
+ /**
+ * Utilities
+ */
+
+ createClass = function (/* [baseclass, [mixin, ...]], definition */) {
+ var Class, args;
+ Class = function () {
+ this.init.apply(this, arguments);
+ };
+ if (arguments.length > 1) {
+ if (arguments[0]) {
+ Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);
+ Class._super = arguments[0].prototype;
+ } else {
+ Class.prototype = arguments[arguments.length - 1];
+ }
+ if (arguments.length > 2) {
+ args = Array.prototype.slice.call(arguments, 1, -1);
+ args.unshift(Class.prototype);
+ $.extend.apply($, args);
+ }
+ } else {
+ Class.prototype = arguments[0];
+ }
+ Class.prototype.cls = Class;
+ return Class;
+ };
+
+ /**
+ * Wraps a format string for tooltips
+ * {{x}}
+ * {{x.2}
+ * {{x:months}}
+ */
+ $.SPFormatClass = SPFormat = createClass({
+ fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
+ precre: /(\w+)\.(\d+)/,
+
+ init: function (format, fclass) {
+ this.format = format;
+ this.fclass = fclass;
+ },
+
+ render: function (fieldset, lookups, options) {
+ var self = this,
+ fields = fieldset,
+ match, token, lookupkey, fieldvalue, prec;
+ return this.format.replace(this.fre, function () {
+ var lookup;
+ token = arguments[1];
+ lookupkey = arguments[3];
+ match = self.precre.exec(token);
+ if (match) {
+ prec = match[2];
+ token = match[1];
+ } else {
+ prec = false;
+ }
+ fieldvalue = fields[token];
+ if (fieldvalue === undefined) {
+ return '';
+ }
+ if (lookupkey && lookups && lookups[lookupkey]) {
+ lookup = lookups[lookupkey];
+ if (lookup.get) { // RangeMap
+ return lookups[lookupkey].get(fieldvalue) || fieldvalue;
+ } else {
+ return lookups[lookupkey][fieldvalue] || fieldvalue;
+ }
+ }
+ if (isNumber(fieldvalue)) {
+ if (options.get('numberFormatter')) {
+ fieldvalue = options.get('numberFormatter')(fieldvalue);
+ } else {
+ fieldvalue = formatNumber(fieldvalue, prec,
+ options.get('numberDigitGroupCount'),
+ options.get('numberDigitGroupSep'),
+ options.get('numberDecimalMark'));
+ }
+ }
+ return fieldvalue;
+ });
+ }
+ });
+
+ // convience method to avoid needing the new operator
+ $.spformat = function(format, fclass) {
+ return new SPFormat(format, fclass);
+ };
+
+ clipval = function (val, min, max) {
+ if (val < min) {
+ return min;
+ }
+ if (val > max) {
+ return max;
+ }
+ return val;
+ };
+
+ quartile = function (values, q) {
+ var vl;
+ if (q === 2) {
+ vl = Math.floor(values.length / 2);
+ return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;
+ } else {
+ if (values.length % 2 ) { // odd
+ vl = (values.length * q + q) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+ } else { //even
+ vl = (values.length * q + 2) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+
+ }
+ }
+ };
+
+ normalizeValue = function (val) {
+ var nf;
+ switch (val) {
+ case 'undefined':
+ val = undefined;
+ break;
+ case 'null':
+ val = null;
+ break;
+ case 'true':
+ val = true;
+ break;
+ case 'false':
+ val = false;
+ break;
+ default:
+ nf = parseFloat(val);
+ if (val == nf) {
+ val = nf;
+ }
+ }
+ return val;
+ };
+
+ normalizeValues = function (vals) {
+ var i, result = [];
+ for (i = vals.length; i--;) {
+ result[i] = normalizeValue(vals[i]);
+ }
+ return result;
+ };
+
+ remove = function (vals, filter) {
+ var i, vl, result = [];
+ for (i = 0, vl = vals.length; i < vl; i++) {
+ if (vals[i] !== filter) {
+ result.push(vals[i]);
+ }
+ }
+ return result;
+ };
+
+ isNumber = function (num) {
+ return !isNaN(parseFloat(num)) && isFinite(num);
+ };
+
+ formatNumber = function (num, prec, groupsize, groupsep, decsep) {
+ var p, i;
+ num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');
+ p = (p = $.inArray('.', num)) < 0 ? num.length : p;
+ if (p < num.length) {
+ num[p] = decsep;
+ }
+ for (i = p - groupsize; i > 0; i -= groupsize) {
+ num.splice(i, 0, groupsep);
+ }
+ return num.join('');
+ };
+
+ // determine if all values of an array match a value
+ // returns true if the array is empty
+ all = function (val, arr, ignoreNull) {
+ var i;
+ for (i = arr.length; i--; ) {
+ if (ignoreNull && arr[i] === null) continue;
+ if (arr[i] !== val) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // sums the numeric values in an array, ignoring other values
+ sum = function (vals) {
+ var total = 0, i;
+ for (i = vals.length; i--;) {
+ total += typeof vals[i] === 'number' ? vals[i] : 0;
+ }
+ return total;
+ };
+
+ ensureArray = function (val) {
+ return $.isArray(val) ? val : [val];
+ };
+
+ // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/
+ addCSS = function(css) {
+ var tag;
+ //if ('\v' == 'v') /* ie only */ {
+ if (document.createStyleSheet) {
+ document.createStyleSheet().cssText = css;
+ } else {
+ tag = document.createElement('style');
+ tag.type = 'text/css';
+ document.getElementsByTagName('head')[0].appendChild(tag);
+ tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;
+ }
+ };
+
+ // Provide a cross-browser interface to a few simple drawing primitives
+ $.fn.simpledraw = function (width, height, useExisting, interact) {
+ var target, mhandler;
+ if (useExisting && (target = this.data('_jqs_vcanvas'))) {
+ return target;
+ }
+
+ if ($.fn.sparkline.canvas === false) {
+ // We've already determined that neither Canvas nor VML are available
+ return false;
+
+ } else if ($.fn.sparkline.canvas === undefined) {
+ // No function defined yet -- need to see if we support Canvas or VML
+ var el = document.createElement('canvas');
+ if (!!(el.getContext && el.getContext('2d'))) {
+ // Canvas is available
+ $.fn.sparkline.canvas = function(width, height, target, interact) {
+ return new VCanvas_canvas(width, height, target, interact);
+ };
+ } else if (document.namespaces && !document.namespaces.v) {
+ // VML is available
+ document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
+ $.fn.sparkline.canvas = function(width, height, target, interact) {
+ return new VCanvas_vml(width, height, target);
+ };
+ } else {
+ // Neither Canvas nor VML are available
+ $.fn.sparkline.canvas = false;
+ return false;
+ }
+ }
+
+ if (width === undefined) {
+ width = $(this).innerWidth();
+ }
+ if (height === undefined) {
+ height = $(this).innerHeight();
+ }
+
+ target = $.fn.sparkline.canvas(width, height, this, interact);
+
+ mhandler = $(this).data('_jqs_mhandler');
+ if (mhandler) {
+ mhandler.registerCanvas(target);
+ }
+ return target;
+ };
+
+ $.fn.cleardraw = function () {
+ var target = this.data('_jqs_vcanvas');
+ if (target) {
+ target.reset();
+ }
+ };
+
+ $.RangeMapClass = RangeMap = createClass({
+ init: function (map) {
+ var key, range, rangelist = [];
+ for (key in map) {
+ if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {
+ range = key.split(':');
+ range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
+ range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
+ range[2] = map[key];
+ rangelist.push(range);
+ }
+ }
+ this.map = map;
+ this.rangelist = rangelist || false;
+ },
+
+ get: function (value) {
+ var rangelist = this.rangelist,
+ i, range, result;
+ if ((result = this.map[value]) !== undefined) {
+ return result;
+ }
+ if (rangelist) {
+ for (i = rangelist.length; i--;) {
+ range = rangelist[i];
+ if (range[0] <= value && range[1] >= value) {
+ return range[2];
+ }
+ }
+ }
+ return undefined;
+ }
+ });
+
+ // Convenience function
+ $.range_map = function(map) {
+ return new RangeMap(map);
+ };
+
+ MouseHandler = createClass({
+ init: function (el, options) {
+ var $el = $(el);
+ this.$el = $el;
+ this.options = options;
+ this.currentPageX = 0;
+ this.currentPageY = 0;
+ this.el = el;
+ this.splist = [];
+ this.tooltip = null;
+ this.over = false;
+ this.displayTooltips = !options.get('disableTooltips');
+ this.highlightEnabled = !options.get('disableHighlight');
+ },
+
+ registerSparkline: function (sp) {
+ this.splist.push(sp);
+ if (this.over) {
+ this.updateDisplay();
+ }
+ },
+
+ registerCanvas: function (canvas) {
+ var $canvas = $(canvas.canvas);
+ this.canvas = canvas;
+ this.$canvas = $canvas;
+ $canvas.mouseenter($.proxy(this.mouseenter, this));
+ $canvas.mouseleave($.proxy(this.mouseleave, this));
+ $canvas.click($.proxy(this.mouseclick, this));
+ },
+
+ reset: function (removeTooltip) {
+ this.splist = [];
+ if (this.tooltip && removeTooltip) {
+ this.tooltip.remove();
+ this.tooltip = undefined;
+ }
+ },
+
+ mouseclick: function (e) {
+ var clickEvent = $.Event('sparklineClick');
+ clickEvent.originalEvent = e;
+ clickEvent.sparklines = this.splist;
+ this.$el.trigger(clickEvent);
+ },
+
+ mouseenter: function (e) {
+ $(document.body).unbind('mousemove.jqs');
+ $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));
+ this.over = true;
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (!this.tooltip && this.displayTooltips) {
+ this.tooltip = new Tooltip(this.options);
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ mouseleave: function () {
+ $(document.body).unbind('mousemove.jqs');
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ sp, i;
+ this.over = false;
+ this.currentEl = null;
+
+ if (this.tooltip) {
+ this.tooltip.remove();
+ this.tooltip = null;
+ }
+
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ if (sp.clearRegionHighlight()) {
+ needsRefresh = true;
+ }
+ }
+
+ if (needsRefresh) {
+ this.canvas.render();
+ }
+ },
+
+ mousemove: function (e) {
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (this.tooltip) {
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ updateDisplay: function () {
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ offset = this.$canvas.offset(),
+ localX = this.currentPageX - offset.left,
+ localY = this.currentPageY - offset.top,
+ tooltiphtml, sp, i, result, changeEvent;
+ if (!this.over) {
+ return;
+ }
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ result = sp.setRegionHighlight(this.currentEl, localX, localY);
+ if (result) {
+ needsRefresh = true;
+ }
+ }
+ if (needsRefresh) {
+ changeEvent = $.Event('sparklineRegionChange');
+ changeEvent.sparklines = this.splist;
+ this.$el.trigger(changeEvent);
+ if (this.tooltip) {
+ tooltiphtml = '';
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ tooltiphtml += sp.getCurrentRegionTooltip();
+ }
+ this.tooltip.setContent(tooltiphtml);
+ }
+ if (!this.disableHighlight) {
+ this.canvas.render();
+ }
+ }
+ if (result === null) {
+ this.mouseleave();
+ }
+ }
+ });
+
+
+ Tooltip = createClass({
+ sizeStyle: 'position: static !important;' +
+ 'display: block !important;' +
+ 'visibility: hidden !important;' +
+ 'float: left !important;',
+
+ init: function (options) {
+ var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),
+ sizetipStyle = this.sizeStyle,
+ offset;
+ this.container = options.get('tooltipContainer') || document.body;
+ this.tooltipOffsetX = options.get('tooltipOffsetX', 10);
+ this.tooltipOffsetY = options.get('tooltipOffsetY', 12);
+ // remove any previous lingering tooltip
+ $('#jqssizetip').remove();
+ $('#jqstooltip').remove();
+ this.sizetip = $('<div/>', {
+ id: 'jqssizetip',
+ style: sizetipStyle,
+ 'class': tooltipClassname
+ });
+ this.tooltip = $('<div/>', {
+ id: 'jqstooltip',
+ 'class': tooltipClassname
+ }).appendTo(this.container);
+ // account for the container's location
+ offset = this.tooltip.offset();
+ this.offsetLeft = offset.left;
+ this.offsetTop = offset.top;
+ this.hidden = true;
+ $(window).unbind('resize.jqs scroll.jqs');
+ $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));
+ this.updateWindowDims();
+ },
+
+ updateWindowDims: function () {
+ this.scrollTop = $(window).scrollTop();
+ this.scrollLeft = $(window).scrollLeft();
+ this.scrollRight = this.scrollLeft + $(window).width();
+ this.updatePosition();
+ },
+
+ getSize: function (content) {
+ this.sizetip.html(content).appendTo(this.container);
+ this.width = this.sizetip.width() + 1;
+ this.height = this.sizetip.height();
+ this.sizetip.remove();
+ },
+
+ setContent: function (content) {
+ if (!content) {
+ this.tooltip.css('visibility', 'hidden');
+ this.hidden = true;
+ return;
+ }
+ this.getSize(content);
+ this.tooltip.html(content)
+ .css({
+ 'width': this.width,
+ 'height': this.height,
+ 'visibility': 'visible'
+ });
+ if (this.hidden) {
+ this.hidden = false;
+ this.updatePosition();
+ }
+ },
+
+ updatePosition: function (x, y) {
+ if (x === undefined) {
+ if (this.mousex === undefined) {
+ return;
+ }
+ x = this.mousex - this.offsetLeft;
+ y = this.mousey - this.offsetTop;
+
+ } else {
+ this.mousex = x = x - this.offsetLeft;
+ this.mousey = y = y - this.offsetTop;
+ }
+ if (!this.height || !this.width || this.hidden) {
+ return;
+ }
+
+ y -= this.height + this.tooltipOffsetY;
+ x += this.tooltipOffsetX;
+
+ if (y < this.scrollTop) {
+ y = this.scrollTop;
+ }
+ if (x < this.scrollLeft) {
+ x = this.scrollLeft;
+ } else if (x + this.width > this.scrollRight) {
+ x = this.scrollRight - this.width;
+ }
+
+ this.tooltip.css({
+ 'left': x,
+ 'top': y
+ });
+ },
+
+ remove: function () {
+ this.tooltip.remove();
+ this.sizetip.remove();
+ this.sizetip = this.tooltip = undefined;
+ $(window).unbind('resize.jqs scroll.jqs');
+ }
+ });
+
+ initStyles = function() {
+ addCSS(defaultStyles);
+ };
+
+ $(initStyles);
+
+ pending = [];
+ $.fn.sparkline = function (userValues, userOptions) {
+ return this.each(function () {
+ var options = new $.fn.sparkline.options(this, userOptions),
+ $this = $(this),
+ render, i;
+ render = function () {
+ var values, width, height, tmp, mhandler, sp, vals;
+ if (userValues === 'html' || userValues === undefined) {
+ vals = this.getAttribute(options.get('tagValuesAttribute'));
+ if (vals === undefined || vals === null) {
+ vals = $this.html();
+ }
+ values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, '').split(',');
+ } else {
+ values = userValues;
+ }
+
+ width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');
+ if (options.get('height') === 'auto') {
+ if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {
+ // must be a better way to get the line height
+ tmp = document.createElement('span');
+ tmp.innerHTML = 'a';
+ $this.html(tmp);
+ height = $(tmp).innerHeight() || $(tmp).height();
+ $(tmp).remove();
+ tmp = null;
+ }
+ } else {
+ height = options.get('height');
+ }
+
+ if (!options.get('disableInteraction')) {
+ mhandler = $.data(this, '_jqs_mhandler');
+ if (!mhandler) {
+ mhandler = new MouseHandler(this, options);
+ $.data(this, '_jqs_mhandler', mhandler);
+ } else if (!options.get('composite')) {
+ mhandler.reset();
+ }
+ } else {
+ mhandler = false;
+ }
+
+ if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {
+ if (!$.data(this, '_jqs_errnotify')) {
+ alert('Attempted to attach a composite sparkline to an element with no existing sparkline');
+ $.data(this, '_jqs_errnotify', true);
+ }
+ return;
+ }
+
+ sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);
+
+ sp.render();
+
+ if (mhandler) {
+ mhandler.registerSparkline(sp);
+ }
+ };
+ if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {
+ if (!options.get('composite') && $.data(this, '_jqs_pending')) {
+ // remove any existing references to the element
+ for (i = pending.length; i; i--) {
+ if (pending[i - 1][0] == this) {
+ pending.splice(i - 1, 1);
+ }
+ }
+ }
+ pending.push([this, render]);
+ $.data(this, '_jqs_pending', true);
+ } else {
+ render.call(this);
+ }
+ });
+ };
+
+ $.fn.sparkline.defaults = getDefaults();
+
+
+ $.sparkline_display_visible = function () {
+ var el, i, pl;
+ var done = [];
+ for (i = 0, pl = pending.length; i < pl; i++) {
+ el = pending[i][0];
+ if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {
+ pending[i][1].call(el);
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {
+ // element has been inserted and removed from the DOM
+ // If it was not yet inserted into the dom then the .data request
+ // will return true.
+ // removing from the dom causes the data to be removed.
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ }
+ }
+ for (i = done.length; i; i--) {
+ pending.splice(done[i - 1], 1);
+ }
+ };
+
+
+ /**
+ * User option handler
+ */
+ $.fn.sparkline.options = createClass({
+ init: function (tag, userOptions) {
+ var extendedOptions, defaults, base, tagOptionType;
+ this.userOptions = userOptions = userOptions || {};
+ this.tag = tag;
+ this.tagValCache = {};
+ defaults = $.fn.sparkline.defaults;
+ base = defaults.common;
+ this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
+
+ tagOptionType = this.getTagSetting('type');
+ if (tagOptionType === UNSET_OPTION) {
+ extendedOptions = defaults[userOptions.type || base.type];
+ } else {
+ extendedOptions = defaults[tagOptionType];
+ }
+ this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);
+ },
+
+
+ getTagSetting: function (key) {
+ var prefix = this.tagOptionsPrefix,
+ val, i, pairs, keyval;
+ if (prefix === false || prefix === undefined) {
+ return UNSET_OPTION;
+ }
+ if (this.tagValCache.hasOwnProperty(key)) {
+ val = this.tagValCache.key;
+ } else {
+ val = this.tag.getAttribute(prefix + key);
+ if (val === undefined || val === null) {
+ val = UNSET_OPTION;
+ } else if (val.substr(0, 1) === '[') {
+ val = val.substr(1, val.length - 2).split(',');
+ for (i = val.length; i--;) {
+ val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else if (val.substr(0, 1) === '{') {
+ pairs = val.substr(1, val.length - 2).split(',');
+ val = {};
+ for (i = pairs.length; i--;) {
+ keyval = pairs[i].split(':', 2);
+ val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else {
+ val = normalizeValue(val);
+ }
+ this.tagValCache.key = val;
+ }
+ return val;
+ },
+
+ get: function (key, defaultval) {
+ var tagOption = this.getTagSetting(key),
+ result;
+ if (tagOption !== UNSET_OPTION) {
+ return tagOption;
+ }
+ return (result = this.mergedOptions[key]) === undefined ? defaultval : result;
+ }
+ });
+
+
+ $.fn.sparkline._base = createClass({
+ disabled: false,
+
+ init: function (el, values, options, width, height) {
+ this.el = el;
+ this.$el = $(el);
+ this.values = values;
+ this.options = options;
+ this.width = width;
+ this.height = height;
+ this.currentRegion = undefined;
+ },
+
+ /**
+ * Setup the canvas
+ */
+ initTarget: function () {
+ var interactive = !this.options.get('disableInteraction');
+ if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {
+ this.disabled = true;
+ } else {
+ this.canvasWidth = this.target.pixelWidth;
+ this.canvasHeight = this.target.pixelHeight;
+ }
+ },
+
+ /**
+ * Actually render the chart to the canvas
+ */
+ render: function () {
+ if (this.disabled) {
+ this.el.innerHTML = '';
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * Return a region id for a given x/y co-ordinate
+ */
+ getRegion: function (x, y) {
+ },
+
+ /**
+ * Highlight an item based on the moused-over x,y co-ordinate
+ */
+ setRegionHighlight: function (el, x, y) {
+ var currentRegion = this.currentRegion,
+ highlightEnabled = !this.options.get('disableHighlight'),
+ newRegion;
+ if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
+ return null;
+ }
+ newRegion = this.getRegion(el, x, y);
+ if (currentRegion !== newRegion) {
+ if (currentRegion !== undefined && highlightEnabled) {
+ this.removeHighlight();
+ }
+ this.currentRegion = newRegion;
+ if (newRegion !== undefined && highlightEnabled) {
+ this.renderHighlight();
+ }
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Reset any currently highlighted item
+ */
+ clearRegionHighlight: function () {
+ if (this.currentRegion !== undefined) {
+ this.removeHighlight();
+ this.currentRegion = undefined;
+ return true;
+ }
+ return false;
+ },
+
+ renderHighlight: function () {
+ this.changeHighlight(true);
+ },
+
+ removeHighlight: function () {
+ this.changeHighlight(false);
+ },
+
+ changeHighlight: function (highlight) {},
+
+ /**
+ * Fetch the HTML to display as a tooltip
+ */
+ getCurrentRegionTooltip: function () {
+ var options = this.options,
+ header = '',
+ entries = [],
+ fields, formats, formatlen, fclass, text, i,
+ showFields, showFieldsKey, newFields, fv,
+ formatter, format, fieldlen, j;
+ if (this.currentRegion === undefined) {
+ return '';
+ }
+ fields = this.getCurrentRegionFields();
+ formatter = options.get('tooltipFormatter');
+ if (formatter) {
+ return formatter(this, options, fields);
+ }
+ if (options.get('tooltipChartTitle')) {
+ header += '<div class="jqs jqstitle">' + options.get('tooltipChartTitle') + '</div>\n';
+ }
+ formats = this.options.get('tooltipFormat');
+ if (!formats) {
+ return '';
+ }
+ if (!$.isArray(formats)) {
+ formats = [formats];
+ }
+ if (!$.isArray(fields)) {
+ fields = [fields];
+ }
+ showFields = this.options.get('tooltipFormatFieldlist');
+ showFieldsKey = this.options.get('tooltipFormatFieldlistKey');
+ if (showFields && showFieldsKey) {
+ // user-selected ordering of fields
+ newFields = [];
+ for (i = fields.length; i--;) {
+ fv = fields[i][showFieldsKey];
+ if ((j = $.inArray(fv, showFields)) != -1) {
+ newFields[j] = fields[i];
+ }
+ }
+ fields = newFields;
+ }
+ formatlen = formats.length;
+ fieldlen = fields.length;
+ for (i = 0; i < formatlen; i++) {
+ format = formats[i];
+ if (typeof format === 'string') {
+ format = new SPFormat(format);
+ }
+ fclass = format.fclass || 'jqsfield';
+ for (j = 0; j < fieldlen; j++) {
+ if (!fields[j].isNull || !options.get('tooltipSkipNull')) {
+ $.extend(fields[j], {
+ prefix: options.get('tooltipPrefix'),
+ suffix: options.get('tooltipSuffix')
+ });
+ text = format.render(fields[j], options.get('tooltipValueLookups'), options);
+ entries.push('<div class="' + fclass + '">' + text + '</div>');
+ }
+ }
+ }
+ if (entries.length) {
+ return header + entries.join('\n');
+ }
+ return '';
+ },
+
+ getCurrentRegionFields: function () {},
+
+ calcHighlightColor: function (color, options) {
+ var highlightColor = options.get('highlightColor'),
+ lighten = options.get('highlightLighten'),
+ parse, mult, rgbnew, i;
+ if (highlightColor) {
+ return highlightColor;
+ }
+ if (lighten) {
+ // extract RGB values
+ parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
+ if (parse) {
+ rgbnew = [];
+ mult = color.length === 4 ? 16 : 1;
+ for (i = 0; i < 3; i++) {
+ rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
+ }
+ return 'rgb(' + rgbnew.join(',') + ')';
+ }
+
+ }
+ return color;
+ }
+
+ });
+
+ barHighlightMixin = {
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ shapeids = this.regionShapes[currentRegion],
+ newShapes;
+ // will be null if the region value was null
+ if (shapeids) {
+ newShapes = this.renderRegion(currentRegion, highlight);
+ if ($.isArray(newShapes) || $.isArray(shapeids)) {
+ target.replaceWithShapes(shapeids, newShapes);
+ this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {
+ return newShape.id;
+ });
+ } else {
+ target.replaceWithShape(shapeids, newShapes);
+ this.regionShapes[currentRegion] = newShapes.id;
+ }
+ }
+ },
+
+ render: function () {
+ var values = this.values,
+ target = this.target,
+ regionShapes = this.regionShapes,
+ shapes, ids, i, j;
+
+ if (!this.cls._super.render.call(this)) {
+ return;
+ }
+ for (i = values.length; i--;) {
+ shapes = this.renderRegion(i);
+ if (shapes) {
+ if ($.isArray(shapes)) {
+ ids = [];
+ for (j = shapes.length; j--;) {
+ shapes[j].append();
+ ids.push(shapes[j].id);
+ }
+ regionShapes[i] = ids;
+ } else {
+ shapes.append();
+ regionShapes[i] = shapes.id; // store just the shapeid
+ }
+ } else {
+ // null value
+ regionShapes[i] = null;
+ }
+ }
+ target.render();
+ }
+ };
+
+ /**
+ * Line charts
+ */
+ $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
+ type: 'line',
+
+ init: function (el, values, options, width, height) {
+ line._super.init.call(this, el, values, options, width, height);
+ this.vertices = [];
+ this.regionMap = [];
+ this.xvalues = [];
+ this.yvalues = [];
+ this.yminmax = [];
+ this.hightlightSpotId = null;
+ this.lastShapeId = null;
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var i,
+ regionMap = this.regionMap; // maps regions to value positions
+ for (i = regionMap.length; i--;) {
+ if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
+ return regionMap[i][2];
+ }
+ }
+ return undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.yvalues[currentRegion] === null,
+ x: this.xvalues[currentRegion],
+ y: this.yvalues[currentRegion],
+ color: this.options.get('lineColor'),
+ fillColor: this.options.get('fillColor'),
+ offset: currentRegion
+ };
+ },
+
+ renderHighlight: function () {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ vertex = this.vertices[currentRegion],
+ options = this.options,
+ spotRadius = options.get('spotRadius'),
+ highlightSpotColor = options.get('highlightSpotColor'),
+ highlightLineColor = options.get('highlightLineColor'),
+ highlightSpot, highlightLine;
+
+ if (!vertex) {
+ return;
+ }
+ if (spotRadius && highlightSpotColor) {
+ highlightSpot = target.drawCircle(vertex[0], vertex[1],
+ spotRadius, undefined, highlightSpotColor);
+ this.highlightSpotId = highlightSpot.id;
+ target.insertAfterShape(this.lastShapeId, highlightSpot);
+ }
+ if (highlightLineColor) {
+ highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
+ this.canvasTop + this.canvasHeight, highlightLineColor);
+ this.highlightLineId = highlightLine.id;
+ target.insertAfterShape(this.lastShapeId, highlightLine);
+ }
+ },
+
+ removeHighlight: function () {
+ var target = this.target;
+ if (this.highlightSpotId) {
+ target.removeShapeId(this.highlightSpotId);
+ this.highlightSpotId = null;
+ }
+ if (this.highlightLineId) {
+ target.removeShapeId(this.highlightLineId);
+ this.highlightLineId = null;
+ }
+ },
+
+ scanValues: function () {
+ var values = this.values,
+ valcount = values.length,
+ xvalues = this.xvalues,
+ yvalues = this.yvalues,
+ yminmax = this.yminmax,
+ i, val, isStr, isArray, sp;
+ for (i = 0; i < valcount; i++) {
+ val = values[i];
+ isStr = typeof(values[i]) === 'string';
+ isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
+ sp = isStr && values[i].split(':');
+ if (isStr && sp.length === 2) { // x:y
+ xvalues.push(Number(sp[0]));
+ yvalues.push(Number(sp[1]));
+ yminmax.push(Number(sp[1]));
+ } else if (isArray) {
+ xvalues.push(val[0]);
+ yvalues.push(val[1]);
+ yminmax.push(val[1]);
+ } else {
+ xvalues.push(i);
+ if (values[i] === null || values[i] === 'null') {
+ yvalues.push(null);
+ } else {
+ yvalues.push(Number(val));
+ yminmax.push(Number(val));
+ }
+ }
+ }
+ if (this.options.get('xvalues')) {
+ xvalues = this.options.get('xvalues');
+ }
+
+ this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
+ this.miny = this.minyorg = Math.min.apply(Math, yminmax);
+
+ this.maxx = Math.max.apply(Math, xvalues);
+ this.minx = Math.min.apply(Math, xvalues);
+
+ this.xvalues = xvalues;
+ this.yvalues = yvalues;
+ this.yminmax = yminmax;
+
+ },
+
+ processRangeOptions: function () {
+ var options = this.options,
+ normalRangeMin = options.get('normalRangeMin'),
+ normalRangeMax = options.get('normalRangeMax');
+
+ if (normalRangeMin !== undefined) {
+ if (normalRangeMin < this.miny) {
+ this.miny = normalRangeMin;
+ }
+ if (normalRangeMax > this.maxy) {
+ this.maxy = normalRangeMax;
+ }
+ }
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
+ this.miny = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
+ this.maxy = options.get('chartRangeMax');
+ }
+ if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
+ this.minx = options.get('chartRangeMinX');
+ }
+ if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
+ this.maxx = options.get('chartRangeMaxX');
+ }
+
+ },
+
+ drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
+ var normalRangeMin = this.options.get('normalRangeMin'),
+ normalRangeMax = this.options.get('normalRangeMax'),
+ ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
+ height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
+ this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
+ },
+
+ render: function () {
+ var options = this.options,
+ target = this.target,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ vertices = this.vertices,
+ spotRadius = options.get('spotRadius'),
+ regionMap = this.regionMap,
+ rangex, rangey, yvallast,
+ canvasTop, canvasLeft,
+ vertex, path, paths, x, y, xnext, xpos, xposnext,
+ last, next, yvalcount, lineShapes, fillShapes, plen,
+ valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
+
+ if (!line._super.render.call(this)) {
+ return;
+ }
+
+ this.scanValues();
+ this.processRangeOptions();
+
+ xvalues = this.xvalues;
+ yvalues = this.yvalues;
+
+ if (!this.yminmax.length || this.yvalues.length < 2) {
+ // empty or all null valuess
+ return;
+ }
+
+ canvasTop = canvasLeft = 0;
+
+ rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
+ rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
+ yvallast = this.yvalues.length - 1;
+
+ if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
+ spotRadius = 0;
+ }
+ if (spotRadius) {
+ // adjust the canvas size as required so that spots will fit
+ hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');
+ if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ canvasTop += Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled ||
+ ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
+ canvasLeft += Math.ceil(spotRadius);
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('spotColor') ||
+ (options.get('minSpotColor') || options.get('maxSpotColor') &&
+ (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ }
+
+
+ canvasHeight--;
+
+ if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ path = [];
+ paths = [path];
+ last = next = null;
+ yvalcount = yvalues.length;
+ for (i = 0; i < yvalcount; i++) {
+ x = xvalues[i];
+ xnext = xvalues[i + 1];
+ y = yvalues[i];
+ xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
+ xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
+ next = xpos + ((xposnext - xpos) / 2);
+ regionMap[i] = [last || 0, next, i];
+ last = next;
+ if (y === null) {
+ if (i) {
+ if (yvalues[i - 1] !== null) {
+ path = [];
+ paths.push(path);
+ }
+ vertices.push(null);
+ }
+ } else {
+ if (y < this.miny) {
+ y = this.miny;
+ }
+ if (y > this.maxy) {
+ y = this.maxy;
+ }
+ if (!path.length) {
+ // previous value was null
+ path.push([xpos, canvasTop + canvasHeight]);
+ }
+ vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
+ path.push(vertex);
+ vertices.push(vertex);
+ }
+ }
+
+ lineShapes = [];
+ fillShapes = [];
+ plen = paths.length;
+ for (i = 0; i < plen; i++) {
+ path = paths[i];
+ if (path.length) {
+ if (options.get('fillColor')) {
+ path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
+ fillShapes.push(path.slice(0));
+ path.pop();
+ }
+ // if there's only a single point in this path, then we want to display it
+ // as a vertical line which means we keep path[0] as is
+ if (path.length > 2) {
+ // else we want the first value
+ path[0] = [path[0][0], path[1][1]];
+ }
+ lineShapes.push(path);
+ }
+ }
+
+ // draw the fill first, then optionally the normal range, then the line on top of that
+ plen = fillShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(fillShapes[i],
+ options.get('fillColor'), options.get('fillColor')).append();
+ }
+
+ if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ plen = lineShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
+ options.get('lineWidth')).append();
+ }
+
+ if (spotRadius && options.get('valueSpots')) {
+ valueSpots = options.get('valueSpots');
+ if (valueSpots.get === undefined) {
+ valueSpots = new RangeMap(valueSpots);
+ }
+ for (i = 0; i < yvalcount; i++) {
+ color = valueSpots.get(yvalues[i]);
+ if (color) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
+ spotRadius, undefined,
+ color).append();
+ }
+ }
+
+ }
+ if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('spotColor')).append();
+ }
+ if (this.maxy !== this.minyorg) {
+ if (spotRadius && options.get('minSpotColor')) {
+ x = xvalues[$.inArray(this.minyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('minSpotColor')).append();
+ }
+ if (spotRadius && options.get('maxSpotColor')) {
+ x = xvalues[$.inArray(this.maxyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('maxSpotColor')).append();
+ }
+ }
+
+ this.lastShapeId = target.getLastShapeId();
+ this.canvasTop = canvasTop;
+ target.render();
+ }
+ });
+
+ /**
+ * Bar charts
+ */
+ $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'bar',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10),
+ chartRangeMin = options.get('chartRangeMin'),
+ chartRangeMax = options.get('chartRangeMax'),
+ chartRangeClip = options.get('chartRangeClip'),
+ stackMin = Infinity,
+ stackMax = -Infinity,
+ isStackString, groupMin, groupMax, stackRanges,
+ numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,
+ stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
+ bar._super.init.call(this, el, values, options, width, height);
+
+ // scan values to determine whether to stack bars
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ val = values[i];
+ isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;
+ if (isStackString || $.isArray(val)) {
+ stacked = true;
+ if (isStackString) {
+ val = values[i] = normalizeValues(val.split(':'));
+ }
+ val = remove(val, null); // min/max will treat null as zero
+ groupMin = Math.min.apply(Math, val);
+ groupMax = Math.max.apply(Math, val);
+ if (groupMin < stackMin) {
+ stackMin = groupMin;
+ }
+ if (groupMax > stackMax) {
+ stackMax = groupMax;
+ }
+ }
+ }
+
+ this.stacked = stacked;
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ this.initTarget();
+
+ if (chartRangeClip) {
+ clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;
+ clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;
+ }
+
+ numValues = [];
+ stackRanges = stacked ? [] : numValues;
+ var stackTotals = [];
+ var stackRangesNeg = [];
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ if (stacked) {
+ vlist = values[i];
+ values[i] = svals = [];
+ stackTotals[i] = 0;
+ stackRanges[i] = stackRangesNeg[i] = 0;
+ for (j = 0, slen = vlist.length; j < slen; j++) {
+ val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
+ if (val !== null) {
+ if (val > 0) {
+ stackTotals[i] += val;
+ }
+ if (stackMin < 0 && stackMax > 0) {
+ if (val < 0) {
+ stackRangesNeg[i] += Math.abs(val);
+ } else {
+ stackRanges[i] += val;
+ }
+ } else {
+ stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));
+ }
+ numValues.push(val);
+ }
+ }
+ } else {
+ val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
+ val = values[i] = normalizeValue(val);
+ if (val !== null) {
+ numValues.push(val);
+ }
+ }
+ }
+ this.max = max = Math.max.apply(Math, numValues);
+ this.min = min = Math.min.apply(Math, numValues);
+ this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;
+ this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;
+
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {
+ min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {
+ max = options.get('chartRangeMax');
+ }
+
+ this.zeroAxis = zeroAxis = options.get('zeroAxis', true);
+ if (min <= 0 && max >= 0 && zeroAxis) {
+ xaxisOffset = 0;
+ } else if (zeroAxis == false) {
+ xaxisOffset = min;
+ } else if (min > 0) {
+ xaxisOffset = min;
+ } else {
+ xaxisOffset = max;
+ }
+ this.xaxisOffset = xaxisOffset;
+
+ range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;
+
+ // as we plot zero/min values a single pixel line, we add a pixel to all other
+ // values - Reduce the effective canvas size to suit
+ this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;
+
+ if (min < xaxisOffset) {
+ yMaxCalc = (stacked && max >= 0) ? stackMax : max;
+ yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
+ if (yoffset !== Math.ceil(yoffset)) {
+ this.canvasHeightEf -= 2;
+ yoffset = Math.ceil(yoffset);
+ }
+ } else {
+ yoffset = this.canvasHeight;
+ }
+ this.yoffset = yoffset;
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+
+ this.range = range;
+ },
+
+ getRegion: function (el, x, y) {
+ var result = Math.floor(x / this.totalBarWidth);
+ return (result < 0 || result >= this.values.length) ? undefined : result;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion,
+ values = ensureArray(this.values[currentRegion]),
+ result = [],
+ value, i;
+ for (i = values.length; i--;) {
+ value = values[i];
+ result.push({
+ isNull: value === null,
+ value: value,
+ color: this.calcColor(i, value, currentRegion),
+ offset: currentRegion
+ });
+ }
+ return result;
+ },
+
+ calcColor: function (stacknum, value, valuenum) {
+ var colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ options = this.options,
+ color, newColor;
+ if (this.stacked) {
+ color = options.get('stackedBarColor');
+ } else {
+ color = (value < 0) ? options.get('negBarColor') : options.get('barColor');
+ }
+ if (value === 0 && options.get('zeroColor') !== undefined) {
+ color = options.get('zeroColor');
+ }
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ }
+ return $.isArray(color) ? color[stacknum % color.length] : color;
+ },
+
+ /**
+ * Render bar(s) for a region
+ */
+ renderRegion: function (valuenum, highlight) {
+ var vals = this.values[valuenum],
+ options = this.options,
+ xaxisOffset = this.xaxisOffset,
+ result = [],
+ range = this.range,
+ stacked = this.stacked,
+ target = this.target,
+ x = valuenum * this.totalBarWidth,
+ canvasHeightEf = this.canvasHeightEf,
+ yoffset = this.yoffset,
+ y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
+
+ vals = $.isArray(vals) ? vals : [vals];
+ valcount = vals.length;
+ val = vals[0];
+ isNull = all(null, vals);
+ allMin = all(xaxisOffset, vals, true);
+
+ if (isNull) {
+ if (options.get('nullColor')) {
+ color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);
+ y = (yoffset > 0) ? yoffset - 1 : yoffset;
+ return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
+ } else {
+ return undefined;
+ }
+ }
+ yoffsetNeg = yoffset;
+ for (i = 0; i < valcount; i++) {
+ val = vals[i];
+
+ if (stacked && val === xaxisOffset) {
+ if (!allMin || minPlotted) {
+ continue;
+ }
+ minPlotted = true;
+ }
+
+ if (range > 0) {
+ height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;
+ } else {
+ height = 1;
+ }
+ if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {
+ y = yoffsetNeg;
+ yoffsetNeg += height;
+ } else {
+ y = yoffset - height;
+ yoffset -= height;
+ }
+ color = this.calcColor(i, val, valuenum);
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
+ }
+ if (result.length === 1) {
+ return result[0];
+ }
+ return result;
+ }
+ });
+
+ /**
+ * Tristate charts
+ */
+ $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'tristate',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10);
+ tristate._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.values = $.map(values, Number);
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.totalBarWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ color: this.calcColor(this.values[currentRegion], currentRegion),
+ offset: currentRegion
+ };
+ },
+
+ calcColor: function (value, valuenum) {
+ var values = this.values,
+ options = this.options,
+ colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ color, newColor;
+
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ } else if (values[valuenum] < 0) {
+ color = options.get('negBarColor');
+ } else if (values[valuenum] > 0) {
+ color = options.get('posBarColor');
+ } else {
+ color = options.get('zeroBarColor');
+ }
+ return color;
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ target = this.target,
+ canvasHeight, height, halfHeight,
+ x, y, color;
+
+ canvasHeight = target.pixelHeight;
+ halfHeight = Math.round(canvasHeight / 2);
+
+ x = valuenum * this.totalBarWidth;
+ if (values[valuenum] < 0) {
+ y = halfHeight;
+ height = halfHeight - 1;
+ } else if (values[valuenum] > 0) {
+ y = 0;
+ height = halfHeight - 1;
+ } else {
+ y = halfHeight - 1;
+ height = 2;
+ }
+ color = this.calcColor(values[valuenum], valuenum);
+ if (color === null) {
+ return;
+ }
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
+ }
+ });
+
+ /**
+ * Discrete charts
+ */
+ $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'discrete',
+
+ init: function (el, values, options, width, height) {
+ discrete._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.values = values = $.map(values, Number);
+ this.min = Math.min.apply(Math, values);
+ this.max = Math.max.apply(Math, values);
+ this.range = this.max - this.min;
+ this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
+ this.interval = Math.floor(width / values.length);
+ this.itemWidth = width / values.length;
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
+ this.min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
+ this.max = options.get('chartRangeMax');
+ }
+ this.initTarget();
+ if (this.target) {
+ this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
+ }
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.itemWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ offset: currentRegion
+ };
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ min = this.min,
+ max = this.max,
+ range = this.range,
+ interval = this.interval,
+ target = this.target,
+ canvasHeight = this.canvasHeight,
+ lineHeight = this.lineHeight,
+ pheight = canvasHeight - lineHeight,
+ ytop, val, color, x;
+
+ val = clipval(values[valuenum], min, max);
+ x = valuenum * interval;
+ ytop = Math.round(pheight - pheight * ((val - min) / range));
+ color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawLine(x, ytop, x, ytop + lineHeight, color);
+ }
+ });
+
+ /**
+ * Bullet charts
+ */
+ $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
+ type: 'bullet',
+
+ init: function (el, values, options, width, height) {
+ var min, max, vals;
+ bullet._super.init.call(this, el, values, options, width, height);
+
+ // values: target, performance, range1, range2, range3
+ this.values = values = normalizeValues(values);
+ // target or performance could be null
+ vals = values.slice();
+ vals[0] = vals[0] === null ? vals[2] : vals[0];
+ vals[1] = values[1] === null ? vals[2] : vals[1];
+ min = Math.min.apply(Math, values);
+ max = Math.max.apply(Math, values);
+ if (options.get('base') === undefined) {
+ min = min < 0 ? min : 0;
+ } else {
+ min = options.get('base');
+ }
+ this.min = min;
+ this.max = max;
+ this.range = max - min;
+ this.shapes = {};
+ this.valueShapes = {};
+ this.regiondata = {};
+ this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.target = this.$el.simpledraw(width, height, options.get('composite'));
+ if (!values.length) {
+ this.disabled = true;
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ fieldkey: currentRegion.substr(0, 1),
+ value: this.values[currentRegion.substr(1)],
+ region: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ shapeid = this.valueShapes[currentRegion],
+ shape;
+ delete this.shapes[shapeid];
+ switch (currentRegion.substr(0, 1)) {
+ case 'r':
+ shape = this.renderRange(currentRegion.substr(1), highlight);
+ break;
+ case 'p':
+ shape = this.renderPerformance(highlight);
+ break;
+ case 't':
+ shape = this.renderTarget(highlight);
+ break;
+ }
+ this.valueShapes[currentRegion] = shape.id;
+ this.shapes[shape.id] = currentRegion;
+ this.target.replaceWithShape(shapeid, shape);
+ },
+
+ renderRange: function (rn, highlight) {
+ var rangeval = this.values[rn],
+ rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
+ color = this.options.get('rangeColors')[rn - 2];
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
+ },
+
+ renderPerformance: function (highlight) {
+ var perfval = this.values[1],
+ perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
+ color = this.options.get('performanceColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
+ Math.round(this.canvasHeight * 0.4) - 1, color, color);
+ },
+
+ renderTarget: function (highlight) {
+ var targetval = this.values[0],
+ x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
+ targettop = Math.round(this.canvasHeight * 0.10),
+ targetheight = this.canvasHeight - (targettop * 2),
+ color = this.options.get('targetColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
+ },
+
+ render: function () {
+ var vlen = this.values.length,
+ target = this.target,
+ i, shape;
+ if (!bullet._super.render.call(this)) {
+ return;
+ }
+ for (i = 2; i < vlen; i++) {
+ shape = this.renderRange(i).append();
+ this.shapes[shape.id] = 'r' + i;
+ this.valueShapes['r' + i] = shape.id;
+ }
+ if (this.values[1] !== null) {
+ shape = this.renderPerformance().append();
+ this.shapes[shape.id] = 'p1';
+ this.valueShapes.p1 = shape.id;
+ }
+ if (this.values[0] !== null) {
+ shape = this.renderTarget().append();
+ this.shapes[shape.id] = 't0';
+ this.valueShapes.t0 = shape.id;
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Pie charts
+ */
+ $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
+ type: 'pie',
+
+ init: function (el, values, options, width, height) {
+ var total = 0, i;
+
+ pie._super.init.call(this, el, values, options, width, height);
+
+ this.shapes = {}; // map shape ids to value offsets
+ this.valueShapes = {}; // maps value offsets to shape ids
+ this.values = values = $.map(values, Number);
+
+ if (options.get('width') === 'auto') {
+ this.width = this.height;
+ }
+
+ if (values.length > 0) {
+ for (i = values.length; i--;) {
+ total += values[i];
+ }
+ }
+ this.total = total;
+ this.initTarget();
+ this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ percent: this.values[currentRegion] / this.total * 100,
+ color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
+ offset: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ newslice = this.renderSlice(currentRegion, highlight),
+ shapeid = this.valueShapes[currentRegion];
+ delete this.shapes[shapeid];
+ this.target.replaceWithShape(shapeid, newslice);
+ this.valueShapes[currentRegion] = newslice.id;
+ this.shapes[newslice.id] = currentRegion;
+ },
+
+ renderSlice: function (valuenum, highlight) {
+ var target = this.target,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ offset = options.get('offset'),
+ circle = 2 * Math.PI,
+ values = this.values,
+ total = this.total,
+ next = offset ? (2*Math.PI)*(offset/360) : 0,
+ start, end, i, vlen, color;
+
+ vlen = values.length;
+ for (i = 0; i < vlen; i++) {
+ start = next;
+ end = next;
+ if (total > 0) { // avoid divide by zero
+ end = next + (circle * (values[i] / total));
+ }
+ if (valuenum === i) {
+ color = options.get('sliceColors')[i % options.get('sliceColors').length];
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+
+ return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
+ }
+ next = end;
+ }
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ shape, i;
+
+ if (!pie._super.render.call(this)) {
+ return;
+ }
+ if (borderWidth) {
+ target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
+ options.get('borderColor'), undefined, borderWidth).append();
+ }
+ for (i = values.length; i--;) {
+ if (values[i]) { // don't render zero values
+ shape = this.renderSlice(i).append();
+ this.valueShapes[i] = shape.id; // store just the shapeid
+ this.shapes[shape.id] = i;
+ }
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Box plots
+ */
+ $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
+ type: 'box',
+
+ init: function (el, values, options, width, height) {
+ box._super.init.call(this, el, values, options, width, height);
+ this.values = $.map(values, Number);
+ this.width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.initTarget();
+ if (!this.values.length) {
+ this.disabled = 1;
+ }
+ },
+
+ /**
+ * Simulate a single region
+ */
+ getRegion: function () {
+ return 1;
+ },
+
+ getCurrentRegionFields: function () {
+ var result = [
+ { field: 'lq', value: this.quartiles[0] },
+ { field: 'med', value: this.quartiles[1] },
+ { field: 'uq', value: this.quartiles[2] }
+ ];
+ if (this.loutlier !== undefined) {
+ result.push({ field: 'lo', value: this.loutlier});
+ }
+ if (this.routlier !== undefined) {
+ result.push({ field: 'ro', value: this.routlier});
+ }
+ if (this.lwhisker !== undefined) {
+ result.push({ field: 'lw', value: this.lwhisker});
+ }
+ if (this.rwhisker !== undefined) {
+ result.push({ field: 'rw', value: this.rwhisker});
+ }
+ return result;
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ vlen = values.length,
+ options = this.options,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
+ maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
+ canvasLeft = 0,
+ lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
+ size, unitSize;
+
+ if (!box._super.render.call(this)) {
+ return;
+ }
+
+ if (options.get('raw')) {
+ if (options.get('showOutliers') && values.length > 5) {
+ loutlier = values[0];
+ lwhisker = values[1];
+ q1 = values[2];
+ q2 = values[3];
+ q3 = values[4];
+ rwhisker = values[5];
+ routlier = values[6];
+ } else {
+ lwhisker = values[0];
+ q1 = values[1];
+ q2 = values[2];
+ q3 = values[3];
+ rwhisker = values[4];
+ }
+ } else {
+ values.sort(function (a, b) { return a - b; });
+ q1 = quartile(values, 1);
+ q2 = quartile(values, 2);
+ q3 = quartile(values, 3);
+ iqr = q3 - q1;
+ if (options.get('showOutliers')) {
+ lwhisker = rwhisker = undefined;
+ for (i = 0; i < vlen; i++) {
+ if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
+ lwhisker = values[i];
+ }
+ if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
+ rwhisker = values[i];
+ }
+ }
+ loutlier = values[0];
+ routlier = values[vlen - 1];
+ } else {
+ lwhisker = values[0];
+ rwhisker = values[vlen - 1];
+ }
+ }
+ this.quartiles = [q1, q2, q3];
+ this.lwhisker = lwhisker;
+ this.rwhisker = rwhisker;
+ this.loutlier = loutlier;
+ this.routlier = routlier;
+
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (options.get('showOutliers')) {
+ canvasLeft = Math.ceil(options.get('spotRadius'));
+ canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (loutlier < lwhisker) {
+ target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ if (routlier > rwhisker) {
+ target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ }
+
+ // box
+ target.drawRect(
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q3 - q1) * unitSize),
+ Math.round(canvasHeight * 0.8),
+ options.get('boxLineColor'),
+ options.get('boxFillColor')).append();
+ // left whisker
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // right whisker
+ target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q3 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // median line
+ target.drawLine(
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.9),
+ options.get('medianColor')).append();
+ if (options.get('target')) {
+ size = Math.ceil(options.get('spotRadius'));
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) - size),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) + size),
+ options.get('targetColor')).append();
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
+ Math.round(canvasHeight / 2),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
+ Math.round(canvasHeight / 2),
+ options.get('targetColor')).append();
+ }
+ target.render();
+ }
+ });
+
+ // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
+ // This is accessible as $(foo).simpledraw()
+
+ VShape = createClass({
+ init: function (target, id, type, args) {
+ this.target = target;
+ this.id = id;
+ this.type = type;
+ this.args = args;
+ },
+ append: function () {
+ this.target.appendShape(this);
+ return this;
+ }
+ });
+
+ VCanvas_base = createClass({
+ _pxregex: /(\d+)(px)?\s*$/i,
+
+ init: function (width, height, target) {
+ if (!width) {
+ return;
+ }
+ this.width = width;
+ this.height = height;
+ this.target = target;
+ this.lastShapeId = null;
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ },
+
+ drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {
+ return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
+ },
+
+ drawShape: function (path, lineColor, fillColor, lineWidth) {
+ return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);
+ },
+
+ drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {
+ return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);
+ },
+
+ drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
+ },
+
+ drawRect: function (x, y, width, height, lineColor, fillColor) {
+ return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);
+ },
+
+ getElement: function () {
+ return this.canvas;
+ },
+
+ /**
+ * Return the most recently inserted shape id
+ */
+ getLastShapeId: function () {
+ return this.lastShapeId;
+ },
+
+ /**
+ * Clear and reset the canvas
+ */
+ reset: function () {
+ alert('reset not implemented');
+ },
+
+ _insert: function (el, target) {
+ $(target).html(el);
+ },
+
+ /**
+ * Calculate the pixel dimensions of the canvas
+ */
+ _calculatePixelDims: function (width, height, canvas) {
+ // XXX This should probably be a configurable option
+ var match;
+ match = this._pxregex.exec(height);
+ if (match) {
+ this.pixelHeight = match[1];
+ } else {
+ this.pixelHeight = $(canvas).height();
+ }
+ match = this._pxregex.exec(width);
+ if (match) {
+ this.pixelWidth = match[1];
+ } else {
+ this.pixelWidth = $(canvas).width();
+ }
+ },
+
+ /**
+ * Generate a shape object and id for later rendering
+ */
+ _genShape: function (shapetype, shapeargs) {
+ var id = shapeCount++;
+ shapeargs.unshift(id);
+ return new VShape(this, id, shapetype, shapeargs);
+ },
+
+ /**
+ * Add a shape to the end of the render queue
+ */
+ appendShape: function (shape) {
+ alert('appendShape not implemented');
+ },
+
+ /**
+ * Replace one shape with another
+ */
+ replaceWithShape: function (shapeid, shape) {
+ alert('replaceWithShape not implemented');
+ },
+
+ /**
+ * Insert one shape after another in the render queue
+ */
+ insertAfterShape: function (shapeid, shape) {
+ alert('insertAfterShape not implemented');
+ },
+
+ /**
+ * Remove a shape from the queue
+ */
+ removeShapeId: function (shapeid) {
+ alert('removeShapeId not implemented');
+ },
+
+ /**
+ * Find a shape at the specified x/y co-ordinates
+ */
+ getShapeAt: function (el, x, y) {
+ alert('getShapeAt not implemented');
+ },
+
+ /**
+ * Render all queued shapes onto the canvas
+ */
+ render: function () {
+ alert('render not implemented');
+ }
+ });
+
+ VCanvas_canvas = createClass(VCanvas_base, {
+ init: function (width, height, target, interact) {
+ VCanvas_canvas._super.init.call(this, width, height, target);
+ this.canvas = document.createElement('canvas');
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ this.interact = interact;
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});
+ },
+
+ _getContext: function (lineColor, fillColor, lineWidth) {
+ var context = this.canvas.getContext('2d');
+ if (lineColor !== undefined) {
+ context.strokeStyle = lineColor;
+ }
+ context.lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ if (fillColor !== undefined) {
+ context.fillStyle = fillColor;
+ }
+ return context;
+ },
+
+ reset: function () {
+ var context = this._getContext();
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth),
+ i, plen;
+ context.beginPath();
+ context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
+ for (i = 1, plen = path.length; i < plen; i++) {
+ context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth);
+ context.beginPath();
+ context.arc(x, y, radius, 0, 2 * Math.PI, false);
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var context = this._getContext(lineColor, fillColor);
+ context.beginPath();
+ context.moveTo(x, y);
+ context.arc(x, y, radius, startAngle, endAngle, false);
+ context.lineTo(x, y);
+ context.closePath();
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
+ },
+
+ appendShape: function (shape) {
+ this.shapes[shape.id] = shape;
+ this.shapeseq.push(shape.id);
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ this.shapes[shape.id] = shape;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] == shapeid) {
+ shapeseq[i] = shape.id;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ var shapeseq = this.shapeseq,
+ shapemap = {},
+ sid, i, first;
+
+ for (i = shapeids.length; i--;) {
+ shapemap[shapeids[i]] = true;
+ }
+ for (i = shapeseq.length; i--;) {
+ sid = shapeseq[i];
+ if (shapemap[sid]) {
+ shapeseq.splice(i, 1);
+ delete this.shapes[sid];
+ first = i;
+ }
+ }
+ for (i = shapes.length; i--;) {
+ shapeseq.splice(first, 0, shapes[i].id);
+ this.shapes[shapes[i].id] = shapes[i];
+ }
+
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i + 1, 0, shape.id);
+ this.shapes[shape.id] = shape;
+ return;
+ }
+ }
+ },
+
+ removeShapeId: function (shapeid) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i, 1);
+ break;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ getShapeAt: function (el, x, y) {
+ this.targetX = x;
+ this.targetY = y;
+ this.render();
+ return this.currentTargetShapeId;
+ },
+
+ render: function () {
+ var shapeseq = this.shapeseq,
+ shapes = this.shapes,
+ shapeCount = shapeseq.length,
+ context = this._getContext(),
+ shapeid, shape, i;
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ for (i = 0; i < shapeCount; i++) {
+ shapeid = shapeseq[i];
+ shape = shapes[shapeid];
+ this['_draw' + shape.type].apply(this, shape.args);
+ }
+ if (!this.interact) {
+ // not interactive so no need to keep the shapes array
+ this.shapes = {};
+ this.shapeseq = [];
+ }
+ }
+
+ });
+
+ VCanvas_vml = createClass(VCanvas_base, {
+ init: function (width, height, target) {
+ var groupel;
+ VCanvas_vml._super.init.call(this, width, height, target);
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ this.canvas = document.createElement('span');
+ $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ groupel = '<v:group coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '"' +
+ ' style="position:absolute;top:0;left:0;width:' + this.pixelWidth + 'px;height=' + this.pixelHeight + 'px;"></v:group>';
+ this.canvas.insertAdjacentHTML('beforeEnd', groupel);
+ this.group = $(this.canvas).children()[0];
+ this.rendered = false;
+ this.prerender = '';
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var vpath = [],
+ initial, stroke, fill, closed, vel, plen, i;
+ for (i = 0, plen = path.length; i < plen; i++) {
+ vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);
+ }
+ initial = vpath.splice(0, 1);
+ lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';
+ vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
+ ' path="m ' + initial + ' l ' + vpath.join(', ') + ' ' + closed + 'e">' +
+ ' </v:shape>';
+ return vel;
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var stroke, fill, vel;
+ x -= radius;
+ y -= radius;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '<v:oval ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;top:' + y + 'px; left:' + x + 'px; width:' + (radius * 2) + 'px; height:' + (radius * 2) + 'px"></v:oval>';
+ return vel;
+
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var vpath, startx, starty, endx, endy, stroke, fill, vel;
+ if (startAngle === endAngle) {
+ return ''; // VML seems to have problem when start angle equals end angle.
+ }
+ if ((endAngle - startAngle) === (2 * Math.PI)) {
+ startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0
+ endAngle = (2 * Math.PI);
+ }
+
+ startx = x + Math.round(Math.cos(startAngle) * radius);
+ starty = y + Math.round(Math.sin(startAngle) * radius);
+ endx = x + Math.round(Math.cos(endAngle) * radius);
+ endy = y + Math.round(Math.sin(endAngle) * radius);
+
+ if (startx === endx && starty === endy) {
+ if ((endAngle - startAngle) < Math.PI) {
+ // Prevent very small slices from being mistaken as a whole pie
+ return '';
+ }
+ // essentially going to be the entire circle, so ignore startAngle
+ startx = endx = x + radius;
+ starty = endy = y;
+ }
+
+ if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
+ return '';
+ }
+
+ vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
+ ' path="m ' + x + ',' + y + ' wa ' + vpath.join(', ') + ' x e">' +
+ ' </v:shape>';
+ return vel;
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
+ },
+
+ reset: function () {
+ this.group.innerHTML = '';
+ },
+
+ appendShape: function (shape) {
+ var vel = this['_draw' + shape.type].apply(this, shape.args);
+ if (this.rendered) {
+ this.group.insertAdjacentHTML('beforeEnd', vel);
+ } else {
+ this.prerender += vel;
+ }
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].outerHTML = vel;
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ // replace the first shapeid with all the new shapes then toast the remaining old shapes
+ var existing = $('#jqsshape' + shapeids[0]),
+ replace = '',
+ slen = shapes.length,
+ i;
+ for (i = 0; i < slen; i++) {
+ replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
+ }
+ existing[0].outerHTML = replace;
+ for (i = 1; i < shapeids.length; i++) {
+ $('#jqsshape' + shapeids[i]).remove();
+ }
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].insertAdjacentHTML('afterEnd', vel);
+ },
+
+ removeShapeId: function (shapeid) {
+ var existing = $('#jqsshape' + shapeid);
+ this.group.removeChild(existing[0]);
+ },
+
+ getShapeAt: function (el, x, y) {
+ var shapeid = el.id.substr(8);
+ return shapeid;
+ },
+
+ render: function () {
+ if (!this.rendered) {
+ // batch the intial render into a single repaint
+ this.group.innerHTML = this.prerender;
+ this.rendered = true;
+ }
+ }
+ });
+
+}))}(document, Math)); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js
new file mode 100644
index 00000000..4a16a907
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js
@@ -0,0 +1,1406 @@
+/**
+ * Copyright (C) 2010-2013 Graham Breach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * jQuery.tagcanvas 2.1.2
+ * For more information, please contact <graham@goat1000.com>
+ */
+(function($){
+"use strict";
+var i, j, abs = Math.abs, sin = Math.sin, cos = Math.cos,
+ max = Math.max, min = Math.min, ceil = Math.ceil,
+ hexlookup3 = {}, hexlookup2 = {}, hexlookup1 = {
+ 0:"0,", 1:"17,", 2:"34,", 3:"51,", 4:"68,", 5:"85,",
+ 6:"102,", 7:"119,", 8:"136,", 9:"153,", a:"170,", A:"170,",
+ b:"187,", B:"187,", c:"204,", C:"204,", d:"221,", D:"221,",
+ e:"238,", E:"238,", f:"255,", F:"255,"
+}, Oproto, Tproto, TCproto, doc = document, ocanvas, handlers = {};
+for(i = 0; i < 256; ++i) {
+ j = i.toString(16);
+ if(i < 16)
+ j = '0' + j;
+ hexlookup2[j] = hexlookup2[j.toUpperCase()] = i.toString() + ',';
+}
+function Defined(d) {
+ return typeof(d) != 'undefined';
+}
+function Clamp(v, mn, mx) {
+ return isNaN(v) ? mx : min(mx, max(mn, v));
+}
+function Nop() {
+ return false;
+}
+function SortList(l, f) {
+ var nl = [], tl = l.length, i;
+ for(i = 0; i < tl; ++i)
+ nl.push(l[i]);
+ nl.sort(f);
+ return nl;
+}
+function Shuffle(a) {
+ var i = a.length-1, t, p;
+ while(i) {
+ p = ~~(Math.random()*i);
+ t = a[i];
+ a[i] = a[p];
+ a[p] = t;
+ --i;
+ }
+}
+function Matrix(a) {
+ this[1] = {1: a[0], 2: a[1], 3: a[2], 4: a[3]};
+ this[2] = {1: a[4], 2: a[5], 3: a[6], 4: a[7]};
+ this[3] = {1: a[8], 2: a[9], 3: a[10], 4: a[11]};
+ this[4] = {1: a[12], 2: a[13], 3: a[14], 4: a[15]};
+}
+Matrix.Identity = function() {
+ return new Matrix([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
+}
+Matrix.prototype.mul = function(m) {
+ var a = [], i, j;
+ for(i = 1; i <= 4; ++i)
+ for(j = 1; j <= 4; ++j)
+ a.push(this[i][1] * m[1][j] +
+ this[i][2] * m[2][j] +
+ this[i][3] * m[3][j] +
+ this[i][4] * m[4][j]);
+ return new Matrix(a);
+}
+Matrix.prototype.xform = function(p) {
+ var a = {}, x = p.x, y = p.y, z = p.z, w = Defined(p.w) ? p.w : 1;
+ a.x = x * this[1][1] + y * this[2][1] + z * this[3][1] + w * this[4][1];
+ a.y = x * this[1][2] + y * this[2][2] + z * this[3][2] + w * this[4][2];
+ a.z = x * this[1][3] + y * this[2][3] + z * this[3][3] + w * this[4][3];
+ a.w = x * this[1][4] + y * this[2][4] + z * this[3][4] + w * this[4][4];
+ return a;
+}
+function PointsOnSphere(n,xr,yr,zr) {
+ var i, y, r, phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n;
+ for(i = 0; i < n; ++i) {
+ y = i * off - 1 + (off / 2);
+ r = Math.sqrt(1 - y*y);
+ phi = i * inc;
+ pts.push([cos(phi) * r * xr, y * yr, sin(phi) * r * zr]);
+ }
+ return pts;
+}
+function Cylinder(n,o,xr,yr,zr) {
+ var phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n, i, j, k, l;
+ for(i = 0; i < n; ++i) {
+ j = i * off - 1 + (off / 2);
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function Ring(o, n, xr, yr, zr, j) {
+ var phi, pts = [], inc = Math.PI * 2 / n, i, k, l;
+ for(i = 0; i < n; ++i) {
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function PointsOnCylinderV(n,xr,yr,zr) { return Cylinder(n, 0, xr, yr, zr) }
+function PointsOnCylinderH(n,xr,yr,zr) { return Cylinder(n, 1, xr, yr, zr) }
+function PointsOnRingV(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(0, n, xr, yr, zr, offset);
+}
+function PointsOnRingH(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(1, n, xr, yr, zr, offset);
+}
+function SetAlpha(c,a) {
+ var d = c, p1, p2, ae = (a*1).toPrecision(3) + ')';
+ if(c[0] === '#') {
+ if(!hexlookup3[c])
+ if(c.length === 4)
+ hexlookup3[c] = 'rgba(' + hexlookup1[c[1]] + hexlookup1[c[2]] + hexlookup1[c[3]];
+ else
+ hexlookup3[c] = 'rgba(' + hexlookup2[c.substr(1,2)] + hexlookup2[c.substr(3,2)] + hexlookup2[c.substr(5,2)];
+ d = hexlookup3[c] + ae;
+ } else if(c.substr(0,4) === 'rgb(' || c.substr(0,4) === 'hsl(') {
+ d = (c.replace('(','a(').replace(')', ',' + ae));
+ } else if(c.substr(0,5) === 'rgba(' || c.substr(0,5) === 'hsla(') {
+ p1 = c.lastIndexOf(',') + 1, p2 = c.indexOf(')');
+ a *= parseFloat(c.substring(p1,p2));
+ d = c.substr(0,p1) + a.toPrecision(3) + ')';
+ }
+ return d;
+}
+function NewCanvas(w,h) {
+ // if using excanvas, give up now
+ if(window.G_vmlCanvasManager)
+ return null;
+ var c = doc.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ return c;
+}
+// I think all browsers pass this test now...
+function ShadowAlphaBroken() {
+ var cv = NewCanvas(3,3), c, i;
+ if(!cv)
+ return false;
+ c = cv.getContext('2d');
+ c.strokeStyle = '#000';
+ c.shadowColor = '#fff';
+ c.shadowBlur = 3;
+ c.globalAlpha = 0;
+ c.strokeRect(2,2,2,2);
+ c.globalAlpha = 1;
+ i = c.getImageData(2,2,1,1);
+ cv = null;
+ return (i.data[0] > 0);
+}
+function FindGradientColour(t,p) {
+ var l = 1024, g = t.weightGradient, cv, c, i, gd, d;
+ if(t.gCanvas) {
+ c = t.gCanvas.getContext('2d');
+ } else {
+ t.gCanvas = cv = NewCanvas(l,1);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ gd = c.createLinearGradient(0,0,l,0);
+ for(i in g)
+ gd.addColorStop(1-i, g[i]);
+ c.fillStyle = gd;
+ c.fillRect(0,0,l,1);
+ }
+ d = c.getImageData(~~((l-1)*p),0,1,1).data;
+ return 'rgba(' + d[0] + ',' + d[1] + ',' + d[2] + ',' + (d[3]/255) + ')';
+}
+function TextSet(c,f,l,s,sc,sb,so,wm,wl) {
+ var xo = (sb || 0) + (so && so[0] < 0 ? abs(so[0]) : 0),
+ yo = (sb || 0) + (so && so[1] < 0 ? abs(so[1]) : 0), i, xc;
+ c.font = f;
+ c.textBaseline = 'top';
+ c.fillStyle = l;
+ sc && (c.shadowColor = sc);
+ sb && (c.shadowBlur = sb);
+ so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
+ for(i = 0; i < s.length; ++i) {
+ xc = wl ? (wm - wl[i]) / 2 : 0;
+ c.fillText(s[i], xo + xc, yo);
+ yo += parseInt(f);
+ }
+}
+function TextToCanvas(s,f,ht,w,h,l,sc,sb,so,padx,pady,wmax,wlist) {
+ var cw = w + abs(so[0]) + sb + sb, ch = h + abs(so[1]) + sb + sb, cv, c;
+ cv = NewCanvas(cw+padx,ch+pady);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ TextSet(c,f,l,s,sc,sb,so,wmax,wlist);
+ return cv;
+}
+function AddShadowToImage(i,sc,sb,so) {
+ var sw = abs(so[0]), sh = abs(so[1]),
+ cw = i.width + (sw > sb ? sw + sb : sb * 2),
+ ch = i.height + (sh > sb ? sh + sb : sb * 2),
+ xo = (sb || 0) + (so[0] < 0 ? sw : 0),
+ yo = (sb || 0) + (so[1] < 0 ? sh : 0), cv, c;
+ cv = NewCanvas(cw, ch);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ sc && (c.shadowColor = sc);
+ sb && (c.shadowBlur = sb);
+ so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
+ c.drawImage(i, xo, yo, i.width, i.height);
+ return cv;
+}
+function FindTextBoundingBox(s,f,ht) {
+ var w = parseInt(s.toString().length * ht), h = parseInt(ht * 2 * s.length),
+ cv = NewCanvas(w,h), c, idata, w1, h1, x, y, i, ex;
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ c.fillStyle = '#000';
+ c.fillRect(0,0,w,h);
+ TextSet(c,ht + 'px ' + f,'#fff',s,0,0,[])
+
+ idata = c.getImageData(0,0,w,h);
+ w1 = idata.width; h1 = idata.height;
+ ex = {
+ min: { x: w1, y: h1 },
+ max: { x: -1, y: -1 }
+ };
+ for(y = 0; y < h1; ++y) {
+ for(x = 0; x < w1; ++x) {
+ i = (y * w1 + x) * 4;
+ if(idata.data[i+1] > 0) {
+ if(x < ex.min.x) ex.min.x = x;
+ if(x > ex.max.x) ex.max.x = x;
+ if(y < ex.min.y) ex.min.y = y;
+ if(y > ex.max.y) ex.max.y = y;
+ }
+ }
+ }
+ // device pixels might not be css pixels
+ if(w1 != w) {
+ ex.min.x *= (w / w1);
+ ex.max.x *= (w / w1);
+ }
+ if(h1 != h) {
+ ex.min.y *= (w / h1);
+ ex.max.y *= (w / h1);
+ }
+
+ cv = null;
+ return ex;
+}
+function FixFont(f) {
+ return "'" + f.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
+}
+function AddHandler(h,f,e) {
+ e = e || doc;
+ if(e.addEventListener)
+ e.addEventListener(h,f,false);
+ else
+ e.attachEvent('on' + h, f);
+}
+function AddImage(i, o, t, tc) {
+ var s = tc.imageScale, ic;
+ // image not loaded, wait for image onload
+ if(!o.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, o);
+ if(!i.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, i);
+
+ // Yes, this does look like nonsense, but it makes sure that both the
+ // width and height are actually set and not just calculated. This is
+ // required to keep proportional sizes when the images are hidden, so
+ // the images can be used again for another cloud.
+ o.width = o.width;
+ o.height = o.height;
+
+ if(s) {
+ i.width = o.width * s;
+ i.height = o.height * s;
+ }
+ t.w = i.width;
+ t.h = i.height;
+ if(tc.txtOpt && tc.shadow) {
+ ic = AddShadowToImage(i, tc.shadow, tc.shadowBlur, tc.shadowOffset);
+ if(ic) {
+ t.image = ic;
+ t.w = ic.width;
+ t.h = ic.height;
+ }
+ }
+}
+function GetProperty(e,p) {
+ var dv = doc.defaultView, pc = p.replace(/\-([a-z])/g,function(a){return a.charAt(1).toUpperCase()});
+ return (dv && dv.getComputedStyle && dv.getComputedStyle(e,null).getPropertyValue(p)) ||
+ (e.currentStyle && e.currentStyle[pc]);
+}
+function FindWeight(t,a) {
+ var w = 1, p;
+ if(t.weightFrom) {
+ w = 1 * (a.getAttribute(t.weightFrom) || t.textHeight);
+ } else if(p = GetProperty(a,'font-size')) {
+ w = (p.indexOf('px') > -1 && p.replace('px','') * 1) ||
+ (p.indexOf('pt') > -1 && p.replace('pt','') * 1.25) ||
+ p * 3.3;
+ } else {
+ t.weight = false;
+ }
+ return w;
+}
+function EventToCanvasId(e) {
+ return e.target && Defined(e.target.id) ? e.target.id :
+ e.srcElement.parentNode.id;
+}
+function EventXY(e, c) {
+ var xy, p, xmul = parseInt(GetProperty(c, 'width')) / c.width,
+ ymul = parseInt(GetProperty(c, 'height')) / c.height;
+ if(Defined(e.offsetX)) {
+ xy = {x: e.offsetX, y: e.offsetY};
+ } else {
+ p = AbsPos(c.id);
+ if(Defined(e.changedTouches))
+ e = e.changedTouches[0];
+ if(e.pageX)
+ xy = {x: e.pageX - p.x, y: e.pageY - p.y};
+ }
+ if(xy && xmul && ymul) {
+ xy.x /= xmul;
+ xy.y /= ymul;
+ }
+ return xy;
+}
+function MouseOut(e) {
+ var cv = e.target || e.fromElement.parentNode, tc = TagCanvas.tc[cv.id];
+ if(tc) {
+ tc.mx = tc.my = -1;
+ tc.UnFreeze();
+ tc.EndDrag();
+ }
+}
+function MouseMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ if(tg && t.tc[tg]) {
+ tc = t.tc[tg];
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.Drag(e, p);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseDown(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e);
+ if(tg && e.button == cb && t.tc[tg]) {
+ t.tc[tg].BeginDrag(e);
+ }
+}
+function MouseUp(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e), tc;
+ if(tg && e.button == cb && t.tc[tg]) {
+ tc = t.tc[tg];
+ MouseMove(e);
+ if(!tc.EndDrag() && !tc.touched)
+ tc.Clicked(e);
+ }
+}
+function TouchDown(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && e.changedTouches && t.tc[tg]) {
+ t.tc[tg].touched = 1;
+ t.tc[tg].BeginDrag(e);
+ }
+}
+function TouchUp(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && e.changedTouches && t.tc[tg]) {
+ TouchMove(e);
+ if(!t.tc[tg].EndDrag()){
+ t.tc[tg].Draw();
+ t.tc[tg].Clicked(e);
+ }
+ }
+}
+function TouchMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ if(tg && t.tc[tg] && e.changedTouches) {
+ tc = t.tc[tg];
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.Drag(e, p);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseWheel(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && t.tc[tg]) {
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+ t.tc[tg].Wheel((e.wheelDelta || e.detail) > 0);
+ }
+}
+function DrawCanvas(t) {
+ var tc = TagCanvas.tc, i, interval;
+ t = t || new Date().valueOf();
+ for(i in tc) {
+ interval = tc[i].interval;
+ tc[i].Draw(t);
+ }
+ TagCanvas.NextFrame(interval);
+}
+function AbsPos(id) {
+ var e = doc.getElementById(id), r = e.getBoundingClientRect(),
+ dd = doc.documentElement, b = doc.body, w = window,
+ xs = w.pageXOffset || dd.scrollLeft,
+ ys = w.pageYOffset || dd.scrollTop,
+ xo = dd.clientLeft || b.clientLeft,
+ yo = dd.clientTop || b.clientTop;
+ return { x: r.left + xs - xo, y: r.top + ys - yo };
+}
+function Project(tc,p1,sx,sy) {
+ var m = tc.radius * tc.z1 / (tc.z1 + tc.z2 + p1.z);
+ return {
+ x: p1.x * m * sx,
+ y: p1.y * m * sy,
+ z: p1.z,
+ w: (tc.z1 - p1.z) / tc.z2
+ };
+}
+/**
+ * @constructor
+ * for recursively splitting tag contents on <br> tags
+ */
+function TextSplitter(e) {
+ this.e = e;
+ this.br = 0;
+ this.line = [];
+ this.text = [];
+ this.original = e.innerText || e.textContent;
+};
+TextSplitter.prototype.Lines = function(e) {
+ var r = e ? 1 : 0, cn, cl, i;
+ e = e || this.e;
+ cn = e.childNodes;
+ cl = cn.length;
+
+ for(i = 0; i < cl; ++i) {
+ if(cn[i].nodeName == 'BR') {
+ this.text.push(this.line.join(' '));
+ this.br = 1;
+ } else if(cn[i].nodeType == 3) {
+ if(this.br) {
+ this.line = [cn[i].nodeValue];
+ this.br = 0;
+ } else {
+ this.line.push(cn[i].nodeValue);
+ }
+ } else {
+ this.Lines(cn[i]);
+ }
+ }
+ r || this.br || this.text.push(this.line.join(' '));
+ return this.text;
+}
+TextSplitter.prototype.SplitWidth = function(w, c, f, h) {
+ var i, j, words, text = [];
+ c.font = h + 'px ' + f;
+ for(i = 0; i < this.text.length; ++i) {
+ words = this.text[i].split(/\s+/);
+ this.line = [words[0]];
+ for(j = 1; j < words.length; ++j) {
+ if(c.measureText(this.line.join(' ') + ' ' + words[j]).width > w) {
+ text.push(this.line.join(' '));
+ this.line = [words[j]];
+ } else {
+ this.line.push(words[j]);
+ }
+ }
+ text.push(this.line.join(' '));
+ }
+ return this.text = text;
+}
+/**
+ * @constructor
+ */
+function Outline(tc) {
+ this.ts = new Date().valueOf();
+ this.tc = tc;
+ this.x = this.y = this.w = this.h = this.sc = 1;
+ this.z = 0;
+ this.Draw = tc.pulsateTo < 1 && tc.outlineMethod != 'colour' ? this.DrawPulsate : this.DrawSimple;
+ this.SetMethod(tc.outlineMethod);
+}
+Oproto = Outline.prototype;
+Oproto.SetMethod = function(om) {
+ var methods = {
+ block: ['PreDraw','DrawBlock'],
+ colour: ['PreDraw','DrawColour'],
+ outline: ['PostDraw','DrawOutline'],
+ classic: ['LastDraw','DrawOutline'],
+ none: ['LastDraw']
+ }, funcs = methods[om] || methods.outline;
+ if(om == 'none') {
+ this.Draw = function() { return 1; }
+ } else {
+ this.drawFunc = this[funcs[1]];
+ }
+ this[funcs[0]] = this.Draw;
+};
+Oproto.Update = function(x,y,w,h,sc,z,xo,yo) {
+ var o = this.tc.outlineOffset, o2 = 2 * o;
+ this.x = sc * x + xo - o;
+ this.y = sc * y + yo - o;
+ this.w = sc * w + o2;
+ this.h = sc * h + o2;
+ this.sc = sc; // used to determine frontmost
+ this.z = z;
+};
+Oproto.DrawOutline = function(c,x,y,w,h,colour) {
+ c.strokeStyle = colour;
+ c.strokeRect(x,y,w,h);
+};
+Oproto.DrawColour = function(c,x,y,w,h,colour,tag,x1,y1) {
+ return this[tag.image ? 'DrawColourImage' : 'DrawColourText'](c,x,y,w,h,colour,tag,x1,y1);
+};
+Oproto.DrawColourText = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var normal = tag.colour;
+ tag.colour = colour;
+ tag.alpha = 1;
+ tag.Draw(c,x1,y1);
+ tag.colour = normal;
+ return 1;
+};
+Oproto.DrawColourImage = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var ccanvas = c.canvas, fx = ~~max(x,0), fy = ~~max(y,0),
+ fw = min(ccanvas.width - fx, w) + .5|0, fh = min(ccanvas.height - fy,h) + .5|0, cc;
+ if(ocanvas)
+ ocanvas.width = fw, ocanvas.height = fh;
+ else
+ ocanvas = NewCanvas(fw, fh);
+ if(!ocanvas)
+ return this.SetMethod('outline'); // if using IE and images, give up!
+ cc = ocanvas.getContext('2d');
+
+ cc.drawImage(ccanvas,fx,fy,fw,fh,0,0,fw,fh);
+ c.clearRect(fx,fy,fw,fh);
+ tag.alpha = 1;
+ tag.Draw(c,x1,y1);
+ c.setTransform(1,0,0,1,0,0);
+ c.save();
+ c.beginPath();
+ c.rect(fx,fy,fw,fh);
+ c.clip();
+ c.globalCompositeOperation = 'source-in';
+ c.fillStyle = colour;
+ c.fillRect(fx,fy,fw,fh);
+ c.restore();
+ c.globalCompositeOperation = 'destination-over';
+ c.drawImage(ocanvas,0,0,fw,fh,fx,fy,fw,fh);
+ c.globalCompositeOperation = 'source-over';
+ return 1;
+};
+Oproto.DrawBlock = function(c,x,y,w,h,colour) {
+ c.fillStyle = colour;
+ c.fillRect(x,y,w,h);
+};
+Oproto.DrawSimple = function(c, tag, x1, y1) {
+ var t = this.tc;
+ c.setTransform(1,0,0,1,0,0);
+ c.strokeStyle = t.outlineColour;
+ c.lineWidth = t.outlineThickness;
+ c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
+ c.globalAlpha = 1;
+ return this.drawFunc(c,this.x,this.y,this.w,this.h,t.outlineColour,tag,x1,y1);
+};
+Oproto.DrawPulsate = function(c, tag, x1, y1) {
+ var diff = new Date().valueOf() - this.ts, t = this.tc;
+ c.setTransform(1,0,0,1,0,0);
+ c.strokeStyle = t.outlineColour;
+ c.lineWidth = t.outlineThickness;
+ c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
+ c.globalAlpha = t.pulsateTo + ((1 - t.pulsateTo) *
+ (0.5 + (cos(2 * Math.PI * diff / (1000 * t.pulsateTime)) / 2)));
+ return this.drawFunc(c,this.x,this.y,this.w,this.h,t.outlineColour,tag,x1,y1);
+};
+Oproto.Active = function(c,x,y) {
+ return (x >= this.x && y >= this.y &&
+ x <= this.x + this.w && y <= this.y + this.h);
+};
+Oproto.PreDraw = Oproto.PostDraw = Oproto.LastDraw = Nop;
+/**
+ * @constructor
+ */
+function Tag(tc,text,a,v,w,h,col,font,original) {
+ var c = tc.ctxt;
+ this.tc = tc;
+ this.image = text.src ? text : null;
+ this.text = text.src ? [] : text;
+ this.text_original = original;
+ this.line_widths = [];
+ this.title = a.title || null;
+ this.a = a;
+ this.position = { x: v[0], y: v[1], z: v[2] };
+ this.x = this.y = this.z = 0;
+ this.w = w;
+ this.h = h;
+ this.colour = col || tc.textColour;
+ this.textFont = font || tc.textFont;
+ this.weight = this.sc = this.alpha = 1;
+ this.weighted = !tc.weight;
+ this.outline = new Outline(tc);
+ if(!this.image) {
+ this.textHeight = tc.textHeight;
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+ this.Measure(c,tc);
+ }
+ this.SetShadowColour = tc.shadowAlpha ? this.SetShadowColourAlpha : this.SetShadowColourFixed;
+ this.SetDraw(tc);
+}
+Tproto = Tag.prototype;
+Tproto.EqualTo = function(e) {
+ var i = e.getElementsByTagName('img');
+ if(this.a.href != e.href)
+ return 0;
+ if(i.length)
+ return this.image.src == i[0].src;
+ return (e.innerText || e.textContent) == this.text_original;
+};
+Tproto.SetDraw = function(t) {
+ this.Draw = this.image ? (t.ie > 7 ? this.DrawImageIE : this.DrawImage) : this.DrawText;
+ t.noSelect && (this.CheckActive = Nop);
+};
+Tproto.MeasureText = function(c) {
+ var i, l = this.text.length, w = 0, wl;
+ for(i = 0; i < l; ++i) {
+ this.line_widths[i] = wl = c.measureText(this.text[i]).width;
+ w = max(w, wl);
+ }
+ return w;
+};
+Tproto.Measure = function(c,t) {
+ this.h = this.extents ? this.extents.max.y + this.extents.min.y : this.textHeight;
+ c.font = this.font = this.textHeight + 'px ' + this.textFont;
+ this.w = this.MeasureText(c);
+ if(t.txtOpt) {
+ var s = t.txtScale, th = s * this.textHeight, f = th + 'px ' + this.textFont,
+ soff = [s*t.shadowOffset[0],s*t.shadowOffset[1]], cw;
+ c.font = f;
+ cw = this.MeasureText(c);
+ this.image = TextToCanvas(this.text, f, th, cw, s * this.h, this.colour,
+ t.shadow, s * t.shadowBlur, soff, s, s, cw, this.line_widths);
+ if(this.image) {
+ this.w = this.image.width / s;
+ this.h = this.image.height / s;
+ }
+ this.SetDraw(t);
+ t.txtOpt = !!this.image;
+ }
+};
+Tproto.SetFont = function(f, c) {
+ this.textFont = f;
+ this.colour = c;
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+ this.Measure(this.tc.ctxt, this.tc);
+};
+Tproto.SetWeight = function(w) {
+ if(!this.text.length)
+ return;
+ this.weight = w;
+ this.Weight(this.tc.ctxt, this.tc);
+ this.Measure(this.tc.ctxt, this.tc);
+};
+Tproto.Weight = function(c,t) {
+ var w = this.weight, m = t.weightMode;
+ this.weighted = true;
+ if(m == 'colour' || m == 'both')
+ this.colour = FindGradientColour(t, (w - t.min_weight) / (t.max_weight-t.min_weight));
+ if(m == 'size' || m == 'both') {
+ if(t.weightSizeMin > 0 && t.weightSizeMax > t.weightSizeMin) {
+ this.textHeight = t.weightSize *
+ (t.weightSizeMin + (t.weightSizeMax - t.weightSizeMin) *
+ (w - t.min_weight) / (t.max_weight - t.min_weight));
+ } else {
+ this.textHeight = w * t.weightSize;
+ }
+ }
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+};
+Tproto.SetShadowColourFixed = function(c,s,a) {
+ c.shadowColor = s;
+};
+Tproto.SetShadowColourAlpha = function(c,s,a) {
+ c.shadowColor = SetAlpha(s, a);
+};
+Tproto.DrawText = function(c,xoff,yoff) {
+ var t = this.tc, x = this.x, y = this.y, s = this.sc, i, xl;
+ c.globalAlpha = this.alpha;
+ c.fillStyle = this.colour;
+ t.shadow && this.SetShadowColour(c,t.shadow,this.alpha);
+ c.font = this.font;
+ x += xoff / s;
+ y += (yoff / s) - (this.h / 2);
+ for(i = 0; i < this.text.length; ++i) {
+ xl = x - (this.line_widths[i] / 2);
+ c.setTransform(s, 0, 0, s, s * xl, s * y);
+ c.fillText(this.text[i], 0, 0);
+ y += this.textHeight;
+ }
+};
+Tproto.DrawImage = function(c,xoff,yoff) {
+ var x = this.x, y = this.y, s = this.sc,
+ i = this.image, w = this.w, h = this.h, a = this.alpha,
+ shadow = this.shadow;
+ c.globalAlpha = a;
+ shadow && this.SetShadowColour(c,shadow,a);
+ x += (xoff / s) - (w / 2);
+ y += (yoff / s) - (h / 2);
+ c.setTransform(s, 0, 0, s, s * x, s * y);
+ c.drawImage(i, 0, 0, w, h);
+};
+Tproto.DrawImageIE = function(c,xoff,yoff) {
+ var i = this.image, s = this.sc,
+ w = i.width = this.w*s, h = i.height = this.h * s,
+ x = (this.x*s) + xoff - (w/2), y = (this.y*s) + yoff - (h/2);
+ c.setTransform(1,0,0,1,0,0);
+ c.globalAlpha = this.alpha;
+ c.drawImage(i, x, y);
+};
+Tproto.Calc = function(m) {
+ var pp, t = this.tc, mnb = t.minBrightness,
+ mxb = t.maxBrightness, r = t.max_radius;
+ pp = m.xform(this.position);
+ pp = Project(t, pp, t.stretchX, t.stretchY);
+ this.x = pp.x;
+ this.y = pp.y;
+ this.z = pp.z;
+ this.sc = pp.w;
+ this.alpha = Clamp(mnb + (mxb - mnb) * (r - this.z) / (2 * r), 0, 1);
+};
+Tproto.CheckActive = function(c,xoff,yoff) {
+ var t = this.tc, o = this.outline,
+ w = this.w, h = this.h,
+ x = this.x - w/2, y = this.y - h/2;
+ o.Update(x, y, w, h, this.sc, this.z, xoff, yoff);
+ return o.Active(c, t.mx, t.my) ? o : null;
+};
+Tproto.Clicked = function(e) {
+ var a = this.a, t = a.target, h = a.href, evt;
+ if(t != '' && t != '_self') {
+ if(self.frames[t]) {
+ self.frames[t].document.location = h;
+ } else{
+ try {
+ if(top.frames[t]) {
+ top.frames[t].document.location = h;
+ return;
+ }
+ } catch(err) {
+ // different domain/port/protocol?
+ }
+ window.open(h, t);
+ }
+ return;
+ }
+ if(doc.createEvent) {
+ evt = doc.createEvent('MouseEvents');
+ evt.initMouseEvent('click', 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
+ if(!a.dispatchEvent(evt))
+ return;
+ } else if(a.fireEvent) {
+ if(!a.fireEvent('onclick'))
+ return;
+ }
+ doc.location = h;
+};
+/**
+ * @constructor
+ */
+function TagCanvas(cid,lctr,opt) {
+ var i, p, c = doc.getElementById(cid), cp = ['id','class','innerHTML'];
+
+ if(!c) throw 0;
+ if(Defined(window.G_vmlCanvasManager)) {
+ c = window.G_vmlCanvasManager.initElement(c);
+ this.ie = parseFloat(navigator.appVersion.split('MSIE')[1]);
+ }
+ if(c && (!c.getContext || !c.getContext('2d').fillText)) {
+ p = doc.createElement('DIV');
+ for(i = 0; i < cp.length; ++i)
+ p[cp[i]] = c[cp[i]];
+ c.parentNode.insertBefore(p,c);
+ c.parentNode.removeChild(c);
+ throw 0;
+ }
+ for(i in TagCanvas.options)
+ this[i] = opt && Defined(opt[i]) ? opt[i] :
+ (Defined(TagCanvas[i]) ? TagCanvas[i] : TagCanvas.options[i]);
+
+ this.canvas = c;
+ this.ctxt = c.getContext('2d');
+ this.z1 = 250 / this.depth;
+ this.z2 = this.z1 / this.zoom;
+ this.radius = min(c.height, c.width) * 0.0075; // fits radius of 100 in canvas
+ this.max_weight = 0;
+ this.min_weight = 200;
+ this.textFont = this.textFont && FixFont(this.textFont);
+ this.textHeight *= 1;
+ this.pulsateTo = Clamp(this.pulsateTo, 0, 1);
+ this.minBrightness = Clamp(this.minBrightness, 0, 1);
+ this.maxBrightness = Clamp(this.maxBrightness, this.minBrightness, 1);
+ this.ctxt.textBaseline = 'top';
+ this.lx = (this.lock + '').indexOf('x') + 1;
+ this.ly = (this.lock + '').indexOf('y') + 1;
+ this.frozen = 0;
+ this.dx = this.dy = 0;
+ this.touched = 0;
+ this.source = lctr || cid;
+ this.transform = Matrix.Identity();
+ this.time = new Date().valueOf();
+ this.Animate = this.dragControl ? this.AnimateDrag : this.AnimatePosition;
+ if(this.shadowBlur || this.shadowOffset[0] || this.shadowOffset[1]) {
+ // let the browser translate "red" into "#ff0000"
+ this.ctxt.shadowColor = this.shadow;
+ this.shadow = this.ctxt.shadowColor;
+ this.shadowAlpha = ShadowAlphaBroken();
+ } else {
+ delete this.shadow;
+ }
+ this.Load();
+ if(lctr && this.hideTags) {
+ (function(t) {
+ if(TagCanvas.loaded)
+ t.HideTags();
+ else
+ AddHandler('load', function() { t.HideTags(); }, window);
+ })(this);
+ }
+
+ this.yaw = this.initial ? this.initial[0] * this.maxSpeed : 0;
+ this.pitch = this.initial ? this.initial[1] * this.maxSpeed : 0;
+ if(this.tooltip) {
+ if(this.tooltip == 'native') {
+ this.Tooltip = this.TooltipNative;
+ } else {
+ this.Tooltip = this.TooltipDiv;
+ if(!this.ttdiv) {
+ this.ttdiv = doc.createElement('div');
+ this.ttdiv.className = this.tooltipClass;
+ this.ttdiv.style.position = 'absolute';
+ this.ttdiv.style.zIndex = c.style.zIndex + 1;
+ AddHandler('mouseover',function(e){e.target.style.display='none';},this.ttdiv);
+ doc.body.appendChild(this.ttdiv);
+ }
+ }
+ } else {
+ this.Tooltip = this.TooltipNone;
+ }
+ if(!this.noMouse && !handlers[cid]) {
+ AddHandler('mousemove', MouseMove, c);
+ AddHandler('mouseout', MouseOut, c);
+ AddHandler('mouseup', MouseUp, c);
+ AddHandler('touchstart', TouchDown, c);
+ AddHandler('touchend', TouchUp, c);
+ AddHandler('touchcancel', TouchUp, c);
+ AddHandler('touchmove', TouchMove, c);
+ if(this.dragControl) {
+ AddHandler('mousedown', MouseDown, c);
+ AddHandler('selectstart', Nop, c);
+ }
+ if(this.wheelZoom) {
+ AddHandler('mousewheel', MouseWheel, c);
+ AddHandler('DOMMouseScroll', MouseWheel, c);
+ }
+ handlers[cid] = 1;
+ }
+ TagCanvas.started || (TagCanvas.started = setTimeout(DrawCanvas, this.interval));
+}
+TCproto = TagCanvas.prototype;
+TCproto.SourceElements = function() {
+ if(doc.querySelectorAll)
+ return doc.querySelectorAll('#' + this.source);
+ return [doc.getElementById(this.source)];
+};
+TCproto.HideTags = function() {
+ var el = this.SourceElements(), i;
+ for(i = 0; i < el.length; ++i)
+ el[i].style.display = 'none';
+};
+TCproto.GetTags = function() {
+ var el = this.SourceElements(), etl, tl = [], i, j;
+ for(i = 0; i < el.length; ++i) {
+ etl = el[i].getElementsByTagName('a');
+ for(j = 0; j < etl.length; ++j) {
+ tl.push(etl[j]);
+ }
+ }
+ return tl;
+};
+TCproto.CreateTag = function(e, p) {
+ var im = e.getElementsByTagName('img'), i, t, ts, font;
+ p = p || [0, 0, 0];
+ if(im.length) {
+ i = new Image;
+ i.src = im[0].src;
+ t = new Tag(this, i, e, p, 0, 0);
+ AddImage(i, im[0], t, this);
+ return t;
+ }
+ ts = new TextSplitter(e);
+ t = ts.Lines();
+ font = this.textFont || FixFont(GetProperty(e,'font-family'));
+ if(this.splitWidth)
+ t = ts.SplitWidth(this.splitWidth, this.ctxt, font, this.textHeight);
+
+ return new Tag(this, t, e, p, 2, this.textHeight + 2,
+ this.textColour || GetProperty(e,'color'), font, ts.original);
+};
+TCproto.UpdateTag = function(t, a) {
+ var colour = this.textColour || GetProperty(a, 'color'),
+ font = this.textFont || FixFont(GetProperty(a, 'font-family'));
+ t.title = a.title;
+ if(t.colour != colour || t.textFont != font)
+ t.SetFont(font, colour);
+};
+TCproto.Weight = function(tl) {
+ var l = tl.length, w, i, weights = [];
+ for(i = 0; i < l; ++i) {
+ w = FindWeight(this, tl[i].a);
+ if(w > this.max_weight) this.max_weight = w;
+ if(w < this.min_weight) this.min_weight = w;
+ weights.push(w);
+ }
+ if(this.max_weight > this.min_weight) {
+ for(i = 0; i < l; ++i) {
+ tl[i].SetWeight(weights[i]);
+ }
+ }
+};
+TCproto.Load = function() {
+ var tl = this.GetTags(), taglist = [], shape,
+ shapeArgs, rx, ry, rz, vl, i, tagmap = [], pfuncs = {
+ sphere: PointsOnSphere,
+ vcylinder: PointsOnCylinderV,
+ hcylinder: PointsOnCylinderH,
+ vring: PointsOnRingV,
+ hring: PointsOnRingH
+ };
+
+ if(tl.length) {
+ tagmap.length = tl.length;
+ for(i = 0; i < tl.length; ++i)
+ tagmap[i] = i;
+ this.shuffleTags && Shuffle(tagmap);
+ rx = 100 * this.radiusX;
+ ry = 100 * this.radiusY;
+ rz = 100 * this.radiusZ;
+ this.max_radius = max(rx, max(ry, rz));
+
+ if(this.shapeArgs) {
+ this.shapeArgs[0] = tl.length;
+ } else {
+ shapeArgs = this.shape.toString().split(/[(),]/);
+ shape = shapeArgs.shift();
+ this.shape = pfuncs[shape] || pfuncs.sphere;
+ this.shapeArgs = [tl.length, rx, ry, rz].concat(shapeArgs);
+ }
+ vl = this.shape.apply(this, this.shapeArgs);
+ this.listLength = tl.length;
+ for(i = 0; i < tl.length; ++i) {
+ taglist.push(this.CreateTag(tl[tagmap[i]], vl[i]));
+ }
+ this.weight && this.Weight(taglist, true);
+ }
+ this.taglist = taglist;
+};
+TCproto.Update = function() {
+ var tl = this.GetTags(), newlist = [],
+ taglist = this.taglist, found,
+ added = [], removed = [], vl, ol, nl, i, j;
+
+ if(!this.shapeArgs)
+ return this.Load();
+
+ if(tl.length) {
+ nl = this.listLength = tl.length;
+ ol = taglist.length;
+
+ // copy existing list, populate "removed"
+ for(i = 0; i < ol; ++i) {
+ newlist.push(taglist[i]);
+ removed.push(i);
+ }
+
+ // find added and removed tags
+ for(i = 0; i < nl; ++i) {
+ for(j = 0, found = 0; j < ol; ++j) {
+ if(taglist[j].EqualTo(tl[i])) {
+ this.UpdateTag(newlist[j], tl[i]);
+ found = removed[j] = -1;
+ }
+ }
+ if(!found)
+ added.push(i);
+ }
+
+ // clean out found tags from removed list
+ for(i = 0, j = 0; i < ol; ++i) {
+ if(removed[j] == -1)
+ removed.splice(j,1);
+ else
+ ++j;
+ }
+
+ // insert new tags in gaps where old tags removed
+ if(removed.length) {
+ Shuffle(removed);
+ while(removed.length && added.length) {
+ i = removed.shift();
+ j = added.shift();
+ newlist[i] = this.CreateTag(tl[j]);
+ }
+
+ // remove any more (in reverse order)
+ removed.sort(function(a,b) {return a-b});
+ while(removed.length) {
+ newlist.splice(removed.pop(), 1);
+ }
+ }
+
+ // add any extra tags
+ j = newlist.length / (added.length + 1);
+ i = 0;
+ while(added.length) {
+ newlist.splice(ceil(++i * j), 0, this.CreateTag(tl[added.shift()]));
+ }
+
+ // assign correct positions to tags
+ this.shapeArgs[0] = nl = newlist.length;
+ vl = this.shape.apply(this, this.shapeArgs);
+ for(i = 0; i < nl; ++i)
+ newlist[i].position = { x: vl[i][0], y: vl[i][1], z: vl[i][2] };
+
+ // reweight tags
+ this.weight && this.Weight(newlist);
+ }
+ this.taglist = newlist;
+};
+TCproto.SetShadow = function(c) {
+ c.shadowBlur = this.shadowBlur;
+ c.shadowOffsetX = this.shadowOffset[0];
+ c.shadowOffsetY = this.shadowOffset[1];
+};
+TCproto.Draw = function(t) {
+ if(this.paused)
+ return;
+ var cv = this.canvas, cw = cv.width, ch = cv.height, max_sc = 0,
+ tdelta = (t - this.time) * this.interval / 1000,
+ x = cw / 2 + this.offsetX, y = ch / 2 + this.offsetY, c = this.ctxt,
+ active, a, i, aindex = -1, tl = this.taglist, l = tl.length,
+ frontsel = this.frontSelect, centreDrawn = (this.centreFunc == Nop);
+ this.time = t;
+ if(this.frozen && this.drawn)
+ return this.Animate(cw,ch,tdelta);
+ c.setTransform(1,0,0,1,0,0);
+ this.active = null;
+ for(i = 0; i < l; ++i)
+ tl[i].Calc(this.transform);
+ tl = SortList(tl, function(a,b) {return b.z-a.z});
+
+ for(i = 0; i < l; ++i) {
+ a = this.mx >= 0 && this.my >= 0 && this.taglist[i].CheckActive(c, x, y);
+ if(a && a.sc > max_sc && (!frontsel || a.z <= 0)) {
+ active = a;
+ aindex = i;
+ active.tag = this.taglist[i];
+ max_sc = a.sc;
+ }
+ }
+ this.active = active;
+
+ this.txtOpt || (this.shadow && this.SetShadow(c));
+
+ c.clearRect(0,0,cw,ch);
+ for(i = 0; i < l; ++i) {
+ if(!centreDrawn && tl[i].z <= 0) {
+ // run the centreFunc if the next tag is at the front
+ try { this.centreFunc(c, cw, ch, x, y); }
+ catch(e) {
+ alert(e);
+ // don't run it again
+ this.centreFunc = Nop;
+ }
+ centreDrawn = true;
+ }
+
+ if(!(active && active.tag == tl[i] && active.PreDraw(c, tl[i], x, y)))
+ tl[i].Draw(c, x, y);
+ active && active.tag == tl[i] && active.PostDraw(c);
+ }
+ if(this.freezeActive && active) {
+ this.Freeze();
+ } else {
+ this.UnFreeze();
+ this.drawn = (l == this.listLength);
+ }
+ this.Animate(cw, ch, tdelta);
+ active && active.LastDraw(c);
+ cv.style.cursor = active ? this.activeCursor : '';
+ this.Tooltip(active,this.taglist[aindex]);
+};
+TCproto.TooltipNone = function() { };
+TCproto.TooltipNative = function(active,tag) {
+ this.canvas.title = active && tag.title ? tag.title : '';
+};
+TCproto.TooltipDiv = function(active,tag) {
+ var tc = this, s = tc.ttdiv.style, cid = tc.canvas.id, none = 'none';
+ if(active && tag.title) {
+ if(tag.title != tc.ttdiv.innerHTML)
+ s.display = none;
+ tc.ttdiv.innerHTML = tag.title;
+ tag.title = tc.ttdiv.innerHTML;
+ if(s.display == none && ! tc.tttimer) {
+ tc.tttimer = setTimeout(function() {
+ var p = AbsPos(cid);
+ s.display = 'block';
+ s.left = p.x + tc.mx + 'px';
+ s.top = p.y + tc.my + 24 + 'px';
+ tc.tttimer = null;
+ }, tc.tooltipDelay);
+ }
+ } else {
+ s.display = none;
+ }
+};
+TCproto.Transform = function(tc, p, y) {
+ if(p || y) {
+ var sp = sin(p), cp = cos(p), sy = sin(y), cy = cos(y),
+ ym = new Matrix([cy,0,sy,0, 0,1,0,0, -sy,0,cy,0, 0,0,0,1]),
+ pm = new Matrix([1,0,0,0, 0,cp,-sp,0, 0,sp,cp,0, 0,0,0,1]);
+ tc.transform = tc.transform.mul(ym.mul(pm));
+ }
+};
+TCproto.AnimatePosition = function(w, h, t) {
+ var tc = this, x = tc.mx, y = tc.my, s, r;
+ if(!tc.frozen && x >= 0 && y >= 0 && x < w && y < h) {
+ s = tc.maxSpeed, r = tc.reverse ? -1 : 1;
+ tc.lx || (tc.yaw = r * t * ((s * 2 * x / w) - s));
+ tc.ly || (tc.pitch = r * t * -((s * 2 * y / h) - s));
+ tc.initial = null;
+ } else if(!tc.initial) {
+ if(tc.frozen && !tc.freezeDecel)
+ tc.yaw = tc.pitch = 0;
+ else
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.AnimateDrag = function(w, h, t) {
+ var tc = this, rs = 100 * t * tc.maxSpeed / tc.max_radius / tc.zoom;
+ if(tc.dx || tc.dy) {
+ tc.lx || (tc.yaw = tc.dx * rs / tc.stretchX);
+ tc.ly || (tc.pitch = tc.dy * -rs / tc.stretchY);
+ tc.dx = tc.dy = 0;
+ tc.initial = null;
+ } else if(!tc.initial) {
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.Freeze = function() {
+ if(!this.frozen) {
+ this.preFreeze = [this.yaw, this.pitch];
+ this.frozen = 1;
+ this.drawn = 0;
+ }
+};
+TCproto.UnFreeze = function() {
+ if(this.frozen) {
+ this.yaw = this.preFreeze[0];
+ this.pitch = this.preFreeze[1];
+ this.frozen = 0;
+ }
+};
+TCproto.Decel = function(tc) {
+ var s = tc.minSpeed, ay = abs(tc.yaw), ap = abs(tc.pitch);
+ if(!tc.lx && ay > s)
+ tc.yaw = ay > tc.z0 ? tc.yaw * tc.decel : 0;
+ if(!tc.ly && ap > s)
+ tc.pitch = ap > tc.z0 ? tc.pitch * tc.decel : 0;
+};
+TCproto.Zoom = function(r) {
+ this.z2 = this.z1 * (1/r);
+ this.drawn = 0;
+};
+TCproto.Clicked = function(e) {
+ var a = this.active;
+ try {
+ a && a.tag && a.tag.Clicked(e);
+ } catch(ex) {
+ }
+};
+TCproto.Wheel = function(i) {
+ var z = this.zoom + this.zoomStep * (i ? 1 : -1);
+ this.zoom = min(this.zoomMax,max(this.zoomMin,z));
+ this.Zoom(this.zoom);
+};
+TCproto.BeginDrag = function(e) {
+ this.down = EventXY(e, this.canvas);
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+};
+TCproto.Drag = function(e, p) {
+ if(this.dragControl && this.down) {
+ var t2 = this.dragThreshold * this.dragThreshold,
+ dx = p.x - this.down.x, dy = p.y - this.down.y;
+ if(this.dragging || dx * dx + dy * dy > t2) {
+ this.dx = dx;
+ this.dy = dy;
+ this.dragging = 1;
+ this.down = p;
+ }
+ }
+};
+TCproto.EndDrag = function() {
+ var res = this.dragging;
+ this.dragging = this.down = null;
+ return res;
+};
+TCproto.Pause = function() { this.paused = true; };
+TCproto.Resume = function() { this.paused = false; };
+TagCanvas.Start = function(id,l,o) {
+ TagCanvas.tc[id] = new TagCanvas(id,l,o);
+};
+function tccall(f,id) {
+ TagCanvas.tc[id] && TagCanvas.tc[id][f]();
+}
+TagCanvas.Pause = function(id) {
+ tccall('Pause',id);
+};
+TagCanvas.Resume = function(id) {
+ tccall('Resume',id);
+};
+TagCanvas.Reload = function(id) {
+ tccall('Load',id);
+};
+TagCanvas.Update = function(id) {
+ tccall('Update',id);
+};
+TagCanvas.NextFrame = function(iv) {
+ var raf = window.requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ TagCanvas.NextFrame = raf ? TagCanvas.NextFrameRAF : TagCanvas.NextFrameTimeout;
+ TagCanvas.NextFrame(iv);
+};
+TagCanvas.NextFrameRAF = function() {
+ requestAnimationFrame(DrawCanvas);
+};
+TagCanvas.NextFrameTimeout = function(iv) {
+ setTimeout(DrawCanvas, iv);
+};
+TagCanvas.tc = {};
+TagCanvas.options = {
+z1: 20000,
+z2: 20000,
+z0: 0.0002,
+freezeActive: false,
+freezeDecel: false,
+activeCursor: 'pointer',
+pulsateTo: 1,
+pulsateTime: 3,
+reverse: false,
+depth: 0.5,
+maxSpeed: 0.05,
+minSpeed: 0,
+decel: 0.95,
+interval: 20,
+minBrightness: 0.1,
+maxBrightness: 1,
+outlineColour: '#ffff99',
+outlineThickness: 2,
+outlineOffset: 5,
+outlineMethod: 'outline',
+textColour: '#ff99ff',
+textHeight: 15,
+textFont: 'Helvetica, Arial, sans-serif',
+shadow: '#000',
+shadowBlur: 0,
+shadowOffset: [0,0],
+initial: null,
+hideTags: true,
+zoom: 1,
+weight: false,
+weightMode: 'size',
+weightFrom: null,
+weightSize: 1,
+weightSizeMin: null,
+weightSizeMax: null,
+weightGradient: {0:'#f00', 0.33:'#ff0', 0.66:'#0f0', 1:'#00f'},
+txtOpt: true,
+txtScale: 2,
+frontSelect: false,
+wheelZoom: true,
+zoomMin: 0.3,
+zoomMax: 3,
+zoomStep: 0.05,
+shape: 'sphere',
+lock: null,
+tooltip: null,
+tooltipDelay: 300,
+tooltipClass: 'tctooltip',
+radiusX: 1,
+radiusY: 1,
+radiusZ: 1,
+stretchX: 1,
+stretchY: 1,
+offsetX: 0,
+offsetY: 0,
+shuffleTags: false,
+noSelect: false,
+noMouse: false,
+imageScale: 1,
+paused: false,
+dragControl: false,
+dragThreshold: 4,
+centreFunc: Nop,
+splitWidth: 0
+};
+for(i in TagCanvas.options) TagCanvas[i] = TagCanvas.options[i];
+window.TagCanvas = TagCanvas;
+jQuery.fn.tagcanvas = function(options, lctr) {
+ var fn = {
+ pause: function() {
+ $(this).each(function() {
+ tccall('Pause',$(this)[0].id);
+ });
+ },
+ resume: function() {
+ $(this).each(function() {
+ tccall('Resume',$(this)[0].id);
+ });
+ },
+ reload: function() {
+ $(this).each(function() {
+ tccall('Reload',$(this)[0].id);
+ });
+ },
+ update: function() {
+ $(this).each(function() {
+ tccall('Update',$(this)[0].id);
+ });
+ },
+ };
+ if(typeof(options) == 'string' && fn[options]) {
+ fn[options].apply(this);
+ } else {
+ TagCanvas.jquery = 1;
+ $(this).each(function() {
+ TagCanvas.Start($(this)[0].id, lctr, options);
+ });
+ return TagCanvas.started;
+ }
+};
+
+// set a flag for when the window has loaded
+AddHandler('load',function(){TagCanvas.loaded=1},window);
+})(jQuery); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css
new file mode 100644
index 00000000..8a08e22b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css
@@ -0,0 +1,23 @@
+.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
+.ui-multiselect span.ui-icon { float:right }
+.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
+.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
+
+.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
+.ui-multiselect-header ul { font-size:0.9em }
+.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
+.ui-multiselect-header a { text-decoration:none }
+.ui-multiselect-header a:hover { text-decoration:underline }
+.ui-multiselect-header span.ui-icon { float:left }
+.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
+
+.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left }
+.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:auto }
+.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
+.ui-multiselect-checkboxes label input { position:relative; top:1px }
+.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
+
+/* remove label borders in IE6 because IE6 does not support transparency */
+* html .ui-multiselect-checkboxes label { border:none }
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css
new file mode 100644
index 00000000..f8c323a7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css
@@ -0,0 +1,3 @@
+.ui-multiselect-hasfilter ul { position:relative; top:2px }
+.ui-multiselect-filter { float:left; margin-right:10px; font-size:11px }
+.ui-multiselect-filter input { width:100px; font-size:10px; margin-left:5px; height:15px; padding:2px; border:1px solid #292929; -webkit-appearance:textfield; -webkit-box-sizing:content-box; }
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js
new file mode 100644
index 00000000..88e04b93
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js
@@ -0,0 +1,172 @@
+/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
+/*
+ * jQuery MultiSelect UI Widget Filtering Plugin 1.5pre
+ * Copyright (c) 2012 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
+ *
+ * Depends:
+ * - jQuery UI MultiSelect widget
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function($) {
+ var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g;
+
+ $.widget('ech.multiselectfilter', {
+
+ options: {
+ label: 'Filter:',
+ width: null, /* override default width set in css file (px). null will inherit */
+ placeholder: 'Enter keywords',
+ autoReset: false
+ },
+
+ _create: function() {
+ var opts = this.options;
+
+ // get the multiselect instance
+ var instance = (this.instance = $(this.element).data('multiselect'));
+
+ // store header; add filter class so the close/check all/uncheck all links can be positioned correctly
+ var header = (this.header = instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter'));
+
+ // wrapper elem
+ var wrapper = (this.wrapper = $('<div class="ui-multiselect-filter">' + (opts.label.length ? opts.label : '') + '<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"' : '') + ' /></div>').prependTo(this.header));
+
+ // reference to the actual inputs
+ this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');
+
+ // build the input box
+ this.input = wrapper.find('input').bind({
+ keydown: function(e) {
+ // prevent the enter key from submitting the form / closing the widget
+ if(e.which === 13) {
+ e.preventDefault();
+ }
+ },
+ keyup: $.proxy(this._handler, this),
+ click: $.proxy(this._handler, this)
+ });
+
+ // cache input values for searching
+ this.updateCache();
+
+ // rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
+ // only the currently filtered elements are checked
+ instance._toggleChecked = function(flag, group) {
+ var $inputs = (group && group.length) ? group : this.labels.find('input');
+
+ // do not include hidden elems if the menu isn't open.
+ var selector = instance._isOpen ? ':disabled, :hidden' : ':disabled';
+
+ $inputs = $inputs
+ .not(selector)
+ .each(this._toggleState('checked', flag));
+
+ // update text
+ this.update();
+
+ // gather an array of the values that actually changed
+ var values = $inputs.map(function() {
+ return this.value;
+ }).get();
+
+ // select option tags
+ this.element.find('option').filter(function() {
+ if(!this.disabled && $.inArray(this.value, values) > -1) {
+ _self._toggleState('selected', flag).call(this);
+ }
+ });
+
+ // trigger the change event on the select
+ if($inputs.length) {
+ this.element.trigger('change');
+ }
+ };
+
+ // rebuild cache when multiselect is updated
+ var doc = $(document).bind('multiselectrefresh', $.proxy(function() {
+ this.updateCache();
+ this._handler();
+ }, this));
+
+ // automatically reset the widget on close?
+ if(this.options.autoReset) {
+ doc.bind('multiselectclose', $.proxy(this._reset, this));
+ }
+ },
+
+ // thx for the logic here ben alman
+ _handler: function(e) {
+ var term = $.trim(this.input[0].value.toLowerCase()),
+
+ // speed up lookups
+ rows = this.rows, inputs = this.inputs, cache = this.cache;
+
+ if(!term) {
+ rows.show();
+ } else {
+ rows.hide();
+
+ var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');
+
+ this._trigger("filter", e, $.map(cache, function(v, i) {
+ if(v.search(regex) !== -1) {
+ rows.eq(i).show();
+ return inputs.get(i);
+ }
+
+ return null;
+ }));
+ }
+
+ // show/hide optgroups
+ this.instance.menu.find(".ui-multiselect-optgroup-label").each(function() {
+ var $this = $(this);
+ var isVisible = $this.nextUntil('.ui-multiselect-optgroup-label').filter(function() {
+ return $.css(this, "display") !== 'none';
+ }).length;
+
+ $this[isVisible ? 'show' : 'hide']();
+ });
+ },
+
+ _reset: function() {
+ this.input.val('').trigger('keyup');
+ },
+
+ updateCache: function() {
+ // each list item
+ this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");
+
+ // cache
+ this.cache = this.element.children().map(function() {
+ var elem = $(this);
+
+ // account for optgroups
+ if(this.tagName.toLowerCase() === "optgroup") {
+ elem = elem.children();
+ }
+
+ return elem.map(function() {
+ return this.innerHTML.toLowerCase();
+ }).get();
+ }).get();
+ },
+
+ widget: function() {
+ return this.wrapper;
+ },
+
+ destroy: function() {
+ $.Widget.prototype.destroy.call(this);
+ this.input.val('').trigger("keyup");
+ this.wrapper.remove();
+ }
+ });
+
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js
new file mode 100644
index 00000000..a879506b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js
@@ -0,0 +1,727 @@
+/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
+/*
+ * jQuery MultiSelect UI Widget 1.14pre
+ * Copyright (c) 2012 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
+ *
+ * Depends:
+ * - jQuery 1.4.2+
+ * - jQuery UI 1.8 widget factory
+ *
+ * Optional:
+ * - jQuery UI effects
+ * - jQuery UI position utility
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function($, undefined) {
+
+ var multiselectID = 0;
+ var $doc = $(document);
+
+ $.widget("ech.multiselect", {
+
+ // default options
+ options: {
+ header: true,
+ height: 175,
+ minWidth: 225,
+ classes: '',
+ checkAllText: 'Check all',
+ uncheckAllText: 'Uncheck all',
+ noneSelectedText: 'Select options',
+ selectedText: '# selected',
+ selectedList: 0,
+ show: null,
+ hide: null,
+ autoOpen: false,
+ multiple: true,
+ position: {}
+ },
+
+ _create: function() {
+ var el = this.element.hide();
+ var o = this.options;
+
+ this.speed = $.fx.speeds._default; // default speed for effects
+ this._isOpen = false; // assume no
+
+ // create a unique namespace for events that the widget
+ // factory cannot unbind automatically. Use eventNamespace if on
+ // jQuery UI 1.9+, and otherwise fallback to a custom string.
+ this._namespaceID = this.eventNamespace || ('multiselect' + multiselectID);
+
+ var button = (this.button = $('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>'))
+ .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all')
+ .addClass(o.classes)
+ .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') })
+ .insertAfter(el),
+
+ buttonlabel = (this.buttonlabel = $('<span />'))
+ .html(o.noneSelectedText)
+ .appendTo(button),
+
+ menu = (this.menu = $('<div />'))
+ .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all')
+ .addClass(o.classes)
+ .appendTo(document.body),
+
+ header = (this.header = $('<div />'))
+ .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix')
+ .appendTo(menu),
+
+ headerLinkContainer = (this.headerLinkContainer = $('<ul />'))
+ .addClass('ui-helper-reset')
+ .html(function() {
+ if(o.header === true) {
+ return '<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>' + o.checkAllText + '</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>' + o.uncheckAllText + '</span></a></li>';
+ } else if(typeof o.header === "string") {
+ return '<li>' + o.header + '</li>';
+ } else {
+ return '';
+ }
+ })
+ .append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>')
+ .appendTo(header),
+
+ checkboxContainer = (this.checkboxContainer = $('<ul />'))
+ .addClass('ui-multiselect-checkboxes ui-helper-reset')
+ .appendTo(menu);
+
+ // perform event bindings
+ this._bindEvents();
+
+ // build menu
+ this.refresh(true);
+
+ // some addl. logic for single selects
+ if(!o.multiple) {
+ menu.addClass('ui-multiselect-single');
+ }
+
+ // bump unique ID
+ multiselectID++;
+ },
+
+ _init: function() {
+ if(this.options.header === false) {
+ this.header.hide();
+ }
+ if(!this.options.multiple) {
+ this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide();
+ }
+ if(this.options.autoOpen) {
+ this.open();
+ }
+ if(this.element.is(':disabled')) {
+ this.disable();
+ }
+ },
+
+ refresh: function(init) {
+ var el = this.element;
+ var o = this.options;
+ var menu = this.menu;
+ var checkboxContainer = this.checkboxContainer;
+ var optgroups = [];
+ var html = "";
+ var id = el.attr('id') || multiselectID++; // unique ID for the label & option tags
+
+ // build items
+ el.find('option').each(function(i) {
+ var $this = $(this);
+ var parent = this.parentNode;
+ var title = this.innerHTML;
+ var description = this.title;
+ var value = this.value;
+ var inputID = 'ui-multiselect-' + (this.id || id + '-option-' + i);
+ var isDisabled = this.disabled;
+ var isSelected = this.selected;
+ var labelClasses = [ 'ui-corner-all' ];
+ var liClasses = (isDisabled ? 'ui-multiselect-disabled ' : ' ') + this.className;
+ var optLabel;
+
+ // is this an optgroup?
+ if(parent.tagName === 'OPTGROUP') {
+ optLabel = parent.getAttribute('label');
+
+ // has this optgroup been added already?
+ if($.inArray(optLabel, optgroups) === -1) {
+ html += '<li class="ui-multiselect-optgroup-label ' + parent.className + '"><a href="#">' + optLabel + '</a></li>';
+ optgroups.push(optLabel);
+ }
+ }
+
+ if(isDisabled) {
+ labelClasses.push('ui-state-disabled');
+ }
+
+ // browsers automatically select the first option
+ // by default with single selects
+ if(isSelected && !o.multiple) {
+ labelClasses.push('ui-state-active');
+ }
+
+ html += '<li class="' + liClasses + '">';
+
+ // create the label
+ html += '<label for="' + inputID + '" title="' + description + '" class="' + labelClasses.join(' ') + '">';
+ html += '<input id="' + inputID + '" name="multiselect_' + id + '" type="' + (o.multiple ? "checkbox" : "radio") + '" value="' + value + '" title="' + title + '"';
+
+ // pre-selected?
+ if(isSelected) {
+ html += ' checked="checked"';
+ html += ' aria-selected="true"';
+ }
+
+ // disabled?
+ if(isDisabled) {
+ html += ' disabled="disabled"';
+ html += ' aria-disabled="true"';
+ }
+
+ // add the title and close everything off
+ html += ' /><span>' + title + '</span></label></li>';
+ });
+
+ // insert into the DOM
+ checkboxContainer.html(html);
+
+ // cache some moar useful elements
+ this.labels = menu.find('label');
+ this.inputs = this.labels.children('input');
+
+ // set widths
+ this._setButtonWidth();
+ this._setMenuWidth();
+
+ // remember default value
+ this.button[0].defaultValue = this.update();
+
+ // broadcast refresh event; useful for widgets
+ if(!init) {
+ this._trigger('refresh');
+ }
+ },
+
+ // updates the button text. call refresh() to rebuild
+ update: function() {
+ var o = this.options;
+ var $inputs = this.inputs;
+ var $checked = $inputs.filter(':checked');
+ var numChecked = $checked.length;
+ var value;
+
+ if(numChecked === 0) {
+ value = o.noneSelectedText;
+ } else {
+ if($.isFunction(o.selectedText)) {
+ value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get());
+ } else if(/\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList) {
+ value = $checked.map(function() { return $(this).next().html(); }).get().join(', ');
+ } else {
+ value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length);
+ }
+ }
+
+ this._setButtonValue(value);
+
+ return value;
+ },
+
+ // this exists as a separate method so that the developer
+ // can easily override it.
+ _setButtonValue: function(value) {
+ this.buttonlabel.text(value);
+ },
+
+ // binds events
+ _bindEvents: function() {
+ var self = this;
+ var button = this.button;
+
+ function clickHandler() {
+ self[ self._isOpen ? 'close' : 'open' ]();
+ return false;
+ }
+
+ // webkit doesn't like it when you click on the span :(
+ button
+ .find('span')
+ .bind('click.multiselect', clickHandler);
+
+ // button events
+ button.bind({
+ click: clickHandler,
+ keypress: function(e) {
+ switch(e.which) {
+ case 27: // esc
+ case 38: // up
+ case 37: // left
+ self.close();
+ break;
+ case 39: // right
+ case 40: // down
+ self.open();
+ break;
+ }
+ },
+ mouseenter: function() {
+ if(!button.hasClass('ui-state-disabled')) {
+ $(this).addClass('ui-state-hover');
+ }
+ },
+ mouseleave: function() {
+ $(this).removeClass('ui-state-hover');
+ },
+ focus: function() {
+ if(!button.hasClass('ui-state-disabled')) {
+ $(this).addClass('ui-state-focus');
+ }
+ },
+ blur: function() {
+ $(this).removeClass('ui-state-focus');
+ }
+ });
+
+ // header links
+ this.header.delegate('a', 'click.multiselect', function(e) {
+ // close link
+ if($(this).hasClass('ui-multiselect-close')) {
+ self.close();
+
+ // check all / uncheck all
+ } else {
+ self[$(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll']();
+ }
+
+ e.preventDefault();
+ });
+
+ // optgroup label toggle support
+ this.menu.delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function(e) {
+ e.preventDefault();
+
+ var $this = $(this);
+ var $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)');
+ var nodes = $inputs.get();
+ var label = $this.parent().text();
+
+ // trigger event and bail if the return is false
+ if(self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false) {
+ return;
+ }
+
+ // toggle inputs
+ self._toggleChecked(
+ $inputs.filter(':checked').length !== $inputs.length,
+ $inputs
+ );
+
+ self._trigger('optgrouptoggle', e, {
+ inputs: nodes,
+ label: label,
+ checked: nodes[0].checked
+ });
+ })
+ .delegate('label', 'mouseenter.multiselect', function() {
+ if(!$(this).hasClass('ui-state-disabled')) {
+ self.labels.removeClass('ui-state-hover');
+ $(this).addClass('ui-state-hover').find('input').focus();
+ }
+ })
+ .delegate('label', 'keydown.multiselect', function(e) {
+ e.preventDefault();
+
+ switch(e.which) {
+ case 9: // tab
+ case 27: // esc
+ self.close();
+ break;
+ case 38: // up
+ case 40: // down
+ case 37: // left
+ case 39: // right
+ self._traverse(e.which, this);
+ break;
+ case 13: // enter
+ $(this).find('input')[0].click();
+ break;
+ }
+ })
+ .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function(e) {
+ var $this = $(this);
+ var val = this.value;
+ var checked = this.checked;
+ var tags = self.element.find('option');
+
+ // bail if this input is disabled or the event is cancelled
+ if(this.disabled || self._trigger('click', e, { value: val, text: this.title, checked: checked }) === false) {
+ e.preventDefault();
+ return;
+ }
+
+ // make sure the input has focus. otherwise, the esc key
+ // won't close the menu after clicking an item.
+ $this.focus();
+
+ // toggle aria state
+ $this.attr('aria-selected', checked);
+
+ // change state on the original option tags
+ tags.each(function() {
+ if(this.value === val) {
+ this.selected = checked;
+ } else if(!self.options.multiple) {
+ this.selected = false;
+ }
+ });
+
+ // some additional single select-specific logic
+ if(!self.options.multiple) {
+ self.labels.removeClass('ui-state-active');
+ $this.closest('label').toggleClass('ui-state-active', checked);
+
+ // close menu
+ self.close();
+ }
+
+ // fire change on the select box
+ self.element.trigger("change");
+
+ // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827
+ // http://bugs.jquery.com/ticket/3827
+ setTimeout($.proxy(self.update, self), 10);
+ });
+
+ // close each widget when clicking on any other element/anywhere else on the page
+ $doc.bind('mousedown.' + this._namespaceID, function(e) {
+ if(self._isOpen && !$.contains(self.menu[0], e.target) && !$.contains(self.button[0], e.target) && e.target !== self.button[0]) {
+ self.close();
+ }
+ });
+
+ // deal with form resets. the problem here is that buttons aren't
+ // restored to their defaultValue prop on form reset, and the reset
+ // handler fires before the form is actually reset. delaying it a bit
+ // gives the form inputs time to clear.
+ $(this.element[0].form).bind('reset.multiselect', function() {
+ setTimeout($.proxy(self.refresh, self), 10);
+ });
+ },
+
+ // set button width
+ _setButtonWidth: function() {
+ var width = this.element.outerWidth();
+ var o = this.options;
+
+ if(/\d/.test(o.minWidth) && width < o.minWidth) {
+ width = o.minWidth;
+ }
+
+ // set widths
+ this.button.outerWidth(width);
+ },
+
+ // set menu width
+ _setMenuWidth: function() {
+ var m = this.menu;
+ m.outerWidth(this.button.outerWidth());
+ },
+
+ // move up or down within the menu
+ _traverse: function(which, start) {
+ var $start = $(start);
+ var moveToLast = which === 38 || which === 37;
+
+ // select the first li that isn't an optgroup label / disabled
+ $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)')[ moveToLast ? 'last' : 'first']();
+
+ // if at the first/last element
+ if(!$next.length) {
+ var $container = this.menu.find('ul').last();
+
+ // move to the first/last
+ this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover');
+
+ // set scroll position
+ $container.scrollTop(moveToLast ? $container.height() : 0);
+
+ } else {
+ $next.find('label').trigger('mouseover');
+ }
+ },
+
+ // This is an internal function to toggle the checked property and
+ // other related attributes of a checkbox.
+ //
+ // The context of this function should be a checkbox; do not proxy it.
+ _toggleState: function(prop, flag) {
+ return function() {
+ if(!this.disabled) {
+ this[ prop ] = flag;
+ }
+
+ if(flag) {
+ this.setAttribute('aria-selected', true);
+ } else {
+ this.removeAttribute('aria-selected');
+ }
+ };
+ },
+
+ _toggleChecked: function(flag, group) {
+ var $inputs = (group && group.length) ? group : this.inputs;
+ var self = this;
+
+ // toggle state on inputs
+ $inputs.each(this._toggleState('checked', flag));
+
+ // give the first input focus
+ $inputs.eq(0).focus();
+
+ // update button text
+ this.update();
+
+ // gather an array of the values that actually changed
+ var values = $inputs.map(function() {
+ return this.value;
+ }).get();
+
+ // toggle state on original option tags
+ this.element
+ .find('option')
+ .each(function() {
+ if(!this.disabled && $.inArray(this.value, values) > -1) {
+ self._toggleState('selected', flag).call(this);
+ }
+ });
+
+ // trigger the change event on the select
+ if($inputs.length) {
+ this.element.trigger("change");
+ }
+ },
+
+ _toggleDisabled: function(flag) {
+ this.button.attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
+
+ var inputs = this.menu.find('input');
+ var key = "ech-multiselect-disabled";
+
+ if(flag) {
+ // remember which elements this widget disabled (not pre-disabled)
+ // elements, so that they can be restored if the widget is re-enabled.
+ inputs = inputs.filter(':enabled').data(key, true)
+ } else {
+ inputs = inputs.filter(function() {
+ return $.data(this, key) === true;
+ }).removeData(key);
+ }
+
+ inputs
+ .attr({ 'disabled':flag, 'arial-disabled':flag })
+ .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
+
+ this.element.attr({
+ 'disabled':flag,
+ 'aria-disabled':flag
+ });
+ },
+
+ // open the menu
+ open: function(e) {
+ var self = this;
+ var button = this.button;
+ var menu = this.menu;
+ var speed = this.speed;
+ var o = this.options;
+ var args = [];
+
+ // bail if the multiselectopen event returns false, this widget is disabled, or is already open
+ if(this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen) {
+ return;
+ }
+
+ var $container = menu.find('ul').last();
+ var effect = o.show;
+
+ // figure out opening effects/speeds
+ if($.isArray(o.show)) {
+ effect = o.show[0];
+ speed = o.show[1] || self.speed;
+ }
+
+ // if there's an effect, assume jQuery UI is in use
+ // build the arguments to pass to show()
+ if(effect) {
+ args = [ effect, speed ];
+ }
+
+ // set the scroll of the checkbox container
+ $container.scrollTop(0).height(o.height);
+
+ // positon
+ this.position();
+
+ // show the menu, maybe with a speed/effect combo
+ $.fn.show.apply(menu, args);
+
+ // select the first option
+ // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover
+ // will actually trigger mouseenter. the mouseenter trigger is there for when it's eventually fixed
+ this.labels.eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus');
+
+ button.addClass('ui-state-active');
+ this._isOpen = true;
+ this._trigger('open');
+ },
+
+ // close the menu
+ close: function() {
+ if(this._trigger('beforeclose') === false) {
+ return;
+ }
+
+ var o = this.options;
+ var effect = o.hide;
+ var speed = this.speed;
+ var args = [];
+
+ // figure out opening effects/speeds
+ if($.isArray(o.hide)) {
+ effect = o.hide[0];
+ speed = o.hide[1] || this.speed;
+ }
+
+ if(effect) {
+ args = [ effect, speed ];
+ }
+
+ $.fn.hide.apply(this.menu, args);
+ this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave');
+ this._isOpen = false;
+ this._trigger('close');
+ },
+
+ enable: function() {
+ this._toggleDisabled(false);
+ },
+
+ disable: function() {
+ this._toggleDisabled(true);
+ },
+
+ checkAll: function(e) {
+ this._toggleChecked(true);
+ this._trigger('checkAll');
+ },
+
+ uncheckAll: function() {
+ this._toggleChecked(false);
+ this._trigger('uncheckAll');
+ },
+
+ getChecked: function() {
+ return this.menu.find('input').filter(':checked');
+ },
+
+ destroy: function() {
+ // remove classes + data
+ $.Widget.prototype.destroy.call(this);
+
+ // unbind events
+ $doc.unbind(this._namespaceID);
+
+ this.button.remove();
+ this.menu.remove();
+ this.element.show();
+
+ return this;
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ widget: function() {
+ return this.menu;
+ },
+
+ getButton: function() {
+ return this.button;
+ },
+
+ position: function() {
+ var o = this.options;
+
+ // use the position utility if it exists and options are specifified
+ if($.ui.position && !$.isEmptyObject(o.position)) {
+ o.position.of = o.position.of || button;
+
+ this.menu
+ .show()
+ .position(o.position)
+ .hide();
+
+ // otherwise fallback to custom positioning
+ } else {
+ var pos = this.button.offset();
+
+ this.menu.css({
+ top: pos.top + this.button.outerHeight(),
+ left: pos.left
+ });
+ }
+ },
+
+ // react to option changes after initialization
+ _setOption: function(key, value) {
+ var menu = this.menu;
+
+ switch(key) {
+ case 'header':
+ menu.find('div.ui-multiselect-header')[value ? 'show' : 'hide']();
+ break;
+ case 'checkAllText':
+ menu.find('a.ui-multiselect-all span').eq(-1).text(value);
+ break;
+ case 'uncheckAllText':
+ menu.find('a.ui-multiselect-none span').eq(-1).text(value);
+ break;
+ case 'height':
+ menu.find('ul').last().height(parseInt(value, 10));
+ break;
+ case 'minWidth':
+ this.options[key] = parseInt(value, 10);
+ this._setButtonWidth();
+ this._setMenuWidth();
+ break;
+ case 'selectedText':
+ case 'selectedList':
+ case 'noneSelectedText':
+ this.options[key] = value; // these all needs to update immediately for the update() call
+ this.update();
+ break;
+ case 'classes':
+ menu.add(this.button).removeClass(this.options.classes).addClass(value);
+ break;
+ case 'multiple':
+ menu.toggleClass('ui-multiselect-single', !value);
+ this.options.multiple = value;
+ this.element[0].multiple = value;
+ this.refresh();
+ break;
+ case 'position':
+ this.position();
+ }
+
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ });
+
+})(jQuery);
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js
new file mode 100644
index 00000000..997de3b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js
@@ -0,0 +1,157 @@
+/**
+ * SRF JavaScript srf.optionslist widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Helper method
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ */
+ $.widget( 'srf.optionslist', {
+
+ /**
+ * Internal method that runs once during initialization
+ *
+ * @private
+ * @return {object}
+ */
+ _init: function() {
+ var self = this,
+ el = self.element;
+ return el;
+ },
+
+ /**
+ * Create checkbox elements from an array
+ *
+ * @return object
+ */
+ checklist: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Returns a list of elements
+ function checkList( list, checkListClass ) {
+ if ( list !== undefined ) {
+ var elements = [];
+ $.each( list, function( key, item ) {
+ if ( key !== '' ) {
+ key = $.type( item ) === 'object' ? item.key : key;
+ item = $.type( item ) === 'object' ? item.label : item;
+ elements.push(
+ html.element( 'input', {
+ 'type': 'checkbox',
+ 'checked': 'checked',
+ 'id': item,
+ 'name': item,
+ 'value': key
+ }, item )
+ );
+ }
+ } );
+ return '<ul><li class="' + checkListClass + '-item">'+ elements.join('</li><li class="' + checkListClass + '-item">') + '</li></ul>';
+ }
+
+ }
+
+ this.checkList = $( checkList( options.list, options['class'] ) ).appendTo( el );
+
+ // Create element and the bind click event
+ self.checkList = this.checkList
+ .on( 'click', ':checkbox', function( event ){
+ var that = $( this );
+ if ( $.isFunction( options.click ) ){
+ options.click( event, {
+ checked: that.is( ':checked' ),
+ value: that.attr( 'value' ),
+ name: that.attr( 'name' )
+ } )
+ }
+ } );
+
+ return options.show || options.show === undefined ? self.checkList.show() : self.checkList.hide();
+ },
+
+ /**
+ * Create select elements from an array
+ *
+ * @since 1.9
+ *
+ * @param {array} options
+ *
+ * @return object
+ */
+ selectlist: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Returns a list of elements
+ function selectList( list ) {
+ if ( list !== undefined ) {
+ var dropdown = '';
+ $.each( list, function( key, item ) {
+ key = $.type( item ) === 'object' ? item.key : key;
+ item = $.type( item ) === 'object' ? item.label : item;
+ dropdown = dropdown + html.element( 'option', {
+ 'value': key,
+ 'selected': options.selectedAll
+ },item );
+ } );
+
+ return html.element( 'select', {
+ 'id': options['class'],
+ 'class': options['class'],
+ 'multiple': options.multiple || false,
+ 'size': options.multiple ? ( list.length > 5 ? 5 : list.length ) : 1
+ }, new html.Raw( ( options.null ? html.element( 'option', { }, '' ) : '' ) + dropdown )
+ );
+ }
+ }
+
+ // Create element and bind the click event
+ this.selectList = $( selectList( options.list ) ).appendTo( el );
+ self.selectList = this.selectList
+ .on( 'change', function( event ){
+ var that = $( this );
+ if ( $.isFunction( options.change ) ){
+ options.change( event, {
+ selected: that.is( ':selected' ),
+ value: that.val()
+ } );
+ }
+ } );
+
+ return options.show || options.show === undefined ? self.selectList.show() : self.selectList.hide();
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ */
+ destroy: function() {
+ $.Widget.prototype.destroy.apply( this );
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js
new file mode 100644
index 00000000..52ca2047
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js
@@ -0,0 +1,107 @@
+/**
+ * SRF JavaScript srf.panel widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Html element generation
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ */
+ $.widget( 'srf.panel', {
+
+ /**
+ * Create method which runs once (during initialization)
+ *
+ * @return object
+ */
+ _create: function() {
+ var self = this,
+ el = self.element;
+
+ this.panel = $(
+ html.element( 'div', { 'class': self.widgetBaseClass }, '' )
+ ).insertAfter( el );
+ return this.options.show ? this.panel.show() : this.panel.hide();
+ },
+
+ /**
+ * Returns the pane context
+ *
+ * @since 1.9
+ * @return object
+ */
+ getContext: function( ) {
+ return this.panel;
+ },
+
+ /**
+ * Adds a portlet
+ *
+ * @since 1.9
+ * @var options
+ */
+ portlet: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Specify the pane instance
+ this.panel = this.panel || $();
+
+ // Append
+ this.panelPortlet = $(
+ html.element( 'div', {
+ 'id': self.widgetBaseClass + '-' + options['class'],
+ 'class': options['class'] },
+ new html.Raw( ( options['fieldset'] ? html.element( 'fieldset', {},
+ new html.Raw( html.element( 'legend', { }, options['title'] ) ) ) : ''
+ )
+ )
+ )
+ ).appendTo( this.panel );
+
+ self.panelPortlet = this.panelPortlet;
+ return options.hide ? self.panelPortlet.hide() : self.panelPortlet.show() ;
+ },
+
+ /**
+ * Depending on its state toggle show/hide
+ *
+ * @since 1.9
+ */
+ toggle: function() {
+ return this.panel.css( 'display' ) === 'none' ? this.panel.fadeIn( 'slow' ): this.panel.hide();
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.panel ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js
new file mode 100644
index 00000000..f2ec074a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js
@@ -0,0 +1,128 @@
+/**
+ * SRF JavaScript for srf.parameters widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Html element and utility objects
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ */
+ $.widget( 'srf.parameters', {
+
+ _init: function() {
+ var self = this,
+ el = self.element;
+ return el;
+ },
+
+ /**
+ * Limit parameter
+ *
+ * @since 1.9
+ */
+ limit: function( options ) {
+ var self = this,
+ el = self.element;
+
+ function element(){
+ return html.element( 'div', { 'class': 'limit-parameter' }, new html.Raw(
+ html.element( 'div', { 'class' : 'parameter-section' }, mw.msg( 'srf-ui-widgets-label-parameter-limit' ) ) +
+ html.element( 'span', { 'class': 'value' }, '' ) +
+ html.element( 'span', { 'class': 'count' }, '' ) + '<br/>' +
+ html.element( 'div', { 'class': 'slider' }, '' )
+ ) );
+ }
+
+ this.limitParameter = $( element() ).appendTo( el );
+
+ // Slider instance
+ this.limitParameter.find( '.slider' ).slider( {
+ range: 'min',
+ value: options.limit,
+ min: 1,
+ max: options.max,
+ step: options.step,
+ slide: function( event, ui ){
+ self._limitParameterUpdate( { limit: self._limitConstrain( ui.value, options.max ) } );
+ },
+ change: function( event, ui ){
+ if ( $.isFunction( options.change ) ){
+ options.change( event, { value : self._limitConstrain( ui.value, options.max ) } );
+ }
+ }
+ } );
+
+ // Show initial limit/count
+ this._limitParameterUpdate( { limit: options.limit, count: options.count } );
+ },
+
+ /**
+ * Limit/count value update
+ *
+ * @since 1.9
+ */
+ _limitParameterUpdate: function( options ){
+ var self = this,
+ el = self.element;
+
+ $( '.value', self.element ).text( options.limit );
+
+ if ( options.count ){
+ $( '.count', self.element ).text( '[ ' + options.count + ' ]' );
+ } else {
+ $( '.count', self.element ).text( '' );
+ }
+ },
+
+ _limitConstrain: function( value, max ){
+ return value > 1 ? value >= max ? max : value - 1 : value;
+ },
+
+ /**
+ * Change options
+ *
+ * @param name
+ * @param value
+ */
+ _setOption: function ( name, value ) {
+ switch( name ){
+ case 'limit':
+ this._limitParameterUpdate( value );
+ break;
+ }
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.pane ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/src/BibTex/BibTexFileExportPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/BibTex/BibTexFileExportPrinter.php
new file mode 100644
index 00000000..aa2bc011
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/BibTex/BibTexFileExportPrinter.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace SRF\BibTex;
+
+use SMWTimeValue as TimeValue;
+use SMWQueryResult as QueryResult;
+use SMW\Query\ResultPrinters\FileExportPrinter;
+
+/**
+ * Printer class for creating BibTeX exports
+ *
+ * For details on availble keys see the README
+ *
+ * Example of a book :
+ *
+ * @Book{abramowitz1964homf,
+ * author = "Milton Abramowitz and Irene A. Stegun",
+ * title = "Handbook of Mathematical Functions",
+ * publisher = "Dover",
+ * year = 1964,
+ * address = "New York",
+ * edition = "ninth Dover printing, tenth GPO printing"
+ * }
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ * @author Steren Giannini
+ */
+class BibTexFileExportPrinter extends FileExportPrinter {
+
+ /**
+ * @see ResultPrinter::getName
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return wfMessage( 'srf_printername_bibtex' )->text();
+ }
+
+ /**
+ * @see FileExportPrinter::getMimeType
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getMimeType( QueryResult $queryResult ) {
+ return 'text/bibtex';
+ }
+
+ /**
+ * @see FileExportPrinter::getFileName
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getFileName( QueryResult $queryResult ) {
+
+ if ( $this->params['filename'] !== '' ) {
+
+ if ( strpos( $this->params['filename'], '.bib' ) === false ) {
+ $this->params['filename'] .= '.bib';
+ }
+
+ return str_replace( ' ', '_', $this->params['filename'] );
+ } elseif ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) {
+ return str_replace( ' ', '_', $this->getSearchLabel( SMW_OUTPUT_WIKI ) ) . '.bib';
+ }
+
+ return 'BibTeX.bib';
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['filename'] = [
+ 'message' => 'smw-paramdesc-filename',
+ 'default' => 'bibtex.bib',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param array $list
+ *
+ * @return string
+ */
+ public function getFormattedList( $key, array $values ) {
+ return $GLOBALS['wgLang']->listToText( $values );
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ *
+ * {@inheritDoc}
+ */
+ protected function getResultText( QueryResult $res, $outputMode ) {
+
+ if ( $outputMode !== SMW_OUTPUT_FILE ) {
+ return $this->getBibTexLink( $res, $outputMode );
+ }
+
+ $items = [];
+
+ while ( $row = $res->getNext() ) {
+ $items[] = $this->newItem( $row )->text();
+ }
+
+ return implode( "\r\n\r\n", $items );
+ }
+
+ private function getBibTexLink( QueryResult $res, $outputMode ) {
+
+ // Can be viewed as HTML if requested, no more parsing needed
+ $this->isHTML = $outputMode == SMW_OUTPUT_HTML;
+
+ $link = $this->getLink(
+ $res,
+ $outputMode
+ );
+
+ return $link->getText( $outputMode, $this->mLinker );
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $row array of SMWResultArray
+ *
+ * @return bibTexItem
+ */
+ private function newItem( array /* of SMWResultArray */ $row ) {
+
+ $item = new Item();
+ $item->setFormatterCallback( [ $this, 'getFormattedList' ] );
+
+ foreach ( $row as /* SMWResultArray */ $field ) {
+ $printRequest = $field->getPrintRequest();
+ $values = [];
+
+ $label = strtolower( $printRequest->getLabel() );
+ $dataValue = $field->getNextDataValue();
+
+ if ( $dataValue === false ) {
+ continue;
+ }
+
+ if ( $label === 'date' && $dataValue instanceof TimeValue ) {
+ $item->set( 'year', $dataValue->getYear() );
+ $item->set( 'month', $dataValue->getMonth() );
+ } elseif ( $label === 'author' || $label === 'authors' ) {
+ $values[] = $dataValue->getShortWikiText();
+
+ while ( ( /* SMWDataValue */ $dataValue = $field->getNextDataValue() ) !== false ) {
+ $values[] = $dataValue->getShortWikiText();
+ }
+
+ $item->set( 'author', $values );
+ } elseif ( $label === 'editor' || $label === 'editors' ) {
+ $values[] = $dataValue->getShortWikiText();
+
+ while ( ( /* SMWDataValue */ $dataValue = $field->getNextDataValue() ) !== false ) {
+ $values[] = $dataValue->getShortWikiText();
+ }
+
+ $item->set( 'editor', $values );
+ } else {
+ $item->set( $label, $dataValue->getShortWikiText() );
+ }
+ }
+
+ return $item;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/BibTex/Item.php b/www/wiki/extensions/SemanticResultFormats/src/BibTex/Item.php
new file mode 100644
index 00000000..7ff631ef
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/BibTex/Item.php
@@ -0,0 +1,185 @@
+<?php
+
+namespace SRF\BibTex;
+
+use SMWDataValue as DataValue;
+
+/**
+ * @see http://www.semantic-mediawiki.org/wiki/BibTex
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class Item {
+
+ /**
+ * @see https://en.wikipedia.org/wiki/BibTeX
+ *
+ * @var string
+ */
+ private $type = '';
+
+ /**
+ * @var []
+ */
+ protected $fields = [
+ 'address' => '',
+ 'annote' => '',
+ 'author' => [],
+ 'booktitle' => '',
+ 'chapter' => '',
+ 'crossref' => '',
+ 'doi' => '',
+ 'edition' => '',
+ 'editor' => [],
+ 'eprint' => '',
+ 'howpublished' => '',
+ 'institution' => '',
+ 'journal' => '',
+ 'key' => '',
+ 'month' => '',
+ 'note' => '',
+ 'number' => '',
+ 'organization' => '',
+ 'pages' => '',
+ 'publisher' => '',
+ 'school' => '',
+ 'series' => '',
+ 'title' => '',
+ 'url' => '',
+ 'volume' => '',
+ 'year' => ''
+ ];
+
+ /**
+ * @var callable
+ */
+ private $formatterCallback;
+
+ /**
+ * @since 3.1
+ */
+ public function __construct() {
+ $this->type = 'Book';
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param callable $compoundLabelCallback
+ */
+ public function setFormatterCallback( callable $formatterCallback ) {
+ $this->formatterCallback = $formatterCallback;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $key
+ * @param string $text
+ *
+ * @return string
+ */
+ public function replace( $key, $text ) {
+
+ if ( $key === 'uri' ) {
+ $text = str_replace(
+ [ "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß" ],
+ [ 'Ae', 'ae', 'Oe', 'oe', 'Ue', 'ue', 'ss' ],
+ $text
+ );
+ $text = preg_replace("/[^a-zA-Z0-9]+/", "", $text );
+ }
+
+ return $text;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $key
+ * @param mixed $value
+ */
+ public function set( $key, $value ) {
+
+ $key = strtolower( $key );
+
+ if ( $key === 'type' ) {
+ $this->type = ucfirst( $value );
+ }
+
+ if ( isset( $this->fields[$key] ) ) {
+ $this->fields[$key] = $value;
+ }
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @return string
+ */
+ public function text() {
+
+ $formatterCallback = $this->formatterCallback;
+
+ $text = '@' . $this->type . '{' . $this->buildURI() . ",\r\n";
+
+ foreach ( $this->fields as $key => $value ) {
+
+ if ( ( $key === 'author' || $key === 'editor' ) && is_array( $value ) ) {
+ if ( is_callable( $formatterCallback ) ) {
+ $value = $formatterCallback( $key, $value );
+ } else {
+ $value = implode( ', ', $value );
+ }
+ }
+
+ if ( $value === '' ) {
+ continue;
+ }
+
+ $text .= ' ' . $key . ' = "' . $value . '", ' . "\r\n";
+ }
+
+ $text .= "}";
+
+ return $text;
+ }
+
+ /**
+ * Consist of `author last name` + `year` + `first word of title`
+ *
+ * @return string
+ */
+ protected function buildURI() {
+
+ $uri = '';
+
+ if ( isset( $this->fields['author'] ) ) {
+ foreach ( $this->fields['author'] as $key => $author ) {
+ $elements = explode( ' ', $author );
+ $uri .= array_pop( $elements );
+ break;
+ }
+ }
+
+ if ( isset( $this->fields['year'] ) ) {
+ $uri .= $this->fields['year'];
+ }
+
+ if ( isset( $this->fields['title'] ) ) {
+ foreach ( explode( ' ', $this->fields['title'] ) as $titleWord ) {
+ $charsTitleWord = preg_split( '//', $titleWord, -1, PREG_SPLIT_NO_EMPTY );
+
+ if ( !empty( $charsTitleWord ) ) {
+ $uri .= $charsTitleWord[0];
+ }
+ }
+ }
+
+ return strtolower( $this->replace( 'uri', $uri ) );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/BibTex/README.md b/www/wiki/extensions/SemanticResultFormats/src/BibTex/README.md
new file mode 100644
index 00000000..1feab534
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/BibTex/README.md
@@ -0,0 +1,91 @@
+Info is copied from http://en.wikipedia.org/wiki/Bibtex
+
+## Fields
+
+- address: Publisher's address (usually just the city, but can be the full address for lesser-known publishers)
+- annote: An annotation for annotated bibliography styles (not typical)
+- author: The name(s) of the author(s) (in the case of more than one author, separated by and)
+- booktitle: The title of the book, if only part of it is being cited
+- chapter: The chapter number
+- crossref: The key of the cross-referenced entry
+- doi: The DOI number of the entry
+- edition: The edition of a book, long form (such as "first" or "second")
+- editor: The name(s) of the editor(s)
+- eprint: A specification of an electronic publication, often a preprint or a technical report
+- howpublished: How it was published, if the publishing method is nonstandard
+- institution: The institution that was involved in the publishing, but not necessarily the publisher
+- journal: The journal or magazine the work was published in
+- key: A hidden field used for specifying or overriding the alphabetical order of entries (when the "author" and "editor" fields are missing). Note that this is very different from the key (mentioned just after this list) that is used to cite or cross-reference the entry.
+- month: The month of publication (or, if unpublished, the month of creation)
+- note: Miscellaneous extra information
+- number: The "number" of a journal, magazine, or tech-report, if applicable. (Most publications have a "volume", but no "number" field.)
+- organization: The conference sponsor
+- pages: Page numbers, separated either by commas or double-hyphens. For books, the total number of pages.
+- publisher: The publisher's name
+- school: The school where the thesis was written
+- series: The series of books the book was published in (e.g. "The Hardy Boys" or "Lecture Notes in Computer Science")
+- title: The title of the work
+- type: The type of tech-report, for example, "Research Note"
+- url: The WWW address
+- volume: The volume of a journal or multi-volume book
+- year: The year of publication (or, if unpublished, the year of creation)
+
+
+## Types
+
+- article:
+ An article from a journal or magazine.
+ Required fields: author, title, journal, year
+ Optional fields: volume, number, pages, month, note, key
+- book:
+ A book with an explicit publisher.
+ Required fields: author/editor, title, publisher, year
+ Optional fields: volume, series, address, edition, month, note, key, pages
+- booklet:
+ A work that is printed and bound, but without a named publisher or sponsoring institution.
+ Required fields: title
+ Optional fields: author, howpublished, address, month, year, note, key
+- conference:
+ The same as inproceedings, included for Scribe compatibility.
+ Required fields: author, title, booktitle, year
+ Optional fields: editor, pages, organization, publisher, address, month, note, key
+- inbook:
+ A part of a book, usually untitled. May be a chapter (or section or whatever) and/or a range of pages.
+ Required fields: author/editor, title, chapter/pages, publisher, year
+ Optional fields: volume, series, address, edition, month, note, key
+- incollection:
+ A part of a book having its own title.
+ Required fields: author, title, booktitle, year
+ Optional fields: editor, pages, organization, publisher, address, month, note, key
+- inproceedings:
+ An article in a conference proceedings.
+ Required fields: author, title, booktitle, year
+ Optional fields: editor, pages, organization, publisher, address, month, note, key
+- manual:
+ Technical documentation.
+ Required fields: title
+ Optional fields: author, organization, address, edition, month, year, note, key
+- mastersthesis:
+ A Master's thesis.
+ Required fields: author, title, school, year
+ Optional fields: address, month, note, key
+- misc:
+ For use when nothing else fits.
+ Required fields: none
+ Optional fields: author, title, howpublished, month, year, note, key
+- phdthesis:
+ A Ph.D. thesis.
+ Required fields: author, title, school, year
+ Optional fields: address, month, note, key
+- proceedings:
+ The proceedings of a conference.
+ Required fields: title, year
+ Optional fields: editor, publisher, organization, address, month, note, key
+- techreport:
+ A report published by a school or other institution, usually numbered within a series.
+ Required fields: author, title, institution, year
+ Optional fields: type, number, address, month, note, key
+- unpublished:
+ A document having an author and title, but not formally published.
+ Required fields: author, title, note
+ Optional fields: month, year, key
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php
new file mode 100644
index 00000000..91def23d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php
@@ -0,0 +1,419 @@
+<?php
+
+namespace SRF\Graph;
+
+use SMWResultPrinter;
+use SMWQueryResult;
+use SMWDataValue;
+use SMWWikiPageValue;
+
+/**
+ * SMW result printer for graphs using graphViz.
+ * In order to use this printer you need to have both
+ * the graphViz library installed on your system and
+ * have the graphViz MediaWiki extension installed.
+ *
+ * @file SRF_Graph.php
+ * @ingroup SemanticResultFormats
+ *
+ * @licence GNU GPL v2+
+ * @author Frank Dengler
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class GraphPrinter extends SMWResultPrinter {
+
+ const NODELABEL_DISPLAYTITLE = 'displaytitle';
+
+ public static $NODE_LABELS = [
+ self::NODELABEL_DISPLAYTITLE,
+ ];
+
+ public static $NODE_SHAPES = [
+ 'box',
+ 'box3d',
+ 'circle',
+ 'component',
+ 'diamond',
+ 'doublecircle',
+ 'doubleoctagon',
+ 'egg',
+ 'ellipse',
+ 'folder',
+ 'hexagon',
+ 'house',
+ 'invhouse',
+ 'invtrapezium',
+ 'invtriangle',
+ 'Mcircle',
+ 'Mdiamond',
+ 'Msquare',
+ 'none',
+ 'note',
+ 'octagon',
+ 'parallelogram',
+ 'pentagon ',
+ 'plaintext',
+ 'point',
+ 'polygon',
+ 'rect',
+ 'rectangle',
+ 'septagon',
+ 'square',
+ 'tab',
+ 'trapezium',
+ 'triangle',
+ 'tripleoctagon',
+ ];
+
+ protected $m_graphName;
+ protected $m_graphLabel;
+ protected $m_graphColor;
+ protected $m_graphLegend;
+ protected $m_graphLink;
+ protected $m_rankdir;
+ protected $m_graphSize;
+ protected $m_labelArray = [];
+ protected $m_graphColors = [
+ 'black',
+ 'red',
+ 'green',
+ 'blue',
+ 'darkviolet',
+ 'gold',
+ 'deeppink',
+ 'brown',
+ 'bisque',
+ 'darkgreen',
+ 'yellow',
+ 'darkblue',
+ 'magenta',
+ 'steelblue2' ];
+ protected $m_nameProperty;
+ protected $m_nodeShape;
+ protected $m_parentRelation;
+ protected $m_wordWrapLimit;
+ protected $m_nodeLabel;
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::handleParameters()
+ */
+ protected function handleParameters( array $params, $outputmode ) {
+ parent::handleParameters( $params, $outputmode );
+
+ $this->m_graphName = trim( $params['graphname'] );
+ $this->m_graphSize = trim( $params['graphsize'] );
+
+ $this->m_graphLegend = $params['graphlegend'];
+ $this->m_graphLabel = $params['graphlabel'];
+
+ $this->m_rankdir = strtoupper( trim( $params['arrowdirection'] ) );
+
+ $this->m_graphLink = $params['graphlink'];
+ $this->m_graphColor = $params['graphcolor'];
+
+ $this->m_nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] );
+
+ $this->m_parentRelation = strtolower( trim( $params['relation'] ) ) == 'parent';
+
+ $this->m_nodeShape = $params['nodeshape'];
+ $this->m_wordWrapLimit = $params['wordwraplimit'];
+
+ $this->m_nodeLabel = $params['nodelabel'];
+ }
+
+ protected function getResultText( SMWQueryResult $res, $outputmode ) {
+
+ if ( !class_exists( 'GraphViz' )
+ && !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' )
+ ) {
+ wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' );
+ return '';
+ }
+
+ $this->isHTML = true;
+
+ $graphInput = "digraph $this->m_graphName {";
+ if ( $this->m_graphSize != '' ) {
+ $graphInput .= "size=\"$this->m_graphSize\";";
+ }
+ if ( $this->m_nodeShape ) {
+ $graphInput .= "node [shape=$this->m_nodeShape];";
+ }
+ $graphInput .= "rankdir=$this->m_rankdir;";
+
+ while ( $row = $res->getNext() ) {
+ $graphInput .= $this->getGVForItem( $row, $outputmode );
+ }
+
+ $graphInput .= "}";
+
+ // Calls graphvizParserHook function from MediaWiki GraphViz extension
+ $result = $GLOBALS['wgParser']->recursiveTagParse( "<graphviz>$graphInput</graphviz>" );
+
+ if ( $this->m_graphLegend && $this->m_graphColor ) {
+ $arrayCount = 0;
+ $arraySize = count( $this->m_graphColors );
+ $result .= "<P>";
+
+ foreach ( $this->m_labelArray as $m_label ) {
+ if ( $arrayCount >= $arraySize ) {
+ $arrayCount = 0;
+ }
+
+ $color = $this->m_graphColors[$arrayCount];
+ $result .= "<font color=$color>$color: $m_label </font><br />";
+
+ $arrayCount += 1;
+ }
+
+ $result .= "</P>";
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the GV for a single subject.
+ *
+ * @since 1.5.4
+ *
+ * @param array $row
+ * @param $outputmode
+ *
+ * @return string
+ */
+ protected function getGVForItem( array /* of SMWResultArray */
+ $row, $outputmode ) {
+ $segments = [];
+
+ // Loop throught all fields of the record.
+ foreach ( $row as $i => $resultArray ) {
+
+ // Loop throught all the parts of the field value.
+ while ( ( $object = $resultArray->getNextDataValue() ) !== false ) {
+ $propName = $resultArray->getPrintRequest()->getLabel();
+ $isName = $this->m_nameProperty ? ( $i != 0 && $this->m_nameProperty === $propName ) : $i == 0;
+
+ if ( $isName ) {
+ $name = $this->getWordWrappedText( $object->getShortText( $outputmode ), $this->m_wordWrapLimit );
+ }
+
+ if ( !( $this->m_nameProperty && $i == 0 ) ) {
+ $segments[] = $this->getGVForDataValue( $object, $outputmode, $isName, $name, $propName );
+ }
+ }
+ }
+
+ return implode( "\n", $segments );
+ }
+
+ /**
+ * Returns the GV for a single SMWDataValue.
+ *
+ * @since 1.5.4
+ *
+ * @param SMWDataValue $object
+ * @param $outputmode
+ * @param boolean $isName Is this the name that should be used for the node?
+ * @param string $name
+ * @param string $labelName
+ *
+ * @return string
+ */
+ protected function getGVForDataValue( SMWDataValue $object, $outputmode, $isName, $name, $labelName ) {
+ $graphInput = '';
+ $nodeLabel = '';
+ $text = $object->getShortText( $outputmode );
+
+ if ( $this->m_graphLink ) {
+ $nodeLinkURL = "[[" . $text . "]]";
+ }
+
+ $text = $this->getWordWrappedText( $text, $this->m_wordWrapLimit );
+
+ if ( $this->m_nodeLabel === self::NODELABEL_DISPLAYTITLE && $object instanceof SMWWikiPageValue ) {
+ $objectDisplayTitle = $object->getDisplayTitle();
+ if ( !empty( $objectDisplayTitle )) {
+ $nodeLabel = $this->getWordWrappedText( $objectDisplayTitle, $this->m_wordWrapLimit );
+ }
+ }
+
+ if ( $this->m_graphLink ) {
+ if( $nodeLabel === '' ) {
+ $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\"]; ";
+ } else {
+ $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]; ";
+ }
+ }
+
+ if ( !$isName ) {
+ $graphInput .= $this->m_parentRelation ? " \"$text\" -> \"$name\" " : " \"$name\" -> \"$text\" ";
+
+ if ( $this->m_graphLabel || $this->m_graphColor ) {
+ $graphInput .= ' [';
+
+ if ( array_search( $labelName, $this->m_labelArray, true ) === false ) {
+ $this->m_labelArray[] = $labelName;
+ }
+
+ $color = $this->m_graphColors[array_search( $labelName, $this->m_labelArray, true )];
+
+ if ( $this->m_graphLabel ) {
+ $graphInput .= "label=\"$labelName\"";
+ if ( $this->m_graphColor ) {
+ $graphInput .= ",fontcolor=$color,";
+ }
+ }
+
+ if ( $this->m_graphColor ) {
+ $graphInput .= "color=$color";
+ }
+
+ $graphInput .= ']';
+
+ }
+
+ $graphInput .= ';';
+ }
+
+ return $graphInput;
+ }
+
+ /**
+ * Returns the word wrapped version of the provided text.
+ *
+ * @since 1.5.4
+ *
+ * @param string $text
+ * @param integer $charLimit
+ *
+ * @return string
+ */
+ protected function getWordWrappedText( $text, $charLimit ) {
+ $charLimit = max( [ $charLimit, 1 ] );
+ $segments = [];
+
+ while ( strlen( $text ) > $charLimit ) {
+ // Find the last space in the allowed range.
+ $splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
+
+ if ( $splitPosition === false ) {
+ // If there is no space (lond word), find the next space.
+ $splitPosition = strpos( $text, ' ' );
+
+ if ( $splitPosition === false ) {
+ // If there are no spaces, everything goes on one line.
+ $splitPosition = strlen( $text ) - 1;
+ }
+ }
+
+ $segments[] = substr( $text, 0, $splitPosition + 1 );
+ $text = substr( $text, $splitPosition + 1 );
+ }
+
+ $segments[] = $text;
+
+ return implode( '\n', $segments );
+ }
+
+ /**
+ * (non-PHPdoc)
+ * @see SMWResultPrinter::getName()
+ */
+ public function getName() {
+ return wfMessage( 'srf-printername-graph' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * @param $definitions array of IParamDefinition
+ *
+ * @return array of IParamDefinition|array
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['graphname'] = [
+ 'default' => 'QueryResult',
+ 'message' => 'srf-paramdesc-graphname',
+ ];
+
+ $params['graphsize'] = [
+ 'type' => 'string',
+ 'default' => '',
+ 'message' => 'srf-paramdesc-graphsize',
+ 'manipulatedefault' => false,
+ ];
+
+ $params['graphlegend'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graphlegend',
+ ];
+
+ $params['graphlabel'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graphlabel',
+ ];
+
+ $params['graphlink'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graphlink',
+ ];
+
+ $params['graphcolor'] = [
+ 'type' => 'boolean',
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graphcolor',
+ ];
+
+ $params['arrowdirection'] = [
+ 'aliases' => 'rankdir',
+ 'default' => 'LR',
+ 'message' => 'srf-paramdesc-rankdir',
+ 'values' => [ 'LR', 'RL', 'TB', 'BT' ],
+ ];
+
+ $params['nodeshape'] = [
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graph-nodeshape',
+ 'manipulatedefault' => false,
+ 'values' => self::$NODE_SHAPES,
+ ];
+
+ $params['relation'] = [
+ 'default' => 'child',
+ 'message' => 'srf-paramdesc-graph-relation',
+ 'manipulatedefault' => false,
+ 'values' => [ 'parent', 'child' ],
+ ];
+
+ $params['nameproperty'] = [
+ 'default' => false,
+ 'message' => 'srf-paramdesc-graph-nameprop',
+ 'manipulatedefault' => false,
+ ];
+
+ $params['wordwraplimit'] = [
+ 'type' => 'integer',
+ 'default' => 25,
+ 'message' => 'srf-paramdesc-graph-wwl',
+ 'manipulatedefault' => false,
+ ];
+
+ $params['nodelabel'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-nodelabel',
+ 'values' => self::$NODE_LABELS,
+ ];
+
+ return $params;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/ListTreeBuilder.php b/www/wiki/extensions/SemanticResultFormats/src/Outline/ListTreeBuilder.php
new file mode 100644
index 00000000..f64a4366
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/ListTreeBuilder.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace SRF\Outline;
+
+use SMW\Query\PrintRequest;
+use SRF\Outline\OutlineTree;
+use SMWDataItem as DataItem;
+
+/**
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class ListTreeBuilder {
+
+ /**
+ * @var []
+ */
+ private $params = [];
+
+ /**
+ * @var Linker
+ */
+ private $linker;
+
+ /**
+ * @param array $params
+ */
+ public function __construct( array $params ) {
+ $this->params = $params;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param Linker|null|false $linker
+ */
+ public function setLinker( $linker ) {
+ $this->linker = $linker;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param OutlineTree $tree
+ *
+ * @return string
+ */
+ public function build( OutlineTree $outlineTree ) {
+ return $this->tree( $outlineTree );
+ }
+
+ private function tree( $outline_tree, $level = 0 ) {
+ $text = "";
+
+ if ( !is_null( $outline_tree->items ) ) {
+ $text .= "<ul>\n";
+ foreach ( $outline_tree->items as $item ) {
+ $text .= "<li>{$this->item($item)}</li>\n";
+ }
+ $text .= "</ul>\n";
+ }
+
+ if ( $level > 0 ) {
+ $text .= "<ul>\n";
+ }
+
+ $num_levels = count( $this->params['outlineproperties'] );
+ // set font size and weight depending on level we're at
+ $font_level = $level;
+
+ if ( $num_levels < 4 ) {
+ $font_level += ( 4 - $num_levels );
+ }
+
+ if ( $font_level == 0 ) {
+ $font_size = 'x-large';
+ } elseif ( $font_level == 1 ) {
+ $font_size = 'large';
+ } elseif ( $font_level == 2 ) {
+ $font_size = 'medium';
+ } else {
+ $font_size = 'small';
+ }
+
+ if ( $font_level == 3 ) {
+ $font_weight = 'bold';
+ } else {
+ $font_weight = 'regular';
+ }
+
+ foreach ( $outline_tree->tree as $key => $node ) {
+ $text .= "<p style=\"font-size: $font_size; font-weight: $font_weight;\">$key</p>\n";
+ $text .= $this->tree( $node, $level + 1 );
+ }
+
+ if ( $level > 0 ) {
+ $text .= "</ul>\n";
+ }
+
+ return $text;
+ }
+
+ private function item( $item ) {
+ $first_col = true;
+ $found_values = false; // has anything but the first column been printed?
+ $result = "";
+
+ foreach ( $item->row as $resultArray ) {
+
+ $printRequest = $resultArray->getPrintRequest();
+ $val = $printRequest->getText( SMW_OUTPUT_WIKI, null );
+ $first_value = true;
+
+ if ( in_array( $val, $this->params['outlineproperties'] ) ) {
+ continue;
+ }
+
+ $linker = $this->params['link'] === 'all' ? $this->linker : null;
+
+ if ( $this->params['link'] === 'subject' && $printRequest->isMode( PrintRequest::PRINT_THIS ) ) {
+ $linker = $this->linker;
+ }
+
+ while ( ( $dv = $resultArray->getNextDataValue() ) !== false ) {
+
+ if ( !$first_col && !$found_values ) { // first values after first column
+ $result .= ' (';
+ $found_values = true;
+ } elseif ( $found_values || !$first_value ) {
+ // any value after '(' or non-first values on first column
+ $result .= ', ';
+ }
+
+ if ( $first_value ) { // first value in any column, print header
+ $first_value = false;
+ if ( $this->params['showHeaders'] && ( '' != $printRequest->getLabel() ) ) {
+ $result .= $printRequest->getText( SMW_OUTPUT_WIKI, $linker ) . ' ';
+ }
+ }
+
+ $dataItem = $dv->getDataItem();
+
+ if ( $linker === null && $dataItem->getDIType() === DataItem::TYPE_WIKIPAGE && ( $caption = $dv->getDisplayTitle() ) !== '' ) {
+ $dv->setCaption( $caption );
+ }
+
+ $result .= $dv->getShortText( SMW_OUTPUT_WIKI, $linker );
+ }
+
+ $first_col = false;
+ }
+
+ if ( $found_values ) {
+ $result .= ')';
+ }
+
+ return $result;
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineItem.php b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineItem.php
new file mode 100644
index 00000000..7b273c25
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineItem.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace SRF\Outline;
+
+/**
+ * Represents a single item, or page, in the outline - contains both the
+ * SMWResultArray and an array of some of its values, for easier aggregation
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ */
+class OutlineItem {
+
+ /**
+ * @var [type]
+ */
+ public $row;
+
+ /**
+ * @var []
+ */
+ private $vals;
+
+ /**
+ * @since 3.1
+ *
+ * @param $row
+ */
+ public function __construct( $row ) {
+ $this->row = $row;
+ $this->vals = [];
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $name
+ * @param $value
+ */
+ public function addFieldValue( $key, $value ) {
+ if ( array_key_exists( $key, $this->vals ) ) {
+ $this->vals[$key][] = $value;
+ } else {
+ $this->vals[$key] = [ $value ];
+ }
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $row
+ */
+ public function getFieldValues( $key ) {
+
+ if ( array_key_exists( $key, $this->vals ) ) {
+ return $this->vals[$key];
+ }
+
+ return [ wfMessage( 'srf_outline_novalue' )->text() ];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineResultPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineResultPrinter.php
new file mode 100644
index 00000000..9bb3b042
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineResultPrinter.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace SRF\Outline;
+
+use SMWResultPrinter as ResultPrinter;
+use SMWQueryResult as QueryResult;
+
+/**
+ * A class to print query results in an outline format, along with some
+ * helper classes to handle the aggregation
+ *
+ * @license GNU GPL v2+
+ * @since 1.4.3
+ *
+ * @author Yaron Koren
+ */
+class OutlineResultPrinter extends ResultPrinter {
+
+ /**
+ * @see ResultPrinter::getName
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return wfMessage( 'srf_printername_outline' )->text();
+ }
+
+ /**
+ * @see SMWResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['outlineproperties'] = [
+ 'islist' => true,
+ 'default' => [],
+ 'message' => 'srf_paramdesc_outlineproperties',
+ ];
+
+ $params[] = [
+ 'name' => 'template',
+ 'message' => 'smw-paramdesc-template',
+ 'default' => '',
+ ];
+
+ $params[] = [
+ 'name' => 'userparam',
+ 'message' => 'smw-paramdesc-userparam',
+ 'default' => '',
+ ];
+
+ $params[] = [
+ 'name' => 'named args',
+ 'type' => 'boolean',
+ 'message' => 'smw-paramdesc-named_args',
+ 'default' => true,
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ *
+ * {@inheritDoc}
+ */
+ protected function getResultText( QueryResult $res, $outputMode ) {
+
+ // for each result row, create an array of the row itself
+ // and all its sorted-on fields, and add it to the initial
+ // 'tree'
+ $outlineTree = new OutlineTree();
+
+ while ( $row = $res->getNext() ) {
+ $outlineTree->addItem( $this->newOutlineItem( $row ) );
+ }
+
+ // now, cycle through the outline properties, creating the
+ // tree
+ foreach ( $this->params['outlineproperties'] as $property ) {
+ $outlineTree->addProperty( $property );
+ }
+
+ if ( $this->params['template'] !== '' ) {
+ $this->hasTemplates = true;
+ $templateBuilder = new TemplateBuilder(
+ $this->params
+ );
+
+ $templateBuilder->setLinker( $this->mLinker );
+ $result = $templateBuilder->build( $outlineTree );
+ } else {
+ $listTreeBuilder = new ListTreeBuilder(
+ $this->params + [ 'showHeaders' => $this->mShowHeaders ]
+ );
+
+ $listTreeBuilder->setLinker( $this->mLinker );
+ $result = $listTreeBuilder->build( $outlineTree );
+ }
+
+ if ( $this->linkFurtherResults( $res ) ) {
+ $link = $this->getFurtherResultsLink(
+ $res,
+ $outputMode
+ );
+
+ $result .= $link->getText( $outputMode, $this->mLinker ) . "\n";
+ }
+
+ return $result;
+ }
+
+ private function newOutlineItem( $row ) {
+
+ $outlineItem = new OutlineItem( $row );
+
+ foreach ( $row as $field ) {
+ $name = $field->getPrintRequest()->getText( SMW_OUTPUT_HTML );
+
+ if ( !in_array( $name, $this->params['outlineproperties'] ) ) {
+ continue;
+ }
+
+ while ( ( $dataValue = $field->getNextDataValue() ) !== false ) {
+ $outlineItem->addFieldValue(
+ $name,
+ $dataValue->getLongWikiText( $this->getLinker() )
+ );
+ }
+ }
+
+ return $outlineItem;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineTree.php b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineTree.php
new file mode 100644
index 00000000..3a3ecabb
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/OutlineTree.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace SRF\Outline;
+
+/**
+ * A tree structure for holding the outline data
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ */
+class OutlineTree {
+
+ /**
+ * @var []
+ */
+ public $tree;
+
+ /**
+ * @var []
+ */
+ public $items;
+
+ /**
+ * @var integer
+ */
+ public $itemCount = 0;
+
+ /**
+ * @var integer
+ */
+ public $leafCount = 0;
+
+ /**
+ * @since 3.1
+ *
+ * @param array $items
+ */
+ public function __construct( $items = [] ) {
+ $this->tree = [];
+ $this->items = $items;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $item
+ */
+ public function addItem( $item ) {
+ $this->items[] = $item;
+ $this->itemCount++;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $vals
+ * @param $item
+ */
+ public function categorizeItem( $vals, $item ) {
+ foreach ( $vals as $val ) {
+ if ( array_key_exists( $val, $this->tree ) ) {
+ $this->tree[$val]->items[] = $item;
+ $this->tree[$val]->leafCount++;
+ } else {
+ $this->tree[$val] = new self( [ $item ] );
+ $this->tree[$val]->leafCount++;
+ }
+ }
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param $property
+ */
+ public function addProperty( $property ) {
+ if ( $this->items !== null && count( $this->items ) > 0 ) {
+ foreach ( $this->items as $item ) {
+ $cur_vals = $item->getFieldValues( $property );
+ $this->categorizeItem( $cur_vals, $item );
+ }
+ $this->items = null;
+ } else {
+ foreach ( $this->tree as $i => $node ) {
+ $this->tree[$i]->addProperty( $property );
+ }
+ }
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/README.md b/www/wiki/extensions/SemanticResultFormats/src/Outline/README.md
new file mode 100644
index 00000000..62319dfc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/README.md
@@ -0,0 +1,53 @@
+# Outline format
+
+The format is to display pages in a hierarchical outline form, using one or more of the pages' properties as outline headers.
+
+## Usage
+
+```
+{{#ask: [[Category:Task]]
+ |?Severity
+ |format=outline
+ |outlineproperties=Severity, Assigned to
+ |template=phab-view
+}}
+```
+
+For example, with `phab-view` as template name, the `outline` format will generate two distinct templates `phab-view-header` and `phab-view-item` to be used for the output with `-header` and `-item` being a fixed affix to distinguish the output level of the result content.
+
+The `...-header` template will provide additional information and includes:
+- `#outlinelevel` the level of the header being processed (depends on the iteration level invoked by the `outlineproperties` parameter)
+- `#itemcount` provides a count information for the items assigned to the
+the level
+- `#userparam`
+
+The `...-item` template will also provide additional information such as:
+
+- `#itemsection` section number of the item
+- `#itemsubject` the subject (aka page) of the item processed
+- `#userparam` content provided by a user via the `#ask` `userparam` parameter
+
+
+## Examples
+
+Using a template can provide means to individually style the result output, for example a simple list can be turned into a phabricator task list.
+
+```
+{{#ask: [[Category:Task]]
+ ...
+ |outlineproperties=Severity
+ |template=phab-view
+}}
+```
+
+![image](https://user-images.githubusercontent.com/1245473/51059660-d2826b00-15e4-11e9-8ff3-bb1591b04e81.png)
+
+```
+{{#ask: [[Category:Task]]
+ ...
+ |outlineproperties=Severity, Assigned to
+ |template=phab-view
+}}
+```
+
+![image](https://user-images.githubusercontent.com/1245473/51059791-52103a00-15e5-11e9-85cf-86c503a10b55.png)
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Outline/TemplateBuilder.php b/www/wiki/extensions/SemanticResultFormats/src/Outline/TemplateBuilder.php
new file mode 100644
index 00000000..e6982e29
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/Outline/TemplateBuilder.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace SRF\Outline;
+
+use SMW\Query\PrintRequest;
+use SRF\Outline\OutlineTree;
+
+/**
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class TemplateBuilder {
+
+ /**
+ * @var []
+ */
+ private $params = [];
+
+ /**
+ * @var Linker
+ */
+ private $linker;
+
+ /**
+ * @var string
+ */
+ private $template = '';
+
+ /**
+ * @param array $params
+ */
+ public function __construct( array $params ) {
+ $this->params = $params;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param Linker|null|false $linker
+ */
+ public function setLinker( $linker ) {
+ $this->linker = $linker;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param OutlineTree $tree
+ *
+ * @return string
+ */
+ public function build( OutlineTree $outlineTree ) {
+ $this->tree( $outlineTree );
+
+ return $this->template;
+ }
+
+ private function tree( $outlineTree, $level = 0 ) {
+
+ if ( $outlineTree->items !== null ) {
+ foreach ( $outlineTree->items as $i => $item ) {
+ $this->template .= $this->item( $i, $item );
+ }
+ }
+
+ foreach ( $outlineTree->tree as $key => $node ) {
+ $property = $this->params['outlineproperties'][$level];
+ $class = $this->params['template'] . '-section-' . strtolower( str_replace( ' ', '-', $property ) );
+
+ $this->template .= "<div class='$class'>";
+ $this->template .= $this->open( $this->params['template'] . "-header" );
+ $this->template .= $this->parameter( $property, $key );
+ $this->template .= $this->parameter( "#outlinelevel", $level );
+ $this->template .= $this->parameter( "#itemcount", $node->leafCount );
+ $this->template .= $this->parameter( "#userparam", $this->params['userparam'] );
+ $this->template .= $this->close();
+ $this->template .= "<div class='" . $this->params['template'] . "-items'>";
+ $this->tree( $node, $level + 1 );
+ $this->template .= "</div>";
+ $this->template .= "</div>";
+ }
+ }
+
+ private function item( $i, $item ) {
+
+ $first_col = true;
+ $template = '';
+ $linker = $this->params['link'] === 'all' ? $this->linker : null;
+ $itemnumber = 0;
+
+ foreach ( $item->row as $resultArray ) {
+
+ $printRequest = $resultArray->getPrintRequest();
+ $val = $printRequest->getText( SMW_OUTPUT_WIKI, null );
+
+ if ( in_array( $val, $this->params['outlineproperties'] ) ) {
+ continue;
+ }
+
+ while ( ( $dv = $resultArray->getNextDataValue() ) !== false ) {
+ $template .= $this->open( $this->params['template'] . '-item' );
+ $template .= $this->parameter( "#itemsection", $i );
+
+ $template .= $this->parameter( "#itemnumber", $itemnumber );
+ $template .= $this->parameter( "#userparam", $this->params['userparam'] );
+
+ $template .= $this->itemText( $dv, $linker, $printRequest, $first_col );
+ $template .= $this->close();
+
+ $itemnumber++;
+ }
+ }
+
+ return "<div class='" . $this->params['template'] . "-item'>" . $template . '</div>';
+ }
+
+ private function itemText( $dv, $linker, $printRequest, &$first_col ) {
+
+ if ( $first_col && $printRequest->isMode( PrintRequest::PRINT_THIS ) ) {
+ $first_col = false;
+
+ if ( $linker === null && ( $caption = $dv->getDisplayTitle() ) !== '' ) {
+ $dv->setCaption( $caption );
+ }
+
+ $text = $dv->getShortText(
+ SMW_OUTPUT_WIKI,
+ $this->params['link'] === 'subject' ? $this->linker : $linker
+ );
+
+ return $this->parameter( "#itemsubject", $text );
+ }
+
+ $text = $dv->getShortText(
+ SMW_OUTPUT_WIKI,
+ $linker
+ );
+
+ return $this->parameter( $printRequest->getLabel(), $text );
+ }
+
+ private function open( $v ) {
+ return "{{" . $v;
+ }
+
+ private function parameter( $k, $v ) {
+ return " |$k=$v";
+ }
+
+ private function close() {
+ return "}}";
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/src/ResourceFormatter.php b/www/wiki/extensions/SemanticResultFormats/src/ResourceFormatter.php
new file mode 100644
index 00000000..4f4044b0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/ResourceFormatter.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace SRF;
+
+use Html;
+use SMWOutputs as ResourceManager;
+use SMWQueryResult as QueryResult;
+
+/**
+ * @since 3.0
+ *
+ * @license GNU GPL v2 or later
+ * @author mwjames
+ */
+class ResourceFormatter {
+
+ /**
+ * @since 3.0
+ *
+ * @param array $modules
+ * @param array $styleModules
+ */
+ public static function registerResources( array $modules = [], array $styleModules = [] ) {
+
+ foreach ( $modules as $module ) {
+ ResourceManager::requireResource( $module );
+ }
+
+ foreach ( $styleModules as $styleModule ) {
+ ResourceManager::requireStyle( $styleModule );
+ }
+ }
+
+ /**
+ * @since 3.0
+ *
+ * @return string
+ */
+ public static function session() {
+ return 'smw-' . uniqid();
+ }
+
+ /**
+ * Convenience method generating a visual placeholder before any
+ * JS is registered to indicate that resources (JavaScript, CSS)
+ * are being loaded and once ready ensure to set
+ * ( '.smw-spinner' ).hide()
+ *
+ * @since 3.0
+ */
+ public static function placeholder() {
+ self::registerResources( [], [ 'ext.smw.style' ] );
+
+ return Html::rawElement(
+ 'div',
+ [ 'class' => 'srf-loading-dots' ]
+ );
+ }
+
+ /**
+ *
+ * @since 3.0
+ *
+ * @param string $id
+ * @param array $data
+ */
+ public static function encode( $id, $data ) {
+ ResourceManager::requireHeadItem(
+ $id,
+ \Skin::makeVariablesScript(
+ [
+ $id => json_encode( $data )
+ ],
+ false
+ )
+ );
+ }
+
+ /**
+ * @param QueryResult $queryResult
+ * @param $outputMode
+ *
+ * @return string
+ */
+ public static function getData( QueryResult $queryResult, $outputMode, $parameters = [] ) {
+
+ // Add parameters that are only known to the specific printer
+ $ask = $queryResult->getQuery()->toArray();
+
+ foreach ( $parameters as $key => $value ) {
+ if ( is_string( $value ) || is_integer( $value ) || is_bool( $value ) ) {
+ $ask['parameters'][$key] = $value;
+ }
+ }
+
+ // Combine all data into one object
+ $data = [
+ 'query' => [
+ 'result' => $queryResult->toArray(),
+ 'ask' => $ask
+ ]
+ ];
+
+ return $data;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/iCalendar/IcalTimezoneFormatter.php b/www/wiki/extensions/SemanticResultFormats/src/iCalendar/IcalTimezoneFormatter.php
new file mode 100644
index 00000000..5437452a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/iCalendar/IcalTimezoneFormatter.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace SRF\iCalendar;
+
+use DateTimeZone;
+use Exception;
+
+/**
+ * Create the iCalendar's vTimezone component
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author HgO
+ */
+class IcalTimezoneFormatter {
+
+ /**
+ * @var array
+ */
+ private $localTimezones = [];
+
+ /**
+ * @var array
+ */
+ private $transitions = [];
+
+ /**
+ * @var array
+ */
+ private $offsets = [];
+
+ /**
+ * @since 3.0
+ */
+ public function __construct() {
+ $this->localTimezones = [ $GLOBALS['wgLocaltimezone'] ];
+ }
+
+ /**
+ * Set a list of local timezones.
+ *
+ * @since 3.0
+ *
+ * @param array|string $localTimezones
+ */
+ public function setLocalTimezones( $localTimezones ) {
+
+ if ( is_array( $localTimezones ) ) {
+ $localTimezones = $localTimezones;
+ } elseif ( strpos( $localTimezones, ',' ) !== false ) {
+ $localTimezones = explode( ',', $localTimezones );
+ } elseif ( $localTimezones !== '' ) {
+ $localTimezones = [ $localTimezones ];
+ } else {
+ $localTimezones = [];
+ }
+
+ $this->localTimezones = $localTimezones;
+ }
+
+ /**
+ * Calculate transitions for each timezone.
+ *
+ * @since 3.0
+ *
+ * @param integer $from Timestamp from which transitions are generated.
+ * @param integer $to Timestamp until which transitions are generated.
+ *
+ * @return boolean
+ */
+ public function calcTransitions( $from = null, $to = null ) {
+
+ if ( $this->localTimezones === [] ) {
+ return false;
+ }
+
+ if ( $from === null || $to === null ) {
+ return false;
+ }
+
+ foreach ( $this->localTimezones as $timezone ) {
+ try {
+ $dateTimezone = new DateTimeZone( $timezone );
+ }
+ catch ( Exception $e ) {
+ continue;
+ }
+
+ $transitions = $dateTimezone->getTransitions( $from, $to );
+
+ if ( $transitions === false ) {
+ continue;
+ }
+
+ $min = 0;
+ $max = 1;
+
+ foreach ( $transitions as $i => $transition ) {
+ if ( $transition['ts'] < $from ) {
+ $min = $i;
+ continue;
+ }
+
+ if ( $transition['ts'] > $to ) {
+ $max = $i;
+ break;
+ }
+ }
+
+ $this->offsets[$timezone] = $transitions[max( $min - 1, 0 )]['offset'];
+ $this->transitions[$timezone] = array_slice( $transitions, $min, $max - $min );
+ }
+
+ return true;
+ }
+
+ /**
+ * Generate the transitions for a given range, for each timezones, in the
+ * iCalendar format.
+ *
+ * @since 3.0
+ *
+ * @return string
+ */
+ public function getTransitions() {
+
+ $result = '';
+
+ if ( $this->transitions === null || $this->transitions === [] ) {
+ return $result;
+ }
+
+ foreach ( $this->transitions as $timezone => $transitions ) {
+ // cf. http://www.kanzaki.com/docs/ical/vtimezone.html
+ $result .= "BEGIN:VTIMEZONE\r\n";
+ $result .= "TZID:$timezone\r\n";
+
+ $tzfrom = $this->offsets[$timezone] / 3600;
+ foreach ( $transitions as $transition ) {
+ $dst = ( $transition['isdst'] ) ? "DAYLIGHT" : "STANDARD";
+ $result .= "BEGIN:$dst\r\n";
+
+ $start_date = date( 'Ymd\THis', $transition['ts'] );
+ $result .= "DTSTART:$start_date\r\n";
+
+ $offset = $transition['offset'] / 3600;
+
+ $offset_from = $this->formatTimezoneOffset( $tzfrom );
+ $result .= "TZOFFSETFROM:$offset_from\r\n";
+
+ $offset_to = $this->formatTimezoneOffset( $offset );
+ $result .= "TZOFFSETTO:$offset_to\r\n";
+
+ if ( !empty( $transition['abbr'] ) ) {
+ $result .= "TZNAME:{$transition['abbr']}\r\n";
+ }
+
+ $result .= "END:$dst\r\n";
+
+ $tzfrom = $offset;
+ }
+
+ $result .= "END:VTIMEZONE\r\n";
+ }
+
+ // Clear the calculation
+ $this->transitions = [];
+
+ return $result;
+ }
+
+ /**
+ * Format an integer offset to '+hhii', where hh are the hours, and ii the
+ * minutes
+ *
+ * @param int $offset
+ */
+ private function formatTimezoneOffset( $offset ) {
+ return sprintf( '%s%02d%02d', $offset >= 0 ? '+' : '-', abs( floor( $offset ) ), ( $offset - floor( $offset ) ) * 60 );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/iCalendar/iCalendarFileExportPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/iCalendar/iCalendarFileExportPrinter.php
new file mode 100644
index 00000000..e13e243a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/iCalendar/iCalendarFileExportPrinter.php
@@ -0,0 +1,368 @@
+<?php
+
+namespace SRF\iCalendar;
+
+use SMW\Query\Result\ResultArray;
+use SMWDataValueFactory as DataValueFactory;
+use SMWExportPrinter as FileExportPrinter;
+use SMWQuery as Query;
+use SMWQueryProcessor as QueryProcessor;
+use SMWQueryResult as QueryResult;
+use SMWTimeValue as TimeValue;
+use WikiPage;
+
+/**
+ * Printer class for iCalendar exports
+ *
+ * @see https://en.wikipedia.org/wiki/ICalendar
+ * @see https://tools.ietf.org/html/rfc5545
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Jeroen De Dauw
+ */
+class iCalendarFileExportPrinter extends FileExportPrinter {
+
+ /**
+ * @var string
+ */
+ private $title;
+
+ /**
+ * @var string
+ */
+ private $description;
+
+ /**
+ * @var IcalTimezoneFormatter
+ */
+ private $icalTimezoneFormatter;
+
+ /**
+ * @see ResultPrinter::getName
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return wfMessage( 'srf_printername_icalendar' )->text();
+ }
+
+ /**
+ * @see FileExportPrinter::getMimeType
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getMimeType( QueryResult $queryResult ) {
+ return 'text/calendar';
+ }
+
+ /**
+ * @see FileExportPrinter::getFileName
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getFileName( QueryResult $queryResult ) {
+
+ if ( $this->title != '' ) {
+ return str_replace( ' ', '_', $this->title ) . '.ics';
+ }
+
+ return 'iCalendar.ics';
+ }
+
+ /**
+ * @see FileExportPrinter::getQueryMode
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getQueryMode( $context ) {
+ return ( $context == QueryProcessor::SPECIAL_PAGE ) ? Query::MODE_INSTANCES : Query::MODE_NONE;
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['title'] = [
+ 'default' => '',
+ 'message' => 'srf_paramdesc_icalendartitle',
+ ];
+
+ $params['description'] = [
+ 'default' => '',
+ 'message' => 'srf_paramdesc_icalendardescription',
+ ];
+
+ $params['timezone'] = [
+ 'default' => '',
+ 'message' => 'srf-paramdesc-icalendar-timezone',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @see ResultPrinter::handleParameters
+ *
+ * {@inheritDoc}
+ */
+ protected function handleParameters( array $params, $outputMode ) {
+ parent::handleParameters( $params, $outputMode );
+
+ $this->title = trim( $params['title'] );
+ $this->description = trim( $params['description'] );
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ *
+ * {@inheritDoc}
+ */
+ protected function getResultText( QueryResult $res, $outputMode ) {
+
+ if ( $outputMode == SMW_OUTPUT_FILE ) {
+ return $this->getIcal( $res );
+ }
+
+ return $this->getIcalLink( $res, $outputMode );
+ }
+
+ /**
+ * Returns the query result in iCal.
+ */
+ private function getIcal( QueryResult $res ) {
+
+ $this->icalTimezoneFormatter = new IcalTimezoneFormatter();
+
+ $this->icalTimezoneFormatter->setLocalTimezones(
+ isset( $this->params['timezone'] ) ? $this->params['timezone'] : []
+ );
+
+ $result = '';
+
+ if ( $this->title == '' ) {
+ $this->title = $GLOBALS['wgSitename'];
+ }
+
+ $result .= "BEGIN:VCALENDAR\r\n";
+ $result .= "PRODID:-//SMW Project//Semantic Result Formats\r\n";
+ $result .= "VERSION:2.0\r\n";
+ $result .= "METHOD:PUBLISH\r\n";
+ $result .= "X-WR-CALNAME:" . $this->title . "\r\n";
+
+ if ( $this->description !== '' ) {
+ $result .= "X-WR-CALDESC:" . $this->description . "\r\n";
+ }
+
+ $events = '';
+
+ while ( $row = $res->getNext() ) {
+ $events .= $this->getIcalForItem( $row );
+ }
+
+ $result .= $this->icalTimezoneFormatter->getTransitions();
+ $result .= $events;
+ $result .= "END:VCALENDAR\r\n";
+
+ return $result;
+ }
+
+ /**
+ * Returns html for a link to a query that returns the iCal.
+ */
+ private function getIcalLink( QueryResult $res, $outputMode ) {
+
+ if ( $this->getSearchLabel( $outputMode ) ) {
+ $label = $this->getSearchLabel( $outputMode );
+ } else {
+ $label = wfMessage( 'srf_icalendar_link' )->inContentLanguage()->text();
+ }
+
+ $link = $res->getQueryLink( $label );
+ $link->setParameter( 'icalendar', 'format' );
+
+ if ( $this->title !== '' ) {
+ $link->setParameter( $this->title, 'title' );
+ }
+
+ if ( $this->description !== '' ) {
+ $link->setParameter( $this->description, 'description' );
+ }
+
+ if ( array_key_exists( 'limit', $this->params ) ) {
+ $link->setParameter( $this->params['limit'], 'limit' );
+ } else { // use a reasonable default limit
+ $link->setParameter( 20, 'limit' );
+ }
+
+ // yes, our code can be viewed as HTML if requested, no more parsing needed
+ $this->isHTML = ( $outputMode == SMW_OUTPUT_HTML );
+
+ return $link->getText( $outputMode, $this->mLinker );
+ }
+
+ /**
+ * Returns the iCal for a single item.
+ *
+ * @param ResultArray[] $row
+ *
+ * @return string
+ * @throws \MWException
+ */
+ private function getIcalForItem( array $row ) {
+ $result = '';
+
+ $subjectDI = $row[0]->getResultSubject(); // get the object
+ $subjectDV = DataValueFactory::getInstance()->newDataValueByItem( $subjectDI, null );
+
+ $params = [
+ 'summary' => $subjectDV->getShortWikiText()
+ ];
+
+ $from = null;
+ $to = null;
+ foreach ( $row as /* SMWResultArray */
+ $field ) {
+ // later we may add more things like a generic
+ // mechanism to add whatever you want :)
+ // could include funny things like geo, description etc. though
+ $req = $field->getPrintRequest();
+ $label = strtolower( $req->getLabel() );
+
+ switch ( $label ) {
+ case 'start':
+ case 'end':
+ if ( $req->getTypeID() == '_dat' ) {
+ $dataValue = $field->getNextDataValue();
+
+ if ( $dataValue === false ) {
+ unset( $params[$label] );
+ } else {
+ $params[$label] = $this->parsedate( $dataValue, $label == 'end' );
+
+ $timestamp = strtotime( $params[$label] );
+ if ( $from === null || $timestamp < $from ) {
+ $from = $timestamp;
+ }
+ if ( $to === null || $timestamp > $to ) {
+ $to = $timestamp;
+ }
+ }
+ }
+ break;
+ case 'location':
+ case 'description':
+ case 'summary':
+ $value = $field->getNextDataValue();
+ if ( $value !== false ) {
+ $params[$label] = $value->getShortWikiText();
+ }
+ break;
+ }
+ }
+
+ $this->icalTimezoneFormatter->calcTransitions( $from, $to );
+
+ $title = $subjectDI->getTitle();
+ $timestamp = WikiPage::factory( $title )->getTimestamp();
+ $url = $title->getFullURL();
+
+ $result .= "BEGIN:VEVENT\r\n";
+ $result .= "SUMMARY:" . $this->escape( $params['summary'] ) . "\r\n";
+ $result .= "URL:$url\r\n";
+ $result .= "UID:$url\r\n";
+
+ if ( array_key_exists( 'start', $params ) ) {
+ $result .= "DTSTART:" . $params['start'] . "\r\n";
+ }
+
+ if ( array_key_exists( 'end', $params ) ) {
+ $result .= "DTEND:" . $params['end'] . "\r\n";
+ }
+
+ if ( array_key_exists( 'location', $params ) ) {
+ $result .= "LOCATION:" . $this->escape( $params['location'] ) . "\r\n";
+ }
+
+ if ( array_key_exists( 'description', $params ) ) {
+ $result .= "DESCRIPTION:" . $this->escape( $params['description'] ) . "\r\n";
+ }
+
+ $t = strtotime( str_replace( 'T', ' ', $timestamp ) );
+ $result .= "DTSTAMP:" . date( "Ymd", $t ) . "T" . date( "His", $t ) . "\r\n";
+ $result .= "SEQUENCE:" . $title->getLatestRevID() . "\r\n";
+ $result .= "END:VEVENT\r\n";
+
+ return $result;
+ }
+
+ /**
+ * Extract a date string formatted for iCalendar from a SMWTimeValue object.
+ */
+ private function parsedate( TimeValue $dv, $isend = false ) {
+ $year = $dv->getYear();
+
+ // ISO range is limited to four digits
+ if ( ( $year > 9999 ) || ( $year < -9998 ) ) {
+ return '';
+ }
+
+ $year = number_format( $year, 0, '.', '' );
+ $time = str_replace( ':', '', $dv->getTimeString( false ) );
+
+ // increment by one day, compute date to cover leap years etc.
+ if ( ( $time == false ) && ( $isend ) ) {
+ $dv = DataValueFactoryg::getInstance()->newDataValueByType(
+ '_dat',
+ $dv->getWikiValue() . 'T00:00:00-24:00'
+ );
+ }
+
+ $month = $dv->getMonth();
+
+ if ( strlen( $month ) == 1 ) {
+ $month = '0' . $month;
+ }
+
+ $day = $dv->getDay();
+
+ if ( strlen( $day ) == 1 ) {
+ $day = '0' . $day;
+ }
+
+ $result = $year . $month . $day;
+
+ if ( $time != false ) {
+ $result .= "T$time";
+ }
+
+ return $result;
+ }
+
+ /**
+ * Implements esaping of special characters for iCalendar properties of type
+ * TEXT. This is defined in RFC2445 Section 4.3.11.
+ */
+ private function escape( $text ) {
+ // Note that \\ is a PHP escaped single \ here
+ return str_replace( [ "\\", "\n", ";", "," ], [ "\\\\", "\\n", "\\;", "\\," ], $text );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/vCard/Address.php b/www/wiki/extensions/SemanticResultFormats/src/vCard/Address.php
new file mode 100644
index 00000000..9145bb21
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/vCard/Address.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace SRF\vCard;
+
+/**
+ * Represents a single address entry in an vCard
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/vCard
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ */
+class Address {
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @var array
+ */
+ private $adr = [];
+
+ /**
+ * @param string $type
+ * @param array $adr
+ */
+ public function __construct( $type, array $adr = [] ) {
+ $this->type = $type;
+ $this->adr = $adr;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @return boolean
+ */
+ public function hasAddress() {
+ return $this->adr !== [];
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param string $key
+ * @param string $value
+ */
+ public function set( $key, $value ) {
+ $this->adr[$key] = $value;
+ }
+
+ /**
+ * @return string
+ */
+ public function text() {
+
+ if ( $this->type == "" ) {
+ $this->type = "WORK";
+ }
+
+ $adr = [];
+
+ // Expected sequence as defined by
+ // https://tools.ietf.org/html/rfc6350#section-6.3.1
+ $map = [
+ 'pobox',
+ 'ext',
+ 'street',
+ 'locality',
+ 'region',
+ 'code',
+ 'country'
+ ];
+
+ foreach ( $map as $k ) {
+ $adr[] = isset( $this->adr[$k] ) ? vCard::escape( $this->adr[$k] ) : '';
+ }
+
+ return "ADR;TYPE=$this->type;CHARSET=UTF-8:" . implode( ';', $adr ) . "\r\n";
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/vCard/Email.php b/www/wiki/extensions/SemanticResultFormats/src/vCard/Email.php
new file mode 100644
index 00000000..908c6cf9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/vCard/Email.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace SRF\vCard;
+
+/**
+ * Represents a single email entry in an vCard entry.
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/vCard
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ */
+class Email {
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @var string
+ */
+ private $emailaddress;
+
+ /**
+ * @param string $type
+ * @param string $emailaddress
+ */
+ public function __construct( $type, $emailaddress ) {
+ $this->type = $type;
+ $this->emailaddress = $emailaddress; // no escape, normally not needed anyway
+ }
+
+ /**
+ * Creates the vCard output for a single email item.
+ */
+ public function text() {
+
+ if ( $this->type == "" ) {
+ $this->type = "INTERNET";
+ }
+
+ return "EMAIL;TYPE=$this->type:$this->emailaddress\r\n";
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/src/vCard/Tel.php b/www/wiki/extensions/SemanticResultFormats/src/vCard/Tel.php
new file mode 100644
index 00000000..15d84c92
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/vCard/Tel.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace SRF\vCard;
+
+/**
+ * Represents a single telephone entry in an vCard entry.
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/vCard
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ */
+class Tel {
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @var string
+ */
+ private $telnumber;
+
+ /**
+ * @param string $type
+ * @param string $telnumber
+ */
+ public function __construct( $type, $telnumber ) {
+ $this->type = $type; // may be a vCard value list using ",", no escaping
+ $this->telnumber = vCard::escape( $telnumber ); // escape to be sure
+ }
+
+ /**
+ * Creates the vCard output for a single telephone item.
+ */
+ public function text() {
+
+ if ( $this->type == "" ) {
+ $this->type = "WORK";
+ }
+
+ return "TEL;TYPE=$this->type:$this->telnumber\r\n";
+ }
+
+}
+
diff --git a/www/wiki/extensions/SemanticResultFormats/src/vCard/vCard.php b/www/wiki/extensions/SemanticResultFormats/src/vCard/vCard.php
new file mode 100644
index 00000000..e5d6e0f9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/vCard/vCard.php
@@ -0,0 +1,250 @@
+<?php
+
+namespace SRF\vCard;
+
+use Article;
+use Title;
+
+/**
+ * Represents a single entry in an vCard
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/vCard
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ */
+class vCard {
+
+ /**
+ * @var string
+ */
+ private $uri;
+
+ /**
+ * @var string
+ */
+ private $text;
+
+ /**
+ * @var array
+ */
+ private $vcard = [];
+
+ /**
+ * @var boolean
+ */
+ private $isPublic = true;
+
+ /**
+ * @var integer
+ */
+ private $timestamp;
+
+ /**
+ * @since 3.0
+ *
+ * @param string $uri
+ * @param string $text
+ * @param array $vcard
+ */
+ public function __construct( $uri, $text, array $vcard ) {
+ $this->uri = $uri;
+ $this->text = $text;
+
+ $default = [
+ 'prefix' => '',
+ 'firstname' => '',
+ 'lastname' => '',
+ 'additionalname' => '',
+ 'suffix' => '',
+ 'fullname' => '',
+ 'tel' => [],
+ 'address' => [],
+ 'email' => [],
+ 'birthday' => '',
+ 'title' => '',
+ 'role' => '',
+ 'organization' => '',
+ 'department' => '',
+ 'category' => '',
+ 'url' => '',
+ 'note' => ''
+ ];
+
+ $this->vcard = $vcard + $default;
+ }
+
+ /**
+ * @since 3.1
+ *
+ * @param string $key
+ * @param string $value
+ */
+ public function set( $key, $value ) {
+ $this->vcard[$key] = $value;
+ }
+
+ /**
+ * @since 3.0
+ *
+ * @param boolean $isPublic
+ */
+ public function isPublic( $isPublic ) {
+ $this->isPublic = $isPublic;
+ }
+
+ /**
+ * @since 3.0
+ *
+ * @param integer $timestamp
+ */
+ public function setTimestamp( $timestamp ) {
+ $this->timestamp = $timestamp;
+ }
+
+ /**
+ * Creates the vCard output for a single item.
+ *
+ * @return string
+ */
+ public function text() {
+
+ $vcard = $this->prepareCard( $this->vcard );
+
+ $text = "BEGIN:VCARD\r\n";
+ $text .= "VERSION:3.0\r\n";
+
+ // N and FN are required properties in vCard 3.0, we need to write something there
+ $text .= "N;CHARSET=UTF-8:" .
+ $vcard['lastname'] . ';' .
+ $vcard['firstname'] . ';' .
+ $vcard['additionalname'] . ';' .
+ $vcard['prefix'] . ';' .
+ $vcard['suffix'] . "\r\n";
+
+ $text .= "FN;CHARSET=UTF-8:" .
+ $vcard['label'] . "\r\n";
+
+ $text .= ( $this->isPublic ? 'CLASS:PUBLIC' : 'CLASS:CONFIDENTIAL' ) . "\r\n";
+
+ if ( $vcard['birthday'] !== "" ) {
+ $text .= "BDAY:" . $vcard['birthday'] . "\r\n";
+ }
+
+ if ( $vcard['title'] !== "" ) {
+ $text .= "TITLE;CHARSET=UTF-8:" . $vcard['title'] . "\r\n";
+ }
+
+ if ( $vcard['role'] !== "" ) {
+ $text .= "ROLE;CHARSET=UTF-8:" . $vcard['role'] . "\r\n";
+ }
+
+ if ( $vcard['organization'] !== "" ) {
+ $text .= "ORG;CHARSET=UTF-8:" . $vcard['organization'] . ';' . $vcard['department'] . "\r\n";
+ }
+
+ if ( $vcard['category'] !== "" ) {
+ $text .= "CATEGORIES;CHARSET=UTF-8:" . $vcard['category'] . "\r\n";
+ }
+
+ foreach ( $vcard['email'] as $e ) {
+ $text .= $e->text();
+ }
+
+ foreach ( $vcard['address'] as $a ) {
+ if ( $a->hasAddress() ) {
+ $text .= $a->text();
+ }
+ }
+
+ foreach ( $vcard['tel'] as $t ) {
+ $text .= $t->text();
+ }
+
+ if ( $vcard['note'] !== "" ) {
+ $text .= "NOTE;CHARSET=UTF-8:" . $vcard['note'] . "\r\n";
+ }
+
+ $text .= "SOURCE;CHARSET=UTF-8:$this->uri\r\n";
+
+ // The identifier for the product that created the vCard object
+ $text .= "PRODID:-////Semantic MediaWiki\r\n";
+
+ // A timestamp for the last time the vCard was updated
+ $text .= "REV:$this->timestamp\r\n";
+
+ // A URL pointing to a website that represents the person in some way
+ $text .= "URL:" . ( $vcard['url'] !== "" ? $vcard['url'] : $this->uri ) . "\r\n";
+
+ // Specifies a value that represents a persistent, globally unique
+ // identifier associated with the object.
+ $text .= "UID:$this->uri\r\n";
+ $text .= "END:VCARD\r\n";
+
+ return $text;
+ }
+
+ public static function escape( $text ) {
+ return str_replace( [ '\\', ',', ':', ';' ], [ '\\\\', '\,', '\:', '\;' ], $text );
+ }
+
+ private function prepareCard( $vcard ) {
+
+ $vcard['label'] = '';
+
+ $additionalname = $vcard['additionalname'];
+
+ // Read fullname or guess it in a simple way from other names that are
+ // given
+ if ( $vcard['fullname'] != '' ) {
+ $vcard['label'] = $vcard['fullname'];
+ } elseif ( $vcard['firstname'] . $vcard['lastname'] != '' ) {
+ $vcard['label'] = $vcard['firstname'] . ( ( ( $vcard['firstname'] != '' ) && ( $vcard['lastname'] != '' ) ) ? ' ' : '' ) . $vcard['lastname'];
+ } else {
+ $vcard['label'] = $this->text;
+ }
+
+ $vcard['label'] = self::escape( $vcard['label'] );
+
+ // read firstname and lastname, or guess it from other names that are given
+ if ( $vcard['firstname'] . $vcard['lastname'] == '' ) { // guessing needed
+ $nameparts = explode( ' ', $vcard['label'] );
+ // Accepted forms for guessing:
+ // "Lastname"
+ // "Firstname Lastname"
+ // "Firstname <Additionalnames> Lastname"
+ $vcard['lastname'] = self::escape( array_pop( $nameparts ) );
+
+ if ( count( $nameparts ) > 0 ) {
+ $vcard['firstname'] = self::escape( array_shift( $nameparts ) );
+ }
+
+ foreach ( $nameparts as $name ) {
+ $vcard['additionalname'] .= ( $vcard['additionalname'] != '' ? ',' : '' ) . self::escape( $name );
+ }
+ } else {
+ $vcard['firstname'] = self::escape( $vcard['firstname'] );
+ $vcard['lastname'] = self::escape( $vcard['lastname'] );
+ }
+
+ // no escape, can be a value list
+ if ( $additionalname != '' ) {
+ $vcard['additionalname'] = $additionalname;
+ }
+
+ $vcard['prefix'] = self::escape( $vcard['prefix'] );
+ $vcard['suffix'] = self::escape( $vcard['suffix'] );
+ $vcard['title'] = self::escape( $vcard['title'] );
+ $vcard['role'] = self::escape( $vcard['role'] );
+ $vcard['organization'] = self::escape( $vcard['organization'] );
+ $vcard['department'] = self::escape( $vcard['department'] );
+ $vcard['note'] = self::escape( $vcard['note'] );
+
+ return $vcard;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/src/vCard/vCardFileExportPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/vCard/vCardFileExportPrinter.php
new file mode 100644
index 00000000..6ca75fad
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/src/vCard/vCardFileExportPrinter.php
@@ -0,0 +1,433 @@
+<?php
+
+namespace SRF\vCard;
+
+use SMWExportPrinter as FileExportPrinter;
+use SMWQuery as Query;
+use SMWQueryProcessor as QueryProcessor;
+use SMWQueryResult as QueryResult;
+use SMWTimeValue as TimeValue;
+use WikiPage;
+
+/**
+ * Printer class for creating vCard exports
+ *
+ * @see http://www.semantic-mediawiki.org/wiki/vCard
+ * @see https://tools.ietf.org/html/rfc6350
+ * @see https://www.w3.org/2002/12/cal/vcard-notes.html
+ *
+ * @license GNU GPL v2+
+ * @since 1.5
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author Frank Dengler
+ * @author mwjames
+ */
+class vCardFileExportPrinter extends FileExportPrinter {
+
+ /**
+ * @see FileExportPrinter::getName
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return wfMessage( 'srf_printername_vcard' )->text();
+ }
+
+ /**
+ * @see FileExportPrinter::getMimeType
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getMimeType( QueryResult $queryResult ) {
+ return 'text/x-vcard';
+ }
+
+ /**
+ * @see FileExportPrinter::getFileName
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getFileName( QueryResult $queryResult ) {
+
+ if ( $this->params['filename'] !== '' ) {
+
+ if ( strpos( $this->params['filename'], '.vcf' ) === false ) {
+ $this->params['filename'] .= '.vcf';
+ }
+
+ return str_replace( ' ', '_', $this->params['filename'] );
+ } elseif ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) {
+ return str_replace( ' ', '_', $this->getSearchLabel( SMW_OUTPUT_WIKI ) ) . '.vcf';
+ }
+
+ return 'vCard.vcf';
+ }
+
+ /**
+ * @see FileExportPrinter::getQueryMode
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getQueryMode( $context ) {
+ return ( $context == QueryProcessor::SPECIAL_PAGE ) ? Query::MODE_INSTANCES : Query::MODE_NONE;
+ }
+
+ /**
+ * @see ResultPrinter::getParamDefinitions
+ *
+ * @since 1.8
+ *
+ * {@inheritDoc}
+ */
+ public function getParamDefinitions( array $definitions ) {
+ $params = parent::getParamDefinitions( $definitions );
+
+ $params['filename'] = [
+ 'message' => 'smw-paramdesc-filename',
+ 'default' => 'vCard.vcf',
+ ];
+
+ return $params;
+ }
+
+ /**
+ * @see ResultPrinter::getResultText
+ */
+ protected function getResultText( QueryResult $res, $outputMode ) {
+
+ // Always return a link for when the output mode is not a file request,
+ // a file request is normally only initiated when resolving the query
+ // via Special:Ask
+ if ( $outputMode !== SMW_OUTPUT_FILE ) {
+ return $this->getVCardLink( $res, $outputMode );
+ }
+
+ return $this->getVCardContent( $res );
+ }
+
+ private function getVCardLink( QueryResult $res, $outputMode ) {
+
+ // Can be viewed as HTML if requested, no more parsing needed
+ $this->isHTML = $outputMode == SMW_OUTPUT_HTML;
+
+ if ( $this->getSearchLabel( $outputMode ) ) {
+ $label = $this->getSearchLabel( $outputMode );
+ } else {
+ $label = wfMessage( 'srf_vcard_link' )->inContentLanguage()->text();
+ }
+
+ $link = $res->getQueryLink( $label );
+ $link->setParameter( 'vcard', 'format' );
+
+ if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) {
+ $link->setParameter( $this->getSearchLabel( SMW_OUTPUT_WIKI ), 'searchlabel' );
+ }
+
+ if ( array_key_exists( 'limit', $this->params ) ) {
+ $link->setParameter( $this->params['limit'], 'limit' );
+ } else { // use a reasonable default limit
+ $link->setParameter( 20, 'limit' );
+ }
+
+ return $link->getText( $outputMode, $this->mLinker );
+ }
+
+ /**
+ * @param QueryResult $res
+ *
+ * @return string
+ * @throws \MWException
+ */
+ private function getVCardContent( $res ) {
+
+ $result = '';
+ $vCards = [];
+
+ $row = $res->getNext();
+ $isPublic = $this->isPublic();
+
+ while ( $row !== false ) {
+ // Subject of the Result
+ $subject = $row[0]->getResultSubject();
+ $title = $subject->getTitle();
+
+ // Specifies a value that represents a persistent, globally unique
+ // identifier associated with the object.
+ $uri = $title->getFullURL();
+
+ // A timestamp for the last time the vCard was updated
+ $timestamp = WikiPage::factory( $title )->getTimestamp();
+ $text = $title->getText();
+
+ $vCards[] = $this->newVCard( $row, $uri, $text, $timestamp, $isPublic );
+ $row = $res->getNext();
+ }
+
+ foreach ( $vCards as $vCard ) {
+ $result .= $vCard->text();
+ }
+
+ return $result;
+ }
+
+ private function newVCard( $row, $uri, $text, $timestamp, $isPublic ) {
+
+ $vCard = new vCard(
+ $uri,
+ $text,
+ [
+
+ // something like 'Dr.'
+ 'prefix' => '',
+
+ // given name
+ 'firstname' => '',
+
+ // family name
+ 'lastname' => '',
+
+ // typically the "middle" name (second first name)
+ 'additionalname' => '',
+
+ // things like "jun." or "sen."
+ 'suffix' => '',
+
+ // the "formatted name", may be independent from
+ // first/lastname & co.
+ 'fullname' => '',
+
+ 'tel' => [],
+ 'address' => [],
+ 'email' => [],
+ // a date
+ 'birthday' => '',
+
+ // organisational details
+ 'organization' => '',
+ 'department' => '',
+ 'title' => '',
+ 'role' => '',
+ 'category' => '',
+
+ // homepage, a legal URL
+ 'url' => '',
+
+ // any text
+ 'note' => ''
+ ]
+ );
+
+ $tels = [];
+ $emails = [];
+
+ $addresses['work'] = new Address( 'WORK' );
+ $addresses['home'] = new Address( 'HOME' );
+
+ foreach ( $row as $field ) {
+ $this->mapField( $field, $vCard, $tels, $addresses, $emails );
+ }
+
+ $vCard->set( 'tel', $tels );
+ $vCard->set( 'address', $addresses );
+ $vCard->set( 'email', $emails );
+
+ $vCard->isPublic( $isPublic );
+ $vCard->setTimestamp( $timestamp );
+
+ return $vCard;
+ }
+
+ private function isPublic() {
+ // heuristic for setting confidentiality level of vCard:
+ global $wgGroupPermissions;
+
+ if ( ( array_key_exists( '*', $wgGroupPermissions ) ) && ( array_key_exists(
+ 'read',
+ $wgGroupPermissions['*']
+ ) ) ) {
+ return $wgGroupPermissions['*']['read'];
+ }
+
+ return true;
+ }
+
+ private function mapField( $field, $vCard, &$tels, &$addresses, &$emails ) {
+
+ $printRequest = $field->getPrintRequest();
+
+ switch ( strtolower( $printRequest->getLabel() ) ) {
+ case "name":
+ $vCard->set( 'fullname', $this->getFieldValue( $field ) );
+ break;
+ case "prefix":
+ $vCard->set( 'prefix', $this->getFieldCommaList( $field ) );
+ break;
+ case "suffix":
+ $vCard->set( 'suffix', $this->getFieldCommaList( $field ) );
+ break;
+ case "firstname":
+ // save only the first
+ $vCard->set( 'firstname', $this->getFieldValue( $field ) );
+ break;
+ case "additionalname":
+ case "extraname":
+ $vCard->set( 'additionalname', $this->getFieldCommaList( $field ) );
+ break;
+ case "lastname":
+ // save only the first
+ $vCard->set( 'lastname', $this->getFieldValue( $field ) );
+ break;
+ case "note":
+ $vCard->set( 'note', $this->getFieldCommaList( $field ) );
+ break;
+ case "category":
+ $vCard->set( 'category', $this->getFieldCommaList( $field ) );
+ case "email":
+ while ( $value = $field->getNextDataValue() ) {
+ $emails[] = new Email( 'INTERNET', $value->getShortWikiText() );
+ }
+ break;
+ case "workphone":
+ while ( $value = $field->getNextDataValue() ) {
+ $tels[] = new Tel( 'WORK', $value->getShortWikiText() );
+ }
+ break;
+ case "cellphone":
+ while ( $value = $field->getNextDataValue() ) {
+ $tels[] = new Tel( 'CELL', $value->getShortWikiText() );
+ }
+ break;
+ case "homephone":
+ while ( $value = $field->getNextDataValue() ) {
+ $tels[] = new Tel( 'HOME', $value->getShortWikiText() );
+ }
+ break;
+ case "organization":
+ $vCard->set( 'organization', $this->getFieldValue( $field ) );
+ break;
+ case "workpostofficebox":
+ if ( ( $workpostofficebox = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'pobox', $workpostofficebox );
+ }
+ break;
+ case "workextendedaddress":
+ if ( ( $workextendedaddress = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'ext', $workextendedaddress );
+ }
+ break;
+ case "workstreet":
+ if ( ( $workstreet = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'street', $workstreet );
+ }
+ break;
+ case "worklocality":
+ if ( ( $worklocality = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'locality', $worklocality );
+ }
+ break;
+ case "workregion":
+ if ( ( $workregion = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'region', $workregion );
+ }
+ break;
+ case "workpostalcode":
+ if ( ( $workpostalcode = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'code', $workpostalcode );
+ }
+ break;
+ case "workcountry":
+ if ( ( $workcountry = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['work']->set( 'country', $workcountry );
+ }
+ break;
+ case "homepostofficebox":
+ if ( ( $homepostofficebox = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'pobox', $homepostofficebox );
+ }
+ break;
+ case "homeextendedaddress":
+ if ( ( $homeextendedaddress = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'ext', $homeextendedaddress );
+ }
+ break;
+ case "homestreet":
+ if ( ( $homestreet = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'street', $homestreet );
+ }
+ break;
+ case "homelocality":
+ if ( ( $homelocality = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'locality', $homelocality );
+ }
+ break;
+ case "homeregion":
+ if ( ( $homeregion = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'region', $homeregion );
+ }
+ break;
+ case "homepostalcode":
+ if ( ( $homepostalcode = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'code', $homepostalcode );
+ }
+ break;
+ case "homecountry":
+ if ( ( $homecountry = $this->getFieldValue( $field ) ) !== '' ) {
+ $addresses['home']->set( 'country', $homecountry );
+ }
+ break;
+ case "birthday":
+ if ( $printRequest->getTypeID() == TimeValue::TYPE_ID ) {
+ $value = $field->getNextDataValue();
+
+ if ( $value !== false ) {
+ $birthday = $value->getISO8601Date();
+ $vCard->set( 'birthday', $birthday );
+ }
+ }
+ break;
+ case "homepage":
+ if ( $printRequest->getTypeID() == "_uri" ) {
+ $value = $field->getNextDataValue();
+
+ if ( $value !== false ) {
+ $url = $value->getWikiValue();
+ $vCard->set( 'url', $url );
+ }
+ }
+ break;
+ }
+ }
+
+ private function getFieldCommaList( $field ) {
+
+ $list = '';
+
+ while ( $value = $field->getNextDataValue() ) {
+ $list .= ( $list ? ',' : '' ) . $value->getShortWikiText();
+ }
+
+ return $list;
+ }
+
+ private function getFieldValue( $field ) {
+
+ $v = '';
+
+ if ( ( $value = $field->getNextDataValue() ) !== false ) {
+ $v = $value->getShortWikiText();
+ }
+
+ return $v;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/bootstrap.php b/www/wiki/extensions/SemanticResultFormats/tests/bootstrap.php
new file mode 100644
index 00000000..b8d09067
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/bootstrap.php
@@ -0,0 +1,20 @@
+<?php
+
+if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
+ die( 'Not an entry point' );
+}
+
+if ( !is_readable( $path = __DIR__ . '/../../SemanticMediaWiki/tests/autoloader.php' ) ) {
+ die( 'The SemanticMediaWiki test autoloader is not available' );
+}
+
+print sprintf( "\n%-20s%s\n", "Semantic Result Formats: ", SRF_VERSION );
+
+$autoloader = require $path;
+$autoloader->addPsr4( 'SRF\\Tests\\', __DIR__ . '/phpunit' );
+$autoloader->addPsr4( 'SMW\\Test\\', __DIR__ . '/../../SemanticMediaWiki/tests/phpunit' );
+$autoloader->addPsr4( 'SMW\\Tests\\', __DIR__ . '/../../SemanticMediaWiki/tests/phpunit' );
+
+$autoloader->addClassMap( [
+ 'SRF\Tests\ResultPrinterReflector' => __DIR__ . '/phpunit/ResultPrinterReflector.php',
+] );
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/I18nJsonFileIntegrityTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/I18nJsonFileIntegrityTest.php
new file mode 100644
index 00000000..a676f6b7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/I18nJsonFileIntegrityTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace SRF\Tests\Integration;
+
+use SMW\Tests\Utils\UtilityFactory;
+
+/**
+ * @group SRF
+ * @group SMWExtension
+ *
+ * @license GNU GPL v2+
+ * @since 2.5
+ *
+ * @author mwjames
+ */
+class I18nJsonFileIntegrityTest extends \PHPUnit_Framework_TestCase {
+
+ /**
+ * @dataProvider i18nFileProvider
+ */
+ public function testI18NJsonDecodeEncode( $file ) {
+
+ $jsonFileReader = UtilityFactory::getInstance()->newJsonFileReader( $file );
+
+ $this->assertInternalType(
+ 'integer',
+ $jsonFileReader->getModificationTime()
+ );
+
+ $this->assertInternalType(
+ 'array',
+ $jsonFileReader->read()
+ );
+ }
+
+ public function i18nFileProvider() {
+
+ $provider = [];
+ $location = $GLOBALS['wgMessagesDirs']['SemanticResultFormats'];
+
+ $bulkFileProvider = UtilityFactory::getInstance()->newBulkFileProvider( $location );
+ $bulkFileProvider->searchByFileExtension( 'json' );
+
+ foreach ( $bulkFileProvider->getFiles() as $file ) {
+ $provider[basename( $file )] = [ $file ];
+ }
+
+ asort( $provider );
+ return $provider;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-0.bib b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-0.bib
new file mode 100644
index 00000000..6f076aef
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-0.bib
@@ -0,0 +1,2 @@
+@Book{,
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-1.bib b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-1.bib
new file mode 100644
index 00000000..8c65f8f1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-1.bib
@@ -0,0 +1,10 @@
+@Incollection{maskin1985ttoiineas,
+ address = "Cambridge",
+ author = "Eric S. Maskin",
+ booktitle = "Social Goals and Social Organization",
+ editor = "Leonid Hurwicz, David Schmeidler and Hugo Sonnenschein",
+ pages = "173-204",
+ publisher = "Cambridge University Press",
+ title = "The theory of implementation in nash equilibrium: a survey",
+ year = "1985",
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-2.bib b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-2.bib
new file mode 100644
index 00000000..5a1d6c5a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-2.bib
@@ -0,0 +1,8 @@
+@Book{abramowitz1964homf,
+ address = "New York",
+ author = "Milton Abramowitz and Irene A. Stegun",
+ edition = "ninth Dover printing, tenth GPO printing",
+ publisher = "Dover",
+ title = "Handbook of Mathematical Functions",
+ year = "1964",
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-3.bib b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-3.bib
new file mode 100644
index 00000000..b5602c23
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/bibtex-01-3.bib
@@ -0,0 +1,16 @@
+@Book{maskin1985ttoiineas,
+ address = "Cambridge",
+ author = "Eric S. Maskin",
+ publisher = "Cambridge University Press",
+ title = "The theory of implementation in nash equilibrium: a survey",
+ year = "1985",
+}
+
+@Book{abramowitz1964homf,
+ address = "New York",
+ author = "Milton Abramowitz and Irene A. Stegun",
+ edition = "ninth Dover printing, tenth GPO printing",
+ publisher = "Dover",
+ title = "Handbook of Mathematical Functions",
+ year = "1964",
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-01.1.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-01.1.txt
new file mode 100644
index 00000000..5537abc5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-01.1.txt
@@ -0,0 +1,14 @@
+BEGIN:VCALENDAR
+PRODID:-//SMW Project//Semantic Result Formats
+VERSION:2.0
+METHOD:PUBLISH
+X-WR-CALNAME:.*
+X-WR-CALDESC:Simple description
+BEGIN:VEVENT
+SUMMARY:Example/ICalendar-01/1
+URL:.*/Example/ICalendar-01/1
+UID:.*/Example/ICalendar-01/1
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+END:VCALENDAR \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-02.0.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-02.0.txt
new file mode 100644
index 00000000..63ef744e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-02.0.txt
@@ -0,0 +1,28 @@
+BEGIN:VCALENDAR
+PRODID:-//SMW Project//Semantic Result Formats
+VERSION:2.0
+METHOD:PUBLISH
+X-WR-CALNAME:.*
+X-WR-CALDESC:Simple description
+BEGIN:VEVENT
+SUMMARY:A
+URL:.*/Example/ICalendar-02/1
+UID:.*/Example/ICalendar-02/1
+DTSTART:19700101
+LOCATION:LOC-A
+DESCRIPTION:Something about A
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:B
+URL:.*/Example/ICalendar-02/2
+UID:.*/Example/ICalendar-02/2
+DTSTART:19700102T120000
+DTEND:19700102T150000
+LOCATION:LOC-B
+DESCRIPTION:Something about B
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+END:VCALENDAR
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.0.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.0.txt
new file mode 100644
index 00000000..f942fbec
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.0.txt
@@ -0,0 +1,37 @@
+BEGIN:VCALENDAR
+PRODID:-//SMW Project//Semantic Result Formats
+VERSION:2.0
+METHOD:PUBLISH
+X-WR-CALNAME:.*
+X-WR-CALDESC:Simple description
+BEGIN:VTIMEZONE
+TZID:UTC
+BEGIN:STANDARD
+DTSTART:.*
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0000
+TZNAME:UTC
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+SUMMARY:A
+URL:.*/Example/ICalendar-03/1
+UID:.*/Example/ICalendar-03/1
+DTSTART:19700101
+LOCATION:LOC-A
+DESCRIPTION:Something about A
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:B
+URL:.*/Example/ICalendar-03/2
+UID:.*/Example/ICalendar-03/2
+DTSTART:19700102T120000
+DTEND:19700102T150000
+LOCATION:LOC-B
+DESCRIPTION:Something about B
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+END:VCALENDAR
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.1.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.1.txt
new file mode 100644
index 00000000..b1821b39
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/icalendar-03.1.txt
@@ -0,0 +1,46 @@
+BEGIN:VCALENDAR
+PRODID:-//SMW Project//Semantic Result Formats
+VERSION:2.0
+METHOD:PUBLISH
+X-WR-CALNAME:.*
+X-WR-CALDESC:Simple description
+BEGIN:VTIMEZONE
+TZID:UTC
+BEGIN:STANDARD
+DTSTART:.*
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0000
+TZNAME:UTC
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VTIMEZONE
+TZID:America/New_York
+BEGIN:STANDARD
+DTSTART:.*
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+SUMMARY:A
+URL:.*/Example/ICalendar-03/1
+UID:.*/Example/ICalendar-03/1
+DTSTART:19700101
+LOCATION:LOC-A
+DESCRIPTION:Something about A
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:B
+URL:.*/Example/ICalendar-03/2
+UID:.*/Example/ICalendar-03/2
+DTSTART:19700102T120000
+DTEND:19700102T150000
+LOCATION:LOC-B
+DESCRIPTION:Something about B
+DTSTAMP:.*
+SEQUENCE:.*
+END:VEVENT
+END:VCALENDAR
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/image-upload-480.png b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/image-upload-480.png
new file mode 100644
index 00000000..4353df8e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/image-upload-480.png
Binary files differ
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.0.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.0.txt
new file mode 100644
index 00000000..263d5669
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.0.txt
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N;CHARSET=UTF-8:Example/Vcard-01/0;;;;
+FN;CHARSET=UTF-8:Example/Vcard-01/0
+CLASS:PUBLIC
+CATEGORIES;CHARSET=UTF-8:Category:Vcard-00
+SOURCE;CHARSET=UTF-8:.*/Example/Vcard-01/0
+PRODID:-////Semantic MediaWiki
+REV:.*
+URL:.*/Example/Vcard-01/0
+UID:.*/Example/Vcard-01/0
+END:VCARD \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.1.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.1.txt
new file mode 100644
index 00000000..15117522
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.1.txt
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N;CHARSET=UTF-8:Doe;John;;;
+FN;CHARSET=UTF-8:John Doe
+CLASS:PUBLIC
+BDAY:1952-01-01
+EMAIL;TYPE=INTERNET:johnDoe@example.org
+ADR;TYPE=HOME;CHARSET=UTF-8:;;Example Avenue;Anytown;;;
+TEL;TYPE=CELL:+1 781 555 1212
+TEL;TYPE=HOME:+1 202 555 1212
+NOTE;CHARSET=UTF-8:John Doe has a long and varied history\, being documented on more ...
+SOURCE;CHARSET=UTF-8:.*/Example/Vcard-01/1
+PRODID:-////Semantic MediaWiki
+REV:.*
+URL:http://www.example/com/doe
+UID:.*/Example/Vcard-01/1
+END:VCARD \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.2.txt b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.2.txt
new file mode 100644
index 00000000..7c536b1c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/Fixtures/vcard-01.2.txt
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N;CHARSET=UTF-8:Doe;John;;;
+FN;CHARSET=UTF-8:John Doe
+CLASS:PUBLIC
+BDAY:1952-01-01
+EMAIL;TYPE=INTERNET:johnDoe@example.org
+ADR;TYPE=HOME;CHARSET=UTF-8:;;Example Avenue;Anytown;;;
+TEL;TYPE=CELL:+1 781 555 1212
+TEL;TYPE=HOME:+1 202 555 1212
+NOTE;CHARSET=UTF-8:John Doe has a long and varied history\, being documented on more ...
+SOURCE;CHARSET=UTF-8:.*/Example/Vcard-01/2#_f8bae6eae7468315094dd5c6a509e2c4
+PRODID:-////Semantic MediaWiki
+REV:.*
+URL:http://www.example/com/doe
+UID:.*/Example/Vcard-01/2#_f8bae6eae7468315094dd5c6a509e2c4
+END:VCARD \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/JsonTestCaseScriptRunnerTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/JsonTestCaseScriptRunnerTest.php
new file mode 100644
index 00000000..63e740fc
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/JsonTestCaseScriptRunnerTest.php
@@ -0,0 +1,63 @@
+<?php
+namespace SRF\Tests\Integration\JSONScript;
+use SMW\Tests\Integration\JSONScript\JsonTestCaseScriptRunnerTest as SMWJsonTestCaseScriptRunnerTest;
+/**
+ * @see https://github.com/SemanticMediaWiki/SemanticMediaWiki/tree/master/tests#write-integration-tests-using-json-script
+ *
+ * `JsonTestCaseScriptRunner` provisioned by SMW is a base class allowing to use a JSON
+ * format to create test definitions with the objective to compose "real" content
+ * and test integration with MediaWiki, Semantic MediaWiki, and Scribunto.
+ *
+ * @group SRF
+ * @group SMWExtension
+ *
+ * @license GNU GPL v2+
+ * @since 2.5
+ *
+ * @author Stephan Gambke
+ */
+class JsonTestCaseScriptRunnerTest extends SMWJsonTestCaseScriptRunnerTest {
+ /**
+ * @see \SMW\Tests\JsonTestCaseScriptRunner::getTestCaseLocation
+ * @return string
+ */
+ protected function getTestCaseLocation() {
+ return __DIR__ . '/TestCases';
+ }
+ /**
+ * @return string[]
+ * @since 3.0
+ */
+ protected function getPermittedSettings() {
+ $settings = parent::getPermittedSettings();
+ $settings[] = 'srfgMapProvider';
+ return $settings;
+ }
+
+ /**
+ * @see JsonTestCaseScriptRunner::getDependencyDefinitions
+ */
+ protected function getDependencyDefinitions() {
+ return [
+ 'Mermaid' => [ $this, 'checkMermaidDependency' ]
+ ];
+ }
+ public function checkMermaidDependency( $val, &$reason ) {
+
+ if ( !defined( 'MERMAID_VERSION' ) ) {
+ $reason = "Dependency: Mermaid as requirement is not available!";
+ return false;
+ }
+
+ list( $compare, $requiredVersion ) = explode( ' ', $val );
+ $version = MERMAID_VERSION;
+
+ if ( !version_compare( $version, $requiredVersion, $compare ) ) {
+ $reason = "Dependency: Required version of Mermaid($requiredVersion $compare $version) is not available!";
+ return false;
+ }
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/README.md b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/README.md
new file mode 100644
index 00000000..0888a4b9
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/README.md
@@ -0,0 +1,82 @@
+
+<!-- Begin of generated contents by readmeContentsBuilder.php -->
+
+## TestCases
+
+Contains 21 files with a total of 62 tests:
+
+### D
+* [datatables-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/datatables-01.json) Test `format=datatables` html output (no JS validation)
+
+### E
+* [earliest-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/earliest-01.json) Test for `format=earliest`
+* [eventcalendar-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/eventcalendar-01.json) Test `format=eventcalendar` html output (no JS validation)
+
+### F
+* [filtered-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/filtered-01.json) Filtered format: ...
+* [filtered-02.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/filtered-02.json) Filtered format: ...
+
+### G
+* [gallery-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/gallery-01.json) Test `format=gallery` with file upload
+
+### I
+* [icalendar-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/icalendar-01.json) Test `format=icalendar`
+* [icalendar-02.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/icalendar-02.json) Test `format=icalendar` on iCalendar specific labels using `Special:Ask`
+* [icalendar-03.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/icalendar-03.json) Test `format=icalendar` with timezone using `Special:Ask`
+
+### L
+* [latest-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/latest-01.json) Test for `format=latest`
+
+### M
+* [math-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/math-01.json) Test for math/sum result format in pt-br lang
+
+### T
+* [tagcloud-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-01.json) Test `format=tagcloud` html output
+* [timeline-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/timeline-01.json) Test for timeline result format
+* [tree-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-01.json) Tree format: Multi-page results
+* [tree-02.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-02.json) Tree format: Simple one-page result
+* [tree-03.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-03.json) Tree format: Raising error: Missing 'parent' parameter
+* [tree-04.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-04.json) Tree format: Empty resultset does not produce tree
+* [tree-05.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-05.json) Tree format: Loop detection
+* [tree-06.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-06.json) Tree format: Insert elements with multiple parents multiple times
+* [tree-07.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/tree-07.json) Tree format: Simple one-page result
+
+### V
+* [vcard-01.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/TestCases/vcard-01.json) Test `format=vcard`
+
+-- Last updated on 2017-11-11 by `readmeContentsBuilder.php`
+
+<!-- End of generated contents by readmeContentsBuilder.php -->
+
+## Writing a test case
+
+Have a look at the [bootstrap.json](https://github.com/SemanticMediaWiki/SemanticResultFormats/tree/master/tests/phpunit/Integration/JSONScript/bootstrap.json) example test case and the [introduction video](https://youtu.be/7fDKjPFaTaY). For further assistance, please read the following [document](https://github.com/SemanticMediaWiki/SemanticMediaWiki/tree/master/tests/phpunit/Integration/JSONScript#designing-an-integration-test).
+
+## Running a test
+
+The `composer integration` command can be used the quickly execute the integration tests and in
+combination with the `--filter` option allows to select a single specific case.
+
+<pre>
+$ composer integration -- --filter vcard
+Using PHP 7.1.1
+
+Semantic Result Formats: 3.0.0-alpha
+
+Semantic MediaWiki: 3.0.0-alpha (c352b6a, SMWSQLStore3, mysql)
+MediaWiki: 1.31.0-alpha (44c06df, MediaWiki vendor autoloader)
+Site language: en
+
+Execution time: 2017-01-01 12:00
+Debug logs: Disabled
+Xdebug: Disabled (or not installed)
+
+PHPUnit 4.8.35 by Sebastian Bergmann and contributors.
+
+Runtime: PHP 7.1.1
+Configuration: /var/www/html/w/extensions/SemanticResultFormats/phpunit.xml.dist
+
+.
+
+Time: 18.38 seconds, Memory: 38.00MB
+</pre>
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/bibtex-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/bibtex-01.json
new file mode 100644
index 00000000..2966fbe0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/bibtex-01.json
@@ -0,0 +1,159 @@
+{
+ "description": "Test `format=bibtex`",
+ "setup": [
+ {
+ "page": "Has author",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has title",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has publisher",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has year",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has address",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has edition",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has email",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Email]]"
+ },
+ {
+ "page": "BibTex/00",
+ "contents": "[[Category:Bibtex-00]]"
+ },
+ {
+ "page": "BibTex/01",
+ "contents": "[[Category:Bibtex-01]] [[Type::incollection]] [[Has author:: Eric S. Maskin]] [[Has editor::Leonid Hurwicz]] [[Has editor::David Schmeidler]] [[Has editor::Hugo Sonnenschein]] [[Has title::The theory of implementation in nash equilibrium: a survey]] [[Has booktitle::Social Goals and Social Organization]] [[Has year::1985]] [[Has publisher::Cambridge University Press]] [[Has address::Cambridge]] [[Has pages::173-204]]"
+ },
+ {
+ "page": "BibTex/02",
+ "contents": "[[Category:Bibtex-02]] [[Has author::Milton Abramowitz]] [[Has author::Irene A. Stegun]] [[Has title::Handbook of Mathematical Functions]] [[Has year::1964]] [[Has publisher::Dover]] [[Has address::New York]] [[Has edition::ninth Dover printing, tenth GPO printing]]"
+ }
+ ],
+ "tests": [
+ {
+ "type": "special",
+ "about": "#0 `format=bibtex` empty (bibtex-01-0.bib)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "bibtex"
+ },
+ "q": "[[Category:Bibtex-00]]",
+ "po": "?Has author=author|?Has title=title|?Has publisher=publisher|?Has year=year|?Has address=address|?Has edition=edition"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/bibtex-01-0.bib"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#1 `format=bibtex` single author, editor (bibtex-01-1.bib)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "bibtex"
+ },
+ "q": "[[Category:Bibtex-01]]",
+ "po": "?Type=type|?Has author=author|?Has title=title|?Has publisher=publisher|?Has year=year|?Has address=address|?Has edition=edition|?Has editor=editor|?Has pages=pages|?Has booktitle=booktitle"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/bibtex-01-1.bib"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#2 `format=bibtex` multiple authors (bibtex-01-2.bib)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "bibtex"
+ },
+ "q": "[[Category:Bibtex-02]]",
+ "po": "?Has author=author|?Has title=title|?Has publisher=publisher|?Has year=year|?Has address=address|?Has edition=edition"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/bibtex-01-2.bib"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#3 `format=bibtex` multiple records (bibtex-01-3.bib)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "bibtex"
+ },
+ "q": "[[Category:Bibtex-02]] OR [[Category:Bibtex-01]]",
+ "po": "?Has author=author|+order=desc|?Has title=title|?Has publisher=publisher|?Has year=year|?Has address=address|?Has edition=edition"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/bibtex-01-3.bib"
+ }
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/datatables-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/datatables-01.json
new file mode 100644
index 00000000..2ea26ebf
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/datatables-01.json
@@ -0,0 +1,47 @@
+{
+ "description": "Test `format=datatables` html output (no JS validation)",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/Datatables/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Datatables]]"
+ },
+ {
+ "page": "Example/Datatables/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Datatables]]"
+ },
+ {
+ "page": "Test/Datatables/Q.1",
+ "contents": "{{#ask: [[Category:Datatables]] |?Has date |format=datatables }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0",
+ "subject": "Test/Datatables/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"srf-datatables\" data-theme=\"bootstrap\"><div class=\"top\">"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/earliest-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/earliest-01.json
new file mode 100644
index 00000000..700e5265
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/earliest-01.json
@@ -0,0 +1,61 @@
+{
+ "description": "Test for `format=earliest`",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/Earliest/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Earliest]]"
+ },
+ {
+ "page": "Example/Earliest/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Earliest]]"
+ },
+ {
+ "page": "Example/Earliest/Q.1",
+ "contents": "{{#ask: [[Category:Earliest]] |?Has date |format=earliest }}"
+ },
+ {
+ "page": "Example/Earliest/Q.2",
+ "contents": "{{#ask: [[Category:Earliest/default]] |?Has date |format=earliest |default=No date }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0",
+ "subject": "Example/Earliest/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "1 January 1970"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 default output",
+ "subject": "Example/Earliest/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "No date"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/eventcalendar-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/eventcalendar-01.json
new file mode 100644
index 00000000..681ed40d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/eventcalendar-01.json
@@ -0,0 +1,47 @@
+{
+ "description": "Test `format=eventcalendar` html output (no JS validation)",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/Eventcalendar/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Eventcalendar]]"
+ },
+ {
+ "page": "Example/Eventcalendar/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Eventcalendar]]"
+ },
+ {
+ "page": "Test/Eventcalendar/Q.1",
+ "contents": "{{#ask: [[Category:Eventcalendar]] |?Has date |format=eventcalendar }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0",
+ "subject": "Test/Eventcalendar/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"srf-eventcalendar\" data-external-class=\"\">"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-01.json
new file mode 100644
index 00000000..d86ba5fe
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-01.json
@@ -0,0 +1,330 @@
+{
+ "description": "Filtered format: ...",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/City name",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Location",
+ "contents": "[[Has type::Geographic coordinates]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Country code",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Population",
+ "contents": "[[Has type::Number]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Elevation",
+ "contents": "[[Has type::Quantity]][[Corresponds to::1 m]][[Corresponds to::0.001 km]][[Corresponds to::3.28084 ft]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Timezone",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Modification date",
+ "contents": "[[Has type::Date]]"
+ },
+
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "City",
+ "contents": "[[Category:Filtered test]][[Category:City]][[Filtered test/City name::{{{name|}}}]][[Filtered test/Location:: {{{latitude|}}}°, {{{longitude|}}}°]][[Filtered test/Country code::{{{country code|}}}]][[Filtered test/Population::{{{population|}}}]][[Filtered test/Elevation::{{{dem|}}} m]][[Filtered test/Timezone::{{{timezone|}}}]][[Filtered test/Modification date::{{{modification date|}}}]]"
+ },
+
+ {
+ "page": "Filtered test/Berlin",
+ "contents": "{{City |name=Berlin |latitude=52.52437 |longitude=13.41053 |country code=DE |population=3426354 |dem=43 |timezone=Europe/Berlin |modification date=2016-09-26 }}"
+ },
+ {
+ "page": "Filtered test/Cairo",
+ "contents": "{{City |name=Cairo |latitude=30.06263 |longitude=31.24967 |country code=EG |population=7734614 |dem=23 |timezone=Africa/Cairo |modification date=2015-06-03 }}"
+ },
+ {
+ "page": "Filtered test/London",
+ "contents": "{{City |name=London |latitude=51.50853 |longitude=-0.12574 |country code=GB |population=7556900 |dem=25 |timezone=Europe/London |modification date=2016-09-14 }}"
+ },
+ {
+ "page": "Filtered test/Madrid",
+ "contents": "{{City |name=Madrid |latitude=40.4165 |longitude=-3.70256 |country code=ES |population=3255944 |dem=665 |timezone=Europe/Madrid |modification date=2015-06-03 }}"
+ },
+ {
+ "page": "Filtered test/Paris",
+ "contents": "{{City |name=Paris |latitude=48.85341 |longitude=2.3488 |country code=FR |population=2138551 |dem=42 |timezone=Europe/Paris |modification date=2016-02-18 }}"
+ },
+ {
+ "page": "Filtered test/Sofia",
+ "contents": "{{City |name=Sofia |latitude=42.69751 |longitude=23.32415 |country code=BG |population=1152556 |dem=562 |timezone=Europe/Sofia |modification date=2011-06-16 }}"
+ },
+ {
+ "page": "Filtered test/Vienna",
+ "contents": "{{City |name=Vienna |latitude=48.20849 |longitude=16.37208 |country code=AT |population=1691468 |dem=193 |timezone=Europe/Vienna |modification date=2015-07-29 }}"
+ },
+ {
+ "page": "Filtered test/Yerevan",
+ "contents": "{{City |name=Yerevan |latitude=40.18111 |longitude=44.51361 |country code=AM |population=1093485 |dem=994 |timezone=Asia/Yerevan |modification date=2016-03-10 }}"
+ },
+ {
+ "page": "Example/Filtered 01-01",
+ "contents": "{{#ask:[[Category:Filtered test]]|format=filtered}}"
+ },
+ {
+ "page": "Example/Filtered 01-02",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=list}}"
+ },
+ {
+ "page": "Example/Filtered 01-03",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=calendar}}"
+ },
+ {
+ "page": "Example/Filtered 01-04",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=table}}"
+ },
+ {
+ "page": "Example/Filtered 01-05",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=map}}"
+ },
+ {
+ "page": "Example/Filtered 01-06",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |+filter=value |format=filtered }}"
+ },
+ {
+ "page": "Example/Filtered 01-07",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/Elevation |+filter=number |format=filtered }}"
+ },
+ {
+ "page": "Example/Filtered 01-08",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/Location |+filter=distance |+distance filter origin=52.52437° 13.41053° |format=filtered }}"
+ },
+ {
+ "page": "Example/Filtered 01-09",
+ "contents": "{{#ask:[[Category:Filtered test]] |format=filtered |filter position=top }}"
+ },
+ {
+ "page": "Example/Filtered 01-10",
+ "contents": "{{#ask:[[Category:Filtered test]] |format=filtered |filter position=bottom }}"
+ },
+ {
+ "page": "Example/Filtered 01-11",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=list |list view type=ul }}"
+ },
+ {
+ "page": "Example/Filtered 01-12",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=list |list view type=ol }}"
+ },
+ {
+ "page": "Example/Filtered 01-17",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/Location |+filter=distance |format=filtered }}"
+ },
+ {
+ "page": "Example/Filtered 01-18",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/Elevation |+filter=distance |format=filtered }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-01 (Empty response)",
+ "subject": "Example/Filtered 01-01",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ [ "div.filtered", 1 ],
+ "div.filtered > div.filtered-filters > div.filtered-filter-spinner",
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container:empty",
+ "div.filtered > div.filtered-views > div.filtered-views-container:empty"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-02 (List view)",
+ "subject": "Example/Filtered 01-02",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter-spinner",
+ [ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-list", 1 ],
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-list:contains('List')",
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-list", 1 ],
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-list > div.filtered-list-item:not(:empty)", 8 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-03 (Calendar view)",
+ "subject": "Example/Filtered 01-03",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter-spinner",
+ [ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-calendar", 1 ],
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-calendar:contains('Calendar')",
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-calendar", 1 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-04 (Table view)",
+ "subject": "Example/Filtered 01-04",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter-spinner",
+ [ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-table", 1 ],
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-table:contains('Table')",
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-table", 1 ],
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-table > table tr > th:not(:empty)", 3 ],
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-table > table tr.filtered-table-item:not(:empty)", 8 ],
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-table > table tr.filtered-table-item > td", 24 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-05 (Map view)",
+ "subject": "Example/Filtered 01-05",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter-spinner",
+ [ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-map", 1 ],
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container > div.filtered-view-selector.filtered-map:contains('Map')",
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-map", 1 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-06 (Value filter)",
+ "subject": "Example/Filtered 01-06",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter.filtered-value",
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container:empty",
+ "div.filtered > div.filtered-views > div.filtered-views-container:empty"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-07 (Number filter)",
+ "subject": "Example/Filtered 01-07",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter.filtered-number",
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container:empty",
+ "div.filtered > div.filtered-views > div.filtered-views-container:empty"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-08 (Distance filter)",
+ "subject": "Example/Filtered 01-08",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered > div.filtered-filters > div.filtered-filter.filtered-distance",
+ "div.filtered > div.filtered-views > div.filtered-views-selectors-container:empty",
+ "div.filtered > div.filtered-views > div.filtered-views-container:empty"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-09 (Filters on top)",
+ "subject": "Example/Filtered 01-09",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ [ "div.filtered", 1 ],
+ "div.filtered > div.filtered-filters + div.filtered-views"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-10 (Filters at bottom)",
+ "subject": "Example/Filtered 01-10",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ [ "div.filtered", 1 ],
+ "div.filtered > div.filtered-views + div.filtered-filters "
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-11 (List view: Type ul)",
+ "subject": "Example/Filtered 01-11",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-list > ul > li.filtered-list-item:not(:empty)", 8 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Filtered 01-12 (List view: Type ul)",
+ "subject": "Example/Filtered 01-12",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ [ "div.filtered > div.filtered-views > div.filtered-views-container > div.filtered-view.filtered-list > ol > li.filtered-list-item:not(:empty)", 8 ]
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Filtered 01-17 (Distance filter: Missing origin)",
+ "subject": "Example/Filtered 01-17",
+ "assert-output": {
+ "to-contain": [
+ "Missing origin for distance filter on 'Filtered test/Location'."
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Filtered 01-18 (Distance filter: Wrong printout type)",
+ "subject": "Example/Filtered 01-18",
+ "assert-output": {
+ "to-contain": [
+ "The 'distance' filter can not be used on the 'Filtered test/Elevation' printout."
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "srfgMapProvider": "OpenStreetMap.Mapnik",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-02.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-02.json
new file mode 100644
index 00000000..03512762
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/filtered-02.json
@@ -0,0 +1,56 @@
+{
+ "description": "Filtered format: ...",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/City name",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Filtered test/Location",
+ "contents": "[[Has type::Geographic coordinates]]"
+ },
+
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "City",
+ "contents": "[[Category:Filtered test]][[Category:City]][[Filtered test/City name::{{{name|}}}]][[Filtered test/Location:: {{{latitude|}}}°, {{{longitude|}}}°]]"
+ },
+
+ {
+ "page": "Filtered test/Berlin",
+ "contents": "{{City |name=Berlin |latitude=52.52437 |longitude=13.41053 }}"
+ },
+ {
+ "page": "Example/Filtered 02-01",
+ "contents": "{{#ask:[[Category:Filtered test]] |?Filtered test/City name |?Filtered test/Location |format=filtered |views=map}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Filtered 02-01 (Map view: No srfgMapProvider specified)",
+ "subject": "Example/Filtered 02-01",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ "div.filtered + span.smw-highlighter[data-title=\"Warning\"][title='No map provider specified for \"map\" view.'], div.filtered + p span.smw-highlighter[data-title=\"Warning\"][title='No map provider specified for \"map\" view.']"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gallery-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gallery-01.json
new file mode 100644
index 00000000..0be9e237
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gallery-01.json
@@ -0,0 +1,60 @@
+{
+ "description": "Test `format=gallery` with file upload",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has text",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "NS_FILE",
+ "page": "Gallery01.png",
+ "contents": {
+ "upload": {
+ "file" : "/../Fixtures/image-upload-480.png",
+ "text" : "[[Has file::{{FULLPAGENAME}}]] [[Has caption::123]]"
+ }
+ }
+ },
+ {
+ "page": "Example/Gallery-01/Q.1",
+ "contents": "{{#ask: [[Has caption::123]] |?Has file |format=gallery |limit=1 }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 (simple)",
+ "subject": "Example/Gallery-01/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"srf-gallery\" data-redirect-type=\"_wpg\">",
+ "<div class=\"thumb\" style=\"width: 150px;\"><div style=\"margin:15px auto;\"><a href=\".*File:Gallery01.png\" class=\"image\">"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "wgEnableUploads": true,
+ "wgFileExtensions": [
+ "png"
+ ],
+ "wgDefaultUserOptions": {
+ "thumbsize": 5
+ },
+ "smwgPageSpecialProperties": [
+ "_MDAT"
+ ],
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "NS_FILE": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gantt-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gantt-01.json
new file mode 100644
index 00000000..b35e5d3e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/gantt-01.json
@@ -0,0 +1,167 @@
+{
+ "description": "Test the gantt format",
+ "requires": {
+ "Mermaid": ">= 2.0"
+ },
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Display Title",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Start Date",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "End Date",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Status",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Priority",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Related To Section",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "Task",
+ "contents": "[[Category:Task]][[Display Title::{{{title|}}}]][[Start Date::{{{start|}}}]][[End Date::{{{end|}}}]][[Status::{{{status|}}}]][[Priority::{{{priority|}}}]][[Related To Section::{{{section|}}}]]"
+ },
+ {
+ "page": "Gantt Test/Task1",
+ "contents": "{{Task |title=Task01 |start=2019-01-01 |end=2019-01-15 |status=completed |priority=high |section=First Section }}"
+ },
+ {
+ "page": "Gantt Test/Task2",
+ "contents": "{{Task |title=Task02 |start=2019-01-15 |end=2019-01-31 |status=backlog |priority=low |section=Second Section }}"
+ },
+ {
+ "page": "Gantt Test/Task3",
+ "contents": "{{Task |title=Task03 |start=2019-02-01 |end=2019-02-15 |status=open |priority=critical |section=First Section }}"
+ },
+ {
+ "page": "Gantt Test/Task4",
+ "contents": "{{Task |title=Task04 |start=2019-02-15 |end=2019-02-28 |status=done |priority=very high |section=First Section }}"
+ },
+ {
+ "page": "Example/Gantt Diagram min config",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt }}"
+ },
+ {
+ "page": "Example/Gantt Diagram config all",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt |theme=forest |sortkey=title |bargap=15 |barheight=40 |titletopmargin=30 |leftpadding=130}}"
+ },
+ {
+ "page": "Example/Gantt Diagram test axis format 1",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt | axisformat=%m/%d/%Y}}"
+ },
+ {
+ "page": "Example/Gantt Diagram test axis format 2",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt | axisformat=%m/%Y}}"
+ },
+ {
+ "page": "Example/Gantt Diagram test axis format 3",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt | axisformat=%B-%Y}}"
+ },
+ {
+ "page": "Example/Gantt Diagram mapping test 1",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Status=status |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Priority=priority| format=gantt |theme=forest |sortkey=title |bargap=15 |barheight=40 |titletopmargin=30 |leftpadding=130}}"
+ },
+ {
+ "page": "Example/Gantt priority mapping test",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Status=status |?Priority=priority| |prioritymapping=critical=>crit; very high=>crit| format=gantt |theme=forest |sortkey=title |bargap=15 |barheight=40 |titletopmargin=30 |leftpadding=130}}"
+ },
+ {
+ "page": "Example/Gantt status mapping test",
+ "contents": "{{#ask:[[Category:Task]] |?Display Title=task |?Start Date=startdate |?End Date=enddate |?Related To Section=section |?Status=status |?Priority=priority| |statusmapping=backlog=>active;open=>active;done=>done| format=gantt |theme=forest |sortkey=title |bargap=15 |barheight=40 |titletopmargin=30 |leftpadding=130}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Test Selector of created SVG",
+ "subject": "Example/Gantt Diagram min config",
+ "assert-output": {
+ "to-be-valid-html": 1,
+ "to-contain": [
+ ["div.mw-parser-output > div.srf-gantt",1]
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Test gantt min config",
+ "subject": "Example/Gantt Diagram min config",
+ "assert-output": {
+ "to-contain": [
+ "data-mermaid=\"&#123;&quot;content&quot;:&quot;gantt\\ndateFormat YYYY-MM-DD\\naxisFormat&#160;%m\\/%d\\/%Y\\nsection First Section\\nTask01\\t&#160;:2019-01-01, 2019-01-15\\nTask03\\t&#160;:2019-02-01, 2019-02-15\\nTask04\\t&#160;:2019-02-15, 2019-02-28\\nsection Second Section\\nTask02\\t&#160;:2019-01-15, 2019-01-31\\n&quot;,&quot;config&quot;:&#123;&quot;theme&quot;:&quot;default&quot;,&quot;gantt&quot;:&#123;&quot;leftPadding&quot;:75,&quot;titleTopMargin&quot;:25,&quot;barHeight&quot;:20,&quot;barGap&quot;:4&#125;&#125;&#125;\"><div class=\"mermaid-dots\"></div></div>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Test gantt when all config params set",
+ "subject": "Example/Gantt Diagram config all",
+ "assert-output": {
+ "to-contain": [
+ "data-mermaid=\"&#123;&quot;content&quot;:&quot;gantt\\ndateFormat YYYY-MM-DD\\naxisFormat&#160;%m\\/%d\\/%Y\\nsection First Section\\nTask01\\t&#160;:2019-01-01, 2019-01-15\\nTask03\\t&#160;:2019-02-01, 2019-02-15\\nTask04\\t&#160;:2019-02-15, 2019-02-28\\nsection Second Section\\nTask02\\t&#160;:2019-01-15, 2019-01-31\\n&quot;,&quot;config&quot;:&#123;&quot;theme&quot;:&quot;forest&quot;,&quot;gantt&quot;:&#123;&quot;leftPadding&quot;:130,&quot;titleTopMargin&quot;:30,&quot;barHeight&quot;:40,&quot;barGap&quot;:15&#125;&#125;&#125;\"><div class=\"mermaid-dots\"></div></div>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Test axis forma %m/%d/%Y",
+ "subject": "Example/Gantt Diagram test axis format 1",
+ "assert-output": {
+ "to-contain": [
+ "axisFormat&#160;%m\\/%d\\/%Y"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Test priority mapping",
+ "subject": "Example/Gantt priority mapping test",
+ "assert-output": {
+ "to-contain": [
+ "data-mermaid=\"&#123;&quot;content&quot;:&quot;gantt\\ndateFormat YYYY-MM-DD\\naxisFormat&#160;%m\\/%d\\/%Y\\nsection First Section\\nTask01\\t&#160;:2019-01-01, 2019-01-15\\nTask03\\t&#160;:crit, 2019-02-01, 2019-02-15\\nTask04\\t&#160;:crit, 2019-02-15, 2019-02-28\\nsection Second Section\\nTask02\\t&#160;:2019-01-15, 2019-01-31\\n&quot;,&quot;config&quot;:&#123;&quot;theme&quot;:&quot;forest&quot;,&quot;gantt&quot;:&#123;&quot;leftPadding&quot;:130,&quot;titleTopMargin&quot;:30,&quot;barHeight&quot;:40,&quot;barGap&quot;:15&#125;&#125;&#125;\"><div class=\"mermaid-dots\"></div></div>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Test priority mapping",
+ "subject": "Example/Gantt status mapping test",
+ "assert-output": {
+ "to-contain": [
+ "data-mermaid=\"&#123;&quot;content&quot;:&quot;gantt\\ndateFormat YYYY-MM-DD\\naxisFormat&#160;%m\\/%d\\/%Y\\nsection First Section\\nTask01\\t&#160;:2019-01-01, 2019-01-15\\nTask03\\t&#160;:active, 2019-02-01, 2019-02-15\\nTask04\\t&#160;:done, 2019-02-15, 2019-02-28\\nsection Second Section\\nTask02\\t&#160;:active, 2019-01-15, 2019-01-31\\n&quot;,&quot;config&quot;:&#123;&quot;theme&quot;:&quot;forest&quot;,&quot;gantt&quot;:&#123;&quot;leftPadding&quot;:130,&quot;titleTopMargin&quot;:30,&quot;barHeight&quot;:40,&quot;barGap&quot;:15&#125;&#125;&#125;\"><div class=\"mermaid-dots\"></div></div>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": true
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-01.json
new file mode 100644
index 00000000..068d5dc5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-01.json
@@ -0,0 +1,68 @@
+{
+ "description": "Test `format=icalendar`",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/ICalendar-01/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:ICalendar-01]]"
+ },
+ {
+ "page": "Example/ICalendar/Q.1",
+ "contents": "{{#ask: [[Category:ICalendar-01]] |?Has date |title=SRF integration |description=Simple description |format=icalendar }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 `format=icalendar` embedded",
+ "subject": "Example/ICalendar/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "Special:Ask/-5B-5BCategory:ICalendar-2D01-5D-5D/-3FHas-20date/mainlabel%3D/limit%3D50/offset%3D0/format%3Dicalendar/title%3DSRF-20integration/description%3DSimple-20description"
+ ]
+ }
+ },
+ {
+ "type": "special",
+ "about": "#1 `format=icalendar` raw output via `Special:Ask`",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "icalendar",
+ "title": "SRF integration",
+ "description": "Simple description"
+ },
+ "q": "[[Category:ICalendar-01]]",
+ "po": "?Has date"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/icalendar-01.1.txt"
+ }
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-02.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-02.json
new file mode 100644
index 00000000..10691946
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-02.json
@@ -0,0 +1,78 @@
+{
+ "description": "Test `format=icalendar` on iCalendar specific labels using `Special:Ask`",
+ "setup": [
+ {
+ "page": "Has planned start",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has planned finish",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has conference",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has description",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has location",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "page": "Example/ICalendar-02/1",
+ "contents": "[[Has conference::A]] [[Has planned start::1 Jan 1970]] [[Has location::LOC-A]] [[Has description::Something about A]] [[Category:ICalendar-02]]"
+ },
+ {
+ "page": "Example/ICalendar-02/2",
+ "contents": "[[Has conference::B]] [[Has planned start::2 Jan 1970 12:00]] [[Has planned finish::2 Jan 1970 15:00]] [[Has location::LOC-B]] [[Has description::Something about B]] [[Category:ICalendar-02]]"
+ }
+ ],
+ "tests": [
+ {
+ "type": "special",
+ "about": "#0 `format=icalendar`, match iCalendar specific labels",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "icalendar",
+ "title": "SRF integration",
+ "description": "Simple description"
+ },
+ "q": "[[Category:ICalendar-02]]",
+ "po": "?Has conference=summary|?Has planned start=start|?Has planned finish=end|?Has location=location|?Has description=description"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/icalendar-02.0.txt"
+ }
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-03.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-03.json
new file mode 100644
index 00000000..0904c17f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/icalendar-03.json
@@ -0,0 +1,131 @@
+{
+ "description": "Test `format=icalendar` with timezone using `Special:Ask`",
+ "setup": [
+ {
+ "page": "Has planned start",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has planned finish",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has conference",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has description",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has location",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "page": "Example/ICalendar-03/1",
+ "contents": "[[Has conference::A]] [[Has planned start::1 Jan 1970]] [[Has location::LOC-A]] [[Has description::Something about A]] [[Category:ICalendar-03]]"
+ },
+ {
+ "page": "Example/ICalendar-03/2",
+ "contents": "[[Has conference::B]] [[Has planned start::2 Jan 1970 12:00]] [[Has planned finish::2 Jan 1970 15:00]] [[Has location::LOC-B]] [[Has description::Something about B]] [[Category:ICalendar-03]]"
+ }
+ ],
+ "tests": [
+ {
+ "type": "special",
+ "about": "#0 single timezone (UTC)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "icalendar",
+ "title": "SRF integration",
+ "timezone": "UTC",
+ "description": "Simple description"
+ },
+ "q": "[[Category:ICalendar-03]]",
+ "po": "?Has conference=summary|?Has planned start=start|?Has planned finish=end|?Has location=location|?Has description=description"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/icalendar-03.0.txt"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#1 multiple timezones (UTC,America/New_York)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "icalendar",
+ "title": "SRF integration",
+ "timezone": "UTC,America/New_York",
+ "description": "Simple description"
+ },
+ "q": "[[Category:ICalendar-03]]",
+ "po": "?Has conference=summary|?Has planned start=start|?Has planned finish=end|?Has location=location|?Has description=description"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/icalendar-03.1.txt"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#2 unknown timezone",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "icalendar",
+ "title": "SRF integration",
+ "timezone": "UTC,Foo",
+ "description": "Simple description"
+ },
+ "q": "[[Category:ICalendar-03]]",
+ "po": "?Has conference=summary|?Has planned start=start|?Has planned finish=end|?Has location=location|?Has description=description"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/icalendar-03.0.txt"
+ }
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/latest-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/latest-01.json
new file mode 100644
index 00000000..c8b7b759
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/latest-01.json
@@ -0,0 +1,61 @@
+{
+ "description": "Test for `format=latest`",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/Latest/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Latest]]"
+ },
+ {
+ "page": "Example/Latest/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Latest]]"
+ },
+ {
+ "page": "Example/Latest/Q.1",
+ "contents": "{{#ask: [[Category:Latest]] |?Has date |format=latest }}"
+ },
+ {
+ "page": "Example/Latest/Q.2",
+ "contents": "{{#ask: [[Category:Latest/default]] |?Has date |format=latest |default=No date }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0",
+ "subject": "Example/Latest/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "3 January 1970"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 default output",
+ "subject": "Example/Latest/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "No date"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/listwidget-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/listwidget-01.json
new file mode 100644
index 00000000..2a55ca24
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/listwidget-01.json
@@ -0,0 +1,95 @@
+{
+ "description": "Listwidget format: widgets - unordered (#449 - `wgContLang=fr`, `wgLang=en`)",
+ "setup": [
+ {
+ "namespace": "NS_CATEGORY",
+ "page": "Listwidget example",
+ "contents": "Holds listwidget examples."
+ },
+ {
+ "page": "May 2000",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2001",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2002",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2003",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2004",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2005",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "May 2006",
+ "contents": "[[Category:Listwidget example]]"
+ },
+ {
+ "page": "Listwidget - alphabet - unordered",
+ "contents": "{{#ask: [[Category:Listwidget example]] |format=listwidget |link=all |headers=show |listtype=unordered |widget=alphabet |pageitems=6}}"
+ },
+ {
+ "page": "Listwidget - menu - listtype unspecified",
+ "contents": "{{#ask: [[Category:Listwidget example]] |format=listwidget |link=all |headers=show |widget=menu }}"
+ },
+ {
+ "page": "Listwidget - pagination - ordered",
+ "contents": "{{#ask: [[Category:Listwidget example]] |format=listwidget |link=all |headers=show |listtype=ordered |widget=pagination }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "#0 Listwidget - alphabet - unordered",
+ "subject": "Listwidget - alphabet - unordered",
+ "assert-output": {
+ "to-contain": [
+ ".srf-listwidget[data-listtype=\"ul\"][data-widget=\"alphabet\"][data-pageitems=\"6\"] .listwidget-container[id]"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "#1 Listwidget - menu - listtype unspecified",
+ "subject": "Listwidget - menu - listtype unspecified",
+ "assert-output": {
+ "to-contain": [
+ ".srf-listwidget[data-listtype=\"ul\"][data-widget=\"menu\"][data-pageitems=\"5\"] .listwidget-container[id]"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "#2 Listwidget - pagination - ordered",
+ "subject": "Listwidget - pagination - ordered",
+ "assert-output": {
+ "to-contain": [
+ ".srf-listwidget[data-listtype=\"ol\"][data-widget=\"pagination\"][data-pageitems=\"5\"] .listwidget-container[id]"
+ ]
+ }
+ }
+
+ ],
+ "settings": {
+ "wgContLang": "fr",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": true
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/math-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/math-01.json
new file mode 100644
index 00000000..0a0258c6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/math-01.json
@@ -0,0 +1,113 @@
+{
+ "description": "Test for math/sum result format in pt-br lang",
+ "setup": [
+ {
+ "page": "Has number",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Number]]"
+ },
+ {
+ "page": "Example/Math/1",
+ "contents": "[[Has number::30000000]] [[Has number::15000]] [[Has number::15000,25]] [[Has number::25,50]] "
+ },
+ {
+ "page": "Example/Math/Q.1",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=sum }}"
+ },
+ {
+ "page": "Example/Math/Q.2",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=max }}"
+ },
+ {
+ "page": "Example/Math/Q.3",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=min }}"
+ },
+ {
+ "page": "Example/Math/Q.4",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=product }}"
+ },
+ {
+ "page": "Example/Math/Q.5",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=average }}"
+ },
+ {
+ "page": "Example/Math/Q.6",
+ "contents": "{{#show: Example/Math/1 |?Has number|format=median }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 format=sum (kilo and decimal separators)",
+ "subject": "Example/Math/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "30.030.025,75"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 format=max (kilo and decimal separators)",
+ "subject": "Example/Math/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "30.000.000"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#2 format=min (kilo and decimal separators)",
+ "subject": "Example/Math/Q.3",
+ "assert-output": {
+ "to-contain": [
+ "25,5"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#3 format=product (kilo and decimal separators)",
+ "subject": "Example/Math/Q.4",
+ "assert-output": {
+ "to-contain": [
+ "1,721279e+17"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#4 format=average (kilo and decimal separators)",
+ "subject": "Example/Math/Q.5",
+ "assert-output": {
+ "to-contain": [
+ "7.507.506,438"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#5 format=median (kilo and decimal separators)",
+ "subject": "Example/Math/Q.6",
+ "assert-output": {
+ "to-contain": [
+ "15.000,125"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "pt-br",
+ "wgLang": "pt-br",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-01.json
new file mode 100644
index 00000000..f29c8e30
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-01.json
@@ -0,0 +1,101 @@
+{
+ "description": "Test `format=outline` template output",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Assigned to",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Severity",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "outline-test-header",
+ "contents": "<includeonly> #outlinelevel: {{{#outlinelevel}}}, #itemcount: {{{#itemcount}}}, Severity: {{{Severity}}}</includeonly>"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "outline-test-item",
+ "contents": "<includeonly> #itemsubject: {{{#itemsubject}}}, #itemsection: {{{#itemsection}}}, #itemnumber: {{{#itemnumber}}}, Assigned to: {{{Assigned to}}}</includeonly>"
+ },
+ {
+ "page": "SRF/Outline/1",
+ "contents": "[[Assigned to::John]] [[Severity::Normal]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/2",
+ "contents": "[[Assigned to::Jane]] [[Severity::Urgent]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/3",
+ "contents": "[[Assigned to::田中]] [[Severity::Urgent]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/Q.1",
+ "contents": "{{#ask: [[Category:Outline]] |?Severity |?Assigned to |format=outline |template=outline-test |sort=Severity,Assigned to |outlineproperties=Severity |link=none }}"
+ },
+ {
+ "page": "SRF/Outline/Q.2",
+ "contents": "{{#ask: [[Category:Outline]] |?Severity |?Assigned to |format=outline |template=outline-test |sort=Severity,Assigned to |outlineproperties=Severity,Assigned to |link=none }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 (`outlineproperties=Severity`)",
+ "subject": "SRF/Outline/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"outline-test-section-severity\"> #outlinelevel: 0, #itemcount: 1, Severity: Normal",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-item\">",
+ "#itemsubject: SRF/Outline/1, #itemsection: 0, #itemnumber: 0, Assigned to: {{{Assigned to}}}",
+ "#itemsubject: {{{#itemsubject}}}, #itemsection: 0, #itemnumber: 1, Assigned to: John</div></div></div>",
+ "<div class=\"outline-test-section-severity\"> #outlinelevel: 0, #itemcount: 2, Severity: Urgent",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-item\">",
+ "#itemsubject: SRF/Outline/2, #itemsection: 0, #itemnumber: 0, Assigned to: {{{Assigned to}}}",
+ "#itemsubject: {{{#itemsubject}}}, #itemsection: 0, #itemnumber: 1, Assigned to: Jane</div>",
+ "#itemsubject: SRF/Outline/3, #itemsection: 1, #itemnumber: 0, Assigned to: {{{Assigned to}}}",
+ "#itemsubject: {{{#itemsubject}}}, #itemsection: 1, #itemnumber: 1, Assigned to: 田中</div></div></div>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 (`outlineproperties=Severity,Assigned to`)",
+ "subject": "SRF/Outline/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"outline-test-section-severity\"> #outlinelevel: 0, #itemcount: 1, Severity: Normal",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-section-assigned-to\">",
+ "#outlinelevel: 1, #itemcount: 1, Severity: {{{Severity}}}",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-item\">",
+ "#itemsubject: SRF/Outline/1, #itemsection: 0, #itemnumber: 0, Assigned to: {{{Assigned to}}}</div></div></div></div></div>",
+ "<div class=\"outline-test-section-severity\"> #outlinelevel: 0, #itemcount: 2, Severity: Urgent",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-section-assigned-to\">",
+ "#outlinelevel: 1, #itemcount: 1, Severity: {{{Severity}}}",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-item\">",
+ "#itemsubject: SRF/Outline/2, #itemsection: 0, #itemnumber: 0, Assigned to: {{{Assigned to}}}</div></div></div>",
+ "<div class=\"outline-test-section-assigned-to\"> #outlinelevel: 1, #itemcount: 1, Severity: {{{Severity}}}",
+ "<div class=\"outline-test-items\"><div class=\"outline-test-item\">",
+ "#itemsubject: SRF/Outline/3, #itemsection: 0, #itemnumber: 0, Assigned to: {{{Assigned to}}}</div></div></div></div></div>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-02.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-02.json
new file mode 100644
index 00000000..d9122f8d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/outline-02.json
@@ -0,0 +1,105 @@
+{
+ "description": "Test `format=outline` list output",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Assigned to",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Severity",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "SRF/Outline/1",
+ "contents": "[[Assigned to::John]] [[Severity::Normal]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/2",
+ "contents": "[[Assigned to::Jane]] [[Severity::Urgent]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/3",
+ "contents": "[[Assigned to::田中]] [[Severity::Urgent]] [[Category:Outline]]"
+ },
+ {
+ "page": "SRF/Outline/Q.1",
+ "contents": "{{#ask: [[Category:Outline]] |?Severity |?Assigned to |format=outline |sort=Severity,Assigned to |outlineproperties=Severity |link=none }}"
+ },
+ {
+ "page": "SRF/Outline/Q.2",
+ "contents": "{{#ask: [[Category:Outline]] |?Severity |?Assigned to |format=outline |sort=Severity,Assigned to |outlineproperties=Severity,Assigned to |link=none }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 (`outlineproperties=Severity`)",
+ "subject": "SRF/Outline/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<p style=\"font-size: small; font-weight: bold;\">Normal</p>",
+ "<ul>",
+ "<li>SRF/Outline/1 (Assigned to John)</li>",
+ "</ul>",
+ "<ul>",
+ "</ul>",
+ "<p style=\"font-size: small; font-weight: bold;\">Urgent</p>",
+ "<ul>",
+ "<li>SRF/Outline/2 (Assigned to Jane)</li>",
+ "<li>SRF/Outline/3 (Assigned to 田中)</li>",
+ "</ul>",
+ "<ul>",
+ "</ul>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 (`outlineproperties=Severity,Assigned to`)",
+ "subject": "SRF/Outline/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "<p style=\"font-size: medium; font-weight: regular;\">Normal</p>",
+ "<ul>",
+ "<p style=\"font-size: small; font-weight: bold;\">John</p>",
+ "<ul>",
+ "<li>SRF/Outline/1</li>",
+ "</ul>",
+ "<ul>",
+ "</ul>",
+ "</ul>",
+ "<p style=\"font-size: medium; font-weight: regular;\">Urgent</p>",
+ "<ul>",
+ "<p style=\"font-size: small; font-weight: bold;\">Jane</p>",
+ "<ul>",
+ "<li>SRF/Outline/2</li>",
+ "</ul>",
+ "<ul>",
+ "</ul>",
+ "<p style=\"font-size: small; font-weight: bold;\">田中</p>",
+ "<ul>",
+ "<li>SRF/Outline/3</li>",
+ "</ul>",
+ "<ul>",
+ "</ul>",
+ "</ul>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-01.json
new file mode 100644
index 00000000..c2800225
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-01.json
@@ -0,0 +1,70 @@
+{
+ "description": "Test `format=tagcloud` html output",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "TagcloudTemplate",
+ "namespace": "NS_TEMPLATE",
+ "contents": "<includeonly>T: {{{1}}}</includeonly>"
+ },
+ {
+ "page": "Example/Tagcloud/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Tagcloud]]"
+ },
+ {
+ "page": "Example/Tagcloud/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Tagcloud]]"
+ },
+ {
+ "page": "Example/Tagcloud/3",
+ "contents": "[[Has date::3 Jan 1970]] [[Has date::4 Jan 1970]] [[Category:Tagcloud]]"
+ },
+ {
+ "page": "Test/Tagcloud/Q.1",
+ "contents": "{{#ask: [[Category:Tagcloud]] |?Has date |format=tagcloud }}"
+ },
+ {
+ "page": "Test/Tagcloud/Q.2",
+ "contents": "{{#ask: [[Category:Tagcloud]] |?Has date |template=TagcloudTemplate |format=tagcloud }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0",
+ "subject": "Test/Tagcloud/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"srf-tagcloud\" data-version=\"0.4.1\"><span style=\"font-size:77%\">1 January 1970</span> <span style=\"font-size:242%\">3 January 1970</span> <span style=\"font-size:77%\">4 January 1970</span></div>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#0 with template",
+ "subject": "Test/Tagcloud/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "<div class=\"srf-tagcloud\" data-version=\"0.4.1\"><span style=\"font-size:77%\">T: 1 January 1970</span> <span style=\"font-size:242%\">T: 3 January 1970</span> <span style=\"font-size:77%\">T: 4 January 1970</span></div>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-02.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-02.json
new file mode 100644
index 00000000..525b867a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tagcloud-02.json
@@ -0,0 +1,78 @@
+{
+ "description": "Test `format=tagcloud` html output, namespaced",
+ "setup": [
+ {
+ "page": "Has page",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "page": "TagcloudTemplate",
+ "namespace": "NS_TEMPLATE",
+ "contents": "<includeonly>{{{1}}}</includeonly>"
+ },
+ {
+ "page": "Example/Tagcloud/1",
+ "namespace": "NS_HELP",
+ "contents": "[[Has page::Help:Test1]] [[Category:Tagcloud-2]]"
+ },
+ {
+ "page": "Example/Tagcloud/2",
+ "namespace": "NS_HELP",
+ "contents": "[[Has page::Help:Test2]] [[Category:Tagcloud-2]]"
+ },
+ {
+ "page": "Example/Tagcloud/3",
+ "namespace": "NS_HELP",
+ "contents": "[[Has page::Help:Test3]] [[Category:Tagcloud-2]]"
+ },
+ {
+ "page": "Test/Tagcloud/Q.1",
+ "contents": "{{#ask: [[Category:Tagcloud-2]] |?Has page |format=tagcloud }}"
+ },
+ {
+ "page": "Test/Tagcloud/Q.2",
+ "contents": "{{#ask: [[Category:Tagcloud-2]] |?Has page |template=TagcloudTemplate |format=tagcloud }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 (namespaced page value)",
+ "subject": "Test/Tagcloud/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<a href=.* class=\"new\" title=\"Help:Test1.*\">Help:Test1</a>",
+ "<a href=.* class=\"new\" title=\"Help:Test2.*\">Help:Test2</a>",
+ "<a href=.* class=\"new\" title=\"Help:Test3.*\">Help:Test3</a>"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "#1 (#355, template namespaced page value)",
+ "subject": "Test/Tagcloud/Q.2",
+ "assert-output": {
+ "to-contain": [
+ "<span style=\"font-size:77%\">Help:Test1</span>",
+ "<span style=\"font-size:77%\">Help:Test2</span>",
+ "<span style=\"font-size:77%\">Help:Test3</span>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "NS_HELP":true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/timeline-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/timeline-01.json
new file mode 100644
index 00000000..fc0e475c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/timeline-01.json
@@ -0,0 +1,50 @@
+{
+ "description": "Test for timeline result format",
+ "setup": [
+ {
+ "page": "Has date",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Example/Timeline/1",
+ "contents": "[[Has date::1 Jan 1970]] [[Category:Timeline]]"
+ },
+ {
+ "page": "Example/Timeline/2",
+ "contents": "[[Has date::3 Jan 1970]] [[Category:Timeline]]"
+ },
+ {
+ "page": "Example/Timeline/Q.1",
+ "contents": "{{#ask: [[Category:Timeline]] |?Has date |format=timeline }}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 default bands",
+ "subject": "Example/Timeline/Q.1",
+ "assert-output": {
+ "to-contain": [
+ "<div id=\"smwtimeline.* class=\"smwtimeline is-disabled\" style=\"height: 300px\">",
+ "<span class=\"smwtlband\" style=\"display:none;\">MONTH</span><span class=\"smwtlband\" style=\"display:none;\">YEAR</span>",
+ "<span class=\"smwtlurl\"><a .* title=\"Example/Timeline/1\">Example/Timeline/1</a></span><span class=\"smwtlstart\">1970-01-01</span>",
+ "<span class=\"smwtlurl\"><a .* title=\"Example/Timeline/2\">Example/Timeline/2</a></span><span class=\"smwtlstart\">1970-01-03</span>"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-01.json
new file mode 100644
index 00000000..df5288c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-01.json
@@ -0,0 +1,222 @@
+{
+ "description": "Tree format: Multi-page results",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Example/Tree 1",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 2",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 3",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 11",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 12",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 13",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 21",
+ "contents": "[[Has parent::Example/Tree 2]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 22",
+ "contents": "[[Has parent::Example/Tree 2]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 31",
+ "contents": "[[Has parent::Example/Tree 3]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 32",
+ "contents": "[[Has parent::Example/Tree 3]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 33",
+ "contents": "[[Has parent::Example/Tree 3]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 121",
+ "contents": "[[Has parent::Example/Tree 12]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 321",
+ "contents": "[[Has parent::Example/Tree 32]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 01-01",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent}}</div>"
+ },
+ {
+ "page": "Example/Tree 01-02",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent|root=Example/Tree 1}}</div>"
+ },
+ {
+ "page": "Example/Tree 01-03",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=ultree|parent=Has parent}}</div>"
+ },
+ {
+ "page": "Example/Tree 01-04",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=ultree|parent=Has parent|root=Example/Tree 3}}</div>"
+ },
+ {
+ "page": "Example/Tree 01-05",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=oltree|parent=Has parent}}</div>"
+ },
+ {
+ "page": "Example/Tree 01-06",
+ "contents": "<div>{{#ask:[[Part of::Tree test]]|format=oltree|parent=Has parent|root=Example/Tree 2}}</div>"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Tree 01-01 (Multi-page result)",
+ "subject": "Example/Tree 01-01",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 21\"]:only-child",
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 22\"]:only-child",
+
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 31\"]:only-child",
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 32\"] + ul > li:only-child > a[title=\"Example/Tree 321\"]:only-child",
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 33\"]:only-child",
+
+ [ "div > ul:only-child", 1 ],
+ [ "div > ul > li", 3 ],
+ [ "div > ul > li > ul > li", 8 ],
+ [ "div > ul > li > ul > li > ul > li", 2 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 01-02 (Multi-page result with root specified)",
+ "subject": "Example/Tree 01-02",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:only-child > a[title=\"Example/Tree 1\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ul > li:only-child > a[title=\"Example/Tree 1\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ul > li:only-child > a[title=\"Example/Tree 1\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ [ "div > ul > li", 1 ],
+ [ "div > ul > li > ul > li", 3 ],
+ [ "div > ul > li > ul > li > ul > li", 1 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 01-03 (Multi-page result (ultree))",
+ "subject": "Example/Tree 01-03",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 21\"]:only-child",
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 22\"]:only-child",
+
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 31\"]:only-child",
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 32\"] + ul > li:only-child > a[title=\"Example/Tree 321\"]:only-child",
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 33\"]:only-child",
+
+ [ "div > ul > li", 3 ],
+ [ "div > ul > li > ul > li", 8 ],
+ [ "div > ul > li > ul > li > ul > li", 2 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 01-04 (Multi-page result with root specified (ultree))",
+ "subject": "Example/Tree 01-04",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:only-child > a[title=\"Example/Tree 3\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 31\"]:only-child",
+ "div > ul > li:only-child > a[title=\"Example/Tree 3\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 32\"] + ul > li:only-child > a[title=\"Example/Tree 321\"]:only-child",
+ "div > ul > li:only-child > a[title=\"Example/Tree 3\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 33\"]:only-child",
+
+ [ "div > ul > li", 1 ],
+ [ "div > ul > li > ul > li", 3 ],
+ [ "div > ul > li > ul > li > ul > li", 1 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 01-05 (Multi-page result (oltree))",
+ "subject": "Example/Tree 01-05",
+ "assert-output": {
+ "to-contain": [
+ "div > ol > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ol > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ol > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ol > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ol > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ol > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ol > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ "div > ol > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ol > li:nth-child(1) > a[title=\"Example/Tree 21\"]:only-child",
+ "div > ol > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ol > li:nth-child(2) > a[title=\"Example/Tree 22\"]:only-child",
+
+ "div > ol > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ol > li:nth-child(1) > a[title=\"Example/Tree 31\"]:only-child",
+ "div > ol > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ol > li:nth-child(2) > a[title=\"Example/Tree 32\"] + ol > li:only-child > a[title=\"Example/Tree 321\"]:only-child",
+ "div > ol > li:nth-child(3) > a[title=\"Example/Tree 3\"] + ol > li:nth-child(3) > a[title=\"Example/Tree 33\"]:only-child",
+
+ [ "div > ol > li", 3 ],
+ [ "div > ol > li > ol > li", 8 ],
+ [ "div > ol > li > ol > li > ol > li", 2 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 01-06 (Multi-page result with root specified (oltree))",
+ "subject": "Example/Tree 01-06",
+ "assert-output": {
+ "to-contain": [
+ "div > ol > li:only-child > a[title=\"Example/Tree 2\"] + ol > li:nth-child(1) > a[title=\"Example/Tree 21\"]:only-child",
+ "div > ol > li:only-child > a[title=\"Example/Tree 2\"] + ol > li:nth-child(2) > a[title=\"Example/Tree 22\"]:only-child",
+
+ [ "div > ol > li", 1 ],
+ [ "div > ol > li > ol > li", 2 ]
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": true
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-02.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-02.json
new file mode 100644
index 00000000..721c363a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-02.json
@@ -0,0 +1,91 @@
+{
+ "description": "Tree format: Simple one-page result",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "Example/Tree format template",
+ "contents": "FOO{{{1|}}}BAR"
+ },
+ {
+ "page": "Example/Tree 1",
+ "contents": "[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 02-01",
+ "contents": "{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent}}"
+ },
+ {
+ "page": "Example/Tree 02-02",
+ "contents": "{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent|template=Example/Tree format template }}"
+ },
+ {
+ "page": "Example/Tree 02-03",
+ "contents": "{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent|class=some-class}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Tree 02-01 (Simple one-page result)",
+ "subject": "Example/Tree 02-01",
+ "assert-output": {
+ "to-contain": [
+ "ul > li:only-child > a[title=\"Example/Tree 1\"]:only-child"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 02-02-1 (Simple one-page result with template - structure)",
+ "subject": "Example/Tree 02-02",
+ "assert-output": {
+ "to-contain": [
+ "ul > li:only-child > a[title=\"Example/Tree 1\"]:only-child"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Tree 02-02-2 (Simple one-page result with template - content)",
+ "subject": "Example/Tree 02-02",
+ "assert-output": {
+ "to-contain": [
+ "FOO.*Example/Tree 1.*BAR"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 02-03 (Simple one-page result with class parameter)",
+ "subject": "Example/Tree 02-03",
+ "assert-output": {
+ "to-contain": [
+ "div.some-class > ul > li:only-child > a[title=\"Example/Tree 1\"]:only-child"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-03.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-03.json
new file mode 100644
index 00000000..c90493d5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-03.json
@@ -0,0 +1,43 @@
+{
+ "description": "Tree format: Raising error: Missing 'parent' parameter",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Example/Boostrap",
+ "contents": "[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 03-01",
+ "contents": "{{#ask:[[Part of::Tree test]]|format=tree}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "Tree 03-01 (Raising error: Missing 'parent' parameter)",
+ "subject": "Example/Tree 03-01",
+ "assert-output": {
+ "to-contain": [
+ "No parent property given. The tree can not be built without a specified parent property."
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-04.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-04.json
new file mode 100644
index 00000000..c1176503
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-04.json
@@ -0,0 +1,44 @@
+{
+ "description": "Tree format: Empty resultset does not produce tree",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Example/Tree 04-01",
+ "contents": "{{#ask:[[Part of::+]]|format=tree|parent=Has example}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Tree 04-01 (Empty resultset does not produce tree)",
+ "subject": "Example/Tree 04-01",
+ "assert-output": {
+ "to-contain": [
+ [ "div.srf-tree", 0 ]
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-05.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-05.json
new file mode 100644
index 00000000..c9d82e6d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-05.json
@@ -0,0 +1,76 @@
+{
+ "description": "Tree format: Loop detection",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Example/Tree 1",
+ "contents": "[[Has parent::Example/Tree 121]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 2",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 3",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 11",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 12",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 31",
+ "contents": "[[Has parent::Example/Tree 3]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 32",
+ "contents": "[[Has parent::Example/Tree 3]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 121",
+ "contents": "[[Has parent::Example/Tree 12]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 05-01",
+ "contents": "{{#ask:[[Part of::Tree test]]|format=tree|parent=Has parent}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "Tree 05-01 (Loop detection)",
+ "subject": "Example/Tree 05-01",
+ "assert-output": {
+ "to-contain": [
+ "Circle detected when trying to insert Example/Tree 121 into the tree."
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": true
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-06.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-06.json
new file mode 100644
index 00000000..c6bc3184
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-06.json
@@ -0,0 +1,127 @@
+{
+ "description": "Tree format: Insert elements with multiple parents multiple times",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "Example/Tree format template",
+ "contents": "FOO{{{1|}}}BAR"
+ },
+ {
+ "page": "Example/Tree 1",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 2",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 3",
+ "contents": "<!-- No parent -->[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 11",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 12",
+ "contents": "[[Has parent::Example/Tree 1]][[Has parent::Example/Tree 2]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 13",
+ "contents": "[[Has parent::Example/Tree 1]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 121",
+ "contents": "[[Has parent::Example/Tree 12]][[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 06-01",
+ "contents": "<div>{{#ask:[[Part of::Tree test]] |format=tree |parent=Has parent }}</div>"
+ },
+ {
+ "page": "Example/Tree 06-02",
+ "contents": "<div>{{#ask:[[Part of::Tree test]] |format=tree |parent=Has parent |template=Example/Tree format template }}</div>"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Tree 06-01 (Insert elements with multiple parents multiple times)",
+ "subject": "Example/Tree 06-01",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:only-child > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"]:only-child",
+
+ [ "div > ul > li", 3 ],
+ [ "div > ul > li > ul > li", 4 ],
+ [ "div > ul > li > ul > li > ul > li", 2 ]
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 06-02-1 (Insert elements with multiple parents multiple times (with template)) - structure",
+ "subject": "Example/Tree 06-02",
+ "assert-output": {
+ "to-contain": [
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(1) > a[title=\"Example/Tree 11\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(2) > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+ "div > ul > li:nth-child(1) > a[title=\"Example/Tree 1\"] + ul > li:nth-child(3) > a[title=\"Example/Tree 13\"]:only-child",
+
+ "div > ul > li:nth-child(2) > a[title=\"Example/Tree 2\"] + ul > li:only-child > a[title=\"Example/Tree 12\"] + ul > li:only-child > a[title=\"Example/Tree 121\"]:only-child",
+
+ "div > ul > li:nth-child(3) > a[title=\"Example/Tree 3\"]:only-child",
+
+ [ "div > ul > li", 3 ],
+ [ "div > ul > li > ul > li", 4 ],
+ [ "div > ul > li > ul > li > ul > li", 2 ]
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Tree 06-02-2 (Insert elements with multiple parents multiple times (with template)) - content",
+ "subject": "Example/Tree 06-02",
+ "assert-output": {
+ "to-contain": [
+ "FOO.*Example/Tree 1.*BAR",
+ "FOO.*Example/Tree 11.*BAR",
+ "FOO.*Example/Tree 12.*BAR",
+ "FOO.*Example/Tree 121.*BAR",
+ "FOO.*Example/Tree 13.*BAR",
+ "FOO.*Example/Tree 2.*BAR",
+ "FOO.*Example/Tree 3.*BAR"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": true
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-07.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-07.json
new file mode 100644
index 00000000..8b09e758
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/tree-07.json
@@ -0,0 +1,139 @@
+{
+ "description": "Tree format: Simple one-page result",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has parent",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Part of",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "namespace": "NS_TEMPLATE",
+ "page": "Example/Tree format template",
+ "contents": "FOO{{{1|}}}BAR{{{userparam|}}}BAZ"
+ },
+ {
+ "page": "Example/Tree 1",
+ "contents": "[[Part of::Tree test]]"
+ },
+ {
+ "page": "Example/Tree 11",
+ "contents": "[[Part of::Tree test]][[Has parent::Example/Tree 1]]"
+ },
+ {
+ "page": "Example/Tree 07-01",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent }}"
+ },
+ {
+ "page": "Example/Tree 07-02",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent |link=all}}"
+ },
+ {
+ "page": "Example/Tree 07-03",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent |link=subject}}"
+ },
+ {
+ "page": "Example/Tree 07-04",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent |link=none}}"
+ },
+ {
+ "page": "Example/Tree 07-05",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent |template=Example/Tree format template |userparam=someparam }}"
+ },
+ {
+ "page": "Example/Tree 07-06",
+ "contents": "{{#ask:[[Part of::Tree test]] |?Has parent |format=tree |parent=Has parent |template=Example/Tree format template |userparam=someparam |link=none}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser-html",
+ "about": "Tree 07-01 (Default linking)",
+ "subject": "Example/Tree 07-01",
+ "assert-output": {
+ "to-contain": [
+ "ul > li > a[title=\"Example/Tree 1\"] + ul > li > a[title=\"Example/Tree 11\"] + a[title=\"Property:Has parent\"] + a[title=\"Example/Tree 1\"]"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 07-02 (link=all)",
+ "subject": "Example/Tree 07-02",
+ "assert-output": {
+ "to-contain": [
+ "ul > li > a[title=\"Example/Tree 1\"] + ul > li > a[title=\"Example/Tree 11\"] + a[title=\"Property:Has parent\"] + a[title=\"Example/Tree 1\"]"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 07-03 (link=subject)",
+ "subject": "Example/Tree 07-03",
+ "assert-output": {
+ "to-contain": [
+ "ul > li > a[title=\"Example/Tree 1\"] + ul > li > a[title=\"Example/Tree 11\"]:first-of-type + a[title=\"Property:Has parent\"]:last-of-type"
+
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 07-04 (link=none)",
+ "subject": "Example/Tree 07-04",
+ "assert-output": {
+ "to-contain": [
+ "ul > li > ul:only-child > li > a[title=\"Property:Has parent\"]:only-child"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Tree 07-05-1 (template with userparam)",
+ "subject": "Example/Tree 07-05",
+ "assert-output": {
+ "to-contain": [
+ "BARsomeparamBAZ"
+ ]
+ }
+ },
+ {
+ "type": "parser-html",
+ "about": "Tree 07-05-2 (template with userparam: assert intact default linking)",
+ "subject": "Example/Tree 07-05",
+ "assert-output": {
+ "to-contain": [
+ "ul > li > a[title=\"Example/Tree 1\"] + ul > li > a[title=\"Example/Tree 11\"]"
+ ]
+ }
+ },
+ {
+ "type": "parser",
+ "about": "Tree 07-06 (template with userparam and link=none)",
+ "subject": "Example/Tree 07-06",
+ "assert-output": {
+ "to-contain": [
+ "FOOExample/Tree 1BARsomeparamBAZ",
+ "FOOExample/Tree 11BARsomeparamBAZ"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/vcard-01.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/vcard-01.json
new file mode 100644
index 00000000..536f5a8d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/TestCases/vcard-01.json
@@ -0,0 +1,136 @@
+{
+ "description": "Test `format=vcard`",
+ "setup": [
+ {
+ "page": "Has birthday",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Date]]"
+ },
+ {
+ "page": "Has address",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has cellphone",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Phone]]"
+ },
+ {
+ "page": "Has homephone",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Phone]]"
+ },
+ {
+ "page": "Has note",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Text]]"
+ },
+ {
+ "page": "Has homepage",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::URL]]"
+ },
+ {
+ "page": "Has email",
+ "namespace": "SMW_NS_PROPERTY",
+ "contents": "[[Has type::Email]]"
+ },
+ {
+ "page": "Example/Vcard-01/0",
+ "contents": "[[Category:Vcard-00]]"
+ },
+ {
+ "page": "Example/Vcard-01/1",
+ "contents": "[[Category:Vcard-01]] [[Has name::John Doe]] [[Has birthday::1 Jan 1952]] [[Has email::johnDoe@example.org]] [[Has homepage::http://www.example/com/doe]] [[Has address::Example Avenue]] [[Has town::Anytown]] [[Has cellphone::+1 781 555 1212]] [[Has homephone::+1 202 555 1212]] [[Has note::John Doe has a long and varied history, being documented on more ...]]"
+ },
+ {
+ "page": "Example/Vcard-01/2",
+ "contents": "{{#subobject: |Has name=John Doe |Has birthday=1 Jan 1952 |Has email=johnDoe@example.org |Has homepage=http://www.example/com/doe |Has address=Example Avenue |Has town=Anytown |Has cellphone=+1 781 555 1212 |Has homephone=+1 202 555 1212 |Has note=John Doe has a long and varied history, being documented on more ... |@category=Vcard-02}}"
+ }
+ ],
+ "tests": [
+ {
+ "type": "special",
+ "about": "#0 `format=vcard` empty",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "vcard"
+ },
+ "q": "[[Category:Vcard-00]]",
+ "po": "?Category=category"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/vcard-01.0.txt"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#1 `format=vcard` name + address",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "vcard"
+ },
+ "q": "[[Category:Vcard-01]]",
+ "po": "?Has name=name|?Has birthday=birthday|?Has email=email|?Has homepage=homepage|?Has address=homestreet|?has town=homelocality|?Has cellphone=cellphone|?Has homephone=homephone|?Has note=note"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/vcard-01.1.txt"
+ }
+ }
+ },
+ {
+ "type": "special",
+ "about": "#2 `format=vcard` name + address (subobject)",
+ "special-page": {
+ "page": "Ask",
+ "request-parameters": {
+ "p": {
+ "link": "none",
+ "limit": "10",
+ "offset": "0",
+ "mainlabel": "",
+ "format": "vcard"
+ },
+ "q": "[[Category:Vcard-02]]",
+ "po": "?Has name=name|?Has birthday=birthday|?Has email=email|?Has homepage=homepage|?Has address=homestreet|?has town=homelocality|?Has cellphone=cellphone|?Has homephone=homephone|?Has note=note"
+ }
+ },
+ "assert-output": {
+ "to-contain": {
+ "contents-file" : "/../Fixtures/vcard-01.2.txt"
+ }
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/bootstrap.json b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/bootstrap.json
new file mode 100644
index 00000000..da01021e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/JSONScript/bootstrap.json
@@ -0,0 +1,53 @@
+{
+ "description": "Example bootstrap test case (see https://youtu.be/7fDKjPFaTaY)",
+ "setup": [
+ {
+ "namespace": "SMW_NS_PROPERTY",
+ "page": "Has example",
+ "contents": "[[Has type::Page]]"
+ },
+ {
+ "page": "Example/Boostrap",
+ "contents": "[[Has example::Example123]]"
+ }
+ ],
+ "tests": [
+ {
+ "type": "parser",
+ "about": "#0 (page type annotation)",
+ "subject": "Example/Boostrap",
+ "assert-store": {
+ "semantic-data": {
+ "strictPropertyValueMatch": false,
+ "propertyCount": 3,
+ "propertyKeys": [
+ "_SKEY",
+ "_MDAT",
+ "Has example"
+ ],
+ "propertyValues": [
+ "Example123"
+ ]
+ }
+ },
+ "assert-output": {
+ "to-contain": [
+ "Example123"
+ ]
+ }
+ }
+ ],
+ "settings": {
+ "wgContLang": "en",
+ "wgLang": "en",
+ "smwgNamespacesWithSemanticLinks": {
+ "NS_MAIN": true,
+ "SMW_NS_PROPERTY": true
+ }
+ },
+ "meta": {
+ "version": "2",
+ "is-incomplete": false,
+ "debug": false
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/ResourcesTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/ResourcesTest.php
new file mode 100644
index 00000000..20b55c40
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Integration/ResourcesTest.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace SRF\Tests\Integration;
+
+use ResourceLoader;
+use ResourceLoaderContext;
+use ResourceLoaderModule;
+
+/**
+ * Tests for resource definitions and files
+ *
+ * @file
+ * @since 1.9
+ *
+ * @ingroup SRF
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class ResourcesTest extends \PHPUnit_Framework_TestCase {
+
+ /**
+ * Helper method to load resources only valid for this extension
+ *
+ * @return array
+ */
+ private function getSRFResourceModules() {
+ global $srfgIP;
+ return include $srfgIP . '/' . 'Resources.php';
+ }
+
+ public function moduleDataProvider() {
+
+ // #501
+ // MW 1.33+
+ if ( class_exists( '\MediaWiki\MediaWikiServices' ) && method_exists( '\MediaWiki\MediaWikiServices', 'getResourceLoader' ) ) {
+ $resourceLoader = \MediaWiki\MediaWikiServices::getInstance()->getResourceLoader();
+ } else {
+ $resourceLoader = new ResourceLoader();
+ }
+
+ $context = ResourceLoaderContext::newDummyContext();
+ $modules = $this->getSRFResourceModules();
+
+ return [ [ $modules, $resourceLoader, $context ] ];
+ }
+
+ /**
+ * @dataProvider moduleDataProvider
+ */
+ public function testModulesScriptsFilesAreAccessible( $modules, ResourceLoader $resourceLoader, $context ) {
+ foreach ( $modules as $name => $values ) {
+ $module = $resourceLoader->getModule( $name );
+ $scripts = $module->getScript( $context );
+ $this->assertInternalType( 'string', $scripts );
+ }
+ }
+
+ /**
+ * Test styles accessibility
+ *
+ * @dataProvider moduleDataProvider
+ */
+ public function testModulesStylesFilesAreAccessible( $modules, ResourceLoader $resourceLoader, $context ) {
+
+ foreach ( $modules as $name => $values ) {
+
+ // Get module details
+ $module = $resourceLoader->getModule( $name );
+
+ // Get styles per module
+ $styles = $module->getStyles( $context );
+ $this->assertContainsOnly( 'string', $styles );
+ }
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/ResultPrinterReflector.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/ResultPrinterReflector.php
new file mode 100644
index 00000000..5b9f3ae6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/ResultPrinterReflector.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace SRF\Tests;
+
+use ReflectionClass;
+use SMW\Query\ResultPrinter;
+
+/**
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class ResultPrinterReflector {
+
+ /**
+ * Helper method sets result printer parameters
+ *
+ * @param ResultPrinter $instance
+ * @param array $parameters
+ *
+ * @return ResultPrinter
+ */
+ public function addParameters( ResultPrinter $instance, array $parameters ) {
+
+ $reflector = new ReflectionClass( $instance );
+ $params = $reflector->getProperty( 'params' );
+ $params->setAccessible( true );
+ $params->setValue( $instance, $parameters );
+
+ if ( isset( $parameters['searchlabel'] ) ) {
+ $searchlabel = $reflector->getProperty( 'mSearchlabel' );
+ $searchlabel->setAccessible( true );
+ $searchlabel->setValue( $instance, $parameters['searchlabel'] );
+ }
+
+ if ( isset( $parameters['headers'] ) ) {
+ $searchlabel = $reflector->getProperty( 'mShowHeaders' );
+ $searchlabel->setAccessible( true );
+ $searchlabel->setValue( $instance, $parameters['headers'] );
+ }
+
+ return $instance;
+ }
+
+ public function invoke( ResultPrinter $instance, $queryResult, $outputMode ) {
+
+ $reflector = new ReflectionClass( $instance );
+ $method = $reflector->getMethod( 'getResultText' );
+ $method->setAccessible( true );
+
+ return $method->invoke( $instance, $queryResult, $outputMode );
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/BibTexFileExportPrinterTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/BibTexFileExportPrinterTest.php
new file mode 100644
index 00000000..86432d11
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/BibTexFileExportPrinterTest.php
@@ -0,0 +1,149 @@
+<?php
+
+namespace SRF\Tests\BibTex;
+
+use PHPUnit\Framework\MockObject\MockObject;
+use SMWInfolink;
+use SMWQueryResult;
+use SRF\BibTex\BibTexFileExportPrinter;
+use SRF\Tests\ResultPrinterReflector;
+
+/**
+ * @covers \SRF\BibTex\BibTexFileExportPrinter
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class BibTexFileExportPrinterTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ BibTexFileExportPrinter::class,
+ new BibTexFileExportPrinter( 'bibtex' )
+ );
+ }
+
+ /**
+ * @dataProvider filenameProvider
+ */
+ public function testGetFileName( $filename, $searchlabel, $expected ) {
+
+ $parameters = [
+ 'filename' => $filename,
+ 'searchlabel' => $searchlabel
+ ];
+
+ $bibTexPrinter = new BibTexFileExportPrinter( 'bibtex' );
+
+ ( new ResultPrinterReflector() )->addParameters( $bibTexPrinter, $parameters );
+
+ $this->assertEquals(
+ $expected,
+ $bibTexPrinter->getFileName( $this->newQueryResultDummy() )
+ );
+ }
+
+ public function filenameProvider() {
+
+ yield[
+ '',
+ '',
+ 'BibTeX.bib'
+ ];
+
+ yield[
+ '',
+ 'foo bar',
+ 'foo_bar.bib'
+ ];
+
+ yield[
+ 'foo',
+ '',
+ 'foo.bib'
+ ];
+
+ yield[
+ 'foo.bib',
+ '',
+ 'foo.bib'
+ ];
+
+ yield[
+ 'foo bar.bib',
+ '',
+ 'foo_bar.bib'
+ ];
+ }
+
+ /**
+ * @return MockObject|SMWQueryResult
+ */
+ private function newQueryResultDummy() {
+ return $this->getMockBuilder( SMWQueryResult::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testGetMimeType() {
+
+ $instance = new BibTexFileExportPrinter(
+ 'bibtex'
+ );
+
+ $this->assertEquals(
+ 'text/bibtex',
+ $instance->getMimeType( $this->newQueryResultDummy() )
+ );
+ }
+
+ public function testGetResult_LinkOnNonFileOutput() {
+ $bibTexPrinter = new BibTexFileExportPrinter(
+ 'bibtex'
+ );
+
+ $this->assertEquals(
+ 'foo_link',
+ $bibTexPrinter->getResult(
+ $this->newMockQueryResultWithLink(),
+ [],
+ SMW_OUTPUT_HTML
+ )
+ );
+ }
+
+ private function newMockQueryResultWithLink() {
+ $queryResult = $this->newQueryResultDummy();
+
+ $queryResult->expects( $this->any() )
+ ->method( 'getErrors' )
+ ->will( $this->returnValue( [] ) );
+
+ $queryResult->expects( $this->any() )
+ ->method( 'getCount' )
+ ->will( $this->returnValue( 1 ) );
+
+ $queryResult->expects( $this->once() )
+ ->method( 'getQueryLink' )
+ ->will( $this->returnValue( $this->newInfoLinkStub() ) );
+
+ return $queryResult;
+ }
+
+ private function newInfoLinkStub() {
+ $link = $this->getMockBuilder( SMWInfolink::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $link->expects( $this->any() )
+ ->method( 'getText' )
+ ->will( $this->returnValue( 'foo_link' ) );
+
+ return $link;
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/ItemTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/ItemTest.php
new file mode 100644
index 00000000..b2102f6a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/BibTex/ItemTest.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace SRF\Tests\BibTex;
+
+use SRF\BibTex\Item;
+
+/**
+ * @covers \SRF\BibTex\Item
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class ItemTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ Item::class,
+ new Item()
+ );
+ }
+
+ /**
+ * @dataProvider fieldsProvider
+ */
+ public function testText( $fields, $expected ) {
+
+ $instance = new Item();
+
+ foreach ( $fields as $key => $value ) {
+ $instance->set( $key, $value );
+ }
+
+ $this->assertEquals(
+ $expected,
+ $instance->text()
+ );
+ }
+
+ /**
+ * @dataProvider formatterCallbackFieldsProvider
+ */
+ public function testFormatterCallback( $fields, $expected ) {
+
+ $instance = new Item();
+ $instance->setFormatterCallback( function( $key, $values ) {
+ return implode( '#', $values );
+ } );
+
+ foreach ( $fields as $key => $value ) {
+ $instance->set( $key, $value );
+ }
+
+ $this->assertEquals(
+ $expected,
+ $instance->text()
+ );
+ }
+
+ /**
+ * @dataProvider replaceTextProvider
+ */
+ public function testReplace( $key, $text, $expected ) {
+
+ $instance = new Item();
+
+ $this->assertEquals(
+ $expected,
+ $instance->replace( 'uri', $text )
+ );
+ }
+
+ public function fieldsProvider() {
+
+ yield [
+ [ 'foo' => 'test', 'author' => [ 'abc', 'def', '123' ] ],
+ "@Book{abc,\r\n author = \"abc, def, 123\", \r\n}"
+ ];
+
+ yield [
+ [ 'foo' => 'test', 'title' => 'foo bar', 'editor' => [ 'abc', 'def', '123' ] ],
+ "@Book{fb,\r\n editor = \"abc, def, 123\", \r\n title = \"foo bar\", \r\n}"
+ ];
+ }
+
+ public function formatterCallbackFieldsProvider() {
+
+ yield [
+ [ 'foo' => 'test', 'author' => [ 'abc', 'def', '123' ] ],
+ "@Book{abc,\r\n author = \"abc#def#123\", \r\n}"
+ ];
+
+ yield [
+ [ 'foo' => 'test', 'title' => 'foo bar', 'editor' => [ 'abc', 'def', '123' ] ],
+ "@Book{fb,\r\n editor = \"abc#def#123\", \r\n title = \"foo bar\", \r\n}"
+ ];
+ }
+
+ public function replaceTextProvider() {
+
+ yield [
+ 'uri',
+ 'abc-_+ÄäÖ',
+ 'abcAeaeOe'
+ ];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ArrayTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ArrayTest.php
new file mode 100644
index 00000000..69900f34
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ArrayTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Array class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class ArrayTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see ResultPrinterTest::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'array' ];
+ }
+
+ /**
+ * @see ResultPrinterTest::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFArray';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DataTablesTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DataTablesTest.php
new file mode 100644
index 00000000..1e0826fd
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DataTablesTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\DataTables class.
+ *
+ * @file
+ * @since 1.9
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class DataTablesTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.9
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'datatables' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.9
+ *
+ * @return string
+ */
+ public function getClass() {
+ return 'SRF\DataTables';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DygraphsTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DygraphsTest.php
new file mode 100644
index 00000000..f078b44c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/DygraphsTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Dygraphs class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class DygraphsTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'dygraphs' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return 'SRFDygraphs';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/EventCalendarTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/EventCalendarTest.php
new file mode 100644
index 00000000..44a52bae
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/EventCalendarTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\EventCalendar class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class EventCalendarTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'eventcalendar' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return 'SRF\EventCalendar';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GalleryTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GalleryTest.php
new file mode 100644
index 00000000..91eeeca7
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GalleryTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Gallery class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class GalleryTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'gallery' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return 'SRF\Gallery';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GanttTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GanttTest.php
new file mode 100644
index 00000000..8eda6159
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GanttTest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace SRF\Tests\Gantt;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+class GanttTest extends QueryPrinterRegistryTestCase{
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'gantt' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRF\Gantt\GanttPrinter';
+ }
+} \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GraphTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GraphTest.php
new file mode 100644
index 00000000..f55ef3df
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/GraphTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Array class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class GraphTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'graph' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRF\Graph\GraphPrinter';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/IncomingTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/IncomingTest.php
new file mode 100644
index 00000000..c38f5a33
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/IncomingTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Incoming class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class IncomingTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'incoming' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFIncoming';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ListWidgetTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ListWidgetTest.php
new file mode 100644
index 00000000..d7e737a4
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/ListWidgetTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\ListWidget class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class ListWidgetTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'listwidget' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFListWidget';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MathTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MathTest.php
new file mode 100644
index 00000000..fb6b1cf6
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MathTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Math class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class MathTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'max', 'min', 'sum', 'product', 'average', 'median' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFMath';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MediaPlayerTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MediaPlayerTest.php
new file mode 100644
index 00000000..469e48e1
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/MediaPlayerTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\MediaPlayer class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class MediaPlayerTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'media' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return 'SRF\MediaPlayer';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/PageWidgetTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/PageWidgetTest.php
new file mode 100644
index 00000000..34ae814c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/PageWidgetTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\PageWidget class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class PageWidgetTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'pagewidget' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFPageWidget';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SparklineTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SparklineTest.php
new file mode 100644
index 00000000..48ed8add
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SparklineTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Sparkline class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class SparklineTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'sparkline' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFSparkline';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SpreadsheetTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SpreadsheetTest.php
new file mode 100644
index 00000000..15783478
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/SpreadsheetTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+use SRF\SpreadsheetPrinter;
+
+/**
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ */
+class SpreadsheetTest extends QueryPrinterRegistryTestCase {
+
+ public function getFormats() {
+ return [ 'spreadsheet' ];
+ }
+
+ public function getClass() {
+ return 'SRF\SpreadsheetPrinter';
+ }
+
+ public function testLink() {
+
+ $link = $this->getMockBuilder( '\SMWInfolink' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $queryResult = $this->getMockBuilder( '\SMWQueryResult' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $queryResult->expects( $this->once() )
+ ->method( 'getQueryLink' )
+ ->will( $this->returnValue( $link ) );
+
+ $queryResult->expects( $this->any() )
+ ->method( 'getCount' )
+ ->will( $this->returnValue( 1 ) );
+
+ $queryResult->expects( $this->any() )
+ ->method( 'getErrors' )
+ ->will( $this->returnValue( [] ) );
+
+ $instance = new SpreadsheetPrinter( 'csv' );
+ $instance->getResult( $queryResult, [], SMW_OUTPUT_WIKI );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TagCloudTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TagCloudTest.php
new file mode 100644
index 00000000..f78b0c1c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TagCloudTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\TagCloud class.
+ *
+ * @since 1.8
+ *
+ * @file
+ *
+ * @ingroup SRF
+ * @ingroup Test
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+
+/**
+ * Tests for the SRF\TagCloud class.
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ */
+class TagCloudTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'tagcloud' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRF\TagCloud';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TimeseriesTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TimeseriesTest.php
new file mode 100644
index 00000000..495a7522
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TimeseriesTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Sparkline class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class TimeseriesTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'timeseries' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFTimeseries';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TreeTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TreeTest.php
new file mode 100644
index 00000000..8b4135db
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/TreeTest.php
@@ -0,0 +1,173 @@
+<?php
+
+namespace SRF\Test;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+use SMW\Tests\Utils\Mock\CoreMockObjectRepository;
+use SMW\Tests\Utils\Mock\MockObjectBuilder;
+use SMWQueryProcessor;
+use SRF\Formats\Tree\TreeResultPrinter;
+
+/**
+ * Class TreeTest
+ *
+ * @since 2.5
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @author Stephan Gambke
+ */
+class TreeTest extends QueryPrinterRegistryTestCase {
+
+ private $parser;
+ private $title;
+
+ private static $initial_parser;
+ private static $initial_title;
+
+ /**
+ * Keep the global state and restore it on tearDown to avoid influencing
+ * other tests in case this one fails in between.
+ */
+ public static function setUpBeforeClass() {
+ self::$initial_parser = $GLOBALS['wgParser'];
+ self::$initial_title = $GLOBALS['wgTitle'];
+ }
+
+ protected function tearDown() {
+ $GLOBALS['wgParser'] = self::$initial_parser;
+ $GLOBALS['wgTitle'] = self::$initial_title;
+
+ parent::tearDown();
+ }
+
+ /**
+ * Returns the names of the formats being tested.
+ *
+ * @return string[]
+ */
+ public function getFormats() {
+ return [ 'tree' ];
+ }
+
+ /**
+ * Returns the name of the class being tested.
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRF\Formats\Tree\TreeResultPrinter';
+ }
+
+ /**
+ */
+ public function testGetResult_NoParentProperty() {
+
+ $this->prepareGlobalState();
+
+ $mockBuilder = new MockObjectBuilder();
+ $mockBuilder->registerRepository( new CoreMockObjectRepository() );
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject $queryResult */
+ $queryResult = $mockBuilder->newObject( 'QueryResult', [ 'getCount' => 1 ] );
+
+ $queryResult->expects( $this->once() )
+ ->method( 'addErrors' )
+ ->will( $this->returnValue( null ) );
+
+ $params = SMWQueryProcessor::getProcessedParams( [ 'format' => 'tree' ], [] );
+
+ $testObject = new TreeResultPrinter( 'tree' );
+
+ $this->assertEquals(
+ '',
+ $testObject->getResult( $queryResult, $params, SMW_OUTPUT_HTML ),
+ 'Result should be empty.'
+ );
+
+ // Restore GLOBAL state to ensure that preceding tests do not use a
+ // mocked instance
+ $GLOBALS['wgParser'] = $this->parser;
+ $GLOBALS['wgTitle'] = $this->title;
+ }
+
+ protected function prepareGlobalState() {
+
+ // Store current state
+ $this->parser = $GLOBALS['wgParser'];
+ $this->title = $GLOBALS['wgTitle'];
+
+ $parserOutput = $this->getMockBuilder( '\ParserOutput' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $parserOutput->expects( $this->any() )
+ ->method( 'getHeadItems' )
+ ->will( $this->returnValue( [] ) );
+
+ $parser = $this->getMockBuilder( '\Parser' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $parser->expects( $this->any() )
+ ->method( 'parse' )
+ ->will( $this->returnValue( $parserOutput ) );
+
+ $title = $this->getMockBuilder( '\Title' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ // Careful!!
+ $GLOBALS['wgParser'] = $parser;
+ $GLOBALS['wgTitle'] = $title;
+ }
+
+ /**
+ * @return array
+ */
+ protected function provideQueryParamsAndResults() {
+ $mockBuilder = new MockObjectBuilder();
+ $mockBuilder->registerRepository( new CoreMockObjectRepository() );
+
+ /** @var \SMWResultArray[]|false $resultRow */
+ $resultRow = $mockBuilder->newObject( 'ResultArray' );
+
+ //$resultRow->add( $resultCell );
+
+ $resultSet[] = [];
+
+ $resultSet[] = $resultRow;
+
+ /** @var array(SMWResultArray[]|false) $resultSet */
+ $resultSet[] = false;
+
+ $queryResult = $mockBuilder->newObject(
+ 'QueryResult',
+ [
+ 'getCount' => 1,
+ ]
+ );
+
+ $queryResult->expects( $this->any() )
+ ->method( 'getNext' )
+ ->will( call_user_func( [ $this, 'onConsecutiveCalls' ], $resultSet ) );
+
+ $queryResult = $mockBuilder->newObject(
+ 'QueryResult',
+ [
+ 'getCount' => 1,
+ ]
+ );
+
+ $params = SMWQueryProcessor::getProcessedParams( [ 'format' => 'tree' ], [] );
+
+ $expected = '';
+
+ return [ $queryResult, $params, $expected ];
+ }
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotChartTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotChartTest.php
new file mode 100644
index 00000000..b51ee365
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotChartTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\jqPlotChart class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class jqPlotChartTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'jqplotchart' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFjqPlotChart';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotSeriesTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotSeriesTest.php
new file mode 100644
index 00000000..6ab2e5e8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/jqPlotSeriesTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\jqPlotSeries class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class jqPlotSeriesTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'jqplotseries' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRFjqPlotSeries';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/vCardTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/vCardTest.php
new file mode 100644
index 00000000..565d4955
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Formats/vCardTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\Unit\Formats;
+
+use SMW\Test\QueryPrinterRegistryTestCase;
+
+/**
+ * Tests for the SRF\Gallery class.
+ *
+ * @file
+ * @since 1.8
+ *
+ * @ingroup SemanticResultFormats
+ * @ingroup Test
+ *
+ * @group SRF
+ * @group SMWExtension
+ * @group ResultPrinters
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class vCardTest extends QueryPrinterRegistryTestCase {
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getFormats
+ *
+ * @since 1.8
+ *
+ * @return array
+ */
+ public function getFormats() {
+ return [ 'vcard' ];
+ }
+
+ /**
+ * @see QueryPrinterRegistryTestCase::getClass
+ *
+ * @since 1.8
+ *
+ * @return string
+ */
+ public function getClass() {
+ return '\SRF\vCard\vCardFileExportPrinter';
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/ListTreeBuilderTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/ListTreeBuilderTest.php
new file mode 100644
index 00000000..80679e90
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/ListTreeBuilderTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace SRF\Tests\Outline;
+
+use SRF\Outline\ListTreeBuilder;
+use SRF\Outline\OutlineTree;
+
+/**
+ * @covers \SRF\Outline\ListTreeBuilder
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class ListTreeBuilderTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ ListTreeBuilder::class,
+ new ListTreeBuilder( [] )
+ );
+ }
+
+ public function testBuildForEmptyTree() {
+
+ $params = [
+ 'outlineproperties' => [ 'Foo' ]
+ ];
+
+ $instance = new ListTreeBuilder( $params );
+
+ $this->assertInternalType(
+ 'string',
+ $instance->build( new OutlineTree() )
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineItemTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineItemTest.php
new file mode 100644
index 00000000..6819ee10
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineItemTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace SRF\Tests\Outline;
+
+use SRF\Outline\OutlineItem;
+
+/**
+ * @covers \SRF\Outline\OutlineItem
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class OutlineItemTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ OutlineItem::class,
+ new OutlineItem( [] )
+ );
+ }
+
+ public function testPropertyAccess() {
+
+ $instance = new OutlineItem( [ 'Foo' ] );
+
+ $this->assertEquals(
+ [ 'Foo' ],
+ $instance->row
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineResultPrinterTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineResultPrinterTest.php
new file mode 100644
index 00000000..523ecf9b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineResultPrinterTest.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace SRF\Tests\Outline;
+
+use SRF\Outline\OutlineResultPrinter;
+
+/**
+ * @covers \SRF\Outline\OutlineResultPrinter
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class OutlineResultPrinterTest extends \PHPUnit_Framework_TestCase {
+
+ private $queryResult;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->queryResult = $this->getMockBuilder( '\SMWQueryResult' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ OutlineResultPrinter::class,
+ new OutlineResultPrinter( 'outline' )
+ );
+ }
+
+ public function testGetResult_LinkOnNonFileOutput() {
+
+ $link = $this->getMockBuilder( '\SMWInfolink' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $link->expects( $this->any() )
+ ->method( 'getText' )
+ ->will( $this->returnValue( 'foo_link' ) );
+
+ $this->queryResult->expects( $this->any() )
+ ->method( 'getErrors' )
+ ->will( $this->returnValue( [] ) );
+
+ $this->queryResult->expects( $this->any() )
+ ->method( 'getCount' )
+ ->will( $this->returnValue( 1 ) );
+
+ $instance = new OutlineResultPrinter(
+ 'outline'
+ );
+
+ // IParam is an empty interface !!! so we use stdClass
+ $outlineproperties = $this->getMockBuilder( '\stdClass' )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'getName', 'getValue' ] )
+ ->getMock();
+
+ $outlineproperties->expects( $this->any() )
+ ->method( 'getName' )
+ ->will( $this->returnValue( 'outlineproperties' ) );
+
+ $outlineproperties->expects( $this->any() )
+ ->method( 'getValue' )
+ ->will( $this->returnValue( [] ) );
+
+ $template = $this->getMockBuilder( '\stdClass' )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'getName', 'getValue' ] )
+ ->getMock();
+
+ $template->expects( $this->any() )
+ ->method( 'getName' )
+ ->will( $this->returnValue( 'template' ) );
+
+ $template->expects( $this->any() )
+ ->method( 'getValue' )
+ ->will( $this->returnValue( '' ) );
+
+ $parameters = [
+ $outlineproperties,
+ $template
+ ];
+
+ $this->assertContains(
+ "<ul>\n</ul>\n",
+ $instance->getResult( $this->queryResult, $parameters, SMW_OUTPUT_HTML )
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineTreeTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineTreeTest.php
new file mode 100644
index 00000000..3af491c0
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/OutlineTreeTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace SRF\Tests\Outline;
+
+use SRF\Outline\OutlineTree;
+
+/**
+ * @covers \SRF\Outline\OutlineTree
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class OutlineTreeTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ OutlineTree::class,
+ new OutlineTree( [] )
+ );
+ }
+
+ public function testPropertyAccess() {
+
+ $instance = new OutlineTree();
+
+ $this->assertEmpty(
+ $instance->tree
+ );
+
+ $this->assertEmpty(
+ $instance->items
+ );
+
+ $this->assertEquals(
+ 0,
+ $instance->itemCount
+ );
+
+ $this->assertEquals(
+ 0,
+ $instance->leafCount
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/TemplateBuilderTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/TemplateBuilderTest.php
new file mode 100644
index 00000000..ac00d67c
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/Outline/TemplateBuilderTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace SRF\Tests\Outline;
+
+use SRF\Outline\TemplateBuilder;
+use SRF\Outline\OutlineTree;
+
+/**
+ * @covers \SRF\Outline\TemplateBuilder
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class TemplateBuilderTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ TemplateBuilder::class,
+ new TemplateBuilder( [] )
+ );
+ }
+
+ public function testBuildForEmptyTree() {
+
+ $params = [
+ 'outlineproperties' => [ 'Foo' ],
+ 'template' => 'Bar',
+ 'userparam' => ''
+ ];
+
+ $instance = new TemplateBuilder( $params );
+
+ $this->assertInternalType(
+ 'string',
+ $instance->build( new OutlineTree() )
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/ResourceFormatterTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/ResourceFormatterTest.php
new file mode 100644
index 00000000..9443b94a
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/ResourceFormatterTest.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace SRF\Tests;
+
+use SRF\ResourceFormatter;
+
+/**
+ * @covers \SRF\ResourceFormatter
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class ResourceFormatterTest extends \PHPUnit_Framework_TestCase {
+
+ public function testSession() {
+
+ $this->assertContains(
+ 'smw-',
+ ResourceFormatter::session()
+ );
+ }
+
+ public function testPlaceholder() {
+
+ $this->assertInternalType(
+ 'string',
+ ResourceFormatter::placeholder()
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/iCalendar/IcalTimezoneFormatterTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/iCalendar/IcalTimezoneFormatterTest.php
new file mode 100644
index 00000000..858af78b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/iCalendar/IcalTimezoneFormatterTest.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace SRF\Tests\iCalendar;
+
+use SMW\Tests\TestEnvironment;
+use SRF\iCalendar\IcalTimezoneFormatter;
+
+/**
+ * @covers \SRF\iCalendar\IcalTimezoneFormatter
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class IcalTimezoneFormatterTest extends \PHPUnit_Framework_TestCase {
+
+ private $stringValidator;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->stringValidator = TestEnvironment::newValidatorFactory()->newStringValidator();
+ }
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ IcalTimezoneFormatter::class,
+ new IcalTimezoneFormatter()
+ );
+ }
+
+ /**
+ * @dataProvider transitionsProvider
+ */
+ public function testGetTransitions( $tz, $from, $to, $expected ) {
+
+ $instance = new IcalTimezoneFormatter();
+ $instance->setLocalTimezones( $tz );
+ $instance->calcTransitions( $from, $to );
+
+ $this->stringValidator->assertThatStringContains(
+ $expected,
+ $instance->getTransitions()
+ );
+ }
+
+ public function transitionsProvider() {
+
+ // DTSTART can be different pending the OS hence use .*
+
+ yield [
+ 'UTC',
+ 1,
+ 2,
+ "BEGIN:VTIMEZONE\r\nTZID:UTC\r\nBEGIN:STANDARD\r\nDTSTART:.*\r\n" .
+ "TZOFFSETFROM:+0000\r\nTZOFFSETTO:+0000\r\nTZNAME:UTC\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"
+ ];
+
+ yield [
+ 'Asia/Bangkok',
+ 1,
+ 2,
+ "BEGIN:VTIMEZONE\r\nTZID:Asia/Bangkok\r\nBEGIN:STANDARD\r\nDTSTART:.*\r\n" .
+ // Travis-CI PHP 7 issue, outputs `TZNAME:+07`
+ // "TZOFFSETFROM:+0700\r\nTZOFFSETTO:+0700\r\nTZNAME:ICT\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"
+ "TZOFFSETFROM:+0700\r\nTZOFFSETTO:+0700\r\nTZNAME:.*\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"
+ ];
+
+ yield [
+ 'Asia/Tokyo',
+ 1,
+ 2,
+ "BEGIN:VTIMEZONE\r\nTZID:Asia/Tokyo\r\nBEGIN:STANDARD\r\nDTSTART:.*\r\n" .
+ "TZOFFSETFROM:+0900\r\nTZOFFSETTO:+0900\r\nTZNAME:JST\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"
+ ];
+
+ yield [
+ 'America/New_York',
+ 1,
+ 2,
+ "BEGIN:VTIMEZONE\r\nTZID:America/New_York\r\nBEGIN:STANDARD\r\nDTSTART:.*\r\n" .
+ "TZOFFSETFROM:-0500\r\nTZOFFSETTO:-0500\r\nTZNAME:EST\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"
+ ];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/AddressTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/AddressTest.php
new file mode 100644
index 00000000..0b4855b2
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/AddressTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace SRF\Tests\vCard;
+
+use SRF\vCard\Address;
+
+/**
+ * @covers \SRF\vCard\Address
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class AddressTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ Address::class,
+ new Address( '', [] )
+ );
+ }
+
+ public function testHasAddress() {
+
+ $instance = new Address( '', [] );
+
+ $this->assertFalse(
+ $instance->hasAddress()
+ );
+ }
+
+ public function testText() {
+
+ $adr = [
+ 'pobox' => '',
+ 'ext' => '',
+ 'street' => '2 Example Avenue',
+ 'locality' => 'Anytown',
+ 'region' => 'Foo',
+ 'code' => '01111',
+ 'country' => 'Bar'
+ ];
+
+ $instance = new Address( '', $adr );
+ $instance->set( 'region', 'Bar0042' );
+
+ $this->assertSame(
+ "ADR;TYPE=WORK;CHARSET=UTF-8:;;2 Example Avenue;Anytown;Bar0042;01111;Bar\r\n",
+ $instance->text()
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/EmailTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/EmailTest.php
new file mode 100644
index 00000000..51dfe2d5
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/EmailTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace SRF\Tests\vCard;
+
+use SRF\vCard\Email;
+
+/**
+ * @covers \SRF\vCard\Email
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class EmailTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ Email::class,
+ new Email( '', '' )
+ );
+ }
+
+ public function testText() {
+
+ $instance = new Email( '', 'johnDoe@example.org' );
+
+ $this->assertSame(
+ "EMAIL;TYPE=INTERNET:johnDoe@example.org\r\n",
+ $instance->text()
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/TelTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/TelTest.php
new file mode 100644
index 00000000..58ed6022
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/TelTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace SRF\Tests\vCard;
+
+use SRF\vCard\Tel;
+
+/**
+ * @covers \SRF\vCard\Tel
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class TelTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ Tel::class,
+ new Tel( '', '' )
+ );
+ }
+
+ public function testText() {
+
+ $instance = new Tel( '', '+1 781 555 1212' );
+
+ $this->assertSame(
+ "TEL;TYPE=WORK:+1 781 555 1212\r\n",
+ $instance->text()
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardFileExportPrinterTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardFileExportPrinterTest.php
new file mode 100644
index 00000000..f094268f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardFileExportPrinterTest.php
@@ -0,0 +1,133 @@
+<?php
+
+namespace SRF\Tests\vCard;
+
+use SRF\vCard\vCardFileExportPrinter;
+use SRF\Tests\ResultPrinterReflector;
+
+/**
+ * @covers \SRF\vCard\vCardFileExportPrinter
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2+
+ * @since 3.1
+ *
+ * @author mwjames
+ */
+class vCardFileExportPrinterTest extends \PHPUnit_Framework_TestCase {
+
+ private $queryResult;
+ private $resultPrinterReflector;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->resultPrinterReflector = new ResultPrinterReflector();
+
+ $this->queryResult = $this->getMockBuilder( '\SMWQueryResult' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ vCardFileExportPrinter::class,
+ new vCardFileExportPrinter( 'vcard' )
+ );
+ }
+
+ /**
+ * @dataProvider filenameProvider
+ */
+ public function testGetFileName( $filename, $searchlabel, $expected ) {
+
+ $parameters = [
+ 'filename' => $filename,
+ 'searchlabel' => $searchlabel
+ ];
+
+ $instance = new vCardFileExportPrinter(
+ 'vcard'
+ );
+
+ $this->resultPrinterReflector->addParameters( $instance, $parameters );
+
+ $this->assertEquals(
+ $expected,
+ $instance->getFileName( $this->queryResult )
+ );
+ }
+
+ public function testGetMimeType() {
+
+ $instance = new vCardFileExportPrinter(
+ 'vcard'
+ );
+
+ $this->assertEquals(
+ 'text/x-vcard',
+ $instance->getMimeType( $this->queryResult )
+ );
+ }
+
+ public function testGetResult_LinkOnNonFileOutput() {
+
+ $link = $this->getMockBuilder( '\SMWInfolink' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $link->expects( $this->any() )
+ ->method( 'getText' )
+ ->will( $this->returnValue( 'foo_link' ) );
+
+ $this->queryResult->expects( $this->any() )
+ ->method( 'getErrors' )
+ ->will( $this->returnValue( [] ) );
+
+ $this->queryResult->expects( $this->any() )
+ ->method( 'getCount' )
+ ->will( $this->returnValue( 1 ) );
+
+ $this->queryResult->expects( $this->once() )
+ ->method( 'getQueryLink' )
+ ->will( $this->returnValue( $link ) );
+
+ $instance = new vCardFileExportPrinter(
+ 'vcard'
+ );
+
+ $this->assertEquals(
+ 'foo_link',
+ $instance->getResult( $this->queryResult, [], SMW_OUTPUT_HTML )
+ );
+ }
+
+ public function filenameProvider() {
+
+ yield[
+ '',
+ 'foo bar',
+ 'foo_bar.vcf'
+ ];
+
+ yield[
+ 'foo',
+ '',
+ 'foo.vcf'
+ ];
+
+ yield[
+ 'foo.vcf',
+ '',
+ 'foo.vcf'
+ ];
+
+ yield[
+ 'foo bar.vcf',
+ '',
+ 'foo_bar.vcf'
+ ];
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardTest.php b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardTest.php
new file mode 100644
index 00000000..2467df95
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/phpunit/Unit/vCard/vCardTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace SRF\Tests\vCard;
+
+use SRF\vCard\vCard;
+
+/**
+ * @covers \SRF\vCard\vCard
+ * @group semantic-result-formats
+ *
+ * @license GNU GPL v2"
+ * @since 3.0
+ *
+ * @author mwjames
+ */
+class vCardTest extends \PHPUnit_Framework_TestCase {
+
+ public function testCanConstruct() {
+
+ $this->assertInstanceOf(
+ vCard::class,
+ new vCard( '', '', [] )
+ );
+ }
+
+ public function testEmptyCard() {
+
+ $instance = new vCard( 'http://example.org/Foo', 'Foo', [] );
+ $instance->set( 'url', 'http://example.org/Bar' );
+
+ $this->assertSame(
+ "BEGIN:VCARD\r\n" .
+ "VERSION:3.0\r\n" .
+ "N;CHARSET=UTF-8:Foo;;;;\r\n" .
+ "FN;CHARSET=UTF-8:Foo\r\n" .
+ "CLASS:PUBLIC\r\n" .
+ "SOURCE;CHARSET=UTF-8:http://example.org/Foo\r\n" .
+ "PRODID:-////Semantic MediaWiki\r\n" .
+ "REV:\r\n" .
+ "URL:http://example.org/Bar\r\n" .
+ "UID:http://example.org/Foo\r\n" .
+ "END:VCARD\r\n",
+ $instance->text()
+ );
+ }
+
+}
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.test.js
new file mode 100644
index 00000000..7b2f24e3
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.test.js
@@ -0,0 +1,79 @@
+/**
+ * This file is part of the Semantic Result Formats QUnit Suite
+ * @see https://www.semantic-mediawiki.org/wiki/QUnit
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SMW
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * QUnit tests for the srf base class
+ *
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf', QUnit.newMwEnvironment() );
+
+ /**
+ * Test initialization and accessibility
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'init', 6, function ( assert ) {
+
+ assert.ok( srf instanceof Object, 'srf namespace and instance was accessible' );
+ assert.equal( $.type( srf.log ), 'function', '.log() was accessible' );
+ assert.equal( $.type( srf.msg ), 'function', '.msg() was accessible' );
+ assert.equal( $.type( srf.settings.getList ), 'function', '.settings.getList() was accessible' );
+ assert.equal( $.type( srf.settings.get ), 'function', '.settings.get() was accessible' );
+ assert.equal( $.type( srf.version ), 'function', '.version() was accessible' );
+
+ } );
+
+ /**
+ * Test settings function
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'settings', 4, function ( assert ) {
+
+ assert.equal( $.type( srf.settings.getList() ), 'object', '.getList() returned a list of objects' );
+ assert.equal( $.type( srf.settings.get( 'srfgScriptPath' ) ), 'string', '.get( "srfgScriptPath" ) returned a value' );
+ assert.equal( srf.settings.get( 'lula' ), undefined, '.get( "lula" ) returned undefined for an unknown key' );
+ assert.equal( srf.settings.get(), undefined, '.get() returned undefined for an empty key' );
+
+ } );
+
+ /**
+ * Test version function
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'version', 1, function ( assert ) {
+
+ assert.equal( $.type( srf.version() ), 'string', '.version() returned a string' );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.util.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.util.test.js
new file mode 100644
index 00000000..caac7d2d
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/ext.srf.util.test.js
@@ -0,0 +1,119 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.util', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( '.prototype', 1, function ( assert ) {
+ var util;
+
+ util = new srf.util();
+
+ assert.ok( util instanceof srf.util, pass + 'the srf.util.prototype instance was accessible' );
+
+ } );
+
+ /**
+ * Object testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( '.message', 3, function ( assert ) {
+ var util;
+ var fixture = $( '#qunit-fixture' );
+
+ util = new srf.util();
+
+ assert.equal( $.type( util.message ), 'object', pass + 'the message object was accessible' );
+
+ util.message.set( { context: fixture, message: 'Test' } );
+ assert.equal( $( '.ui-widget', fixture ).length, 1, pass + 'message.set() created an object' );
+
+ QUnit.raises( function() {
+ util.message.exception( { context: fixture, message: 'Test' } );
+ }, pass + 'message.exception() thrown an exception' );
+
+
+ } );
+
+ /**
+ * Test spinner
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'spinner', 2, function ( assert ) {
+ var context;
+ var util = new srf.util();
+
+ context = $( '<div><div id="spinner1" class="srf-spinner"></div></div>', '#qunit-fixture' );
+ util.spinner.hide( context );
+ assert.equal( context.find( '#' + 'spinner1' ).css( 'display' ), 'none', '.hide( context ) was successful' );
+
+ context = $( '<div><div><div id="spinner2" class="srf-spinner"></div></div></div>', '#qunit-fixture' );
+ util.spinner.hide( { context: context } );
+ assert.equal( context.find( '#' + 'spinner2' ).css( 'display' ), 'none', '.hide( { context: ... } ) was successful' );
+
+ } );
+
+ /**
+ * Test notification
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'notification', 3, function ( assert ) {
+ var util;
+
+ util = new srf.util();
+
+ assert.equal( $.type( util.notification ), 'object', pass + 'the notification object was accessible' );
+ assert.equal( $.type( util.notification.create ), 'function', pass + 'notification.create() was accessible' );
+ assert.equal( $.type( $.blockUI ), 'function', pass + '$.blockUI() was accessible' );
+
+ } );
+
+ /**
+ * Method testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( '.getImageURL()', 1, function ( assert ) {
+ var util;
+
+ util = new srf.util();
+
+ assert.equal( $.type( util.getImageURL ), 'function', pass + '.getImageURL() was accessible' );
+
+ } );
+
+ /**
+ * Method testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( '.getTitleURL()', 1, function ( assert ) {
+ var util;
+
+ util = new srf.util();
+
+ assert.equal( $.type( util.getTitleURL ), 'function', pass + '.getTitleURL() was accessible' );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.datatables.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.datatables.test.js
new file mode 100644
index 00000000..de7ae30f
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.datatables.test.js
@@ -0,0 +1,119 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.formats.datatables', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+ var context = $( '<div class="srf-datatables"><div id="smw-test" class="container"></div></div>', '#qunit-fixture' ),
+ container = context.find( '.container' );
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'instance', 1, function ( assert ) {
+
+ var datatables = new srf.formats.datatables();
+ assert.ok( datatables instanceof srf.formats.datatables, pass + 'the srf.formats.datatables instance was accessible' );
+
+ } );
+
+ /**
+ * SMWAPI parse testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'parse', 3, function ( assert ) {
+ var datatables = new srf.formats.datatables();
+
+ var _uriTestCase = '{\"query\":{\"result\":{\"printrequests\":[{\"label\":\"\",\"typeid\":\"_wpg\",\"mode\":2},{\"label\":\"Has url\",\"typeid\":\"_uri\",\"mode\":1}],\"results\":{\"Data\\/1\":{\"printouts\":{\"Has url\":[\"http:\\/\\/localhost\\/mw\\/index.php?title=Data\\/\"]},\"fulltext\":\"Data\\/1\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Data\\/1\"},\"Main Page\":{\"printouts\":{\"Has url\":[\"http:\\/\\/localhost\\/mw\\/test\\/testcase\"]},\"fulltext\":\"Main Page\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Main_Page\"}},\"meta\":{\"hash\":\"c957c73b571d202b08f1385faf7550ec\",\"count\":2,\"offset\":0}},\"ask\":{\"conditions\":\"[[Has url::+]]\",\"parameters\":{\"limit\":50,\"offset\":0,\"format\":\"datatables\",\"link\":\"all\",\"headers\":\"show\",\"mainlabel\":\"\",\"intro\":\"\",\"outro\":\"\",\"searchlabel\":\"\\u2026 further results\",\"default\":\"\",\"class\":\"sortable wikitable smwtable\",\"theme\":\"bootstrap\"},\"printouts\":[\"?Has url\"]}},\"version\":\"0.1\"}';
+ assert.equal( $.type( datatables.test._parse ), 'object', pass + 'the parse object was accessible' );
+
+ var smwAPI = new smw.api();
+ var data = smwAPI.parse( _uriTestCase );
+ var result = datatables.test._parse.results( context, data );
+ assert.equal( result.aaData.length, 2, pass + 'the result parsing returned an aaData array' );
+ assert.equal( data.aoColumnDefs.length, 2, pass + 'the result parsing returned an aoColumnDefs array' );
+
+ } );
+
+ /**
+ * Update testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'table init and update test', 3, function ( assert ) {
+ var datatables = new srf.formats.datatables();
+
+ assert.equal( $.type( datatables.update ), 'function', pass + 'the function was accessible' );
+
+ var _modDateCase= '{\"query\":{\"result\":{\"printrequests\":[{\"label\":\"\",\"typeid\":\"_wpg\",\"mode\":2},{\"label\":\"Modification date\",\"typeid\":\"_dat\",\"mode\":1}],\"results\":{\"File:5025159-view-of-the-golden-gate-bridge-san-francisco.jpg\":{\"printouts\":{\"Modification date\":[\"1360064258\"]},\"fulltext\":\"File:5025159-view-of-the-golden-gate-bridge-san-francisco.jpg\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/File:5025159-view-of-the-golden-gate-bridge-san-francisco.jpg\",\"namespace\":6,\"exists\":true},\"Concepttest3\":{\"printouts\":{\"Modification date\":[\"1358906761\"]},\"fulltext\":\"Concepttest3\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Concepttest3\",\"namespace\":0,\"exists\":true},\"Concepttest4\":{\"printouts\":{\"Modification date\":[\"1358905485\"]},\"fulltext\":\"Concepttest4\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Concepttest4\",\"namespace\":0,\"exists\":true}},\"meta\":{\"hash\":\"f790045e40c932332c73b3c8bf7139a8\",\"count\":3,\"offset\":0}},\"ask\":{\"conditions\":\"[[Modification date::+]]\",\"parameters\":{\"limit\":3,\"offset\":0,\"format\":\"datatables\",\"link\":\"all\",\"headers\":\"show\",\"mainlabel\":\"\",\"intro\":\"\",\"outro\":\"\",\"searchlabel\":\"\\u2026 further results\",\"default\":\"\",\"class\":\"\",\"theme\":\"bootstrap\"},\"printouts\":[\"?Modification date\"]}},\"version\":\"0.1\"}';
+
+ var smwAPI = new smw.api();
+ var data = smwAPI.parse( _modDateCase );
+
+ datatables.init( context, container, data );
+ assert.ok( container.find( 'table' ) , pass + 'table was created' );
+
+ datatables.update( context, data );
+ assert.ok( container.find( 'table' ) , pass + 'table was updated' );
+
+ } );
+
+ QUnit.test( 'Issue#172: table with subject printout', 1, function ( assert ) {
+ var oldAlert = window.alert;
+ try {
+ var alerts = [];
+ window.alert = function( msg ) {
+ alerts.push( msg );
+ };
+ var datatables = new srf.formats.datatables();
+
+ var parameters = {"limit":50,"offset":0,"sortkeys":{"":"ASC"},"mainlabel":"-","querymode":1,"format":"datatables","source":"","link":"all","headers":"show","intro":"","outro":"","searchlabel":"... further results","default":"","class":"","theme":"bootstrap"};
+ var data1 = new smw.dataItem.wikiPage( "Data/1", "http://localhost/wiki/Data/1", 0, "1", "Data 1" );
+ data1.printouts = {
+ "Has value":{"0":new smw.dataItem.wikiPage( "Value 1","http://localhost/wiki/Value_1",0,"1",null),"property":"Has value"}
+ };
+ var data2 = new smw.dataItem.wikiPage( "Data/2", "http://localhost/wiki/Data/2", 0, "1", "Data 2" );
+ data2.printouts = {
+ "Has value":{"0":new smw.dataItem.wikiPage( "Value 2","http://localhost/wiki/Value_2",0,"1",null),"property":"Has value"}
+ };
+ var results = {
+ "Data/1": data1,
+ "Data/2": data2
+ };
+ var printReqs = [{"label":"Has value","key":"Has_value","redi":"","typeid":"_wpg","mode":1,"format":""},{"label":"Data","key":"","redi":"","typeid":"_wpg","mode":2,"format":""}];
+
+ var data = {
+ "query" : {
+ "ask" : {
+ "parameters" : parameters
+ },
+ "result" : {
+ "results" : results,
+ "printrequests" : printReqs
+ }
+ }
+ };
+ assert.strictEqual( alerts.length, 0, "Shouldn't generate any alerts" );
+ var actual = datatables.test._parse.results( context, data );
+ var expected = {"aaData":[{"Has value":"<a href=\"http://localhost/wiki/Value_1\">Value 1</a>","Data":"<a href=\"http://localhost/wiki/Data/1\">Data 1</a>"},{"Has value":"<a href=\"http://localhost/wiki/Value_2\">Value 2</a>","Data":"<a href=\"http://localhost/wiki/Data/2\">Data 2</a>"}]};
+ assert.deepEqual( actual, expected, 'Generated results should look right' );
+ } finally {
+ window.alert = oldAlert;
+ }
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.eventcalendar.tests.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.eventcalendar.tests.js
new file mode 100644
index 00000000..f3c0d053
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.eventcalendar.tests.js
@@ -0,0 +1,160 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.formats.eventcalendar', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+ var context = $( '<div class="srf-eventcalendar"><div id="smw-test" class="container"></div></div>', '#qunit-fixture' ),
+ container = context.find( '.container' );
+
+ var testJSON1 = {"smw-test":"{\"query\":{\"result\":{\"printrequests\":[{\"label\":\"\",\"typeid\":\"_wpg\",\"mode\":2},{\"label\":\"title\",\"typeid\":\"_wpg\",\"mode\":1},{\"label\":\"Has event start\",\"typeid\":\"_dat\",\"mode\":1},{\"label\":\"Has event end\",\"typeid\":\"_dat\",\"mode\":1}],\"results\":{\"Event\\/1\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1325390400\"],\"Has event end\":[\"1325563200\"]},\"fulltext\":\"Event\\/1\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/1\"},\"Event\\/2\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1325300400\"],\"Has event end\":[]},\"fulltext\":\"Event\\/2\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/2\"},\"Event\\/4\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1357304400\"],\"Has event end\":[\"1357308000\"]},\"fulltext\":\"Event\\/4\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/4\"}},\"meta\":{\"hash\":\"ddf5e7e1558d010bf1a1e9ab5c2fa54b\",\"count\":3,\"offset\":0}},\"ask\":{\"conditions\":\"[[Has event start::+]]\",\"parameters\":{\"limit\":50,\"offset\":0,\"format\":\"eventcalendar\",\"link\":\"all\",\"headers\":\"show\",\"mainlabel\":\"\",\"intro\":\"\",\"outro\":\"\",\"searchlabel\":\"\\u2026 further results\",\"default\":\"\",\"defaultview\":\"month\",\"firstday\":\"Sunday\",\"start\":\"earliest\",\"legend\":\"none\",\"class\":\"\",\"theme\":\"basic\",\"dayview\":false},\"printouts\":[\"?Has event=title\",\"?Has event start\",\"?Has event end\"]}},\"version\":\"0.7.4\"}"};
+ var testJSON2 = {"smw-test":"{\"query\":{\"result\":{\"printrequests\":[{\"label\":\"\",\"typeid\":\"_wpg\",\"mode\":2},{\"label\":\"title\",\"typeid\":\"_wpg\",\"mode\":1},{\"label\":\"Has event start\",\"typeid\":\"_dat\",\"mode\":1},{\"label\":\"Has event end\",\"typeid\":\"_dat\",\"mode\":1},{\"label\":\"Has event type\",\"typeid\":\"_wpg\",\"mode\":1},{\"label\":\"color\",\"typeid\":\"_str\",\"mode\":1}],\"results\":{\"Event\\/1# c39a574c835d239ebf85019eeb91e4bb\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1325390400\"],\"Has event end\":[\"1325563200\"],\"Has event type\":[{\"fulltext\":\"Meeting\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Meeting\"}],\"color\":[\"green\"]},\"fulltext\":\"Event\\/1# c39a574c835d239ebf85019eeb91e4bb\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/1#_c39a574c835d239ebf85019eeb91e4bb\"},\"Event\\/2# 17423f0168b2fd7d113dbd843224884a\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1325300400\"],\"Has event end\":[],\"Has event type\":[{\"fulltext\":\"Talk\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Talk\"}],\"color\":[\"yellow\"]},\"fulltext\":\"Event\\/2# 17423f0168b2fd7d113dbd843224884a\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/2#_17423f0168b2fd7d113dbd843224884a\"},\"Event\\/3# 4e920606589bc542048086b8913edb9c\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1358910000\"],\"Has event end\":[\"1358913600\"],\"Has event type\":[{\"fulltext\":\"Meeting\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Meeting\"}],\"color\":[]},\"fulltext\":\"Event\\/3# 4e920606589bc542048086b8913edb9c\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/3#_4e920606589bc542048086b8913edb9c\"},\"Event\\/4# 48bff722d643b0c550e6dcdf09699c47\":{\"printouts\":{\"title\":[{\"fulltext\":\"Demo 230\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Demo_230\"}],\"Has event start\":[\"1357304400\"],\"Has event end\":[\"1357308000\"],\"Has event type\":[{\"fulltext\":\"Meeting\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Meeting\"}],\"color\":[]},\"fulltext\":\"Event\\/4# 48bff722d643b0c550e6dcdf09699c47\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event\\/4#_48bff722d643b0c550e6dcdf09699c47\"}},\"meta\":{\"hash\":\"4f7be8ca26f266b1d36fcae82cdbe21c\",\"count\":4,\"offset\":0}},\"ask\":{\"conditions\":\"[[Has event start::+]]\",\"parameters\":{\"limit\":50,\"offset\":0,\"format\":\"eventcalendar\",\"link\":\"all\",\"headers\":\"show\",\"mainlabel\":\"\",\"intro\":\"\",\"outro\":\"\",\"searchlabel\":\"\\u2026 further results\",\"default\":\"\",\"defaultview\":\"month\",\"firstday\":\"Sunday\",\"start\":\"earliest\",\"legend\":\"tooltip\",\"class\":\"\",\"theme\":\"basic\",\"dayview\":true},\"printouts\":[\"?Has event=title\",\"?Has event start\",\"?Has event end\",\"?Has event type\",\"?Has event color=color\"]}},\"version\":\"0.7.4\"}"};
+ var testJSON3 = {"smw-test":"{\"query\":{\"result\":{\"printrequests\":[{\"label\":\"\",\"typeid\":\"_wpg\",\"mode\":2},{\"label\":\"title\",\"typeid\":\"_str\",\"mode\":1},{\"label\":\"Has event start\",\"typeid\":\"_dat\",\"mode\":1},{\"label\":\"Has event end\",\"typeid\":\"_dat\",\"mode\":1},{\"label\":\"Description\",\"typeid\":\"_txt\",\"mode\":1},{\"label\":\"icon\",\"typeid\":\"_str\",\"mode\":1},{\"label\":\"color\",\"typeid\":\"_str\",\"mode\":1},{\"label\":\"Has event location\",\"typeid\":\"_wpg\",\"mode\":1}],\"results\":{\"Event calendar test\\/1# dd20ac429f9cec8c9e0fb69719753261\":{\"printouts\":{\"title\":[\"Pellentesque dui pretiu\"],\"Has event start\":[\"1360886400\"],\"Has event end\":[],\"Description\":[\"\\u0432\\u0442\\u043e\\u0440\\u043e\\u0435\"],\"icon\":[\"File:Event-presentation-icon.png\"],\"color\":[\"\\n#A0D8F1\"],\"Has event location\":[]},\"fulltext\":\"Event calendar test\\/1# dd20ac429f9cec8c9e0fb69719753261\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event_calendar_test\\/1#_dd20ac429f9cec8c9e0fb69719753261\",\"namespace\":0,\"exists\":true},\"Event calendar test\\/2# 9040bf1853edcb06d47891ed0760bb35\":{\"printouts\":{\"title\":[\"Lorem ipsum dolor ... nascetur ipsum.\"],\"icon\":[\"File:Event-meeting-icon.gif\"],\"color\":[\"\\n#E9AF32\"],\"Has event location\":[{\"fulltext\":\"Eveline Hall\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Eveline_Hall\",\"namespace\":0,\"exists\":false}]},\"fulltext\":\"Event calendar test\\/2# 9040bf1853edcb06d47891ed0760bb35\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event_calendar_test\\/2#_9040bf1853edcb06d47891ed0760bb35\",\"namespace\":0,\"exists\":true},\"Event calendar test\\/3# b37ba5543d4fd3485d86576a3cbddf48\":{\"printouts\":{\"title\":[\"Condimentum ut ... amet Cras tempus.\"],\"icon\":[\"File:Event-presentation-icon.png\"],\"color\":[\"\\n#A0D8F1\"],\"Has event location\":[]},\"fulltext\":\"Event calendar test\\/3# b37ba5543d4fd3485d86576a3cbddf48\",\"fullurl\":\"http:\\/\\/localhost\\/mw\\/index.php\\/Event_calendar_test\\/3#_b37ba5543d4fd3485d86576a3cbddf48\",\"namespace\":0,\"exists\":true}},\"meta\":{\"hash\":\"5c7f3ce435d3918537e4090289716bda\",\"count\":3,\"offset\":0}},\"ask\":{\"conditions\":\"[[Has project::test 2]]\",\"parameters\":{\"limit\":50,\"offset\":0,\"format\":\"eventcalendar\",\"link\":\"subject\",\"headers\":\"show\",\"mainlabel\":\"\",\"intro\":\"\",\"outro\":\"\",\"searchlabel\":\"\\u2026 further results\",\"default\":\"\",\"defaultview\":\"month\",\"firstday\":\"Monday\",\"start\":\"earliest\",\"legend\":\"pane\",\"class\":\"\",\"theme\":\"vector\",\"dayview\":true},\"printouts\":[\"?Has event=title\",\"?Has event start\",\"?Has event end\",\"?Has event description=Description\",\"?Has event icon=icon\",\"?Has event color=color\",\"?Has event location\"]}},\"version\":\"0.7.4\"}"};
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'instance', 1, function ( assert ) {
+
+ var calendar = new srf.formats.eventcalendar();
+ assert.ok( calendar instanceof srf.formats.eventcalendar, pass + 'the srf.formats.eventcalendar instance was accessible' );
+
+ } );
+
+ /**
+ * SMWAPI parse testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'parse', 8, function ( assert ) {
+ var calendar = new srf.formats.eventcalendar();
+
+ assert.equal( $.type( calendar.test._parse ), 'object', pass + 'the parse object was accessible' );
+
+ // Base data set
+ mw.config.set( testJSON1 );
+ assert.equal( $.type( calendar.test._getData( container ) ), 'object', pass + 'getData() returned an object' );
+
+ // Check api is available
+ var testData = calendar.test._getData( container );
+ assert.equal( $.type( calendar.test._parse.api( testData ) ), 'object', pass + 'api() was accessible' );
+
+ var expected = {
+ "dates": [
+ "1325390400",
+ "1325563200",
+ "1325300400",
+ "1357304400",
+ "1357308000"
+ ]
+ }
+
+ // Check for parsed dates array
+ var results = calendar.test._parse.api( testData );
+ assert.deepEqual( results.dates, expected.dates , pass + 'dates [] did match' );
+
+ // Second test data contains type data for colorFilter settings
+ mw.config.set( testJSON2 );
+ var testData = calendar.test._getData( container );
+
+ results = calendar.test._parse.api( testData );
+ assert.deepEqual( results.legend, {} , pass + 'filterProperty was empty and therefore an empty {} was returned' );
+
+ testData.query.ask.parameters.filterProperty = 'Has event type';
+ var results = calendar.test._parse.api( testData ),
+ expected = { "legend": {
+ "Meeting": {"color": ["green"],"filter": false},
+ "Talk": {"color": ["yellow"],"filter": false} }
+ };
+
+ assert.deepEqual( results.legend, expected.legend , pass + 'filterProperty was set and a legend {} was returned' );
+
+ // Id101d97fc69a: title test (typeof _wpg)
+ assert.equal( results.events[0].title, 'Demo 230' , pass + 'correct title (typeof _wpg) was returned' );
+
+ // Id101d97fc69a: title test (typeof _str)
+ mw.config.set( testJSON3 );
+ var testData = calendar.test._getData( container );
+ results = calendar.test._parse.api( testData );
+ assert.equal( results.events[0].title, 'Pellentesque dui pretiu' , pass + 'correct title (typeof _str) was returned' );
+
+ } );
+
+ /**
+ * startDate testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'startDate', 10, function ( assert ) {
+
+ var calendar = new srf.formats.eventcalendar();
+
+ var testData = [ '1325390400', '1325563200', '1357304400', '1357308000' ];
+
+ assert.equal( $.type( calendar.test._startDate() ) , 'object', pass + 'the object was accessible' );
+ assert.equal( $.type( calendar.test._startDate( testData ).minmax() ), 'object', pass + 'minmax() was accessible' );
+ assert.equal( $.type( calendar.test._startDate( testData ).get() ), 'date', pass + 'get() was accessible' );
+
+ var results = calendar.test._startDate( testData ).minmax();
+ assert.deepEqual( results, {"max": "1357308000","min": "1325390400"}, pass + 'minmax() returned an object' );
+
+ var results = calendar.test._startDate( testData ).get();
+ assert.deepEqual( results, new Date() , pass + 'get() returned new Date()' );
+
+ var results = calendar.test._startDate( testData ).get( 'foo' );
+ assert.deepEqual( results, new Date() , pass + 'get( "foo" ) returned new Date()' );
+
+ var results = calendar.test._startDate( testData ).get( 'earliest' );
+ assert.equal( results.getDate(), '1' , pass + 'get( "earliest" ) returned 4' );
+
+ var results = calendar.test._startDate( testData ).get( 'latest' );
+ assert.equal( results.getDate(), '4' , pass + 'get( "latest" ) returned 1' );
+
+ var testData = [ '633830400', '634176000', '1262563200' ];
+ var results = calendar.test._startDate( testData ).minmax();
+ assert.deepEqual( results, {"max": "1262563200","min": "633830400"}, pass + 'minmax() returned the correct object' );
+
+ // I7156d76086b62: Regression test
+ var testData = ["1360886400", "1347753600", "1347753600", "1347926400", "1347926400"];
+ var results = calendar.test._startDate( testData ).minmax();
+ assert.deepEqual( results, {"max": "1360886400","min": "1347753600"}, pass + 'minmax() returned the correct object' );
+
+ } );
+
+ /**
+ * Update testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'update', 2, function ( assert ) {
+ var calendar = new srf.formats.eventcalendar();
+
+ assert.equal( $.type( calendar.update ), 'function', pass + 'the function was accessible' );
+
+ mw.config.set( testJSON1 );
+ var testData = calendar.test._getData( container );
+
+ // Wait for an asynchronous action to complete
+ calendar.update( context, container, testData );
+ stop();
+ container.on( "srf.eventcalendar.updateAfterParse", function() {
+ assert.ok( true, pass + 'the "srf.eventcalendar.updateAfterParse" event was triggered' );
+ start();
+ } );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.filtered.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.filtered.test.js
new file mode 100644
index 00000000..874e346b
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.filtered.test.js
@@ -0,0 +1,1404 @@
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+"use strict";
+/// <reference types="jquery" />
+exports.__esModule = true;
+var View_1 = require("./View/View");
+var Controller = /** @class */ (function () {
+ function Controller(target, data, printRequests) {
+ this.target = undefined;
+ this.filterSpinner = undefined;
+ this.views = {};
+ this.filters = {};
+ this.currentView = undefined;
+ this.target = target;
+ if (this.target !== undefined) {
+ this.filterSpinner = this.target.find('div.filtered-filter-spinner');
+ }
+ this.data = data;
+ this.printRequests = printRequests;
+ for (var rowId in this.data) {
+ if (!this.data[rowId].hasOwnProperty('visible')) {
+ this.data[rowId].visible = {};
+ }
+ }
+ }
+ Controller.prototype.getData = function () {
+ return this.data;
+ };
+ Controller.prototype.getPrintRequests = function () {
+ return this.printRequests;
+ };
+ Controller.prototype.getPath = function () {
+ return srf.settings.get('srfgScriptPath') + '/formats/filtered/resources/';
+ };
+ Controller.prototype.attachView = function (viewid, view) {
+ this.views[viewid] = view;
+ if (this.currentView === undefined) {
+ this.currentView = view;
+ view.show();
+ }
+ else {
+ view.hide();
+ }
+ return this;
+ };
+ Controller.prototype.getView = function (viewId) {
+ return this.views[viewId];
+ };
+ Controller.prototype.attachFilter = function (filter) {
+ var filterId = filter.getId();
+ this.filters[filterId] = filter;
+ filter.init();
+ return this.onFilterUpdated(filterId);
+ };
+ Controller.prototype.getFilter = function (filterId) {
+ return this.filters[filterId];
+ };
+ Controller.prototype.show = function () {
+ this.initializeFilters();
+ this.target.children('.filtered-spinner').remove();
+ this.target.children().show();
+ this.switchToView(this.currentView);
+ };
+ Controller.prototype.switchToView = function (view) {
+ if (this.currentView instanceof View_1.View) {
+ this.currentView.hide();
+ }
+ this.currentView = view;
+ if (this.currentView instanceof View_1.View) {
+ view.show();
+ }
+ };
+ Controller.prototype.initializeFilters = function () {
+ var toShow = [];
+ var toHide = [];
+ for (var rowId in this.data) {
+ for (var filterId in this.filters) {
+ this.data[rowId].visible[filterId] = this.filters[filterId].isDisabled() || this.filters[filterId].isVisible(rowId);
+ }
+ if (this.isVisible(rowId)) {
+ toShow.push(rowId);
+ }
+ else {
+ toHide.push(rowId);
+ }
+ }
+ this.hideRows(toHide);
+ this.showRows(toShow);
+ };
+ Controller.prototype.onViewSelected = function (viewID) {
+ this.switchToView(this.views[viewID]);
+ };
+ Controller.prototype.onFilterUpdated = function (filterId) {
+ var _this = this;
+ return this.showSpinner()
+ .then(function () {
+ var toShow = [];
+ var toHide = [];
+ var disabled = _this.filters[filterId].isDisabled();
+ for (var rowId in _this.data) {
+ var newVisible = disabled || _this.filters[filterId].isVisible(rowId);
+ if (_this.data[rowId].visible[filterId] !== newVisible) {
+ _this.data[rowId].visible[filterId] = newVisible;
+ if (newVisible && _this.isVisible(rowId)) {
+ toShow.push(rowId);
+ }
+ else {
+ toHide.push(rowId);
+ }
+ }
+ }
+ _this.hideRows(toHide);
+ _this.showRows(toShow);
+ })
+ .then(function () { _this.hideSpinner(); });
+ };
+ Controller.prototype.isVisible = function (rowId) {
+ for (var filterId in this.data[rowId].visible) {
+ if (!this.data[rowId].visible[filterId]) {
+ return false;
+ }
+ }
+ return true;
+ };
+ Controller.prototype.hideRows = function (rowIds) {
+ if (rowIds.length === 0) {
+ return;
+ }
+ for (var viewId in this.views) {
+ this.views[viewId].hideRows(rowIds);
+ }
+ };
+ Controller.prototype.showRows = function (rowIds) {
+ if (rowIds.length === 0) {
+ return;
+ }
+ for (var viewId in this.views) {
+ this.views[viewId].showRows(rowIds);
+ }
+ };
+ Controller.prototype.showSpinner = function () {
+ return this.animateSpinner();
+ };
+ Controller.prototype.hideSpinner = function () {
+ return this.animateSpinner(false);
+ };
+ Controller.prototype.animateSpinner = function (show) {
+ if (show === void 0) { show = true; }
+ if (this.filterSpinner === undefined) {
+ return jQuery.when();
+ }
+ if (show) {
+ return this.filterSpinner.fadeIn(200).promise();
+ }
+ return this.filterSpinner.fadeOut(200).promise();
+ };
+ return Controller;
+}());
+exports.Controller = Controller;
+
+},{"./View/View":5}],2:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var Filter = /** @class */ (function () {
+ function Filter(filterId, target, printrequestId, controller, options) {
+ this.outerTarget = undefined;
+ this.target = undefined;
+ this.options = undefined;
+ this.disabled = false;
+ this.collapsed = false;
+ this.target = target;
+ this.outerTarget = target;
+ this.filterId = filterId;
+ this.printrequestId = printrequestId;
+ this.controller = controller;
+ this.options = options || {};
+ }
+ Filter.prototype.init = function () { };
+ ;
+ Filter.prototype.isDisabled = function () {
+ return this.disabled;
+ };
+ Filter.prototype.disable = function () {
+ var _this = this;
+ this.disabled = true;
+ this.outerTarget
+ .removeClass('enabled')
+ .addClass('disabled');
+ this.collapse();
+ this.target.promise().then(function () { return _this.controller.onFilterUpdated(_this.filterId); });
+ };
+ Filter.prototype.enable = function () {
+ var _this = this;
+ this.disabled = false;
+ this.outerTarget
+ .removeClass('disabled')
+ .addClass('enabled');
+ if (!this.collapsed) {
+ this.uncollapse();
+ }
+ this.target.promise().then(function () { return _this.controller.onFilterUpdated(_this.filterId); });
+ };
+ Filter.prototype.collapse = function (duration) {
+ var _this = this;
+ if (duration === void 0) { duration = 400; }
+ if (!this.collapsed) {
+ this.outerTarget.promise()
+ .then(function () {
+ _this.target.slideUp(duration);
+ _this.outerTarget.animate({
+ 'padding-top': 0,
+ 'padding-bottom': 0,
+ 'margin-bottom': '2em'
+ }, duration);
+ });
+ }
+ };
+ Filter.prototype.uncollapse = function () {
+ var _this = this;
+ this.outerTarget.promise()
+ .then(function () {
+ _this.target.slideDown();
+ var style = _this.outerTarget.attr('style');
+ _this.outerTarget.removeAttr('style');
+ var uncollapsedCss = _this.outerTarget.css(['padding-top', 'padding-bottom', 'margin-bottom']);
+ _this.outerTarget.attr('style', style);
+ _this.outerTarget.animate(uncollapsedCss);
+ });
+ };
+ Filter.prototype.isVisible = function (rowId) {
+ return this.options.hasOwnProperty('show if undefined') && this.options['show if undefined'] === true;
+ };
+ Filter.prototype.getId = function () {
+ return this.filterId;
+ };
+ Filter.prototype.buildEmptyControl = function () {
+ this.target = $('<div class="filtered-filter-container">');
+ this.outerTarget
+ .append(this.target)
+ .addClass('enabled');
+ this.addOnOffSwitch();
+ this.addLabel();
+ this.addControlForCollapsing();
+ return this.target;
+ };
+ Filter.prototype.addLabel = function () {
+ // insert the label of the printout this filter filters on
+ this.target.before("<div class=\"filtered-filter-label\">" + this.options['label'] + "</div>");
+ };
+ Filter.prototype.addOnOffSwitch = function () {
+ var _this = this;
+ if (this.options.hasOwnProperty('switches')) {
+ var switches = this.options['switches'];
+ if (switches.length > 0 && $.inArray('on off', switches) >= 0) {
+ var onOffControl = $("<div class=\"filtered-filter-onoff on\"></div>");
+ this.target.before(onOffControl);
+ onOffControl.click(function () {
+ if (_this.outerTarget.hasClass('enabled')) {
+ _this.disable();
+ }
+ else {
+ _this.enable();
+ }
+ });
+ }
+ }
+ };
+ Filter.prototype.addControlForCollapsing = function () {
+ var _this = this;
+ var collapsible = this.options.hasOwnProperty('collapsible') ? this.options['collapsible'] : undefined;
+ if (collapsible === 'collapsed' || collapsible === 'uncollapsed') {
+ var collapseControl_1 = $('<span class="filtered-filter-collapse">');
+ this.target.before(collapseControl_1);
+ collapseControl_1.click(function () {
+ if (collapseControl_1.hasClass('collapsed')) {
+ _this.uncollapse();
+ _this.collapsed = false;
+ collapseControl_1
+ .removeClass('collapsed')
+ .addClass('uncollapsed');
+ }
+ else {
+ _this.collapse();
+ _this.collapsed = true;
+ collapseControl_1
+ .removeClass('uncollapsed')
+ .addClass('collapsed');
+ }
+ });
+ if (collapsible === 'collapsed') {
+ this.collapse(0);
+ this.collapsed = true;
+ collapseControl_1.addClass('collapsed');
+ }
+ else {
+ collapseControl_1.addClass('uncollapsed');
+ }
+ }
+ };
+ return Filter;
+}());
+exports.Filter = Filter;
+
+},{}],3:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var Filter_1 = require("./Filter");
+var ValueFilter = /** @class */ (function (_super) {
+ __extends(ValueFilter, _super);
+ function ValueFilter() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.values = {};
+ _this.visibleValues = [];
+ _this._useOr = true;
+ return _this;
+ }
+ ValueFilter.prototype.init = function () {
+ this.values = this.getSortedValues();
+ this.buildControl();
+ };
+ ValueFilter.prototype.useOr = function (useOr) {
+ this._useOr = useOr;
+ this.controller.onFilterUpdated(this.getId());
+ };
+ ValueFilter.prototype.getSortedValues = function () {
+ /** Map of value => label distinct values */
+ var distinctValues = {};
+ /** Map of value => sort value distinct values */
+ var distinctSortValues = {};
+ if (this.options.hasOwnProperty('values')) {
+ return this.options['values'].map(function (item) {
+ return {
+ printoutValue: item,
+ formattedValue: item
+ };
+ });
+ }
+ else {
+ // build filter values from available values in result set
+ var data = this.controller.getData();
+ var sortedEntries = [];
+ for (var id in data) {
+ var printoutValues = data[id]['printouts'][this.printrequestId]['values'];
+ var printoutFormattedValues = data[id]['printouts'][this.printrequestId]['formatted values'];
+ var printoutSortValues = data[id]['printouts'][this.printrequestId]['sort values'];
+ for (var i in printoutValues) {
+ var printoutFormattedValue = printoutFormattedValues[i];
+ if (printoutFormattedValue.indexOf('<a') > -1) {
+ printoutFormattedValue = /<a.*>(.*?)<\/a>/.exec(printoutFormattedValue)[1];
+ }
+ distinctValues[printoutValues[i]] = printoutFormattedValue;
+ distinctSortValues[printoutValues[i]] = printoutSortValues[i];
+ }
+ }
+ for (var printoutValue in distinctSortValues) {
+ sortedEntries.push({
+ printoutValue: printoutValue,
+ sortValue: distinctSortValues[printoutValue],
+ formattedValue: distinctValues[printoutValue]
+ });
+ }
+ sortedEntries.sort(function (a, b) {
+ return a.sortValue.localeCompare(b.sortValue);
+ });
+ return sortedEntries;
+ }
+ };
+ ValueFilter.prototype.buildControl = function () {
+ var filtercontrols = this.buildEmptyControl();
+ filtercontrols = this.addControlForSwitches(filtercontrols);
+ var maxCheckboxes = this.options.hasOwnProperty('max checkboxes') ? this.options['max checkboxes'] : 5;
+ if (this.values.length > maxCheckboxes) {
+ filtercontrols.append(this.getSelected2Control());
+ }
+ else {
+ filtercontrols.append(this.getCheckboxesControl());
+ }
+ };
+ ValueFilter.prototype.getCheckboxesControl = function () {
+ var _this = this;
+ var checkboxes = $('<div class="filtered-value-checkboxes" style="width: 100%;">');
+ // insert options (checkboxes and labels)
+ for (var _i = 0, _a = this.values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ checkboxes.append("<div class=\"filtered-value-option\"><label><input type=\"checkbox\" value=\"" + value.printoutValue + "\" ><div class=\"filtered-value-option-label\">" + (value.formattedValue || value.printoutValue) + "</div></label></div>");
+ }
+ // attach event handler
+ checkboxes
+ .on('change', ':checkbox', function (eventObject) {
+ var checkboxElement = eventObject.currentTarget;
+ _this.onFilterUpdated(checkboxElement.value, checkboxElement.checked);
+ });
+ return checkboxes;
+ };
+ ValueFilter.prototype.getSelected2Control = function () {
+ var _this = this;
+ var select = $('<select class="filtered-value-select" style="width: 100%;">');
+ var data = [];
+ // insert options (checkboxes and labels) and attach event handlers
+ for (var _i = 0, _a = this.values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ // Try to get label, if not fall back to value id
+ var label = value.formattedValue || value.printoutValue;
+ data.push({ id: value.printoutValue, text: label });
+ }
+ mw.loader.using('ext.srf.filtered.value-filter.select').then(function () {
+ select.select2({
+ multiple: true,
+ placeholder: mw.message('srf-filtered-value-filter-placeholder').text(),
+ data: data
+ });
+ select.on("select2:select", function (e) {
+ _this.onFilterUpdated(e.params.data.id, true);
+ });
+ select.on("select2:unselect", function (e) {
+ _this.onFilterUpdated(e.params.data.id, false);
+ });
+ });
+ return select;
+ };
+ ValueFilter.prototype.addControlForSwitches = function (filtercontrols) {
+ // insert switches
+ var switches = this.options.hasOwnProperty('switches') ? this.options['switches'] : undefined;
+ if (switches !== undefined && $.inArray('and or', switches) >= 0) {
+ var switchControls = $('<div class="filtered-value-switches">');
+ var andorControl = $('<div class="filtered-value-andor">');
+ var orControl = this.getRadioControl('or', true);
+ var andControl = this.getRadioControl('and');
+ andorControl
+ .append(orControl)
+ .append(andControl)
+ .appendTo(switchControls);
+ andorControl
+ .find('input')
+ .on('change', undefined, { 'filter': this }, function (eventObject) {
+ return eventObject.data.filter.useOr(eventObject.target.getAttribute('value') === 'or');
+ });
+ filtercontrols.append(switchControls);
+ }
+ return filtercontrols;
+ };
+ ValueFilter.prototype.getRadioControl = function (type, isChecked) {
+ if (isChecked === void 0) { isChecked = false; }
+ var checkedAttr = isChecked ? 'checked' : '';
+ var labelText = mw.message('srf-filtered-value-filter-' + type).text();
+ var controlText = "<label for=\"filtered-value-" + type + "-" + this.printrequestId + "\">" +
+ ("<input type=\"radio\" name=\"filtered-value-" + this.printrequestId + "\" class=\"filtered-value-" + type + "\" id=\"filtered-value-" + type + "-" + this.printrequestId + "\" value=\"" + type + "\" " + checkedAttr + ">") +
+ (labelText + "</label>");
+ return $(controlText);
+ };
+ ValueFilter.prototype.isVisible = function (rowId) {
+ if (this.visibleValues.length === 0) {
+ return true;
+ }
+ var values = this.controller.getData()[rowId].printouts[this.printrequestId].values;
+ if (values.length === 0) {
+ return _super.prototype.isVisible.call(this, rowId);
+ }
+ if (this._useOr) {
+ for (var _i = 0, _a = this.visibleValues; _i < _a.length; _i++) {
+ var expectedValue = _a[_i];
+ if (values.indexOf(expectedValue) >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ else {
+ for (var _b = 0, _c = this.visibleValues; _b < _c.length; _b++) {
+ var expectedValue = _c[_b];
+ if (values.indexOf(expectedValue) < 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ ValueFilter.prototype.onFilterUpdated = function (value, isChecked) {
+ var index = this.visibleValues.indexOf(value);
+ if (isChecked && index === -1) {
+ this.visibleValues.push(value);
+ }
+ else if (!isChecked && index >= 0) {
+ this.visibleValues.splice(index, 1);
+ }
+ this.controller.onFilterUpdated(this.getId());
+ };
+ return ValueFilter;
+}(Filter_1.Filter));
+exports.ValueFilter = ValueFilter;
+
+},{"./Filter":2}],4:[function(require,module,exports){
+"use strict";
+/// <reference types="leaflet" />
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var View_1 = require("./View");
+var MapView = /** @class */ (function (_super) {
+ __extends(MapView, _super);
+ function MapView() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.map = undefined;
+ _this.icon = undefined;
+ _this.markers = undefined;
+ _this.markerClusterGroup = undefined;
+ _this.bounds = undefined;
+ _this.initialized = false;
+ _this.zoom = -1;
+ _this.minZoom = -1;
+ _this.maxZoom = -1;
+ _this.leafletPromise = undefined;
+ return _this;
+ }
+ MapView.prototype.init = function () {
+ var _this = this;
+ var data = this.controller.getData();
+ var markers = {};
+ if (this.options.hasOwnProperty('height')) {
+ this.target.height(this.options.height);
+ }
+ this.leafletPromise = mw.loader.using('ext.srf.filtered.map-view.leaflet')
+ .then(function () {
+ var bounds = undefined;
+ var disableClusteringAtZoom = _this.getZoomForUnclustering();
+ var clusterOptions = {
+ animateAddingMarkers: true,
+ disableClusteringAtZoom: disableClusteringAtZoom,
+ spiderfyOnMaxZoom: disableClusteringAtZoom === null
+ };
+ clusterOptions = _this.getOptions(['maxClusterRadius', 'zoomToBoundsOnClick'], clusterOptions);
+ var markerClusterGroup = L.markerClusterGroup(clusterOptions);
+ for (var rowId in data) {
+ if (data[rowId]['data'].hasOwnProperty(_this.id)) {
+ var positions = data[rowId]['data'][_this.id]['positions'];
+ markers[rowId] = [];
+ for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {
+ var pos = positions_1[_i];
+ bounds = (bounds === undefined) ? new L.LatLngBounds(pos, pos) : bounds.extend(pos);
+ var marker = _this.getMarker(pos, data[rowId]);
+ markers[rowId].push(marker);
+ markerClusterGroup.addLayer(marker);
+ }
+ }
+ }
+ _this.markerClusterGroup = markerClusterGroup;
+ _this.markers = markers;
+ _this.bounds = (bounds === undefined) ? new L.LatLngBounds([-180, -90], [180, 90]) : bounds;
+ });
+ return this.leafletPromise;
+ };
+ MapView.prototype.getZoomForUnclustering = function () {
+ if (this.options.hasOwnProperty('marker cluster') && this.options['marker cluster'] === false) {
+ return 0;
+ }
+ if (this.options.hasOwnProperty('marker cluster max zoom')) {
+ return this.options['marker cluster max zoom'] + 1;
+ }
+ return null;
+ };
+ MapView.prototype.getIcon = function (row) {
+ if (this.icon === undefined) {
+ this.buildIconList();
+ }
+ if (this.options.hasOwnProperty('marker icon property')) {
+ var vals = row['printouts'][this.options['marker icon property']]['values'];
+ if (vals.length > 0 && this.icon.hasOwnProperty(vals[0])) {
+ return this.icon[vals[0]];
+ }
+ }
+ return this.icon['default'];
+ };
+ MapView.prototype.buildIconList = function () {
+ this.icon = {};
+ var iconPath = this.controller.getPath() + 'css/images/';
+ this.icon['default'] = new L.Icon({
+ 'iconUrl': iconPath + 'marker-icon.png',
+ 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [25, 41],
+ 'iconAnchor': [12, 41],
+ 'popupAnchor': [1, -34],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [41, 41]
+ });
+ if (this.options.hasOwnProperty('marker icons')) {
+ for (var value in this.options['marker icons']) {
+ this.icon[value] = new L.Icon({
+ 'iconUrl': this.options['marker icons'][value],
+ // 'iconRetinaUrl': iconPath + 'marker-icon-2x.png',
+ 'shadowUrl': iconPath + 'marker-shadow.png',
+ 'iconSize': [32, 32],
+ 'iconAnchor': [16, 32],
+ 'popupAnchor': [1, -30],
+ // 'tooltipAnchor': [16, -28],
+ 'shadowSize': [41, 41],
+ 'shadowAnchor': [12, 41]
+ });
+ }
+ }
+ };
+ MapView.prototype.getMarker = function (latLng, row) {
+ var title = undefined;
+ var popup = [];
+ // TODO: Use <div> instead of <b> and do CSS styling
+ for (var prId in row['printouts']) {
+ var printrequest = (this.controller.getPrintRequests())[prId];
+ if (!printrequest.hasOwnProperty('hide') || printrequest.hide === false) {
+ var printouts = row['printouts'][prId];
+ if (title === undefined) {
+ title = printouts['values'].join(', ');
+ popup.push('<b>' + printouts['formatted values'].join(', ') + '</b>');
+ }
+ else {
+ popup.push((printouts.label ? '<b>' + printouts.label + ':</b> ' : '') + printouts['formatted values'].join(', '));
+ }
+ }
+ }
+ var marker = L.marker(latLng, { title: title, alt: title });
+ marker.bindPopup(popup.join('<br>'));
+ marker.setIcon(this.getIcon(row));
+ return marker;
+ };
+ MapView.prototype.lateInit = function () {
+ var _this = this;
+ if (this.initialized) {
+ return;
+ }
+ this.initialized = true;
+ var that = this;
+ this.leafletPromise.then(function () {
+ var mapOptions = {
+ center: _this.bounds !== undefined ? _this.bounds.getCenter() : [0, 0]
+ };
+ mapOptions = that.getOptions(['zoom', 'minZoom', 'maxZoom'], mapOptions);
+ // TODO: Limit zoom values to map max zoom
+ that.map = L.map(that.getTargetElement().get(0), mapOptions);
+ that.map.addLayer(that.markerClusterGroup);
+ if (_this.options.hasOwnProperty('map provider')) {
+ L.tileLayer.provider(_this.options['map provider']).addTo(that.map);
+ }
+ if (!mapOptions.hasOwnProperty('zoom')) {
+ that.map.fitBounds(that.bounds);
+ }
+ });
+ };
+ MapView.prototype.getOptions = function (keys, defaults) {
+ if (defaults === void 0) { defaults = {}; }
+ for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
+ var key = keys_1[_i];
+ if (this.options.hasOwnProperty(key)) {
+ defaults[key] = this.options[key];
+ }
+ }
+ return defaults;
+ };
+ MapView.prototype.showRows = function (rowIds) {
+ var _this = this;
+ this.leafletPromise.then(function () {
+ _this.manipulateLayers(rowIds, function (layers) {
+ _this.markerClusterGroup.addLayers(layers);
+ });
+ });
+ };
+ MapView.prototype.hideRows = function (rowIds) {
+ var _this = this;
+ this.leafletPromise.then(function () {
+ _this.manipulateLayers(rowIds, function (layers) {
+ _this.markerClusterGroup.removeLayers(layers);
+ });
+ });
+ };
+ MapView.prototype.manipulateLayers = function (rowIds, cb) {
+ var layersFromRowIds = this.getLayersFromRowIds(rowIds);
+ if (layersFromRowIds.length > 0) {
+ cb(layersFromRowIds);
+ }
+ };
+ MapView.prototype.getLayersFromRowIds = function (rowIds) {
+ return this.flatten(this.getLayersFromRowIdsRaw(rowIds));
+ };
+ MapView.prototype.getLayersFromRowIdsRaw = function (rowIds) {
+ var _this = this;
+ return rowIds.map(function (rowId) { return _this.markers[rowId] ? _this.markers[rowId] : []; });
+ };
+ MapView.prototype.flatten = function (markers) {
+ return markers.reduce(function (result, layers) { return result.concat(layers); }, []);
+ };
+ MapView.prototype.show = function () {
+ _super.prototype.show.call(this);
+ this.lateInit();
+ };
+ return MapView;
+}(View_1.View));
+exports.MapView = MapView;
+
+},{"./View":5}],5:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var View = /** @class */ (function () {
+ function View(id, target, c, options) {
+ if (options === void 0) { options = {}; }
+ this.id = undefined;
+ this.target = undefined;
+ this.controller = undefined;
+ this.options = undefined;
+ this.visible = false;
+ this.rows = {};
+ this.id = id;
+ this.target = target;
+ this.controller = c;
+ this.options = options;
+ }
+ View.prototype.init = function () {
+ var _this = this;
+ var rowIds = Object.keys(this.controller.getData());
+ var rows = this.target.find(this.getItemClassName());
+ rows.each(function (index, elem) {
+ var classes = elem.classList;
+ for (var i = 0; i < classes.length; i++) {
+ if (rowIds.indexOf(classes[i]) >= 0) {
+ _this.rows[classes[i]] = $(rows[index]);
+ }
+ }
+ });
+ };
+ View.prototype.getItemClassName = function () {
+ return '.filtered-item';
+ };
+ View.prototype.getTargetElement = function () {
+ return this.target;
+ };
+ View.prototype.showRows = function (rowIds) {
+ var _this = this;
+ if (this.visible && rowIds.length < 200) {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].slideDown(400);
+ });
+ }
+ else {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].css('display', '');
+ });
+ }
+ };
+ View.prototype.hideRows = function (rowIds) {
+ var _this = this;
+ if (this.visible && rowIds.length < 200) {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].slideUp(400);
+ });
+ }
+ else {
+ rowIds.forEach(function (rowId) {
+ _this.rows[rowId].css('display', 'none');
+ });
+ }
+ };
+ View.prototype.show = function () {
+ this.target.show();
+ this.visible = true;
+ };
+ View.prototype.hide = function () {
+ this.target.hide();
+ this.visible = false;
+ };
+ return View;
+}());
+exports.View = View;
+
+},{}],6:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var ViewSelector = /** @class */ (function () {
+ function ViewSelector(target, viewIDs, controller) {
+ this.target = undefined;
+ this.viewIDs = undefined;
+ this.controller = undefined;
+ this.target = target;
+ this.viewIDs = viewIDs;
+ this.controller = controller;
+ }
+ ViewSelector.prototype.init = function () {
+ var _this = this;
+ if (this.viewIDs.length > 1) {
+ this.viewIDs.forEach(function (id) { _this.target.on('click', '.' + id, { 'target': id, 'controller': _this.controller }, ViewSelector.onSelectorSelected); });
+ this.target.children().first().addClass('selected');
+ this.target.show();
+ }
+ };
+ ViewSelector.onSelectorSelected = function (event) {
+ event.data.controller.onViewSelected(event.data.target);
+ $(event.target)
+ .addClass('selected')
+ .siblings().removeClass('selected');
+ event.stopPropagation();
+ event.preventDefault();
+ };
+ return ViewSelector;
+}());
+exports.ViewSelector = ViewSelector;
+
+},{}],7:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+exports.__esModule = true;
+var Controller_1 = require("../../../resources/ts/Filtered/Controller");
+var MockedFilter_1 = require("../Util/MockedFilter");
+var View_1 = require("../../../resources/ts/Filtered/View/View");
+var ControllerTest = /** @class */ (function () {
+ function ControllerTest() {
+ }
+ ControllerTest.prototype.runTests = function () {
+ QUnit.test('Controller: Can construct and attach data', this.testConstructAndAttachData);
+ QUnit.test('Controller: Attaching 3 views (foo, bar, baz) and switch between them', this.testAttachViewsAndSwitchToViews);
+ QUnit.test('Controller: Show', this.testShow);
+ QUnit.test('Controller: Attaching 3 filters (foo, bar, baz)', this.testAttachFilter);
+ return true;
+ };
+ /**
+ * @covers Controller.constructor
+ * @covers Controller.getData
+ */
+ ControllerTest.prototype.testConstructAndAttachData = function (assert) {
+ // Setup
+ var data = { 'foo': {} };
+ // Run
+ var c = new Controller_1.Controller(undefined, data, {});
+ // Assert: Can construct
+ assert.ok(c instanceof Controller_1.Controller, 'Can construct Controller.');
+ // Assert: Data correctly attached and retained
+ assert.deepEqual(c.getData(), data, 'Returns result data as given to constructor.');
+ };
+ /**
+ * @covers Controller.attachView
+ * @covers Controller.getView
+ * @covers Controller.onViewSelected
+ */
+ ControllerTest.prototype.testAttachViewsAndSwitchToViews = function (assert) {
+ // Setup
+ var c = new Controller_1.Controller(undefined, undefined, undefined);
+ var viewIds = ['foo', 'bar', 'baz'];
+ var viewsShown = [];
+ var viewsHidden = [];
+ var views = {};
+ viewIds.forEach(function (viewId) {
+ var v = new View_1.View(viewId, undefined, c, {});
+ v.show = function () {
+ if (viewsShown.indexOf(v) === -1) {
+ viewsShown.push(v);
+ }
+ var index = viewsHidden.indexOf(v);
+ if (index >= 0) {
+ viewsHidden.splice(index, 1);
+ }
+ };
+ v.hide = function () {
+ if (viewsHidden.indexOf(v) === -1) {
+ viewsHidden.push(v);
+ }
+ var index = viewsShown.indexOf(v);
+ if (index >= 0) {
+ viewsShown.splice(index, 1);
+ }
+ };
+ views[viewId] = v;
+ // Run
+ c.attachView(viewId, v);
+ });
+ // Assert: One view visible, all others hidden, i.e. none has undefined
+ // visibility
+ assert.strictEqual(viewsShown.length, 1, 'One view visible.');
+ assert.strictEqual(viewsHidden.length, viewIds.length - 1, 'All but one view hidden.');
+ for (var viewId in views) {
+ // Assert: View correctly attached and retained
+ assert.deepEqual(c.getView(viewId), views[viewId], "Controller knows \"" + viewId + "\" view.");
+ }
+ for (var viewId in views) {
+ // Run: Select view
+ c.onViewSelected(viewId);
+ // Assert: Only selected view visible, all others hidden, i.e. none
+ // has undefined visibility
+ assert.ok(viewsShown.length === 1 && viewsShown.indexOf(views[viewId]) >= 0, 'Selected view visible.');
+ assert.strictEqual(viewsHidden.length, viewIds.length - 1, 'All other views hidden.');
+ }
+ };
+ /**
+ * @covers Controller.show
+ */
+ ControllerTest.prototype.testShow = function (assert) {
+ // Setup
+ var targetElement = $();
+ var targetShown = false;
+ targetElement.children = function (selector) {
+ var targetChild = $();
+ targetChild.show = function () {
+ targetShown = true;
+ return targetChild;
+ };
+ return targetChild;
+ };
+ // Run
+ new Controller_1.Controller(targetElement, undefined, undefined).show();
+ // Assert
+ assert.ok(targetShown, 'Container made visible.');
+ };
+ /**
+ * @covers Controller.attachFilter
+ * @covers Controller.getFilter
+ */
+ ControllerTest.prototype.testAttachFilter = function (assert) {
+ // Setup
+ var data = { 'foo': {} };
+ var controller = new Controller_1.Controller(undefined, data, {});
+ var filterIds = ['foo', 'bar', 'baz'];
+ var done = assert.async();
+ var promises = [];
+ filterIds.forEach(function (filterId) {
+ var visibilityWasQueried = false;
+ var filter = new MockedFilter_1.MockedFilter(filterId, undefined, undefined, controller);
+ filter.isVisible = function (rowId) {
+ visibilityWasQueried = true;
+ return true;
+ };
+ // Run
+ var promise = controller.attachFilter(filter)
+ .then(function () {
+ // Assert: Filter was queried for the visibility of result items
+ assert.ok(visibilityWasQueried, "Filter \"" + filterId + "\" was queried after attaching.");
+ });
+ promises.push(promise);
+ // Assert: Filter correctly attached and retained.
+ assert.deepEqual(controller.getFilter(filterId), filter, "Controller knows \"" + filterId + "\" filter.");
+ });
+ jQuery.when.apply(jQuery, promises).then(done);
+ };
+ return ControllerTest;
+}());
+exports.ControllerTest = ControllerTest;
+
+},{"../../../resources/ts/Filtered/Controller":1,"../../../resources/ts/Filtered/View/View":5,"../Util/MockedFilter":12}],8:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var ValueFilter_1 = require("../../../../resources/ts/Filtered/Filter/ValueFilter");
+var Controller_1 = require("../../../../resources/ts/Filtered/Controller");
+var QUnitTest_1 = require("../../Util/QUnitTest");
+var ValueFilterTest = /** @class */ (function (_super) {
+ __extends(ValueFilterTest, _super);
+ function ValueFilterTest() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // TODO:
+ // public isVisible( rowId: string ): boolean {
+ // public onFilterUpdated( eventObject: JQueryEventObject ) {
+ ValueFilterTest.prototype.runTests = function () {
+ QUnit.test('ValueFilter: Can construct', this.testCanConstruct);
+ QUnit.test('ValueFilter: Init', this.testInit);
+ QUnit.test('ValueFilter: Update on and/or switch.', this.testUseOr);
+ return true;
+ };
+ ;
+ ValueFilterTest.prototype.testCanConstruct = function (assert) {
+ var controller = undefined;
+ var options = {};
+ var f = new ValueFilter_1.ValueFilter('foo', $(), 'fooPR', controller, options);
+ assert.ok(f instanceof ValueFilter_1.ValueFilter, 'Can construct ValueFilter.');
+ };
+ ;
+ ValueFilterTest.prototype.testInit = function (assert) {
+ // Setup
+ var controller = new Controller_1.Controller($(), {}, {});
+ var options = {
+ 'switches': [
+ 'and or'
+ ],
+ 'values': [
+ 'foo',
+ 'bar'
+ ],
+ 'collapsible': 'uncollapsed',
+ 'type': 'value',
+ 'label': 'FooLabel'
+ };
+ var target = $('<div>');
+ var f = new ValueFilter_1.ValueFilter('foo', target, 'fooPR', controller, options);
+ // Run
+ f.init();
+ // Assert
+ assert.strictEqual(target.find('.filtered-filter-container').length, 1, 'Added container for collapsable content.');
+ assert.strictEqual(target.find('.filtered-value-andor').length, 1, 'Added container for and/or switch.');
+ var done = assert.async();
+ setTimeout(function () {
+ // Assert: One input added per value
+ for (var _i = 0, _a = options.values; _i < _a.length; _i++) {
+ var value = _a[_i];
+ assert.strictEqual(target.find("input[value=\"" + value + "\"]").length, 1, "Added option for value \"" + value + "\".");
+ }
+ done();
+ }, 100);
+ };
+ ;
+ ValueFilterTest.prototype.testUseOr = function (assert) {
+ // Setup
+ var controller = new Controller_1.Controller($(), {}, {});
+ controller.onFilterUpdated = function (filterId) {
+ // Assert
+ assert.ok(true, 'Filter updated.');
+ var d = jQuery.Deferred();
+ d.resolve();
+ return d.promise();
+ };
+ var f = new ValueFilter_1.ValueFilter('foo', $(), 'fooPR', controller, {});
+ assert.expect(1);
+ // Run
+ f.useOr(true);
+ };
+ ;
+ return ValueFilterTest;
+}(QUnitTest_1.QUnitTest));
+exports.ValueFilterTest = ValueFilterTest;
+
+},{"../../../../resources/ts/Filtered/Controller":1,"../../../../resources/ts/Filtered/Filter/ValueFilter":3,"../../Util/QUnitTest":13}],9:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var ViewTest_1 = require("./ViewTest");
+var MapView_1 = require("../../../../resources/ts/Filtered/View/MapView");
+var Controller_1 = require("../../../../resources/ts/Filtered/Controller");
+var MapViewTest = /** @class */ (function (_super) {
+ __extends(MapViewTest, _super);
+ function MapViewTest() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // TODO:
+ MapViewTest.prototype.getTestObject = function (id, target, c, options) {
+ if (id === void 0) { id = 'foo'; }
+ if (target === void 0) { target = undefined; }
+ if (c === void 0) { c = undefined; }
+ if (options === void 0) { options = {}; }
+ c = c || new Controller_1.Controller(undefined, {}, undefined);
+ return new MapView_1.MapView(id, target, c, options);
+ };
+ ;
+ MapViewTest.prototype.runTests = function () {
+ _super.prototype.runTests.call(this);
+ return true;
+ };
+ ;
+ return MapViewTest;
+}(ViewTest_1.ViewTest));
+exports.MapViewTest = MapViewTest;
+
+},{"../../../../resources/ts/Filtered/Controller":1,"../../../../resources/ts/Filtered/View/MapView":4,"./ViewTest":10}],10:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var QUnitTest_1 = require("../../Util/QUnitTest");
+var View_1 = require("../../../../resources/ts/Filtered/View/View");
+var Controller_1 = require("../../../../resources/ts/Filtered/Controller");
+var ViewTest = /** @class */ (function (_super) {
+ __extends(ViewTest, _super);
+ function ViewTest() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Coverage:
+ // [x] public constructor( id: string, target: JQuery, c: Controller, options: Options = {} )
+ // [x] public init()
+ // [x] public getTargetElement(): JQuery
+ // [ ] public showRows( rowIds: string[] )
+ // [ ] public hideRows( rowIds: string[] )
+ // [x] public show()
+ // [x] public hide()
+ ViewTest.prototype.getTestObject = function (id, target, c, options) {
+ if (id === void 0) { id = 'foo'; }
+ if (target === void 0) { target = undefined; }
+ if (c === void 0) { c = undefined; }
+ if (options === void 0) { options = {}; }
+ c = c || new Controller_1.Controller(undefined, {}, undefined);
+ return new View_1.View(id, target, c, options);
+ };
+ ;
+ ViewTest.prototype.runTests = function () {
+ var className = this.getTestObject().constructor['name'];
+ var that = this;
+ QUnit.test(className + ": Can construct, init and knows target element", function (assert) { that.testBasics(assert, that); });
+ QUnit.test(className + ": Show and Hide", function (assert) { that.testShowAndHide(assert, that); });
+ return true;
+ };
+ ;
+ ViewTest.prototype.testBasics = function (assert, that) {
+ //Setup
+ var target = $('<div>');
+ // Run
+ var v = that.getTestObject('foo', target);
+ var ret = v.init();
+ if (ret !== undefined) {
+ var done_1 = assert.async();
+ ret.then(function () {
+ assert.ok(v instanceof View_1.View, 'Can construct View. (P)');
+ assert.strictEqual(v.getTargetElement(), target, 'View retains target element. (P)');
+ done_1();
+ });
+ }
+ else {
+ // Assert
+ assert.ok(v instanceof View_1.View, 'Can construct View.');
+ assert.strictEqual(v.getTargetElement(), target, 'View retains target element.');
+ }
+ };
+ ;
+ ViewTest.prototype.testShowAndHide = function (assert, that) {
+ // Setup
+ var target = $('<div>');
+ target.show = function () { assert.ok(true, 'Target element shown.'); return target; };
+ target.hide = function () { assert.ok(true, 'Target element hidden.'); return target; };
+ var v = that.getTestObject('foo', target);
+ v.init();
+ v.show();
+ v.hide();
+ assert.expect(2);
+ };
+ ;
+ return ViewTest;
+}(QUnitTest_1.QUnitTest));
+exports.ViewTest = ViewTest;
+
+},{"../../../../resources/ts/Filtered/Controller":1,"../../../../resources/ts/Filtered/View/View":5,"../../Util/QUnitTest":13}],11:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+/// <reference types="jquery" />
+exports.__esModule = true;
+var ViewSelector_1 = require("../../../resources/ts/Filtered/ViewSelector");
+var Controller_1 = require("../../../resources/ts/Filtered/Controller");
+var ViewSelectorTest = /** @class */ (function () {
+ function ViewSelectorTest() {
+ }
+ ViewSelectorTest.prototype.runTests = function () {
+ QUnit.test('ViewSelector: Can construct', this.testCanConstruct);
+ QUnit.test('ViewSelector: Init for 1 view', this.testInitSingleView);
+ QUnit.test('ViewSelector: Init for 2 views', this.testInitMultipleViews);
+ QUnit.test('ViewSelector: Selecting views when clicked (3 views: foo, bar, baz)', this.testSelectViews);
+ return true;
+ };
+ ViewSelectorTest.prototype.testCanConstruct = function (assert) {
+ var v = new ViewSelector_1.ViewSelector(undefined, [], undefined);
+ assert.ok(v instanceof ViewSelector_1.ViewSelector, 'Can construct ViewSelector.');
+ };
+ ViewSelectorTest.prototype.testInitSingleView = function (assert) {
+ // Setup
+ var callCount = 0;
+ var viewName = 'foo';
+ var target = $('<div style="display:none">');
+ target.append('<div class="' + viewName + '">');
+ target.on = function () {
+ var args = [];
+ for (var _a = 0; _a < arguments.length; _a++) {
+ args[_a] = arguments[_a];
+ }
+ callCount++;
+ return target;
+ };
+ target.appendTo('body');
+ var v = new ViewSelector_1.ViewSelector(target, [viewName], undefined);
+ // Run
+ v.init();
+ // Assert
+ assert.strictEqual(callCount, 0, 'Registers no Click events.');
+ assert.ok(target.is(':hidden'), 'Target element is NOT visible.');
+ // Tear down
+ target.remove();
+ };
+ ViewSelectorTest.prototype.testInitMultipleViews = function (assert) {
+ // Setup
+ var target = $('<div style="display:none">');
+ var viewSelectors = {};
+ var viewIDs = ['foo', 'bar'];
+ for (var _a = 0, viewIDs_1 = viewIDs; _a < viewIDs_1.length; _a++) {
+ var id = viewIDs_1[_a];
+ viewSelectors[id] = $('<div class="' + id + '">');
+ target.append(viewSelectors[id]);
+ }
+ var eventRegistrationCount = 0;
+ target.origOn = target.on;
+ target.on = function () {
+ var args = [];
+ for (var _a = 0; _a < arguments.length; _a++) {
+ args[_a] = arguments[_a];
+ }
+ eventRegistrationCount++;
+ return target.origOn.apply(target, args);
+ };
+ target.appendTo('body');
+ var v = new ViewSelector_1.ViewSelector(target, viewIDs, undefined);
+ // Run test: Initialize ViewSelector
+ v.init();
+ // Assert
+ assert.strictEqual(eventRegistrationCount, viewIDs.length, "Registers " + viewIDs.length + " Click events.");
+ assert.ok(target.children().first().hasClass('selected'), 'First view selector is marked as selected.');
+ assert.ok(target.is(':visible'), 'Target element is visible.');
+ // Tear down
+ target.remove();
+ };
+ ViewSelectorTest.prototype.testSelectViews = function (assert) {
+ // Setup
+ var target = $('<div style="display:none">');
+ var viewSelectors = {};
+ var viewIDs = ['foo', 'bar', 'baz'];
+ for (var _i = 0, viewIDs_2 = viewIDs; _i < viewIDs_2.length; _i++) {
+ var id = viewIDs_2[_i];
+ viewSelectors[id] = $('<div class="' + id + '">');
+ target.append(viewSelectors[id]);
+ }
+ target.appendTo('body');
+ var c = new Controller_1.Controller(undefined, undefined, undefined);
+ c.onViewSelected = function (viewID) {
+ // Assert that the ViewSelector called the Controller when clicked
+ assert.ok(true, "Controller was called to select view \"" + viewID + "\".");
+ };
+ var v = new ViewSelector_1.ViewSelector(target, viewIDs, c);
+ v.init();
+ // Run test: Select view
+ assert.expect(6);
+ for (var id in viewSelectors) {
+ viewSelectors[id].click();
+ // Assert: Only the clicked ViewController has class 'selected'
+ assert.ok(viewSelectors[id].hasClass('selected') && !viewSelectors[id].siblings().hasClass('selected'), "View selector \"" + id + "\" marked as selected, siblings NOT marked as selected.");
+ }
+ // Tear down
+ target.remove();
+ };
+ return ViewSelectorTest;
+}());
+exports.ViewSelectorTest = ViewSelectorTest;
+
+},{"../../../resources/ts/Filtered/Controller":1,"../../../resources/ts/Filtered/ViewSelector":6}],12:[function(require,module,exports){
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+exports.__esModule = true;
+var Filter_1 = require("../../../resources/ts/Filtered/Filter/Filter");
+var MockedFilter = /** @class */ (function (_super) {
+ __extends(MockedFilter, _super);
+ function MockedFilter() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return MockedFilter;
+}(Filter_1.Filter));
+exports.MockedFilter = MockedFilter;
+
+},{"../../../resources/ts/Filtered/Filter/Filter":2}],13:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var QUnitTest = /** @class */ (function () {
+ function QUnitTest() {
+ }
+ QUnitTest.prototype.runTests = function () { };
+ ;
+ return QUnitTest;
+}());
+exports.QUnitTest = QUnitTest;
+
+},{}],14:[function(require,module,exports){
+"use strict";
+exports.__esModule = true;
+var QUnitTestHandler = /** @class */ (function () {
+ function QUnitTestHandler(moduleName, testclasses) {
+ this.isInitialised = false;
+ this.moduleName = moduleName;
+ this.testclasses = testclasses;
+ }
+ QUnitTestHandler.prototype.init = function () {
+ var _this = this;
+ if (this.isInitialised) {
+ return;
+ }
+ this.isInitialised = true;
+ QUnit.testDone(function (details) {
+ var message = "Pass: " + details.passed + " Fail: " + details.failed + " Total: " + details.total + " " + details.module + " - " + details.name + " (" + details.duration + "ms)";
+ _this.reportResult(details.failed, message);
+ });
+ QUnit.done(function (details) {
+ var message = "All tests finished. (" + details.runtime + "ms)\nPass: " + details.passed + " Fail: " + details.failed + " Total: " + details.total;
+ _this.reportResult(details.failed, message);
+ });
+ };
+ ;
+ QUnitTestHandler.prototype.reportResult = function (failed, message) {
+ if (failed === 0) {
+ console.log(message);
+ }
+ else {
+ console.error(message);
+ }
+ };
+ QUnitTestHandler.prototype.runTests = function () {
+ this.init();
+ QUnit.module(this.moduleName, QUnit.newMwEnvironment());
+ this.testclasses.forEach(function (testclass) {
+ return new testclass().runTests();
+ });
+ };
+ ;
+ return QUnitTestHandler;
+}());
+exports.QUnitTestHandler = QUnitTestHandler;
+
+},{}],15:[function(require,module,exports){
+"use strict";
+/// <reference types="qunit" />
+exports.__esModule = true;
+var ViewSelectorTest_1 = require("./Filtered/ViewSelectorTest");
+var ControllerTest_1 = require("./Filtered/ControllerTest");
+var ValueFilterTest_1 = require("./Filtered/Filter/ValueFilterTest");
+var QUnitTestHandler_1 = require("./Util/QUnitTestHandler");
+var ViewTest_1 = require("./Filtered/View/ViewTest");
+var MapViewTest_1 = require("./Filtered/View/MapViewTest");
+var testclasses = [
+ ViewSelectorTest_1.ViewSelectorTest,
+ ControllerTest_1.ControllerTest,
+ ValueFilterTest_1.ValueFilterTest,
+ ViewTest_1.ViewTest,
+ MapViewTest_1.MapViewTest,
+];
+var testhandler = new QUnitTestHandler_1.QUnitTestHandler('ext.srf.formats.filtered', testclasses);
+testhandler.runTests();
+
+},{"./Filtered/ControllerTest":7,"./Filtered/Filter/ValueFilterTest":8,"./Filtered/View/MapViewTest":9,"./Filtered/View/ViewTest":10,"./Filtered/ViewSelectorTest":11,"./Util/QUnitTestHandler":14}]},{},[15]);
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.gallery.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.gallery.test.js
new file mode 100644
index 00000000..56db0d62
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.gallery.test.js
@@ -0,0 +1,73 @@
+/**
+ * This file is part of the Semantic Result Formats QUnit Suite
+ * @see https://www.semantic-mediawiki.org/wiki/QUnit
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * QUnit tests for the srf.formats.gallery class
+ *
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.formats.gallery', QUnit.newMwEnvironment() );
+
+ /**
+ * Test initialization and accessibility
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'init', 5, function ( assert ) {
+ var gallery = new srf.formats.gallery();
+
+ assert.ok( gallery instanceof Object, 'gallery instance was accessible' );
+ assert.equal( $.type( gallery.redirect ), 'function', '.redirect() was accessible' );
+ assert.equal( $.type( gallery.overlay ), 'function', '.overlay() was accessible' );
+ assert.equal( $.type( gallery.slideshow ), 'function', '.slideshow() was accessible' );
+ assert.equal( $.type( gallery.carousel ), 'function', '.carousel() was accessible' );
+
+ } );
+
+ /**
+ * Test overlay
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'overlay', 2, function ( assert ) {
+
+ var context = $( '<div class="srf-overlay"</div>', '#qunit-fixture' );
+ var gallery = new srf.formats.gallery();
+
+ var ns = 'File';
+
+ gallery.overlay( context, ns );
+ assert.equal( $.type( gallery.defaults.path ), 'string', '.defaults.path was initialized and returned a string' );
+ assert.equal( gallery.defaults.ns, ns, '.defaults.ns was initialized and returned the invoked string' );
+
+ } );
+
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.media.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.media.test.js
new file mode 100644
index 00000000..55908382
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.media.test.js
@@ -0,0 +1,131 @@
+/**
+ * This file is part of the Semantic Result Formats QUnit Suite
+ * @see https://www.semantic-mediawiki.org/wiki/QUnit
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * QUnit tests for the srf.formats.media class
+ *
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.formats.media', QUnit.newMwEnvironment() );
+
+ var jsonString = '{\"data\":{\"File:Foo.mp3\":{\"mp3\":\"\\/mw\\/Foo.mp3\",\"subject\":\"File:Foo.mp3\"}},\"count\":5,\"mediaType\":\"audio\",\"mimeTypes\":\"ogg,mp3\",\"inspector\":true}';
+
+ /**
+ * Test initialization and accessibility
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'init', 8, function ( assert ) {
+ var media = new srf.formats.media();
+
+ assert.ok( media instanceof Object, 'srf.formats.media() instance was accessible' );
+ assert.equal( $.type( media.defaults ), 'object', '.defaults was accessible' );
+ assert.equal( $.type( media.parse ), 'function', '.parse() was accessible' );
+ assert.equal( $.type( media.getId ), 'function', '.getId() was accessible' );
+ assert.equal( $.type( media.getPlayerSize ), 'function', '.getPlayerSize() was accessible' );
+ assert.equal( $.type( media.getData ), 'function', '.getData() was accessible' );
+ assert.equal( $.type( media.getPlayerTemplate ), 'function', '.getPlayerTemplate() was accessible' );
+ assert.equal( $.type( media.getInspector ), 'function', '.getInspector() was accessible' );
+
+ } );
+
+ /**
+ * Test template accessibility
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'template', 3, function ( assert ) {
+
+ assert.equal( $.type( srf.template.jplayer.inspector ), 'function', '.jplayer.inspector() was accessible' );
+ assert.equal( $.type( srf.template.jplayer.audio ), 'object', '.jplayer.audio returned an object' );
+ assert.equal( $.type( srf.template.jplayer.video ), 'object', '.jplayer.video returned an object' );
+
+ } );
+
+ /**
+ * Test default settings
+ *
+ * @since: 1.9
+ */
+ QUnit.asyncTest( 'defaults', 2, function ( assert ) {
+ var media = new srf.formats.media();
+
+ $.get( media.defaults.posterImage )
+ .done( function() {
+ QUnit.start();
+ assert.ok( true, media.defaults.posterImage + ' verified' );
+ } )
+ .fail( function() {
+ // doesn't exists
+ QUnit.start();
+ } );
+
+ $.get( media.defaults.jplayer.swfPath )
+ .done( function() {
+ QUnit.start();
+ assert.ok( true, media.defaults.jplayer.swfPath + ' verified' );
+ } )
+ .fail( function() {
+ // doesn't exists
+ QUnit.start();
+ } );
+
+ } );
+
+ /**
+ * Test parse
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'parse', 1, function ( assert ) {
+ var media = new srf.formats.media();
+
+ assert.equal( $.type( media.parse( jsonString ) ), 'object', '.parse() returned an object' );
+
+ } );
+
+ /**
+ * Test getData
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'getData', 2, function ( assert ) {
+ var media = new srf.formats.media();
+ var json = media.parse( jsonString );
+ var result = media.getData( json.data, json.mediaType );
+
+ $.map( result, function ( data ) {
+ assert.equal( data.subject, 'File:Foo.mp3', 'subject returned "File:Foo.mp3"' );
+ assert.equal( data.title, 'File:Foo.mp3', 'title returned "File:Foo.mp3"' );
+ } );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.tagcloud.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.tagcloud.test.js
new file mode 100644
index 00000000..11fddce8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/formats/ext.srf.formats.tagcloud.test.js
@@ -0,0 +1,178 @@
+/*!
+ * This file is part of the Semantic Result Formats QUnit Suite
+ * @see https://www.semantic-mediawiki.org/wiki/QUnit
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @license GNU GPL v2+
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.formats.tagcloud', QUnit.newMwEnvironment() );
+
+ var context = $(
+ '<div><div id="test" class="srf-container">' +
+ '<div id="test1" class="srf-tags"><ul>' +
+ '<li><a href="/test1">Test1</a></li>' +
+ '<li><a href="/test2">Test2</a></li>' +
+ '</ul></div></div></div>', '#qunit-fixture' );
+
+ /**
+ * Test initialization and accessibility
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'init', 4, function ( assert ) {
+ var tagcloud = new srf.formats.tagcloud();
+
+ assert.equal( $.type( tagcloud.defaults ), 'object', '.defaults was accessible' );
+ assert.equal( $.type( tagcloud.sphere ), 'function', '.sphere() was accessible' );
+ assert.equal( $.type( tagcloud.wordcloud ), 'function', '.wordcloud() was accessible' );
+ assert.equal( $.type( tagcloud.load ), 'function', '.load() was accessible' );
+
+ } );
+
+ /**
+ * Test dependencies
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'dependencies', 4, function ( assert ) {
+ var util = new srf.util();
+
+ assert.equal( $.type( util.assert ), 'function', 'util.assert was accessible' );
+ assert.equal( $.type( smw.async.load ), 'function', 'smw.async.load was accessible' );
+ assert.equal( $.type( util.spinner.hide ), 'function', 'util.spinner.hide was accessible' );
+ assert.equal( $.type( util.message.set ), 'function', 'util.message.set was accessible' );
+
+ } );
+
+ /**
+ * Test load
+ *
+ * @since: 1.9
+ */
+ QUnit.test( 'load', 4, function ( assert ) {
+ var tagcloud = new srf.formats.tagcloud();
+ var result,
+ options;
+
+ context.data( 'version', '0.4.1' );
+
+ options = {
+ context: context,
+ element: 'canvas',
+ module: 'ext.jquery.tagcanvas',
+ method: tagcloud.sphere
+ };
+
+ result = tagcloud.load( options );
+ assert.ok( result, 'sphere was initialized' );
+
+ options = {
+ context: context,
+ element: 'svg',
+ module: 'ext.d3.wordcloud',
+ method: tagcloud.wordcloud
+ };
+
+ result = tagcloud.load( options );
+ assert.ok( result, 'wordcloud was initialized' );
+
+ // Check for a non existing element
+ options = {
+ context: context,
+ element: 'lula',
+ module: '',
+ method: ''
+ };
+
+ result = tagcloud.load( options );
+ assert.ok( result, 'non existing element' );
+
+ // Check invalid version
+ options = {
+ context: context,
+ element: 'lula',
+ module: '',
+ method: ''
+ };
+
+ tagcloud.version = '0.4.2';
+ result = tagcloud.load( options );
+ assert.equal( result, false, 'wrong version' );
+
+ } );
+
+ /**
+ * Test sphere/tagcanvas
+ *
+ * @since: 1.9
+ */
+ QUnit.asyncTest( 'sphere', 1, function ( assert ) {
+ var tagcloud = new srf.formats.tagcloud();
+
+ context.find( '.srf-container' ).data( {
+ 'width': 100,
+ 'height': 100,
+ 'font': 'sans'
+ } );
+
+ // Tagcanvas dies during testing for some reasons,
+ // QUnit returns with a time-out
+ mw.loader.using( 'ext.jquery.tagcanvas', function() {
+ QUnit.start();
+ tagcloud.sphere( context );
+ assert.ok( context.find( 'canvas' ), 'canvas element was found' );
+ } );
+
+ // As of now mark this test as OK because of the above issue
+ assert.ok( true, 'Not really true but for now we pass' );
+ } );
+
+ /**
+ * Test wordcloud
+ *
+ * @since: 1.9
+ */
+ QUnit.asyncTest( 'wordcloud', 2, function ( assert ) {
+ var tagcloud = new srf.formats.tagcloud();
+
+ context.find( '.srf-container' ).data( {
+ 'width': 100,
+ 'height': 100,
+ 'font': 'sans'
+ } );
+
+ mw.loader.using( 'ext.d3.wordcloud', function() {
+ QUnit.start();
+ var result = tagcloud.wordcloud( context );
+ assert.ok( result, 'function returned true' );
+ assert.ok( context.find( 'svg' ), 'svg element was found' );
+ } );
+
+ } );
+
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.eventcalendar.tests.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.eventcalendar.tests.js
new file mode 100644
index 00000000..ea919647
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.eventcalendar.tests.js
@@ -0,0 +1,137 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.widgets.eventcalendar', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+ var context = $( '<div class="srf-eventcalendar"><div class="info"></div><div id="smw-test" class="container"></div></div>', '#qunit-fixture' ),
+ container = context.find( '.container' );
+
+ /**
+ * calendarpane widget testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'calendarpane widget', 4, function ( assert ) {
+ var pane = context.find( '.info' );
+
+ // Set visibility
+ pane.calendarpane( {
+ 'show': true
+ } );
+
+ // Without fieldset
+ var test = pane.calendarpane( 'portlet', {
+ 'class' : 'test',
+ 'title' : 'Test',
+ 'fieldset': false
+ } );
+
+ var results = test.find( 'fieldset' ).length;
+ assert.ok( results === 0, pass + 'the test portlet was created without fieldset (false)' );
+
+ // With fieldset
+ var test = pane.calendarpane( 'portlet', {
+ 'class' : 'test',
+ 'title' : 'Test',
+ 'fieldset': true
+ } );
+
+ var results = test.find( 'fieldset' ).length;
+ assert.ok( results > 0, pass + 'the test portlet was created with a fieldset (true)' );
+
+ // Toggle
+ pane.calendarpane( 'toggle' );
+ var result = pane.calendarpane( 'context' ).css( 'display' );
+ assert.equal( result , 'none', pass + 'the pane toggle was successful (hide) ' );
+
+ pane.calendarpane( 'toggle' );
+ var result = pane.calendarpane( 'context' ).css( 'display' );
+ assert.equal( result, 'block', pass + 'the pane toggle was successful (show)' );
+
+ } );
+
+ /**
+ * calendarbutton widget testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'calendarbutton widget', 1, function ( assert ) {
+ var button = context.find( '.info' );
+
+ button.calendarbutton( {
+ 'class': 'pane',
+ icon : 'ui-icon ui-icon-bookmark',
+ title: '',
+ theme: ''
+ } )
+ .on( 'click', '.srf-calendarbutton-pane' , function( event ) {
+ assert.ok( true, pass + 'the click trigger was successful' );
+ } );
+
+ button.find( '.srf-calendarbutton-pane' ).trigger( 'click' );
+
+ } );
+
+ /**
+ * calendarparameters widget testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'calendarparameters widget - eventStart', 4, function ( assert ) {
+ var pane = context.find( '.info' );
+
+ // Set visibility
+ pane.calendarpane( {
+ 'show': true
+ } );
+
+ var param = pane.calendarpane( 'portlet', {
+ 'class' : 'parameters',
+ 'title' : 'Test',
+ 'fieldset': true
+ } ).find( 'fieldset' ).calendarparameters();
+
+ // Start parameter
+ param.calendarparameters( 'eventStart', {
+ type: 'earliest',
+ change: function( type ){
+ assert.ok( true, pass + 'the change event (' + type + ') was triggered' );
+ },
+ reset: function(){
+ assert.ok( true, pass + 'the reset event was triggered' );
+ }
+ } );
+
+ var results = param.find( '.srf-calendarparameters-minmax' ).length;
+ assert.ok( results === 0, pass + 'the minmax portlet was created' );
+
+ // Trigger change earliest
+ param.find( '#min' ).trigger( 'change' );
+
+ // Change option
+ param.calendarparameters(
+ 'option', 'eventStart', {
+ 'type': 'latest'
+ } );
+
+ // Trigger change for latest
+ param.find( '#max' ).trigger( 'change' );
+
+ // Trigger click for reset
+ param.find( '.reset-link' ).trigger( 'click' );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.optionslist.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.optionslist.test.js
new file mode 100644
index 00000000..ee575e7e
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.optionslist.test.js
@@ -0,0 +1,154 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.widgets.optionslist', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+ var list = [ { key: 0, label: 'foo' }, { key: 2, label: 'fooBar' }, { key: 11, label: 'bar' } ];
+ var list2 = [ 'foo', 'bar', 'fooBar' ];
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'instance', 1, function ( assert ) {
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ context.optionslist();
+ var result = context.optionslist( 'checklist', {
+ show: true,
+ list: list,
+ 'class': 'test'
+ } );
+
+ assert.ok( result.length > 0 , pass + 'the srf.checklist widget returned an object with length > 0' );
+
+ } );
+
+ /**
+ * onClick testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'checklist click event', 2, function ( assert ) {
+ var result ;
+ var context;
+
+ context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ context.optionslist();
+ result = context.optionslist( 'checklist', {
+ show: true,
+ list: list,
+ 'class': 'test',
+ click: function( event, ui ){
+ assert.equal( ui.value, 11, pass + 'object key (11) was returned for id(#bar)' );
+ }
+ } );
+
+ // Trigger click
+ result.find( '#bar' ).trigger( 'click' );
+
+ context = $( '<div class="test"></div>', '#qunit-fixture' );
+ context.optionslist();
+ result = context.optionslist( 'checklist', {
+ show: true,
+ list: list2,
+ 'class': 'test',
+ click: function( event, ui ){
+ assert.equal( ui.value, 1, pass + 'array key (1) was returned for id(#bar)' );
+ }
+ } );
+
+ // Trigger click
+ result.find( '#bar' ).trigger( 'click' );
+
+ } );
+
+ /**
+ * show/hide option
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'checklist show/hide ', 3, function ( assert ) {
+ var result;
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ context.optionslist();
+ result = context.optionslist( 'checklist', {
+ show: true,
+ list: list,
+ 'class': 'listTest'
+ } );
+ assert.equal( result.css( 'display' ) , 'block', pass + 'option resulted in a visible list' );
+
+ context.optionslist();
+ result = context.optionslist( 'checklist', {
+ list: list,
+ 'class': 'listTest'
+ } );
+ assert.equal( result.css( 'display' ) , 'block', pass + 'option resulted in a visible list' );
+
+ context.optionslist();
+ result = context.optionslist( 'checklist', {
+ show: false,
+ list: list,
+ 'class': 'listTest'
+ } );
+ assert.equal( result.css( 'display' ) , 'none', pass + 'option resulted in a hidden list' );
+
+ } );
+
+ /**
+ * change event testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'selectlist change event', 2, function ( assert ) {
+ var result ;
+ var context;
+
+ context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ context.optionslist();
+ result = context.optionslist( 'selectlist', {
+ show: true,
+ list: list,
+ 'class': 'test',
+ change: function( event, ui ){
+ assert.equal( ui.value, 11, pass + 'value (11) was returned' );
+
+
+ }
+ } );
+
+ // Trigger click
+ result.find( 'option[value="11"]' ).trigger( 'change' );
+
+ context.optionslist();
+ result = context.optionslist( 'selectlist', {
+ show: true,
+ list: list2,
+ 'class': 'test2',
+ change: function( event, ui ){
+ assert.equal( ui.value, 2, pass + 'value (2) was returned' );
+ }
+ } );
+
+ // Trigger click
+ result.find( 'option[value=2]' ).trigger( 'change' );
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.panel.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.panel.test.js
new file mode 100644
index 00000000..838ba706
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.panel.test.js
@@ -0,0 +1,57 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.widgets.panel', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'instance', 1, function ( assert ) {
+ var result;
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ result = context.panel( {
+ 'show': true
+ } );
+ assert.ok( result.find( '.srf-panel') , pass + 'the srf.panel widget returned a DOM object' );
+
+ } );
+
+ /**
+ * Portlet testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'add portlet', 1, function ( assert ) {
+ var result;
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ result = context.panel( {
+ 'show': true
+ } );
+
+ result = result.panel( 'portlet', {
+ 'class' : 'portlet',
+ 'title' : 'portlet',
+ 'fieldset': true
+ } );
+ assert.ok( result.find( '.portlet > fieldset' ), pass + 'the srf.panel widget added a portlet' );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file
diff --git a/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.parameters.test.js b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.parameters.test.js
new file mode 100644
index 00000000..85f213e8
--- /dev/null
+++ b/www/wiki/extensions/SemanticResultFormats/tests/qunit/widgets/ext.srf.widgets.parameters.test.js
@@ -0,0 +1,69 @@
+/**
+ * QUnit tests
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function ( $, mw, srf ) {
+ 'use strict';
+
+ QUnit.module( 'ext.srf.widgets.parameters', QUnit.newMwEnvironment() );
+
+ var pass = 'Passes because ';
+
+ /**
+ * Instance testing
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'instance', 1, function ( assert ) {
+ var result;
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ result = context.parameters();
+
+ assert.ok( result.find( '.parameters') , pass + 'the srf.parameters widget returned a DOM object' );
+
+ } );
+
+ /**
+ * Limit parameter test
+ *
+ * @since 1.9
+ */
+ QUnit.test( 'limit parameter test', 3, function ( assert ) {
+ var result;
+ var context = $( '<div class="test"></div>', '#qunit-fixture' );
+
+ var parameters = context.parameters();
+ parameters.parameters( 'limit', {
+ limit : 10,
+ count : 1,
+ max : 20,
+ step : 1,
+ change: function( event, ui ) {
+ assert.equal( ui.value, ( 3 - 1 ), pass + 'the limit parameter was changed to 2' );
+ }
+ } );
+
+ assert.equal( parameters.find( '.value' ).text(), "10", pass + 'the limit parameter is 10' );
+
+ // Simulate slider value change
+ parameters.find( '.slider' ).slider( "value", 3 );
+
+ // Update limit display
+ parameters.parameters(
+ 'option', 'limit', {
+ 'limit': 3,
+ 'count': 3
+ } ) ;
+ assert.equal( parameters.find( '.value' ).text(), "3", pass + 'the limit parameter is 3' );
+
+ } );
+
+}( jQuery, mediaWiki, semanticFormats ) ); \ No newline at end of file